options.c revision 206182
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: head/bin/sh/options.c 206182 2010-04-05 14:15:51Z jilles $"); 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" 5917987Speter#ifndef NO_HISTORY 6017987Speter#include "myhistedit.h" 6117987Speter#endif 621556Srgrimes 631556Srgrimeschar *arg0; /* value of $0 */ 641556Srgrimesstruct shparam shellparam; /* current positional parameters */ 651556Srgrimeschar **argptr; /* argument list for builtin commands */ 6659436Scracauerchar *shoptarg; /* set by nextopt (like getopt) */ 67201053Sjilleschar *nextopt_optptr; /* used by nextopt */ 681556Srgrimes 691556Srgrimeschar *minusc; /* argument to -c option */ 701556Srgrimes 711556Srgrimes 7290111SimpSTATIC void options(int); 7390111SimpSTATIC void minus_o(char *, int); 7490111SimpSTATIC void setoption(int, int); 7590111SimpSTATIC int getopts(char *, char *, char **, char ***, char **); 761556Srgrimes 771556Srgrimes 781556Srgrimes/* 791556Srgrimes * Process the shell command line arguments. 801556Srgrimes */ 811556Srgrimes 821556Srgrimesvoid 8390111Simpprocargs(int argc, char **argv) 8417987Speter{ 851556Srgrimes int i; 861556Srgrimes 871556Srgrimes argptr = argv; 881556Srgrimes if (argc > 0) 891556Srgrimes argptr++; 901556Srgrimes for (i = 0; i < NOPTS; i++) 911556Srgrimes optlist[i].val = 2; 9219240Ssteve privileged = (getuid() != geteuid() || getgid() != getegid()); 931556Srgrimes options(1); 941556Srgrimes if (*argptr == NULL && minusc == NULL) 951556Srgrimes sflag = 1; 96206182Sjilles if (iflag != 0 && sflag == 1 && isatty(0) && isatty(1)) { 971556Srgrimes iflag = 1; 98206182Sjilles if (Eflag == 2) 99206182Sjilles Eflag = 1; 100206182Sjilles } 1011556Srgrimes if (mflag == 2) 1021556Srgrimes mflag = iflag; 1031556Srgrimes for (i = 0; i < NOPTS; i++) 1041556Srgrimes if (optlist[i].val == 2) 1051556Srgrimes optlist[i].val = 0; 1061556Srgrimes arg0 = argv[0]; 1071556Srgrimes if (sflag == 0 && minusc == NULL) { 1081556Srgrimes commandname = arg0 = *argptr++; 1091556Srgrimes setinputfile(commandname, 0); 1101556Srgrimes } 11120425Ssteve /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ 11225227Ssteve if (argptr && minusc && *argptr) 11311111Sjoerg arg0 = *argptr++; 11420742Ssteve 1151556Srgrimes shellparam.p = argptr; 11620742Ssteve shellparam.reset = 1; 1171556Srgrimes /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 1181556Srgrimes while (*argptr) { 1191556Srgrimes shellparam.nparam++; 1201556Srgrimes argptr++; 1211556Srgrimes } 1221556Srgrimes optschanged(); 1231556Srgrimes} 1241556Srgrimes 1251556Srgrimes 12617987Spetervoid 12790111Simpoptschanged(void) 12817987Speter{ 1291556Srgrimes setinteractive(iflag); 13017987Speter#ifndef NO_HISTORY 1311556Srgrimes histedit(); 13217987Speter#endif 1331556Srgrimes setjobctl(mflag); 1341556Srgrimes} 1351556Srgrimes 1361556Srgrimes/* 1371556Srgrimes * Process shell options. The global variable argptr contains a pointer 1381556Srgrimes * to the argument list; we advance it past the options. 1391556Srgrimes */ 1401556Srgrimes 1411556SrgrimesSTATIC void 14290111Simpoptions(int cmdline) 14317987Speter{ 144146255Sgad char *kp, *p; 1451556Srgrimes int val; 1461556Srgrimes int c; 1471556Srgrimes 1481556Srgrimes if (cmdline) 1491556Srgrimes minusc = NULL; 1501556Srgrimes while ((p = *argptr) != NULL) { 1511556Srgrimes argptr++; 1521556Srgrimes if ((c = *p++) == '-') { 1531556Srgrimes val = 1; 154141962Sgad /* A "-" or "--" terminates options */ 155141962Sgad if (p[0] == '\0') 156141962Sgad goto end_options1; 157141962Sgad if (p[0] == '-' && p[1] == '\0') 158141962Sgad goto end_options2; 159146255Sgad /** 160146255Sgad * For the benefit of `#!' lines in shell scripts, 161146255Sgad * treat a string of '-- *#.*' the same as '--'. 162146255Sgad * This is needed so that a script starting with: 163146255Sgad * #!/bin/sh -- # -*- perl -*- 164146255Sgad * will continue to work after a change is made to 165146255Sgad * kern/imgact_shell.c to NOT token-ize the options 166146255Sgad * specified on a '#!' line. A bit of a kludge, 167146255Sgad * but that trick is recommended in documentation 168146255Sgad * for some scripting languages, and we might as 169146255Sgad * well continue to support it. 170146255Sgad */ 171146255Sgad if (p[0] == '-') { 172146255Sgad kp = p + 1; 173146255Sgad while (*kp == ' ' || *kp == '\t') 174146255Sgad kp++; 175146255Sgad if (*kp == '#' || *kp == '\0') 176146255Sgad goto end_options2; 177146255Sgad } 1781556Srgrimes } else if (c == '+') { 1791556Srgrimes val = 0; 1801556Srgrimes } else { 1811556Srgrimes argptr--; 1821556Srgrimes break; 1831556Srgrimes } 1841556Srgrimes while ((c = *p++) != '\0') { 1851556Srgrimes if (c == 'c' && cmdline) { 1861556Srgrimes char *q; 1871556Srgrimes#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ 1881556Srgrimes if (*p == '\0') 1891556Srgrimes#endif 1901556Srgrimes q = *argptr++; 1911556Srgrimes if (q == NULL || minusc != NULL) 1921556Srgrimes error("Bad -c option"); 1931556Srgrimes minusc = q; 1941556Srgrimes#ifdef NOHACK 1951556Srgrimes break; 1961556Srgrimes#endif 1971556Srgrimes } else if (c == 'o') { 1981556Srgrimes minus_o(*argptr, val); 1991556Srgrimes if (*argptr) 2001556Srgrimes argptr++; 2011556Srgrimes } else { 20219240Ssteve if (c == 'p' && !val && privileged) { 20319240Ssteve (void) setuid(getuid()); 20419240Ssteve (void) setgid(getgid()); 20519240Ssteve } 2061556Srgrimes setoption(c, val); 2071556Srgrimes } 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) 228141962Sgad setparam(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 2501556SrgrimesSTATIC void 25190111Simpminus_o(char *name, int val) 2521556Srgrimes{ 253151866Sstefanf int i; 2541556Srgrimes 2551556Srgrimes if (name == NULL) { 25697276Stjr if (val) { 25797276Stjr /* "Pretty" output. */ 25897276Stjr out1str("Current option settings\n"); 25997276Stjr for (i = 0; i < NOPTS; i++) 26097276Stjr out1fmt("%-16s%s\n", optlist[i].name, 26197276Stjr optlist[i].val ? "on" : "off"); 26297276Stjr } else { 26397276Stjr /* Output suitable for re-input to shell. */ 264151866Sstefanf for (i = 0; i < NOPTS; i++) { 265151866Sstefanf if (i % 6 == 0) 266151866Sstefanf out1str(i == 0 ? "set" : "\nset"); 267151866Sstefanf out1fmt(" %co %s", optlist[i].val ? '-' : '+', 268151866Sstefanf optlist[i].name); 269151866Sstefanf } 270151866Sstefanf out1c('\n'); 27197276Stjr } 2721556Srgrimes } else { 2731556Srgrimes for (i = 0; i < NOPTS; i++) 2741556Srgrimes if (equal(name, optlist[i].name)) { 27519240Ssteve if (!val && privileged && equal(name, "privileged")) { 27619240Ssteve (void) setuid(getuid()); 27719240Ssteve (void) setgid(getgid()); 27819240Ssteve } 2791556Srgrimes setoption(optlist[i].letter, val); 2801556Srgrimes return; 2811556Srgrimes } 2821556Srgrimes error("Illegal option -o %s", name); 2831556Srgrimes } 2841556Srgrimes} 2851556Srgrimes 2868855Srgrimes 2871556SrgrimesSTATIC void 28890111Simpsetoption(int flag, int val) 28990111Simp{ 2901556Srgrimes int i; 2911556Srgrimes 2921556Srgrimes for (i = 0; i < NOPTS; i++) 2931556Srgrimes if (optlist[i].letter == flag) { 2941556Srgrimes optlist[i].val = val; 2951556Srgrimes if (val) { 2961556Srgrimes /* #%$ hack for ksh semantics */ 2971556Srgrimes if (flag == 'V') 2981556Srgrimes Eflag = 0; 2991556Srgrimes else if (flag == 'E') 3001556Srgrimes Vflag = 0; 3011556Srgrimes } 3021556Srgrimes return; 3031556Srgrimes } 3041556Srgrimes error("Illegal option -%c", flag); 3051556Srgrimes} 3061556Srgrimes 3071556Srgrimes 3081556Srgrimes 3091556Srgrimes#ifdef mkinit 3101556SrgrimesINCLUDE "options.h" 3111556Srgrimes 3121556SrgrimesSHELLPROC { 3131556Srgrimes int i; 3141556Srgrimes 3151556Srgrimes for (i = 0; i < NOPTS; i++) 3161556Srgrimes optlist[i].val = 0; 3171556Srgrimes optschanged(); 3181556Srgrimes 3191556Srgrimes} 3201556Srgrimes#endif 3211556Srgrimes 3221556Srgrimes 3231556Srgrimes/* 3241556Srgrimes * Set the shell parameters. 3251556Srgrimes */ 3261556Srgrimes 3271556Srgrimesvoid 32890111Simpsetparam(char **argv) 32990111Simp{ 3301556Srgrimes char **newparam; 3311556Srgrimes char **ap; 3321556Srgrimes int nparam; 3331556Srgrimes 3341556Srgrimes for (nparam = 0 ; argv[nparam] ; nparam++); 3351556Srgrimes ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); 3361556Srgrimes while (*argv) { 3371556Srgrimes *ap++ = savestr(*argv++); 3381556Srgrimes } 3391556Srgrimes *ap = NULL; 3401556Srgrimes freeparam(&shellparam); 3411556Srgrimes shellparam.malloc = 1; 3421556Srgrimes shellparam.nparam = nparam; 3431556Srgrimes shellparam.p = newparam; 344182300Sstefanf shellparam.reset = 1; 3451556Srgrimes shellparam.optnext = NULL; 3461556Srgrimes} 3471556Srgrimes 3481556Srgrimes 3491556Srgrimes/* 3501556Srgrimes * Free the list of positional parameters. 3511556Srgrimes */ 3521556Srgrimes 3531556Srgrimesvoid 35490111Simpfreeparam(struct shparam *param) 35590111Simp{ 3561556Srgrimes char **ap; 3571556Srgrimes 3581556Srgrimes if (param->malloc) { 3591556Srgrimes for (ap = param->p ; *ap ; ap++) 3601556Srgrimes ckfree(*ap); 3611556Srgrimes ckfree(param->p); 3621556Srgrimes } 3631556Srgrimes} 3641556Srgrimes 3651556Srgrimes 3661556Srgrimes 3671556Srgrimes/* 3681556Srgrimes * The shift builtin command. 3691556Srgrimes */ 3701556Srgrimes 37117987Speterint 37290111Simpshiftcmd(int argc, char **argv) 37317987Speter{ 3741556Srgrimes int n; 3751556Srgrimes char **ap1, **ap2; 3761556Srgrimes 3771556Srgrimes n = 1; 3781556Srgrimes if (argc > 1) 3791556Srgrimes n = number(argv[1]); 3801556Srgrimes if (n > shellparam.nparam) 381157601Sstefanf return 1; 3821556Srgrimes INTOFF; 3831556Srgrimes shellparam.nparam -= n; 3841556Srgrimes for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { 3851556Srgrimes if (shellparam.malloc) 3861556Srgrimes ckfree(*ap1); 3871556Srgrimes } 3881556Srgrimes ap2 = shellparam.p; 3891556Srgrimes while ((*ap2++ = *ap1++) != NULL); 390177497Sstefanf shellparam.reset = 1; 3911556Srgrimes INTON; 3921556Srgrimes return 0; 3931556Srgrimes} 3941556Srgrimes 3951556Srgrimes 3961556Srgrimes 3971556Srgrimes/* 3981556Srgrimes * The set command builtin. 3991556Srgrimes */ 4001556Srgrimes 40117987Speterint 40290111Simpsetcmd(int argc, char **argv) 40317987Speter{ 4041556Srgrimes if (argc == 1) 4051556Srgrimes return showvarscmd(argc, argv); 4061556Srgrimes INTOFF; 4071556Srgrimes options(0); 4081556Srgrimes optschanged(); 4091556Srgrimes if (*argptr != NULL) { 4101556Srgrimes setparam(argptr); 4111556Srgrimes } 4121556Srgrimes INTON; 4131556Srgrimes return 0; 4141556Srgrimes} 4151556Srgrimes 4161556Srgrimes 41720425Sstevevoid 41890111Simpgetoptsreset(const char *value) 41920425Ssteve{ 42020425Ssteve if (number(value) == 1) { 42120425Ssteve shellparam.reset = 1; 42220425Ssteve } 42320425Ssteve} 42420425Ssteve 4251556Srgrimes/* 4261556Srgrimes * The getopts builtin. Shellparam.optnext points to the next argument 4271556Srgrimes * to be processed. Shellparam.optptr points to the next character to 4281556Srgrimes * be processed in the current argument. If shellparam.optnext is NULL, 4291556Srgrimes * then it's the first time getopts has been called. 4301556Srgrimes */ 4311556Srgrimes 43217987Speterint 43390111Simpgetoptscmd(int argc, char **argv) 43417987Speter{ 43520425Ssteve char **optbase = NULL; 43620425Ssteve 43720425Ssteve if (argc < 3) 43895258Sdes error("usage: getopts optstring var [arg]"); 43920425Ssteve else if (argc == 3) 44020425Ssteve optbase = shellparam.p; 44120425Ssteve else 44220425Ssteve optbase = &argv[3]; 44320425Ssteve 44420425Ssteve if (shellparam.reset == 1) { 44520425Ssteve shellparam.optnext = optbase; 44620425Ssteve shellparam.optptr = NULL; 44720425Ssteve shellparam.reset = 0; 44820425Ssteve } 44920425Ssteve 45020425Ssteve return getopts(argv[1], argv[2], optbase, &shellparam.optnext, 45120425Ssteve &shellparam.optptr); 45220425Ssteve} 45320425Ssteve 45420425SsteveSTATIC int 45590111Simpgetopts(char *optstr, char *optvar, char **optfirst, char ***optnext, 45690111Simp char **optptr) 45720425Ssteve{ 45825227Ssteve char *p, *q; 45920425Ssteve char c = '?'; 46020425Ssteve int done = 0; 46120425Ssteve int ind = 0; 46220425Ssteve int err = 0; 4631556Srgrimes char s[10]; 4641556Srgrimes 46520425Ssteve if ((p = *optptr) == NULL || *p == '\0') { 46620425Ssteve /* Current word is done, advance */ 46720425Ssteve if (*optnext == NULL) 46820425Ssteve return 1; 46920425Ssteve p = **optnext; 4701556Srgrimes if (p == NULL || *p != '-' || *++p == '\0') { 4711556Srgrimesatend: 47220742Ssteve ind = *optnext - optfirst + 1; 47320425Ssteve *optnext = NULL; 47420742Ssteve p = NULL; 47520425Ssteve done = 1; 47620425Ssteve goto out; 4771556Srgrimes } 47820425Ssteve (*optnext)++; 4791556Srgrimes if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 4801556Srgrimes goto atend; 4811556Srgrimes } 48220425Ssteve 4831556Srgrimes c = *p++; 48420425Ssteve for (q = optstr; *q != c; ) { 4851556Srgrimes if (*q == '\0') { 48620425Ssteve if (optstr[0] == ':') { 48720425Ssteve s[0] = c; 48820425Ssteve s[1] = '\0'; 48920425Ssteve err |= setvarsafe("OPTARG", s, 0); 49020425Ssteve } 49120425Ssteve else { 49220425Ssteve out1fmt("Illegal option -%c\n", c); 49320425Ssteve (void) unsetvar("OPTARG"); 49420425Ssteve } 4951556Srgrimes c = '?'; 49620425Ssteve goto bad; 4971556Srgrimes } 4981556Srgrimes if (*++q == ':') 4991556Srgrimes q++; 5001556Srgrimes } 50120425Ssteve 5021556Srgrimes if (*++q == ':') { 50320425Ssteve if (*p == '\0' && (p = **optnext) == NULL) { 50420425Ssteve if (optstr[0] == ':') { 50520425Ssteve s[0] = c; 50620425Ssteve s[1] = '\0'; 50720425Ssteve err |= setvarsafe("OPTARG", s, 0); 50820425Ssteve c = ':'; 50920425Ssteve } 51020425Ssteve else { 51120425Ssteve out1fmt("No arg for -%c option\n", c); 51220425Ssteve (void) unsetvar("OPTARG"); 51320425Ssteve c = '?'; 51420425Ssteve } 51520425Ssteve goto bad; 5161556Srgrimes } 51720425Ssteve 51820425Ssteve if (p == **optnext) 51920425Ssteve (*optnext)++; 52020425Ssteve setvarsafe("OPTARG", p, 0); 5211556Srgrimes p = NULL; 5221556Srgrimes } 52320425Ssteve else 52420425Ssteve setvarsafe("OPTARG", "", 0); 52520425Ssteve ind = *optnext - optfirst + 1; 52620425Ssteve goto out; 52720425Ssteve 52820425Sstevebad: 52920425Ssteve ind = 1; 53020425Ssteve *optnext = NULL; 53120425Ssteve p = NULL; 5321556Srgrimesout: 53320425Ssteve *optptr = p; 53420425Ssteve fmtstr(s, sizeof(s), "%d", ind); 53520425Ssteve err |= setvarsafe("OPTIND", s, VNOFUNC); 5361556Srgrimes s[0] = c; 5371556Srgrimes s[1] = '\0'; 53820425Ssteve err |= setvarsafe(optvar, s, 0); 53920425Ssteve if (err) { 54020425Ssteve *optnext = NULL; 54120425Ssteve *optptr = NULL; 54220425Ssteve flushall(); 54320425Ssteve exraise(EXERROR); 54420425Ssteve } 54520425Ssteve return done; 5461556Srgrimes} 5471556Srgrimes 5481556Srgrimes/* 5491556Srgrimes * XXX - should get rid of. have all builtins use getopt(3). the 5501556Srgrimes * library getopt must have the BSD extension static variable "optreset" 5511556Srgrimes * otherwise it can't be used within the shell safely. 5521556Srgrimes * 5531556Srgrimes * Standard option processing (a la getopt) for builtin routines. The 5541556Srgrimes * only argument that is passed to nextopt is the option string; the 5551556Srgrimes * other arguments are unnecessary. It return the character, or '\0' on 5561556Srgrimes * end of input. 5571556Srgrimes */ 5581556Srgrimes 5591556Srgrimesint 560200956Sjillesnextopt(const char *optstring) 56190111Simp{ 562200956Sjilles char *p; 563200956Sjilles const char *q; 5641556Srgrimes char c; 5651556Srgrimes 566201053Sjilles if ((p = nextopt_optptr) == NULL || *p == '\0') { 5671556Srgrimes p = *argptr; 5681556Srgrimes if (p == NULL || *p != '-' || *++p == '\0') 5691556Srgrimes return '\0'; 5701556Srgrimes argptr++; 5711556Srgrimes if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 5721556Srgrimes return '\0'; 5731556Srgrimes } 5741556Srgrimes c = *p++; 5751556Srgrimes for (q = optstring ; *q != c ; ) { 5761556Srgrimes if (*q == '\0') 5771556Srgrimes error("Illegal option -%c", c); 5781556Srgrimes if (*++q == ':') 5791556Srgrimes q++; 5801556Srgrimes } 5811556Srgrimes if (*++q == ':') { 5821556Srgrimes if (*p == '\0' && (p = *argptr++) == NULL) 5831556Srgrimes error("No arg for -%c option", c); 58459436Scracauer shoptarg = p; 5851556Srgrimes p = NULL; 5861556Srgrimes } 587201053Sjilles nextopt_optptr = p; 5881556Srgrimes return c; 5891556Srgrimes} 590