From 4d5a53b6f2811e82e313b979e4b53fd2071f2107 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Thu, 28 Nov 2013 00:38:26 -0800 Subject: * stream.c (struct stdio_handle): New member, mode. (stdio_stream_mark): Mark the new member during gc. (stdio_seek): When we seek, we should reset the utf8 machine. (tail_strategy): New function. (tail_get_line, tail_get_char, tail_get_byte): Use tail_strategy for polling the file at EOF. (open_tail): Store the mode in the file handle. * utf8.c (w_freopen): New function. * utf8.h (w_freopen): Declared. --- ChangeLog | 14 ++++++++++++++ stream.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- utf8.c | 10 ++++++++++ utf8.h | 1 + 4 files changed, 85 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8878d73f..d6266302 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2013-11-28 Kaz Kylheku + + * stream.c (struct stdio_handle): New member, mode. + (stdio_stream_mark): Mark the new member during gc. + (stdio_seek): When we seek, we should reset the utf8 machine. + (tail_strategy): New function. + (tail_get_line, tail_get_char, tail_get_byte): Use + tail_strategy for polling the file at EOF. + (open_tail): Store the mode in the file handle. + + * utf8.c (w_freopen): New function. + + * utf8.h (w_freopen): Declared. + 2013-11-27 Kaz Kylheku * Makefile (conftest.clean): Use @ to suppress output. diff --git a/stream.c b/stream.c index e4e0bed2..c90d4c18 100644 --- a/stream.c +++ b/stream.c @@ -91,6 +91,7 @@ static void common_destroy(val obj) struct stdio_handle { FILE *f; val descr; + val mode; /* used by tail */ utf8_decoder_t ud; #if HAVE_FORK_STUFF pid_t pid; @@ -119,6 +120,7 @@ static void stdio_stream_mark(val stream) { struct stdio_handle *h = (struct stdio_handle *) stream->co.handle; gc_mark(h->descr); + gc_mark(h->mode); } static val stdio_maybe_read_error(val stream) @@ -212,8 +214,10 @@ static val stdio_seek(val stream, cnum offset, enum strm_whence whence) if (where >= 0) return num(where); } else { - if (fseek(h->f, offset, whence) == 0) + if (fseek(h->f, offset, whence) == 0) { + utf8_decoder_init(&h->ud); return t; + } } } @@ -318,32 +322,78 @@ static struct strm_ops stdio_ops = { stdio_seek }; +static void tail_strategy(val stream, unsigned long *state) +{ + unsigned long count = (*state)++; + int sec, mod; + (void) stream; + + if (count > 32) + count = 32; + + sec = 1 << (count / 8); + mod = 8 >> (count / 8); + + if (mod == 0) + mod = 1; + + sleep(sec); + + if (*state % mod == 0) { + struct stdio_handle *h = (struct stdio_handle *) stream->co.handle; + long save_pos, size; + + if ((save_pos = ftell(h->f)) == -1) + return; + + if (!(h->f = w_freopen(c_str(h->descr), c_str(h->mode), h->f))) + uw_throwf(file_error_s, lit("error opening ~a: ~a/~s"), + h->descr, num(errno), string_utf8(strerror(errno)), nao); + + utf8_decoder_init(&h->ud); + + if ((fseek(h->f, 0, SEEK_END)) == -1) + return; + + if ((size = ftell(h->f)) == -1) + return; + + if (size >= save_pos) + fseek(h->f, save_pos, SEEK_SET); + else + rewind(h->f); + } +} + static val tail_get_line(val stream) { + unsigned long state = 0; val ret; while ((ret = stdio_get_line(stream)) == nil) - sleep(1); + tail_strategy(stream, &state); return ret; } static val tail_get_char(val stream) { + unsigned long state = 0; val ret; while ((ret = stdio_get_char(stream)) == nil) - sleep(1); + tail_strategy(stream, &state); return ret; } static val tail_get_byte(val stream) { + unsigned long state = 0; val ret; while ((ret = stdio_get_byte(stream)) == nil) - sleep(1); + tail_strategy(stream, &state); return ret; } @@ -1671,6 +1721,8 @@ val open_file(val path, val mode_str) val open_tail(val path, val mode_str, val seek_end_p) { FILE *f = w_fopen(c_str(path), c_str(mode_str)); + struct stdio_handle *h; + val stream; if (!f) uw_throwf(file_error_s, lit("error opening ~a: ~a/~s"), @@ -1681,7 +1733,10 @@ val open_tail(val path, val mode_str, val seek_end_p) uw_throwf(file_error_s, lit("error seeking to end of ~a: ~a/~s"), path, num(errno), string_utf8(strerror(errno)), nao); - return make_tail_stream(f, path); + stream = make_tail_stream(f, path); + h = (struct stdio_handle *) stream->co.handle; + h->mode = mode_str; + return stream; } val open_command(val path, val mode_str) diff --git a/utf8.c b/utf8.c index 27550be2..99e21978 100644 --- a/utf8.c +++ b/utf8.c @@ -371,3 +371,13 @@ FILE *w_popen(const wchar_t *wcmd, const wchar_t *wmode) free(mode); return f; } + +FILE *w_freopen(const wchar_t *wname, const wchar_t *wmode, FILE *fold) +{ + char *name = utf8_dup_to(wname); + char *mode = utf8_dup_to(wmode); + FILE *f = freopen(name, mode, fold); + free(name); + free(mode); + return f; +} diff --git a/utf8.h b/utf8.h index ce147fb6..134af026 100644 --- a/utf8.h +++ b/utf8.h @@ -48,3 +48,4 @@ wint_t utf8_decode(utf8_decoder_t *,int (*get)(mem_t *ctx), mem_t *ctx); FILE *w_fopen(const wchar_t *, const wchar_t *); FILE *w_popen(const wchar_t *, const wchar_t *); +FILE *w_freopen(const wchar_t *, const wchar_t *, FILE *); -- cgit v1.2.3