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