diff options
-rw-r--r-- | misc/fnmatch.c | 453 | ||||
-rw-r--r-- | misc/fnmatch.h | 65 | ||||
-rw-r--r-- | misc/setenv.c | 11 |
3 files changed, 424 insertions, 105 deletions
diff --git a/misc/fnmatch.c b/misc/fnmatch.c index ca38e1daf..e5570c286 100644 --- a/misc/fnmatch.c +++ b/misc/fnmatch.c @@ -1,21 +1,51 @@ -/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. +/* 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. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +/* Enable GNU extensions in fnmatch.h. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif -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. +#include <errno.h> +#include <fnmatch.h> +#include <ctype.h> -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. +#if HAVE_STRING_H || defined _LIBC +# include <string.h> +#else +# include <strings.h> +#endif -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., 675 Mass Ave, -Cambridge, MA 02139, USA. */ +#if defined STDC_HEADERS || defined _LIBC +# include <stdlib.h> +#endif -#include "system.h" +/* For platform which support the ISO C amendement 1 functionality we + support user defined character classes. */ +#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) +/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */ +# include <wchar.h> +# include <wctype.h> +#endif /* 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 @@ -25,26 +55,96 @@ Cambridge, MA 02139, USA. */ program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ -#if defined (_LIBC) || !defined (__GNU_LIBRARY__) +#if defined _LIBC || !defined __GNU_LIBRARY__ -#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) -extern int errno; +# if defined STDC_HEADERS || !defined isascii +# define ISASCII(c) 1 +# else +# define ISASCII(c) isascii(c) +# endif + +#ifdef isblank +# define ISBLANK(c) (ISASCII (c) && isblank (c)) +#else +# define ISBLANK(c) ((c) == ' ' || (c) == '\t') #endif +#ifdef isgraph +# define ISGRAPH(c) (ISASCII (c) && isgraph (c)) +#else +# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c)) +#endif + +#define ISPRINT(c) (ISASCII (c) && isprint (c)) +#define ISDIGIT(c) (ISASCII (c) && isdigit (c)) +#define ISALNUM(c) (ISASCII (c) && isalnum (c)) +#define ISALPHA(c) (ISASCII (c) && isalpha (c)) +#define ISCNTRL(c) (ISASCII (c) && iscntrl (c)) +#define ISLOWER(c) (ISASCII (c) && islower (c)) +#define ISPUNCT(c) (ISASCII (c) && ispunct (c)) +#define ISSPACE(c) (ISASCII (c) && isspace (c)) +#define ISUPPER(c) (ISASCII (c) && isupper (c)) +#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c)) + +# define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) + +# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) +/* The GNU C library provides support for user-defined character classes + and the functions from ISO C amendement 1. */ +# ifdef CHARCLASS_NAME_MAX +# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX +# else +/* This shouldn't happen but some implementation might still have this + problem. Use a reasonable default value. */ +# define CHAR_CLASS_MAX_LENGTH 256 +# endif + +# ifdef _LIBC +# define IS_CHAR_CLASS(string) __wctype (string) +# else +# define IS_CHAR_CLASS(string) wctype (string) +# endif +# else +# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ + +# define IS_CHAR_CLASS(string) \ + (STREQ (string, "alpha") || STREQ (string, "upper") \ + || STREQ (string, "lower") || STREQ (string, "digit") \ + || STREQ (string, "alnum") || STREQ (string, "xdigit") \ + || STREQ (string, "space") || STREQ (string, "print") \ + || STREQ (string, "punct") || STREQ (string, "graph") \ + || STREQ (string, "cntrl") || STREQ (string, "blank")) +# endif + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +# if !defined _LIBC && !defined getenv +extern char *getenv (); +# endif + +# ifndef errno +extern int errno; +# endif /* Match STRING against the filename pattern PATTERN, returning zero if it matches, nonzero if not. */ -int -fnmatch (pattern, string, flags) - const char *pattern; - const char *string; - int flags; +static int +#ifdef _LIBC +internal_function +#endif +internal_fnmatch (const char *pattern, const char *string, + int no_leading_period, int flags) { register const char *p = pattern, *n = string; - register char c; + register unsigned char c; -/* Note that this evalutes C many times. */ -#define FOLD(c) ((flags & FNM_CASEFOLD) && isupper (c) ? tolower (c) : (c)) +/* Note that this evaluates C many times. */ +# ifdef _LIBC +# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c)) +# else +# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c)) +# endif while ((c = *p++) != '\0') { @@ -55,10 +155,11 @@ fnmatch (pattern, string, flags) case '?': if (*n == '\0') return FNM_NOMATCH; - else if ((flags & FNM_FILE_NAME) && *n == '/') + else if (*n == '/' && (flags & FNM_FILE_NAME)) return FNM_NOMATCH; - else if ((flags & FNM_PERIOD) && *n == '.' && - (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + else if (*n == '.' && no_leading_period + && (n == string + || (n[-1] == '/' && (flags & FNM_FILE_NAME)))) return FNM_NOMATCH; break; @@ -66,95 +167,274 @@ fnmatch (pattern, string, flags) if (!(flags & FNM_NOESCAPE)) { c = *p++; + if (c == '\0') + /* Trailing \ loses. */ + return FNM_NOMATCH; c = FOLD (c); } - if (FOLD (*n) != c) + if (FOLD ((unsigned char) *n) != c) return FNM_NOMATCH; break; case '*': - if ((flags & FNM_PERIOD) && *n == '.' && - (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + if (*n == '.' && no_leading_period + && (n == string + || (n[-1] == '/' && (flags & FNM_FILE_NAME)))) return FNM_NOMATCH; - for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) - if (((flags & FNM_FILE_NAME) && *n == '/') || - (c == '?' && *n == '\0')) - return FNM_NOMATCH; + for (c = *p++; c == '?' || c == '*'; c = *p++) + { + if (*n == '/' && (flags & FNM_FILE_NAME)) + /* A slash does not match a wildcard under FNM_FILE_NAME. */ + return FNM_NOMATCH; + else if (c == '?') + { + /* A ? needs to match one character. */ + if (*n == '\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 == '\0') - return 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, '/'); + + if (flags & FNM_LEADING_DIR) + { + if (slashp != NULL + && strchr (slashp + 1, '/') == NULL) + result = 0; + } + else + { + if (slashp == NULL) + result = 0; + } + } + + return result; + } + else + { + const char *endp; + + endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0'); + + if (c == '[') + { + int flags2 = ((flags & FNM_FILE_NAME) + ? flags : (flags & ~FNM_PERIOD)); + + for (--p; n < endp; ++n) + if (internal_fnmatch (p, n, + (no_leading_period + && (n == string + || (n[-1] == '/' + && (flags + & FNM_FILE_NAME)))), + flags2) + == 0) + return 0; + } + else if (c == '/' && (flags & FNM_FILE_NAME)) + { + while (*n != '\0' && *n != '/') + ++n; + if (*n == '/' + && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD, + flags) == 0)) + return 0; + } + else + { + int flags2 = ((flags & FNM_FILE_NAME) + ? flags : (flags & ~FNM_PERIOD)); + + if (c == '\\' && !(flags & FNM_NOESCAPE)) + c = *p; + c = FOLD (c); + for (--p; n < endp; ++n) + if (FOLD ((unsigned char) *n) == c + && (internal_fnmatch (p, n, + (no_leading_period + && (n == string + || (n[-1] == '/' + && (flags + & FNM_FILE_NAME)))), + flags2) == 0)) + return 0; + } + } - { - char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; - c1 = FOLD (c1); - for (--p; *n != '\0'; ++n) - if ((c == '[' || FOLD (*n) == c1) && - fnmatch (p, n, flags & ~FNM_PERIOD) == 0) - return 0; - return FNM_NOMATCH; - } + /* If we come here no match is possible with the wildcard. */ + return FNM_NOMATCH; case '[': { /* 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 == '\0') return FNM_NOMATCH; - if ((flags & FNM_PERIOD) && *n == '.' && - (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + if (*n == '.' && no_leading_period && (n == string + || (n[-1] == '/' + && (flags + & FNM_FILE_NAME)))) return FNM_NOMATCH; - not = (*p == '!' || *p == '^'); + if (*n == '/' && (flags & FNM_FILE_NAME)) + /* `/' cannot be matched. */ + return FNM_NOMATCH; + + not = (*p == '!' || (posixly_correct < 0 && *p == '^')); if (not) ++p; c = *p++; for (;;) { - register char cstart = c, cend = c; + unsigned char fn = FOLD ((unsigned char) *n); if (!(flags & FNM_NOESCAPE) && c == '\\') - cstart = cend = *p++; + { + if (*p == '\0') + return FNM_NOMATCH; + c = FOLD ((unsigned char) *p); + ++p; - cstart = cend = FOLD (cstart); + if (c == fn) + goto matched; + } + else if (c == '[' && *p == ':') + { + /* 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 == ':' && p[1] == ']') + { + p += 2; + break; + } + if (c < 'a' || c >= 'z') + { + /* This cannot possibly be a character class name. + Match it as a normal range. */ + p = startp; + c = '['; + goto normal_bracket; + } + str[c1++] = c; + } + str[c1] = '\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 (c == '\0') + if (__iswctype (__btowc ((unsigned char) *n), wt)) + goto matched; +# else + if ((STREQ (str, "alnum") && ISALNUM ((unsigned char) *n)) + || (STREQ (str, "alpha") && ISALPHA ((unsigned char) *n)) + || (STREQ (str, "blank") && ISBLANK ((unsigned char) *n)) + || (STREQ (str, "cntrl") && ISCNTRL ((unsigned char) *n)) + || (STREQ (str, "digit") && ISDIGIT ((unsigned char) *n)) + || (STREQ (str, "graph") && ISGRAPH ((unsigned char) *n)) + || (STREQ (str, "lower") && ISLOWER ((unsigned char) *n)) + || (STREQ (str, "print") && ISPRINT ((unsigned char) *n)) + || (STREQ (str, "punct") && ISPUNCT ((unsigned char) *n)) + || (STREQ (str, "space") && ISSPACE ((unsigned char) *n)) + || (STREQ (str, "upper") && ISUPPER ((unsigned char) *n)) + || (STREQ (str, "xdigit") && ISXDIGIT ((unsigned char) *n))) + goto matched; +# endif + } + else if (c == '\0') /* [ (unterminated) loses. */ return FNM_NOMATCH; - - c = *p++; - c = FOLD (c); - - if ((flags & FNM_FILE_NAME) && c == '/') - /* [/] can never match. */ - return FNM_NOMATCH; - - if (c == '-' && *p != ']') + else { - cend = *p++; - if (!(flags & FNM_NOESCAPE) && cend == '\\') - cend = *p++; - if (cend == '\0') - return FNM_NOMATCH; - cend = FOLD (cend); + c = FOLD (c); + normal_bracket: + if (c == fn) + goto matched; + cold = c; c = *p++; - } - if (FOLD (*n) >= cstart && FOLD (*n) <= cend) - goto matched; + if (c == '-' && *p != ']') + { + /* It is a range. */ + char lo[2]; + char fc[2]; + unsigned char cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return FNM_NOMATCH; + + lo[0] = cold; + lo[1] = '\0'; + fc[0] = fn; + fc[1] = '\0'; + if (strcoll (lo, fc) <= 0) + { + char hi[2]; + hi[0] = FOLD (cend); + hi[1] = '\0'; + if (strcoll (fc, hi) <= 0) + goto matched; + } + + c = *p++; + } + } if (c == ']') break; } + if (!not) return FNM_NOMATCH; break; - matched:; + matched: /* Skip the rest of the [...] that already matched. */ while (c != ']') { @@ -164,8 +444,21 @@ fnmatch (pattern, string, flags) c = *p++; if (!(flags & FNM_NOESCAPE) && c == '\\') - /* XXX 1003.2d11 is unclear if this is right. */ - ++p; + { + if (*p == '\0') + return FNM_NOMATCH; + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } + else if (c == '[' && *p == ':') + { + do + if (*++p == '\0') + return FNM_NOMATCH; + while (*p != ':' || p[1] == ']'); + p += 2; + c = *p; + } } if (not) return FNM_NOMATCH; @@ -173,7 +466,7 @@ fnmatch (pattern, string, flags) break; default: - if (c != FOLD (*n)) + if (c != FOLD ((unsigned char) *n)) return FNM_NOMATCH; } @@ -188,6 +481,18 @@ fnmatch (pattern, string, flags) return 0; return FNM_NOMATCH; + +# undef FOLD +} + + +int +fnmatch (pattern, string, flags) + const char *pattern; + const char *string; + int flags; +{ + return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags); } #endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/misc/fnmatch.h b/misc/fnmatch.h index d9d73b3d8..eeaee7fb8 100644 --- a/misc/fnmatch.h +++ b/misc/fnmatch.h @@ -1,39 +1,48 @@ -/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. +/* Copyright (C) 1991, 92, 93, 96, 97, 98 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. + The GNU C 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. + The GNU C 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., 675 Mass Ave, -Cambridge, MA 02139, USA. */ + You should have received a copy of the GNU Library General Public + License along with the GNU C 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. */ #ifndef _FNMATCH_H - #define _FNMATCH_H 1 #ifdef __cplusplus extern "C" { #endif -#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) -#undef __P -#define __P(protos) protos +#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32 +# if !defined __GLIBC__ || !defined __P +# undef __P +# define __P(protos) protos +# endif #else /* Not C++ or ANSI C. */ -#undef __P -#define __P(protos) () +# undef __P +# define __P(protos) () /* We can get away without defining `const' here only because in this file it is used only inside the prototype for `fnmatch', which is elided in non-ANSI C where `const' is problematical. */ #endif /* C++ or ANSI C. */ +#ifndef const +# if (defined __STDC__ && __STDC__) || defined __cplusplus +# define __const const +# else +# define __const +# endif +#endif /* We #undef these before defining them because some losing systems (HP-UX A.08.07 for example) define these in <unistd.h>. */ @@ -46,18 +55,26 @@ extern "C" { #define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ #define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ -#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE) -#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. */ +#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE +# 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. */ #endif /* Value returned by `fnmatch' if STRING does not match PATTERN. */ #define FNM_NOMATCH 1 +/* This value is returned if the implementation does not support + `fnmatch'. Since this is not the case here it will never be + returned but the conformance test suites still require the symbol + to be defined. */ +#ifdef _XOPEN_SOURCE +# define FNM_NOSYS (-1) +#endif + /* Match STRING against the filename pattern PATTERN, returning zero if it matches, FNM_NOMATCH if not. */ -extern int fnmatch __P ((const char *__pattern, const char *__string, +extern int fnmatch __P ((__const char *__pattern, __const char *__string, int __flags)); #ifdef __cplusplus diff --git a/misc/setenv.c b/misc/setenv.c index 12d984afe..daf1e02f4 100644 --- a/misc/setenv.c +++ b/misc/setenv.c @@ -104,12 +104,9 @@ static char **last_environ; must be used directly. This is all complicated by the fact that we try to reuse values once generated for a `setenv' call since we can never free the strings. */ -int -__add_to_environ (name, value, combined, replace) - const char *name; - const char *value; - const char *combined; - int replace; +static int +__add_to_environ (const char *name, const char *value, const char *combined, + int replace) { register char **ep; register size_t size; @@ -292,7 +289,7 @@ unsetenv (name) never made it. Nevertheless the POSIX.9 standard (POSIX bindings for Fortran 77) requires this function. */ int -clearenv () +clearenv (void) { LOCK; |