// generic useful stuff for any C++ program #ifndef _TOOLS_H #define _TOOLS_H #ifdef NULL #undef NULL #endif #define NULL 0 typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; #ifdef _DEBUG #ifdef __GNUC__ #define ASSERT(c) if(!(c)) { asm("int $3"); } #else #define ASSERT(c) if(!(c)) { __asm int 3 } #endif #include #define DEBUG(v) if(DEBUGCOND) { std::cout << behindpath(__FILE__) << ":" << __LINE__ << " " << __FUNCTION__ << "(..) " << v << std::endl; } #define DEBUGVAR(v) if(DEBUGCOND) { std::cout << behindpath(__FILE__) << ":" << __LINE__ << " " << __FUNCTION__ << "(..) " << #v << " = " << v << std::endl; } #else #define DEBUG(v) {} #define DEBUGVAR(v) {} #define ASSERT(c) if(c) {} #endif #ifdef swap #undef swap #endif template static inline void swap(T &a, T &b) { T t = a; a = b; b = t; } #ifdef max #undef max #endif #ifdef min #undef min #endif template static inline T max(T a, T b) { return a > b ? a : b; } template static inline T min(T a, T b) { return a < b ? a : b; } static inline float round(float x) { return floor(x + 0.5f); } #define clamp(a,b,c) (max(b, min(a, c))) #define rnd(max) (rand()%(max)) #define rnd_2x(max) (rand()%(max)+rand()%(max)) #define detrnd(s, x) ((int)(((((uint)(s))*1103515245+12345)>>16)%(x))) #define loop(v,m) for(int v = 0; v 0 ) // this is not a pair, but there is a previous pattern { if (*s == '.' || *s == *(s-1) || issimilar(*(s+1),*dp) ); // separator or typo (do nothing) else if ( issimilar(*(s+1),*(dp+1)) || *s == '*' ) dp++; // wild card or typo else hit--; // maybe this is nothing } else dp = d; // nothing here s++; // walk on the string if ( hit && 5 * hit > 4 * len ) return true; // found it! } return false; } #define loopv(v) for(int i = 0; i<(v).length(); i++) #define loopvj(v) for(int j = 0; j<(v).length(); j++) #define loopvk(v) for(int k = 0; k<(v).length(); k++) #define loopvrev(v) for(int i = (v).length()-1; i>=0; i--) #define loopvjrev(v) for(int j = (v).length()-1; i>=0; i--) template struct databuf { enum { OVERREAD = 1<<0, OVERWROTE = 1<<1 }; T *buf; int len, maxlen; uchar flags; databuf() : buf(NULL), len(0), maxlen(0), flags(0) {} template databuf(T *buf, U maxlen) : buf(buf), len(0), maxlen((int)maxlen), flags(0) {} const T &get() { static T overreadval; if(len charbuf; typedef databuf ucharbuf; struct packetbuf : ucharbuf { ENetPacket *packet; int growth; packetbuf(ENetPacket *packet) : ucharbuf(packet->data, packet->dataLength), packet(packet), growth(0) {} packetbuf(int growth, int pflags = 0) : growth(growth) { packet = enet_packet_create(NULL, growth, pflags); buf = (uchar *)packet->data; maxlen = packet->dataLength; } ~packetbuf() { cleanup(); } void reliable() { packet->flags |= ENET_PACKET_FLAG_RELIABLE; } void resize(int n) { enet_packet_resize(packet, n); buf = (uchar *)packet->data; maxlen = packet->dataLength; } void checkspace(int n) { if(len + n > maxlen && packet && growth > 0) resize(max(len + n, maxlen + growth)); } ucharbuf subbuf(int sz) { checkspace(sz); return ucharbuf::subbuf(sz); } void put(const uchar &val) { checkspace(1); ucharbuf::put(val); } void put(const uchar *vals, int numvals) { checkspace(numvals); ucharbuf::put(vals, numvals); } bool overwrote() const { return false; } ENetPacket *finalize() { resize(len); return packet; } void cleanup() { if(growth > 0 && packet && !packet->referenceCount) { enet_packet_destroy(packet); packet = NULL; buf = NULL; len = maxlen = 0; } } }; template struct bitbuf { T &q; int blen; bitbuf(T &oq) : q(oq), blen(0) {} int getbits(int n) { int res = 0, p = 0; while(n > 0) { if(!blen) q.get(); int r = 8 - blen; if(r > n) r = n; res |= ((q.buf[q.len - 1] >> blen) & ((1 << r) - 1)) << p; n -= r; p += r; blen = (blen + r) % 8; } return res; } void putbits(int n, int v) { while(n > 0) { if(!blen) { q.put(0); if(q.overwrote()) return; } int r = 8 - blen; if(r > n) r = n; q.buf[q.len - 1] |= (v & ((1 << r) - 1)) << blen; n -= r; v >>= r; blen = (blen + r) % 8; } } int rembits() { return (8 - blen) % 8; } // 0..7 bits remaining in current byte }; template struct vector { static const int MINSIZE = 8; T *buf; int alen, ulen; vector() : buf(NULL), alen(0), ulen(0) { } vector(const vector &v) : buf(NULL), alen(0), ulen(0) { *this = v; } ~vector() { shrink(0); if(buf) delete[] (uchar *)buf; } vector &operator=(const vector &v) { shrink(0); if(v.length() > alen) growbuf(v.length()); loopv(v) add(v[i]); return *this; } T &add(const T &x) { if(ulen==alen) growbuf(ulen+1); new (&buf[ulen]) T(x); return buf[ulen++]; } T &add() { if(ulen==alen) growbuf(ulen+1); new (&buf[ulen]) T; return buf[ulen++]; } T &dup() { if(ulen==alen) growbuf(ulen+1); new (&buf[ulen]) T(buf[ulen-1]); return buf[ulen++]; } bool inrange(size_t i) const { return i=0 && i=0 && i= 0 && ii) drop(); } void setsize(int i) { ASSERT(i<=ulen); ulen = i; } void deletecontents() { while(!empty()) delete pop(); } void deletearrays() { while(!empty()) delete[] pop(); } T *getbuf() { return buf; } const T *getbuf() const { return buf; } bool inbuf(const T *e) const { return e >= buf && e < &buf[ulen]; } template void sort(int (__cdecl *cf)(ST *, ST *), int i = 0, int n = -1) { qsort(&buf[i], n<0 ? ulen : n, sizeof(T), (int (__cdecl *)(const void *,const void *))cf); } template T *search(T *key, int (__cdecl *cf)(ST *, ST *), int i = 0, int n = -1) { return (T *) bsearch(key, &buf[i], n<0 ? ulen : n, sizeof(T), (int (__cdecl *)(const void *,const void *))cf); } void growbuf(int sz) { int olen = alen; if(!alen) alen = max(MINSIZE, sz); else while(alen < sz) alen *= 2; if(alen <= olen) return; uchar *newbuf = new uchar[alen*sizeof(T)]; if(olen > 0) { memcpy(newbuf, buf, olen*sizeof(T)); delete[] (uchar *)buf; } buf = (T *)newbuf; } databuf reserve(int sz) { if(ulen+sz > alen) growbuf(ulen+sz); return databuf(&buf[ulen], sz); } void advance(int sz) { ulen += sz; } void addbuf(const databuf &p) { advance(p.length()); } void put(const T &v) { add(v); } void put(const T *v, int n) { databuf buf = reserve(n); buf.put(v, n); addbuf(buf); } void remove(int i, int n) { for(int p = i+n; pi; p--) buf[p] = buf[p-1]; buf[i] = e; return buf[i]; } T *insert(int i, const T *e, int n) { if(ulen+n>alen) growbuf(ulen+n); loopj(n) add(T()); for(int p = ulen-1; p>=i+n; p--) buf[p] = buf[p-n]; loopj(n) buf[i+j] = e[j]; return &buf[i]; } }; static inline uint hthash(const char *key) { uint h = 5381; for(int i = 0, k; (k = key[i]); i++) h = ((h<<5)+h)^k; // bernstein k=33 xor return h; } static inline bool htcmp(const char *x, const char *y) { return !strcmp(x, y); } static inline uint hthash(int key) { return key; } static inline bool htcmp(int x, int y) { return x==y; } static inline uint hthash(uint key) { return key; } static inline bool htcmp(uint x, uint y) { return x==y; } template struct hashtable { typedef K key; typedef const K const_key; typedef T value; typedef const T const_value; enum { CHUNKSIZE = 16 }; struct chain { T data; K key; chain *next; }; struct chainchunk { chain chains[CHUNKSIZE]; chainchunk *next; }; int size; int numelems; chain **table; chain *enumc; chainchunk *chunks; chain *unused; hashtable(int size = 1<<10) : size(size) { numelems = 0; chunks = NULL; unused = NULL; table = new chain *[size]; loopi(size) table[i] = NULL; } ~hashtable() { DELETEA(table); deletechunks(); } void insertchains(chainchunk *emptychunk) { loopi(CHUNKSIZE-1) emptychunk->chains[i].next = &emptychunk->chains[i+1]; emptychunk->chains[CHUNKSIZE-1].next = unused; unused = emptychunk->chains; } chain *insert(const K &key, uint h) { if(!unused) { chainchunk *chunk = new chainchunk; chunk->next = chunks; chunks = chunk; insertchains(chunk); } chain *c = unused; unused = unused->next; c->key = key; c->next = table[h]; table[h] = c; numelems++; return c; } #define HTFIND(success, fail) \ uint h = hthash(key)&(size-1); \ for(chain *c = table[h]; c; c = c->next) \ { \ if(htcmp(key, c->key)) return (success); \ } \ return (fail); T *access(const K &key) { HTFIND(&c->data, NULL); } T &access(const K &key, const T &data) { HTFIND(c->data, insert(key, h)->data = data); } T &operator[](const K &key) { HTFIND(c->data, insert(key, h)->data); } #undef HTFIND bool remove(const K &key) { uint h = hthash(key)&(size-1); for(chain **p = &table[h], *c = table[h]; c; p = &c->next, c = c->next) { if(htcmp(key, c->key)) { *p = c->next; c->data.~T(); c->key.~K(); new (&c->data) T; new (&c->key) K; c->next = unused; unused = c; numelems--; return true; } } return false; } void deletechunks() { for(chainchunk *nextchunk; chunks; chunks = nextchunk) { nextchunk = chunks->next; delete chunks; } } void clear(bool del = true) { loopi(size) table[i] = NULL; numelems = 0; unused = NULL; if(del) deletechunks(); else { for(chainchunk *chunk = chunks; chunk; chunk = chunk->next) insertchains(chunk); } } }; template struct ringbuf { int index, len; T data[SIZE]; ringbuf() { clear(); } void clear() { index = len = 0; } bool empty() const { return !len; } int maxsize() const { return SIZE; } int length() const { return len; } T &remove() { int start = index - len; if(start < 0) start += SIZE; len--; return data[start]; } T &add(const T &e) { T &t = data[index]; t = e; index++; if(index>=SIZE) index = 0; if(len= SIZE) i -= SIZE; return data[i]; } const T &operator[](int i) const { int start = index - len; if(start < 0) start += SIZE; i += start; if(i >= SIZE) i -= SIZE; return data[i]; } int find(const T &o) { loopi(len) if(data[i]==o) return i; return -1; } }; #define itoa(s, i) sprintf(s, "%d", i) #define ftoa(s, f) sprintf(s, (f) == int(f) ? "%.1f" : "%.7g", f) #define enumeratekt(ht,k,e,t,f,b) loopi((ht).size) for(hashtable::chain *enumc = (ht).table[i]; enumc;) { hashtable::const_key &e = enumc->key; t &f = enumc->data; enumc = enumc->next; b; } #define enumeratek(ht,k,e,b) loopi((ht).size) for((ht).enumc = (ht).table[i]; (ht).enumc;) { k &e = (ht).enumc->key; (ht).enumc = (ht).enumc->next; b; } #define enumerate(ht,t,e,b) loopi((ht).size) for((ht).enumc = (ht).table[i]; (ht).enumc;) { t &e = (ht).enumc->data; (ht).enumc = (ht).enumc->next; b; } #ifndef STANDALONE // ease time measurement struct stopwatch { int millis; stopwatch() : millis(-1) {} void start() { millis = SDL_GetTicks(); } // returns elapsed time int stop() { ASSERT(millis >= 0); int time = SDL_GetTicks() - millis; millis = -1; return time; } }; #endif inline char *newstring(size_t l) { return new char[l+1]; } inline char *newstring(const char *s, size_t l) { return copystring(newstring(l), s, l+1); } inline char *newstring(const char *s) { return newstring(s, strlen(s)); } inline char *newstringbuf() { return newstring(MAXSTRLEN-1); } inline char *newstringbuf(const char *s) { return newstring(s, MAXSTRLEN-1); } #ifndef STANDALONE inline const char *_gettext(const char *msgid) { if(msgid && msgid[0] != '\0') return gettext(msgid); else return ""; } #endif #define _(s) _gettext(s) const int islittleendian = 1; #ifdef SDL_BYTEORDER #define endianswap16 SDL_Swap16 #define endianswap32 SDL_Swap32 #else inline ushort endianswap16(ushort n) { return (n<<8) | (n>>8); } inline uint endianswap32(uint n) { return (n<<24) | (n>>24) | ((n>>8)&0xFF00) | ((n<<8)&0xFF0000); } #endif template inline T endianswap(T n) { union { T t; uint i; } conv; conv.t = n; conv.i = endianswap32(conv.i); return conv.t; } template<> inline ushort endianswap(ushort n) { return endianswap16(n); } template<> inline short endianswap(short n) { return endianswap16(n); } template<> inline uint endianswap(uint n) { return endianswap32(n); } template<> inline int endianswap(int n) { return endianswap32(n); } template inline void endianswap(T *buf, int len) { for(T *end = &buf[len]; buf < end; buf++) *buf = endianswap(*buf); } template inline T endiansame(T n) { return n; } template inline void endiansame(T *buf, int len) {} #ifdef SDL_BYTEORDER #if SDL_BYTEORDER == SDL_LIL_ENDIAN #define lilswap endiansame #define bigswap endianswap #else #define lilswap endianswap #define bigswap endiansame #endif #else template inline T lilswap(T n) { return *(const uchar *)&islittleendian ? n : endianswap(n); } template inline void lilswap(T *buf, int len) { if(!*(const uchar *)&islittleendian) endianswap(buf, len); } template inline T bigswap(T n) { return *(const uchar *)&islittleendian ? endianswap(n) : n; } template inline void bigswap(T *buf, int len) { if(*(const uchar *)&islittleendian) endianswap(buf, len); } #endif /* workaround for some C platforms that have these two functions as macros - not used anywhere */ #ifdef getchar #undef getchar #endif #ifdef putchar #undef putchar #endif struct stream { virtual ~stream() {} virtual void close() = 0; virtual bool end() = 0; virtual long tell() { return -1; } virtual bool seek(long offset, int whence = SEEK_SET) { return false; } virtual long size(); virtual int read(void *buf, int len) { return 0; } virtual int write(const void *buf, int len) { return 0; } virtual int getchar() { uchar c; return read(&c, 1) == 1 ? c : -1; } virtual bool putchar(int n) { uchar c = n; return write(&c, 1) == 1; } virtual bool getline(char *str, int len); virtual bool putstring(const char *str) { int len = (int)strlen(str); return write(str, len) == len; } virtual bool putline(const char *str) { return putstring(str) && putchar('\n'); } virtual int printf(const char *fmt, ...) { return -1; } virtual uint getcrc() { return 0; } template bool put(T n) { return write(&n, sizeof(n)) == sizeof(n); } template bool putlil(T n) { return put(lilswap(n)); } template bool putbig(T n) { return put(bigswap(n)); } template T get() { T n; return read(&n, sizeof(n)) == sizeof(n) ? n : 0; } template T getlil() { return lilswap(get()); } template T getbig() { return bigswap(get()); } #ifndef STANDALONE SDL_RWops *rwops(); #endif }; extern const char *timestring(bool local = false, const char *fmt = NULL); extern const char *asctime(); extern const char *numtime(); extern char *path(char *s); extern char *path(const char *s, bool copy); extern const char *behindpath(const char *s); extern const char *parentdir(const char *directory); extern bool fileexists(const char *path, const char *mode); extern bool createdir(const char *path); extern size_t fixpackagedir(char *dir); extern void sethomedir(const char *dir); extern void addpackagedir(const char *dir); extern const char *findfile(const char *filename, const char *mode); extern int getfilesize(const char *filename); extern stream *openrawfile(const char *filename, const char *mode); extern stream *openzipfile(const char *filename, const char *mode); extern stream *openfile(const char *filename, const char *mode); extern stream *opentempfile(const char *filename, const char *mode); extern stream *opengzfile(const char *filename, const char *mode, stream *file = NULL, int level = Z_BEST_COMPRESSION); extern char *loadfile(const char *fn, int *size, const char *mode = NULL); extern bool listdir(const char *dir, const char *ext, vector &files); extern int listfiles(const char *dir, const char *ext, vector &files); extern int listzipfiles(const char *dir, const char *ext, vector &files); extern bool delfile(const char *path); extern struct mapstats *loadmapstats(const char *filename, bool getlayout); extern bool cmpb(void *b, int n, enet_uint32 c); extern bool cmpf(char *fn, enet_uint32 c); extern enet_uint32 adler(unsigned char *data, size_t len); extern void endianswap(void *, int, int); extern bool isbigendian(); extern void strtoupper(char *t, const char *s = NULL); struct iprange { enet_uint32 lr, ur; }; extern const char *atoip(const char *s, enet_uint32 *ip); extern const char *atoipr(const char *s, iprange *ir); extern const char *iptoa(const enet_uint32 ip); extern const char *iprtoa(const struct iprange &ipr); extern int cmpiprange(const struct iprange *a, const struct iprange *b); extern int cmpipmatch(const struct iprange *a, const struct iprange *b); extern const char *hiddenpwd(const char *pwd, int showchars = 0); #if defined(WIN32) && !defined(_DEBUG) && !defined(__GNUC__) extern void stackdumper(unsigned int type, EXCEPTION_POINTERS *ep); #endif #endif