2007-03-08 04:03:40 +08:00
|
|
|
/* -*-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
|
2010-11-24 02:34:14 +08:00
|
|
|
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
|
2007-03-08 04:03:40 +08:00
|
|
|
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);
|
2007-05-16 09:38:45 +08:00
|
|
|
first_node to access the head name = (char *) first_node (l);
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
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);
|
2007-05-16 09:38:45 +08:00
|
|
|
first_node to access the head name = (char *) first_node (l);
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
To implement LISP like functions use:
|
|
|
|
|
2007-05-16 09:38:45 +08:00
|
|
|
first_node CAR x = (int) first_node (l);
|
2010-11-24 02:34:14 +08:00
|
|
|
rest CDR l = list_rest (l);
|
2007-03-08 04:03:40 +08:00
|
|
|
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.
|
2007-05-16 09:38:45 +08:00
|
|
|
a = first_node (push (a, b))
|
2010-11-24 02:34:14 +08:00
|
|
|
b = list_rest (push (a, b))
|
|
|
|
a = push (pop (a), a)) For all a <> NIL_LIST
|
2007-03-08 04:03:40 +08:00
|
|
|
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
|
|
|
|
----------------------------------------------------------------------*/
|
2007-05-16 09:38:45 +08:00
|
|
|
#define add_on(l,x) l = push (l,first_node (x))
|
2010-11-24 02:34:14 +08:00
|
|
|
#define next_one(l) l = list_rest (l)
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
|
|
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) {
|
2010-11-24 02:34:14 +08:00
|
|
|
LIST result = NIL_LIST;
|
|
|
|
LIST last_one = NIL_LIST;
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
if (is_equal == NULL)
|
|
|
|
is_equal = is_same;
|
|
|
|
|
2010-11-24 02:34:14 +08:00
|
|
|
while (list != NIL_LIST) {
|
2007-05-16 09:38:45 +08:00
|
|
|
if (!(*is_equal) (first_node (list), key)) {
|
2010-11-24 02:34:14 +08:00
|
|
|
if (last_one == NIL_LIST) {
|
2007-03-08 04:03:40 +08:00
|
|
|
last_one = list;
|
2010-11-24 02:34:14 +08:00
|
|
|
list = list_rest (list);
|
2007-03-08 04:03:40 +08:00
|
|
|
result = last_one;
|
2010-11-24 02:34:14 +08:00
|
|
|
set_rest(last_one, NIL_LIST);
|
2007-03-08 04:03:40 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
set_rest(last_one, list);
|
|
|
|
last_one = list;
|
2010-11-24 02:34:14 +08:00
|
|
|
list = list_rest (list);
|
|
|
|
set_rest(last_one, NIL_LIST);
|
2007-03-08 04:03:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
list = pop (list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2009-07-11 10:19:04 +08:00
|
|
|
LIST delete_d(LIST list, void *key,
|
2010-11-24 02:34:14 +08:00
|
|
|
TessResultCallback2<int, void*, void*>* is_equal) {
|
|
|
|
LIST result = NIL_LIST;
|
|
|
|
LIST last_one = NIL_LIST;
|
2009-07-11 10:19:04 +08:00
|
|
|
|
2010-11-24 02:34:14 +08:00
|
|
|
while (list != NIL_LIST) {
|
2009-07-11 10:19:04 +08:00
|
|
|
if (!(*is_equal).Run (first_node (list), key)) {
|
2010-11-24 02:34:14 +08:00
|
|
|
if (last_one == NIL_LIST) {
|
2009-07-11 10:19:04 +08:00
|
|
|
last_one = list;
|
2010-11-24 02:34:14 +08:00
|
|
|
list = list_rest (list);
|
2009-07-11 10:19:04 +08:00
|
|
|
result = last_one;
|
2010-11-24 02:34:14 +08:00
|
|
|
set_rest(last_one, NIL_LIST);
|
2009-07-11 10:19:04 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
set_rest(last_one, list);
|
|
|
|
last_one = list;
|
2010-11-24 02:34:14 +08:00
|
|
|
list = list_rest (list);
|
|
|
|
set_rest(last_one, NIL_LIST);
|
2009-07-11 10:19:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
list = pop (list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* d e s t r o y
|
|
|
|
*
|
|
|
|
* Return the space taken by a list to the heap.
|
|
|
|
**********************************************************************/
|
|
|
|
LIST destroy(LIST list) {
|
|
|
|
LIST next;
|
|
|
|
|
2010-11-24 02:34:14 +08:00
|
|
|
while (list != NIL_LIST) {
|
|
|
|
next = list_rest (list);
|
2007-03-08 04:03:40 +08:00
|
|
|
free_cell(list);
|
|
|
|
list = next;
|
|
|
|
}
|
2010-11-24 02:34:14 +08:00
|
|
|
return (NIL_LIST);
|
2007-03-08 04:03:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* 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;
|
|
|
|
|
2010-11-24 02:34:14 +08:00
|
|
|
while (list != NIL_LIST) {
|
2007-05-16 09:38:45 +08:00
|
|
|
(*destructor) (first_node (list));
|
2007-03-08 04:03:40 +08:00
|
|
|
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;
|
|
|
|
|
2010-11-24 02:34:14 +08:00
|
|
|
if (list != NIL_LIST) {
|
|
|
|
element = push (NIL_LIST, node);
|
|
|
|
set_rest (element, list_rest (list));
|
2007-03-08 04:03:40 +08:00
|
|
|
set_rest(list, element);
|
2007-05-16 09:38:45 +08:00
|
|
|
node = first_node (list);
|
2010-11-24 02:34:14 +08:00
|
|
|
list->node = first_node (list_rest (list));
|
2007-03-08 04:03:40 +08:00
|
|
|
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) {
|
2010-11-24 02:34:14 +08:00
|
|
|
if (list1 == NIL_LIST)
|
2007-03-08 04:03:40 +08:00
|
|
|
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) {
|
2010-11-24 02:34:14 +08:00
|
|
|
while (list_rest (var_list) != NIL_LIST)
|
|
|
|
var_list = list_rest (var_list);
|
2007-03-08 04:03:40 +08:00
|
|
|
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;
|
|
|
|
|
2010-11-24 02:34:14 +08:00
|
|
|
temp = list_rest (list);
|
2007-03-08 04:03:40 +08:00
|
|
|
|
2010-11-24 02:34:14 +08:00
|
|
|
if (list != NIL_LIST) {
|
2007-03-08 04:03:40 +08:00
|
|
|
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;
|
|
|
|
|
2010-11-24 02:34:14 +08:00
|
|
|
if (list != NIL_LIST) {
|
2007-03-08 04:03:40 +08:00
|
|
|
t = last (list);
|
2010-11-24 02:34:14 +08:00
|
|
|
t->next = push (NIL_LIST, item);
|
2007-03-08 04:03:40 +08:00
|
|
|
return (list);
|
|
|
|
}
|
|
|
|
else
|
2010-11-24 02:34:14 +08:00
|
|
|
return (push (NIL_LIST, item));
|
2007-03-08 04:03:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* 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) {
|
2010-11-24 02:34:14 +08:00
|
|
|
LIST newlist = NIL_LIST;
|
2007-03-08 04:03:40 +08:00
|
|
|
|
|
|
|
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) {
|
2007-05-16 09:38:45 +08:00
|
|
|
result = (*compare) (variable, first_node (l));
|
2007-03-08 04:03:40 +08:00
|
|
|
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
|
|
|
|
*
|
2010-11-24 02:34:14 +08:00
|
|
|
* Search list, return NIL_LIST if not found. Return the list starting from
|
2007-03-08 04:03:40 +08:00
|
|
|
* 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;
|
|
|
|
|
2007-05-16 09:38:45 +08:00
|
|
|
iterate (list) if ((*is_equal) (first_node (list), key))
|
2007-03-08 04:03:40 +08:00
|
|
|
return (list);
|
2010-11-24 02:34:14 +08:00
|
|
|
return (NIL_LIST);
|
2007-03-08 04:03:40 +08:00
|
|
|
}
|
2009-07-11 10:19:04 +08:00
|
|
|
|
2010-11-24 02:34:14 +08:00
|
|
|
LIST search(LIST list, void *key, TessResultCallback2<int, void*, void*>* is_equal) {
|
2009-07-11 10:19:04 +08:00
|
|
|
iterate (list) if ((*is_equal).Run(first_node (list), key))
|
|
|
|
return (list);
|
2010-11-24 02:34:14 +08:00
|
|
|
return (NIL_LIST);
|
2009-07-11 10:19:04 +08:00
|
|
|
}
|