#ifndef MUTILS_PLATFORM_H
#define MUTILS_PLATFORM_H
/**
  \file

\verbatim
  $Id: platform.h,v 1.16 2014/11/19 01:02:24 rauch Exp $
\endverbatim
  \author Kevin P. Rauch
  \brief  MathUtils platform identification macros.

  Defines integer types of known (minimum) sizes; failure is possible but
  unlikely on a modern system. Also defines standard values for CPU and OS
  type; returns error message if platform is not recognized. Platform is then
  used to set byte ordering (MU_BIGENDIAN).

*/
#ifdef __cplusplus
#include <climits>

extern "C" {
namespace MUTILS {
#else
#include <limits.h>
#endif

/* ISO C requires at least 8- and 16-bits for these */
typedef   signed char  int8;
typedef unsigned char uint8;
typedef   signed short int  int16;
typedef unsigned short int uint16;

#ifndef INT_MAX
#define INT_MAX 2147483647L
#endif
#if INT_MAX >= 2147483647L
typedef   signed int  int32;
typedef unsigned int uint32;
#else
typedef   signed long int  int32;
typedef unsigned long int uint32;
#endif

#ifndef LONG_MAX
#define LONG_MAX 2147483647L
#endif
#if LONG_MAX > 2147483647L
typedef   signed long int  int64;
typedef unsigned long int uint64;
#else
typedef   signed long long int  int64;
typedef unsigned long long int uint64;
#endif

#ifdef __cplusplus
}  // namespace MUTILS
}  // extern "C" {
#endif


/*
   Pure preprocessor work below here---CANNOT be confined to a namespace.
*/
#define MU_MAKESTR(arg) #arg
#define MU_VERSTR(num) MU_MAKESTR(num)

/* Standardized compiler name strings. */
#define mu_compiler_known
#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
#  define mu_compiler "sunpro"
#  define mu_compiler_sunpro
#elif defined(__PGI)
#  define mu_compiler "pgcc"
#  define mu_compiler_pgcc
#elif defined(__ICC)
#  define mu_compiler ("icc" MU_VERSTR(__ICC))
#  define mu_compiler_icc
#elif defined(__DECC)
#  define mu_compiler "decc"
#  define mu_compiler_decc
#elif defined(__xlC__)
#  define mu_compiler "xlc"
#  define mu_compiler_xlc
#elif defined(__GNUC__)
#  define mu_compiler ("gcc" MU_VERSTR(__GNUC__) "." MU_VERSTR(__GNUC_MINOR__))
#  define mu_compiler_gcc
#else
#  define mu_compiler "unknown"
#  undef  mu_compiler_known
#endif


/* OS defines. */
#define mu_os_known
#ifdef DJGPP
#  define mu_os_djgpp
#elif defined(__UWIN__)
#  define mu_os_uwin
#elif defined(__MINGW32__) || defined(__CYGWIN32__) || defined(_MSC_VER) || \
      defined(__WIN32)     || defined(_WIN32)       || defined(WIN32)
#  define mu_os_mswin
#elif defined(__APPLE__) && defined(__MACH__)
#  define mu_os_macx
#elif defined(aix) || defined(__aix)
#  define mu_os_aix
#elif defined(hpux) || defined(__hpux)
#  define mu_os_hpux
#elif defined(irix) || defined(sgi) || defined(__sgi) || defined(__irix)
#  define mu_os_irix
#elif defined(linx) || defined(linux) || defined(__linux__) || defined(__linx)
#  define mu_os_linux
#elif defined(osf1) || defined (__osf__) || \
      (defined(__digital__) && defined(__unix__)) || defined(__osf1)
