scanargs
utzoo!decvax!ucbvax!mhtsa!harpo!utah-cs!thomas
utzoo!decvax!ucbvax!mhtsa!harpo!utah-cs!thomas
Mon Feb 22 10:09:16 AEST 1982
/*
Version 7 compatible
Argument scanner, scans argv style argument list.
Some stuff is a kludge because sscanf screws up
Gary Newman - 10/4/1979 - Ampex Corp.
Modified by Spencer W. Thomas, Univ. of Utah, 5/81 to
add args introduced by a flag, add qscanargs call,
allow empty flags.
Compiling with QUICK defined generates 'qscanargs' ==
scanargs w/o floating point support; avoids huge size
of scanf.
If you make improvements we'd like to get them too.
Jay Lepreau lepreau at utah-20, decvax!{harpo,randvax}!utah-cs!lepreau
Spencer Thomas thomas at utah-20, decvax!{harpo,randvax}!utah-cs!thomas
(There seems to be a bug here in that if the last option you have
is a flag, and the user enters args incorrectly, sometimes the usage
message printed will miss the null and go flying off thru core...)
--jay for spencer
*/
#include <stdio.h>
#include <ctype.h>
#define YES 1
#define NO 0
#define ERROR(msg) {fprintf(stderr, "msg\n"); goto error; }
#ifndef QUICK
scanargs (argc, argv, format, arglist)
#else
qscanargs (argc, argv, format, arglist)
#endif
int argc;
char **argv;
char *format;
int arglist[];
{
#ifndef QUICK
_scanargs (argc, argv, format, &arglist);
#else
_qscanargs (argc, argv, format, &arglist);
#endif
}
#ifndef QUICK
_scanargs (argc, argv, format, arglist)
#else
_qscanargs (argc, argv, format, arglist)
#endif
int argc;
char **argv;
char *format;
int *arglist[];
{
register check; /* check counter to be sure all argvs
are processed */
register char *cp;
register cnt;
char tmpflg; /* temp flag */
char c;
char numnum; /* number of numbers already processed
*/
char numstr; /* count # of strings already
processed */
char tmpcnt; /* temp count of # things already
processed */
char required;
char exflag; /* when set, one of a set of exclusive
flags is set */
char excnt; /* count of which exclusive flag is
being processed */
char *ncp; /* remember cp during flag scanning */
#ifndef QUICK
char *cntrl; /* control string for scanf's */
char junk[2]; /* junk buffer for scanf's */
cntrl = "% %1s"; /* control string initialization for
scanf's */
#endif
check = numnum = numstr = 0;
cp = format;
while (*cp)
{
required = NO;
switch (*(cp++))
{
default: /* all other chars */
break;
case '!': /* required argument */
required = YES;
case '%': /* not required argument */
switch (tmpflg = *(cp++))
{
case '-': /* argument is flag */
/* go back to label */
ncp = cp-1; /* remember */
cp -= 3;
for (excnt = exflag = 0
; *cp != ' ' && !(*cp=='-' &&(cp[-1]=='!'||cp[-1]=='%'));
(--cp, excnt++))
{
for (cnt = 1; cnt < argc; cnt++)
{
/* flags all start with - */
if (*argv[cnt] == '-' && !isdigit(argv[cnt][1]))
if (*(argv[cnt] + 1) == *cp)
{
if (*(argv[cnt] + 2) != 0)
ERROR (extra flags ignored);
if (exflag)
ERROR (more than one exclusive flag chosen);
exflag++;
required = NO;
check += cnt;
**arglist |=
(1 << excnt);
break;
}
}
}
if (required)
ERROR (flag argument missing);
cp = ncp;
if (!exflag) /* if no flags scanned, skip */
{
while (*++cp != ' ' && *cp)
if (*cp == '!' || *cp == '%')
arglist++;
}
else
cp++; /* skip over - */
while (*cp == ' ')
cp++;
arglist++;
break;
case 's': /* char string */
case 'd': /* decimal # */
case 'o': /* octal # */
case 'x': /* hexadecimal # */
#ifndef QUICK
case 'f': /* floating # */
#endif
case 'D': /* long decimal # */
case 'O': /* long octal # */
case 'X': /* long hexadecimal # */
#ifndef QUICK
case 'F': /* double precision floating # */
#endif
tmpcnt = tmpflg == 's' ? numstr : numnum;
for (cnt = 1; cnt < argc; cnt++)
{
if (tmpflg == 's')/* string */
{
if ((c = *argv[cnt]) == '-')
continue;
if (c >= '0' && c <= '9')
continue;
if (tmpcnt-- != 0)
continue;
**arglist = argv[cnt];
check += cnt;
numstr++;
required = NO;
break;
}
if (*argv[cnt] == '-')
{
if(!isdigit (*(argv[cnt] + 1)))
continue;
}
else if (!isdigit(*argv[cnt]))
continue;
if (tmpcnt-- != 0)/* skip to new one */
continue;
#ifndef QUICK
/* kludge for sscanf */
if ((tmpflg == 'o' || tmpflg == 'O')
&& *argv[cnt] > '7')
ERROR (Bad numeric argument);
cntrl[1] = tmpflg;/* put in conversion */
if (sscanf (argv[cnt], cntrl, *arglist
,junk) != 1)
#else
if (numcvt(argv[cnt], tmpflg, *arglist) != 1)
#endif
ERROR (Bad numeric argument);
check += cnt;
numnum++;
required = NO;
break;
}
if (required)
switch (tmpflg)
{
case 'x':
case 'X':
ERROR (missing hexadecimal argument);
case 's':
ERROR (missing string argument);
case 'o':
case 'O':
ERROR (missing octal argument);
case 'd':
case 'D':
ERROR (missing decimal argument);
case 'f':
case 'F':
ERROR (missing floating argument);
}
arglist++;
while (*cp == ' ')
cp++;
break;
default: /* error */
fprintf (stderr, "error in call to scanargs\n");
return (0);
}
}
}
/* Count up empty flags */
for (cnt=1; cnt<argc; cnt++)
if (argv[cnt][0] == '-' && argv[cnt][1] == 0)
check += cnt;
/* sum from 1 to N = n*(n+1)/2 used to count up checks */
if (check != (((argc - 1) * argc) / 2))
ERROR (extra arguments not processed);
return (1);
error:
fprintf (stderr, "usage : ");
if (*(cp = format) != ' ')
while (putc (*cp++, stderr) != ' ');
else
fprintf (stderr, "?? ");
while (*cp == ' ')
cp++;
prformat (cp, NO);
return 0;
}
prformat (format, recurse)
char *format;
{
register char *cp;
char required;
cp = format;
if (recurse)
putc (' ', stderr);
required = NO;
while (*cp)
{
if (recurse && *cp == ' ')
break;
switch (*cp)
{
default:
cp++;
break;
case '!':
required = YES;
case '%':
switch (*++cp)
{
case '-': /* flags */
if (!required)
{
putc ('[', stderr);
putc ('-', stderr);
}
else
{
putc ('-', stderr);
putc ('{', stderr);
}
cp = format;
while (*cp != '%' && *cp != '!')
putc (*cp++, stderr);
if (required)
putc ('}', stderr);
cp += 2; /* skip !- or %- */
if (*cp != ' ')
cp = prformat (cp, YES);
/* this is a recursive call */
if (!required)
putc (']', stderr);
break;
case 's': /* char string */
case 'd': /* decimal # */
case 'o': /* octal # */
case 'x': /* hexadecimal # */
case 'f': /* floating # */
case 'D': /* long decimal # */
case 'O': /* long octal # */
case 'X': /* long hexadecimal # */
case 'F': /* double precision floating # */
if (!required)
putc ('[', stderr);
for (; format < cp - 1; format++)
putc (*format, stderr);
if (!required)
putc (']', stderr);
break;
default:
break;
}
required = NO;
format = ++cp;
putc (' ', stderr);
}
}
if (!recurse)
putc ('\n', stderr);
return (cp);
}
#ifdef QUICK
numcvt(str, conv, val)
register char *str;
char conv;
int *val;
{
int base, neg = 0;
register unsigned int d;
long retval = 0;
register char *digits;
extern char *index();
if (conv == 'o' || conv == 'O')
base = 8;
else if (conv == 'd' || conv == 'D')
base = 10;
else if (conv == 'x' || conv == 'X')
base = 16;
else
return 0;
if (*str == '-')
{
neg = 1;
str++;
}
while (*str)
{
if (*str >= '0' && *str < '0'+base)
d = *str - '0';
else if (base == 16 && *str >= 'a' && *str <= 'f')
d = 10 + *str - 'a';
else if (base == 16 && *str >= 'A' && *str <= 'F')
d = 10 + *str - 'A';
else
return 0;
retval = retval*base + d;
str++;
}
if (neg)
retval = -retval;
if (conv == 'D' || conv == 'O' || conv == 'X')
*(long *) val = retval;
else
*val = (int) retval;
return 1;
}
#endif QUICK
More information about the Comp.sources.unix
mailing list