1408 lines
29 KiB
C
1408 lines
29 KiB
C
/*
|
|
* 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>
|
|
|
|
#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;
|
|
}
|