diff options
Diffstat (limited to 'libgfortran/io/read.c')
-rw-r--r-- | libgfortran/io/read.c | 490 |
1 files changed, 221 insertions, 269 deletions
diff --git a/libgfortran/io/read.c b/libgfortran/io/read.c index a8ae3d7..b651665 100644 --- a/libgfortran/io/read.c +++ b/libgfortran/io/read.c @@ -33,6 +33,7 @@ Boston, MA 02110-1301, USA. */ #include <errno.h> #include <ctype.h> #include <stdlib.h> +#include <assert.h> typedef unsigned char uchar; @@ -141,38 +142,30 @@ convert_real (st_parameter_dt *dtp, void *dest, const char *buffer, int length) switch (length) { case 4: - { - GFC_REAL_4 tmp = + *((GFC_REAL_4*) dest) = #if defined(HAVE_STRTOF) - strtof (buffer, NULL); + strtof (buffer, NULL); #else - (GFC_REAL_4) strtod (buffer, NULL); + (GFC_REAL_4) strtod (buffer, NULL); #endif - memcpy (dest, (void *) &tmp, length); - } break; + case 8: - { - GFC_REAL_8 tmp = strtod (buffer, NULL); - memcpy (dest, (void *) &tmp, length); - } + *((GFC_REAL_8*) dest) = strtod (buffer, NULL); break; + #if defined(HAVE_GFC_REAL_10) && defined (HAVE_STRTOLD) case 10: - { - GFC_REAL_10 tmp = strtold (buffer, NULL); - memcpy (dest, (void *) &tmp, length); - } + *((GFC_REAL_10*) dest) = strtold (buffer, NULL); break; #endif + #if defined(HAVE_GFC_REAL_16) && defined (HAVE_STRTOLD) case 16: - { - GFC_REAL_16 tmp = strtold (buffer, NULL); - memcpy (dest, (void *) &tmp, length); - } + *((GFC_REAL_16*) dest) = strtold (buffer, NULL); break; #endif + default: internal_error (&dtp->common, "Unsupported real kind during IO"); } @@ -195,13 +188,13 @@ void read_l (st_parameter_dt *dtp, const fnode *f, char *dest, int length) { char *p; - size_t w; + int w; w = f->u.w; - p = gfc_alloca (w); + p = read_block_form (dtp, &w); - if (read_block_form (dtp, p, &w) == FAILURE) + if (p == NULL) return; while (*p == ' ') @@ -238,28 +231,26 @@ read_l (st_parameter_dt *dtp, const fnode *f, char *dest, int length) } -static inline gfc_char4_t -read_utf8 (st_parameter_dt *dtp, size_t *nbytes) +static gfc_char4_t +read_utf8 (st_parameter_dt *dtp, int *nbytes) { static const uchar masks[6] = { 0x7F, 0x1F, 0x0F, 0x07, 0x02, 0x01 }; static const uchar patns[6] = { 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - static uchar buffer[6]; - size_t i, nb, nread; + int i, nb, nread; gfc_char4_t c; - int status; char *s; *nbytes = 1; - s = (char *) &buffer[0]; - status = read_block_form (dtp, s, nbytes); - if (status == FAILURE) + + s = read_block_form (dtp, nbytes); + if (s == NULL) return 0; /* If this is a short read, just return. */ if (*nbytes == 0) return 0; - c = buffer[0]; + c = (uchar) s[0]; if (c < 0x80) return c; @@ -274,9 +265,8 @@ read_utf8 (st_parameter_dt *dtp, size_t *nbytes) c = (c & masks[nb-1]); nread = nb - 1; - s = (char *) &buffer[1]; - status = read_block_form (dtp, s, &nread); - if (status == FAILURE) + s = read_block_form (dtp, &nread); + if (s == NULL) return 0; /* Decode the bytes read. */ for (i = 1; i < nb; i++) @@ -309,14 +299,14 @@ read_utf8 (st_parameter_dt *dtp, size_t *nbytes) static void -read_utf8_char1 (st_parameter_dt *dtp, char *p, int len, size_t width) +read_utf8_char1 (st_parameter_dt *dtp, char *p, int len, int width) { gfc_char4_t c; char *dest; - size_t nbytes; + int nbytes; int i, j; - len = ((int) width < len) ? len : (int) width; + len = (width < len) ? len : width; dest = (char *) p; @@ -339,21 +329,19 @@ read_utf8_char1 (st_parameter_dt *dtp, char *p, int len, size_t width) } static void -read_default_char1 (st_parameter_dt *dtp, char *p, int len, size_t width) +read_default_char1 (st_parameter_dt *dtp, char *p, int len, int width) { char *s; - int m, n, status; + int m, n; - s = gfc_alloca (width); - - status = read_block_form (dtp, s, &width); + s = read_block_form (dtp, &width); - if (status == FAILURE) + if (s == NULL) return; - if (width > (size_t) len) + if (width > len) s += (width - len); - m = ((int) width > len) ? len : (int) width; + m = (width > len) ? len : width; memcpy (p, s, m); n = len - width; @@ -363,13 +351,13 @@ read_default_char1 (st_parameter_dt *dtp, char *p, int len, size_t width) static void -read_utf8_char4 (st_parameter_dt *dtp, void *p, int len, size_t width) +read_utf8_char4 (st_parameter_dt *dtp, void *p, int len, int width) { gfc_char4_t *dest; - size_t nbytes; + int nbytes; int i, j; - len = ((int) width < len) ? len : (int) width; + len = (width < len) ? len : width; dest = (gfc_char4_t *) p; @@ -391,19 +379,17 @@ read_utf8_char4 (st_parameter_dt *dtp, void *p, int len, size_t width) static void -read_default_char4 (st_parameter_dt *dtp, char *p, int len, size_t width) +read_default_char4 (st_parameter_dt *dtp, char *p, int len, int width) { char *s; gfc_char4_t *dest; - int m, n, status; - - s = gfc_alloca (width); + int m, n; - status = read_block_form (dtp, s, &width); + s = read_block_form (dtp, &width); - if (status == FAILURE) + if (s == NULL) return; - if (width > (size_t) len) + if (width > len) s += (width - len); m = ((int) width > len) ? len : (int) width; @@ -425,7 +411,7 @@ void read_a (st_parameter_dt *dtp, const fnode *f, char *p, int length) { int wi; - size_t w; + int w; wi = f->u.w; if (wi == -1) /* '(A)' edit descriptor */ @@ -451,13 +437,11 @@ read_a (st_parameter_dt *dtp, const fnode *f, char *p, int length) void read_a_char4 (st_parameter_dt *dtp, const fnode *f, char *p, int length) { - int wi; - size_t w; + int w; - wi = f->u.w; - if (wi == -1) /* '(A)' edit descriptor */ - wi = length; - w = wi; + w = f->u.w; + if (w == -1) /* '(A)' edit descriptor */ + w = length; /* Read in w characters, treating comma as not a separator. */ dtp->u.p.sf_read_comma = 0; @@ -532,18 +516,15 @@ read_decimal (st_parameter_dt *dtp, const fnode *f, char *dest, int length) GFC_UINTEGER_LARGEST value, maxv, maxv_10; GFC_INTEGER_LARGEST v; int w, negative; - size_t wu; char c, *p; - wu = f->u.w; + w = f->u.w; - p = gfc_alloca (wu); + p = read_block_form (dtp, &w); - if (read_block_form (dtp, p, &wu) == FAILURE) + if (p == NULL) return; - w = wu; - p = eat_leading_spaces (&w, p); if (w == 0) { @@ -636,17 +617,14 @@ read_radix (st_parameter_dt *dtp, const fnode *f, char *dest, int length, GFC_INTEGER_LARGEST v; int w, negative; char c, *p; - size_t wu; - wu = f->u.w; + w = f->u.w; - p = gfc_alloca (wu); + p = read_block_form (dtp, &w); - if (read_block_form (dtp, p, &wu) == FAILURE) + if (p == NULL) return; - w = wu; - p = eat_leading_spaces (&w, p); if (w == 0) { @@ -783,75 +761,83 @@ read_radix (st_parameter_dt *dtp, const fnode *f, char *dest, int length, void read_f (st_parameter_dt *dtp, const fnode *f, char *dest, int length) { - size_t wu; int w, seen_dp, exponent; - int exponent_sign, val_sign; - int ndigits; - int edigits; - int i; - char *p, *buffer; - char *digits; - char scratch[SCRATCH_SIZE]; - - val_sign = 1; - seen_dp = 0; - wu = f->u.w; + int exponent_sign; + const char *p; + char *buffer; + char *out; + int seen_int_digit; /* Seen a digit before the decimal point? */ + int seen_dec_digit; /* Seen a digit after the decimal point? */ - p = gfc_alloca (wu); + seen_dp = 0; + seen_int_digit = 0; + seen_dec_digit = 0; + exponent_sign = 1; + exponent = 0; + w = f->u.w; - if (read_block_form (dtp, p, &wu) == FAILURE) + /* Read in the next block. */ + p = read_block_form (dtp, &w); + if (p == NULL) return; - - w = wu; - - p = eat_leading_spaces (&w, p); + p = eat_leading_spaces (&w, (char*) p); if (w == 0) goto zero; - /* Optional sign */ + /* In this buffer we're going to re-format the number cleanly to be parsed + by convert_real in the end; this assures we're using strtod from the + C library for parsing and thus probably get the best accuracy possible. + This process may add a '+0.0' in front of the number as well as change the + exponent because of an implicit decimal point or the like. Thus allocating + strlen ("+0.0e-1000") == 10 characters plus one for NUL more than the + original buffer had should be enough. */ + buffer = gfc_alloca (w + 11); + out = buffer; + /* Optional sign */ if (*p == '-' || *p == '+') { if (*p == '-') - val_sign = -1; - p++; - w--; + *(out++) = '-'; + ++p; + --w; } - exponent_sign = 1; - p = eat_leading_spaces (&w, p); + p = eat_leading_spaces (&w, (char*) p); if (w == 0) goto zero; - /* A digit, a '.' or a exponent character ('e', 'E', 'd' or 'D') - is required at this point */ - - if (!isdigit (*p) && *p != '.' && *p != ',' && *p != 'd' && *p != 'D' - && *p != 'e' && *p != 'E') - goto bad_float; - - /* Remember the position of the first digit. */ - digits = p; - ndigits = 0; - - /* Scan through the string to find the exponent. */ + /* Process the mantissa string. */ while (w > 0) { switch (*p) { case ',': - if (dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA - && *p == ',') - *p = '.'; - else + if (dtp->u.p.current_unit->decimal_status != DECIMAL_COMMA) goto bad_float; - /* Fall through */ + /* Fall through. */ case '.': if (seen_dp) goto bad_float; + if (!seen_int_digit) + *(out++) = '0'; + *(out++) = '.'; seen_dp = 1; - /* Fall through */ + break; + case ' ': + if (dtp->u.p.blank_status == BLANK_ZERO) + { + *(out++) = '0'; + goto found_digit; + } + else if (dtp->u.p.blank_status == BLANK_NULL) + break; + else + /* TODO: Should we check instead that there are only trailing + blanks here, as is done below for exponents? */ + goto done; + /* Fall through. */ case '0': case '1': case '2': @@ -862,207 +848,173 @@ read_f (st_parameter_dt *dtp, const fnode *f, char *dest, int length) case '7': case '8': case '9': - case ' ': - ndigits++; - p++; - w--; + *(out++) = *p; +found_digit: + if (!seen_dp) + seen_int_digit = 1; + else + seen_dec_digit = 1; break; case '-': - exponent_sign = -1; - /* Fall through */ - case '+': - p++; - w--; - goto exp2; + goto exponent; - case 'd': case 'e': - case 'D': case 'E': - p++; - w--; - goto exp1; + case 'd': + case 'D': + ++p; + --w; + goto exponent; default: goto bad_float; } - } - /* No exponent has been seen, so we use the current scale factor */ - exponent = -dtp->u.p.scale_factor; - goto done; - - bad_float: - generate_error (&dtp->common, LIBERROR_READ_VALUE, - "Bad value during floating point read"); - next_record (dtp, 1); - return; - - /* The value read is zero */ - zero: - switch (length) - { - case 4: - *((GFC_REAL_4 *) dest) = 0; - break; - - case 8: - *((GFC_REAL_8 *) dest) = 0; - break; - -#ifdef HAVE_GFC_REAL_10 - case 10: - *((GFC_REAL_10 *) dest) = 0; - break; -#endif - -#ifdef HAVE_GFC_REAL_16 - case 16: - *((GFC_REAL_16 *) dest) = 0; - break; -#endif - - default: - internal_error (&dtp->common, "Unsupported real kind during IO"); + ++p; + --w; } - return; + + /* No exponent has been seen, so we use the current scale factor. */ + exponent = - dtp->u.p.scale_factor; + goto done; - /* At this point the start of an exponent has been found */ - exp1: - while (w > 0 && *p == ' ') + /* At this point the start of an exponent has been found. */ +exponent: + p = eat_leading_spaces (&w, (char*) p); + if (*p == '-' || *p == '+') { - w--; - p++; + if (*p == '-') + exponent_sign = -1; + ++p; + --w; } - switch (*p) - { - case '-': - exponent_sign = -1; - /* Fall through */ - - case '+': - p++; - w--; - break; - } + /* At this point a digit string is required. We calculate the value + of the exponent in order to take account of the scale factor and + the d parameter before explict conversion takes place. */ if (w == 0) goto bad_float; - /* At this point a digit string is required. We calculate the value - of the exponent in order to take account of the scale factor and - the d parameter before explict conversion takes place. */ - exp2: - /* Normal processing of exponent */ - exponent = 0; if (dtp->u.p.blank_status == BLANK_UNSPECIFIED) { while (w > 0 && isdigit (*p)) - { - exponent = 10 * exponent + *p - '0'; - p++; - w--; - } - - /* Only allow trailing blanks */ - + { + exponent *= 10; + exponent += *p - '0'; + ++p; + --w; + } + + /* Only allow trailing blanks. */ while (w > 0) - { - if (*p != ' ') + { + if (*p != ' ') goto bad_float; - p++; - w--; - } + ++p; + --w; + } } - else /* BZ or BN status is enabled */ + else /* BZ or BN status is enabled. */ { while (w > 0) - { - if (*p == ' ') - { - if (dtp->u.p.blank_status == BLANK_ZERO) *p = '0'; - if (dtp->u.p.blank_status == BLANK_NULL) - { - p++; - w--; - continue; - } - } - else if (!isdigit (*p)) - goto bad_float; - - exponent = 10 * exponent + *p - '0'; - p++; - w--; - } + { + if (*p == ' ') + { + if (dtp->u.p.blank_status == BLANK_ZERO) + exponent *= 10; + else + assert (dtp->u.p.blank_status == BLANK_NULL); + } + else if (!isdigit (*p)) + goto bad_float; + else + { + exponent *= 10; + exponent += *p - '0'; + } + + ++p; + --w; + } } - exponent = exponent * exponent_sign; + exponent *= exponent_sign; - done: +done: /* Use the precision specified in the format if no decimal point has been seen. */ if (!seen_dp) exponent -= f->u.real.d; - if (exponent > 0) - { - edigits = 2; - i = exponent; - } - else - { - edigits = 3; - i = -exponent; - } + /* Output a trailing '0' after decimal point if not yet found. */ + if (seen_dp && !seen_dec_digit) + *(out++) = '0'; - while (i >= 10) + /* Print out the exponent to finish the reformatted number. Maximum 4 + digits for the exponent. */ + if (exponent != 0) { - i /= 10; - edigits++; - } + int dig; - i = ndigits + edigits + 1; - if (val_sign < 0) - i++; + *(out++) = 'e'; + if (exponent < 0) + { + *(out++) = '-'; + exponent = - exponent; + } - if (i < SCRATCH_SIZE) - buffer = scratch; - else - buffer = get_mem (i); - - /* Reformat the string into a temporary buffer. As we're using atof it's - easiest to just leave the decimal point in place. */ - p = buffer; - if (val_sign < 0) - *(p++) = '-'; - for (; ndigits > 0; ndigits--) - { - if (*digits == ' ') - { - if (dtp->u.p.blank_status == BLANK_ZERO) *digits = '0'; - if (dtp->u.p.blank_status == BLANK_NULL) - { - digits++; - continue; - } - } - *p = *digits; - p++; - digits++; + assert (exponent < 10000); + for (dig = 3; dig >= 0; --dig) + { + out[dig] = (char) ('0' + exponent % 10); + exponent /= 10; + } + out += 4; } - *(p++) = 'e'; - sprintf (p, "%d", exponent); + *(out++) = '\0'; /* Do the actual conversion. */ convert_real (dtp, dest, buffer, length); - if (buffer != scratch) - free_mem (buffer); + return; + /* The value read is zero. */ +zero: + switch (length) + { + case 4: + *((GFC_REAL_4 *) dest) = 0.0; + break; + + case 8: + *((GFC_REAL_8 *) dest) = 0.0; + break; + +#ifdef HAVE_GFC_REAL_10 + case 10: + *((GFC_REAL_10 *) dest) = 0.0; + break; +#endif + +#ifdef HAVE_GFC_REAL_16 + case 16: + *((GFC_REAL_16 *) dest) = 0.0; + break; +#endif + + default: + internal_error (&dtp->common, "Unsupported real kind during IO"); + } + return; + +bad_float: + generate_error (&dtp->common, LIBERROR_READ_VALUE, + "Bad value during floating point read"); + next_record (dtp, 1); + return; } |