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