Package: guile;
Reported by: dwheeler <at> dwheeler.com
Date: Fri, 17 Aug 2012 02:03:01 UTC
Severity: normal
Done: Mark H Weaver <mhw <at> netris.org>
Bug is archived. No further changes may be made.
View this message in rfc822 format
From: Mark H Weaver <mhw <at> netris.org> To: Andy Wingo <wingo <at> pobox.com> Cc: almkglor <almkglor <at> gmail.com>, dwheeler <at> dwheeler.com, 12216 <12216 <at> debbugs.gnu.org> Subject: bug#12216: peek-char incorrectly *CONSUMES* eof Date: Sun, 31 Mar 2013 22:05:45 -0400
[Message part 1 (text/plain, inline)]
Mark H Weaver <mhw <at> netris.org> writes: > Andy Wingo <wingo <at> pobox.com> writes: >> Maybe if it is somehow confined to scm_peek_char and scm_fill_input it >> could be doable. > > I think I now see a reasonable way to fix this. > > First of all, all interfaces that do something like 'peek' would, when > returning an EOF, set a 'pending_eof' flag in the port structure. Then > 'scm_fill_input' would start by checking this flag; if it is set, then > it would clear the flag and return EOF. > > We would also need to clear the 'pending_eof' flag in a few other > places, most notably in 'scm_end_input'. In theory, that might be > enough, but to be on the safe side we should also clear the flag in any > procedure that writes or seeks. Upon further thought, I decided that we shouldn't clear it on writes. If 'rw_random' is set, then 'scm_end_input' will be called anyway. If 'rw_random' is not set, then we should *not* clear the flag on writes, because it indicates that the read and write streams are independent, e.g. a terminal or socket. On the other hand, the 'pending_eof' flag should of course be cleared when putting characters back (unget). I've attached a proposed patch. It depends on the three preliminary patches posted here: http://lists.gnu.org/archive/html/guile-devel/2013-03/msg00221.html Thoughts? Regards, Mark
[0004-Peeks-do-not-consume-EOFs.patch (text/x-diff, inline)]
From e732d035b86a990ea0cfb56a710ee9224d8dbd31 Mon Sep 17 00:00:00 2001 From: Mark H Weaver <mhw <at> netris.org> Date: Sun, 31 Mar 2013 19:06:51 -0400 Subject: [PATCH 4/5] Peeks do not consume EOFs. * libguile/ports-internal.h (struct scm_port_internal): Add 'pending_eof' flag. * libguile/inline.h (scm_peek_byte_or_eof): Set 'pending_eof' flag before returning EOF. * libguile/ports.c (scm_i_set_pending_eof): New function. (scm_i_clear_pending_eof): New static function. (scm_new_port_table_entry): Initialize 'pending_eof'. (scm_fill_input): Check for 'pending_eof'. (scm_end_input, scm_unget_byte, scm_seek): Clear 'pending_eof'. (scm_peek_char): Set 'pending_eof' flag before returning EOF. * libguile/ports.h (scm_i_set_pending_eof): Add prototype. --- libguile/inline.h | 5 ++++- libguile/ports-internal.h | 1 + libguile/ports.c | 33 +++++++++++++++++++++++++++++++-- libguile/ports.h | 1 + 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/libguile/inline.h b/libguile/inline.h index 88ba7f7..fffe101 100644 --- a/libguile/inline.h +++ b/libguile/inline.h @@ -134,7 +134,10 @@ scm_peek_byte_or_eof (SCM port) if (pt->read_pos >= pt->read_end) { if (SCM_UNLIKELY (scm_fill_input (port) == EOF)) - return EOF; + { + scm_i_set_pending_eof (port); + return EOF; + } } c = *pt->read_pos; diff --git a/libguile/ports-internal.h b/libguile/ports-internal.h index d52eab2..5bde9d0 100644 --- a/libguile/ports-internal.h +++ b/libguile/ports-internal.h @@ -48,6 +48,7 @@ struct scm_port_internal { scm_t_port_encoding_mode encoding_mode; scm_t_iconv_descriptors *iconv_descriptors; + int pending_eof; }; typedef struct scm_port_internal scm_t_port_internal; diff --git a/libguile/ports.c b/libguile/ports.c index 1ac9106..89e1714 100644 --- a/libguile/ports.c +++ b/libguile/ports.c @@ -241,6 +241,18 @@ scm_set_port_input_waiting (scm_t_bits tc, int (*input_waiting) (SCM)) scm_ptobs[SCM_TC2PTOBNUM (tc)].input_waiting = input_waiting; } +void +scm_i_set_pending_eof (SCM port) +{ + SCM_INTERNAL_PTAB_ENTRY (port)->pending_eof = 1; +} + +static void +scm_i_clear_pending_eof (SCM port) +{ + SCM_INTERNAL_PTAB_ENTRY (port)->pending_eof = 0; +} + SCM_DEFINE (scm_char_ready_p, "char-ready?", 0, 1, 0, @@ -634,6 +646,8 @@ scm_new_port_table_entry (scm_t_bits tag) entry->input_cd = pti; /* XXX pointer to the internal port structure */ entry->output_cd = NULL; /* XXX unused */ + pti->pending_eof = 0; + SCM_SET_CELL_TYPE (z, tag); SCM_SETPTAB_ENTRY (z, entry); @@ -1410,9 +1424,16 @@ int scm_fill_input (SCM port) { scm_t_port *pt = SCM_PTAB_ENTRY (port); + scm_t_port_internal *pti = SCM_INTERNAL_PTAB_ENTRY (port); assert (pt->read_pos == pt->read_end); + if (pti->pending_eof) + { + pti->pending_eof = 0; + return EOF; + } + if (pt->read_buf == pt->putback_buf) { /* finished reading put-back chars. */ @@ -1652,6 +1673,7 @@ scm_end_input (SCM port) long offset; scm_t_port *pt = SCM_PTAB_ENTRY (port); + scm_i_clear_pending_eof (port); if (pt->read_buf == pt->putback_buf) { offset = pt->read_end - pt->read_pos; @@ -1675,6 +1697,7 @@ scm_unget_byte (int c, SCM port) { scm_t_port *pt = SCM_PTAB_ENTRY (port); + scm_i_clear_pending_eof (port); if (pt->read_buf == pt->putback_buf) /* already using the put-back buffer. */ { @@ -1846,7 +1869,10 @@ SCM_DEFINE (scm_peek_char, "peek-char", 0, 1, 0, result = SCM_BOOL_F; } else if (c == EOF) - result = SCM_EOF_VAL; + { + scm_i_set_pending_eof (port); + result = SCM_EOF_VAL; + } else result = SCM_MAKE_CHAR (c); @@ -1945,7 +1971,10 @@ SCM_DEFINE (scm_seek, "seek", 3, 0, 0, SCM_MISC_ERROR ("port is not seekable", scm_cons (fd_port, SCM_EOL)); else - rv = ptob->seek (fd_port, off, how); + { + scm_i_clear_pending_eof (fd_port); + rv = ptob->seek (fd_port, off, how); + } return scm_from_off_t_or_off64_t (rv); } else /* file descriptor?. */ diff --git a/libguile/ports.h b/libguile/ports.h index 95545cd..5aca26d 100644 --- a/libguile/ports.h +++ b/libguile/ports.h @@ -319,6 +319,7 @@ SCM_API SCM scm_set_port_filename_x (SCM port, SCM filename); SCM_INTERNAL const char *scm_i_default_port_encoding (void); SCM_INTERNAL void scm_i_set_default_port_encoding (const char *); SCM_INTERNAL void scm_i_set_port_encoding_x (SCM port, const char *str); +SCM_INTERNAL void scm_i_set_pending_eof (SCM port); SCM_API SCM scm_port_encoding (SCM port); SCM_API SCM scm_set_port_encoding_x (SCM port, SCM encoding); SCM_INTERNAL scm_t_string_failed_conversion_handler -- 1.7.10.4
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.