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