Imported from ../bash-2.02.tar.gz.
This commit is contained in:
parent
e8ce775db8
commit
cce855bc5b
323 changed files with 33916 additions and 12321 deletions
129
lib/glob/collsyms.h
Normal file
129
lib/glob/collsyms.h
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/* collsyms.h -- collating symbol names and their corresponding characters
|
||||
(in ascii) as given by POSIX.2 in table 2.8. */
|
||||
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash 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 General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef _COLLSYMS_H_
|
||||
# define _COLLSYSMS_H_
|
||||
|
||||
/* The upper-case letters, lower-case letters, and digits are omitted from
|
||||
this table. The digits are not included in the table in the POSIX.2
|
||||
spec. The upper and lower case letters are translated by the code
|
||||
in fnmatch.c:collsym(). */
|
||||
|
||||
typedef struct _collsym {
|
||||
char *name;
|
||||
char code;
|
||||
} COLLSYM;
|
||||
|
||||
static COLLSYM posix_collsyms[] =
|
||||
{
|
||||
"NUL", '\0',
|
||||
"SOH", '\001',
|
||||
"STX", '\002',
|
||||
"ETX", '\003',
|
||||
"EOT", '\004',
|
||||
"ENQ", '\005',
|
||||
"ACK", '\006',
|
||||
#ifdef __STDC__
|
||||
"alert", '\a',
|
||||
#else
|
||||
"alert", '\007',
|
||||
#endif
|
||||
"backspace", '\b',
|
||||
"tab", '\t',
|
||||
"newline", '\n',
|
||||
"vertical-tab", '\v',
|
||||
"form-feed", '\f',
|
||||
"carriage-return", '\r',
|
||||
"SO", '\016',
|
||||
"SI", '\017',
|
||||
"DLE", '\020',
|
||||
"DC1", '\021',
|
||||
"DC2", '\022',
|
||||
"DC3", '\023',
|
||||
"DC4", '\024',
|
||||
"NAK", '\025',
|
||||
"SYN", '\026',
|
||||
"ETB", '\027',
|
||||
"CAN", '\030',
|
||||
"EM", '\031',
|
||||
"SUB", '\032',
|
||||
"ESC", '\033',
|
||||
"IS4", '\034',
|
||||
"IS3", '\035',
|
||||
"IS2", '\036',
|
||||
"IS1", '\037',
|
||||
"space", ' ',
|
||||
"exclamation-mark", '!',
|
||||
"quotation-mark", '"',
|
||||
"number-sign", '#',
|
||||
"dollar-sign", '$',
|
||||
"percent-sign", '%',
|
||||
"ampersand", '&',
|
||||
"apostrophe", '\'',
|
||||
"left-parenthesis", '(',
|
||||
"right-parenthesis", ')',
|
||||
"asterisk", '*',
|
||||
"plus-sign", '+',
|
||||
"comma", ',',
|
||||
"hyphen", '-',
|
||||
"minus", '-', /* extension from POSIX.2 */
|
||||
"dash", '-', /* extension from POSIX.2 */
|
||||
"period", '.',
|
||||
"slash", '/',
|
||||
"solidus", '/', /* extension from POSIX.2 */
|
||||
"zero", '0',
|
||||
"one", '1',
|
||||
"two", '2',
|
||||
"three", '3',
|
||||
"four", '4',
|
||||
"five", '5',
|
||||
"six", '6',
|
||||
"seven", '7',
|
||||
"eight", '8',
|
||||
"nine", '9',
|
||||
"colon", ':',
|
||||
"semicolon", ';',
|
||||
"less-than-sign", '<',
|
||||
"equals-sign", '=',
|
||||
"greater-than-sign", '>',
|
||||
"question-mark", '?',
|
||||
"commercial-at", '@',
|
||||
/* upper-case letters omitted */
|
||||
"left-square-bracket",'[',
|
||||
"backslash", '\\',
|
||||
"reverse-solidus", '\\',
|
||||
"right-square-bracket", ']',
|
||||
"circumflex", '^',
|
||||
"circumflex-accent", '^', /* extension from POSIX.2 */
|
||||
"underscore", '_',
|
||||
"grave-accent", '`',
|
||||
/* lower-case letters omitted */
|
||||
"left-brace", '{', /* extension from POSIX.2 */
|
||||
"left-curly-bracket", '{',
|
||||
"vertical-line", '|',
|
||||
"right-brace", '}', /* extension from POSIX.2 */
|
||||
"right-curly-bracket", '}',
|
||||
"tilde", '~',
|
||||
"DEL", '\177',
|
||||
0, 0,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,238 +1,738 @@
|
|||
/* Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
/* fnmatch.c -- ksh-like extended pattern matching for the shell and filename
|
||||
globbing. */
|
||||
|
||||
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.
|
||||
/* Copyright (C) 1991, 1997 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash 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 General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 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., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <config.h>
|
||||
|
||||
#include "fnmatch.h"
|
||||
#include "collsyms.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#if !defined (__GNU_LIBRARY__) && !defined (STDC_HEADERS)
|
||||
# if !defined (errno)
|
||||
extern int errno;
|
||||
# endif /* !errno */
|
||||
static int gmatch ();
|
||||
static char *brackmatch ();
|
||||
#ifdef EXTENDED_GLOB
|
||||
static int extmatch ();
|
||||
#endif
|
||||
|
||||
#if !defined (isascii)
|
||||
# define isascii(c) ((unsigned int)(c) <= 0177)
|
||||
#endif
|
||||
|
||||
/* Match STRING against the filename pattern PATTERN, returning zero if
|
||||
it matches, FNM_NOMATCH if not. */
|
||||
/* Note that these evaluate C many times. */
|
||||
|
||||
#define ISUPPER(c) (isascii (c) && isupper (c))
|
||||
#define ISLOWER(c) (isascii (c) && islower (c))
|
||||
|
||||
#ifndef isblank
|
||||
# define isblank(c) ((c) == ' ' || (c) == '\t')
|
||||
#endif
|
||||
|
||||
#ifndef isgraph
|
||||
# define isgraph(c) ((c) != ' ' && isprint((c)))
|
||||
#endif
|
||||
|
||||
#ifndef isxdigit
|
||||
# define isxdigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
|
||||
#endif
|
||||
|
||||
# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
|
||||
|
||||
#ifndef STREQ
|
||||
#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0)
|
||||
#define STREQN(a, b, n) ((a)[0] == (b)[0] && strncmp(a, b, n) == 0)
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_STRCOLL)
|
||||
static int rangecmp (c1, c2)
|
||||
int c1, c2;
|
||||
{
|
||||
static char s1[2] = { ' ', '\0' };
|
||||
static char s2[2] = { ' ', '\0' };
|
||||
int ret;
|
||||
|
||||
/* Eight bits only. Period. */
|
||||
c1 &= 0xFF;
|
||||
c2 &= 0xFF;
|
||||
|
||||
if (c1 == c2)
|
||||
return (0);
|
||||
|
||||
s1[0] = c1;
|
||||
s2[0] = c2;
|
||||
|
||||
if ((ret = strcoll (s1, s2)) != 0)
|
||||
return ret;
|
||||
return (c1 - c2);
|
||||
}
|
||||
#else /* !HAVE_STRCOLL */
|
||||
# define rangecmp(c1, c2) ((c1) - (c2))
|
||||
#endif /* !HAVE_STRCOLL */
|
||||
|
||||
#if defined (HAVE_STRCOLL)
|
||||
static int collequiv (c1, c2)
|
||||
int c1, c2;
|
||||
{
|
||||
return (rangecmp (c1, c2) == 0);
|
||||
}
|
||||
#else
|
||||
# define collequiv(c1, c2) ((c1) == (c2))
|
||||
#endif
|
||||
|
||||
static int
|
||||
collsym (s, len)
|
||||
char *s;
|
||||
int len;
|
||||
{
|
||||
register struct _collsym *csp;
|
||||
|
||||
for (csp = posix_collsyms; csp->name; csp++)
|
||||
{
|
||||
if (STREQN(csp->name, s, len) && csp->name[len] == '\0')
|
||||
return (csp->code);
|
||||
}
|
||||
if (len == 1)
|
||||
return s[0];
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
fnmatch (pattern, string, flags)
|
||||
char *pattern;
|
||||
char *string;
|
||||
int flags;
|
||||
{
|
||||
register char *p = pattern, *n = string;
|
||||
register char c;
|
||||
char *se, *pe;
|
||||
|
||||
if ((flags & ~__FNM_FLAGS) != 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
if (string == 0 || pattern == 0)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
while ((c = *p++) != '\0')
|
||||
se = string + strlen (string);
|
||||
pe = pattern + strlen (pattern);
|
||||
|
||||
return (gmatch (string, se, pattern, pe, flags));
|
||||
}
|
||||
|
||||
/* Match STRING against the filename pattern PATTERN, returning zero if
|
||||
it matches, FNM_NOMATCH if not. */
|
||||
static int
|
||||
gmatch (string, se, pattern, pe, flags)
|
||||
char *string, *se;
|
||||
char *pattern, *pe;
|
||||
int flags;
|
||||
{
|
||||
register char *p, *n; /* pattern, string */
|
||||
register char c; /* current pattern character */
|
||||
register char sc; /* current string character */
|
||||
|
||||
p = pattern;
|
||||
n = string;
|
||||
|
||||
if (string == 0 || pattern == 0)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
while (p < pe)
|
||||
{
|
||||
c = *p++;
|
||||
c = FOLD (c);
|
||||
|
||||
sc = n < se ? *n : '\0';
|
||||
|
||||
#ifdef EXTENDED_GLOB
|
||||
if ((flags & FNM_EXTMATCH) && *p == '(' &&
|
||||
(c == '+' || c == '*' || c == '?' || c == '@' || c == '!')) /* ) */
|
||||
/* extmatch () will handle recursively calling gmatch, so we can
|
||||
just return what extmatch() returns. */
|
||||
return (extmatch (c, n, se, p, pe, flags));
|
||||
#endif
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '?':
|
||||
if (*n == '\0')
|
||||
return (FNM_NOMATCH);
|
||||
else if ((flags & FNM_PATHNAME) && *n == '/')
|
||||
case '?': /* Match single character */
|
||||
if (sc == '\0')
|
||||
return FNM_NOMATCH;
|
||||
else if ((flags & FNM_PATHNAME) && sc == '/')
|
||||
/* If we are matching a pathname, `?' can never match a `/'. */
|
||||
return (FNM_NOMATCH);
|
||||
else if ((flags & FNM_PERIOD) && *n == '.' &&
|
||||
return FNM_NOMATCH;
|
||||
else if ((flags & FNM_PERIOD) && sc == '.' &&
|
||||
(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);
|
||||
return FNM_NOMATCH;
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
if (!(flags & FNM_NOESCAPE))
|
||||
case '\\': /* backslash escape removes special meaning */
|
||||
if (p == pe)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
if ((flags & FNM_NOESCAPE) == 0)
|
||||
{
|
||||
c = *p++;
|
||||
if (c == '\0')
|
||||
return (FNM_NOMATCH);
|
||||
/* A trailing `\' cannot match. */
|
||||
if (p > pe)
|
||||
return FNM_NOMATCH;
|
||||
c = FOLD (c);
|
||||
}
|
||||
if (*n != c)
|
||||
return (FNM_NOMATCH);
|
||||
if (FOLD (sc) != c)
|
||||
return FNM_NOMATCH;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
if ((flags & FNM_PERIOD) && *n == '.' &&
|
||||
case '*': /* Match zero or more characters */
|
||||
if (p == pe)
|
||||
return 0;
|
||||
|
||||
if ((flags & FNM_PERIOD) && sc == '.' &&
|
||||
(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);
|
||||
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++)
|
||||
for (c = *p++; (c == '?' || c == '*'); c = *p++)
|
||||
{
|
||||
if ((flags & FNM_PATHNAME) && *n == '/')
|
||||
if ((flags & FNM_PATHNAME) && sc == '/')
|
||||
/* A slash does not match a wildcard under FNM_PATHNAME. */
|
||||
return (FNM_NOMATCH);
|
||||
return FNM_NOMATCH;
|
||||
else if (c == '?')
|
||||
{
|
||||
if (*n == '\0')
|
||||
return (FNM_NOMATCH);
|
||||
if (sc == '\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++;
|
||||
sc = n < se ? *n : '\0';
|
||||
}
|
||||
|
||||
#ifdef EXTENDED_GLOB
|
||||
/* Handle ******(patlist) */
|
||||
if ((flags & FNM_EXTMATCH) && c == '*' && *p == '(') /*)*/
|
||||
return (extmatch (c, n, se, p, pe, flags));
|
||||
#endif
|
||||
if (p == pe)
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '\0')
|
||||
/* If we've hit the end of the pattern and the last character of
|
||||
the pattern was handled by the loop above, we've succeeded.
|
||||
Otherwise, we need to match that last character. */
|
||||
if (p == pe && (c == '?' || c == '*'))
|
||||
return (0);
|
||||
|
||||
/* General case, use recursion. */
|
||||
{
|
||||
char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
|
||||
for (--p; *n != '\0'; ++n)
|
||||
char c1;
|
||||
|
||||
c1 = ((flags & FNM_NOESCAPE) == 0 && c == '\\') ? *p : c;
|
||||
c1 = FOLD (c1);
|
||||
for (--p; n < se; ++n)
|
||||
/* Only call fnmatch if the first character indicates a
|
||||
possible match. */
|
||||
if ((c == '[' || *n == c1) &&
|
||||
fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
|
||||
if ((c == '[' || FOLD (*n) == c1) &&
|
||||
gmatch (n, se, p, pe, flags & ~FNM_PERIOD) == 0)
|
||||
return (0);
|
||||
return (FNM_NOMATCH);
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
|
||||
case '[':
|
||||
{
|
||||
/* Nonzero if the sense of the character class is inverted. */
|
||||
register int not;
|
||||
|
||||
if (*n == '\0')
|
||||
return (FNM_NOMATCH);
|
||||
if (sc == '\0' || n == se)
|
||||
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 == '.' &&
|
||||
if ((flags & FNM_PERIOD) && sc == '.' &&
|
||||
(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
/* 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++)
|
||||
;
|
||||
|
||||
if (np && !*np)
|
||||
{
|
||||
if (*n != '[')
|
||||
return (FNM_NOMATCH);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
not = (*p == '!' || *p == '^');
|
||||
if (not)
|
||||
++p;
|
||||
|
||||
c = *p++;
|
||||
for (;;)
|
||||
{
|
||||
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 == '\\')
|
||||
{
|
||||
if (*p == '\0')
|
||||
return FNM_NOMATCH;
|
||||
cstart = cend = *p++;
|
||||
}
|
||||
|
||||
if (c == '\0')
|
||||
/* [ (unterminated) loses. */
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
c = *p++;
|
||||
|
||||
if ((flags & FNM_PATHNAME) && c == '/')
|
||||
/* [/] 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++;
|
||||
}
|
||||
|
||||
if (*n >= cstart && *n <= cend)
|
||||
goto matched;
|
||||
|
||||
if (c == ']')
|
||||
break;
|
||||
}
|
||||
if (!not)
|
||||
return (FNM_NOMATCH);
|
||||
break;
|
||||
|
||||
matched:
|
||||
/* Skip the rest of the [...] that already matched. */
|
||||
while (c != ']')
|
||||
{
|
||||
if (c == '\0')
|
||||
/* [... (unterminated) loses. */
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
c = *p++;
|
||||
if (!(flags & FNM_NOESCAPE) && c == '\\')
|
||||
{
|
||||
if (*p == '\0')
|
||||
return FNM_NOMATCH;
|
||||
/* XXX 1003.2d11 is unclear if this is right. */
|
||||
++p;
|
||||
}
|
||||
}
|
||||
if (not)
|
||||
return (FNM_NOMATCH);
|
||||
p = brackmatch (p, sc, flags);
|
||||
if (p == 0)
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (c != *n)
|
||||
if (c != FOLD (sc))
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
|
||||
++n;
|
||||
}
|
||||
|
||||
if (*n == '\0')
|
||||
if (n == se)
|
||||
return (0);
|
||||
|
||||
if ((flags & FNM_LEADING_DIR) && *n == '/')
|
||||
/* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
|
||||
return 0;
|
||||
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
|
||||
/* Parse a bracket expression collating symbol ([.sym.]) starting at P, find
|
||||
the value of the symbol, and move P past the collating symbol expression.
|
||||
The value is returned in *VP, if VP is not null. */
|
||||
static char *
|
||||
parse_collsym (p, vp)
|
||||
char *p;
|
||||
int *vp;
|
||||
{
|
||||
register int pc;
|
||||
int val;
|
||||
|
||||
p++; /* move past the `.' */
|
||||
|
||||
for (pc = 0; p[pc]; pc++)
|
||||
if (p[pc] == '.' && p[pc+1] == ']')
|
||||
break;
|
||||
val = collsym (p, pc);
|
||||
if (vp)
|
||||
*vp = val;
|
||||
return (p + pc + 2);
|
||||
}
|
||||
|
||||
static char *
|
||||
brackmatch (p, test, flags)
|
||||
char *p;
|
||||
unsigned char test;
|
||||
int flags;
|
||||
{
|
||||
register char cstart, cend, c;
|
||||
register int not; /* Nonzero if the sense of the character class is inverted. */
|
||||
int pc, brcnt;
|
||||
char *savep;
|
||||
|
||||
test = FOLD (test);
|
||||
|
||||
savep = p;
|
||||
|
||||
/* POSIX.2 3.13.1 says that an exclamation mark (`!') shall replace the
|
||||
circumflex (`^') in its role in a `nonmatching list'. A bracket
|
||||
expression starging with an unquoted circumflex character produces
|
||||
unspecified results. This implementation treats the two identically. */
|
||||
if (not = (*p == '!' || *p == '^'))
|
||||
++p;
|
||||
|
||||
c = *p++;
|
||||
for (;;)
|
||||
{
|
||||
/* Initialize cstart and cend in case `-' is the last
|
||||
character of the pattern. */
|
||||
cstart = cend = c;
|
||||
|
||||
/* POSIX.2 equivalence class: [=c=]. See POSIX.2 2.8.3.2. Find
|
||||
the end of the equivalence class, move the pattern pointer past
|
||||
it, and check for equivalence. XXX - this handles only
|
||||
single-character equivalence classes, which is wrong, or at
|
||||
least incomplete. */
|
||||
if (c == '[' && *p == '=' && p[2] == '=' && p[3] == ']')
|
||||
{
|
||||
pc = FOLD (p[1]);
|
||||
p += 4;
|
||||
if (collequiv (test, pc))
|
||||
goto matched;
|
||||
else
|
||||
{
|
||||
c = *p++;
|
||||
if (c == '\0')
|
||||
return ((test == '[') ? savep : (char *)0);
|
||||
c = FOLD (c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* POSIX.2 character class expression. See POSIX.2 2.8.3.2. */
|
||||
if (c == '[' && *p == ':')
|
||||
{
|
||||
pc = 0; /* make sure invalid char classes don't match. */
|
||||
if (STREQN (p+1, "alnum:]", 7))
|
||||
{ pc = isalnum (test); p += 8; }
|
||||
else if (STREQN (p+1, "alpha:]", 7))
|
||||
{ pc = isalpha (test); p += 8; }
|
||||
else if (STREQN (p+1, "blank:]", 7))
|
||||
{ pc = isblank (test); p += 8; }
|
||||
else if (STREQN (p+1, "cntrl:]", 7))
|
||||
{ pc = iscntrl (test); p += 8; }
|
||||
else if (STREQN (p+1, "digit:]", 7))
|
||||
{ pc = isdigit (test); p += 8; }
|
||||
else if (STREQN (p+1, "graph:]", 7))
|
||||
{ pc = isgraph (test); p += 8; }
|
||||
else if (STREQN (p+1, "lower:]", 7))
|
||||
{ pc = ISLOWER (test); p += 8; }
|
||||
else if (STREQN (p+1, "print:]", 7))
|
||||
{ pc = isprint (test); p += 8; }
|
||||
else if (STREQN (p+1, "punct:]", 7))
|
||||
{ pc = ispunct (test); p += 8; }
|
||||
else if (STREQN (p+1, "space:]", 7))
|
||||
{ pc = isspace (test); p += 8; }
|
||||
else if (STREQN (p+1, "upper:]", 7))
|
||||
{ pc = ISUPPER (test); p += 8; }
|
||||
else if (STREQN (p+1, "xdigit:]", 8))
|
||||
{ pc = isxdigit (test); p += 9; }
|
||||
else if (STREQN (p+1, "ascii:]", 7))
|
||||
{ pc = isascii (test); p += 8; }
|
||||
if (pc)
|
||||
goto matched;
|
||||
else
|
||||
{
|
||||
/* continue the loop here, since this expression can't be
|
||||
the first part of a range expression. */
|
||||
c = *p++;
|
||||
if (c == '\0')
|
||||
return ((test == '[') ? savep : (char *)0);
|
||||
else if (c == ']')
|
||||
break;
|
||||
c = FOLD (c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* POSIX.2 collating symbols. See POSIX.2 2.8.3.2. Find the end of
|
||||
the symbol name, make sure it is terminated by `.]', translate
|
||||
the name to a character using the external table, and do the
|
||||
comparison. */
|
||||
if (c == '[' && *p == '.')
|
||||
{
|
||||
p = parse_collsym (p, &pc);
|
||||
/* An invalid collating symbol cannot be the first point of a
|
||||
range. If it is, we set cstart to one greater than `test',
|
||||
so any comparisons later will fail. */
|
||||
cstart = (pc == -1) ? test + 1 : pc;
|
||||
}
|
||||
|
||||
if (!(flags & FNM_NOESCAPE) && c == '\\')
|
||||
{
|
||||
if (*p == '\0')
|
||||
return (char *)0;
|
||||
cstart = cend = *p++;
|
||||
}
|
||||
|
||||
cstart = cend = FOLD (cstart);
|
||||
|
||||
/* 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 `]'. */
|
||||
if (c == '\0')
|
||||
return ((test == '[') ? savep : (char *)0);
|
||||
|
||||
c = *p++;
|
||||
c = FOLD (c);
|
||||
|
||||
if ((flags & FNM_PATHNAME) && c == '/')
|
||||
/* [/] can never match when matching a pathname. */
|
||||
return (char *)0;
|
||||
|
||||
/* 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 (char *)0;
|
||||
if (cend == '[' && *p == '.')
|
||||
{
|
||||
p = parse_collsym (p, &pc);
|
||||
/* An invalid collating symbol cannot be the second part of a
|
||||
range expression. If we get one, we set cend to one fewer
|
||||
than the test character to make sure the range test fails. */
|
||||
cend = (pc == -1) ? test - 1 : pc;
|
||||
}
|
||||
cend = FOLD (cend);
|
||||
|
||||
c = *p++;
|
||||
|
||||
/* POSIX.2 2.8.3.2: ``The ending range point shall collate
|
||||
equal to or higher than the starting range point; otherwise
|
||||
the expression shall be treated as invalid.'' Note that this
|
||||
applies to only the range expression; the rest of the bracket
|
||||
expression is still checked for matches. */
|
||||
if (rangecmp (cstart, cend) > 0)
|
||||
{
|
||||
if (c == ']')
|
||||
break;
|
||||
c = FOLD (c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (rangecmp (test, cstart) >= 0 && rangecmp (test, cend) <= 0)
|
||||
goto matched;
|
||||
|
||||
if (c == ']')
|
||||
break;
|
||||
}
|
||||
/* No match. */
|
||||
return (!not ? (char *)0 : p);
|
||||
|
||||
matched:
|
||||
/* Skip the rest of the [...] that already matched. */
|
||||
brcnt = (c != ']') + (c == '[' && (*p == '=' || *p == ':' || *p == '.'));
|
||||
while (brcnt > 0)
|
||||
{
|
||||
/* A `[' without a matching `]' is just another character to match. */
|
||||
if (c == '\0')
|
||||
return ((test == '[') ? savep : (char *)0);
|
||||
|
||||
c = *p++;
|
||||
if (c == '[' && (*p == '=' || *p == ':' || *p == '.'))
|
||||
brcnt++;
|
||||
else if (c == ']')
|
||||
brcnt--;
|
||||
else if (!(flags & FNM_NOESCAPE) && c == '\\')
|
||||
{
|
||||
if (*p == '\0')
|
||||
return (char *)0;
|
||||
/* XXX 1003.2d11 is unclear if this is right. */
|
||||
++p;
|
||||
}
|
||||
}
|
||||
return (not ? (char *)0 : p);
|
||||
}
|
||||
|
||||
#if defined (EXTENDED_GLOB)
|
||||
/* ksh-like extended pattern matching:
|
||||
|
||||
[?*+@!](pat-list)
|
||||
|
||||
where pat-list is a list of one or patterns separated by `|'. Operation
|
||||
is as follows:
|
||||
|
||||
?(patlist) match zero or one of the given patterns
|
||||
*(patlist) match zero or more of the given patterns
|
||||
+(patlist) match one or more of the given patterns
|
||||
@(patlist) match exactly one of the given patterns
|
||||
!(patlist) match anything except one of the given patterns
|
||||
*/
|
||||
|
||||
/* Scan a pattern starting at STRING and ending at END, keeping track of
|
||||
embedded () and []. If DELIM is 0, we scan until a matching `)'
|
||||
because we're scanning a `patlist'. Otherwise, we scan until we see
|
||||
DELIM. In all cases, we never scan past END. The return value is the
|
||||
first character after the matching DELIM. */
|
||||
static char *
|
||||
patscan (string, end, delim)
|
||||
char *string, *end;
|
||||
int delim;
|
||||
{
|
||||
int pnest, bnest;
|
||||
char *s, c;
|
||||
|
||||
pnest = bnest = 0;
|
||||
for (s = string; c = *s; s++)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '\0':
|
||||
return ((char *)0);
|
||||
case '[':
|
||||
bnest++;
|
||||
break;
|
||||
case ']':
|
||||
if (bnest)
|
||||
bnest--;
|
||||
break;
|
||||
case '(':
|
||||
if (bnest == 0)
|
||||
pnest++;
|
||||
break;
|
||||
case ')':
|
||||
if (bnest == 0)
|
||||
pnest--;
|
||||
if (pnest <= 0)
|
||||
return ++s;
|
||||
break;
|
||||
case '|':
|
||||
if (bnest == 0 && pnest == 0 && delim == '|')
|
||||
return ++s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (char *)0;
|
||||
}
|
||||
|
||||
/* Return 0 if dequoted pattern matches S in the current locale. */
|
||||
static int
|
||||
strcompare (p, pe, s, se)
|
||||
char *p, *pe, *s, *se;
|
||||
{
|
||||
int ret;
|
||||
char c1, c2;
|
||||
|
||||
c1 = *pe;
|
||||
c2 = *se;
|
||||
|
||||
*pe = *se = '\0';
|
||||
#if defined (HAVE_STRCOLL)
|
||||
ret = strcoll (p, s);
|
||||
#else
|
||||
ret = strcmp (p, s);
|
||||
#endif
|
||||
|
||||
*pe = c1;
|
||||
*se = c2;
|
||||
|
||||
return (ret == 0 ? ret : FNM_NOMATCH);
|
||||
}
|
||||
|
||||
/* Match a ksh extended pattern specifier. Return FNM_NOMATCH on failure or
|
||||
0 on success. This is handed the entire rest of the pattern and string
|
||||
the first time an extended pattern specifier is encountered, so it calls
|
||||
gmatch recursively. */
|
||||
static int
|
||||
extmatch (xc, s, se, p, pe, flags)
|
||||
int xc; /* select which operation */
|
||||
char *s, *se;
|
||||
char *p, *pe;
|
||||
int flags;
|
||||
{
|
||||
char *prest; /* pointer to rest of pattern */
|
||||
char *psub; /* pointer to sub-pattern */
|
||||
char *pnext; /* pointer to next sub-pattern */
|
||||
char *srest; /* pointer to rest of string */
|
||||
int m1, m2;
|
||||
|
||||
switch (xc)
|
||||
{
|
||||
case '+': /* match one or more occurrences */
|
||||
case '*': /* match zero or more occurrences */
|
||||
prest = patscan (p, pe, 0);
|
||||
if (prest == 0)
|
||||
/* If PREST is 0, we failed to scan a valid pattern. In this
|
||||
case, we just want to compare the two as strings. */
|
||||
return (strcompare (p - 1, pe, s, se));
|
||||
|
||||
/* If we can get away with no matches, don't even bother. Just
|
||||
call gmatch on the rest of the pattern and return success if
|
||||
it succeeds. */
|
||||
if (xc == '*' && (gmatch (s, se, prest, pe, flags) == 0))
|
||||
return 0;
|
||||
|
||||
/* OK, we have to do this the hard way. First, we make sure one of
|
||||
the subpatterns matches, then we try to match the rest of the
|
||||
string. */
|
||||
for (psub = p + 1; ; psub = pnext)
|
||||
{
|
||||
pnext = patscan (psub, pe, '|');
|
||||
for (srest = s; srest <= se; srest++)
|
||||
{
|
||||
/* Match this substring (S -> SREST) against this
|
||||
subpattern (psub -> pnext - 1) */
|
||||
m1 = gmatch (s, srest, psub, pnext - 1, flags) == 0;
|
||||
/* OK, we matched a subpattern, so make sure the rest of the
|
||||
string matches the rest of the pattern. Also handle
|
||||
multiple matches of the pattern. */
|
||||
if (m1)
|
||||
m2 = (gmatch (srest, se, prest, pe, flags) == 0) ||
|
||||
(s != srest && gmatch (srest, se, p - 1, pe, flags) == 0);
|
||||
if (m1 && m2)
|
||||
return (0);
|
||||
}
|
||||
if (pnext == prest)
|
||||
break;
|
||||
}
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
case '?': /* match zero or one of the patterns */
|
||||
case '@': /* match exactly one of the patterns */
|
||||
prest = patscan (p, pe, 0);
|
||||
if (prest == 0)
|
||||
return (strcompare (p - 1, pe, s, se));
|
||||
|
||||
/* If we can get away with no matches, don't even bother. Just
|
||||
call gmatch on the rest of the pattern and return success if
|
||||
it succeeds. */
|
||||
if (xc == '?' && (gmatch (s, se, prest, pe, flags) == 0))
|
||||
return 0;
|
||||
|
||||
/* OK, we have to do this the hard way. First, we see if one of
|
||||
the subpatterns matches, then, if it does, we try to match the
|
||||
rest of the string. */
|
||||
for (psub = p + 1; ; psub = pnext)
|
||||
{
|
||||
pnext = patscan (psub, pe, '|');
|
||||
srest = (prest == pe) ? se : s;
|
||||
for ( ; srest <= se; srest++)
|
||||
{
|
||||
if (gmatch (s, srest, psub, pnext - 1, flags) == 0 &&
|
||||
gmatch (srest, se, prest, pe, flags) == 0)
|
||||
return (0);
|
||||
}
|
||||
if (pnext == prest)
|
||||
break;
|
||||
}
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
case '!': /* match anything *except* one of the patterns */
|
||||
prest = patscan (p, pe, 0);
|
||||
if (prest == 0)
|
||||
return (strcompare (p - 1, pe, s, se));
|
||||
|
||||
for (srest = s; srest <= se; srest++)
|
||||
{
|
||||
m1 = 0;
|
||||
for (psub = p + 1; ; psub = pnext)
|
||||
{
|
||||
pnext = patscan (psub, pe, '|');
|
||||
/* If one of the patterns matches, just bail immediately. */
|
||||
if (m1 = (gmatch (s, srest, psub, pnext - 1, flags) == 0))
|
||||
break;
|
||||
if (pnext == prest)
|
||||
break;
|
||||
}
|
||||
if (m1 == 0 && gmatch (srest, se, prest, pe, flags) == 0)
|
||||
return (0);
|
||||
}
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
#endif /* EXTENDED_GLOB */
|
||||
|
||||
#ifdef TEST
|
||||
main (c, v)
|
||||
int c;
|
||||
char **v;
|
||||
{
|
||||
char *string, *pat;
|
||||
|
||||
string = v[1];
|
||||
pat = v[2];
|
||||
|
||||
if (fnmatch (pat, string, 0) == 0)
|
||||
{
|
||||
printf ("%s matches %s\n", string, pat);
|
||||
exit (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("%s does not match %s\n", string, pat);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -17,14 +17,24 @@ not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
|||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef _FNMATCH_H
|
||||
|
||||
#define _FNMATCH_H 1
|
||||
|
||||
/* We #undef these before defining them because some losing systems
|
||||
(HP-UX A.08.07 for example) define these in <unistd.h>. */
|
||||
#undef FNM_PATHNAME
|
||||
#undef FNM_NOESCAPE
|
||||
#undef FNM_PERIOD
|
||||
|
||||
/* Bits set in the FLAGS argument to `fnmatch'. */
|
||||
#define FNM_PATHNAME (1 << 0)/* No wildcard can ever match `/'. */
|
||||
#define FNM_NOESCAPE (1 << 1)/* Backslashes don't quote special chars. */
|
||||
#define FNM_PERIOD (1 << 2)/* Leading `.' is matched only explicitly. */
|
||||
#define __FNM_FLAGS (FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD)
|
||||
/* standard flags */
|
||||
#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
|
||||
#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
|
||||
#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */
|
||||
|
||||
/* extended flags */
|
||||
#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
|
||||
#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
|
||||
#define FNM_EXTMATCH (1 << 5) /* Use ksh-like extended matching. */
|
||||
|
||||
/* Value returned by `fnmatch' if STRING does not match PATTERN. */
|
||||
#define FNM_NOMATCH 1
|
||||
|
|
@ -33,4 +43,4 @@ Cambridge, MA 02139, USA. */
|
|||
returning zero if it matches, FNM_NOMATCH if not. */
|
||||
extern int fnmatch();
|
||||
|
||||
#endif /* fnmatch.h */
|
||||
#endif /* _FNMATCH_H */
|
||||
|
|
|
|||
287
lib/glob/glob.c
287
lib/glob/glob.c
|
|
@ -25,20 +25,29 @@
|
|||
#pragma alloca
|
||||
#endif /* _AIX && RISC6000 && !__GNUC__ */
|
||||
|
||||
#if defined (SHELL)
|
||||
# include "bashtypes.h"
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_STDLIB_H)
|
||||
# include <stdlib.h>
|
||||
#if defined (SHELL)
|
||||
# include "bashansi.h"
|
||||
#else
|
||||
# if defined (SHELL)
|
||||
# include "ansi_stdlib.h"
|
||||
# endif /* SHELL */
|
||||
# if defined (HAVE_STDLIB_H)
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
# if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
# else /* !HAVE_STRING_H */
|
||||
# include <strings.h>
|
||||
# endif /* !HAVE_STRING_H */
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined (HAVE_DIRENT_H)
|
||||
# include <dirent.h>
|
||||
# define D_NAMLEN(d) strlen ((d)->d_name)
|
||||
|
|
@ -66,27 +75,25 @@
|
|||
# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
|
||||
#endif /* _POSIX_SOURCE */
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#else /* !HAVE_STRING_H */
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRING_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. */
|
||||
#if defined (OPENDIR_NOT_ROBUST)
|
||||
# if defined (SHELL)
|
||||
# include "posixstat.h"
|
||||
# else /* !SHELL */
|
||||
# include <sys/stat.h>
|
||||
# endif /* !SHELL */
|
||||
#endif /* OPENDIR_NOT_ROBUST */
|
||||
#if defined (SHELL)
|
||||
# include "posixstat.h"
|
||||
#else /* !SHELL */
|
||||
# include <sys/stat.h>
|
||||
#endif /* !SHELL */
|
||||
|
||||
#include "filecntl.h"
|
||||
#if !defined (F_OK)
|
||||
# define F_OK 0
|
||||
#endif
|
||||
|
||||
#if defined (SHELL)
|
||||
# include "memalloc.h"
|
||||
#endif
|
||||
|
||||
#include "memalloc.h"
|
||||
#include "fnmatch.h"
|
||||
|
||||
#if !defined (HAVE_STDLIB_H) && !defined (SHELL)
|
||||
|
|
@ -104,14 +111,20 @@ extern void free ();
|
|||
|
||||
#if defined (SHELL)
|
||||
extern void throw_to_top_level ();
|
||||
extern int test_eaccess ();
|
||||
|
||||
extern int interrupt_state;
|
||||
extern int extended_glob;
|
||||
#endif /* SHELL */
|
||||
|
||||
/* Global variable which controls whether or not * matches .*.
|
||||
Non-zero means don't match .*. */
|
||||
int noglob_dot_filenames = 1;
|
||||
|
||||
/* Global variable which controls whether or not filename globbing
|
||||
is done without regard to case. */
|
||||
int glob_ignore_case = 0;
|
||||
|
||||
/* Global variable to return to signify an error in globbing. */
|
||||
char *glob_error_return;
|
||||
|
||||
|
|
@ -120,9 +133,12 @@ int
|
|||
glob_pattern_p (pattern)
|
||||
char *pattern;
|
||||
{
|
||||
register char *p = pattern;
|
||||
register char *p;
|
||||
register char c;
|
||||
int open = 0;
|
||||
int bopen;
|
||||
|
||||
p = pattern;
|
||||
bopen = 0;
|
||||
|
||||
while ((c = *p++) != '\0')
|
||||
switch (c)
|
||||
|
|
@ -132,13 +148,20 @@ glob_pattern_p (pattern)
|
|||
return (1);
|
||||
|
||||
case '[': /* Only accept an open brace if there is a close */
|
||||
open++; /* brace to match it. Bracket expressions must be */
|
||||
bopen++; /* brace to match it. Bracket expressions must be */
|
||||
continue; /* complete, according to Posix.2 */
|
||||
case ']':
|
||||
if (open)
|
||||
if (bopen)
|
||||
return (1);
|
||||
continue;
|
||||
|
||||
case '+': /* extended matching operators */
|
||||
case '@':
|
||||
case '!':
|
||||
if (*p == '(') /*) */
|
||||
return (1);
|
||||
continue;
|
||||
|
||||
case '\\':
|
||||
if (*p++ == '\0')
|
||||
return (0);
|
||||
|
|
@ -168,6 +191,35 @@ dequote_pathname (pathname)
|
|||
}
|
||||
|
||||
|
||||
|
||||
/* Test whether NAME exists. */
|
||||
|
||||
#if defined (HAVE_LSTAT)
|
||||
# define GLOB_TESTNAME(name) (lstat (name, &finfo))
|
||||
#else /* !HAVE_LSTAT */
|
||||
# if defined (SHELL) && !defined (AFS)
|
||||
# define GLOB_TESTNAME(name) (test_eaccess (nextname, F_OK))
|
||||
# else /* !SHELL || AFS */
|
||||
# define GLOB_TESTNAME(name) (access (nextname, F_OK))
|
||||
# endif /* !SHELL || AFS */
|
||||
#endif /* !HAVE_LSTAT */
|
||||
|
||||
/* Return 0 if DIR is a directory, -1 otherwise. */
|
||||
static int
|
||||
glob_testdir (dir)
|
||||
char *dir;
|
||||
{
|
||||
struct stat finfo;
|
||||
|
||||
if (stat (dir, &finfo) < 0)
|
||||
return (-1);
|
||||
|
||||
if (S_ISDIR (finfo.st_mode) == 0)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Return a vector of names of files in directory DIR
|
||||
whose names match glob pattern PAT.
|
||||
The names are not in any particular order.
|
||||
|
|
@ -204,103 +256,161 @@ glob_vector (pat, dir)
|
|||
int lose, skip;
|
||||
register char **name_vector;
|
||||
register unsigned int i;
|
||||
#if defined (OPENDIR_NOT_ROBUST)
|
||||
struct stat finfo;
|
||||
|
||||
if (stat (dir, &finfo) < 0)
|
||||
return ((char **) &glob_error_return);
|
||||
|
||||
if (!S_ISDIR (finfo.st_mode))
|
||||
return ((char **) &glob_error_return);
|
||||
#endif /* OPENDIR_NOT_ROBUST */
|
||||
|
||||
d = opendir (dir);
|
||||
if (d == NULL)
|
||||
return ((char **) &glob_error_return);
|
||||
int flags; /* Flags passed to fnmatch (). */
|
||||
|
||||
lastlink = 0;
|
||||
count = 0;
|
||||
lose = 0;
|
||||
skip = 0;
|
||||
count = lose = skip = 0;
|
||||
|
||||
/* If PAT is empty, skip the loop, but return one (empty) filename. */
|
||||
if (!pat || !*pat)
|
||||
if (pat == 0 || *pat == '\0')
|
||||
{
|
||||
if (glob_testdir (dir) < 0)
|
||||
return ((char **) &glob_error_return);
|
||||
|
||||
nextlink = (struct globval *)alloca (sizeof (struct globval));
|
||||
nextlink->next = lastlink;
|
||||
nextlink->next = (struct globval *)0;
|
||||
nextname = (char *) malloc (1);
|
||||
if (!nextname)
|
||||
if (nextname == 0)
|
||||
lose = 1;
|
||||
else
|
||||
{
|
||||
lastlink = nextlink;
|
||||
nextlink->name = nextname;
|
||||
nextname[0] = '\0';
|
||||
count++;
|
||||
count = 1;
|
||||
}
|
||||
|
||||
skip = 1;
|
||||
}
|
||||
|
||||
/* Scan the directory, finding all names that match.
|
||||
For each name that matches, allocate a struct globval
|
||||
on the stack and store the name in it.
|
||||
Chain those structs together; lastlink is the front of the chain. */
|
||||
while (!skip)
|
||||
/* If the filename pattern (PAT) does not contain any globbing characters,
|
||||
we can dispense with reading the directory, and just see if there is
|
||||
a filename `DIR/PAT'. If there is, and we can access it, just make the
|
||||
vector to return and bail immediately. */
|
||||
if (skip == 0 && glob_pattern_p (pat) == 0)
|
||||
{
|
||||
int flags; /* Flags passed to fnmatch (). */
|
||||
#if defined (SHELL)
|
||||
/* Make globbing interruptible in the bash shell. */
|
||||
if (interrupt_state)
|
||||
int dirlen;
|
||||
struct stat finfo;
|
||||
|
||||
if (glob_testdir (dir) < 0)
|
||||
return ((char **) &glob_error_return);
|
||||
|
||||
dirlen = strlen (dir);
|
||||
nextname = (char *)malloc (dirlen + strlen (pat) + 2);
|
||||
if (nextname == 0)
|
||||
lose = 1;
|
||||
else
|
||||
{
|
||||
closedir (d);
|
||||
lose = 1;
|
||||
goto lost;
|
||||
strcpy (nextname, dir);
|
||||
nextname[dirlen++] = '/';
|
||||
strcpy (nextname + dirlen, pat);
|
||||
|
||||
if (GLOB_TESTNAME (nextname) >= 0)
|
||||
{
|
||||
free (nextname);
|
||||
nextlink = (struct globval *)alloca (sizeof (struct globval));
|
||||
nextlink->next = (struct globval *)0;
|
||||
nextname = (char *) malloc (strlen (pat) + 1);
|
||||
if (nextname == 0)
|
||||
lose = 1;
|
||||
else
|
||||
{
|
||||
lastlink = nextlink;
|
||||
nextlink->name = nextname;
|
||||
strcpy (nextname, pat);
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
free (nextname);
|
||||
}
|
||||
#endif /* SHELL */
|
||||
|
||||
dp = readdir (d);
|
||||
if (dp == NULL)
|
||||
break;
|
||||
|
||||
/* If this directory entry is not to be used, try again. */
|
||||
if (!REAL_DIR_ENTRY (dp))
|
||||
continue;
|
||||
skip = 1;
|
||||
}
|
||||
|
||||
/* If a dot must be explicity matched, check to see if they do. */
|
||||
if (noglob_dot_filenames && dp->d_name[0] == '.' && pat[0] != '.' &&
|
||||
(pat[0] != '\\' || pat[1] != '.'))
|
||||
continue;
|
||||
if (skip == 0)
|
||||
{
|
||||
/* Open the directory, punting immediately if we cannot. If opendir
|
||||
is not robust (i.e., it opens non-directories successfully), test
|
||||
that DIR is a directory and punt if it's not. */
|
||||
#if defined (OPENDIR_NOT_ROBUST)
|
||||
if (glob_testdir (dir) < 0)
|
||||
return ((char **) &glob_error_return);
|
||||
#endif
|
||||
|
||||
d = opendir (dir);
|
||||
if (d == NULL)
|
||||
return ((char **) &glob_error_return);
|
||||
|
||||
/* Compute the flags that will be passed to fnmatch(). We don't
|
||||
need to do this every time through the loop. */
|
||||
flags = (noglob_dot_filenames ? FNM_PERIOD : 0) | FNM_PATHNAME;
|
||||
|
||||
if (fnmatch (pat, dp->d_name, flags) != FNM_NOMATCH)
|
||||
#ifdef FNM_CASEFOLD
|
||||
if (glob_ignore_case)
|
||||
flags |= FNM_CASEFOLD;
|
||||
#endif
|
||||
|
||||
#ifdef SHELL
|
||||
if (extended_glob)
|
||||
flags |= FNM_EXTMATCH;
|
||||
#endif
|
||||
|
||||
/* Scan the directory, finding all names that match.
|
||||
For each name that matches, allocate a struct globval
|
||||
on the stack and store the name in it.
|
||||
Chain those structs together; lastlink is the front of the chain. */
|
||||
while (1)
|
||||
{
|
||||
nextlink = (struct globval *) alloca (sizeof (struct globval));
|
||||
nextlink->next = lastlink;
|
||||
nextname = (char *) malloc (D_NAMLEN (dp) + 1);
|
||||
if (nextname == NULL)
|
||||
#if defined (SHELL)
|
||||
/* Make globbing interruptible in the shell. */
|
||||
if (interrupt_state)
|
||||
{
|
||||
lose = 1;
|
||||
break;
|
||||
}
|
||||
lastlink = nextlink;
|
||||
nextlink->name = nextname;
|
||||
bcopy (dp->d_name, nextname, D_NAMLEN (dp) + 1);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
(void) closedir (d);
|
||||
#endif /* SHELL */
|
||||
|
||||
dp = readdir (d);
|
||||
if (dp == NULL)
|
||||
break;
|
||||
|
||||
if (!lose)
|
||||
/* If this directory entry is not to be used, try again. */
|
||||
if (REAL_DIR_ENTRY (dp) == 0)
|
||||
continue;
|
||||
|
||||
/* If a dot must be explicity matched, check to see if they do. */
|
||||
if (noglob_dot_filenames && dp->d_name[0] == '.' && pat[0] != '.' &&
|
||||
(pat[0] != '\\' || pat[1] != '.'))
|
||||
continue;
|
||||
|
||||
if (fnmatch (pat, dp->d_name, flags) != FNM_NOMATCH)
|
||||
{
|
||||
nextlink = (struct globval *) alloca (sizeof (struct globval));
|
||||
nextlink->next = lastlink;
|
||||
nextname = (char *) malloc (D_NAMLEN (dp) + 1);
|
||||
if (nextname == NULL)
|
||||
{
|
||||
lose = 1;
|
||||
break;
|
||||
}
|
||||
lastlink = nextlink;
|
||||
nextlink->name = nextname;
|
||||
bcopy (dp->d_name, nextname, D_NAMLEN (dp) + 1);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
(void) closedir (d);
|
||||
}
|
||||
|
||||
if (lose == 0)
|
||||
{
|
||||
name_vector = (char **) malloc ((count + 1) * sizeof (char *));
|
||||
lose |= name_vector == NULL;
|
||||
}
|
||||
|
||||
/* Have we run out of memory? */
|
||||
#if defined (SHELL)
|
||||
lost:
|
||||
#endif
|
||||
if (lose)
|
||||
{
|
||||
/* Here free the strings we have got. */
|
||||
|
|
@ -313,7 +423,8 @@ glob_vector (pat, dir)
|
|||
if (interrupt_state)
|
||||
throw_to_top_level ();
|
||||
#endif /* SHELL */
|
||||
return (NULL);
|
||||
|
||||
return ((char **)NULL);
|
||||
}
|
||||
|
||||
/* Copy the name pointers from the linked list into the vector. */
|
||||
|
|
|
|||
|
|
@ -26,5 +26,6 @@ extern char **glob_filename __P((char *));
|
|||
|
||||
extern char *glob_error_return;
|
||||
extern int noglob_dot_filenames;
|
||||
extern int glob_ignore_case;
|
||||
|
||||
#endif /* _GLOB_H_ */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue