Blame lib/fnmatch_loop.c

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