about summary refs log tree commit diff
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.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.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 */
 
 /**/