aboutsummaryrefslogtreecommitdiff
path: root/miscutils/bc.c
diff options
context:
space:
mode:
Diffstat (limited to 'miscutils/bc.c')
-rw-r--r--miscutils/bc.c111
1 files changed, 60 insertions, 51 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c
index 4d987325e..53eb5c799 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -231,7 +231,7 @@ typedef struct BcNum {
231#define BC_NUM_MAX_IBASE 36 231#define BC_NUM_MAX_IBASE 36
232// larger value might speed up BIGNUM calculations a bit: 232// larger value might speed up BIGNUM calculations a bit:
233#define BC_NUM_DEF_SIZE 16 233#define BC_NUM_DEF_SIZE 16
234#define BC_NUM_PRINT_WIDTH 69 234#define BC_NUM_PRINT_WIDTH 70
235 235
236#define BC_NUM_KARATSUBA_LEN 32 236#define BC_NUM_KARATSUBA_LEN 32
237 237
@@ -517,7 +517,7 @@ struct BcLexKeyword {
517}; 517};
518#define LEX_KW_ENTRY(a, b) \ 518#define LEX_KW_ENTRY(a, b) \
519 { .name8 = a /*, .posix = b */ } 519 { .name8 = a /*, .posix = b */ }
520static const struct BcLexKeyword bc_lex_kws[20] = { 520static const struct BcLexKeyword bc_lex_kws[20] ALIGN8 = {
521 LEX_KW_ENTRY("auto" , 1), // 0 521 LEX_KW_ENTRY("auto" , 1), // 0
522 LEX_KW_ENTRY("break" , 1), // 1 522 LEX_KW_ENTRY("break" , 1), // 1
523 LEX_KW_ENTRY("continue", 0), // 2 note: this one has no terminating NUL 523 LEX_KW_ENTRY("continue", 0), // 2 note: this one has no terminating NUL
@@ -1827,7 +1827,7 @@ static FAST_FUNC BC_STATUS zbc_num_k(BcNum *restrict a, BcNum *restrict b,
1827#define zbc_num_k(...) (zbc_num_k(__VA_ARGS__) COMMA_SUCCESS) 1827#define zbc_num_k(...) (zbc_num_k(__VA_ARGS__) COMMA_SUCCESS)
1828{ 1828{
1829 BcStatus s; 1829 BcStatus s;
1830 size_t max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2; 1830 size_t max, max2;
1831 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp; 1831 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1832 bool aone; 1832 bool aone;
1833 1833
@@ -1841,9 +1841,9 @@ static FAST_FUNC BC_STATUS zbc_num_k(BcNum *restrict a, BcNum *restrict b,
1841 RETURN_STATUS(BC_STATUS_SUCCESS); 1841 RETURN_STATUS(BC_STATUS_SUCCESS);
1842 } 1842 }
1843 1843
1844 if (a->len + b->len < BC_NUM_KARATSUBA_LEN 1844 if (a->len < BC_NUM_KARATSUBA_LEN
1845 || a->len < BC_NUM_KARATSUBA_LEN
1846 || b->len < BC_NUM_KARATSUBA_LEN 1845 || b->len < BC_NUM_KARATSUBA_LEN
1846 /* || a->len + b->len < BC_NUM_KARATSUBA_LEN - redundant check */
1847 ) { 1847 ) {
1848 size_t i, j, len; 1848 size_t i, j, len;
1849 1849
@@ -1877,6 +1877,7 @@ static FAST_FUNC BC_STATUS zbc_num_k(BcNum *restrict a, BcNum *restrict b,
1877 RETURN_STATUS(BC_STATUS_SUCCESS); 1877 RETURN_STATUS(BC_STATUS_SUCCESS);
1878 } 1878 }
1879 1879
1880 max = BC_MAX(a->len, b->len);
1880 bc_num_init(&l1, max); 1881 bc_num_init(&l1, max);
1881 bc_num_init(&h1, max); 1882 bc_num_init(&h1, max);
1882 bc_num_init(&l2, max); 1883 bc_num_init(&l2, max);
@@ -1888,6 +1889,7 @@ static FAST_FUNC BC_STATUS zbc_num_k(BcNum *restrict a, BcNum *restrict b,
1888 bc_num_init(&z2, max); 1889 bc_num_init(&z2, max);
1889 bc_num_init(&temp, max + max); 1890 bc_num_init(&temp, max + max);
1890 1891
1892 max2 = (max + 1) / 2;
1891 bc_num_split(a, max2, &l1, &h1); 1893 bc_num_split(a, max2, &l1, &h1);
1892 bc_num_split(b, max2, &l2, &h2); 1894 bc_num_split(b, max2, &l2, &h2);
1893 1895
@@ -2201,8 +2203,8 @@ static BC_STATUS zbc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2201 BcStatus s; 2203 BcStatus s;
2202 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp; 2204 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2203 BcDig half_digs[1]; 2205 BcDig half_digs[1];
2204 size_t pow, len, digs, digs1, resrdx, req, times = 0; 2206 size_t pow, len, digs, digs1, resrdx, req, times;
2205 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX; 2207 ssize_t cmp, cmp1, cmp2;
2206 2208
2207 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1; 2209 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2208 bc_num_expand(b, req); 2210 bc_num_expand(b, req);
@@ -2255,11 +2257,12 @@ static BC_STATUS zbc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2255 x0->rdx -= pow; 2257 x0->rdx -= pow;
2256 } 2258 }
2257 2259
2258 x0->rdx = digs = digs1 = 0; 2260 x0->rdx = digs = digs1 = times = 0;
2259 resrdx = scale + 2; 2261 resrdx = scale + 2;
2260 len = BC_NUM_INT(x0) + resrdx - 1; 2262 len = x0->len + resrdx - 1;
2261 2263 cmp = 1;
2262 while (cmp != 0 || digs < len) { 2264 cmp1 = cmp2 = SSIZE_MAX;
2265 do {
2263 s = zbc_num_div(a, x0, &f, resrdx); 2266 s = zbc_num_div(a, x0, &f, resrdx);
2264 if (s) goto err; 2267 if (s) goto err;
2265 s = zbc_num_add(x0, &f, &fprime, resrdx); 2268 s = zbc_num_add(x0, &f, &fprime, resrdx);
@@ -2284,11 +2287,12 @@ static BC_STATUS zbc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2284 temp = x0; 2287 temp = x0;
2285 x0 = x1; 2288 x0 = x1;
2286 x1 = temp; 2289 x1 = temp;
2287 } 2290 } while (cmp != 0 || digs < len);
2288 2291
2289 bc_num_copy(b, x0); 2292 bc_num_copy(b, x0);
2290 scale -= 1; 2293 scale -= 1;
2291 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale); 2294 if (b->rdx > scale)
2295 bc_num_truncate(b, b->rdx - scale);
2292 err: 2296 err:
2293 bc_num_free(&fprime); 2297 bc_num_free(&fprime);
2294 bc_num_free(&f); 2298 bc_num_free(&f);
@@ -2522,9 +2526,6 @@ static void xc_read_line(BcVec *vec, FILE *fp)
2522 2526
2523#if ENABLE_FEATURE_BC_INTERACTIVE 2527#if ENABLE_FEATURE_BC_INTERACTIVE
2524 if (G_interrupt) { // ^C was pressed 2528 if (G_interrupt) { // ^C was pressed
2525# if ENABLE_FEATURE_EDITING
2526 intr:
2527# endif
2528 if (fp != stdin) { 2529 if (fp != stdin) {
2529 // ^C while running a script (bc SCRIPT): die. 2530 // ^C while running a script (bc SCRIPT): die.
2530 // We do not return to interactive prompt: 2531 // We do not return to interactive prompt:
@@ -2535,22 +2536,25 @@ static void xc_read_line(BcVec *vec, FILE *fp)
2535 // the shell would be unexpected. 2536 // the shell would be unexpected.
2536 xfunc_die(); 2537 xfunc_die();
2537 } 2538 }
2538 // ^C while interactive input 2539 // There was ^C while running calculations
2539 G_interrupt = 0; 2540 G_interrupt = 0;
2540 // GNU bc says "interrupted execution." 2541 // GNU bc says "interrupted execution." (to stdout, not stderr)
2541 // GNU dc says "Interrupt!" 2542 // GNU dc says "Interrupt!"
2542 fputs("\ninterrupted execution\n", stderr); 2543 puts("\ninterrupted execution");
2543 } 2544 }
2544 2545
2545# if ENABLE_FEATURE_EDITING 2546# if ENABLE_FEATURE_EDITING
2546 if (G_ttyin && fp == stdin) { 2547 if (G_ttyin && fp == stdin) {
2547 int n, i; 2548 int n, i;
2549 if (!G.line_input_state)
2550 G.line_input_state = new_line_input_t(DO_HISTORY);
2548# define line_buf bb_common_bufsiz1 2551# define line_buf bb_common_bufsiz1
2549 n = read_line_input(G.line_input_state, "", line_buf, COMMON_BUFSIZE); 2552 n = read_line_input(G.line_input_state, "", line_buf, COMMON_BUFSIZE);
2550 if (n <= 0) { // read errors or EOF, or ^D, or ^C 2553 if (n <= 0) { // read errors or EOF, or ^D, or ^C
2551 if (n == 0) // ^C 2554 //GNU bc prints this on ^C:
2552 goto intr; 2555 //if (n == 0) // ^C
2553 bc_vec_pushZeroByte(vec); // ^D or EOF (or error) 2556 // puts("(interrupt) Exiting bc.");
2557 bc_vec_pushZeroByte(vec);
2554 return; 2558 return;
2555 } 2559 }
2556 i = 0; 2560 i = 0;
@@ -6872,22 +6876,6 @@ static BC_STATUS zxc_program_exec(void)
6872} 6876}
6873#define zxc_program_exec(...) (zxc_program_exec(__VA_ARGS__) COMMA_SUCCESS) 6877#define zxc_program_exec(...) (zxc_program_exec(__VA_ARGS__) COMMA_SUCCESS)
6874 6878
6875static unsigned xc_vm_envLen(const char *var)
6876{
6877 char *lenv;
6878 unsigned len;
6879
6880 lenv = getenv(var);
6881 len = BC_NUM_PRINT_WIDTH;
6882 if (!lenv) return len;
6883
6884 len = bb_strtou(lenv, NULL, 10) - 1;
6885 if (errno || len < 2 || len >= INT_MAX)
6886 len = BC_NUM_PRINT_WIDTH;
6887
6888 return len;
6889}
6890
6891static BC_STATUS zxc_vm_process(const char *text) 6879static BC_STATUS zxc_vm_process(const char *text)
6892{ 6880{
6893 BcStatus s; 6881 BcStatus s;
@@ -7377,12 +7365,43 @@ static void xc_program_init(void)
7377 bc_char_vec_init(&G.input_buffer); 7365 bc_char_vec_init(&G.input_buffer);
7378} 7366}
7379 7367
7368static unsigned xc_vm_envLen(const char *var)
7369{
7370 char *lenv;
7371 unsigned len;
7372
7373 lenv = getenv(var);
7374 len = BC_NUM_PRINT_WIDTH;
7375 if (lenv) {
7376 len = bb_strtou(lenv, NULL, 10);
7377 if (len == 0 || len > INT_MAX)
7378 len = INT_MAX;
7379 if (errno)
7380 len = BC_NUM_PRINT_WIDTH;
7381 }
7382
7383 // dc (GNU bc 1.07.1) 1.4.1 seems to use width
7384 // 1 char wider than bc from the same package.
7385 // Both default width, and xC_LINE_LENGTH=N are wider:
7386 // "DC_LINE_LENGTH=5 dc -e'123456 p'" prints:
7387 // |1234\ |
7388 // |56 |
7389 // "echo '123456' | BC_LINE_LENGTH=5 bc" prints:
7390 // |123\ |
7391 // |456 |
7392 // Do the same, but it might be a bug in GNU package
7393 if (IS_BC)
7394 len--;
7395
7396 if (len < 2)
7397 len = IS_BC ? BC_NUM_PRINT_WIDTH - 1 : BC_NUM_PRINT_WIDTH;
7398
7399 return len;
7400}
7401
7380static int xc_vm_init(const char *env_len) 7402static int xc_vm_init(const char *env_len)
7381{ 7403{
7382 G.prog.len = xc_vm_envLen(env_len); 7404 G.prog.len = xc_vm_envLen(env_len);
7383#if ENABLE_FEATURE_EDITING
7384 G.line_input_state = new_line_input_t(DO_HISTORY);
7385#endif
7386 bc_vec_init(&G.files, sizeof(char *), NULL); 7405 bc_vec_init(&G.files, sizeof(char *), NULL);
7387 7406
7388 xc_program_init(); 7407 xc_program_init();
@@ -7466,16 +7485,6 @@ int dc_main(int argc UNUSED_PARAM, char **argv)
7466 7485
7467 INIT_G(); 7486 INIT_G();
7468 7487
7469 // TODO: dc (GNU bc 1.07.1) 1.4.1 seems to use width
7470 // 1 char wider than bc from the same package.
7471 // Both default width, and xC_LINE_LENGTH=N are wider:
7472 // "DC_LINE_LENGTH=5 dc -e'123456 p'" prints:
7473 // |1234\ |
7474 // |56 |
7475 // "echo '123456' | BC_LINE_LENGTH=5 bc" prints:
7476 // |123\ |
7477 // |456 |
7478 // Do the same, or it's a bug?
7479 xc_vm_init("DC_LINE_LENGTH"); 7488 xc_vm_init("DC_LINE_LENGTH");
7480 7489
7481 // Run -e'SCRIPT' and -fFILE in order of appearance, then handle FILEs 7490 // Run -e'SCRIPT' and -fFILE in order of appearance, then handle FILEs