summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2012-03-19 19:31:37 -0700
committerKaz Kylheku <kaz@kylheku.com>2012-03-19 19:31:37 -0700
commite75c5716a22e2c977648230e0d9a0917b41afe56 (patch)
tree556c60c7bbe55bc1707f89e9c8fadbc165020fde
parent16414f430caa17fccb2e15611a367bb9236ac0ee (diff)
downloadtxr-e75c5716a22e2c977648230e0d9a0917b41afe56.tar.gz
txr-e75c5716a22e2c977648230e0d9a0917b41afe56.tar.bz2
txr-e75c5716a22e2c977648230e0d9a0917b41afe56.zip
* stream.c (vformat): num_buf increased to 256 because we
are now printing floating point numbers into it, letting the C library handle precision which can generate many digits. We cap the precision at at 128. New format specifiers ~e and ~f implemented, which loosely correspond to those of printf. The ~s and ~a directives handle floats similarly to ~g in printf, except that they ensure that a decimal point is printed for the non-exponential notation.
-rw-r--r--ChangeLog11
-rw-r--r--stream.c55
2 files changed, 65 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index f378d7ba..f3c1822a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
2012-03-19 Kaz Kylheku <kaz@kylheku.com>
+ * stream.c (vformat): num_buf increased to 256 because we
+ are now printing floating point numbers into it, letting
+ the C library handle precision which can generate many digits.
+ We cap the precision at at 128. New format specifiers ~e
+ and ~f implemented, which loosely correspond to those of printf.
+ The ~s and ~a directives handle floats similarly to ~g in
+ printf, except that they ensure that a decimal point is printed
+ for the non-exponential notation.
+
+2012-03-19 Kaz Kylheku <kaz@kylheku.com>
+
* configure (uintptr): New variable. Indicates whether unsigned
version of intptr_t is available and should be generated in config.h
as uintptr_t.
diff --git a/stream.c b/stream.c
index 4a2e4e7f..2d7a6e94 100644
--- a/stream.c
+++ b/stream.c
@@ -967,7 +967,7 @@ val vformat(val stream, val fmtstr, va_list vl)
for (;;) {
val obj;
wchar_t ch = *fmt++;
- char num_buf[64], *pnum = num_buf;
+ char num_buf[256], *pnum = num_buf;
switch (state) {
case vf_init:
@@ -1113,6 +1113,40 @@ val vformat(val stream, val fmtstr, va_list vl)
sprintf(num_buf, num_fmt->oct, value);
}
goto output_num;
+ case 'f': case 'e':
+ obj = va_arg(vl, val);
+
+ if (obj == nao)
+ goto premature;
+
+ {
+ double n;
+
+ if (bignump(obj))
+ uw_throwf(error_s, lit("format: ~s: bignum to float "
+ "conversion unsupported\n"), obj, nao);
+
+ if (fixnump(obj))
+ n = (double) c_num(obj);
+ else if (floatp(obj))
+ n = obj->fl.n;
+ else
+ uw_throwf(error_s, lit("format: ~~~a conversion requires "
+ "numeric arg: ~s given\n"),
+ chr(ch), obj, nao);
+
+ /* guard against num_buf overflow */
+ if (precision > 128)
+ uw_throwf(error_s, lit("excessive precision in format: ~s\n"),
+ num(precision), nao);
+
+ if (ch == 'e')
+ sprintf(num_buf, "%.*e", precision, obj->fl.n);
+ else
+ sprintf(num_buf, "%.*f", precision, obj->fl.n);
+ precision = 0;
+ goto output_num;
+ }
case 'a': case 's':
obj = va_arg(vl, val);
if (obj == nao)
@@ -1127,6 +1161,25 @@ val vformat(val stream, val fmtstr, va_list vl)
pnum = (char *) chk_malloc(nchars + 1);
mp_toradix(mp(obj), (unsigned char *) pnum, 10);
goto output_num;
+ } else if (floatp(obj)) {
+ sprintf(num_buf, "%g", obj->fl.n);
+
+ if (!precision) {
+ if (!strpbrk(num_buf, "e."))
+ strcat(num_buf, ".0");
+ } else {
+ /* guard against num_buf overflow */
+ if (precision > 128)
+ uw_throwf(error_s, lit("excessive precision in format: ~s\n"),
+ num(precision), nao);
+
+ if (strchr(num_buf, 'e'))
+ sprintf(num_buf, "%.*e", precision, obj->fl.n);
+ else
+ sprintf(num_buf, "%.*f", precision, obj->fl.n);
+ precision = 0;
+ }
+ goto output_num;
} else if (width != 0) {
val str = format(nil, ch == 'a' ? lit("~a") : lit("~s"), obj, nao);
if (!vformat_str(stream, str, width, left, precision))