diff options
author | Peter Stephenson <pws@zsh.org> | 2014-01-23 10:32:59 +0000 |
---|---|---|
committer | Peter Stephenson <pws@zsh.org> | 2014-01-23 10:32:59 +0000 |
commit | 22b8fd6da931657ec930ba2625179c704de3e830 (patch) | |
tree | 2266493aa799af7431af9308fd6cb7e088fb668e /Src/params.c | |
parent | 6c603a412751c810ba04bcd463cd3595091ca391 (diff) | |
download | zsh-22b8fd6da931657ec930ba2625179c704de3e830.tar.gz zsh-22b8fd6da931657ec930ba2625179c704de3e830.tar.xz zsh-22b8fd6da931657ec930ba2625179c704de3e830.zip |
32299: add use of underscores on arithmetic output for spacing
Diffstat (limited to 'Src/params.c')
-rw-r--r-- | Src/params.c | 151 |
1 files changed, 147 insertions, 4 deletions
diff --git a/Src/params.c b/Src/params.c index ad9e3470b..dc41c6c92 100644 --- a/Src/params.c +++ b/Src/params.c @@ -2416,9 +2416,10 @@ setnumvalue(Value v, mnumber val) if ((val.type & MN_INTEGER) || outputradix) { if (!(val.type & MN_INTEGER)) val.u.l = (zlong) val.u.d; - convbase(p = buf, val.u.l, outputradix); + p = convbase_underscore(buf, val.u.l, outputradix, + outputunderscore); } else - p = convfloat(val.u.d, 0, 0, NULL); + p = convfloat_underscore(val.u.d, outputunderscore); setstrvalue(v, ztrdup(p)); break; case PM_INTEGER: @@ -4555,9 +4556,14 @@ delenv(Param pm) */ } +/* + * Guts of convbase: this version can return the number of digits + * sans any base discriminator. + */ + /**/ -mod_export void -convbase(char *s, zlong v, int base) +void +convbase_ptr(char *s, zlong v, int base, int *ndigits) { int digs = 0; zulong x; @@ -4583,6 +4589,8 @@ convbase(char *s, zlong v, int base) x /= base; if (!digs) digs = 1; + if (ndigits) + *ndigits = digs; s[digs--] = '\0'; x = v; while (digs >= 0) { @@ -4594,6 +4602,64 @@ convbase(char *s, zlong v, int base) } /* + * Basic conversion of integer to a string given a base. + * If 0 base is 10. + * If negative no base discriminator is output. + */ + +/**/ +mod_export void +convbase(char *s, zlong v, int base) +{ + convbase_ptr(s, v, base, NULL); +} + +/* + * Add underscores to converted integer for readability with given spacing. + * s is as for convbase: at least BDIGBUFSIZE. + * If underscores were added, returned value with underscores comes from + * heap, else the returned value is s. + */ + +/**/ +char * +convbase_underscore(char *s, zlong v, int base, int underscore) +{ + char *retptr, *sptr, *dptr; + int ndigits, nunderscore, mod, len; + + convbase_ptr(s, v, base, &ndigits); + + if (underscore <= 0) + return s; + + nunderscore = (ndigits - 1) / underscore; + if (!nunderscore) + return s; + len = strlen(s); + retptr = zhalloc(len + nunderscore + 1); + mod = 0; + memcpy(retptr, s, len - ndigits); + sptr = s + len; + dptr = retptr + len + nunderscore; + /* copy the null */ + *dptr-- = *sptr--; + for (;;) { + *dptr = *sptr; + if (!--ndigits) + break; + dptr--; + sptr--; + if (++mod == underscore) { + mod = 0; + *dptr-- = '_'; + } + } + + return retptr; +} + +/* * Convert a floating point value for output. * Unlike convbase(), this has its own internal storage and returns * a value from the heap. @@ -4659,6 +4725,83 @@ convfloat(double dval, int digits, int flags, FILE *fout) return ret; } +/* + * convert float to string with basic options but inserting underscores + * for readability. + */ + +/**/ +char *convfloat_underscore(double dval, int underscore) +{ + int ndigits_int = 0, ndigits_frac = 0, nunderscore, len; + char *s, *retptr, *sptr, *dptr; + + s = convfloat(dval, 0, 0, NULL); + if (underscore <= 0) + return s; + + /* + * Count the number of digits before and after the decimal point, if any. + */ + sptr = s; + if (*sptr == '-') + sptr++; + while (idigit(*sptr)) { + ndigits_int++; + sptr++; + } + if (*sptr == '.') { + sptr++; + while (idigit(*sptr)) { + ndigits_frac++; + sptr++; + } + } + + /* + * Work out how many underscores to insert --- remember we + * put them in integer and fractional parts separately. + */ + nunderscore = (ndigits_int-1) / underscore + (ndigits_frac-1) / underscore; + if (!nunderscore) + return s; + len = strlen(s); + dptr = retptr = zhalloc(len + nunderscore + 1); + + /* + * Insert underscores in integer part. + * Grouping starts from the point in both directions. + */ + sptr = s; + if (*sptr == '-') + *dptr++ = *sptr++; + while (ndigits_int) { + *dptr++ = *sptr++; + if (--ndigits_int && !(ndigits_int % underscore)) + *dptr++ = '_'; + } + if (ndigits_frac) { + /* + * Insert underscores in the fractional part. + */ + int mod = 0; + /* decimal point, we already checked */ + *dptr++ = *sptr++; + while (ndigits_frac) { + *dptr++ = *sptr++; + mod++; + if (--ndigits_frac && mod == underscore) { + *dptr++ = '_'; + mod = 0; + } + } + } + /* Copy exponent and anything else up to null */ + while ((*dptr++ = *sptr++)) + ; + return retptr; +} + /* Start a parameter scope */ /**/ |