bc: simplify, stop testing for IO errors on every output

function                                             old     new   delta
bc_read_line                                         297     342     +45
bc_vm_run                                           2601    2608      +7
bc_program_reset                                     178     182      +4
bc_args                                              125     123      -2
dc_name                                                3       -      -3
bc_name                                                3       -      -3
bc_program_printStream                               176     172      -4
bcg                                                   48      40      -8
dc_main                                               97      80     -17
bc_main                                               97      80     -17
bc_vm_fflush                                          21       -     -21
bc_vm_puts                                            23       -     -23
bc_vm_printf                                          36       -     -36
bc_vm_putchar                                         46       -     -46
bc_vm_exit                                            46       -     -46
bc_vm_process                                        361     312     -49
bc_vm_info                                            76      19     -57
bc_copyright                                         155       -    -155
------------------------------------------------------------------------------
(add/remove: 0/8 grow/shrink: 3/7 up/down: 56/-487)          Total: -431 bytes
   text	   data	    bss	    dec	    hex	filename
 989722	    485	   7344	 997551	  f38af	busybox_old
 989491	    485	   7336	 997312	  f37c0	busybox_unstripped

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/miscutils/bc.c b/miscutils/bc.c
index 4cbef4d..f36534c 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -165,7 +165,7 @@
 	BC_STATUS_SUCCESS,
 
 	BC_STATUS_ALLOC_ERR,
-	BC_STATUS_IO_ERR,
+	BC_STATUS_INPUT_EOF,
 	BC_STATUS_BIN_FILE,
 	BC_STATUS_PATH_IS_DIR,
 
@@ -719,9 +719,9 @@
 static BcStatus bc_parse_parse(BcParse *p);
 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
 
-#endif
+#endif // ENABLE_BC
 
-#ifdef ENABLE_DC
+#if ENABLE_DC
 
 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
 
@@ -849,51 +849,38 @@
 	long warn;
 	long exreg;
 
-	const char *name;
 #if ENABLE_FEATURE_BC_SIGNALS
 	const char *sig_msg;
 #endif
 	const char *help;
-	bool bc;
 
 } BcGlobals;
 
+#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
+
 #if ENABLE_BC
 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
                                  const char *msg);
 #endif
 
-static void bc_vm_exit(BcStatus s);
-static void bc_vm_printf(FILE *restrict f, const char *fmt, ...);
-static void bc_vm_puts(const char *str, FILE *restrict f);
-static void bc_vm_putchar(int c);
-static void bc_vm_fflush(FILE *restrict f);
-
-static void bc_vm_info(const char *const help);
+static void bc_vm_info(void);
 static BcStatus bc_vm_run(int argc, char *argv[], BcVmExe exe,
                           const char *env_len);
 
 static BcGlobals bcg;
 
 #if ENABLE_BC
-static const char bc_name[] = "bc";
 # if ENABLE_FEATURE_BC_SIGNALS
 static const char bc_sig_msg[] = "\ninterrupt (type \"quit\" to exit)\n";
 # endif
 #endif
 
 #if ENABLE_DC
-static const char dc_name[] = "dc";
 # if ENABLE_FEATURE_BC_SIGNALS
 static const char dc_sig_msg[] = "\ninterrupt (type \"q\" to exit)\n";
 # endif
 #endif
 
-static const char bc_copyright[] =
-	"Copyright (c) 2018 Gavin D. Howard and contributors\n"
-	"Report bugs at: https://github.com/gavinhoward/bc\n\n"
-	"This is free software with ABSOLUTELY NO WARRANTY.\n";
-
 static const char* const bc_args_env_name = "BC_ENV_ARGS";
 
 static const char bc_err_fmt[] = "\n%s error: %s\n";
