/*
 * Title: General Utility Defines and Prototypes
 * Utilities for portability, string manipulation and datastructure management
 *
 * Copyright (C) 2001-2006 Aron Rubin Lockheed Martin Advanced Technology Labs
 * $Id: general_utils.h,v 1.1 2006/10/24 18:18:11 arubin Exp $
 */

#ifndef GENERAL_UTILS_H
#define GENERAL_UTILS_H
#define UTIL_H

/* -------------------------------------------------------------------- */
/*      The following apparently allow you to use strcpy() and other    */
/*      functions judged "unsafe" by microsoft in VS 8 (2005).          */
/* -------------------------------------------------------------------- */
#ifdef _MSC_VER
#  ifndef _CRT_SECURE_NO_DEPRECATE
#    define _CRT_SECURE_NO_DEPRECATE
#  endif
#  ifndef _CRT_NONSTDC_NO_DEPRECATE
#    define _CRT_NONSTDC_NO_DEPRECATE
#  endif
#endif

#if defined(__MINGW32__) || defined(__MSYS__)
#include <windows.h>
#endif


#ifndef __GNUC__
# define __DLL_IMPORT __declspec(dllimport)
#else
# define __DLL_IMPORT __attribute__((dllimport)) extern
#endif

#if defined (BUILD_ddd_DLL) || !defined (__WIN32__)
# define DLL_IMPORT extern
#else
# define DLL_IMPORT __DLL_IMPORT
#endif

#ifdef __APPLE__
#define __USE_POSIX
#endif

#ifdef __cplusplus
#define BEGIN_C_BLOCK extern "C" {
#define END_C_BLOCK }
#else  // __cplusplus
#define BEGIN_C_BLOCK
#define END_C_BLOCK
#endif // __cplusplus

BEGIN_C_BLOCK


/**********************************************\
       Section: Missing Functions Support
\**********************************************/

#ifndef __USE_POSIX
// macro: strtok_r
//   re-entrant string tokenize (POSIX.1c)
#  define strtok_r(s, sep, nextp) c_strtok_r(s, sep, nextp)
// macro: usleep
//   microsecond sleep (BSD 4.3)
#  define usleep(t) Sleep((t)*0.001)
// macro: sleep
//   second sleep (POSIX.1)
#  define sleep(t) Sleep((t)*1000.0)
// macro: fsync
//   synchronize a file's complete in-core state with that on disk (POSIX.1b)
#  define fsync(__fd) ((FlushFileBuffers ((HANDLE) _get_osfhandle (__fd))) ? 0 : -1)
// macro: strdup
//   duplicate a string (SVID 3, BSD 4.3)
#  define strdup(s) _strdup(s) // strcpy( malloc( strlen(s) ), (s) )
// macro: strndup
//   duplicate up to a specified number of characters of a string (GNU)
#  define strndup(s,n) c_strndup(s,n)
// macro: strcasecmp
//   compare two strings without respect to case (BSD 4.4)
#  define strcasecmp(s1, s2) stricmp(s1, s2)
// macro: strcasecmp
//   compare up to a specified number of characters of two strings without
//   respect to case (BSD 4.4)
#  define strncasecmp(s1, s2) _mbsnbicmp(s1, s2)
//typedef unsigned long in_addr_t;
#endif

// macro: inline_strfrob
//   encrypts a string by exclusive-ORing each character with the number 42
#define inline_strfrob(s) ({ char *p; for( p = (char *)(s); *p; *p++ ^= 42 ); })

#if !defined( mempcpy ) && !defined( __mempcpy )
// macro: mempcpy
#  define mempcpy(dst,src,n) (memcpy(dst,src,n) + (n))
#endif

#ifndef MAX
// macro: MAX
#  define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
// macro: MIN
#  define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
#ifndef CLAMP
// macro: CLAMP
#  define CLAMP(a,b,c) MAX((a),MIN((b),(c)))
#endif
#ifndef ABS
// macro: ABS
#  define ABS(x) ((x) < 0 ? -(x) : (x))
#endif
#ifndef SQR
// macro: SQR
#  define SQR(x) ((x)*(x))
#endif

#ifndef DBL_EPSILON
#define DBL_EPSILON 1e-9
#endif
#ifndef FLT_EPSILON
#define FLT_EPSILON 1e-5
#endif
#ifndef FLT_MAX
#define FLT_MAX 1E+37
#endif


