1/*	Id	*/
2/*	$NetBSD: list.c,v 1.1.1.1 2016/02/09 20:29:12 plunky Exp $	*/
3
4/*-
5 * Copyright (c) 2014 Iain Hibbert.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26#include <stdarg.h>
27#include <stdio.h>
28#include <stdlib.h>
29
30#include "driver.h"
31
32/*
33 * A list is an opaque collection of strings. We can add strings, another
34 * list or an array of strings to the list. We can get a pointer to the
35 * array of strings in the list and the number of strings in it, and we
36 * can free the entire list when we are done.
37 */
38
39#define COUNT	64		/* element count increments */
40#define BLOCK	4096		/* buffer size increments */
41
42struct list {
43	const char **	array;
44	size_t		arraylen;
45	size_t		arrayused;
46	void *		buf;
47	size_t		buflen;
48	size_t		bufused;
49};
50
51/*
52 * return array pointer
53 */
54const char **
55list_array(const struct list *l)
56{
57
58	return l->array;
59}
60
61/*
62 * return array count
63 */
64size_t
65list_count(const struct list *l)
66{
67
68	return l->arrayused;
69}
70
71/*
72 * allocate a new list header
73 */
74struct list *
75list_alloc(void)
76{
77	struct list *l;
78
79	l = xmalloc(sizeof(struct list));
80	l->array = xmalloc(COUNT * sizeof(char *));
81	l->array[0] = NULL;
82	l->arraylen = COUNT;
83	l->arrayused = 0;
84	l->buf = NULL;
85	l->buflen = 0;
86	l->bufused = 0;
87
88	return l;
89}
90
91/*
92 * release a list header and associated storage
93 */
94void
95list_free(struct list *l)
96{
97
98	free(l->array);
99	free(l->buf);
100	free(l);
101}
102
103/*
104 * print out a list
105 */
106void
107list_print(const struct list *l)
108{
109	size_t i;
110
111	for (i = 0; i < l->arrayused; i++)
112		fprintf(stderr, "%s%s\n", (i == 0 ? "" : " "), l->array[i]);
113}
114
115/*
116 * add const string to list
117 */
118void
119list_add_nocopy(struct list *l, const char *str)
120{
121
122	l->array[l->arrayused++] = str;
123
124	if (l->arrayused == l->arraylen) {
125		l->arraylen += COUNT;
126		l->array = xrealloc(l->array, l->arraylen * sizeof(char *));
127	}
128
129	l->array[l->arrayused] = NULL;
130}
131
132/*
133 * add formatted string to list, storing in list buffer
134 */
135void
136list_add(struct list *l, const char *str, ...)
137{
138	va_list ap;
139	void *p;
140	size_t s;
141	int n;
142
143	for (;;) {
144		p = l->buf + l->bufused;
145		s = l->buflen - l->bufused;
146
147		va_start(ap, str);
148		n = vsnprintf(p, s, str, ap);
149		va_end(ap);
150
151		if (n < 0)
152			error("vsnprintf");
153
154		if ((unsigned int)n < s)
155			break;
156
157		l->buflen += BLOCK;
158		l->buf = xrealloc(l->buf, l->buflen);
159	}
160
161	list_add_nocopy(l, p);
162	l->bufused += n;
163}
164
165/*
166 * add a NULL terminated array of const data to list
167 */
168void
169list_add_array(struct list *l, const char **a)
170{
171
172	while (*a)
173		list_add_nocopy(l, *a++);
174}
175
176/*
177 * add another list to list (with copy)
178 */
179void
180list_add_list(struct list *l1, const struct list *l2)
181{
182	size_t i;
183
184	for (i = 0; i < l2->arrayused; i++)
185		list_add(l1, l2->array[i]);
186}
187