281 lines
6.6 KiB
C
281 lines
6.6 KiB
C
/* _ f _ t v c */
|
|
|
|
/* This code implements the %f, %g and %e formats for input conversion
|
|
* of floating point numbers. It is called from _vfscanf().
|
|
*/
|
|
|
|
extern int __mpow10;
|
|
|
|
#include "stdiolib.h"
|
|
#include <math.h>
|
|
|
|
/*LINTLIBRARY*/
|
|
|
|
#define NEXTCH() (nbytes++, ch = getc(fp))
|
|
|
|
#if '0'+1 != '1' || '1'+1 != '2' || '2'+1 != '3' || '3'+1 != '4' || \
|
|
'4'+1 != '5' || '5'+1 != '6' || '6'+1 != '7' || '7'+1 != '8' || \
|
|
'8'+1 != '9'
|
|
<< Violation of collating sequence assumption >>
|
|
#endif
|
|
|
|
char __xfptvc = 0; /* linkage for library */
|
|
|
|
/****************************************************************/
|
|
/* Assume that division or multiplication by FLT_RADIX is exact */
|
|
/****************************************************************/
|
|
|
|
int __tvc F5(FILE *, fp, int, width, VA_LIST *, argp, int, fptype, char *, ok)
|
|
|
|
{
|
|
int ch; /* look-ahead character */
|
|
int nbytes; /* bytes scanned */
|
|
int fracpart; /* fractional part of mantissa */
|
|
longguard mant; /* mantissa */
|
|
longdouble Mantissa; /* result */
|
|
int exponent; /* exponent */
|
|
int digits; /* significant digits */
|
|
char haveexp; /* exponent exists */
|
|
char scannedzeros; /* scanned leading zeros */
|
|
char negative; /* negative */
|
|
char expnegative; /* exponent negative */
|
|
long imantissa; /* mantissa collection */
|
|
int imantdigs; /* digits collected */
|
|
int gdigits; /* guard digits */
|
|
int normexp; /* exponent for normalised number */
|
|
int expoffset; /* offset for exponent */
|
|
longguard pow10; /* guarded power of ten */
|
|
char *dbp; /* point to digit insertion */
|
|
char *edbp; /* end of digit buffer */
|
|
char dbuf[3*LDBL_DIG/2]; /* digit buffer */
|
|
int i; /* index */
|
|
static longdouble flt_radix = FLT_RADIX;/* exponent radix */
|
|
#ifdef LMR
|
|
static int ldbl_max_radix[sizeof(longdouble)/sizeof(int)] = {
|
|
#include "lmr.h"
|
|
};
|
|
#else
|
|
static longdouble ldbl_max_radix[1];
|
|
#endif
|
|
|
|
ch = getc(fp);
|
|
nbytes = 0;
|
|
fracpart = 0;
|
|
negative = 0;
|
|
expnegative = 0;
|
|
exponent = 0;
|
|
haveexp = 0;
|
|
scannedzeros = 0;
|
|
*ok = 0;
|
|
dbp = &dbuf[0];
|
|
edbp = &dbuf[sizeof(dbuf)/sizeof(dbuf[0])];
|
|
|
|
#ifndef LMR
|
|
ldbl_max_radix[0] = LDBL_MAX / FLT_RADIX;
|
|
#endif
|
|
|
|
/* Leading sign bit */
|
|
if (width != 0) {
|
|
if (ch == '-') {
|
|
negative++;
|
|
NEXTCH();
|
|
width--;
|
|
} else if (ch == '+') {
|
|
NEXTCH();
|
|
width--;
|
|
}
|
|
}
|
|
|
|
/* Skip leading zeros in integer part */
|
|
while (width != 0 && ch == '0') {
|
|
NEXTCH();
|
|
width--;
|
|
scannedzeros = 1;
|
|
}
|
|
|
|
/* Integer part */
|
|
while (width != 0 && ch >= '0' && ch <= '9') {
|
|
if (dbp < edbp)
|
|
*dbp++ = ch;
|
|
else
|
|
fracpart--;
|
|
NEXTCH();
|
|
width--;
|
|
}
|
|
|
|
/* Fractional part */
|
|
if (width != 0 && ch == '.') {
|
|
NEXTCH();
|
|
width--;
|
|
|
|
/* Skip leading zeros in fractional part */
|
|
if (dbp == &dbuf[0]) {
|
|
while (width != 0 && ch == '0') {
|
|
NEXTCH();
|
|
width--;
|
|
fracpart++;
|
|
scannedzeros = 1;
|
|
}
|
|
}
|
|
|
|
/* Fractional part proper */
|
|
while (width != 0 && ch >= '0' && ch <= '9') {
|
|
if (dbp < edbp) {
|
|
*dbp++ = ch;
|
|
fracpart++;
|
|
}
|
|
NEXTCH();
|
|
width--;
|
|
}
|
|
}
|
|
|
|
/* Discard trailing zeros */
|
|
for (digits = dbp - &dbuf[0]; digits > 0 && *--dbp == '0'; digits--)
|
|
fracpart--;
|
|
|
|
/* Validate mantissa */
|
|
if (scannedzeros == 0 && digits == 0)
|
|
goto Failed;
|
|
|
|
/* Convert digits */
|
|
imantissa = 0;
|
|
imantdigs = 0;
|
|
gdigits = 0;
|
|
mant.number = 0.0;
|
|
mant.guard = 0.0;
|
|
mant.exponent = 0;
|
|
for (dbp = &dbuf[0], i = 0; i < digits; imantdigs++, i++, dbp++) {
|
|
if (i != LDBL_DIG/2 && imantdigs < __Mipow10)
|
|
imantissa = imantissa * 10 + (dbp[0] - '0');
|
|
else {
|
|
if (i == LDBL_DIG/2)
|
|
mant.number = imantissa;
|
|
else {
|
|
mant.guard = mant.guard * __fpow10[imantdigs] + imantissa;
|
|
gdigits += imantdigs;
|
|
}
|
|
imantissa = dbp[0] - '0';
|
|
imantdigs = 0;
|
|
}
|
|
}
|
|
if (imantdigs != 0) {
|
|
if (i <= LDBL_DIG/2)
|
|
mant.number = imantissa;
|
|
else {
|
|
mant.guard = mant.guard * __fpow10[imantdigs] + imantissa;
|
|
gdigits += imantdigs;
|
|
}
|
|
}
|
|
if (gdigits != 0)
|
|
mant.guard /= __fpow10[gdigits];
|
|
|
|
/* In order to ensure that LDBL_MIN is able to be scanned properly
|
|
* it is necessary the normalised decimal mantissa need only a single
|
|
* guarded multiplication to convert it into the required number.
|
|
*/
|
|
ASSERT(LDBL_DIG/2 - 1 + LDBL_MIN_10_EXP >= __mpow10);
|
|
|
|
/* Exponent */
|
|
if (width != 0 && (ch == 'e' || ch == 'E')) {
|
|
NEXTCH();
|
|
width--;
|
|
if (width != 0) {
|
|
if (ch == '-') {
|
|
expnegative = 1;
|
|
NEXTCH();
|
|
width--;
|
|
} else if (ch == '+') {
|
|
NEXTCH();
|
|
width--;
|
|
}
|
|
}
|
|
|
|
expoffset = digits - fracpart - 1;
|
|
if (expnegative)
|
|
expoffset = -expoffset;
|
|
|
|
while (width != 0 && ch >= '0' && ch <= '9') {
|
|
haveexp = 1;
|
|
if (exponent + expoffset <= LDBL_MAX_10_EXP)
|
|
exponent = exponent * 10 + (ch - '0');
|
|
NEXTCH();
|
|
width--;
|
|
}
|
|
if (haveexp == 0)
|
|
goto Failed;
|
|
if (expnegative)
|
|
exponent = -exponent;
|
|
}
|
|
|
|
/* Merge mantissa and exponent */
|
|
exponent += gdigits - fracpart;
|
|
|
|
if (exponent < 0) {
|
|
|
|
while (exponent < __mpow10) {
|
|
__gpow10(__mpow10, &pow10);
|
|
__ggmul(&mant, &mant, &pow10);
|
|
__gguard(&mant);
|
|
exponent -= __mpow10;
|
|
}
|
|
|
|
__gpow10(exponent, &pow10);
|
|
Mantissa = __gmul(&mant, &pow10);
|
|
}
|
|
|
|
else {
|
|
|
|
normexp = exponent + (digits - gdigits) - 1;
|
|
|
|
/* Magnitude of number is too great */
|
|
if (normexp > LDBL_MAX_10_EXP)
|
|
Mantissa = HUGE_VAL;
|
|
|
|
/* Exponent is in range or on limit */
|
|
else {
|
|
while (exponent > LDBL_MAX_10_EXP) {
|
|
__gpow10(LDBL_MAX_10_EXP, &pow10);
|
|
__ggmul(&mant, &mant, &pow10);
|
|
__gguard(&mant);
|
|
exponent -= LDBL_MAX_10_EXP;
|
|
}
|
|
|
|
/* Number is well within range */
|
|
if (normexp < LDBL_MAX_10_EXP) {
|
|
__gpow10(exponent, &pow10);
|
|
Mantissa = __gmul(&mant, &pow10);
|
|
}
|
|
|
|
/* Number may overflow and is close to the limit of the representation. */
|
|
else {
|
|
__gpow10(gdigits - digits + 1, &pow10);
|
|
__ggmul(&mant, &mant, &pow10);
|
|
__gguard(&mant);
|
|
__gpow10(LDBL_MAX_10_EXP, &pow10);
|
|
Mantissa = __gmul(&mant, &pow10);
|
|
Mantissa /= flt_radix;
|
|
if (Mantissa <= * (longdouble *) &ldbl_max_radix[0])
|
|
Mantissa *= flt_radix;
|
|
else
|
|
Mantissa = HUGE_VAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Merge sign */
|
|
if (negative)
|
|
Mantissa = -Mantissa;
|
|
|
|
/* Generate result */
|
|
*ok = 1;
|
|
switch (fptype) {
|
|
case 1: * VA_ARG(*argp, longdouble *) = Mantissa; break;
|
|
case 2: * VA_ARG(*argp, double *) = Mantissa; break;
|
|
case 3: * VA_ARG(*argp, float *) = Mantissa; break;
|
|
}
|
|
|
|
Failed:
|
|
ungetc(ch, fp);
|
|
return nbytes;
|
|
}
|