/**********************************************\
         Section: Missing Types Support
\**********************************************/

#ifndef ulong
// type: ulong
//   alias of unsigned long int
#  define ulong unsigned long int
#endif
#ifndef ushort
// type: ushort
//   alias of unsigned short int
#  define ushort unsigned short int
#endif
#ifndef uint
// type: uint
//   alias of unsigned int
#  define uint unsigned int
#endif

#ifndef __uint32_t_defined
#  define __uint32_t_defined
  // type: uint16_t
  //   unsigned 16 bit integer
  typedef unsigned short int uint16_t;
  // type: uint32_t
  //   unsigned 16 bit integer
  typedef unsigned int uint32_t;
  // type: uint64_t
  //   unsigned 16 bit integer
  typedef unsigned long long int uint64_t;
#endif


/**********************************************\
      Section: Memory Allocation Support
\**********************************************/

#ifndef c_new
// macro: c_new
//   allocate memory for _n_ members of _t_ type
#define c_new(t,n) ((t *)malloc( sizeof(t)*(n) ))
// macro: c_new
//   allocate memory zeroed for _n_ members of _t_ type
#define c_new0(t,n) ((t *)calloc( (n), sizeof(t) ))
// macro: c_dup
//   duplicate _n_ members of _t_ type pointed to by _p_
#define c_dup(p,t,n) ((t *)memcpy( malloc( sizeof(t)*(n) ), (char *)(p), sizeof(t)*(n) ))
#define c_strdup(s) strcpy( malloc( strlen(s) ), (s) )
#endif

#ifndef c_renew
// macro: c_renew
//   expand or contract an existing memory allocation
#  define c_renew(p,t,n) ((t *)realloc( (p), sizeof(t)*(n) ))
#  define c_renew0(p,t,oldn,n) ({					\
      unsigned long size = sizeof(t)*(n), osize = sizeof(t)*(oldn);	\
      unsigned long dn = size - osize;					\
      unsigned char *newp = realloc( (p), size );			\
      if( newp && dn > 0 ) memset( newp + osize, 0, dn );		\
      newp;								\
    })
#endif

/**********************************************\
         Section: Polymophism Support
\**********************************************/

// macro: C_STRUCT_OFFSET
//   return the offset or a member of a structure
#define C_STRUCT_OFFSET(struct_type, member)	\
    ((long) ((unsigned char *) &((struct_type*) 0)->member))
// macro: C_STRUCT_OFFSET_P
//   return the member of a structure instance at _struct_offset_ bytes
#define C_STRUCT_MEMBER_P(struct_p, struct_offset)   \
    ((void *) ((unsigned char *) (struct_p) + (long) (struct_offset)))
// macro: C_STRUCT_MEMBER
//   return the member of a structure instance at _struct_offset_ bytes
#define C_STRUCT_MEMBER(member_type, struct_p, struct_offset)   \
    (*(member_type*) C_STRUCT_MEMBER_P ((struct_p), (struct_offset)))


/**********************************************\
          Section: Debugging Support
\**********************************************/

// macro: logmsg
//    Print a log message if the verbosity is set high enough
// note:
//   VERBOSITY_VAR must be defined for this to work
#define logmsg(lvl,fmt,args...) ({if( (VERBOSITY_VAR) >= (lvl)) printf(fmt, ## args);})

// macro: logmsg
//    Print a debug message if the verbosity is set high enough and DEBUG is on
// note:
//   VERBOSITY_VAR must be defined for this to work
#ifdef DEBUG
#define dbgmsg(lvl,fmt,args...) ({if( (DEBUG_VERBOSITY_VAR) >= (lvl)) printf(fmt, ## args);})
#else
#define dbgmsg(lvl,fmt,args...)
#endif


/**********************************************\
          Section: Byte Order Support
\**********************************************/

// macro: bswap16
#ifndef bswap16
#define bswap16(x) ({ (x) = (((x) & 0x00ffU) << 8) | (((x) & 0xff00U) >> 8); })
#endif
// macro: bswap32
#ifndef bswap32
#define bswap32(x) \
  ({ (x) =			     \
    ( (((x) & 0x000000ffUL) << 24) | \
      (((x) & 0x0000ff00UL) <<  8) | \
      (((x) & 0x00ff0000UL) >>  8) | \
      (((x) & 0xff000000UL) >> 24) ); \
  })
#endif
// macro: bswap64
#ifndef bswap64
#define bswap64(x) \
  ({ (x) =				      \
    ( (((x) & 0x00000000000000ffULL) << 56) | \
      (((x) & 0x000000000000ff00ULL) << 40) | \
      (((x) & 0x0000000000ff0000ULL) << 24) | \
      (((x) & 0x00000000ff000000ULL) <<  8) | \
      (((x) & 0x000000ff00000000ULL) >>  8) | \
      (((x) & 0x0000ff0000000000ULL) >> 24) | \
      (((x) & 0x00ff000000000000ULL) >> 40) | \
      (((x) & 0xff00000000000000ULL) >> 56) ); \
  })
#endif
// macro: bswapper
#ifndef bswapper
#define bswapper(data,pattern)				\
  ({char *ptr = (char *)(data);				\
    size_t i;						\
    for( i = 0; (pattern)[i]; i++ ) {			\
      switch( (pattern)[i] ) {				\
       case -8: bswap64( *(uint64_t *)ptr ); break;	\
       case -4: bswap32( *(uint32_t *)ptr ); break;	\
       case -2: bswap16( *(uint16_t *)ptr ); break;	\
      }							\
      ptr += ABS( (pattern)[i] );			\
    }							\
  })
#endif

/**********************************************\
       Section: Math and Vector Speedups
\**********************************************/

// Group: Vector Speedup Macros

// func: minus_init3v
//   Calculate difference of two 3 element vectors (arrays) as initializer
#define minus_init3v(v1,v2) {(v1)[0] - (v2)[0], (v1)[1] - (v2)[1], (v1)[2] - (v2)[2]}

// func: minus_init2v
//   Calculate difference of two 2 element vectors (arrays) as initializer
#define minus_init2v(v1,v2) {(v1)[0] - (v2)[0], (v1)[1] - (v2)[1]}

// func: minus3v
//   Calculate difference of two 3 element vectors (arrays)
#define minus3v(dv,v1,v2) {dv[0] = (v1)[0] - (v2)[0];\
                           dv[1] = (v1)[1] - (v2)[1];\
                           dv[2] = (v1)[2] - (v2)[2];}

// func: minus2v
//   Calculate difference of two 2 element vectors (arrays)
#define minus2v(dv,v1,v2) {dv[0] = (v1)[0] - (v2)[0];\
                           dv[1] = (v1)[1] - (v2)[1];}

// func: dotnv
//   Calculate dot product of two _n_ element vectors (arrays)
#define dotnv(v1,v2,dim) { int i; double dot = 0.0;\
    for( i = 0; i < dim; i++ ) dot += (v1)[i]*(v2)[i]; dot;}

// func: dot3v
//   Calculate dot product of two 3 element vectors (arrays)
#define dot3v(v1,v2) ((v1)[0]*(v2)[0] + (v1)[1]*(v2)[1] + (v1)[2]*(v2)[2])

// func: hypotnv
//   Calculate hypotenuse of the difference of two _n_ element vectors (arrays)
#define hypotnv(v1,v2,dim) { int i; double dv, mag2 = 0.0;\
    for( i = 0; i < dim; i++ ) { dv = (v2)[i] - (v1)[i]; mag2 += dv*dv; } \
    sqrt( mag2 ); }

// macro: hypot3v
//   Calculate hypotenuse of a 3 element vector (array)
#define hypot3v(vec) sqrt( dot3v(vec,vec) )

// macro: hypot2v
//   Calculate hypotenuse of a 2 element vector (array)
#define hypot2v(vec) hypot( (vec)[0], (vec)[1] )

// func: scale3v
//   Scale a 3 element vector (array) into _svec_
#define scale3v(svec, vec, scale) {(svec)[0] = (vec)[0]*scale;(svec)[1] = (vec)[1]*scale;(svec)[2] = (vec)[2]*scale;}

// func: scalein3v
//   Scale 3 element vector (array) in place.
#define scalein3v(vec, scale) {(vec)[0] *= scale;(vec)[1] *= scale;(vec)[2] *= scale;}

