diff options
-rw-r--r-- | miscutils/bc.c | 159 |
1 files changed, 101 insertions, 58 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c index 0200afca2..3f7da3abc 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c | |||
@@ -134,12 +134,13 @@ | |||
134 | //usage:#define bc_full_usage "\n" | 134 | //usage:#define bc_full_usage "\n" |
135 | //usage: "\nArbitrary precision calculator" | 135 | //usage: "\nArbitrary precision calculator" |
136 | //usage: "\n" | 136 | //usage: "\n" |
137 | //usage: "\n -i Interactive" | 137 | ///////: "\n -i Interactive" - has no effect for now |
138 | //usage: "\n -q Quiet" | ||
138 | //usage: "\n -l Load standard math library" | 139 | //usage: "\n -l Load standard math library" |
139 | //usage: "\n -s Be POSIX compatible" | 140 | //usage: "\n -s Be POSIX compatible" |
140 | //usage: "\n -q Quiet" | ||
141 | //usage: "\n -w Warn if extensions are used" | 141 | //usage: "\n -w Warn if extensions are used" |
142 | ///////: "\n -v Version" | 142 | ///////: "\n -v Version" |
143 | //usage: "\n" | ||
143 | //usage: "\n$BC_LINE_LENGTH changes output width" | 144 | //usage: "\n$BC_LINE_LENGTH changes output width" |
144 | //usage: | 145 | //usage: |
145 | //usage:#define bc_example_usage | 146 | //usage:#define bc_example_usage |
@@ -154,29 +155,29 @@ | |||
154 | //usage: "obase = A\n" | 155 | //usage: "obase = A\n" |
155 | //usage: | 156 | //usage: |
156 | //usage:#define dc_trivial_usage | 157 | //usage:#define dc_trivial_usage |
157 | //usage: "EXPRESSION..." | 158 | //usage: "[-eSCRIPT]... [-fFILE]... [FILE]..." |
158 | //usage: | 159 | //usage: |
159 | //usage:#define dc_full_usage "\n" | 160 | //usage:#define dc_full_usage "\n" |
160 | //usage: "\nTiny RPN calculator. Operations:" | 161 | //usage: "\nTiny RPN calculator. Operations:" |
161 | //usage: "\n+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, " | 162 | //usage: "\n+, -, *, /, %, ^, exp, ~, divmod, |, " |
162 | //usage: "modular exponentiation," | 163 | //usage: "modular exponentiation," |
163 | //usage: "\np - print top of the stack (without popping)," | 164 | //usage: "\np - print top of the stack (without popping)" |
164 | //usage: "\nf - print entire stack," | 165 | //usage: "\nf - print entire stack" |
165 | //usage: "\nk - pop the value and set the precision." | 166 | //usage: "\nk - pop the value and set the precision" |
166 | //usage: "\ni - pop the value and set input radix." | 167 | //usage: "\ni - pop the value and set input radix" |
167 | //usage: "\no - pop the value and set output radix." | 168 | //usage: "\no - pop the value and set output radix" |
168 | //usage: "\nExamples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16" | 169 | //usage: "\nExamples: dc -e'2 2 + p' -> 4, dc -e'8 8 * 2 2 + / p' -> 16" |
169 | //usage: | 170 | //usage: |
170 | //usage:#define dc_example_usage | 171 | //usage:#define dc_example_usage |
171 | //usage: "$ dc 2 2 + p\n" | 172 | //usage: "$ dc -e'2 2 + p'\n" |
172 | //usage: "4\n" | 173 | //usage: "4\n" |
173 | //usage: "$ dc 8 8 \\* 2 2 + / p\n" | 174 | //usage: "$ dc -e'8 8 \\* 2 2 + / p'\n" |
174 | //usage: "16\n" | 175 | //usage: "16\n" |
175 | //usage: "$ dc 0 1 and p\n" | 176 | //usage: "$ dc -e'0 1 & p'\n" |
176 | //usage: "0\n" | 177 | //usage: "0\n" |
177 | //usage: "$ dc 0 1 or p\n" | 178 | //usage: "$ dc -e'0 1 | p'\n" |
178 | //usage: "1\n" | 179 | //usage: "1\n" |
179 | //usage: "$ echo 72 9 div 8 mul p | dc\n" | 180 | //usage: "$ echo '72 9 / 8 * p' | dc\n" |
180 | //usage: "64\n" | 181 | //usage: "64\n" |
181 | 182 | ||
182 | #include "libbb.h" | 183 | #include "libbb.h" |
@@ -718,13 +719,13 @@ typedef struct BcProgram { | |||
718 | 719 | ||
719 | typedef unsigned long (*BcProgramBuiltIn)(BcNum *); | 720 | typedef unsigned long (*BcProgramBuiltIn)(BcNum *); |
720 | 721 | ||
721 | #define BC_FLAG_X (1 << 0) | 722 | #define BC_FLAG_W (1 << 0) |
722 | #define BC_FLAG_W (1 << 1) | 723 | #define BC_FLAG_V (1 << 1) |
723 | #define BC_FLAG_V (1 << 2) | 724 | #define BC_FLAG_S (1 << 2) |
724 | #define BC_FLAG_S (1 << 3) | 725 | #define BC_FLAG_Q (1 << 3) |
725 | #define BC_FLAG_Q (1 << 4) | 726 | #define BC_FLAG_L (1 << 4) |
726 | #define BC_FLAG_L (1 << 5) | 727 | #define BC_FLAG_I (1 << 5) |
727 | #define BC_FLAG_I (1 << 6) | 728 | #define DC_FLAG_X (1 << 6) |
728 | 729 | ||
729 | #define BC_MAX(a, b) ((a) > (b) ? (a) : (b)) | 730 | #define BC_MAX(a, b) ((a) > (b) ? (a) : (b)) |
730 | #define BC_MIN(a, b) ((a) < (b) ? (a) : (b)) | 731 | #define BC_MIN(a, b) ((a) < (b) ? (a) : (b)) |
@@ -768,7 +769,7 @@ struct globals { | |||
768 | } while (0) | 769 | } while (0) |
769 | #define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S)) | 770 | #define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S)) |
770 | #define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W)) | 771 | #define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W)) |
771 | #define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X)) | 772 | #define G_exreg (ENABLE_DC && (option_mask32 & DC_FLAG_X)) |
772 | #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0) | 773 | #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0) |
773 | #if ENABLE_FEATURE_BC_SIGNALS | 774 | #if ENABLE_FEATURE_BC_SIGNALS |
774 | # define G_ttyin G.ttyin | 775 | # define G_ttyin G.ttyin |
@@ -6898,6 +6899,7 @@ static BcStatus bc_program_exec(void) | |||
6898 | return s; | 6899 | return s; |
6899 | } | 6900 | } |
6900 | 6901 | ||
6902 | #if ENABLE_BC | ||
6901 | static void bc_vm_info(void) | 6903 | static void bc_vm_info(void) |
6902 | { | 6904 | { |
6903 | printf("%s "BB_VER"\n" | 6905 | printf("%s "BB_VER"\n" |
@@ -6914,8 +6916,7 @@ static void bc_args(char **argv) | |||
6914 | 6916 | ||
6915 | GETOPT_RESET(); | 6917 | GETOPT_RESET(); |
6916 | #if ENABLE_FEATURE_BC_LONG_OPTIONS | 6918 | #if ENABLE_FEATURE_BC_LONG_OPTIONS |
6917 | opts = option_mask32 |= getopt32long(argv, "xwvsqli", | 6919 | opts = option_mask32 |= getopt32long(argv, "wvsqli", |
6918 | "extended-register\0" No_argument "x" | ||
6919 | "warn\0" No_argument "w" | 6920 | "warn\0" No_argument "w" |
6920 | "version\0" No_argument "v" | 6921 | "version\0" No_argument "v" |
6921 | "standard\0" No_argument "s" | 6922 | "standard\0" No_argument "s" |
@@ -6924,7 +6925,7 @@ static void bc_args(char **argv) | |||
6924 | "interactive\0" No_argument "i" | 6925 | "interactive\0" No_argument "i" |
6925 | ); | 6926 | ); |
6926 | #else | 6927 | #else |
6927 | opts = option_mask32 |= getopt32(argv, "xwvsqli"); | 6928 | opts = option_mask32 |= getopt32(argv, "wvsqli"); |
6928 | #endif | 6929 | #endif |
6929 | if (getenv("POSIXLY_CORRECT")) | 6930 | if (getenv("POSIXLY_CORRECT")) |
6930 | option_mask32 |= BC_FLAG_S; | 6931 | option_mask32 |= BC_FLAG_S; |
@@ -6939,7 +6940,6 @@ static void bc_args(char **argv) | |||
6939 | bc_vec_push(&G.files, argv + i); | 6940 | bc_vec_push(&G.files, argv + i); |
6940 | } | 6941 | } |
6941 | 6942 | ||
6942 | #if ENABLE_BC | ||
6943 | static void bc_vm_envArgs(void) | 6943 | static void bc_vm_envArgs(void) |
6944 | { | 6944 | { |
6945 | BcVec v; | 6945 | BcVec v; |
@@ -7308,7 +7308,7 @@ static const char bc_lib[] = { | |||
7308 | 7308 | ||
7309 | static BcStatus bc_vm_exec(void) | 7309 | static BcStatus bc_vm_exec(void) |
7310 | { | 7310 | { |
7311 | BcStatus s = BC_STATUS_SUCCESS; | 7311 | BcStatus s; |
7312 | size_t i; | 7312 | size_t i; |
7313 | 7313 | ||
7314 | #if ENABLE_BC | 7314 | #if ENABLE_BC |
@@ -7330,21 +7330,24 @@ static BcStatus bc_vm_exec(void) | |||
7330 | } | 7330 | } |
7331 | #endif | 7331 | #endif |
7332 | 7332 | ||
7333 | s = BC_STATUS_SUCCESS; | ||
7333 | for (i = 0; !s && i < G.files.len; ++i) | 7334 | for (i = 0; !s && i < G.files.len; ++i) |
7334 | s = bc_vm_file(*((char **) bc_vec_item(&G.files, i))); | 7335 | s = bc_vm_file(*((char **) bc_vec_item(&G.files, i))); |
7335 | if (s) { | 7336 | if (ENABLE_FEATURE_CLEAN_UP && s && !G_ttyin) { |
7336 | if (ENABLE_FEATURE_CLEAN_UP && !G_ttyin) { | 7337 | // Debug config, non-interactive mode: |
7337 | // Debug config, non-interactive mode: | 7338 | // return all the way back to main. |
7338 | // return all the way back to main. | 7339 | // Non-debug builds do not come here, they exit. |
7339 | // Non-debug builds do not come here, they exit. | 7340 | return s; |
7340 | return s; | ||
7341 | } | ||
7342 | fflush_and_check(); | ||
7343 | fputs("ready for more input\n", stderr); | ||
7344 | } | 7341 | } |
7345 | 7342 | ||
7346 | if (IS_BC || !G.files.len) | 7343 | if (IS_BC || (option_mask32 & BC_FLAG_I)) { |
7344 | if (s) { | ||
7345 | fflush_and_check(); | ||
7346 | fputs("ready for more input\n", stderr); | ||
7347 | } | ||
7347 | s = bc_vm_stdin(); | 7348 | s = bc_vm_stdin(); |
7349 | } | ||
7350 | |||
7348 | if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) | 7351 | if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) |
7349 | s = bc_vm_process(""); | 7352 | s = bc_vm_process(""); |
7350 | 7353 | ||
@@ -7439,8 +7442,13 @@ static void bc_program_init(void) | |||
7439 | bc_vec_push(&G.prog.stack, &ip); | 7442 | bc_vec_push(&G.prog.stack, &ip); |
7440 | } | 7443 | } |
7441 | 7444 | ||
7442 | static void bc_vm_init(void) | 7445 | static int bc_vm_init(const char *env_len) |
7443 | { | 7446 | { |
7447 | #if ENABLE_FEATURE_EDITING | ||
7448 | G.line_input_state = new_line_input_t(DO_HISTORY); | ||
7449 | #endif | ||
7450 | G.prog.len = bc_vm_envLen(env_len); | ||
7451 | |||
7444 | bc_vec_init(&G.files, sizeof(char *), NULL); | 7452 | bc_vec_init(&G.files, sizeof(char *), NULL); |
7445 | if (IS_BC) | 7453 | if (IS_BC) |
7446 | IF_BC(bc_vm_envArgs();) | 7454 | IF_BC(bc_vm_envArgs();) |
@@ -7450,19 +7458,6 @@ static void bc_vm_init(void) | |||
7450 | } else { | 7458 | } else { |
7451 | IF_DC(dc_parse_init(&G.prs, BC_PROG_MAIN);) | 7459 | IF_DC(dc_parse_init(&G.prs, BC_PROG_MAIN);) |
7452 | } | 7460 | } |
7453 | } | ||
7454 | |||
7455 | static BcStatus bc_vm_run(char **argv, const char *env_len) | ||
7456 | { | ||
7457 | BcStatus st; | ||
7458 | |||
7459 | #if ENABLE_FEATURE_EDITING | ||
7460 | G.line_input_state = new_line_input_t(DO_HISTORY); | ||
7461 | #endif | ||
7462 | G.prog.len = bc_vm_envLen(env_len); | ||
7463 | |||
7464 | bc_vm_init(); | ||
7465 | bc_args(argv); | ||
7466 | 7461 | ||
7467 | if (isatty(0)) { | 7462 | if (isatty(0)) { |
7468 | #if ENABLE_FEATURE_BC_SIGNALS | 7463 | #if ENABLE_FEATURE_BC_SIGNALS |
@@ -7485,12 +7480,14 @@ static BcStatus bc_vm_run(char **argv, const char *env_len) | |||
7485 | // and exit. | 7480 | // and exit. |
7486 | //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo); | 7481 | //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo); |
7487 | #endif | 7482 | #endif |
7488 | if (!(option_mask32 & BC_FLAG_Q)) | 7483 | return 1; // "tty" |
7489 | bc_vm_info(); | ||
7490 | } | 7484 | } |
7485 | return 0; // "not a tty" | ||
7486 | } | ||
7491 | 7487 | ||
7492 | st = bc_vm_exec(); | 7488 | static BcStatus bc_vm_run(void) |
7493 | 7489 | { | |
7490 | BcStatus st = bc_vm_exec(); | ||
7494 | #if ENABLE_FEATURE_CLEAN_UP | 7491 | #if ENABLE_FEATURE_CLEAN_UP |
7495 | bc_vm_free(); | 7492 | bc_vm_free(); |
7496 | # if ENABLE_FEATURE_EDITING | 7493 | # if ENABLE_FEATURE_EDITING |
@@ -7505,10 +7502,19 @@ static BcStatus bc_vm_run(char **argv, const char *env_len) | |||
7505 | int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 7502 | int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
7506 | int bc_main(int argc UNUSED_PARAM, char **argv) | 7503 | int bc_main(int argc UNUSED_PARAM, char **argv) |
7507 | { | 7504 | { |
7505 | int is_tty; | ||
7506 | |||
7508 | INIT_G(); | 7507 | INIT_G(); |
7509 | G.sbgn = G.send = '"'; | 7508 | G.sbgn = G.send = '"'; |
7510 | 7509 | ||
7511 | return bc_vm_run(argv, "BC_LINE_LENGTH"); | 7510 | is_tty = bc_vm_init("BC_LINE_LENGTH"); |
7511 | |||
7512 | bc_args(argv); | ||
7513 | |||
7514 | if (is_tty && !(option_mask32 & BC_FLAG_Q)) | ||
7515 | bc_vm_info(); | ||
7516 | |||
7517 | return bc_vm_run(); | ||
7512 | } | 7518 | } |
7513 | #endif | 7519 | #endif |
7514 | 7520 | ||
@@ -7516,11 +7522,48 @@ int bc_main(int argc UNUSED_PARAM, char **argv) | |||
7516 | int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 7522 | int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
7517 | int dc_main(int argc UNUSED_PARAM, char **argv) | 7523 | int dc_main(int argc UNUSED_PARAM, char **argv) |
7518 | { | 7524 | { |
7525 | int noscript; | ||
7526 | |||
7519 | INIT_G(); | 7527 | INIT_G(); |
7520 | G.sbgn = '['; | 7528 | G.sbgn = '['; |
7521 | G.send = ']'; | 7529 | G.send = ']'; |
7530 | // TODO: dc (GNU bc 1.07.1) 1.4.1 seems to use default width | ||
7531 | // 1 char narrower than bc from the same package. Do the same? | ||
7532 | bc_vm_init("DC_LINE_LENGTH"); | ||
7533 | |||
7534 | // Run -e'SCRIPT' and -fFILE in order of appearance, then handle FILEs | ||
7535 | noscript = BC_FLAG_I; | ||
7536 | for (;;) { | ||
7537 | int n = getopt(argc, argv, "e:f:x"); | ||
7538 | if (n <= 0) | ||
7539 | break; | ||
7540 | switch (n) { | ||
7541 | case 'e': | ||
7542 | noscript = 0; | ||
7543 | n = bc_vm_process(optarg); | ||
7544 | if (n) return n; | ||
7545 | break; | ||
7546 | case 'f': | ||
7547 | noscript = 0; | ||
7548 | bc_vm_file(optarg); | ||
7549 | break; | ||
7550 | case 'x': | ||
7551 | option_mask32 |= DC_FLAG_X; | ||
7552 | break; | ||
7553 | default: | ||
7554 | bb_show_usage(); | ||
7555 | } | ||
7556 | } | ||
7557 | argv += optind; | ||
7558 | |||
7559 | while (*argv) { | ||
7560 | noscript = 0; | ||
7561 | bc_vec_push(&G.files, argv++); | ||
7562 | } | ||
7563 | |||
7564 | option_mask32 |= noscript; // set BC_FLAG_I if we need to interpret stdin | ||
7522 | 7565 | ||
7523 | return bc_vm_run(argv, "DC_LINE_LENGTH"); | 7566 | return bc_vm_run(); |
7524 | } | 7567 | } |
7525 | #endif | 7568 | #endif |
7526 | 7569 | ||