00001 /* just some information about this file */ 00002 #define DOUBLELINKEDLIST_VERSION "1.1.1" 00003 #define DOUBLELINKEDLIST_DATE "04-Dec-2003" 00004 00005 /* structures and typedefs */ 00006 00007 /** @file 00008 * Fault-tolerant double linked list data structure. 00009 * 00010 * This structure provides a fault-tolerant data structure of a double linked list. Basically, a double 00011 * linked list is a dynamic data structure. This implementation facilitates insertions and removals of 00012 * nodes. A queue and a stack are emulated with 'define' functions (see below). 00013 * 00014 * Two structures are used to implement the list: 00015 * @li @ref listNode (self-referential structure) 00016 * @li @ref List 00017 * <BR> 00018 * represent a node of the list and the complete double linked list, respectively. As the data of 00019 * each node is just a @c void* every kind of data can be stored. 00020 * 00021 * The structure is created with @ref List_create, destroyed with @ref List_destroy and 00022 * displayed with @ref List_display. The list is traversed using @ref List_getNext and 00023 * @ref List_hasNext. Elements are added at the current position with 00024 * @ref List_insert and removed with @ref List_remove. Additionally, a node is added at the end of the 00025 * list with @ref List_insertTail and at the beginning with @ref List_insertHead. Nodes are removed from 00026 * the head of the list with @ref List_removeHead and from the end of the list with @ref List_removeTail. 00027 * As the list keeps track of the current node during traversal (changed with @ref List_getNext) it is 00028 * rewinded with @ref List_rewind. The function @ref List_isEmpty returns @ref BOOLEAN_TRUE if the list 00029 * is empty and @ref BOOLEAN_FALSE otherwise. 00030 * 00031 * The structure @ref List provides also a possibility to store a name for this list as a char*. The 00032 * name can be accessed with @ref List_setName and @ref List_getName. The structure keeps automatically 00033 * track of the current number of nodes. This value is returned by @ref List_getNumberOfNodes. 00034 * <BR> 00035 * Stacks are implemented by the define @c functions @ref List_pushhead, @ref List_pophead and @ref 00036 * List_top. Functionality of a queue is provided by @ref List_enqueue and @ref List_dequeue. 00037 * <BR><BR> 00038 * One has to provide a function pointer to display the data that is stored in the individual nodes via 00039 * the @c void*! The display function has to comply to the prototype <b>void 00040 * displayFunction( void*, FILE* )</b>. A function pointer to destroy (i.e. free) the data of a node is 00041 * also mandatory. The destroy function has to comply to the prototype <b>void destroyFunction 00042 * ( void* )</b>. 00043 * <BR><BR> 00044 * The list can automatically check for every insertion operation if there exists already a node with a 00045 * void* @c data that is identical to the one that should be inserted. This has to be specified with a 00046 * function parameter during creation of the List (@ref List_create) and cannot be changed afterwards. 00047 * However, function @ref List_getUniqueData can be used to query a list about its 'uniqueness' status. 00048 * The status is queried with @ref List_getUniqueData. Uniqueness is guaranteed with the function 00049 * @c identicalFunction; it is provided as a function parameter to @ref List_create. The provided 00050 * function @c identicalFunction has to return BOOLEAN_FALSE or BOOLEAN_TRUE if the data is identical or 00051 * non-identical, respectively. 00052 * <P> 00053 * @anchor listNode 00054 * <B>Structure listNode</B> 00055 * <BR><BR> 00056 * The structure listNode consists of a @c void* to store the data, of a pointer to the next node in 00057 * the list and of a pointer to the previous node (self-referential structure). 00058 * 00059 * <B>Description of the members of listNode:</B><BR><BR> 00060 * @c void* - points to the data of the node<BR> 00061 * @c struct listNode* - pointer on the <b>previous</b> node in the list<BR> 00062 * @c struct listNode* - pointer on the <b>next</b> node in the list<BR> 00063 * <P> 00064 * 00065 * @anchor List 00066 * <B>Structure List</B> 00067 * <BR><BR> 00068 * The structure List conists of a ListNode_Ptr on the first node, a ListNode_Ptr on the 00069 * last node, a pointer on the current node (needed for sequential traversal of the list) and a 00070 * function pointer to display the data of a node. Additionally, a name (char*) and the current number 00071 * of nodes is stored and accessible with appropriate functions. 00072 * 00073 * <B>Description of the members of SingleLinkedList:</B><BR><BR> 00074 * @c name - char* to store the name of the list<BR> 00075 * @c numberOfNodes - stores the number of nodes in the list<BR> 00076 * @c headNodePtr - ListNode_Ptr on the first node in the list<BR> 00077 * @c tailNodePtr - ListNode_Ptr on the last node in the list<BR> 00078 * @c currentNodePtr - ListNode_Ptr on the current node in the list<BR> 00079 * @c uniqueData - indicates via BOOLEAN_TRUE and BOOLEAN_FALSE if nodes with identical data are allowed<BR> 00080 * @c displayFunction - pointer to a function that is capable of displaying the data of a node<BR> 00081 * @c destroyFunction - pointer to a function that is capable of destroying the data of a node<BR> 00082 * @c identicalFunction - pointer to a function that returns whether the data of two nodes is identical<BR> 00083 * <P> 00084 * @author Uli Fechner 00085 * @version 28/11/2003 - Uli Fechner - initial release 00086 * @version 03/12/2003 - Uli Fechner - added support for lists that contain only non-identical @c data 00087 * in their nodes (added member @c uniqueData and @c identicalFunction to structure List; added functions 00088 * @ref List_isContained, @ref List_getUniqueData; modified @ref List_insert, @ref List_insertHead and 00089 * @ref List_insertTail); the currentNodePtr 00090 * @version 04/12/2003 - Uli Fechner - changed the behaviour of re-setting @c currentNodePtr in @ref 00091 * List_remove and @ref List_removeHead for consistency reasons 00092 * @@code 00093 */ 00094 struct listNode 00095 { 00096 void* data; 00097 struct listNode* previousNodePtr; 00098 struct listNode* nextNodePtr; 00099 }; 00100 00101 /** A structure @ref listNode is assigned the name @c ListNode. */ 00102 typedef struct listNode ListNode; 00103 00104 /** A pointer to structure @ref ListNode is assigned the name @c ListNode_Ptr. */ 00105 typedef ListNode* ListNode_Ptr; 00106 00107 typedef struct 00108 { 00109 char* name; 00110 int numberOfNodes; 00111 ListNode_Ptr headNodePtr; 00112 ListNode_Ptr tailNodePtr; 00113 ListNode_Ptr currentNodePtr; 00114 int uniqueData; 00115 void (*displayFunction) ( void* data, FILE* outputStream ); 00116 void (*destroyFunction) ( void* data ); 00117 int (*identicalFunction) ( const void* data1, const void* data2 ); 00118 } List; 00119 00120 /** A pointer to structure @ref List is assigned the name @c List_Ptr. */ 00121 typedef List* List_Ptr; 00122 /** @endcode */ 00123 00124 /* defines */ 00125 00126 /** If DOUBLELINKESLIST_DEBUG is set to 1 some debug information is written to standard error. 00127 * 00128 * @author Uli Fechner 00129 * @version 25/11/2003 - Uli Fechner - initial release 00130 */ 00131 #ifndef DOUBLELINKESLIST_DEBUG 00132 #define DOUBLELINKEDLIST_DEBUG 0 00133 #endif 00134 00135 /** Boolean variables are simulated with the defines BOOLEAN_FALSE and BOOLEAN_TRUE. 00136 * 00137 * @author Uli Fechner 00138 * @version 03/12/2003 - Uli Fechner - initial release 00139 */ 00140 #ifndef BOOLEAN_FALSE 00141 #define BOOLEAN_FALSE 0 00142 #endif 00143 00144 /** Boolean variables are simulated with the defines BOOLEAN_FALSE and BOOLEAN_TRUE. 00145 * 00146 * @author Uli Fechner 00147 * @version 03/12/2003 - Uli Fechner - initial release 00148 */ 00149 #ifndef BOOLEAN_TRUE 00150 #define BOOLEAN_TRUE 1 00151 #endif 00152 00153 /* define 'functions' */ 00154 /* The following defines are used to emulate function calls for stacks */ 00155 00156 /** Pushes an element on top of a <b>stack</b>. 00157 * 00158 * @attention 00159 * This define is only a wrapper for @ref List_insertHead! 00160 * 00161 * @author Uli Fechner 00162 * @version 25/11/2003 - Uli Fechner - initial release 00163 */ 00164 #define List_pushhead( listPtr, data ) \ 00165 ( List_insertHead( listPtr, data ) ) 00166 00167 /** Pops an element from top of a <b>stack</b>. 00168 * 00169 * @attention 00170 * This define is only a wrapper for @ref List_removeHead! 00171 * 00172 * @author Uli Fechner 00173 * @version 25/11/2003 - Uli Fechner - initial release 00174 */ 00175 #define List_pophead( listPtr ) \ 00176 ( List_removeHead( listPtr ) ) 00177 00178 /** Returns the element on top of a <b>stack</b> without removing it. 00179 * 00180 * @attention 00181 * This define wraps sequentially @ref List_rewind and @ref List_getNext! 00182 * 00183 * @author Uli Fechner 00184 * @version 25/11/2003 - Uli Fechner - initial release 00185 */ 00186 #define List_top( listPtr ) \ 00187 ( ( List_rewind( listPtr ) ), \ 00188 ( List_getNext( listPtr ) ) ) 00189 00190 /* The following defines are used to emulate function calls for queues */ 00191 00192 /** Enqueues an element in a <b>queue</b>. 00193 * 00194 * @attention 00195 * This define is only a wrapper for @ref List_insertTail! 00196 * 00197 * @author Uli Fechner 00198 * @version 25/11/2003 - Uli Fechner - initial release 00199 */ 00200 #define List_enqueue( listPtr, data ) \ 00201 ( List_insertTail( listPtr, data ) ) 00202 00203 /** Dequeues an element of a <b>queue</b>. 00204 * 00205 * @attention 00206 * This define is only a wrapper for @ref List_removeTail! 00207 * 00208 * @author Uli Fechner 00209 * @version 25/11/2003 - Uli Fechner - initial release 00210 */ 00211 #define List_dequeue( listPtr ) \ 00212 ( List_removeHead( listPtr ) ) 00213 00214 /* function prototypes */ 00215 00216 List_Ptr List_create( const int uniqueData, void (*displayFunction) ( void* data, FILE* outputStream ), \ 00217 void (*destroyFunction) ( void* data ), \ 00218 int (*compareFunction) ( const void* data1, const void* data2 ) ); 00219 00220 void List_destroy( List_Ptr listPtr ); 00221 00222 void List_display( const List_Ptr listPtr, FILE* outputStream ); 00223 00224 void* List_getNext( const List_Ptr listPtr ); 00225 00226 int List_hasNext( const List_Ptr listPtr ); 00227 00228 void List_rewind( const List_Ptr listPtr ); 00229 00230 int List_insert( const List_Ptr listPtr, void* data ); 00231 00232 void* List_remove( const List_Ptr listPtr ); 00233 00234 int List_insertHead( const List_Ptr listPtr, void* data ); 00235 00236 int List_insertTail( const List_Ptr listPtr, void* data ); 00237 00238 void* List_removeHead( const List_Ptr listPtr ); 00239 00240 void* List_removeTail( const List_Ptr listPtr ); 00241 00242 int List_isEmpty( const List_Ptr listPtr ); 00243 00244 int List_isContained( const List_Ptr listPtr, const void* data ); 00245 00246 int List_getNumberOfNodes( const List_Ptr listPtr ); 00247 00248 void List_setName( const List_Ptr listPtr, char* name ); 00249 00250 char* List_getName( const List_Ptr listPtr ); 00251 00252 int List_getUniqueData( const List_Ptr listPtr ); 00253 00254 /* functions */ 00255 00256 /** Creates an @ref List structure. 00257 * 00258 * A structure @ref List is created. The memory of the structure itself and of its members is 00259 * allocated automatically. A function pointer on a function to display the data that is stored in this 00260 * List has to provided as an argument. 00261 * 00262 * @param uniqueData indicates via a boolean variable whether the data of the list should be checked for uniqueness 00263 * @param displayFunction function pointer on a function that is capable of displaying the data of a node 00264 * @param destroyFunction function pointer on a function that is capable of destroying the data of a node 00265 * @param identicalFunction function pointer on a function that is capable of checking whether the data of two nodes is identical 00266 * @retval List_Ptr pointer on the newly created structure @ref List 00267 * @author Uli Fechner 00268 * @version 28/11/2003 - Uli Fechner - initial release 00269 * @version 03/12/2003 - Uli Fechner - added function parameters uniqueData and compareFunction 00270 */ 00271 List_Ptr List_create( const int uniqueData, void (*displayFunction) ( void* data, FILE* outputStream ), \ 00272 void (*destroyFunction) ( void* data ), \ 00273 int (*identicalFunction) ( const void* data1, const void* data2 ) ) 00274 { 00275 List_Ptr listPtr; 00276 if( !( listPtr = calloc( 1, sizeof( List ) ) ) ) 00277 MemoryError( "listPtr", "List_create" ); 00278 00279 if( displayFunction == NULL ) 00280 { 00281 fprintf( stderr, "\nERROR: The argument (*displayFunction) of the function\n" ); 00282 fprintf( stderr, "List_create must not be 'NULL'!\n" ); 00283 AbortProgram; 00284 } 00285 00286 if( destroyFunction == NULL ) 00287 { 00288 fprintf( stderr, "\nERROR: The argument (*destroyFunction) of the function\n" ); 00289 fprintf( stderr, "List_create must not be 'NULL'!\n" ); 00290 AbortProgram; 00291 } 00292 00293 listPtr->name = NULL; 00294 listPtr->numberOfNodes = 0; 00295 listPtr->headNodePtr = NULL; 00296 listPtr->tailNodePtr = NULL; 00297 listPtr->currentNodePtr = NULL; 00298 listPtr->uniqueData = uniqueData; 00299 listPtr->displayFunction = displayFunction; 00300 listPtr->destroyFunction = destroyFunction; 00301 listPtr->identicalFunction = identicalFunction; 00302 00303 return listPtr; 00304 } 00305 00306 /** Destroys a @ref List structure. 00307 * 00308 * The structure @ref List the pointer @c listPtr refers to is destroyed. The memory of the 00309 * structure itself and of its members is freed automatically. 00310 * 00311 * @attention 00312 * The data of all nodes is freed with a trivial free of the node void pointers! If the void pointer 00313 * refers to structures that have members that allocate memory this memory is not freed! In such a case 00314 * it is best to remove the nodes one by one and free the memory individually. 00315 * 00316 * @param listPtr pointer on structure @ref List that should be destroyed 00317 * @author Uli Fechner 00318 * @version 28/11/2003 - Uli Fechner - initial release 00319 */ 00320 void List_destroy( List_Ptr listPtr ) 00321 { 00322 void* data; 00323 00324 if( listPtr == NULL ) 00325 { 00326 fprintf( stderr, "\n\nERROR: Function 'List_destroy' can not destroy a structure\n" ); 00327 fprintf( stderr, "'List' that has not been created before!\n" ); 00328 AbortProgram; 00329 } 00330 00331 List_rewind( listPtr ); // re-set the currentNodePtr 00332 while( !List_isEmpty( listPtr ) ) 00333 { 00334 data = List_removeHead( listPtr ); 00335 listPtr->destroyFunction( data ); 00336 } 00337 /* destroying the struct List itself */ 00338 free( listPtr ); 00339 } 00340 00341 /** Displays a structure @ref List. 00342 * 00343 * The structure @ref List the pointer @c listPtr refers to is displayed on the FILE* @c 00344 * outputStream. If the list is empty an appropriate message is printed on @c outputStream. 00345 * 00346 * @param listPtr pointer on the structure @ref List that should be displayed 00347 * @param outputStream FILE* on the stream the output should be sent to 00348 * @author Uli Fechner 00349 * @version 25/11/2003 - Uli Fechner - initial release 00350 * @version 03/12/2003 - Uli Fechner - added support for the members @c uniqueData and identicalFunction 00351 */ 00352 void List_display( const List_Ptr listPtr, FILE* outputStream ) 00353 { 00354 ListNode_Ptr tempNodePtr; 00355 tempNodePtr = listPtr->headNodePtr; 00356 00357 #if DOUBLELINKEDLIST_DEBUG 00358 fprintf( stderr, "list %p\nname: %s\nnumberOfNodes: %d\nuniqueData: %d\n", listPtr, listPtr->name, \ 00359 listPtr->numberOfNodes, listPtr->uniqueData ); 00360 fprintf( stderr, "headNodePtr: %p\ntailNodePtr: %p\ncurrentNodePtr: %p\n", listPtr->headNodePtr, \ 00361 listPtr->tailNodePtr, listPtr->currentNodePtr ); 00362 fprintf( stderr, "displayFunction: %p\ndestroyFunction: %p\nidenticalFunction: %p\n", \ 00363 listPtr->displayFunction, listPtr->destroyFunction, listPtr->identicalFunction ); 00364 #endif 00365 /* if the list is empty an appropriate message is printed on outputStream */ 00366 if( tempNodePtr == NULL ) 00367 fprintf( outputStream, "The list is empty.\n" ); 00368 /* if the list is not empty we go from node to node and use displayFunction to output the data */ 00369 while( tempNodePtr != NULL ) 00370 { 00371 #if DOUBLELINKEDLIST_DEBUG 00372 fprintf( stderr, "current node: %p\n", tempNodePtr ); 00373 fprintf( stderr, "previous node: %p\n", tempNodePtr->previousNodePtr ); 00374 fprintf( stderr, "next node: %p\n", tempNodePtr->nextNodePtr ); 00375 #endif 00376 listPtr->displayFunction( tempNodePtr->data, outputStream ); 00377 tempNodePtr = tempNodePtr->nextNodePtr; 00378 } 00379 fprintf( outputStream, "\n" ); 00380 } 00381 00382 /** Returns the data of the next node in the list. 00383 * 00384 * The current position within the @ref List is stored in the member @c currentNodePtr. 00385 * 00386 * @param listPtr pointer on the structure @ref List the node belongs to 00387 * @retval void* on the data of the node 00388 * @author Uli Fechner 00389 * @version 24/11/2003 - Uli Fechner - initial release 00390 */ 00391 void* List_getNext( const List_Ptr listPtr ) 00392 { 00393 /* checking if the currentNodePtr points 'before' the first node */ 00394 if( listPtr->currentNodePtr == NULL ) 00395 { 00396 /* checking if the list is empty */ 00397 if( !List_isEmpty( listPtr ) ) 00398 { 00399 listPtr->currentNodePtr = listPtr->headNodePtr; 00400 return (listPtr->currentNodePtr)->data; // FUNCTION EXITS HERE 00401 } 00402 /* list is empty */ 00403 else 00404 { 00405 fprintf( stderr, "\nERROR: The double linked list [%p] is empty!\n", listPtr ); 00406 fprintf( stderr, "Function List_getNext must not be called for an empty list\n!" ); 00407 AbortProgram; 00408 } 00409 } 00410 00411 /* checking if currentNodePtr points already to the last node in the list */ 00412 if( listPtr->currentNodePtr == listPtr->tailNodePtr ) 00413 { 00414 fprintf( stderr, "\nERROR: Function List_getNext reached the end of the double linked\n" ); 00415 fprintf( stderr, "list [%s; %p]! Boundaries of the single linked list must be checked!\n", \ 00416 List_getName( listPtr ), listPtr ); 00417 AbortProgram; 00418 } 00419 00420 /* setting currentNodePtr to the next node */ 00421 listPtr->currentNodePtr = (listPtr->currentNodePtr)->nextNodePtr; 00422 00423 return (listPtr->currentNodePtr)->data; 00424 } 00425 00426 /** Checks if the @ref List has at least one more node (directed forwards). 00427 * 00428 * The current position within the @ref List is stored in the member @c currentNodePtr. This function 00429 * checks if @c currentNodePtr points to @c tailNodePtr. If so, the end of the list is reached. 00430 * 00431 * @param listPtr pointer on the structure @ref List that is checked 00432 * @retval int BOOLEAN_FALSE or BOOLEAN_TRUE 00433 * @author Uli Fechner 00434 * @version 24/11/2003 - Uli Fechner - initial release 00435 */ 00436 int List_hasNext( const List_Ptr listPtr ) 00437 { 00438 if( listPtr->currentNodePtr == listPtr->tailNodePtr ) 00439 return BOOLEAN_FALSE; 00440 else 00441 return BOOLEAN_TRUE; 00442 } 00443 00444 /** Re-sets the position pointer of the @ref List to the beginning of the list. 00445 * 00446 * The current position within the @ref List is stored in the member @c currentNodePtr. This function 00447 * re-sets @c currentNodePtr to the very beginning of the list, so that the next call to @ref 00448 * List_getNext returns the data of the first node. 00449 * 00450 * @param listPtr pointer on the structure @ref List the position pointer is re-set 00451 * @author Uli Fechner 00452 * @version 24/11/2003 - Uli Fechner - initial release 00453 */ 00454 void List_rewind( const List_Ptr listPtr ) 00455 { 00456 listPtr->currentNodePtr = NULL; 00457 } 00458 00459 /** A new node is inserted in @ref List at the position that is referred by @c currentNodePtr. 00460 * 00461 * @attention 00462 * After a successful insertion the @c currentNodePtr points to the newly created node. 00463 * 00464 * @param listPtr pointer on the structure @ref List the node is inserted 00465 * @param data data of the new node 00466 * @retval int returns BOOLEAN_TRUE on a successful and BOOLEAN_FALSE on a unsuccessful insertion 00467 * @author Uli Fechner 00468 * @version 24/11/2003 - Uli Fechner - initial release 00469 * @version 03/12/2003 - Uli Fechner - changed return type from void to int (BOOLEAN_TRUE and 00470 * BOOLEAN_FALSE); added support for uniqueData list 00471 */ 00472 int List_insert( const List_Ptr listPtr, void* data ) 00473 { 00474 ListNode_Ptr newListNodePtr; 00475 int successfulInsertion; 00476 00477 /* node is inserted as the first one in the list */ 00478 if( listPtr->currentNodePtr == NULL ) 00479 { 00480 successfulInsertion = List_insertHead( listPtr, data ); 00481 listPtr->currentNodePtr = listPtr->headNodePtr; 00482 return successfulInsertion; 00483 } 00484 00485 /* node is inserted as the last one in the list */ 00486 if( listPtr->currentNodePtr == listPtr->tailNodePtr ) 00487 { 00488 successfulInsertion = List_insertTail( listPtr, data ); 00489 listPtr->currentNodePtr = listPtr->tailNodePtr; 00490 return successfulInsertion; 00491 } 00492 00493 /* if the list allows only unique data we check here if the data to be inserted is already in the 00494 list; if we find a duplicate NULL is returned */ 00495 if( listPtr->uniqueData == BOOLEAN_TRUE ) 00496 { 00497 if( ( List_isContained( listPtr, data ) ) == BOOLEAN_TRUE ) 00498 return BOOLEAN_FALSE; 00499 } 00500 00501 if( !( newListNodePtr = calloc( 1, sizeof( ListNode ) ) ) ) 00502 MemoryError( "newListNodePtr", "List_insert" ); 00503 newListNodePtr->data = data; 00504 newListNodePtr->nextNodePtr = NULL; 00505 newListNodePtr->previousNodePtr = NULL; 00506 00507 newListNodePtr->previousNodePtr = listPtr->currentNodePtr; 00508 newListNodePtr->nextNodePtr = (listPtr->currentNodePtr)->nextNodePtr; 00509 ((listPtr->currentNodePtr)->nextNodePtr)->previousNodePtr = newListNodePtr; 00510 (listPtr->currentNodePtr)->nextNodePtr = newListNodePtr; 00511 00512 listPtr->currentNodePtr = newListNodePtr; 00513 (listPtr->numberOfNodes)++; 00514 00515 return BOOLEAN_TRUE; 00516 } 00517 00518 /** The node that is referred to by @c currentNodePtr is removed from @ref List and its data is returned. 00519 * 00520 * @attention 00521 * The @c currentNodePtr is moved to the previous node. If the head node is removed @c currentNodePtr is 00522 * moved <b>before</b> the new head node. This behaviour guarantees that the following call of @ref 00523 * List_getNext returns the element that follows the one that was removed. 00524 * 00525 * @param listPtr pointer on the structure @ref List the node is removed from 00526 * @retval void* data of the removed node 00527 * @author Uli Fechner 00528 * @version 24/11/2003 - Uli Fechner - initial release 00529 * @version 04/12/2003 - Uli Fechner - changed the behaviour of @c currentNodePtr 00530 */ 00531 void* List_remove( const List_Ptr listPtr ) 00532 { 00533 void* data; 00534 /* ListNode_Ptr on the previous and the next node of listPtr->currentNodePtr */ 00535 ListNode_Ptr previousNodePtr, nextNodePtr; 00536 00537 /* returns with a function call to List_removeHead if currentNodePtr points to headNodePtr */ 00538 if( listPtr->currentNodePtr == listPtr->headNodePtr ) 00539 return List_removeHead( listPtr ); 00540 00541 /* returns with a function call to List_removeTail if currentNodePtr points to tailNodePtr */ 00542 if( listPtr->currentNodePtr == listPtr->tailNodePtr ) 00543 return List_removeTail( listPtr ); 00544 00545 if( listPtr->currentNodePtr == NULL ) 00546 { 00547 fprintf( stderr, "\nERROR: currentNodePtr points before the first node of the\n" ); 00548 fprintf( stderr, "list [%s; %p]. Removal is not possible.\n", List_getName( listPtr ), listPtr ); 00549 AbortProgram; 00550 } 00551 00552 previousNodePtr = (listPtr->currentNodePtr)->previousNodePtr; 00553 nextNodePtr = (listPtr->currentNodePtr)->nextNodePtr; 00554 previousNodePtr->nextNodePtr = nextNodePtr; 00555 nextNodePtr->previousNodePtr = previousNodePtr; 00556 data = (listPtr->currentNodePtr)->data; 00557 free( listPtr->currentNodePtr ); 00558 listPtr->currentNodePtr = previousNodePtr; 00559 //listPtr->currentNodePtr = nextNodePtr; 00560 (listPtr->numberOfNodes)--; 00561 00562 return data; 00563 } 00564 00565 /** Inserts a node at the head of the @ref List. 00566 * 00567 * @attention 00568 * The @c currentNodePtr is not changed if this function is called directly. 00569 * 00570 * @param listPtr pointer on the structure @ref List the new node is added 00571 * @param data void pointer on the actual data 00572 * @retval int returns BOOLEAN_TRUE on a successful and BOOLEAN_FALSE on an unsuccessful insertion 00573 * @author Uli Fechner 00574 * @version 28/11/2003 - Uli Fechner - initial release 00575 * @version 03/12/2003 - Uli Fechner - changed return type from void to int (BOOLEAN_TRUE and 00576 * BOOLEAN_FALSE); added support for uniqueData list 00577 */ 00578 int List_insertHead( const List_Ptr listPtr, void* data ) 00579 { 00580 ListNode_Ptr newListNodePtr; 00581 00582 /* if the list allows only unique data we check here if the data to be inserted is already in the 00583 list; if we find a duplicate NULL is returned */ 00584 if( listPtr->uniqueData == BOOLEAN_TRUE ) 00585 { 00586 if( ( List_isContained( listPtr, data ) ) == BOOLEAN_TRUE ) 00587 return BOOLEAN_FALSE; 00588 } 00589 00590 if( !( newListNodePtr = calloc( 1, sizeof( ListNode ) ) ) ) 00591 MemoryError( "newListNodePtr", "List_insertHead" ); 00592 newListNodePtr->data = data; 00593 newListNodePtr->nextNodePtr = NULL; 00594 newListNodePtr->previousNodePtr = NULL; 00595 00596 /* sets the currentNodePtr to the inserted node */ 00597 //listPtr->currentNodePtr = newListNodePtr; 00598 00599 /* if the list is empty tailNodePtr has to point on the newly added node */ 00600 if( listPtr->headNodePtr == NULL ) 00601 { 00602 listPtr->tailNodePtr = newListNodePtr; 00603 } 00604 /* if the list is non-empty the previousNodePtr of the first node has to point on the newly added node 00605 and the nextNodePtr of the newly added node has to point on headNodePtr */ 00606 else 00607 { 00608 (listPtr->headNodePtr)->previousNodePtr = newListNodePtr; 00609 newListNodePtr->nextNodePtr = listPtr->headNodePtr; 00610 } 00611 00612 listPtr->headNodePtr = newListNodePtr; 00613 (listPtr->numberOfNodes)++; 00614 00615 return BOOLEAN_TRUE; 00616 } 00617 00618 /** Inserts a node at the tail of the @ref List. 00619 * 00620 * @attention 00621 * The @c currentNodePtr is not changed if this function is called directly. 00622 * 00623 * @param listPtr pointer on the structure @ref List the new node is added 00624 * @param data void pointer on the actual data 00625 * @retval int returns BOOLEAN_TRUE on a successful and BOOLEAN_FALSE on an unsuccessful insertion 00626 * @author Uli Fechner 00627 * @version 28/11/2003 - Uli Fechner - initial release 00628 * @version 03/12/2003 - Uli Fechner - changed return type from void to int (BOOLEAN_TRUE and 00629 * BOOLEAN_FALSE); added support for uniqueData list 00630 */ 00631 int List_insertTail( const List_Ptr listPtr, void* data ) 00632 { 00633 ListNode_Ptr newListNodePtr; 00634 00635 /* if the list allows only unique data we check here if the data to be inserted is already in the 00636 list; if we find a duplicate NULL is returned */ 00637 if( listPtr->uniqueData == BOOLEAN_TRUE ) 00638 { 00639 if( ( List_isContained( listPtr, data ) ) == BOOLEAN_TRUE ) 00640 return BOOLEAN_FALSE; 00641 } 00642 00643 if( !( newListNodePtr = calloc( 1, sizeof( ListNode ) ) ) ) 00644 MemoryError( "newListNodePtr", "List_insertTail" ); 00645 newListNodePtr->data = data; 00646 newListNodePtr->nextNodePtr = NULL; 00647 newListNodePtr->previousNodePtr = NULL; 00648 00649 /* sets the currentNodePtr to the inserted node */ 00650 //listPtr->currentNodePtr = newListNodePtr; 00651 00652 /* if the list is empty headNodePtr has to point on the newly added node */ 00653 if( listPtr->headNodePtr == NULL ) 00654 { 00655 listPtr->headNodePtr = newListNodePtr; 00656 } 00657 /* if the list is non-empty the nextNodePtr of the last node has to point on the newly added node 00658 and the previousNodePtr of the newly added node has to point on tailNodePtr */ 00659 else 00660 { 00661 (listPtr->tailNodePtr)->nextNodePtr = newListNodePtr; 00662 newListNodePtr->previousNodePtr = listPtr->tailNodePtr; 00663 } 00664 00665 listPtr->tailNodePtr = newListNodePtr; 00666 (listPtr->numberOfNodes)++; 00667 00668 return BOOLEAN_TRUE; 00669 } 00670 00671 /** The first node of the structure @ref List is removed. 00672 * 00673 * @attention 00674 * If the @c currentNodePtr points to the head node it is moved before the new head node. Otherwise it is 00675 * left untouched. This behaviour guarantees that a call to @ref List_getNext retrieves the node that 00676 * follows the one that was removed. 00677 * 00678 * @param listPtr pointer on the structure @ref List the node is removed from 00679 * @retval void* data of the removed node 00680 * @author Uli Fechner 00681 * @version 28/11/2003 - Uli Fechner - initial release 00682 * @version 04/12/2003 - Uli Fechner - changed the behaviour of the currentNodePtr 00683 */ 00684 void* List_removeHead( const List_Ptr listPtr ) 00685 { 00686 void* data; 00687 ListNode_Ptr newHeadNodePtr; /* temporary storage for the new head node pointer of list */ 00688 00689 /* nothing can be removed if the list is empty */ 00690 if( listPtr->headNodePtr == NULL ) 00691 { 00692 fprintf( stderr, "\nERROR: Structure List [%p] is empty!\n", listPtr ); 00693 fprintf( stderr, "Function 'List_removeHead' must not be called for an empty list.\n" ); 00694 AbortProgram; 00695 } 00696 00697 /* if currentNodePtr points to the head node it is moved to the next node */ 00698 if( listPtr->currentNodePtr == listPtr->headNodePtr ) 00699 listPtr->currentNodePtr = NULL; 00700 //listPtr->currentNodePtr = (listPtr->currentNodePtr)->nextNodePtr; 00701 00702 data = (listPtr->headNodePtr)->data; 00703 newHeadNodePtr = (listPtr->headNodePtr)->nextNodePtr; 00704 if( newHeadNodePtr != NULL ) 00705 newHeadNodePtr->previousNodePtr = NULL; 00706 free( listPtr->headNodePtr ); 00707 listPtr->headNodePtr = newHeadNodePtr; 00708 00709 /* if the last node is removed from the list tailNodePtr is set to NULL */ 00710 if( listPtr->headNodePtr == NULL ) 00711 listPtr->tailNodePtr = NULL; 00712 00713 (listPtr->numberOfNodes)--; 00714 return data; 00715 } 00716 00717 /** The last node of the structure @ref List is removed. 00718 * 00719 * @attention 00720 * If the @c currentNodePtr points to the tail node it is moved to the new tail node. Otherwise it is 00721 * left untouched. 00722 * 00723 * @param listPtr pointer on the structure @ref List the node is removed from 00724 * @retval void* data of the removed node 00725 * @author Uli Fechner 00726 * @version 24/11/2003 - Uli Fechner - initial release 00727 */ 00728 void* List_removeTail( const List_Ptr listPtr ) 00729 { 00730 void* data; 00731 ListNode_Ptr newTailNodePtr; /* temporary storage for the new tail node pointer of list */ 00732 00733 /* nothing can be removed if the list is empty */ 00734 if( listPtr->headNodePtr == NULL ) 00735 { 00736 fprintf( stderr, "\nERROR: Structure List [%p] is empty!\n", listPtr ); 00737 fprintf( stderr, "Function 'List_removeTail' must not be called for an empty list.\n" ); 00738 AbortProgram; 00739 } 00740 00741 /* if currentNodePtr points to the tail node it is moved to the previous node */ 00742 if( listPtr->currentNodePtr == listPtr->tailNodePtr ) 00743 listPtr->currentNodePtr = (listPtr->currentNodePtr)->previousNodePtr; 00744 00745 data = (listPtr->tailNodePtr)->data; 00746 newTailNodePtr = (listPtr->tailNodePtr)->previousNodePtr; 00747 if( newTailNodePtr != NULL ) 00748 newTailNodePtr->nextNodePtr = NULL; 00749 free( listPtr->tailNodePtr ); 00750 listPtr->tailNodePtr = newTailNodePtr; 00751 00752 /* if the last node is removed from the list headNodePtr is set to NULL */ 00753 if( listPtr->tailNodePtr == NULL ) 00754 listPtr->headNodePtr = NULL; 00755 00756 (listPtr->numberOfNodes)--; 00757 return data; 00758 } 00759 00760 /** Checks if the structure @ref List is empty. 00761 * 00762 * This function returns @ref BOOLEAN_TRUE if the structure @ref List is empty and @ref BOOLEAN_FALSE 00763 * otherwise. 00764 * 00765 * @param listPtr pointer on the structure @ref List that is checked for emptiness 00766 * @retval int @ref BOOLEAN_TRUE or @ref BOOLEAN_FALSE 00767 * @author Uli Fechner 00768 * @version 24/11/2003 - Uli Fechner - initial release 00769 */ 00770 int List_isEmpty( const List_Ptr listPtr ) 00771 { 00772 if( listPtr->headNodePtr == NULL ) 00773 return BOOLEAN_TRUE; 00774 else 00775 return BOOLEAN_FALSE; 00776 } 00777 00778 /** Checks if @c data is contained in the @ref List. 00779 * 00780 * This function returns @ref BOOLEAN_TRUE if @c data is contained in the @ref List and @ref BOOLEAN_FALSE 00781 * otherwise. 00782 * 00783 * @param listPtr pointer on the structure @ref List that is checked for the presence of @c data 00784 * @param data void pointer on the actual data 00785 * @retval int @ref BOOLEAN_TRUE or @ref BOOLEAN_FALSE 00786 * @author Uli Fechner 00787 * @version 03/12/2003 - Uli Fechner - initial release 00788 */ 00789 int List_isContained( const List_Ptr listPtr, const void* data ) 00790 { 00791 ListNode_Ptr tempNodePtr; 00792 tempNodePtr = listPtr->headNodePtr; 00793 00794 /* we go from node to node */ 00795 while( tempNodePtr != NULL ) 00796 { 00797 if( ( listPtr->identicalFunction( tempNodePtr->data, data ) ) == BOOLEAN_TRUE ) 00798 return BOOLEAN_TRUE; 00799 tempNodePtr = tempNodePtr->nextNodePtr; 00800 } 00801 00802 /* we did not find data within the list */ 00803 return BOOLEAN_FALSE; 00804 } 00805 00806 /** The @c numberOfNodes of the @ref List is returned. 00807 * 00808 * @param listPtr pointer on the structure @ref List 00809 * @retval int number of nodes in the @ref List 00810 * @author Uli Fechner 00811 * @version 25/11/2003 - Uli Fechner - initial release 00812 */ 00813 int List_getNumberOfNodes( const List_Ptr listPtr ) 00814 { 00815 return listPtr->numberOfNodes; 00816 } 00817 00818 /** Sets the @c name of the @ref List. 00819 * 00820 * @attention 00821 * The provided parameter @c name is copied. @c name is <b>not</b> freed afterwards. This has to be done 00822 * by the caller of this function! 00823 * 00824 * @param listPtr pointer on the structure @ref List that is associated with @c name 00825 * @param name name of the @ref List 00826 * @author Uli Fechner 00827 * @version 24/11/2003 - Uli Fechner - initial release 00828 */ 00829 void List_setName( const List_Ptr listPtr, char* name ) 00830 { 00831 if( name != NULL ) 00832 { 00833 if( !( listPtr->name = calloc( strlen( name ) + 1, sizeof( char ) ) ) ) 00834 MemoryError( "List_setName", "listPtr->name" ); 00835 strncpy( listPtr->name, name, strlen( name ) + 1 ); 00836 } 00837 else 00838 listPtr->name = NULL; 00839 } 00840 00841 /** The @c name of the @ref List is returned. 00842 * 00843 * @param listPtr pointer on the structure @ref List that contains the value 00844 * @retval char name of the @ref List 00845 * @author Uli Fechner 00846 * @version 24/11/2003 - Uli Fechner - initial release 00847 */ 00848 char* List_getName( const List_Ptr listPtr ) 00849 { 00850 return listPtr->name; 00851 } 00852 00853 /** The value of the member @c uniqueData of the @ref List is returned. 00854 * 00855 * @param listPtr pointer on the structure @ref List that contains the value 00856 * @retval int value of @c uniqueData of the @ref List 00857 * @author Uli Fechner 00858 * @version 03/12/2003 - Uli Fechner - initial release 00859 */ 00860 int List_getUniqueData( const List_Ptr listPtr ) 00861 { 00862 return listPtr->uniqueData; 00863 }