#define INIT_G() do { \
SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
} while (0)
+#define FREE_G() do { \
+ FREE_PTR_TO_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))
bb_perror_msg_and_die("output error");
}
+#if ENABLE_FEATURE_CLEAN_UP
+#define quit_or_return_for_exit() \
+do { \
+ G.ttyin = 0; /* do not loop in main loop anymore */ \
+ return BC_STATUS_FAILURE; \
+} while (0)
+#else
+#define quit_or_return_for_exit() quit()
+#endif
+
static void quit(void) NORETURN;
static void quit(void)
{
bc_verror_msg(fmt, p);
va_end(p);
- if (!G.ttyin)
+ if (!ENABLE_FEATURE_CLEAN_UP && !G.ttyin)
exit(1);
return BC_STATUS_FAILURE;
}
// Do we treat non-POSIX constructs as errors?
if (!(option_mask32 & BC_FLAG_S))
return BC_STATUS_SUCCESS; // no, it's a warning
- if (!G.ttyin)
+ if (!ENABLE_FEATURE_CLEAN_UP && !G.ttyin)
exit(1);
return BC_STATUS_FAILURE;
}
// "quit" is a compile-time command. For example,
// "if (0 == 1) quit" terminates when parsing the statement,
// not when it is executed
- quit();
+ quit_or_return_for_exit();
}
case BC_LEX_KEY_RETURN:
if (G.prog.stack.len < val)
return bc_error_stack_has_too_few_elements();
- if (G.prog.stack.len == val)
+ if (G.prog.stack.len == val) {
+ if (ENABLE_FEATURE_CLEAN_UP)
+ return BC_STATUS_FAILURE;
quit();
+ }
bc_vec_npop(&G.prog.stack, val);
case BC_INST_HALT:
{
- quit();
+ quit_or_return_for_exit();
break;
}
case BC_INST_QUIT:
{
if (G.prog.stack.len <= 2)
- quit();
+ quit_or_return_for_exit();
bc_vec_npop(&G.prog.stack, 2);
break;
}
bc_vec_concat(&buffer, buf.v);
s = bc_vm_process(buffer.v);
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.
+ break;
+ }
fflush_and_check();
fputs("ready for more input\n", stderr);
}
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
-static void bc_program_free()
+static void bc_program_free(void)
{
bc_num_free(&G.prog.ib);
bc_num_free(&G.prog.ob);
#if ENABLE_FEATURE_CLEAN_UP
bc_vm_free();
+ FREE_G();
#endif
return st;
}