xref: /original-bsd/bin/sh/options.c (revision 3b6250d9)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * 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	5.2 (Berkeley) 03/13/91";
13 #endif /* not lint */
14 
15 #include "shell.h"
16 #define DEFINE_OPTIONS
17 #include "options.h"
18 #undef DEFINE_OPTIONS
19 #include "nodes.h"	/* for other header files */
20 #include "eval.h"
21 #include "jobs.h"
22 #include "input.h"
23 #include "output.h"
24 #include "trap.h"
25 #include "var.h"
26 #include "memalloc.h"
27 #include "error.h"
28 #include "mystring.h"
29 
30 char *arg0;			/* value of $0 */
31 struct shparam shellparam;	/* current positional parameters */
32 char **argptr;			/* argument list for builtin commands */
33 char *optarg;			/* set by nextopt (like getopt) */
34 char *optptr;			/* used by nextopt */
35 
36 char *minusc;			/* argument to -c option */
37 
38 
39 #ifdef __STDC__
40 STATIC void options(int);
41 STATIC void setoption(int, int);
42 #else
43 STATIC void options();
44 STATIC void setoption();
45 #endif
46 
47 
48 
49 /*
50  * Process the shell command line arguments.
51  */
52 
53 void
54 procargs(argc, argv)
55 	char **argv;
56 	{
57 	char *p;
58 
59 	argptr = argv;
60 	if (argc > 0)
61 		argptr++;
62 	for (p = optval ; p < optval + sizeof optval - 1 ; p++)
63 		*p = 2;
64 	options(1);
65 	if (*argptr == NULL && minusc == NULL)
66 		sflag = 1;
67 	if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
68 		iflag = 1;
69 	if (jflag == 2)
70 		jflag = iflag;
71 	for (p = optval ; p < optval + sizeof optval - 1 ; p++)
72 		if (*p == 2)
73 			*p = 0;
74 	arg0 = argv[0];
75 	if (sflag == 0 && minusc == NULL) {
76 		commandname = arg0 = *argptr++;
77 		setinputfile(commandname, 0);
78 	}
79 	shellparam.p = argptr;
80 	/* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
81 	while (*argptr) {
82 		shellparam.nparam++;
83 		argptr++;
84 	}
85 	setinteractive(iflag);
86 	setjobctl(jflag);
87 }
88 
89 
90 
91 /*
92  * Process shell options.  The global variable argptr contains a pointer
93  * to the argument list; we advance it past the options.
94  */
95 
96 STATIC void
97 options(cmdline) {
98 	register char *p;
99 	int val;
100 	int c;
101 
102 	if (cmdline)
103 		minusc = NULL;
104 	while ((p = *argptr) != NULL) {
105 		argptr++;
106 		if ((c = *p++) == '-') {
107 			val = 1;
108                         if (p[0] == '\0' || p[0] == '-' && p[1] == '\0') {
109                                 if (!cmdline) {
110                                         /* "-" means turn off -x and -v */
111                                         if (p[0] == '\0')
112                                                 xflag = vflag = 0;
113                                         /* "--" means reset params */
114                                         else if (*argptr == NULL)
115                                                 setparam(argptr);
116                                 }
117 				break;	  /* "-" or  "--" terminates options */
118 			}
119 		} else if (c == '+') {
120 			val = 0;
121 		} else {
122 			argptr--;
123 			break;
124 		}
125 		while ((c = *p++) != '\0') {
126 			if (c == 'c' && cmdline) {
127 				char *q;
128 #ifdef NOHACK	/* removing this code allows sh -ce 'foo' for compat */
129 				if (*p == '\0')
130 #endif
131 					q = *argptr++;
132 				if (q == NULL || minusc != NULL)
133 					error("Bad -c option");
134 				minusc = q;
135 #ifdef NOHACK
136 				break;
137 #endif
138 			} else {
139 				setoption(c, val);
140 			}
141 		}
142 		if (! cmdline)
143 			break;
144 	}
145 }
146 
147 
148 STATIC void
149 setoption(flag, val)
150 	char flag;
151 	int val;
152 	{
153 	register char *p;
154 
155 	if ((p = strchr(optchar, flag)) == NULL)
156 		error("Illegal option -%c", flag);
157 	optval[p - optchar] = val;
158 }
159 
160 
161 
162 #ifdef mkinit
163 INCLUDE "options.h"
164 
165 SHELLPROC {
166 	char *p;
167 
168 	for (p = optval ; p < optval + sizeof optval ; p++)
169 		*p = 0;
170 }
171 #endif
172 
173 
174 /*
175  * Set the shell parameters.
176  */
177 
178 void
179 setparam(argv)
180 	char **argv;
181 	{
182 	char **newparam;
183 	char **ap;
184 	int nparam;
185 
186 	for (nparam = 0 ; argv[nparam] ; nparam++);
187 	ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
188 	while (*argv) {
189 		*ap++ = savestr(*argv++);
190 	}
191 	*ap = NULL;
192 	freeparam(&shellparam);
193 	shellparam.malloc = 1;
194 	shellparam.nparam = nparam;
195 	shellparam.p = newparam;
196 	shellparam.optnext = NULL;
197 }
198 
199 
200 /*
201  * Free the list of positional parameters.
202  */
203 
204 void
205 freeparam(param)
206 	struct shparam *param;
207 	{
208 	char **ap;
209 
210 	if (param->malloc) {
211 		for (ap = param->p ; *ap ; ap++)
212 			ckfree(*ap);
213 		ckfree(param->p);
214 	}
215 }
216 
217 
218 
219 /*
220  * The shift builtin command.
221  */
222 
223 shiftcmd(argc, argv)  char **argv; {
224 	int n;
225 	char **ap1, **ap2;
226 
227 	n = 1;
228 	if (argc > 1)
229 		n = number(argv[1]);
230 	if (n > shellparam.nparam)
231 		n = shellparam.nparam;
232 	INTOFF;
233 	shellparam.nparam -= n;
234 	for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
235 		if (shellparam.malloc)
236 			ckfree(*ap1);
237 	}
238 	ap2 = shellparam.p;
239 	while ((*ap2++ = *ap1++) != NULL);
240 	shellparam.optnext = NULL;
241 	INTON;
242 	return 0;
243 }
244 
245 
246 
247 /*
248  * The set command builtin.
249  */
250 
251 setcmd(argc, argv)  char **argv; {
252 	if (argc == 1)
253 		return showvarscmd(argc, argv);
254 	INTOFF;
255 	options(0);
256 	setinteractive(iflag);
257 	setjobctl(jflag);
258 	if (*argptr != NULL) {
259 		setparam(argptr);
260 	}
261 	INTON;
262 	return 0;
263 }
264 
265 
266 /*
267  * The getopts builtin.  Shellparam.optnext points to the next argument
268  * to be processed.  Shellparam.optptr points to the next character to
269  * be processed in the current argument.  If shellparam.optnext is NULL,
270  * then it's the first time getopts has been called.
271  */
272 
273 getoptscmd(argc, argv)  char **argv; {
274 	register char *p, *q;
275 	char c;
276 	char s[10];
277 
278 	if (argc != 3)
279 		error("Usage: getopts optstring var");
280 	if (shellparam.optnext == NULL) {
281 		shellparam.optnext = shellparam.p;
282 		shellparam.optptr = NULL;
283 	}
284 	if ((p = shellparam.optptr) == NULL || *p == '\0') {
285 		p = *shellparam.optnext;
286 		if (p == NULL || *p != '-' || *++p == '\0') {
287 atend:
288 			fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1);
289 			setvar("OPTIND", s, 0);
290 			shellparam.optnext = NULL;
291 			return 1;
292 		}
293 		shellparam.optnext++;
294 		if (p[0] == '-' && p[1] == '\0')	/* check for "--" */
295 			goto atend;
296 	}
297 	c = *p++;
298 	for (q = argv[1] ; *q != c ; ) {
299 		if (*q == '\0') {
300 			out1fmt("Illegal option -%c\n", c);
301 			c = '?';
302 			goto out;
303 		}
304 		if (*++q == ':')
305 			q++;
306 	}
307 	if (*++q == ':') {
308 		if (*p == '\0' && (p = *shellparam.optnext) == NULL) {
309 			out1fmt("No arg for -%c option\n", c);
310 			c = '?';
311 			goto out;
312 		}
313 		shellparam.optnext++;
314 		setvar("OPTARG", p, 0);
315 		p = NULL;
316 	}
317 out:
318 	shellparam.optptr = p;
319 	s[0] = c;
320 	s[1] = '\0';
321 	setvar(argv[2], s, 0);
322 	return 0;
323 }
324 
325 /*
326  * Standard option processing (a la getopt) for builtin routines.  The
327  * only argument that is passed to nextopt is the option string; the
328  * other arguments are unnecessary.  It return the character, or '\0' on
329  * end of input.
330  */
331 
332 int
333 nextopt(optstring)
334 	char *optstring;
335 	{
336 	register char *p, *q;
337 	char c;
338 
339 	if ((p = optptr) == NULL || *p == '\0') {
340 		p = *argptr;
341 		if (p == NULL || *p != '-' || *++p == '\0')
342 			return '\0';
343 		argptr++;
344 		if (p[0] == '-' && p[1] == '\0')	/* check for "--" */
345 			return '\0';
346 	}
347 	c = *p++;
348 	for (q = optstring ; *q != c ; ) {
349 		if (*q == '\0')
350 			error("Illegal option -%c", c);
351 		if (*++q == ':')
352 			q++;
353 	}
354 	if (*++q == ':') {
355 		if (*p == '\0' && (p = *argptr++) == NULL)
356 			error("No arg for -%c option", c);
357 		optarg = p;
358 		p = NULL;
359 	}
360 	optptr = p;
361 	return c;
362 }
363