Blame gnulib/lib/fnmatch_loop.c

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