Commit 7984a2f0 by Paul Brook Committed by Paul Brook

re PR libfortran/17195 (Infinite loop in output_float in libgfortran/io/write.c)

	PR libfortran/17195
	* libgfortran.h (rtoa): Remove prototype.
	* runtime/error.c (rtoa): Remove.
	* io/write.c (calculate_G_format): Don't add blanks if E format is
	used.  Add correct number of blanks when exponent width is specified.
	(output_float): Rewrite.
testsuite/
	* gfortran.dg/edit_real_1.f90: New test.

From-SVN: r86701
parent 39b8ce7f
2004-08-28 Paul Brook <paul@codesourcery.com>
PR libfortran/17195
* gfortran.dg/edit_real_1.f90: New test.
2004-08-27 Paul Brook <paul@codesourcery.com> 2004-08-27 Paul Brook <paul@codesourcery.com>
* gfortran.dg/rewind_1.f90: New test. * gfortran.dg/rewind_1.f90: New test.
......
! { dg-do run }
! Check real value edit descriptors
! Also checks that rounding is performed correctly
program edit_real_1
character(len=20) s
character(len=20) x
character(len=200) t
parameter (x = "xxxxxxxxxxxxxxxxxxxx")
! W append a "z" onto each test to check the field is the correct width
s = x
! G -> F format
write (s, '(G10.3,A)') 12.36, "z"
if (s .ne. " 12.4 z") call abort
s = x
! G -> E format
write (s, '(G10.3,A)') -0.0012346, "z"
if (s .ne. "-0.123E-02z") call abort
s = x
! Gw.eEe format
write (s, '(G10.3e1,a)') 12.34, "z"
if (s .ne. " 12.3 z") call abort
! E format with excessive precision
write (t, '(E199.192,A)') 1.5, "z"
if ((t(1:7) .ne. " 0.1500") .or. (t(194:200) .ne. "00E+01z")) call abort
! EN format
s = x
write (s, '(EN15.3,A)') 12873.6, "z"
if (s .ne. " 12.874E+03z") call abort
! EN format, negative exponent
s = x
write (s, '(EN15.3,A)') 12.345e-6, "z"
if (s .ne. " 12.345E-06z") call abort
! ES format
s = x
write (s, '(ES10.3,A)') 16.235, "z"
if (s .ne. " 1.624E+01z") call abort
! F format, small number
s = x
write (s, '(F10.8,A)') 1.0e-20, "z"
if (s .ne. "0.00000000z") call abort
! E format, very large number.
! Used to overflow with positive scale factor
s = x
write (s, '(1PE10.3,A)') huge(0d0), "z"
! The actual value is target specific, so just do a basic check
if ((s(1:1) .eq. "*") .or. (s(7:7) .ne. "+") .or. &
(s(11:11) .ne. "z")) call abort
! F format, round up with carry to most significant digit.
s = x
write (s, '(F10.3,A)') 0.9999, "z"
if (s .ne. " 1.000z") call abort
! F format, round up with carry to most significant digit < 0.1.
s = x
write (s, '(F10.3,A)') 0.0099, "z"
if (s .ne. " 0.010z") call abort
! E format, round up with carry to most significant digit.
s = x
write (s, '(E10.3,A)') 0.9999, "z"
if (s .ne. " 0.100E+01z") call abort
! EN format, round up with carry to most significant digit.
s = x
write (s, '(EN15.3,A)') 999.9999, "z"
if (s .ne. " 1.000E+03z") call abort
end
2004-08-28 Paul Brook <paul@codesourcery.com>
PR libfortran/17195
* libgfortran.h (rtoa): Remove prototype.
* runtime/error.c (rtoa): Remove.
* io/write.c (calculate_G_format): Don't add blanks if E format is
used. Add correct number of blanks when exponent width is specified.
(output_float): Rewrite.
2004-08-27 Paul Brook <paul@codesourcery.com> 2004-08-27 Paul Brook <paul@codesourcery.com>
* io/rewind.c (st_rewind): Reset unit to read mode. * io/rewind.c (st_rewind): Reset unit to read mode.
......
...@@ -24,6 +24,7 @@ Boston, MA 02111-1307, USA. */ ...@@ -24,6 +24,7 @@ Boston, MA 02111-1307, USA. */
#include "libgfortran.h" #include "libgfortran.h"
#include "io.h" #include "io.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#define star_fill(p, n) memset(p, '*', n) #define star_fill(p, n) memset(p, '*', n)
...@@ -150,7 +151,7 @@ calculate_exp (int d) ...@@ -150,7 +151,7 @@ calculate_exp (int d)
/* Generate corresponding I/O format for FMT_G output. /* Generate corresponding I/O format for FMT_G output.
The rules to translate FMT_G to FMT_E or FNT_F from DEC fortran The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran
LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is: LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is:
Data Magnitude Equivalent Conversion Data Magnitude Equivalent Conversion
...@@ -192,7 +193,7 @@ calculate_G_format (fnode *f, double value, int len, int *num_blank) ...@@ -192,7 +193,7 @@ calculate_G_format (fnode *f, double value, int len, int *num_blank)
newf->u.real.w = w; newf->u.real.w = w;
newf->u.real.d = d; newf->u.real.d = d;
newf->u.real.e = e; newf->u.real.e = e;
*num_blank = e + 2; *num_blank = 0;
return newf; return newf;
} }
...@@ -232,9 +233,15 @@ calculate_G_format (fnode *f, double value, int len, int *num_blank) ...@@ -232,9 +233,15 @@ calculate_G_format (fnode *f, double value, int len, int *num_blank)
break; break;
} }
/* Generate the F editing. F(w-4).(-(mid-d-1)), 4' '. */ /* Pad with blanks where the exponent would be. */
if (e < 0)
*num_blank = 4;
else
*num_blank = e + 2;
/* Generate the F editing. F(w-n).(-(mid-d-1)), n' '. */
newf->format = FMT_F; newf->format = FMT_F;
newf->u.real.w = f->u.real.w - 4; newf->u.real.w = f->u.real.w - *num_blank;
/* Special case. */ /* Special case. */
if (m == 0.0) if (m == 0.0)
...@@ -242,8 +249,6 @@ calculate_G_format (fnode *f, double value, int len, int *num_blank) ...@@ -242,8 +249,6 @@ calculate_G_format (fnode *f, double value, int len, int *num_blank)
else else
newf->u.real.d = - (mid - d - 1); newf->u.real.d = - (mid - d - 1);
*num_blank = 4;
/* For F editing, the scale factor is ignored. */ /* For F editing, the scale factor is ignored. */
g.scale_factor = 0; g.scale_factor = 0;
return newf; return newf;
...@@ -255,229 +260,348 @@ calculate_G_format (fnode *f, double value, int len, int *num_blank) ...@@ -255,229 +260,348 @@ calculate_G_format (fnode *f, double value, int len, int *num_blank)
static void static void
output_float (fnode *f, double value, int len) output_float (fnode *f, double value, int len)
{ {
int w, d, e, e_new; /* This must be large enough to accurately hold any value. */
int digits; char buffer[32];
int nsign, nblank, nesign; char *out;
int sca, neval, itmp; char *digits;
char *p; int e;
const char *q, *intstr, *base; char expchar;
double n;
format_token ft; format_token ft;
char exp_char = 'E'; int w;
int with_exp = 1; int d;
int scale_flag = 1 ; int edigits;
double minv = 0.0, maxv = 0.0; int ndigits;
sign_t sign = SIGN_NONE, esign = SIGN_NONE; /* Number of digits before the decimal point. */
int nbefore;
int intval = 0, intlen = 0; /* Number of zeros after the decimal point. */
int j; int nzero;
/* Number of digits after the decimal point. */
/* EXP value for this number. */ int nafter;
neval = 0; int leadzero;
int nblanks;
/* Width of EXP and it's sign. */ int i;
nesign = 0; sign_t sign;
ft = f->format; ft = f->format;
w = f->u.real.w; w = f->u.real.w;
d = f->u.real.d + 1; d = f->u.real.d;
/* We should always know the field width and precision. */
if (d < 0)
internal_error ("Uspecified precision");
/* Use sprintf to print the number in the format +D.DDDDe+ddd
For an N digit exponent, this gives us (32-6)-N digits after the
decimal point, plus annother one before the decimal point. */
sign = calculate_sign (value < 0.0);
if (value < 0)
value = -value;
/* Printf always prints at least two exponent digits. */
if (value == 0)
edigits = 2;
else
{
edigits = 1 + (int) log10 (fabs(log10 (value)));
if (edigits < 2)
edigits = 2;
}
/* Width of the EXP. */ if (FMT_F || FMT_ES)
e = 0; {
/* Always convert at full precision to avoid double rounding. */
ndigits = 27 - edigits;
}
else
{
/* We know the number of digits, so can let printf do the rounding
for us. */
if (ft == FMT_ES)
ndigits = d + 1;
else
ndigits = d;
if (ndigits > 27 - edigits)
ndigits = 27 - edigits;
}
sca = g.scale_factor; sprintf (buffer, "%+-31.*e", ndigits - 1, value);
n = value;
sign = calculate_sign (n < 0.0); /* Check the resulting string has punctuation in the correct places. */
if (n < 0) if (buffer[2] != '.' || buffer[ndigits + 2] != 'e')
n = -n; {
printf ("'%s', %d\n", buffer, ndigits);
internal_error ("printf is broken");
}
/* Width of the sign for the whole number. */ /* Read the exponent back in. */
nsign = (sign == SIGN_NONE ? 0 : 1); e = atoi (&buffer[ndigits + 3]) + 1;
/* Make sure zero comes out as 0.0e0. */
if (value == 0.0)
e = 0;
digits = 0; /* Normalize the fractional component. */
if (ft != FMT_F) buffer[2] = buffer[1];
digits = &buffer[2];
/* Figure out where to place the decimal point. */
switch (ft)
{
case FMT_F:
nbefore = e + g.scale_factor;
if (nbefore < 0)
{ {
e = f->u.real.e; nzero = -nbefore;
if (nzero > d)
nzero = d;
nafter = d - nzero;
nbefore = 0;
} }
if (ft == FMT_F || ft == FMT_E || ft == FMT_D) else
{ {
if (ft == FMT_F) nzero = 0;
scale_flag = 0; nafter = d;
if (ft == FMT_D) }
exp_char = 'D' ; expchar = 0;
minv = 0.1; break;
maxv = 1.0;
/* Calculate the new val of the number with consideration case FMT_E:
of global scale value. */ case FMT_D:
while (sca > 0) i = g.scale_factor;
if (i < 0)
{
nbefore = 0;
nzero = -i;
nafter = d + i;
}
else
{ {
minv *= 10.0; nbefore = i;
maxv *= 10.0; nzero = 0;
n *= 10.0; nafter = d - i;
sca -- ;
neval --;
} }
if (ft = FMT_E)
expchar = 'E';
else
expchar = 'D';
break;
/* Now calculate the new Exp value for this number. */ case FMT_EN:
sca = g.scale_factor; /* The exponent must be a multiple of three, with 1-3 digits before
while(sca >= 1) the decimal point. */
e--;
if (e >= 0)
nbefore = e % 3;
else
{ {
sca /= 10; nbefore = (-e) % 3;
digits ++ ; if (nbefore != 0)
nbefore = 3 - nbefore;
} }
e -= nbefore;
nbefore++;
nzero = 0;
nafter = d;
expchar = 'E';
break;
case FMT_ES:
e--;
nbefore = 1;
nzero = 0;
nafter = d;
expchar = 'E';
break;
default:
/* Should never happen. */
internal_error ("Unexpected format token");
} }
if (ft == FMT_EN ) /* Round the value. */
if (nbefore + nafter < ndigits && nbefore + nafter > 0)
{ {
minv = 1.0; i = nbefore + nafter;
maxv = 1000.0; if (digits[i] >= '5')
} {
if (ft == FMT_ES) /* Propagate the carry. */
for (i--; i >= 0; i--)
{ {
minv = 1.0; if (digits[i] != '9')
maxv = 10.0; {
digits[i]++;
break;
}
digits[i] = '0';
} }
/* OK, let's scale the number to appropriate range. */ if (i < 0)
while (scale_flag && n > 0.0 && n < minv)
{ {
if (n < minv) /* The carry overflowed. Fortunately we have some spare space
at the start of the buffer. We may discard some digits, but
this is ok because we already know they are zero. */
digits--;
digits[0] = '1';
if (ft == FMT_F)
{ {
n = n * 10.0 ; if (nzero > 0)
neval --; {
nzero--;
nafter++;
} }
else
nbefore++;
} }
while (scale_flag && n > 0.0 && n > maxv) else if (ft == FMT_EN)
{ {
if (n > maxv) nbefore++;
if (nbefore == 4)
{ {
n = n / 10.0 ; nbefore = 1;
neval ++; e += 3;
}
}
else
e++;
} }
} }
}
/* Calculate the format of the exponent field. */
if (expchar)
{
edigits = 1;
for (i = abs (e); i >= 10; i /= 10)
edigits++;
/* It is time to process the EXP part of the number. if (f->u.real.e < 0)
Value of 'nesign' is 0 unless following codes is executed. */
if (ft != FMT_F)
{ {
/* Sign of the EXP value. */ /* Width not specified. Must be no more than 3 digits. */
if (neval >= 0) if (e > 999 || e < -999)
esign = SIGN_PLUS; edigits = -1;
else else
{ {
esign = SIGN_MINUS; edigits = 4;
neval = - neval ; if (e > 99 || e < -99)
expchar = ' ';
} }
}
/* Width of the EXP. */ else
e_new = 0;
j = neval;
while (j > 0)
{ {
j = j / 10; /* Exponent width specified, check it is wide enough. */
e_new ++ ; if (edigits > f->u.real.e)
edigits = -1;
else
edigits = f->u.real.e + 2;
} }
if (e <= e_new)
e = e_new;
/* Got the width of EXP. */
if (e < digits)
e = digits ;
/* Minimum value of the width would be 2. */
if (e < 2)
e = 2;
nesign = 1 ; /* We must give a position for the 'exp_char' */
if (e > 0)
nesign = e + nesign + (esign != SIGN_NONE ? 1 : 0);
} }
else
edigits = 0;
/* Pick a field size if none was specified. */
intval = n;
intstr = itoa (intval);
intlen = strlen (intstr);
q = rtoa (n, len, d);
digits = strlen (q);
/* Select a width if none was specified. */
if (w <= 0) if (w <= 0)
w = digits + nsign; w = nbefore + nzero + nafter + 2;
p = write_block (w); /* Create the ouput buffer. */
if (p == NULL) out = write_block (w);
if (out == NULL)
return; return;
base = p; /* Work out how much padding is needed. */
nblanks = w - (nbefore + nzero + nafter + edigits + 1);
if (sign != SIGN_NONE)
nblanks--;
nblank = w - (nsign + intlen + d + nesign); /* Check the value fits in the specified field width. */
if (nblank == -1 && ft != FMT_F) if (nblanks < 0 || edigits == -1)
{
with_exp = 0;
nesign -= 1;
nblank = w - (nsign + intlen + d + nesign);
}
/* Don't let a leading '0' cause field overflow. */
if (nblank == -1 && ft == FMT_F && q[0] == '0')
{ {
q++; star_fill (out, w);
nblank = 0; return;
} }
if (nblank < 0) /* See if we have space for a zero before the decimal point. */
if (nbefore == 0 && nblanks > 0)
{ {
star_fill (p, w); leadzero = 1;
goto done; nblanks--;
} }
memset (p, ' ', nblank); else
p += nblank; leadzero = 0;
switch (sign) /* Padd to full field width. */
if (nblanks > 0)
{ {
case SIGN_PLUS: memset (out, ' ', nblanks);
*p++ = '+'; out += nblanks;
break;
case SIGN_MINUS:
*p++ = '-';
break;
case SIGN_NONE:
break;
} }
memcpy (p, q, intlen + d + 1); /* Output the initial sign (if any). */
p += intlen + d; if (sign == SIGN_PLUS)
*(out++) = '+';
else if (sign == SIGN_MINUS)
*(out++) = '-';
/* Output an optional leading zero. */
if (leadzero)
*(out++) = '0';
if (nesign > 0) /* Output the part before the decimal point, padding with zeros. */
if (nbefore > 0)
{ {
if (with_exp) if (nbefore > ndigits)
*p++ = exp_char; i = ndigits;
switch (esign) else
i = nbefore;
memcpy (out, digits, i);
while (i < nbefore)
out[i++] = '0';
digits += i;
ndigits -= i;
out += nbefore;
}
/* Output the decimal point. */
*(out++) = '.';
/* Output leading zeros after the decimal point. */
if (nzero > 0)
{ {
case SIGN_PLUS: for (i = 0; i < nzero; i++)
*p++ = '+'; *(out++) = '0';
break;
case SIGN_MINUS:
*p++ = '-';
break;
case SIGN_NONE:
break;
} }
q = itoa (neval);
digits = strlen (q);
for (itmp = 0; itmp < e - digits; itmp++) /* Output digits after the decimal point, padding with zeros. */
*p++ = '0'; if (nafter > 0)
memcpy (p, q, digits); {
p[digits] = 0; if (nafter > ndigits)
i = ndigits;
else
i = nafter;
memcpy (out, digits, i);
while (i < nafter)
out[i++] = '0';
digits += i;
ndigits -= i;
out += nafter;
} }
done: /* Output the exponent. */
return ; if (expchar)
{
if (expchar != ' ')
{
*(out++) = expchar;
edigits--;
}
snprintf (buffer, 32, "%+0*d", edigits, e);
memcpy (out, buffer, edigits);
}
} }
void void
write_l (fnode * f, char *source, int len) write_l (fnode * f, char *source, int len)
{ {
......
...@@ -250,9 +250,6 @@ void get_args (int *, char ***); ...@@ -250,9 +250,6 @@ void get_args (int *, char ***);
/* error.c */ /* error.c */
#define rtoa prefix(rtoa)
char *rtoa (double f, int length, int oprec);
#define itoa prefix(itoa) #define itoa prefix(itoa)
char *itoa (int64_t); char *itoa (int64_t);
......
...@@ -53,62 +53,6 @@ unsigned line; ...@@ -53,62 +53,6 @@ unsigned line;
static char buffer[32]; /* buffer for integer/ascii conversions */ static char buffer[32]; /* buffer for integer/ascii conversions */
/* rtoa()-- Real to ascii conversion for base 10 and below.
* Returns a pointer to a static buffer. */
char *
rtoa (double f, int length, int oprec)
{
double n = f;
double fval, minval;
int negative, prec;
unsigned k;
char formats[16];
prec = 0;
negative = 0;
if (n < 0.0)
{
negative = 1;
n = -n;
}
if (length >= 8)
minval = FLT_MIN;
else
minval = DBL_MIN;
if (n <= minval)
{
buffer[0] = '0';
buffer[1] = '.';
for (k = 2; k < 28 ; k++)
buffer[k] = '0';
buffer[k+1] = '\0';
return buffer;
}
fval = n;
while (fval > 1.0)
{
fval = fval / 10.0;
prec ++;
}
prec = sizeof (buffer) - 2 - prec;
if (prec > 20)
prec = 20;
prec = prec > oprec ? oprec : prec ;
if (negative)
sprintf (formats, "-%%.%df", prec);
else
sprintf (formats, "%%.%df", prec);
sprintf (buffer, formats, n);
return buffer;
}
/* Returns a pointer to a static buffer. */ /* Returns a pointer to a static buffer. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment