aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Denys Vlasenko <vda.linux@googlemail.com>2019-05-19 17:23:31 +0200
committerGravatar Denys Vlasenko <vda.linux@googlemail.com>2019-05-19 17:23:31 +0200
commit9edd268bad93128bcadfbdde28bb978a4b4c5bab (patch)
tree0163e19dd3fb1dc0b16c3c694f4ba39fee0c5cb8
parent30a4c32a4d21728a7e25025f70fcc1d7cd722fe0 (diff)
downloadbusybox-9edd268bad93128bcadfbdde28bb978a4b4c5bab.tar.gz
busybox-9edd268bad93128bcadfbdde28bb978a4b4c5bab.tar.bz2
shell: implement optional "BASE#nnnn" numeric literals
function old new delta evaluate_string 729 851 +122 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/Config.src5
-rw-r--r--shell/math.c36
-rw-r--r--shell/math.h16
3 files changed, 51 insertions, 6 deletions
diff --git a/shell/Config.src b/shell/Config.src
index bc7218fe5..d7623f774 100644
--- a/shell/Config.src
+++ b/shell/Config.src
@@ -99,6 +99,11 @@ config FEATURE_SH_MATH_64
slightly larger, but will allow computation with very large numbers.
This is not in POSIX, so do not rely on this in portable code.
+config FEATURE_SH_MATH_BASE
+ bool "Support BASE#nnnn literals"
+ default y
+ depends on FEATURE_SH_MATH
+
config FEATURE_SH_EXTRA_QUIET
bool "Hide message on interactive shell startup"
default y
diff --git a/shell/math.c b/shell/math.c
index 611b3beab..2ea0317e9 100644
--- a/shell/math.c
+++ b/shell/math.c
@@ -513,6 +513,42 @@ static const char op_tokens[] ALIGN1 = {
};
#define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7])
+#if ENABLE_FEATURE_SH_MATH_BASE
+static arith_t strto_arith_t(const char *nptr, char **endptr)
+{
+ unsigned base;
+ arith_t n;
+
+# if ENABLE_FEATURE_SH_MATH_64
+ n = strtoull(nptr, endptr, 0);
+# else
+ n = strtoul(nptr, endptr, 0);
+# endif
+ if (**endptr != '#'
+ || (*nptr < '1' || *nptr > '9')
+ || (n < 2 || n > 64)
+ ) {
+ return n;
+ }
+
+ /* It's "N#nnnn" or "NN#nnnn" syntax, NN can't start with 0,
+ * NN is in 2..64 range.
+ */
+ base = (unsigned)n;
+ n = 0;
+ nptr = *endptr + 1;
+ /* bash allows "N#" (empty "nnnn" part) */
+ while (isdigit(*nptr)) {
+ /* bash does not check for overflows */
+ n = n * base + (*nptr++ - '0');
+ }
+ *endptr = (char*)nptr;
+ return n;
+}
+#define strto_arith_t(nptr, endptr, base_is_always_0) \
+ strto_arith_t(nptr, endptr)
+#endif
+
static arith_t FAST_FUNC
evaluate_string(arith_state_t *math_state, const char *expr)
{
diff --git a/shell/math.h b/shell/math.h
index 2c5ae9b44..ec9decb1f 100644
--- a/shell/math.h
+++ b/shell/math.h
@@ -65,15 +65,19 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
#if ENABLE_FEATURE_SH_MATH_64
typedef long long arith_t;
-#define ARITH_FMT "%lld"
-#define strto_arith_t strtoull
+# define ARITH_FMT "%lld"
#else
typedef long arith_t;
-#define ARITH_FMT "%ld"
-#define strto_arith_t strtoul
+# define ARITH_FMT "%ld"
+#endif
+
+#if !ENABLE_FEATURE_SH_MATH_BASE
+# if ENABLE_FEATURE_SH_MATH_64
+# define strto_arith_t strtoull
+# else
+# define strto_arith_t strtoul
+# endif
#endif
-//TODO: bash supports "BASE#nnnnn" numeric literals, e.g. 2#1111 = 15.
-//Make strto_arith_t() support that?
typedef const char* FAST_FUNC (*arith_var_lookup_t)(const char *name);
typedef void FAST_FUNC (*arith_var_set_t)(const char *name, const char *val);