1 /* Declarations for getopt.
2    Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
3 
4    This program is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public License
6    as published by the Free Software Foundation; either version 2, or
7    (at your option) any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU Library General Public License for more details.
13 
14    You should have received a copy of the GNU Library General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17 
18 // This file is part of the GNU Binutils package. Obviously, it's under
19 // the GPL. It's included for the benefit of people with extremely broken
20 // compilers, such as MSVC++, who otherwise could not compile this code.
21 
22 #define _LIBC
23 
24 #ifndef _NO_PROTO
25 #define _NO_PROTO
26 #endif
27 
28 #ifdef HAVE_CONFIG_H
29 #if defined (emacs) || defined (CONFIG_BROKETS)
30 /* We use <config.h> instead of "config.h" so that a compilation
31    using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
32    (which it would do because it found this file in $srcdir).  */
33 #include <config.h>
34 #else
35 #include "config.h"
36 #endif
37 #endif
38 
39 #ifndef __STDC__
40 #ifndef const
41 #define const
42 #endif
43 #endif
44 
45 #include <stdio.h>
46 #include <string.h>
47 
48 #if defined (_LIBC) || !defined (__GNU_LIBRARY__) || defined (__linux__)
49 #ifdef	__GNU_LIBRARY__
50 #include <stdlib.h>
51 #endif	/* GNU C library.  */
52 
53 #include "getopt.h"
54 
55 char *optarg = NULL;
56 
57 int optind = 0;
58 
59 static char *nextchar;
60 
61 int opterr = 1;
62 
63 int optopt = '?';
64 
65 static enum
66 {
67   REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
68 } ordering;
69 
70 #ifdef	__GNU_LIBRARY__
71 #include <string.h>
72 #define	my_index	strchr
73 #else
74 
75 char *getenv ();
76 
77 static char *
my_index(str,chr)78 my_index (str, chr)
79      const char *str;
80      int chr;
81 {
82   while (*str)
83     {
84       if (*str == chr)
85 	return (char *) str;
86       str++;
87     }
88   return 0;
89 }
90 
91 #ifdef __GNUC__
92 #ifndef __STDC__
93 extern int strlen (const char *);
94 #endif /* not __STDC__ */
95 #endif /* __GNUC__ */
96 
97 #endif /* not __GNU_LIBRARY__ */
98 
99 static int first_nonopt;
100 static int last_nonopt;
101 
102 static void
exchange(argv)103 exchange (argv)
104      char **argv;
105 {
106   int bottom = first_nonopt;
107   int middle = last_nonopt;
108   int top = optind;
109   char *tem;
110 
111   while (top > middle && middle > bottom)
112     {
113       if (top - middle > middle - bottom)
114 	{
115 	  int len = middle - bottom;
116 	  register int i;
117 
118 	  for (i = 0; i < len; i++)
119 	    {
120 	      tem = argv[bottom + i];
121 	      argv[bottom + i] = argv[top - (middle - bottom) + i];
122 	      argv[top - (middle - bottom) + i] = tem;
123 	    }
124 	  /* Exclude the moved bottom segment from further swapping.  */
125 	  top -= len;
126 	}
127       else
128 	{
129 	  /* Top segment is the short one.  */
130 	  int len = top - middle;
131 	  register int i;
132 
133 	  /* Swap it with the bottom part of the bottom segment.  */
134 	  for (i = 0; i < len; i++)
135 	    {
136 	      tem = argv[bottom + i];
137 	      argv[bottom + i] = argv[middle + i];
138 	      argv[middle + i] = tem;
139 	    }
140 	  /* Exclude the moved top segment from further swapping.  */
141 	  bottom += len;
142 	}
143     }
144 
145   /* Update records for the slots the non-options now occupy.  */
146 
147   first_nonopt += (optind - last_nonopt);
148   last_nonopt = optind;
149 }
150 
151 /* Initialize the internal data when the first call is made.  */
152 
153 static const char *
_getopt_initialize(optstring)154 _getopt_initialize (optstring)
155      const char *optstring;
156 {
157   first_nonopt = last_nonopt = optind = 1;
158 
159   nextchar = NULL;
160 
161   if (optstring[0] == '-')
162     {
163       ordering = RETURN_IN_ORDER;
164       ++optstring;
165     }
166   else if (optstring[0] == '+')
167     {
168       ordering = REQUIRE_ORDER;
169       ++optstring;
170     }
171   else if (getenv ("POSIXLY_CORRECT") != NULL)
172     ordering = REQUIRE_ORDER;
173   else
174     ordering = PERMUTE;
175 
176   return optstring;
177 }
178 
179 int
_getopt_internal(argc,argv,optstring,longopts,longind,long_only)180 _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
181      int argc;
182      char *const *argv;
183      const char *optstring;
184      const struct option *longopts;
185      int *longind;
186      int long_only;
187 {
188   optarg = NULL;
189 
190   if (optind == 0)
191     optstring = _getopt_initialize (optstring);
192 
193   if (argc == 0)
194     return EOF;
195 
196   if (nextchar == NULL || *nextchar == '\0')
197     {
198       /* Advance to the next ARGV-element.  */
199 
200       if (ordering == PERMUTE)
201 	{
202 	  /* If we have just processed some options following some non-options,
203 	     exchange them so that the options come first.  */
204 
205 	  if (first_nonopt != last_nonopt && last_nonopt != optind)
206 	    exchange ((char **) argv);
207 	  else if (last_nonopt != optind)
208 	    first_nonopt = optind;
209 
210 	  /* Skip any additional non-options
211 	     and extend the range of non-options previously skipped.  */
212 
213 	  while (optind < argc
214 		 && (argv[optind][0] != '-' || argv[optind][1] == '\0'))
215 	    optind++;
216 	  last_nonopt = optind;
217 	}
218 
219       if (optind != argc && !strcmp (argv[optind], "--"))
220 	{
221 	  optind++;
222 
223 	  if (first_nonopt != last_nonopt && last_nonopt != optind)
224 	    exchange ((char **) argv);
225 	  else if (first_nonopt == last_nonopt)
226 	    first_nonopt = optind;
227 	  last_nonopt = argc;
228 
229 	  optind = argc;
230 	}
231 
232       /* If we have done all the ARGV-elements, stop the scan
233 	 and back over any non-options that we skipped and permuted.  */
234 
235       if (optind == argc)
236 	{
237 	  /* Set the next-arg-index to point at the non-options
238 	     that we previously skipped, so the caller will digest them.  */
239 	  if (first_nonopt != last_nonopt)
240 	    optind = first_nonopt;
241 	  return EOF;
242 	}
243 
244       /* If we have come to a non-option and did not permute it,
245 	 either stop the scan or describe it to the caller and pass it by.  */
246 
247       if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
248 	{
249 	  if (ordering == REQUIRE_ORDER)
250 	    return EOF;
251 	  optarg = argv[optind++];
252 	  return 1;
253 	}
254 
255       /* We have found another option-ARGV-element.
256 	 Skip the initial punctuation.  */
257 
258       nextchar = (argv[optind] + 1
259 		  + (longopts != NULL && argv[optind][1] == '-'));
260     }
261 
262   if (longopts != NULL
263       && (argv[optind][1] == '-'
264 	  || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
265     {
266       char *nameend;
267       const struct option *p;
268       const struct option *pfound = NULL;
269       int exact = 0;
270       int ambig = 0;
271       int indfound;
272       int option_index;
273 
274       for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
275 	/* Do nothing.  */ ;
276 
277       /* Test all long options for either exact match
278 	 or abbreviated matches.  */
279       for (p = longopts, option_index = 0; p->name; p++, option_index++)
280 	if (!strncmp (p->name, nextchar, nameend - nextchar))
281 	  {
282 	    if (nameend - nextchar == strlen (p->name))
283 	      {
284 		/* Exact match found.  */
285 		pfound = p;
286 		indfound = option_index;
287 		exact = 1;
288 		break;
289 	      }
290 	    else if (pfound == NULL)
291 	      {
292 		/* First nonexact match found.  */
293 		pfound = p;
294 		indfound = option_index;
295 	      }
296 	    else
297 	      /* Second or later nonexact match found.  */
298 	      ambig = 1;
299 	  }
300 
301       if (ambig && !exact)
302 	{
303 	  if (opterr)
304 	    fprintf (stderr, "%s: option `%s' is ambiguous\n",
305 		     argv[0], argv[optind]);
306 	  nextchar += strlen (nextchar);
307 	  optind++;
308 	  return '?';
309 	}
310 
311       if (pfound != NULL)
312 	{
313 	  option_index = indfound;
314 	  optind++;
315 	  if (*nameend)
316 	    {
317 	      /* Don't test has_arg with >, because some C compilers don't
318 		 allow it to be used on enums.  */
319 	      if (pfound->has_arg)
320 		optarg = nameend + 1;
321 	      else
322 		{
323 		  if (opterr)
324 		    {
325 		      if (argv[optind - 1][1] == '-')
326 			/* --option */
327 			fprintf (stderr,
328 				 "%s: option `--%s' doesn't allow an argument\n",
329 				 argv[0], pfound->name);
330 		      else
331 			/* +option or -option */
332 			fprintf (stderr,
333 			     "%s: option `%c%s' doesn't allow an argument\n",
334 			     argv[0], argv[optind - 1][0], pfound->name);
335 		    }
336 		  nextchar += strlen (nextchar);
337 		  return '?';
338 		}
339 	    }
340 	  else if (pfound->has_arg == 1)
341 	    {
342 	      if (optind < argc)
343 		optarg = argv[optind++];
344 	      else
345 		{
346 		  if (opterr)
347 		    fprintf (stderr, "%s: option `%s' requires an argument\n",
348 			     argv[0], argv[optind - 1]);
349 		  nextchar += strlen (nextchar);
350 		  return optstring[0] == ':' ? ':' : '?';
351 		}
352 	    }
353 	  nextchar += strlen (nextchar);
354 	  if (longind != NULL)
355 	    *longind = option_index;
356 	  if (pfound->flag)
357 	    {
358 	      *(pfound->flag) = pfound->val;
359 	      return 0;
360 	    }
361 	  return pfound->val;
362 	}
363 
364       if (!long_only || argv[optind][1] == '-'
365 	  || my_index (optstring, *nextchar) == NULL)
366 	{
367 	  if (opterr)
368 	    {
369 	      if (argv[optind][1] == '-')
370 		/* --option */
371 		fprintf (stderr, "%s: unrecognized option `--%s'\n",
372 			 argv[0], nextchar);
373 	      else
374 		/* +option or -option */
375 		fprintf (stderr, "%s: unrecognized option `%c%s'\n",
376 			 argv[0], argv[optind][0], nextchar);
377 	    }
378 	  nextchar = (char *) "";
379 	  optind++;
380 	  return '?';
381 	}
382     }
383 
384   /* Look at and handle the next short option-character.  */
385 
386   {
387     char c = *nextchar++;
388     char *temp = my_index (optstring, c);
389 
390     /* Increment `optind' when we start to process its last character.  */
391     if (*nextchar == '\0')
392       ++optind;
393 
394     if (temp == NULL || c == ':')
395       {
396 	if (opterr)
397 	  {
398 	    /* 1003.2 specifies the format of this message.  */
399 	    fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
400 	  }
401 	optopt = c;
402 	return '?';
403       }
404     if (temp[1] == ':')
405       {
406 	if (temp[2] == ':')
407 	  {
408 	    /* This is an option that accepts an argument optionally.  */
409 	    if (*nextchar != '\0')
410 	      {
411 		optarg = nextchar;
412 		optind++;
413 	      }
414 	    else
415 	      optarg = NULL;
416 	    nextchar = NULL;
417 	  }
418 	else
419 	  {
420 	    /* This is an option that requires an argument.  */
421 	    if (*nextchar != '\0')
422 	      {
423 		optarg = nextchar;
424 		/* If we end this ARGV-element by taking the rest as an arg,
425 		   we must advance to the next element now.  */
426 		optind++;
427 	      }
428 	    else if (optind == argc)
429 	      {
430 		if (opterr)
431 		  {
432 		    /* 1003.2 specifies the format of this message.  */
433 		    fprintf (stderr, "%s: option requires an argument -- %c\n",
434 			     argv[0], c);
435 		  }
436 		optopt = c;
437 		if (optstring[0] == ':')
438 		  c = ':';
439 		else
440 		  c = '?';
441 	      }
442 	    else
443 	      /* We already incremented `optind' once;
444 		 increment it again when taking next ARGV-elt as argument.  */
445 	      optarg = argv[optind++];
446 	    nextchar = NULL;
447 	  }
448       }
449     return c;
450   }
451 }
452 
453 int
getopt(argc,argv,optstring)454 getopt (argc, argv, optstring)
455      int argc;
456      char *const *argv;
457      const char *optstring;
458 {
459   return _getopt_internal (argc, argv, optstring,
460 			   (const struct option *) 0,
461 			   (int *) 0,
462 			   0);
463 }
464 
465 #endif	/* _LIBC or not __GNU_LIBRARY__.  */
466 
467