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:
47
eval.c
47
eval.c
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#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
|
* string expansion
|
||||||
@ -1061,7 +1061,7 @@ varsub(Expand *xp, const char *sp, const char *word,
|
|||||||
int c;
|
int c;
|
||||||
int state; /* next state: XBASE, XARG, XSUB, XNULLSUB */
|
int state; /* next state: XBASE, XARG, XSUB, XNULLSUB */
|
||||||
int stype; /* substitution type */
|
int stype; /* substitution type */
|
||||||
int slen;
|
int slen = 0;
|
||||||
const char *p;
|
const char *p;
|
||||||
struct tbl *vp;
|
struct tbl *vp;
|
||||||
bool zero_ok = false;
|
bool zero_ok = false;
|
||||||
@ -1140,10 +1140,24 @@ varsub(Expand *xp, const char *sp, const char *word,
|
|||||||
xp->str = shf_smprintf("%d", c);
|
xp->str = shf_smprintf("%d", c);
|
||||||
return (XSUB);
|
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 */
|
/* Check for qualifiers in word part */
|
||||||
stype = 0;
|
stype = 0;
|
||||||
c = word[slen = 0] == CHAR ? word[1] : 0;
|
c = word[slen + 0] == CHAR ? word[slen + 1] : 0;
|
||||||
if (c == ':') {
|
if (c == ':') {
|
||||||
slen += 2;
|
slen += 2;
|
||||||
stype = 0x80;
|
stype = 0x80;
|
||||||
@ -1182,8 +1196,6 @@ varsub(Expand *xp, const char *sp, const char *word,
|
|||||||
return (-1);
|
return (-1);
|
||||||
if (!stype && *word != CSUBST)
|
if (!stype && *word != CSUBST)
|
||||||
return (-1);
|
return (-1);
|
||||||
*stypep = stype;
|
|
||||||
*slenp = slen;
|
|
||||||
|
|
||||||
c = sp[0];
|
c = sp[0];
|
||||||
if (c == '*' || c == '@') {
|
if (c == '*' || c == '@') {
|
||||||
@ -1230,9 +1242,9 @@ varsub(Expand *xp, const char *sp, const char *word,
|
|||||||
case 0x100 | 'Q':
|
case 0x100 | 'Q':
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
c = 0;
|
||||||
|
arraynames:
|
||||||
XPinit(wv, 32);
|
XPinit(wv, 32);
|
||||||
if ((c = sp[0]) == '!')
|
|
||||||
++sp;
|
|
||||||
vp = global(arrayname(sp));
|
vp = global(arrayname(sp));
|
||||||
for (; vp; vp = vp->u.array) {
|
for (; vp; vp = vp->u.array) {
|
||||||
if (!(vp->flag&ISSET))
|
if (!(vp->flag&ISSET))
|
||||||
@ -1254,23 +1266,12 @@ varsub(Expand *xp, const char *sp, const char *word,
|
|||||||
state = XARG;
|
state = XARG;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Can't assign things like $! or $1 */
|
xp->var = global(sp);
|
||||||
if ((stype & 0x17F) == '=' &&
|
xp->str = str_val(xp->var);
|
||||||
|
/* can't assign things like $! or $1 */
|
||||||
|
if ((stype & 0x17F) == '=' && !*xp->str &&
|
||||||
ctype(*sp, C_VAR1 | C_DIGIT))
|
ctype(*sp, C_VAR1 | C_DIGIT))
|
||||||
return (-1);
|
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;
|
state = XSUB;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1288,6 +1289,8 @@ varsub(Expand *xp, const char *sp, const char *word,
|
|||||||
if (Flag(FNOUNSET) && xp->str == null && !zero_ok &&
|
if (Flag(FNOUNSET) && xp->str == null && !zero_ok &&
|
||||||
(ctype(c, C_SUBOP2) || (state != XBASE && c != '+')))
|
(ctype(c, C_SUBOP2) || (state != XBASE && c != '+')))
|
||||||
errorf("%s: parameter not set", sp);
|
errorf("%s: parameter not set", sp);
|
||||||
|
*stypep = stype;
|
||||||
|
*slenp = slen;
|
||||||
return (state);
|
return (state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
45
lex.c
45
lex.c
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#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
|
* states while lexing word
|
||||||
@ -1574,14 +1574,29 @@ get_brace_var(XString *wsp, char *wp)
|
|||||||
c = getsc();
|
c = getsc();
|
||||||
/* State machine to figure out where the variable part ends. */
|
/* State machine to figure out where the variable part ends. */
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case PS_SAW_BANG:
|
case PS_SAW_HASH:
|
||||||
if (ctype(c, C_VAR1))
|
if (ctype(c, C_VAR1)) {
|
||||||
goto out;
|
char c2;
|
||||||
|
|
||||||
if (0)
|
c2 = getsc();
|
||||||
/* FALLTHROUGH */
|
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:
|
case PS_INITIAL:
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '%':
|
case '%':
|
||||||
state = PS_SAW_PERCENT;
|
state = PS_SAW_PERCENT;
|
||||||
goto next;
|
goto next;
|
||||||
@ -1594,24 +1609,12 @@ get_brace_var(XString *wsp, char *wp)
|
|||||||
}
|
}
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case PS_SAW_PERCENT:
|
case PS_SAW_PERCENT:
|
||||||
case PS_SAW_HASH:
|
ps_common:
|
||||||
if (ksh_isalphx(c))
|
if (ksh_isalphx(c))
|
||||||
state = PS_IDENT;
|
state = PS_IDENT;
|
||||||
else if (ksh_isdigit(c))
|
else if (ksh_isdigit(c))
|
||||||
state = PS_NUMBER;
|
state = PS_NUMBER;
|
||||||
else if (c == '#') {
|
else if (ctype(c, C_VAR1))
|
||||||
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))
|
|
||||||
state = PS_VAR1;
|
state = PS_VAR1;
|
||||||
else
|
else
|
||||||
goto out;
|
goto out;
|
||||||
|
Reference in New Issue
Block a user