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