home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 10
/
aminetcdnumber101996.iso
/
Aminet
/
misc
/
unix
/
sploiner.lha
/
source.lha
/
getopt.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-09-07
|
8KB
|
303 lines
/****************************************************************************
* getopt(): Return the next user option on each iteration.
* This is a clone of the usual UNIX getopt() function.
* If you have never used a getopt() before, you'll have to
* read about it on any UNIX machine or other C system that
* documents it.
*
* Author: Daniel J. Barrett, barrett@cs.umass.edu.
*
* License: This code is placed in the Public Domain.
* Give it away to anybody for free!
* Use it for any purpose you like!
*
* If you use this code in a program, please give me credit
* for my work. Thanks!
*
* Why I wrote it:
*
* Because every other getopt() function I have ever seen
* had source code that was difficult to understand.
* I wrote this code to be very modular and readable.
* I hope you find it instructive and/or helpful.
*
* BUGS
* "--JUNK" is treated as "--", the "end of options" flag.
*
* REVISION HISTORY:
*
* Version: 1.3
* Date: January 21, 1993
* Comments: Bugfix. Option "-:" was accepted as OK. Not anymore.
*
* Version: 1.2a
* Date: January 21, 1993
* Comments: Improved the TESTME main program. More useful output.
* Rewrote Error() to eliminate redundancy.
*
* Version: 1.2
* Date: January 21, 1993
* Comments: If a legal option is not followed by a required
* argument, getopt() previously returned the option's
* character. It should have returned UNKNOWN_OPT.
* This has been fixed. Note that HandleArgument()
* now returns an int value rather than void.
*
* Version: 1.1b
* Date: December 17, 1991.
* Comments: Minor change of NULL to '\0' in 1 spot.
*
* Version: 1.1
* Date: February 20, 1991.
* Comments: Bug fix in Pass(). Forgot to check that the
* current argument is non-empty and starts with
* a DASH.
*
* Got rid of the unnecessary "g_" at the beginning
* of each function name. Since they're static, we
* don't have to worry about duplication of names
* by the calling program.
*
* Version: 1.0
* Date: April 12, 1990.
* Comments: First released version.
*
****************************************************************************/
#ifndef __STDIO_H /* If we haven't already included stdio.h, do it. */
# include <stdio.h> /* Maybe someday I'll eliminate this. */
#endif
#ifndef __STRING_H
# include <string.h> /* For strchr() */
#endif
/************************************************************************
* Some constants.
************************************************************************/
#define DASH '-' /* This preceeds an option. */
#define ARG_COMING ':' /* In the option string, this indicates that
* that the option requires an argument. */
#define UNKNOWN_OPT '?' /* The char returned for unknown option. */
/************************************************************************
* Internal error codes.
************************************************************************/
#define ERROR_BAD_OPTION 1
#define ERROR_MISSING_ARGUMENT 2
/************************************************************************
* ANSI function prototypes.
************************************************************************/
int getopt(int argc, char *argv[], char *optString);
static int NextOption(char *argv[], char *optString);
static int RealOption(char *argv[], char *str, int *skip, int *ind,
int opt);
static int HandleArgument(char *argv[], int *optind, int *skip);
static void Error(int err, int c);
static void Pass(char *argv[], int *optind, int *optsSkipped);
/************************************************************************
* Global variables. You must declare these externs in your program
* if you want to see their values!
************************************************************************/
char *optarg = NULL; /* This will point to a required argument, if any. */
int optind = 1; /* The index of the next argument in argv. */
int opterr = 1; /* 1 == print internal error messages. 0 else. */
int optopt; /* The actual option letter that was found. */
int getopt(int argc, char *argv[], char *optString)
{
optarg = NULL;
if (optind < argc) /* More arguments to check. */
return(NextOption(argv, optString));
else /* We're done. */
return(EOF);
}
/* If the current argument does not begin with DASH, it is not an option.
* Return EOF.
* If we have ONLY a DASH, and nothing after it... return EOF as well.
* If we have a DASH followed immediately by another DASH, this is the
* special "--" option that means "no more options follow." Return EOF.
* Otherwise, we have an actual option or list of options. Process it. */
static int NextOption(char *argv[], char *optString)
{
static int optsSkipped = 0; /* In a single argv[i]. */
if ((argv[optind][0] == DASH)
&& ((optopt = argv[optind][1+optsSkipped]) != '\0'))
{
if (optopt == DASH)
{
optind++;
return(EOF);
}
else
return(RealOption(argv, optString, &optsSkipped,
&optind, optopt));
}
else
return(EOF);
}
/* At this point, we know that argv[optind] is an option or list of
* options. If this is a list of options, *optsSkipped tells us how
* many of those options have ALREADY been parsed on previous calls
* to getopt().
* If the option is not legal (not in optString), complain and return
* UNKNOWN_OPT.
* If the option requires no argument, just return the option letter.
* If the option requires an argument, call HandleArgument and return
* the option letter. */
static int RealOption(char *argv[], char *optString, int *optsSkipped,
int *optind, int optopt)
{
char *where; /* Pointer to the letter in optString. */
int argWasOK; /* An indication that a required arg was found. */
(*optsSkipped)++;
if (optopt == ARG_COMING) /* Special case of "-:" */
{
Error(ERROR_BAD_OPTION, optopt);
Pass(argv, optind, optsSkipped);
return(UNKNOWN_OPT);
}
else if ((where = strchr(optString, optopt)) != NULL)
{
argWasOK = 1; /* Assume any argument will be found. */
if (*(where+1) == ARG_COMING)
argWasOK = HandleArgument(argv, optind, optsSkipped);
Pass(argv, optind, optsSkipped);
return(argWasOK ? optopt : UNKNOWN_OPT);
}
else
{
Error(ERROR_BAD_OPTION, optopt);
Pass(argv, optind, optsSkipped);
return(UNKNOWN_OPT);
}
}
/* We have an option in argv[optind] that requires an argument. If there
* is no whitespace after the option letter itself, take the rest of
* argv[optind] to be the argument.
* If there IS whitespace after the option letter, take argv[optind+1] to
* be the argument.
* Otherwise, if there is NO argument, complain!
* Return 1 on success, 0 on error.
*/
static int HandleArgument(char *argv[], int *optind, int *optsSkipped)
{
int OK;
if (argv[*optind][1+(*optsSkipped)])
{
optarg = argv[*optind] + 1 + (*optsSkipped);
OK = 1;
}
else if (argv[(*optind)+1])
{
optarg = argv[(*optind)+1];
(*optind)++;
OK = 1;
}
else
{
Error(ERROR_MISSING_ARGUMENT, optopt);
OK = 0;
}
(*optsSkipped) = 0;
(*optind)++;
return(OK);
}
/* Print an appropriate error message. */
static void Error(int err, int c)
{
if (opterr)
{
fprintf(stderr, "-%c: ", c);
switch (err)
{
case ERROR_BAD_OPTION:
fprintf(stderr, "Illegal option.\n");
break;
case ERROR_MISSING_ARGUMENT:
fprintf(stderr,
"An argument is required, but missing.\n");
break;
default:
fprintf(stderr,
"An unknown error occurred.\n");
break;
}
}
}
/* We have reached the end of argv[optind]... there are no more options
* in it to parse. Skip to the next item in argv. */
static void Pass(char *argv[], int *optind, int *optsSkipped)
{
if (argv[*optind]
&& (argv[*optind][0] == DASH)
&& (argv[*optind][1+(*optsSkipped)] == '\0'))
{
(*optind)++;
(*optsSkipped) = 0;
}
}
/***************************************************************************
* A test program. Compile this file with -DTESTME as an option.
***************************************************************************/
#ifdef TESTME
main(int argc, char *argv[])
{
char c;
int i;
while ((c = getopt(argc, argv, "a:b:cde")) != EOF)
{
printf("OPTION %c", c);
if ((c == 'a') || (c == 'b'))
printf(", arg=\"%s\"\n", optarg);
else
printf("\n");
}
for (i=optind; i<argc; i++)
{
printf("Arg %d (argv[%d]): \"%s\"\n",
i - optind + 1,
i,
argv[i]);
}
exit(0);
}
#endif