aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-12-31 19:42:13 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-12-31 19:42:13 +0100
commit680ccd357395ad081afe821ffbeef1ff338fe41d (patch)
treeb6c8622f8f221c5691346fe9ec4ff31ecbc74d8d
parent2747f6195b94db6c1adf2eae243df5c0a01d39f2 (diff)
downloadbusybox-w32-680ccd357395ad081afe821ffbeef1ff338fe41d.tar.gz
busybox-w32-680ccd357395ad081afe821ffbeef1ff338fe41d.tar.bz2
busybox-w32-680ccd357395ad081afe821ffbeef1ff338fe41d.zip
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>
-rw-r--r--miscutils/bc.c50
-rwxr-xr-xtestsuite/bc.tests5
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 @@
5 * Original code copyright (c) 2018 Gavin D. Howard and contributors. 5 * Original code copyright (c) 2018 Gavin D. Howard and contributors.
6 */ 6 */
7//TODO: GNU extensions: 7//TODO: GNU extensions:
8// support ibase up to 36
9// support "define void f()..." 8// support "define void f()..."
10// support "define f(*param[])" - "pass array by reference" syntax 9// support "define f(*param[])" - "pass array by reference" syntax
11 10
@@ -231,7 +230,7 @@ typedef struct BcNum {
231 bool neg; 230 bool neg;
232} BcNum; 231} BcNum;
233 232
234#define BC_NUM_MAX_IBASE ((unsigned long) 16) 233#define BC_NUM_MAX_IBASE 36
235// larger value might speed up BIGNUM calculations a bit: 234// larger value might speed up BIGNUM calculations a bit:
236#define BC_NUM_DEF_SIZE 16 235#define BC_NUM_DEF_SIZE 16
237#define BC_NUM_PRINT_WIDTH 69 236#define BC_NUM_PRINT_WIDTH 69
@@ -2638,32 +2637,33 @@ static void bc_num_parseDecimal(BcNum *n, const char *val)
2638static void bc_num_parseBase(BcNum *n, const char *val, unsigned base_t) 2637static void bc_num_parseBase(BcNum *n, const char *val, unsigned base_t)
2639{ 2638{
2640 BcStatus s; 2639 BcStatus s;
2641 BcNum temp, mult, result; 2640 BcNum mult, result;
2641 BcNum temp;
2642 BcNum base; 2642 BcNum base;
2643 BcDig temp_digs[ULONG_NUM_BUFSIZE];
2643 BcDig base_digs[ULONG_NUM_BUFSIZE]; 2644 BcDig base_digs[ULONG_NUM_BUFSIZE];
2644 BcDig c = '\0'; 2645 BcDig c = '\0';
2645 unsigned long v; 2646 size_t digits;
2646 size_t i, digits;
2647
2648 for (i = 0; ; ++i) {
2649 if (val[i] == '\0')
2650 return;
2651 if (val[i] != '.' && val[i] != '0')
2652 break;
2653 }
2654 2647
2655 bc_num_init_DEF_SIZE(&temp);
2656 bc_num_init_DEF_SIZE(&mult); 2648 bc_num_init_DEF_SIZE(&mult);
2649
2650 temp.cap = ARRAY_SIZE(temp_digs);
2651 temp.num = temp_digs;
2652
2657 base.cap = ARRAY_SIZE(base_digs); 2653 base.cap = ARRAY_SIZE(base_digs);
2658 base.num = base_digs; 2654 base.num = base_digs;
2659 bc_num_ulong2num(&base, base_t); 2655 bc_num_ulong2num(&base, base_t);
2656 base_t--;
2660 2657
2661 for (;;) { 2658 for (;;) {
2659 unsigned v;
2660
2662 c = *val++; 2661 c = *val++;
2663 if (c == '\0') goto int_err; 2662 if (c == '\0') goto int_err;
2664 if (c == '.') break; 2663 if (c == '.') break;
2665 2664
2666 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10); 2665 v = (unsigned)(c <= '9' ? c - '0' : c - 'A' + 10);
2666 if (v > base_t) v = base_t;
2667 2667
2668 s = zbc_num_mul(n, &base, &mult, 0); 2668 s = zbc_num_mul(n, &base, &mult, 0);
2669 if (s) goto int_err; 2669 if (s) goto int_err;
@@ -2678,11 +2678,14 @@ static void bc_num_parseBase(BcNum *n, const char *val, unsigned base_t)
2678 2678
2679 digits = 0; 2679 digits = 0;
2680 for (;;) { 2680 for (;;) {
2681 unsigned v;
2682
2681 c = *val++; 2683 c = *val++;
2682 if (c == '\0') break; 2684 if (c == '\0') break;
2683 digits++; 2685 digits++;
2684 2686
2685 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10); 2687 v = (unsigned)(c <= '9' ? c - '0' : c - 'A' + 10);
2688 if (v > base_t) v = base_t;
2686 2689
2687 s = zbc_num_mul(&result, &base, &result, 0); 2690 s = zbc_num_mul(&result, &base, &result, 0);
2688 if (s) goto err; 2691 if (s) goto err;
@@ -2707,18 +2710,27 @@ static void bc_num_parseBase(BcNum *n, const char *val, unsigned base_t)
2707 bc_num_free(&result); 2710 bc_num_free(&result);
2708 int_err: 2711 int_err:
2709 bc_num_free(&mult); 2712 bc_num_free(&mult);
2710 bc_num_free(&temp);
2711} 2713}
2712 2714
2713static BC_STATUS zxc_num_parse(BcNum *n, const char *val, unsigned base_t) 2715static BC_STATUS zxc_num_parse(BcNum *n, const char *val, unsigned base_t)
2714{ 2716{
2717 size_t i;
2718
2715 if (!xc_num_strValid(val)) 2719 if (!xc_num_strValid(val))
2716 RETURN_STATUS(bc_error("bad number string")); 2720 RETURN_STATUS(bc_error("bad number string"));
2717 2721
2718 bc_num_zero(n); 2722 bc_num_zero(n);
2719 while (*val == '0') val++; 2723 while (*val == '0')
2724 val++;
2725 for (i = 0; ; ++i) {
2726 if (val[i] == '\0')
2727 RETURN_STATUS(BC_STATUS_SUCCESS);
2728 if (val[i] != '.' && val[i] != '0')
2729 break;
2730 }
2720 2731
2721 if (base_t == 10) 2732 if (base_t == 10 || val[1] == '\0')
2733 // Decimal, or single-digit number
2722 bc_num_parseDecimal(n, val); 2734 bc_num_parseDecimal(n, val);
2723 else 2735 else
2724 bc_num_parseBase(n, val, base_t); 2736 bc_num_parseBase(n, val, base_t);
@@ -5526,7 +5538,7 @@ static BC_STATUS zxc_num_printBase(BcNum *n)
5526 5538
5527 n->neg = false; 5539 n->neg = false;
5528 5540
5529 if (G.prog.ob_t <= BC_NUM_MAX_IBASE) { 5541 if (G.prog.ob_t <= 16) {
5530 width = 1; 5542 width = 1;
5531 print = bc_num_printHex; 5543 print = bc_num_printHex;
5532 } else { 5544 } 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++) {
21899 21899
219" 219"
220 220
221testing "bc ibase" \
222 "bc" \
223 "99\n1295\n1224\n" \
224 "" "a=ZZ;a;ibase=36;a=ZZ;a;ibase=Z;a=ZZ;a"
225
221tar xJf bc_large.tar.xz 226tar xJf bc_large.tar.xz
222 227
223for f in bc*.bc; do 228for f in bc*.bc; do