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