// func: scaleaccum3v
//   Scale a 3 element vector (array) into an accumulation vector (array).
//   Source vector and accumulation vector may be the same.
#define scaleaccum3v(acc, vec, scale) {(acc)[0] += (vec)[0]*scale;(acc)[1] += (vec)[1]*scale;(acc)[2] += (vec)[2]*scale;}

// func: copy3v
#define copy3v(d,s) {(d)[0] = (s)[0];(d)[1] = (s)[1];(d)[2] = (s)[2];}

// func: normalize3v
//   Normalize a 3 element vector in place.
#define normalize3v(vec) {double d = hypot3v(vec);if( d > 0.0 ) scalein3v(vec,d);}

float pt2edge3f( float *pt, float *vrt1, float *vrt2 );
float pt2poly3f( float *pt, int numvrts, int stride, float *vrts );
float poly2poly3f( int numvrts1, int stride, float *vrts1, int numvrts2, float *vrts2 );
int edgeintersect3f( float *vrt1, float *vrt2, float *vrt3, float *vrt4,
		     float *pta, float *ptb, double *prja, double *prjb );
int edgeintersect2f( float *vrt1, float *vrt2, float *vrt3, float *vrt4,
		     float *pti, double *prja, double *prjb );
// func: recip_sqrt
//   Ultra fast approximation to 1f/sqrt(x) that exploits ieee floating point
#define recip_sqrt(_x) ({			\
      float x = (_x), xhalf = 0.5f*x;		\
      int i = *(int *)&x;			\
      i = 0x5f375a86 - (i>>1);			\
      x = *(float *)&i;				\
      x = x*(1.5f - xhalf*x*x);			\
    })

/**********************************************\
        Section: Utility Data Structures
\**********************************************/

typedef struct DataList DataList;
// struct: DataList
struct DataList {
  void *data;
  DataList *next;
};

// func: DListCompareFunc
typedef int (*DListCompareFunc)( void *a, void *b );

// define: DIR_ENTRY_DIRSEP_CHR
//
// define: DIR_ENTRY_DIRSEP_STR
#ifdef __USE_POSIX
#define DIR_ENTRY_DIRSEP_CHR '/'
#define DIR_ENTRY_DIRSEP_STR "/"
#else
#define DIR_ENTRY_DIRSEP_CHR '\\'
#define DIR_ENTRY_DIRSEP_STR "\\"
#endif
typedef enum DirEntryType {
  DIR_ENTRY_REG_FILE,
  DIR_ENTRY_DIRECTORY,
  DIR_ENTRY_BLOCK_DEV,
  DIR_ENTRY_CHAR_DEV,
  DIR_ENTRY_SOCKET,
  DIR_ENTRY_FIFO
} DirEntryType;
typedef struct DirEntry DirEntry;
// struct: DirEntry
struct DirEntry {
  char *name;
  DirEntryType type;
  unsigned char month;
  unsigned char day;
  unsigned short year;
  unsigned char hour;
  unsigned char minute;
  unsigned short second;
  unsigned long long size;

  DirEntry *next;
};

typedef struct HashTreeNode HashTreeNode;
typedef struct HashTreeNode HashTable;
struct HashTreeNode {
  size_t size;
  void *key;
  union {
    void *data;
    HashTreeNode *branch;
    HashTreeNode **nodes;
  } o;
  HashTreeNode *next;
};

// Group: SXML Types

// func: SXMLStartTagFunc
typedef void (*SXMLStartTagFunc)( char *name, char *attrs[], void *ud );
// func: SXMLEndTagFunc
typedef void (*SXMLEndTagFunc)( char *name, void *ud );
// func: SXMLCharsFunc
typedef void (*SXMLCharsFunc)( char *chars, void *ud );

typedef struct SXMLNsHandler SXMLNsHandler;
struct SXMLNsHandler {
  char *nsname;
  char *uri;
  
  SXMLStartTagFunc start;
  SXMLEndTagFunc end;
  SXMLCharsFunc chars;
  void *user_data;

  SXMLNsHandler *next;
};

typedef struct SXMLNsContext SXMLNsContext;
struct SXMLNsContext {
  char *spool;
  uint spool_len;

  SXMLNsHandler *default_ns;
  SXMLNsHandler *last_ns;
  HashTable *handlers;
};


