VirtualBox

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

Last change on this file since 3456 was 3445, checked in by bird, 5 years ago

kash: fixed a couple of alloctions when setting up subshells. Must pass redir to openhere_child.

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

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