/* * Copyright 2001-2004 Brandon Long * All Rights Reserved. * * ClearSilver Templating System * * This code is made available under the terms of the ClearSilver License. * http://www.clearsilver.net/license.hdf * */ #include "cs_config.h" #include <stdlib.h> #include <string.h> #include <errno.h> #include "neo_misc.h" #include "neo_err.h" #include "ulist.h" #define ULIST_DEFAULT_SIZE 10 static NEOERR *check_resize (ULIST *ul, int size) { if (size > ul->max) { void **new_items; int new_size = 0; new_size = ul->max*2; if (size > new_size) { new_size = size + ul->max; } new_items = (void **) realloc ((void *)(ul->items), new_size * sizeof(void *)); if (new_items == NULL) { return nerr_raise(NERR_NOMEM, "Unable to resize ULIST to %d: Out of memory", new_size); } ul->items = new_items; ul->max = new_size; } return STATUS_OK; } NEOERR *uListInit(ULIST **ul, int size, int flags) { ULIST *r_ul; *ul = NULL; if (size == 0) { size = ULIST_DEFAULT_SIZE; } r_ul = (ULIST *) calloc (1, sizeof (ULIST)); if (r_ul == NULL) { return nerr_raise(NERR_NOMEM, "Unable to create ULIST: Out of memory"); } r_ul->items = (void **) calloc (size, sizeof(void *)); if (r_ul->items == NULL) { free (r_ul); return nerr_raise(NERR_NOMEM, "Unable to create ULIST: Out of memory"); } r_ul->num = 0; r_ul->max = size; r_ul->flags = flags; *ul = r_ul; return STATUS_OK; } NEOERR *uListvInit(ULIST **ul, ...) { NEOERR *err; va_list ap; void *it; err = uListInit (ul, 0, 0); if (err) return nerr_pass (err); va_start (ap, ul); it = va_arg (ap, void *); while (it) { err = uListAppend (*ul, it); if (err) { uListDestroy(ul, 0); return nerr_pass (err); } it = va_arg (ap, void *); } return STATUS_OK; } NEOERR *uListAppend (ULIST *ul, void *data) { NEOERR *r; r = check_resize (ul, ul->num + 1); if (r != STATUS_OK) return r; ul->items[ul->num] = data; ul->num++; return STATUS_OK; } NEOERR *uListPop (ULIST *ul, void **data) { if (ul->num == 0) return nerr_raise(NERR_OUTOFRANGE, "uListPop: empty list"); *data = ul->items[ul->num - 1]; ul->num--; return STATUS_OK; } NEOERR *uListInsert (ULIST *ul, int x, void *data) { void **start; NEOERR *r; if (x < 0) x = ul->num + x; if (x >= ul->num) return nerr_raise(NERR_OUTOFRANGE, "uListInsert: past end (%d > %d)", x, ul->num); r = check_resize (ul, ul->num + 1); if (r != STATUS_OK) return r; start = &(ul->items[x]); memmove (start + 1, start, (ul->num - x) * sizeof(void *)); ul->items[x] = data; ++ul->num; return STATUS_OK; } NEOERR *uListDelete (ULIST *ul, int x, void **data) { void **start; if (x < 0) x = ul->num + x; if (x >= ul->num) return nerr_raise(NERR_OUTOFRANGE, "uListDelete: past end (%d > %d)", x, ul->num); if (data != NULL) *data = ul->items[x]; start = &(ul->items[x]); memmove (start, start+1, (ul->num - x - 1) * sizeof(void *)); --ul->num; return STATUS_OK; } NEOERR *uListGet (ULIST *ul, int x, void **data) { if (x < 0) x = ul->num + x; if (x >= ul->num) return nerr_raise(NERR_OUTOFRANGE, "uListGet: past end (%d > %d)", x, ul->num); if (x < 0) return nerr_raise(NERR_OUTOFRANGE, "uListGet: past beginning (%d < 0)", x); *data = ul->items[x]; return STATUS_OK; } NEOERR *uListSet (ULIST *ul, int x, void *data) { if (x >= ul->num) return nerr_raise(NERR_OUTOFRANGE, "uListSet: past end (%d > %d)", x, ul->num); ul->items[x] = data; return STATUS_OK; } NEOERR *uListReverse (ULIST *ul) { int i; for (i = 0; i < ul->num/2; ++i) { void *tmp = ul->items[i]; ul->items[i] = ul->items[ul->num-1-i]; ul->items[ul->num-1-i] = tmp; } return STATUS_OK; } NEOERR *uListSort (ULIST *ul, int (*compareFunc)(const void *, const void*)) { qsort(ul->items, ul->num, sizeof(void *), compareFunc); return STATUS_OK; } void *uListSearch (ULIST *ul, const void *key, int (*compareFunc)(const void *, const void*)) { return bsearch(key, ul->items, ul->num, sizeof(void *), compareFunc); } void *uListIn (ULIST *ul, const void *key, int (*compareFunc)(const void *, const void*)) { int i; for (i = 0; i < ul->num; ++i) { if (!compareFunc(key, &ul->items[i])) { return &ul->items[i]; } } return NULL; } int uListIndex (ULIST *ul, const void *key, int (*compareFunc)(const void *, const void*)) { void **p = uListIn(ul, key, compareFunc); return p ? (p - ul->items) : -1; } NEOERR *uListDestroy (ULIST **ul, int flags) { if (flags & ULIST_FREE) { return uListDestroyFunc(ul, free); } else { return uListDestroyFunc(ul, NULL); } } NEOERR *uListDestroyFunc (ULIST **ul, void (*destroyFunc)(void *)) { ULIST *r_ul; r_ul = *ul; if (r_ul == NULL) return STATUS_OK; if (destroyFunc != NULL) { int x; for (x = 0; x < r_ul->num; x++) { (*destroyFunc)(r_ul->items[x]); } } free (r_ul->items); free (r_ul); *ul = NULL; return STATUS_OK; } int uListLength (ULIST *ul) { if (ul == NULL) return 0; return ul->num; }