summaryrefslogtreecommitdiffstats
path: root/strudel.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-12-08 18:11:59 -0800
committerKaz Kylheku <kaz@kylheku.com>2017-12-08 18:11:59 -0800
commitc71b79a13a7960f255e6e1d66ca543daba328771 (patch)
tree30bf8f53afcf65ad0b8500ef879a5a4e99868dd9 /strudel.c
parent8834a98cff2d8f80458957fccab5424f4b90cde5 (diff)
downloadtxr-c71b79a13a7960f255e6e1d66ca543daba328771.tar.gz
txr-c71b79a13a7960f255e6e1d66ca543daba328771.tar.bz2
txr-c71b79a13a7960f255e6e1d66ca543daba328771.zip
New feature: structure delegate streams.
A new kind of stream object which redirects its operations to the methods of a structure. * Makefile (OBJS): New object file, strudel.o. * lib.c (init): Call new strudel_init function. * lisplib.c (stream_wrap_set_entries, stream_wrap_instantiate): New static functions. (lisplib_init): Arrange for autloading of new stream-wrap.tl. * share/txr/stdlib/stream-wrap.tl: New file. * stream.c (put_string_s, put_char_s, put_byte_s, get_line_s, get_char_s, get_byte_s, unget_char_s, unget_byte_s, put_buf_s, fill_buf_s, flush_s, seek_s, truncate_s, get_prop_s, set_prop_s, get_error_s, get_error_str_s, clear_error_s, get_fd_s): New symbol variables. (stream_init): New symbol variables initialized. Numerous functions registered via these variables now rather than intern(...) expressions. * stream.h (put_string_s, put_char_s, put_byte_s, get_line_s, get_char_s, get_byte_s, unget_char_s, unget_byte_s, put_buf_s, fill_buf_s, flush_s, seek_s, truncate_s, get_prop_s, set_prop_s, get_error_s, get_error_str_s, clear_error_s, get_fd_s): Declared. * strudel.c, strudel.h: New files.
Diffstat (limited to 'strudel.c')
-rw-r--r--strudel.c271
1 files changed, 271 insertions, 0 deletions
diff --git a/strudel.c b/strudel.c
new file mode 100644
index 00000000..05971cac
--- /dev/null
+++ b/strudel.c
@@ -0,0 +1,271 @@
+/* Copyright 2017
+ * Kaz Kylheku <kaz@kylheku.com>
+ * Vancouver, Canada
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <wchar.h>
+#include <signal.h>
+#include <dirent.h>
+#include <syslog.h>
+#include "config.h"
+#include ALLOCA_H
+#include "lib.h"
+#include "stream.h"
+#include "gc.h"
+#include "args.h"
+#include "utf8.h"
+#include "eval.h"
+#include "struct.h"
+#include "strudel.h"
+
+struct strudel_base { /* stru-ct del-egate :) */
+ struct strm_base a;
+ val obj;
+};
+
+static void strudel_base_mark(struct strudel_base *sb)
+{
+ strm_base_mark(&sb->a);
+ gc_mark(sb->obj);
+}
+
+static void strudel_mark_op(val stream)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ strudel_base_mark(sb);
+}
+
+static val strudel_put_string(val stream, val str)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, put_string_s);
+ return funcall2(meth, obj, str);
+}
+
+static val strudel_put_char(val stream, val ch)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, put_char_s);
+ return funcall2(meth, obj, ch);
+}
+
+static val strudel_put_byte(val stream, int byte)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, put_byte_s);
+ return funcall2(meth, obj, num_fast(byte));
+}
+
+static val strudel_get_line(val stream)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, get_line_s);
+ return funcall1(meth, obj);
+}
+
+static val strudel_get_char(val stream)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, get_char_s);
+ return funcall1(meth, obj);
+}
+
+static val strudel_get_byte(val stream)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, get_byte_s);
+ return funcall1(meth, obj);
+}
+
+static val strudel_unget_char(val stream, val ch)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, unget_char_s);
+ return funcall2(meth, obj, ch);
+}
+
+static val strudel_unget_byte(val stream, int byte)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, unget_byte_s);
+ return funcall2(meth, obj, num_fast(byte));
+}
+
+static val strudel_put_buf(val stream, val buf, cnum pos)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, put_buf_s);
+ return funcall3(meth, obj, buf, num(pos));
+}
+
+static val strudel_fill_buf(val stream, val buf, cnum pos)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, fill_buf_s);
+ return funcall3(meth, obj, buf, num(pos));
+}
+
+static val strudel_close(val stream, val throw_on_error)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, close_s);
+ return funcall2(meth, obj, throw_on_error);
+}
+
+static val strudel_flush(val stream)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, flush_s);
+ return funcall1(meth, obj);
+}
+
+static val strudel_seek(val stream, val off, enum strm_whence whence)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val wh;
+ val obj = sb->obj;
+ val meth = slot(obj, seek_s);
+
+ switch (whence) {
+ default:
+ case strm_start:
+ wh = from_start_k;
+ break;
+ case strm_cur:
+ wh = from_current_k;
+ break;
+ case strm_end:
+ wh = from_end_k;
+ break;
+ }
+
+ return funcall3(meth, obj, off, wh);
+}
+
+static val strudel_truncate(val stream, val len)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, truncate_s);
+ return funcall2(meth, obj, len);
+}
+
+static val strudel_get_prop(val stream, val ind)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, get_prop_s);
+ return funcall2(meth, obj, ind);
+}
+
+static val strudel_set_prop(val stream, val ind, val value)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, set_prop_s);
+ return funcall3(meth, obj, ind, value);
+}
+
+static val strudel_get_error(val stream)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, get_error_s);
+ return funcall1(meth, obj);
+}
+
+static val strudel_get_error_str(val stream)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, get_error_str_s);
+ return funcall1(meth, obj);
+}
+
+static val strudel_clear_error(val stream)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, clear_error_s);
+ return funcall1(meth, obj);
+}
+
+static val strudel_get_fd(val stream)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *, stream->co.handle);
+ val obj = sb->obj;
+ val meth = slot(obj, get_fd_s);
+ return funcall1(meth, obj);
+}
+
+static struct strm_ops strudel_ops =
+ strm_ops_init(cobj_ops_init(eq,
+ stream_print_op,
+ stream_destroy_op,
+ strudel_mark_op,
+ cobj_eq_hash_op),
+ wli("struct-delegate-stream"),
+ strudel_put_string, strudel_put_char, strudel_put_byte,
+ strudel_get_line, strudel_get_char, strudel_get_byte,
+ strudel_unget_char, strudel_unget_byte,
+ strudel_put_buf, strudel_fill_buf,
+ strudel_close, strudel_flush, strudel_seek,
+ strudel_truncate, strudel_get_prop, strudel_set_prop,
+ strudel_get_error, strudel_get_error_str,
+ strudel_clear_error, strudel_get_fd);
+
+val make_struct_delegate_stream(val target_obj)
+{
+ struct strudel_base *sb = coerce(struct strudel_base *,
+ chk_malloc(sizeof *sb));
+ val stream;
+ strm_base_init(&sb->a);
+ sb->obj = nil;
+ stream = cobj(coerce(mem_t *, sb), stream_s, &strudel_ops.cobj_ops);
+ sb->obj = target_obj;
+ return stream;
+}
+
+void strudel_init(void)
+{
+ reg_fun(intern(lit("make-struct-delegate-stream"), user_package), func_n1(make_struct_delegate_stream));
+ fill_stream_ops(&strudel_ops);
+}