From f8ddbe1ccce9eceaaac28b4b1aa71631fcc56db6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 25 Jul 2016 03:56:00 +0200 Subject: [PATCH] ash: fix handling of ${VAR: -2} Signed-off-by: Denys Vlasenko --- shell/ash.c | 12 ++++++++---- shell/ash_test/ash-vars/var_bash1a.right | 6 ++++++ shell/ash_test/ash-vars/var_bash1a.tests | 11 +++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 shell/ash_test/ash-vars/var_bash1a.right create mode 100755 shell/ash_test/ash-vars/var_bash1a.tests diff --git a/shell/ash.c b/shell/ash.c index 4f6376f78..496167fbe 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -6323,6 +6323,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype, #if ENABLE_ASH_BASH_COMPAT case VSSUBSTR: +//TODO: support more general format ${v:EXPR:EXPR}, +// where EXPR follows $(()) rules loc = str = stackblock() + strloc; /* Read POS in ${var:POS:LEN} */ pos = atoi(loc); /* number(loc) errors out on "1:4" */ @@ -11577,15 +11579,18 @@ parsesub: { STPUTC('=', out); flags = 0; if (subtype == 0) { + static const char types[] ALIGN1 = "}-+?="; /* ${VAR...} but not $VAR or ${#VAR} */ /* c == first char after VAR */ switch (c) { case ':': c = pgetc(); #if ENABLE_ASH_BASH_COMPAT - if (c == ':' || c == '$' || isdigit(c)) { -//TODO: support more general format ${v:EXPR:EXPR}, -// where EXPR follows $(()) rules + /* This check is only needed to not misinterpret + * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD} + * constructs. + */ + if (!strchr(types, c)) { subtype = VSSUBSTR; pungetc(); break; /* "goto do_pungetc" is bigger (!) */ @@ -11594,7 +11599,6 @@ parsesub: { flags = VSNUL; /*FALLTHROUGH*/ default: { - static const char types[] ALIGN1 = "}-+?="; const char *p = strchr(types, c); if (p == NULL) goto badsub; diff --git a/shell/ash_test/ash-vars/var_bash1a.right b/shell/ash_test/ash-vars/var_bash1a.right new file mode 100644 index 000000000..1965b5c6c --- /dev/null +++ b/shell/ash_test/ash-vars/var_bash1a.right @@ -0,0 +1,6 @@ +parameter 'abcdef' +varoffset2 'cdef' +varoffset-2 'ef' +literal '2' 'cdef' +literal '-2' 'abcdef' +literal ' -2' 'ef' diff --git a/shell/ash_test/ash-vars/var_bash1a.tests b/shell/ash_test/ash-vars/var_bash1a.tests new file mode 100755 index 000000000..551dd9acc --- /dev/null +++ b/shell/ash_test/ash-vars/var_bash1a.tests @@ -0,0 +1,11 @@ +parameter=abcdef +offset=2 +noffset=-2 +echo "parameter '${parameter}'" +echo "varoffset2 '${parameter:${offset}}'" +echo "varoffset-2 '${parameter:${noffset}}'" +echo "literal '2' '${parameter:2}'" +# This is not inrpreted as ${VAR:POS{:LEN}}, +# but as ${VAR:=WORD} - if VAR is unset or null, substitute WORD +echo "literal '-2' '${parameter:-2}'" +echo "literal ' -2' '${parameter: -2}'"