/**********************************************\
      Section: Utility Routine Prototypes
\**********************************************/

double get_current_time();
char *get_tok_quote( char *str, char *delim, char **save_ptr );
char *c_strndup( char *str, size_t len );
char *c_strtok_r( char *str, char *delim, char **save_ptr );
char *c_strtok_nd( char *str, char *delim, char **save_ptr );
char *strtrim( char *str );
char *strtrimquote( char *str );
char *strtrimtag( char *str );
char *memspool( char *spool, uint *len, const void *data, const size_t n );
char *chrspool( char *spool, uint *len, char chr );
char *strspool( char *spool, uint *len, const char *str );
int strrncmp( char *s1, char *s2, size_t n );
char *sstrjoin( char *spool, uint *len, const char *joiner, ... );
char *strjoin( const char *joiner, ... );
char *sstrvjoin( char *spool, uint *len, const char *joiner, char **strs );
char *strvjoin( const char *joiner, char **strs );

char *sxml_parse( char *spool, uint *len, char *str, size_t slen,
		  SXMLStartTagFunc start, SXMLEndTagFunc end,
		  SXMLCharsFunc chars, void *ud );
char *sxml_spool_escaped( char *spool, uint *len, char *str );
char *sxml_unescape( char *str, int slen, int append_eq );

HashTreeNode *hash_tree_new( size_t fanout );
HashTreeNode *hash_tree_node_new( void *key, size_t size );
void **hash_tree_access( HashTreeNode *trunk, void *key, size_t size,
			 uint prehash, int mode );
void **hash_tree_direct_access( HashTreeNode *trunk, void *key, int mode );
void *hash_tree_lookup( HashTreeNode *trunk, void *key, size_t size );
void *hash_tree_lookup_hash( HashTreeNode *trunk, void *key, size_t size,
			     unsigned int hash );
void hash_tree_remove( HashTreeNode *trunk, void *key, size_t size );
void hash_tree_destroy( HashTreeNode *trunk );
int hash_tree_set( HashTreeNode *trunk, void *key, size_t size, void *value );
void hash_tree_foreach( HashTreeNode *trunk,
			void (*func)( void *, size_t, void *, void * ),
			void *ud );
int c_prime_ceiling( int x );

void *direct_list_append( void *list, int next, int prev, void *node );
void *direct_list_prepend( void *list, int next, int prev, void *node );
void *direct_list_insert( void *list, int next, int prev, void *node,
			  size_t at );
void *direct_list_insert_sorted( void *list, int next, int prev, void *node,
				 DListCompareFunc compare );
void *direct_list_remove( void *list, int next, int prev, void *node );
void *direct_list_remove_each( void *list, int next, int prev,
			       int (*compare)( void *a, void *b ),
			       int (*callback)( void *node, void *user_data ),
			       void *user_data );
void direct_list_foreach( void *list, int next, int prev, void *node,
			  int (*callback)( void *node, void *user_data ),
			  void *user_data );
void *direct_list_search( void *list, int next, int data, void *val );
size_t direct_list_length( void *list, int next );
void *direct_list_nth( void *list, int next, size_t n );

DataList *data_list_append( DataList *list, void *data );
DataList *data_list_prepend( DataList *list, void *data );
DataList *data_list_insert( DataList *list, void *data, size_t at );
DataList *data_list_insert_sorted( DataList *list, void *data,
				   DListCompareFunc compare );
DataList *data_list_remove( DataList *list, void *data );
DataList *data_list_remove_each( DataList *list, DListCompareFunc compare,
				 int (*callback)( void *node, void *user_data ),
				 void *user_data );
// string pad copy
char *strpcpy( char *dst, char *src, char pad, uint len );

// string pre-pad copy
char *strppcpy( char *dst, char *src, char pad, uint len );

// string flip
char *strflip( char *str );

// string rotate
char *strrot( char *dst, char *src, int offset );

// string rotate characters in place (i.e. rot13)
char *strrotc( char *str, char upper, char lower, int offset );

// interleave two strings
char *strinterleave( char *dst, char *src1, char *src2 );

// get a list of entries in a directory
DirEntry *dir_entries_get( char *pattern, int *count );

END_C_BLOCK

#endif // UTIL_H
