summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog96
-rw-r--r--gc.c4
-rw-r--r--lib.c141
-rw-r--r--lib.h5
-rw-r--r--match.c261
-rw-r--r--parser.h2
-rw-r--r--parser.l92
-rw-r--r--stream.c491
-rw-r--r--stream.h8
-rw-r--r--txr.c139
-rw-r--r--unwind.c46
-rw-r--r--unwind.h32
-rw-r--r--utf8.c8
13 files changed, 756 insertions, 569 deletions
diff --git a/ChangeLog b/ChangeLog
index 376dfb31..0cb0e42e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,99 @@
+2009-11-16 Kaz Kylheku <kkylheku@gmail.com>
+
+ Big round of changes to switch the code base to use the stream
+ abstraction instead of directly using C standard I/O,
+ to eliminate most uses of C formatted I/O,
+ and fix numerous bugs, such variadic argument lists which
+ lack a terminating ``nao'' sentinel.
+
+ Bug 28033 is addressed by this patch, since streams no longer provide
+ printf-compatible formatting. The native formatter is extended with
+ some additional capabilities to take over.
+
+ The work on literal objects is expanded and they are now used
+ throughout the code base.
+
+ Fixed bad realloc in string output stream: reallocating by number
+ of wide chars rather than bytes.
+
+ * gc.c (sweep): Debugging code switched from fprintf to format.
+
+ * lib.c (typ_check, type_check2, car, cdr, car_l, cdr_l, list,
+ num, chrp, apply, cobj_print_op, dump): Retargetted, with help of new
+ literals, to new funtions that take string objects, rather than raw C
+ strings.
+ (obj_print, obj_pprint): Revamped with support for LIT type.
+ Retargetted to not use C style I/O functions in streams.
+
+ * lib.h (lit): Macro retargetted to another macro so that it expands
+ its argument.
+ (lit_noex): New macro, like lit, but does not macro-expand argument.
+ (auto_str): New macro.
+ (static_str): New macro.
+
+ * match.c (debugf, debuglf, sem_error, file_err): Converted from C
+ string to string object.
+ (dest_bind, match_line, LOG_MISMATCH, LOG_MATCH, match_files):
+ Retargetted to new interfaces that take string objects rather than raw
+ C strings.
+ (complex_stream): New function.
+ (do_output_line, do_output, extract): Retargetted from C streams to
+ object streams.
+
+ * parser.h (yyerrorf): Declaration updated.
+
+ * parser.l (yyerror): Call new yyerrorf interface, using auto_str
+ macro to dress up C string as a temporary object.
+ (yyerrorf): Changed from C strings to object strings.
+ (yybadtoken, grammar): Retargetted to new yyerrorf.
+
+ * stream.c (strm_ops): put_string and put_char function pointers
+ changed to take object strings rather than C strings. vcformat and
+ vformat virtuals removed. C formatting is not supported, and vformat is
+ handled above the stream switch level in one place for all streams.
+ (common_vformat, stdio_vcformat, string_out_vcformat, cformat,
+ put_cstring, put_cchar): Functions removed.
+ (stdio_stream_print, stdio_stream_destroy, stdio_maybe_write_error,
+ stdio_put_string, stdio_put_char, stdio_close, pipe_close,
+ string_out_put_char, make_pipe_stream, make_string_input_stream,
+ make_string_output_stream, make_dir_stream, close_stream,
+ get_line, put_line, get_char, put_char, put_string): Retargetted to new
+ string object interfaces.
+ (stdio_ops, pipe_ops): stdio_vcformat and common_vcformat initializers
+ (string_out_ops): string_out_vcformat and common_vcformat initializers
+ removed.
+ (string_in_ops, byte_in_ops, dir_ops): Two null initializers removed.
+ (string_out_put_string): Converted to object string interface.
+ Unnecessary chk_realloc call suppressed.
+ (get_string_from_stream): Fixed bad call to realloc with incorrect
+ size.
+ (vformat_num, vformat_str): New functions, helper to vformat.
+ (vformat): Rewritten. Is now the formatting engine.
+ (format, put_string, put_char): Interface converted from C string to
+ object string.
+
+ * stream.h (vformat, format): Declarations updated.
+ (vcformat, cformat, put_cstring, put_cchar): Declarations removed.
+
+ * txr.c (oom_realloc_handler, help, txr_main): Retargetted to object
+ stream and strings.
+
+ * unwind.c (uw_throw, type_mismatch, uw_register_subtype): Retargetted
+ to new string object interfaces.
+ (uw_throwf, uw_errorf): Interface changed from C string to object
+ string.
+ (uw_throwcf, uw_errorcf): Functions removed.
+
+ * unwind.h (uw_throwf, uw_errorf, type_mismatch): Declarations updated.
+ (uw_throwcf, uw_errorcf): Declarations removed.
+ (internal_error): Macro interface changed and retargetted to
+ object strings. Also, num hygiene problem worked around with local
+ extern declaration.
+ (numeric_assert, range_bug_unless): Retargetted to object strings.
+
+ * utf8.c (utf8_to, utf8_dup_from_uc, utf8_dup_from,
+ utf8_dup_to_uc): Casts of chk_malloc return value added.
+
2009-11-15 Kaz Kylheku <kkylheku@gmail.com>
Use the 11 tag bit pattern to denote a new type: LIT. This is a
diff --git a/gc.c b/gc.c
index 850fab3f..3167fe4d 100644
--- a/gc.c
+++ b/gc.c
@@ -324,9 +324,9 @@ static void sweep(void)
continue;
if (0 && dbg) {
- fwprintf(stderr, L"%ls: finalizing: ", progname);
+ format(std_error, lit("~a: finalizing: "), progname, nao);
obj_print(block, std_error);
- putwc('\n', stderr);
+ put_char(std_error, chr('\n'));
}
finalize(block);
block->t.type |= FREE;
diff --git a/lib.c b/lib.c
index a04b1ee6..258d63de 100644
--- a/lib.c
+++ b/lib.c
@@ -128,14 +128,14 @@ obj_t *typeof(obj_t *obj)
obj_t *type_check(obj_t *obj, int type)
{
if (!is_ptr(obj) || obj->t.type != type)
- type_mismatch(L"~s is not of type ~s", obj, code2type(type), nao);
+ type_mismatch(lit("~s is not of type ~s"), obj, code2type(type), nao);
return t;
}
obj_t *type_check2(obj_t *obj, int t1, int t2)
{
if (!is_ptr(obj) || (obj->t.type != t1 && obj->t.type != t2))
- type_mismatch(L"~s is not of type ~s or ~s", obj,
+ type_mismatch(lit("~s is not of type ~s or ~s"), obj,
code2type(t1), code2type(t2), nao);
return t;
}
@@ -144,7 +144,7 @@ obj_t *type_check3(obj_t *obj, int t1, int t2, int t3)
{
if (!is_ptr(obj) || (obj->t.type != t1 && obj->t.type != t2
&& obj->t.type != t3))
- type_mismatch(L"~s is not of type ~s, ~s nor ~s", obj,
+ type_mismatch(lit("~s is not of type ~s, ~s nor ~s"), obj,
code2type(t1), code2type(t2), code2type(t3), nao);
return t;
}
@@ -165,7 +165,7 @@ obj_t *car(obj_t *cons)
return cons->lc.car;
}
default:
- type_mismatch(L"~s is not a cons", cons, nao);
+ type_mismatch(lit("~s is not a cons"), cons, nao);
}
}
@@ -185,7 +185,7 @@ obj_t *cdr(obj_t *cons)
return cons->lc.cdr;
}
default:
- type_mismatch(L"~s is not a cons", cons, nao);
+ type_mismatch(lit("~s is not a cons"), cons, nao);
}
}
@@ -198,7 +198,7 @@ obj_t **car_l(obj_t *cons)
funcall1(cons->lc.func, cons);
return &cons->lc.car;
default:
- type_mismatch(L"~s is not a cons", cons, nao);
+ type_mismatch(lit("~s is not a cons"), cons, nao);
}
}
@@ -211,7 +211,7 @@ obj_t **cdr_l(obj_t *cons)
funcall1(cons->lc.func, cons);
return &cons->lc.cdr;
default:
- type_mismatch(L"~s is not a cons", cons, nao);
+ type_mismatch(lit("~s is not a cons"), cons, nao);
}
}
@@ -561,7 +561,7 @@ obj_t *list(obj_t *first, ...)
do {
*ptr++ = next;
if (ptr == array + 32)
- internal_error(L"runaway arguments in list function");
+ internal_error("runaway arguments in list function");
next = va_arg(vl, obj_t *);
} while (next != nao);
@@ -624,7 +624,7 @@ obj_t *num(long val)
long c_num(obj_t *num)
{
if (!is_num(num))
- type_mismatch(L"~s is not a number", num, nao);
+ type_mismatch(lit("~s is not a number"), num, nao);
return ((long) num) >> TAG_SHIFT;
}
@@ -1012,7 +1012,7 @@ obj_t *chrp(obj_t *chr)
wchar_t c_chr(obj_t *chr)
{
if (!is_chr(chr))
- type_mismatch(L"~s is not a character", chr, nao);
+ type_mismatch(lit("~s is not a character"), chr, nao);
return ((wchar_t) chr) >> TAG_SHIFT;
}
@@ -1184,7 +1184,7 @@ obj_t *apply(obj_t *fun, obj_t *arglist)
type_check (fun, FUN);
type_assert (listp(arglist),
- (L"apply arglist ~s is not a list", arglist, nao));
+ (lit("apply arglist ~s is not a list"), arglist, nao));
*p++ = car(arglist); arglist = cdr(arglist);
*p++ = car(arglist); arglist = cdr(arglist);
@@ -1563,9 +1563,9 @@ obj_t *cobj(void *handle, obj_t *cls_sym, struct cobj_ops *ops)
void cobj_print_op(obj_t *obj, obj_t *out)
{
- put_cstring(out, L"#<");
+ put_string(out, lit("#<"));
obj_print(obj->co.cls, out);
- cformat(out, L": %p>", obj->co.handle);
+ format(out, lit(": ~p>"), obj->co.handle, nao);
}
obj_t *assoc(obj_t *list, obj_t *key)
@@ -1844,7 +1844,7 @@ static void obj_init(void)
void obj_print(obj_t *obj, obj_t *out)
{
if (obj == nil) {
- put_cstring(out, L"nil");
+ put_string(out, lit("nil"));
return;
}
@@ -1853,110 +1853,110 @@ void obj_print(obj_t *obj, obj_t *out)
case LCONS:
{
obj_t *iter;
- put_cchar(out, '(');
+ put_char(out, chr('('));
for (iter = obj; consp(iter); iter = cdr(iter)) {
obj_print(car(iter), out);
if (nullp(cdr(iter))) {
- put_cchar(out, ')');
+ put_char(out, chr(')'));
} else if (consp(cdr(iter))) {
- put_cchar(out, ' ');
+ put_char(out, chr(' '));
} else {
- put_cstring(out, L" . ");
+ put_string(out, lit(" . "));
obj_print(cdr(iter), out);
- put_cchar(out, ')');
+ put_char(out, chr(')'));
}
}
}
return;
- case STR:
case LIT:
+ case STR:
{
const wchar_t *ptr;
- put_cchar(out, '"');
+ put_char(out, chr('"'));
for (ptr = c_str(obj); *ptr; ptr++) {
switch (*ptr) {
- case L'\a': put_cstring(out, L"\\a"); break;
- case L'\b': put_cstring(out, L"\\b"); break;
- case L'\t': put_cstring(out, L"\\t"); break;
- case L'\n': put_cstring(out, L"\\n"); break;
- case L'\v': put_cstring(out, L"\\v"); break;
- case L'\f': put_cstring(out, L"\\f"); break;
- case L'\r': put_cstring(out, L"\\r"); break;
- case L'"': put_cstring(out, L"\\\""); break;
- case L'\\': put_cstring(out, L"\\\\"); break;
- case 27: put_cstring(out, L"\\e"); break;
+ case '\a': put_string(out, lit("\\a")); break;
+ case '\b': put_string(out, lit("\\b")); break;
+ case '\t': put_string(out, lit("\\t")); break;
+ case '\n': put_string(out, lit("\\n")); break;
+ case '\v': put_string(out, lit("\\v")); break;
+ case '\f': put_string(out, lit("\\f")); break;
+ case '\r': put_string(out, lit("\\r")); break;
+ case '"': put_string(out, lit("\\\"")); break;
+ case '\\': put_string(out, lit("\\\\")); break;
+ case 27: put_string(out, lit("\\e")); break;
default:
if (iswprint(*ptr))
- put_cchar(out, *ptr);
+ put_char(out, chr(*ptr));
else
- cformat(out, L"\\%03o", (int) *ptr);
+ format(out, lit("\\~03o"), num(*ptr), nao);
}
}
- put_cchar(out, '"');
+ put_char(out, chr('"'));
}
return;
case CHR:
{
- int ch = c_chr(obj);
+ wchar_t ch = c_chr(obj);
- put_cchar(out, '\'');
+ put_char(out, chr('\''));
switch (ch) {
- case L'\a': put_cstring(out, L"\\a"); break;
- case L'\b': put_cstring(out, L"\\b"); break;
- case L'\t': put_cstring(out, L"\\t"); break;
- case L'\n': put_cstring(out, L"\\n"); break;
- case L'\v': put_cstring(out, L"\\v"); break;
- case L'\f': put_cstring(out, L"\\f"); break;
- case L'\r': put_cstring(out, L"\\r"); break;
- case L'"': put_cstring(out, L"\\\""); break;
- case L'\\': put_cstring(out, L"\\\\"); break;
- case 27: put_cstring(out, L"\\e"); break;
+ case '\a': put_string(out, lit("\\a")); break;
+ case '\b': put_string(out, lit("\\b")); break;
+ case '\t': put_string(out, lit("\\t")); break;
+ case '\n': put_string(out, lit("\\n")); break;
+ case '\v': put_string(out, lit("\\v")); break;
+ case '\f': put_string(out, lit("\\f")); break;
+ case '\r': put_string(out, lit("\\r")); break;
+ case '"': put_string(out, lit("\\\"")); break;
+ case '\\': put_string(out, lit("\\\\")); break;
+ case 27: put_string(out, lit("\\e")); break;
default:
if (iswprint(ch))
- put_cchar(out, ch);
+ put_char(out, chr(ch));
else
- cformat(out, L"\\%03o", ch);
+ format(out, lit("\\~03o"), num(ch), nao);
}
- put_cchar(out, '\'');
+ put_char(out, chr('\''));
}
return;
case NUM:
- cformat(out, L"%ld", c_num(obj));
+ format(out, lit("~s"), obj, nao);
return;
case SYM:
put_string(out, symbol_name(obj));
return;
case FUN:
- cformat(out, L"#<function: f%d>", (int) obj->f.functype);
+ format(out, lit("#<function: f~a>"), num(obj->f.functype), nao);
return;
case VEC:
{
long i, fill = c_num(obj->v.vec[vec_fill]);
- put_cstring(out, L"#(");
+ put_string(out, lit("#("));
for (i = 0; i < fill; i++) {
obj_print(obj->v.vec[i], out);
if (i < fill - 1)
- put_cchar(out, ' ');
+ put_char(out, chr(' '));
}
- put_cchar(out, ')');
+ put_char(out, chr(')'));
}
return;
case LSTR:
obj_print(obj->ls.prefix, out);
- put_cstring(out, L"#<... lazy string>");
+ put_string(out, lit("#<... lazy string>"));
return;
case COBJ:
obj->co.ops->print(obj, out);
return;
}
- cformat(out, L"#<garbage: %p>", (void *) obj);
+ format(out, lit("#<garbage: ~p>"), (void *) obj, nao);
}
void obj_pprint(obj_t *obj, obj_t *out)
{
if (obj == nil) {
- put_cstring(out, L"nil");
+ put_string(out, lit("nil"));
return;
}
@@ -1965,21 +1965,22 @@ void obj_pprint(obj_t *obj, obj_t *out)
case LCONS:
{
obj_t *iter;
- put_cchar(out, '(');
+ put_char(out, chr('('));
for (iter = obj; consp(iter); iter = cdr(iter)) {
obj_pprint(car(iter), out);
if (nullp(cdr(iter))) {
- put_cchar(out, ')');
+ put_char(out, chr(')'));
} else if (consp(cdr(iter))) {
- put_cchar(out, ' ');
+ put_char(out, chr(' '));
} else {
- put_cstring(out, L" . ");
+ put_string(out, lit(" . "));
obj_pprint(cdr(iter), out);
- put_cchar(out, ')');
+ put_char(out, chr(')'));
}
}
}
return;
+ case LIT:
case STR:
put_string(out, obj);
return;
@@ -1987,36 +1988,36 @@ void obj_pprint(obj_t *obj, obj_t *out)
put_char(out, obj);
return;
case NUM:
- cformat(out, L"%ld", c_num(obj));
+ format(out, lit("~s"), obj, nao);
return;
case SYM:
put_string(out, symbol_name(obj));
return;
case FUN:
- cformat(out, L"#<function: f%d>", (int) obj->f.functype);
+ format(out, lit("#<function: f~a>"), num(obj->f.functype), nao);
return;
case VEC:
{
long i, fill = c_num(obj->v.vec[vec_fill]);
- put_cstring(out, L"#(");
+ put_string(out, lit("#("));
for (i = 0; i < fill; i++) {
obj_pprint(obj->v.vec[i], out);
if (i < fill - 1)
- put_cchar(out, ' ');
+ put_char(out, chr(' '));
}
- put_cchar(out, ')');
+ put_char(out, chr(')'));
}
return;
case LSTR:
obj_pprint(obj->ls.prefix, out);
- put_cstring(out, L"...");
+ put_string(out, lit("..."));
return;
case COBJ:
obj->co.ops->print(obj, out);
return;
}
- cformat(out, L"#<garbage: %p>", (void *) obj);
+ format(out, lit("#<garbage: ~p>"), (void *) obj, nao);
}
void init(const wchar_t *pn, void *(*oom)(void *, size_t),
@@ -2037,7 +2038,7 @@ void init(const wchar_t *pn, void *(*oom)(void *, size_t),
void dump(obj_t *obj, obj_t *out)
{
obj_print(obj, out);
- put_cchar(out, '\n');
+ put_char(out, chr('\n'));
}
/*
diff --git a/lib.h b/lib.h
index 4db6ebf8..47f33e1a 100644
--- a/lib.h
+++ b/lib.h
@@ -51,7 +51,10 @@ typedef enum functype
#define is_chr(obj) (tag(obj) == TAG_CHR)
#define is_lit(obj) (tag(obj) == TAG_LIT)
#define type(obj) (tag(obj) ? ((type_t) tag(obj)) : (obj)->t.type)
-#define lit(strlit) ((obj_t *) ((long) (L ## strlit) | TAG_LIT))
+#define lit_noex(strlit) ((obj_t *) ((long) (L ## strlit) | TAG_LIT))
+#define lit(strlit) lit_noex(strlit)
+#define auto_str(str) ((obj_t *) ((long) (str) | TAG_LIT))
+#define static_str(str) ((obj_t *) ((long) (str) | TAG_LIT))
#define litptr(obj) ((wchar_t *) ((long) obj & ~TAG_MASK))
typedef union obj obj_t;
diff --git a/match.c b/match.c
index 4e260705..ea028583 100644
--- a/match.c
+++ b/match.c
@@ -45,50 +45,39 @@
int output_produced;
-static void debugf(const wchar_t *fmt, ...)
+static void debugf(obj_t *fmt, ...)
{
if (opt_loglevel >= 2) {
va_list vl;
va_start (vl, fmt);
- format(std_error, L"~a: ", prog_string, nao);
+ format(std_error, lit("~a: "), prog_string, nao);
vformat(std_error, fmt, vl);
- put_cchar(std_error, '\n');
+ put_char(std_error, chr('\n'));
va_end (vl);
}
}
-static void debuglf(obj_t *line, const wchar_t *fmt, ...)
+static void debuglf(obj_t *line, obj_t *fmt, ...)
{
if (opt_loglevel >= 2) {
va_list vl;
va_start (vl, fmt);
- format(std_error, L"~a: (~a:~a) ", prog_string, spec_file_str, line, nao);
+ format(std_error, lit("~a: (~a:~a) "), prog_string,
+ spec_file_str, line, nao);
vformat(std_error, fmt, vl);
- put_cchar(std_error, '\n');
+ put_char(std_error, chr('\n'));
va_end (vl);
}
}
-static void debuglcf(obj_t *line, const wchar_t *fmt, ...)
-{
- if (opt_loglevel >= 2) {
- va_list vl;
- va_start (vl, fmt);
- format(std_error, L"~a: (~a:~a) ", prog_string, spec_file_str, line, nao);
- vcformat(std_error, fmt, vl);
- put_cchar(std_error, '\n');
- va_end (vl);
- }
-}
-
-static void sem_error(obj_t *line, const wchar_t *fmt, ...)
+static void sem_error(obj_t *line, obj_t *fmt, ...)
{
va_list vl;
obj_t *stream = make_string_output_stream();
va_start (vl, fmt);
if (line)
- format(stream, L"(~a:~a) ", spec_file_str, line, nao);
+ format(stream, lit("(~a:~a) "), spec_file_str, line, nao);
(void) vformat(stream, fmt, vl);
va_end (vl);
@@ -96,14 +85,14 @@ static void sem_error(obj_t *line, const wchar_t *fmt, ...)
abort();
}
-static void file_err(obj_t *line, const wchar_t *fmt, ...)
+static void file_err(obj_t *line, obj_t *fmt, ...)
{
va_list vl;
obj_t *stream = make_string_output_stream();
va_start (vl, fmt);
if (line)
- format(stream, L"(~a:~a) ", spec_file_str, line, nao);
+ format(stream, lit("(~a:~a) "), spec_file_str, line, nao);
(void) vformat(stream, fmt, vl);
va_end (vl);
@@ -243,7 +232,7 @@ obj_t *dest_bind(obj_t *bindings, obj_t *pattern, obj_t *value)
return bindings;
if (tree_find(cdr(existing), value))
return bindings;
- debugf(L"bind variable mismatch: ~a", pattern, nao);
+ debugf(lit("bind variable mismatch: ~a"), pattern, nao);
return t;
}
return cons(cons(pattern, value), bindings);
@@ -276,19 +265,19 @@ obj_t *match_line(obj_t *bindings, obj_t *specline, obj_t *dataline,
obj_t *file)
{
#define LOG_MISMATCH(KIND) \
- debuglf(spec_lineno, KIND L" mismatch, position ~a (~a:~a)", pos, \
+ debuglf(spec_lineno, lit(KIND " mismatch, position ~a (~a:~a)"), pos, \
file, data_lineno, nao); \
- debuglf(spec_lineno, L" ~a", dataline, nao); \
+ debuglf(spec_lineno, lit(" ~a"), dataline, nao); \
if (c_num(pos) < 77) \
- debuglcf(spec_lineno, L" %*ls^", (int) c_num(pos), L"")
+ debuglf(spec_lineno, lit(" ~*~a^"), pos, lit(""), nao)
#define LOG_MATCH(KIND, EXTENT) \
- debuglf(spec_lineno, KIND L" matched, position ~a-~a (~a:~a)", \
+ debuglf(spec_lineno, lit(KIND " matched, position ~a-~a (~a:~a)"), \
pos, EXTENT, file, data_lineno, nao); \
- debuglf(spec_lineno, L" ~a", dataline, nao); \
+ debuglf(spec_lineno, lit(" ~a"), dataline, nao); \
if (c_num(EXTENT) < 77) \
- debuglcf(spec_lineno, L" %*ls%-*ls^", (int) c_num(pos), \
- L"", (int) (c_num(EXTENT) - c_num(pos)), L"^")
+ debuglf(spec_lineno, lit(" ~*~a~-*~a^"), pos, lit(""), \
+ minus(EXTENT, pos), lit("^"), nao)
for (;;) {
obj_t *elem;
@@ -322,18 +311,18 @@ obj_t *match_line(obj_t *bindings, obj_t *specline, obj_t *dataline,
if (length_str_lt(dataline, past) || lt(past, pos))
{
- LOG_MISMATCH(L"fixed field size");
+ LOG_MISMATCH("fixed field size");
return nil;
}
if (!tree_find(trim_str(sub_str(dataline, pos, past)),
cdr(pair)))
{
- LOG_MISMATCH(L"fixed field contents");
+ LOG_MISMATCH("fixed field contents");
return nil;
}
- LOG_MATCH(L"fixed field", past);
+ LOG_MATCH("fixed field", past);
pos = past;
specline = cdr(specline);
} else {
@@ -344,20 +333,20 @@ obj_t *match_line(obj_t *bindings, obj_t *specline, obj_t *dataline,
if (consp(modifier)) {
obj_t *past = match_regex(dataline, car(modifier), pos);
if (nullp(past)) {
- LOG_MISMATCH(L"var positive regex");
+ LOG_MISMATCH("var positive regex");
return nil;
}
- LOG_MATCH(L"var positive regex", past);
+ LOG_MATCH("var positive regex", past);
bindings = acons_new(bindings, sym, sub_str(dataline, pos, past));
pos = past;
} else if (nump(modifier)) {
obj_t *past = plus(pos, modifier);
if (length_str_lt(dataline, past) || lt(past, pos))
{
- LOG_MISMATCH(L"count based var");
+ LOG_MISMATCH("count based var");
return nil;
}
- LOG_MATCH(L"count based var", past);
+ LOG_MATCH("count based var", past);
bindings = acons_new(bindings, sym, trim_str(sub_str(dataline, pos, past)));
pos = past;
} else {
@@ -367,10 +356,10 @@ obj_t *match_line(obj_t *bindings, obj_t *specline, obj_t *dataline,
} else if (type(pat) == STR) {
obj_t *find = search_str(dataline, pat, pos, modifier);
if (!find) {
- LOG_MISMATCH(L"var delimiting string");
+ LOG_MISMATCH("var delimiting string");
return nil;
}
- LOG_MATCH(L"var delimiting string", find);
+ LOG_MATCH("var delimiting string", find);
bindings = acons_new(bindings, sym, sub_str(dataline, pos, find));
pos = plus(find, length_str(pat));
} else if (consp(pat) && typeof(first(pat)) == regex) {
@@ -378,10 +367,10 @@ obj_t *match_line(obj_t *bindings, obj_t *specline, obj_t *dataline,
obj_t *fpos = car(find);
obj_t *flen = cdr(find);
if (!find) {
- LOG_MISMATCH(L"var delimiting regex");
+ LOG_MISMATCH("var delimiting regex");
return nil;
}
- LOG_MATCH(L"var delimiting regex", fpos);
+ LOG_MATCH("var delimiting regex", fpos);
bindings = acons_new(bindings, sym, sub_str(dataline, pos, fpos));
pos = plus(fpos, flen);
} else if (consp(pat) && first(pat) == var) {
@@ -391,7 +380,7 @@ obj_t *match_line(obj_t *bindings, obj_t *specline, obj_t *dataline,
obj_t *pair = assoc(bindings, second_sym); /* var exists already? */
if (!pair)
- sem_error(spec_lineno, L"consecutive unbound variables", nao);
+ sem_error(spec_lineno, lit("consecutive unbound variables"), nao);
/* Re-generate a new spec with an edited version of
the element we just processed, and repeat. */
@@ -408,14 +397,14 @@ obj_t *match_line(obj_t *bindings, obj_t *specline, obj_t *dataline,
} else if (consp(pat) && (consp(first(pat)) || stringp(first(pat)))) {
cons_bind (find, len, search_str(dataline, pat, pos, modifier));
if (!find) {
- LOG_MISMATCH(L"string");
+ LOG_MISMATCH("string");
return nil;
}
bindings = acons_new(bindings, sym, sub_str(dataline, pos, find));
pos = plus(find, len);
} else {
sem_error(spec_lineno,
- L"variable followed by invalid element", nao);
+ lit("variable followed by invalid element"), nao);
}
} else if (typeof(directive) == regex) {
obj_t *past = match_regex(dataline, directive, pos);
@@ -477,7 +466,7 @@ obj_t *match_line(obj_t *bindings, obj_t *specline, obj_t *dataline,
if (!bindings_coll) {
- debuglf(spec_lineno, L"nothing was collected", nao);
+ debuglf(spec_lineno, lit("nothing was collected"), nao);
return nil;
}
@@ -491,15 +480,15 @@ obj_t *match_line(obj_t *bindings, obj_t *specline, obj_t *dataline,
obj_t *newpos;
if (find == nil || !equal(find, pos)) {
- LOG_MISMATCH(L"string tree");
+ LOG_MISMATCH("string tree");
return nil;
}
newpos = plus(find, len);
- LOG_MATCH(L"string tree", newpos);
+ LOG_MATCH("string tree", newpos);
pos = newpos;
} else {
- sem_error(spec_lineno, L"unknown directive: ~a", directive, nao);
+ sem_error(spec_lineno, lit("unknown directive: ~a"), directive, nao);
}
}
break;
@@ -517,7 +506,7 @@ obj_t *match_line(obj_t *bindings, obj_t *specline, obj_t *dataline,
break;
}
default:
- sem_error(spec_lineno, L"unsupported object in spec: ~s", elem, nao);
+ sem_error(spec_lineno, lit("unsupported object in spec: ~s"), elem, nao);
}
specline = cdr(specline);
@@ -698,6 +687,21 @@ obj_t *complex_snarf(fpip_t fp, obj_t *name)
internal_error("bad input source type");
}
+obj_t *complex_stream(fpip_t fp, obj_t *name)
+{
+ switch (fp.close) {
+ case fpip_fclose:
+ return make_stdio_stream(fp.f, name, t, nil);
+ case fpip_pclose:
+ return make_pipe_stream(fp.f, name, t, nil);
+ case fpip_closedir:
+ uw_throwf(query_error, lit("cannot output to directory: ~a"), name, nao);
+ }
+
+ internal_error("bad input source type");
+}
+
+
obj_t *robust_length(obj_t *obj)
{
if (obj == nil)
@@ -750,7 +754,7 @@ obj_t *extract_bindings(obj_t *bindings, obj_t *output_spec)
}
void do_output_line(obj_t *bindings, obj_t *specline,
- obj_t *spec_lineno, FILE *out)
+ obj_t *spec_lineno, obj_t *out)
{
for (; specline; specline = rest(specline)) {
obj_t *elem = first(specline);
@@ -763,8 +767,9 @@ void do_output_line(obj_t *bindings, obj_t *specline,
if (directive == var) {
obj_t *str = cat_str(subst_vars(cons(elem, nil), bindings), nil);
if (str == nil)
- sem_error(spec_lineno, L"bad substitution: ~a", second(elem), nao);
- fputws(c_str(str), out);
+ sem_error(spec_lineno, lit("bad substitution: ~a"),
+ second(elem), nao);
+ put_string(out, str);
} else if (directive == rep) {
obj_t *main_clauses = second(elem);
obj_t *single_clauses = third(elem);
@@ -803,22 +808,23 @@ void do_output_line(obj_t *bindings, obj_t *specline,
}
} else {
- sem_error(spec_lineno, L"unknown directive: ~a", directive, nao);
+ sem_error(spec_lineno, lit("unknown directive: ~a"), directive, nao);
}
}
break;
case STR:
- fputws(c_str(elem), out);
+ put_string(out, elem);
break;
case 0:
break;
default:
- sem_error(spec_lineno, L"unsupported object in output spec: ~s", elem);
+ sem_error(spec_lineno,
+ lit("unsupported object in output spec: ~s"), elem, nao);
}
}
}
-void do_output(obj_t *bindings, obj_t *specs, FILE *out)
+void do_output(obj_t *bindings, obj_t *specs, obj_t *out)
{
if (equal(specs, null_list))
return;
@@ -871,7 +877,7 @@ void do_output(obj_t *bindings, obj_t *specs, FILE *out)
}
do_output_line(bindings, specline, spec_lineno, out);
- putwc('\n', out);
+ put_char(out, chr('\n'));
}
}
@@ -893,21 +899,21 @@ obj_t *match_files(obj_t *spec, obj_t *files,
obj_t *first_spec_item = second(first(spec));
if (consp(first_spec_item) && eq(first(first_spec_item), next)) {
- debugf(L"not opening source ~a since query starts with next directive",
- name, nao);
+ debugf(lit("not opening source ~a "
+ "since query starts with next directive"), name, nao);
} else {
- debugf(L"opening data source ~a", name, nao);
+ debugf(lit("opening data source ~a"), name, nao);
if (complex_open_failed(fp)) {
if (consp(source_spec) && car(source_spec) == nothrow) {
- debugf(L"could not open ~a: treating as failed match due to nothrow",
- name, nao);
+ debugf(lit("could not open ~a: "
+ "treating as failed match due to nothrow"), name, nao);
return nil;
} else if (errno != 0)
- file_err(nil, L"could not open ~a (error ~a/~a)", name,
+ file_err(nil, lit("could not open ~a (error ~a/~a)"), name,
num(errno), string_utf8(strerror(errno)), nao);
else
- file_err(nil, L"could not open ~a", name, nao);
+ file_err(nil, lit("could not open ~a"), name, nao);
return nil;
}
@@ -936,7 +942,7 @@ repeat_spec_same_data:
if (rest(specline))
sem_error(spec_linenum,
- L"unexpected material after skip directive", nao);
+ lit("unexpected material after skip directive"), nao);
if ((spec = rest(spec)) == nil)
break;
@@ -949,12 +955,12 @@ repeat_spec_same_data:
data, num(data_lineno));
if (result) {
- debuglf(spec_linenum, L"skip matched ~a:~a", first(files),
+ debuglf(spec_linenum, lit("skip matched ~a:~a"), first(files),
num(data_lineno), nao);
break;
}
- debuglf(spec_linenum, L"skip didn't match ~a:~a", first(files),
+ debuglf(spec_linenum, lit("skip didn't match ~a:~a"), first(files),
num(data_lineno), nao);
data = rest(data);
data_lineno++;
@@ -967,12 +973,12 @@ repeat_spec_same_data:
return result;
}
- debuglf(spec_linenum, L"skip failed", nao);
+ debuglf(spec_linenum, lit("skip failed"), nao);
return nil;
} else if (sym == trailer) {
if (rest(specline))
sem_error(spec_linenum,
- L"unexpected material after trailer directive", nao);
+ lit("unexpected material after trailer directive"), nao);
if ((spec = rest(spec)) == nil)
break;
@@ -994,7 +1000,7 @@ repeat_spec_same_data:
if ((spec = rest(spec)) == nil) {
sem_error(spec_linenum,
- L"freeform must be followed by a query line", nao);
+ lit("freeform must be followed by a query line"), nao);
} else {
obj_t *limit = or2(if2(nump(first(vals)), first(vals)),
if2(nump(second(vals)), second(vals)));
@@ -1008,7 +1014,7 @@ repeat_spec_same_data:
spec_linenum, num(data_lineno), first(files)));
if (!success) {
- debuglf(spec_linenum, L"freeform match failure", nao);
+ debuglf(spec_linenum, lit("freeform match failure"), nao);
return nil;
}
@@ -1026,7 +1032,7 @@ repeat_spec_same_data:
obj_t *name = first(rest(first_spec));
if (rest(specline))
sem_error(spec_linenum,
- L"unexpected material after block directive", nao);
+ lit("unexpected material after block directive"), nao);
if ((spec = rest(spec)) == nil)
break;
{
@@ -1039,7 +1045,7 @@ repeat_spec_same_data:
obj_t *target = first(rest(first_spec));
if (rest(specline))
- sem_error(spec_linenum, L"unexpected material after ~a", sym, nao);
+ sem_error(spec_linenum, lit("unexpected material after ~a"), sym, nao);
uw_block_return(target,
if2(sym == accept,
@@ -1047,15 +1053,16 @@ repeat_spec_same_data:
if3(data, cons(data, num(data_lineno)), t))));
/* TODO: uw_block_return could just throw this */
if (target)
- sem_error(spec_linenum, L"~a: no block named ~a in scope",
+ sem_error(spec_linenum, lit("~a: no block named ~a in scope"),
sym, target, nao);
else
- sem_error(spec_linenum, L"%~a: no anonymous block in scope", sym, nao);
+ sem_error(spec_linenum, lit("%~a: no anonymous block in scope"),
+ sym, nao);
return nil;
} else if (sym == next) {
if (rest(first_spec) && rest(specline))
- sem_error(spec_linenum,
- L"invalid combination of old and new next syntax", nao);
+ sem_error(spec_linenum, lit("invalid combination of old "
+ "and new next syntax"), nao);
if ((spec = rest(spec)) == nil)
break;
@@ -1081,7 +1088,7 @@ repeat_spec_same_data:
obj_t *name = cdr(val);
if (!val)
- sem_error(spec_linenum, L"next: unbound variable in form ~a",
+ sem_error(spec_linenum, lit("next: unbound variable in form ~a"),
first(source), nao);
if (eq(second(source), nothrow)) {
@@ -1090,7 +1097,7 @@ repeat_spec_same_data:
} else {
files = rest(files);
if (!files) {
- debuglf(spec_linenum, L"next: out of arguments", nao);
+ debuglf(spec_linenum, lit("next: out of arguments"), nao);
return nil;
}
files = cons(cons(nothrow, first(files)), rest(files));
@@ -1101,7 +1108,7 @@ repeat_spec_same_data:
} else {
files = rest(files);
if (!files)
- sem_error(spec_linenum, L"next: out of arguments", nao);
+ sem_error(spec_linenum, lit("next: out of arguments"), nao);
files = cons(cons(nothrow, first(files)), rest(files));
}
}
@@ -1110,14 +1117,15 @@ repeat_spec_same_data:
obj_t *sub = subst_vars(rest(specline), bindings);
obj_t *str = cat_str(sub, nil);
if (str == nil) {
- sem_error(spec_linenum, L"bad substitution in next file spec", nao);
+ sem_error(spec_linenum, lit("bad substitution in next file spec"),
+ nao);
continue;
}
files = cons(cons(nothrow, str), files);
} else {
files = rest(files);
if (!files)
- sem_error(spec_linenum, L"next: out of arguments", nao);
+ sem_error(spec_linenum, lit("next: out of arguments"), nao);
}
/* We recursively process the file list, but the new
@@ -1171,17 +1179,17 @@ repeat_spec_same_data:
}
if (sym == all && !all_match) {
- debuglf(spec_linenum, L"all: some clauses didn't match", nao);
+ debuglf(spec_linenum, lit("all: some clauses didn't match"), nao);
return nil;
}
if ((sym == some || sym == cases) && !some_match) {
- debuglf(spec_linenum, L"some/cases: no clauses matched", nao);
+ debuglf(spec_linenum, lit("some/cases: no clauses matched"), nao);
return nil;
}
if (sym == none && some_match) {
- debuglf(spec_linenum, L"none: some clauses matched", nao);
+ debuglf(spec_linenum, lit("none: some clauses matched"), nao);
return nil;
}
@@ -1227,8 +1235,8 @@ repeat_spec_same_data:
}
if (success) {
- debuglcf(spec_linenum, L"collect matched %ls:%ld",
- c_str(first(files)), data_lineno);
+ debuglf(spec_linenum, lit("collect matched ~a:~a"),
+ first(files), num(data_lineno), nao);
for (iter = new_bindings; iter && iter != bindings;
iter = cdr(iter))
@@ -1253,14 +1261,13 @@ repeat_spec_same_data:
new_lineno++;
}
- debuglcf(spec_linenum,
- L"collect advancing from line %ld to %ld",
- data_lineno, new_lineno);
+ debuglf(spec_linenum, lit("collect advancing from line ~a to ~a"),
+ num(data_lineno), num(new_lineno), nao);
data = new_data;
data_lineno = new_lineno;
} else {
- debuglf(spec_linenum, L"collect consumed entire file", nao);
+ debuglf(spec_linenum, lit("collect consumed entire file"), nao);
data = nil;
}
} else {
@@ -1272,12 +1279,12 @@ repeat_spec_same_data:
uw_block_end;
if (!result) {
- debuglf(spec_linenum, L"collect explicitly failed", nao);
+ debuglf(spec_linenum, lit("collect explicitly failed"), nao);
return nil;
}
if (!bindings_coll) {
- debuglf(spec_linenum, L"nothing was collected", nao);
+ debuglf(spec_linenum, lit("nothing was collected"), nao);
return nil;
}
@@ -1298,7 +1305,8 @@ repeat_spec_same_data:
obj_t *sym = first(iter);
if (!symbolp(sym)) {
- sem_error(spec_linenum, L"non-symbol in flatten directive", nao);
+ sem_error(spec_linenum, lit("non-symbol in flatten directive"),
+ nao);
} else {
obj_t *existing = assoc(bindings, sym);
@@ -1324,7 +1332,7 @@ repeat_spec_same_data:
obj_t *merged = nil;
if (!target || !symbolp(target))
- sem_error(spec_linenum, L"bad merge directive", nao);
+ sem_error(spec_linenum, lit("bad merge directive"), nao);
for (; args; args = rest(args)) {
obj_t *other_sym = first(args);
@@ -1333,9 +1341,10 @@ repeat_spec_same_data:
obj_t *other_lookup = assoc(bindings, other_sym);
if (!symbolp(other_sym))
- sem_error(spec_linenum, L"non-symbol in merge directive", nao);
+ sem_error(spec_linenum, lit("non-symbol in merge directive"),
+ nao);
else if (!other_lookup)
- sem_error(spec_linenum, L"merge: nonexistent symbol ~a",
+ sem_error(spec_linenum, lit("merge: nonexistent symbol ~a"),
other_sym, nao);
if (merged)
@@ -1358,7 +1367,8 @@ repeat_spec_same_data:
obj_t *val = eval_form(form, bindings);
if (!val)
- sem_error(spec_linenum, L"bind: unbound variable on right side", nao);
+ sem_error(spec_linenum, lit("bind: unbound variable on right side"),
+ nao);
bindings = dest_bind(bindings, pattern, cdr(val));
@@ -1376,7 +1386,7 @@ repeat_spec_same_data:
obj_t *sym = first(iter);
if (!symbolp(sym)) {
- sem_error(spec_linenum, L"non-symbol in cat directive", nao);
+ sem_error(spec_linenum, lit("non-symbol in cat directive"), nao);
} else {
obj_t *existing = assoc(bindings, sym);
obj_t *sep = nil;
@@ -1413,8 +1423,8 @@ repeat_spec_same_data:
obj_t *val = eval_form(form, bindings);
if (!val)
- sem_error(spec_linenum, L"output: unbound variable in form ~a",
- form, nao);
+ sem_error(spec_linenum,
+ lit("output: unbound variable in form ~a"), form, nao);
nt = eq(second(new_style_dest), nothrow);
dest = or2(cdr(val), string(L"-"));
@@ -1423,22 +1433,23 @@ repeat_spec_same_data:
fpip_t fp = (errno = 0, complex_open(dest, t));
- debugf(L"opening data sink ~a", dest, nao);
+ debugf(lit("opening data sink ~a"), dest, nao);
if (complex_open_failed(fp)) {
if (nt) {
- debugf(L"could not open ~a: treating as failed match due to nothrow",
- dest, nao);
+ debugf(lit("could not open ~a: "
+ "treating as failed match due to nothrow"), dest, nao);
return nil;
} else if (errno != 0) {
- file_err(nil, L"could not open ~a (error ~a/~a)", dest,
+ file_err(nil, lit("could not open ~a (error ~a/~a)"), dest,
num(errno), string_utf8(strerror(errno)), nao);
} else {
- file_err(nil, L"could not open ~a", dest, nao);
+ file_err(nil, lit("could not open ~a"), dest, nao);
}
} else {
- do_output(bindings, specs, fp.f);
- complex_close(fp);
+ obj_t *stream = complex_stream(fp, dest);
+ do_output(bindings, specs, stream);
+ close_stream(stream, t);
}
if ((spec = rest(spec)) == nil)
@@ -1452,7 +1463,8 @@ repeat_spec_same_data:
obj_t *params = second(args);
if (rest(specline))
- sem_error(spec_linenum, L"unexpected material after define", nao);
+ sem_error(spec_linenum,
+ lit("unexpected material after define"), nao);
uw_set_func(name, cons(params, body));
@@ -1595,7 +1607,8 @@ repeat_spec_same_data:
} else if (sym == defex) {
obj_t *types = rest(first_spec);
if (!all_satisfy(types, func_n1(symbolp), nil))
- sem_error(spec_linenum, L"defex arguments must all be symbols", nao);
+ sem_error(spec_linenum, lit("defex arguments must all be symbols"),
+ nao);
(void) reduce_left(func_n2(uw_register_subtype), types, nil, nil);
if ((spec = rest(spec)) == nil)
break;
@@ -1604,7 +1617,7 @@ repeat_spec_same_data:
obj_t *type = second(first_spec);
obj_t *args = rest(rest(first_spec));
if (!symbolp(type))
- sem_error(spec_linenum, L"throw: ~a is not a type symbol",
+ sem_error(spec_linenum, lit("throw: ~a is not a type symbol"),
first(first_spec), nao);
{
obj_t *values = mapcar(bind2other(func_n2(eval_form), bindings),
@@ -1623,7 +1636,7 @@ repeat_spec_same_data:
obj_t *bindings_cp = copy_alist(bindings);
if (!equal(length(args), length(params)))
- sem_error(spec_linenum, L"function ~a takes ~a argument(s)",
+ sem_error(spec_linenum, lit("function ~a takes ~a argument(s)"),
sym, length(params), nao);
for (piter = params, aiter = args; piter;
@@ -1646,7 +1659,8 @@ repeat_spec_same_data:
obj_t *val = eval_form(arg, bindings);
if (!val)
sem_error(spec_linenum,
- L"unbound variable in function argument form", nao);
+ lit("unbound variable in function argument form"),
+ nao);
bindings_cp = acons_new(bindings_cp, param, cdr(val));
}
}
@@ -1660,7 +1674,7 @@ repeat_spec_same_data:
uw_block_end;
if (!result) {
- debuglf(spec_linenum, L"function failed", nao);
+ debuglf(spec_linenum, lit("function failed"), nao);
return nil;
}
@@ -1676,8 +1690,9 @@ repeat_spec_same_data:
if (newbind) {
bindings = dest_bind(bindings, arg, cdr(newbind));
if (bindings == t) {
- debuglf(spec_linenum, L"binding mismatch on ~a "
- L"when returning from ~a", arg, sym, nao);
+ debuglf(spec_linenum,
+ lit("binding mismatch on ~a "
+ "when returning from ~a"), arg, sym, nao);
return nil;
}
}
@@ -1685,13 +1700,15 @@ repeat_spec_same_data:
}
if (consp(success)) {
- debuglcf(spec_linenum,
- L"function matched; advancing from line %ld to %ld",
- data_lineno, c_num(cdr(success)));
+ debuglf(spec_linenum,
+ lit("function matched; "
+ "advancing from line ~a to ~a"),
+ num(data_lineno), cdr(success), nao);
data = car(success);
data_lineno = c_num(cdr(success));
} else {
- debuglf(spec_linenum, L"function consumed entire file", nao);
+ debuglf(spec_linenum, lit("function consumed entire file"),
+ nao);
data = nil;
}
}
@@ -1714,7 +1731,7 @@ repeat_spec_same_data:
spec_linenum, num(data_lineno), first(files)));
if (nump(success) && c_num(success) < c_num(length_str(dataline))) {
- debuglf(spec_linenum, L"spec only matches line to position ~a: ~a",
+ debuglf(spec_linenum, lit("spec only matches line to position ~a: ~a"),
success, dataline, nao);
return nil;
}
@@ -1743,7 +1760,7 @@ int extract(obj_t *spec, obj_t *files, obj_t *predefined_bindings)
}
if (!success)
- fputws(L"false", stdout);
+ put_line(std_output, lit("false"));
}
return success ? 0 : EXIT_FAILURE;
diff --git a/parser.h b/parser.h
index 38d0ad3f..85f0f582 100644
--- a/parser.h
+++ b/parser.h
@@ -32,5 +32,5 @@ extern const wchar_t *spec_file;
extern obj_t *spec_file_str;
int yyparse(void);
obj_t *get_spec(void);
-void yyerrorf(const wchar_t *s, ...);
+void yyerrorf(obj_t *s, ...);
void yybadtoken(int tok, const char *context);
diff --git a/parser.l b/parser.l
index 39392d7f..4d48c238 100644
--- a/parser.l
+++ b/parser.l
@@ -67,17 +67,17 @@ int errors;
void yyerror(const char *s)
{
- yyerrorf(L"%s", s);
+ yyerrorf(lit("~a"), auto_str(s), nao);
}
-void yyerrorf(const wchar_t *s, ...)
+void yyerrorf(obj_t *fmt, ...)
{
if (opt_loglevel >= 1) {
va_list vl;
- va_start (vl, s);
- fwprintf(stderr, L"%ls: (%ls:%ld): ", progname, spec_file, lineno);
- vfwprintf(stderr, s, vl);
- putwc('\n', stderr);
+ va_start (vl, fmt);
+ format(std_error, lit("~a: (~a:~a): "), progname, spec_file, lineno);
+ vformat(std_error, fmt, vl);
+ put_char(std_error, chr('\n'));
va_end (vl);
}
errors++;
@@ -85,48 +85,48 @@ void yyerrorf(const wchar_t *s, ...)
void yybadtoken(int tok, const char *context)
{
- const wchar_t *problem = 0;
+ const obj_t *problem = nil;
switch (tok) {
- case TEXT: problem = L"text"; break;
- case IDENT: problem = L"identifier"; break;
- case ALL: problem = L"\"all\""; break;
- case SOME: problem = L"\"some\""; break;
- case NONE: problem = L"\"none\""; break;
- case MAYBE: problem = L"\"maybe\""; break;
- case CASES: problem = L"\"cases\""; break;
- case AND: problem = L"\"and\""; break;
- case OR: problem = L"\"or\""; break;
- case END: problem = L"\"end\""; break;
- case COLLECT: problem = L"\"collect\""; break;
- case UNTIL: problem = L"\"until\""; break;
- case COLL: problem = L"\"coll\""; break;
- case OUTPUT: problem = L"\"output\""; break;
- case REPEAT: problem = L"\"repeat\""; break;
- case REP: problem = L"\"rep\""; break;
- case SINGLE: problem = L"\"single\""; break;
- case FIRST: problem = L"\"first\""; break;
- case LAST: problem = L"\"last\""; break;
- case EMPTY: problem = L"\"empty\""; break;
- case DEFINE: problem = L"\"define\""; break;
- case TRY: problem = L"\"try\""; break;
- case CATCH: problem = L"\"catch\""; break;
- case FINALLY: problem = L"\"finally\""; break;
- case NUMBER: problem = L"\"number\""; break;
- case REGCHAR: problem = L"regular expression character"; break;
- case LITCHAR: problem = L"string literal character"; break;
+ case TEXT: problem = lit("text"); break;
+ case IDENT: problem = lit("identifier"); break;
+ case ALL: problem = lit("\"all\""); break;
+ case SOME: problem = lit("\"some\""); break;
+ case NONE: problem = lit("\"none\""); break;
+ case MAYBE: problem = lit("\"maybe\""); break;
+ case CASES: problem = lit("\"cases\""); break;
+ case AND: problem = lit("\"and\""); break;
+ case OR: problem = lit("\"or\""); break;
+ case END: problem = lit("\"end\""); break;
+ case COLLECT: problem = lit("\"collect\""); break;
+ case UNTIL: problem = lit("\"until\""); break;
+ case COLL: problem = lit("\"coll\""); break;
+ case OUTPUT: problem = lit("\"output\""); break;
+ case REPEAT: problem = lit("\"repeat\""); break;
+ case REP: problem = lit("\"rep\""); break;
+ case SINGLE: problem = lit("\"single\""); break;
+ case FIRST: problem = lit("\"first\""); break;
+ case LAST: problem = lit("\"last\""); break;
+ case EMPTY: problem = lit("\"empty\""); break;
+ case DEFINE: problem = lit("\"define\""); break;
+ case TRY: problem = lit("\"try\""); break;
+ case CATCH: problem = lit("\"catch\""); break;
+ case FINALLY: problem = lit("\"finally\""); break;
+ case NUMBER: problem = lit("\"number\""); break;
+ case REGCHAR: problem = lit("regular expression character"); break;
+ case LITCHAR: problem = lit("string literal character"); break;
}
if (problem != 0)
if (context)
- yyerrorf(L"misplaced %ls in %ls", problem, context);
+ yyerrorf(lit("misplaced ~a in ~a"), problem, context, nao);
else
- yyerrorf(L"unexpected %ls", problem);
+ yyerrorf(lit("unexpected ~a"), problem, nao);
else
if (context)
- yyerrorf(L"unterminated %ls", context);
+ yyerrorf(lit("unterminated ~a"), context, nao);
else
- yyerrorf(L"unexpected end of input");
+ yyerrorf(lit("unexpected end of input"), nao);
}
static wchar_t char_esc(int letter)
@@ -396,12 +396,14 @@ UONLY {U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U}
}
<SPECIAL,NESTED>{UANYN} {
- yyerrorf(L"bad character in directive: '%s'", yytext);
+ yyerrorf(lit("bad character in directive: '~a'"),
+ string_utf8(yytext), nao);
}
<SPECIAL,NESTED>. {
- yyerrorf(L"non-UTF-8 byte in directive: '\\x%02x'",
- (unsigned char) yytext[0]);
+ yyerrorf(lit("non-UTF-8 byte in directive: "
+ "'\\x~02x'"),
+ num((unsigned char) yytext[0]), nao);
}
<REGEX>[/] {
@@ -458,8 +460,8 @@ UONLY {U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U}
}
<REGEX>. {
- yyerrorf(L"non-UTF-8 byte in regex: '\\x%02x'",
- (unsigned char) yytext[0]);
+ yyerrorf(lit("non-UTF-8 byte in regex: '\\x~02x'"),
+ num((unsigned char) yytext[0]), nao);
}
<INITIAL>({UONLY}|[^@\n])+ {
@@ -547,8 +549,8 @@ UONLY {U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U}
}
<STRLIT,CHRLIT,QSILIT>. {
- yyerrorf(L"non-UTF-8 byte in literal: '\\x%02x'",
- (unsigned char) yytext[0]);
+ yyerrorf(lit("non-UTF-8 byte in regex: '\\x~02x'"),
+ num((unsigned char) yytext[0]), nao);
}
%%
diff --git a/stream.c b/stream.c
index 7d31c89d..1546ff50 100644
--- a/stream.c
+++ b/stream.c
@@ -50,13 +50,11 @@ obj_t *std_input, *std_output, *std_error;
struct strm_ops {
struct cobj_ops cobj_ops;
- obj_t *(*put_string)(obj_t *, const wchar_t *);
- obj_t *(*put_char)(obj_t *, wchar_t);
+ obj_t *(*put_string)(obj_t *, obj_t *);
+ obj_t *(*put_char)(obj_t *, obj_t *);
obj_t *(*get_line)(obj_t *);
obj_t *(*get_char)(obj_t *);
obj_t *(*get_byte)(obj_t *);
- obj_t *(*vcformat)(obj_t *, const wchar_t *fmt, va_list vl);
- obj_t *(*vformat)(obj_t *, const wchar_t *fmt, va_list vl);
obj_t *(*close)(obj_t *, obj_t *);
};
@@ -70,47 +68,6 @@ static void common_destroy(obj_t *obj)
(void) close_stream(obj, nil);
}
-obj_t *common_vformat(obj_t *stream, const wchar_t *fmt, va_list vl)
-{
- wchar_t ch;
-
- for (; (ch = *fmt) != 0; fmt++) {
- obj_t *obj;
-
- if (ch == '~') {
- ch = *++fmt;
- if (ch == 0)
- abort();
- switch (ch) {
- case '~':
- put_cchar(stream, ch);
- continue;
- case 'a':
- obj = va_arg(vl, obj_t *);
- if (obj == nao)
- abort();
- obj_pprint(obj, stream);
- continue;
- case 's':
- obj = va_arg(vl, obj_t *);
- if (obj == nao)
- abort();
- obj_print(obj, stream);
- continue;
- default:
- abort();
- }
- continue;
- }
-
- put_cchar(stream, ch);
- }
-
- if (va_arg(vl, obj_t *) != nao)
- internal_error("unterminated format argument list");
- return t;
-}
-
struct stdio_handle {
FILE *f;
#ifdef BROKEN_POPEN_GETWC
@@ -122,7 +79,7 @@ struct stdio_handle {
void stdio_stream_print(obj_t *stream, obj_t *out)
{
struct stdio_handle *h = (struct stdio_handle *) stream->co.handle;
- format(out, L"#<~s ~s>", stream->co.cls, h->descr, nao);
+ format(out, lit("#<~s ~s>"), stream->co.cls, h->descr, nao);
}
void stdio_stream_destroy(obj_t *stream)
@@ -143,8 +100,8 @@ static obj_t *stdio_maybe_read_error(obj_t *stream)
struct stdio_handle *h = (struct stdio_handle *) stream->co.handle;
if (ferror(h->f)) {
clearerr(h->f);
- uw_throwf(file_error, L"error reading ~a: ~a/~s",
- stream, num(errno), string_utf8(strerror(errno)));
+ uw_throwf(file_error, lit("error reading ~a: ~a/~s"),
+ stream, num(errno), string_utf8(strerror(errno)), nao);
}
return nil;
}
@@ -154,22 +111,23 @@ static obj_t *stdio_maybe_write_error(obj_t *stream)
struct stdio_handle *h = (struct stdio_handle *) stream->co.handle;
if (ferror(h->f)) {
clearerr(h->f);
- uw_throwf(file_error, L"error writing ~a: ~a/~s",
- stream, num(errno), string_utf8(strerror(errno)));
+ uw_throwf(file_error, lit("error writing ~a: ~a/~s"),
+ stream, num(errno), string_utf8(strerror(errno)), nao);
}
return nil;
}
-static obj_t *stdio_put_string(obj_t *stream, const wchar_t *s)
+static obj_t *stdio_put_string(obj_t *stream, obj_t *s)
{
struct stdio_handle *h = (struct stdio_handle *) stream->co.handle;
- return (h->f && fputws(s, h->f) != -1) ? t : stdio_maybe_write_error(stream);
+ return (h->f && fputws(c_str(s), h->f) != -1)
+ ? t : stdio_maybe_write_error(stream);
}
-static obj_t *stdio_put_char(obj_t *stream, wchar_t ch)
+static obj_t *stdio_put_char(obj_t *stream, obj_t *ch)
{
struct stdio_handle *h = (struct stdio_handle *) stream->co.handle;
- return (h->f && putwc(ch, h->f) != WEOF)
+ return (h->f && putwc(c_chr(ch), h->f) != WEOF)
? t : stdio_maybe_write_error(stream);
}
@@ -238,17 +196,6 @@ obj_t *stdio_get_byte(obj_t *stream)
return nil;
}
-obj_t *stdio_vcformat(obj_t *stream, const wchar_t *fmt, va_list vl)
-{
- struct stdio_handle *h = (struct stdio_handle *) stream->co.handle;
-
- if (h->f) {
- int n = vfwprintf(h->f, fmt, vl);
- return (n >= 0) ? num(n) : stdio_maybe_write_error(stream);
- }
- return nil;
-}
-
static obj_t *stdio_close(obj_t *stream, obj_t *throw_on_error)
{
struct stdio_handle *h = (struct stdio_handle *) stream->co.handle;
@@ -257,8 +204,8 @@ static obj_t *stdio_close(obj_t *stream, obj_t *throw_on_error)
int result = fclose(h->f);
h->f = 0;
if (result == EOF && throw_on_error) {
- uw_throwf(file_error, L"error closing ~a: ~a/~s",
- stream, num(errno), string_utf8(strerror(errno)));
+ uw_throwf(file_error, lit("error closing ~a: ~a/~s"),
+ stream, num(errno), string_utf8(strerror(errno)), nao);
}
return result != EOF ? t : nil;
}
@@ -275,8 +222,6 @@ static struct strm_ops stdio_ops = {
stdio_get_line,
stdio_get_char,
stdio_get_byte,
- stdio_vcformat,
- common_vformat,
stdio_close
};
@@ -296,22 +241,23 @@ static obj_t *pipe_close(obj_t *stream, obj_t *throw_on_error)
if (status != 0 && throw_on_error) {
if (status < 0) {
uw_throwf(process_error,
- L"unable to obtain status of command ~a: ~a/~s",
+ lit("unable to obtain status of command ~a: ~a/~s"),
stream, num(errno), string_utf8(strerror(errno)), nao);
} else if (WIFEXITED(status)) {
int exitstatus = WEXITSTATUS(status);
- uw_throwf(process_error, L"pipe ~a terminated with status ~a",
+ uw_throwf(process_error, lit("pipe ~a terminated with status ~a"),
stream, num(exitstatus), nao);
} else if (WIFSIGNALED(status)) {
int termsig = WTERMSIG(status);
- uw_throwf(process_error, L"pipe ~a terminated by signal ~a",
+ uw_throwf(process_error, lit("pipe ~a terminated by signal ~a"),
stream, num(termsig), nao);
} else if (WIFSTOPPED(status) || WIFCONTINUED(status)) {
- uw_throwf(process_error, L"processes of closed pipe ~a still running",
+ uw_throwf(process_error,
+ lit("processes of closed pipe ~a still running"),
stream, nao);
} else {
- uw_throwf(file_error, L"strange status in when closing pipe ~a",
+ uw_throwf(file_error, lit("strange status in when closing pipe ~a"),
stream, nao);
}
}
@@ -331,8 +277,6 @@ static struct strm_ops pipe_ops = {
stdio_get_line,
stdio_get_char,
stdio_get_byte,
- stdio_vcformat,
- common_vformat,
pipe_close
};
@@ -382,8 +326,6 @@ static struct strm_ops string_in_ops = {
string_in_get_line,
string_in_get_char,
0,
- 0,
- 0,
0
};
@@ -412,8 +354,6 @@ static struct strm_ops byte_in_ops = {
0,
0,
byte_in_get_byte,
- 0,
- 0,
0
};
@@ -436,14 +376,15 @@ static void string_out_stream_destroy(obj_t *stream)
}
}
-static obj_t *string_out_put_string(obj_t *stream, const wchar_t *s)
+static obj_t *string_out_put_string(obj_t *stream, obj_t *str)
{
struct string_output *so = (struct string_output *) stream->co.handle;
if (so == 0) {
return nil;
} else {
- size_t len = wcslen(s);
+ const wchar_t *s = c_str(str);
+ size_t len = c_num(length_str(str));
size_t old_size = so->size;
size_t required_size = len + so->fill + 1;
@@ -456,67 +397,20 @@ static obj_t *string_out_put_string(obj_t *stream, const wchar_t *s)
return nil;
}
- so->buf = chk_realloc(so->buf, so->size * sizeof *so->buf);
- memcpy(so->buf + so->fill, s, (len + 1) * sizeof *so->buf);
+ if (so->size != old_size)
+ so->buf = chk_realloc(so->buf, so->size * sizeof *so->buf);
+ wmemcpy(so->buf + so->fill, s, len + 1);
so->fill += len;
return t;
}
}
-static obj_t *string_out_put_char(obj_t *stream, wchar_t ch)
+static obj_t *string_out_put_char(obj_t *stream, obj_t *ch)
{
wchar_t mini[2];
- mini[0] = ch;
+ mini[0] = c_chr(ch);
mini[1] = 0;
- return string_out_put_string(stream, mini);
-}
-
-obj_t *string_out_vcformat(obj_t *stream, const wchar_t *fmt, va_list vl)
-{
- struct string_output *so = (struct string_output *) stream->co.handle;
-
- if (so == 0) {
- return nil;
- } else {
- int nchars, nchars2;
- wchar_t dummy_buf[1];
- size_t old_size = so->size;
- size_t required_size;
- va_list vl_copy;
-
-#if defined va_copy
- va_copy (vl_copy, vl);
-#elif defined __va_copy
- __va_copy (vl_copy, vl);
-#else
- vl_copy = vl;
-#endif
-
- nchars = vswprintf(dummy_buf, 0, fmt, vl_copy);
-
-#if defined va_copy || defined __va_copy
- va_end (vl_copy);
-#endif
-
- bug_unless (nchars >= 0);
-
- required_size = so->fill + nchars + 1;
-
- if (required_size < so->fill)
- return nil;
-
- while (so->size <= required_size) {
- so->size *= 2;
- if (so->size < old_size)
- return nil;
- }
-
- so->buf = chk_realloc(so->buf, so->size * sizeof *so->buf);
- nchars2 = vswprintf(so->buf + so->fill, so->size-so->fill, fmt, vl);
- bug_unless (nchars == nchars2);
- so->fill += nchars;
- return t;
- }
+ return string_out_put_string(stream, auto_str(mini));
}
static struct strm_ops string_out_ops = {
@@ -529,8 +423,6 @@ static struct strm_ops string_out_ops = {
0,
0,
0,
- string_out_vcformat,
- common_vformat,
0,
};
@@ -573,8 +465,6 @@ static struct strm_ops dir_ops = {
dir_get_line,
0,
0,
- 0,
- 0,
dir_close
};
@@ -605,7 +495,7 @@ obj_t *make_pipe_stream(FILE *f, obj_t *descr, obj_t *input, obj_t *output)
/* Don't leave h uninitialized; it is gc-reachable through stream cobj. */
h->f = h->f_orig_pipe = 0;
h->descr = descr;
- uw_throwf(process_error, L"unable to create pipe ~a: ~a/~s", descr,
+ uw_throwf(process_error, lit("unable to create pipe ~a: ~a/~s"), descr,
num(error), string_utf8(strerror(error)), nao);
}
@@ -625,7 +515,7 @@ obj_t *make_string_input_stream(obj_t *string)
obj_t *make_string_byte_input_stream(obj_t *string)
{
- type_assert (stringp(string), (L"~a is not a string", string));
+ type_assert (stringp(string), (lit("~a is not a string"), string, nao));
{
struct byte_input *bi = (struct byte_input *) chk_malloc(sizeof *bi);
@@ -650,7 +540,8 @@ obj_t *make_string_output_stream(void)
obj_t *get_string_from_stream(obj_t *stream)
{
type_check (stream, COBJ);
- type_assert (stream->co.cls == stream_t, (L"~a is not a stream", stream));
+ type_assert (stream->co.cls == stream_t,
+ (lit("~a is not a stream"), stream, nao));
if (stream->co.ops == &string_out_ops.cobj_ops) {
struct string_output *so = (struct string_output *) stream->co.handle;
@@ -661,7 +552,7 @@ obj_t *get_string_from_stream(obj_t *stream)
if (!so)
return out;
- so->buf = chk_realloc(so->buf, so->fill + 1);
+ so->buf = chk_realloc(so->buf, (so->fill + 1) * sizeof *so->buf);
out = string_own(so->buf);
free(so);
return out;
@@ -681,7 +572,8 @@ obj_t *make_dir_stream(DIR *dir)
obj_t *close_stream(obj_t *stream, obj_t *throw_on_error)
{
type_check (stream, COBJ);
- type_assert (stream->co.cls == stream_t, (L"~a is not a stream", stream));
+ type_assert (stream->co.cls == stream_t, (lit("~a is not a stream"),
+ stream, nao));
{
struct strm_ops *ops = (struct strm_ops *) stream->co.ops;
@@ -692,7 +584,8 @@ obj_t *close_stream(obj_t *stream, obj_t *throw_on_error)
obj_t *get_line(obj_t *stream)
{
type_check (stream, COBJ);
- type_assert (stream->co.cls == stream_t, (L"~a is not a stream", stream));
+ type_assert (stream->co.cls == stream_t, (lit("~a is not a stream"),
+ stream, nao));
{
struct strm_ops *ops = (struct strm_ops *) stream->co.ops;
@@ -703,7 +596,8 @@ obj_t *get_line(obj_t *stream)
obj_t *get_char(obj_t *stream)
{
type_check (stream, COBJ);
- type_assert (stream->co.cls == stream_t, (L"~a is not a stream", stream));
+ type_assert (stream->co.cls == stream_t, (lit("~a is not a stream"),
+ stream, nao));
{
struct strm_ops *ops = (struct strm_ops *) stream->co.ops;
@@ -714,7 +608,8 @@ obj_t *get_char(obj_t *stream)
obj_t *get_byte(obj_t *stream)
{
type_check (stream, COBJ);
- type_assert (stream->co.cls == stream_t, (L"~a is not a stream", stream));
+ type_assert (stream->co.cls == stream_t, (lit("~a is not a stream"),
+ stream, nao));
{
struct strm_ops *ops = (struct strm_ops *) stream->co.ops;
@@ -722,57 +617,269 @@ obj_t *get_byte(obj_t *stream)
}
}
-obj_t *vformat(obj_t *stream, const wchar_t *str, va_list vl)
+static obj_t *vformat_num(obj_t *stream, const char *str,
+ int width, int left, int pad, int precision)
{
- type_check (stream, COBJ);
- type_assert (stream->co.cls == stream_t, (L"~a is not a stream", stream));
+ int len = strlen(str);
+ int truewidth = (width < precision) ? width : precision;
+ int slack = (len < truewidth) ? truewidth - len : 0;
+ int padlen = (len < precision) ? precision - len : 0;
+ int i;
- {
- struct strm_ops *ops = (struct strm_ops *) stream->co.ops;
- return ops->vformat ? ops->vformat(stream, str, vl) : nil;
- }
+ if (!left)
+ for (i = 0; i < slack; i++)
+ if (!put_char(stream, pad ? chr('0') : chr(' ')))
+ return nil;
+
+ for (i = 0; i < padlen; i++)
+ if (!put_char(stream, pad ? chr('0') : chr(' ')))
+ return nil;
+
+ while (*str)
+ if (!put_char(stream, chr(*str++)))
+ return nil;
+
+ if (left)
+ for (i = 0; i < slack; i++)
+ if (!put_char(stream, chr(' ')))
+ return nil;
+
+ return t;
}
-obj_t *vcformat(obj_t *stream, const wchar_t *string, va_list vl)
+obj_t *vformat_str(obj_t *stream, obj_t *str, int width, int left,
+ int precision)
{
- type_check (stream, COBJ);
- type_assert (stream->co.cls == stream_t, (L"~a is not a stream", stream));
+ const wchar_t *cstr = c_str(str);
+ int len = c_num(length_str(str));
+ int truelen = (precision && precision < len) ? precision : len;
+ int slack = (truelen < width) ? width - truelen : 0;
+ int i;
- {
- struct strm_ops *ops = (struct strm_ops *) stream->co.ops;
- return ops->vcformat ? ops->vcformat(stream, string, vl) : nil;
- }
+ if (!left)
+ for (i = 0; i < slack; i++)
+ if (!put_char(stream, chr(' ')))
+ return nil;
+
+ for (i = 0; i < truelen; i++)
+ if (!put_char(stream, chr(cstr[i])))
+ return nil;
+
+ if (left)
+ for (i = 0; i < slack; i++)
+ if (!put_char(stream, chr(' ')))
+ return nil;
+
+ return t;
}
-obj_t *format(obj_t *stream, const wchar_t *str, ...)
+obj_t *vformat(obj_t *stream, obj_t *fmtstr, va_list vl)
{
type_check (stream, COBJ);
- type_assert (stream->co.cls == stream_t, (L"~a is not a stream", stream));
+ type_assert (stream->co.cls == stream_t, (lit("~a is not a stream"),
+ stream, nao));
{
- struct strm_ops *ops = (struct strm_ops *) stream->co.ops;
- va_list vl;
- obj_t *ret;
+ const wchar_t *fmt = c_str(fmtstr);
+ 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 left = 0, zeropad = 0;
+ long val;
+ void *ptr;
+ char num_buf[64];
- va_start (vl, str);
- ret = ops->vformat ? ops->vformat(stream, str, vl) : nil;
- va_end (vl);
- return ret;
+ for (;;) {
+ obj_t *obj;
+ wchar_t ch = *fmt++;
+
+ switch (state) {
+ case vf_init:
+ switch (ch) {
+ case 0:
+ break;
+ case '~':
+ state = vf_width;
+ width = 0;
+ left = 0;
+ zeropad = 0;
+ precision = 0;
+ digits = 0;
+ continue;
+ default:
+ put_char(stream, chr(ch));
+ continue;
+ }
+ break;
+ case vf_width:
+ switch (ch) {
+ case '~':
+ put_char(stream, chr('~'));
+ continue;
+ case '-':
+ left = 1;
+ continue;
+ case ',':
+ state = vf_precision;
+ continue;
+ case '0':
+ saved_state = state;
+ state = vf_digits;
+ zeropad = 1;
+ continue;
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ saved_state = state;
+ state = vf_digits;
+ digits = ch - '0';
+ continue;
+ case '*':
+ obj = va_arg(vl, obj_t *);
+ width = c_num(obj);
+ state = vf_precision;
+ continue;
+ default:
+ state = vf_spec;
+ --fmt;
+ continue;
+ }
+ break;
+ case vf_precision:
+ switch (ch) {
+ case '0': case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ saved_state = state;
+ state = vf_digits;
+ digits = ch - '0';
+ continue;
+ case '*':
+ obj = va_arg(vl, obj_t *);
+ width = c_num(obj);
+ precision = vf_precision;
+ continue;
+ default:
+ state = vf_spec;
+ continue;
+ }
+ break;
+ case vf_digits:
+ switch (ch) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ digits = (digits * 10) + (ch - '0');
+ if (digits > 999999)
+ goto toobig;
+ continue;
+ default:
+ switch (saved_state) {
+ case vf_width:
+ if (width < 0) {
+ width = -digits;
+ left = 1;
+ } else {
+ width = digits;
+ }
+ state = (ch == ',') ? vf_precision : vf_spec;
+ continue;
+ case vf_precision:
+ precision = digits;
+ state = vf_spec;
+ --fmt;
+ continue;
+ default:
+ internal_error("unexpected state in formatter");
+ }
+ }
+ break;
+ case vf_spec:
+ state = vf_init;
+ switch (ch) {
+ case 'x':
+ obj = va_arg(vl, obj_t *);
+ val = c_num(obj);
+ sprintf(num_buf, "%lx", val);
+ goto output_num;
+ case 'X':
+ obj = va_arg(vl, obj_t *);
+ val = c_num(obj);
+ sprintf(num_buf, "%lX", val);
+ goto output_num;
+ case 'o':
+ obj = va_arg(vl, obj_t *);
+ val = c_num(obj);
+ sprintf(num_buf, "%lo", val);
+ goto output_num;
+ case 'a':
+ obj = va_arg(vl, obj_t *);
+ if (obj == nao)
+ goto premature;
+ if (nump(obj)) {
+ val = c_num(obj);
+ sprintf(num_buf, "%ld", val);
+ goto output_num;
+ } else if (stringp(obj)) {
+ if (!vformat_str(stream, obj, width, left, precision))
+ return nil;
+ continue;
+ }
+ obj_pprint(obj, stream);
+ continue;
+ case 's':
+ obj = va_arg(vl, obj_t *);
+ if (obj == nao)
+ goto premature;
+ if (nump(obj)) {
+ val = c_num(obj);
+ sprintf(num_buf, "%ld", val);
+ if (vformat_num(stream, num_buf, 0, 0, 0, 0))
+ return nil;
+ continue;
+ }
+ obj_print(obj, stream);
+ continue;
+ case 'p':
+ ptr = va_arg(vl, void *);
+ val = (int) ptr;
+ sprintf(num_buf, "0x%lx", val);
+ goto output_num;
+ default:
+ abort();
+ output_num:
+ if (!vformat_num(stream, num_buf, width, left,
+ precision ? 0 : zeropad,
+ precision ? precision : 1))
+ return nil;
+ continue;
+ }
+ continue;
+ }
+
+ break;
+ }
}
+
+
+ if (va_arg(vl, obj_t *) != nao)
+ internal_error("unterminated format argument list");
+ return t;
+premature:
+ internal_error("insufficient arguments for format");
+toobig:
+ internal_error("ridiculous precision or field width in format");
}
-obj_t *cformat(obj_t *stream, const wchar_t *string, ...)
+obj_t *format(obj_t *stream, obj_t *str, ...)
{
type_check (stream, COBJ);
- type_assert (stream->co.cls == stream_t, (L"~a is not a stream", stream));
+ type_assert (stream->co.cls == stream_t, (lit("~a is not a stream"),
+ stream, nao));
{
- struct strm_ops *ops = (struct strm_ops *) stream->co.ops;
va_list vl;
obj_t *ret;
-
- va_start (vl, string);
- ret = ops->vformat ? ops->vcformat(stream, string, vl) : nil;
+ va_start (vl, str);
+ ret = vformat(stream, str, vl);
va_end (vl);
return ret;
}
@@ -781,40 +888,20 @@ obj_t *cformat(obj_t *stream, const wchar_t *string, ...)
obj_t *put_string(obj_t *stream, obj_t *string)
{
type_check (stream, COBJ);
- type_assert (stream->co.cls == stream_t, (L"~a is not a stream", stream));
-
- {
- struct strm_ops *ops = (struct strm_ops *) stream->co.ops;
- return ops->put_string ? ops->put_string(stream, c_str(string)) : nil;
- }
-}
-
-obj_t *put_cstring(obj_t *stream, const wchar_t *str)
-{
- type_check (stream, COBJ);
- type_assert (stream->co.cls == stream_t, (L"~a is not a stream", stream));
+ type_assert (stream->co.cls == stream_t, (lit("~a is not a stream"),
+ stream, nao));
{
struct strm_ops *ops = (struct strm_ops *) stream->co.ops;
- return ops->put_string ? ops->put_string(stream, str) : nil;
+ return ops->put_string ? ops->put_string(stream, string) : nil;
}
}
obj_t *put_char(obj_t *stream, obj_t *ch)
{
type_check (stream, COBJ);
- type_assert (stream->co.cls == stream_t, (L"~a is not a stream", stream));
-
- {
- struct strm_ops *ops = (struct strm_ops *) stream->co.ops;
- return ops->put_char ? ops->put_char(stream, c_chr(ch)) : nil;
- }
-}
-
-obj_t *put_cchar(obj_t *stream, wchar_t ch)
-{
- type_check (stream, COBJ);
- type_assert (stream->co.cls == stream_t, (L"~a is not a stream", stream));
+ type_assert (stream->co.cls == stream_t, (lit("~a is not a stream"),
+ stream, nao));
{
struct strm_ops *ops = (struct strm_ops *) stream->co.ops;
@@ -824,7 +911,7 @@ obj_t *put_cchar(obj_t *stream, wchar_t ch)
obj_t *put_line(obj_t *stream, obj_t *string)
{
- return (put_string(stream, string), put_cchar(stream, '\n'));
+ return (put_string(stream, string), put_char(stream, chr('\n')));
}
void stream_init(void)
diff --git a/stream.h b/stream.h
index b4354168..9929cc5e 100644
--- a/stream.h
+++ b/stream.h
@@ -37,14 +37,10 @@ obj_t *close_stream(obj_t *stream, obj_t *throw_on_error);
obj_t *get_line(obj_t *);
obj_t *get_char(obj_t *);
obj_t *get_byte(obj_t *);
-obj_t *vformat(obj_t *stream, const wchar_t *string, va_list);
-obj_t *vcformat(obj_t *stream, const wchar_t *string, va_list);
-obj_t *format(obj_t *stream, const wchar_t *string, ...);
-obj_t *cformat(obj_t *stream, const wchar_t *string, ...);
+obj_t *vformat(obj_t *stream, obj_t *string, va_list);
+obj_t *format(obj_t *stream, obj_t *string, ...);
obj_t *put_string(obj_t *stream, obj_t *string);
obj_t *put_line(obj_t *stream, obj_t *string);
-obj_t *put_cstring(obj_t *stream, const wchar_t *);
obj_t *put_char(obj_t *stream, obj_t *ch);
-obj_t *put_cchar(obj_t *stream, wchar_t ch);
void stream_init(void);
diff --git a/txr.c b/txr.c
index bb2814a5..8f95ffdd 100644
--- a/txr.c
+++ b/txr.c
@@ -54,66 +54,67 @@ obj_t *spec_file_str;
*/
void *oom_realloc_handler(void *old, size_t size)
{
- fwprintf(stderr, L"%ls: out of memory\n", progname);
- fputws(L"false", stderr);
+ format(std_error, lit("~a: out of memory\n"), prog_string, nao);
+ put_line(std_error, lit("false"));
abort();
}
void help(void)
{
- const wchar_t *text =
-L"\n"
-L"txr version %ls\n"
-L"\n"
-L"copyright 2009, Kaz Kylheku <kkylheku@gmail.com>\n"
-L"\n"
-L"usage:\n"
-L"\n"
-L" %ls [ options ] query-file { data-file }*\n"
-L"\n"
-L"The query-file or data-file arguments may be specified as -, in which case\n"
-L"standard input is used. All data-file arguments which begin with a !\n"
-L"character are treated as command pipes. Those which begin with a $\n"
-L"are interpreted as directories to read. Leading arguments which begin\n"
-L"with a - followed by one or more characters, and which are not arguments to\n"
-L"options are interpreted as options. The -- option indicates the end of the\n"
-L"options.\n"
-L"\n"
-L"If no data-file arguments sare supplied, then the query itself must open a\n"
-L"a data source prior to attempting to make any pattern match, or it will\n"
-L"simply fail due to a match which has run out of data.\n"
-L"\n"
-L"options:\n"
-L"\n"
-L"-Dvar=value Pre-define variable var, with the given value.\n"
-L" A list value can be specified using commas.\n"
-L"-Dvar Predefine variable var, with empty string value.\n"
-L"-q Quiet: don't report errors during query matching.\n"
-L"-v Verbose: extra logging from matcher.\n"
-L"-b Don't dump list of bindings.\n"
-L"-a num Generate array variables up to num-dimensions.\n"
-L" Default is 1. Additional dimensions are fudged\n"
-L" by generating numeric suffixes\n"
-L"-c query-text The query is read from the query-text argument\n"
-L" itself. The query-file argument is omitted in\n"
-L" this case; the first argument is a data file.\n"
-L"-f query-file Specify the query-file as an option argument.\n"
-L" option, instead of the query-file argument.\n"
-L" This allows #! scripts to pass options through\n"
-L" to the utility.\n"
-L"--help You already know!\n"
-L"--version Display program version\n"
-L"\n"
-L"Options that take no argument can be combined. The -q and -v options\n"
-L"are mutually exclusive; the right-most one dominates.\n"
-L"\n"
- ;
- fwprintf(stdout, text, version, progname);
+ obj_t *text = lit(
+"\n"
+"txr version ~a\n"
+"\n"
+"copyright 2009, Kaz Kylheku <kkylheku@gmail.com>\n"
+"\n"
+"usage:\n"
+"\n"
+" ~a [ options ] query-file { data-file }*\n"
+"\n"
+"The query-file or data-file arguments may be specified as -, in which case\n"
+"standard input is used. All data-file arguments which begin with a !\n"
+"character are treated as command pipes. Those which begin with a $\n"
+"are interpreted as directories to read. Leading arguments which begin\n"
+"with a - followed by one or more characters, and which are not arguments to\n"
+"options are interpreted as options. The -- option indicates the end of the\n"
+"options.\n"
+"\n"
+"If no data-file arguments sare supplied, then the query itself must open a\n"
+"a data source prior to attempting to make any pattern match, or it will\n"
+"simply fail due to a match which has run out of data.\n"
+"\n"
+"options:\n"
+"\n"
+"-Dvar=value Pre-define variable var, with the given value.\n"
+" A list value can be specified using commas.\n"
+"-Dvar Predefine variable var, with empty string value.\n"
+"-q Quiet: don't report errors during query matching.\n"
+"-v Verbose: extra logging from matcher.\n"
+"-b Don't dump list of bindings.\n"
+"-a num Generate array variables up to num-dimensions.\n"
+" Default is 1. Additional dimensions are fudged\n"
+" by generating numeric suffixes\n"
+"-c query-text The query is read from the query-text argument\n"
+" itself. The query-file argument is omitted in\n"
+" this case; the first argument is a data file.\n"
+"-f query-file Specify the query-file as an option argument.\n"
+" option, instead of the query-file argument.\n"
+" This allows #! scripts to pass options through\n"
+" to the utility.\n"
+"--help You already know!\n"
+"--version Display program version\n"
+"\n"
+"Options that take no argument can be combined. The -q and -v options\n"
+"are mutually exclusive; the right-most one dominates.\n"
+"\n"
+);
+ format(std_output, text, auto_str(version), prog_string, nao);
}
void hint(void)
{
- fwprintf(stderr, L"%ls: incorrect arguments: try --help\n", progname);
+ format(std_error, lit("~a: incorrect arguments: try --help\n"),
+ prog_string, nao);
}
obj_t *remove_hash_bang_line(obj_t *spec)
@@ -215,7 +216,8 @@ static int txr_main(int argc, char **argv)
}
if (!strcmp(*argv, "--version")) {
- wprintf(L"%ls: version %ls\n", progname, version);
+ format(std_output, lit("~a: version ~a\n"),
+ prog_string, auto_str(version), nao);
return 0;
}
@@ -230,7 +232,8 @@ static int txr_main(int argc, char **argv)
char opt = (*argv)[1];
if (argc == 1) {
- fwprintf(stderr, L"%ls: option %c needs argument\n", progname, opt);
+ format(std_error, lit("~a: option -~a needs argument\n"),
+ prog_string, chr(opt), nao);
return EXIT_FAILURE;
}
@@ -241,8 +244,9 @@ static int txr_main(int argc, char **argv)
case 'a':
val = strtol(*argv, &errp, 10);
if (*errp != 0) {
- fwprintf(stderr, L"%ls: option %c needs numeric argument, not %s\n",
- progname, opt, *argv);
+ format(std_error, lit("~a: option -~a needs numeric argument, "
+ "not ~a\n"), prog_string, chr(opt),
+ string_utf8(*argv), nao);
return EXIT_FAILURE;
}
@@ -282,15 +286,16 @@ static int txr_main(int argc, char **argv)
case 'a':
case 'c':
case 'D':
- fwprintf(stderr, L"%ls: option -%c does not clump\n",
- progname, *popt);
+ format(std_error, lit("~a: option -~a does not clump\n"),
+ prog_string, chr(*popt), nao);
return EXIT_FAILURE;
case '-':
- fwprintf(stderr, L"%ls: unrecognized long option: --%s\n",
- progname, popt + 1);
+ format(std_error, lit("~a: unrecognized long option: --~a\n"),
+ prog_string, string_utf8(popt + 1), nao);
return EXIT_FAILURE;
default:
- fwprintf(stderr, L"%ls: unrecognized option: %c\n", progname, *popt);
+ format(std_error, lit("~a: unrecognized option: -~a\n"),
+ prog_string, chr(*popt), nao);
return EXIT_FAILURE;
}
}
@@ -300,7 +305,8 @@ static int txr_main(int argc, char **argv)
}
if (specstring && spec_file_str) {
- fwprintf(stderr, L"%ls: cannot specify both -f and -c\n", progname);
+ format(std_error, lit("~a: cannot specify both -f and -c\n"),
+ prog_string, nao);
return EXIT_FAILURE;
}
@@ -315,7 +321,7 @@ static int txr_main(int argc, char **argv)
if (wcscmp(c_str(spec_file_str), L"-") != 0) {
FILE *in = w_fopen(c_str(spec_file_str), L"r");
if (in == 0)
- uw_throwcf(file_error, L"unable to open %ls", c_str(spec_file_str));
+ uw_throwf(file_error, lit("unable to open ~a"), spec_file_str, nao);
yyin_stream = make_stdio_stream(in, spec_file_str, t, nil);
} else {
spec_file = L"stdin";
@@ -328,9 +334,10 @@ static int txr_main(int argc, char **argv)
if (strcmp(*argv, "-") != 0) {
FILE *in = fopen(*argv, "r");
+ obj_t *name = string_utf8(*argv);
if (in == 0)
- uw_throwcf(file_error, L"unable to open %s", *argv);
- yyin_stream = make_stdio_stream(in, string_utf8(*argv), t, nil);
+ uw_throwf(file_error, lit("unable to open ~a"), name, nao);
+ yyin_stream = make_stdio_stream(in, name, t, nil);
spec_file = utf8_dup_from(*argv);
} else {
spec_file = L"stdin";
@@ -353,8 +360,8 @@ static int txr_main(int argc, char **argv)
opt_loglevel = match_loglevel;
if (opt_loglevel >= 2) {
- format(std_error, L"spec:\n~s\n", spec, nao);
- format(std_error, L"bindings:\n~s\n", bindings, nao);
+ format(std_error, lit("spec:\n~s\n"), spec, nao);
+ format(std_error, lit("bindings:\n~s\n"), bindings, nao);
}
{
diff --git a/unwind.c b/unwind.c
index 43c93184..3e3083da 100644
--- a/unwind.c
+++ b/unwind.c
@@ -217,15 +217,15 @@ obj_t *uw_throw(obj_t *sym, obj_t *exception)
if (ex == 0) {
if (opt_loglevel >= 1) {
obj_t *s = stringp(exception);
- format(std_error, L"~a: unhandled exception of type ~a:\n",
+ format(std_error, lit("~a: unhandled exception of type ~a:\n"),
prog_string, sym, nao);
- format(std_error, s ? L"~a: ~a\n" : L"~a: ~s\n",
+ format(std_error, s ? lit("~a: ~a\n") : lit("~a: ~s\n"),
prog_string, exception, nao);
}
if (uw_exception_subtype_p(sym, query_error) ||
uw_exception_subtype_p(sym, file_error)) {
if (!output_produced)
- put_cstring(std_output, L"false\n");
+ put_line(std_output, lit("false"));
exit(EXIT_FAILURE);
}
abort();
@@ -238,7 +238,7 @@ obj_t *uw_throw(obj_t *sym, obj_t *exception)
abort();
}
-obj_t *uw_throwf(obj_t *sym, const wchar_t *fmt, ...)
+obj_t *uw_throwf(obj_t *sym, obj_t *fmt, ...)
{
va_list vl;
obj_t *stream = make_string_output_stream();
@@ -251,7 +251,7 @@ obj_t *uw_throwf(obj_t *sym, const wchar_t *fmt, ...)
abort();
}
-obj_t *uw_errorf(const wchar_t *fmt, ...)
+obj_t *uw_errorf(obj_t *fmt, ...)
{
va_list vl;
obj_t *stream = make_string_output_stream();
@@ -264,33 +264,7 @@ obj_t *uw_errorf(const wchar_t *fmt, ...)
abort();
}
-obj_t *uw_throwcf(obj_t *sym, const wchar_t *fmt, ...)
-{
- va_list vl;
- obj_t *stream = make_string_output_stream();
-
- va_start (vl, fmt);
- (void) vcformat(stream, fmt, vl);
- va_end (vl);
-
- uw_throw(sym, get_string_from_stream(stream));
- abort();
-}
-
-obj_t *uw_errorcf(const wchar_t *fmt, ...)
-{
- va_list vl;
- obj_t *stream = make_string_output_stream();
-
- va_start (vl, fmt);
- (void) vcformat(stream, fmt, vl);
- va_end (vl);
-
- uw_throw(error, get_string_from_stream(stream));
- abort();
-}
-
-obj_t *type_mismatch(const wchar_t *fmt, ...)
+obj_t *type_mismatch(obj_t *fmt, ...)
{
va_list vl;
obj_t *stream = make_string_output_stream();
@@ -317,21 +291,21 @@ obj_t *uw_register_subtype(obj_t *sub, obj_t *sup)
if (sub == t) {
if (sup == t)
return sup;
- uw_throwf(type_error, L"cannot define ~a as an exception subtype of ~a",
+ uw_throwf(type_error, lit("cannot define ~a as an exception subtype of ~a"),
sub, sup, nao);
}
if (sup == nil) {
- uw_throwf(type_error, L"cannot define ~a as an exception subtype of ~a",
+ uw_throwf(type_error, lit("cannot define ~a as an exception subtype of ~a"),
sub, sup, nao);
}
if (uw_exception_subtype_p(sub, sup))
- uw_throwf(type_error, L"~a is already an exception subtype of ~a",
+ uw_throwf(type_error, lit("~a is already an exception subtype of ~a"),
sub, sup, nao);
if (uw_exception_subtype_p(sup, sub))
- uw_throwf(type_error, L"~a is already an exception supertype of ~a",
+ uw_throwf(type_error, lit("~a is already an exception supertype of ~a"),
sub, sup, nao);
/* If sup symbol not registered, then we make it
diff --git a/unwind.h b/unwind.h
index 6f7683a8..00931429 100644
--- a/unwind.h
+++ b/unwind.h
@@ -79,17 +79,15 @@ obj_t *uw_set_func(obj_t *sym, obj_t *value);
obj_t *uw_block_return(obj_t *tag, obj_t *result);
void uw_push_catch(uw_frame_t *, obj_t *matches);
noreturn obj_t *uw_throw(obj_t *sym, obj_t *exception);
-noreturn obj_t *uw_throwf(obj_t *sym, const wchar_t *fmt, ...);
-noreturn obj_t *uw_errorf(const wchar_t *fmt, ...);
-noreturn obj_t *uw_throwcf(obj_t *sym, const wchar_t *fmt, ...);
-noreturn obj_t *uw_errorcf(const wchar_t *fmt, ...);
+noreturn obj_t *uw_throwf(obj_t *sym, obj_t *fmt, ...);
+noreturn obj_t *uw_errorf(obj_t *fmt, ...);
obj_t *uw_register_subtype(obj_t *sub, obj_t *super);
obj_t *uw_exception_subtype_p(obj_t *sub, obj_t *sup);
void uw_continue(uw_frame_t *curr, uw_frame_t *target);
void uw_pop_frame(uw_frame_t *);
void uw_init(void);
-noreturn obj_t *type_mismatch(const wchar_t *, ...);
+noreturn obj_t *type_mismatch(obj_t *, ...);
#define uw_block_begin(TAG, RESULTVAR) \
obj_t *RESULTVAR = nil; \
@@ -149,9 +147,14 @@ noreturn obj_t *type_mismatch(const wchar_t *, ...);
}
#define internal_error(STR) \
- uw_throwcf(internal_err, \
- L"%s:%d %ls", __FILE__, \
- __LINE__, STR)
+ do { \
+ extern obj_t *num(long); \
+ uw_throwf(internal_err, \
+ lit("~a:~a ~a"), \
+ lit(__FILE__), \
+ num(__LINE__), lit(STR), \
+ nao); \
+ } while (0)
#define type_assert(EXPR, ARGS) \
if (!(EXPR)) type_mismatch ARGS
@@ -164,12 +167,13 @@ noreturn obj_t *type_mismatch(const wchar_t *, ...);
#define numeric_assert(EXPR) \
if (!(EXPR)) \
- uw_throwcf(numeric_err, L"%ls", \
- L"assertion " #EXPR \
- L" failed")
+ uw_throwf(numeric_err, \
+ lit("assertion " #EXPR \
+ "failed"), nao)
#define range_bug_unless(EXPR) \
if (!(EXPR)) \
- uw_throwcf(range_err, L"%ls", \
- L"assertion" #EXPR \
- L" failed")
+ uw_throwf(range_err, \
+ lit("assertion " #EXPR \
+ "failed"), nao)
+
diff --git a/utf8.c b/utf8.c
index 5936e43a..46b1feae 100644
--- a/utf8.c
+++ b/utf8.c
@@ -153,7 +153,7 @@ size_t utf8_to(char *dst, const wchar_t *wsrc)
wchar_t *utf8_dup_from_uc(const unsigned char *str)
{
size_t nchar = utf8_from_uc(0, str);
- wchar_t *wstr = chk_malloc(sizeof *wstr * nchar);
+ wchar_t *wstr = (wchar_t *) chk_malloc(nchar * sizeof *wstr);
utf8_from_uc(wstr, str);
return wstr;
}
@@ -161,7 +161,7 @@ wchar_t *utf8_dup_from_uc(const unsigned char *str)
wchar_t *utf8_dup_from(const char *str)
{
size_t nchar = utf8_from(0, str);
- wchar_t *wstr = chk_malloc(sizeof *wstr * nchar);
+ wchar_t *wstr = (wchar_t *) chk_malloc(nchar * sizeof *wstr);
utf8_from(wstr, str);
return wstr;
}
@@ -169,7 +169,7 @@ wchar_t *utf8_dup_from(const char *str)
unsigned char *utf8_dup_to_uc(const wchar_t *wstr)
{
size_t nbyte = utf8_to_uc(0, wstr);
- unsigned char *str = chk_malloc(nbyte);
+ unsigned char *str = (unsigned char *) chk_malloc(nbyte);
utf8_to_uc(str, wstr);
return str;
}
@@ -177,7 +177,7 @@ unsigned char *utf8_dup_to_uc(const wchar_t *wstr)
char *utf8_dup_to(const wchar_t *wstr)
{
size_t nbyte = utf8_to(0, wstr);
- char *str = chk_malloc(nbyte);
+ char *str = (char *) chk_malloc(nbyte);
utf8_to(str, wstr);
return str;
}