vm.c (78bc019d220e05abb5b12f678f9b4a847019bbcc) | vm.c (d101cdd6edd782f6ec56eef63ed91abd77a8b317) |
---|---|
1/* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * | 1/* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * |
6 * Copyright (c) 2018-2021 Gavin D. Howard and contributors. | 6 * Copyright (c) 2018-2023 Gavin D. Howard and contributors. |
7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 11 * * Redistributions of source code must retain the above copyright notice, this 12 * list of conditions and the following disclaimer. 13 * 14 * * Redistributions in binary form must reproduce the above copyright notice, --- 43 unchanged lines hidden (view full) --- 58#endif // _WIN32 59 60#include <status.h> 61#include <vector.h> 62#include <args.h> 63#include <vm.h> 64#include <read.h> 65#include <bc.h> | 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 11 * * Redistributions of source code must retain the above copyright notice, this 12 * list of conditions and the following disclaimer. 13 * 14 * * Redistributions in binary form must reproduce the above copyright notice, --- 43 unchanged lines hidden (view full) --- 58#endif // _WIN32 59 60#include <status.h> 61#include <vector.h> 62#include <args.h> 63#include <vm.h> 64#include <read.h> 65#include <bc.h> |
66#if BC_ENABLE_LIBRARY 67#include <library.h> 68#endif // BC_ENABLE_LIBRARY |
|
66 | 69 |
70#if !BC_ENABLE_LIBRARY 71 |
|
67// The actual globals. | 72// The actual globals. |
68static BcDig* temps_buf[BC_VM_MAX_TEMPS]; | |
69char output_bufs[BC_VM_BUF_SIZE]; | 73char output_bufs[BC_VM_BUF_SIZE]; |
70BcVm vm; | 74BcVm vm_data; 75BcVm* vm = &vm_data; |
71 | 76 |
77#endif // !BC_ENABLE_LIBRARY 78 |
|
72#if BC_DEBUG_CODE 73BC_NORETURN void 74bc_vm_jmp(const char* f) 75{ 76#else // BC_DEBUG_CODE 77BC_NORETURN void 78bc_vm_jmp(void) 79{ 80#endif 81 | 79#if BC_DEBUG_CODE 80BC_NORETURN void 81bc_vm_jmp(const char* f) 82{ 83#else // BC_DEBUG_CODE 84BC_NORETURN void 85bc_vm_jmp(void) 86{ 87#endif 88 |
82 assert(BC_SIG_EXC); | 89#if BC_ENABLE_LIBRARY 90 BcVm* vm = bcl_getspecific(); 91#endif // BC_ENABLE_LIBRARY |
83 | 92 |
93 assert(BC_SIG_EXC(vm)); 94 |
|
84 BC_SIG_MAYLOCK; 85 86#if BC_DEBUG_CODE | 95 BC_SIG_MAYLOCK; 96 97#if 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); | 98 bc_file_puts(&vm->ferr, bc_flush_none, "Longjmp: "); 99 bc_file_puts(&vm->ferr, bc_flush_none, f); 100 bc_file_putchar(&vm->ferr, bc_flush_none, '\n'); 101 bc_file_flush(&vm->ferr, bc_flush_none); |
91#endif // BC_DEBUG_CODE 92 93#ifndef NDEBUG | 102#endif // BC_DEBUG_CODE 103 104#ifndef NDEBUG |
94 assert(vm.jmp_bufs.len - (size_t) vm.sig_pop); | 105 assert(vm->jmp_bufs.len - (size_t) vm->sig_pop); |
95#endif // NDEBUG 96 | 106#endif // NDEBUG 107 |
97 if (vm.jmp_bufs.len == 0) abort(); 98 if (vm.sig_pop) bc_vec_pop(&vm.jmp_bufs); 99 else vm.sig_pop = 1; | 108 if (vm->jmp_bufs.len == 0) abort(); 109 if (vm->sig_pop) bc_vec_pop(&vm->jmp_bufs); 110 else vm->sig_pop = 1; |
100 | 111 |
101 siglongjmp(*((sigjmp_buf*) bc_vec_top(&vm.jmp_bufs)), 1); | 112 siglongjmp(*((sigjmp_buf*) bc_vec_top(&vm->jmp_bufs)), 1); |
102} 103 104#if !BC_ENABLE_LIBRARY 105 106/** 107 * Handles signals. This is the signal handler. 108 * @param sig The signal to handle. 109 */ 110static void 111bc_vm_sig(int sig) 112{ | 113} 114 115#if !BC_ENABLE_LIBRARY 116 117/** 118 * Handles signals. This is the signal handler. 119 * @param sig The signal to handle. 120 */ 121static void 122bc_vm_sig(int sig) 123{ |
113 // There is already a signal in flight. 114 if (vm.status == (sig_atomic_t) BC_STATUS_QUIT || vm.sig) | 124#if BC_ENABLE_EDITLINE 125 // Editline needs this to resize the terminal. This also needs to come first 126 // because a resize always needs to happen. 127 if (sig == SIGWINCH) |
115 { | 128 { |
116 if (!BC_I || sig != SIGINT) vm.status = BC_STATUS_QUIT; | 129 if (BC_TTY) 130 { 131 el_resize(vm->history.el); 132 133 // If the signal was a SIGWINCH, clear it because we don't need to 134 // print a stack trace in that case. 135 if (vm->sig == SIGWINCH) 136 { 137 vm->sig = 0; 138 } 139 } 140 |
117 return; 118 } | 141 return; 142 } |
143#endif // BC_ENABLE_EDITLINE |
|
119 | 144 |
120#if BC_ENABLE_EDITLINE 121 // Editline needs this to resize the terminal. 122 if (sig == SIGWINCH) | 145 // There is already a signal in flight if this is true. 146 if (vm->status == (sig_atomic_t) BC_STATUS_QUIT || vm->sig != 0) |
123 { | 147 { |
124 el_resize(vm.history.el); | 148 if (!BC_I || sig != SIGINT) vm->status = BC_STATUS_QUIT; |
125 return; 126 } | 149 return; 150 } |
127#endif // BC_ENABLE_EDITLINE | |
128 | 151 |
152 // We always want to set this because a stack trace can be printed if we do. 153 vm->sig = sig; 154 |
|
129 // Only reset under these conditions; otherwise, quit. 130 if (sig == SIGINT && BC_SIGINT && BC_I) 131 { 132 int err = errno; 133 134#if BC_ENABLE_EDITLINE 135 // Editline needs this, for some unknown reason. 136 if (write(STDOUT_FILENO, "^C", 2) != (ssize_t) 2) 137 { | 155 // Only reset under these conditions; otherwise, quit. 156 if (sig == SIGINT && BC_SIGINT && BC_I) 157 { 158 int err = errno; 159 160#if BC_ENABLE_EDITLINE 161 // Editline needs this, for some unknown reason. 162 if (write(STDOUT_FILENO, "^C", 2) != (ssize_t) 2) 163 { |
138 vm.status = BC_STATUS_ERROR_FATAL; | 164 vm->status = BC_STATUS_ERROR_FATAL; |
139 } 140#endif // BC_ENABLE_EDITLINE 141 142 // Write the message. | 165 } 166#endif // BC_ENABLE_EDITLINE 167 168 // Write the message. |
143 if (write(STDOUT_FILENO, vm.sigmsg, vm.siglen) != (ssize_t) vm.siglen) | 169 if (write(STDOUT_FILENO, vm->sigmsg, vm->siglen) != 170 (ssize_t) vm->siglen) |
144 { | 171 { |
145 vm.status = BC_STATUS_ERROR_FATAL; | 172 vm->status = BC_STATUS_ERROR_FATAL; |
146 } | 173 } |
147 else vm.sig = 1; | |
148 149 errno = err; 150 } 151 else 152 { 153#if BC_ENABLE_EDITLINE 154 if (write(STDOUT_FILENO, "^C", 2) != (ssize_t) 2) 155 { | 174 175 errno = err; 176 } 177 else 178 { 179#if BC_ENABLE_EDITLINE 180 if (write(STDOUT_FILENO, "^C", 2) != (ssize_t) 2) 181 { |
156 vm.status = BC_STATUS_ERROR_FATAL; | 182 vm->status = BC_STATUS_ERROR_FATAL; |
157 return; 158 } 159#endif // BC_ENABLE_EDITLINE 160 | 183 return; 184 } 185#endif // BC_ENABLE_EDITLINE 186 |
161 vm.status = BC_STATUS_QUIT; | 187 vm->status = BC_STATUS_QUIT; |
162 } 163 164#if BC_ENABLE_LINE_LIB 165 // Readline and Editline need this to actually handle sigints correctly. 166 if (sig == SIGINT && bc_history_inlinelib) 167 { 168 bc_history_inlinelib = 0; 169 siglongjmp(bc_history_jmpbuf, 1); 170 } 171#endif // BC_ENABLE_LINE_LIB 172 | 188 } 189 190#if BC_ENABLE_LINE_LIB 191 // Readline and Editline need this to actually handle sigints correctly. 192 if (sig == SIGINT && bc_history_inlinelib) 193 { 194 bc_history_inlinelib = 0; 195 siglongjmp(bc_history_jmpbuf, 1); 196 } 197#endif // BC_ENABLE_LINE_LIB 198 |
173 assert(vm.jmp_bufs.len); | 199 assert(vm->jmp_bufs.len); |
174 175 // Only jump if signals are not locked. The jump will happen by whoever 176 // unlocks signals. | 200 201 // Only jump if signals are not locked. The jump will happen by whoever 202 // unlocks signals. |
177 if (!vm.sig_lock) BC_JMP; | 203 if (!vm->sig_lock) BC_JMP; |
178} 179 180/** 181 * Sets up signal handling. 182 */ 183static void 184bc_vm_sigaction(void) 185{ 186#ifndef _WIN32 187 188 struct sigaction sa; 189 190 sigemptyset(&sa.sa_mask); | 204} 205 206/** 207 * Sets up signal handling. 208 */ 209static void 210bc_vm_sigaction(void) 211{ 212#ifndef _WIN32 213 214 struct sigaction sa; 215 216 sigemptyset(&sa.sa_mask); |
217 sa.sa_flags = 0; 218 219 // This mess is to silence a warning on Clang with regards to glibc's 220 // sigaction handler, which activates the warning here. 221#if BC_CLANG 222#pragma clang diagnostic ignored "-Wdisabled-macro-expansion" 223#endif // BC_CLANG |
|
191 sa.sa_handler = bc_vm_sig; | 224 sa.sa_handler = bc_vm_sig; |
192 sa.sa_flags = SA_NODEFER; | 225#if BC_CLANG 226#pragma clang diagnostic warning "-Wdisabled-macro-expansion" 227#endif // BC_CLANG |
193 194 sigaction(SIGTERM, &sa, NULL); 195 sigaction(SIGQUIT, &sa, NULL); 196 sigaction(SIGINT, &sa, NULL); 197 198#if BC_ENABLE_EDITLINE 199 // Editline needs this to resize the terminal. | 228 229 sigaction(SIGTERM, &sa, NULL); 230 sigaction(SIGQUIT, &sa, NULL); 231 sigaction(SIGINT, &sa, NULL); 232 233#if BC_ENABLE_EDITLINE 234 // Editline needs this to resize the terminal. |
200 sigaction(SIGWINCH, &sa, NULL); | 235 if (BC_TTY) sigaction(SIGWINCH, &sa, NULL); |
201#endif // BC_ENABLE_EDITLINE 202 203#if BC_ENABLE_HISTORY 204 if (BC_TTY) sigaction(SIGHUP, &sa, NULL); 205#endif // BC_ENABLE_HISTORY 206 207#else // _WIN32 208 --- 4 unchanged lines hidden (view full) --- 213} 214 215void 216bc_vm_info(const char* const help) 217{ 218 BC_SIG_ASSERT_LOCKED; 219 220 // Print the banner. | 236#endif // BC_ENABLE_EDITLINE 237 238#if BC_ENABLE_HISTORY 239 if (BC_TTY) sigaction(SIGHUP, &sa, NULL); 240#endif // BC_ENABLE_HISTORY 241 242#else // _WIN32 243 --- 4 unchanged lines hidden (view full) --- 248} 249 250void 251bc_vm_info(const char* const help) 252{ 253 BC_SIG_ASSERT_LOCKED; 254 255 // Print the banner. |
221 bc_file_printf(&vm.fout, "%s %s\n%s", vm.name, BC_VERSION, bc_copyright); | 256 bc_file_printf(&vm->fout, "%s %s\n%s", vm->name, BC_VERSION, bc_copyright); |
222 223 // Print the help. 224 if (help != NULL) 225 { | 257 258 // Print the help. 259 if (help != NULL) 260 { |
226 bc_file_putchar(&vm.fout, bc_flush_none, '\n'); | 261 bc_file_putchar(&vm->fout, bc_flush_none, '\n'); |
227 228#if BC_ENABLED 229 if (BC_IS_BC) 230 { 231 const char* const banner = BC_DEFAULT_BANNER ? "to" : "to not"; 232 const char* const sigint = BC_DEFAULT_SIGINT_RESET ? "to reset" : 233 "to exit"; 234 const char* const tty = BC_DEFAULT_TTY_MODE ? "enabled" : 235 "disabled"; 236 const char* const prompt = BC_DEFAULT_PROMPT ? "enabled" : 237 "disabled"; 238 const char* const expr = BC_DEFAULT_EXPR_EXIT ? "to exit" : 239 "to not exit"; | 262 263#if BC_ENABLED 264 if (BC_IS_BC) 265 { 266 const char* const banner = BC_DEFAULT_BANNER ? "to" : "to not"; 267 const char* const sigint = BC_DEFAULT_SIGINT_RESET ? "to reset" : 268 "to exit"; 269 const char* const tty = BC_DEFAULT_TTY_MODE ? "enabled" : 270 "disabled"; 271 const char* const prompt = BC_DEFAULT_PROMPT ? "enabled" : 272 "disabled"; 273 const char* const expr = BC_DEFAULT_EXPR_EXIT ? "to exit" : 274 "to not exit"; |
275 const char* const clamp = BC_DEFAULT_DIGIT_CLAMP ? "to clamp" : 276 "to not clamp"; |
|
240 | 277 |
241 bc_file_printf(&vm.fout, help, vm.name, vm.name, BC_VERSION, 242 BC_BUILD_TYPE, banner, sigint, tty, prompt, expr); | 278 bc_file_printf(&vm->fout, help, vm->name, vm->name, BC_VERSION, 279 BC_BUILD_TYPE, banner, sigint, tty, prompt, expr, 280 clamp); |
243 } 244#endif // BC_ENABLED 245 246#if DC_ENABLED 247 if (BC_IS_DC) 248 { 249 const char* const sigint = DC_DEFAULT_SIGINT_RESET ? "to reset" : 250 "to exit"; 251 const char* const tty = DC_DEFAULT_TTY_MODE ? "enabled" : 252 "disabled"; 253 const char* const prompt = DC_DEFAULT_PROMPT ? "enabled" : 254 "disabled"; 255 const char* const expr = DC_DEFAULT_EXPR_EXIT ? "to exit" : 256 "to not exit"; | 281 } 282#endif // BC_ENABLED 283 284#if DC_ENABLED 285 if (BC_IS_DC) 286 { 287 const char* const sigint = DC_DEFAULT_SIGINT_RESET ? "to reset" : 288 "to exit"; 289 const char* const tty = DC_DEFAULT_TTY_MODE ? "enabled" : 290 "disabled"; 291 const char* const prompt = DC_DEFAULT_PROMPT ? "enabled" : 292 "disabled"; 293 const char* const expr = DC_DEFAULT_EXPR_EXIT ? "to exit" : 294 "to not exit"; |
295 const char* const clamp = DC_DEFAULT_DIGIT_CLAMP ? "to clamp" : 296 "to not clamp"; |
|
257 | 297 |
258 bc_file_printf(&vm.fout, help, vm.name, vm.name, BC_VERSION, 259 BC_BUILD_TYPE, sigint, tty, prompt, expr); | 298 bc_file_printf(&vm->fout, help, vm->name, vm->name, BC_VERSION, 299 BC_BUILD_TYPE, sigint, tty, prompt, expr, clamp); |
260 } 261#endif // DC_ENABLED 262 } 263 264 // Flush. | 300 } 301#endif // DC_ENABLED 302 } 303 304 // Flush. |
265 bc_file_flush(&vm.fout, bc_flush_none); | 305 bc_file_flush(&vm->fout, bc_flush_none); |
266} 267#endif // !BC_ENABLE_LIBRARY 268 269#if !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK 270BC_NORETURN 271#endif // !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK 272void 273bc_vm_fatalError(BcErr e) 274{ 275 bc_err(e); 276#if !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK 277 BC_UNREACHABLE | 306} 307#endif // !BC_ENABLE_LIBRARY 308 309#if !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK 310BC_NORETURN 311#endif // !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK 312void 313bc_vm_fatalError(BcErr e) 314{ 315 bc_err(e); 316#if !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK 317 BC_UNREACHABLE |
318#if !BC_CLANG |
|
278 abort(); | 319 abort(); |
320#endif // !BC_CLANG |
|
279#endif // !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK 280} 281 282#if BC_ENABLE_LIBRARY | 321#endif // !BC_ENABLE_LIBRARY && !BC_ENABLE_MEMCHECK 322} 323 324#if BC_ENABLE_LIBRARY |
283void | 325BC_NORETURN void |
284bc_vm_handleError(BcErr e) 285{ | 326bc_vm_handleError(BcErr e) 327{ |
328#if BC_ENABLE_LIBRARY 329 BcVm* vm = bcl_getspecific(); 330#endif // BC_ENABLE_LIBRARY 331 |
|
286 assert(e < BC_ERR_NELEMS); | 332 assert(e < BC_ERR_NELEMS); |
287 assert(!vm.sig_pop); | 333 assert(!vm->sig_pop); |
288 289 BC_SIG_LOCK; 290 291 // If we have a normal error... 292 if (e <= BC_ERR_MATH_DIVIDE_BY_ZERO) 293 { 294 // Set the error. | 334 335 BC_SIG_LOCK; 336 337 // If we have a normal error... 338 if (e <= BC_ERR_MATH_DIVIDE_BY_ZERO) 339 { 340 // Set the error. |
295 vm.err = (BclError) (e - BC_ERR_MATH_NEGATIVE + 296 BCL_ERROR_MATH_NEGATIVE); | 341 vm->err = (BclError) (e - BC_ERR_MATH_NEGATIVE + 342 BCL_ERROR_MATH_NEGATIVE); |
297 } 298 // Abort if we should. | 343 } 344 // 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; | 345 else if (vm->abrt) abort(); 346 else if (e == BC_ERR_FATAL_ALLOC_ERR) vm->err = BCL_ERROR_FATAL_ALLOC_ERR; 347 else vm->err = BCL_ERROR_FATAL_UNKNOWN_ERR; |
302 303 BC_JMP; 304} 305#else // BC_ENABLE_LIBRARY | 348 349 BC_JMP; 350} 351#else // BC_ENABLE_LIBRARY |
352#ifndef NDEBUG |
|
306void | 353void |
354bc_vm_handleError(BcErr e, const char* file, int fline, size_t line, ...) 355#else // NDEBUG 356void |
|
307bc_vm_handleError(BcErr e, size_t line, ...) | 357bc_vm_handleError(BcErr e, size_t line, ...) |
358#endif // NDEBUG |
|
308{ 309 BcStatus s; 310 va_list args; 311 uchar id = bc_err_ids[e]; | 359{ 360 BcStatus s; 361 va_list args; 362 uchar id = bc_err_ids[e]; |
312 const char* err_type = vm.err_ids[id]; | 363 const char* err_type = vm->err_ids[id]; |
313 sig_atomic_t lock; 314 315 assert(e < BC_ERR_NELEMS); | 364 sig_atomic_t lock; 365 366 assert(e < BC_ERR_NELEMS); |
316 assert(!vm.sig_pop); | 367 assert(!vm->sig_pop); |
317 318#if BC_ENABLED 319 // Figure out if the POSIX error should be an error, a warning, or nothing. 320 if (!BC_S && e >= BC_ERR_POSIX_START) 321 { 322 if (BC_W) 323 { 324 // Make sure to not return an error. 325 id = UCHAR_MAX; | 368 369#if BC_ENABLED 370 // Figure out if the POSIX error should be an error, a warning, or nothing. 371 if (!BC_S && e >= BC_ERR_POSIX_START) 372 { 373 if (BC_W) 374 { 375 // Make sure to not return an error. 376 id = UCHAR_MAX; |
326 err_type = vm.err_ids[BC_ERR_IDX_WARN]; | 377 err_type = vm->err_ids[BC_ERR_IDX_WARN]; |
327 } 328 else return; 329 } 330#endif // BC_ENABLED 331 332 BC_SIG_TRYLOCK(lock); 333 334 // Make sure all of stdout is written first. | 378 } 379 else return; 380 } 381#endif // BC_ENABLED 382 383 BC_SIG_TRYLOCK(lock); 384 385 // Make sure all of stdout is written first. |
335 s = bc_file_flushErr(&vm.fout, bc_flush_err); | 386 s = bc_file_flushErr(&vm->fout, bc_flush_err); |
336 337 // Just jump out if the flush failed; there's nothing we can do. 338 if (BC_ERR(s == BC_STATUS_ERROR_FATAL)) 339 { | 387 388 // Just jump out if the flush failed; there's nothing we can do. 389 if (BC_ERR(s == BC_STATUS_ERROR_FATAL)) 390 { |
340 vm.status = (sig_atomic_t) s; | 391 vm->status = (sig_atomic_t) s; |
341 BC_JMP; 342 } 343 344 // Print the error message. 345 va_start(args, line); | 392 BC_JMP; 393 } 394 395 // Print the error message. 396 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); | 397 bc_file_putchar(&vm->ferr, bc_flush_none, '\n'); 398 bc_file_puts(&vm->ferr, bc_flush_none, err_type); 399 bc_file_putchar(&vm->ferr, bc_flush_none, ' '); 400 bc_file_vprintf(&vm->ferr, vm->err_msgs[e], args); |
350 va_end(args); 351 352 // Print the extra information if we have it. | 401 va_end(args); 402 403 // Print the extra information if we have it. |
353 if (BC_NO_ERR(vm.file != NULL)) | 404 if (BC_NO_ERR(vm->file != NULL)) |
354 { 355 // This is the condition for parsing vs runtime. 356 // If line is not 0, it is parsing. 357 if (line) 358 { | 405 { 406 // This is the condition for parsing vs runtime. 407 // If line is not 0, it is parsing. 408 if (line) 409 { |
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); | 410 bc_file_puts(&vm->ferr, bc_flush_none, "\n "); 411 bc_file_puts(&vm->ferr, bc_flush_none, vm->file); 412 bc_file_printf(&vm->ferr, ":%zu\n", line); |
362 } 363 else 364 { | 413 } 414 else 415 { |
365 BcInstPtr* ip = bc_vec_item_rev(&vm.prog.stack, 0); 366 BcFunc* f = bc_vec_item(&vm.prog.fns, ip->func); 367 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); 372 373#if BC_ENABLED 374 if (BC_IS_BC && ip->func != BC_PROG_MAIN && 375 ip->func != BC_PROG_READ) 376 { 377 bc_file_puts(&vm.ferr, bc_flush_none, "()"); 378 } 379#endif // BC_ENABLED | 416 // Print a stack trace. 417 bc_file_putchar(&vm->ferr, bc_flush_none, '\n'); 418 bc_program_printStackTrace(&vm->prog); |
380 } 381 } | 419 } 420 } |
421 else 422 { 423 bc_file_putchar(&vm->ferr, bc_flush_none, '\n'); 424 } |
|
382 | 425 |
383 bc_file_puts(&vm.ferr, bc_flush_none, "\n\n"); | 426#ifndef NDEBUG 427 bc_file_printf(&vm->ferr, "\n %s:%d\n", file, fline); 428#endif // NDEBUG |
384 | 429 |
385 s = bc_file_flushErr(&vm.ferr, bc_flush_err); | 430 bc_file_puts(&vm->ferr, bc_flush_none, "\n"); |
386 | 431 |
432 s = bc_file_flushErr(&vm->ferr, bc_flush_err); 433 |
|
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)) 392 { 393 exit(bc_vm_atexit((int) BC_STATUS_ERROR_FATAL)); 394 } 395#else // !BC_ENABLE_MEMCHECK | 434#if !BC_ENABLE_MEMCHECK 435 // Because this function is called by a BC_NORETURN function when fatal 436 // errors happen, we need to make sure to exit on fatal errors. This will 437 // be faster anyway. This function *cannot jump when a fatal error occurs!* 438 if (BC_ERR(id == BC_ERR_IDX_FATAL || s == BC_STATUS_ERROR_FATAL)) 439 { 440 exit(bc_vm_atexit((int) BC_STATUS_ERROR_FATAL)); 441 } 442#else // !BC_ENABLE_MEMCHECK |
396 if (BC_ERR(s == BC_STATUS_ERROR_FATAL)) vm.status = (sig_atomic_t) s; | 443 if (BC_ERR(s == BC_STATUS_ERROR_FATAL)) vm->status = (sig_atomic_t) s; |
397 else 398#endif // !BC_ENABLE_MEMCHECK 399 { | 444 else 445#endif // !BC_ENABLE_MEMCHECK 446 { |
400 vm.status = (sig_atomic_t) (uchar) (id + 1); | 447 vm->status = (sig_atomic_t) (uchar) (id + 1); |
401 } 402 403 // Only jump if there is an error. | 448 } 449 450 // Only jump if there is an error. |
404 if (BC_ERR(vm.status)) BC_JMP; | 451 if (BC_ERR(vm->status)) BC_JMP; |
405 406 BC_SIG_TRYUNLOCK(lock); 407} 408 409char* 410bc_vm_getenv(const char* var) 411{ 412 char* ret; --- 27 unchanged lines hidden (view full) --- 440{ 441 // Get the value. 442 char* val = bc_vm_getenv(var); 443 444 // If there is no value... 445 if (val == NULL) 446 { 447 // Set the default. | 452 453 BC_SIG_TRYUNLOCK(lock); 454} 455 456char* 457bc_vm_getenv(const char* var) 458{ 459 char* ret; --- 27 unchanged lines hidden (view full) --- 487{ 488 // Get the value. 489 char* val = bc_vm_getenv(var); 490 491 // If there is no value... 492 if (val == NULL) 493 { 494 // Set the default. |
448 if (def) vm.flags |= flag; 449 else vm.flags &= ~(flag); | 495 if (def) vm->flags |= flag; 496 else vm->flags &= ~(flag); |
450 } 451 // Parse the value. | 497 } 498 // Parse the value. |
452 else if (strtoul(val, NULL, 0)) vm.flags |= flag; 453 else vm.flags &= ~(flag); | 499 else if (strtoul(val, NULL, 0)) vm->flags |= flag; 500 else vm->flags &= ~(flag); |
454 455 bc_vm_getenvFree(val); 456} 457 458/** 459 * Parses the arguments in {B,D]C_ENV_ARGS. 460 * @param env_args_name The environment variable to use. | 501 502 bc_vm_getenvFree(val); 503} 504 505/** 506 * Parses the arguments in {B,D]C_ENV_ARGS. 507 * @param env_args_name The environment variable to use. |
508 * @param scale A pointer to return the scale that the arguments set, 509 * if any. 510 * @param ibase A pointer to return the ibase that the arguments set, 511 * if any. 512 * @param obase A pointer to return the obase that the arguments set, 513 * if any. |
|
461 */ 462static void | 514 */ 515static void |
463bc_vm_envArgs(const char* const env_args_name) | 516bc_vm_envArgs(const char* const env_args_name, BcBigDig* scale, BcBigDig* ibase, 517 BcBigDig* obase) |
464{ 465 char *env_args = bc_vm_getenv(env_args_name), *buf, *start; 466 char instr = '\0'; 467 468 BC_SIG_ASSERT_LOCKED; 469 470 if (env_args == NULL) return; 471 472 // Windows already allocates, so we don't need to. 473#ifndef _WIN32 | 518{ 519 char *env_args = bc_vm_getenv(env_args_name), *buf, *start; 520 char instr = '\0'; 521 522 BC_SIG_ASSERT_LOCKED; 523 524 if (env_args == NULL) return; 525 526 // Windows already allocates, so we don't need to. 527#ifndef _WIN32 |
474 start = buf = vm.env_args_buffer = bc_vm_strdup(env_args); | 528 start = buf = vm->env_args_buffer = bc_vm_strdup(env_args); |
475#else // _WIN32 | 529#else // _WIN32 |
476 start = buf = vm.env_args_buffer = env_args; | 530 start = buf = vm->env_args_buffer = env_args; |
477#endif // _WIN32 478 479 assert(buf != NULL); 480 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 483 // there. | 531#endif // _WIN32 532 533 assert(buf != NULL); 534 535 // Create two buffers for parsing. These need to stay throughout the entire 536 // execution of bc, unfortunately, because of filenames that might be in 537 // there. |
484 bc_vec_init(&vm.env_args, sizeof(char*), BC_DTOR_NONE); 485 bc_vec_push(&vm.env_args, &env_args_name); | 538 bc_vec_init(&vm->env_args, sizeof(char*), BC_DTOR_NONE); 539 bc_vec_push(&vm->env_args, &env_args_name); |
486 487 // While we haven't reached the end of the args... 488 while (*buf) 489 { 490 // If we don't have whitespace... 491 if (!isspace(*buf)) 492 { 493 // If we have the start of a string... --- 8 unchanged lines hidden (view full) --- 502 { 503 instr = '\0'; 504 buf += 1; 505 continue; 506 } 507 } 508 509 // Push the pointer to the args buffer. | 540 541 // While we haven't reached the end of the args... 542 while (*buf) 543 { 544 // If we don't have whitespace... 545 if (!isspace(*buf)) 546 { 547 // If we have the start of a string... --- 8 unchanged lines hidden (view full) --- 556 { 557 instr = '\0'; 558 buf += 1; 559 continue; 560 } 561 } 562 563 // Push the pointer to the args buffer. |
510 bc_vec_push(&vm.env_args, &buf); | 564 bc_vec_push(&vm->env_args, &buf); |
511 512 // Parse the string. 513 while (*buf && 514 ((!instr && !isspace(*buf)) || (instr && *buf != instr))) 515 { 516 buf += 1; 517 } 518 --- 10 unchanged lines hidden (view full) --- 529 else if (instr) bc_error(BC_ERR_FATAL_OPTION, 0, start); 530 } 531 // If we have whitespace, eat it. 532 else buf += 1; 533 } 534 535 // Make sure to push a NULL pointer at the end. 536 buf = NULL; | 565 566 // Parse the string. 567 while (*buf && 568 ((!instr && !isspace(*buf)) || (instr && *buf != instr))) 569 { 570 buf += 1; 571 } 572 --- 10 unchanged lines hidden (view full) --- 583 else if (instr) bc_error(BC_ERR_FATAL_OPTION, 0, start); 584 } 585 // If we have whitespace, eat it. 586 else buf += 1; 587 } 588 589 // Make sure to push a NULL pointer at the end. 590 buf = NULL; |
537 bc_vec_push(&vm.env_args, &buf); | 591 bc_vec_push(&vm->env_args, &buf); |
538 539 // Parse the arguments. | 592 593 // 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)); | 594 bc_args((int) vm->env_args.len - 1, bc_vec_item(&vm->env_args, 0), false, 595 scale, ibase, obase); |
542} 543 544/** 545 * Gets the {B,D}C_LINE_LENGTH. 546 * @param var The environment variable to pull it from. 547 * @return The line length. 548 */ 549static size_t --- 31 unchanged lines hidden (view full) --- 581#endif // BC_ENABLE_LIBRARY 582 583void 584bc_vm_shutdown(void) 585{ 586 BC_SIG_ASSERT_LOCKED; 587 588#if BC_ENABLE_NLS | 596} 597 598/** 599 * Gets the {B,D}C_LINE_LENGTH. 600 * @param var The environment variable to pull it from. 601 * @return The line length. 602 */ 603static size_t --- 31 unchanged lines hidden (view full) --- 635#endif // BC_ENABLE_LIBRARY 636 637void 638bc_vm_shutdown(void) 639{ 640 BC_SIG_ASSERT_LOCKED; 641 642#if BC_ENABLE_NLS |
589 if (vm.catalog != BC_VM_INVALID_CATALOG) catclose(vm.catalog); | 643 if (vm->catalog != BC_VM_INVALID_CATALOG) catclose(vm->catalog); |
590#endif // BC_ENABLE_NLS 591 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. | 644#endif // BC_ENABLE_NLS 645 646#if BC_ENABLE_HISTORY 647 // This must always run to ensure that the terminal is back to normal, i.e., 648 // has raw mode disabled. But we should only do it if we did not have a bad 649 // terminal because history was not initialized if it is a bad terminal. |
596 if (BC_TTY && !vm.history.badTerm) bc_history_free(&vm.history); | 650 if (BC_TTY && !vm->history.badTerm) bc_history_free(&vm->history); |
597#endif // BC_ENABLE_HISTORY 598 599#ifndef NDEBUG 600#if !BC_ENABLE_LIBRARY | 651#endif // BC_ENABLE_HISTORY 652 653#ifndef NDEBUG 654#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); | 655 bc_vec_free(&vm->env_args); 656 free(vm->env_args_buffer); 657 bc_vec_free(&vm->files); 658 bc_vec_free(&vm->exprs); |
605 | 659 |
606 if (BC_PARSE_IS_INITED(&vm.read_prs, &vm.prog)) | 660 if (BC_PARSE_IS_INITED(&vm->read_prs, &vm->prog)) |
607 { | 661 { |
608 bc_vec_free(&vm.read_buf); 609 bc_parse_free(&vm.read_prs); | 662 bc_vec_free(&vm->read_buf); 663 bc_parse_free(&vm->read_prs); |
610 } 611 | 664 } 665 |
612 bc_parse_free(&vm.prs); 613 bc_program_free(&vm.prog); | 666 bc_parse_free(&vm->prs); 667 bc_program_free(&vm->prog); |
614 | 668 |
615 bc_slabvec_free(&vm.other_slabs); 616 bc_slabvec_free(&vm.main_slabs); 617 bc_slabvec_free(&vm.main_const_slab); | 669 bc_slabvec_free(&vm->slabs); |
618#endif // !BC_ENABLE_LIBRARY 619 620 bc_vm_freeTemps(); 621#endif // NDEBUG 622 623#if !BC_ENABLE_LIBRARY 624 // We always want to flush. | 670#endif // !BC_ENABLE_LIBRARY 671 672 bc_vm_freeTemps(); 673#endif // NDEBUG 674 675#if !BC_ENABLE_LIBRARY 676 // We always want to flush. |
625 bc_file_free(&vm.fout); 626 bc_file_free(&vm.ferr); | 677 bc_file_free(&vm->fout); 678 bc_file_free(&vm->ferr); |
627#endif // !BC_ENABLE_LIBRARY 628} 629 630void 631bc_vm_addTemp(BcDig* num) 632{ | 679#endif // !BC_ENABLE_LIBRARY 680} 681 682void 683bc_vm_addTemp(BcDig* num) 684{ |
685#if BC_ENABLE_LIBRARY 686 BcVm* vm = bcl_getspecific(); 687#endif // BC_ENABLE_LIBRARY 688 |
|
633 BC_SIG_ASSERT_LOCKED; 634 635 // If we don't have room, just free. | 689 BC_SIG_ASSERT_LOCKED; 690 691 // If we don't have room, just free. |
636 if (vm.temps_len == BC_VM_MAX_TEMPS) free(num); | 692 if (vm->temps_len == BC_VM_MAX_TEMPS) free(num); |
637 else 638 { 639 // Add to the buffer and length. | 693 else 694 { 695 // Add to the buffer and length. |
640 temps_buf[vm.temps_len] = num; 641 vm.temps_len += 1; | 696 vm->temps_buf[vm->temps_len] = num; 697 vm->temps_len += 1; |
642 } 643} 644 645BcDig* 646bc_vm_takeTemp(void) 647{ | 698 } 699} 700 701BcDig* 702bc_vm_takeTemp(void) 703{ |
704#if BC_ENABLE_LIBRARY 705 BcVm* vm = bcl_getspecific(); 706#endif // BC_ENABLE_LIBRARY 707 |
|
648 BC_SIG_ASSERT_LOCKED; 649 | 708 BC_SIG_ASSERT_LOCKED; 709 |
650 if (!vm.temps_len) return NULL; | 710 if (!vm->temps_len) return NULL; |
651 | 711 |
652 vm.temps_len -= 1; | 712 vm->temps_len -= 1; |
653 | 713 |
654 return temps_buf[vm.temps_len]; | 714 return vm->temps_buf[vm->temps_len]; |
655} 656 | 715} 716 |
717BcDig* 718bc_vm_getTemp(void) 719{ 720#if BC_ENABLE_LIBRARY 721 BcVm* vm = bcl_getspecific(); 722#endif // BC_ENABLE_LIBRARY 723 724 BC_SIG_ASSERT_LOCKED; 725 726 if (!vm->temps_len) return NULL; 727 728 return vm->temps_buf[vm->temps_len - 1]; 729} 730 |
|
657void 658bc_vm_freeTemps(void) 659{ 660 size_t i; | 731void 732bc_vm_freeTemps(void) 733{ 734 size_t i; |
735#if BC_ENABLE_LIBRARY 736 BcVm* vm = bcl_getspecific(); 737#endif // BC_ENABLE_LIBRARY |
|
661 662 BC_SIG_ASSERT_LOCKED; 663 | 738 739 BC_SIG_ASSERT_LOCKED; 740 |
664 if (!vm.temps_len) return; | 741 if (!vm->temps_len) return; |
665 666 // Free them all... | 742 743 // Free them all... |
667 for (i = 0; i < vm.temps_len; ++i) | 744 for (i = 0; i < vm->temps_len; ++i) |
668 { | 745 { |
669 free(temps_buf[i]); | 746 free(vm->temps_buf[i]); |
670 } 671 | 747 } 748 |
672 vm.temps_len = 0; | 749 vm->temps_len = 0; |
673} 674 | 750} 751 |
752#if !BC_ENABLE_LIBRARY 753 754size_t 755bc_vm_numDigits(size_t val) 756{ 757 size_t digits = 0; 758 759 do 760 { 761 digits += 1; 762 val /= 10; 763 } 764 while (val != 0); 765 766 return digits; 767} 768 769#endif // !BC_ENABLE_LIBRARY 770 |
|
675inline size_t 676bc_vm_arraySize(size_t n, size_t size) 677{ 678 size_t res = n * size; | 771inline size_t 772bc_vm_arraySize(size_t n, size_t size) 773{ 774 size_t res = n * size; |
775 |
|
679 if (BC_ERR(BC_VM_MUL_OVERFLOW(n, size, res))) 680 { 681 bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR); 682 } | 776 if (BC_ERR(BC_VM_MUL_OVERFLOW(n, size, res))) 777 { 778 bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR); 779 } |
780 |
|
683 return res; 684} 685 686inline size_t 687bc_vm_growSize(size_t a, size_t b) 688{ 689 size_t res = a + b; | 781 return res; 782} 783 784inline size_t 785bc_vm_growSize(size_t a, size_t b) 786{ 787 size_t res = a + b; |
788 |
|
690 if (BC_ERR(res >= SIZE_MAX || res < a)) 691 { 692 bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR); 693 } | 789 if (BC_ERR(res >= SIZE_MAX || res < a)) 790 { 791 bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR); 792 } |
793 |
|
694 return res; 695} 696 697void* 698bc_vm_malloc(size_t n) 699{ 700 void* ptr; 701 --- 55 unchanged lines hidden (view full) --- 757 return s; 758} 759 760#if !BC_ENABLE_LIBRARY 761void 762bc_vm_printf(const char* fmt, ...) 763{ 764 va_list args; | 794 return res; 795} 796 797void* 798bc_vm_malloc(size_t n) 799{ 800 void* ptr; 801 --- 55 unchanged lines hidden (view full) --- 857 return s; 858} 859 860#if !BC_ENABLE_LIBRARY 861void 862bc_vm_printf(const char* fmt, ...) 863{ 864 va_list args; |
865#if BC_ENABLE_LIBRARY 866 BcVm* vm = bcl_getspecific(); 867#else // BC_ENABLE_LIBRARY |
|
765 sig_atomic_t lock; | 868 sig_atomic_t lock; |
869#endif // BC_ENABLE_LIBRARY |
|
766 767 BC_SIG_TRYLOCK(lock); 768 769 va_start(args, fmt); | 870 871 BC_SIG_TRYLOCK(lock); 872 873 va_start(args, fmt); |
770 bc_file_vprintf(&vm.fout, fmt, args); | 874 bc_file_vprintf(&vm->fout, fmt, args); |
771 va_end(args); 772 | 875 va_end(args); 876 |
773 vm.nchars = 0; | 877 vm->nchars = 0; |
774 775 BC_SIG_TRYUNLOCK(lock); 776} 777#endif // !BC_ENABLE_LIBRARY 778 779void 780bc_vm_putchar(int c, BcFlushType type) 781{ 782#if BC_ENABLE_LIBRARY | 878 879 BC_SIG_TRYUNLOCK(lock); 880} 881#endif // !BC_ENABLE_LIBRARY 882 883void 884bc_vm_putchar(int c, BcFlushType type) 885{ 886#if BC_ENABLE_LIBRARY |
783 bc_vec_pushByte(&vm.out, (uchar) c); | 887 BcVm* vm = bcl_getspecific(); 888 bc_vec_pushByte(&vm->out, (uchar) c); |
784#else // BC_ENABLE_LIBRARY | 889#else // BC_ENABLE_LIBRARY |
785 bc_file_putchar(&vm.fout, type, (uchar) c); 786 vm.nchars = (c == '\n' ? 0 : vm.nchars + 1); | 890 bc_file_putchar(&vm->fout, type, (uchar) c); 891 vm->nchars = (c == '\n' ? 0 : vm->nchars + 1); |
787#endif // BC_ENABLE_LIBRARY 788} 789 790#if !BC_ENABLE_LIBRARY 791 792#ifdef __OpenBSD__ 793 794/** 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 797 * just in case. 798 * @param msg The message to print. 799 */ 800BC_NORETURN static void 801bc_abortm(const char* msg) 802{ | 892#endif // BC_ENABLE_LIBRARY 893} 894 895#if !BC_ENABLE_LIBRARY 896 897#ifdef __OpenBSD__ 898 899/** 900 * Aborts with a message. This should never be called because I have carefully 901 * made sure that the calls to pledge() and unveil() are correct, but it's here 902 * just in case. 903 * @param msg The message to print. 904 */ 905BC_NORETURN static void 906bc_abortm(const char* msg) 907{ |
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); | 908 bc_file_puts(&vm->ferr, bc_flush_none, msg); 909 bc_file_puts(&vm->ferr, bc_flush_none, "; this is a bug"); 910 bc_file_flush(&vm->ferr, bc_flush_none); |
806 abort(); 807} 808 809void 810bc_pledge(const char* promises, const char* execpromises) 811{ 812 int r = pledge(promises, execpromises); 813 if (r) bc_abortm("pledge() failed"); --- 7 unchanged lines hidden (view full) --- 821 * @param permissions The permissions for the path. 822 */ 823static void 824bc_unveil(const char* path, const char* permissions) 825{ 826 int r = unveil(path, permissions); 827 if (r) bc_abortm("unveil() failed"); 828} | 911 abort(); 912} 913 914void 915bc_pledge(const char* promises, const char* execpromises) 916{ 917 int r = pledge(promises, execpromises); 918 if (r) bc_abortm("pledge() failed"); --- 7 unchanged lines hidden (view full) --- 926 * @param permissions The permissions for the path. 927 */ 928static void 929bc_unveil(const char* path, const char* permissions) 930{ 931 int r = unveil(path, permissions); 932 if (r) bc_abortm("unveil() failed"); 933} |
934 |
|
829#endif // BC_ENABLE_EXTRA_MATH 830 831#else // __OpenBSD__ 832 833void 834bc_pledge(const char* promises, const char* execpromises) 835{ 836 BC_UNUSED(promises); --- 14 unchanged lines hidden (view full) --- 851/** 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. 855 */ 856static void 857bc_vm_clean(void) 858{ | 935#endif // BC_ENABLE_EXTRA_MATH 936 937#else // __OpenBSD__ 938 939void 940bc_pledge(const char* promises, const char* execpromises) 941{ 942 BC_UNUSED(promises); --- 14 unchanged lines hidden (view full) --- 957/** 958 * Cleans unneeded variables, arrays, functions, strings, and constants when 959 * done executing a line of stdin. This is to prevent memory usage growing 960 * without bound. This is an idea from busybox. 961 */ 962static void 963bc_vm_clean(void) 964{ |
859 BcVec* fns = &vm.prog.fns; | 965 BcVec* fns = &vm->prog.fns; |
860 BcFunc* f = bc_vec_item(fns, BC_PROG_MAIN); | 966 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); | 967 BcInstPtr* ip = bc_vec_item(&vm->prog.stack, 0); 968 bool good = ((vm->status && vm->status != BC_STATUS_QUIT) || vm->sig != 0); |
863 864 BC_SIG_ASSERT_LOCKED; 865 866 // If all is good, go ahead and reset. | 969 970 BC_SIG_ASSERT_LOCKED; 971 972 // If all is good, go ahead and reset. |
867 if (good) bc_program_reset(&vm.prog); | 973 if (good) bc_program_reset(&vm->prog); |
868 869#if BC_ENABLED 870 // bc has this extra condition. If it not satisfied, it is in the middle of 871 // a parse. | 974 975#if BC_ENABLED 976 // bc has this extra condition. If it not satisfied, it is in the middle of 977 // a parse. |
872 if (good && BC_IS_BC) good = !BC_PARSE_NO_EXEC(&vm.prs); | 978 if (good && BC_IS_BC) good = !BC_PARSE_NO_EXEC(&vm->prs); |
873#endif // BC_ENABLED 874 875#if DC_ENABLED 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. 879 if (BC_IS_DC) 880 { 881 size_t i; 882 883 good = true; 884 | 979#endif // BC_ENABLED 980 981#if DC_ENABLED 982 // For dc, it is safe only when all of the results on the results stack are 983 // safe, which means that they are temporaries or other things that don't 984 // need strings or constants. 985 if (BC_IS_DC) 986 { 987 size_t i; 988 989 good = true; 990 |
885 for (i = 0; good && i < vm.prog.results.len; ++i) | 991 for (i = 0; good && i < vm->prog.results.len; ++i) |
886 { | 992 { |
887 BcResult* r = (BcResult*) bc_vec_item(&vm.prog.results, i); | 993 BcResult* r = (BcResult*) bc_vec_item(&vm->prog.results, i); |
888 good = BC_VM_SAFE_RESULT(r); 889 } 890 } 891#endif // DC_ENABLED 892 893 // If this condition is true, we can get rid of strings, 894 // constants, and code. | 994 good = BC_VM_SAFE_RESULT(r); 995 } 996 } 997#endif // DC_ENABLED 998 999 // If this condition is true, we can get rid of strings, 1000 // constants, and code. |
895 if (good && vm.prog.stack.len == 1 && ip->idx == f->code.len) | 1001 if (good && vm->prog.stack.len == 1 && ip->idx == f->code.len) |
896 { | 1002 { |
1003 // XXX: Nothing can be popped in dc. Deal with it. 1004 |
|
897#if BC_ENABLED 898 if (BC_IS_BC) 899 { | 1005#if BC_ENABLED 1006 if (BC_IS_BC) 1007 { |
1008 // XXX: you cannot delete strings, functions, or constants in bc. 1009 // Deal with it. |
|
900 bc_vec_popAll(&f->labels); | 1010 bc_vec_popAll(&f->labels); |
901 bc_vec_popAll(&f->strs); 902 bc_vec_popAll(&f->consts); 903 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); | |
909 } 910#endif // BC_ENABLED 911 | 1011 } 1012#endif // BC_ENABLED 1013 |
912#if DC_ENABLED 913 // Note to self: you cannot delete strings and functions. Deal with it. 914 if (BC_IS_DC) 915 { 916 bc_vec_popAll(vm.prog.consts); 917 bc_slabvec_clear(&vm.main_const_slab); 918 } 919#endif // DC_ENABLED 920 | |
921 bc_vec_popAll(&f->code); 922 923 ip->idx = 0; 924 } 925} 926 927/** 928 * Process a bunch of text. | 1014 bc_vec_popAll(&f->code); 1015 1016 ip->idx = 0; 1017 } 1018} 1019 1020/** 1021 * 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 932 * otherwise. | 1022 * @param text The text to process. 1023 * @param mode The mode to process in. |
933 */ 934static void | 1024 */ 1025static void |
935bc_vm_process(const char* text, bool is_stdin, bool is_exprs) | 1026bc_vm_process(const char* text, BcMode mode) |
936{ 937 // Set up the parser. | 1027{ 1028 // Set up the parser. |
938 bc_parse_text(&vm.prs, text, is_stdin, is_exprs); | 1029 bc_parse_text(&vm->prs, text, mode); |
939 | 1030 |
940 do | 1031 while (vm->prs.l.t != BC_LEX_EOF) |
941 { | 1032 { |
1033 // Parsing requires a signal lock. We also don't parse everything; we 1034 // want to execute as soon as possible for *everything*. |
|
942 BC_SIG_LOCK; | 1035 BC_SIG_LOCK; |
943 944#if BC_ENABLED 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); 948#endif // BC_ENABLED 949 950 // Parse it all. 951 while (BC_PARSE_CAN_PARSE(vm.prs)) 952 { 953 vm.parse(&vm.prs); 954 } 955 | 1036 vm->parse(&vm->prs); |
956 BC_SIG_UNLOCK; 957 958 // Execute if possible. | 1037 BC_SIG_UNLOCK; 1038 1039 // Execute if possible. |
959 if (BC_IS_DC || !BC_PARSE_NO_EXEC(&vm.prs)) bc_program_exec(&vm.prog); | 1040 if (BC_IS_DC || !BC_PARSE_NO_EXEC(&vm->prs)) bc_program_exec(&vm->prog); |
960 | 1041 |
961 assert(BC_IS_DC || vm.prog.results.len == 0); | 1042 assert(BC_IS_DC || vm->prog.results.len == 0); |
962 963 // Flush in interactive mode. | 1043 1044 // Flush in interactive mode. |
964 if (BC_I) bc_file_flush(&vm.fout, bc_flush_save); | 1045 if (BC_I) bc_file_flush(&vm->fout, bc_flush_save); |
965 } | 1046 } |
966 while (vm.prs.l.t != BC_LEX_EOF); | |
967} 968 969#if BC_ENABLED 970 971/** 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. 976 */ 977static void 978bc_vm_endif(void) 979{ | 1047} 1048 1049#if BC_ENABLED 1050 1051/** 1052 * Ends a series of if statements. This is to ensure that full parses happen 1053 * when a file finishes or stdin has no more data. Without this, bc thinks that 1054 * it cannot parse any further. But if we reach the end of a file or stdin has 1055 * no more data, we know we can add an empty else clause. 1056 */ 1057static void 1058bc_vm_endif(void) 1059{ |
980 bc_parse_endif(&vm.prs); 981 bc_program_exec(&vm.prog); | 1060 bc_parse_endif(&vm->prs); 1061 bc_program_exec(&vm->prog); |
982} | 1062} |
1063 |
|
983#endif // BC_ENABLED 984 985/** 986 * Processes a file. 987 * @param file The filename. 988 */ 989static void 990bc_vm_file(const char* file) 991{ 992 char* data = NULL; | 1064#endif // BC_ENABLED 1065 1066/** 1067 * Processes a file. 1068 * @param file The filename. 1069 */ 1070static void 1071bc_vm_file(const char* file) 1072{ 1073 char* data = NULL; |
1074#if BC_ENABLE_LIBRARY 1075 BcVm* vm = bcl_getspecific(); 1076#endif // BC_ENABLE_LIBRARY |
|
993 | 1077 |
994 assert(!vm.sig_pop); | 1078 assert(!vm->sig_pop); |
995 | 1079 |
1080 vm->mode = BC_MODE_FILE; 1081 |
|
996 // Set up the lexer. | 1082 // Set up the lexer. |
997 bc_lex_file(&vm.prs.l, file); | 1083 bc_lex_file(&vm->prs.l, file); |
998 999 BC_SIG_LOCK; 1000 1001 // Read the file. 1002 data = bc_read_file(file); 1003 1004 assert(data != NULL); 1005 | 1084 1085 BC_SIG_LOCK; 1086 1087 // Read the file. 1088 data = bc_read_file(file); 1089 1090 assert(data != NULL); 1091 |
1006 BC_SETJMP_LOCKED(err); | 1092 BC_SETJMP_LOCKED(vm, err); |
1007 1008 BC_SIG_UNLOCK; 1009 1010 // Process it. | 1093 1094 BC_SIG_UNLOCK; 1095 1096 // Process it. |
1011 bc_vm_process(data, false, false); | 1097 bc_vm_process(data, BC_MODE_FILE); |
1012 1013#if BC_ENABLED 1014 // Make sure to end any open if statements. 1015 if (BC_IS_BC) bc_vm_endif(); 1016#endif // BC_ENABLED 1017 1018err: | 1098 1099#if BC_ENABLED 1100 // Make sure to end any open if statements. 1101 if (BC_IS_BC) bc_vm_endif(); 1102#endif // BC_ENABLED 1103 1104err: |
1105 |
|
1019 BC_SIG_MAYLOCK; 1020 1021 // Cleanup. 1022 free(data); 1023 bc_vm_clean(); 1024 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. | 1106 BC_SIG_MAYLOCK; 1107 1108 // Cleanup. 1109 free(data); 1110 bc_vm_clean(); 1111 1112 // bc_program_reset(), called by bc_vm_clean(), resets the status. 1113 // 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; | 1114 if (vm->status == (sig_atomic_t) BC_STATUS_SUCCESS) BC_LONGJMP_STOP; |
1028 | 1115 |
1029 BC_LONGJMP_CONT; | 1116 BC_LONGJMP_CONT(vm); |
1030} 1031 1032bool 1033bc_vm_readLine(bool clear) 1034{ 1035 BcStatus s; 1036 bool good; 1037 1038 BC_SIG_ASSERT_NOT_LOCKED; 1039 1040 // Clear the buffer if desired. | 1117} 1118 1119bool 1120bc_vm_readLine(bool clear) 1121{ 1122 BcStatus s; 1123 bool good; 1124 1125 BC_SIG_ASSERT_NOT_LOCKED; 1126 1127 // Clear the buffer if desired. |
1041 if (clear) bc_vec_empty(&vm.buffer); | 1128 if (clear) bc_vec_empty(&vm->buffer); |
1042 1043 // Empty the line buffer. | 1129 1130 // Empty the line buffer. |
1044 bc_vec_empty(&vm.line_buf); | 1131 bc_vec_empty(&vm->line_buf); |
1045 | 1132 |
1046 if (vm.eof) return false; | 1133 if (vm->eof) return false; |
1047 1048 do 1049 { 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 1052 // out instead. | 1134 1135 do 1136 { 1137 // bc_read_line() must always return either BC_STATUS_SUCCESS or 1138 // BC_STATUS_EOF. Everything else, it and whatever it calls, must jump 1139 // out instead. |
1053 s = bc_read_line(&vm.line_buf, ">>> "); 1054 vm.eof = (s == BC_STATUS_EOF); | 1140 s = bc_read_line(&vm->line_buf, ">>> "); 1141 vm->eof = (s == BC_STATUS_EOF); |
1055 } | 1142 } |
1056 while (!(s) && !vm.eof && vm.line_buf.len < 1); | 1143 while (s == BC_STATUS_SUCCESS && !vm->eof && vm->line_buf.len < 1); |
1057 | 1144 |
1058 good = (vm.line_buf.len > 1); | 1145 good = (vm->line_buf.len > 1); |
1059 1060 // Concat if we found something. | 1146 1147 // Concat if we found something. |
1061 if (good) bc_vec_concat(&vm.buffer, vm.line_buf.v); | 1148 if (good) bc_vec_concat(&vm->buffer, vm->line_buf.v); |
1062 1063 return good; 1064} 1065 1066/** 1067 * Processes text from stdin. 1068 */ 1069static void 1070bc_vm_stdin(void) 1071{ | 1149 1150 return good; 1151} 1152 1153/** 1154 * Processes text from stdin. 1155 */ 1156static void 1157bc_vm_stdin(void) 1158{ |
1072 bool clear = true; | 1159 bool clear; |
1073 | 1160 |
1074 vm.is_stdin = true; | 1161#if BC_ENABLE_LIBRARY 1162 BcVm* vm = bcl_getspecific(); 1163#endif // BC_ENABLE_LIBRARY |
1075 | 1164 |
1165 clear = true; 1166 vm->mode = BC_MODE_STDIN; 1167 |
|
1076 // Set up the lexer. | 1168 // Set up the lexer. |
1077 bc_lex_file(&vm.prs.l, bc_program_stdin_name); | 1169 bc_lex_file(&vm->prs.l, bc_program_stdin_name); |
1078 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 | 1170 1171 // These are global so that the lexers can access them, but they are 1172 // allocated and freed in this function because they should only be used for 1173 // stdin and expressions (they are used in bc_vm_exprs() as well). So they 1174 // 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 | 1175 // 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. 1087 BC_SIG_LOCK; | 1176 // reading from stdin. Well, both lexers care. And the reason they care is 1177 // so that if a comment or a string goes across multiple lines, the lexer 1178 // can request more data from stdin until the comment or string is ended. 1179 BC_SIG_LOCK; |
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); | 1180 bc_vec_init(&vm->buffer, sizeof(uchar), BC_DTOR_NONE); 1181 bc_vec_init(&vm->line_buf, sizeof(uchar), BC_DTOR_NONE); 1182 BC_SETJMP_LOCKED(vm, err); |
1091 BC_SIG_UNLOCK; 1092 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. 1096restart: 1097 1098 // While we still read data from stdin. 1099 while (bc_vm_readLine(clear)) 1100 { | 1183 BC_SIG_UNLOCK; 1184 1185// This label exists because errors can cause jumps to end up at the err label 1186// below. If that happens, and the error should be cleared and execution 1187// continue, then we need to jump back. 1188restart: 1189 1190 // While we still read data from stdin. 1191 while (bc_vm_readLine(clear)) 1192 { |
1101 size_t len = vm.buffer.len - 1; 1102 const char* str = vm.buffer.v; | 1193 size_t len = vm->buffer.len - 1; 1194 const char* str = vm->buffer.v; |
1103 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; 1108 1109 // Process the data. | 1195 1196 // We don't want to clear the buffer when the line ends with a backslash 1197 // because a backslash newline is special in bc. 1198 clear = (len < 2 || str[len - 2] != '\\' || str[len - 1] != '\n'); 1199 if (!clear) continue; 1200 1201 // Process the data. |
1110 bc_vm_process(vm.buffer.v, true, false); | 1202 bc_vm_process(vm->buffer.v, BC_MODE_STDIN); |
1111 | 1203 |
1112 if (vm.eof) break; | 1204 if (vm->eof) break; |
1113 else 1114 { 1115 BC_SIG_LOCK; 1116 bc_vm_clean(); 1117 BC_SIG_UNLOCK; 1118 } 1119 } 1120 --- 5 unchanged lines hidden (view full) --- 1126err: 1127 1128 BC_SIG_MAYLOCK; 1129 1130 // Cleanup. 1131 bc_vm_clean(); 1132 1133#if !BC_ENABLE_MEMCHECK | 1205 else 1206 { 1207 BC_SIG_LOCK; 1208 bc_vm_clean(); 1209 BC_SIG_UNLOCK; 1210 } 1211 } 1212 --- 5 unchanged lines hidden (view full) --- 1218err: 1219 1220 BC_SIG_MAYLOCK; 1221 1222 // Cleanup. 1223 bc_vm_clean(); 1224 1225#if !BC_ENABLE_MEMCHECK |
1134 assert(vm.status != BC_STATUS_ERROR_FATAL); | 1226 assert(vm->status != BC_STATUS_ERROR_FATAL); |
1135 | 1227 |
1136 vm.status = vm.status == BC_STATUS_QUIT || !BC_I ? vm.status : 1137 BC_STATUS_SUCCESS; | 1228 vm->status = vm->status == BC_STATUS_QUIT || !BC_I ? vm->status : 1229 BC_STATUS_SUCCESS; |
1138#else // !BC_ENABLE_MEMCHECK | 1230#else // !BC_ENABLE_MEMCHECK |
1139 vm.status = vm.status == BC_STATUS_ERROR_FATAL || 1140 vm.status == BC_STATUS_QUIT || !BC_I ? 1141 vm.status : 1142 BC_STATUS_SUCCESS; | 1231 vm->status = vm->status == BC_STATUS_ERROR_FATAL || 1232 vm->status == BC_STATUS_QUIT || !BC_I ? 1233 vm->status : 1234 BC_STATUS_SUCCESS; |
1143#endif // !BC_ENABLE_MEMCHECK 1144 | 1235#endif // !BC_ENABLE_MEMCHECK 1236 |
1145 if (!vm.status && !vm.eof) | 1237 if (!vm->status && !vm->eof) |
1146 { | 1238 { |
1147 bc_vec_empty(&vm.buffer); | 1239 bc_vec_empty(&vm->buffer); |
1148 BC_LONGJMP_STOP; 1149 BC_SIG_UNLOCK; 1150 goto restart; 1151 } 1152 1153#ifndef NDEBUG 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. | 1240 BC_LONGJMP_STOP; 1241 BC_SIG_UNLOCK; 1242 goto restart; 1243 } 1244 1245#ifndef NDEBUG 1246 // Since these are tied to this function, free them here. We only free in 1247 // debug mode because stdin is always the last thing read. |
1156 bc_vec_free(&vm.line_buf); 1157 bc_vec_free(&vm.buffer); | 1248 bc_vec_free(&vm->line_buf); 1249 bc_vec_free(&vm->buffer); |
1158#endif // NDEBUG 1159 | 1250#endif // NDEBUG 1251 |
1160 BC_LONGJMP_CONT; | 1252 BC_LONGJMP_CONT(vm); |
1161} 1162 1163bool 1164bc_vm_readBuf(bool clear) 1165{ | 1253} 1254 1255bool 1256bc_vm_readBuf(bool clear) 1257{ |
1166 size_t len = vm.exprs.len - 1; | 1258 size_t len = vm->exprs.len - 1; |
1167 bool more; 1168 1169 BC_SIG_ASSERT_NOT_LOCKED; 1170 1171 // Clear the buffer if desired. | 1259 bool more; 1260 1261 BC_SIG_ASSERT_NOT_LOCKED; 1262 1263 // Clear the buffer if desired. |
1172 if (clear) bc_vec_empty(&vm.buffer); | 1264 if (clear) bc_vec_empty(&vm->buffer); |
1173 1174 // We want to pop the nul byte off because that's what bc_read_buf() 1175 // expects. | 1265 1266 // We want to pop the nul byte off because that's what bc_read_buf() 1267 // expects. |
1176 bc_vec_pop(&vm.buffer); | 1268 bc_vec_pop(&vm->buffer); |
1177 1178 // Read one line of expressions. | 1269 1270 // Read one line of expressions. |
1179 more = bc_read_buf(&vm.buffer, vm.exprs.v, &len); 1180 bc_vec_pushByte(&vm.buffer, '\0'); | 1271 more = bc_read_buf(&vm->buffer, vm->exprs.v, &len); 1272 bc_vec_pushByte(&vm->buffer, '\0'); |
1181 1182 return more; 1183} 1184 1185static void 1186bc_vm_exprs(void) 1187{ | 1273 1274 return more; 1275} 1276 1277static void 1278bc_vm_exprs(void) 1279{ |
1188 bool clear = true; | 1280 bool clear; |
1189 | 1281 |
1282#if BC_ENABLE_LIBRARY 1283 BcVm* vm = bcl_getspecific(); 1284#endif // BC_ENABLE_LIBRARY 1285 1286 clear = true; 1287 vm->mode = BC_MODE_EXPRS; 1288 |
|
1190 // Prepare the lexer. | 1289 // Prepare the lexer. |
1191 bc_lex_file(&vm.prs.l, bc_program_exprs_name); | 1290 bc_lex_file(&vm->prs.l, bc_program_exprs_name); |
1192 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 | 1291 1292 // We initialize this so that the lexer can access it in the case that it 1293 // 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 | 1294 // comment. See the comment on the allocation of vm->buffer above in |
1196 // bc_vm_stdin() for more information. 1197 BC_SIG_LOCK; | 1295 // bc_vm_stdin() for more information. 1296 BC_SIG_LOCK; |
1198 bc_vec_init(&vm.buffer, sizeof(uchar), BC_DTOR_NONE); 1199 BC_SETJMP_LOCKED(err); | 1297 bc_vec_init(&vm->buffer, sizeof(uchar), BC_DTOR_NONE); 1298 BC_SETJMP_LOCKED(vm, err); |
1200 BC_SIG_UNLOCK; 1201 1202 while (bc_vm_readBuf(clear)) 1203 { | 1299 BC_SIG_UNLOCK; 1300 1301 while (bc_vm_readBuf(clear)) 1302 { |
1204 size_t len = vm.buffer.len - 1; 1205 const char* str = vm.buffer.v; | 1303 size_t len = vm->buffer.len - 1; 1304 const char* str = vm->buffer.v; |
1206 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; 1211 1212 // Process the data. | 1305 1306 // We don't want to clear the buffer when the line ends with a backslash 1307 // because a backslash newline is special in bc. 1308 clear = (len < 2 || str[len - 2] != '\\' || str[len - 1] != '\n'); 1309 if (!clear) continue; 1310 1311 // Process the data. |
1213 bc_vm_process(vm.buffer.v, false, true); | 1312 bc_vm_process(vm->buffer.v, BC_MODE_EXPRS); |
1214 } 1215 1216 // If we were not supposed to clear, then we should process everything. This 1217 // makes sure that errors get reported. | 1313 } 1314 1315 // If we were not supposed to clear, then we should process everything. This 1316 // makes sure that errors get reported. |
1218 if (!clear) bc_vm_process(vm.buffer.v, false, true); | 1317 if (!clear) bc_vm_process(vm->buffer.v, BC_MODE_EXPRS); |
1219 1220err: 1221 1222 BC_SIG_MAYLOCK; 1223 1224 // Cleanup. 1225 bc_vm_clean(); 1226 | 1318 1319err: 1320 1321 BC_SIG_MAYLOCK; 1322 1323 // Cleanup. 1324 bc_vm_clean(); 1325 |
1326 // bc_program_reset(), called by bc_vm_clean(), resets the status. 1327 // We want it to clear the sig_pop variable in case it was set. 1328 if (vm->status == (sig_atomic_t) BC_STATUS_SUCCESS) BC_LONGJMP_STOP; 1329 |
|
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. | 1330 // Since this is tied to this function, free it here. We always free it here 1331 // because bc_vm_stdin() may or may not use it later. |
1229 bc_vec_free(&vm.buffer); | 1332 bc_vec_free(&vm->buffer); |
1230 | 1333 |
1231 BC_LONGJMP_CONT; | 1334 BC_LONGJMP_CONT(vm); |
1232} 1233 1234#if BC_ENABLED 1235 1236/** 1237 * Loads a math library. 1238 * @param name The name of the library. 1239 * @param text The text of the source code. 1240 */ 1241static void 1242bc_vm_load(const char* name, const char* text) 1243{ | 1335} 1336 1337#if BC_ENABLED 1338 1339/** 1340 * Loads a math library. 1341 * @param name The name of the library. 1342 * @param text The text of the source code. 1343 */ 1344static void 1345bc_vm_load(const char* name, const char* text) 1346{ |
1244 bc_lex_file(&vm.prs.l, name); 1245 bc_parse_text(&vm.prs, text, false, false); | 1347 bc_lex_file(&vm->prs.l, name); 1348 bc_parse_text(&vm->prs, text, BC_MODE_FILE); |
1246 1247 BC_SIG_LOCK; 1248 | 1349 1350 BC_SIG_LOCK; 1351 |
1249 while (vm.prs.l.t != BC_LEX_EOF) | 1352 while (vm->prs.l.t != BC_LEX_EOF) |
1250 { | 1353 { |
1251 vm.parse(&vm.prs); | 1354 vm->parse(&vm->prs); |
1252 } 1253 1254 BC_SIG_UNLOCK; 1255} 1256 1257#endif // BC_ENABLED 1258 1259/** 1260 * Loads the default error messages. 1261 */ 1262static void 1263bc_vm_defaultMsgs(void) 1264{ 1265 size_t i; 1266 | 1355 } 1356 1357 BC_SIG_UNLOCK; 1358} 1359 1360#endif // BC_ENABLED 1361 1362/** 1363 * Loads the default error messages. 1364 */ 1365static void 1366bc_vm_defaultMsgs(void) 1367{ 1368 size_t i; 1369 |
1267 vm.func_header = bc_err_func_header; 1268 | |
1269 // Load the error categories. 1270 for (i = 0; i < BC_ERR_IDX_NELEMS + BC_ENABLED; ++i) 1271 { | 1370 // Load the error categories. 1371 for (i = 0; i < BC_ERR_IDX_NELEMS + BC_ENABLED; ++i) 1372 { |
1272 vm.err_ids[i] = bc_errs[i]; | 1373 vm->err_ids[i] = bc_errs[i]; |
1273 } 1274 1275 // Load the error messages. 1276 for (i = 0; i < BC_ERR_NELEMS; ++i) 1277 { | 1374 } 1375 1376 // Load the error messages. 1377 for (i = 0; i < BC_ERR_NELEMS; ++i) 1378 { |
1278 vm.err_msgs[i] = bc_err_msgs[i]; | 1379 vm->err_msgs[i] = bc_err_msgs[i]; |
1279 } 1280} 1281 1282/** 1283 * Loads the error messages for the locale. If NLS is disabled, this just loads 1284 * the default messages. 1285 */ 1286static void 1287bc_vm_gettext(void) 1288{ 1289#if BC_ENABLE_NLS 1290 uchar id = 0; | 1380 } 1381} 1382 1383/** 1384 * Loads the error messages for the locale. If NLS is disabled, this just loads 1385 * the default messages. 1386 */ 1387static void 1388bc_vm_gettext(void) 1389{ 1390#if BC_ENABLE_NLS 1391 uchar id = 0; |
1291 int set = 1, msg = 1; | 1392 int set, msg = 1; |
1292 size_t i; 1293 1294 // If no locale, load the defaults. | 1393 size_t i; 1394 1395 // If no locale, load the defaults. |
1295 if (vm.locale == NULL) | 1396 if (vm->locale == NULL) |
1296 { | 1397 { |
1297 vm.catalog = BC_VM_INVALID_CATALOG; | 1398 vm->catalog = BC_VM_INVALID_CATALOG; |
1298 bc_vm_defaultMsgs(); 1299 return; 1300 } 1301 | 1399 bc_vm_defaultMsgs(); 1400 return; 1401 } 1402 |
1302 vm.catalog = catopen(BC_MAINEXEC, NL_CAT_LOCALE); | 1403 vm->catalog = catopen(BC_MAINEXEC, NL_CAT_LOCALE); |
1303 1304 // If no catalog, load the defaults. | 1404 1405 // If no catalog, load the defaults. |
1305 if (vm.catalog == BC_VM_INVALID_CATALOG) | 1406 if (vm->catalog == BC_VM_INVALID_CATALOG) |
1306 { 1307 bc_vm_defaultMsgs(); 1308 return; 1309 } 1310 | 1407 { 1408 bc_vm_defaultMsgs(); 1409 return; 1410 } 1411 |
1311 // Load the function header. 1312 vm.func_header = catgets(vm.catalog, set, msg, bc_err_func_header); 1313 | |
1314 // Load the error categories. | 1412 // Load the error categories. |
1315 for (set += 1; msg <= BC_ERR_IDX_NELEMS + BC_ENABLED; ++msg) | 1413 for (set = 1; msg <= BC_ERR_IDX_NELEMS + BC_ENABLED; ++msg) |
1316 { | 1414 { |
1317 vm.err_ids[msg - 1] = catgets(vm.catalog, set, msg, bc_errs[msg - 1]); | 1415 vm->err_ids[msg - 1] = catgets(vm->catalog, set, msg, bc_errs[msg - 1]); |
1318 } 1319 1320 i = 0; 1321 id = bc_err_ids[i]; 1322 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. | 1416 } 1417 1418 i = 0; 1419 id = bc_err_ids[i]; 1420 1421 // Load the error messages. In order to understand this loop, you must know 1422 // 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) | 1423 for (set = id + 2, msg = 1; i < BC_ERR_NELEMS; ++i, ++msg) |
1326 { 1327 if (id != bc_err_ids[i]) 1328 { 1329 msg = 1; 1330 id = bc_err_ids[i]; | 1424 { 1425 if (id != bc_err_ids[i]) 1426 { 1427 msg = 1; 1428 id = bc_err_ids[i]; |
1331 set = id + 3; | 1429 set = id + 2; |
1332 } 1333 | 1430 } 1431 |
1334 vm.err_msgs[i] = catgets(vm.catalog, set, msg, bc_err_msgs[i]); | 1432 vm->err_msgs[i] = catgets(vm->catalog, set, msg, bc_err_msgs[i]); |
1335 } 1336#else // BC_ENABLE_NLS 1337 bc_vm_defaultMsgs(); 1338#endif // BC_ENABLE_NLS 1339} 1340 1341/** 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. 1345 */ 1346static void 1347bc_vm_exec(void) 1348{ 1349 size_t i; | 1433 } 1434#else // BC_ENABLE_NLS 1435 bc_vm_defaultMsgs(); 1436#endif // BC_ENABLE_NLS 1437} 1438 1439/** 1440 * Starts execution. Really, this is a function of historical accident; it could 1441 * probably be combined with bc_vm_boot(), but I don't care enough. Really, this 1442 * function starts when execution of bc or dc source code starts. 1443 */ 1444static void 1445bc_vm_exec(void) 1446{ 1447 size_t i; |
1448#if DC_ENABLED |
|
1350 bool has_file = false; | 1449 bool has_file = false; |
1450#endif // DC_ENABLED |
|
1351 1352#if BC_ENABLED 1353 // Load the math libraries. | 1451 1452#if BC_ENABLED 1453 // Load the math libraries. |
1354 if (BC_IS_BC && (vm.flags & BC_FLAG_L)) | 1454 if (BC_IS_BC && (vm->flags & BC_FLAG_L)) |
1355 { 1356 // Can't allow redefinitions in the builtin library. | 1455 { 1456 // Can't allow redefinitions in the builtin library. |
1357 vm.no_redefine = true; | 1457 vm->no_redefine = true; |
1358 1359 bc_vm_load(bc_lib_name, bc_lib); 1360 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 1364 1365 // Make sure to clear this. | 1458 1459 bc_vm_load(bc_lib_name, bc_lib); 1460 1461#if BC_ENABLE_EXTRA_MATH 1462 if (!BC_IS_POSIX) bc_vm_load(bc_lib2_name, bc_lib2); 1463#endif // BC_ENABLE_EXTRA_MATH 1464 1465 // Make sure to clear this. |
1366 vm.no_redefine = false; | 1466 vm->no_redefine = false; |
1367 1368 // Execute to ensure that all is hunky dory. Without this, scale can be 1369 // set improperly. | 1467 1468 // Execute to ensure that all is hunky dory. Without this, scale can be 1469 // set improperly. |
1370 bc_program_exec(&vm.prog); | 1470 bc_program_exec(&vm->prog); |
1371 } 1372#endif // BC_ENABLED 1373 1374 // If there are expressions to execute... | 1471 } 1472#endif // BC_ENABLED 1473 1474 // If there are expressions to execute... |
1375 if (vm.exprs.len) | 1475 if (vm->exprs.len) |
1376 { 1377 // Process the expressions. 1378 bc_vm_exprs(); 1379 1380 // Sometimes, executing expressions means we need to quit. | 1476 { 1477 // Process the expressions. 1478 bc_vm_exprs(); 1479 1480 // Sometimes, executing expressions means we need to quit. |
1381 if (!vm.no_exprs && vm.exit_exprs && BC_EXPR_EXIT) return; | 1481 if (!vm->no_exprs && vm->exit_exprs && BC_EXPR_EXIT) return; |
1382 } 1383 1384 // Process files. | 1482 } 1483 1484 // Process files. |
1385 for (i = 0; i < vm.files.len; ++i) | 1485 for (i = 0; i < vm->files.len; ++i) |
1386 { | 1486 { |
1387 char* path = *((char**) bc_vec_item(&vm.files, i)); | 1487 char* path = *((char**) bc_vec_item(&vm->files, i)); |
1388 if (!strcmp(path, "")) continue; | 1488 if (!strcmp(path, "")) continue; |
1489#if DC_ENABLED |
|
1389 has_file = true; | 1490 has_file = true; |
1491#endif // DC_ENABLED |
|
1390 bc_vm_file(path); 1391 } 1392 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 1399 1400#if BC_ENABLE_HISTORY 1401 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. | 1492 bc_vm_file(path); 1493 } 1494 1495#if BC_ENABLE_EXTRA_MATH 1496 // These are needed for the pseudo-random number generator. 1497 bc_unveil("/dev/urandom", "r"); 1498 bc_unveil("/dev/random", "r"); 1499 bc_unveil(NULL, NULL); 1500#endif // BC_ENABLE_EXTRA_MATH 1501 1502#if BC_ENABLE_HISTORY 1503 1504 // We need to keep tty if history is enabled, and we need to keep rpath for 1505 // the times when we read from /dev/urandom. |
1404 if (BC_TTY && !vm.history.badTerm) bc_pledge(bc_pledge_end_history, NULL); | 1506 if (BC_TTY && !vm->history.badTerm) bc_pledge(bc_pledge_end_history, NULL); |
1405 else 1406#endif // BC_ENABLE_HISTORY 1407 { 1408 bc_pledge(bc_pledge_end, NULL); 1409 } 1410 1411#if BC_ENABLE_AFL 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. 1416 __AFL_INIT(); 1417#endif // BC_ENABLE_AFL 1418 1419 // Execute from stdin. bc always does. | 1507 else 1508#endif // BC_ENABLE_HISTORY 1509 { 1510 bc_pledge(bc_pledge_end, NULL); 1511 } 1512 1513#if BC_ENABLE_AFL 1514 // This is the thing that makes fuzzing with AFL++ so fast. If you move this 1515 // back, you won't cause any problems, but fuzzing will slow down. If you 1516 // move this forward, you won't fuzz anything because you will be skipping 1517 // the reading from stdin. 1518 __AFL_INIT(); 1519#endif // BC_ENABLE_AFL 1520 1521 // Execute from stdin. bc always does. |
1420 if (BC_IS_BC || !has_file) bc_vm_stdin(); | 1522 if (BC_VM_RUN_STDIN(has_file)) bc_vm_stdin(); |
1421} 1422 1423void 1424bc_vm_boot(int argc, char* argv[]) 1425{ 1426 int ttyin, ttyout, ttyerr; 1427 bool tty; | 1523} 1524 1525void 1526bc_vm_boot(int argc, char* argv[]) 1527{ 1528 int ttyin, ttyout, ttyerr; 1529 bool tty; |
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; | 1530 const char* const env_len = BC_VM_LINE_LENGTH_STR; 1531 const char* const env_args = BC_VM_ENV_ARGS_STR; 1532 const char* const env_exit = BC_VM_EXPR_EXIT_STR; 1533 const char* const env_clamp = BC_VM_DIGIT_CLAMP_STR; 1534 int env_exit_def = BC_VM_EXPR_EXIT_DEF; 1535 int env_clamp_def = BC_VM_DIGIT_CLAMP_DEF; 1536 BcBigDig scale = BC_NUM_BIGDIG_MAX; 1537 BcBigDig env_scale = BC_NUM_BIGDIG_MAX; 1538 BcBigDig ibase = BC_NUM_BIGDIG_MAX; 1539 BcBigDig env_ibase = BC_NUM_BIGDIG_MAX; 1540 BcBigDig obase = BC_NUM_BIGDIG_MAX; 1541 BcBigDig env_obase = BC_NUM_BIGDIG_MAX; |
1432 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); 1438 | 1542 1543 // We need to know which of stdin, stdout, and stderr are tty's. 1544 ttyin = isatty(STDIN_FILENO); 1545 ttyout = isatty(STDOUT_FILENO); 1546 ttyerr = isatty(STDERR_FILENO); 1547 tty = (ttyin != 0 && ttyout != 0 && ttyerr != 0); 1548 |
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; | 1549 vm->flags |= ttyin ? BC_FLAG_TTYIN : 0; 1550 vm->flags |= tty ? BC_FLAG_TTY : 0; 1551 vm->flags |= ttyin && ttyout ? BC_FLAG_I : 0; |
1442 1443 // Set up signals. 1444 bc_vm_sigaction(); 1445 1446 // Initialize some vm stuff. This is separate to make things easier for the 1447 // library. 1448 bc_vm_init(); 1449 1450 // Explicitly set this in case NULL isn't all zeroes. | 1552 1553 // Set up signals. 1554 bc_vm_sigaction(); 1555 1556 // Initialize some vm stuff. This is separate to make things easier for the 1557 // library. 1558 bc_vm_init(); 1559 1560 // Explicitly set this in case NULL isn't all zeroes. |
1451 vm.file = NULL; | 1561 vm->file = NULL; |
1452 1453 // Set the error messages. 1454 bc_vm_gettext(); 1455 1456#if BC_ENABLE_LINE_LIB | 1562 1563 // Set the error messages. 1564 bc_vm_gettext(); 1565 1566#if BC_ENABLE_LINE_LIB |
1567 |
|
1457 // Initialize the output file buffers. | 1568 // Initialize the output file buffers. |
1458 bc_file_init(&vm.ferr, stderr); 1459 bc_file_init(&vm.fout, stdout); | 1569 bc_file_init(&vm->ferr, stderr); 1570 bc_file_init(&vm->fout, stdout); |
1460 1461 // Set the input buffer. | 1571 1572 // Set the input buffer. |
1462 vm.buf = output_bufs; | 1573 vm->buf = output_bufs; |
1463 1464#else // BC_ENABLE_LINE_LIB | 1574 1575#else // BC_ENABLE_LINE_LIB |
1576 |
|
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. | 1577 // Initialize the output file buffers. They each take portions of the global 1578 // 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, | 1579 bc_file_init(&vm->ferr, STDERR_FILENO, output_bufs + BC_VM_STDOUT_BUF_SIZE, |
1468 BC_VM_STDERR_BUF_SIZE); | 1580 BC_VM_STDERR_BUF_SIZE); |
1469 bc_file_init(&vm.fout, STDOUT_FILENO, output_bufs, BC_VM_STDOUT_BUF_SIZE); | 1581 bc_file_init(&vm->fout, STDOUT_FILENO, output_bufs, BC_VM_STDOUT_BUF_SIZE); |
1470 1471 // Set the input buffer to the rest of the global buffer. | 1582 1583 // 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; | 1584 vm->buf = output_bufs + BC_VM_STDOUT_BUF_SIZE + BC_VM_STDERR_BUF_SIZE; |
1473#endif // BC_ENABLE_LINE_LIB 1474 1475 // Set the line length by environment variable. | 1585#endif // BC_ENABLE_LINE_LIB 1586 1587 // Set the line length by environment variable. |
1476 vm.line_len = (uint16_t) bc_vm_envLen(env_len); | 1588 vm->line_len = (uint16_t) bc_vm_envLen(env_len); |
1477 1478 bc_vm_setenvFlag(env_exit, env_exit_def, BC_FLAG_EXPR_EXIT); | 1589 1590 bc_vm_setenvFlag(env_exit, env_exit_def, BC_FLAG_EXPR_EXIT); |
1591 bc_vm_setenvFlag(env_clamp, env_clamp_def, BC_FLAG_DIGIT_CLAMP); |
|
1479 1480 // Clear the files and expressions vectors, just in case. This marks them as 1481 // *not* allocated. | 1592 1593 // Clear the files and expressions vectors, just in case. This marks them as 1594 // *not* allocated. |
1482 bc_vec_clear(&vm.files); 1483 bc_vec_clear(&vm.exprs); | 1595 bc_vec_clear(&vm->files); 1596 bc_vec_clear(&vm->exprs); |
1484 1485#if !BC_ENABLE_LIBRARY 1486 | 1597 1598#if !BC_ENABLE_LIBRARY 1599 |
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); | 1600 // Initialize the slab vector. 1601 bc_slabvec_init(&vm->slabs); |
1491 1492#endif // !BC_ENABLE_LIBRARY 1493 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. | 1602 1603#endif // !BC_ENABLE_LIBRARY 1604 1605 // Initialize the program and main parser. These have to be in this order 1606 // because the program has to be initialized first, since a pointer to it is 1607 // passed to the parser. |
1497 bc_program_init(&vm.prog); 1498 bc_parse_init(&vm.prs, &vm.prog, BC_PROG_MAIN); | 1608 bc_program_init(&vm->prog); 1609 bc_parse_init(&vm->prs, &vm->prog, BC_PROG_MAIN); |
1499 1500 // Set defaults. | 1610 1611 // Set defaults. |
1501 vm.flags |= BC_TTY ? BC_FLAG_P | BC_FLAG_R : 0; 1502 vm.flags |= BC_I ? BC_FLAG_Q : 0; | 1612 vm->flags |= BC_TTY ? BC_FLAG_P | BC_FLAG_R : 0; 1613 vm->flags |= BC_I ? BC_FLAG_Q : 0; |
1503 1504#if BC_ENABLED 1505 if (BC_IS_BC) 1506 { 1507 // bc checks this environment variable to see if it should run in 1508 // standard mode. 1509 char* var = bc_vm_getenv("POSIXLY_CORRECT"); 1510 | 1614 1615#if BC_ENABLED 1616 if (BC_IS_BC) 1617 { 1618 // bc checks this environment variable to see if it should run in 1619 // standard mode. 1620 char* var = bc_vm_getenv("POSIXLY_CORRECT"); 1621 |
1511 vm.flags |= BC_FLAG_S * (var != NULL); | 1622 vm->flags |= BC_FLAG_S * (var != NULL); |
1512 bc_vm_getenvFree(var); 1513 1514 // Set whether we print the banner or not. 1515 if (BC_I) bc_vm_setenvFlag("BC_BANNER", BC_DEFAULT_BANNER, BC_FLAG_Q); 1516 } 1517#endif // BC_ENABLED 1518 1519 // Are we in TTY mode? 1520 if (BC_TTY) 1521 { | 1623 bc_vm_getenvFree(var); 1624 1625 // Set whether we print the banner or not. 1626 if (BC_I) bc_vm_setenvFlag("BC_BANNER", BC_DEFAULT_BANNER, BC_FLAG_Q); 1627 } 1628#endif // BC_ENABLED 1629 1630 // Are we in TTY mode? 1631 if (BC_TTY) 1632 { |
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; | 1633 const char* const env_tty = BC_VM_TTY_MODE_STR; 1634 int env_tty_def = BC_VM_TTY_MODE_DEF; 1635 const char* const env_prompt = BC_VM_PROMPT_STR; 1636 int env_prompt_def = BC_VM_PROMPT_DEF; |
1526 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); 1530 1531#if BC_ENABLE_HISTORY 1532 // If TTY mode is used, activate history. | 1637 1638 // Set flags for TTY mode and prompt. 1639 bc_vm_setenvFlag(env_tty, env_tty_def, BC_FLAG_TTY); 1640 bc_vm_setenvFlag(env_prompt, tty ? env_prompt_def : 0, BC_FLAG_P); 1641 1642#if BC_ENABLE_HISTORY 1643 // If TTY mode is used, activate history. |
1533 if (BC_TTY) bc_history_init(&vm.history); | 1644 if (BC_TTY) bc_history_init(&vm->history); |
1534#endif // BC_ENABLE_HISTORY 1535 } 1536 1537 // Process environment and command-line arguments. | 1645#endif // BC_ENABLE_HISTORY 1646 } 1647 1648 // Process environment and command-line arguments. |
1538 bc_vm_envArgs(env_args); 1539 bc_args(argc, argv, true, BC_PROG_SCALE(&vm.prog)); | 1649 bc_vm_envArgs(env_args, &env_scale, &env_ibase, &env_obase); 1650 bc_args(argc, argv, true, &scale, &ibase, &obase); |
1540 | 1651 |
1652 // This section is here because we don't want the math library to stomp on 1653 // the user's given value for scale. And we don't want ibase affecting how 1654 // the scale is interpreted. Also, it's sectioned off just for this comment. 1655 { 1656 BC_SIG_UNLOCK; 1657 1658 scale = scale == BC_NUM_BIGDIG_MAX ? env_scale : scale; 1659#if BC_ENABLED 1660 // Assign the library value only if it is used and no value was set. 1661 scale = scale == BC_NUM_BIGDIG_MAX && BC_L ? 20 : scale; 1662#endif // BC_ENABLED 1663 obase = obase == BC_NUM_BIGDIG_MAX ? env_obase : obase; 1664 ibase = ibase == BC_NUM_BIGDIG_MAX ? env_ibase : ibase; 1665 1666 if (scale != BC_NUM_BIGDIG_MAX) 1667 { 1668 bc_program_assignBuiltin(&vm->prog, true, false, scale); 1669 } 1670 1671 if (obase != BC_NUM_BIGDIG_MAX) 1672 { 1673 bc_program_assignBuiltin(&vm->prog, false, true, obase); 1674 } 1675 1676 // This is last to avoid it affecting the value of the others. 1677 if (ibase != BC_NUM_BIGDIG_MAX) 1678 { 1679 bc_program_assignBuiltin(&vm->prog, false, false, ibase); 1680 } 1681 1682 BC_SIG_LOCK; 1683 } 1684 |
|
1541 // If we are in interactive mode... 1542 if (BC_I) 1543 { | 1685 // If we are in interactive mode... 1686 if (BC_I) 1687 { |
1544 const char* const env_sigint = BC_IS_BC ? "BC_SIGINT_RESET" : 1545 "DC_SIGINT_RESET"; 1546 int env_sigint_def = BC_IS_BC ? BC_DEFAULT_SIGINT_RESET : 1547 DC_DEFAULT_SIGINT_RESET; | 1688 const char* const env_sigint = BC_VM_SIGINT_RESET_STR; 1689 int env_sigint_def = BC_VM_SIGINT_RESET_DEF; |
1548 1549 // Set whether we reset on SIGINT or not. 1550 bc_vm_setenvFlag(env_sigint, env_sigint_def, BC_FLAG_SIGINT); 1551 } 1552 1553#if BC_ENABLED 1554 // Disable global stacks in POSIX mode. | 1690 1691 // Set whether we reset on SIGINT or not. 1692 bc_vm_setenvFlag(env_sigint, env_sigint_def, BC_FLAG_SIGINT); 1693 } 1694 1695#if BC_ENABLED 1696 // Disable global stacks in POSIX mode. |
1555 if (BC_IS_POSIX) vm.flags &= ~(BC_FLAG_G); | 1697 if (BC_IS_POSIX) vm->flags &= ~(BC_FLAG_G); |
1556 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. | 1698 1699 // Print the banner if allowed. We have to be in bc, in interactive mode, 1700 // and not be quieted by command-line option or environment variable. |
1559 if (BC_IS_BC && BC_I && (vm.flags & BC_FLAG_Q)) | 1701 if (BC_IS_BC && BC_I && (vm->flags & BC_FLAG_Q)) |
1560 { 1561 bc_vm_info(NULL); | 1702 { 1703 bc_vm_info(NULL); |
1562 bc_file_putchar(&vm.fout, bc_flush_none, '\n'); 1563 bc_file_flush(&vm.fout, bc_flush_none); | 1704 bc_file_putchar(&vm->fout, bc_flush_none, '\n'); 1705 bc_file_flush(&vm->fout, bc_flush_none); |
1564 } 1565#endif // BC_ENABLED 1566 1567 BC_SIG_UNLOCK; 1568 1569 // Start executing. 1570 bc_vm_exec(); 1571} 1572#endif // !BC_ENABLE_LIBRARY 1573 1574void 1575bc_vm_init(void) 1576{ | 1706 } 1707#endif // BC_ENABLED 1708 1709 BC_SIG_UNLOCK; 1710 1711 // Start executing. 1712 bc_vm_exec(); 1713} 1714#endif // !BC_ENABLE_LIBRARY 1715 1716void 1717bc_vm_init(void) 1718{ |
1719#if BC_ENABLE_LIBRARY 1720 BcVm* vm = bcl_getspecific(); 1721#endif // BC_ENABLE_LIBRARY 1722 |
|
1577 BC_SIG_ASSERT_LOCKED; 1578 1579#if !BC_ENABLE_LIBRARY 1580 // Set up the constant zero. | 1723 BC_SIG_ASSERT_LOCKED; 1724 1725#if !BC_ENABLE_LIBRARY 1726 // Set up the constant zero. |
1581 bc_num_setup(&vm.zero, vm.zero_num, BC_VM_ONE_CAP); | 1727 bc_num_setup(&vm->zero, vm->zero_num, BC_VM_ONE_CAP); |
1582#endif // !BC_ENABLE_LIBRARY 1583 1584 // Set up more constant BcNum's. | 1728#endif // !BC_ENABLE_LIBRARY 1729 1730 // 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); | 1731 bc_num_setup(&vm->one, vm->one_num, BC_VM_ONE_CAP); 1732 bc_num_one(&vm->one); |
1587 1588 // Set up more constant BcNum's. 1589 // NOLINTNEXTLINE | 1733 1734 // Set up more constant BcNum's. 1735 // NOLINTNEXTLINE |
1590 memcpy(vm.max_num, bc_num_bigdigMax, bc_num_bigdigMax_size * sizeof(BcDig)); | 1736 memcpy(vm->max_num, bc_num_bigdigMax, 1737 bc_num_bigdigMax_size * sizeof(BcDig)); |
1591 // NOLINTNEXTLINE | 1738 // NOLINTNEXTLINE |
1592 memcpy(vm.max2_num, bc_num_bigdigMax2, | 1739 memcpy(vm->max2_num, bc_num_bigdigMax2, |
1593 bc_num_bigdigMax2_size * sizeof(BcDig)); | 1740 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; | 1741 bc_num_setup(&vm->max, vm->max_num, BC_NUM_BIGDIG_LOG10); 1742 bc_num_setup(&vm->max2, vm->max2_num, BC_NUM_BIGDIG_LOG10); 1743 vm->max.len = bc_num_bigdigMax_size; 1744 vm->max2.len = bc_num_bigdigMax2_size; |
1598 1599 // Set up the maxes for the globals. | 1745 1746 // 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; | 1747 vm->maxes[BC_PROG_GLOBALS_IBASE] = BC_NUM_MAX_POSIX_IBASE; 1748 vm->maxes[BC_PROG_GLOBALS_OBASE] = BC_MAX_OBASE; 1749 vm->maxes[BC_PROG_GLOBALS_SCALE] = BC_MAX_SCALE; |
1603 1604#if BC_ENABLE_EXTRA_MATH | 1750 1751#if BC_ENABLE_EXTRA_MATH |
1605 vm.maxes[BC_PROG_MAX_RAND] = ((BcRand) 0) - 1; | 1752 vm->maxes[BC_PROG_MAX_RAND] = ((BcRand) 0) - 1; |
1606#endif // BC_ENABLE_EXTRA_MATH 1607 1608#if BC_ENABLED 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 1613 { | 1753#endif // BC_ENABLE_EXTRA_MATH 1754 1755#if BC_ENABLED 1756#if !BC_ENABLE_LIBRARY 1757 // bc has a higher max ibase when it's not in POSIX mode. 1758 if (BC_IS_BC && !BC_IS_POSIX) 1759#endif // !BC_ENABLE_LIBRARY 1760 { |
1614 vm.maxes[BC_PROG_GLOBALS_IBASE] = BC_NUM_MAX_IBASE; | 1761 vm->maxes[BC_PROG_GLOBALS_IBASE] = BC_NUM_MAX_IBASE; |
1615 } 1616#endif // BC_ENABLED 1617} 1618 1619#if BC_ENABLE_LIBRARY 1620void 1621bc_vm_atexit(void) 1622{ | 1762 } 1763#endif // BC_ENABLED 1764} 1765 1766#if BC_ENABLE_LIBRARY 1767void 1768bc_vm_atexit(void) 1769{ |
1770#ifndef NDEBUG 1771#if BC_ENABLE_LIBRARY 1772 BcVm* vm = bcl_getspecific(); 1773#endif // BC_ENABLE_LIBRARY 1774#endif // NDEBUG 1775 |
|
1623 bc_vm_shutdown(); 1624 1625#ifndef NDEBUG | 1776 bc_vm_shutdown(); 1777 1778#ifndef NDEBUG |
1626 bc_vec_free(&vm.jmp_bufs); | 1779 bc_vec_free(&vm->jmp_bufs); |
1627#endif // NDEBUG 1628} 1629#else // BC_ENABLE_LIBRARY 1630int 1631bc_vm_atexit(int status) 1632{ 1633 // Set the status correctly. 1634 int s = BC_STATUS_IS_ERROR(status) ? status : BC_STATUS_SUCCESS; 1635 1636 bc_vm_shutdown(); 1637 1638#ifndef NDEBUG | 1780#endif // NDEBUG 1781} 1782#else // BC_ENABLE_LIBRARY 1783int 1784bc_vm_atexit(int status) 1785{ 1786 // Set the status correctly. 1787 int s = BC_STATUS_IS_ERROR(status) ? status : BC_STATUS_SUCCESS; 1788 1789 bc_vm_shutdown(); 1790 1791#ifndef NDEBUG |
1639 bc_vec_free(&vm.jmp_bufs); | 1792 bc_vec_free(&vm->jmp_bufs); |
1640#endif // NDEBUG 1641 1642 return s; 1643} 1644#endif // BC_ENABLE_LIBRARY | 1793#endif // NDEBUG 1794 1795 return s; 1796} 1797#endif // BC_ENABLE_LIBRARY |