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
procargs(argc,argv)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
optschanged()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
options(cmdline)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
minus_o(name,val)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
setoption(flag,val)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
setparam(argv)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
freeparam(param)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
shiftcmd(argc,argv)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
setcmd(argc,argv)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
getoptscmd(argc,argv)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
nextopt(optstring)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