[git commit] bc: correctly parse dc options

Denys Vlasenko vda.linux at googlemail.com
Thu Dec 6 17:41:59 UTC 2018


commit: https://git.busybox.net/busybox/commit/?id=6d0be10aae1fb92879269e4397ae4e7ab037a628
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
bc_vm_init                                             -     821    +821
bc_vm_file                                             -     226    +226
dc_main                                               41     187    +146
bc_main                                               41      73     +32
packed_usage                                       33076   33059     -17
bc_vm_run                                           1903     701   -1202
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 2/2 up/down: 1225/-1219)          Total: 6 bytes
   text	   data	    bss	    dec	    hex	filename
 987046	    485	   7296	 994827	  f2e0b	busybox_old
 987037	    485	   7296	 994818	  f2e02	busybox_unstripped

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 miscutils/bc.c | 159 ++++++++++++++++++++++++++++++++++++---------------------
 1 file 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 @@
 //usage:#define bc_full_usage "\n"
 //usage:     "\nArbitrary precision calculator"
 //usage:     "\n"
-//usage:     "\n	-i	Interactive"
+///////:     "\n	-i	Interactive" - has no effect for now
+//usage:     "\n	-q	Quiet"
 //usage:     "\n	-l	Load standard math library"
 //usage:     "\n	-s	Be POSIX compatible"
-//usage:     "\n	-q	Quiet"
 //usage:     "\n	-w	Warn if extensions are used"
 ///////:     "\n	-v	Version"
+//usage:     "\n"
 //usage:     "\n$BC_LINE_LENGTH changes output width"
 //usage:
 //usage:#define bc_example_usage
@@ -154,29 +155,29 @@
 //usage:       "obase = A\n"
 //usage:
 //usage:#define dc_trivial_usage
-//usage:       "EXPRESSION..."
+//usage:       "[-eSCRIPT]... [-fFILE]... [FILE]..."
 //usage:
 //usage:#define dc_full_usage "\n"
 //usage:     "\nTiny RPN calculator. Operations:"
-//usage:     "\n+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
+//usage:     "\n+, -, *, /, %, ^, exp, ~, divmod, |, "
 //usage:       "modular exponentiation,"
-//usage:     "\np - print top of the stack (without popping),"
-//usage:     "\nf - print entire stack,"
-//usage:     "\nk - pop the value and set the precision."
-//usage:     "\ni - pop the value and set input radix."
-//usage:     "\no - pop the value and set output radix."
-//usage:     "\nExamples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
+//usage:     "\np - print top of the stack (without popping)"
+//usage:     "\nf - print entire stack"
+//usage:     "\nk - pop the value and set the precision"
+//usage:     "\ni - pop the value and set input radix"
+//usage:     "\no - pop the value and set output radix"
+//usage:     "\nExamples: dc -e'2 2 + p' -> 4, dc -e'8 8 * 2 2 + / p' -> 16"
 //usage:
 //usage:#define dc_example_usage
-//usage:       "$ dc 2 2 + p\n"
+//usage:       "$ dc -e'2 2 + p'\n"
 //usage:       "4\n"
-//usage:       "$ dc 8 8 \\* 2 2 + / p\n"
+//usage:       "$ dc -e'8 8 \\* 2 2 + / p'\n"
 //usage:       "16\n"
-//usage:       "$ dc 0 1 and p\n"
+//usage:       "$ dc -e'0 1 & p'\n"
 //usage:       "0\n"
-//usage:       "$ dc 0 1 or p\n"
+//usage:       "$ dc -e'0 1 | p'\n"
 //usage:       "1\n"
-//usage:       "$ echo 72 9 div 8 mul p | dc\n"
+//usage:       "$ echo '72 9 / 8 * p' | dc\n"
 //usage:       "64\n"
 
 #include "libbb.h"
