options.c revision 141962
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 141962 2005-02-16 05:17:58Z gad $"); 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) */ 671556Srgrimeschar *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; 961556Srgrimes if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) 971556Srgrimes iflag = 1; 981556Srgrimes if (mflag == 2) 991556Srgrimes mflag = iflag; 1001556Srgrimes for (i = 0; i < NOPTS; i++) 1011556Srgrimes if (optlist[i].val == 2) 1021556Srgrimes optlist[i].val = 0; 1031556Srgrimes arg0 = argv[0]; 1041556Srgrimes if (sflag == 0 && minusc == NULL) { 1051556Srgrimes commandname = arg0 = *argptr++; 1061556Srgrimes setinputfile(commandname, 0); 1071556Srgrimes } 10820425Ssteve /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ 10925227Ssteve if (argptr && minusc && *argptr) 11011111Sjoerg arg0 = *argptr++; 11120742Ssteve 1121556Srgrimes shellparam.p = argptr; 11320742Ssteve shellparam.reset = 1; 1141556Srgrimes /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 1151556Srgrimes while (*argptr) { 1161556Srgrimes shellparam.nparam++; 1171556Srgrimes argptr++; 1181556Srgrimes } 1191556Srgrimes optschanged(); 1201556Srgrimes} 1211556Srgrimes 1221556Srgrimes 12317987Spetervoid 12490111Simpoptschanged(void) 12517987Speter{ 1261556Srgrimes setinteractive(iflag); 12717987Speter#ifndef NO_HISTORY 1281556Srgrimes histedit(); 12917987Speter#endif 1301556Srgrimes setjobctl(mflag); 1311556Srgrimes} 1321556Srgrimes 1331556Srgrimes/* 1341556Srgrimes * Process shell options. The global variable argptr contains a pointer 1351556Srgrimes * to the argument list; we advance it past the options. 1361556Srgrimes */ 1371556Srgrimes 1381556SrgrimesSTATIC void 13990111Simpoptions(int cmdline) 14017987Speter{ 14125227Ssteve char *p; 1421556Srgrimes int val; 1431556Srgrimes int c; 1441556Srgrimes 1451556Srgrimes if (cmdline) 1461556Srgrimes minusc = NULL; 1471556Srgrimes while ((p = *argptr) != NULL) { 1481556Srgrimes argptr++; 1491556Srgrimes if ((c = *p++) == '-') { 1501556Srgrimes val = 1; 151141962Sgad /* A "-" or "--" terminates options */ 152141962Sgad if (p[0] == '\0') 153141962Sgad goto end_options1; 154141962Sgad if (p[0] == '-' && p[1] == '\0') 155141962Sgad goto end_options2; 1561556Srgrimes } else if (c == '+') { 1571556Srgrimes val = 0; 1581556Srgrimes } else { 1591556Srgrimes argptr--; 1601556Srgrimes break; 1611556Srgrimes } 1621556Srgrimes while ((c = *p++) != '\0') { 1631556Srgrimes if (c == 'c' && cmdline) { 1641556Srgrimes char *q; 1651556Srgrimes#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ 1661556Srgrimes if (*p == '\0') 1671556Srgrimes#endif 1681556Srgrimes q = *argptr++; 1691556Srgrimes if (q == NULL || minusc != NULL) 1701556Srgrimes error("Bad -c option"); 1711556Srgrimes minusc = q; 1721556Srgrimes#ifdef NOHACK 1731556Srgrimes break; 1741556Srgrimes#endif 1751556Srgrimes } else if (c == 'o') { 1761556Srgrimes minus_o(*argptr, val); 1771556Srgrimes if (*argptr) 1781556Srgrimes argptr++; 1791556Srgrimes } else { 18019240Ssteve if (c == 'p' && !val && privileged) { 18119240Ssteve (void) setuid(getuid()); 18219240Ssteve (void) setgid(getgid()); 18319240Ssteve } 1841556Srgrimes setoption(c, val); 1851556Srgrimes } 1861556Srgrimes } 1871556Srgrimes } 188141962Sgad return; 189141962Sgad 190141962Sgad /* When processing `set', a single "-" means turn off -x and -v */ 191141962Sgadend_options1: 192141962Sgad if (!cmdline) { 193141962Sgad xflag = vflag = 0; 194141962Sgad return; 195141962Sgad } 196141962Sgad 197141962Sgad /* 198141962Sgad * When processing `set', a "--" means the remaining arguments 199141962Sgad * replace the positional parameters in the active shell. If 200141962Sgad * there are no remaining options, then all the positional 201141962Sgad * parameters are cleared (equivalent to doing ``shift $#''). 202141962Sgad */ 203141962Sgadend_options2: 204141962Sgad if (!cmdline) { 205141962Sgad if (*argptr == NULL) 206141962Sgad setparam(argptr); 207141962Sgad return; 208141962Sgad } 209141962Sgad 210141962Sgad /* 211141962Sgad * At this point we are processing options given to 'sh' on a command 212141962Sgad * line. If an end-of-options marker ("-" or "--") is followed by an 213141962Sgad * arg of "#", then skip over all remaining arguments. Some scripting 214141962Sgad * languages (e.g.: perl) document that /bin/sh will implement this 215141962Sgad * behavior, and they recommend that users take advantage of it to 216141962Sgad * solve certain issues that can come up when writing a perl script. 217141962Sgad * Yes, this feature is in /bin/sh to help users write perl scripts. 218141962Sgad */ 219141962Sgad p = *argptr; 220141962Sgad if (p != NULL && p[0] == '#' && p[1] == '\0') { 221141962Sgad while (*argptr != NULL) 222141962Sgad argptr++; 223141962Sgad /* We need to keep the final argument */ 224141962Sgad argptr--; 225141962Sgad } 2261556Srgrimes} 2271556Srgrimes 2281556SrgrimesSTATIC void 22990111Simpminus_o(char *name, int val) 2301556Srgrimes{ 23197276Stjr int doneset, i; 2321556Srgrimes 2331556Srgrimes if (name == NULL) { 23497276Stjr if (val) { 23597276Stjr /* "Pretty" output. */ 23697276Stjr out1str("Current option settings\n"); 23797276Stjr for (i = 0; i < NOPTS; i++) 23897276Stjr out1fmt("%-16s%s\n", optlist[i].name, 23997276Stjr optlist[i].val ? "on" : "off"); 24097276Stjr } else { 24197276Stjr /* Output suitable for re-input to shell. */ 24297276Stjr for (doneset = i = 0; i < NOPTS; i++) 24397276Stjr if (optlist[i].val) { 24497276Stjr if (!doneset) { 24597276Stjr out1str("set"); 24697276Stjr doneset = 1; 24797276Stjr } 24897276Stjr out1fmt(" -o %s", optlist[i].name); 24997276Stjr } 25097276Stjr if (doneset) 25197276Stjr out1c('\n'); 25297276Stjr } 2531556Srgrimes } else { 2541556Srgrimes for (i = 0; i < NOPTS; i++) 2551556Srgrimes if (equal(name, optlist[i].name)) { 25619240Ssteve if (!val && privileged && equal(name, "privileged")) { 25719240Ssteve (void) setuid(getuid()); 25819240Ssteve (void) setgid(getgid()); 25919240Ssteve } 2601556Srgrimes setoption(optlist[i].letter, val); 2611556Srgrimes return; 2621556Srgrimes } 2631556Srgrimes error("Illegal option -o %s", name); 2641556Srgrimes } 2651556Srgrimes} 2661556Srgrimes 2678855Srgrimes 2681556SrgrimesSTATIC void 26990111Simpsetoption(int flag, int val) 27090111Simp{ 2711556Srgrimes int i; 2721556Srgrimes 2731556Srgrimes for (i = 0; i < NOPTS; i++) 2741556Srgrimes if (optlist[i].letter == flag) { 2751556Srgrimes optlist[i].val = val; 2761556Srgrimes if (val) { 2771556Srgrimes /* #%$ hack for ksh semantics */ 2781556Srgrimes if (flag == 'V') 2791556Srgrimes Eflag = 0; 2801556Srgrimes else if (flag == 'E') 2811556Srgrimes Vflag = 0; 2821556Srgrimes } 2831556Srgrimes return; 2841556Srgrimes } 2851556Srgrimes error("Illegal option -%c", flag); 2861556Srgrimes} 2871556Srgrimes 2881556Srgrimes 2891556Srgrimes 2901556Srgrimes#ifdef mkinit 2911556SrgrimesINCLUDE "options.h" 2921556Srgrimes 2931556SrgrimesSHELLPROC { 2941556Srgrimes int i; 2951556Srgrimes 2961556Srgrimes for (i = 0; i < NOPTS; i++) 2971556Srgrimes optlist[i].val = 0; 2981556Srgrimes optschanged(); 2991556Srgrimes 3001556Srgrimes} 3011556Srgrimes#endif 3021556Srgrimes 3031556Srgrimes 3041556Srgrimes/* 3051556Srgrimes * Set the shell parameters. 3061556Srgrimes */ 3071556Srgrimes 3081556Srgrimesvoid 30990111Simpsetparam(char **argv) 31090111Simp{ 3111556Srgrimes char **newparam; 3121556Srgrimes char **ap; 3131556Srgrimes int nparam; 3141556Srgrimes 3151556Srgrimes for (nparam = 0 ; argv[nparam] ; nparam++); 3161556Srgrimes ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); 3171556Srgrimes while (*argv) { 3181556Srgrimes *ap++ = savestr(*argv++); 3191556Srgrimes } 3201556Srgrimes *ap = NULL; 3211556Srgrimes freeparam(&shellparam); 3221556Srgrimes shellparam.malloc = 1; 3231556Srgrimes shellparam.nparam = nparam; 3241556Srgrimes shellparam.p = newparam; 3251556Srgrimes shellparam.optnext = NULL; 3261556Srgrimes} 3271556Srgrimes 3281556Srgrimes 3291556Srgrimes/* 3301556Srgrimes * Free the list of positional parameters. 3311556Srgrimes */ 3321556Srgrimes 3331556Srgrimesvoid 33490111Simpfreeparam(struct shparam *param) 33590111Simp{ 3361556Srgrimes char **ap; 3371556Srgrimes 3381556Srgrimes if (param->malloc) { 3391556Srgrimes for (ap = param->p ; *ap ; ap++) 3401556Srgrimes ckfree(*ap); 3411556Srgrimes ckfree(param->p); 3421556Srgrimes } 3431556Srgrimes} 3441556Srgrimes 3451556Srgrimes 3461556Srgrimes 3471556Srgrimes/* 3481556Srgrimes * The shift builtin command. 3491556Srgrimes */ 3501556Srgrimes 35117987Speterint 35290111Simpshiftcmd(int argc, char **argv) 35317987Speter{ 3541556Srgrimes int n; 3551556Srgrimes char **ap1, **ap2; 3561556Srgrimes 3571556Srgrimes n = 1; 3581556Srgrimes if (argc > 1) 3591556Srgrimes n = number(argv[1]); 3601556Srgrimes if (n > shellparam.nparam) 3611556Srgrimes error("can't shift that many"); 3621556Srgrimes INTOFF; 3631556Srgrimes shellparam.nparam -= n; 3641556Srgrimes for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { 3651556Srgrimes if (shellparam.malloc) 3661556Srgrimes ckfree(*ap1); 3671556Srgrimes } 3681556Srgrimes ap2 = shellparam.p; 3691556Srgrimes while ((*ap2++ = *ap1++) != NULL); 3701556Srgrimes shellparam.optnext = NULL; 3711556Srgrimes INTON; 3721556Srgrimes return 0; 3731556Srgrimes} 3741556Srgrimes 3751556Srgrimes 3761556Srgrimes 3771556Srgrimes/* 3781556Srgrimes * The set command builtin. 3791556Srgrimes */ 3801556Srgrimes 38117987Speterint 38290111Simpsetcmd(int argc, char **argv) 38317987Speter{ 3841556Srgrimes if (argc == 1) 3851556Srgrimes return showvarscmd(argc, argv); 3861556Srgrimes INTOFF; 3871556Srgrimes options(0); 3881556Srgrimes optschanged(); 3891556Srgrimes if (*argptr != NULL) { 3901556Srgrimes setparam(argptr); 3911556Srgrimes } 3921556Srgrimes INTON; 3931556Srgrimes return 0; 3941556Srgrimes} 3951556Srgrimes 3961556Srgrimes 39720425Sstevevoid 39890111Simpgetoptsreset(const char *value) 39920425Ssteve{ 40020425Ssteve if (number(value) == 1) { 40120425Ssteve shellparam.optnext = NULL; 40220425Ssteve shellparam.reset = 1; 40320425Ssteve } 40420425Ssteve} 40520425Ssteve 4061556Srgrimes/* 4071556Srgrimes * The getopts builtin. Shellparam.optnext points to the next argument 4081556Srgrimes * to be processed. Shellparam.optptr points to the next character to 4091556Srgrimes * be processed in the current argument. If shellparam.optnext is NULL, 4101556Srgrimes * then it's the first time getopts has been called. 4111556Srgrimes */ 4121556Srgrimes 41317987Speterint 41490111Simpgetoptscmd(int argc, char **argv) 41517987Speter{ 41620425Ssteve char **optbase = NULL; 41720425Ssteve 41820425Ssteve if (argc < 3) 41995258Sdes error("usage: getopts optstring var [arg]"); 42020425Ssteve else if (argc == 3) 42120425Ssteve optbase = shellparam.p; 42220425Ssteve else 42320425Ssteve optbase = &argv[3]; 42420425Ssteve 42520425Ssteve if (shellparam.reset == 1) { 42620425Ssteve shellparam.optnext = optbase; 42720425Ssteve shellparam.optptr = NULL; 42820425Ssteve shellparam.reset = 0; 42920425Ssteve } 43020425Ssteve 43120425Ssteve return getopts(argv[1], argv[2], optbase, &shellparam.optnext, 43220425Ssteve &shellparam.optptr); 43320425Ssteve} 43420425Ssteve 43520425SsteveSTATIC int 43690111Simpgetopts(char *optstr, char *optvar, char **optfirst, char ***optnext, 43790111Simp char **optptr) 43820425Ssteve{ 43925227Ssteve char *p, *q; 44020425Ssteve char c = '?'; 44120425Ssteve int done = 0; 44220425Ssteve int ind = 0; 44320425Ssteve int err = 0; 4441556Srgrimes char s[10]; 4451556Srgrimes 44620425Ssteve if ((p = *optptr) == NULL || *p == '\0') { 44720425Ssteve /* Current word is done, advance */ 44820425Ssteve if (*optnext == NULL) 44920425Ssteve return 1; 45020425Ssteve p = **optnext; 4511556Srgrimes if (p == NULL || *p != '-' || *++p == '\0') { 4521556Srgrimesatend: 45320742Ssteve ind = *optnext - optfirst + 1; 45420425Ssteve *optnext = NULL; 45520742Ssteve p = NULL; 45620425Ssteve done = 1; 45720425Ssteve goto out; 4581556Srgrimes } 45920425Ssteve (*optnext)++; 4601556Srgrimes if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 4611556Srgrimes goto atend; 4621556Srgrimes } 46320425Ssteve 4641556Srgrimes c = *p++; 46520425Ssteve for (q = optstr; *q != c; ) { 4661556Srgrimes if (*q == '\0') { 46720425Ssteve if (optstr[0] == ':') { 46820425Ssteve s[0] = c; 46920425Ssteve s[1] = '\0'; 47020425Ssteve err |= setvarsafe("OPTARG", s, 0); 47120425Ssteve } 47220425Ssteve else { 47320425Ssteve out1fmt("Illegal option -%c\n", c); 47420425Ssteve (void) unsetvar("OPTARG"); 47520425Ssteve } 4761556Srgrimes c = '?'; 47720425Ssteve goto bad; 4781556Srgrimes } 4791556Srgrimes if (*++q == ':') 4801556Srgrimes q++; 4811556Srgrimes } 48220425Ssteve 4831556Srgrimes if (*++q == ':') { 48420425Ssteve if (*p == '\0' && (p = **optnext) == NULL) { 48520425Ssteve if (optstr[0] == ':') { 48620425Ssteve s[0] = c; 48720425Ssteve s[1] = '\0'; 48820425Ssteve err |= setvarsafe("OPTARG", s, 0); 48920425Ssteve c = ':'; 49020425Ssteve } 49120425Ssteve else { 49220425Ssteve out1fmt("No arg for -%c option\n", c); 49320425Ssteve (void) unsetvar("OPTARG"); 49420425Ssteve c = '?'; 49520425Ssteve } 49620425Ssteve goto bad; 4971556Srgrimes } 49820425Ssteve 49920425Ssteve if (p == **optnext) 50020425Ssteve (*optnext)++; 50120425Ssteve setvarsafe("OPTARG", p, 0); 5021556Srgrimes p = NULL; 5031556Srgrimes } 50420425Ssteve else 50520425Ssteve setvarsafe("OPTARG", "", 0); 50620425Ssteve ind = *optnext - optfirst + 1; 50720425Ssteve goto out; 50820425Ssteve 50920425Sstevebad: 51020425Ssteve ind = 1; 51120425Ssteve *optnext = NULL; 51220425Ssteve p = NULL; 5131556Srgrimesout: 51420425Ssteve *optptr = p; 51520425Ssteve fmtstr(s, sizeof(s), "%d", ind); 51620425Ssteve err |= setvarsafe("OPTIND", s, VNOFUNC); 5171556Srgrimes s[0] = c; 5181556Srgrimes s[1] = '\0'; 51920425Ssteve err |= setvarsafe(optvar, s, 0); 52020425Ssteve if (err) { 52120425Ssteve *optnext = NULL; 52220425Ssteve *optptr = NULL; 52320425Ssteve flushall(); 52420425Ssteve exraise(EXERROR); 52520425Ssteve } 52620425Ssteve return done; 5271556Srgrimes} 5281556Srgrimes 5291556Srgrimes/* 5301556Srgrimes * XXX - should get rid of. have all builtins use getopt(3). the 5311556Srgrimes * library getopt must have the BSD extension static variable "optreset" 5321556Srgrimes * otherwise it can't be used within the shell safely. 5331556Srgrimes * 5341556Srgrimes * Standard option processing (a la getopt) for builtin routines. The 5351556Srgrimes * only argument that is passed to nextopt is the option string; the 5361556Srgrimes * other arguments are unnecessary. It return the character, or '\0' on 5371556Srgrimes * end of input. 5381556Srgrimes */ 5391556Srgrimes 5401556Srgrimesint 54190111Simpnextopt(char *optstring) 54290111Simp{ 54325227Ssteve char *p, *q; 5441556Srgrimes char c; 5451556Srgrimes 5461556Srgrimes if ((p = optptr) == NULL || *p == '\0') { 5471556Srgrimes p = *argptr; 5481556Srgrimes if (p == NULL || *p != '-' || *++p == '\0') 5491556Srgrimes return '\0'; 5501556Srgrimes argptr++; 5511556Srgrimes if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 5521556Srgrimes return '\0'; 5531556Srgrimes } 5541556Srgrimes c = *p++; 5551556Srgrimes for (q = optstring ; *q != c ; ) { 5561556Srgrimes if (*q == '\0') 5571556Srgrimes error("Illegal option -%c", c); 5581556Srgrimes if (*++q == ':') 5591556Srgrimes q++; 5601556Srgrimes } 5611556Srgrimes if (*++q == ':') { 5621556Srgrimes if (*p == '\0' && (p = *argptr++) == NULL) 5631556Srgrimes error("No arg for -%c option", c); 56459436Scracauer shoptarg = p; 5651556Srgrimes p = NULL; 5661556Srgrimes } 5671556Srgrimes optptr = p; 5681556Srgrimes return c; 5691556Srgrimes} 570