mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-20 11:40:18 +02:00
Flush buffered reads / writes before seeking
* libguile/ports.c (scm_seek): Flush before seeking on a buffered port. * libguile/fports.c (fport_seek): * libguile/strports.c (st_seek): Remove code to flush buffers. * test-suite/tests/ports.test: Update test expectations that the putback buffer is flushed on a seek. Previously there was a special case for SEEK_CUR with an offset of 0 to avoid flushing buffers, but that's an arbitrary choice that differs from all other combinations of OFFSET and WHENCE.
This commit is contained in:
parent
b7e49a75a9
commit
b77fb752dd
4 changed files with 52 additions and 100 deletions
|
@ -670,50 +670,12 @@ fport_fill_input (SCM port)
|
||||||
static scm_t_off
|
static scm_t_off
|
||||||
fport_seek (SCM port, scm_t_off offset, int whence)
|
fport_seek (SCM port, scm_t_off offset, int whence)
|
||||||
{
|
{
|
||||||
scm_t_port *pt = SCM_PTAB_ENTRY (port);
|
|
||||||
scm_t_fport *fp = SCM_FSTREAM (port);
|
scm_t_fport *fp = SCM_FSTREAM (port);
|
||||||
off_t_or_off64_t rv;
|
|
||||||
off_t_or_off64_t result;
|
off_t_or_off64_t result;
|
||||||
|
|
||||||
if (pt->rw_active == SCM_PORT_WRITE)
|
result = lseek_or_lseek64 (fp->fdes, offset, whence);
|
||||||
{
|
|
||||||
if (offset != 0 || whence != SEEK_CUR)
|
|
||||||
{
|
|
||||||
fport_flush (port);
|
|
||||||
result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* read current position without disturbing the buffer. */
|
|
||||||
rv = lseek_or_lseek64 (fp->fdes, offset, whence);
|
|
||||||
result = rv + (pt->write_pos - pt->write_buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (pt->rw_active == SCM_PORT_READ)
|
|
||||||
{
|
|
||||||
if (offset != 0 || whence != SEEK_CUR)
|
|
||||||
{
|
|
||||||
/* could expand to avoid a second seek. */
|
|
||||||
scm_end_input_unlocked (port);
|
|
||||||
result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* read current position without disturbing the buffer
|
|
||||||
(particularly the unread-char buffer). */
|
|
||||||
rv = lseek_or_lseek64 (fp->fdes, offset, whence);
|
|
||||||
result = rv - (pt->read_end - pt->read_pos);
|
|
||||||
|
|
||||||
if (pt->read_buf == pt->putback_buf)
|
if (result == -1)
|
||||||
result -= pt->saved_read_end - pt->saved_read_pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else /* SCM_PORT_NEITHER */
|
|
||||||
{
|
|
||||||
result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rv == -1)
|
|
||||||
scm_syserror ("fport_seek");
|
scm_syserror ("fport_seek");
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -2851,16 +2851,26 @@ SCM_DEFINE (scm_seek, "seek", 3, 0, 0,
|
||||||
|
|
||||||
if (SCM_OPPORTP (fd_port))
|
if (SCM_OPPORTP (fd_port))
|
||||||
{
|
{
|
||||||
|
scm_t_port *pt = SCM_PTAB_ENTRY (fd_port);
|
||||||
scm_t_port_internal *pti = SCM_PORT_GET_INTERNAL (fd_port);
|
scm_t_port_internal *pti = SCM_PORT_GET_INTERNAL (fd_port);
|
||||||
scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (fd_port);
|
scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (fd_port);
|
||||||
off_t_or_off64_t off = scm_to_off_t_or_off64_t (offset);
|
off_t_or_off64_t off = scm_to_off_t_or_off64_t (offset);
|
||||||
off_t_or_off64_t rv;
|
off_t_or_off64_t rv;
|
||||||
|
|
||||||
if (!ptob->seek)
|
if (!ptob->seek || !pt->rw_random)
|
||||||
SCM_MISC_ERROR ("port is not seekable",
|
SCM_MISC_ERROR ("port is not seekable",
|
||||||
scm_cons (fd_port, SCM_EOL));
|
scm_cons (fd_port, SCM_EOL));
|
||||||
else
|
|
||||||
rv = ptob->seek (fd_port, off, how);
|
/* FIXME: Avoid flushing buffers for SEEK_CUR with an offset of
|
||||||
|
0. */
|
||||||
|
|
||||||
|
if (pt->rw_active == SCM_PORT_READ)
|
||||||
|
scm_end_input_unlocked (pt->port);
|
||||||
|
else if (pt->rw_active == SCM_PORT_WRITE)
|
||||||
|
scm_flush_unlocked (pt->port);
|
||||||
|
pt->rw_active = SCM_PORT_NEITHER;
|
||||||
|
|
||||||
|
rv = ptob->seek (fd_port, off, how);
|
||||||
|
|
||||||
/* Set stream-start flags according to new position. */
|
/* Set stream-start flags according to new position. */
|
||||||
pti->at_stream_start_for_bom_read = (rv == 0);
|
pti->at_stream_start_for_bom_read = (rv == 0);
|
||||||
|
|
|
@ -162,64 +162,44 @@ st_seek (SCM port, scm_t_off offset, int whence)
|
||||||
scm_t_port *pt = SCM_PTAB_ENTRY (port);
|
scm_t_port *pt = SCM_PTAB_ENTRY (port);
|
||||||
scm_t_off target;
|
scm_t_off target;
|
||||||
|
|
||||||
if (pt->rw_active == SCM_PORT_READ && offset == 0 && whence == SEEK_CUR)
|
switch (whence)
|
||||||
/* special case to avoid disturbing the unread-char buffer. */
|
|
||||||
{
|
{
|
||||||
if (pt->read_buf == pt->putback_buf)
|
case SEEK_CUR:
|
||||||
{
|
target = pt->read_pos - pt->read_buf + offset;
|
||||||
target = pt->saved_read_pos - pt->saved_read_buf
|
break;
|
||||||
- (pt->read_end - pt->read_pos);
|
case SEEK_END:
|
||||||
}
|
target = pt->read_end - pt->read_buf + offset;
|
||||||
else
|
break;
|
||||||
{
|
default: /* SEEK_SET */
|
||||||
target = pt->read_pos - pt->read_buf;
|
target = offset;
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
/* all other cases. */
|
|
||||||
{
|
|
||||||
if (pt->rw_active == SCM_PORT_READ)
|
|
||||||
scm_end_input_unlocked (port);
|
|
||||||
|
|
||||||
pt->rw_active = SCM_PORT_NEITHER;
|
if (target < 0)
|
||||||
|
scm_misc_error ("st_seek", "negative offset", SCM_EOL);
|
||||||
switch (whence)
|
|
||||||
{
|
|
||||||
case SEEK_CUR:
|
|
||||||
target = pt->read_pos - pt->read_buf + offset;
|
|
||||||
break;
|
|
||||||
case SEEK_END:
|
|
||||||
target = pt->read_end - pt->read_buf + offset;
|
|
||||||
break;
|
|
||||||
default: /* SEEK_SET */
|
|
||||||
target = offset;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target < 0)
|
|
||||||
scm_misc_error ("st_seek", "negative offset", SCM_EOL);
|
|
||||||
|
|
||||||
if (target >= pt->write_buf_size)
|
if (target >= pt->write_buf_size)
|
||||||
{
|
{
|
||||||
if (!(SCM_CELL_WORD_0 (port) & SCM_WRTNG))
|
if (!(SCM_CELL_WORD_0 (port) & SCM_WRTNG))
|
||||||
{
|
{
|
||||||
if (target > pt->write_buf_size)
|
if (target > pt->write_buf_size)
|
||||||
{
|
{
|
||||||
scm_misc_error ("st_seek",
|
scm_misc_error ("st_seek",
|
||||||
"seek past end of read-only strport",
|
"seek past end of read-only strport",
|
||||||
SCM_EOL);
|
SCM_EOL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (target == pt->write_buf_size)
|
else if (target == pt->write_buf_size)
|
||||||
st_resize_port (pt, target * 2);
|
st_resize_port (pt, target * 2);
|
||||||
}
|
|
||||||
pt->read_pos = pt->write_pos = pt->read_buf + target;
|
|
||||||
if (pt->read_pos > pt->read_end)
|
|
||||||
{
|
|
||||||
pt->read_end = (unsigned char *) pt->read_pos;
|
|
||||||
pt->read_buf_size = pt->read_end - pt->read_buf;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pt->read_pos = pt->write_pos = pt->read_buf + target;
|
||||||
|
if (pt->read_pos > pt->read_end)
|
||||||
|
{
|
||||||
|
pt->read_end = (unsigned char *) pt->read_pos;
|
||||||
|
pt->read_buf_size = pt->read_end - pt->read_buf;
|
||||||
|
}
|
||||||
|
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -176,8 +176,8 @@
|
||||||
(unread-char #\z iport)
|
(unread-char #\z iport)
|
||||||
(pass-if "file: in tell 0 after unread"
|
(pass-if "file: in tell 0 after unread"
|
||||||
(= (seek iport 0 SEEK_CUR) 0))
|
(= (seek iport 0 SEEK_CUR) 0))
|
||||||
(pass-if "file: unread char still there"
|
(pass-if "file: putback buffer flushed after seek"
|
||||||
(char=? (read-char iport) #\z))
|
(char=? (read-char iport) #\J))
|
||||||
(seek iport 7 SEEK_SET)
|
(seek iport 7 SEEK_SET)
|
||||||
(pass-if "file: in last char"
|
(pass-if "file: in last char"
|
||||||
(char=? (read-char iport) #\x))
|
(char=? (read-char iport) #\x))
|
||||||
|
@ -700,8 +700,8 @@
|
||||||
(unread-char #\x p)
|
(unread-char #\x p)
|
||||||
(pass-if "input tell back to 0"
|
(pass-if "input tell back to 0"
|
||||||
(= (seek p 0 SEEK_CUR) 0))
|
(= (seek p 0 SEEK_CUR) 0))
|
||||||
(pass-if "input ungetted char"
|
(pass-if "putback buffer discarded after seek"
|
||||||
(char=? (read-char p) #\x))
|
(char=? (read-char p) #\t))
|
||||||
(seek p 0 SEEK_END)
|
(seek p 0 SEEK_END)
|
||||||
(pass-if "input seek to end"
|
(pass-if "input seek to end"
|
||||||
(= (seek p 0 SEEK_CUR)
|
(= (seek p 0 SEEK_CUR)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue