From 1b20b0c4761ac03c369b17b923bdf2372395b73e Mon Sep 17 00:00:00 2001
From: Doug Coleman <doug.coleman@gmail.com>
Date: Thu, 8 Sep 2011 17:24:05 -0700
Subject: [PATCH] Make sure 0 read always returns f. Fixes issue #70. More unit
 tests, fix read-until to return f f sometimes Rename ((read-until)) to
 read-until-loop. Fix the stack effect declarations of (read) and
 handle-readln.

---
 basis/io/streams/string/string-tests.factor   |  6 ++++
 core/io/encodings/encodings.factor            | 33 ++++++++++++-------
 .../byte-array/byte-array-tests.factor        | 12 ++++++-
 3 files changed, 38 insertions(+), 13 deletions(-)

diff --git a/basis/io/streams/string/string-tests.factor b/basis/io/streams/string/string-tests.factor
index 27971f1431..fe01626dec 100644
--- a/basis/io/streams/string/string-tests.factor
+++ b/basis/io/streams/string/string-tests.factor
@@ -59,3 +59,9 @@ unit-test
     dup stream-readln
     2 rot stream-read
 ] unit-test
+
+! Issue #70 github
+[ f ] [ "" [ 0 read ] with-string-reader ] unit-test
+[ f ] [ "" [ 1 read ] with-string-reader ] unit-test
+[ f ] [ "" [ readln ] with-string-reader ] unit-test
+[ "\"\"" ] [ "\"\"" [ readln ] with-string-reader ] unit-test
diff --git a/core/io/encodings/encodings.factor b/core/io/encodings/encodings.factor
index 1880859db1..1b34b6aa8b 100644
--- a/core/io/encodings/encodings.factor
+++ b/core/io/encodings/encodings.factor
@@ -1,9 +1,8 @@
 ! Copyright (C) 2008, 2010 Daniel Ehrenberg, Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: math kernel sequences sbufs vectors namespaces growable
-strings io classes continuations destructors combinators
-io.streams.plain splitting byte-arrays
-sequences.private accessors ;
+USING: accessors combinators destructors io io.streams.plain
+kernel math namespaces sbufs sequences sequences.private
+splitting strings ;
 IN: io.encodings
 
 ! The encoding descriptor protocol
@@ -69,14 +68,16 @@ M: decoder stream-read1
         ] when
     ] when nip ; inline
 
-: (read) ( n quot -- n string )
+! If we read the entire buffer, chars-read is f
+! If we hit EOF while reading, chars-read indicates how many chars were read
+: (read) ( chars-requested quot -- chars-read/f string )
     over 0 <string> [
         [
             over [ swapd set-nth-unsafe f ] [ 3drop t ] if
         ] curry compose find-integer
     ] keep ; inline
 
-: finish-read ( n string -- string/f )
+: finish-read ( n/f string -- string/f )
     {
         { [ over 0 = ] [ 2drop f ] }
         { [ over not ] [ nip ] }
@@ -84,8 +85,13 @@ M: decoder stream-read1
     } cond ; inline
 
 M: decoder stream-read
-    [ nip ] [ >decoder< [ decode-char ] 2curry (read) finish-read ] 2bi
-    fix-read ;
+    over 0 = [
+        2drop f
+    ] [
+        [ nip ]
+        [ >decoder< [ decode-char ] 2curry (read) finish-read ] 2bi
+        fix-read
+    ] if ;
 
 M: decoder stream-read-partial stream-read ;
 
@@ -104,13 +110,16 @@ M: decoder stream-read-partial stream-read ;
         { CHAR: \n [ line-ends\n ] }
     } case ; inline
 
-: ((read-until)) ( buf quot: ( -- char stop? ) -- string/f sep/f )
+! If the stop? branch is taken convert the sbuf to a string
+! If sep is present, returns ``string sep'' (string can be "")
+! If sep is f, returns ``string f'' or ``f f''
+: read-until-loop ( buf quot: ( -- char stop? ) -- string/f sep/f )
     dup call
-    [ [ drop "" like ] dip ]
-    [ pick push ((read-until)) ] if ; inline recursive
+    [ nip [ "" like ] dip [ f like f ] unless* ]
+    [ pick push read-until-loop ] if ; inline recursive
 
 : (read-until) ( quot -- string/f sep/f )
-    100 <sbuf> swap ((read-until)) ; inline
+    [ 100 <sbuf> ] dip read-until-loop ; inline
 
 : decoder-read-until ( seps stream encoding -- string/f sep/f )
     [ decode-char dup [ dup rot member? ] [ 2drop f t ] if ] 3curry
diff --git a/core/io/streams/byte-array/byte-array-tests.factor b/core/io/streams/byte-array/byte-array-tests.factor
index 1c7826719c..c220121402 100644
--- a/core/io/streams/byte-array/byte-array-tests.factor
+++ b/core/io/streams/byte-array/byte-array-tests.factor
@@ -1,10 +1,20 @@
 USING: tools.test io.streams.byte-array io.encodings.binary
 io.encodings.utf8 io kernel arrays strings namespaces math
-specialized-arrays alien.c-types ;
+specialized-arrays alien.c-types io.encodings.ascii ;
 SPECIALIZED-ARRAY: int
 IN: io.streams.byte-array.tests
 
 [ B{ } ] [ B{ } binary [ contents ] with-byte-reader ] unit-test
+
+! Issue #70 github
+[ f ] [ B{ } binary [ 0 read ] with-byte-reader ] unit-test
+[ f ] [ B{ } binary [ 1 read ] with-byte-reader ] unit-test
+[ f ] [ B{ } ascii [ 0 read ] with-byte-reader ] unit-test
+[ f ] [ B{ } ascii [ readln ] with-byte-reader ] unit-test
+[ f f ] [ B{ } ascii [ "a" read-until ] with-byte-reader ] unit-test
+[ f f ] [ B{ } binary [ { 2 } read-until ] with-byte-reader ] unit-test
+
+
 [ B{ 1 2 3 } ] [ binary [ B{ 1 2 3 } write ] with-byte-writer ] unit-test
 [ B{ 1 2 3 4 5 6 } ] [ binary [ B{ 1 2 3 } write B{ 4 5 6 } write ] with-byte-writer ] unit-test
 [ B{ 1 2 3 } ] [ { 1 2 3 } binary [ 3 read ] with-byte-reader ] unit-test