guile-devel
[Top][All Lists]
Advanced

[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 ""))))





reply via email to

[Prev in Thread] Current Thread [Next in Thread]