Update to glibc-2.1 version with GNU extensions.
authorjbj <devnull@localhost>
Fri, 10 Mar 2000 17:49:09 +0000 (17:49 +0000)
committerjbj <devnull@localhost>
Fri, 10 Mar 2000 17:49:09 +0000 (17:49 +0000)
CVS patchset: 3615
CVS date: 2000/03/10 17:49:09

misc/glob.c
misc/glob.h

index 8cfd337..42ba460 100644 (file)
@@ -1,26 +1,44 @@
-/* Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+/* Copyright (C) 1991,92,93,94,95,96,97,98,99 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
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   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.
+   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., 675 Mass Ave,
-Cambridge, MA 02139, USA.  */
+   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.  */
 
 /* AIX requires this to be the first thing in the file.  */
-#if defined (_AIX) && !defined (__GNUC__)
+#if defined _AIX && !defined __GNUC__
  #pragma alloca
 #endif
 
-#include "system.h"
+#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>
+
+/* Outcomment the following line for production quality code.  */
+/* #define NDEBUG 1 */
+#include <assert.h>
+
+#include <stdio.h>             /* Needed on stupid SunOS for assert.  */
+
 
 /* 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
@@ -30,81 +48,155 @@ 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__)
-
-#ifdef STDC_HEADERS
-#include <stddef.h>
+#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
 
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#ifndef POSIX
-#ifdef _POSIX_VERSION
-#define        POSIX
+#ifndef ELIDE_CODE
+
+#if defined STDC_HEADERS || defined __GNU_LIBRARY__
+# include <stddef.h>
 #endif
+
+#if defined HAVE_UNISTD_H || defined _LIBC
+# include <unistd.h>
+# ifndef POSIX
+#  ifdef _POSIX_VERSION
+#   define POSIX
+#  endif
+# endif
 #endif
+
+#if !defined _AMIGA && !defined VMS && !defined WINDOWS32
+# include <pwd.h>
 #endif
 
-#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
+#if !defined __GNU_LIBRARY__ && !defined STDC_HEADERS
 extern int errno;
 #endif
+#ifndef __set_errno
+# define __set_errno(val) errno = (val)
+#endif
 
 #ifndef        NULL
-#define        NULL    0
+# 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 (__GNU_LIBRARY__)
+/* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available
+   if the `d_type' member for `struct dirent' is available.  */
+#ifdef _DIRENT_HAVE_D_TYPE
+# define HAVE_D_TYPE   1
+#endif
+
+
+#if (defined POSIX || defined WINDOWS32) && !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
+# define REAL_DIR_ENTRY(dp) 1
 #else
-#define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
+# 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
+#if defined STDC_HEADERS || defined __GNU_LIBRARY__
+# include <stdlib.h>
+# include <string.h>
+# define       ANSI_STRING
 #else  /* No standard headers.  */
 
-#ifdef HAVE_STRING_H
-#define        ANSI_STRING
-#endif
-#ifdef HAVE_MEMORY_H
-#include <memory.h>
-#endif
+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>
+# endif
+
+extern char *malloc (), *realloc ();
+extern void free ();
 
 extern void qsort ();
 extern void abort (), exit ();
 
 #endif /* Standard headers.  */
 
+#ifdef HAVE_GETLOGIN_R
+extern int getlogin_r __P ((char *, size_t));
+#else
+extern char *getlogin __P ((void));
+#endif
+
 #ifndef        ANSI_STRING
 
-#ifndef        bzero
+# ifndef bzero
 extern void bzero ();
-#endif
-#ifndef        bcopy
+# endif
+# ifndef bcopy
 extern void bcopy ();
-#endif
+# endif
 
-#define        memcpy(d, s, n) bcopy ((s), (d), (n))
-#define        strrchr rindex
+# 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) \
+# 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
+#if !defined HAVE_STRCOLL && !defined _LIBC
+# define strcoll       strcmp
 #endif
 
+#if !defined HAVE_MEMPCPY && __GLIBC__ - 0 == 2 && __GLIBC_MINOR__ >= 1
+# define HAVE_MEMPCPY  1
+# undef  mempcpy
+# define mempcpy(Dest, Src, Len) __mempcpy (Dest, Src, Len)
+#endif
 
 #ifndef        __GNU_LIBRARY__
-#ifdef __GNUC__
+# ifdef        __GNUC__
 __inline
-#endif
+# endif
+# ifndef __SASC
+#  ifdef WINDOWS32
+static void *
+#  else
 static char *
+# endif
 my_realloc (p, n)
      char *p;
      unsigned int n;
@@ -115,69 +207,150 @@ my_realloc (p, n)
     return (char *) malloc (n);
   return (char *) realloc (p, n);
 }
-#define        realloc my_realloc
-#endif
-
+# 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 WINDOWS32
+#     include <malloc.h>
+#    else
+extern char *alloca ();
+#    endif /* WINDOWS32 */
+#   endif /* Not _AIX.  */
+#  endif /* sparc or HAVE_ALLOCA_H.  */
+# endif        /* GCC.  */
 
-#if    !defined(__alloca) && !defined(__GNU_LIBRARY__)
+# define __alloca      alloca
 
-#ifdef __GNUC__
-#undef alloca
-#define        alloca(n)       __builtin_alloca (n)
-#else  /* Not GCC.  */
-#if    defined (sparc) || defined (HAVE_ALLOCA_H)
-#include <alloca.h>
-#else  /* Not sparc or HAVE_ALLOCA_H.  */
-#ifndef        _AIX
-extern char *alloca ();
-#endif /* Not _AIX.  */
-#endif /* sparc or HAVE_ALLOCA_H.  */
-#endif /* GCC.  */
+#endif
 
