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>
This commit is contained in:
Denys Vlasenko 2019-05-19 17:23:31 +02:00
parent 30a4c32a4d
commit 9edd268bad
3 changed files with 51 additions and 6 deletions

View File

@ -99,6 +99,11 @@ config FEATURE_SH_MATH_64
slightly larger, but will allow computation with very large numbers. slightly larger, but will allow computation with very large numbers.
This is not in POSIX, so do not rely on this in portable code. 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 config FEATURE_SH_EXTRA_QUIET
bool "Hide message on interactive shell startup" bool "Hide message on interactive shell startup"
default y default y

View File

@ -513,6 +513,42 @@ static const char op_tokens[] ALIGN1 = {
}; };
#define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7]) #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 static arith_t FAST_FUNC
evaluate_string(arith_state_t *math_state, const char *expr) evaluate_string(arith_state_t *math_state, const char *expr)
{ {

View File

@ -65,15 +65,19 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
#if ENABLE_FEATURE_SH_MATH_64 #if ENABLE_FEATURE_SH_MATH_64
typedef long long arith_t; typedef long long arith_t;
#define ARITH_FMT "%lld" # define ARITH_FMT "%lld"
#define strto_arith_t strtoull
#else #else
typedef long arith_t; typedef long arith_t;
#define ARITH_FMT "%ld" # define ARITH_FMT "%ld"
#define strto_arith_t strtoul #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 #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 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); typedef void FAST_FUNC (*arith_var_set_t)(const char *name, const char *val);