/* -*-C-*- ############################################################################### # # File: list.c # Description: List processing procedures. # Author: Mark Seaman, Software Productivity # Created: Thu Jul 23 13:24:09 1987 # Modified: Thu Dec 22 10:59:52 1988 (Mark Seaman) marks@hpgrlt # Language: C # Package: N/A # Status: Reusable Software Component # # (c) Copyright 1987, Hewlett-Packard Company. ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** http://www.apache.org/licenses/LICENSE-2.0 ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. # ################################################################################ * Revision 1.13 90/03/06 15:37:54 15:37:54 marks (Mark Seaman) * Look for correct file of <malloc.h> or <stdlib.h> * * Revision 1.12 90/02/26 17:37:36 17:37:36 marks (Mark Seaman) * Added pop_off and join_on * This file contains a set of general purpose list manipulation routines. These routines can be used in a wide variety of ways to provide several different popular data structures. A new list can be created by declaring a variable of type 'LIST', and can be initialized with the value 'NIL_LIST'. All of these routines check for the NIL_LIST condition before dereferencing pointers. NOTE: There is a users' manual available in printed form from Mark Seaman at (303) 350-4492 at Greeley Hard Copy. To implement a STACK use: push to add to the Stack l = push (l, (LIST) "jim"); pop to remove items from the Stack l = pop (l); first_node to access the head name = (char *) first_node (l); To implement a QUEUE use: push_last to add to the Queue l = push_last (l, (LIST) "jim"); pop remove items from the Queue l = pop (l); first_node to access the head name = (char *) first_node (l); To implement LISP like functions use: first_node CAR x = (int) first_node (l); rest CDR l = list_rest (l); push CONS l = push (l, (LIST) this); last LAST x = last (l); concat APPEND l = concat (r, s); count LENGTH x = count (l); search MEMBER if (search (l, x, NULL)) To implement SETS use: adjoin l = adjoin (l, x); set_union l = set_union (r, s); intersection l = intersection (r, s); set_difference l = set_difference (r, s); delete l = delete (s, x, NULL); search if (search (l, x, NULL)) To Implement Associated LISTS use: lpush l = lpush (l, p); assoc s = assoc (l, x); adelete l = adelete (l, x); The following rules of closure exist for the functions provided. a = first_node (push (a, b)) b = list_rest (push (a, b)) a = push (pop (a), a)) For all a <> NIL_LIST a = reverse (reverse (a)) ******************************************************************************/ #include "oldlist.h" #include "structures.h" #include <stdio.h> #if MAC_OR_DOS #include <stdlib.h> #else #include "freelist.h" #endif /*---------------------------------------------------------------------- M a c r o s ----------------------------------------------------------------------*/ #define add_on(l,x) l = push (l,first_node (x)) #define next_one(l) l = list_rest (l) /*---------------------------------------------------------------------- F u n c t i o n s ----------------------------------------------------------------------*/ /********************************************************************** * c o u n t * * Recursively count the elements in a list. Return the count. **********************************************************************/ int count(LIST var_list) { int temp = 0; iterate (var_list) temp += 1; return (temp); } /********************************************************************** * d e l e t e d * * Delete all the elements out of the current list that match the key. * This operation destroys the original list. The caller will supply a * routine that will compare each node to the * key, and return a non-zero value when they match. If the value * NULL is supplied for is_equal, the is_key routine will be used. **********************************************************************/ LIST delete_d(LIST list, void *key, int_compare is_equal) { LIST result = NIL_LIST; LIST last_one = NIL_LIST; if (is_equal == NULL) is_equal = is_same; while (list != NIL_LIST) { if (!(*is_equal) (first_node (list), key)) { if (last_one == NIL_LIST) { last_one = list; list = list_rest (list); result = last_one; set_rest(last_one, NIL_LIST); } else { set_rest(last_one, list); last_one = list; list = list_rest (list); set_rest(last_one, NIL_LIST); } } else { list = pop (list); } } return (result); } LIST delete_d(LIST list, void *key, TessResultCallback2<int, void*, void*>* is_equal) { LIST result = NIL_LIST; LIST last_one = NIL_LIST; while (list != NIL_LIST) { if (!(*is_equal).Run (first_node (list), key)) { if (last_one == NIL_LIST) { last_one = list; list = list_rest (list); result = last_one; set_rest(last_one, NIL_LIST); } else { set_rest(last_one, list); last_one = list; list = list_rest (list); set_rest(last_one, NIL_LIST); } } else { list = pop (list); } } return (result); } /********************************************************************** * d e s t r o y * * Return the space taken by a list to the heap. **********************************************************************/ LIST destroy(LIST list) { LIST next; while (list != NIL_LIST) { next = list_rest (list); free_cell(list); list = next; } return (NIL_LIST); } /********************************************************************** * d e s t r o y n o d e s * * Return the space taken by the LISTs of a list to the heap. **********************************************************************/ void destroy_nodes(LIST list, void_dest destructor) { if (destructor == NULL) destructor = memfree; while (list != NIL_LIST) { (*destructor) (first_node (list)); list = pop (list); } } /********************************************************************** * i n s e r t * * Create a list element and rearange the pointers so that the first * element in the list is the second aurgment. **********************************************************************/ void insert(LIST list, void *node) { LIST element; if (list != NIL_LIST) { element = push (NIL_LIST, node); set_rest (element, list_rest (list)); set_rest(list, element); node = first_node (list); list->node = first_node (list_rest (list)); list->next->node = (LIST) node; } } /********************************************************************** * i s s a m e n o d e * * Compare the list node with the key value return TRUE (non-zero) * if they are equivalent strings. (Return FALSE if not) **********************************************************************/ int is_same_node(void *item1, void *item2) { return (item1 == item2); } /********************************************************************** * i s s a m e * * Compare the list node with the key value return TRUE (non-zero) * if they are equivalent strings. (Return FALSE if not) **********************************************************************/ int is_same(void *item1, void *item2) { return (!strcmp ((char *) item1, (char *) item2)); } /********************************************************************** * j o i n * * Join the two lists together. This function is similar to concat * except that concat creates a new list. This function returns the * first list updated. **********************************************************************/ LIST join(LIST list1, LIST list2) { if (list1 == NIL_LIST) return (list2); set_rest (last (list1), list2); return (list1); } /********************************************************************** * l a s t * * Return the last list item (this is list type). **********************************************************************/ LIST last(LIST var_list) { while (list_rest (var_list) != NIL_LIST) var_list = list_rest (var_list); return (var_list); } /********************************************************************** * n t h c e l l * * Return nth list cell in the list. **********************************************************************/ void *nth_cell(LIST var_list, int item_num) { int x = 0; iterate(var_list) { if (x++ == item_num) return (var_list); } return (var_list); } /********************************************************************** * p o p * * Return the list with the first element removed. Destroy the space * that it occupied in the list. **********************************************************************/ LIST pop(LIST list) { LIST temp; temp = list_rest (list); if (list != NIL_LIST) { free_cell(list); } return (temp); } /********************************************************************** * p u s h * * Create a list element. Push the second parameter (the node) onto * the first parameter (the list). Return the new list to the caller. **********************************************************************/ LIST push(LIST list, void *element) { LIST t; t = new_cell (); t->node = (LIST) element; set_rest(t, list); return (t); } /********************************************************************** * p u s h l a s t * * Create a list element. Add the element onto the end of the list. **********************************************************************/ LIST push_last(LIST list, void *item) { LIST t; if (list != NIL_LIST) { t = last (list); t->next = push (NIL_LIST, item); return (list); } else return (push (NIL_LIST, item)); } /********************************************************************** * r e v e r s e * * Create a new list with the elements reversed. The old list is not * destroyed. **********************************************************************/ LIST reverse(LIST list) { LIST newlist = NIL_LIST; iterate (list) copy_first (list, newlist); return (newlist); } /********************************************************************** * r e v e r s e d * * Create a new list with the elements reversed. The old list is * destroyed. **********************************************************************/ LIST reverse_d(LIST list) { LIST result = reverse (list); destroy(list); return (result); } /********************************************************************** * s a d j o i n * * Adjoin an element to an assorted list. The original list is * modified. Returns the modified list. **********************************************************************/ LIST s_adjoin(LIST var_list, void *variable, int_compare compare) { LIST l; int result; if (compare == NULL) compare = (int_compare) strcmp; l = var_list; iterate(l) { result = (*compare) (variable, first_node (l)); if (result == 0) return (var_list); else if (result < 0) { insert(l, variable); return (var_list); } } return (push_last (var_list, variable)); } /********************************************************************** * s e a r c h * * Search list, return NIL_LIST if not found. Return the list starting from * the item if found. The compare routine "is_equal" is passed in as * the third paramter to this routine. If the value NULL is supplied * for is_equal, the is_key routine will be used. **********************************************************************/ LIST search(LIST list, void *key, int_compare is_equal) { if (is_equal == NULL) is_equal = is_same; iterate (list) if ((*is_equal) (first_node (list), key)) return (list); return (NIL_LIST); } LIST search(LIST list, void *key, TessResultCallback2<int, void*, void*>* is_equal) { iterate (list) if ((*is_equal).Run(first_node (list), key)) return (list); return (NIL_LIST); }