# HG changeset patch # User jwe # Date 856985004 0 # Node ID 655b1615eb54fb0a0511c870333da33a2af3fa1d # Parent 16e6f709009b047fea5c3bcbfa68f23ef40fc9ea [project @ 1997-02-26 19:21:14 by jwe] diff --git a/glob/configure.in b/glob/configure.in --- a/glob/configure.in +++ b/glob/configure.in @@ -13,7 +13,6 @@ AC_HEADER_STDC AC_CHECK_HEADERS(memory.h unistd.h string.h) AC_HEADER_DIRENT -AC_CHECK_FUNCS(bcopy bzero) AC_FUNC_CLOSEDIR_VOID AC_FUNC_ALLOCA AC_FUNC_STRCOLL diff --git a/glob/fnmatch.c b/glob/fnmatch.c --- a/glob/fnmatch.c +++ b/glob/fnmatch.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. +/* Copyright (C) 1991, 1992, 1993, 1996 Free Software Foundation, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as @@ -19,6 +19,11 @@ #include #endif +/* Enable GNU extensions in fnmatch.h. */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + #include #include #include @@ -73,6 +78,9 @@ if (!(flags & FNM_NOESCAPE)) { c = *p++; + if (c == '\0') + /* Trailing \ loses. */ + return FNM_NOMATCH; c = FOLD (c); } if (FOLD (*n) != c) @@ -84,10 +92,24 @@ (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) 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 ((flags & FNM_FILE_NAME) && *n == '/') + /* 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; @@ -124,7 +146,11 @@ register char cstart = c, cend = c; if (!(flags & FNM_NOESCAPE) && c == '\\') - cstart = cend = *p++; + { + if (*p == '\0') + return FNM_NOMATCH; + cstart = cend = *p++; + } cstart = cend = FOLD (cstart); @@ -171,8 +197,12 @@ 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; + } } if (not) return FNM_NOMATCH; diff --git a/glob/fnmatch.h b/glob/fnmatch.h --- a/glob/fnmatch.h +++ b/glob/fnmatch.h @@ -23,7 +23,8 @@ extern "C" { #endif -#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +#if (defined (__cplusplus) || (defined (__STDC__) && __STDC__) \ + || defined (WIN32)) #undef __P #define __P(protos) protos #else /* Not C++ or ANSI C. */ diff --git a/glob/glob.c b/glob/glob.c --- a/glob/glob.c +++ b/glob/glob.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +/* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as @@ -24,8 +24,14 @@ #include #endif +/* Enable GNU extensions in glob.h. */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + #include #include +#include /* Comment out all this code if we are using the GNU C Library, and are not @@ -36,8 +42,15 @@ 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__) +#define GLOB_INTERFACE_VERSION 1 +#if !defined (_LIBC) && defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1 +#include +#if _GNU_GLOB_INTERFACE_VERSION == GLOB_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif +#ifndef ELIDE_CODE #ifdef STDC_HEADERS #include @@ -52,6 +65,10 @@ #endif #endif +#if !defined (_AMIGA) && !defined (VMS) && !defined(WIN32) +#include +#endif + #if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) extern int errno; #endif @@ -61,28 +78,35 @@ #endif -#if defined (POSIX) || defined (HAVE_DIRENT_H) || defined (__GNU_LIBRARY__) -#include -#ifndef __GNU_LIBRARY__ -#define D_NAMLEN(d) strlen((d)->d_name) -#else /* GNU C library. */ -#define D_NAMLEN(d) ((d)->d_namlen) -#endif /* Not GNU C library. */ -#else /* Not POSIX or HAVE_DIRENT_H. */ -#define direct dirent -#define D_NAMLEN(d) ((d)->d_namlen) -#ifdef HAVE_SYS_NDIR_H -#include -#endif /* HAVE_SYS_NDIR_H */ -#ifdef HAVE_SYS_DIR_H -#include -#endif /* HAVE_SYS_DIR_H */ -#ifdef HAVE_NDIR_H -#include -#endif /* HAVE_NDIR_H */ -#endif /* POSIX or HAVE_DIRENT_H or __GNU_LIBRARY__. */ +#if defined (HAVE_DIRENT_H) || defined (__GNU_LIBRARY__) +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +# ifdef HAVE_VMSDIR_H +# include "vmsdir.h" +# endif /* HAVE_VMSDIR_H */ +#endif -#if defined (POSIX) && !defined (__GNU_LIBRARY__) + +/* In GNU systems, defines this macro for us. */ +#ifdef _D_NAMLEN +#undef NAMLEN +#define NAMLEN(d) _D_NAMLEN(d) +#endif + + +#if (defined (POSIX) || defined (WIN32)) && !defined (__GNU_LIBRARY__) /* Posix does not require that the d_ino field be present, and some systems do not provide it. */ #define REAL_DIR_ENTRY(dp) 1 @@ -96,6 +120,8 @@ #define ANSI_STRING #else /* No standard headers. */ +extern char *getenv (); + #ifdef HAVE_STRING_H #include #define ANSI_STRING @@ -139,7 +165,12 @@ #ifdef __GNUC__ __inline #endif +#ifndef __SASC +#ifdef WIN32 +static void * +#else static char * +#endif my_realloc (p, n) char *p; unsigned int n; @@ -151,7 +182,8 @@ return (char *) realloc (p, n); } #define realloc my_realloc -#endif +#endif /* __SASC */ +#endif /* __GNU_LIBRARY__ */ #if !defined(__alloca) && !defined(__GNU_LIBRARY__) @@ -160,11 +192,15 @@ #undef alloca #define alloca(n) __builtin_alloca (n) #else /* Not GCC. */ -#if defined (sparc) || defined (HAVE_ALLOCA_H) +#ifdef HAVE_ALLOCA_H #include -#else /* Not sparc or HAVE_ALLOCA_H. */ +#else /* Not HAVE_ALLOCA_H. */ #ifndef _AIX +#ifdef WIN32 +#include +#else extern char *alloca (); +#endif /* WIN32 */ #endif /* Not _AIX. */ #endif /* sparc or HAVE_ALLOCA_H. */ #endif /* GCC. */ @@ -173,6 +209,16 @@ #endif +#ifndef __GNU_LIBRARY__ +#define __stat stat +#ifdef STAT_MACROS_BROKEN +#undef S_ISDIR +#endif +#ifndef S_ISDIR +#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#endif +#endif + #ifndef STDC_HEADERS #undef size_t #define size_t unsigned int @@ -197,10 +243,6 @@ #undef GLOB_PERIOD #include -__ptr_t (*__glob_opendir_hook) __P ((const char *directory)); -const char *(*__glob_readdir_hook) __P ((__ptr_t stream)); -void (*__glob_closedir_hook) __P ((__ptr_t stream)); - static int glob_pattern_p __P ((const char *pattern, int quote)); static int glob_in_dir __P ((const char *pattern, const char *directory, int flags, @@ -236,12 +278,139 @@ return -1; } + if (flags & GLOB_BRACE) + { + const char *begin = strchr (pattern, '{'); + if (begin != NULL) + { + int firstc; + size_t restlen; + const char *p, *end, *next; + unsigned int depth = 0; + + /* Find the end of the brace expression, by counting braces. + While we're at it, notice the first comma at top brace level. */ + end = begin + 1; + next = NULL; + while (1) + { + switch (*end++) + { + case ',': + if (depth == 0 && next == NULL) + next = end; + continue; + case '{': + ++depth; + continue; + case '}': + if (depth-- == 0) + break; + continue; + case '\0': + return glob (pattern, flags &~ GLOB_BRACE, errfunc, pglob); + } + break; + } + restlen = strlen (end) + 1; + if (next == NULL) + next = end; + + /* We have a brace expression. BEGIN points to the opening {, + NEXT points past the terminator of the first element, and END + points past the final }. We will accumulate result names from + recursive runs for each brace alternative in the buffer using + GLOB_APPEND. */ + + if (!(flags & GLOB_APPEND)) + { + /* This call is to set a new vector, so clear out the + vector so we can append to it. */ + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + } + firstc = pglob->gl_pathc; + + /* In this loop P points to the beginning of the current element + and NEXT points past its terminator. */ + p = begin + 1; + while (1) + { + /* Construct a whole name that is one of the brace + alternatives in a temporary buffer. */ + int result; + size_t bufsz = (begin - pattern) + (next - 1 - p) + restlen; +#ifdef __GNUC__ + char onealt[bufsz]; +#else + char *onealt = malloc (bufsz); + if (onealt == NULL) + { + if (!(flags & GLOB_APPEND)) + globfree (pglob); + return GLOB_NOSPACE; + } +#endif + memcpy (onealt, pattern, begin - pattern); + memcpy (&onealt[begin - pattern], p, next - 1 - p); + memcpy (&onealt[(begin - pattern) + (next - 1 - p)], + end, restlen); + result = glob (onealt, + ((flags & ~(GLOB_NOCHECK|GLOB_NOMAGIC)) | + GLOB_APPEND), errfunc, pglob); +#ifndef __GNUC__ + free (onealt); +#endif + + /* If we got an error, return it. */ + if (result && result != GLOB_NOMATCH) + { + if (!(flags & GLOB_APPEND)) + globfree (pglob); + return result; + } + + /* Advance past this alternative and process the next. */ + p = next; + depth = 0; + scan: + switch (*p++) + { + case ',': + if (depth == 0) + { + /* Found the next alternative. Loop to glob it. */ + next = p; + continue; + } + goto scan; + case '{': + ++depth; + goto scan; + case '}': + if (depth-- == 0) + /* End of the brace expression. Break out of the loop. */ + break; + goto scan; + } + } + + if (pglob->gl_pathc == firstc && + !(flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) + return GLOB_NOMATCH; + } + } + /* Find the filename. */ filename = strrchr (pattern, '/'); if (filename == NULL) { filename = pattern; +#ifdef _AMIGA + dirname = (char *) ""; +#else dirname = (char *) "."; +#endif dirlen = 0; } else if (filename == pattern) @@ -277,6 +446,57 @@ oldcount = pglob->gl_pathc; +#ifndef VMS + if ((flags & GLOB_TILDE) && dirname[0] == '~') + { + if (dirname[1] == '\0') + { + /* Look up home directory. */ + dirname = getenv ("HOME"); +#ifdef _AMIGA + if (dirname == NULL || dirname[0] == '\0') + dirname = "SYS:"; +#else +#ifdef WIN32 + if (dirname == NULL || dirname[0] == '\0') + dirname = "c:/users/default"; /* poor default */ +#else + if (dirname == NULL || dirname[0] == '\0') + { + extern char *getlogin __P ((void)); + char *name = getlogin (); + if (name != NULL) + { + struct passwd *p = getpwnam (name); + if (p != NULL) + dirname = p->pw_dir; + } + } + if (dirname == NULL || dirname[0] == '\0') + dirname = (char *) "~"; /* No luck. */ +#endif /* WIN32 */ +#endif + } + else + { +#ifdef _AMIGA + if (dirname == NULL || dirname[0] == '\0') + dirname = "SYS:"; +#else +#ifdef WIN32 + if (dirname == NULL || dirname[0] == '\0') + dirname = "c:/users/default"; /* poor default */ +#else + /* Look up specific user's home directory. */ + struct passwd *p = getpwnam (dirname + 1); + if (p != NULL) + dirname = p->pw_dir; +#endif /* WIN32 */ +#endif + } + } +#endif /* Not VMS. */ + if (glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE))) { /* The directory name contains metacharacters, so we @@ -394,9 +614,32 @@ } } + if (flags & GLOB_MARK) + { + /* Append slashes to directory names. */ + int i; + struct stat st; + for (i = oldcount; i < pglob->gl_pathc; ++i) + if (((flags & GLOB_ALTDIRFUNC) ? + (*pglob->gl_stat) (pglob->gl_pathv[i], &st) : + __stat (pglob->gl_pathv[i], &st)) == 0 && + S_ISDIR (st.st_mode)) + { + size_t len = strlen (pglob->gl_pathv[i]) + 2; + char *new = realloc (pglob->gl_pathv[i], len); + if (new == NULL) + { + globfree (pglob); + return GLOB_NOSPACE; + } + strcpy (&new[len - 2], "/"); + pglob->gl_pathv[i] = new; + } + } + if (!(flags & GLOB_NOSORT)) /* Sort the vector. */ - qsort ((__ptr_t) & pglob->gl_pathv[oldcount], + qsort ((__ptr_t) &pglob->gl_pathv[oldcount], pglob->gl_pathc - oldcount, sizeof (char *), collated_compare); @@ -497,7 +740,7 @@ return 1; case '\\': - if (quote) + if (quote && p[1] != '\0') ++p; break; @@ -546,8 +789,9 @@ { flags |= GLOB_MAGCHAR; - stream = (__glob_opendir_hook ? (*__glob_opendir_hook) (directory) - : (__ptr_t) opendir (directory)); + stream = ((flags & GLOB_ALTDIRFUNC) ? + (*pglob->gl_opendir) (directory) : + (__ptr_t) opendir (directory)); if (stream == NULL) { if ((errfunc != NULL && (*errfunc) (directory, errno)) || @@ -559,44 +803,32 @@ { const char *name; size_t len; + struct dirent *d = ((flags & GLOB_ALTDIRFUNC) ? + (*pglob->gl_readdir) (stream) : + readdir ((DIR *) stream)); + if (d == NULL) + break; + if (! REAL_DIR_ENTRY (d)) + continue; - if (__glob_readdir_hook) - { - name = (*__glob_readdir_hook) (stream); - if (name == NULL) - break; - len = 0; - } - else - { - struct dirent *d = readdir ((DIR *) stream); - if (d == NULL) - break; - if (! REAL_DIR_ENTRY (d)) - continue; - name = d->d_name; -#ifdef HAVE_D_NAMLEN - len = d->d_namlen; -#else - len = 0; -#endif - } - + name = d->d_name; + if (fnmatch (pattern, name, (!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) | - ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)) == 0) + ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) +#ifdef _AMIGA + | FNM_CASEFOLD +#endif + ) == 0) { struct globlink *new = (struct globlink *) __alloca (sizeof (struct globlink)); - if (len == 0) - len = strlen (name); + len = NAMLEN (d); new->name - = (char *) malloc (len + ((flags & GLOB_MARK) ? 1 : 0) + 1); + = (char *) malloc (len + 1); if (new->name == NULL) goto memory_error; memcpy ((__ptr_t) new->name, name, len); - if (flags & GLOB_MARK) - new->name[len++] = '/'; new->name[len] = '\0'; new->next = names; names = new; @@ -605,18 +837,20 @@ } } + if (nfound == 0 && (flags & GLOB_NOMAGIC) && + ! glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE))) + flags |= GLOB_NOCHECK; + if (nfound == 0 && (flags & GLOB_NOCHECK)) { size_t len = strlen (pattern); nfound = 1; names = (struct globlink *) __alloca (sizeof (struct globlink)); names->next = NULL; - names->name = (char *) malloc (len + ((flags & GLOB_MARK) ? 1 : 0) + 1); + names->name = (char *) malloc (len + 1); if (names->name == NULL) goto memory_error; memcpy (names->name, pattern, len); - if (flags & GLOB_MARK) - names->name[len++] = '/'; names->name[len] = '\0'; } @@ -642,10 +876,10 @@ if (stream != NULL) { int save = errno; - if (__glob_closedir_hook) - (*__glob_closedir_hook) (stream); + if (flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir) (stream); else - (void) closedir ((DIR *) stream); + closedir ((DIR *) stream); errno = save; } return nfound == 0 ? GLOB_NOMATCH : 0; @@ -653,10 +887,10 @@ memory_error: { int save = errno; - if (__glob_closedir_hook) - (*__glob_closedir_hook) (stream); + if (flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir) (stream); else - (void) closedir ((DIR *) stream); + closedir ((DIR *) stream); errno = save; } while (names != NULL) @@ -668,4 +902,5 @@ return GLOB_NOSPACE; } -#endif /* _LIBC or not __GNU_LIBRARY__. */ +#endif /* Not ELIDE_CODE. */ + diff --git a/glob/glob.h b/glob/glob.h --- a/glob/glob.h +++ b/glob/glob.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +/* Copyright (C) 1991, 1992, 1995, 1996 Free Software Foundation, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as @@ -25,7 +25,8 @@ #endif #undef __ptr_t -#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +#if (defined (__cplusplus) || (defined (__STDC__) && __STDC__) \ + || defined (WIN32)) #undef __P #define __P(protos) protos #define __ptr_t void * @@ -47,10 +48,16 @@ #define GLOB_NOESCAPE (1 << 6)/* Backslashes don't quote metacharacters. */ #define GLOB_PERIOD (1 << 7)/* Leading `.' can be matched by metachars. */ #define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \ - GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND|GLOB_PERIOD) + GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \ + GLOB_PERIOD|GLOB_ALTDIRFUNC|GLOB_BRACE| \ + GLOB_NOMAGIC|GLOB_TILDE) #if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_BSD_SOURCE) #define GLOB_MAGCHAR (1 << 8)/* Set in gl_flags if any metachars seen. */ +#define GLOB_ALTDIRFUNC (1 << 9)/* Use gl_opendir et al functions. */ +#define GLOB_BRACE (1 << 10)/* Expand "{a,b}" to "a" "b". */ +#define GLOB_NOMAGIC (1 << 11)/* If no magic chars, return the pattern. */ +#define GLOB_TILDE (1 <<12)/* Expand ~user and ~ to home directories. */ #endif /* Error returns from `glob'. */ @@ -59,12 +66,23 @@ #define GLOB_NOMATCH 3 /* No matches found. */ /* Structure describing a globbing run. */ +#if !defined (_AMIGA) && !defined (VMS) /* Buggy compiler. */ +struct stat; +#endif typedef struct { int gl_pathc; /* Count of paths matched by the pattern. */ char **gl_pathv; /* List of matched pathnames. */ int gl_offs; /* Slots to reserve in `gl_pathv'. */ int gl_flags; /* Set to FLAGS, maybe | GLOB_MAGCHAR. */ + + /* If the GLOB_ALTDIRFUNC flag is set, the following functions + are used instead of the normal file access functions. */ + void (*gl_closedir) __P ((void *)); + struct dirent *(*gl_readdir) __P ((void *)); + __ptr_t (*gl_opendir) __P ((const char *)); + int (*gl_lstat) __P ((const char *, struct stat *)); + int (*gl_stat) __P ((const char *, struct stat *)); } glob_t; /* Do glob searching for PATTERN, placing results in PGLOB. @@ -83,13 +101,6 @@ extern void globfree __P ((glob_t *__pglob)); -#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE) -/* If they are not NULL, `glob' uses these functions to read directories. */ -extern __ptr_t (*__glob_opendir_hook) __P ((const char *__directory)); -extern const char *(*__glob_readdir_hook) __P ((__ptr_t __stream)); -extern void (*__glob_closedir_hook) __P ((__ptr_t __stream)); -#endif - #ifdef __cplusplus } #endif