@@ -1386,18 +1373,22 @@
 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
 {
 	int i;
-	signed char c = 0;
+	signed char c;
 
 	if (bcg.ttyin && !bcg.posix) {
-		bc_vm_puts(prompt, stderr);
-		bc_vm_fflush(stderr);
+		fputs(prompt, stderr);
+		fflush(stderr);
 	}
 
 	bc_vec_npop(vec, vec->len);
 
-	while (c != '\n') {
+	do {
+		if (ferror(stdout) || ferror(stderr))
+			bb_perror_msg_and_die("output error");
 
 		i = fgetc(stdin);
+		if (ferror(stdin))
+			bb_perror_msg_and_die("input error");
 
 		if (i == EOF) {
 
@@ -1408,22 +1399,22 @@
 				bcg.signe = 0;
 
 				if (bcg.ttyin) {
-					bc_vm_puts(bc_program_ready_msg, stderr);
-					if (!bcg.posix) bc_vm_puts(prompt, stderr);
-					bc_vm_fflush(stderr);
+					fputs(bc_program_ready_msg, stderr);
+					if (!bcg.posix) fputs(prompt, stderr);
+					fflush(stderr);
 				}
 
 				continue;
 			}
 #endif
 
-			return BC_STATUS_IO_ERR;
+			return BC_STATUS_INPUT_EOF;
 		}
 
 		c = (signed char) i;
 		if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
 		bc_vec_push(vec, &c);
-	}
+	} while (c != '\n');
 
 	bc_vec_pushByte(vec, '\0');
 
@@ -1477,7 +1468,7 @@
 	*flags = getopt32(argv, bc_args_opt);
 #endif
 
-	if ((*flags) & BC_FLAG_V) bc_vm_info(NULL);
+	if ((*flags) & BC_FLAG_V) bc_vm_info();
 	if (do_exit) exit((int) s);
 	if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
 
@@ -2329,8 +2320,8 @@
 static void bc_num_printNewline(size_t *nchars, size_t line_len)
 {
 	if (*nchars == line_len - 1) {
-		bc_vm_putchar('\\');
-		bc_vm_putchar('\n');
+		bb_putchar('\\');
+		bb_putchar('\n');
 		*nchars = 0;
 	}
 }
@@ -2340,7 +2331,7 @@
                              size_t *nchars, size_t line_len)
 {
 	(void) radix, (void) line_len;
-	bc_vm_putchar((char) num);
+	bb_putchar((char) num);
 	*nchars = *nchars + width;
 }
 #endif
@@ -2351,7 +2342,7 @@
 	size_t exp, pow;
 
 	bc_num_printNewline(nchars, line_len);
-	bc_vm_putchar(radix ? '.' : ' ');
+	bb_putchar(radix ? '.' : ' ');
 	++(*nchars);
 
 	bc_num_printNewline(nchars, line_len);
@@ -2363,7 +2354,7 @@
 		bc_num_printNewline(nchars, line_len);
 		dig = num / pow;
 		num -= dig * pow;
-		bc_vm_putchar(((char) dig) + '0');
+		bb_putchar(((char) dig) + '0');
 	}
 }
 
@@ -2372,12 +2363,12 @@
 {
 	if (radix) {
 		bc_num_printNewline(nchars, line_len);
-		bc_vm_putchar('.');
+		bb_putchar('.');
 		*nchars += 1;
 	}
 
 	bc_num_printNewline(nchars, line_len);
-	bc_vm_putchar(bb_hexdigits_upcase[num]);
+	bb_putchar(bb_hexdigits_upcase[num]);
 	*nchars = *nchars + width;
 }
 
