summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog50
-rwxr-xr-xconfigure20
-rw-r--r--lib.c28
-rw-r--r--match.c5
-rw-r--r--stream.c77
-rw-r--r--stream.h3
6 files changed, 169 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index ba8fd507..f3da9b17 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/configure b/configure
index 51e067a9..3578d71f 100755
--- a/configure
+++ b/configure
@@ -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
#
diff --git a/lib.c b/lib.c
index 6a59ecd3..48349c2e 100644
--- a/lib.c
+++ b/lib.c
@@ -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)
diff --git a/match.c b/match.c
index 100089b7..746a622c 100644
--- a/match.c
+++ b/match.c
@@ -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,
diff --git a/stream.c b/stream.c
index a74705ab..8bae32eb 100644
--- a/stream.c
+++ b/stream.c
@@ -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);
diff --git a/stream.h b/stream.h
index efd3e912..6bf7c5e6 100644
--- a/stream.h
+++ b/stream.h
@@ -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);