Annotation of /trunk/mkinitrd-magellan/klibc/usr/dash/options.c
Parent Directory | Revision Log
Revision 1122 -
(hide annotations)
(download)
Wed Aug 18 21:11:40 2010 UTC (13 years, 9 months ago) by niro
File MIME type: text/plain
File size: 11266 byte(s)
Wed Aug 18 21:11:40 2010 UTC (13 years, 9 months ago) by niro
File MIME type: text/plain
File size: 11266 byte(s)
-updated to klibc-1.5.19
1 | niro | 532 | /*- |
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 | niro | 1122 | static int options(int); |
110 | niro | 532 | STATIC void minus_o(char *, int); |
111 | STATIC void setoption(int, int); | ||
112 | niro | 1122 | STATIC int getopts(char *, char *, char **); |
113 | niro | 532 | |
114 | |||
115 | /* | ||
116 | * Process the shell command line arguments. | ||
117 | */ | ||
118 | |||
119 | niro | 1122 | int |
120 | niro | 532 | procargs(int argc, char **argv) |
121 | { | ||
122 | int i; | ||
123 | const char *xminusc; | ||
124 | char **xargv; | ||
125 | niro | 1122 | int login; |
126 | niro | 532 | |
127 | xargv = argv; | ||
128 | niro | 1122 | login = xargv[0] && xargv[0][0] == '-'; |
129 | niro | 532 | arg0 = xargv[0]; |
130 | if (argc > 0) | ||
131 | xargv++; | ||
132 | for (i = 0; i < NOPTS; i++) | ||
133 | optlist[i] = 2; | ||
134 | argptr = xargv; | ||
135 | niro | 1122 | login |= options(1); |
136 | niro | 532 | xargv = argptr; |
137 | xminusc = minusc; | ||
138 | if (*xargv == NULL) { | ||
139 | if (xminusc) | ||
140 | sh_error("-c requires an argument"); | ||
141 | sflag = 1; | ||
142 | } | ||
143 | if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) | ||
144 | iflag = 1; | ||
145 | if (mflag == 2) | ||
146 | mflag = iflag; | ||
147 | for (i = 0; i < NOPTS; i++) | ||
148 | if (optlist[i] == 2) | ||
149 | optlist[i] = 0; | ||
150 | #if DEBUG == 2 | ||
151 | debug = 1; | ||
152 | #endif | ||
153 | /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ | ||
154 | if (xminusc) { | ||
155 | minusc = *xargv++; | ||
156 | if (*xargv) | ||
157 | goto setarg0; | ||
158 | } else if (!sflag) { | ||
159 | setinputfile(*xargv, 0); | ||
160 | setarg0: | ||
161 | arg0 = *xargv++; | ||
162 | commandname = arg0; | ||
163 | } | ||
164 | |||
165 | shellparam.p = xargv; | ||
166 | shellparam.optind = 1; | ||
167 | shellparam.optoff = -1; | ||
168 | /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ | ||
169 | while (*xargv) { | ||
170 | shellparam.nparam++; | ||
171 | xargv++; | ||
172 | } | ||
173 | optschanged(); | ||
174 | niro | 1122 | |
175 | return login; | ||
176 | niro | 532 | } |
177 | |||
178 | |||
179 | void | ||
180 | optschanged(void) | ||
181 | { | ||
182 | #ifdef DEBUG | ||
183 | opentrace(); | ||
184 | #endif | ||
185 | setinteractive(iflag); | ||
186 | #ifndef SMALL | ||
187 | histedit(); | ||
188 | #endif | ||
189 | setjobctl(mflag); | ||
190 | } | ||
191 | |||
192 | /* | ||
193 | * Process shell options. The global variable argptr contains a pointer | ||
194 | * to the argument list; we advance it past the options. | ||
195 | */ | ||
196 | |||
197 | niro | 1122 | STATIC int |
198 | niro | 532 | options(int cmdline) |
199 | { | ||
200 | char *p; | ||
201 | int val; | ||
202 | int c; | ||
203 | niro | 1122 | int login = 0; |
204 | niro | 532 | |
205 | if (cmdline) | ||
206 | minusc = NULL; | ||
207 | while ((p = *argptr) != NULL) { | ||
208 | argptr++; | ||
209 | if ((c = *p++) == '-') { | ||
210 | val = 1; | ||
211 | if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) { | ||
212 | if (!cmdline) { | ||
213 | /* "-" means turn off -x and -v */ | ||
214 | if (p[0] == '\0') | ||
215 | xflag = vflag = 0; | ||
216 | /* "--" means reset params */ | ||
217 | else if (*argptr == NULL) | ||
218 | setparam(argptr); | ||
219 | } | ||
220 | break; /* "-" or "--" terminates options */ | ||
221 | } | ||
222 | } else if (c == '+') { | ||
223 | val = 0; | ||
224 | } else { | ||
225 | argptr--; | ||
226 | break; | ||
227 | } | ||
228 | while ((c = *p++) != '\0') { | ||
229 | if (c == 'c' && cmdline) { | ||
230 | minusc = p; /* command is after shell args*/ | ||
231 | niro | 1122 | } else if (c == 'l' && cmdline) { |
232 | login = 1; | ||
233 | niro | 532 | } else if (c == 'o') { |
234 | minus_o(*argptr, val); | ||
235 | if (*argptr) | ||
236 | argptr++; | ||
237 | } else { | ||
238 | setoption(c, val); | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | niro | 1122 | |
243 | return login; | ||
244 | niro | 532 | } |
245 | |||
246 | STATIC void | ||
247 | minus_o(char *name, int val) | ||
248 | { | ||
249 | int i; | ||
250 | |||
251 | if (name == NULL) { | ||
252 | niro | 1122 | if (val) { |
253 | out1str("Current option settings\n"); | ||
254 | for (i = 0; i < NOPTS; i++) | ||
255 | out1fmt("%-16s%s\n", optnames[i], | ||
256 | optlist[i] ? "on" : "off"); | ||
257 | } else { | ||
258 | for (i = 0; i < NOPTS; i++) | ||
259 | out1fmt("set %s %s\n", | ||
260 | optlist[i] ? "-o" : "+o", | ||
261 | optnames[i]); | ||
262 | |||
263 | } | ||
264 | niro | 532 | } else { |
265 | for (i = 0; i < NOPTS; i++) | ||
266 | if (equal(name, optnames[i])) { | ||
267 | optlist[i] = val; | ||
268 | return; | ||
269 | } | ||
270 | sh_error("Illegal option -o %s", name); | ||
271 | } | ||
272 | } | ||
273 | |||
274 | |||
275 | STATIC void | ||
276 | setoption(int flag, int val) | ||
277 | { | ||
278 | int i; | ||
279 | |||
280 | for (i = 0; i < NOPTS; i++) | ||
281 | if (optletters[i] == flag) { | ||
282 | optlist[i] = val; | ||
283 | if (val) { | ||
284 | /* #%$ hack for ksh semantics */ | ||
285 | if (flag == 'V') | ||
286 | Eflag = 0; | ||
287 | else if (flag == 'E') | ||
288 | Vflag = 0; | ||
289 | } | ||
290 | return; | ||
291 | } | ||
292 | sh_error("Illegal option -%c", flag); | ||
293 | /* NOTREACHED */ | ||
294 | } | ||
295 | |||
296 | |||
297 | |||
298 | /* | ||
299 | * Set the shell parameters. | ||
300 | */ | ||
301 | |||
302 | void | ||
303 | setparam(char **argv) | ||
304 | { | ||
305 | char **newparam; | ||
306 | char **ap; | ||
307 | int nparam; | ||
308 | |||
309 | for (nparam = 0 ; argv[nparam] ; nparam++); | ||
310 | ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); | ||
311 | while (*argv) { | ||
312 | *ap++ = savestr(*argv++); | ||
313 | } | ||
314 | *ap = NULL; | ||
315 | freeparam(&shellparam); | ||
316 | shellparam.malloc = 1; | ||
317 | shellparam.nparam = nparam; | ||
318 | shellparam.p = newparam; | ||
319 | shellparam.optind = 1; | ||
320 | shellparam.optoff = -1; | ||
321 | } | ||
322 | |||
323 | |||
324 | /* | ||
325 | * Free the list of positional parameters. | ||
326 | */ | ||
327 | |||
328 | void | ||
329 | freeparam(volatile struct shparam *param) | ||
330 | { | ||
331 | char **ap; | ||
332 | |||
333 | if (param->malloc) { | ||
334 | for (ap = param->p ; *ap ; ap++) | ||
335 | ckfree(*ap); | ||
336 | ckfree(param->p); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | |||
341 | |||
342 | /* | ||
343 | * The shift builtin command. | ||
344 | */ | ||
345 | |||
346 | int | ||
347 | shiftcmd(int argc, char **argv) | ||
348 | { | ||
349 | int n; | ||
350 | char **ap1, **ap2; | ||
351 | |||
352 | n = 1; | ||
353 | if (argc > 1) | ||
354 | n = number(argv[1]); | ||
355 | if (n > shellparam.nparam) | ||
356 | sh_error("can't shift that many"); | ||
357 | INTOFF; | ||
358 | shellparam.nparam -= n; | ||
359 | for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { | ||
360 | if (shellparam.malloc) | ||
361 | ckfree(*ap1); | ||
362 | } | ||
363 | ap2 = shellparam.p; | ||
364 | while ((*ap2++ = *ap1++) != NULL); | ||
365 | shellparam.optind = 1; | ||
366 | shellparam.optoff = -1; | ||
367 | INTON; | ||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | |||
372 | |||
373 | /* | ||
374 | * The set command builtin. | ||
375 | */ | ||
376 | |||
377 | int | ||
378 | setcmd(int argc, char **argv) | ||
379 | { | ||
380 | if (argc == 1) | ||
381 | return showvars(nullstr, 0, VUNSET); | ||
382 | INTOFF; | ||
383 | options(0); | ||
384 | optschanged(); | ||
385 | if (*argptr != NULL) { | ||
386 | setparam(argptr); | ||
387 | } | ||
388 | INTON; | ||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | |||
393 | void | ||
394 | getoptsreset(value) | ||
395 | const char *value; | ||
396 | { | ||
397 | niro | 1122 | shellparam.optind = number(value) ?: 1; |
398 | niro | 532 | shellparam.optoff = -1; |
399 | } | ||
400 | |||
401 | /* | ||
402 | * The getopts builtin. Shellparam.optnext points to the next argument | ||
403 | * to be processed. Shellparam.optptr points to the next character to | ||
404 | * be processed in the current argument. If shellparam.optnext is NULL, | ||
405 | * then it's the first time getopts has been called. | ||
406 | */ | ||
407 | |||
408 | int | ||
409 | getoptscmd(int argc, char **argv) | ||
410 | { | ||
411 | char **optbase; | ||
412 | |||
413 | if (argc < 3) | ||
414 | sh_error("Usage: getopts optstring var [arg]"); | ||
415 | else if (argc == 3) { | ||
416 | optbase = shellparam.p; | ||
417 | niro | 1122 | if ((unsigned)shellparam.optind > shellparam.nparam + 1) { |
418 | niro | 532 | shellparam.optind = 1; |
419 | shellparam.optoff = -1; | ||
420 | } | ||
421 | } | ||
422 | else { | ||
423 | optbase = &argv[3]; | ||
424 | niro | 1122 | if ((unsigned)shellparam.optind > argc - 2) { |
425 | niro | 532 | shellparam.optind = 1; |
426 | shellparam.optoff = -1; | ||
427 | } | ||
428 | } | ||
429 | |||
430 | niro | 1122 | return getopts(argv[1], argv[2], optbase); |
431 | niro | 532 | } |
432 | |||
433 | STATIC int | ||
434 | niro | 1122 | getopts(char *optstr, char *optvar, char **optfirst) |
435 | niro | 532 | { |
436 | char *p, *q; | ||
437 | char c = '?'; | ||
438 | int done = 0; | ||
439 | niro | 1122 | char s[2]; |
440 | niro | 532 | char **optnext; |
441 | niro | 1122 | int ind = shellparam.optind; |
442 | int off = shellparam.optoff; | ||
443 | niro | 532 | |
444 | niro | 1122 | shellparam.optind = -1; |
445 | optnext = optfirst + ind - 1; | ||
446 | niro | 532 | |
447 | niro | 1122 | if (ind <= 1 || off < 0 || strlen(optnext[-1]) < off) |
448 | niro | 532 | p = NULL; |
449 | else | ||
450 | niro | 1122 | p = optnext[-1] + off; |
451 | niro | 532 | if (p == NULL || *p == '\0') { |
452 | /* Current word is done, advance */ | ||
453 | p = *optnext; | ||
454 | if (p == NULL || *p != '-' || *++p == '\0') { | ||
455 | atend: | ||
456 | p = NULL; | ||
457 | done = 1; | ||
458 | goto out; | ||
459 | } | ||
460 | optnext++; | ||
461 | if (p[0] == '-' && p[1] == '\0') /* check for "--" */ | ||
462 | goto atend; | ||
463 | } | ||
464 | |||
465 | c = *p++; | ||
466 | for (q = optstr; *q != c; ) { | ||
467 | if (*q == '\0') { | ||
468 | if (optstr[0] == ':') { | ||
469 | s[0] = c; | ||
470 | s[1] = '\0'; | ||
471 | niro | 1122 | setvar("OPTARG", s, 0); |
472 | niro | 532 | } else { |
473 | outfmt(&errout, "Illegal option -%c\n", c); | ||
474 | (void) unsetvar("OPTARG"); | ||
475 | } | ||
476 | c = '?'; | ||
477 | goto out; | ||
478 | } | ||
479 | if (*++q == ':') | ||
480 | q++; | ||
481 | } | ||
482 | |||
483 | if (*++q == ':') { | ||
484 | if (*p == '\0' && (p = *optnext) == NULL) { | ||
485 | if (optstr[0] == ':') { | ||
486 | s[0] = c; | ||
487 | s[1] = '\0'; | ||
488 | niro | 1122 | setvar("OPTARG", s, 0); |
489 | niro | 532 | c = ':'; |
490 | } else { | ||
491 | outfmt(&errout, "No arg for -%c option\n", c); | ||
492 | (void) unsetvar("OPTARG"); | ||
493 | c = '?'; | ||
494 | } | ||
495 | goto out; | ||
496 | } | ||
497 | |||
498 | if (p == *optnext) | ||
499 | optnext++; | ||
500 | niro | 1122 | setvar("OPTARG", p, 0); |
501 | niro | 532 | p = NULL; |
502 | } else | ||
503 | niro | 1122 | setvar("OPTARG", nullstr, 0); |
504 | niro | 532 | |
505 | out: | ||
506 | niro | 1122 | ind = optnext - optfirst + 1; |
507 | setvarint("OPTIND", ind, VNOFUNC); | ||
508 | niro | 532 | s[0] = c; |
509 | s[1] = '\0'; | ||
510 | niro | 1122 | setvar(optvar, s, 0); |
511 | |||
512 | shellparam.optoff = p ? p - *(optnext - 1) : -1; | ||
513 | shellparam.optind = ind; | ||
514 | |||
515 | niro | 532 | return done; |
516 | } | ||
517 | |||
518 | /* | ||
519 | * XXX - should get rid of. have all builtins use getopt(3). the | ||
520 | * library getopt must have the BSD extension static variable "optreset" | ||
521 | * otherwise it can't be used within the shell safely. | ||
522 | * | ||
523 | * Standard option processing (a la getopt) for builtin routines. The | ||
524 | * only argument that is passed to nextopt is the option string; the | ||
525 | * other arguments are unnecessary. It return the character, or '\0' on | ||
526 | * end of input. | ||
527 | */ | ||
528 | |||
529 | int | ||
530 | nextopt(const char *optstring) | ||
531 | { | ||
532 | char *p; | ||
533 | const char *q; | ||
534 | char c; | ||
535 | |||
536 | if ((p = optptr) == NULL || *p == '\0') { | ||
537 | p = *argptr; | ||
538 | if (p == NULL || *p != '-' || *++p == '\0') | ||
539 | return '\0'; | ||
540 | argptr++; | ||
541 | if (p[0] == '-' && p[1] == '\0') /* check for "--" */ | ||
542 | return '\0'; | ||
543 | } | ||
544 | c = *p++; | ||
545 | for (q = optstring ; *q != c ; ) { | ||
546 | if (*q == '\0') | ||
547 | sh_error("Illegal option -%c", c); | ||
548 | if (*++q == ':') | ||
549 | q++; | ||
550 | } | ||
551 | if (*++q == ':') { | ||
552 | if (*p == '\0' && (p = *argptr++) == NULL) | ||
553 | sh_error("No arg for -%c option", c); | ||
554 | optionarg = p; | ||
555 | p = NULL; | ||
556 | } | ||
557 | optptr = p; | ||
558 | return c; | ||
559 | } |