@@ -718,13 +719,13 @@ typedef struct BcProgram {
 
 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
 
-#define BC_FLAG_X (1 << 0)
-#define BC_FLAG_W (1 << 1)
-#define BC_FLAG_V (1 << 2)
-#define BC_FLAG_S (1 << 3)
-#define BC_FLAG_Q (1 << 4)
-#define BC_FLAG_L (1 << 5)
-#define BC_FLAG_I (1 << 6)
+#define BC_FLAG_W (1 << 0)
+#define BC_FLAG_V (1 << 1)
+#define BC_FLAG_S (1 << 2)
+#define BC_FLAG_Q (1 << 3)
+#define BC_FLAG_L (1 << 4)
+#define BC_FLAG_I (1 << 5)
+#define DC_FLAG_X (1 << 6)
 
 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
@@ -768,7 +769,7 @@ struct globals {
 } while (0)
 #define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
 #define G_warn  (ENABLE_BC && (option_mask32 & BC_FLAG_W))
-#define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X))
+#define G_exreg (ENABLE_DC && (option_mask32 & DC_FLAG_X))
 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
 #if ENABLE_FEATURE_BC_SIGNALS
 # define G_ttyin G.ttyin
@@ -6898,6 +6899,7 @@ static BcStatus bc_program_exec(void)
 	return s;
 }
 
