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