misc cleanup
[unix-history] / usr / src / bin / sh / options.c
CommitLineData
6af41caa 1/*-
d1b73048
KB
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
6af41caa
KB
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
13b3e634 12static char sccsid[] = "@(#)options.c 8.2 (Berkeley) %G%";
6af41caa
KB
13#endif /* not lint */
14
13b3e634
CZ
15#include <signal.h>
16#include <unistd.h>
17#include <stdlib.h>
18
6af41caa
KB
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"
13b3e634
CZ
33#ifndef NO_HISTORY
34#include "myhistedit.h"
35#endif
6af41caa
KB
36
37char *arg0; /* value of $0 */
38struct shparam shellparam; /* current positional parameters */
39char **argptr; /* argument list for builtin commands */
40char *optarg; /* set by nextopt (like getopt) */
41char *optptr; /* used by nextopt */
42
43char *minusc; /* argument to -c option */
44
45
13b3e634
CZ
46STATIC void options __P((int));
47STATIC void minus_o __P((char *, int));
48STATIC void setoption __P((int, int));
6af41caa
KB
49
50
51/*
52 * Process the shell command line arguments.
53 */
54
55void
56procargs(argc, argv)
13b3e634 57 int argc;
6af41caa 58 char **argv;
13b3e634 59{
838b4aae 60 int i;
6af41caa
KB
61
62 argptr = argv;
63 if (argc > 0)
64 argptr++;
838b4aae
MT
65 for (i = 0; i < NOPTS; i++)
66 optlist[i].val = 2;
6af41caa
KB
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;
838b4aae
MT
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;
6af41caa
KB
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 }
838b4aae 88 optschanged();
6af41caa
KB
89}
90
91
13b3e634
CZ
92void
93optschanged()
94{
838b4aae 95 setinteractive(iflag);
13b3e634 96#ifndef NO_HISTORY
838b4aae 97 histedit();
13b3e634 98#endif
838b4aae
MT
99 setjobctl(mflag);
100}
6af41caa
KB
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
107STATIC void
13b3e634
CZ
108options(cmdline)
109 int cmdline;
110{
6af41caa
KB
111 register char *p;
112 int val;
113 int c;
114
ddba57cd
MT
115 if (cmdline)
116 minusc = NULL;
6af41caa
KB
117 while ((p = *argptr) != NULL) {
118 argptr++;
119 if ((c = *p++) == '-') {
120 val = 1;
13b3e634 121 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
ddba57cd
MT
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)
13b3e634 128 setparam(argptr);
ddba57cd 129 }
6af41caa 130 break; /* "-" or "--" terminates options */
ddba57cd 131 }
6af41caa
KB
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;
ddba57cd 141#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
6af41caa
KB
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
838b4aae
MT
151 } else if (c == 'o') {
152 minus_o(*argptr, val);
153 if (*argptr)
154 argptr++;
6af41caa
KB
155 } else {
156 setoption(c, val);
157 }
158 }
6af41caa
KB
159 }
160}
161
838b4aae
MT
162STATIC void
163minus_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
6af41caa
KB
184
185STATIC void
186setoption(flag, val)
187 char flag;
188 int val;
189 {
838b4aae
MT
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);
6af41caa
KB
205}
206
207
208
209#ifdef mkinit
210INCLUDE "options.h"
211
212SHELLPROC {
838b4aae
MT
213 int i;
214
215 for (i = 0; i < NOPTS; i++)
216 optlist[i].val = 0;
217 optschanged();
6af41caa 218
6af41caa
KB
219}
220#endif
221
222
223/*
224 * Set the shell parameters.
225 */
226
227void
228setparam(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
253void
254freeparam(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
13b3e634
CZ
272int
273shiftcmd(argc, argv)
274 int argc;
275 char **argv;
276{
6af41caa
KB
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)
f9a81c0d 284 error("can't shift that many");
6af41caa
KB
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
13b3e634
CZ
304int
305setcmd(argc, argv)
306 int argc;
307 char **argv;
308{
6af41caa
KB
309 if (argc == 1)
310 return showvarscmd(argc, argv);
311 INTOFF;
312 options(0);
838b4aae 313 optschanged();
6af41caa
KB
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
13b3e634
CZ
329int
330getoptscmd(argc, argv)
331 int argc;
332 char **argv;
333{
6af41caa
KB
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') {
347atend:
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 }
377out:
378 shellparam.optptr = p;
379 s[0] = c;
380 s[1] = '\0';
381 setvar(argv[2], s, 0);
382 return 0;
383}
384
6af41caa 385/*
838b4aae
MT
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 *
6af41caa
KB
390 * Standard option processing (a la getopt) for builtin routines. The
391 * only argument that is passed to nextopt is the option string; the
ddba57cd
MT
392 * other arguments are unnecessary. It return the character, or '\0' on
393 * end of input.
6af41caa
KB
394 */
395
396int
397nextopt(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')
ddba57cd 406 return '\0';
6af41caa
KB
407 argptr++;
408 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
ddba57cd 409 return '\0';
6af41caa
KB
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}