xref: /original-bsd/bin/sh/options.c (revision b3c06cab)
1 /*-
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Kenneth Almquist.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 static char sccsid[] = "@(#)options.c	8.2 (Berkeley) 05/04/95";
13 #endif /* not lint */
14 
15 #include <signal.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18 
19 #include "shell.h"
20 #define DEFINE_OPTIONS
21 #include "options.h"
22 #undef DEFINE_OPTIONS
23 #include "nodes.h"	/* for other header files */
24 #include "eval.h"
25 #include "jobs.h"
26 #include "input.h"
27 #include "output.h"
28 #include "trap.h"
29 #include "var.h"
30 #include "memalloc.h"
31 #include "error.h"
32 #include "mystring.h"
33 #ifndef NO_HISTORY
34 #include "myhistedit.h"
35 #endif
36 
37 char *arg0;			/* value of $0 */
38 struct shparam shellparam;	/* current positional parameters */
39 char **argptr;			/* argument list for builtin commands */
40 char *optarg;			/* set by nextopt (like getopt) */
41 char *optptr;			/* used by nextopt */
42 
43 char *minusc;			/* argument to -c option */
44 
45 
46 STATIC void options __P((int));
47 STATIC void minus_o __P((char *, int));
48 STATIC void setoption __P((int, int));
49 
50 
51 /*
52  * Process the shell command line arguments.
53  */
54 
55 void
56 procargs(argc, argv)
57 	int argc;
58 	char **argv;
59 {
60 	int i;
61 
62 	argptr = argv;
63 	if (argc > 0)
64 		argptr++;
65 	for (i = 0; i < NOPTS; i++)
66 		optlist[i].val = 2;
67 	options(1);
68 	if (*argptr == NULL && minusc == NULL)
69 		sflag = 1;
70 	if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
71 		iflag = 1;
72 	if (mflag == 2)
73 		mflag = iflag;
74 	for (i = 0; i < NOPTS; i++)
75 		if (optlist[i].val == 2)
76 			optlist[i].val = 0;
77 	arg0 = argv[0];
78 	if (sflag == 0 && minusc == NULL) {
79 		commandname = arg0 = *argptr++;
80 		setinputfile(commandname, 0);
81 	}
82 	shellparam.p = argptr;
83 	/* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
84 	while (*argptr) {
85 		shellparam.nparam++;
86 		argptr++;
87 	}
88 	optschanged();
89 }
90 
91 
92 void
93 optschanged()
94 {
95 	setinteractive(iflag);
96 #ifndef NO_HISTORY
97 	histedit();
98 #endif
99 	setjobctl(mflag);
100 }
101 
102 /*
103  * Process shell options.  The global variable argptr contains a pointer
104  * to the argument list; we advance it past the options.
105  */
106 
107 STATIC void
108 options(cmdline)
109 	int cmdline;
110 {
111 	register char *p;
112 	int val;
113 	int c;
114 
115 	if (cmdline)
116 		minusc = NULL;
117 	while ((p = *argptr) != NULL) {
118 		argptr++;
119 		if ((c = *p++) == '-') {
120 			val = 1;
121                         if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
122                                 if (!cmdline) {
123                                         /* "-" means turn off -x and -v */
124                                         if (p[0] == '\0')
125                                                 xflag = vflag = 0;
126                                         /* "--" means reset params */
127                                         else if (*argptr == NULL)
128 						setparam(argptr);
129                                 }
130 				break;	  /* "-" or  "--" terminates options */
131 			}
132 		} else if (c == '+') {
133 			val = 0;
134 		} else {
135 			argptr--;
136 			break;
137 		}
138 		while ((c = *p++) != '\0') {
139 			if (c == 'c' && cmdline) {
140 				char *q;
141 #ifdef NOHACK	/* removing this code allows sh -ce 'foo' for compat */
142 				if (*p == '\0')
143 #endif
144 					q = *argptr++;
145 				if (q == NULL || minusc != NULL)
146 					error("Bad -c option");
147 				minusc = q;
148 #ifdef NOHACK
149 				break;
150 #endif
151 			} else if (c == 'o') {
152 				minus_o(*argptr, val);
153 				if (*argptr)
154 					argptr++;
155 			} else {
156 				setoption(c, val);
157 			}
158 		}
159 	}
160 }
161 
162 STATIC void
163 minus_o(name, val)
164 	char *name;
165 	int val;
166 {
167 	int i;
168 
169 	if (name == NULL) {
170 		out1str("Current option settings\n");
171 		for (i = 0; i < NOPTS; i++)
172 			out1fmt("%-16s%s\n", optlist[i].name,
173 				optlist[i].val ? "on" : "off");
174 	} else {
175 		for (i = 0; i < NOPTS; i++)
176 			if (equal(name, optlist[i].name)) {
177 				setoption(optlist[i].letter, val);
178 				return;
179 			}
180 		error("Illegal option -o %s", name);
181 	}
182 }
183 
184 
185 STATIC void
186 setoption(flag, val)
187 	char flag;
188 	int val;
189 	{
190 	int i;
191 
192 	for (i = 0; i < NOPTS; i++)
193 		if (optlist[i].letter == flag) {
194 			optlist[i].val = val;
195 			if (val) {
196 				/* #%$ hack for ksh semantics */
197 				if (flag == 'V')
198 					Eflag = 0;
199 				else if (flag == 'E')
200 					Vflag = 0;
201 			}
202 			return;
203 		}
204 	error("Illegal option -%c", flag);
205 }
206 
207 
208 
209 #ifdef mkinit
210 INCLUDE "options.h"
211 
212 SHELLPROC {
213 	int i;
214 
215 	for (i = 0; i < NOPTS; i++)
216 		optlist[i].val = 0;
217 	optschanged();
218 
219 }
220 #endif
221 
222 
223 /*
224  * Set the shell parameters.
225  */
226 
227 void
228 setparam(argv)
229 	char **argv;
230 	{
231 	char **newparam;
232 	char **ap;
233 	int nparam;
234 
235 	for (nparam = 0 ; argv[nparam] ; nparam++);
236 	ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
237 	while (*argv) {
238 		*ap++ = savestr(*argv++);
239 	}
240 	*ap = NULL;
241 	freeparam(&shellparam);
242 	shellparam.malloc = 1;
243 	shellparam.nparam = nparam;
244 	shellparam.p = newparam;
245 	shellparam.optnext = NULL;
246 }
247 
248 
249 /*
250  * Free the list of positional parameters.
251  */
252 
253 void
254 freeparam(param)
255 	struct shparam *param;
256 	{
257 	char **ap;
258 
259 	if (param->malloc) {
260 		for (ap = param->p ; *ap ; ap++)
261 			ckfree(*ap);
262 		ckfree(param->p);
263 	}
264 }
265 
266 
267 
268 /*
269  * The shift builtin command.
270  */
271 
272 int
273 shiftcmd(argc, argv)
274 	int argc;
275 	char **argv;
276 {
277 	int n;
278 	char **ap1, **ap2;
279 
280 	n = 1;
281 	if (argc > 1)
282 		n = number(argv[1]);
283 	if (n > shellparam.nparam)
284 		error("can't shift that many");
285 	INTOFF;
286 	shellparam.nparam -= n;
287 	for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
288 		if (shellparam.malloc)
289 			ckfree(*ap1);
290 	}
291 	ap2 = shellparam.p;
292 	while ((*ap2++ = *ap1++) != NULL);
293 	shellparam.optnext = NULL;
294 	INTON;
295 	return 0;
296 }
297 
298 
299 
300 /*
301  * The set command builtin.
302  */
303 
304 int
305 setcmd(argc, argv)
306 	int argc;
307 	char **argv;
308 {
309 	if (argc == 1)
310 		return showvarscmd(argc, argv);
311 	INTOFF;
312 	options(0);
313 	optschanged();
314 	if (*argptr != NULL) {
315 		setparam(argptr);
316 	}
317 	INTON;
318 	return 0;
319 }
320 
321 
322 /*
323  * The getopts builtin.  Shellparam.optnext points to the next argument
324  * to be processed.  Shellparam.optptr points to the next character to
325  * be processed in the current argument.  If shellparam.optnext is NULL,
326  * then it's the first time getopts has been called.
327  */
328 
329 int
330 getoptscmd(argc, argv)
331 	int argc;
332 	char **argv;
333 {
334 	register char *p, *q;
335 	char c;
336 	char s[10];
337 
338 	if (argc != 3)
339 		error("Usage: getopts optstring var");
340 	if (shellparam.optnext == NULL) {
341 		shellparam.optnext = shellparam.p;
342 		shellparam.optptr = NULL;
343 	}
344 	if ((p = shellparam.optptr) == NULL || *p == '\0') {
345 		p = *shellparam.optnext;
346 		if (p == NULL || *p != '-' || *++p == '\0') {
347 atend:
348 			fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1);
349 			setvar("OPTIND", s, 0);
350 			shellparam.optnext = NULL;
351 			return 1;
352 		}
353 		shellparam.optnext++;
354 		if (p[0] == '-' && p[1] == '\0')	/* check for "--" */
355 			goto atend;
356 	}
357 	c = *p++;
358 	for (q = argv[1] ; *q != c ; ) {
359 		if (*q == '\0') {
360 			out1fmt("Illegal option -%c\n", c);
361 			c = '?';
362 			goto out;
363 		}
364 		if (*++q == ':')
365 			q++;
366 	}
367 	if (*++q == ':') {
368 		if (*p == '\0' && (p = *shellparam.optnext) == NULL) {
369 			out1fmt("No arg for -%c option\n", c);
370 			c = '?';
371 			goto out;
372 		}
373 		shellparam.optnext++;
374 		setvar("OPTARG", p, 0);
375 		p = NULL;
376 	}
377 out:
378 	shellparam.optptr = p;
379 	s[0] = c;
380 	s[1] = '\0';
381 	setvar(argv[2], s, 0);
382 	return 0;
383 }
384 
385 /*
386  * XXX - should get rid of.  have all builtins use getopt(3).  the
387  * library getopt must have the BSD extension static variable "optreset"
388  * otherwise it can't be used within the shell safely.
389  *
390  * Standard option processing (a la getopt) for builtin routines.  The
391  * only argument that is passed to nextopt is the option string; the
392  * other arguments are unnecessary.  It return the character, or '\0' on
393  * end of input.
394  */
395 
396 int
397 nextopt(optstring)
398 	char *optstring;
399 	{
400 	register char *p, *q;
401 	char c;
402 
403 	if ((p = optptr) == NULL || *p == '\0') {
404 		p = *argptr;
405 		if (p == NULL || *p != '-' || *++p == '\0')
406 			return '\0';
407 		argptr++;
408 		if (p[0] == '-' && p[1] == '\0')	/* check for "--" */
409 			return '\0';
410 	}
411 	c = *p++;
412 	for (q = optstring ; *q != c ; ) {
413 		if (*q == '\0')
414 			error("Illegal option -%c", c);
415 		if (*++q == ':')
416 			q++;
417 	}
418 	if (*++q == ':') {
419 		if (*p == '\0' && (p = *argptr++) == NULL)
420 			error("No arg for -%c option", c);
421 		optarg = p;
422 		p = NULL;
423 	}
424 	optptr = p;
425 	return c;
426 }
427