Main Page | Data Structures | File List | Data Fields | Globals

doubleLinkedList.c

Go to the documentation of this file.
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 }

Generated on Mon Nov 8 16:04:06 2004 for countSmarts by doxygen 1.3.6