options.c revision 20425
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 * 3. All advertising materials mentioning features or use of this software
171556Srgrimes *    must display the following acknowledgement:
181556Srgrimes *	This product includes software developed by the University of
191556Srgrimes *	California, Berkeley and its contributors.
201556Srgrimes * 4. Neither the name of the University nor the names of its contributors
211556Srgrimes *    may be used to endorse or promote products derived from this software
221556Srgrimes *    without specific prior written permission.
231556Srgrimes *
241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341556Srgrimes * SUCH DAMAGE.
353044Sdg *
3620425Ssteve *	$Id: options.c,v 1.8 1996/10/29 03:12:48 steve Exp $
371556Srgrimes */
381556Srgrimes
391556Srgrimes#ifndef lint
4020425Sstevestatic char const sccsid[] = "@(#)options.c	8.2 (Berkeley) 5/4/95";
411556Srgrimes#endif /* not lint */
421556Srgrimes
4317987Speter#include <signal.h>
4417987Speter#include <unistd.h>
4517987Speter#include <stdlib.h>
4617987Speter
471556Srgrimes#include "shell.h"
481556Srgrimes#define DEFINE_OPTIONS
491556Srgrimes#include "options.h"
501556Srgrimes#undef DEFINE_OPTIONS
511556Srgrimes#include "nodes.h"	/* for other header files */
521556Srgrimes#include "eval.h"
531556Srgrimes#include "jobs.h"
541556Srgrimes#include "input.h"
551556Srgrimes#include "output.h"
561556Srgrimes#include "trap.h"
571556Srgrimes#include "var.h"
581556Srgrimes#include "memalloc.h"
591556Srgrimes#include "error.h"
601556Srgrimes#include "mystring.h"
6117987Speter#ifndef NO_HISTORY
6217987Speter#include "myhistedit.h"
6317987Speter#endif
641556Srgrimes
651556Srgrimeschar *arg0;			/* value of $0 */
661556Srgrimesstruct shparam shellparam;	/* current positional parameters */
671556Srgrimeschar **argptr;			/* argument list for builtin commands */
681556Srgrimeschar *optarg;			/* set by nextopt (like getopt) */
691556Srgrimeschar *optptr;			/* used by nextopt */
701556Srgrimes
711556Srgrimeschar *minusc;			/* argument to -c option */
721556Srgrimes
731556Srgrimes
7417987SpeterSTATIC void options __P((int));
7517987SpeterSTATIC void minus_o __P((char *, int));
7617987SpeterSTATIC void setoption __P((int, int));
7720425SsteveSTATIC int getopts __P((char *, char *, char **, char ***, char **));
781556Srgrimes
791556Srgrimes
801556Srgrimes/*
811556Srgrimes * Process the shell command line arguments.
821556Srgrimes */
831556Srgrimes
841556Srgrimesvoid
851556Srgrimesprocargs(argc, argv)
8617987Speter	int argc;
871556Srgrimes	char **argv;
8817987Speter{
891556Srgrimes	int i;
901556Srgrimes
911556Srgrimes	argptr = argv;
921556Srgrimes	if (argc > 0)
931556Srgrimes		argptr++;
941556Srgrimes	for (i = 0; i < NOPTS; i++)
951556Srgrimes		optlist[i].val = 2;
9619240Ssteve	privileged = (getuid() != geteuid() || getgid() != getegid());
971556Srgrimes	options(1);
981556Srgrimes	if (*argptr == NULL && minusc == NULL)
991556Srgrimes		sflag = 1;
1001556Srgrimes	if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
1011556Srgrimes		iflag = 1;
1021556Srgrimes	if (mflag == 2)
1031556Srgrimes		mflag = iflag;
1041556Srgrimes	for (i = 0; i < NOPTS; i++)
1051556Srgrimes		if (optlist[i].val == 2)
1061556Srgrimes			optlist[i].val = 0;
1071556Srgrimes	arg0 = argv[0];
1081556Srgrimes	if (sflag == 0 && minusc == NULL) {
1091556Srgrimes		commandname = arg0 = *argptr++;
1101556Srgrimes		setinputfile(commandname, 0);
1111556Srgrimes	}
11220425Ssteve	/* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
11311377Sjoerg	if (*argptr && minusc)
11411111Sjoerg		arg0 = *argptr++;
1151556Srgrimes	shellparam.p = argptr;
1161556Srgrimes	/* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
1171556Srgrimes	while (*argptr) {
1181556Srgrimes		shellparam.nparam++;
1191556Srgrimes		argptr++;
1201556Srgrimes	}
1211556Srgrimes	optschanged();
1221556Srgrimes}
1231556Srgrimes
1241556Srgrimes
12517987Spetervoid
12617987Speteroptschanged()
12717987Speter{
1281556Srgrimes	setinteractive(iflag);
12917987Speter#ifndef NO_HISTORY
1301556Srgrimes	histedit();
13117987Speter#endif
1321556Srgrimes	setjobctl(mflag);
1331556Srgrimes}
1341556Srgrimes
1351556Srgrimes/*
1361556Srgrimes * Process shell options.  The global variable argptr contains a pointer
1371556Srgrimes * to the argument list; we advance it past the options.
1381556Srgrimes */
1391556Srgrimes
1401556SrgrimesSTATIC void
14120425Ssteveoptions(cmdline)
14217987Speter	int cmdline;
14317987Speter{
1441556Srgrimes	register char *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;
15417987Speter                        if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
1551556Srgrimes                                if (!cmdline) {
1561556Srgrimes                                        /* "-" means turn off -x and -v */
1571556Srgrimes                                        if (p[0] == '\0')
1581556Srgrimes                                                xflag = vflag = 0;
1591556Srgrimes                                        /* "--" means reset params */
1601556Srgrimes                                        else if (*argptr == NULL)
16117987Speter						setparam(argptr);
1621556Srgrimes                                }
1631556Srgrimes				break;	  /* "-" or  "--" terminates options */
1641556Srgrimes			}
1651556Srgrimes		} else if (c == '+') {
1661556Srgrimes			val = 0;
1671556Srgrimes		} else {
1681556Srgrimes			argptr--;
1691556Srgrimes			break;
1701556Srgrimes		}
1711556Srgrimes		while ((c = *p++) != '\0') {
1721556Srgrimes			if (c == 'c' && cmdline) {
1731556Srgrimes				char *q;
1741556Srgrimes#ifdef NOHACK	/* removing this code allows sh -ce 'foo' for compat */
1751556Srgrimes				if (*p == '\0')
1761556Srgrimes#endif
1771556Srgrimes					q = *argptr++;
1781556Srgrimes				if (q == NULL || minusc != NULL)
1791556Srgrimes					error("Bad -c option");
1801556Srgrimes				minusc = q;
1811556Srgrimes#ifdef NOHACK
1821556Srgrimes				break;
1831556Srgrimes#endif
1841556Srgrimes			} else if (c == 'o') {
1851556Srgrimes				minus_o(*argptr, val);
1861556Srgrimes				if (*argptr)
1871556Srgrimes					argptr++;
1881556Srgrimes			} else {
18919240Ssteve				if (c == 'p' && !val && privileged) {
19019240Ssteve					(void) setuid(getuid());
19119240Ssteve					(void) setgid(getgid());
19219240Ssteve				}
1931556Srgrimes				setoption(c, val);
1941556Srgrimes			}
1951556Srgrimes		}
1961556Srgrimes	}
1971556Srgrimes}
1981556Srgrimes
1991556SrgrimesSTATIC void
2001556Srgrimesminus_o(name, val)
2011556Srgrimes	char *name;
2021556Srgrimes	int val;
2031556Srgrimes{
2041556Srgrimes	int i;
2051556Srgrimes
2061556Srgrimes	if (name == NULL) {
2071556Srgrimes		out1str("Current option settings\n");
2081556Srgrimes		for (i = 0; i < NOPTS; i++)
2091556Srgrimes			out1fmt("%-16s%s\n", optlist[i].name,
2101556Srgrimes				optlist[i].val ? "on" : "off");
2111556Srgrimes	} else {
2121556Srgrimes		for (i = 0; i < NOPTS; i++)
2131556Srgrimes			if (equal(name, optlist[i].name)) {
21419240Ssteve				if (!val && privileged && equal(name, "privileged")) {
21519240Ssteve					(void) setuid(getuid());
21619240Ssteve					(void) setgid(getgid());
21719240Ssteve				}
2181556Srgrimes				setoption(optlist[i].letter, val);
2191556Srgrimes				return;
2201556Srgrimes			}
2211556Srgrimes		error("Illegal option -o %s", name);
2221556Srgrimes	}
2231556Srgrimes}
2241556Srgrimes
2258855Srgrimes
2261556SrgrimesSTATIC void
2271556Srgrimessetoption(flag, val)
2281556Srgrimes	char flag;
2291556Srgrimes	int val;
2301556Srgrimes	{
2311556Srgrimes	int i;
2321556Srgrimes
2331556Srgrimes	for (i = 0; i < NOPTS; i++)
2341556Srgrimes		if (optlist[i].letter == flag) {
2351556Srgrimes			optlist[i].val = val;
2361556Srgrimes			if (val) {
2371556Srgrimes				/* #%$ hack for ksh semantics */
2381556Srgrimes				if (flag == 'V')
2391556Srgrimes					Eflag = 0;
2401556Srgrimes				else if (flag == 'E')
2411556Srgrimes					Vflag = 0;
2421556Srgrimes			}
2431556Srgrimes			return;
2441556Srgrimes		}
2451556Srgrimes	error("Illegal option -%c", flag);
2461556Srgrimes}
2471556Srgrimes
2481556Srgrimes
2491556Srgrimes
2501556Srgrimes#ifdef mkinit
2511556SrgrimesINCLUDE "options.h"
2521556Srgrimes
2531556SrgrimesSHELLPROC {
2541556Srgrimes	int i;
2551556Srgrimes
2561556Srgrimes	for (i = 0; i < NOPTS; i++)
2571556Srgrimes		optlist[i].val = 0;
2581556Srgrimes	optschanged();
2591556Srgrimes
2601556Srgrimes}
2611556Srgrimes#endif
2621556Srgrimes
2631556Srgrimes
2641556Srgrimes/*
2651556Srgrimes * Set the shell parameters.
2661556Srgrimes */
2671556Srgrimes
2681556Srgrimesvoid
2691556Srgrimessetparam(argv)
2701556Srgrimes	char **argv;
2711556Srgrimes	{
2721556Srgrimes	char **newparam;
2731556Srgrimes	char **ap;
2741556Srgrimes	int nparam;
2751556Srgrimes
2761556Srgrimes	for (nparam = 0 ; argv[nparam] ; nparam++);
2771556Srgrimes	ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
2781556Srgrimes	while (*argv) {
2791556Srgrimes		*ap++ = savestr(*argv++);
2801556Srgrimes	}
2811556Srgrimes	*ap = NULL;
2821556Srgrimes	freeparam(&shellparam);
2831556Srgrimes	shellparam.malloc = 1;
2841556Srgrimes	shellparam.nparam = nparam;
2851556Srgrimes	shellparam.p = newparam;
2861556Srgrimes	shellparam.optnext = NULL;
2871556Srgrimes}
2881556Srgrimes
2891556Srgrimes
2901556Srgrimes/*
2911556Srgrimes * Free the list of positional parameters.
2921556Srgrimes */
2931556Srgrimes
2941556Srgrimesvoid
2951556Srgrimesfreeparam(param)
2961556Srgrimes	struct shparam *param;
2971556Srgrimes	{
2981556Srgrimes	char **ap;
2991556Srgrimes
3001556Srgrimes	if (param->malloc) {
3011556Srgrimes		for (ap = param->p ; *ap ; ap++)
3021556Srgrimes			ckfree(*ap);
3031556Srgrimes		ckfree(param->p);
3041556Srgrimes	}
3051556Srgrimes}
3061556Srgrimes
3071556Srgrimes
3081556Srgrimes
3091556Srgrimes/*
3101556Srgrimes * The shift builtin command.
3111556Srgrimes */
3121556Srgrimes
31317987Speterint
31417987Spetershiftcmd(argc, argv)
31517987Speter	int argc;
31620425Ssteve	char **argv;
31717987Speter{
3181556Srgrimes	int n;
3191556Srgrimes	char **ap1, **ap2;
3201556Srgrimes
3211556Srgrimes	n = 1;
3221556Srgrimes	if (argc > 1)
3231556Srgrimes		n = number(argv[1]);
3241556Srgrimes	if (n > shellparam.nparam)
3251556Srgrimes		error("can't shift that many");
3261556Srgrimes	INTOFF;
3271556Srgrimes	shellparam.nparam -= n;
3281556Srgrimes	for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
3291556Srgrimes		if (shellparam.malloc)
3301556Srgrimes			ckfree(*ap1);
3311556Srgrimes	}
3321556Srgrimes	ap2 = shellparam.p;
3331556Srgrimes	while ((*ap2++ = *ap1++) != NULL);
3341556Srgrimes	shellparam.optnext = NULL;
3351556Srgrimes	INTON;
3361556Srgrimes	return 0;
3371556Srgrimes}
3381556Srgrimes
3391556Srgrimes
3401556Srgrimes
3411556Srgrimes/*
3421556Srgrimes * The set command builtin.
3431556Srgrimes */
3441556Srgrimes
34517987Speterint
34617987Spetersetcmd(argc, argv)
34717987Speter	int argc;
34820425Ssteve	char **argv;
34917987Speter{
3501556Srgrimes	if (argc == 1)
3511556Srgrimes		return showvarscmd(argc, argv);
3521556Srgrimes	INTOFF;
3531556Srgrimes	options(0);
3541556Srgrimes	optschanged();
3551556Srgrimes	if (*argptr != NULL) {
3561556Srgrimes		setparam(argptr);
3571556Srgrimes	}
3581556Srgrimes	INTON;
3591556Srgrimes	return 0;
3601556Srgrimes}
3611556Srgrimes
3621556Srgrimes
36320425Sstevevoid
36420425Sstevegetoptsreset(value)
36520425Ssteve	const char *value;
36620425Ssteve{
36720425Ssteve	if (number(value) == 1) {
36820425Ssteve		shellparam.optnext = NULL;
36920425Ssteve		shellparam.reset = 1;
37020425Ssteve	}
37120425Ssteve}
37220425Ssteve
3731556Srgrimes/*
3741556Srgrimes * The getopts builtin.  Shellparam.optnext points to the next argument
3751556Srgrimes * to be processed.  Shellparam.optptr points to the next character to
3761556Srgrimes * be processed in the current argument.  If shellparam.optnext is NULL,
3771556Srgrimes * then it's the first time getopts has been called.
3781556Srgrimes */
3791556Srgrimes
38017987Speterint
38117987Spetergetoptscmd(argc, argv)
38217987Speter	int argc;
38320425Ssteve	char **argv;
38417987Speter{
38520425Ssteve	char **optbase = NULL;
38620425Ssteve
38720425Ssteve	if (argc < 3)
38820425Ssteve		error("Usage: getopts optstring var [arg]");
38920425Ssteve	else if (argc == 3)
39020425Ssteve		optbase = shellparam.p;
39120425Ssteve	else
39220425Ssteve		optbase = &argv[3];
39320425Ssteve
39420425Ssteve	if (shellparam.reset == 1) {
39520425Ssteve		shellparam.optnext = optbase;
39620425Ssteve		shellparam.optptr = NULL;
39720425Ssteve		shellparam.reset = 0;
39820425Ssteve	}
39920425Ssteve
40020425Ssteve	return getopts(argv[1], argv[2], optbase, &shellparam.optnext,
40120425Ssteve		       &shellparam.optptr);
40220425Ssteve}
40320425Ssteve
40420425SsteveSTATIC int
40520425Sstevegetopts(optstr, optvar, optfirst, optnext, optptr)
40620425Ssteve	char *optstr;
40720425Ssteve	char *optvar;
40820425Ssteve	char **optfirst;
40920425Ssteve	char ***optnext;
41020425Ssteve	char **optptr;
41120425Ssteve{
4121556Srgrimes	register char *p, *q;
41320425Ssteve	char c = '?';
41420425Ssteve	int done = 0;
41520425Ssteve	int ind = 0;
41620425Ssteve	int err = 0;
4171556Srgrimes	char s[10];
4181556Srgrimes
41920425Ssteve	if ((p = *optptr) == NULL || *p == '\0') {
42020425Ssteve		/* Current word is done, advance */
42120425Ssteve		if (*optnext == NULL)
42220425Ssteve			return 1;
42320425Ssteve		p = **optnext;
4241556Srgrimes		if (p == NULL || *p != '-' || *++p == '\0') {
4251556Srgrimesatend:
42620425Ssteve			*optnext = NULL;
42720425Ssteve			ind = *optnext - optfirst + 1;
42820425Ssteve			done = 1;
42920425Ssteve			goto out;
4301556Srgrimes		}
43120425Ssteve		(*optnext)++;
4321556Srgrimes		if (p[0] == '-' && p[1] == '\0')	/* check for "--" */
4331556Srgrimes			goto atend;
4341556Srgrimes	}
43520425Ssteve
4361556Srgrimes	c = *p++;
43720425Ssteve	for (q = optstr; *q != c; ) {
4381556Srgrimes		if (*q == '\0') {
43920425Ssteve			if (optstr[0] == ':') {
44020425Ssteve				s[0] = c;
44120425Ssteve				s[1] = '\0';
44220425Ssteve				err |= setvarsafe("OPTARG", s, 0);
44320425Ssteve			}
44420425Ssteve			else {
44520425Ssteve				out1fmt("Illegal option -%c\n", c);
44620425Ssteve				(void) unsetvar("OPTARG");
44720425Ssteve			}
4481556Srgrimes			c = '?';
44920425Ssteve			goto bad;
4501556Srgrimes		}
4511556Srgrimes		if (*++q == ':')
4521556Srgrimes			q++;
4531556Srgrimes	}
45420425Ssteve
4551556Srgrimes	if (*++q == ':') {
45620425Ssteve		if (*p == '\0' && (p = **optnext) == NULL) {
45720425Ssteve			if (optstr[0] == ':') {
45820425Ssteve				s[0] = c;
45920425Ssteve				s[1] = '\0';
46020425Ssteve				err |= setvarsafe("OPTARG", s, 0);
46120425Ssteve				c = ':';
46220425Ssteve			}
46320425Ssteve			else {
46420425Ssteve				out1fmt("No arg for -%c option\n", c);
46520425Ssteve				(void) unsetvar("OPTARG");
46620425Ssteve				c = '?';
46720425Ssteve			}
46820425Ssteve			goto bad;
4691556Srgrimes		}
47020425Ssteve
47120425Ssteve		if (p == **optnext)
47220425Ssteve			(*optnext)++;
47320425Ssteve		setvarsafe("OPTARG", p, 0);
4741556Srgrimes		p = NULL;
4751556Srgrimes	}
47620425Ssteve	else
47720425Ssteve		setvarsafe("OPTARG", "", 0);
47820425Ssteve	ind = *optnext - optfirst + 1;
47920425Ssteve	goto out;
48020425Ssteve
48120425Sstevebad:
48220425Ssteve	ind = 1;
48320425Ssteve	*optnext = NULL;
48420425Ssteve	p = NULL;
4851556Srgrimesout:
48620425Ssteve	*optptr = p;
48720425Ssteve	fmtstr(s, sizeof(s), "%d", ind);
48820425Ssteve	err |= setvarsafe("OPTIND", s, VNOFUNC);
4891556Srgrimes	s[0] = c;
4901556Srgrimes	s[1] = '\0';
49120425Ssteve	err |= setvarsafe(optvar, s, 0);
49220425Ssteve	if (err) {
49320425Ssteve		*optnext = NULL;
49420425Ssteve		*optptr = NULL;
49520425Ssteve		flushall();
49620425Ssteve		exraise(EXERROR);
49720425Ssteve	}
49820425Ssteve	return done;
4991556Srgrimes}
5001556Srgrimes
5011556Srgrimes/*
5021556Srgrimes * XXX - should get rid of.  have all builtins use getopt(3).  the
5031556Srgrimes * library getopt must have the BSD extension static variable "optreset"
5041556Srgrimes * otherwise it can't be used within the shell safely.
5051556Srgrimes *
5061556Srgrimes * Standard option processing (a la getopt) for builtin routines.  The
5071556Srgrimes * only argument that is passed to nextopt is the option string; the
5081556Srgrimes * other arguments are unnecessary.  It return the character, or '\0' on
5091556Srgrimes * end of input.
5101556Srgrimes */
5111556Srgrimes
5121556Srgrimesint
5131556Srgrimesnextopt(optstring)
5141556Srgrimes	char *optstring;
5151556Srgrimes	{
5161556Srgrimes	register char *p, *q;
5171556Srgrimes	char c;
5181556Srgrimes
5191556Srgrimes	if ((p = optptr) == NULL || *p == '\0') {
5201556Srgrimes		p = *argptr;
5211556Srgrimes		if (p == NULL || *p != '-' || *++p == '\0')
5221556Srgrimes			return '\0';
5231556Srgrimes		argptr++;
5241556Srgrimes		if (p[0] == '-' && p[1] == '\0')	/* check for "--" */
5251556Srgrimes			return '\0';
5261556Srgrimes	}
5271556Srgrimes	c = *p++;
5281556Srgrimes	for (q = optstring ; *q != c ; ) {
5291556Srgrimes		if (*q == '\0')
5301556Srgrimes			error("Illegal option -%c", c);
5311556Srgrimes		if (*++q == ':')
5321556Srgrimes			q++;
5331556Srgrimes	}
5341556Srgrimes	if (*++q == ':') {
5351556Srgrimes		if (*p == '\0' && (p = *argptr++) == NULL)
5361556Srgrimes			error("No arg for -%c option", c);
5371556Srgrimes		optarg = p;
5381556Srgrimes		p = NULL;
5391556Srgrimes	}
5401556Srgrimes	optptr = p;
5411556Srgrimes	return c;
5421556Srgrimes}
543