home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / ntcode / gnugrep / getopt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-19  |  16.5 KB  |  518 lines

  1. /* Getopt for GNU.  Heavily modified by Frank Whaley
  2.    Copyright (C) 1987 Free Software Foundation, Inc.
  3.  
  4.                NO WARRANTY
  5.  
  6.   BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
  7. NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW.  EXCEPT
  8. WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
  9. RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
  10. WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
  11. BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  12. FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
  13. AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE
  14. DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
  15. CORRECTION.
  16.  
  17.  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
  18. STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
  19. WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
  20. LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
  21. OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
  22. USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
  23. DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
  24. A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
  25. PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
  26. DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
  27.  
  28.         GENERAL PUBLIC LICENSE TO COPY
  29.  
  30.   1. You may copy and distribute verbatim copies of this source file
  31. as you receive it, in any medium, provided that you conspicuously and
  32. appropriately publish on each copy a valid copyright notice "Copyright
  33.  (C) 1987 Free Software Foundation, Inc."; and include following the
  34. copyright notice a verbatim copy of the above disclaimer of warranty
  35. and of this License.  You may charge a distribution fee for the
  36. physical act of transferring a copy.
  37.  
  38.   2. You may modify your copy or copies of this source file or
  39. any portion of it, and copy and distribute such modifications under
  40. the terms of Paragraph 1 above, provided that you also do the following:
  41.  
  42.     a) cause the modified files to carry prominent notices stating
  43.     that you changed the files and the date of any change; and
  44.  
  45.     b) cause the whole of any work that you distribute or publish,
  46.     that in whole or in part contains or is a derivative of this
  47.     program or any part thereof, to be licensed at no charge to all
  48.     third parties on terms identical to those contained in this
  49.     License Agreement (except that you may choose to grant more
  50.     extensive warranty protection to third parties, at your option).
  51.  
  52.     c) You may charge a distribution fee for the physical act of
  53.     transferring a copy, and you may at your option offer warranty
  54.     protection in exchange for a fee.
  55.  
  56.   3. You may copy and distribute this program or any portion of it in
  57. compiled, executable or object code form under the terms of Paragraphs
  58. 1 and 2 above provided that you do the following:
  59.  
  60.     a) cause each such copy to be accompanied by the
  61.     corresponding machine-readable source code, which must
  62.     be distributed under the terms of Paragraphs 1 and 2 above; or,
  63.  
  64.     b) cause each such copy to be accompanied by a
  65.     written offer, with no time limit, to give any third party
  66.     free (except for a nominal shipping charge) a machine readable
  67.     copy of the corresponding source code, to be distributed
  68.     under the terms of Paragraphs 1 and 2 above; or,
  69.  
  70.     c) in the case of a recipient of this program in compiled, executable
  71.     or object code form (without the corresponding source code) you
  72.     shall cause copies you distribute to be accompanied by a copy
  73.     of the written offer of source code which you received along
  74.     with the copy you received.
  75.  
  76.   4. You may not copy, sublicense, distribute or transfer this program
  77. except as expressly provided under this License Agreement.  Any attempt
  78. otherwise to copy, sublicense, distribute or transfer this program is void and
  79. your rights to use the program under this License agreement shall be
  80. automatically terminated.  However, parties who have received computer
  81. software programs from you with this License Agreement will not have
  82. their licenses terminated so long as such parties remain in full compliance.
  83.  
  84.   5. If you wish to incorporate parts of this program into other free
  85. programs whose distribution conditions are different, write to the Free
  86. Software Foundation at 675 Mass Ave, Cambridge, MA 02139.  We have not yet
  87. worked out a simple rule that can be stated here, but we will often permit
  88. this.  We will be guided by the two goals of preserving the free status of
  89. all derivatives of our free software and of promoting the sharing and reuse of
  90. software.
  91.  
  92.  
  93. In other words, you are welcome to use, share and improve this program.
  94. You are forbidden to forbid anyone else to use, share and improve
  95. what you give them.   Help stamp out software-hoarding!  */
  96.  
  97. /*
  98.  *    This version of 'getopt' appears to the caller like standard Unix 
  99.  *    'getopt' but it behaves differently for the user, since it allows 
  100.  *    the user to intersperse the options with the other arguments.
  101.  *
  102.  *    As 'getopt' works, it permutes the elements of 'argv' so that, when 
  103.  *    it is done, all the options precede everything else.  Thus all 
  104.  *    application programs are extended to handle flexible argument order.
  105.  *
  106.  *    Setting the environment variable _POSIX_OPTION_ORDER disables 
  107.  *    permutation.  Then the behavior is completely standard.
  108.  *
  109.  *    GNU application programs can use a third alternative mode in which 
  110.  *    they can distinguish the relative order of options and other 
  111.  *    arguments.
  112.  */
  113.  
  114. #include <stdio.h>
  115. #include <stdlib.h>
  116. #include <string.h>
  117. #include <malloc.h>
  118.  
  119. /*
  120.  *    For communication from 'getopt' to the caller.
  121.  *    When 'getopt' finds an option that takes an argument, the argument 
  122.  *    value is returned here.  Also, when 'ordering' is RETURN_IN_ORDER, 
  123.  *    each non-option ARGV-element is returned here.
  124.  */
  125. char *optarg = NULL;
  126.  
  127. /*
  128.  *    Index in ARGV of the next element to be scanned.
  129.  *    This is used for communication to and from the caller and for 
  130.  *    communication between successive calls to 'getopt'.
  131.  *
  132.  *    On entry to 'getopt', zero means this is the first call; initialize.
  133.  *
  134.  *    When 'getopt' returns EOF, this is the index of the first of the 
  135.  *    non-option elements that the caller should itself scan.
  136.  *
  137.  *    Otherwise, 'optind' communicates from one call to the next how much 
  138.  *    of ARGV has been scanned so far.
  139.  */
  140. int optind = 0;
  141.  
  142. /*
  143.  *    The next char to be scanned in the option-element in which the last 
  144.  *    option character we returned was found.  This allows us to pick up 
  145.  *    the scan where we left off.
  146.  *
  147.  *    If this is zero, or a null string, it means resume the scan by 
  148.  *    advancing to the next ARGV-element.
  149.  */
  150. static char *nextChar;
  151.  
  152. /*
  153.  *    Callers store zero here to inhibit the error message for 
  154.  *    unrecognized options.
  155.  */
  156. int opterr = 1;
  157.  
  158. /*
  159.  *    Set to an option character which was unrecognized.
  160.  */
  161. int optopt;
  162.  
  163. /*
  164.  *    Describe how to deal with options that follow non-option ARGV-elements.
  165.  *
  166.  *    UNSPECIFIED means the caller did not specify anything; the default 
  167.  *    is then REQUIRE_ORDER if the environment variable _OPTIONS_FIRST is 
  168.  *    defined, PERMUTE otherwise.
  169.  *
  170.  *    REQUIRE_ORDER means don't recognize them as options.  Stop option 
  171.  *    processing when the first non-option is seen.  This is what Unix does.
  172.  *
  173.  *    PERMUTE is the default.  We permute the contents of 'argv' as we scan, 
  174.  *    so that eventually all the options are at the end.  This allows 
  175.  *    options to be given in any order, even with programs that were not 
  176.  *    written to expect this.
  177.  *
  178.  *    RETURN_IN_ORDER is an option available to programs that were written 
  179.  *    to expect options and other ARGV-elements in any order and that care 
  180.  *    about the ordering of the two.  We describe each non-option 
  181.  *    ARGV-element as if it were the argument of an option with character 
  182.  *    code zero.  Using '-' as the first character of the list of option 
  183.  *    characters requests this mode of operation.
  184.  *
  185.  *    The special argument '--' forces an end of option-scanning regardless 
  186.  *    of the value of 'ordering'.  In the case of RETURN_IN_ORDER, only 
  187.  *    '--' can cause 'getopt' to return EOF with 'optind' != ARGC.
  188.  */
  189. static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering;
  190.  
  191. /*
  192.  *    Handle permutation of arguments.
  193.  *    Describe the part of ARGV that contains non-options that have been 
  194.  *    skipped.  'firstNonOption' is the index in ARGV of the first of them; 
  195.  *    'lastNonOption' is the index after the last of them.
  196.  */
  197. static int firstNonOption;
  198. static int lastNonOption;
  199.  
  200. /*
  201.  *    Exchange two adjacent subsequences of ARGV.
  202.  *    One subsequence is elements [firstNonOption,lastNonOption) which 
  203.  *    contains all the non-options that have been skipped so far.  The 
  204.  *    other is elements [lastNonOption,optind), which contains all the 
  205.  *    options processed since those non-options were skipped.
  206.  *
  207.  *    'firstNonOption' and 'lastNonOption' are relocated so that they 
  208.  *    describe the new indices of the non-options in ARGV after they 
  209.  *    are moved.
  210.  */
  211.     static void
  212. exchange(char **argv)
  213. {
  214.     int nonopts_size = (lastNonOption - firstNonOption) * sizeof(char *);
  215.     char **temp = (char **)malloc(nonopts_size);
  216.  
  217.     /*  interchange the two blocks of data in argv  */
  218.     memcpy(temp, &argv[firstNonOption], nonopts_size);
  219.     memcpy(&argv[firstNonOption], &argv[lastNonOption],
  220.                 (optind - lastNonOption) * sizeof(char *));
  221.     memcpy(&argv[firstNonOption + optind - lastNonOption], temp,
  222.                 nonopts_size);
  223.  
  224.     /*  update records for the slots the non-options now occupy  */
  225.     firstNonOption += (optind - lastNonOption);
  226.     lastNonOption = optind;
  227.  
  228.     free(temp);
  229. }
  230.  
  231. /*
  232.  *    Scan elements of ARGV (whose length is ARGC) for option characters 
  233.  *    given in OPTSTRING.
  234.  *
  235.  *    If an element of ARGV starts with '-', and is not exactly "-" or "--", 
  236.  *    then it is an option element.  The characters of this element (aside 
  237.  *    from the initial '-') are option characters.  If 'getopt' is called 
  238.  *    repeatedly, it returns successively each of theoption characters from 
  239.  *    each of the option elements.
  240.  *    If 'getopt' finds another option character, it returns that character, 
  241.  *    updating 'optind' and 'nextChar' so that the next call to 'getopt' can 
  242.  *    resume the scan with the following option character or ARGV-element.
  243.  *
  244.  *    If there are no more option characters, 'getopt' returns 'EOF'.  
  245.  *    Then 'optind' is the index in ARGV of the first ARGV-element that is 
  246.  *    not an option.  (The ARGV-elements have been permuted so that those 
  247.  *    that are not options now come last.)
  248.  *
  249.  *    OPTSTRING is a string containing the legitimate option characters.  
  250.  *    A colon in OPTSTRING means that the previous character is an option 
  251.  *    that wants an argument.  The argument is taken from the rest of the 
  252.  *    current ARGV-element, or from the following ARGV-element, and 
  253.  *    returned in 'optarg'.
  254.  *
  255.  *    If an option character is seen that is not listed in OPTSTRING, 
  256.  *    return '?' after printing an error message.  If you set 'opterr' to 
  257.  *    zero, the error message is suppressed but we still return '?'.
  258.  *
  259.  *    If a char in OPTSTRING is followed by a colon, that means it wants 
  260.  *    an arg, so the following text in the same ARGV-element, or the text 
  261.  *    of the following ARGV-element, is returned in 'optarg.  Two colons 
  262.  *    mean an option that wants an optional arg; if there is text in the 
  263.  *    current ARGV-element, it is returned in 'optarg'.
  264.  *
  265.  *    If OPTSTRING starts with '-', it requests a different method of 
  266.  *    handling the non-option ARGV-elements.  See the comments about 
  267.  *    RETURN_IN_ORDER, above.
  268.  */
  269.     int
  270. getopt(int argc, char **argv, char *optstring)
  271. {
  272.     /*
  273.      *  Initialize the internal data when the first call is made.
  274.      *  Start processing options with ARGV-element 1 (since ARGV-element 0
  275.      *  is the program name); the sequence of previously skipped
  276.      *  non-option ARGV-elements is empty.
  277.      */
  278.     if ( optind == 0 )
  279.     {
  280.         firstNonOption = lastNonOption = optind = 1;
  281.  
  282.         nextChar = NULL;
  283.  
  284.         /*
  285.          *  Determine how to handle the ordering of options and
  286.          *  nonoptions.
  287.          */
  288.         if ( optstring[0] == '-' )
  289.             ordering = RETURN_IN_ORDER;
  290.         else if ( getenv("_POSIX_OPTION_ORDER") != NULL )
  291.             ordering = REQUIRE_ORDER;
  292.         else
  293.             ordering = PERMUTE;
  294.     }
  295.  
  296.     if ( (nextChar == NULL) || (*nextChar == '\0') )
  297.     {
  298.         if ( ordering == PERMUTE )
  299.         {
  300.             /*
  301.              *  If we have just processed some options following
  302.              *  some non-options, exchange them so that the
  303.              *  options come first.
  304.              */
  305.             if ( (firstNonOption != lastNonOption) &&
  306.                  (lastNonOption != optind) )
  307.                 exchange (argv);
  308.             else if ( lastNonOption != optind )
  309.                 firstNonOption = optind;
  310.  
  311.             /*
  312.              *  Now skip any additional non-options and extend the
  313.              *  range of non-options previously skipped.
  314.              */
  315.             while ( (optind < argc) &&
  316.                     ((argv[optind][0] != '-') ||
  317.                      (argv[optind][1] == 0) ) )
  318.                 optind++;
  319.             lastNonOption = optind;
  320.         }
  321.  
  322.         /*
  323.          *  Special ARGV-element '--' means premature end of options.
  324.          *  Skip it like a null option, then exchange with previous
  325.          *  non-options as if it were an option, then skip everything
  326.          *  else like a non-option.
  327.          */
  328.         if ( (optind != argc) && !strcmp(argv[optind], "--") )
  329.         {
  330.             optind++;
  331.  
  332.             if ( (firstNonOption != lastNonOption) &&
  333.                  (lastNonOption != optind) )
  334.                 exchange(argv);
  335.             else if ( firstNonOption == lastNonOption )
  336.                 firstNonOption = optind;
  337.  
  338.             lastNonOption = argc;
  339.  
  340.             optind = argc;
  341.         }
  342.  
  343.         /*
  344.          *  If we have done all the ARGV-elements, stop the scan 
  345.          *  and back over any non-options that we skipped and permuted.
  346.          */
  347.         if ( optind == argc )
  348.         {
  349.             /*
  350.              *  Set the next-arg-index to point at the non-options 
  351.              *  that we previously skipped, so the caller will 
  352.              *  digest them.
  353.              */
  354.             if ( firstNonOption != lastNonOption )
  355.                 optind = firstNonOption;
  356.             return ( EOF );
  357.         }
  358.              
  359.         /*
  360.          *  If we have come to a non-option and did not permute it, 
  361.          *  either stop the scan or describe it to the caller and 
  362.          *  pass it by.
  363.          */
  364.         if ( (argv[optind][0] != '-') || (argv[optind][1] == 0) )
  365.         {
  366.             if ( ordering == REQUIRE_ORDER )
  367.                 return ( EOF );
  368.             optarg = argv[optind++];
  369.             return ( 0 );
  370.         }
  371.  
  372.         /*
  373.          *  We have found another option-ARGV-element.  
  374.          *  Start decoding its characters.
  375.          */
  376.         nextChar = argv[optind] + 1;
  377.     }
  378.  
  379.     /*  look at and handle the next option-character  */
  380.     {
  381.         char c = *nextChar++;
  382.         char *temp = strchr(optstring, c);
  383.  
  384.         /*  increment 'optind' when we process its last character  */
  385.         if ( *nextChar == 0 )
  386.             optind++;
  387.  
  388.         if ( (temp == 0) || (c == ':') )
  389.         {
  390.             if ( opterr != 0 )
  391.             {
  392.                 if ( (c < 040) || (c >= 0177) )
  393.                     fprintf(stderr, "%s: unrecognized option, character code 0%o\n",
  394.                                 argv[0], c);
  395.                 else
  396.                     fprintf(stderr, "%s: unrecognized option '-%c'\n",
  397.                                 argv[0], c);
  398.             }
  399.             optopt = c;
  400.             return ( '?' );
  401.         }
  402.         if ( temp[1] == ':' )
  403.         {
  404.             if ( temp[2] == ':' )
  405.             {
  406.                 /*  this is an option that accepts an argument optionally  */
  407.                 if ( *nextChar != 0 )
  408.                 {
  409.                     optarg = nextChar;
  410.                     optind++;
  411.                 }
  412.                 else
  413.                     optarg = 0;
  414.                 nextChar = 0;
  415.             }
  416.             else
  417.             {
  418.                 /*  this is an option that requires an argument  */
  419.                 if ( *nextChar != 0 )
  420.                 {
  421.                     optarg = nextChar;
  422.                     /*
  423.                      *  If we end this ARGV-element by 
  424.                      *  taking the rest as an arg, we must 
  425.                      *  advance to the next element now.
  426.                      */
  427.                     optind++;
  428.                 }
  429.                 else if ( optind == argc )
  430.                 {
  431.                     if ( opterr != 0 )
  432.                         fprintf(stderr, "%s: no argument for '-%c' option\n",
  433.                                 argv[0], c);
  434.                     optarg = 0;
  435.                 }
  436.                 else
  437.                     /*
  438.                      *  We already incremented 'optind' 
  439.                      *  once; increment it again when 
  440.                      *  taking next ARGV-elt as argument.
  441.                      */
  442.                     optarg = argv[optind++];
  443.                 nextChar = 0;
  444.             }
  445.         }
  446.         return ( c );
  447.     }
  448. }
  449.  
  450. #ifdef TEST
  451. /*
  452.  *    test driver for getopt()
  453.  */
  454.     int
  455. main(int argc, char **argv)
  456. {
  457.     char c;
  458.     int digit_optind = 0;
  459.  
  460.     for ( ;; )
  461.     {
  462.         int this_option_optind = optind;
  463.         if ( (c = getopt(argc, argv, "abc:d:0123456789")) == EOF )
  464.             break;
  465.  
  466.         switch ( c )
  467.         {
  468.         case '0':
  469.         case '1':
  470.         case '2':
  471.         case '3':
  472.         case '4':
  473.         case '5':
  474.         case '6':
  475.         case '7':
  476.         case '8':
  477.         case '9':
  478.             if ( (digit_optind != 0) &&
  479.                  (digit_optind != this_option_optind) )
  480.                 printf("digits occur in two different argv-elements.\n");
  481.             digit_optind = this_option_optind;
  482.             printf("option %c\n", c);
  483.             break;
  484.  
  485.         case 'a':
  486.             printf("option a\n");
  487.             break;
  488.  
  489.         case 'b':
  490.             printf("option b\n");
  491.             break;
  492.  
  493.         case 'c':
  494.             printf("option c with value '%s'\n", optarg);
  495.             break;
  496.  
  497.         case '?':
  498.             break;
  499.  
  500.         default:
  501.             printf("?? getopt returned character code 0%o ??\n", c);
  502.         }
  503.     }
  504.  
  505.     if ( optind < argc )
  506.     {
  507.         printf("non-option ARGV-elements: ");
  508.         while ( optind < argc )
  509.             printf("%s ", argv[optind++]);
  510.         printf ("\n");
  511.     }
  512.  
  513.     return ( 0 );
  514. }
  515. #endif /*TEST*/
  516.  
  517. /*  END of getopt.c  */
  518.