MinGWベースのwchar_t対応getopt
- https://www.codeproject.com/Articles/157001/Full-getopt-Port-for-Unicode-and-Multibyte-Microso
@@ -1,3 +1,10 @@ | ||
1 | 1 | # getopt |
2 | +- https://www.codeproject.com/Articles/157001/Full-getopt-Port-for-Unicode-and-Multibyte-Microso | |
3 | +- License | |
4 | + - LGPL | |
2 | 5 | |
3 | -https://www.codeproject.com/Articles/157001/Full-getopt-Port-for-Unicode-and-Multibyte-Microso | |
6 | +# getoptW | |
7 | +- https://github.com/bluebaroncanada/getoptW | |
8 | +- License | |
9 | + - MIT/X11 | |
10 | + - https://mingw.osdn.io/index.html?page=terms.html |
@@ -0,0 +1,142 @@ | ||
1 | +# getoptW | |
2 | + | |
3 | +A completely wchar_t port of MinGW's port of getopt.c/h. Implements getoptW, getoptW_long, getoptW_long_only. | |
4 | + | |
5 | +I really just went through all the code in the MinGW repo and replaced all instances of char with wchar_t. This should work and it's free. The other option on the web is GPL which means you can't use it commercially unless you compile it as a DLL. This one is very small and light. | |
6 | + | |
7 | +Here's the licence preamble from the MinGW version. By using this you agree to all the same terms as well as the Selection of Venue paragraph. | |
8 | + | |
9 | +##Licence | |
10 | + | |
11 | +Permission is hereby granted, free of charge, to any person obtaining a | |
12 | +copy of this software and associated documentation files (the "Software"), | |
13 | +to deal in the Software without restriction, including without limitation | |
14 | +the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
15 | +and/or sell copies of the Software, and to permit persons to whom the | |
16 | +Software is furnished to do so, subject to the following conditions: | |
17 | + | |
18 | +The above copyright notice, this permission notice, and the following | |
19 | +disclaimer shall be included in all copies or substantial portions of | |
20 | +the Software. | |
21 | + | |
22 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
23 | +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
24 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
25 | +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
26 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
27 | +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
28 | +DEALINGS IN THE SOFTWARE. | |
29 | + | |
30 | + | |
31 | +### Selection of Venue: | |
32 | + | |
33 | +This licence is governed by the laws of Ontario, Canada and any dispute | |
34 | +shall be finally resolved by the courts in London, Ontario, Canada. | |
35 | + | |
36 | + | |
37 | +## Usage | |
38 | +You can pretty much just follow the getopt, getopt_long, getopt_long_only docs. | |
39 | +```c | |
40 | + struct option long_options[] = | |
41 | + { | |
42 | + {L"range", required_argument, 0, L'r'}, | |
43 | + {L"username", required_argument, 0, L'u'}, | |
44 | + {L"domain", required_argument, 0, L'd'}, | |
45 | + {L"password", required_argument, 0, L'p'}, | |
46 | + {L"loglevel", required_argument, 0, L'l'}, | |
47 | + {L"hostfile", required_argument, 0, L'h'}, | |
48 | + {L"threadmax", required_argument, 0, L't'}, | |
49 | + {0, 0, 0, 0} | |
50 | + }; | |
51 | + | |
52 | + int option; | |
53 | + | |
54 | + | |
55 | + int option_index = 0; | |
56 | + int loglevel = 0; | |
57 | + bool hostrange_defined = false; | |
58 | + bool hostfile_defined = false; | |
59 | + int threadmax = 0; | |
60 | + | |
61 | + while(1) { | |
62 | + option = getoptW_long(argc, argv, L"h:u:d:p:l:r:", long_options, &option_index); | |
63 | + | |
64 | + if(option == -1) break; | |
65 | + | |
66 | + DUSTERR err; | |
67 | + | |
68 | + switch (option) | |
69 | + { | |
70 | + case L't': | |
71 | + threadmax = _wtoi(optarg); | |
72 | + if (threadmax > 100) | |
73 | + { | |
74 | + display_error("Error: Too many threads specified. Max is 100."); | |
75 | + return DUST_ERR_THREAD_MAX_EXCEEDED; | |
76 | + } | |
77 | + if(threadmax < 1) | |
78 | + { | |
79 | + display_error("Error: Too few threads specified. Min is 1."); | |
80 | + return DUST_ERR_THREAD_MIN_EXCEEDED; | |
81 | + } | |
82 | + | |
83 | + settings->max_threads = (unsigned int)threadmax; | |
84 | + | |
85 | + break; | |
86 | + case L'h': | |
87 | + if(hostrange_defined) | |
88 | + { | |
89 | + display_error("Error: Both a host range and host file were defined. Please define only one."); | |
90 | + return DUST_ERR_HOSTFILE_AND_HOSTRANGE_BOTH_DEFINED; | |
91 | + } | |
92 | + settings->hostfile = wcsdup(optarg); | |
93 | + err = read_hosts_to_array(settings->hostfile, &settings->hosts); | |
94 | + | |
95 | + if(err != DUST_ERR_SUCCESS) { | |
96 | + return err; | |
97 | + } | |
98 | + | |
99 | + hostfile_defined = true; | |
100 | + break; | |
101 | + | |
102 | + case L'l': | |
103 | + loglevel = _wtoi(optarg); | |
104 | + if(loglevel < 1 || loglevel > 3) | |
105 | + { | |
106 | + display_error("Invalid log level"); | |
107 | + return DUST_ERR_INVALID_PARAMETER_VALUE; | |
108 | + } | |
109 | + settings->loglevel = loglevel; | |
110 | + break; | |
111 | + | |
112 | + case L'u': | |
113 | + settings->username = wcsdup(optarg); | |
114 | + break; | |
115 | + | |
116 | + case L'p': | |
117 | + settings->password = wcsdup(optarg); | |
118 | + break; | |
119 | + | |
120 | + case L'd': | |
121 | + settings->domain = wcsdup(optarg); | |
122 | + break; | |
123 | + | |
124 | + case L'r': | |
125 | + if(hostfile_defined) | |
126 | + { | |
127 | + display_error("Error: Both a host range and host file were defined. Please define only one."); | |
128 | + return DUST_ERR_HOSTFILE_AND_HOSTRANGE_BOTH_DEFINED; | |
129 | + } | |
130 | + ConvertTCharToUtf8(optarg, &settings->hostrange); | |
131 | + err = parse_host_range(settings->hostrange, &settings->hosts); | |
132 | + if (DUST_ERR_SUCCESS != err) | |
133 | + { | |
134 | + display_error("Error: Invalid host range."); | |
135 | + return err; | |
136 | + } | |
137 | + hostrange_defined = true; | |
138 | + break; | |
139 | + } | |
140 | + } | |
141 | + | |
142 | +``` | |
\ No newline at end of file |
@@ -0,0 +1,801 @@ | ||
1 | +/* | |
2 | + * getoptW.c | |
3 | + * | |
4 | + * Implementation of the `getoptW', `getoptW_longW' and `getoptW_long_onlyW' | |
5 | + * APIs, for inclusion in the MinGW runtime library. | |
6 | + * | |
7 | + * This file is part of the MinGW32 package set. | |
8 | + * | |
9 | + * Written by Keith Marshall <keithmarshall@users.sourceforge.net> | |
10 | + * Copyright (C) 2008, 2009, 2011, 2012, MinGW.org Project. | |
11 | + * | |
12 | + * --------------------------------------------------------------------------- | |
13 | + * | |
14 | + * Permission is hereby granted, free of charge, to any person obtaining a | |
15 | + * copy of this software and associated documentation files (the "Software"), | |
16 | + * to deal in the Software without restriction, including without limitation | |
17 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
18 | + * and/or sell copies of the Software, and to permit persons to whom the | |
19 | + * Software is furnished to do so, subject to the following conditions: | |
20 | + * | |
21 | + * The above copyright notice, this permission notice, and the following | |
22 | + * disclaimer shall be included in all copies or substantial portions of | |
23 | + * the Software. | |
24 | + * | |
25 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
26 | + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
27 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
28 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
29 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
30 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
31 | + * DEALINGS IN THE SOFTWARE. | |
32 | + * | |
33 | + * This licence is governed by the laws of Ontario, Canada and any dispute | |
34 | + * shall be finally resolved by the courts in London, Ontario, Canada. | |
35 | + * | |
36 | + * --------------------------------------------------------------------------- | |
37 | + * | |
38 | + */ | |
39 | + | |
40 | +#ifndef UNICODE | |
41 | +#define UNICODE | |
42 | +#endif | |
43 | + | |
44 | +#include <stdio.h> | |
45 | +#include <stdlib.h> | |
46 | +#include <stdarg.h> | |
47 | +#include "getoptW.h" | |
48 | +#include <tchar.h> | |
49 | +#include <crtdefs.h> | |
50 | + | |
51 | +/* Identify how to get the calling program name, for use in messages... | |
52 | + */ | |
53 | +#ifdef __CYGWIN__ | |
54 | +/* | |
55 | + * CYGWIN uses this DLL reference... | |
56 | + */ | |
57 | +# define PROGNAME __progname | |
58 | +extern char __declspec(dllimport) *__progname; | |
59 | +#else | |
60 | +/* | |
61 | + * ...while elsewhere, we simply use the first argument passed. | |
62 | + */ | |
63 | +# define PROGNAME *argv | |
64 | +#endif | |
65 | + | |
66 | +/* Initialise the public variables. */ | |
67 | + | |
68 | +int optind = 1; /* index for first non-option arg */ | |
69 | +int opterr = 1; /* enable built-in error messages */ | |
70 | + | |
71 | + | |
72 | +#define WCHAR wchar_t /* argument type selector */ | |
73 | + | |
74 | +WCHAR *optarg = NULL; /* pointer to current option argument */ | |
75 | + | |
76 | +#define getoptW_switchar L'-' /* option prefix character in argv */ | |
77 | +#define getoptW_pluschar L'+' /* prefix for POSIX mode in optstring */ | |
78 | +#define getoptW_takes_argument L':' /* marker for optarg in optstring */ | |
79 | +#define getoptW_arg_assign L'=' /* longopt argument field separator */ | |
80 | +#define getoptW_unknown L'?' /* return code for unmatched option */ | |
81 | +#define getoptW_ordered 1 /* return code for ordered non-option */ | |
82 | + | |
83 | +#define getoptW_all_done -1 /* return code to indicate completion */ | |
84 | + | |
85 | +enum | |
86 | +{ /* All `getoptW' API functions are implemented via calls to the | |
87 | + * common static function `getoptW_parse()'; these `mode' selectors | |
88 | + * determine the behaviour of `getoptW_parse()', to deliver the | |
89 | + * appropriate result in each case. | |
90 | + */ | |
91 | + getoptW_mode_standard = 0, /* getoptW() */ | |
92 | + getoptW_mode_long, /* getoptW_long() */ | |
93 | + getoptW_mode_long_only /* getoptW_long_only() */ | |
94 | +}; | |
95 | + | |
96 | +enum | |
97 | +{ /* When attempting to match a command line argument to a long form option, | |
98 | + * these indicate the status of the match. | |
99 | + */ | |
100 | + getoptW_no_match = 0, /* no successful match */ | |
101 | + getoptW_abbreviated_match, /* argument is an abbreviation for an option */ | |
102 | + getoptW_exact_match /* argument matches the full option name */ | |
103 | +}; | |
104 | + | |
105 | +int optopt = getoptW_unknown; /* return value for option being evaluated */ | |
106 | + | |
107 | +/* Some BSD applications expect to be able to reinitialise `getoptW' parsing | |
108 | + * by setting a global variable called `optreset'. We provide an obfuscated | |
109 | + * API, which allows applications to emulate this brain damage; however, any | |
110 | + * use of this is non-portable, and is strongly discouraged. | |
111 | + */ | |
112 | +#define optreset __mingw_optreset | |
113 | +int optreset = 0; | |
114 | + | |
115 | +static __inline__ | |
116 | +int getoptW_missing_arg( const WCHAR *optstring ) | |
117 | +{ | |
118 | + /* Helper function to determine the appropriate return value, | |
119 | + * for the case where a required option argument is missing. | |
120 | + */ | |
121 | + if( (*optstring == getoptW_pluschar) || (*optstring == getoptW_switchar) ) | |
122 | + ++optstring; | |
123 | + return (*optstring == getoptW_takes_argument) | |
124 | + ? getoptW_takes_argument | |
125 | + : getoptW_unknown; | |
126 | +} | |
127 | + | |
128 | +/* `complain' macro facilitates the generation of simple built-in | |
129 | + * error messages, displayed on various fault conditions, provided | |
130 | + * `opterr' is non-zero. | |
131 | + */ | |
132 | +#define complain( MSG, ARG ) if( opterr ) \ | |
133 | + fwprintf( stderr, L"%ls: " MSG L"\n", PROGNAME, ARG ) | |
134 | + | |
135 | +static __inline__ | |
136 | +int getoptW_argerror( int mode, WCHAR *fmt, WCHAR *prog, struct option *opt, int retval ) | |
137 | +{ | |
138 | + /* Helper function, to generate more complex built-in error | |
139 | + * messages, for invalid arguments to long form options ... | |
140 | + */ | |
141 | + if( opterr ) | |
142 | + { | |
143 | + /* ... but, displayed only if `opterr' is non-zero. | |
144 | + */ | |
145 | + WCHAR flag[] = L"--"; | |
146 | + if( mode != getoptW_mode_long ) | |
147 | + /* | |
148 | + * only display one hyphen, for implicit long form options, | |
149 | + * improperly resolved by `getoptW_long_only()'. | |
150 | + */ | |
151 | + flag[1] = L'\0'; | |
152 | + /* | |
153 | + * always preface the program name ... | |
154 | + */ | |
155 | + fwprintf( stderr, L"%ls: ", prog ); | |
156 | + /* | |
157 | + * to the appropriate, option specific message. | |
158 | + */ | |
159 | + fwprintf( stderr, fmt, flag, opt->name ); | |
160 | + } | |
161 | + /* Whether displaying the message, or not, always set `optopt' | |
162 | + * to identify the faulty option ... | |
163 | + */ | |
164 | + optopt = opt->val; | |
165 | + /* | |
166 | + * and return the `invalid option' indicator. | |
167 | + */ | |
168 | + return retval; | |
169 | +} | |
170 | + | |
171 | +/* `getoptW_conventions' establish behavioural options, to control | |
172 | + * the operation of `getoptW_parse()', e.g. to select between POSIX | |
173 | + * and GNU style argument parsing behaviour. | |
174 | + */ | |
175 | +#define getoptW_set_conventions 0x1000 | |
176 | +#define getoptW_posixly_correct 0x0010 | |
177 | + | |
178 | +static __inline__ | |
179 | +int getoptW_conventions( int flags ) | |
180 | +{ | |
181 | + static int conventions = 0; | |
182 | + | |
183 | + if( (conventions == 0) && ((flags & getoptW_set_conventions) == 0) ) | |
184 | + { | |
185 | + /* default conventions have not yet been established; | |
186 | + * initialise them now! | |
187 | + */ | |
188 | + conventions = getoptW_set_conventions; | |
189 | + if( (flags == getoptW_pluschar) || (getenv( "POSIXLY_CORRECT" ) != NULL) ) | |
190 | + conventions |= getoptW_posixly_correct; | |
191 | + } | |
192 | + | |
193 | + else if( flags & getoptW_set_conventions ) | |
194 | + /* | |
195 | + * default conventions may have already been established, | |
196 | + * but this is a specific request to augment them. | |
197 | + */ | |
198 | + conventions |= flags; | |
199 | + | |
200 | + /* in any event, return the currently established conventions. | |
201 | + */ | |
202 | + return conventions; | |
203 | +} | |
204 | + | |
205 | +static __inline__ | |
206 | +int is_switchar( WCHAR flag ) | |
207 | +{ | |
208 | + /* A simple helper function, used to identify the switch character | |
209 | + * introducing an optional command line argument. | |
210 | + */ | |
211 | + return flag == getoptW_switchar; | |
212 | +} | |
213 | + | |
214 | +static __inline__ | |
215 | +const WCHAR *getoptW_match( WCHAR lookup, const WCHAR *opt_string ) | |
216 | +{ | |
217 | + /* Helper function, used to identify short form options. | |
218 | + */ | |
219 | + if( (*opt_string == getoptW_pluschar) || (*opt_string == getoptW_switchar) ) | |
220 | + ++opt_string; | |
221 | + if( *opt_string == getoptW_takes_argument ) | |
222 | + ++opt_string; | |
223 | + do if( lookup == *opt_string ) return opt_string; | |
224 | + while( *++opt_string ); | |
225 | + return NULL; | |
226 | +} | |
227 | + | |
228 | +static __inline__ | |
229 | +int getoptW_match_long( const WCHAR *nextchar, const WCHAR *optname ) | |
230 | +{ | |
231 | + /* Helper function, used to identify potential matches for | |
232 | + * long form options. | |
233 | + */ | |
234 | + WCHAR matchchar; | |
235 | + while( (matchchar = *nextchar++) && (matchchar == *optname) ) | |
236 | + /* | |
237 | + * skip over initial substring which DOES match. | |
238 | + */ | |
239 | + ++optname; | |
240 | + | |
241 | + if( matchchar ) | |
242 | + { | |
243 | + /* did NOT match the entire argument to an initial substring | |
244 | + * of a defined option name ... | |
245 | + */ | |
246 | + if( matchchar != getoptW_arg_assign ) | |
247 | + /* | |
248 | + * ... and didn't stop at an `=' internal field separator, | |
249 | + * so this is NOT a possible match. | |
250 | + */ | |
251 | + return getoptW_no_match; | |
252 | + | |
253 | + /* DID stop at an `=' internal field separator, | |
254 | + * so this IS a possible match, and what follows is an | |
255 | + * argument to the possibly matched option. | |
256 | + */ | |
257 | + optarg = (WCHAR *)(nextchar); | |
258 | + } | |
259 | + return *optname | |
260 | + /* | |
261 | + * if we DIDN'T match the ENTIRE text of the option name, | |
262 | + * then it's a possible abbreviated match ... | |
263 | + */ | |
264 | + ? getoptW_abbreviated_match | |
265 | + /* | |
266 | + * but if we DID match the entire option name, | |
267 | + * then it's a DEFINITE EXACT match. | |
268 | + */ | |
269 | + : getoptW_exact_match; | |
270 | +} | |
271 | + | |
272 | +static __inline__ | |
273 | +int getoptW_resolved( int mode, int argc, WCHAR *const *argv, int *argind, | |
274 | + struct option *opt, int index, int *retindex, const WCHAR *optstring ) | |
275 | +{ | |
276 | + /* Helper function to establish appropriate return conditions, | |
277 | + * on resolution of a long form option. | |
278 | + */ | |
279 | + if( retindex != NULL ) | |
280 | + *retindex = index; | |
281 | + | |
282 | + /* On return, `optind' should normally refer to the argument, if any, | |
283 | + * which follows the current one; it is convenient to set this, before | |
284 | + * checking for the presence of any `optarg'. | |
285 | + */ | |
286 | + optind = *argind + 1; | |
287 | + | |
288 | + if( optarg && (opt[index].has_arg == no_argument) ) | |
289 | + /* | |
290 | + * it is an error for the user to specify an option specific argument | |
291 | + * with an option which doesn't expect one! | |
292 | + */ | |
293 | + return getoptW_argerror( mode, L"option `%ls%ls' doesn't accept an argument\n", | |
294 | + PROGNAME, opt + index, getoptW_unknown ); | |
295 | + | |
296 | + else if( (optarg == NULL) && (opt[index].has_arg == required_argument) ) | |
297 | + { | |
298 | + /* similarly, it is an error if no argument is specified | |
299 | + * with an option which requires one ... | |
300 | + */ | |
301 | + if( optind < argc ) | |
302 | + /* | |
303 | + * ... except that the requirement may be satisfied from | |
304 | + * the following command line argument, if any ... | |
305 | + */ | |
306 | + optarg = argv[*argind = optind++]; | |
307 | + | |
308 | + else | |
309 | + /* so fail this case, only if no such argument exists! | |
310 | + */ | |
311 | + return getoptW_argerror( mode, L"option `%ls%ls' requires an argument\n", | |
312 | + PROGNAME, opt + index, getoptW_missing_arg( optstring ) ); | |
313 | + } | |
314 | + | |
315 | + /* when the caller has provided a return buffer ... | |
316 | + */ | |
317 | + if( opt[index].flag != NULL ) | |
318 | + { | |
319 | + /* ... then we place the proper return value there, | |
320 | + * and return a status code of zero ... | |
321 | + */ | |
322 | + *(opt[index].flag) = opt[index].val; | |
323 | + return 0; | |
324 | + } | |
325 | + /* ... otherwise, the return value becomes the status code. | |
326 | + */ | |
327 | + return opt[index].val; | |
328 | +} | |
329 | + | |
330 | +static __inline__ | |
331 | +int getoptW_verify( const WCHAR *nextchar, const WCHAR *optstring ) | |
332 | +{ | |
333 | + /* Helper function, called by getoptW_parse() when invoked | |
334 | + * by getoptW_long_only(), to verify when an unmatched or an | |
335 | + * ambiguously matched long form option string is valid as | |
336 | + * a short form option specification. | |
337 | + */ | |
338 | + if( ! (nextchar && *nextchar && optstring && *optstring) ) | |
339 | + /* | |
340 | + * There are no characters to be matched, or there are no | |
341 | + * valid short form option characters to which they can be | |
342 | + * matched, so this can never be valid. | |
343 | + */ | |
344 | + return 0; | |
345 | + | |
346 | + while( *nextchar ) | |
347 | + { | |
348 | + /* For each command line character in turn ... | |
349 | + */ | |
350 | + const WCHAR *test; | |
351 | + if( (test = getoptW_match( *nextchar++, optstring )) == NULL ) | |
352 | + /* | |
353 | + * ... there is no short form option to match the current | |
354 | + * candidate, so the entire argument fails. | |
355 | + */ | |
356 | + return 0; | |
357 | + | |
358 | + if( test[1] == getoptW_takes_argument ) | |
359 | + /* | |
360 | + * The current candidate is valid, and it matches an option | |
361 | + * which takes an argument, so this command line argument is | |
362 | + * a valid short form option specification; accept it. | |
363 | + */ | |
364 | + return 1; | |
365 | + } | |
366 | + /* If we get to here, then every character in the command line | |
367 | + * argument was valid as a short form option; accept it. | |
368 | + */ | |
369 | + return 1; | |
370 | +} | |
371 | + | |
372 | +static | |
373 | +#define getoptW_std_args int argc, WCHAR *const argv[], const WCHAR *optstring | |
374 | +int getoptW_parse( int mode, getoptW_std_args, ... ) | |
375 | +{ | |
376 | + /* Common core implementation for ALL `getoptW' functions. | |
377 | + */ | |
378 | + static int argind = 0; | |
379 | + static int optbase = 0; | |
380 | + static const WCHAR *nextchar = NULL; | |
381 | + static int optmark = 0; | |
382 | + | |
383 | + if( (optreset |= (optind < 1)) || (optind < optbase) ) | |
384 | + { | |
385 | + /* POSIX does not prescribe any definitive mechanism for restarting | |
386 | + * a `getoptW' scan, but some applications may require such capability. | |
387 | + * We will support it, by allowing the caller to adjust the value of | |
388 | + * `optind' downwards, (nominally setting it to zero). Since POSIX | |
389 | + * wants `optind' to have an initial value of one, but we want all | |
390 | + * of our internal place holders to be initialised to zero, when we | |
391 | + * are called for the first time, we will handle such a reset by | |
392 | + * adjusting all of the internal place holders to one less than | |
393 | + * the adjusted `optind' value, (but never to less than zero). | |
394 | + */ | |
395 | + if( optreset ) | |
396 | + { | |
397 | + /* User has explicitly requested reinitialisation... | |
398 | + * We need to reset `optind' to it's normal initial value of 1, | |
399 | + * to avoid a potential infinitely recursive loop; by doing this | |
400 | + * up front, we also ensure that the remaining place holders | |
401 | + * will be correctly reinitialised to no less than zero. | |
402 | + */ | |
403 | + optind = 1; | |
404 | + | |
405 | + /* We also need to clear the `optreset' request... | |
406 | + */ | |
407 | + optreset = 0; | |
408 | + } | |
409 | + | |
410 | + /* Now, we may safely reinitialise the internal place holders, to | |
411 | + * one less than `optind', without fear of making them negative. | |
412 | + */ | |
413 | + optmark = optbase = argind = optind - 1; | |
414 | + nextchar = NULL; | |
415 | + } | |
416 | + | |
417 | + /* From a POSIX perspective, the following is `undefined behaviour'; | |
418 | + * we implement it thus, for compatibility with GNU and BSD getoptW. | |
419 | + */ | |
420 | + else if( optind > (argind + 1) ) | |
421 | + { | |
422 | + /* Some applications expect to be able to manipulate `optind', | |
423 | + * causing `getoptW' to skip over one or more elements of `argv'; | |
424 | + * POSIX doesn't require us to support this brain-damaged concept; | |
425 | + * (indeed, POSIX defines no particular behaviour, in the event of | |
426 | + * such usage, so it must be considered a bug for an application | |
427 | + * to rely on any particular outcome); nonetheless, Mac-OS-X and | |
428 | + * BSD actually provide *documented* support for this capability, | |
429 | + * so we ensure that our internal place holders keep track of | |
430 | + * external `optind' increments; (`argind' must lag by one). | |
431 | + */ | |
432 | + argind = optind - 1; | |
433 | + | |
434 | + /* When `optind' is misused, in this fashion, we also abandon any | |
435 | + * residual text in the argument we had been parsing; this is done | |
436 | + * without any further processing of such abandoned text, assuming | |
437 | + * that the caller is equipped to handle it appropriately. | |
438 | + */ | |
439 | + nextchar = NULL; | |
440 | + } | |
441 | + | |
442 | + if( nextchar && *nextchar ) | |
443 | + { | |
444 | + /* we are parsing a standard, or short format, option argument ... | |
445 | + */ | |
446 | + const WCHAR *optchar; | |
447 | + if( (optchar = getoptW_match( optopt = *nextchar++, optstring )) != NULL ) | |
448 | + { | |
449 | + /* we have identified it as valid ... | |
450 | + */ | |
451 | + if( optchar[1] == getoptW_takes_argument ) | |
452 | + { | |
453 | + /* and determined that it requires an associated argument ... | |
454 | + */ | |
455 | + if( ! *(optarg = (WCHAR *)(nextchar)) ) | |
456 | + { | |
457 | + /* the argument is NOT attached ... | |
458 | + */ | |
459 | + if( optchar[2] == getoptW_takes_argument ) | |
460 | + /* | |
461 | + * but this GNU extension marks it as optional, | |
462 | + * so we don't provide one on this occasion. | |
463 | + */ | |
464 | + optarg = NULL; | |
465 | + | |
466 | + /* otherwise this option takes a mandatory argument, | |
467 | + * so, provided there is one available ... | |
468 | + */ | |
469 | + else if( (argc - argind) > 1 ) | |
470 | + /* | |
471 | + * we take the following command line argument, | |
472 | + * as the appropriate option argument. | |
473 | + */ | |
474 | + optarg = argv[++argind]; | |
475 | + | |
476 | + /* but if no further argument is available, | |
477 | + * then there is nothing we can do, except for | |
478 | + * issuing the requisite diagnostic message. | |
479 | + */ | |
480 | + else | |
481 | + { | |
482 | + complain( "option requires an argument -- %c", optopt ); | |
483 | + return getoptW_missing_arg( optstring ); | |
484 | + } | |
485 | + } | |
486 | + optind = argind + 1; | |
487 | + nextchar = NULL; | |
488 | + } | |
489 | + else | |
490 | + optarg = NULL; | |
491 | + optind = (nextchar && *nextchar) ? argind : argind + 1; | |
492 | + return optopt; | |
493 | + } | |
494 | + /* if we didn't find a valid match for the specified option character, | |
495 | + * then we fall through to here, so take appropriate diagnostic action. | |
496 | + */ | |
497 | + if( mode == getoptW_mode_long_only ) | |
498 | + { | |
499 | + complain( "unrecognised option `-%s'", --nextchar ); | |
500 | + nextchar = NULL; | |
501 | + optopt = 0; | |
502 | + } | |
503 | + else | |
504 | + complain( "invalid option -- %c", optopt ); | |
505 | + optind = (nextchar && *nextchar) ? argind : argind + 1; | |
506 | + return getoptW_unknown; | |
507 | + } | |
508 | + | |
509 | + if( optmark > optbase ) | |
510 | + { | |
511 | + /* This can happen, in GNU parsing mode ONLY, when we have | |
512 | + * skipped over non-option arguments, and found a subsequent | |
513 | + * option argument; in this case we permute the arguments. | |
514 | + */ | |
515 | + int index; | |
516 | + /* | |
517 | + * `optspan' specifies the number of contiguous arguments | |
518 | + * which are spanned by the current option, and so must be | |
519 | + * moved together during permutation. | |
520 | + */ | |
521 | + int optspan = argind - optmark + 1; | |
522 | + /* | |
523 | + * we use `this_arg' to store these temporarily. | |
524 | + */ | |
525 | + WCHAR *this_arg[optspan]; | |
526 | + /* | |
527 | + * we cannot manipulate `argv' directly, since the `getoptW' | |
528 | + * API prototypes it as `read-only'; this cast to `arglist' | |
529 | + * allows us to work around that restriction. | |
530 | + */ | |
531 | + WCHAR **arglist = (WCHAR **)(argv); | |
532 | + | |
533 | + /* save temporary copies of the arguments which are associated | |
534 | + * with the current option ... | |
535 | + */ | |
536 | + for( index = 0; index < optspan; ++index ) | |
537 | + this_arg[index] = arglist[optmark + index]; | |
538 | + | |
539 | + /* move all preceding non-option arguments to the right, | |
540 | + * overwriting these saved arguments, while making space | |
541 | + * to replace them in their permuted location. | |
542 | + */ | |
543 | + for( --optmark; optmark >= optbase; --optmark ) | |
544 | + arglist[optmark + optspan] = arglist[optmark]; | |
545 | + | |
546 | + /* restore the temporarily saved option arguments to | |
547 | + * their permuted location. | |
548 | + */ | |
549 | + for( index = 0; index < optspan; ++index ) | |
550 | + arglist[optbase + index] = this_arg[index]; | |
551 | + | |
552 | + /* adjust `optbase', to account for the relocated option. | |
553 | + */ | |
554 | + optbase += optspan; | |
555 | + } | |
556 | + | |
557 | + else | |
558 | + /* no permutation occurred ... | |
559 | + * simply adjust `optbase' for all options parsed so far. | |
560 | + */ | |
561 | + optbase = argind + 1; | |
562 | + | |
563 | + /* enter main parsing loop ... | |
564 | + */ | |
565 | + while( argc > ++argind ) | |
566 | + { | |
567 | + /* inspect each argument in turn, identifying possible options ... | |
568 | + */ | |
569 | + if( is_switchar( *(nextchar = argv[optmark = argind]) ) && *++nextchar ) | |
570 | + { | |
571 | + /* we've found a candidate option argument ... */ | |
572 | + | |
573 | + if( is_switchar( *nextchar ) ) | |
574 | + { | |
575 | + /* it's a double hyphen argument ... */ | |
576 | + | |
577 | + const WCHAR *refchar = nextchar; | |
578 | + if( *++refchar ) | |
579 | + { | |
580 | + /* and it looks like a long format option ... | |
581 | + * `getoptW_long' mode must be active to accept it as such, | |
582 | + * `getoptW_long_only' also qualifies, but we must downgrade | |
583 | + * it to force explicit handling as a long format option. | |
584 | + */ | |
585 | + if( mode >= getoptW_mode_long ) | |
586 | + { | |
587 | + nextchar = refchar; | |
588 | + mode = getoptW_mode_long; | |
589 | + } | |
590 | + } | |
591 | + else | |
592 | + { | |
593 | + /* this is an explicit `--' end of options marker, so wrap up now! | |
594 | + */ | |
595 | + if( optmark > optbase ) | |
596 | + { | |
597 | + /* permuting the argument list as necessary ... | |
598 | + * (note use of `this_arg' and `arglist', as above). | |
599 | + */ | |
600 | + WCHAR *this_arg = argv[optmark]; | |
601 | + WCHAR **arglist = (WCHAR **)(argv); | |
602 | + | |
603 | + /* move all preceding non-option arguments to the right ... | |
604 | + */ | |
605 | + do arglist[optmark] = arglist[optmark - 1]; | |
606 | + while( optmark-- > optbase ); | |
607 | + | |
608 | + /* reinstate the `--' marker, in its permuted location. | |
609 | + */ | |
610 | + arglist[optbase] = this_arg; | |
611 | + } | |
612 | + /* ... before finally bumping `optbase' past the `--' marker, | |
613 | + * and returning the `all done' completion indicator. | |
614 | + */ | |
615 | + optind = ++optbase; | |
616 | + return getoptW_all_done; | |
617 | + } | |
618 | + } | |
619 | + else if( mode < getoptW_mode_long_only ) | |
620 | + { | |
621 | + /* it's not an explicit long option, and `getoptW_long_only' isn't active, | |
622 | + * so we must explicitly try to match it as a short option. | |
623 | + */ | |
624 | + mode = getoptW_mode_standard; | |
625 | + } | |
626 | + | |
627 | + if( mode >= getoptW_mode_long ) | |
628 | + { | |
629 | + /* the current argument is a long form option, (either explicitly, | |
630 | + * introduced by a double hyphen, or implicitly because we were called | |
631 | + * by `getoptW_long_only'); this is where we parse it. | |
632 | + */ | |
633 | + int lookup; | |
634 | + int matched = -1; | |
635 | + | |
636 | + /* we need to fetch the `extra' function arguments, which are | |
637 | + * specified for the `getoptW_long' APIs. | |
638 | + */ | |
639 | + va_list refptr; | |
640 | + va_start( refptr, optstring ); | |
641 | + struct option *longopts = va_arg( refptr, struct option * ); | |
642 | + int *optindex = va_arg( refptr, int * ); | |
643 | + va_end( refptr ); | |
644 | + | |
645 | + /* ensuring that `optarg' does not inherit any junk, from parsing | |
646 | + * preceding arguments ... | |
647 | + */ | |
648 | + optarg = NULL; | |
649 | + for( lookup = 0; longopts && longopts[lookup].name; ++lookup ) | |
650 | + { | |
651 | + /* scan the list of defined long form options ... | |
652 | + */ | |
653 | + switch( getoptW_match_long( nextchar, longopts[lookup].name ) ) | |
654 | + { | |
655 | + /* looking for possible matches for the current argument. | |
656 | + */ | |
657 | + case getoptW_exact_match: | |
658 | + /* | |
659 | + * when an exact match is found, | |
660 | + * return it immediately, setting `nextchar' to NULL, | |
661 | + * to ensure we don't mistakenly try to match any | |
662 | + * subsequent characters as short form options. | |
663 | + */ | |
664 | + nextchar = NULL; | |
665 | + return getoptW_resolved( mode, argc, argv, &argind, | |
666 | + longopts, lookup, optindex, optstring ); | |
667 | + | |
668 | + case getoptW_abbreviated_match: | |
669 | + /* | |
670 | + * but, for a partial (initial substring) match ... | |
671 | + */ | |
672 | + if( matched >= 0 ) | |
673 | + { | |
674 | + /* if this is not the first, then we have an ambiguity ... | |
675 | + */ | |
676 | + if( (mode == getoptW_mode_long_only) | |
677 | + /* | |
678 | + * However, in the case of getoptW_long_only(), if | |
679 | + * the entire ambiguously matched string represents | |
680 | + * a valid short option specification, then we may | |
681 | + * proceed to interpret it as such. | |
682 | + */ | |
683 | + && getoptW_verify( nextchar, optstring ) ) | |
684 | + return getoptW_parse( mode, argc, argv, optstring ); | |
685 | + | |
686 | + /* If we get to here, then the ambiguously matched | |
687 | + * partial long option isn't valid for short option | |
688 | + * evaluation; reset parser context to resume with | |
689 | + * the following command line argument, diagnose | |
690 | + * ambiguity, and bail out. | |
691 | + */ | |
692 | + optopt = 0; | |
693 | + nextchar = NULL; | |
694 | + optind = argind + 1; | |
695 | + complain( "option `%s' is ambiguous", argv[argind] ); | |
696 | + return getoptW_unknown; | |
697 | + } | |
698 | + /* otherwise just note that we've found a possible match ... | |
699 | + */ | |
700 | + matched = lookup; | |
701 | + } | |
702 | + } | |
703 | + if( matched >= 0 ) | |
704 | + { | |
705 | + /* if we get to here, then we found exactly one partial match, | |
706 | + * so return it, as for an exact match. | |
707 | + */ | |
708 | + nextchar = NULL; | |
709 | + return getoptW_resolved( mode, argc, argv, &argind, | |
710 | + longopts, matched, optindex, optstring ); | |
711 | + } | |
712 | + /* if here, then we had what SHOULD have been a long form option, | |
713 | + * but it is unmatched ... | |
714 | + */ | |
715 | + if( (mode < getoptW_mode_long_only) | |
716 | + /* | |
717 | + * ... although paradoxically, `mode == getoptW_mode_long_only' | |
718 | + * allows us to still try to match it as a short form option. | |
719 | + */ | |
720 | + || (getoptW_verify( nextchar, optstring ) == 0) ) | |
721 | + { | |
722 | + /* When it cannot be matched, reset the parsing context to | |
723 | + * resume from the next argument, diagnose the failed match, | |
724 | + * and bail out. | |
725 | + */ | |
726 | + optopt = 0; | |
727 | + nextchar = NULL; | |
728 | + optind = argind + 1; | |
729 | + complain( "unrecognised option `%s'", argv[argind] ); | |
730 | + return getoptW_unknown; | |
731 | + } | |
732 | + } | |
733 | + /* fall through to handle standard short form options... | |
734 | + * when the option argument format is neither explictly identified | |
735 | + * as long, nor implicitly matched as such, and the argument isn't | |
736 | + * just a bare hyphen, (which isn't an option), then we make one | |
737 | + * recursive call to explicitly interpret it as short format. | |
738 | + */ | |
739 | + if( *nextchar ) | |
740 | + return getoptW_parse( mode, argc, argv, optstring ); | |
741 | + } | |
742 | + /* if we get to here, then we've parsed a non-option argument ... | |
743 | + * in GNU compatibility mode, we step over it, so we can permute | |
744 | + * any subsequent option arguments, but ... | |
745 | + */ | |
746 | + if( *optstring == getoptW_switchar ) | |
747 | + { | |
748 | + /* if `optstring' begins with a `-' character, this special | |
749 | + * GNU specific behaviour requires us to return the non-option | |
750 | + * arguments in strict order, as pseudo-arguments to a special | |
751 | + * option, with return value defined as `getoptW_ordered'. | |
752 | + */ | |
753 | + nextchar = NULL; | |
754 | + optind = argind + 1; | |
755 | + optarg = argv[argind]; | |
756 | + return getoptW_ordered; | |
757 | + } | |
758 | + if( getoptW_conventions( *optstring ) & getoptW_posixly_correct ) | |
759 | + /* | |
760 | + * otherwise ... | |
761 | + * for POSIXLY_CORRECT behaviour, or if `optstring' begins with | |
762 | + * a `+' character, then we break out of the parsing loop, so that | |
763 | + * the scan ends at the current argument, with no permutation. | |
764 | + */ | |
765 | + break; | |
766 | + } | |
767 | + /* fall through when all arguments have been evaluated, | |
768 | + */ | |
769 | + optind = optbase; | |
770 | + return getoptW_all_done; | |
771 | +} | |
772 | + | |
773 | +/* All three public API entry points are trivially defined, | |
774 | + * in terms of the internal `getoptW_parse' function. | |
775 | + */ | |
776 | +int getoptW( getoptW_std_args ) | |
777 | +{ | |
778 | + return getoptW_parse( getoptW_mode_standard, argc, argv, optstring ); | |
779 | +} | |
780 | + | |
781 | +int getoptW_long( getoptW_std_args, const struct option *opts, int *index ) | |
782 | +{ | |
783 | + return getoptW_parse( getoptW_mode_long, argc, argv, optstring, opts, index ); | |
784 | +} | |
785 | + | |
786 | +int getoptW_long_only( getoptW_std_args, const struct option *opts, int *index ) | |
787 | +{ | |
788 | + return getoptW_parse( getoptW_mode_long_only, argc, argv, optstring, opts, index ); | |
789 | +} | |
790 | + | |
791 | +#ifdef __weak_alias | |
792 | +/* | |
793 | + * These Microsnot style uglified aliases are provided for compatibility | |
794 | + * with the previous MinGW implementation of the getoptW API. | |
795 | + */ | |
796 | +__weak_alias( getoptW, _getoptW ) | |
797 | +__weak_alias( getoptW_long, _getoptW_long ) | |
798 | +__weak_alias( getoptW_long_only, _getoptW_long_only ) | |
799 | +#endif | |
800 | + | |
801 | +/* $RCSfile$: end of file */ |
@@ -0,0 +1,98 @@ | ||
1 | +#ifndef __GETOPTW_H__ | |
2 | +/** | |
3 | + * DISCLAIMER | |
4 | + * This file has no copyright assigned and is placed in the Public Domain. | |
5 | + * This file is part of the mingw-w64 runtime package. | |
6 | + * | |
7 | + * The mingw-w64 runtime package and its code is distributed in the hope that it | |
8 | + * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR | |
9 | + * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to | |
10 | + * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
11 | + * | |
12 | + * This licence is governed by the laws of Ontario, Canada and any dispute | |
13 | + * shall be finally resolved by the courts in London, Ontario, Canada. | |
14 | + */ | |
15 | + | |
16 | +#define __GETOPTW_H__ | |
17 | + | |
18 | +/* All the headers include this file. */ | |
19 | +#include <crtdefs.h> | |
20 | + | |
21 | +#ifdef __cplusplus | |
22 | +extern "C" { | |
23 | +#endif | |
24 | + | |
25 | +extern int optind; /* index of first non-option in argv */ | |
26 | +extern int optopt; /* single option character, as parsed */ | |
27 | +extern int opterr; /* flag to enable built-in diagnostics... */ | |
28 | +/* (user may set to zero, to suppress) */ | |
29 | + | |
30 | +extern wchar_t *optarg; /* pointer to argument of current option */ | |
31 | + | |
32 | +extern int getoptW(int nargc, wchar_t * const *nargv, const wchar_t *options); | |
33 | + | |
34 | +#ifdef _BSD_SOURCE | |
35 | +/* | |
36 | + * BSD adds the non-standard `optreset' feature, for reinitialisation | |
37 | + * of `getoptW' parsing. We support this feature, for applications which | |
38 | + * proclaim their BSD heritage, before including this header; however, | |
39 | + * to maintain portability, developers are advised to avoid it. | |
40 | + */ | |
41 | +# define optreset __mingw_optreset | |
42 | +extern int optreset; | |
43 | +#endif | |
44 | +#ifdef __cplusplus | |
45 | +} | |
46 | +#endif | |
47 | +/* | |
48 | + * POSIX requires the `getoptW' API to be specified in `unistd.h'; | |
49 | + * thus, `unistd.h' includes this header. However, we do not want | |
50 | + * to expose the `getoptW_long' or `getoptW_long_only' APIs, when | |
51 | + * included in this manner. Thus, close the standard __GETOPTW_H__ | |
52 | + * declarations block, and open an additional __GETOPTW_LONG_H__ | |
53 | + * specific block, only when *not* __UNISTD_H_SOURCED__, in which | |
54 | + * to declare the extended API. | |
55 | + */ | |
56 | +#endif /* !defined(__GETOPTW_H__) */ | |
57 | + | |
58 | +#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPTW_LONG_H__) | |
59 | +#define __GETOPTW_LONG_H__ | |
60 | + | |
61 | +#ifdef __cplusplus | |
62 | +extern "C" { | |
63 | +#endif | |
64 | + | |
65 | +struct option /* specification for a long form option... */ | |
66 | +{ | |
67 | + const wchar_t *name; /* option name, without leading hyphens */ | |
68 | + int has_arg; /* does it take an argument? */ | |
69 | + int *flag; /* where to save its status, or NULL */ | |
70 | + int val; /* its associated status value */ | |
71 | +}; | |
72 | + | |
73 | +enum /* permitted values for its `has_arg' field... */ | |
74 | +{ | |
75 | + no_argument = 0, /* option never takes an argument */ | |
76 | + required_argument, /* option always requires an argument */ | |
77 | + optional_argument /* option may take an argument */ | |
78 | +}; | |
79 | + | |
80 | +int getoptW_long(int nargc, wchar_t * const *nargv, const wchar_t *options, | |
81 | + const struct option *long_options, int *idx); | |
82 | +int getoptW_long_only(int nargc, wchar_t * const *nargv, const wchar_t *options, | |
83 | + const struct option *long_options, int *idx); | |
84 | +/* | |
85 | + * Previous MinGW implementation had... | |
86 | + */ | |
87 | +#ifndef HAVE_DECL_GETOPT | |
88 | +/* | |
89 | + * ...for the long form API only; keep this for compatibility. | |
90 | + */ | |
91 | +# define HAVE_DECL_GETOPT 1 | |
92 | +#endif | |
93 | + | |
94 | +#ifdef __cplusplus | |
95 | +} | |
96 | +#endif | |
97 | + | |
98 | +#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPTW_LONG_H__) */ |