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