/*
* 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;
}