/* q_endian.h -- endianness detection / handling
*
* Copyright (C) 1996-1997 Id Software, Inc.
* Copyright (C) 2007-2016 O.Sezer <sezero@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef QENDIAN_H
#define QENDIAN_H
/* to detect byte order at runtime instead of compile time, define as 1 */
#undef ENDIAN_RUNTIME_DETECT
#define ENDIAN_RUNTIME_DETECT 0
/* try the system headers first: with BSD and derivatives,
* sys/types.h can pull in the correct header and defs. */
#include <sys/types.h>
#if !defined(BYTE_ORDER) /* include more if it didn't work */
# if defined(__linux__) || defined(__linux)
# include <endian.h>
# elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
defined(__FreeBSD_kernel__) /* Debian GNU/kFreeBSD */ || \
(defined(__APPLE__) && defined(__MACH__)) /* Mac OS X */ || \
defined(__DragonFly__)
# include <machine/endian.h>
# elif defined(__sun) || defined(__svr4__)
# include <sys/byteorder.h>
# elif defined(_AIX)
# include <sys/machine.h>
# elif defined(sgi)
# include <sys/endian.h>
# elif defined(__MINGW32__)
# include <sys/param.h>
# elif defined(__DJGPP__)
# include <machine/endian.h>
# elif defined(__EMX__)
# include <machine/endian.h>
# elif defined(__OS2__) && defined(__WATCOMC__)
# include <machine/endian.h>
# elif defined(__MORPHOS__)
# include <machine/endian.h>
# elif defined(__amigaos__) && defined(__NEWLIB__)
# include <machine/endian.h>
# elif defined(__amigaos__) && defined(__CLIB2__)
# if !defined(__amigaos4__)
# define __NO_NET_API /* have netinclude/ instead */
# endif
# include <unistd.h>
# endif
#endif /* endian includes */
/* alternative macro names: */
#if defined(__BYTE_ORDER) && !defined(BYTE_ORDER)
#define BYTE_ORDER __BYTE_ORDER
#endif
#if defined(__LITTLE_ENDIAN) && !defined(LITTLE_ENDIAN)
#define LITTLE_ENDIAN __LITTLE_ENDIAN
#endif
#if defined(__BIG_ENDIAN) && !defined(BIG_ENDIAN)
#define BIG_ENDIAN __BIG_ENDIAN
#endif
/* new gcc and clang versions pre-define the following: */
#if defined(__BYTE_ORDER__) && !defined(BYTE_ORDER)
#define BYTE_ORDER __BYTE_ORDER__
#endif
#if defined(__ORDER_LITTLE_ENDIAN__) && !defined(LITTLE_ENDIAN)
#define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__
#endif
#if defined(__ORDER_BIG_ENDIAN__) && !defined(BIG_ENDIAN)
#define BIG_ENDIAN __ORDER_BIG_ENDIAN__
#endif
#if !defined(PDP_ENDIAN)
#if defined(__ORDER_PDP_ENDIAN__)
#define PDP_ENDIAN __ORDER_PDP_ENDIAN__
#elif defined(__PDP_ENDIAN)
#define PDP_ENDIAN __PDP_ENDIAN
#else
#define PDP_ENDIAN 3412
#endif
#endif /* NUXI endian -- unsupported */
#if defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
# if (BYTE_ORDER != LITTLE_ENDIAN) && (BYTE_ORDER != BIG_ENDIAN)
# error "Unsupported endianness."
# endif
#else /* one of the definitions is mising. */
# undef BYTE_ORDER
# undef LITTLE_ENDIAN
# undef BIG_ENDIAN
# define LITTLE_ENDIAN 1234
# define BIG_ENDIAN 4321
#endif /* byte order defs */
#if !defined(BYTE_ORDER) /* good assumptions: */
/* try the compiler-predefined endianness macros.
* Ref.: https://sf.net/p/predef/wiki/Endianness/
*/
# if defined(__BIG_ENDIAN__) || defined(_BIG_ENDIAN)
# define BYTE_ORDER BIG_ENDIAN
# elif defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \
defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__)
# define BYTE_ORDER BIG_ENDIAN
# elif defined(__LITTLE_ENDIAN__) || defined(_LITTLE_ENDIAN)
# define BYTE_ORDER LITTLE_ENDIAN
# elif defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \
defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__)
# define BYTE_ORDER LITTLE_ENDIAN
/* assumptions based on OS and/or architecture macros. Some refs:
* predef/other/endian.h from the boost library
* http://labs.hoffmanlabs.com/node/544
* https://blogs.msdn.com/larryosterman/archive/2005/06/07/426334.aspx
*/
# elif defined(__i386) || defined(__i386__) || defined(__386__) || defined(_M_IX86) || defined(__I386__)
# define BYTE_ORDER LITTLE_ENDIAN /* any x86 */
# elif defined(__amd64) || defined(__x86_64__) || defined(_M_X64)
# define BYTE_ORDER LITTLE_ENDIAN /* any x64 */
# elif defined(__mc68000__) || defined(__M68K__) || defined(__m68k__) || defined(__MC68K__)
# define BYTE_ORDER BIG_ENDIAN /* Motorola 68k */
# elif defined(__sun) || defined(__svr4__) /* solaris */
# if defined(_LITTLE_ENDIAN) /* x86 */
# define BYTE_ORDER LITTLE_ENDIAN
# elif defined(_BIG_ENDIAN) /* sparc */
# define BYTE_ORDER BIG_ENDIAN
# endif
# elif defined(__hppa) || defined(__hppa__)
# define BYTE_ORDER BIG_ENDIAN /* PARISC */
# elif defined(__sparc) || defined(__sparc__)
# define BYTE_ORDER BIG_ENDIAN /* SPARC -- cf. boost/predef/other/endian.h */
# elif defined(__DJGPP__) || defined(__MSDOS__) || defined(__DOS__) || defined(_DOS)
# define BYTE_ORDER LITTLE_ENDIAN /* DOS */
# elif defined(__OS2__) || defined(__EMX__)
# define BYTE_ORDER LITTLE_ENDIAN /* OS2 */
# elif defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) || defined(__NT__) || defined(_Windows)
# define BYTE_ORDER LITTLE_ENDIAN /* Windows */
# endif
#endif /* good assumptions */
#if !defined(BYTE_ORDER) /* [un]safe assumptions: */
/* assumptions based on OS and/or architecture macros.
* proceed carefully: many of these are bi-endian CPUs.
*/
# if defined(__ppc__) || defined(__powerpc__) || defined(__POWERPC__) || defined(__PPC__)
# define BYTE_ORDER BIG_ENDIAN
# elif defined(__alpha__) || defined(__alpha)
# define BYTE_ORDER LITTLE_ENDIAN
# elif defined(__mips__) || defined(__MIPS__)
# define BYTE_ORDER BIG_ENDIAN
# endif
# if defined(BYTE_ORDER) && 0 /* change to 1 to for warnings */
# if (BYTE_ORDER == LITTLE_ENDIAN)
# warning "Using LIL endian as a SAFE default."
# else /*(BYTE_ORDER == BIG_ENDIAN)*/
# warning "Using BIG endian as a SAFE default."
# endif
# endif
#endif /* [un]safe assumptions */
#if !ENDIAN_RUNTIME_DETECT
#if !defined(BYTE_ORDER)
# error Could not determine BYTE_ORDER
#endif
/* for autotools compatibility */
#if (BYTE_ORDER == BIG_ENDIAN) && !defined(WORDS_BIGENDIAN)
# define WORDS_BIGENDIAN 1
#endif
#if (BYTE_ORDER != BIG_ENDIAN) && defined(WORDS_BIGENDIAN)
#error WORDS_BIGENDIAN defined for non-BIG_ENDIAN
#endif
#endif /* ! ENDIAN_RUNTIME_DETECT */
extern int host_byteorder;
extern int host_bigendian; /* bool */
extern int DetectByteorder (void);
extern void ByteOrder_Init (void);
/* byte swapping. most times we want to convert to
* little endian: our data files are written in LE
* format. sometimes, such as when writing to net,
* we also convert to big endian.
*/
#if ENDIAN_RUNTIME_DETECT
extern int (*BigLong) (int);
extern int (*LittleLong) (int);
#else /* ! ENDIAN_RUNTIME_DETECT */
extern int LongSwap (int);
#if (BYTE_ORDER == BIG_ENDIAN)
#define BigLong(l) (l)
#define LittleLong(l) LongSwap((l))
#else /* BYTE_ORDER == LITTLE_ENDIAN */
#define BigLong(l) LongSwap((l))
#define LittleLong(l) (l)
#endif /* swap macros */
#endif /* runtime det */
#endif /* QENDIAN_H */