[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: |
Nala Ginrut |
Subject: |
Re: [PATCH] add new read-delimited option to return #f while terminating delimiter can't be found. |
Date: |
Wed, 23 Jan 2013 18:24:20 +0800 |
On Wed, 2013-01-23 at 11:00 +0100, Andy Wingo wrote:
> 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.
>
OK, since this patch is a little old (one year ago), I can't remember
exactly what code-context make me send this patch. So it may lack of
persuade power.
And I realized that it could be solved like this:
------------------code-----------------
(define (read-delimiter-fail delim port)
(let ((r (read-delimiter delim 'split)))
(if (eof-object? (cdr r))
#f
(car r))))
------------------end------------------
Though I don't agree the all three points, it's not worthy to get
involved with this issue anymore.
@andy: it's the cautious in last second I should learn. I confess I
don't think hard about this patch. ;-)
> Regards,
>
> Andy
>
> differences between files attachment
> (0001-Add-fail-mode-to-read-delimited.patch)
> 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 ""))))