Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Improved GetOpt class.

5 views
Skip to first unread message

Vinicius Jose Latorre

unread,
Feb 24, 1995, 11:56:05 AM2/24/95
to
Hi,

I am sending here an improvement of GetOpt class, extending to treat long options.
The new long options may be (with valid syntax):

NO_ARGUMENT
-option

REQUIRED_ARGUMENT
-option value
-option=value

OPTIONAL_ARGUMENT
-option
-option=value

LIST_ARGUMENT
-option
-option=value
-option=value value...
-option value
-option value value...

ALTERNATIVE_ARGUMENT (OPTIONAL_ARGUMENT extension)
-option
-option=value
-option value

The struct Option has a field `valid' that points to a set of valid values that
the option accepts.

Thanks,


Vinicius J. Latorre
CPqD TELEBRAS (Research and Development Center of Brazilian Telecomunications)
e-mail: vini...@cpqd.br

==========================CUT HERE===============================================
GetOpt.h:
---------
// This may look like C code, but it is really -*- C++ -*-

// Getopt for GNU.
// Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
// (Modified by Douglas C. Schmidt for use with GNU G++ (Getopt).)
// (Modified by Vinicius J. Latorre for use with long options.)

// This file is part of the GNU C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms of
// the GNU Library General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your
// option) any later version. This library is distributed in the hope
// that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU Library General Public License for more details.
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.


// 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.

#ifndef GetOpt_h
#ifdef __GNUG__
#pragma interface
#endif
#define GetOpt_h 1


#include <std.h>
#include <stdio.h>
#include <String.h>


// Describe the long-named options requested by the application.
// The LONG_OPTIONS argument below is a vector of `struct option'
// terminated by an element containing a name which is zero.

// The field `has_arg' is:
// NO_ARGUMENT if the option does not take an argument,
// REQUIRED_ARGUMENT if the option requires an argument
// (accepts the following syntax:
// -option=value
// -option value),
// OPTIONAL_ARGUMENT if the option takes an optional argument
// (accepts the following syntax:
// -option
// -option=value),
// LIST_ARGUMENT if the option takes a list argument
// (zero, one or more arguments; accepts the
// following syntax:
// -option
// -option=value
// -option=value value ...
// -option value
// -option value value ...),
// ALTERNATIVE_ARGUMENT if the option takes an optional argument,
// (an OPTIONAL_ARGUMENT extension, that is,
// accepts the following syntax:
// -option
// -option=value
// -option value).

// If the field `flag' is not NULL, it points to a variable that is set
// to the value given in the field `val' when the option is found, but
// left unchanged if the option is not found.

// To have a long-named option do something other than set an `int' to
// a compiled-in constant, such as set a value from `optarg', set the
// option's `flag' field to zero and its `val' field to a nonzero
// value (the equivalent single-letter option character, if there is
// one). For long options that have a zero `flag' field, `getopt'
// returns the contents of the `val' field.

// If field `valid' is not NULL, it points to a vector of string
// terminated by an element which is zero, this vector correspondes to
// valid values for this option.
// If field `valid' is NULL and the field `has_arg' is LIST_ARGUMENT,
// all value will be considered a valid value for this option until
// reachs a valid option or an option terminator.

enum Option_Argument
{ NO_ARGUMENT, REQUIRED_ARGUMENT, OPTIONAL_ARGUMENT,
LIST_ARGUMENT, ALTERNATIVE_ARGUMENT };

struct Option
{
const char *name;
Option_Argument has_arg;
int *flag;
int val;
const char **valid;
};


class GetOpt
{

private:
// 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;


// 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.

enum OrderingEnum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER };
OrderingEnum ordering;


// Handle permutation of arguments.

// Describe the part of ARGV that contains non-options that have
// been skipped. `first_nonopt' is the index in ARGV of the first of them;
// `last_nonopt' is the index after the last of them.

static int first_nonopt;
static int last_nonopt;


// The last long option that has field `has_arg' set to LIST_ARGUMENT.
// In each iteration, the current argument is checked to see if it is
// an valid value for the last list long option or it is an option.

const struct Option *list_option;

// Flag used to determine the very first LIST_ARGUMENT processing.

