aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--miscutils/bc.c159
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
719typedef unsigned long (*BcProgramBuiltIn)(BcNum *); 720typedef 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
6901static void bc_vm_info(void) 6903static 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
6943static void bc_vm_envArgs(void) 6943static void bc_vm_envArgs(void)
6944{ 6944{
6945 BcVec v; 6945 BcVec v;
@@ -7308,7 +7308,7 @@ static const char bc_lib[] = {
7308 7308
7309static BcStatus bc_vm_exec(void) 7309static 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
7442static void bc_vm_init(void) 7445static 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
7455static 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(); 7488static 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)
7505int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 7502int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7506int bc_main(int argc UNUSED_PARAM, char **argv) 7503int 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)
7516int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 7522int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7517int dc_main(int argc UNUSED_PARAM, char **argv) 7523int 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