1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 *
26 */
27
28/* $Id: list.c 146 2006-03-24 00:26:54Z njacobs $ */
29
30#pragma ident	"%Z%%M%	%I%	%E% SMI"
31
32/*LINTLIBRARY*/
33
34#include <stdlib.h>
35#include <stdarg.h>
36#include <errno.h>
37
38static int __list_increment = 16;
39
40#define	LIST_SIZE(x)	((((x) / __list_increment) + 1) * __list_increment)
41
42int
43list_append(void ***list, void *item)
44{
45	int count;
46
47	if ((list == NULL) || (item == NULL)) {
48		errno = EINVAL;
49		return (-1);
50	}
51
52	if (item != NULL) {
53		if (*list == NULL)
54			*list = (void **)calloc(__list_increment,
55			    sizeof (void *));
56
57		for (count = 0; (*list)[count] != NULL; count++)
58			;
59
60		if ((count + 1) % __list_increment == 0) { /* expand the list */
61			void **new_list = NULL;
62			int new_size = LIST_SIZE(count + 1);
63
64			new_list = (void **)calloc(new_size, sizeof (void *));
65			if (new_list == NULL)
66				return (-1);
67
68			for (count = 0; (*list)[count] != NULL; count++)
69				new_list[count] = (*list)[count];
70			free(*list);
71			*list = new_list;
72		}
73
74		(*list)[count] = item;
75	}
76
77	return (0);
78}
79
80/*
81 *  list_concatenate() takes in two NULL terminated lists of items (type **)
82 *      and creates a new list with items from list2 appended on the end of
83 *      the list of items from list1.  The result is a list (type **).  If
84 *      there is a failure, -1 is returned.
85 */
86int
87list_concatenate(void ***result, void **list2)
88{
89	void    **list1;
90	int	size1 = 0;
91	int	size2 = 0;
92	int	new_size = 0;
93
94	if ((result == NULL) || ((*result == NULL) && (list2 == NULL))) {
95		errno = EINVAL;
96		return (-1);
97	}
98
99	list1 = *result;
100
101	if (list1 != NULL)
102		for (size1 = 0; list1[size1] != NULL; size1++)
103			;
104	if (list2 != NULL)
105		for (size2 = 0; list2[size2] != NULL; size2++)
106			;
107
108	/* list1 + list2 padded to a multiple of _list_increment */
109	new_size = LIST_SIZE(size1 + size2);
110
111	if ((*result = (void **)calloc((new_size), sizeof (void *))) != NULL) {
112		int count = 0;
113
114		if (list1 != NULL)
115			for (size1 = 0; list1[size1] != NULL; size1++)
116				(*result)[count++] = list1[size1];
117		if (list2 != NULL)
118			for (size2 = 0; list2[size2] != NULL; size2++)
119				(*result)[count++] = list2[size2];
120		free(list1);
121	}
122
123	return (0);
124}
125
126/*
127 *  list_locate() iterates through the list passed in and uses the comparison
128 *      routine and element passed in to find an element in the list.  It
129 *      returns the first element matched, or NULL if none exists
130 */
131void *
132list_locate(void **list, int (*compare)(void *, void *), void *element)
133{
134	int current = 0;
135
136	if ((list != NULL) && (element != NULL))
137		for (current = 0; list[current] != NULL; current++)
138			if ((compare)(list[current], element) == 0)
139				return (list[current]);
140	return (NULL);
141}
142
143void
144list_remove(void ***list, void *item)
145{
146	int i = 0, count;
147
148	if ((list == NULL) || (*list == NULL) || (item == NULL))
149		return;
150
151	/* size the original list */
152	for (count = 0; (*list)[count] != NULL; count++)
153		if ((*list)[count] == item) {	/* mark the location of item */
154			i = count;
155			item = NULL;
156		}
157
158	/* if found, remove it */
159	if (item == NULL) {
160		/* shift the list over the item */
161		for (++i; ((*list)[i] != NULL); i++)
162			(*list)[i-1] = (*list)[i];
163		(*list)[i-1] = NULL;
164	}
165
166	/* if found, removed, and list should shrink, shrink it */
167	if ((item == NULL) && (LIST_SIZE(i) < LIST_SIZE(count))) {
168		void **tmp = (void **)calloc(LIST_SIZE(i), sizeof (void *));
169
170		if (tmp != NULL) {
171			for (i = 0; (*list)[i] != NULL; i++)
172				tmp[i] = (*list)[i];
173			free(*list);
174			*list = tmp;
175		}
176	}
177}
178