+#if ENABLE_BC
 static void bc_vm_info(void)
 {
 	printf("%s "BB_VER"\n"
@@ -6914,8 +6916,7 @@ static void bc_args(char **argv)
 
 	GETOPT_RESET();
 #if ENABLE_FEATURE_BC_LONG_OPTIONS
-	opts = option_mask32 |= getopt32long(argv, "xwvsqli",
-		"extended-register\0" No_argument "x"
+	opts = option_mask32 |= getopt32long(argv, "wvsqli",
 		"warn\0"              No_argument "w"
 		"version\0"           No_argument "v"
 		"standard\0"          No_argument "s"
@@ -6924,7 +6925,7 @@ static void bc_args(char **argv)
 		"interactive\0"       No_argument "i"
 	);
 #else
-	opts = option_mask32 |= getopt32(argv, "xwvsqli");
+	opts = option_mask32 |= getopt32(argv, "wvsqli");
 #endif
 	if (getenv("POSIXLY_CORRECT"))
 		option_mask32 |= BC_FLAG_S;
@@ -6939,7 +6940,6 @@ static void bc_args(char **argv)
 		bc_vec_push(&G.files, argv + i);
 }
 
-#if ENABLE_BC
 static void bc_vm_envArgs(void)
 {
 	BcVec v;
@@ -7308,7 +7308,7 @@ static const char bc_lib[] = {
 
 static BcStatus bc_vm_exec(void)
 {
-	BcStatus s = BC_STATUS_SUCCESS;
+	BcStatus s;
 	size_t i;
 
 #if ENABLE_BC
@@ -7330,21 +7330,24 @@ static BcStatus bc_vm_exec(void)
 	}
 #endif
 
+	s = BC_STATUS_SUCCESS;
 	for (i = 0; !s && i < G.files.len; ++i)
 		s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
-	if (s) {
-		if (ENABLE_FEATURE_CLEAN_UP && !G_ttyin) {
-			// Debug config, non-interactive mode:
-			// return all the way back to main.
-			// Non-debug builds do not come here, they exit.
-			return s;
-		}
-		fflush_and_check();
-		fputs("ready for more input\n", stderr);
+	if (ENABLE_FEATURE_CLEAN_UP && s && !G_ttyin) {
+		// Debug config, non-interactive mode:
+		// return all the way back to main.
+		// Non-debug builds do not come here, they exit.
+		return s;
 	}
 
-	if (IS_BC || !G.files.len)
+	if (IS_BC || (option_mask32 & BC_FLAG_I)) {
+		if (s) {
+			fflush_and_check();
+			fputs("ready for more input\n", stderr);
+		}
 		s = bc_vm_stdin();
+	}
+
 	if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
 		s = bc_vm_process("");
 
@@ -7439,8 +7442,13 @@ static void bc_program_init(void)
 	bc_vec_push(&G.prog.stack, &ip);
 }
 
-static void bc_vm_init(void)
+static int bc_vm_init(const char *env_len)
 {
+#if ENABLE_FEATURE_EDITING
+	G.line_input_state = new_line_input_t(DO_HISTORY);
+#endif
+	G.prog.len = bc_vm_envLen(env_len);
+
 	bc_vec_init(&G.files, sizeof(char *), NULL);
 	if (IS_BC)
 		IF_BC(bc_vm_envArgs();)
@@ -7450,19 +7458,6 @@ static void bc_vm_init(void)
 	} else {
 		IF_DC(dc_parse_init(&G.prs, BC_PROG_MAIN);)
 	}
-}
-
-static BcStatus bc_vm_run(char **argv, const char *env_len)
-{
-	BcStatus st;
-
-#if ENABLE_FEATURE_EDITING
-	G.line_input_state = new_line_input_t(DO_HISTORY);
-#endif
-	G.prog.len = bc_vm_envLen(env_len);
-
-	bc_vm_init();
-	bc_args(argv);
 
 	if (isatty(0)) {
 #if ENABLE_FEATURE_BC_SIGNALS
@@ -7485,12 +7480,14 @@ static BcStatus bc_vm_run(char **argv, const char *env_len)
 		// and exit.
 		//signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
 #endif
-		if (!(option_mask32 & BC_FLAG_Q))
-			bc_vm_info();
+		return 1; // "tty"
 	}
+	return 0; // "not a tty"
+}
 
-	st = bc_vm_exec();
-
+static BcStatus bc_vm_run(void)
+{
+	BcStatus st = bc_vm_exec();
 #if ENABLE_FEATURE_CLEAN_UP
 	bc_vm_free();
 # if ENABLE_FEATURE_EDITING
@@ -7505,10 +7502,19 @@ static BcStatus bc_vm_run(char **argv, const char *env_len)
 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int bc_main(int argc UNUSED_PARAM, char **argv)
 {
+	int is_tty;
+
 	INIT_G();
 	G.sbgn = G.send = '"';
 
-	return bc_vm_run(argv, "BC_LINE_LENGTH");
+	is_tty = bc_vm_init("BC_LINE_LENGTH");
+
+	bc_args(argv);
+
+	if (is_tty && !(option_mask32 & BC_FLAG_Q))
+		bc_vm_info();
+
+	return bc_vm_run();
 }
 #endif
 
@@ -7516,11 +7522,48 @@ int bc_main(int argc UNUSED_PARAM, char **argv)
 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int dc_main(int argc UNUSED_PARAM, char **argv)
 {
+	int noscript;
+
 	INIT_G();
 	G.sbgn = '[';
 	G.send = ']';
+	// TODO: dc (GNU bc 1.07.1) 1.4.1 seems to use default width
+	// 1 char narrower than bc from the same package. Do the same?
+	bc_vm_init("DC_LINE_LENGTH");
+
+	// Run -e'SCRIPT' and -fFILE in order of appearance, then handle FILEs
+	noscript = BC_FLAG_I;
+	for (;;) {
+		int n = getopt(argc, argv, "e:f:x");
+		if (n <= 0)
+			break;
+		switch (n) {
+		case 'e':
+			noscript = 0;
+			n = bc_vm_process(optarg);
+			if (n) return n;
+			break;
+		case 'f':
+			noscript = 0;
+			bc_vm_file(optarg);
+			break;
+		case 'x':
+			option_mask32 |= DC_FLAG_X;
+			break;
+		default:
+			bb_show_usage();
+		}
+	}
+	argv += optind;
+
+	while (*argv) {
+		noscript = 0;
+		bc_vec_push(&G.files, argv++);
+	}
+
+	option_mask32 |= noscript; // set BC_FLAG_I if we need to interpret stdin
 
-	return bc_vm_run(argv, "DC_LINE_LENGTH");
+	return bc_vm_run();
 }
 #endif
 


More information about the busybox-cvs mailing list