1*58193Selan /*
2*58193Selan Getopt for GNU.
3*58193Selan Copyright (C) 1987, 1989 Free Software Foundation, Inc.
4*58193Selan 
5*58193Selan (Modified by Douglas C. Schmidt for use with GNU G++.)
6*58193Selan This file is part of the GNU C++ Library.  This library is free
7*58193Selan software; you can redistribute it and/or modify it under the terms of
8*58193Selan the GNU Library General Public License as published by the Free
9*58193Selan Software Foundation; either version 2 of the License, or (at your
10*58193Selan option) any later version.  This library is distributed in the hope
11*58193Selan that it will be useful, but WITHOUT ANY WARRANTY; without even the
12*58193Selan implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13*58193Selan PURPOSE.  See the GNU Library General Public License for more details.
14*58193Selan You should have received a copy of the GNU Library General Public
15*58193Selan License along with this library; if not, write to the Free Software
16*58193Selan Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
17*58193Selan */
18*58193Selan 
19*58193Selan #ifdef __GNUG__
20*58193Selan #pragma implementation
21*58193Selan #endif
22*58193Selan /* AIX requires the alloca decl to be the first thing in the file. */
23*58193Selan #ifdef __GNUC__
24*58193Selan #define alloca __builtin_alloca
25*58193Selan #elif defined(sparc)
26*58193Selan #include <alloca.h>
27*58193Selan #elif defined(_AIX)
28*58193Selan #pragma alloca
29*58193Selan #else
30*58193Selan char *alloca ();
31*58193Selan #endif
32*58193Selan #include <GetOpt.h>
33*58193Selan 
34*58193Selan char* GetOpt::nextchar = 0;
35*58193Selan int GetOpt::first_nonopt = 0;
36*58193Selan int GetOpt::last_nonopt = 0;
37*58193Selan 
38*58193Selan GetOpt::GetOpt (int argc, char **argv, const char *optstring)
39*58193Selan  :opterr (1), nargc (argc), nargv (argv), noptstring (optstring)
40*58193Selan {
41*58193Selan   /* Initialize the internal data when the first call is made.
42*58193Selan      Start processing options with ARGV-element 1 (since ARGV-element 0
43*58193Selan      is the program name); the sequence of previously skipped
44*58193Selan      non-option ARGV-elements is empty.  */
45*58193Selan 
46*58193Selan   first_nonopt = last_nonopt = optind = 1;
47*58193Selan   optarg = nextchar = 0;
48*58193Selan 
49*58193Selan   /* Determine how to handle the ordering of options and nonoptions.  */
50*58193Selan 
51*58193Selan   if (optstring[0] == '-')
52*58193Selan     ordering = RETURN_IN_ORDER;
53*58193Selan   else if (getenv ("_POSIX_OPTION_ORDER") != 0)
54*58193Selan     ordering = REQUIRE_ORDER;
55*58193Selan   else
56*58193Selan     ordering = PERMUTE;
57*58193Selan }
58*58193Selan 
59*58193Selan void
60*58193Selan GetOpt::exchange (char **argv)
61*58193Selan {
62*58193Selan   int nonopts_size
63*58193Selan     = (last_nonopt - first_nonopt) * sizeof (char *);
64*58193Selan   char **temp = (char **) alloca (nonopts_size);
65*58193Selan 
66*58193Selan   /* Interchange the two blocks of data in argv.  */
67*58193Selan 
68*58193Selan   memcpy (temp, &argv[first_nonopt], nonopts_size);
69*58193Selan   memcpy (&argv[first_nonopt], &argv[last_nonopt],
70*58193Selan          (optind - last_nonopt) * sizeof (char *));
71*58193Selan   memcpy (&argv[first_nonopt + optind - last_nonopt], temp,
72*58193Selan          nonopts_size);
73*58193Selan 
74*58193Selan   /* Update records for the slots the non-options now occupy.  */
75*58193Selan 
76*58193Selan   first_nonopt += (optind - last_nonopt);
77*58193Selan   last_nonopt = optind;
78*58193Selan }
79*58193Selan 
80*58193Selan /* Scan elements of ARGV (whose length is ARGC) for option characters
81*58193Selan    given in OPTSTRING.
82*58193Selan 
83*58193Selan    If an element of ARGV starts with '-', and is not exactly "-" or "--",
84*58193Selan    then it is an option element.  The characters of this element
85*58193Selan    (aside from the initial '-') are option characters.  If `getopt'
86*58193Selan    is called repeatedly, it returns successively each of theoption characters
87*58193Selan    from each of the option elements.
88*58193Selan 
89*58193Selan    If `getopt' finds another option character, it returns that character,
90*58193Selan    updating `optind' and `nextchar' so that the next call to `getopt' can
91*58193Selan    resume the scan with the following option character or ARGV-element.
92*58193Selan 
93*58193Selan    If there are no more option characters, `getopt' returns `EOF'.
94*58193Selan    Then `optind' is the index in ARGV of the first ARGV-element
95*58193Selan    that is not an option.  (The ARGV-elements have been permuted
96*58193Selan    so that those that are not options now come last.)
97*58193Selan 
98*58193Selan    OPTSTRING is a string containing the legitimate option characters.
99*58193Selan    A colon in OPTSTRING means that the previous character is an option
100*58193Selan    that wants an argument.  The argument is taken from the rest of the
101*58193Selan    current ARGV-element, or from the following ARGV-element,
102*58193Selan    and returned in `optarg'.
103*58193Selan 
104*58193Selan    If an option character is seen that is not listed in OPTSTRING,
105*58193Selan    return '?' after printing an error message.  If you set `opterr' to
106*58193Selan    zero, the error message is suppressed but we still return '?'.
107*58193Selan 
108*58193Selan    If a char in OPTSTRING is followed by a colon, that means it wants an arg,
109*58193Selan    so the following text in the same ARGV-element, or the text of the following
110*58193Selan    ARGV-element, is returned in `optarg.  Two colons mean an option that
111*58193Selan    wants an optional arg; if there is text in the current ARGV-element,
112*58193Selan    it is returned in `optarg'.
113*58193Selan 
114*58193Selan    If OPTSTRING starts with `-', it requests a different method of handling the
115*58193Selan    non-option ARGV-elements.  See the comments about RETURN_IN_ORDER, above.  */
116*58193Selan 
117*58193Selan int
118*58193Selan GetOpt::operator () (void)
119*58193Selan {
120*58193Selan   if (nextchar == 0 || *nextchar == 0)
121*58193Selan     {
122*58193Selan       if (ordering == PERMUTE)
123*58193Selan         {
124*58193Selan           /* If we have just processed some options following some non-options,
125*58193Selan              exchange them so that the options come first.  */
126*58193Selan 
127*58193Selan           if (first_nonopt != last_nonopt && last_nonopt != optind)
128*58193Selan             exchange (nargv);
129*58193Selan           else if (last_nonopt != optind)
130*58193Selan             first_nonopt = optind;
131*58193Selan 
132*58193Selan           /* Now skip any additional non-options
133*58193Selan              and extend the range of non-options previously skipped.  */
134*58193Selan 
135*58193Selan           while (optind < nargc
136*58193Selan                  && (nargv[optind][0] != '-'
137*58193Selan                      || nargv[optind][1] == 0))
138*58193Selan             optind++;
139*58193Selan           last_nonopt = optind;
140*58193Selan         }
141*58193Selan 
142*58193Selan       /* Special ARGV-element `--' means premature end of options.
143*58193Selan          Skip it like a null option,
144*58193Selan          then exchange with previous non-options as if it were an option,
145*58193Selan          then skip everything else like a non-option.  */
146*58193Selan 
147*58193Selan       if (optind != nargc && !strcmp (nargv[optind], "--"))
148*58193Selan         {
149*58193Selan           optind++;
150*58193Selan 
151*58193Selan           if (first_nonopt != last_nonopt && last_nonopt != optind)
152*58193Selan             exchange (nargv);
153*58193Selan           else if (first_nonopt == last_nonopt)
154*58193Selan             first_nonopt = optind;
155*58193Selan           last_nonopt = nargc;
156*58193Selan 
157*58193Selan           optind = nargc;
158*58193Selan         }
159*58193Selan 
160*58193Selan       /* If we have done all the ARGV-elements, stop the scan
161*58193Selan          and back over any non-options that we skipped and permuted.  */
162*58193Selan 
163*58193Selan       if (optind == nargc)
164*58193Selan         {
165*58193Selan           /* Set the next-arg-index to point at the non-options
166*58193Selan              that we previously skipped, so the caller will digest them.  */
167*58193Selan           if (first_nonopt != last_nonopt)
168*58193Selan             optind = first_nonopt;
169*58193Selan           return EOF;
170*58193Selan         }
171*58193Selan 
172*58193Selan       /* If we have come to a non-option and did not permute it,
173*58193Selan          either stop the scan or describe it to the caller and pass it by.  */
174*58193Selan 
175*58193Selan       if (nargv[optind][0] != '-' || nargv[optind][1] == 0)
176*58193Selan         {
177*58193Selan           if (ordering == REQUIRE_ORDER)
178*58193Selan             return EOF;
179*58193Selan           optarg = nargv[optind++];
180*58193Selan           return 0;
181*58193Selan         }
182*58193Selan 
183*58193Selan       /* We have found another option-ARGV-element.
184*58193Selan          Start decoding its characters.  */
185*58193Selan 
186*58193Selan       nextchar = nargv[optind] + 1;
187*58193Selan     }
188*58193Selan 
189*58193Selan   /* Look at and handle the next option-character.  */
190*58193Selan 
191*58193Selan   {
192*58193Selan     char c = *nextchar++;
193*58193Selan     char *temp = (char *) strchr (noptstring, c);
194*58193Selan 
195*58193Selan     /* Increment `optind' when we start to process its last character.  */
196*58193Selan     if (*nextchar == 0)
197*58193Selan       optind++;
198*58193Selan 
199*58193Selan     if (temp == 0 || c == ':')
200*58193Selan       {
201*58193Selan         if (opterr != 0)
202*58193Selan           {
203*58193Selan             if (c < 040 || c >= 0177)
204*58193Selan               fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
205*58193Selan                        nargv[0], c);
206*58193Selan             else
207*58193Selan               fprintf (stderr, "%s: unrecognized option `-%c'\n",
208*58193Selan                        nargv[0], c);
209*58193Selan           }
210*58193Selan         return '?';
211*58193Selan       }
212*58193Selan     if (temp[1] == ':')
213*58193Selan       {
214*58193Selan         if (temp[2] == ':')
215*58193Selan           {
216*58193Selan             /* This is an option that accepts an argument optionally.  */
217*58193Selan             if (*nextchar != 0)
218*58193Selan               {
219*58193Selan                 optarg = nextchar;
220*58193Selan                 optind++;
221*58193Selan               }
222*58193Selan             else
223*58193Selan               optarg = 0;
224*58193Selan             nextchar = 0;
225*58193Selan           }
226*58193Selan         else
227*58193Selan           {
228*58193Selan             /* This is an option that requires an argument.  */
229*58193Selan             if (*nextchar != 0)
230*58193Selan               {
231*58193Selan                 optarg = nextchar;
232*58193Selan                 /* If we end this ARGV-element by taking the rest as an arg,
233*58193Selan                    we must advance to the next element now.  */
234*58193Selan                 optind++;
235*58193Selan               }
236*58193Selan             else if (optind == nargc)
237*58193Selan               {
238*58193Selan                 if (opterr != 0)
239*58193Selan                   fprintf (stderr, "%s: no argument for `-%c' option\n",
240*58193Selan                            nargv[0], c);
241*58193Selan                 c = '?';
242*58193Selan               }
243*58193Selan             else
244*58193Selan               /* We already incremented `optind' once;
245*58193Selan                  increment it again when taking next ARGV-elt as argument.  */
246*58193Selan               optarg = nargv[optind++];
247*58193Selan             nextchar = 0;
248*58193Selan           }
249*58193Selan       }
250*58193Selan     return c;
251*58193Selan   }
252*58193Selan }
253