-#define        __alloca        alloca
+#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
 
+#ifdef _LIBC
+# undef strdup
+# define strdup(str) __strdup (str)
+# define sysconf(id) __sysconf (id)
+# define closedir(dir) __closedir (dir)
+# define opendir(name) __opendir (name)
+# define readdir(str) __readdir (str)
+# define getpwnam_r(name, bufp, buf, len, res) \
+   __getpwnam_r (name, bufp, buf, len, res)
+# ifndef __stat
+#  define __stat(fname, buf) __xstat (_STAT_VER, fname, buf)
+# endif
 #endif
 
-#ifndef        STDC_HEADERS
-#undef size_t
-#define        size_t  unsigned int
+#if !(defined STDC_HEADERS || defined __GNU_LIBRARY__)
+# 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
+#ifndef __GNU_LIBRARY__
+# undef        FNM_PATHNAME
+# undef        FNM_NOESCAPE
+# undef        FNM_PERIOD
+#endif
+#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
-
-__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));
+#ifndef __GNU_LIBRARY__
+# undef        GLOB_ERR
+# undef        GLOB_MARK
+# undef        GLOB_NOSORT
+# undef        GLOB_DOOFFS
+# undef        GLOB_NOCHECK
+# undef        GLOB_APPEND
+# undef        GLOB_NOESCAPE
+# undef        GLOB_PERIOD
+#endif
+#include <glob.h>
+\f
+static
+#if __GNUC__ - 0 >= 2
+inline
+#endif
+const char *next_brace_sub __P ((const char *begin));
 static int glob_in_dir __P ((const char *pattern, const char *directory,
                             int flags,
-                            int (*errfunc) __P ((const char *, int)),
+                            int (*errfunc) (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));
 
+
+/* Find the end of the sub-pattern in a brace expression.  We define
+   this as an inline function if the compiler permits.  */
+static
+#if __GNUC__ - 0 >= 2
+inline
+#endif
+const char *
+next_brace_sub (begin)
+     const char *begin;
+{
+  unsigned int depth = 0;
+  const char *cp = begin;
+
+  while (1)
+    {
+      if (depth == 0)
+       {
+         if (*cp != ',' && *cp != '}' && *cp != '\0')
+           {
+             if (*cp == '{')
+               ++depth;
+             ++cp;
+             continue;
+           }
+       }
+      else
+       {
+         while (*cp != '\0' && (*cp != '}' || depth > 0))
+           {
+             if (*cp == '}')
+               --depth;
+             ++cp;
+           }
+         if (*cp == '\0')
+           /* An incorrectly terminated brace expression.  */
+           return NULL;
+
+         continue;
+       }
+      break;
+    }
+
+  return cp;
+}
+
 /* 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.
+   `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
    If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
    Otherwise, `glob' returns zero.  */
 int
@@ -188,48 +361,238 @@ glob (pattern, flags, errfunc, pglob)
      glob_t *pglob;
 {
   const char *filename;
-  char *dirname;
+  const char *dirname;
   size_t dirlen;
   int status;
   int oldcount;
 
   if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
     {
-      errno = EINVAL;
+      __set_errno (EINVAL);
       return -1;
     }
 
+  if (flags & GLOB_BRACE)
+    {
+      const char *begin = strchr (pattern, '{');
+      if (begin != NULL)
+       {
+         /* Allocate working buffer large enough for our work.  Note that
+           we have at least an opening and closing brace.  */
+         int firstc;
+         char *alt_start;
+         const char *p;
+         const char *next;
+         const char *rest;
+         size_t rest_len;
+#ifdef __GNUC__
+         char onealt[strlen (pattern) - 1];
+#else
+         char *onealt = (char *) malloc (strlen (pattern) - 1);
+         if (onealt == NULL)
+           {
+             if (!(flags & GLOB_APPEND))
+               globfree (pglob);
+             return GLOB_NOSPACE;
+           }
+#endif
+
+         /* We know the prefix for all sub-patterns.  */
+#ifdef HAVE_MEMPCPY
+         alt_start = mempcpy (onealt, pattern, begin - pattern);
+#else
+         memcpy (onealt, pattern, begin - pattern);
+         alt_start = &onealt[begin - pattern];
+#endif
+
+         /* Find the first sub-pattern and at the same time find the
+            rest after the closing brace.  */
+         next = next_brace_sub (begin + 1);
+         if (next == NULL)
+           {
+             /* It is an illegal expression.  */
+#ifndef __GNUC__
+             free (onealt);
+#endif
+             return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
+           }
+
+         /* Now find the end of the whole brace expression.  */
+         rest = next;
+         while (*rest != '}')
+           {
+             rest = next_brace_sub (rest + 1);
+             if (rest == NULL)
+               {
+                 /* It is an illegal expression.  */
+#ifndef __GNUC__
+                 free (onealt);
+#endif
+                 return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
+               }
+           }
+         /* Please note that we now can be sure the brace expression
+            is well-formed.  */
+         rest_len = strlen (++rest) + 1;
+
+         /* 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;
+
+         p = begin + 1;
+         while (1)
+           {
+             int result;
+
+             /* Construct the new glob expression.  */
+#ifdef HAVE_MEMPCPY
+             mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
+#else
+             memcpy (alt_start, p, next - p);
+             memcpy (&alt_start[next - p], rest, rest_len);
+#endif
+
+             result = glob (onealt,
+                            ((flags & ~(GLOB_NOCHECK|GLOB_NOMAGIC))
+                             | GLOB_APPEND), errfunc, pglob);
+
+             /* If we got an error, return it.  */
+             if (result && result != GLOB_NOMATCH)
+               {
+#ifndef __GNUC__
+                 free (onealt);
+#endif
+                 if (!(flags & GLOB_APPEND))
+                   globfree (pglob);
+                 return result;
+               }
+
+             if (*next == '}')
+               /* We saw the last entry.  */
+               break;
+
+             p = next + 1;
+             next = next_brace_sub (p);
+             assert (next != NULL);
+           }
+
+#ifndef __GNUC__
+         free (onealt);
+#endif
+
+         if (pglob->gl_pathc != firstc)
+           /* We found some entries.  */
+           return 0;
+         else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
+           return GLOB_NOMATCH;
+       }
+    }
+
   /* Find the filename.  */
   filename = strrchr (pattern, '/');
+#if defined __MSDOS__ || defined WINDOWS32
+  /* The case of "d:pattern".  Since `:' is not allowed in
+     file names, we can safely assume that wherever it
+     happens in pattern, it signals the filename part.  This
+     is so we could some day support patterns like "[a-z]:foo".  */
+  if (filename == NULL)
+    filename = strchr (pattern, ':');
+#endif /* __MSDOS__ || WINDOWS32 */
   if (filename == NULL)
     {
-      filename = pattern;
-      dirname = (char *) ".";
-      dirlen = 0;
+      /* This can mean two things: a simple name or "~name".  The latter
+        case is nothing but a notation for a directory.  */
+      if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~')
+       {
+         dirname = pattern;
+         dirlen = strlen (pattern);
+
+         /* Set FILENAME to NULL as a special flag.  This is ugly but
+            other solutions would require much more code.  We test for
+            this special case below.  */
+         filename = NULL;
+       }
+      else
+       {
+         filename = pattern;
+#ifdef _AMIGA
+         dirname = "";
+#else
+         dirname = ".";
+#endif
+         dirlen = 0;
+       }
     }
   else if (filename == pattern)
     {
       /* "/pattern".  */
-      dirname = (char *) "/";
+      dirname = "/";
       dirlen = 1;
       ++filename;
     }
   else
     {
+      char *newp;
       dirlen = filename - pattern;
-      dirname = (char *) __alloca (dirlen + 1);
-      memcpy (dirname, pattern, dirlen);
-      dirname[dirlen] = '\0';
+#if defined __MSDOS__ || defined WINDOWS32
+      if (*filename == ':'
+         || (filename > pattern + 1 && filename[-1] == ':'))
+       {
+         char *drive_spec;
+
+         ++dirlen;
+         drive_spec = (char *) __alloca (dirlen + 1);
+#ifdef HAVE_MEMPCPY
+         *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
+#else
+         memcpy (drive_spec, pattern, dirlen);
+         drive_spec[dirlen] = '\0';
+#endif
+         /* For now, disallow wildcards in the drive spec, to
+            prevent infinite recursion in glob.  */
+         if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
+           return GLOB_NOMATCH;
+         /* If this is "d:pattern", we need to copy `:' to DIRNAME
+            as well.  If it's "d:/pattern", don't remove the slash
+            from "d:/", since "d:" and "d:/" are not the same.*/
+       }
+#endif
+      newp = (char *) __alloca (dirlen + 1);
+#ifdef HAVE_MEMPCPY
+      *((char *) mempcpy (newp, pattern, dirlen)) = '\0';
+#else
+      memcpy (newp, pattern, dirlen);
+      newp[dirlen] = '\0';
+#endif
+      dirname = newp;
       ++filename;
-    }
 
-  if (filename[0] == '\0' && dirlen > 1)
-    /* "pattern/".  Expand "pattern", appending slashes.  */
-    {
-      int ret = glob (dirname, flags | GLOB_MARK, errfunc, pglob);
-      if (ret == 0)
-       pglob->gl_flags = (pglob->gl_flags & ~GLOB_MARK) | (flags & GLOB_MARK);
-      return ret;
+      if (filename[0] == '\0'
+#if defined __MSDOS__ || defined WINDOWS32
+          && dirname[dirlen - 1] != ':'
+         && (dirlen < 3 || dirname[dirlen - 2] != ':'
+             || dirname[dirlen - 1] != '/')
+#endif
+         && 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))
@@ -240,7 +603,237 @@ glob (pattern, flags, errfunc, pglob)
 
   oldcount = pglob->gl_pathc;
 
-  if (glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE)))
+#ifndef VMS
+  if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
+    {
+      if (dirname[1] == '\0' || dirname[1] == '/')
+       {
+         /* Look up home directory.  */
+         const char *home_dir = getenv ("HOME");
+# ifdef _AMIGA
+         if (home_dir == NULL || home_dir[0] == '\0')
+           home_dir = "SYS:";
+# else
+#  ifdef WINDOWS32
+         if (home_dir == NULL || home_dir[0] == '\0')
+            home_dir = "c:/users/default"; /* poor default */
+#  else
+         if (home_dir == NULL || home_dir[0] == '\0')
+           {
+             int success;
+             char *name;
+#   if defined HAVE_GETLOGIN_R || defined _LIBC
+             size_t buflen = sysconf (_SC_LOGIN_NAME_MAX) + 1;
+
+             if (buflen == 0)
+               /* `sysconf' does not support _SC_LOGIN_NAME_MAX.  Try
+                  a moderate value.  */
+               buflen = 20;
+             name = (char *) __alloca (buflen);
+
+             success = getlogin_r (name, buflen) >= 0;
+#   else
+             success = (name = getlogin ()) != NULL;
+#   endif
+             if (success)
+               {
+                 struct passwd *p;
+#   if defined HAVE_GETPWNAM_R || defined _LIBC
+                 size_t pwbuflen = sysconf (_SC_GETPW_R_SIZE_MAX);
+                 char *pwtmpbuf;
+                 struct passwd pwbuf;
+                 int save = errno;
+
+                 if (pwbuflen == -1)
+                   /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
+                      Try a moderate value.  */
+                   pwbuflen = 1024;
+                 pwtmpbuf = (char *) __alloca (pwbuflen);
+
+                 while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
+                        != 0)
+                   {
+                     if (errno != ERANGE)
+                       {
+                         p = NULL;
+                         break;
+                       }
+                     pwbuflen *= 2;
+                     pwtmpbuf = (char *) __alloca (pwbuflen);
+                     __set_errno (save);
+                   }
+#   else
+                 p = getpwnam (name);
+#   endif
+                 if (p != NULL)
+                   home_dir = p->pw_dir;
+               }
+           }
+         if (home_dir == NULL || home_dir[0] == '\0')
+           {
+             if (flags & GLOB_TILDE_CHECK)
+               return GLOB_NOMATCH;
+             else
+               home_dir = "~"; /* No luck.  */
+           }
+#  endif /* WINDOWS32 */
+# endif
+         /* Now construct the full directory.  */
+         if (dirname[1] == '\0')
+           dirname = home_dir;
+         else
+           {
+             char *newp;
+             size_t home_len = strlen (home_dir);
+             newp = (char *) __alloca (home_len + dirlen);
+# ifdef HAVE_MEMPCPY
+             mempcpy (mempcpy (newp, home_dir, home_len),
+                      &dirname[1], dirlen);
+# else
+             memcpy (newp, home_dir, home_len);
+             memcpy (&newp[home_len], &dirname[1], dirlen);
+# endif
+             dirname = newp;
+           }
+       }
+# if !defined _AMIGA && !defined WINDOWS32
+      else
+       {
+         char *end_name = strchr (dirname, '/');
+         const char *user_name;
+         const char *home_dir;
+
+         if (end_name == NULL)
+           user_name = dirname + 1;
+         else
+           {
+             char *newp;
+             newp = (char *) __alloca (end_name - dirname);
+# ifdef HAVE_MEMPCPY
+             *((char *) mempcpy (newp, dirname + 1, end_name - dirname))
+               = '\0';
+# else
+             memcpy (newp, dirname + 1, end_name - dirname);
+             newp[end_name - dirname - 1] = '\0';
+# endif
+             user_name = newp;
+           }
+
+         /* Look up specific user's home directory.  */
+         {
+           struct passwd *p;
+#  if defined HAVE_GETPWNAM_R || defined _LIBC
+           size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
+           char *pwtmpbuf;
+           struct passwd pwbuf;
+           int save = errno;
+
+           if (buflen == -1)
+             /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.  Try a
+                moderate value.  */
+             buflen = 1024;
+           pwtmpbuf = (char *) __alloca (buflen);
+
+           while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
+             {
+               if (errno != ERANGE)
+                 {
+                   p = NULL;
+                   break;
+                 }
+               buflen *= 2;
+               pwtmpbuf = __alloca (buflen);
+               __set_errno (save);
+             }
+#  else
+           p = getpwnam (user_name);
+#  endif
+           if (p != NULL)
+             home_dir = p->pw_dir;
+           else
+             home_dir = NULL;
+         }
+         /* If we found a home directory use this.  */
+         if (home_dir != NULL)
+           {
+             char *newp;
+             size_t home_len = strlen (home_dir);
+             size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
+             newp = (char *) __alloca (home_len + rest_len + 1);
+#  ifdef HAVE_MEMPCPY
+             *((char *) mempcpy (mempcpy (newp, home_dir, home_len),
+                                 end_name, rest_len)) = '\0';
+#  else
+             memcpy (newp, home_dir, home_len);
+             memcpy (&newp[home_len], end_name, rest_len);
+             newp[home_len + rest_len] = '\0';
+#  endif
+             dirname = newp;
+           }
+         else
+           if (flags & GLOB_TILDE_CHECK)
+             /* We have to regard it as an error if we cannot find the
+                home directory.  */
+             return GLOB_NOMATCH;
+       }
+# endif        /* Not Amiga && not WINDOWS32.  */
+    }
+#endif /* Not VMS.  */
+
+  /* Now test whether we looked for "~" or "~NAME".  In this case we
+     can give the answer now.  */
+  if (filename == NULL)
+    {
+      struct stat st;
+
+      /* Return the directory if we don't check for error or if it exists.  */
+      if ((flags & GLOB_NOCHECK)
+         || (((flags & GLOB_ALTDIRFUNC)
+              ? (*pglob->gl_stat) (dirname, &st)
+              : __stat (dirname, &st)) == 0
+             && S_ISDIR (st.st_mode)))
+       {
+         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)
+           return GLOB_NOSPACE;
+
+         if (flags & GLOB_DOOFFS)
+           while (pglob->gl_pathc < pglob->gl_offs)
+             pglob->gl_pathv[pglob->gl_pathc++] = NULL;
+
+#if defined HAVE_STRDUP || defined _LIBC
+         pglob->gl_pathv[pglob->gl_pathc] = strdup (dirname);
+#else
+         {
+           size_t len = strlen (dirname) + 1;
+           char *dircopy = malloc (len);
+           if (dircopy != NULL)
+             pglob->gl_pathv[pglob->gl_pathc] = memcpy (dircopy, dirname,
+                                                        len);
+         }
+#endif
+         if (pglob->gl_pathv[pglob->gl_pathc] == NULL)
+           {
+             free (pglob->gl_pathv);
+             return GLOB_NOSPACE;
+           }
+         pglob->gl_pathv[++pglob->gl_pathc] = NULL;
+         pglob->gl_flags = flags;
+
+         return 0;
+       }
+
+      /* Not found.  */
+      return GLOB_NOMATCH;
+    }
+
+  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
@@ -248,9 +841,21 @@ glob (pattern, flags, errfunc, pglob)
       glob_t dirs;
       register int i;
 
