From f15aa57a7f5edcbf3098873b8798c0ea7f496ed7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Oct 2016 15:56:53 +0200 Subject: ash: [PARSER] Fix parsing of ${##1} Upstream commit: Date: Thu, 4 Oct 2007 22:15:10 +0800 [PARSER] Fix parsing of ${##1} Previously dash treated ${##1} as a length operation. This patch fixes that. Test case: set -- a echo ${##1}OK Old result: 1OK New result: OK This was a real bug in ash (but not in hush). Signed-off-by: Denys Vlasenko --- shell/ash.c | 28 +++++++++++++++--------- shell/ash_test/ash-vars/param_expand_len.right | 3 +++ shell/ash_test/ash-vars/param_expand_len.tests | 7 ++++++ shell/hush_test/hush-vars/param_expand_len.right | 3 +++ shell/hush_test/hush-vars/param_expand_len.tests | 7 ++++++ 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index b404449d0..2cebfe2c0 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -11728,16 +11728,9 @@ parsesub: { subtype = VSNORMAL; if (c == '{') { c = pgetc_eatbnl(); - if (c == '#') { - c = pgetc_eatbnl(); - if (c == '}') - c = '#'; /* ${#} - same as $# */ - else - subtype = VSLENGTH; /* ${#VAR} */ - } else { - subtype = 0; - } + subtype = 0; } + varname: if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) { /* $[{[#]]NAME[}] */ do { @@ -11752,8 +11745,23 @@ parsesub: { } while (isdigit(c)); } else if (is_special(c)) { /* $[{[#]][}] */ - USTPUTC(c, out); + int cc = c; + c = pgetc_eatbnl(); + if (!subtype && cc == '#') { + subtype = VSLENGTH; + if (c == '_' || isalnum(c)) + goto varname; + cc = c; + c = pgetc_eatbnl(); + if (cc == '}' || c != '}') { + pungetc(); + subtype = 0; + c = cc; + cc = '#'; + } + } + USTPUTC(cc, out); } else { goto badsub; } diff --git a/shell/ash_test/ash-vars/param_expand_len.right b/shell/ash_test/ash-vars/param_expand_len.right index 96e8cb59b..48d01d2fe 100644 --- a/shell/ash_test/ash-vars/param_expand_len.right +++ b/shell/ash_test/ash-vars/param_expand_len.right @@ -7,3 +7,6 @@ Make sure len parsing doesnt break arg count Testing len op 4 3 2 1 0 0 0 3 0 +Nothing: +Nothing: +One:1 diff --git a/shell/ash_test/ash-vars/param_expand_len.tests b/shell/ash_test/ash-vars/param_expand_len.tests index fe20a45e9..369c8d456 100755 --- a/shell/ash_test/ash-vars/param_expand_len.tests +++ b/shell/ash_test/ash-vars/param_expand_len.tests @@ -15,3 +15,10 @@ unset e f=abc g= echo ${#e} ${#f} ${#g} + +set -- a +# This must be interpreted as: $# ("1"), then remove trailing "1". +# IOW: empty result. +echo Nothing:${##1} +echo Nothing:${#%1} +echo One:${##x} diff --git a/shell/hush_test/hush-vars/param_expand_len.right b/shell/hush_test/hush-vars/param_expand_len.right index 96e8cb59b..48d01d2fe 100644 --- a/shell/hush_test/hush-vars/param_expand_len.right +++ b/shell/hush_test/hush-vars/param_expand_len.right @@ -7,3 +7,6 @@ Make sure len parsing doesnt break arg count Testing len op 4 3 2 1 0 0 0 3 0 +Nothing: +Nothing: +One:1 diff --git a/shell/hush_test/hush-vars/param_expand_len.tests b/shell/hush_test/hush-vars/param_expand_len.tests index fe20a45e9..369c8d456 100755 --- a/shell/hush_test/hush-vars/param_expand_len.tests +++ b/shell/hush_test/hush-vars/param_expand_len.tests @@ -15,3 +15,10 @@ unset e f=abc g= echo ${#e} ${#f} ${#g} + +set -- a +# This must be interpreted as: $# ("1"), then remove trailing "1". +# IOW: empty result. +echo Nothing:${##1} +echo Nothing:${#%1} +echo One:${##x} -- cgit v1.2.3