@@ -2385,7 +2376,7 @@
 {
 	size_t i, rdx = n->rdx - 1;
 
-	if (n->neg) bc_vm_putchar('-');
+	if (n->neg) bb_putchar('-');
 	(*nchars) += n->neg;
 
 	for (i = n->len - 1; i < n->len; --i)
@@ -2465,7 +2456,7 @@
 	BcNumDigitOp print;
 	bool neg = n->neg;
 
-	if (neg) bc_vm_putchar('-');
+	if (neg) bb_putchar('-');
 	(*nchars) += neg;
 
 	n->neg = false;
@@ -2546,7 +2537,7 @@
 	bc_num_printNewline(nchars, line_len);
 
 	if (n->len == 0) {
-		bc_vm_putchar('0');
+		bb_putchar('0');
 		++(*nchars);
 	}
 	else if (base_t == 10)
@@ -2555,7 +2546,7 @@
 		s = bc_num_printBase(n, base, base_t, nchars, line_len);
 
 	if (newline) {
-		bc_vm_putchar('\n');
+		bb_putchar('\n');
 		*nchars = 0;
 	}
 
@@ -5577,7 +5568,7 @@
 
 #if ENABLE_DC
 	if (len == 0) {
-		bc_vm_putchar('\0');
+		bb_putchar('\0');
 		return;
 	}
 #endif
@@ -5587,7 +5578,7 @@
 		int c = str[i];
 
 		if (c != '\\' || i == len - 1)
-			bc_vm_putchar(c);
+			bb_putchar(c);
 		else {
 
 			c = str[++i];
@@ -5596,60 +5587,60 @@
 
 				case 'a':
 				{
-					bc_vm_putchar('\a');
+					bb_putchar('\a');
 					break;
 				}
 
 				case 'b':
 				{
-					bc_vm_putchar('\b');
+					bb_putchar('\b');
 					break;
 				}
 
 				case '\\':
 				case 'e':
 				{
-					bc_vm_putchar('\\');
+					bb_putchar('\\');
 					break;
 				}
 
 				case 'f':
 				{
-					bc_vm_putchar('\f');
+					bb_putchar('\f');
 					break;
 				}
 
 				case 'n':
 				{
-					bc_vm_putchar('\n');
+					bb_putchar('\n');
 					*nchars = SIZE_MAX;
 					break;
 				}
 
 				case 'r':
 				{
-					bc_vm_putchar('\r');
+					bb_putchar('\r');
 					break;
 				}
 
 				case 'q':
 				{
-					bc_vm_putchar('"');
+					bb_putchar('"');
 					break;
 				}
 
 				case 't':
 				{
-					bc_vm_putchar('\t');
+					bb_putchar('\t');
 					break;
 				}
 
 				default:
 				{
 					// Just print the backslash and following character.
-					bc_vm_putchar('\\');
+					bb_putchar('\\');
 					++(*nchars);
-					bc_vm_putchar(c);
+					bb_putchar(c);
 					break;
 				}
 			}
@@ -5684,14 +5675,14 @@
 		if (inst == BC_INST_PRINT_STR) {
 			for (i = 0, len = strlen(str); i < len; ++i) {
 				char c = str[i];
-				bc_vm_putchar(c);
+				bb_putchar(c);
 				if (c == '\n') p->nchars = SIZE_MAX;
 				++p->nchars;
 			}
 		}
 		else {
 			bc_program_printString(str, &p->nchars);
-			if (inst == BC_INST_PRINT) bc_vm_putchar('\n');
+			if (inst == BC_INST_PRINT) bb_putchar('\n');
 		}
 	}
 
@@ -6392,7 +6383,7 @@
 	else {
 		idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
 		str = *((char **) bc_vec_item(&p->strs, idx));
-		bc_vm_printf(stdout, "%s", str);
+		printf("%s", str);
 	}
 
 	return s;
@@ -6685,8 +6676,8 @@
 
 	if (!s || s == BC_STATUS_EXEC_SIGNAL) {
 		if (bcg.ttyin) {
-			bc_vm_puts(bc_program_ready_msg, stderr);
-			bc_vm_fflush(stderr);
+			fputs(bc_program_ready_msg, stderr);
+			fflush(stderr);
 			s = BC_STATUS_SUCCESS;
 		}
 		else
@@ -7029,20 +7020,22 @@
 }
 #endif
 