+      if ((flags & GLOB_ALTDIRFUNC) != 0)
+       {
+         /* Use the alternative access functions also in the recursive
+            call.  */
+         dirs.gl_opendir = pglob->gl_opendir;
+         dirs.gl_readdir = pglob->gl_readdir;
+         dirs.gl_closedir = pglob->gl_closedir;
+         dirs.gl_stat = pglob->gl_stat;
+         dirs.gl_lstat = pglob->gl_lstat;
+       }
+
       status = glob (dirname,
-                    ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE)) |
-                     GLOB_NOSORT),
+                    ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE
+                               | GLOB_ALTDIRFUNC))
+                     | GLOB_NOSORT | GLOB_ONLYDIR),
                     errfunc, &dirs);
       if (status != 0)
        return status;
@@ -260,7 +865,7 @@ glob (pattern, flags, errfunc, pglob)
         appending the results to PGLOB.  */
       for (i = 0; i < dirs.gl_pathc; ++i)
        {
-         int oldcount;
+         int old_pathc;
 
 #ifdef SHELL
          {
@@ -271,14 +876,15 @@ glob (pattern, flags, errfunc, pglob)
              {
                globfree (&dirs);
                globfree (&files);
-               return GLOB_ABEND;
+               return GLOB_ABORTED;
              }
          }
 #endif /* SHELL.  */
 
-         oldcount = pglob->gl_pathc;
+         old_pathc = pglob->gl_pathc;
          status = glob_in_dir (filename, dirs.gl_pathv[i],
-                               (flags | GLOB_APPEND) & ~GLOB_NOCHECK,
+                               ((flags | GLOB_APPEND)
+                                & ~(GLOB_NOCHECK | GLOB_ERR)),
                                errfunc, pglob);
          if (status == GLOB_NOMATCH)
            /* No matches in this directory.  Try the next.  */
@@ -293,8 +899,8 @@ glob (pattern, flags, errfunc, pglob)
 
          /* Stick the directory on the front of each name.  */
          if (prefix_array (dirs.gl_pathv[i],
-                           &pglob->gl_pathv[oldcount],
-                           pglob->gl_pathc - oldcount))
+                           &pglob->gl_pathv[old_pathc],
+                           pglob->gl_pathc - old_pathc))
            {
              globfree (&dirs);
              globfree (pglob);
@@ -304,39 +910,87 @@ glob (pattern, flags, errfunc, pglob)
 
       flags |= GLOB_MAGCHAR;
 
+      /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls.
+        But if we have not found any matching entry and thie GLOB_NOCHECK
+        flag was set we must return the list consisting of the disrectory
+        names followed by the filename.  */
       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;
+       {
+         /* No matches.  */
+         if (flags & GLOB_NOCHECK)
+           {
+             size_t filename_len = strlen (filename) + 1;
+             char **new_pathv;
+             struct stat st;
+
+             /* This is an pessimistic guess about the size.  */
+             pglob->gl_pathv
+               = (char **) realloc (pglob->gl_pathv,
+                                    (pglob->gl_pathc +
+                                     ((flags & GLOB_DOOFFS) ?
+                                      pglob->gl_offs : 0) +
+                                     dirs.gl_pathc + 1) *
+                                    sizeof (char *));
+             if (pglob->gl_pathv == NULL)
+               {
+                 globfree (&dirs);
+                 return GLOB_NOSPACE;
+               }
+
+             if (flags & GLOB_DOOFFS)
+               while (pglob->gl_pathc < pglob->gl_offs)
+                 pglob->gl_pathv[pglob->gl_pathc++] = NULL;
+
+             for (i = 0; i < dirs.gl_pathc; ++i)
+               {
+                 const char *dir = dirs.gl_pathv[i];
+                 size_t dir_len = strlen (dir);
+
+                 /* First check whether this really is a directory.  */
+                 if (((flags & GLOB_ALTDIRFUNC)
+                      ? (*pglob->gl_stat) (dir, &st) : __stat (dir, &st)) != 0
+                     || !S_ISDIR (st.st_mode))
+                   /* No directory, ignore this entry.  */
+                   continue;
+
+                 pglob->gl_pathv[pglob->gl_pathc] = malloc (dir_len + 1
+                                                            + filename_len);
+                 if (pglob->gl_pathv[pglob->gl_pathc] == NULL)
+                   {
+                     globfree (&dirs);
+                     globfree (pglob);
+                     return GLOB_NOSPACE;
+                   }
+
+#ifdef HAVE_MEMPCPY
+                 mempcpy (mempcpy (mempcpy (pglob->gl_pathv[pglob->gl_pathc],
+                                            dir, dir_len),
+                                   "/", 1),
+                          filename, filename_len);
+#else
+                 memcpy (pglob->gl_pathv[pglob->gl_pathc], dir, dir_len);
+                 pglob->gl_pathv[pglob->gl_pathc][dir_len] = '/';
+                 memcpy (&pglob->gl_pathv[pglob->gl_pathc][dir_len + 1],
+                         filename, filename_len);
+#endif
+                 ++pglob->gl_pathc;
+               }
+
+             pglob->gl_pathv[pglob->gl_pathc] = NULL;
+             pglob->gl_flags = flags;
+
+             /* Now we know how large the gl_pathv vector must be.  */
+             new_pathv = (char **) realloc (pglob->gl_pathv,
+                                            ((pglob->gl_pathc + 1)
+                                             * sizeof (char *)));
+             if (new_pathv != NULL)
+               pglob->gl_pathv = new_pathv;
+           }
+         else
+           return GLOB_NOMATCH;
+       }
 
-           pglob->gl_pathv[pglob->gl_pathc++] = patcopy;
-           pglob->gl_pathv[pglob->gl_pathc] = NULL;
-           pglob->gl_flags = flags;
-         }
-       else
-         return GLOB_NOMATCH;
+      globfree (&dirs);
     }
   else
     {
@@ -347,9 +1001,14 @@ glob (pattern, flags, errfunc, pglob)
       if (dirlen > 0)
        {
          /* Stick the directory on the front of each name.  */
+         int ignore = oldcount;
+
+         if ((flags & GLOB_DOOFFS) && ignore < pglob->gl_offs)
+           ignore = pglob->gl_offs;
+
          if (prefix_array (dirname,
-                           &pglob->gl_pathv[oldcount],
-                           pglob->gl_pathc - oldcount))
+                           &pglob->gl_pathv[ignore],
+                           pglob->gl_pathc - ignore))
            {
              globfree (pglob);
              return GLOB_NOSPACE;
@@ -357,11 +1016,41 @@ glob (pattern, flags, errfunc, pglob)
        }
     }
 
