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:
parent
2747f6195b
commit
680ccd3573
@ -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 {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user