/*!\file sys/swap.h
 * Swapping of short/long values.
 */

#ifndef __SYS_SWAP_BYTES_H
#define __SYS_SWAP_BYTES_H

#ifndef __SYS_CDEFS_H
#include <sys/cdefs.h>
#endif

#ifndef W32_NAMESPACE
#define W32_NAMESPACE(x) _w32_ ## x
#endif

#ifndef __NETINET_IN_H
#include <netinet/in.h>
#endif

#if defined(__dj_include_netinet_in_h_)
  #ifdef __GNUC__
  #error "Your using the wrong version of <netinet/in.h>. Ref. point 9 of the INSTALL file"
  #endif

#else
  #undef  ntohs
  #undef  htons
  #undef  ntohl
  #undef  htonl
  #define ntohs(x)  intel16(x)
  #define htons(x)  intel16(x)
  #define ntohl(x)  intel(x)
  #define htonl(x)  intel(x)
#endif

__BEGIN_DECLS

 /*
  * Hard to believe, but someone uses Watt-32 on a
  * Motorola/PowerPC embedded target.
  */
#if defined(BIG_ENDIAN_MACHINE) || defined(USE_BIGENDIAN)
  #define intel(x)    x
  #define intel16(x)  x

#elif defined(__GNUC__)
  #define intel(x)   __ntohl(x)
  #define intel16(x) __ntohs(x)

  /*
   * Ripped (and adapted) from <linux/include/asm-386/byteorder.h>
   */
  /*@unused@*/ extern __inline__ unsigned long __ntohl (unsigned long x)
  {
    __asm__ __volatile (
             "xchgb %b0, %h0\n\t"   /* swap lower bytes  */
             "rorl  $16, %0\n\t"    /* swap words        */
             "xchgb %b0, %h0"       /* swap higher bytes */
            : "=q" (x) : "0" (x));
    return (x);
  }

  /*@unused@*/ extern __inline__ unsigned short __ntohs (unsigned short x)
  {
    __asm__ __volatile__ (
              "xchgb %b0, %h0"       /* swap bytes */
            : "=q" (x) : "0" (x));
    return (x);
  }

#elif defined(__WATCOMC__) && defined(__FLAT__) /* Watcom 32-bit */
  #define intel(x)   __ntohl(x)
  #define intel16(x) __ntohs(x)

  extern unsigned long __ntohl (unsigned long x);
  #pragma aux  __ntohl =     \
              "xchg al, ah"  \
              "ror  eax, 16" \
              "xchg al, ah"  \
              parm   [eax]   \
              modify [eax];

  extern unsigned short __ntohs (unsigned short x);
  #pragma aux __ntohs =     \
              "xchg al, ah" \
              parm   [ax]   \
              modify [ax];

#elif defined(__WATCOMC__) && !defined(__FLAT__) /* Watcom 16-bit */
  #define intel(x)   __ntohl(x)
  #define intel16(x) __ntohs(x)

  extern unsigned long __ntohl (unsigned long x);
  #pragma aux  __ntohl =     \
              "xchg al, dh"  \
              "xchg ah, dl"  \
              parm   [dx ax] \
              modify [dx ax];

  extern unsigned short __ntohs (unsigned short x);
  #pragma aux __ntohs =     \
              "xchg al, ah" \
              parm   [ax]   \
              modify [ax];  

#elif (defined(__BORLANDC__) && defined(__FLAT__)) || /* bcc32, dmc -mx */ \
      (defined(__DMC__) && (__INTSIZE==4))
  #include <dos.h>

  #define intel(x)    __ntohl(x)
  #define intel16(x)  __ntohs(x)

  #define __ntohs(x)  (_AX = x, \
                       __emit__(0x86,0xC4),      /* xchg al, ah */ \
                       _AX)

  #define __ntohl(x)  (_EAX = x, \
                       __emit__(0x86,0xC4),      /* xchg al, ah  */ \
                       __emit__(0xC1,0xC8,0x10), /* ror  eax, 16 */ \
                       __emit__(0x86,0xC4),      /* xchg al, ah  */ \
                       _EAX)

#elif defined(__CCDL__) && defined(__386__)      /* LadSoft 386 */
  #define intel(x)    __ntohl(x)
  #define intel16(x)  __ntohs(x)

  static unsigned long __ntohl (unsigned long x)
  {
    asm { mov  eax, [x]
          xchg al, ah
          ror  eax, 16
          xchg al, ah
        }
    return (_EAX);
  }
  static unsigned short __ntohs (unsigned short x)
  {
    asm { mov  ax, [x]
          xchg al, ah
        }
    return (unsigned short)_EAX;  /* doesn't have _AX */
  }

#else  /* no inlining possible (or worth the effort) */
  #define intel   W32_NAMESPACE (intel)
  #define intel16 W32_NAMESPACE (intel16)
  #define NO_INLINE_INTEL

  extern unsigned long  cdecl intel   (unsigned long x);
  extern unsigned short cdecl intel16 (unsigned short x);
#endif

__END_DECLS

#endif /* __SYS_SWAP_BYTES_H */