+  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],
-          pglob->gl_pathc - oldcount,
-          sizeof (char *), collated_compare);
+    {
+      /* Sort the vector.  */
+      int non_sort = oldcount;
+
+      if ((flags & GLOB_DOOFFS) && pglob->gl_offs > oldcount)
+       non_sort = pglob->gl_offs;
+
+      qsort ((__ptr_t) &pglob->gl_pathv[non_sort],
+            pglob->gl_pathc - non_sort,
+            sizeof (char *), collated_compare);
+    }
 
   return 0;
 }
@@ -410,15 +1099,35 @@ static int
 prefix_array (dirname, array, n)
      const char *dirname;
      char **array;
-     const size_t n;
+     size_t n;
 {
   register size_t i;
   size_t dirlen = strlen (dirname);
+#if defined __MSDOS__ || defined WINDOWS32
+  int sep_char = '/';
+# define DIRSEP_CHAR sep_char
+#else
+# define DIRSEP_CHAR '/'
+#endif
 
   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;
+#if defined __MSDOS__ || defined WINDOWS32
+  else if (dirlen > 1)
+    {
+      if (dirname[dirlen - 1] == '/')
+       /* DIRNAME is "d:/".  Don't prepend the slash from DIRNAME.  */
+       --dirlen;
+      else if (dirname[dirlen - 1] == ':')
+       {
+         /* DIRNAME is "d:".  Use `:' instead of `/'.  */
+         --dirlen;
+         sep_char = ':';
+       }
+    }
+#endif
 
   for (i = 0; i < n; ++i)
     {
@@ -431,9 +1140,17 @@ prefix_array (dirname, array, n)
          return 1;
        }
 
+#ifdef HAVE_MEMPCPY
+      {
+       char *endp = (char *) mempcpy (new, dirname, dirlen);
+       *endp++ = DIRSEP_CHAR;
+       mempcpy (endp, array[i], eltlen);
+      }
+#else
       memcpy (new, dirname, dirlen);
-      new[dirlen] = '/';
+      new[dirlen] = DIRSEP_CHAR;
       memcpy (&new[dirlen + 1], array[i], eltlen);
+#endif
       free ((__ptr_t) array[i]);
       array[i] = new;
     }