-static void bc_vm_info(const char *const help)
+static void bc_vm_info(void)
 {
-	bc_vm_printf(stdout, "%s %s\n", bcg.name, "1.1");
-	bc_vm_puts(bc_copyright, stdout);
-	if (help) bc_vm_printf(stdout, help, bcg.name);
+	printf("%s "BB_VER"\n"
+		"Copyright (c) 2018 Gavin D. Howard and contributors\n"
+		"Report bugs at: https://github.com/gavinhoward/bc\n\n"
+		"This is free software with ABSOLUTELY NO WARRANTY\n"
+	, applet_name);
 }
 
 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
 {
 	if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
 
-	bc_vm_printf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
-	bc_vm_printf(stderr, "    %s", file);
-	bc_vm_printf(stderr, bc_err_line + 4 * !line, line);
+	fprintf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
+	fprintf(stderr, "    %s", file);
+	fprintf(stderr, bc_err_line + 4 * !line, line);
 
 	return s * (!bcg.ttyin || !!strcmp(file, bc_program_stdin_name));
 }
@@ -7056,10 +7049,10 @@
 
 	if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
 
-	bc_vm_printf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
-	if (msg) bc_vm_printf(stderr, "    %s\n", msg);
-	bc_vm_printf(stderr, "    %s", file);
-	bc_vm_printf(stderr, bc_err_line + 4 * !line, line);
+	fprintf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
+	if (msg) fprintf(stderr, "    %s\n", msg);
+	fprintf(stderr, "    %s", file);
+	fprintf(stderr, bc_err_line + 4 * !line, line);
 
 	return s * (!bcg.ttyin && !!p);
 }
@@ -7117,39 +7110,6 @@
 	return len;
 }
 
-static void bc_vm_exit(BcStatus s)
-{
-	bc_vm_printf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
-	exit((int) s);
-}
-
-static void bc_vm_printf(FILE *restrict f, const char *fmt, ...)
-{
-	va_list args;
-	bool bad;
-
-	va_start(args, fmt);
-	bad = vfprintf(f, fmt, args) < 0;
-	va_end(args);
-
-	if (bad) bc_vm_exit(BC_STATUS_IO_ERR);
-}
-
-static void bc_vm_puts(const char *str, FILE *restrict f)
-{
-	if (fputs(str, f) == EOF) bc_vm_exit(BC_STATUS_IO_ERR);
-}
-
-static void bc_vm_putchar(int c)
-{
-	if (putchar(c) == EOF) bc_vm_exit(BC_STATUS_IO_ERR);
-}
-
-static void bc_vm_fflush(FILE *restrict f)
-{
-	if (fflush(f) == EOF) bc_vm_exit(BC_STATUS_IO_ERR);
-}
-
 static BcStatus bc_vm_process(BcVm *vm, const char *text)
 {
 	BcStatus s = bc_parse_text(&vm->prs, text);
@@ -7163,16 +7123,16 @@
 
 		if (s == BC_STATUS_LIMITS) {
 
-			bc_vm_putchar('\n');
-			bc_vm_printf(stdout, "BC_BASE_MAX     = %lu\n", BC_MAX_OBASE);
-			bc_vm_printf(stdout, "BC_DIM_MAX      = %lu\n", BC_MAX_DIM);
-			bc_vm_printf(stdout, "BC_SCALE_MAX    = %lu\n", BC_MAX_SCALE);
-			bc_vm_printf(stdout, "BC_STRING_MAX   = %lu\n", BC_MAX_STRING);
-			bc_vm_printf(stdout, "BC_NAME_MAX     = %lu\n", BC_MAX_NAME);
-			bc_vm_printf(stdout, "BC_NUM_MAX      = %lu\n", BC_MAX_NUM);
-			bc_vm_printf(stdout, "Max Exponent    = %lu\n", BC_MAX_EXP);
-			bc_vm_printf(stdout, "Number of Vars  = %lu\n", BC_MAX_VARS);
-			bc_vm_putchar('\n');
+			bb_putchar('\n');
+			printf("BC_BASE_MAX     = %lu\n", BC_MAX_OBASE);
+			printf("BC_DIM_MAX      = %lu\n", BC_MAX_DIM);
+			printf("BC_SCALE_MAX    = %lu\n", BC_MAX_SCALE);
+			printf("BC_STRING_MAX   = %lu\n", BC_MAX_STRING);
+			printf("BC_NAME_MAX     = %lu\n", BC_MAX_NAME);
+			printf("BC_NUM_MAX      = %lu\n", BC_MAX_NUM);
+			printf("Max Exponent    = %lu\n", BC_MAX_EXP);
+			printf("Number of Vars  = %lu\n", BC_MAX_VARS);
+			bb_putchar('\n');
 
 			s = BC_STATUS_SUCCESS;
 		}
@@ -7185,7 +7145,7 @@
 
 	if (BC_PARSE_CAN_EXEC(&vm->prs)) {
 		s = bc_program_exec(&vm->prog);
-		if (!s && bcg.tty) bc_vm_fflush(stdout);
+		if (!s && bcg.tty) fflush(stdout);
 		if (s && s != BC_STATUS_QUIT)
 			s = bc_vm_error(bc_program_reset(&vm->prog, s), vm->prs.l.f, 0);
 	}
@@ -7290,7 +7250,8 @@
 
 	// I/O error will always happen when stdin is
 	// closed. It's not a problem in that case.
-	s = s == BC_STATUS_IO_ERR || s == BC_STATUS_QUIT ? BC_STATUS_SUCCESS : s;
+	if (s == BC_STATUS_INPUT_EOF || s == BC_STATUS_QUIT)
+		s = BC_STATUS_SUCCESS;
 
 	if (str)
 		s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, vm->prs.l.f,
@@ -7328,10 +7289,12 @@
 		s = bc_vm_file(vm, *((char **) bc_vec_item(&vm->files, i)));
 	if (s && s != BC_STATUS_QUIT) return s;
 
-	if (bcg.bc || !vm->files.len) s = bc_vm_stdin(vm);
+	if (IS_BC || !vm->files.len) s = bc_vm_stdin(vm);
 	if (!s && !BC_PARSE_CAN_EXEC(&vm->prs)) s = bc_vm_process(vm, "");
 
-	return s == BC_STATUS_QUIT ? BC_STATUS_SUCCESS : s;
+	if (s == BC_STATUS_QUIT)
+		s = BC_STATUS_SUCCESS;
+	return s;
 }
 
 static void bc_vm_free(BcVm *vm)
