xref: /csrg-svn/bin/sh/options.c (revision 55229)
147135Sbostic /*-
247135Sbostic  * Copyright (c) 1991 The Regents of the University of California.
347135Sbostic  * All rights reserved.
447135Sbostic  *
547135Sbostic  * This code is derived from software contributed to Berkeley by
647135Sbostic  * Kenneth Almquist.
747135Sbostic  *
847135Sbostic  * %sccs.include.redist.c%
947135Sbostic  */
1047135Sbostic 
1147135Sbostic #ifndef lint
12*55229Smarc static char sccsid[] = "@(#)options.c	5.4 (Berkeley) 07/15/92";
1347135Sbostic #endif /* not lint */
1447135Sbostic 
1547135Sbostic #include "shell.h"
1647135Sbostic #define DEFINE_OPTIONS
1747135Sbostic #include "options.h"
1847135Sbostic #undef DEFINE_OPTIONS
1947135Sbostic #include "nodes.h"	/* for other header files */
2047135Sbostic #include "eval.h"
2147135Sbostic #include "jobs.h"
2247135Sbostic #include "input.h"
2347135Sbostic #include "output.h"
2447135Sbostic #include "trap.h"
2547135Sbostic #include "var.h"
2647135Sbostic #include "memalloc.h"
2747135Sbostic #include "error.h"
2847135Sbostic #include "mystring.h"
2947135Sbostic 
3047135Sbostic char *arg0;			/* value of $0 */
3147135Sbostic struct shparam shellparam;	/* current positional parameters */
3247135Sbostic char **argptr;			/* argument list for builtin commands */
3347135Sbostic char *optarg;			/* set by nextopt (like getopt) */
3447135Sbostic char *optptr;			/* used by nextopt */
3547135Sbostic 
3647135Sbostic char *minusc;			/* argument to -c option */
3747135Sbostic 
3847135Sbostic 
3947135Sbostic #ifdef __STDC__
4047135Sbostic STATIC void options(int);
4147135Sbostic STATIC void setoption(int, int);
42*55229Smarc STATIC void minus_o(char *, int);
4347135Sbostic #else
4447135Sbostic STATIC void options();
4547135Sbostic STATIC void setoption();
46*55229Smarc STATIC void minus_o();
4747135Sbostic #endif
4847135Sbostic 
4947135Sbostic 
5047135Sbostic 
5147135Sbostic /*
5247135Sbostic  * Process the shell command line arguments.
5347135Sbostic  */
5447135Sbostic 
5547135Sbostic void
5647135Sbostic procargs(argc, argv)
5747135Sbostic 	char **argv;
5847135Sbostic 	{
59*55229Smarc 	int i;
6047135Sbostic 
6147135Sbostic 	argptr = argv;
6247135Sbostic 	if (argc > 0)
6347135Sbostic 		argptr++;
64*55229Smarc 	for (i = 0; i < NOPTS; i++)
65*55229Smarc 		optlist[i].val = 2;
6647135Sbostic 	options(1);
6747135Sbostic 	if (*argptr == NULL && minusc == NULL)
6847135Sbostic 		sflag = 1;
6947135Sbostic 	if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
7047135Sbostic 		iflag = 1;
71*55229Smarc 	if (mflag == 2)
72*55229Smarc 		mflag = iflag;
73*55229Smarc 	for (i = 0; i < NOPTS; i++)
74*55229Smarc 		if (optlist[i].val == 2)
75*55229Smarc 			optlist[i].val = 0;
7647135Sbostic 	arg0 = argv[0];
7747135Sbostic 	if (sflag == 0 && minusc == NULL) {
7847135Sbostic 		commandname = arg0 = *argptr++;
7947135Sbostic 		setinputfile(commandname, 0);
8047135Sbostic 	}
8147135Sbostic 	shellparam.p = argptr;
8247135Sbostic 	/* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8347135Sbostic 	while (*argptr) {
8447135Sbostic 		shellparam.nparam++;
8547135Sbostic 		argptr++;
8647135Sbostic 	}
87*55229Smarc 	optschanged();
88*55229Smarc }
89*55229Smarc 
90*55229Smarc 
91*55229Smarc optschanged() {
9247135Sbostic 	setinteractive(iflag);
9354377Smarc 	histedit();
94*55229Smarc 	setjobctl(mflag);
9547135Sbostic }
9647135Sbostic 
9747135Sbostic /*
9847135Sbostic  * Process shell options.  The global variable argptr contains a pointer
9947135Sbostic  * to the argument list; we advance it past the options.
10047135Sbostic  */
10147135Sbostic 
10247135Sbostic STATIC void
10347135Sbostic options(cmdline) {
10447135Sbostic 	register char *p;
10547135Sbostic 	int val;
10647135Sbostic 	int c;
10747135Sbostic 
10847299Smarc 	if (cmdline)
10947299Smarc 		minusc = NULL;
11047135Sbostic 	while ((p = *argptr) != NULL) {
11147135Sbostic 		argptr++;
11247135Sbostic 		if ((c = *p++) == '-') {
11347135Sbostic 			val = 1;
11447299Smarc                         if (p[0] == '\0' || p[0] == '-' && p[1] == '\0') {
11547299Smarc                                 if (!cmdline) {
11647299Smarc                                         /* "-" means turn off -x and -v */
11747299Smarc                                         if (p[0] == '\0')
11847299Smarc                                                 xflag = vflag = 0;
11947299Smarc                                         /* "--" means reset params */
12047299Smarc                                         else if (*argptr == NULL)
12147299Smarc                                                 setparam(argptr);
12247299Smarc                                 }
12347135Sbostic 				break;	  /* "-" or  "--" terminates options */
12447299Smarc 			}
12547135Sbostic 		} else if (c == '+') {
12647135Sbostic 			val = 0;
12747135Sbostic 		} else {
12847135Sbostic 			argptr--;
12947135Sbostic 			break;
13047135Sbostic 		}
13147135Sbostic 		while ((c = *p++) != '\0') {
13247135Sbostic 			if (c == 'c' && cmdline) {
13347135Sbostic 				char *q;
13447299Smarc #ifdef NOHACK	/* removing this code allows sh -ce 'foo' for compat */
13547135Sbostic 				if (*p == '\0')
13647135Sbostic #endif
13747135Sbostic 					q = *argptr++;
13847135Sbostic 				if (q == NULL || minusc != NULL)
13947135Sbostic 					error("Bad -c option");
14047135Sbostic 				minusc = q;
14147135Sbostic #ifdef NOHACK
14247135Sbostic 				break;
14347135Sbostic #endif
144*55229Smarc 			} else if (c == 'o') {
145*55229Smarc 				minus_o(*argptr, val);
146*55229Smarc 				if (*argptr)
147*55229Smarc 					argptr++;
14847135Sbostic 			} else {
14947135Sbostic 				setoption(c, val);
15047135Sbostic 			}
15147135Sbostic 		}
15247135Sbostic 	}
15347135Sbostic }
15447135Sbostic 
155*55229Smarc STATIC void
156*55229Smarc minus_o(name, val)
157*55229Smarc 	char *name;
158*55229Smarc 	int val;
159*55229Smarc {
160*55229Smarc 	int i;
16147135Sbostic 
162*55229Smarc 	if (name == NULL) {
163*55229Smarc 		out1str("Current option settings\n");
164*55229Smarc 		for (i = 0; i < NOPTS; i++)
165*55229Smarc 			out1fmt("%-16s%s\n", optlist[i].name,
166*55229Smarc 				optlist[i].val ? "on" : "off");
167*55229Smarc 	} else {
168*55229Smarc 		for (i = 0; i < NOPTS; i++)
169*55229Smarc 			if (equal(name, optlist[i].name)) {
170*55229Smarc 				setoption(optlist[i].letter, val);
171*55229Smarc 				return;
172*55229Smarc 			}
173*55229Smarc 		error("Illegal option -o %s", name);
174*55229Smarc 	}
175*55229Smarc }
176*55229Smarc 
177*55229Smarc 
17847135Sbostic STATIC void
17947135Sbostic setoption(flag, val)
18047135Sbostic 	char flag;
18147135Sbostic 	int val;
18247135Sbostic 	{
183*55229Smarc 	int i;
18447135Sbostic 
185*55229Smarc 	for (i = 0; i < NOPTS; i++)
186*55229Smarc 		if (optlist[i].letter == flag) {
187*55229Smarc 			optlist[i].val = val;
188*55229Smarc 			if (val) {
189*55229Smarc 				/* #%$ hack for ksh semantics */
190*55229Smarc 				if (flag == 'V')
191*55229Smarc 					Eflag = 0;
192*55229Smarc 				else if (flag == 'E')
193*55229Smarc 					Vflag = 0;
194*55229Smarc 			}
195*55229Smarc 			return;
196*55229Smarc 		}
197*55229Smarc 	error("Illegal option -%c", flag);
19847135Sbostic }
19947135Sbostic 
20047135Sbostic 
20147135Sbostic 
20247135Sbostic #ifdef mkinit
20347135Sbostic INCLUDE "options.h"
20447135Sbostic 
20547135Sbostic SHELLPROC {
206*55229Smarc 	int i;
20747135Sbostic 
208*55229Smarc 	for (i = 0; i < NOPTS; i++)
209*55229Smarc 		optlist[i].val = 0;
210*55229Smarc 	optschanged();
211*55229Smarc 
21247135Sbostic }
21347135Sbostic #endif
21447135Sbostic 
21547135Sbostic 
21647135Sbostic /*
21747135Sbostic  * Set the shell parameters.
21847135Sbostic  */
21947135Sbostic 
22047135Sbostic void
22147135Sbostic setparam(argv)
22247135Sbostic 	char **argv;
22347135Sbostic 	{
22447135Sbostic 	char **newparam;
22547135Sbostic 	char **ap;
22647135Sbostic 	int nparam;
22747135Sbostic 
22847135Sbostic 	for (nparam = 0 ; argv[nparam] ; nparam++);
22947135Sbostic 	ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
23047135Sbostic 	while (*argv) {
23147135Sbostic 		*ap++ = savestr(*argv++);
23247135Sbostic 	}
23347135Sbostic 	*ap = NULL;
23447135Sbostic 	freeparam(&shellparam);
23547135Sbostic 	shellparam.malloc = 1;
23647135Sbostic 	shellparam.nparam = nparam;
23747135Sbostic 	shellparam.p = newparam;
23847135Sbostic 	shellparam.optnext = NULL;
23947135Sbostic }
24047135Sbostic 
24147135Sbostic 
24247135Sbostic /*
24347135Sbostic  * Free the list of positional parameters.
24447135Sbostic  */
24547135Sbostic 
24647135Sbostic void
24747135Sbostic freeparam(param)
24847135Sbostic 	struct shparam *param;
24947135Sbostic 	{
25047135Sbostic 	char **ap;
25147135Sbostic 
25247135Sbostic 	if (param->malloc) {
25347135Sbostic 		for (ap = param->p ; *ap ; ap++)
25447135Sbostic 			ckfree(*ap);
25547135Sbostic 		ckfree(param->p);
25647135Sbostic 	}
25747135Sbostic }
25847135Sbostic 
25947135Sbostic 
26047135Sbostic 
26147135Sbostic /*
26247135Sbostic  * The shift builtin command.
26347135Sbostic  */
26447135Sbostic 
26547135Sbostic shiftcmd(argc, argv)  char **argv; {
26647135Sbostic 	int n;
26747135Sbostic 	char **ap1, **ap2;
26847135Sbostic 
26947135Sbostic 	n = 1;
27047135Sbostic 	if (argc > 1)
27147135Sbostic 		n = number(argv[1]);
27247135Sbostic 	if (n > shellparam.nparam)
27347135Sbostic 		n = shellparam.nparam;
27447135Sbostic 	INTOFF;
27547135Sbostic 	shellparam.nparam -= n;
27647135Sbostic 	for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
27747135Sbostic 		if (shellparam.malloc)
27847135Sbostic 			ckfree(*ap1);
27947135Sbostic 	}
28047135Sbostic 	ap2 = shellparam.p;
28147135Sbostic 	while ((*ap2++ = *ap1++) != NULL);
28247135Sbostic 	shellparam.optnext = NULL;
28347135Sbostic 	INTON;
28447135Sbostic 	return 0;
28547135Sbostic }
28647135Sbostic 
28747135Sbostic 
28847135Sbostic 
28947135Sbostic /*
29047135Sbostic  * The set command builtin.
29147135Sbostic  */
29247135Sbostic 
29347135Sbostic setcmd(argc, argv)  char **argv; {
29447135Sbostic 	if (argc == 1)
29547135Sbostic 		return showvarscmd(argc, argv);
29647135Sbostic 	INTOFF;
29747135Sbostic 	options(0);
298*55229Smarc 	optschanged();
29947135Sbostic 	if (*argptr != NULL) {
30047135Sbostic 		setparam(argptr);
30147135Sbostic 	}
30247135Sbostic 	INTON;
30347135Sbostic 	return 0;
30447135Sbostic }
30547135Sbostic 
30647135Sbostic 
30747135Sbostic /*
30847135Sbostic  * The getopts builtin.  Shellparam.optnext points to the next argument
30947135Sbostic  * to be processed.  Shellparam.optptr points to the next character to
31047135Sbostic  * be processed in the current argument.  If shellparam.optnext is NULL,
31147135Sbostic  * then it's the first time getopts has been called.
31247135Sbostic  */
31347135Sbostic 
31447135Sbostic getoptscmd(argc, argv)  char **argv; {
31547135Sbostic 	register char *p, *q;
31647135Sbostic 	char c;
31747135Sbostic 	char s[10];
31847135Sbostic 
31947135Sbostic 	if (argc != 3)
32047135Sbostic 		error("Usage: getopts optstring var");
32147135Sbostic 	if (shellparam.optnext == NULL) {
32247135Sbostic 		shellparam.optnext = shellparam.p;
32347135Sbostic 		shellparam.optptr = NULL;
32447135Sbostic 	}
32547135Sbostic 	if ((p = shellparam.optptr) == NULL || *p == '\0') {
32647135Sbostic 		p = *shellparam.optnext;
32747135Sbostic 		if (p == NULL || *p != '-' || *++p == '\0') {
32847135Sbostic atend:
32947135Sbostic 			fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1);
33047135Sbostic 			setvar("OPTIND", s, 0);
33147135Sbostic 			shellparam.optnext = NULL;
33247135Sbostic 			return 1;
33347135Sbostic 		}
33447135Sbostic 		shellparam.optnext++;
33547135Sbostic 		if (p[0] == '-' && p[1] == '\0')	/* check for "--" */
33647135Sbostic 			goto atend;
33747135Sbostic 	}
33847135Sbostic 	c = *p++;
33947135Sbostic 	for (q = argv[1] ; *q != c ; ) {
34047135Sbostic 		if (*q == '\0') {
34147135Sbostic 			out1fmt("Illegal option -%c\n", c);
34247135Sbostic 			c = '?';
34347135Sbostic 			goto out;
34447135Sbostic 		}
34547135Sbostic 		if (*++q == ':')
34647135Sbostic 			q++;
34747135Sbostic 	}
34847135Sbostic 	if (*++q == ':') {
34947135Sbostic 		if (*p == '\0' && (p = *shellparam.optnext) == NULL) {
35047135Sbostic 			out1fmt("No arg for -%c option\n", c);
35147135Sbostic 			c = '?';
35247135Sbostic 			goto out;
35347135Sbostic 		}
35447135Sbostic 		shellparam.optnext++;
35547135Sbostic 		setvar("OPTARG", p, 0);
35647135Sbostic 		p = NULL;
35747135Sbostic 	}
35847135Sbostic out:
35947135Sbostic 	shellparam.optptr = p;
36047135Sbostic 	s[0] = c;
36147135Sbostic 	s[1] = '\0';
36247135Sbostic 	setvar(argv[2], s, 0);
36347135Sbostic 	return 0;
36447135Sbostic }
36547135Sbostic 
36647135Sbostic /*
367*55229Smarc  * XXX - should get rid of.  have all builtins use getopt(3).  the
368*55229Smarc  * library getopt must have the BSD extension static variable "optreset"
369*55229Smarc  * otherwise it can't be used within the shell safely.
370*55229Smarc  *
37147135Sbostic  * Standard option processing (a la getopt) for builtin routines.  The
37247135Sbostic  * only argument that is passed to nextopt is the option string; the
37347299Smarc  * other arguments are unnecessary.  It return the character, or '\0' on
37447299Smarc  * end of input.
37547135Sbostic  */
37647135Sbostic 
37747135Sbostic int
37847135Sbostic nextopt(optstring)
37947135Sbostic 	char *optstring;
38047135Sbostic 	{
38147135Sbostic 	register char *p, *q;
38247135Sbostic 	char c;
38347135Sbostic 
38447135Sbostic 	if ((p = optptr) == NULL || *p == '\0') {
38547135Sbostic 		p = *argptr;
38647135Sbostic 		if (p == NULL || *p != '-' || *++p == '\0')
38747299Smarc 			return '\0';
38847135Sbostic 		argptr++;
38947135Sbostic 		if (p[0] == '-' && p[1] == '\0')	/* check for "--" */
39047299Smarc 			return '\0';
39147135Sbostic 	}
39247135Sbostic 	c = *p++;
39347135Sbostic 	for (q = optstring ; *q != c ; ) {
39447135Sbostic 		if (*q == '\0')
39547135Sbostic 			error("Illegal option -%c", c);
39647135Sbostic 		if (*++q == ':')
39747135Sbostic 			q++;
39847135Sbostic 	}
39947135Sbostic 	if (*++q == ':') {
40047135Sbostic 		if (*p == '\0' && (p = *argptr++) == NULL)
40147135Sbostic 			error("No arg for -%c option", c);
40247135Sbostic 		optarg = p;
40347135Sbostic 		p = NULL;
40447135Sbostic 	}
40547135Sbostic 	optptr = p;
40647135Sbostic 	return c;
40747135Sbostic }
408