#ifndef _TYPES_H
#define _TYPES_H



#include <limits.h>                     /* ULONG_MAX UINT_MAX UCHAR_MAX */
#include <stddef.h>                     /* offsetof() */



#define TRUE  1
#define FALSE 0


/* derive OS from processor and SVR4 flavor */

#if !defined(NETRAMET)  /* NETRAMET uses GNU autoconfig to do this */
# ifdef __alpha__
#     define OSF
# else
#     ifdef __sun__
#         ifdef __svr4__
#             define SOLARIS
#         else
#             define SUNOS
#         endif
#     endif
# endif
#else  /* NeTraMet */
# if !defined(DOS)
# define __unix__  1  /* Not defined by NetBSD */
# endif
#endif



#ifdef __sun
#   define HOST_IS_BIG_ENDIAN TRUE
#else
#   define HOST_IS_BIG_ENDIAN FALSE
#endif



typedef unsigned char Bit8;
#define BIT8_MAX UCHAR_MAX
typedef char Signed8;
#define SIGNED8_MAX CHAR_MAX

typedef unsigned short Bit16;
#define BIT16_MAX USHRT_MAX
typedef short Signed16;
#define SIGNED16_MAX SHRT_MAX

#define BIT24_MAX 16777215UL

#if __alpha
    typedef unsigned Bit32;
    typedef int Signed32;
    typedef unsigned long Bit64;
#   define BIT64_AVAILABLE TRUE
#   define BIT32_MAX UINT_MAX
#   define SIGNED32_MAX INT_MAX
#   define SIGNED32_MIN INT_MIN
#else
    typedef unsigned long Bit32;
    typedef long Signed32;
    typedef struct Bit64_class Bit64;
#   define BIT64_AVAILABLE FALSE
#   define BIT32_MAX ULONG_MAX
#   define SIGNED32_MAX LONG_MAX
#   define SIGNED32_MIN LONG_MIN
#endif

#define DWORD_SIZE    4294967296.0      /* 4G */
#ifdef __BORLANDC__
    // must be called before any further arithmetic occurs!
    //
#   define ADD_HAD_CARRY(before,after)       (_FLAGS&1)
#   define SUBTRACT_HAD_BORROW(before,after) (_FLAGS&1)
#else
    /* safe to call at any time */
 