@@ -442,12 +1159,14 @@ prefix_array (dirname, array, n)
 }
 
 
+/* We must not compile this function twice.  */
+#if !defined _LIBC || !defined NO_GLOB_PATTERN_P
 /* Return nonzero if PATTERN contains any metacharacters.
    Metacharacters can be quoted with backslashes if QUOTE is nonzero.  */
-static int
-glob_pattern_p (pattern, quote)
+int
+__glob_pattern_p (pattern, quote)
      const char *pattern;
-     const int quote;
+     int quote;
 {
   register const char *p;
   int open = 0;
@@ -460,7 +1179,7 @@ glob_pattern_p (pattern, quote)
        return 1;
 
       case '\\':
-       if (quote)
+       if (quote && p[1] != '\0')
          ++p;
        break;
 
@@ -476,6 +1195,10 @@ glob_pattern_p (pattern, quote)
 
   return 0;
 }
+# ifdef _LIBC
+weak_alias (__glob_pattern_p, glob_pattern_p)
+# endif
+#endif
 
 
 /* Like `glob', but PATTERN is a final pathname component,
@@ -490,7 +1213,7 @@ glob_in_dir (pattern, directory, flags, errfunc, pglob)
      int (*errfunc) __P ((const char *, int));
      glob_t *pglob;
 {
-  __ptr_t stream;
+  __ptr_t stream = NULL;
 
   struct globlink
     {
@@ -498,70 +1221,130 @@ glob_in_dir (pattern, directory, flags, errfunc, pglob)
       char *name;
     };
   struct globlink *names = NULL;
-  size_t nfound = 0;
+  size_t nfound;
+  int meta;
+  int save;
 
-  if (!glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE)))
+  meta = __glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE));
+  if (meta == 0)
     {
-      stream = NULL;
-      flags |= GLOB_NOCHECK;
+      if (flags & (GLOB_NOCHECK|GLOB_NOMAGIC))
+       /* We need not do any tests.  The PATTERN contains no meta
+          characters and we must not return an error therefore the
+          result will always contain exactly one name.  */
+       flags |= GLOB_NOCHECK;
+      else
+       {
+         /* Since we use the normal file functions we can also use stat()
+            to verify the file is there.  */
+         struct stat st;
+         size_t patlen = strlen (pattern);
+         size_t dirlen = strlen (directory);
+         char *fullname = (char *) __alloca (dirlen + 1 + patlen + 1);
+
+# ifdef HAVE_MEMPCPY
+         mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
+                           "/", 1),
+                  pattern, patlen + 1);
+# else
+         memcpy (fullname, directory, dirlen);
+         fullname[dirlen] = '/';
+         memcpy (&fullname[dirlen + 1], pattern, patlen + 1);
+# endif
+         if (((flags & GLOB_ALTDIRFUNC)
+              ? (*pglob->gl_stat) (fullname, &st)
+              : __stat (fullname, &st)) == 0)
+           /* We found this file to be existing.  Now tell the rest
+              of the function to copy this name into the result.  */
+           flags |= GLOB_NOCHECK;
+       }
+
+      nfound = 0;
     }
   else
     {
-      flags |= GLOB_MAGCHAR;
-
-      stream = (__glob_opendir_hook ? (*__glob_opendir_hook) (directory)
-               : (__ptr_t) opendir (directory));
-      if (stream == NULL)
+      if (pattern[0] == '\0')
        {
-         if ((errfunc != NULL && (*errfunc) (directory, errno)) ||
-             (flags & GLOB_ERR))
-           return GLOB_ABEND;
+         /* This is a special case for matching directories like in
+            "*a/".  */
+         names = (struct globlink *) __alloca (sizeof (struct globlink));
+         names->name = (char *) malloc (1);
+         if (names->name == NULL)
+           goto memory_error;
+         names->name[0] = '\0';
+         names->next = NULL;
+         nfound = 1;
+         meta = 0;
        }
       else
-       while (1)
-         {
-           const char *name;
-           size_t len;
+       {
+         stream = ((flags & GLOB_ALTDIRFUNC)
+                   ? (*pglob->gl_opendir) (directory)
+                   : (__ptr_t) opendir (directory));
+         if (stream == NULL)
+           {
+             if (errno != ENOTDIR
+                 && ((errfunc != NULL && (*errfunc) (directory, errno))
+                     || (flags & GLOB_ERR)))
+               return GLOB_ABORTED;
+             nfound = 0;
+             meta = 0;
+           }
+         else
+           {
+             int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
+                              | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
+#if defined _AMIGA || defined VMS
+                                  | FNM_CASEFOLD
+#endif
+                                  );
+             nfound = 0;
+             flags |= GLOB_MAGCHAR;
+
+             while (1)
+               {
+                 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;
+
+#ifdef HAVE_D_TYPE
+                 /* If we shall match only directories use the information
+                    provided by the dirent call if possible.  */
+                 if ((flags & GLOB_ONLYDIR)
+                     && d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
+                   continue;
+#endif
 
-           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;
-               len = NLENGTH(d);
-             }
-               
-           if (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);
-               if (flags & GLOB_MARK)
-                 new->name[len++] = '/';
-               new->name[len] = '\0';
-               new->next = names;
-               names = new;
-               ++nfound;
-             }
-         }
+                 name = d->d_name;
+
+                 if (fnmatch (pattern, name, fnm_flags) == 0)
+                   {
+                     struct globlink *new = (struct globlink *)
+                       __alloca (sizeof (struct globlink));
+                     len = NAMLEN (d);
+                     new->name = (char *) malloc (len + 1);
+                     if (new->name == NULL)
+                       goto memory_error;
+#ifdef HAVE_MEMPCPY
+                     *((char *) mempcpy ((__ptr_t) new->name, name, len))
+                       = '\0';
+#else
+                     memcpy ((__ptr_t) new->name, name, len);
+                     new->name[len] = '\0';
+#endif
+                     new->next = names;
+                     names = new;
+                     ++nfound;
+                   }
+               }
+           }
+       }
     }
 
   if (nfound == 0 && (flags & GLOB_NOCHECK))
