xref: /netbsd-src/external/gpl2/gettext/dist/gettext-tools/gnulib-lib/fnmatch_loop.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
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