summaryrefslogtreecommitdiffstats
path: root/stream.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2011-10-21 13:27:31 -0400
committerKaz Kylheku <kaz@kylheku.com>2011-10-21 13:27:31 -0400
commite98d94aa2a8c46c392eec4b7ac664eb989f3c589 (patch)
treea656c2267ebf3fc1e62f5606e914bcf9f7860825 /stream.c
parent7cf8f4c01a851c8dc3158802df0d5132d146bf69 (diff)
downloadtxr-e98d94aa2a8c46c392eec4b7ac664eb989f3c589.tar.gz
txr-e98d94aa2a8c46c392eec4b7ac664eb989f3c589.tar.bz2
txr-e98d94aa2a8c46c392eec4b7ac664eb989f3c589.zip
New features. Strling list output streams in stream
library, allow output to be captured as a list of strings representing lines (in contrast to string streams which capture a single string). The output directive can output to a variable, and next can scan over a variable. * lib.c (span_str, compl_span_str, break_str): New functions. * lib.h (span_str, compl_span_str, break_str): New functions declared. * match.c (into_k, var_k): New keyword variables. (mf_file_data): New static function. (v_next): Refactored argument handling. Added support for :var keyword. (v_output): Added support for :into keyword. * stream.c (strlist_mark, strlist_out_put_string, strlist_out_put_char): New static functions. (strlist_out_ops): New static struct. (make_strlist_output_stream, get_list_from_stream): New functions. * stream.h (make_strlist_output_stream, get_list_from_stream): New functions declared.
Diffstat (limited to 'stream.c')
-rw-r--r--stream.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/stream.c b/stream.c
index aea2960d..bb9641df 100644
--- a/stream.c
+++ b/stream.c
@@ -438,6 +438,96 @@ static struct strm_ops string_out_ops = {
0,
};
+static void strlist_mark(val stream)
+{
+ val stuff = (val) stream->co.handle;
+ gc_mark(stuff);
+}
+
+static val strlist_out_put_string(val stream, val str)
+{
+ val cell = (val) stream->co.handle;
+ cons_bind (lines, strstream, cell);
+
+ for (;;) {
+ val length = length_str(str);
+ val span_to_newline = compl_span_str(str, lit("\n"));
+
+ if (zerop(length))
+ break;
+
+ put_string(strstream, sub_str(str, nil, span_to_newline));
+
+ if (equal(span_to_newline, length))
+ break;
+
+ str = sub_str(str, plus(span_to_newline, num(1)), nil);
+ push(get_string_from_stream(strstream), &lines);
+ strstream = make_string_output_stream();
+ }
+
+ *car_l(cell) = lines;
+ *cdr_l(cell) = strstream;
+
+ return t;
+}
+
+static val strlist_out_put_char(val stream, val ch)
+{
+ val cell = (val) stream->co.handle;
+ cons_bind (lines, strstream, cell);
+
+ if (ch == chr('\n')) {
+ push(get_string_from_stream(strstream), &lines);
+ strstream = make_string_output_stream();
+ } else {
+ put_char(strstream, ch);
+ }
+
+ *car_l(cell) = lines;
+ *cdr_l(cell) = strstream;
+
+ return t;
+}
+
+static struct strm_ops strlist_out_ops = {
+ { cobj_equal_op,
+ cobj_print_op,
+ cobj_destroy_stub_op,
+ strlist_mark,
+ cobj_hash_op },
+ strlist_out_put_string,
+ strlist_out_put_char,
+ 0,
+ 0,
+ 0,
+ 0,
+};
+
+val make_strlist_output_stream(void)
+{
+ return cobj((mem_t *) cons(nil, make_string_output_stream()),
+ stream_s, &strlist_out_ops.cobj_ops);
+}
+
+val get_list_from_stream(val stream)
+{
+ type_check (stream, COBJ);
+ type_assert (stream->co.cls == stream_s,
+ (lit("~a is not a stream"), stream, nao));
+
+ if (stream->co.ops == &strlist_out_ops.cobj_ops) {
+ val cell = (val) stream->co.handle;
+ cons_bind (lines, strstream, cell);
+ val stray = get_string_from_stream(strstream);
+ if (!zerop(length_str(stray)))
+ push(stray, &lines);
+ return nreverse(lines);
+ }
+
+ type_mismatch(lit("~s is not a string list stream"), stream);
+}
+
static val dir_get_line(val stream)
{
DIR *handle = (DIR *) stream->co.handle;