On Wed 07 Mar 2012 17:32, Nala Ginrut <nalagin...@gmail.com> 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 <nalagin...@gmail.com> 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, -@c 2010, 2011 Free Software Foundation, Inc. +@c 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)}. -@var{handle-delim} takes the same values as described for @code{read-line}. + +@var{handle-delim} takes the same values as described for +@code{read-line}, with one addition: +@table @code +@item 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}. +@end 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/