#  define mu_os_osf1
#elif defined(sun4) || defined(__sun4)
#  define mu_os_sun4
#elif defined(sun5) || defined(__sun5) || (defined(__PGI) && defined(sun))
#  define mu_os_sun5
#elif defined(sun) || defined(__sun) /* Make educated guesses... */
#  if defined(__SVR4) || defined(__svr4__) || defined(__sun5)
#    define mu_os_sun5
#  elif (!defined(__SVR4) && !defined(__svr4__)) || defined(__sun4)
#    define mu_os_sun4
#  endif
#else
#  undef mu_os_known  /* OS unknown. */
#endif

#ifndef mu_os_known
#  error "OS not supported in platform.h."
#endif


/* CPU defines. */
#define mu_cpu_known
#if defined(alpha) || defined(__alpha__) || defined(__alpha)
#  define mu_cpu_alpha
#elif defined(hppa) || defined(__hppa)
#  define mu_cpu_hppa
#elif defined(__MIC__)
#  define mu_cpu_x86_mic
#elif defined(i386) || defined(i486) || defined(i586)   || \
      defined(i686) || defined(i786) || defined(__i386) || defined(_X86_) || \
      defined(__386__) || defined(__i386__) || defined(_M_IX86)
#  define mu_cpu_x86
#elif defined(x86_64) || defined(__x86_64) || defined(__x86_64__) || \
      defined(__amd64) || defined(__amd64__)
#  define mu_cpu_x86_64
#elif defined(mips) || defined(host_mips) || \
      defined(__host_mips) || defined(__mips)
#  define mu_cpu_mips
#elif defined(__bgq__) && defined(__PPC64__)
#  define mu_cpu_bgq
#elif defined(__PPC64__) || defined(__ARCH_PPC64)
#  define mu_cpu_ppc64
#elif defined(__ppc__) || defined(__PPC__) || defined(__ppc) || \
      defined(__powerpc__) || defined(__powerpc)
#  define mu_cpu_ppc
#elif defined(rs6000) || defined(__rs6000__) || defined(__rs6000)
#  define mu_cpu_rs6000
#elif defined(sparc) || defined(__sparc__) || defined(__sparc)
#  define mu_cpu_sparc
#else
#  undef mu_cpu_known  /* CPU unknown. */
#endif

#ifndef mu_cpu_known
#  error "CPU not supported in platform.h."
#endif


/* ASM defines. */
#define mu_asm_known
#if (defined(mu_compiler_icc) || defined(mu_compiler_gcc) || \
     defined(mu_compiler_sunpro)) && \
     defined(mu_cpu_x86) && !defined(mu_os_macx)
#  define mu_asm_att_x86
#elif (defined(mu_compiler_icc) || defined(mu_compiler_gcc) || \
       defined(mu_compiler_sunpro)) && \
       defined(mu_cpu_x86_64) && !defined(mu_os_macx)
#  define mu_asm_att_x86_64
#else
#  undef mu_asm_known  /* ASM variant unknown. */
#endif


/* Byte order defines. */
#if defined(mu_cpu_alpha) || defined(mu_cpu_x86) || defined(mu_cpu_x86_64) || \
    defined(mu_cpu_x86_mic) || defined(mu_cpu_rs6000) || \
   (defined(mu_cpu_mips) && !defined(_MIPSEB) && !defined(MIPSEB)) || \
    defined(L_ENDIAN)
#  undef  MU_BIGENDIAN
#elif defined(mu_cpu_bgq) || defined(mu_cpu_hppa)  || defined(mu_cpu_mips) || \
      defined(mu_cpu_ppc) || defined(mu_cpu_ppc64) || defined(mu_cpu_sparc) || \
      defined(B_ENDIAN)
#  define MU_BIGENDIAN
#else
#  error "Byte order unknown in platform.h; CPU type supported??"
#endif


#if   defined(DLL_EXPORT)
#  define DLLSPEC __declspec(dllexport)
#elif defined(DLL_IMPORT)
#  define DLLSPEC __declspec(dllimport)
#else
#  define DLLSPEC
#endif

#endif  /* MUTILS_PLATFORM_H */
