diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2012-03-19 19:31:37 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2012-03-19 19:31:37 -0700 |
commit | e75c5716a22e2c977648230e0d9a0917b41afe56 (patch) | |
tree | 556c60c7bbe55bc1707f89e9c8fadbc165020fde | |
parent | 16414f430caa17fccb2e15611a367bb9236ac0ee (diff) | |
download | txr-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-- | ChangeLog | 11 | ||||
-rw-r--r-- | stream.c | 55 |
2 files changed, 65 insertions, 1 deletions
@@ -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. @@ -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)) |