1 /* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2018-2021 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, 15 * this list of conditions and the following disclaimer in the documentation 16 * and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 * 30 * ***************************************************************************** 31 * 32 * Code for processing command-line arguments. 33 * 34 */ 35 36 #include <assert.h> 37 #include <ctype.h> 38 #include <stdbool.h> 39 #include <stdlib.h> 40 #include <string.h> 41 42 #ifndef _WIN32 43 #include <unistd.h> 44 #endif // _WIN32 45 46 #include <vector.h> 47 #include <read.h> 48 #include <args.h> 49 #include <opt.h> 50 51 static const BcOptLong bc_args_lopt[] = { 52 53 { "expression", BC_OPT_REQUIRED, 'e' }, 54 { "file", BC_OPT_REQUIRED, 'f' }, 55 { "help", BC_OPT_NONE, 'h' }, 56 { "interactive", BC_OPT_NONE, 'i' }, 57 { "no-prompt", BC_OPT_NONE, 'P' }, 58 { "no-read-prompt", BC_OPT_NONE, 'R' }, 59 #if BC_ENABLED 60 { "global-stacks", BC_OPT_BC_ONLY, 'g' }, 61 { "mathlib", BC_OPT_BC_ONLY, 'l' }, 62 { "quiet", BC_OPT_BC_ONLY, 'q' }, 63 { "standard", BC_OPT_BC_ONLY, 's' }, 64 { "warn", BC_OPT_BC_ONLY, 'w' }, 65 #endif // BC_ENABLED 66 { "version", BC_OPT_NONE, 'v' }, 67 { "version", BC_OPT_NONE, 'V' }, 68 #if DC_ENABLED 69 { "extended-register", BC_OPT_DC_ONLY, 'x' }, 70 #endif // DC_ENABLED 71 { NULL, 0, 0 }, 72 73 }; 74 75 static void bc_args_exprs(const char *str) { 76 BC_SIG_ASSERT_LOCKED; 77 if (vm.exprs.v == NULL) bc_vec_init(&vm.exprs, sizeof(uchar), NULL); 78 bc_vec_concat(&vm.exprs, str); 79 bc_vec_concat(&vm.exprs, "\n"); 80 } 81 82 static void bc_args_file(const char *file) { 83 84 char *buf; 85 86 BC_SIG_ASSERT_LOCKED; 87 88 vm.file = file; 89 90 bc_read_file(file, &buf); 91 bc_args_exprs(buf); 92 free(buf); 93 } 94 95 void bc_args(int argc, char *argv[], bool exit_exprs) { 96 97 int c; 98 size_t i; 99 bool do_exit = false, version = false; 100 BcOpt opts; 101 102 BC_SIG_ASSERT_LOCKED; 103 104 bc_opt_init(&opts, argv); 105 106 while ((c = bc_opt_parse(&opts, bc_args_lopt)) != -1) { 107 108 switch (c) { 109 110 case 'e': 111 { 112 if (vm.no_exit_exprs) 113 bc_vm_verr(BC_ERR_FATAL_OPTION, "-e (--expression)"); 114 bc_args_exprs(opts.optarg); 115 vm.exit_exprs = (exit_exprs || vm.exit_exprs); 116 break; 117 } 118 119 case 'f': 120 { 121 if (!strcmp(opts.optarg, "-")) vm.no_exit_exprs = true; 122 else { 123 if (vm.no_exit_exprs) 124 bc_vm_verr(BC_ERR_FATAL_OPTION, "-f (--file)"); 125 bc_args_file(opts.optarg); 126 vm.exit_exprs = (exit_exprs || vm.exit_exprs); 127 } 128 break; 129 } 130 131 case 'h': 132 { 133 bc_vm_info(vm.help); 134 do_exit = true; 135 break; 136 } 137 138 case 'i': 139 { 140 vm.flags |= BC_FLAG_I; 141 break; 142 } 143 144 case 'P': 145 { 146 vm.flags |= BC_FLAG_P; 147 break; 148 } 149 150 case 'R': 151 { 152 vm.flags |= BC_FLAG_R; 153 break; 154 } 155 156 #if BC_ENABLED 157 case 'g': 158 { 159 assert(BC_IS_BC); 160 vm.flags |= BC_FLAG_G; 161 break; 162 } 163 164 case 'l': 165 { 166 assert(BC_IS_BC); 167 vm.flags |= BC_FLAG_L; 168 break; 169 } 170 171 case 'q': 172 { 173 assert(BC_IS_BC); 174 // Do nothing. 175 break; 176 } 177 178 case 's': 179 { 180 assert(BC_IS_BC); 181 vm.flags |= BC_FLAG_S; 182 break; 183 } 184 185 case 'w': 186 { 187 assert(BC_IS_BC); 188 vm.flags |= BC_FLAG_W; 189 break; 190 } 191 #endif // BC_ENABLED 192 193 case 'V': 194 case 'v': 195 { 196 do_exit = version = true; 197 break; 198 } 199 200 #if DC_ENABLED 201 case 'x': 202 { 203 assert(BC_IS_DC); 204 vm.flags |= DC_FLAG_X; 205 break; 206 } 207 #endif // DC_ENABLED 208 209 #ifndef NDEBUG 210 // We shouldn't get here because bc_opt_error()/bc_vm_error() should 211 // longjmp() out. 212 case '?': 213 case ':': 214 default: 215 { 216 abort(); 217 } 218 #endif // NDEBUG 219 } 220 } 221 222 if (version) bc_vm_info(NULL); 223 if (do_exit) exit((int) vm.status); 224 225 if (opts.optind < (size_t) argc && vm.files.v == NULL) 226 bc_vec_init(&vm.files, sizeof(char*), NULL); 227 228 for (i = opts.optind; i < (size_t) argc; ++i) 229 bc_vec_push(&vm.files, argv + i); 230 } 231