int list_option_first;


void exchange (char **argv);


// Internal methods

void Initialize (const char *optstring);
int List_Value (int i);
int List_No_Value ();
void print_expanding (char *v);


public:
// Set to an option character which was unrecognized.

int optopt;


// 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;


// 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;


// Used only for long options.
// If current option has field `valid' not NULL and current argument
// is a valid value, `optindvalue' indexes the valid value in field `valid'.
// If there is no valid value in field `valid' or field `valid' is NULL,
// `optindvalue' is set to EOF.

int optindvalue;


// Callers store zero here to inhibit the error message
// for unrecognized options.

int opterr;

int nargc;
char **nargv;
const char *noptstring;
const struct Option *nlongopts;
int *nlongind;
int nlong_only;


// 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 the option 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 `-' or `+', it requests different methods of
// handling the non-option ARGV-elements.
// See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.

// Long-named options begin with `--' instead of `-'.
// Their names may be abbreviated as long as the abbreviation is unique
// or is an exact match for some defined option. If they have an
// argument, it follows the option name in the same ARGV-element, separated
// from the option name by a `=', or else the in next ARGV-element.
// When `getopt' finds a long-named option, it returns 0 if that option's
// `flag' field is nonzero, the value of the option's `val' field
// if the `flag' field is zero.

// The elements of ARGV aren't really const, because we permute them.
// But we pretend they're const in the prototype to be compatible
// with other systems.

// LONGOPTS is a vector of `struct option' terminated by an
// element containing a name which is zero.

// LONGIND returns the index in LONGOPT of the long-named option found.
// It is only valid when a long-named option has been found by the most
// recent call.

// If LONG_ONLY is nonzero, '-' as well as '--' can introduce
// long-named options. If an option that starts with '-' (not '--')
// doesn't match a long option, but does match a short option,
// it is parsed as a short option instead.

GetOpt (int argc, char **argv, const char *optstring);
GetOpt (int argc, char **argv, const char *optstring,
const struct Option *longopts, int *longind, int long_only);
int operator () (void);


// first_char returns the first character of the argument.

int first_char ();

// next_arg looks at next argument for an integer, double or string
// depending on the type of argument given to it. If the correct type is
// found, the value is set and next_arg returns 1. If the type is not
// correct, next_arg returns 0.

// double arguments start with a digit, plus, minus or period.
// integer arguments start with a digit.
// String arguments have no restriction.

// If the next argument is an integer, set the reference variable to it
// and increment the index to the options. Return 1 if an integer is
// found, else return 0.

int next_arg (int &i);
int next_arg (double &d);
int next_arg (String &s);


// Prints an message of invalid argument.

void print_invalid ();

};

inline int GetOpt::first_char ()
{
return nargv[optind][0];
};


#endif


/* ====== GetOpt.h ends here ====== */

==========================CUT HERE===============================================
GetOpt.cc:
----------
// This may look like C code, but it is really -*- C++ -*-

// Getopt for GNU.
// Copyright (C) 1987, 1989 Free Software Foundation, Inc.

// (Modified by Douglas C. Schmidt for use with GNU G++.)
// (Modified by Vinicius J. Latorre for use with long options.)

// This file is part of the GNU C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms of
// the GNU Library General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your
// option) any later version. This library is distributed in the hope
// that it will be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU Library General Public License for more details.
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.


#ifdef __GNUG__
#pragma implementation
#endif

// AIX requires the alloca decl to be the first thing in the file.

#ifdef __GNUC__

#define alloca __builtin_alloca

#elif defined(sparc)

#include <alloca.h>
extern "C" void *__builtin_alloca(...);

#elif defined(_AIX)

#pragma alloca

#else

char *alloca ();

#endif


#include <GetOpt.h>


char* GetOpt::nextchar = 0;
int GetOpt::first_nonopt = 0;
int GetOpt::last_nonopt = 0;


GetOpt::GetOpt (int argc, char **argv, const char *optstring)
:opterr (1), nargc (argc), nargv (argv), noptstring (optstring)
, list_option (0), list_option_first (0)
, nlongopts (0), nlongind (0), nlong_only (0)
, optindvalue (EOF)
{
Initialize (optstring);
}


