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