diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/math.c | 35 | ||||
-rw-r--r-- | Src/params.c | 151 | ||||
-rw-r--r-- | Src/subst.c | 8 |
3 files changed, 176 insertions, 18 deletions
diff --git a/Src/math.c b/Src/math.c index 42355f885..266569827 100644 --- a/Src/math.c +++ b/Src/math.c @@ -556,6 +556,9 @@ lexconstant(void) int outputradix; /**/ +int outputunderscore; + +/**/ static int zzlex(void) { @@ -713,7 +716,7 @@ zzlex(void) return EOI; case '[': { - int n; + int n, checkradix = 0; if (idigit(*ptr)) { n = zstrtol(ptr, &ptr, 10); @@ -730,9 +733,19 @@ zzlex(void) n = -1; ptr++; } - if (!idigit(*ptr)) + if (!idigit(*ptr) && *ptr != '_') goto bofs; - outputradix = n * zstrtol(ptr, &ptr, 10); + if (idigit(*ptr)) { + outputradix = n * zstrtol(ptr, &ptr, 10); + checkradix = 1; + } + if (*ptr == '_') { + ptr++; + if (idigit(*ptr)) + outputunderscore = zstrtol(ptr, &ptr, 10); + else + outputunderscore = 3; + } } else { bofs: zerr("bad output format specification"); @@ -740,11 +753,13 @@ zzlex(void) } if(*ptr != ']') goto bofs; - n = (outputradix < 0) ? -outputradix : outputradix; - if (n < 2 || n > 36) { - zerr("invalid base (must be 2 to 36 inclusive): %d", - outputradix); - return EOI; + if (checkradix) { + n = (outputradix < 0) ? -outputradix : outputradix; + if (n < 2 || n > 36) { + zerr("invalid base (must be 2 to 36 inclusive): %d", + outputradix); + return EOI; + } } ptr++; break; @@ -1337,9 +1352,9 @@ matheval(char *s) char *junk; mnumber x; int xmtok = mtok; - /* maintain outputradix across levels of evaluation */ + /* maintain outputradix and outputunderscore across levels of evaluation */ if (!mlevel) - outputradix = 0; + outputradix = outputunderscore = 0; if (!*s) { x.type = MN_INTEGER; 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 */ /**/ diff --git a/Src/subst.c b/Src/subst.c index 1059508ef..cc5df3fba 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -3754,19 +3754,19 @@ static char * arithsubst(char *a, char **bptr, char *rest) { char *s = *bptr, *t; - char buf[BDIGBUFSIZE], *b = buf; + char buf[BDIGBUFSIZE], *b; mnumber v; singsub(&a); v = matheval(a); if ((v.type & MN_FLOAT) && !outputradix) - b = convfloat(v.u.d, 0, 0, NULL); + b = convfloat_underscore(v.u.d, outputunderscore); else { if (v.type & MN_FLOAT) v.u.l = (zlong) v.u.d; - convbase(buf, v.u.l, outputradix); + b = convbase_underscore(buf, v.u.l, outputradix, outputunderscore); } - t = *bptr = (char *) hcalloc(strlen(*bptr) + strlen(b) + + t = *bptr = (char *) hcalloc(strlen(*bptr) + strlen(b) + strlen(rest) + 1); t--; while ((*++t = *s++)); |