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 
25 **DISCLAIMER**
26 THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
27 EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE
28 IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
29 PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE
30 EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT
31 APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY
32 DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY
33 USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST
34 PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON
35 YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE
36 EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
37 */
38 #define _CRT_SECURE_NO_WARNINGS
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <malloc.h>
42 #include "getopt.h"
43 
44 #ifdef __cplusplus
45 	#define _GETOPT_THROW throw()
46 #else
47 	#define _GETOPT_THROW
48 #endif
49 
50 int optind = 1;
51 int opterr = 1;
52 int optopt = '?';
53 enum ENUM_ORDERING { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER };
54 
55 //
56 //
57 //		Ansi structures and functions follow
58 //
59 //
60 
61 static struct _getopt_data_a
62 {
63 	int optind;
64 	int opterr;
65 	int optopt;
66 	char *optarg;
67 	int __initialized;
68 	char *__nextchar;
69 	enum ENUM_ORDERING __ordering;
70 	int __posixly_correct;
71 	int __first_nonopt;
72 	int __last_nonopt;
73 } getopt_data_a;
74 char *optarg_a;
75 
exchange_a(char ** argv,struct _getopt_data_a * d)76 static void exchange_a(char **argv, struct _getopt_data_a *d)
77 {
78 	int bottom = d->__first_nonopt;
79 	int middle = d->__last_nonopt;
80 	int top = d->optind;
81 	char *tem;
82 	while (top > middle && middle > bottom)
83 	{
84 		if (top - middle > middle - bottom)
85 		{
86 			int len = middle - bottom;
87 			for (int 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 			for (int i = 0; i < len; i++)
99 			{
100 				tem = argv[bottom + i];
101 				argv[bottom + i] = argv[middle + i];
102 				argv[middle + i] = tem;
103 			}
104 			bottom += len;
105 		}
106 	}
107 	d->__first_nonopt += (d->optind - d->__last_nonopt);
108 	d->__last_nonopt = d->optind;
109 }
_getopt_initialize_a(const char * optstring,struct _getopt_data_a * d,int posixly_correct)110 static const char *_getopt_initialize_a (const char *optstring, struct _getopt_data_a *d, int posixly_correct)
111 {
112 	d->__first_nonopt = d->__last_nonopt = d->optind;
113 	d->__nextchar = NULL;
114 	d->__posixly_correct = posixly_correct | !!getenv("POSIXLY_CORRECT");
115 	if (optstring[0] == '-')
116 	{
117 		d->__ordering = RETURN_IN_ORDER;
118 		++optstring;
119 	}
120 	else if (optstring[0] == '+')
121 	{
122 		d->__ordering = REQUIRE_ORDER;
123 		++optstring;
124 	}
125 	else if (d->__posixly_correct)
126 		d->__ordering = REQUIRE_ORDER;
127 	else
128 		d->__ordering = PERMUTE;
129 	return optstring;
130 }
_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)131 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)
132 {
133 	int print_errors = d->opterr;
134 	if (argc < 1)
135 		return -1;
136 	d->optarg = NULL;
137 	if (d->optind == 0 || !d->__initialized)
138 	{
139 		if (d->optind == 0)
140 			d->optind = 1;
141 		optstring = _getopt_initialize_a (optstring, d, posixly_correct);
142 		d->__initialized = 1;
143 	}
144 	else if (optstring[0] == '-' || optstring[0] == '+')
145 		optstring++;
146 	if (optstring[0] == ':')
147 		print_errors = 0;
148 	if (d->__nextchar == NULL || *d->__nextchar == '\0')
149 	{
150 		if (d->__last_nonopt > d->optind)
151 			d->__last_nonopt = d->optind;
152 		if (d->__first_nonopt > d->optind)
153 			d->__first_nonopt = d->optind;
154 		if (d->__ordering == PERMUTE)
155 		{
156 			if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
157 				exchange_a ((char **) argv, d);
158 			else if (d->__last_nonopt != d->optind)
159 				d->__first_nonopt = d->optind;
160 			while (d->optind < argc && (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0'))
161 				d->optind++;
162 			d->__last_nonopt = d->optind;
163 		}
164 		if (d->optind != argc && !strcmp(argv[d->optind], "--"))
165 		{
166 			d->optind++;
167 			if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
168 				exchange_a((char **) argv, d);
169 			else if (d->__first_nonopt == d->__last_nonopt)
170 				d->__first_nonopt = d->optind;
171 			d->__last_nonopt = argc;
172 			d->optind = argc;
173 		}
174 		if (d->optind == argc)
175 		{
176 			if (d->__first_nonopt != d->__last_nonopt)
177 				d->optind = d->__first_nonopt;
178 			return -1;
179 		}
180 		if ((argv[d->optind][0] != '-' || argv[d->optind][1] == '\0'))
181 		{
182 			if (d->__ordering == REQUIRE_ORDER)
183 				return -1;
184 			d->optarg = argv[d->optind++];
185 			return 1;
186 		}
187 		d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == '-'));
188 	}
189 	if (longopts != NULL && (argv[d->optind][1] == '-' || (long_only && (argv[d->optind][2] || !strchr(optstring, argv[d->optind][1])))))
190 	{
191 		char *nameend;
192 		unsigned int namelen;
193 		const struct option_a *p;
194 		const struct option_a *pfound = NULL;
195 		struct option_list
196 		{
197 			const struct option_a *p;
198 			struct option_list *next;
199 		} *ambig_list = NULL;
200 		int exact = 0;
201 		int indfound = -1;
202 		int option_index;
203 		for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++);
204 		namelen = (unsigned int)(nameend - d->__nextchar);
205 		for (p = longopts, option_index = 0; p->name; p++, option_index++)
206 			if (!strncmp(p->name, d->__nextchar, namelen))
207 			{
208 				if (namelen == (unsigned int)strlen(p->name))
209 				{
210 					pfound = p;
211 					indfound = option_index;
212 					exact = 1;
213 					break;
214 				}
215 				else if (pfound == NULL)
216 				{
217 					pfound = p;
218 					indfound = option_index;
219 				}
220 				else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
221 				{
222 					struct option_list *newp = (struct option_list*)alloca(sizeof(*newp));
223 					newp->p = p;
224 					newp->next = ambig_list;
225 					ambig_list = newp;
226 				}
227 			}
228 			if (ambig_list != NULL && !exact)
229 			{
230 				if (print_errors)
231 				{
232 					struct option_list first;
233 					first.p = pfound;
234 					first.next = ambig_list;
235 					ambig_list = &first;
236 					fprintf (stderr, "%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]);
237 					do
238 					{
239 						fprintf (stderr, " '--%s'", ambig_list->p->name);
240 						ambig_list = ambig_list->next;
241 					}
242 					while (ambig_list != NULL);
243 					fputc ('\n', stderr);
244 				}
245 				d->__nextchar += strlen(d->__nextchar);
246 				d->optind++;
247 				d->optopt = 0;
248 				return '?';
249 			}
250 			if (pfound != NULL)
251 			{
252 				option_index = indfound;
253 				d->optind++;
254 				if (*nameend)
255 				{
256 					if (pfound->has_arg)
257 						d->optarg = nameend + 1;
258 					else
259 					{
260 						if (print_errors)
261 						{
262 							if (argv[d->optind - 1][1] == '-')
263 							{
264 								fprintf(stderr, "%s: option '--%s' doesn't allow an argument\n",argv[0], pfound->name);
265 							}
266 							else
267 							{
268 								fprintf(stderr, "%s: option '%c%s' doesn't allow an argument\n",argv[0], argv[d->optind - 1][0],pfound->name);
269 							}
270 						}
271 						d->__nextchar += strlen(d->__nextchar);
272 						d->optopt = pfound->val;
273 						return '?';
274 					}
275 				}
276 				else if (pfound->has_arg == 1)
277 				{
278 					if (d->optind < argc)
279 						d->optarg = argv[d->optind++];
280 					else
281 					{
282 						if (print_errors)
283 						{
284 							fprintf(stderr,"%s: option '--%s' requires an argument\n",argv[0], pfound->name);
285 						}
286 						d->__nextchar += strlen(d->__nextchar);
287 						d->optopt = pfound->val;
288 						return optstring[0] == ':' ? ':' : '?';
289 					}
290 				}
291 				d->__nextchar += strlen(d->__nextchar);
292 				if (longind != NULL)
293 					*longind = option_index;
294 				if (pfound->flag)
295 				{
296 					*(pfound->flag) = pfound->val;
297 					return 0;
298 				}
299 				return pfound->val;
300 			}
301 			if (!long_only || argv[d->optind][1] == '-' || strchr(optstring, *d->__nextchar) == NULL)
302 			{
303 				if (print_errors)
304 				{
305 					if (argv[d->optind][1] == '-')
306 					{
307 						fprintf(stderr, "%s: unrecognized option '--%s'\n",argv[0], d->__nextchar);
308 					}
309 					else
310 					{
311 						fprintf(stderr, "%s: unrecognized option '%c%s'\n",argv[0], argv[d->optind][0], d->__nextchar);
312 					}
313 				}
314 				d->__nextchar = (char *)"";
315 				d->optind++;
316 				d->optopt = 0;
317 				return '?';
318 			}
319 	}
320 	{
321 		char c = *d->__nextchar++;
322 		char *temp = (char*)strchr(optstring, c);
323 		if (*d->__nextchar == '\0')
324 			++d->optind;
325 		if (temp == NULL || c == ':' || c == ';')
326 		{
327 			if (print_errors)
328 			{
329 				fprintf(stderr, "%s: invalid option -- '%c'\n", argv[0], c);
330 			}
331 			d->optopt = c;
332 			return '?';
333 		}
334 		if (temp[0] == 'W' && temp[1] == ';')
335 		{
336 			char *nameend;
337 			const struct option_a *p;
338 			const struct option_a *pfound = NULL;
339 			int exact = 0;
340 			int ambig = 0;
341 			int indfound = 0;
342 			int option_index;
343 			if (longopts == NULL)
344 				goto no_longs;
345 			if (*d->__nextchar != '\0')
346 			{
347 				d->optarg = d->__nextchar;
348 				d->optind++;
349 			}
350 			else if (d->optind == argc)
351 			{
352 				if (print_errors)
353 				{
354 					fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c);
355 				}
356 				d->optopt = c;
357 				if (optstring[0] == ':')
358 					c = ':';
359 				else
360 					c = '?';
361 				return c;
362 			}
363 			else
364 				d->optarg = argv[d->optind++];
365 			for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; nameend++);
366 			for (p = longopts, option_index = 0; p->name; p++, option_index++)
367 				if (!strncmp(p->name, d->__nextchar, nameend - d->__nextchar))
368 				{
369 					if ((unsigned int) (nameend - d->__nextchar) == strlen(p->name))
370 					{
371 						pfound = p;
372 						indfound = option_index;
373 						exact = 1;
374 						break;
375 					}
376 					else if (pfound == NULL)
377 					{
378 						pfound = p;
379 						indfound = option_index;
380 					}
381 					else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
382 						ambig = 1;
383 				}
384 				if (ambig && !exact)
385 				{
386 					if (print_errors)
387 					{
388 						fprintf(stderr, "%s: option '-W %s' is ambiguous\n",argv[0], d->optarg);
389 					}
390 					d->__nextchar += strlen(d->__nextchar);
391 					d->optind++;
392 					return '?';
393 				}
394 				if (pfound != NULL)
395 				{
396 					option_index = indfound;
397 					if (*nameend)
398 					{
399 						if (pfound->has_arg)
400 							d->optarg = nameend + 1;
401 						else
402 						{
403 							if (print_errors)
404 							{
405 								fprintf(stderr, "%s: option '-W %s' doesn't allow an argument\n",argv[0], pfound->name);
406 							}
407 							d->__nextchar += strlen(d->__nextchar);
408 							return '?';
409 						}
410 					}
411 					else if (pfound->has_arg == 1)
412 					{
413 						if (d->optind < argc)
414 							d->optarg = argv[d->optind++];
415 						else
416 						{
417 							if (print_errors)
418 							{
419 								fprintf(stderr, "%s: option '-W %s' requires an argument\n",argv[0], pfound->name);
420 							}
421 							d->__nextchar += strlen(d->__nextchar);
422 							return optstring[0] == ':' ? ':' : '?';
423 						}
424 					}
425 					else
426 						d->optarg = NULL;
427 					d->__nextchar += strlen(d->__nextchar);
428 					if (longind != NULL)
429 						*longind = option_index;
430 					if (pfound->flag)
431 					{
432 						*(pfound->flag) = pfound->val;
433 						return 0;
434 					}
435 					return pfound->val;
436 				}
437 no_longs:
438 				d->__nextchar = NULL;
439 				return 'W';
440 		}
441 		if (temp[1] == ':')
442 		{
443 			if (temp[2] == ':')
444 			{
445 				if (*d->__nextchar != '\0')
446 				{
447 					d->optarg = d->__nextchar;
448 					d->optind++;
449 				}
450 				else
451 					d->optarg = NULL;
452 				d->__nextchar = NULL;
453 			}
454 			else
455 			{
456 				if (*d->__nextchar != '\0')
457 				{
458 					d->optarg = d->__nextchar;
459 					d->optind++;
460 				}
461 				else if (d->optind == argc)
462 				{
463 					if (print_errors)
464 					{
465 						fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c);
466 					}
467 					d->optopt = c;
468 					if (optstring[0] == ':')
469 						c = ':';
470 					else
471 						c = '?';
472 				}
473 				else
474 					d->optarg = argv[d->optind++];
475 				d->__nextchar = NULL;
476 			}
477 		}
478 		return c;
479 	}
480 }
_getopt_internal_a(int argc,char * const * argv,const char * optstring,const struct option_a * longopts,int * longind,int long_only,int posixly_correct)481 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)
482 {
483 	int result;
484 	getopt_data_a.optind = optind;
485 	getopt_data_a.opterr = opterr;
486 	result = _getopt_internal_r_a (argc, argv, optstring, longopts,longind, long_only, &getopt_data_a,posixly_correct);
487 	optind = getopt_data_a.optind;
488 	optarg_a = getopt_data_a.optarg;
489 	optopt = getopt_data_a.optopt;
490 	return result;
491 }
getopt_a(int argc,char * const * argv,const char * optstring)492 int getopt_a (int argc, char *const *argv, const char *optstring) _GETOPT_THROW
493 {
494 	return _getopt_internal_a (argc, argv, optstring, (const struct option_a *) 0, (int *) 0, 0, 0);
495 }
getopt_long_a(int argc,char * const * argv,const char * options,const struct option_a * long_options,int * opt_index)496 int getopt_long_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW
497 {
498 	return _getopt_internal_a (argc, argv, options, long_options, opt_index, 0, 0);
499 }
getopt_long_only_a(int argc,char * const * argv,const char * options,const struct option_a * long_options,int * opt_index)500 int getopt_long_only_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW
501 {
502 	return _getopt_internal_a (argc, argv, options, long_options, opt_index, 1, 0);
503 }
_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)504 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)
505 {
506 	return _getopt_internal_r_a (argc, argv, options, long_options, opt_index,0, d, 0);
507 }
_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)508 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)
509 {
510 	return _getopt_internal_r_a (argc, argv, options, long_options, opt_index, 1, d, 0);
511 }
512 
513 //
514 //
515 //	Unicode Structures and Functions
516 //
517 //
518 
519 static struct _getopt_data_w
520 {
521 	int optind;
522 	int opterr;
523 	int optopt;
524 	wchar_t *optarg;
525 	int __initialized;
526 	wchar_t *__nextchar;
527 	enum ENUM_ORDERING __ordering;
528 	int __posixly_correct;
529 	int __first_nonopt;
530 	int __last_nonopt;
531 } getopt_data_w;
532 wchar_t *optarg_w;
533 
exchange_w(wchar_t ** argv,struct _getopt_data_w * d)534 static void exchange_w(wchar_t **argv, struct _getopt_data_w *d)
535 {
536 	int bottom = d->__first_nonopt;
537 	int middle = d->__last_nonopt;
538 	int top = d->optind;
539 	wchar_t *tem;
540 	while (top > middle && middle > bottom)
541 	{
542 		if (top - middle > middle - bottom)
543 		{
544 			int len = middle - bottom;
545 			for (int i = 0; i < len; i++)
546 			{
547 				tem = argv[bottom + i];
548 				argv[bottom + i] = argv[top - (middle - bottom) + i];
549 				argv[top - (middle - bottom) + i] = tem;
550 			}
551 			top -= len;
552 		}
553 		else
554 		{
555 			int len = top - middle;
556 			for (int i = 0; i < len; i++)
557 			{
558 				tem = argv[bottom + i];
559 				argv[bottom + i] = argv[middle + i];
560 				argv[middle + i] = tem;
561 			}
562 			bottom += len;
563 		}
564 	}
565 	d->__first_nonopt += (d->optind - d->__last_nonopt);
566 	d->__last_nonopt = d->optind;
567 }
_getopt_initialize_w(const wchar_t * optstring,struct _getopt_data_w * d,int posixly_correct)568 static const wchar_t *_getopt_initialize_w (const wchar_t *optstring, struct _getopt_data_w *d, int posixly_correct)
569 {
570 	d->__first_nonopt = d->__last_nonopt = d->optind;
571 	d->__nextchar = NULL;
572 	d->__posixly_correct = posixly_correct | !!_wgetenv(L"POSIXLY_CORRECT");
573 	if (optstring[0] == L'-')
574 	{
575 		d->__ordering = RETURN_IN_ORDER;
576 		++optstring;
577 	}
578 	else if (optstring[0] == L'+')
579 	{
580 		d->__ordering = REQUIRE_ORDER;
581 		++optstring;
582 	}
583 	else if (d->__posixly_correct)
584 		d->__ordering = REQUIRE_ORDER;
585 	else
586 		d->__ordering = PERMUTE;
587 	return optstring;
588 }
_getopt_internal_r_w(int argc,wchar_t * const * argv,const wchar_t * optstring,const struct option_w * longopts,int * longind,int long_only,struct _getopt_data_w * d,int posixly_correct)589 int _getopt_internal_r_w (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, struct _getopt_data_w *d, int posixly_correct)
590 {
591 	int print_errors = d->opterr;
592 	if (argc < 1)
593 		return -1;
594 	d->optarg = NULL;
595 	if (d->optind == 0 || !d->__initialized)
596 	{
597 		if (d->optind == 0)
598 			d->optind = 1;
599 		optstring = _getopt_initialize_w (optstring, d, posixly_correct);
600 		d->__initialized = 1;
601 	}
602 	else if (optstring[0] == L'-' || optstring[0] == L'+')
603 		optstring++;
604 	if (optstring[0] == L':')
605 		print_errors = 0;
606 	if (d->__nextchar == NULL || *d->__nextchar == L'\0')
607 	{
608 		if (d->__last_nonopt > d->optind)
609 			d->__last_nonopt = d->optind;
610 		if (d->__first_nonopt > d->optind)
611 			d->__first_nonopt = d->optind;
612 		if (d->__ordering == PERMUTE)
613 		{
614 			if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
615 				exchange_w((wchar_t **) argv, d);
616 			else if (d->__last_nonopt != d->optind)
617 				d->__first_nonopt = d->optind;
618 			while (d->optind < argc && (argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0'))
619 				d->optind++;
620 			d->__last_nonopt = d->optind;
621 		}
622 		if (d->optind != argc && !wcscmp(argv[d->optind], L"--"))
623 		{
624 			d->optind++;
625 			if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
626 				exchange_w((wchar_t **) argv, d);
627 			else if (d->__first_nonopt == d->__last_nonopt)
628 				d->__first_nonopt = d->optind;
629 			d->__last_nonopt = argc;
630 			d->optind = argc;
631 		}
632 		if (d->optind == argc)
633 		{
634 			if (d->__first_nonopt != d->__last_nonopt)
635 				d->optind = d->__first_nonopt;
636 			return -1;
637 		}
638 		if ((argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0'))
639 		{
640 			if (d->__ordering == REQUIRE_ORDER)
641 				return -1;
642 			d->optarg = argv[d->optind++];
643 			return 1;
644 		}
645 		d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == L'-'));
646 	}
647 	if (longopts != NULL && (argv[d->optind][1] == L'-' || (long_only && (argv[d->optind][2] || !wcschr(optstring, argv[d->optind][1])))))
648 	{
649 		wchar_t *nameend;
650 		unsigned int namelen;
651 		const struct option_w *p;
652 		const struct option_w *pfound = NULL;
653 		struct option_list
654 		{
655 			const struct option_w *p;
656 			struct option_list *next;
657 		} *ambig_list = NULL;
658 		int exact = 0;
659 		int indfound = -1;
660 		int option_index;
661 		for (nameend = d->__nextchar; *nameend && *nameend != L'='; nameend++);
662 		namelen = (unsigned int)(nameend - d->__nextchar);
663 		for (p = longopts, option_index = 0; p->name; p++, option_index++)
664 			if (!wcsncmp(p->name, d->__nextchar, namelen))
665 			{
666 				if (namelen == (unsigned int)wcslen(p->name))
667 				{
668 					pfound = p;
669 					indfound = option_index;
670 					exact = 1;
671 					break;
672 				}
673 				else if (pfound == NULL)
674 				{
675 					pfound = p;
676 					indfound = option_index;
677 				}
678 				else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
679 				{
680 					struct option_list *newp = (struct option_list*)alloca(sizeof(*newp));
681 					newp->p = p;
682 					newp->next = ambig_list;
683 					ambig_list = newp;
684 				}
685 			}
686 			if (ambig_list != NULL && !exact)
687 			{
688 				if (print_errors)
689 				{
690 					struct option_list first;
691 					first.p = pfound;
692 					first.next = ambig_list;
693 					ambig_list = &first;
694 					fwprintf(stderr, L"%ls: option '%ls' is ambiguous; possibilities:", argv[0], argv[d->optind]);
695 					do
696 					{
697 						fwprintf (stderr, L" '--%ls'", ambig_list->p->name);
698 						ambig_list = ambig_list->next;
699 					}
700 					while (ambig_list != NULL);
701 					fputwc (L'\n', stderr);
702 				}
703 				d->__nextchar += wcslen(d->__nextchar);
704 				d->optind++;
705 				d->optopt = 0;
706 				return L'?';
707 			}
708 			if (pfound != NULL)
709 			{
710 				option_index = indfound;
711 				d->optind++;
712 				if (*nameend)
713 				{
714 					if (pfound->has_arg)
715 						d->optarg = nameend + 1;
716 					else
717 					{
718 						if (print_errors)
719 						{
720 							if (argv[d->optind - 1][1] == L'-')
721 							{
722 								fwprintf(stderr, L"%ls: option '--%ls' doesn't allow an argument\n",argv[0], pfound->name);
723 							}
724 							else
725 							{
726 								fwprintf(stderr, L"%ls: option '%c%ls' doesn't allow an argument\n",argv[0], argv[d->optind - 1][0],pfound->name);
727 							}
728 						}
729 						d->__nextchar += wcslen(d->__nextchar);
730 						d->optopt = pfound->val;
731 						return L'?';
732 					}
733 				}
734 				else if (pfound->has_arg == 1)
735 				{
736 					if (d->optind < argc)
737 						d->optarg = argv[d->optind++];
738 					else
739 					{
740 						if (print_errors)
741 						{
742 							fwprintf(stderr,L"%ls: option '--%ls' requires an argument\n",argv[0], pfound->name);
743 						}
744 						d->__nextchar += wcslen(d->__nextchar);
745 						d->optopt = pfound->val;
746 						return optstring[0] == L':' ? L':' : L'?';
747 					}
748 				}
749 				d->__nextchar += wcslen(d->__nextchar);
750 				if (longind != NULL)
751 					*longind = option_index;
752 				if (pfound->flag)
753 				{
754 					*(pfound->flag) = pfound->val;
755 					return 0;
756 				}
757 				return pfound->val;
758 			}
759 			if (!long_only || argv[d->optind][1] == L'-' || wcschr(optstring, *d->__nextchar) == NULL)
760 			{
761 				if (print_errors)
762 				{
763 					if (argv[d->optind][1] == L'-')
764 					{
765 						fwprintf(stderr, L"%ls: unrecognized option '--%ls'\n",argv[0], d->__nextchar);
766 					}
767 					else
768 					{
769 						fwprintf(stderr, L"%ls: unrecognized option '%c%ls'\n",argv[0], argv[d->optind][0], d->__nextchar);
770 					}
771 				}
772 				d->__nextchar = (wchar_t *)L"";
773 				d->optind++;
774 				d->optopt = 0;
775 				return L'?';
776 			}
777 	}
778 	{
779 		wchar_t c = *d->__nextchar++;
780 		wchar_t *temp = (wchar_t*)wcschr(optstring, c);
781 		if (*d->__nextchar == L'\0')
782 			++d->optind;
783 		if (temp == NULL || c == L':' || c == L';')
784 		{
785 			if (print_errors)
786 			{
787 				fwprintf(stderr, L"%ls: invalid option -- '%c'\n", argv[0], c);
788 			}
789 			d->optopt = c;
790 			return L'?';
791 		}
792 		if (temp[0] == L'W' && temp[1] == L';')
793 		{
794 			wchar_t *nameend;
795 			const struct option_w *p;
796 			const struct option_w *pfound = NULL;
797 			int exact = 0;
798 			int ambig = 0;
799 			int indfound = 0;
800 			int option_index;
801 			if (longopts == NULL)
802 				goto no_longs;
803 			if (*d->__nextchar != L'\0')
804 			{
805 				d->optarg = d->__nextchar;
806 				d->optind++;
807 			}
808 			else if (d->optind == argc)
809 			{
810 				if (print_errors)
811 				{
812 					fwprintf(stderr,L"%ls: option requires an argument -- '%c'\n",argv[0], c);
813 				}
814 				d->optopt = c;
815 				if (optstring[0] == L':')
816 					c = L':';
817 				else
818 					c = L'?';
819 				return c;
820 			}
821 			else
822 				d->optarg = argv[d->optind++];
823 			for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != L'='; nameend++);
824 			for (p = longopts, option_index = 0; p->name; p++, option_index++)
825 				if (!wcsncmp(p->name, d->__nextchar, nameend - d->__nextchar))
826 				{
827 					if ((unsigned int) (nameend - d->__nextchar) == wcslen(p->name))
828 					{
829 						pfound = p;
830 						indfound = option_index;
831 						exact = 1;
832 						break;
833 					}
834 					else if (pfound == NULL)
835 					{
836 						pfound = p;
837 						indfound = option_index;
838 					}
839 					else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
840 						ambig = 1;
841 				}
842 				if (ambig && !exact)
843 				{
844 					if (print_errors)
845 					{
846 						fwprintf(stderr, L"%ls: option '-W %ls' is ambiguous\n",argv[0], d->optarg);
847 					}
848 					d->__nextchar += wcslen(d->__nextchar);
849 					d->optind++;
850 					return L'?';
851 				}
852 				if (pfound != NULL)
853 				{
854 					option_index = indfound;
855 					if (*nameend)
856 					{
857 						if (pfound->has_arg)
858 							d->optarg = nameend + 1;
859 						else
860 						{
861 							if (print_errors)
862 							{
863 								fwprintf(stderr, L"%ls: option '-W %ls' doesn't allow an argument\n",argv[0], pfound->name);
864 							}
865 							d->__nextchar += wcslen(d->__nextchar);
866 							return L'?';
867 						}
868 					}
869 					else if (pfound->has_arg == 1)
870 					{
871 						if (d->optind < argc)
872 							d->optarg = argv[d->optind++];
873 						else
874 						{
875 							if (print_errors)
876 							{
877 								fwprintf(stderr, L"%ls: option '-W %ls' requires an argument\n",argv[0], pfound->name);
878 							}
879 							d->__nextchar += wcslen(d->__nextchar);
880 							return optstring[0] == L':' ? L':' : L'?';
881 						}
882 					}
883 					else
884 						d->optarg = NULL;
885 					d->__nextchar += wcslen(d->__nextchar);
886 					if (longind != NULL)
887 						*longind = option_index;
888 					if (pfound->flag)
889 					{
890 						*(pfound->flag) = pfound->val;
891 						return 0;
892 					}
893 					return pfound->val;
894 				}
895 no_longs:
896 				d->__nextchar = NULL;
897 				return L'W';
898 		}
899 		if (temp[1] == L':')
900 		{
901 			if (temp[2] == L':')
902 			{
903 				if (*d->__nextchar != L'\0')
904 				{
905 					d->optarg = d->__nextchar;
906 					d->optind++;
907 				}
908 				else
909 					d->optarg = NULL;
910 				d->__nextchar = NULL;
911 			}
912 			else
913 			{
914 				if (*d->__nextchar != L'\0')
915 				{
916 					d->optarg = d->__nextchar;
917 					d->optind++;
918 				}
919 				else if (d->optind == argc)
920 				{
921 					if (print_errors)
922 					{
923 						fwprintf(stderr,L"%ls: option requires an argument -- '%c'\n",argv[0], c);
924 					}
925 					d->optopt = c;
926 					if (optstring[0] == L':')
927 						c = L':';
928 					else
929 						c = L'?';
930 				}
931 				else
932 					d->optarg = argv[d->optind++];
933 				d->__nextchar = NULL;
934 			}
935 		}
936 		return c;
937 	}
938 }
_getopt_internal_w(int argc,wchar_t * const * argv,const wchar_t * optstring,const struct option_w * longopts,int * longind,int long_only,int posixly_correct)939 int _getopt_internal_w (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, int posixly_correct)
940 {
941 	int result;
942 	getopt_data_w.optind = optind;
943 	getopt_data_w.opterr = opterr;
944 	result = _getopt_internal_r_w (argc, argv, optstring, longopts,longind, long_only, &getopt_data_w,posixly_correct);
945 	optind = getopt_data_w.optind;
946 	optarg_w = getopt_data_w.optarg;
947 	optopt = getopt_data_w.optopt;
948 	return result;
949 }
getopt_w(int argc,wchar_t * const * argv,const wchar_t * optstring)950 int getopt_w (int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW
951 {
952 	return _getopt_internal_w (argc, argv, optstring, (const struct option_w *) 0, (int *) 0, 0, 0);
953 }
getopt_long_w(int argc,wchar_t * const * argv,const wchar_t * options,const struct option_w * long_options,int * opt_index)954 int getopt_long_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW
955 {
956 	return _getopt_internal_w (argc, argv, options, long_options, opt_index, 0, 0);
957 }
getopt_long_only_w(int argc,wchar_t * const * argv,const wchar_t * options,const struct option_w * long_options,int * opt_index)958 int getopt_long_only_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW
959 {
960 	return _getopt_internal_w (argc, argv, options, long_options, opt_index, 1, 0);
961 }
_getopt_long_r_w(int argc,wchar_t * const * argv,const wchar_t * options,const struct option_w * long_options,int * opt_index,struct _getopt_data_w * d)962 int _getopt_long_r_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d)
963 {
964 	return _getopt_internal_r_w (argc, argv, options, long_options, opt_index,0, d, 0);
965 }
_getopt_long_only_r_w(int argc,wchar_t * const * argv,const wchar_t * options,const struct option_w * long_options,int * opt_index,struct _getopt_data_w * d)966 int _getopt_long_only_r_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d)
967 {
968 	return _getopt_internal_r_w (argc, argv, options, long_options, opt_index, 1, d, 0);
969 }
970