1 1.62 kre /* $NetBSD: options.c,v 1.62 2024/10/14 09:10:35 kre Exp $ */ 2 1.11 cgd 3 1.1 cgd /*- 4 1.5 jtc * Copyright (c) 1991, 1993 5 1.5 jtc * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.1 cgd * Kenneth Almquist. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.35 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.25 christos #include <sys/cdefs.h> 36 1.1 cgd #ifndef lint 37 1.11 cgd #if 0 38 1.14 christos static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95"; 39 1.11 cgd #else 40 1.62 kre __RCSID("$NetBSD: options.c,v 1.62 2024/10/14 09:10:35 kre Exp $"); 41 1.11 cgd #endif 42 1.1 cgd #endif /* not lint */ 43 1.1 cgd 44 1.14 christos #include <signal.h> 45 1.14 christos #include <unistd.h> 46 1.14 christos #include <stdlib.h> 47 1.14 christos 48 1.1 cgd #include "shell.h" 49 1.1 cgd #define DEFINE_OPTIONS 50 1.1 cgd #include "options.h" 51 1.1 cgd #undef DEFINE_OPTIONS 52 1.42 christos #include "builtins.h" 53 1.1 cgd #include "nodes.h" /* for other header files */ 54 1.1 cgd #include "eval.h" 55 1.1 cgd #include "jobs.h" 56 1.1 cgd #include "input.h" 57 1.1 cgd #include "output.h" 58 1.1 cgd #include "trap.h" 59 1.1 cgd #include "var.h" 60 1.1 cgd #include "memalloc.h" 61 1.1 cgd #include "error.h" 62 1.1 cgd #include "mystring.h" 63 1.53 kre #include "syntax.h" 64 1.24 christos #ifndef SMALL 65 1.14 christos #include "myhistedit.h" 66 1.14 christos #endif 67 1.32 christos #include "show.h" 68 1.1 cgd 69 1.1 cgd char *arg0; /* value of $0 */ 70 1.1 cgd struct shparam shellparam; /* current positional parameters */ 71 1.1 cgd char **argptr; /* argument list for builtin commands */ 72 1.30 christos char *optionarg; /* set by nextopt (like getopt) */ 73 1.1 cgd char *optptr; /* used by nextopt */ 74 1.1 cgd 75 1.1 cgd char *minusc; /* argument to -c option */ 76 1.1 cgd 77 1.1 cgd 78 1.32 christos STATIC void options(int); 79 1.32 christos STATIC void minus_o(char *, int); 80 1.32 christos STATIC void setoption(int, int); 81 1.32 christos STATIC int getopts(char *, char *, char **, char ***, char **); 82 1.1 cgd 83 1.1 cgd 84 1.1 cgd /* 85 1.1 cgd * Process the shell command line arguments. 86 1.1 cgd */ 87 1.1 cgd 88 1.1 cgd void 89 1.32 christos procargs(int argc, char **argv) 90 1.10 cgd { 91 1.41 lukem size_t i; 92 1.48 kre int psx; 93 1.1 cgd 94 1.1 cgd argptr = argv; 95 1.1 cgd if (argc > 0) 96 1.1 cgd argptr++; 97 1.48 kre 98 1.48 kre psx = posix; /* save what we set it to earlier */ 99 1.48 kre /* 100 1.48 kre * option values are mostly boolean 0:off 1:on 101 1.48 kre * we use 2 (just in this routine) to mean "unknown yet" 102 1.48 kre */ 103 1.5 jtc for (i = 0; i < NOPTS; i++) 104 1.5 jtc optlist[i].val = 2; 105 1.48 kre posix = psx; /* restore before processing -o ... */ 106 1.48 kre 107 1.1 cgd options(1); 108 1.48 kre 109 1.1 cgd if (*argptr == NULL && minusc == NULL) 110 1.1 cgd sflag = 1; 111 1.50 kre if (iflag == 2 && sflag == 1 && isatty(0) && isatty(2)) 112 1.1 cgd iflag = 1; 113 1.39 christos if (iflag == 1 && sflag == 2) 114 1.39 christos iflag = 2; 115 1.5 jtc if (mflag == 2) 116 1.5 jtc mflag = iflag; 117 1.44 christos #ifndef DO_SHAREDVFORK 118 1.44 christos if (usefork == 2) 119 1.44 christos usefork = 1; 120 1.44 christos #endif 121 1.49 kre #if DEBUG >= 2 122 1.48 kre if (debug == 2) 123 1.48 kre debug = 1; 124 1.32 christos #endif 125 1.58 kre arg0 = argv[0]; 126 1.58 kre if (loginsh == 2 && arg0 != NULL && arg0[0] == '-') 127 1.58 kre loginsh = 1; 128 1.58 kre 129 1.48 kre /* 130 1.48 kre * Any options not dealt with as special cases just above, 131 1.48 kre * and which were not set on the command line, are set to 132 1.48 kre * their expected default values (mostly "off") 133 1.48 kre * 134 1.48 kre * then as each option is initialised, save its setting now 135 1.48 kre * as its "default" value for future use ("set -o default"). 136 1.48 kre */ 137 1.48 kre for (i = 0; i < NOPTS; i++) { 138 1.48 kre if (optlist[i].val == 2) 139 1.48 kre optlist[i].val = optlist[i].dflt; 140 1.48 kre optlist[i].dflt = optlist[i].val; 141 1.48 kre } 142 1.48 kre 143 1.1 cgd if (sflag == 0 && minusc == NULL) { 144 1.31 wiz commandname = argv[0]; 145 1.31 wiz arg0 = *argptr++; 146 1.31 wiz setinputfile(arg0, 0); 147 1.31 wiz commandname = arg0; 148 1.1 cgd } 149 1.17 christos /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ 150 1.33 dsl if (minusc != NULL) { 151 1.33 dsl if (argptr == NULL || *argptr == NULL) 152 1.33 dsl error("Bad -c option"); 153 1.33 dsl minusc = *argptr++; 154 1.33 dsl if (*argptr != 0) 155 1.33 dsl arg0 = *argptr++; 156 1.33 dsl } 157 1.17 christos 158 1.1 cgd shellparam.p = argptr; 159 1.19 christos shellparam.reset = 1; 160 1.1 cgd /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 161 1.1 cgd while (*argptr) { 162 1.1 cgd shellparam.nparam++; 163 1.1 cgd argptr++; 164 1.1 cgd } 165 1.5 jtc optschanged(); 166 1.1 cgd } 167 1.1 cgd 168 1.1 cgd 169 1.9 cgd void 170 1.32 christos optschanged(void) 171 1.9 cgd { 172 1.5 jtc setinteractive(iflag); 173 1.24 christos #ifndef SMALL 174 1.5 jtc histedit(); 175 1.7 cgd #endif 176 1.5 jtc setjobctl(mflag); 177 1.56 kre 178 1.56 kre if (privileged && !pflag) { 179 1.56 kre setuid(getuid()); 180 1.56 kre setgid(getgid()); 181 1.56 kre privileged = 0; 182 1.56 kre setvarsafe("PSc", (getuid() == 0 ? "#" : "$"), 0); 183 1.56 kre } 184 1.5 jtc } 185 1.1 cgd 186 1.1 cgd /* 187 1.1 cgd * Process shell options. The global variable argptr contains a pointer 188 1.1 cgd * to the argument list; we advance it past the options. 189 1.1 cgd */ 190 1.1 cgd 191 1.1 cgd STATIC void 192 1.32 christos options(int cmdline) 193 1.10 cgd { 194 1.37 christos static char empty[] = ""; 195 1.22 tls char *p; 196 1.1 cgd int val; 197 1.1 cgd int c; 198 1.1 cgd 199 1.1 cgd if (cmdline) 200 1.1 cgd minusc = NULL; 201 1.1 cgd while ((p = *argptr) != NULL) { 202 1.1 cgd argptr++; 203 1.1 cgd if ((c = *p++) == '-') { 204 1.1 cgd val = 1; 205 1.14 christos if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) { 206 1.1 cgd if (!cmdline) { 207 1.1 cgd /* "-" means turn off -x and -v */ 208 1.1 cgd if (p[0] == '\0') 209 1.1 cgd xflag = vflag = 0; 210 1.1 cgd /* "--" means reset params */ 211 1.13 christos else if (*argptr == NULL) 212 1.13 christos setparam(argptr); 213 1.1 cgd } 214 1.1 cgd break; /* "-" or "--" terminates options */ 215 1.1 cgd } 216 1.1 cgd } else if (c == '+') { 217 1.1 cgd val = 0; 218 1.1 cgd } else { 219 1.1 cgd argptr--; 220 1.1 cgd break; 221 1.1 cgd } 222 1.1 cgd while ((c = *p++) != '\0') { 223 1.48 kre if (val == 1 && c == 'c' && cmdline) { 224 1.37 christos /* command is after shell args*/ 225 1.37 christos minusc = empty; 226 1.5 jtc } else if (c == 'o') { 227 1.48 kre if (*p != '\0') 228 1.48 kre minus_o(p, val + (cmdline ? val : 0)); 229 1.48 kre else if (*argptr) 230 1.48 kre minus_o(*argptr++, 231 1.48 kre val + (cmdline ? val : 0)); 232 1.48 kre else if (!cmdline) 233 1.48 kre minus_o(NULL, val); 234 1.48 kre else 235 1.48 kre error("arg for %co missing", "+-"[val]); 236 1.48 kre break; 237 1.47 kre #ifdef DEBUG 238 1.47 kre } else if (c == 'D') { 239 1.47 kre if (*p) { 240 1.47 kre set_debug(p, val); 241 1.47 kre break; 242 1.47 kre } else if (*argptr) 243 1.47 kre set_debug(*argptr++, val); 244 1.47 kre else 245 1.47 kre set_debug("*$", val); 246 1.47 kre #endif 247 1.61 kre } else if (cmdline && c == 'r') { 248 1.62 kre out1fmt("NetBSD shell: %s\n", 249 1.62 kre lookupvar("NETBSD_SHELL")); 250 1.61 kre sh_exit(0); 251 1.1 cgd } else { 252 1.1 cgd setoption(c, val); 253 1.1 cgd } 254 1.1 cgd } 255 1.1 cgd } 256 1.1 cgd } 257 1.1 cgd 258 1.32 christos static void 259 1.41 lukem set_opt_val(size_t i, int val) 260 1.32 christos { 261 1.41 lukem size_t j; 262 1.32 christos int flag; 263 1.32 christos 264 1.32 christos if (val && (flag = optlist[i].opt_set)) { 265 1.32 christos /* some options (eg vi/emacs) are mutually exclusive */ 266 1.32 christos for (j = 0; j < NOPTS; j++) 267 1.32 christos if (optlist[j].opt_set == flag) 268 1.32 christos optlist[j].val = 0; 269 1.32 christos } 270 1.52 kre #ifndef SMALL 271 1.51 kre if (i == _SH_OPT_Xflag) 272 1.51 kre xtracefdsetup(val); 273 1.52 kre #endif 274 1.32 christos optlist[i].val = val; 275 1.32 christos #ifdef DEBUG 276 1.32 christos if (&optlist[i].val == &debug) 277 1.51 kre opentrace(); /* different "trace" than the -x one... */ 278 1.32 christos #endif 279 1.32 christos } 280 1.32 christos 281 1.5 jtc STATIC void 282 1.32 christos minus_o(char *name, int val) 283 1.5 jtc { 284 1.41 lukem size_t i; 285 1.46 christos const char *sep = ": "; 286 1.5 jtc 287 1.5 jtc if (name == NULL) { 288 1.40 dsl if (val) { 289 1.46 christos out1str("Current option settings"); 290 1.40 dsl for (i = 0; i < NOPTS; i++) { 291 1.46 christos if (optlist[i].name == NULL) { 292 1.46 christos out1fmt("%s%c%c", sep, 293 1.46 christos "+-"[optlist[i].val], 294 1.46 christos optlist[i].letter); 295 1.46 christos sep = ", "; 296 1.46 christos } 297 1.46 christos } 298 1.46 christos out1c('\n'); 299 1.46 christos for (i = 0; i < NOPTS; i++) { 300 1.46 christos if (optlist[i].name) 301 1.48 kre out1fmt("%-19s %s\n", optlist[i].name, 302 1.40 dsl optlist[i].val ? "on" : "off"); 303 1.40 dsl } 304 1.40 dsl } else { 305 1.48 kre out1str("set -o default"); 306 1.40 dsl for (i = 0; i < NOPTS; i++) { 307 1.48 kre if (optlist[i].val == optlist[i].dflt) 308 1.48 kre continue; 309 1.46 christos if (optlist[i].name) 310 1.46 christos out1fmt(" %co %s", 311 1.40 dsl "+-"[optlist[i].val], optlist[i].name); 312 1.46 christos else 313 1.46 christos out1fmt(" %c%c", "+-"[optlist[i].val], 314 1.46 christos optlist[i].letter); 315 1.40 dsl } 316 1.46 christos out1c('\n'); 317 1.40 dsl } 318 1.5 jtc } else { 319 1.48 kre if (val == 1 && equal(name, "default")) { /* special case */ 320 1.48 kre for (i = 0; i < NOPTS; i++) 321 1.48 kre set_opt_val(i, optlist[i].dflt); 322 1.48 kre return; 323 1.48 kre } 324 1.48 kre if (val) 325 1.48 kre val = 1; 326 1.5 jtc for (i = 0; i < NOPTS; i++) 327 1.46 christos if (optlist[i].name && equal(name, optlist[i].name)) { 328 1.32 christos set_opt_val(i, val); 329 1.52 kre #ifndef SMALL 330 1.51 kre if (i == _SH_OPT_Xflag) 331 1.51 kre set_opt_val(_SH_OPT_xflag, val); 332 1.52 kre #endif 333 1.5 jtc return; 334 1.5 jtc } 335 1.57 kre error("Unknown option %co %s", "+-"[val], name); 336 1.5 jtc } 337 1.5 jtc } 338 1.17 christos 339 1.1 cgd 340 1.1 cgd STATIC void 341 1.32 christos setoption(int flag, int val) 342 1.32 christos { 343 1.41 lukem size_t i; 344 1.1 cgd 345 1.5 jtc for (i = 0; i < NOPTS; i++) 346 1.5 jtc if (optlist[i].letter == flag) { 347 1.51 kre set_opt_val(i, val); 348 1.52 kre #ifndef SMALL 349 1.51 kre if (i == _SH_OPT_Xflag) 350 1.51 kre set_opt_val(_SH_OPT_xflag, val); 351 1.52 kre #endif 352 1.5 jtc return; 353 1.5 jtc } 354 1.57 kre error("Unknown option %c%c", "+-"[val], flag); 355 1.28 mycroft /* NOTREACHED */ 356 1.1 cgd } 357 1.1 cgd 358 1.1 cgd 359 1.1 cgd 360 1.1 cgd #ifdef mkinit 361 1.1 cgd INCLUDE "options.h" 362 1.1 cgd 363 1.1 cgd SHELLPROC { 364 1.5 jtc int i; 365 1.5 jtc 366 1.32 christos for (i = 0; optlist[i].name; i++) 367 1.5 jtc optlist[i].val = 0; 368 1.5 jtc optschanged(); 369 1.1 cgd 370 1.1 cgd } 371 1.1 cgd #endif 372 1.1 cgd 373 1.1 cgd 374 1.1 cgd /* 375 1.1 cgd * Set the shell parameters. 376 1.1 cgd */ 377 1.1 cgd 378 1.1 cgd void 379 1.32 christos setparam(char **argv) 380 1.32 christos { 381 1.1 cgd char **newparam; 382 1.1 cgd char **ap; 383 1.1 cgd int nparam; 384 1.1 cgd 385 1.38 dsl for (nparam = 0 ; argv[nparam] ; nparam++) 386 1.38 dsl continue; 387 1.1 cgd ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); 388 1.1 cgd while (*argv) { 389 1.1 cgd *ap++ = savestr(*argv++); 390 1.1 cgd } 391 1.1 cgd *ap = NULL; 392 1.1 cgd freeparam(&shellparam); 393 1.1 cgd shellparam.malloc = 1; 394 1.1 cgd shellparam.nparam = nparam; 395 1.1 cgd shellparam.p = newparam; 396 1.1 cgd shellparam.optnext = NULL; 397 1.1 cgd } 398 1.1 cgd 399 1.1 cgd 400 1.1 cgd /* 401 1.1 cgd * Free the list of positional parameters. 402 1.1 cgd */ 403 1.1 cgd 404 1.1 cgd void 405 1.32 christos freeparam(volatile struct shparam *param) 406 1.32 christos { 407 1.1 cgd char **ap; 408 1.1 cgd 409 1.1 cgd if (param->malloc) { 410 1.1 cgd for (ap = param->p ; *ap ; ap++) 411 1.1 cgd ckfree(*ap); 412 1.1 cgd ckfree(param->p); 413 1.1 cgd } 414 1.1 cgd } 415 1.1 cgd 416 1.1 cgd 417 1.1 cgd 418 1.1 cgd /* 419 1.1 cgd * The shift builtin command. 420 1.1 cgd */ 421 1.1 cgd 422 1.60 kre #ifndef TINY 423 1.60 kre /* first the rotate variant */ 424 1.60 kre static inline int 425 1.60 kre rotatecmd(int argc, char **argv) 426 1.60 kre { 427 1.60 kre int n; 428 1.60 kre char **ap1, **ap2, **ss; 429 1.60 kre 430 1.60 kre (void) nextopt(NULL); /* ignore '--' as leading option */ 431 1.60 kre 432 1.60 kre /* 433 1.60 kre * half this is just in case it ever becomes 434 1.60 kre * a separate named command, while it remains 435 1.60 kre * puerly an inline inside shift, the compiler 436 1.60 kre * should optimise most of it to nothingness 437 1.60 kre */ 438 1.60 kre if (argptr[0] && argptr[1]) 439 1.60 kre error("Usage: rotate [n]"); 440 1.60 kre n = 1; 441 1.60 kre if (*argptr) { 442 1.60 kre if (**argptr == '-') 443 1.60 kre n = number(*argptr + 1); 444 1.60 kre else /* anti-clockwise n == clockwise $# - n */ 445 1.60 kre n = shellparam.nparam - number(*argptr); 446 1.60 kre } 447 1.60 kre 448 1.60 kre if (n == 0 || n == shellparam.nparam) /* nothing to do */ 449 1.60 kre return 0; 450 1.60 kre 451 1.60 kre if (n < 0 || n > shellparam.nparam) 452 1.60 kre error("can't rotate that many"); 453 1.60 kre 454 1.60 kre ap2 = ss = (char **)stalloc(n * sizeof(char *)); 455 1.60 kre INTOFF; 456 1.60 kre for (ap1 = shellparam.p + shellparam.nparam - n; 457 1.60 kre ap1 < shellparam.p + shellparam.nparam; ) 458 1.60 kre *ap2++ = *ap1++; 459 1.60 kre for (ap2 = shellparam.p + shellparam.nparam, ap1 = ap2 - n; 460 1.60 kre ap1 > shellparam.p; ) 461 1.60 kre *--ap2 = *--ap1; 462 1.60 kre for (ap1 = ss + n; ap1 > ss; ) 463 1.60 kre *--ap2 = *--ap1; 464 1.60 kre shellparam.optnext = NULL; 465 1.60 kre INTON; 466 1.60 kre stunalloc(ss); 467 1.60 kre 468 1.60 kre return 0; 469 1.60 kre } 470 1.60 kre #endif 471 1.60 kre 472 1.10 cgd int 473 1.32 christos shiftcmd(int argc, char **argv) 474 1.10 cgd { 475 1.1 cgd int n; 476 1.1 cgd char **ap1, **ap2; 477 1.1 cgd 478 1.60 kre (void) nextopt(NULL); /* ignore '--' as leading option */ 479 1.60 kre 480 1.60 kre if (argptr[0] && argptr[1]) 481 1.45 christos error("Usage: shift [n]"); 482 1.60 kre 483 1.60 kre #ifndef TINY 484 1.60 kre if (*argptr && **argptr == '-') { 485 1.60 kre argptr = argv + 1; /* reinit nextopt() */ 486 1.60 kre optptr = NULL; 487 1.60 kre return rotatecmd(argc, argv); 488 1.60 kre } 489 1.60 kre #endif 490 1.60 kre 491 1.1 cgd n = 1; 492 1.60 kre if (*argptr) 493 1.60 kre n = number(*argptr); 494 1.1 cgd if (n > shellparam.nparam) 495 1.5 jtc error("can't shift that many"); 496 1.1 cgd INTOFF; 497 1.1 cgd shellparam.nparam -= n; 498 1.1 cgd for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { 499 1.1 cgd if (shellparam.malloc) 500 1.1 cgd ckfree(*ap1); 501 1.1 cgd } 502 1.1 cgd ap2 = shellparam.p; 503 1.45 christos while ((*ap2++ = *ap1++) != NULL) 504 1.45 christos continue; 505 1.1 cgd shellparam.optnext = NULL; 506 1.1 cgd INTON; 507 1.1 cgd return 0; 508 1.1 cgd } 509 1.1 cgd 510 1.1 cgd 511 1.1 cgd 512 1.1 cgd /* 513 1.1 cgd * The set command builtin. 514 1.1 cgd */ 515 1.1 cgd 516 1.10 cgd int 517 1.32 christos setcmd(int argc, char **argv) 518 1.10 cgd { 519 1.1 cgd if (argc == 1) 520 1.46 christos return showvars(0, 0, 1, 0); 521 1.1 cgd INTOFF; 522 1.1 cgd options(0); 523 1.5 jtc optschanged(); 524 1.1 cgd if (*argptr != NULL) { 525 1.1 cgd setparam(argptr); 526 1.1 cgd } 527 1.1 cgd INTON; 528 1.1 cgd return 0; 529 1.1 cgd } 530 1.1 cgd 531 1.1 cgd 532 1.16 christos void 533 1.59 kre getoptsreset(char *value, int flags __unused) 534 1.16 christos { 535 1.53 kre /* 536 1.53 kre * This is just to detect the case where OPTIND=1 537 1.53 kre * is executed. Any other string assigned to OPTIND 538 1.53 kre * is OK, but is not a reset. No errors, so cannot use number() 539 1.53 kre */ 540 1.53 kre if (is_digit(*value) && strtol(value, NULL, 10) == 1) { 541 1.18 christos shellparam.optnext = NULL; 542 1.19 christos shellparam.reset = 1; 543 1.19 christos } 544 1.16 christos } 545 1.16 christos 546 1.1 cgd /* 547 1.1 cgd * The getopts builtin. Shellparam.optnext points to the next argument 548 1.1 cgd * to be processed. Shellparam.optptr points to the next character to 549 1.1 cgd * be processed in the current argument. If shellparam.optnext is NULL, 550 1.1 cgd * then it's the first time getopts has been called. 551 1.1 cgd */ 552 1.1 cgd 553 1.10 cgd int 554 1.32 christos getoptscmd(int argc, char **argv) 555 1.10 cgd { 556 1.15 christos char **optbase; 557 1.15 christos 558 1.15 christos if (argc < 3) 559 1.36 jmmv error("usage: getopts optstring var [arg]"); 560 1.15 christos else if (argc == 3) 561 1.15 christos optbase = shellparam.p; 562 1.17 christos else 563 1.15 christos optbase = &argv[3]; 564 1.1 cgd 565 1.19 christos if (shellparam.reset == 1) { 566 1.15 christos shellparam.optnext = optbase; 567 1.1 cgd shellparam.optptr = NULL; 568 1.19 christos shellparam.reset = 0; 569 1.1 cgd } 570 1.15 christos 571 1.15 christos return getopts(argv[1], argv[2], optbase, &shellparam.optnext, 572 1.15 christos &shellparam.optptr); 573 1.15 christos } 574 1.15 christos 575 1.15 christos STATIC int 576 1.32 christos getopts(char *optstr, char *optvar, char **optfirst, char ***optnext, char **optpptr) 577 1.15 christos { 578 1.22 tls char *p, *q; 579 1.15 christos char c = '?'; 580 1.15 christos int done = 0; 581 1.15 christos int ind = 0; 582 1.16 christos int err = 0; 583 1.34 itojun char s[12]; 584 1.15 christos 585 1.29 christos if ((p = *optpptr) == NULL || *p == '\0') { 586 1.15 christos /* Current word is done, advance */ 587 1.19 christos if (*optnext == NULL) 588 1.19 christos return 1; 589 1.15 christos p = **optnext; 590 1.1 cgd if (p == NULL || *p != '-' || *++p == '\0') { 591 1.1 cgd atend: 592 1.21 christos ind = *optnext - optfirst + 1; 593 1.20 christos *optnext = NULL; 594 1.21 christos p = NULL; 595 1.15 christos done = 1; 596 1.15 christos goto out; 597 1.1 cgd } 598 1.15 christos (*optnext)++; 599 1.1 cgd if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 600 1.1 cgd goto atend; 601 1.1 cgd } 602 1.15 christos 603 1.1 cgd c = *p++; 604 1.15 christos for (q = optstr; *q != c; ) { 605 1.1 cgd if (*q == '\0') { 606 1.15 christos if (optstr[0] == ':') { 607 1.15 christos s[0] = c; 608 1.15 christos s[1] = '\0'; 609 1.16 christos err |= setvarsafe("OPTARG", s, 0); 610 1.32 christos } else { 611 1.57 kre outfmt(&errout, "Unknown option -%c\n", c); 612 1.32 christos (void) unsetvar("OPTARG", 0); 613 1.15 christos } 614 1.1 cgd c = '?'; 615 1.16 christos goto bad; 616 1.1 cgd } 617 1.1 cgd if (*++q == ':') 618 1.1 cgd q++; 619 1.1 cgd } 620 1.15 christos 621 1.1 cgd if (*++q == ':') { 622 1.15 christos if (*p == '\0' && (p = **optnext) == NULL) { 623 1.15 christos if (optstr[0] == ':') { 624 1.15 christos s[0] = c; 625 1.15 christos s[1] = '\0'; 626 1.16 christos err |= setvarsafe("OPTARG", s, 0); 627 1.15 christos c = ':'; 628 1.32 christos } else { 629 1.26 christos outfmt(&errout, "No arg for -%c option\n", c); 630 1.32 christos (void) unsetvar("OPTARG", 0); 631 1.15 christos c = '?'; 632 1.15 christos } 633 1.16 christos goto bad; 634 1.1 cgd } 635 1.15 christos 636 1.15 christos if (p == **optnext) 637 1.15 christos (*optnext)++; 638 1.32 christos err |= setvarsafe("OPTARG", p, 0); 639 1.1 cgd p = NULL; 640 1.32 christos } else 641 1.32 christos err |= setvarsafe("OPTARG", "", 0); 642 1.19 christos ind = *optnext - optfirst + 1; 643 1.19 christos goto out; 644 1.19 christos 645 1.16 christos bad: 646 1.16 christos ind = 1; 647 1.16 christos *optnext = NULL; 648 1.16 christos p = NULL; 649 1.1 cgd out: 650 1.29 christos *optpptr = p; 651 1.15 christos fmtstr(s, sizeof(s), "%d", ind); 652 1.16 christos err |= setvarsafe("OPTIND", s, VNOFUNC); 653 1.1 cgd s[0] = c; 654 1.1 cgd s[1] = '\0'; 655 1.16 christos err |= setvarsafe(optvar, s, 0); 656 1.16 christos if (err) { 657 1.16 christos *optnext = NULL; 658 1.29 christos *optpptr = NULL; 659 1.16 christos flushall(); 660 1.16 christos exraise(EXERROR); 661 1.16 christos } 662 1.15 christos return done; 663 1.1 cgd } 664 1.1 cgd 665 1.1 cgd /* 666 1.5 jtc * XXX - should get rid of. have all builtins use getopt(3). the 667 1.5 jtc * library getopt must have the BSD extension static variable "optreset" 668 1.5 jtc * otherwise it can't be used within the shell safely. 669 1.5 jtc * 670 1.1 cgd * Standard option processing (a la getopt) for builtin routines. The 671 1.1 cgd * only argument that is passed to nextopt is the option string; the 672 1.1 cgd * other arguments are unnecessary. It return the character, or '\0' on 673 1.54 kre * end of input. If optstring is NULL, then there are no options, and 674 1.54 kre * args are allowed to begin with '-', but a single leading "--" will be 675 1.54 kre * discarded. This is for some POSIX special builtins that require 676 1.54 kre * -- processing, have no args, and we never did opt processing before 677 1.54 kre * and need to retain backwards compat. 678 1.1 cgd */ 679 1.1 cgd 680 1.1 cgd int 681 1.32 christos nextopt(const char *optstring) 682 1.32 christos { 683 1.29 christos char *p; 684 1.29 christos const char *q; 685 1.1 cgd char c; 686 1.1 cgd 687 1.1 cgd if ((p = optptr) == NULL || *p == '\0') { 688 1.1 cgd p = *argptr; 689 1.1 cgd if (p == NULL || *p != '-' || *++p == '\0') 690 1.1 cgd return '\0'; 691 1.1 cgd argptr++; 692 1.1 cgd if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 693 1.1 cgd return '\0'; 694 1.55 kre if (optstring == NULL) /* not processing the "option" */ 695 1.55 kre argptr--; /* so make it be an arg again */ 696 1.1 cgd } 697 1.54 kre if (optstring == NULL) 698 1.54 kre return '\0'; 699 1.1 cgd c = *p++; 700 1.1 cgd for (q = optstring ; *q != c ; ) { 701 1.1 cgd if (*q == '\0') 702 1.57 kre error("Unknown option -%c", c); 703 1.1 cgd if (*++q == ':') 704 1.1 cgd q++; 705 1.1 cgd } 706 1.1 cgd if (*++q == ':') { 707 1.1 cgd if (*p == '\0' && (p = *argptr++) == NULL) 708 1.1 cgd error("No arg for -%c option", c); 709 1.30 christos optionarg = p; 710 1.1 cgd p = NULL; 711 1.1 cgd } 712 1.1 cgd optptr = p; 713 1.1 cgd return c; 714 1.1 cgd } 715