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:
parent
1563b70658
commit
262ae5a436
47
eval.c
47
eval.c
@ -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
45
lex.c
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user