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