|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 6949 (0x1b25)
Types: TextFile
Notes: UNIX file
Names: »scanf.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »libc/stdio/scanf.c«
/*
* Standard I/O Library formatted input
* Non-portable things:
* 1) alignment of arguments is assumed to be completely contiguous.
*/
#include <stdio.h>
union alltypes {
char *c;
short *h;
int *i;
unsigned *u;
long *l;
double *d;
char *s;
};
/*
* scan standard input
*/
int
scanf(args)
union alltypes args;
{
return (xscanf(stdin, &args));
}
/*
* scan given file
*/
int
fscanf(fp, args)
FILE *fp;
union alltypes args;
{
return (xscanf(fp, &args));
}
/*
* scan given string by handcrafting file structure for getc
*/
int
sscanf(sp, args)
char *sp;
union alltypes args;
{
FILE file;
_stropen(sp, strlen(sp), &file);
return (xscanf(&file, &args));
}
static
int
xscanf(fp, argp)
FILE *fp;
union alltypes *argp;
{
register int fc, gc;
int base, width, gotany, supprf, longf, shortf, retval = 0;
char *fmt;
extern char *index();
fmt = *(char **)argp++;
for (;;) {
switch (fc = *fmt++) {
case '\0':
break;
case '\t':
case '\n':
case ' ':
ungetc(gc=skipws(fp), fp);
if (gc == EOF)
break;
else
continue;
default:
matchin:
if ((gc=getc(fp)) != fc) {
ungetc(gc, fp);
break;
} else
continue;
case '%':
supprf = (fc = *fmt++) == '*';
if (supprf)
fc = *fmt++;
for (width = 0; '0'<=fc && fc<='9'; fc = *fmt++)
width = width*10 + fc - '0';
longf = fc=='l';
shortf = fc=='h';
if (longf || shortf)
fc = *fmt++;
switch (fc) {
default:
fputs("Bad format in scanf\n", stderr);
abort();
case '\0':
break;
case '%':
goto matchin;
case 'D':
longf++;
case 'd':
base = 10;
goto fixed;
case 'O':
longf++;
case 'o':
base = 8;
goto fixed;
case 'N':
longf++;
case 'n':
base = 0;
goto fixed;
case 'X':
longf++;
case 'x':
base = 16;
fixed:
{
long longn, fgetnum();
longn = fgetnum(fp, base, width, &gotany);
if (!gotany)
break;
if (supprf)
continue;
if (longf)
**(long **)argp++ = longn;
else if (shortf)
**(short **)argp++ = longn;
else
**(int **)argp++ = longn;
retval++;
continue;
}
case 'E':
case 'F':
longf++;
case 'e':
case 'f':
{
double doublen, fgetdbl();
doublen = fgetdbl(fp, width, &gotany);
if (!gotany)
break;
if (supprf)
continue;
if (longf)
**(double **)argp++ = doublen;
else
**(float **)argp++ = doublen;
retval++;
continue;
}
case '[':
{
char ss[64], *s = ss;
int breakf;
register char *cp;
breakf = (fc = *fmt++) == '^';
if (breakf)
fc = *fmt++;
while (fc!='\0' && fc!=']') {
*s++ = fc;
fc = *fmt++;
}
*s = '\0';
s = ss;
gc = getc(fp);
goto scanin;
case 'c':
if (width==0)
width = 1;
gc = getc(fp);
s = "";
breakf = 1;
goto scanin;
case 's':
gc = skipws(fp);
s = "\t\n ";
breakf = 1;
scanin:
if (!supprf)
cp = *(char **)argp++;
gotany = 0;
while (gc!=EOF
&& (index(s, gc)==NULL) == breakf) {
gotany++;
if (!supprf)
*cp++ = gc;
if (--width==0)
gc = EOF;
else
gc = getc(fp);
}
if (gc!=EOF)
ungetc(gc, fp);
if (!gotany)
break;
if (supprf)
continue;
if (fc!='c')
*cp = '\0';
retval++;
continue;
}
}
break;
}
break;
}
return (retval==0&&feof(fp) ? EOF : retval);
}
/*
* Read a long integer from file fp
*/
static
long
fgetnum(fp, base, width, got)
FILE *fp;
register int base, width;
int *got;
{
long val = 0;
register int c, i;
int neg;
if (width <= 0 || 32 < width)
width = 32;
*got = 0;
c = skipws(fp);
if ((neg=c=='-') || c=='+')
c = getc(fp), ++*got;
if (*got>width)
;
else if (base!=0)
;
else if (c!='0')
base = 10;
else if (c=getc(fp), ++*got>width)
;
else if (c!='x')
base = 8;
else {
base = 16;
c = getc(fp), ++*got;
}
for (; *got < width; ++*got) {
if ((10<=(i=c-('a'-10))
|| 10<=(i=c-('A'-10))
|| 0<=(i=c-'0') && i<=9)
&& i<base
|| base==16 && val==0 && (i=c-'x')==0) {
val = val*base - i;
c = getc(fp);
} else
break;
}
ungetc(c, fp);
return (neg ? val : -val);
}
/*
* Scan off floating point number into buffer for atof
* using automaton shown below
* states in parantheses
* inputs in brackets
* for all inputs not shown, transition is to (end)
*
* --
* / \
* v \
* ----------> [0-9] -> (3)
* / ^ | \
* / / | \
* / / v \
* / / [.] \ ->[+-] -
* / / | \ / \
* / / | \ / \
* / / v v / v
* (0) --> [+-] -> (1) (4) --> [Ee] -> (6) -> [0-9] -> (7)
* \ / / ^ ^ /
* \ / / / \ /
* \ / / / --
* \ / / /
* \ / / /
* \ / / /
* v v /
* [.] --> (2) -> [0-9] -> (5)
* ^ /
* \ /
* --
*
*/
static
double
fgetdbl(fp, width, got)
FILE *fp;
int width, *got;
{
double atof();
register int c, state = 0;
char str[33];
register char *s = str;
if (width<=0 || 32<width)
width = 32;
for (*got = 0; *got < width; ++*got) {
switch (c=getc(fp)) {
case '\t':
case '\n':
case ' ':
if (state!=0)
break;
--*got;
continue;
case '+':
case '-':
if (state!=0 && state!=6)
break;
state++;
*s++ = c;
continue;
case '.':
if (state<=1)
state = 2;
else if (state==3)
state++;
else
break;
*s++ = c;
continue;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (state==0 || state==1 || state==3)
state = 3;
else if (state==2 || state==4 || state==5)
state = 5;
else if (state==6 || state==7)
state = 7;
else
break;
*s++ = c;
continue;
case 'E':
case 'e':
if (state<3 || 5<state)
break;
state = 6;
*s++ = c;
continue;
default:
break;
}
ungetc(c, fp);
break;
}
*s = '\0';
return (atof(str));
}
static
int
skipws(fp)
FILE *fp;
{
register int c;
while ((c=getc(fp))==' ' || c=='\n' || c=='\t')
;
return (c);
}