xref: /csrg-svn/bin/sh/options.c (revision 69272)
147135Sbostic /*-
260698Sbostic  * Copyright (c) 1991, 1993
360698Sbostic  *	The Regents of the University of California.  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*69272Schristos static char sccsid[] = "@(#)options.c	8.2 (Berkeley) 05/04/95";
1347135Sbostic #endif /* not lint */
1447135Sbostic 
15*69272Schristos #include <signal.h>
16*69272Schristos #include <unistd.h>
17*69272Schristos #include <stdlib.h>
18*69272Schristos 
1947135Sbostic #include "shell.h"
2047135Sbostic #define DEFINE_OPTIONS
2147135Sbostic #include "options.h"
2247135Sbostic #undef DEFINE_OPTIONS
2347135Sbostic #include "nodes.h"	/* for other header files */
2447135Sbostic #include "eval.h"
2547135Sbostic #include "jobs.h"
2647135Sbostic #include "input.h"
2747135Sbostic #include "output.h"
2847135Sbostic #include "trap.h"
2947135Sbostic #include "var.h"
3047135Sbostic #include "memalloc.h"
3147135Sbostic #include "error.h"
3247135Sbostic #include "mystring.h"
33*69272Schristos #ifndef NO_HISTORY
34*69272Schristos #include "myhistedit.h"
35*69272Schristos #endif
3647135Sbostic 
3747135Sbostic char *arg0;			/* value of $0 */
3847135Sbostic struct shparam shellparam;	/* current positional parameters */
3947135Sbostic char **argptr;			/* argument list for builtin commands */
4047135Sbostic char *optarg;			/* set by nextopt (like getopt) */
4147135Sbostic char *optptr;			/* used by nextopt */
4247135Sbostic 
4347135Sbostic char *minusc;			/* argument to -c option */
4447135Sbostic 
4547135Sbostic 
46*69272Schristos STATIC void options __P((int));
47*69272Schristos STATIC void minus_o __P((char *, int));
48*69272Schristos STATIC void setoption __P((int, int));
4947135Sbostic 
5047135Sbostic 
5147135Sbostic /*
5247135Sbostic  * Process the shell command line arguments.
5347135Sbostic  */
5447135Sbostic 
5547135Sbostic void
procargs(argc,argv)5647135Sbostic procargs(argc, argv)
57*69272Schristos 	int argc;
5847135Sbostic 	char **argv;
59*69272Schristos {
6055229Smarc 	int i;
6147135Sbostic 
6247135Sbostic 	argptr = argv;
6347135Sbostic 	if (argc > 0)
6447135Sbostic 		argptr++;
6555229Smarc 	for (i = 0; i < NOPTS; i++)
6655229Smarc 		optlist[i].val = 2;
6747135Sbostic 	options(1);
6847135Sbostic 	if (*argptr == NULL && minusc == NULL)
6947135Sbostic 		sflag = 1;
7047135Sbostic 	if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
7147135Sbostic 		iflag = 1;
7255229Smarc 	if (mflag == 2)
7355229Smarc 		mflag = iflag;
7455229Smarc 	for (i = 0; i < NOPTS; i++)
7555229Smarc 		if (optlist[i].val == 2)
7655229Smarc 			optlist[i].val = 0;
7747135Sbostic 	arg0 = argv[0];
7847135Sbostic 	if (sflag == 0 && minusc == NULL) {
7947135Sbostic 		commandname = arg0 = *argptr++;
8047135Sbostic 		setinputfile(commandname, 0);
8147135Sbostic 	}
8247135Sbostic 	shellparam.p = argptr;
8347135Sbostic 	/* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8447135Sbostic 	while (*argptr) {
8547135Sbostic 		shellparam.nparam++;
8647135Sbostic 		argptr++;
8747135Sbostic 	}
8855229Smarc 	optschanged();
8955229Smarc }
9055229Smarc 
9155229Smarc 
92*69272Schristos void
optschanged()93*69272Schristos optschanged()
94*69272Schristos {
9547135Sbostic 	setinteractive(iflag);
96*69272Schristos #ifndef NO_HISTORY
9754377Smarc 	histedit();
98*69272Schristos #endif
9955229Smarc 	setjobctl(mflag);
10047135Sbostic }
10147135Sbostic 
10247135Sbostic /*
10347135Sbostic  * Process shell options.  The global variable argptr contains a pointer
10447135Sbostic  * to the argument list; we advance it past the options.
10547135Sbostic  */
10647135Sbostic 
10747135Sbostic STATIC void
options(cmdline)108*69272Schristos options(cmdline)
109*69272Schristos 	int cmdline;
110*69272Schristos {
11147135Sbostic 	register char *p;
11247135Sbostic 	int val;
11347135Sbostic 	int c;
11447135Sbostic 
11547299Smarc 	if (cmdline)
11647299Smarc 		minusc = NULL;
11747135Sbostic 	while ((p = *argptr) != NULL) {
11847135Sbostic 		argptr++;
11947135Sbostic 		if ((c = *p++) == '-') {
12047135Sbostic 			val = 1;
121*69272Schristos                         if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
12247299Smarc                                 if (!cmdline) {
12347299Smarc                                         /* "-" means turn off -x and -v */
12447299Smarc                                         if (p[0] == '\0')
12547299Smarc                                                 xflag = vflag = 0;
12647299Smarc                                         /* "--" means reset params */
12747299Smarc                                         else if (*argptr == NULL)
128*69272Schristos 						setparam(argptr);
12947299Smarc                                 }
13047135Sbostic 				break;	  /* "-" or  "--" terminates options */
13147299Smarc 			}
13247135Sbostic 		} else if (c == '+') {
13347135Sbostic 			val = 0;
13447135Sbostic 		} else {
13547135Sbostic 			argptr--;
13647135Sbostic 			break;
13747135Sbostic 		}
13847135Sbostic 		while ((c = *p++) != '\0') {
13947135Sbostic 			if (c == 'c' && cmdline) {
14047135Sbostic 				char *q;
14147299Smarc #ifdef NOHACK	/* removing this code allows sh -ce 'foo' for compat */
14247135Sbostic 				if (*p == '\0')
14347135Sbostic #endif
14447135Sbostic 					q = *argptr++;
14547135Sbostic 				if (q == NULL || minusc != NULL)
14647135Sbostic 					error("Bad -c option");
14747135Sbostic 				minusc = q;
14847135Sbostic #ifdef NOHACK
14947135Sbostic 				break;
15047135Sbostic #endif
15155229Smarc 			} else if (c == 'o') {
15255229Smarc 				minus_o(*argptr, val);
15355229Smarc 				if (*argptr)
15455229Smarc 					argptr++;
15547135Sbostic 			} else {
15647135Sbostic 				setoption(c, val);
15747135Sbostic 			}
15847135Sbostic 		}
15947135Sbostic 	}
16047135Sbostic }
16147135Sbostic 
16255229Smarc STATIC void
minus_o(name,val)16355229Smarc minus_o(name, val)
16455229Smarc 	char *name;
16555229Smarc 	int val;
16655229Smarc {
16755229Smarc 	int i;
16847135Sbostic 
16955229Smarc 	if (name == NULL) {
17055229Smarc 		out1str("Current option settings\n");
17155229Smarc 		for (i = 0; i < NOPTS; i++)
17255229Smarc 			out1fmt("%-16s%s\n", optlist[i].name,
17355229Smarc 				optlist[i].val ? "on" : "off");
17455229Smarc 	} else {
17555229Smarc 		for (i = 0; i < NOPTS; i++)
17655229Smarc 			if (equal(name, optlist[i].name)) {
17755229Smarc 				setoption(optlist[i].letter, val);
17855229Smarc 				return;
17955229Smarc 			}
18055229Smarc 		error("Illegal option -o %s", name);
18155229Smarc 	}
18255229Smarc }
18355229Smarc 
18455229Smarc 
18547135Sbostic STATIC void
setoption(flag,val)18647135Sbostic setoption(flag, val)
18747135Sbostic 	char flag;
18847135Sbostic 	int val;
18947135Sbostic 	{
19055229Smarc 	int i;
19147135Sbostic 
19255229Smarc 	for (i = 0; i < NOPTS; i++)
19355229Smarc 		if (optlist[i].letter == flag) {
19455229Smarc 			optlist[i].val = val;
19555229Smarc 			if (val) {
19655229Smarc 				/* #%$ hack for ksh semantics */
19755229Smarc 				if (flag == 'V')
19855229Smarc 					Eflag = 0;
19955229Smarc 				else if (flag == 'E')
20055229Smarc 					Vflag = 0;
20155229Smarc 			}
20255229Smarc 			return;
20355229Smarc 		}
20455229Smarc 	error("Illegal option -%c", flag);
20547135Sbostic }
20647135Sbostic 
20747135Sbostic 
20847135Sbostic 
20947135Sbostic #ifdef mkinit
21047135Sbostic INCLUDE "options.h"
21147135Sbostic 
21247135Sbostic SHELLPROC {
21355229Smarc 	int i;
21447135Sbostic 
21555229Smarc 	for (i = 0; i < NOPTS; i++)
21655229Smarc 		optlist[i].val = 0;
21755229Smarc 	optschanged();
21855229Smarc 
21947135Sbostic }
22047135Sbostic #endif
22147135Sbostic 
22247135Sbostic 
22347135Sbostic /*
22447135Sbostic  * Set the shell parameters.
22547135Sbostic  */
22647135Sbostic 
22747135Sbostic void
setparam(argv)22847135Sbostic setparam(argv)
22947135Sbostic 	char **argv;
23047135Sbostic 	{
23147135Sbostic 	char **newparam;
23247135Sbostic 	char **ap;
23347135Sbostic 	int nparam;
23447135Sbostic 
23547135Sbostic 	for (nparam = 0 ; argv[nparam] ; nparam++);
23647135Sbostic 	ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
23747135Sbostic 	while (*argv) {
23847135Sbostic 		*ap++ = savestr(*argv++);
23947135Sbostic 	}
24047135Sbostic 	*ap = NULL;
24147135Sbostic 	freeparam(&shellparam);
24247135Sbostic 	shellparam.malloc = 1;
24347135Sbostic 	shellparam.nparam = nparam;
24447135Sbostic 	shellparam.p = newparam;
24547135Sbostic 	shellparam.optnext = NULL;
24647135Sbostic }
24747135Sbostic 
24847135Sbostic 
24947135Sbostic /*
25047135Sbostic  * Free the list of positional parameters.
25147135Sbostic  */
25247135Sbostic 
25347135Sbostic void
freeparam(param)25447135Sbostic freeparam(param)
25547135Sbostic 	struct shparam *param;
25647135Sbostic 	{
25747135Sbostic 	char **ap;
25847135Sbostic 
25947135Sbostic 	if (param->malloc) {
26047135Sbostic 		for (ap = param->p ; *ap ; ap++)
26147135Sbostic 			ckfree(*ap);
26247135Sbostic 		ckfree(param->p);
26347135Sbostic 	}
26447135Sbostic }
26547135Sbostic 
26647135Sbostic 
26747135Sbostic 
26847135Sbostic /*
26947135Sbostic  * The shift builtin command.
27047135Sbostic  */
27147135Sbostic 
272*69272Schristos int
shiftcmd(argc,argv)273*69272Schristos shiftcmd(argc, argv)
274*69272Schristos 	int argc;
275*69272Schristos 	char **argv;
276*69272Schristos {
27747135Sbostic 	int n;
27847135Sbostic 	char **ap1, **ap2;
27947135Sbostic 
28047135Sbostic 	n = 1;
28147135Sbostic 	if (argc > 1)
28247135Sbostic 		n = number(argv[1]);
28347135Sbostic 	if (n > shellparam.nparam)
28455301Smarc 		error("can't shift that many");
28547135Sbostic 	INTOFF;
28647135Sbostic 	shellparam.nparam -= n;
28747135Sbostic 	for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
28847135Sbostic 		if (shellparam.malloc)
28947135Sbostic 			ckfree(*ap1);
29047135Sbostic 	}
29147135Sbostic 	ap2 = shellparam.p;
29247135Sbostic 	while ((*ap2++ = *ap1++) != NULL);
29347135Sbostic 	shellparam.optnext = NULL;
29447135Sbostic 	INTON;
29547135Sbostic 	return 0;
29647135Sbostic }
29747135Sbostic 
29847135Sbostic 
29947135Sbostic 
30047135Sbostic /*
30147135Sbostic  * The set command builtin.
30247135Sbostic  */
30347135Sbostic 
304*69272Schristos int
setcmd(argc,argv)305*69272Schristos setcmd(argc, argv)
306*69272Schristos 	int argc;
307*69272Schristos 	char **argv;
308*69272Schristos {
30947135Sbostic 	if (argc == 1)
31047135Sbostic 		return showvarscmd(argc, argv);
31147135Sbostic 	INTOFF;
31247135Sbostic 	options(0);
31355229Smarc 	optschanged();
31447135Sbostic 	if (*argptr != NULL) {
31547135Sbostic 		setparam(argptr);
31647135Sbostic 	}
31747135Sbostic 	INTON;
31847135Sbostic 	return 0;
31947135Sbostic }
32047135Sbostic 
32147135Sbostic 
32247135Sbostic /*
32347135Sbostic  * The getopts builtin.  Shellparam.optnext points to the next argument
32447135Sbostic  * to be processed.  Shellparam.optptr points to the next character to
32547135Sbostic  * be processed in the current argument.  If shellparam.optnext is NULL,
32647135Sbostic  * then it's the first time getopts has been called.
32747135Sbostic  */
32847135Sbostic 
329*69272Schristos int
getoptscmd(argc,argv)330*69272Schristos getoptscmd(argc, argv)
331*69272Schristos 	int argc;
332*69272Schristos 	char **argv;
333*69272Schristos {
33447135Sbostic 	register char *p, *q;
33547135Sbostic 	char c;
33647135Sbostic 	char s[10];
33747135Sbostic 
33847135Sbostic 	if (argc != 3)
33947135Sbostic 		error("Usage: getopts optstring var");
34047135Sbostic 	if (shellparam.optnext == NULL) {
34147135Sbostic 		shellparam.optnext = shellparam.p;
34247135Sbostic 		shellparam.optptr = NULL;
34347135Sbostic 	}
34447135Sbostic 	if ((p = shellparam.optptr) == NULL || *p == '\0') {
34547135Sbostic 		p = *shellparam.optnext;
34647135Sbostic 		if (p == NULL || *p != '-' || *++p == '\0') {
34747135Sbostic atend:
34847135Sbostic 			fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1);
34947135Sbostic 			setvar("OPTIND", s, 0);
35047135Sbostic 			shellparam.optnext = NULL;
35147135Sbostic 			return 1;
35247135Sbostic 		}
35347135Sbostic 		shellparam.optnext++;
35447135Sbostic 		if (p[0] == '-' && p[1] == '\0')	/* check for "--" */
35547135Sbostic 			goto atend;
35647135Sbostic 	}
35747135Sbostic 	c = *p++;
35847135Sbostic 	for (q = argv[1] ; *q != c ; ) {
35947135Sbostic 		if (*q == '\0') {
36047135Sbostic 			out1fmt("Illegal option -%c\n", c);
36147135Sbostic 			c = '?';
36247135Sbostic 			goto out;
36347135Sbostic 		}
36447135Sbostic 		if (*++q == ':')
36547135Sbostic 			q++;
36647135Sbostic 	}
36747135Sbostic 	if (*++q == ':') {
36847135Sbostic 		if (*p == '\0' && (p = *shellparam.optnext) == NULL) {
36947135Sbostic 			out1fmt("No arg for -%c option\n", c);
37047135Sbostic 			c = '?';
37147135Sbostic 			goto out;
37247135Sbostic 		}
37347135Sbostic 		shellparam.optnext++;
37447135Sbostic 		setvar("OPTARG", p, 0);
37547135Sbostic 		p = NULL;
37647135Sbostic 	}
37747135Sbostic out:
37847135Sbostic 	shellparam.optptr = p;
37947135Sbostic 	s[0] = c;
38047135Sbostic 	s[1] = '\0';
38147135Sbostic 	setvar(argv[2], s, 0);
38247135Sbostic 	return 0;
38347135Sbostic }
38447135Sbostic 
38547135Sbostic /*
38655229Smarc  * XXX - should get rid of.  have all builtins use getopt(3).  the
38755229Smarc  * library getopt must have the BSD extension static variable "optreset"
38855229Smarc  * otherwise it can't be used within the shell safely.
38955229Smarc  *
39047135Sbostic  * Standard option processing (a la getopt) for builtin routines.  The
39147135Sbostic  * only argument that is passed to nextopt is the option string; the
39247299Smarc  * other arguments are unnecessary.  It return the character, or '\0' on
39347299Smarc  * end of input.
39447135Sbostic  */
39547135Sbostic 
39647135Sbostic int
nextopt(optstring)39747135Sbostic nextopt(optstring)
39847135Sbostic 	char *optstring;
39947135Sbostic 	{
40047135Sbostic 	register char *p, *q;
40147135Sbostic 	char c;
40247135Sbostic 
40347135Sbostic 	if ((p = optptr) == NULL || *p == '\0') {
40447135Sbostic 		p = *argptr;
40547135Sbostic 		if (p == NULL || *p != '-' || *++p == '\0')
40647299Smarc 			return '\0';
40747135Sbostic 		argptr++;
40847135Sbostic 		if (p[0] == '-' && p[1] == '\0')	/* check for "--" */
40947299Smarc 			return '\0';
41047135Sbostic 	}
41147135Sbostic 	c = *p++;
41247135Sbostic 	for (q = optstring ; *q != c ; ) {
41347135Sbostic 		if (*q == '\0')
41447135Sbostic 			error("Illegal option -%c", c);
41547135Sbostic 		if (*++q == ':')
41647135Sbostic 			q++;
41747135Sbostic 	}
41847135Sbostic 	if (*++q == ':') {
41947135Sbostic 		if (*p == '\0' && (p = *argptr++) == NULL)
42047135Sbostic 			error("No arg for -%c option", c);
42147135Sbostic 		optarg = p;
42247135Sbostic 		p = NULL;
42347135Sbostic 	}
42447135Sbostic 	optptr = p;
42547135Sbostic 	return c;
42647135Sbostic }
427