home *** CD-ROM | disk | FTP | other *** search
- /* Getopt for GNU. Heavily modified by Frank Whaley
- Copyright (C) 1987 Free Software Foundation, Inc.
-
- NO WARRANTY
-
- BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
- NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT
- WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
- RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
- WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
- BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY
- AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
- DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
- CORRECTION.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
- STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
- WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
- LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
- OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
- USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
- DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
- A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
- PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
- DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
-
- GENERAL PUBLIC LICENSE TO COPY
-
- 1. You may copy and distribute verbatim copies of this source file
- as you receive it, in any medium, provided that you conspicuously and
- appropriately publish on each copy a valid copyright notice "Copyright
- (C) 1987 Free Software Foundation, Inc."; and include following the
- copyright notice a verbatim copy of the above disclaimer of warranty
- and of this License. You may charge a distribution fee for the
- physical act of transferring a copy.
-
- 2. You may modify your copy or copies of this source file or
- any portion of it, and copy and distribute such modifications under
- the terms of Paragraph 1 above, provided that you also do the following:
-
- a) cause the modified files to carry prominent notices stating
- that you changed the files and the date of any change; and
-
- b) cause the whole of any work that you distribute or publish,
- that in whole or in part contains or is a derivative of this
- program or any part thereof, to be licensed at no charge to all
- third parties on terms identical to those contained in this
- License Agreement (except that you may choose to grant more
- extensive warranty protection to third parties, at your option).
-
- c) You may charge a distribution fee for the physical act of
- transferring a copy, and you may at your option offer warranty
- protection in exchange for a fee.
-
- 3. You may copy and distribute this program or any portion of it in
- compiled, executable or object code form under the terms of Paragraphs
- 1 and 2 above provided that you do the following:
-
- a) cause each such copy to be accompanied by the
- corresponding machine-readable source code, which must
- be distributed under the terms of Paragraphs 1 and 2 above; or,
-
- b) cause each such copy to be accompanied by a
- written offer, with no time limit, to give any third party
- free (except for a nominal shipping charge) a machine readable
- copy of the corresponding source code, to be distributed
- under the terms of Paragraphs 1 and 2 above; or,
-
- c) in the case of a recipient of this program in compiled, executable
- or object code form (without the corresponding source code) you
- shall cause copies you distribute to be accompanied by a copy
- of the written offer of source code which you received along
- with the copy you received.
-
- 4. You may not copy, sublicense, distribute or transfer this program
- except as expressly provided under this License Agreement. Any attempt
- otherwise to copy, sublicense, distribute or transfer this program is void and
- your rights to use the program under this License agreement shall be
- automatically terminated. However, parties who have received computer
- software programs from you with this License Agreement will not have
- their licenses terminated so long as such parties remain in full compliance.
-
- 5. If you wish to incorporate parts of this program into other free
- programs whose distribution conditions are different, write to the Free
- Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet
- worked out a simple rule that can be stated here, but we will often permit
- this. We will be guided by the two goals of preserving the free status of
- all derivatives of our free software and of promoting the sharing and reuse of
- software.
-
-
- In other words, you are welcome to use, share and improve this program.
- You are forbidden to forbid anyone else to use, share and improve
- what you give them. Help stamp out software-hoarding! */
-
- /*
- * This version of 'getopt' appears to the caller like standard Unix
- * 'getopt' but it behaves differently for the user, since it allows
- * the user to intersperse the options with the other arguments.
- *
- * As 'getopt' works, it permutes the elements of 'argv' so that, when
- * it is done, all the options precede everything else. Thus all
- * application programs are extended to handle flexible argument order.
- *
- * Setting the environment variable _POSIX_OPTION_ORDER disables
- * permutation. Then the behavior is completely standard.
- *
- * GNU application programs can use a third alternative mode in which
- * they can distinguish the relative order of options and other
- * arguments.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <malloc.h>
-
- /*
- * For communication from 'getopt' to the caller.
- * When 'getopt' finds an option that takes an argument, the argument
- * value is returned here. Also, when 'ordering' is RETURN_IN_ORDER,
- * each non-option ARGV-element is returned here.
- */
- char *optarg = NULL;
-
- /*
- * Index in ARGV of the next element to be scanned.
- * This is used for communication to and from the caller and for
- * communication between successive calls to 'getopt'.
- *
- * On entry to 'getopt', zero means this is the first call; initialize.
- *
- * When 'getopt' returns EOF, this is the index of the first of the
- * non-option elements that the caller should itself scan.
- *
- * Otherwise, 'optind' communicates from one call to the next how much
- * of ARGV has been scanned so far.
- */
- int optind = 0;
-
- /*
- * The next char to be scanned in the option-element in which the last
- * option character we returned was found. This allows us to pick up
- * the scan where we left off.
- *
- * If this is zero, or a null string, it means resume the scan by
- * advancing to the next ARGV-element.
- */
- static char *nextChar;
-
- /*
- * Callers store zero here to inhibit the error message for
- * unrecognized options.
- */
- int opterr = 1;
-
- /*
- * Set to an option character which was unrecognized.
- */
- int optopt;
-
- /*
- * Describe how to deal with options that follow non-option ARGV-elements.
- *
- * UNSPECIFIED means the caller did not specify anything; the default
- * is then REQUIRE_ORDER if the environment variable _OPTIONS_FIRST is
- * defined, PERMUTE otherwise.
- *
- * REQUIRE_ORDER means don't recognize them as options. Stop option
- * processing when the first non-option is seen. This is what Unix does.
- *
- * PERMUTE is the default. We permute the contents of 'argv' as we scan,
- * so that eventually all the options are at the end. This allows
- * options to be given in any order, even with programs that were not
- * written to expect this.
- *
- * RETURN_IN_ORDER is an option available to programs that were written
- * to expect options and other ARGV-elements in any order and that care
- * about the ordering of the two. We describe each non-option
- * ARGV-element as if it were the argument of an option with character
- * code zero. Using '-' as the first character of the list of option
- * characters requests this mode of operation.
- *
- * The special argument '--' forces an end of option-scanning regardless
- * of the value of 'ordering'. In the case of RETURN_IN_ORDER, only
- * '--' can cause 'getopt' to return EOF with 'optind' != ARGC.
- */
- static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering;
-
- /*
- * Handle permutation of arguments.
- * Describe the part of ARGV that contains non-options that have been
- * skipped. 'firstNonOption' is the index in ARGV of the first of them;
- * 'lastNonOption' is the index after the last of them.
- */
- static int firstNonOption;
- static int lastNonOption;
-
- /*
- * Exchange two adjacent subsequences of ARGV.
- * One subsequence is elements [firstNonOption,lastNonOption) which
- * contains all the non-options that have been skipped so far. The
- * other is elements [lastNonOption,optind), which contains all the
- * options processed since those non-options were skipped.
- *
- * 'firstNonOption' and 'lastNonOption' are relocated so that they
- * describe the new indices of the non-options in ARGV after they
- * are moved.
- */
- static void
- exchange(char **argv)
- {
- int nonopts_size = (lastNonOption - firstNonOption) * sizeof(char *);
- char **temp = (char **)malloc(nonopts_size);
-
- /* interchange the two blocks of data in argv */
- memcpy(temp, &argv[firstNonOption], nonopts_size);
- memcpy(&argv[firstNonOption], &argv[lastNonOption],
- (optind - lastNonOption) * sizeof(char *));
- memcpy(&argv[firstNonOption + optind - lastNonOption], temp,
- nonopts_size);
-
- /* update records for the slots the non-options now occupy */
- firstNonOption += (optind - lastNonOption);
- lastNonOption = optind;
-
- free(temp);
- }
-
- /*
- * Scan elements of ARGV (whose length is ARGC) for option characters
- * given in OPTSTRING.
- *
- * If an element of ARGV starts with '-', and is not exactly "-" or "--",
- * then it is an option element. The characters of this element (aside
- * from the initial '-') are option characters. If 'getopt' is called
- * repeatedly, it returns successively each of theoption characters from
- * each of the option elements.
- * If 'getopt' finds another option character, it returns that character,
- * updating 'optind' and 'nextChar' so that the next call to 'getopt' can
- * resume the scan with the following option character or ARGV-element.
- *
- * If there are no more option characters, 'getopt' returns 'EOF'.
- * Then 'optind' is the index in ARGV of the first ARGV-element that is
- * not an option. (The ARGV-elements have been permuted so that those
- * that are not options now come last.)
- *
- * OPTSTRING is a string containing the legitimate option characters.
- * A colon in OPTSTRING means that the previous character is an option
- * that wants an argument. The argument is taken from the rest of the
- * current ARGV-element, or from the following ARGV-element, and
- * returned in 'optarg'.
- *
- * If an option character is seen that is not listed in OPTSTRING,
- * return '?' after printing an error message. If you set 'opterr' to
- * zero, the error message is suppressed but we still return '?'.
- *
- * If a char in OPTSTRING is followed by a colon, that means it wants
- * an arg, so the following text in the same ARGV-element, or the text
- * of the following ARGV-element, is returned in 'optarg. Two colons
- * mean an option that wants an optional arg; if there is text in the
- * current ARGV-element, it is returned in 'optarg'.
- *
- * If OPTSTRING starts with '-', it requests a different method of
- * handling the non-option ARGV-elements. See the comments about
- * RETURN_IN_ORDER, above.
- */
- int
- getopt(int argc, char **argv, char *optstring)
- {
- /*
- * Initialize the internal data when the first call is made.
- * Start processing options with ARGV-element 1 (since ARGV-element 0
- * is the program name); the sequence of previously skipped
- * non-option ARGV-elements is empty.
- */
- if ( optind == 0 )
- {
- firstNonOption = lastNonOption = optind = 1;
-
- nextChar = NULL;
-
- /*
- * Determine how to handle the ordering of options and
- * nonoptions.
- */
- if ( optstring[0] == '-' )
- ordering = RETURN_IN_ORDER;
- else if ( getenv("_POSIX_OPTION_ORDER") != NULL )
- ordering = REQUIRE_ORDER;
- else
- ordering = PERMUTE;
- }
-
- if ( (nextChar == NULL) || (*nextChar == '\0') )
- {
- if ( ordering == PERMUTE )
- {
- /*
- * If we have just processed some options following
- * some non-options, exchange them so that the
- * options come first.
- */
- if ( (firstNonOption != lastNonOption) &&
- (lastNonOption != optind) )
- exchange (argv);
- else if ( lastNonOption != optind )
- firstNonOption = optind;
-
- /*
- * Now skip any additional non-options and extend the
- * range of non-options previously skipped.
- */
- while ( (optind < argc) &&
- ((argv[optind][0] != '-') ||
- (argv[optind][1] == 0) ) )
- optind++;
- lastNonOption = optind;
- }
-
- /*
- * Special ARGV-element '--' means premature end of options.
- * Skip it like a null option, then exchange with previous
- * non-options as if it were an option, then skip everything
- * else like a non-option.
- */
- if ( (optind != argc) && !strcmp(argv[optind], "--") )
- {
- optind++;
-
- if ( (firstNonOption != lastNonOption) &&
- (lastNonOption != optind) )
- exchange(argv);
- else if ( firstNonOption == lastNonOption )
- firstNonOption = optind;
-
- lastNonOption = argc;
-
- optind = argc;
- }
-
- /*
- * If we have done all the ARGV-elements, stop the scan
- * and back over any non-options that we skipped and permuted.
- */
- if ( optind == argc )
- {
- /*
- * Set the next-arg-index to point at the non-options
- * that we previously skipped, so the caller will
- * digest them.
- */
- if ( firstNonOption != lastNonOption )
- optind = firstNonOption;
- return ( EOF );
- }
-
- /*
- * If we have come to a non-option and did not permute it,
- * either stop the scan or describe it to the caller and
- * pass it by.
- */
- if ( (argv[optind][0] != '-') || (argv[optind][1] == 0) )
- {
- if ( ordering == REQUIRE_ORDER )
- return ( EOF );
- optarg = argv[optind++];
- return ( 0 );
- }
-
- /*
- * We have found another option-ARGV-element.
- * Start decoding its characters.
- */
- nextChar = argv[optind] + 1;
- }
-
- /* look at and handle the next option-character */
- {
- char c = *nextChar++;
- char *temp = strchr(optstring, c);
-
- /* increment 'optind' when we process its last character */
- if ( *nextChar == 0 )
- optind++;
-
- if ( (temp == 0) || (c == ':') )
- {
- if ( opterr != 0 )
- {
- if ( (c < 040) || (c >= 0177) )
- fprintf(stderr, "%s: unrecognized option, character code 0%o\n",
- argv[0], c);
- else
- fprintf(stderr, "%s: unrecognized option '-%c'\n",
- argv[0], c);
- }
- optopt = c;
- return ( '?' );
- }
- if ( temp[1] == ':' )
- {
- if ( temp[2] == ':' )
- {
- /* this is an option that accepts an argument optionally */
- if ( *nextChar != 0 )
- {
- optarg = nextChar;
- optind++;
- }
- else
- optarg = 0;
- nextChar = 0;
- }
- else
- {
- /* this is an option that requires an argument */
- if ( *nextChar != 0 )
- {
- optarg = nextChar;
- /*
- * If we end this ARGV-element by
- * taking the rest as an arg, we must
- * advance to the next element now.
- */
- optind++;
- }
- else if ( optind == argc )
- {
- if ( opterr != 0 )
- fprintf(stderr, "%s: no argument for '-%c' option\n",
- argv[0], c);
- optarg = 0;
- }
- else
- /*
- * We already incremented 'optind'
- * once; increment it again when
- * taking next ARGV-elt as argument.
- */
- optarg = argv[optind++];
- nextChar = 0;
- }
- }
- return ( c );
- }
- }
-
- #ifdef TEST
- /*
- * test driver for getopt()
- */
- int
- main(int argc, char **argv)
- {
- char c;
- int digit_optind = 0;
-
- for ( ;; )
- {
- int this_option_optind = optind;
- if ( (c = getopt(argc, argv, "abc:d:0123456789")) == EOF )
- break;
-
- switch ( c )
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- if ( (digit_optind != 0) &&
- (digit_optind != this_option_optind) )
- printf("digits occur in two different argv-elements.\n");
- digit_optind = this_option_optind;
- printf("option %c\n", c);
- break;
-
- case 'a':
- printf("option a\n");
- break;
-
- case 'b':
- printf("option b\n");
- break;
-
- case 'c':
- printf("option c with value '%s'\n", optarg);
- break;
-
- case '?':
- break;
-
- default:
- printf("?? getopt returned character code 0%o ??\n", c);
- }
- }
-
- if ( optind < argc )
- {
- printf("non-option ARGV-elements: ");
- while ( optind < argc )
- printf("%s ", argv[optind++]);
- printf ("\n");
- }
-
- return ( 0 );
- }
- #endif /*TEST*/
-
- /* END of getopt.c */
-