Bash-4.3 distribution sources and documentation
This commit is contained in:
parent
4539d736f1
commit
ac50fbac37
497 changed files with 129395 additions and 87598 deletions
347
lib/glob/glob.c
347
lib/glob/glob.c
|
|
@ -48,6 +48,8 @@
|
|||
#include "stdc.h"
|
||||
#include "memalloc.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
#include "glob.h"
|
||||
|
|
@ -84,6 +86,8 @@ struct globval
|
|||
extern void throw_to_top_level __P((void));
|
||||
extern int sh_eaccess __P((char *, int));
|
||||
extern char *sh_makepath __P((const char *, const char *, int));
|
||||
extern int signal_is_pending __P((int));
|
||||
extern void run_pending_traps __P((void));
|
||||
|
||||
extern int extended_glob;
|
||||
|
||||
|
|
@ -112,9 +116,13 @@ static void wdequote_pathname __P((char *));
|
|||
# define dequote_pathname udequote_pathname
|
||||
#endif
|
||||
static void dequote_pathname __P((char *));
|
||||
static int glob_testdir __P((char *));
|
||||
static int glob_testdir __P((char *, int));
|
||||
static char **glob_dir_to_array __P((char *, char **, int));
|
||||
|
||||
/* Make sure these names continue to agree with what's in smatch.c */
|
||||
extern char *glob_patscan __P((char *, char *, int));
|
||||
extern wchar_t *glob_patscan_wc __P((wchar_t *, wchar_t *, int));
|
||||
|
||||
/* Compile `glob_loop.c' for single-byte characters. */
|
||||
#define CHAR unsigned char
|
||||
#define INT int
|
||||
|
|
@ -162,15 +170,67 @@ glob_pattern_p (pattern)
|
|||
#endif
|
||||
}
|
||||
|
||||
#if EXTENDED_GLOB
|
||||
/* Return 1 if all subpatterns in the extended globbing pattern PAT indicate
|
||||
that the name should be skipped. XXX - doesn't handle pattern negation,
|
||||
not sure if it should */
|
||||
static int
|
||||
extglob_skipname (pat, dname, flags)
|
||||
char *pat, *dname;
|
||||
int flags;
|
||||
{
|
||||
char *pp, *pe, *t;
|
||||
int n, r;
|
||||
|
||||
pp = pat + 2;
|
||||
pe = pp + strlen (pp) - 1; /*(*/
|
||||
if (*pe != ')')
|
||||
return 0;
|
||||
if ((t = strchr (pp, '|')) == 0) /* easy case first */
|
||||
{
|
||||
*pe = '\0';
|
||||
r = skipname (pp, dname, flags); /*(*/
|
||||
*pe = ')';
|
||||
return r;
|
||||
}
|
||||
while (t = glob_patscan (pp, pe, '|'))
|
||||
{
|
||||
n = t[-1];
|
||||
t[-1] = '\0';
|
||||
r = skipname (pp, dname, flags);
|
||||
t[-1] = n;
|
||||
if (r == 0) /* if any pattern says not skip, we don't skip */
|
||||
return r;
|
||||
pp = t;
|
||||
} /*(*/
|
||||
|
||||
if (pp == pe) /* glob_patscan might find end of pattern */
|
||||
return r;
|
||||
|
||||
*pe = '\0';
|
||||
# if defined (HANDLE_MULTIBYTE)
|
||||
r = mbskipname (pp, dname, flags); /*(*/
|
||||
# else
|
||||
r = skipname (pp, dname, flags); /*(*/
|
||||
# endif
|
||||
*pe = ')';
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return 1 if DNAME should be skipped according to PAT. Mostly concerned
|
||||
with matching leading `.'. */
|
||||
|
||||
static int
|
||||
skipname (pat, dname, flags)
|
||||
char *pat;
|
||||
char *dname;
|
||||
int flags;
|
||||
{
|
||||
#if EXTENDED_GLOB
|
||||
if (extglob_pattern_p (pat)) /* XXX */
|
||||
return (extglob_skipname (pat, dname, flags));
|
||||
#endif
|
||||
|
||||
/* If a leading dot need not be explicitly matched, and the pattern
|
||||
doesn't start with a `.', don't match `.' or `..' */
|
||||
if (noglob_dot_filenames == 0 && pat[0] != '.' &&
|
||||
|
|
@ -179,7 +239,7 @@ skipname (pat, dname, flags)
|
|||
(dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0'))))
|
||||
return 1;
|
||||
|
||||
/* If a dot must be explicity matched, check to see if they do. */
|
||||
/* If a dot must be explicitly matched, check to see if they do. */
|
||||
else if (noglob_dot_filenames && dname[0] == '.' && pat[0] != '.' &&
|
||||
(pat[0] != '\\' || pat[1] != '.'))
|
||||
return 1;
|
||||
|
|
@ -188,18 +248,91 @@ skipname (pat, dname, flags)
|
|||
}
|
||||
|
||||
#if HANDLE_MULTIBYTE
|
||||
|
||||
static int
|
||||
wchkname (pat_wc, dn_wc)
|
||||
wchar_t *pat_wc, *dn_wc;
|
||||
{
|
||||
/* If a leading dot need not be explicitly matched, and the
|
||||
pattern doesn't start with a `.', don't match `.' or `..' */
|
||||
if (noglob_dot_filenames == 0 && pat_wc[0] != L'.' &&
|
||||
(pat_wc[0] != L'\\' || pat_wc[1] != L'.') &&
|
||||
(dn_wc[0] == L'.' &&
|
||||
(dn_wc[1] == L'\0' || (dn_wc[1] == L'.' && dn_wc[2] == L'\0'))))
|
||||
return 1;
|
||||
|
||||
/* If a leading dot must be explicitly matched, check to see if the
|
||||
pattern and dirname both have one. */
|
||||
else if (noglob_dot_filenames && dn_wc[0] == L'.' &&
|
||||
pat_wc[0] != L'.' &&
|
||||
(pat_wc[0] != L'\\' || pat_wc[1] != L'.'))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
wextglob_skipname (pat, dname, flags)
|
||||
wchar_t *pat, *dname;
|
||||
int flags;
|
||||
{
|
||||
#if EXTENDED_GLOB
|
||||
wchar_t *pp, *pe, *t, n;
|
||||
int r;
|
||||
|
||||
pp = pat + 2;
|
||||
pe = pp + wcslen (pp) - 1; /*(*/
|
||||
if (*pe != L')')
|
||||
return 0;
|
||||
if ((t = wcschr (pp, L'|')) == 0)
|
||||
{
|
||||
*pe = L'\0';
|
||||
r = wchkname (pp, dname); /*(*/
|
||||
*pe = L')';
|
||||
return r;
|
||||
}
|
||||
while (t = glob_patscan_wc (pp, pe, '|'))
|
||||
{
|
||||
n = t[-1];
|
||||
t[-1] = L'\0';
|
||||
r = wchkname (pp, dname);
|
||||
t[-1] = n;
|
||||
if (r == 0)
|
||||
return 0;
|
||||
pp = t;
|
||||
}
|
||||
|
||||
if (pp == pe) /* glob_patscan_wc might find end of pattern */
|
||||
return r;
|
||||
|
||||
*pe = L'\0';
|
||||
r = wchkname (pp, dname); /*(*/
|
||||
*pe = L')';
|
||||
return r;
|
||||
#else
|
||||
return (wchkname (pat, dname));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return 1 if DNAME should be skipped according to PAT. Handles multibyte
|
||||
characters in PAT and DNAME. Mostly concerned with matching leading `.'. */
|
||||
|
||||
static int
|
||||
mbskipname (pat, dname, flags)
|
||||
char *pat, *dname;
|
||||
int flags;
|
||||
{
|
||||
int ret;
|
||||
int ret, ext;
|
||||
wchar_t *pat_wc, *dn_wc;
|
||||
size_t pat_n, dn_n;
|
||||
|
||||
if (mbsmbchar (dname) == 0 && mbsmbchar (pat) == 0)
|
||||
return (skipname (pat, dname, flags));
|
||||
|
||||
ext = 0;
|
||||
#if EXTENDED_GLOB
|
||||
ext = extglob_pattern_p (pat);
|
||||
#endif
|
||||
|
||||
pat_wc = dn_wc = (wchar_t *)NULL;
|
||||
|
||||
pat_n = xdupmbstowcs (&pat_wc, NULL, pat);
|
||||
|
|
@ -208,22 +341,7 @@ mbskipname (pat, dname, flags)
|
|||
|
||||
ret = 0;
|
||||
if (pat_n != (size_t)-1 && dn_n !=(size_t)-1)
|
||||
{
|
||||
/* If a leading dot need not be explicitly matched, and the
|
||||
pattern doesn't start with a `.', don't match `.' or `..' */
|
||||
if (noglob_dot_filenames == 0 && pat_wc[0] != L'.' &&
|
||||
(pat_wc[0] != L'\\' || pat_wc[1] != L'.') &&
|
||||
(dn_wc[0] == L'.' &&
|
||||
(dn_wc[1] == L'\0' || (dn_wc[1] == L'.' && dn_wc[2] == L'\0'))))
|
||||
ret = 1;
|
||||
|
||||
/* If a leading dot must be explicity matched, check to see if the
|
||||
pattern and dirname both have one. */
|
||||
else if (noglob_dot_filenames && dn_wc[0] == L'.' &&
|
||||
pat_wc[0] != L'.' &&
|
||||
(pat_wc[0] != L'\\' || pat_wc[1] != L'.'))
|
||||
ret = 1;
|
||||
}
|
||||
ret = ext ? wextglob_skipname (pat_wc, dn_wc, flags) : wchkname (pat_wc, dn_wc);
|
||||
else
|
||||
ret = skipname (pat, dname, flags);
|
||||
|
||||
|
|
@ -325,13 +443,20 @@ dequote_pathname (pathname)
|
|||
|
||||
/* Return 0 if DIR is a directory, -1 otherwise. */
|
||||
static int
|
||||
glob_testdir (dir)
|
||||
glob_testdir (dir, flags)
|
||||
char *dir;
|
||||
int flags;
|
||||
{
|
||||
struct stat finfo;
|
||||
int r;
|
||||
|
||||
/*itrace("glob_testdir: testing %s", dir);*/
|
||||
if (stat (dir, &finfo) < 0)
|
||||
/*itrace("glob_testdir: testing %s" flags = %d, dir, flags);*/
|
||||
#if defined (HAVE_LSTAT)
|
||||
r = (flags & GX_ALLDIRS) ? lstat (dir, &finfo) : stat (dir, &finfo);
|
||||
#else
|
||||
r = stat (dir, &finfo);
|
||||
#endif
|
||||
if (r < 0)
|
||||
return (-1);
|
||||
|
||||
if (S_ISDIR (finfo.st_mode) == 0)
|
||||
|
|
@ -407,7 +532,6 @@ finddirs (pat, sdir, flags, ep, np)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Return a vector of names of files in directory DIR
|
||||
whose names match glob pattern PAT.
|
||||
|
|
@ -456,7 +580,7 @@ glob_vector (pat, dir, flags)
|
|||
/* If PAT is empty, skip the loop, but return one (empty) filename. */
|
||||
if (pat == 0 || *pat == '\0')
|
||||
{
|
||||
if (glob_testdir (dir) < 0)
|
||||
if (glob_testdir (dir, 0) < 0)
|
||||
return ((char **) &glob_error_return);
|
||||
|
||||
nextlink = (struct globval *)alloca (sizeof (struct globval));
|
||||
|
|
@ -478,7 +602,7 @@ glob_vector (pat, dir, flags)
|
|||
skip = 1;
|
||||
}
|
||||
|
||||
patlen = strlen (pat);
|
||||
patlen = (pat && *pat) ? strlen (pat) : 0;
|
||||
|
||||
/* If the filename pattern (PAT) does not contain any globbing characters,
|
||||
we can dispense with reading the directory, and just see if there is
|
||||
|
|
@ -489,14 +613,18 @@ glob_vector (pat, dir, flags)
|
|||
int dirlen;
|
||||
struct stat finfo;
|
||||
|
||||
if (glob_testdir (dir) < 0)
|
||||
if (glob_testdir (dir, 0) < 0)
|
||||
return ((char **) &glob_error_return);
|
||||
|
||||
dirlen = strlen (dir);
|
||||
nextname = (char *)malloc (dirlen + patlen + 2);
|
||||
npat = (char *)malloc (patlen + 1);
|
||||
if (nextname == 0 || npat == 0)
|
||||
lose = 1;
|
||||
{
|
||||
FREE (nextname);
|
||||
FREE (npat);
|
||||
lose = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy (npat, pat);
|
||||
|
|
@ -518,7 +646,10 @@ glob_vector (pat, dir, flags)
|
|||
count = 1;
|
||||
}
|
||||
else
|
||||
lose = 1;
|
||||
{
|
||||
free (npat);
|
||||
lose = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -536,7 +667,7 @@ glob_vector (pat, dir, flags)
|
|||
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)
|
||||
if (glob_testdir (dir, 0) < 0)
|
||||
return ((char **) &glob_error_return);
|
||||
#endif
|
||||
|
||||
|
|
@ -570,7 +701,12 @@ glob_vector (pat, dir, flags)
|
|||
lose = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
else if (signal_is_pending (SIGINT)) /* XXX - make SIGINT traps responsive */
|
||||
{
|
||||
lose = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
dp = readdir (d);
|
||||
if (dp == NULL)
|
||||
break;
|
||||
|
|
@ -599,7 +735,7 @@ glob_vector (pat, dir, flags)
|
|||
if (flags & GX_NULLDIR)
|
||||
pflags |= MP_IGNDOT;
|
||||
subdir = sh_makepath (dir, dp->d_name, pflags);
|
||||
isdir = glob_testdir (subdir);
|
||||
isdir = glob_testdir (subdir, flags);
|
||||
if (isdir < 0 && (flags & GX_MATCHDIRS))
|
||||
{
|
||||
free (subdir);
|
||||
|
|
@ -635,6 +771,8 @@ glob_vector (pat, dir, flags)
|
|||
nextname = (char *) malloc (sdlen + 1);
|
||||
if (nextlink == 0 || nextname == 0)
|
||||
{
|
||||
FREE (nextlink);
|
||||
FREE (nextname);
|
||||
free (subdir);
|
||||
lose = 1;
|
||||
break;
|
||||
|
|
@ -647,6 +785,8 @@ glob_vector (pat, dir, flags)
|
|||
++count;
|
||||
continue;
|
||||
}
|
||||
else if (flags & GX_MATCHDIRS)
|
||||
free (subdir);
|
||||
|
||||
convfn = fnx_fromfs (dp->d_name, D_NAMLEN (dp));
|
||||
if (strmatch (pat, convfn, mflags) != FNM_NOMATCH)
|
||||
|
|
@ -666,6 +806,8 @@ glob_vector (pat, dir, flags)
|
|||
nextname = (char *) malloc (D_NAMLEN (dp) + 1);
|
||||
if (nextlink == 0 || nextname == 0)
|
||||
{
|
||||
FREE (nextlink);
|
||||
FREE (nextname);
|
||||
lose = 1;
|
||||
break;
|
||||
}
|
||||
|
|
@ -689,7 +831,11 @@ glob_vector (pat, dir, flags)
|
|||
nextname = (char *)malloc (sdlen + 1);
|
||||
nextlink = (struct globval *) malloc (sizeof (struct globval));
|
||||
if (nextlink == 0 || nextname == 0)
|
||||
lose = 1;
|
||||
{
|
||||
FREE (nextlink);
|
||||
FREE (nextname);
|
||||
lose = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextlink->name = nextname;
|
||||
|
|
@ -733,7 +879,7 @@ glob_vector (pat, dir, flags)
|
|||
FREE (tmplink);
|
||||
}
|
||||
|
||||
QUIT;
|
||||
/* Don't call QUIT; here; let higher layers deal with it. */
|
||||
|
||||
return ((char **)NULL);
|
||||
}
|
||||
|
|
@ -815,7 +961,13 @@ glob_dir_to_array (dir, array, flags)
|
|||
result[i] = (char *) malloc (l + strlen (array[i]) + 3);
|
||||
|
||||
if (result[i] == NULL)
|
||||
return (NULL);
|
||||
{
|
||||
int ind;
|
||||
for (ind = 0; ind < i; ind++)
|
||||
free (result[ind]);
|
||||
free (result);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
strcpy (result[i], dir);
|
||||
if (add_slash)
|
||||
|
|
@ -893,19 +1045,70 @@ glob_filename (pathname, flags)
|
|||
|
||||
/* If directory_name contains globbing characters, then we
|
||||
have to expand the previous levels. Just recurse. */
|
||||
if (glob_pattern_p (directory_name))
|
||||
if (directory_len > 0 && glob_pattern_p (directory_name))
|
||||
{
|
||||
char **directories;
|
||||
char **directories, *d, *p;
|
||||
register unsigned int i;
|
||||
int all_starstar, last_starstar;
|
||||
|
||||
all_starstar = last_starstar = 0;
|
||||
d = directory_name;
|
||||
dflags = flags & ~GX_MARKDIRS;
|
||||
if ((flags & GX_GLOBSTAR) && directory_name[0] == '*' && directory_name[1] == '*' && (directory_name[2] == '/' || directory_name[2] == '\0'))
|
||||
dflags |= GX_ALLDIRS|GX_ADDCURDIR;
|
||||
/* Collapse a sequence of ** patterns separated by one or more slashes
|
||||
to a single ** terminated by a slash or NUL */
|
||||
if ((flags & GX_GLOBSTAR) && d[0] == '*' && d[1] == '*' && (d[2] == '/' || d[2] == '\0'))
|
||||
{
|
||||
p = d;
|
||||
while (d[0] == '*' && d[1] == '*' && (d[2] == '/' || d[2] == '\0'))
|
||||
{
|
||||
p = d;
|
||||
if (d[2])
|
||||
{
|
||||
d += 3;
|
||||
while (*d == '/')
|
||||
d++;
|
||||
if (*d == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*d == 0)
|
||||
all_starstar = 1;
|
||||
d = p;
|
||||
dflags |= GX_ALLDIRS|GX_ADDCURDIR;
|
||||
directory_len = strlen (d);
|
||||
}
|
||||
|
||||
if (directory_name[directory_len - 1] == '/')
|
||||
directory_name[directory_len - 1] = '\0';
|
||||
/* If there is a non [star][star]/ component in directory_name, we
|
||||
still need to collapse trailing sequences of [star][star]/ into
|
||||
a single one and note that the directory name ends with [star][star],
|
||||
so we can compensate if filename is [star][star] */
|
||||
if ((flags & GX_GLOBSTAR) && all_starstar == 0)
|
||||
{
|
||||
int dl, prev;
|
||||
prev = dl = directory_len;
|
||||
while (dl >= 4 && d[dl - 1] == '/' &&
|
||||
d[dl - 2] == '*' &&
|
||||
d[dl - 3] == '*' &&
|
||||
d[dl - 4] == '/')
|
||||
prev = dl, dl -= 3;
|
||||
if (dl != directory_len)
|
||||
last_starstar = 1;
|
||||
directory_len = prev;
|
||||
}
|
||||
|
||||
directories = glob_filename (directory_name, dflags);
|
||||
/* If the directory name ends in [star][star]/ but the filename is
|
||||
[star][star], just remove the final [star][star] from the directory
|
||||
so we don't have to scan everything twice. */
|
||||
if (last_starstar && directory_len > 4 &&
|
||||
filename[0] == '*' && filename[1] == '*' && filename[2] == 0)
|
||||
{
|
||||
directory_len -= 3;
|
||||
}
|
||||
|
||||
if (d[directory_len - 1] == '/')
|
||||
d[directory_len - 1] = '\0';
|
||||
|
||||
directories = glob_filename (d, dflags);
|
||||
|
||||
if (free_dirname)
|
||||
{
|
||||
|
|
@ -927,13 +1130,26 @@ glob_filename (pathname, flags)
|
|||
return ((char **) &glob_error_return);
|
||||
}
|
||||
|
||||
/* If we have something like [star][star]/[star][star], it's no use to
|
||||
glob **, then do it again, and throw half the results away. */
|
||||
if (all_starstar && filename[0] == '*' && filename[1] == '*' && filename[2] == 0)
|
||||
{
|
||||
free ((char *) directories);
|
||||
free (directory_name);
|
||||
directory_name = NULL;
|
||||
directory_len = 0;
|
||||
goto only_filename;
|
||||
}
|
||||
|
||||
/* We have successfully globbed the preceding directory name.
|
||||
For each name in DIRECTORIES, call glob_vector on it and
|
||||
FILENAME. Concatenate the results together. */
|
||||
for (i = 0; directories[i] != NULL; ++i)
|
||||
{
|
||||
char **temp_results;
|
||||
int shouldbreak;
|
||||
|
||||
shouldbreak = 0;
|
||||
/* XXX -- we've recursively scanned any directories resulting from
|
||||
a `**', so turn off the flag. We turn it on again below if
|
||||
filename is `**' */
|
||||
|
|
@ -964,8 +1180,39 @@ glob_filename (pathname, flags)
|
|||
|
||||
/* If we're expanding **, we don't need to glue the directory
|
||||
name to the results; we've already done it in glob_vector */
|
||||
if ((dflags & GX_ALLDIRS) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0')
|
||||
array = temp_results;
|
||||
if ((dflags & GX_ALLDIRS) && filename[0] == '*' && filename[1] == '*' && (filename[2] == '\0' || filename[2] == '/'))
|
||||
{
|
||||
/* When do we remove null elements from temp_results? And
|
||||
how to avoid duplicate elements in the final result? */
|
||||
/* If (dflags & GX_NULLDIR) glob_filename potentially left a
|
||||
NULL placeholder in the temp results just in case
|
||||
glob_vector/glob_dir_to_array did something with it, but
|
||||
if it didn't, and we're not supposed to be passing them
|
||||
through for some reason ((flags & GX_NULLDIR) == 0) we
|
||||
need to remove all the NULL elements from the beginning
|
||||
of TEMP_RESULTS. */
|
||||
/* If we have a null directory name and ** as the filename,
|
||||
we have just searched for everything from the current
|
||||
directory on down. Break now (shouldbreak = 1) to avoid
|
||||
duplicate entries in the final result. */
|
||||
#define NULL_PLACEHOLDER(x) ((x) && *(x) && **(x) == 0)
|
||||
if ((dflags & GX_NULLDIR) && (flags & GX_NULLDIR) == 0 &&
|
||||
NULL_PLACEHOLDER (temp_results))
|
||||
#undef NULL_PLACEHOLDER
|
||||
{
|
||||
register int i, n;
|
||||
for (n = 0; temp_results[n] && *temp_results[n] == 0; n++)
|
||||
;
|
||||
i = n;
|
||||
do
|
||||
temp_results[i - n] = temp_results[i];
|
||||
while (temp_results[i++] != 0);
|
||||
array = temp_results;
|
||||
shouldbreak = 1;
|
||||
}
|
||||
else
|
||||
array = temp_results;
|
||||
}
|
||||
else
|
||||
array = glob_dir_to_array (directories[i], temp_results, flags);
|
||||
l = 0;
|
||||
|
|
@ -986,6 +1233,11 @@ glob_filename (pathname, flags)
|
|||
/* Note that the elements of ARRAY are not freed. */
|
||||
if (array != temp_results)
|
||||
free ((char *) array);
|
||||
else if ((dflags & GX_ALLDIRS) && filename[0] == '*' && filename[1] == '*' && filename[2] == '\0')
|
||||
free (temp_results); /* expanding ** case above */
|
||||
|
||||
if (shouldbreak)
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Free the directories. */
|
||||
|
|
@ -997,6 +1249,7 @@ glob_filename (pathname, flags)
|
|||
return (result);
|
||||
}
|
||||
|
||||
only_filename:
|
||||
/* If there is only a directory name, return it. */
|
||||
if (*filename == '\0')
|
||||
{
|
||||
|
|
@ -1055,10 +1308,13 @@ glob_filename (pathname, flags)
|
|||
{
|
||||
if (free_dirname)
|
||||
free (directory_name);
|
||||
QUIT; /* XXX - shell */
|
||||
run_pending_traps ();
|
||||
return (temp_results);
|
||||
}
|
||||
|
||||
result = glob_dir_to_array ((dflags & GX_ALLDIRS) ? "" : directory_name, temp_results, flags);
|
||||
|
||||
if (free_dirname)
|
||||
free (directory_name);
|
||||
return (result);
|
||||
|
|
@ -1079,6 +1335,7 @@ glob_filename (pathname, flags)
|
|||
free (directory_name);
|
||||
|
||||
QUIT;
|
||||
run_pending_traps ();
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ extern int glob_pattern_p __P((const char *));
|
|||
extern char **glob_vector __P((char *, char *, int));
|
||||
extern char **glob_filename __P((char *, int));
|
||||
|
||||
extern int extglob_pattern_p __P((const char *));
|
||||
|
||||
extern char *glob_error_return;
|
||||
extern int noglob_dot_filenames;
|
||||
extern int glob_ignore_case;
|
||||
|
|
|
|||
|
|
@ -200,6 +200,24 @@ bad_bracket:
|
|||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
extglob_pattern_p (pat)
|
||||
char *pat;
|
||||
{
|
||||
switch (pat[0])
|
||||
{
|
||||
case '*':
|
||||
case '+':
|
||||
case '!':
|
||||
case '@':
|
||||
return (pat[1] == LPAREN);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return 1 of the first character of STRING could match the first
|
||||
character of pattern PAT. Used to avoid n2 calls to strmatch(). */
|
||||
int
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 1991-2006 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1991-2011 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
|
|
@ -22,7 +22,8 @@ static int GMATCH __P((CHAR *, CHAR *, CHAR *, CHAR *, int));
|
|||
static CHAR *PARSE_COLLSYM __P((CHAR *, INT *));
|
||||
static CHAR *BRACKMATCH __P((CHAR *, U_CHAR, int));
|
||||
static int EXTMATCH __P((INT, CHAR *, CHAR *, CHAR *, CHAR *, int));
|
||||
static CHAR *PATSCAN __P((CHAR *, CHAR *, INT));
|
||||
|
||||
/*static*/ CHAR *PATSCAN __P((CHAR *, CHAR *, INT));
|
||||
|
||||
int
|
||||
FCT (pattern, string, flags)
|
||||
|
|
@ -144,8 +145,9 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
|
|||
if (EXTMATCH (c, newn, se, p, pe, flags) == 0)
|
||||
return (0);
|
||||
}
|
||||
/* We didn't match. If we have a `?(...)', that's failure. */
|
||||
return FNM_NOMATCH;
|
||||
/* We didn't match. If we have a `?(...)', we can match 0
|
||||
or 1 times. */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
else if (c == L('?'))
|
||||
|
|
@ -191,6 +193,18 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
|
|||
if (p == pe && (c == L('?') || c == L('*')))
|
||||
return (0);
|
||||
|
||||
/* If we've hit the end of the string and the rest of the pattern
|
||||
is something that matches the empty string, we can succeed. */
|
||||
#if defined (EXTENDED_GLOB)
|
||||
if (n == se && ((flags & FNM_EXTMATCH) && (c == L('!') || c == L('?')) && *p == L('(')))
|
||||
{
|
||||
--p;
|
||||
if (EXTMATCH (c, n, se, p, pe, flags) == 0)
|
||||
return (c == L('!') ? FNM_NOMATCH : 0);
|
||||
return (c == L('!') ? 0 : FNM_NOMATCH);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* General case, use recursion. */
|
||||
{
|
||||
U_CHAR c1;
|
||||
|
|
@ -290,7 +304,7 @@ BRACKMATCH (p, test, flags)
|
|||
{
|
||||
register CHAR cstart, cend, c;
|
||||
register int not; /* Nonzero if the sense of the character class is inverted. */
|
||||
int brcnt;
|
||||
int brcnt, forcecoll;
|
||||
INT pc;
|
||||
CHAR *savep;
|
||||
|
||||
|
|
@ -311,6 +325,7 @@ BRACKMATCH (p, test, flags)
|
|||
/* Initialize cstart and cend in case `-' is the last
|
||||
character of the pattern. */
|
||||
cstart = cend = c;
|
||||
forcecoll = 0;
|
||||
|
||||
/* POSIX.2 equivalence class: [=c=]. See POSIX.2 2.8.3.2. Find
|
||||
the end of the equivalence class, move the pattern pointer past
|
||||
|
|
@ -400,6 +415,7 @@ BRACKMATCH (p, test, flags)
|
|||
range. If it is, we set cstart to one greater than `test',
|
||||
so any comparisons later will fail. */
|
||||
cstart = (pc == INVALID) ? test + 1 : pc;
|
||||
forcecoll = 1;
|
||||
}
|
||||
|
||||
if (!(flags & FNM_NOESCAPE) && c == L('\\'))
|
||||
|
|
@ -443,6 +459,7 @@ BRACKMATCH (p, test, flags)
|
|||
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 == INVALID) ? test - 1 : pc;
|
||||
forcecoll = 1;
|
||||
}
|
||||
cend = FOLD (cend);
|
||||
|
||||
|
|
@ -453,7 +470,7 @@ BRACKMATCH (p, test, flags)
|
|||
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 (RANGECMP (cstart, cend, forcecoll) > 0)
|
||||
{
|
||||
if (c == L(']'))
|
||||
break;
|
||||
|
|
@ -462,7 +479,7 @@ BRACKMATCH (p, test, flags)
|
|||
}
|
||||
}
|
||||
|
||||
if (RANGECMP (test, cstart) >= 0 && RANGECMP (test, cend) <= 0)
|
||||
if (RANGECMP (test, cstart, forcecoll) >= 0 && RANGECMP (test, cend, forcecoll) <= 0)
|
||||
goto matched;
|
||||
|
||||
if (c == L(']'))
|
||||
|
|
@ -517,7 +534,7 @@ matched:
|
|||
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 *
|
||||
/*static*/ CHAR *
|
||||
PATSCAN (string, end, delim)
|
||||
CHAR *string, *end;
|
||||
INT delim;
|
||||
|
|
@ -530,6 +547,9 @@ PATSCAN (string, end, delim)
|
|||
cchar = 0;
|
||||
bfirst = NULL;
|
||||
|
||||
if (string == end)
|
||||
return (NULL);
|
||||
|
||||
for (s = string; c = *s; s++)
|
||||
{
|
||||
if (s >= end)
|
||||
|
|
@ -606,19 +626,32 @@ STRCOMPARE (p, pe, s, se)
|
|||
{
|
||||
int ret;
|
||||
CHAR c1, c2;
|
||||
int l1, l2;
|
||||
|
||||
l1 = pe - p;
|
||||
l2 = se - s;
|
||||
|
||||
if (l1 != l2)
|
||||
return (FNM_NOMATCH); /* unequal lengths, can't be identical */
|
||||
|
||||
c1 = *pe;
|
||||
c2 = *se;
|
||||
|
||||
*pe = *se = '\0';
|
||||
if (c1 != 0)
|
||||
*pe = '\0';
|
||||
if (c2 != 0)
|
||||
*se = '\0';
|
||||
|
||||
#if HAVE_MULTIBYTE || defined (HAVE_STRCOLL)
|
||||
ret = STRCOLL ((XCHAR *)p, (XCHAR *)s);
|
||||
#else
|
||||
ret = STRCMP ((XCHAR *)p, (XCHAR *)s);
|
||||
#endif
|
||||
|
||||
*pe = c1;
|
||||
*se = c2;
|
||||
if (c1 != 0)
|
||||
*pe = c1;
|
||||
if (c2 != 0)
|
||||
*se = c2;
|
||||
|
||||
return (ret == 0 ? ret : FNM_NOMATCH);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,15 +43,25 @@
|
|||
#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)
|
||||
|
||||
#ifndef GLOBASCII_DEFAULT
|
||||
# define GLOBASCII_DEFAULT 0
|
||||
#endif
|
||||
|
||||
int glob_asciirange = GLOBASCII_DEFAULT;
|
||||
|
||||
/* We use strcoll(3) for range comparisons in bracket expressions,
|
||||
even though it can have unwanted side effects in locales
|
||||
other than POSIX or US. For instance, in the de locale, [A-Z] matches
|
||||
all characters. */
|
||||
all characters. If GLOB_ASCIIRANGE is non-zero, and we're not forcing
|
||||
the use of strcoll (e.g., for explicit collating symbols), we use
|
||||
straight ordering as if in the C locale. */
|
||||
|
||||
#if defined (HAVE_STRCOLL)
|
||||
/* Helper function for collating symbol equivalence. */
|
||||
static int rangecmp (c1, c2)
|
||||
static int
|
||||
rangecmp (c1, c2, forcecoll)
|
||||
int c1, c2;
|
||||
int forcecoll;
|
||||
{
|
||||
static char s1[2] = { ' ', '\0' };
|
||||
static char s2[2] = { ' ', '\0' };
|
||||
|
|
@ -64,6 +74,9 @@ static int rangecmp (c1, c2)
|
|||
if (c1 == c2)
|
||||
return (0);
|
||||
|
||||
if (forcecoll == 0 && glob_asciirange)
|
||||
return (c1 - c2);
|
||||
|
||||
s1[0] = c1;
|
||||
s2[0] = c2;
|
||||
|
||||
|
|
@ -72,7 +85,7 @@ static int rangecmp (c1, c2)
|
|||
return (c1 - c2);
|
||||
}
|
||||
#else /* !HAVE_STRCOLL */
|
||||
# define rangecmp(c1, c2) ((int)(c1) - (int)(c2))
|
||||
# define rangecmp(c1, c2, f) ((int)(c1) - (int)(c2))
|
||||
#endif /* !HAVE_STRCOLL */
|
||||
|
||||
#if defined (HAVE_STRCOLL)
|
||||
|
|
@ -80,7 +93,7 @@ static int
|
|||
collequiv (c1, c2)
|
||||
int c1, c2;
|
||||
{
|
||||
return (rangecmp (c1, c2) == 0);
|
||||
return (rangecmp (c1, c2, 1) == 0);
|
||||
}
|
||||
#else
|
||||
# define collequiv(c1, c2) ((c1) == (c2))
|
||||
|
|
@ -214,14 +227,14 @@ is_cclass (c, name)
|
|||
#define COLLSYM collsym
|
||||
#define PARSE_COLLSYM parse_collsym
|
||||
#define BRACKMATCH brackmatch
|
||||
#define PATSCAN patscan
|
||||
#define PATSCAN glob_patscan
|
||||
#define STRCOMPARE strcompare
|
||||
#define EXTMATCH extmatch
|
||||
#define STRCHR(S, C) strchr((S), (C))
|
||||
#define STRCOLL(S1, S2) strcoll((S1), (S2))
|
||||
#define STRLEN(S) strlen(S)
|
||||
#define STRCMP(S1, S2) strcmp((S1), (S2))
|
||||
#define RANGECMP(C1, C2) rangecmp((C1), (C2))
|
||||
#define RANGECMP(C1, C2, F) rangecmp((C1), (C2), (F))
|
||||
#define COLLEQUIV(C1, C2) collequiv((C1), (C2))
|
||||
#define CTYPE_T enum char_class
|
||||
#define IS_CCLASS(C, S) is_cclass((C), (S))
|
||||
|
|
@ -244,8 +257,9 @@ is_cclass (c, name)
|
|||
extern char *mbsmbchar __P((const char *));
|
||||
|
||||
static int
|
||||
rangecmp_wc (c1, c2)
|
||||
rangecmp_wc (c1, c2, forcecoll)
|
||||
wint_t c1, c2;
|
||||
int forcecoll;
|
||||
{
|
||||
static wchar_t s1[2] = { L' ', L'\0' };
|
||||
static wchar_t s2[2] = { L' ', L'\0' };
|
||||
|
|
@ -253,6 +267,9 @@ rangecmp_wc (c1, c2)
|
|||
if (c1 == c2)
|
||||
return 0;
|
||||
|
||||
if (forcecoll == 0 && glob_asciirange && c1 <= UCHAR_MAX && c2 <= UCHAR_MAX)
|
||||
return ((int)(c1 - c2));
|
||||
|
||||
s1[0] = c1;
|
||||
s2[0] = c2;
|
||||
|
||||
|
|
@ -263,7 +280,7 @@ static int
|
|||
collequiv_wc (c, equiv)
|
||||
wint_t c, equiv;
|
||||
{
|
||||
return (!(c - equiv));
|
||||
return (c == equiv);
|
||||
}
|
||||
|
||||
/* Helper function for collating symbol. */
|
||||
|
|
@ -342,14 +359,14 @@ is_wcclass (wc, name)
|
|||
#define COLLSYM collwcsym
|
||||
#define PARSE_COLLSYM parse_collwcsym
|
||||
#define BRACKMATCH brackmatch_wc
|
||||
#define PATSCAN patscan_wc
|
||||
#define PATSCAN glob_patscan_wc
|
||||
#define STRCOMPARE wscompare
|
||||
#define EXTMATCH extmatch_wc
|
||||
#define STRCHR(S, C) wcschr((S), (C))
|
||||
#define STRCOLL(S1, S2) wcscoll((S1), (S2))
|
||||
#define STRLEN(S) wcslen(S)
|
||||
#define STRCMP(S1, S2) wcscmp((S1), (S2))
|
||||
#define RANGECMP(C1, C2) rangecmp_wc((C1), (C2))
|
||||
#define RANGECMP(C1, C2, F) rangecmp_wc((C1), (C2), (F))
|
||||
#define COLLEQUIV(C1, C2) collequiv_wc((C1), (C2))
|
||||
#define CTYPE_T enum char_class
|
||||
#define IS_CCLASS(C, S) is_wcclass((C), (S))
|
||||
|
|
@ -369,13 +386,7 @@ xstrmatch (pattern, string, flags)
|
|||
wchar_t *wpattern, *wstring;
|
||||
size_t plen, slen, mplen, mslen;
|
||||
|
||||
#if 0
|
||||
plen = strlen (pattern);
|
||||
mplen = mbstrlen (pattern);
|
||||
if (plen == mplen && strlen (string) == mbstrlen (string))
|
||||
#else
|
||||
if (mbsmbchar (string) == 0 && mbsmbchar (pattern) == 0)
|
||||
#endif
|
||||
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
|
||||
|
||||
if (MB_CUR_MAX == 1)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* xmbsrtowcs.c -- replacement function for mbsrtowcs */
|
||||
|
||||
/* Copyright (C) 2002-2010 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 2002-2013 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
|
|
@ -166,7 +166,7 @@ xdupmbstowcs2 (destp, src)
|
|||
do
|
||||
{
|
||||
end_or_backslash = strchrnul(p, '\\');
|
||||
nms = (end_or_backslash - p);
|
||||
nms = end_or_backslash - p;
|
||||
if (*end_or_backslash == '\0')
|
||||
nms++;
|
||||
|
||||
|
|
@ -283,6 +283,8 @@ xdupmbstowcs (destp, indicesp, src)
|
|||
{
|
||||
if (destp)
|
||||
*destp = NULL;
|
||||
if (indicesp)
|
||||
*indicesp = NULL;
|
||||
return (size_t)-1;
|
||||
}
|
||||
|
||||
|
|
@ -298,6 +300,8 @@ xdupmbstowcs (destp, indicesp, src)
|
|||
if (wsbuf == NULL)
|
||||
{
|
||||
*destp = NULL;
|
||||
if (indicesp)
|
||||
*indicesp = NULL;
|
||||
return (size_t)-1;
|
||||
}
|
||||
|
||||
|
|
@ -309,6 +313,7 @@ xdupmbstowcs (destp, indicesp, src)
|
|||
{
|
||||
free (wsbuf);
|
||||
*destp = NULL;
|
||||
*indicesp = NULL;
|
||||
return (size_t)-1;
|
||||
}
|
||||
}
|
||||
|
|
@ -343,6 +348,8 @@ xdupmbstowcs (destp, indicesp, src)
|
|||
free (wsbuf);
|
||||
FREE (indices);
|
||||
*destp = NULL;
|
||||
if (indicesp)
|
||||
*indicesp = NULL;
|
||||
return (size_t)-1;
|
||||
}
|
||||
|
||||
|
|
@ -362,18 +369,22 @@ xdupmbstowcs (destp, indicesp, src)
|
|||
free (wsbuf);
|
||||
FREE (indices);
|
||||
*destp = NULL;
|
||||
if (indicesp)
|
||||
*indicesp = NULL;
|
||||
return (size_t)-1;
|
||||
}
|
||||
wsbuf = wstmp;
|
||||
|
||||
if (indicesp)
|
||||
{
|
||||
idxtmp = (char **) realloc (indices, wsbuf_size * sizeof (char **));
|
||||
idxtmp = (char **) realloc (indices, wsbuf_size * sizeof (char *));
|
||||
if (idxtmp == NULL)
|
||||
{
|
||||
free (wsbuf);
|
||||
free (indices);
|
||||
*destp = NULL;
|
||||
if (indicesp)
|
||||
*indicesp = NULL;
|
||||
return (size_t)-1;
|
||||
}
|
||||
indices = idxtmp;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue