avrdude/lists.c

1409 lines
29 KiB
C
Raw Normal View History

/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 1990-2004 Brian S. Dean <bsd@bsdhome.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* $Id$ */
/*----------------------------------------------------------------------
Id: lists.c,v 1.4 2001/08/19 23:26:20 bsd Exp $
----------------------------------------------------------------------*/
/*------------------------------------------------------------------------
lists.c
General purpose linked list routines. These routines implement a
generic doubly linked list. Any data type may be placed in the
lists. Stacking and Queuing routines are provided via #defines
declared in 'lists.h'.
Author : Brian Dean
Date : 10 January, 1990
------------------------------------------------------------------------*/
#include "ac_cfg.h"
#include <stdio.h>
#include <stdlib.h>
2020-01-18 17:05:50 +00:00
#include "avrdude.h"
#include "libavrdude.h"
#define MAGIC 0xb05b05b0
#define CHECK_MAGIC 0 /* set to 1 to enable memory overwrite detection */
#ifdef BOS
#define MALLOC(size,x) kmalloc(size,x)
#define FREE kfree
#else
#define MALLOC(size,x) malloc(size)
#define FREE free
#endif
/*------------------------------------------------------------
| required private data structures
------------------------------------------------------------*/
typedef struct LISTNODE {
#if CHECK_MAGIC
unsigned int magic1;
#endif
struct LISTNODE * next; /* chain to next item in the list */
struct LISTNODE * prev; /* chain to previous item in the list */
void * data; /* pointer to user data */
#if CHECK_MAGIC
unsigned int magic2;
#endif
} LISTNODE;
typedef struct NODEPOOL {
#if CHECK_MAGIC
unsigned int magic1;
#endif
struct NODEPOOL * chain_next; /* chain to next node pool */
struct NODEPOOL * chain_prev; /* chain to previous node pool */
#if CHECK_MAGIC
unsigned int magic2;
#endif
} NODEPOOL;
typedef struct LIST {
#if CHECK_MAGIC
unsigned int magic1;
#endif
int num; /* number of elements in the list */
short int free_on_close; /* free the LIST memory on close T/F */
short int poolsize; /* list node allocation size */
int n_ln_pool; /* number of listnodes in a pool */
LISTNODE * top; /* top of the list */
LISTNODE * bottom; /* bottom of the list */
LISTNODE * next_ln; /* next available list node */
NODEPOOL * np_top; /* top of the node pool chain */
NODEPOOL * np_bottom; /* bottom of the node pool chain */
#if CHECK_MAGIC
unsigned int magic2;
#endif
} LIST;
/* allocate list nodes in 512 byte chunks, giving 42 elements */
#define DEFAULT_POOLSIZE 512
#if CHECK_MAGIC
#define CKMAGIC(p) { if (p->magic1 != MAGIC) breakpoint(); \
if (p->magic2 != MAGIC) breakpoint(); }
#define CKNPMAGIC(p) cknpmagic(p)
#define CKLNMAGIC(p) cklnmagic(p)
#define CKLMAGIC(p) cklmagic(p)
#else
#define CKMAGIC(p)
#define CKNPMAGIC(p)
#define CKLNMAGIC(p)
#define CKLMAGIC(p)
#endif
static int insert_ln ( LIST * l, LISTNODE * ln, void * data_ptr );
#if CHECK_MAGIC
static int cknpmagic ( LIST * l )
{
NODEPOOL * np;
int i;
i = 0;
np = l->np_top;
while (np) {
i++;
CKMAGIC(np);
np = np->chain_next;
}
i = 0;
np = l->np_bottom;
while (np) {
i++;
CKMAGIC(np);
np = np->chain_prev;
}
return 0;
}
static int cklnmagic ( LIST * l )
{
LISTNODE * ln;
int i;
i = 0;
ln = l->top;
while (ln) {
i++;
CKMAGIC(ln);
ln = ln->next;
}
i = 0;
ln = l->bottom;
while (ln) {
i++;
CKMAGIC(ln);
ln = ln->prev;
}
return 0;
}
static int cklmagic ( LIST * l )
{
CKMAGIC(l);
CKNPMAGIC(l);
CKLNMAGIC(l);
CKMAGIC(l);
return 0;
}
#endif
/*------------------------------------------------------------
| new_node_pool
|
| Create and initialize a new pool of list nodes. This is
| just a big block of memory with the first sizeof(NODEPOOL)
| bytes reserved. The first available list node resides at
| offset sizeof(NODEPOOL).
------------------------------------------------------------*/
static
NODEPOOL *
new_nodepool ( LIST * l )
{
NODEPOOL * np;
LISTNODE * ln;
int i;
CKLMAGIC(l);
/*--------------------------------------------------
| get a block of memory for the new pool
--------------------------------------------------*/
np = (NODEPOOL *) MALLOC ( l->poolsize, "list node pool" );
if (np == NULL) {
return NULL;
}
/*--------------------------------------------------
| initialize the chaining information at the
| beginning of the pool.
--------------------------------------------------*/
#if CHECK_MAGIC
np->magic1 = MAGIC;
#endif
np->chain_next = NULL;
np->chain_prev = NULL;
#if CHECK_MAGIC
np->magic2 = MAGIC;
#endif
/*--------------------------------------------------
| initialize all the list nodes within the node
| pool, which begin just after the NODEPOOL
| structure at the beginning of the memory block
--------------------------------------------------*/
ln = (LISTNODE *) (&np[1]);
#if CHECK_MAGIC
ln[0].magic1 = MAGIC;
#endif
ln[0].data = NULL;
ln[0].next = &ln[1];
ln[0].prev = NULL;
#if CHECK_MAGIC
ln[0].magic2 = MAGIC;
#endif
for (i=1; i<l->n_ln_pool-1; i++) {
#if CHECK_MAGIC
ln[i].magic1 = MAGIC;
#endif
ln[i].data = NULL;
ln[i].next = &ln[i+1];
ln[i].prev = &ln[i-1];
#if CHECK_MAGIC
ln[i].magic2 = MAGIC;
#endif
}
#if CHECK_MAGIC
ln[l->n_ln_pool-1].magic1 = MAGIC;
#endif
ln[l->n_ln_pool-1].data = NULL;
ln[l->n_ln_pool-1].next = NULL;
ln[l->n_ln_pool-1].prev = &ln[l->n_ln_pool-2];
#if CHECK_MAGIC
ln[l->n_ln_pool-1].magic2 = MAGIC;
#endif
CKMAGIC(np);
CKLMAGIC(l);
return np;
}
/*------------------------------------------------------------
| get_listnode
|
| Get the next available list node. If there are no more
| list nodes, another pool of list nodes is allocated. If
| that fails, NULL is returned.
------------------------------------------------------------*/
static
LISTNODE *
get_listnode ( LIST * l )
{
LISTNODE * ln;
NODEPOOL * np;
CKLMAGIC(l);
if (l->next_ln == NULL) {
/*--------------------------------------------------
| allocate a new node pool and chain to the others
--------------------------------------------------*/
np = new_nodepool(l);
if (np == NULL) {
CKLMAGIC(l);
return NULL;
}
if (l->np_top == NULL) {
/*--------------------------------------------------
| this is the first node pool for this list,
| directly assign to the top and bottom.
--------------------------------------------------*/
l->np_top = np;
l->np_bottom = np;
np->chain_next = NULL;
np->chain_prev = NULL;
}
else {
/*--------------------------------------------------
| this is an additional node pool, add it to the
| chain.
--------------------------------------------------*/
np->chain_next = NULL;
np->chain_prev = l->np_bottom;
l->np_bottom->chain_next = np;
l->np_bottom = np;
}
/*--------------------------------------------------
| set the list's pointer to the next available
| list node to the first list node in this new
| pool.
--------------------------------------------------*/
l->next_ln = (LISTNODE *)&np[1];
CKMAGIC(np);
}
/*--------------------------------------------------
| get the next available list node, set the list's
| next available list node to the next one in the
| list.
--------------------------------------------------*/
ln = l->next_ln;
l->next_ln = ln->next;
CKMAGIC(ln);
/*--------------------------------------------------
| initialize the new list node and return
--------------------------------------------------*/
ln->next = NULL;
ln->prev = NULL;
ln->data = NULL;
CKLMAGIC(l);
return ln;
}
/*------------------------------------------------------------
| free_listnode
|
| Return a list node to the pool of list nodes. This puts
| the node at the head of the free list, so that the next
| call to 'get_listnode', with return the most recently
| freed one.
------------------------------------------------------------*/
static
int
free_listnode ( LIST * l, LISTNODE * ln )
{
CKLMAGIC(l);
/*--------------------------------------------------
| insert the list node at the head of the list of
| free list nodes.
--------------------------------------------------*/
ln->prev = NULL;
ln->data = NULL;
ln->next = l->next_ln;
l->next_ln = ln;
CKLMAGIC(l);
return 0;
}
/*----------------------------------------------------------------------
lcreat
Create a new list data structure.
If liststruct is not NULL, it is used to provide the memory space
for the list structure instance, otherwise, the necessary memory is
malloc'd.
If elements is zero, the default poolsize is used, otherwise,
poolsizes of 'elements' elements are malloc'd to obtain the memory
for list nodes. Minimum element count is 5.
The first node pool is not preallocated; instead it is malloc'd at
the time of the first use.
----------------------------------------------------------------------*/
LISTID
lcreat ( void * liststruct, int elements )
{
LIST * l;
if (liststruct == NULL) {
/*--------------------------------------------------
allocate memory for the list itself
--------------------------------------------------*/
l = (LIST *) MALLOC ( sizeof(LIST), "list struct" );
if (l == NULL) {
return NULL;
}
l->free_on_close = 1;
}
else {
/*-----------------------------------------------------------------
use the memory given to us for the list structure
-----------------------------------------------------------------*/
l = liststruct;
l->free_on_close = 0;
}
/*--------------------------------------------------
| initialize the list
--------------------------------------------------*/
#if CHECK_MAGIC
l->magic1 = MAGIC;
l->magic2 = MAGIC;
#endif
l->top = NULL;
l->bottom = NULL;
l->num = 0;
if (elements == 0) {
l->poolsize = DEFAULT_POOLSIZE;
}
else {
l->poolsize = elements*sizeof(LISTNODE)+sizeof(NODEPOOL);
}
l->n_ln_pool = (l->poolsize-sizeof(NODEPOOL))/sizeof(LISTNODE);
if (l->n_ln_pool < 5) {
if (!liststruct) {
FREE(l);
}
return NULL;
}
l->np_top = NULL;
l->np_bottom = NULL;
l->next_ln = NULL;
CKLMAGIC(l);
return (LISTID)l;
}
/*--------------------------------------------------
| ldestroy_cb
|
| destroy an existing list data structure, calling
| the user routine 'ucleanup' on the data pointer
| of each list element. Allows the user to free
| up a list data structure and have this routine
| call their function to free up each list element
| at the same time.
--------------------------------------------------*/
void
ldestroy_cb ( LISTID lid, void (*ucleanup)(void * data_ptr) )
{
LIST * l;
LISTNODE * ln;
l = (LIST *)lid;
CKLMAGIC(l);
ln = l->top;
while (ln != NULL) {
ucleanup ( ln->data );
ln = ln->next;
}
ldestroy ( l );
}
/*--------------------------------------------------
| ldestroy
|
| destroy an existing list data structure.
|
| assumes that each data element does not need to
| be freed.
--------------------------------------------------*/
void
ldestroy ( LISTID lid )
{
LIST * l;
NODEPOOL * p1, * p2;
l = (LIST *)lid;
CKLMAGIC(l);
/*--------------------------------------------------
| free each node pool - start at the first node
| pool and free each successive until there are
| no more.
--------------------------------------------------*/
p1 = l->np_top;
while (p1 != NULL) {
p2 = p1->chain_next;
FREE(p1);
p1 = p2;
}
/*--------------------------------------------------
| now free the memory occupied by the list itself
--------------------------------------------------*/
if (l->free_on_close) {
FREE ( l );
}
}
/*------------------------------------------------------------
| ladd
|
| add list - add item p to the list
------------------------------------------------------------*/
int
ladd ( LISTID lid, void * p )
{
LIST * l;
LISTNODE *lnptr;
l = (LIST *)lid;
CKLMAGIC(l);
lnptr = get_listnode(l);
if (lnptr==NULL) {
#ifdef BOS
breakpoint();
#endif
return -1;
}
CKMAGIC(lnptr);
lnptr->data = p;
if (l->top == NULL) {
l->top = lnptr;
l->bottom = lnptr;
lnptr->next = NULL;
lnptr->prev = NULL;
}
else {
lnptr->prev = l->bottom;
lnptr->next = NULL;
l->bottom->next = lnptr;
l->bottom = lnptr;
}
l->num++;
CKLMAGIC(l);
return 0;
}
/*------------------------------------------------------------
| laddo
|
| add list, ordered - add item p to the list, use 'compare'
| function to place 'p' when the comparison 'p' is less than
| the next item. Return 0 if this was a unique entry,
| else return 1 indicating a duplicate entry, i.e., the
| compare function returned 0 while inserting the element.
------------------------------------------------------------*/
int
laddo ( LISTID lid, void * p, int (*compare)(const void *p1,const void *p2),
LNODEID * firstdup )
{
LIST * l;
LISTNODE * ln;
int dup, cmp;
l = (LIST *)lid;
CKLMAGIC(l);
dup = 0;
ln = l->top;
while (ln!=NULL) {
CKMAGIC(ln);
cmp = compare(p,ln->data);
if (cmp == 0) {
dup = 1;
if (firstdup)
*firstdup = ln;
}
if (cmp < 0) {
insert_ln(l,ln,p);
CKLMAGIC(l);
return dup;
}
else {
ln = ln->next;
}
}
ladd(l,p);
CKLMAGIC(l);
return dup;
}
/*---------------------------------------------------------------------------
| laddu
|
| add list, ordered, unique - add item p to the list, use 'compare'
| function to place 'p' when the comparison 'p' is less than the next
| item. Return 1 if the item was added, 0 if not.
|
--------------------------------------------------------------------------*/
int
laddu ( LISTID lid, void * p, int (*compare)(const void *p1,const void *p2) )
{
LIST * l;
LISTNODE * ln;
int cmp;
l = (LIST *)lid;
CKLMAGIC(l);
ln = l->top;
while (ln!=NULL) {
CKMAGIC(ln);
cmp = compare(p,ln->data);
if (cmp == 0) {
CKLMAGIC(l);
return 0;
}
if (cmp < 0) {
insert_ln(l,ln,p);
CKLMAGIC(l);
return 1;
}
else {
ln = ln->next;
}
}
ladd(l,p);
CKLMAGIC(l);
return 1;
}
LNODEID
lfirst ( LISTID lid )
{
CKLMAGIC(((LIST *)lid));
return ((LIST *)lid)->top;
}
LNODEID
llast ( LISTID lid )
{
CKLMAGIC(((LIST *)lid));
return ((LIST *)lid)->bottom;
}
LNODEID
lnext ( LNODEID lnid )
{
CKMAGIC(((LISTNODE *)lnid));
return ((LISTNODE *)lnid)->next;
}
LNODEID
lprev ( LNODEID lnid )
{
CKMAGIC(((LISTNODE *)lnid));
return ((LISTNODE *)lnid)->prev;
}
void *
ldata ( LNODEID lnid )
{
CKMAGIC(((LISTNODE *)lnid));
return ((LISTNODE *)lnid)->data;
}
int
lsize ( LISTID lid )
{
CKLMAGIC(((LIST *)lid));
return ((LIST *)lid)->num;
}
/*------------------------------------------------------------
| lcat
|
| catenate - catenate l2 to l1, return pointer to l1.
------------------------------------------------------------*/
LISTID
lcat ( LISTID lid1, LISTID lid2 )
{
CKLMAGIC(((LIST *)lid1));
CKLMAGIC(((LIST *)lid2));
while (lsize(lid2)) {
ladd ( lid1, lrmv_n(lid2,1) );
}
CKLMAGIC(((LIST *)lid1));
CKLMAGIC(((LIST *)lid2));
return lid1;
}
/*----------------------------------------------------------------------
| lget
|
| get from list, last item - return pointer to the data of the last
| item in the list, non-destructive
----------------------------------------------------------------------*/
void *
lget ( LISTID lid )
{
LIST * l;
LISTNODE * p;
l = (LIST *)lid;
CKLMAGIC(l);
p = l->bottom;
if (p == NULL) {
CKLMAGIC(l);
return NULL;
}
else {
CKLMAGIC(l);
return p->data;
}
}
/*---------------------------------------------------------------
| lget_n
|
| get from list, index - return the nth list item,
| non-destructive
---------------------------------------------------------------*/
void *
lget_n ( LISTID lid, unsigned int n )
{
int i;
LIST * l;
LISTNODE * ln;
l = (LIST *)lid;
CKLMAGIC(l);
if ((n<1)||(n>lsize(l))) {
return NULL;
}
ln = l->top;
i = 1;
while (ln && (i!=n)) {
CKMAGIC(ln);
ln = ln->next;
i++;
}
if (ln) {
CKLMAGIC(l);
return ln->data;
}
else {
CKLMAGIC(l);
return NULL;
}
}
/*---------------------------------------------------------------
| lget_ln
|
| get from list, listnode - return the nth list item, the
| listnode is returned instead of the data, non-destructive
---------------------------------------------------------------*/
LNODEID
lget_ln ( LISTID lid, unsigned int n )
{
int i;
LIST * l;
LISTNODE * ln;
l = (LIST *)lid;
CKLMAGIC(l);
if ((n<1)||(n>lsize(l))) {
return NULL;
}
ln = l->top;
i = 1;
while (i!=n) {
CKMAGIC(ln);
ln = ln->next;
i++;
}
CKLMAGIC(l);
return (LNODEID)ln;
}
/*----------------------------------------------------------------------
| insert_ln
|
| insert data, listnode - insert data just before the list item
| pointed to by 'ln'.
|
| This routine is not intended to be called directly by the user
| because the validity of ln is not checked. This routine is called
| by list manipulation routines within this module, in which ln is
| known to point to a valid list node.
----------------------------------------------------------------------*/
static
int
insert_ln ( LIST * l, LISTNODE * ln, void * data_ptr )
{
LISTNODE * lnptr;
CKLMAGIC(l);
if (ln==NULL) {
ladd ( l, data_ptr );
CKLMAGIC(l);
return 0;
}
lnptr = get_listnode(l);
if (lnptr == NULL) {
#ifdef BOS
breakpoint();
#endif
return -1;
}
CKMAGIC(lnptr);
lnptr->data = data_ptr;
if (ln==l->top) {
/*------------------------------
| insert before the list head
------------------------------*/
lnptr->next = ln;
lnptr->prev = NULL;
ln->prev = lnptr;
l->top = lnptr;
}
else if (ln==NULL) {
/*-----------------
| list was empty
-----------------*/
lnptr->next = NULL;
lnptr->prev = l->bottom;
l->bottom->next = lnptr;
l->bottom = lnptr;
}
else {
/*-----------------------------------
| insert in the middle of the list
-----------------------------------*/
lnptr->next = ln;
lnptr->prev = ln->prev;
lnptr->next->prev = lnptr;
lnptr->prev->next = lnptr;
}
l->num++;
CKLMAGIC(l);
return 0;
}
/*-----------------------------------------------------------------
| lins_n
|
| Insert data before the nth item in the list.
-----------------------------------------------------------------*/
int
lins_n ( LISTID lid, void * data_ptr, unsigned int n )
{
int i;
LIST * l;
LISTNODE * ln;
l = (LIST *)lid;
CKLMAGIC(l);
if ((n<1)||(n>(l->num+1))) {
return -1;
}
if (l->num == 0) {
return ladd ( lid, data_ptr );
}
/*----------------------------------
| locate the nth item in the list
----------------------------------*/
ln = l->top;
i = 1;
while (ln && (i!=n)) {
CKMAGIC(ln);
ln = ln->next;
i++;
}
if (!ln) {
CKLMAGIC(l);
return -1;
}
CKLMAGIC(l);
/*-----------------------------------------
| insert before the nth item in the list
-----------------------------------------*/
return insert_ln ( l, ln, data_ptr );
}
/*-----------------------------------------------------------------
| lins_ln
|
| Insert data before the list node pointed to by ln.
-----------------------------------------------------------------*/
int
lins_ln ( LISTID lid, LNODEID lnid, void * data_ptr )
{
LIST * l;
LISTNODE * ln;
LISTNODE * ln_ptr;
l = (LIST *)lid;
ln = (LISTNODE *)lnid;
CKLMAGIC(l);
CKMAGIC(ln);
/*-----------------------------------------
| validate that ln is indeed in the list
-----------------------------------------*/
ln_ptr = l->top;
while ((ln_ptr!=NULL)&&(ln_ptr!=ln)) {
CKMAGIC(ln_ptr);
ln_ptr = ln_ptr->next;
}
if (ln_ptr == NULL) {
CKLMAGIC(l);
return -1;
}
CKLMAGIC(l);
/*--------------------------------
| insert the data into the list
--------------------------------*/
return insert_ln ( l, ln, data_ptr );
}
/*----------------------------------------------------------------------
| remove_ln
|
| Remove the item in the list pointed to by ln. This routine is not
| intended to be called directly by the user because the validity
| of ln is not checked. This routine is called by list manipulation
| routines within this module, in which ln is known to point to a
| valid list node.
----------------------------------------------------------------------*/
static
void *
remove_ln ( LIST * l, LISTNODE * ln )
{
void * r;
CKLMAGIC(l);
CKMAGIC(ln);
if (ln==l->top) {
/*------------------------------
| remove the head of the list
------------------------------*/
l->top = ln->next;
if (l->top != NULL) {
l->top->prev = NULL;
}
else {
/*----------------------------------------
| this was the only item in the list
----------------------------------------*/
l->bottom = NULL;
}
}
else if (ln==l->bottom) {
/*------------------------------
| remove the tail of the list
------------------------------*/
l->bottom = ln->prev;
if (l->bottom != NULL) {
l->bottom->next = NULL;
}
}
else {
/*-------------------------------------
| remove from the middle of the list
-------------------------------------*/
ln->prev->next = ln->next;
ln->next->prev = ln->prev;
}
/*-----------------------------
| prepare to return the data
-----------------------------*/
r = ln->data;
/*-----------------------------------------------
| free the listnode for re-use
-----------------------------------------------*/
free_listnode(l,ln);
/*------------------------------------
| adjust the item count of the list
------------------------------------*/
l->num--;
CKLMAGIC(l);
return r;
}
/*-------------------------------------------------------------------------
| lrmv_d
|
| remove from list, data - removes the data element from the list,
| destructive
-------------------------------------------------------------------------*/
void *
lrmv_d ( LISTID lid, void * data_ptr )
{
LIST * l;
LISTNODE * ln;
int i;
l = (LIST *)lid;
CKLMAGIC(l);
i = 0;
ln = l->top;
while (ln && (ln->data != data_ptr)) {
i++;
CKMAGIC(ln);
ln = ln->next;
}
if (ln == NULL) {
CKLMAGIC(l);
return NULL;
}
else {
CKLMAGIC(l);
return remove_ln ( l, ln );
}
}
/*-------------------------------------------------------------------------
| lrmv_ln
|
| remove from list, by list node - remove the data element pointed to
| by 'ln' from the list, destructive
-------------------------------------------------------------------------*/
void *
lrmv_ln ( LISTID lid, LNODEID lnid )
{
LIST * l;
LISTNODE * ln;
LISTNODE * p;
l = (LIST *)lid;
ln = (LISTNODE *)lnid;
CKLMAGIC(l);
CKMAGIC(ln);
p = l->top;
while ((p!=NULL)&&(p!=ln)) {
CKMAGIC(p);
p = p->next;
}
if (p==NULL) {
CKLMAGIC(l);
return NULL;
}
else {
CKLMAGIC(l);
return remove_ln ( l, p );
}
}
/*----------------------------------------------------------------------
| lrmv_n
|
| remove from list, by item number - remove the nth element from
| the list.
----------------------------------------------------------------------*/
void *
lrmv_n ( LISTID lid, unsigned int n )
{
int i;
LIST * l;
LISTNODE * ln;
l = (LIST *)lid;
CKLMAGIC(l);
if ((n<1)||(n>l->num)) {
return NULL;
}
ln = l->top;
i = 1;
while (ln && (i!=n)) {
CKMAGIC(ln);
ln = ln->next;
i++;
}
if (ln) {
CKLMAGIC(l);
return remove_ln ( l, ln );
}
else {
CKLMAGIC(l);
return NULL;
}
}
/*----------------------------------------------------------------------
| lrmv
|
| remove from list, last item - remove the last item from the list,
| destructive
----------------------------------------------------------------------*/
void *
lrmv ( LISTID lid )
{
LIST * l;
LISTNODE * p;
l = (LIST *)lid;
CKLMAGIC(l);
p = l->bottom;
if (p == NULL) {
CKLMAGIC(l);
return NULL;
}
else {
CKLMAGIC(l);
return remove_ln ( l, p );
}
}
/*----------------------------------------------------------------------
| lsrch
|
| search list - return data element pointed to by 'p', NULL if not
| found
----------------------------------------------------------------------*/
void *
lsrch ( LISTID lid, void * p, int (* compare)(void * p1, void * p2) )
{
LIST * l;
LISTNODE * ln;
l = (LIST *)lid;
CKLMAGIC(l);
ln = l->top;
while (ln!=NULL) {
CKMAGIC(ln);
if (compare(p,ln->data) == 0) {
CKLMAGIC(l);
return ln->data;
}
else {
ln = ln->next;
}
}
CKLMAGIC(l);
return NULL;
}
/*----------------------------------------------------------------------
| lsort
|
| sort list - sorts list inplace (using bubble sort)
|
----------------------------------------------------------------------*/
void
lsort ( LISTID lid, int (* compare)(void * p1, void * p2) )
{
LIST * l;
LISTNODE * lt; /* this */
LISTNODE * ln; /* next */
int unsorted = 1;
l = (LIST *)lid;
CKLMAGIC(l);
while(unsorted){
lt = l->top;
unsorted = 0;
while (lt!=NULL) {
CKMAGIC(lt);
ln = lt->next;
if (ln!= NULL && compare(lt->data,ln->data) > 0) {
void * p = ln->data;
ln->data = lt->data;
lt->data = p;
unsorted = 1;
}
lt = ln;
}
}
CKLMAGIC(l);
}
int lprint ( FILE * f, LISTID lid )
{
LIST * l;
LISTNODE * ln;
NODEPOOL * np;
int count;
l = (LIST *)lid;
fprintf ( f, "list id %p internal data structures:\n",
lid );
#if CHECK_MAGIC
if ((l->magic1 != MAGIC) || (l->magic2 != MAGIC)) {
fprintf ( f, " *** WARNING: LIST MAGIC IS CORRUPT ***\n" );
}
fprintf ( f,
" magic1=0x%08x\n"
" magic2=0x%08x\n",
l->magic1, l->magic2 );
#endif
fprintf ( f, " num f pool n_ln top bottom next_ln np_top np_bottom\n" );
fprintf ( f, " ---- - ---- ---- ---------- ---------- ---------- ---------- ----------\n" );
fprintf ( f, " %4d %1d %4d %4d %10p %10p %10p %10p %10p\n",
l->num, l->free_on_close, l->poolsize, l->n_ln_pool,
l->top, l->bottom,
l->next_ln, l->np_top, l->np_bottom );
fprintf ( f,
" node pools:\n"
" idx np magic1 next prev magic2\n"
" ---- ---------- ---------- ---------- ---------- ----------\n" );
count = 0;
np = l->np_top;
while (np != NULL) {
count++;
fprintf ( f, " %4d %10p 0x%08x %10p %10p 0x%08x\n",
count, np,
#if CHECK_MAGIC
np->magic1,
#else
0,
#endif
np->chain_next, np->chain_prev,
#if CHECK_MAGIC
np->magic2
#else
0
#endif
);
np = np->chain_next;
}
if (f) {
fprintf ( f,
" list elements:\n"
" n ln magic1 next prev data magic2\n"
" ---- ---------- ---------- ---------- ---------- ---------- ----------\n" );
count = 0;
ln = l->top;
while (ln != NULL) {
count++;
fprintf ( f, " %4d %10p %10x %10p %10p %10p %10x\n",
count, ln,
#if CHECK_MAGIC
ln->magic1,
#else
0,
#endif
ln->next, ln->prev, ln->data,
#if CHECK_MAGIC
ln->magic2
#else
0
#endif
);
ln = lnext(ln);
}
if (count != l->num) {
fprintf ( f,
" *** list count is not correct\n"
" *** list id indicates %d, counted items = %d\n",
l->num, count );
}
}
return 0;
}