#   define ADD_HAD_CARRY(before,after)       (after<before)
#   define SUBTRACT_HAD_BORROW(before,after) (after>before)
#endif


    /* 64-bit integer, for use when your compiler does
       not support such a thing intrinsically
      
       unfortunately, this was also used as a base class
       of PentiumClock, and several fools rely upon its having
       2 separate 32-bit fields, so this must exist even when
       the compiler or CPU has an intrinsic 64-bit integer
    */
    struct Bit64_class
    {

#if HOST_IS_BIG_ENDIAN
        Bit32 high;
        Bit32 low;
#else
        Bit32 low;
        Bit32 high;
#endif

#ifdef __cplusplus
        // no destructor needed

        // construct w/o args
        //
        Bit64_class()
        {
        }

        // construct from one unsigned 32-bit integer
        //
        Bit64_class( Bit32 low0 ) :
            low( low0 ),
            high( 0 )
        {
        }

        // construct from two unsigned 32-bit integers
        //
        Bit64_class( Bit32 high0, Bit32 low0 ) :
            low( low0 ),
            high( high0 )
        {
        }

        // construct from double-precision floating
        // point using that assignment operator
        //
        Bit64_class( double second )
        {
            *this = second;
        }

        // assignment from double-precision floating point operator
        //
        Bit64_class &operator =( double second )
        {
            high = Bit32( second / DWORD_SIZE );
            low  = Bit32( second - (high * DWORD_SIZE) );
            return *this;
        }

        // assignment from unsigned 32-bit integer
        //
        Bit64_class &operator =( Bit32 second )
        {
            high = 0;
            low  = second;
            return *this;
        }

#if 0
        // type conversion to single-precision floating point
        //
        // causes compiler confusion, and is mostly unwanted
        // since printf() and our statistics want double,
        // so we dont allow this member function to compile
        //
        operator float() const
        {
            return high * (float)DWORD_SIZE + low;
        }
#endif

        // type conversion to double-precision floating point
        //
        operator double() const
        {
            return high * (double)DWORD_SIZE + low;
        }

        // subtraction operator overload
        //
        Bit64_class operator -( const Bit64_class &second ) const
        {
            Bit64_class result;

            result.high = high - second.high;
            result.low = low - second.low;

            if( SUBTRACT_HAD_BORROW( low, result.low ) )

                // believe it or not, the low word
                // is already correct!!!
                //

                // fix the high dword
                //
                result.high--;

            return result;
        }

        // subtraction with assignment operator overload
        //
        Bit64_class &operator -=( const Bit64_class &second )
        {
#ifndef __BORLANDC__
            Bit32 before = low;
#endif
            high -= second.high;
            low  -= second.low;

            // if there was a borrow...
            //
            if( SUBTRACT_HAD_BORROW( before, low ) )

                // believe it or not, the low word
                // is already correct!!!
                //

                // fix the high dword
                //
                high--;

            return *this;
        }

        // addition operator overload
        //
        Bit64_class operator +( const Bit64_class &second ) const
        {
            Bit64_class result;

            result.high = high + second.high;
            result.low = low + second.low;

            if( ADD_HAD_CARRY( low, result.low ) )

                // believe it or not, the low word
                // is already correct!!!
                //

                // fix the high dword
                //
                result.high++;

            return result;
        }

        // addition with assignment operator overload
        //
        Bit64_class &operator +=( const Bit64_class &second )
        {
            high += second.high;
            low  += second.low;

            if( ADD_HAD_CARRY( second.low, low ) )

                // believe it or not, the low word
                // is already correct!!!
                //

                // fix the high dword
                //
                high++;

            return *this;
        }

        // addition of Bit32 with assignment operator overload
        //
        // helps avoid the construction of a temporary Bit64_class
        // such as when adding IP packet length to a byte count
        // in the fast path (per-packet processing) of FS2FLOWS.C
        //
        Bit64_class &operator +=( const Bit32 second )
        {
            low += second;

            // I sure wish we could cause the CPUs
            // "add 0 with carry to high"
            // instruction to be generated somehow,
            // so this code could be unconditional...
            //
            if( ADD_HAD_CARRY( second, low ) )

                // believe it or not, the low word
                // is already correct!!!
                //

                // fix the high dword
                //
                high++;

            return *this;
        }

#if 0
        // division operator overload
        //
        Bit64_class operator /( const Bit64_class &second ) const
        {
        }

        // division operator overload
        //
        Bit64_class operator /( const Bit32 second ) const
        {
            Bit64_class result;

            result.high = high / second.high;
???         result.low = DWORD_SIZE*(high % second.high) + second.low;

            return result;
        }
#endif

        // equality comparison operator overload
        //
        int operator ==( const Bit64_class &second ) const
        {
            return low==second.low && high==second.high;
        }

        // less than or equal comparison operator overload
        //
        int operator <=( const Bit64_class &second ) const
        {
            return high<second.high
               || (high==second.high && low<=second.low);
        }

        // greater than or equal comparison operator overload
        //
        int operator >=( const Bit64_class &second ) const
        {
            return high>second.high
               || (high==second.high && low>=second.low);
        }

        // greater than comparison operator overload
        //
        int operator >( const Bit64_class &second ) const
        {
            return high>second.high
               || (high==second.high && low>second.low);
        }

        // less than comparison operator overload
        //
        int operator <( const Bit64_class &second ) const
        {
            return high<second.high
               || (high==second.high && low<second.low);
        }
#endif  // defined(__cplusplus)
    };

typedef struct
{
    Bit32 offset;
    Bit16 selector;
} Bit48;

/* pointer to a function that accepts
 * no arguments and returns nothing
 */
typedef void (*vfp)( void );

/* increment up to some limit, but no further
 */
#define saturated_inc(x,y) if((x)<(y)) (x)++
#define saturated_inc_bit8(x) saturated_inc(x,255)
#define saturated_dec(x) if((x)>0) (x)--

/* fold the halves of words (of various sizes) together
 */
#define fold_64_to_32(x) ((((x)>>32) ^ (x)) & 0xFFFFFFFF)
#define fold_32_to_16(x) ((((x)>>16) ^ (x)) & 0xFFFF)
#define fold_32_to_8(x) ((((x)>>24) ^ ((x)>>16) ^ ((x)>>8) ^ (x)) & 0xFF)

/* convert a pointer to a field inside a structure
 * to a pointer to the structure itself
 */
#define struct_from_field(around,field,ptr) ((struct around *) ((Bit8 *)ptr - offsetof(struct around,field)))

#ifdef __unix__
/* lets DOS programs, which try to specify to open()
 * whether CR-LF should be converted to/from LF,
 * compile under UNIX
 */
#define O_BINARY        0
#define O_TEXT          0

/* lets DOS programs, which try to print the textual
 * description of a C library error, compile and run
 * under UNIX
 */
#define _sys_errlist    sys_errlist
extern int sys_nerr;
#if !defined(ALPHA) && !defined(IRIX) && !defined(NETBSD)
extern const char *const sys_errlist[];
#endif

#define stricmp         strcasecmp
extern int      strcasecmp( /* const char *s1, const char *s2 */ );

/* lets DOS programs, which try to do special actions
 * when a key is pressed, compile and run under UNIX
 */
#include <unistd.h>                     /* STDIN_FILENO */
#ifdef __cplusplus
extern "C"
#endif
long dataready( int handle );
#define kbhit() dataready(STDIN_FILENO)
#endif

#endif      /* not included yet */
