home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume10
/
parseargs
/
unix_args.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-02-16
|
7KB
|
366 lines
#include <useful.h>
#include <parseargs.h>
#include <ctype.h>
VERSIONID("$Header: parseargs.c,v 2.1 89/12/30 20:59:48 eric Exp $");
/*
** PARSEARGS -- parse an argument vector, given a description
**
** Parameters:
** argv -- pointer to the argument vector as passed to main().
** argd -- the argument descriptor array.
**
** Returns:
** Nothing.
** Exits with return code 2 if error in args.
** Exits with return code 1 if system error.
**
** Side Effects:
** Converts and stores arguments into variables as
** described by argd.
**
** Globals:
** DefaultPath -- the pathname of a set of places to
** look for system files, set from the ROOTPATH
** environment variable, or a default.
** ProgName -- the name of this program, saved for error
** messages and the like.
**
** Author:
** Eric Allman
** University of California, Berkeley
*/
#define ALL_AD ad = argd; ad->ad_name != '\0'; ad++
#define ALL_DEFS ad = _DefaultArgs; ad->ad_name != '\0'; ad++
char *ProgName;
#ifdef TRACESTUFF
extern BOOL argTrace ARGS((ARGDESC *, char *, BOOL));
#endif
extern BOOL argEnd ARGS((ARGDESC *, char *, BOOL));
/* default arguments -- apply to all programs */
STATIC ARGDESC _DefaultArgs[] =
{
/* name flags type valp prompt */
#ifdef TRACESTUFF
'T', ARGOPT, argTrace, ARBNULL, "TRACE",
#endif
'-', ARGOPT, argEnd, ARBNULL, "ARGS",
ENDOFARGS
};
/* override argument descriptor, if none given by user */
STATIC ARGDESC _NullArgDesc[] =
{
ENDOFARGS
};
VOID
parseargs(argv, argd)
char **argv;
ARGDESC argd[];
{
register ARGDESC *ad, *list;
register char **av;
register char *p;
int argc;
BOOL noflags;
BOOL error;
#ifdef INTERACTIVE
BOOL shouldprompt;
#endif
extern char *getenv ARGS((char *));
#ifdef INTERACTIVE
extern int isatty ARGS((int));
#endif
av = argv++;
argc = 1;
/* save the name of this program (for error messages) */
ProgName = *av;
#ifdef INTERACTIVE
/* test to see if we are interactive */
shouldprompt = (BOOL) isatty(0) && (BOOL) isatty(2);
#endif
/* allow null argument descriptor */
if (argd == (ARGDESC *) NULL)
argd = _NullArgDesc;
/* clear out any cruft in the argument descriptor */
for (ALL_AD)
{
ad->ad_flags &= ~ARGGIVEN;
}
for (ALL_DEFS)
{
ad->ad_flags &= ~ARGGIVEN;
}
/* run through the argument vector */
noflags = FALSE;
error = FALSE;
list = NULL;
while ((p = *++av) != CHARNULL)
{
if (*p == '-' && !noflags)
{
/* flag argument */
if (*++p == '-' && p[1] == '\0')
{
/* -- indicates end of flags */
noflags = TRUE;
list = NULL;
continue;
}
while (*p != '\0')
{
/* find the flag in the list */
for (ALL_AD)
{
if (ad->ad_name == *p)
break;
}
if (ad->ad_name == '\0')
{
for (ALL_DEFS)
{
if (ad->ad_name == *p)
break;
}
if (ad->ad_name == '\0')
{
usrerr("flag -%c unknown", *p++);
error = TRUE;
continue;
}
}
/* move p up to point to the (possible) value */
p++;
/* booleans are special, having no value */
if (ad->ad_type == argBool)
{
*(BOOL *) ad->ad_valp = TRUE;
ad->ad_flags |= ARGGIVEN;
continue;
}
#ifdef TRACESTUFF
else if (ad->ad_type == argTrace)
{
traceset(p);
ad->ad_flags |= ARGGIVEN;
break;
}
#endif
/* now get the real value */
if (*p == '\0')
{
p = *++av;
if (p == CHARNULL || *p == '-')
{
av--;
usrerr("%s required for -%c flag",
ad->ad_prompt, ad->ad_name);
error = TRUE;
break;
}
}
/* try to convert the type */
if (!(*ad->ad_type)(ad, p, FALSE))
error = TRUE;
else
ad->ad_flags |= ARGGIVEN;
if(ad->ad_type == argList)
list = ad;
else
list = NULL;
break;
}
}
else
{
/* parsing a list of arguments */
if(list) {
if (!argList(list, p, FALSE))
error = TRUE;
continue;
}
/* positional argument */
for (ALL_AD)
{
if (ad->ad_name == ' ' &&
(ad->ad_type == argList ||
!BITSET(ARGGIVEN, ad->ad_flags))
)
break;
}
if (ad->ad_name == '\0')
{
usrerr("too any arguments");
error = 1;
continue;
}
/* try to convert */
if (!(*ad->ad_type)(ad, p, FALSE))
error = TRUE;
else
ad->ad_flags |= ARGGIVEN;
}
}
/* now rescan for missing required arguments */
for (ALL_AD)
{
if (BITSET(ARGREQ, ad->ad_flags) && !BITSET(ARGGIVEN, ad->ad_flags))
{
#ifdef INTERACTIVE
/* can we prompt? */
while (shouldprompt && !error)
{
char buf[MAXINPUTLINE];
fprintf(stderr, "%s? ", ad->ad_prompt);
fflush(stderr);
if (fgets(buf, sizeof buf, stdin) == CHARNULL)
break;
p = strchr(buf, '\n');
if (p != CHARNULL)
*p = '\0';
if (buf[0] == '\0')
{
usrerr("value required");
continue;
}
if ((*ad->ad_type)(ad, buf, TRUE))
{
ad->ad_flags |= ARGGIVEN;
break;
}
}
#endif
if (!BITSET(ARGGIVEN, ad->ad_flags))
{
/* still didn't get a value... sigh */
if (ad->ad_name == ' ')
{
usrerr("%s required",
ad->ad_prompt);
}
else
{
usrerr("%s required for -%c flag",
ad->ad_prompt, ad->ad_name);
}
error = TRUE;
}
}
}
if (error)
{
usage(argd);
exit(2);
}
return argc;
}
/*
** USAGE -- print a usage message
**
** Parameters:
** argd -- the description of expected arguments.
**
** Returns:
** none
**
** Side Effects:
** prints on stderr
**
** Globals:
** MaxOutputLine -- the length of the maximum output line
** allowed before wrapping. This should be fetched
** from the terminal driver on systems that support
** this sort of thing.
*/
int MaxOutputLine = 72;
VOID
usage(argd)
ARGDESC *argd;
{
register ARGDESC *ad;
int ll;
int pl;
fprintf(stderr, "Usage: %s", ProgName);
ll = strlen(ProgName) + 7;
for (ALL_AD)
{
/* don't display hidden arguments */
if (BITSET(ARGHIDDEN, ad->ad_flags))
continue;
/* figure out how wide this parameter is (for printing) */
if (ad->ad_name != ' ')
{
pl = 2; /* -x */
if (ad->ad_type != argBool)
pl += strlen(ad->ad_prompt) + 3;/* _< > */
}
else
{
pl = strlen(ad->ad_prompt) + 2; /* < > */
}
if (!BITSET(ARGREQ, ad->ad_flags))
pl += 2; /* [ ] */
if (ad->ad_type == argList) /* ... */
pl += 3;
pl += 1; /* leading sp */
/* see if this will fit */
if (ll + pl > MaxOutputLine)
{
/* no... start a new line */
fprintf(stderr, " \\\n\t");
ll = 7;
}
else
{
/* yes... just throw in a space */
fprintf(stderr, " ");
}
ll += pl;
/* show the argument */
if (!BITSET(ARGREQ, ad->ad_flags))
fprintf(stderr, "[");
if (ad->ad_name != ' ')
{
fprintf(stderr, "-%c", ad->ad_name);
if (ad->ad_type != argBool)
fprintf(stderr, " ");
}
if (ad->ad_name == ' ' || ad->ad_type != argBool)
fprintf(stderr, "<%s>", ad->ad_prompt);
if (!BITSET(ARGREQ, ad->ad_flags))
fprintf(stderr, "]");
if (ad->ad_type == argList)
fprintf(stderr, "...");
}
fprintf(stderr, "\n");
}