From 9edd268bad93128bcadfbdde28bb978a4b4c5bab Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 19 May 2019 17:23:31 +0200 Subject: shell: implement optional "BASE#nnnn" numeric literals function old new delta evaluate_string 729 851 +122 Signed-off-by: Denys Vlasenko --- shell/Config.src | 5 +++++ shell/math.c | 36 ++++++++++++++++++++++++++++++++++++ shell/math.h | 16 ++++++++++------ 3 files changed, 51 insertions(+), 6 deletions(-) (limited to 'shell') diff --git a/shell/Config.src b/shell/Config.src index bc7218f..d7623f7 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 611b3be..2ea0317 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 2c5ae9b..ec9decb 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); -- cgit v1.1