summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog33
-rw-r--r--stream.c233
-rw-r--r--stream.h3
-rw-r--r--syslog.c4
4 files changed, 247 insertions, 26 deletions
diff --git a/ChangeLog b/ChangeLog
index 57278a06..788f2396 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+2015-07-06 Kaz Kylheku <kaz@kylheku.com>
+
+ Tightening behavior for unimplemented stream ops.
+
+ In many cases, if a stream operation is not applicable to a stream, it
+ is not appropriate to just do nothing and return nil. An error
+ must be thrown.
+
+ * stream.c (unimpl, unimpl_put_string, unimpl_put_char,
+ unimpl_put_byte, unimpl_get_line, unimpl_get_char, unimpl_get_byte,
+ unimpl_unget_char, unimpl_unget_byte, unimpl_seek, null_put_string,
+ null_put_char, null_put_byte, null_get_line, null_get_char,
+ null_get_byte, null_close, null_flush, null_seek, null_set_prop,
+ null_get_error, null_get_error_str, null_clear_error): New
+ static functions.
+ (fill_stream_ops): New function.
+ (null_ops): Use null_put_string, etc., instead of null pointers.
+ (stdio_clear_error, dir_clear_error, cat_clear_error): Return value now
+ indicating whether an error was cleared.
+ (stream_set_prop, stream_get_prop, real_time_stream_p, close_stream,
+ get_error, get_error_str, clear_error, get_line, get_char, get_byte,
+ unget_char, unget_byte, put_string, put_char, put_byte,
+ flush_stream): Do not test whether a function in the ops table
+ is defined; just call it, and return its value.
+ (stream_init): Call fill_stream_ops on all stream operation
+ structures so any null pointers are defaulted to appropriate
+ functions.
+
+ * stream.h (struct strm_ops): clear_error gets return value.
+ (fill_stream_ops): Declared.
+
+ * syslog.c (syslog_init): Call fill_stream_ops on syslog_strm_ops.
+
2015-07-04 Kaz Kylheku <kaz@kylheku.com>
Reduce regex duplication in genvim.txr.
diff --git a/stream.c b/stream.c
index 9c074ce2..23c2d214 100644
--- a/stream.c
+++ b/stream.c
@@ -77,6 +77,104 @@ static void null_stream_print(val stream, val out)
format(out, lit("#<~s null>"), stream->co.cls, nao);
}
+static noreturn void unimpl(val stream, val op)
+{
+ uw_throwf(file_error_s, lit("~a: not supported by stream ~s\n"),
+ op, stream, nao);
+ abort();
+}
+
+static noreturn val unimpl_put_string(val stream, val str)
+{
+ unimpl(stream, lit("put-string"));
+}
+
+static noreturn val unimpl_put_char(val stream, val ch)
+{
+ unimpl(stream, lit("put-char"));
+}
+
+static noreturn val unimpl_put_byte(val stream, int byte)
+{
+ unimpl(stream, lit("put-byte"));
+}
+
+static noreturn val unimpl_get_line(val stream)
+{
+ unimpl(stream, lit("get-line"));
+}
+
+static noreturn val unimpl_get_char(val stream)
+{
+ unimpl(stream, lit("get-char"));
+}
+
+static noreturn val unimpl_get_byte(val stream)
+{
+ unimpl(stream, lit("get-byte"));
+}
+
+static noreturn val unimpl_unget_char(val stream, val ch)
+{
+ unimpl(stream, lit("unget-char"));
+}
+
+static noreturn val unimpl_unget_byte(val stream, int byte)
+{
+ unimpl(stream, lit("unget-byte"));
+}
+
+static noreturn val unimpl_seek(val stream, cnum off, enum strm_whence whence)
+{
+ unimpl(stream, lit("seek"));
+}
+
+static val null_put_string(val stream, val str)
+{
+ return nil;
+}
+
+static val null_put_char(val stream, val ch)
+{
+ return nil;
+}
+
+static val null_put_byte(val stream, int byte)
+{
+ return nil;
+}
+
+static val null_get_line(val stream)
+{
+ return nil;
+}
+
+static val null_get_char(val stream)
+{
+ return nil;
+}
+
+static val null_get_byte(val stream)
+{
+ return nil;
+}
+
+static val null_close(val stream, val throw_on_error)
+{
+ return nil;
+}
+
+static val null_flush(val stream)
+{
+ return nil;
+}
+
+static val null_seek(val stream, cnum off, enum strm_whence whence)
+{
+ return nil;
+}
+
+
static val null_get_prop(val stream, val ind)
{
if (ind == name_k)
@@ -84,14 +182,74 @@ static val null_get_prop(val stream, val ind)
return nil;
}
+static val null_set_prop(val stream, val ind, val value)
+{
+ return nil;
+}
+
+static val null_get_error(val stream)
+{
+ return nil;
+}
+
+static val null_get_error_str(val stream)
+{
+ return nil;
+}
+
+static val null_clear_error(val stream)
+{
+ return nil;
+}
+
+void fill_stream_ops(struct strm_ops *ops)
+{
+ if (!ops->put_string)
+ ops->put_string = unimpl_put_string;
+ if (!ops->put_char)
+ ops->put_char = unimpl_put_char;
+ if (!ops->put_byte)
+ ops->put_byte = unimpl_put_byte;
+ if (!ops->get_line)
+ ops->get_line = unimpl_get_line;
+ if (!ops->get_char)
+ ops->get_char = unimpl_get_char;
+ if (!ops->get_byte)
+ ops->get_byte = unimpl_get_byte;
+ if (!ops->unget_char)
+ ops->unget_char = unimpl_unget_char;
+ if (!ops->unget_byte)
+ ops->unget_byte = unimpl_unget_byte;
+ if (!ops->close)
+ ops->close = null_close;
+ if (!ops->flush)
+ ops->flush = null_flush;
+ if (!ops->seek)
+ ops->seek = unimpl_seek;
+ if (!ops->get_prop)
+ ops->get_prop = null_get_prop;
+ if (!ops->set_prop)
+ ops->set_prop = null_set_prop;
+ if (!ops->get_error)
+ ops->get_error = null_get_error;
+ if (!ops->get_error_str)
+ ops->get_error_str = null_get_error_str;
+ if (!ops->clear_error)
+ ops->clear_error = null_clear_error;
+}
+
static struct strm_ops null_ops =
strm_ops_init(cobj_ops_init(eq,
null_stream_print,
cobj_destroy_stub_op,
cobj_mark_op,
cobj_hash_op),
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- null_get_prop, 0, 0, 0, 0);
+ null_put_string, null_put_char, null_put_byte, null_get_line,
+ null_get_char, null_get_byte,
+ unimpl_unget_char, unimpl_unget_byte,
+ null_close, null_flush, null_seek, null_get_prop,
+ null_set_prop, null_get_error, null_get_error_str,
+ null_clear_error);
val make_null_stream(void)
{
@@ -325,12 +483,22 @@ static val stdio_get_error_str(val stream)
return errno_to_string(h->err);
}
-static void stdio_clear_error(val stream)
+static val stdio_clear_error(val stream)
{
struct stdio_handle *h = coerce(struct stdio_handle *, stream->co.handle);
- if (h->f != 0)
+ val ret = nil;
+
+ if (h->err) {
+ h->err = nil;
+ ret = t;
+ }
+
+ if (h->f != 0 && (feof(h->f) || ferror(h->f))) {
clearerr(h->f);
- h->err = nil;
+ ret = t;
+ }
+
+ return ret;
}
static wchar_t *snarf_line(struct stdio_handle *h)
@@ -1201,10 +1369,14 @@ static val dir_get_error_str(val stream)
return errno_to_string(h->err);
}
-static void dir_clear_error(val stream)
+static val dir_clear_error(val stream)
{
struct dir_handle *h = coerce(struct dir_handle *, stream->co.handle);
- h->err = nil;
+ if (h->err) {
+ h->err = nil;
+ return t;
+ }
+ return nil;
}
static struct strm_ops dir_ops =
@@ -1473,7 +1645,7 @@ val stream_set_prop(val stream, val ind, val prop)
{
struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops);
- return ops->set_prop ? ops->set_prop(stream, ind, prop) : nil;
+ return ops->set_prop(stream, ind, prop);
}
}
@@ -1485,7 +1657,7 @@ val stream_get_prop(val stream, val ind)
{
struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops);
- return ops->get_prop ? ops->get_prop(stream, ind) : nil;
+ return ops->get_prop(stream, ind);
}
}
@@ -1493,7 +1665,7 @@ val real_time_stream_p(val obj)
{
if (streamp(obj)) {
struct strm_ops *ops = coerce(struct strm_ops *, obj->co.ops);
- return ops->get_prop ? ops->get_prop(obj, real_time_k) : nil;
+ return ops->get_prop(obj, real_time_k);
}
return nil;
@@ -1507,26 +1679,26 @@ val close_stream(val stream, val throw_on_error)
{
struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops);
- return ops->close ? ops->close(stream, throw_on_error) : nil;
+ return ops->close(stream, throw_on_error);
}
}
val get_error(val stream)
{
struct strm_ops *ops = coerce(struct strm_ops *, cobj_ops(stream, stream_s));
- return ops->get_error ? ops->get_error(stream) : nil;
+ return ops->get_error(stream);
}
val get_error_str(val stream)
{
struct strm_ops *ops = coerce(struct strm_ops *, cobj_ops(stream, stream_s));
- return ops->get_error_str ? ops->get_error_str(stream) : lit("no error");
+ return ops->get_error_str(stream);
}
val clear_error(val stream)
{
struct strm_ops *ops = coerce(struct strm_ops *, cobj_ops(stream, stream_s));
- return ops->clear_error ? (ops->clear_error(stream), t) : nil;
+ return ops->clear_error(stream);
}
val get_line(val stream)
@@ -1539,7 +1711,7 @@ val get_line(val stream)
{
struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops);
- return ops->get_line ? ops->get_line(stream) : nil;
+ return ops->get_line(stream);
}
}
@@ -1553,7 +1725,7 @@ val get_char(val stream)
{
struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops);
- return ops->get_char ? ops->get_char(stream) : nil;
+ return ops->get_char(stream);
}
}
@@ -1567,7 +1739,7 @@ val get_byte(val stream)
{
struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops);
- return ops->get_byte ? ops->get_byte(stream) : nil;
+ return ops->get_byte(stream);
}
}
@@ -1581,7 +1753,7 @@ val unget_char(val ch, val stream)
{
struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops);
- return ops->unget_char ? ops->unget_char(stream, ch) : nil;
+ return ops->unget_char(stream, ch);
}
}
@@ -1601,7 +1773,7 @@ val unget_byte(val byte, val stream)
{
struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops);
- return ops->unget_byte ? ops->unget_byte(stream, b) : nil;
+ return ops->unget_byte(stream, b);
}
}
@@ -2160,7 +2332,7 @@ val put_string(val string, val stream)
{
struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops);
- return ops->put_string ? ops->put_string(stream, string) : nil;
+ return ops->put_string(stream, string);
}
}
@@ -2174,7 +2346,7 @@ val put_char(val ch, val stream)
{
struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops);
- return ops->put_char ? ops->put_char(stream, ch) : nil;
+ return ops->put_char(stream, ch);
}
}
@@ -2194,7 +2366,7 @@ val put_byte(val byte, val stream)
{
struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops);
- return ops->put_byte ? ops->put_byte(stream, b) : nil;
+ return ops->put_byte(stream, b);
}
}
@@ -2229,7 +2401,7 @@ val flush_stream(val stream)
{
struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops);
- return ops->flush ? ops->flush(stream) : t;
+ return ops->flush(stream);
}
}
@@ -2757,10 +2929,10 @@ static val cat_get_error_str(val stream)
return if3(streams, get_error_str(first(streams)), lit("eof"));
}
-static void cat_clear_error(val stream)
+static val cat_clear_error(val stream)
{
val streams = coerce(val, stream->co.handle);
- if2(streams, clear_error(first(streams)));
+ return if2(streams, clear_error(first(streams)));
}
static struct strm_ops cat_stream_ops =
@@ -2961,4 +3133,15 @@ void stream_init(void)
reg_fun(intern(lit("open-files"), user_package), func_n2o(open_files, 1));
reg_fun(intern(lit("open-files*"), user_package), func_n2o(open_files_star, 1));
reg_fun(intern(lit("abs-path-p"), user_package), func_n1(abs_path_p));
+
+ fill_stream_ops(&null_ops);
+ fill_stream_ops(&stdio_ops);
+ fill_stream_ops(&tail_ops);
+ fill_stream_ops(&pipe_ops);
+ fill_stream_ops(&string_in_ops);
+ fill_stream_ops(&byte_in_ops);
+ fill_stream_ops(&string_out_ops);
+ fill_stream_ops(&strlist_out_ops);
+ fill_stream_ops(&dir_ops);
+ fill_stream_ops(&cat_stream_ops);
}
diff --git a/stream.h b/stream.h
index ed947577..2162045e 100644
--- a/stream.h
+++ b/stream.h
@@ -47,7 +47,7 @@ struct strm_ops {
val (*set_prop)(val, val ind, val);
val (*get_error)(val);
val (*get_error_str)(val);
- void (*clear_error)(val);
+ val (*clear_error)(val);
};
#define strm_ops_init(cobj_init_macro, put_string, put_char, put_byte, \
@@ -77,6 +77,7 @@ extern val format_s;
extern val stdin_s, stdout_s, stddebug_s, stderr_s, stdnull_s;
+void fill_stream_ops(struct strm_ops *ops);
val make_null_stream(void);
val make_stdio_stream(FILE *, val descr);
val make_tail_stream(FILE *, val descr);
diff --git a/syslog.c b/syslog.c
index d4c5fb8a..cfc24cb8 100644
--- a/syslog.c
+++ b/syslog.c
@@ -45,6 +45,8 @@
val prio_k;
+static struct strm_ops syslog_strm_ops;
+
void syslog_init(void)
{
reg_var(intern(lit("log-pid"), user_package), num_fast(LOG_PID));
@@ -77,6 +79,8 @@ void syslog_init(void)
prio_k = intern(lit("prio"), keyword_package);
reg_var(intern(lit("*stdlog*"), user_package), make_syslog_stream(num_fast(LOG_INFO)));
+
+ fill_stream_ops(&syslog_strm_ops);
}
val openlog_wrap(val wident, val optmask, val facility)