Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright 2001-2004 Brandon Long
      3  * All Rights Reserved.
      4  *
      5  * ClearSilver Templating System
      6  *
      7  * This code is made available under the terms of the ClearSilver License.
      8  * http://www.clearsilver.net/license.hdf
      9  *
     10  */
     11 
     12 #include "cs_config.h"
     13 
     14 #include <stdlib.h>
     15 #include <string.h>
     16 #include <errno.h>
     17 
     18 #include "neo_misc.h"
     19 #include "neo_err.h"
     20 #include "ulist.h"
     21 
     22 #define ULIST_DEFAULT_SIZE 10
     23 
     24 static NEOERR *check_resize (ULIST *ul, int size)
     25 {
     26   if (size > ul->max)
     27   {
     28     void **new_items;
     29     int new_size = 0;
     30 
     31     new_size = ul->max*2;
     32     if (size > new_size)
     33     {
     34       new_size = size + ul->max;
     35     }
     36 
     37     new_items = (void **) realloc ((void *)(ul->items), new_size * sizeof(void *));
     38     if (new_items == NULL)
     39     {
     40       return nerr_raise(NERR_NOMEM,
     41 	  "Unable to resize ULIST to %d: Out of memory", new_size);
     42     }
     43     ul->items = new_items;
     44     ul->max = new_size;
     45   }
     46 
     47   return STATUS_OK;
     48 }
     49 
     50 
     51 NEOERR *uListInit(ULIST **ul, int size, int flags)
     52 {
     53   ULIST *r_ul;
     54 
     55   *ul = NULL;
     56   if (size == 0)
     57   {
     58     size = ULIST_DEFAULT_SIZE;
     59   }
     60 
     61   r_ul = (ULIST *) calloc (1, sizeof (ULIST));
     62   if (r_ul == NULL)
     63   {
     64     return nerr_raise(NERR_NOMEM, "Unable to create ULIST: Out of memory");
     65   }
     66   r_ul->items = (void **) calloc (size, sizeof(void *));
     67   if (r_ul->items == NULL)
     68   {
     69     free (r_ul);
     70     return nerr_raise(NERR_NOMEM, "Unable to create ULIST: Out of memory");
     71   }
     72 
     73   r_ul->num = 0;
     74   r_ul->max = size;
     75   r_ul->flags = flags;
     76   *ul = r_ul;
     77 
     78   return STATUS_OK;
     79 }
     80 
     81 NEOERR *uListvInit(ULIST **ul, ...)
     82 {
     83   NEOERR *err;
     84   va_list ap;
     85   void *it;
     86 
     87   err = uListInit (ul, 0, 0);
     88   if (err) return nerr_pass (err);
     89 
     90   va_start (ap, ul);
     91 
     92   it = va_arg (ap, void *);
     93 
     94   while (it)
     95   {
     96     err = uListAppend (*ul, it);
     97     if (err)
     98     {
     99       uListDestroy(ul, 0);
    100       return nerr_pass (err);
    101     }
    102     it = va_arg (ap, void *);
    103   }
    104   return STATUS_OK;
    105 }
    106 
    107 NEOERR *uListAppend (ULIST *ul, void *data)
    108 {
    109   NEOERR *r;
    110 
    111   r = check_resize (ul, ul->num + 1);
    112   if (r != STATUS_OK)
    113     return r;
    114 
    115   ul->items[ul->num] = data;
    116   ul->num++;
    117 
    118   return STATUS_OK;
    119 }
    120 
    121 NEOERR *uListPop (ULIST *ul, void **data)
    122 {
    123   if (ul->num == 0)
    124     return nerr_raise(NERR_OUTOFRANGE, "uListPop: empty list");
    125 
    126   *data = ul->items[ul->num - 1];
    127   ul->num--;
    128 
    129   return STATUS_OK;
    130 }
    131 
    132 NEOERR *uListInsert (ULIST *ul, int x, void *data)
    133 {
    134   void **start;
    135   NEOERR *r;
    136 
    137   if (x < 0)
    138     x = ul->num + x;
    139 
    140   if (x >= ul->num)
    141     return nerr_raise(NERR_OUTOFRANGE, "uListInsert: past end (%d > %d)",
    142 	x, ul->num);
    143 
    144   r = check_resize (ul, ul->num + 1);
    145   if (r != STATUS_OK)
    146     return r;
    147 
    148   start = &(ul->items[x]);
    149   memmove (start + 1, start, (ul->num - x) * sizeof(void *));
    150   ul->items[x] = data;
    151   ++ul->num;
    152 
    153   return STATUS_OK;
    154 }
    155 
    156 NEOERR *uListDelete (ULIST *ul, int x, void **data)
    157 {
    158   void **start;
    159 
    160   if (x < 0)
    161     x = ul->num + x;
    162 
    163   if (x >= ul->num)
    164     return nerr_raise(NERR_OUTOFRANGE, "uListDelete: past end (%d > %d)",
    165 	x, ul->num);
    166 
    167   if (data != NULL)
    168     *data = ul->items[x];
    169 
    170   start = &(ul->items[x]);
    171   memmove (start, start+1, (ul->num - x - 1) * sizeof(void *));
    172   --ul->num;
    173 
    174   return STATUS_OK;
    175 }
    176 
    177 NEOERR *uListGet (ULIST *ul, int x, void **data)
    178 {
    179   if (x < 0)
    180     x = ul->num + x;
    181 
    182   if (x >= ul->num)
    183     return nerr_raise(NERR_OUTOFRANGE, "uListGet: past end (%d > %d)",
    184 	x, ul->num);
    185 
    186   if (x < 0)
    187     return nerr_raise(NERR_OUTOFRANGE, "uListGet: past beginning (%d < 0)", x);
    188 
    189   *data = ul->items[x];
    190 
    191   return STATUS_OK;
    192 }
    193 
    194 NEOERR *uListSet (ULIST *ul, int x, void *data)
    195 {
    196   if (x >= ul->num)
    197     return nerr_raise(NERR_OUTOFRANGE, "uListSet: past end (%d > %d)",
    198 	x, ul->num);
    199 
    200   ul->items[x] = data;
    201 
    202   return STATUS_OK;
    203 }
    204 
    205 NEOERR *uListReverse (ULIST *ul)
    206 {
    207   int i;
    208 
    209   for (i = 0; i < ul->num/2; ++i) {
    210     void *tmp = ul->items[i];
    211     ul->items[i] = ul->items[ul->num-1-i];
    212     ul->items[ul->num-1-i] = tmp;
    213   }
    214 
    215   return STATUS_OK;
    216 }
    217 
    218 NEOERR *uListSort (ULIST *ul, int (*compareFunc)(const void *, const void*)) {
    219   qsort(ul->items, ul->num, sizeof(void *), compareFunc);
    220   return STATUS_OK;
    221 }
    222 
    223 void *uListSearch (ULIST *ul, const void *key, int
    224     (*compareFunc)(const void *, const void*)) {
    225   return bsearch(key, ul->items, ul->num, sizeof(void *), compareFunc);
    226 }
    227 
    228 void *uListIn (ULIST *ul, const void *key, int (*compareFunc)(const void *, const void*)) {
    229   int i;
    230 
    231   for (i = 0; i < ul->num; ++i) {
    232     if (!compareFunc(key, &ul->items[i])) {
    233       return &ul->items[i];
    234     }
    235   }
    236   return NULL;
    237 }
    238 
    239 int uListIndex (ULIST *ul, const void *key, int (*compareFunc)(const void *, const void*)) {
    240   void **p = uListIn(ul, key, compareFunc);
    241   return p ? (p - ul->items) : -1;
    242 }
    243 
    244 
    245 
    246 NEOERR *uListDestroy (ULIST **ul, int flags)
    247 {
    248   if (flags & ULIST_FREE)
    249   {
    250     return uListDestroyFunc(ul, free);
    251   }
    252   else
    253   {
    254     return uListDestroyFunc(ul, NULL);
    255   }
    256 }
    257 
    258 NEOERR *uListDestroyFunc (ULIST **ul, void (*destroyFunc)(void *))
    259 {
    260   ULIST *r_ul;
    261 
    262   r_ul = *ul;
    263 
    264   if (r_ul == NULL)
    265     return STATUS_OK;
    266 
    267   if (destroyFunc != NULL)
    268   {
    269     int x;
    270     for (x = 0; x < r_ul->num; x++)
    271     {
    272       (*destroyFunc)(r_ul->items[x]);
    273     }
    274   }
    275   free (r_ul->items);
    276   free (r_ul);
    277   *ul = NULL;
    278 
    279   return STATUS_OK;
    280 }
    281 
    282 int uListLength (ULIST *ul)
    283 {
    284   if (ul == NULL) return 0;
    285   return ul->num;
    286 }
    287