xref: /386bsd/usr/src/usr.bin/pr/getopt.c (revision a2142627)
1 /* Getopt for GNU.
2    Copyright (C) 1987, 1989, 1990 Free Software Foundation, Inc.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 1, or (at your option)
7    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 General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
17 
18 #ifdef __STDC__
19 #define CONST const
20 #else
21 #define CONST
22 #endif
23 
24 /* This version of `getopt' appears to the caller like standard Unix `getopt'
25    but it behaves differently for the user, since it allows the user
26    to intersperse the options with the other arguments.
27 
28    As `getopt' works, it permutes the elements of `argv' so that,
29    when it is done, all the options precede everything else.  Thus
30    all application programs are extended to handle flexible argument order.
31 
32    Setting the environment variable _POSIX_OPTION_ORDER disables permutation.
33    Then the behavior is completely standard.
34 
35    GNU application programs can use a third alternative mode in which
36    they can distinguish the relative order of options and other arguments.  */
37 
38 #include <stdio.h>
39 
40 /* If compiled with GNU C, use the built-in alloca */
41 #ifdef __GNUC__
42 #define alloca __builtin_alloca
43 #else /* not __GNUC__ */
44 #ifdef sparc
45 #include <alloca.h>
46 #else
47 char *alloca ();
48 #endif
49 #endif /* not __GNUC__ */
50 
51 #if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__)
52 #include <stdlib.h>
53 #include <string.h>
54 #define bcopy(s, d, n) memcpy ((d), (s), (n))
55 #define index strchr
56 #else
57 
58 #ifdef USG
59 #include <string.h>
60 #define bcopy(s, d, n) memcpy ((d), (s), (n))
61 #define index strchr
62 #else
63 #ifdef VMS
64 #include <string.h>
65 #else
66 #include <strings.h>
67 #endif
68 void bcopy ();
69 #endif
70 
71 char *getenv ();
72 char *malloc ();
73 #endif
74 
75 /* For communication from `getopt' to the caller.
76    When `getopt' finds an option that takes an argument,
77    the argument value is returned here.
78    Also, when `ordering' is RETURN_IN_ORDER,
79    each non-option ARGV-element is returned here.  */
80 
81 char *optarg = 0;
82 
83 /* Index in ARGV of the next element to be scanned.
84    This is used for communication to and from the caller
85    and for communication between successive calls to `getopt'.
86 
87    On entry to `getopt', zero means this is the first call; initialize.
88 
89    When `getopt' returns EOF, this is the index of the first of the
90    non-option elements that the caller should itself scan.
91 
92    Otherwise, `optind' communicates from one call to the next
93    how much of ARGV has been scanned so far.  */
94 
95 int optind = 0;
96 
97 /* The next char to be scanned in the option-element
98    in which the last option character we returned was found.
99    This allows us to pick up the scan where we left off.
100 
101    If this is zero, or a null string, it means resume the scan
102    by advancing to the next ARGV-element.  */
103 
104 static char *nextchar;
105 
106 /* Callers store zero here to inhibit the error message
107    for unrecognized options.  */
108 
109 int opterr = 1;
110 
111 /* Describe how to deal with options that follow non-option ARGV-elements.
112 
113    If the caller did not specify anything,
114    the default is REQUIRE_ORDER if the environment variable
115    _POSIX_OPTION_ORDER is defined, PERMUTE otherwise.
116 
117    REQUIRE_ORDER means don't recognize them as options;
118    stop option processing when the first non-option is seen.
119    This is what Unix does.
120    This mode of operation is selected by either setting the environment
121    variable _POSIX_OPTION_ORDER, or using `+' as the first character
122    of the list of option characters.
123 
124    PERMUTE is the default.  We permute the contents of ARGV as we scan,
125    so that eventually all the non-options are at the end.  This allows options
126    to be given in any order, even with programs that were not written to
127    expect this.
128 
129    RETURN_IN_ORDER is an option available to programs that were written
130    to expect options and other ARGV-elements in any order and that care about
131    the ordering of the two.  We describe each non-option ARGV-element
132    as if it were the argument of an option with character code 1.
133    Using `-' as the first character of the list of option characters
134    selects this mode of operation.
135 
136    The special argument `--' forces an end of option-scanning regardless
137    of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
138    `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
139 
140 static enum
141 {
142   REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
143 } ordering;
144 
145 /* Describe the long-named options requested by the application.
146    _GETOPT_LONG_OPTIONS is a vector of `struct option' terminated by an
147    element containing a name which is zero.
148    The field `has_arg' is 1 if the option takes an argument,
149    2 if it takes an optional argument.  */
150 
151 struct option
152 {
153   char *name;
154   int has_arg;
155   int *flag;
156   int val;
157 };
158 
159 CONST struct option *_getopt_long_options;
160 
161 int _getopt_long_only = 0;
162 
163 /* Index in _GETOPT_LONG_OPTIONS of the long-named option actually found.
164    Only valid when a long-named option was found. */
165 
166 int option_index;
167 
168 /* Handle permutation of arguments.  */
169 
170 /* Describe the part of ARGV that contains non-options that have
171    been skipped.  `first_nonopt' is the index in ARGV of the first of them;
172    `last_nonopt' is the index after the last of them.  */
173 
174 static int first_nonopt;
175 static int last_nonopt;
176 
177 /* Exchange two adjacent subsequences of ARGV.
178    One subsequence is elements [first_nonopt,last_nonopt)
179     which contains all the non-options that have been skipped so far.
180    The other is elements [last_nonopt,optind), which contains all
181     the options processed since those non-options were skipped.
182 
183    `first_nonopt' and `last_nonopt' are relocated so that they describe
184     the new indices of the non-options in ARGV after they are moved.  */
185 
186 static void
exchange(argv)187 exchange (argv)
188      char **argv;
189 {
190   int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
191   char **temp = (char **) alloca (nonopts_size);
192 
193   /* Interchange the two blocks of data in ARGV.  */
194 
195   bcopy (&argv[first_nonopt], temp, nonopts_size);
196   bcopy (&argv[last_nonopt], &argv[first_nonopt],
197 	 (optind - last_nonopt) * sizeof (char *));
198   bcopy (temp, &argv[first_nonopt + optind - last_nonopt], nonopts_size);
199 
200   /* Update records for the slots the non-options now occupy.  */
201 
202   first_nonopt += (optind - last_nonopt);
203   last_nonopt = optind;
204 }
205 
206 /* Scan elements of ARGV (whose length is ARGC) for option characters
207    given in OPTSTRING.
208 
209    If an element of ARGV starts with '-', and is not exactly "-" or "--",
210    then it is an option element.  The characters of this element
211    (aside from the initial '-') are option characters.  If `getopt'
212    is called repeatedly, it returns successively each of the option characters
213    from each of the option elements.
214 
215    If `getopt' finds another option character, it returns that character,
216    updating `optind' and `nextchar' so that the next call to `getopt' can
217    resume the scan with the following option character or ARGV-element.
218 
219    If there are no more option characters, `getopt' returns `EOF'.
220    Then `optind' is the index in ARGV of the first ARGV-element
221    that is not an option.  (The ARGV-elements have been permuted
222    so that those that are not options now come last.)
223 
224    OPTSTRING is a string containing the legitimate option characters.
225    If an option character is seen that is not listed in OPTSTRING,
226    return '?' after printing an error message.  If you set `opterr' to
227    zero, the error message is suppressed but we still return '?'.
228 
229    If a char in OPTSTRING is followed by a colon, that means it wants an arg,
230    so the following text in the same ARGV-element, or the text of the following
231    ARGV-element, is returned in `optarg'.  Two colons mean an option that
232    wants an optional arg; if there is text in the current ARGV-element,
233    it is returned in `optarg', otherwise `optarg' is set to zero.
234 
235    If OPTSTRING starts with `-' or `+', it requests different methods of
236    handling the non-option ARGV-elements.
237    See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
238 
239    Long-named options begin with `+' instead of `-'.
240    Their names may be abbreviated as long as the abbreviation is unique
241    or is an exact match for some defined option.  If they have an
242    argument, it follows the option name in the same ARGV-element, separated
243    from the option name by a `=', or else the in next ARGV-element.
244    When `getopt' finds a long-named option, it returns 0 if that option's
245    `flag' field is nonzero, the value of the option's `val' field
246    otherwise.  */
247 
248 int
getopt(argc,argv,optstring)249 getopt (argc, argv, optstring)
250      int argc;
251      char **argv;
252      CONST char *optstring;
253 {
254   optarg = 0;
255 
256   /* Initialize the internal data when the first call is made.
257      Start processing options with ARGV-element 1 (since ARGV-element 0
258      is the program name); the sequence of previously skipped
259      non-option ARGV-elements is empty.  */
260 
261   if (optind == 0)
262     {
263       first_nonopt = last_nonopt = optind = 1;
264 
265       nextchar = 0;
266 
267       /* Determine how to handle the ordering of options and nonoptions.  */
268 
269       if (optstring[0] == '-')
270 	{
271 	  ordering = RETURN_IN_ORDER;
272 	  ++optstring;
273 	}
274       else if (optstring[0] == '+')
275 	{
276 	  ordering = REQUIRE_ORDER;
277 	  ++optstring;
278 	}
279       else if (getenv ("_POSIX_OPTION_ORDER") != 0)
280 	ordering = REQUIRE_ORDER;
281       else
282 	ordering = PERMUTE;
283     }
284 
285   if (nextchar == 0 || *nextchar == 0)
286     {
287       if (ordering == PERMUTE)
288 	{
289 	  /* If we have just processed some options following some non-options,
290 	     exchange them so that the options come first.  */
291 
292 	  if (first_nonopt != last_nonopt && last_nonopt != optind)
293 	    exchange (argv);
294 	  else if (last_nonopt != optind)
295 	    first_nonopt = optind;
296 
297 	  /* Now skip any additional non-options
298 	     and extend the range of non-options previously skipped.  */
299 
300 	  while (optind < argc
301 		 && (argv[optind][0] != '-'
302 		     || argv[optind][1] == 0)
303 		 && (_getopt_long_options == 0
304 		     || argv[optind][0] != '+'
305 		     || argv[optind][1] == 0))
306 	    optind++;
307 	  last_nonopt = optind;
308 	}
309 
310       /* Special ARGV-element `--' means premature end of options.
311 	 Skip it like a null option,
312 	 then exchange with previous non-options as if it were an option,
313 	 then skip everything else like a non-option.  */
314 
315       if (optind != argc && !strcmp (argv[optind], "--"))
316 	{
317 	  optind++;
318 
319 	  if (first_nonopt != last_nonopt && last_nonopt != optind)
320 	    exchange (argv);
321 	  else if (first_nonopt == last_nonopt)
322 	    first_nonopt = optind;
323 	  last_nonopt = argc;
324 
325 	  optind = argc;
326 	}
327 
328       /* If we have done all the ARGV-elements, stop the scan
329 	 and back over any non-options that we skipped and permuted.  */
330 
331       if (optind == argc)
332 	{
333 	  /* Set the next-arg-index to point at the non-options
334 	     that we previously skipped, so the caller will digest them.  */
335 	  if (first_nonopt != last_nonopt)
336 	    optind = first_nonopt;
337 	  return EOF;
338 	}
339 
340       /* If we have come to a non-option and did not permute it,
341 	 either stop the scan or describe it to the caller and pass it by.  */
342 
343       if ((argv[optind][0] != '-' || argv[optind][1] == 0)
344 	  && (_getopt_long_options == 0
345 	      || argv[optind][0] != '+' || argv[optind][1] == 0))
346 	{
347 	  if (ordering == REQUIRE_ORDER)
348 	    return EOF;
349 	  optarg = argv[optind++];
350 	  return 1;
351 	}
352 
353       /* We have found another option-ARGV-element.
354 	 Start decoding its characters.  */
355 
356       nextchar = argv[optind] + 1;
357     }
358 
359   if (_getopt_long_options != 0
360       && (argv[optind][0] == '+'
361 	  || (_getopt_long_only && argv[optind][0] == '-'))
362     )
363     {
364       CONST struct option *p;
365       char *s = nextchar;
366       int exact = 0;
367       int ambig = 0;
368       CONST struct option *pfound = 0;
369       int indfound;
370 
371       while (*s && *s != '=')
372 	s++;
373 
374       /* Test all options for either exact match or abbreviated matches.  */
375       for (p = _getopt_long_options, option_index = 0; p->name;
376 	   p++, option_index++)
377 	if (!strncmp (p->name, nextchar, s - nextchar))
378 	  {
379 	    if (s - nextchar == strlen (p->name))
380 	      {
381 		/* Exact match found.  */
382 		pfound = p;
383 		indfound = option_index;
384 		exact = 1;
385 		break;
386 	      }
387 	    else if (pfound == 0)
388 	      {
389 		/* First nonexact match found.  */
390 		pfound = p;
391 		indfound = option_index;
392 	      }
393 	    else
394 	      /* Second nonexact match found.  */
395 	      ambig = 1;
396 	  }
397 
398       if (ambig && !exact)
399 	{
400 	  fprintf (stderr, "%s: option `%s' is ambiguous\n",
401 		   argv[0], argv[optind]);
402 	  nextchar += strlen (nextchar);
403 	  optind++;
404 	  return '?';
405 	}
406 
407       if (pfound != 0)
408 	{
409 	  option_index = indfound;
410 	  optind++;
411 	  if (*s)
412 	    {
413 	      if (pfound->has_arg > 0)
414 		optarg = s + 1;
415 	      else
416 		{
417 		  fprintf (stderr,
418 			   "%s: option `%c%s' doesn't allow an argument\n",
419 			   argv[0], argv[optind - 1][0], pfound->name);
420 		  nextchar += strlen (nextchar);
421 		  return '?';
422 		}
423 	    }
424 	  else if (pfound->has_arg == 1)
425 	    {
426 	      if (optind < argc)
427 		optarg = argv[optind++];
428 	      else
429 		{
430 		  fprintf (stderr, "%s: option `%s' requires an argument\n",
431 			   argv[0], argv[optind - 1]);
432 		  nextchar += strlen (nextchar);
433 		  return '?';
434 		}
435 	    }
436 	  nextchar += strlen (nextchar);
437 	  if (pfound->flag)
438 	    {
439 	      *(pfound->flag) = pfound->val;
440 	      return 0;
441 	    }
442 	  return pfound->val;
443 	}
444       /* Can't find it as a long option.  If this is getopt_long_only,
445 	 and the option starts with '-' and is a valid short
446 	 option, then interpret it as a short option.  Otherwise it's
447 	 an error.  */
448       if (_getopt_long_only == 0 || argv[optind][0] == '+' ||
449 	  index (optstring, *nextchar) == 0)
450 	{
451 	  if (opterr != 0)
452 	    fprintf (stderr, "%s: unrecognized option `%c%s'\n",
453 		     argv[0], argv[optind][0], nextchar);
454 	  nextchar += strlen (nextchar);
455 	  optind++;
456 	  return '?';
457 	}
458     }
459 
460   /* Look at and handle the next option-character.  */
461 
462   {
463     char c = *nextchar++;
464     char *temp = index (optstring, c);
465 
466     /* Increment `optind' when we start to process its last character.  */
467     if (*nextchar == 0)
468       optind++;
469 
470     if (temp == 0 || c == ':')
471       {
472 	if (opterr != 0)
473 	  {
474 	    if (c < 040 || c >= 0177)
475 	      fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
476 		       argv[0], c);
477 	    else
478 	      fprintf (stderr, "%s: unrecognized option `-%c'\n",
479 		       argv[0], c);
480 	  }
481 	return '?';
482       }
483     if (temp[1] == ':')
484       {
485 	if (temp[2] == ':')
486 	  {
487 	    /* This is an option that accepts an argument optionally.  */
488 	    if (*nextchar != 0)
489 	      {
490 		optarg = nextchar;
491 		optind++;
492 	      }
493 	    else
494 	      optarg = 0;
495 	    nextchar = 0;
496 	  }
497 	else
498 	  {
499 	    /* This is an option that requires an argument.  */
500 	    if (*nextchar != 0)
501 	      {
502 		optarg = nextchar;
503 		/* If we end this ARGV-element by taking the rest as an arg,
504 		   we must advance to the next element now.  */
505 		optind++;
506 	      }
507 	    else if (optind == argc)
508 	      {
509 		if (opterr != 0)
510 		  fprintf (stderr, "%s: option `-%c' requires an argument\n",
511 			   argv[0], c);
512 		c = '?';
513 	      }
514 	    else
515 	      /* We already incremented `optind' once;
516 		 increment it again when taking next ARGV-elt as argument.  */
517 	      optarg = argv[optind++];
518 	    nextchar = 0;
519 	  }
520       }
521     return c;
522   }
523 }
524 
525 #ifdef TEST
526 
527 /* Compile with -DTEST to make an executable for use in testing
528    the above definition of `getopt'.  */
529 
530 int
main(argc,argv)531 main (argc, argv)
532      int argc;
533      char **argv;
534 {
535   int c;
536   int digit_optind = 0;
537 
538   while (1)
539     {
540       int this_option_optind = optind ? optind : 1;
541 
542       c = getopt (argc, argv, "abc:d:0123456789");
543       if (c == EOF)
544 	break;
545 
546       switch (c)
547 	{
548 	case '0':
549 	case '1':
550 	case '2':
551 	case '3':
552 	case '4':
553 	case '5':
554 	case '6':
555 	case '7':
556 	case '8':
557 	case '9':
558 	  if (digit_optind != 0 && digit_optind != this_option_optind)
559 	    printf ("digits occur in two different argv-elements.\n");
560 	  digit_optind = this_option_optind;
561 	  printf ("option %c\n", c);
562 	  break;
563 
564 	case 'a':
565 	  printf ("option a\n");
566 	  break;
567 
568 	case 'b':
569 	  printf ("option b\n");
570 	  break;
571 
572 	case 'c':
573 	  printf ("option c with value `%s'\n", optarg);
574 	  break;
575 
576 	case '?':
577 	  break;
578 
579 	default:
580 	  printf ("?? getopt returned character code 0%o ??\n", c);
581 	}
582     }
583 
584   if (optind < argc)
585     {
586       printf ("non-option ARGV-elements: ");
587       while (optind < argc)
588 	printf ("%s ", argv[optind++]);
589       printf ("\n");
590     }
591 
592   exit (0);
593 }
594 
595 #endif /* TEST */
596