ash: fix BASE##nn bashism for bases 36..64
authorDenys Vlasenko <vda.linux@googlemail.com>
Sun, 22 Sep 2019 21:40:10 +0000 (23:40 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Mon, 21 Oct 2019 14:54:40 +0000 (16:54 +0200)
function                                             old     new   delta
evaluate_string                                      876     932     +56

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/math.c

index 0c806ad39107dcace3eed5f5e8cdc78a0092ae22..af1ab55c0500fc5516cc0982cb59de7d1a929ce3 100644 (file)
@@ -540,11 +540,29 @@ static arith_t strto_arith_t(const char *nptr, char **endptr)
        /* bash allows "N#" (empty "nnnn" part) */
        for (;;) {
                unsigned digit = (unsigned)*nptr - '0';
-               if (digit >= 10 || digit >= base) {
+               if (digit >= 10) {
+                       /* *nptr is not 0..9 */
+                       if (*nptr > 'z')
+                               break; /* this rejects e.g. $((64#~)) */
+                       /* in bases up to 36, case does not matter for a-z */
                        digit = (unsigned)(*nptr | 0x20) - ('a' - 10);
-                       if (digit >= base)
-                               break;
+                       if (base > 36 && *nptr <= '_') {
+                               /* otherwise, A-Z,@,_ are 36..61,62,63 */
+                               if (*nptr == '@')
+                                       digit = 62;
+                               else if (*nptr == '_')
+                                       digit = 63;
+                               else if (digit < 36) /* A-Z */
+                                       digit += 36 - 10;
+                               else
+                                       break; /* error, such as [ or \ */
+                       }
+                       //bb_error_msg("ch:'%c'%d digit:%u", *nptr, *nptr, digit);
+                       //if (digit < 10) - example where we need this?
+                       //      break;
                }
+               if (digit >= base)
+                       break;
                /* bash does not check for overflows */
                n = n * base + digit;
                nptr++;