summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2021-08-04 20:52:10 -0700
committerKaz Kylheku <kaz@kylheku.com>2021-08-04 20:52:10 -0700
commit29b5a31ad6d3783e9bb178f35d21110bea06451e (patch)
tree4a19b7113c79b0d80e93c7501db45aac9fe9c1f8
parent75c6845ef1fc840afe995a84f3cd1c94f5257d7d (diff)
downloadtxr-29b5a31ad6d3783e9bb178f35d21110bea06451e.tar.gz
txr-29b5a31ad6d3783e9bb178f35d21110bea06451e.tar.bz2
txr-29b5a31ad6d3783e9bb178f35d21110bea06451e.zip
close-stream: make idemponent.
* stream.c (strm_base_init): Add new element to the initializer to initialize the close_result member to nao, indicating that the close operation has not been invoked. (strm_base_mark): Mark the close_result value, if it isn't nao. This is just in case it is a heap object. The structure delegate mechanism opens the possibility that the stream is actually user code that can return anything so we have to be careful. (close_stream): Only call ops->close if close_result is nao, indicating that close had never been called (or possibly that it had been called bu threw an exception) and store the return value in close_result, otherwise return the previously stored value. * stream.h (struct strm_base): New member, close_result. * txr.1: Documented.
-rw-r--r--stream.c16
-rw-r--r--stream.h1
-rw-r--r--txr.110
3 files changed, 17 insertions, 10 deletions
diff --git a/stream.c b/stream.c
index a1f5ead2..3f2cafb3 100644
--- a/stream.c
+++ b/stream.c
@@ -109,7 +109,7 @@ static val shell, shell_arg;
void strm_base_init(struct strm_base *s)
{
- static struct strm_base init = { indent_off, 60, 10, 0, 0, 0, 0, 0, 0 };
+ static struct strm_base init = { indent_off, 60, 10, 0, 0, 0, 0, 0, nao, 0 };
*s = init;
}
@@ -120,7 +120,8 @@ void strm_base_cleanup(struct strm_base *s)
void strm_base_mark(struct strm_base *s)
{
- (void) s;
+ if (s->close_result != nao)
+ gc_mark(s->close_result);
}
void stream_print_op(val stream, val out, val pretty, struct strm_ctx *ctx)
@@ -2971,9 +2972,14 @@ val real_time_stream_p(val obj)
val close_stream(val stream, val throw_on_error)
{
val self = lit("close-stream");
- struct strm_ops *ops = coerce(struct strm_ops *,
- cobj_ops(self, stream, stream_cls));
- return ops->close(stream, throw_on_error);
+ struct strm_base *s = coerce(struct strm_base *,
+ cobj_handle(self, stream, stream_cls));
+ struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops);
+
+ if (s->close_result == nao)
+ s->close_result = ops->close(stream, throw_on_error);
+
+ return s->close_result;
}
val get_error(val stream)
diff --git a/stream.h b/stream.h
index 3b9db2b3..e81dc8c1 100644
--- a/stream.h
+++ b/stream.h
@@ -55,6 +55,7 @@ struct strm_base {
unsigned force_break;
cnum max_length;
cnum max_depth;
+ val close_result;
struct strm_ctx *ctx;
};
diff --git a/txr.1 b/txr.1
index 280aff16..b4fe9a7f 100644
--- a/txr.1
+++ b/txr.1
@@ -56709,13 +56709,13 @@ instead of returning
If
.code close-stream
-is applied to a
+is called in such a way that it returns a value, without throwing an exception,
+that value is retained. Additional calls to the function with the same
.meta stream
-which is already closed, the operation returns
-.code nil
-regardless of the
+object return that same value without having any effect on the stream.
+These additional calls ignore the
.meta throw-on-error-p
-argument's value.
+argument.
.coNP Macro @ with-stream
.synb