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