VirtualBox

source: kBuild/trunk/src/kash/options.c

Last change on this file was 3477, checked in by bird, 4 years ago

kash: Use kHlpAssert instead of assert.h (debugger stops on the assertion rather than at exit process code).

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
File size: 15.6 KB
Line 
1/* $NetBSD: options.c,v 1.38 2005/03/20 21:38:17 dsl Exp $ */
2
3/*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#if 0
36#ifndef lint
37static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95";
38#else
39__RCSID("$NetBSD: options.c,v 1.38 2005/03/20 21:38:17 dsl Exp $");
40#endif /* not lint */
41#endif
42
43#include <stdlib.h>
44
45#include "shell.h"
46#define DEFINE_OPTIONS
47#include "options.h"
48#undef DEFINE_OPTIONS
49#include "nodes.h" /* for other header files */
50#include "eval.h"
51#include "jobs.h"
52#include "input.h"
53#include "output.h"
54#include "trap.h"
55#include "var.h"
56#include "memalloc.h"
57#include "error.h"
58#include "mystring.h"
59#ifndef SMALL
60# include "myhistedit.h"
61#endif
62#include "show.h"
63#include "shinstance.h"
64
65//char *arg0; /* value of $0 */
66//struct shparam shellparam; /* current positional parameters */
67//char **argptr; /* argument list for builtin commands */
68//char *optionarg; /* set by nextopt (like getopt) */
69//char *optptr; /* used by nextopt */
70
71//char *minusc; /* argument to -c option */
72
73
74STATIC void options(shinstance *, int);
75STATIC void minus_o(shinstance *, char *, int);
76STATIC void setoption(shinstance *, int, int);
77STATIC int getopts(shinstance *, char *, char *, char **, char ***, char **);
78
79#ifndef SH_FORKED_MODE
80void
81subshellinitoptions(shinstance *psh, shinstance *inherit)
82{
83 unsigned i;
84 int left;
85 const char *arg;
86 memcpy(&psh->optlist[0], &inherit->optlist[0], sizeof(psh->optlist));
87
88 /** @todo opimize: skip this when executing builtins. */
89 /* Whether the subshell uses argptr/shellparam/arg0 or replaces them depends
90 on whether the shell will execute a builtin command or not.
91
92 orgargv is already set by the shinstance.c core code, scan the original
93 again and update arg0, shellparm, argptr and optptr. */
94
95 /* arg0 is either something from orgargv, or in the EXSHELLPROC case a
96 separate allocation that we need to dupe here. The (new) arg0malloc
97 flag indicates which. */
98 i = 0;
99 psh->arg0malloc = inherit->arg0malloc;
100 if (inherit->arg0malloc) {
101 psh->arg0 = savestr(psh, inherit->arg0);
102 } else {
103 while ((arg = inherit->orgargv[i]) != NULL) {
104 if (inherit->arg0 == arg) {
105 psh->arg0 = psh->orgargv[i];
106 break;
107 }
108 i++;
109 }
110 kHlpAssert(psh->arg0 != NULL);
111 }
112
113 /* eval.h's commandname is same as arg0 when set unless we're doing a dot-include. */
114 if (inherit->commandname) {
115 if (inherit->commandname == inherit->arg0) {
116 psh->commandname = psh->arg0;
117 } else {
118 psh->commandname = savestr(psh, inherit->commandname);
119 psh->commandnamemalloc = 1;
120 }
121 }
122
123 /* shellparam is either pointing right after arg0 in orgargv, though it may
124 also be a separately allocated thing (see setparam), or pointing to the
125 arguments of a shell function we're executing (see eval.c). All in all,
126 it's simpler if we just copy the whole darn thing, ASSUMING no
127 modifications will be made that are needed to be visible elsewhere.
128 */
129 psh->shellparam.malloc = 1;
130 psh->shellparam.reset = inherit->shellparam.reset;
131 psh->shellparam.nparam = left = inherit->shellparam.nparam;
132 kHlpAssert(left >= 0);
133 psh->shellparam.p = (char **)ckmalloc(psh, (left + 1) * sizeof(psh->shellparam.p[0]));
134 psh->shellparam.p[left] = NULL;
135 while (left-- > 0) {
136 arg = inherit->shellparam.p[left];
137 psh->shellparam.p[left] = savestr(psh, arg);
138 }
139
140 /* The shellparam.optnext member is either NULL or points to a 'p' entry. */
141 if (inherit->shellparam.optnext) {
142 size_t idx = (size_t)(inherit->shellparam.optnext - inherit->shellparam.p);
143 kHlpAssert(idx <= inherit->shellparam.nparam);
144 if (idx <= inherit->shellparam.nparam)
145 psh->shellparam.optnext = &psh->shellparam.p[idx];
146 }
147
148 /* The shellparam.optptr member is either NULL or points within argument
149 prior to shellparam.optnext. We can leave it as NULL if at the EOS. */
150 if (inherit->shellparam.optptr && *inherit->shellparam.optptr != '\0') {
151 intptr_t idx;
152 if (!inherit->shellparam.optnext || inherit->shellparam.optnext == inherit->shellparam.p)
153 idx = (intptr_t)(inherit->shellparam.nparam - 1);
154 else {
155 idx = (intptr_t)(inherit->shellparam.optnext - inherit->shellparam.p - 1);
156 if (idx > inherit->shellparam.nparam)
157 idx = inherit->shellparam.nparam - 1;
158 }
159 while (idx >= 0) {
160 size_t arglen, off;
161 arg = inherit->shellparam.p[idx];
162 arglen = strlen(arg);
163 off = (size_t)(inherit->shellparam.optptr - arg);
164 if (off < arglen) {
165 psh->shellparam.optptr = psh->shellparam.p[idx] + off;
166 break;
167 }
168 off--;
169 }
170 kHlpAssert(psh->shellparam.optptr != NULL);
171 }
172
173 /* minusc: only used in main.c, so not applicable to subshells. */
174 /* optionarg: only used by callers of nextopt, so not relevant when forking subhells. */
175}
176#endif /* SH_FORKED_MODE */
177
178
179/*
180 * Process the shell command line arguments.
181 */
182
183void
184procargs(shinstance *psh, int argc, char **argv)
185{
186 int i;
187
188 psh->argptr = argv;
189 if (argc > 0)
190 psh->argptr++;
191 for (i = 0; i < NOPTS; i++)
192 psh->optlist[i].val = 2;
193 options(psh, 1);
194 if (*psh->argptr == NULL && psh->minusc == NULL)
195 sflag(psh) = 1;
196 if (iflag(psh) == 2 && sflag(psh) == 1 && shfile_isatty(&psh->fdtab, 0) && shfile_isatty(&psh->fdtab, 1))
197 iflag(psh) = 1;
198 if (mflag(psh) == 2)
199 mflag(psh) = iflag(psh);
200 for (i = 0; i < NOPTS; i++)
201 if (psh->optlist[i].val == 2)
202 psh->optlist[i].val = 0;
203#if DEBUG == 2
204 debug(psh) = 1;
205#endif
206 psh->commandnamemalloc = 0;
207 psh->arg0malloc = 0;
208 psh->arg0 = argv[0];
209 if (sflag(psh) == 0 && psh->minusc == NULL) {
210 psh->commandname = argv[0];
211 psh->arg0 = *psh->argptr++;
212 setinputfile(psh, psh->arg0, 0);
213 psh->commandname = psh->arg0;
214 }
215 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
216 if (psh->minusc != NULL) {
217 if (psh->argptr == NULL || *psh->argptr == NULL)
218 error(psh, "Bad -c option");
219 psh->minusc = *psh->argptr++;
220 if (*psh->argptr != 0)
221 psh->arg0 = *psh->argptr++;
222 }
223
224 psh->shellparam.p = psh->argptr;
225 psh->shellparam.reset = 1;
226 /* kHlpAssert(shellparam.malloc == 0 && shellparam.nparam == 0); */
227 while (*psh->argptr) {
228 psh->shellparam.nparam++;
229 psh->argptr++;
230 }
231 optschanged(psh);
232}
233
234
235void
236optschanged(shinstance *psh)
237{
238 setinteractive(psh, iflag(psh));
239#ifndef SMALL
240 histedit(psh);
241#endif
242 setjobctl(psh, mflag(psh));
243}
244
245/*
246 * Process shell options. The global variable argptr contains a pointer
247 * to the argument list; we advance it past the options.
248 */
249
250STATIC void
251options(shinstance *psh, int cmdline)
252{
253 static char empty[] = "";
254 char *p;
255 int val;
256 int c;
257
258 if (cmdline)
259 psh->minusc = NULL;
260 while ((p = *psh->argptr) != NULL) {
261 psh->argptr++;
262 if ((c = *p++) == '-') {
263 val = 1;
264 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
265 if (!cmdline) {
266 /* "-" means turn off -x and -v */
267 if (p[0] == '\0')
268 xflag(psh) = vflag(psh) = 0;
269 /* "--" means reset params */
270 else if (*psh->argptr == NULL)
271 setparam(psh, psh->argptr);
272 }
273 break; /* "-" or "--" terminates options */
274 }
275 } else if (c == '+') {
276 val = 0;
277 } else {
278 psh->argptr--;
279 break;
280 }
281 while ((c = *p++) != '\0') {
282 if (c == 'c' && cmdline) {
283 /* command is after shell args*/
284 psh->minusc = empty;
285 } else if (c == 'o') {
286 minus_o(psh, *psh->argptr, val);
287 if (*psh->argptr)
288 psh->argptr++;
289 } else {
290 setoption(psh, c, val);
291 }
292 }
293 }
294}
295
296static void
297set_opt_val(shinstance *psh, int i, int val)
298{
299 int j;
300 int flag;
301
302 if (val && (flag = psh->optlist[i].opt_set)) {
303 /* some options (eg vi/emacs) are mutually exclusive */
304 for (j = 0; j < NOPTS; j++)
305 if (psh->optlist[j].opt_set == flag)
306 psh->optlist[j].val = 0;
307 }
308 psh->optlist[i].val = val;
309#ifdef DEBUG
310 if (&psh->optlist[i].val == &debug(psh))
311 opentrace(psh);
312#endif
313}
314
315STATIC void
316minus_o(shinstance *psh, char *name, int val)
317{
318 int i;
319
320 if (name == NULL) {
321 out1str(psh, "Current option settings\n");
322 for (i = 0; i < NOPTS; i++)
323 out1fmt(psh, "%-16s%s\n", psh->optlist[i].name,
324 psh->optlist[i].val ? "on" : "off");
325 } else {
326 for (i = 0; i < NOPTS; i++)
327 if (equal(name, psh->optlist[i].name)) {
328 set_opt_val(psh, i, val);
329 return;
330 }
331 error(psh, "Illegal option -o %s", name);
332 }
333}
334
335
336STATIC void
337setoption(shinstance *psh, int flag, int val)
338{
339 int i;
340
341 for (i = 0; i < NOPTS; i++)
342 if (psh->optlist[i].letter == flag) {
343 set_opt_val(psh, i, val);
344 return;
345 }
346 error(psh, "Illegal option -%c", flag);
347 /* NOTREACHED */
348}
349
350
351
352#ifdef mkinit
353INCLUDE "options.h"
354
355INIT {
356 memcpy(&psh->optlist[0], &ro_optlist[0], sizeof(psh->optlist));
357}
358
359SHELLPROC {
360 int i;
361
362 for (i = 0; psh->optlist[i].name; i++)
363 psh->optlist[i].val = 0;
364# if DEBUG == 2
365 debug(psh) = 1;
366# endif
367 optschanged(psh);
368}
369#endif
370
371
372/*
373 * Set the shell parameters.
374 */
375
376void
377setparam(shinstance *psh, char **argv)
378{
379 char **newparam;
380 char **ap;
381 int nparam;
382
383 for (nparam = 0 ; argv[nparam] ; nparam++)
384 continue;
385 ap = newparam = ckmalloc(psh, (nparam + 1) * sizeof *ap);
386 while (*argv) {
387 *ap++ = savestr(psh, *argv++);
388 }
389 *ap = NULL;
390 freeparam(psh, &psh->shellparam);
391 psh->shellparam.malloc = 1;
392 psh->shellparam.nparam = nparam;
393 psh->shellparam.p = newparam;
394 psh->shellparam.optnext = NULL;
395}
396
397
398/*
399 * Free the list of positional parameters.
400 */
401
402void
403freeparam(shinstance *psh, volatile struct shparam *param)
404{
405 char **ap;
406
407 if (param->malloc) {
408 for (ap = param->p ; *ap ; ap++)
409 ckfree(psh, *ap);
410 ckfree(psh, param->p);
411 }
412}
413
414
415
416/*
417 * The shift builtin command.
418 */
419
420int
421shiftcmd(shinstance *psh, int argc, char **argv)
422{
423 int n;
424 char **ap1, **ap2;
425
426 n = 1;
427 if (argc > 1)
428 n = number(psh, argv[1]);
429 if (n > psh->shellparam.nparam)
430 error(psh, "can't shift that many");
431 INTOFF;
432 psh->shellparam.nparam -= n;
433 for (ap1 = psh->shellparam.p ; --n >= 0 ; ap1++) {
434 if (psh->shellparam.malloc)
435 ckfree(psh, *ap1);
436 }
437 ap2 = psh->shellparam.p;
438 while ((*ap2++ = *ap1++) != NULL);
439 psh->shellparam.optnext = NULL;
440 INTON;
441 return 0;
442}
443
444
445
446/*
447 * The set command builtin.
448 */
449
450int
451setcmd(shinstance *psh, int argc, char **argv)
452{
453 if (argc == 1)
454 return showvars(psh, 0, 0, 1);
455 INTOFF;
456 options(psh, 0);
457 optschanged(psh);
458 if (*psh->argptr != NULL) {
459 setparam(psh, psh->argptr);
460 }
461 INTON;
462 return 0;
463}
464
465
466void
467getoptsreset(shinstance *psh, const char *value)
468{
469 if (number(psh, value) == 1) {
470 psh->shellparam.optnext = NULL;
471 psh->shellparam.reset = 1;
472 }
473}
474
475/*
476 * The getopts builtin. Shellparam.optnext points to the next argument
477 * to be processed. Shellparam.optptr points to the next character to
478 * be processed in the current argument. If shellparam.optnext is NULL,
479 * then it's the first time getopts has been called.
480 */
481
482int
483getoptscmd(shinstance *psh, int argc, char **argv)
484{
485 char **optbase;
486
487 if (argc < 3)
488 error(psh, "usage: getopts optstring var [arg]");
489 else if (argc == 3)
490 optbase = psh->shellparam.p;
491 else
492 optbase = &argv[3];
493
494 if (psh->shellparam.reset == 1) {
495 psh->shellparam.optnext = optbase;
496 psh->shellparam.optptr = NULL;
497 psh->shellparam.reset = 0;
498 }
499
500 return getopts(psh, argv[1], argv[2], optbase, &psh->shellparam.optnext,
501 &psh->shellparam.optptr);
502}
503
504STATIC int
505getopts(shinstance *psh, char *optstr, char *optvar, char **optfirst, char ***optnext, char **optpptr)
506{
507 char *p, *q;
508 char c = '?';
509 int done = 0;
510 int ind = 0;
511 int err = 0;
512 char s[12];
513
514 if ((p = *optpptr) == NULL || *p == '\0') {
515 /* Current word is done, advance */
516 if (*optnext == NULL)
517 return 1;
518 p = **optnext;
519 if (p == NULL || *p != '-' || *++p == '\0') {
520atend:
521 ind = (int)(*optnext - optfirst + 1);
522 *optnext = NULL;
523 p = NULL;
524 done = 1;
525 goto out;
526 }
527 (*optnext)++;
528 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
529 goto atend;
530 }
531
532 c = *p++;
533 for (q = optstr; *q != c; ) {
534 if (*q == '\0') {
535 if (optstr[0] == ':') {
536 s[0] = c;
537 s[1] = '\0';
538 err |= setvarsafe(psh, "OPTARG", s, 0);
539 } else {
540 outfmt(&psh->errout, "Illegal option -%c\n", c);
541 (void) unsetvar(psh, "OPTARG", 0);
542 }
543 c = '?';
544 goto bad;
545 }
546 if (*++q == ':')
547 q++;
548 }
549
550 if (*++q == ':') {
551 if (*p == '\0' && (p = **optnext) == NULL) {
552 if (optstr[0] == ':') {
553 s[0] = c;
554 s[1] = '\0';
555 err |= setvarsafe(psh, "OPTARG", s, 0);
556 c = ':';
557 } else {
558 outfmt(&psh->errout, "No arg for -%c option\n", c);
559 (void) unsetvar(psh, "OPTARG", 0);
560 c = '?';
561 }
562 goto bad;
563 }
564
565 if (p == **optnext)
566 (*optnext)++;
567 err |= setvarsafe(psh, "OPTARG", p, 0);
568 p = NULL;
569 } else
570 err |= setvarsafe(psh, "OPTARG", "", 0);
571 ind = (int)(*optnext - optfirst + 1);
572 goto out;
573
574bad:
575 ind = 1;
576 *optnext = NULL;
577 p = NULL;
578out:
579 *optpptr = p;
580 fmtstr(s, sizeof(s), "%d", ind);
581 err |= setvarsafe(psh, "OPTIND", s, VNOFUNC);
582 s[0] = c;
583 s[1] = '\0';
584 err |= setvarsafe(psh, optvar, s, 0);
585 if (err) {
586 *optnext = NULL;
587 *optpptr = NULL;
588 output_flushall(psh);
589 exraise(psh, EXERROR);
590 }
591 return done;
592}
593
594/*
595 * XXX - should get rid of. have all builtins use getopt(3). the
596 * library getopt must have the BSD extension static variable "optreset"
597 * otherwise it can't be used within the shell safely.
598 *
599 * Standard option processing (a la getopt) for builtin routines. The
600 * only argument that is passed to nextopt is the option string; the
601 * other arguments are unnecessary. It return the character, or '\0' on
602 * end of input.
603 */
604
605int
606nextopt(shinstance *psh, const char *optstring)
607{
608 char *p;
609 const char *q;
610 char c;
611
612 if ((p = psh->optptr) == NULL || *p == '\0') {
613 p = *psh->argptr;
614 if (p == NULL || *p != '-' || *++p == '\0')
615 return '\0';
616 psh->argptr++;
617 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
618 return '\0';
619 }
620 c = *p++;
621 for (q = optstring ; *q != c ; ) {
622 if (*q == '\0')
623 error(psh, "Illegal option -%c", c);
624 if (*++q == ':')
625 q++;
626 }
627 if (*++q == ':') {
628 if (*p == '\0' && (p = *psh->argptr++) == NULL)
629 error(psh, "No arg for -%c option", c);
630 psh->optionarg = p;
631 p = NULL;
632 }
633 psh->optptr = p;
634 return c;
635}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette