diff options
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | builtin.c | 117 | ||||
-rw-r--r-- | pc/Makefile.tst | 10 | ||||
-rw-r--r-- | test/ChangeLog | 2 | ||||
-rw-r--r-- | test/Makefile.am | 9 | ||||
-rw-r--r-- | test/Makefile.in | 15 | ||||
-rw-r--r-- | test/Maketests | 6 |
7 files changed, 160 insertions, 9 deletions
@@ -1,3 +1,13 @@ +2021-09-06 Arnold D. Robbins <arnold@skeeve.com> + + Have the ' flag work for %d in MPFR mode also. Thanks to + Dan Nielsen <catskill549@yahoo.com> for the report. + + * builtin.c (add_thousands): New function. + (reverse): New helper function. + (format_tree): Use add_thousands if MPFR and an integer + format. + 2021-09-03 Arnold D. Robbins <arnold@skeeve.com> * main.c (UPDATE_YEAR): Update to 2021. @@ -79,6 +79,7 @@ extern NODE **fields_arr; extern bool output_is_tty; extern FILE *output_fp; +static const char *add_thousands(const char *original, struct lconv *loc); #define POP_TWO_SCALARS(s1, s2) \ s2 = POP_SCALAR(); \ @@ -1553,6 +1554,7 @@ mpf1: setlocale(LC_NUMERIC, ""); #endif + bool need_to_add_thousands = false; switch (fmt_type) { #ifdef HAVE_MPFR case MP_INT_WITH_PREC: @@ -1560,12 +1562,14 @@ mpf1: while ((nc = mpfr_snprintf(obufout, ofre, cpbuf, (int) fw, (int) prec, zi)) >= (int) ofre) chksize(nc) + need_to_add_thousands = true; break; case MP_INT_WITHOUT_PREC: sprintf(cp, "*Z%c", cs1); while ((nc = mpfr_snprintf(obufout, ofre, cpbuf, (int) fw, zi)) >= (int) ofre) chksize(nc) + need_to_add_thousands = true; break; case MP_FLOAT: sprintf(cp, "*.*R*%c", cs1); @@ -1596,8 +1600,16 @@ mpf1: if (quote_flag && ! use_lc_numeric) setlocale(LC_NUMERIC, "C"); #endif - len = strlen(obufout); + if (quote_flag && need_to_add_thousands) { + const char *new_text = add_thousands(obufout, & loc); + + len = strlen(new_text); + chksize(len) + strcpy(obufout, new_text); + free((void *) new_text); + } + ofre -= len; obufout += len; s0 = s1; @@ -4349,3 +4361,106 @@ check_symtab_functab(NODE *dest, const char *fname, const char *msg) else if (dest == func_table) fatal(msg, fname, "FUNCTAB"); } + +/* reverse --- reverse the contents of a string in place */ + +static void +reverse(char *str) +{ + int i, j; + char tmp; + + for (i = 0, j = strlen(str) - 1; j > i; i++, j--) { + tmp = str[i]; + str[i] = str[j]; + str[j] = tmp; + } +} + +/* add_thousands --- add the thousands separator. Needed for MPFR %d format */ + +/* + * Copy the source string into the destination string, backwards, + * adding the thousands separator at the right points. Then reverse + * the string when done. This gives us much cleaner code than trying + * to work through the string backwards. (We tried it, it was yucky.) + */ + +static const char * +add_thousands(const char *original, struct lconv *loc) +{ + size_t orig_len = strlen(original); + size_t new_len = orig_len + (orig_len * strlen(loc->thousands_sep)) + 1; // worst case + char *newbuf; + char decimal_point = '\0'; + const char *dec = NULL; + const char *src; + char *dest; + + emalloc(newbuf, char *, new_len, "add_thousands"); + memset(newbuf, '\0', new_len); + + src = original + strlen(original) - 1; + dest = newbuf; + + if (loc->decimal_point[0] != '\0') { + decimal_point = loc->decimal_point[0]; + if ((dec = strchr(original, decimal_point)) != NULL) { + while (src >= dec) + *dest++ = *src--; + } + } + + + int ii = 0; + int jj = 0; + do { + *dest++ = *src--; + if (loc->grouping[ii] && ++jj == loc->grouping[ii]) { + if (src >= original) { /* only add if more digits coming */ + const char *ts = loc->thousands_sep; + + while (*ts != '\0') + *dest++ = *ts++; + } + if (loc->grouping[ii+1] == 0) + jj = 0; /* keep using current val in loc.grouping[ii] */ + else if (loc->grouping[ii+1] == CHAR_MAX) { + // copy in the rest and be done + while (src >= original) + *dest++ = *src--; + break; + } else { + ii++; + jj = 0; + } + } + } while (src >= original); + + *dest++ = '\0'; + reverse(newbuf); + + return newbuf; +} + +#if 0 +// test program + +int main(int argc, char **argv) +{ + struct lconv *l; + + setlocale(LC_ALL, ""); + l = localeconv(); + + const char *new = add_thousands("12345678901234567890.54321", l); + printf("%s\n", new); + free((void*) new); + + new = add_thousands("12345678901234567890", l); + printf("%s\n", new); + free((void*) new); + + return 0; +} +#endif diff --git a/pc/Makefile.tst b/pc/Makefile.tst index 0894a057..b2c92c74 100644 --- a/pc/Makefile.tst +++ b/pc/Makefile.tst @@ -193,7 +193,7 @@ GAWK_EXT_TESTS = \ arraytype \ backw badargs beginfile1 beginfile2 binmode1 \ charasbytes colonwarn clos1way clos1way2 clos1way3 clos1way4 clos1way5 \ - clos1way6 crlf \ + clos1way6 commas crlf \ dbugeval dbugeval2 dbugeval3 dbugtypedre1 dbugtypedre2 delsub \ devfd devfd1 devfd2 dfacheck1 dumpvars \ errno exit fieldwdth forcenum \ @@ -305,7 +305,7 @@ NEED_LOCALE_C = \ clos1way gsubtst6 range2 NEED_LOCALE_EN = \ - backbigs1 backsmalls1 backsmalls2 concat4 dfamb1 ignrcas2 lc_num1 \ + backbigs1 backsmalls1 backsmalls2 commas concat4 dfamb1 ignrcas2 lc_num1 \ mbfw1 mbprintf1 mbprintf3 mbprintf4 mbstr1 mbstr2 posix_compare \ printhuge reint2 rri1 subamp subi18n wideidx wideidx2 \ widesub widesub2 widesub3 widesub4 @@ -2629,6 +2629,12 @@ clos1way6: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +commas: + @echo $@ + @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=ENU_USA.1252; export GAWKLOCALE; \ + AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + crlf: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/test/ChangeLog b/test/ChangeLog index e79d3383..007d182b 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -2,6 +2,8 @@ * Makefile.am (EXTRA_DIST): typeof6, new test. * typeof6.awk, typeof6.ok: New files. + * Makefile.am (EXTRA_DIST): commas, new test. + * commas.awk, commas.ok: New files. 2021-08-13 Arnold D. Robbins <arnold@skeeve.com> diff --git a/test/Makefile.am b/test/Makefile.am index e4a7b640..bd800fff 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -195,6 +195,9 @@ EXTRA_DIST = \ colonwarn.awk \ colonwarn.in \ colonwarn.ok \ + commas.awk \ + commas.in \ + commas.ok \ compare.awk \ compare.in \ compare.ok \ @@ -1437,7 +1440,7 @@ GAWK_EXT_TESTS = \ arraytype \ backw badargs beginfile1 beginfile2 binmode1 \ charasbytes colonwarn clos1way clos1way2 clos1way3 clos1way4 clos1way5 \ - clos1way6 crlf \ + clos1way6 commas crlf \ dbugeval dbugeval2 dbugeval3 dbugtypedre1 dbugtypedre2 delsub \ devfd devfd1 devfd2 dfacheck1 dumpvars \ errno exit fieldwdth forcenum \ @@ -1548,12 +1551,12 @@ NEED_LOCALE_C = \ clos1way gsubtst6 range2 NEED_LOCALE_EN = \ - backbigs1 backsmalls1 backsmalls2 concat4 dfamb1 ignrcas2 lc_num1 \ + backbigs1 backsmalls1 backsmalls2 commas concat4 dfamb1 ignrcas2 lc_num1 \ mbfw1 mbprintf1 mbprintf3 mbprintf4 mbstr1 mbstr2 posix_compare \ printhuge reint2 rri1 subamp subi18n wideidx wideidx2 \ widesub widesub2 widesub3 widesub4 -# Unused at the moment, since nlstringtest has additional stufff it does +# Unused at the moment, since nlstringtest has additional stuff it does # NEED_LOCALE_FR = # Same for ignrcas3 # NEED_LOCALE_GR = diff --git a/test/Makefile.in b/test/Makefile.in index 7882baef..3a8381c8 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -458,6 +458,9 @@ EXTRA_DIST = \ colonwarn.awk \ colonwarn.in \ colonwarn.ok \ + commas.awk \ + commas.in \ + commas.ok \ compare.awk \ compare.in \ compare.ok \ @@ -1700,7 +1703,7 @@ GAWK_EXT_TESTS = \ arraytype \ backw badargs beginfile1 beginfile2 binmode1 \ charasbytes colonwarn clos1way clos1way2 clos1way3 clos1way4 clos1way5 \ - clos1way6 crlf \ + clos1way6 commas crlf \ dbugeval dbugeval2 dbugeval3 dbugtypedre1 dbugtypedre2 delsub \ devfd devfd1 devfd2 dfacheck1 dumpvars \ errno exit fieldwdth forcenum \ @@ -1812,13 +1815,13 @@ NEED_LOCALE_C = \ clos1way gsubtst6 range2 NEED_LOCALE_EN = \ - backbigs1 backsmalls1 backsmalls2 concat4 dfamb1 ignrcas2 lc_num1 \ + backbigs1 backsmalls1 backsmalls2 commas concat4 dfamb1 ignrcas2 lc_num1 \ mbfw1 mbprintf1 mbprintf3 mbprintf4 mbstr1 mbstr2 posix_compare \ printhuge reint2 rri1 subamp subi18n wideidx wideidx2 \ widesub widesub2 widesub3 widesub4 -# Unused at the moment, since nlstringtest has additional stufff it does +# Unused at the moment, since nlstringtest has additional stuff it does # NEED_LOCALE_FR = # Same for ignrcas3 # NEED_LOCALE_GR = @@ -4304,6 +4307,12 @@ clos1way6: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +commas: + @echo $@ + @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; export GAWKLOCALE; \ + AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + crlf: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ diff --git a/test/Maketests b/test/Maketests index 2d7b4d78..a1062736 100644 --- a/test/Maketests +++ b/test/Maketests @@ -1366,6 +1366,12 @@ clos1way6: @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ +commas: + @echo $@ + @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; export GAWKLOCALE; \ + AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@ + crlf: @echo $@ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ |