158193Selan /*
258193Selan Getopt for GNU.
358193Selan Copyright (C) 1987, 1989 Free Software Foundation, Inc.
458193Selan 
558193Selan (Modified by Douglas C. Schmidt for use with GNU G++.)
658193Selan This file is part of the GNU C++ Library.  This library is free
758193Selan software; you can redistribute it and/or modify it under the terms of
858193Selan the GNU Library General Public License as published by the Free
958193Selan Software Foundation; either version 2 of the License, or (at your
1058193Selan option) any later version.  This library is distributed in the hope
1158193Selan that it will be useful, but WITHOUT ANY WARRANTY; without even the
1258193Selan implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
1358193Selan PURPOSE.  See the GNU Library General Public License for more details.
1458193Selan You should have received a copy of the GNU Library General Public
1558193Selan License along with this library; if not, write to the Free Software
1658193Selan Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
1758193Selan */
1858193Selan 
1958193Selan #ifdef __GNUG__
2058193Selan #pragma implementation
2158193Selan #endif
2258193Selan /* AIX requires the alloca decl to be the first thing in the file. */
2358193Selan #ifdef __GNUC__
24*60385Selan #define alloca alloca
2558193Selan #elif defined(sparc)
2658193Selan #include <alloca.h>
2758193Selan #elif defined(_AIX)
2858193Selan #pragma alloca
2958193Selan #else
3058193Selan char *alloca ();
3158193Selan #endif
3258193Selan #include <GetOpt.h>
3358193Selan 
3458193Selan char* GetOpt::nextchar = 0;
3558193Selan int GetOpt::first_nonopt = 0;
3658193Selan int GetOpt::last_nonopt = 0;
3758193Selan 
GetOpt(int argc,char ** argv,const char * optstring)3858193Selan GetOpt::GetOpt (int argc, char **argv, const char *optstring)
3958193Selan  :opterr (1), nargc (argc), nargv (argv), noptstring (optstring)
4058193Selan {
4158193Selan   /* Initialize the internal data when the first call is made.
4258193Selan      Start processing options with ARGV-element 1 (since ARGV-element 0
4358193Selan      is the program name); the sequence of previously skipped
4458193Selan      non-option ARGV-elements is empty.  */
4558193Selan 
4658193Selan   first_nonopt = last_nonopt = optind = 1;
4758193Selan   optarg = nextchar = 0;
4858193Selan 
4958193Selan   /* Determine how to handle the ordering of options and nonoptions.  */
5058193Selan 
5158193Selan   if (optstring[0] == '-')
5258193Selan     ordering = RETURN_IN_ORDER;
5358193Selan   else if (getenv ("_POSIX_OPTION_ORDER") != 0)
5458193Selan     ordering = REQUIRE_ORDER;
5558193Selan   else
5658193Selan     ordering = PERMUTE;
5758193Selan }
5858193Selan 
5958193Selan void
exchange(char ** argv)6058193Selan GetOpt::exchange (char **argv)
6158193Selan {
6258193Selan   int nonopts_size
6358193Selan     = (last_nonopt - first_nonopt) * sizeof (char *);
6458193Selan   char **temp = (char **) alloca (nonopts_size);
6558193Selan 
6658193Selan   /* Interchange the two blocks of data in argv.  */
6758193Selan 
6858193Selan   memcpy (temp, &argv[first_nonopt], nonopts_size);
6958193Selan   memcpy (&argv[first_nonopt], &argv[last_nonopt],
7058193Selan          (optind - last_nonopt) * sizeof (char *));
7158193Selan   memcpy (&argv[first_nonopt + optind - last_nonopt], temp,
7258193Selan          nonopts_size);
7358193Selan 
7458193Selan   /* Update records for the slots the non-options now occupy.  */
7558193Selan 
7658193Selan   first_nonopt += (optind - last_nonopt);
7758193Selan   last_nonopt = optind;
7858193Selan }
7958193Selan 
8058193Selan /* Scan elements of ARGV (whose length is ARGC) for option characters
8158193Selan    given in OPTSTRING.
8258193Selan 
8358193Selan    If an element of ARGV starts with '-', and is not exactly "-" or "--",
8458193Selan    then it is an option element.  The characters of this element
8558193Selan    (aside from the initial '-') are option characters.  If `getopt'
8658193Selan    is called repeatedly, it returns successively each of theoption characters
8758193Selan    from each of the option elements.
8858193Selan 
8958193Selan    If `getopt' finds another option character, it returns that character,
9058193Selan    updating `optind' and `nextchar' so that the next call to `getopt' can
9158193Selan    resume the scan with the following option character or ARGV-element.
9258193Selan 
9358193Selan    If there are no more option characters, `getopt' returns `EOF'.
9458193Selan    Then `optind' is the index in ARGV of the first ARGV-element
9558193Selan    that is not an option.  (The ARGV-elements have been permuted
9658193Selan    so that those that are not options now come last.)
9758193Selan 
9858193Selan    OPTSTRING is a string containing the legitimate option characters.
9958193Selan    A colon in OPTSTRING means that the previous character is an option
10058193Selan    that wants an argument.  The argument is taken from the rest of the
10158193Selan    current ARGV-element, or from the following ARGV-element,
10258193Selan    and returned in `optarg'.
10358193Selan 
10458193Selan    If an option character is seen that is not listed in OPTSTRING,
10558193Selan    return '?' after printing an error message.  If you set `opterr' to
10658193Selan    zero, the error message is suppressed but we still return '?'.
10758193Selan 
10858193Selan    If a char in OPTSTRING is followed by a colon, that means it wants an arg,
10958193Selan    so the following text in the same ARGV-element, or the text of the following
11058193Selan    ARGV-element, is returned in `optarg.  Two colons mean an option that
11158193Selan    wants an optional arg; if there is text in the current ARGV-element,
11258193Selan    it is returned in `optarg'.
11358193Selan 
11458193Selan    If OPTSTRING starts with `-', it requests a different method of handling the
11558193Selan    non-option ARGV-elements.  See the comments about RETURN_IN_ORDER, above.  */
11658193Selan 
11758193Selan int
operator ()(void)11858193Selan GetOpt::operator () (void)
11958193Selan {
12058193Selan   if (nextchar == 0 || *nextchar == 0)
12158193Selan     {
12258193Selan       if (ordering == PERMUTE)
12358193Selan         {
12458193Selan           /* If we have just processed some options following some non-options,
12558193Selan              exchange them so that the options come first.  */
12658193Selan 
12758193Selan           if (first_nonopt != last_nonopt && last_nonopt != optind)
12858193Selan             exchange (nargv);
12958193Selan           else if (last_nonopt != optind)
13058193Selan             first_nonopt = optind;
13158193Selan 
13258193Selan           /* Now skip any additional non-options
13358193Selan              and extend the range of non-options previously skipped.  */
13458193Selan 
13558193Selan           while (optind < nargc
13658193Selan                  && (nargv[optind][0] != '-'
13758193Selan                      || nargv[optind][1] == 0))
13858193Selan             optind++;
13958193Selan           last_nonopt = optind;
14058193Selan         }
14158193Selan 
14258193Selan       /* Special ARGV-element `--' means premature end of options.
14358193Selan          Skip it like a null option,
14458193Selan          then exchange with previous non-options as if it were an option,
14558193Selan          then skip everything else like a non-option.  */
14658193Selan 
14758193Selan       if (optind != nargc && !strcmp (nargv[optind], "--"))
14858193Selan         {
14958193Selan           optind++;
15058193Selan 
15158193Selan           if (first_nonopt != last_nonopt && last_nonopt != optind)
15258193Selan             exchange (nargv);
15358193Selan           else if (first_nonopt == last_nonopt)
15458193Selan             first_nonopt = optind;
15558193Selan           last_nonopt = nargc;
15658193Selan 
15758193Selan           optind = nargc;
15858193Selan         }
15958193Selan 
16058193Selan       /* If we have done all the ARGV-elements, stop the scan
16158193Selan          and back over any non-options that we skipped and permuted.  */
16258193Selan 
16358193Selan       if (optind == nargc)
16458193Selan         {
16558193Selan           /* Set the next-arg-index to point at the non-options
16658193Selan              that we previously skipped, so the caller will digest them.  */
16758193Selan           if (first_nonopt != last_nonopt)
16858193Selan             optind = first_nonopt;
16958193Selan           return EOF;
17058193Selan         }
17158193Selan 
17258193Selan       /* If we have come to a non-option and did not permute it,
17358193Selan          either stop the scan or describe it to the caller and pass it by.  */
17458193Selan 
17558193Selan       if (nargv[optind][0] != '-' || nargv[optind][1] == 0)
17658193Selan         {
17758193Selan           if (ordering == REQUIRE_ORDER)
17858193Selan             return EOF;
17958193Selan           optarg = nargv[optind++];
18058193Selan           return 0;
18158193Selan         }
18258193Selan 
18358193Selan       /* We have found another option-ARGV-element.
18458193Selan          Start decoding its characters.  */
18558193Selan 
18658193Selan       nextchar = nargv[optind] + 1;
18758193Selan     }
18858193Selan 
18958193Selan   /* Look at and handle the next option-character.  */
19058193Selan 
19158193Selan   {
19258193Selan     char c = *nextchar++;
19358193Selan     char *temp = (char *) strchr (noptstring, c);
19458193Selan 
19558193Selan     /* Increment `optind' when we start to process its last character.  */
19658193Selan     if (*nextchar == 0)
19758193Selan       optind++;
19858193Selan 
19958193Selan     if (temp == 0 || c == ':')
20058193Selan       {
20158193Selan         if (opterr != 0)
20258193Selan           {
20358193Selan             if (c < 040 || c >= 0177)
20458193Selan               fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
20558193Selan                        nargv[0], c);
20658193Selan             else
20758193Selan               fprintf (stderr, "%s: unrecognized option `-%c'\n",
20858193Selan                        nargv[0], c);
20958193Selan           }
21058193Selan         return '?';
21158193Selan       }
21258193Selan     if (temp[1] == ':')
21358193Selan       {
21458193Selan         if (temp[2] == ':')
21558193Selan           {
21658193Selan             /* This is an option that accepts an argument optionally.  */
21758193Selan             if (*nextchar != 0)
21858193Selan               {
21958193Selan                 optarg = nextchar;
22058193Selan                 optind++;
22158193Selan               }
22258193Selan             else
22358193Selan               optarg = 0;
22458193Selan             nextchar = 0;
22558193Selan           }
22658193Selan         else
22758193Selan           {
22858193Selan             /* This is an option that requires an argument.  */
22958193Selan             if (*nextchar != 0)
23058193Selan               {
23158193Selan                 optarg = nextchar;
23258193Selan                 /* If we end this ARGV-element by taking the rest as an arg,
23358193Selan                    we must advance to the next element now.  */
23458193Selan                 optind++;
23558193Selan               }
23658193Selan             else if (optind == nargc)
23758193Selan               {
23858193Selan                 if (opterr != 0)
23958193Selan                   fprintf (stderr, "%s: no argument for `-%c' option\n",
24058193Selan                            nargv[0], c);
24158193Selan                 c = '?';
24258193Selan               }
24358193Selan             else
24458193Selan               /* We already incremented `optind' once;
24558193Selan                  increment it again when taking next ARGV-elt as argument.  */
24658193Selan               optarg = nargv[optind++];
24758193Selan             nextchar = 0;
24858193Selan           }
24958193Selan       }
25058193Selan     return c;
25158193Selan   }
25258193Selan }
253