summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary Houston <ghouston@arglist.com>2001-01-06 22:03:07 +0000
committerGary Houston <ghouston@arglist.com>2001-01-06 22:03:07 +0000
commitc2da26487a71b44786e279588e37a71a9f036ada (patch)
tree5a51768b93dd39298c2bf91367a452a8c5423ebd
parent4651d663fa7fabc7326efe0696244f751fc17598 (diff)
downloadguile-c2da26487a71b44786e279588e37a71a9f036ada.tar.gz
* ioext.c (scm_read_string_x_partial): new procedure, implements
read-string!/partial. * ports.c (scm_take_from_input_buffers): new procedure used by scm_read_string_x_partial. (scm_drain_input): use scm_take_from_input_buffers.
-rw-r--r--libguile/ChangeLog8
-rw-r--r--libguile/fports.c5
-rw-r--r--libguile/ioext.c104
-rw-r--r--libguile/ioext.h5
-rw-r--r--libguile/ports.c43
-rw-r--r--libguile/ports.h1
6 files changed, 151 insertions, 15 deletions
diff --git a/libguile/ChangeLog b/libguile/ChangeLog
index 565b97f45..9d1101522 100644
--- a/libguile/ChangeLog
+++ b/libguile/ChangeLog
@@ -1,3 +1,11 @@
+2001-01-06 Gary Houston <ghouston@arglist.com>
+
+ * ioext.c (scm_read_string_x_partial): new procedure, implements
+ read-string!/partial.
+ * ports.c (scm_take_from_input_buffers): new procedure used by
+ scm_read_string_x_partial.
+ (scm_drain_input): use scm_take_from_input_buffers.
+
2001-01-06 Marius Vollmer <mvo@zagadka.ping.de>
* validate.h (SCM_VALIDATE_NUMBER): New.
diff --git a/libguile/fports.c b/libguile/fports.c
index 9d0f96d51..093a4ee45 100644
--- a/libguile/fports.c
+++ b/libguile/fports.c
@@ -486,9 +486,8 @@ fport_wait_for_input (SCM port)
static void fport_flush (SCM port);
-/* fill a port's read-buffer with a single read.
- returns the first char and moves the read_pos pointer past it.
- or returns EOF if end of file. */
+/* fill a port's read-buffer with a single read. returns the first
+ char or EOF if end of file. */
static int
fport_fill_input (SCM port)
{
diff --git a/libguile/ioext.c b/libguile/ioext.c
index b88dfa21b..ee0e9c631 100644
--- a/libguile/ioext.c
+++ b/libguile/ioext.c
@@ -69,6 +69,110 @@
#endif
+SCM_DEFINE (scm_read_string_x_partial, "read-string!/partial", 1, 3, 0,
+ (SCM str, SCM port_or_fdes, SCM start, SCM end),
+ "Read characters from an fport or file descriptor into a\n"
+ "string @var{str}. This procedure is scsh-compatible\n"
+ "and can efficiently read large strings. It will:\n\n"
+ "@itemize\n"
+ "@item\n"
+ "attempt to fill the entire string, unless the @var{start}\n"
+ "and/or @var{end} arguments are supplied. i.e., @var{start}\n"
+ "defaults to 0 and @var{end} defaults to\n"
+ "@code{(string-length str)}\n"
+ "@item\n"
+ "use the current input port if @var{port_or_fdes} is not\n"
+ "supplied.\n"
+ "@item\n"
+ "read any characters that are currently available,\n"
+ "without waiting for the rest (short reads are possible).\n\n"
+ "@item\n"
+ "wait for as long as it needs to for the first character to\n"
+ "become available, unless the port is in non-blocking mode\n"
+ "@item\n"
+ "return @code{#f} if end-of-file is encountered before reading\n"
+ "any characters, otherwise return the number of characters\n"
+ "read.\n"
+ "@item\n"
+ "return 0 if the port is in non-blocking mode and no characters\n"
+ "are immediately available.\n"
+ "@item\n"
+ "return 0 if the request is for 0 bytes, with no\n"
+ "end-of-file check\n"
+ "@end itemize")
+#define FUNC_NAME s_scm_read_string_x_partial
+{
+ char *dest;
+ long read_len;
+ long chars_read = 0;
+ int fdes = -1;
+ SCM port = SCM_BOOL_F;
+
+ SCM_VALIDATE_STRING_COPY (1, str, dest);
+ if (SCM_UNBNDP (port_or_fdes))
+ port = scm_cur_inp;
+ else if (SCM_INUMP (port_or_fdes))
+ fdes = SCM_INUM (port_or_fdes);
+ else
+ {
+ SCM_VALIDATE_OPFPORT (2, port_or_fdes);
+ SCM_VALIDATE_INPUT_PORT (2, port_or_fdes);
+ port = port_or_fdes;
+ }
+
+ {
+ long string_len = SCM_STRING_LENGTH (str);
+ long offset = SCM_NUM2LONG_DEF (3, start, 0);
+ long last = SCM_NUM2LONG_DEF (4, end, string_len);
+
+ if (offset < 0 || offset > string_len)
+ SCM_OUT_OF_RANGE (3, start);
+ if (last < offset || last > string_len)
+ SCM_OUT_OF_RANGE (4, end);
+
+ dest += offset;
+ read_len = last - offset;
+ }
+
+ if (fdes == -1)
+ {
+ /* if there's anything in the port buffers, use it. but if
+ something is read from the buffers, don't touch the file
+ descriptor. otherwise the "return immediately if something
+ is available" rule may be violated. */
+ chars_read = scm_take_from_input_buffers (port, dest, read_len);
+
+ }
+
+ if (chars_read == 0 && read_len > 0) /* don't confuse read_len == 0 with
+ EOF. */
+ {
+ if (fdes == -1)
+ fdes = SCM_FPORT_FDES (port);
+
+ SCM_SYSCALL (chars_read = read (fdes, dest, read_len));
+ if (chars_read == -1)
+ {
+#if defined (EWOULDBLOCK) || defined (EAGAIN)
+ if (
+#if defined (EWOULDBLOCK)
+ errno == EWOULDBLOCK
+#else
+ errno == EAGAIN
+#endif
+ )
+ chars_read = 0;
+ else
+#endif
+ SCM_SYSERROR;
+ }
+ else if (chars_read == 0)
+ return SCM_BOOL_F;
+ }
+ return scm_long2num (chars_read);
+}
+#undef FUNC_NAME
+
SCM_DEFINE (scm_read_delimited_x, "%read-delimited!", 3, 3, 0,
(SCM delims, SCM buf, SCM gobble, SCM port, SCM start, SCM end),
"Read characters from @var{port} into @var{buf} until one of the\n"
diff --git a/libguile/ioext.h b/libguile/ioext.h
index a79b1a5b5..579da70e6 100644
--- a/libguile/ioext.h
+++ b/libguile/ioext.h
@@ -48,7 +48,10 @@
-extern SCM scm_read_delimited_x (SCM delims, SCM buf, SCM gobble, SCM port, SCM offset, SCM length);
+extern SCM scm_read_string_x_partial (SCM str, SCM port_or_fdes, SCM start,
+ SCM end);
+extern SCM scm_read_delimited_x (SCM delims, SCM buf, SCM gobble, SCM port,
+ SCM offset, SCM length);
extern SCM scm_read_line (SCM port);
extern SCM scm_write_line (SCM obj, SCM port);
extern SCM scm_ftell (SCM object);
diff --git a/libguile/ports.c b/libguile/ports.c
index 4e703cbdd..f955b0302 100644
--- a/libguile/ports.c
+++ b/libguile/ports.c
@@ -272,6 +272,37 @@ SCM_DEFINE (scm_char_ready_p, "char-ready?", 0, 1, 0,
}
#undef FUNC_NAME
+/* move up to read_len chars from port's putback and/or read buffers
+ into memory starting at dest. returns the number of chars moved. */
+size_t scm_take_from_input_buffers (SCM port, char *dest, size_t read_len)
+{
+ scm_port *pt = SCM_PTAB_ENTRY (port);
+ size_t chars_read = 0;
+ size_t from_buf = min (pt->read_end - pt->read_pos, read_len);
+
+ if (from_buf > 0)
+ {
+ memcpy (dest, pt->read_pos, from_buf);
+ pt->read_pos += from_buf;
+ chars_read += from_buf;
+ read_len -= from_buf;
+ dest += from_buf;
+ }
+
+ /* if putback was active, try the real input buffer too. */
+ if (pt->read_buf == pt->putback_buf)
+ {
+ from_buf = min (pt->saved_read_end - pt->saved_read_pos, read_len);
+ if (from_buf > 0)
+ {
+ memcpy (dest, pt->saved_read_pos, from_buf);
+ pt->saved_read_pos += from_buf;
+ chars_read += from_buf;
+ }
+ }
+ return chars_read;
+}
+
/* Clear a port's read buffers, returning the contents. */
SCM_DEFINE (scm_drain_input, "drain-input", 1, 0, 0,
(SCM port),
@@ -282,7 +313,6 @@ SCM_DEFINE (scm_drain_input, "drain-input", 1, 0, 0,
SCM result;
scm_port *pt = SCM_PTAB_ENTRY (port);
int count;
- char *dst;
SCM_VALIDATE_OPINPORT (1,port);
@@ -291,16 +321,7 @@ SCM_DEFINE (scm_drain_input, "drain-input", 1, 0, 0,
count += pt->saved_read_end - pt->saved_read_pos;
result = scm_makstr (count, 0);
- dst = SCM_STRING_CHARS (result);
-
- while (pt->read_pos < pt->read_end)
- *dst++ = *(pt->read_pos++);
-
- if (pt->read_buf == pt->putback_buf)
- {
- while (pt->saved_read_pos < pt->saved_read_end)
- *dst++ = *(pt->saved_read_pos++);
- }
+ scm_take_from_input_buffers (port, SCM_STRING_CHARS (result), count);
return result;
}
diff --git a/libguile/ports.h b/libguile/ports.h
index 9315c9d9f..9676bde18 100644
--- a/libguile/ports.h
+++ b/libguile/ports.h
@@ -244,6 +244,7 @@ extern void scm_set_port_truncate (long tc,
off_t length));
extern void scm_set_port_input_waiting (long tc, int (*input_waiting) (SCM));
extern SCM scm_char_ready_p (SCM port);
+size_t scm_take_from_input_buffers (SCM port, char *dest, size_t read_len);
extern SCM scm_drain_input (SCM port);
extern SCM scm_current_input_port (void);
extern SCM scm_current_output_port (void);