diff options
author | Jerry DeLisle <jvdelisle@gcc.gnu.org> | 2016-06-23 15:58:05 +0000 |
---|---|---|
committer | Jerry DeLisle <jvdelisle@gcc.gnu.org> | 2016-06-23 15:58:05 +0000 |
commit | 5b0e27a724e8ddc12065fa1d0848ae7c2495290e (patch) | |
tree | 15a9936a35c8faea733bb284959bf1f4484f4c85 /libgfortran/io/write.c | |
parent | cd64be5bcae8c6f0ccf50aac0e0a16f28e23d042 (diff) | |
download | gcc-5b0e27a724e8ddc12065fa1d0848ae7c2495290e.zip gcc-5b0e27a724e8ddc12065fa1d0848ae7c2495290e.tar.gz gcc-5b0e27a724e8ddc12065fa1d0848ae7c2495290e.tar.bz2 |
re PR libfortran/48852 (Invalid spaces in list-directed output of complex constants)
2016-06-23 Jerry DeLisle <jvdelisle@gcc.gnu.org>
PR libgfortran/48852
* io/write.c: Cleaned up whitespace.
(write_d, write_e, write_f, write_es, write_en): Use new helper function
write_float_0. (write_float_0): New helper function.
(get_precision, select_buffer, select_string, write_float_string): New
helper functions used in remaining float writing functions. Helper function
write_float_string now contains code for writing to kind=4 character
internal units.
(write_real): Modified to establish working buffers at this level and to
use new helper functions.
(write_real_g0): Likewise modified.
(write_complex): Likewise modified. Gets both float strings before
output so that final lengths can be determined which allows right
justifying the complex number with no intervening spaces.
* io/write_float.def (build_float_string): Renamed from previosly
output_float, modified to use buffers passed in from higher functions,
builds a null terminated string of the floating point value. Character
kind=4 code eliminated.
(write_infnan): Likewise modified to use incoming buffers and eliminate
kind=4 related code.
(OUTPUT_FLOAT_FMT_G): Deleted, functionality moved into FORMAT_FLOAT.
(FORMAT_FLOAT): Renamed macro from WRITE_FLOAT. Use build_float_string.
(get_float_string): Renamed from write_float, uses FORMAT_FLOAT macro.
Buffer allocation removed, now at higher level.
PR libgfortran/48852
* gfortran.dg/char4_iunit_1.f03: Update test.
* gfortran.dg/f2003_io_5.f03: Update test.
* gfortran.dg/real_const_3.f90: Update test.
From-SVN: r237735
Diffstat (limited to 'libgfortran/io/write.c')
-rw-r--r-- | libgfortran/io/write.c | 274 |
1 files changed, 218 insertions, 56 deletions
diff --git a/libgfortran/io/write.c b/libgfortran/io/write.c index 9136eb7..db27f2d 100644 --- a/libgfortran/io/write.c +++ b/libgfortran/io/write.c @@ -1101,42 +1101,6 @@ write_z (st_parameter_dt *dtp, const fnode *f, const char *source, int len) } } - -void -write_d (st_parameter_dt *dtp, const fnode *f, const char *p, int len) -{ - write_float (dtp, f, p, len, 0); -} - - -void -write_e (st_parameter_dt *dtp, const fnode *f, const char *p, int len) -{ - write_float (dtp, f, p, len, 0); -} - - -void -write_f (st_parameter_dt *dtp, const fnode *f, const char *p, int len) -{ - write_float (dtp, f, p, len, 0); -} - - -void -write_en (st_parameter_dt *dtp, const fnode *f, const char *p, int len) -{ - write_float (dtp, f, p, len, 0); -} - - -void -write_es (st_parameter_dt *dtp, const fnode *f, const char *p, int len) -{ - write_float (dtp, f, p, len, 0); -} - - /* Take care of the X/TR descriptor. */ void @@ -1380,6 +1344,119 @@ write_character (st_parameter_dt *dtp, const char *source, int kind, int length, } } +/* Floating point helper functions. */ + +#define BUF_STACK_SZ 256 + +static int +get_precision (st_parameter_dt *dtp, const fnode *f, const char *source, int kind) +{ + if (f->format != FMT_EN) + return determine_precision (dtp, f, kind); + else + return determine_en_precision (dtp, f, source, kind); +} + +static char * +select_buffer (int precision, char *buf, size_t *size) +{ + char *result; + *size = BUF_STACK_SZ / 2 + precision; + if (*size > BUF_STACK_SZ) + result = xmalloc (*size); + else + result = buf; + return result; +} + +static char * +select_string (const fnode *f, char *buf, size_t *size) +{ + char *result; + *size = f->u.real.w + 1; + if (*size > BUF_STACK_SZ) + result = xmalloc (*size); + else + result = buf; + return result; +} + +static void +write_float_string (st_parameter_dt *dtp, char *fstr, size_t len) +{ + char *p = write_block (dtp, len); + if (p == NULL) + return; + + if (unlikely (is_char4_unit (dtp))) + { + gfc_char4_t *p4 = (gfc_char4_t *) p; + memcpy4 (p4, fstr, len); + return; + } + memcpy (p, fstr, len); +} + +static void +write_float_0 (st_parameter_dt *dtp, const fnode *f, const char *source, int kind) +{ + char buf_stack[BUF_STACK_SZ]; + char str_buf[BUF_STACK_SZ]; + char *buffer, *result; + size_t buf_size, res_len; + + /* Precision for snprintf call. */ + int precision = get_precision (dtp, f, source, kind); + + /* String buffer to hold final result. */ + result = select_string (f, str_buf, &res_len); + + buffer = select_buffer (precision, buf_stack, &buf_size); + + get_float_string (dtp, f, source , kind, 0, buffer, + precision, buf_size, result, &res_len); + write_float_string (dtp, result, res_len); + + if (buf_size > BUF_STACK_SZ) + free (buffer); + if (res_len > BUF_STACK_SZ) + free (result); +} + +void +write_d (st_parameter_dt *dtp, const fnode *f, const char *p, int len) +{ + write_float_0 (dtp, f, p, len); +} + + +void +write_e (st_parameter_dt *dtp, const fnode *f, const char *p, int len) +{ + write_float_0 (dtp, f, p, len); +} + + +void +write_f (st_parameter_dt *dtp, const fnode *f, const char *p, int len) +{ + write_float_0 (dtp, f, p, len); +} + + +void +write_en (st_parameter_dt *dtp, const fnode *f, const char *p, int len) +{ + write_float_0 (dtp, f, p, len); +} + + +void +write_es (st_parameter_dt *dtp, const fnode *f, const char *p, int len) +{ + write_float_0 (dtp, f, p, len); +} + /* Set an fnode to default format. */ @@ -1422,12 +1499,12 @@ set_fnode_default (st_parameter_dt *dtp, fnode *f, int length) } } -/* Output a real number with default format. To guarantee that a - binary -> decimal -> binary roundtrip conversion recovers the - original value, IEEE 754-2008 requires 9, 17, 21 and 36 significant - digits for REAL kinds 4, 8, 10, and 16, respectively. Thus, we use - 1PG16.9E2 for REAL(4), 1PG25.17E3 for REAL(8), 1PG30.21E4 for - REAL(10) and 1PG45.36E4 for REAL(16). The exception is that the +/* Output a real number with default format. + To guarantee that a binary -> decimal -> binary roundtrip conversion + recovers the original value, IEEE 754-2008 requires 9, 17, 21 and 36 + significant digits for REAL kinds 4, 8, 10, and 16, respectively. + Thus, we use 1PG16.9E2 for REAL(4), 1PG25.17E3 for REAL(8), 1PG30.21E4 + for REAL(10) and 1PG45.36E4 for REAL(16). The exception is that the Fortran standard requires outputting an extra digit when the scale factor is 1 and when the magnitude of the value is such that E editing is used. However, gfortran compensates for this, and thus @@ -1435,25 +1512,51 @@ set_fnode_default (st_parameter_dt *dtp, fnode *f, int length) generated both when using F and E editing. */ void -write_real (st_parameter_dt *dtp, const char *source, int length) +write_real (st_parameter_dt *dtp, const char *source, int kind) { fnode f ; - int org_scale = dtp->u.p.scale_factor; + char buf_stack[BUF_STACK_SZ]; + char str_buf[BUF_STACK_SZ]; + char *buffer, *result; + size_t buf_size, res_len; + int orig_scale = dtp->u.p.scale_factor; dtp->u.p.scale_factor = 1; - set_fnode_default (dtp, &f, length); - write_float (dtp, &f, source , length, 1); - dtp->u.p.scale_factor = org_scale; + set_fnode_default (dtp, &f, kind); + + /* Precision for snprintf call. */ + int precision = get_precision (dtp, &f, source, kind); + + /* String buffer to hold final result. */ + result = select_string (&f, str_buf, &res_len); + + /* scratch buffer to hold final result. */ + buffer = select_buffer (precision, buf_stack, &buf_size); + + get_float_string (dtp, &f, source , kind, 1, buffer, + precision, buf_size, result, &res_len); + write_float_string (dtp, result, res_len); + + dtp->u.p.scale_factor = orig_scale; + if (buf_size > BUF_STACK_SZ) + free (buffer); + if (res_len > BUF_STACK_SZ) + free (result); } /* Similar to list formatted REAL output, for kPG0 where k > 0 we compensate for the extra digit. */ void -write_real_g0 (st_parameter_dt *dtp, const char *source, int length, int d) +write_real_g0 (st_parameter_dt *dtp, const char *source, int kind, int d) { fnode f; + char buf_stack[BUF_STACK_SZ]; + char str_buf[BUF_STACK_SZ]; + char *buffer, *result; + size_t buf_size, res_len; int comp_d; - set_fnode_default (dtp, &f, length); + set_fnode_default (dtp, &f, kind); + if (d > 0) f.u.real.d = d; @@ -1464,8 +1567,24 @@ write_real_g0 (st_parameter_dt *dtp, const char *source, int length, int d) else comp_d = 0; dtp->u.p.g0_no_blanks = 1; - write_float (dtp, &f, source , length, comp_d); + + /* Precision for snprintf call. */ + int precision = get_precision (dtp, &f, source, kind); + + /* String buffer to hold final result. */ + result = select_string (&f, str_buf, &res_len); + + buffer = select_buffer (precision, buf_stack, &buf_size); + + get_float_string (dtp, &f, source , kind, comp_d, buffer, + precision, buf_size, result, &res_len); + write_float_string (dtp, result, res_len); + dtp->u.p.g0_no_blanks = 0; + if (buf_size > BUF_STACK_SZ) + free (buffer); + if (res_len > BUF_STACK_SZ) + free (result); } @@ -1475,15 +1594,58 @@ write_complex (st_parameter_dt *dtp, const char *source, int kind, size_t size) char semi_comma = dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? ',' : ';'; - if (write_char (dtp, '(')) - return; - write_real (dtp, source, kind); + /* Set for no blanks so we get a string result with no leading + blanks. We will pad left later. */ + dtp->u.p.g0_no_blanks = 1; - if (write_char (dtp, semi_comma)) - return; - write_real (dtp, source + size / 2, kind); + fnode f ; + char buf_stack[BUF_STACK_SZ]; + char str1_buf[BUF_STACK_SZ]; + char str2_buf[BUF_STACK_SZ]; + char *buffer, *result1, *result2; + size_t buf_size, res_len1, res_len2; + int width, lblanks, orig_scale = dtp->u.p.scale_factor; + dtp->u.p.scale_factor = 1; + set_fnode_default (dtp, &f, kind); + + /* Set width for two values, parenthesis, and comma. */ + width = 2 * f.u.real.w + 3; + + /* Set for no blanks so we get a string result with no leading + blanks. We will pad left later. */ + dtp->u.p.g0_no_blanks = 1; + + /* Precision for snprintf call. */ + int precision = get_precision (dtp, &f, source, kind); + + /* String buffers to hold final result. */ + result1 = select_string (&f, str1_buf, &res_len1); + result2 = select_string (&f, str2_buf, &res_len2); + + buffer = select_buffer (precision, buf_stack, &buf_size); + + get_float_string (dtp, &f, source , kind, 0, buffer, + precision, buf_size, result1, &res_len1); + get_float_string (dtp, &f, source + size / 2 , kind, 0, buffer, + precision, buf_size, result2, &res_len2); + lblanks = width - res_len1 - res_len2 - 3; + + write_x (dtp, lblanks, lblanks); + write_char (dtp, '('); + write_float_string (dtp, result1, res_len1); + write_char (dtp, semi_comma); + write_float_string (dtp, result2, res_len2); write_char (dtp, ')'); + + dtp->u.p.scale_factor = orig_scale; + dtp->u.p.g0_no_blanks = 0; + if (buf_size > BUF_STACK_SZ) + free (buffer); + if (res_len1 > BUF_STACK_SZ) + free (result1); + if (res_len2 > BUF_STACK_SZ) + free (result2); } |