[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] add new read-delimited option to return #f while terminating
From: |
Andy Wingo |
Subject: |
Re: [PATCH] add new read-delimited option to return #f while terminating delimiter can't be found. |
Date: |
Wed, 23 Jan 2013 11:00:21 +0100 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.2 (gnu/linux) |
On Wed 07 Mar 2012 17:32, Nala Ginrut <address@hidden> writes:
> I found current read-delimited will return the whole string if delimiter
> can't be found. It's inconvenient for some cases.
>
> I expect it return #f for this.
> And Andy said it maybe because some back compatible reasons. So I decide
> to add an option to do this job.
I have fixed up the docs a bit, and now I really don't want to add it.
Patch attached, but here are the docs:
-- Scheme Procedure: read-delimited delims [port] [handle-delim]
Read text until one of the characters in the string DELIMS is found
or end-of-file is reached. Read from PORT if supplied, otherwise
from the value returned by `(current-input-port)'.
HANDLE-DELIM takes the same values as described for `read-line',
with one addition:
`fail'
If a delimiter is not found, return `#f' instead of returning
a string of the characters that were read. The characters
that were read are lost. Otherwise, return a string of the
characters that were read, without the delimiter, as in
`trim'.
-- Scheme Procedure: read-delimited! delims buf [port] [handle-delim]
[start] [end]
Read text into the supplied string BUF.
If a delimiter was found, return the number of characters written,
with two exceptions: if HANDLE-DELIM is `split', the return value
is a pair, as noted above; and if it is `fail', `#f' is returned
if the delimiter is not found.
As a special case, if PORT was already at end-of-stream, the EOF
object is returned. Also, if no characters were written because the
buffer was full, `#f' is returned.
It's something of a wacky interface, to be honest.
There are three things I don't like about `fail':
* It throws away the characters that were read. A user could expect
(incorrectly, and it's not really possible to do) that a return
value of #f leaves the characters in the port.
* It makes a strange interface even stranger.
* It falls back to the "trim" behavior, whereas a user might actually
want concat or peek. (If they wanted split, they could check
themselves).
Now that Guile 2.0 always truncates multiple-value returns, I think we
should change this interface to always return two values: the string
that was read, and the delimiter. Then we don't have to think about
modes, the default behavior is sane, and all the information is
available to the client if they call in a two-valued context.
> Now it's better:
> -----------------------------------cut-----------------------------------
> ------------------
> (call-with-input-string "asdf" (lambda (port) (read-delimited "@" port
> 'fail))))
> ==> #f
If you are reading from strings, there are better interfaces (regexes,
string-split, string-index, etc etc; see srfi-13).
So for now I am thinking that I would not like to apply this patch to
Guile.
Regards,
Andy
>From 33f272d55f1a70572e73eb41df34c4d914cf8b49 Mon Sep 17 00:00:00 2001
From: Nala Ginrut <address@hidden>
Date: Wed, 23 Jan 2013 00:30:25 +0800
Subject: [PATCH] Add 'fail' mode to read-delimited.
* doc/ref/api-io.texi: Update the doc for read-delmited.
* module/ice-9/rdelim.scm: Add new mode to read-delimited.
* test-suite/tests/rdelim.test: Add test case for 'fail' mode.
---
doc/ref/api-io.texi | 20 +++++++++++++++-----
module/ice-9/rdelim.scm | 2 ++
test-suite/tests/rdelim.test | 21 +++++++++++++++++++++
3 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/doc/ref/api-io.texi b/doc/ref/api-io.texi
index 11ae580..4ffad6b 100644
--- a/doc/ref/api-io.texi
+++ b/doc/ref/api-io.texi
@@ -1,7 +1,7 @@
@c -*-texinfo-*-
@c This is part of the GNU Guile Reference Manual.
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2007, 2009,
address@hidden 2010, 2011 Free Software Foundation, Inc.
address@hidden 2010, 2011, 2013 Free Software Foundation, Inc.
@c See the file guile.texi for copying conditions.
@node Input and Output
@@ -548,16 +548,26 @@ specified, otherwise from the value returned by
@code{(current-input-port)}.
Read text until one of the characters in the string @var{delims} is found
or end-of-file is reached. Read from @var{port} if supplied, otherwise
from the value returned by @code{(current-input-port)}.
address@hidden takes the same values as described for @code{read-line}.
+
address@hidden takes the same values as described for
address@hidden, with one addition:
address@hidden @code
address@hidden fail
+If a delimiter is not found, return @code{#f} instead of returning a
+string of the characters that were read. The characters that were read
+are lost. Otherwise, return a string of the characters that were read,
+without the delimiter, as in @code{trim}.
address@hidden table
@end deffn
@c begin (scm-doc-string "rdelim.scm" "read-delimited!")
@deffn {Scheme Procedure} read-delimited! delims buf [port] [handle-delim]
[start] [end]
Read text into the supplied string @var{buf}.
-If a delimiter was found, return the number of characters written,
-except if @var{handle-delim} is @code{split}, in which case the return
-value is a pair, as noted above.
+If a delimiter was found, return the number of characters written, with
+two exceptions: if @var{handle-delim} is @code{split}, the return value
+is a pair, as noted above; and if it is @code{fail}, @code{#f} is
+returned if the delimiter is not found.
As a special case, if @var{port} was already at end-of-stream, the EOF
object is returned. Also, if no characters were written because the
diff --git a/module/ice-9/rdelim.scm b/module/ice-9/rdelim.scm
index 32908cc..66ae5dc 100644
--- a/module/ice-9/rdelim.scm
+++ b/module/ice-9/rdelim.scm
@@ -76,6 +76,7 @@
((concat) (string-set! buf (+ nchars start) terminator)
(+ nchars 1))
((split) (cons nchars terminator))
+ ((fail) (if (eof-object? terminator) #f nchars))
(else (error "unexpected handle-delim value: "
handle-delim)))))))
@@ -113,6 +114,7 @@
(string-append joined (string terminator))))
((trim peek) joined)
((split) (cons joined terminator))
+ ((fail) (if (eof-object? terminator) #f joined))
(else (error "unexpected handle-delim value: "
handle-delim)))))))))
diff --git a/test-suite/tests/rdelim.test b/test-suite/tests/rdelim.test
index 5cfe646..f47270c 100644
--- a/test-suite/tests/rdelim.test
+++ b/test-suite/tests/rdelim.test
@@ -113,6 +113,16 @@
(read-delimited ",.;" (open-input-string "hello, world!")
'concat)))
+ (pass-if "delimiter miss, fail"
+ (equal? #f
+ (read-delimited "@" (open-input-string "asdf")
+ 'fail)))
+
+ (pass-if "delimiter hit, fail"
+ (equal? "hello"
+ (read-delimited "," (open-input-string "hello, world")
+ 'fail)))
+
(pass-if "delimiter hit, peek"
(let ((p (open-input-string "hello, world!")))
(and (string=? "hello" (read-delimited ",.;" p 'peek))
@@ -161,6 +171,11 @@
(string=? (substring s 0 5) "hello")
(char=? #\, (peek-char p)))))
+ (pass-if "delimiter hit, fail"
+ (let ((s (make-string 123))
+ (p (open-input-string "asdf")))
+ (not (read-delimited! "@" s p 'fail))))
+
(pass-if "string too small"
(let ((s (make-string 7)))
(and (= 7 (read-delimited! "}{" s
@@ -183,6 +198,12 @@
'split))
(string=? s "hello, "))))
+ (pass-if "string too small, fail"
+ (let ((s (make-string 7)))
+ (not (read-delimited! "@" s
+ (open-input-string "asdf")
+ 'fail))))
+
(pass-if "eof"
(eof-object? (read-delimited! ":" (make-string 7)
(open-input-string ""))))
--
1.7.10.4
--
http://wingolog.org/