2 * *****************************************************************************
4 * SPDX-License-Identifier: BSD-2-Clause
6 * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
30 * *****************************************************************************
32 * Code common to all of bc and dc.
49 #include <sys/types.h>
54 #define WIN32_LEAN_AND_MEAN
67 // The actual globals.
68 static BcDig* temps_buf[BC_VM_MAX_TEMPS];
69 char output_bufs[BC_VM_BUF_SIZE];
74 bc_vm_jmp(const char* f)
76 #else // BC_DEBUG_CODE
87 bc_file_puts(&vm.ferr, bc_flush_none, "Longjmp: ");
88 bc_file_puts(&vm.ferr, bc_flush_none, f);
89 bc_file_putchar(&vm.ferr, bc_flush_none, '\n');
90 bc_file_flush(&vm.ferr, bc_flush_none);
91 #endif // BC_DEBUG_CODE
94 assert(vm.jmp_bufs.len - (size_t) vm.sig_pop);
97 if (vm.jmp_bufs.len == 0) abort();
98 if (vm.sig_pop) bc_vec_pop(&vm.jmp_bufs);
101 siglongjmp(*((sigjmp_buf*) bc_vec_top(&vm.jmp_bufs)), 1);
104 #if !BC_ENABLE_LIBRARY
107 * Handles signals. This is the signal handler.
108 * @param sig The signal to handle.
113 // There is already a signal in flight.
114 if (vm.status == (sig_atomic_t) BC_STATUS_QUIT || vm.sig)
116 if (!BC_I || sig != SIGINT) vm.status = BC_STATUS_QUIT;
120 #if BC_ENABLE_EDITLINE
121 // Editline needs this to resize the terminal.
124 el_resize(vm.history.el);
127 #endif // BC_ENABLE_EDITLINE
129 // Only reset under these conditions; otherwise, quit.
130 if (sig == SIGINT && BC_SIGINT && BC_I)
134 #if BC_ENABLE_EDITLINE
135 // Editline needs this, for some unknown reason.
136 if (write(STDOUT_FILENO, "^C", 2) != (ssize_t) 2)
138 vm.status = BC_STATUS_ERROR_FATAL;
140 #endif // BC_ENABLE_EDITLINE
142 // Write the message.
143 if (write(STDOUT_FILENO, vm.sigmsg, vm.siglen) != (ssize_t) vm.siglen)
145 vm.status = BC_STATUS_ERROR_FATAL;
153 #if BC_ENABLE_EDITLINE
154 if (write(STDOUT_FILENO, "^C", 2) != (ssize_t) 2)
156 vm.status = BC_STATUS_ERROR_FATAL;
159 #endif // BC_ENABLE_EDITLINE
161 vm.status = BC_STATUS_QUIT;
164 #if BC_ENABLE_LINE_LIB
165 // Readline and Editline need this to actually handle sigints correctly.
166 if (sig == SIGINT && bc_history_inlinelib)
168 bc_history_inlinelib = 0;
169 siglongjmp(bc_history_jmpbuf, 1);
171 #endif // BC_ENABLE_LINE_LIB
173 assert(vm.jmp_bufs.len);
175 // Only jump if signals are not locked. The jump will happen by whoever
177 if (!vm.sig_lock) BC_JMP;
181 * Sets up signal handling.
184 bc_vm_sigaction(void)
190 sigemptyset(&sa.sa_mask);
191 sa.sa_handler = bc_vm_sig;
192 sa.sa_flags = SA_NODEFER;
194 sigaction(SIGTERM, &sa, NULL);
195 sigaction(SIGQUIT, &sa, NULL);
196 sigaction(SIGINT, &sa, NULL);
198 #if BC_ENABLE_EDITLINE
199 // Editline needs this to resize the terminal.
200 sigaction(SIGWINCH, &sa, NULL);
201 #endif // BC_ENABLE_EDITLINE
203 #if BC_ENABLE_HISTORY
204 if (BC_TTY) sigaction(SIGHUP, &sa, NULL);
205 #endif // BC_ENABLE_HISTORY
209 signal(SIGTERM, bc_vm_sig);
210 signal(SIGINT, bc_vm_sig);
216 bc_vm_info(const char* const help)
218 BC_SIG_ASSERT_LOCKED;
221 bc_file_printf(&vm.fout, "%s %s\n%s", vm.name, BC_VERSION, bc_copyright);
226 bc_file_putchar(&vm.fout, bc_flush_none, '\n');
231 const char* const banner = BC_DEFAULT_BANNER ? "to" : "to not";
232 const char* const sigint = BC_DEFAULT_SIGINT_RESET ? "to reset" :
234 const char* const tty = BC_DEFAULT_TTY_MODE ? "enabled" :
236 const char* const prompt = BC_DEFAULT_PROMPT ? "enabled" :
238 const char* const expr = BC_DEFAULT_EXPR_EXIT ? "to exit" :
241 bc_file_printf(&vm.fout, help, vm.name, vm.name, BC_VERSION,
242 BC_BUILD_TYPE, banner, sigint, tty, prompt, expr);
249 const char* const sigint = DC_DEFAULT_SIGINT_RESET ? "to reset" :
251 const char* const tty = DC_DEFAULT_TTY_MODE ? "enabled" :
253 const char* const prompt = DC_DEFAULT_PROMPT ? "enabled" :
255 const char* const expr = DC_DEFAULT_EXPR_EXIT ? "to exit" :
258 bc_file_printf(&vm.fout, help, vm.name, vm.name, BC_VERSION,
259 BC_BUILD_TYPE, sigint, tty, prompt, expr);
265 bc_file_flush(&vm.fout, bc_flush_none);
267 #endif // !BC_ENABLE_LIBRARY
269 #if !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK
271 #endif // !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK
273 bc_vm_fatalError(BcErr e)
276 #if !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK
279 #endif // !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK
282 #if BC_ENABLE_LIBRARY
284 bc_vm_handleError(BcErr e)
286 assert(e < BC_ERR_NELEMS);
291 // If we have a normal error...
292 if (e <= BC_ERR_MATH_DIVIDE_BY_ZERO)
295 vm.err = (BclError) (e - BC_ERR_MATH_NEGATIVE +
296 BCL_ERROR_MATH_NEGATIVE);
298 // Abort if we should.
299 else if (vm.abrt) abort();
300 else if (e == BC_ERR_FATAL_ALLOC_ERR) vm.err = BCL_ERROR_FATAL_ALLOC_ERR;
301 else vm.err = BCL_ERROR_FATAL_UNKNOWN_ERR;
305 #else // BC_ENABLE_LIBRARY
307 bc_vm_handleError(BcErr e, size_t line, ...)
311 uchar id = bc_err_ids[e];
312 const char* err_type = vm.err_ids[id];
315 assert(e < BC_ERR_NELEMS);
319 // Figure out if the POSIX error should be an error, a warning, or nothing.
320 if (!BC_S && e >= BC_ERR_POSIX_START)
324 // Make sure to not return an error.
326 err_type = vm.err_ids[BC_ERR_IDX_WARN];
332 BC_SIG_TRYLOCK(lock);
334 // Make sure all of stdout is written first.
335 s = bc_file_flushErr(&vm.fout, bc_flush_err);
337 // Just jump out if the flush failed; there's nothing we can do.
338 if (BC_ERR(s == BC_STATUS_ERROR_FATAL))
340 vm.status = (sig_atomic_t) s;
344 // Print the error message.
345 va_start(args, line);
346 bc_file_putchar(&vm.ferr, bc_flush_none, '\n');
347 bc_file_puts(&vm.ferr, bc_flush_none, err_type);
348 bc_file_putchar(&vm.ferr, bc_flush_none, ' ');
349 bc_file_vprintf(&vm.ferr, vm.err_msgs[e], args);
352 // Print the extra information if we have it.
353 if (BC_NO_ERR(vm.file != NULL))
355 // This is the condition for parsing vs runtime.
356 // If line is not 0, it is parsing.
359 bc_file_puts(&vm.ferr, bc_flush_none, "\n ");
360 bc_file_puts(&vm.ferr, bc_flush_none, vm.file);
361 bc_file_printf(&vm.ferr, bc_err_line, line);
365 BcInstPtr* ip = bc_vec_item_rev(&vm.prog.stack, 0);
366 BcFunc* f = bc_vec_item(&vm.prog.fns, ip->func);
368 bc_file_puts(&vm.ferr, bc_flush_none, "\n ");
369 bc_file_puts(&vm.ferr, bc_flush_none, vm.func_header);
370 bc_file_putchar(&vm.ferr, bc_flush_none, ' ');
371 bc_file_puts(&vm.ferr, bc_flush_none, f->name);
374 if (BC_IS_BC && ip->func != BC_PROG_MAIN &&
375 ip->func != BC_PROG_READ)
377 bc_file_puts(&vm.ferr, bc_flush_none, "()");
383 bc_file_puts(&vm.ferr, bc_flush_none, "\n\n");
385 s = bc_file_flushErr(&vm.ferr, bc_flush_err);
387 #if !BC_ENABLE_MEMCHECK
388 // Because this function is called by a BC_NORETURN function when fatal
389 // errors happen, we need to make sure to exit on fatal errors. This will
390 // be faster anyway. This function *cannot jump when a fatal error occurs!*
391 if (BC_ERR(id == BC_ERR_IDX_FATAL || s == BC_STATUS_ERROR_FATAL))
393 exit(bc_vm_atexit((int) BC_STATUS_ERROR_FATAL));
395 #else // !BC_ENABLE_MEMCHECK
396 if (BC_ERR(s == BC_STATUS_ERROR_FATAL)) vm.status = (sig_atomic_t) s;
398 #endif // !BC_ENABLE_MEMCHECK
400 vm.status = (sig_atomic_t) (uchar) (id + 1);
403 // Only jump if there is an error.
404 if (BC_ERR(vm.status)) BC_JMP;
406 BC_SIG_TRYUNLOCK(lock);
410 bc_vm_getenv(const char* var)
417 _dupenv_s(&ret, NULL, var);
424 bc_vm_getenvFree(char* val)
433 * Sets a flag from an environment variable and the default.
434 * @param var The environment variable.
435 * @param def The default.
436 * @param flag The flag to set.
439 bc_vm_setenvFlag(const char* const var, int def, uint16_t flag)
442 char* val = bc_vm_getenv(var);
444 // If there is no value...
448 if (def) vm.flags |= flag;
449 else vm.flags &= ~(flag);
452 else if (strtoul(val, NULL, 0)) vm.flags |= flag;
453 else vm.flags &= ~(flag);
455 bc_vm_getenvFree(val);
459 * Parses the arguments in {B,D]C_ENV_ARGS.
460 * @param env_args_name The environment variable to use.
463 bc_vm_envArgs(const char* const env_args_name)
465 char *env_args = bc_vm_getenv(env_args_name), *buf, *start;
468 BC_SIG_ASSERT_LOCKED;
470 if (env_args == NULL) return;
472 // Windows already allocates, so we don't need to.
474 start = buf = vm.env_args_buffer = bc_vm_strdup(env_args);
476 start = buf = vm.env_args_buffer = env_args;
481 // Create two buffers for parsing. These need to stay throughout the entire
482 // execution of bc, unfortunately, because of filenames that might be in
484 bc_vec_init(&vm.env_args, sizeof(char*), BC_DTOR_NONE);
485 bc_vec_push(&vm.env_args, &env_args_name);
487 // While we haven't reached the end of the args...
490 // If we don't have whitespace...
493 // If we have the start of a string...
494 if (*buf == '"' || *buf == '\'')
496 // Set stuff appropriately.
500 // Check for the empty string.
509 // Push the pointer to the args buffer.
510 bc_vec_push(&vm.env_args, &buf);
514 ((!instr && !isspace(*buf)) || (instr && *buf != instr)))
519 // If we did find the end of the string...
522 if (instr) instr = '\0';
529 else if (instr) bc_error(BC_ERR_FATAL_OPTION, 0, start);
531 // If we have whitespace, eat it.
535 // Make sure to push a NULL pointer at the end.
537 bc_vec_push(&vm.env_args, &buf);
539 // Parse the arguments.
540 bc_args((int) vm.env_args.len - 1, bc_vec_item(&vm.env_args, 0), false,
541 BC_PROG_SCALE(&vm.prog));
545 * Gets the {B,D}C_LINE_LENGTH.
546 * @param var The environment variable to pull it from.
547 * @return The line length.
550 bc_vm_envLen(const char* var)
552 char* lenv = bc_vm_getenv(var);
553 size_t i, len = BC_NUM_PRINT_WIDTH;
556 // Return the default with none.
557 if (lenv == NULL) return len;
561 // Figure out if it's a number.
562 for (num = 1, i = 0; num && i < len; ++i)
564 num = isdigit(lenv[i]);
567 // If it is a number...
570 // Parse it and clamp it if needed.
571 len = (size_t) atoi(lenv) - 1;
572 if (len == 1 || len >= UINT16_MAX) len = BC_NUM_PRINT_WIDTH;
575 else len = BC_NUM_PRINT_WIDTH;
577 bc_vm_getenvFree(lenv);
581 #endif // BC_ENABLE_LIBRARY
586 BC_SIG_ASSERT_LOCKED;
589 if (vm.catalog != BC_VM_INVALID_CATALOG) catclose(vm.catalog);
590 #endif // BC_ENABLE_NLS
592 #if BC_ENABLE_HISTORY
593 // This must always run to ensure that the terminal is back to normal, i.e.,
594 // has raw mode disabled. But we should only do it if we did not have a bad
595 // terminal because history was not initialized if it is a bad terminal.
596 if (BC_TTY && !vm.history.badTerm) bc_history_free(&vm.history);
597 #endif // BC_ENABLE_HISTORY
600 #if !BC_ENABLE_LIBRARY
601 bc_vec_free(&vm.env_args);
602 free(vm.env_args_buffer);
603 bc_vec_free(&vm.files);
604 bc_vec_free(&vm.exprs);
606 if (BC_PARSE_IS_INITED(&vm.read_prs, &vm.prog))
608 bc_vec_free(&vm.read_buf);
609 bc_parse_free(&vm.read_prs);
612 bc_parse_free(&vm.prs);
613 bc_program_free(&vm.prog);
615 bc_slabvec_free(&vm.other_slabs);
616 bc_slabvec_free(&vm.main_slabs);
617 bc_slabvec_free(&vm.main_const_slab);
618 #endif // !BC_ENABLE_LIBRARY
623 #if !BC_ENABLE_LIBRARY
624 // We always want to flush.
625 bc_file_free(&vm.fout);
626 bc_file_free(&vm.ferr);
627 #endif // !BC_ENABLE_LIBRARY
631 bc_vm_addTemp(BcDig* num)
633 BC_SIG_ASSERT_LOCKED;
635 // If we don't have room, just free.
636 if (vm.temps_len == BC_VM_MAX_TEMPS) free(num);
639 // Add to the buffer and length.
640 temps_buf[vm.temps_len] = num;
648 BC_SIG_ASSERT_LOCKED;
650 if (!vm.temps_len) return NULL;
654 return temps_buf[vm.temps_len];
658 bc_vm_freeTemps(void)
662 BC_SIG_ASSERT_LOCKED;
664 if (!vm.temps_len) return;
667 for (i = 0; i < vm.temps_len; ++i)
676 bc_vm_arraySize(size_t n, size_t size)
678 size_t res = n * size;
679 if (BC_ERR(BC_VM_MUL_OVERFLOW(n, size, res)))
681 bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR);
687 bc_vm_growSize(size_t a, size_t b)
690 if (BC_ERR(res >= SIZE_MAX || res < a))
692 bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR);
698 bc_vm_malloc(size_t n)
702 BC_SIG_ASSERT_LOCKED;
706 if (BC_ERR(ptr == NULL))
712 if (BC_ERR(ptr == NULL)) bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR);
719 bc_vm_realloc(void* ptr, size_t n)
723 BC_SIG_ASSERT_LOCKED;
725 temp = realloc(ptr, n);
727 if (BC_ERR(temp == NULL))
731 temp = realloc(ptr, n);
733 if (BC_ERR(temp == NULL)) bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR);
740 bc_vm_strdup(const char* str)
744 BC_SIG_ASSERT_LOCKED;
748 if (BC_ERR(s == NULL))
754 if (BC_ERR(s == NULL)) bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR);
760 #if !BC_ENABLE_LIBRARY
762 bc_vm_printf(const char* fmt, ...)
767 BC_SIG_TRYLOCK(lock);
770 bc_file_vprintf(&vm.fout, fmt, args);
775 BC_SIG_TRYUNLOCK(lock);
777 #endif // !BC_ENABLE_LIBRARY
780 bc_vm_putchar(int c, BcFlushType type)
782 #if BC_ENABLE_LIBRARY
783 bc_vec_pushByte(&vm.out, (uchar) c);
784 #else // BC_ENABLE_LIBRARY
785 bc_file_putchar(&vm.fout, type, (uchar) c);
786 vm.nchars = (c == '\n' ? 0 : vm.nchars + 1);
787 #endif // BC_ENABLE_LIBRARY
790 #if !BC_ENABLE_LIBRARY
795 * Aborts with a message. This should never be called because I have carefully
796 * made sure that the calls to pledge() and unveil() are correct, but it's here
798 * @param msg The message to print.
800 BC_NORETURN static void
801 bc_abortm(const char* msg)
803 bc_file_puts(&vm.ferr, bc_flush_none, msg);
804 bc_file_puts(&vm.ferr, bc_flush_none, "; this is a bug");
805 bc_file_flush(&vm.ferr, bc_flush_none);
810 bc_pledge(const char* promises, const char* execpromises)
812 int r = pledge(promises, execpromises);
813 if (r) bc_abortm("pledge() failed");
816 #if BC_ENABLE_EXTRA_MATH
819 * A convenience and portability function for OpenBSD's unveil().
820 * @param path The path.
821 * @param permissions The permissions for the path.
824 bc_unveil(const char* path, const char* permissions)
826 int r = unveil(path, permissions);
827 if (r) bc_abortm("unveil() failed");
829 #endif // BC_ENABLE_EXTRA_MATH
834 bc_pledge(const char* promises, const char* execpromises)
837 BC_UNUSED(execpromises);
840 #if BC_ENABLE_EXTRA_MATH
842 bc_unveil(const char* path, const char* permissions)
845 BC_UNUSED(permissions);
847 #endif // BC_ENABLE_EXTRA_MATH
849 #endif // __OpenBSD__
852 * Cleans unneeded variables, arrays, functions, strings, and constants when
853 * done executing a line of stdin. This is to prevent memory usage growing
854 * without bound. This is an idea from busybox.
859 BcVec* fns = &vm.prog.fns;
860 BcFunc* f = bc_vec_item(fns, BC_PROG_MAIN);
861 BcInstPtr* ip = bc_vec_item(&vm.prog.stack, 0);
862 bool good = ((vm.status && vm.status != BC_STATUS_QUIT) || vm.sig);
864 BC_SIG_ASSERT_LOCKED;
866 // If all is good, go ahead and reset.
867 if (good) bc_program_reset(&vm.prog);
870 // bc has this extra condition. If it not satisfied, it is in the middle of
872 if (good && BC_IS_BC) good = !BC_PARSE_NO_EXEC(&vm.prs);
876 // For dc, it is safe only when all of the results on the results stack are
877 // safe, which means that they are temporaries or other things that don't
878 // need strings or constants.
885 for (i = 0; good && i < vm.prog.results.len; ++i)
887 BcResult* r = (BcResult*) bc_vec_item(&vm.prog.results, i);
888 good = BC_VM_SAFE_RESULT(r);
893 // If this condition is true, we can get rid of strings,
894 // constants, and code.
895 if (good && vm.prog.stack.len == 1 && ip->idx == f->code.len)
900 bc_vec_popAll(&f->labels);
901 bc_vec_popAll(&f->strs);
902 bc_vec_popAll(&f->consts);
904 // I can't clear out the other_slabs because it has functions,
905 // consts, strings, vars, and arrays. It has strings from *other*
906 // functions, specifically.
907 bc_slabvec_clear(&vm.main_const_slab);
908 bc_slabvec_clear(&vm.main_slabs);
913 // Note to self: you cannot delete strings and functions. Deal with it.
916 bc_vec_popAll(vm.prog.consts);
917 bc_slabvec_clear(&vm.main_const_slab);
921 bc_vec_popAll(&f->code);
928 * Process a bunch of text.
929 * @param text The text to process.
930 * @param is_stdin True if the text came from stdin, false otherwise.
931 * @param is_exprs True if the text is from command-line expressions, false
935 bc_vm_process(const char* text, bool is_stdin, bool is_exprs)
937 // Set up the parser.
938 bc_parse_text(&vm.prs, text, is_stdin, is_exprs);
945 // If the first token is the keyword define, then we need to do this
946 // specially because bc thinks it may not be able to parse.
947 if (vm.prs.l.t == BC_LEX_KW_DEFINE) vm.parse(&vm.prs);
951 while (BC_PARSE_CAN_PARSE(vm.prs))
958 // Execute if possible.
959 if (BC_IS_DC || !BC_PARSE_NO_EXEC(&vm.prs)) bc_program_exec(&vm.prog);
961 assert(BC_IS_DC || vm.prog.results.len == 0);
963 // Flush in interactive mode.
964 if (BC_I) bc_file_flush(&vm.fout, bc_flush_save);
966 while (vm.prs.l.t != BC_LEX_EOF);
972 * Ends a series of if statements. This is to ensure that full parses happen
973 * when a file finishes or stdin has no more data. Without this, bc thinks that
974 * it cannot parse any further. But if we reach the end of a file or stdin has
975 * no more data, we know we can add an empty else clause.
980 bc_parse_endif(&vm.prs);
981 bc_program_exec(&vm.prog);
987 * @param file The filename.
990 bc_vm_file(const char* file)
997 bc_lex_file(&vm.prs.l, file);
1002 data = bc_read_file(file);
1004 assert(data != NULL);
1006 BC_SETJMP_LOCKED(err);
1011 bc_vm_process(data, false, false);
1014 // Make sure to end any open if statements.
1015 if (BC_IS_BC) bc_vm_endif();
1016 #endif // BC_ENABLED
1025 // bc_program_reset(), called by bc_vm_clean(), resets the status.
1026 // We want it to clear the sig_pop variable in case it was set.
1027 if (vm.status == (sig_atomic_t) BC_STATUS_SUCCESS) BC_LONGJMP_STOP;
1033 bc_vm_readLine(bool clear)
1038 BC_SIG_ASSERT_NOT_LOCKED;
1040 // Clear the buffer if desired.
1041 if (clear) bc_vec_empty(&vm.buffer);
1043 // Empty the line buffer.
1044 bc_vec_empty(&vm.line_buf);
1046 if (vm.eof) return false;
1050 // bc_read_line() must always return either BC_STATUS_SUCCESS or
1051 // BC_STATUS_EOF. Everything else, it and whatever it calls, must jump
1053 s = bc_read_line(&vm.line_buf, ">>> ");
1054 vm.eof = (s == BC_STATUS_EOF);
1056 while (!(s) && !vm.eof && vm.line_buf.len < 1);
1058 good = (vm.line_buf.len > 1);
1060 // Concat if we found something.
1061 if (good) bc_vec_concat(&vm.buffer, vm.line_buf.v);
1067 * Processes text from stdin.
1076 // Set up the lexer.
1077 bc_lex_file(&vm.prs.l, bc_program_stdin_name);
1079 // These are global so that the lexers can access them, but they are
1080 // allocated and freed in this function because they should only be used for
1081 // stdin and expressions (they are used in bc_vm_exprs() as well). So they
1082 // are tied to this function, really. Well, this and bc_vm_readLine(). These
1083 // are the reasons that we have vm.is_stdin to tell the lexers if we are
1084 // reading from stdin. Well, both lexers care. And the reason they care is
1085 // so that if a comment or a string goes across multiple lines, the lexer
1086 // can request more data from stdin until the comment or string is ended.
1088 bc_vec_init(&vm.buffer, sizeof(uchar), BC_DTOR_NONE);
1089 bc_vec_init(&vm.line_buf, sizeof(uchar), BC_DTOR_NONE);
1090 BC_SETJMP_LOCKED(err);
1093 // This label exists because errors can cause jumps to end up at the err label
1094 // below. If that happens, and the error should be cleared and execution
1095 // continue, then we need to jump back.
1098 // While we still read data from stdin.
1099 while (bc_vm_readLine(clear))
1101 size_t len = vm.buffer.len - 1;
1102 const char* str = vm.buffer.v;
1104 // We don't want to clear the buffer when the line ends with a backslash
1105 // because a backslash newline is special in bc.
1106 clear = (len < 2 || str[len - 2] != '\\' || str[len - 1] != '\n');
1107 if (!clear) continue;
1109 // Process the data.
1110 bc_vm_process(vm.buffer.v, true, false);
1122 // End the if statements.
1123 if (BC_IS_BC) bc_vm_endif();
1124 #endif // BC_ENABLED
1133 #if !BC_ENABLE_MEMCHECK
1134 assert(vm.status != BC_STATUS_ERROR_FATAL);
1136 vm.status = vm.status == BC_STATUS_QUIT || !BC_I ? vm.status :
1138 #else // !BC_ENABLE_MEMCHECK
1139 vm.status = vm.status == BC_STATUS_ERROR_FATAL ||
1140 vm.status == BC_STATUS_QUIT || !BC_I ?
1143 #endif // !BC_ENABLE_MEMCHECK
1145 if (!vm.status && !vm.eof)
1147 bc_vec_empty(&vm.buffer);
1154 // Since these are tied to this function, free them here. We only free in
1155 // debug mode because stdin is always the last thing read.
1156 bc_vec_free(&vm.line_buf);
1157 bc_vec_free(&vm.buffer);
1164 bc_vm_readBuf(bool clear)
1166 size_t len = vm.exprs.len - 1;
1169 BC_SIG_ASSERT_NOT_LOCKED;
1171 // Clear the buffer if desired.
1172 if (clear) bc_vec_empty(&vm.buffer);
1174 // We want to pop the nul byte off because that's what bc_read_buf()
1176 bc_vec_pop(&vm.buffer);
1178 // Read one line of expressions.
1179 more = bc_read_buf(&vm.buffer, vm.exprs.v, &len);
1180 bc_vec_pushByte(&vm.buffer, '\0');
1190 // Prepare the lexer.
1191 bc_lex_file(&vm.prs.l, bc_program_exprs_name);
1193 // We initialize this so that the lexer can access it in the case that it
1194 // needs more data for expressions, such as for a multiline string or
1195 // comment. See the comment on the allocation of vm.buffer above in
1196 // bc_vm_stdin() for more information.
1198 bc_vec_init(&vm.buffer, sizeof(uchar), BC_DTOR_NONE);
1199 BC_SETJMP_LOCKED(err);
1202 while (bc_vm_readBuf(clear))
1204 size_t len = vm.buffer.len - 1;
1205 const char* str = vm.buffer.v;
1207 // We don't want to clear the buffer when the line ends with a backslash
1208 // because a backslash newline is special in bc.
1209 clear = (len < 2 || str[len - 2] != '\\' || str[len - 1] != '\n');
1210 if (!clear) continue;
1212 // Process the data.
1213 bc_vm_process(vm.buffer.v, false, true);
1216 // If we were not supposed to clear, then we should process everything. This
1217 // makes sure that errors get reported.
1218 if (!clear) bc_vm_process(vm.buffer.v, false, true);
1227 // Since this is tied to this function, free it here. We always free it here
1228 // because bc_vm_stdin() may or may not use it later.
1229 bc_vec_free(&vm.buffer);
1237 * Loads a math library.
1238 * @param name The name of the library.
1239 * @param text The text of the source code.
1242 bc_vm_load(const char* name, const char* text)
1244 bc_lex_file(&vm.prs.l, name);
1245 bc_parse_text(&vm.prs, text, false, false);
1249 while (vm.prs.l.t != BC_LEX_EOF)
1257 #endif // BC_ENABLED
1260 * Loads the default error messages.
1263 bc_vm_defaultMsgs(void)
1267 vm.func_header = bc_err_func_header;
1269 // Load the error categories.
1270 for (i = 0; i < BC_ERR_IDX_NELEMS + BC_ENABLED; ++i)
1272 vm.err_ids[i] = bc_errs[i];
1275 // Load the error messages.
1276 for (i = 0; i < BC_ERR_NELEMS; ++i)
1278 vm.err_msgs[i] = bc_err_msgs[i];
1283 * Loads the error messages for the locale. If NLS is disabled, this just loads
1284 * the default messages.
1291 int set = 1, msg = 1;
1294 // If no locale, load the defaults.
1295 if (vm.locale == NULL)
1297 vm.catalog = BC_VM_INVALID_CATALOG;
1298 bc_vm_defaultMsgs();
1302 vm.catalog = catopen(BC_MAINEXEC, NL_CAT_LOCALE);
1304 // If no catalog, load the defaults.
1305 if (vm.catalog == BC_VM_INVALID_CATALOG)
1307 bc_vm_defaultMsgs();
1311 // Load the function header.
1312 vm.func_header = catgets(vm.catalog, set, msg, bc_err_func_header);
1314 // Load the error categories.
1315 for (set += 1; msg <= BC_ERR_IDX_NELEMS + BC_ENABLED; ++msg)
1317 vm.err_ids[msg - 1] = catgets(vm.catalog, set, msg, bc_errs[msg - 1]);
1323 // Load the error messages. In order to understand this loop, you must know
1324 // the order of messages and categories in the enum and in the locale files.
1325 for (set = id + 3, msg = 1; i < BC_ERR_NELEMS; ++i, ++msg)
1327 if (id != bc_err_ids[i])
1334 vm.err_msgs[i] = catgets(vm.catalog, set, msg, bc_err_msgs[i]);
1336 #else // BC_ENABLE_NLS
1337 bc_vm_defaultMsgs();
1338 #endif // BC_ENABLE_NLS
1342 * Starts execution. Really, this is a function of historical accident; it could
1343 * probably be combined with bc_vm_boot(), but I don't care enough. Really, this
1344 * function starts when execution of bc or dc source code starts.
1350 bool has_file = false;
1353 // Load the math libraries.
1354 if (BC_IS_BC && (vm.flags & BC_FLAG_L))
1356 // Can't allow redefinitions in the builtin library.
1357 vm.no_redefine = true;
1359 bc_vm_load(bc_lib_name, bc_lib);
1361 #if BC_ENABLE_EXTRA_MATH
1362 if (!BC_IS_POSIX) bc_vm_load(bc_lib2_name, bc_lib2);
1363 #endif // BC_ENABLE_EXTRA_MATH
1365 // Make sure to clear this.
1366 vm.no_redefine = false;
1368 // Execute to ensure that all is hunky dory. Without this, scale can be
1370 bc_program_exec(&vm.prog);
1372 #endif // BC_ENABLED
1374 // If there are expressions to execute...
1377 // Process the expressions.
1380 // Sometimes, executing expressions means we need to quit.
1381 if (!vm.no_exprs && vm.exit_exprs && BC_EXPR_EXIT) return;
1385 for (i = 0; i < vm.files.len; ++i)
1387 char* path = *((char**) bc_vec_item(&vm.files, i));
1388 if (!strcmp(path, "")) continue;
1393 #if BC_ENABLE_EXTRA_MATH
1394 // These are needed for the pseudo-random number generator.
1395 bc_unveil("/dev/urandom", "r");
1396 bc_unveil("/dev/random", "r");
1397 bc_unveil(NULL, NULL);
1398 #endif // BC_ENABLE_EXTRA_MATH
1400 #if BC_ENABLE_HISTORY
1402 // We need to keep tty if history is enabled, and we need to keep rpath for
1403 // the times when we read from /dev/urandom.
1404 if (BC_TTY && !vm.history.badTerm) bc_pledge(bc_pledge_end_history, NULL);
1406 #endif // BC_ENABLE_HISTORY
1408 bc_pledge(bc_pledge_end, NULL);
1412 // This is the thing that makes fuzzing with AFL++ so fast. If you move this
1413 // back, you won't cause any problems, but fuzzing will slow down. If you
1414 // move this forward, you won't fuzz anything because you will be skipping
1415 // the reading from stdin.
1417 #endif // BC_ENABLE_AFL
1419 // Execute from stdin. bc always does.
1420 if (BC_IS_BC || !has_file) bc_vm_stdin();
1424 bc_vm_boot(int argc, char* argv[])
1426 int ttyin, ttyout, ttyerr;
1428 const char* const env_len = BC_IS_BC ? "BC_LINE_LENGTH" : "DC_LINE_LENGTH";
1429 const char* const env_args = BC_IS_BC ? "BC_ENV_ARGS" : "DC_ENV_ARGS";
1430 const char* const env_exit = BC_IS_BC ? "BC_EXPR_EXIT" : "DC_EXPR_EXIT";
1431 int env_exit_def = BC_IS_BC ? BC_DEFAULT_EXPR_EXIT : DC_DEFAULT_EXPR_EXIT;
1433 // We need to know which of stdin, stdout, and stderr are tty's.
1434 ttyin = isatty(STDIN_FILENO);
1435 ttyout = isatty(STDOUT_FILENO);
1436 ttyerr = isatty(STDERR_FILENO);
1437 tty = (ttyin != 0 && ttyout != 0 && ttyerr != 0);
1439 vm.flags |= ttyin ? BC_FLAG_TTYIN : 0;
1440 vm.flags |= tty ? BC_FLAG_TTY : 0;
1441 vm.flags |= ttyin && ttyout ? BC_FLAG_I : 0;
1446 // Initialize some vm stuff. This is separate to make things easier for the
1450 // Explicitly set this in case NULL isn't all zeroes.
1453 // Set the error messages.
1456 #if BC_ENABLE_LINE_LIB
1457 // Initialize the output file buffers.
1458 bc_file_init(&vm.ferr, stderr);
1459 bc_file_init(&vm.fout, stdout);
1461 // Set the input buffer.
1462 vm.buf = output_bufs;
1464 #else // BC_ENABLE_LINE_LIB
1465 // Initialize the output file buffers. They each take portions of the global
1466 // buffer. stdout gets more because it will probably have more data.
1467 bc_file_init(&vm.ferr, STDERR_FILENO, output_bufs + BC_VM_STDOUT_BUF_SIZE,
1468 BC_VM_STDERR_BUF_SIZE);
1469 bc_file_init(&vm.fout, STDOUT_FILENO, output_bufs, BC_VM_STDOUT_BUF_SIZE);
1471 // Set the input buffer to the rest of the global buffer.
1472 vm.buf = output_bufs + BC_VM_STDOUT_BUF_SIZE + BC_VM_STDERR_BUF_SIZE;
1473 #endif // BC_ENABLE_LINE_LIB
1475 // Set the line length by environment variable.
1476 vm.line_len = (uint16_t) bc_vm_envLen(env_len);
1478 bc_vm_setenvFlag(env_exit, env_exit_def, BC_FLAG_EXPR_EXIT);
1480 // Clear the files and expressions vectors, just in case. This marks them as
1482 bc_vec_clear(&vm.files);
1483 bc_vec_clear(&vm.exprs);
1485 #if !BC_ENABLE_LIBRARY
1487 // Initialize the slab vectors.
1488 bc_slabvec_init(&vm.main_const_slab);
1489 bc_slabvec_init(&vm.main_slabs);
1490 bc_slabvec_init(&vm.other_slabs);
1492 #endif // !BC_ENABLE_LIBRARY
1494 // Initialize the program and main parser. These have to be in this order
1495 // because the program has to be initialized first, since a pointer to it is
1496 // passed to the parser.
1497 bc_program_init(&vm.prog);
1498 bc_parse_init(&vm.prs, &vm.prog, BC_PROG_MAIN);
1501 vm.flags |= BC_TTY ? BC_FLAG_P | BC_FLAG_R : 0;
1502 vm.flags |= BC_I ? BC_FLAG_Q : 0;
1507 // bc checks this environment variable to see if it should run in
1509 char* var = bc_vm_getenv("POSIXLY_CORRECT");
1511 vm.flags |= BC_FLAG_S * (var != NULL);
1512 bc_vm_getenvFree(var);
1514 // Set whether we print the banner or not.
1515 if (BC_I) bc_vm_setenvFlag("BC_BANNER", BC_DEFAULT_BANNER, BC_FLAG_Q);
1517 #endif // BC_ENABLED
1519 // Are we in TTY mode?
1522 const char* const env_tty = BC_IS_BC ? "BC_TTY_MODE" : "DC_TTY_MODE";
1523 int env_tty_def = BC_IS_BC ? BC_DEFAULT_TTY_MODE : DC_DEFAULT_TTY_MODE;
1524 const char* const env_prompt = BC_IS_BC ? "BC_PROMPT" : "DC_PROMPT";
1525 int env_prompt_def = BC_IS_BC ? BC_DEFAULT_PROMPT : DC_DEFAULT_PROMPT;
1527 // Set flags for TTY mode and prompt.
1528 bc_vm_setenvFlag(env_tty, env_tty_def, BC_FLAG_TTY);
1529 bc_vm_setenvFlag(env_prompt, tty ? env_prompt_def : 0, BC_FLAG_P);
1531 #if BC_ENABLE_HISTORY
1532 // If TTY mode is used, activate history.
1533 if (BC_TTY) bc_history_init(&vm.history);
1534 #endif // BC_ENABLE_HISTORY
1537 // Process environment and command-line arguments.
1538 bc_vm_envArgs(env_args);
1539 bc_args(argc, argv, true, BC_PROG_SCALE(&vm.prog));
1541 // If we are in interactive mode...
1544 const char* const env_sigint = BC_IS_BC ? "BC_SIGINT_RESET" :
1546 int env_sigint_def = BC_IS_BC ? BC_DEFAULT_SIGINT_RESET :
1547 DC_DEFAULT_SIGINT_RESET;
1549 // Set whether we reset on SIGINT or not.
1550 bc_vm_setenvFlag(env_sigint, env_sigint_def, BC_FLAG_SIGINT);
1554 // Disable global stacks in POSIX mode.
1555 if (BC_IS_POSIX) vm.flags &= ~(BC_FLAG_G);
1557 // Print the banner if allowed. We have to be in bc, in interactive mode,
1558 // and not be quieted by command-line option or environment variable.
1559 if (BC_IS_BC && BC_I && (vm.flags & BC_FLAG_Q))
1562 bc_file_putchar(&vm.fout, bc_flush_none, '\n');
1563 bc_file_flush(&vm.fout, bc_flush_none);
1565 #endif // BC_ENABLED
1572 #endif // !BC_ENABLE_LIBRARY
1577 BC_SIG_ASSERT_LOCKED;
1579 #if !BC_ENABLE_LIBRARY
1580 // Set up the constant zero.
1581 bc_num_setup(&vm.zero, vm.zero_num, BC_VM_ONE_CAP);
1582 #endif // !BC_ENABLE_LIBRARY
1584 // Set up more constant BcNum's.
1585 bc_num_setup(&vm.one, vm.one_num, BC_VM_ONE_CAP);
1586 bc_num_one(&vm.one);
1588 // Set up more constant BcNum's.
1590 memcpy(vm.max_num, bc_num_bigdigMax, bc_num_bigdigMax_size * sizeof(BcDig));
1592 memcpy(vm.max2_num, bc_num_bigdigMax2,
1593 bc_num_bigdigMax2_size * sizeof(BcDig));
1594 bc_num_setup(&vm.max, vm.max_num, BC_NUM_BIGDIG_LOG10);
1595 bc_num_setup(&vm.max2, vm.max2_num, BC_NUM_BIGDIG_LOG10);
1596 vm.max.len = bc_num_bigdigMax_size;
1597 vm.max2.len = bc_num_bigdigMax2_size;
1599 // Set up the maxes for the globals.
1600 vm.maxes[BC_PROG_GLOBALS_IBASE] = BC_NUM_MAX_POSIX_IBASE;
1601 vm.maxes[BC_PROG_GLOBALS_OBASE] = BC_MAX_OBASE;
1602 vm.maxes[BC_PROG_GLOBALS_SCALE] = BC_MAX_SCALE;
1604 #if BC_ENABLE_EXTRA_MATH
1605 vm.maxes[BC_PROG_MAX_RAND] = ((BcRand) 0) - 1;
1606 #endif // BC_ENABLE_EXTRA_MATH
1609 #if !BC_ENABLE_LIBRARY
1610 // bc has a higher max ibase when it's not in POSIX mode.
1611 if (BC_IS_BC && !BC_IS_POSIX)
1612 #endif // !BC_ENABLE_LIBRARY
1614 vm.maxes[BC_PROG_GLOBALS_IBASE] = BC_NUM_MAX_IBASE;
1616 #endif // BC_ENABLED
1619 #if BC_ENABLE_LIBRARY
1626 bc_vec_free(&vm.jmp_bufs);
1629 #else // BC_ENABLE_LIBRARY
1631 bc_vm_atexit(int status)
1633 // Set the status correctly.
1634 int s = BC_STATUS_IS_ERROR(status) ? status : BC_STATUS_SUCCESS;
1639 bc_vec_free(&vm.jmp_bufs);
1644 #endif // BC_ENABLE_LIBRARY