@@ -570,53 +1353,59 @@ glob_in_dir (pattern, directory, flags, errfunc, pglob)
       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;
+#ifdef HAVE_MEMPCPY
+      *((char *) mempcpy (names->name, pattern, len)) = '\0';
+#else
       memcpy (names->name, pattern, len);
-      if (flags & GLOB_MARK)
-       names->name[len++] = '/';
       names->name[len] = '\0';
+#endif
     }
 
-  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 (nfound != 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;
+      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;
+      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;
+      pglob->gl_flags = flags;
+    }
 
+  save = errno;
   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);
-      errno = save;
+       closedir ((DIR *) stream);
     }
+  __set_errno (save);
+
   return nfound == 0 ? GLOB_NOMATCH : 0;
 
  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);
-    errno = save;
+      closedir ((DIR *) stream);
+    __set_errno (save);
   }
   while (names != NULL)
     {
@@ -627,4 +1416,4 @@ glob_in_dir (pattern, directory, flags, errfunc, pglob)
   return GLOB_NOSPACE;
 }
 
-#endif /* _LIBC or not __GNU_LIBRARY__.  */
+#endif /* Not ELIDE_CODE.  */
index df074c5..c4ad24f 100644 (file)
@@ -1,42 +1,68 @@
-/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 92, 95, 96, 97, 98, 2000 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
-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        _GLOB_H
-
 #define        _GLOB_H 1
 
 #ifdef __cplusplus
