home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
files
/
language
/
sozobon2
/
scanf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-23
|
8KB
|
421 lines
#include <stdio.h>
#include <ctype.h>
extern char _numstr[];
/* #define skip() do{c=(*get)(ip); if (c<1) goto done;}while(isspace(c))*/
#define skip() while(isspace(c)) { if ((c=(*get)(ip))<1) goto done; }
#if FLOATS
/* fp scan actions */
#define F_NADA 0 /* just change state */
#define F_SIGN 1 /* set sign */
#define F_ESIGN 2 /* set exponent's sign */
#define F_INT 3 /* adjust integer part */
#define F_FRAC 4 /* adjust fraction part */
#define F_EXP 5 /* adjust exponent part */
#define F_QUIT 6
#define NSTATE 8
#define FS_INIT 0 /* initial state */
#define FS_SIGNED 1 /* saw sign */
#define FS_DIGS 2 /* saw digits, no . */
#define FS_DOT 3 /* saw ., no digits */
#define FS_DD 4 /* saw digits and . */
#define FS_E 5 /* saw 'e' */
#define FS_ESIGN 6 /* saw exp's sign */
#define FS_EDIGS 7 /* saw exp's digits */
#define FC_DIG 0
#define FC_DOT 1
#define FC_E 2
#define FC_SIGN 3
/* given transition,state do what action? */
int fp_do[][NSTATE] = {
{F_INT,F_INT,F_INT,
F_FRAC,F_FRAC,
F_EXP,F_EXP,F_EXP}, /* see digit */
{F_NADA,F_NADA,F_NADA,
F_QUIT,F_QUIT,F_QUIT,F_QUIT,F_QUIT}, /* see '.' */
{F_QUIT,F_QUIT,
F_NADA,F_QUIT,F_NADA,
F_QUIT,F_QUIT,F_QUIT}, /* see e/E */
{F_SIGN,F_QUIT,F_QUIT,F_QUIT,F_QUIT,
F_ESIGN,F_QUIT,F_QUIT}, /* see sign */
};
/* given transition,state what is new state? */
int fp_ns[][NSTATE] = {
{FS_DIGS,FS_DIGS,FS_DIGS,
FS_DD,FS_DD,
FS_EDIGS,FS_EDIGS,FS_EDIGS}, /* see digit */
{FS_DOT,FS_DOT,FS_DD,
}, /* see '.' */
{0,0,
FS_E,0,FS_E,
}, /* see e/E */
{FS_SIGNED,0,0,0,0,
FS_ESIGN,0,0}, /* see sign */
};
/* which states are valid terminators? */
int fp_sval[NSTATE] = {
0,0,1,0,1,0,0,1
};
#endif
_scanf(ip, get, unget, fmt, args)
register unsigned char *ip;
int (*get)();
int (*unget)();
register unsigned char *fmt;
char **args;
{
register long n;
register int c, width, lval, cnt = 0;
int store, neg, base, wide1, endnull, rngflag, c2;
register unsigned char *p;
unsigned char delim[128], digits[17], *q;
char *strchr(), *strcpy();
#if FLOATS
long frac, expo;
int eneg, fraclen, fstate, trans;
double fx, fp_scan();
#endif
if (!*fmt)
return(0);
c = (*get)(ip);
while(c > 0)
{
store = FALSE;
if (*fmt == '%')
{
n = 0;
width = -1;
wide1 = 1;
base = 10;
lval = FALSE;
store = TRUE;
endnull = TRUE;
neg = -1;
strcpy(delim, "\011\012\013\014\015 ");
strcpy(digits, _numstr); /* "01234567890ABCDEF" */
if (fmt[1] == '*')
{
endnull = store = FALSE;
++fmt;
}
while (isdigit(*++fmt)) /* width digit(s) */
{
if (width == -1)
width = 0;
wide1 = width = (width * 10) + (*fmt - '0');
}
--fmt;
fmtnxt:
++fmt;
switch(tolower(*fmt)) /* tolower() is a MACRO! */
{
case '*':
endnull = store = FALSE;
goto fmtnxt;
case 'l': /* long data */
lval = TRUE;
/* for compatability --> */ case 'h': /* short data */
goto fmtnxt;
case 'i': /* any-base numeric */
base = 0;
goto numfmt;
case 'b': /* unsigned binary */
base = 2;
goto numfmt;
case 'o': /* unsigned octal */
base = 8;
goto numfmt;
case 'x': /* unsigned hexadecimal */
base = 16;
goto numfmt;
case 'd': /* SIGNED decimal */
neg = FALSE;
/* FALL-THRU */
case 'u': /* unsigned decimal */
numfmt: skip();
if (isupper(*fmt))
lval = TRUE;
if (!base)
{
base = 10;
neg = FALSE;
if (c == '%')
{
base = 2;
goto skip1;
}
else if (c == '0')
{
c = (*get)(ip);
if (c < 1)
goto savnum;
if ((c != 'x')
&& (c != 'X'))
{
base = 8;
digits[8]= '\0';
goto zeroin;
}
base = 16;
goto skip1;
}
}
if ((neg == FALSE) && (base == 10)
&& ((neg = (c == '-')) || (c == '+')))
{
skip1:
c = (*get)(ip);
if (c < 1)
goto done;
}
digits[base] = '\0';
p = ((unsigned char *)
strchr(digits,toupper(c)));
if ((!c || !p) && width)
goto done;
while (p && width-- && c)
{
n = (n * base) + (p - digits);
c = (*get)(ip);
zeroin:
p = ((unsigned char *)
strchr(digits,toupper(c)));
}
savnum:
if (store)
{
p = ((unsigned char *) *args);
if (neg == TRUE)
n = -n;
if (lval)
*((long*) p) = n;
else
*((int *) p) = n;
++cnt;
}
break;
#if FLOATS
case 'e': /* float */
case 'f':
case 'g':
skip();
if (isupper(*fmt))
lval = TRUE;
fstate = FS_INIT;
neg = FALSE; eneg = FALSE;
n = 0; frac = 0; expo = 0;
fraclen = 0;
while (c && width--) {
if (c >= '0' && c <= '9')
trans = FC_DIG;
else if (c == '.')
trans = FC_DOT;
else if (c == '+' || c == '-')
trans = FC_SIGN;
else if (tolower(c) == 'e')
trans = FC_E;
else
goto fdone;
switch (fp_do[trans][fstate]) {
case F_SIGN:
neg = (c == '-');
break;
case F_ESIGN:
eneg = (c == '-');
break;
case F_INT:
n = 10*n + (c - '0');
break;
case F_FRAC:
frac = 10*frac + (c - '0');
fraclen++;
break;
case F_EXP:
expo = 10*expo + (c - '0');
break;
case F_QUIT:
goto fdone;
}
fstate = fp_ns[trans][fstate];
c = (*get)(ip);
}
fdone:
if (!fp_sval[fstate])
goto done;
if (store) {
fx = fp_scan(neg, eneg,
n, frac, expo, fraclen);
p = (unsigned char *) *args;
if (lval)
*((double *) p) = fx;
else
*((float *) p) = fx;
++cnt;
}
break;
#endif
case 'c': /* character data */
width = wide1;
endnull = FALSE;
delim[0] = '\0';
goto strproc;
case '[': /* string w/ delimiter set */
/* get delimiters */
p = delim;
if (*++fmt == '^')
fmt++;
else
lval = TRUE;
rngflag = 2;
if ((*fmt == ']') || (*fmt == '-'))
{
*p++ = *fmt++;
rngflag = FALSE;
}
while (*fmt != ']')
{
if (*fmt == '\0')
goto done;
switch (rngflag)
{
case TRUE:
c2 = *(p-2);
if (c2 <= *fmt)
{
p -= 2;
while (c2 < *fmt)
*p++ = c2++;
rngflag = 2;
break;
}
/* fall thru intentional */
case FALSE:
rngflag = (*fmt == '-');
break;
case 2:
rngflag = FALSE;
}
*p++ = *fmt++;
}
*p = '\0';
goto strproc;
case 's': /* string data */
skip();
strproc:
/* process string */
p = ((unsigned char *) *args);
/* if the 1st char fails, match fails */
if (width)
{
q = ((unsigned char *)
strchr(delim, c));
if((c < 1)
|| (lval ? !q : (int) q))
{
if (endnull)
*p = '\0';
goto done;
}
}
for (;;) /* FOREVER */
{
if (store)
*p++ = c;
if (((c = (*get)(ip)) < 1) ||
(--width == 0))
break;
q = ((unsigned char *)
strchr(delim, c));
if (lval ? !q : (int) q)
break;
}
if (store)
{
if (endnull)
*p = '\0';
++cnt;
}
break;
case '\0': /* early EOS */
--fmt;
/* FALL THRU */
default:
goto cmatch;
}
}
else if (isspace(*fmt)) /* skip whitespace */
{
skip();
}
else
{ /* normal match char */
cmatch:
if (c != *fmt)
break;
c = (*get)(ip);
}
if (store)
args++;
if (!*++fmt)
break;
}
done: /* end of scan */
if ((c < 0) && (cnt == 0))
return(EOF);
(*unget)(c, ip);
return(cnt);
}