aboutsummaryrefslogtreecommitdiff
path: root/libgfortran/io/write.c
diff options
context:
space:
mode:
Diffstat (limited to 'libgfortran/io/write.c')
-rw-r--r--libgfortran/io/write.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/libgfortran/io/write.c b/libgfortran/io/write.c
index 91d1da2..2f414c6 100644
--- a/libgfortran/io/write.c
+++ b/libgfortran/io/write.c
@@ -949,7 +949,134 @@ write_decimal (st_parameter_dt *dtp, const fnode *f, const char *source,
return;
}
+/* Same as above, but somewhat simpler because we only treat unsigned
+ numbers. */
+static void
+write_decimal_unsigned (st_parameter_dt *dtp, const fnode *f,
+ const char *source, int len)
+{
+ GFC_UINTEGER_LARGEST n = 0;
+ int w, m, digits, nsign, nzero, nblank;
+ char *p;
+ const char *q;
+ sign_t sign;
+ char itoa_buf[GFC_BTOA_BUF_SIZE];
+
+ w = f->u.integer.w;
+ m = f->format == FMT_G ? -1 : f->u.integer.m;
+
+ n = extract_uint (source, len);
+
+ /* Special case: */
+ if (m == 0 && n == 0)
+ {
+ if (w == 0)
+ w = 1;
+
+ p = write_block (dtp, w);
+ if (p == NULL)
+ return;
+
+ if (unlikely (is_char4_unit (dtp)))
+ {
+ gfc_char4_t *p4 = (gfc_char4_t *) p;
+ memset4 (p4, ' ', w);
+ }
+ else
+ memset (p, ' ', w);
+ goto done;
+ }
+
+ /* Just in case somebody wants a + sign. */
+ sign = calculate_sign (dtp, false);
+ nsign = sign == S_NONE ? 0 : 1;
+
+ q = gfc_itoa (n, itoa_buf, sizeof (itoa_buf));
+ digits = strlen (q);
+
+ /* Select a width if none was specified. The idea here is to always
+ print something. */
+ if (w == DEFAULT_WIDTH)
+ w = default_width_for_integer (len);
+
+ if (w == 0)
+ w = ((digits < m) ? m : digits) + nsign;
+
+ p = write_block (dtp, w);
+ if (p == NULL)
+ return;
+
+ nzero = 0;
+ if (digits < m)
+ nzero = m - digits;
+
+ /* See if things will work. */
+
+ nblank = w - (nsign + nzero + digits);
+
+ if (unlikely (is_char4_unit (dtp)))
+ {
+ gfc_char4_t *p4 = (gfc_char4_t *)p;
+ if (nblank < 0)
+ {
+ memset4 (p4, '*', w);
+ goto done;
+ }
+
+ if (!dtp->u.p.namelist_mode)
+ {
+ memset4 (p4, ' ', nblank);
+ p4 += nblank;
+ }
+
+ if (sign == S_PLUS)
+ *p4++ = '+';
+
+ memset4 (p4, '0', nzero);
+ p4 += nzero;
+
+ memcpy4 (p4, q, digits);
+
+ if (dtp->u.p.namelist_mode)
+ {
+ p4 += digits;
+ memset4 (p4, ' ', nblank);
+ }
+
+ return;
+ }
+
+ if (nblank < 0)
+ {
+ star_fill (p, w);
+ goto done;
+ }
+
+ if (!dtp->u.p.namelist_mode)
+ {
+ memset (p, ' ', nblank);
+ p += nblank;
+ }
+
+ if (sign == S_PLUS)
+ *p++ = '+';
+
+ memset (p, '0', nzero);
+ p += nzero;
+
+ memcpy (p, q, digits);
+
+ if (dtp->u.p.namelist_mode)
+ {
+ p += digits;
+ memset (p, ' ', nblank);
+ }
+
+ done:
+ return;
+
+}
/* Convert hexadecimal to ASCII. */
static const char *
@@ -1240,6 +1367,11 @@ write_i (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
write_decimal (dtp, f, p, len);
}
+void
+write_iu (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
+{
+ write_decimal_unsigned (dtp, f, p, len);
+}
void
write_b (st_parameter_dt *dtp, const fnode *f, const char *source, int len)
@@ -1404,6 +1536,47 @@ write_integer (st_parameter_dt *dtp, const char *source, int kind)
write_decimal (dtp, &f, source, kind);
}
+/* Write a list-directed unsigned value. We use the same formatting
+ as for integer. */
+
+static void
+write_unsigned (st_parameter_dt *dtp, const char *source, int kind)
+{
+ int width;
+ fnode f;
+
+ switch (kind)
+ {
+ case 1:
+ width = 4;
+ break;
+
+ case 2:
+ width = 6;
+ break;
+
+ case 4:
+ width = 11;
+ break;
+
+ case 8:
+ width = 20;
+ break;
+
+ case 16:
+ width = 40;
+ break;
+
+ default:
+ width = 0;
+ break;
+ }
+ f.u.integer.w = width;
+ f.u.integer.m = -1;
+ f.format = FMT_NONE;
+ write_decimal_unsigned (dtp, &f, source, kind);
+}
+
/* Write a list-directed string. We have to worry about delimiting
the strings if the file has been opened in that mode. */
@@ -1942,6 +2115,9 @@ list_formatted_write_scalar (st_parameter_dt *dtp, bt type, void *p, int kind,
case BT_INTEGER:
write_integer (dtp, p, kind);
break;
+ case BT_UNSIGNED:
+ write_unsigned (dtp, p, kind);
+ break;
case BT_LOGICAL:
write_logical (dtp, p, kind);
break;