Skip to content

Commit

Permalink
glob/fnmatch
Browse files Browse the repository at this point in the history
git-svn-id: http://svn.ruby-lang.org/repos/ruby/branches/v1_1r@214 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information
matz committed May 15, 1998
1 parent bf316cd commit a597c26
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 66 deletions.
79 changes: 64 additions & 15 deletions fnmatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,35 +55,62 @@ fnmatch (pattern, string, flags)
if (*n == '\0')
return (FNM_NOMATCH);
else if ((flags & FNM_PATHNAME) && *n == '/')
/* If we are matching a pathname, `?' can never match a `/'. */
return (FNM_NOMATCH);
else if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
/* `?' cannot match a `.' if it is the first character of the
string or if it is the first character following a slash and
we are matching a pathname. */
return (FNM_NOMATCH);
break;

case '\\':
if (!(flags & FNM_NOESCAPE))
c = *p++;
{
c = *p++;
if (c == '\0')
return (FNM_NOMATCH);
}
if (*n != c)
return (FNM_NOMATCH);
break;

case '*':
if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
/* `*' cannot match a `.' if it is the first character of the
string or if it is the first character following a slash and
we are matching a pathname. */
return (FNM_NOMATCH);

for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
if (((flags & FNM_PATHNAME) && *n == '/') ||
(c == '?' && *n == '\0'))
return (FNM_NOMATCH);
/* Collapse multiple consecutive, `*' and `?', but make sure that
one character of the string is consumed for each `?'. */
for (c = *p++; c == '?' || c == '*'; c = *p++)
{
if ((flags & FNM_PATHNAME) && *n == '/')
/* A slash does not match a wildcard under FNM_PATHNAME. */
return (FNM_NOMATCH);
else if (c == '?')
{
if (*n == '\0')
return (FNM_NOMATCH);
/* One character of the string is consumed in matching
this ? wildcard, so *??? won't match if there are
fewer than three characters. */
n++;
}
}

if (c == '\0')
return (0);

/* General case, use recursion. */
{
char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
for (--p; *n != '\0'; ++n)
/* Only call fnmatch if the first character indicates a
possible match. */
if ((c == '[' || *n == c1) &&
fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
return (0);
Expand All @@ -98,22 +125,30 @@ fnmatch (pattern, string, flags)
if (*n == '\0')
return (FNM_NOMATCH);

/* A character class cannot match a `.' if it is the first
character of the string or if it is the first character
following a slash and we are matching a pathname. */
if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
return (FNM_NOMATCH);

/* Make sure there is a closing `]'. If there isn't, the `['
is just a character to be matched. */
/* POSIX.2 2.8.3.1.2 says: `An expression containing a `[' that
is not preceded by a backslash and is not part of a bracket
expression produces undefined results.' This implementation
treats the `[' as just a character to be matched if there is
not a closing `]'. This code will have to be changed when
POSIX.2 character classes are implemented. */
{
register char *np;

for (np = p; np && *np && *np != ']'; np++);
for (np = p; np && *np && *np != ']'; np++)
;

if (np && !*np)
{
if (*n != '[')
return (FNM_NOMATCH);
goto next_char;
break;
}
}

Expand All @@ -124,10 +159,18 @@ fnmatch (pattern, string, flags)
c = *p++;
for (;;)
{
register char cstart = c, cend = c;
register char cstart, cend;

/* Initialize cstart and cend in case `-' is the last
character of the pattern. */
cstart = cend = c;

if (!(flags & FNM_NOESCAPE) && c == '\\')
cstart = cend = *p++;
{
if (*p == '\0')
return FNM_NOMATCH;
cstart = cend = *p++;
}

if (c == '\0')
/* [ (unterminated) loses. */
Expand All @@ -139,13 +182,17 @@ fnmatch (pattern, string, flags)
/* [/] can never match. */
return (FNM_NOMATCH);

/* This introduces a range, unless the `-' is the last
character of the class. Find the end of the range
and move past it. */
if (c == '-' && *p != ']')
{
cend = *p++;
if (!(flags & FNM_NOESCAPE) && cend == '\\')
cend = *p++;
if (cend == '\0')
return (FNM_NOMATCH);

c = *p++;
}

Expand All @@ -157,8 +204,6 @@ fnmatch (pattern, string, flags)
}
if (!not)
return (FNM_NOMATCH);

next_char:
break;

matched:
Expand All @@ -171,8 +216,12 @@ fnmatch (pattern, string, flags)

c = *p++;
if (!(flags & FNM_NOESCAPE) && c == '\\')
/* 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);
Expand Down
106 changes: 55 additions & 51 deletions glob.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,42 +14,48 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */


/* To whomever it may concern: I have never seen the code which most
Unix programs use to perform this function. I wrote this from scratch
based on specifications for the pattern matching. --RMS. */

#include "config.h"
#include <config.h>

#include <sys/types.h>
#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX)
#pragma alloca
#endif /* _AIX && RISC6000 && !__GNUC__ */

#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif

#if !defined (SHELL) && (defined (_POSIX_VERSION) || defined (USGr3))
# if !defined (HAVE_DIRENT_H)
# define HAVE_DIRENT_H
# endif /* !HAVE_DIRENT_H */
#endif /* !SHELL && (_POSIX_VERSION || USGr3) */
#if defined (HAVE_STDLIB_H)
# include <stdlib.h>
#else
# if defined (SHELL)
# include "ansi_stdlib.h"
# endif /* SHELL */
#endif

#include <sys/types.h>

#if defined (HAVE_DIRENT_H)
# include <dirent.h>
# if !defined (direct)
# define direct dirent
# endif /* !direct */
# define D_NAMLEN(d) strlen ((d)->d_name)
#else /* !HAVE_DIRENT_H */
# define D_NAMLEN(d) ((d)->d_namlen)
# if defined (USG)
# if defined (Xenix)
# include <sys/ndir.h>
# else /* !Xenix (but USG...) */
# include "ndir.h"
# endif /* !Xenix */
# else /* !USG */
# if defined(NT)
# include "missing/dir.h"
# else
# if defined (HAVE_SYS_NDIR_H)
# include <sys/ndir.h>
# endif
# if defined (HAVE_SYS_DIR_H)
# include <sys/dir.h>
# endif /* !NT */
# endif /* !USG */
# endif /* HAVE_SYS_DIR_H */
# if defined (HAVE_NDIR_H)
# include <ndir.h>
# endif
# if !defined (dirent)
# define dirent direct
# endif
#endif /* !HAVE_DIRENT_H */

#if defined (_POSIX_SOURCE) || defined(DJGPP) || defined(USE_CWGUSI)
Expand All @@ -60,37 +66,18 @@
# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
#endif /* _POSIX_SOURCE */

#if defined (USG) || defined (NeXT)
# if !defined (HAVE_STRING_H)
# define HAVE_STRING_H
# endif /* !HAVE_STRING_H */
#endif /* USG || NeXT */

#if defined (HAVE_STRING_H)
# include <string.h>
#else /* !HAVE_STRING_H */
# include <strings.h>
#endif /* !HAVE_STRING_H */

#ifndef bcopy
# define bcopy(s, d, n) (memcpy ((d), (s), (n)))
#endif

#ifdef _AIX
#pragma alloca
#else
#if defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
#include <alloca.h>
#else
char *alloca ();
#endif
#endif

#include "fnmatch.h"
#if !defined (HAVE_BCOPY)
# define bcopy(s, d, n) ((void) memcpy ((d), (s), (n)))
#endif /* !HAVE_BCOPY */

/* If the opendir () on your system lets you open non-directory files,
then we consider that not robust. Define OPENDIR_NOT_ROBUST in the
SYSDEP_CFLAGS for your machines entry in machines.h. */
then we consider that not robust. */
#if defined (OPENDIR_NOT_ROBUST)
# if defined (SHELL)
# include "posixstat.h"
Expand All @@ -99,6 +86,8 @@ char *alloca ();
# endif /* !SHELL */
#endif /* OPENDIR_NOT_ROBUST */

#include "fnmatch.h"

extern void *xmalloc (), *xrealloc ();
#if !defined (HAVE_STDLIB_H)
extern void free ();
Expand All @@ -113,6 +102,8 @@ extern void free ();
#endif /* !NULL */

#if defined (SHELL)
extern void throw_to_top_level ();

extern int interrupt_state;
#endif /* SHELL */

Expand All @@ -123,7 +114,6 @@ int noglob_dot_filenames = 1;
/* Global variable to return to signify an error in globbing. */
char *glob_error_return;


/* Return nonzero if PATTERN has any special globbing chars in it. */
int
glob_pattern_p (pattern)
Expand Down Expand Up @@ -205,7 +195,7 @@ glob_vector (pat, dir)
};

DIR *d;
register struct direct *dp;
register struct dirent *dp;
struct globval *lastlink;
register struct globval *nextlink;
register char *nextname;
Expand Down Expand Up @@ -276,7 +266,8 @@ glob_vector (pat, dir)
continue;

/* If a dot must be explicity matched, check to see if they do. */
if (noglob_dot_filenames && dp->d_name[0] == '.' && pat[0] != '.')
if (noglob_dot_filenames && dp->d_name[0] == '.' && pat[0] != '.' &&
(pat[0] != '\\' || pat[1] != '.'))
continue;

flags = (noglob_dot_filenames ? FNM_PERIOD : 0) | FNM_PATHNAME;
Expand Down Expand Up @@ -306,7 +297,9 @@ glob_vector (pat, dir)
}

/* Have we run out of memory? */
#if defined (SHELL)
lost:
#endif
if (lose)
{
/* Here free the strings we have got. */
Expand Down Expand Up @@ -365,7 +358,14 @@ glob_dir_to_array (dir, array)
+ strlen (array[i]) + 1);
if (result[i] == NULL)
return (NULL);
sprintf (result[i], "%s%s%s", dir, add_slash ? "/" : "", array[i]);
#if 1
strcpy (result[i], dir);
if (add_slash)
result[i][l] = '/';
strcpy (result[i] + l + add_slash, array[i]);
#else
(void)sprintf (result[i], "%s%s%s", dir, add_slash ? "/" : "", array[i]);
#endif
}
result[i] = NULL;

Expand Down Expand Up @@ -435,10 +435,14 @@ glob_filename (pathname)
if (directories == NULL)
goto memory_error;
else if (directories == (char **)&glob_error_return)
return ((char **) &glob_error_return);
{
free ((char *) result);
return ((char **) &glob_error_return);
}
else if (*directories == NULL)
{
free ((char *) directories);
free ((char *) result);
return ((char **) &glob_error_return);
}

Expand Down

0 comments on commit a597c26

Please sign in to comment.