Subject: [clisp-list] ext:with-keyboard / ext:*keyboard-input* and listen

From: Jamison Masse <[email-masked]>
Date: Wed Dec 11 17:20:03 2002

Hello,
 There is seems to be a bug in linux clisp (I tried this with WinXP and
it seemed to work as I expected) with with-keyboard/keyboard-input. If
you run this code the first character typed is ignored, then the second
is picked up and the loop terminates. The same behaviour if
read-char-no-hang is used instead of the listen/read-char combo. Of
course, I expect it to pick up the first character.

(setq c nil)
(ext:with-keyboard
 (loop
  (if (listen ext:*keyboard-input*) 
     (setq c (read-char ext:*keyboard-input*)))
 (when (not (eq nil c)) (return))))
(print c)

I'm running clisp 2.29/Redhat 7.3

---

From: Sam Steingold <[email-masked]>
Date: Fri Dec 13 07:53:03 2002

> * In message <[email-masked]>
> * On the subject of "[clisp-list] ext:with-keyboard / ext:*keyboard-input* and listen"
> * Sent on 12 Dec 2002 10:24:38 +0900
> * Honorable Jamison Masse <[email-masked]> writes:
>

thanks for reporting the bug.
Please try the appended patch - it should fix the bug.
Please report your experiences here ASAP.

>  (when (not (eq nil c)) (return))))

note that this is a "busywait" loop, i.e., it will get your loadavg to 1.

> I'm running clisp 2.29/Redhat 7.3

the latest release is 2.30.

-- 
Sam Steingold (http://www.podval.org/~sds) running RedHat8 GNU/Linux
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html>
Man has 2 states: hungry/angry and sate/sleepy.  Catch him in transition.

--- stream.d.~1.324.~	2002-12-12 21:32:21.000000000 -0500
+++ stream.d	2002-12-13 10:46:18.000000000 -0500
@@ -8635,6 +8635,12 @@
 #endif
 
 #if (defined(UNIX) && !defined(NEXTAPP)) || defined(RISCOS)
+local inline gcv_object_t* kbd_last_buf (const gcv_object_t* stream_) {
+  var gcv_object_t* last_ = &TheStream(*stream_)->strm_keyboard_buffer;
+  while (mconsp(*last_)) { last_ = &Cdr(*last_); }
+  return last_;
+}
+
 # cf. rd_ch_unbuffered() :
 local object rd_ch_keyboard (const gcv_object_t* stream_) {
  restart_it:
@@ -8642,6 +8648,15 @@
   if (eq(TheStream(stream)->strm_rd_ch_last,eof_value)) # EOF already?
     return eof_value;
   # Still something in the Buffer?
+  if (UnbufferedStream_status(stream) > 0) {
+    var uintL num_bytes = UnbufferedStream_status(stream);
+    var uintB *bytes = UnbufferedStream_bytebuf(stream);
+    var uintL count;
+    UnbufferedStream_status(stream) = 0;
+    dotimespL(count,num_bytes,{ pushSTACK(code_char(as_chart(*bytes++))); }); # FIXME: This should take into account the encoding.
+    *kbd_last_buf(stream_) = listof(num_bytes);
+    stream = *stream_;
+  }
   if (mconsp(TheStream(stream)->strm_keyboard_buffer))
     goto empty_buffer;
   # read a character:
@@ -8668,20 +8683,16 @@
         TheStream(stream)->strm_rd_ch_last = eof_value; return eof_value;
       }
     }
-  next_char_is_read:
-    # It increases the Buffer:
-    {
+  next_char_is_read: { /* increase the buffer: */
       var object new_cons = allocate_cons();
       Car(new_cons) = code_char(as_chart(c)); # FIXME: This should take into account the encoding.
-      stream = *stream_;
-      var gcv_object_t* last_ = &TheStream(stream)->strm_keyboard_buffer;
-      while (mconsp(*last_)) { last_ = &Cdr(*last_); }
-      *last_ = new_cons;
+      *kbd_last_buf(stream_) = new_cons;
     }
     # Is the buffer a complete sequence of characters for a key,
     # so we will return this key. Is the buffer a genuine starting piece
     # of a sequence of characters for a key, so we will wait a little bit.
     # Otherwise we start to empty the buffer character for character.
+    stream = *stream_;
     {
       var object keytab = TheStream(stream)->strm_keyboard_keytab;
       while (consp(keytab)) {

---

From: Jamison Masse <[email-masked]>
Date: Sun Dec 15 01:25:02 2002

> Please report your experiences here ASAP.
I downloaded 2.30 (was running 2.29), applied the patch the stream.d and
it failed to compile, the errors follow:

stream.d: At top level:
stream.d:8649: parse error before `*'
stream.d:8649: warning: type defaults to `int' in declaration of
`gcv_object_t'
stream.d:8649: parse error before `*'
stream.d:8649: warning: return type defaults to `int'
stream.d: In function `kbd_last_buf':
stream.d:8650: `gcv_object_t' undeclared (first use in this function)
stream.d:8650: (Each undeclared identifier is reported only once
stream.d:8650: for each function it appears in.)
stream.d:8650: `last_' undeclared (first use in this function)
stream.d:8650: `stream_' undeclared (first use in this function)
stream.d:8653: warning: control reaches end of non-void function

I quickly grep'ed around the source and couldn't find a definition for
gcv_object_t, perhaps there's more changes in cvs I need to pick up?
Anyway, its not that important, I have no problem waiting for the next
point revision to pick up the patch and test it.
 
> note that this is a "busywait" loop, i.e., it will get your loadavg to 1.
I'm aware of that (and unhappy about it), does clisp have a mechanism
that will raise some sort of event when a stream's got something to say?
I want to grab keyboard input and keep an eye on a socket at the same
time.

Thanks,
Jamison

---

From: Sam Steingold <[email-masked]>
Date: Sun Dec 15 06:41:02 2002

> * In message <[email-masked]>
> * On the subject of "Re: [clisp-list] ext:with-keyboard / ext:*keyboard-input* and listen"
> * Sent on 15 Dec 2002 18:29:45 +0900

replace `gcv_object_t' with `object'.

> I want to grab keyboard input and keep an eye on a socket at the same

SOCKET-STATUS
<http://clisp.cons.org/impnotes/socket.html#so-status>

-- 
Sam Steingold (http://www.podval.org/~sds) running RedHat8 GNU/Linux
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.palestine-central.com/links.html>
Trespassers will be shot.  Survivors will be prosecuted.

---

From: Sam Steingold <[email-masked]>
Date: Sun Dec 15 12:40:04 2002

> <http://clisp.cons.org/impnotes/socket.html#so-status>

you will need the appended patch to make SOCKET-STATUS work with
keyboard-streams too.  (or use CVS head)

Garbage In, Gospel Out

Index: stream.d
===================================================================
RCS file: /cvsroot/clisp/clisp/src/stream.d,v
retrieving revision 1.325
retrieving revision 1.326
diff -u -w -b -u -b -w -i -B -r1.325 -r1.326
--- stream.d	13 Dec 2002 16:04:39 -0000	1.325
+++ stream.d	15 Dec 2002 20:08:16 -0000	1.326
@@ -14822,6 +14822,11 @@
       if (out_sock) *out_sock = (SOCKET)stdout_handle;
       if (char_p) *char_p = true;
       return;
+    case strmtype_keyboard:
+      if (in_sock)
+        *in_sock = TheSocket(TheStream(obj)->strm_keyboard_handle);
+      if (char_p) *char_p = true;
+      return;
     case strmtype_twoway_socket:
       obj = TheStream(obj)->strm_twoway_socket_input;
       if (in_sock)  *in_sock  = SocketChannel(obj);