diff options
Diffstat (limited to 'miscutils/bc.c')
-rw-r--r-- | miscutils/bc.c | 111 |
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 */ } |
520 | static const struct BcLexKeyword bc_lex_kws[20] = { | 520 | static 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 | ||
6875 | static 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 | |||
6891 | static BC_STATUS zxc_vm_process(const char *text) | 6879 | static 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 | ||
7368 | static 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 | |||
7380 | static int xc_vm_init(const char *env_len) | 7402 | static 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 |