home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Carousel
/
CAROUSEL.cdr
/
mactosh
/
lang
/
lsc30p4u.sit
/
scanf2.c
< prev
next >
Wrap
Text File
|
1988-08-02
|
13KB
|
619 lines
/*
scanf routines for LightspeedC
(C) Copyright 1986. THINK Technologies, Inc. All rights reserved.
*/
#include "config.h"
#ifndef _stdioh_
#include "stdio.h"
#endif
#ifndef _MacTypes_
#include "MacTypes.h"
#endif
#ifndef _ctypeh_
#include "ctype.h"
#endif
#ifndef _saneh_
#include "sane.h"
#endif
#ifndef _setjmph_
#include "setjmp.h"
#endif
#ifndef _math_
#include "Math.h"
#endif
#include "pascal.h"
#ifdef _MC68881_
/* conversion from 68881 to SANE extended type */
static void x96tox80(x96, x80)
register Extended96 *x96;
register Extended80 *x80;
{
(*x80).exponent = (*x96).exponent;
(*x80).mantissa = (*x96).mantissa;
}
static void x80tox96(x80, x96)
register Extended80 *x80;
register Extended96 *x96;
{
(*x96).exponent = (*x80).exponent;
(*x96).reserved = 0;
(*x96).mantissa = (*x80).mantissa;
}
#define _fromDecimal() fp68k(&_decimal_,&x80,FFEXT|FOD2B)
#define _tox96() x80tox96(&x80, *(double**)argument)
#else
#define _fromDecimal() fp68k(&_decimal_,*(double**)argument,FFEXT|FOD2B)
#define _tox96()
#endif
/*----------------------------------------------------------------------------
some global storage to prevent excessive parameter transfer
----------------------------------------------------------------------------*/
int (*_scanf_input)(); /* global pointer to function for input */
int (*_scanf_putback)(); /* global pointer to function for putback */
_scanf_scan(); /* function to handle formatting */
jmp_buf _scanf_env; /* for error exit context switch */
static unsigned char *destination; /* pointer to indicate stream for output */
static char scratch[256]; /* used for [ command for byte validation */
static
int from_memory()
{
register unsigned char c;
c = *destination;
if (c) {
destination++;
return(c);
} else return(EOF);
}
static
put_back_into_memory(x)
char x;
{
destination--;
}
#line 0 sscanf
int sscanf(dest, fmt)
unsigned char *dest; /* pointer to buffer space */
char *fmt; /* pointer to format string */
{
_scanf_input = from_memory;
_scanf_putback = put_back_into_memory;
destination = dest;
return(_scanf_scan(&fmt));
}
static
Boolean okdigit(c, base, value_in_base_ptr)
register char c;
register int base;
register int *value_in_base_ptr;
{
/* only works for bases 2 through 10 (inclusive) and 16! */
*value_in_base_ptr = 0;
if (c >= '0')
{
if (c <= (((base<=10)?base:10)+'0'-1))
{
*value_in_base_ptr = c-'0';
return (true);
}
if (base == 16)
{
/* if character is lower case, convert to upper case */
if ((c >= 'a') && (c <= 'f')) c -= 'a'-'A';
if ((c >= 'A') && (c <= 'F'))
{
*value_in_base_ptr = c - 'A' + 10;
return (true);
}
}
}
return (false);
}
static
long read_num(num,err,at_least_one, base)
register unsigned num;
register Boolean *err;
register Boolean *at_least_one;
register int base;
{
register long number = 0;
register int c;
register Boolean oneX=false;
int value_in_base;
*at_least_one = false;
*err = false;
if (num == 0) num--;
/* if first char is EOF, then it's not a number */
if ((c = (*_scanf_input)()) == EOF)
{
*err = true;
return(EOF);
}
/* loop collecting digits while num is not zero */
while (okdigit(c, base, &value_in_base) && num--)
{
number = number * base + value_in_base;
*at_least_one = true;
/* no need to put back EOF if we hit it */
if ((c = (*_scanf_input)()) == EOF) return (number);
/* the form 0xNNNN is allowed for hex numbers, just swallow the
X and continue from there, but only do it once! */
if ((base == 16) && ((c == 'x') || (c == 'X')))
{
if ((number > 0) || oneX) break;
/* pick up next digit -- error if nothing follows X */
if ((c = (*_scanf_input)()) == EOF) return (EOF);
}
/* only allow hex form after first zero, otherwise it is an error */
oneX = true;
}
(*_scanf_putback)(c);
return(number);
}
static
int skip_white()
{
register int c;
do
{
if ((c = (*_scanf_input)()) == EOF) longjmp(_scanf_env, EOF);
}
while (c && isspace(c));
return(c); /* returns character after white space */
}
int _scanf_scan(fmt)
char **fmt; /* pointer to pointer to format string */
{
char c; /* current character under inspection */
char *format; /* pointer to format string */
Boolean its_a_long; /* flag to indicate long integer */
Boolean its_a_short; /* flag to indicate short integer */
Boolean neg; /* flag for negative # */
register Boolean assign; /* flag for suppression flag */
Boolean read_err; /* Used as error flag for read_ routines */
Boolean valid; /* valid digit? */
register long value; /* for conversion of numerics */
register char *argument; /* pointer to arguments for fmt string */
register unsigned width; /* field width as specified by format */
register int curr_char; /* last character read */
register char **loc; /* used to run thru argument */
int i; /* counter */
register count; /* counter */
register int (*_scanf_putbackx)() = _scanf_putback;
#ifdef _MC68881_
Extended80 x80;
#endif
if (count=setjmp(_scanf_env)) return (count); /* set up error handler */
format = *fmt++; /* set "format" to the format string */
/* "fmt" is left pointing to first argument */
argument = (char *) fmt; /* set "argument" to point to first argument */
count = 0; /* set count to zero */
while (c = *format++) /* scan format string until NULL */
{
if (c == '%')
{
neg = false;
assign = true;
if ((c = *format) == '*') /* suppress mode? */
{
assign = false; /* set flag if so */
format++; /* point to next char */
}
/* compute total field width, zero allows arbitrary width */
width = (isdigit(*format)) ? _std_decode(&format) : 0;
/* check if long integer is required */
if (its_a_long = ((*format) == 'l')) format++;
/* check if short integer is required */
if (its_a_short = ((*format) == 'h')) format++;
c = *format++;
/* note that "format" is left ready for the next pass */
switch (c)
{
case 'd': switch (curr_char = skip_white())
{
case '+': /* swallow a + */
break;
case '-': /* remember a -, swallow char */
neg = true;
break;
default: /* oops, put it back! */
(*_scanf_putbackx)(curr_char);
break;
}
value = read_num(width,&read_err,&valid, 10);
if (read_err) return(EOF);
if (valid == false) return(count);
if (neg) value = -value;
if (assign)
{
if(its_a_long)
**(long **)argument = value;
else
**(int **)argument = value;
argument += sizeof(long);
count++;
}
break;
case 'u':
(*_scanf_putbackx)(skip_white());
value = read_num(width,&read_err,&valid, 10);
if (read_err) return(EOF);
if (valid == false) return(count);
if (assign)
{
if(its_a_long)
**(unsigned long **)argument = value;
else
**(unsigned int **)argument = value;
argument += sizeof(long);
count++;
}
break;
case 'x':
case 'X':
(*_scanf_putbackx)(skip_white());
value = read_num(width,&read_err,&valid, 16);
if (read_err) return(EOF);
if (valid == false) return(count);
if (assign)
{
if(its_a_long)
**(unsigned long **)argument = value;
else
**(unsigned int **)argument = value;
argument += sizeof(long);
count++;
}
break;
case 'o':
case 'O':
(*_scanf_putbackx)(skip_white());
value = read_num(width,&read_err,&valid, 8);
if (read_err) return(EOF);
if (valid == false) return(count);
if (assign)
{
if(its_a_long)
**(unsigned long **)argument = value;
else
**(unsigned int **)argument = value;
argument += sizeof(long);
count++;
}
break;
case 'c': if (width<=0) width = 1;
loc = (char **)argument;
do
{
if ((curr_char = (*_scanf_input)()) == EOF)
return(EOF);
if (assign)
{
**(char **)loc = curr_char;
(*loc)++;
}
width--;
}
while (width);
if (assign)
{
argument += sizeof(long);
count++;
}
break;
case 'p':
case 's':
{ char *strStart;
/* first char cannot be EOF after skip_white */
(*_scanf_putbackx)(skip_white());
loc = (char **)argument;
strStart = *loc;
do
{
if ((curr_char = (*_scanf_input)()) == EOF)
{
if (assign) {
**(char**) loc = '\0';
if (c == 'p') CtoPstr(strStart);
}
return (count);
}
if (assign)
{
if (!isspace(curr_char))
**(char **)loc = curr_char;
else
**(char **)loc = '\0';
(*loc)++;
}
width--;
}
while ((curr_char)&&(width)&&(!isspace(curr_char)));
if (!curr_char || isspace(curr_char))
(*_scanf_putbackx)(curr_char);
else
if (assign)
**(char **)loc = '\0';
if (assign)
{
argument += sizeof(long);
if (c == 'p') CtoPstr(strStart);
count++;
}
break;
}
case '[': neg = false;
if (*format == '^') /* check for negate */
{
neg = true; /* set if necessary */
format++;
}
loc = (char **)argument; /* point to destination */
/* initialize lookup table */
for (i=255; i>=0; i--)
scratch[i] = neg;
/* pointing after [ or ^ */
while ((curr_char = *format++) != ']')
scratch[curr_char] = (!neg);
do
{
if ((curr_char = (*_scanf_input)()) == EOF)
return(EOF);
if (assign)
{
if (scratch[curr_char])
**(char **)loc = curr_char;
else
**(char **)loc = '\0';
(*loc)++;
}
width--;
}
while ((width) && (scratch[curr_char]));
if (!scratch[curr_char])
(*_scanf_putbackx)(curr_char);
else
if (assign)
**(char **)loc = '\0';
if (assign)
{
argument += sizeof(long);
count++;
}
break;
case '%': if ((curr_char = (*_scanf_input)()) == EOF)
return(EOF);
if (curr_char != '%')
return (count);
break;
case 'f':
case 'e':
case 'E':
case 'g':
case 'G':
{Decimal _decimal_;
int fblen = 0;
scratch[0] = '\0';
curr_char = skip_white();
valid = false;
do
{int index = 0;
scratch[fblen++] = curr_char;
scratch[fblen] = '\0';
read_err = false;
if (scratch[fblen-1])
{
CStr2Dec(&scratch,&index,&_decimal_,&read_err);
/* read_err is true if NO READ ERROR! */
if (read_err)
{
valid = true;
/* read next character */
if ((curr_char = (*_scanf_input)()) == EOF)
read_err = false;
if (isspace(curr_char))
{
read_err = false;
(*_scanf_putbackx)(curr_char);
}
}
else
(*_scanf_putbackx)(scratch[fblen-1]);
}
} while ((read_err)&&(--width));
if (!valid) return(count);
if (assign)
{
if (its_a_long) {
_fromDecimal();
_tox96();
}
else
if (its_a_short)
fp68k(&_decimal_,*(short double**)argument,FFDBL|FOD2B);
else
fp68k(&_decimal_,*(float**)argument,FFSGL|FOD2B);
count++;
}
argument += sizeof(long);
break;
}
} /* end switch */
} /* end '%' */
else
{
if (!c || isspace(c))
{
/* expecting zero or more spaces
pdg - 6/20/86 - used to require at least 1 space! */
while (isspace(curr_char = (*_scanf_input)()))
;
/* prevent trailing white space from incurring EOF exit */
if (curr_char == EOF)
{
if (count > 0) return (count);
return (EOF);
}
(*_scanf_putbackx)(curr_char);
/* skip all contiguous spaces in format string */
while (isspace(*format)) format++;
}
else
{
if ((curr_char = (*_scanf_input)()) == EOF) return(EOF);
/* character must match exactly! */
if (curr_char != c)
{
(*_scanf_putbackx)(curr_char);
return(count);
}
}
} /* else % */
} /* end while (*format) */
/* return number of successful assignments */
return(count);
}