⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 glob.c

📁 它通过提供glibc兼容使得应用程序移植到较小的c 库时相当得容易. 它能够应用到带虚拟存储的Linux和uClinux上.在大多数带MMU部件的平台上为使它更加紧凑,它也能够编译成共享库.uClib
💻 C
字号:
/* Copyright (C) 1991, 1992, 1993, 1994, 1995 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.  */#include <stdlib.h>#include <string.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <dirent.h>#include <malloc.h>#include <fnmatch.h>#include <glob.h>extern __ptr_t (*__glob_opendir_hook) __P ((const char *directory));extern void (*__glob_closedir_hook) __P ((__ptr_t stream));extern const char *(*__glob_readdir_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,			     int (*errfunc) __P ((const char *, int)),			     glob_t *pglob));static int prefix_array __P ((const char *prefix, char **array, size_t n,			      int add_slash));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;    }  /* Find the filename.  */  filename = strrchr (pattern, '/');  if (filename == NULL)    {      filename = pattern;      dirname = (char *) ".";      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;  if (glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE)))    {      /* The directory name contains metacharacters, so we	 have to glob for the directory, and then glob for	 the pattern in each directory found.  */      glob_t dirs;      register int i;      status = glob (dirname,		     ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE)) |		      GLOB_NOSORT),		     errfunc, &dirs);      if (status != 0)	return status;      /* We have successfully globbed the preceding directory name.	 For each name we found, call glob_in_dir on it and FILENAME,	 appending the results to PGLOB.  */      for (i = 0; i < dirs.gl_pathc; ++i)	{	  int oldcount;#ifdef	SHELL	  {	    /* Make globbing interruptible in the bash shell. */	    extern int interrupt_state;	    if (interrupt_state)	      {		globfree (&dirs);		globfree (&files);		return GLOB_ABEND;	      }	  }#endif /* SHELL.  */	  oldcount = pglob->gl_pathc;	  status = glob_in_dir (filename, dirs.gl_pathv[i],				(flags | GLOB_APPEND) & ~GLOB_NOCHECK,				errfunc, pglob);	  if (status == GLOB_NOMATCH)	    /* No matches in this directory.  Try the next.  */	    continue;	  if (status != 0)	    {	      globfree (&dirs);	      globfree (pglob);	      return status;	    }	  /* Stick the directory on the front of each name.  */	  if (prefix_array (dirs.gl_pathv[i],			    &pglob->gl_pathv[oldcount],			    pglob->gl_pathc - oldcount,			    flags & GLOB_MARK))	    {	      globfree (&dirs);	      globfree (pglob);	      return GLOB_NOSPACE;	    }	}      flags |= GLOB_MAGCHAR;      if (pglob->gl_pathc == oldcount)      {	/* No matches.  */	if (flags & GLOB_NOCHECK)	{	    size_t len = strlen (pattern) + 1;	    char *patcopy = (char *) malloc (len);	    if (patcopy == NULL)	      return GLOB_NOSPACE;	    memcpy (patcopy, pattern, len);	    pglob->gl_pathv	      = (char **) realloc (pglob->gl_pathv,				   (pglob->gl_pathc +				    ((flags & GLOB_DOOFFS) ?				     pglob->gl_offs : 0) +				    1 + 1) *				   sizeof (char *));	    if (pglob->gl_pathv == NULL)	      {		free (patcopy);		return GLOB_NOSPACE;	      }	    if (flags & GLOB_DOOFFS)	      while (pglob->gl_pathc < pglob->gl_offs)		pglob->gl_pathv[pglob->gl_pathc++] = NULL;	    pglob->gl_pathv[pglob->gl_pathc++] = patcopy;	    pglob->gl_pathv[pglob->gl_pathc] = NULL;	    pglob->gl_flags = flags;	}	else 	{	  return GLOB_NOMATCH;	}      }    }  else    {      status = glob_in_dir (filename, dirname, flags, errfunc, pglob);      if (status != 0)	return status;      if (dirlen > 0)	{	  /* Stick the directory on the front of each name.  */	  if (prefix_array (dirname,			    &pglob->gl_pathv[oldcount],			    pglob->gl_pathc - oldcount,			    flags & GLOB_MARK))	    {	      globfree (pglob);	      return GLOB_NOSPACE;	    }	}    }  if (flags & GLOB_MARK)    {      /* Append slashes to directory names.  glob_in_dir has already	 allocated the extra character for us.  */      int i;      struct stat st;      for (i = oldcount; i < pglob->gl_pathc; ++i)	if (lstat (pglob->gl_pathv[i], &st) == 0 &&	    S_ISDIR (st.st_mode))	  strcat (pglob->gl_pathv[i], "/");    }  if (!(flags & GLOB_NOSORT))    /* Sort the vector.  */    qsort ((__ptr_t) &pglob->gl_pathv[oldcount],	   pglob->gl_pathc - oldcount,	   sizeof (char *), (__compar_fn_t)collated_compare);  return 0;}/* Free storage allocated in PGLOB by a previous `glob' call.  */voidglobfree (pglob)     register glob_t *pglob;{  if (pglob->gl_pathv != NULL)    {      register int i;      for (i = 0; i < pglob->gl_pathc; ++i)	if (pglob->gl_pathv[i] != NULL)	  free ((__ptr_t) pglob->gl_pathv[i]);      free ((__ptr_t) pglob->gl_pathv);    }}/* Do a collated comparison of A and B.  */static intcollated_compare (a, b)     const __ptr_t a;     const __ptr_t b;{  const char *const s1 = *(const char *const *) a;  const char *const s2 = *(const char *const *) b;  if (s1 == s2)    return 0;  if (s1 == NULL)    return 1;  if (s2 == NULL)    return -1;  return strcoll (s1, s2);}/* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's   elements in place.  Return nonzero if out of memory, zero if successful.   A slash is inserted between DIRNAME and each elt of ARRAY,   unless DIRNAME is just "/".  Each old element of ARRAY is freed.   If ADD_SLASH is non-zero, allocate one character more than   necessary, so that a slash can be appended later.  */static intprefix_array (dirname, array, n, add_slash)     const char *dirname;     char **array;     size_t n;     int add_slash;{  register size_t i;  size_t dirlen = strlen (dirname);  if (dirlen == 1 && dirname[0] == '/')    /* DIRNAME is just "/", so normal prepending would get us "//foo".       We want "/foo" instead, so don't prepend any chars from DIRNAME.  */    dirlen = 0;  for (i = 0; i < n; ++i)    {      size_t eltlen = strlen (array[i]) + 1;      char *new = (char *) malloc (dirlen + 1 + eltlen + (add_slash ? 1 : 0));      if (new == NULL)	{	  while (i > 0)	    free ((__ptr_t) array[--i]);	  return 1;	}      memcpy (new, dirname, dirlen);      new[dirlen] = '/';      memcpy (&new[dirlen + 1], array[i], eltlen);      free ((__ptr_t) array[i]);      array[i] = new;    }  return 0;}/* Return nonzero if PATTERN contains any metacharacters.   Metacharacters can be quoted with backslashes if QUOTE is nonzero.  */static intglob_pattern_p (pattern, quote)     const char *pattern;     int quote;{  register const char *p;  int open = 0;  for (p = pattern; *p != '\0'; ++p)    switch (*p)      {      case '?':      case '*':	return 1;      case '\\':	if (quote)	  ++p;	break;      case '[':	open = 1;	break;      case ']':	if (open)	  return 1;	break;      }  return 0;}/* Like `glob', but PATTERN is a final pathname component,   and matches are searched for in DIRECTORY.   The GLOB_NOSORT bit in FLAGS is ignored.  No sorting is ever done.   The GLOB_APPEND flag is assumed to be set (always appends).  */static intglob_in_dir (pattern, directory, flags, errfunc, pglob)     const char *pattern;     const char *directory;     int flags;     int (*errfunc) __P ((const char *, int));     glob_t *pglob;{  __ptr_t stream;  struct globlink    {      struct globlink *next;      char *name;    };  struct globlink *names = NULL;  size_t nfound = 0;  int meta;  stream = (__glob_opendir_hook ? (*__glob_opendir_hook) (directory)	   : (__ptr_t) opendir (directory));  if (stream == NULL)    {      if ((errfunc != NULL && (*errfunc) (directory, errno)) ||	  (flags & GLOB_ERR))	return GLOB_ABORTED;    }  meta = glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE));  if (meta)    flags |= GLOB_MAGCHAR;  while (1)    {      const char *name;      size_t len;      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 (! (d->d_ino != 0))	    continue;	  name = d->d_name;#ifdef	HAVE_D_NAMLEN	  len = d->d_namlen;#else	  len = 0;#endif	}		      if ((!meta && strcmp (pattern, name) == 0)	  || fnmatch (pattern, name,		      (!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) |		      ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)) == 0)	{	  struct globlink *new	    = (struct globlink *) alloca (sizeof (struct globlink));	  if (len == 0)	    len = strlen (name);	  new->name	    = (char *) malloc (len + ((flags & GLOB_MARK) ? 1 : 0) + 1);	  if (new->name == NULL)	    goto memory_error;	  memcpy ((__ptr_t) new->name, name, len);	  new->name[len] = '\0';	  new->next = names;	  names = new;	  ++nfound;	  if (!meta)	    break;	}    }  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);      if (names->name == NULL)	goto memory_error;      memcpy (names->name, pattern, len);      names->name[len] = '\0';    }  pglob->gl_pathv    = (char **) realloc (pglob->gl_pathv,			 (pglob->gl_pathc +			  ((flags & GLOB_DOOFFS) ? pglob->gl_offs : 0) +			  nfound + 1) *			 sizeof (char *));  if (pglob->gl_pathv == NULL)    goto memory_error;  if (flags & GLOB_DOOFFS)    while (pglob->gl_pathc < pglob->gl_offs)      pglob->gl_pathv[pglob->gl_pathc++] = NULL;  for (; names != NULL; names = names->next)    pglob->gl_pathv[pglob->gl_pathc++] = names->name;  pglob->gl_pathv[pglob->gl_pathc] = NULL;  pglob->gl_flags = flags;  {    int save = errno;    if (__glob_closedir_hook)      (*__glob_closedir_hook) (stream);    else      (void) closedir ((DIR *) stream);    errno = save;  }  return nfound == 0 ? GLOB_NOMATCH : 0; memory_error:  {    int save = errno;    if (__glob_closedir_hook)      (*__glob_closedir_hook) (stream);    else      (void) closedir ((DIR *) stream);    errno = save;  }  while (names != NULL)    {      if (names->name != NULL)	free ((__ptr_t) names->name);      names = names->next;    }  return GLOB_NOSPACE;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -