462 lines
9.3 KiB
C
462 lines
9.3 KiB
C
/* @configure_input@ */
|
|
|
|
/*
|
|
** Copyright 1998-2002 University of Illinois Board of Trustees
|
|
** Copyright 1998-2002 Mark D. Roth
|
|
** All rights reserved.
|
|
**
|
|
** @LISTHASH_PREFIX@_list.c - linked list routines
|
|
**
|
|
** Mark D. Roth <roth@uiuc.edu>
|
|
** Campus Information Technologies and Educational Services
|
|
** University of Illinois at Urbana-Champaign
|
|
*/
|
|
|
|
#include <@LISTHASH_PREFIX@/config.h>
|
|
#include <@LISTHASH_PREFIX@/compat.h>
|
|
|
|
#include <@LISTHASH_PREFIX@/@LISTHASH_PREFIX@_listhash.h>
|
|
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
|
|
#ifdef STDC_HEADERS
|
|
# include <string.h>
|
|
# include <stdlib.h>
|
|
#endif
|
|
|
|
|
|
/*
|
|
** @LISTHASH_PREFIX@_listptr_reset() - reset a list pointer
|
|
*/
|
|
void
|
|
@LISTHASH_PREFIX@_listptr_reset(@LISTHASH_PREFIX@_listptr_t *lp)
|
|
{
|
|
*lp = NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
** @LISTHASH_PREFIX@_listptr_data() - retrieve the data pointed to by lp
|
|
*/
|
|
void *
|
|
@LISTHASH_PREFIX@_listptr_data(@LISTHASH_PREFIX@_listptr_t *lp)
|
|
{
|
|
return (*lp)->data;
|
|
}
|
|
|
|
|
|
/*
|
|
** @LISTHASH_PREFIX@_list_new() - create a new, empty list
|
|
*/
|
|
@LISTHASH_PREFIX@_list_t *
|
|
@LISTHASH_PREFIX@_list_new(int flags, @LISTHASH_PREFIX@_cmpfunc_t cmpfunc)
|
|
{
|
|
@LISTHASH_PREFIX@_list_t *newlist;
|
|
|
|
#ifdef DS_DEBUG
|
|
printf("in @LISTHASH_PREFIX@_list_new(%d, 0x%lx)\n", flags, cmpfunc);
|
|
#endif
|
|
|
|
if (flags != LIST_USERFUNC
|
|
&& flags != LIST_STACK
|
|
&& flags != LIST_QUEUE)
|
|
{
|
|
errno = EINVAL;
|
|
return NULL;
|
|
}
|
|
|
|
newlist = (@LISTHASH_PREFIX@_list_t *)calloc(1, sizeof(@LISTHASH_PREFIX@_list_t));
|
|
if (cmpfunc != NULL)
|
|
newlist->cmpfunc = cmpfunc;
|
|
else
|
|
newlist->cmpfunc = (@LISTHASH_PREFIX@_cmpfunc_t)strcmp;
|
|
newlist->flags = flags;
|
|
|
|
return newlist;
|
|
}
|
|
|
|
|
|
/*
|
|
** @LISTHASH_PREFIX@_list_iterate() - call a function for every element
|
|
** in a list
|
|
*/
|
|
int
|
|
@LISTHASH_PREFIX@_list_iterate(@LISTHASH_PREFIX@_list_t *l,
|
|
@LISTHASH_PREFIX@_iterate_func_t plugin,
|
|
void *state)
|
|
{
|
|
@LISTHASH_PREFIX@_listptr_t n;
|
|
|
|
if (l == NULL)
|
|
return -1;
|
|
|
|
for (n = l->first; n != NULL; n = n->next)
|
|
{
|
|
if ((*plugin)(n->data, state) == -1)
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
** @LISTHASH_PREFIX@_list_empty() - empty the list
|
|
*/
|
|
void
|
|
@LISTHASH_PREFIX@_list_empty(@LISTHASH_PREFIX@_list_t *l, @LISTHASH_PREFIX@_freefunc_t freefunc)
|
|
{
|
|
@LISTHASH_PREFIX@_listptr_t n;
|
|
|
|
for (n = l->first; n != NULL; n = l->first)
|
|
{
|
|
l->first = n->next;
|
|
if (freefunc != NULL)
|
|
(*freefunc)(n->data);
|
|
free(n);
|
|
}
|
|
|
|
l->nents = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
** @LISTHASH_PREFIX@_list_free() - remove and free() the whole list
|
|
*/
|
|
void
|
|
@LISTHASH_PREFIX@_list_free(@LISTHASH_PREFIX@_list_t *l, @LISTHASH_PREFIX@_freefunc_t freefunc)
|
|
{
|
|
@LISTHASH_PREFIX@_list_empty(l, freefunc);
|
|
free(l);
|
|
}
|
|
|
|
|
|
/*
|
|
** @LISTHASH_PREFIX@_list_nents() - return number of elements in the list
|
|
*/
|
|
unsigned int
|
|
@LISTHASH_PREFIX@_list_nents(@LISTHASH_PREFIX@_list_t *l)
|
|
{
|
|
return l->nents;
|
|
}
|
|
|
|
|
|
/*
|
|
** @LISTHASH_PREFIX@_list_add() - adds an element to the list
|
|
** returns:
|
|
** 0 success
|
|
** -1 (and sets errno) failure
|
|
*/
|
|
int
|
|
@LISTHASH_PREFIX@_list_add(@LISTHASH_PREFIX@_list_t *l, void *data)
|
|
{
|
|
@LISTHASH_PREFIX@_listptr_t n, m;
|
|
|
|
#ifdef DS_DEBUG
|
|
printf("==> @LISTHASH_PREFIX@_list_add(\"%s\")\n", (char *)data);
|
|
#endif
|
|
|
|
n = (@LISTHASH_PREFIX@_listptr_t)malloc(sizeof(struct @LISTHASH_PREFIX@_node));
|
|
if (n == NULL)
|
|
return -1;
|
|
n->data = data;
|
|
l->nents++;
|
|
|
|
#ifdef DS_DEBUG
|
|
printf(" @LISTHASH_PREFIX@_list_add(): allocated data\n");
|
|
#endif
|
|
|
|
/* if the list is empty */
|
|
if (l->first == NULL)
|
|
{
|
|
l->last = l->first = n;
|
|
n->next = n->prev = NULL;
|
|
#ifdef DS_DEBUG
|
|
printf("<== @LISTHASH_PREFIX@_list_add(): list was empty; "
|
|
"added first element and returning 0\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
#ifdef DS_DEBUG
|
|
printf(" @LISTHASH_PREFIX@_list_add(): list not empty\n");
|
|
#endif
|
|
|
|
if (l->flags == LIST_STACK)
|
|
{
|
|
n->prev = NULL;
|
|
n->next = l->first;
|
|
if (l->first != NULL)
|
|
l->first->prev = n;
|
|
l->first = n;
|
|
#ifdef DS_DEBUG
|
|
printf("<== @LISTHASH_PREFIX@_list_add(): LIST_STACK set; "
|
|
"added in front\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
if (l->flags == LIST_QUEUE)
|
|
{
|
|
n->prev = l->last;
|
|
n->next = NULL;
|
|
if (l->last != NULL)
|
|
l->last->next = n;
|
|
l->last = n;
|
|
#ifdef DS_DEBUG
|
|
printf("<== @LISTHASH_PREFIX@_list_add(): LIST_QUEUE set; "
|
|
"added at end\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
for (m = l->first; m != NULL; m = m->next)
|
|
if ((*(l->cmpfunc))(data, m->data) < 0)
|
|
{
|
|
/*
|
|
** if we find one that's bigger,
|
|
** insert data before it
|
|
*/
|
|
#ifdef DS_DEBUG
|
|
printf(" @LISTHASH_PREFIX@_list_add(): gotcha..."
|
|
"inserting data\n");
|
|
#endif
|
|
if (m == l->first)
|
|
{
|
|
l->first = n;
|
|
n->prev = NULL;
|
|
m->prev = n;
|
|
n->next = m;
|
|
#ifdef DS_DEBUG
|
|
printf("<== @LISTHASH_PREFIX@_list_add(): "
|
|
"added first, returning 0\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
m->prev->next = n;
|
|
n->prev = m->prev;
|
|
m->prev = n;
|
|
n->next = m;
|
|
#ifdef DS_DEBUG
|
|
printf("<== @LISTHASH_PREFIX@_list_add(): added middle,"
|
|
" returning 0\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
#ifdef DS_DEBUG
|
|
printf(" @LISTHASH_PREFIX@_list_add(): new data larger than current "
|
|
"list elements\n");
|
|
#endif
|
|
|
|
/* if we get here, data is bigger than everything in the list */
|
|
l->last->next = n;
|
|
n->prev = l->last;
|
|
l->last = n;
|
|
n->next = NULL;
|
|
#ifdef DS_DEBUG
|
|
printf("<== @LISTHASH_PREFIX@_list_add(): added end, returning 0\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
** @LISTHASH_PREFIX@_list_del() - remove the element pointed to by n
|
|
** from the list l
|
|
*/
|
|
void
|
|
@LISTHASH_PREFIX@_list_del(@LISTHASH_PREFIX@_list_t *l, @LISTHASH_PREFIX@_listptr_t *n)
|
|
{
|
|
@LISTHASH_PREFIX@_listptr_t m;
|
|
|
|
#ifdef DS_DEBUG
|
|
printf("==> @LISTHASH_PREFIX@_list_del()\n");
|
|
#endif
|
|
|
|
l->nents--;
|
|
|
|
m = (*n)->next;
|
|
|
|
if ((*n)->prev)
|
|
(*n)->prev->next = (*n)->next;
|
|
else
|
|
l->first = (*n)->next;
|
|
if ((*n)->next)
|
|
(*n)->next->prev = (*n)->prev;
|
|
else
|
|
l->last = (*n)->prev;
|
|
|
|
free(*n);
|
|
*n = m;
|
|
}
|
|
|
|
|
|
/*
|
|
** @LISTHASH_PREFIX@_list_next() - get the next element in the list
|
|
** returns:
|
|
** 1 success
|
|
** 0 end of list
|
|
*/
|
|
int
|
|
@LISTHASH_PREFIX@_list_next(@LISTHASH_PREFIX@_list_t *l,
|
|
@LISTHASH_PREFIX@_listptr_t *n)
|
|
{
|
|
if (*n == NULL)
|
|
*n = l->first;
|
|
else
|
|
*n = (*n)->next;
|
|
|
|
return (*n != NULL ? 1 : 0);
|
|
}
|
|
|
|
|
|
/*
|
|
** @LISTHASH_PREFIX@_list_prev() - get the previous element in the list
|
|
** returns:
|
|
** 1 success
|
|
** 0 end of list
|
|
*/
|
|
int
|
|
@LISTHASH_PREFIX@_list_prev(@LISTHASH_PREFIX@_list_t *l,
|
|
@LISTHASH_PREFIX@_listptr_t *n)
|
|
{
|
|
if (*n == NULL)
|
|
*n = l->last;
|
|
else
|
|
*n = (*n)->prev;
|
|
|
|
return (*n != NULL ? 1 : 0);
|
|
}
|
|
|
|
|
|
/*
|
|
** @LISTHASH_PREFIX@_str_match() - string matching function
|
|
** returns:
|
|
** 1 match
|
|
** 0 no match
|
|
*/
|
|
int
|
|
@LISTHASH_PREFIX@_str_match(char *check, char *data)
|
|
{
|
|
return !strcmp(check, data);
|
|
}
|
|
|
|
|
|
/*
|
|
** @LISTHASH_PREFIX@_list_add_str() - splits string str into delim-delimited
|
|
** elements and adds them to list l
|
|
** returns:
|
|
** 0 success
|
|
** -1 (and sets errno) failure
|
|
*/
|
|
int
|
|
@LISTHASH_PREFIX@_list_add_str(@LISTHASH_PREFIX@_list_t *l,
|
|
char *str, char *delim)
|
|
{
|
|
char tmp[10240];
|
|
char *tokp, *nextp = tmp;
|
|
|
|
strlcpy(tmp, str, sizeof(tmp));
|
|
while ((tokp = strsep(&nextp, delim)) != NULL)
|
|
{
|
|
if (*tokp == '\0')
|
|
continue;
|
|
if (@LISTHASH_PREFIX@_list_add(l, strdup(tokp)))
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
** @LISTHASH_PREFIX@_list_search() - find an entry in a list
|
|
** returns:
|
|
** 1 match found
|
|
** 0 no match
|
|
*/
|
|
int
|
|
@LISTHASH_PREFIX@_list_search(@LISTHASH_PREFIX@_list_t *l,
|
|
@LISTHASH_PREFIX@_listptr_t *n, void *data,
|
|
@LISTHASH_PREFIX@_matchfunc_t matchfunc)
|
|
{
|
|
#ifdef DS_DEBUG
|
|
printf("==> @LISTHASH_PREFIX@_list_search(l=0x%lx, n=0x%lx, \"%s\")\n",
|
|
l, n, (char *)data);
|
|
#endif
|
|
|
|
if (matchfunc == NULL)
|
|
matchfunc = (@LISTHASH_PREFIX@_matchfunc_t)@LISTHASH_PREFIX@_str_match;
|
|
|
|
if (*n == NULL)
|
|
*n = l->first;
|
|
else
|
|
*n = (*n)->next;
|
|
|
|
for (; *n != NULL; *n = (*n)->next)
|
|
{
|
|
#ifdef DS_DEBUG
|
|
printf("checking against \"%s\"\n", (char *)(*n)->data);
|
|
#endif
|
|
if ((*(matchfunc))(data, (*n)->data) != 0)
|
|
return 1;
|
|
}
|
|
|
|
#ifdef DS_DEBUG
|
|
printf("no matches found\n");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
** @LISTHASH_PREFIX@_list_dup() - copy an existing list
|
|
*/
|
|
/*
|
|
static @LISTHASH_PREFIX@_list_t *
|
|
@LISTHASH_PREFIX@_list_dup(@LISTHASH_PREFIX@_list_t *l)
|
|
{
|
|
@LISTHASH_PREFIX@_list_t *newlist;
|
|
@LISTHASH_PREFIX@_listptr_t n;
|
|
|
|
newlist = @LISTHASH_PREFIX@_list_new(l->flags, l->cmpfunc);
|
|
for (n = l->first; n != NULL; n = n->next)
|
|
@LISTHASH_PREFIX@_list_add(newlist, n->data);
|
|
|
|
#ifdef DS_DEBUG
|
|
printf("returning from @LISTHASH_PREFIX@_list_dup()\n");
|
|
#endif
|
|
return newlist;
|
|
}
|
|
*/
|
|
|
|
|
|
/*
|
|
** @LISTHASH_PREFIX@_list_merge() - merge two lists into a new list
|
|
*/
|
|
/*
|
|
static @LISTHASH_PREFIX@_list_t *
|
|
@LISTHASH_PREFIX@_list_merge(@LISTHASH_PREFIX@_cmpfunc_t cmpfunc, int flags,
|
|
@LISTHASH_PREFIX@_list_t *list1,
|
|
@LISTHASH_PREFIX@_list_t *list2)
|
|
{
|
|
@LISTHASH_PREFIX@_list_t *newlist;
|
|
@LISTHASH_PREFIX@_listptr_t n;
|
|
|
|
newlist = @LISTHASH_PREFIX@_list_new(flags, cmpfunc);
|
|
|
|
n = NULL;
|
|
while (@LISTHASH_PREFIX@_list_next(list1, &n) != 0)
|
|
@LISTHASH_PREFIX@_list_add(newlist, n->data);
|
|
n = NULL;
|
|
while (@LISTHASH_PREFIX@_list_next(list2, &n) != 0)
|
|
@LISTHASH_PREFIX@_list_add(newlist, n->data);
|
|
|
|
return newlist;
|
|
}
|
|
*/
|
|
|
|
|