/********************************************************************
 * Generic routines, such as file io, memory allocation, etc, 
 * with convenient error wrappers.
 ********************************************************************/

#ifndef __GENERIC
#define __GENERIC

#define ERR_FILEOPEN 1
#define ERR_MALLOC 2
#define ERR_FREE 3
#define ERR_ASSERT -1

#define FALSE 0
#define TRUE 1

typedef int BOOL;

#define abs(x) ((x > 0) ? (x) : (-(x)))
#define max(a,b) ((a)>(b) ? (a) : (b))
#define min(a,b) ((a)<(b) ? (a) : (b))
// NB: Consider mid(2,4,1)!!  Assumes a<c.
//#define mid(a,b,c) (min(max(a, b), c))
#define bound(a,b,c) ((a)>(b) ? (a) \
                              : ((b)<(c) ? (b) : (c)))
// Works regardless:
#define mid(a,b,c) ((a)<(b) ? ((b) < (c) ? (b) : ((a) < (c) ? (c) : (a))) \
                            : ((b) > (c) ? (b) : ((a) > (c) ? (c) : (a))))
//#define max3(a, b, c) (max(a, max(b, c)))
#define max3(a,b,c) ((b)>(c) ? ((a)>(b) ? (a) : (b)) \
                             : ((a)>(c) ? (a) : (c)))
#define min3(a,b,c) ((b)<(c) ? ((a)<(b) ? (a) : (b)) \
                             : ((a)<(c) ? (a) : (c)))
//#define max4(a, b, c, d) (max(max(a,b), max(c, d)))
#define max4(a,b,c,d) ((a)>(b) ? ((c)>(d) ? ((a)>(c) ? (a) : (c))  \
                                          : ((a)>(d) ? (a) : (d))) \
                               : ((c)>(d) ? ((b)>(c) ? (b) : (c))  \
                                          : ((b)>(d) ? (b) : (d))))
#define min4(a,b,c,d) ((a)<(b) ? ((c)<(d) ? ((a)<(c) ? (a) : (c))  \
                                          : ((a)<(d) ? (a) : (d))) \
                               : ((c)<(d) ? ((b)<(c) ? (b) : (c))  \
                                          : ((b)<(d) ? (b) : (d))))

#define sgn(a) ((a)<0 ? -1 : (a) ? 1 : 0)

#define ASSERT

char *OptGetMem(int length);
void OptFreeMem(char *p);

int FileSize(FILE *fp);
FILE *WriteOpenFP(char *fname);
FILE *ReadOpenFP(char *fname);
void SetErrorHandler(void (*callback)(int error, char *text));
void CRASH(int num, char *text);
char *ourstrdup(char *s);

void _assert(int expr, char *file, int line);

    #define GetMem(len) (OptGetMem(len))
    #define FreeMem(p) (OptFreeMem((char *)p))

// Personal assert class....
#ifdef ASSERT
    #define assert(expr) (_assert((int)(expr), __FILE__, __LINE__ ))
#else
    #define assert(expr) ((void)0)
#endif

#endif
