summaryrefslogtreecommitdiff
path: root/Src/params.c
diff options
context:
space:
mode:
authorPeter Stephenson <pws@zsh.org>2014-01-23 10:32:59 +0000
committerPeter Stephenson <pws@zsh.org>2014-01-23 10:32:59 +0000
commit22b8fd6da931657ec930ba2625179c704de3e830 (patch)
tree2266493aa799af7431af9308fd6cb7e088fb668e /Src/params.c
parent6c603a412751c810ba04bcd463cd3595091ca391 (diff)
downloadzsh-22b8fd6da931657ec930ba2625179c704de3e830.tar.gz
zsh-22b8fd6da931657ec930ba2625179c704de3e830.zip
32299: add use of underscores on arithmetic output for spacing
Diffstat (limited to 'Src/params.c')
-rw-r--r--Src/params.c151
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 */
/**/