mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-27 07:43:07 +02:00
more changes for bracket expressions in patterns
This commit is contained in:
@@ -4579,3 +4579,37 @@ variables.c
|
||||
find_variable_last_nameref_context: make sure to return
|
||||
&nameref_maxloop_value consistently and handle getting it as a
|
||||
return value from other functions
|
||||
|
||||
11/29
|
||||
-----
|
||||
lib/readline/display.c
|
||||
- _rl_update_final: if there is only one line (_rl_vis_botlin == 0)
|
||||
and that line is empty (botline_length == 0), assume there is no
|
||||
prompt and the line has no contents, so output the CR/LF to indicate
|
||||
that the newline has been read. From a report from
|
||||
Kevin Pulo <kev@pulo.com.au>
|
||||
|
||||
11/30
|
||||
-----
|
||||
builtins/evalstring.c
|
||||
- parse_and_execute: if we are executing the eval builtin, and the
|
||||
return status from the command is suppressed (builtin_ignoring_errexit),
|
||||
set CMD_IGNORE_RETURN in the parsed command's flags. From a report
|
||||
from Tycho Kirchner <tychokirchner@mail.de>
|
||||
|
||||
12/1
|
||||
----
|
||||
lib/glob/sm_loop.c
|
||||
- PARSE_SUBBRACKET: a reworked PARSE_COLLSYM, generalized to handle
|
||||
[:, [=, and [. special bracket expressions
|
||||
- BRACKMATCH: change to use PARSE_SUBBRACKET consistently to parse
|
||||
[:, [=, and [. special bracket expressions
|
||||
- PATSCAN: takes new FLAGS arg, changed all callers to just pass the
|
||||
flags they get through to PATSCAN
|
||||
- PATSCAN: call PARSE_SUBBRACKET for [:, [=, and [. to treat them
|
||||
consistently (uses FLAGS argument here)
|
||||
- PATSCAN: handle FNM_NOESCAPE appearing in FLAGS argument
|
||||
This set of fixes contributed by Koichi Murase <myoga.murase@gmail.com>
|
||||
|
||||
lib/glob/{glob,gmisc}.c
|
||||
- PATSCAN: change all callers to add extra flags arg of 0
|
||||
|
||||
@@ -1168,6 +1168,8 @@ tests/globstar.right f
|
||||
tests/globstar1.sub f
|
||||
tests/globstar2.sub f
|
||||
tests/globstar3.sub f
|
||||
tests/glob-bracket.tests f
|
||||
tests/glob-bracket.right f
|
||||
tests/heredoc.tests f
|
||||
tests/heredoc.right f
|
||||
tests/heredoc1.sub f
|
||||
@@ -1414,6 +1416,7 @@ tests/run-extglob3 f
|
||||
tests/run-func f
|
||||
tests/run-getopts f
|
||||
tests/run-glob-test f
|
||||
tests/run-glob-bracket f
|
||||
tests/run-globstar f
|
||||
tests/run-heredoc f
|
||||
tests/run-herestr f
|
||||
@@ -1494,6 +1497,7 @@ tests/trap3.sub f
|
||||
tests/trap4.sub f
|
||||
tests/trap5.sub f
|
||||
tests/trap6.sub f
|
||||
tests/trap7.sub f
|
||||
tests/type.tests f
|
||||
tests/type.right f
|
||||
tests/type1.sub f
|
||||
|
||||
@@ -234,6 +234,7 @@ parse_prologue (string, flags, tag)
|
||||
unwind_protect_int (loop_level);
|
||||
unwind_protect_int (executing_list);
|
||||
unwind_protect_int (comsub_ignore_return);
|
||||
unwind_protect_int (builtin_ignoring_errexit);
|
||||
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
|
||||
unwind_protect_int (interactive);
|
||||
|
||||
@@ -299,7 +300,7 @@ parse_and_execute (string, from_file, flags)
|
||||
const char *from_file;
|
||||
int flags;
|
||||
{
|
||||
int code, lreset;
|
||||
int code, lreset, ignore_return;
|
||||
volatile int should_jump_to_top_level, last_result;
|
||||
COMMAND *volatile command;
|
||||
volatile sigset_t pe_sigmask;
|
||||
@@ -309,6 +310,8 @@ parse_and_execute (string, from_file, flags)
|
||||
parse_and_execute_level++;
|
||||
|
||||
lreset = flags & SEVAL_RESETLINE;
|
||||
ignore_return = (this_shell_builtin == eval_builtin || this_shell_builtin == source_builtin) &&
|
||||
builtin_ignoring_errexit;
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
/* If we longjmp and are going to go on, use this to restore signal mask */
|
||||
@@ -476,6 +479,9 @@ parse_and_execute (string, from_file, flags)
|
||||
if ((subshell_environment & SUBSHELL_COMSUB) && comsub_ignore_return)
|
||||
command->flags |= CMD_IGNORE_RETURN;
|
||||
|
||||
if (ignore_return)
|
||||
command->flags |= CMD_IGNORE_RETURN;
|
||||
|
||||
#if defined (ONESHOT)
|
||||
/*
|
||||
* IF
|
||||
|
||||
+1
-1
@@ -3984,7 +3984,7 @@ Matches anything except one of the given patterns
|
||||
.RE
|
||||
.PD
|
||||
.PP
|
||||
The\fBextglob\fP option changes the behavior of the parser, since the
|
||||
The \fBextglob\fP option changes the behavior of the parser, since the
|
||||
parentheses are normally treated as operators with syntactic meaning.
|
||||
To ensure that extended matching patterns are parsed correctly, make sure
|
||||
that \fBextglob\fP is enabled before parsing constructs containing the
|
||||
|
||||
+6
-6
@@ -127,8 +127,8 @@ static int glob_testdir PARAMS((char *, int));
|
||||
static char **glob_dir_to_array PARAMS((char *, char **, int));
|
||||
|
||||
/* Make sure these names continue to agree with what's in smatch.c */
|
||||
extern char *glob_patscan PARAMS((char *, char *, int));
|
||||
extern wchar_t *glob_patscan_wc PARAMS((wchar_t *, wchar_t *, int));
|
||||
extern char *glob_patscan PARAMS((char *, char *, int, int));
|
||||
extern wchar_t *glob_patscan_wc PARAMS((wchar_t *, wchar_t *, wint_t, int));
|
||||
|
||||
/* And this from gmisc.c/gm_loop.c */
|
||||
extern int wextglob_pattern_p PARAMS((wchar_t *));
|
||||
@@ -207,7 +207,7 @@ extglob_skipname (pat, dname, flags)
|
||||
wild = *pat == '*' || *pat == '?';
|
||||
pp = pat + 2;
|
||||
se = pp + strlen (pp); /* end of pattern string */
|
||||
pe = glob_patscan (pp, se, 0); /* end of extglob pattern */
|
||||
pe = glob_patscan (pp, se, 0, 0); /* end of extglob pattern */
|
||||
|
||||
/* if pe == 0, this is an invalid extglob pattern */
|
||||
if (pe == 0)
|
||||
@@ -234,7 +234,7 @@ extglob_skipname (pat, dname, flags)
|
||||
nullpat = pe >= (pat + 2) && pe[-2] == '(' && pe[-1] == ')';
|
||||
|
||||
/* check every subpattern */
|
||||
while (t = glob_patscan (pp, pe, '|'))
|
||||
while (t = glob_patscan (pp, pe, '|', 0))
|
||||
{
|
||||
/* If T == PE and *T == 0 (&& PE[-1] == RPAREN), we have hit the end
|
||||
of a pattern with no trailing characters. */
|
||||
@@ -358,7 +358,7 @@ wextglob_skipname (pat, dname, flags)
|
||||
wild = *pat == L'*' || *pat == L'?';
|
||||
pp = pat + 2;
|
||||
se = pp + wcslen (pp);
|
||||
pe = glob_patscan_wc (pp, se, 0);
|
||||
pe = glob_patscan_wc (pp, se, 0, 0);
|
||||
|
||||
/* if pe == 0, this is an invalid extglob pattern */
|
||||
if (pe == 0)
|
||||
@@ -382,7 +382,7 @@ wextglob_skipname (pat, dname, flags)
|
||||
nullpat = pe >= (pat + 2) && pe[-2] == L'(' && pe[-1] == L')';
|
||||
|
||||
/* check every subpattern */
|
||||
while (t = glob_patscan_wc (pp, pe, '|'))
|
||||
while (t = glob_patscan_wc (pp, pe, '|', 0))
|
||||
{
|
||||
n = t[-1]; /* ( */
|
||||
if (wextglob_pattern_p (pp) && n == L')') /* nested extglob? */
|
||||
|
||||
+2
-2
@@ -38,7 +38,7 @@
|
||||
#include "glob.h"
|
||||
|
||||
/* Make sure these names continue to agree with what's in smatch.c */
|
||||
extern char *glob_patscan PARAMS((char *, char *, int));
|
||||
extern char *glob_patscan PARAMS((char *, char *, int, int));
|
||||
|
||||
/* Compile `gm_loop.c' for single-byte characters. */
|
||||
#define CHAR char
|
||||
@@ -92,7 +92,7 @@ glob_dirscan (pat, dirsep)
|
||||
{
|
||||
if (se == 0)
|
||||
se = p + strlen (p) - 1;
|
||||
pe = glob_patscan (p + 2, se, 0);
|
||||
pe = glob_patscan (p + 2, se, 0, 0);
|
||||
if (pe == 0)
|
||||
continue;
|
||||
else if (*pe == 0)
|
||||
|
||||
+79
-122
@@ -27,13 +27,13 @@ struct STRUCT
|
||||
int FCT PARAMS((CHAR *, CHAR *, int));
|
||||
|
||||
static int GMATCH PARAMS((CHAR *, CHAR *, CHAR *, CHAR *, struct STRUCT *, int));
|
||||
static CHAR *PARSE_COLLSYM PARAMS((CHAR *, INT *));
|
||||
static inline CHAR *PARSE_SUBBRACKET PARAMS((CHAR *, int));
|
||||
static CHAR *BRACKMATCH PARAMS((CHAR *, U_CHAR, int));
|
||||
static int EXTMATCH PARAMS((INT, CHAR *, CHAR *, CHAR *, CHAR *, int));
|
||||
|
||||
extern void DEQUOTE_PATHNAME PARAMS((CHAR *));
|
||||
|
||||
/*static*/ CHAR *PATSCAN PARAMS((CHAR *, CHAR *, INT));
|
||||
/*static*/ CHAR *PATSCAN PARAMS((CHAR *, CHAR *, INT, int));
|
||||
|
||||
int
|
||||
FCT (pattern, string, flags)
|
||||
@@ -192,7 +192,7 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
|
||||
that's OK, since we can match 0 or 1 occurrences.
|
||||
We need to skip the glob pattern and see if we
|
||||
match the rest of the string. */
|
||||
newn = PATSCAN (p + 1, pe, 0);
|
||||
newn = PATSCAN (p + 1, pe, 0, flags);
|
||||
/* If NEWN is 0, we have an ill-formed pattern. */
|
||||
p = newn ? newn : pe;
|
||||
}
|
||||
@@ -225,7 +225,7 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
|
||||
that's OK, since we can match 0 or more occurrences.
|
||||
We need to skip the glob pattern and see if we
|
||||
match the rest of the string. */
|
||||
newn = PATSCAN (p + 1, pe, 0);
|
||||
newn = PATSCAN (p + 1, pe, 0, flags);
|
||||
/* If NEWN is 0, we have an ill-formed pattern. */
|
||||
p = newn ? newn : pe;
|
||||
}
|
||||
@@ -380,36 +380,28 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
|
||||
/* Parse a bracket expression collating symbol ([.sym.]) starting at P, find
|
||||
the value of the symbol, and move P past the collating symbol expression.
|
||||
The value is returned in *VP, if VP is not null. */
|
||||
static CHAR *
|
||||
PARSE_COLLSYM (p, vp)
|
||||
CHAR *p;
|
||||
INT *vp;
|
||||
{
|
||||
register int pc;
|
||||
INT val;
|
||||
|
||||
p++; /* move past the `.' */
|
||||
|
||||
for (pc = 0; p[pc]; pc++)
|
||||
if (p[pc] == L('.') && p[pc+1] == L(']'))
|
||||
break;
|
||||
if (p[pc] == 0)
|
||||
{
|
||||
if (vp)
|
||||
*vp = INVALID;
|
||||
return (p + pc);
|
||||
}
|
||||
val = COLLSYM (p, pc);
|
||||
if (vp)
|
||||
*vp = val;
|
||||
return (p + pc + 2);
|
||||
}
|
||||
|
||||
#define SLASH_PATHNAME(c) (c == L('/') && (flags & FNM_PATHNAME))
|
||||
|
||||
/* Parse a special bracket expression symbol ([.sym.], [=char=], [:cclass:]),
|
||||
starting at P, and return the position of the terminating .], =], or :].
|
||||
P points to the character after the opening bracket. Returns NULL if the
|
||||
symbol isn't correctly terminated. */
|
||||
static inline CHAR *
|
||||
PARSE_SUBBRACKET (p, flags)
|
||||
CHAR *p;
|
||||
int flags;
|
||||
{
|
||||
CHAR type; /* the type of special bracket expression symbol */
|
||||
|
||||
type = *p;
|
||||
|
||||
/* POSIX allows a right bracket to appear in a collating symbol. */
|
||||
while (*++p != L('\0') && SLASH_PATHNAME (*p) == 0 && (type != L('.') && *p == L(']')) == 0)
|
||||
if (*p == type && p[1] == L(']'))
|
||||
return p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Use prototype definition here because of type promotion. */
|
||||
static CHAR *
|
||||
#if defined (PROTOTYPES)
|
||||
@@ -423,10 +415,10 @@ 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, isrange;
|
||||
int forcecoll, isrange;
|
||||
INT pc;
|
||||
CHAR *savep;
|
||||
CHAR *brchrp;
|
||||
CHAR *close;
|
||||
U_CHAR orig_test;
|
||||
|
||||
orig_test = test;
|
||||
@@ -451,18 +443,13 @@ BRACKMATCH (p, test, flags)
|
||||
|
||||
/* POSIX.2 equivalence class: [=c=]. See POSIX.2 2.8.3.2. Find
|
||||
the end of the equivalence class, move the pattern pointer past
|
||||
it, and check for equivalence. XXX - this handles only
|
||||
single-character equivalence classes, which is wrong, or at
|
||||
least incomplete. */
|
||||
if (c == L('[') && *p == L('=') && p[2] == L('=') && p[3] == L(']'))
|
||||
it, and check for equivalence. */
|
||||
if (c == L('[') && *p == L('=') && (close = PARSE_SUBBRACKET (p, flags)) != NULL)
|
||||
{
|
||||
pc = FOLD (p[1]);
|
||||
p += 4;
|
||||
|
||||
/* Finding a slash in a bracket expression means you have to
|
||||
match the bracket as an ordinary character (see below). */
|
||||
if (pc == L('/') && (flags & FNM_PATHNAME))
|
||||
return ((test == L('[')) ? savep : (CHAR *)0); /*]*/
|
||||
p++;
|
||||
pc = COLLSYM (p, close - p);
|
||||
pc = FOLD (pc);
|
||||
p = close + 2;
|
||||
|
||||
if (COLLEQUIV (test, pc))
|
||||
{
|
||||
@@ -486,30 +473,21 @@ BRACKMATCH (p, test, flags)
|
||||
}
|
||||
|
||||
/* POSIX.2 character class expression. See POSIX.2 2.8.3.2. */
|
||||
if (c == L('[') && *p == L(':'))
|
||||
if (c == L('[') && *p == L(':') && (close = PARSE_SUBBRACKET (p, flags)) != NULL)
|
||||
{
|
||||
CHAR *close, *ccname;
|
||||
CHAR *ccname;
|
||||
|
||||
pc = 0; /* make sure invalid char classes don't match. */
|
||||
/* Find end of character class name */
|
||||
for (close = p + 1; *close != '\0' && SLASH_PATHNAME(*close) == 0; close++)
|
||||
if (*close == L(':') && *(close+1) == L(']'))
|
||||
break;
|
||||
|
||||
if (*close != L('\0') && SLASH_PATHNAME(*close) == 0)
|
||||
ccname = (CHAR *)malloc ((close - p) * sizeof (CHAR));
|
||||
if (ccname)
|
||||
{
|
||||
ccname = (CHAR *)malloc ((close - p) * sizeof (CHAR));
|
||||
if (ccname == 0)
|
||||
pc = 0;
|
||||
else
|
||||
{
|
||||
bcopy (p + 1, ccname, (close - p - 1) * sizeof (CHAR));
|
||||
*(ccname + (close - p - 1)) = L('\0');
|
||||
/* As a result of a POSIX discussion, char class names are
|
||||
allowed to be quoted (?) */
|
||||
DEQUOTE_PATHNAME (ccname);
|
||||
pc = IS_CCLASS (orig_test, (XCHAR *)ccname);
|
||||
}
|
||||
bcopy (p + 1, ccname, (close - p - 1) * sizeof (CHAR));
|
||||
*(ccname + (close - p - 1)) = L('\0');
|
||||
/* As a result of a POSIX discussion, char class names are
|
||||
allowed to be quoted (?) */
|
||||
DEQUOTE_PATHNAME (ccname);
|
||||
pc = IS_CCLASS (orig_test, (XCHAR *)ccname);
|
||||
if (pc == -1)
|
||||
{
|
||||
/* CCNAME is not a valid character class in the current
|
||||
@@ -521,14 +499,12 @@ BRACKMATCH (p, test, flags)
|
||||
string. If we don't want to do that, take out the update
|
||||
of P. */
|
||||
pc = 0;
|
||||
p = close + 2;
|
||||
}
|
||||
else
|
||||
p = close + 2; /* move past the closing `]' */
|
||||
|
||||
free (ccname);
|
||||
}
|
||||
|
||||
free (ccname);
|
||||
|
||||
p = close + 2;
|
||||
|
||||
if (pc)
|
||||
{
|
||||
/*[*/ /* Move past the closing `]', since the first thing we do at
|
||||
@@ -556,13 +532,11 @@ BRACKMATCH (p, test, flags)
|
||||
the symbol name, make sure it is terminated by `.]', translate
|
||||
the name to a character using the external table, and do the
|
||||
comparison. */
|
||||
if (c == L('[') && *p == L('.'))
|
||||
if (c == L('[') && *p == L('.') && (close = PARSE_SUBBRACKET (p, flags)) != NULL)
|
||||
{
|
||||
p = PARSE_COLLSYM (p, &pc);
|
||||
/* An invalid collating symbol cannot be the first point of a
|
||||
range. If it is, we set cstart to one greater than `test',
|
||||
so any comparisons later will fail. */
|
||||
cstart = (pc == INVALID) ? test + 1 : pc;
|
||||
p++;
|
||||
cstart = COLLSYM (p, close - p);
|
||||
p = close + 2;
|
||||
forcecoll = 1;
|
||||
}
|
||||
|
||||
@@ -616,13 +590,11 @@ BRACKMATCH (p, test, flags)
|
||||
return ((test == L('[')) ? savep : (CHAR *)0);
|
||||
else if (cend == L('/') && (flags & FNM_PATHNAME))
|
||||
return ((test == L('[')) ? savep : (CHAR *)0);
|
||||
if (cend == L('[') && *p == L('.'))
|
||||
if (cend == L('[') && *p == L('.') && (close = PARSE_SUBBRACKET (p, flags)) != NULL)
|
||||
{
|
||||
p = PARSE_COLLSYM (p, &pc);
|
||||
/* An invalid collating symbol cannot be the second part of a
|
||||
range expression. If we get one, we set cend to one fewer
|
||||
than the test character to make sure the range test fails. */
|
||||
cend = (pc == INVALID) ? test - 1 : pc;
|
||||
p++;
|
||||
cend = COLLSYM (p, close - p);
|
||||
p = close + 2;
|
||||
forcecoll = 1;
|
||||
}
|
||||
cend = FOLD (cend);
|
||||
@@ -658,46 +630,29 @@ BRACKMATCH (p, test, flags)
|
||||
matched:
|
||||
/* Skip the rest of the [...] that already matched. */
|
||||
c = *--p;
|
||||
brcnt = 1;
|
||||
brchrp = 0;
|
||||
while (brcnt > 0)
|
||||
while (1)
|
||||
{
|
||||
int oc;
|
||||
|
||||
/* A `[' without a matching `]' is just another character to match. */
|
||||
if (c == L('\0'))
|
||||
return ((test == L('[')) ? savep : (CHAR *)0);
|
||||
else if (c == L('/') && (flags & FNM_PATHNAME))
|
||||
return ((test == L('[')) ? savep : (CHAR *)0);
|
||||
|
||||
oc = c;
|
||||
c = *p++;
|
||||
if (c == L('[') && (*p == L('=') || *p == L(':') || *p == L('.')))
|
||||
{
|
||||
brcnt++;
|
||||
brchrp = p++; /* skip over the char after the left bracket */
|
||||
c = *p;
|
||||
if (c == L('\0'))
|
||||
return ((test == L('[')) ? savep : (CHAR *)0);
|
||||
else if (c == L('/') && (flags & FNM_PATHNAME))
|
||||
return ((test == L('[')) ? savep : (CHAR *)0);
|
||||
/* If *brchrp == ':' we should check that the rest of the characters
|
||||
form a valid character class name. We don't do that yet, but we
|
||||
keep BRCHRP in case we want to. */
|
||||
}
|
||||
/* We only want to check brchrp if we set it above. */
|
||||
else if (c == L(']') && brcnt > 1 && brchrp != 0 && oc == *brchrp)
|
||||
{
|
||||
brcnt--;
|
||||
brchrp = 0; /* just in case */
|
||||
if ((close = PARSE_SUBBRACKET (p, flags)) != NULL)
|
||||
p = close + 2;
|
||||
}
|
||||
/* Left bracket loses its special meaning inside a bracket expression.
|
||||
It is only valid when followed by a `.', `=', or `:', which we check
|
||||
for above. Technically the right bracket can appear in a collating
|
||||
symbol, so we check for that here. Otherwise, it terminates the
|
||||
bracket expression. */
|
||||
else if (c == L(']') && (brchrp == 0 || *brchrp != L('.')) && brcnt >= 1)
|
||||
brcnt = 0;
|
||||
symbol, so we check for that as well. The right brackets terminating
|
||||
collating symbols, equivalence classes, or character classes are
|
||||
processed by PARSE_SUBBRACKET. Otherwise, a right bracket terminates
|
||||
the bracket expression. */
|
||||
else if (c == L(']'))
|
||||
break;
|
||||
else if (!(flags & FNM_NOESCAPE) && c == L('\\'))
|
||||
{
|
||||
if (*p == '\0')
|
||||
@@ -734,16 +689,15 @@ matched:
|
||||
first character after the matching DELIM or NULL if the pattern is
|
||||
empty or invalid. */
|
||||
/*static*/ CHAR *
|
||||
PATSCAN (string, end, delim)
|
||||
PATSCAN (string, end, delim, flags)
|
||||
CHAR *string, *end;
|
||||
INT delim;
|
||||
int flags;
|
||||
{
|
||||
int pnest, bnest, skip;
|
||||
INT cchar;
|
||||
CHAR *s, c, *bfirst;
|
||||
CHAR *s, c, *bfirst, *t;
|
||||
|
||||
pnest = bnest = skip = 0;
|
||||
cchar = 0;
|
||||
bfirst = NULL;
|
||||
|
||||
if (string == end)
|
||||
@@ -761,7 +715,8 @@ PATSCAN (string, end, delim)
|
||||
switch (c)
|
||||
{
|
||||
case L('\\'):
|
||||
skip = 1;
|
||||
if ((flags & FNM_NOESCAPE) == 0)
|
||||
skip = 1;
|
||||
break;
|
||||
|
||||
case L('\0'):
|
||||
@@ -779,7 +734,11 @@ PATSCAN (string, end, delim)
|
||||
bnest++;
|
||||
}
|
||||
else if (s[1] == L(':') || s[1] == L('.') || s[1] == L('='))
|
||||
cchar = s[1];
|
||||
{
|
||||
t = PARSE_SUBBRACKET (s + 1, flags);
|
||||
if (t)
|
||||
s = t + 2 - 1; /* -1 to cancel s++ in loop above */
|
||||
}
|
||||
break;
|
||||
|
||||
/* `]' is not special if it's the first char (after a leading `!'
|
||||
@@ -788,9 +747,7 @@ PATSCAN (string, end, delim)
|
||||
case L(']'):
|
||||
if (bnest)
|
||||
{
|
||||
if (cchar && s[-1] == cchar)
|
||||
cchar = 0;
|
||||
else if (s != bfirst)
|
||||
if (s != bfirst)
|
||||
{
|
||||
bnest--;
|
||||
bfirst = 0;
|
||||
@@ -879,7 +836,7 @@ fprintf(stderr, "extmatch: p = %s; pe = %s\n", p, pe);
|
||||
fprintf(stderr, "extmatch: flags = %d\n", flags);
|
||||
#endif
|
||||
|
||||
prest = PATSCAN (p + (*p == L('(')), pe, 0); /* ) */
|
||||
prest = PATSCAN (p + (*p == L('(')), pe, 0, flags); /* ) */
|
||||
if (prest == 0)
|
||||
/* If PREST is 0, we failed to scan a valid pattern. In this
|
||||
case, we just want to compare the two as strings. */
|
||||
@@ -902,7 +859,7 @@ fprintf(stderr, "extmatch: flags = %d\n", flags);
|
||||
string. */
|
||||
for (psub = p + 1; ; psub = pnext)
|
||||
{
|
||||
pnext = PATSCAN (psub, pe, L('|'));
|
||||
pnext = PATSCAN (psub, pe, L('|'), flags);
|
||||
for (srest = s; srest <= se; srest++)
|
||||
{
|
||||
/* Match this substring (S -> SREST) against this
|
||||
@@ -939,7 +896,7 @@ fprintf(stderr, "extmatch: flags = %d\n", flags);
|
||||
rest of the string. */
|
||||
for (psub = p + 1; ; psub = pnext)
|
||||
{
|
||||
pnext = PATSCAN (psub, pe, L('|'));
|
||||
pnext = PATSCAN (psub, pe, L('|'), flags);
|
||||
srest = (prest == pe) ? se : s;
|
||||
for ( ; srest <= se; srest++)
|
||||
{
|
||||
@@ -960,7 +917,7 @@ fprintf(stderr, "extmatch: flags = %d\n", flags);
|
||||
m1 = 0;
|
||||
for (psub = p + 1; ; psub = pnext)
|
||||
{
|
||||
pnext = PATSCAN (psub, pe, L('|'));
|
||||
pnext = PATSCAN (psub, pe, L('|'), flags);
|
||||
/* If one of the patterns matches, just bail immediately. */
|
||||
if (m1 = (GMATCH (s, srest, psub, pnext - 1, NULL, flags) == 0))
|
||||
break;
|
||||
@@ -1001,7 +958,7 @@ fprintf(stderr, "extmatch: flags = %d\n", flags);
|
||||
#undef FCT
|
||||
#undef GMATCH
|
||||
#undef COLLSYM
|
||||
#undef PARSE_COLLSYM
|
||||
#undef PARSE_SUBBRACKET
|
||||
#undef PATSCAN
|
||||
#undef STRCOMPARE
|
||||
#undef EXTMATCH
|
||||
|
||||
+2
-2
@@ -322,7 +322,7 @@ is_cclass (c, name)
|
||||
#define FCT internal_strmatch
|
||||
#define GMATCH gmatch
|
||||
#define COLLSYM collsym
|
||||
#define PARSE_COLLSYM parse_collsym
|
||||
#define PARSE_SUBBRACKET parse_subbracket
|
||||
#define BRACKMATCH brackmatch
|
||||
#define PATSCAN glob_patscan
|
||||
#define STRCOMPARE strcompare
|
||||
@@ -578,7 +578,7 @@ posix_cclass_only (pattern)
|
||||
#define FCT internal_wstrmatch
|
||||
#define GMATCH gmatch_wc
|
||||
#define COLLSYM collwcsym
|
||||
#define PARSE_COLLSYM parse_collwcsym
|
||||
#define PARSE_SUBBRACKET parse_subbracket_wc
|
||||
#define BRACKMATCH brackmatch_wc
|
||||
#define PATSCAN glob_patscan_wc
|
||||
#define STRCOMPARE wscompare
|
||||
|
||||
@@ -3394,9 +3394,9 @@ _rl_update_final (void)
|
||||
puts_face (&last_line[_rl_screenwidth - 1 + woff],
|
||||
&last_face[_rl_screenwidth - 1 + woff], 1);
|
||||
}
|
||||
_rl_vis_botlin = 0;
|
||||
if (botline_length > 0 || _rl_last_c_pos > 0)
|
||||
if ((_rl_vis_botlin == 0 && botline_length == 0) || botline_length > 0 || _rl_last_c_pos > 0)
|
||||
rl_crlf ();
|
||||
_rl_vis_botlin = 0;
|
||||
fflush (rl_outstream);
|
||||
rl_display_fixed++;
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,6 +25,6 @@
|
||||
regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
|
||||
looks for to find the patch level (for the sccs version string). */
|
||||
|
||||
#define PATCHLEVEL 9
|
||||
#define PATCHLEVEL 12
|
||||
|
||||
#endif /* _PATCHLEVEL_H_ */
|
||||
|
||||
@@ -9,7 +9,7 @@ msgstr ""
|
||||
"Project-Id-Version: bash-5.2-rc1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-01-11 14:50-0500\n"
|
||||
"PO-Revision-Date: 2022-06-25 01:50+0900\n"
|
||||
"PO-Revision-Date: 2022-11-29 14:23+0900\n"
|
||||
"Last-Translator: Seong-ho Cho <darkcircle.0426@gmail.com>\n"
|
||||
"Language-Team: Korean <translation-team-ko@googlegroups.com>\n"
|
||||
"Language: ko\n"
|
||||
@@ -566,7 +566,7 @@ msgstr ""
|
||||
"셸에 대한 일반적인 정보를 더 확인하려면 `info bash'를 사용하십시오.\n"
|
||||
"이 목록에 없는 명령어에 대해 더 알아보려면 `man -k' 또는 `info'를 사용하십시오.\n"
|
||||
"\n"
|
||||
"명령어 이름 다음의 별(*) 표시는 해당 명령어의 비활성 상태을 의미합니다.\n"
|
||||
"명령어 이름 다음의 별(*) 표시는 해당 명령어를 사용하지 않음을 의미합니다.\n"
|
||||
"\n"
|
||||
|
||||
#: builtins/history.def:159
|
||||
@@ -1737,7 +1737,7 @@ msgstr "셸 옵션:\n"
|
||||
|
||||
#: shell.c:2069
|
||||
msgid "\t-ilrsD or -c command or -O shopt_option\t\t(invocation only)\n"
|
||||
msgstr "\t-ilrsD 또는 -c <명령> 또는 -O shopt_option\t\t(invocation 전용)\n"
|
||||
msgstr "\t-ilrsD 또는 -c <명령> 또는 -O <shopt_옵션>\t\t(실행 전용)\n"
|
||||
|
||||
#: shell.c:2088
|
||||
#, c-format
|
||||
@@ -2289,7 +2289,7 @@ msgstr "eval [인자 ...]"
|
||||
|
||||
#: builtins.c:96
|
||||
msgid "getopts optstring name [arg ...]"
|
||||
msgstr "getopts optstring name [<인자> ...]"
|
||||
msgstr "getopts <옵션문자열> <이름> [<인자> ...]"
|
||||
|
||||
#: builtins.c:98
|
||||
msgid "exec [-cl] [-a name] [command [argument ...]] [redirection ...]"
|
||||
@@ -2309,11 +2309,11 @@ msgstr "fc [-e <편집기이름>] [-lnr] [<처음>] [<종결>] 또는 fc -s [<
|
||||
|
||||
#: builtins.c:109
|
||||
msgid "fg [job_spec]"
|
||||
msgstr "fg [<JOBSPEC>]"
|
||||
msgstr "fg [<작업명세>]"
|
||||
|
||||
#: builtins.c:113
|
||||
msgid "bg [job_spec ...]"
|
||||
msgstr "bg [<JOBSPEC> ...]"
|
||||
msgstr "bg [<작업명세> ...]"
|
||||
|
||||
#: builtins.c:116
|
||||
msgid "hash [-lr] [-p pathname] [-dt] [name ...]"
|
||||
@@ -2329,15 +2329,15 @@ msgstr "history [-c] [-d <오프셋>] [n] 또는 history -anrw [<파일이름>]
|
||||
|
||||
#: builtins.c:127
|
||||
msgid "jobs [-lnprs] [jobspec ...] or jobs -x command [args]"
|
||||
msgstr "jobs [-lnprs] [jobspec ...] 또는 jobs -x command [args]"
|
||||
msgstr "jobs [-lnprs] [<작업명세> ...] 또는 jobs -x <명령> [<인자> ...]"
|
||||
|
||||
#: builtins.c:131
|
||||
msgid "disown [-h] [-ar] [jobspec ... | pid ...]"
|
||||
msgstr "disown [-h] [-ar] [<JOBSPEC> ... | <PID> ...]"
|
||||
msgstr "disown [-h] [-ar] [<작업명세> ... | <PID> ...]"
|
||||
|
||||
#: builtins.c:134
|
||||
msgid "kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]"
|
||||
msgstr "kill [-s <시그널명세> | -n <시그널번호> | -<시그널명세>] <PID> | <JOBSPEC> ... 또는 kill -l [<시그널명세>]"
|
||||
msgstr "kill [-s <시그널명세> | -n <시그널번호> | -<시그널명세>] <PID> | <작업명세> ... 또는 kill -l [<시그널명세>]"
|
||||
|
||||
#: builtins.c:136
|
||||
msgid "let arg [arg ...]"
|
||||
@@ -5057,8 +5057,7 @@ msgstr ""
|
||||
" HOME\t로그인 후 접근하는 완전한 경로 이름입니다.\n"
|
||||
" HOSTNAME\t현재 호스트 이름입니다.\n"
|
||||
" HOSTTYPE\t이 배시 버전이 실행하고 있는 시스템의 CPU 형식입니다.\n"
|
||||
" IGNOREEOF\n"
|
||||
"EOF 문자 입력을 유일한 입력으로 받는 셸의 동작을\n"
|
||||
" IGNOREEOF\tEOF 문자 입력을 유일한 입력으로 받는 셸의 동작을\n"
|
||||
" \t\t제어합니다. 설정하면, 이 변수의 값은 셸을 나가기\n"
|
||||
" \t\t전 빈 줄에 한줄로 나타낼 EOF 문자 수 입니다 (기본 10개).\n"
|
||||
" \t\t설정을 해제하면, EOF는 입력 끝을 나타냅니다.\n"
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
--- $GLOBIGNORE vs fnmatch(3) ---
|
||||
#1: pat=ab/cd/efg yes/yes
|
||||
#2: pat=ab[/]cd/efg no/no
|
||||
#3: pat=ab[/a]cd/efg no/no
|
||||
#4: pat=ab[a/]cd/efg no/no
|
||||
#5: pat=ab[!a]cd/efg no/no
|
||||
#6: pat=ab[.-0]cd/efg no/no
|
||||
#7: pat=*/*/efg yes/yes
|
||||
#8: pat=*[/]*/efg no/no
|
||||
#9: pat=*[/a]*/efg no/no
|
||||
#10: pat=*[a/]*/efg no/no
|
||||
#11: pat=*[!a]*/efg no/no
|
||||
#12: pat=*[.-0]*/efg no/no
|
||||
#13: pat=*/*/efg yes/yes
|
||||
#14: pat=*[b]/*/efg yes/yes
|
||||
#15: pat=*[ab]/*/efg yes/yes
|
||||
#16: pat=*[ba]/*/efg yes/yes
|
||||
#17: pat=*[!a]/*/efg yes/yes
|
||||
#18: pat=*[a-c]/*/efg yes/yes
|
||||
#19: pat=ab@(/)cd/efg no/no
|
||||
#20: pat=*@(/)cd/efg no/no
|
||||
#21: pat=*/cd/efg yes/yes
|
||||
|
||||
---Tests for a slash in bracket expressions---
|
||||
#22: pat=ab[/]ef str=ab[/]ef yes/yes
|
||||
#23: pat=ab[/]ef str=ab/ef no/no
|
||||
#24: pat=ab[c/d]ef str=ab[c/d]ef yes/yes
|
||||
#25: pat=ab[c/d]ef str=abcef no/no
|
||||
#26: pat=ab[.-/]ef str=ab[.-/]ef yes/yes
|
||||
#27: pat=ab[.-/]ef str=ab.ef no/no
|
||||
#28: pat=ab[[=/=]]ef str=ab[[=/=]]ef yes/yes
|
||||
#29: pat=ab[[=/=]]ef str=ab/ef no/no
|
||||
#30: pat=ab[[=c=]/]ef str=ab[=/]ef yes/yes
|
||||
#31: pat=ab[[=c=]/]ef str=abcef no/no
|
||||
#32: pat=ab[[:alpha:]/]ef str=ab[:/]ef yes/yes
|
||||
#33: pat=ab[[:alpha:]/]ef str=abxef no/no
|
||||
#34: pat=ab[/[abc]]ef str=ab[/c]ef yes/yes
|
||||
#35: pat=ab[/[abc]]ef str=abc]ef no/no
|
||||
#36: pat=ab[c[=/=]]ef str=ab[c[=/=]]ef yes/yes
|
||||
#37: pat=ab[c[=/=]]ef str=abc[=/=]ef no/no
|
||||
#38: pat=ab[c[=/=]]ef str=abcef no/no
|
||||
#39: pat=a[b\/c] str=a[b/c] yes/yes
|
||||
#40: pat=a[b\/c] str=ab no/no
|
||||
#41: pat=a[b\/c] str=ac no/no
|
||||
|
||||
---Tests for incomplete bracket expressions---
|
||||
#42: pat=ab[c str=ab[c yes/yes
|
||||
#43: pat=ab[c str=abc no/no
|
||||
#44: pat=ab[c[=d= str=ab[c[=d= yes/yes
|
||||
#45: pat=ab[c[=d= str=abc no/no
|
||||
#46: pat=ab[c[.d str=ab[c[.d yes/yes
|
||||
#47: pat=ab[c[.d str=abc no/no
|
||||
#48: pat=ab[c[:alpha: str=ab[c[:alpha: yes/yes
|
||||
#49: pat=ab[c[:alpha: str=abc no/no
|
||||
#50: pat=ab[c- str=ab[c- yes/yes
|
||||
#51: pat=ab[c- str=abc no/no
|
||||
#52: pat=ab[c\ str=ab[c\ yes/yes
|
||||
#53: pat=ab[c\ str=abc no/no
|
||||
#54: pat=ab[[\ str=ab[[\ yes/yes
|
||||
#55: pat=ab[[\ str=ab[ no/no
|
||||
|
||||
--- PATSCAN vs BRACKMATCH ---
|
||||
#56: pat=@([[.].])A]) str=] yes/yes
|
||||
#57: pat=@([[.].])A]) str===]A]) no/no
|
||||
#58: pat=@([[.].])A]) str=AA]) no/no
|
||||
#59: pat=@([[=]=])A]) str=] no/no
|
||||
#60: pat=@([[=]=])A]) str===]A]) yes/yes
|
||||
#61: pat=@([[=]=])A]) str=AA]) no/no
|
||||
|
||||
--- BRACKMATCH: after match vs before match ---
|
||||
#62: pat=[[=]=]ab] str=a no/no
|
||||
#63: pat=[[.[=.]ab] str=a yes/yes
|
||||
#64: pat=[[.[==].]ab] str=a yes/yes
|
||||
|
||||
#65: pat=[a[=]=]b] str=a no/no
|
||||
#66: pat=[a[.[=.]b] str=a yes/yes
|
||||
#67: pat=[a[.[==].]b] str=a yes/yes
|
||||
|
||||
#68: pat=[a[=]=]b] str=b no/no
|
||||
#69: pat=[a[=]=]b] str=a=]b] yes/yes
|
||||
#70: pat=[a[.[=.]b] str=b yes/yes
|
||||
#71: pat=[a[.[=.]b] str=ab] no/no
|
||||
#72: pat=[a[.[==].]b] str=b yes/yes
|
||||
#73: pat=[a[.[==].]b] str=ab] no/no
|
||||
|
||||
--- incomplete POSIX brackets ---
|
||||
#74: pat=x[a[:y] str=x[ yes/yes
|
||||
#75: pat=x[a[:y] str=x: yes/yes
|
||||
#76: pat=x[a[:y] str=xy yes/yes
|
||||
#77: pat=x[a[:y] str=x[ay no/no
|
||||
|
||||
#78: pat=x[a[.y] str=x[ yes/yes
|
||||
#79: pat=x[a[.y] str=x. yes/yes
|
||||
#80: pat=x[a[.y] str=xy yes/yes
|
||||
#81: pat=x[a[.y] str=x[ay no/no
|
||||
|
||||
#82: pat=x[a[=y] str=x[ yes/yes
|
||||
#83: pat=x[a[=y] str=x= yes/yes
|
||||
#84: pat=x[a[=y] str=xy yes/yes
|
||||
#85: pat=x[a[=y] str=x[ay no/no
|
||||
|
||||
--- MISC tests ---
|
||||
#86: pat=a\ str=a\ yes/yes
|
||||
@@ -0,0 +1,291 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# tests of various aspects of pathname expansion, mostly dealing with bracket
|
||||
# expressions
|
||||
|
||||
LC_COLLATE=C
|
||||
|
||||
ORIG_DIR=$PWD
|
||||
|
||||
: ${TMPDIR:=/tmp} ${BUILD_DIR:=$ORIG_DIR}
|
||||
|
||||
trap 'rm -rf $TESTDIR $WORK_DIR' EXIT
|
||||
|
||||
WORK_DIR=${TMPDIR}/globtest-$$
|
||||
|
||||
mkdir $WORK_DIR || {
|
||||
echo "cannot create directory $WORK_DIR" >&2
|
||||
exit 1
|
||||
}
|
||||
cd $WORK_DIR || {
|
||||
echo "cannot cd to directory $WORK_DIR" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
gcc -O2 -xc -o ./fnmatch - <<-EOF
|
||||
#include <fnmatch.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (2 >= argc) {
|
||||
fprintf(stderr, "usage: fnmatch string pattern\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
#ifdef FNM_EXTMATCH
|
||||
int flags = FNM_PATHNAME | FNM_PERIOD | FNM_EXTMATCH;
|
||||
#else
|
||||
int flags = FNM_PATHNAME | FNM_PERIOD;
|
||||
#endif
|
||||
if (fnmatch(argv[2], argv[1], flags) == 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
EOF
|
||||
|
||||
eval $(grep -E '^(CC |SHOBJ_).*=' $BUILD_DIR/examples/loadables/Makefile | sed -e 's/[ ]*=[ ]*/="/' -e 's/$/"/' )
|
||||
|
||||
if [ "$SHOBJ_STATUS" != "supported" ]; then
|
||||
echo "glob-bracket: shared objects not supported, cannot continue" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
cat > ./strmatch.c <<-EOF
|
||||
#define BUILTIN_ENABLED 0x01
|
||||
struct word_desc { char* word; int flags; };
|
||||
struct word_list { struct word_list* next; struct word_desc* word; };
|
||||
struct builtin {
|
||||
const char* name;
|
||||
int (*function)(struct word_list*);
|
||||
int flags;
|
||||
const char** long_doc;
|
||||
const char* short_doc;
|
||||
char* handle;
|
||||
};
|
||||
|
||||
/*#include <glob/strmatch.h>*/
|
||||
int strmatch(char *pattern, char *string, int flags);
|
||||
#define FNM_PATHNAME (1 << 0)
|
||||
#define FNM_NOESCAPE (1 << 1)
|
||||
#define FNM_PERIOD (1 << 2)
|
||||
#define FNM_LEADING_DIR (1 << 3)
|
||||
#define FNM_CASEFOLD (1 << 4)
|
||||
#define FNM_EXTMATCH (1 << 5)
|
||||
#define FNM_FIRSTCHAR (1 << 6)
|
||||
#define FNM_DOTDOT (1 << 7)
|
||||
|
||||
static int strmatch_builtin(struct word_list* list) {
|
||||
char *str, *pat;
|
||||
if (!list || !list->word) return 2;
|
||||
str = list->word->word;
|
||||
if (!list->next || !list->next->word) return 2;
|
||||
pat = list->next->word->word;
|
||||
|
||||
if (strmatch (pat, str, FNM_PATHNAME | FNM_PERIOD | FNM_EXTMATCH) == 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
static const char* strmatch_doc[] = { "This is a builtin to test the behavior of strmatch", 0 };
|
||||
struct builtin strmatch_struct = { "strmatch", strmatch_builtin, BUILTIN_ENABLED, strmatch_doc, "strmatch string pattern", 0, };
|
||||
EOF
|
||||
|
||||
${SHOBJ_CC} ${SHOBJ_CFLAGS} -c -o strmatch.o strmatch.c
|
||||
rm -f strmatch.c
|
||||
|
||||
${SHOBJ_LD} ${SHOBJ_LDFLAGS} ${SHOBJ_XLDFLAGS} -o strmatch.so strmatch.o ${SHOBJ_LIBS}
|
||||
rm -f strmatch.o
|
||||
|
||||
if [ ! -f strmatch.so ] ; then
|
||||
echo "glob-bracket: cannot create strmatch loadable builtin" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
enable -f ./strmatch.so strmatch || {
|
||||
echo "glob-bracket: cannot load strmatch builtin" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
check_count=1
|
||||
|
||||
if [ -z "$BASH_TSTOUT" ]; then
|
||||
yes=$(printf '\033[32myes\033[m') no=$(printf '\033[31mno\033[m')
|
||||
else
|
||||
yes=yes no=no
|
||||
fi
|
||||
|
||||
function check {
|
||||
# bash impl
|
||||
if strmatch "$2" "$1"; then
|
||||
local strmatch=$yes
|
||||
else
|
||||
local strmatch=$no
|
||||
fi
|
||||
|
||||
# fnmatch
|
||||
local expect=${3-}
|
||||
if [[ ! $expect ]]; then
|
||||
if $WORK_DIR/fnmatch "$2" "$1"; then
|
||||
expect=$yes
|
||||
else
|
||||
expect=$no
|
||||
fi
|
||||
fi
|
||||
printf '#%d: pat=%-20s str=%-16s %s/%s\n' "$((check_count++))" "$1" "$2" "$strmatch" "$expect"
|
||||
}
|
||||
|
||||
function pcheck {
|
||||
local GLOBIGNORE=$1
|
||||
|
||||
# bash impl
|
||||
local -a f=(*/*/efg*)
|
||||
if [[ $f == '*/*/efg*' ]]; then
|
||||
local strmatch=$yes
|
||||
else
|
||||
local strmatch=$no
|
||||
fi
|
||||
|
||||
# Linux fnmatch
|
||||
if $WORK_DIR/fnmatch ab/cd/efg "$1"; then
|
||||
local fnmatch=$yes
|
||||
else
|
||||
local fnmatch=$no
|
||||
fi
|
||||
|
||||
printf '#%d: pat=%-16s %s/%s\n' "$((check_count++))" "$1" "$strmatch" "$fnmatch"
|
||||
}
|
||||
|
||||
TESTDIR=${TMPDIR}/pathtest-$$
|
||||
TESTPATH=${TESTDIR}/ab/cd/efg
|
||||
mkdir -p $TESTPATH
|
||||
|
||||
if [ -d "$TESTPATH" ] && cd "$TESTDIR"; then
|
||||
echo '--- $GLOBIGNORE vs fnmatch(3) ---'
|
||||
pcheck 'ab/cd/efg'
|
||||
pcheck 'ab[/]cd/efg'
|
||||
pcheck 'ab[/a]cd/efg'
|
||||
pcheck 'ab[a/]cd/efg'
|
||||
pcheck 'ab[!a]cd/efg'
|
||||
pcheck 'ab[.-0]cd/efg'
|
||||
pcheck '*/*/efg'
|
||||
pcheck '*[/]*/efg'
|
||||
pcheck '*[/a]*/efg'
|
||||
pcheck '*[a/]*/efg'
|
||||
pcheck '*[!a]*/efg'
|
||||
pcheck '*[.-0]*/efg'
|
||||
|
||||
pcheck '*/*/efg'
|
||||
pcheck '*[b]/*/efg'
|
||||
pcheck '*[ab]/*/efg'
|
||||
pcheck '*[ba]/*/efg'
|
||||
pcheck '*[!a]/*/efg'
|
||||
pcheck '*[a-c]/*/efg'
|
||||
|
||||
pcheck 'ab@(/)cd/efg'
|
||||
pcheck '*@(/)cd/efg'
|
||||
pcheck '*/cd/efg'
|
||||
|
||||
cd "$WORK_DIR"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo '---Tests for a slash in bracket expressions---'
|
||||
check 'ab[/]ef' 'ab[/]ef' "$yes"
|
||||
check 'ab[/]ef' 'ab/ef' "$no"
|
||||
check 'ab[c/d]ef' 'ab[c/d]ef' "$yes"
|
||||
check 'ab[c/d]ef' 'abcef' "$no"
|
||||
check 'ab[.-/]ef' 'ab[.-/]ef' "$yes"
|
||||
check 'ab[.-/]ef' 'ab.ef' "$no"
|
||||
check 'ab[[=/=]]ef' 'ab[[=/=]]ef' "$yes"
|
||||
check 'ab[[=/=]]ef' 'ab/ef' "$no"
|
||||
check 'ab[[=c=]/]ef' 'ab[=/]ef' "$yes"
|
||||
check 'ab[[=c=]/]ef' 'abcef' "$no"
|
||||
check 'ab[[:alpha:]/]ef' 'ab[:/]ef' "$yes"
|
||||
check 'ab[[:alpha:]/]ef' 'abxef' "$no"
|
||||
check 'ab[/[abc]]ef' 'ab[/c]ef' "$yes"
|
||||
check 'ab[/[abc]]ef' 'abc]ef' "$no"
|
||||
check 'ab[c[=/=]]ef' 'ab[c[=/=]]ef' "$yes"
|
||||
check 'ab[c[=/=]]ef' 'abc[=/=]ef' "$no"
|
||||
check 'ab[c[=/=]]ef' 'abcef' "$no"
|
||||
check 'a[b\/c]' 'a[b/c]' "$yes"
|
||||
check 'a[b\/c]' 'ab' "$no"
|
||||
check 'a[b\/c]' 'ac' "$no"
|
||||
|
||||
echo
|
||||
echo '---Tests for incomplete bracket expressions---'
|
||||
check 'ab[c' 'ab[c' "$yes"
|
||||
check 'ab[c' 'abc' "$no"
|
||||
check 'ab[c[=d=' 'ab[c[=d=' "$yes"
|
||||
check 'ab[c[=d=' 'abc' "$no"
|
||||
check 'ab[c[.d' 'ab[c[.d' "$yes"
|
||||
check 'ab[c[.d' 'abc' "$no"
|
||||
check 'ab[c[:alpha:' 'ab[c[:alpha:' "$yes"
|
||||
check 'ab[c[:alpha:' 'abc' "$no"
|
||||
check 'ab[c-' 'ab[c-' "$yes"
|
||||
check 'ab[c-' 'abc' "$no"
|
||||
check 'ab[c\' 'ab[c\' "$yes"
|
||||
check 'ab[c\' 'abc' "$no"
|
||||
check 'ab[[\' 'ab[[\' "$yes"
|
||||
check 'ab[[\' 'ab[' "$no"
|
||||
|
||||
echo
|
||||
echo '--- PATSCAN vs BRACKMATCH ---'
|
||||
check '@([[.].])A])' ']' "$yes"
|
||||
check '@([[.].])A])' '==]A])' "$no"
|
||||
check '@([[.].])A])' 'AA])' "$no"
|
||||
check '@([[=]=])A])' ']' "$no"
|
||||
check '@([[=]=])A])' '==]A])' "$yes"
|
||||
check '@([[=]=])A])' 'AA])' "$no"
|
||||
|
||||
echo
|
||||
echo '--- BRACKMATCH: after match vs before match ---'
|
||||
check '[[=]=]ab]' 'a' "$no"
|
||||
check '[[.[=.]ab]' 'a' "$yes"
|
||||
check '[[.[==].]ab]' 'a' "$yes"
|
||||
echo
|
||||
check '[a[=]=]b]' 'a' "$no"
|
||||
check '[a[.[=.]b]' 'a' "$yes"
|
||||
check '[a[.[==].]b]' 'a' "$yes"
|
||||
echo
|
||||
check '[a[=]=]b]' 'b' "$no"
|
||||
check '[a[=]=]b]' 'a=]b]' "$yes"
|
||||
check '[a[.[=.]b]' 'b' "$yes"
|
||||
check '[a[.[=.]b]' 'ab]' "$no"
|
||||
check '[a[.[==].]b]' 'b' "$yes"
|
||||
check '[a[.[==].]b]' 'ab]' "$no"
|
||||
|
||||
echo
|
||||
echo '--- incomplete POSIX brackets ---'
|
||||
check 'x[a[:y]' 'x[' "$yes"
|
||||
check 'x[a[:y]' 'x:' "$yes"
|
||||
check 'x[a[:y]' 'xy' "$yes"
|
||||
check 'x[a[:y]' 'x[ay' "$no"
|
||||
echo
|
||||
check 'x[a[.y]' 'x[' "$yes"
|
||||
check 'x[a[.y]' 'x.' "$yes"
|
||||
check 'x[a[.y]' 'xy' "$yes"
|
||||
check 'x[a[.y]' 'x[ay' "$no"
|
||||
echo
|
||||
check 'x[a[=y]' 'x[' "$yes"
|
||||
check 'x[a[=y]' 'x=' "$yes"
|
||||
check 'x[a[=y]' 'xy' "$yes"
|
||||
check 'x[a[=y]' 'x[ay' "$no"
|
||||
|
||||
echo
|
||||
echo '--- MISC tests ---'
|
||||
check 'a\' 'a\' "$yes"
|
||||
|
||||
cd $ORIG_DIR
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,388 @@
|
||||
export LC_COLLATE=C
|
||||
#
|
||||
# test the shell globbing
|
||||
#
|
||||
expect()
|
||||
{
|
||||
echo expect "$@"
|
||||
}
|
||||
|
||||
# First, a test that bash-2.01.1 fails
|
||||
${THIS_SH} ./glob1.sub
|
||||
|
||||
MYDIR=$PWD # save where we are
|
||||
|
||||
TESTDIR=/tmp/glob-test
|
||||
mkdir $TESTDIR
|
||||
builtin cd $TESTDIR || { echo $0: cannot cd to $TESTDIR >&2 ; exit 1; }
|
||||
rm -rf *
|
||||
|
||||
touch a b c d abc abd abe bb bcd ca cb dd de Beware
|
||||
mkdir bdir
|
||||
|
||||
# see if `regular' globbing works right
|
||||
expect '<a> <abc> <abd> <abe> <X*>'
|
||||
recho a* X*
|
||||
|
||||
expect '<a> <abc> <abd> <abe>'
|
||||
recho \a*
|
||||
|
||||
# see if null glob expansion works
|
||||
shopt -s nullglob
|
||||
|
||||
expect '<a> <abc> <abd> <abe>'
|
||||
recho a* X*
|
||||
|
||||
shopt -u nullglob
|
||||
|
||||
# see if the failglob option works
|
||||
|
||||
mkdir tmp
|
||||
touch tmp/l1 tmp/l2 tmp/l3
|
||||
builtin echo tmp/l[12] tmp/*4 tmp/*3
|
||||
shopt -s failglob
|
||||
builtin echo tmp/l[12] tmp/*4 tmp/*3
|
||||
rm -r tmp
|
||||
shopt -u failglob
|
||||
|
||||
# see if the code that expands directories only works
|
||||
expect '<bdir/>'
|
||||
recho b*/
|
||||
|
||||
# Test quoted and unquoted globbing characters
|
||||
expect '<*>'
|
||||
recho \*
|
||||
|
||||
expect '<a*>'
|
||||
recho 'a*'
|
||||
|
||||
expect '<a*>'
|
||||
recho a\*
|
||||
|
||||
expect '<c> <ca> <cb> <a*> <*q*>'
|
||||
recho c* a\* *q*
|
||||
|
||||
expect '<**>'
|
||||
recho "*"*
|
||||
|
||||
expect '<**>'
|
||||
recho \**
|
||||
|
||||
expect '<\.\./*/>'
|
||||
recho "\.\./*/"
|
||||
|
||||
expect '<s/\..*//>'
|
||||
recho 's/\..*//'
|
||||
|
||||
# Pattern from Larry Wall's Configure that caused bash to blow up
|
||||
expect '</^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/>'
|
||||
recho "/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*"'$'"/\1/"
|
||||
|
||||
# Make sure character classes work properly
|
||||
|
||||
expect '<abc> <abd> <abe> <bb> <cb>'
|
||||
recho [a-c]b*
|
||||
|
||||
expect '<abd> <abe> <bb> <bcd> <bdir> <ca> <cb> <dd> <de>'
|
||||
recho [a-y]*[^c]
|
||||
|
||||
expect '<abd> <abe>'
|
||||
recho a*[^c]
|
||||
|
||||
touch a-b aXb
|
||||
expect '<a-b> <aXb>'
|
||||
recho a[X-]b
|
||||
|
||||
touch .x .y
|
||||
expect '<Beware> <d> <dd> <de>'
|
||||
recho [^a-c]*
|
||||
|
||||
# Make sure that filenames with embedded globbing characters are handled
|
||||
# properly
|
||||
mkdir a\*b
|
||||
> a\*b/ooo
|
||||
|
||||
expect '<a*b/ooo>'
|
||||
recho a\*b/*
|
||||
|
||||
expect '<a*b/ooo>'
|
||||
recho a\*?/*
|
||||
|
||||
expect '<no match>'
|
||||
cmd='echo !7'
|
||||
case "$cmd" in
|
||||
*\\!*) echo match ;;
|
||||
*) echo no match ;;
|
||||
esac
|
||||
|
||||
expect '<not there>'
|
||||
file='r.*'
|
||||
case $file in
|
||||
*.\*) echo not there ;;
|
||||
*) echo there ;;
|
||||
esac
|
||||
|
||||
# examples from the Posix.2 spec (d11.2, p. 243)
|
||||
expect '<abc>'
|
||||
recho a[b]c
|
||||
|
||||
expect '<abc>'
|
||||
recho a["b"]c
|
||||
|
||||
expect '<abc>'
|
||||
recho a[\b]c
|
||||
|
||||
expect '<abc>'
|
||||
recho a?c
|
||||
|
||||
expect '<match 1>'
|
||||
case abc in
|
||||
a"b"c) echo 'match 1' ;;
|
||||
*) echo 'BAD match 1' ;;
|
||||
esac
|
||||
|
||||
expect '<match 2>'
|
||||
case abc in
|
||||
a*c) echo 'match 2' ;;
|
||||
*) echo 'BAD match 2' ;;
|
||||
esac
|
||||
|
||||
expect '<ok 1>'
|
||||
case abc in
|
||||
"a?c") echo 'bad 1' ;;
|
||||
*) echo 'ok 1' ;;
|
||||
esac
|
||||
|
||||
expect '<ok 2>'
|
||||
case abc in
|
||||
a\*c) echo 'bad 2' ;;
|
||||
*) echo 'ok 2' ;;
|
||||
esac
|
||||
|
||||
expect '<ok 3>'
|
||||
case abc in
|
||||
a\[b]c) echo 'bad 3' ;;
|
||||
*) echo 'ok 3' ;;
|
||||
esac
|
||||
|
||||
expect '<ok 4>'
|
||||
case "$nosuchvar" in
|
||||
"") echo 'ok 4' ;;
|
||||
*) echo 'bad 4' ;;
|
||||
esac
|
||||
|
||||
# This is very odd, but sh and ksh seem to agree
|
||||
expect '<ok 5>'
|
||||
case abc in
|
||||
a["\b"]c) echo 'ok 5' ;;
|
||||
*) echo 'bad 5' ;;
|
||||
esac
|
||||
|
||||
mkdir man
|
||||
mkdir man/man1
|
||||
touch man/man1/bash.1
|
||||
expect '<man/man1/bash.1>'
|
||||
recho */man*/bash.*
|
||||
expect '<man/man1/bash.1>'
|
||||
recho $(echo */man*/bash.*)
|
||||
expect '<man/man1/bash.1>'
|
||||
recho "$(echo */man*/bash.*)"
|
||||
|
||||
# tests with multiple `*'s
|
||||
case abc in
|
||||
a***c) echo ok 1;;
|
||||
esac
|
||||
|
||||
case abc in
|
||||
a*****?c) echo ok 2;;
|
||||
esac
|
||||
|
||||
case abc in
|
||||
?*****??) echo ok 3;;
|
||||
esac
|
||||
|
||||
case abc in
|
||||
*****??) echo ok 4;;
|
||||
esac
|
||||
|
||||
case abc in
|
||||
*****??c) echo ok 5;;
|
||||
esac
|
||||
|
||||
case abc in
|
||||
?*****?c) echo ok 6;;
|
||||
esac
|
||||
|
||||
case abc in
|
||||
?***?****c) echo ok 7;;
|
||||
esac
|
||||
|
||||
case abc in
|
||||
?***?****?) echo ok 8;;
|
||||
esac
|
||||
|
||||
case abc in
|
||||
?***?****) echo ok 9;;
|
||||
esac
|
||||
|
||||
case abc in
|
||||
*******c) echo ok 10;;
|
||||
esac
|
||||
|
||||
case abc in
|
||||
*******?) echo ok 11;;
|
||||
esac
|
||||
|
||||
case abcdecdhjk in
|
||||
a*cd**?**??k) echo ok 20;;
|
||||
esac
|
||||
|
||||
case abcdecdhjk in
|
||||
a**?**cd**?**??k) echo ok 21;;
|
||||
esac
|
||||
|
||||
case abcdecdhjk in
|
||||
a**?**cd**?**??k***) echo ok 22;;
|
||||
esac
|
||||
|
||||
case abcdecdhjk in
|
||||
a**?**cd**?**??***k) echo ok 23;;
|
||||
esac
|
||||
|
||||
case abcdecdhjk in
|
||||
a**?**cd**?**??***k**) echo ok 24;;
|
||||
esac
|
||||
|
||||
case abcdecdhjk in
|
||||
a****c**?**??*****) echo ok 25;;
|
||||
esac
|
||||
|
||||
case '-' in
|
||||
[-abc]) echo ok 26 ;;
|
||||
esac
|
||||
|
||||
case '-' in
|
||||
[abc-]) echo ok 27 ;;
|
||||
esac
|
||||
|
||||
case '\' in
|
||||
\\) echo ok 28 ;;
|
||||
esac
|
||||
|
||||
case '\' in
|
||||
[\\]) echo ok 29 ;;
|
||||
esac
|
||||
|
||||
case '\' in
|
||||
'\') echo ok 30 ;;
|
||||
esac
|
||||
|
||||
case '[' in
|
||||
[[]) echo ok 31 ;;
|
||||
esac
|
||||
|
||||
# a `[' without a closing `]' is just another character to match, in the
|
||||
# bash implementation
|
||||
case '[' in
|
||||
[) echo ok 32 ;;
|
||||
esac
|
||||
|
||||
case '[abc' in
|
||||
[*) echo 'ok 33';;
|
||||
esac
|
||||
|
||||
# a right bracket shall lose its special meaning and represent itself in
|
||||
# a bracket expression if it occurs first in the list. -- POSIX.2 2.8.3.2
|
||||
case ']' in
|
||||
[]]) echo ok 34 ;;
|
||||
esac
|
||||
|
||||
case '-' in
|
||||
[]-]) echo ok 35 ;;
|
||||
esac
|
||||
|
||||
# a backslash should just escape the next character in this context
|
||||
case p in
|
||||
[a-\z]) echo ok 36 ;;
|
||||
esac
|
||||
|
||||
# this was a bug in all versions up to bash-2.04-release
|
||||
case "/tmp" in
|
||||
[/\\]*) echo ok 37 ;;
|
||||
esac
|
||||
|
||||
# none of these should output anything
|
||||
|
||||
case abc in
|
||||
??**********?****?) echo bad 1;;
|
||||
esac
|
||||
|
||||
case abc in
|
||||
??**********?****c) echo bad 2;;
|
||||
esac
|
||||
|
||||
case abc in
|
||||
?************c****?****) echo bad 3;;
|
||||
esac
|
||||
|
||||
case abc in
|
||||
*c*?**) echo bad 4;;
|
||||
esac
|
||||
|
||||
case abc in
|
||||
a*****c*?**) echo bad 5;;
|
||||
esac
|
||||
|
||||
case abc in
|
||||
a********???*******) echo bad 6;;
|
||||
esac
|
||||
|
||||
case 'a' in
|
||||
[]) echo bad 7 ;;
|
||||
esac
|
||||
|
||||
case '[' in
|
||||
[abc) echo bad 8;;
|
||||
esac
|
||||
|
||||
# let's start testing the case-insensitive globbing code
|
||||
recho b*
|
||||
|
||||
shopt -s nocaseglob
|
||||
recho b*
|
||||
|
||||
recho [b]*
|
||||
shopt -u nocaseglob
|
||||
|
||||
# make sure set -f works right
|
||||
set -f
|
||||
recho *
|
||||
set +f
|
||||
|
||||
# test out the GLOBIGNORE code
|
||||
GLOBIGNORE='.*:*c:*e:?'
|
||||
recho *
|
||||
|
||||
GLOBIGNORE='.*:*b:*d:?'
|
||||
recho *
|
||||
|
||||
# see if GLOBIGNORE can substitute for `set -f'
|
||||
GLOBIGNORE='.*:*'
|
||||
recho *
|
||||
|
||||
unset GLOBIGNORE
|
||||
expect '<man/man1/bash.1>'
|
||||
recho */man*/bash.*
|
||||
|
||||
# make sure null values for GLOBIGNORE have no effect
|
||||
GLOBIGNORE=
|
||||
expect '<man/man1/bash.1>'
|
||||
recho */man*/bash.*
|
||||
|
||||
# this is for the benefit of pure coverage, so it writes the pcv file
|
||||
# in the right place, and for gprof
|
||||
builtin cd $MYDIR
|
||||
|
||||
rm -rf $TESTDIR
|
||||
|
||||
exit 0
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
export TMPDIR
|
||||
|
||||
# basic /bin/sh syntax
|
||||
SUFFIX=`${THIS_SH} -c 'echo $(( $RANDOM + $BASHPID ))'`
|
||||
SUFFIX=$( ${THIS_SH} -c 'echo $(( $RANDOM + $BASHPID ))' )
|
||||
|
||||
BASH_TSTOUT=${TMPDIR}/bashtst-$SUFFIX # for now
|
||||
export BASH_TSTOUT
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
PATH=$PATH:`pwd`
|
||||
export PATH
|
||||
|
||||
${THIS_SH} ./glob-bracket.tests > ${BASH_TSTOUT} 2>&1
|
||||
diff ${BASH_TSTOUT} glob-bracket.right && rm -f ${BASH_TSTOUT}
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
export TMPDIR
|
||||
|
||||
# basic /bin/sh syntax
|
||||
SUFFIX=`${THIS_SH} -c 'echo $(( $RANDOM + $BASHPID ))'`
|
||||
SUFFIX=$( ${THIS_SH} -c 'echo $(( $RANDOM + $BASHPID ))' )
|
||||
|
||||
BASH_TSTOUT=${TMPDIR}/bashtst-$SUFFIX # for now
|
||||
export BASH_TSTOUT
|
||||
|
||||
@@ -90,6 +90,9 @@ ${THIS_SH} ./trap4.sub
|
||||
# Return trap issues
|
||||
${THIS_SH} ./trap6.sub
|
||||
|
||||
# eval and ERR trap
|
||||
${THIS_SH} ./trap7.sub
|
||||
|
||||
#
|
||||
# show that setting a trap on SIGCHLD is not disastrous.
|
||||
#
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
func()
|
||||
{
|
||||
eval "trap 'return 42' ERR; false"
|
||||
return 0
|
||||
}
|
||||
|
||||
set -o errtrace
|
||||
func || echo oops: $?
|
||||
Reference in New Issue
Block a user