summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-08-17 07:08:16 -0700
committerKaz Kylheku <kaz@kylheku.com>2015-08-17 07:08:16 -0700
commit22460fb5930d630172c69ecf0e2bfdcb73958445 (patch)
treec8830c01cc4d31d1d6c6092fc3605e234be2e409
parent9d481651d4f20d186ffda0a8680c043e656949b8 (diff)
downloadtxr-22460fb5930d630172c69ecf0e2bfdcb73958445.tar.gz
txr-22460fb5930d630172c69ecf0e2bfdcb73958445.tar.bz2
txr-22460fb5930d630172c69ecf0e2bfdcb73958445.zip
Streamlining format with new args module.
* stream.c (vformat): split into a new function called aformat, and a small wrapper which retains the vformat name. (aformat): New function formed from most of vformat. Takes struct args * instead of va_list. (formatv): Big switch statement hack gone. Now the function fills in a struct args, allocated on the stack, with an accurate size based on the args list. This is passed directly to aformat.
-rw-r--r--stream.c114
1 files changed, 48 insertions, 66 deletions
diff --git a/stream.c b/stream.c
index bf50220f..7ffe18c3 100644
--- a/stream.c
+++ b/stream.c
@@ -26,6 +26,7 @@
#include <stdio.h>
#include <string.h>
+#include <stddef.h>
#include <dirent.h>
#include <stdarg.h>
#include <stdlib.h>
@@ -53,6 +54,8 @@
#include "gc.h"
#include "signal.h"
#include "unwind.h"
+#include ALLOCA_H
+#include "args.h"
#include "stream.h"
#include "utf8.h"
#include "eval.h"
@@ -2132,10 +2135,11 @@ static void vformat_str(val stream, val str, int width, enum align align,
rel1(&str);
}
-val vformat(val stream, val fmtstr, va_list vl)
+static val aformat(val stream, val fmtstr, struct args *al)
{
val save_indent = get_indent(stream);
val save_mode = nil;
+ val name = lit("format");
uw_simple_catch_begin;
@@ -2150,6 +2154,7 @@ val vformat(val stream, val fmtstr, va_list vl)
enum align align = al_right;
int sign = 0, zeropad = 0;
cnum value;
+ cnum arg_ix = 0;
for (;;) {
val obj;
@@ -2242,7 +2247,8 @@ val vformat(val stream, val fmtstr, va_list vl)
case '5': case '6': case '7': case '8': case '9':
digits = (digits * 10) + (ch - '0');
if (digits > 999999)
- goto toobig;
+ uw_throwf(assert_s, lit("~a: ridiculous precision or field"),
+ name, nao);
continue;
default:
do_digits:
@@ -2275,7 +2281,7 @@ val vformat(val stream, val fmtstr, va_list vl)
}
break;
case vf_star:
- obj = va_arg(vl, val);
+ obj = args_get_checked(name, al, &arg_ix);
digits = c_num(obj);
goto do_digits;
break;
@@ -2283,7 +2289,7 @@ val vformat(val stream, val fmtstr, va_list vl)
state = vf_init;
switch (ch) {
case 'x': case 'X':
- obj = va_arg(vl, val);
+ obj = args_get_checked(name, al, &arg_ix);
if (bignump(obj)) {
int nchars = mp_radix_size(mp(obj), 16);
if (nchars >= convert(int, sizeof (num_buf)))
@@ -2301,7 +2307,7 @@ val vformat(val stream, val fmtstr, va_list vl)
}
goto output_num;
case 'o':
- obj = va_arg(vl, val);
+ obj = args_get_checked(name, al, &arg_ix);
if (bignump(obj)) {
int nchars = mp_radix_size(mp(obj), 8);
if (nchars >= convert(int, sizeof (num_buf)))
@@ -2313,10 +2319,7 @@ val vformat(val stream, val fmtstr, va_list vl)
}
goto output_num;
case 'f': case 'e':
- obj = va_arg(vl, val);
-
- if (obj == nao)
- goto premature;
+ obj = args_get_checked(name, al, &arg_ix);
{
double n;
@@ -2382,9 +2385,8 @@ val vformat(val stream, val fmtstr, va_list vl)
goto output_num;
}
case 'a': case 's':
- obj = va_arg(vl, val);
- if (obj == nao)
- goto premature;
+ obj = args_get_checked(name, al, &arg_ix);
+
switch (type(obj)) {
case NUM:
value = c_num(obj);
@@ -2455,7 +2457,7 @@ val vformat(val stream, val fmtstr, va_list vl)
continue;
case 'p':
{
- val ptr = va_arg(vl, val);
+ val ptr = args_get_checked(name, al, &arg_ix);
value = coerce(cnum, ptr);
sprintf(num_buf, num_fmt->hex, value);
}
@@ -2485,17 +2487,11 @@ val vformat(val stream, val fmtstr, va_list vl)
break;
}
- }
- if (0) {
-premature:
- internal_error("insufficient arguments for format");
-toobig:
- internal_error("ridiculous precision or field width in format");
+ if (args_more(al, arg_ix))
+ uw_throwf(assert_s, lit("~a: excess arguments"), name, nao);
}
- if (va_arg(vl, val) != nao)
- internal_error("unterminated format argument list");
uw_unwind {
set_indent(stream, save_indent);
@@ -2510,6 +2506,18 @@ toobig:
return t;
}
+val vformat(val stream, val fmtstr, va_list vl)
+{
+ struct args *args = args_alloc(ARGS_MAX);
+ val arg;
+ args_init(args, ARGS_MAX);
+
+ while ((arg = va_arg(vl, val)) != nao)
+ args_add_checked(lit("format"), args, arg);
+
+ return aformat(stream, fmtstr, args);
+}
+
val vformat_to_string(val fmtstr, va_list vl)
{
val stream = make_string_output_stream();
@@ -2535,51 +2543,25 @@ val format(val stream, val str, ...)
}
}
-val formatv(val stream, val string, val args)
-{
- val arg[32], *p = arg;
-
- for (; args && p - arg < 32; args = cdr(args), p++)
- *p = car(args);
-
- switch (p - arg) {
- case 0: return format(stream, string, nao);
- case 1: return format(stream, string, arg[0], nao);
- case 2: return format(stream, string, arg[0], arg[1], nao);
- case 3: return format(stream, string, arg[0], arg[1], arg[2], nao);
- case 4: return format(stream, string, arg[0], arg[1], arg[2], arg[3], nao);
- case 5: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], nao);
- case 6: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], nao);
- case 7: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], nao);
- case 8: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], nao);
- case 9: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], nao);
- case 10: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], nao);
- case 11: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], nao);
- case 12: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], nao);
- case 13: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], nao);
- case 14: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], nao);
- case 15: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], nao);
- case 16: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], nao);
- case 17: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], nao);
- case 18: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], nao);
- case 19: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], nao);
- case 20: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], nao);
- case 21: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], nao);
- case 22: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], nao);
- case 23: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], nao);
- case 24: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], nao);
- case 25: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], arg[24], nao);
- case 26: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], arg[24], arg[25], nao);
- case 27: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], arg[24], arg[25], arg[26], nao);
- case 28: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], arg[24], arg[25], arg[26], arg[27], nao);
- case 29: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], arg[24], arg[25], arg[26], arg[27], arg[28], nao);
- case 30: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], arg[24], arg[25], arg[26], arg[27], arg[28], arg[29], nao);
- case 31: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], arg[24], arg[25], arg[26], arg[27], arg[28], arg[29], arg[30], nao);
- case 32: return format(stream, string, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14], arg[15], arg[16], arg[17], arg[18], arg[19], arg[20], arg[21], arg[22], arg[23], arg[24], arg[25], arg[26], arg[27], arg[28], arg[29], arg[30], arg[31], nao);
- }
-
- uw_throwf(file_error_s, lit("too many arguments to format"), nao);
- abort();
+val formatv(val stream, val string, val arglist)
+{
+ uses_or2;
+ val st = if3(stream == t,
+ std_output,
+ or2(stream, make_string_output_stream()));
+ cnum argc = args_limit(lit("format"), c_num(length_list(arglist)));
+ struct args *args = args_alloc(argc);
+ val ret;
+
+ class_check(st, stream_s);
+ args_init(args, argc);
+
+ for (; arglist; arglist = cdr(arglist))
+ args_add(args, car(arglist));
+
+ ret = aformat(st, string, args);
+
+ return (stream) ? ret : get_string_from_stream(st);
}
static val put_indent(val stream, struct strm_ops *ops, cnum chars)