mirror of
https://github.com/zsh-users/zsh
synced 2024-10-14 11:53:24 +00:00
35168: Improve parsing of case patterns.
"|" is now found properly by looking for words that come from the lexical analyser, rather than hacking a pattern returned in one dollop. Update some completion functions that need extra quoting as a result. Add test for new parsing. Update version number to 5.0.8-dev-3 because of wordcode incompatibility.
This commit is contained in:
parent
34a1489f43
commit
52aeb9aaeb
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
|||
2015-05-18 Peter Stephenson <p.stephenson@samsung.com>
|
||||
|
||||
* 35168: Completion/Unix/Command/_ant,
|
||||
Completion/Unix/Command/_cp, Completion/Unix/Command/_locate,
|
||||
Completion/Unix/Command/_make, Completion/Unix/Command/_tar,
|
||||
Completion/Unix/Type/_path_commands,
|
||||
Completion/X/Command/_xrandr, Config/version.mk, Src/lex.c,
|
||||
Src/loop.c, Src/parse.c, Src/text.c, Test/A01grammar.ztst:
|
||||
Fix parsing of case patterns so "|" is extracted by looking
|
||||
for words; quote completion functions where needed in
|
||||
consequence; add test; updated version number to 5.0.7-dev-3
|
||||
because of wordcode incompatibility.
|
||||
|
||||
2015-05-18 Daniel Hahler <git@thequod.de>
|
||||
|
||||
* 35126: Completion/Unix/Command/_git: __git_recent_commits:
|
||||
|
|
|
@ -123,8 +123,7 @@ case $state in
|
|||
# Output target again indicating its the default one.
|
||||
print -n "'${default_target}:(Default target) ' "
|
||||
;;
|
||||
(Searching:*|Main:targets:|Subtargets:|BUILD:SUCCESSFUL|Total:time:
|
||||
*)
|
||||
(Searching:*|Main:targets:|Subtargets:|BUILD:SUCCESSFUL|Total:time:*)
|
||||
;;
|
||||
(*)
|
||||
# Return target and description
|
||||
|
|
|
@ -13,7 +13,7 @@ if _pick_variant gnu=GNU unix --version; then
|
|||
'-H[follow command-line symbolic links]' \
|
||||
'(-l --link)'{-l,--link}'[link files instead of copying]' \
|
||||
'(-L --dereference)'{-L,--dereference}'[always follow symbolic links]' \
|
||||
(-n --no-clobber -i --interactive){-n,--no-clobber}"[don't overwrite an existing file]" \
|
||||
'(-n --no-clobber -i --interactive)'{-n,--no-clobber}"[don't overwrite an existing file]" \
|
||||
'(-P --no-dereference)'{-P,--no-dereference}'[never follow symbolic links]' \
|
||||
'-p[same as --preserve=mode,ownership,timestamps]' \
|
||||
'--preserve=-[preserve specified attributes]:: :_values -s , attribute mode timestamps ownership links context xattr all' \
|
||||
|
|
|
@ -25,7 +25,7 @@ case $basename in
|
|||
ltype=gnu
|
||||
;;
|
||||
|
||||
(*illegal option*)
|
||||
(*"illegal option"*)
|
||||
if [[ $OSTYPE == (freebsd|openbsd|dragonfly|darwin)* ]]; then
|
||||
ltype=bsd
|
||||
else
|
||||
|
|
|
@ -65,7 +65,7 @@ _make-parseMakefile () {
|
|||
do
|
||||
case "$input " in
|
||||
# VARIABLE = value OR VARIABLE ?= value
|
||||
([[:alnum:]][[:alnum:]_]#[ $TAB]#(\?|)=*)
|
||||
([[:alnum:]][[:alnum:]_]#[" "$TAB]#(\?|)=*)
|
||||
var=${input%%[ $TAB]#(\?|)=*}
|
||||
val=${input#*=}
|
||||
val=${val##[ $TAB]#}
|
||||
|
@ -74,7 +74,7 @@ _make-parseMakefile () {
|
|||
|
||||
# VARIABLE := value OR VARIABLE ::= value
|
||||
# Evaluated immediately
|
||||
([[:alnum:]][[:alnum:]_]#[ $TAB]#:(:|)=*)
|
||||
([[:alnum:]][[:alnum:]_]#[" "$TAB]#:(:|)=*)
|
||||
var=${input%%[ $TAB]#:(:|)=*}
|
||||
val=${input#*=}
|
||||
val=${val##[ $TAB]#}
|
||||
|
@ -97,7 +97,7 @@ _make-parseMakefile () {
|
|||
;;
|
||||
|
||||
# Include another makefile
|
||||
(${~incl} *)
|
||||
(${~incl}" "*)
|
||||
local f=${input##${~incl} ##}
|
||||
if [[ $incl == '.include' ]]
|
||||
then
|
||||
|
|
|
@ -23,7 +23,7 @@ local _tar_cmd tf tmp tmpb del index
|
|||
|
||||
if _pick_variant gnu=GNU unix --version; then
|
||||
case "$($service --version)" in
|
||||
(tar \(GNU tar\) (#b)([0-9.-]##)*)
|
||||
("tar (GNU tar) "(#b)([0-9.-]##)*)
|
||||
autoload -z is-at-least
|
||||
is-at-least 1.14.91 "$match[1]" || _cmd_variant[$service]="gnu-old"
|
||||
;;
|
||||
|
|
|
@ -25,7 +25,7 @@ return 1
|
|||
|
||||
_call_whatis() {
|
||||
case "$(whatis --version)" in
|
||||
(whatis from *)
|
||||
("whatis from "*)
|
||||
local -A args
|
||||
zparseopts -D -A args s: r:
|
||||
apropos "${args[-r]:-"$@"}" | fgrep "($args[-s]"
|
||||
|
|
|
@ -51,7 +51,7 @@ _arguments -C \
|
|||
case $state in
|
||||
value)
|
||||
case $words[CURRENT-1] in
|
||||
(scaling* mode)
|
||||
(scaling*" mode")
|
||||
_description value expl "output property 'scaling mode'"
|
||||
compadd "$@" "$expl[@]" None Full Center Full\ aspect && return 0
|
||||
;;
|
||||
|
|
|
@ -27,5 +27,5 @@
|
|||
# This must also serve as a shell script, so do not add spaces around the
|
||||
# `=' signs.
|
||||
|
||||
VERSION=5.0.7-dev-2
|
||||
VERSION_DATE='May 5, 2015'
|
||||
VERSION=5.0.7-dev-3
|
||||
VERSION_DATE='May 17, 2015'
|
||||
|
|
|
@ -761,6 +761,8 @@ gettok(void)
|
|||
lexstop = 0;
|
||||
return BAR;
|
||||
case LX1_INPAR:
|
||||
if (incasepat == 2)
|
||||
return INPAR;
|
||||
d = hgetc();
|
||||
if (d == '(') {
|
||||
if (infor) {
|
||||
|
|
96
Src/loop.c
96
Src/loop.c
|
@ -545,7 +545,7 @@ execcase(Estate state, int do_exec)
|
|||
Wordcode end, next;
|
||||
wordcode code = state->pc[-1];
|
||||
char *word, *pat;
|
||||
int npat, save;
|
||||
int npat, save, nalts, ialt, patok;
|
||||
Patprog *spprog, pprog;
|
||||
|
||||
end = state->pc + WC_CASE_SKIP(code);
|
||||
|
@ -561,60 +561,74 @@ execcase(Estate state, int do_exec)
|
|||
if (wc_code(code) != WC_CASE)
|
||||
break;
|
||||
|
||||
pat = NULL;
|
||||
pprog = NULL;
|
||||
save = 0;
|
||||
npat = state->pc[1];
|
||||
spprog = state->prog->pats + npat;
|
||||
|
||||
next = state->pc + WC_CASE_SKIP(code);
|
||||
nalts = *state->pc++;
|
||||
ialt = patok = 0;
|
||||
|
||||
if (isset(XTRACE)) {
|
||||
char *opat;
|
||||
|
||||
pat = dupstring(opat = ecrawstr(state->prog, state->pc, NULL));
|
||||
singsub(&pat);
|
||||
save = (!(state->prog->flags & EF_HEAP) &&
|
||||
!strcmp(pat, opat) && *spprog != dummy_patprog2);
|
||||
|
||||
printprompt4();
|
||||
fprintf(xtrerr, "case %s (", word);
|
||||
quote_tokenized_output(pat, xtrerr);
|
||||
}
|
||||
|
||||
while (!patok && nalts) {
|
||||
npat = state->pc[1];
|
||||
spprog = state->prog->pats + npat;
|
||||
pprog = NULL;
|
||||
pat = NULL;
|
||||
|
||||
if (isset(XTRACE)) {
|
||||
int htok = 0;
|
||||
pat = dupstring(ecrawstr(state->prog, state->pc, &htok));
|
||||
if (htok)
|
||||
singsub(&pat);
|
||||
|
||||
if (ialt++)
|
||||
fprintf(stderr, " | ");
|
||||
quote_tokenized_output(pat, xtrerr);
|
||||
}
|
||||
|
||||
if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2)
|
||||
pprog = *spprog;
|
||||
|
||||
if (!pprog) {
|
||||
if (!pat) {
|
||||
char *opat;
|
||||
int htok = 0;
|
||||
|
||||
pat = dupstring(opat = ecrawstr(state->prog,
|
||||
state->pc, &htok));
|
||||
if (htok)
|
||||
singsub(&pat);
|
||||
save = (!(state->prog->flags & EF_HEAP) &&
|
||||
!strcmp(pat, opat) && *spprog != dummy_patprog2);
|
||||
}
|
||||
if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC),
|
||||
NULL)))
|
||||
zerr("bad pattern: %s", pat);
|
||||
else if (save)
|
||||
*spprog = pprog;
|
||||
}
|
||||
if (pprog && pattry(pprog, word))
|
||||
patok = 1;
|
||||
state->pc += 2;
|
||||
nalts--;
|
||||
}
|
||||
state->pc += 2 * nalts;
|
||||
if (isset(XTRACE)) {
|
||||
fprintf(xtrerr, ")\n");
|
||||
fflush(xtrerr);
|
||||
}
|
||||
state->pc += 2;
|
||||
|
||||
if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2)
|
||||
pprog = *spprog;
|
||||
|
||||
if (!pprog) {
|
||||
if (!pat) {
|
||||
char *opat;
|
||||
int htok = 0;
|
||||
|
||||
pat = dupstring(opat = ecrawstr(state->prog,
|
||||
state->pc - 2, &htok));
|
||||
if (htok)
|
||||
singsub(&pat);
|
||||
save = (!(state->prog->flags & EF_HEAP) &&
|
||||
!strcmp(pat, opat) && *spprog != dummy_patprog2);
|
||||
}
|
||||
if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC),
|
||||
NULL)))
|
||||
zerr("bad pattern: %s", pat);
|
||||
else if (save)
|
||||
*spprog = pprog;
|
||||
}
|
||||
if (pprog && pattry(pprog, word)) {
|
||||
if (patok) {
|
||||
execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
|
||||
do_exec));
|
||||
while (!retflag && wc_code(code) == WC_CASE &&
|
||||
WC_CASE_TYPE(code) == WC_CASE_AND) {
|
||||
state->pc = next;
|
||||
code = *state->pc;
|
||||
state->pc += 3;
|
||||
next = state->pc + WC_CASE_SKIP(code) - 2;
|
||||
code = *state->pc++;
|
||||
next = state->pc + WC_CASE_SKIP(code);
|
||||
nalts = *state->pc++;
|
||||
state->pc += 2 * nalts;
|
||||
execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
|
||||
do_exec));
|
||||
}
|
||||
|
|
87
Src/parse.c
87
Src/parse.c
|
@ -349,9 +349,8 @@ ecadd(wordcode c)
|
|||
eclen += a;
|
||||
}
|
||||
ecbuf[ecused] = c;
|
||||
ecused++;
|
||||
|
||||
return ecused - 1;
|
||||
return ecused++;
|
||||
}
|
||||
|
||||
/* Delete a wordcode. */
|
||||
|
@ -1128,7 +1127,7 @@ par_for(int *cmplx)
|
|||
static void
|
||||
par_case(int *cmplx)
|
||||
{
|
||||
int oecused = ecused, brflag, p, pp, n = 1, type;
|
||||
int oecused = ecused, brflag, p, pp, palts, type, nalts;
|
||||
int ona, onc;
|
||||
|
||||
p = ecadd(0);
|
||||
|
@ -1153,7 +1152,7 @@ par_case(int *cmplx)
|
|||
YYERRORV(oecused);
|
||||
}
|
||||
brflag = (tok == INBRACE);
|
||||
incasepat = 1;
|
||||
incasepat = 2;
|
||||
incmdpos = 0;
|
||||
noaliases = ona;
|
||||
nocorrect = onc;
|
||||
|
@ -1166,8 +1165,10 @@ par_case(int *cmplx)
|
|||
zshlex();
|
||||
if (tok == OUTBRACE)
|
||||
break;
|
||||
if (tok == INPAR)
|
||||
if (tok == INPAR) {
|
||||
incasepat = 1;
|
||||
zshlex();
|
||||
}
|
||||
if (tok != STRING)
|
||||
YYERRORV(oecused);
|
||||
if (!strcmp(tokstr, "esac"))
|
||||
|
@ -1176,89 +1177,45 @@ par_case(int *cmplx)
|
|||
incasepat = 0;
|
||||
incmdpos = 1;
|
||||
type = WC_CASE_OR;
|
||||
pp = ecadd(0);
|
||||
palts = ecadd(0);
|
||||
nalts = 0;
|
||||
for (;;) {
|
||||
ecstr(str);
|
||||
ecadd(ecnpats++);
|
||||
nalts++;
|
||||
|
||||
zshlex();
|
||||
if (tok == OUTPAR) {
|
||||
incasepat = 0;
|
||||
incmdpos = 1;
|
||||
zshlex();
|
||||
break;
|
||||
} else if (tok == BAR) {
|
||||
char *str2;
|
||||
int sl = strlen(str);
|
||||
} else if (tok != BAR)
|
||||
YYERRORV(oecused);
|
||||
|
||||
incasepat = 1;
|
||||
incmdpos = 0;
|
||||
str2 = hcalloc(sl + 2);
|
||||
strcpy(str2, str);
|
||||
str2[sl] = Bar;
|
||||
str2[sl+1] = '\0';
|
||||
str = str2;
|
||||
} else {
|
||||
int sl = strlen(str);
|
||||
|
||||
if (!sl || str[sl - 1] != Bar) {
|
||||
/* POSIX allows (foo*) patterns */
|
||||
int pct;
|
||||
char *s;
|
||||
|
||||
for (s = str, pct = 0; *s; s++) {
|
||||
if (*s == Inpar)
|
||||
pct++;
|
||||
if (!pct)
|
||||
break;
|
||||
if (pct == 1) {
|
||||
if (*s == Bar || *s == Inpar)
|
||||
while (iblank(s[1]))
|
||||
chuck(s+1);
|
||||
if (*s == Bar || *s == Outpar)
|
||||
while (iblank(s[-1]) &&
|
||||
(s < str + 1 || s[-2] != Meta))
|
||||
chuck(--s);
|
||||
}
|
||||
if (*s == Outpar)
|
||||
pct--;
|
||||
}
|
||||
if (*s || pct || s == str)
|
||||
YYERRORV(oecused);
|
||||
/* Simplify pattern by removing surrounding (...) */
|
||||
sl = strlen(str);
|
||||
DPUTS(*str != Inpar || str[sl - 1] != Outpar,
|
||||
"BUG: strange case pattern");
|
||||
str[sl - 1] = '\0';
|
||||
chuck(str);
|
||||
break;
|
||||
} else {
|
||||
char *str2;
|
||||
|
||||
if (tok != STRING)
|
||||
YYERRORV(oecused);
|
||||
str2 = hcalloc(sl + strlen(tokstr) + 1);
|
||||
strcpy(str2, str);
|
||||
strcpy(str2 + sl, tokstr);
|
||||
str = str2;
|
||||
}
|
||||
}
|
||||
zshlex();
|
||||
if (tok != STRING)
|
||||
YYERRORV(oecused);
|
||||
str = dupstring(tokstr);
|
||||
}
|
||||
pp = ecadd(0);
|
||||
ecstr(str);
|
||||
ecadd(ecnpats++);
|
||||
par_save_list(cmplx);
|
||||
n++;
|
||||
if (tok == SEMIAMP)
|
||||
type = WC_CASE_AND;
|
||||
else if (tok == SEMIBAR)
|
||||
type = WC_CASE_TESTAND;
|
||||
ecbuf[pp] = WCB_CASE(type, ecused - 1 - pp);
|
||||
ecbuf[palts] = nalts;
|
||||
if ((tok == ESAC && !brflag) || (tok == OUTBRACE && brflag))
|
||||
break;
|
||||
if (tok != DSEMI && tok != SEMIAMP && tok != SEMIBAR)
|
||||
YYERRORV(oecused);
|
||||
incasepat = 1;
|
||||
incasepat = 2;
|
||||
incmdpos = 0;
|
||||
zshlex();
|
||||
}
|
||||
incmdpos = 1;
|
||||
incasepat = 0;
|
||||
zshlex();
|
||||
|
||||
ecbuf[p] = WCB_CASE(WC_CASE_HEAD, ecused - 1 - p);
|
||||
|
|
28
Src/text.c
28
Src/text.c
|
@ -602,6 +602,7 @@ gettext2(Estate state)
|
|||
case WC_CASE:
|
||||
if (!s) {
|
||||
Wordcode end = state->pc + WC_CASE_SKIP(code);
|
||||
wordcode nalts;
|
||||
|
||||
taddstr("case ");
|
||||
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||
|
@ -622,8 +623,13 @@ gettext2(Estate state)
|
|||
taddchr(' ');
|
||||
taddstr("(");
|
||||
code = *state->pc++;
|
||||
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||
state->pc++;
|
||||
nalts = *state->pc++;
|
||||
while (nalts--) {
|
||||
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||
state->pc++;
|
||||
if (nalts)
|
||||
taddstr(" | ");
|
||||
}
|
||||
taddstr(") ");
|
||||
tindent++;
|
||||
n = tpush(code, 0);
|
||||
|
@ -631,6 +637,7 @@ gettext2(Estate state)
|
|||
n->pop = (state->pc - 2 + WC_CASE_SKIP(code) >= end);
|
||||
}
|
||||
} else if (state->pc < s->u._case.end) {
|
||||
wordcode nalts;
|
||||
dec_tindent();
|
||||
switch (WC_CASE_TYPE(code)) {
|
||||
case WC_CASE_OR:
|
||||
|
@ -638,11 +645,11 @@ gettext2(Estate state)
|
|||
break;
|
||||
|
||||
case WC_CASE_AND:
|
||||
taddstr(";&");
|
||||
taddstr(" ;&");
|
||||
break;
|
||||
|
||||
default:
|
||||
taddstr(";|");
|
||||
taddstr(" ;|");
|
||||
break;
|
||||
}
|
||||
if (tnewlins)
|
||||
|
@ -651,8 +658,13 @@ gettext2(Estate state)
|
|||
taddchr(' ');
|
||||
taddstr("(");
|
||||
code = *state->pc++;
|
||||
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||
state->pc++;
|
||||
nalts = *state->pc++;
|
||||
while (nalts--) {
|
||||
taddstr(ecgetstr(state, EC_NODUP, NULL));
|
||||
state->pc++;
|
||||
if (nalts)
|
||||
taddstr(" | ");
|
||||
}
|
||||
taddstr(") ");
|
||||
tindent++;
|
||||
s->code = code;
|
||||
|
@ -666,11 +678,11 @@ gettext2(Estate state)
|
|||
break;
|
||||
|
||||
case WC_CASE_AND:
|
||||
taddstr(";&");
|
||||
taddstr(" ;&");
|
||||
break;
|
||||
|
||||
default:
|
||||
taddstr(";|");
|
||||
taddstr(" ;|");
|
||||
break;
|
||||
}
|
||||
dec_tindent();
|
||||
|
|
|
@ -572,6 +572,7 @@
|
|||
$ZTST_testdir/../Src/zsh -f myscript
|
||||
127q:PATHSCRIPT option not used.
|
||||
?$ZTST_testdir/../Src/zsh: can't open input file: myscript
|
||||
# '
|
||||
|
||||
$ZTST_testdir/../Src/zsh -fc 'echo $0; echo $1' myargzero myargone
|
||||
0:$0 is traditionally if bizarrely set to the first argument with -c
|
||||
|
@ -611,3 +612,41 @@
|
|||
>BEGIN
|
||||
>mytrue
|
||||
>END
|
||||
|
||||
fn() {
|
||||
case $1 in
|
||||
( one | two | three )
|
||||
print Matched $1
|
||||
;;
|
||||
( fo* | fi* | si* )
|
||||
print Pattern matched $1
|
||||
;;
|
||||
( []x | a[b]* )
|
||||
print Character class matched $1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
which fn
|
||||
fn one
|
||||
fn two
|
||||
fn three
|
||||
fn four
|
||||
fn five
|
||||
fn six
|
||||
fn abecedinarian
|
||||
fn xylophone
|
||||
0: case word handling
|
||||
>fn () {
|
||||
> case $1 in
|
||||
> (one | two | three) print Matched $1 ;;
|
||||
> (fo* | fi* | si*) print Pattern matched $1 ;;
|
||||
> ([]x | a[b]*) print Character class matched $1 ;;
|
||||
> esac
|
||||
>}
|
||||
>Matched one
|
||||
>Matched two
|
||||
>Matched three
|
||||
>Pattern matched four
|
||||
>Pattern matched five
|
||||
>Pattern matched six
|
||||
>Character class matched abecedinarian
|
||||
|
|
Loading…
Reference in a new issue