[prev in list] [next in list] [prev in thread] [next in thread] 

List:       busybox-cvs
Subject:    [git commit] bc: fix handling of "digits" above 9
From:       Denys Vlasenko <vda.linux () googlemail ! com>
Date:       2018-12-29 1:24:19
Message-ID: 20181229012010.EE8B786647 () busybox ! osuosl ! org
[Download RAW message or body]

commit: https://git.busybox.net/busybox/commit/?id6a5223d20e5715b98e1fd21fa8d59e75e4e793
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
zxc_lex_next                                        1573    1608     +35
xc_parse_pushIndex                                    58      56      -2
xc_program_index                                      71      63      -8
zxc_program_num                                     1022     990     -32
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/3 up/down: 35/-42)             Total: -7 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 miscutils/bc.c                    | 82 ++++++++++++++++++++++++++++++---------
 testsuite/bc_numbers1.bc          | 23 +++++++++++
 testsuite/bc_numbers1_results.txt | 17 ++++++++
 3 files changed, 103 insertions(+), 19 deletions(-)

diff --git a/miscutils/bc.c b/miscutils/bc.c
index c10cd73fa..07327af6f 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -2555,13 +2555,16 @@ static void xc_read_line(BcVec *vec, FILE *fp)
 // Parsing routines
 //

