static void
write_decimal (st_parameter_dt *dtp, const fnode *f, const char *source,
- int len,
- const char *(*conv) (GFC_INTEGER_LARGEST, char *, size_t))
+ int len)
{
GFC_INTEGER_LARGEST n = 0;
+ GFC_UINTEGER_LARGEST absn;
int w, m, digits, nsign, nzero, nblank;
char *p;
const char *q;
sign = calculate_sign (dtp, n < 0);
if (n < 0)
- n = -n;
+ /* Use unsigned to protect from overflow. */
+ absn = -(GFC_UINTEGER_LARGEST) n;
+ else
+ absn = n;
nsign = sign == S_NONE ? 0 : 1;
- /* conv calls itoa which sets the negative sign needed
- by write_integer. The sign '+' or '-' is set below based on sign
- calculated above, so we just point past the sign in the string
- before proceeding to avoid double signs in corner cases.
- (see PR38504) */
- q = conv (n, itoa_buf, sizeof (itoa_buf));
- if (*q == '-')
- q++;
-
+ /* gfc_itoa() converts the nonnegative value to decimal representation. */
+ q = gfc_itoa (absn, itoa_buf, sizeof (itoa_buf));
digits = strlen (q);
/* Select a width if none was specified. The idea here is to always
}
-/* Convert unsigned octal to ascii. */
+/* Convert hexadecimal to ASCII. */
+
+static const char *
+xtoa (GFC_UINTEGER_LARGEST n, char *buffer, size_t len)
+{
+ int digit;
+ char *p;
+
+ assert (len >= GFC_XTOA_BUF_SIZE);
+
+ if (n == 0)
+ return "0";
+
+ p = buffer + GFC_XTOA_BUF_SIZE - 1;
+ *p = '\0';
+
+ while (n != 0)
+ {
+ digit = n & 0xF;
+ if (digit > 9)
+ digit += 'A' - '0' - 10;
+
+ *--p = '0' + digit;
+ n >>= 4;
+ }
+
+ return p;
+}
+
+
+/* Convert unsigned octal to ASCII. */
static const char *
otoa (GFC_UINTEGER_LARGEST n, char *buffer, size_t len)
}
-/* Convert unsigned binary to ascii. */
+/* Convert unsigned binary to ASCII. */
static const char *
btoa (GFC_UINTEGER_LARGEST n, char *buffer, size_t len)
return p;
}
-/* The following three functions, btoa_big, otoa_big, and ztoa_big, are needed
+/* The following three functions, btoa_big, otoa_big, and xtoa_big, are needed
to convert large reals with kind sizes that exceed the largest integer type
available on certain platforms. In these cases, byte by byte conversion is
performed. Endianess is taken into account. */
return q;
}
-/* Conversion to hexidecimal. */
+/* Conversion to hexadecimal. */
static const char *
-ztoa_big (const char *s, char *buffer, int len, GFC_UINTEGER_LARGEST *n)
+xtoa_big (const char *s, char *buffer, int len, GFC_UINTEGER_LARGEST *n)
{
static char a[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
}
}
- /* write_z, which calls ztoa_big, is called from transfer.c,
+ /* write_z, which calls xtoa_big, is called from transfer.c,
formatted_transfer_scalar_write. There it is passed the kind as
argument, which means a maximum of 16. The buffer is large
enough, but the compiler does not know that, so shut up the
void
write_i (st_parameter_dt *dtp, const fnode *f, const char *p, int len)
{
- write_decimal (dtp, f, p, len, (void *) gfc_itoa);
+ write_decimal (dtp, f, p, len);
}
if (len > (int) sizeof (GFC_UINTEGER_LARGEST))
{
- p = ztoa_big (source, itoa_buf, len, &n);
+ p = xtoa_big (source, itoa_buf, len, &n);
write_boz (dtp, f, p, n, len);
}
else
{
n = extract_uint (source, len);
- p = gfc_xtoa (n, itoa_buf, sizeof (itoa_buf));
+ p = xtoa (n, itoa_buf, sizeof (itoa_buf));
write_boz (dtp, f, p, n, len);
}
}
f.u.integer.w = width;
f.u.integer.m = -1;
f.format = FMT_NONE;
- write_decimal (dtp, &f, source, kind, (void *) gfc_itoa);
+ write_decimal (dtp, &f, source, kind);
}
#define GFC_LARGEST_BUF (sizeof (GFC_INTEGER_LARGEST))
#endif
-#define GFC_ITOA_BUF_SIZE (sizeof (GFC_INTEGER_LARGEST) * 3 + 2)
+#define GFC_ITOA_BUF_SIZE (sizeof (GFC_INTEGER_LARGEST) * 3 + 1)
#define GFC_XTOA_BUF_SIZE (GFC_LARGEST_BUF * 2 + 1)
#define GFC_OTOA_BUF_SIZE (GFC_LARGEST_BUF * 3 + 1)
#define GFC_BTOA_BUF_SIZE (GFC_LARGEST_BUF * 8 + 1)
__attribute__((format (gfc_printf, 1, 2)));
internal_proto(st_printf);
-extern const char *gfc_xtoa (GFC_UINTEGER_LARGEST, char *, size_t);
-internal_proto(gfc_xtoa);
-
extern _Noreturn void os_error (const char *);
iexport_proto(os_error);
extern char *fc_strdup_notrim(const char *, gfc_charlen_type);
internal_proto(fc_strdup_notrim);
-extern const char *gfc_itoa(GFC_INTEGER_LARGEST, char *, size_t);
+extern const char *gfc_itoa(GFC_UINTEGER_LARGEST, char *, size_t);
internal_proto(gfc_itoa);
/* io/intrinsics.c */
}
-/* gfc_itoa()-- Integer to decimal conversion.
- The itoa function is a widespread non-standard extension to
- standard C, often declared in <stdlib.h>. Even though the itoa
- defined here is a static function we take care not to conflict with
- any prior non-static declaration. Hence the 'gfc_' prefix, which
- is normally reserved for functions with external linkage. Notably,
- in contrast to the *printf() family of functions, this ought to be
- async-signal-safe. */
+/* Integer to decimal conversion.
+
+ This function is much more restricted than the widespread (but
+ non-standard) itoa() function. This version has the following
+ characteristics:
+
+ - it takes only non-negative arguments
+ - it is async-signal-safe (we use it runtime/backtrace.c)
+ - it works in base 10 (see xtoa, otoa, btoa functions
+ in io/write.c for other radices)
+ */
const char *
-gfc_itoa (GFC_INTEGER_LARGEST n, char *buffer, size_t len)
+gfc_itoa (GFC_UINTEGER_LARGEST n, char *buffer, size_t len)
{
- int negative;
char *p;
- GFC_UINTEGER_LARGEST t;
if (len < GFC_ITOA_BUF_SIZE)
sys_abort ();
if (n == 0)
return "0";
- negative = 0;
- t = n;
- if (n < 0)
- {
- negative = 1;
- t = -(GFC_UINTEGER_LARGEST) n; /* Must use unsigned to protect from overflow. */
- }
-
p = buffer + GFC_ITOA_BUF_SIZE - 1;
*p = '\0';
- while (t != 0)
+ while (n != 0)
{
- *--p = '0' + (t % 10);
- t /= 10;
+ *--p = '0' + (n % 10);
+ n /= 10;
}
- if (negative)
- *--p = '-';
return p;
}