1 // generic useful stuff for any C++ program
2
3 #ifndef _TOOLS_H
4 #define _TOOLS_H
5
6 #ifdef NULL
7 #undef NULL
8 #endif
9 #define NULL 0
10
11 typedef unsigned char uchar;
12 typedef unsigned short ushort;
13 typedef unsigned int uint;
14
15 #ifdef _DEBUG
16 #ifdef __GNUC__
17 #define ASSERT(c) if(!(c)) { asm("int $3"); }
18 #else
19 #define ASSERT(c) if(!(c)) { __asm int 3 }
20 #endif
21 #else
22 #define ASSERT(c) if(c) {}
23 #endif
24
25 #ifdef swap
26 #undef swap
27 #endif
28 template<class T>
swap(T & a,T & b)29 static inline void swap(T &a, T &b)
30 {
31 T t = a;
32 a = b;
33 b = t;
34 }
35 #ifdef max
36 #undef max
37 #endif
38 #ifdef min
39 #undef min
40 #endif
41 template<class T>
max(T a,T b)42 static inline T max(T a, T b)
43 {
44 return a > b ? a : b;
45 }
46 template<class T>
min(T a,T b)47 static inline T min(T a, T b)
48 {
49 return a < b ? a : b;
50 }
51
52 #define clamp(a,b,c) (max(b, min(a, c)))
53 #define rnd(x) ((int)(randomMT()&0xFFFFFF)%(x))
54 #define rndscale(x) (float((randomMT()&0xFFFFFF)*double(x)/double(0xFFFFFF)))
55 #define detrnd(s, x) ((int)(((((uint)(s))*1103515245+12345)>>16)%(x)))
56 #define isnumeric(c) (isdigit(c) || c == '+' || c == '-')
57
58 #define loop(v,m) for(int v = 0; v<int(m); v++)
59 #define loopi(m) loop(i,m)
60 #define loopj(m) loop(j,m)
61 #define loopk(m) loop(k,m)
62 #define loopl(m) loop(l,m)
63 #define loopirev(v) for(int i = v-1; i>=0; i--)
64
65
66 #define DELETEP(p) if(p) { delete p; p = 0; }
67 #define DELETEA(p) if(p) { delete[] p; p = 0; }
68
69 #define PI (3.1415927f)
70 #define PI2 (2*PI)
71 #define SQRT2 (1.4142136f)
72 #define SQRT3 (1.7320508f)
73 #define RAD (PI / 180.0f)
74
75 #ifdef WIN32
76 #ifdef M_PI
77 #undef M_PI
78 #endif
79 #define M_PI 3.14159265
80
81 #ifndef __GNUC__
82 #pragma warning (3: 4189) // local variable is initialized but not referenced
83 #pragma warning (disable: 4244) // conversion from 'int' to 'float', possible loss of data
84 #pragma warning (disable: 4267) // conversion from 'size_t' to 'int', possible loss of data
85 #pragma warning (disable: 4355) // 'this' : used in base member initializer list
86 #pragma warning (disable: 4996) // 'strncpy' was declared deprecated
87 #pragma warning (disable: 4800) // forcing value to bool 'true' or 'false' (performance warning)
88 #endif
89
90 #define strcasecmp _stricmp
91 #define PATHDIV '\\'
92 #else
93 #define __cdecl
94 #define _vsnprintf vsnprintf
95 #define PATHDIV '/'
96 #endif
97
98 // easy safe strings
99
100 #define MAXSTRLEN 512 // must be at least 512 bytes to comply with rfc1459
101 typedef char string[MAXSTRLEN];
102 #define mkstring(d) string d; d[0] = 0;
103
104 inline void vformatstring(char *d, const char *fmt, va_list v, int len = MAXSTRLEN) { _vsnprintf(d, len, fmt, v); d[len-1] = 0; }
105 inline char *copystring(char *d, const char *s, size_t len = MAXSTRLEN) { strncpy(d, s, len); d[len-1] = 0; return d; }
concatstring(char * d,const char * s)106 inline char *concatstring(char *d, const char *s) { size_t len = strlen(d); return copystring(d+len, s, MAXSTRLEN-len); }
107
108 struct stringformatter
109 {
110 char *buf;
stringformatterstringformatter111 stringformatter(char *buf): buf((char *)buf) {}
operatorstringformatter112 void operator()(const char *fmt, ...)
113 {
114 va_list v;
115 va_start(v, fmt);
116 vformatstring(buf, fmt, v);
117 va_end(v);
118 }
119 };
120
121 #define formatstring(d) stringformatter((char *)d)
122 #define defformatstring(d) string d; formatstring(d)
123 #define defvformatstring(d,last,fmt) string d; { va_list ap; va_start(ap, last); vformatstring(d, fmt, ap); va_end(ap); }
124
125 #define loopv(v) for(int i = 0; i<(v).length(); i++)
126 #define loopvj(v) for(int j = 0; j<(v).length(); j++)
127 #define loopvk(v) for(int k = 0; k<(v).length(); k++)
128 #define loopvrev(v) for(int i = (v).length()-1; i>=0; i--)
129
130 template <class T>
131 struct databuf
132 {
133 enum
134 {
135 OVERREAD = 1<<0,
136 OVERWROTE = 1<<1
137 };
138
139 T *buf;
140 int len, maxlen;
141 uchar flags;
142
databufdatabuf143 databuf() : buf(NULL), len(0), maxlen(0), flags(0) {}
144
145 template<class U>
databufdatabuf146 databuf(T *buf, U maxlen) : buf(buf), len(0), maxlen((int)maxlen), flags(0) {}
147
getdatabuf148 const T &get()
149 {
150 static T overreadval;
151 if(len<maxlen) return buf[len++];
152 flags |= OVERREAD;
153 return overreadval;
154 }
155
subbufdatabuf156 databuf subbuf(int sz)
157 {
158 sz = min(sz, maxlen-len);
159 len += sz;
160 return databuf(&buf[len-sz], sz);
161 }
162
putdatabuf163 void put(const T &val)
164 {
165 if(len<maxlen) buf[len++] = val;
166 else flags |= OVERWROTE;
167 }
168
putdatabuf169 void put(const T *vals, int numvals)
170 {
171 if(maxlen-len<numvals) flags |= OVERWROTE;
172 memcpy(&buf[len], vals, min(maxlen-len, numvals)*sizeof(T));
173 len += min(maxlen-len, numvals);
174 }
175
getdatabuf176 int get(T *vals, int numvals)
177 {
178 int read = min(maxlen-len, numvals);
179 if(read<numvals) flags |= OVERREAD;
180 memcpy(vals, &buf[len], read*sizeof(T));
181 len += read;
182 return read;
183 }
184
lengthdatabuf185 int length() const { return len; }
remainingdatabuf186 int remaining() const { return maxlen-len; }
overreaddatabuf187 bool overread() const { return (flags&OVERREAD)!=0; }
overwrotedatabuf188 bool overwrote() const { return (flags&OVERWROTE)!=0; }
189
forceoverreaddatabuf190 void forceoverread()
191 {
192 len = maxlen;
193 flags |= OVERREAD;
194 }
195 };
196
197 typedef databuf<char> charbuf;
198 typedef databuf<uchar> ucharbuf;
199
200 struct packetbuf : ucharbuf
201 {
202 ENetPacket *packet;
203 int growth;
204
packetbufpacketbuf205 packetbuf(ENetPacket *packet) : ucharbuf(packet->data, packet->dataLength), packet(packet), growth(0) {}
growthpacketbuf206 packetbuf(int growth, int pflags = 0) : growth(growth)
207 {
208 packet = enet_packet_create(NULL, growth, pflags);
209 buf = (uchar *)packet->data;
210 maxlen = packet->dataLength;
211 }
~packetbufpacketbuf212 ~packetbuf() { cleanup(); }
213
reliablepacketbuf214 void reliable() { packet->flags |= ENET_PACKET_FLAG_RELIABLE; }
215
resizepacketbuf216 void resize(int n)
217 {
218 enet_packet_resize(packet, n);
219 buf = (uchar *)packet->data;
220 maxlen = packet->dataLength;
221 }
222
checkspacepacketbuf223 void checkspace(int n)
224 {
225 if(len + n > maxlen && packet && growth > 0) resize(max(len + n, maxlen + growth));
226 }
227
subbufpacketbuf228 ucharbuf subbuf(int sz)
229 {
230 checkspace(sz);
231 return ucharbuf::subbuf(sz);
232 }
233
putpacketbuf234 void put(const uchar &val)
235 {
236 checkspace(1);
237 ucharbuf::put(val);
238 }
239
putpacketbuf240 void put(const uchar *vals, int numvals)
241 {
242 checkspace(numvals);
243 ucharbuf::put(vals, numvals);
244 }
245
finalizepacketbuf246 ENetPacket *finalize()
247 {
248 resize(len);
249 return packet;
250 }
251
cleanuppacketbuf252 void cleanup()
253 {
254 if(growth > 0 && packet && !packet->referenceCount) { enet_packet_destroy(packet); packet = NULL; buf = NULL; len = maxlen = 0; }
255 }
256 };
257
258 template<class T>
heapscore(const T & n)259 static inline float heapscore(const T &n) { return n; }
260
261 template<class T, class U>
quicksort(T * buf,int n,int (__cdecl * func)(U *,U *))262 static inline void quicksort(T *buf, int n, int (__cdecl *func)(U *, U *))
263 {
264 qsort(buf, n, sizeof(T), (int (__cdecl *)(const void *,const void *))func);
265 }
266
267 template <class T> struct vector
268 {
269 static const int MINSIZE = 8;
270
271 T *buf;
272 int alen, ulen;
273
vectorvector274 vector() : buf(NULL), alen(0), ulen(0)
275 {
276 }
277
vectorvector278 vector(const vector &v) : buf(NULL), alen(0), ulen(0)
279 {
280 *this = v;
281 }
282
~vectorvector283 ~vector() { setsize(0); if(buf) delete[] (uchar *)buf; }
284
285 vector<T> &operator=(const vector<T> &v)
286 {
287 setsize(0);
288 if(v.length() > alen) vrealloc(v.length());
289 loopv(v) add(v[i]);
290 return *this;
291 }
292
addvector293 T &add(const T &x)
294 {
295 if(ulen==alen) vrealloc(ulen+1);
296 new (&buf[ulen]) T(x);
297 return buf[ulen++];
298 }
299
addvector300 T &add()
301 {
302 if(ulen==alen) vrealloc(ulen+1);
303 new (&buf[ulen]) T;
304 return buf[ulen++];
305 }
306
dupvector307 T &dup()
308 {
309 if(ulen==alen) vrealloc(ulen+1);
310 new (&buf[ulen]) T(buf[ulen-1]);
311 return buf[ulen++];
312 }
313
movevector314 void move(vector<T> &v)
315 {
316 if(!ulen)
317 {
318 swap(buf, v.buf);
319 swap(ulen, v.ulen);
320 swap(alen, v.alen);
321 }
322 else
323 {
324 vrealloc(ulen+v.ulen);
325 if(v.ulen) memcpy(&buf[ulen], v.buf, v.ulen*sizeof(T));
326 ulen += v.ulen;
327 v.ulen = 0;
328 }
329 }
330
inrangevector331 bool inrange(size_t i) const { return i<size_t(ulen); }
inrangevector332 bool inrange(int i) const { return i>=0 && i<ulen; }
333
popvector334 T &pop() { return buf[--ulen]; }
lastvector335 T &last() { return buf[ulen-1]; }
dropvector336 void drop() { ulen--; buf[ulen].~T(); }
emptyvector337 bool empty() const { return ulen==0; }
338
capacityvector339 int capacity() const { return alen; }
lengthvector340 int length() const { return ulen; }
341 T &operator[](int i) { ASSERT(i>=0 && i<ulen); return buf[i]; }
342 const T &operator[](int i) const { ASSERT(i >= 0 && i<ulen); return buf[i]; }
343
setsizevector344 void setsize(int i) { ASSERT(i<=ulen); while(ulen>i) drop(); }
setsizenodeletevector345 void setsizenodelete(int i) { ASSERT(i<=ulen); ulen = i; }
346
deletecontentspvector347 void deletecontentsp() { while(!empty()) delete pop(); }
deletecontentsavector348 void deletecontentsa() { while(!empty()) delete[] pop(); }
349
getbufvector350 T *getbuf() { return buf; }
getbufvector351 const T *getbuf() const { return buf; }
inbufvector352 bool inbuf(const T *e) const { return e >= buf && e < &buf[ulen]; }
353
354 template<class ST>
355 void sort(int (__cdecl *cf)(ST *, ST *), int i = 0, int n = -1)
356 {
357 quicksort(&buf[i], n < 0 ? ulen : n, cf);
358 }
359
vreallocvector360 void vrealloc(int sz)
361 {
362 int olen = alen;
363 if(!alen) alen = max(MINSIZE, sz);
364 else while(alen < sz) alen *= 2;
365 if(alen <= olen) return;
366 uchar *newbuf = new uchar[alen*sizeof(T)];
367 if(olen > 0)
368 {
369 memcpy(newbuf, buf, olen*sizeof(T));
370 delete[] (uchar *)buf;
371 }
372 buf = (T *)newbuf;
373 }
374
reservevector375 databuf<T> reserve(int sz)
376 {
377 if(ulen+sz > alen) vrealloc(ulen+sz);
378 return databuf<T>(&buf[ulen], sz);
379 }
380
advancevector381 void advance(int sz)
382 {
383 ulen += sz;
384 }
385
addbufvector386 void addbuf(const databuf<T> &p)
387 {
388 advance(p.length());
389 }
390
putvector391 void put(const T &v) { add(v); }
392
putvector393 void put(const T *v, int n)
394 {
395 databuf<T> buf = reserve(n);
396 buf.put(v, n);
397 addbuf(buf);
398 }
399
removevector400 void remove(int i, int n)
401 {
402 for(int p = i+n; p<ulen; p++) buf[p-n] = buf[p];
403 ulen -= n;
404 }
405
removevector406 T remove(int i)
407 {
408 T e = buf[i];
409 for(int p = i+1; p<ulen; p++) buf[p-1] = buf[p];
410 ulen--;
411 return e;
412 }
413
removeunorderedvector414 T removeunordered(int i)
415 {
416 T e = buf[i];
417 ulen--;
418 if(ulen>0) buf[i] = buf[ulen];
419 return e;
420 }
421
422 template<class U>
findvector423 int find(const U &o)
424 {
425 loopi(ulen) if(buf[i]==o) return i;
426 return -1;
427 }
428
removeobjvector429 void removeobj(const T &o)
430 {
431 loopi(ulen) if(buf[i]==o) remove(i--);
432 }
433
replacewithlastvector434 void replacewithlast(const T &o)
435 {
436 if(!ulen) return;
437 loopi(ulen-1) if(buf[i]==o)
438 {
439 buf[i] = buf[ulen-1];
440 }
441 ulen--;
442 }
443
insertvector444 T &insert(int i, const T &e)
445 {
446 add(T());
447 for(int p = ulen-1; p>i; p--) buf[p] = buf[p-1];
448 buf[i] = e;
449 return buf[i];
450 }
451
insertvector452 T *insert(int i, const T *e, int n)
453 {
454 if(ulen+n>alen) vrealloc(ulen+n);
455 loopj(n) add(T());
456 for(int p = ulen-1; p>=i+n; p--) buf[p] = buf[p-n];
457 loopj(n) buf[i+j] = e[j];
458 return &buf[i];
459 }
460
reversevector461 void reverse()
462 {
463 loopi(ulen/2) swap(buf[i], buf[ulen-1-i]);
464 }
465
heapparentvector466 static int heapparent(int i) { return (i - 1) >> 1; }
heapchildvector467 static int heapchild(int i) { return (i << 1) + 1; }
468
buildheapvector469 void buildheap()
470 {
471 for(int i = ulen/2; i >= 0; i--) downheap(i);
472 }
473
upheapvector474 int upheap(int i)
475 {
476 float score = heapscore(buf[i]);
477 while(i > 0)
478 {
479 int pi = heapparent(i);
480 if(score >= heapscore(buf[pi])) break;
481 swap(buf[i], buf[pi]);
482 i = pi;
483 }
484 return i;
485 }
486
addheapvector487 T &addheap(const T &x)
488 {
489 add(x);
490 return buf[upheap(ulen-1)];
491 }
492
downheapvector493 int downheap(int i)
494 {
495 float score = heapscore(buf[i]);
496 for(;;)
497 {
498 int ci = heapchild(i);
499 if(ci >= ulen) break;
500 float cscore = heapscore(buf[ci]);
501 if(score > cscore)
502 {
503 if(ci+1 < ulen && heapscore(buf[ci+1]) < cscore) { swap(buf[ci+1], buf[i]); i = ci+1; }
504 else { swap(buf[ci], buf[i]); i = ci; }
505 }
506 else if(ci+1 < ulen && heapscore(buf[ci+1]) < score) { swap(buf[ci+1], buf[i]); i = ci+1; }
507 else break;
508 }
509 return i;
510 }
511
removeheapvector512 T removeheap()
513 {
514 T e = removeunordered(0);
515 if(ulen) downheap(0);
516 return e;
517 }
518 };
519
520 typedef vector<char *> cvector;
521 typedef vector<int> ivector;
522 typedef vector<ushort> usvector;
523
hthash(const char * key)524 static inline uint hthash(const char *key)
525 {
526 uint h = 5381;
527 for(int i = 0, k; (k = key[i]); i++) h = ((h<<5)+h)^k; // bernstein k=33 xor
528 return h;
529 }
530
htcmp(const char * x,const char * y)531 static inline bool htcmp(const char *x, const char *y)
532 {
533 return !strcmp(x, y);
534 }
535
hthash(int key)536 static inline uint hthash(int key)
537 {
538 return key;
539 }
540
htcmp(int x,int y)541 static inline bool htcmp(int x, int y)
542 {
543 return x==y;
544 }
545
546 template <class K, class T> struct hashtable
547 {
548 typedef K key;
549 typedef const K const_key;
550 typedef T value;
551 typedef const T const_value;
552
553 enum { CHUNKSIZE = 64 };
554
555 struct chain { T data; K key; chain *next; };
556 struct chainchunk { chain chains[CHUNKSIZE]; chainchunk *next; };
557
558 int size;
559 int numelems;
560 chain **table;
561 chain *enumc;
562
563 chainchunk *chunks;
564 chain *unused;
565
566 hashtable(int size = 1<<10)
sizehashtable567 : size(size)
568 {
569 numelems = 0;
570 chunks = NULL;
571 unused = NULL;
572 table = new chain *[size];
573 loopi(size) table[i] = NULL;
574 }
575
~hashtablehashtable576 ~hashtable()
577 {
578 DELETEA(table);
579 deletechunks();
580 }
581
inserthashtable582 chain *insert(const K &key, uint h)
583 {
584 if(!unused)
585 {
586 chainchunk *chunk = new chainchunk;
587 chunk->next = chunks;
588 chunks = chunk;
589 loopi(CHUNKSIZE-1) chunk->chains[i].next = &chunk->chains[i+1];
590 chunk->chains[CHUNKSIZE-1].next = unused;
591 unused = chunk->chains;
592 }
593 chain *c = unused;
594 unused = unused->next;
595 c->key = key;
596 c->next = table[h];
597 table[h] = c;
598 numelems++;
599 return c;
600 }
601
602 #define HTFIND(success, fail) \
603 uint h = hthash(key)&(size-1); \
604 for(chain *c = table[h]; c; c = c->next) \
605 { \
606 if(htcmp(key, c->key)) return (success); \
607 } \
608 return (fail);
609
accesshashtable610 T *access(const K &key)
611 {
612 HTFIND(&c->data, NULL);
613 }
614
accesshashtable615 T &access(const K &key, const T &data)
616 {
617 HTFIND(c->data, insert(key, h)->data = data);
618 }
619
620 T &operator[](const K &key)
621 {
622 HTFIND(c->data, insert(key, h)->data);
623 }
624
625 #undef HTFIND
626
removehashtable627 bool remove(const K &key)
628 {
629 uint h = hthash(key)&(size-1);
630 for(chain **p = &table[h], *c = table[h]; c; p = &c->next, c = c->next)
631 {
632 if(htcmp(key, c->key))
633 {
634 *p = c->next;
635 c->data.~T();
636 c->key.~K();
637 new (&c->data) T;
638 new (&c->key) K;
639 c->next = unused;
640 unused = c;
641 numelems--;
642 return true;
643 }
644 }
645 return false;
646 }
647
deletechunkshashtable648 void deletechunks()
649 {
650 for(chainchunk *nextchunk; chunks; chunks = nextchunk)
651 {
652 nextchunk = chunks->next;
653 delete chunks;
654 }
655 }
656
clearhashtable657 void clear()
658 {
659 if(!numelems) return;
660 loopi(size) table[i] = NULL;
661 numelems = 0;
662 unused = NULL;
663 deletechunks();
664 }
665 };
666
667 #define enumeratekt(ht,k,e,t,f,b) loopi((ht).size) for(hashtable<k,t>::chain *enumc = (ht).table[i]; enumc;) { hashtable<k,t>::const_key &e = enumc->key; t &f = enumc->data; enumc = enumc->next; b; }
668 #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; }
669
670 struct unionfind
671 {
672 struct ufval
673 {
674 int rank, next;
675
ufvalunionfind::ufval676 ufval() : rank(0), next(-1) {}
677 };
678
679 vector<ufval> ufvals;
680
findunionfind681 int find(int k)
682 {
683 if(k>=ufvals.length()) return k;
684 while(ufvals[k].next>=0) k = ufvals[k].next;
685 return k;
686 }
687
compressfindunionfind688 int compressfind(int k)
689 {
690 if(ufvals[k].next<0) return k;
691 return ufvals[k].next = compressfind(ufvals[k].next);
692 }
693
uniteunionfind694 void unite (int x, int y)
695 {
696 while(ufvals.length() <= max(x, y)) ufvals.add();
697 x = compressfind(x);
698 y = compressfind(y);
699 if(x==y) return;
700 ufval &xval = ufvals[x], &yval = ufvals[y];
701 if(xval.rank < yval.rank) xval.next = y;
702 else
703 {
704 yval.next = x;
705 if(xval.rank==yval.rank) yval.rank++;
706 }
707 }
708 };
709
710 template <class T, int SIZE> struct ringbuf
711 {
712 int index, len;
713 T data[SIZE];
714
ringbufringbuf715 ringbuf() { clear(); }
716
clearringbuf717 void clear()
718 {
719 index = len = 0;
720 }
721
emptyringbuf722 bool empty() const { return !len; }
723
lengthringbuf724 const int length() const { return len; }
725
addringbuf726 T &add(const T &e)
727 {
728 T &t = (data[index] = e);
729 index++;
730 if(index >= SIZE) index -= SIZE;
731 if(len < SIZE) len++;
732 return t;
733 }
734
addringbuf735 T &add() { return add(T()); }
736
737 T &operator[](int i)
738 {
739 i += index - len;
740 return data[i < 0 ? i + SIZE : i%SIZE];
741 }
742
743 const T &operator[](int i) const
744 {
745 i += index - len;
746 return data[i < 0 ? i + SIZE : i%SIZE];
747 }
748 };
749
750 template <class T, int SIZE> struct queue
751 {
752 int head, tail, len;
753 T data[SIZE];
754
queuequeue755 queue() { clear(); }
756
clearqueue757 void clear() { head = tail = len = 0; }
758
lengthqueue759 int length() const { return len; }
emptyqueue760 bool empty() const { return !len; }
fullqueue761 bool full() const { return len == SIZE; }
762
addedqueue763 T &added() { return data[tail > 0 ? tail-1 : SIZE-1]; }
addedqueue764 T &added(int offset) { return data[tail-offset > 0 ? tail-offset-1 : tail-offset-1 + SIZE]; }
addingqueue765 T &adding() { return data[tail]; }
addingqueue766 T &adding(int offset) { return data[tail+offset >= SIZE ? tail+offset - SIZE : tail+offset]; }
addqueue767 T &add()
768 {
769 ASSERT(len < SIZE);
770 T &t = data[tail];
771 tail = (tail + 1)%SIZE;
772 len++;
773 return t;
774 }
775
removingqueue776 T &removing() { return data[head]; }
removingqueue777 T &removing(int offset) { return data[head+offset >= SIZE ? head+offset - SIZE : head+offset]; }
removequeue778 T &remove()
779 {
780 ASSERT(len > 0);
781 T &t = data[head];
782 head = (head + 1)%SIZE;
783 len--;
784 return t;
785 }
786 };
787
newstring(size_t l)788 inline char *newstring(size_t l) { return new char[l+1]; }
newstring(const char * s,size_t l)789 inline char *newstring(const char *s, size_t l) { return copystring(newstring(l), s, l+1); }
newstring(const char * s)790 inline char *newstring(const char *s) { return newstring(s, strlen(s)); }
newstringbuf(const char * s)791 inline char *newstringbuf(const char *s) { return newstring(s, MAXSTRLEN-1); }
792
itoa(char * s,int i)793 inline void itoa(char *s, int i) { formatstring(s)("%d", i); }
exchangestr(char * o,const char * n)794 inline char *exchangestr(char *o, const char *n) { delete[] o; return newstring(n); }
795 inline char *expandstr(char *o, const char *n, char *delimit = " ")
796 {
797 int len = strlen(o)+strlen(n)+strlen(delimit)+1;
798 char *q = new char[len];
799 copystring(q, o, len);
800 if(*delimit) concatstring(q, delimit);
801 concatstring(q, n);
802 delete[] o;
803 return q;
804 }
805
806 #if defined(WIN32) && !defined(__GNUC__)
807 #ifdef _DEBUG
808 //#define _CRTDBG_MAP_ALLOC
809 #include <crtdbg.h>
new(size_t n,const char * fn,int l)810 inline void *__cdecl operator new(size_t n, const char *fn, int l) { return ::operator new(n, 1, fn, l); }
delete(void * p,const char * fn,int l)811 inline void __cdecl operator delete(void *p, const char *fn, int l) { ::operator delete(p, 1, fn, l); }
812 #define new new(__FILE__,__LINE__)
813 #endif
814 #endif
815
816 const int islittleendian = 1;
817 #ifdef SDL_BYTEORDER
818 #define endianswap16 SDL_Swap16
819 #define endianswap32 SDL_Swap32
820 #else
endianswap16(ushort n)821 inline ushort endianswap16(ushort n) { return (n<<8) | (n>>8); }
endianswap32(uint n)822 inline uint endianswap32(uint n) { return (n<<24) | (n>>24) | ((n>>8)&0xFF00) | ((n<<8)&0xFF0000); }
823 #endif
endianswap(T n)824 template<class T> inline T endianswap(T n) { union { T t; uint i; } conv; conv.t = n; conv.i = endianswap32(conv.i); return conv.t; }
825 template<> inline ushort endianswap<ushort>(ushort n) { return endianswap16(n); }
826 template<> inline short endianswap<short>(short n) { return endianswap16(n); }
827 template<> inline uint endianswap<uint>(uint n) { return endianswap32(n); }
828 template<> inline int endianswap<int>(int n) { return endianswap32(n); }
endianswap(T * buf,int len)829 template<class T> inline void endianswap(T *buf, int len) { for(T *end = &buf[len]; buf < end; buf++) *buf = endianswap(*buf); }
endiansame(T n)830 template<class T> inline T endiansame(T n) { return n; }
endiansame(T * buf,int len)831 template<class T> inline void endiansame(T *buf, int len) {}
832 #ifdef SDL_BYTEORDER
833 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
834 #define lilswap endiansame
835 #define bigswap endianswap
836 #else
837 #define lilswap endianswap
838 #define bigswap endiansame
839 #endif
840 #else
lilswap(T n)841 template<class T> inline T lilswap(T n) { return *(const uchar *)&islittleendian ? n : endianswap(n); }
lilswap(T * buf,int len)842 template<class T> inline void lilswap(T *buf, int len) { if(!*(const uchar *)&islittleendian) endianswap(buf, len); }
bigswap(T n)843 template<class T> inline T bigswap(T n) { return *(const uchar *)&islittleendian ? endianswap(n) : n; }
bigswap(T * buf,int len)844 template<class T> inline void bigswap(T *buf, int len) { if(*(const uchar *)&islittleendian) endianswap(buf, len); }
845 #endif
846
847 /* workaround for some C platforms that have these two functions as macros - not used anywhere */
848 #ifdef getchar
849 #undef getchar
850 #endif
851 #ifdef putchar
852 #undef putchar
853 #endif
854
855 struct stream
856 {
~streamstream857 virtual ~stream() {}
858 virtual void close() = 0;
859 virtual bool end() = 0;
tellstream860 virtual long tell() { return -1; }
861 virtual bool seek(long offset, int whence = SEEK_SET) { return false; }
862 virtual long size();
readstream863 virtual int read(void *buf, int len) { return 0; }
writestream864 virtual int write(const void *buf, int len) { return 0; }
getcharstream865 virtual int getchar() { uchar c; return read(&c, 1) == 1 ? c : -1; }
putcharstream866 virtual bool putchar(int n) { uchar c = n; return write(&c, 1) == 1; }
867 virtual bool getline(char *str, int len);
putstringstream868 virtual bool putstring(const char *str) { int len = (int)strlen(str); return write(str, len) == len; }
putlinestream869 virtual bool putline(const char *str) { return putstring(str) && putchar('\n'); }
printfstream870 virtual int printf(const char *fmt, ...) { return -1; }
getcrcstream871 virtual uint getcrc() { return 0; }
872
putstream873 template<class T> bool put(T n) { return write(&n, sizeof(n)) == sizeof(n); }
putlilstream874 template<class T> bool putlil(T n) { return put<T>(lilswap(n)); }
putbigstream875 template<class T> bool putbig(T n) { return put<T>(bigswap(n)); }
876
getstream877 template<class T> T get() { T n; return read(&n, sizeof(n)) == sizeof(n) ? n : 0; }
getlilstream878 template<class T> T getlil() { return lilswap(get<T>()); }
getbigstream879 template<class T> T getbig() { return bigswap(get<T>()); }
880
881 #ifndef STANDALONE
882 SDL_RWops *rwops();
883 #endif
884 };
885
886 extern char *makerelpath(const char *dir, const char *file, const char *prefix = NULL, const char *cmd = NULL);
887 extern char *makefile(const char *s, const char *e = "", int revision = 0, int start = 1, bool skip = false);
888 extern char *path(char *s);
889 extern char *path(const char *s, bool copy);
890 extern const char *parentdir(const char *directory);
891 extern bool fileexists(const char *path, const char *mode);
892 extern bool createdir(const char *path);
893 extern void sethomedir(const char *dir);
894 extern void appendhomedir(const char *dir);
895 extern void addpackagedir(const char *dir, int flags = 0);
896 extern int maskpackagedirs(int flags);
897 extern const char *findfile(const char *filename, const char *mode);
898 extern stream *openrawfile(const char *filename, const char *mode);
899 extern stream *openzipfile(const char *filename, const char *mode);
900 extern stream *openfile(const char *filename, const char *mode);
901 extern stream *opentempfile(const char *filename, const char *mode);
902 extern stream *opengzfile(const char *filename, const char *mode, stream *file = NULL, int level = Z_BEST_COMPRESSION);
903 extern char *loadfile(const char *fn, int *size);
904 extern bool listdir(const char *dir, const char *ext, vector<char *> &files);
905 extern int listfiles(const char *dir, const char *ext, vector<char *> &files);
906 extern int listzipfiles(const char *dir, const char *ext, vector<char *> &files);
907 extern void backup(const char *fname, const char *ext, int revision = 0, int start = 1);
908
909 extern void endianswap(void *, int, int);
910 extern void seedMT(uint seed);
911 extern uint randomMT(void);
912
913 #endif
914
915