bc: handle "limits" and "quit" immediately at parse time
authorDenys Vlasenko <vda.linux@googlemail.com>
Mon, 3 Dec 2018 13:02:35 +0000 (14:02 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Wed, 5 Dec 2018 14:43:35 +0000 (15:43 +0100)
No need to propagate a special exit code.

function                                             old     new   delta
bc_parse_stmt                                       2197    2301    +104
quit                                                   -      38     +38
bc_read_line                                         344     349      +5
bc_program_reset                                     174     172      -2
bc_num_s                                             252     246      -6
bc_num_a                                             454     445      -9
bc_parse_parse                                       471     461     -10
bc_num_ulong                                          95      85     -10
bc_program_exec                                     4500    4478     -22
bc_vm_run                                           2006    1978     -28
bc_vm_process                                        291     139    -152
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 2/8 up/down: 147/-239)          Total: -92 bytes
   text    data     bss     dec     hex filename
 987936     485    7296  995717   f3185 busybox_old
 987844     485    7296  995625   f3129 busybox_unstripped

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

index ee6cc47cea1fe229292425093dd847c5ba5babf3..c3d118417a30630f731b291dc905a74b9188995a 100644 (file)
@@ -231,8 +231,8 @@ typedef enum BcStatus {
        BC_STATUS_POSIX_FOR3,
        BC_STATUS_POSIX_BRACE,
 #endif
-       BC_STATUS_QUIT,
-       BC_STATUS_LIMITS,
+//     BC_STATUS_QUIT,
+//     BC_STATUS_LIMITS,
 
 //     BC_STATUS_INVALID_OPTION,
 } BcStatus;
@@ -1121,6 +1121,13 @@ static const char bc_lib[] = {
 };
 #endif // ENABLE_BC
 
