diff options
-rw-r--r-- | ChangeLog | 96 | ||||
-rw-r--r-- | gc.c | 4 | ||||
-rw-r--r-- | lib.c | 141 | ||||
-rw-r--r-- | lib.h | 5 | ||||
-rw-r--r-- | match.c | 261 | ||||
-rw-r--r-- | parser.h | 2 | ||||
-rw-r--r-- | parser.l | 92 | ||||
-rw-r--r-- | stream.c | 491 | ||||
-rw-r--r-- | stream.h | 8 | ||||
-rw-r--r-- | txr.c | 139 | ||||
-rw-r--r-- | unwind.c | 46 | ||||
-rw-r--r-- | unwind.h | 32 | ||||
-rw-r--r-- | utf8.c | 8 |
13 files changed, 756 insertions, 569 deletions
@@ -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 @@ -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; @@ -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')); } /* @@ -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; @@ -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; @@ -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); @@ -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); } %% @@ -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) @@ -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); @@ -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); } { @@ -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 @@ -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) + @@ -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; } |