Blame lib/fnmatch_loop.c

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