- New chopper driver for MARS Juelich chopper system - New docbook based SANS manual SKIPPED: psi/amorcomp.c psi/amordrive.h psi/amorset.c psi/amorset.h psi/amorset.tex psi/amorset.w psi/julcho.c psi/libpsi.a psi/make_gen psi/psi.c
701 lines
20 KiB
C
701 lines
20 KiB
C
/* =======================================================================
|
|
LLD.c Generic Doubly Linked Lists for fixed size data.
|
|
Each List has its own specific data size.
|
|
This version uses dummy head and dummy tail nodes.
|
|
Which prevents special handling for the first and last
|
|
nodes.
|
|
|
|
v1.00 94-08-21
|
|
|
|
Compile with NDEBUG not defined for debugging version.
|
|
Compile with NDEBUG defined for production version.
|
|
|
|
The node pointers are restricted to valid values.
|
|
They point only in empty lists to invalid data.
|
|
|
|
Possible future enhancements:
|
|
- List(s) of free nodes for fast node memory alloc.
|
|
- FindFirst() & FindNext().
|
|
- Data access via first and/or last node pointers.
|
|
(duplicate the functions and change .current to
|
|
.first or .last)
|
|
- Node deletion via first and/or last node pointers.
|
|
(as for access functions, then simplify ...)
|
|
|
|
_____ This version is Public Domain.
|
|
/_|__| A.Reitsma, Delft, The Netherlands.
|
|
/ | \ --------------------------------------------------------------- */
|
|
|
|
#include <stdarg.h> /* variable arg handling */
|
|
#include <assert.h> /* debugging */
|
|
#include "defines.h" /* debugging incl MALLOC (re-) definition */
|
|
#include "lld.h" /* also includes portable.h if necessary */
|
|
|
|
#define NO_PROBLEMS LIST_NO_PROBLEMS /* local redefinition */
|
|
|
|
struct Node
|
|
{
|
|
struct Node * next;
|
|
struct Node * prev;
|
|
int data; /* also place-holder for larger items. */
|
|
}; /* actual nodes have various sizes, */
|
|
/* but a fixed size within a list. */
|
|
struct ListHead
|
|
{
|
|
struct Node * current; /* points to the actual current node */
|
|
struct Node * first; /* always points to dummy head node */
|
|
struct Node * last; /* always points to dummy tail node */
|
|
int itemsize ; /* zero value: used as 'list not used' flag */
|
|
};
|
|
|
|
#define ERR_MEMORY -1
|
|
|
|
#define NODE_MALLOC(list) (struct Node *) \
|
|
MALLOC( ListControl[ list ].itemsize \
|
|
+ 2 * sizeof( struct Node * )\
|
|
+ sizeof(int), char )
|
|
|
|
#define NODE_FREE(node) FREE(node)
|
|
|
|
/* ---- Local data ---------------------------------------------------- */
|
|
|
|
static struct ListHead * ListControl = NULL;
|
|
static unsigned int ListCount = 0;
|
|
|
|
/* ---- LL system mangement ------------------------------------------- */
|
|
|
|
static int ListInit( int List, int ItemSize )
|
|
{
|
|
struct Node * Tmp ;
|
|
|
|
if( 0 != ItemSize )
|
|
{
|
|
/* create dummy head node
|
|
*/
|
|
Fortify_CheckAllMemory();
|
|
Tmp = NODE_MALLOC( List );
|
|
if( NULL == Tmp )
|
|
{
|
|
return ERR_MEMORY ;
|
|
}
|
|
Tmp->prev = NULL ; /* NULL identifies it as dummy head node */
|
|
Tmp->data = 0xA709 ; /* dummy value */
|
|
ListControl[ List ].first = Tmp ;
|
|
|
|
/* create dummy tail node
|
|
*/
|
|
Tmp = NODE_MALLOC( List );
|
|
if( NULL == Tmp )
|
|
{
|
|
NODE_FREE( Tmp ); /* no need to cause memory leaks */
|
|
ListControl[ List ].first = NULL ; /* or other errors */
|
|
return ERR_MEMORY ; /* even if we're in trouble ... */
|
|
}
|
|
Tmp->next = NULL ; /* NULL identifies it as dummy tail node */
|
|
Tmp->data = 0xA725 ; /* dummy value */
|
|
Tmp->prev = ListControl[ List ].first ;
|
|
|
|
ListControl[ List ].current =
|
|
ListControl[ List ].last =
|
|
ListControl[ List ].first->next = Tmp ;
|
|
}
|
|
else
|
|
{
|
|
ListControl[ List ].current =
|
|
ListControl[ List ].first =
|
|
ListControl[ List ].last = NULL ;
|
|
}
|
|
|
|
ListControl[ List ].itemsize = ItemSize ; /* zero: list not used */
|
|
return NO_PROBLEMS ;
|
|
}
|
|
|
|
int LLDsystemInit( int ListCountInit )
|
|
{
|
|
assert( (unsigned) ( ListCountInit -1 ) <= 20 -1 );
|
|
/* negative is logic error (cast => neg. is large int) */
|
|
/* higher than 20 is ridiculous for an initial setup */
|
|
/* zero is useless */
|
|
|
|
if( NULL != ListControl )
|
|
{
|
|
return NO_PROBLEMS ; /* LL system already initialized */
|
|
}
|
|
|
|
ListControl = MALLOC( ListCountInit, struct ListHead );
|
|
if( NULL == ListControl )
|
|
{
|
|
return ERR_MEMORY ;
|
|
}
|
|
/* MK */
|
|
memset(ListControl,0,ListCountInit*sizeof(struct ListHead));
|
|
|
|
for( ListCount = 0 ; ListCount < (unsigned)ListCountInit ; ListCount++ )
|
|
ListInit( ListCount, 0 ); /* just mark it as usable ... */
|
|
|
|
/* ListCount is now ListCountInit */
|
|
assert( ListCount == (unsigned)ListCountInit );
|
|
|
|
return NO_PROBLEMS;
|
|
}
|
|
|
|
int LLDsystemClose(void)
|
|
{
|
|
if(ListControl)
|
|
{
|
|
free(ListControl);
|
|
}
|
|
ListControl = NULL;
|
|
return 1;
|
|
}
|
|
int LLDcreate( int ItemSize )
|
|
{
|
|
int List ;
|
|
|
|
assert( (unsigned) ( ItemSize -1 ) < 1024 -1 ) ;
|
|
/* limit to 1kB. A size of 0 is ridiculous */
|
|
|
|
/* trigger automatic system initialisation if neccesary
|
|
*/
|
|
if( NULL == ListControl && 0 != LLDsystemInit( 1 ))
|
|
{
|
|
return ERR_MEMORY ;
|
|
}
|
|
|
|
/* Look for empty slot
|
|
*/
|
|
for( List = 0; List < (int)ListCount; List++ )
|
|
{
|
|
if( 0 == ListControl[ List ].itemsize )
|
|
break;
|
|
}
|
|
|
|
/* What if NO EMPTY slot ???
|
|
*/
|
|
if( List == (int)ListCount )
|
|
{
|
|
struct ListHead * tmp ; /* ListControl expansion needed */
|
|
|
|
tmp = MALLOC( ListCount + 1, struct ListHead );
|
|
if( NULL == tmp )
|
|
{
|
|
return ERR_MEMORY ;
|
|
}
|
|
/* MK */
|
|
memset(tmp,0,(ListCount+1)*sizeof(struct ListHead));
|
|
|
|
memcpy( tmp, ListControl, ListCount * sizeof( struct ListHead ));
|
|
/* MK */
|
|
free(ListControl);
|
|
ListControl = tmp ;
|
|
ListCount++ ;
|
|
}
|
|
|
|
/* create dummy head node and set up ListControl for the list.
|
|
*/
|
|
if( ERR_MEMORY == ListInit( List, ItemSize ))
|
|
{
|
|
return ERR_MEMORY ;
|
|
}
|
|
|
|
return List ;
|
|
}
|
|
|
|
void LLDdelete( int List )
|
|
{
|
|
struct Node * Tmp ;
|
|
struct Node * Old ;
|
|
|
|
assert( (unsigned) List < ListCount );
|
|
|
|
if(ListControl == NULL)
|
|
{
|
|
return;
|
|
}
|
|
Tmp = ListControl[ List ].first ; /* dummies are also deleted !!! */
|
|
while( NULL != Tmp ) /* still assuming last node has */
|
|
{ /* a NULL next pointer ... */
|
|
Old = Tmp ;
|
|
Tmp = Old->next;
|
|
NODE_FREE( Old ); /* data already presumed to be deleted */
|
|
}
|
|
|
|
ListInit( List, 0 ); /* 0: mark list as not used. */
|
|
|
|
return ;
|
|
}
|
|
|
|
/* ---- LL system maintenance ----------------------------------------- */
|
|
|
|
int LLDcheck( int List )
|
|
{
|
|
if( NULL == ListControl )
|
|
{
|
|
return LIST_SYSTEM_NULL ;
|
|
}
|
|
|
|
if( (unsigned) List >= ListCount )
|
|
{
|
|
return LIST_INV_NUMBER ;
|
|
}
|
|
|
|
if( 0 == ListControl[ List ].itemsize )
|
|
{
|
|
return LIST_NOT_CREATED ;
|
|
}
|
|
|
|
if( NULL == ListControl[ List ].first
|
|
|| NULL == ListControl[ List ].first->next /* missing tail ? */
|
|
|| NULL != ListControl[ List ].first->prev )
|
|
{
|
|
return LIST_ERR_HEAD ;
|
|
}
|
|
|
|
/* Validate current pointer
|
|
*/
|
|
if( NULL == ListControl[ List ].current )
|
|
{
|
|
return LIST_CORRUPT7 ; /* shouldn't be NULL with a good head */
|
|
}
|
|
|
|
if( NULL != ListControl[ List ].first->next->next ) /* empty list ? */
|
|
{ /* not empty. */
|
|
struct Node * tmp = ListControl[ List ].first ;
|
|
|
|
if( NULL == ListControl[ List ].current->next )
|
|
{
|
|
return LIST_CORRUPT6 ; /* a NULL next pointer is only valid */
|
|
} /* for an empty list. */
|
|
|
|
/* look for .current in list,
|
|
checking the .prev links along the way
|
|
*/
|
|
do
|
|
{
|
|
tmp = tmp->next ;
|
|
|
|
if( NULL == tmp || NULL == tmp->prev
|
|
|| tmp != tmp->prev->next )
|
|
{
|
|
return LIST_CORRUPT5 ; /* current not found in list */
|
|
} /* or link to/from next node */
|
|
/* invalid */
|
|
}while( tmp != ListControl[ List ].current );
|
|
|
|
/* Found .current in list. Also without link errors.
|
|
Now look for valid last node pointer in the list,
|
|
checking the .prev links along the way
|
|
Note that .current itself is never supposed to be equal
|
|
to .last (which points to the dummy tail) !
|
|
*/
|
|
if( NULL == ListControl[ List ].last )
|
|
{
|
|
return LIST_ERR_LAST ;
|
|
}
|
|
|
|
do
|
|
{
|
|
tmp = tmp->next ;
|
|
if( NULL == tmp || NULL == tmp->prev
|
|
|| tmp != tmp->prev->next )
|
|
{
|
|
return LIST_CORRUPT4 ; /* last not found in list */
|
|
} /* or link to/from prev node */
|
|
/* invalid */
|
|
}while( tmp != ListControl[ List ].last );
|
|
|
|
/* Found .last in list but is it really a valid last pointer?
|
|
Note: tmp == .last
|
|
*/
|
|
if( NULL != tmp->next )
|
|
{
|
|
return LIST_CORRUPT3 ;
|
|
}
|
|
|
|
return NO_PROBLEMS ;
|
|
}
|
|
|
|
/* .first->next->next == NULL => list is empty
|
|
*/
|
|
if( ListControl[ List ].current != ListControl[ List ].first->next )
|
|
{
|
|
return LIST_CORRUPT2 ;
|
|
}
|
|
|
|
if( ListControl[ List ].last != ListControl[ List ].first->next
|
|
|| ListControl[ List ].last
|
|
!= ListControl[ List ].current->prev->next )
|
|
{
|
|
return LIST_CORRUPT1 ;
|
|
}
|
|
|
|
return LIST_EMPTY ;
|
|
}
|
|
|
|
/* ---- node management ----------------------------------------------- */
|
|
|
|
int LLDnodeInsert( int List, ... ) /* insert _BEFORE_ current node */
|
|
{
|
|
va_list DataPtr ;
|
|
int Retval ;
|
|
|
|
/* set DataPtr to the address of "..."
|
|
then action, cleanup and return.
|
|
*/
|
|
va_start( DataPtr, List );
|
|
|
|
Retval = LLDnodeInsertFrom( List, (void *)va_arg(DataPtr,void *) );
|
|
|
|
va_end( DataPtr );
|
|
return Retval ;
|
|
}
|
|
|
|
int LLDnodeAdd( int List, ... ) /* insert _AFTER_ current node */
|
|
{
|
|
va_list DataPtr ;
|
|
int Retval ;
|
|
|
|
/* set DataPtr to the address of "..."
|
|
then action, cleanup and return.
|
|
*/
|
|
va_start( DataPtr, List );
|
|
|
|
Retval = LLDnodeAddFrom( List, (void *)va_arg(DataPtr,void *) );
|
|
|
|
va_end( DataPtr );
|
|
return Retval ;
|
|
}
|
|
|
|
int LLDnodePrepend( int List, ... ) /* insert as first node */
|
|
{
|
|
va_list DataPtr ;
|
|
int Retval ;
|
|
|
|
/* set DataPtr to the address of "..."
|
|
then action, cleanup and return.
|
|
*/
|
|
va_start( DataPtr, List );
|
|
|
|
Retval = LLDnodePrependFrom( List, (void *)va_arg(DataPtr,void *) );
|
|
|
|
va_end( DataPtr );
|
|
return Retval ;
|
|
}
|
|
|
|
int LLDnodeAppend( int List, ... ) /* insert as last node */
|
|
{
|
|
va_list DataPtr ;
|
|
int Retval ;
|
|
|
|
/* set DataPtr to the address of "..."
|
|
then action, cleanup and return.
|
|
*/
|
|
va_start( DataPtr, List );
|
|
|
|
Retval = LLDnodeAppendFrom( List, (void *)va_arg(DataPtr,void *) );
|
|
|
|
va_end( DataPtr );
|
|
return Retval ;
|
|
}
|
|
|
|
int LLDnodeInsertFrom( int List, void * Source )
|
|
{ /* insert _BEFORE_ current node */
|
|
struct Node * New ;
|
|
|
|
assert( (unsigned) List < ListCount );
|
|
|
|
/* create new node if possible
|
|
*/
|
|
New = NODE_MALLOC( List );
|
|
if( NULL == New )
|
|
{
|
|
return ERR_MEMORY ;
|
|
}
|
|
|
|
/* fill node with data, link to next and previous nodes
|
|
and adjust current node pointer
|
|
*/
|
|
memcpy( & New->data, Source, ListControl[ List ].itemsize );
|
|
New->next = ListControl[ List ].current;
|
|
New->prev = ListControl[ List ].current->prev;
|
|
|
|
ListControl[ List ].current->prev = New ;
|
|
New->prev->next = New ;
|
|
|
|
ListControl[ List ].current = New ;
|
|
|
|
return NO_PROBLEMS;
|
|
}
|
|
|
|
int LLDnodeAddFrom( int List, void * Source )
|
|
{ /* insert _AFTER_ current node */
|
|
struct Node * New ;
|
|
|
|
assert( (unsigned) List < ListCount );
|
|
|
|
/* create new node if possible
|
|
*/
|
|
New = NODE_MALLOC( List );
|
|
if( NULL == New )
|
|
{
|
|
return ERR_MEMORY ;
|
|
}
|
|
|
|
/* fill node with data and link to next and previous nodes
|
|
with special handling when the current node pointer points
|
|
to the dummy tail node: i.e it is an empty list.
|
|
(the same case in a non-empty list is made not to occur.)
|
|
*/
|
|
memcpy( & New->data, Source, ListControl[ List ].itemsize );
|
|
|
|
if( NULL != ListControl[ List ].current->next )
|
|
ListControl[ List ].current = ListControl[ List ].current->next ;
|
|
|
|
New->next = ListControl[ List ].current;
|
|
New->prev = ListControl[ List ].current->prev;
|
|
|
|
ListControl[ List ].current->prev = New ;
|
|
New->prev->next = New ;
|
|
|
|
ListControl[ List ].current = New ;
|
|
|
|
return NO_PROBLEMS;
|
|
}
|
|
|
|
int LLDnodePrependFrom( int List, void * Source )
|
|
{ /* insert as first node */
|
|
struct Node * New ;
|
|
|
|
assert( (unsigned) List < ListCount );
|
|
|
|
/* create new node if possible
|
|
*/
|
|
New = NODE_MALLOC( List );
|
|
if( NULL == New )
|
|
{
|
|
return ERR_MEMORY ;
|
|
}
|
|
|
|
/* fill node with data and link to dummy head and actual first nodes
|
|
*/
|
|
memcpy( & New->data, Source, ListControl[ List ].itemsize );
|
|
New->prev = ListControl[ List ].first; /* == .first->next->prev */
|
|
New->next = ListControl[ List ].first->next;
|
|
|
|
ListControl[ List ].first->next = New;
|
|
New->next->prev = New ;
|
|
|
|
/* Prevent .current from pointing at the dummy tail
|
|
(New is the only normal node...)
|
|
*/
|
|
if( NULL == ListControl[ List ].current->next )
|
|
ListControl[ List ].current = New;
|
|
|
|
return NO_PROBLEMS;
|
|
}
|
|
|
|
int LLDnodeAppendFrom( int List, void * Source )
|
|
{ /* insert as last node */
|
|
struct Node * New ;
|
|
|
|
assert( (unsigned) List < ListCount );
|
|
|
|
/* create new node if possible
|
|
*/
|
|
New = NODE_MALLOC( List );
|
|
if( NULL == New )
|
|
{
|
|
return ERR_MEMORY ;
|
|
}
|
|
|
|
/* fill node with data and link to dummy tail and actual last nodes
|
|
*/
|
|
memcpy( & New->data, Source, ListControl[ List ].itemsize );
|
|
New->next = ListControl[ List ].last ; /* == .last->prev->next */
|
|
New->prev = ListControl[ List ].last->prev;
|
|
|
|
ListControl[ List ].last->prev = New ;
|
|
New->prev->next = New ;
|
|
|
|
/* Prevent .current from pointing at the dummy tail
|
|
(New is the only normal node...)
|
|
*/
|
|
if( NULL == ListControl[ List ].current->next )
|
|
ListControl[ List ].current = New;
|
|
|
|
return NO_PROBLEMS;
|
|
}
|
|
|
|
void LLDnodeDelete( int List )
|
|
{
|
|
struct Node * Old = ListControl[ List ].current ;
|
|
|
|
assert( (unsigned) List < ListCount );
|
|
|
|
if( NULL == ListControl[ List ].current->next )
|
|
{
|
|
return ; /* don't delete dummy tail node (list is empty) */
|
|
}
|
|
|
|
/* adjust links
|
|
*/
|
|
Old->prev->next = Old->next ;
|
|
Old->next->prev = Old->prev ;
|
|
|
|
/* adjust current node pointer
|
|
prevent it from pointing to the dummy tail node
|
|
*/
|
|
if( NULL != Old->next->next )
|
|
ListControl[ List ].current = Old->next ;
|
|
else
|
|
ListControl[ List ].current = Old->prev ;
|
|
|
|
NODE_FREE( Old );
|
|
|
|
return ;
|
|
}
|
|
|
|
int LLDnodeFind( int List, CompFunPtr Compare, void * DataPtr )
|
|
{ /* FindFirst/FindNext format may be needed ... */
|
|
int RetVal ;
|
|
|
|
assert( (unsigned) List < ListCount );
|
|
|
|
if( NULL == ListControl[ List ].first->next->next ) /* empty list ? */
|
|
{
|
|
return 2; /* a compare usually returns just -1, 0 or 1 !!! */
|
|
}
|
|
|
|
/* note: current->next will never be NULL in a non-empty list */
|
|
|
|
if( NULL == Compare ) /* default to memcmp with .itemsize */
|
|
{
|
|
while( 0 != (RetVal = memcmp( DataPtr,
|
|
& ListControl[ List ].current->data,
|
|
ListControl[ List ].itemsize ))
|
|
&& NULL != ListControl[ List ].current->next->next )
|
|
{
|
|
ListControl[ List ].current=ListControl[ List ].current->next;
|
|
}
|
|
return RetVal ;
|
|
}
|
|
else
|
|
{
|
|
while( 0 != (RetVal = (*Compare)( DataPtr,
|
|
& ListControl[ List ].current->data ))
|
|
&& NULL != ListControl[ List ].current->next->next )
|
|
{
|
|
ListControl[ List ].current=ListControl[ List ].current->next;
|
|
}
|
|
return RetVal ;
|
|
}
|
|
}
|
|
|
|
/* ---- current node pointer management ------------------------------- */
|
|
|
|
int LLDnodePtr2First( int List )
|
|
{
|
|
assert( (unsigned) List < ListCount );
|
|
|
|
ListControl[ List ].current = ListControl[ List ].first->next ;
|
|
|
|
if(ListControl[List].first->next == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return NULL != ListControl[ List ].first->next->next ;
|
|
}
|
|
|
|
int LLDnodePtr2Last( int List )
|
|
{
|
|
assert( (unsigned) List < ListCount );
|
|
|
|
ListControl[ List ].current = ListControl[ List ].last->prev ;
|
|
|
|
return NULL != ListControl[ List ].last->prev->prev ;
|
|
}
|
|
|
|
int LLDnodePtr2Next( int List )
|
|
{
|
|
assert( (unsigned) List < ListCount );
|
|
|
|
if( NULL == ListControl[ List ].current->next /* empty list ? */
|
|
|| NULL == ListControl[ List ].current->next->next ) /* at end ?*/
|
|
{
|
|
return 0 ; /* do not allow the current node pointer */
|
|
} /* to point at the dummy tail node ... */
|
|
|
|
ListControl[ List ].current = ListControl[ List ].current->next ;
|
|
return 1 ;
|
|
}
|
|
|
|
int LLDnodePtr2Prev( int List )
|
|
{
|
|
assert( (unsigned) List < ListCount );
|
|
|
|
if( NULL == ListControl[ List ].current->prev /* empty list ? */
|
|
|| NULL == ListControl[ List ].current->prev->prev ) /* begin ? */
|
|
{
|
|
return 0 ; /* do not allow the current node pointer */
|
|
} /* to point at the dummy head node ... */
|
|
|
|
ListControl[ List ].current = ListControl[ List ].current->prev ;
|
|
return 1 ;
|
|
}
|
|
|
|
/* ---- stored data management ---------------------------------------- */
|
|
|
|
int LLDnodeInt( int List )
|
|
{
|
|
return ListControl[ List ].current->data;
|
|
}
|
|
|
|
long LLDnodeLong( int List )
|
|
{
|
|
return *((long *) &ListControl[ List ].current->data );
|
|
}
|
|
|
|
float LLDnodeFloat( int List )
|
|
{
|
|
return *((float *) &ListControl[ List ].current->data );
|
|
}
|
|
|
|
void * LLDnodePtr( int List )
|
|
{
|
|
return *((void **) &ListControl[ List ].current->data );
|
|
}
|
|
|
|
void FAR * LLDnodeFptr( int List )
|
|
{
|
|
return *((void FAR **) &ListControl[ List ].current->data );
|
|
}
|
|
|
|
int LLDnodeDataTo( int List, void * Destination )
|
|
{
|
|
if( NULL != Destination )
|
|
{
|
|
memcpy( Destination,
|
|
& ListControl[ List ].current->data,
|
|
ListControl[ List ].itemsize );
|
|
}
|
|
|
|
return ListControl[ List ].itemsize ; /* size needed for blob */
|
|
}
|
|
|
|
/* added: Mark Koennecke, 7.4.1997 */
|
|
int LLDnodeDataFrom( int List, void *source )
|
|
{
|
|
if( NULL != source )
|
|
{
|
|
memcpy(
|
|
& ListControl[ List ].current->data,
|
|
source,
|
|
ListControl[ List ].itemsize );
|
|
}
|
|
|
|
return ListControl[ List ].itemsize ; /* size needed for blob */
|
|
}
|
|
|
|
/* ==== LLD.c end ==================================================== */
|