//config: Also note that, like the FreeBSD dc, extended registers are not
//config: allowed unless the "-x" option is given.
//config:
+//config:config FEATURE_DC_SMALL
+//config: bool "Minimal dc implementation (4.2 kb), not using bc code base"
+//config: depends on DC && !BC
+//config: default y
+//config:
+//config:config FEATURE_DC_LIBM
+//config: bool "Enable power and exp functions (requires libm)"
+//config: default y
+//config: depends on FEATURE_DC_SMALL
+//config: help
+//config: Enable power and exp functions.
+//config: NOTE: This will require libm to be present for linking.
+//config:
//config:config FEATURE_BC_SIGNALS
//config: bool "Enable bc/dc signal handling"
//config: default y
-//config: depends on BC || DC
+//config: depends on (BC || DC) && !FEATURE_DC_SMALL
//config: help
//config: Enable signal handling for bc and dc.
//config:
//config:config FEATURE_BC_LONG_OPTIONS
//config: bool "Enable bc/dc long options"
//config: default y
-//config: depends on BC || DC
+//config: depends on (BC || DC) && !FEATURE_DC_SMALL
//config: help
//config: Enable long options for bc and dc.
//See www.gnu.org/software/bc/manual/bc.html
//usage:#define bc_trivial_usage
-//usage: "[-sqli] FILE..."
+//usage: "[-sqliw] FILE..."
//usage:
//usage:#define bc_full_usage "\n"
//usage: "\nArbitrary precision calculator"
//usage: "\n -q Quiet"
//usage: "\n -w Warn if extensions are used"
///////: "\n -v Version"
+//usage: "\n$BC_LINE_LENGTH changes output width"
//usage:
//usage:#define bc_example_usage
//usage: "3 + 4.129\n"
//usage:#define dc_trivial_usage
//usage: "EXPRESSION..."
//usage:
-//usage:#define dc_full_usage "\n\n"
-//usage: "Tiny RPN calculator. Operations:\n"
-//usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
-//usage: "modular exponentiation,\n"
-//usage: "p - print top of the stack (without popping),\n"
-//usage: "f - print entire stack,\n"
-//usage: "k - pop the value and set the precision.\n"
-//usage: "i - pop the value and set input radix.\n"
-//usage: "o - pop the value and set output radix.\n"
-//usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
+//usage:#define dc_full_usage "\n"
+//usage: "\nTiny RPN calculator. Operations:"
+//usage: "\n+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
+//usage: "modular exponentiation,"
+//usage: "\np - print top of the stack (without popping),"
+//usage: "\nf - print entire stack,"
+//usage: "\nk - pop the value and set the precision."
+//usage: "\ni - pop the value and set input radix."
+//usage: "\no - pop the value and set output radix."
+//usage: "\nExamples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
//usage:
//usage:#define dc_example_usage
//usage: "$ dc 2 2 + p\n"
//usage: "64\n"
#include "libbb.h"
+#include "common_bufsiz.h"
+
+#if ENABLE_FEATURE_DC_SMALL
+# include "dc.c"
+#else
typedef enum BcStatus {
BC_STATUS_SUCCESS = 0,
BcVecFree dtor;
} BcVec;
-#define bc_vec_pop(v) (bc_vec_npop((v), 1))
-#define bc_vec_top(v) (bc_vec_item_rev((v), 0))
-
typedef signed char BcDig;
typedef struct BcNum {
bool neg;
} BcNum;
-#define BC_NUM_MIN_BASE ((unsigned long) 2)
-#define BC_NUM_MAX_IBASE ((unsigned long) 16)
-#define BC_NUM_DEF_SIZE (16)
-#define BC_NUM_PRINT_WIDTH (69)
+#define BC_NUM_MIN_BASE ((unsigned long) 2)
+#define BC_NUM_MAX_IBASE ((unsigned long) 16)
+// larger value might speed up BIGNUM calculations a bit:
+#define BC_NUM_DEF_SIZE (16)
+#define BC_NUM_PRINT_WIDTH (69)
-#define BC_NUM_KARATSUBA_LEN (32)
+#define BC_NUM_KARATSUBA_LEN (32)
-#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
-#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
-#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
+#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
+#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
+#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
#define BC_NUM_AREQ(a, b) \
(BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
#define BC_NUM_MREQ(a, b, scale) \
struct BcLexKeyword {
char name8[8];
};
-#define BC_LEX_KW_ENTRY(a, b, c) \
- { .name8 = a /*, .len = b, .posix = c*/ }
+#define BC_LEX_KW_ENTRY(a, b) \
+ { .name8 = a /*, .posix = b */ }
static const struct BcLexKeyword bc_lex_kws[20] = {
- BC_LEX_KW_ENTRY("auto" , 4, 1), // 0
- BC_LEX_KW_ENTRY("break" , 5, 1), // 1
- BC_LEX_KW_ENTRY("continue", 8, 0), // 2 note: this one has no terminating NUL
- BC_LEX_KW_ENTRY("define" , 6, 1), // 3
-
- BC_LEX_KW_ENTRY("else" , 4, 0), // 4
- BC_LEX_KW_ENTRY("for" , 3, 1), // 5
- BC_LEX_KW_ENTRY("halt" , 4, 0), // 6
- BC_LEX_KW_ENTRY("ibase" , 5, 1), // 7
-
- BC_LEX_KW_ENTRY("if" , 2, 1), // 8
- BC_LEX_KW_ENTRY("last" , 4, 0), // 9
- BC_LEX_KW_ENTRY("length" , 6, 1), // 10
- BC_LEX_KW_ENTRY("limits" , 6, 0), // 11
-
- BC_LEX_KW_ENTRY("obase" , 5, 1), // 12
- BC_LEX_KW_ENTRY("print" , 5, 0), // 13
- BC_LEX_KW_ENTRY("quit" , 4, 1), // 14
- BC_LEX_KW_ENTRY("read" , 4, 0), // 15
-
- BC_LEX_KW_ENTRY("return" , 6, 1), // 16
- BC_LEX_KW_ENTRY("scale" , 5, 1), // 17
- BC_LEX_KW_ENTRY("sqrt" , 4, 1), // 18
- BC_LEX_KW_ENTRY("while" , 5, 1), // 19
+ BC_LEX_KW_ENTRY("auto" , 1), // 0
+ BC_LEX_KW_ENTRY("break" , 1), // 1
+ BC_LEX_KW_ENTRY("continue", 0), // 2 note: this one has no terminating NUL
+ BC_LEX_KW_ENTRY("define" , 1), // 3
+
+ BC_LEX_KW_ENTRY("else" , 0), // 4
+ BC_LEX_KW_ENTRY("for" , 1), // 5
+ BC_LEX_KW_ENTRY("halt" , 0), // 6
+ BC_LEX_KW_ENTRY("ibase" , 1), // 7
+
+ BC_LEX_KW_ENTRY("if" , 1), // 8
+ BC_LEX_KW_ENTRY("last" , 0), // 9
+ BC_LEX_KW_ENTRY("length" , 1), // 10
+ BC_LEX_KW_ENTRY("limits" , 0), // 11
+
+ BC_LEX_KW_ENTRY("obase" , 1), // 12
+ BC_LEX_KW_ENTRY("print" , 0), // 13
+ BC_LEX_KW_ENTRY("quit" , 1), // 14
+ BC_LEX_KW_ENTRY("read" , 0), // 15
+
+ BC_LEX_KW_ENTRY("return" , 1), // 16
+ BC_LEX_KW_ENTRY("scale" , 1), // 17
+ BC_LEX_KW_ENTRY("sqrt" , 1), // 18
+ BC_LEX_KW_ENTRY("while" , 1), // 19
};
+#undef BC_LEX_KW_ENTRY
enum {
POSIX_KWORD_MASK = 0
| (1 << 0)
| (1 << 18)
| (1 << 19)
};
+#define bc_lex_kws_POSIX(i) ((1 << (i)) & POSIX_KWORD_MASK)
#endif
struct BcLex;
#define BC_PARSE_STREND ((char) UCHAR_MAX)
-#define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
-#define bc_parse_updateFunc(p, f) \
- ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
-
-#define BC_PARSE_REL (1 << 0)
-#define BC_PARSE_PRINT (1 << 1)
+#define BC_PARSE_REL (1 << 0)
+#define BC_PARSE_PRINT (1 << 1)
#define BC_PARSE_NOCALL (1 << 2)
#define BC_PARSE_NOREAD (1 << 3)
-#define BC_PARSE_ARRAY (1 << 4)
+#define BC_PARSE_ARRAY (1 << 4)
#define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
#define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
BcLexType tokens[4];
} BcParseNext;
-#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
-#define BC_PARSE_NEXT(a, ...) \
- { \
- .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
- }
-
struct BcParse;
struct BcProgram;
#define BC_PROG_MAIN (0)
#define BC_PROG_READ (1)
-
#if ENABLE_DC
#define BC_PROG_REQ_FUNCS (2)
#endif
typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
-static void bc_program_addFunc(char *name, size_t *idx);
-static void bc_program_reset(void);
-
#define BC_FLAG_X (1 << 0)
#define BC_FLAG_W (1 << 1)
#define BC_FLAG_V (1 << 2)
#define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
struct globals {
- smallint ttyin;
+ IF_FEATURE_BC_SIGNALS(smallint ttyin;)
smallint eof;
char sbgn;
char send;
BcVec files;
char *env_args;
+
+#if ENABLE_FEATURE_EDITING
+ line_input_t *line_input_state;
+#endif
} FIX_ALIASING;
#define G (*ptr_to_globals)
#define INIT_G() do { \
#define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
#define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X))
#define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
-
+#if ENABLE_FEATURE_BC_SIGNALS
+# define G_ttyin G.ttyin
+#else
+# define G_ttyin 0
+#endif
#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
#if ENABLE_BC
#define bc_parse_op_LEFT(i) (bc_parse_ops[i] & 0x10)
// These identify what tokens can come after expressions in certain cases.
+#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
+#define BC_PARSE_NEXT(a, ...) \
+ { \
+ .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
+ }
static const BcParseNext bc_parse_next_expr =
BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
static const BcParseNext bc_parse_next_param =
#if ENABLE_FEATURE_CLEAN_UP
#define quit_or_return_for_exit() \
do { \
- G.ttyin = 0; /* do not loop in main loop anymore */ \
+ IF_FEATURE_BC_SIGNALS(G_ttyin = 0;) /* do not loop in main loop anymore */ \
return BC_STATUS_FAILURE; \
} while (0)
#else
bc_verror_msg(fmt, p);
va_end(p);
- if (!ENABLE_FEATURE_CLEAN_UP && !G.ttyin)
+ if (!ENABLE_FEATURE_CLEAN_UP && !G_ttyin)
exit(1);
return BC_STATUS_FAILURE;
}
+#if ENABLE_BC
static NOINLINE int bc_posix_error_fmt(const char *fmt, ...)
{
va_list p;
// Do we treat non-POSIX constructs as errors?
if (!(option_mask32 & BC_FLAG_S))
return BC_STATUS_SUCCESS; // no, it's a warning
- if (!ENABLE_FEATURE_CLEAN_UP && !G.ttyin)
+ if (!ENABLE_FEATURE_CLEAN_UP && !G_ttyin)
exit(1);
return BC_STATUS_FAILURE;
}
+#endif
// We use error functions with "return bc_error(FMT[, PARAMS])" idiom.
// This idiom begs for tail-call optimization, but for it to work,
-// function must not have calller-cleaned parameters on stack.
-// Unfortunately, vararg functions do exactly that on most arches.
-// Thus, these shims for the cases when we have no PARAMS:
+// function must not have caller-cleaned parameters on stack.
+// Unfortunately, vararg function API does exactly that on most arches.
+// Thus, use these shims for the cases when we have no vararg PARAMS:
static int bc_error(const char *msg)
{
return bc_error_fmt("%s", msg);
}
-static int bc_posix_error(const char *msg)
+#if ENABLE_BC
+static int bc_POSIX_requires(const char *msg)
{
- return bc_posix_error_fmt("%s", msg);
+ return bc_posix_error_fmt("POSIX requires %s", msg);
}
static int bc_POSIX_does_not_allow(const char *msg)
{
{
return bc_posix_error_fmt("%san empty %s expression in a for loop", "POSIX does not allow ", msg);
}
+#endif
static int bc_error_bad_character(char c)
{
return bc_error_fmt("bad character '%c'", c);
}
}
+static void bc_vec_pop(BcVec *v)
+{
+ v->len--;
+ if (v->dtor)
+ v->dtor(v->v + (v->size * v->len));
+}
+
static void bc_vec_npop(BcVec *v, size_t n)
{
if (!v->dtor)
len = v->len + strlen(str);
if (v->cap < len) bc_vec_grow(v, len - v->len);
- strcat(v->v, str);
+ strcpy(v->v + v->len - 1, str);
v->len = len;
}
return v->v + v->size * (v->len - idx - 1);
}
+static void *bc_vec_top(const BcVec *v)
+{
+ return v->v + v->size * (v->len - 1);
+}
+
static void bc_vec_free(void *vec)
{
BcVec *v = (BcVec *) vec;
return 1; // "was inserted"
}
+#if ENABLE_BC
static size_t bc_map_index(const BcVec *v, const void *ptr)
{
size_t i = bc_map_find(v, ptr);
if (i >= v->len) return BC_VEC_INVALID_IDX;
return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
}
+#endif
+
+static int push_input_byte(BcVec *vec, char c)
+{
+ if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
+ || c > 0x7e
+ ) {
+ // Bad chars on this line, ignore entire line
+ bc_error_fmt("illegal character 0x%02x", c);
+ return 1;
+ }
+ bc_vec_pushByte(vec, (char)c);
+ return 0;
+}
static BcStatus bc_read_line(BcVec *vec, const char *prompt)
{
bool bad_chars;
+ if (G_posix) prompt = "";
+
do {
- int i;
+ int c;
bad_chars = 0;
bc_vec_pop_all(vec);
fflush_and_check();
+
#if ENABLE_FEATURE_BC_SIGNALS
if (bb_got_signal) { // ^C was pressed
intr:
: "\ninterrupt (type \"q\" to exit)\n"
, stderr);
}
+# if ENABLE_FEATURE_EDITING
+ if (G_ttyin) {
+ int n, i;
+# define line_buf bb_common_bufsiz1
+ n = read_line_input(G.line_input_state, prompt, line_buf, COMMON_BUFSIZE);
+ if (n <= 0) { // read errors or EOF, or ^D, or ^C
+ if (n == 0) // ^C
+ goto intr;
+ G.eof = 1;
+ break;
+ }
+ i = 0;
+ for (;;) {
+ c = line_buf[i++];
+ if (!c) break;
+ bad_chars |= push_input_byte(vec, c);
+ }
+# undef line_buf
+ } else
+# endif
#endif
- if (G.ttyin && !G_posix)
- fputs(prompt, stderr);
-
-#if ENABLE_FEATURE_BC_SIGNALS
- errno = 0;
-#endif
- do {
- i = fgetc(stdin);
- if (i == EOF) {
-#if ENABLE_FEATURE_BC_SIGNALS
+ {
+ if (G_ttyin)
+ fputs(prompt, stderr);
+ IF_FEATURE_BC_SIGNALS(errno = 0;)
+ do {
+ c = fgetc(stdin);
+#if ENABLE_FEATURE_BC_SIGNALS && !ENABLE_FEATURE_EDITING
// Both conditions appear simultaneously, check both just in case
if (errno == EINTR || bb_got_signal) {
// ^C was pressed
goto intr;
}
#endif
- if (ferror(stdin))
- quit(); // this emits error message
- G.eof = 1;
- // Note: EOF does not append '\n', therefore:
- // printf 'print 123\n' | bc - works
- // printf 'print 123' | bc - fails (syntax error)
- break;
- }
-
- if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
- || i > 0x7e
- ) {
- // Bad chars on this line, ignore entire line
- bc_error_fmt("illegal character 0x%02x", i);
- bad_chars = 1;
- }
- bc_vec_pushByte(vec, (char)i);
- } while (i != '\n');
+ if (c == EOF) {
+ if (ferror(stdin))
+ quit(); // this emits error message
+ G.eof = 1;
+ // Note: EOF does not append '\n', therefore:
+ // printf 'print 123\n' | bc - works
+ // printf 'print 123' | bc - fails (syntax error)
+ break;
+ }
+ bad_chars |= push_input_byte(vec, c);
+ } while (c != '\n');
+ }
} while (bad_chars);
bc_vec_pushZeroByte(vec);
size_t size = ((size_t) -1);
size_t i;
- buf = xmalloc_open_read_close(path, &size);
+ // Never returns NULL (dies on errors)
+ buf = xmalloc_xopen_read_close(path, &size);
for (i = 0; i < size; ++i) {
char c = buf[i];
}
#endif // ENABLE_DC
+#if ENABLE_BC
static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
{
BcId a;
return BC_STATUS_SUCCESS;
}
+#endif
static void bc_func_init(BcFunc *f)
{
match:
// buf starts with keyword bc_lex_kws[i]
l->t.t = BC_LEX_KEY_1st_keyword + i;
- if (!((1 << i) & POSIX_KWORD_MASK)) {
+ if (!bc_lex_kws_POSIX(i)) {
s = bc_posix_error_fmt("%sthe '%.8s' keyword", "POSIX does not allow ", bc_lex_kws[i].name8);
if (s) return s;
}
}
else {
bc_vec_pop_all(&l->t.v);
- bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
+ bc_vec_push(&l->t.v, &l->buf[l->i - 1]);
bc_vec_pushZeroByte(&l->t.v);
l->t.t = BC_LEX_NAME;
}
}
#endif // ENABLE_DC
+static void bc_program_addFunc(char *name, size_t *idx);
+
static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
{
bc_program_addFunc(name, idx);
p->func = bc_vec_item(&G.prog.fns, p->fidx);
}
+#define bc_parse_push(p, i) bc_vec_pushByte(&(p)->func->code, (char) (i))
+
static void bc_parse_pushName(BcParse *p, char *name)
{
size_t i = 0, len = strlen(name);
return bc_lex_text(&p->l, text);
}
+// Called when parsing or execution detects a failure,
+// resets execution structures.
+static void bc_program_reset(void)
+{
+ BcFunc *f;
+ BcInstPtr *ip;
+
+ bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
+ bc_vec_pop_all(&G.prog.results);
+
+ f = bc_vec_item(&G.prog.fns, 0);
+ ip = bc_vec_top(&G.prog.stack);
+ ip->idx = f->code.len;
+}
+
+#define bc_parse_updateFunc(p, f) \
+ ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
+
// Called when bc/dc_parse_parse() detects a failure,
// resets parsing structures.
static void bc_parse_reset(BcParse *p)
if (s) return s;
if (!paren || p->l.t.last != BC_LEX_RPAREN) {
- s = bc_posix_error("POSIX requires parentheses around return expressions");
+ s = bc_POSIX_requires("parentheses around return expressions");
if (s) return s;
}
if (s) return s;
if (p->l.t.t != BC_LEX_LBRACE)
- s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
+ s = bc_POSIX_requires("the left brace be on the same line as the function header");
return s;
if (s) return s;
}
else if ((flags & BC_PARSE_REL) && nrelops > 1) {
- s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
+ s = bc_POSIX_requires("exactly one comparison operator per condition");
if (s) return s;
}
static void common_parse_init(BcParse *p, size_t func)
{
if (IS_BC) {
- bc_parse_init(p, func);
+ IF_BC(bc_parse_init(p, func);)
} else {
- dc_parse_init(p, func);
+ IF_DC(dc_parse_init(p, func);)
}
}
static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
{
if (IS_BC) {
- return bc_parse_expression(p, flags);
+ IF_BC(return bc_parse_expression(p, flags);)
} else {
- return dc_parse_expr(p, flags);
+ IF_DC(return dc_parse_expr(p, flags);)
}
}
}
}
-// Called when parsing or execution detects a failure,
-// resets execution structures.
-static void bc_program_reset(void)
-{
- BcFunc *f;
- BcInstPtr *ip;
-
- bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
- bc_vec_pop_all(&G.prog.results);
-
- f = bc_vec_item(&G.prog.fns, 0);
- ip = bc_vec_top(&G.prog.stack);
- ip->idx = f->code.len;
-
- // If !tty, no need to check for ^C: we don't have ^C handler,
- // we would be killed by a signal and won't reach this place
-}
-
static BcStatus bc_program_exec(void)
{
BcStatus s = BC_STATUS_SUCCESS;
bc_vec_concat(&buffer, buf.v);
s = bc_vm_process(buffer.v);
if (s) {
- if (ENABLE_FEATURE_CLEAN_UP && !G.ttyin) {
+ 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.
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) {
+ 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.
{
bc_vec_init(&G.files, sizeof(char *), NULL);
if (IS_BC)
- bc_vm_envArgs();
+ IF_BC(bc_vm_envArgs();)
bc_program_init();
if (IS_BC) {
- bc_parse_init(&G.prs, BC_PROG_MAIN);
+ IF_BC(bc_parse_init(&G.prs, BC_PROG_MAIN);)
} else {
- dc_parse_init(&G.prs, BC_PROG_MAIN);
+ IF_DC(dc_parse_init(&G.prs, BC_PROG_MAIN);)
}
}
{
BcStatus st;
+#if ENABLE_FEATURE_EDITING
+ G.line_input_state = new_line_input_t(DO_HISTORY);
+#endif
G.prog.len = bc_vm_envLen(env_len);
bc_vm_init();
bc_args(argv);
- G.ttyin = isatty(0);
- if (G.ttyin) {
+ if (isatty(0)) {
#if ENABLE_FEATURE_BC_SIGNALS
+ G_ttyin = 1;
// With SA_RESTART, most system calls will restart
// (IOW: they won't fail with EINTR).
// In particular, this means ^C won't cause
#if ENABLE_FEATURE_CLEAN_UP
bc_vm_free();
+# if ENABLE_FEATURE_EDITING
+ free_line_input_t(G.line_input_state);
+# endif
FREE_G();
#endif
return st;
return bc_vm_run(argv, "DC_LINE_LENGTH");
}
#endif
+
+#endif // not DC_SMALL