GetOpt::GetOpt (int argc, char **argv, const char *optstring,
const struct Option *longopts, int *longind, int long_only)
:opterr (1), nargc (argc), nargv (argv), noptstring (optstring)
, list_option (0), list_option_first (0)
, nlongopts (longopts), nlongind (longind), nlong_only (long_only)
, optindvalue (EOF)
{
Initialize (optstring);
}


void
GetOpt::Initialize (const 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.

first_nonopt = last_nonopt = optind = 1;
optarg = nextchar = 0;

// Determine how to handle the ordering of options and nonoptions.

if (optstring == 0)
{
noptstring = "";
if (getenv ("_POSIX_OPTION_ORDER"))
ordering = REQUIRE_ORDER;
else
ordering = PERMUTE;
}
else if (optstring[0] == '-')
ordering = RETURN_IN_ORDER;
else if ((optstring[0] == '+') || (getenv ("_POSIX_OPTION_ORDER")))
ordering = REQUIRE_ORDER;
else
ordering = PERMUTE;
}


void
GetOpt::exchange (char **argv)
{
int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
char **temp = (char **) alloca (nonopts_size);

// Interchange the two blocks of data in argv.

memcpy (temp, &argv[first_nonopt], nonopts_size);
memcpy (&argv[first_nonopt], &argv[last_nonopt],
(optind - last_nonopt) * sizeof (char *));
memcpy (&argv[first_nonopt + optind - last_nonopt], temp,
nonopts_size);

// Update records for the slots the non-options now occupy.

first_nonopt += (optind - last_nonopt);
last_nonopt = optind;
}


int
GetOpt::List_Value (int i)
{
const struct Option *x = list_option;

list_option_first = 0;
optarg = nargv[i];
nextchar = 0;
if (list_option->has_arg != LIST_ARGUMENT)
list_option = 0;
if (x->flag)
{
*(x->flag) = x->val;
return 0;
}
return x->val;
}


int
GetOpt::List_No_Value ()
{
const struct Option *x = list_option;

list_option_first = 0;
list_option = 0;
optindvalue = EOF;
optarg = 0;
nextchar = 0;
if (x->flag)
{
*(x->flag) = x->val;
return 0;
}
return x->val;
}


void
GetOpt::print_expanding (char *v)
{
int x;

for (; (x = *v) != 0; v++)
if (x < 040)
fprintf (stderr, "^%c", x + '@');
else if (x > 0177)
fprintf (stderr, "\\%o", x);
else
fprintf (stderr, "%c", x);
}


void
GetOpt::print_invalid ()
{
fprintf (stderr, "%s: invalid argument `", nargv[0]);
print_expanding (optarg);
fprintf (stderr, "'\n");
}


// 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 the option 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 `-' or `+', it requests different methods of
// handling the non-option ARGV-elements.
// See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.

// Long-named options begin with `--' instead of `-'.
// Their names may be abbreviated as long as the abbreviation is unique
// or is an exact match for some defined option. If they have an
// argument, it follows the option name in the same ARGV-element, separated
// from the option name by a `=', or else the in next ARGV-element.
// When `getopt' finds a long-named option, it returns 0 if that option's
// `flag' field is nonzero, the value of the option's `val' field
// if the `flag' field is zero.

// The elements of ARGV aren't really const, because we permute them.
// But we pretend they're const in the prototype to be compatible
// with other systems.

// LONGOPTS is a vector of `struct option' terminated by an
// element containing a name which is zero.

// LONGIND returns the index in LONGOPT of the long-named option found.
// It is only valid when a long-named option has been found by the most
// recent call.

// If LONG_ONLY is nonzero, '-' as well as '--' can introduce
// long-named options. If an option that starts with '-' (not '--')
// doesn't match a long option, but does match a short option,
// it is parsed as a short option instead.

int
GetOpt::operator () (void)
{
optopt = 0;

// We are processing a LIST_ARGUMENT or ALTERNATIVE_ARGUMENT,
// now we try to see if the next argument is a current option value
// or is another option.

TRY_TO_GET_A_VALUE:
if (list_option)
{
// If we have done all the ARGV-elements, stop the scan.

if (optind == nargc)
// Check if first LIST_ARGUMENT with no argument.
if (list_option_first)
return List_No_Value ();
else
return EOF;

if (list_option->valid == 0)
{
// If there isn't a valid list of values,
// try to see if current argument isn't an option.

if (nargv[optind][0] != '-')
return List_Value (optind++);

// An argument starting with '-' may be an option or not,
// this check is made below.
}
else
{
// If there is a valid list of values,
// try to see if current argument is a valid value.

const char **v;

for (v = list_option->valid, optindvalue = 0; *v != 0; v++, optindvalue++)
if (strcmp (*v, nargv[optind]) == 0)
return List_Value (optind++);
optindvalue = EOF;

// Check if first LIST_ARGUMENT with no argument;
// Otherwise, here we know that the LIST_ARGUMENT processing terminates.

if (list_option_first)
return List_No_Value ();
list_option = 0;
}
}

if (nextchar == 0 || *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 (first_nonopt != last_nonopt && last_nonopt != optind)
exchange (nargv);
else if (last_nonopt != optind)
first_nonopt = optind;

// Now skip any additional non-options
// and extend the range of non-options previously skipped.

while (optind < nargc
&& (nargv[optind][0] != '-' || nargv[optind][1] == 0))
optind++;
last_nonopt = 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 != nargc && !strcmp (nargv[optind], "--"))
{
optind++;

if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange (nargv);
else if (first_nonopt == last_nonopt)
first_nonopt = optind;
last_nonopt = nargc;

optind = nargc;
}

// If we have done all the ARGV-elements, stop the scan
// and back over any non-options that we skipped and permuted.

if (optind == nargc)
{
// Check if first LIST_ARGUMENT with no argument;
// Otherwise, terminates LIST_ARGUMENT processing.

if (list_option_first)
return List_No_Value ();
list_option = 0;

// Set the next-arg-index to point at the non-options
// that we previously skipped, so the caller will digest them.

if (first_nonopt != last_nonopt)
optind = first_nonopt;
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 (nargv[optind][0] != '-' || nargv[optind][1] == 0)
{
// Check if first LIST_ARGUMENT with no argument;
// Otherwise, terminates LIST_ARGUMENT processing.

if (list_option_first)
return List_No_Value ();
list_option = 0;

if (ordering == REQUIRE_ORDER)
return EOF;
optarg = nargv[optind++];
optopt = EOF;
return 0;
}

// We have found another option-ARGV-element.
// Start decoding its characters.

nextchar = nargv[optind] + 1;
}

// Decode the current option-ARGV-element.

// Check whether the ARGV-element is a long option.

// If long_only and the ARGV-element has the form "-f", where f is
// a valid short option, don't consider it an abbreviated form of
// a long option that starts with f. Otherwise there would be no
// way to give the -f short option.

// On the other hand, if there's a long option "fubar" and
// the ARGV-element is "-fu", do consider that an abbreviation of
// the long option, just like "--fu", and not "-f" with arg "u".

// This distinction seems to be the most useful approach.

if (nlongopts
&& ((nargv[optind][1] == '-') ? (nextchar++, 1) : (0)
|| (nlong_only && (nargv[optind][2] || !strchr (noptstring, nargv[optind][1])))))
{
char *nameend;
const struct Option *p;
const struct Option *pfound = 0;
int exact = 0;
int ambig = 0;
int indfound;
int option_index;

for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
// Do nothing.
;

// Test all long options for either exact match or abbreviated matches.
for (p = nlongopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, nextchar, nameend - nextchar))
{
if (nameend - nextchar == strlen (p->name))
{
// Exact match found.
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == 0)
{
// First nonexact match found.
pfound = p;
indfound = option_index;
}
else
// Second or later nonexact match found.
ambig = 1;
}

if (ambig && !exact)
{
if (list_option)
// It is not a long option, but it is a value for LIST_ARGUMENT
return List_Value (optind++);
if (opterr)
fprintf (stderr, "%s: option `%s' is ambiguous\n",
nargv[0], nargv[optind]);
nextchar += strlen (nextchar);
optind++;
return '?';
}

if (pfound)
{
// Check if first LIST_ARGUMENT with no argument;
// Otherwise, terminates LIST_ARGUMENT processing.

if (list_option_first)
return List_No_Value ();
list_option = 0;

option_index = indfound;
optind++;
if ((*nameend) != 0)
// (-option=value)
// Don't test has_arg with >, because some C compilers don't
// allow it to be used on enums.
switch (pfound->has_arg)
{

case NO_ARGUMENT:
if (opterr)
{
if (nargv[optind - 1][1] == '-')
// --option
fprintf (stderr,
"%s: option `--%s' doesn't allow an argument\n",
nargv[0], pfound->name);
else
// +option or -option
fprintf (stderr,
"%s: option `%c%s' doesn't allow an argument\n",
nargv[0], nargv[optind - 1][0], pfound->name);
}
nextchar += strlen (nextchar);
return '?';

case LIST_ARGUMENT:
list_option = pfound;

default:
optarg = nameend + 1;
break;

}
else
// (-option value) or (-option)
switch (pfound->has_arg)
{

// See methods List_Value and List_No_Value
case ALTERNATIVE_ARGUMENT:
case LIST_ARGUMENT:
nextchar += strlen (nextchar);
if (nlongind)
*nlongind = option_index;
list_option_first = 1;
list_option = pfound;
goto TRY_TO_GET_A_VALUE;

case REQUIRED_ARGUMENT:
if (optind < nargc)
optarg = nargv[optind++];
else
{
if (opterr)
fprintf (stderr, "%s: option `%s' requires an argument\n",
nargv[0], nargv[optind - 1]);
nextchar += strlen (nextchar);
return (noptstring[0] == ':') ? (':') : ('?');
}
break;

default:
optarg = 0;
break;

}

// Check if `optarg' is a valid value.

{
int result;

nextchar += strlen (nextchar);
if (nlongind)
*nlongind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
result = 0;
}
else
result = pfound->val;

// If there is a valid list of values,
// check if `optarg' is a valid value.

if ((pfound->valid) && (optarg))
{
const char **v;

for (v = pfound->valid, optindvalue = 0; *v != 0; v++, optindvalue++)
if (strcmp (*v, optarg) == 0)
return result;
optindvalue = EOF;

// Here we know it is an invalid value.

if (opterr)
{
fprintf (stderr, "%s: value `", nargv[0]);
print_expanding (optarg);
if (nargv[optind - 2][1] == '-')
// --option
fprintf (stderr, "' is invalid for option `--%s'\n",
pfound->name);
else
// +option or -option
fprintf (stderr, "' is invalid for option `%c%s'\n",
nargv[optind - 2][0], pfound->name);
}
return '?';
}

// There is a NULL valid list of values.

return result;
}
}

// Can't find it as a long option. If this is not long_only,
// or the option starts with '--' or is not a valid short
// option, then it's an error.
// Otherwise interpret it as a short option.

if (!nlong_only || nargv[optind][1] == '-' || strchr (noptstring, *nextchar) == 0)
{
if (list_option)
// It is not a long option, but it is a value for LIST_ARGUMENT
return List_Value (optind++);
if (opterr)
{
char * v;
int x;

if (nargv[optind][1] == '-')
// --option
fprintf (stderr, "%s: unrecognized option `--",
nargv[0]);
else
// +option or -option
fprintf (stderr, "%s: unrecognized option `%c",
nargv[0], nargv[optind][0]);
print_expanding (nextchar);
fprintf (stderr, "'\n");
}
nextchar = (char *) "";
optind++;
return '?';
}
}

// Look at and handle the next option-character.

{
int c = *nextchar++;
char *temp = (char *) strchr (noptstring, c);

// Increment `optind' when we start to process its last character.
if (*nextchar == 0)
optind++;

if (temp == 0 || c == ':')
{
if (opterr)
{
if (c < 040 || c >= 0177)
{
// Check if first LIST_ARGUMENT with no argument;
// Otherwise, terminates LIST_ARGUMENT processing.

if (list_option_first)
return List_No_Value ();
list_option = 0;

fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
nargv[0], c);
}
else
{
if (list_option)
// It is not a short option, but it is a value for LIST_ARGUMENT
return List_Value ((*nextchar == 0) ? (optind - 1) : (optind++));
fprintf (stderr, "%s: unrecognized option `-%c'\n",
nargv[0], c);
}
}
optopt = c;
return '?';
}

