Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Johnston <jjohnstn@redhat.com>2000-12-07 02:50:11 +0300
committerJeff Johnston <jjohnstn@redhat.com>2000-12-07 02:50:11 +0300
commit6bdac416e9e1aecfb94cd3ae383889cc7b7e62e3 (patch)
tree0871ae257bee23aa786ad2ac43aeb3470d340f5f /newlib/libc/stdio
parent81e615de9818b0094abea875b60ca955edfcec9c (diff)
2000-12-06 Jeff Johnston <jjohnstn@redhat.com>
* libc/stdlib/Makefile.am: Added ldtoa.c to list of sources. * libc/stdlib/Makefile.in: Regenerated. * libc/stdio/floatio.h: Added suitable MAXEXP for long double. * libc/stdio/vfieeefp.h: Added long double bit structures. * libc/stdio/vfprintf.c[WANT_IO_LONG_DBL]: Added long double support. [WANT_IO_LONG_DBL](isinfl, isnanl): New static long double routines. (exponent): Changed expbuf to reasonable maximum instead of MAXEXP. * libc/stdio/vfscanf.c[WANT_IO_LONG_DBL]: Added long double support. * libc/stdlib/ldtoa.c: New file containing _ldtoa_r and _strtold routines used for conversions between character and long double.
Diffstat (limited to 'newlib/libc/stdio')
-rw-r--r--newlib/libc/stdio/floatio.h5
-rw-r--r--newlib/libc/stdio/vfieeefp.h79
-rw-r--r--newlib/libc/stdio/vfprintf.c130
-rw-r--r--newlib/libc/stdio/vfscanf.c28
4 files changed, 223 insertions, 19 deletions
diff --git a/newlib/libc/stdio/floatio.h b/newlib/libc/stdio/floatio.h
index d9577b2b2..496721b88 100644
--- a/newlib/libc/stdio/floatio.h
+++ b/newlib/libc/stdio/floatio.h
@@ -21,7 +21,12 @@
* Floating point scanf/printf (input/output) definitions.
*/
+#ifdef _NO_LONGDBL
/* 11-bit exponent (VAX G floating point) is 308 decimal digits */
#define MAXEXP 308
+#else /* !_NO_LONGDBL */
+/* 15-bit exponent (Intel extended floating point) is 4932 decimal digits */
+#define MAXEXP 4932
+#endif /* !_NO_LONGDBL */
/* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
#define MAXFRACT 39
diff --git a/newlib/libc/stdio/vfieeefp.h b/newlib/libc/stdio/vfieeefp.h
index 6843d5f47..de0267223 100644
--- a/newlib/libc/stdio/vfieeefp.h
+++ b/newlib/libc/stdio/vfieeefp.h
@@ -57,6 +57,85 @@
Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined.
#endif
+#ifdef WANT_IO_LONG_DBL
+/* If we are going to examine or modify specific bits in a long double using
+ the lword0 or lwordx macros, then we must wrap the long double inside
+ a union. This is necessary to avoid undefined behavior according to
+ the ANSI C spec. */
+
+#ifdef IEEE_8087
+#if LDBL_MANT_DIG == 24
+struct ldieee
+{
+ unsigned manh:23;
+ unsigned exp:8;
+ unsigned sign:1;
+}
+#elif LDBL_MANT_DIG == 53
+struct ldieee
+{
+ unsigned manl:20;
+ unsigned manh:32;
+ unsigned exp:11;
+ unsigned sign:1;
+}
+#elif LDBL_MANT_DIG == 64
+struct ldieee
+{
+ unsigned manl:32;
+ unsigned manh:32;
+ unsigned exp:15;
+ unsigned sign:1;
+};
+#elif LDBL_MANT_DIG > 64
+struct ldieee
+{
+ unsigned manl3:16;
+ unsigned manl2:32;
+ unsigned manl:32;
+ unsigned manh:32;
+ unsigned exp:15;
+ unsigned sign:1;
+};
+#endif /* LDBL_MANT_DIG */
+#else /* !IEEE_8087 */
+#if LDBL_MANT_DIG == 24
+struct ldieee
+{
+ unsigned sign:1;
+ unsigned exp:8;
+ unsigned manh:23;
+}
+#elif LDBL_MANT_DIG == 53
+struct ldieee
+{
+ unsigned sign:1;
+ unsigned exp:11;
+ unsigned manh:32;
+ unsigned manl:20;
+}
+#elif LDBL_MANT_DIG == 64
+struct ldieee
+{
+ unsigned sign:1;
+ unsigned exp:15;
+ unsigned manh:32;
+ unsigned manl:32;
+}
+#elif LDBL_MANT_DIG > 64
+struct ldieee
+{
+ unsigned sign:1;
+ unsigned exp:15;
+ unsigned manh:32;
+ unsigned manl:32;
+ unsigned manl2:32;
+ unsigned manl3;16;
+};
+#endif /* LDBL_MANT_DIG */
+#endif /* !IEEE_8087 */
+#endif /* WANT_IO_LONG_DBL */
+
/* If we are going to examine or modify specific bits in a double using
the word0 and/or word1 macros, then we must wrap the double inside
a union. This is necessary to avoid undefined behavior according to
diff --git a/newlib/libc/stdio/vfprintf.c b/newlib/libc/stdio/vfprintf.c
index 117f7eb80..ea458467d 100644
--- a/newlib/libc/stdio/vfprintf.c
+++ b/newlib/libc/stdio/vfprintf.c
@@ -174,6 +174,14 @@ static char *rcsid = "$Id$";
#include "fvwrite.h"
#include "vfieeefp.h"
+/* Currently a test is made to see if long double processing is warranted.
+ This could be changed in the future should the _ldtoa_r code be
+ preferred over _dtoa_r. */
+#define _NO_LONGDBL
+#if defined WANT_IO_LONG_DBL && (LDBL_MANT_DIG > DBL_MANT_DIG)
+#undef _NO_LONGDBL
+#endif
+
/*
* Flush out all the vectors defined by the given uio,
* then reset it so that it can be reused.
@@ -240,7 +248,14 @@ __sbprintf(fp, fmt, ap)
#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
#define DEFPREC 6
+#ifdef _NO_LONGDBL
static char *cvt _PARAMS((struct _reent *, double, int, int, char *, int *, int, int *));
+#else
+static char *cvt _PARAMS((struct _reent *, _LONG_DOUBLE, int, int, char *, int *, int, int *));
+static int isinfl _PARAMS((_LONG_DOUBLE *));
+static int isnanl _PARAMS((_LONG_DOUBLE *));
+#endif
+
static int exponent _PARAMS((char *, int, int));
#else /* no FLOATING_POINT */
@@ -263,7 +278,7 @@ static int exponent _PARAMS((char *, int, int));
#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 LONGDBL 0x008 /* long double */
#define LONGINT 0x010 /* long integer */
#define QUADINT 0x020 /* quad integer */
#define SHORTINT 0x040 /* short integer */
@@ -301,9 +316,13 @@ _DEFUN (_VFPRINTF_R, (data, fp, fmt0, ap),
#ifdef FLOATING_POINT
char *decimal_point = localeconv()->decimal_point;
char softsign; /* temporary negative sign for floats */
- double _double; /* double precision arguments %[eEfgG] */
+#ifdef _NO_LONGDBL
+ double _fpvalue; /* floating point arguments %[eEfgG] */
+#else
+ _LONG_DOUBLE _fpvalue; /* floating point arguments %[eEfgG] */
+#endif
int expt; /* integer value of exponent */
- int expsize; /* character count for expstr */
+ int expsize = 0; /* character count for expstr */
int ndig; /* actual number of digits returned by cvt */
char expstr[7]; /* buffer for exponent string */
#endif
@@ -322,7 +341,7 @@ _DEFUN (_VFPRINTF_R, (data, fp, fmt0, ap),
int dprec; /* a copy of prec if [diouxX], 0 otherwise */
int realsz; /* field size expanded by dprec */
int size; /* size of converted field or string */
- char *xdigs; /* digits for [xX] conversion */
+ char *xdigs = NULL; /* digits for [xX] conversion */
#define NIOV 8
struct __suio uio; /* output information: summary */
struct __siov iov[NIOV];/* ... and individual io vectors */
@@ -553,29 +572,55 @@ reswitch: switch (ch) {
prec = 1;
}
+#ifdef _NO_LONGDBL
+ if (flags & LONGDBL) {
+ _fpvalue = (double) va_arg(ap, _LONG_DOUBLE);
+ } else {
+ _fpvalue = va_arg(ap, double);
+ }
+
+ /* do this before tricky precision changes */
+ if (isinf(_fpvalue)) {
+ if (_fpvalue < 0)
+ sign = '-';
+ cp = "Inf";
+ size = 3;
+ break;
+ }
+ if (isnan(_fpvalue)) {
+ cp = "NaN";
+ size = 3;
+ break;
+ }
+
+#else /* !_NO_LONGDBL */
+
if (flags & LONGDBL) {
- _double = (double) va_arg(ap, long double);
+ _fpvalue = va_arg(ap, _LONG_DOUBLE);
} else {
- _double = va_arg(ap, double);
+ _fpvalue = (_LONG_DOUBLE)va_arg(ap, double);
}
/* do this before tricky precision changes */
- if (isinf(_double)) {
- if (_double < 0)
+ if (isinfl(&_fpvalue)) {
+ if (_fpvalue < 0)
sign = '-';
cp = "Inf";
size = 3;
break;
}
- if (isnan(_double)) {
+ if (isnanl(&_fpvalue)) {
cp = "NaN";
size = 3;
break;
}
+#endif /* !_NO_LONGDBL */
flags |= FPT;
- cp = cvt(data, _double, prec, flags, &softsign,
+
+ cp = cvt(data, _fpvalue, prec, flags, &softsign,
&expt, ch, &ndig);
+
if (ch == 'g' || ch == 'G') {
if (expt <= -4 || expt > prec)
ch = (ch == 'g') ? 'e' : 'E';
@@ -796,7 +841,7 @@ number: if ((dprec = prec) >= 0)
PRINT(cp, size);
} else { /* glue together f_p fragments */
if (ch >= 'f') { /* 'f' or 'g' */
- if (_double == 0) {
+ if (_fpvalue == 0) {
/* kludge for __dtoa irregularity */
PRINT("0", 1);
if (expt < ndig || (flags & ALT) != 0) {
@@ -826,7 +871,7 @@ number: if ((dprec = prec) >= 0)
ox[0] = *cp++;
ox[1] = '.';
PRINT(ox, 2);
- if (_double) {
+ if (_fpvalue) {
PRINT(cp, ndig-1);
} else /* 0.[0..] */
/* __dtoa irregularity */
@@ -857,19 +902,60 @@ error:
#ifdef FLOATING_POINT
+#ifdef _NO_LONGDBL
extern char *_dtoa_r _PARAMS((struct _reent *, double, int,
int, int *, int *, char **));
+#else
+extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int,
+ int, int *, int *, char **));
+#undef word0
+#define word0(x) ldword0(x)
+
+static int
+isinfl (value)
+ _LONG_DOUBLE *value;
+{
+ struct ldieee *ldptr;
+
+ ldptr = (struct ldieee *)value;
+
+ if (ldptr->exp == 0x7fff && !(ldptr->manh & 0x7fffffff) && !ldptr->manl)
+ return 1;
+ return 0;
+}
+
+static int
+isnanl (value)
+ _LONG_DOUBLE *value;
+{
+ struct ldieee *ldptr;
+
+ ldptr = (struct ldieee *)value;
+
+ if (ldptr->exp == 0x7fff && ((ldptr->manh & 0x7fffffff) || ldptr->manl))
+ return 1;
+ return 0;
+}
+#endif
static char *
cvt(data, value, ndigits, flags, sign, decpt, ch, length)
struct _reent *data;
+#ifdef _NO_LONGDBL
double value;
+#else
+ _LONG_DOUBLE value;
+#endif
int ndigits, flags, *decpt, ch, *length;
char *sign;
{
int mode, dsgn;
char *digits, *bp, *rve;
+#ifdef _NO_LONGDBL
union double_union tmp;
+#else
+ struct ldieee *ldptr;
+#endif
if (ch == 'f') {
mode = 3; /* ndigits after the decimal point */
@@ -884,13 +970,27 @@ cvt(data, value, ndigits, flags, sign, decpt, ch, length)
mode = 2; /* ndigits significant digits */
}
+#ifdef _NO_LONGDBL
tmp.d = value;
+
if (word0(tmp) & Sign_bit) { /* this will check for < 0 and -0.0 */
value = -value;
*sign = '-';
} else
*sign = '\000';
+
digits = _dtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve);
+#else /* !_NO_LONGDBL */
+ ldptr = (struct ldieee *)&value;
+ if (ldptr->sign) { /* this will check for < 0 and -0.0 */
+ value = -value;
+ *sign = '-';
+ } else
+ *sign = '\000';
+
+ digits = _ldtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve);
+#endif /* !_NO_LONGDBL */
+
if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */
bp = digits + ndigits;
if (ch == 'f') {
@@ -913,7 +1013,7 @@ exponent(p0, exp, fmtch)
int exp, fmtch;
{
register char *p, *t;
- char expbuf[MAXEXP];
+ char expbuf[40];
p = p0;
*p++ = fmtch;
@@ -923,13 +1023,13 @@ exponent(p0, exp, fmtch)
}
else
*p++ = '+';
- t = expbuf + MAXEXP;
+ t = expbuf + 40;
if (exp > 9) {
do {
*--t = to_char(exp % 10);
} while ((exp /= 10) > 9);
*--t = to_char(exp);
- for (; t < expbuf + MAXEXP; *p++ = *t++);
+ for (; t < expbuf + 40; *p++ = *t++);
}
else {
*p++ = '0';
diff --git a/newlib/libc/stdio/vfscanf.c b/newlib/libc/stdio/vfscanf.c
index 7e88f1202..cc0f26d3c 100644
--- a/newlib/libc/stdio/vfscanf.c
+++ b/newlib/libc/stdio/vfscanf.c
@@ -34,6 +34,17 @@
#endif
#ifdef FLOATING_POINT
+#include <float.h>
+
+/* Currently a test is made to see if long double processing is warranted.
+ This could be changed in the future should the _ldtoa_r code be
+ preferred over _dtoa_r. */
+#define _NO_LONGDBL
+#if defined WANT_IO_LONG_DBL && (LDBL_MANT_DIG > DBL_MANT_DIG)
+#undef _NO_LONGDBL
+extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr));
+#endif
+
#include "floatio.h"
#define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */
/* An upper bound for how long a long prints in decimal. 4 / 13 approximates
@@ -48,7 +59,7 @@
*/
#define LONG 0x01 /* l: long or double */
-#define LONGDBL 0x02 /* L: long double; unimplemented */
+#define LONGDBL 0x02 /* L: long double */
#define SHORT 0x04 /* h: short */
#define SUPPRESS 0x08 /* suppress assignment */
#define POINTER 0x10 /* weird %p pointer (`fake hex') */
@@ -372,7 +383,7 @@ __svfscanf (fp, fmt0, ap)
for (;;)
{
- if ((n = fp->_r) < width)
+ if ((n = fp->_r) < (int)width)
{
sum += n;
width -= n;
@@ -683,8 +694,9 @@ __svfscanf (fp, fmt0, ap)
However, ANSI / ISO C makes no such stipulation; we have to get
exact results even when there is an unreasonable amount of
leading zeroes. */
- long leading_zeroes, zeroes, exp_adjust;
- char *exp_start;
+ long leading_zeroes = 0;
+ long zeroes, exp_adjust;
+ char *exp_start = NULL;
#ifdef hardway
if (width == 0 || width > sizeof (buf) - 1)
width = sizeof (buf) - 1;
@@ -808,7 +820,11 @@ __svfscanf (fp, fmt0, ap)
}
if ((flags & SUPPRESS) == 0)
{
+#ifdef _NO_LONGDBL
double res;
+#else /* !_NO_LONG_DBL */
+ long double res;
+#endif /* !_NO_LONG_DBL */
long new_exp;
*p = 0;
@@ -829,7 +845,11 @@ __svfscanf (fp, fmt0, ap)
exp_start = buf + sizeof (buf) - MAX_LONG_LEN - 1;
sprintf (exp_start, "e%ld", new_exp);
}
+#ifdef _NO_LONG_DBL
res = atof (buf);
+#else /* !_NO_LONG_DBL */
+ res = _strtold (buf, NULL);
+#endif /* !_NO_LONG_DBL */
if (flags & LONG)
{
dp = va_arg (ap, double *);