bc: support ibase up to 36 (GNU compat)

function                                             old     new   delta
zxc_program_num                                      995    1018     +23

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2018-12-31 19:42:13 +01:00
parent 2747f6195b
commit 680ccd3573
2 changed files with 36 additions and 19 deletions

View File

@ -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 {

View File

@ -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