update for better FP routines, from AT&T & elsewhere
This commit is contained in:
parent
965a95338b
commit
49693da854
@ -33,9 +33,9 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)scanf.3 6.11 (Berkeley) 6/29/91
|
||||
.\" @(#)scanf.3 6.14 (Berkeley) 1/8/93
|
||||
.\"
|
||||
.Dd June 29, 1991
|
||||
.Dd January 8, 1993
|
||||
.Dt SCANF 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -393,6 +393,7 @@ the number of conversions which were successfully completed is returned.
|
||||
.Sh SEE ALSO
|
||||
.Xr strtol 3 ,
|
||||
.Xr strtoul 3 ,
|
||||
.Xr strtod 3 ,
|
||||
.Xr getc 3 ,
|
||||
.Xr printf 3
|
||||
.Sh STANDARDS
|
||||
@ -418,3 +419,12 @@ and
|
||||
conversions is unfortunate.
|
||||
.Pp
|
||||
All of the backwards compatibility formats will be removed in the future.
|
||||
.Pp
|
||||
Numerical strings are truncated to 512 characters; for example,
|
||||
.Cm %f
|
||||
and
|
||||
.Cm %d
|
||||
are implicitly
|
||||
.Cm %512f
|
||||
and
|
||||
.Cm %512d .
|
||||
|
@ -35,7 +35,7 @@
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)vfprintf.c 5.47 (Berkeley) 3/22/91";
|
||||
static char sccsid[] = "@(#)vfprintf.c 5.50 (Berkeley) 12/16/92";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
/*
|
||||
@ -45,100 +45,22 @@ static char sccsid[] = "@(#)vfprintf.c 5.47 (Berkeley) 3/22/91";
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if __STDC__
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
|
||||
#include "local.h"
|
||||
#include "fvwrite.h"
|
||||
|
||||
/*
|
||||
* Define FLOATING_POINT to get floating point.
|
||||
* Define CSH to get a csh-specific version (grr).
|
||||
*/
|
||||
#ifndef CSH
|
||||
/* Define FLOATING_POINT to get floating point. */
|
||||
#define FLOATING_POINT
|
||||
#endif
|
||||
|
||||
/* end of configuration stuff */
|
||||
|
||||
|
||||
#ifdef CSH
|
||||
/*
|
||||
* C shell hacks. Ick, gag.
|
||||
*/
|
||||
#undef BUFSIZ
|
||||
#include "sh.h"
|
||||
|
||||
#if __STDC__
|
||||
int
|
||||
printf(const char *fmt, ...) {
|
||||
FILE f;
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start(ap, fmt);
|
||||
f._flags = __SWR;
|
||||
f._write = NULL;
|
||||
ret = vfprintf(&f, fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
int
|
||||
printf(fmt, args)
|
||||
char *fmt;
|
||||
{
|
||||
FILE f;
|
||||
|
||||
f._flags = __SWR;
|
||||
f._write = NULL;
|
||||
return (vfprintf(&f, fmt, &args));
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
__sprint(fp, uio)
|
||||
FILE *fp;
|
||||
register struct __suio *uio;
|
||||
{
|
||||
register char *p;
|
||||
register int n, ch, iovcnt;
|
||||
register struct __siov *iov;
|
||||
|
||||
/* must allow sprintf to work, might as well allow others too */
|
||||
if (fp->_write || fp->_flags & __SSTR) {
|
||||
if (uio->uio_resid == 0) {
|
||||
uio->uio_iovcnt = 0;
|
||||
return (0);
|
||||
}
|
||||
n = __sfvwrite(fp, uio);
|
||||
uio->uio_resid = 0;
|
||||
uio->uio_iovcnt = 0;
|
||||
return (n);
|
||||
}
|
||||
iov = uio->uio_iov;
|
||||
for (iovcnt = uio->uio_iovcnt; --iovcnt >= 0; iov++) {
|
||||
for (p = iov->iov_base, n = iov->iov_len; --n >= 0;) {
|
||||
#ifdef CSHPUTCHAR
|
||||
ch = *p++;
|
||||
CSHPUTCHAR; /* this horrid macro uses `ch' */
|
||||
#else
|
||||
#undef putchar
|
||||
putchar(*p++);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
uio->uio_resid = 0;
|
||||
uio->uio_iovcnt = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
#else /* CSH */
|
||||
|
||||
/*
|
||||
* Flush out all the vectors defined by the given uio,
|
||||
@ -196,16 +118,16 @@ __sbprintf(fp, fmt, ap)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#endif /* CSH */
|
||||
|
||||
|
||||
#ifdef FLOATING_POINT
|
||||
#include <math.h>
|
||||
#include "floatio.h"
|
||||
|
||||
#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
|
||||
#define DEFPREC 6
|
||||
|
||||
static int cvt();
|
||||
static char *cvt __P((double, int, int, char *, int *, int, int *));
|
||||
static int exponent __P((char *, int, int));
|
||||
|
||||
#else /* no FLOATING_POINT */
|
||||
|
||||
@ -224,22 +146,20 @@ static int cvt();
|
||||
/*
|
||||
* Flags used during conversion.
|
||||
*/
|
||||
#define LONGINT 0x01 /* long integer */
|
||||
#define LONGDBL 0x02 /* long double; unimplemented */
|
||||
#define SHORTINT 0x04 /* short integer */
|
||||
#define ALT 0x08 /* alternate form */
|
||||
#define LADJUST 0x10 /* left adjustment */
|
||||
#define ZEROPAD 0x20 /* zero (as opposed to blank) pad */
|
||||
#define HEXPREFIX 0x40 /* add 0x or 0X prefix */
|
||||
|
||||
#define ALT 0x001 /* alternate form */
|
||||
#define HEXPREFIX 0x002 /* add 0x or 0X prefix */
|
||||
#define LADJUST 0x004 /* left adjustment */
|
||||
#define LONGDBL 0x008 /* long double; unimplemented */
|
||||
#define LONGINT 0x010 /* long integer */
|
||||
#define QUADINT 0x020 /* quad integer */
|
||||
#define SHORTINT 0x040 /* short integer */
|
||||
#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
|
||||
#define FPT 0x100 /* Floating point number */
|
||||
int
|
||||
vfprintf(fp, fmt0, ap)
|
||||
FILE *fp;
|
||||
const char *fmt0;
|
||||
#if tahoe
|
||||
register /* technically illegal, since we do not know what type va_list is */
|
||||
#endif
|
||||
_VA_LIST_ ap;
|
||||
va_list ap;
|
||||
{
|
||||
register char *fmt; /* format string */
|
||||
register int ch; /* character from fmt */
|
||||
@ -254,9 +174,18 @@ vfprintf(fp, fmt0, ap)
|
||||
#ifdef FLOATING_POINT
|
||||
char softsign; /* temporary negative sign for floats */
|
||||
double _double; /* double precision arguments %[eEfgG] */
|
||||
int fpprec; /* `extra' floating precision in [eEfgG] */
|
||||
int expt; /* integer value of exponent */
|
||||
int expsize; /* character count for expstr */
|
||||
int ndig; /* actual number of digits returned by cvt */
|
||||
char expstr[7]; /* buffer for exponent string */
|
||||
#endif
|
||||
u_long _ulong; /* integer arguments %[diouxX] */
|
||||
|
||||
#ifdef __GNUC__ /* gcc has builtin quad type (long long) SOS */
|
||||
#define quad_t long long
|
||||
#define u_quad_t unsigned long long
|
||||
#endif
|
||||
|
||||
u_quad_t _uquad; /* integer arguments %[diouxX] */
|
||||
enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
|
||||
int dprec; /* a copy of prec if [diouxX], 0 otherwise */
|
||||
int fieldsz; /* field size expanded by sign, etc */
|
||||
@ -270,9 +199,9 @@ vfprintf(fp, fmt0, ap)
|
||||
char ox[2]; /* space for 0x hex-prefix */
|
||||
|
||||
/*
|
||||
* Choose PADSIZE to trade efficiency vs size. If larger
|
||||
* printf fields occur frequently, increase PADSIZE (and make
|
||||
* the initialisers below longer).
|
||||
* Choose PADSIZE to trade efficiency vs. size. If larger printf
|
||||
* fields occur frequently, increase PADSIZE and make the initialisers
|
||||
* below longer.
|
||||
*/
|
||||
#define PADSIZE 16 /* pad chunk size */
|
||||
static char blanks[PADSIZE] =
|
||||
@ -315,15 +244,16 @@ vfprintf(fp, fmt0, ap)
|
||||
* argument extraction methods.
|
||||
*/
|
||||
#define SARG() \
|
||||
(flags&LONGINT ? va_arg(ap, long) : \
|
||||
(flags&QUADINT ? va_arg(ap, quad_t) : \
|
||||
flags&LONGINT ? va_arg(ap, long) : \
|
||||
flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
|
||||
(long)va_arg(ap, int))
|
||||
#define UARG() \
|
||||
(flags&LONGINT ? va_arg(ap, u_long) : \
|
||||
(flags&QUADINT ? va_arg(ap, u_quad_t) : \
|
||||
flags&LONGINT ? va_arg(ap, u_long) : \
|
||||
flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
|
||||
(u_long)va_arg(ap, u_int))
|
||||
|
||||
#ifndef CSH
|
||||
/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
|
||||
if (cantwrite(fp))
|
||||
return (EOF);
|
||||
@ -332,7 +262,6 @@ vfprintf(fp, fmt0, ap)
|
||||
if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
|
||||
fp->_file >= 0)
|
||||
return (__sbprintf(fp, fmt0, ap));
|
||||
#endif /* CSH */
|
||||
|
||||
fmt = (char *)fmt0;
|
||||
uio.uio_iov = iovp = iov;
|
||||
@ -356,9 +285,6 @@ vfprintf(fp, fmt0, ap)
|
||||
|
||||
flags = 0;
|
||||
dprec = 0;
|
||||
#ifdef FLOATING_POINT
|
||||
fpprec = 0;
|
||||
#endif
|
||||
width = 0;
|
||||
prec = -1;
|
||||
sign = '\0';
|
||||
@ -435,6 +361,9 @@ reswitch: switch (ch) {
|
||||
case 'l':
|
||||
flags |= LONGINT;
|
||||
goto rflag;
|
||||
case 'q':
|
||||
flags |= QUADINT;
|
||||
goto rflag;
|
||||
case 'c':
|
||||
*(cp = buf) = va_arg(ap, int);
|
||||
size = 1;
|
||||
@ -445,20 +374,28 @@ reswitch: switch (ch) {
|
||||
/*FALLTHROUGH*/
|
||||
case 'd':
|
||||
case 'i':
|
||||
_ulong = SARG();
|
||||
if ((long)_ulong < 0) {
|
||||
_ulong = -_ulong;
|
||||
_uquad = SARG();
|
||||
if ((quad_t)_uquad < 0) {
|
||||
_uquad = -_uquad;
|
||||
sign = '-';
|
||||
}
|
||||
base = DEC;
|
||||
goto number;
|
||||
#ifdef FLOATING_POINT
|
||||
case 'e':
|
||||
case 'e': /* anomalous precision */
|
||||
case 'E':
|
||||
case 'f':
|
||||
prec = (prec == -1) ?
|
||||
DEFPREC + 1 : prec + 1;
|
||||
/* FALLTHROUGH */
|
||||
goto fp_begin;
|
||||
case 'f': /* always print trailing zeroes */
|
||||
if (prec != 0)
|
||||
flags |= ALT;
|
||||
case 'g':
|
||||
case 'G':
|
||||
_double = va_arg(ap, double);
|
||||
if (prec == -1)
|
||||
prec = DEFPREC;
|
||||
fp_begin: _double = va_arg(ap, double);
|
||||
/* do this before tricky precision changes */
|
||||
if (isinf(_double)) {
|
||||
if (_double < 0)
|
||||
@ -472,35 +409,44 @@ reswitch: switch (ch) {
|
||||
size = 3;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* don't do unrealistic precision; just pad it with
|
||||
* zeroes later, so buffer size stays rational.
|
||||
*/
|
||||
if (prec > MAXFRACT) {
|
||||
if (ch != 'g' && ch != 'G' || (flags&ALT))
|
||||
fpprec = prec - MAXFRACT;
|
||||
prec = MAXFRACT;
|
||||
} else if (prec == -1)
|
||||
prec = DEFPREC;
|
||||
/*
|
||||
* cvt may have to round up before the "start" of
|
||||
* its buffer, i.e. ``intf("%.2f", (double)9.999);'';
|
||||
* if the first character is still NUL, it did.
|
||||
* softsign avoids negative 0 if _double < 0 but
|
||||
* no significant digits will be shown.
|
||||
*/
|
||||
cp = buf;
|
||||
*cp = '\0';
|
||||
size = cvt(_double, prec, flags, &softsign, ch,
|
||||
cp, buf + sizeof(buf));
|
||||
flags |= FPT;
|
||||
cp = cvt(_double, prec, flags, &softsign,
|
||||
&expt, ch, &ndig);
|
||||
if (ch == 'g' || ch == 'G') {
|
||||
if (expt <= -4 || expt > prec)
|
||||
ch = (ch == 'g') ? 'e' : 'E';
|
||||
else
|
||||
ch = 'g';
|
||||
}
|
||||
if (ch <= 'e') { /* 'e' or 'E' fmt */
|
||||
--expt;
|
||||
expsize = exponent(expstr, expt, ch);
|
||||
size = expsize + ndig;
|
||||
if (ndig > 1 || flags & ALT)
|
||||
++size;
|
||||
} else if (ch == 'f') { /* f fmt */
|
||||
if (expt > 0) {
|
||||
size = expt;
|
||||
if (prec || flags & ALT)
|
||||
size += prec + 1;
|
||||
} else /* "0.X" */
|
||||
size = prec + 2;
|
||||
} else if (expt >= ndig) { /* fixed g fmt */
|
||||
size = expt;
|
||||
if (flags & ALT)
|
||||
++size;
|
||||
} else
|
||||
size = ndig + (expt > 0 ?
|
||||
1 : 2 - expt);
|
||||
|
||||
if (softsign)
|
||||
sign = '-';
|
||||
if (*cp == '\0')
|
||||
cp++;
|
||||
break;
|
||||
#endif /* FLOATING_POINT */
|
||||
case 'n':
|
||||
if (flags & LONGINT)
|
||||
if (flags & QUADINT)
|
||||
*va_arg(ap, quad_t *) = ret;
|
||||
else if (flags & LONGINT)
|
||||
*va_arg(ap, long *) = ret;
|
||||
else if (flags & SHORTINT)
|
||||
*va_arg(ap, short *) = ret;
|
||||
@ -511,7 +457,7 @@ reswitch: switch (ch) {
|
||||
flags |= LONGINT;
|
||||
/*FALLTHROUGH*/
|
||||
case 'o':
|
||||
_ulong = UARG();
|
||||
_uquad = UARG();
|
||||
base = OCT;
|
||||
goto nosign;
|
||||
case 'p':
|
||||
@ -523,7 +469,7 @@ reswitch: switch (ch) {
|
||||
* -- ANSI X3J11
|
||||
*/
|
||||
/* NOSTRICT */
|
||||
_ulong = (u_long)va_arg(ap, void *);
|
||||
_uquad = (u_quad_t)va_arg(ap, void *);
|
||||
base = HEX;
|
||||
xdigs = "0123456789abcdef";
|
||||
flags |= HEXPREFIX;
|
||||
@ -554,7 +500,7 @@ reswitch: switch (ch) {
|
||||
flags |= LONGINT;
|
||||
/*FALLTHROUGH*/
|
||||
case 'u':
|
||||
_ulong = UARG();
|
||||
_uquad = UARG();
|
||||
base = DEC;
|
||||
goto nosign;
|
||||
case 'X':
|
||||
@ -562,10 +508,10 @@ reswitch: switch (ch) {
|
||||
goto hex;
|
||||
case 'x':
|
||||
xdigs = "0123456789abcdef";
|
||||
hex: _ulong = UARG();
|
||||
hex: _uquad = UARG();
|
||||
base = HEX;
|
||||
/* leading 0x/X only if non-zero */
|
||||
if (flags & ALT && _ulong != 0)
|
||||
if (flags & ALT && _uquad != 0)
|
||||
flags |= HEXPREFIX;
|
||||
|
||||
/* unsigned conversions */
|
||||
@ -584,18 +530,18 @@ number: if ((dprec = prec) >= 0)
|
||||
* -- ANSI X3J11
|
||||
*/
|
||||
cp = buf + BUF;
|
||||
if (_ulong != 0 || prec != 0) {
|
||||
if (_uquad != 0 || prec != 0) {
|
||||
/*
|
||||
* unsigned mod is hard, and unsigned mod
|
||||
* Unsigned mod is hard, and unsigned mod
|
||||
* by a constant is easier than that by
|
||||
* a variable; hence this switch.
|
||||
*/
|
||||
switch (base) {
|
||||
case OCT:
|
||||
do {
|
||||
*--cp = to_char(_ulong & 7);
|
||||
_ulong >>= 3;
|
||||
} while (_ulong);
|
||||
*--cp = to_char(_uquad & 7);
|
||||
_uquad >>= 3;
|
||||
} while (_uquad);
|
||||
/* handle octal leading 0 */
|
||||
if (flags & ALT && *cp != '0')
|
||||
*--cp = '0';
|
||||
@ -603,18 +549,18 @@ number: if ((dprec = prec) >= 0)
|
||||
|
||||
case DEC:
|
||||
/* many numbers are 1 digit */
|
||||
while (_ulong >= 10) {
|
||||
*--cp = to_char(_ulong % 10);
|
||||
_ulong /= 10;
|
||||
while (_uquad >= 10) {
|
||||
*--cp = to_char(_uquad % 10);
|
||||
_uquad /= 10;
|
||||
}
|
||||
*--cp = to_char(_ulong);
|
||||
*--cp = to_char(_uquad);
|
||||
break;
|
||||
|
||||
case HEX:
|
||||
do {
|
||||
*--cp = xdigs[_ulong & 15];
|
||||
_ulong >>= 4;
|
||||
} while (_ulong);
|
||||
*--cp = xdigs[_uquad & 15];
|
||||
_uquad >>= 4;
|
||||
} while (_uquad);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -638,28 +584,20 @@ number: if ((dprec = prec) >= 0)
|
||||
}
|
||||
|
||||
/*
|
||||
* All reasonable formats wind up here. At this point,
|
||||
* `cp' points to a string which (if not flags&LADJUST)
|
||||
* should be padded out to `width' places. If
|
||||
* flags&ZEROPAD, it should first be prefixed by any
|
||||
* sign or other prefix; otherwise, it should be blank
|
||||
* padded before the prefix is emitted. After any
|
||||
* left-hand padding and prefixing, emit zeroes
|
||||
* required by a decimal [diouxX] precision, then print
|
||||
* the string proper, then emit zeroes required by any
|
||||
* leftover floating precision; finally, if LADJUST,
|
||||
* pad with blanks.
|
||||
* All reasonable formats wind up here. At this point, `cp'
|
||||
* points to a string which (if not flags&LADJUST) should be
|
||||
* padded out to `width' places. If flags&ZEROPAD, it should
|
||||
* first be prefixed by any sign or other prefix; otherwise,
|
||||
* it should be blank padded before the prefix is emitted.
|
||||
* After any left-hand padding and prefixing, emit zeroes
|
||||
* required by a decimal [diouxX] precision, then print the
|
||||
* string proper, then emit zeroes required by any leftover
|
||||
* floating precision; finally, if LADJUST, pad with blanks.
|
||||
*
|
||||
* Compute actual size, so we know how much to pad.
|
||||
* fieldsz excludes decimal prec; realsz includes it.
|
||||
*/
|
||||
|
||||
/*
|
||||
* compute actual size, so we know how much to pad.
|
||||
* fieldsz excludes decimal prec; realsz includes it
|
||||
*/
|
||||
#ifdef FLOATING_POINT
|
||||
fieldsz = size + fpprec;
|
||||
#else
|
||||
fieldsz = size;
|
||||
#endif
|
||||
if (sign)
|
||||
fieldsz++;
|
||||
else if (flags & HEXPREFIX)
|
||||
@ -687,13 +625,53 @@ number: if ((dprec = prec) >= 0)
|
||||
PAD(dprec - fieldsz, zeroes);
|
||||
|
||||
/* the string or number proper */
|
||||
PRINT(cp, size);
|
||||
|
||||
#ifdef FLOATING_POINT
|
||||
/* trailing f.p. zeroes */
|
||||
PAD(fpprec, zeroes);
|
||||
if ((flags & FPT) == 0) {
|
||||
PRINT(cp, size);
|
||||
} else { /* glue together f_p fragments */
|
||||
if (ch >= 'f') { /* 'f' or 'g' */
|
||||
if (_double == 0) {
|
||||
/* kludge for __dtoa irregularity */
|
||||
if (prec == 0 ||
|
||||
(flags & ALT) == 0) {
|
||||
PRINT("0", 1);
|
||||
} else {
|
||||
PRINT("0.", 2);
|
||||
PAD(ndig - 1, zeroes);
|
||||
}
|
||||
} else if (expt <= 0) {
|
||||
PRINT("0.", 2);
|
||||
PAD(-expt, zeroes);
|
||||
PRINT(cp, ndig);
|
||||
} else if (expt >= ndig) {
|
||||
PRINT(cp, ndig);
|
||||
PAD(expt - ndig, zeroes);
|
||||
if (flags & ALT)
|
||||
PRINT(".", 1);
|
||||
} else {
|
||||
PRINT(cp, expt);
|
||||
cp += expt;
|
||||
PRINT(".", 1);
|
||||
PRINT(cp, ndig-expt);
|
||||
}
|
||||
} else { /* 'e' or 'E' */
|
||||
if (ndig > 1 || flags & ALT) {
|
||||
ox[0] = *cp++;
|
||||
ox[1] = '.';
|
||||
PRINT(ox, 2);
|
||||
if (_double || flags & ALT == 0) {
|
||||
PRINT(cp, ndig-1);
|
||||
} else /* 0.[0..] */
|
||||
/* __dtoa irregularity */
|
||||
PAD(ndig - 1, zeroes);
|
||||
} else /* XeYYY */
|
||||
PRINT(cp, 1);
|
||||
PRINT(expstr, expsize);
|
||||
}
|
||||
}
|
||||
#else
|
||||
PRINT(cp, size);
|
||||
#endif
|
||||
|
||||
/* left-adjusting padding (always blank) */
|
||||
if (flags & LADJUST)
|
||||
PAD(width - realsz, blanks);
|
||||
@ -711,257 +689,54 @@ error:
|
||||
}
|
||||
|
||||
#ifdef FLOATING_POINT
|
||||
#include <math.h>
|
||||
|
||||
static char *exponent();
|
||||
static char *round();
|
||||
extern char *__dtoa __P((double, int, int, int *, int *, char **));
|
||||
|
||||
static char *
|
||||
cvt(value, ndigits, flags, sign, decpt, ch, length)
|
||||
double value;
|
||||
int ndigits, flags, *decpt, ch, *length;
|
||||
char *sign;
|
||||
{
|
||||
int mode, dsgn;
|
||||
char *digits, *bp, *rve;
|
||||
|
||||
if (ch == 'f')
|
||||
mode = 3;
|
||||
else {
|
||||
mode = 2;
|
||||
}
|
||||
if (value < 0) {
|
||||
value = -value;
|
||||
*sign = '-';
|
||||
} else
|
||||
*sign = '\000';
|
||||
digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
|
||||
if (flags & ALT) { /* Print trailing zeros */
|
||||
bp = digits + ndigits;
|
||||
if (ch == 'f') {
|
||||
if (*digits == '0' && value)
|
||||
*decpt = -ndigits + 1;
|
||||
bp += *decpt;
|
||||
}
|
||||
if (value == 0) /* kludge for __dtoa irregularity */
|
||||
rve = bp;
|
||||
while (rve < bp)
|
||||
*rve++ = '0';
|
||||
}
|
||||
*length = rve - digits;
|
||||
return (digits);
|
||||
}
|
||||
|
||||
static int
|
||||
cvt(number, prec, flags, signp, fmtch, startp, endp)
|
||||
double number;
|
||||
register int prec;
|
||||
int flags;
|
||||
char *signp;
|
||||
int fmtch;
|
||||
char *startp, *endp;
|
||||
exponent(p0, exp, fmtch)
|
||||
char *p0;
|
||||
int exp, fmtch;
|
||||
{
|
||||
register char *p, *t;
|
||||
register double fract;
|
||||
int dotrim, expcnt, gformat;
|
||||
double integer, tmp;
|
||||
|
||||
dotrim = expcnt = gformat = 0;
|
||||
if (number < 0) {
|
||||
number = -number;
|
||||
*signp = '-';
|
||||
} else
|
||||
*signp = 0;
|
||||
|
||||
fract = modf(number, &integer);
|
||||
|
||||
/* get an extra slot for rounding. */
|
||||
t = ++startp;
|
||||
|
||||
/*
|
||||
* get integer portion of number; put into the end of the buffer; the
|
||||
* .01 is added for modf(356.0 / 10, &integer) returning .59999999...
|
||||
*/
|
||||
for (p = endp - 1; integer; ++expcnt) {
|
||||
tmp = modf(integer / 10, &integer);
|
||||
*p-- = to_char((int)((tmp + .01) * 10));
|
||||
}
|
||||
switch (fmtch) {
|
||||
case 'f':
|
||||
/* reverse integer into beginning of buffer */
|
||||
if (expcnt)
|
||||
for (; ++p < endp; *t++ = *p);
|
||||
else
|
||||
*t++ = '0';
|
||||
/*
|
||||
* if precision required or alternate flag set, add in a
|
||||
* decimal point.
|
||||
*/
|
||||
if (prec || flags&ALT)
|
||||
*t++ = '.';
|
||||
/* if requires more precision and some fraction left */
|
||||
if (fract) {
|
||||
if (prec)
|
||||
do {
|
||||
fract = modf(fract * 10, &tmp);
|
||||
*t++ = to_char((int)tmp);
|
||||
} while (--prec && fract);
|
||||
if (fract)
|
||||
startp = round(fract, (int *)NULL, startp,
|
||||
t - 1, (char)0, signp);
|
||||
}
|
||||
for (; prec--; *t++ = '0');
|
||||
break;
|
||||
case 'e':
|
||||
case 'E':
|
||||
eformat: if (expcnt) {
|
||||
*t++ = *++p;
|
||||
if (prec || flags&ALT)
|
||||
*t++ = '.';
|
||||
/* if requires more precision and some integer left */
|
||||
for (; prec && ++p < endp; --prec)
|
||||
*t++ = *p;
|
||||
/*
|
||||
* if done precision and more of the integer component,
|
||||
* round using it; adjust fract so we don't re-round
|
||||
* later.
|
||||
*/
|
||||
if (!prec && ++p < endp) {
|
||||
fract = 0;
|
||||
startp = round((double)0, &expcnt, startp,
|
||||
t - 1, *p, signp);
|
||||
}
|
||||
/* adjust expcnt for digit in front of decimal */
|
||||
--expcnt;
|
||||
}
|
||||
/* until first fractional digit, decrement exponent */
|
||||
else if (fract) {
|
||||
/* adjust expcnt for digit in front of decimal */
|
||||
for (expcnt = -1;; --expcnt) {
|
||||
fract = modf(fract * 10, &tmp);
|
||||
if (tmp)
|
||||
break;
|
||||
}
|
||||
*t++ = to_char((int)tmp);
|
||||
if (prec || flags&ALT)
|
||||
*t++ = '.';
|
||||
}
|
||||
else {
|
||||
*t++ = '0';
|
||||
if (prec || flags&ALT)
|
||||
*t++ = '.';
|
||||
}
|
||||
/* if requires more precision and some fraction left */
|
||||
if (fract) {
|
||||
if (prec)
|
||||
do {
|
||||
fract = modf(fract * 10, &tmp);
|
||||
*t++ = to_char((int)tmp);
|
||||
} while (--prec && fract);
|
||||
if (fract)
|
||||
startp = round(fract, &expcnt, startp,
|
||||
t - 1, (char)0, signp);
|
||||
}
|
||||
/* if requires more precision */
|
||||
for (; prec--; *t++ = '0');
|
||||
|
||||
/* unless alternate flag, trim any g/G format trailing 0's */
|
||||
if (gformat && !(flags&ALT)) {
|
||||
while (t > startp && *--t == '0');
|
||||
if (*t == '.')
|
||||
--t;
|
||||
++t;
|
||||
}
|
||||
t = exponent(t, expcnt, fmtch);
|
||||
break;
|
||||
case 'g':
|
||||
case 'G':
|
||||
/* a precision of 0 is treated as a precision of 1. */
|
||||
if (!prec)
|
||||
++prec;
|
||||
/*
|
||||
* ``The style used depends on the value converted; style e
|
||||
* will be used only if the exponent resulting from the
|
||||
* conversion is less than -4 or greater than the precision.''
|
||||
* -- ANSI X3J11
|
||||
*/
|
||||
if (expcnt > prec || !expcnt && fract && fract < .0001) {
|
||||
/*
|
||||
* g/G format counts "significant digits, not digits of
|
||||
* precision; for the e/E format, this just causes an
|
||||
* off-by-one problem, i.e. g/G considers the digit
|
||||
* before the decimal point significant and e/E doesn't
|
||||
* count it as precision.
|
||||
*/
|
||||
--prec;
|
||||
fmtch -= 2; /* G->E, g->e */
|
||||
gformat = 1;
|
||||
goto eformat;
|
||||
}
|
||||
/*
|
||||
* reverse integer into beginning of buffer,
|
||||
* note, decrement precision
|
||||
*/
|
||||
if (expcnt)
|
||||
for (; ++p < endp; *t++ = *p, --prec);
|
||||
else
|
||||
*t++ = '0';
|
||||
/*
|
||||
* if precision required or alternate flag set, add in a
|
||||
* decimal point. If no digits yet, add in leading 0.
|
||||
*/
|
||||
if (prec || flags&ALT) {
|
||||
dotrim = 1;
|
||||
*t++ = '.';
|
||||
}
|
||||
else
|
||||
dotrim = 0;
|
||||
/* if requires more precision and some fraction left */
|
||||
if (fract) {
|
||||
if (prec) {
|
||||
do {
|
||||
fract = modf(fract * 10, &tmp);
|
||||
*t++ = to_char((int)tmp);
|
||||
} while(!tmp);
|
||||
while (--prec && fract) {
|
||||
fract = modf(fract * 10, &tmp);
|
||||
*t++ = to_char((int)tmp);
|
||||
}
|
||||
}
|
||||
if (fract)
|
||||
startp = round(fract, (int *)NULL, startp,
|
||||
t - 1, (char)0, signp);
|
||||
}
|
||||
/* alternate format, adds 0's for precision, else trim 0's */
|
||||
if (flags&ALT)
|
||||
for (; prec--; *t++ = '0');
|
||||
else if (dotrim) {
|
||||
while (t > startp && *--t == '0');
|
||||
if (*t != '.')
|
||||
++t;
|
||||
}
|
||||
}
|
||||
return (t - startp);
|
||||
}
|
||||
|
||||
static char *
|
||||
round(fract, exp, start, end, ch, signp)
|
||||
double fract;
|
||||
int *exp;
|
||||
register char *start, *end;
|
||||
char ch, *signp;
|
||||
{
|
||||
double tmp;
|
||||
|
||||
if (fract)
|
||||
(void)modf(fract * 10, &tmp);
|
||||
else
|
||||
tmp = to_digit(ch);
|
||||
if (tmp > 4)
|
||||
for (;; --end) {
|
||||
if (*end == '.')
|
||||
--end;
|
||||
if (++*end <= '9')
|
||||
break;
|
||||
*end = '0';
|
||||
if (end == start) {
|
||||
if (exp) { /* e/E; increment exponent */
|
||||
*end = '1';
|
||||
++*exp;
|
||||
}
|
||||
else { /* f; add extra digit */
|
||||
*--end = '1';
|
||||
--start;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
|
||||
else if (*signp == '-')
|
||||
for (;; --end) {
|
||||
if (*end == '.')
|
||||
--end;
|
||||
if (*end != '0')
|
||||
break;
|
||||
if (end == start)
|
||||
*signp = 0;
|
||||
}
|
||||
return (start);
|
||||
}
|
||||
|
||||
static char *
|
||||
exponent(p, exp, fmtch)
|
||||
register char *p;
|
||||
register int exp;
|
||||
int fmtch;
|
||||
{
|
||||
register char *t;
|
||||
char expbuf[MAXEXP];
|
||||
|
||||
p = p0;
|
||||
*p++ = fmtch;
|
||||
if (exp < 0) {
|
||||
exp = -exp;
|
||||
@ -981,6 +756,6 @@ exponent(p, exp, fmtch)
|
||||
*p++ = '0';
|
||||
*p++ = to_char(exp);
|
||||
}
|
||||
return (p);
|
||||
return (p - p0);
|
||||
}
|
||||
#endif /* FLOATING_POINT */
|
||||
|
@ -35,7 +35,7 @@
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)vfscanf.c 5.6 (Berkeley) 2/24/91";
|
||||
static char sccsid[] = "@(#)vfscanf.c 5.7 (Berkeley) 12/14/92";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <stdio.h>
|
||||
@ -50,12 +50,8 @@ static char sccsid[] = "@(#)vfscanf.c 5.6 (Berkeley) 2/24/91";
|
||||
|
||||
#define FLOATING_POINT
|
||||
|
||||
#ifdef FLOATING_POINT
|
||||
#include "floatio.h"
|
||||
#define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */
|
||||
#else
|
||||
#define BUF 40
|
||||
#endif
|
||||
#define BUF 513 /* Maximum length of numeric string. */
|
||||
|
||||
/*
|
||||
* Flags used during conversion.
|
||||
@ -101,7 +97,7 @@ static u_char *__sccl();
|
||||
__svfscanf(fp, fmt0, ap)
|
||||
register FILE *fp;
|
||||
char const *fmt0;
|
||||
_VA_LIST_ ap;
|
||||
va_list ap;
|
||||
{
|
||||
register u_char *fmt = (u_char *)fmt0;
|
||||
register int c; /* character from format, or conversion */
|
||||
@ -635,7 +631,7 @@ literal:
|
||||
double res;
|
||||
|
||||
*p = 0;
|
||||
res = atof(buf);
|
||||
res = strtod(buf, (char **) NULL);
|
||||
if (flags & LONG)
|
||||
*va_arg(ap, double *) = res;
|
||||
else
|
||||
|
@ -3,10 +3,10 @@
|
||||
# stdlib sources
|
||||
.PATH: ${.CURDIR}/${MACHINE}/stdlib ${.CURDIR}/stdlib
|
||||
|
||||
SRCS+= abort.c atexit.c atoi.c atol.c bsearch.c calloc.c div.c exit.c \
|
||||
SRCS+= abort.c atexit.c atoi.c atof.c atol.c bsearch.c calloc.c div.c exit.c \
|
||||
getenv.c getopt.c heapsort.c labs.c ldiv.c malloc.c multibyte.c \
|
||||
putenv.c qsort.c radixsort.c rand.c random.c setenv.c strtol.c \
|
||||
strtoul.c system.c
|
||||
putenv.c qsort.c radixsort.c rand.c random.c setenv.c strtod.c \
|
||||
strtol.c strtoul.c system.c
|
||||
|
||||
.if (${MACHINE} == "hp300")
|
||||
SRCS+= abs.s atof.c
|
||||
|
@ -32,7 +32,7 @@
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)atof.c 5.2 (Berkeley) 6/1/90";
|
||||
static char sccsid[] = "@(#)atof.c 5.3 (Berkeley) 1/8/93";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
2410
lib/libc/stdlib/strtod.c
Normal file
2410
lib/libc/stdlib/strtod.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user