bash-5.0 distribution sources and documentation

This commit is contained in:
Chet Ramey
2019-01-07 09:27:52 -05:00
parent 6444760999
commit d233b485e8
528 changed files with 84836 additions and 67099 deletions
+2 -1
View File
@@ -53,7 +53,7 @@ BASHINCDIR = ${topdir}/include
INCLUDES = -I. -I../.. -I$(topdir) -I$(BASHINCDIR) -I$(topdir)/lib
CCFLAGS = $(PROFILE_FLAGS) $(DEFS) $(LOCAL_DEFS) ${INCLUDES} $(CPPFLAGS) \
$(LOCAL_CFLAGS) $(CFLAGS)
$(LOCAL_CFLAGS) $(CFLAGS) ${ADDON_CFLAGS}
# Here is a rule for making .o files from .c files that doesn't force
# the type of the machine (like -sun3) into the flags.
@@ -164,4 +164,5 @@ xmbsrtowcs.o: xmbsrtowcs.c
# dependencies for C files that include other C files
glob.o: glob_loop.c
gmisc.o: gm_loop.c
smatch.o: sm_loop.c
+67 -29
View File
@@ -1,6 +1,6 @@
/* glob.c -- file-name wildcard pattern matching for Bash.
Copyright (C) 1985-2009 Free Software Foundation, Inc.
Copyright (C) 1985-2017 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne-Again SHell.
@@ -123,10 +123,14 @@ static char **glob_dir_to_array __P((char *, char **, int));
extern char *glob_patscan __P((char *, char *, int));
extern wchar_t *glob_patscan_wc __P((wchar_t *, wchar_t *, int));
/* And this from gmisc.c/gm_loop.c */
extern int wextglob_pattern_p __P((wchar_t *));
extern char *glob_dirscan __P((char *, int));
/* Compile `glob_loop.c' for single-byte characters. */
#define CHAR unsigned char
#define GCHAR unsigned char
#define CHAR char
#define INT int
#define L(CS) CS
#define INTERNAL_GLOB_PATTERN_P internal_glob_pattern_p
@@ -135,6 +139,7 @@ extern char *glob_dirscan __P((char *, int));
/* Compile `glob_loop.c' again for multibyte characters. */
#if HANDLE_MULTIBYTE
#define GCHAR wchar_t
#define CHAR wchar_t
#define INT wint_t
#define L(CS) L##CS
@@ -182,9 +187,10 @@ extglob_skipname (pat, dname, flags)
int flags;
{
char *pp, *pe, *t, *se;
int n, r, negate;
int n, r, negate, wild;
negate = *pat == '!';
wild = *pat == '*' || *pat == '?';
pp = pat + 2;
se = pp + strlen (pp) - 1; /* end of string */
pe = glob_patscan (pp, se, 0); /* end of extglob pattern (( */
@@ -203,14 +209,19 @@ extglob_skipname (pat, dname, flags)
r = skipname (pp, dname, flags); /*(*/
#endif
*pe = ')';
if (wild && pe[1]) /* if we can match zero instances, check further */
return (skipname (pe+1, dname, flags));
return r;
}
/* check every subpattern */
while (t = glob_patscan (pp, pe, '|'))
{
n = t[-1];
t[-1] = '\0';
n = t[-1]; /* ( */
if (extglob_pattern_p (pp) && n == ')')
t[-1] = n; /* no-op for now */
else
t[-1] = '\0';
#if defined (HANDLE_MULTIBYTE)
r = mbskipname (pp, dname, flags);
#else
@@ -222,12 +233,14 @@ extglob_skipname (pat, dname, flags)
pp = t;
} /*(*/
/* glob_patscan might find end of pattern */
/* glob_patscan might find end of string */
if (pp == se)
return r;
/* but if it doesn't then we didn't match a leading dot */
return 0;
if (wild && *pe) /* if we can match zero instances, check further */
return (skipname (pe, dname, flags));
return 1;
}
#endif
@@ -263,22 +276,23 @@ skipname (pat, dname, flags)
#if HANDLE_MULTIBYTE
static int
wchkname (pat_wc, dn_wc)
wchar_t *pat_wc, *dn_wc;
wskipname (pat, dname, flags)
wchar_t *pat, *dname;
int flags;
{
/* 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'))))
if (noglob_dot_filenames == 0 && pat[0] != L'.' &&
(pat[0] != L'\\' || pat[1] != L'.') &&
(dname[0] == L'.' &&
(dname[1] == L'\0' || (dname[1] == L'.' && dname[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'.'))
else if (noglob_dot_filenames && dname[0] == L'.' &&
pat[0] != L'.' &&
(pat[0] != L'\\' || pat[1] != L'.'))
return 1;
return 0;
@@ -291,9 +305,10 @@ wextglob_skipname (pat, dname, flags)
{
#if EXTENDED_GLOB
wchar_t *pp, *pe, *t, n, *se;
int r, negate;
int r, negate, wild;
negate = *pat == L'!';
wild = *pat == L'*' || *pat == L'?';
pp = pat + 2;
se = pp + wcslen (pp) - 1; /*(*/
pe = glob_patscan_wc (pp, se, 0);
@@ -301,17 +316,22 @@ wextglob_skipname (pat, dname, flags)
if (pe == se && *pe == ')' && (t = wcschr (pp, L'|')) == 0)
{
*pe = L'\0';
r = wchkname (pp, dname); /*(*/
r = wskipname (pp, dname, flags); /*(*/
*pe = L')';
if (wild && pe[1] != L'\0')
return (wskipname (pe+1, dname, flags));
return r;
}
/* check every subpattern */
while (t = glob_patscan_wc (pp, pe, '|'))
{
n = t[-1];
t[-1] = L'\0';
r = wchkname (pp, dname);
n = t[-1]; /* ( */
if (wextglob_pattern_p (pp) && n == L')')
t[-1] = n; /* no-op for now */
else
t[-1] = L'\0';
r = wskipname (pp, dname, flags);
t[-1] = n;
if (r == 0)
return 0;
@@ -322,9 +342,11 @@ wextglob_skipname (pat, dname, flags)
return r;
/* but if it doesn't then we didn't match a leading dot */
return 0;
if (wild && *pe != L'\0')
return (wskipname (pe, dname, flags));
return 1;
#else
return (wchkname (pat, dname));
return (wskipname (pat, dname, flags));
#endif
}
@@ -355,7 +377,7 @@ mbskipname (pat, dname, flags)
ret = 0;
if (pat_n != (size_t)-1 && dn_n !=(size_t)-1)
ret = ext ? wextglob_skipname (pat_wc, dn_wc, flags) : wchkname (pat_wc, dn_wc);
ret = ext ? wextglob_skipname (pat_wc, dn_wc, flags) : wskipname (pat_wc, dn_wc, flags);
else
ret = skipname (pat, dname, flags);
@@ -455,7 +477,7 @@ dequote_pathname (pathname)
# endif /* AFS */
#endif /* !HAVE_LSTAT */
/* Return 0 if DIR is a directory, -1 otherwise. */
/* Return 0 if DIR is a directory, -2 if DIR is a symlink, -1 otherwise. */
static int
glob_testdir (dir, flags)
char *dir;
@@ -473,6 +495,11 @@ glob_testdir (dir, flags)
if (r < 0)
return (-1);
#if defined (S_ISLNK)
if (S_ISLNK (finfo.st_mode))
return (-2);
#endif
if (S_ISDIR (finfo.st_mode) == 0)
return (-1);
@@ -590,6 +617,8 @@ glob_vector (pat, dir, flags)
firstmalloc = 0;
nalloca = 0;
name_vector = NULL;
/*itrace("glob_vector: pat = `%s' dir = `%s' flags = 0x%x", pat, dir, flags);*/
/* If PAT is empty, skip the loop, but return one (empty) filename. */
if (pat == 0 || *pat == '\0')
@@ -778,6 +807,15 @@ glob_vector (pat, dir, flags)
}
}
/* When FLAGS includes GX_ALLDIRS, we want to skip a symlink
to a directory, since we will pick the directory up later. */
if (isdir == -2 && glob_testdir (subdir, 0) == 0)
{
free (subdir);
continue;
}
/* XXX - should we even add this if it's not a directory? */
nextlink = (struct globval *) malloc (sizeof (struct globval));
if (firstmalloc == 0)
firstmalloc = nextlink;
@@ -1018,7 +1056,7 @@ glob_filename (pathname, flags)
char *pathname;
int flags;
{
char **result;
char **result, **new_result;
unsigned int result_size;
char *directory_name, *filename, *dname, *fn;
unsigned int directory_len;
@@ -1248,16 +1286,16 @@ glob_filename (pathname, flags)
while (array[l] != NULL)
++l;
result =
(char **)realloc (result, (result_size + l) * sizeof (char *));
new_result = (char **)realloc (result, (result_size + l) * sizeof (char *));
if (result == NULL)
if (new_result == NULL)
{
for (l = 0; array[l]; ++l)
free (array[l]);
free ((char *)array);
goto memory_error;
}
result = new_result;
for (l = 0; array[l] != NULL; ++l)
result[result_size++ - 1] = array[l];
+15 -5
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 1991-2005 Free Software Foundation, Inc.
/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -16,16 +16,16 @@
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
static int INTERNAL_GLOB_PATTERN_P __P((const CHAR *));
static int INTERNAL_GLOB_PATTERN_P __P((const GCHAR *));
/* Return nonzero if PATTERN has any special globbing chars in it.
Compiled twice, once each for single-byte and multibyte characters. */
static int
INTERNAL_GLOB_PATTERN_P (pattern)
const CHAR *pattern;
const GCHAR *pattern;
{
register const CHAR *p;
register CHAR c;
register const GCHAR *p;
register GCHAR c;
int bopen;
p = pattern;
@@ -54,8 +54,17 @@ INTERNAL_GLOB_PATTERN_P (pattern)
continue;
case L('\\'):
#if 0
/* Don't let the pattern end in a backslash (GMATCH returns no match
if the pattern ends in a backslash anyway), but otherwise return 1,
since the matching engine uses backslash as an escape character
and it can be removed. */
return (*p != L('\0'));
#else
/* The pattern may not end with a backslash. */
if (*p++ == L('\0'))
return 0;
#endif
}
return 0;
@@ -65,3 +74,4 @@ INTERNAL_GLOB_PATTERN_P (pattern)
#undef L
#undef INT
#undef CHAR
#undef GCHAR
+208
View File
@@ -0,0 +1,208 @@
/* Copyright (C) 1991-2017 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
*/
#if EXTENDED_GLOB
int
EXTGLOB_PATTERN_P (pat)
const CHAR *pat;
{
switch (pat[0])
{
case L('*'):
case L('+'):
case L('!'):
case L('@'):
case L('?'):
return (pat[1] == L('(')); /* ) */
default:
return 0;
}
return 0;
}
#endif
/* Return 1 of the first character of STRING could match the first
character of pattern PAT. Compiled to both single and wiide character
versions. FLAGS is a subset of strmatch flags; used to do case-insensitive
matching for now. */
int
MATCH_PATTERN_CHAR (pat, string, flags)
CHAR *pat, *string;
int flags;
{
CHAR c;
if (*string == 0)
return (*pat == L('*')); /* XXX - allow only * to match empty string */
switch (c = *pat++)
{
default:
return (FOLD(*string) == FOLD(c));
case L('\\'):
return (FOLD(*string) == FOLD(*pat));
case L('?'):
return (*pat == L('(') ? 1 : (*string != L'\0'));
case L('*'):
return (1);
case L('+'):
case L('!'):
case L('@'):
return (*pat == L('(') ? 1 : (FOLD(*string) == FOLD(c)));
case L('['):
return (*string != L('\0'));
}
}
int
MATCHLEN (pat, max)
CHAR *pat;
size_t max;
{
CHAR c;
int matlen, bracklen, t, in_cclass, in_collsym, in_equiv;
if (*pat == 0)
return (0);
matlen = in_cclass = in_collsym = in_equiv = 0;
while (c = *pat++)
{
switch (c)
{
default:
matlen++;
break;
case L('\\'):
if (*pat == 0)
return ++matlen;
else
{
matlen++;
pat++;
}
break;
case L('?'):
if (*pat == LPAREN)
return (matlen = -1); /* XXX for now */
else
matlen++;
break;
case L('*'):
return (matlen = -1);
case L('+'):
case L('!'):
case L('@'):
if (*pat == LPAREN)
return (matlen = -1); /* XXX for now */
else
matlen++;
break;
case L('['):
/* scan for ending `]', skipping over embedded [:...:] */
bracklen = 1;
c = *pat++;
do
{
if (c == 0)
{
pat--; /* back up to NUL */
matlen += bracklen;
goto bad_bracket;
}
else if (c == L('\\'))
{
/* *pat == backslash-escaped character */
bracklen++;
/* If the backslash or backslash-escape ends the string,
bail. The ++pat skips over the backslash escape */
if (*pat == 0 || *++pat == 0)
{
matlen += bracklen;
goto bad_bracket;
}
}
else if (c == L('[') && *pat == L(':')) /* character class */
{
pat++;
bracklen++;
in_cclass = 1;
}
else if (in_cclass && c == L(':') && *pat == L(']'))
{
pat++;
bracklen++;
in_cclass = 0;
}
else if (c == L('[') && *pat == L('.')) /* collating symbol */
{
pat++;
bracklen++;
if (*pat == L(']')) /* right bracket can appear as collating symbol */
{
pat++;
bracklen++;
}
in_collsym = 1;
}
else if (in_collsym && c == L('.') && *pat == L(']'))
{
pat++;
bracklen++;
in_collsym = 0;
}
else if (c == L('[') && *pat == L('=')) /* equivalence class */
{
pat++;
bracklen++;
if (*pat == L(']')) /* right bracket can appear as equivalence class */
{
pat++;
bracklen++;
}
in_equiv = 1;
}
else if (in_equiv && c == L('=') && *pat == L(']'))
{
pat++;
bracklen++;
in_equiv = 0;
}
else
bracklen++;
}
while ((c = *pat++) != L(']'));
matlen++; /* bracket expression can only match one char */
bad_bracket:
break;
}
}
return matlen;
}
#undef EXTGLOB_PATTERN_P
#undef MATCH_PATTERN_CHAR
#undef MATCHLEN
#undef FOLD
#undef L
#undef LPAREN
#undef RPAREN
#undef INT
#undef CHAR
+27 -350
View File
@@ -1,6 +1,6 @@
/* gmisc.c -- miscellaneous pattern matching utility functions for Bash.
Copyright (C) 2010 Free Software Foundation, Inc.
Copyright (C) 2010-2017 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne-Again SHell.
@@ -35,367 +35,44 @@
#ifndef FNM_CASEFOLD
# include "strmatch.h"
#endif
#ifndef LPAREN
# define LPAREN '('
#endif
#ifndef RPAREN
# define RPAREN ')'
#endif
#if defined (HANDLE_MULTIBYTE)
#define WLPAREN L'('
#define WRPAREN L')'
#include "glob.h"
/* 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));
#define FOLD(c) ((flags & FNM_CASEFOLD) && iswupper (c) ? towlower (c) : (c))
/* Return 1 of the first character of WSTRING could match the first
character of pattern WPAT. Wide character version. FLAGS is a
subset of strmatch flags; used to do case-insensitive matching for now. */
int
match_pattern_wchar (wpat, wstring, flags)
wchar_t *wpat, *wstring;
int flags;
{
wchar_t wc;
if (*wstring == 0)
return (*wpat == L'*'); /* XXX - allow only * to match empty string */
switch (wc = *wpat++)
{
default:
return (FOLD(*wstring) == FOLD(wc));
case L'\\':
return (FOLD(*wstring) == FOLD(*wpat));
case L'?':
return (*wpat == WLPAREN ? 1 : (*wstring != L'\0'));
case L'*':
return (1);
case L'+':
case L'!':
case L'@':
return (*wpat == WLPAREN ? 1 : (FOLD(*wstring) == FOLD(wc)));
case L'[':
return (*wstring != L'\0');
}
}
int
wmatchlen (wpat, wmax)
wchar_t *wpat;
size_t wmax;
{
wchar_t wc;
int matlen, bracklen, t, in_cclass, in_collsym, in_equiv;
if (*wpat == 0)
return (0);
matlen = in_cclass = in_collsym = in_equiv = 0;
while (wc = *wpat++)
{
switch (wc)
{
default:
matlen++;
break;
case L'\\':
if (*wpat == 0)
return ++matlen;
else
{
matlen++;
wpat++;
}
break;
case L'?':
if (*wpat == WLPAREN)
return (matlen = -1); /* XXX for now */
else
matlen++;
break;
case L'*':
return (matlen = -1);
case L'+':
case L'!':
case L'@':
if (*wpat == WLPAREN)
return (matlen = -1); /* XXX for now */
else
matlen++;
break;
case L'[':
/* scan for ending `]', skipping over embedded [:...:] */
bracklen = 1;
wc = *wpat++;
do
{
if (wc == 0)
{
wpat--; /* back up to NUL */
matlen += bracklen;
goto bad_bracket;
}
else if (wc == L'\\')
{
/* *wpat == backslash-escaped character */
bracklen++;
/* If the backslash or backslash-escape ends the string,
bail. The ++wpat skips over the backslash escape */
if (*wpat == 0 || *++wpat == 0)
{
matlen += bracklen;
goto bad_bracket;
}
}
else if (wc == L'[' && *wpat == L':') /* character class */
{
wpat++;
bracklen++;
in_cclass = 1;
}
else if (in_cclass && wc == L':' && *wpat == L']')
{
wpat++;
bracklen++;
in_cclass = 0;
}
else if (wc == L'[' && *wpat == L'.') /* collating symbol */
{
wpat++;
bracklen++;
if (*wpat == L']') /* right bracket can appear as collating symbol */
{
wpat++;
bracklen++;
}
in_collsym = 1;
}
else if (in_collsym && wc == L'.' && *wpat == L']')
{
wpat++;
bracklen++;
in_collsym = 0;
}
else if (wc == L'[' && *wpat == L'=') /* equivalence class */
{
wpat++;
bracklen++;
if (*wpat == L']') /* right bracket can appear as equivalence class */
{
wpat++;
bracklen++;
}
in_equiv = 1;
}
else if (in_equiv && wc == L'=' && *wpat == L']')
{
wpat++;
bracklen++;
in_equiv = 0;
}
else
bracklen++;
}
while ((wc = *wpat++) != L']');
matlen++; /* bracket expression can only match one char */
bad_bracket:
break;
}
}
return matlen;
}
#endif
int
extglob_pattern_p (pat)
char *pat;
{
switch (pat[0])
{
case '*':
case '+':
case '!':
case '@':
case '?':
return (pat[1] == LPAREN);
default:
return 0;
}
return 0;
}
#undef FOLD
/* Compile `gm_loop.c' for single-byte characters. */
#define CHAR char
#define INT int
#define L(CS) CS
#define EXTGLOB_PATTERN_P extglob_pattern_p
#define MATCH_PATTERN_CHAR match_pattern_char
#define MATCHLEN umatchlen
#define FOLD(c) ((flags & FNM_CASEFOLD) \
? TOLOWER ((unsigned char)c) \
: ((unsigned char)c))
#ifndef LPAREN
#define LPAREN '('
#define RPAREN ')'
#endif
#include "gm_loop.c"
/* Return 1 of the first character of STRING could match the first
character of pattern PAT. Used to avoid n2 calls to strmatch().
FLAGS is a subset of strmatch flags; used to do case-insensitive
matching for now. */
int
match_pattern_char (pat, string, flags)
char *pat, *string;
int flags;
{
char c;
/* Compile `gm_loop.c' again for multibyte characters. */
#if HANDLE_MULTIBYTE
if (*string == 0)
return (*pat == '*'); /* XXX - allow only * to match empty string */
#define CHAR wchar_t
#define INT wint_t
#define L(CS) L##CS
#define EXTGLOB_PATTERN_P wextglob_pattern_p
#define MATCH_PATTERN_CHAR match_pattern_wchar
#define MATCHLEN wmatchlen
switch (c = *pat++)
{
default:
return (FOLD(*string) == FOLD(c));
case '\\':
return (FOLD(*string) == FOLD(*pat));
case '?':
return (*pat == LPAREN ? 1 : (*string != '\0'));
case '*':
return (1);
case '+':
case '!':
case '@':
return (*pat == LPAREN ? 1 : (FOLD(*string) == FOLD(c)));
case '[':
return (*string != '\0');
}
}
#define FOLD(c) ((flags & FNM_CASEFOLD) && iswupper (c) ? towlower (c) : (c))
#define LPAREN L'('
#define RPAREN L')'
#include "gm_loop.c"
int
umatchlen (pat, max)
char *pat;
size_t max;
{
char c;
int matlen, bracklen, t, in_cclass, in_collsym, in_equiv;
#endif /* HANDLE_MULTIBYTE */
if (*pat == 0)
return (0);
matlen = in_cclass = in_collsym = in_equiv = 0;
while (c = *pat++)
{
switch (c)
{
default:
matlen++;
break;
case '\\':
if (*pat == 0)
return ++matlen;
else
{
matlen++;
pat++;
}
break;
case '?':
if (*pat == LPAREN)
return (matlen = -1); /* XXX for now */
else
matlen++;
break;
case '*':
return (matlen = -1);
case '+':
case '!':
case '@':
if (*pat == LPAREN)
return (matlen = -1); /* XXX for now */
else
matlen++;
break;
case '[':
/* scan for ending `]', skipping over embedded [:...:] */
bracklen = 1;
c = *pat++;
do
{
if (c == 0)
{
pat--; /* back up to NUL */
matlen += bracklen;
goto bad_bracket;
}
else if (c == '\\')
{
/* *pat == backslash-escaped character */
bracklen++;
/* If the backslash or backslash-escape ends the string,
bail. The ++pat skips over the backslash escape */
if (*pat == 0 || *++pat == 0)
{
matlen += bracklen;
goto bad_bracket;
}
}
else if (c == '[' && *pat == ':') /* character class */
{
pat++;
bracklen++;
in_cclass = 1;
}
else if (in_cclass && c == ':' && *pat == ']')
{
pat++;
bracklen++;
in_cclass = 0;
}
else if (c == '[' && *pat == '.') /* collating symbol */
{
pat++;
bracklen++;
if (*pat == ']') /* right bracket can appear as collating symbol */
{
pat++;
bracklen++;
}
in_collsym = 1;
}
else if (in_collsym && c == '.' && *pat == ']')
{
pat++;
bracklen++;
in_collsym = 0;
}
else if (c == '[' && *pat == '=') /* equivalence class */
{
pat++;
bracklen++;
if (*pat == ']') /* right bracket can appear as equivalence class */
{
pat++;
bracklen++;
}
in_equiv = 1;
}
else if (in_equiv && c == '=' && *pat == ']')
{
pat++;
bracklen++;
in_equiv = 0;
}
else
bracklen++;
}
while ((c = *pat++) != ']');
matlen++; /* bracket expression can only match one char */
bad_bracket:
break;
}
}
return matlen;
}
#if defined (EXTENDED_GLOB)
/* Skip characters in PAT and return the final occurrence of DIRSEP. This
+101 -32
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 1991-2011 Free Software Foundation, Inc.
/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -16,9 +16,15 @@
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
struct STRUCT
{
CHAR *pattern;
CHAR *string;
};
int FCT __P((CHAR *, CHAR *, int));
static int GMATCH __P((CHAR *, CHAR *, CHAR *, CHAR *, int));
static int GMATCH __P((CHAR *, CHAR *, CHAR *, CHAR *, struct STRUCT *, 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));
@@ -39,15 +45,16 @@ FCT (pattern, string, flags)
se = string + STRLEN ((XCHAR *)string);
pe = pattern + STRLEN ((XCHAR *)pattern);
return (GMATCH (string, se, pattern, pe, flags));
return (GMATCH (string, se, pattern, pe, (struct STRUCT *)NULL, 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)
GMATCH (string, se, pattern, pe, ends, flags)
CHAR *string, *se;
CHAR *pattern, *pe;
struct STRUCT *ends;
int flags;
{
CHAR *p, *n; /* pattern, string */
@@ -103,6 +110,9 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
break;
case L('\\'): /* backslash escape removes special meaning */
if (p == pe && sc == '\\' && (n+1 == se))
break;
if (p == pe)
return FNM_NOMATCH;
@@ -118,7 +128,16 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
return FNM_NOMATCH;
break;
case '*': /* Match zero or more characters */
case L('*'): /* Match zero or more characters */
/* See below for the reason for using this. It avoids backtracking
back to a previous `*'. Picked up from glibc. */
if (ends != NULL)
{
ends->pattern = p - 1;
ends->string = n;
return (0);
}
if ((flags & FNM_PERIOD) && sc == L('.') &&
(n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/'))))
/* `*' cannot match a `.' if it is the first character of the
@@ -141,17 +160,9 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
{
CHAR *newn;
#if 0
for (newn = n; newn < se; ++newn)
{
if (EXTMATCH (c, newn, se, p, pe, flags) == 0)
return (0);
}
#else
/* We can match 0 or 1 times. If we match, return success */
if (EXTMATCH (c, n, se, p, pe, flags) == 0)
return (0);
#endif
/* We didn't match the extended glob pattern, but
that's OK, since we can match 0 or 1 occurrences.
@@ -241,7 +252,7 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
{
while (n < se && *n != L('/'))
++n;
if (n < se && *n == L('/') && (GMATCH (n+1, se, p, pe, flags) == 0))
if (n < se && *n == L('/') && (GMATCH (n+1, se, p, pe, NULL, flags) == 0))
return 0;
return FNM_NOMATCH; /* XXX */
}
@@ -250,10 +261,13 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
{
U_CHAR c1;
const CHAR *endp;
struct STRUCT end;
end.pattern = NULL;
endp = MEMCHR (n, (flags & FNM_PATHNAME) ? L('/') : L('\0'), se - n);
if (endp == 0)
endp = se;
c1 = ((flags & FNM_NOESCAPE) == 0 && c == L('\\')) ? *p : c;
c1 = FOLD (c1);
for (--p; n < endp; ++n)
@@ -272,9 +286,24 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
continue;
/* Otherwise, we just recurse. */
if (GMATCH (n, se, p, pe, flags & ~FNM_PERIOD) == 0)
return (0);
if (GMATCH (n, se, p, pe, &end, flags & ~FNM_PERIOD) == 0)
{
if (end.pattern == NULL)
return (0);
break;
}
}
/* This is a clever idea from glibc, used to avoid backtracking
to a `*' that appears earlier in the pattern. We get away
without saving se and pe because they are always the same,
even in the recursive calls to gmatch */
if (end.pattern != NULL)
{
p = end.pattern;
n = end.string;
continue;
}
return FNM_NOMATCH;
}
@@ -355,11 +384,13 @@ BRACKMATCH (p, test, flags)
{
register CHAR cstart, cend, c;
register int not; /* Nonzero if the sense of the character class is inverted. */
int brcnt, forcecoll;
int brcnt, brchr, forcecoll, isrange;
INT pc;
CHAR *savep;
U_CHAR orig_test;
test = FOLD (test);
orig_test = test;
test = FOLD (orig_test);
savep = p;
@@ -424,12 +455,23 @@ BRACKMATCH (p, test, flags)
{
bcopy (p + 1, ccname, (close - p - 1) * sizeof (CHAR));
*(ccname + (close - p - 1)) = L('\0');
pc = IS_CCLASS (test, (XCHAR *)ccname);
pc = IS_CCLASS (orig_test, (XCHAR *)ccname);
}
if (pc == -1)
pc = 0;
{
/* CCNAME is not a valid character class in the current
locale. In addition to noting no match (pc = 0), we have
a choice about what to do with the invalid charclass.
Posix leaves the behavior unspecified, but we're going
to skip over the charclass and keep going instead of
testing ORIG_TEST against each character in the class
string. If we don't want to do that, take out the update
of P. */
pc = 0;
p = close + 2;
}
else
p = close + 2;
p = close + 2; /* move past the closing `]' */
free (ccname);
}
@@ -477,6 +519,7 @@ BRACKMATCH (p, test, flags)
}
cstart = cend = FOLD (cstart);
isrange = 0;
/* 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
@@ -531,10 +574,18 @@ BRACKMATCH (p, test, flags)
c = FOLD (c);
continue;
}
isrange = 1;
}
#if 0 /* TAG: bash-5.1 */
if (isrange == 0 && test == cstart)
goto matched;
if (isrange && RANGECMP (test, cstart, forcecoll) >= 0 && RANGECMP (test, cend, forcecoll) <= 0)
goto matched;
#else
if (RANGECMP (test, cstart, forcecoll) >= 0 && RANGECMP (test, cend, forcecoll) <= 0)
goto matched;
#endif
if (c == L(']'))
break;
@@ -546,16 +597,26 @@ matched:
/* Skip the rest of the [...] that already matched. */
c = *--p;
brcnt = 1;
brchr = 0;
while (brcnt > 0)
{
int oc;
/* A `[' without a matching `]' is just another character to match. */
if (c == L('\0'))
return ((test == L('[')) ? savep : (CHAR *)0);
oc = c;
c = *p++;
if (c == L('[') && (*p == L('=') || *p == L(':') || *p == L('.')))
brcnt++;
else if (c == L(']'))
{
brcnt++;
brchr = *p;
}
/* we only want to check brchr if we set it above */
else if (c == L(']') && brcnt > 1 && brchr != 0 && oc == brchr)
brcnt--;
else if (c == L(']') && brcnt == 1)
brcnt--;
else if (!(flags & FNM_NOESCAPE) && c == L('\\'))
{
@@ -748,7 +809,7 @@ fprintf(stderr, "extmatch: flags = %d\n", flags);
/* 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 == L('*') && (GMATCH (s, se, prest, pe, flags) == 0))
if (xc == L('*') && (GMATCH (s, se, prest, pe, NULL, flags) == 0))
return 0;
/* OK, we have to do this the hard way. First, we make sure one of
@@ -761,7 +822,7 @@ fprintf(stderr, "extmatch: flags = %d\n", flags);
{
/* Match this substring (S -> SREST) against this
subpattern (psub -> pnext - 1) */
m1 = GMATCH (s, srest, psub, pnext - 1, flags) == 0;
m1 = GMATCH (s, srest, psub, pnext - 1, NULL, 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. */
@@ -769,8 +830,8 @@ fprintf(stderr, "extmatch: flags = %d\n", flags);
{
/* if srest > s, we are not at start of string */
xflags = (srest > s) ? (flags & ~FNM_PERIOD) : flags;
m2 = (GMATCH (srest, se, prest, pe, xflags) == 0) ||
(s != srest && GMATCH (srest, se, p - 1, pe, xflags) == 0);
m2 = (GMATCH (srest, se, prest, pe, NULL, xflags) == 0) ||
(s != srest && GMATCH (srest, se, p - 1, pe, NULL, xflags) == 0);
}
if (m1 && m2)
return (0);
@@ -785,7 +846,7 @@ fprintf(stderr, "extmatch: flags = %d\n", flags);
/* 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 == L('?') && (GMATCH (s, se, prest, pe, flags) == 0))
if (xc == L('?') && (GMATCH (s, se, prest, pe, NULL, flags) == 0))
return 0;
/* OK, we have to do this the hard way. First, we see if one of
@@ -799,8 +860,8 @@ fprintf(stderr, "extmatch: flags = %d\n", flags);
{
/* if srest > s, we are not at start of string */
xflags = (srest > s) ? (flags & ~FNM_PERIOD) : flags;
if (GMATCH (s, srest, psub, pnext - 1, flags) == 0 &&
GMATCH (srest, se, prest, pe, xflags) == 0)
if (GMATCH (s, srest, psub, pnext - 1, NULL, flags) == 0 &&
GMATCH (srest, se, prest, pe, NULL, xflags) == 0)
return (0);
}
if (pnext == prest)
@@ -816,14 +877,21 @@ fprintf(stderr, "extmatch: flags = %d\n", flags);
{
pnext = PATSCAN (psub, pe, L('|'));
/* If one of the patterns matches, just bail immediately. */
if (m1 = (GMATCH (s, srest, psub, pnext - 1, flags) == 0))
if (m1 = (GMATCH (s, srest, psub, pnext - 1, NULL, flags) == 0))
break;
if (pnext == prest)
break;
}
/* If nothing matched, but the string starts with a period and we
need to match periods explicitly, don't return this as a match,
even for negation. Might need to do this only if srest == s. */
if (m1 == 0 && *s == '.' && (flags & FNM_PERIOD))
return (FNM_NOMATCH);
/* if srest > s, we are not at start of string */
xflags = (srest > s) ? (flags & ~FNM_PERIOD) : flags;
if (m1 == 0 && GMATCH (srest, se, prest, pe, xflags) == 0)
if (m1 == 0 && GMATCH (srest, se, prest, pe, NULL, xflags) == 0)
return (0);
}
return (FNM_NOMATCH);
@@ -847,6 +915,7 @@ fprintf(stderr, "extmatch: flags = %d\n", flags);
#undef PATSCAN
#undef STRCOMPARE
#undef EXTMATCH
#undef STRUCT
#undef BRACKMATCH
#undef STRCHR
#undef STRCOLL
+149 -13
View File
@@ -1,7 +1,7 @@
/* strmatch.c -- ksh-like extended pattern matching for the shell and filename
globbing. */
/* Copyright (C) 1991-2011 Free Software Foundation, Inc.
/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -30,6 +30,12 @@
#include "shmbutil.h"
#include "xmalloc.h"
#include <errno.h>
#if !defined (errno)
extern int errno;
#endif
/* First, compile `sm_loop.c' for single-byte characters. */
#define CHAR unsigned char
#define U_CHAR unsigned char
@@ -82,7 +88,7 @@ rangecmp (c1, c2, forcecoll)
if ((ret = strcoll (s1, s2)) != 0)
return ret;
return (c1 - c2);
return (c1 - c2); /* impose total ordering */
}
#else /* !HAVE_STRCOLL */
# define rangecmp(c1, c2, f) ((int)(c1) - (int)(c2))
@@ -144,25 +150,33 @@ static char const *const cclass_name[] =
#define N_CHAR_CLASS (sizeof(cclass_name) / sizeof (cclass_name[0]))
static int
is_cclass (c, name)
int c;
static enum char_class
is_valid_cclass (name)
const char *name;
{
enum char_class char_class = CC_NO_CLASS;
int i, result;
enum char_class ret;
int i;
ret = CC_NO_CLASS;
for (i = 1; i < N_CHAR_CLASS; i++)
{
if (STREQ (name, cclass_name[i]))
{
char_class = (enum char_class)i;
ret = (enum char_class)i;
break;
}
}
if (char_class == 0)
return -1;
return ret;
}
static int
cclass_test (c, char_class)
int c;
enum char_class char_class;
{
int result;
switch (char_class)
{
@@ -215,6 +229,22 @@ is_cclass (c, name)
return result;
}
static int
is_cclass (c, name)
int c;
const char *name;
{
enum char_class char_class;
int result;
char_class = is_valid_cclass (name);
if (char_class == CC_NO_CLASS)
return -1;
result = cclass_test (c, char_class);
return (result);
}
/* Now include `sm_loop.c' for single-byte characters. */
/* The result of FOLD is an `unsigned char' */
@@ -230,6 +260,7 @@ is_cclass (c, name)
#define PATSCAN glob_patscan
#define STRCOMPARE strcompare
#define EXTMATCH extmatch
#define STRUCT smat_struct
#define STRCHR(S, C) strchr((S), (C))
#define MEMCHR(S, C, N) memchr((S), (C), (N))
#define STRCOLL(S1, S2) strcoll((S1), (S2))
@@ -257,6 +288,41 @@ is_cclass (c, name)
extern char *mbsmbchar __P((const char *));
#if FNMATCH_EQUIV_FALLBACK
/* We don't include <fnmatch.h> in order to avoid namespace collisions; the
internal strmatch still uses the FNM_ constants. */
extern int fnmatch (const char *, const char *, int);
/* Construct a string w1 = "c1" and a pattern w2 = "[[=c2=]]" and pass them
to fnmatch to see if wide characters c1 and c2 collate as members of the
same equivalence class. We can't really do this portably any other way */
static int
_fnmatch_fallback_wc (c1, c2)
wchar_t c1, c2; /* string char, patchar */
{
char w1[MB_LEN_MAX+1]; /* string */
char w2[MB_LEN_MAX+8]; /* constructed pattern */
int l1, l2;
l1 = wctomb (w1, c1);
if (l1 == -1)
return (2);
w1[l1] = '\0';
/* reconstruct the pattern */
w2[0] = w2[1] = '[';
w2[2] = '=';
l2 = wctomb (w2+3, c2);
if (l2 == -1)
return (2);
w2[l2+3] = '=';
w2[l2+4] = w2[l2+5] = ']';
w2[l2+6] = '\0';
return (fnmatch ((const char *)w2, (const char *)w1, 0));
}
#endif
static int
rangecmp_wc (c1, c2, forcecoll)
wint_t c1, c2;
@@ -264,6 +330,7 @@ rangecmp_wc (c1, c2, forcecoll)
{
static wchar_t s1[2] = { L' ', L'\0' };
static wchar_t s2[2] = { L' ', L'\0' };
int r, oerrno;
if (c1 == c2)
return 0;
@@ -274,14 +341,38 @@ rangecmp_wc (c1, c2, forcecoll)
s1[0] = c1;
s2[0] = c2;
#if 0 /* TAG:bash-5.1 */
/* We impose a total ordering here by returning c1-c2 if wcscoll returns 0,
as we do above in the single-byte case. If we do this, we can no longer
use this code in collequiv_wc */
if ((r = wcscoll (s1, s2)) != 0)
return r;
return ((int)(c1 - c2)); /* impose total ordering */
#else
return (wcscoll (s1, s2));
#endif
}
/* Returns non-zero on success */
static int
collequiv_wc (c, equiv)
wint_t c, equiv;
{
return (c == equiv);
wchar_t s, p;
if (rangecmp_wc (c, equiv, 1) == 0)
return 1;
#if FNMATCH_EQUIV_FALLBACK
/* We check explicitly for success (fnmatch returns 0) to avoid problems if
our local definition of FNM_NOMATCH (strmatch.h) doesn't match the
system's (fnmatch.h). We don't care about error return values here. */
s = c;
p = equiv;
return (_fnmatch_fallback_wc (s, p) == 0);
#else
return 0;
#endif
}
/* Helper function for collating symbol. */
@@ -355,6 +446,50 @@ is_wcclass (wc, name)
return (iswctype (wc, desc));
}
/* Return 1 if there are no char class [:class:] expressions (degenerate case)
or only posix-specified (C locale supported) char class expressions in
PATTERN. These are the ones where it's safe to punt to the single-byte
code, since wide character support allows locale-defined char classes.
This only uses single-byte code, but is only needed to support multibyte
locales. */
static int
posix_cclass_only (pattern)
char *pattern;
{
char *p, *p1;
char cc[16]; /* sufficient for all valid posix char class names */
enum char_class valid;
p = pattern;
while (p = strchr (p, '['))
{
if (p[1] != ':')
{
p++;
continue;
}
p += 2; /* skip past "[:" */
/* Find end of char class expression */
for (p1 = p; *p1; p1++)
if (*p1 == ':' && p1[1] == ']')
break;
if (*p1 == 0) /* no char class expression found */
break;
/* Find char class name and validate it against posix char classes */
if ((p1 - p) >= sizeof (cc))
return 0;
bcopy (p, cc, p1 - p);
cc[p1 - p] = '\0';
valid = is_valid_cclass (cc);
if (valid == CC_NO_CLASS)
return 0; /* found unrecognized char class name */
p = p1 + 2; /* found posix char class name */
}
return 1; /* no char class names or only posix */
}
/* Now include `sm_loop.c' for multibyte characters. */
#define FOLD(c) ((flags & FNM_CASEFOLD) && iswupper (c) ? towlower (c) : (c))
#define FCT internal_wstrmatch
@@ -365,6 +500,7 @@ is_wcclass (wc, name)
#define PATSCAN glob_patscan_wc
#define STRCOMPARE wscompare
#define EXTMATCH extmatch_wc
#define STRUCT wcsmat_struct
#define STRCHR(S, C) wcschr((S), (C))
#define MEMCHR(S, C, N) wmemchr((S), (C), (N))
#define STRCOLL(S1, S2) wcscoll((S1), (S2))
@@ -390,10 +526,10 @@ xstrmatch (pattern, string, flags)
wchar_t *wpattern, *wstring;
size_t plen, slen, mplen, mslen;
if (mbsmbchar (string) == 0 && mbsmbchar (pattern) == 0)
if (MB_CUR_MAX == 1)
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
if (MB_CUR_MAX == 1)
if (mbsmbchar (string) == 0 && mbsmbchar (pattern) == 0 && posix_cclass_only (pattern) )
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
n = xdupmbstowcs (&wpattern, NULL, pattern);
+2
View File
@@ -46,6 +46,8 @@
#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
#define FNM_EXTMATCH (1 << 5) /* Use ksh-like extended matching. */
#define FNM_FIRSTCHAR (1 << 6) /* Match only the first character */
/* Value returned by `strmatch' if STRING does not match PATTERN. */
#undef FNM_NOMATCH