1252884aeSStefan Eßer /* 2252884aeSStefan Eßer * ***************************************************************************** 3252884aeSStefan Eßer * 43aa99676SStefan Eßer * SPDX-License-Identifier: BSD-2-Clause 5252884aeSStefan Eßer * 610328f8bSStefan Eßer * Copyright (c) 2018-2021 Gavin D. Howard and contributors. 7252884aeSStefan Eßer * 8252884aeSStefan Eßer * Redistribution and use in source and binary forms, with or without 9252884aeSStefan Eßer * modification, are permitted provided that the following conditions are met: 10252884aeSStefan Eßer * 11252884aeSStefan Eßer * * Redistributions of source code must retain the above copyright notice, this 12252884aeSStefan Eßer * list of conditions and the following disclaimer. 13252884aeSStefan Eßer * 14252884aeSStefan Eßer * * Redistributions in binary form must reproduce the above copyright notice, 15252884aeSStefan Eßer * this list of conditions and the following disclaimer in the documentation 16252884aeSStefan Eßer * and/or other materials provided with the distribution. 17252884aeSStefan Eßer * 18252884aeSStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19252884aeSStefan Eßer * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20252884aeSStefan Eßer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21252884aeSStefan Eßer * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22252884aeSStefan Eßer * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23252884aeSStefan Eßer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24252884aeSStefan Eßer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25252884aeSStefan Eßer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26252884aeSStefan Eßer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27252884aeSStefan Eßer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28252884aeSStefan Eßer * POSSIBILITY OF SUCH DAMAGE. 29252884aeSStefan Eßer * 30252884aeSStefan Eßer * ***************************************************************************** 31252884aeSStefan Eßer * 32252884aeSStefan Eßer * Code for processing command-line arguments. 33252884aeSStefan Eßer * 34252884aeSStefan Eßer */ 35252884aeSStefan Eßer 36252884aeSStefan Eßer #include <assert.h> 37252884aeSStefan Eßer #include <ctype.h> 38252884aeSStefan Eßer #include <stdbool.h> 39252884aeSStefan Eßer #include <stdlib.h> 40252884aeSStefan Eßer #include <string.h> 41252884aeSStefan Eßer 427e5c51e5SStefan Eßer #ifndef _WIN32 43252884aeSStefan Eßer #include <unistd.h> 447e5c51e5SStefan Eßer #endif // _WIN32 45252884aeSStefan Eßer 46252884aeSStefan Eßer #include <vector.h> 47252884aeSStefan Eßer #include <read.h> 48252884aeSStefan Eßer #include <args.h> 49252884aeSStefan Eßer #include <opt.h> 50252884aeSStefan Eßer 5144d4804dSStefan Eßer /** 5244d4804dSStefan Eßer * Adds @a str to the list of expressions to execute later. 5344d4804dSStefan Eßer * @param str The string to add to the list of expressions. 5444d4804dSStefan Eßer */ 55252884aeSStefan Eßer static void bc_args_exprs(const char *str) { 56252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 5744d4804dSStefan Eßer if (vm.exprs.v == NULL) bc_vec_init(&vm.exprs, sizeof(uchar), BC_DTOR_NONE); 58252884aeSStefan Eßer bc_vec_concat(&vm.exprs, str); 59252884aeSStefan Eßer bc_vec_concat(&vm.exprs, "\n"); 60252884aeSStefan Eßer } 61252884aeSStefan Eßer 6244d4804dSStefan Eßer /** 6344d4804dSStefan Eßer * Adds the contents of @a file to the list of expressions to execute later. 6444d4804dSStefan Eßer * @param file The name of the file whose contents should be added to the list 6544d4804dSStefan Eßer * of expressions to execute. 6644d4804dSStefan Eßer */ 67252884aeSStefan Eßer static void bc_args_file(const char *file) { 68252884aeSStefan Eßer 69252884aeSStefan Eßer char *buf; 70252884aeSStefan Eßer 71252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 72252884aeSStefan Eßer 73252884aeSStefan Eßer vm.file = file; 74252884aeSStefan Eßer 7544d4804dSStefan Eßer buf = bc_read_file(file); 7644d4804dSStefan Eßer 7744d4804dSStefan Eßer assert(buf != NULL); 7844d4804dSStefan Eßer 79252884aeSStefan Eßer bc_args_exprs(buf); 80252884aeSStefan Eßer free(buf); 81252884aeSStefan Eßer } 82252884aeSStefan Eßer 8344d4804dSStefan Eßer #if BC_ENABLED 8444d4804dSStefan Eßer 8544d4804dSStefan Eßer /** 8644d4804dSStefan Eßer * Redefines a keyword, if it exists and is not a POSIX keyword. Otherwise, it 8744d4804dSStefan Eßer * throws a fatal error. 8844d4804dSStefan Eßer * @param keyword The keyword to redefine. 8944d4804dSStefan Eßer */ 9044d4804dSStefan Eßer static void bc_args_redefine(const char *keyword) { 9144d4804dSStefan Eßer 9244d4804dSStefan Eßer size_t i; 9344d4804dSStefan Eßer 94*10041e99SStefan Eßer BC_SIG_ASSERT_LOCKED; 95*10041e99SStefan Eßer 9644d4804dSStefan Eßer for (i = 0; i < bc_lex_kws_len; ++i) { 9744d4804dSStefan Eßer 9844d4804dSStefan Eßer const BcLexKeyword *kw = bc_lex_kws + i; 9944d4804dSStefan Eßer 10044d4804dSStefan Eßer if (!strcmp(keyword, kw->name)) { 10144d4804dSStefan Eßer 10244d4804dSStefan Eßer if (BC_LEX_KW_POSIX(kw)) break; 10344d4804dSStefan Eßer 10444d4804dSStefan Eßer vm.redefined_kws[i] = true; 10544d4804dSStefan Eßer 10644d4804dSStefan Eßer return; 10744d4804dSStefan Eßer } 10844d4804dSStefan Eßer } 10944d4804dSStefan Eßer 11044d4804dSStefan Eßer bc_error(BC_ERR_FATAL_ARG, 0, keyword); 11144d4804dSStefan Eßer } 11244d4804dSStefan Eßer 11344d4804dSStefan Eßer #endif // BC_ENABLED 11444d4804dSStefan Eßer 1159a995fe1SStefan Eßer void bc_args(int argc, char *argv[], bool exit_exprs) { 116252884aeSStefan Eßer 117252884aeSStefan Eßer int c; 118252884aeSStefan Eßer size_t i; 119252884aeSStefan Eßer bool do_exit = false, version = false; 120252884aeSStefan Eßer BcOpt opts; 121252884aeSStefan Eßer 122252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 123252884aeSStefan Eßer 124252884aeSStefan Eßer bc_opt_init(&opts, argv); 125252884aeSStefan Eßer 12644d4804dSStefan Eßer // This loop should look familiar to anyone who has used getopt() or 12744d4804dSStefan Eßer // getopt_long() in C. 128252884aeSStefan Eßer while ((c = bc_opt_parse(&opts, bc_args_lopt)) != -1) { 129252884aeSStefan Eßer 130252884aeSStefan Eßer switch (c) { 131252884aeSStefan Eßer 132252884aeSStefan Eßer case 'e': 133252884aeSStefan Eßer { 13444d4804dSStefan Eßer // Barf if not allowed. 13544d4804dSStefan Eßer if (vm.no_exprs) 13644d4804dSStefan Eßer bc_verr(BC_ERR_FATAL_OPTION, "-e (--expression)"); 13744d4804dSStefan Eßer 13844d4804dSStefan Eßer // Add the expressions and set exit. 139252884aeSStefan Eßer bc_args_exprs(opts.optarg); 1409a995fe1SStefan Eßer vm.exit_exprs = (exit_exprs || vm.exit_exprs); 14144d4804dSStefan Eßer 142252884aeSStefan Eßer break; 143252884aeSStefan Eßer } 144252884aeSStefan Eßer 145252884aeSStefan Eßer case 'f': 146252884aeSStefan Eßer { 14744d4804dSStefan Eßer // Figure out if exiting on expressions is disabled. 14844d4804dSStefan Eßer if (!strcmp(opts.optarg, "-")) vm.no_exprs = true; 1495d934bc0SStefan Eßer else { 15044d4804dSStefan Eßer 15144d4804dSStefan Eßer // Barf if not allowed. 15244d4804dSStefan Eßer if (vm.no_exprs) 15344d4804dSStefan Eßer bc_verr(BC_ERR_FATAL_OPTION, "-f (--file)"); 15444d4804dSStefan Eßer 15544d4804dSStefan Eßer // Add the expressions and set exit. 156252884aeSStefan Eßer bc_args_file(opts.optarg); 1579a995fe1SStefan Eßer vm.exit_exprs = (exit_exprs || vm.exit_exprs); 1585d934bc0SStefan Eßer } 15944d4804dSStefan Eßer 160252884aeSStefan Eßer break; 161252884aeSStefan Eßer } 162252884aeSStefan Eßer 163252884aeSStefan Eßer case 'h': 164252884aeSStefan Eßer { 165252884aeSStefan Eßer bc_vm_info(vm.help); 166252884aeSStefan Eßer do_exit = true; 167252884aeSStefan Eßer break; 168252884aeSStefan Eßer } 169252884aeSStefan Eßer 170252884aeSStefan Eßer case 'i': 171252884aeSStefan Eßer { 172252884aeSStefan Eßer vm.flags |= BC_FLAG_I; 173252884aeSStefan Eßer break; 174252884aeSStefan Eßer } 175252884aeSStefan Eßer 176d43fa8efSStefan Eßer case 'z': 177d43fa8efSStefan Eßer { 178d43fa8efSStefan Eßer vm.flags |= BC_FLAG_Z; 179d43fa8efSStefan Eßer break; 180d43fa8efSStefan Eßer } 181d43fa8efSStefan Eßer 182d43fa8efSStefan Eßer case 'L': 183d43fa8efSStefan Eßer { 184d43fa8efSStefan Eßer vm.line_len = 0; 185d43fa8efSStefan Eßer break; 186d43fa8efSStefan Eßer } 187d43fa8efSStefan Eßer 188252884aeSStefan Eßer case 'P': 189252884aeSStefan Eßer { 19044d4804dSStefan Eßer vm.flags &= ~(BC_FLAG_P); 191252884aeSStefan Eßer break; 192252884aeSStefan Eßer } 193252884aeSStefan Eßer 1947e5c51e5SStefan Eßer case 'R': 1957e5c51e5SStefan Eßer { 19644d4804dSStefan Eßer vm.flags &= ~(BC_FLAG_R); 1977e5c51e5SStefan Eßer break; 1987e5c51e5SStefan Eßer } 1997e5c51e5SStefan Eßer 200252884aeSStefan Eßer #if BC_ENABLED 201252884aeSStefan Eßer case 'g': 202252884aeSStefan Eßer { 203252884aeSStefan Eßer assert(BC_IS_BC); 204252884aeSStefan Eßer vm.flags |= BC_FLAG_G; 205252884aeSStefan Eßer break; 206252884aeSStefan Eßer } 207252884aeSStefan Eßer 208252884aeSStefan Eßer case 'l': 209252884aeSStefan Eßer { 210252884aeSStefan Eßer assert(BC_IS_BC); 211252884aeSStefan Eßer vm.flags |= BC_FLAG_L; 212252884aeSStefan Eßer break; 213252884aeSStefan Eßer } 214252884aeSStefan Eßer 215252884aeSStefan Eßer case 'q': 216252884aeSStefan Eßer { 217252884aeSStefan Eßer assert(BC_IS_BC); 218d43fa8efSStefan Eßer vm.flags &= ~(BC_FLAG_Q); 219252884aeSStefan Eßer break; 220252884aeSStefan Eßer } 221252884aeSStefan Eßer 22244d4804dSStefan Eßer case 'r': 22344d4804dSStefan Eßer { 22444d4804dSStefan Eßer bc_args_redefine(opts.optarg); 22544d4804dSStefan Eßer break; 22644d4804dSStefan Eßer } 22744d4804dSStefan Eßer 228252884aeSStefan Eßer case 's': 229252884aeSStefan Eßer { 230252884aeSStefan Eßer assert(BC_IS_BC); 231252884aeSStefan Eßer vm.flags |= BC_FLAG_S; 232252884aeSStefan Eßer break; 233252884aeSStefan Eßer } 234252884aeSStefan Eßer 235252884aeSStefan Eßer case 'w': 236252884aeSStefan Eßer { 237252884aeSStefan Eßer assert(BC_IS_BC); 238252884aeSStefan Eßer vm.flags |= BC_FLAG_W; 239252884aeSStefan Eßer break; 240252884aeSStefan Eßer } 241252884aeSStefan Eßer #endif // BC_ENABLED 242252884aeSStefan Eßer 243252884aeSStefan Eßer case 'V': 244252884aeSStefan Eßer case 'v': 245252884aeSStefan Eßer { 246252884aeSStefan Eßer do_exit = version = true; 247252884aeSStefan Eßer break; 248252884aeSStefan Eßer } 249252884aeSStefan Eßer 250252884aeSStefan Eßer #if DC_ENABLED 251252884aeSStefan Eßer case 'x': 252252884aeSStefan Eßer { 2533aa99676SStefan Eßer assert(BC_IS_DC); 254252884aeSStefan Eßer vm.flags |= DC_FLAG_X; 255252884aeSStefan Eßer break; 256252884aeSStefan Eßer } 257252884aeSStefan Eßer #endif // DC_ENABLED 258252884aeSStefan Eßer 259252884aeSStefan Eßer #ifndef NDEBUG 26044d4804dSStefan Eßer // We shouldn't get here because bc_opt_error()/bc_error() should 261252884aeSStefan Eßer // longjmp() out. 262252884aeSStefan Eßer case '?': 263252884aeSStefan Eßer case ':': 264252884aeSStefan Eßer default: 265252884aeSStefan Eßer { 26644d4804dSStefan Eßer BC_UNREACHABLE 267252884aeSStefan Eßer abort(); 268252884aeSStefan Eßer } 269252884aeSStefan Eßer #endif // NDEBUG 270252884aeSStefan Eßer } 271252884aeSStefan Eßer } 272252884aeSStefan Eßer 273252884aeSStefan Eßer if (version) bc_vm_info(NULL); 27444d4804dSStefan Eßer if (do_exit) { 27544d4804dSStefan Eßer vm.status = (sig_atomic_t) BC_STATUS_QUIT; 27644d4804dSStefan Eßer BC_JMP; 27744d4804dSStefan Eßer } 278252884aeSStefan Eßer 27944d4804dSStefan Eßer // We do not print the banner if expressions are used or dc is used. 28044d4804dSStefan Eßer if (!BC_IS_BC || vm.exprs.len > 1) vm.flags &= ~(BC_FLAG_Q); 28144d4804dSStefan Eßer 28244d4804dSStefan Eßer // We need to make sure the files list is initialized. We don't want to 28344d4804dSStefan Eßer // initialize it if there are no files because it's just a waste of memory. 2845d934bc0SStefan Eßer if (opts.optind < (size_t) argc && vm.files.v == NULL) 28544d4804dSStefan Eßer bc_vec_init(&vm.files, sizeof(char*), BC_DTOR_NONE); 286252884aeSStefan Eßer 28744d4804dSStefan Eßer // Add all the files to the vector. 288252884aeSStefan Eßer for (i = opts.optind; i < (size_t) argc; ++i) 289252884aeSStefan Eßer bc_vec_push(&vm.files, argv + i); 290252884aeSStefan Eßer } 291