Rev 3317 | Rev 3336 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3317 | Rev 3318 | ||
---|---|---|---|
1 | /* $NetBSD: getopt_long.c,v 1.21.4.1 2008/01/09 01:34:14 matt Exp $ */ |
1 | /* $NetBSD: getopt_long.c,v 1.21.4.1 2008/01/09 01:34:14 matt Exp $ */ |
2 | 2 | ||
3 | /*- |
3 | /*- |
4 | * Copyright (c) 2000 The NetBSD Foundation, Inc. |
4 | * Copyright (c) 2000 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
5 | * All rights reserved. |
6 | * |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Dieter Baron and Thomas Klausner. |
8 | * by Dieter Baron and Thomas Klausner. |
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 | * |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
30 | */ |
31 | 31 | ||
32 | /* Ported to HelenOS August 2008 by Tim Post <echo@echoreply.us> */ |
32 | /* Ported to HelenOS August 2008 by Tim Post <echo@echoreply.us> */ |
33 | 33 | ||
34 | #include <assert.h> |
34 | #include <assert.h> |
35 | #include <stdarg.h> |
35 | #include <stdarg.h> |
36 | #include <err.h> |
36 | #include <err.h> |
37 | #include <errno.h> |
37 | #include <errno.h> |
38 | #include <getopt.h> |
38 | #include <getopt.h> |
39 | #include <stdlib.h> |
39 | #include <stdlib.h> |
40 | #include <string.h> |
40 | #include <string.h> |
41 | 41 | ||
42 | /* HelenOS Port: Something similar to warnx(), however we just print |
42 | /* HelenOS Port: Something similar to warnx(), however we just print |
43 | * to the console */ |
43 | * to the console */ |
44 | 44 | ||
45 | void warnx(const char *fmt, ...); |
45 | void warnx(const char *fmt, ...); |
46 | 46 | ||
47 | void warnx(const char *fmt, ...) |
47 | void warnx(const char *fmt, ...) |
48 | { |
48 | { |
49 | va_list vargs; |
49 | va_list vargs; |
50 | va_start(vargs, fmt); |
50 | va_start(vargs, fmt); |
51 | vprintf(fmt, vargs); |
51 | vprintf(fmt, vargs); |
52 | va_end(vargs); |
52 | va_end(vargs); |
53 | printf("\n"); |
53 | printf("\n"); |
54 | return; |
54 | return; |
55 | } |
55 | } |
56 | 56 | ||
57 | /* HelenOS Port : We're incorporating only the modern getopt_long with wrappers |
57 | /* HelenOS Port : We're incorporating only the modern getopt_long with wrappers |
58 | * to keep legacy getopt() usage from breaking. All references to REPLACE_GETOPT |
58 | * to keep legacy getopt() usage from breaking. All references to REPLACE_GETOPT |
59 | * are dropped, we just include the code */ |
59 | * are dropped, we just include the code */ |
60 | 60 | ||
61 | int opterr = 1; /* if error message should be printed */ |
61 | int opterr = 1; /* if error message should be printed */ |
62 | int optind = 1; /* index into parent argv vector */ |
62 | int optind = 1; /* index into parent argv vector */ |
63 | int optopt = '?'; /* character checked for validity */ |
63 | int optopt = '?'; /* character checked for validity */ |
64 | int optreset; /* reset getopt */ |
64 | int optreset; /* reset getopt */ |
65 | char *optarg; /* argument associated with option */ |
65 | char *optarg; /* argument associated with option */ |
66 | 66 | ||
67 | 67 | ||
68 | #define IGNORE_FIRST (*options == '-' || *options == '+') |
68 | #define IGNORE_FIRST (*options == '-' || *options == '+') |
69 | #define PRINT_ERROR ((opterr) && ((*options != ':') \ |
69 | #define PRINT_ERROR ((opterr) && ((*options != ':') \ |
70 | || (IGNORE_FIRST && options[1] != ':'))) |
70 | || (IGNORE_FIRST && options[1] != ':'))) |
71 | /*HelenOS Port - POSIXLY_CORRECT is always false */ |
71 | /*HelenOS Port - POSIXLY_CORRECT is always false */ |
72 | #define IS_POSIXLY_CORRECT 0 |
72 | #define IS_POSIXLY_CORRECT 0 |
73 | #define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) |
73 | #define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) |
74 | /* XXX: GNU ignores PC if *options == '-' */ |
74 | /* XXX: GNU ignores PC if *options == '-' */ |
75 | #define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') |
75 | #define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') |
76 | 76 | ||
77 | /* return values */ |
77 | /* return values */ |
78 | #define BADCH (int)'?' |
78 | #define BADCH (int)'?' |
79 | #define BADARG ((IGNORE_FIRST && options[1] == ':') \ |
79 | #define BADARG ((IGNORE_FIRST && options[1] == ':') \ |
80 | || (*options == ':') ? (int)':' : (int)'?') |
80 | || (*options == ':') ? (int)':' : (int)'?') |
81 | #define INORDER (int)1 |
81 | #define INORDER (int)1 |
82 | 82 | ||
83 | #define EMSG "" |
83 | #define EMSG "" |
84 | 84 | ||
85 | static int getopt_internal(int, char **, const char *); |
85 | static int getopt_internal(int, char **, const char *); |
86 | static int gcd(int, int); |
86 | static int gcd(int, int); |
87 | static void permute_args(int, int, int, char **); |
87 | static void permute_args(int, int, int, char **); |
88 | 88 | ||
89 | static const char *place = EMSG; /* option letter processing */ |
89 | static const char *place = EMSG; /* option letter processing */ |
90 | 90 | ||
91 | /* XXX: set optreset to 1 rather than these two */ |
91 | /* XXX: set optreset to 1 rather than these two */ |
92 | static int nonopt_start = -1; /* first non option argument (for permute) */ |
92 | static int nonopt_start = -1; /* first non option argument (for permute) */ |
93 | static int nonopt_end = -1; /* first option after non options (for permute) */ |
93 | static int nonopt_end = -1; /* first option after non options (for permute) */ |
94 | 94 | ||
95 | /* Error messages */ |
95 | /* Error messages */ |
96 | static const char recargchar[] = "option requires an argument -- %c"; |
96 | static const char recargchar[] = "option requires an argument -- %c"; |
97 | static const char recargstring[] = "option requires an argument -- %s"; |
97 | static const char recargstring[] = "option requires an argument -- %s"; |
98 | static const char ambig[] = "ambiguous option -- %.*s"; |
98 | static const char ambig[] = "ambiguous option -- %.*s"; |
99 | static const char noarg[] = "option doesn't take an argument -- %.*s"; |
99 | static const char noarg[] = "option doesn't take an argument -- %.*s"; |
100 | static const char illoptchar[] = "unknown option -- %c"; |
100 | static const char illoptchar[] = "unknown option -- %c"; |
101 | static const char illoptstring[] = "unknown option -- %s"; |
101 | static const char illoptstring[] = "unknown option -- %s"; |
102 | 102 | ||
103 | 103 | ||
104 | /* |
104 | /* |
105 | * Compute the greatest common divisor of a and b. |
105 | * Compute the greatest common divisor of a and b. |
106 | */ |
106 | */ |
107 | static int |
107 | static int |
108 | gcd(a, b) |
108 | gcd(a, b) |
109 | int a; |
109 | int a; |
110 | int b; |
110 | int b; |
111 | { |
111 | { |
112 | int c; |
112 | int c; |
113 | 113 | ||
114 | c = a % b; |
114 | c = a % b; |
115 | while (c != 0) { |
115 | while (c != 0) { |
116 | a = b; |
116 | a = b; |
117 | b = c; |
117 | b = c; |
118 | c = a % b; |
118 | c = a % b; |
119 | } |
119 | } |
120 | 120 | ||
121 | return b; |
121 | return b; |
122 | } |
122 | } |
123 | 123 | ||
124 | /* |
124 | /* |
125 | * Exchange the block from nonopt_start to nonopt_end with the block |
125 | * Exchange the block from nonopt_start to nonopt_end with the block |
126 | * from nonopt_end to opt_end (keeping the same order of arguments |
126 | * from nonopt_end to opt_end (keeping the same order of arguments |
127 | * in each block). |
127 | * in each block). |
128 | */ |
128 | */ |
129 | static void |
129 | static void |
130 | permute_args(panonopt_start, panonopt_end, opt_end, nargv) |
130 | permute_args(panonopt_start, panonopt_end, opt_end, nargv) |
131 | int panonopt_start; |
131 | int panonopt_start; |
132 | int panonopt_end; |
132 | int panonopt_end; |
133 | int opt_end; |
133 | int opt_end; |
134 | char **nargv; |
134 | char **nargv; |
135 | { |
135 | { |
136 | int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; |
136 | int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; |
137 | char *swap; |
137 | char *swap; |
138 | 138 | ||
139 | assert(nargv != NULL); |
139 | assert(nargv != NULL); |
140 | 140 | ||
141 | /* |
141 | /* |
142 | * compute lengths of blocks and number and size of cycles |
142 | * compute lengths of blocks and number and size of cycles |
143 | */ |
143 | */ |
144 | nnonopts = panonopt_end - panonopt_start; |
144 | nnonopts = panonopt_end - panonopt_start; |
145 | nopts = opt_end - panonopt_end; |
145 | nopts = opt_end - panonopt_end; |
146 | ncycle = gcd(nnonopts, nopts); |
146 | ncycle = gcd(nnonopts, nopts); |
147 | cyclelen = (opt_end - panonopt_start) / ncycle; |
147 | cyclelen = (opt_end - panonopt_start) / ncycle; |
148 | 148 | ||
149 | for (i = 0; i < ncycle; i++) { |
149 | for (i = 0; i < ncycle; i++) { |
150 | cstart = panonopt_end+i; |
150 | cstart = panonopt_end+i; |
151 | pos = cstart; |
151 | pos = cstart; |
152 | for (j = 0; j < cyclelen; j++) { |
152 | for (j = 0; j < cyclelen; j++) { |
153 | if (pos >= panonopt_end) |
153 | if (pos >= panonopt_end) |
154 | pos -= nnonopts; |
154 | pos -= nnonopts; |
155 | else |
155 | else |
156 | pos += nopts; |
156 | pos += nopts; |
157 | swap = nargv[pos]; |
157 | swap = nargv[pos]; |
158 | nargv[pos] = nargv[cstart]; |
158 | nargv[pos] = nargv[cstart]; |
159 | nargv[cstart] = swap; |
159 | nargv[cstart] = swap; |
160 | } |
160 | } |
161 | } |
161 | } |
162 | } |
162 | } |
163 | 163 | ||
164 | /* |
164 | /* |
165 | * getopt_internal -- |
165 | * getopt_internal -- |
166 | * Parse argc/argv argument vector. Called by user level routines. |
166 | * Parse argc/argv argument vector. Called by user level routines. |
167 | * Returns -2 if -- is found (can be long option or end of options marker). |
167 | * Returns -2 if -- is found (can be long option or end of options marker). |
168 | */ |
168 | */ |
169 | static int |
169 | static int |
170 | getopt_internal(nargc, nargv, options) |
170 | getopt_internal(nargc, nargv, options) |
171 | int nargc; |
171 | int nargc; |
172 | char **nargv; |
172 | char **nargv; |
173 | const char *options; |
173 | const char *options; |
174 | { |
174 | { |
175 | char *oli; /* option letter list index */ |
175 | char *oli; /* option letter list index */ |
176 | int optchar; |
176 | int optchar; |
177 | 177 | ||
178 | assert(nargv != NULL); |
178 | assert(nargv != NULL); |
179 | assert(options != NULL); |
179 | assert(options != NULL); |
180 | 180 | ||
181 | optarg = NULL; |
181 | optarg = NULL; |
182 | 182 | ||
183 | /* |
183 | /* |
184 | * XXX Some programs (like rsyncd) expect to be able to |
184 | * XXX Some programs (like rsyncd) expect to be able to |
185 | * XXX re-initialize optind to 0 and have getopt_long(3) |
185 | * XXX re-initialize optind to 0 and have getopt_long(3) |
186 | * XXX properly function again. Work around this braindamage. |
186 | * XXX properly function again. Work around this braindamage. |
187 | */ |
187 | */ |
188 | if (optind == 0) |
188 | if (optind == 0) |
189 | optind = 1; |
189 | optind = 1; |
190 | 190 | ||
191 | if (optreset) |
191 | if (optreset) |
192 | nonopt_start = nonopt_end = -1; |
192 | nonopt_start = nonopt_end = -1; |
193 | start: |
193 | start: |
194 | if (optreset || !*place) { /* update scanning pointer */ |
194 | if (optreset || !*place) { /* update scanning pointer */ |
195 | optreset = 0; |
195 | optreset = 0; |
196 | if (optind >= nargc) { /* end of argument vector */ |
196 | if (optind >= nargc) { /* end of argument vector */ |
197 | place = EMSG; |
197 | place = EMSG; |
198 | if (nonopt_end != -1) { |
198 | if (nonopt_end != -1) { |
199 | /* do permutation, if we have to */ |
199 | /* do permutation, if we have to */ |
200 | permute_args(nonopt_start, nonopt_end, |
200 | permute_args(nonopt_start, nonopt_end, |
201 | optind, nargv); |
201 | optind, nargv); |
202 | optind -= nonopt_end - nonopt_start; |
202 | optind -= nonopt_end - nonopt_start; |
203 | } |
203 | } |
204 | else if (nonopt_start != -1) { |
204 | else if (nonopt_start != -1) { |
205 | /* |
205 | /* |
206 | * If we skipped non-options, set optind |
206 | * If we skipped non-options, set optind |
207 | * to the first of them. |
207 | * to the first of them. |
208 | */ |
208 | */ |
209 | optind = nonopt_start; |
209 | optind = nonopt_start; |
210 | } |
210 | } |
211 | nonopt_start = nonopt_end = -1; |
211 | nonopt_start = nonopt_end = -1; |
212 | return -1; |
212 | return -1; |
213 | } |
213 | } |
214 | if ((*(place = nargv[optind]) != '-') |
214 | if ((*(place = nargv[optind]) != '-') |
215 | || (place[1] == '\0')) { /* found non-option */ |
215 | || (place[1] == '\0')) { /* found non-option */ |
216 | place = EMSG; |
216 | place = EMSG; |
217 | if (IN_ORDER) { |
217 | if (IN_ORDER) { |
218 | /* |
218 | /* |
219 | * GNU extension: |
219 | * GNU extension: |
220 | * return non-option as argument to option 1 |
220 | * return non-option as argument to option 1 |
221 | */ |
221 | */ |
222 | optarg = nargv[optind++]; |
222 | optarg = nargv[optind++]; |
223 | return INORDER; |
223 | return INORDER; |
224 | } |
224 | } |
225 | if (!PERMUTE) { |
225 | if (!PERMUTE) { |
226 | /* |
226 | /* |
227 | * if no permutation wanted, stop parsing |
227 | * if no permutation wanted, stop parsing |
228 | * at first non-option |
228 | * at first non-option |
229 | */ |
229 | */ |
230 | return -1; |
230 | return -1; |
231 | } |
231 | } |
232 | /* do permutation */ |
232 | /* do permutation */ |
233 | if (nonopt_start == -1) |
233 | if (nonopt_start == -1) |
234 | nonopt_start = optind; |
234 | nonopt_start = optind; |
235 | else if (nonopt_end != -1) { |
235 | else if (nonopt_end != -1) { |
236 | permute_args(nonopt_start, nonopt_end, |
236 | permute_args(nonopt_start, nonopt_end, |
237 | optind, nargv); |
237 | optind, nargv); |
238 | nonopt_start = optind - |
238 | nonopt_start = optind - |
239 | (nonopt_end - nonopt_start); |
239 | (nonopt_end - nonopt_start); |
240 | nonopt_end = -1; |
240 | nonopt_end = -1; |
241 | } |
241 | } |
242 | optind++; |
242 | optind++; |
243 | /* process next argument */ |
243 | /* process next argument */ |
244 | goto start; |
244 | goto start; |
245 | } |
245 | } |
246 | if (nonopt_start != -1 && nonopt_end == -1) |
246 | if (nonopt_start != -1 && nonopt_end == -1) |
247 | nonopt_end = optind; |
247 | nonopt_end = optind; |
248 | if (place[1] && *++place == '-') { /* found "--" */ |
248 | if (place[1] && *++place == '-') { /* found "--" */ |
249 | place++; |
249 | place++; |
250 | return -2; |
250 | return -2; |
251 | } |
251 | } |
252 | } |
252 | } |
253 | if ((optchar = (int)*place++) == (int)':' || |
253 | if ((optchar = (int)*place++) == (int)':' || |
254 | (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) { |
254 | (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) { |
255 | /* option letter unknown or ':' */ |
255 | /* option letter unknown or ':' */ |
256 | if (!*place) |
256 | if (!*place) |
257 | ++optind; |
257 | ++optind; |
258 | if (PRINT_ERROR) |
258 | if (PRINT_ERROR) |
259 | warnx(illoptchar, optchar); |
259 | warnx(illoptchar, optchar); |
260 | optopt = optchar; |
260 | optopt = optchar; |
261 | return BADCH; |
261 | return BADCH; |
262 | } |
262 | } |
263 | if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ |
263 | if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ |
264 | /* XXX: what if no long options provided (called by getopt)? */ |
264 | /* XXX: what if no long options provided (called by getopt)? */ |
265 | if (*place) |
265 | if (*place) |
266 | return -2; |
266 | return -2; |
267 | 267 | ||
268 | if (++optind >= nargc) { /* no arg */ |
268 | if (++optind >= nargc) { /* no arg */ |
269 | place = EMSG; |
269 | place = EMSG; |
270 | if (PRINT_ERROR) |
270 | if (PRINT_ERROR) |
271 | warnx(recargchar, optchar); |
271 | warnx(recargchar, optchar); |
272 | optopt = optchar; |
272 | optopt = optchar; |
273 | return BADARG; |
273 | return BADARG; |
274 | } else /* white space */ |
274 | } else /* white space */ |
275 | place = nargv[optind]; |
275 | place = nargv[optind]; |
276 | /* |
276 | /* |
277 | * Handle -W arg the same as --arg (which causes getopt to |
277 | * Handle -W arg the same as --arg (which causes getopt to |
278 | * stop parsing). |
278 | * stop parsing). |
279 | */ |
279 | */ |
280 | return -2; |
280 | return -2; |
281 | } |
281 | } |
282 | if (*++oli != ':') { /* doesn't take argument */ |
282 | if (*++oli != ':') { /* doesn't take argument */ |
283 | if (!*place) |
283 | if (!*place) |
284 | ++optind; |
284 | ++optind; |
285 | } else { /* takes (optional) argument */ |
285 | } else { /* takes (optional) argument */ |
286 | optarg = NULL; |
286 | optarg = NULL; |
287 | if (*place) /* no white space */ |
287 | if (*place) /* no white space */ |
288 | optarg = *place; |
288 | optarg = *place; |
289 | /* XXX: disable test for :: if PC? (GNU doesn't) */ |
289 | /* XXX: disable test for :: if PC? (GNU doesn't) */ |
290 | else if (oli[1] != ':') { /* arg not optional */ |
290 | else if (oli[1] != ':') { /* arg not optional */ |
291 | if (++optind >= nargc) { /* no arg */ |
291 | if (++optind >= nargc) { /* no arg */ |
292 | place = EMSG; |
292 | place = EMSG; |
293 | if (PRINT_ERROR) |
293 | if (PRINT_ERROR) |
294 | warnx(recargchar, optchar); |
294 | warnx(recargchar, optchar); |
295 | optopt = optchar; |
295 | optopt = optchar; |
296 | return BADARG; |
296 | return BADARG; |
297 | } else |
297 | } else |
298 | optarg = nargv[optind]; |
298 | optarg = nargv[optind]; |
299 | } |
299 | } |
300 | place = EMSG; |
300 | place = EMSG; |
301 | ++optind; |
301 | ++optind; |
302 | } |
302 | } |
303 | /* dump back option letter */ |
303 | /* dump back option letter */ |
304 | return optchar; |
304 | return optchar; |
305 | } |
305 | } |
306 | 306 | ||
307 | /* |
307 | /* |
308 | * getopt -- |
308 | * getopt -- |
309 | * Parse argc/argv argument vector. |
309 | * Parse argc/argv argument vector. |
310 | * |
- | |
311 | * [eventually this will replace the real getopt] |
- | |
312 | */ |
310 | */ |
313 | int |
311 | int |
314 | getopt(nargc, nargv, options) |
312 | getopt(nargc, nargv, options) |
315 | int nargc; |
313 | int nargc; |
316 | char * const *nargv; |
314 | char * const *nargv; |
317 | const char *options; |
315 | const char *options; |
318 | { |
316 | { |
319 | int retval; |
317 | int retval; |
320 | 318 | ||
321 | assert(nargv != NULL); |
319 | assert(nargv != NULL); |
322 | assert(options != NULL); |
320 | assert(options != NULL); |
323 | 321 | ||
324 | retval = getopt_internal(nargc, (char **)nargv, options); |
322 | retval = getopt_internal(nargc, (char **)nargv, options); |
325 | if (retval == -2) { |
323 | if (retval == -2) { |
326 | ++optind; |
324 | ++optind; |
327 | /* |
325 | /* |
328 | * We found an option (--), so if we skipped non-options, |
326 | * We found an option (--), so if we skipped non-options, |
329 | * we have to permute. |
327 | * we have to permute. |
330 | */ |
328 | */ |
331 | if (nonopt_end != -1) { |
329 | if (nonopt_end != -1) { |
332 | permute_args(nonopt_start, nonopt_end, optind, |
330 | permute_args(nonopt_start, nonopt_end, optind, |
333 | (char **)nargv); |
331 | (char **)nargv); |
334 | optind -= nonopt_end - nonopt_start; |
332 | optind -= nonopt_end - nonopt_start; |
335 | } |
333 | } |
336 | nonopt_start = nonopt_end = -1; |
334 | nonopt_start = nonopt_end = -1; |
337 | retval = -1; |
335 | retval = -1; |
338 | } |
336 | } |
339 | return retval; |
337 | return retval; |
340 | } |
338 | } |
341 | 339 | ||
342 | /* |
340 | /* |
343 | * getopt_long -- |
341 | * getopt_long -- |
344 | * Parse argc/argv argument vector. |
342 | * Parse argc/argv argument vector. |
345 | */ |
343 | */ |
346 | int |
344 | int |
347 | getopt_long(nargc, nargv, options, long_options, idx) |
345 | getopt_long(nargc, nargv, options, long_options, idx) |
348 | int nargc; |
346 | int nargc; |
349 | char * const *nargv; |
347 | char * const *nargv; |
350 | const char *options; |
348 | const char *options; |
351 | const struct option *long_options; |
349 | const struct option *long_options; |
352 | int *idx; |
350 | int *idx; |
353 | { |
351 | { |
354 | int retval; |
352 | int retval; |
355 | 353 | ||
356 | #define IDENTICAL_INTERPRETATION(_x, _y) \ |
354 | #define IDENTICAL_INTERPRETATION(_x, _y) \ |
357 | (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ |
355 | (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ |
358 | long_options[(_x)].flag == long_options[(_y)].flag && \ |
356 | long_options[(_x)].flag == long_options[(_y)].flag && \ |
359 | long_options[(_x)].val == long_options[(_y)].val) |
357 | long_options[(_x)].val == long_options[(_y)].val) |
360 | 358 | ||
361 | assert(nargv != NULL); |
359 | assert(nargv != NULL); |
362 | assert(options != NULL); |
360 | assert(options != NULL); |
363 | assert(long_options != NULL); |
361 | assert(long_options != NULL); |
364 | /* idx may be NULL */ |
362 | /* idx may be NULL */ |
365 | 363 | ||
366 | retval = getopt_internal(nargc, (char **)nargv, options); |
364 | retval = getopt_internal(nargc, (char **)nargv, options); |
367 | if (retval == -2) { |
365 | if (retval == -2) { |
368 | char *current_argv, *has_equal; |
366 | char *current_argv, *has_equal; |
369 | size_t current_argv_len; |
367 | size_t current_argv_len; |
370 | int i, ambiguous, match; |
368 | int i, ambiguous, match; |
371 | 369 | ||
372 | current_argv = (char *)place; |
370 | current_argv = (char *)place; |
373 | match = -1; |
371 | match = -1; |
374 | ambiguous = 0; |
372 | ambiguous = 0; |
375 | 373 | ||
376 | optind++; |
374 | optind++; |
377 | place = EMSG; |
375 | place = EMSG; |
378 | 376 | ||
379 | if (*current_argv == '\0') { /* found "--" */ |
377 | if (*current_argv == '\0') { /* found "--" */ |
380 | /* |
378 | /* |
381 | * We found an option (--), so if we skipped |
379 | * We found an option (--), so if we skipped |
382 | * non-options, we have to permute. |
380 | * non-options, we have to permute. |
383 | */ |
381 | */ |
384 | if (nonopt_end != -1) { |
382 | if (nonopt_end != -1) { |
385 | permute_args(nonopt_start, nonopt_end, |
383 | permute_args(nonopt_start, nonopt_end, |
386 | optind, (char **)nargv); |
384 | optind, (char **)nargv); |
387 | optind -= nonopt_end - nonopt_start; |
385 | optind -= nonopt_end - nonopt_start; |
388 | } |
386 | } |
389 | nonopt_start = nonopt_end = -1; |
387 | nonopt_start = nonopt_end = -1; |
390 | return -1; |
388 | return -1; |
391 | } |
389 | } |
392 | if ((has_equal = strchr(current_argv, '=')) != NULL) { |
390 | if ((has_equal = strchr(current_argv, '=')) != NULL) { |
393 | /* argument found (--option=arg) */ |
391 | /* argument found (--option=arg) */ |
394 | current_argv_len = has_equal - current_argv; |
392 | current_argv_len = has_equal - current_argv; |
395 | has_equal++; |
393 | has_equal++; |
396 | } else |
394 | } else |
397 | current_argv_len = strlen(current_argv); |
395 | current_argv_len = strlen(current_argv); |
398 | 396 | ||
399 | for (i = 0; long_options[i].name; i++) { |
397 | for (i = 0; long_options[i].name; i++) { |
400 | /* find matching long option */ |
398 | /* find matching long option */ |
401 | if (strncmp(current_argv, long_options[i].name, |
399 | if (strncmp(current_argv, long_options[i].name, |
402 | current_argv_len)) |
400 | current_argv_len)) |
403 | continue; |
401 | continue; |
404 | 402 | ||
405 | if (strlen(long_options[i].name) == |
403 | if (strlen(long_options[i].name) == |
406 | (unsigned)current_argv_len) { |
404 | (unsigned)current_argv_len) { |
407 | /* exact match */ |
405 | /* exact match */ |
408 | match = i; |
406 | match = i; |
409 | ambiguous = 0; |
407 | ambiguous = 0; |
410 | break; |
408 | break; |
411 | } |
409 | } |
412 | if (match == -1) /* partial match */ |
410 | if (match == -1) /* partial match */ |
413 | match = i; |
411 | match = i; |
414 | else if (!IDENTICAL_INTERPRETATION(i, match)) |
412 | else if (!IDENTICAL_INTERPRETATION(i, match)) |
415 | ambiguous = 1; |
413 | ambiguous = 1; |
416 | } |
414 | } |
417 | if (ambiguous) { |
415 | if (ambiguous) { |
418 | /* ambiguous abbreviation */ |
416 | /* ambiguous abbreviation */ |
419 | if (PRINT_ERROR) |
417 | if (PRINT_ERROR) |
420 | warnx(ambig, (int)current_argv_len, |
418 | warnx(ambig, (int)current_argv_len, |
421 | current_argv); |
419 | current_argv); |
422 | optopt = 0; |
420 | optopt = 0; |
423 | return BADCH; |
421 | return BADCH; |
424 | } |
422 | } |
425 | if (match != -1) { /* option found */ |
423 | if (match != -1) { /* option found */ |
426 | if (long_options[match].has_arg == no_argument |
424 | if (long_options[match].has_arg == no_argument |
427 | && has_equal) { |
425 | && has_equal) { |
428 | if (PRINT_ERROR) |
426 | if (PRINT_ERROR) |
429 | warnx(noarg, (int)current_argv_len, |
427 | warnx(noarg, (int)current_argv_len, |
430 | current_argv); |
428 | current_argv); |
431 | /* |
429 | /* |
432 | * XXX: GNU sets optopt to val regardless of |
430 | * XXX: GNU sets optopt to val regardless of |
433 | * flag |
431 | * flag |
434 | */ |
432 | */ |
435 | if (long_options[match].flag == NULL) |
433 | if (long_options[match].flag == NULL) |
436 | optopt = long_options[match].val; |
434 | optopt = long_options[match].val; |
437 | else |
435 | else |
438 | optopt = 0; |
436 | optopt = 0; |
439 | return BADARG; |
437 | return BADARG; |
440 | } |
438 | } |
441 | if (long_options[match].has_arg == required_argument || |
439 | if (long_options[match].has_arg == required_argument || |
442 | long_options[match].has_arg == optional_argument) { |
440 | long_options[match].has_arg == optional_argument) { |
443 | if (has_equal) |
441 | if (has_equal) |
444 | optarg = has_equal; |
442 | optarg = has_equal; |
445 | else if (long_options[match].has_arg == |
443 | else if (long_options[match].has_arg == |
446 | required_argument) { |
444 | required_argument) { |
447 | /* |
445 | /* |
448 | * optional argument doesn't use |
446 | * optional argument doesn't use |
449 | * next nargv |
447 | * next nargv |
450 | */ |
448 | */ |
451 | optarg = nargv[optind++]; |
449 | optarg = nargv[optind++]; |
452 | } |
450 | } |
453 | } |
451 | } |
454 | if ((long_options[match].has_arg == required_argument) |
452 | if ((long_options[match].has_arg == required_argument) |
455 | && (optarg == NULL)) { |
453 | && (optarg == NULL)) { |
456 | /* |
454 | /* |
457 | * Missing argument; leading ':' |
455 | * Missing argument; leading ':' |
458 | * indicates no error should be generated |
456 | * indicates no error should be generated |
459 | */ |
457 | */ |
460 | if (PRINT_ERROR) |
458 | if (PRINT_ERROR) |
461 | warnx(recargstring, current_argv); |
459 | warnx(recargstring, current_argv); |
462 | /* |
460 | /* |
463 | * XXX: GNU sets optopt to val regardless |
461 | * XXX: GNU sets optopt to val regardless |
464 | * of flag |
462 | * of flag |
465 | */ |
463 | */ |
466 | if (long_options[match].flag == NULL) |
464 | if (long_options[match].flag == NULL) |
467 | optopt = long_options[match].val; |
465 | optopt = long_options[match].val; |
468 | else |
466 | else |
469 | optopt = 0; |
467 | optopt = 0; |
470 | --optind; |
468 | --optind; |
471 | return BADARG; |
469 | return BADARG; |
472 | } |
470 | } |
473 | } else { /* unknown option */ |
471 | } else { /* unknown option */ |
474 | if (PRINT_ERROR) |
472 | if (PRINT_ERROR) |
475 | warnx(illoptstring, current_argv); |
473 | warnx(illoptstring, current_argv); |
476 | optopt = 0; |
474 | optopt = 0; |
477 | return BADCH; |
475 | return BADCH; |
478 | } |
476 | } |
479 | if (long_options[match].flag) { |
477 | if (long_options[match].flag) { |
480 | *long_options[match].flag = long_options[match].val; |
478 | *long_options[match].flag = long_options[match].val; |
481 | retval = 0; |
479 | retval = 0; |
482 | } else |
480 | } else |
483 | retval = long_options[match].val; |
481 | retval = long_options[match].val; |
484 | if (idx) |
482 | if (idx) |
485 | *idx = match; |
483 | *idx = match; |
486 | } |
484 | } |
487 | return retval; |
485 | return retval; |
488 | #undef IDENTICAL_INTERPRETATION |
486 | #undef IDENTICAL_INTERPRETATION |
489 | } |
487 | } |
490 | 488 | ||
491 | 489 |