initial load of upstream version 1.06.32
[xmlrpc-c] / lib / abyss / src / data.c
1 /******************************************************************************
2 **
3 ** list.c
4 **
5 ** This file is part of the ABYSS Web server project.
6 **
7 ** Copyright (C) 2000 by Moez Mahfoudh <mmoez@bigfoot.com>.
8 ** All rights reserved.
9 **
10 ** Redistribution and use in source and binary forms, with or without
11 ** modification, are permitted provided that the following conditions
12 ** are met:
13 ** 1. Redistributions of source code must retain the above copyright
14 **    notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 **    notice, this list of conditions and the following disclaimer in the
17 **    documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 **    derived from this software without specific prior written permission.
20 ** 
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 ** SUCH DAMAGE.
32 **
33 *******************************************************************************/
34
35 #include <assert.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include "mallocvar.h"
40 #include "xmlrpc-c/util_int.h"
41 #include "xmlrpc-c/string_int.h"
42
43 #include "xmlrpc-c/abyss.h"
44
45 #include "token.h"
46
47 #include "data.h"
48
49 /*********************************************************************
50 ** List
51 *********************************************************************/
52
53 void ListInit(TList *sl)
54 {
55     sl->item=NULL;
56     sl->size=sl->maxsize=0;
57     sl->autofree=FALSE;
58 }
59
60 void ListInitAutoFree(TList *sl)
61 {
62     sl->item=NULL;
63     sl->size=sl->maxsize=0;
64     sl->autofree=TRUE;
65 }
66
67
68
69 void
70 ListFree(TList * const sl) {
71
72     if (sl->item) {
73         if (sl->autofree) {
74             unsigned int i;
75             for (i = sl->size; i > 0; --i)
76                 free(sl->item[i-1]);
77             
78         }
79         free(sl->item);
80     }
81     sl->item = NULL;
82     sl->size = 0;
83     sl->maxsize = 0;
84 }
85
86
87
88 void
89 ListFreeItems(TList * const sl) {
90
91     if (sl->item) {
92         unsigned int i;
93         for (i = sl->size; i > 0; --i)
94             free(sl->item[i-1]);
95     }
96 }
97
98
99
100 abyss_bool
101 ListAdd(TList * const sl,
102         void *  const str) {
103 /*----------------------------------------------------------------------------
104    Add an item to the end of the list.
105 -----------------------------------------------------------------------------*/
106     abyss_bool success;
107
108     if (sl->size >= sl->maxsize) {
109         uint16_t newSize = sl->maxsize + 16;
110         void **newitem;
111         
112         newitem = realloc(sl->item, newSize * sizeof(void *));
113         if (newitem) {
114             sl->item    = newitem;
115             sl->maxsize = newSize;
116         }
117     }
118
119     if (sl->size >= sl->maxsize)
120         success = FALSE;
121     else {
122         success = TRUE;
123         sl->item[sl->size++] = str;
124     }
125     return success;
126 }
127
128
129
130 void
131 ListRemove(TList * const sl) {
132 /*----------------------------------------------------------------------------
133    Remove the last item from the list.
134 -----------------------------------------------------------------------------*/
135
136     assert(sl->size > 0);
137
138     --sl->size;
139 }
140
141
142
143 abyss_bool
144 ListAddFromString(TList *      const list,
145                   const char * const stringArg) {
146
147     abyss_bool retval;
148     
149     if (!stringArg)
150         retval = TRUE;
151     else {
152         char * buffer;
153         
154         buffer = strdup(stringArg);
155         if (!buffer)
156             retval = FALSE;
157         else {
158             abyss_bool endOfString;
159             abyss_bool error;
160             char * c;
161
162             for (c = &buffer[0], endOfString = FALSE, error = FALSE;
163                  !endOfString && !error;
164                 ) {
165                 const char * t;
166                 NextToken((const char **)&c);
167                 
168                 while (*c == ',')
169                     ++c;
170                 
171                 t = GetToken(&c);
172                 if (!t)
173                     endOfString = TRUE;
174                 else {
175                     char * p;
176
177                     for (p = c - 2; *p == ','; --p)
178                         *p = '\0';
179                     
180                     if (t[0] != '\0') {
181                         abyss_bool added;
182                         added = ListAdd(list, (void*)t);
183                         
184                         if (!added)
185                             error = TRUE;
186                     }
187                 }
188             }
189             retval = !error;
190             xmlrpc_strfree(buffer);
191         }
192     }
193     return retval;
194 }
195
196
197
198 abyss_bool
199 ListFindString(TList *      const sl,
200                const char * const str,
201                uint16_t *   const indexP)
202 {
203     uint16_t i;
204
205     if (sl->item && str)
206         for (i=0;i<sl->size;i++)
207             if (strcmp(str,(char *)(sl->item[i]))==0)
208             {
209                 *indexP=i;
210                 return TRUE;
211             };
212
213     return FALSE;
214 }
215
216 /*********************************************************************
217 ** Buffer
218 *********************************************************************/
219
220 abyss_bool BufferAlloc(TBuffer *buf,uint32_t memsize)
221 {
222     /* ************** Implement the static buffers ***/
223     buf->staticid=0;
224     buf->data=(void *)malloc(memsize);
225     if (buf->data)
226     {
227         buf->size=memsize;
228         return TRUE;
229     }
230     else
231     {
232         buf->size=0;
233         return FALSE;
234     };
235 }
236
237 void BufferFree(TBuffer *buf)
238 {
239     if (buf->staticid)
240     {
241         /* ************** Implement the static buffers ***/
242     }
243     else
244         free(buf->data);
245
246     buf->size=0;
247     buf->staticid=0;
248 }
249
250 abyss_bool BufferRealloc(TBuffer *buf,uint32_t memsize)
251 {
252     if (buf->staticid)
253     {
254         TBuffer b;
255
256         if (memsize<=buf->size)
257             return TRUE;
258
259         if (BufferAlloc(&b,memsize))
260         {
261             memcpy(b.data,buf->data,buf->size);
262             BufferFree(buf);
263             *buf=b;
264             return TRUE;
265         }
266     }
267     else
268     {
269         void *d;
270         
271         d=realloc(buf->data,memsize);
272         if (d)
273         {
274             buf->data=d;
275             buf->size=memsize;
276             return TRUE;
277         }
278     }
279
280     return FALSE;
281 }
282
283
284 /*********************************************************************
285 ** String
286 *********************************************************************/
287
288 abyss_bool StringAlloc(TString *s)
289 {
290     s->size=0;
291     if (BufferAlloc(&(s->buffer),256))
292     {
293         *(char *)(s->buffer.data)='\0';
294         return TRUE;
295     }
296     else
297         return FALSE;
298 }
299
300 abyss_bool StringConcat(TString *s,char *s2)
301 {
302     uint32_t len=strlen(s2);
303
304     if (len+s->size+1>s->buffer.size)
305         if (!BufferRealloc(&(s->buffer),((len+s->size+1+256)/256)*256))
306             return FALSE;
307     
308     strcat((char *)(s->buffer.data),s2);
309     s->size+=len;
310     return TRUE;
311 }
312
313 abyss_bool StringBlockConcat(TString *s,char *s2,char **ref)
314 {
315     uint32_t len=strlen(s2)+1;
316
317     if (len+s->size>s->buffer.size)
318         if (!BufferRealloc(&(s->buffer),((len+s->size+1+256)/256)*256))
319             return FALSE;
320     
321     *ref=(char *)(s->buffer.data)+s->size;
322     memcpy(*ref,s2,len);
323     s->size+=len;
324     return TRUE;
325 }
326
327 void StringFree(TString *s)
328 {
329     s->size=0;
330     BufferFree(&(s->buffer));
331 }
332
333 char *StringData(TString *s)
334 {
335     return (char *)(s->buffer.data);
336 }
337
338 /*********************************************************************
339 ** Hash
340 *********************************************************************/
341
342 static uint16_t
343 Hash16(const char * const start) {
344
345     const char * s;
346     
347     uint16_t i;
348     
349     s = start;
350     i = 0;
351
352     while(*s)
353         i = i * 37 + *s++;
354
355     return i;
356 }
357
358 /*********************************************************************
359 ** Table
360 *********************************************************************/
361
362 void TableInit(TTable *t)
363 {
364     t->item=NULL;
365     t->size=t->maxsize=0;
366 }
367
368 void TableFree(TTable *t)
369 {
370     uint16_t i;
371
372     if (t->item)
373     {
374         if (t->size)
375             for (i=t->size;i>0;i--)
376             {
377                 free(t->item[i-1].name);
378                 free(t->item[i-1].value);
379             };
380             
381         free(t->item);
382     }
383
384     TableInit(t);
385 }
386
387
388
389 abyss_bool
390 TableFindIndex(TTable *     const t,
391                const char * const name,
392                uint16_t *   const index) {
393
394     uint16_t i,hash=Hash16(name);
395
396     if ((t->item) && (t->size>0) && (*index<t->size))
397     {
398         for (i=*index;i<t->size;i++)
399             if (hash==t->item[i].hash)
400                 if (strcmp(t->item[i].name,name)==0)
401                 {
402                     *index=i;
403                     return TRUE;
404                 };
405     };
406
407     return FALSE;
408 }
409
410
411
412 abyss_bool
413 TableAddReplace(TTable *     const t,
414                 const char * const name,
415                 const char * const value) {
416
417     uint16_t i=0;
418
419     if (TableFindIndex(t,name,&i))
420     {
421         free(t->item[i].value);
422         if (value)
423             t->item[i].value=strdup(value);
424         else
425         {
426             free(t->item[i].name);
427             if (--t->size>0)
428                 t->item[i]=t->item[t->size];
429         };
430
431         return TRUE;
432     }
433     else
434         return TableAdd(t,name,value);
435 }
436
437
438
439 abyss_bool
440 TableAdd(TTable *     const t,
441          const char * const name,
442          const char * const value) {
443
444     if (t->size>=t->maxsize) {
445         TTableItem *newitem;
446         
447         t->maxsize+=16;
448
449         newitem=(TTableItem *)realloc(t->item,(t->maxsize)*sizeof(TTableItem));
450         if (newitem)
451             t->item=newitem;
452         else {
453             t->maxsize-=16;
454             return FALSE;
455         }
456     }
457
458     t->item[t->size].name=strdup(name);
459     t->item[t->size].value=strdup(value);
460     t->item[t->size].hash=Hash16(name);
461
462     ++t->size;
463
464     return TRUE;
465 }
466
467
468
469 char *
470 TableFind(TTable *     const t,
471           const char * const name) {
472
473     uint16_t i=0;
474
475     if (TableFindIndex(t,name,&i))
476         return t->item[i].value;
477     else
478         return NULL;
479 }
480
481 /*********************************************************************
482 ** Pool
483 *********************************************************************/
484
485 static TPoolZone *
486 PoolZoneAlloc(uint32_t const zonesize) {
487
488     TPoolZone * poolZoneP;
489     
490     MALLOCARRAY(poolZoneP, zonesize);
491     if (poolZoneP) {
492         poolZoneP->pos    = &poolZoneP->data[0];
493         poolZoneP->maxpos = poolZoneP->pos + zonesize;
494         poolZoneP->next   = NULL;
495         poolZoneP->prev   = NULL;
496     }
497     return poolZoneP;
498 }
499
500
501
502 static void
503 PoolZoneFree(TPoolZone * const poolZoneP) {
504
505     free(poolZoneP);
506 }
507
508
509
510 abyss_bool
511 PoolCreate(TPool *  const poolP,
512            uint32_t const zonesize) {
513
514     abyss_bool success;
515     abyss_bool mutexCreated;
516
517     poolP->zonesize = zonesize;
518
519     mutexCreated = MutexCreate(&poolP->mutex);
520     if (mutexCreated) {
521         TPoolZone * const firstZoneP = PoolZoneAlloc(zonesize);
522
523         if (firstZoneP != NULL) {
524             poolP->firstzone   = firstZoneP;
525             poolP->currentzone = firstZoneP;
526             success = TRUE;
527         } else
528             success = FALSE;
529         if (!success)
530             MutexFree(&poolP->mutex);
531     } else
532         success = FALSE;
533
534     return success;
535 }
536
537
538
539 void *
540 PoolAlloc(TPool *  const poolP,
541           uint32_t const size) {
542 /*----------------------------------------------------------------------------
543    Allocate a block of size 'size' from pool 'poolP'.
544 -----------------------------------------------------------------------------*/
545     void * retval;
546
547     if (size == 0)
548         retval = NULL;
549     else {
550         abyss_bool gotMutexLock;
551
552         gotMutexLock = MutexLock(&poolP->mutex);
553         if (!gotMutexLock)
554             retval = NULL;
555         else {
556             TPoolZone * const curPoolZoneP = poolP->currentzone;
557
558             if (curPoolZoneP->pos + size < curPoolZoneP->maxpos) {
559                 retval = curPoolZoneP->pos;
560                 curPoolZoneP->pos += size;
561             } else {
562                 uint32_t const zonesize = MAX(size, poolP->zonesize);
563
564                 TPoolZone * const newPoolZoneP = PoolZoneAlloc(zonesize);
565                 if (newPoolZoneP) {
566                     newPoolZoneP->prev = curPoolZoneP;
567                     newPoolZoneP->next = curPoolZoneP->next;
568                     curPoolZoneP->next = newPoolZoneP;
569                     poolP->currentzone = newPoolZoneP;
570                     retval= newPoolZoneP->data;
571                     newPoolZoneP->pos = newPoolZoneP->data + size;
572                 } else
573                     retval = NULL;
574             }
575             MutexUnlock(&poolP->mutex);
576         }
577     }
578     return retval;
579 }
580
581
582
583 void
584 PoolReturn(TPool *  const poolP,
585            void *   const blockP) {
586 /*----------------------------------------------------------------------------
587    Return the block at 'blockP' to the pool 'poolP'.  WE ASSUME THAT IS
588    THE MOST RECENTLY ALLOCATED AND NOT RETURNED BLOCK IN THE POOL.
589 -----------------------------------------------------------------------------*/
590     TPoolZone * const curPoolZoneP = poolP->currentzone;
591
592     assert((char*)curPoolZoneP->data < (char*)blockP &&
593            (char*)blockP < (char*)curPoolZoneP->pos);
594
595     curPoolZoneP->pos = blockP;
596
597     if (curPoolZoneP->pos == curPoolZoneP->data) {
598         /* That emptied out the current zone.  Free it and make the previous
599            zone current.
600         */
601
602         assert(curPoolZoneP->prev);  /* entry condition */
603
604         curPoolZoneP->prev->next = NULL;
605
606         PoolZoneFree(curPoolZoneP);
607     }
608 }
609
610
611
612 void
613 PoolFree(TPool * const poolP) {
614
615     TPoolZone * poolZoneP;
616     TPoolZone * nextPoolZoneP;
617     
618     for (poolZoneP = poolP->firstzone; poolZoneP; poolZoneP = nextPoolZoneP) {
619         nextPoolZoneP = poolZoneP->next;
620         free(poolZoneP);
621     }
622 }
623
624
625
626 const char *
627 PoolStrdup(TPool *      const poolP,
628            const char * const origString) {
629
630     char * newString;
631
632     if (origString == NULL)
633         newString = NULL;
634     else {
635         newString = PoolAlloc(poolP, strlen(origString) + 1);
636         if (newString != NULL)
637             strcpy(newString, origString);
638     }
639     return newString;
640 }