diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-31 19:42:13 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-31 19:42:13 +0100 |
commit | 680ccd357395ad081afe821ffbeef1ff338fe41d (patch) | |
tree | b6c8622f8f221c5691346fe9ec4ff31ecbc74d8d | |
parent | 2747f6195b94db6c1adf2eae243df5c0a01d39f2 (diff) | |
download | busybox-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.c | 50 | ||||
-rwxr-xr-x | 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 @@ | |||
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) | |||
2638 | static void bc_num_parseBase(BcNum *n, const char *val, unsigned base_t) | 2637 | static 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 | ||
2713 | static BC_STATUS zxc_num_parse(BcNum *n, const char *val, unsigned base_t) | 2715 | static 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++) { | |||
218 | 99 | 218 | 99 |
219 | " | 219 | " |
220 | 220 | ||
221 | testing "bc ibase" \ | ||
222 | "bc" \ | ||
223 | "99\n1295\n1224\n" \ | ||
224 | "" "a=ZZ;a;ibase=36;a=ZZ;a;ibase=Z;a=ZZ;a" | ||
225 | |||
221 | tar xJf bc_large.tar.xz | 226 | tar xJf bc_large.tar.xz |
222 | 227 | ||
223 | for f in bc*.bc; do | 228 | for f in bc*.bc; do |