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: 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/

reply via email to

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