diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2025-05-24 21:09:02 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2025-05-24 21:09:02 -0700 |
commit | a76b786482431a3cc3a85d493ca3e972a0ee027a (patch) | |
tree | 71c942abac780422d6903167f428b6aab92eaa31 | |
parent | 2707ec86cb50f81cce392fb2024f9e854cdf1b6a (diff) | |
download | txr-a76b786482431a3cc3a85d493ca3e972a0ee027a.tar.gz txr-a76b786482431a3cc3a85d493ca3e972a0ee027a.tar.bz2 txr-a76b786482431a3cc3a85d493ca3e972a0ee027a.zip |
streams: replace get_line virtual with new interface.
* stream.h (struct strm_ops): The simple get_line
virtual is replaced by get_string, which takes
a character limit and a delimiting stop character.
(strm_ops_init): Rename get_line parameter to get_string.
(get_string_s): Declared.
(generic_get_line): Declaration removed.
(generic_get_string, get_delimited_string): Declared.
* stream.c (get_string_s): New symbol variable.
(unimpl_get_line): Function removed.
(unimpl_get_string): New function.
(null_get_line): Function removed.
(null_get_string): New function.
(fill_stream_ops): Configure ops->get_string
rather than ops->get_line.
(null_ops): Wire null_get_string in place of
null_get_line.
(generic_get_line): Renamed to generic_get_string.
(generic_get_string): Implement the limit and stop_char
parameters.
(get_line_limited_check): New static function.
(stdio_ops): Wire in generic_get_string instead of
generic_get_line.
(tail_get_line): Replaced by tail_get_string.
(tail_get_string): Call generic_get_string instead of
generic_get_line, and pass the limit and stop_char
arguments down.
(tail_ops): Wire in tail_get_string instead of tail_get_line.
(pipe_ops): Wire generic_get_string instead of generic_get_line.
(dir_get_line): Renamed to dir_get_string.
(dir_get_string): Use get_line_limited_check to defend
against unhandled argument values.
(dir_ops): Wire dir_get_string instead of dir_get_line.
(string_in_get_line): Replaced by string_in_get_string.
(string_in_get_string): Implement limit and stop_char
parameters.
(string_in_ops): Wire string_in_get_string instead of
string_in_get_line.
(strlist_in_get_line): Replaced with strlist_in_get_string.
(strlist_in_get_string): Use get_line_limited_check to
defend against unsupported arguments.
(strlist_in_ops): Wire in strlist_in_get_string instead
of strlist_in_get_line.
(cat_get_line): Replaced by cat_get_string.
(cat_get_string): Rather than recursing into the get_line
public interface, we fetch the stream's get_string
virtual and pass all arguments to it.
(cat_stream_ops): Wire cat_get_string instead of cat_get_line.
(record_adapter_get_line): Replaced by record_adapter_get_string.
(record_adapter_get_string): use get_line_limited_check
to guard against unsupported arguments.
(record_adapter_ops): Wire record_adapter_get_string instead
of record_adapter_get_line.
(get_line): Implement using get_string virtual now.
We pass UINT_PTR_MAX as limit, which means no character limit,
and '\n' as the delimiter for reading a line.
(get_delimited_string): New function, which exposes
the full semantics of the get_string virtual.
(stream_init): Initialize get_string_s.
Register get-delimited-string function.
Use get_string_s symbol in registration of get-string.
* strudel.c (strudel_get_line): Replaced by strudel_get_string.
(strudel_get_string): Call look up the get-string method
and pass all arguments to it, encoded into Lisp values
in the right way, nil indicating not present.
(strudel_ops): Wire strudel_get_string in place of
strudel_get_line.
* parser.c (shadow_ops_template): Replace generic_get_line
with generic_get_string.
* buf.c (buf_strm_ops): Likewise.
* socket.c (dgram_strm_ops): Likewise.
* gzio.c (gzio_ops_rd): Likewise.
* stdlib/stream-wrap.tl (stream-wrap get-line): Method
replaced by (stream-wrap get-string). This calls
get-delimited-string rather than get-line.
* tests/018/streams.tl: New tests, mainly concerned
with the new logic in the string input stream which
has its own implementation of get_string with several
cases.
* txr.1: Document new get-delimited-string function,
and the get-string method of the delegate stream,
removing the documentation for removed get-line method.
-rw-r--r-- | buf.c | 2 | ||||
-rw-r--r-- | gzio.c | 2 | ||||
-rw-r--r-- | parser.c | 2 | ||||
-rw-r--r-- | socket.c | 2 | ||||
-rw-r--r-- | stdlib/stream-wrap.tl | 5 | ||||
-rw-r--r-- | stream.c | 140 | ||||
-rw-r--r-- | stream.h | 11 | ||||
-rw-r--r-- | strudel.c | 10 | ||||
-rw-r--r-- | tests/018/streams.tl | 55 | ||||
-rw-r--r-- | txr.1 | 63 |
10 files changed, 239 insertions, 53 deletions
@@ -1279,7 +1279,7 @@ static struct strm_ops buf_strm_ops = buf_strm_put_string, buf_strm_put_char, buf_strm_put_byte, - generic_get_line, + generic_get_string, buf_strm_get_char, buf_strm_get_byte, buf_strm_unget_char, @@ -450,7 +450,7 @@ static struct strm_ops gzio_ops_rd = 0, 0, 0, - generic_get_line, + generic_get_string, gzio_get_char, gzio_get_byte, gzio_unget_char, @@ -2297,7 +2297,7 @@ static struct strm_ops shadow_ops_template = 0), wli("shadow-stream"), shadow_put_string, shadow_put_char, shadow_put_byte, - generic_get_line, shadow_get_char, shadow_get_byte, + generic_get_string, shadow_get_char, shadow_get_byte, shadow_unget_char, shadow_unget_byte, shadow_put_buf, shadow_fill_buf, shadow_close, shadow_flush, shadow_seek, shadow_truncate, @@ -685,7 +685,7 @@ static_def(struct strm_ops dgram_strm_ops = dgram_put_string, dgram_put_char, dgram_put_byte, - generic_get_line, + generic_get_string, dgram_get_char, dgram_get_byte, dgram_unget_char, diff --git a/stdlib/stream-wrap.tl b/stdlib/stream-wrap.tl index a257e741..60c7cd1e 100644 --- a/stdlib/stream-wrap.tl +++ b/stdlib/stream-wrap.tl @@ -33,8 +33,9 @@ (put-char chr me.stream)) (:method put-byte (me byte) (put-byte byte me.stream)) - (:method get-line (me) - (get-line me.stream)) + (:method get-string (me nchars stopchar self) + (ignore self) + (get-delimited-string me.stream nchars stopchar)) (:method get-char (me) (get-char me.stream)) (:method get-byte (me) @@ -92,7 +92,7 @@ val stdin_s, stdout_s, stddebug_s, stderr_s, stdnull_s; val put_string_s, put_char_s, put_byte_s, get_line_s, get_char_s; val get_byte_s, unget_char_s, unget_byte_s, put_buf_s, fill_buf_s; val flush_s, seek_s, truncate_s, get_prop_s, set_prop_s; -val get_error_s, get_error_str_s, clear_error_s, get_fd_s; +val get_error_s, get_error_str_s, clear_error_s, get_fd_s, get_string_s; val print_flo_precision_s, print_flo_digits_s, print_flo_format_s; val pprint_flo_format_s, print_base_s, print_circle_s; @@ -183,9 +183,13 @@ static NORETURN val unimpl_put_byte(val stream, int byte) unimpl(stream, lit("put-byte")); } -static NORETURN val unimpl_get_line(val stream) +static NORETURN val unimpl_get_string(val stream, ucnum limit, + wint_t stopchar, val self) { - unimpl(stream, lit("get-line")); + (void) limit; + (void) stopchar; + (void) self; + unimpl(stream, self); } static NORETURN val unimpl_get_char(val stream) @@ -281,9 +285,12 @@ static val null_put_byte(val stream, int byte) return nil; } -static val null_get_line(val stream) +static val null_get_string(val stream, ucnum limit, wint_t stopchar, val self) { (void) stream; + (void) limit; + (void) stopchar; + (void) self; return nil; } @@ -406,8 +413,8 @@ void fill_stream_ops(struct strm_ops *ops) 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_string) + ops->get_string = unimpl_get_string; if (!ops->get_char) ops->get_char = unimpl_get_char; if (!ops->get_byte) @@ -497,7 +504,7 @@ static struct strm_ops null_ops = cobj_eq_hash_op, 0), wli("null-stream"), - null_put_string, null_put_char, null_put_byte, null_get_line, + null_put_string, null_put_char, null_put_byte, null_get_string, null_get_char, null_get_byte, unimpl_unget_char, unimpl_unget_byte, unimpl_put_buf, unimpl_fill_buf, @@ -830,17 +837,20 @@ static val stdio_get_fd(val stream) return h->f ? num(fileno(h->f)) : nil; } -val generic_get_line(val stream) +val generic_get_string(val stream, ucnum limit, wint_t stopchar, val self) { const size_t min_size = 512; size_t size = 0; size_t fill = 0; wchar_t *volatile buf = 0; val out = nil; + ucnum count = limit; + + (void) self; uw_simple_catch_begin; - for (;;) { + for (; limit == UINT_PTR_MAX || count > 0; --count) { struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops); val chr = ops->get_char(stream); wint_t ch = chr ? convert(wint_t, c_chr(chr)) : WEOF; @@ -855,7 +865,7 @@ val generic_get_line(val stream) size = newsize; } - if (ch == '\n' || ch == WEOF) { + if (ch == stopchar || ch == WEOF) { buf[fill++] = 0; break; } @@ -882,6 +892,20 @@ val generic_get_line(val stream) return out; } +static void get_line_limited_check(val stream, ucnum limit, + wint_t stopchar, val self) +{ + if (limit != UINT_PTR_MAX) + uw_throwf(file_error_s, + lit("~a: ~s doesn't support count-limited string read"), + self, stream, nao); + + if (stopchar != '\n' && stopchar != WEOF) + uw_throwf(file_error_s, + lit("~a: ~s doesn't read delimited by character ~s"), + self, stream, chr(stopchar), nao); +} + static val stdio_get_char(val stream) { struct stdio_handle *h = coerce(struct stdio_handle *, stream->co.handle); @@ -1123,7 +1147,7 @@ static struct strm_ops stdio_ops = stdio_put_string, stdio_put_char, stdio_put_byte, - generic_get_line, + generic_get_string, stdio_get_char, stdio_get_byte, stdio_unget_char, @@ -1314,12 +1338,12 @@ static void tail_strategy(val stream, unsigned long *state) } } -static val tail_get_line(val stream) +static val tail_get_string(val stream, ucnum limit, wint_t stopchar, val self) { unsigned long state = 0; val ret; - while ((ret = generic_get_line(stream)) == nil) + while ((ret = generic_get_string(stream, limit, stopchar, self)) == nil) tail_strategy(stream, &state); return ret; @@ -1358,7 +1382,7 @@ static struct strm_ops tail_ops = stdio_put_string, stdio_put_char, stdio_put_byte, - tail_get_line, + tail_get_string, tail_get_char, tail_get_byte, stdio_unget_char, @@ -1440,7 +1464,7 @@ static struct strm_ops pipe_ops = stdio_put_string, stdio_put_char, stdio_put_byte, - generic_get_line, + generic_get_string, stdio_get_char, stdio_get_byte, stdio_unget_char, @@ -1866,10 +1890,15 @@ static void dir_mark(val stream) gc_mark(h->err); } -static val dir_get_line(val stream) +static val dir_get_string(val stream, ucnum limit, wint_t stopchar, val self) { struct dir_handle *h = coerce(struct dir_handle *, stream->co.handle); + get_line_limited_check(stream, limit, stopchar, self); + + (void) limit; + (void) stopchar; + if (h->d == 0) { return nil; } else { @@ -1929,7 +1958,7 @@ static struct strm_ops dir_ops = 0), wli("dir-stream"), 0, 0, 0, - dir_get_line, + dir_get_string, 0, 0, 0, 0, 0, 0, dir_close, 0, 0, 0, 0, 0, @@ -1970,15 +1999,36 @@ static val find_char(val string, val start, val ch) return nil; } -static val string_in_get_line(val stream) +static val string_in_get_string(val stream, ucnum limit, + wint_t stopchar, val self) { struct string_in *s = coerce(struct string_in *, stream->co.handle); + (void) self; if (length_str_gt(s->string, s->pos)) { - val nlpos = find_char(s->string, s->pos, chr('\n')); - val result = sub_str(s->string, s->pos, nlpos); - set(mkloc(s->pos, stream), nlpos ? plus(nlpos, one) : length_str(s->string)); - return result; + if (limit == UINT_PTR_MAX && stopchar != WEOF) { + val chpos = find_char(s->string, s->pos, chr(stopchar)); + val result = sub_str(s->string, s->pos, chpos); + set(mkloc(s->pos, stream), chpos ? plus(chpos, one) : length_str(s->string)); + return result; + } else if (limit == UINT_PTR_MAX && stopchar == WEOF) { + val result = sub_str(s->string, s->pos, nil);; + set(mkloc(s->pos, stream), length_str(s->string)); + return result; + } else if (limit != UINT_PTR_MAX && stopchar == WEOF) { + val topos = min2(length_str(s->string), plus(s->pos, unum(limit))); + val result = sub_str(s->string, s->pos, topos); + set(mkloc(s->pos, stream), topos); + return result; + } else { + val lpos = min2(length_str(s->string), plus(s->pos, unum(limit))); + val chpos = find_char(s->string, s->pos, chr(stopchar)); + val topos = chpos ? min2(lpos, chpos) : lpos; + val nxpos = chpos ? min2(lpos, succ(chpos)) : lpos; + val result = sub_str(s->string, s->pos, topos); + set(mkloc(s->pos, stream), nxpos); + return result; + } } return nil; @@ -2049,7 +2099,7 @@ static struct strm_ops string_in_ops = 0), wli("string-input-stream"), 0, 0, 0, - string_in_get_line, + string_in_get_string, string_in_get_char, 0, string_in_unget_char, @@ -2242,10 +2292,13 @@ static void strlist_in_stream_mark(val stream) gc_mark(s->list); } -static val strlist_in_get_line(val stream) +static val strlist_in_get_string(val stream, ucnum limit, + wint_t stopchar, val self) { struct strlist_in *s = coerce(struct strlist_in *, stream->co.handle); + get_line_limited_check(stream, limit, stopchar, self); + if (s->string) { val result = sub_str(s->string, s->pos, t); s->string = pop(&s->list); @@ -2339,7 +2392,7 @@ static struct strm_ops strlist_in_ops = 0), wli("strlist-input-stream"), 0, 0, 0, - strlist_in_get_line, + strlist_in_get_string, strlist_in_get_char, 0, strlist_in_unget_char, @@ -2662,14 +2715,17 @@ static void cat_stream_print(val stream, val out, val pretty, format(out, lit("#<~a ~s>"), name, s->streams, nao); } -static val cat_get_line(val stream) +static val cat_get_string(val stream, ucnum limit, wint_t stopchar, val self) { + uses_or2; struct cat_strm *s = coerce(struct cat_strm *, stream->co.handle); val streams = s->streams; while (streams) { - val fs = first(streams); - val line = get_line(fs); + val fs = or2(first(streams), std_input); + struct strm_ops *ops = coerce(struct strm_ops *, + cobj_ops(self, fs, stream_cls)); + val line = ops->get_string(fs, limit, stopchar, self); if (line) return line; if ((streams = rest(streams)) != nil) { @@ -2793,7 +2849,7 @@ static struct strm_ops cat_stream_ops = 0), wli("catenated-stream"), 0, 0, 0, - cat_get_line, + cat_get_string, cat_get_char, cat_get_byte, cat_unget_char, @@ -3037,10 +3093,12 @@ static void record_adapter_mark_op(val stream) record_adapter_base_mark(rb); } -static val record_adapter_get_line(val stream) +static val record_adapter_get_string(val stream, ucnum limit, + wint_t stopchar, val self) { struct record_adapter_base *rb = coerce(struct record_adapter_base *, stream->co.handle); + get_line_limited_check(stream, limit, stopchar, self); return read_until_match(rb->regex, rb->db.target_stream, rb->include_match); } @@ -3053,7 +3111,7 @@ static struct strm_ops record_adapter_ops = 0), wli("record-adapter"), delegate_put_string, delegate_put_char, delegate_put_byte, - record_adapter_get_line, delegate_get_char, delegate_get_byte, + record_adapter_get_string, delegate_get_char, delegate_get_byte, delegate_unget_char, delegate_unget_byte, delegate_put_buf, delegate_fill_buf, delegate_close, delegate_flush, delegate_seek, @@ -3161,7 +3219,21 @@ val get_line(val stream_in) val stream = default_arg_strict(stream_in, std_input); struct strm_ops *ops = coerce(struct strm_ops *, cobj_ops(self, stream, stream_cls)); - return ops->get_line(stream); + return ops->get_string(stream, UINT_PTR_MAX, '\n', self); +} + +val get_delimited_string(val stream_in, val nchars_in, val stop_char_in) +{ + val self = lit("get-delimited-string"); + val stream = default_arg_strict(stream_in, std_input); + struct strm_ops *ops = coerce(struct strm_ops *, + cobj_ops(self, stream, stream_cls)); + val nchars = default_null_arg(nchars_in); + val stop_char = default_null_arg(stop_char_in); + ucnum nc = if3(nchars, c_unum(nchars, self), UINT_PTR_MAX); + wint_t sc = if3(stop_char, convert(wint_t, c_chr(stop_char)), WEOF); + + return ops->get_string(stream, nc, sc, self); } val get_char(val stream_in) @@ -5769,6 +5841,7 @@ void stream_init(void) put_char_s = intern(lit("put-char"), user_package); put_byte_s = intern(lit("put-byte"), user_package); get_line_s = intern(lit("get-line"), user_package); + get_string_s = intern(lit("get-string"), user_package); get_char_s = intern(lit("get-char"), user_package); get_byte_s = intern(lit("get-byte"), user_package); unget_char_s = intern(lit("unget-char"), user_package); @@ -5839,9 +5912,10 @@ void stream_init(void) reg_fun(get_error_str_s, func_n1(get_error_str)); reg_fun(clear_error_s, func_n1(clear_error)); reg_fun(get_line_s, func_n1o(get_line, 0)); + reg_fun(intern(lit("get-delimited-string"), user_package), func_n3o(get_delimited_string, 0)); reg_fun(get_char_s, func_n1o(get_char, 0)); reg_fun(get_byte_s, func_n1o(get_byte, 0)); - reg_fun(intern(lit("get-string"), user_package), func_n3o(get_string, 0)); + reg_fun(get_string_s, func_n3o(get_string, 0)); reg_fun(put_string_s, func_n2o(put_string, 1)); reg_fun(intern(lit("put-line"), user_package), func_n2o(put_line, 0)); reg_fun(put_char_s, func_n2o(put_char, 1)); @@ -70,7 +70,7 @@ struct strm_ops { val (*put_string)(val, val); val (*put_char)(val, val); val (*put_byte)(val, int); - val (*get_line)(val); + val (*get_string)(val, ucnum limit, wint_t stopchar, val self); val (*get_char)(val); val (*get_byte)(val); val (*unget_char)(val, val); @@ -94,12 +94,12 @@ struct strm_ops { }; #define strm_ops_init(cobj_init_macro, name, put_string, put_char, put_byte, \ - get_line, get_char, get_byte, unget_char, unget_byte, \ + get_string, get_char, get_byte, unget_char, unget_byte,\ put_buf, fill_buf, \ close, flush, seek, truncate, get_prop, set_prop, \ get_error, get_error_str, clear_error, get_fd) \ { \ - cobj_init_macro, name, put_string, put_char, put_byte, get_line, \ + cobj_init_macro, name, put_string, put_char, put_byte, get_string, \ get_char, get_byte, unget_char, unget_byte, put_buf, fill_buf, \ close, flush, seek, truncate, get_prop, set_prop, \ get_error, get_error_str, clear_error, get_fd, 0, 0, 0, 0 \ @@ -164,7 +164,7 @@ extern val stdin_s, stdout_s, stddebug_s, stderr_s, stdnull_s; extern val put_string_s, put_char_s, put_byte_s, get_line_s, get_char_s; extern val get_byte_s, unget_char_s, unget_byte_s, put_buf_s, fill_buf_s; extern val close_s, flush_s, seek_s, truncate_s, get_prop_s, set_prop_s; -extern val get_error_s, get_error_str_s, clear_error_s, get_fd_s; +extern val get_error_s, get_error_str_s, clear_error_s, get_fd_s, get_string_s; extern val print_flo_precision_s, print_flo_digits_s, print_flo_format_s; extern val pprint_flo_format_s, print_base_s, print_circle_s; @@ -198,7 +198,7 @@ val normalize_mode_no_bin(struct stdio_mode *m, val mode_str, struct stdio_mode m_dfl, val self); val set_mode_props(const struct stdio_mode m, val stream); ucnum generic_fill_buf(val stream, mem_t *ptr, ucnum len, ucnum pos); -val generic_get_line(val stream); +val generic_get_string(val stream, ucnum limit, wint_t stopchar, val self); val errno_to_string(val err); val make_null_stream(void); val make_stdio_stream(FILE *, val descr); @@ -233,6 +233,7 @@ val get_error(val stream); val get_error_str(val stream); val clear_error(val stream); val get_line(val); +val get_delimited_string(val, val nchars, val stop_char); val get_char(val); val get_byte(val); val get_bytes(val self, val, mem_t *ptr, ucnum len); @@ -81,12 +81,14 @@ static val strudel_put_byte(val stream, int byte) return funcall2(meth, obj, num_fast(byte)); } -static val strudel_get_line(val stream) +static val strudel_get_string(val stream, ucnum limit, wint_t stopchar, val self) { 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); + val meth = slot(obj, get_string_s); + return funcall4(meth, obj, + if2(limit != UINT_PTR_MAX, unum(limit)), + if2(stopchar != WEOF, chr(stopchar)), self); } static val strudel_get_char(val stream) @@ -247,7 +249,7 @@ static struct strm_ops strudel_ops = 0), wli("struct-delegate-stream"), strudel_put_string, strudel_put_char, strudel_put_byte, - strudel_get_line, strudel_get_char, strudel_get_byte, + strudel_get_string, strudel_get_char, strudel_get_byte, strudel_unget_char, strudel_unget_byte, strudel_put_buf, strudel_fill_buf, strudel_close, strudel_flush, strudel_seek, diff --git a/tests/018/streams.tl b/tests/018/streams.tl index e3ee783b..1abde546 100644 --- a/tests/018/streams.tl +++ b/tests/018/streams.tl @@ -84,3 +84,58 @@ (read-until-match #/:/ s t) "foo:" (iread s) (1 2 3) (get-char s) #\x)) + +(with-in-string-stream (s "abcd:") + (mtest + (get-delimited-string s 3 #\:) "abc" + (get-string s) "d:")) + +(with-in-string-stream (s "abcd:") + (mtest + (get-delimited-string s 4 #\:) "abcd" + (get-string s) ":")) + +(with-in-string-stream (s "abcd:") + (mtest + (get-delimited-string s 5 #\:) "abcd" + (get-string s) "")) + +(with-in-string-stream (s "abcd:") + (mtest + (get-delimited-string s) "abcd:" + (get-string s) "")) + +(with-in-string-stream (s "abcd:") + (mtest + (get-delimited-string s 3) "abc" + (get-string s) "d:")) + +(with-in-string-stream (s "abcd:") + (mtest + (get-delimited-string s 4) "abcd" + (get-string s) ":")) + +(with-in-string-stream (s "abcd:") + (mtest + (get-delimited-string s 5) "abcd:" + (get-string s) "")) + +(with-in-string-stream (s "abcd:") + (mtest + (get-delimited-string s 6) "abcd:" + (get-string s) "")) + +(with-in-string-stream (s "abcd:") + (mtest + (get-delimited-string s) "abcd:" + (get-string s) "")) + +(with-in-string-stream (s "abcd:") + (mtest + (get-delimited-string s : #\:) "abcd" + (get-string s) "")) + +(with-in-string-stream (s "abcd:") + (mtest + (get-delimited-string s : #\a) "" + (get-string s) "bcd:")) @@ -67408,6 +67408,46 @@ longer than .metn count , but may be shorter. +.coNP Function @ get-delimited-string +.synb +.mets (get-delimited-string >> [ stream >> [ count <> [ stop-char ]]]) +.syne +.desc +The +.code get-delimited-string +function reads characters from a stream, returning them as a +string. + +If the +.meta count +argument is given, it should be a non-negative integer. The function +stops reading when it has accumulated +.meta count +characters. If +.meta count +is zero, no characters are read and an empty string is returned. + +If the +.meta stop-char +argument is given, it should be a character. When the function +reads that character, it discards it and stops reading. + +If both +.meta count +and +.meta stop-char +are specified, the behavior is determined by whichever terminating +condition occurs first. In the case when exactly +.meta count +characters have been read, and the most recently read character is +.metn stop-char , +the semantics of +.meta stop-char +prevails, as if +.meta count +were absent: the character is ignored and a string consisting +of the previous characters is returned. + .coNP Functions @ unget-char and @ unget-byte .synb .mets (unget-char < char <> [ stream ]) @@ -70954,7 +70994,7 @@ subsets of, or all of, the following methods: .codn put-string , .codn put-char , .codn put-byte , -.codn get-line , +.codn get-string , .codn get-char , .codn get-byte , .codn unget-char , @@ -71021,19 +71061,32 @@ description of the .code put-byte stream I/O function. -.coNP Method @ get-line +.coNP Method @ get-string .synb -.mets << stream .(get-line) +.mets << stream .(get-string < count << stop-char ) .syne .desc The -.code get-line +.code get-string method is implemented on a stream interface object. It should behave in a manner consistent with the description of the -.code get-line +.code get-delimited-string stream I/O function. +This function is used as the basis for the +.code get-line +function also. + +All arguments are always passed to this method; +the parameters are not optional. When +.meta count +or +.meta stop-char +are understood as not specified, they appear as +.code nil +values. + .coNP Method @ get-char .synb .mets << stream .(get-char) |