// Check if first LIST_ARGUMENT with no argument;
// Otherwise, terminates LIST_ARGUMENT processing.

if (list_option_first)
return List_No_Value ();
list_option = 0;

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 == nargc)
{
if (opterr)
fprintf (stderr, "%s: option `-%c' requires an argument\n",
nargv[0], c);
optopt = c;
c = (noptstring[0] == ':') ? (':') : ('?');
}
else
// We already incremented `optind' once;
// increment it again when taking next ARGV-elt as argument.
optarg = nargv[optind++];
nextchar = 0;
}
}
return c;
}
}


int
GetOpt::next_arg (int &i)
{
int tmp;

// Terminates LIST_ARGUMENT processing.

list_option = 0;

if (0 < sscanf (nargv[optind], "%d", &tmp))
{
i = tmp;
optind++;
return 1;
}
else
return 0;
}


int
GetOpt::next_arg (double &d)
{
double tmp;

// Terminates LIST_ARGUMENT processing.

list_option = 0;

if (0 < sscanf (nargv[optind], "%lf", &tmp))
{
d = tmp;
optind++;
return 1;
}
else
return 0;
}


int
GetOpt::next_arg (String &s)
{
// Terminates LIST_ARGUMENT processing.

list_option = 0;

if ('-' != nargv[optind][0])
{
s = nargv[optind];
optind++;
return 1;
}
else
return 0;
}


#ifdef TEST_GetOpt

#include <stdio.h>

int
main (int argc, char **argv)
{
int c;
int digit_optind = 0;
int this_option_optind = 1;
int option_index = 0;
static const char *vfile[] = {"file", "archive", 0};
static const char *vlist[] = {"one", "two", "three", 0};
static const char *vopt[] = {"optional", "alternative", 0};
static struct Option long_options[] =
{
{"add", REQUIRED_ARGUMENT, 0, 0, 0},
{"append", NO_ARGUMENT, 0, 0, 0},
{"delete", REQUIRED_ARGUMENT, 0, 0, 0},
{"verbose", NO_ARGUMENT, 0, 0, 0},
{"create", NO_ARGUMENT, 0, 0, 0},
{"file", REQUIRED_ARGUMENT, 0, 0, 0},
{"list", LIST_ARGUMENT, 0, 0, 0},
{"opt", OPTIONAL_ARGUMENT, 0, 0, 0},
{"alt", ALTERNATIVE_ARGUMENT, 0, 0, 0},
{"vfile", REQUIRED_ARGUMENT, 0, 0, vfile},
{"vlist", LIST_ARGUMENT, 0, 0, vlist},
{"vopt", OPTIONAL_ARGUMENT, 0, 0, vopt},
{"valt", ALTERNATIVE_ARGUMENT, 0, 0, vopt},
{0, NO_ARGUMENT, 0, 0, 0}
};
GetOpt getopt_long (argc, argv, "abc:d:o::0123456789",
long_options, &option_index, 1);

while ((c = getopt_long ()) != EOF)
{
switch (c)
{
case 0:
printf ("option %s", long_options[option_index].name);
if (getopt_long.optarg)
printf (" with arg %s", getopt_long.optarg);
printf ("\n");
break;

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", getopt_long.optarg);
break;

case 'd':
printf ("option d with value `%s'\n", getopt_long.optarg);
break;

case 'o':
printf ("option o");
if (getopt_long.optarg)
printf (" with value `%s'", getopt_long.optarg);
printf ("\n");
break;

case '?':
break;

default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}

if ((c = getopt_long.optind) < argc)
{
printf ("non-option ARGV-elements: ");
while (c < argc)
printf ("%s ", argv[c++]);
printf ("\n");
}

exit (0);
}

#endif // TEST_GetOpt


/* ====== GetOpt.cc ends here ====== */

0 new messages