@@ -7364,8 +7327,8 @@
 	bc_vec_init(&vm->files, sizeof(char *), NULL);
 
 #if ENABLE_BC
-	vm->flags |= BC_FLAG_S * bcg.bc * (getenv("POSIXLY_CORRECT") != NULL);
-	if (bcg.bc) s = bc_vm_envArgs(vm);
+	vm->flags |= BC_FLAG_S * IS_BC * (getenv("POSIXLY_CORRECT") != NULL);
+	if (IS_BC) s = bc_vm_envArgs(vm);
 #endif
 
 	bc_program_init(&vm->prog, len, exe.init, exe.exp);
@@ -7396,7 +7359,7 @@
 	bcg.exreg = vm.flags & BC_FLAG_X;
 #endif
 
-	if (bcg.ttyin && !(vm.flags & BC_FLAG_Q)) bc_vm_info(NULL);
+	if (bcg.ttyin && !(vm.flags & BC_FLAG_Q)) bc_vm_info();
 	st = bc_vm_exec(&vm);
 
 exit:
@@ -7409,8 +7372,6 @@
 {
 	BcVmExe exec;
 
-	bcg.bc = true;
-	bcg.name = bc_name;
 # if ENABLE_FEATURE_BC_SIGNALS
 	bcg.sig_msg = bc_sig_msg;
 # endif
@@ -7428,8 +7389,6 @@
 {
 	BcVmExe exec;
 
-	bcg.bc = false;
-	bcg.name = dc_name;
 # if ENABLE_FEATURE_BC_SIGNALS
 	bcg.sig_msg = dc_sig_msg;
 # endif