Subject: AW: [clisp-list] read-line (clisp 2.30/woody)

From: "Hoehle, Joerg-Cyril" <[email-masked]>
Date: Mon Jan 20 09:20:08 2003

Hi,

I tried out Michael's example code. It appears that the symptom come from CRLF or CR occurring in the stream. Whether this is acceptable behaviour I shall not comment upon now. What's observable is that users have been hit by READ-LINE several times already in the past.

E.g. type blabla CTRL-J blob CTRL-J -> everything is fine
Use CRLF (e.g. add CTRL-M) or solely CR as line terminator and I start observing those empty lines

Status (NIL INPUT)
Line: () Flag:(NIL)
Status (NIL INPUT)
Line: (oihdjui) Flag:(NIL)
Status (NIL NIL)

The strange empty line is returned as soon as I start entering the next input (long after the CTRL-M terminating the previous line).

BTW, here's a small bug:
(describe sock)
#<IO UNBUFFERED SOCKET-STREAM CHARACTER 0.0.0.0:5555> is an 
input/output-stream.waiting for input
            dot    ^ here    but not ^there

BTW, in my setup, when I close the MS-Windows goofy telnet window, I don't see any errors reported in the status line, but the loop immediately runs to completion (apparently socket-status returns without waiting).

>   - but the following progn does NOT show
>  the named missbehavior - so its a side effect between socket-status
>  and read-line, as the call of socket-status is the main difference
>  between them.
[read-line in a loop, without socket-status]
Indeed, the difference in behaviour sounds unnormal. Maybe the internal state engine about CR and/or LF line-termination detection is broken?

Regards,
	Jorg Hohle.

---

From: Michael Koehne <[email-masked]>
Date: Mon Jan 20 18:49:05 2003

Moin Joerg-Cyril Hoehle, 

> I tried out Michael's example code. It appears that the symptom come
> from CRLF or CR occurring in the stream.

  *hm* nice that someone else managed to reproduce the situation.

> Indeed, the difference in behaviour sounds unnormal. Maybe the internal
  state engine about CR and/or LF line-termination detection is broken?

  well something with read-line or read-sequence semantics would never
  work reliable together with the select() system call. A code calling
  socket-status and read-line is broken by design, even if the side
  effect between socket-status and read-line is solved. A ready for
  reading condition on select() system call means that one can do
  !exactly one! read() system call afterwards. Now read-line wants
  a line, so read-line will block, if there is no <CR><LF> in the
  first packet.
  
  I think I need two low level lisp functions :
  
        (unix-read array &optional stream) => count; errno
        (unix-write array &optional stream) => count; errno

  The main difference between this unix-read and read-sequence is
  that read-sequence will block to fill the array, unless :eof,
  while the unix read() system call only returns those bytes that
  are already there.
  
CLHS:
  Position is the index of the first element of sequence that was not          
  updated, which might be less than end because the end of file was
  reached.   
man 2 read
  It is not an  error  if  this  number  is smaller  than the number
  of bytes requested; this may happen for example because fewer bytes
  are actually available right now.

  The unix-write has to provide writing for such low level sockets.
  SIGPIPE should be ignored before the write() system call, so EPIPE
  could be used as a normal error conditions. Its a question, if count
  should become NIL or stay -1 on error conditions.

  Btw: My idea is chat server, where people can connect via normal
  telnet or special mud clients. So unix-read and unix-write must
  think in bytes semantics, as the server has to implement IAC
  options of telnet protocol.

  I tried read-sequence similar using read() and select(), but using
  read-sequence with an array of size 4096 instead of read-line will
  block. But an array size of one should work - i thought ;-(

(progn
  (format t "waiting for connect")
  (setq serv (socket-server 5555))
  (setq sock (socket-accept serv))
  (setq buff (make-array 1))
; (setq buff (make-array 1 :element-type '(integer 0 255)))
  (format t "waiting for input")
  (dotimes (n 1000)
    (setq stat (socket-status (list serv (cons sock :input)) 0 500000))
    (format t "Status ~A~%" stat)
    (when (eq (cadr stat) :INPUT)
      (setq flag (read-sequence buff sock))
      (format t "Line: (~A) Flag:(~A)~%" buff flag)
      )
    )
  )

  Constraining the array to bytes (i dont want any c-function to
  interprete the stream - i have to talk IAC telnet options - without
  any translations) did'nt work :

*** - SYSTEM::STORE: #\a does not fit into #(0), bad type

  not constraining the array type will reveal the followin missfortune.

  the first 'asdfg<enter>' :

    Status (NIL NIL)
    Status (NIL INPUT)
    Line: (#(a)) Flag:(1)
    Status (NIL INPUT)
    Line: (#(s)) Flag:(1)
    Status (NIL INPUT)
    Line: (#(d)) Flag:(1)
    Status (NIL INPUT)
    Line: (#(f)) Flag:(1)
    Status (NIL INPUT)
    Line: (#(g)) Flag:(1)
    Status (NIL INPUT)
    Line: (#()) Flag:(1)                    < perhaps CR - where is LF ?
    Status (NIL NIL)

  the first 'asdfg<enter>' :

    Status (NIL NIL)
    Status (NIL INPUT)
    Line: (#()) Flag:(1)                    < what happens here ? LF buffered ?
    Status (NIL INPUT)
    Line: (#(a)) Flag:(1)
    Status (NIL INPUT)
    Line: (#(s)) Flag:(1)
    Status (NIL INPUT)
    Line: (#(d)) Flag:(1)
    Status (NIL INPUT)
    Line: (#(f)) Flag:(1)
    Status (NIL INPUT)
    Line: (#(g)) Flag:(1)
    Status (NIL INPUT)
    Line: (#()) Flag:(1)                    < perhaps CR - where is LF ?
    Status (NIL NIL)

  user types control-]close in telnet

    Status (NIL NIL)
    Status (NIL INPUT)
    Line: (#()) Flag:(1)                    < this should be #(), 0
                                              or its the buffered LF,
                                              but I'm missing eof
                                              condition here
    Status (NIL NIL)
    Status (NIL NIL)                        < nearly 1000 times
                                              as usual socket-server is
                                              running wild, because of a
                                              dead socket.

  so i cant distinct between <CR> and <LF> as both are mapped #()
  and i still dont have a way to catch the :eof condition.

Bye Michael
-- 
  mailto:[email-masked]             UNA:+.? 'CED+2+:::Linux:2.4.6'UNZ+1'
  http://www.xml-edifact.org/           CETERUM CENSEO WINDOWS ESSE DELENDAM