037a26d623e3e37e014091d293a48b109ee353e3
[platform/upstream/glibc.git] / posix / fnmatch_loop.c
1 /* Copyright (C) 1991-1993, 1996-1999, 2000 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    This library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public
15    License along with this library; see the file COPYING.LIB.  If not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 02111-1307, USA.  */
18
19 /* Match STRING against the filename pattern PATTERN, returning zero if
20    it matches, nonzero if not.  */
21 static int FCT (const CHAR *pattern, const CHAR *string,
22                 int no_leading_period, int flags) internal_function;
23
24 static int
25 internal_function
26 FCT (pattern, string, no_leading_period, flags)
27      const CHAR *pattern;
28      const CHAR *string;
29      int no_leading_period;
30      int flags;
31 {
32   register const CHAR *p = pattern, *n = string;
33   register UCHAR c;
34
35   while ((c = *p++) != L('\0'))
36     {
37       c = FOLD (c);
38
39       switch (c)
40         {
41         case L('?'):
42           if (*n == L('\0'))
43             return FNM_NOMATCH;
44           else if (*n == L('/') && (flags & FNM_FILE_NAME))
45             return FNM_NOMATCH;
46           else if (*n == L('.') && no_leading_period
47                    && (n == string
48                        || (n[-1] == L('/') && (flags & FNM_FILE_NAME))))
49             return FNM_NOMATCH;
50           break;
51
52         case L('\\'):
53           if (!(flags & FNM_NOESCAPE))
54             {
55               c = *p++;
56               if (c == L('\0'))
57                 /* Trailing \ loses.  */
58                 return FNM_NOMATCH;
59               c = FOLD (c);
60             }
61           if (FOLD ((UCHAR) *n) != c)
62             return FNM_NOMATCH;
63           break;
64
65         case L('*'):
66           if (*n == L('.') && no_leading_period
67               && (n == string
68                   || (n[-1] == L('/') && (flags & FNM_FILE_NAME))))
69             return FNM_NOMATCH;
70
71           for (c = *p++; c == L('?') || c == L('*'); c = *p++)
72             {
73               if (*n == L('/') && (flags & FNM_FILE_NAME))
74                 /* A slash does not match a wildcard under FNM_FILE_NAME.  */
75                 return FNM_NOMATCH;
76               else if (c == L('?'))
77                 {
78                   /* A ? needs to match one character.  */
79                   if (*n == L('\0'))
80                     /* There isn't another character; no match.  */
81                     return FNM_NOMATCH;
82                   else
83                     /* One character of the string is consumed in matching
84                        this ? wildcard, so *??? won't match if there are
85                        less than three characters.  */
86                     ++n;
87                 }
88             }
89
90           if (c == L('\0'))
91             /* The wildcard(s) is/are the last element of the pattern.
92                If the name is a file name and contains another slash
93                this does mean it cannot match.  */
94             return ((flags & FNM_FILE_NAME) && STRCHR (n, L('/')) != NULL
95                     ? FNM_NOMATCH : 0);
96           else
97             {
98               const CHAR *endp;
99
100               endp = STRCHRNUL (n, (flags & FNM_FILE_NAME) ? L('/') : L('\0'));
101
102               if (c == L('['))
103                 {
104                   int flags2 = ((flags & FNM_FILE_NAME)
105                                 ? flags : (flags & ~FNM_PERIOD));
106
107                   for (--p; n < endp; ++n)
108                     if (FCT (p, n, (no_leading_period
109                                     && (n == string
110                                         || (n[-1] == L('/')
111                                             && (flags & FNM_FILE_NAME)))),
112                              flags2) == 0)
113                       return 0;
114                 }
115               else if (c == L('/') && (flags & FNM_FILE_NAME))
116                 {
117                   while (*n != L('\0') && *n != L('/'))
118                     ++n;
119                   if (*n == L('/')
120                       && (FCT (p, n + 1, flags & FNM_PERIOD, flags) == 0))
121                     return 0;
122                 }
123               else
124                 {
125                   int flags2 = ((flags & FNM_FILE_NAME)
126                                 ? flags : (flags & ~FNM_PERIOD));
127
128                   if (c == L('\\') && !(flags & FNM_NOESCAPE))
129                     c = *p;
130                   c = FOLD (c);
131                   for (--p; n < endp; ++n)
132                     if (FOLD ((UCHAR) *n) == c
133                         && (FCT (p, n, (no_leading_period
134                                         && (n == string
135                                             || (n[-1] == L('/')
136                                                 && (flags & FNM_FILE_NAME)))),
137                                  flags2) == 0))
138                       return 0;
139                 }
140             }
141
142           /* If we come here no match is possible with the wildcard.  */
143           return FNM_NOMATCH;
144
145         case L('['):
146           {
147             /* Nonzero if the sense of the character class is inverted.  */
148             static int posixly_correct;
149             register int not;
150             CHAR cold;
151
152             if (posixly_correct == 0)
153               posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
154
155             if (*n == L('\0'))
156               return FNM_NOMATCH;
157
158             if (*n == L('.') && no_leading_period
159                 && (n == string
160                     || (n[-1] == L('/') && (flags & FNM_FILE_NAME))))
161               return FNM_NOMATCH;
162
163             if (*n == L('/') && (flags & FNM_FILE_NAME))
164               /* `/' cannot be matched.  */
165               return FNM_NOMATCH;
166
167             not = (*p == L('!') || (posixly_correct < 0 && *p == L('^')));
168             if (not)
169               ++p;
170
171             c = *p++;
172             for (;;)
173               {
174                 UCHAR fn = FOLD ((UCHAR) *n);
175
176                 if (!(flags & FNM_NOESCAPE) && c == L('\\'))
177                   {
178                     if (*p == L('\0'))
179                       return FNM_NOMATCH;
180                     c = FOLD ((UCHAR) *p);
181                     ++p;
182
183                     if (c == fn)
184                       goto matched;
185                   }
186                 else if (c == L('[') && *p == L(':'))
187                   {
188                     /* Leave room for the null.  */
189                     CHAR str[CHAR_CLASS_MAX_LENGTH + 1];
190                     size_t c1 = 0;
191 # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
192                     wctype_t wt;
193 # endif
194                     const CHAR *startp = p;
195
196                     for (;;)
197                       {
198                         if (c1 == CHAR_CLASS_MAX_LENGTH)
199                           /* The name is too long and therefore the pattern
200                              is ill-formed.  */
201                           return FNM_NOMATCH;
202
203                         c = *++p;
204                         if (c == L(':') && p[1] == L(']'))
205                           {
206                             p += 2;
207                             break;
208                           }
209                         if (c < L('a') || c >= L('z'))
210                           {
211                             /* This cannot possibly be a character class name.
212                                Match it as a normal range.  */
213                             p = startp;
214                             c = L('[');
215                             goto normal_bracket;
216                           }
217                         str[c1++] = c;
218                       }
219                     str[c1] = L('\0');
220
221 # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
222                     wt = IS_CHAR_CLASS (str);
223                     if (wt == 0)
224                       /* Invalid character class name.  */
225                       return FNM_NOMATCH;
226
227                     if (__iswctype (__btowc ((UCHAR) *n), wt))
228                       goto matched;
229 # else
230                     if ((STREQ (str, L("alnum")) && ISALNUM ((UCHAR) *n))
231                         || (STREQ (str, L("alpha")) && ISALPHA ((UCHAR) *n))
232                         || (STREQ (str, L("blank")) && ISBLANK ((UCHAR) *n))
233                         || (STREQ (str, L("cntrl")) && ISCNTRL ((UCHAR) *n))
234                         || (STREQ (str, L("digit")) && ISDIGIT ((UCHAR) *n))
235                         || (STREQ (str, L("graph")) && ISGRAPH ((UCHAR) *n))
236                         || (STREQ (str, L("lower")) && ISLOWER ((UCHAR) *n))
237                         || (STREQ (str, L("print")) && ISPRINT ((UCHAR) *n))
238                         || (STREQ (str, L("punct")) && ISPUNCT ((UCHAR) *n))
239                         || (STREQ (str, L("space")) && ISSPACE ((UCHAR) *n))
240                         || (STREQ (str, L("upper")) && ISUPPER ((UCHAR) *n))
241                         || (STREQ (str, L("xdigit")) && ISXDIGIT ((UCHAR) *n)))
242                       goto matched;
243 # endif
244                   }
245                 else if (c == L('\0'))
246                   /* [ (unterminated) loses.  */
247                   return FNM_NOMATCH;
248                 else
249                   {
250                   normal_bracket:
251                     if (FOLD (c) == fn)
252                       goto matched;
253
254                     cold = c;
255                     c = *p++;
256
257                     if (c == L('-') && *p != L(']'))
258                       {
259                         /* It is a range.  */
260                         UCHAR cend = *p++;
261                         if (!(flags & FNM_NOESCAPE) && cend == L('\\'))
262                           cend = *p++;
263                         if (cend == L('\0'))
264                           return FNM_NOMATCH;
265
266                         if (cold <= fn && fn <= FOLD (cend))
267                           goto matched;
268
269                         c = *p++;
270                       }
271                   }
272
273                 if (c == L(']'))
274                   break;
275               }
276
277             if (!not)
278               return FNM_NOMATCH;
279             break;
280
281           matched:
282             /* Skip the rest of the [...] that already matched.  */
283             while (c != L(']'))
284               {
285                 if (c == L('\0'))
286                   /* [... (unterminated) loses.  */
287                   return FNM_NOMATCH;
288
289                 c = *p++;
290                 if (!(flags & FNM_NOESCAPE) && c == L('\\'))
291                   {
292                     if (*p == L('\0'))
293                       return FNM_NOMATCH;
294                     /* XXX 1003.2d11 is unclear if this is right.  */
295                     ++p;
296                   }
297                 else if (c == L('[') && *p == L(':'))
298                   {
299                     do
300                       if (*++p == L('\0'))
301                         return FNM_NOMATCH;
302                     while (*p != L(':') || p[1] == L(']'));
303                     p += 2;
304                     c = *p;
305                   }
306               }
307             if (not)
308               return FNM_NOMATCH;
309           }
310           break;
311
312         default:
313           if (c != FOLD ((UCHAR) *n))
314             return FNM_NOMATCH;
315         }
316
317       ++n;
318     }
319
320   if (*n == '\0')
321     return 0;
322
323   if ((flags & FNM_LEADING_DIR) && *n == L('/'))
324     /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
325     return 0;
326
327   return FNM_NOMATCH;
328
329 #undef FOLD
330 #undef CHAR
331 #undef UCHAR
332 #undef FCT
333 #undef STRCHR
334 #undef STRCHRNUL
335 #undef L
336 }