Files
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

530 lines
9.9 KiB
C

/*
Copyright 1982, 1983
Alcyon Corporation
8716 Production Ave.
San Diego, Ca. 92121
@(#)fscanf.c 1.1 11/9/83
*/
/*
** formatted read routine
**
** functionally equivalent to scanf in portable C library
*/
#include <stdio.h>
#include <math.h>
/* Delimiters */
#define NEWLINE '\n'
#define TAB '\t'
#define SPACE ' '
#define NULL '\0'
/* returns from __next() */
#define CHAR 0
#define NOT_WHT -1
#define NOT_WHT_NL 1
/* returns from __scan() */
#define NORETURN 0
#define VALID 1
#define NOMATCH -1
#define AT_EOF -2
#define ERROR -3
FILE *__stream;
char **_p, *__sstr, __holdch;
int __smode, __hold;
scanf(parlist)
char *parlist;
{
__smode = 0;
_p = &parlist;
return(__doscanf());
}
fscanf(stream,parlist)
FILE *stream;
char *parlist;
{
if( (stream->_flag&(_RMODE|_UPDATE)) == 0 || feof(stream) )
return(EOF);
__smode = 1;
__stream = stream;
_p = &parlist;
return(__doscanf());
}
sscanf(s,parlist)
char *s, *parlist;
{
__smode = 2;
__sstr = s;
_p = &parlist;
return(__doscanf());
}
__doscanf()
{
register int nmatch;
register char ch;
char *format;
register char match_ch;
nmatch = __hold = 0;
format = *_p++;
while( 1 ) {
switch (ch = *format++) {
case NULL:
return(nmatch);
case '%':
if( *format != '%' ) {
switch (__scan(&format, *_p)) {
case VALID: /* good return*/
_p++;
nmatch++;
case NORETURN: /* no return*/
break;
case NOMATCH: /* no match */
return(nmatch);
case AT_EOF: /* end of file */
return(nmatch ? nmatch : NOMATCH);
default: /* syntax error */
return(NOMATCH);
}
break;
}
format++;
default:
match_ch = __next(CHAR);
if( ch != match_ch ) {
__unget(match_ch);
return(nmatch ? nmatch : AT_EOF);
}
break;
}
}
}
/*
* main scan routine -- look at characters in the conversion string
* and do their bidding
*/
__scan(spec, result)
char **spec;
char *result;
{
register int longf, length;
register char ch;
extern int __strend(), __splend();
longf = length = 0;
while( 1 ) {
switch (ch = *(*spec)++) {
case '*':
result = 0;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
length = length * 10 + ch - '0';
break;
case 'l':
if( longf )
return(ERROR);
longf = 1;
break;
case 'h': /* short */
if( longf )
return(ERROR);
longf = NOMATCH;
break;
case 'o':
case 'O':
return(__dec(result, length ? length : 100, 8, longf));
case 'd':
case 'D':
return(__dec(result, length ? length : 100, 10, longf));
case 'x':
case 'X':
return(__dec(result, length ? length : 100, 16, longf));
case 'c':
case 'C':
if( longf )
return(ERROR);
return(__char(result, length ? length : 1));
case 's':
case 'S':
if( longf )
return(ERROR);
return(__strx(result, length ? length : 100, __strend));
case 'e':
case 'E':
case 'f':
case 'F':
if( longf )
return(ERROR);
return(__float(result, length ? length : 100));
/*return(ERROR); /* not yet implemented */
case '[':
if( longf )
return(ERROR);
if( __inits(spec) )
return(ERROR);
return(__strx(result, length ? length : 100, __splend));
default:
return(ERROR);
}
}
}
/*
* get a constant -- octal, decimal, or hex depending on base
*/
__dec(result, length, base, longf)
register int *result;
int length;
int base;
int longf;
{
register char ch;
register int val;
register int ndigit;
register long *lresult;
register long lres;
register int ires;
register int minus, ok;
ires = 0;
lres = 0;
ndigit = minus = 0;
switch (ch = __next(NOT_WHT_NL)) {
case NULL:
case EOF:
return(AT_EOF);
case '-':
minus = 1;
case '+':
ndigit++;
ch = __next(NOT_WHT);
}
ok = 0;
while( (val = __digit(ch, base)) >= 0 && ndigit++ < length ) {
ok++;
if( longf )
lres = lres * base + val;
else
ires = ires * base + val;
ch = __next(CHAR);
}
__unget(ch);
if( !ok )
return(NOMATCH);
if( !result )
return(NORETURN);
if( minus )
if( longf )
lres = -lres;
else
ires = -ires;
if( longf ) {
lresult = result;
*lresult = lres;
}
else
*result = ires;
return(VALID);
}
/*
* get a floating point constant
*/
__float(result, length)
register double *result;
int length;
{
char buffer[100];
double val;
int ret, ch;
ret = __strx(buffer, 100, __strend);
val = atof(buffer);
*result = val;
return(ret);
}
__next(mode)
int mode;
{
/*
* mode -1: get next non-space or non-tab
* mode 0: get next character
* mode 1: get next non-space, non-tab, or non-newline
*/
register int ch;
if( (ch = __getch()) == EOF )
return(EOF);
if( mode == 0 )
return(ch);
while( ch == SPACE || ch == TAB || ch == NEWLINE ) {
if( ch == NEWLINE && mode < 0 )
break;
ch = __getch();
}
return(ch);
}
/*
* check an input character for a valid constant digit (octal, decimal,
* or hex) if found, return the proper numeric value. Negative results
* indicate error.
*/
__digit(ch, base)
register char ch;
register int base;
{
register int n;
if( ch < '0' )
return(NOMATCH);
if( ch <= '7' )
return(ch - '0');
if( base == 8 )
return(NOMATCH);
if( ch <= '9' )
return(ch - '0');
if( base == 10 || ch < 'A' )
return(NOMATCH);
if( ch <= 'F' )
return(ch - 'A' + 10);
if( ch < 'a' || ch > 'f' )
return(NOMATCH);
return(ch - 'a' + 10);
}
/*
* check for an end of string delimiter
*/
__strend(cha)
char cha;
{
register char ch;
if( (ch = cha) == EOF )
return(EOF);
if( ch == SPACE || ch == TAB || ch == NEWLINE || ch == NULL )
return(VALID);
return(NORETURN);
}
char __splset[128];
/*
* check for the occurrance of any character in the set which
* the user wants to be end-of-string delimiters
*/
__splend(ch)
char ch;
{
if( ch == EOF )
return(EOF);
return(__splset[ch]);
}
/*
* initialize the array which inidcates the special chars which the user
* wants to be included (or not included) in strings.
*/
__inits(spec)
register char **spec;
{
register char ch;
register int i;
register int val;
ch = *(*spec)++;
if( ch == '^' ) {
val = 0;
ch = *(*spec)++;
}
else
val = 1;
for (i = 1; i < 128; i++)
__splset[i] = val;
val = 1 - val;
while( ch != ']' ) {
if( ch == 0 )
return(NOMATCH);
__splset[ch & 0177] = val;
ch = *(*spec)++;
}
__splset[0] = 1;
return(NORETURN);
}
/*
* getting a string
*/
__strx(result, length, endfn)
register char *result;
register int length;
register int (*endfn)();
{
register char ch;
extern int __splend();
register int imode, notok;
notok = 1;
imode = (endfn != __splend);
if (imode) {
ch = __next(NOT_WHT_NL);
__unget(ch); /* bypass tab or space... */
}
while( !(*endfn)( (ch = __next(imode)) ) && length-- > 0 ) {
if( result )
*result++ = ch;
imode = notok = 0;
}
__unget(ch);
if( notok )
return(ch == EOF ? AT_EOF : NOMATCH);
if( !result )
return(NORETURN);
*result = 0;
return(VALID);
}
/*
* getting a character constant
*/
__char(result, length)
register char *result;
register int length;
{
register char *r, ch;
register int l;
r = result;
l = length;
while( l-- ) {
if( (ch = __next(CHAR)) <= 0 ) {
if( l + 1 == length )
return(ch == EOF ? AT_EOF : NOMATCH);
else
return(result != 0);
}
if( result )
*result++ = ch;
}
return(result != 0);
}
__getch()
{
switch(__smode) {
case 0:
return(__gstdi());
case 1:
return(getc(__stream));
case 2:
return(__gs());
}
}
__unget(ch)
char ch;
{
switch(__smode) {
case 0:
__ugstdi(ch);
break;
case 1:
ungetc(ch,__stream);
break;
case 2:
__ungs(ch);
break;
}
}
/*
* return the next char pointed to by *s
*/
__gs()
{
register char c;
c = *__sstr;
if( c )
__sstr++;
else
return(EOF);
return(c);
}
/*
* put back a char for further scanning
*/
__ungs(c)
char c;
{
if( c )
__sstr--;
}
__gstdi()
{
if( !__hold)
return(getchar());
else {
__hold = 0;
return(__holdch);
}
}
__ugstdi(ch)
char ch;
{
__hold = 1;
__holdch = ch;
}