ash: [PARSER] Fix parsing of ${##1}
authorDenys Vlasenko <vda.linux@googlemail.com>
Wed, 26 Oct 2016 13:56:53 +0000 (15:56 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Wed, 26 Oct 2016 13:56:53 +0000 (15:56 +0200)
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 <vda.linux@googlemail.com>
shell/ash.c
shell/ash_test/ash-vars/param_expand_len.right
shell/ash_test/ash-vars/param_expand_len.tests
shell/hush_test/hush-vars/param_expand_len.right
shell/hush_test/hush-vars/param_expand_len.tests

index b404449d0a9d035e02e33a93619d6863377cfbe0..2cebfe2c0bada255ce573fa6dcb9322ec06f3c96 100644 (file)
@@ -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)) {
                        /* $[{[#]]<specialchar>[}] */
-                       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;
                }
index 96e8cb59b68a6b53f8226b69e5ae528cb3a48e9d..48d01d2fe37250a9dce6a2ce11105d103a8f48ac 100644 (file)
@@ -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
index fe20a45e957bf55e2af66a2fdf6d3107cac8d99a..369c8d456a8316c131de4c99dd6590d08a039a66 100755 (executable)
@@ -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}
index 96e8cb59b68a6b53f8226b69e5ae528cb3a48e9d..48d01d2fe37250a9dce6a2ce11105d103a8f48ac 100644 (file)
@@ -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
index fe20a45e957bf55e2af66a2fdf6d3107cac8d99a..369c8d456a8316c131de4c99dd6590d08a039a66 100755 (executable)
@@ -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}