[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[SCM] gawk branch, stable/printf-rework, updated. gawk-4.1.0-5492-g7b9e9
From: |
Arnold Robbins |
Subject: |
[SCM] gawk branch, stable/printf-rework, updated. gawk-4.1.0-5492-g7b9e9bca |
Date: |
Sun, 7 Jul 2024 15:21:55 -0400 (EDT) |
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "gawk".
The branch, stable/printf-rework has been updated
via 7b9e9bca203c92acaa6b3cd107764be319994038 (commit)
from dde70cc78f2cfc69439c35713575158d14366567 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://git.sv.gnu.org/cgit/gawk.git/commit/?id=7b9e9bca203c92acaa6b3cd107764be319994038
commit 7b9e9bca203c92acaa6b3cd107764be319994038
Author: Arnold D. Robbins <arnold@skeeve.com>
Date: Sun Jul 7 22:21:31 2024 +0300
Continuing to refactor printf.
diff --git a/ChangeLog b/ChangeLog
index 0f07fbab..226ec04e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2024-07-07 Arnold D. Robbins <arnold@skeeve.com>
+
+ * printf.c: Signed and unsigned integer printing mostly working now.
+ Still to go: Finish that up, get GMP/MPFR integer printing working.
+
2024-07-05 Arnold D. Robbins <arnold@skeeve.com>
* printf.c: Lots of cleanup. Floating point format pretty
diff --git a/printf.c b/printf.c
index 3cb5450c..939741b7 100644
--- a/printf.c
+++ b/printf.c
@@ -1139,7 +1139,7 @@ NODE *
format_tree_new(
const char *fmt_string,
size_t n0,
- NODE **the_args,
+ NODE *the_args[],
long num_args)
{
/* copy 'l' bytes from 's' to 'obufout' checking for space in the process */
@@ -1824,6 +1824,18 @@ out0:
set_flags();
adjust_flags(& flags);
+ {
+ const char *formatted = format_unsigned_integer(arg, &
flags);
+ len = strlen(formatted);
+ chksize(len)
+ strcpy(obufout, formatted);
+ free((void *) formatted);
+
+ ofre -= len;
+ obufout += len;
+ s0 = s1;
+ break;
+ }
if (out_of_range(arg))
@@ -2358,8 +2370,9 @@ format_integer_digits(NODE *arg, struct flags *flags)
const char *chbuf;
char *cp;
bool quote_flag = false;
- bool negative = false;
uintmax_t uval;
+ int i;
+ double tmpval;
#define growbuffer(buf, buflen, cp) { \
erealloc(buf, char *, buflen * 2, "format_integer_xxx"); \
@@ -2370,34 +2383,47 @@ format_integer_digits(NODE *arg, struct flags *flags)
#if defined(HAVE_LOCALE_H)
quote_flag = (flags->quote && loc.thousands_sep[0] != '\0');
#endif
-
- chbuf = (flags->format == 'X' ? Uchbuf : lchbuf);
emalloc(buf, char *, VALUE_SIZE, "format_integer_digits");
buflen = VALUE_SIZE;
cp = buf;
- // C 2023 says negative zeros get a minus sign
- // for floating conversions.
- if (flags->base == 10 && arg->numbr < 0) {
- negative = true;
- arg->numbr = -arg->numbr;
- }
- uval = get_number_uj(arg);
+ if (flags->base == 10 && flags->format != 'u') {
+ // signed decimal
+ tmpval = double_to_int(arg->numbr);
+ if (tmpval == -0)
+ tmpval = 0;
+
+ /*
+ * Use snprintf return value to tell if there
+ * is enough room in the buffer or not.
+ */
+ while ((i = snprintf(buf, buflen, "%.0f", tmpval)) >= buflen) {
+ if (i > 0)
+ buflen += (i > buflen) ? i : buflen;
+ else
+ buflen *= 2;
+ assert(buflen > 0);
+ erealloc(buf, char *, buflen, "format_tree");
+ }
+ } else {
+ // octal or hex
+ chbuf = (flags->format == 'X' ? Uchbuf : lchbuf);
- // generate the digits backwards.
- do {
- if (cp >= buf + buflen)
- growbuffer(buf, buflen, cp);
+ uval = get_number_uj(arg);
- *cp++ = chbuf[uval % flags->base];
- uval /= flags->base;
- } while (uval > 0);
- if (negative)
- *cp++ = '-';
- *cp = '\0';
+ // generate the digits backwards.
+ do {
+ if (cp >= buf + buflen)
+ growbuffer(buf, buflen, cp);
- // turn it back around
- reverse(buf);
+ *cp++ = chbuf[uval % flags->base];
+ uval /= flags->base;
+ } while (uval > 0);
+ *cp = '\0';
+
+ // turn it back around
+ reverse(buf);
+ }
if (flags->base == 10 && quote_flag) {
const char *with_commas = add_thousands(buf);
@@ -2508,13 +2534,11 @@ format_signed_integer(NODE *arg, struct flags *flags)
static const char *
format_unsigned_integer(NODE *arg, struct flags *flags)
{
- // FIXME: still needs work
const char *number_value;
- double tmpval;
char *buf1 = NULL;
- size_t buflen;
char *buf2 = NULL;
char fill[] = " ";
+ size_t val_len;
if (out_of_range(arg))
return format_out_of_range(arg, flags);
@@ -2522,187 +2546,85 @@ format_unsigned_integer(NODE *arg, struct flags *flags)
if (is_mpg_integer(arg) || is_mpg_float(arg))
return format_mpg_integer(arg, flags);
- number_value = format_integer_digits(arg, flags); // just digits,
possible leading '-'
- tmpval = arg->numbr;
-
+ number_value = format_integer_digits(arg, flags); // just digits
+ val_len = strlen(number_value);
// We now have the initial *integer* decimal, octal, or hex value in
hand.
- // If it's decimal, we've added commas if appropriate. If it's negative
- // and decimal, it has a minus sign.
+ // If it's decimal, we've added commas if appropriate.
// The next step is deal with the rest of the printf flags.
- if (tmpval == 0 && flags->field_width == 0
- && ! flags->have_prec) {
- // relatively simple case
- if (flags->base == 16 && flags->alt) {
- size_t len = strlen(number_value) + 2 + 1;
-
- emalloc(buf1, char *, len, "format_integer");
- sprintf(buf1, "0%c%s", flags->format, number_value);
- free((void *) number_value);
-
- return buf1;
- } else if (flags->base == 10 && (flags->plus || flags->space)
- && number_value[0] != '-') {
- size_t len = strlen(number_value) + 1 + 1;
-
- emalloc(buf1, char *, len, "format_integer");
- if (flags->plus)
- sprintf(buf1, "+%s", number_value);
- else
- sprintf(buf1, " %s", number_value);
- free((void *) number_value);
-
- return buf1;
- } else
- return number_value;
- }
-
- // Now it gets messy...
-
+ // Add more output digits to match the precision
+ if (flags->have_prec && val_len < flags->precision) {
+ char *cp;
+ const char *src;
+ int prec = flags->precision;
- /*
- * ``The result of converting a zero value with a
- * precision of zero is no characters.''
- *
- * If I remember the ANSI C standard, though,
- * it says that for octal conversions
- * the precision is artificially increased
- * to add an extra 0 if # is supplied.
- * Indeed, in C,
- * printf("%#.0o\n", 0);
- * prints a single 0.
- */
- if (! flags->alt && flags->have_prec && flags->precision == 0 && tmpval
== 0) {
- if (flags->base == 8)
- flags->precision = 1;
- else {
- buf1 = (char *) number_value;
- goto pr_tail;
+ // plus and space flags are only for signed conversions
+ emalloc(buf1, char *, flags->precision + 1,
+ "format_unsigned_integer");
+ cp = buf1;
+ src = number_value;
+ if (number_value[0] == '-') {
+ *cp++ = '-';
+ src++;
+ val_len--;
}
- }
-
- if (compute_zero_flag(flags))
- fill[0] = '0'; // fill with zeros
-
- /* add more output digits to match the precision */
- if (flags->have_prec && flags->precision > 0) {
- bool negative = (number_value[0] == '-');
- size_t len = strlen(number_value);
- char *cp1;
- len += flags->precision + 1;
- emalloc(buf1, char *, len, "format_integer");
- strcpy(buf1, number_value);
-
- reverse(buf1);
- cp1 = buf1 + len;
- if (negative)
- cp1--; // overwrite the '-', we'll add it back in a
minute
- while (cp1 - buf1 < flags->precision) {
- if (cp1 - buf1 >= len)
- growbuffer(buf1, len, cp1);
+ for (; prec > val_len; prec--)
+ *cp++ = '0';
- *cp1++ = '0';
- }
- if (negative)
- *cp1++ = '-';
- *cp1 = '\0';
- reverse(buf1);
+ strcpy(cp, src);
+ free((void *) number_value);
+ val_len = strlen(buf1);
} else
buf1 = (char *) number_value;
+ // handle the alt flag
if (flags->alt) {
- if (flags->base == 16 && tmpval != 0) {
- if (fill[0] == '0') {
- emalloc(buf2, char *, strlen(buf1) + 3,
"format_integer");
- sprintf(buf2, "0%c%s", flags->format, buf1);
- flags->field_width -= 2;
- free((void *) buf1);
- buf1 = buf2;
- }
- } else if (flags->base == 8 && tmpval == 0) {
- assert(number_value[0] == '\0');
- emalloc(buf2, char *, 2, "format_integer");
- strcpy(buf2, "0");
- flags->field_width--;
- free((void *) buf1);
- buf1 = buf2;
+ emalloc(buf2, char *, val_len + 3, "format_unsigned_integer");
+
+ if (flags->base == 16) {
+ sprintf(buf2, "0%c%s", flags->format, buf1);
+ } else if (flags->base == 8) {
+ if (number_value[0] != '0')
+ sprintf(buf2, "0%s", buf1);
+ else
+ strcpy(buf2, buf1);
}
+ free((void *) buf1);
+ buf1 = buf2;
+ val_len = strlen(buf1);
}
- // deal with space or plus flags
-
- if (flags->precision > flags->field_width)
- flags->field_width = flags->precision;
- flags->precision = strlen(buf1);
-pr_tail:
- int st_len = strlen(buf1);
- buflen = flags->field_width;
- if (buflen < st_len)
- buflen = st_len;
- if (flags->plus || flags->space)
- buflen++;
- buflen++; // for '\0'
-
- emalloc(buf2, char *, buflen, "format_integer");
- char *cp = buf2;
- /*
- * Order:
- * 1. Create the number. This is what's in buf1.
- * 2. If zero flag, pad number to field width.
- * 3. If plus flag, first leading zero converts to +.
- * 4. Else if space flag, first leading zero converts to space.
- * 5. If not padded, just, insert plus or space if need be.
- *
- * If we have not padded, and the field width is > length of
- * number, two cases:
- * 1. Left justified, stick plus or space in front of number,
- * then the number, then the spaces.
- * 2. Right justified, do spaces, then plus, then number.
- *
- * Plus sign is only added if not a negative number and if signed;
- * in practice this means base == 10.
- */
- bool padded = false;
- int padlen = buflen - st_len;
+ // pad the field if necessary
+ if (flags->field_width > val_len) {
+ char *cp;
+ const char *src;
+ int fw = flags->field_width;
- if (flags->zero) {
- for (; padlen > 0; padlen--)
- *cp++ = '0';
- strcpy(cp, buf1);
- padded = true;
- }
+ emalloc(buf2, char *, flags->field_width + 1,
"format_unsigned_integer");
- if (padded) {
- buf2[0] = (flags->plus ? '+' :
- flags->space ? ' ' : '0');
- } else if (flags->plus || flags->space) {
- sprintf(buf2, "%c%s",
- flags->plus ? '+' : ' ', buf1);
- }
+ cp = buf2;
+ src = buf1;
+ if (compute_zero_flag(flags) && ! flags->alt)
+ fill[0] = '0';
- if (flags->left_just) {
- } else {
- // normal - spaces or zeros first.
- if (flags->plus && fill[0] == '0') {
- *cp++ = '+';
- flags->field_width--;
- }
- while (flags->field_width > flags->precision) {
- *cp++ = fill[0];
- flags->field_width--;
+ if (flags->left_just) {
+ strcpy(cp, src);
+ cp += val_len;
+ for (; fw > val_len; fw--)
+ *cp++ = fill[0];
+ } else {
+ for (; fw > val_len; fw--)
+ *cp++ = fill[0];
+ strcpy(cp, src);
}
- if (flags->plus && fill[0] == ' ')
- *--cp = '+';
- }
- // bchunk(cp, buf1);
- free((void *) buf1);
- while (flags->field_width > flags->precision) {
- // bchunk_one(fill);
- flags->field_width--;
+
+ free((void *) buf1);
+ buf1 = buf2;
+ val_len = strlen(buf1);
}
return buf1;
@@ -2792,7 +2714,79 @@ compute_zero_flag(struct flags *flags)
static const char *
format_mpg_integer(NODE *arg, struct flags *flags)
{
- return strdup("mpg_int");
+#if 0
+#ifdef HAVE_MPFR
+ mpz_ptr zi;
+ mpfr_ptr mf;
+ bool zero_flags = compute_zero_flag(flags);
+
+ if (is_mpg_integer(arg)) {
+ zi = arg->mpg_i;
+
+ if (flags->format != 'd' && flags->format != 'i') {
+ if (mpz_sgn(zi) <= 0) {
+ /*
+ * Negative value or 0 requires special
handling.
+ * Unlike MPFR, GMP does not allow conversion
+ * to (u)intmax_t. So we first convert GMP type
to
+ * a MPFR type.
+ */
+ mf = mpz2mpfr(zi);
+ goto mpf1;
+ }
+ signchar = '\0'; /* Don't print '+' */
+ }
+
+ zero_flags = compute_zero_flag(flags);
+
+ fmt_type = have_prec ? MP_INT_WITH_PREC : MP_INT_WITHOUT_PREC;
+ goto fmt0;
+
+ } else if (is_mpg_float(arg)) {
+mpf0:
+ mf = arg->mpg_numbr;
+ if (! mpfr_number_p(mf)) {
+ cant_happen("%s", "format_mpg_integer called on nan or
inf");
+ }
+
+ if (cs1 != 'd' && cs1 != 'i') {
+mpf1:
+ /*
+ * The output of printf("%#.0x", 0) is 0 instead of 0x,
hence <= in
+ * the comparison below.
+ */
+ if (mpfr_sgn(mf) <= 0) {
+ if (! mpfr_fits_intmax_p(mf, ROUND_MODE)) {
+ return format_float(arg, flags);
+ }
+
+ tmpval = uval = (uintmax_t) mpfr_get_sj(mf,
ROUND_MODE);
+ if (! alt && have_prec && prec == 0 && tmpval
== 0) {
+ if (flags->base == 8)
+ return strdup("0");
+ else
+ return strdup(""); /*
printf("%.0x", 0) is no characters */
+ }
+ goto int0;
+ }
+ }
+
+ /* See comments above about when to fill with zeros */
+ zero_flag = (! lj
+ && ((zero_flag && ! have_prec)
+ || (fw == 0 && have_prec)));
+
+ (void) mpfr_get_z(mpzval, mf, MPFR_RNDZ); /* convert to
GMP integer */
+ fmt_type = have_prec ? MP_INT_WITH_PREC : MP_INT_WITHOUT_PREC;
+ zi = mpzval;
+ goto fmt0;
+ }
+#else
+ cant_happen("%s", "trying to format GMP integer");
+#endif
+#else
+ return strdup("mpgint");
+#endif
}
@@ -2838,6 +2832,9 @@ format_mpg_integer(NODE *arg, struct flags *flags)
static void
adjust_flags(struct flags *flags)
{
+ if (flags->base == 0)
+ cant_happen("%s", "flags->base == 0");
+
if (flags->base == 10 || strchr("cdisu", flags->format) != NULL)
flags->alt = false;
@@ -2849,13 +2846,16 @@ adjust_flags(struct flags *flags)
if (flags->base != 10) {
flags->quote = false;
flags->plus = false;
+ flags->space = false;
}
if (flags->plus)
flags->space = false;
- if (flags->format == 'u')
+ if (flags->format == 'u') {
flags->plus = false;
+ flags->space = false;
+ }
if (flags->left_just)
flags->zero = false;
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 5 +
printf.c | 376 +++++++++++++++++++++++++++++++-------------------------------
2 files changed, 193 insertions(+), 188 deletions(-)
hooks/post-receive
--
gawk
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [SCM] gawk branch, stable/printf-rework, updated. gawk-4.1.0-5492-g7b9e9bca,
Arnold Robbins <=