xref: /netbsd-src/sys/lib/libkern/strlist.c (revision 6ed8189e161d2dee3538e9b076adc711e4cef98f)
1*6ed8189eSmrg /*	$NetBSD: strlist.c,v 1.3 2023/08/11 07:05:39 mrg Exp $	*/
2fa320c3fSthorpej 
3fa320c3fSthorpej /*-
4fa320c3fSthorpej  * Copyright (c) 2021 The NetBSD Foundation, Inc.
5fa320c3fSthorpej  * All rights reserved.
6fa320c3fSthorpej  *
7fa320c3fSthorpej  * This code is derived from software contributed to The NetBSD Foundation
8fa320c3fSthorpej  * by Jason R. Thorpe.
9fa320c3fSthorpej  *
10fa320c3fSthorpej  * Redistribution and use in source and binary forms, with or without
11fa320c3fSthorpej  * modification, are permitted provided that the following conditions
12fa320c3fSthorpej  * are met:
13fa320c3fSthorpej  * 1. Redistributions of source code must retain the above copyright
14fa320c3fSthorpej  *    notice, this list of conditions and the following disclaimer.
15fa320c3fSthorpej  * 2. Redistributions in binary form must reproduce the above copyright
16fa320c3fSthorpej  *    notice, this list of conditions and the following disclaimer in the
17fa320c3fSthorpej  *    documentation and/or other materials provided with the distribution.
18fa320c3fSthorpej  *
19fa320c3fSthorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20fa320c3fSthorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21fa320c3fSthorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22fa320c3fSthorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23fa320c3fSthorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24fa320c3fSthorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25fa320c3fSthorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26fa320c3fSthorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27fa320c3fSthorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28fa320c3fSthorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29fa320c3fSthorpej  * POSSIBILITY OF SUCH DAMAGE.
30fa320c3fSthorpej  */
31fa320c3fSthorpej 
32fa320c3fSthorpej /*
33fa320c3fSthorpej  * strlist --
34fa320c3fSthorpej  *
35fa320c3fSthorpej  *	A set of routines for interacting with IEEE 1275 (OpenFirmware)
36fa320c3fSthorpej  *	style string lists.
37fa320c3fSthorpej  *
38fa320c3fSthorpej  *	An OpenFirmware string list is simply a buffer containing
39fa320c3fSthorpej  *	multiple NUL-terminated strings concatenated together.
40fa320c3fSthorpej  *
41fa320c3fSthorpej  *	So, for example, the a string list consisting of the strings
42fa320c3fSthorpej  *	"foo", "bar", and "baz" would be represented in memory like:
43fa320c3fSthorpej  *
44fa320c3fSthorpej  *		foo\0bar\0baz\0
45fa320c3fSthorpej  */
46fa320c3fSthorpej 
47fa320c3fSthorpej #include <sys/types.h>
48fa320c3fSthorpej 
49fa320c3fSthorpej /*
50fa320c3fSthorpej  * Memory allocation wrappers to handle different environments.
51fa320c3fSthorpej  */
52fa320c3fSthorpej #if defined(_KERNEL)
53fa320c3fSthorpej #include <sys/kmem.h>
54fa320c3fSthorpej #include <sys/systm.h>
55fa320c3fSthorpej 
56fa320c3fSthorpej static void *
strlist_alloc(size_t const size)57fa320c3fSthorpej strlist_alloc(size_t const size)
58fa320c3fSthorpej {
59fa320c3fSthorpej 	return kmem_zalloc(size, KM_SLEEP);
60fa320c3fSthorpej }
61fa320c3fSthorpej 
62fa320c3fSthorpej static void
strlist_free(void * const v,size_t const size)63fa320c3fSthorpej strlist_free(void * const v, size_t const size)
64fa320c3fSthorpej {
65fa320c3fSthorpej 	kmem_free(v, size);
66fa320c3fSthorpej }
67fa320c3fSthorpej #elif defined(_STANDALONE)
6858b41725Sthorpej #include <lib/libkern/libkern.h>
69fa320c3fSthorpej #include <lib/libsa/stand.h>
70fa320c3fSthorpej 
71fa320c3fSthorpej static void *
strlist_alloc(size_t const size)72fa320c3fSthorpej strlist_alloc(size_t const size)
73fa320c3fSthorpej {
7458b41725Sthorpej 	char *cp = alloc(size);
75fa320c3fSthorpej 	if (cp != NULL) {
76fa320c3fSthorpej 		memset(cp, 0, size);
77fa320c3fSthorpej 	}
78fa320c3fSthorpej 	return cp;
79fa320c3fSthorpej }
80fa320c3fSthorpej 
81fa320c3fSthorpej static void
strlist_free(void * const v,size_t const size)82fa320c3fSthorpej strlist_free(void * const v, size_t const size)
83fa320c3fSthorpej {
84fa320c3fSthorpej 	dealloc(v, size);
85fa320c3fSthorpej }
86fa320c3fSthorpej #else /* user-space */
87fa320c3fSthorpej #include <stdlib.h>
88fa320c3fSthorpej #include <string.h>
89fa320c3fSthorpej 
90fa320c3fSthorpej extern int pmatch(const char *, const char *, const char **);
91fa320c3fSthorpej 
92fa320c3fSthorpej static void *
strlist_alloc(size_t const size)93fa320c3fSthorpej strlist_alloc(size_t const size)
94fa320c3fSthorpej {
95fa320c3fSthorpej 	return calloc(1, size);
96fa320c3fSthorpej }
97fa320c3fSthorpej 
98fa320c3fSthorpej static void
strlist_free(void * const v,size_t const size __unused)99fa320c3fSthorpej strlist_free(void * const v, size_t const size __unused)
100fa320c3fSthorpej {
101fa320c3fSthorpej 	free(v);
102fa320c3fSthorpej }
103fa320c3fSthorpej #endif
104fa320c3fSthorpej 
105fa320c3fSthorpej #include "strlist.h"
106fa320c3fSthorpej 
107fa320c3fSthorpej /*
108fa320c3fSthorpej  * strlist_next --
109fa320c3fSthorpej  *
110fa320c3fSthorpej  *	Return a pointer to the next string in the strlist,
111fa320c3fSthorpej  *	or NULL if there are no more strings.
112fa320c3fSthorpej  */
113fa320c3fSthorpej const char *
strlist_next(const char * const sl,size_t const slsize,size_t * const cursorp)114fa320c3fSthorpej strlist_next(const char * const sl, size_t const slsize, size_t * const cursorp)
115fa320c3fSthorpej {
116fa320c3fSthorpej 
117fa320c3fSthorpej 	if (sl == NULL || slsize == 0 || cursorp == NULL) {
118fa320c3fSthorpej 		return NULL;
119fa320c3fSthorpej 	}
120fa320c3fSthorpej 
121fa320c3fSthorpej 	size_t cursor = *cursorp;
122fa320c3fSthorpej 
123fa320c3fSthorpej 	if (cursor >= slsize) {
124fa320c3fSthorpej 		/* No more strings in the list. */
125fa320c3fSthorpej 		return NULL;
126fa320c3fSthorpej 	}
127fa320c3fSthorpej 
128fa320c3fSthorpej 	const char *cp = sl + cursor;
129fa320c3fSthorpej 	*cursorp = cursor + strlen(cp) + 1;
130fa320c3fSthorpej 
131fa320c3fSthorpej 	return cp;
132fa320c3fSthorpej }
133fa320c3fSthorpej 
134fa320c3fSthorpej /*
135fa320c3fSthorpej  * strlist_count --
136fa320c3fSthorpej  *
137fa320c3fSthorpej  *	Return the number of strings in the strlist.
138fa320c3fSthorpej  */
139fa320c3fSthorpej unsigned int
strlist_count(const char * sl,size_t slsize)140fa320c3fSthorpej strlist_count(const char *sl, size_t slsize)
141fa320c3fSthorpej {
142fa320c3fSthorpej 
143fa320c3fSthorpej 	if (sl == NULL || slsize == 0) {
144fa320c3fSthorpej 		return 0;
145fa320c3fSthorpej 	}
146fa320c3fSthorpej 
147fa320c3fSthorpej 	size_t cursize;
148fa320c3fSthorpej 	unsigned int count;
149fa320c3fSthorpej 
150fa320c3fSthorpej 	for (count = 0; slsize != 0;
151fa320c3fSthorpej 	     count++, sl += cursize, slsize -= cursize) {
152fa320c3fSthorpej 		cursize = strlen(sl) + 1;
153fa320c3fSthorpej 	}
154fa320c3fSthorpej 	return count;
155fa320c3fSthorpej }
156fa320c3fSthorpej 
157fa320c3fSthorpej /*
158fa320c3fSthorpej  * strlist_string --
159fa320c3fSthorpej  *
160fa320c3fSthorpej  *	Returns the string in the strlist at the specified index.
161fa320c3fSthorpej  *	Returns NULL if the index is beyond the strlist range.
162fa320c3fSthorpej  */
163fa320c3fSthorpej const char *
strlist_string(const char * sl,size_t slsize,unsigned int const idx)164fa320c3fSthorpej strlist_string(const char * sl, size_t slsize, unsigned int const idx)
165fa320c3fSthorpej {
166fa320c3fSthorpej 
167fa320c3fSthorpej 	if (sl == NULL || slsize == 0) {
168fa320c3fSthorpej 		return NULL;
169fa320c3fSthorpej 	}
170fa320c3fSthorpej 
171fa320c3fSthorpej 	size_t cursize;
172fa320c3fSthorpej 	unsigned int i;
173fa320c3fSthorpej 
174fa320c3fSthorpej 	for (i = 0; slsize != 0; i++, slsize -= cursize, sl += cursize) {
175fa320c3fSthorpej 		cursize = strlen(sl) + 1;
176fa320c3fSthorpej 		if (i == idx) {
177fa320c3fSthorpej 			return sl;
178fa320c3fSthorpej 		}
179fa320c3fSthorpej 	}
180fa320c3fSthorpej 
181fa320c3fSthorpej 	return NULL;
182fa320c3fSthorpej }
183fa320c3fSthorpej 
184fa320c3fSthorpej static bool
match_strcmp(const char * const s1,const char * const s2)185fa320c3fSthorpej match_strcmp(const char * const s1, const char * const s2)
186fa320c3fSthorpej {
187fa320c3fSthorpej 	return strcmp(s1, s2) == 0;
188fa320c3fSthorpej }
189fa320c3fSthorpej 
190fa320c3fSthorpej #if !defined(_STANDALONE)
191fa320c3fSthorpej static bool
match_pmatch(const char * const s1,const char * const s2)192fa320c3fSthorpej match_pmatch(const char * const s1, const char * const s2)
193fa320c3fSthorpej {
194fa320c3fSthorpej 	return pmatch(s1, s2, NULL) == 2;
195fa320c3fSthorpej }
196fa320c3fSthorpej #endif /* _STANDALONE */
197fa320c3fSthorpej 
198fa320c3fSthorpej static bool
strlist_match_internal(const char * const sl,size_t slsize,const char * const str,int * const indexp,unsigned int * const countp,bool (* match_fn)(const char *,const char *))199fa320c3fSthorpej strlist_match_internal(const char * const sl, size_t slsize,
200fa320c3fSthorpej     const char * const str, int * const indexp, unsigned int * const countp,
201fa320c3fSthorpej     bool (*match_fn)(const char *, const char *))
202fa320c3fSthorpej {
203fa320c3fSthorpej 	const char *cp;
204fa320c3fSthorpej 	size_t l;
205fa320c3fSthorpej 	int i;
206fa320c3fSthorpej 	bool rv = false;
207fa320c3fSthorpej 
208fa320c3fSthorpej 	if (sl == NULL || slsize == 0) {
209fa320c3fSthorpej 		return false;
210fa320c3fSthorpej 	}
211fa320c3fSthorpej 
212fa320c3fSthorpej 	cp = sl;
213fa320c3fSthorpej 
214fa320c3fSthorpej 	for (i = 0; slsize != 0;
215fa320c3fSthorpej 	     l = strlen(cp) + 1, slsize -= l, cp += l, i++) {
216fa320c3fSthorpej 		if (rv) {
217fa320c3fSthorpej 			/*
218fa320c3fSthorpej 			 * We've already matched. We must be
219fa320c3fSthorpej 			 * counting to the end.
220fa320c3fSthorpej 			 */
221fa320c3fSthorpej 			continue;
222fa320c3fSthorpej 		}
223fa320c3fSthorpej 		if ((*match_fn)(cp, str)) {
224fa320c3fSthorpej 			/*
225fa320c3fSthorpej 			 * Matched!  Get the index.  If we don't
226fa320c3fSthorpej 			 * also want the total count, then get
227fa320c3fSthorpej 			 * out early.
228fa320c3fSthorpej 			 */
229fa320c3fSthorpej 			*indexp = i;
230fa320c3fSthorpej 			rv = true;
231fa320c3fSthorpej 			if (countp == NULL) {
232fa320c3fSthorpej 				break;
233fa320c3fSthorpej 			}
234fa320c3fSthorpej 		}
235fa320c3fSthorpej 	}
236fa320c3fSthorpej 
237fa320c3fSthorpej 	if (countp != NULL) {
238fa320c3fSthorpej 		*countp = i;
239fa320c3fSthorpej 	}
240fa320c3fSthorpej 
241fa320c3fSthorpej 	return rv;
242fa320c3fSthorpej }
243fa320c3fSthorpej 
244fa320c3fSthorpej /*
245fa320c3fSthorpej  * strlist_match --
246fa320c3fSthorpej  *
247fa320c3fSthorpej  *	Returns a weighted match value (1 <= match <= sl->count) if the
248fa320c3fSthorpej  *	specified string appears in the strlist.  A match at the
249fa320c3fSthorpej  *	beginning of the list carriest the greatest weight (i.e. sl->count)
250fa320c3fSthorpej  *	and a match at the end of the list carriest the least (i.e. 1).
251fa320c3fSthorpej  *	Returns 0 if there is no match.
252fa320c3fSthorpej  *
253fa320c3fSthorpej  *	This routine operates independently of the cursor used to enumerate
254fa320c3fSthorpej  *	a strlist.
255fa320c3fSthorpej  */
256fa320c3fSthorpej int
strlist_match(const char * const sl,size_t const slsize,const char * const str)257fa320c3fSthorpej strlist_match(const char * const sl, size_t const slsize,
258fa320c3fSthorpej     const char * const str)
259fa320c3fSthorpej {
260fa320c3fSthorpej 	unsigned int count;
261*6ed8189eSmrg 	int idx = 0 /* XXXGCC 12 */;
262fa320c3fSthorpej 
263fa320c3fSthorpej 	if (strlist_match_internal(sl, slsize, str, &idx, &count,
264fa320c3fSthorpej 				   match_strcmp)) {
265fa320c3fSthorpej 		return count - idx;
266fa320c3fSthorpej 	}
267fa320c3fSthorpej 	return 0;
268fa320c3fSthorpej }
269fa320c3fSthorpej 
270fa320c3fSthorpej #if !defined(_STANDALONE)
271fa320c3fSthorpej /*
272fa320c3fSthorpej  * strlist_pmatch --
273fa320c3fSthorpej  *
274fa320c3fSthorpej  *	Like strlist_match(), but uses pmatch(9) to match the
275fa320c3fSthorpej  *	strings.
276fa320c3fSthorpej  */
277fa320c3fSthorpej int
strlist_pmatch(const char * const sl,size_t const slsize,const char * const pattern)278fa320c3fSthorpej strlist_pmatch(const char * const sl, size_t const slsize,
279fa320c3fSthorpej     const char * const pattern)
280fa320c3fSthorpej {
281fa320c3fSthorpej 	unsigned int count;
282*6ed8189eSmrg 	int idx = 0; /* XXXGCC12 */
283fa320c3fSthorpej 
284fa320c3fSthorpej 	if (strlist_match_internal(sl, slsize, pattern, &idx, &count,
285fa320c3fSthorpej 				   match_pmatch)) {
286fa320c3fSthorpej 		return count - idx;
287fa320c3fSthorpej 	}
288fa320c3fSthorpej 	return 0;
289fa320c3fSthorpej }
290fa320c3fSthorpej #endif /* _STANDALONE */
291fa320c3fSthorpej 
292fa320c3fSthorpej /*
293fa320c3fSthorpej  * strlist_index --
294fa320c3fSthorpej  *
295fa320c3fSthorpej  *	Returns the index of the specified string if it appears
296fa320c3fSthorpej  *	in the strlist.  Returns -1 if the string is not found.
297fa320c3fSthorpej  *
298fa320c3fSthorpej  *	This routine operates independently of the cursor used to enumerate
299fa320c3fSthorpej  *	a strlist.
300fa320c3fSthorpej  */
301fa320c3fSthorpej int
strlist_index(const char * const sl,size_t const slsize,const char * const str)302fa320c3fSthorpej strlist_index(const char * const sl, size_t const slsize,
303fa320c3fSthorpej     const char * const str)
304fa320c3fSthorpej {
305fa320c3fSthorpej 	int idx;
306fa320c3fSthorpej 
307fa320c3fSthorpej 	if (strlist_match_internal(sl, slsize, str, &idx, NULL,
308fa320c3fSthorpej 				   match_strcmp)) {
309fa320c3fSthorpej 		return idx;
310fa320c3fSthorpej 	}
311fa320c3fSthorpej 	return -1;
312fa320c3fSthorpej }
313fa320c3fSthorpej 
314fa320c3fSthorpej /*
315fa320c3fSthorpej  * strlist_append --
316fa320c3fSthorpej  *
317fa320c3fSthorpej  *	Append the specified string to a mutable strlist.  Turns
318fa320c3fSthorpej  *	true if successful, false upon failure for any reason.
319fa320c3fSthorpej  */
320fa320c3fSthorpej bool
strlist_append(char ** const slp,size_t * const slsizep,const char * const str)321fa320c3fSthorpej strlist_append(char ** const slp, size_t * const slsizep,
322fa320c3fSthorpej     const char * const str)
323fa320c3fSthorpej {
324fa320c3fSthorpej 	size_t const slsize = *slsizep;
325fa320c3fSthorpej 	char * const sl = *slp;
326fa320c3fSthorpej 
327fa320c3fSthorpej 	size_t const addsize = strlen(str) + 1;
328fa320c3fSthorpej 	size_t const newsize = slsize + addsize;
329fa320c3fSthorpej 	char * const newbuf = strlist_alloc(newsize);
330fa320c3fSthorpej 
331fa320c3fSthorpej 	if (newbuf == NULL) {
332fa320c3fSthorpej 		return false;
333fa320c3fSthorpej 	}
334fa320c3fSthorpej 
335fa320c3fSthorpej 	if (sl != NULL) {
336fa320c3fSthorpej 		memcpy(newbuf, sl, slsize);
337fa320c3fSthorpej 	}
338fa320c3fSthorpej 
339fa320c3fSthorpej 	memcpy(newbuf + slsize, str, addsize);
340fa320c3fSthorpej 
341fa320c3fSthorpej 	if (sl != NULL) {
342fa320c3fSthorpej 		strlist_free(sl, slsize);
343fa320c3fSthorpej 	}
344fa320c3fSthorpej 
345fa320c3fSthorpej 	*slp = newbuf;
346fa320c3fSthorpej 	*slsizep = newsize;
347fa320c3fSthorpej 
348fa320c3fSthorpej 	return true;
349fa320c3fSthorpej }
350fa320c3fSthorpej 
351fa320c3fSthorpej #ifdef STRLIST_TEST
352fa320c3fSthorpej /*
353fa320c3fSthorpej  * To build and run the tests:
354fa320c3fSthorpej  *
355fa320c3fSthorpej  * % cc -DSTRLIST_TEST -Os pmatch.c strlist.c
356fa320c3fSthorpej  * % ./a.out
357fa320c3fSthorpej  * Testing basic properties.
358fa320c3fSthorpej  * Testing enumeration.
359fa320c3fSthorpej  * Testing weighted matching.
360fa320c3fSthorpej  * Testing pattern matching.
361fa320c3fSthorpej  * Testing index return.
362fa320c3fSthorpej  * Testing string-at-index.
363fa320c3fSthorpej  * Testing gross blob count.
364fa320c3fSthorpej  * Testing gross blob indexing.
365fa320c3fSthorpej  * Testing creating a strlist.
366fa320c3fSthorpej  * Verifying new strlist.
367fa320c3fSthorpej  * All tests completed successfully.
368fa320c3fSthorpej  * %
369fa320c3fSthorpej  */
370fa320c3fSthorpej 
371fa320c3fSthorpej static char nice_blob[] = "zero\0one\0two\0three\0four\0five";
372fa320c3fSthorpej static char gross_blob[] = "zero\0\0two\0\0four\0\0";
373fa320c3fSthorpej 
374fa320c3fSthorpej #include <assert.h>
375fa320c3fSthorpej #include <stdio.h>
376fa320c3fSthorpej 
377fa320c3fSthorpej int
main(int argc,char * argv[])378fa320c3fSthorpej main(int argc, char *argv[])
379fa320c3fSthorpej {
380fa320c3fSthorpej 	const char *sl;
381fa320c3fSthorpej 	size_t slsize;
382fa320c3fSthorpej 	size_t cursor;
383fa320c3fSthorpej 	const char *cp;
384fa320c3fSthorpej 	size_t size;
385fa320c3fSthorpej 
386fa320c3fSthorpej 	sl = nice_blob;
387fa320c3fSthorpej 	slsize = sizeof(nice_blob);
388fa320c3fSthorpej 
389fa320c3fSthorpej 	printf("Testing basic properties.\n");
390fa320c3fSthorpej 	assert(strlist_count(sl, slsize) == 6);
391fa320c3fSthorpej 
392fa320c3fSthorpej 	printf("Testing enumeration.\n");
393fa320c3fSthorpej 	cursor = 0;
394fa320c3fSthorpej 	assert((cp = strlist_next(sl, slsize, &cursor)) != NULL);
395fa320c3fSthorpej 	assert(strcmp(cp, "zero") == 0);
396fa320c3fSthorpej 
397fa320c3fSthorpej 	assert((cp = strlist_next(sl, slsize, &cursor)) != NULL);
398fa320c3fSthorpej 	assert(strcmp(cp, "one") == 0);
399fa320c3fSthorpej 
400fa320c3fSthorpej 	assert((cp = strlist_next(sl, slsize, &cursor)) != NULL);
401fa320c3fSthorpej 	assert(strcmp(cp, "two") == 0);
402fa320c3fSthorpej 
403fa320c3fSthorpej 	assert((cp = strlist_next(sl, slsize, &cursor)) != NULL);
404fa320c3fSthorpej 	assert(strcmp(cp, "three") == 0);
405fa320c3fSthorpej 
406fa320c3fSthorpej 	assert((cp = strlist_next(sl, slsize, &cursor)) != NULL);
407fa320c3fSthorpej 	assert(strcmp(cp, "four") == 0);
408fa320c3fSthorpej 
409fa320c3fSthorpej 	assert((cp = strlist_next(sl, slsize, &cursor)) != NULL);
410fa320c3fSthorpej 	assert(strcmp(cp, "five") == 0);
411fa320c3fSthorpej 
412fa320c3fSthorpej 	assert((cp = strlist_next(sl, slsize, &cursor)) == NULL);
413fa320c3fSthorpej 
414fa320c3fSthorpej 	printf("Testing weighted matching.\n");
415fa320c3fSthorpej 	assert(strlist_match(sl, slsize, "non-existent") == 0);
416fa320c3fSthorpej 	assert(strlist_match(sl, slsize, "zero") == 6);
417fa320c3fSthorpej 	assert(strlist_match(sl, slsize, "one") == 5);
418fa320c3fSthorpej 	assert(strlist_match(sl, slsize, "two") == 4);
419fa320c3fSthorpej 	assert(strlist_match(sl, slsize, "three") == 3);
420fa320c3fSthorpej 	assert(strlist_match(sl, slsize, "four") == 2);
421fa320c3fSthorpej 	assert(strlist_match(sl, slsize, "five") == 1);
422fa320c3fSthorpej 
423fa320c3fSthorpej 	printf("Testing pattern matching.\n");
424fa320c3fSthorpej 	assert(strlist_pmatch(sl, slsize, "t?o") == 4);
425fa320c3fSthorpej 	assert(strlist_pmatch(sl, slsize, "f[a-o][o-u][a-z]") == 2);
426fa320c3fSthorpej 
427fa320c3fSthorpej 	printf("Testing index return.\n");
428fa320c3fSthorpej 	assert(strlist_index(sl, slsize, "non-existent") == -1);
429fa320c3fSthorpej 	assert(strlist_index(sl, slsize, "zero") == 0);
430fa320c3fSthorpej 	assert(strlist_index(sl, slsize, "one") == 1);
431fa320c3fSthorpej 	assert(strlist_index(sl, slsize, "two") == 2);
432fa320c3fSthorpej 	assert(strlist_index(sl, slsize, "three") == 3);
433fa320c3fSthorpej 	assert(strlist_index(sl, slsize, "four") == 4);
434fa320c3fSthorpej 	assert(strlist_index(sl, slsize, "five") == 5);
435fa320c3fSthorpej 
436fa320c3fSthorpej 	printf("Testing string-at-index.\n");
437fa320c3fSthorpej 	assert(strcmp(strlist_string(sl, slsize, 0), "zero") == 0);
438fa320c3fSthorpej 	assert(strcmp(strlist_string(sl, slsize, 1), "one") == 0);
439fa320c3fSthorpej 	assert(strcmp(strlist_string(sl, slsize, 2), "two") == 0);
440fa320c3fSthorpej 	assert(strcmp(strlist_string(sl, slsize, 3), "three") == 0);
441fa320c3fSthorpej 	assert(strcmp(strlist_string(sl, slsize, 4), "four") == 0);
442fa320c3fSthorpej 	assert(strcmp(strlist_string(sl, slsize, 5), "five") == 0);
443fa320c3fSthorpej 	assert(strlist_string(sl, slsize, 6) == NULL);
444fa320c3fSthorpej 
445fa320c3fSthorpej 	sl = gross_blob;
446fa320c3fSthorpej 	slsize = sizeof(gross_blob);
447fa320c3fSthorpej 
448fa320c3fSthorpej 	printf("Testing gross blob count.\n");
449fa320c3fSthorpej 	assert(strlist_count(sl, slsize) == 7);
450fa320c3fSthorpej 
451fa320c3fSthorpej 	printf("Testing gross blob indexing.\n");
452fa320c3fSthorpej 	assert(strcmp(strlist_string(sl, slsize, 0), "zero") == 0);
453fa320c3fSthorpej 	assert(strcmp(strlist_string(sl, slsize, 1), "") == 0);
454fa320c3fSthorpej 	assert(strcmp(strlist_string(sl, slsize, 2), "two") == 0);
455fa320c3fSthorpej 	assert(strcmp(strlist_string(sl, slsize, 3), "") == 0);
456fa320c3fSthorpej 	assert(strcmp(strlist_string(sl, slsize, 4), "four") == 0);
457fa320c3fSthorpej 	assert(strcmp(strlist_string(sl, slsize, 5), "") == 0);
458fa320c3fSthorpej 	assert(strcmp(strlist_string(sl, slsize, 6), "") == 0);
459fa320c3fSthorpej 	assert(strlist_string(sl, slsize, 7) == NULL);
460fa320c3fSthorpej 
461fa320c3fSthorpej 
462fa320c3fSthorpej 	printf("Testing creating a strlist.\n");
463fa320c3fSthorpej 	char *newsl = NULL;
464fa320c3fSthorpej 	size_t newslsize = 0;
465fa320c3fSthorpej 	assert(strlist_append(&newsl, &newslsize, "zero"));
466fa320c3fSthorpej 	assert(strlist_append(&newsl, &newslsize, "one"));
467fa320c3fSthorpej 	assert(strlist_append(&newsl, &newslsize, "two"));
468fa320c3fSthorpej 	assert(strlist_append(&newsl, &newslsize, "three"));
469fa320c3fSthorpej 	assert(strlist_append(&newsl, &newslsize, "four"));
470fa320c3fSthorpej 	assert(strlist_append(&newsl, &newslsize, "five"));
471fa320c3fSthorpej 
472fa320c3fSthorpej 	printf("Verifying new strlist.\n");
473fa320c3fSthorpej 	assert(strlist_count(newsl, newslsize) == 6);
474fa320c3fSthorpej 	assert(strcmp(strlist_string(newsl, newslsize, 0), "zero") == 0);
475fa320c3fSthorpej 	assert(strcmp(strlist_string(newsl, newslsize, 1), "one") == 0);
476fa320c3fSthorpej 	assert(strcmp(strlist_string(newsl, newslsize, 2), "two") == 0);
477fa320c3fSthorpej 	assert(strcmp(strlist_string(newsl, newslsize, 3), "three") == 0);
478fa320c3fSthorpej 	assert(strcmp(strlist_string(newsl, newslsize, 4), "four") == 0);
479fa320c3fSthorpej 	assert(strcmp(strlist_string(newsl, newslsize, 5), "five") == 0);
480fa320c3fSthorpej 	assert(strlist_string(newsl, newslsize, 6) == NULL);
481fa320c3fSthorpej 
482fa320c3fSthorpej 	/* This should be equivalent to nice_blob. */
483fa320c3fSthorpej 	assert(newslsize == sizeof(nice_blob));
484fa320c3fSthorpej 	assert(memcmp(newsl, nice_blob, newslsize) == 0);
485fa320c3fSthorpej 
486fa320c3fSthorpej 
487fa320c3fSthorpej 	printf("All tests completed successfully.\n");
488fa320c3fSthorpej 	return 0;
489fa320c3fSthorpej }
490fa320c3fSthorpej 
491fa320c3fSthorpej #endif /* STRLIST_TEST */
492