bc: simplify, and restore ^C, fix ^D handling
authorDenys Vlasenko <vda.linux@googlemail.com>
Sun, 2 Dec 2018 13:35:32 +0000 (14:35 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Wed, 5 Dec 2018 14:43:35 +0000 (15:43 +0100)
^D used to enter infinite loop

function                                             old     new   delta
bc_read_line                                         342     359     +17
bc_args_opt                                            8       -      -8
dc_sig_msg                                            31       -     -31
bc_sig_msg                                            34       -     -34
bc_vm_run                                           2608    2569     -39
bc_args                                              123      83     -40
bc_args_lopt                                          81       -     -81
------------------------------------------------------------------------------
(add/remove: 0/4 grow/shrink: 1/2 up/down: 17/-233)          Total: -216 bytes
   text    data     bss     dec     hex filename
 989491     485    7336  997312   f37c0 busybox_old
 989425     485    7336  997246   f377e busybox_unstripped

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
miscutils/bc.c

index f36534c36aae86dc4a597a02827b68d6347fbd4c..d5f5775987d5175c28bb412bfb962563ba59eb96 100644 (file)
@@ -249,7 +249,6 @@ typedef enum BcStatus {
 #define BC_VEC_START_CAP (1 << 5)
 
 typedef void (*BcVecFree)(void *);
-typedef int (*BcVecCmp)(const void *, const void *);
 
 typedef struct BcVec {
        char *v;
@@ -691,8 +690,6 @@ typedef struct BcParse {
 
 #if ENABLE_BC
 
-BcStatus bc_main(int argc, char *argv[]);
-
 typedef struct BcLexKeyword {
        const char name[9];
        const char len;
@@ -725,8 +722,6 @@ static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
 
 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
 
-BcStatus dc_main(int argc, char *argv[]);
-
 static BcStatus dc_lex_token(BcLex *l);
 
 static void dc_parse_init(BcParse *p, struct BcProgram *prog, size_t func);
@@ -864,23 +859,9 @@ static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
 #endif
 
 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
-# if ENABLE_FEATURE_BC_SIGNALS
-static const char bc_sig_msg[] = "\ninterrupt (type \"quit\" to exit)\n";
-# endif
-#endif
-
-#if ENABLE_DC
-# if ENABLE_FEATURE_BC_SIGNALS
-static const char dc_sig_msg[] = "\ninterrupt (type \"q\" to exit)\n";
-# endif
-#endif
-
 static const char* const bc_args_env_name = "BC_ENV_ARGS";
 
 static const char bc_err_fmt[] = "\n%s error: %s\n";
@@ -1386,28 +1367,25 @@ static BcStatus bc_read_line(BcVec *vec, const char *prompt)
                if (ferror(stdout) || ferror(stderr))
                        bb_perror_msg_and_die("output error");
 
+               errno = 0;
                i = fgetc(stdin);
-               if (ferror(stdin))
-                       bb_perror_msg_and_die("input error");
 
                if (i == EOF) {
-
 #if ENABLE_FEATURE_BC_SIGNALS
                        if (errno == EINTR) {
-
                                bcg.sigc = bcg.sig;
                                bcg.signe = 0;
-
                                if (bcg.ttyin) {
                                        fputs(bc_program_ready_msg, stderr);
                                        if (!bcg.posix) fputs(prompt, stderr);
                                        fflush(stderr);
                                }
-
+                               clearerr(stdin);
                                continue;
                        }
+                       if (ferror(stdin))
+                               bb_perror_msg_and_die("input error");
 #endif
-
                        return BC_STATUS_INPUT_EOF;
                }
 
@@ -1441,40 +1419,32 @@ read_err:
        return s;
 }
 
-#if ENABLE_FEATURE_BC_LONG_OPTIONS
-static const char bc_args_lopt[] ALIGN1 =
-       "extended-register\0"No_argument"x"
-       "warn\0"No_argument"w"
-       "version\0"No_argument"v"
-       "standard\0"No_argument"s"
-       "quiet\0"No_argument"q"
-       "mathlib\0"No_argument"l"
-       "interactive\0"No_argument"i";
-#endif
-
-static const char bc_args_opt[] ALIGN1 = "xwvsqli";
-
-static BcStatus bc_args(int argc, char *argv[], uint32_t *flags, BcVec *files)
+static void bc_args(int argc, char *argv[], uint32_t *flags, BcVec *files)
 {
-       BcStatus s = BC_STATUS_SUCCESS;
        int i;
        bool do_exit = false;
 
-       i = optind = 0;
-
+       GETOPT_RESET();
 #if ENABLE_FEATURE_BC_LONG_OPTIONS
-       *flags = getopt32long(argv, bc_args_opt, bc_args_lopt);
+       *flags = getopt32long(argv, "xwvsqli",
+               "extended-register\0" No_argument "x"
+               "warn\0"              No_argument "w"
+               "version\0"           No_argument "v"
+               "standard\0"          No_argument "s"
+               "quiet\0"             No_argument "q"
+               "mathlib\0"           No_argument "l"
+               "interactive\0"       No_argument "i"
+       );
 #else
-       *flags = getopt32(argv, bc_args_opt);
+       *flags = getopt32(argv, "xwvsqli");
 #endif
 
        if ((*flags) & BC_FLAG_V) bc_vm_info();
-       if (do_exit) exit((int) s);
-       if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
+       if (do_exit) exit(0);
+       // should not be necessary, getopt32() handles this??
+       //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
 
        for (i = optind; i < argc; ++i) bc_vec_push(files, argv + i);
-
-       return s;
 }
 
 static void bc_num_setToZero(BcNum *n, size_t scale)
@@ -7024,7 +6994,7 @@ static void bc_vm_info(void)
 {
        printf("%s "BB_VER"\n"
                "Copyright (c) 2018 Gavin D. Howard and contributors\n"
-               "Report bugs at: https://github.com/gavinhoward/bc\n\n"
+               "Report bugs at: https://github.com/gavinhoward/bc\n"
                "This is free software with ABSOLUTELY NO WARRANTY\n"
        , applet_name);
 }
@@ -7057,13 +7027,12 @@ static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
        return s * (!bcg.ttyin && !!p);
 }
 
-static BcStatus bc_vm_envArgs(BcVm *vm)
+static void bc_vm_envArgs(BcVm *vm)
 {
-       BcStatus s = BC_STATUS_SUCCESS;
        BcVec v;
        char *env_args = getenv(bc_args_env_name), *buf;
 
-       if (!env_args) return s;
+       if (!env_args) return;
 
        vm->env_args = xstrdup(env_args);
        buf = vm->env_args;
@@ -7081,11 +7050,9 @@ static BcStatus bc_vm_envArgs(BcVm *vm)
                        ++buf;
        }
 
-       s = bc_args((int) v.len, (char **) v.v, &vm->flags, &vm->files);
+       bc_args((int) v.len, (char **) v.v, &vm->flags, &vm->files);
 
        bc_vec_free(&v);
-
-       return s;
 }
 #endif // ENABLE_BC
 
@@ -7248,7 +7215,7 @@ static BcStatus bc_vm_stdin(BcVm *vm)
 
        if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, vm->prs.l.f, 0);
 
-       // I/O error will always happen when stdin is
+       // INPUT_EOF will always happen when stdin is
        // closed. It's not a problem in that case.
        if (s == BC_STATUS_INPUT_EOF || s == BC_STATUS_QUIT)
                s = BC_STATUS_SUCCESS;
@@ -7305,9 +7272,8 @@ static void bc_vm_free(BcVm *vm)
        free(vm->env_args);
 }
 
