Rev 2714 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2714 | Rev 2787 | ||
---|---|---|---|
1 | /* $NetBSD: options.c,v 1.29 1999/07/09 03:05:50 christos Exp $ */ |
1 | /* $NetBSD: options.c,v 1.29 1999/07/09 03:05:50 christos Exp $ */ |
2 | 2 | ||
3 | /*- |
3 | /*- |
4 | * Copyright (c) 1991, 1993 |
4 | * Copyright (c) 1991, 1993 |
5 | * The Regents of the University of California. All rights reserved. |
5 | * The Regents of the University of California. All rights reserved. |
6 | * |
6 | * |
7 | * This code is derived from software contributed to Berkeley by |
7 | * This code is derived from software contributed to Berkeley by |
8 | * Kenneth Almquist. |
8 | * Kenneth Almquist. |
9 | * |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
17 | * documentation and/or other materials provided with the distribution. |
18 | * 3. All advertising materials mentioning features or use of this software |
18 | * 3. All advertising materials mentioning features or use of this software |
19 | * must display the following acknowledgement: |
19 | * must display the following acknowledgement: |
20 | * This product includes software developed by the University of |
20 | * This product includes software developed by the University of |
21 | * California, Berkeley and its contributors. |
21 | * California, Berkeley and its contributors. |
22 | * 4. Neither the name of the University nor the names of its contributors |
22 | * 4. Neither the name of the University nor the names of its contributors |
23 | * may be used to endorse or promote products derived from this software |
23 | * may be used to endorse or promote products derived from this software |
24 | * without specific prior written permission. |
24 | * without specific prior written permission. |
25 | * |
25 | * |
26 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
26 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
30 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
30 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
31 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
31 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
32 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
32 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
36 | * SUCH DAMAGE. |
36 | * SUCH DAMAGE. |
37 | */ |
37 | */ |
38 | 38 | ||
39 | #include <sys/cdefs.h> |
39 | #include <sys/cdefs.h> |
40 | #ifndef lint |
40 | #ifndef lint |
41 | #if 0 |
41 | #if 0 |
42 | static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95"; |
42 | static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95"; |
43 | #else |
43 | #else |
44 | __RCSID("$NetBSD: options.c,v 1.29 1999/07/09 03:05:50 christos Exp $"); |
44 | __RCSID("$NetBSD: options.c,v 1.29 1999/07/09 03:05:50 christos Exp $"); |
45 | #endif |
45 | #endif |
46 | #endif /* not lint */ |
46 | #endif /* not lint */ |
47 | 47 | ||
48 | #include <signal.h> |
48 | #include <signal.h> |
49 | #include <unistd.h> |
49 | #include <unistd.h> |
50 | #include <stdlib.h> |
50 | #include <stdlib.h> |
51 | 51 | ||
52 | #include "shell.h" |
52 | #include "shell.h" |
53 | #define DEFINE_OPTIONS |
53 | #define DEFINE_OPTIONS |
54 | #include "options.h" |
54 | #include "options.h" |
55 | #undef DEFINE_OPTIONS |
55 | #undef DEFINE_OPTIONS |
56 | #include "nodes.h" /* for other header files */ |
56 | #include "nodes.h" /* for other header files */ |
57 | #include "eval.h" |
57 | #include "eval.h" |
58 | #include "jobs.h" |
58 | #include "jobs.h" |
59 | #include "input.h" |
59 | #include "input.h" |
60 | #include "output.h" |
60 | #include "output.h" |
61 | #include "trap.h" |
61 | #include "trap.h" |
62 | #include "var.h" |
62 | #include "var.h" |
63 | #include "memalloc.h" |
63 | #include "memalloc.h" |
64 | #include "error.h" |
64 | #include "error.h" |
65 | #include "mystring.h" |
65 | #include "mystring.h" |
66 | #ifndef SMALL |
66 | #ifndef SMALL |
67 | #include "myhistedit.h" |
67 | #include "myhistedit.h" |
68 | #endif |
68 | #endif |
69 | 69 | ||
70 | char *arg0; /* value of $0 */ |
70 | char *arg0; /* value of $0 */ |
71 | struct shparam shellparam; /* current positional parameters */ |
71 | struct shparam shellparam; /* current positional parameters */ |
72 | char **argptr; /* argument list for builtin commands */ |
72 | char **argptr; /* argument list for builtin commands */ |
73 | char *optarg; /* set by nextopt (like getopt) */ |
73 | char *optarg; /* set by nextopt (like getopt) */ |
74 | char *optptr; /* used by nextopt */ |
74 | char *optptr; /* used by nextopt */ |
75 | 75 | ||
76 | char *minusc; /* argument to -c option */ |
76 | char *minusc; /* argument to -c option */ |
77 | 77 | ||
78 | 78 | ||
79 | STATIC void options (int); |
79 | STATIC void options (int); |
80 | STATIC void minus_o (char *, int); |
80 | STATIC void minus_o (char *, int); |
81 | STATIC void setoption (int, int); |
81 | STATIC void setoption (int, int); |
82 | STATIC int getopts (char *, char *, char **, int *, int *); |
82 | STATIC int getopts (char *, char *, char **, int *, int *); |
83 | 83 | ||
84 | 84 | ||
85 | /* |
85 | /* |
86 | * Process the shell command line arguments. |
86 | * Process the shell command line arguments. |
87 | */ |
87 | */ |
88 | 88 | ||
89 | void |
89 | void |
90 | procargs(argc, argv) |
90 | procargs(argc, argv) |
91 | int argc; |
91 | int argc; |
92 | char **argv; |
92 | char **argv; |
93 | { |
93 | { |
94 | int i; |
94 | int i; |
95 | 95 | ||
96 | argptr = argv; |
96 | argptr = argv; |
97 | if (argc > 0) |
97 | if (argc > 0) |
98 | argptr++; |
98 | argptr++; |
99 | for (i = 0; i < NOPTS; i++) |
99 | for (i = 0; i < NOPTS; i++) |
100 | optlist[i].val = 2; |
100 | optlist[i].val = 2; |
101 | options(1); |
101 | options(1); |
102 | if (*argptr == NULL && minusc == NULL) |
102 | if (*argptr == NULL && minusc == NULL) |
103 | sflag = 1; |
103 | sflag = 1; |
104 | if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) |
104 | if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) |
105 | iflag = 1; |
105 | iflag = 1; |
106 | if (mflag == 2) |
106 | if (mflag == 2) |
107 | mflag = iflag; |
107 | mflag = iflag; |
108 | for (i = 0; i < NOPTS; i++) |
108 | for (i = 0; i < NOPTS; i++) |
109 | if (optlist[i].val == 2) |
109 | if (optlist[i].val == 2) |
110 | optlist[i].val = 0; |
110 | optlist[i].val = 0; |
111 | arg0 = argv[0]; |
111 | arg0 = argv[0]; |
112 | if (sflag == 0 && minusc == NULL) { |
112 | if (sflag == 0 && minusc == NULL) { |
113 | commandname = arg0 = *argptr++; |
113 | commandname = arg0 = *argptr++; |
114 | setinputfile(commandname, 0); |
114 | setinputfile(commandname, 0); |
115 | } |
115 | } |
116 | /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ |
116 | /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ |
117 | if (argptr && minusc && *argptr) |
117 | if (argptr && minusc && *argptr) |
118 | arg0 = *argptr++; |
118 | arg0 = *argptr++; |
119 | 119 | ||
120 | shellparam.p = argptr; |
120 | shellparam.p = argptr; |
121 | shellparam.optind = 1; |
121 | shellparam.optind = 1; |
122 | shellparam.optoff = -1; |
122 | shellparam.optoff = -1; |
123 | /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ |
123 | /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ |
124 | while (*argptr) { |
124 | while (*argptr) { |
125 | shellparam.nparam++; |
125 | shellparam.nparam++; |
126 | argptr++; |
126 | argptr++; |
127 | } |
127 | } |
128 | optschanged(); |
128 | optschanged(); |
129 | } |
129 | } |
130 | 130 | ||
131 | 131 | ||
132 | void |
132 | void |
133 | optschanged() |
133 | optschanged() |
134 | { |
134 | { |
135 | setinteractive(iflag); |
135 | setinteractive(iflag); |
136 | #ifndef SMALL |
136 | #ifndef SMALL |
137 | histedit(); |
137 | histedit(); |
138 | #endif |
138 | #endif |
139 | setjobctl(mflag); |
139 | setjobctl(mflag); |
140 | } |
140 | } |
141 | 141 | ||
142 | /* |
142 | /* |
143 | * Process shell options. The global variable argptr contains a pointer |
143 | * Process shell options. The global variable argptr contains a pointer |
144 | * to the argument list; we advance it past the options. |
144 | * to the argument list; we advance it past the options. |
145 | */ |
145 | */ |
146 | 146 | ||
147 | STATIC void |
147 | STATIC void |
148 | options(cmdline) |
148 | options(cmdline) |
149 | int cmdline; |
149 | int cmdline; |
150 | { |
150 | { |
151 | char *p; |
151 | char *p; |
152 | int val; |
152 | int val; |
153 | int c; |
153 | int c; |
154 | 154 | ||
155 | if (cmdline) |
155 | if (cmdline) |
156 | minusc = NULL; |
156 | minusc = NULL; |
157 | while ((p = *argptr) != NULL) { |
157 | while ((p = *argptr) != NULL) { |
158 | argptr++; |
158 | argptr++; |
159 | if ((c = *p++) == '-') { |
159 | if ((c = *p++) == '-') { |
160 | val = 1; |
160 | val = 1; |
161 | if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) { |
161 | if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) { |
162 | if (!cmdline) { |
162 | if (!cmdline) { |
163 | /* "-" means turn off -x and -v */ |
163 | /* "-" means turn off -x and -v */ |
164 | if (p[0] == '\0') |
164 | if (p[0] == '\0') |
165 | xflag = vflag = 0; |
165 | xflag = vflag = 0; |
166 | /* "--" means reset params */ |
166 | /* "--" means reset params */ |
167 | else if (*argptr == NULL) |
167 | else if (*argptr == NULL) |
168 | setparam(argptr); |
168 | setparam(argptr); |
169 | } |
169 | } |
170 | break; /* "-" or "--" terminates options */ |
170 | break; /* "-" or "--" terminates options */ |
171 | } |
171 | } |
172 | } else if (c == '+') { |
172 | } else if (c == '+') { |
173 | val = 0; |
173 | val = 0; |
174 | } else { |
174 | } else { |
175 | argptr--; |
175 | argptr--; |
176 | break; |
176 | break; |
177 | } |
177 | } |
178 | while ((c = *p++) != '\0') { |
178 | while ((c = *p++) != '\0') { |
179 | if (c == 'c' && cmdline) { |
179 | if (c == 'c' && cmdline) { |
180 | char *q; |
180 | char *q; |
181 | #ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ |
181 | #ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ |
182 | if (*p == '\0') |
182 | if (*p == '\0') |
183 | #endif |
183 | #endif |
184 | q = *argptr++; |
184 | q = *argptr++; |
185 | if (q == NULL || minusc != NULL) |
185 | if (q == NULL || minusc != NULL) |
186 | error("Bad -c option"); |
186 | error("Bad -c option"); |
187 | minusc = q; |
187 | minusc = q; |
188 | #ifdef NOHACK |
188 | #ifdef NOHACK |
189 | break; |
189 | break; |
190 | #endif |
190 | #endif |
191 | } else if (c == 'o') { |
191 | } else if (c == 'o') { |
192 | minus_o(*argptr, val); |
192 | minus_o(*argptr, val); |
193 | if (*argptr) |
193 | if (*argptr) |
194 | argptr++; |
194 | argptr++; |
195 | } else { |
195 | } else { |
196 | setoption(c, val); |
196 | setoption(c, val); |
197 | } |
197 | } |
198 | } |
198 | } |
199 | } |
199 | } |
200 | } |
200 | } |
201 | 201 | ||
202 | STATIC void |
202 | STATIC void |
203 | minus_o(name, val) |
203 | minus_o(name, val) |
204 | char *name; |
204 | char *name; |
205 | int val; |
205 | int val; |
206 | { |
206 | { |
207 | int i; |
207 | int i; |
208 | 208 | ||
209 | if (name == NULL) { |
209 | if (name == NULL) { |
210 | out1str("Current option settings\n"); |
210 | out1str("Current option settings\n"); |
211 | for (i = 0; i < NOPTS; i++) |
211 | for (i = 0; i < NOPTS; i++) |
212 | out1fmt("%-16s%s\n", optlist[i].name, |
212 | out1fmt("%-16s%s\n", optlist[i].name, |
213 | optlist[i].val ? "on" : "off"); |
213 | optlist[i].val ? "on" : "off"); |
214 | } else { |
214 | } else { |
215 | for (i = 0; i < NOPTS; i++) |
215 | for (i = 0; i < NOPTS; i++) |
216 | if (equal(name, optlist[i].name)) { |
216 | if (equal(name, optlist[i].name)) { |
217 | setoption(optlist[i].letter, val); |
217 | setoption(optlist[i].letter, val); |
218 | return; |
218 | return; |
219 | } |
219 | } |
220 | error("Illegal option -o %s", name); |
220 | error("Illegal option -o %s", name); |
221 | } |
221 | } |
222 | } |
222 | } |
223 | 223 | ||
224 | 224 | ||
225 | STATIC void |
225 | STATIC void |
226 | setoption(flag, val) |
226 | setoption(flag, val) |
227 | char flag; |
227 | char flag; |
228 | int val; |
228 | int val; |
229 | { |
229 | { |
230 | int i; |
230 | int i; |
231 | 231 | ||
232 | for (i = 0; i < NOPTS; i++) |
232 | for (i = 0; i < NOPTS; i++) |
233 | if (optlist[i].letter == flag) { |
233 | if (optlist[i].letter == flag) { |
234 | optlist[i].val = val; |
234 | optlist[i].val = val; |
235 | if (val) { |
235 | if (val) { |
236 | /* #%$ hack for ksh semantics */ |
236 | /* #%$ hack for ksh semantics */ |
237 | if (flag == 'V') |
237 | if (flag == 'V') |
238 | Eflag = 0; |
238 | Eflag = 0; |
239 | else if (flag == 'E') |
239 | else if (flag == 'E') |
240 | Vflag = 0; |
240 | Vflag = 0; |
241 | } |
241 | } |
242 | return; |
242 | return; |
243 | } |
243 | } |
244 | error("Illegal option -%c", flag); |
244 | error("Illegal option -%c", flag); |
245 | /* NOTREACHED */ |
245 | /* NOTREACHED */ |
246 | } |
246 | } |
247 | 247 | ||
248 | 248 | ||
249 | 249 | ||
250 | #ifdef mkinit |
250 | #ifdef mkinit |
251 | INCLUDE "options.h" |
251 | INCLUDE "options.h" |
252 | 252 | ||
253 | SHELLPROC { |
253 | SHELLPROC { |
254 | int i; |
254 | int i; |
255 | 255 | ||
256 | for (i = 0; i < NOPTS; i++) |
256 | for (i = 0; i < NOPTS; i++) |
257 | optlist[i].val = 0; |
257 | optlist[i].val = 0; |
258 | optschanged(); |
258 | optschanged(); |
259 | 259 | ||
260 | } |
260 | } |
261 | #endif |
261 | #endif |
262 | 262 | ||
263 | 263 | ||
264 | /* |
264 | /* |
265 | * Set the shell parameters. |
265 | * Set the shell parameters. |
266 | */ |
266 | */ |
267 | 267 | ||
268 | void |
268 | void |
269 | setparam(argv) |
269 | setparam(argv) |
270 | char **argv; |
270 | char **argv; |
271 | { |
271 | { |
272 | char **newparam; |
272 | char **newparam; |
273 | char **ap; |
273 | char **ap; |
274 | int nparam; |
274 | int nparam; |
275 | 275 | ||
276 | for (nparam = 0 ; argv[nparam] ; nparam++); |
276 | for (nparam = 0 ; argv[nparam] ; nparam++); |
277 | ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); |
277 | ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); |
278 | while (*argv) { |
278 | while (*argv) { |
279 | *ap++ = savestr(*argv++); |
279 | *ap++ = savestr(*argv++); |
280 | } |
280 | } |
281 | *ap = NULL; |
281 | *ap = NULL; |
282 | freeparam(&shellparam); |
282 | freeparam(&shellparam); |
283 | shellparam.malloc = 1; |
283 | shellparam.malloc = 1; |
284 | shellparam.nparam = nparam; |
284 | shellparam.nparam = nparam; |
285 | shellparam.p = newparam; |
285 | shellparam.p = newparam; |
286 | shellparam.optind = 1; |
286 | shellparam.optind = 1; |
287 | shellparam.optoff = -1; |
287 | shellparam.optoff = -1; |
288 | } |
288 | } |
289 | 289 | ||
290 | 290 | ||
291 | /* |
291 | /* |
292 | * Free the list of positional parameters. |
292 | * Free the list of positional parameters. |
293 | */ |
293 | */ |
294 | 294 | ||
295 | void |
295 | void |
296 | freeparam(param) |
296 | freeparam(param) |
297 | volatile struct shparam *param; |
297 | volatile struct shparam *param; |
298 | { |
298 | { |
299 | char **ap; |
299 | char **ap; |
300 | 300 | ||
301 | if (param->malloc) { |
301 | if (param->malloc) { |
302 | for (ap = param->p ; *ap ; ap++) |
302 | for (ap = param->p ; *ap ; ap++) |
303 | ckfree(*ap); |
303 | ckfree(*ap); |
304 | ckfree(param->p); |
304 | ckfree(param->p); |
305 | } |
305 | } |
306 | } |
306 | } |
307 | 307 | ||
308 | 308 | ||
309 | 309 | ||
310 | /* |
310 | /* |
311 | * The shift builtin command. |
311 | * The shift builtin command. |
312 | */ |
312 | */ |
313 | 313 | ||
314 | int |
314 | int |
315 | shiftcmd(argc, argv) |
315 | shiftcmd(argc, argv) |
316 | int argc; |
316 | int argc; |
317 | char **argv; |
317 | char **argv; |
318 | { |
318 | { |
319 | int n; |
319 | int n; |
320 | char **ap1, **ap2; |
320 | char **ap1, **ap2; |
321 | 321 | ||
322 | n = 1; |
322 | n = 1; |
323 | if (argc > 1) |
323 | if (argc > 1) |
324 | n = number(argv[1]); |
324 | n = number(argv[1]); |
325 | if (n > shellparam.nparam) |
325 | if (n > shellparam.nparam) |
326 | error("can't shift that many"); |
326 | error("can't shift that many"); |
327 | INTOFF; |
327 | INTOFF; |
328 | shellparam.nparam -= n; |
328 | shellparam.nparam -= n; |
329 | for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { |
329 | for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { |
330 | if (shellparam.malloc) |
330 | if (shellparam.malloc) |
331 | ckfree(*ap1); |
331 | ckfree(*ap1); |
332 | } |
332 | } |
333 | ap2 = shellparam.p; |
333 | ap2 = shellparam.p; |
334 | while ((*ap2++ = *ap1++) != NULL); |
334 | while ((*ap2++ = *ap1++) != NULL); |
335 | shellparam.optind = 1; |
335 | shellparam.optind = 1; |
336 | shellparam.optoff = -1; |
336 | shellparam.optoff = -1; |
337 | INTON; |
337 | INTON; |
338 | return 0; |
338 | return 0; |
339 | } |
339 | } |
340 | 340 | ||
341 | 341 | ||
342 | 342 | ||
343 | /* |
343 | /* |
344 | * The set command builtin. |
344 | * The set command builtin. |
345 | */ |
345 | */ |
346 | 346 | ||
347 | int |
347 | int |
348 | setcmd(argc, argv) |
348 | setcmd(argc, argv) |
349 | int argc; |
349 | int argc; |
350 | char **argv; |
350 | char **argv; |
351 | { |
351 | { |
352 | if (argc == 1) |
352 | if (argc == 1) |
353 | return showvarscmd(argc, argv); |
353 | return showvarscmd(argc, argv); |
354 | INTOFF; |
354 | INTOFF; |
355 | options(0); |
355 | options(0); |
356 | optschanged(); |
356 | optschanged(); |
357 | if (*argptr != NULL) { |
357 | if (*argptr != NULL) { |
358 | setparam(argptr); |
358 | setparam(argptr); |
359 | } |
359 | } |
360 | INTON; |
360 | INTON; |
361 | return 0; |
361 | return 0; |
362 | } |
362 | } |
363 | 363 | ||
364 | 364 | ||
365 | void |
365 | void |
366 | getoptsreset(value) |
366 | getoptsreset(value) |
367 | const char *value; |
367 | const char *value; |
368 | { |
368 | { |
369 | shellparam.optind = number(value); |
369 | shellparam.optind = number(value); |
370 | shellparam.optoff = -1; |
370 | shellparam.optoff = -1; |
371 | } |
371 | } |
372 | 372 | ||
373 | /* |
373 | /* |
374 | * The getopts builtin. Shellparam.optnext points to the next argument |
374 | * The getopts builtin. Shellparam.optnext points to the next argument |
375 | * to be processed. Shellparam.optptr points to the next character to |
375 | * to be processed. Shellparam.optptr points to the next character to |
376 | * be processed in the current argument. If shellparam.optnext is NULL, |
376 | * be processed in the current argument. If shellparam.optnext is NULL, |
377 | * then it's the first time getopts has been called. |
377 | * then it's the first time getopts has been called. |
378 | */ |
378 | */ |
379 | 379 | ||
380 | int |
380 | int |
381 | getoptscmd(argc, argv) |
381 | getoptscmd(argc, argv) |
382 | int argc; |
382 | int argc; |
383 | char **argv; |
383 | char **argv; |
384 | { |
384 | { |
385 | char **optbase; |
385 | char **optbase; |
386 | 386 | ||
387 | if (argc < 3) |
387 | if (argc < 3) |
388 | error("Usage: getopts optstring var [arg]"); |
388 | error("Usage: getopts optstring var [arg]"); |
389 | else if (argc == 3) { |
389 | else if (argc == 3) { |
390 | optbase = shellparam.p; |
390 | optbase = shellparam.p; |
391 | if (shellparam.optind > shellparam.nparam + 1) { |
391 | if (shellparam.optind > shellparam.nparam + 1) { |
392 | shellparam.optind = 1; |
392 | shellparam.optind = 1; |
393 | shellparam.optoff = -1; |
393 | shellparam.optoff = -1; |
394 | } |
394 | } |
395 | } |
395 | } |
396 | else { |
396 | else { |
397 | optbase = &argv[3]; |
397 | optbase = &argv[3]; |
398 | if (shellparam.optind > argc - 2) { |
398 | if (shellparam.optind > argc - 2) { |
399 | shellparam.optind = 1; |
399 | shellparam.optind = 1; |
400 | shellparam.optoff = -1; |
400 | shellparam.optoff = -1; |
401 | } |
401 | } |
402 | } |
402 | } |
403 | 403 | ||
404 | return getopts(argv[1], argv[2], optbase, &shellparam.optind, |
404 | return getopts(argv[1], argv[2], optbase, &shellparam.optind, |
405 | &shellparam.optoff); |
405 | &shellparam.optoff); |
406 | } |
406 | } |
407 | 407 | ||
408 | STATIC int |
408 | STATIC int |
409 | getopts(optstr, optvar, optfirst, optind, optoff) |
409 | getopts(optstr, optvar, optfirst, optind, optoff) |
410 | char *optstr; |
410 | char *optstr; |
411 | char *optvar; |
411 | char *optvar; |
412 | char **optfirst; |
412 | char **optfirst; |
413 | int *optind; |
413 | int *optind; |
414 | int *optoff; |
414 | int *optoff; |
415 | { |
415 | { |
416 | char *p, *q; |
416 | char *p, *q; |
417 | char c = '?'; |
417 | char c = '?'; |
418 | int done = 0; |
418 | int done = 0; |
419 | int err = 0; |
419 | int err = 0; |
420 | char s[10]; |
420 | char s[10]; |
421 | char **optnext = optfirst + *optind - 1; |
421 | char **optnext = optfirst + *optind - 1; |
422 | 422 | ||
423 | if (*optind <= 1 || *optoff < 0 || !(*(optnext - 1)) || |
423 | if (*optind <= 1 || *optoff < 0 || !(*(optnext - 1)) || |
424 | strlen(*(optnext - 1)) < *optoff) |
424 | strlen(*(optnext - 1)) < *optoff) |
425 | p = NULL; |
425 | p = NULL; |
426 | else |
426 | else |
427 | p = *(optnext - 1) + *optoff; |
427 | p = *(optnext - 1) + *optoff; |
428 | if (p == NULL || *p == '\0') { |
428 | if (p == NULL || *p == '\0') { |
429 | /* Current word is done, advance */ |
429 | /* Current word is done, advance */ |
430 | if (optnext == NULL) |
430 | if (optnext == NULL) |
431 | return 1; |
431 | return 1; |
432 | p = *optnext; |
432 | p = *optnext; |
433 | if (p == NULL || *p != '-' || *++p == '\0') { |
433 | if (p == NULL || *p != '-' || *++p == '\0') { |
434 | atend: |
434 | atend: |
435 | *optind = optnext - optfirst + 1; |
435 | *optind = optnext - optfirst + 1; |
436 | p = NULL; |
436 | p = NULL; |
437 | done = 1; |
437 | done = 1; |
438 | goto out; |
438 | goto out; |
439 | } |
439 | } |
440 | optnext++; |
440 | optnext++; |
441 | if (p[0] == '-' && p[1] == '\0') /* check for "--" */ |
441 | if (p[0] == '-' && p[1] == '\0') /* check for "--" */ |
442 | goto atend; |
442 | goto atend; |
443 | } |
443 | } |
444 | 444 | ||
445 | c = *p++; |
445 | c = *p++; |
446 | for (q = optstr; *q != c; ) { |
446 | for (q = optstr; *q != c; ) { |
447 | if (*q == '\0') { |
447 | if (*q == '\0') { |
448 | if (optstr[0] == ':') { |
448 | if (optstr[0] == ':') { |
449 | s[0] = c; |
449 | s[0] = c; |
450 | s[1] = '\0'; |
450 | s[1] = '\0'; |
451 | err |= setvarsafe("OPTARG", s, 0); |
451 | err |= setvarsafe("OPTARG", s, 0); |
452 | } |
452 | } |
453 | else { |
453 | else { |
454 | outfmt(&errout, "Illegal option -%c\n", c); |
454 | outfmt(&errout, "Illegal option -%c\n", c); |
455 | (void) unsetvar("OPTARG"); |
455 | (void) unsetvar("OPTARG"); |
456 | } |
456 | } |
457 | c = '?'; |
457 | c = '?'; |
458 | goto bad; |
458 | goto bad; |
459 | } |
459 | } |
460 | if (*++q == ':') |
460 | if (*++q == ':') |
461 | q++; |
461 | q++; |
462 | } |
462 | } |
463 | 463 | ||
464 | if (*++q == ':') { |
464 | if (*++q == ':') { |
465 | if (*p == '\0' && (p = *optnext) == NULL) { |
465 | if (*p == '\0' && (p = *optnext) == NULL) { |
466 | if (optstr[0] == ':') { |
466 | if (optstr[0] == ':') { |
467 | s[0] = c; |
467 | s[0] = c; |
468 | s[1] = '\0'; |
468 | s[1] = '\0'; |
469 | err |= setvarsafe("OPTARG", s, 0); |
469 | err |= setvarsafe("OPTARG", s, 0); |
470 | c = ':'; |
470 | c = ':'; |
471 | } |
471 | } |
472 | else { |
472 | else { |
473 | outfmt(&errout, "No arg for -%c option\n", c); |
473 | outfmt(&errout, "No arg for -%c option\n", c); |
474 | (void) unsetvar("OPTARG"); |
474 | (void) unsetvar("OPTARG"); |
475 | c = '?'; |
475 | c = '?'; |
476 | } |
476 | } |
477 | goto bad; |
477 | goto bad; |
478 | } |
478 | } |
479 | 479 | ||
480 | if (p == *optnext) |
480 | if (p == *optnext) |
481 | optnext++; |
481 | optnext++; |
482 | setvarsafe("OPTARG", p, 0); |
482 | setvarsafe("OPTARG", p, 0); |
483 | p = NULL; |
483 | p = NULL; |
484 | } |
484 | } |
485 | else |
485 | else |
486 | setvarsafe("OPTARG", "", 0); |
486 | setvarsafe("OPTARG", "", 0); |
487 | *optind = optnext - optfirst + 1; |
487 | *optind = optnext - optfirst + 1; |
488 | goto out; |
488 | goto out; |
489 | 489 | ||
490 | bad: |
490 | bad: |
491 | *optind = 1; |
491 | *optind = 1; |
492 | p = NULL; |
492 | p = NULL; |
493 | out: |
493 | out: |
494 | *optoff = p ? p - *(optnext - 1) : -1; |
494 | *optoff = p ? p - *(optnext - 1) : -1; |
495 | fmtstr(s, sizeof(s), "%d", *optind); |
495 | fmtstr(s, sizeof(s), "%d", *optind); |
496 | err |= setvarsafe("OPTIND", s, VNOFUNC); |
496 | err |= setvarsafe("OPTIND", s, VNOFUNC); |
497 | s[0] = c; |
497 | s[0] = c; |
498 | s[1] = '\0'; |
498 | s[1] = '\0'; |
499 | err |= setvarsafe(optvar, s, 0); |
499 | err |= setvarsafe(optvar, s, 0); |
500 | if (err) { |
500 | if (err) { |
501 | *optind = 1; |
501 | *optind = 1; |
502 | *optoff = -1; |
502 | *optoff = -1; |
503 | flushall(); |
503 | flushall(); |
504 | exraise(EXERROR); |
504 | exraise(EXERROR); |
505 | } |
505 | } |
506 | return done; |
506 | return done; |
507 | } |
507 | } |
508 | 508 | ||
509 | /* |
509 | /* |
510 | * XXX - should get rid of. have all builtins use getopt(3). the |
510 | * XXX - should get rid of. have all builtins use getopt(3). the |
511 | * library getopt must have the BSD extension static variable "optreset" |
511 | * library getopt must have the BSD extension static variable "optreset" |
512 | * otherwise it can't be used within the shell safely. |
512 | * otherwise it can't be used within the shell safely. |
513 | * |
513 | * |
514 | * Standard option processing (a la getopt) for builtin routines. The |
514 | * Standard option processing (a la getopt) for builtin routines. The |
515 | * only argument that is passed to nextopt is the option string; the |
515 | * only argument that is passed to nextopt is the option string; the |
516 | * other arguments are unnecessary. It return the character, or '\0' on |
516 | * other arguments are unnecessary. It return the character, or '\0' on |
517 | * end of input. |
517 | * end of input. |
518 | */ |
518 | */ |
519 | 519 | ||
520 | int |
520 | int |
521 | nextopt(optstring) |
521 | nextopt(optstring) |
522 | const char *optstring; |
522 | const char *optstring; |
523 | { |
523 | { |
524 | char *p; |
524 | char *p; |
525 | const char *q; |
525 | const char *q; |
526 | char c; |
526 | char c; |
527 | 527 | ||
528 | if ((p = optptr) == NULL || *p == '\0') { |
528 | if ((p = optptr) == NULL || *p == '\0') { |
529 | p = *argptr; |
529 | p = *argptr; |
530 | if (p == NULL || *p != '-' || *++p == '\0') |
530 | if (p == NULL || *p != '-' || *++p == '\0') |
531 | return '\0'; |
531 | return '\0'; |
532 | argptr++; |
532 | argptr++; |
533 | if (p[0] == '-' && p[1] == '\0') /* check for "--" */ |
533 | if (p[0] == '-' && p[1] == '\0') /* check for "--" */ |
534 | return '\0'; |
534 | return '\0'; |
535 | } |
535 | } |
536 | c = *p++; |
536 | c = *p++; |
537 | for (q = optstring ; *q != c ; ) { |
537 | for (q = optstring ; *q != c ; ) { |
538 | if (*q == '\0') |
538 | if (*q == '\0') |
539 | error("Illegal option -%c", c); |
539 | error("Illegal option -%c", c); |
540 | if (*++q == ':') |
540 | if (*++q == ':') |
541 | q++; |
541 | q++; |
542 | } |
542 | } |
543 | if (*++q == ':') { |
543 | if (*++q == ':') { |
544 | if (*p == '\0' && (p = *argptr++) == NULL) |
544 | if (*p == '\0' && (p = *argptr++) == NULL) |
545 | error("No arg for -%c option", c); |
545 | error("No arg for -%c option", c); |
546 | optarg = p; |
546 | optarg = p; |
547 | p = NULL; |
547 | p = NULL; |
548 | } |
548 | } |
549 | optptr = p; |
549 | optptr = p; |
550 | return c; |
550 | return c; |
551 | } |
551 | } |
552 | 552 |