blob: bb102c5bb5c63be852401ae7b9541b2c3e6ebe6f [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* Tests for fnmatch function.
2 Copyright (C) 2000, 2001 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
19
20#include <errno.h>
21#include <error.h>
22#include <fnmatch.h>
23#include <locale.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <ctype.h>
28#include <sys/types.h>
29
30
31static char *next_input (char **line, int first, int last);
32static int convert_flags (const char *str);
33static char *flag_output (int flags);
34static char *escape (const char *str, size_t *reslenp, char **resbuf);
35
36
37int str_isalpha(const char *str)
38{
39 size_t i = strlen(str);
40 while (i--)
41 if (isascii(str[i]) == 0)
42 return 0;
43 return 1;
44}
45int str_has_funk(const char *str, const char x)
46{
47 size_t i, max = strlen(str);
48 for (i=0; i+1<max; ++i)
49 if (str[i] == '[' && str[i+1] == x)
50 return 1;
51 return 0;
52}
53
54
55int
56main (void)
57{
58 char *linebuf = NULL;
59 size_t linebuflen = 0;
60 int ntests = 0;
61 int nfailed = 0;
62 int nskipped = 0;
63 char *escinput = NULL;
64 size_t escinputlen = 0;
65 char *escpattern = NULL;
66 size_t escpatternlen = 0;
67 int nr = 0;
68
69 /* Read lines from stdin with the following format:
70
71 locale input-string match-string flags result
72
73 where `result' is either 0 or 1. If the first character of a
74 string is '"' we read until the next '"' and handled escaped '"'. */
75 while (! feof (stdin))
76 {
77 ssize_t n = getline (&linebuf, &linebuflen, stdin);
78 char *cp;
79 const char *locale;
80 const char *input;
81 const char *pattern;
82 const char *result_str;
83 int result;
84 const char *flags;
85 int flags_val;
86 int fnmres;
87 char numbuf[24];
88
89 if (n == -1)
90 break;
91
92 if (n == 0)
93 /* Maybe an empty line. */
94 continue;
95
96 /* Skip over all leading white spaces. */
97 cp = linebuf;
98
99 locale = next_input (&cp, 1, 0);
100 if (locale == NULL)
101 continue;
102
103 input = next_input (&cp, 0, 0);
104 if (input == NULL)
105 continue;
106
107 pattern = next_input (&cp, 0, 0);
108 if (pattern == NULL)
109 continue;
110
111 result_str = next_input (&cp, 0, 0);
112 if (result_str == NULL)
113 continue;
114
115 if (strcmp (result_str, "0") == 0)
116 result = 0;
117 else if (strcasecmp (result_str, "NOMATCH") == 0)
118 result = FNM_NOMATCH;
119 else
120 {
121 char *endp;
122 result = strtol (result_str, &endp, 0);
123 if (*endp != '\0')
124 continue;
125 }
126
127 flags = next_input (&cp, 0, 1);
128 if (flags == NULL)
129 /* We allow the flags missing. */
130 flags = "";
131
132 /* Convert the text describing the flags in a numeric value. */
133 flags_val = convert_flags (flags);
134 if (flags_val == -1)
135 /* Something went wrong. */
136 continue;
137
138 /* Now run the actual test. */
139 ++ntests;
140
141#ifdef __UCLIBC_HAS_XLOCALE__
142 if (setlocale (LC_COLLATE, locale) == NULL
143 || setlocale (LC_CTYPE, locale) == NULL)
144 {
145 puts ("*** Cannot set locale");
146 ++nfailed;
147 continue;
148 }
149#else
150 /* skip non-ascii strings */
151 if (!str_isalpha(pattern) || !str_isalpha(input))
152 {
153 ++nskipped;
154 printf("%3d: fnmatch (\"%s\", \"%s\"): SKIP multibyte test (requires locale support)\n", ++nr, pattern, input);
155 continue;
156 }
157 /* skip collating symbols */
158 if (str_has_funk(pattern, '.') || str_has_funk(input, '.'))
159 {
160 ++nskipped;
161 printf("%3d: fnmatch (\"%s\", \"%s\"): SKIP collating symbol test (requires locale support)\n", ++nr, pattern, input);
162 continue;
163 }
164 /* skip equivalence class expressions */
165 if (str_has_funk(pattern, '=') || str_has_funk(input, '='))
166 {
167 ++nskipped;
168 printf("%3d: fnmatch (\"%s\", \"%s\"): SKIP equivalence class test (requires locale support)\n", ++nr, pattern, input);
169 continue;
170 }
171#endif
172
173 fnmres = fnmatch (pattern, input, flags_val);
174
175 printf ("%3d: fnmatch (\"%s\", \"%s\", %s) = %s%c",
176 ++nr,
177 escape (pattern, &escpatternlen, &escpattern),
178 escape (input, &escinputlen, &escinput),
179 flag_output (flags_val),
180 (fnmres == 0
181 ? "0" : (fnmres == FNM_NOMATCH
182 ? "FNM_NOMATCH"
183 : (sprintf (numbuf, "%d", fnmres), numbuf))),
184 (fnmres != 0) != (result != 0) ? ' ' : '\n');
185
186 if ((fnmres != 0) != (result != 0))
187 {
188 printf ("(FAIL, expected %s) ***\n",
189 result == 0
190 ? "0" : (result == FNM_NOMATCH
191 ? "FNM_NOMATCH"
192 : (sprintf (numbuf, "%d", result), numbuf)));
193 ++nfailed;
194 }
195 }
196
197 printf ("=====================\n%3d tests, %3d failed, %3d skipped\n", ntests, nfailed, nskipped);
198
199 free (escpattern);
200 free (escinput);
201 free (linebuf);
202
203 return nfailed != 0;
204}
205
206
207static char *
208next_input (char **line, int first, int last)
209{
210 char *cp = *line;
211 char *result;
212
213 while (*cp == ' ' || *cp == '\t')
214 ++cp;
215
216 /* We allow comment lines starting with '#'. */
217 if (first && *cp == '#')
218 return NULL;
219
220 if (*cp == '"')
221 {
222 char *wp;
223
224 result = ++cp;
225 wp = cp;
226
227 while (*cp != '"' && *cp != '\0' && *cp != '\n')
228 if (*cp == '\\')
229 {
230 if (cp[1] == '\n' || cp[1] == '\0')
231 return NULL;
232
233 ++cp;
234 if (*cp == 't')
235 *wp++ = '\t';
236 else if (*cp == 'n')
237 *wp++ = '\n';
238 else
239 *wp++ = *cp;
240
241 ++cp;
242 }
243 else
244 *wp++ = *cp++;
245
246 if (*cp != '"')
247 return NULL;
248
249 if (wp != cp)
250 *wp = '\0';
251 }
252 else
253 {
254 result = cp;
255 while (*cp != '\0' && *cp != '\n' && *cp != ' ' && *cp != '\t')
256 ++cp;
257
258 if (cp == result && ! last)
259 /* Premature end of line. */
260 return NULL;
261 }
262
263 /* Terminate and skip over the next white spaces. */
264 *cp++ = '\0';
265
266 *line = cp;
267 return result;
268}
269
270
271static int
272convert_flags (const char *str)
273{
274 int result = 0;
275
276 while (*str != '\0')
277 {
278 int len;
279
280 if (strncasecmp (str, "PATHNAME", 8) == 0
281 && (str[8] == '|' || str[8] == '\0'))
282 {
283 result |= FNM_PATHNAME;
284 len = 8;
285 }
286 else if (strncasecmp (str, "NOESCAPE", 8) == 0
287 && (str[8] == '|' || str[8] == '\0'))
288 {
289 result |= FNM_NOESCAPE;
290 len = 8;
291 }
292 else if (strncasecmp (str, "PERIOD", 6) == 0
293 && (str[6] == '|' || str[6] == '\0'))
294 {
295 result |= FNM_PERIOD;
296 len = 6;
297 }
298#ifdef FNM_LEADING_DIR
299 else if (strncasecmp (str, "LEADING_DIR", 11) == 0
300 && (str[11] == '|' || str[11] == '\0'))
301 {
302 result |= FNM_LEADING_DIR;
303 len = 11;
304 }
305#endif
306#ifdef FNM_CASEFOLD
307 else if (strncasecmp (str, "CASEFOLD", 8) == 0
308 && (str[8] == '|' || str[8] == '\0'))
309 {
310 result |= FNM_CASEFOLD;
311 len = 8;
312 }
313#endif
314#ifdef FNM_EXTMATCH
315 else if (strncasecmp (str, "EXTMATCH", 8) == 0
316 && (str[8] == '|' || str[8] == '\0'))
317 {
318 result |= FNM_EXTMATCH;
319 len = 8;
320 }
321#endif
322 else
323 return -1;
324
325 str += len;
326 if (*str != '\0')
327 ++str;
328 }
329
330 return result;
331}
332
333
334static char *
335flag_output (int flags)
336{
337 static char buf[100];
338 int first = 1;
339 char *cp = buf;
340
341 if (flags & FNM_PATHNAME)
342 {
343 cp = stpcpy (cp, "FNM_PATHNAME");
344 first = 0;
345 }
346 if (flags & FNM_NOESCAPE)
347 {
348 if (! first)
349 *cp++ = '|';
350 cp = stpcpy (cp, "FNM_NOESCAPE");
351 first = 0;
352 }
353 if (flags & FNM_PERIOD)
354 {
355 if (! first)
356 *cp++ = '|';
357 cp = stpcpy (cp, "FNM_PERIOD");
358 first = 0;
359 }
360#ifdef FNM_LEADING_DIR
361 if (flags & FNM_LEADING_DIR)
362 {
363 if (! first)
364 *cp++ = '|';
365 cp = stpcpy (cp, "FNM_LEADING_DIR");
366 first = 0;
367 }
368#endif
369#ifdef FNM_CASEFOLD
370 if (flags & FNM_CASEFOLD)
371 {
372 if (! first)
373 *cp++ = '|';
374 cp = stpcpy (cp, "FNM_CASEFOLD");
375 first = 0;
376 }
377#endif
378#ifdef FNM_EXTMATCH
379 if (flags & FNM_EXTMATCH)
380 {
381 if (! first)
382 *cp++ = '|';
383 cp = stpcpy (cp, "FNM_EXTMATCH");
384 first = 0;
385 }
386#endif
387 if (cp == buf)
388 *cp++ = '0';
389 *cp = '\0';
390
391 return buf;
392}
393
394
395static char *
396escape (const char *str, size_t *reslenp, char **resbufp)
397{
398 size_t reslen = *reslenp;
399 char *resbuf = *resbufp;
400 size_t len = strlen (str);
401 char *wp;
402
403 if (2 * len + 1 > reslen)
404 {
405 resbuf = (char *) realloc (resbuf, 2 * len + 1);
406 if (resbuf == NULL)
407 error (EXIT_FAILURE, errno, "while allocating buffer for printing");
408 *reslenp = 2 * len + 1;
409 *resbufp = resbuf;
410 }
411
412 wp = resbuf;
413 while (*str != '\0')
414 if (*str == '\t')
415 {
416 *wp++ = '\\';
417 *wp++ = 't';
418 ++str;
419 }
420 else if (*str == '\n')
421 {
422 *wp++ = '\\';
423 *wp++ = 'n';
424 ++str;
425 }
426 else if (*str == '"')
427 {
428 *wp++ = '\\';
429 *wp++ = '"';
430 ++str;
431 }
432 else if (*str == '\\')
433 {
434 *wp++ = '\\';
435 *wp++ = '\\';
436 ++str;
437 }
438 else
439 *wp++ = *str++;
440
441 *wp = '\0';
442
443 return resbuf;
444}