-extern "C"
-{
+extern "C" {
 #endif
 
 #undef __ptr_t
-#if defined (__cplusplus) || defined (__STDC__)
-#undef __P
-#define        __P(protos)     protos
-#define        __ptr_t void *
+#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32
+# if !defined __GLIBC__ || !defined __P
+#  undef __P
+#  undef __PMT
+#  define __P(protos)  protos
+#  define __PMT(protos)        protos
+#  if !defined __GNUC__ || __GNUC__ < 2
+#   undef __const
+#   define __const const
+#  endif
+# endif
+# define __ptr_t       void *
 #else /* Not C++ or ANSI C.  */
-#undef __P
-#define        __P(protos)     ()
-#undef const
-#define        const
-#define        __ptr_t char *
+# undef        __P
+# undef __PMT
+# define __P(protos)   ()
+# define __PMT(protos) ()
+# undef        __const
+# define __const
+# define __ptr_t       char *
 #endif /* C++ or ANSI C.  */
 
+/* We need `size_t' for the following definitions.  */
+#ifndef __size_t
+# if defined __GNUC__ && __GNUC__ >= 2
+typedef __SIZE_TYPE__ __size_t;
+#  ifdef _XOPEN_SOURCE
+typedef __SIZE_TYPE__ size_t;
+#  endif
+# else
+/* This is a guess.  */
+typedef unsigned long int __size_t;
+# endif
+#else
+/* The GNU CC stddef.h version defines __size_t as empty.  We need a real
+   definition.  */
+# undef __size_t
+# define __size_t size_t
+#endif
+
 /* Bits set in the FLAGS argument to `glob'.  */
 #define        GLOB_ERR        (1 << 0)/* Return on read errors.  */
 #define        GLOB_MARK       (1 << 1)/* Append a slash to each name.  */
@@ -46,27 +72,77 @@ extern "C"
 #define        GLOB_APPEND     (1 << 5)/* Append to results of a previous call.  */
 #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)
 
-#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.  */
+#if (!defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _BSD_SOURCE \
+     || defined _GNU_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. */
+# define GLOB_ONLYDIR   (1 << 13)/* Match only directories.  */
+# define GLOB_TILDE_CHECK (1 << 14)/* Like GLOB_TILDE but return an error
+                                     if the user name is not available.  */
+# define __GLOB_FLAGS  (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
+                        GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND|     \
+                        GLOB_PERIOD|GLOB_ALTDIRFUNC|GLOB_BRACE|     \
+                        GLOB_NOMAGIC|GLOB_TILDE|GLOB_ONLYDIR|GLOB_TILDE_CHECK)
+#else
+# define __GLOB_FLAGS  (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
+                        GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND|     \
+                        GLOB_PERIOD)
 #endif
 
 /* Error returns from `glob'.  */
 #define        GLOB_NOSPACE    1       /* Ran out of memory.  */
