summaryrefslogtreecommitdiffstats
path: root/stream.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2012-03-22 13:51:15 -0700
committerKaz Kylheku <kaz@kylheku.com>2012-03-22 13:51:15 -0700
commitcffd912f512dc46b5a732068a0380c059db0f07d (patch)
tree724d494ff91f293f0044cdc120f9346cbdcb0b9d /stream.c
parent1ccc6d458fbda380233019a1d80d5aff576d9d03 (diff)
downloadtxr-cffd912f512dc46b5a732068a0380c059db0f07d.tar.gz
txr-cffd912f512dc46b5a732068a0380c059db0f07d.tar.bz2
txr-cffd912f512dc46b5a732068a0380c059db0f07d.zip
* parser.l: Bugfix: was not allowing e-notation floats
with no decimal point like 1E1. * stream.c: (vformat): Keep track of whether or not precision was given in precision_p local variable. When printing #<bad-float> pass a precision of 0 to vformat_str, not precision, since precision does not apply. In ~f and ~e, if the precision was not given, default it to 3. Restructured float printing in ~a and ~s. It now just uses sprintf's %g with a precision. If user does not specify precision, it defaults to DBL_DIG to print the number with reasonable accuracy. A .0 is added if it sprintf produces an integer, and the conversion is ~s rather than ~a.
Diffstat (limited to 'stream.c')
-rw-r--r--stream.c43
1 files changed, 23 insertions, 20 deletions
diff --git a/stream.c b/stream.c
index 6761afd8..a4b7863d 100644
--- a/stream.c
+++ b/stream.c
@@ -35,6 +35,7 @@
#include <ctype.h>
#include <wchar.h>
#include <unistd.h>
+#include <float.h>
#include "config.h"
#if HAVE_SYS_WAIT
#include <sys/wait.h>
@@ -960,7 +961,7 @@ val vformat(val stream, val fmtstr, va_list vl)
enum {
vf_init, vf_width, vf_digits, vf_precision, vf_spec
} state = vf_init, saved_state = vf_init;
- int width = 0, precision = 0, digits = 0;
+ int width = 0, precision = 0, precision_p = 0, digits = 0;
int left = 0, sign = 0, zeropad = 0;
cnum value;
void *ptr;
@@ -981,6 +982,7 @@ val vformat(val stream, val fmtstr, va_list vl)
left = 0;
zeropad = 0;
precision = 0;
+ precision_p = 0;
digits = 0;
continue;
default:
@@ -1035,6 +1037,7 @@ val vformat(val stream, val fmtstr, va_list vl)
obj = va_arg(vl, val);
width = c_num(obj);
precision = vf_precision;
+ precision_p = 1;
continue;
default:
state = vf_spec;
@@ -1067,6 +1070,7 @@ val vformat(val stream, val fmtstr, va_list vl)
continue;
case vf_precision:
precision = digits;
+ precision_p = 1;
state = vf_spec;
--fmt;
continue;
@@ -1139,6 +1143,9 @@ val vformat(val stream, val fmtstr, va_list vl)
chr(ch), obj, nao);
}
+ if (!precision_p)
+ precision = 3;
+
/* guard against num_buf overflow */
if (precision > 128)
uw_throwf(error_s, lit("excessive precision in format: ~s\n"),
@@ -1150,7 +1157,7 @@ val vformat(val stream, val fmtstr, va_list vl)
sprintf(num_buf, "%.*f", precision, n);
if (!isdigit(num_buf[0])) {
if (!vformat_str(stream, lit("#<bad-float>"),
- width, left, precision))
+ width, left, 0))
return nil;
continue;
}
@@ -1175,30 +1182,26 @@ val vformat(val stream, val fmtstr, va_list vl)
}
goto output_num;
case FLNUM:
- sprintf(num_buf, "%g", obj->fl.n);
+ if (!precision_p)
+ precision = DBL_DIG;
- if (!isdigit(num_buf[0])) {
+ if (precision > 500)
+ uw_throwf(error_s, lit("excessive precision in format: ~s\n"),
+ num(precision), nao);
+
+ sprintf(num_buf, "%.*g", precision, obj->fl.n);
+
+ if (ch == 's' && !precision_p && !strpbrk(num_buf, "e."))
+ strcat(num_buf, ".0");
+
+ if (!isdigit(num_buf[0]) && !isdigit(num_buf[1])) {
if (!vformat_str(stream, lit("#<bad-float>"),
- width, left, precision))
+ width, left, 0))
return nil;
continue;
}
- 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;
- }
+ precision = 0;
goto output_num;
default:
if (width != 0) {