new function list_deep_free
[swftools.git] / lib / q.c
1 /* q.c
2
3    Part of the swftools package.
4    
5    Copyright (c) 2001,2002,2003,2004 Matthias Kramm <kramm@quiss.org>
6  
7    This program is rfx_free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the rfx_free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the rfx_free Software
19    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
20
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <assert.h>
26 #include <memory.h>
27 #include "mem.h"
28 #include "types.h"
29 #include "q.h"
30
31 // ------------------------------- malloc, alloc routines ---------------------
32
33 #ifndef STRNDUP
34 char* strdup_n(const char*str, int size)
35 {
36     char*m = (char*)rfx_alloc(size+1);
37     memcpy(m, str, size);
38     m[size] = 0;
39     return m;
40 }
41 #endif
42 char*qstrdup(const char*string)
43 {
44     return strdup(string);
45 }
46 char*qstrndup(const char*string, int len)
47 {
48     return strdup_n(string, len);
49 }
50
51 // ------------------------------- mem_t --------------------------------------
52
53 void mem_init(mem_t*mem)
54 {
55     memset(mem, 0, sizeof(mem_t));
56 }
57 void mem_clear(mem_t*mem)
58 {
59     rfx_free(mem->buffer);mem->buffer = 0;
60 }
61 void mem_destroy(mem_t*mem)
62 {
63     mem_clear(mem);
64     rfx_free(mem);
65 }
66 static int mem_put_(mem_t*m,const void*data, int length, int null)
67 {
68     int n = m->pos;
69     m->pos += length + (null?1:0);
70     if(m->pos > m->len) { 
71         int v1 = (m->pos+63)&~63;
72         int v2 = m->len + m->len / 2;
73         m->len = v1>v2?v1:v2;
74         m->buffer = m->buffer?(char*)rfx_realloc(m->buffer,m->len):(char*)rfx_alloc(m->len);
75     }
76     assert(n+length <= m->len);
77     memcpy(&m->buffer[n], data, length);
78     if(null)
79         m->buffer[n + length] = 0;
80     return n;
81 }
82 int mem_put(mem_t*m,void*data, int length)
83 {
84     return mem_put_(m, data, length, 0);
85 }
86 int mem_putstring(mem_t*m,string_t str)
87 {
88     return mem_put_(m, str.str, str.len, 1);
89 }
90 int mem_get(mem_t*m, void*data, int length)
91 {
92     if(m->read_pos + length > m->pos) {
93         length = m->pos - m->read_pos;
94     }
95     memcpy(data, m->buffer+m->read_pos, length);
96     m->read_pos += length;
97     return length;
98 }
99
100 // ------------------------------- ringbuffer_t -------------------------------
101
102 typedef struct _ringbuffer_internal_t
103 {
104     unsigned char*buffer;
105     int readpos;
106     int writepos;
107     int buffersize;
108 } ringbuffer_internal_t;
109
110 void ringbuffer_init(ringbuffer_t*r)
111 {
112     ringbuffer_internal_t*i = (ringbuffer_internal_t*)rfx_calloc(sizeof(ringbuffer_internal_t)); 
113     memset(r, 0, sizeof(ringbuffer_t));
114     r->internal = i;
115     i->buffer = (unsigned char*)rfx_alloc(1024);
116     i->buffersize = 1024;
117 }
118 int ringbuffer_read(ringbuffer_t*r, void*buf, int len)
119 {
120     unsigned char* data = (unsigned char*)buf;
121     ringbuffer_internal_t*i = (ringbuffer_internal_t*)r->internal;
122     if(r->available < len)
123         len = r->available;
124     if(!len)
125         return 0;
126     if(i->readpos + len > i->buffersize) {
127         int read1 = i->buffersize-i->readpos;
128         memcpy(data, &i->buffer[i->readpos], read1);
129         memcpy(&data[read1], &i->buffer[0], len - read1);
130         i->readpos = len - read1;
131     } else {
132         memcpy(data, &i->buffer[i->readpos], len);
133         i->readpos += len;
134         i->readpos %= i->buffersize;
135     }
136     r->available -= len;
137     return len;
138 }
139 void ringbuffer_put(ringbuffer_t*r, void*buf, int len)
140 {
141     unsigned char* data = (unsigned char*)buf;
142     ringbuffer_internal_t*i = (ringbuffer_internal_t*)r->internal;
143     
144     if(i->buffersize - r->available < len)
145     {
146         unsigned char* buf2;
147         int newbuffersize = i->buffersize;
148         int oldavailable = r->available;
149         newbuffersize*=3;newbuffersize/=2; /*grow at least by 50% each time */
150
151         if(newbuffersize < r->available + len)
152             newbuffersize = r->available + len + 1024;
153
154         buf2 = (unsigned char*)rfx_alloc(newbuffersize);
155         ringbuffer_read(r, buf2, r->available);
156         rfx_free(i->buffer);
157         i->buffer = buf2;
158         i->buffersize = newbuffersize;
159         i->readpos = 0;
160         i->writepos = oldavailable;
161         r->available = oldavailable;
162     }
163     if(i->writepos + len > i->buffersize) {
164         int read1 = i->buffersize-i->writepos;
165         memcpy(&i->buffer[i->writepos], data, read1);
166         memcpy(&i->buffer[0], &data[read1], len - read1);
167         i->writepos = len - read1;
168     } else {
169         memcpy(&i->buffer[i->writepos], data, len);
170         i->writepos += len;
171         i->writepos %= i->buffersize;
172     }
173     r->available += len;
174 }
175 void ringbuffer_clear(ringbuffer_t*r)
176 {
177     ringbuffer_internal_t*i = (ringbuffer_internal_t*)r->internal;
178     rfx_free(i->buffer);i->buffer = 0;
179     rfx_free(i);
180 }
181
182 // ------------------------------- heap_t -------------------------------
183
184 void heap_init(heap_t*h,int n,int elem_size, int(*compare)(const void *, const void *))
185 {
186     memset(h, 0, sizeof(heap_t));
187     h->max_size = n;
188     h->size = 0;
189     h->elem_size = elem_size;
190     h->compare = compare;
191     h->elements = (void**)rfx_calloc(n*sizeof(void*));
192     h->data = (char*)rfx_calloc(h->max_size*h->elem_size);
193 }
194 void heap_clear(heap_t*h)
195 {
196     rfx_free(h->elements);
197     rfx_free(h->data);
198 }
199
200 #define HEAP_NODE_SMALLER(h,node1,node2) ((h)->compare((node1),(node2))>0)
201
202 static void up(heap_t*h, int node)
203 {
204     void*node_p = h->elements[node];
205     int parent = node;
206     do {
207         node = parent;
208         if(!node) break;
209         parent = (node-1)/2;
210         h->elements[node] = h->elements[parent];
211     } while(HEAP_NODE_SMALLER(h,h->elements[parent], node_p));
212
213     h->elements[node] = node_p;
214 }
215 static void down(heap_t*h, int node)
216 {
217     void*node_p = h->elements[node];
218     int child = node;
219     do {
220         node = child;
221
222         /* determine new child's position */
223         child = node<<1|1;
224         if(child >= h->size) 
225             break;
226         if(child+1 < h->size && HEAP_NODE_SMALLER(h,h->elements[child],h->elements[child+1])) // search for bigger child
227             child++;
228
229         h->elements[node] = h->elements[child];
230     } while(HEAP_NODE_SMALLER(h,node_p, h->elements[child]));
231     
232     h->elements[node] = node_p;
233 }
234 void heap_put(heap_t*h, void*e) 
235 {
236     int pos = h->size++;
237     memcpy(&h->data[pos*h->elem_size],e,h->elem_size);
238     h->elements[pos] = &h->data[pos];
239     up(h, pos);
240 }
241 int heap_size(heap_t*h)
242 {
243     return h->size;
244 }
245 void* heap_max(heap_t*h)
246 {
247     return h->elements[0];
248 }
249 void* heap_chopmax(heap_t*h)
250 {
251     void*p = h->elements[0];
252     h->elements[0] = h->elements[--h->size];
253     down(h,0);
254     return p;
255 }
256 void heap_dump(heap_t*h, FILE*fi)
257 {
258     int t;
259     for(t=0;t<h->size;t++) {
260         int s;
261         for(s=0;s<=t;s=(s+1)*2-1) {
262             if(s==t) fprintf(fi,"\n");
263         }
264         //fprintf(fi,"%d ", h->elements[t]->x); //?
265     }
266 }
267 void** heap_flatten(heap_t*h)
268 {
269     void**nodes = (void**)rfx_alloc(h->size*sizeof(void*));
270     void**p = nodes;
271    
272     while(h->size) {
273         /*printf("Heap Size: %d\n", h->size);
274         heap_print(stdout, h);
275         printf("\n");*/
276         *p++ = heap_chopmax(h);
277     }
278     return nodes;
279 }
280
281 // ------------------------------- crc32 --------------------------------------
282 static unsigned int*crc32 = 0;
283 static void crc32_init(void)
284 {
285     int t;
286     if(crc32) 
287         return;
288     crc32= (unsigned int*)rfx_alloc(sizeof(unsigned int)*256);
289     for(t=0; t<256; t++) {
290         unsigned int c = t;
291         int s;
292         for (s = 0; s < 8; s++) {
293           c = (0xedb88320L*(c&1)) ^ (c >> 1);
294         }
295         crc32[t] = c;
296     }
297 }
298 // ------------------------------- string_t -----------------------------------
299
300 void string_set2(string_t*str, const char*text, int len)
301 {
302     str->len = len;
303     str->str = text;
304 }
305 void string_set(string_t*str, const char*text)
306 {
307     if(text) {
308         str->len = strlen(text);
309     } else {
310         str->len = 0;
311     }
312     str->str = text;
313 }
314 string_t string_new(const char*text, int len)
315 {
316     string_t s;
317     s.len = len;
318     s.str = text;
319     return s;
320 }
321 string_t string_new2(const char*text)
322 {
323     string_t s;
324     if(text) {
325         s.len = strlen(text);
326     } else {
327         s.len = 0;
328     }
329     s.str = text;
330     return s;
331 }
332 string_t* string_new3(const char*text, int len)
333 {
334     if(!text) {
335         string_t*s = malloc(sizeof(string_t));
336         s->len = 0;
337         s->str = 0;
338         return s;
339     } else {
340         string_t*s = malloc(sizeof(string_t)+len+1);
341         s->len = len;
342         s->str = (const char*)(s+1);
343         memcpy((char*)s->str, text, len);
344         ((char*)s->str)[len]=0;
345         return s;
346     }
347 }
348 string_t* string_new4(const char*text)
349 {
350     int l = strlen(text);
351     return string_new3(text, l);
352 }
353
354 void string_free(string_t*s)
355 {
356     if(!s) 
357         return;
358     s->len = 0;
359     if((string_t*)(s->str) == s+1) {
360         s->str = 0;
361         rfx_free(s);
362     } else {
363         rfx_free((char*)(s->str));
364         s->str = 0;
365         rfx_free(s);
366     }
367 }
368 char* string_cstr(string_t*str)
369 {
370     return strdup_n(str->str, str->len);
371 }
372 char* string_escape(string_t*str)
373 {
374     int t;
375     int len = 0;
376     for(t=0;t<str->len;t++) {
377         if(str->str[t]<0x20)
378             len+=3;
379         else
380             len++;
381     }
382     char*s = malloc(len+1);
383     char*p=s;
384     for(t=0;t<str->len;t++) {
385         if(str->str[t]<0x20) {
386             *p++ ='\\';
387             unsigned char c = str->str[t];
388             *p++ = "0123456789abcdef"[c>>4];
389             *p++ = "0123456789abcdef"[c&0x0f];
390         } else {
391             *p++ = str->str[t];
392         }
393     }
394     *p++ = 0;
395     assert(p == &s[len+1]);
396     return s;
397 }
398
399 unsigned int crc32_add_byte(unsigned int checksum, unsigned char b) 
400 {
401     if(!crc32)
402         crc32_init();
403     return checksum>>8 ^ crc32[(b^checksum)&0xff];
404 }
405 unsigned int crc32_add_string(unsigned int checksum, const char*s)
406 {
407     if(!crc32)
408         crc32_init();
409     if(!s)
410         return checksum;
411     while(*s) {
412         checksum = checksum>>8 ^ crc32[(*s^checksum)&0xff];
413         s++;
414     }
415     return checksum;
416 }
417
418 unsigned int string_hash(const string_t*str)
419 {
420     int t;
421     unsigned int checksum = 0;
422     if(!crc32)
423         crc32_init();
424     for(t=0;t<str->len;t++) {
425         checksum = checksum>>8 ^ crc32[(str->str[t]^checksum)&0xff];
426     }
427     return checksum;
428 }
429 unsigned int string_hash2(const char*str)
430 {
431     unsigned int checksum = 0;
432     const char*p = str;
433     if(!crc32)
434         crc32_init();
435     while(*p) {
436         checksum = checksum>>8 ^ crc32[(*p^checksum)&0xff];
437         p++;
438     }
439     return checksum;
440 }
441 unsigned int string_hash3(const char*str, int len)
442 {
443     string_t s;
444     s.str = str;
445     s.len = len;
446     return string_hash(&s);
447 }
448 void string_dup2(string_t*str, const char*text, int len)
449 {
450     str->len = len;
451     str->str = strdup_n(text, len);
452 }
453 void string_dup(string_t*str, const char*text)
454 {
455     str->len = strlen(text);
456     str->str = strdup(text);
457 }
458 int string_equals(string_t*str, const char*text)
459 {
460     int l = strlen(text);
461     if(str->len == l && !memcmp(str->str, text, l))
462         return 1;
463     return 0;
464 }
465 int string_equals2(string_t*str, string_t*str2)
466 {
467     if(str->len == str2->len && !memcmp(str->str, str2->str, str->len))
468         return 1;
469     return 0;
470 }
471
472 // ------------------------------- stringarray_t ------------------------------
473
474 typedef struct _stringlist {
475     int index;
476     struct _stringlist*next;
477 } stringlist_t;
478
479 typedef struct _stringarray_internal_t
480 {
481     mem_t pos;
482     stringlist_t**hash;
483     int num;
484     int hashsize;
485 } stringarray_internal_t;
486
487 void stringarray_init(stringarray_t*sa, int hashsize)
488 {
489     stringarray_internal_t*s;
490     int t;
491     sa->internal = (stringarray_internal_t*)rfx_calloc(sizeof(stringarray_internal_t)); 
492     s = (stringarray_internal_t*)sa->internal;
493     mem_init(&s->pos);
494     s->hash = rfx_calloc(sizeof(stringlist_t*)*hashsize);
495     s->hashsize = hashsize;
496 }
497 void stringarray_put(stringarray_t*sa, string_t str)
498 {
499     stringarray_internal_t*s = (stringarray_internal_t*)sa->internal;
500     int pos;
501     int hash = string_hash(&str) % s->hashsize;
502
503     char*ss = string_cstr(&str);
504     mem_put(&s->pos, &ss, sizeof(char*));
505
506     stringlist_t*l = rfx_alloc(sizeof(stringlist_t));
507     l->index = s->num;
508     l->next = s->hash[hash];
509     s->hash[hash] = l;
510
511     s->num++;
512 }
513 char* stringarray_at(stringarray_t*sa, int pos)
514 {
515     stringarray_internal_t*s = (stringarray_internal_t*)sa->internal;
516     char*p;
517     if(pos<0 || pos>=s->num)
518         return 0;
519     p = *(char**)&s->pos.buffer[pos*sizeof(char*)];
520     if(p<0)
521         return 0;
522     return p;
523 }
524 string_t stringarray_at2(stringarray_t*sa, int pos)
525 {
526     string_t s;
527     s.str = stringarray_at(sa, pos);
528     s.len = s.str?strlen(s.str):0;
529     return s;
530 }
531 static stringlist_t* stringlist_del(stringarray_t*sa, stringlist_t*l, int index)
532 {
533     stringlist_t*ll = l;
534     stringlist_t*old = l;
535     while(l) {
536         if(index==l->index) {
537             old->next = l->next;
538             memset(l, 0, sizeof(stringlist_t));
539             rfx_free(l);
540             if(old==l)
541                 return 0;
542             else
543                 return ll;
544         }
545         old = l;
546         l = l->next;
547     }
548     fprintf(stderr, "Internal error: did not find string %d in hash\n", index);
549     return ll;
550 }
551
552 void stringarray_del(stringarray_t*sa, int pos)
553 {
554     stringarray_internal_t*s = (stringarray_internal_t*)sa->internal;
555     string_t str = stringarray_at2(sa, pos);
556     int hash = string_hash(&str) % s->hashsize;
557     s->hash[hash] = stringlist_del(sa, s->hash[hash], pos);
558     *(char**)&s->pos.buffer[pos*sizeof(char*)] = 0;
559 }
560 int stringarray_find(stringarray_t*sa, string_t* str)
561 {
562     stringarray_internal_t*s = (stringarray_internal_t*)sa->internal;
563     int hash = string_hash(str) % s->hashsize;
564     int t;
565     stringlist_t*l = s->hash[hash];
566     //TODO: statistics
567     while(l) {
568         string_t s = stringarray_at2(sa, l->index);
569         if(string_equals2(str, &s)) {
570             return l->index;
571         }
572         l = l->next;
573     }
574     return -1;
575 }
576 void stringarray_clear(stringarray_t*sa)
577 {
578     stringarray_internal_t*s = (stringarray_internal_t*)sa->internal;
579     mem_clear(&s->pos);
580     int t;
581     for(t=0;t<s->hashsize;t++) {
582         stringlist_t*l = s->hash[t];
583         while(l) {
584             stringlist_t*next = l->next;
585             memset(l, 0, sizeof(stringlist_t));
586             rfx_free(l);
587             l = next;
588         }
589     }
590     rfx_free(s->hash);s->hash=0;
591     rfx_free(s);
592 }
593 void stringarray_destroy(stringarray_t*sa)
594 {
595     stringarray_clear(sa);
596     rfx_free(sa);
597 }
598
599 // ------------------------------- type_t -------------------------------
600
601 char ptr_equals(const void*o1, const void*o2) 
602 {
603     return o1==o2;
604 }
605 unsigned int ptr_hash(const void*o) 
606 {
607     return string_hash3((const char*)&o, sizeof(o));
608 }
609 void* ptr_dup(const void*o) 
610 {
611     return (void*)o;
612 }
613 void ptr_free(void*o) 
614 {
615     return;
616 }
617
618 char charptr_equals(const void*o1, const void*o2) 
619 {
620     if(!o1 || !o2)
621         return o1==o2;
622     return !strcmp(o1,o2);
623 }
624 unsigned int charptr_hash(const void*o) 
625 {
626     if(!o)
627         return 0;
628     return string_hash2(o);
629 }
630 void* charptr_dup(const void*o) 
631 {
632     if(!o)
633         return 0;
634     return strdup(o);
635 }
636 void charptr_free(void*o) 
637 {
638     if(o) {
639         rfx_free(o);
640     }
641 }
642
643 char stringstruct_equals(const void*o1, const void*o2) 
644 {
645     if(!o1 || !o2) 
646         return o1==o2;
647     string_t*s1 = (string_t*)o1;
648     string_t*s2 = (string_t*)o2;
649     int l = s1->len<s2->len?s1->len:s2->len;
650     int r = memcmp(s1->str, s2->str, l);
651     if(r)
652         return 0;
653     else
654         return s1->len==s2->len;
655 }
656 unsigned int stringstruct_hash(const void*o) 
657 {
658     if(!o) return 0;
659     return string_hash(o);
660 }
661 string_t*string_dup3(string_t*o)
662 {
663     if(!o) return 0;
664     if(!o->str) {
665         string_t*s = malloc(sizeof(string_t));
666         s->str=0;
667         s->len=0;
668         return s;
669     }
670     string_t*s = rfx_alloc(sizeof(string_t)+o->len+1);
671     s->len = o->len;
672     s->str = (const char*)(s+1);
673     memcpy((char*)s->str, o->str, s->len);
674     ((char*)s->str)[s->len]=0;
675     return s;
676 }
677 void stringstruct_free(void*o) 
678 {
679     if(o)
680         string_free(o);
681 }
682
683 type_t ptr_type = {
684     equals: ptr_equals,
685     hash: ptr_hash,
686     dup: ptr_dup,
687     free: ptr_free,
688 };
689
690 type_t charptr_type = {
691     equals: charptr_equals,
692     hash: charptr_hash,
693     dup: charptr_dup,
694     free: charptr_free,
695 };
696
697 type_t stringstruct_type = {
698     equals: stringstruct_equals,
699     hash: stringstruct_hash,
700     dup: (dup_func)string_dup3,
701     free: stringstruct_free,
702 };
703
704 // ------------------------------- dictionary_t -------------------------------
705
706 #define INITIAL_SIZE 1
707
708 static int max(int x, int y) {
709     return x>y?x:y;
710 }
711
712 dict_t*dict_new()
713 {
714     dict_t*d = rfx_alloc(sizeof(dict_t));
715     dict_init(d, INITIAL_SIZE);
716     return d;
717 }
718 dict_t*dict_new2(type_t*t)
719 {
720     dict_t*d = rfx_alloc(sizeof(dict_t));
721     dict_init(d, INITIAL_SIZE);
722     d->key_type = t;
723     return d;
724 }
725 void dict_init(dict_t*h, int size) 
726 {
727     memset(h, 0, sizeof(dict_t));
728     h->hashsize = size;
729     h->slots = h->hashsize?(dictentry_t**)rfx_calloc(sizeof(dictentry_t*)*h->hashsize):0;
730     h->num = 0;
731     h->key_type = &charptr_type;
732 }
733
734 dict_t*dict_clone(dict_t*o)
735 {
736     dict_t*h = rfx_alloc(sizeof(dict_t));
737     memcpy(h, o, sizeof(dict_t));
738     h->slots = h->hashsize?(dictentry_t**)rfx_calloc(sizeof(dictentry_t*)*h->hashsize):0;
739     int t;
740     for(t=0;t<o->hashsize;t++) {
741         dictentry_t*e = o->slots[t];
742         while(e) {
743             dictentry_t*n = (dictentry_t*)rfx_alloc(sizeof(dictentry_t));
744             memcpy(n, e, sizeof(dictentry_t));
745             n->key = h->key_type->dup(e->key);
746             n->data = e->data;
747             n->next = h->slots[t];
748             h->slots[t] = n;
749             e = e->next;
750         }
751     }
752     return h;
753 }
754
755 static void dict_expand(dict_t*h, int newlen)
756 {
757     assert(h->hashsize < newlen);
758     dictentry_t**newslots = (dictentry_t**)rfx_calloc(sizeof(dictentry_t*)*newlen);
759     int t; 
760     for(t=0;t<h->hashsize;t++) {
761         dictentry_t*e = h->slots[t];
762         while(e) {
763             dictentry_t*next = e->next;
764             unsigned int newhash = e->hash%newlen;
765             e->next = newslots[newhash];
766             newslots[newhash] = e;
767             e = next;
768         }
769     }
770     if(h->slots)
771         rfx_free(h->slots);
772     h->slots = newslots;
773     h->hashsize = newlen;
774 }
775
776 dictentry_t* dict_put(dict_t*h, const void*key, void* data)
777 {
778     unsigned int hash = h->key_type->hash(key);
779     dictentry_t*e = (dictentry_t*)rfx_alloc(sizeof(dictentry_t));
780     unsigned int hash2 = hash % h->hashsize;
781     
782     e->key = h->key_type->dup(key);
783     e->hash = hash; //for resizing
784     e->next = h->slots[hash2];
785     e->data = data;
786     h->slots[hash2] = e;
787     h->num++;
788     return e;
789 }
790 void dict_put2(dict_t*h, const char*s, void*data) 
791 {
792     assert(h->key_type == &charptr_type);
793     dict_put(h, s, data);
794 }
795 void dict_dump(dict_t*h, FILE*fi, const char*prefix)
796 {
797     int t;
798     for(t=0;t<h->hashsize;t++) {
799         dictentry_t*e = h->slots[t];
800         while(e) {
801             if(h->key_type!=&charptr_type) {
802                 fprintf(fi, "%s%08x=%08x\n", prefix, e->key, e->data);
803             } else {
804                 fprintf(fi, "%s%s=%08x\n", prefix, e->key, e->data);
805             }
806             e = e->next;
807         }
808     }
809 }
810
811 int dict_count(dict_t*h)
812 {
813     return h->num;
814 }
815
816 static inline dictentry_t* dict_do_lookup(dict_t*h, const void*key)
817 {
818     if(!h->num) {
819         return 0;
820     }
821     
822     unsigned int ohash = h->key_type->hash(key);
823     unsigned int hash = ohash % h->hashsize;
824
825     /* check first entry for match */
826     dictentry_t*e = h->slots[hash];
827     if(e && h->key_type->equals(e->key, key)) {
828         return e;
829     } else if(e) {
830         e = e->next;
831     }
832
833     /* if dict is 2/3 filled, double the size. Do
834        this the first time we have to actually iterate
835        through a slot to find our data */
836     if(e && h->num*3 >= h->hashsize*2) {
837         int newsize = h->hashsize;
838         while(h->num*3 >= newsize*2) {
839             newsize = newsize<15?15:(newsize+1)*2-1;
840         }
841         dict_expand(h, newsize);
842         hash = ohash % h->hashsize;
843         e = h->slots[hash];
844         if(e && h->key_type->equals(e->key, key)) {
845             // omit move to front
846             return e;
847         } else if(e) {
848             e = e->next;
849         }
850     }
851
852     /* check subsequent entries for a match */
853     dictentry_t*last = h->slots[hash];
854     while(e) {
855         if(h->key_type->equals(e->key, key)) {
856             /* move to front- makes a difference of about 10% in most applications */
857             last->next = e->next;
858             e->next = h->slots[hash];
859             h->slots[hash] = e;
860             return e;
861         }
862         last=e;
863         e = e->next;
864     }
865     return 0;
866 }
867 void* dict_lookup(dict_t*h, const void*key)
868 {
869     dictentry_t*e = dict_do_lookup(h, key);
870     if(e)
871         return e->data;
872     return 0;
873 }
874 char dict_contains(dict_t*h, const void*key)
875 {
876     dictentry_t*e = dict_do_lookup(h, key);
877     return !!e;
878 }
879
880 char dict_del(dict_t*h, const void*key)
881 {
882     if(!h->num)
883         return 0;
884     unsigned int hash = h->key_type->hash(key) % h->hashsize;
885     dictentry_t*head = h->slots[hash];
886     dictentry_t*e = head, *prev=0;
887     while(e) {
888         if(h->key_type->equals(e->key, key)) {
889             dictentry_t*next = e->next;
890             rfx_free((void*)e->key);
891             memset(e, 0, sizeof(dictentry_t));
892             rfx_free(e);
893             if(e == head) {
894                 h->slots[hash] = 0;
895             } else {
896                 assert(prev);
897                 prev->next = next;
898             }
899             h->num--;
900             return 1;
901         }
902         prev = e;
903         e = e->next;
904     }
905     return 0;
906 }
907
908 dictentry_t* dict_get_slot(dict_t*h, const void*key)
909 {
910     if(!h->num)
911         return 0;
912     unsigned int ohash = h->key_type->hash(key);
913     unsigned int hash = ohash % h->hashsize;
914     return h->slots[hash];
915 }
916
917 void dict_foreach_keyvalue(dict_t*h, void (*runFunction)(void*data, const void*key, void*val), void*data)
918 {
919     int t;
920     for(t=0;t<h->hashsize;t++) {
921         dictentry_t*e = h->slots[t];
922         while(e) {
923             dictentry_t*next = e->next;
924             if(runFunction) {
925                 runFunction(data, e->key, e->data);
926             }
927             e = e->next;
928         }
929     }
930 }
931 void dict_foreach_value(dict_t*h, void (*runFunction)(void*))
932 {
933     int t;
934     for(t=0;t<h->hashsize;t++) {
935         dictentry_t*e = h->slots[t];
936         while(e) {
937             dictentry_t*next = e->next;
938             if(runFunction) {
939                 runFunction(e->data);
940             }
941             e = e->next;
942         }
943     }
944 }
945
946 void dict_free_all(dict_t*h, char free_keys, void (*free_data_function)(void*))
947 {
948     int t;
949     for(t=0;t<h->hashsize;t++) {
950         dictentry_t*e = h->slots[t];
951         while(e) {
952             dictentry_t*next = e->next;
953             if(free_keys) {
954                 h->key_type->free(e->key);
955             }
956             if(free_data_function) {
957                 free_data_function(e->data);
958             }
959             memset(e, 0, sizeof(dictentry_t));
960             rfx_free(e);
961             e = next;
962         }
963         h->slots[t]=0;
964     }
965     rfx_free(h->slots);
966     memset(h, 0, sizeof(dict_t));
967 }
968
969 void dict_clear_shallow(dict_t*h) 
970 {
971     dict_free_all(h, 0, 0);
972 }
973
974 void dict_clear(dict_t*h) 
975 {
976     dict_free_all(h, 1, 0);
977 }
978
979 void dict_destroy_shallow(dict_t*dict)
980 {
981     dict_clear_shallow(dict);
982     rfx_free(dict);
983 }
984
985 void dict_destroy(dict_t*dict)
986 {
987     dict_clear(dict);
988     rfx_free(dict);
989 }
990
991 // ------------------------------- map_t --------------------------------------
992
993 typedef struct _map_internal_t
994 {
995     dict_t d;
996 } map_internal_t;
997
998 void map_init(map_t*map)
999 {
1000     map_internal_t*m;
1001     map->internal = (map_internal_t*)rfx_calloc(sizeof(map_internal_t));
1002     m = (map_internal_t*)map->internal;
1003     dict_init(&m->d, INITIAL_SIZE);
1004 }
1005 void map_put(map_t*map, string_t t1, string_t t2)
1006 {
1007     map_internal_t*m = (map_internal_t*)map->internal;
1008     string_t s;
1009     char* s1 = string_cstr(&t1);
1010     dict_put2(&m->d, s1, (void*)string_cstr(&t2));
1011     rfx_free(s1);
1012 }
1013 const char* map_lookup(map_t*map, const char*name)
1014 {
1015     map_internal_t*m = (map_internal_t*)map->internal;
1016     const char*value = dict_lookup(&m->d, name);
1017     return value;
1018 }
1019 static void freestring(void*data)
1020 {
1021     rfx_free(data);
1022 }
1023 static void dumpmapentry(void*data, const void*key, void*value)
1024 {
1025     FILE*fi = (FILE*)data;
1026     fprintf(fi, "%s=%s\n", key, (char*)value);
1027 }
1028 void map_dump(map_t*map, FILE*fi, const char*prefix)
1029 {
1030     int t;
1031     map_internal_t*m = (map_internal_t*)map->internal;
1032     dict_foreach_keyvalue(&m->d, dumpmapentry, fi);
1033 }
1034 void map_clear(map_t*map)
1035 {
1036     map_internal_t*m = (map_internal_t*)map->internal;
1037     dict_free_all(&m->d, 1, freestring);
1038     rfx_free(m);
1039 }
1040 void map_destroy(map_t*map)
1041 {
1042     map_clear(map);
1043     rfx_free(map);
1044 }
1045
1046 // ------------------------------- array_t --------------------------------------
1047
1048 array_t* array_new() {
1049     array_t*d = malloc(sizeof(array_t));
1050     memset(d, 0, sizeof(array_t));
1051     d->entry2pos = dict_new();
1052     return d;
1053 }
1054 array_t* array_new2(type_t*type) {
1055     array_t*d = malloc(sizeof(array_t));
1056     memset(d, 0, sizeof(array_t));
1057     d->entry2pos = dict_new2(type);
1058     return d;
1059 }
1060 void*array_getkey(array_t*array, int nr) {
1061     if(nr > array->num || nr<0) {
1062         printf("error: reference to element %d in array[%d]\n", nr, array->num);
1063         *(int*)0 = 0xdead;
1064         return 0;
1065     }
1066     return array->d[nr].name;
1067 }
1068 void*array_getvalue(array_t*array, int nr) {
1069     if(nr > array->num || nr<0) {
1070         printf("error: reference to element %d in array[%d]\n", nr, array->num);
1071         *(int*)0 = 0xdead;
1072         return 0;
1073     }
1074     return array->d[nr].data;
1075 }
1076 int array_append(array_t*array, const void*name, void*data) {
1077     while(array->size <= array->num) {
1078         array->size += 64;
1079         if(!array->d) {
1080             array->d = malloc(sizeof(array_entry_t)*array->size);
1081         } else {
1082             array->d = realloc(array->d, sizeof(array_entry_t)*array->size);
1083         }
1084     }
1085
1086     dictentry_t*e = dict_put(array->entry2pos, name, (void*)(ptroff_t)(array->num+1));
1087
1088     if(name) {
1089         array->d[array->num].name = e->key;
1090     } else {
1091         array->d[array->num].name = 0;
1092     }
1093     array->d[array->num].data = (void*)data;
1094     return array->num++;
1095 }
1096 int array_find(array_t*array, const void*name)
1097 {
1098     int pos = (int)(ptroff_t)dict_lookup(array->entry2pos, name);
1099     return pos-1;
1100 }
1101 int array_find2(array_t*array, const void*name, void*data)
1102 {
1103     dict_t*h= array->entry2pos;
1104     dictentry_t*e = dict_get_slot(array->entry2pos, name);
1105
1106     while(e) {
1107         int index = ((int)(ptroff_t)e->data) - 1;
1108         if(h->key_type->equals(e->key, name) && array->d[index].data == data) {
1109             return index;
1110         }
1111         e = e->next;
1112     }
1113     return -1;
1114 }
1115 int array_update(array_t*array, const void*name, void*data) {
1116     int pos = array_find(array, name);
1117     if(pos>=0) {
1118         array->d[pos].data = data;
1119         return pos;
1120     }
1121     return array_append(array, name, data);
1122 }
1123 int array_append_if_new(array_t*array, const void*name, void*data) {
1124     int pos = array_find(array, name);
1125     if(pos>=0)
1126         return pos;
1127     return array_append(array, name, data);
1128 }
1129 void array_free(array_t*array) {
1130     dict_destroy(array->entry2pos);
1131     if(array->d) {
1132         free(array->d);array->d = 0;
1133     }
1134     free(array);
1135 }
1136
1137 // ------------------------------- list_t --------------------------------------
1138
1139 struct _commonlist;
1140 typedef struct _listinfo {
1141     int size;
1142     struct _commonlist*last;
1143 } listinfo_t;
1144
1145 typedef struct _commonlist {
1146     void*entry;
1147     struct _commonlist*next;
1148     listinfo_t info[0];
1149 } commonlist_t;
1150
1151 int list_length_(void*_list)
1152 {
1153     commonlist_t*l = (commonlist_t*)_list;
1154     if(!l)
1155         return 0;
1156     return l->info[0].size;
1157 }
1158 void list_concat_(void*_l1, void*_l2)
1159 {
1160     commonlist_t**l1 = (commonlist_t**)_l1;
1161     commonlist_t**l2 = (commonlist_t**)_l2;
1162
1163     if(!*l1) {
1164         *l1 = *l2;
1165     } else if(*l2) {
1166         (*l1)->info[0].last->next = *l2;
1167         (*l1)->info[0].last = (*l2)->info[0].last;
1168         (*l1)->info[0].size += (*l2)->info[0].size;
1169     }
1170     *l2 = 0;
1171 }
1172 void list_append_(void*_list, void*entry)
1173 {
1174     commonlist_t**list = (commonlist_t**)_list;
1175     commonlist_t* n = 0;
1176     if(!*list) {
1177         n = (commonlist_t*)malloc(sizeof(commonlist_t)+sizeof(listinfo_t));
1178         *list = n;
1179         (*list)->info[0].size = 0;
1180     } else {
1181         n = malloc(sizeof(commonlist_t));
1182         (*list)->info[0].last->next = n;
1183     }
1184     n->next = 0;
1185     n->entry = entry;
1186     (*list)->info[0].last = n;
1187     (*list)->info[0].size++;
1188 }
1189 /* notice: prepending uses slighly more space than appending */
1190 void list_prepend_(void*_list, void*entry)
1191 {
1192     commonlist_t**list = (commonlist_t**)_list;
1193     commonlist_t* n = (commonlist_t*)malloc(sizeof(commonlist_t)+sizeof(listinfo_t));
1194     int size = 0;
1195     commonlist_t* last = 0;
1196     if(*list) {
1197         last = (*list)->info[0].last;
1198         size = (*list)->info[0].size;
1199     }
1200     n->next = *list;
1201     n->entry = entry;
1202     *list = n;
1203     (*list)->info[0].last = last;
1204     (*list)->info[0].size = size+1;
1205 }
1206 void list_free_(void*_list) 
1207 {
1208     commonlist_t**list = (commonlist_t**)_list;
1209     commonlist_t*l = *list;
1210     while(l) {
1211         commonlist_t*next = l->next;
1212         free(l);
1213         l = next;
1214     }
1215     *list = 0;
1216 }
1217 void list_deep_free_(void*_list)
1218 {
1219     commonlist_t**list = (commonlist_t**)_list;
1220     commonlist_t*l = *list;
1221     while(l) {
1222         commonlist_t*next = l->next;
1223         if(l->entry) {
1224             free(l->entry);l->entry=0;
1225         }
1226         free(l);
1227         l = next;
1228     }
1229     *list = 0;
1230 }
1231 void*list_clone_(void*_list) 
1232 {
1233     commonlist_t*l = *(commonlist_t**)_list;
1234
1235     void*dest = 0;
1236     while(l) {
1237         commonlist_t*next = l->next;
1238         list_append_(&dest, l->entry);
1239         l = next;
1240     }
1241     return dest;
1242
1243 }