Blame posix/fnmatch_loop.c

Packit 6c4009
/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <stdint.h>
Packit 6c4009
Packit 6c4009
struct STRUCT
Packit 6c4009
{
Packit 6c4009
  const CHAR *pattern;
Packit 6c4009
  const CHAR *string;
Packit 6c4009
  int no_leading_period;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* Match STRING against the filename pattern PATTERN, returning zero if
Packit 6c4009
   it matches, nonzero if not.  */
Packit 6c4009
static int FCT (const CHAR *pattern, const CHAR *string,
Packit 6c4009
		const CHAR *string_end, int no_leading_period, int flags,
Packit 6c4009
		struct STRUCT *ends, size_t alloca_used);
Packit 6c4009
static int EXT (INT opt, const CHAR *pattern, const CHAR *string,
Packit 6c4009
		const CHAR *string_end, int no_leading_period, int flags,
Packit 6c4009
		size_t alloca_used);
Packit 6c4009
static const CHAR *END (const CHAR *patternp);
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end,
Packit 6c4009
     int no_leading_period, int flags, struct STRUCT *ends, size_t alloca_used)
Packit 6c4009
{
Packit 6c4009
  const CHAR *p = pattern, *n = string;
Packit 6c4009
  UCHAR c;
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
# if WIDE_CHAR_VERSION
Packit 6c4009
  const char *collseq = (const char *)
Packit 6c4009
    _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC);
Packit 6c4009
# else
Packit 6c4009
  const UCHAR *collseq = (const UCHAR *)
