home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 2: PC / frozenfish_august_1995.bin / bbs / d07xx / d0797.lha / PSUtils / getopt.c < prev    next >
C/C++ Source or Header  |  1993-01-10  |  18KB  |  646 lines

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