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