OSDN Git Service

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