fix most of the ambiguous ${[prefix] var [op [word]]} corner cases

prodded by izabera and carstenh; resolution is:
• you can’t trim a vector in mksh, still (consider ${@:-1})
• future POSIX will require non-empty “word” for most “op”s
• dissolve in order of standard → extension
• dissolve to prefer “op” over “prefix” where still necessary, mostly
This commit is contained in:
tg 2016-06-25 23:55:00 +00:00
parent 1563b70658
commit 262ae5a436
3 changed files with 98 additions and 3663 deletions

3669
check.t

File diff suppressed because it is too large Load Diff

47
eval.c
View File

@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.187 2016/05/05 22:45:57 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.188 2016/06/25 23:54:59 tg Exp $");
/*
* string expansion
@ -1061,7 +1061,7 @@ varsub(Expand *xp, const char *sp, const char *word,
int c;
int state; /* next state: XBASE, XARG, XSUB, XNULLSUB */
int stype; /* substitution type */
int slen;
int slen = 0;
const char *p;
struct tbl *vp;
bool zero_ok = false;
@ -1140,10 +1140,24 @@ varsub(Expand *xp, const char *sp, const char *word,
xp->str = shf_smprintf("%d", c);
return (XSUB);
}
if (stype == '!' && c != '\0' && *word == CSUBST) {
sp++;
if ((p = cstrchr(sp, '[')) && (p[1] == '*' || p[1] == '@') &&
p[2] == ']') {
c = '!';
stype = 0;
goto arraynames;
}
xp->var = global(sp);
xp->str = p ? shf_smprintf("%s[%lu]",
xp->var->name, arrayindex(xp->var)) : xp->var->name;
*stypep = 0;
return (XSUB);
}
/* Check for qualifiers in word part */
stype = 0;
c = word[slen = 0] == CHAR ? word[1] : 0;
c = word[slen + 0] == CHAR ? word[slen + 1] : 0;
if (c == ':') {
slen += 2;
stype = 0x80;
@ -1182,8 +1196,6 @@ varsub(Expand *xp, const char *sp, const char *word,
return (-1);
if (!stype && *word != CSUBST)
return (-1);
*stypep = stype;
*slenp = slen;
c = sp[0];
if (c == '*' || c == '@') {
@ -1230,9 +1242,9 @@ varsub(Expand *xp, const char *sp, const char *word,
case 0x100 | 'Q':
return (-1);
}
c = 0;
arraynames:
XPinit(wv, 32);
if ((c = sp[0]) == '!')
++sp;
vp = global(arrayname(sp));
for (; vp; vp = vp->u.array) {
if (!(vp->flag&ISSET))
@ -1254,23 +1266,12 @@ varsub(Expand *xp, const char *sp, const char *word,
state = XARG;
}
} else {
/* Can't assign things like $! or $1 */
if ((stype & 0x17F) == '=' &&
xp->var = global(sp);
xp->str = str_val(xp->var);
/* can't assign things like $! or $1 */
if ((stype & 0x17F) == '=' && !*xp->str &&
ctype(*sp, C_VAR1 | C_DIGIT))
return (-1);
if (*sp == '!' && sp[1] && !ctype(sp[1], C_VAR1)) {
++sp;
xp->var = global(sp);
if (vstrchr(sp, '['))
xp->str = shf_smprintf("%s[%lu]",
xp->var->name,
arrayindex(xp->var));
else
xp->str = xp->var->name;
} else {
xp->var = global(sp);
xp->str = str_val(xp->var);
}
state = XSUB;
}
@ -1288,6 +1289,8 @@ varsub(Expand *xp, const char *sp, const char *word,
if (Flag(FNOUNSET) && xp->str == null && !zero_ok &&
(ctype(c, C_SUBOP2) || (state != XBASE && c != '+')))
errorf("%s: parameter not set", sp);
*stypep = stype;
*slenp = slen;
return (state);
}

45
lex.c
View File

@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.224 2016/05/05 22:45:58 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.225 2016/06/25 23:55:00 tg Exp $");
/*
* states while lexing word
@ -1574,14 +1574,29 @@ get_brace_var(XString *wsp, char *wp)
c = getsc();
/* State machine to figure out where the variable part ends. */
switch (state) {
case PS_SAW_BANG:
if (ctype(c, C_VAR1))
goto out;
case PS_SAW_HASH:
if (ctype(c, C_VAR1)) {
char c2;
if (0)
/* FALLTHROUGH */
c2 = getsc();
ungetsc(c2);
if (c2 != /*{*/ '}') {
ungetsc(c);
goto out;
}
}
goto ps_common;
case PS_SAW_BANG:
switch (c) {
case '@':
case '#':
case '-':
case '?':
goto out;
}
goto ps_common;
case PS_INITIAL:
switch (c) {
switch (c) {
case '%':
state = PS_SAW_PERCENT;
goto next;
@ -1594,24 +1609,12 @@ get_brace_var(XString *wsp, char *wp)
}
/* FALLTHROUGH */
case PS_SAW_PERCENT:
case PS_SAW_HASH:
ps_common:
if (ksh_isalphx(c))
state = PS_IDENT;
else if (ksh_isdigit(c))
state = PS_NUMBER;
else if (c == '#') {
if (state == PS_SAW_HASH) {
char c2;
c2 = getsc();
ungetsc(c2);
if (c2 != /*{*/ '}') {
ungetsc(c);
goto out;
}
}
state = PS_VAR1;
} else if (ctype(c, C_VAR1))
else if (ctype(c, C_VAR1))
state = PS_VAR1;
else
goto out;