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