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