1/* $NetBSD: t_strchrnul.c,v 1.1 2023/01/30 19:49:49 christos Exp $ */
2
3/*
4 * Written by J.T. Conklin <jtc@acorntoolworks.com>
5 * Public domain.
6 */
7
8#include <atf-c.h>
9#include <string.h>
10#include <unistd.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <dlfcn.h>
14
15static char	*slow_strchrnul(char *, int);
16static void	 verify_strchrnul(char *, int, unsigned int, unsigned int);
17
18char * (*volatile strchrnul_fn)(const char *, int);
19
20static char *
21slow_strchrnul(char *buf, int ch)
22{
23	unsigned char c = 1;
24
25	ch &= 0xff;
26
27	for (; ; buf++) {
28		c = *buf;
29		if (c == ch || c == 0)
30			return buf;
31	}
32}
33
34static void
35verify_strchrnul(char *buf, int ch, unsigned int t, unsigned int a)
36{
37	const char *off, *ok_off;
38
39	off = strchrnul_fn(buf, ch);
40	ok_off = slow_strchrnul(buf, ch);
41	if (off == ok_off)
42		return;
43
44	fprintf(stderr, "test_strchrnul(\"%s\", %#x) gave %zd not %zd (test %d, "
45	    "alignment %d)\n",
46	    buf, ch, off ? off - buf : -1, ok_off ? ok_off - buf : -1, t, a);
47
48	atf_tc_fail("Check stderr for details");
49}
50
51ATF_TC(strchrnul_basic);
52ATF_TC_HEAD(strchrnul_basic, tc)
53{
54
55        atf_tc_set_md_var(tc, "descr", "Test strchrnul(3) results");
56}
57
58ATF_TC_BODY(strchrnul_basic, tc)
59{
60	void *dl_handle;
61	char *off;
62	char buf[32];
63	unsigned int t, a;
64
65	const char *tab[] = {
66		"",
67		"a",
68		"aa",
69		"abc",
70		"abcd",
71		"abcde",
72		"abcdef",
73		"abcdefg",
74		"abcdefgh",
75
76		"/",
77		"//",
78		"/a",
79		"/a/",
80		"/ab",
81		"/ab/",
82		"/abc",
83		"/abc/",
84		"/abcd",
85		"/abcd/",
86		"/abcde",
87		"/abcde/",
88		"/abcdef",
89		"/abcdef/",
90		"/abcdefg",
91		"/abcdefg/",
92		"/abcdefgh",
93		"/abcdefgh/",
94
95		"a/",
96		"a//",
97		"a/a",
98		"a/a/",
99		"a/ab",
100		"a/ab/",
101		"a/abc",
102		"a/abc/",
103		"a/abcd",
104		"a/abcd/",
105		"a/abcde",
106		"a/abcde/",
107		"a/abcdef",
108		"a/abcdef/",
109		"a/abcdefg",
110		"a/abcdefg/",
111		"a/abcdefgh",
112		"a/abcdefgh/",
113
114		"ab/",
115		"ab//",
116		"ab/a",
117		"ab/a/",
118		"ab/ab",
119		"ab/ab/",
120		"ab/abc",
121		"ab/abc/",
122		"ab/abcd",
123		"ab/abcd/",
124		"ab/abcde",
125		"ab/abcde/",
126		"ab/abcdef",
127		"ab/abcdef/",
128		"ab/abcdefg",
129		"ab/abcdefg/",
130		"ab/abcdefgh",
131		"ab/abcdefgh/",
132
133		"abc/",
134		"abc//",
135		"abc/a",
136		"abc/a/",
137		"abc/ab",
138		"abc/ab/",
139		"abc/abc",
140		"abc/abc/",
141		"abc/abcd",
142		"abc/abcd/",
143		"abc/abcde",
144		"abc/abcde/",
145		"abc/abcdef",
146		"abc/abcdef/",
147		"abc/abcdefg",
148		"abc/abcdefg/",
149		"abc/abcdefgh",
150		"abc/abcdefgh/",
151
152		"abcd/",
153		"abcd//",
154		"abcd/a",
155		"abcd/a/",
156		"abcd/ab",
157		"abcd/ab/",
158		"abcd/abc",
159		"abcd/abc/",
160		"abcd/abcd",
161		"abcd/abcd/",
162		"abcd/abcde",
163		"abcd/abcde/",
164		"abcd/abcdef",
165		"abcd/abcdef/",
166		"abcd/abcdefg",
167		"abcd/abcdefg/",
168		"abcd/abcdefgh",
169		"abcd/abcdefgh/",
170
171		"abcde/",
172		"abcde//",
173		"abcde/a",
174		"abcde/a/",
175		"abcde/ab",
176		"abcde/ab/",
177		"abcde/abc",
178		"abcde/abc/",
179		"abcde/abcd",
180		"abcde/abcd/",
181		"abcde/abcde",
182		"abcde/abcde/",
183		"abcde/abcdef",
184		"abcde/abcdef/",
185		"abcde/abcdefg",
186		"abcde/abcdefg/",
187		"abcde/abcdefgh",
188		"abcde/abcdefgh/",
189
190		"abcdef/",
191		"abcdef//",
192		"abcdef/a",
193		"abcdef/a/",
194		"abcdef/ab",
195		"abcdef/ab/",
196		"abcdef/abc",
197		"abcdef/abc/",
198		"abcdef/abcd",
199		"abcdef/abcd/",
200		"abcdef/abcde",
201		"abcdef/abcde/",
202		"abcdef/abcdef",
203		"abcdef/abcdef/",
204		"abcdef/abcdefg",
205		"abcdef/abcdefg/",
206		"abcdef/abcdefgh",
207		"abcdef/abcdefgh/",
208
209		"abcdefg/",
210		"abcdefg//",
211		"abcdefg/a",
212		"abcdefg/a/",
213		"abcdefg/ab",
214		"abcdefg/ab/",
215		"abcdefg/abc",
216		"abcdefg/abc/",
217		"abcdefg/abcd",
218		"abcdefg/abcd/",
219		"abcdefg/abcde",
220		"abcdefg/abcde/",
221		"abcdefg/abcdef",
222		"abcdefg/abcdef/",
223		"abcdefg/abcdefg",
224		"abcdefg/abcdefg/",
225		"abcdefg/abcdefgh",
226		"abcdefg/abcdefgh/",
227
228		"abcdefgh/",
229		"abcdefgh//",
230		"abcdefgh/a",
231		"abcdefgh/a/",
232		"abcdefgh/ab",
233		"abcdefgh/ab/",
234		"abcdefgh/abc",
235		"abcdefgh/abc/",
236		"abcdefgh/abcd",
237		"abcdefgh/abcd/",
238		"abcdefgh/abcde",
239		"abcdefgh/abcde/",
240		"abcdefgh/abcdef",
241		"abcdefgh/abcdef/",
242		"abcdefgh/abcdefg",
243		"abcdefgh/abcdefg/",
244		"abcdefgh/abcdefgh",
245		"abcdefgh/abcdefgh/",
246	};
247
248	dl_handle = dlopen(NULL, RTLD_LAZY);
249	strchrnul_fn = dlsym(dl_handle, "test_strchrnul");
250	if (!strchrnul_fn)
251		strchrnul_fn = strchrnul;
252
253	for (a = 3; a < 3 + sizeof(long); ++a) {
254		/* Put char and a \0 before the buffer */
255		buf[a-1] = '/';
256		buf[a-2] = '0';
257		buf[a-3] = 0xff;
258		for (t = 0; t < (sizeof(tab) / sizeof(tab[0])); ++t) {
259			int len = strlen(tab[t]) + 1;
260			memcpy(&buf[a], tab[t], len);
261
262			/* Put the char we are looking for after the \0 */
263			buf[a + len] = '/';
264
265			/* Check search for NUL at end of string */
266			verify_strchrnul(buf + a, 0, t, a);
267
268			/* Then for the '/' in the strings */
269			verify_strchrnul(buf + a, '/', t, a);
270
271			/* check zero extension of char arg */
272			verify_strchrnul(buf + a, 0xffffff00 | '/', t, a);
273
274			/* Replace all the '/' with 0xff */
275			while (*(off = slow_strchrnul(buf + a, '/')) != '\0')
276				*off = 0xff;
277
278			buf[a + len] = 0xff;
279
280			/* Check we can search for 0xff as well as '/' */
281			verify_strchrnul(buf + a, 0xff, t, a);
282		}
283	}
284	(void)dlclose(dl_handle);
285}
286
287ATF_TP_ADD_TCS(tp)
288{
289
290	ATF_TP_ADD_TC(tp, strchrnul_basic);
291
292	return atf_no_error();
293}
294