mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-08-06 10:12:38 +02:00
bash-5.0 distribution sources and documentation
This commit is contained in:
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user