]> wimlib.net Git - wimlib/blob - programs/wgetopt.c
wimapply.1: fix documentation for valid Windows filenames
[wimlib] / programs / wgetopt.c
1 /* 
2  * wgetopt.c:  Wide-character versions of getopt, getopt_long, and
3  * getopt_long_only.
4  *
5  * This has been modified from the original, which is
6  * Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
7  * 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
8  * 2010 Free Software Foundation, Inc.
9  *
10  * This file is free software; you can redistribute it and/or modify it under
11  * the terms of the GNU General Public License as published by the Free Software
12  * Foundation; either version 3 of the License, or (at your option) any later
13  * version.
14  *
15  * This file is distributed in the hope that it will be useful, but WITHOUT ANY
16  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * this file; if not, see http://www.gnu.org/licenses/.
21  */
22
23 #include "wgetopt.h"
24 #include <stdlib.h>
25 #include <stdio.h>
26
27 /* For communication from `getopt' to the caller.
28    When `getopt' finds an option that takes an argument,
29    the argument value is returned here.
30    Also, when `ordering' is RETURN_IN_ORDER,
31    each non-option ARGV-element is returned here.  */
32
33 wchar_t *woptarg = NULL;
34
35 /* Index in ARGV of the next element to be scanned.
36    This is used for communication to and from the caller
37    and for communication between successive calls to `getopt'.
38
39    On entry to `getopt', zero means this is the first call; initialize.
40
41    When `getopt' returns -1, this is the index of the first of the
42    non-option elements that the caller should itself scan.
43
44    Otherwise, `woptind' communicates from one call to the next
45    how much of ARGV has been scanned so far.  */
46
47 /* 1003.2 says this must be 1 before any call.  */
48 int woptind = 1;
49
50 /* Formerly, initialization of getopt depended on woptind==0, which
51    causes problems with re-calling getopt as programs generally don't
52    know that. */
53
54 int __getopt_initialized = 0;
55
56 /* The next char to be scanned in the option-element
57    in which the last option character we returned was found.
58    This allows us to pick up the scan where we left off.
59
60    If this is zero, or a null string, it means resume the scan
61    by advancing to the next ARGV-element.  */
62
63 static wchar_t *nextchar;
64
65 /* Callers store zero here to inhibit the error message
66    for unrecognized options.  */
67
68 int wopterr = 1;
69
70 /* Set to an option character which was unrecognized.
71    This must be initialized on some systems to avoid linking in the
72    system's own getopt implementation.  */
73
74 int woptopt = '?';
75
76 /* Describe how to deal with options that follow non-option ARGV-elements.
77
78    If the caller did not specify anything,
79    the default is REQUIRE_ORDER if the environment variable
80    POSIXLY_CORRECT is defined, PERMUTE otherwise.
81
82    REQUIRE_ORDER means don't recognize them as options;
83    stop option processing when the first non-option is seen.
84    This is what Unix does.
85    This mode of operation is selected by either setting the environment
86    variable POSIXLY_CORRECT, or using `+' as the first character
87    of the list of option characters.
88
89    PERMUTE is the default.  We permute the contents of ARGV as we scan,
90    so that eventually all the non-options are at the end.  This allows options
91    to be given in any order, even with programs that were not written to
92    expect this.
93
94    RETURN_IN_ORDER is an option available to programs that were written
95    to expect options and other ARGV-elements in any order and that care about
96    the ordering of the two.  We describe each non-option ARGV-element
97    as if it were the argument of an option with character code 1.
98    Using `-' as the first character of the list of option characters
99    selects this mode of operation.
100
101    The special argument `--' forces an end of option-scanning regardless
102    of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
103    `--' can cause `getopt' to return -1 with `woptind' != ARGC.  */
104
105 static enum
106 {
107   REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
108 } ordering;
109
110 /* Value of POSIXLY_CORRECT environment variable.  */
111 static char *posixly_correct;
112
113
114 /* Handle permutation of arguments.  */
115
116 /* Describe the part of ARGV that contains non-options that have
117    been skipped.  `first_nonopt' is the index in ARGV of the first of them;
118    `last_nonopt' is the index after the last of them.  */
119
120 static int first_nonopt;
121 static int last_nonopt;
122
123 /* Exchange two adjacent subsequences of ARGV.
124    One subsequence is elements [first_nonopt,last_nonopt)
125    which contains all the non-options that have been skipped so far.
126    The other is elements [last_nonopt,woptind), which contains all
127    the options processed since those non-options were skipped.
128
129    `first_nonopt' and `last_nonopt' are relocated so that they describe
130    the new indices of the non-options in ARGV after they are moved.  */
131
132 static void
133 exchange (wchar_t **argv)
134 {
135   int bottom = first_nonopt;
136   int middle = last_nonopt;
137   int top = woptind;
138   wchar_t *tem;
139
140   /* Exchange the shorter segment with the far end of the longer segment.
141      That puts the shorter segment into the right place.
142      It leaves the longer segment in the right place overall,
143      but it consists of two parts that need to be swapped next.  */
144
145   while (top > middle && middle > bottom)
146     {
147       if (top - middle > middle - bottom)
148         {
149           /* Bottom segment is the short one.  */
150           int len = middle - bottom;
151           register int i;
152
153           /* Swap it with the top part of the top segment.  */
154           for (i = 0; i < len; i++)
155             {
156               tem = argv[bottom + i];
157               argv[bottom + i] = argv[top - (middle - bottom) + i];
158               argv[top - (middle - bottom) + i] = tem;
159             }
160           /* Exclude the moved bottom segment from further swapping.  */
161           top -= len;
162         }
163       else
164         {
165           /* Top segment is the short one.  */
166           int len = top - middle;
167           register int i;
168
169           /* Swap it with the bottom part of the bottom segment.  */
170           for (i = 0; i < len; i++)
171             {
172               tem = argv[bottom + i];
173               argv[bottom + i] = argv[middle + i];
174               argv[middle + i] = tem;
175             }
176           /* Exclude the moved top segment from further swapping.  */
177           bottom += len;
178         }
179     }
180
181   /* Update records for the slots the non-options now occupy.  */
182
183   first_nonopt += (woptind - last_nonopt);
184   last_nonopt = woptind;
185 }
186
187 /* Initialize the internal data when the first call is made.  */
188
189 static const wchar_t *
190 _getopt_initialize (int argc, wchar_t *const *argv, const wchar_t *optstring)
191 {
192   /* Start processing options with ARGV-element 1 (since ARGV-element 0
193      is the program name); the sequence of previously skipped
194      non-option ARGV-elements is empty.  */
195
196   first_nonopt = last_nonopt = woptind;
197
198   nextchar = NULL;
199
200   posixly_correct = getenv ("POSIXLY_CORRECT");
201
202   /* Determine how to handle the ordering of options and nonoptions.  */
203
204   if (optstring[0] == L'-')
205     {
206       ordering = RETURN_IN_ORDER;
207       ++optstring;
208     }
209   else if (optstring[0] == L'+')
210     {
211       ordering = REQUIRE_ORDER;
212       ++optstring;
213     }
214   else if (posixly_correct != NULL)
215     ordering = REQUIRE_ORDER;
216   else
217     ordering = PERMUTE;
218
219   return optstring;
220 }
221 \f
222 /* Scan elements of ARGV (whose length is ARGC) for option characters
223    given in OPTSTRING.
224
225    If an element of ARGV starts with '-', and is not exactly "-" or "--",
226    then it is an option element.  The characters of this element
227    (aside from the initial '-') are option characters.  If `getopt'
228    is called repeatedly, it returns successively each of the option characters
229    from each of the option elements.
230
231    If `getopt' finds another option character, it returns that character,
232    updating `woptind' and `nextchar' so that the next call to `getopt' can
233    resume the scan with the following option character or ARGV-element.
234
235    If there are no more option characters, `getopt' returns -1.
236    Then `woptind' is the index in ARGV of the first ARGV-element
237    that is not an option.  (The ARGV-elements have been permuted
238    so that those that are not options now come last.)
239
240    OPTSTRING is a string containing the legitimate option characters.
241    If an option character is seen that is not listed in OPTSTRING,
242    return '?' after printing an error message.  If you set `wopterr' to
243    zero, the error message is suppressed but we still return '?'.
244
245    If a char in OPTSTRING is followed by a colon, that means it wants an arg,
246    so the following text in the same ARGV-element, or the text of the following
247    ARGV-element, is returned in `woptarg'.  Two colons mean an option that
248    wants an optional arg; if there is text in the current ARGV-element,
249    it is returned in `woptarg', otherwise `woptarg' is set to zero.
250
251    If OPTSTRING starts with `-' or `+', it requests different methods of
252    handling the non-option ARGV-elements.
253    See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
254
255    Long-named options begin with `--' instead of `-'.
256    Their names may be abbreviated as long as the abbreviation is unique
257    or is an exact match for some defined option.  If they have an
258    argument, it follows the option name in the same ARGV-element, separated
259    from the option name by a `=', or else the in next ARGV-element.
260    When `getopt' finds a long-named option, it returns 0 if that option's
261    `flag' field is nonzero, the value of the option's `val' field
262    if the `flag' field is zero.
263
264    The elements of ARGV aren't really const, because we permute them.
265    But we pretend they're const in the prototype to be compatible
266    with other systems.
267
268    LONGOPTS is a vector of `struct woption' terminated by an
269    element containing a name which is zero.
270
271    LONGIND returns the index in LONGOPT of the long-named option found.
272    It is only valid when a long-named option has been found by the most
273    recent call.
274
275    If LONG_ONLY is nonzero, '-' as well as '--' can introduce
276    long-named options.  */
277
278 static int
279 _wgetopt_internal (int argc, wchar_t *const *argv, const wchar_t *optstring,
280                   const struct woption *longopts, int *longind, int long_only)
281 {
282   woptarg = NULL;
283
284   if (woptind == 0 || !__getopt_initialized)
285     {
286       if (woptind == 0)
287         woptind = 1;    /* Don't scan ARGV[0], the program name.  */
288       optstring = _getopt_initialize (argc, argv, optstring);
289       __getopt_initialized = 1;
290     }
291
292   /* Test whether ARGV[woptind] points to a non-option argument.
293      Either it does not have option syntax, or there is an environment flag
294      from the shell indicating it is not an option.  The later information
295      is only used when the used in the GNU libc.  */
296 # define NONOPTION_P (argv[woptind][0] != L'-' || argv[woptind][1] == L'\0')
297
298   if (nextchar == NULL || *nextchar == '\0')
299     {
300       /* Advance to the next ARGV-element.  */
301
302       /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
303          moved back by the user (who may also have changed the arguments).  */
304       if (last_nonopt > woptind)
305         last_nonopt = woptind;
306       if (first_nonopt > woptind)
307         first_nonopt = woptind;
308
309       if (ordering == PERMUTE)
310         {
311           /* If we have just processed some options following some non-options,
312              exchange them so that the options come first.  */
313
314           if (first_nonopt != last_nonopt && last_nonopt != woptind)
315             exchange ((wchar_t **) argv);
316           else if (last_nonopt != woptind)
317             first_nonopt = woptind;
318
319           /* Skip any additional non-options
320              and extend the range of non-options previously skipped.  */
321
322           while (woptind < argc && NONOPTION_P)
323             woptind++;
324           last_nonopt = woptind;
325         }
326
327       /* The special ARGV-element `--' means premature end of options.
328          Skip it like a null option,
329          then exchange with previous non-options as if it were an option,
330          then skip everything else like a non-option.  */
331
332       if (woptind != argc && !wcscmp (argv[woptind], L"--"))
333         {
334           woptind++;
335
336           if (first_nonopt != last_nonopt && last_nonopt != woptind)
337             exchange ((wchar_t **) argv);
338           else if (first_nonopt == last_nonopt)
339             first_nonopt = woptind;
340           last_nonopt = argc;
341
342           woptind = argc;
343         }
344
345       /* If we have done all the ARGV-elements, stop the scan
346          and back over any non-options that we skipped and permuted.  */
347
348       if (woptind == argc)
349         {
350           /* Set the next-arg-index to point at the non-options
351              that we previously skipped, so the caller will digest them.  */
352           if (first_nonopt != last_nonopt)
353             woptind = first_nonopt;
354           return -1;
355         }
356
357       /* If we have come to a non-option and did not permute it,
358          either stop the scan or describe it to the caller and pass it by.  */
359
360       if (NONOPTION_P)
361         {
362           if (ordering == REQUIRE_ORDER)
363             return -1;
364           woptarg = argv[woptind++];
365           return 1;
366         }
367
368       /* We have found another option-ARGV-element.
369          Skip the initial punctuation.  */
370
371       nextchar = (argv[woptind] + 1
372                   + (longopts != NULL && argv[woptind][1] == L'-'));
373     }
374
375   /* Decode the current option-ARGV-element.  */
376
377   /* Check whether the ARGV-element is a long option.
378
379      If long_only and the ARGV-element has the form "-f", where f is
380      a valid short option, don't consider it an abbreviated form of
381      a long option that starts with f.  Otherwise there would be no
382      way to give the -f short option.
383
384      On the other hand, if there's a long option "fubar" and
385      the ARGV-element is "-fu", do consider that an abbreviation of
386      the long option, just like "--fu", and not "-f" with arg "u".
387
388      This distinction seems to be the most useful approach.  */
389
390   if (longopts != NULL
391       && (argv[woptind][1] == L'-'
392           || (long_only && (argv[woptind][2] || !wcschr (optstring, argv[woptind][1])))))
393     {
394       wchar_t *nameend;
395       const struct woption *p;
396       const struct woption *pfound = NULL;
397       int exact = 0;
398       int ambig = 0;
399       int indfound = -1;
400       int option_index;
401
402       for (nameend = nextchar; *nameend && *nameend != L'='; nameend++)
403         /* Do nothing.  */ ;
404
405       /* Test all long options for either exact match
406          or abbreviated matches.  */
407       for (p = longopts, option_index = 0; p->name; p++, option_index++)
408         if (!wcsncmp (p->name, nextchar, nameend - nextchar))
409           {
410             if ((unsigned int) (nameend - nextchar)
411                 == (unsigned int) wcslen (p->name))
412               {
413                 /* Exact match found.  */
414                 pfound = p;
415                 indfound = option_index;
416                 exact = 1;
417                 break;
418               }
419             else if (pfound == NULL)
420               {
421                 /* First nonexact match found.  */
422                 pfound = p;
423                 indfound = option_index;
424               }
425             else
426               /* Second or later nonexact match found.  */
427               ambig = 1;
428           }
429
430       if (ambig && !exact)
431         {
432           if (wopterr)
433             fwprintf (stderr, L"%ls: option `%ls' is ambiguous\n",
434                       argv[0], argv[woptind]);
435           nextchar += wcslen (nextchar);
436           woptind++;
437           woptopt = 0;
438           return L'?';
439         }
440
441       if (pfound != NULL)
442         {
443           option_index = indfound;
444           woptind++;
445           if (*nameend)
446             {
447               /* Don't test has_arg with >, because some C compilers don't
448                  allow it to be used on enums.  */
449               if (pfound->has_arg)
450                 woptarg = nameend + 1;
451               else
452                 {
453                   if (wopterr) {
454                    if (argv[woptind - 1][1] == L'-')
455                     /* --option */
456                     fwprintf (stderr,
457                      L"%ls: option `--%ls' doesn't allow an argument\n",
458                      argv[0], pfound->name);
459                    else
460                     /* +option or -option */
461                     fwprintf (stderr,
462                      L"%ls: option `%lc%ls' doesn't allow an argument\n",
463                      argv[0], argv[woptind - 1][0], pfound->name);
464                   }
465
466                   nextchar += wcslen (nextchar);
467
468                   woptopt = pfound->val;
469                   return L'?';
470                 }
471             }
472           else if (pfound->has_arg == 1)
473             {
474               if (woptind < argc)
475                 woptarg = argv[woptind++];
476               else
477                 {
478                   if (wopterr)
479                     fwprintf (stderr,
480                            L"%ls: option `%ls' requires an argument\n",
481                            argv[0], argv[woptind - 1]);
482                   nextchar += wcslen (nextchar);
483                   woptopt = pfound->val;
484                   return optstring[0] == L':' ? L':' : L'?';
485                 }
486             }
487           nextchar += wcslen (nextchar);
488           if (longind != NULL)
489             *longind = option_index;
490           if (pfound->flag)
491             {
492               *(pfound->flag) = pfound->val;
493               return 0;
494             }
495           return pfound->val;
496         }
497
498       /* Can't find it as a long option.  If this is not getopt_long_only,
499          or the option starts with '--' or is not a valid short
500          option, then it's an error.
501          Otherwise interpret it as a short option.  */
502       if (!long_only || argv[woptind][1] == L'-'
503           || wcschr (optstring, *nextchar) == NULL)
504         {
505           if (wopterr)
506             {
507               if (argv[woptind][1] == '-')
508                 /* --option */
509                 fwprintf (stderr, L"%ls: unrecognized option `--%ls'\n",
510                          argv[0], nextchar);
511               else
512                 /* +option or -option */
513                 fwprintf (stderr, L"%ls: unrecognized option `%lc%ls'\n",
514                          argv[0], argv[woptind][0], nextchar);
515             }
516           nextchar = (wchar_t *) L"";
517           woptind++;
518           woptopt = 0;
519           return L'?';
520         }
521     }
522
523   /* Look at and handle the next short option-character.  */
524
525   {
526     wchar_t c = *nextchar++;
527     wchar_t *temp = wcschr (optstring, c);
528
529     /* Increment `woptind' when we start to process its last character.  */
530     if (*nextchar == L'\0')
531       ++woptind;
532
533     if (temp == NULL || c == L':')
534       {
535         if (wopterr)
536           {
537             if (posixly_correct)
538               /* 1003.2 specifies the format of this message.  */
539               fwprintf (stderr, L"%ls: illegal option -- %lc\n",
540                        argv[0], c);
541             else
542               fwprintf (stderr, L"%ls: invalid option -- %lc\n",
543                        argv[0], c);
544           }
545         woptopt = c;
546         return L'?';
547       }
548     /* Convenience. Treat POSIX -W foo same as long option --foo */
549     if (temp[0] == L'W' && temp[1] == L';')
550       {
551         wchar_t *nameend;
552         const struct woption *p;
553         const struct woption *pfound = NULL;
554         int exact = 0;
555         int ambig = 0;
556         int indfound = 0;
557         int option_index;
558
559         /* This is an option that requires an argument.  */
560         if (*nextchar != L'\0')
561           {
562             woptarg = nextchar;
563             /* If we end this ARGV-element by taking the rest as an arg,
564                we must advance to the next element now.  */
565             woptind++;
566           }
567         else if (woptind == argc)
568           {
569             if (wopterr)
570               {
571                 /* 1003.2 specifies the format of this message.  */
572                 fwprintf (stderr, L"%ls: option requires an argument -- %lc\n",
573                          argv[0], c);
574               }
575             woptopt = c;
576             if (optstring[0] == L':')
577               c = L':';
578             else
579               c = L'?';
580             return c;
581           }
582         else
583           /* We already incremented `woptind' once;
584              increment it again when taking next ARGV-elt as argument.  */
585           woptarg = argv[woptind++];
586
587         /* woptarg is now the argument, see if it's in the
588            table of longopts.  */
589
590         for (nextchar = nameend = woptarg; *nameend && *nameend != L'='; nameend++)
591           /* Do nothing.  */ ;
592
593         /* Test all long options for either exact match
594            or abbreviated matches.  */
595         for (p = longopts, option_index = 0; p->name; p++, option_index++)
596           if (!wcsncmp (p->name, nextchar, nameend - nextchar))
597             {
598               if ((unsigned int) (nameend - nextchar) == wcslen (p->name))
599                 {
600                   /* Exact match found.  */
601                   pfound = p;
602                   indfound = option_index;
603                   exact = 1;
604                   break;
605                 }
606               else if (pfound == NULL)
607                 {
608                   /* First nonexact match found.  */
609                   pfound = p;
610                   indfound = option_index;
611                 }
612               else
613                 /* Second or later nonexact match found.  */
614                 ambig = 1;
615             }
616         if (ambig && !exact)
617           {
618             if (wopterr)
619               fwprintf (stderr, L"%ls: option `-W %ls' is ambiguous\n",
620                        argv[0], argv[woptind]);
621             nextchar += wcslen (nextchar);
622             woptind++;
623             return L'?';
624           }
625         if (pfound != NULL)
626           {
627             option_index = indfound;
628             if (*nameend)
629               {
630                 /* Don't test has_arg with >, because some C compilers don't
631                    allow it to be used on enums.  */
632                 if (pfound->has_arg)
633                   woptarg = nameend + 1;
634                 else
635                   {
636                     if (wopterr)
637                       fwprintf (stderr, L"\
638 %ls: option `-W %ls' doesn't allow an argument\n",
639                                argv[0], pfound->name);
640
641                     nextchar += wcslen (nextchar);
642                     return L'?';
643                   }
644               }
645             else if (pfound->has_arg == 1)
646               {
647                 if (woptind < argc)
648                   woptarg = argv[woptind++];
649                 else
650                   {
651                     if (wopterr)
652                       fwprintf (stderr,
653                                L"%ls: option `%ls' requires an argument\n",
654                                argv[0], argv[woptind - 1]);
655                     nextchar += wcslen (nextchar);
656                     return optstring[0] == L':' ? L':' : L'?';
657                   }
658               }
659             nextchar += wcslen (nextchar);
660             if (longind != NULL)
661               *longind = option_index;
662             if (pfound->flag)
663               {
664                 *(pfound->flag) = pfound->val;
665                 return 0;
666               }
667             return pfound->val;
668           }
669           nextchar = NULL;
670           return L'W';  /* Let the application handle it.   */
671       }
672     if (temp[1] == L':')
673       {
674         if (temp[2] == L':')
675           {
676             /* This is an option that accepts an argument optionally.  */
677             if (*nextchar != L'\0')
678               {
679                 woptarg = nextchar;
680                 woptind++;
681               }
682             else
683               woptarg = NULL;
684             nextchar = NULL;
685           }
686         else
687           {
688             /* This is an option that requires an argument.  */
689             if (*nextchar != L'\0')
690               {
691                 woptarg = nextchar;
692                 /* If we end this ARGV-element by taking the rest as an arg,
693                    we must advance to the next element now.  */
694                 woptind++;
695               }
696             else if (woptind == argc)
697               {
698                 if (wopterr)
699                   {
700                     /* 1003.2 specifies the format of this message.  */
701                     fwprintf (stderr,
702                              L"%ls: option requires an argument -- %lc\n",
703                              argv[0], c);
704                   }
705                 woptopt = c;
706                 if (optstring[0] == L':')
707                   c = L':';
708                 else
709                   c = L'?';
710               }
711             else
712               /* We already incremented `woptind' once;
713                  increment it again when taking next ARGV-elt as argument.  */
714               woptarg = argv[woptind++];
715             nextchar = NULL;
716           }
717       }
718     return c;
719   }
720 }
721
722 int
723 wgetopt (int argc, wchar_t *const *argv, const wchar_t *optstring)
724 {
725   return _wgetopt_internal (argc, argv, optstring,
726                             (const struct woption *) 0,
727                             (int *) 0,
728                             0);
729 }
730
731 int
732 wgetopt_long (int argc, wchar_t * const *argv, const wchar_t *options,
733               const struct woption *long_options, int *opt_index)
734 {
735   return _wgetopt_internal (argc, argv, options, long_options, opt_index, 0);
736 }
737
738 /* Like getopt_long, but '-' as well as '--' can indicate a long option.
739    If an option that starts with '-' (not '--') doesn't match a long option,
740    but does match a short option, it is parsed as a short option
741    instead.  */
742 int
743 wgetopt_long_only (int argc, wchar_t * const *argv, const wchar_t *options,
744                   const struct woption *long_options, int *opt_index)
745 {
746   return _wgetopt_internal (argc, argv, options, long_options, opt_index, 1);
747 }