// C++ code Copyright (C) David R. Evans G4AMJ/NQ0I

#ifndef DEFS_DOSH
#define DEFS_DOSH

#define INTEL

typedef unsigned char boolean;
typedef unsigned char byte;
typedef unsigned char octet;

#define then
#define false	0
#define true	1
#define forever while(true)
#define START(x) fseek(x, 0, 0)
#define END(x) fseek(x, 0, 2)

#define reveal(type, name, internalname) \
  inline type name (void) const \
    { return (internalname) ; }

// define some items of standard length (these would be neater as classes,
// but for now this should be sufficient)
#define int16 int
#define int32 long int

#define uint16 unsigned int16
#define uint32 unsigned int32
#define uint unsigned int

// byte inversion routines. These swap in place
//extern void invert(uint16&);
//extern void invert(uint32&);

// The Borland compiler has a bug in that two identical typedefs are
// flagged as an error, so we have to include the whole mess here. Argh!
#include <stdio.h>

template <class T> inline int SIGN(T x)
  { return ((x < 0) ? -1 : ((x > 0) ? 1 : 0)) }

template <class T> inline T MAX(T x, T y)
  { return ((x > y) ? x : y); }

template <class T> inline T MIN(T x, T y)
  { return ((x < y) ? x : y); }

template <class T> inline T SQR(T x)
  { return (x * x); }

template <class T> void invert(T& x)
{ if (ODD(sizeof(T))) then
    return;
  byte* temp = (byte*)&x;
  for (int n = 0; n < sizeof(T) / 2; n++)
  { register byte t = temp[2*n];
    temp[2*n] = temp[2*n + 1];
    temp[2*n + 1] = t;
  }
}

// GNU does not permit an invisible third parameter 
template <class T> inline int READ(FILE* fp, T& var)
  { const int status = fread(&var, sizeof(T), 1, fp);
    if (EVEN(sizeof(T))) then
    { // circumvent production of temporary
      //T* temp = &var;
      //invert(*temp);
      invert(var);
    }
    return status;
  }

template <class T> inline int WRITE(FILE* fp, T& var)
  { 
    if (sizeof(T) > 1) then
      invert(T);
    return(fwrite(&var, sizeof(T), 1, fp));
}

// if two values are not identical, abort with a message. This is
// a "better" assert.
template <class T> void _TST(T& obj1, T& obj2, const char* msg,
                             const char* filename, const int line_nr)
{ if (!(obj1 == obj2)) then    // == more likely to be defined than !=
    _FE(msg, filename, line_nr);
}

extern void _CST(const unsigned long, const unsigned long, const char*, const int);

#define check_stack(x, y) _CST(x, y, __FILE__, __LINE__)
#define heap_check(x) _HC(x, __FILE__, __LINE__)
#define fatal_error(x) _FE(x, __FILE__, __LINE__)

#define nonfatal_error(x) _NFE(x, __FILE__, __LINE__)
#define warning(x) _NFE(x, __FILE__, __LINE__)

extern void _FE(const char*, const char*, const int);
extern void _HC(void*, const char*, const int);
extern void _NFE(const char*, const char*, const int);

#ifdef TRACE
#define trace(x) _TRACELOG(x, __FILE__, __LINE__)
#else
#define trace(x)
#endif

extern void _TRACELOG(const char*, const char*, const int);

extern void information(const char*);

// provide a yield function for non pre-emptive multitasking systems
// (… la Windows)
inline void yield(void) { }

#ifndef PI
#define PI 3.14159265
#endif

template <class T> int read_binary(FILE* fp, T& var)
{ const int status = fread(&var, sizeof(T), 1, fp);
  if (EVEN(sizeof(T))) then
    invert(var);
  return status;
}

template <class T> int write_binary(FILE* fp, T& var)
{ if (sizeof(T) > 1) then
    invert(var);
  return(fwrite(&var, sizeof(T), 1, fp));
}

template <class T> void destroy(T* pointer)
{ if (pointer) then
    delete pointer;
  pointer = 0;
}

template <class T> void destroy_array(T* pointer)
{ if (pointer) then
    delete [] pointer;
  pointer = 0;
}

#endif
