1*ef5ccd6cSJohn Marino /* Copyright (C) 1991-1993, 1996-2006, 2009-2012 Free Software Foundation, Inc.
2*ef5ccd6cSJohn Marino    This file is part of the GNU C Library.
3*ef5ccd6cSJohn Marino 
4*ef5ccd6cSJohn Marino    This program is free software; you can redistribute it and/or modify
5*ef5ccd6cSJohn Marino    it under the terms of the GNU General Public License as published by
6*ef5ccd6cSJohn Marino    the Free Software Foundation; either version 3, or (at your option)
7*ef5ccd6cSJohn Marino    any later version.
8*ef5ccd6cSJohn Marino 
9*ef5ccd6cSJohn Marino    This program is distributed in the hope that it will be useful,
10*ef5ccd6cSJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
11*ef5ccd6cSJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*ef5ccd6cSJohn Marino    GNU General Public License for more details.
13*ef5ccd6cSJohn Marino 
14*ef5ccd6cSJohn Marino    You should have received a copy of the GNU General Public License
15*ef5ccd6cSJohn Marino    along with this program; if not, see <http://www.gnu.org/licenses/>.  */
16*ef5ccd6cSJohn Marino 
17*ef5ccd6cSJohn Marino /* Match STRING against the file name pattern PATTERN, returning zero if
18*ef5ccd6cSJohn Marino    it matches, nonzero if not.  */
19*ef5ccd6cSJohn Marino static int EXT (INT opt, const CHAR *pattern, const CHAR *string,
20*ef5ccd6cSJohn Marino                 const CHAR *string_end, bool no_leading_period, int flags)
21*ef5ccd6cSJohn Marino      internal_function;
22*ef5ccd6cSJohn Marino static const CHAR *END (const CHAR *patternp) internal_function;
23*ef5ccd6cSJohn Marino 
24*ef5ccd6cSJohn Marino static int
25*ef5ccd6cSJohn Marino internal_function
FCT(const CHAR * pattern,const CHAR * string,const CHAR * string_end,bool no_leading_period,int flags)26*ef5ccd6cSJohn Marino FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end,
27*ef5ccd6cSJohn Marino      bool no_leading_period, int flags)
28*ef5ccd6cSJohn Marino {
29*ef5ccd6cSJohn Marino   register const CHAR *p = pattern, *n = string;
30*ef5ccd6cSJohn Marino   register UCHAR c;
31*ef5ccd6cSJohn Marino #ifdef _LIBC
32*ef5ccd6cSJohn Marino # if WIDE_CHAR_VERSION
33*ef5ccd6cSJohn Marino   const char *collseq = (const char *)
34*ef5ccd6cSJohn Marino     _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC);
35*ef5ccd6cSJohn Marino # else
36*ef5ccd6cSJohn Marino   const UCHAR *collseq = (const UCHAR *)
37*ef5ccd6cSJohn Marino     _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQMB);
38*ef5ccd6cSJohn Marino # endif
39*ef5ccd6cSJohn Marino #endif
40*ef5ccd6cSJohn Marino 
41*ef5ccd6cSJohn Marino   while ((c = *p++) != L_('\0'))
42*ef5ccd6cSJohn Marino     {
43*ef5ccd6cSJohn Marino       bool new_no_leading_period = false;
44*ef5ccd6cSJohn Marino       c = FOLD (c);
45*ef5ccd6cSJohn Marino 
46*ef5ccd6cSJohn Marino       switch (c)
47*ef5ccd6cSJohn Marino         {
48*ef5ccd6cSJohn Marino         case L_('?'):
49*ef5ccd6cSJohn Marino           if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
50*ef5ccd6cSJohn Marino             {
51*ef5ccd6cSJohn Marino               int res;
52*ef5ccd6cSJohn Marino 
53*ef5ccd6cSJohn Marino               res = EXT (c, p, n, string_end, no_leading_period,
54*ef5ccd6cSJohn Marino                          flags);
55*ef5ccd6cSJohn Marino               if (res != -1)
56*ef5ccd6cSJohn Marino                 return res;
57*ef5ccd6cSJohn Marino             }
58*ef5ccd6cSJohn Marino 
59*ef5ccd6cSJohn Marino           if (n == string_end)
60*ef5ccd6cSJohn Marino             return FNM_NOMATCH;
61*ef5ccd6cSJohn Marino           else if (*n == L_('/') && (flags & FNM_FILE_NAME))
62*ef5ccd6cSJohn Marino             return FNM_NOMATCH;
63*ef5ccd6cSJohn Marino           else if (*n == L_('.') && no_leading_period)
64*ef5ccd6cSJohn Marino             return FNM_NOMATCH;
65*ef5ccd6cSJohn Marino           break;
66*ef5ccd6cSJohn Marino 
67*ef5ccd6cSJohn Marino         case L_('\\'):
68*ef5ccd6cSJohn Marino           if (!(flags & FNM_NOESCAPE))
69*ef5ccd6cSJohn Marino             {
70*ef5ccd6cSJohn Marino               c = *p++;
71*ef5ccd6cSJohn Marino               if (c == L_('\0'))
72*ef5ccd6cSJohn Marino                 /* Trailing \ loses.  */
73*ef5ccd6cSJohn Marino                 return FNM_NOMATCH;
74*ef5ccd6cSJohn Marino               c = FOLD (c);
75*ef5ccd6cSJohn Marino             }
76*ef5ccd6cSJohn Marino           if (n == string_end || FOLD ((UCHAR) *n) != c)
77*ef5ccd6cSJohn Marino             return FNM_NOMATCH;
78*ef5ccd6cSJohn Marino           break;
79*ef5ccd6cSJohn Marino 
80*ef5ccd6cSJohn Marino         case L_('*'):
81*ef5ccd6cSJohn Marino           if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
82*ef5ccd6cSJohn Marino             {
83*ef5ccd6cSJohn Marino               int res;
84*ef5ccd6cSJohn Marino 
85*ef5ccd6cSJohn Marino               res = EXT (c, p, n, string_end, no_leading_period,
86*ef5ccd6cSJohn Marino                          flags);
87*ef5ccd6cSJohn Marino               if (res != -1)
88*ef5ccd6cSJohn Marino                 return res;
89*ef5ccd6cSJohn Marino             }
90*ef5ccd6cSJohn Marino 
91*ef5ccd6cSJohn Marino           if (n != string_end && *n == L_('.') && no_leading_period)
92*ef5ccd6cSJohn Marino             return FNM_NOMATCH;
93*ef5ccd6cSJohn Marino 
94*ef5ccd6cSJohn Marino           for (c = *p++; c == L_('?') || c == L_('*'); c = *p++)
95*ef5ccd6cSJohn Marino             {
96*ef5ccd6cSJohn Marino               if (*p == L_('(') && (flags & FNM_EXTMATCH) != 0)
97*ef5ccd6cSJohn Marino                 {
98*ef5ccd6cSJohn Marino                   const CHAR *endp = END (p);
99*ef5ccd6cSJohn Marino                   if (endp != p)
100*ef5ccd6cSJohn Marino                     {
101*ef5ccd6cSJohn Marino                       /* This is a pattern.  Skip over it.  */
102*ef5ccd6cSJohn Marino                       p = endp;
103*ef5ccd6cSJohn Marino                       continue;
104*ef5ccd6cSJohn Marino                     }
105*ef5ccd6cSJohn Marino                 }
106*ef5ccd6cSJohn Marino 
107*ef5ccd6cSJohn Marino               if (c == L_('?'))
108*ef5ccd6cSJohn Marino                 {
109*ef5ccd6cSJohn Marino                   /* A ? needs to match one character.  */
110*ef5ccd6cSJohn Marino                   if (n == string_end)
111*ef5ccd6cSJohn Marino                     /* There isn't another character; no match.  */
112*ef5ccd6cSJohn Marino                     return FNM_NOMATCH;
113*ef5ccd6cSJohn Marino                   else if (*n == L_('/')
114*ef5ccd6cSJohn Marino                            && __builtin_expect (flags & FNM_FILE_NAME, 0))
115*ef5ccd6cSJohn Marino                     /* A slash does not match a wildcard under
116*ef5ccd6cSJohn Marino                        FNM_FILE_NAME.  */
117*ef5ccd6cSJohn Marino                     return FNM_NOMATCH;
118*ef5ccd6cSJohn Marino                   else
119*ef5ccd6cSJohn Marino                     /* One character of the string is consumed in matching
120*ef5ccd6cSJohn Marino                        this ? wildcard, so *??? won't match if there are
121*ef5ccd6cSJohn Marino                        less than three characters.  */
122*ef5ccd6cSJohn Marino                     ++n;
123*ef5ccd6cSJohn Marino                 }
124*ef5ccd6cSJohn Marino             }
125*ef5ccd6cSJohn Marino 
126*ef5ccd6cSJohn Marino           if (c == L_('\0'))
127*ef5ccd6cSJohn Marino             /* The wildcard(s) is/are the last element of the pattern.
128*ef5ccd6cSJohn Marino                If the name is a file name and contains another slash
129*ef5ccd6cSJohn Marino                this means it cannot match, unless the FNM_LEADING_DIR
130*ef5ccd6cSJohn Marino                flag is set.  */
131*ef5ccd6cSJohn Marino             {
132*ef5ccd6cSJohn Marino               int result = (flags & FNM_FILE_NAME) == 0 ? 0 : FNM_NOMATCH;
133*ef5ccd6cSJohn Marino 
134*ef5ccd6cSJohn Marino               if (flags & FNM_FILE_NAME)
135*ef5ccd6cSJohn Marino                 {
136*ef5ccd6cSJohn Marino                   if (flags & FNM_LEADING_DIR)
137*ef5ccd6cSJohn Marino                     result = 0;
138*ef5ccd6cSJohn Marino                   else
139*ef5ccd6cSJohn Marino                     {
140*ef5ccd6cSJohn Marino                       if (MEMCHR (n, L_('/'), string_end - n) == NULL)
141*ef5ccd6cSJohn Marino                         result = 0;
142*ef5ccd6cSJohn Marino                     }
143*ef5ccd6cSJohn Marino                 }
144*ef5ccd6cSJohn Marino 
145*ef5ccd6cSJohn Marino               return result;
146*ef5ccd6cSJohn Marino             }
147*ef5ccd6cSJohn Marino           else
148*ef5ccd6cSJohn Marino             {
149*ef5ccd6cSJohn Marino               const CHAR *endp;
150*ef5ccd6cSJohn Marino 
151*ef5ccd6cSJohn Marino               endp = MEMCHR (n, (flags & FNM_FILE_NAME) ? L_('/') : L_('\0'),
152*ef5ccd6cSJohn Marino                              string_end - n);
153*ef5ccd6cSJohn Marino               if (endp == NULL)
154*ef5ccd6cSJohn Marino                 endp = string_end;
155*ef5ccd6cSJohn Marino 
156*ef5ccd6cSJohn Marino               if (c == L_('[')
157*ef5ccd6cSJohn Marino                   || (__builtin_expect (flags & FNM_EXTMATCH, 0) != 0
158*ef5ccd6cSJohn Marino                       && (c == L_('@') || c == L_('+') || c == L_('!'))
159*ef5ccd6cSJohn Marino                       && *p == L_('(')))
160*ef5ccd6cSJohn Marino                 {
161*ef5ccd6cSJohn Marino                   int flags2 = ((flags & FNM_FILE_NAME)
162*ef5ccd6cSJohn Marino                                 ? flags : (flags & ~FNM_PERIOD));
163*ef5ccd6cSJohn Marino                   bool no_leading_period2 = no_leading_period;
164*ef5ccd6cSJohn Marino 
165*ef5ccd6cSJohn Marino                   for (--p; n < endp; ++n, no_leading_period2 = false)
166*ef5ccd6cSJohn Marino                     if (FCT (p, n, string_end, no_leading_period2, flags2)
167*ef5ccd6cSJohn Marino                         == 0)
168*ef5ccd6cSJohn Marino                       return 0;
169*ef5ccd6cSJohn Marino                 }
170*ef5ccd6cSJohn Marino               else if (c == L_('/') && (flags & FNM_FILE_NAME))
171*ef5ccd6cSJohn Marino                 {
172*ef5ccd6cSJohn Marino                   while (n < string_end && *n != L_('/'))
173*ef5ccd6cSJohn Marino                     ++n;
174*ef5ccd6cSJohn Marino                   if (n < string_end && *n == L_('/')
175*ef5ccd6cSJohn Marino                       && (FCT (p, n + 1, string_end, flags & FNM_PERIOD, flags)
176*ef5ccd6cSJohn Marino                           == 0))
177*ef5ccd6cSJohn Marino                     return 0;
178*ef5ccd6cSJohn Marino                 }
179*ef5ccd6cSJohn Marino               else
180*ef5ccd6cSJohn Marino                 {
181*ef5ccd6cSJohn Marino                   int flags2 = ((flags & FNM_FILE_NAME)
182*ef5ccd6cSJohn Marino                                 ? flags : (flags & ~FNM_PERIOD));
183*ef5ccd6cSJohn Marino                   int no_leading_period2 = no_leading_period;
184*ef5ccd6cSJohn Marino 
185*ef5ccd6cSJohn Marino                   if (c == L_('\\') && !(flags & FNM_NOESCAPE))
186*ef5ccd6cSJohn Marino                     c = *p;
187*ef5ccd6cSJohn Marino                   c = FOLD (c);
188*ef5ccd6cSJohn Marino                   for (--p; n < endp; ++n, no_leading_period2 = false)
189*ef5ccd6cSJohn Marino                     if (FOLD ((UCHAR) *n) == c
190*ef5ccd6cSJohn Marino                         && (FCT (p, n, string_end, no_leading_period2, flags2)
191*ef5ccd6cSJohn Marino                             == 0))
192*ef5ccd6cSJohn Marino                       return 0;
193*ef5ccd6cSJohn Marino                 }
194*ef5ccd6cSJohn Marino             }
195*ef5ccd6cSJohn Marino 
196*ef5ccd6cSJohn Marino           /* If we come here no match is possible with the wildcard.  */
197*ef5ccd6cSJohn Marino           return FNM_NOMATCH;
198*ef5ccd6cSJohn Marino 
199*ef5ccd6cSJohn Marino         case L_('['):
200*ef5ccd6cSJohn Marino           {
201*ef5ccd6cSJohn Marino             /* Nonzero if the sense of the character class is inverted.  */
202*ef5ccd6cSJohn Marino             const CHAR *p_init = p;
203*ef5ccd6cSJohn Marino             const CHAR *n_init = n;
204*ef5ccd6cSJohn Marino             register bool not;
205*ef5ccd6cSJohn Marino             CHAR cold;
206*ef5ccd6cSJohn Marino             UCHAR fn;
207*ef5ccd6cSJohn Marino 
208*ef5ccd6cSJohn Marino             if (posixly_correct == 0)
209*ef5ccd6cSJohn Marino               posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
210*ef5ccd6cSJohn Marino 
211*ef5ccd6cSJohn Marino             if (n == string_end)
212*ef5ccd6cSJohn Marino               return FNM_NOMATCH;
213*ef5ccd6cSJohn Marino 
214*ef5ccd6cSJohn Marino             if (*n == L_('.') && no_leading_period)
215*ef5ccd6cSJohn Marino               return FNM_NOMATCH;
216*ef5ccd6cSJohn Marino 
217*ef5ccd6cSJohn Marino             if (*n == L_('/') && (flags & FNM_FILE_NAME))
218*ef5ccd6cSJohn Marino               /* '/' cannot be matched.  */
219*ef5ccd6cSJohn Marino               return FNM_NOMATCH;
220*ef5ccd6cSJohn Marino 
221*ef5ccd6cSJohn Marino             not = (*p == L_('!') || (posixly_correct < 0 && *p == L_('^')));
222*ef5ccd6cSJohn Marino             if (not)
223*ef5ccd6cSJohn Marino               ++p;
224*ef5ccd6cSJohn Marino 
225*ef5ccd6cSJohn Marino             fn = FOLD ((UCHAR) *n);
226*ef5ccd6cSJohn Marino 
227*ef5ccd6cSJohn Marino             c = *p++;
228*ef5ccd6cSJohn Marino             for (;;)
229*ef5ccd6cSJohn Marino               {
230*ef5ccd6cSJohn Marino                 if (!(flags & FNM_NOESCAPE) && c == L_('\\'))
231*ef5ccd6cSJohn Marino                   {
232*ef5ccd6cSJohn Marino                     if (*p == L_('\0'))
233*ef5ccd6cSJohn Marino                       return FNM_NOMATCH;
234*ef5ccd6cSJohn Marino                     c = FOLD ((UCHAR) *p);
235*ef5ccd6cSJohn Marino                     ++p;
236*ef5ccd6cSJohn Marino 
237*ef5ccd6cSJohn Marino                     goto normal_bracket;
238*ef5ccd6cSJohn Marino                   }
239*ef5ccd6cSJohn Marino                 else if (c == L_('[') && *p == L_(':'))
240*ef5ccd6cSJohn Marino                   {
241*ef5ccd6cSJohn Marino                     /* Leave room for the null.  */
242*ef5ccd6cSJohn Marino                     CHAR str[CHAR_CLASS_MAX_LENGTH + 1];
243*ef5ccd6cSJohn Marino                     size_t c1 = 0;
244*ef5ccd6cSJohn Marino #if defined _LIBC || WIDE_CHAR_SUPPORT
245*ef5ccd6cSJohn Marino                     wctype_t wt;
246*ef5ccd6cSJohn Marino #endif
247*ef5ccd6cSJohn Marino                     const CHAR *startp = p;
248*ef5ccd6cSJohn Marino 
249*ef5ccd6cSJohn Marino                     for (;;)
250*ef5ccd6cSJohn Marino                       {
251*ef5ccd6cSJohn Marino                         if (c1 == CHAR_CLASS_MAX_LENGTH)
252*ef5ccd6cSJohn Marino                           /* The name is too long and therefore the pattern
253*ef5ccd6cSJohn Marino                              is ill-formed.  */
254*ef5ccd6cSJohn Marino                           return FNM_NOMATCH;
255*ef5ccd6cSJohn Marino 
256*ef5ccd6cSJohn Marino                         c = *++p;
257*ef5ccd6cSJohn Marino                         if (c == L_(':') && p[1] == L_(']'))
258*ef5ccd6cSJohn Marino                           {
259*ef5ccd6cSJohn Marino                             p += 2;
260*ef5ccd6cSJohn Marino                             break;
261*ef5ccd6cSJohn Marino                           }
262*ef5ccd6cSJohn Marino                         if (c < L_('a') || c >= L_('z'))
263*ef5ccd6cSJohn Marino                           {
264*ef5ccd6cSJohn Marino                             /* This cannot possibly be a character class name.
265*ef5ccd6cSJohn Marino                                Match it as a normal range.  */
266*ef5ccd6cSJohn Marino                             p = startp;
267*ef5ccd6cSJohn Marino                             c = L_('[');
268*ef5ccd6cSJohn Marino                             goto normal_bracket;
269*ef5ccd6cSJohn Marino                           }
270*ef5ccd6cSJohn Marino                         str[c1++] = c;
271*ef5ccd6cSJohn Marino                       }
272*ef5ccd6cSJohn Marino                     str[c1] = L_('\0');
273*ef5ccd6cSJohn Marino 
274*ef5ccd6cSJohn Marino #if defined _LIBC || WIDE_CHAR_SUPPORT
275*ef5ccd6cSJohn Marino                     wt = IS_CHAR_CLASS (str);
276*ef5ccd6cSJohn Marino                     if (wt == 0)
277*ef5ccd6cSJohn Marino                       /* Invalid character class name.  */
278*ef5ccd6cSJohn Marino                       return FNM_NOMATCH;
279*ef5ccd6cSJohn Marino 
280*ef5ccd6cSJohn Marino # if defined _LIBC && ! WIDE_CHAR_VERSION
281*ef5ccd6cSJohn Marino                     /* The following code is glibc specific but does
282*ef5ccd6cSJohn Marino                        there a good job in speeding up the code since
283*ef5ccd6cSJohn Marino                        we can avoid the btowc() call.  */
284*ef5ccd6cSJohn Marino                     if (_ISCTYPE ((UCHAR) *n, wt))
285*ef5ccd6cSJohn Marino                       goto matched;
286*ef5ccd6cSJohn Marino # else
287*ef5ccd6cSJohn Marino                     if (ISWCTYPE (BTOWC ((UCHAR) *n), wt))
288*ef5ccd6cSJohn Marino                       goto matched;
289*ef5ccd6cSJohn Marino # endif
290*ef5ccd6cSJohn Marino #else
291*ef5ccd6cSJohn Marino                     if ((STREQ (str, L_("alnum")) && isalnum ((UCHAR) *n))
292*ef5ccd6cSJohn Marino                         || (STREQ (str, L_("alpha")) && isalpha ((UCHAR) *n))
293*ef5ccd6cSJohn Marino                         || (STREQ (str, L_("blank")) && isblank ((UCHAR) *n))
294*ef5ccd6cSJohn Marino                         || (STREQ (str, L_("cntrl")) && iscntrl ((UCHAR) *n))
295*ef5ccd6cSJohn Marino                         || (STREQ (str, L_("digit")) && isdigit ((UCHAR) *n))
296*ef5ccd6cSJohn Marino                         || (STREQ (str, L_("graph")) && isgraph ((UCHAR) *n))
297*ef5ccd6cSJohn Marino                         || (STREQ (str, L_("lower")) && islower ((UCHAR) *n))
298*ef5ccd6cSJohn Marino                         || (STREQ (str, L_("print")) && isprint ((UCHAR) *n))
299*ef5ccd6cSJohn Marino                         || (STREQ (str, L_("punct")) && ispunct ((UCHAR) *n))
300*ef5ccd6cSJohn Marino                         || (STREQ (str, L_("space")) && isspace ((UCHAR) *n))
301*ef5ccd6cSJohn Marino                         || (STREQ (str, L_("upper")) && isupper ((UCHAR) *n))
302*ef5ccd6cSJohn Marino                         || (STREQ (str, L_("xdigit")) && isxdigit ((UCHAR) *n)))
303*ef5ccd6cSJohn Marino                       goto matched;
304*ef5ccd6cSJohn Marino #endif
305*ef5ccd6cSJohn Marino                     c = *p++;
306*ef5ccd6cSJohn Marino                   }
307*ef5ccd6cSJohn Marino #ifdef _LIBC
308*ef5ccd6cSJohn Marino                 else if (c == L_('[') && *p == L_('='))
309*ef5ccd6cSJohn Marino                   {
310*ef5ccd6cSJohn Marino                     UCHAR str[1];
311*ef5ccd6cSJohn Marino                     uint32_t nrules =
312*ef5ccd6cSJohn Marino                       _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
313*ef5ccd6cSJohn Marino                     const CHAR *startp = p;
314*ef5ccd6cSJohn Marino 
315*ef5ccd6cSJohn Marino                     c = *++p;
316*ef5ccd6cSJohn Marino                     if (c == L_('\0'))
317*ef5ccd6cSJohn Marino                       {
318*ef5ccd6cSJohn Marino                         p = startp;
319*ef5ccd6cSJohn Marino                         c = L_('[');
320*ef5ccd6cSJohn Marino                         goto normal_bracket;
321*ef5ccd6cSJohn Marino                       }
322*ef5ccd6cSJohn Marino                     str[0] = c;
323*ef5ccd6cSJohn Marino 
324*ef5ccd6cSJohn Marino                     c = *++p;
325*ef5ccd6cSJohn Marino                     if (c != L_('=') || p[1] != L_(']'))
326*ef5ccd6cSJohn Marino                       {
327*ef5ccd6cSJohn Marino                         p = startp;
328*ef5ccd6cSJohn Marino                         c = L_('[');
329*ef5ccd6cSJohn Marino                         goto normal_bracket;
330*ef5ccd6cSJohn Marino                       }
331*ef5ccd6cSJohn Marino                     p += 2;
332*ef5ccd6cSJohn Marino 
333*ef5ccd6cSJohn Marino                     if (nrules == 0)
334*ef5ccd6cSJohn Marino                       {
335*ef5ccd6cSJohn Marino                         if ((UCHAR) *n == str[0])
336*ef5ccd6cSJohn Marino                           goto matched;
337*ef5ccd6cSJohn Marino                       }
338*ef5ccd6cSJohn Marino                     else
339*ef5ccd6cSJohn Marino                       {
340*ef5ccd6cSJohn Marino                         const int32_t *table;
341*ef5ccd6cSJohn Marino # if WIDE_CHAR_VERSION
342*ef5ccd6cSJohn Marino                         const int32_t *weights;
343*ef5ccd6cSJohn Marino                         const int32_t *extra;
344*ef5ccd6cSJohn Marino # else
345*ef5ccd6cSJohn Marino                         const unsigned char *weights;
346*ef5ccd6cSJohn Marino                         const unsigned char *extra;
347*ef5ccd6cSJohn Marino # endif
348*ef5ccd6cSJohn Marino                         const int32_t *indirect;
349*ef5ccd6cSJohn Marino                         int32_t idx;
350*ef5ccd6cSJohn Marino                         const UCHAR *cp = (const UCHAR *) str;
351*ef5ccd6cSJohn Marino 
352*ef5ccd6cSJohn Marino                         /* This #include defines a local function!  */
353*ef5ccd6cSJohn Marino # if WIDE_CHAR_VERSION
354*ef5ccd6cSJohn Marino #  include <locale/weightwc.h>
355*ef5ccd6cSJohn Marino # else
356*ef5ccd6cSJohn Marino #  include <locale/weight.h>
357*ef5ccd6cSJohn Marino # endif
358*ef5ccd6cSJohn Marino 
359*ef5ccd6cSJohn Marino # if WIDE_CHAR_VERSION
360*ef5ccd6cSJohn Marino                         table = (const int32_t *)
361*ef5ccd6cSJohn Marino                           _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEWC);
362*ef5ccd6cSJohn Marino                         weights = (const int32_t *)
363*ef5ccd6cSJohn Marino                           _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTWC);
364*ef5ccd6cSJohn Marino                         extra = (const int32_t *)
365*ef5ccd6cSJohn Marino                           _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAWC);
366*ef5ccd6cSJohn Marino                         indirect = (const int32_t *)
367*ef5ccd6cSJohn Marino                           _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTWC);
368*ef5ccd6cSJohn Marino # else
369*ef5ccd6cSJohn Marino                         table = (const int32_t *)
370*ef5ccd6cSJohn Marino                           _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
371*ef5ccd6cSJohn Marino                         weights = (const unsigned char *)
372*ef5ccd6cSJohn Marino                           _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB);
373*ef5ccd6cSJohn Marino                         extra = (const unsigned char *)
374*ef5ccd6cSJohn Marino                           _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
375*ef5ccd6cSJohn Marino                         indirect = (const int32_t *)
376*ef5ccd6cSJohn Marino                           _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB);
377*ef5ccd6cSJohn Marino # endif
378*ef5ccd6cSJohn Marino 
379*ef5ccd6cSJohn Marino                         idx = findidx (&cp);
380*ef5ccd6cSJohn Marino                         if (idx != 0)
381*ef5ccd6cSJohn Marino                           {
382*ef5ccd6cSJohn Marino                             /* We found a table entry.  Now see whether the
383*ef5ccd6cSJohn Marino                                character we are currently at has the same
384*ef5ccd6cSJohn Marino                                equivalence class value.  */
385*ef5ccd6cSJohn Marino                             int len = weights[idx & 0xffffff];
386*ef5ccd6cSJohn Marino                             int32_t idx2;
387*ef5ccd6cSJohn Marino                             const UCHAR *np = (const UCHAR *) n;
388*ef5ccd6cSJohn Marino 
389*ef5ccd6cSJohn Marino                             idx2 = findidx (&np);
390*ef5ccd6cSJohn Marino                             if (idx2 != 0
391*ef5ccd6cSJohn Marino                                 && (idx >> 24) == (idx2 >> 24)
392*ef5ccd6cSJohn Marino                                 && len == weights[idx2 & 0xffffff])
393*ef5ccd6cSJohn Marino                               {
394*ef5ccd6cSJohn Marino                                 int cnt = 0;
395*ef5ccd6cSJohn Marino 
396*ef5ccd6cSJohn Marino                                 idx &= 0xffffff;
397*ef5ccd6cSJohn Marino                                 idx2 &= 0xffffff;
398*ef5ccd6cSJohn Marino 
399*ef5ccd6cSJohn Marino                                 while (cnt < len
400*ef5ccd6cSJohn Marino                                        && (weights[idx + 1 + cnt]
401*ef5ccd6cSJohn Marino                                            == weights[idx2 + 1 + cnt]))
402*ef5ccd6cSJohn Marino                                   ++cnt;
403*ef5ccd6cSJohn Marino 
404*ef5ccd6cSJohn Marino                                 if (cnt == len)
405*ef5ccd6cSJohn Marino                                   goto matched;
406*ef5ccd6cSJohn Marino                               }
407*ef5ccd6cSJohn Marino                           }
408*ef5ccd6cSJohn Marino                       }
409*ef5ccd6cSJohn Marino 
410*ef5ccd6cSJohn Marino                     c = *p++;
411*ef5ccd6cSJohn Marino                   }
412*ef5ccd6cSJohn Marino #endif
413*ef5ccd6cSJohn Marino                 else if (c == L_('\0'))
414*ef5ccd6cSJohn Marino                   {
415*ef5ccd6cSJohn Marino                     /* [ unterminated, treat as normal character.  */
416*ef5ccd6cSJohn Marino                     p = p_init;
417*ef5ccd6cSJohn Marino                     n = n_init;
418*ef5ccd6cSJohn Marino                     c = L_('[');
419*ef5ccd6cSJohn Marino                     goto normal_match;
420*ef5ccd6cSJohn Marino                   }
421*ef5ccd6cSJohn Marino                 else
422*ef5ccd6cSJohn Marino                   {
423*ef5ccd6cSJohn Marino                     bool is_range = false;
424*ef5ccd6cSJohn Marino 
425*ef5ccd6cSJohn Marino #ifdef _LIBC
426*ef5ccd6cSJohn Marino                     bool is_seqval = false;
427*ef5ccd6cSJohn Marino 
428*ef5ccd6cSJohn Marino                     if (c == L_('[') && *p == L_('.'))
429*ef5ccd6cSJohn Marino                       {
430*ef5ccd6cSJohn Marino                         uint32_t nrules =
431*ef5ccd6cSJohn Marino                           _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
432*ef5ccd6cSJohn Marino                         const CHAR *startp = p;
433*ef5ccd6cSJohn Marino                         size_t c1 = 0;
434*ef5ccd6cSJohn Marino 
435*ef5ccd6cSJohn Marino                         while (1)
436*ef5ccd6cSJohn Marino                           {
437*ef5ccd6cSJohn Marino                             c = *++p;
438*ef5ccd6cSJohn Marino                             if (c == L_('.') && p[1] == L_(']'))
439*ef5ccd6cSJohn Marino                               {
440*ef5ccd6cSJohn Marino                                 p += 2;
441*ef5ccd6cSJohn Marino                                 break;
442*ef5ccd6cSJohn Marino                               }
443*ef5ccd6cSJohn Marino                             if (c == '\0')
444*ef5ccd6cSJohn Marino                               return FNM_NOMATCH;
445*ef5ccd6cSJohn Marino                             ++c1;
446*ef5ccd6cSJohn Marino                           }
447*ef5ccd6cSJohn Marino 
448*ef5ccd6cSJohn Marino                         /* We have to handling the symbols differently in
449*ef5ccd6cSJohn Marino                            ranges since then the collation sequence is
450*ef5ccd6cSJohn Marino                            important.  */
451*ef5ccd6cSJohn Marino                         is_range = *p == L_('-') && p[1] != L_('\0');
452*ef5ccd6cSJohn Marino 
453*ef5ccd6cSJohn Marino                         if (nrules == 0)
454*ef5ccd6cSJohn Marino                           {
455*ef5ccd6cSJohn Marino                             /* There are no names defined in the collation
456*ef5ccd6cSJohn Marino                                data.  Therefore we only accept the trivial
457*ef5ccd6cSJohn Marino                                names consisting of the character itself.  */
458*ef5ccd6cSJohn Marino                             if (c1 != 1)
459*ef5ccd6cSJohn Marino                               return FNM_NOMATCH;
460*ef5ccd6cSJohn Marino 
461*ef5ccd6cSJohn Marino                             if (!is_range && *n == startp[1])
462*ef5ccd6cSJohn Marino                               goto matched;
463*ef5ccd6cSJohn Marino 
464*ef5ccd6cSJohn Marino                             cold = startp[1];
465*ef5ccd6cSJohn Marino                             c = *p++;
466*ef5ccd6cSJohn Marino                           }
467*ef5ccd6cSJohn Marino                         else
468*ef5ccd6cSJohn Marino                           {
469*ef5ccd6cSJohn Marino                             int32_t table_size;
470*ef5ccd6cSJohn Marino                             const int32_t *symb_table;
471*ef5ccd6cSJohn Marino # ifdef WIDE_CHAR_VERSION
472*ef5ccd6cSJohn Marino                             char str[c1];
473*ef5ccd6cSJohn Marino                             size_t strcnt;
474*ef5ccd6cSJohn Marino # else
475*ef5ccd6cSJohn Marino #  define str (startp + 1)
476*ef5ccd6cSJohn Marino # endif
477*ef5ccd6cSJohn Marino                             const unsigned char *extra;
478*ef5ccd6cSJohn Marino                             int32_t idx;
479*ef5ccd6cSJohn Marino                             int32_t elem;
480*ef5ccd6cSJohn Marino                             int32_t second;
481*ef5ccd6cSJohn Marino                             int32_t hash;
482*ef5ccd6cSJohn Marino 
483*ef5ccd6cSJohn Marino # ifdef WIDE_CHAR_VERSION
484*ef5ccd6cSJohn Marino                             /* We have to convert the name to a single-byte
485*ef5ccd6cSJohn Marino                                string.  This is possible since the names
486*ef5ccd6cSJohn Marino                                consist of ASCII characters and the internal
487*ef5ccd6cSJohn Marino                                representation is UCS4.  */
488*ef5ccd6cSJohn Marino                             for (strcnt = 0; strcnt < c1; ++strcnt)
489*ef5ccd6cSJohn Marino                               str[strcnt] = startp[1 + strcnt];
490*ef5ccd6cSJohn Marino # endif
491*ef5ccd6cSJohn Marino 
492*ef5ccd6cSJohn Marino                             table_size =
493*ef5ccd6cSJohn Marino                               _NL_CURRENT_WORD (LC_COLLATE,
494*ef5ccd6cSJohn Marino                                                 _NL_COLLATE_SYMB_HASH_SIZEMB);
495*ef5ccd6cSJohn Marino                             symb_table = (const int32_t *)
496*ef5ccd6cSJohn Marino                               _NL_CURRENT (LC_COLLATE,
497*ef5ccd6cSJohn Marino                                            _NL_COLLATE_SYMB_TABLEMB);
498*ef5ccd6cSJohn Marino                             extra = (const unsigned char *)
499*ef5ccd6cSJohn Marino                               _NL_CURRENT (LC_COLLATE,
500*ef5ccd6cSJohn Marino                                            _NL_COLLATE_SYMB_EXTRAMB);
501*ef5ccd6cSJohn Marino 
502*ef5ccd6cSJohn Marino                             /* Locate the character in the hashing table.  */
503*ef5ccd6cSJohn Marino                             hash = elem_hash (str, c1);
504*ef5ccd6cSJohn Marino 
505*ef5ccd6cSJohn Marino                             idx = 0;
506*ef5ccd6cSJohn Marino                             elem = hash % table_size;
507*ef5ccd6cSJohn Marino                             if (symb_table[2 * elem] != 0)
508*ef5ccd6cSJohn Marino                               {
509*ef5ccd6cSJohn Marino                                 second = hash % (table_size - 2) + 1;
510*ef5ccd6cSJohn Marino 
511*ef5ccd6cSJohn Marino                                 do
512*ef5ccd6cSJohn Marino                                   {
513*ef5ccd6cSJohn Marino                                     /* First compare the hashing value.  */
514*ef5ccd6cSJohn Marino                                     if (symb_table[2 * elem] == hash
515*ef5ccd6cSJohn Marino                                         && (c1
516*ef5ccd6cSJohn Marino                                             == extra[symb_table[2 * elem + 1]])
517*ef5ccd6cSJohn Marino                                         && memcmp (str,
518*ef5ccd6cSJohn Marino                                                    &extra[symb_table[2 * elem
519*ef5ccd6cSJohn Marino                                                                      + 1]
520*ef5ccd6cSJohn Marino                                                           + 1], c1) == 0)
521*ef5ccd6cSJohn Marino                                       {
522*ef5ccd6cSJohn Marino                                         /* Yep, this is the entry.  */
523*ef5ccd6cSJohn Marino                                         idx = symb_table[2 * elem + 1];
524*ef5ccd6cSJohn Marino                                         idx += 1 + extra[idx];
525*ef5ccd6cSJohn Marino                                         break;
526*ef5ccd6cSJohn Marino                                       }
527*ef5ccd6cSJohn Marino 
528*ef5ccd6cSJohn Marino                                     /* Next entry.  */
529*ef5ccd6cSJohn Marino                                     elem += second;
530*ef5ccd6cSJohn Marino                                   }
531*ef5ccd6cSJohn Marino                                 while (symb_table[2 * elem] != 0);
532*ef5ccd6cSJohn Marino                               }
533*ef5ccd6cSJohn Marino 
534*ef5ccd6cSJohn Marino                             if (symb_table[2 * elem] != 0)
535*ef5ccd6cSJohn Marino                               {
536*ef5ccd6cSJohn Marino                                 /* Compare the byte sequence but only if
537*ef5ccd6cSJohn Marino                                    this is not part of a range.  */
538*ef5ccd6cSJohn Marino # ifdef WIDE_CHAR_VERSION
539*ef5ccd6cSJohn Marino                                 int32_t *wextra;
540*ef5ccd6cSJohn Marino 
541*ef5ccd6cSJohn Marino                                 idx += 1 + extra[idx];
542*ef5ccd6cSJohn Marino                                 /* Adjust for the alignment.  */
543*ef5ccd6cSJohn Marino                                 idx = (idx + 3) & ~3;
544*ef5ccd6cSJohn Marino 
545*ef5ccd6cSJohn Marino                                 wextra = (int32_t *) &extra[idx + 4];
546*ef5ccd6cSJohn Marino # endif
547*ef5ccd6cSJohn Marino 
548*ef5ccd6cSJohn Marino                                 if (! is_range)
549*ef5ccd6cSJohn Marino                                   {
550*ef5ccd6cSJohn Marino # ifdef WIDE_CHAR_VERSION
551*ef5ccd6cSJohn Marino                                     for (c1 = 0;
552*ef5ccd6cSJohn Marino                                          (int32_t) c1 < wextra[idx];
553*ef5ccd6cSJohn Marino                                          ++c1)
554*ef5ccd6cSJohn Marino                                       if (n[c1] != wextra[1 + c1])
555*ef5ccd6cSJohn Marino                                         break;
556*ef5ccd6cSJohn Marino 
557*ef5ccd6cSJohn Marino                                     if ((int32_t) c1 == wextra[idx])
558*ef5ccd6cSJohn Marino                                       goto matched;
559*ef5ccd6cSJohn Marino # else
560*ef5ccd6cSJohn Marino                                     for (c1 = 0; c1 < extra[idx]; ++c1)
561*ef5ccd6cSJohn Marino                                       if (n[c1] != extra[1 + c1])
562*ef5ccd6cSJohn Marino                                         break;
563*ef5ccd6cSJohn Marino 
564*ef5ccd6cSJohn Marino                                     if (c1 == extra[idx])
565*ef5ccd6cSJohn Marino                                       goto matched;
566*ef5ccd6cSJohn Marino # endif
567*ef5ccd6cSJohn Marino                                   }
568*ef5ccd6cSJohn Marino 
569*ef5ccd6cSJohn Marino                                 /* Get the collation sequence value.  */
570*ef5ccd6cSJohn Marino                                 is_seqval = true;
571*ef5ccd6cSJohn Marino # ifdef WIDE_CHAR_VERSION
572*ef5ccd6cSJohn Marino                                 cold = wextra[1 + wextra[idx]];
573*ef5ccd6cSJohn Marino # else
574*ef5ccd6cSJohn Marino                                 /* Adjust for the alignment.  */
575*ef5ccd6cSJohn Marino                                 idx += 1 + extra[idx];
576*ef5ccd6cSJohn Marino                                 idx = (idx + 3) & ~4;
577*ef5ccd6cSJohn Marino                                 cold = *((int32_t *) &extra[idx]);
578*ef5ccd6cSJohn Marino # endif
579*ef5ccd6cSJohn Marino 
580*ef5ccd6cSJohn Marino                                 c = *p++;
581*ef5ccd6cSJohn Marino                               }
582*ef5ccd6cSJohn Marino                             else if (c1 == 1)
583*ef5ccd6cSJohn Marino                               {
584*ef5ccd6cSJohn Marino                                 /* No valid character.  Match it as a
585*ef5ccd6cSJohn Marino                                    single byte.  */
586*ef5ccd6cSJohn Marino                                 if (!is_range && *n == str[0])
587*ef5ccd6cSJohn Marino                                   goto matched;
588*ef5ccd6cSJohn Marino 
589*ef5ccd6cSJohn Marino                                 cold = str[0];
590*ef5ccd6cSJohn Marino                                 c = *p++;
591*ef5ccd6cSJohn Marino                               }
592*ef5ccd6cSJohn Marino                             else
593*ef5ccd6cSJohn Marino                               return FNM_NOMATCH;
594*ef5ccd6cSJohn Marino                           }
595*ef5ccd6cSJohn Marino                       }
596*ef5ccd6cSJohn Marino                     else
597*ef5ccd6cSJohn Marino # undef str
598*ef5ccd6cSJohn Marino #endif
599*ef5ccd6cSJohn Marino                       {
600*ef5ccd6cSJohn Marino                         c = FOLD (c);
601*ef5ccd6cSJohn Marino                       normal_bracket:
602*ef5ccd6cSJohn Marino 
603*ef5ccd6cSJohn Marino                         /* We have to handling the symbols differently in
604*ef5ccd6cSJohn Marino                            ranges since then the collation sequence is
605*ef5ccd6cSJohn Marino                            important.  */
606*ef5ccd6cSJohn Marino                         is_range = (*p == L_('-') && p[1] != L_('\0')
607*ef5ccd6cSJohn Marino                                     && p[1] != L_(']'));
608*ef5ccd6cSJohn Marino 
609*ef5ccd6cSJohn Marino                         if (!is_range && c == fn)
610*ef5ccd6cSJohn Marino                           goto matched;
611*ef5ccd6cSJohn Marino 
612*ef5ccd6cSJohn Marino #if _LIBC
613*ef5ccd6cSJohn Marino                         /* This is needed if we goto normal_bracket; from
614*ef5ccd6cSJohn Marino                            outside of is_seqval's scope.  */
615*ef5ccd6cSJohn Marino                         is_seqval = false;
616*ef5ccd6cSJohn Marino #endif
617*ef5ccd6cSJohn Marino 
618*ef5ccd6cSJohn Marino                         cold = c;
619*ef5ccd6cSJohn Marino                         c = *p++;
620*ef5ccd6cSJohn Marino                       }
621*ef5ccd6cSJohn Marino 
622*ef5ccd6cSJohn Marino                     if (c == L_('-') && *p != L_(']'))
623*ef5ccd6cSJohn Marino                       {
624*ef5ccd6cSJohn Marino #if _LIBC
625*ef5ccd6cSJohn Marino                         /* We have to find the collation sequence
626*ef5ccd6cSJohn Marino                            value for C.  Collation sequence is nothing
627*ef5ccd6cSJohn Marino                            we can regularly access.  The sequence
628*ef5ccd6cSJohn Marino                            value is defined by the order in which the
629*ef5ccd6cSJohn Marino                            definitions of the collation values for the
630*ef5ccd6cSJohn Marino                            various characters appear in the source
631*ef5ccd6cSJohn Marino                            file.  A strange concept, nowhere
632*ef5ccd6cSJohn Marino                            documented.  */
633*ef5ccd6cSJohn Marino                         uint32_t fcollseq;
634*ef5ccd6cSJohn Marino                         uint32_t lcollseq;
635*ef5ccd6cSJohn Marino                         UCHAR cend = *p++;
636*ef5ccd6cSJohn Marino 
637*ef5ccd6cSJohn Marino # ifdef WIDE_CHAR_VERSION
638*ef5ccd6cSJohn Marino                         /* Search in the 'names' array for the characters.  */
639*ef5ccd6cSJohn Marino                         fcollseq = __collseq_table_lookup (collseq, fn);
640*ef5ccd6cSJohn Marino                         if (fcollseq == ~((uint32_t) 0))
641*ef5ccd6cSJohn Marino                           /* XXX We don't know anything about the character
642*ef5ccd6cSJohn Marino                              we are supposed to match.  This means we are
643*ef5ccd6cSJohn Marino                              failing.  */
644*ef5ccd6cSJohn Marino                           goto range_not_matched;
645*ef5ccd6cSJohn Marino 
646*ef5ccd6cSJohn Marino                         if (is_seqval)
647*ef5ccd6cSJohn Marino                           lcollseq = cold;
648*ef5ccd6cSJohn Marino                         else
649*ef5ccd6cSJohn Marino                           lcollseq = __collseq_table_lookup (collseq, cold);
650*ef5ccd6cSJohn Marino # else
651*ef5ccd6cSJohn Marino                         fcollseq = collseq[fn];
652*ef5ccd6cSJohn Marino                         lcollseq = is_seqval ? cold : collseq[(UCHAR) cold];
653*ef5ccd6cSJohn Marino # endif
654*ef5ccd6cSJohn Marino 
655*ef5ccd6cSJohn Marino                         is_seqval = false;
656*ef5ccd6cSJohn Marino                         if (cend == L_('[') && *p == L_('.'))
657*ef5ccd6cSJohn Marino                           {
658*ef5ccd6cSJohn Marino                             uint32_t nrules =
659*ef5ccd6cSJohn Marino                               _NL_CURRENT_WORD (LC_COLLATE,
660*ef5ccd6cSJohn Marino                                                 _NL_COLLATE_NRULES);
661*ef5ccd6cSJohn Marino                             const CHAR *startp = p;
662*ef5ccd6cSJohn Marino                             size_t c1 = 0;
663*ef5ccd6cSJohn Marino 
664*ef5ccd6cSJohn Marino                             while (1)
665*ef5ccd6cSJohn Marino                               {
666*ef5ccd6cSJohn Marino                                 c = *++p;
667*ef5ccd6cSJohn Marino                                 if (c == L_('.') && p[1] == L_(']'))
668*ef5ccd6cSJohn Marino                                   {
669*ef5ccd6cSJohn Marino                                     p += 2;
670*ef5ccd6cSJohn Marino                                     break;
671*ef5ccd6cSJohn Marino                                   }
672*ef5ccd6cSJohn Marino                                 if (c == '\0')
673*ef5ccd6cSJohn Marino                                   return FNM_NOMATCH;
674*ef5ccd6cSJohn Marino                                 ++c1;
675*ef5ccd6cSJohn Marino                               }
676*ef5ccd6cSJohn Marino 
677*ef5ccd6cSJohn Marino                             if (nrules == 0)
678*ef5ccd6cSJohn Marino                               {
679*ef5ccd6cSJohn Marino                                 /* There are no names defined in the
680*ef5ccd6cSJohn Marino                                    collation data.  Therefore we only
681*ef5ccd6cSJohn Marino                                    accept the trivial names consisting
682*ef5ccd6cSJohn Marino                                    of the character itself.  */
683*ef5ccd6cSJohn Marino                                 if (c1 != 1)
684*ef5ccd6cSJohn Marino                                   return FNM_NOMATCH;
685*ef5ccd6cSJohn Marino 
686*ef5ccd6cSJohn Marino                                 cend = startp[1];
687*ef5ccd6cSJohn Marino                               }
688*ef5ccd6cSJohn Marino                             else
689*ef5ccd6cSJohn Marino                               {
690*ef5ccd6cSJohn Marino                                 int32_t table_size;
691*ef5ccd6cSJohn Marino                                 const int32_t *symb_table;
692*ef5ccd6cSJohn Marino # ifdef WIDE_CHAR_VERSION
693*ef5ccd6cSJohn Marino                                 char str[c1];
694*ef5ccd6cSJohn Marino                                 size_t strcnt;
695*ef5ccd6cSJohn Marino # else
696*ef5ccd6cSJohn Marino #  define str (startp + 1)
697*ef5ccd6cSJohn Marino # endif
698*ef5ccd6cSJohn Marino                                 const unsigned char *extra;
699*ef5ccd6cSJohn Marino                                 int32_t idx;
700*ef5ccd6cSJohn Marino                                 int32_t elem;
701*ef5ccd6cSJohn Marino                                 int32_t second;
702*ef5ccd6cSJohn Marino                                 int32_t hash;
703*ef5ccd6cSJohn Marino 
704*ef5ccd6cSJohn Marino # ifdef WIDE_CHAR_VERSION
705*ef5ccd6cSJohn Marino                                 /* We have to convert the name to a single-byte
706*ef5ccd6cSJohn Marino                                    string.  This is possible since the names
707*ef5ccd6cSJohn Marino                                    consist of ASCII characters and the internal
708*ef5ccd6cSJohn Marino                                    representation is UCS4.  */
709*ef5ccd6cSJohn Marino                                 for (strcnt = 0; strcnt < c1; ++strcnt)
710*ef5ccd6cSJohn Marino                                   str[strcnt] = startp[1 + strcnt];
711*ef5ccd6cSJohn Marino # endif
712*ef5ccd6cSJohn Marino 
713*ef5ccd6cSJohn Marino                                 table_size =
714*ef5ccd6cSJohn Marino                                   _NL_CURRENT_WORD (LC_COLLATE,
715*ef5ccd6cSJohn Marino                                                     _NL_COLLATE_SYMB_HASH_SIZEMB);
716*ef5ccd6cSJohn Marino                                 symb_table = (const int32_t *)
717*ef5ccd6cSJohn Marino                                   _NL_CURRENT (LC_COLLATE,
718*ef5ccd6cSJohn Marino                                                _NL_COLLATE_SYMB_TABLEMB);
719*ef5ccd6cSJohn Marino                                 extra = (const unsigned char *)
720*ef5ccd6cSJohn Marino                                   _NL_CURRENT (LC_COLLATE,
721*ef5ccd6cSJohn Marino                                                _NL_COLLATE_SYMB_EXTRAMB);
722*ef5ccd6cSJohn Marino 
723*ef5ccd6cSJohn Marino                                 /* Locate the character in the hashing
724*ef5ccd6cSJohn Marino                                    table.  */
725*ef5ccd6cSJohn Marino                                 hash = elem_hash (str, c1);
726*ef5ccd6cSJohn Marino 
727*ef5ccd6cSJohn Marino                                 idx = 0;
728*ef5ccd6cSJohn Marino                                 elem = hash % table_size;
729*ef5ccd6cSJohn Marino                                 if (symb_table[2 * elem] != 0)
730*ef5ccd6cSJohn Marino                                   {
731*ef5ccd6cSJohn Marino                                     second = hash % (table_size - 2) + 1;
732*ef5ccd6cSJohn Marino 
733*ef5ccd6cSJohn Marino                                     do
734*ef5ccd6cSJohn Marino                                       {
735*ef5ccd6cSJohn Marino                                         /* First compare the hashing value.  */
736*ef5ccd6cSJohn Marino                                         if (symb_table[2 * elem] == hash
737*ef5ccd6cSJohn Marino                                             && (c1
738*ef5ccd6cSJohn Marino                                                 == extra[symb_table[2 * elem + 1]])
739*ef5ccd6cSJohn Marino                                             && memcmp (str,
740*ef5ccd6cSJohn Marino                                                        &extra[symb_table[2 * elem + 1]
741*ef5ccd6cSJohn Marino                                                               + 1], c1) == 0)
742*ef5ccd6cSJohn Marino                                           {
743*ef5ccd6cSJohn Marino                                             /* Yep, this is the entry.  */
744*ef5ccd6cSJohn Marino                                             idx = symb_table[2 * elem + 1];
745*ef5ccd6cSJohn Marino                                             idx += 1 + extra[idx];
746*ef5ccd6cSJohn Marino                                             break;
747*ef5ccd6cSJohn Marino                                           }
748*ef5ccd6cSJohn Marino 
749*ef5ccd6cSJohn Marino                                         /* Next entry.  */
750*ef5ccd6cSJohn Marino                                         elem += second;
751*ef5ccd6cSJohn Marino                                       }
752*ef5ccd6cSJohn Marino                                     while (symb_table[2 * elem] != 0);
753*ef5ccd6cSJohn Marino                                   }
754*ef5ccd6cSJohn Marino 
755*ef5ccd6cSJohn Marino                                 if (symb_table[2 * elem] != 0)
756*ef5ccd6cSJohn Marino                                   {
757*ef5ccd6cSJohn Marino                                     /* Compare the byte sequence but only if
758*ef5ccd6cSJohn Marino                                        this is not part of a range.  */
759*ef5ccd6cSJohn Marino # ifdef WIDE_CHAR_VERSION
760*ef5ccd6cSJohn Marino                                     int32_t *wextra;
761*ef5ccd6cSJohn Marino 
762*ef5ccd6cSJohn Marino                                     idx += 1 + extra[idx];
763*ef5ccd6cSJohn Marino                                     /* Adjust for the alignment.  */
764*ef5ccd6cSJohn Marino                                     idx = (idx + 3) & ~4;
765*ef5ccd6cSJohn Marino 
766*ef5ccd6cSJohn Marino                                     wextra = (int32_t *) &extra[idx + 4];
767*ef5ccd6cSJohn Marino # endif
768*ef5ccd6cSJohn Marino                                     /* Get the collation sequence value.  */
769*ef5ccd6cSJohn Marino                                     is_seqval = true;
770*ef5ccd6cSJohn Marino # ifdef WIDE_CHAR_VERSION
771*ef5ccd6cSJohn Marino                                     cend = wextra[1 + wextra[idx]];
772*ef5ccd6cSJohn Marino # else
773*ef5ccd6cSJohn Marino                                     /* Adjust for the alignment.  */
774*ef5ccd6cSJohn Marino                                     idx += 1 + extra[idx];
775*ef5ccd6cSJohn Marino                                     idx = (idx + 3) & ~4;
776*ef5ccd6cSJohn Marino                                     cend = *((int32_t *) &extra[idx]);
777*ef5ccd6cSJohn Marino # endif
778*ef5ccd6cSJohn Marino                                   }
779*ef5ccd6cSJohn Marino                                 else if (symb_table[2 * elem] != 0 && c1 == 1)
780*ef5ccd6cSJohn Marino                                   {
781*ef5ccd6cSJohn Marino                                     cend = str[0];
782*ef5ccd6cSJohn Marino                                     c = *p++;
783*ef5ccd6cSJohn Marino                                   }
784*ef5ccd6cSJohn Marino                                 else
785*ef5ccd6cSJohn Marino                                   return FNM_NOMATCH;
786*ef5ccd6cSJohn Marino                               }
787*ef5ccd6cSJohn Marino # undef str
788*ef5ccd6cSJohn Marino                           }
789*ef5ccd6cSJohn Marino                         else
790*ef5ccd6cSJohn Marino                           {
791*ef5ccd6cSJohn Marino                             if (!(flags & FNM_NOESCAPE) && cend == L_('\\'))
792*ef5ccd6cSJohn Marino                               cend = *p++;
793*ef5ccd6cSJohn Marino                             if (cend == L_('\0'))
794*ef5ccd6cSJohn Marino                               return FNM_NOMATCH;
795*ef5ccd6cSJohn Marino                             cend = FOLD (cend);
796*ef5ccd6cSJohn Marino                           }
797*ef5ccd6cSJohn Marino 
798*ef5ccd6cSJohn Marino                         /* XXX It is not entirely clear to me how to handle
799*ef5ccd6cSJohn Marino                            characters which are not mentioned in the
800*ef5ccd6cSJohn Marino                            collation specification.  */
801*ef5ccd6cSJohn Marino                         if (
802*ef5ccd6cSJohn Marino # ifdef WIDE_CHAR_VERSION
803*ef5ccd6cSJohn Marino                             lcollseq == 0xffffffff ||
804*ef5ccd6cSJohn Marino # endif
805*ef5ccd6cSJohn Marino                             lcollseq <= fcollseq)
806*ef5ccd6cSJohn Marino                           {
807*ef5ccd6cSJohn Marino                             /* We have to look at the upper bound.  */
808*ef5ccd6cSJohn Marino                             uint32_t hcollseq;
809*ef5ccd6cSJohn Marino 
810*ef5ccd6cSJohn Marino                             if (is_seqval)
811*ef5ccd6cSJohn Marino                               hcollseq = cend;
812*ef5ccd6cSJohn Marino                             else
813*ef5ccd6cSJohn Marino                               {
814*ef5ccd6cSJohn Marino # ifdef WIDE_CHAR_VERSION
815*ef5ccd6cSJohn Marino                                 hcollseq =
816*ef5ccd6cSJohn Marino                                   __collseq_table_lookup (collseq, cend);
817*ef5ccd6cSJohn Marino                                 if (hcollseq == ~((uint32_t) 0))
818*ef5ccd6cSJohn Marino                                   {
819*ef5ccd6cSJohn Marino                                     /* Hum, no information about the upper
820*ef5ccd6cSJohn Marino                                        bound.  The matching succeeds if the
821*ef5ccd6cSJohn Marino                                        lower bound is matched exactly.  */
822*ef5ccd6cSJohn Marino                                     if (lcollseq != fcollseq)
823*ef5ccd6cSJohn Marino                                       goto range_not_matched;
824*ef5ccd6cSJohn Marino 
825*ef5ccd6cSJohn Marino                                     goto matched;
826*ef5ccd6cSJohn Marino                                   }
827*ef5ccd6cSJohn Marino # else
828*ef5ccd6cSJohn Marino                                 hcollseq = collseq[cend];
829*ef5ccd6cSJohn Marino # endif
830*ef5ccd6cSJohn Marino                               }
831*ef5ccd6cSJohn Marino 
832*ef5ccd6cSJohn Marino                             if (lcollseq <= hcollseq && fcollseq <= hcollseq)
833*ef5ccd6cSJohn Marino                               goto matched;
834*ef5ccd6cSJohn Marino                           }
835*ef5ccd6cSJohn Marino # ifdef WIDE_CHAR_VERSION
836*ef5ccd6cSJohn Marino                       range_not_matched:
837*ef5ccd6cSJohn Marino # endif
838*ef5ccd6cSJohn Marino #else
839*ef5ccd6cSJohn Marino                         /* We use a boring value comparison of the character
840*ef5ccd6cSJohn Marino                            values.  This is better than comparing using
841*ef5ccd6cSJohn Marino                            'strcoll' since the latter would have surprising
842*ef5ccd6cSJohn Marino                            and sometimes fatal consequences.  */
843*ef5ccd6cSJohn Marino                         UCHAR cend = *p++;
844*ef5ccd6cSJohn Marino 
845*ef5ccd6cSJohn Marino                         if (!(flags & FNM_NOESCAPE) && cend == L_('\\'))
846*ef5ccd6cSJohn Marino                           cend = *p++;
847*ef5ccd6cSJohn Marino                         if (cend == L_('\0'))
848*ef5ccd6cSJohn Marino                           return FNM_NOMATCH;
849*ef5ccd6cSJohn Marino 
850*ef5ccd6cSJohn Marino                         /* It is a range.  */
851*ef5ccd6cSJohn Marino                         if (cold <= fn && fn <= cend)
852*ef5ccd6cSJohn Marino                           goto matched;
853*ef5ccd6cSJohn Marino #endif
854*ef5ccd6cSJohn Marino 
855*ef5ccd6cSJohn Marino                         c = *p++;
856*ef5ccd6cSJohn Marino                       }
857*ef5ccd6cSJohn Marino                   }
858*ef5ccd6cSJohn Marino 
859*ef5ccd6cSJohn Marino                 if (c == L_(']'))
860*ef5ccd6cSJohn Marino                   break;
861*ef5ccd6cSJohn Marino               }
862*ef5ccd6cSJohn Marino 
863*ef5ccd6cSJohn Marino             if (!not)
864*ef5ccd6cSJohn Marino               return FNM_NOMATCH;
865*ef5ccd6cSJohn Marino             break;
866*ef5ccd6cSJohn Marino 
867*ef5ccd6cSJohn Marino           matched:
868*ef5ccd6cSJohn Marino             /* Skip the rest of the [...] that already matched.  */
869*ef5ccd6cSJohn Marino             do
870*ef5ccd6cSJohn Marino               {
871*ef5ccd6cSJohn Marino               ignore_next:
872*ef5ccd6cSJohn Marino                 c = *p++;
873*ef5ccd6cSJohn Marino 
874*ef5ccd6cSJohn Marino                 if (c == L_('\0'))
875*ef5ccd6cSJohn Marino                   /* [... (unterminated) loses.  */
876*ef5ccd6cSJohn Marino                   return FNM_NOMATCH;
877*ef5ccd6cSJohn Marino 
878*ef5ccd6cSJohn Marino                 if (!(flags & FNM_NOESCAPE) && c == L_('\\'))
879*ef5ccd6cSJohn Marino                   {
880*ef5ccd6cSJohn Marino                     if (*p == L_('\0'))
881*ef5ccd6cSJohn Marino                       return FNM_NOMATCH;
882*ef5ccd6cSJohn Marino                     /* XXX 1003.2d11 is unclear if this is right.  */
883*ef5ccd6cSJohn Marino                     ++p;
884*ef5ccd6cSJohn Marino                   }
885*ef5ccd6cSJohn Marino                 else if (c == L_('[') && *p == L_(':'))
886*ef5ccd6cSJohn Marino                   {
887*ef5ccd6cSJohn Marino                     int c1 = 0;
888*ef5ccd6cSJohn Marino                     const CHAR *startp = p;
889*ef5ccd6cSJohn Marino 
890*ef5ccd6cSJohn Marino                     while (1)
891*ef5ccd6cSJohn Marino                       {
892*ef5ccd6cSJohn Marino                         c = *++p;
893*ef5ccd6cSJohn Marino                         if (++c1 == CHAR_CLASS_MAX_LENGTH)
894*ef5ccd6cSJohn Marino                           return FNM_NOMATCH;
895*ef5ccd6cSJohn Marino 
896*ef5ccd6cSJohn Marino                         if (*p == L_(':') && p[1] == L_(']'))
897*ef5ccd6cSJohn Marino                           break;
898*ef5ccd6cSJohn Marino 
899*ef5ccd6cSJohn Marino                         if (c < L_('a') || c >= L_('z'))
900*ef5ccd6cSJohn Marino                           {
901*ef5ccd6cSJohn Marino                             p = startp;
902*ef5ccd6cSJohn Marino                             goto ignore_next;
903*ef5ccd6cSJohn Marino                           }
904*ef5ccd6cSJohn Marino                       }
905*ef5ccd6cSJohn Marino                     p += 2;
906*ef5ccd6cSJohn Marino                     c = *p++;
907*ef5ccd6cSJohn Marino                   }
908*ef5ccd6cSJohn Marino                 else if (c == L_('[') && *p == L_('='))
909*ef5ccd6cSJohn Marino                   {
910*ef5ccd6cSJohn Marino                     c = *++p;
911*ef5ccd6cSJohn Marino                     if (c == L_('\0'))
912*ef5ccd6cSJohn Marino                       return FNM_NOMATCH;
913*ef5ccd6cSJohn Marino                     c = *++p;
914*ef5ccd6cSJohn Marino                     if (c != L_('=') || p[1] != L_(']'))
915*ef5ccd6cSJohn Marino                       return FNM_NOMATCH;
916*ef5ccd6cSJohn Marino                     p += 2;
917*ef5ccd6cSJohn Marino                     c = *p++;
918*ef5ccd6cSJohn Marino                   }
919*ef5ccd6cSJohn Marino                 else if (c == L_('[') && *p == L_('.'))
920*ef5ccd6cSJohn Marino                   {
921*ef5ccd6cSJohn Marino                     ++p;
922*ef5ccd6cSJohn Marino                     while (1)
923*ef5ccd6cSJohn Marino                       {
924*ef5ccd6cSJohn Marino                         c = *++p;
925*ef5ccd6cSJohn Marino                         if (c == '\0')
926*ef5ccd6cSJohn Marino                           return FNM_NOMATCH;
927*ef5ccd6cSJohn Marino 
928*ef5ccd6cSJohn Marino                         if (*p == L_('.') && p[1] == L_(']'))
929*ef5ccd6cSJohn Marino                           break;
930*ef5ccd6cSJohn Marino                       }
931*ef5ccd6cSJohn Marino                     p += 2;
932*ef5ccd6cSJohn Marino                     c = *p++;
933*ef5ccd6cSJohn Marino                   }
934*ef5ccd6cSJohn Marino               }
935*ef5ccd6cSJohn Marino             while (c != L_(']'));
936*ef5ccd6cSJohn Marino             if (not)
937*ef5ccd6cSJohn Marino               return FNM_NOMATCH;
938*ef5ccd6cSJohn Marino           }
939*ef5ccd6cSJohn Marino           break;
940*ef5ccd6cSJohn Marino 
941*ef5ccd6cSJohn Marino         case L_('+'):
942*ef5ccd6cSJohn Marino         case L_('@'):
943*ef5ccd6cSJohn Marino         case L_('!'):
944*ef5ccd6cSJohn Marino           if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
945*ef5ccd6cSJohn Marino             {
946*ef5ccd6cSJohn Marino               int res;
947*ef5ccd6cSJohn Marino 
948*ef5ccd6cSJohn Marino               res = EXT (c, p, n, string_end, no_leading_period, flags);
949*ef5ccd6cSJohn Marino               if (res != -1)
950*ef5ccd6cSJohn Marino                 return res;
951*ef5ccd6cSJohn Marino             }
952*ef5ccd6cSJohn Marino           goto normal_match;
953*ef5ccd6cSJohn Marino 
954*ef5ccd6cSJohn Marino         case L_('/'):
955*ef5ccd6cSJohn Marino           if (NO_LEADING_PERIOD (flags))
956*ef5ccd6cSJohn Marino             {
957*ef5ccd6cSJohn Marino               if (n == string_end || c != (UCHAR) *n)
958*ef5ccd6cSJohn Marino                 return FNM_NOMATCH;
959*ef5ccd6cSJohn Marino 
960*ef5ccd6cSJohn Marino               new_no_leading_period = true;
961*ef5ccd6cSJohn Marino               break;
962*ef5ccd6cSJohn Marino             }
963*ef5ccd6cSJohn Marino           /* FALLTHROUGH */
964*ef5ccd6cSJohn Marino         default:
965*ef5ccd6cSJohn Marino         normal_match:
966*ef5ccd6cSJohn Marino           if (n == string_end || c != FOLD ((UCHAR) *n))
967*ef5ccd6cSJohn Marino             return FNM_NOMATCH;
968*ef5ccd6cSJohn Marino         }
969*ef5ccd6cSJohn Marino 
970*ef5ccd6cSJohn Marino       no_leading_period = new_no_leading_period;
971*ef5ccd6cSJohn Marino       ++n;
972*ef5ccd6cSJohn Marino     }
973*ef5ccd6cSJohn Marino 
974*ef5ccd6cSJohn Marino   if (n == string_end)
975*ef5ccd6cSJohn Marino     return 0;
976*ef5ccd6cSJohn Marino 
977*ef5ccd6cSJohn Marino   if ((flags & FNM_LEADING_DIR) && n != string_end && *n == L_('/'))
978*ef5ccd6cSJohn Marino     /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
979*ef5ccd6cSJohn Marino     return 0;
980*ef5ccd6cSJohn Marino 
981*ef5ccd6cSJohn Marino   return FNM_NOMATCH;
982*ef5ccd6cSJohn Marino }
983*ef5ccd6cSJohn Marino 
984*ef5ccd6cSJohn Marino 
985*ef5ccd6cSJohn Marino static const CHAR *
986*ef5ccd6cSJohn Marino internal_function
END(const CHAR * pattern)987*ef5ccd6cSJohn Marino END (const CHAR *pattern)
988*ef5ccd6cSJohn Marino {
989*ef5ccd6cSJohn Marino   const CHAR *p = pattern;
990*ef5ccd6cSJohn Marino 
991*ef5ccd6cSJohn Marino   while (1)
992*ef5ccd6cSJohn Marino     if (*++p == L_('\0'))
993*ef5ccd6cSJohn Marino       /* This is an invalid pattern.  */
994*ef5ccd6cSJohn Marino       return pattern;
995*ef5ccd6cSJohn Marino     else if (*p == L_('['))
996*ef5ccd6cSJohn Marino       {
997*ef5ccd6cSJohn Marino         /* Handle brackets special.  */
998*ef5ccd6cSJohn Marino         if (posixly_correct == 0)
999*ef5ccd6cSJohn Marino           posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
1000*ef5ccd6cSJohn Marino 
1001*ef5ccd6cSJohn Marino         /* Skip the not sign.  We have to recognize it because of a possibly
1002*ef5ccd6cSJohn Marino            following ']'.  */
1003*ef5ccd6cSJohn Marino         if (*++p == L_('!') || (posixly_correct < 0 && *p == L_('^')))
1004*ef5ccd6cSJohn Marino           ++p;
1005*ef5ccd6cSJohn Marino         /* A leading ']' is recognized as such.  */
1006*ef5ccd6cSJohn Marino         if (*p == L_(']'))
1007*ef5ccd6cSJohn Marino           ++p;
1008*ef5ccd6cSJohn Marino         /* Skip over all characters of the list.  */
1009*ef5ccd6cSJohn Marino         while (*p != L_(']'))
1010*ef5ccd6cSJohn Marino           if (*p++ == L_('\0'))
1011*ef5ccd6cSJohn Marino             /* This is no valid pattern.  */
1012*ef5ccd6cSJohn Marino             return pattern;
1013*ef5ccd6cSJohn Marino       }
1014*ef5ccd6cSJohn Marino     else if ((*p == L_('?') || *p == L_('*') || *p == L_('+') || *p == L_('@')
1015*ef5ccd6cSJohn Marino               || *p == L_('!')) && p[1] == L_('('))
1016*ef5ccd6cSJohn Marino       p = END (p + 1);
1017*ef5ccd6cSJohn Marino     else if (*p == L_(')'))
1018*ef5ccd6cSJohn Marino       break;
1019*ef5ccd6cSJohn Marino 
1020*ef5ccd6cSJohn Marino   return p + 1;
1021*ef5ccd6cSJohn Marino }
1022*ef5ccd6cSJohn Marino 
1023*ef5ccd6cSJohn Marino 
1024*ef5ccd6cSJohn Marino static int
1025*ef5ccd6cSJohn Marino internal_function
EXT(INT opt,const CHAR * pattern,const CHAR * string,const CHAR * string_end,bool no_leading_period,int flags)1026*ef5ccd6cSJohn Marino EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end,
1027*ef5ccd6cSJohn Marino      bool no_leading_period, int flags)
1028*ef5ccd6cSJohn Marino {
1029*ef5ccd6cSJohn Marino   const CHAR *startp;
1030*ef5ccd6cSJohn Marino   size_t level;
1031*ef5ccd6cSJohn Marino   struct patternlist
1032*ef5ccd6cSJohn Marino   {
1033*ef5ccd6cSJohn Marino     struct patternlist *next;
1034*ef5ccd6cSJohn Marino     CHAR str[1];
1035*ef5ccd6cSJohn Marino   } *list = NULL;
1036*ef5ccd6cSJohn Marino   struct patternlist **lastp = &list;
1037*ef5ccd6cSJohn Marino   size_t pattern_len = STRLEN (pattern);
1038*ef5ccd6cSJohn Marino   const CHAR *p;
1039*ef5ccd6cSJohn Marino   const CHAR *rs;
1040*ef5ccd6cSJohn Marino   enum { ALLOCA_LIMIT = 8000 };
1041*ef5ccd6cSJohn Marino 
1042*ef5ccd6cSJohn Marino   /* Parse the pattern.  Store the individual parts in the list.  */
1043*ef5ccd6cSJohn Marino   level = 0;
1044*ef5ccd6cSJohn Marino   for (startp = p = pattern + 1; ; ++p)
1045*ef5ccd6cSJohn Marino     if (*p == L_('\0'))
1046*ef5ccd6cSJohn Marino       /* This is an invalid pattern.  */
1047*ef5ccd6cSJohn Marino       return -1;
1048*ef5ccd6cSJohn Marino     else if (*p == L_('['))
1049*ef5ccd6cSJohn Marino       {
1050*ef5ccd6cSJohn Marino         /* Handle brackets special.  */
1051*ef5ccd6cSJohn Marino         if (posixly_correct == 0)
1052*ef5ccd6cSJohn Marino           posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
1053*ef5ccd6cSJohn Marino 
1054*ef5ccd6cSJohn Marino         /* Skip the not sign.  We have to recognize it because of a possibly
1055*ef5ccd6cSJohn Marino            following ']'.  */
1056*ef5ccd6cSJohn Marino         if (*++p == L_('!') || (posixly_correct < 0 && *p == L_('^')))
1057*ef5ccd6cSJohn Marino           ++p;
1058*ef5ccd6cSJohn Marino         /* A leading ']' is recognized as such.  */
1059*ef5ccd6cSJohn Marino         if (*p == L_(']'))
1060*ef5ccd6cSJohn Marino           ++p;
1061*ef5ccd6cSJohn Marino         /* Skip over all characters of the list.  */
1062*ef5ccd6cSJohn Marino         while (*p != L_(']'))
1063*ef5ccd6cSJohn Marino           if (*p++ == L_('\0'))
1064*ef5ccd6cSJohn Marino             /* This is no valid pattern.  */
1065*ef5ccd6cSJohn Marino             return -1;
1066*ef5ccd6cSJohn Marino       }
1067*ef5ccd6cSJohn Marino     else if ((*p == L_('?') || *p == L_('*') || *p == L_('+') || *p == L_('@')
1068*ef5ccd6cSJohn Marino               || *p == L_('!')) && p[1] == L_('('))
1069*ef5ccd6cSJohn Marino       /* Remember the nesting level.  */
1070*ef5ccd6cSJohn Marino       ++level;
1071*ef5ccd6cSJohn Marino     else if (*p == L_(')'))
1072*ef5ccd6cSJohn Marino       {
1073*ef5ccd6cSJohn Marino         if (level-- == 0)
1074*ef5ccd6cSJohn Marino           {
1075*ef5ccd6cSJohn Marino             /* This means we found the end of the pattern.  */
1076*ef5ccd6cSJohn Marino #define NEW_PATTERN \
1077*ef5ccd6cSJohn Marino             struct patternlist *newp;                                         \
1078*ef5ccd6cSJohn Marino             size_t plen;                                                      \
1079*ef5ccd6cSJohn Marino             size_t plensize;                                                  \
1080*ef5ccd6cSJohn Marino             size_t newpsize;                                                  \
1081*ef5ccd6cSJohn Marino                                                                               \
1082*ef5ccd6cSJohn Marino             plen = (opt == L_('?') || opt == L_('@')                          \
1083*ef5ccd6cSJohn Marino                     ? pattern_len                                             \
1084*ef5ccd6cSJohn Marino                     : p - startp + 1UL);                                      \
1085*ef5ccd6cSJohn Marino             plensize = plen * sizeof (CHAR);                                  \
1086*ef5ccd6cSJohn Marino             newpsize = offsetof (struct patternlist, str) + plensize;         \
1087*ef5ccd6cSJohn Marino             if ((size_t) -1 / sizeof (CHAR) < plen                            \
1088*ef5ccd6cSJohn Marino                 || newpsize < offsetof (struct patternlist, str)              \
1089*ef5ccd6cSJohn Marino                 || ALLOCA_LIMIT <= newpsize)                                  \
1090*ef5ccd6cSJohn Marino               return -1;                                                      \
1091*ef5ccd6cSJohn Marino             newp = (struct patternlist *) alloca (newpsize);                  \
1092*ef5ccd6cSJohn Marino             *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L_('\0');    \
1093*ef5ccd6cSJohn Marino             newp->next = NULL;                                                \
1094*ef5ccd6cSJohn Marino             *lastp = newp;                                                    \
1095*ef5ccd6cSJohn Marino             lastp = &newp->next
1096*ef5ccd6cSJohn Marino             NEW_PATTERN;
1097*ef5ccd6cSJohn Marino             break;
1098*ef5ccd6cSJohn Marino           }
1099*ef5ccd6cSJohn Marino       }
1100*ef5ccd6cSJohn Marino     else if (*p == L_('|'))
1101*ef5ccd6cSJohn Marino       {
1102*ef5ccd6cSJohn Marino         if (level == 0)
1103*ef5ccd6cSJohn Marino           {
1104*ef5ccd6cSJohn Marino             NEW_PATTERN;
1105*ef5ccd6cSJohn Marino             startp = p + 1;
1106*ef5ccd6cSJohn Marino           }
1107*ef5ccd6cSJohn Marino       }
1108*ef5ccd6cSJohn Marino   assert (list != NULL);
1109*ef5ccd6cSJohn Marino   assert (p[-1] == L_(')'));
1110*ef5ccd6cSJohn Marino #undef NEW_PATTERN
1111*ef5ccd6cSJohn Marino 
1112*ef5ccd6cSJohn Marino   switch (opt)
1113*ef5ccd6cSJohn Marino     {
1114*ef5ccd6cSJohn Marino     case L_('*'):
1115*ef5ccd6cSJohn Marino       if (FCT (p, string, string_end, no_leading_period, flags) == 0)
1116*ef5ccd6cSJohn Marino         return 0;
1117*ef5ccd6cSJohn Marino       /* FALLTHROUGH */
1118*ef5ccd6cSJohn Marino 
1119*ef5ccd6cSJohn Marino     case L_('+'):
1120*ef5ccd6cSJohn Marino       do
1121*ef5ccd6cSJohn Marino         {
1122*ef5ccd6cSJohn Marino           for (rs = string; rs <= string_end; ++rs)
1123*ef5ccd6cSJohn Marino             /* First match the prefix with the current pattern with the
1124*ef5ccd6cSJohn Marino                current pattern.  */
1125*ef5ccd6cSJohn Marino             if (FCT (list->str, string, rs, no_leading_period,
1126*ef5ccd6cSJohn Marino                      flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0
1127*ef5ccd6cSJohn Marino                 /* This was successful.  Now match the rest with the rest
1128*ef5ccd6cSJohn Marino                    of the pattern.  */
1129*ef5ccd6cSJohn Marino                 && (FCT (p, rs, string_end,
1130*ef5ccd6cSJohn Marino                          rs == string
1131*ef5ccd6cSJohn Marino                          ? no_leading_period
1132*ef5ccd6cSJohn Marino                          : rs[-1] == '/' && NO_LEADING_PERIOD (flags),
1133*ef5ccd6cSJohn Marino                          flags & FNM_FILE_NAME
1134*ef5ccd6cSJohn Marino                          ? flags : flags & ~FNM_PERIOD) == 0
1135*ef5ccd6cSJohn Marino                     /* This didn't work.  Try the whole pattern.  */
1136*ef5ccd6cSJohn Marino                     || (rs != string
1137*ef5ccd6cSJohn Marino                         && FCT (pattern - 1, rs, string_end,
1138*ef5ccd6cSJohn Marino                                 rs == string
1139*ef5ccd6cSJohn Marino                                 ? no_leading_period
1140*ef5ccd6cSJohn Marino                                 : rs[-1] == '/' && NO_LEADING_PERIOD (flags),
1141*ef5ccd6cSJohn Marino                                 flags & FNM_FILE_NAME
1142*ef5ccd6cSJohn Marino                                 ? flags : flags & ~FNM_PERIOD) == 0)))
1143*ef5ccd6cSJohn Marino               /* It worked.  Signal success.  */
1144*ef5ccd6cSJohn Marino               return 0;
1145*ef5ccd6cSJohn Marino         }
1146*ef5ccd6cSJohn Marino       while ((list = list->next) != NULL);
1147*ef5ccd6cSJohn Marino 
1148*ef5ccd6cSJohn Marino       /* None of the patterns lead to a match.  */
1149*ef5ccd6cSJohn Marino       return FNM_NOMATCH;
1150*ef5ccd6cSJohn Marino 
1151*ef5ccd6cSJohn Marino     case L_('?'):
1152*ef5ccd6cSJohn Marino       if (FCT (p, string, string_end, no_leading_period, flags) == 0)
1153*ef5ccd6cSJohn Marino         return 0;
1154*ef5ccd6cSJohn Marino       /* FALLTHROUGH */
1155*ef5ccd6cSJohn Marino 
1156*ef5ccd6cSJohn Marino     case L_('@'):
1157*ef5ccd6cSJohn Marino       do
1158*ef5ccd6cSJohn Marino         /* I cannot believe it but 'strcat' is actually acceptable
1159*ef5ccd6cSJohn Marino            here.  Match the entire string with the prefix from the
1160*ef5ccd6cSJohn Marino            pattern list and the rest of the pattern following the
1161*ef5ccd6cSJohn Marino            pattern list.  */
1162*ef5ccd6cSJohn Marino         if (FCT (STRCAT (list->str, p), string, string_end,
1163*ef5ccd6cSJohn Marino                  no_leading_period,
1164*ef5ccd6cSJohn Marino                  flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0)
1165*ef5ccd6cSJohn Marino           /* It worked.  Signal success.  */
1166*ef5ccd6cSJohn Marino           return 0;
1167*ef5ccd6cSJohn Marino       while ((list = list->next) != NULL);
1168*ef5ccd6cSJohn Marino 
1169*ef5ccd6cSJohn Marino       /* None of the patterns lead to a match.  */
1170*ef5ccd6cSJohn Marino       return FNM_NOMATCH;
1171*ef5ccd6cSJohn Marino 
1172*ef5ccd6cSJohn Marino     case L_('!'):
1173*ef5ccd6cSJohn Marino       for (rs = string; rs <= string_end; ++rs)
1174*ef5ccd6cSJohn Marino         {
1175*ef5ccd6cSJohn Marino           struct patternlist *runp;
1176*ef5ccd6cSJohn Marino 
1177*ef5ccd6cSJohn Marino           for (runp = list; runp != NULL; runp = runp->next)
1178*ef5ccd6cSJohn Marino             if (FCT (runp->str, string, rs,  no_leading_period,
1179*ef5ccd6cSJohn Marino                      flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0)
1180*ef5ccd6cSJohn Marino               break;
1181*ef5ccd6cSJohn Marino 
1182*ef5ccd6cSJohn Marino           /* If none of the patterns matched see whether the rest does.  */
1183*ef5ccd6cSJohn Marino           if (runp == NULL
1184*ef5ccd6cSJohn Marino               && (FCT (p, rs, string_end,
1185*ef5ccd6cSJohn Marino                        rs == string
1186*ef5ccd6cSJohn Marino                        ? no_leading_period
1187*ef5ccd6cSJohn Marino                        : rs[-1] == '/' && NO_LEADING_PERIOD (flags),
1188*ef5ccd6cSJohn Marino                        flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD)
1189*ef5ccd6cSJohn Marino                   == 0))
1190*ef5ccd6cSJohn Marino             /* This is successful.  */
1191*ef5ccd6cSJohn Marino             return 0;
1192*ef5ccd6cSJohn Marino         }
1193*ef5ccd6cSJohn Marino 
1194*ef5ccd6cSJohn Marino       /* None of the patterns together with the rest of the pattern
1195*ef5ccd6cSJohn Marino          lead to a match.  */
1196*ef5ccd6cSJohn Marino       return FNM_NOMATCH;
1197*ef5ccd6cSJohn Marino 
1198*ef5ccd6cSJohn Marino     default:
1199*ef5ccd6cSJohn Marino       assert (! "Invalid extended matching operator");
1200*ef5ccd6cSJohn Marino       break;
1201*ef5ccd6cSJohn Marino     }
1202*ef5ccd6cSJohn Marino 
1203*ef5ccd6cSJohn Marino   return -1;
1204*ef5ccd6cSJohn Marino }
1205*ef5ccd6cSJohn Marino 
1206*ef5ccd6cSJohn Marino 
1207*ef5ccd6cSJohn Marino #undef FOLD
1208*ef5ccd6cSJohn Marino #undef CHAR
1209*ef5ccd6cSJohn Marino #undef UCHAR
1210*ef5ccd6cSJohn Marino #undef INT
1211*ef5ccd6cSJohn Marino #undef FCT
1212*ef5ccd6cSJohn Marino #undef EXT
1213*ef5ccd6cSJohn Marino #undef END
1214*ef5ccd6cSJohn Marino #undef MEMPCPY
1215*ef5ccd6cSJohn Marino #undef MEMCHR
1216*ef5ccd6cSJohn Marino #undef STRLEN
1217*ef5ccd6cSJohn Marino #undef STRCAT
1218*ef5ccd6cSJohn Marino #undef L_
1219*ef5ccd6cSJohn Marino #undef BTOWC
1220