123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474 |
- /* Copyright (C) 1991-1993, 1996-1999, 2000 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
- You should have received a copy of the GNU Library General Public
- License along with this library; see the file COPYING.LIB. If not,
- write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
- /* Match STRING against the filename pattern PATTERN, returning zero if
- it matches, nonzero if not. */
- static int FCT (const CHAR *pattern, const CHAR *string,
- int no_leading_period, int flags) internal_function;
- static int
- internal_function
- FCT (pattern, string, no_leading_period, flags)
- const CHAR *pattern;
- const CHAR *string;
- int no_leading_period;
- int flags;
- {
- register const CHAR *p = pattern, *n = string;
- register UCHAR c;
- #ifdef _LIBC
- const UCHAR *collseq = (const UCHAR *)
- _NL_CURRENT(LC_COLLATE, CONCAT(_NL_COLLATE_COLLSEQ,SUFFIX));
- # ifdef WIDE_CHAR_VERSION
- const wint_t *names = (const wint_t *)
- _NL_CURRENT (LC_COLLATE, _NL_COLLATE_NAMES);
- size_t size = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_HASH_SIZE);
- size_t layers = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_HASH_LAYERS);
- # endif
- #endif
- while ((c = *p++) != L('\0'))
- {
- c = FOLD (c);
- switch (c)
- {
- case L('?'):
- if (*n == L('\0'))
- return FNM_NOMATCH;
- else if (*n == L('/') && (flags & FNM_FILE_NAME))
- return FNM_NOMATCH;
- else if (*n == L('.') && no_leading_period
- && (n == string
- || (n[-1] == L('/') && (flags & FNM_FILE_NAME))))
- return FNM_NOMATCH;
- break;
- case L('\\'):
- if (!(flags & FNM_NOESCAPE))
- {
- c = *p++;
- if (c == L('\0'))
- /* Trailing \ loses. */
- return FNM_NOMATCH;
- c = FOLD (c);
- }
- if (FOLD ((UCHAR) *n) != c)
- return FNM_NOMATCH;
- break;
- case L('*'):
- if (*n == L('.') && no_leading_period
- && (n == string
- || (n[-1] == L('/') && (flags & FNM_FILE_NAME))))
- return FNM_NOMATCH;
- for (c = *p++; c == L('?') || c == L('*'); c = *p++)
- {
- if (*n == L('/') && (flags & FNM_FILE_NAME))
- /* A slash does not match a wildcard under FNM_FILE_NAME. */
- return FNM_NOMATCH;
- else if (c == L('?'))
- {
- /* A ? needs to match one character. */
- if (*n == L('\0'))
- /* There isn't another character; no match. */
- return FNM_NOMATCH;
- else
- /* One character of the string is consumed in matching
- this ? wildcard, so *??? won't match if there are
- less than three characters. */
- ++n;
- }
- }
- if (c == L('\0'))
- /* The wildcard(s) is/are the last element of the pattern.
- If the name is a file name and contains another slash
- this does mean it cannot match. If the FNM_LEADING_DIR
- flag is set and exactly one slash is following, we have
- a match. */
- {
- int result = (flags & FNM_FILE_NAME) == 0 ? 0 : FNM_NOMATCH;
- if (flags & FNM_FILE_NAME)
- {
- const CHAR *slashp = STRCHR (n, L('/'));
- if (flags & FNM_LEADING_DIR)
- {
- if (slashp != NULL
- && STRCHR (slashp + 1, L('/')) == NULL)
- result = 0;
- }
- else
- {
- if (slashp == NULL)
- result = 0;
- }
- }
- return result;
- }
- else
- {
- const CHAR *endp;
- endp = STRCHRNUL (n, (flags & FNM_FILE_NAME) ? L('/') : L('\0'));
- if (c == L('['))
- {
- int flags2 = ((flags & FNM_FILE_NAME)
- ? flags : (flags & ~FNM_PERIOD));
- for (--p; n < endp; ++n)
- if (FCT (p, n, (no_leading_period
- && (n == string
- || (n[-1] == L('/')
- && (flags & FNM_FILE_NAME)))),
- flags2) == 0)
- return 0;
- }
- else if (c == L('/') && (flags & FNM_FILE_NAME))
- {
- while (*n != L('\0') && *n != L('/'))
- ++n;
- if (*n == L('/')
- && (FCT (p, n + 1, flags & FNM_PERIOD, flags) == 0))
- return 0;
- }
- else
- {
- int flags2 = ((flags & FNM_FILE_NAME)
- ? flags : (flags & ~FNM_PERIOD));
- if (c == L('\\') && !(flags & FNM_NOESCAPE))
- c = *p;
- c = FOLD (c);
- for (--p; n < endp; ++n)
- if (FOLD ((UCHAR) *n) == c
- && (FCT (p, n, (no_leading_period
- && (n == string
- || (n[-1] == L('/')
- && (flags & FNM_FILE_NAME)))),
- flags2) == 0))
- return 0;
- }
- }
- /* If we come here no match is possible with the wildcard. */
- return FNM_NOMATCH;
- case L('['):
- {
- /* Nonzero if the sense of the character class is inverted. */
- static int posixly_correct;
- register int not;
- CHAR cold;
- if (posixly_correct == 0)
- posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
- if (*n == L('\0'))
- return FNM_NOMATCH;
- if (*n == L('.') && no_leading_period
- && (n == string
- || (n[-1] == L('/') && (flags & FNM_FILE_NAME))))
- return FNM_NOMATCH;
- if (*n == L('/') && (flags & FNM_FILE_NAME))
- /* `/' cannot be matched. */
- return FNM_NOMATCH;
- not = (*p == L('!') || (posixly_correct < 0 && *p == L('^')));
- if (not)
- ++p;
- c = *p++;
- for (;;)
- {
- UCHAR fn = FOLD ((UCHAR) *n);
- if (!(flags & FNM_NOESCAPE) && c == L('\\'))
- {
- if (*p == L('\0'))
- return FNM_NOMATCH;
- c = FOLD ((UCHAR) *p);
- ++p;
- if (c == fn)
- goto matched;
- }
- else if (c == L('[') && *p == L(':'))
- {
- /* Leave room for the null. */
- CHAR str[CHAR_CLASS_MAX_LENGTH + 1];
- size_t c1 = 0;
- #if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
- wctype_t wt;
- #endif
- const CHAR *startp = p;
- for (;;)
- {
- if (c1 == CHAR_CLASS_MAX_LENGTH)
- /* The name is too long and therefore the pattern
- is ill-formed. */
- return FNM_NOMATCH;
- c = *++p;
- if (c == L(':') && p[1] == L(']'))
- {
- p += 2;
- break;
- }
- if (c < L('a') || c >= L('z'))
- {
- /* This cannot possibly be a character class name.
- Match it as a normal range. */
- p = startp;
- c = L('[');
- goto normal_bracket;
- }
- str[c1++] = c;
- }
- str[c1] = L('\0');
- #if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
- wt = IS_CHAR_CLASS (str);
- if (wt == 0)
- /* Invalid character class name. */
- return FNM_NOMATCH;
- if (ISWCTYPE (BTOWC ((UCHAR) *n), wt))
- goto matched;
- #else
- if ((STREQ (str, L("alnum")) && ISALNUM ((UCHAR) *n))
- || (STREQ (str, L("alpha")) && ISALPHA ((UCHAR) *n))
- || (STREQ (str, L("blank")) && ISBLANK ((UCHAR) *n))
- || (STREQ (str, L("cntrl")) && ISCNTRL ((UCHAR) *n))
- || (STREQ (str, L("digit")) && ISDIGIT ((UCHAR) *n))
- || (STREQ (str, L("graph")) && ISGRAPH ((UCHAR) *n))
- || (STREQ (str, L("lower")) && ISLOWER ((UCHAR) *n))
- || (STREQ (str, L("print")) && ISPRINT ((UCHAR) *n))
- || (STREQ (str, L("punct")) && ISPUNCT ((UCHAR) *n))
- || (STREQ (str, L("space")) && ISSPACE ((UCHAR) *n))
- || (STREQ (str, L("upper")) && ISUPPER ((UCHAR) *n))
- || (STREQ (str, L("xdigit")) && ISXDIGIT ((UCHAR) *n)))
- goto matched;
- #endif
- }
- else if (c == L('\0'))
- /* [ (unterminated) loses. */
- return FNM_NOMATCH;
- else
- {
- c = FOLD (c);
- normal_bracket:
- if (c == fn)
- goto matched;
- cold = c;
- c = *p++;
- if (c == L('-') && *p != L(']'))
- {
- #if _LIBC
- /* We have to find the collation sequence
- value for C. Collation sequence is nothing
- we can regularly access. The sequence
- value is defined by the order in which the
- definitions of the collation values for the
- various characters appear in the source
- file. A strange concept, nowhere
- documented. */
- int32_t fseqidx;
- int32_t lseqidx;
- UCHAR cend = *p++;
- # ifdef WIDE_CHAR_VERSION
- size_t cnt;
- # endif
- if (!(flags & FNM_NOESCAPE) && cend == L('\\'))
- cend = *p++;
- if (cend == L('\0'))
- return FNM_NOMATCH;
- # ifdef WIDE_CHAR_VERSION
- /* Search in the `names' array for the characters. */
- fseqidx = fn % size;
- cnt = 0;
- while (names[fseqidx] != fn)
- {
- if (++cnt == layers)
- /* XXX We don't know anything about
- the character we are supposed to
- match. This means we are failing. */
- goto range_not_matched;
- fseqidx += size;
- }
- lseqidx = cold % size;
- cnt = 0;
- while (names[lseqidx] != cold)
- {
- if (++cnt == layers)
- {
- lseqidx = -1;
- break;
- }
- lseqidx += size;
- }
- # else
- fseqidx = fn;
- lseqidx = cold;
- # endif
- /* XXX It is not entirely clear to me how to handle
- characters which are not mentioned in the
- collation specification. */
- if (
- # ifdef WIDE_CHAR_VERSION
- lseqidx == -1 ||
- # endif
- collseq[lseqidx] <= collseq[fseqidx])
- {
- /* We have to look at the upper bound. */
- int32_t hseqidx;
- cend = FOLD (cend);
- # ifdef WIDE_CHAR_VERSION
- hseqidx = cend % size;
- cnt = 0;
- while (names[hseqidx] != cend)
- {
- if (++cnt == layers)
- {
- /* Hum, no information about the upper
- bound. The matching succeeds if the
- lower bound is matched exactly. */
- if (lseqidx == -1 || cold != fn)
- goto range_not_matched;
- goto matched;
- }
- }
- # else
- hseqidx = cend;
- # endif
- if (
- # ifdef WIDE_CHAR_VERSION
- (lseqidx == -1
- && collseq[fseqidx] == collseq[hseqidx]) ||
- # endif
- collseq[fseqidx] <= collseq[hseqidx])
- goto matched;
- }
- # ifdef WIDE_CHAR_VERSION
- range_not_matched:
- # endif
- #else
- /* We use a boring value comparison of the character
- values. This is better than comparing using
- `strcoll' since the latter would have surprising
- and sometimes fatal consequences. */
- UCHAR cend = *p++;
- if (!(flags & FNM_NOESCAPE) && cend == L('\\'))
- cend = *p++;
- if (cend == L('\0'))
- return FNM_NOMATCH;
- /* It is a range. */
- if (cold <= fc && fc <= c)
- goto matched;
- #endif
- c = *p++;
- }
- }
- if (c == L(']'))
- break;
- }
- if (!not)
- return FNM_NOMATCH;
- break;
- matched:
- /* Skip the rest of the [...] that already matched. */
- while (c != L(']'))
- {
- if (c == L('\0'))
- /* [... (unterminated) loses. */
- return FNM_NOMATCH;
- c = *p++;
- if (!(flags & FNM_NOESCAPE) && c == L('\\'))
- {
- if (*p == L('\0'))
- return FNM_NOMATCH;
- /* XXX 1003.2d11 is unclear if this is right. */
- ++p;
- }
- else if (c == L('[') && *p == L(':'))
- {
- do
- if (*++p == L('\0'))
- return FNM_NOMATCH;
- while (*p != L(':') || p[1] == L(']'));
- p += 2;
- c = *p;
- }
- }
- if (not)
- return FNM_NOMATCH;
- }
- break;
- default:
- if (c != FOLD ((UCHAR) *n))
- return FNM_NOMATCH;
- }
- ++n;
- }
- if (*n == '\0')
- return 0;
- if ((flags & FNM_LEADING_DIR) && *n == L('/'))
- /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
- return 0;
- return FNM_NOMATCH;
- }
- #undef FOLD
- #undef CHAR
- #undef UCHAR
- #undef FCT
- #undef STRCHR
- #undef STRCHRNUL
- #undef STRCOLL
- #undef L
- #undef BTOWC
- #undef SUFFIX
|