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