📄 glob.c
字号:
/* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc.This library is free software; you can redistribute it and/ormodify it under the terms of the GNU Library General Public License aspublished by the Free Software Foundation; either version 2 of theLicense, 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNULibrary General Public License for more details.You should have received a copy of the GNU Library General PublicLicense along with this library; see the file COPYING.LIB. Ifnot, write to the Free Software Foundation, Inc., 675 Mass Ave,Cambridge, MA 02139, USA. *//* AIX requires this to be the first thing in the file. */#if defined (_AIX) && !defined (__GNUC__) #pragma alloca#endif#ifdef HAVE_CONFIG_H#include <config.h>#endif/* Enable GNU extensions in glob.h. */#ifndef _GNU_SOURCE#define _GNU_SOURCE 1#endif#include <errno.h>#include <sys/types.h>#include <sys/stat.h>/* 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 and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU 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. */#define GLOB_INTERFACE_VERSION 1#if !defined (_LIBC) && defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1#include <gnu-versions.h>#if _GNU_GLOB_INTERFACE_VERSION == GLOB_INTERFACE_VERSION#define ELIDE_CODE#endif#endif#ifndef ELIDE_CODE#ifdef STDC_HEADERS#include <stddef.h>#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#ifndef POSIX#ifdef _POSIX_VERSION#define POSIX#endif#endif#endif#if !defined (_AMIGA) && !defined (VMS) && !defined(WIN32)#include <pwd.h>#endif#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)extern int errno;#endif#ifndef NULL#define NULL 0#endif#if defined (HAVE_DIRENT_H) || defined (__GNU_LIBRARY__)# include <dirent.h># define NAMLEN(dirent) strlen((dirent)->d_name)#else# define dirent direct# define NAMLEN(dirent) (dirent)->d_namlen# ifdef HAVE_SYS_NDIR_H# include <sys/ndir.h># endif# ifdef HAVE_SYS_DIR_H# include <sys/dir.h># endif# ifdef HAVE_NDIR_H# include <ndir.h># endif# ifdef HAVE_VMSDIR_H# include "vmsdir.h"# endif /* HAVE_VMSDIR_H */#endif/* In GNU systems, <dirent.h> 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#else#define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)#endif /* POSIX */#if (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__))#include <stdlib.h>#include <string.h>#define ANSI_STRING#else /* No standard headers. */extern char *getenv ();#ifdef HAVE_STRING_H#include <string.h>#define ANSI_STRING#else#include <strings.h>#endif#ifdef HAVE_MEMORY_H#include <memory.h>#endifextern char *malloc (), *realloc ();extern void free ();extern void qsort ();extern void abort (), exit ();#endif /* Standard headers. */#ifndef ANSI_STRING#ifndef bzeroextern void bzero ();#endif#ifndef bcopyextern void bcopy ();#endif#define memcpy(d, s, n) bcopy ((s), (d), (n))#define strrchr rindex/* memset is only used for zero here, but let's be paranoid. */#define memset(s, better_be_zero, n) \ ((void) ((better_be_zero) == 0 ? (bzero((s), (n)), 0) : (abort(), 0)))#endif /* Not ANSI_STRING. */#ifndef HAVE_STRCOLL#define strcoll strcmp#endif#ifndef __GNU_LIBRARY__#ifdef __GNUC____inline#endif#ifndef __SASC#ifdef WIN32static void *#elsestatic char *#endifmy_realloc (p, n) char *p; unsigned int n;{ /* These casts are the for sake of the broken Ultrix compiler, which warns of illegal pointer combinations otherwise. */ if (p == NULL) return (char *) malloc (n); return (char *) realloc (p, n);}#define realloc my_realloc#endif /* __SASC */#endif /* __GNU_LIBRARY__ */#if !defined(__alloca) && !defined(__GNU_LIBRARY__)#ifdef __GNUC__#undef alloca#define alloca(n) __builtin_alloca (n)#else /* Not GCC. */#ifdef HAVE_ALLOCA_H#include <alloca.h>#else /* Not HAVE_ALLOCA_H. */#ifndef _AIX#ifdef WIN32#include <malloc.h>#elseextern char *alloca ();#endif /* WIN32 */#endif /* Not _AIX. */#endif /* sparc or HAVE_ALLOCA_H. */#endif /* GCC. */#define __alloca alloca#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#endif/* Some system header files erroneously define these. We want our own definitions from <fnmatch.h> to take precedence. */#undef FNM_PATHNAME#undef FNM_NOESCAPE#undef FNM_PERIOD#include <fnmatch.h>/* Some system header files erroneously define these. We want our own definitions from <glob.h> to take precedence. */#undef GLOB_ERR#undef GLOB_MARK#undef GLOB_NOSORT#undef GLOB_DOOFFS#undef GLOB_NOCHECK#undef GLOB_APPEND#undef GLOB_NOESCAPE#undef GLOB_PERIOD#include <glob.h>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, int (*errfunc) __P ((const char *, int)), glob_t *pglob));static int prefix_array __P ((const char *prefix, char **array, size_t n));static int collated_compare __P ((const __ptr_t, const __ptr_t));/* Do glob searching for PATTERN, placing results in PGLOB. The bits defined above may be set in FLAGS. If a directory cannot be opened or read and ERRFUNC is not nil, it is called with the pathname that caused the error, and the `errno' value from the failing call; if it returns non-zero `glob' returns GLOB_ABEND; if it returns zero, the error is ignored. If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned. Otherwise, `glob' returns zero. */intglob (pattern, flags, errfunc, pglob) const char *pattern; int flags; int (*errfunc) __P ((const char *, int)); glob_t *pglob;{ const char *filename; char *dirname; size_t dirlen; int status; int oldcount; if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0) { errno = EINVAL; 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) { /* "/pattern". */ dirname = (char *) "/"; dirlen = 1; ++filename; } else { dirlen = filename - pattern; dirname = (char *) __alloca (dirlen + 1); memcpy (dirname, pattern, dirlen); dirname[dirlen] = '\0'; ++filename; } if (filename[0] == '\0' && dirlen > 1) /* "pattern/". Expand "pattern", appending slashes. */ { int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob); if (val == 0) pglob->gl_flags = (pglob->gl_flags & ~GLOB_MARK) | (flags & GLOB_MARK); return val; } if (!(flags & GLOB_APPEND)) { pglob->gl_pathc = 0; pglob->gl_pathv = NULL; } oldcount = pglob->gl_pathc;#ifndef VMS if ((flags & GLOB_TILDE) && dirname[0] == '~') { if (dirname[1] == '\0') { /* Look up home directory. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -