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>
diff --git a/miscutils/bc.c b/miscutils/bc.c
index 72c2354..798bc0a 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 @@
 	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_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 @@
 
 	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 @@
 	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 @@
 
 	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 {