From 680ccd357395ad081afe821ffbeef1ff338fe41d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 31 Dec 2018 19:42:13 +0100 Subject: [PATCH] bc: support ibase up to 36 (GNU compat) function old new delta zxc_program_num 995 1018 +23 Signed-off-by: Denys Vlasenko --- miscutils/bc.c | 50 ++++++++++++++++++++++++++++------------------ testsuite/bc.tests | 5 +++++ 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/miscutils/bc.c b/miscutils/bc.c index 72c23542c..798bc0a3e 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c @@ -5,7 +5,6 @@ * Original code copyright (c) 2018 Gavin D. Howard and contributors. */ //TODO: GNU extensions: -// support ibase up to 36 // support "define void f()..." // support "define f(*param[])" - "pass array by reference" syntax @@ -231,7 +230,7 @@ typedef struct BcNum { bool neg; } BcNum; -#define BC_NUM_MAX_IBASE ((unsigned long) 16) +#define BC_NUM_MAX_IBASE 36 // larger value might speed up BIGNUM calculations a bit: #define BC_NUM_DEF_SIZE 16 #define BC_NUM_PRINT_WIDTH 69 @@ -2638,32 +2637,33 @@ static void bc_num_parseDecimal(BcNum *n, const char *val) static void bc_num_parseBase(BcNum *n, const char *val, unsigned base_t) { BcStatus s; - BcNum temp, mult, result; + BcNum mult, result; + BcNum temp; BcNum base; + BcDig temp_digs[ULONG_NUM_BUFSIZE]; BcDig base_digs[ULONG_NUM_BUFSIZE]; BcDig c = '\0'; - unsigned long v; - size_t i, digits; + size_t digits; - for (i = 0; ; ++i) { - if (val[i] == '\0') - return; - if (val[i] != '.' && val[i] != '0') - break; - } - - bc_num_init_DEF_SIZE(&temp); bc_num_init_DEF_SIZE(&mult); + + temp.cap = ARRAY_SIZE(temp_digs); + temp.num = temp_digs; + base.cap = ARRAY_SIZE(base_digs); base.num = base_digs; bc_num_ulong2num(&base, base_t); + base_t--; for (;;) { + unsigned v; + c = *val++; if (c == '\0') goto int_err; if (c == '.') break; - v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10); + v = (unsigned)(c <= '9' ? c - '0' : c - 'A' + 10); + if (v > base_t) v = base_t; s = zbc_num_mul(n, &base, &mult, 0); if (s) goto int_err; @@ -2678,11 +2678,14 @@ static void bc_num_parseBase(BcNum *n, const char *val, unsigned base_t) digits = 0; for (;;) { + unsigned v; + c = *val++; if (c == '\0') break; digits++; - v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10); + v = (unsigned)(c <= '9' ? c - '0' : c - 'A' + 10); + if (v > base_t) v = base_t; s = zbc_num_mul(&result, &base, &result, 0); if (s) goto err; @@ -2707,18 +2710,27 @@ static void bc_num_parseBase(BcNum *n, const char *val, unsigned base_t) bc_num_free(&result); int_err: bc_num_free(&mult); - bc_num_free(&temp); } static BC_STATUS zxc_num_parse(BcNum *n, const char *val, unsigned base_t) { + size_t i; + if (!xc_num_strValid(val)) RETURN_STATUS(bc_error("bad number string")); bc_num_zero(n); - while (*val == '0') val++; + while (*val == '0') + val++; + for (i = 0; ; ++i) { + if (val[i] == '\0') + RETURN_STATUS(BC_STATUS_SUCCESS); + if (val[i] != '.' && val[i] != '0') + break; + } - if (base_t == 10) + if (base_t == 10 || val[1] == '\0') + // Decimal, or single-digit number bc_num_parseDecimal(n, val); else bc_num_parseBase(n, val, base_t); @@ -5526,7 +5538,7 @@ static BC_STATUS zxc_num_printBase(BcNum *n) n->neg = false; - if (G.prog.ob_t <= BC_NUM_MAX_IBASE) { + if (G.prog.ob_t <= 16) { width = 1; print = bc_num_printHex; } else { diff --git a/testsuite/bc.tests b/testsuite/bc.tests index 3fbb49996..1d4545559 100755 --- a/testsuite/bc.tests +++ b/testsuite/bc.tests @@ -218,6 +218,11 @@ for(i=1; i<3; i++) { 99 " +testing "bc ibase" \ + "bc" \ + "99\n1295\n1224\n" \ + "" "a=ZZ;a;ibase=36;a=ZZ;a;ibase=Z;a=ZZ;a" + tar xJf bc_large.tar.xz for f in bc*.bc; do