LIST(3) LIST(3) NAME list_init, list_mvprev, list_mvnext, list_mvfront, list_mvrear, list_front, list_curr, list_rear, list_insert_before, list_insert_after, list_remove_front, list_remove_curr, list_remove_rear, list_remove_element, list_size, list_empty, list_traverse, list_free - generic doubly-linked-list routines SYNOPSIS #include <list.h> list_t list_init(); list_t list_mvprev(list_t list); list_t list_mvnext(list_t list); list_t list_mvfront(list_t list); list_t list_mvrear(list_t list); void *list_front(list_t list); void *list_curr(list_t list); void *list_rear(list_t list); void *list_insert_before(list_t list, void *element, size_t len); void *list_insert_after(list_t list, void *element, size_t len); void *list_remove_front(list_t list); void *list_remove_curr(list_t list); void *list_remove_rear(list_t list); list_status_t list_remove_element(list_t list, void *element); size_t list_size(list_t list); int list_empty(list_t list); typedef int (*list_traverse_func_t)(void *data, void *element); list_status_t list_traverse(list_t list, void *data, list_traverse_func_t func, int opts); typedef void (*list_dealloc_func_t)(void *element); void list_free(list_t list, list_dealloc_func_t dealloc); - 1 - Formatted: November 6, 2024 LIST(3) LIST(3) Link with -llist. DESCRIPTION These routines provide generic manipulation of (potentially) multiple linked lists. Each list can hold arbitrarily sized elements, with individual elements within a list varying in size. It is the programmers responsibility to account for such differences. Lists are referred to by variables declared as list_t; the type list_t is an opaque handle. Traditionally, LIST * was used instead. LIST * is still defined for API backwards-compatibility, but new code should use list_t. Each descriptor maintains references to the front, rear, and current elements. It also holds the size (or length) of the list. Various routines operate relative to the current element. list_t is list handle. list_status_t may be one of the following meaningful values: LIST_EMPTY The list is empty. No operation was performed. LIST_OK The operation was successfully performed. LIST_EXTENT The operation finished without error but the end of the list was reached without any special action. list_init initializes and returns a list descriptor. list_mvprev, list_mvnext, list_mvfront, list_mvrear, move to the previous, next, front, or rear element in list, and return the modified list descriptor. Movement previous or next is relative to the current element. list_front, list_curr, and list_rear return pointers to the front, current, or rear element in list. list_insert_before and list_insert_after insert an element, pointed to by element and of size len, into list, either before or after the current element. The newly inserted element is then considered the current element. Both routines return a pointer to the newly inserted element. If len is greater than 0, then element is copied into the list, otherwise only the reference data is copied into the list. This allows the user to determine the memory allocation policy. list_remove_front, list_remove_curr, and list_remove_rear remove the front, current, or rear element from list and return a pointer to the removed element. The current element is then set to the next element (prior to the remove) in the list, unless the element at the rear of the list was removed. In this case, the current element is set to the previous element (prior to the remove). list_remove_element removes an element identified by the pointer element from the list. This function is only useful if you are - 2 - Formatted: November 6, 2024 LIST(3) LIST(3) allocating each element yourself (i.e., you are setting len to 0 when calling list_insert_before or list_insert_after). This function will remove all instances of element, at the expense of forcing a traversal of the whole list. If the end of the list is reached without finding element, LIST_EXTENT is returned. Otherwise, if one or more elements is successfully removed, LIST_OK is returned. list_size returns the size (or number of elements) of list as a size_t. list_empty returns 1 (TRUE) if list is empty, 0 (FALSE) otherwise. list_traverse traverses list according to opts, calling func at each element encountered in the traversal, until func returns 0 (FALSE) or the extent of the list is reached. This routine can be used to search for an item or print the contents of the list, for example. See the section LIST TRAVERSAL for more information. list_free deallocates list, applying the user-supplied function dealloc to the data portion of each element remaining in the list. If dealloc is LIST_DEALLOC, then the package will apply its own deallocation routine. This, however, should only be done if the package has been responsible for data element allocation, i.e., the insert routines have been invoked with len greater than 0. If dealloc is LIST_NODEALLOC, no per-element deallocation will be performed. LIST TRAVERSAL The behavior of the routine list_traversal is controlled by the user- supplied function func which is responsible for the actions performed at each element in the traversal. In addition, the scope and direction of the traversal can be specified with the opts parameter. Func should be declared to match the diff_traverse_func_t type: int func(void *data, void *element); and should return 1 (TRUE) if the traversal should continue, or 0 (FALSE) if the traversal should terminate. The function does not need to check if the extent of the list has been reached; the return code from list_traverse will indicate the status of the traversal. At each element encountered in the traversal, list_traverse will invoke func, passing it the two parameters data and element; data being the data pointer sent to list_traverse originally, and element being the current element in the traversal. For example, by passing the following function to list_traverse, the contents of a list of names could be printed. struct mystruct { char *name; }; - 3 - Formatted: November 6, 2024 LIST(3) LIST(3) int func(void *data, struct mystruct *element) { printf("Name=%30s.\n", element->name); return TRUE; } In this example, the parameter data is ignored and the function unconditionally returns 1 (TRUE), but functions like int func(void *data, void *element) { if (strcmp(data, element)) return TRUE; else return FALSE; } can be used to position the current element pointer prior to insertion, so as to keep the list ordered. The direction and scope of the traversal can be controlled by specifying one or more of the following options: LIST_FORW * traverse forward (next) LIST_BACK traverse backwards (prev) LIST_FRNT * start from the front of the list (implies LIST_FORW) LIST_CURR start from the current element LIST_REAR start from the rear element (implies LIST_BACK) LIST_SAVE * do not alter the current element pointer during the traversal LIST_ALTR alter the current element pointer during the traversal The asterisks (*) denote the default values. These options can be combined with the logical OR operator, but at least one value must be specified. For example, specifying LIST_FORW for opts would request a traversal forwards from the current position, restoring the current element pointer after the traversal, whereas (LIST_BACK | LIST_CURR | LIST_ALTR) would request a traversal backwards from the current position, and would set the current element pointer to the last element encountered in the traversal. It should be noted that func should not invoke any of the list - 4 - Formatted: November 6, 2024 LIST(3) LIST(3) routines unless LIST_ALTR has been specified, since many of the routines act relative to the current element pointer, which is not modified during a traversal with LIST_SAVE specified. MEMORY ALLOCATION The routines list_init, list_insert_before, and list_insert_after allocate memory during their execution. As such, list_insert_before and list_insert_after insert a copy of the element into the list when they are invoked with len greater than 0. If len is 0, then only the reference is copied into the list. This allows the user to control the memory allocation policy. Both functions may fail during memory allocation; see DIAGNOSTICS below for more information. Note that list_remove_front, list_remove_curr, and list_remove_rear do not deallocate memory for the removed element. They simply disassociate the element from the list, and thus return a pointer to the element that was previously allocated by the package. It is the programmer's responsibility to deallocate such a removed element. If the user has been responsible for element storage allocation, i.e. the insert routines have been called with len equal to 0, then the user must be responsible for storage deallocation as well. A user- supplied deallocation function should be passed to list_free for this purpose. The deallocation function should be declared as the list_dealloc_func_t typedef: void dealloc(void *data) This function will be passed each element in the list when list_free is invoked. If liblist has been responsible for data element allocation, list_free can be invoked with LIST_DEALLOC for dealloc,; the list package will apply its own deallocation routine, or LIST_NODEALLOC if no per-element deallocation is required. It is the programmer's responsibility to insure that the memory allocation policy is applied properly. DIAGNOSTICS A NULL returned by list_init, list_insert_before, or list_insert_after indicates a failure in allocating memory for the new list or element. See malloc(3) for more information. list_mvprev, list_mvnext, list_mvfront, list_mvrear, list_front, list_curr, list_rear, list_remove_front, list_remove_curr, and list_remove_rear all return NULL if list is empty. list_traverse returns LIST_EMPTY for an empty list, LIST_EXTENT if an attempt was made to move beyond the extent of the list, or LIST_OK otherwise. A core dump indicates a bug ;-) - 5 - Formatted: November 6, 2024 LIST(3) LIST(3) BUGS The routines list_remove_front, list_remove_curr, list_remove_rear, and list_free do not physically reclaim storage space, although they do make it available for reuse. While this is a function of free(3), its application here could be considered a bug. SEE ALSO liblist_queue(3), liblist_stack(3), cache(3) AUTHOR Bradley C. Spatz (bcs@ufl.edu), University of Florida. - 6 - Formatted: November 6, 2024