-#define        GLOB_ABEND      2       /* Read error.  */
+#define        GLOB_ABORTED    2       /* Read error.  */
 #define        GLOB_NOMATCH    3       /* No matches found.  */
+#define GLOB_NOSYS     4       /* Not implemented.  */
+#ifdef _GNU_SOURCE
+/* Previous versions of this file defined GLOB_ABEND instead of
+   GLOB_ABORTED.  Provide a compatibility definition here.  */
+# define GLOB_ABEND GLOB_ABORTED
+#endif
 
 /* 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.  */
+    __size_t 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'.  */
+    __size_t 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) __PMT ((void *));
+    struct dirent *(*gl_readdir) __PMT ((void *));
+    __ptr_t (*gl_opendir) __PMT ((__const char *));
+    int (*gl_lstat) __PMT ((__const char *, struct stat *));
+    int (*gl_stat) __PMT ((__const char *, struct stat *));
   } glob_t;
 
+#ifdef _LARGEFILE64_SOURCE
+struct stat64;
+typedef struct
+  {
+    __size_t gl_pathc;
+    char **gl_pathv;
+    __size_t gl_offs;
+    int gl_flags;
+
+    /* If the GLOB_ALTDIRFUNC flag is set, the following functions
+       are used instead of the normal file access functions.  */
+    void (*gl_closedir) __PMT ((void *));
+    struct dirent64 *(*gl_readdir) __PMT ((void *));
+    __ptr_t (*gl_opendir) __PMT ((__const char *));
+    int (*gl_lstat) __PMT ((__const char *, struct stat64 *));
+    int (*gl_stat) __PMT ((__const char *, struct stat64 *));
+  } glob64_t;
+#endif
+
 /* 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,
@@ -75,19 +151,42 @@ typedef struct
    `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.  */
-extern int glob __P ((const char *__pattern, int __flags,
-                     int (*__errfunc) __P ((const char *, int)),
+#if _FILE_OFFSET_BITS != 64
+extern int glob __P ((__const char *__pattern, int __flags,
+                     int (*__errfunc) (__const char *, int),
                      glob_t *__pglob));
 
 /* Free storage allocated in PGLOB by a previous `glob' call.  */
 extern void globfree __P ((glob_t *__pglob));
+#else
+# if __GNUC__ >= 2
+extern int glob __P ((__const char *__pattern, int __flags,
+                     int (*__errfunc) (__const char *, int),
+                     glob_t *__pglob)) __asm__ ("glob64");
+
+extern void globfree __P ((glob_t *__pglob)) __asm__ ("globfree64");
+# else
+#  define glob glob64
+#  define globfree globfree64
+# endif
+#endif
+
+#ifdef _LARGEFILE64_SOURCE
+extern int glob64 __P ((__const char *__pattern, int __flags,
+                       int (*__errfunc) (__const char *, int),
+                       glob64_t *__pglob));
+
+extern void globfree64 __P ((glob64_t *__pglob));
+#endif
+
 
+#ifdef _GNU_SOURCE
+/* Return nonzero if PATTERN contains any metacharacters.
+   Metacharacters can be quoted with backslashes if QUOTE is nonzero.
 
-#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));
+   This function is not part of the interface specified by POSIX.2
+   but several programs want to use it.  */
+extern int glob_pattern_p __P ((__const char *__pattern, int __quote));
 #endif
 
 #ifdef __cplusplus