+static void quit(void) NORETURN;
+static void quit(void)
+{
+       fflush_all();
+       exit(ferror(stdout) || ferror(stderr));
+}
+
 static void bc_vec_grow(BcVec *v, size_t n)
 {
        size_t cap = v->cap * 2;
@@ -1279,9 +1286,9 @@ static BcStatus bc_read_line(BcVec *vec, const char *prompt)
 
        fflush(stdout);
 #if ENABLE_FEATURE_BC_SIGNALS
-       if (bb_got_signal) { /* ^C was pressed */
+       if (bb_got_signal) { // ^C was pressed
  intr:
-               bb_got_signal = 0; /* resets G_interrupt to zero */
+               bb_got_signal = 0; // resets G_interrupt to zero
                fputs(IS_BC
                        ? "\ninterrupt (type \"quit\" to exit)\n"
                        : "\ninterrupt (type \"q\" to exit)\n"
@@ -1293,7 +1300,6 @@ static BcStatus bc_read_line(BcVec *vec, const char *prompt)
        fflush(stderr);
 
 #if ENABLE_FEATURE_BC_SIGNALS
- again:
        errno = 0;
 #endif
        do {
@@ -1302,16 +1308,13 @@ static BcStatus bc_read_line(BcVec *vec, const char *prompt)
 
                i = fgetc(stdin);
 
-#if ENABLE_FEATURE_BC_SIGNALS
-               if (bb_got_signal) /* ^C was pressed */
-                       goto intr;
-#endif
-
                if (i == EOF) {
 #if ENABLE_FEATURE_BC_SIGNALS
-                       if (errno == EINTR) {
+                       // Both conditions appear simultaneously, check both just in case
+                       if (errno == EINTR || bb_got_signal) {
+                               // ^C was pressed
                                clearerr(stdin);
-                               goto again;
+                               goto intr;
                        }
 #endif
                        if (ferror(stdin))
@@ -4630,9 +4633,18 @@ static BcStatus bc_parse_stmt(BcParse *p)
 
                case BC_LEX_KEY_LIMITS:
                {
+                       // "limits" is a compile-time command,
+                       // the output is produced at _parse time_.
                        s = bc_lex_next(&p->l);
                        if (s) return s;
-                       s = BC_STATUS_LIMITS;
+                       printf("BC_BASE_MAX     = %u\n", BC_MAX_OBASE);
+                       printf("BC_DIM_MAX      = %u\n", BC_MAX_DIM);
+                       printf("BC_SCALE_MAX    = %u\n", BC_MAX_SCALE);
+                       printf("BC_STRING_MAX   = %u\n", BC_MAX_STRING);
+                       printf("BC_NAME_MAX     = %u\n", BC_MAX_NAME);
+                       printf("BC_NUM_MAX      = %u\n", BC_MAX_NUM);
+                       printf("MAX Exponent    = %lu\n", BC_MAX_EXP);
+                       printf("Number of vars  = %lu\n", BC_MAX_VARS);
                        break;
                }
 
@@ -4644,10 +4656,10 @@ static BcStatus bc_parse_stmt(BcParse *p)
 
                case BC_LEX_KEY_QUIT:
                {
-                       // Quit is a compile-time command. We don't exit directly,
-                       // so the vm can clean up. Limits do the same thing.
-                       s = BC_STATUS_QUIT;
-                       break;
+                       // "quit" is a compile-time command. For example,
+                       // "if (0 == 1) quit" terminates when parsing the statement,
+                       // not when it is executed
+                       quit();
                }
 
                case BC_LEX_KEY_RETURN:
@@ -4685,7 +4697,7 @@ static BcStatus bc_parse_parse(BcParse *p)
        else
                s = bc_parse_stmt(p);
 
-       if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || G_interrupt)
+       if (s || G_interrupt)
                s = bc_parse_reset(p, s);
 
        return s;
@@ -6283,8 +6295,8 @@ static BcStatus bc_program_nquit(void)
 
        if (G.prog.stack.len < val)
                return BC_STATUS_EXEC_STACK;
-       else if (G.prog.stack.len == val)
-               return BC_STATUS_QUIT;
+       if (G.prog.stack.len == val)
+               quit();
 
        bc_vec_npop(&G.prog.stack, val);
 
@@ -6456,17 +6468,15 @@ static BcStatus bc_program_reset(BcStatus s)
        ip = bc_vec_top(&G.prog.stack);
        ip->idx = f->code.len;
 
-       if (!s && G_interrupt && !G.tty) return BC_STATUS_QUIT;
+       if (!s && G_interrupt && !G.tty) quit();
 
        if (!s || s == BC_STATUS_EXEC_SIGNAL) {
-               if (G.ttyin) {
-                       fflush(stdout);
-                       fputs(bc_program_ready_msg, stderr);
-                       fflush(stderr);
-                       s = BC_STATUS_SUCCESS;
-               }
-               else
-                       s = BC_STATUS_QUIT;
+               if (!G.ttyin)
+                       quit();
+               fflush(stdout);
+               fputs(bc_program_ready_msg, stderr);
+               fflush(stderr);
+               s = BC_STATUS_SUCCESS;
        }
 
        return s;
@@ -6524,7 +6534,7 @@ static BcStatus bc_program_exec(void)
 
                        case BC_INST_HALT:
                        {
-                               s = BC_STATUS_QUIT;
+                               quit();
                                break;
                        }
 
@@ -6767,9 +6777,8 @@ static BcStatus bc_program_exec(void)
                        case BC_INST_QUIT:
                        {
                                if (G.prog.stack.len <= 2)
-                                       s = BC_STATUS_QUIT;
-                               else
-                                       bc_vec_npop(&G.prog.stack, 2);
+                                       quit();
+                               bc_vec_npop(&G.prog.stack, 2);
                                break;
                        }
 
@@ -6781,7 +6790,7 @@ static BcStatus bc_program_exec(void)
 #endif // ENABLE_DC
                }
 
-               if ((s && s != BC_STATUS_QUIT) || G_interrupt) s = bc_program_reset(s);
+               if (s || G_interrupt) s = bc_program_reset(s);
 
                // If the stack has changed, pointers may be invalid.
                ip = bc_vec_top(&G.prog.stack);
@@ -6895,30 +6904,14 @@ static BcStatus bc_vm_process(const char *text)
 
                s = G.prs.parse(&G.prs);
 
-               if (s == BC_STATUS_LIMITS) {
-
-                       printf("BC_BASE_MAX     = %u\n", BC_MAX_OBASE);
-                       printf("BC_DIM_MAX      = %u\n", BC_MAX_DIM);
-                       printf("BC_SCALE_MAX    = %u\n", BC_MAX_SCALE);
-                       printf("BC_STRING_MAX   = %u\n", BC_MAX_STRING);
-                       printf("BC_NAME_MAX     = %u\n", BC_MAX_NAME);
-                       printf("BC_NUM_MAX      = %u\n", BC_MAX_NUM);
-                       printf("MAX Exponent    = %lu\n", BC_MAX_EXP);
-                       printf("Number of vars  = %lu\n", BC_MAX_VARS);
-
-                       s = BC_STATUS_SUCCESS;
-               }
-               else {
-                       if (s == BC_STATUS_QUIT) return s;
-                       s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
-                       if (s) return s;
-               }
+               s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
+               if (s) return s;
        }
 
        if (BC_PARSE_CAN_EXEC(&G.prs)) {
                s = bc_program_exec();
-               if (!s && G.tty) fflush(stdout);
-               if (s && s != BC_STATUS_QUIT)
+               fflush(stdout);
+               if (s)
                        s = bc_vm_error(bc_program_reset(s), G.prs.l.f, 0);
        }
 
@@ -7021,7 +7014,7 @@ static BcStatus bc_vm_stdin(void)
 
        // 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)
+       if (s == BC_STATUS_INPUT_EOF)
                s = BC_STATUS_SUCCESS;
 
        if (str)
@@ -7058,13 +7051,11 @@ static BcStatus bc_vm_exec(void)
 
        for (i = 0; !s && i < G.files.len; ++i)
                s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
-       if (s && s != BC_STATUS_QUIT) return s;
+       if (s) return s;
 
        if (IS_BC || !G.files.len) s = bc_vm_stdin();
        if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
 
-       if (s == BC_STATUS_QUIT)
-               s = BC_STATUS_SUCCESS;
        return s;
 }