Packit 6c4009
    _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQMB);
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  while ((c = *p++) != L('\0'))
Packit 6c4009
    {
Packit 6c4009
      int new_no_leading_period = 0;
Packit 6c4009
      c = FOLD (c);
Packit 6c4009
Packit 6c4009
      switch (c)
Packit 6c4009
	{
Packit 6c4009
	case L('?'):
Packit 6c4009
	  if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
Packit 6c4009
	    {
Packit 6c4009
	      int res = EXT (c, p, n, string_end, no_leading_period,
Packit 6c4009
			     flags, alloca_used);
Packit 6c4009
	      if (res != -1)
Packit 6c4009
		return res;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (n == string_end)
Packit 6c4009
	    return FNM_NOMATCH;
Packit 6c4009
	  else if (*n == L('/') && (flags & FNM_FILE_NAME))
Packit 6c4009
	    return FNM_NOMATCH;
Packit 6c4009
	  else if (*n == L('.') && no_leading_period)
Packit 6c4009
	    return FNM_NOMATCH;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case L('\\'):
Packit 6c4009
	  if (!(flags & FNM_NOESCAPE))
Packit 6c4009
	    {
Packit 6c4009
	      c = *p++;
Packit 6c4009
	      if (c == L('\0'))
Packit 6c4009
		/* Trailing \ loses.  */
Packit 6c4009
		return FNM_NOMATCH;
Packit 6c4009
	      c = FOLD (c);
Packit 6c4009
	    }
Packit 6c4009
	  if (n == string_end || FOLD ((UCHAR) *n) != c)
Packit 6c4009
	    return FNM_NOMATCH;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case L('*'):
Packit 6c4009
	  if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
Packit 6c4009
	    {
Packit 6c4009
	      int res = EXT (c, p, n, string_end, no_leading_period,
Packit 6c4009
			     flags, alloca_used);
Packit 6c4009
	      if (res != -1)
Packit 6c4009
		return res;
Packit 6c4009
	    }
Packit 6c4009
	  else if (ends != NULL)
Packit 6c4009
	    {
Packit 6c4009
	      ends->pattern = p - 1;
Packit 6c4009
	      ends->string = n;
Packit 6c4009
	      ends->no_leading_period = no_leading_period;
Packit 6c4009
	      return 0;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (n != string_end && *n == L('.') && no_leading_period)
Packit 6c4009
	    return FNM_NOMATCH;
Packit 6c4009
Packit 6c4009
	  for (c = *p++; c == L('?') || c == L('*'); c = *p++)
Packit 6c4009
	    {
Packit 6c4009
	      if (*p == L('(') && (flags & FNM_EXTMATCH) != 0)
Packit 6c4009
		{
Packit 6c4009
		  const CHAR *endp = END (p);
Packit 6c4009
		  if (endp != p)
Packit 6c4009
		    {
Packit 6c4009
		      /* This is a pattern.  Skip over it.  */
Packit 6c4009
		      p = endp;
Packit 6c4009
		      continue;
Packit 6c4009
		    }
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      if (c == L('?'))
Packit 6c4009
		{
Packit 6c4009
		  /* A ? needs to match one character.  */
Packit 6c4009
		  if (n == string_end)
Packit 6c4009
		    /* There isn't another character; no match.  */
Packit 6c4009
		    return FNM_NOMATCH;
Packit 6c4009
		  else if (*n == L('/')
Packit 6c4009
			   && __builtin_expect (flags & FNM_FILE_NAME, 0))
Packit 6c4009
		    /* A slash does not match a wildcard under
Packit 6c4009
		       FNM_FILE_NAME.  */
Packit 6c4009
		    return FNM_NOMATCH;
Packit 6c4009
		  else
Packit 6c4009
		    /* One character of the string is consumed in matching
Packit 6c4009
		       this ? wildcard, so *??? won't match if there are
Packit 6c4009
		       less than three characters.  */
Packit 6c4009
		    ++n;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (c == L('\0'))
Packit 6c4009
	    /* The wildcard(s) is/are the last element of the pattern.
Packit 6c4009
	       If the name is a file name and contains another slash
Packit 6c4009
	       this means it cannot match, unless the FNM_LEADING_DIR
Packit 6c4009
	       flag is set.  */
Packit 6c4009
	    {
Packit 6c4009
	      int result = (flags & FNM_FILE_NAME) == 0 ? 0 : FNM_NOMATCH;
Packit 6c4009
Packit 6c4009
	      if (flags & FNM_FILE_NAME)
Packit 6c4009
		{
Packit 6c4009
		  if (flags & FNM_LEADING_DIR)
Packit 6c4009
		    result = 0;
Packit 6c4009
		  else
Packit 6c4009
		    {
Packit 6c4009
		      if (MEMCHR (n, L('/'), string_end - n) == NULL)
Packit 6c4009
			result = 0;
Packit 6c4009
		    }
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      return result;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      const CHAR *endp;
Packit 6c4009
	      struct STRUCT end;
Packit 6c4009
Packit 6c4009
	      end.pattern = NULL;
Packit 6c4009
	      endp = MEMCHR (n, (flags & FNM_FILE_NAME) ? L('/') : L('\0'),
Packit 6c4009
			     string_end - n);
Packit 6c4009
	      if (endp == NULL)
Packit 6c4009
		endp = string_end;
Packit 6c4009
Packit 6c4009
	      if (c == L('[')
Packit 6c4009
		  || (__builtin_expect (flags & FNM_EXTMATCH, 0) != 0
Packit 6c4009
		      && (c == L('@') || c == L('+') || c == L('!'))
Packit 6c4009
		      && *p == L('(')))
Packit 6c4009
		{
Packit 6c4009
		  int flags2 = ((flags & FNM_FILE_NAME)
Packit 6c4009
				? flags : (flags & ~FNM_PERIOD));
Packit 6c4009
Packit 6c4009
		  for (--p; n < endp; ++n, no_leading_period = 0)
Packit 6c4009
		    if (FCT (p, n, string_end, no_leading_period, flags2,
Packit 6c4009
			     &end, alloca_used) == 0)
Packit 6c4009
		      goto found;
Packit 6c4009
		}
Packit 6c4009
	      else if (c == L('/') && (flags & FNM_FILE_NAME))
Packit 6c4009
		{
Packit 6c4009
		  while (n < string_end && *n != L('/'))
Packit 6c4009
		    ++n;
Packit 6c4009
		  if (n < string_end && *n == L('/')
Packit 6c4009
		      && (FCT (p, n + 1, string_end, flags & FNM_PERIOD, flags,
Packit 6c4009
			       NULL, alloca_used) == 0))
Packit 6c4009
		    return 0;
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		{
Packit 6c4009
		  int flags2 = ((flags & FNM_FILE_NAME)
Packit 6c4009
				? flags : (flags & ~FNM_PERIOD));
Packit 6c4009
Packit 6c4009
		  if (c == L('\\') && !(flags & FNM_NOESCAPE))
Packit 6c4009
		    c = *p;
Packit 6c4009
		  c = FOLD (c);
Packit 6c4009
		  for (--p; n < endp; ++n, no_leading_period = 0)
Packit 6c4009
		    if (FOLD ((UCHAR) *n) == c
Packit 6c4009
			&& (FCT (p, n, string_end, no_leading_period, flags2,
Packit 6c4009
				 &end, alloca_used) == 0))
Packit 6c4009
		      {
Packit 6c4009
		      found:
Packit 6c4009
			if (end.pattern == NULL)
Packit 6c4009
			  return 0;
Packit 6c4009
			break;
Packit 6c4009
		      }
Packit 6c4009
		  if (end.pattern != NULL)
Packit 6c4009
		    {
Packit 6c4009
		      p = end.pattern;
Packit 6c4009
		      n = end.string;
Packit 6c4009
		      no_leading_period = end.no_leading_period;
Packit 6c4009
		      continue;
Packit 6c4009
		    }
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* If we come here no match is possible with the wildcard.  */
Packit 6c4009
	  return FNM_NOMATCH;
Packit 6c4009
Packit 6c4009
	case L('['):
Packit 6c4009
	  {
Packit 6c4009
	    /* Nonzero if the sense of the character class is inverted.  */
Packit 6c4009
	    const CHAR *p_init = p;
Packit 6c4009
	    const CHAR *n_init = n;
Packit 6c4009
	    int not;
Packit 6c4009
	    CHAR cold;
Packit 6c4009
	    UCHAR fn;
Packit 6c4009
Packit 6c4009
	    if (posixly_correct == 0)
Packit 6c4009
	      posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
Packit 6c4009
Packit 6c4009
	    if (n == string_end)
Packit 6c4009
	      return FNM_NOMATCH;
Packit 6c4009
Packit 6c4009
	    if (*n == L('.') && no_leading_period)
Packit 6c4009
	      return FNM_NOMATCH;
Packit 6c4009
Packit 6c4009
	    if (*n == L('/') && (flags & FNM_FILE_NAME))
Packit 6c4009
	      /* `/' cannot be matched.  */
Packit 6c4009
	      return FNM_NOMATCH;
Packit 6c4009
Packit 6c4009
	    not = (*p == L('!') || (posixly_correct < 0 && *p == L('^')));
Packit 6c4009
	    if (not)
Packit 6c4009
	      ++p;
Packit 6c4009
Packit 6c4009
	    fn = FOLD ((UCHAR) *n);
Packit 6c4009
Packit 6c4009
	    c = *p++;
Packit 6c4009
	    for (;;)
Packit 6c4009
	      {
Packit 6c4009
		if (!(flags & FNM_NOESCAPE) && c == L('\\'))
Packit 6c4009
		  {
Packit 6c4009
		    if (*p == L('\0'))
Packit 6c4009
		      return FNM_NOMATCH;
Packit 6c4009
		    c = FOLD ((UCHAR) *p);
Packit 6c4009
		    ++p;
Packit 6c4009
Packit 6c4009
		    goto normal_bracket;
Packit 6c4009
		  }
Packit 6c4009
		else if (c == L('[') && *p == L(':'))
Packit 6c4009
		  {
Packit 6c4009
		    /* Leave room for the null.  */
Packit 6c4009
		    CHAR str[CHAR_CLASS_MAX_LENGTH + 1];
Packit 6c4009
		    size_t c1 = 0;
Packit 6c4009
#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
Packit 6c4009
		    wctype_t wt;
Packit 6c4009
#endif
Packit 6c4009
		    const CHAR *startp = p;
Packit 6c4009
Packit 6c4009
		    for (;;)
Packit 6c4009
		      {
Packit 6c4009
			if (c1 == CHAR_CLASS_MAX_LENGTH)
Packit 6c4009
			  /* The name is too long and therefore the pattern
Packit 6c4009
			     is ill-formed.  */
Packit 6c4009
			  return FNM_NOMATCH;
Packit 6c4009
Packit 6c4009
			c = *++p;
Packit 6c4009
			if (c == L(':') && p[1] == L(']'))
Packit 6c4009
			  {
Packit 6c4009
			    p += 2;
Packit 6c4009
			    break;
Packit 6c4009
			  }
Packit 6c4009
			if (c < L('a') || c >= L('z'))
Packit 6c4009
			  {
Packit 6c4009
			    /* This cannot possibly be a character class name.
Packit 6c4009
			       Match it as a normal range.  */
Packit 6c4009
			    p = startp;
Packit 6c4009
			    c = L('[');
Packit 6c4009
			    goto normal_bracket;
Packit 6c4009
			  }
Packit 6c4009
			str[c1++] = c;
Packit 6c4009
		      }
Packit 6c4009
		    str[c1] = L('\0');
Packit 6c4009
Packit 6c4009
#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
Packit 6c4009
		    wt = IS_CHAR_CLASS (str);
Packit 6c4009
		    if (wt == 0)
Packit 6c4009
		      /* Invalid character class name.  */
Packit 6c4009
		      return FNM_NOMATCH;
Packit 6c4009
Packit 6c4009
# if defined _LIBC && ! WIDE_CHAR_VERSION
Packit 6c4009
		    /* The following code is glibc specific but does
Packit 6c4009
		       there a good job in speeding up the code since
Packit 6c4009
		       we can avoid the btowc() call.  */
Packit 6c4009
		    if (_ISCTYPE ((UCHAR) *n, wt))
Packit 6c4009
		      goto matched;
Packit 6c4009
# else
Packit 6c4009
		    if (ISWCTYPE (BTOWC ((UCHAR) *n), wt))
Packit 6c4009
		      goto matched;
Packit 6c4009
# endif
Packit 6c4009
#else
Packit 6c4009
		    if ((STREQ (str, L("alnum")) && ISALNUM ((UCHAR) *n))
Packit 6c4009
			|| (STREQ (str, L("alpha")) && ISALPHA ((UCHAR) *n))
Packit 6c4009
			|| (STREQ (str, L("blank")) && ISBLANK ((UCHAR) *n))
Packit 6c4009
			|| (STREQ (str, L("cntrl")) && ISCNTRL ((UCHAR) *n))
Packit 6c4009
			|| (STREQ (str, L("digit")) && ISDIGIT ((UCHAR) *n))
Packit 6c4009
			|| (STREQ (str, L("graph")) && ISGRAPH ((UCHAR) *n))
Packit 6c4009
			|| (STREQ (str, L("lower")) && ISLOWER ((UCHAR) *n))
Packit 6c4009
			|| (STREQ (str, L("print")) && ISPRINT ((UCHAR) *n))
Packit 6c4009
			|| (STREQ (str, L("punct")) && ISPUNCT ((UCHAR) *n))
Packit 6c4009
			|| (STREQ (str, L("space")) && ISSPACE ((UCHAR) *n))
Packit 6c4009
			|| (STREQ (str, L("upper")) && ISUPPER ((UCHAR) *n))
Packit 6c4009
			|| (STREQ (str, L("xdigit")) && ISXDIGIT ((UCHAR) *n)))
Packit 6c4009
		      goto matched;
Packit 6c4009
#endif
Packit 6c4009
		    c = *p++;
Packit 6c4009
		  }
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
		else if (c == L('[') && *p == L('='))
Packit 6c4009
		  {
Packit 6c4009
		    /* It's important that STR be a scalar variable rather
Packit 6c4009
		       than a one-element array, because GCC (at least 4.9.2
Packit 6c4009
		       -O2 on x86-64) can be confused by the array and
Packit 6c4009
		       diagnose a "used initialized" in a dead branch in the
Packit 6c4009
		       findidx function.  */
Packit 6c4009
		    UCHAR str;
Packit 6c4009
		    uint32_t nrules =
Packit 6c4009
		      _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
Packit 6c4009
		    const CHAR *startp = p;
Packit 6c4009
Packit 6c4009
		    c = *++p;
Packit 6c4009
		    if (c == L('\0'))
Packit 6c4009
		      {
Packit 6c4009
			p = startp;
Packit 6c4009
			c = L('[');
Packit 6c4009
			goto normal_bracket;
Packit 6c4009
		      }
Packit 6c4009
		    str = c;
Packit 6c4009
Packit 6c4009
		    c = *++p;
Packit 6c4009
		    if (c != L('=') || p[1] != L(']'))
Packit 6c4009
		      {
Packit 6c4009
			p = startp;
Packit 6c4009
			c = L('[');
Packit 6c4009
			goto normal_bracket;
Packit 6c4009
		      }
Packit 6c4009
		    p += 2;
Packit 6c4009
Packit 6c4009
		    if (nrules == 0)
Packit 6c4009
		      {
Packit 6c4009
			if ((UCHAR) *n == str)
Packit 6c4009
			  goto matched;
Packit 6c4009
		      }
Packit 6c4009
		    else
Packit 6c4009
		      {
Packit 6c4009
			const int32_t *table;
Packit 6c4009
# if WIDE_CHAR_VERSION
Packit 6c4009
			const int32_t *weights;
Packit 6c4009
			const wint_t *extra;
Packit 6c4009
# else
Packit 6c4009
			const unsigned char *weights;
Packit 6c4009
			const unsigned char *extra;
Packit 6c4009
# endif
Packit 6c4009
			const int32_t *indirect;
Packit 6c4009
			int32_t idx;
Packit 6c4009
			const UCHAR *cp = (const UCHAR *) &str;
Packit 6c4009
Packit 6c4009
# if WIDE_CHAR_VERSION
Packit 6c4009
			table = (const int32_t *)
Packit 6c4009
			  _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEWC);
Packit 6c4009
			weights = (const int32_t *)
Packit 6c4009
			  _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTWC);
Packit 6c4009
			extra = (const wint_t *)
Packit 6c4009
			  _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAWC);
Packit 6c4009
			indirect = (const int32_t *)
Packit 6c4009
			  _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTWC);
Packit 6c4009
# else
Packit 6c4009
			table = (const int32_t *)
Packit 6c4009
			  _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
Packit 6c4009
			weights = (const unsigned char *)
Packit 6c4009
			  _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB);
Packit 6c4009
			extra = (const unsigned char *)
Packit 6c4009
			  _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
Packit 6c4009
			indirect = (const int32_t *)
Packit 6c4009
			  _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB);
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
			idx = FINDIDX (table, indirect, extra, &cp, 1);
Packit 6c4009
			if (idx != 0)
Packit 6c4009
			  {
Packit 6c4009
			    /* We found a table entry.  Now see whether the
Packit 6c4009
			       character we are currently at has the same
Packit 6c4009
			       equivalance class value.  */
Packit 6c4009
			    int len = weights[idx & 0xffffff];
Packit 6c4009
			    int32_t idx2;
Packit 6c4009
			    const UCHAR *np = (const UCHAR *) n;
Packit 6c4009
Packit 6c4009
			    idx2 = FINDIDX (table, indirect, extra,
Packit 6c4009
					    &np, string_end - n);
Packit 6c4009
			    if (idx2 != 0
Packit 6c4009
				&& (idx >> 24) == (idx2 >> 24)
Packit 6c4009
				&& len == weights[idx2 & 0xffffff])
Packit 6c4009
			      {
Packit 6c4009
				int cnt = 0;
Packit 6c4009
Packit 6c4009
				idx &= 0xffffff;
Packit 6c4009
				idx2 &= 0xffffff;
Packit 6c4009
Packit 6c4009
				while (cnt < len
Packit 6c4009
				       && (weights[idx + 1 + cnt]
Packit 6c4009
					   == weights[idx2 + 1 + cnt]))
Packit 6c4009
				  ++cnt;
Packit 6c4009
Packit 6c4009
				if (cnt == len)
Packit 6c4009
				  goto matched;
Packit 6c4009
			      }
Packit 6c4009
			  }
Packit 6c4009
		      }
Packit 6c4009
Packit 6c4009
		    c = *p++;
Packit 6c4009
		  }
Packit 6c4009
#endif
Packit 6c4009
		else if (c == L('\0'))
Packit 6c4009
		  {
Packit 6c4009
		    /* [ unterminated, treat as normal character.  */
Packit 6c4009
		    p = p_init;
Packit 6c4009
		    n = n_init;
Packit 6c4009
		    c = L('[');
Packit 6c4009
		    goto normal_match;
Packit 6c4009
		  }
Packit 6c4009
		else
Packit 6c4009
		  {
Packit 6c4009
		    int is_range = 0;
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
		    int is_seqval = 0;
Packit 6c4009
Packit 6c4009
		    if (c == L('[') && *p == L('.'))
Packit 6c4009
		      {
Packit 6c4009
			uint32_t nrules =
Packit 6c4009
			  _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
Packit 6c4009
			const CHAR *startp = p;
Packit 6c4009
			size_t c1 = 0;
Packit 6c4009
Packit 6c4009
			while (1)
Packit 6c4009
			  {
Packit 6c4009
			    c = *++p;
Packit 6c4009
			    if (c == L('.') && p[1] == L(']'))
Packit 6c4009
			      {
Packit 6c4009
				p += 2;
Packit 6c4009
				break;
Packit 6c4009
			      }
Packit 6c4009
			    if (c == '\0')
Packit 6c4009
			      return FNM_NOMATCH;
Packit 6c4009
			    ++c1;
Packit 6c4009
			  }
Packit 6c4009
Packit 6c4009
			/* We have to handling the symbols differently in
Packit 6c4009
			   ranges since then the collation sequence is
Packit 6c4009
			   important.  */
Packit 6c4009
			is_range = *p == L('-') && p[1] != L('\0');
Packit 6c4009
Packit 6c4009
			if (nrules == 0)
Packit 6c4009
			  {
Packit 6c4009
			    /* There are no names defined in the collation
Packit 6c4009
			       data.  Therefore we only accept the trivial
Packit 6c4009
			       names consisting of the character itself.  */
Packit 6c4009
			    if (c1 != 1)
Packit 6c4009
			      return FNM_NOMATCH;
Packit 6c4009
Packit 6c4009
			    if (!is_range && *n == startp[1])
Packit 6c4009
			      goto matched;
Packit 6c4009
Packit 6c4009
			    cold = startp[1];
Packit 6c4009
			    c = *p++;
Packit 6c4009
			  }
Packit 6c4009
			else
Packit 6c4009
			  {
Packit 6c4009
			    int32_t table_size;
Packit 6c4009
			    const int32_t *symb_table;
Packit 6c4009
# if WIDE_CHAR_VERSION
Packit 6c4009
			    char str[c1];
Packit 6c4009
			    unsigned int strcnt;
Packit 6c4009
# else
Packit 6c4009
#  define str (startp + 1)
Packit 6c4009
# endif
Packit 6c4009
			    const unsigned char *extra;
Packit 6c4009
			    int32_t idx;
Packit 6c4009
			    int32_t elem;
Packit 6c4009
			    int32_t second;
Packit 6c4009
			    int32_t hash;
Packit 6c4009
Packit 6c4009
# if WIDE_CHAR_VERSION
Packit 6c4009
			    /* We have to convert the name to a single-byte
Packit 6c4009
			       string.  This is possible since the names
Packit 6c4009
			       consist of ASCII characters and the internal
Packit 6c4009
			       representation is UCS4.  */
Packit 6c4009
			    for (strcnt = 0; strcnt < c1; ++strcnt)
Packit 6c4009
			      str[strcnt] = startp[1 + strcnt];
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
			    table_size =
Packit 6c4009
			      _NL_CURRENT_WORD (LC_COLLATE,
Packit 6c4009
						_NL_COLLATE_SYMB_HASH_SIZEMB);
Packit 6c4009
			    symb_table = (const int32_t *)
Packit 6c4009
			      _NL_CURRENT (LC_COLLATE,
Packit 6c4009
					   _NL_COLLATE_SYMB_TABLEMB);
Packit 6c4009
			    extra = (const unsigned char *)
Packit 6c4009
			      _NL_CURRENT (LC_COLLATE,
Packit 6c4009
					   _NL_COLLATE_SYMB_EXTRAMB);
Packit 6c4009
Packit 6c4009
			    /* Locate the character in the hashing table.  */
Packit 6c4009
			    hash = elem_hash (str, c1);
Packit 6c4009
Packit 6c4009
			    idx = 0;
Packit 6c4009
			    elem = hash % table_size;
Packit 6c4009
			    if (symb_table[2 * elem] != 0)
Packit 6c4009
			      {
Packit 6c4009
				second = hash % (table_size - 2) + 1;
Packit 6c4009
Packit 6c4009
				do
Packit 6c4009
				  {
Packit 6c4009
				    /* First compare the hashing value.  */
Packit 6c4009
				    if (symb_table[2 * elem] == hash
Packit 6c4009
					&& (c1
Packit 6c4009
					    == extra[symb_table[2 * elem + 1]])
Packit 6c4009
					&& memcmp (str,
Packit 6c4009
						   &extra[symb_table[2 * elem
Packit 6c4009
								     + 1]
Packit 6c4009
							  + 1], c1) == 0)
Packit 6c4009
				      {
Packit 6c4009
					/* Yep, this is the entry.  */
Packit 6c4009
					idx = symb_table[2 * elem + 1];
Packit 6c4009
					idx += 1 + extra[idx];
Packit 6c4009
					break;
Packit 6c4009
				      }
Packit 6c4009
Packit 6c4009
				    /* Next entry.  */
Packit 6c4009
				    elem += second;
Packit 6c4009
				  }
Packit 6c4009
				while (symb_table[2 * elem] != 0);
Packit 6c4009
			      }
Packit 6c4009
Packit 6c4009
			    if (symb_table[2 * elem] != 0)
Packit 6c4009
			      {
Packit 6c4009
				/* Compare the byte sequence but only if
Packit 6c4009
				   this is not part of a range.  */
Packit 6c4009
# if WIDE_CHAR_VERSION
Packit 6c4009
				int32_t *wextra;
Packit 6c4009
Packit 6c4009
				idx += 1 + extra[idx];
Packit 6c4009
				/* Adjust for the alignment.  */
Packit 6c4009
				idx = (idx + 3) & ~3;
Packit 6c4009
Packit 6c4009
				wextra = (int32_t *) &extra[idx + 4];
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
				if (! is_range)
Packit 6c4009
				  {
Packit 6c4009
# if WIDE_CHAR_VERSION
Packit 6c4009
				    for (c1 = 0;
Packit 6c4009
					 (int32_t) c1 < wextra[idx];
Packit 6c4009
					 ++c1)
Packit 6c4009
				      if (n[c1] != wextra[1 + c1])
Packit 6c4009
					break;
Packit 6c4009
Packit 6c4009
				    if ((int32_t) c1 == wextra[idx])
Packit 6c4009
				      goto matched;
Packit 6c4009
# else
Packit 6c4009
				    for (c1 = 0; c1 < extra[idx]; ++c1)
Packit 6c4009
				      if (n[c1] != extra[1 + c1])
Packit 6c4009
					break;
Packit 6c4009
Packit 6c4009
				    if (c1 == extra[idx])
Packit 6c4009
				      goto matched;
Packit 6c4009
# endif
Packit 6c4009
				  }
Packit 6c4009
Packit 6c4009
				/* Get the collation sequence value.  */
Packit 6c4009
				is_seqval = 1;
Packit 6c4009
# if WIDE_CHAR_VERSION
Packit 6c4009
				cold = wextra[1 + wextra[idx]];
Packit 6c4009
# else
Packit 6c4009
				/* Adjust for the alignment.  */
Packit 6c4009
				idx += 1 + extra[idx];
Packit 6c4009
				idx = (idx + 3) & ~4;
Packit 6c4009
				cold = *((int32_t *) &extra[idx]);
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
				c = *p++;
Packit 6c4009
			      }
Packit 6c4009
			    else if (c1 == 1)
Packit 6c4009
			      {
Packit 6c4009
				/* No valid character.  Match it as a
Packit 6c4009
				   single byte.  */
Packit 6c4009
				if (!is_range && *n == str[0])
Packit 6c4009
				  goto matched;
Packit 6c4009
Packit 6c4009
				cold = str[0];
Packit 6c4009
				c = *p++;
Packit 6c4009
			      }
Packit 6c4009
			    else
Packit 6c4009
			      return FNM_NOMATCH;
Packit 6c4009
			  }
Packit 6c4009
		      }
Packit 6c4009
		    else
Packit 6c4009
# undef str
Packit 6c4009
#endif
Packit 6c4009
		      {
Packit 6c4009
			c = FOLD (c);
Packit 6c4009
		      normal_bracket:
Packit 6c4009
Packit 6c4009
			/* We have to handling the symbols differently in
Packit 6c4009
			   ranges since then the collation sequence is
Packit 6c4009
			   important.  */
Packit 6c4009
			is_range = (*p == L('-') && p[1] != L('\0')
Packit 6c4009
				    && p[1] != L(']'));
Packit 6c4009
Packit 6c4009
			if (!is_range && c == fn)
Packit 6c4009
			  goto matched;
Packit 6c4009
Packit 6c4009
			/* This is needed if we goto normal_bracket; from
Packit 6c4009
			   outside of is_seqval's scope.  */
Packit 6c4009
			is_seqval = 0;
Packit 6c4009
			cold = c;
Packit 6c4009
			c = *p++;
Packit 6c4009
		      }
Packit 6c4009
Packit 6c4009
		    if (c == L('-') && *p != L(']'))
Packit 6c4009
		      {
Packit 6c4009
#if _LIBC
Packit 6c4009
			/* We have to find the collation sequence
Packit 6c4009
			   value for C.  Collation sequence is nothing
Packit 6c4009
			   we can regularly access.  The sequence
Packit 6c4009
			   value is defined by the order in which the
Packit 6c4009
			   definitions of the collation values for the
Packit 6c4009
			   various characters appear in the source
Packit 6c4009
			   file.  A strange concept, nowhere
Packit 6c4009
			   documented.  */
Packit 6c4009
			uint32_t fcollseq;
Packit 6c4009
			uint32_t lcollseq;
Packit 6c4009
			UCHAR cend = *p++;
Packit 6c4009
Packit 6c4009
# if WIDE_CHAR_VERSION
Packit 6c4009
			/* Search in the `names' array for the characters.  */
Packit 6c4009
			fcollseq = __collseq_table_lookup (collseq, fn);
Packit 6c4009
			if (fcollseq == ~((uint32_t) 0))
Packit 6c4009
			  /* XXX We don't know anything about the character
Packit 6c4009
			     we are supposed to match.  This means we are
Packit 6c4009
			     failing.  */
Packit 6c4009
			  goto range_not_matched;
Packit 6c4009
Packit 6c4009
			if (is_seqval)
Packit 6c4009
			  lcollseq = cold;
Packit 6c4009
			else
Packit 6c4009
			  lcollseq = __collseq_table_lookup (collseq, cold);
Packit 6c4009
# else
Packit 6c4009
			fcollseq = collseq[fn];
Packit 6c4009
			lcollseq = is_seqval ? cold : collseq[(UCHAR) cold];
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
			is_seqval = 0;
Packit 6c4009
			if (cend == L('[') && *p == L('.'))
Packit 6c4009
			  {
Packit 6c4009
			    uint32_t nrules =
Packit 6c4009
			      _NL_CURRENT_WORD (LC_COLLATE,
Packit 6c4009
						_NL_COLLATE_NRULES);
Packit 6c4009
			    const CHAR *startp = p;
Packit 6c4009
			    size_t c1 = 0;
Packit 6c4009
Packit 6c4009
			    while (1)
Packit 6c4009
			      {
Packit 6c4009
				c = *++p;
Packit 6c4009
				if (c == L('.') && p[1] == L(']'))
Packit 6c4009
				  {
Packit 6c4009
				    p += 2;
Packit 6c4009
				    break;
Packit 6c4009
				  }
Packit 6c4009
				if (c == '\0')
Packit 6c4009
				  return FNM_NOMATCH;
Packit 6c4009
				++c1;
Packit 6c4009
			      }
Packit 6c4009
Packit 6c4009
			    if (nrules == 0)
Packit 6c4009
			      {
Packit 6c4009
				/* There are no names defined in the
Packit 6c4009
				   collation data.  Therefore we only
Packit 6c4009
				   accept the trivial names consisting
Packit 6c4009
				   of the character itself.  */
Packit 6c4009
				if (c1 != 1)
Packit 6c4009
				  return FNM_NOMATCH;
Packit 6c4009
Packit 6c4009
				cend = startp[1];
Packit 6c4009
			      }
Packit 6c4009
			    else
Packit 6c4009
			      {
Packit 6c4009
				int32_t table_size;
Packit 6c4009
				const int32_t *symb_table;
Packit 6c4009
# if WIDE_CHAR_VERSION
Packit 6c4009
				char str[c1];
Packit 6c4009
				unsigned int strcnt;
Packit 6c4009
# else
Packit 6c4009
#  define str (startp + 1)
Packit 6c4009
# endif
Packit 6c4009
				const unsigned char *extra;
Packit 6c4009
				int32_t idx;
Packit 6c4009
				int32_t elem;
Packit 6c4009
				int32_t second;
Packit 6c4009
				int32_t hash;
Packit 6c4009
Packit 6c4009
# if WIDE_CHAR_VERSION
Packit 6c4009
				/* We have to convert the name to a single-byte
Packit 6c4009
				   string.  This is possible since the names
Packit 6c4009
				   consist of ASCII characters and the internal
Packit 6c4009
				   representation is UCS4.  */
Packit 6c4009
				for (strcnt = 0; strcnt < c1; ++strcnt)
Packit 6c4009
				  str[strcnt] = startp[1 + strcnt];
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
				table_size =
Packit 6c4009
				  _NL_CURRENT_WORD (LC_COLLATE,
Packit 6c4009
						    _NL_COLLATE_SYMB_HASH_SIZEMB);
Packit 6c4009
				symb_table = (const int32_t *)
Packit 6c4009
				  _NL_CURRENT (LC_COLLATE,
Packit 6c4009
					       _NL_COLLATE_SYMB_TABLEMB);
Packit 6c4009
				extra = (const unsigned char *)
Packit 6c4009
				  _NL_CURRENT (LC_COLLATE,
Packit 6c4009
					       _NL_COLLATE_SYMB_EXTRAMB);
Packit 6c4009
Packit 6c4009
				/* Locate the character in the hashing
Packit 6c4009
				   table.  */
Packit 6c4009
				hash = elem_hash (str, c1);
Packit 6c4009
Packit 6c4009
				idx = 0;
Packit 6c4009
				elem = hash % table_size;
Packit 6c4009
				if (symb_table[2 * elem] != 0)
Packit 6c4009
				  {
Packit 6c4009
				    second = hash % (table_size - 2) + 1;
Packit 6c4009
Packit 6c4009
				    do
Packit 6c4009
				      {
Packit 6c4009
					/* First compare the hashing value.  */
Packit 6c4009
					if (symb_table[2 * elem] == hash
Packit 6c4009
					    && (c1
Packit 6c4009
						== extra[symb_table[2 * elem + 1]])
Packit 6c4009
					    && memcmp (str,
Packit 6c4009
						       &extra[symb_table[2 * elem + 1]
Packit 6c4009
							      + 1], c1) == 0)
Packit 6c4009
					  {
Packit 6c4009
					    /* Yep, this is the entry.  */
Packit 6c4009
					    idx = symb_table[2 * elem + 1];
Packit 6c4009
					    idx += 1 + extra[idx];
Packit 6c4009
					    break;
Packit 6c4009
					  }
Packit 6c4009
Packit 6c4009
					/* Next entry.  */
Packit 6c4009
					elem += second;
Packit 6c4009
				      }
Packit 6c4009
				    while (symb_table[2 * elem] != 0);
Packit 6c4009
				  }
Packit 6c4009
Packit 6c4009
				if (symb_table[2 * elem] != 0)
Packit 6c4009
				  {
Packit 6c4009
				    /* Compare the byte sequence but only if
Packit 6c4009
				       this is not part of a range.  */
Packit 6c4009
# if WIDE_CHAR_VERSION
Packit 6c4009
				    int32_t *wextra;
Packit 6c4009
Packit 6c4009
				    idx += 1 + extra[idx];
Packit 6c4009
				    /* Adjust for the alignment.  */
Packit 6c4009
				    idx = (idx + 3) & ~4;
Packit 6c4009
Packit 6c4009
				    wextra = (int32_t *) &extra[idx + 4];
Packit 6c4009
# endif
Packit 6c4009
				    /* Get the collation sequence value.  */
Packit 6c4009
				    is_seqval = 1;
Packit 6c4009
# if WIDE_CHAR_VERSION
Packit 6c4009
				    cend = wextra[1 + wextra[idx]];
Packit 6c4009
# else
Packit 6c4009
				    /* Adjust for the alignment.  */
Packit 6c4009
				    idx += 1 + extra[idx];
Packit 6c4009
				    idx = (idx + 3) & ~4;
Packit 6c4009
				    cend = *((int32_t *) &extra[idx]);
Packit 6c4009
# endif
Packit 6c4009
				  }
Packit 6c4009
				else if (symb_table[2 * elem] != 0 && c1 == 1)
Packit 6c4009
				  {
Packit 6c4009
				    cend = str[0];
Packit 6c4009
				    c = *p++;
Packit 6c4009
				  }
Packit 6c4009
				else
Packit 6c4009
				  return FNM_NOMATCH;
Packit 6c4009
			      }
Packit 6c4009
# undef str
Packit 6c4009
			  }
Packit 6c4009
			else
Packit 6c4009
			  {
Packit 6c4009
			    if (!(flags & FNM_NOESCAPE) && cend == L('\\'))
Packit 6c4009
			      cend = *p++;
Packit 6c4009
			    if (cend == L('\0'))
Packit 6c4009
			      return FNM_NOMATCH;
Packit 6c4009
			    cend = FOLD (cend);
Packit 6c4009
			  }
Packit 6c4009
Packit 6c4009
			/* XXX It is not entirely clear to me how to handle
Packit 6c4009
			   characters which are not mentioned in the
Packit 6c4009
			   collation specification.  */
Packit 6c4009
			if (
Packit 6c4009
# if WIDE_CHAR_VERSION
Packit 6c4009
			    lcollseq == 0xffffffff ||
Packit 6c4009
# endif
Packit 6c4009
			    lcollseq <= fcollseq)
Packit 6c4009
			  {
Packit 6c4009
			    /* We have to look at the upper bound.  */
Packit 6c4009
			    uint32_t hcollseq;
Packit 6c4009
Packit 6c4009
			    if (is_seqval)
Packit 6c4009
			      hcollseq = cend;
Packit 6c4009
			    else
Packit 6c4009
			      {
Packit 6c4009
# if WIDE_CHAR_VERSION
Packit 6c4009
				hcollseq =
Packit 6c4009
				  __collseq_table_lookup (collseq, cend);
Packit 6c4009
				if (hcollseq == ~((uint32_t) 0))
Packit 6c4009
				  {
Packit 6c4009
				    /* Hum, no information about the upper
Packit 6c4009
				       bound.  The matching succeeds if the
Packit 6c4009
				       lower bound is matched exactly.  */
Packit 6c4009
				    if (lcollseq != fcollseq)
Packit 6c4009
				      goto range_not_matched;
Packit 6c4009
Packit 6c4009
				    goto matched;
Packit 6c4009
				  }
Packit 6c4009
# else
Packit 6c4009
				hcollseq = collseq[cend];
Packit 6c4009
# endif
Packit 6c4009
			      }
Packit 6c4009
Packit 6c4009
			    if (lcollseq <= hcollseq && fcollseq <= hcollseq)
Packit 6c4009
			      goto matched;
Packit 6c4009
			  }
Packit 6c4009
# if WIDE_CHAR_VERSION
Packit 6c4009
		      range_not_matched:
Packit 6c4009
# endif
Packit 6c4009
#else
Packit 6c4009
			/* We use a boring value comparison of the character
Packit 6c4009
			   values.  This is better than comparing using
Packit 6c4009
			   `strcoll' since the latter would have surprising
Packit 6c4009
			   and sometimes fatal consequences.  */
Packit 6c4009
			UCHAR cend = *p++;
Packit 6c4009
Packit 6c4009
			if (!(flags & FNM_NOESCAPE) && cend == L('\\'))
Packit 6c4009
			  cend = *p++;
Packit 6c4009
			if (cend == L('\0'))
Packit 6c4009
			  return FNM_NOMATCH;
Packit 6c4009
Packit 6c4009
			/* It is a range.  */
Packit 6c4009
			if (cold <= fn && fn <= cend)
Packit 6c4009
			  goto matched;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
			c = *p++;
Packit 6c4009
		      }
Packit 6c4009
		  }
Packit 6c4009
Packit 6c4009
		if (c == L(']'))
Packit 6c4009
		  break;
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	    if (!not)
Packit 6c4009
	      return FNM_NOMATCH;
Packit 6c4009
	    break;
Packit 6c4009
Packit 6c4009
	  matched:
Packit 6c4009
	    /* Skip the rest of the [...] that already matched.  */
Packit 6c4009
	    while ((c = *p++) != L (']'))
Packit 6c4009
	      {
Packit 6c4009
		if (c == L('\0'))
Packit 6c4009
		  /* [... (unterminated) loses.  */
Packit 6c4009
		  return FNM_NOMATCH;
Packit 6c4009
Packit 6c4009
		if (!(flags & FNM_NOESCAPE) && c == L('\\'))
Packit 6c4009
		  {
Packit 6c4009
		    if (*p == L('\0'))
Packit 6c4009
		      return FNM_NOMATCH;
Packit 6c4009
		    /* XXX 1003.2d11 is unclear if this is right.  */
Packit 6c4009
		    ++p;
Packit 6c4009
		  }
Packit 6c4009
		else if (c == L('[') && *p == L(':'))
Packit 6c4009
		  {
Packit 6c4009
		    int c1 = 0;
Packit 6c4009
		    const CHAR *startp = p;
Packit 6c4009
Packit 6c4009
		    while (1)
Packit 6c4009
		      {
Packit 6c4009
			c = *++p;
Packit 6c4009
			if (++c1 == CHAR_CLASS_MAX_LENGTH)
Packit 6c4009
			  return FNM_NOMATCH;
Packit 6c4009
Packit 6c4009
			if (*p == L(':') && p[1] == L(']'))
Packit 6c4009
			  break;
Packit 6c4009
Packit 6c4009
			if (c < L('a') || c >= L('z'))
Packit 6c4009
			  {
Packit 6c4009
			    p = startp - 2;
Packit 6c4009
			    break;
Packit 6c4009
			  }
Packit 6c4009
		      }
Packit 6c4009
		    p += 2;
Packit 6c4009
		  }
Packit 6c4009
		else if (c == L('[') && *p == L('='))
Packit 6c4009
		  {
Packit 6c4009
		    c = *++p;
Packit 6c4009
		    if (c == L('\0'))
Packit 6c4009
		      return FNM_NOMATCH;
Packit 6c4009
		    c = *++p;
Packit 6c4009
		    if (c != L('=') || p[1] != L(']'))
Packit 6c4009
		      return FNM_NOMATCH;
Packit 6c4009
		    p += 2;
Packit 6c4009
		  }
Packit 6c4009
		else if (c == L('[') && *p == L('.'))
Packit 6c4009
		  {
Packit 6c4009
		    while (1)
Packit 6c4009
		      {
Packit 6c4009
			c = *++p;
Packit 6c4009
			if (c == L('\0'))
Packit 6c4009
			  return FNM_NOMATCH;
Packit 6c4009
Packit 6c4009
			if (c == L('.') && p[1] == L(']'))
Packit 6c4009
			  break;
Packit 6c4009
		      }
Packit 6c4009
		    p += 2;
Packit 6c4009
		  }
Packit 6c4009
	      }
Packit 6c4009
	    if (not)
Packit 6c4009
	      return FNM_NOMATCH;
Packit 6c4009
	  }
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case L('+'):
Packit 6c4009
	case L('@'):
Packit 6c4009
	case L('!'):
Packit 6c4009
	  if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(')
Packit 6c4009
	    {
Packit 6c4009
	      int res = EXT (c, p, n, string_end, no_leading_period, flags,
Packit 6c4009
			     alloca_used);
Packit 6c4009
	      if (res != -1)
Packit 6c4009
		return res;
Packit 6c4009
	    }
Packit 6c4009
	  goto normal_match;
Packit 6c4009
Packit 6c4009
	case L('/'):
Packit 6c4009
	  if (NO_LEADING_PERIOD (flags))
Packit 6c4009
	    {
Packit 6c4009
	      if (n == string_end || c != (UCHAR) *n)
Packit 6c4009
		return FNM_NOMATCH;
Packit 6c4009
Packit 6c4009
	      new_no_leading_period = 1;
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
	  /* FALLTHROUGH */
Packit 6c4009
	default:
Packit 6c4009
	normal_match:
Packit 6c4009
	  if (n == string_end || c != FOLD ((UCHAR) *n))
Packit 6c4009
	    return FNM_NOMATCH;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      no_leading_period = new_no_leading_period;
Packit 6c4009
      ++n;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (n == string_end)
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  if ((flags & FNM_LEADING_DIR) && n != string_end && *n == L('/'))
Packit 6c4009
    /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  return FNM_NOMATCH;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static const CHAR *
Packit 6c4009
END (const CHAR *pattern)
Packit 6c4009
{
Packit 6c4009
  const CHAR *p = pattern;
Packit 6c4009
Packit 6c4009
  while (1)
Packit 6c4009
    if (*++p == L('\0'))
Packit 6c4009
      /* This is an invalid pattern.  */
Packit 6c4009
      return pattern;
Packit 6c4009
    else if (*p == L('['))
Packit 6c4009
      {
Packit 6c4009
	/* Handle brackets special.  */
Packit 6c4009
	if (posixly_correct == 0)
Packit 6c4009
	  posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
Packit 6c4009
Packit 6c4009
	/* Skip the not sign.  We have to recognize it because of a possibly
Packit 6c4009
	   following ']'.  */
Packit 6c4009
	if (*++p == L('!') || (posixly_correct < 0 && *p == L('^')))
Packit 6c4009
	  ++p;
Packit 6c4009
	/* A leading ']' is recognized as such.  */
Packit 6c4009
	if (*p == L(']'))
Packit 6c4009
	  ++p;
Packit 6c4009
	/* Skip over all characters of the list.  */
Packit 6c4009
	while (*p != L(']'))
Packit 6c4009
	  if (*p++ == L('\0'))
Packit 6c4009
	    /* This is no valid pattern.  */
Packit 6c4009
	    return pattern;
Packit 6c4009
      }
Packit 6c4009
    else if ((*p == L('?') || *p == L('*') || *p == L('+') || *p == L('@')
Packit 6c4009
	      || *p == L('!')) && p[1] == L('('))
Packit 6c4009
      {
Packit 6c4009
	p = END (p + 1);
Packit 6c4009
	if (*p == L('\0'))
Packit 6c4009
	  /* This is an invalid pattern.  */
Packit 6c4009
	  return pattern;
Packit 6c4009
      }
Packit 6c4009
    else if (*p == L(')'))
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
  return p + 1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end,
Packit 6c4009
     int no_leading_period, int flags, size_t alloca_used)
Packit 6c4009
{
Packit 6c4009
  const CHAR *startp;
Packit 6c4009
  int level;
Packit 6c4009
  struct patternlist
Packit 6c4009
  {
Packit 6c4009
    struct patternlist *next;
Packit 6c4009
    CHAR malloced;
Packit 6c4009
    CHAR str[0];
Packit 6c4009
  } *list = NULL;
Packit 6c4009
  struct patternlist **lastp = &list;
Packit 6c4009
  size_t pattern_len = STRLEN (pattern);
Packit 6c4009
  int any_malloced = 0;
Packit 6c4009
  const CHAR *p;
Packit 6c4009
  const CHAR *rs;
Packit 6c4009
  int retval = 0;
Packit 6c4009
Packit 6c4009
  /* Parse the pattern.  Store the individual parts in the list.  */
Packit 6c4009
  level = 0;
Packit 6c4009
  for (startp = p = pattern + 1; level >= 0; ++p)
Packit 6c4009
    if (*p == L('\0'))
Packit 6c4009
      {
Packit 6c4009
	/* This is an invalid pattern.  */
Packit 6c4009
	retval = -1;
Packit 6c4009
	goto out;
Packit 6c4009
      }
Packit 6c4009
    else if (*p == L('['))
Packit 6c4009
      {
Packit 6c4009
	/* Handle brackets special.  */
Packit 6c4009
	if (posixly_correct == 0)
Packit 6c4009
	  posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
Packit 6c4009
Packit 6c4009
	/* Skip the not sign.  We have to recognize it because of a possibly
Packit 6c4009
	   following ']'.  */
Packit 6c4009
	if (*++p == L('!') || (posixly_correct < 0 && *p == L('^')))
Packit 6c4009
	  ++p;
Packit 6c4009
	/* A leading ']' is recognized as such.  */
Packit 6c4009
	if (*p == L(']'))
Packit 6c4009
	  ++p;
Packit 6c4009
	/* Skip over all characters of the list.  */
Packit 6c4009
	while (*p != L(']'))
Packit 6c4009
	  if (*p++ == L('\0'))
Packit 6c4009
	    {
Packit 6c4009
	      /* This is no valid pattern.  */
Packit 6c4009
	      retval = -1;
Packit 6c4009
	      goto out;
Packit 6c4009
	    }
Packit 6c4009
      }
Packit 6c4009
    else if ((*p == L('?') || *p == L('*') || *p == L('+') || *p == L('@')
Packit 6c4009
	      || *p == L('!')) && p[1] == L('('))
Packit 6c4009
      /* Remember the nesting level.  */
Packit 6c4009
      ++level;
Packit 6c4009
    else if (*p == L(')'))
Packit 6c4009
      {
Packit 6c4009
	if (level-- == 0)
Packit 6c4009
	  {
Packit 6c4009
	    /* This means we found the end of the pattern.  */
Packit 6c4009
#define NEW_PATTERN \
Packit 6c4009
	    struct patternlist *newp;					      \
Packit 6c4009
	    size_t slen = (opt == L('?') || opt == L('@')		      \
Packit 6c4009
			   ? pattern_len : (p - startp + 1));		      \
Packit 6c4009
	    slen = sizeof (struct patternlist) + (slen * sizeof (CHAR));      \
Packit 6c4009
	    int malloced = ! __libc_use_alloca (alloca_used + slen);	      \
Packit 6c4009
	    if (__builtin_expect (malloced, 0))				      \
Packit 6c4009
	      {								      \
Packit 6c4009
		newp = malloc (slen);					      \
Packit 6c4009
		if (newp == NULL)					      \
Packit 6c4009
		  {							      \
Packit 6c4009
		    retval = -2;					      \
Packit 6c4009
		    goto out;						      \
Packit 6c4009
		  }							      \
Packit 6c4009
		any_malloced = 1;					      \
Packit 6c4009
	      }								      \
Packit 6c4009
	    else							      \
Packit 6c4009
	      newp = alloca_account (slen, alloca_used);		      \
Packit 6c4009
	    newp->next = NULL;						      \
Packit 6c4009
	    newp->malloced = malloced;					      \
Packit 6c4009
	    *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L('\0');    \
Packit 6c4009
	    *lastp = newp;						      \
Packit 6c4009
	    lastp = &newp->next
Packit 6c4009
	    NEW_PATTERN;
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
    else if (*p == L('|'))
Packit 6c4009
      {
Packit 6c4009
	if (level == 0)
Packit 6c4009
	  {
Packit 6c4009
	    NEW_PATTERN;
Packit 6c4009
	    startp = p + 1;
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
  assert (list != NULL);
Packit 6c4009
  assert (p[-1] == L(')'));
Packit 6c4009
#undef NEW_PATTERN
Packit 6c4009
Packit 6c4009
  switch (opt)
Packit 6c4009
    {
Packit 6c4009
    case L('*'):
Packit 6c4009
      if (FCT (p, string, string_end, no_leading_period, flags, NULL,
Packit 6c4009
	       alloca_used) == 0)
Packit 6c4009
	goto success;
Packit 6c4009
      /* FALLTHROUGH */
Packit 6c4009
Packit 6c4009
    case L('+'):
Packit 6c4009
      do
Packit 6c4009
	{
Packit 6c4009
	  for (rs = string; rs <= string_end; ++rs)
Packit 6c4009
	    /* First match the prefix with the current pattern with the
Packit 6c4009
	       current pattern.  */
Packit 6c4009
	    if (FCT (list->str, string, rs, no_leading_period,
Packit 6c4009
		     flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD,
Packit 6c4009
		     NULL, alloca_used) == 0
Packit 6c4009
		/* This was successful.  Now match the rest with the rest
Packit 6c4009
		   of the pattern.  */
Packit 6c4009
		&& (FCT (p, rs, string_end,
Packit 6c4009
			 rs == string
Packit 6c4009
			 ? no_leading_period
Packit 6c4009
			 : rs[-1] == '/' && NO_LEADING_PERIOD (flags) ? 1 : 0,
Packit 6c4009
			 flags & FNM_FILE_NAME
Packit 6c4009
			 ? flags : flags & ~FNM_PERIOD, NULL, alloca_used) == 0
Packit 6c4009
		    /* This didn't work.  Try the whole pattern.  */
Packit 6c4009
		    || (rs != string
Packit 6c4009
			&& FCT (pattern - 1, rs, string_end,
Packit 6c4009
				rs == string
Packit 6c4009
				? no_leading_period
Packit 6c4009
				: (rs[-1] == '/' && NO_LEADING_PERIOD (flags)
Packit 6c4009
				   ? 1 : 0),
Packit 6c4009
				flags & FNM_FILE_NAME
Packit 6c4009
				? flags : flags & ~FNM_PERIOD, NULL,
Packit 6c4009
				alloca_used) == 0)))
Packit 6c4009
	      /* It worked.  Signal success.  */
Packit 6c4009
	      goto success;
Packit 6c4009
	}
Packit 6c4009
      while ((list = list->next) != NULL);
Packit 6c4009
Packit 6c4009
      /* None of the patterns lead to a match.  */
Packit 6c4009
      retval = FNM_NOMATCH;
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case L('?'):
Packit 6c4009
      if (FCT (p, string, string_end, no_leading_period, flags, NULL,
Packit 6c4009
	       alloca_used) == 0)
Packit 6c4009
	goto success;
Packit 6c4009
      /* FALLTHROUGH */
Packit 6c4009
Packit 6c4009
    case L('@'):
Packit 6c4009
      do
Packit 6c4009
	/* I cannot believe it but `strcat' is actually acceptable
Packit 6c4009
	   here.  Match the entire string with the prefix from the
Packit 6c4009
	   pattern list and the rest of the pattern following the
Packit 6c4009
	   pattern list.  */
Packit 6c4009
	if (FCT (STRCAT (list->str, p), string, string_end,
Packit 6c4009
		 no_leading_period,
Packit 6c4009
		 flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD,
Packit 6c4009
		 NULL, alloca_used) == 0)
Packit 6c4009
	  /* It worked.  Signal success.  */
Packit 6c4009
	  goto success;
Packit 6c4009
      while ((list = list->next) != NULL);
Packit 6c4009
Packit 6c4009
      /* None of the patterns lead to a match.  */
Packit 6c4009
      retval = FNM_NOMATCH;
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case L('!'):
Packit 6c4009
      for (rs = string; rs <= string_end; ++rs)
Packit 6c4009
	{
Packit 6c4009
	  struct patternlist *runp;
Packit 6c4009
Packit 6c4009
	  for (runp = list; runp != NULL; runp = runp->next)
Packit 6c4009
	    if (FCT (runp->str, string, rs,  no_leading_period,
Packit 6c4009
		     flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD,
Packit 6c4009
		     NULL, alloca_used) == 0)
Packit 6c4009
	      break;
Packit 6c4009
Packit 6c4009
	  /* If none of the patterns matched see whether the rest does.  */
Packit 6c4009
	  if (runp == NULL
Packit 6c4009
	      && (FCT (p, rs, string_end,
Packit 6c4009
		       rs == string
Packit 6c4009
		       ? no_leading_period
Packit 6c4009
		       : rs[-1] == '/' && NO_LEADING_PERIOD (flags) ? 1 : 0,
Packit 6c4009
		       flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD,
Packit 6c4009
		       NULL, alloca_used) == 0))
Packit 6c4009
	    /* This is successful.  */
Packit 6c4009
	    goto success;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* None of the patterns together with the rest of the pattern
Packit 6c4009
	 lead to a match.  */
Packit 6c4009
      retval = FNM_NOMATCH;
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    default:
Packit 6c4009
      assert (! "Invalid extended matching operator");
Packit 6c4009
      retval = -1;
Packit 6c4009
      break;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
 success:
Packit 6c4009
 out:
Packit 6c4009
  if (any_malloced)
Packit 6c4009
    while (list != NULL)
Packit 6c4009
      {
Packit 6c4009
	struct patternlist *old = list;
Packit 6c4009
	list = list->next;
Packit 6c4009
	if (old->malloced)
Packit 6c4009
	  free (old);
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  return retval;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
#undef FOLD
Packit 6c4009
#undef CHAR
Packit 6c4009
#undef UCHAR
Packit 6c4009
#undef INT
Packit 6c4009
#undef FCT
Packit 6c4009
#undef EXT
Packit 6c4009
#undef END
Packit 6c4009
#undef STRUCT
Packit 6c4009
#undef MEMPCPY
Packit 6c4009
#undef MEMCHR
Packit 6c4009
#undef STRCOLL
Packit 6c4009
#undef STRLEN
Packit 6c4009
#undef STRCAT
Packit 6c4009
#undef L
Packit 6c4009
#undef BTOWC
Packit 6c4009
#undef WIDE_CHAR_VERSION
Packit 6c4009
#undef FINDIDX