-static BcStatus bc_vm_init(BcVm *vm, BcVmExe exe, const char *env_len)
+static void bc_vm_init(BcVm *vm, BcVmExe exe, const char *env_len)
 {
-       BcStatus s = BC_STATUS_SUCCESS;
        size_t len = bc_vm_envLen(env_len);
 #if ENABLE_FEATURE_BC_SIGNALS
        struct sigaction sa;
@@ -7328,13 +7294,11 @@ static BcStatus bc_vm_init(BcVm *vm, BcVmExe exe, const char *env_len)
 
 #if ENABLE_BC
        vm->flags |= BC_FLAG_S * IS_BC * (getenv("POSIXLY_CORRECT") != NULL);
-       if (IS_BC) s = bc_vm_envArgs(vm);
+       if (IS_BC) bc_vm_envArgs(vm);
 #endif
 
        bc_program_init(&vm->prog, len, exe.init, exe.exp);
        exe.init(&vm->prs, &vm->prog, BC_PROG_MAIN);
-
-       return s;
 }
 
 static BcStatus bc_vm_run(int argc, char *argv[], BcVmExe exe,
@@ -7343,10 +7307,8 @@ static BcStatus bc_vm_run(int argc, char *argv[], BcVmExe exe,
        BcStatus st;
        BcVm vm;
 
-       st = bc_vm_init(&vm, exe, env_len);
-       if (st) goto exit;
-       st = bc_args(argc, argv, &vm.flags, &vm.files);
-       if (st) goto exit;
+       bc_vm_init(&vm, exe, env_len);
+       bc_args(argc, argv, &vm.flags, &vm.files);
 
        bcg.ttyin = isatty(0);
        bcg.tty = bcg.ttyin || (vm.flags & BC_FLAG_I) || isatty(1);
@@ -7362,18 +7324,18 @@ static BcStatus bc_vm_run(int argc, char *argv[], BcVmExe exe,
        if (bcg.ttyin && !(vm.flags & BC_FLAG_Q)) bc_vm_info();
        st = bc_vm_exec(&vm);
 
-exit:
        bc_vm_free(&vm);
        return st;
 }
 
 #if ENABLE_BC
-BcStatus bc_main(int argc, char *argv[])
+int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int bc_main(int argc, char **argv)
 {
        BcVmExe exec;
 
 # if ENABLE_FEATURE_BC_SIGNALS
-       bcg.sig_msg = bc_sig_msg;
+       bcg.sig_msg = "\ninterrupt (type \"quit\" to exit)\n";
 # endif
 
        exec.init = bc_parse_init;
@@ -7385,12 +7347,13 @@ BcStatus bc_main(int argc, char *argv[])
 #endif
 
 #if ENABLE_DC
-BcStatus dc_main(int argc, char *argv[])
+int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dc_main(int argc, char **argv)
 {
        BcVmExe exec;
 
 # if ENABLE_FEATURE_BC_SIGNALS
-       bcg.sig_msg = dc_sig_msg;
+       bcg.sig_msg = "\ninterrupt (type \"q\" to exit)\n";
 # endif
 
        exec.init = dc_parse_init;