1 /* Getopt for Microsoft C
2 This code is a modification of the Free Software Foundation, Inc.
3 Getopt library for parsing command line argument the purpose was
4 to provide a Microsoft Visual C friendly derivative. This code
5 provides functionality for both Unicode and Multibyte builds.
6
7 Date: 02/03/2011 - Ludvik Jerabek - Initial Release
8 Version: 1.0
9 Comment: Supports getopt, getopt_long, and getopt_long_only
10 and POSIXLY_CORRECT environment flag
11 License: LGPL
12
13 Revisions:
14
15 02/03/2011 - Ludvik Jerabek - Initial Release
16 02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4
17 07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs
18 08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception
19 08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB
20 02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file
21 08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi
22 10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features
23 06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable
24 24/10/2020 - Paul-Louis Ageneau - Removed Unicode version
25
26 **DISCLAIMER**
27 THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
28 EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE
29 IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
30 PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE
31 EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT
32 APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY
33 DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY
34 USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST
35 PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON
36 YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE
37 EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
38 */
39
40 #ifndef _CRT_SECURE_NO_WARNINGS
41 #define _CRT_SECURE_NO_WARNINGS
42 #endif
43
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <malloc.h>
47 #include "getopt.h"
48
49 #ifdef __cplusplus
50 #define _GETOPT_THROW throw()
51 #else
52 #define _GETOPT_THROW
53 #endif
54
55 int optind = 1;
56 int opterr = 1;
57 int optopt = '?';
58 enum ENUM_ORDERING { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER };
59
60 static struct _getopt_data_a
61 {
62 int optind;
63 int opterr;
64 int optopt;
65 char *optarg;
66 int __initialized;
67 char *__nextchar;
68 enum ENUM_ORDERING __ordering;
69 int __posixly_correct;
70 int __first_nonopt;
71 int __last_nonopt;
72 } getopt_data_a;
73 char *optarg_a;
74
exchange_a(char ** argv,struct _getopt_data_a * d)75 static void exchange_a(char **argv, struct _getopt_data_a *d)
76 {
77 int bottom = d->__first_nonopt;
78 int middle = d->__last_nonopt;
79 int top = d->optind;
80 char *tem;
81 while (top > middle && middle > bottom)
82 {
83 if (top - middle > middle - bottom)
84 {
85 int len = middle - bottom;
86 int i;
87 for (i = 0; i < len; i++)
88 {
89 tem = argv[bottom + i];
90 argv[bottom + i] = argv[top - (middle - bottom) + i];
91 argv[top - (middle - bottom) + i] = tem;
92 }
93 top -= len;
94 }
95 else
96 {
97 int len = top - middle;
98 int i;
99 for (i = 0; i < len; i++)
100 {
101 tem = argv[bottom + i];
102 argv[bottom + i] = argv[middle + i];
103 argv[middle + i] = tem;
104 }
105 bottom += len;
106 }
107 }
108 d->__first_nonopt += (d->optind - d->__last_nonopt);
109 d->__last_nonopt = d->optind;
110 }
_getopt_initialize_a(const char * optstring,struct _getopt_data_a * d,int posixly_correct)111 static const char *_getopt_initialize_a (const char *optstring, struct _getopt_data_a *d, int posixly_correct)
112 {
113 d->__first_nonopt = d->__last_nonopt = d->optind;
114 d->__nextchar = NULL;
115 d->__posixly_correct = posixly_correct | !!getenv("POSIXLY_CORRECT");
116 if (optstring[0] == '-')
117 {
118 d->__ordering = RETURN_IN_ORDER;
119 ++optstring;
120 }
121 else if (optstring[0] == '+')
122 {
123 d->__ordering = REQUIRE_ORDER;
124 ++optstring;
125 }
126 else if (d->__posixly_correct)
127 d->__ordering = REQUIRE_ORDER;
128 else
129 d->__ordering = PERMUTE;
130 return optstring;
131 }
_getopt_internal_r_a(int argc,char * const * argv,const char * optstring,const struct option_a * longopts,int * longind,int long_only,struct _getopt_data_a * d,int posixly_correct)132 int _getopt_internal_r_a (int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int posixly_correct)
133 {
134 int print_errors = d->opterr;
135 if (argc < 1)
136 return -1;
137 d->optarg = NULL;
138 if (d->optind == 0 || !d->__initialized)
139 {
140 if (d->optind == 0)
141 d->optind = 1;
142 optstring = _getopt_initialize_a (optstring, d, posixly_correct);
143 d->__initialized = 1;
144 }
145 else if (optstring[0] == '-' || optstring[0] == '+')
146 optstring++;
147 if (optstring[0] == ':')
148 print_errors = 0;
149 if (d->__nextchar == NULL || *d->__nextchar == '\0')
150 {
151 if (d->__last_nonopt > d->optind)
152 d->__last_nonopt = d->optind;
153 if (d->__first_nonopt > d->optind)
154 d->__first_nonopt = d->optind;
155 if (d->__ordering == PERMUTE)
156 {
157 if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
158 exchange_a ((char **) argv, d);
159 else if (d->__last_nonopt != d->optind)
160 d->__first_nonopt = d->optind;
161 while (d->optind < argc && (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0'))
162 d->optind++;
163 d->__last_nonopt = d->optind;
164 }
165 if (d->optind != argc && !strcmp(argv[d->optind], "--"))
166 {
167 d->optind++;
168 if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
169 exchange_a((char **) argv, d);
170 else if (d->__first_nonopt == d->__last_nonopt)
171 d->__first_nonopt = d->optind;
172 d->__last_nonopt = argc;
173 d->optind = argc;
174 }
175 if (d->optind == argc)
176 {
177 if (d->__first_nonopt != d->__last_nonopt)
178 d->optind = d->__first_nonopt;
179 return -1;
180 }
181 if ((argv[d->optind][0] != '-' || argv[d->optind][1] == '\0'))
182 {
183 if (d->__ordering == REQUIRE_ORDER)
184 return -1;
185 d->optarg = argv[d->optind++];
186 return 1;
187 }
188 d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == '-'));
189 }
190 if (longopts != NULL && (argv[d->optind][1] == '-' || (long_only && (argv[d->optind][2] || !strchr(optstring, argv[d->optind][1])))))
191 {
192 char *nameend;
193 unsigned int namelen;
194 const struct option_a *p;
195 const struct option_a *pfound = NULL;
196 struct option_list
197 {
198 const struct option_a *p;
199 struct option_list *next;
200 } *ambig_list = NULL;
201 int exact = 0;
202 int indfound = -1;
203 int option_index;
204 for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++);
205 namelen = (unsigned int)(nameend - d->__nextchar);
206 for (p = longopts, option_index = 0; p->name; p++, option_index++)
207 if (!strncmp(p->name, d->__nextchar, namelen))
208 {
209 if (namelen == (unsigned int)strlen(p->name))
210 {
211 pfound = p;
212 indfound = option_index;
213 exact = 1;
214 break;
215 }
216 else if (pfound == NULL)
217 {
218 pfound = p;
219 indfound = option_index;
220 }
221 else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
222 {
223 struct option_list *newp = (struct option_list*)alloca(sizeof(*newp));
224 newp->p = p;
225 newp->next = ambig_list;
226 ambig_list = newp;
227 }
228 }
229 if (ambig_list != NULL && !exact)
230 {
231 if (print_errors)
232 {
233 struct option_list first;
234 first.p = pfound;
235 first.next = ambig_list;
236 ambig_list = &first;
237 fprintf (stderr, "%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]);
238 do
239 {
240 fprintf (stderr, " '--%s'", ambig_list->p->name);
241 ambig_list = ambig_list->next;
242 }
243 while (ambig_list != NULL);
244 fputc ('\n', stderr);
245 }
246 d->__nextchar += strlen(d->__nextchar);
247 d->optind++;
248 d->optopt = 0;
249 return '?';
250 }
251 if (pfound != NULL)
252 {
253 option_index = indfound;
254 d->optind++;
255 if (*nameend)
256 {
257 if (pfound->has_arg)
258 d->optarg = nameend + 1;
259 else
260 {
261 if (print_errors)
262 {
263 if (argv[d->optind - 1][1] == '-')
264 {
265 fprintf(stderr, "%s: option '--%s' doesn't allow an argument\n",argv[0], pfound->name);
266 }
267 else
268 {
269 fprintf(stderr, "%s: option '%c%s' doesn't allow an argument\n",argv[0], argv[d->optind - 1][0],pfound->name);
270 }
271 }
272 d->__nextchar += strlen(d->__nextchar);
273 d->optopt = pfound->val;
274 return '?';
275 }
276 }
277 else if (pfound->has_arg == 1)
278 {
279 if (d->optind < argc)
280 d->optarg = argv[d->optind++];
281 else
282 {
283 if (print_errors)
284 {
285 fprintf(stderr,"%s: option '--%s' requires an argument\n",argv[0], pfound->name);
286 }
287 d->__nextchar += strlen(d->__nextchar);
288 d->optopt = pfound->val;
289 return optstring[0] == ':' ? ':' : '?';
290 }
291 }
292 d->__nextchar += strlen(d->__nextchar);
293 if (longind != NULL)
294 *longind = option_index;
295 if (pfound->flag)
296 {
297 *(pfound->flag) = pfound->val;
298 return 0;
299 }
300 return pfound->val;
301 }
302 if (!long_only || argv[d->optind][1] == '-' || strchr(optstring, *d->__nextchar) == NULL)
303 {
304 if (print_errors)
305 {
306 if (argv[d->optind][1] == '-')
307 {
308 fprintf(stderr, "%s: unrecognized option '--%s'\n",argv[0], d->__nextchar);
309 }
310 else
311 {
312 fprintf(stderr, "%s: unrecognized option '%c%s'\n",argv[0], argv[d->optind][0], d->__nextchar);
313 }
314 }
315 d->__nextchar = (char *)"";
316 d->optind++;
317 d->optopt = 0;
318 return '?';
319 }
320 }
321 {
322 char c = *d->__nextchar++;
323 char *temp = (char*)strchr(optstring, c);
324 if (*d->__nextchar == '\0')
325 ++d->optind;
326 if (temp == NULL || c == ':' || c == ';')
327 {
328 if (print_errors)
329 {
330 fprintf(stderr, "%s: invalid option -- '%c'\n", argv[0], c);
331 }
332 d->optopt = c;
333 return '?';
334 }
335 if (temp[0] == 'W' && temp[1] == ';')
336 {
337 char *nameend;
338 const struct option_a *p;
339 const struct option_a *pfound = NULL;
340 int exact = 0;
341 int ambig = 0;
342 int indfound = 0;
343 int option_index;
344 if (longopts == NULL)
345 goto no_longs;
346 if (*d->__nextchar != '\0')
347 {
348 d->optarg = d->__nextchar;
349 d->optind++;
350 }
351 else if (d->optind == argc)
352 {
353 if (print_errors)
354 {
355 fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c);
356 }
357 d->optopt = c;
358 if (optstring[0] == ':')
359 c = ':';
360 else
361 c = '?';
362 return c;
363 }
364 else
365 d->optarg = argv[d->optind++];
366 for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; nameend++);
367 for (p = longopts, option_index = 0; p->name; p++, option_index++)
368 if (!strncmp(p->name, d->__nextchar, nameend - d->__nextchar))
369 {
370 if ((unsigned int) (nameend - d->__nextchar) == strlen(p->name))
371 {
372 pfound = p;
373 indfound = option_index;
374 exact = 1;
375 break;
376 }
377 else if (pfound == NULL)
378 {
379 pfound = p;
380 indfound = option_index;
381 }
382 else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
383 ambig = 1;
384 }
385 if (ambig && !exact)
386 {
387 if (print_errors)
388 {
389 fprintf(stderr, "%s: option '-W %s' is ambiguous\n",argv[0], d->optarg);
390 }
391 d->__nextchar += strlen(d->__nextchar);
392 d->optind++;
393 return '?';
394 }
395 if (pfound != NULL)
396 {
397 option_index = indfound;
398 if (*nameend)
399 {
400 if (pfound->has_arg)
401 d->optarg = nameend + 1;
402 else
403 {
404 if (print_errors)
405 {
406 fprintf(stderr, "%s: option '-W %s' doesn't allow an argument\n",argv[0], pfound->name);
407 }
408 d->__nextchar += strlen(d->__nextchar);
409 return '?';
410 }
411 }
412 else if (pfound->has_arg == 1)
413 {
414 if (d->optind < argc)
415 d->optarg = argv[d->optind++];
416 else
417 {
418 if (print_errors)
419 {
420 fprintf(stderr, "%s: option '-W %s' requires an argument\n",argv[0], pfound->name);
421 }
422 d->__nextchar += strlen(d->__nextchar);
423 return optstring[0] == ':' ? ':' : '?';
424 }
425 }
426 else
427 d->optarg = NULL;
428 d->__nextchar += strlen(d->__nextchar);
429 if (longind != NULL)
430 *longind = option_index;
431 if (pfound->flag)
432 {
433 *(pfound->flag) = pfound->val;
434 return 0;
435 }
436 return pfound->val;
437 }
438 no_longs:
439 d->__nextchar = NULL;
440 return 'W';
441 }
442 if (temp[1] == ':')
443 {
444 if (temp[2] == ':')
445 {
446 if (*d->__nextchar != '\0')
447 {
448 d->optarg = d->__nextchar;
449 d->optind++;
450 }
451 else
452 d->optarg = NULL;
453 d->__nextchar = NULL;
454 }
455 else
456 {
457 if (*d->__nextchar != '\0')
458 {
459 d->optarg = d->__nextchar;
460 d->optind++;
461 }
462 else if (d->optind == argc)
463 {
464 if (print_errors)
465 {
466 fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c);
467 }
468 d->optopt = c;
469 if (optstring[0] == ':')
470 c = ':';
471 else
472 c = '?';
473 }
474 else
475 d->optarg = argv[d->optind++];
476 d->__nextchar = NULL;
477 }
478 }
479 return c;
480 }
481 }
_getopt_internal_a(int argc,char * const * argv,const char * optstring,const struct option_a * longopts,int * longind,int long_only,int posixly_correct)482 int _getopt_internal_a (int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, int posixly_correct)
483 {
484 int result;
485 getopt_data_a.optind = optind;
486 getopt_data_a.opterr = opterr;
487 result = _getopt_internal_r_a (argc, argv, optstring, longopts,longind, long_only, &getopt_data_a,posixly_correct);
488 optind = getopt_data_a.optind;
489 optarg_a = getopt_data_a.optarg;
490 optopt = getopt_data_a.optopt;
491 return result;
492 }
getopt_a(int argc,char * const * argv,const char * optstring)493 int getopt_a (int argc, char *const *argv, const char *optstring) _GETOPT_THROW
494 {
495 return _getopt_internal_a (argc, argv, optstring, (const struct option_a *) 0, (int *) 0, 0, 0);
496 }
getopt_long_a(int argc,char * const * argv,const char * options,const struct option_a * long_options,int * opt_index)497 int getopt_long_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW
498 {
499 return _getopt_internal_a (argc, argv, options, long_options, opt_index, 0, 0);
500 }
getopt_long_only_a(int argc,char * const * argv,const char * options,const struct option_a * long_options,int * opt_index)501 int getopt_long_only_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW
502 {
503 return _getopt_internal_a (argc, argv, options, long_options, opt_index, 1, 0);
504 }
_getopt_long_r_a(int argc,char * const * argv,const char * options,const struct option_a * long_options,int * opt_index,struct _getopt_data_a * d)505 int _getopt_long_r_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d)
506 {
507 return _getopt_internal_r_a (argc, argv, options, long_options, opt_index,0, d, 0);
508 }
_getopt_long_only_r_a(int argc,char * const * argv,const char * options,const struct option_a * long_options,int * opt_index,struct _getopt_data_a * d)509 int _getopt_long_only_r_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d)
510 {
511 return _getopt_internal_r_a (argc, argv, options, long_options, opt_index, 1, d, 0);
512 }
513
514