diff options
-rw-r--r-- | ChangeLog | 50 | ||||
-rwxr-xr-x | configure | 20 | ||||
-rw-r--r-- | lib.c | 28 | ||||
-rw-r--r-- | match.c | 5 | ||||
-rw-r--r-- | stream.c | 77 | ||||
-rw-r--r-- | stream.h | 3 |
6 files changed, 169 insertions, 14 deletions
@@ -1,3 +1,53 @@ +2013-12-01 Kaz Kylheku <kaz@kylheku.com> + + Steps toward fixing an issue: lazy list readahead. + The problem is that accurate lazy lists are not suitable for + real time use, where we want the TXR program to respond immediately + to matching some datum. + + I'm implementing a simple, naive variant of lazy stream lists + which simply populates the lazy cons by reading from the stream when + the car or cdr fields are accessed. This type of stream can never + be nil (empty list) even if the file is empty; in that case + it will be (nil) and in general, it will have a spurious nil + item at the end instead of ending in a string. + (An adjustment was made in match.c to detect this; more + will be needed.) + + I'm adding attributes to streams so streams can now have a + "real-time" attribute. When a lazy string list is constructed over + a real-time stream, the simple implementation is used. + File streams are automatically real-time if (on Unix) they are tied + to tty streams. Tail streams are also real-time. + + More work is needed to achieve the goal of this change, + but this is a big step in the right direction. + + * configure: Detect isatty function. + + * lib.c (simple_lazy_stream_func): New static function. + (lazy_stream_cons): Use simple implementation for real-time streams. + + * match.c (match_files): Do not call match_line_completely + with a data line that is nil (as a result of simple lazy list + over a real-time stream). A nil item in a lazy list of strings + is treated as eof. + + * stream.c (real_time_k): New symbol variable. + (struct strm_ops): New members: get_prop, set_prop. + (struct stdio_handle): New member: is_real_time. + (stdio_get_prop, stdio_set_prop): New static function. + (stdio_ops, tail_ops, pipe_ops): stdio_get_prop and + stdio_set_prop funtions wired in. + (make_stdio_stream_common): Attribute streams as real-time + if they are tty devices. + (make_tail_stream): Tail streams are real-time attributed. + (stream_set_prop, real_time_stream_p): New functions. + (stream_init): Initialize real_time_k. + + * stream.h (real_time_k): Declared. + (real_time_stream_p, stream_set_prop): Likewise. + 2013-11-29 Kaz Kylheku <kaz@kylheku.com> * eval.c (eval_init): New functions countqual, countql, countq @@ -1386,6 +1386,26 @@ else have_unistd=y fi +printf "Checking for isatty function ... " + +cat > conftest.c <<! +#include <unistd.h> + +int main(void) +{ + isatty(0); + return 0; +} +! +rm -f conftest +if ! $make conftest > conftest.err 2>&1 || ! [ -x conftest ] ; then + printf "no\n" +else + printf "yes\n" + printf "#define HAVE_ISATTY 1\n" >> config.h + have_unistd=y +fi + # # Dependent variables # @@ -3836,6 +3836,16 @@ val cat_vec(val list) return vec; } +static val simple_lazy_stream_func(val stream, val lcons) +{ + if (set(lcons->lc.car, get_line(stream)) != nil) + set(lcons->lc.cdr, make_lazy_cons(lcons->lc.func)); + else + lcons->lc.cdr = nil; + + return nil; +} + static val lazy_stream_cont(val stream, val func, val env) { val next = get_line(stream); @@ -3862,15 +3872,19 @@ static val lazy_stream_func(val env, val lcons) val lazy_stream_cons(val stream) { - val first = get_line(stream); + if (real_time_stream_p(stream)) { + return make_lazy_cons(func_f1(stream, simple_lazy_stream_func)); + } else { + val first = get_line(stream); - if (!first) { - close_stream(stream, t); - return nil; - } + if (!first) { + close_stream(stream, t); + return nil; + } - return make_lazy_cons(func_f1(cons(stream, first), - lazy_stream_func)); + return make_lazy_cons(func_f1(cons(stream, first), + lazy_stream_func)); + } } val lazy_str(val lst, val term, val limit) @@ -1545,7 +1545,6 @@ static val complex_stream(fpip_t fp, val name) internal_error("bad input source type"); } - static val robust_length(val obj) { if (obj == nil) @@ -3738,9 +3737,9 @@ repeat_spec_same_data: } } - if (c.data) + if (c.data && car(c.data)) { - val dataline = first(c.data); + val dataline = car(c.data); cons_bind (new_bindings, success, match_line_completely(ml_all(c.bindings, specline, @@ -58,6 +58,7 @@ val dev_k, ino_k, mode_k, nlink_k, uid_k; val gid_k, rdev_k, size_k, blksize_k, blocks_k; val atime_k, mtime_k, ctime_k; val from_start_k, from_current_k, from_end_k; +val real_time_k; val s_ifmt, s_ifsock, s_iflnk, s_ifreg, s_ifblk, s_ifdir; val s_ifchr, s_ififo, s_isuid, s_isgid, s_isvtx, s_irwxu; @@ -81,6 +82,8 @@ struct strm_ops { val (*close)(val, val); val (*flush)(val); val (*seek)(val, cnum, enum strm_whence); + val (*get_prop)(val, val ind); + val (*set_prop)(val, val ind, val); }; static void common_destroy(val obj) @@ -98,6 +101,7 @@ struct stdio_handle { #else int pid; #endif + unsigned is_real_time; }; static void stdio_stream_print(val stream, val out) @@ -224,6 +228,25 @@ static val stdio_seek(val stream, cnum offset, enum strm_whence whence) return stdio_maybe_error(stream, lit("seeking")); } +static val stdio_get_prop(val stream, val ind) +{ + if (ind == real_time_k) { + struct stdio_handle *h = (struct stdio_handle *) stream->co.handle; + return h->is_real_time ? t : nil; + } + return nil; +} + +static val stdio_set_prop(val stream, val ind, val prop) +{ + if (ind == real_time_k) { + struct stdio_handle *h = (struct stdio_handle *) stream->co.handle; + h->is_real_time = prop ? 0 : 1; + return t; + } + return nil; +} + static wchar_t *snarf_line(struct stdio_handle *h) { const size_t min_size = 512; @@ -319,7 +342,9 @@ static struct strm_ops stdio_ops = { stdio_get_byte, stdio_close, stdio_flush, - stdio_seek + stdio_seek, + stdio_get_prop, + stdio_set_prop }; static void tail_calc(unsigned long *state, int *sec, int *mod) @@ -422,7 +447,9 @@ static struct strm_ops tail_ops = { tail_get_byte, stdio_close, stdio_flush, - stdio_seek + stdio_seek, + stdio_get_prop, + stdio_set_prop }; @@ -497,7 +524,9 @@ static struct strm_ops pipe_ops = { stdio_get_byte, pipe_close, stdio_flush, - 0 /* seek: not on pipes */ + 0, /* seek: not on pipes */ + stdio_get_prop, + stdio_set_prop }; static void string_in_stream_mark(val stream) @@ -566,6 +595,8 @@ static struct strm_ops string_in_ops = { 0, /* close */ 0, /* flush */ 0, /* TODO: seek */ + 0, /* get_prop */ + 0 /* set_prop */ }; struct byte_input { @@ -610,6 +641,8 @@ static struct strm_ops byte_in_ops = { 0, /* close */ 0, /* flush */ 0, /* TODO: support seek */ + 0, /* get_prop */ + 0 /* set_prop */ }; @@ -734,6 +767,8 @@ static struct strm_ops string_out_ops = { 0, /* close */ 0, /* flush */ 0, /* TODO: seek, with fill-with-spaces semantics if past end. */ + 0, /* get_prop */ + 0 /* set_prop */ }; static void strlist_mark(val stream) @@ -803,6 +838,8 @@ static struct strm_ops strlist_out_ops = { 0, /* close */ 0, /* flush */ 0, /* seek */ + 0, /* get_prop */ + 0 /* set_prop */ }; val make_strlist_output_stream(void) @@ -873,6 +910,8 @@ static struct strm_ops dir_ops = { dir_close, 0, /* flush */ 0, /* seek */ + 0, /* get_prop */ + 0 /* set_prop */ }; @@ -885,6 +924,11 @@ static val make_stdio_stream_common(FILE *f, val descr, struct cobj_ops *ops) h->mode = nil; utf8_decoder_init(&h->ud); h->pid = 0; +#if HAVE_ISATTY + h->is_real_time = (isatty(fileno(h->f)) == 1); +#else + h->is_real_time = 0; +#endif return stream; } @@ -895,7 +939,9 @@ val make_stdio_stream(FILE *f, val descr) val make_tail_stream(FILE *f, val descr) { - return make_stdio_stream_common(f, descr, &tail_ops.cobj_ops); + val stream = make_stdio_stream_common(f, descr, &tail_ops.cobj_ops); + stream_set_prop(stream, real_time_k, t); + return stream; } val make_pipe_stream(FILE *f, val descr) @@ -985,6 +1031,28 @@ val streamp(val obj) return typeof(obj) == stream_s ? t : nil; } +val stream_set_prop(val stream, val ind, val prop) +{ + type_check (stream, COBJ); + type_assert (stream->co.cls == stream_s, (lit("~a is not a stream"), + stream, nao)); + + { + struct strm_ops *ops = (struct strm_ops *) stream->co.ops; + return ops->set_prop ? ops->set_prop(stream, ind, prop) : nil; + } +} + +val real_time_stream_p(val obj) +{ + if (streamp(obj)) { + struct strm_ops *ops = (struct strm_ops *) obj->co.ops; + return ops->get_prop ? ops->get_prop(obj, real_time_k) : nil; + } + + return nil; +} + val close_stream(val stream, val throw_on_error) { type_check (stream, COBJ); @@ -1914,6 +1982,7 @@ void stream_init(void) from_start_k = intern(lit("from-start"), keyword_package); from_current_k = intern(lit("from-current"), keyword_package); from_end_k = intern(lit("from-end"), keyword_package); + real_time_k = intern(lit("real-time"), keyword_package); s_ifmt = num(S_IFMT); s_iflnk = num(S_IFLNK); s_ifreg = num(S_IFREG); s_ifblk = num(S_IFBLK); s_ifdir = num(S_IFDIR); @@ -31,6 +31,7 @@ extern val dev_k, ino_k, mode_k, nlink_k, uid_k; extern val gid_k, rdev_k, size_k, blksize_k, blocks_k; extern val atime_k, mtime_k, ctime_k; extern val from_start_k, from_current_k, from_end_k; +extern val real_time_k; extern val s_ifmt, s_iflnk, s_ifreg, s_ifblk, s_ifdir; extern val s_ifchr, s_ififo, s_isuid, s_isgid, s_isvtx, s_irwxu; @@ -48,6 +49,8 @@ val make_strlist_output_stream(void); val get_list_from_stream(val); val make_dir_stream(DIR *); val streamp(val obj); +val real_time_stream_p(val obj); +val stream_set_prop(val stream, val ind, val prop); val close_stream(val stream, val throw_on_error); val get_line(val); val get_char(val); |