Contents of /trunk/mkinitrd-magellan/klibc/usr/dash/options.c
Parent Directory | Revision Log
Revision 532 -
(show annotations)
(download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 11155 byte(s)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 11155 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd
1 | /*- |
2 | * Copyright (c) 1991, 1993 |
3 | * The Regents of the University of California. All rights reserved. |
4 | * Copyright (c) 1997-2005 |
5 | * Herbert Xu <herbert@gondor.apana.org.au>. 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 | #include <signal.h> |
36 | #include <unistd.h> |
37 | #include <stdlib.h> |
38 | |
39 | #include "shell.h" |
40 | #define DEFINE_OPTIONS |
41 | #include "options.h" |
42 | #undef DEFINE_OPTIONS |
43 | #include "nodes.h" /* for other header files */ |
44 | #include "eval.h" |
45 | #include "jobs.h" |
46 | #include "input.h" |
47 | #include "output.h" |
48 | #include "trap.h" |
49 | #include "var.h" |
50 | #include "memalloc.h" |
51 | #include "error.h" |
52 | #include "mystring.h" |
53 | #ifndef SMALL |
54 | #include "myhistedit.h" |
55 | #endif |
56 | #include "show.h" |
57 | |
58 | char *arg0; /* value of $0 */ |
59 | struct shparam shellparam; /* current positional parameters */ |
60 | char **argptr; /* argument list for builtin commands */ |
61 | char *optionarg; /* set by nextopt (like getopt) */ |
62 | char *optptr; /* used by nextopt */ |
63 | |
64 | char *minusc; /* argument to -c option */ |
65 | |
66 | static const char *const optnames[NOPTS] = { |
67 | "errexit", |
68 | "noglob", |
69 | "ignoreeof", |
70 | "interactive", |
71 | "monitor", |
72 | "noexec", |
73 | "stdin", |
74 | "xtrace", |
75 | "verbose", |
76 | "vi", |
77 | "emacs", |
78 | "noclobber", |
79 | "allexport", |
80 | "notify", |
81 | "nounset", |
82 | "nolog", |
83 | "debug", |
84 | }; |
85 | |
86 | const char optletters[NOPTS] = { |
87 | 'e', |
88 | 'f', |
89 | 'I', |
90 | 'i', |
91 | 'm', |
92 | 'n', |
93 | 's', |
94 | 'x', |
95 | 'v', |
96 | 'V', |
97 | 'E', |
98 | 'C', |
99 | 'a', |
100 | 'b', |
101 | 'u', |
102 | 0, |
103 | 0, |
104 | }; |
105 | |
106 | char optlist[NOPTS]; |
107 | |
108 | |
109 | STATIC void options(int); |
110 | STATIC void minus_o(char *, int); |
111 | STATIC void setoption(int, int); |
112 | STATIC int getopts(char *, char *, char **, int *, int *); |
113 | |
114 | |
115 | /* |
116 | * Process the shell command line arguments. |
117 | */ |
118 | |
119 | void |
120 | procargs(int argc, char **argv) |
121 | { |
122 | int i; |
123 | const char *xminusc; |
124 | char **xargv; |
125 | |
126 | xargv = argv; |
127 | arg0 = xargv[0]; |
128 | if (argc > 0) |
129 | xargv++; |
130 | for (i = 0; i < NOPTS; i++) |
131 | optlist[i] = 2; |
132 | argptr = xargv; |
133 | options(1); |
134 | xargv = argptr; |
135 | xminusc = minusc; |
136 | if (*xargv == NULL) { |
137 | if (xminusc) |
138 | sh_error("-c requires an argument"); |
139 | sflag = 1; |
140 | } |
141 | if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) |
142 | iflag = 1; |
143 | if (mflag == 2) |
144 | mflag = iflag; |
145 | for (i = 0; i < NOPTS; i++) |
146 | if (optlist[i] == 2) |
147 | optlist[i] = 0; |
148 | #if DEBUG == 2 |
149 | debug = 1; |
150 | #endif |
151 | /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ |
152 | if (xminusc) { |
153 | minusc = *xargv++; |
154 | if (*xargv) |
155 | goto setarg0; |
156 | } else if (!sflag) { |
157 | setinputfile(*xargv, 0); |
158 | setarg0: |
159 | arg0 = *xargv++; |
160 | commandname = arg0; |
161 | } |
162 | |
163 | shellparam.p = xargv; |
164 | shellparam.optind = 1; |
165 | shellparam.optoff = -1; |
166 | /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ |
167 | while (*xargv) { |
168 | shellparam.nparam++; |
169 | xargv++; |
170 | } |
171 | optschanged(); |
172 | } |
173 | |
174 | |
175 | void |
176 | optschanged(void) |
177 | { |
178 | #ifdef DEBUG |
179 | opentrace(); |
180 | #endif |
181 | setinteractive(iflag); |
182 | #ifndef SMALL |
183 | histedit(); |
184 | #endif |
185 | setjobctl(mflag); |
186 | } |
187 | |
188 | /* |
189 | * Process shell options. The global variable argptr contains a pointer |
190 | * to the argument list; we advance it past the options. |
191 | */ |
192 | |
193 | STATIC void |
194 | options(int cmdline) |
195 | { |
196 | char *p; |
197 | int val; |
198 | int c; |
199 | |
200 | if (cmdline) |
201 | minusc = NULL; |
202 | while ((p = *argptr) != NULL) { |
203 | argptr++; |
204 | if ((c = *p++) == '-') { |
205 | val = 1; |
206 | if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) { |
207 | if (!cmdline) { |
208 | /* "-" means turn off -x and -v */ |
209 | if (p[0] == '\0') |
210 | xflag = vflag = 0; |
211 | /* "--" means reset params */ |
212 | else if (*argptr == NULL) |
213 | setparam(argptr); |
214 | } |
215 | break; /* "-" or "--" terminates options */ |
216 | } |
217 | } else if (c == '+') { |
218 | val = 0; |
219 | } else { |
220 | argptr--; |
221 | break; |
222 | } |
223 | while ((c = *p++) != '\0') { |
224 | if (c == 'c' && cmdline) { |
225 | minusc = p; /* command is after shell args*/ |
226 | } else if (c == 'o') { |
227 | minus_o(*argptr, val); |
228 | if (*argptr) |
229 | argptr++; |
230 | } else { |
231 | setoption(c, val); |
232 | } |
233 | } |
234 | } |
235 | } |
236 | |
237 | STATIC void |
238 | minus_o(char *name, int val) |
239 | { |
240 | int i; |
241 | |
242 | if (name == NULL) { |
243 | out1str("Current option settings\n"); |
244 | for (i = 0; i < NOPTS; i++) |
245 | out1fmt("%-16s%s\n", optnames[i], |
246 | optlist[i] ? "on" : "off"); |
247 | } else { |
248 | for (i = 0; i < NOPTS; i++) |
249 | if (equal(name, optnames[i])) { |
250 | optlist[i] = val; |
251 | return; |
252 | } |
253 | sh_error("Illegal option -o %s", name); |
254 | } |
255 | } |
256 | |
257 | |
258 | STATIC void |
259 | setoption(int flag, int val) |
260 | { |
261 | int i; |
262 | |
263 | for (i = 0; i < NOPTS; i++) |
264 | if (optletters[i] == flag) { |
265 | optlist[i] = val; |
266 | if (val) { |
267 | /* #%$ hack for ksh semantics */ |
268 | if (flag == 'V') |
269 | Eflag = 0; |
270 | else if (flag == 'E') |
271 | Vflag = 0; |
272 | } |
273 | return; |
274 | } |
275 | sh_error("Illegal option -%c", flag); |
276 | /* NOTREACHED */ |
277 | } |
278 | |
279 | |
280 | |
281 | /* |
282 | * Set the shell parameters. |
283 | */ |
284 | |
285 | void |
286 | setparam(char **argv) |
287 | { |
288 | char **newparam; |
289 | char **ap; |
290 | int nparam; |
291 | |
292 | for (nparam = 0 ; argv[nparam] ; nparam++); |
293 | ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); |
294 | while (*argv) { |
295 | *ap++ = savestr(*argv++); |
296 | } |
297 | *ap = NULL; |
298 | freeparam(&shellparam); |
299 | shellparam.malloc = 1; |
300 | shellparam.nparam = nparam; |
301 | shellparam.p = newparam; |
302 | shellparam.optind = 1; |
303 | shellparam.optoff = -1; |
304 | } |
305 | |
306 | |
307 | /* |
308 | * Free the list of positional parameters. |
309 | */ |
310 | |
311 | void |
312 | freeparam(volatile struct shparam *param) |
313 | { |
314 | char **ap; |
315 | |
316 | if (param->malloc) { |
317 | for (ap = param->p ; *ap ; ap++) |
318 | ckfree(*ap); |
319 | ckfree(param->p); |
320 | } |
321 | } |
322 | |
323 | |
324 | |
325 | /* |
326 | * The shift builtin command. |
327 | */ |
328 | |
329 | int |
330 | shiftcmd(int argc, char **argv) |
331 | { |
332 | int n; |
333 | char **ap1, **ap2; |
334 | |
335 | n = 1; |
336 | if (argc > 1) |
337 | n = number(argv[1]); |
338 | if (n > shellparam.nparam) |
339 | sh_error("can't shift that many"); |
340 | INTOFF; |
341 | shellparam.nparam -= n; |
342 | for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { |
343 | if (shellparam.malloc) |
344 | ckfree(*ap1); |
345 | } |
346 | ap2 = shellparam.p; |
347 | while ((*ap2++ = *ap1++) != NULL); |
348 | shellparam.optind = 1; |
349 | shellparam.optoff = -1; |
350 | INTON; |
351 | return 0; |
352 | } |
353 | |
354 | |
355 | |
356 | /* |
357 | * The set command builtin. |
358 | */ |
359 | |
360 | int |
361 | setcmd(int argc, char **argv) |
362 | { |
363 | if (argc == 1) |
364 | return showvars(nullstr, 0, VUNSET); |
365 | INTOFF; |
366 | options(0); |
367 | optschanged(); |
368 | if (*argptr != NULL) { |
369 | setparam(argptr); |
370 | } |
371 | INTON; |
372 | return 0; |
373 | } |
374 | |
375 | |
376 | void |
377 | getoptsreset(value) |
378 | const char *value; |
379 | { |
380 | shellparam.optind = number(value); |
381 | shellparam.optoff = -1; |
382 | } |
383 | |
384 | /* |
385 | * The getopts builtin. Shellparam.optnext points to the next argument |
386 | * to be processed. Shellparam.optptr points to the next character to |
387 | * be processed in the current argument. If shellparam.optnext is NULL, |
388 | * then it's the first time getopts has been called. |
389 | */ |
390 | |
391 | int |
392 | getoptscmd(int argc, char **argv) |
393 | { |
394 | char **optbase; |
395 | |
396 | if (argc < 3) |
397 | sh_error("Usage: getopts optstring var [arg]"); |
398 | else if (argc == 3) { |
399 | optbase = shellparam.p; |
400 | if (shellparam.optind > shellparam.nparam + 1) { |
401 | shellparam.optind = 1; |
402 | shellparam.optoff = -1; |
403 | } |
404 | } |
405 | else { |
406 | optbase = &argv[3]; |
407 | if (shellparam.optind > argc - 2) { |
408 | shellparam.optind = 1; |
409 | shellparam.optoff = -1; |
410 | } |
411 | } |
412 | |
413 | return getopts(argv[1], argv[2], optbase, &shellparam.optind, |
414 | &shellparam.optoff); |
415 | } |
416 | |
417 | STATIC int |
418 | getopts(char *optstr, char *optvar, char **optfirst, int *optind, int *optoff) |
419 | { |
420 | char *p, *q; |
421 | char c = '?'; |
422 | int done = 0; |
423 | int err = 0; |
424 | char s[12]; |
425 | char **optnext; |
426 | |
427 | if (*optind < 1) |
428 | return 1; |
429 | optnext = optfirst + *optind - 1; |
430 | |
431 | if (*optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff) |
432 | p = NULL; |
433 | else |
434 | p = optnext[-1] + *optoff; |
435 | if (p == NULL || *p == '\0') { |
436 | /* Current word is done, advance */ |
437 | p = *optnext; |
438 | if (p == NULL || *p != '-' || *++p == '\0') { |
439 | atend: |
440 | p = NULL; |
441 | done = 1; |
442 | goto out; |
443 | } |
444 | optnext++; |
445 | if (p[0] == '-' && p[1] == '\0') /* check for "--" */ |
446 | goto atend; |
447 | } |
448 | |
449 | c = *p++; |
450 | for (q = optstr; *q != c; ) { |
451 | if (*q == '\0') { |
452 | if (optstr[0] == ':') { |
453 | s[0] = c; |
454 | s[1] = '\0'; |
455 | err |= setvarsafe("OPTARG", s, 0); |
456 | } else { |
457 | outfmt(&errout, "Illegal option -%c\n", c); |
458 | (void) unsetvar("OPTARG"); |
459 | } |
460 | c = '?'; |
461 | goto out; |
462 | } |
463 | if (*++q == ':') |
464 | q++; |
465 | } |
466 | |
467 | if (*++q == ':') { |
468 | if (*p == '\0' && (p = *optnext) == NULL) { |
469 | if (optstr[0] == ':') { |
470 | s[0] = c; |
471 | s[1] = '\0'; |
472 | err |= setvarsafe("OPTARG", s, 0); |
473 | c = ':'; |
474 | } else { |
475 | outfmt(&errout, "No arg for -%c option\n", c); |
476 | (void) unsetvar("OPTARG"); |
477 | c = '?'; |
478 | } |
479 | goto out; |
480 | } |
481 | |
482 | if (p == *optnext) |
483 | optnext++; |
484 | err |= setvarsafe("OPTARG", p, 0); |
485 | p = NULL; |
486 | } else |
487 | err |= setvarsafe("OPTARG", nullstr, 0); |
488 | |
489 | out: |
490 | *optoff = p ? p - *(optnext - 1) : -1; |
491 | *optind = optnext - optfirst + 1; |
492 | fmtstr(s, sizeof(s), "%d", *optind); |
493 | err |= setvarsafe("OPTIND", s, VNOFUNC); |
494 | s[0] = c; |
495 | s[1] = '\0'; |
496 | err |= setvarsafe(optvar, s, 0); |
497 | if (err) { |
498 | *optind = 1; |
499 | *optoff = -1; |
500 | flushall(); |
501 | exraise(EXERROR); |
502 | } |
503 | return done; |
504 | } |
505 | |
506 | /* |
507 | * XXX - should get rid of. have all builtins use getopt(3). the |
508 | * library getopt must have the BSD extension static variable "optreset" |
509 | * otherwise it can't be used within the shell safely. |
510 | * |
511 | * Standard option processing (a la getopt) for builtin routines. The |
512 | * only argument that is passed to nextopt is the option string; the |
513 | * other arguments are unnecessary. It return the character, or '\0' on |
514 | * end of input. |
515 | */ |
516 | |
517 | int |
518 | nextopt(const char *optstring) |
519 | { |
520 | char *p; |
521 | const char *q; |
522 | char c; |
523 | |
524 | if ((p = optptr) == NULL || *p == '\0') { |
525 | p = *argptr; |
526 | if (p == NULL || *p != '-' || *++p == '\0') |
527 | return '\0'; |
528 | argptr++; |
529 | if (p[0] == '-' && p[1] == '\0') /* check for "--" */ |
530 | return '\0'; |
531 | } |
532 | c = *p++; |
533 | for (q = optstring ; *q != c ; ) { |
534 | if (*q == '\0') |
535 | sh_error("Illegal option -%c", c); |
536 | if (*++q == ':') |
537 | q++; |
538 | } |
539 | if (*++q == ':') { |
540 | if (*p == '\0' && (p = *argptr++) == NULL) |
541 | sh_error("No arg for -%c option", c); |
542 | optionarg = p; |
543 | p = NULL; |
544 | } |
545 | optptr = p; |
546 | return c; |
547 | } |