-static bool xc_num_strValid(const char *val, size_t base)
-{
-	BcDig b;
-	bool radix;
-
-	b = (BcDig)(base <= 10 ? base + '0' : base - 10 + 'A');
-	radix = false;
+// "Input numbers may contain the characters 0-9 and A-Z.
+// (Note: They must be capitals.  Lower case letters are variable names.)
+// Single digit numbers always have the value of the digit regardless of
+// the value of ibase. (i.e. A = 10.) For multi-digit numbers, bc changes
+// all input digits greater or equal to ibase to the value of ibase-1.
+// This makes the number ZZZ always be the largest 3 digit number of the
+// input base."
+static bool xc_num_strValid(const char *val)
+{
+	bool radix = false;
 	for (;;) {
 		BcDig c = *val++;
 		if (c == '\0')
@@ -2571,7 +2574,7 @@ static bool xc_num_strValid(const char *val, size_t base)
 			radix = true;
 			continue;
 		}
-		if (c < '0' || c >= b || (c > '9' && c < 'A'))
+		if ((c < '0' || c > '9') && (c < 'A' || c > 'Z'))
 			return false;
 	}
 	return true;
@@ -2599,10 +2602,21 @@ static void bc_num_parseDecimal(BcNum *n, const char *val)
 	for (i = 0; val[i]; ++i) {
 		if (val[i] != '0' && val[i] != '.') {
 			// Not entirely zero value - convert it, and exit
+			if (len == 1) {
+				char c = val[0] - '0';
+				if (c > 9) // A-Z => 10-36
+					c -= ('A' - '9' - 1);
+				n->num[0] = c;
+				n->len = 1;
+				break;
+			}
 			i = len - 1;
 			for (;;) {
-				n->num[n->len] = val[i] - '0';
-				++n->len;
+				char c = val[i] - '0';
+				if (c > 9) // A-Z => 9
+					c = 9;
+				n->num[n->len] = c;
+				n->len++;
  skip_dot:
 				if (i == 0) break;
 				if (val[--i] == '.') goto skip_dot;
@@ -2692,7 +2706,7 @@ static void bc_num_parseBase(BcNum *n, const char *val, unsigned base_t)

 static BC_STATUS zxc_num_parse(BcNum *n, const char *val, unsigned base_t)
 {
-	if (!xc_num_strValid(val, base_t))
+	if (!xc_num_strValid(val))
 		RETURN_STATUS(bc_error("bad number string"));

 	bc_num_zero(n);
@@ -2807,6 +2821,13 @@ static BC_STATUS zxc_lex_number(char last)
 	bc_vec_pop_all(&p->lex_strnumbuf);
 	bc_vec_pushByte(&p->lex_strnumbuf, last);

+// "Input numbers may contain the characters 0-9 and A-Z.
+// (Note: They must be capitals.  Lower case letters are variable names.)
+// Single digit numbers always have the value of the digit regardless of
+// the value of ibase. (i.e. A = 10.) For multi-digit numbers, bc changes
+// all input digits greater or equal to ibase to the value of ibase-1.
+// This makes the number ZZZ always be the largest 3 digit number of the
+// input base."
 	pt = (last == '.');
 	p->lex = XC_LEX_NUMBER;
 	for (;;) {
@@ -2822,13 +2843,13 @@ static BC_STATUS zxc_lex_number(char last)
 			c = peek_inbuf(); // force next line to be read
 			goto check_c;
 		}
-		if (!isdigit(c) && (c < 'A' || c > 'F')) {
+		if (!isdigit(c) && (c < 'A' || c > 'Z')) {
 			if (c != '.') break;
 			// if '.' was already seen, stop on second one:
 			if (pt) break;
 			pt = true;
 		}
-		// c is one of "0-9A-F."
+		// c is one of "0-9A-Z."
 		last = c;
 		bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf);
 		p->lex_inbuf++;
@@ -3167,6 +3188,26 @@ static BC_STATUS zbc_lex_token(void)
 	case 'D':
 	case 'E':
 	case 'F':
+	case 'G':
+	case 'H':
+	case 'I':
+	case 'J':
+	case 'K':
+	case 'L':
+	case 'M':
+	case 'N':
+	case 'O':
+	case 'P':
+	case 'Q':
+	case 'R':
+	case 'S':
+	case 'T':
+	case 'U':
+	case 'V':
+	case 'W':
+	case 'X':
+	case 'Y':
+	case 'Z':
 		s = zxc_lex_number(c);
 		break;
 	case ';':
@@ -3450,13 +3491,14 @@ static void xc_parse_pushIndex(size_t idx)

 	mask = ((size_t)0xff) << (sizeof(idx) * 8 - 8);
 	amt = sizeof(idx);
-	do {
+	for (;;) {
 		if (idx & mask) break;
 		mask >>= 8;
 		amt--;
-	} while (amt != 0);
+	}
+	// amt is at least 1 here - "one byte of length data follows"

-	xc_parse_push(SMALL_INDEX_LIMIT + amt);
+	xc_parse_push((SMALL_INDEX_LIMIT - 1) + amt);

 	while (idx != 0) {
  push_idx:
@@ -5260,13 +5302,15 @@ static size_t xc_program_index(char *code, size_t *bgn)
 		*bgn += 1;
 		return amt;
 	}
-	amt -= SMALL_INDEX_LIMIT;
+	amt -= (SMALL_INDEX_LIMIT - 1); // amt is 1 or more here
 	*bgn += amt + 1;

-	amt *= 8;
 	res = 0;
-	for (i = 0; i < amt; i += 8)
+	i = 0;
+	do {
 		res |= (size_t)(*bytes++) << i;
+		i += 8;
+	} while (--amt != 0);

 	return res;
 }
diff --git a/testsuite/bc_numbers1.bc b/testsuite/bc_numbers1.bc
new file mode 100644
index 000000000..fd4e225ee
--- /dev/null
+++ b/testsuite/bc_numbers1.bc
@@ -0,0 +1,23 @@
+ibase=G
+define f() {
+a00;a01;a02;a03;a04;a05;a06;a07;a08;a09	;a0a
;a0b;a0c;a0d
;a0e;a0f
+a10;a11;a12;a13;a14;a15;a16;a17;a18;a19;a1a;a1b;a1c;a1d;a1e;a1f
+a20 ;a21!;a22";a23#;a24$;a25%;a26&;a27';a28(;a29);a2a*;a2b+;a2c,;a2d-;a2e.;a2f/
+a300;a311;a322;a333;a344;a355;a366;a377;a388;a399;a3a:;a3b;;a3c<;a3d=;a3e>;a3f?
+a40@;a41A;a42B;a43C;a44D;a45E;a46F;a47G;a48H;a49I;a4aJ;a4bK;a4cL;a4dM;a4eN;a4fO
+a50P;a51Q;a52R;a53S;a54T;a55U;a56V;a57W;a58X;a59Y;a5aZ;a5b[;a5c\;a5d];a5e^;a5f_
+a60`;a61a;a62b;a63c;a64d;a65e;a66f;a67g;a68h;a69i;a6aj;a6bk;a6cl;a6dm;a6en;a6fo
+a70p;a71q;a72r;a73s;a74t;a75u;a76v;a77w;a78x;a79y;a7az;a7b{;a7c|;a7d};a7e~;a7f
+a80;a81;a82;a83;a84;a85;a86;a87;a88;a89;a8a;a8b;a8c;a8d;a8e;a8f
+a90;a91;a92;a93;a94;a95;a96;a97;a98;a99;a9a;a9b;a9c;a9d;a9e;a9f
+aa0 ;aa1;aa2;aa3;aa4;aa5;aa6;aa7;aa8;aa9;aaa;aab;aac;aad;aae;aaf
+ab0;ab1;ab2;ab3;ab4;ab5;ab6;ab7;ab8;ab9;aba;abb;abc;abd;abe;abf
+ac0;ac1;ac2 ;ac3;ac4;ac5;ac6;ac7;ac8;ac9;aca;acb;acc;acd;ace;acf
+ad0;ad1;ad2;ad3;ad4;ad5;ad6;ad7;ad8;ad9;ada;adb;adc;add;ade;adf
+ae0;ae1;ae2;ae3;ae4;ae5;ae6;ae7;ae8;ae9;aea;aeb;aec;aed;aee;aef
+af0;af1;af2;af3;af4;af5;af6;af7;af8;af9;afa;afb;afc;afd;afe;aff
+# this tests "index encoding" in bc.c: are numbers after 0xfc encoded correctly?
+af0;af1;af2;af3;af4;af5;af6;af7;af8;af9;afa;afb;afc;afd;afe;aff
+}
+f()
+halt
diff --git a/testsuite/bc_numbers1_results.txt b/testsuite/bc_numbers1_results.txt
new file mode 100644
index 000000000..e0ace1049
--- /dev/null
+++ b/testsuite/bc_numbers1_results.txt
@@ -0,0 +1,17 @@
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+0
_______________________________________________
busybox-cvs mailing list
busybox-cvs@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox-cvs
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic