1991-10-06 20:00:00 -04:00
|
|
|
/*
|
|
|
|
* egetopt.c -- Extended 'getopt'.
|
|
|
|
*
|
|
|
|
* A while back, a public-domain version of getopt() was posted to the
|
|
|
|
* net. A bit later, a gentleman by the name of Keith Bostic made some
|
|
|
|
* enhancements and reposted it.
|
|
|
|
*
|
|
|
|
* In recent weeks (i.e., early-to-mid 1988) there's been some
|
|
|
|
* heated discussion in comp.lang.c about the merits and drawbacks
|
|
|
|
* of getopt(), especially with regard to its handling of '?'.
|
|
|
|
*
|
|
|
|
* In light of this, I have taken Mr. Bostic's public-domain getopt()
|
|
|
|
* and have made some changes that I hope will be considered to be
|
|
|
|
* improvements. I call this routine 'egetopt' ("Extended getopt").
|
|
|
|
* The default behavior of this routine is the same as that of getopt(),
|
|
|
|
* but it has some optional features that make it more useful. These
|
|
|
|
* options are controlled by the settings of some global variables.
|
|
|
|
* By not setting any of these extra global variables, you will have
|
|
|
|
* the same functionality as getopt(), which should satisfy those
|
|
|
|
* purists who believe getopt() is perfect and can never be improved.
|
|
|
|
* If, on the other hand, you are someone who isn't satisfied with the
|
|
|
|
* status quo, egetopt() may very well give you the added capabilities
|
|
|
|
* you want.
|
|
|
|
*
|
|
|
|
* Look at the enclosed README file for a description of egetopt()'s
|
|
|
|
* new features.
|
|
|
|
*
|
|
|
|
* The code was originally posted to the net as getopt.c by ...
|
|
|
|
*
|
|
|
|
* Keith Bostic
|
|
|
|
* ARPA: keith@seismo
|
|
|
|
* UUCP: seismo!keith
|
|
|
|
*
|
|
|
|
* Current version: added enhancements and comments, reformatted code.
|
|
|
|
*
|
|
|
|
* Lloyd Zusman
|
|
|
|
* Master Byte Software
|
|
|
|
* Los Gatos, California
|
|
|
|
* Internet: ljz@fx.com
|
|
|
|
* UUCP: ...!ames!fxgrp!ljz
|
|
|
|
*
|
|
|
|
* May, 1988
|
1991-12-12 19:00:00 -05:00
|
|
|
*
|
|
|
|
* Modified for use in free JPEG code:
|
|
|
|
*
|
|
|
|
* Ed Hanway
|
|
|
|
* UUCP: uunet!sisd!jeh
|
|
|
|
*
|
|
|
|
* October, 1991
|
1991-10-06 20:00:00 -04:00
|
|
|
*/
|
|
|
|
|
1991-12-12 19:00:00 -05:00
|
|
|
/* The original egetopt.c was written not to need stdio.h.
|
|
|
|
* For the JPEG code this is an unnecessary and unportable assumption.
|
|
|
|
* Also, we make all the variables and routines "static" to avoid
|
|
|
|
* possible conflicts with a system-library version of getopt.
|
|
|
|
*
|
|
|
|
* In the JPEG code, this file is compiled by #including it in jcmain.c
|
|
|
|
* or jdmain.c. Since ANSI2KNR does not process include files, we can't
|
|
|
|
* rely on it to convert function definitions to K&R style. Hence we
|
|
|
|
* provide both styles of function header with an explicit #ifdef PROTO (ick).
|
1991-10-06 20:00:00 -04:00
|
|
|
*/
|
|
|
|
|
1991-12-12 19:00:00 -05:00
|
|
|
#define GVAR static /* make empty to export these variables */
|
1991-10-06 20:00:00 -04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* None of these constants are referenced in the executable portion of
|
|
|
|
* the code ... their sole purpose is to initialize global variables.
|
|
|
|
*/
|
|
|
|
#define BADCH (int)'?'
|
|
|
|
#define NEEDSEP (int)':'
|
|
|
|
#define MAYBESEP (int)'\0'
|
|
|
|
#define EMSG ""
|
|
|
|
#define START "-"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Here are all the pertinent global variables.
|
|
|
|
*/
|
1991-12-12 19:00:00 -05:00
|
|
|
GVAR int opterr = 1; /* if true, output error message */
|
|
|
|
GVAR int optind = 1; /* index into parent argv vector */
|
|
|
|
GVAR int optopt; /* character checked for validity */
|
|
|
|
GVAR int optbad = BADCH; /* character returned on error */
|
|
|
|
GVAR int optchar = 0; /* character that begins returned option */
|
|
|
|
GVAR int optneed = NEEDSEP; /* flag for mandatory argument */
|
|
|
|
GVAR int optmaybe = MAYBESEP; /* flag for optional argument */
|
|
|
|
GVAR const char *optarg; /* argument associated with option */
|
|
|
|
GVAR const char *optstart = START; /* list of characters that start options */
|
1991-10-06 20:00:00 -04:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Macros.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Conditionally print out an error message and return (depends on the
|
1991-12-12 19:00:00 -05:00
|
|
|
* setting of 'opterr').
|
1991-10-06 20:00:00 -04:00
|
|
|
*/
|
|
|
|
#define TELL(S) { \
|
1991-12-12 19:00:00 -05:00
|
|
|
if (opterr) \
|
|
|
|
fprintf(stderr, "%s%s%c\n", *nargv, (S), optopt); \
|
1991-10-06 20:00:00 -04:00
|
|
|
return (optbad); \
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This works similarly to index() and strchr(). I include it so that you
|
|
|
|
* don't need to be concerned as to which one your system has.
|
|
|
|
*/
|
1991-12-12 19:00:00 -05:00
|
|
|
|
|
|
|
#ifdef PROTO
|
|
|
|
LOCAL const char *
|
|
|
|
_sindex (const char *string, int ch)
|
|
|
|
#else
|
|
|
|
LOCAL const char *
|
|
|
|
_sindex (string, ch)
|
|
|
|
const char *string;
|
|
|
|
int ch;
|
|
|
|
#endif
|
1991-10-06 20:00:00 -04:00
|
|
|
{
|
|
|
|
if (string != NULL) {
|
|
|
|
for (; *string != '\0'; ++string) {
|
|
|
|
if (*string == (char)ch) {
|
|
|
|
return (string);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Here it is:
|
|
|
|
*/
|
1991-12-12 19:00:00 -05:00
|
|
|
|
|
|
|
#ifdef PROTO
|
|
|
|
LOCAL int
|
|
|
|
egetopt (int nargc, char **nargv, const char *ostr)
|
|
|
|
#else
|
|
|
|
LOCAL int
|
|
|
|
egetopt (nargc, nargv, ostr)
|
|
|
|
int nargc;
|
|
|
|
char **nargv;
|
|
|
|
const char *ostr;
|
|
|
|
#endif
|
1991-10-06 20:00:00 -04:00
|
|
|
{
|
1991-12-12 19:00:00 -05:00
|
|
|
static const char *place = EMSG; /* option letter processing */
|
|
|
|
register const char *oli; /* option letter list index */
|
|
|
|
register const char *osi = NULL; /* option start list index */
|
1991-10-06 20:00:00 -04:00
|
|
|
|
|
|
|
if (nargv == (char **)NULL) {
|
|
|
|
return (EOF);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nargc <= optind || nargv[optind] == NULL) {
|
|
|
|
return (EOF);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (place == NULL) {
|
|
|
|
place = EMSG;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Update scanning pointer.
|
|
|
|
*/
|
|
|
|
if (*place == '\0') {
|
|
|
|
place = nargv[optind];
|
|
|
|
if (place == NULL) {
|
|
|
|
return (EOF);
|
|
|
|
}
|
|
|
|
osi = _sindex(optstart, *place);
|
|
|
|
if (osi != NULL) {
|
|
|
|
optchar = (int)*osi;
|
|
|
|
}
|
|
|
|
if (optind >= nargc || osi == NULL || *++place == '\0') {
|
|
|
|
return (EOF);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Two adjacent, identical flag characters were found.
|
|
|
|
* This takes care of "--", for example.
|
|
|
|
*/
|
|
|
|
if (*place == place[-1]) {
|
|
|
|
++optind;
|
|
|
|
return (EOF);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the option is a separator or the option isn't in the list,
|
|
|
|
* we've got an error.
|
|
|
|
*/
|
|
|
|
optopt = (int)*place++;
|
|
|
|
oli = _sindex(ostr, optopt);
|
|
|
|
if (optopt == optneed || optopt == optmaybe || oli == NULL) {
|
|
|
|
/*
|
|
|
|
* If we're at the end of the current argument, bump the
|
|
|
|
* argument index.
|
|
|
|
*/
|
|
|
|
if (*place == '\0') {
|
|
|
|
++optind;
|
|
|
|
}
|
|
|
|
TELL(": illegal option -- "); /* byebye */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If there is no argument indicator, then we don't even try to
|
|
|
|
* return an argument.
|
|
|
|
*/
|
|
|
|
++oli;
|
|
|
|
if (*oli == '\0' || (*oli != optneed && *oli != optmaybe)) {
|
|
|
|
/*
|
|
|
|
* If we're at the end of the current argument, bump the
|
|
|
|
* argument index.
|
|
|
|
*/
|
|
|
|
if (*place == '\0') {
|
|
|
|
++optind;
|
|
|
|
}
|
|
|
|
optarg = NULL;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If we're here, there's an argument indicator. It's handled
|
|
|
|
* differently depending on whether it's a mandatory or an
|
|
|
|
* optional argument.
|
|
|
|
*/
|
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* If there's no white space, use the rest of the
|
|
|
|
* string as the argument. In this case, it doesn't
|
|
|
|
* matter if the argument is mandatory or optional.
|
|
|
|
*/
|
|
|
|
if (*place != '\0') {
|
|
|
|
optarg = place;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If we're here, there's whitespace after the option.
|
|
|
|
*
|
|
|
|
* Is it a mandatory argument? If so, return the
|
|
|
|
* next command-line argument if there is one.
|
|
|
|
*/
|
|
|
|
else if (*oli == optneed) {
|
|
|
|
/*
|
|
|
|
* If we're at the end of the argument list, there
|
|
|
|
* isn't an argument and hence we have an error.
|
|
|
|
* Otherwise, make 'optarg' point to the argument.
|
|
|
|
*/
|
|
|
|
if (nargc <= ++optind) {
|
|
|
|
place = EMSG;
|
|
|
|
TELL(": option requires an argument -- ");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
optarg = nargv[optind];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If we're here it must have been an optional argument.
|
|
|
|
*/
|
|
|
|
else {
|
|
|
|
if (nargc <= ++optind) {
|
|
|
|
place = EMSG;
|
|
|
|
optarg = NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
optarg = nargv[optind];
|
|
|
|
if (optarg == NULL) {
|
|
|
|
place = EMSG;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If the next item begins with a flag
|
|
|
|
* character, we treat it like a new
|
|
|
|
* argument. This is accomplished by
|
|
|
|
* decrementing 'optind' and returning
|
|
|
|
* a null argument.
|
|
|
|
*/
|
|
|
|
else if (_sindex(optstart, *optarg) != NULL) {
|
|
|
|
--optind;
|
|
|
|
optarg = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
place = EMSG;
|
|
|
|
++optind;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return option letter.
|
|
|
|
*/
|
|
|
|
return (optopt);
|
|
|
|
}
|