extern void read_decimal (st_parameter_dt *, const fnode *, char *, int);
internal_proto(read_decimal);
+extern void read_decimal_unsigned (st_parameter_dt *, const fnode *, char *,
+ int);
+internal_proto(read_decimal_unsigned);
+
extern void read_user_defined (st_parameter_dt *, void *);
internal_proto(read_user_defined);
extern void write_i (st_parameter_dt *, const fnode *, const char *, int);
internal_proto(write_i);
+extern void write_iu (st_parameter_dt *, const fnode *, const char *, int);
+internal_proto(write_iu);
+
extern void write_l (st_parameter_dt *, const fnode *, char *, int);
internal_proto(write_l);
if ((c & ~masks[nb-1]) == patns[nb-1])
goto found;
goto invalid;
-
+
found:
c = (c & masks[nb-1]);
nread = nb - 1;
goto invalid;
return c;
-
+
invalid:
generate_error (&dtp->common, LIBERROR_READ_VALUE, "Invalid UTF-8 encoding");
return (gfc_char4_t) '?';
size_t m;
s = read_block_form (dtp, &width);
-
+
if (s == NULL)
return;
if (width > len)
read_utf8_char4 (dtp, p, length, w);
else
read_default_char4 (dtp, p, length, w);
-
+
dtp->u.p.sf_read_comma =
dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA ? 0 : 1;
}
if (c != ' ')
return c;
if (dtp->u.p.blank_status != BLANK_UNSPECIFIED)
- return ' '; /* return a blank to signal a null */
+ return ' '; /* return a blank to signal a null */
/* At this point, the rest of the field has to be trailing blanks */
c = next_char (dtp, &p, &w);
if (c == '\0')
break;
-
+
if (c == ' ')
{
if (dtp->u.p.blank_status == BLANK_NULL)
{
/* Skip spaces. */
for ( ; w > 0; p++, w--)
- if (*p != ' ') break;
+ if (*p != ' ') break;
continue;
}
if (dtp->u.p.blank_status == BLANK_ZERO) c = '0';
}
-
+
if (c < '0' || c > '9')
goto bad;
}
+/* read_decimal_unsigned () - almost the same as above, but we do not check for
+ overflow, but just calculate everything mod 2^n. */
+
+void
+read_decimal_unsigned (st_parameter_dt *dtp, const fnode *f, char *dest,
+ int length)
+{
+ GFC_UINTEGER_LARGEST value, v;
+ size_t w;
+ int negative;
+ char c, *p;
+
+ w = f->u.w;
+
+ /* This is a legacy extension, and the frontend will only allow such cases
+ * through when -fdec-format-defaults is passed.
+ */
+ if (w == (size_t) DEFAULT_WIDTH)
+ w = default_width_for_integer (length);
+
+ p = read_block_form (dtp, &w);
+
+ if (p == NULL)
+ return;
+
+ p = eat_leading_spaces (&w, p);
+ if (w == 0)
+ {
+ set_unsigned (dest, (GFC_UINTEGER_LARGEST) 0, length);
+ return;
+ }
+
+ negative = 0;
+
+ switch (*p)
+ {
+ case '-':
+ negative = 1;
+ /* Fall through */
+
+ case '+':
+ p++;
+ if (--w == 0)
+ goto bad;
+ /* Fall through */
+
+ default:
+ break;
+ }
+
+ /* At this point we have a digit-string */
+ value = 0;
+
+ for (;;)
+ {
+ c = next_char (dtp, &p, &w);
+ if (c == '\0')
+ break;
+
+ if (c == ' ')
+ {
+ if (dtp->u.p.blank_status == BLANK_NULL)
+ {
+ /* Skip spaces. */
+ for ( ; w > 0; p++, w--)
+ if (*p != ' ') break;
+ continue;
+ }
+ if (dtp->u.p.blank_status == BLANK_ZERO) c = '0';
+ }
+
+ if (c < '0' || c > '9')
+ goto bad;
+
+ c -= '0';
+ value = 10 * value;
+ value += c;
+ }
+
+ if (negative)
+ value = -value;
+
+ set_unsigned (dest, value, length);
+ return;
+
+ bad:
+ generate_error (&dtp->common, LIBERROR_READ_VALUE,
+ "Bad value during integer read");
+ next_record (dtp, 1);
+ return;
+}
+
/* read_radix()-- This function reads values for non-decimal radixes.
The difference here is that we treat the values here as unsigned
if (w == 0)
goto zero;
- /* Check for Infinity or NaN. */
+ /* Check for Infinity or NaN. */
if (unlikely ((w >= 3 && (*p == 'i' || *p == 'I' || *p == 'n' || *p == 'N'))))
{
int seen_paren = 0;
++p;
++out;
}
-
+
*out = '\0';
-
+
if (seen_paren != 0 && seen_paren != 2)
goto bad_float;
++p;
--w;
}
-
+
/* No exponent has been seen, so we use the current scale factor. */
exponent = - dtp->u.p.scale_factor;
goto done;
++p;
--w;
}
-
+
/* Only allow trailing blanks. */
while (w > 0)
{
++p;
--w;
}
- }
+ }
else /* BZ or BN status is enabled. */
{
while (w > 0)
significand. */
else if (!seen_int_digit && !seen_dec_digit)
{
- notify_std (&dtp->common, GFC_STD_LEGACY,
+ notify_std (&dtp->common, GFC_STD_LEGACY,
"REAL input of style 'E+NN'");
*(out++) = '0';
}
if ((dtp->u.p.current_unit->pad_status == PAD_NO || is_internal_unit (dtp))
&& dtp->u.p.current_unit->bytes_left < (gfc_offset) n)
n = dtp->u.p.current_unit->bytes_left;
-
+
if (n == 0)
return;
-
+
if (dtp->u.p.current_unit->flags.encoding == ENCODING_UTF8)
{
gfc_char4_t c;
size_t nbytes, j;
-
+
/* Proceed with decoding one character at a time. */
for (j = 0; j < n; j++)
{
c = read_utf8 (dtp, &nbytes);
-
+
/* Check for a short read and if so, break out. */
if (nbytes == 0 || c == (gfc_char4_t)0)
break;
the rest of the I/O statement. Set the corresponding flag. */
if (dtp->u.p.advance_status == ADVANCE_NO || dtp->u.p.seen_dollar)
dtp->u.p.eor_condition = 1;
-
+
/* If we encounter a CR, it might be a CRLF. */
if (q == '\r') /* Probably a CRLF */
{
goto done;
}
n++;
- }
+ }
done:
if (((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0) ||
dtp->u.p.current_unit->bytes_left -= n;
dtp->u.p.current_unit->strm_pos += (gfc_offset) n;
}
-
case BT_INTEGER:
p = "INTEGER";
break;
+ case BT_UNSIGNED:
+ p = "UNSIGNED";
+ break;
case BT_LOGICAL:
p = "LOGICAL";
break;
return 1;
}
+/* Check that the actual matches one of two expected types; issue an error
+ if that is not the case. */
+
+
+static int
+require_one_of_two_types (st_parameter_dt *dtp, bt expected1, bt expected2,
+ bt actual, const fnode *f)
+{
+ char buffer[BUFLEN];
+
+ if (actual == expected1)
+ return 0;
+
+ if (actual == expected2)
+ return 0;
+
+ snprintf (buffer, BUFLEN,
+ "Expected %s or %s for item %d in formatted transfer, got %s",
+ type_name (expected1), type_name (expected2),
+ dtp->u.p.item_count - 1, type_name (actual));
+
+ format_error (dtp, f, buffer);
+ return 1;
+
+}
/* Check that the dtio procedure required for formatted IO is present. */
case FMT_I:
if (n == 0)
goto need_read_data;
- if (require_type (dtp, BT_INTEGER, type, f))
+ if (require_one_of_two_types (dtp, BT_INTEGER, BT_UNSIGNED, type, f))
return;
- read_decimal (dtp, f, p, kind);
+ if (type == BT_INTEGER)
+ read_decimal (dtp, f, p, kind);
+ else
+ read_decimal_unsigned (dtp, f, p, kind);
break;
case FMT_B:
case FMT_I:
if (n == 0)
goto need_data;
- if (require_type (dtp, BT_INTEGER, type, f))
+ if (require_one_of_two_types (dtp, BT_INTEGER, BT_UNSIGNED, type, f))
return;
- write_i (dtp, f, p, kind);
+ if (type == BT_INTEGER)
+ write_i (dtp, f, p, kind);
+ else
+ write_iu (dtp, f, p, kind);
break;
case FMT_B: