Subject: [clisp-list] bug in read-byte-sequence?

From: Basim Al-Shaikhli <[email-masked]>
Date: Fri Oct 10 11:49:03 2003

hi,

i think (feel free to correct me if i'm wrong) there's a bug in
ext:read-byte-sequence with the :no-hang option it seems to
loose the first read byte.

if i try to read the char-sequence "asdfg" it returns "sdfg". and
when called once again returns the missing #\a.

clisp-version is 2.31 (2003-09-01) on WinXP

to demonstrate about what i'm talking, please read the following
transcript. there are 4 tests:

1) (socket-accept ... :buffered nil) with (read-byte-sequence :no-hang t)
fails

2) (socket-accept ... :buffered nil) with (read-byte-sequence :no-hang nil)
works

3) (socket-accept ... :buffered t) with (read-byte-sequence :no-hang t)
works

4) (socket-accept ... :buffered t) with (read-byte-sequence :no-hang nil)
works

i start clisp with

> lisp.exe -M lispinit.mem -q

[1]> (setf s (SOCKET:SOCKET-SERVER 8888))
#<SOCKET-SERVER 0.0.0.0:8888>

from another console window i do a

telnet 127.0.0.1 8888

and type asdfg <ret> ...

back in lisp:

[2]> (setf st (socket:socket-accept s))
#<IO UNBUFFERED SOCKET-STREAM CHARACTER 0.0.0.0:8888>

[3]> (setf (stream-element-type st) '(unsigned-byte 8))
(UNSIGNED-BYTE 8)

[4]> (ext:read-byte-sequence
        (setf a (make-array 10 :element-type '(unsigned-byte 8)
                               :initial-element 32))
           st :no-hang t)
6

[5]> a
#(115 100 102 103 13 10 32 32 32 32)

... so, the #\a from "asdfg" is missing... but where is it?

[6]> (ext:read-byte-sequence
         (setf a (make-array 10 :element-type '(unsigned-byte 8)
                                :initial-element 32))
         st :no-hang t)

1
[7]> a
#(97 32 32 32 32 32 32 32 32 32)

ah, here it is. strange, isn't it?

now i do the same without :no-hang

[8]> (ext:read-byte-sequence
              (setf a (make-array 10 :element-type '(unsigned-byte 8)
                                     :initial-element 32))
               st)
7

[9]> a
#(97 115 100 102 103 13 10 32 32 32)

this is what one would expect...

next, i try both combinations with the :buffered t option from
socket-accept:

[10]> (setf st (socket:socket-accept s :buffered t))
#<IO BUFFERED SOCKET-STREAM CHARACTER 0.0.0.0:8888>

[11]> (ext:read-byte-sequence
              (setf a (make-array 10 :element-type '(unsigned-byte 8)
                                     :initial-element 32))
               st :no-hang t)
10

[12]> a
#(97 115 100 102 103 13 10 32 32 32)

[13]> (ext:read-byte-sequence
              (setf a (make-array 10 :element-type '(unsigned-byte 8)
                                     :initial-element 32))
               st :no-hang nil)
10

[14]> a
#(97 115 100 102 103 13 10 32 32 32)

---

From: Sam Steingold <[email-masked]>
Date: Fri Oct 10 22:18:03 2003

> * Basim Al-Shaikhli <[email-masked]> [2003-10-10 20:45:15 +0200]:
>
> ext:read-byte-sequence with the :no-hang option it seems to loose the
> first read byte.

indeed - please try the appended patch.

-- 
Sam Steingold (http://www.podval.org/~sds) running w2k
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.honestreporting.com>
Good judgment comes from experience and experience comes from bad judgment.

--- stream.d.~1.384.~	2003-10-09 19:17:53.189923800 -0400
+++ stream.d	2003-10-11 01:12:20.566761600 -0400
@@ -4948,18 +4948,28 @@
   return true;
 }
 
-local uintB* low_read_array_unbuffered_handle (object stream, uintB* byteptr,
-                                               uintL len, bool no_hang) {
-  if (UnbufferedStream_status(stream) < 0) # already EOF?
-    return byteptr;
-  while (UnbufferedStream_status(stream) > 0) { # bytebuf contains valid bytes?
+local inline uintB* UnbufferedStream_pop_all
+(object stream, uintB* byteptr, uintL *len)
+{ /* pop bytebuf into byteptr */
+  while (UnbufferedStream_status(stream) > 0) { /* have valid bytes? */
     UnbufferedStreamLow_pop_byte(stream,b);
     *byteptr++ = b;
-    len--;
-    if (len == 0)
+    if (--*len == 0)
+      break;
+  }
       return byteptr;
   }
+
+local uintB* low_read_array_unbuffered_handle (object stream, uintB* byteptr,
+                                               uintL len, bool no_hang) {
+  if (UnbufferedStream_status(stream) < 0) /* already EOF? */
+    return byteptr;
+  byteptr = UnbufferedStream_pop_all(stream,byteptr,&len);
+  if (len == 0) return byteptr;
   if (!no_hang || ls_avail_p(low_listen_unbuffered_handle(stream))) {
+    /* low_listen_unbuffered_handle could add to bytebuf */
+    byteptr = UnbufferedStream_pop_all(stream,byteptr,&len);
+    if (len == 0) return byteptr;
     var Handle handle = TheHandle(TheStream(stream)->strm_ichannel);
     run_time_stop(); /* hold run time clock */
     begin_system_call();

---

From: Basim Al-Shaikhli <[email-masked]>
Date: Sat Oct 11 05:28:03 2003

Sam Steingold wrote:

>>* Basim Al-Shaikhli <[email-masked]> [2003-10-10 20:45:15 +0200]:
>>
thank you, but unfortunately i've neither a c-compiler, nor do i have 
the clisp-source. ;-)

Basim