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