bc: simplify, stop testing for IO errors on every output
authorDenys Vlasenko <vda.linux@googlemail.com>
Fri, 30 Nov 2018 22:13:42 +0000 (23:13 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Wed, 5 Dec 2018 14:42:52 +0000 (15:42 +0100)
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>
miscutils/bc.c

index 4cbef4da6447f0e494627c10e7961adb0851147a..f36534c36aae86dc4a597a02827b68d6347fbd4c 100644 (file)
@@ -165,7 +165,7 @@ typedef enum BcStatus {
        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_lex_token(BcLex *l);
 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 @@ typedef struct BcGlobals {
        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 size_t bc_map_index(const BcVec *v, const void *ptr)
 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 @@ static BcStatus bc_read_line(BcVec *vec, const char *prompt)
                                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 @@ static BcStatus bc_args(int argc, char *argv[], uint32_t *flags, BcVec *files)
        *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 @@ int_err:
 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 @@ static void bc_num_printChar(size_t num, size_t width, bool radix,
                              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 @@ static void bc_num_printDigits(size_t num, size_t width, bool radix,
        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 @@ static void bc_num_printDigits(size_t num, size_t width, bool radix,
                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 @@ static void bc_num_printHex(size_t num, size_t width, bool radix,
 {
        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 @@ static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
 {
        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 @@ static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
        BcNumDigitOp print;
        bool neg = n->neg;
 
-       if (neg) bc_vm_putchar('-');
+       if (neg) bb_putchar('-');
        (*nchars) += neg;
 
        n->neg = false;
@@ -2546,7 +2537,7 @@ static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
        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 @@ static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
                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 @@ static void bc_program_printString(const char *str, size_t *nchars)
 
 #if ENABLE_DC
        if (len == 0) {
-               bc_vm_putchar('\0');
+               bb_putchar('\0');
                return;
        }
 #endif
@@ -5587,7 +5578,7 @@ static void bc_program_printString(const char *str, size_t *nchars)
                int c = str[i];
 
                if (c != '\\' || i == len - 1)
-                       bc_vm_putchar(c);
+                       bb_putchar(c);
                else {
 
                        c = str[++i];
@@ -5596,60 +5587,60 @@ static void bc_program_printString(const char *str, size_t *nchars)
 
                                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 @@ static BcStatus bc_program_print(BcProgram *p, char inst, size_t idx)
                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 @@ static BcStatus bc_program_printStream(BcProgram *p)
        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 @@ static BcStatus bc_program_reset(BcProgram *p, BcStatus s)
 
        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 @@ static void bc_vm_sig(int sig)
 }
 #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 @@ static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
 
        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 @@ static size_t bc_vm_envLen(const char *var)
        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 @@ static BcStatus bc_vm_process(BcVm *vm, const char *text)
 
                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 @@ static BcStatus bc_vm_process(BcVm *vm, const char *text)
 
        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 @@ static BcStatus bc_vm_stdin(BcVm *vm)
 
        // 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 @@ static BcStatus bc_vm_exec(BcVm *vm)
                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 @@ static BcStatus bc_vm_init(BcVm *vm, BcVmExe exe, const char *env_len)
        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 @@ static BcStatus bc_vm_run(int argc, char *argv[], BcVmExe exe,
        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 @@ BcStatus bc_main(int argc, char *argv[])
 {
        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 @@ BcStatus dc_main(int argc, char *argv[])
 {
        BcVmExe exec;
 
-       bcg.bc = false;
-       bcg.name = dc_name;
 # if ENABLE_FEATURE_BC_SIGNALS
        bcg.sig_msg = dc_sig_msg;
 # endif