home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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
- */
-
- /*
- * If you want, include stdio.h or something where EOF and NULL are defined.
- * However, egetopt() is written so as not to need stdio.h, which should
- * make it significantly smaller on some systems.
- */
-
- #ifndef EOF
- # define EOF (-1)
- #endif /* ! EOF */
-
- #ifndef NULL
- # define NULL (char *)0
- #endif /* ! NULL */
-
- /*
- * 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 ERRFD 2
- #define EMSG ""
- #define START "-"
-
- /*
- * Here are all the pertinent global variables.
- */
- int opterr = 1; /* if true, output error message */
- int optind = 1; /* index into parent argv vector */
- int optopt; /* character checked for validity */
- int optbad = BADCH; /* character returned on error */
- int optchar = 0; /* character that begins returned option */
- int optneed = NEEDSEP; /* flag for mandatory argument */
- int optmaybe = MAYBESEP;/* flag for optional argument */
- int opterrfd = ERRFD; /* file descriptor for error text */
- char *optarg; /* argument associated with option */
- char *optstart = START; /* list of characters that start options */
-
-
- /*
- * Macros.
- */
-
- /*
- * Conditionally print out an error message and return (depends on the
- * setting of 'opterr' and 'opterrfd'). Note that this version of
- * TELL() doesn't require the existence of stdio.h.
- */
- #define TELL(S) { \
- if (opterr && opterrfd >= 0) { \
- char option = optopt; \
- write(opterrfd, *nargv, strlen(*nargv)); \
- write(opterrfd, (S), strlen(S)); \
- write(opterrfd, &option, 1); \
- write(opterrfd, "\n", 1); \
- } \
- 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.
- */
- static char *
- _sindex(string, ch)
- char *string;
- int ch;
- {
- if (string != NULL) {
- for (; *string != '\0'; ++string) {
- if (*string == (char)ch) {
- return (string);
- }
- }
- }
-
- return (NULL);
- }
-
- /*
- * Here it is:
- */
- int
- egetopt(nargc, nargv, ostr)
- int nargc;
- char **nargv;
- char *ostr;
- {
- static char *place = EMSG; /* option letter processing */
- register char *oli; /* option letter list index */
- register char *osi = NULL; /* option start list index */
-
- 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);
- }
-