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
24static 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
51NEOERR *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
81NEOERR *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
107NEOERR *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
121NEOERR *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
132NEOERR *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
156NEOERR *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
177NEOERR *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
194NEOERR *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
205NEOERR *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
218NEOERR *uListSort (ULIST *ul, int (*compareFunc)(const void *, const void*)) {
219  qsort(ul->items, ul->num, sizeof(void *), compareFunc);
220  return STATUS_OK;
221}
222
223void *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
228void *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
239int 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
246NEOERR *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
258NEOERR *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
282int uListLength (ULIST *ul)
283{
284  if (ul == NULL) return 0;
285  return ul->num;
286}
287