1*da7ff22aSkre /* $NetBSD: options.c,v 1.62 2024/10/14 09:10:35 kre Exp $ */ 249f0ad86Scgd 361f28255Scgd /*- 437ed7877Sjtc * Copyright (c) 1991, 1993 537ed7877Sjtc * The Regents of the University of California. All rights reserved. 661f28255Scgd * 761f28255Scgd * This code is derived from software contributed to Berkeley by 861f28255Scgd * Kenneth Almquist. 961f28255Scgd * 1061f28255Scgd * Redistribution and use in source and binary forms, with or without 1161f28255Scgd * modification, are permitted provided that the following conditions 1261f28255Scgd * are met: 1361f28255Scgd * 1. Redistributions of source code must retain the above copyright 1461f28255Scgd * notice, this list of conditions and the following disclaimer. 1561f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright 1661f28255Scgd * notice, this list of conditions and the following disclaimer in the 1761f28255Scgd * documentation and/or other materials provided with the distribution. 18b5b29542Sagc * 3. Neither the name of the University nor the names of its contributors 1961f28255Scgd * may be used to endorse or promote products derived from this software 2061f28255Scgd * without specific prior written permission. 2161f28255Scgd * 2261f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2361f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2461f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2561f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2661f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2761f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2861f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2961f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3061f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3161f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3261f28255Scgd * SUCH DAMAGE. 3361f28255Scgd */ 3461f28255Scgd 35cd799663Schristos #include <sys/cdefs.h> 3661f28255Scgd #ifndef lint 3749f0ad86Scgd #if 0 3807bae7edSchristos static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95"; 3949f0ad86Scgd #else 40*da7ff22aSkre __RCSID("$NetBSD: options.c,v 1.62 2024/10/14 09:10:35 kre Exp $"); 4149f0ad86Scgd #endif 4261f28255Scgd #endif /* not lint */ 4361f28255Scgd 4407bae7edSchristos #include <signal.h> 4507bae7edSchristos #include <unistd.h> 4607bae7edSchristos #include <stdlib.h> 4707bae7edSchristos 4861f28255Scgd #include "shell.h" 4961f28255Scgd #define DEFINE_OPTIONS 5061f28255Scgd #include "options.h" 5161f28255Scgd #undef DEFINE_OPTIONS 524fc4fe2eSchristos #include "builtins.h" 5361f28255Scgd #include "nodes.h" /* for other header files */ 5461f28255Scgd #include "eval.h" 5561f28255Scgd #include "jobs.h" 5661f28255Scgd #include "input.h" 5761f28255Scgd #include "output.h" 5861f28255Scgd #include "trap.h" 5961f28255Scgd #include "var.h" 6061f28255Scgd #include "memalloc.h" 6161f28255Scgd #include "error.h" 6261f28255Scgd #include "mystring.h" 63c6c29888Skre #include "syntax.h" 647accaec4Schristos #ifndef SMALL 6507bae7edSchristos #include "myhistedit.h" 6607bae7edSchristos #endif 67c02b3bbdSchristos #include "show.h" 6861f28255Scgd 6961f28255Scgd char *arg0; /* value of $0 */ 7061f28255Scgd struct shparam shellparam; /* current positional parameters */ 7161f28255Scgd char **argptr; /* argument list for builtin commands */ 7233809804Schristos char *optionarg; /* set by nextopt (like getopt) */ 7361f28255Scgd char *optptr; /* used by nextopt */ 7461f28255Scgd 7561f28255Scgd char *minusc; /* argument to -c option */ 7661f28255Scgd 7761f28255Scgd 78c02b3bbdSchristos STATIC void options(int); 79c02b3bbdSchristos STATIC void minus_o(char *, int); 80c02b3bbdSchristos STATIC void setoption(int, int); 81c02b3bbdSchristos STATIC int getopts(char *, char *, char **, char ***, char **); 8261f28255Scgd 8361f28255Scgd 8461f28255Scgd /* 8561f28255Scgd * Process the shell command line arguments. 8661f28255Scgd */ 8761f28255Scgd 8861f28255Scgd void 89c02b3bbdSchristos procargs(int argc, char **argv) 9061f28255Scgd { 91c6144e48Slukem size_t i; 92d98a8b3cSkre int psx; 9361f28255Scgd 9461f28255Scgd argptr = argv; 9561f28255Scgd if (argc > 0) 9661f28255Scgd argptr++; 97d98a8b3cSkre 98d98a8b3cSkre psx = posix; /* save what we set it to earlier */ 99d98a8b3cSkre /* 100d98a8b3cSkre * option values are mostly boolean 0:off 1:on 101d98a8b3cSkre * we use 2 (just in this routine) to mean "unknown yet" 102d98a8b3cSkre */ 10337ed7877Sjtc for (i = 0; i < NOPTS; i++) 10437ed7877Sjtc optlist[i].val = 2; 105d98a8b3cSkre posix = psx; /* restore before processing -o ... */ 106d98a8b3cSkre 10761f28255Scgd options(1); 108d98a8b3cSkre 10961f28255Scgd if (*argptr == NULL && minusc == NULL) 11061f28255Scgd sflag = 1; 111a373e69aSkre if (iflag == 2 && sflag == 1 && isatty(0) && isatty(2)) 11261f28255Scgd iflag = 1; 113b0d51313Schristos if (iflag == 1 && sflag == 2) 114b0d51313Schristos iflag = 2; 11537ed7877Sjtc if (mflag == 2) 11637ed7877Sjtc mflag = iflag; 117750aa922Schristos #ifndef DO_SHAREDVFORK 118750aa922Schristos if (usefork == 2) 119750aa922Schristos usefork = 1; 120750aa922Schristos #endif 1218ffd1099Skre #if DEBUG >= 2 122d98a8b3cSkre if (debug == 2) 123c02b3bbdSchristos debug = 1; 124c02b3bbdSchristos #endif 125e7b0505eSkre arg0 = argv[0]; 126e7b0505eSkre if (loginsh == 2 && arg0 != NULL && arg0[0] == '-') 127e7b0505eSkre loginsh = 1; 128e7b0505eSkre 129d98a8b3cSkre /* 130d98a8b3cSkre * Any options not dealt with as special cases just above, 131d98a8b3cSkre * and which were not set on the command line, are set to 132d98a8b3cSkre * their expected default values (mostly "off") 133d98a8b3cSkre * 134d98a8b3cSkre * then as each option is initialised, save its setting now 135d98a8b3cSkre * as its "default" value for future use ("set -o default"). 136d98a8b3cSkre */ 137d98a8b3cSkre for (i = 0; i < NOPTS; i++) { 138d98a8b3cSkre if (optlist[i].val == 2) 139d98a8b3cSkre optlist[i].val = optlist[i].dflt; 140d98a8b3cSkre optlist[i].dflt = optlist[i].val; 141d98a8b3cSkre } 142d98a8b3cSkre 14361f28255Scgd if (sflag == 0 && minusc == NULL) { 1448d35854bSwiz commandname = argv[0]; 1458d35854bSwiz arg0 = *argptr++; 1468d35854bSwiz setinputfile(arg0, 0); 1478d35854bSwiz commandname = arg0; 14861f28255Scgd } 149fd8c9943Schristos /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ 150e314f958Sdsl if (minusc != NULL) { 151e314f958Sdsl if (argptr == NULL || *argptr == NULL) 152e314f958Sdsl error("Bad -c option"); 153e314f958Sdsl minusc = *argptr++; 154e314f958Sdsl if (*argptr != 0) 155fd8c9943Schristos arg0 = *argptr++; 156e314f958Sdsl } 157fd8c9943Schristos 15861f28255Scgd shellparam.p = argptr; 159ccce082dSchristos shellparam.reset = 1; 16061f28255Scgd /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 16161f28255Scgd while (*argptr) { 16261f28255Scgd shellparam.nparam++; 16361f28255Scgd argptr++; 16461f28255Scgd } 16537ed7877Sjtc optschanged(); 16661f28255Scgd } 16761f28255Scgd 16861f28255Scgd 1695dad1439Scgd void 170c02b3bbdSchristos optschanged(void) 1715dad1439Scgd { 17237ed7877Sjtc setinteractive(iflag); 1737accaec4Schristos #ifndef SMALL 17437ed7877Sjtc histedit(); 175e3c63ad9Scgd #endif 17637ed7877Sjtc setjobctl(mflag); 1774ca0efa9Skre 1784ca0efa9Skre if (privileged && !pflag) { 1794ca0efa9Skre setuid(getuid()); 1804ca0efa9Skre setgid(getgid()); 1814ca0efa9Skre privileged = 0; 1824ca0efa9Skre setvarsafe("PSc", (getuid() == 0 ? "#" : "$"), 0); 1834ca0efa9Skre } 18437ed7877Sjtc } 18561f28255Scgd 18661f28255Scgd /* 18761f28255Scgd * Process shell options. The global variable argptr contains a pointer 18861f28255Scgd * to the argument list; we advance it past the options. 18961f28255Scgd */ 19061f28255Scgd 19161f28255Scgd STATIC void 192c02b3bbdSchristos options(int cmdline) 1934ce0d34aScgd { 194027df12dSchristos static char empty[] = ""; 19548250187Stls char *p; 19661f28255Scgd int val; 19761f28255Scgd int c; 19861f28255Scgd 19961f28255Scgd if (cmdline) 20061f28255Scgd minusc = NULL; 20161f28255Scgd while ((p = *argptr) != NULL) { 20261f28255Scgd argptr++; 20361f28255Scgd if ((c = *p++) == '-') { 20461f28255Scgd val = 1; 20507bae7edSchristos if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) { 20661f28255Scgd if (!cmdline) { 20761f28255Scgd /* "-" means turn off -x and -v */ 20861f28255Scgd if (p[0] == '\0') 20961f28255Scgd xflag = vflag = 0; 21061f28255Scgd /* "--" means reset params */ 2116ee2193dSchristos else if (*argptr == NULL) 21261f28255Scgd setparam(argptr); 21361f28255Scgd } 21461f28255Scgd break; /* "-" or "--" terminates options */ 21561f28255Scgd } 21661f28255Scgd } else if (c == '+') { 21761f28255Scgd val = 0; 21861f28255Scgd } else { 21961f28255Scgd argptr--; 22061f28255Scgd break; 22161f28255Scgd } 22261f28255Scgd while ((c = *p++) != '\0') { 223d98a8b3cSkre if (val == 1 && c == 'c' && cmdline) { 224027df12dSchristos /* command is after shell args*/ 225027df12dSchristos minusc = empty; 22637ed7877Sjtc } else if (c == 'o') { 227d98a8b3cSkre if (*p != '\0') 228d98a8b3cSkre minus_o(p, val + (cmdline ? val : 0)); 229d98a8b3cSkre else if (*argptr) 230d98a8b3cSkre minus_o(*argptr++, 231d98a8b3cSkre val + (cmdline ? val : 0)); 232d98a8b3cSkre else if (!cmdline) 233d98a8b3cSkre minus_o(NULL, val); 234d98a8b3cSkre else 235d98a8b3cSkre error("arg for %co missing", "+-"[val]); 236d98a8b3cSkre break; 237ab36694aSkre #ifdef DEBUG 238ab36694aSkre } else if (c == 'D') { 239ab36694aSkre if (*p) { 240ab36694aSkre set_debug(p, val); 241ab36694aSkre break; 242ab36694aSkre } else if (*argptr) 243ab36694aSkre set_debug(*argptr++, val); 244ab36694aSkre else 245ab36694aSkre set_debug("*$", val); 246ab36694aSkre #endif 2472ecc8e99Skre } else if (cmdline && c == 'r') { 248*da7ff22aSkre out1fmt("NetBSD shell: %s\n", 249*da7ff22aSkre lookupvar("NETBSD_SHELL")); 2502ecc8e99Skre sh_exit(0); 25161f28255Scgd } else { 25261f28255Scgd setoption(c, val); 25361f28255Scgd } 25461f28255Scgd } 25537ed7877Sjtc } 25637ed7877Sjtc } 25737ed7877Sjtc 258c02b3bbdSchristos static void 259c6144e48Slukem set_opt_val(size_t i, int val) 260c02b3bbdSchristos { 261c6144e48Slukem size_t j; 262c02b3bbdSchristos int flag; 263c02b3bbdSchristos 264c02b3bbdSchristos if (val && (flag = optlist[i].opt_set)) { 265c02b3bbdSchristos /* some options (eg vi/emacs) are mutually exclusive */ 266c02b3bbdSchristos for (j = 0; j < NOPTS; j++) 267c02b3bbdSchristos if (optlist[j].opt_set == flag) 268c02b3bbdSchristos optlist[j].val = 0; 269c02b3bbdSchristos } 270ae40879bSkre #ifndef SMALL 271ffc64c63Skre if (i == _SH_OPT_Xflag) 272ffc64c63Skre xtracefdsetup(val); 273ae40879bSkre #endif 274c02b3bbdSchristos optlist[i].val = val; 275c02b3bbdSchristos #ifdef DEBUG 276c02b3bbdSchristos if (&optlist[i].val == &debug) 277ffc64c63Skre opentrace(); /* different "trace" than the -x one... */ 278c02b3bbdSchristos #endif 279c02b3bbdSchristos } 280c02b3bbdSchristos 28137ed7877Sjtc STATIC void 282c02b3bbdSchristos minus_o(char *name, int val) 28337ed7877Sjtc { 284c6144e48Slukem size_t i; 2859302f8efSchristos const char *sep = ": "; 28637ed7877Sjtc 28737ed7877Sjtc if (name == NULL) { 288ea207881Sdsl if (val) { 2899302f8efSchristos out1str("Current option settings"); 290ea207881Sdsl for (i = 0; i < NOPTS; i++) { 2919302f8efSchristos if (optlist[i].name == NULL) { 2929302f8efSchristos out1fmt("%s%c%c", sep, 2939302f8efSchristos "+-"[optlist[i].val], 2949302f8efSchristos optlist[i].letter); 2959302f8efSchristos sep = ", "; 2969302f8efSchristos } 2979302f8efSchristos } 2989302f8efSchristos out1c('\n'); 2999302f8efSchristos for (i = 0; i < NOPTS; i++) { 3009302f8efSchristos if (optlist[i].name) 301d98a8b3cSkre out1fmt("%-19s %s\n", optlist[i].name, 30237ed7877Sjtc optlist[i].val ? "on" : "off"); 303ea207881Sdsl } 304ea207881Sdsl } else { 305d98a8b3cSkre out1str("set -o default"); 306ea207881Sdsl for (i = 0; i < NOPTS; i++) { 307d98a8b3cSkre if (optlist[i].val == optlist[i].dflt) 308d98a8b3cSkre continue; 3099302f8efSchristos if (optlist[i].name) 310ea207881Sdsl out1fmt(" %co %s", 311ea207881Sdsl "+-"[optlist[i].val], optlist[i].name); 3129302f8efSchristos else 3139302f8efSchristos out1fmt(" %c%c", "+-"[optlist[i].val], 3149302f8efSchristos optlist[i].letter); 315ea207881Sdsl } 3169302f8efSchristos out1c('\n'); 317ea207881Sdsl } 31837ed7877Sjtc } else { 319d98a8b3cSkre if (val == 1 && equal(name, "default")) { /* special case */ 320d98a8b3cSkre for (i = 0; i < NOPTS; i++) 321d98a8b3cSkre set_opt_val(i, optlist[i].dflt); 322d98a8b3cSkre return; 323d98a8b3cSkre } 324d98a8b3cSkre if (val) 325d98a8b3cSkre val = 1; 32637ed7877Sjtc for (i = 0; i < NOPTS; i++) 3279302f8efSchristos if (optlist[i].name && equal(name, optlist[i].name)) { 328c02b3bbdSchristos set_opt_val(i, val); 329ae40879bSkre #ifndef SMALL 330ffc64c63Skre if (i == _SH_OPT_Xflag) 331ffc64c63Skre set_opt_val(_SH_OPT_xflag, val); 332ae40879bSkre #endif 33337ed7877Sjtc return; 33437ed7877Sjtc } 33594d6cf1cSkre error("Unknown option %co %s", "+-"[val], name); 33661f28255Scgd } 33761f28255Scgd } 33861f28255Scgd 33961f28255Scgd 34061f28255Scgd STATIC void 341c02b3bbdSchristos setoption(int flag, int val) 34261f28255Scgd { 343c6144e48Slukem size_t i; 34461f28255Scgd 34537ed7877Sjtc for (i = 0; i < NOPTS; i++) 34637ed7877Sjtc if (optlist[i].letter == flag) { 347c02b3bbdSchristos set_opt_val(i, val); 348ae40879bSkre #ifndef SMALL 349ffc64c63Skre if (i == _SH_OPT_Xflag) 350ffc64c63Skre set_opt_val(_SH_OPT_xflag, val); 351ae40879bSkre #endif 35237ed7877Sjtc return; 35337ed7877Sjtc } 35494d6cf1cSkre error("Unknown option %c%c", "+-"[val], flag); 355ee9e50eaSmycroft /* NOTREACHED */ 35661f28255Scgd } 35761f28255Scgd 35861f28255Scgd 35961f28255Scgd 36061f28255Scgd #ifdef mkinit 36161f28255Scgd INCLUDE "options.h" 36261f28255Scgd 36361f28255Scgd SHELLPROC { 36437ed7877Sjtc int i; 36561f28255Scgd 366c02b3bbdSchristos for (i = 0; optlist[i].name; i++) 36737ed7877Sjtc optlist[i].val = 0; 36837ed7877Sjtc optschanged(); 36937ed7877Sjtc 37061f28255Scgd } 37161f28255Scgd #endif 37261f28255Scgd 37361f28255Scgd 37461f28255Scgd /* 37561f28255Scgd * Set the shell parameters. 37661f28255Scgd */ 37761f28255Scgd 37861f28255Scgd void 379c02b3bbdSchristos setparam(char **argv) 38061f28255Scgd { 38161f28255Scgd char **newparam; 38261f28255Scgd char **ap; 38361f28255Scgd int nparam; 38461f28255Scgd 385aecb1ce4Sdsl for (nparam = 0 ; argv[nparam] ; nparam++) 386aecb1ce4Sdsl continue; 38761f28255Scgd ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); 38861f28255Scgd while (*argv) { 38961f28255Scgd *ap++ = savestr(*argv++); 39061f28255Scgd } 39161f28255Scgd *ap = NULL; 39261f28255Scgd freeparam(&shellparam); 39361f28255Scgd shellparam.malloc = 1; 39461f28255Scgd shellparam.nparam = nparam; 39561f28255Scgd shellparam.p = newparam; 39661f28255Scgd shellparam.optnext = NULL; 39761f28255Scgd } 39861f28255Scgd 39961f28255Scgd 40061f28255Scgd /* 40161f28255Scgd * Free the list of positional parameters. 40261f28255Scgd */ 40361f28255Scgd 40461f28255Scgd void 405c02b3bbdSchristos freeparam(volatile struct shparam *param) 40661f28255Scgd { 40761f28255Scgd char **ap; 40861f28255Scgd 40961f28255Scgd if (param->malloc) { 41061f28255Scgd for (ap = param->p ; *ap ; ap++) 41161f28255Scgd ckfree(*ap); 41261f28255Scgd ckfree(param->p); 41361f28255Scgd } 41461f28255Scgd } 41561f28255Scgd 41661f28255Scgd 41761f28255Scgd 41861f28255Scgd /* 41961f28255Scgd * The shift builtin command. 42061f28255Scgd */ 42161f28255Scgd 4222f76de8bSkre #ifndef TINY 4232f76de8bSkre /* first the rotate variant */ 4242f76de8bSkre static inline int 4252f76de8bSkre rotatecmd(int argc, char **argv) 4262f76de8bSkre { 4272f76de8bSkre int n; 4282f76de8bSkre char **ap1, **ap2, **ss; 4292f76de8bSkre 4302f76de8bSkre (void) nextopt(NULL); /* ignore '--' as leading option */ 4312f76de8bSkre 4322f76de8bSkre /* 4332f76de8bSkre * half this is just in case it ever becomes 4342f76de8bSkre * a separate named command, while it remains 4352f76de8bSkre * puerly an inline inside shift, the compiler 4362f76de8bSkre * should optimise most of it to nothingness 4372f76de8bSkre */ 4382f76de8bSkre if (argptr[0] && argptr[1]) 4392f76de8bSkre error("Usage: rotate [n]"); 4402f76de8bSkre n = 1; 4412f76de8bSkre if (*argptr) { 4422f76de8bSkre if (**argptr == '-') 4432f76de8bSkre n = number(*argptr + 1); 4442f76de8bSkre else /* anti-clockwise n == clockwise $# - n */ 4452f76de8bSkre n = shellparam.nparam - number(*argptr); 4462f76de8bSkre } 4472f76de8bSkre 4482f76de8bSkre if (n == 0 || n == shellparam.nparam) /* nothing to do */ 4492f76de8bSkre return 0; 4502f76de8bSkre 4512f76de8bSkre if (n < 0 || n > shellparam.nparam) 4522f76de8bSkre error("can't rotate that many"); 4532f76de8bSkre 4542f76de8bSkre ap2 = ss = (char **)stalloc(n * sizeof(char *)); 4552f76de8bSkre INTOFF; 4562f76de8bSkre for (ap1 = shellparam.p + shellparam.nparam - n; 4572f76de8bSkre ap1 < shellparam.p + shellparam.nparam; ) 4582f76de8bSkre *ap2++ = *ap1++; 4592f76de8bSkre for (ap2 = shellparam.p + shellparam.nparam, ap1 = ap2 - n; 4602f76de8bSkre ap1 > shellparam.p; ) 4612f76de8bSkre *--ap2 = *--ap1; 4622f76de8bSkre for (ap1 = ss + n; ap1 > ss; ) 4632f76de8bSkre *--ap2 = *--ap1; 4642f76de8bSkre shellparam.optnext = NULL; 4652f76de8bSkre INTON; 4662f76de8bSkre stunalloc(ss); 4672f76de8bSkre 4682f76de8bSkre return 0; 4692f76de8bSkre } 4702f76de8bSkre #endif 4712f76de8bSkre 4724ce0d34aScgd int 473c02b3bbdSchristos shiftcmd(int argc, char **argv) 4744ce0d34aScgd { 47561f28255Scgd int n; 47661f28255Scgd char **ap1, **ap2; 47761f28255Scgd 4782f76de8bSkre (void) nextopt(NULL); /* ignore '--' as leading option */ 4792f76de8bSkre 4802f76de8bSkre if (argptr[0] && argptr[1]) 481bff14f8dSchristos error("Usage: shift [n]"); 4822f76de8bSkre 4832f76de8bSkre #ifndef TINY 4842f76de8bSkre if (*argptr && **argptr == '-') { 4852f76de8bSkre argptr = argv + 1; /* reinit nextopt() */ 4862f76de8bSkre optptr = NULL; 4872f76de8bSkre return rotatecmd(argc, argv); 4882f76de8bSkre } 4892f76de8bSkre #endif 4902f76de8bSkre 49161f28255Scgd n = 1; 4922f76de8bSkre if (*argptr) 4932f76de8bSkre n = number(*argptr); 49461f28255Scgd if (n > shellparam.nparam) 49537ed7877Sjtc error("can't shift that many"); 49661f28255Scgd INTOFF; 49761f28255Scgd shellparam.nparam -= n; 49861f28255Scgd for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { 49961f28255Scgd if (shellparam.malloc) 50061f28255Scgd ckfree(*ap1); 50161f28255Scgd } 50261f28255Scgd ap2 = shellparam.p; 503bff14f8dSchristos while ((*ap2++ = *ap1++) != NULL) 504bff14f8dSchristos continue; 50561f28255Scgd shellparam.optnext = NULL; 50661f28255Scgd INTON; 50761f28255Scgd return 0; 50861f28255Scgd } 50961f28255Scgd 51061f28255Scgd 51161f28255Scgd 51261f28255Scgd /* 51361f28255Scgd * The set command builtin. 51461f28255Scgd */ 51561f28255Scgd 5164ce0d34aScgd int 517c02b3bbdSchristos setcmd(int argc, char **argv) 5184ce0d34aScgd { 51961f28255Scgd if (argc == 1) 5209302f8efSchristos return showvars(0, 0, 1, 0); 52161f28255Scgd INTOFF; 52261f28255Scgd options(0); 52337ed7877Sjtc optschanged(); 52461f28255Scgd if (*argptr != NULL) { 52561f28255Scgd setparam(argptr); 52661f28255Scgd } 52761f28255Scgd INTON; 52861f28255Scgd return 0; 52961f28255Scgd } 53061f28255Scgd 53161f28255Scgd 532cc31700aSchristos void 533d73cf48cSkre getoptsreset(char *value, int flags __unused) 534cc31700aSchristos { 535c6c29888Skre /* 536c6c29888Skre * This is just to detect the case where OPTIND=1 537c6c29888Skre * is executed. Any other string assigned to OPTIND 538c6c29888Skre * is OK, but is not a reset. No errors, so cannot use number() 539c6c29888Skre */ 540c6c29888Skre if (is_digit(*value) && strtol(value, NULL, 10) == 1) { 541846dce0eSchristos shellparam.optnext = NULL; 542ccce082dSchristos shellparam.reset = 1; 543ccce082dSchristos } 544cc31700aSchristos } 545cc31700aSchristos 54661f28255Scgd /* 54761f28255Scgd * The getopts builtin. Shellparam.optnext points to the next argument 54861f28255Scgd * to be processed. Shellparam.optptr points to the next character to 54961f28255Scgd * be processed in the current argument. If shellparam.optnext is NULL, 55061f28255Scgd * then it's the first time getopts has been called. 55161f28255Scgd */ 55261f28255Scgd 5534ce0d34aScgd int 554c02b3bbdSchristos getoptscmd(int argc, char **argv) 5554ce0d34aScgd { 5560bc88b24Schristos char **optbase; 55761f28255Scgd 5580bc88b24Schristos if (argc < 3) 559b635f565Sjmmv error("usage: getopts optstring var [arg]"); 5600bc88b24Schristos else if (argc == 3) 5610bc88b24Schristos optbase = shellparam.p; 5620bc88b24Schristos else 5630bc88b24Schristos optbase = &argv[3]; 5640bc88b24Schristos 565ccce082dSchristos if (shellparam.reset == 1) { 5660bc88b24Schristos shellparam.optnext = optbase; 56761f28255Scgd shellparam.optptr = NULL; 568ccce082dSchristos shellparam.reset = 0; 56961f28255Scgd } 5700bc88b24Schristos 5710bc88b24Schristos return getopts(argv[1], argv[2], optbase, &shellparam.optnext, 5720bc88b24Schristos &shellparam.optptr); 5730bc88b24Schristos } 5740bc88b24Schristos 5750bc88b24Schristos STATIC int 576c02b3bbdSchristos getopts(char *optstr, char *optvar, char **optfirst, char ***optnext, char **optpptr) 5770bc88b24Schristos { 57848250187Stls char *p, *q; 5790bc88b24Schristos char c = '?'; 5800bc88b24Schristos int done = 0; 5810bc88b24Schristos int ind = 0; 582cc31700aSchristos int err = 0; 583e6a384fcSitojun char s[12]; 5840bc88b24Schristos 5853d424690Schristos if ((p = *optpptr) == NULL || *p == '\0') { 5860bc88b24Schristos /* Current word is done, advance */ 587ccce082dSchristos if (*optnext == NULL) 588ccce082dSchristos return 1; 5890bc88b24Schristos p = **optnext; 59061f28255Scgd if (p == NULL || *p != '-' || *++p == '\0') { 59161f28255Scgd atend: 5920bc88b24Schristos ind = *optnext - optfirst + 1; 593a00e49c2Schristos *optnext = NULL; 594a00e49c2Schristos p = NULL; 5950bc88b24Schristos done = 1; 5960bc88b24Schristos goto out; 59761f28255Scgd } 5980bc88b24Schristos (*optnext)++; 59961f28255Scgd if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 60061f28255Scgd goto atend; 60161f28255Scgd } 6020bc88b24Schristos 60361f28255Scgd c = *p++; 6040bc88b24Schristos for (q = optstr; *q != c; ) { 60561f28255Scgd if (*q == '\0') { 6060bc88b24Schristos if (optstr[0] == ':') { 6070bc88b24Schristos s[0] = c; 6080bc88b24Schristos s[1] = '\0'; 609cc31700aSchristos err |= setvarsafe("OPTARG", s, 0); 610c02b3bbdSchristos } else { 61194d6cf1cSkre outfmt(&errout, "Unknown option -%c\n", c); 612c02b3bbdSchristos (void) unsetvar("OPTARG", 0); 6130bc88b24Schristos } 61461f28255Scgd c = '?'; 615cc31700aSchristos goto bad; 61661f28255Scgd } 61761f28255Scgd if (*++q == ':') 61861f28255Scgd q++; 61961f28255Scgd } 6200bc88b24Schristos 62161f28255Scgd if (*++q == ':') { 6220bc88b24Schristos if (*p == '\0' && (p = **optnext) == NULL) { 6230bc88b24Schristos if (optstr[0] == ':') { 6240bc88b24Schristos s[0] = c; 6250bc88b24Schristos s[1] = '\0'; 626cc31700aSchristos err |= setvarsafe("OPTARG", s, 0); 6270bc88b24Schristos c = ':'; 628c02b3bbdSchristos } else { 629d2ded939Schristos outfmt(&errout, "No arg for -%c option\n", c); 630c02b3bbdSchristos (void) unsetvar("OPTARG", 0); 63161f28255Scgd c = '?'; 6320bc88b24Schristos } 633cc31700aSchristos goto bad; 63461f28255Scgd } 6350bc88b24Schristos 6360bc88b24Schristos if (p == **optnext) 6370bc88b24Schristos (*optnext)++; 638c02b3bbdSchristos err |= setvarsafe("OPTARG", p, 0); 63961f28255Scgd p = NULL; 640c02b3bbdSchristos } else 641c02b3bbdSchristos err |= setvarsafe("OPTARG", "", 0); 642ccce082dSchristos ind = *optnext - optfirst + 1; 643ccce082dSchristos goto out; 644ccce082dSchristos 645cc31700aSchristos bad: 646cc31700aSchristos ind = 1; 647cc31700aSchristos *optnext = NULL; 648cc31700aSchristos p = NULL; 64961f28255Scgd out: 6503d424690Schristos *optpptr = p; 6510bc88b24Schristos fmtstr(s, sizeof(s), "%d", ind); 652cc31700aSchristos err |= setvarsafe("OPTIND", s, VNOFUNC); 65361f28255Scgd s[0] = c; 65461f28255Scgd s[1] = '\0'; 655cc31700aSchristos err |= setvarsafe(optvar, s, 0); 656cc31700aSchristos if (err) { 657cc31700aSchristos *optnext = NULL; 6583d424690Schristos *optpptr = NULL; 659cc31700aSchristos flushall(); 660cc31700aSchristos exraise(EXERROR); 661cc31700aSchristos } 6620bc88b24Schristos return done; 66361f28255Scgd } 66461f28255Scgd 66561f28255Scgd /* 66637ed7877Sjtc * XXX - should get rid of. have all builtins use getopt(3). the 66737ed7877Sjtc * library getopt must have the BSD extension static variable "optreset" 66837ed7877Sjtc * otherwise it can't be used within the shell safely. 66937ed7877Sjtc * 67061f28255Scgd * Standard option processing (a la getopt) for builtin routines. The 67161f28255Scgd * only argument that is passed to nextopt is the option string; the 67261f28255Scgd * other arguments are unnecessary. It return the character, or '\0' on 673ebc4cf1cSkre * end of input. If optstring is NULL, then there are no options, and 674ebc4cf1cSkre * args are allowed to begin with '-', but a single leading "--" will be 675ebc4cf1cSkre * discarded. This is for some POSIX special builtins that require 676ebc4cf1cSkre * -- processing, have no args, and we never did opt processing before 677ebc4cf1cSkre * and need to retain backwards compat. 67861f28255Scgd */ 67961f28255Scgd 68061f28255Scgd int 681c02b3bbdSchristos nextopt(const char *optstring) 68261f28255Scgd { 6833d424690Schristos char *p; 6843d424690Schristos const char *q; 68561f28255Scgd char c; 68661f28255Scgd 68761f28255Scgd if ((p = optptr) == NULL || *p == '\0') { 68861f28255Scgd p = *argptr; 68961f28255Scgd if (p == NULL || *p != '-' || *++p == '\0') 69061f28255Scgd return '\0'; 69161f28255Scgd argptr++; 69261f28255Scgd if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 69361f28255Scgd return '\0'; 69492dfd40cSkre if (optstring == NULL) /* not processing the "option" */ 69592dfd40cSkre argptr--; /* so make it be an arg again */ 69661f28255Scgd } 697ebc4cf1cSkre if (optstring == NULL) 698ebc4cf1cSkre return '\0'; 69961f28255Scgd c = *p++; 70061f28255Scgd for (q = optstring ; *q != c ; ) { 70161f28255Scgd if (*q == '\0') 70294d6cf1cSkre error("Unknown option -%c", c); 70361f28255Scgd if (*++q == ':') 70461f28255Scgd q++; 70561f28255Scgd } 70661f28255Scgd if (*++q == ':') { 70761f28255Scgd if (*p == '\0' && (p = *argptr++) == NULL) 70861f28255Scgd error("No arg for -%c option", c); 70933809804Schristos optionarg = p; 71061f28255Scgd p = NULL; 71161f28255Scgd } 71261f28255Scgd optptr = p; 71361f28255Scgd return c; 71461f28255Scgd } 715