Files
Arquivotheca.SunOS-4.1.4/usr.etc/tfs/libtfs/list.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

701 lines
14 KiB
C

#ifndef lint
static char sccsid[] = "@(#)list.c 1.1 94/10/31 Copyr 1988 Sun Micro";
#endif
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
#include <stdio.h>
#include <nse/types.h>
#include <nse/param.h>
#include "nse_impl/list.h"
#include <nse/util.h>
static Nse_list alloc_listhdr();
/*
* For stat gathering.
*/
static int n_create;
static int n_copy;
static int n_destroy;
/*
* Allocate and return a new element of a list
*/
Nse_listelem
nse_list_create_elem(list)
Nse_list list;
{
Nse_listelem elem;
Nse_opaquefunc create;
create = list->ops->create;
if (create != NULL) {
elem = NSE_NEW(Nse_listelem);
elem->data = create();
} else {
elem = NULL;
}
return elem;
}
/*
* Allocate and return a new element of a list.
* Set its data to that given.
*/
/* VARARGS1 */
Nse_listelem
nse_list_add_new_data(list, data)
Nse_list list;
Nse_opaque data;
{
Nse_listelem elem;
elem = NSE_NEW(Nse_listelem);
elem->data = data;
nse_list_insert_tail(list, elem);
return elem;
}
/*
* Allocate and return a new element of a list.
* Set its data to a copy of that given.
*/
/* VARARGS1 */
Nse_listelem
nse_list_add_new_copy(list, data)
Nse_list list;
Nse_opaque data;
{
Nse_listelem elem;
Nse_opaquefunc copy_func;
copy_func = list->ops->copy;
elem = NSE_NEW(Nse_listelem);
if (copy_func != NULL) {
elem->data = copy_func(data);
}
nse_list_insert_tail(list, elem);
return elem;
}
/*
* Allocate a new element of a list.
* Insert it at the tail of the list.
* Return a pointer to the data, not the listelem.
*/
Nse_opaque
nse_list_add_new_elem(list)
Nse_list list;
{
Nse_listelem listelem;
Nse_opaque data;
data = NULL;
listelem = nse_list_create_elem(list);
if (listelem != NULL) {
nse_list_insert_tail(list, listelem);
data = listelem->data;
}
return data;
}
/*
* Copy a list.
*/
Nse_list
nse_list_copy(list)
Nse_list list;
{
Nse_list newlist;
Nse_listelem newelem;
Nse_listelem elem;
if (!list) {
return NULL;
}
n_copy++;
newlist = nse_list_alloc(list->ops);
for (elem = list->anchor.next; elem != &list->anchor;
elem = elem->next) {
newelem = nse_listelem_copy(newlist, elem);
nse_list_insert_tail(newlist, newelem);
}
return(newlist);
}
/*
* destroy all of the elements of a list.
*/
void
nse_list_clear(list)
Nse_list list;
{
Nse_listelem elem;
Nse_listelem next;
if (!list) {
return;
}
for (elem = list->anchor.next; elem != &list->anchor; elem = next) {
next = elem->next;
nse_listelem_delete(list, elem);
}
}
/*
* Destroy and free the memory associated with a list.
*/
void
nse_list_destroy(list)
Nse_list list;
{
Nse_listelem elem;
Nse_listelem next;
if (!list) {
return;
}
n_destroy++;
for (elem = list->anchor.next; elem != &list->anchor; elem = next) {
next = elem->next;
nse_listelem_destroy(list, elem);
}
NSE_DISPOSE(list);
}
/*
* Destroy and free the memory associated with the structure wrapped around
* the data elements of a list
*/
void
nse_list_destroy_wrapper(list)
Nse_list list;
{
Nse_listelem elem;
Nse_listelem next;
if (!list) {
return;
}
for (elem = list->anchor.next; elem != &list->anchor; elem = next) {
next = elem->next;
nse_listelem_destroy_wrapper(list, elem);
}
NSE_DISPOSE(list);
}
/*
* Print each element of a list.
*/
void
nse_list_print(list)
Nse_list list;
{
Nse_listelem elem;
if (!list) {
printf("(nil)\n");
return;
}
for (elem = list->anchor.next; elem != &list->anchor;
elem = elem->next) {
nse_listelem_print(list, elem);
}
}
/*
* Return a pointer to the first element of a list
*/
Nse_listelem
nse_list_first_elem(list)
Nse_list list;
{
return list->anchor.next;
}
/*
* Return a pointer to the end of the list.
* The end of the list is actually the anchor - not the last
* element.
*/
Nse_listelem
nse_list_end(list)
Nse_list list;
{
return &list->anchor;
}
/*
* Iterate over a list calling a function with a pointer to each
* member of the list.
*/
/* VARARGS1 */
void
nse_list_iterate(list, func, data1, data2, data3, data4, data5)
Nse_list list;
Nse_voidfunc func;
Nse_opaque data1;
Nse_opaque data2;
Nse_opaque data3;
Nse_opaque data4;
Nse_opaque data5;
{
Nse_listelem elem;
for (elem = list->anchor.next; elem != &list->anchor;
elem = elem->next) {
func(elem->data, data1, data2, data3, data4, data5);
}
}
/*
* Iterate over a list calling a function with a pointer to each
* member of the list, stopping at the first non-zero return value.
*/
/* VARARGS1 */
Nse_opaque
nse_list_iterate_or(list, func, data1, data2, data3, data4)
Nse_list list;
Nse_opaquefunc func;
Nse_opaque data1;
Nse_opaque data2;
Nse_opaque data3;
Nse_opaque data4;
{
Nse_listelem elem;
Nse_opaque ret;
ret = (Nse_opaque) 0;
for (elem = list->anchor.next; elem != &list->anchor;
elem = elem->next) {
if (ret = func(elem->data, data1, data2, data3, data4)) {
break;
}
}
return ret;
}
/*
* Search a list by iterating over it and calling the list equal function on
* each member of the list. When the element is found that matches data, stop
* the search and return element pointer of that list element. If no matching
* element is found, return NULL.
*/
Nse_listelem
nse_list_find_elem(list, data)
Nse_list list;
Nse_opaque data;
{
Nse_boolfunc equal_func;
Nse_listelem r;
equal_func = list->ops->equal;
if (equal_func == NULL) {
return NULL;
}
r = nse_list_search_elem(list, equal_func, data);
return r;
}
/*
* Search a list by iterating over it and calling a function with a pointer to
* each member of the list. When the function returns TRUE, stop the search
* and return data pointer of that list element.
*/
/* VARARGS1 */
Nse_opaque
nse_list_search(list, func, data1, data2, data3, data4)
Nse_list list;
Nse_boolfunc func;
Nse_opaque data1;
Nse_opaque data2;
Nse_opaque data3;
Nse_opaque data4;
{
Nse_listelem elem;
elem = nse_list_search_elem(list, func, data1, data2, data3, data4);
if (elem != NULL) {
return elem->data;
} else {
return NULL;
}
}
/*
* Search a list by iterating over it and calling a function
* with a pointer to each member of the list. When the function
* returns TRUE, stop the search and return that list element.
*/
/* VARARGS1 */
Nse_listelem
nse_list_search_elem(list, func, data1, data2, data3, data4)
Nse_list list;
Nse_boolfunc func;
Nse_opaque data1;
Nse_opaque data2;
Nse_opaque data3;
Nse_opaque data4;
{
Nse_listelem elem;
for (elem = list->anchor.next; elem != &list->anchor;
elem = elem->next) {
if (func(elem->data, data1, data2, data3, data4) == TRUE) {
return elem;
}
}
return NULL;
}
/*
* Insert a node at the head of a list.
*/
void
nse_list_insert_head(list, elem)
Nse_list list;
Nse_listelem elem;
{
nse_list_insert_after(list, &list->anchor, elem);
}
/*
* Insert a node at the tail of a list.
*/
void
nse_list_insert_tail(list, elem)
Nse_list list;
Nse_listelem elem;
{
nse_list_insert_after(list, list->anchor.prev, elem);
}
/*
* Insert a node before another node.
*/
void
nse_list_insert_before(list, old, new)
Nse_list list;
Nse_listelem old;
Nse_listelem new;
{
nse_list_insert_after(list, old->prev, new);
}
/*
* Insert a node after another node.
*/
void
nse_list_insert_after(list, old, new)
Nse_list list;
Nse_listelem old;
Nse_listelem new;
{
old->next->prev = new;
new->next = old->next;
old->next = new;
new->prev = old;
list->nelems++;
}
/*
* Return the number of elements in a list.
*/
int
nse_list_nelems(list)
Nse_list list;
{
if (!list) {
return 0;
}
return list->nelems;
}
/*
* Append one list to the end of the other.
* Make sure the lists are of the same type.
* Modifies destlist and destroys srclist.
*/
Nse_list
nse_list_append(destlist, srclist)
Nse_list destlist;
Nse_list srclist;
{
if (srclist->nelems == 0) {
return;
}
destlist->anchor.prev->next = srclist->anchor.next;
srclist->anchor.next->prev = destlist->anchor.prev;
destlist->anchor.prev = srclist->anchor.prev;
srclist->anchor.prev->next = &destlist->anchor;
destlist->nelems += srclist->nelems;
srclist->anchor.prev = &srclist->anchor;
srclist->anchor.next = &srclist->anchor;
srclist->nelems = 0;
nse_list_destroy(srclist);
}
/*
* Compare two lists. Stop when a difference is found and return FALSE.
* Return TRUE if there are no differences.
*/
bool_t
nse_list_cmp(list1, list2)
Nse_list list1;
Nse_list list2;
{
Nse_listelem le1;
Nse_listelem le2;
register int i;
int numelems;
/* TRUE if the same list or both NULL, FALSE if one NULL */
if (list1 == list2) {
return TRUE;
} else if ((!list1) || (!list2)) {
return FALSE;
}
/* first do quick check by checking the number of elements
* in each list.
*/
if ((numelems = nse_list_nelems(list1)) != nse_list_nelems(list2)) {
return(FALSE);
}
le1 = nse_list_first_elem(list1);
le2 = nse_list_first_elem(list2);
for (i = numelems; i ; i--) {
if (!nse_listelem_equal(list1, le1, le2)) {
return(FALSE);
}
le1 = nse_listelem_next(le1);
le2 = nse_listelem_next(le2);
}
return(TRUE);
}
/*
* Produce a list containing the members that are in list1 and not
* in list2.
*/
Nse_list
nse_list_diff(list1, list2)
Nse_list list1;
Nse_list list2;
{
Nse_list diff;
Nse_listelem le1;
Nse_listelem le2;
Nse_listelem listelem;
Nse_listelem stop1;
Nse_listelem stop2;
diff = nse_list_alloc(list1->ops);
stop1 = nse_list_end(list1);
for (le1 = nse_list_first_elem(list1); le1 != stop1;
le1 = nse_listelem_next(le1)) {
stop2 = nse_list_end(list2);
for (le2 = nse_list_first_elem(list2); le2 != stop2;
le2 = nse_listelem_next(le2)) {
if (nse_listelem_equal(list1, le1, le2)) {
break;
}
}
if (le2 == stop2) {
listelem = nse_listelem_copy(list1, le1);
nse_list_insert_tail(diff, listelem);
}
}
return diff;
}
/*
* Produce a list that is the union of the members of list1 and list2.
*/
Nse_list
nse_list_union(list1, list2)
Nse_list list1;
Nse_list list2;
{
Nse_list either;
Nse_list more;
either = nse_list_copy(list1);
more = nse_list_diff(list2, list1);
nse_list_append(either, more);
return either;
}
/*
* Produce a list that is intersection union of the members of list1 and list2.
*/
Nse_list
nse_list_intersection(list1, list2)
Nse_list list1;
Nse_list list2;
{
Nse_list intersection;
Nse_listelem le1;
Nse_listelem le2;
Nse_listelem listelem;
Nse_listelem stop1;
Nse_listelem stop2;
intersection = nse_list_alloc(list1->ops);
stop1 = nse_list_end(list1);
for (le1 = nse_list_first_elem(list1); le1 != stop1;
le1 = nse_listelem_next(le1)) {
stop2 = nse_list_end(list2);
for (le2 = nse_list_first_elem(list2); le2 != stop2;
le2 = nse_listelem_next(le2)) {
if (nse_listelem_equal(list1, le1, le2)) {
listelem = nse_listelem_copy(list1, le1);
nse_list_insert_tail(intersection, listelem);
break;
}
}
}
return intersection;
}
/*
* Produce a list that is the contents of both list1 and list2.
*/
Nse_list
nse_list_add(list1, list2)
Nse_list list1;
Nse_list list2;
{
Nse_list add;
Nse_list tmp;
add = nse_list_copy(list1);
tmp = nse_list_copy(list2);
nse_list_append(add, tmp);
return add;
}
/*
* Sort a list. Uses qsort(). Allocate buffer large enough
* to hold a pointer to each listelem. Call qsort() and use
* the given comparision function. Then rebuild the list.
*/
void
nse_list_sort(list, compare)
Nse_list list;
Nse_intfunc compare;
{
Nse_listelem le;
Nse_listelem next;
Nse_listelem *argv;
int i, j;
if (list == NULL) {
return;
}
argv = (Nse_listelem *) malloc((unsigned)
(sizeof(Nse_listelem) * list->nelems));
i = 0;
for (le = list->anchor.next; le != &list->anchor; le = next) {
next = le->next;
argv[i] = le;
nse_listelem_remove(list, le);
i++;
}
qsort((char *) argv, i, sizeof(Nse_listelem), compare);
for (j = 0; j < i; j++) {
nse_list_insert_tail(list, argv[j]);
}
}
/*
* Allocate the memory for a listhdr, find its type and initialized
* the type and ops fields.
*/
Nse_list
nse_list_alloc(ops)
Nse_listops ops;
{
Nse_list list;
n_create++;
list = alloc_listhdr();
list->ops = ops;
return list;
}
/*
* Allocate the memory for listhdr and connect the anchor to itself.
*/
static Nse_list
alloc_listhdr()
{
Nse_list list;
list = NSE_NEW(Nse_list);
list->anchor.next = &list->anchor;
list->anchor.prev = &list->anchor;
return list;
}
/*
* Generic routine for printing out stats about a list.
* Gives total number of elements, the number of bytes occupied by
* the elements, the number of bytes private to the data structure
* (strings for instances), and the amount of list overhead.
*/
void
nse_list_print_stats(fp, list, sizeof_elem, func, str)
FILE *fp;
Nse_list list;
int sizeof_elem;
Nse_intfunc func;
char *str;
{
Nse_listelem le;
Nse_listelem stop;
Nse_opaque data;
int n;
int data_bytes;
int private_bytes;
int list_bytes;
if (list == NULL) {
return;
}
n = list->nelems;
fprintf(fp, "\n");
fprintf(fp, "%s\n", str);
fprintf(fp, "\t%-20s %5d\n", "# elements in list", n);
data_bytes = sizeof_elem * n;
fprintf(fp, "\t%-20s %5d\n", "bytes in list data", data_bytes);
private_bytes = 0;
NSE_LIST_ITERATE(list, Nse_opaque, data, le, stop) {
private_bytes += func(data);
}
fprintf(fp, "\t%-20s %5d\n", "data-specific bytes", private_bytes);
list_bytes = n * sizeof(Nse_listelem_rec) + sizeof(Nse_list_rec);
fprintf(fp, "\t%-20s %5d\n", "list overhead", list_bytes);
fprintf(fp, "\t%-20s %5d\n", "total bytes",
data_bytes + private_bytes + list_bytes);
}
/*
* Print stats about the usage of lists.
*/
void
nse_list_print_cnt_stats(fp)
FILE *fp;
{
fprintf(fp, "\n");
fprintf(fp, "Nse_lists (%d bytes each):\n", sizeof(Nse_list));
fprintf(fp, "\t%-20s %5d\n", "creates", n_create);
fprintf(fp, "\t%-20s %5d\n", "copies", n_copy);
fprintf(fp, "\t%-20s %5d\n", "destroys", n_destroy);
}