mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-23 08:24:18 +00:00
539 lines
11 KiB
C
539 lines
11 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;
|
||
}
|
||
|
||
|