From 955994e1313ab81c1db2a456b5fdf7cacb016366 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Thu, 15 Mar 2001 09:36:19 +0000 Subject: [PATCH] Update. 2001-03-15 Ulrich Drepper * posix/fnmatch.h (FNM_EXTMATCH): Define. * posix/fnmatch.c (NO_LEADING_PERIOD): Define. (posixly_correct): Move global variable here. (INT, EXT, END): Name new functions defined in fnmatch_loop.c. (fnmatch): Pretty printing. * posix/fnmatch_loop.c: Add code to handle FNM_EXTMATCH. * posix/tst-fnmatch.c: Recognize EXTMATCH flag. * posix/tst-fnmatch.input: Add tests for extended matching. * posix/testfnm.c: Add test for patterns with multiple ** before /. * posix/fnmatch_loop.c: Fix problem with the test above. --- ChangeLog | 14 ++ posix/fnmatch.c | 88 ++++++---- posix/fnmatch.h | 3 +- posix/fnmatch_loop.c | 372 +++++++++++++++++++++++++++++++++++----- posix/testfnm.c | 3 + posix/tst-fnmatch.c | 15 +- posix/tst-fnmatch.input | 138 ++++++++++++++- 7 files changed, 548 insertions(+), 85 deletions(-) diff --git a/ChangeLog b/ChangeLog index 23bc92a543..da0bcbbf56 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2001-03-15 Ulrich Drepper + + * posix/fnmatch.h (FNM_EXTMATCH): Define. + * posix/fnmatch.c (NO_LEADING_PERIOD): Define. + (posixly_correct): Move global variable here. + (INT, EXT, END): Name new functions defined in fnmatch_loop.c. + (fnmatch): Pretty printing. + * posix/fnmatch_loop.c: Add code to handle FNM_EXTMATCH. + * posix/tst-fnmatch.c: Recognize EXTMATCH flag. + * posix/tst-fnmatch.input: Add tests for extended matching. + + * posix/testfnm.c: Add test for patterns with multiple ** before /. + * posix/fnmatch_loop.c: Fix problem with the test above. + 2001-03-14 Ulrich Drepper * sysdeps/ieee754/dbl-64/e_sqrt.c (__ieee754_sqrt): Remove diff --git a/posix/fnmatch.c b/posix/fnmatch.c index d0d70027d6..98c5ffc5ca 100644 --- a/posix/fnmatch.c +++ b/posix/fnmatch.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991-1993, 1996-1999, 2000 Free Software Foundation, Inc. +/* Copyright (C) 1991-1993,1996-1999,2000,2001 Free Software Foundation, Inc. This file is part of the GNU C Library. This library is free software; you can redistribute it and/or @@ -61,6 +61,10 @@ # define mbsrtowcs __mbsrtowcs #endif +/* We often have to test for FNM_FILE_NAME and FNM_PERIOD being both set. */ +#define NO_LEADING_PERIOD(flags) \ + ((flags & (FNM_FILE_NAME | FNM_PERIOD)) == (FNM_FILE_NAME | FNM_PERIOD)) + /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling @@ -153,6 +157,9 @@ extern char *getenv (); extern int errno; # endif +/* Global variable. */ +static int posixly_correct; + /* This function doesn't exist on most systems. */ # if !defined HAVE___STRCHRNUL && !defined _LIBC @@ -195,15 +202,18 @@ __wcschrnul (s, c) # endif # define CHAR char # define UCHAR unsigned char +# define INT int # define FCT internal_fnmatch +# define EXT ext_match +# define END end_pattern # define L(CS) CS # ifdef _LIBC # define BTOWC(C) __btowc (C) # else # define BTOWC(C) btowc (C) # endif -# define STRCHR(S, C) strchr (S, C) -# define STRCHRNUL(S, C) __strchrnul (S, C) +# define MEMPCPY(D, S, N) __mempcpy (D, S, N) +# define MEMCHR(S, C, N) memchr (S, C, N) # define STRCOLL(S1, S2) strcoll (S1, S2) # include "fnmatch_loop.c" @@ -217,11 +227,14 @@ __wcschrnul (s, c) # endif # define CHAR wchar_t # define UCHAR wint_t +# define INT wint_t # define FCT internal_fnwmatch +# define EXT ext_wmatch +# define END end_wpattern # define L(CS) L##CS # define BTOWC(C) (C) -# define STRCHR(S, C) wcschr (S, C) -# define STRCHRNUL(S, C) __wcschrnul (S, C) +# define MEMPCPY(D, S, N) __wmempcpy (D, S, N) +# define MEMCHR(S, C, N) wmemchr (S, C, N) # define STRCOLL(S1, S2) wcscoll (S1, S2) # define WIDE_CHAR_VERSION 1 @@ -303,42 +316,43 @@ fnmatch (pattern, string, flags) int flags; { # if HANDLE_MULTIBYTE - mbstate_t ps; - size_t n; - wchar_t *wpattern; - wchar_t *wstring; + if (__builtin_expect (MB_CUR_MAX, 1) != 1) + { + mbstate_t ps; + size_t n; + wchar_t *wpattern; + wchar_t *wstring; - if (MB_CUR_MAX == 1) - /* This is an optimization for 8-bit character set. */ - return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags); + /* Convert the strings into wide characters. */ + memset (&ps, '\0', sizeof (ps)); + n = mbsrtowcs (NULL, &pattern, 0, &ps); + if (__builtin_expect (n, 0) == (size_t) -1) + /* Something wrong. + XXX Do we have to set `errno' to something which mbsrtows hasn't + already done? */ + return -1; + wpattern = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t)); + assert (mbsinit (&ps)); + (void) mbsrtowcs (wpattern, &pattern, n + 1, &ps); - /* Convert the strings into wide characters. */ - memset (&ps, '\0', sizeof (ps)); - n = mbsrtowcs (NULL, &pattern, 0, &ps); - if (n == (size_t) -1) - /* Something wrong. - XXX Do we have to set `errno' to something which mbsrtows hasn't - already done? */ - return -1; - wpattern = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t)); - assert (mbsinit (&ps)); - (void) mbsrtowcs (wpattern, &pattern, n + 1, &ps); + assert (mbsinit (&ps)); + n = mbsrtowcs (NULL, &string, 0, &ps); + if (__builtin_expect (n, 0) == (size_t) -1) + /* Something wrong. + XXX Do we have to set `errno' to something which mbsrtows hasn't + already done? */ + return -1; + wstring = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t)); + assert (mbsinit (&ps)); + (void) mbsrtowcs (wstring, &string, n + 1, &ps); - assert (mbsinit (&ps)); - n = mbsrtowcs (NULL, &string, 0, &ps); - if (n == (size_t) -1) - /* Something wrong. - XXX Do we have to set `errno' to something which mbsrtows hasn't - already done? */ - return -1; - wstring = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t)); - assert (mbsinit (&ps)); - (void) mbsrtowcs (wstring, &string, n + 1, &ps); - - return internal_fnwmatch (wpattern, wstring, flags & FNM_PERIOD, flags); -# else - return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags); + return internal_fnwmatch (wpattern, wstring, wstring + n, + flags & FNM_PERIOD, flags); + } # endif /* mbstate_t and mbsrtowcs or _LIBC. */ + + return internal_fnmatch (pattern, string, string + strlen (string), + flags & FNM_PERIOD, flags); } #endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/posix/fnmatch.h b/posix/fnmatch.h index cc3ec37940..56cb561e61 100644 --- a/posix/fnmatch.h +++ b/posix/fnmatch.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc. +/* Copyright (C) 1991,92,93,96,97,98,99,2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -59,6 +59,7 @@ extern "C" { # define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ # define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ # define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +# define FNM_EXTMATCH (1 << 5) /* Use ksh-like extended matching. */ #endif /* Value returned by `fnmatch' if STRING does not match PATTERN. */ diff --git a/posix/fnmatch_loop.c b/posix/fnmatch_loop.c index a453aec835..e9c7af2b7e 100644 --- a/posix/fnmatch_loop.c +++ b/posix/fnmatch_loop.c @@ -19,13 +19,19 @@ /* 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; + const CHAR *string_end, int no_leading_period, int flags) + internal_function; +static int EXT (INT opt, const CHAR *pattern, const CHAR *string, + const CHAR *string_end, int no_leading_period, int flags) + internal_function; +static const CHAR *END (const CHAR *patternp) internal_function; static int internal_function -FCT (pattern, string, no_leading_period, flags) +FCT (pattern, string, string_end, no_leading_period, flags) const CHAR *pattern; const CHAR *string; + const CHAR *string_end; int no_leading_period; int flags; { @@ -43,18 +49,27 @@ FCT (pattern, string, no_leading_period, flags) while ((c = *p++) != L('\0')) { + int new_no_leading_period = 0; c = FOLD (c); switch (c) { case L('?'): - if (*n == L('\0')) + if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(') + { + int res; + + res = EXT (c, p, n, string_end, no_leading_period, + flags); + if (res != -1) + return res; + } + + if (n == string_end) 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)))) + else if (*n == L('.') && no_leading_period) return FNM_NOMATCH; break; @@ -67,27 +82,48 @@ FCT (pattern, string, no_leading_period, flags) return FNM_NOMATCH; c = FOLD (c); } - if (FOLD ((UCHAR) *n) != c) + if (n == string_end || 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)))) + if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(') + { + int res; + + res = EXT (c, p, n, string_end, no_leading_period, + flags); + if (res != -1) + return res; + } + + if (n != string_end && *n == L('.') && no_leading_period) 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('?')) + if (*p == L('(') && (flags & FNM_EXTMATCH) != 0) + { + const CHAR *endp = END (p); + if (endp != p) + { + /* This is a pattern. Skip over it. */ + p = endp; + continue; + } + } + + if (c == L('?')) { /* A ? needs to match one character. */ - if (*n == L('\0')) + if (n == string_end) /* There isn't another character; no match. */ return FNM_NOMATCH; + else if (*n == L('/') + && __builtin_expect (flags & FNM_FILE_NAME, 0)) + /* A slash does not match a wildcard under + FNM_FILE_NAME. */ + return FNM_NOMATCH; else /* One character of the string is consumed in matching this ? wildcard, so *??? won't match if there are @@ -110,7 +146,7 @@ FCT (pattern, string, no_leading_period, flags) result = 0; else { - if (STRCHR (n, L('/')) == NULL) + if (MEMCHR (n, L('/'), string_end - n) == NULL) result = 0; } } @@ -121,44 +157,47 @@ FCT (pattern, string, no_leading_period, flags) { const CHAR *endp; - endp = STRCHRNUL (n, (flags & FNM_FILE_NAME) ? L('/') : L('\0')); + endp = MEMCHR (n, (flags & FNM_FILE_NAME) ? L('/') : L('\0'), + string_end - n); + if (endp == NULL) + endp = string_end; - if (c == L('[')) + if (c == L('[') + || (__builtin_expect (flags & FNM_EXTMATCH, 0) != 0 + /* XXX Do we have to add '!'? */ + && (c == L('@') || c == L('+')) && *p == L('('))) { int flags2 = ((flags & FNM_FILE_NAME) ? flags : (flags & ~FNM_PERIOD)); + int no_leading_period2 = no_leading_period; - for (--p; n < endp; ++n) - if (FCT (p, n, (no_leading_period - && (n == string - || (n[-1] == L('/') - && (flags & FNM_FILE_NAME)))), - flags2) == 0) + for (--p; n < endp; ++n, no_leading_period2 = 0) + if (FCT (p, n, string_end, no_leading_period2, flags2) + == 0) return 0; } else if (c == L('/') && (flags & FNM_FILE_NAME)) { - while (*n != L('\0') && *n != L('/')) + while (n < string_end && *n != L('/')) ++n; - if (*n == L('/') - && (FCT (p, n + 1, flags & FNM_PERIOD, flags) == 0)) + if (n < string_end && *n == L('/') + && (FCT (p, n + 1, string_end, flags & FNM_PERIOD, flags) + == 0)) return 0; } else { int flags2 = ((flags & FNM_FILE_NAME) ? flags : (flags & ~FNM_PERIOD)); + int no_leading_period2 = no_leading_period; if (c == L('\\') && !(flags & FNM_NOESCAPE)) c = *p; c = FOLD (c); - for (--p; n < endp; ++n) + for (--p; n < endp; ++n, no_leading_period2 = 0) if (FOLD ((UCHAR) *n) == c - && (FCT (p, n, (no_leading_period - && (n == string - || (n[-1] == L('/') - && (flags & FNM_FILE_NAME)))), - flags2) == 0)) + && (FCT (p, n, string_end, no_leading_period2, flags2) + == 0)) return 0; } } @@ -168,20 +207,18 @@ FCT (pattern, string, no_leading_period, flags) case L('['): { - static int posixly_correct; /* Nonzero if the sense of the character class is inverted. */ register int not; CHAR cold; + UCHAR fn; if (posixly_correct == 0) posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; - if (*n == L('\0')) + if (n == string_end) return FNM_NOMATCH; - if (*n == L('.') && no_leading_period - && (n == string - || (n[-1] == L('/') && (flags & FNM_FILE_NAME)))) + if (*n == L('.') && no_leading_period) return FNM_NOMATCH; if (*n == L('/') && (flags & FNM_FILE_NAME)) @@ -192,11 +229,11 @@ FCT (pattern, string, no_leading_period, flags) if (not) ++p; + fn = FOLD ((UCHAR) *n); + c = *p++; for (;;) { - UCHAR fn = FOLD ((UCHAR) *n); - if (!(flags & FNM_NOESCAPE) && c == L('\\')) { if (*p == L('\0')) @@ -878,30 +915,275 @@ FCT (pattern, string, no_leading_period, flags) } break; + case L('+'): + case L('@'): + case L('!'): + if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(') + { + int res; + + res = EXT (c, p, n, string_end, no_leading_period, flags); + if (res != -1) + return res; + } + goto normal_match; + + case L('/'): + if (NO_LEADING_PERIOD (flags)) + { + if (n == string_end || c != *n) + return FNM_NOMATCH; + + new_no_leading_period = 1; + break; + } + /* FALLTHROUGH */ default: - if (c != FOLD ((UCHAR) *n)) + normal_match: + if (n == string_end || c != FOLD ((UCHAR) *n)) return FNM_NOMATCH; } + no_leading_period = new_no_leading_period; ++n; } - if (*n == '\0') + if (n == string_end) return 0; - if ((flags & FNM_LEADING_DIR) && *n == L('/')) + if ((flags & FNM_LEADING_DIR) && n != string_end && *n == L('/')) /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ return 0; return FNM_NOMATCH; } + +static const CHAR * +internal_function +END (const CHAR *pattern) +{ + const CHAR *p = pattern; + + while (1) + if (*++p == L('\0')) + /* This is an invalid pattern. */ + return pattern; + else if (*p == L('[')) + { + /* Handle brackets special. */ + if (posixly_correct == 0) + posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; + + /* Skip the not sign. We have to recognize it because of a possibly + following ']'. */ + if (*++p == L('!') || (posixly_correct < 0 && *p == L('^'))) + ++p; + /* A leading ']' is recognized as such. */ + if (*p == L(']')) + ++p; + /* Skip over all characters of the list. */ + while (*p != L(']')) + if (*p++ == L('\0')) + /* This is no valid pattern. */ + return pattern; + } + else if ((*p == L('?') || *p == L('*') || *p == L('+') || *p == L('@') + || *p == L('!')) && p[1] == L('(')) + p = END (p + 1); + else if (*p == L(')')) + break; + + return p + 1; +} + + +static int +internal_function +EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end, + int no_leading_period, int flags) +{ + const CHAR *startp; + int level; + struct patternlist + { + struct patternlist *next; + CHAR str[0]; + } *list = NULL; + struct patternlist **lastp = &list; + const CHAR *p; + const CHAR *rs; + + /* Parse the pattern. Store the individual parts in the list. */ + level = 0; + for (startp = p = pattern + 1; level >= 0; ++p) + if (*p == L('\0')) + /* This is an invalid pattern. */ + return -1; + else if (*p == L('[')) + { + /* Handle brackets special. */ + if (posixly_correct == 0) + posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; + + /* Skip the not sign. We have to recognize it because of a possibly + following ']'. */ + if (*++p == L('!') || (posixly_correct < 0 && *p == L('^'))) + ++p; + /* A leading ']' is recognized as such. */ + if (*p == L(']')) + ++p; + /* Skip over all characters of the list. */ + while (*p != L(']')) + if (*p++ == L('\0')) + /* This is no valid pattern. */ + return -1; + } + else if ((*p == L('?') || *p == L('*') || *p == L('+') || *p == L('@') + || *p == L('!')) && p[1] == L('(')) + /* Remember the nesting level. */ + ++level; + else if (*p == L(')')) + { + if (level-- == 0) + { + /* This means we found the end of the pattern. */ +#define NEW_PATTERN \ + struct patternlist *newp = alloca (sizeof (struct patternlist) \ + + ((p - startp + 1) \ + * sizeof (CHAR))); \ + *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L('\0'); \ + newp->next = NULL; \ + *lastp = newp; \ + lastp = &newp->next + NEW_PATTERN; + } + } + else if (*p == L('|')) + { + if (level == 0) + { + NEW_PATTERN; + startp = p + 1; + } + } + assert (list != NULL); + assert (p[-1] == L(')')); + + switch (opt) + { + case L('*'): + if (FCT (p, string, string_end, no_leading_period, flags) == 0) + return 0; + /* FALLTHROUGH */ + + case L('+'): + do + { + for (rs = string; rs <= string_end; ++rs) + /* First match the prefix with the current pattern with the + current pattern. */ + if (FCT (list->str, string, rs, no_leading_period, + flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0 + /* This was successful. Now match the rest with the rest + of the pattern. */ + && (FCT (p, rs, string_end, + rs == string + ? no_leading_period + : rs[-1] == '/' && NO_LEADING_PERIOD (flags) ? 1 : 0, + flags & FNM_FILE_NAME + ? flags : flags & ~FNM_PERIOD) == 0 + /* This didn't work. Try the whole pattern. */ + || (rs != string + && FCT (pattern - 1, rs, string_end, + rs == string + ? no_leading_period + : (rs[-1] == '/' && NO_LEADING_PERIOD (flags) + ? 1 : 0), + flags & FNM_FILE_NAME + ? flags : flags & ~FNM_PERIOD) == 0))) + /* It worked. Signal success. */ + return 0; + } + while ((list = list->next) != NULL); + + /* None of the patterns lead to a match. */ + return FNM_NOMATCH; + + case L('?'): + if (FCT (p, string, string_end, no_leading_period, flags) == 0) + return 0; + /* FALLTHROUGH */ + + case L('@'): + do + { + for (rs = string; rs <= string_end; ++rs) + /* First match the prefix with the current pattern with the + current pattern. */ + if (FCT (list->str, string, rs, no_leading_period, + flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0 + /* This was successful. Now match the rest of the strings + with the rest of the pattern. */ + && (FCT (p, rs, string_end, + rs == string + ? no_leading_period + : (rs[-1] == '/' && NO_LEADING_PERIOD (flags) + ? 1 : 0), + flags & FNM_FILE_NAME + ? flags : flags & ~FNM_PERIOD) == 0)) + /* It worked. Signal success. */ + return 0; + } + while ((list = list->next) != NULL); + + /* None of the patterns lead to a match. */ + return FNM_NOMATCH; + + case L('!'): + for (rs = string; rs <= string_end; ++rs) + { + struct patternlist *runp; + + for (runp = list; runp != NULL; runp = runp->next) + if (FCT (runp->str, string, rs, no_leading_period, + flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0) + break; + + /* If none of the patterns matched see whether the rest does. */ + if (runp == NULL + && (FCT (p, rs, string_end, + rs == string + ? no_leading_period + : rs[-1] == '/' && NO_LEADING_PERIOD (flags) ? 1 : 0, + flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) + == 0)) + /* This is successful. */ + return 0; + } + + /* None of the patterns together with the rest of the pattern + lead to a match. */ + return FNM_NOMATCH; + + default: + assert (! "Invalid extended matching operator"); + break; + } + + return -1; +} + + #undef FOLD #undef CHAR #undef UCHAR +#undef INT #undef FCT -#undef STRCHR -#undef STRCHRNUL +#undef EXT +#undef END +#undef MEMPCPY +#undef MEMCHR #undef STRCOLL #undef L #undef BTOWC diff --git a/posix/testfnm.c b/posix/testfnm.c index b735a26579..f3165324e9 100644 --- a/posix/testfnm.c +++ b/posix/testfnm.c @@ -54,6 +54,9 @@ struct { { "a/b", "*a*", FNM_PATHNAME|FNM_LEADING_DIR, 0 }, { "ab/c", "*a?", FNM_PATHNAME|FNM_LEADING_DIR, 0 }, { "ab/c", "a?", FNM_PATHNAME|FNM_LEADING_DIR, 0 }, + { "a/b", "?*/?", FNM_PATHNAME, 0 }, + { "/b", "*/?", FNM_PATHNAME, 0 }, + { "/b", "**/?", FNM_PATHNAME, 0 }, }; int diff --git a/posix/tst-fnmatch.c b/posix/tst-fnmatch.c index 719361519c..eee50c6424 100644 --- a/posix/tst-fnmatch.c +++ b/posix/tst-fnmatch.c @@ -1,5 +1,5 @@ /* Tests for fnmatch function. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000, 2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -263,6 +263,12 @@ convert_flags (const char *str) result |= FNM_CASEFOLD; len = 8; } + else if (strncasecmp (str, "EXTMATCH", 8) == 0 + && (str[8] == '|' || str[8] == '\0')) + { + result |= FNM_EXTMATCH; + len = 8; + } else return -1; @@ -315,6 +321,13 @@ flag_output (int flags) cp = stpcpy (cp, "FNM_CASEFOLD"); first = 0; } + if (flags & FNM_EXTMATCH) + { + if (! first) + *cp++ = '|'; + cp = stpcpy (cp, "FNM_EXTMATCH"); + first = 0; + } if (cp == buf) *cp++ = '0'; *cp = '\0'; diff --git a/posix/tst-fnmatch.input b/posix/tst-fnmatch.input index 6add86c662..6ae0a2aa82 100644 --- a/posix/tst-fnmatch.input +++ b/posix/tst-fnmatch.input @@ -348,7 +348,7 @@ C "\\/\\$" "\\/\\$" 0 NOESCAPE # B.6 033(C) C ".asd" ".*" 0 PERIOD -C "/.asd" "*" 0 PERIOD +C "/.asd" "*" 0 PERIOD C "/as/.df" "*/?*f" 0 PERIOD C "..asd" ".[!a-z]*" 0 PERIOD @@ -370,6 +370,17 @@ C "/." "/[!a-z]" NOMATCH PATHNAME|PERIOD C "/a./.b." "/*/*" NOMATCH PATHNAME|PERIOD C "/a./.b." "/??/???" NOMATCH PATHNAME|PERIOD +# Some home-grown tests. +C "foobar" "foo*[abc]z" NOMATCH +C "foobaz" "foo*[abc][xyz]" 0 +C "foobaz" "foo?*[abc][xyz]" 0 +C "foobaz" "foo?*[abc][x/yz]" 0 +C "foobaz" "foo?*[abc]/[xyz]" NOMATCH PATHNAME +C "a" "a/" NOMATCH PATHNAME +C "a/" "a" NOMATCH PATHNAME +C "//a" "/a" NOMATCH PATHNAME +C "/a" "//a" NOMATCH PATHNAME + # Following are tests outside the scope of IEEE 2003.2 since they are using # locales other than the C locale. The main focus of the tests is on the # handling of ranges and the recognition of character (vs bytes). @@ -578,3 +589,128 @@ C "x/y/z" "x/y" 0 PATHNAME|LEADING_DIR C "x" "x?y" NOMATCH PATHNAME|LEADING_DIR C "x/y" "x?y" NOMATCH PATHNAME|LEADING_DIR C "x/y/z" "x?y" NOMATCH PATHNAME|LEADING_DIR + +# ksh style matching. +C "abcd" "?@(a|b)*@(c)d" 0 EXTMATCH +C "/dev/udp/129.22.8.102/45" "/dev/@(tcp|udp)/*/*" 0 PATHNAME|EXTMATCH +C "12" "[1-9]*([0-9])" 0 EXTMATCH +C "12abc" "[1-9]*([0-9])" NOMATCH EXTMATCH +C "1" "[1-9]*([0-9])" 0 EXTMATCH +C "07" "+([0-7])" 0 EXTMATCH +C "0377" "+([0-7])" 0 EXTMATCH +C "09" "+([0-7])" NOMATCH EXTMATCH +C "paragraph" "para@(chute|graph)" 0 EXTMATCH +C "paramour" "para@(chute|graph)" NOMATCH EXTMATCH +C "para991" "para?([345]|99)1" 0 EXTMATCH +C "para381" "para?([345]|99)1" NOMATCH EXTMATCH +C "paragraph" "para*([0-9])" NOMATCH EXTMATCH +C "para" "para*([0-9])" 0 EXTMATCH +C "para13829383746592" "para*([0-9])" 0 EXTMATCH +C "paragraph" "para+([0-9])" NOMATCH EXTMATCH +C "para" "para+([0-9])" NOMATCH EXTMATCH +C "para987346523" "para+([0-9])" 0 EXTMATCH +C "paragraph" "para!(*.[0-9])" 0 EXTMATCH +C "para.38" "para!(*.[0-9])" 0 EXTMATCH +C "para.graph" "para!(*.[0-9])" 0 EXTMATCH +C "para39" "para!(*.[0-9])" 0 EXTMATCH +C "" "*(0|1|3|5|7|9)" 0 EXTMATCH +C "137577991" "*(0|1|3|5|7|9)" 0 EXTMATCH +C "2468" "*(0|1|3|5|7|9)" NOMATCH EXTMATCH +C "1358" "*(0|1|3|5|7|9)" NOMATCH EXTMATCH +C "file.c" "*.c?(c)" 0 EXTMATCH +C "file.C" "*.c?(c)" NOMATCH EXTMATCH +C "file.cc" "*.c?(c)" 0 EXTMATCH +C "file.ccc" "*.c?(c)" NOMATCH EXTMATCH +C "parse.y" "!(*.c|*.h|Makefile.in|config*|README)" 0 EXTMATCH +C "shell.c" "!(*.c|*.h|Makefile.in|config*|README)" NOMATCH EXTMATCH +C "Makefile" "!(*.c|*.h|Makefile.in|config*|README)" 0 EXTMATCH +C "VMS.FILE;1" "*\;[1-9]*([0-9])" 0 EXTMATCH +C "VMS.FILE;0" "*\;[1-9]*([0-9])" NOMATCH EXTMATCH +C "VMS.FILE;" "*\;[1-9]*([0-9])" NOMATCH EXTMATCH +C "VMS.FILE;139" "*\;[1-9]*([0-9])" 0 EXTMATCH +C "VMS.FILE;1N" "*\;[1-9]*([0-9])" NOMATCH EXTMATCH +C "abcfefg" "ab**(e|f)" 0 EXTMATCH +C "abcfefg" "ab**(e|f)g" 0 EXTMATCH +C "ab" "ab*+(e|f)" NOMATCH EXTMATCH +C "abef" "ab***ef" 0 EXTMATCH +C "abef" "ab**" 0 EXTMATCH +C "fofo" "*(f*(o))" 0 EXTMATCH +C "ffo" "*(f*(o))" 0 EXTMATCH +C "foooofo" "*(f*(o))" 0 EXTMATCH +C "foooofof" "*(f*(o))" 0 EXTMATCH +C "fooofoofofooo" "*(f*(o))" 0 EXTMATCH +C "foooofof" "*(f+(o))" NOMATCH EXTMATCH +C "xfoooofof" "*(f*(o))" NOMATCH EXTMATCH +C "foooofofx" "*(f*(o))" NOMATCH EXTMATCH +C "ofxoofxo" "*(*(of*(o)x)o)" 0 EXTMATCH +C "ofooofoofofooo" "*(f*(o))" NOMATCH EXTMATCH +C "foooxfooxfoxfooox" "*(f*(o)x)" 0 EXTMATCH +C "foooxfooxofoxfooox" "*(f*(o)x)" NOMATCH EXTMATCH +C "foooxfooxfxfooox" "*(f*(o)x)" 0 EXTMATCH +C "ofxoofxo" "*(*(of*(o)x)o)" 0 EXTMATCH +C "ofoooxoofxo" "*(*(of*(o)x)o)" 0 EXTMATCH +C "ofoooxoofxoofoooxoofxo" "*(*(of*(o)x)o)" 0 EXTMATCH +C "ofoooxoofxoofoooxoofxoo" "*(*(of*(o)x)o)" 0 EXTMATCH +C "ofoooxoofxoofoooxoofxofo" "*(*(of*(o)x)o)" NOMATCH EXTMATCH +C "ofoooxoofxoofoooxoofxooofxofxo" "*(*(of*(o)x)o)" 0 EXTMATCH +C "aac" "*(@(a))a@(c)" 0 EXTMATCH +C "ac" "*(@(a))a@(c)" 0 EXTMATCH +C "c" "*(@(a))a@(c)" NOMATCH EXTMATCH +C "aaac" "*(@(a))a@(c)" 0 EXTMATCH +C "baaac" "*(@(a))a@(c)" NOMATCH EXTMATCH +C "abcd" "?@(a|b)*@(c)d" 0 EXTMATCH +C "abcd" "@(ab|a*@(b))*(c)d" 0 EXTMATCH +C "acd" "@(ab|a*(b))*(c)d" 0 EXTMATCH +C "abbcd" "@(ab|a*(b))*(c)d" 0 EXTMATCH +C "effgz" "@(b+(c)d|e*(f)g?|?(h)i@(j|k))" 0 EXTMATCH +C "efgz" "@(b+(c)d|e*(f)g?|?(h)i@(j|k))" 0 EXTMATCH +C "egz" "@(b+(c)d|e*(f)g?|?(h)i@(j|k))" 0 EXTMATCH +C "egzefffgzbcdij" "*(b+(c)d|e*(f)g?|?(h)i@(j|k))" 0 EXTMATCH +C "egz" "@(b+(c)d|e+(f)g?|?(h)i@(j|k))" NOMATCH EXTMATCH +C "ofoofo" "*(of+(o))" 0 EXTMATCH +C "oxfoxoxfox" "*(oxf+(ox))" 0 EXTMATCH +C "oxfoxfox" "*(oxf+(ox))" NOMATCH EXTMATCH +C "ofoofo" "*(of+(o)|f)" 0 EXTMATCH +C "foofoofo" "@(foo|f|fo)*(f|of+(o))" 0 EXTMATCH +C "oofooofo" "*(of|oof+(o))" 0 EXTMATCH +C "fffooofoooooffoofffooofff" "*(*(f)*(o))" 0 EXTMATCH +C "fofoofoofofoo" "*(fo|foo)" 0 EXTMATCH +C "foo" "!(x)" 0 EXTMATCH +C "foo" "!(x)*" 0 EXTMATCH +C "foo" "!(foo)" NOMATCH EXTMATCH +C "foo" "!(foo)*" 0 EXTMATCH +C "foobar" "!(foo)" 0 EXTMATCH +C "foobar" "!(foo)*" 0 EXTMATCH +C "moo.cow" "!(*.*).!(*.*)" 0 EXTMATCH +C "mad.moo.cow" "!(*.*).!(*.*)" NOMATCH EXTMATCH +C "mucca.pazza" "mu!(*(c))?.pa!(*(z))?" NOMATCH EXTMATCH +C "fff" "!(f)" 0 EXTMATCH +C "fff" "*(!(f))" 0 EXTMATCH +C "fff" "+(!(f))" 0 EXTMATCH +C "ooo" "!(f)" 0 EXTMATCH +C "ooo" "*(!(f))" 0 EXTMATCH +C "ooo" "+(!(f))" 0 EXTMATCH +C "foo" "!(f)" 0 EXTMATCH +C "foo" "*(!(f))" 0 EXTMATCH +C "foo" "+(!(f))" 0 EXTMATCH +C "f" "!(f)" NOMATCH EXTMATCH +C "f" "*(!(f))" NOMATCH EXTMATCH +C "f" "+(!(f))" NOMATCH EXTMATCH +C "foot" "@(!(z*)|*x)" 0 EXTMATCH +C "zoot" "@(!(z*)|*x)" NOMATCH EXTMATCH +C "foox" "@(!(z*)|*x)" 0 EXTMATCH +C "zoox" "@(!(z*)|*x)" 0 EXTMATCH +C "foo" "*(!(foo)) 0 EXTMATCH +C "foob" "!(foo)b*" NOMATCH EXTMATCH +C "foobb" "!(foo)b*" 0 EXTMATCH +C "[" "*([a[])" 0 EXTMATCH +C "]" "*([]a[])" 0 EXTMATCH +C "a" "*([]a[])" 0 EXTMATCH +C "b" "*([!]a[])" 0 EXTMATCH +C "[" "*([!]a[]|[[])" 0 EXTMATCH +C "]" "*([!]a[]|[]])" 0 EXTMATCH +C "[" "!([!]a[])" 0 EXTMATCH +C "]" "!([!]a[])" 0 EXTMATCH +C ")" "*([)])" 0 EXTMATCH +C "*" "*([*(])" 0 EXTMATCH +C "abcd" "*!(|a)cd" NOMATCH EXTMATCH