summaryrefslogtreecommitdiff
path: root/libgfortran/io/write.c
diff options
context:
space:
mode:
Diffstat (limited to 'libgfortran/io/write.c')
-rw-r--r--libgfortran/io/write.c113
1 files changed, 71 insertions, 42 deletions
diff --git a/libgfortran/io/write.c b/libgfortran/io/write.c
index 793031a9375..0e2a3ac5ccd 100644
--- a/libgfortran/io/write.c
+++ b/libgfortran/io/write.c
@@ -37,7 +37,6 @@ Boston, MA 02111-1307, USA. */
#include "libgfortran.h"
#include "io.h"
-
#define star_fill(p, n) memset(p, '*', n)
@@ -69,10 +68,10 @@ write_a (fnode * f, const char *source, int len)
}
}
-static int64_t
+static GFC_INTEGER_LARGEST
extract_int (const void *p, int len)
{
- int64_t i = 0;
+ GFC_INTEGER_LARGEST i = 0;
if (p == NULL)
return i;
@@ -80,17 +79,22 @@ extract_int (const void *p, int len)
switch (len)
{
case 1:
- i = *((const int8_t *) p);
+ i = *((const GFC_INTEGER_1 *) p);
break;
case 2:
- i = *((const int16_t *) p);
+ i = *((const GFC_INTEGER_2 *) p);
break;
case 4:
- i = *((const int32_t *) p);
+ i = *((const GFC_INTEGER_4 *) p);
break;
case 8:
- i = *((const int64_t *) p);
+ i = *((const GFC_INTEGER_8 *) p);
+ break;
+#ifdef HAVE_GFC_INTEGER_16
+ case 16:
+ i = *((const GFC_INTEGER_16 *) p);
break;
+#endif
default:
internal_error ("bad integer kind");
}
@@ -98,23 +102,32 @@ extract_int (const void *p, int len)
return i;
}
-static double
+static GFC_REAL_LARGEST
extract_real (const void *p, int len)
{
- double i = 0.0;
+ GFC_REAL_LARGEST i = 0;
switch (len)
{
case 4:
- i = *((const float *) p);
+ i = *((const GFC_REAL_4 *) p);
break;
case 8:
- i = *((const double *) p);
+ i = *((const GFC_REAL_8 *) p);
+ break;
+#ifdef HAVE_GFC_REAL_10
+ case 10:
+ i = *((const GFC_REAL_10 *) p);
break;
+#endif
+#ifdef HAVE_GFC_REAL_16
+ case 16:
+ i = *((const GFC_REAL_16 *) p);
+ break;
+#endif
default:
internal_error ("bad real kind");
}
return i;
-
}
@@ -148,11 +161,11 @@ calculate_sign (int negative_flag)
/* Returns the value of 10**d. */
-static double
+static GFC_REAL_LARGEST
calculate_exp (int d)
{
int i;
- double r = 1.0;
+ GFC_REAL_LARGEST r = 1.0;
for (i = 0; i< (d >= 0 ? d : -d); i++)
r *= 10;
@@ -181,13 +194,13 @@ calculate_exp (int d)
for Gw.dEe, n' ' means e+2 blanks */
static fnode *
-calculate_G_format (fnode *f, double value, int *num_blank)
+calculate_G_format (fnode *f, GFC_REAL_LARGEST value, int *num_blank)
{
int e = f->u.real.e;
int d = f->u.real.d;
int w = f->u.real.w;
fnode *newf;
- double m, exp_d;
+ GFC_REAL_LARGEST m, exp_d;
int low, high, mid;
int ubound, lbound;
@@ -199,8 +212,7 @@ calculate_G_format (fnode *f, double value, int *num_blank)
/* In case of the two data magnitude ranges,
generate E editing, Ew.d[Ee]. */
exp_d = calculate_exp (d);
- if ((m > 0.0 && m < 0.1 - 0.05 / (double) exp_d)
- || (m >= (double) exp_d - 0.5 ))
+ if ((m > 0.0 && m < 0.1 - 0.05 / exp_d) || (m >= exp_d - 0.5 ))
{
newf->format = FMT_E;
newf->u.real.w = w;
@@ -219,7 +231,7 @@ calculate_G_format (fnode *f, double value, int *num_blank)
while (low <= high)
{
- double temp;
+ GFC_REAL_LARGEST temp;
mid = (low + high) / 2;
/* 0.1 * 10**mid - 0.5 * 10**(mid-d-1) */
@@ -271,7 +283,7 @@ calculate_G_format (fnode *f, double value, int *num_blank)
/* Output a real number according to its format which is FMT_G free. */
static void
-output_float (fnode *f, double value)
+output_float (fnode *f, GFC_REAL_LARGEST value)
{
/* This must be large enough to accurately hold any value. */
char buffer[32];
@@ -321,11 +333,15 @@ output_float (fnode *f, double value)
edigits = 2;
else
{
- abslog = fabs(log10 (value));
+#if defined(HAVE_GFC_REAL_10) || defined(HAVE_GFC_REAL_16)
+ abslog = fabs((double) log10l(value));
+#else
+ abslog = fabs(log10(value));
+#endif
if (abslog < 100)
edigits = 2;
else
- edigits = 1 + (int) log10 (abslog);
+ edigits = 1 + (int) log10(abslog);
}
if (ft == FMT_F || ft == FMT_EN
@@ -346,7 +362,24 @@ output_float (fnode *f, double value)
ndigits = 27 - edigits;
}
- sprintf (buffer, "%+-#31.*e", ndigits - 1, value);
+ /* # The result will always contain a decimal point, even if no
+ * digits follow it
+ *
+ * - The converted value is to be left adjusted on the field boundary
+ *
+ * + A sign (+ or -) always be placed before a number
+ *
+ * 31 minimum field width
+ *
+ * * (ndigits-1) is used as the precision
+ *
+ * e format: [-]d.ddde±dd where there is one digit before the
+ * decimal-point character and the number of digits after it is
+ * equal to the precision. The exponent always contains at least two
+ * digits; if the value is zero, the exponent is 00.
+ */
+ sprintf (buffer, "%+-#31.*" GFC_REAL_LARGEST_FORMAT "e",
+ ndigits - 1, value);
/* Check the resulting string has punctuation in the correct places. */
if (buffer[2] != '.' || buffer[ndigits + 2] != 'e')
@@ -673,7 +706,7 @@ void
write_l (fnode * f, char *source, int len)
{
char *p;
- int64_t n;
+ GFC_INTEGER_LARGEST n;
p = write_block (f->u.w);
if (p == NULL)
@@ -689,7 +722,7 @@ write_l (fnode * f, char *source, int len)
static void
write_float (fnode *f, const char *source, int len)
{
- double n;
+ GFC_REAL_LARGEST n;
int nb =0, res, save_scale_factor;
char * p, fin;
fnode *f2 = NULL;
@@ -698,7 +731,10 @@ write_float (fnode *f, const char *source, int len)
if (f->format != FMT_B && f->format != FMT_O && f->format != FMT_Z)
{
- res = isfinite (n);
+ /* TODO: there are some systems where isfinite is not able to work
+ with long double variables. We should detect this case and
+ provide our own version for isfinite. */
+ res = isfinite (n);
if (res == 0)
{
nb = f->u.real.w;
@@ -756,10 +792,10 @@ write_float (fnode *f, const char *source, int len)
static void
-write_int (fnode *f, const char *source, int len, char *(*conv) (uint64_t))
+write_int (fnode *f, const char *source, int len,
+ char *(*conv) (GFC_UINTEGER_LARGEST))
{
- uint32_t ns =0;
- uint64_t n = 0;
+ GFC_UINTEGER_LARGEST n = 0;
int w, m, digits, nzero, nblank;
char *p, *q;
@@ -783,15 +819,7 @@ write_int (fnode *f, const char *source, int len, char *(*conv) (uint64_t))
goto done;
}
-
- if (len < 8)
- {
- ns = n;
- q = conv (ns);
- }
- else
- q = conv (n);
-
+ q = conv (n);
digits = strlen (q);
/* Select a width if none was specified. The idea here is to always
@@ -842,9 +870,10 @@ write_int (fnode *f, const char *source, int len, char *(*conv) (uint64_t))
}
static void
-write_decimal (fnode *f, const char *source, int len, char *(*conv) (int64_t))
+write_decimal (fnode *f, const char *source, int len,
+ char *(*conv) (GFC_INTEGER_LARGEST))
{
- int64_t n = 0;
+ GFC_INTEGER_LARGEST n = 0;
int w, m, digits, nsign, nzero, nblank;
char *p, *q;
sign_t sign;
@@ -930,7 +959,7 @@ write_decimal (fnode *f, const char *source, int len, char *(*conv) (int64_t))
/* Convert unsigned octal to ascii. */
static char *
-otoa (uint64_t n)
+otoa (GFC_UINTEGER_LARGEST n)
{
char *p;
@@ -958,7 +987,7 @@ otoa (uint64_t n)
/* Convert unsigned binary to ascii. */
static char *
-btoa (uint64_t n)
+btoa (GFC_UINTEGER_LARGEST n)
{
char *p;