Contents of /trunk/mkinitrd-magellan/klibc/usr/dash/options.c
Parent Directory | Revision Log
Revision 1122 -
(show annotations)
(download)
Wed Aug 18 21:11:40 2010 UTC (13 years, 8 months ago) by niro
File MIME type: text/plain
File size: 11266 byte(s)
Wed Aug 18 21:11:40 2010 UTC (13 years, 8 months ago) by niro
File MIME type: text/plain
File size: 11266 byte(s)
-updated to klibc-1.5.19
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 int options(int); |
110 | STATIC void minus_o(char *, int); |
111 | STATIC void setoption(int, int); |
112 | STATIC int getopts(char *, char *, char **); |
113 | |
114 | |
115 | /* |
116 | * Process the shell command line arguments. |
117 | */ |
118 | |
119 | int |
120 | procargs(int argc, char **argv) |
121 | { |
122 | int i; |
123 | const char *xminusc; |
124 | char **xargv; |
125 | int login; |
126 | |
127 | xargv = argv; |
128 | login = xargv[0] && xargv[0][0] == '-'; |
129 | arg0 = xargv[0]; |
130 | if (argc > 0) |
131 | xargv++; |
132 | for (i = 0; i < NOPTS; i++) |
133 | optlist[i] = 2; |
134 | argptr = xargv; |
135 | login |= options(1); |
136 | 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 | |
175 | return login; |
176 | } |
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 | STATIC int |
198 | options(int cmdline) |
199 | { |
200 | char *p; |
201 | int val; |
202 | int c; |
203 | int login = 0; |
204 | |
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 | } else if (c == 'l' && cmdline) { |
232 | login = 1; |
233 | } else if (c == 'o') { |
234 | minus_o(*argptr, val); |
235 | if (*argptr) |
236 | argptr++; |
237 | } else { |
238 | setoption(c, val); |
239 | } |
240 | } |
241 | } |
242 | |
243 | return login; |
244 | } |
245 | |
246 | STATIC void |
247 | minus_o(char *name, int val) |
248 | { |
249 | int i; |
250 | |
251 | if (name == NULL) { |
252 | 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 | } 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 | shellparam.optind = number(value) ?: 1; |
398 | 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 | if ((unsigned)shellparam.optind > shellparam.nparam + 1) { |
418 | shellparam.optind = 1; |
419 | shellparam.optoff = -1; |
420 | } |
421 | } |
422 | else { |
423 | optbase = &argv[3]; |
424 | if ((unsigned)shellparam.optind > argc - 2) { |
425 | shellparam.optind = 1; |
426 | shellparam.optoff = -1; |
427 | } |
428 | } |
429 | |
430 | return getopts(argv[1], argv[2], optbase); |
431 | } |
432 | |
433 | STATIC int |
434 | getopts(char *optstr, char *optvar, char **optfirst) |
435 | { |
436 | char *p, *q; |
437 | char c = '?'; |
438 | int done = 0; |
439 | char s[2]; |
440 | char **optnext; |
441 | int ind = shellparam.optind; |
442 | int off = shellparam.optoff; |
443 | |
444 | shellparam.optind = -1; |
445 | optnext = optfirst + ind - 1; |
446 | |
447 | if (ind <= 1 || off < 0 || strlen(optnext[-1]) < off) |
448 | p = NULL; |
449 | else |
450 | p = optnext[-1] + off; |
451 | 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 | setvar("OPTARG", s, 0); |
472 | } 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 | setvar("OPTARG", s, 0); |
489 | 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 | setvar("OPTARG", p, 0); |
501 | p = NULL; |
502 | } else |
503 | setvar("OPTARG", nullstr, 0); |
504 | |
505 | out: |
506 | ind = optnext - optfirst + 1; |
507 | setvarint("OPTIND", ind, VNOFUNC); |
508 | s[0] = c; |
509 | s[1] = '\0'; |
510 | setvar(optvar, s, 0); |
511 | |
512 | shellparam.optoff = p ? p - *(optnext - 1) : -1; |
513 | shellparam.optind = ind; |
514 | |
515 | 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 | } |