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: releng/10.3/bin/sh/options.c 240247 2012-09-08 19:24:03Z 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" 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); 76213811Sobrienstatic int getopts(char *, char *, char **, char ***, char **); 771556Srgrimes 781556Srgrimes 791556Srgrimes/* 801556Srgrimes * Process the shell command line arguments. 811556Srgrimes */ 821556Srgrimes 831556Srgrimesvoid 8490111Simpprocargs(int argc, char **argv) 8517987Speter{ 861556Srgrimes int i; 87222699Sjilles char *scriptname; 881556Srgrimes 891556Srgrimes argptr = argv; 901556Srgrimes if (argc > 0) 911556Srgrimes argptr++; 921556Srgrimes for (i = 0; i < NOPTS; i++) 931556Srgrimes optlist[i].val = 2; 9419240Ssteve privileged = (getuid() != geteuid() || getgid() != getegid()); 951556Srgrimes options(1); 961556Srgrimes if (*argptr == NULL && minusc == NULL) 971556Srgrimes sflag = 1; 98206182Sjilles if (iflag != 0 && sflag == 1 && isatty(0) && isatty(1)) { 991556Srgrimes iflag = 1; 100206182Sjilles if (Eflag == 2) 101206182Sjilles Eflag = 1; 102206182Sjilles } 1031556Srgrimes if (mflag == 2) 1041556Srgrimes mflag = iflag; 1051556Srgrimes for (i = 0; i < NOPTS; i++) 1061556Srgrimes if (optlist[i].val == 2) 1071556Srgrimes optlist[i].val = 0; 1081556Srgrimes arg0 = argv[0]; 1091556Srgrimes if (sflag == 0 && minusc == NULL) { 110222699Sjilles scriptname = *argptr++; 111222699Sjilles setinputfile(scriptname, 0); 112222699Sjilles commandname = arg0 = scriptname; 1131556Srgrimes } 11420425Ssteve /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ 11525227Ssteve if (argptr && minusc && *argptr) 11611111Sjoerg arg0 = *argptr++; 11720742Ssteve 1181556Srgrimes shellparam.p = argptr; 11920742Ssteve shellparam.reset = 1; 1201556Srgrimes /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 1211556Srgrimes while (*argptr) { 1221556Srgrimes shellparam.nparam++; 1231556Srgrimes argptr++; 1241556Srgrimes } 1251556Srgrimes optschanged(); 1261556Srgrimes} 1271556Srgrimes 1281556Srgrimes 12917987Spetervoid 13090111Simpoptschanged(void) 13117987Speter{ 1321556Srgrimes setinteractive(iflag); 13317987Speter#ifndef NO_HISTORY 1341556Srgrimes histedit(); 13517987Speter#endif 1361556Srgrimes setjobctl(mflag); 1371556Srgrimes} 1381556Srgrimes 1391556Srgrimes/* 1401556Srgrimes * Process shell options. The global variable argptr contains a pointer 1411556Srgrimes * to the argument list; we advance it past the options. 1421556Srgrimes */ 1431556Srgrimes 144213811Sobrienstatic void 14590111Simpoptions(int cmdline) 14617987Speter{ 147146255Sgad char *kp, *p; 1481556Srgrimes int val; 1491556Srgrimes int c; 1501556Srgrimes 1511556Srgrimes if (cmdline) 1521556Srgrimes minusc = NULL; 1531556Srgrimes while ((p = *argptr) != NULL) { 1541556Srgrimes argptr++; 1551556Srgrimes if ((c = *p++) == '-') { 1561556Srgrimes val = 1; 157141962Sgad /* A "-" or "--" terminates options */ 158141962Sgad if (p[0] == '\0') 159141962Sgad goto end_options1; 160141962Sgad if (p[0] == '-' && p[1] == '\0') 161141962Sgad goto end_options2; 162146255Sgad /** 163146255Sgad * For the benefit of `#!' lines in shell scripts, 164146255Sgad * treat a string of '-- *#.*' the same as '--'. 165146255Sgad * This is needed so that a script starting with: 166146255Sgad * #!/bin/sh -- # -*- perl -*- 167146255Sgad * will continue to work after a change is made to 168146255Sgad * kern/imgact_shell.c to NOT token-ize the options 169146255Sgad * specified on a '#!' line. A bit of a kludge, 170146255Sgad * but that trick is recommended in documentation 171146255Sgad * for some scripting languages, and we might as 172146255Sgad * well continue to support it. 173146255Sgad */ 174146255Sgad if (p[0] == '-') { 175146255Sgad kp = p + 1; 176146255Sgad while (*kp == ' ' || *kp == '\t') 177146255Sgad kp++; 178146255Sgad if (*kp == '#' || *kp == '\0') 179146255Sgad goto end_options2; 180146255Sgad } 1811556Srgrimes } else if (c == '+') { 1821556Srgrimes val = 0; 1831556Srgrimes } else { 1841556Srgrimes argptr--; 1851556Srgrimes break; 1861556Srgrimes } 1871556Srgrimes while ((c = *p++) != '\0') { 1881556Srgrimes if (c == 'c' && cmdline) { 1891556Srgrimes char *q; 1901556Srgrimes#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ 1911556Srgrimes if (*p == '\0') 1921556Srgrimes#endif 1931556Srgrimes q = *argptr++; 1941556Srgrimes if (q == NULL || minusc != NULL) 1951556Srgrimes error("Bad -c option"); 1961556Srgrimes minusc = q; 1971556Srgrimes#ifdef NOHACK 1981556Srgrimes break; 1991556Srgrimes#endif 2001556Srgrimes } else if (c == 'o') { 2011556Srgrimes minus_o(*argptr, val); 2021556Srgrimes if (*argptr) 2031556Srgrimes argptr++; 204221011Sjilles } else 2051556Srgrimes setoption(c, val); 2061556Srgrimes } 2071556Srgrimes } 208141962Sgad return; 209141962Sgad 210141962Sgad /* When processing `set', a single "-" means turn off -x and -v */ 211141962Sgadend_options1: 212141962Sgad if (!cmdline) { 213141962Sgad xflag = vflag = 0; 214141962Sgad return; 215141962Sgad } 216141962Sgad 217141962Sgad /* 218141962Sgad * When processing `set', a "--" means the remaining arguments 219141962Sgad * replace the positional parameters in the active shell. If 220141962Sgad * there are no remaining options, then all the positional 221141962Sgad * parameters are cleared (equivalent to doing ``shift $#''). 222141962Sgad */ 223141962Sgadend_options2: 224141962Sgad if (!cmdline) { 225141962Sgad if (*argptr == NULL) 226141962Sgad setparam(argptr); 227141962Sgad return; 228141962Sgad } 229141962Sgad 230141962Sgad /* 231141962Sgad * At this point we are processing options given to 'sh' on a command 232141962Sgad * line. If an end-of-options marker ("-" or "--") is followed by an 233141962Sgad * arg of "#", then skip over all remaining arguments. Some scripting 234141962Sgad * languages (e.g.: perl) document that /bin/sh will implement this 235141962Sgad * behavior, and they recommend that users take advantage of it to 236141962Sgad * solve certain issues that can come up when writing a perl script. 237141962Sgad * Yes, this feature is in /bin/sh to help users write perl scripts. 238141962Sgad */ 239141962Sgad p = *argptr; 240141962Sgad if (p != NULL && p[0] == '#' && p[1] == '\0') { 241141962Sgad while (*argptr != NULL) 242141962Sgad argptr++; 243141962Sgad /* We need to keep the final argument */ 244141962Sgad argptr--; 245141962Sgad } 2461556Srgrimes} 2471556Srgrimes 248213811Sobrienstatic void 24990111Simpminus_o(char *name, int val) 2501556Srgrimes{ 251151866Sstefanf int i; 2521556Srgrimes 2531556Srgrimes if (name == NULL) { 25497276Stjr if (val) { 25597276Stjr /* "Pretty" output. */ 25697276Stjr out1str("Current option settings\n"); 25797276Stjr for (i = 0; i < NOPTS; i++) 25897276Stjr out1fmt("%-16s%s\n", optlist[i].name, 25997276Stjr optlist[i].val ? "on" : "off"); 26097276Stjr } else { 26197276Stjr /* Output suitable for re-input to shell. */ 262215567Sjilles for (i = 0; i < NOPTS; i++) 263215567Sjilles out1fmt("%s %co %s%s", 264215567Sjilles i % 6 == 0 ? "set" : "", 265215567Sjilles optlist[i].val ? '-' : '+', 266215567Sjilles optlist[i].name, 267215567Sjilles i % 6 == 5 || i == NOPTS - 1 ? "\n" : ""); 26897276Stjr } 2691556Srgrimes } else { 2701556Srgrimes for (i = 0; i < NOPTS; i++) 2711556Srgrimes if (equal(name, optlist[i].name)) { 2721556Srgrimes setoption(optlist[i].letter, val); 2731556Srgrimes return; 2741556Srgrimes } 2751556Srgrimes error("Illegal option -o %s", name); 2761556Srgrimes } 2771556Srgrimes} 2781556Srgrimes 2798855Srgrimes 280213811Sobrienstatic void 28190111Simpsetoption(int flag, int val) 28290111Simp{ 2831556Srgrimes int i; 2841556Srgrimes 285221011Sjilles if (flag == 'p' && !val && privileged) { 286221012Sjilles if (setgid(getgid()) == -1) 287221012Sjilles error("setgid"); 288221012Sjilles if (setuid(getuid()) == -1) 289221012Sjilles error("setuid"); 290221011Sjilles } 2911556Srgrimes for (i = 0; i < NOPTS; i++) 2921556Srgrimes if (optlist[i].letter == flag) { 2931556Srgrimes optlist[i].val = val; 2941556Srgrimes if (val) { 2951556Srgrimes /* #%$ hack for ksh semantics */ 2961556Srgrimes if (flag == 'V') 2971556Srgrimes Eflag = 0; 2981556Srgrimes else if (flag == 'E') 2991556Srgrimes Vflag = 0; 3001556Srgrimes } 3011556Srgrimes return; 3021556Srgrimes } 3031556Srgrimes error("Illegal option -%c", flag); 3041556Srgrimes} 3051556Srgrimes 3061556Srgrimes 3071556Srgrimes/* 3081556Srgrimes * Set the shell parameters. 3091556Srgrimes */ 3101556Srgrimes 3111556Srgrimesvoid 31290111Simpsetparam(char **argv) 31390111Simp{ 3141556Srgrimes char **newparam; 3151556Srgrimes char **ap; 3161556Srgrimes int nparam; 3171556Srgrimes 3181556Srgrimes for (nparam = 0 ; argv[nparam] ; nparam++); 3191556Srgrimes ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); 3201556Srgrimes while (*argv) { 3211556Srgrimes *ap++ = savestr(*argv++); 3221556Srgrimes } 3231556Srgrimes *ap = NULL; 3241556Srgrimes freeparam(&shellparam); 3251556Srgrimes shellparam.malloc = 1; 3261556Srgrimes shellparam.nparam = nparam; 3271556Srgrimes shellparam.p = newparam; 328182300Sstefanf shellparam.reset = 1; 3291556Srgrimes shellparam.optnext = NULL; 3301556Srgrimes} 3311556Srgrimes 3321556Srgrimes 3331556Srgrimes/* 3341556Srgrimes * Free the list of positional parameters. 3351556Srgrimes */ 3361556Srgrimes 3371556Srgrimesvoid 33890111Simpfreeparam(struct shparam *param) 33990111Simp{ 3401556Srgrimes char **ap; 3411556Srgrimes 3421556Srgrimes if (param->malloc) { 3431556Srgrimes for (ap = param->p ; *ap ; ap++) 3441556Srgrimes ckfree(*ap); 3451556Srgrimes ckfree(param->p); 3461556Srgrimes } 3471556Srgrimes} 3481556Srgrimes 3491556Srgrimes 3501556Srgrimes 3511556Srgrimes/* 3521556Srgrimes * The shift builtin command. 3531556Srgrimes */ 3541556Srgrimes 35517987Speterint 35690111Simpshiftcmd(int argc, char **argv) 35717987Speter{ 3581556Srgrimes int n; 3591556Srgrimes char **ap1, **ap2; 3601556Srgrimes 3611556Srgrimes n = 1; 3621556Srgrimes if (argc > 1) 3631556Srgrimes n = number(argv[1]); 3641556Srgrimes if (n > shellparam.nparam) 365157601Sstefanf return 1; 3661556Srgrimes INTOFF; 3671556Srgrimes shellparam.nparam -= n; 3681556Srgrimes for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { 3691556Srgrimes if (shellparam.malloc) 3701556Srgrimes ckfree(*ap1); 3711556Srgrimes } 3721556Srgrimes ap2 = shellparam.p; 3731556Srgrimes while ((*ap2++ = *ap1++) != NULL); 374177497Sstefanf shellparam.reset = 1; 3751556Srgrimes INTON; 3761556Srgrimes return 0; 3771556Srgrimes} 3781556Srgrimes 3791556Srgrimes 3801556Srgrimes 3811556Srgrimes/* 3821556Srgrimes * The set command builtin. 3831556Srgrimes */ 3841556Srgrimes 38517987Speterint 38690111Simpsetcmd(int argc, char **argv) 38717987Speter{ 3881556Srgrimes if (argc == 1) 3891556Srgrimes return showvarscmd(argc, argv); 3901556Srgrimes INTOFF; 3911556Srgrimes options(0); 3921556Srgrimes optschanged(); 3931556Srgrimes if (*argptr != NULL) { 3941556Srgrimes setparam(argptr); 3951556Srgrimes } 3961556Srgrimes INTON; 3971556Srgrimes return 0; 3981556Srgrimes} 3991556Srgrimes 4001556Srgrimes 40120425Sstevevoid 40290111Simpgetoptsreset(const char *value) 40320425Ssteve{ 404227773Sjilles while (*value == '0') 405227773Sjilles value++; 406227773Sjilles if (strcmp(value, "1") == 0) 40720425Ssteve shellparam.reset = 1; 40820425Ssteve} 40920425Ssteve 4101556Srgrimes/* 4111556Srgrimes * The getopts builtin. Shellparam.optnext points to the next argument 4121556Srgrimes * to be processed. Shellparam.optptr points to the next character to 4131556Srgrimes * be processed in the current argument. If shellparam.optnext is NULL, 4141556Srgrimes * then it's the first time getopts has been called. 4151556Srgrimes */ 4161556Srgrimes 41717987Speterint 41890111Simpgetoptscmd(int argc, char **argv) 41917987Speter{ 42020425Ssteve char **optbase = NULL; 42120425Ssteve 42220425Ssteve if (argc < 3) 42395258Sdes error("usage: getopts optstring var [arg]"); 42420425Ssteve else if (argc == 3) 42520425Ssteve optbase = shellparam.p; 42620425Ssteve else 42720425Ssteve optbase = &argv[3]; 42820425Ssteve 42920425Ssteve if (shellparam.reset == 1) { 43020425Ssteve shellparam.optnext = optbase; 43120425Ssteve shellparam.optptr = NULL; 43220425Ssteve shellparam.reset = 0; 43320425Ssteve } 43420425Ssteve 43520425Ssteve return getopts(argv[1], argv[2], optbase, &shellparam.optnext, 43620425Ssteve &shellparam.optptr); 43720425Ssteve} 43820425Ssteve 439213811Sobrienstatic int 44090111Simpgetopts(char *optstr, char *optvar, char **optfirst, char ***optnext, 44190111Simp char **optptr) 44220425Ssteve{ 44325227Ssteve char *p, *q; 44420425Ssteve char c = '?'; 44520425Ssteve int done = 0; 44620425Ssteve int ind = 0; 44720425Ssteve int err = 0; 4481556Srgrimes char s[10]; 4491556Srgrimes 45020425Ssteve if ((p = *optptr) == NULL || *p == '\0') { 45120425Ssteve /* Current word is done, advance */ 45220425Ssteve if (*optnext == NULL) 45320425Ssteve return 1; 45420425Ssteve p = **optnext; 4551556Srgrimes if (p == NULL || *p != '-' || *++p == '\0') { 4561556Srgrimesatend: 45720742Ssteve ind = *optnext - optfirst + 1; 45820425Ssteve *optnext = NULL; 45920742Ssteve p = NULL; 46020425Ssteve done = 1; 46120425Ssteve goto out; 4621556Srgrimes } 46320425Ssteve (*optnext)++; 4641556Srgrimes if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 4651556Srgrimes goto atend; 4661556Srgrimes } 46720425Ssteve 4681556Srgrimes c = *p++; 46920425Ssteve for (q = optstr; *q != c; ) { 4701556Srgrimes if (*q == '\0') { 47120425Ssteve if (optstr[0] == ':') { 47220425Ssteve s[0] = c; 47320425Ssteve s[1] = '\0'; 47420425Ssteve err |= setvarsafe("OPTARG", s, 0); 47520425Ssteve } 47620425Ssteve else { 47720425Ssteve out1fmt("Illegal option -%c\n", c); 47820425Ssteve (void) unsetvar("OPTARG"); 47920425Ssteve } 4801556Srgrimes c = '?'; 48120425Ssteve goto bad; 4821556Srgrimes } 4831556Srgrimes if (*++q == ':') 4841556Srgrimes q++; 4851556Srgrimes } 48620425Ssteve 4871556Srgrimes if (*++q == ':') { 48820425Ssteve if (*p == '\0' && (p = **optnext) == NULL) { 48920425Ssteve if (optstr[0] == ':') { 49020425Ssteve s[0] = c; 49120425Ssteve s[1] = '\0'; 49220425Ssteve err |= setvarsafe("OPTARG", s, 0); 49320425Ssteve c = ':'; 49420425Ssteve } 49520425Ssteve else { 49620425Ssteve out1fmt("No arg for -%c option\n", c); 49720425Ssteve (void) unsetvar("OPTARG"); 49820425Ssteve c = '?'; 49920425Ssteve } 50020425Ssteve goto bad; 5011556Srgrimes } 50220425Ssteve 50320425Ssteve if (p == **optnext) 50420425Ssteve (*optnext)++; 50520425Ssteve setvarsafe("OPTARG", p, 0); 5061556Srgrimes p = NULL; 5071556Srgrimes } 50820425Ssteve else 50920425Ssteve setvarsafe("OPTARG", "", 0); 51020425Ssteve ind = *optnext - optfirst + 1; 51120425Ssteve goto out; 51220425Ssteve 51320425Sstevebad: 51420425Ssteve ind = 1; 51520425Ssteve *optnext = NULL; 51620425Ssteve p = NULL; 5171556Srgrimesout: 51820425Ssteve *optptr = p; 51920425Ssteve fmtstr(s, sizeof(s), "%d", ind); 52020425Ssteve err |= setvarsafe("OPTIND", s, VNOFUNC); 5211556Srgrimes s[0] = c; 5221556Srgrimes s[1] = '\0'; 52320425Ssteve err |= setvarsafe(optvar, s, 0); 52420425Ssteve if (err) { 52520425Ssteve *optnext = NULL; 52620425Ssteve *optptr = NULL; 52720425Ssteve flushall(); 52820425Ssteve exraise(EXERROR); 52920425Ssteve } 53020425Ssteve return done; 5311556Srgrimes} 5321556Srgrimes 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 541200956Sjillesnextopt(const char *optstring) 54290111Simp{ 543200956Sjilles char *p; 544200956Sjilles const char *q; 5451556Srgrimes char c; 5461556Srgrimes 547201053Sjilles if ((p = nextopt_optptr) == NULL || *p == '\0') { 5481556Srgrimes p = *argptr; 5491556Srgrimes if (p == NULL || *p != '-' || *++p == '\0') 5501556Srgrimes return '\0'; 5511556Srgrimes argptr++; 5521556Srgrimes if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 5531556Srgrimes return '\0'; 5541556Srgrimes } 5551556Srgrimes c = *p++; 5561556Srgrimes for (q = optstring ; *q != c ; ) { 5571556Srgrimes if (*q == '\0') 5581556Srgrimes error("Illegal option -%c", c); 5591556Srgrimes if (*++q == ':') 5601556Srgrimes q++; 5611556Srgrimes } 5621556Srgrimes if (*++q == ':') { 5631556Srgrimes if (*p == '\0' && (p = *argptr++) == NULL) 5641556Srgrimes error("No arg for -%c option", c); 56559436Scracauer shoptarg = p; 5661556Srgrimes p = NULL; 5671556Srgrimes } 568201053Sjilles nextopt_optptr = p; 5691556Srgrimes return c; 5701556Srgrimes} 571