initial load of upstream version 1.06.32
[xmlrpc-c] / lib / abyss / src / data.c
diff --git a/lib/abyss/src/data.c b/lib/abyss/src/data.c
new file mode 100644 (file)
index 0000000..03f4c3f
--- /dev/null
@@ -0,0 +1,640 @@
+/******************************************************************************
+**
+** list.c
+**
+** This file is part of the ABYSS Web server project.
+**
+** Copyright (C) 2000 by Moez Mahfoudh <mmoez@bigfoot.com>.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+**    derived from this software without specific prior written permission.
+** 
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+**
+*******************************************************************************/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mallocvar.h"
+#include "xmlrpc-c/util_int.h"
+#include "xmlrpc-c/string_int.h"
+
+#include "xmlrpc-c/abyss.h"
+
+#include "token.h"
+
+#include "data.h"
+
+/*********************************************************************
+** List
+*********************************************************************/
+
+void ListInit(TList *sl)
+{
+    sl->item=NULL;
+    sl->size=sl->maxsize=0;
+    sl->autofree=FALSE;
+}
+
+void ListInitAutoFree(TList *sl)
+{
+    sl->item=NULL;
+    sl->size=sl->maxsize=0;
+    sl->autofree=TRUE;
+}
+
+
+
+void
+ListFree(TList * const sl) {
+
+    if (sl->item) {
+        if (sl->autofree) {
+            unsigned int i;
+            for (i = sl->size; i > 0; --i)
+                free(sl->item[i-1]);
+            
+        }
+        free(sl->item);
+    }
+    sl->item = NULL;
+    sl->size = 0;
+    sl->maxsize = 0;
+}
+
+
+
+void
+ListFreeItems(TList * const sl) {
+
+    if (sl->item) {
+        unsigned int i;
+        for (i = sl->size; i > 0; --i)
+            free(sl->item[i-1]);
+    }
+}
+
+
+
+abyss_bool
+ListAdd(TList * const sl,
+        void *  const str) {
+/*----------------------------------------------------------------------------
+   Add an item to the end of the list.
+-----------------------------------------------------------------------------*/
+    abyss_bool success;
+
+    if (sl->size >= sl->maxsize) {
+        uint16_t newSize = sl->maxsize + 16;
+        void **newitem;
+        
+        newitem = realloc(sl->item, newSize * sizeof(void *));
+        if (newitem) {
+            sl->item    = newitem;
+            sl->maxsize = newSize;
+        }
+    }
+
+    if (sl->size >= sl->maxsize)
+        success = FALSE;
+    else {
+        success = TRUE;
+        sl->item[sl->size++] = str;
+    }
+    return success;
+}
+
+
+
+void
+ListRemove(TList * const sl) {
+/*----------------------------------------------------------------------------
+   Remove the last item from the list.
+-----------------------------------------------------------------------------*/
+
+    assert(sl->size > 0);
+
+    --sl->size;
+}
+
+
+
+abyss_bool
+ListAddFromString(TList *      const list,
+                  const char * const stringArg) {
+
+    abyss_bool retval;
+    
+    if (!stringArg)
+        retval = TRUE;
+    else {
+        char * buffer;
+        
+        buffer = strdup(stringArg);
+        if (!buffer)
+            retval = FALSE;
+        else {
+            abyss_bool endOfString;
+            abyss_bool error;
+            char * c;
+
+            for (c = &buffer[0], endOfString = FALSE, error = FALSE;
+                 !endOfString && !error;
+                ) {
+                const char * t;
+                NextToken((const char **)&c);
+                
+                while (*c == ',')
+                    ++c;
+                
+                t = GetToken(&c);
+                if (!t)
+                    endOfString = TRUE;
+                else {
+                    char * p;
+
+                    for (p = c - 2; *p == ','; --p)
+                        *p = '\0';
+                    
+                    if (t[0] != '\0') {
+                        abyss_bool added;
+                        added = ListAdd(list, (void*)t);
+                        
+                        if (!added)
+                            error = TRUE;
+                    }
+                }
+            }
+            retval = !error;
+            xmlrpc_strfree(buffer);
+        }
+    }
+    return retval;
+}
+
+
+
+abyss_bool
+ListFindString(TList *      const sl,
+               const char * const str,
+               uint16_t *   const indexP)
+{
+    uint16_t i;
+
+    if (sl->item && str)
+        for (i=0;i<sl->size;i++)
+            if (strcmp(str,(char *)(sl->item[i]))==0)
+            {
+                *indexP=i;
+                return TRUE;
+            };
+
+    return FALSE;
+}
+
+/*********************************************************************
+** Buffer
+*********************************************************************/
+
+abyss_bool BufferAlloc(TBuffer *buf,uint32_t memsize)
+{
+    /* ************** Implement the static buffers ***/
+    buf->staticid=0;
+    buf->data=(void *)malloc(memsize);
+    if (buf->data)
+    {
+        buf->size=memsize;
+        return TRUE;
+    }
+    else
+    {
+        buf->size=0;
+        return FALSE;
+    };
+}
+
+void BufferFree(TBuffer *buf)
+{
+    if (buf->staticid)
+    {
+        /* ************** Implement the static buffers ***/
+    }
+    else
+        free(buf->data);
+
+    buf->size=0;
+    buf->staticid=0;
+}
+
+abyss_bool BufferRealloc(TBuffer *buf,uint32_t memsize)
+{
+    if (buf->staticid)
+    {
+        TBuffer b;
+
+        if (memsize<=buf->size)
+            return TRUE;
+
+        if (BufferAlloc(&b,memsize))
+        {
+            memcpy(b.data,buf->data,buf->size);
+            BufferFree(buf);
+            *buf=b;
+            return TRUE;
+        }
+    }
+    else
+    {
+        void *d;
+        
+        d=realloc(buf->data,memsize);
+        if (d)
+        {
+            buf->data=d;
+            buf->size=memsize;
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+
+/*********************************************************************
+** String
+*********************************************************************/
+
+abyss_bool StringAlloc(TString *s)
+{
+    s->size=0;
+    if (BufferAlloc(&(s->buffer),256))
+    {
+        *(char *)(s->buffer.data)='\0';
+        return TRUE;
+    }
+    else
+        return FALSE;
+}
+
+abyss_bool StringConcat(TString *s,char *s2)
+{
+    uint32_t len=strlen(s2);
+
+    if (len+s->size+1>s->buffer.size)
+        if (!BufferRealloc(&(s->buffer),((len+s->size+1+256)/256)*256))
+            return FALSE;
+    
+    strcat((char *)(s->buffer.data),s2);
+    s->size+=len;
+    return TRUE;
+}
+
+abyss_bool StringBlockConcat(TString *s,char *s2,char **ref)
+{
+    uint32_t len=strlen(s2)+1;
+
+    if (len+s->size>s->buffer.size)
+        if (!BufferRealloc(&(s->buffer),((len+s->size+1+256)/256)*256))
+            return FALSE;
+    
+    *ref=(char *)(s->buffer.data)+s->size;
+    memcpy(*ref,s2,len);
+    s->size+=len;
+    return TRUE;
+}
+
+void StringFree(TString *s)
+{
+    s->size=0;
+    BufferFree(&(s->buffer));
+}
+
+char *StringData(TString *s)
+{
+    return (char *)(s->buffer.data);
+}
+
+/*********************************************************************
+** Hash
+*********************************************************************/
+
+static uint16_t
+Hash16(const char * const start) {
+
+    const char * s;
+    
+    uint16_t i;
+    
+    s = start;
+    i = 0;
+
+    while(*s)
+        i = i * 37 + *s++;
+
+    return i;
+}
+
+/*********************************************************************
+** Table
+*********************************************************************/
+
+void TableInit(TTable *t)
+{
+    t->item=NULL;
+    t->size=t->maxsize=0;
+}
+
+void TableFree(TTable *t)
+{
+    uint16_t i;
+
+    if (t->item)
+    {
+        if (t->size)
+            for (i=t->size;i>0;i--)
+            {
+                free(t->item[i-1].name);
+                free(t->item[i-1].value);
+            };
+            
+        free(t->item);
+    }
+
+    TableInit(t);
+}
+
+
+
+abyss_bool
+TableFindIndex(TTable *     const t,
+               const char * const name,
+               uint16_t *   const index) {
+
+    uint16_t i,hash=Hash16(name);
+
+    if ((t->item) && (t->size>0) && (*index<t->size))
+    {
+        for (i=*index;i<t->size;i++)
+            if (hash==t->item[i].hash)
+                if (strcmp(t->item[i].name,name)==0)
+                {
+                    *index=i;
+                    return TRUE;
+                };
+    };
+
+    return FALSE;
+}
+
+
+
+abyss_bool
+TableAddReplace(TTable *     const t,
+                const char * const name,
+                const char * const value) {
+
+    uint16_t i=0;
+
+    if (TableFindIndex(t,name,&i))
+    {
+        free(t->item[i].value);
+        if (value)
+            t->item[i].value=strdup(value);
+        else
+        {
+            free(t->item[i].name);
+            if (--t->size>0)
+                t->item[i]=t->item[t->size];
+        };
+
+        return TRUE;
+    }
+    else
+        return TableAdd(t,name,value);
+}
+
+
+
+abyss_bool
+TableAdd(TTable *     const t,
+         const char * const name,
+         const char * const value) {
+
+    if (t->size>=t->maxsize) {
+        TTableItem *newitem;
+        
+        t->maxsize+=16;
+
+        newitem=(TTableItem *)realloc(t->item,(t->maxsize)*sizeof(TTableItem));
+        if (newitem)
+            t->item=newitem;
+        else {
+            t->maxsize-=16;
+            return FALSE;
+        }
+    }
+
+    t->item[t->size].name=strdup(name);
+    t->item[t->size].value=strdup(value);
+    t->item[t->size].hash=Hash16(name);
+
+    ++t->size;
+
+    return TRUE;
+}
+
+
+
+char *
+TableFind(TTable *     const t,
+          const char * const name) {
+
+    uint16_t i=0;
+
+    if (TableFindIndex(t,name,&i))
+        return t->item[i].value;
+    else
+        return NULL;
+}
+
+/*********************************************************************
+** Pool
+*********************************************************************/
+
+static TPoolZone *
+PoolZoneAlloc(uint32_t const zonesize) {
+
+    TPoolZone * poolZoneP;
+    
+    MALLOCARRAY(poolZoneP, zonesize);
+    if (poolZoneP) {
+        poolZoneP->pos    = &poolZoneP->data[0];
+        poolZoneP->maxpos = poolZoneP->pos + zonesize;
+        poolZoneP->next   = NULL;
+        poolZoneP->prev   = NULL;
+    }
+    return poolZoneP;
+}
+
+
+
+static void
+PoolZoneFree(TPoolZone * const poolZoneP) {
+
+    free(poolZoneP);
+}
+
+
+
+abyss_bool
+PoolCreate(TPool *  const poolP,
+           uint32_t const zonesize) {
+
+    abyss_bool success;
+    abyss_bool mutexCreated;
+
+    poolP->zonesize = zonesize;
+
+    mutexCreated = MutexCreate(&poolP->mutex);
+    if (mutexCreated) {
+        TPoolZone * const firstZoneP = PoolZoneAlloc(zonesize);
+
+        if (firstZoneP != NULL) {
+            poolP->firstzone   = firstZoneP;
+            poolP->currentzone = firstZoneP;
+            success = TRUE;
+        } else
+            success = FALSE;
+        if (!success)
+            MutexFree(&poolP->mutex);
+    } else
+        success = FALSE;
+
+    return success;
+}
+
+
+
+void *
+PoolAlloc(TPool *  const poolP,
+          uint32_t const size) {
+/*----------------------------------------------------------------------------
+   Allocate a block of size 'size' from pool 'poolP'.
+-----------------------------------------------------------------------------*/
+    void * retval;
+
+    if (size == 0)
+        retval = NULL;
+    else {
+        abyss_bool gotMutexLock;
+
+        gotMutexLock = MutexLock(&poolP->mutex);
+        if (!gotMutexLock)
+            retval = NULL;
+        else {
+            TPoolZone * const curPoolZoneP = poolP->currentzone;
+
+            if (curPoolZoneP->pos + size < curPoolZoneP->maxpos) {
+                retval = curPoolZoneP->pos;
+                curPoolZoneP->pos += size;
+            } else {
+                uint32_t const zonesize = MAX(size, poolP->zonesize);
+
+                TPoolZone * const newPoolZoneP = PoolZoneAlloc(zonesize);
+                if (newPoolZoneP) {
+                    newPoolZoneP->prev = curPoolZoneP;
+                    newPoolZoneP->next = curPoolZoneP->next;
+                    curPoolZoneP->next = newPoolZoneP;
+                    poolP->currentzone = newPoolZoneP;
+                    retval= newPoolZoneP->data;
+                    newPoolZoneP->pos = newPoolZoneP->data + size;
+                } else
+                    retval = NULL;
+            }
+            MutexUnlock(&poolP->mutex);
+        }
+    }
+    return retval;
+}
+
+
+
+void
+PoolReturn(TPool *  const poolP,
+           void *   const blockP) {
+/*----------------------------------------------------------------------------
+   Return the block at 'blockP' to the pool 'poolP'.  WE ASSUME THAT IS
+   THE MOST RECENTLY ALLOCATED AND NOT RETURNED BLOCK IN THE POOL.
+-----------------------------------------------------------------------------*/
+    TPoolZone * const curPoolZoneP = poolP->currentzone;
+
+    assert((char*)curPoolZoneP->data < (char*)blockP &&
+           (char*)blockP < (char*)curPoolZoneP->pos);
+
+    curPoolZoneP->pos = blockP;
+
+    if (curPoolZoneP->pos == curPoolZoneP->data) {
+        /* That emptied out the current zone.  Free it and make the previous
+           zone current.
+        */
+
+        assert(curPoolZoneP->prev);  /* entry condition */
+
+        curPoolZoneP->prev->next = NULL;
+
+        PoolZoneFree(curPoolZoneP);
+    }
+}
+
+
+
+void
+PoolFree(TPool * const poolP) {
+
+    TPoolZone * poolZoneP;
+    TPoolZone * nextPoolZoneP;
+    
+    for (poolZoneP = poolP->firstzone; poolZoneP; poolZoneP = nextPoolZoneP) {
+        nextPoolZoneP = poolZoneP->next;
+        free(poolZoneP);
+    }
+}
+
+
+
+const char *
+PoolStrdup(TPool *      const poolP,
+           const char * const origString) {
+
+    char * newString;
+
+    if (origString == NULL)
+        newString = NULL;
+    else {
+        newString = PoolAlloc(poolP, strlen(origString) + 1);
+        if (newString != NULL)
+            strcpy(newString, origString);
+    }
+    return newString;
+}