[git commit branch/1_30_stable] bc: support ibase up to 36 (GNU compat)

Denys Vlasenko vda.linux at googlemail.com
Thu Feb 14 13:40:57 UTC 2019


commit: https://git.busybox.net/busybox/commit/?id=8a7411fcc875711663b7e5439f86a3184e0cb863
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/1_30_stable

function                                             old     new   delta
zxc_program_num                                      995    1018     +23

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 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;
-
-	for (i = 0; ; ++i) {
-		if (val[i] == '\0')
-			return;
-		if (val[i] != '.' && val[i] != '0')
-			break;
-	}
+	size_t digits;
 
-	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


More information about the busybox-cvs mailing list