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