11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1991, 1993 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Kenneth Almquist. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 4. Neither the name of the University nor the names of its contributors 171556Srgrimes * may be used to endorse or promote products derived from this software 181556Srgrimes * without specific prior written permission. 191556Srgrimes * 201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301556Srgrimes * SUCH DAMAGE. 311556Srgrimes */ 321556Srgrimes 331556Srgrimes#ifndef lint 3436150Scharnier#if 0 3536150Scharnierstatic char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95"; 3636150Scharnier#endif 371556Srgrimes#endif /* not lint */ 3899110Sobrien#include <sys/cdefs.h> 3999110Sobrien__FBSDID("$FreeBSD$"); 401556Srgrimes 4117987Speter#include <signal.h> 4217987Speter#include <unistd.h> 4317987Speter#include <stdlib.h> 4417987Speter 451556Srgrimes#include "shell.h" 461556Srgrimes#define DEFINE_OPTIONS 471556Srgrimes#include "options.h" 481556Srgrimes#undef DEFINE_OPTIONS 491556Srgrimes#include "nodes.h" /* for other header files */ 501556Srgrimes#include "eval.h" 511556Srgrimes#include "jobs.h" 521556Srgrimes#include "input.h" 531556Srgrimes#include "output.h" 541556Srgrimes#include "trap.h" 551556Srgrimes#include "var.h" 561556Srgrimes#include "memalloc.h" 571556Srgrimes#include "error.h" 581556Srgrimes#include "mystring.h" 59223060Sjilles#include "builtins.h" 6017987Speter#ifndef NO_HISTORY 6117987Speter#include "myhistedit.h" 6217987Speter#endif 631556Srgrimes 641556Srgrimeschar *arg0; /* value of $0 */ 651556Srgrimesstruct shparam shellparam; /* current positional parameters */ 661556Srgrimeschar **argptr; /* argument list for builtin commands */ 6759436Scracauerchar *shoptarg; /* set by nextopt (like getopt) */ 68201053Sjilleschar *nextopt_optptr; /* used by nextopt */ 691556Srgrimes 701556Srgrimeschar *minusc; /* argument to -c option */ 711556Srgrimes 721556Srgrimes 73213811Sobrienstatic void options(int); 74213811Sobrienstatic void minus_o(char *, int); 75213811Sobrienstatic void setoption(int, int); 76286788Sjillesstatic void setoptionbyindex(int, int); 77294348Sjillesstatic void setparam(int, char **); 78213811Sobrienstatic int getopts(char *, char *, char **, char ***, char **); 791556Srgrimes 801556Srgrimes 811556Srgrimes/* 821556Srgrimes * Process the shell command line arguments. 831556Srgrimes */ 841556Srgrimes 851556Srgrimesvoid 8690111Simpprocargs(int argc, char **argv) 8717987Speter{ 881556Srgrimes int i; 89222699Sjilles char *scriptname; 901556Srgrimes 911556Srgrimes argptr = argv; 921556Srgrimes if (argc > 0) 931556Srgrimes argptr++; 941556Srgrimes for (i = 0; i < NOPTS; i++) 95293392Sjilles optval[i] = 2; 9619240Ssteve privileged = (getuid() != geteuid() || getgid() != getegid()); 971556Srgrimes options(1); 981556Srgrimes if (*argptr == NULL && minusc == NULL) 991556Srgrimes sflag = 1; 100206182Sjilles if (iflag != 0 && sflag == 1 && isatty(0) && isatty(1)) { 1011556Srgrimes iflag = 1; 102206182Sjilles if (Eflag == 2) 103206182Sjilles Eflag = 1; 104206182Sjilles } 1051556Srgrimes if (mflag == 2) 1061556Srgrimes mflag = iflag; 1071556Srgrimes for (i = 0; i < NOPTS; i++) 108293392Sjilles if (optval[i] == 2) 109293392Sjilles optval[i] = 0; 1101556Srgrimes arg0 = argv[0]; 1111556Srgrimes if (sflag == 0 && minusc == NULL) { 112222699Sjilles scriptname = *argptr++; 113222699Sjilles setinputfile(scriptname, 0); 114222699Sjilles commandname = arg0 = scriptname; 1151556Srgrimes } 11620425Ssteve /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ 11725227Ssteve if (argptr && minusc && *argptr) 11811111Sjoerg arg0 = *argptr++; 11920742Ssteve 1201556Srgrimes shellparam.p = argptr; 12120742Ssteve shellparam.reset = 1; 1221556Srgrimes /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 1231556Srgrimes while (*argptr) { 1241556Srgrimes shellparam.nparam++; 1251556Srgrimes argptr++; 1261556Srgrimes } 1271556Srgrimes optschanged(); 1281556Srgrimes} 1291556Srgrimes 1301556Srgrimes 13117987Spetervoid 13290111Simpoptschanged(void) 13317987Speter{ 1341556Srgrimes setinteractive(iflag); 13517987Speter#ifndef NO_HISTORY 1361556Srgrimes histedit(); 13717987Speter#endif 1381556Srgrimes setjobctl(mflag); 1391556Srgrimes} 1401556Srgrimes 1411556Srgrimes/* 1421556Srgrimes * Process shell options. The global variable argptr contains a pointer 1431556Srgrimes * to the argument list; we advance it past the options. 1441556Srgrimes */ 1451556Srgrimes 146213811Sobrienstatic void 14790111Simpoptions(int cmdline) 14817987Speter{ 149146255Sgad char *kp, *p; 1501556Srgrimes int val; 1511556Srgrimes int c; 1521556Srgrimes 1531556Srgrimes if (cmdline) 1541556Srgrimes minusc = NULL; 1551556Srgrimes while ((p = *argptr) != NULL) { 1561556Srgrimes argptr++; 1571556Srgrimes if ((c = *p++) == '-') { 1581556Srgrimes val = 1; 159141962Sgad /* A "-" or "--" terminates options */ 160141962Sgad if (p[0] == '\0') 161141962Sgad goto end_options1; 162141962Sgad if (p[0] == '-' && p[1] == '\0') 163141962Sgad goto end_options2; 164146255Sgad /** 165146255Sgad * For the benefit of `#!' lines in shell scripts, 166146255Sgad * treat a string of '-- *#.*' the same as '--'. 167146255Sgad * This is needed so that a script starting with: 168146255Sgad * #!/bin/sh -- # -*- perl -*- 169146255Sgad * will continue to work after a change is made to 170146255Sgad * kern/imgact_shell.c to NOT token-ize the options 171146255Sgad * specified on a '#!' line. A bit of a kludge, 172146255Sgad * but that trick is recommended in documentation 173146255Sgad * for some scripting languages, and we might as 174146255Sgad * well continue to support it. 175146255Sgad */ 176146255Sgad if (p[0] == '-') { 177146255Sgad kp = p + 1; 178146255Sgad while (*kp == ' ' || *kp == '\t') 179146255Sgad kp++; 180146255Sgad if (*kp == '#' || *kp == '\0') 181146255Sgad goto end_options2; 182146255Sgad } 1831556Srgrimes } else if (c == '+') { 1841556Srgrimes val = 0; 1851556Srgrimes } else { 1861556Srgrimes argptr--; 1871556Srgrimes break; 1881556Srgrimes } 1891556Srgrimes while ((c = *p++) != '\0') { 1901556Srgrimes if (c == 'c' && cmdline) { 1911556Srgrimes char *q; 1921556Srgrimes#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ 1931556Srgrimes if (*p == '\0') 1941556Srgrimes#endif 1951556Srgrimes q = *argptr++; 1961556Srgrimes if (q == NULL || minusc != NULL) 1971556Srgrimes error("Bad -c option"); 1981556Srgrimes minusc = q; 1991556Srgrimes#ifdef NOHACK 2001556Srgrimes break; 2011556Srgrimes#endif 2021556Srgrimes } else if (c == 'o') { 2031556Srgrimes minus_o(*argptr, val); 2041556Srgrimes if (*argptr) 2051556Srgrimes argptr++; 206221011Sjilles } else 2071556Srgrimes setoption(c, val); 2081556Srgrimes } 2091556Srgrimes } 210141962Sgad return; 211141962Sgad 212141962Sgad /* When processing `set', a single "-" means turn off -x and -v */ 213141962Sgadend_options1: 214141962Sgad if (!cmdline) { 215141962Sgad xflag = vflag = 0; 216141962Sgad return; 217141962Sgad } 218141962Sgad 219141962Sgad /* 220141962Sgad * When processing `set', a "--" means the remaining arguments 221141962Sgad * replace the positional parameters in the active shell. If 222141962Sgad * there are no remaining options, then all the positional 223141962Sgad * parameters are cleared (equivalent to doing ``shift $#''). 224141962Sgad */ 225141962Sgadend_options2: 226141962Sgad if (!cmdline) { 227141962Sgad if (*argptr == NULL) 228294348Sjilles setparam(0, argptr); 229141962Sgad return; 230141962Sgad } 231141962Sgad 232141962Sgad /* 233141962Sgad * At this point we are processing options given to 'sh' on a command 234141962Sgad * line. If an end-of-options marker ("-" or "--") is followed by an 235141962Sgad * arg of "#", then skip over all remaining arguments. Some scripting 236141962Sgad * languages (e.g.: perl) document that /bin/sh will implement this 237141962Sgad * behavior, and they recommend that users take advantage of it to 238141962Sgad * solve certain issues that can come up when writing a perl script. 239141962Sgad * Yes, this feature is in /bin/sh to help users write perl scripts. 240141962Sgad */ 241141962Sgad p = *argptr; 242141962Sgad if (p != NULL && p[0] == '#' && p[1] == '\0') { 243141962Sgad while (*argptr != NULL) 244141962Sgad argptr++; 245141962Sgad /* We need to keep the final argument */ 246141962Sgad argptr--; 247141962Sgad } 2481556Srgrimes} 2491556Srgrimes 250213811Sobrienstatic void 25190111Simpminus_o(char *name, int val) 2521556Srgrimes{ 253151866Sstefanf int i; 254293392Sjilles const unsigned char *on; 255293392Sjilles size_t len; 2561556Srgrimes 2571556Srgrimes if (name == NULL) { 25897276Stjr if (val) { 25997276Stjr /* "Pretty" output. */ 26097276Stjr out1str("Current option settings\n"); 261293392Sjilles for (i = 0, on = optname; i < NOPTS; i++, on += *on + 1) 262293392Sjilles out1fmt("%-16.*s%s\n", *on, on + 1, 263293392Sjilles optval[i] ? "on" : "off"); 26497276Stjr } else { 26597276Stjr /* Output suitable for re-input to shell. */ 266293392Sjilles for (i = 0, on = optname; i < NOPTS; i++, on += *on + 1) 267293392Sjilles out1fmt("%s %co %.*s%s", 268215567Sjilles i % 6 == 0 ? "set" : "", 269293392Sjilles optval[i] ? '-' : '+', 270293392Sjilles *on, on + 1, 271215567Sjilles i % 6 == 5 || i == NOPTS - 1 ? "\n" : ""); 27297276Stjr } 2731556Srgrimes } else { 274293392Sjilles len = strlen(name); 275293392Sjilles for (i = 0, on = optname; i < NOPTS; i++, on += *on + 1) 276293392Sjilles if (*on == len && memcmp(on + 1, name, len) == 0) { 277286788Sjilles setoptionbyindex(i, val); 2781556Srgrimes return; 2791556Srgrimes } 2801556Srgrimes error("Illegal option -o %s", name); 2811556Srgrimes } 2821556Srgrimes} 2831556Srgrimes 2848855Srgrimes 285213811Sobrienstatic void 286286788Sjillessetoptionbyindex(int idx, int val) 28790111Simp{ 288296577Sjilles if (&optval[idx] == &privileged && !val && privileged) { 289221012Sjilles if (setgid(getgid()) == -1) 290221012Sjilles error("setgid"); 291221012Sjilles if (setuid(getuid()) == -1) 292221012Sjilles error("setuid"); 293221011Sjilles } 294293392Sjilles optval[idx] = val; 295286788Sjilles if (val) { 296286788Sjilles /* #%$ hack for ksh semantics */ 297296577Sjilles if (&optval[idx] == &Vflag) 298286788Sjilles Eflag = 0; 299296577Sjilles else if (&optval[idx] == &Eflag) 300286788Sjilles Vflag = 0; 301286788Sjilles } 302286788Sjilles} 303286788Sjilles 304286788Sjillesstatic void 305286788Sjillessetoption(int flag, int val) 306286788Sjilles{ 307286788Sjilles int i; 308286788Sjilles 309287296Sjilles for (i = 0; i < NSHORTOPTS; i++) 310293392Sjilles if (optletter[i] == flag) { 311286788Sjilles setoptionbyindex(i, val); 3121556Srgrimes return; 3131556Srgrimes } 3141556Srgrimes error("Illegal option -%c", flag); 3151556Srgrimes} 3161556Srgrimes 3171556Srgrimes 3181556Srgrimes/* 3191556Srgrimes * Set the shell parameters. 3201556Srgrimes */ 3211556Srgrimes 322294348Sjillesstatic void 323294348Sjillessetparam(int argc, char **argv) 32490111Simp{ 3251556Srgrimes char **newparam; 3261556Srgrimes char **ap; 3271556Srgrimes 328294348Sjilles ap = newparam = ckmalloc((argc + 1) * sizeof *ap); 3291556Srgrimes while (*argv) { 3301556Srgrimes *ap++ = savestr(*argv++); 3311556Srgrimes } 3321556Srgrimes *ap = NULL; 3331556Srgrimes freeparam(&shellparam); 3341556Srgrimes shellparam.malloc = 1; 335294348Sjilles shellparam.nparam = argc; 3361556Srgrimes shellparam.p = newparam; 337273700Sjilles shellparam.optp = NULL; 338182300Sstefanf shellparam.reset = 1; 3391556Srgrimes shellparam.optnext = NULL; 3401556Srgrimes} 3411556Srgrimes 3421556Srgrimes 3431556Srgrimes/* 3441556Srgrimes * Free the list of positional parameters. 3451556Srgrimes */ 3461556Srgrimes 3471556Srgrimesvoid 34890111Simpfreeparam(struct shparam *param) 34990111Simp{ 3501556Srgrimes char **ap; 3511556Srgrimes 3521556Srgrimes if (param->malloc) { 3531556Srgrimes for (ap = param->p ; *ap ; ap++) 3541556Srgrimes ckfree(*ap); 3551556Srgrimes ckfree(param->p); 3561556Srgrimes } 357273700Sjilles if (param->optp) { 358273700Sjilles for (ap = param->optp ; *ap ; ap++) 359273700Sjilles ckfree(*ap); 360273700Sjilles ckfree(param->optp); 361273700Sjilles } 3621556Srgrimes} 3631556Srgrimes 3641556Srgrimes 3651556Srgrimes 3661556Srgrimes/* 3671556Srgrimes * The shift builtin command. 3681556Srgrimes */ 3691556Srgrimes 37017987Speterint 37190111Simpshiftcmd(int argc, char **argv) 37217987Speter{ 373294348Sjilles int i, n; 3741556Srgrimes 3751556Srgrimes n = 1; 3761556Srgrimes if (argc > 1) 3771556Srgrimes n = number(argv[1]); 3781556Srgrimes if (n > shellparam.nparam) 379157601Sstefanf return 1; 3801556Srgrimes INTOFF; 3811556Srgrimes shellparam.nparam -= n; 382294348Sjilles if (shellparam.malloc) 383294348Sjilles for (i = 0; i < n; i++) 384294348Sjilles ckfree(shellparam.p[i]); 385294348Sjilles memmove(shellparam.p, shellparam.p + n, 386294348Sjilles (shellparam.nparam + 1) * sizeof(shellparam.p[0])); 387177497Sstefanf shellparam.reset = 1; 3881556Srgrimes INTON; 3891556Srgrimes return 0; 3901556Srgrimes} 3911556Srgrimes 3921556Srgrimes 3931556Srgrimes 3941556Srgrimes/* 3951556Srgrimes * The set command builtin. 3961556Srgrimes */ 3971556Srgrimes 39817987Speterint 39990111Simpsetcmd(int argc, char **argv) 40017987Speter{ 4011556Srgrimes if (argc == 1) 4021556Srgrimes return showvarscmd(argc, argv); 4031556Srgrimes INTOFF; 4041556Srgrimes options(0); 4051556Srgrimes optschanged(); 4061556Srgrimes if (*argptr != NULL) { 407294348Sjilles setparam(argc - (argptr - argv), argptr); 4081556Srgrimes } 4091556Srgrimes INTON; 4101556Srgrimes return 0; 4111556Srgrimes} 4121556Srgrimes 4131556Srgrimes 41420425Sstevevoid 41590111Simpgetoptsreset(const char *value) 41620425Ssteve{ 417227773Sjilles while (*value == '0') 418227773Sjilles value++; 419227773Sjilles if (strcmp(value, "1") == 0) 42020425Ssteve shellparam.reset = 1; 42120425Ssteve} 42220425Ssteve 4231556Srgrimes/* 4241556Srgrimes * The getopts builtin. Shellparam.optnext points to the next argument 4251556Srgrimes * to be processed. Shellparam.optptr points to the next character to 4261556Srgrimes * be processed in the current argument. If shellparam.optnext is NULL, 4271556Srgrimes * then it's the first time getopts has been called. 4281556Srgrimes */ 4291556Srgrimes 43017987Speterint 43190111Simpgetoptscmd(int argc, char **argv) 43217987Speter{ 433273700Sjilles char **optbase = NULL, **ap; 434273700Sjilles int i; 43520425Ssteve 43620425Ssteve if (argc < 3) 43795258Sdes error("usage: getopts optstring var [arg]"); 43820425Ssteve 43920425Ssteve if (shellparam.reset == 1) { 440273700Sjilles INTOFF; 441273700Sjilles if (shellparam.optp) { 442273700Sjilles for (ap = shellparam.optp ; *ap ; ap++) 443273700Sjilles ckfree(*ap); 444273700Sjilles ckfree(shellparam.optp); 445273700Sjilles shellparam.optp = NULL; 446273700Sjilles } 447273700Sjilles if (argc > 3) { 448273700Sjilles shellparam.optp = ckmalloc((argc - 2) * sizeof *ap); 449273700Sjilles memset(shellparam.optp, '\0', (argc - 2) * sizeof *ap); 450273700Sjilles for (i = 0; i < argc - 3; i++) 451273700Sjilles shellparam.optp[i] = savestr(argv[i + 3]); 452273700Sjilles } 453273700Sjilles INTON; 454273700Sjilles optbase = argc == 3 ? shellparam.p : shellparam.optp; 45520425Ssteve shellparam.optnext = optbase; 45620425Ssteve shellparam.optptr = NULL; 45720425Ssteve shellparam.reset = 0; 458273700Sjilles } else 459273700Sjilles optbase = shellparam.optp ? shellparam.optp : shellparam.p; 46020425Ssteve 46120425Ssteve return getopts(argv[1], argv[2], optbase, &shellparam.optnext, 46220425Ssteve &shellparam.optptr); 46320425Ssteve} 46420425Ssteve 465213811Sobrienstatic int 46690111Simpgetopts(char *optstr, char *optvar, char **optfirst, char ***optnext, 46790111Simp char **optptr) 46820425Ssteve{ 46925227Ssteve char *p, *q; 47020425Ssteve char c = '?'; 47120425Ssteve int done = 0; 47220425Ssteve int ind = 0; 47320425Ssteve int err = 0; 4741556Srgrimes char s[10]; 475279508Sjilles const char *newoptarg = NULL; 4761556Srgrimes 47720425Ssteve if ((p = *optptr) == NULL || *p == '\0') { 47820425Ssteve /* Current word is done, advance */ 47920425Ssteve if (*optnext == NULL) 48020425Ssteve return 1; 48120425Ssteve p = **optnext; 4821556Srgrimes if (p == NULL || *p != '-' || *++p == '\0') { 4831556Srgrimesatend: 48420742Ssteve ind = *optnext - optfirst + 1; 48520425Ssteve *optnext = NULL; 48620742Ssteve p = NULL; 48720425Ssteve done = 1; 48820425Ssteve goto out; 4891556Srgrimes } 49020425Ssteve (*optnext)++; 4911556Srgrimes if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 4921556Srgrimes goto atend; 4931556Srgrimes } 49420425Ssteve 4951556Srgrimes c = *p++; 49620425Ssteve for (q = optstr; *q != c; ) { 4971556Srgrimes if (*q == '\0') { 49820425Ssteve if (optstr[0] == ':') { 49920425Ssteve s[0] = c; 50020425Ssteve s[1] = '\0'; 501279508Sjilles newoptarg = s; 50220425Ssteve } 503265849Sjilles else 504265773Sjilles out2fmt_flush("Illegal option -%c\n", c); 5051556Srgrimes c = '?'; 506265844Sjilles goto out; 5071556Srgrimes } 5081556Srgrimes if (*++q == ':') 5091556Srgrimes q++; 5101556Srgrimes } 51120425Ssteve 5121556Srgrimes if (*++q == ':') { 51320425Ssteve if (*p == '\0' && (p = **optnext) == NULL) { 51420425Ssteve if (optstr[0] == ':') { 51520425Ssteve s[0] = c; 51620425Ssteve s[1] = '\0'; 517279508Sjilles newoptarg = s; 51820425Ssteve c = ':'; 51920425Ssteve } 52020425Ssteve else { 521265773Sjilles out2fmt_flush("No arg for -%c option\n", c); 52220425Ssteve c = '?'; 52320425Ssteve } 524265844Sjilles goto out; 5251556Srgrimes } 52620425Ssteve 52720425Ssteve if (p == **optnext) 52820425Ssteve (*optnext)++; 529279508Sjilles newoptarg = p; 5301556Srgrimes p = NULL; 5311556Srgrimes } 53220425Ssteve 5331556Srgrimesout: 534265844Sjilles if (*optnext != NULL) 535265844Sjilles ind = *optnext - optfirst + 1; 53620425Ssteve *optptr = p; 537279508Sjilles if (newoptarg != NULL) 538279508Sjilles err |= setvarsafe("OPTARG", newoptarg, 0); 539265849Sjilles else { 540265849Sjilles INTOFF; 541265849Sjilles err |= unsetvar("OPTARG"); 542265849Sjilles INTON; 543265849Sjilles } 54420425Ssteve fmtstr(s, sizeof(s), "%d", ind); 54520425Ssteve err |= setvarsafe("OPTIND", s, VNOFUNC); 5461556Srgrimes s[0] = c; 5471556Srgrimes s[1] = '\0'; 54820425Ssteve err |= setvarsafe(optvar, s, 0); 54920425Ssteve if (err) { 55020425Ssteve *optnext = NULL; 55120425Ssteve *optptr = NULL; 55220425Ssteve flushall(); 55320425Ssteve exraise(EXERROR); 55420425Ssteve } 55520425Ssteve return done; 5561556Srgrimes} 5571556Srgrimes 5581556Srgrimes/* 5591556Srgrimes * Standard option processing (a la getopt) for builtin routines. The 5601556Srgrimes * only argument that is passed to nextopt is the option string; the 5611556Srgrimes * other arguments are unnecessary. It return the character, or '\0' on 5621556Srgrimes * end of input. 5631556Srgrimes */ 5641556Srgrimes 5651556Srgrimesint 566200956Sjillesnextopt(const char *optstring) 56790111Simp{ 568200956Sjilles char *p; 569200956Sjilles const char *q; 5701556Srgrimes char c; 5711556Srgrimes 572201053Sjilles if ((p = nextopt_optptr) == NULL || *p == '\0') { 5731556Srgrimes p = *argptr; 5741556Srgrimes if (p == NULL || *p != '-' || *++p == '\0') 5751556Srgrimes return '\0'; 5761556Srgrimes argptr++; 5771556Srgrimes if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 5781556Srgrimes return '\0'; 5791556Srgrimes } 5801556Srgrimes c = *p++; 5811556Srgrimes for (q = optstring ; *q != c ; ) { 5821556Srgrimes if (*q == '\0') 5831556Srgrimes error("Illegal option -%c", c); 5841556Srgrimes if (*++q == ':') 5851556Srgrimes q++; 5861556Srgrimes } 5871556Srgrimes if (*++q == ':') { 5881556Srgrimes if (*p == '\0' && (p = *argptr++) == NULL) 5891556Srgrimes error("No arg for -%c option", c); 59059436Scracauer shoptarg = p; 5911556Srgrimes p = NULL; 5921556Srgrimes } 593201053Sjilles nextopt_optptr = p; 5941556Srgrimes return c; 5951556Srgrimes} 596