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