Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CMUCL: read-char

15 views
Skip to first unread message

Matthias Hanitzsch

unread,
Dec 3, 2001, 3:04:12 AM12/3/01
to
Hallo,

i use CMUCL and (read-char) expects to have a RETURN after the
character.
How can i change this to work without the RETURN ?

Thank you for help !

Matthias

Harald Hanche-Olsen

unread,
Dec 3, 2001, 4:43:43 PM12/3/01
to
+ Matthias Hanitzsch <Matthias....@dynamic.de>:

| i use CMUCL and (read-char) expects to have a RETURN after the
| character.

Er, no, it does not. But terminal input is line buffered by default,
and this is probably what bites you.

| How can i change this to work without the RETURN ?

If there is a portable way to do it in Common Lisp, I am sure someone
will say so. I don't see one, though. And I don't see any ready-made
functions for it in CMUCL either, which means you must do the system
call yourself. So you will have to learn to use ioctl() to turn off
input line buffering, and to turn it back on afterwards. Thus this
turns into a unix question, which is probably not appropriate in this
newsgroup. Also, most likely the file descriptor hiding behind
*standard-input* is 0 - but whether or not you can fiddle with ioctl()
on file descriptor 0 behind cmucl's back without getting burnt, is
anybody's guess. So you may have to open /dev/tty explicitly for this
purpose. Check the Unix interface chapter in the CMUCL users manual,
read the man pages (ioctl and termios), and if you get stuck ask for
help on the cmucl mailing list.

--
* Harald Hanche-Olsen <URL:http://www.math.ntnu.no/~hanche/>
- Yes it works in practice - but does it work in theory?

Nils Goesche

unread,
Dec 3, 2001, 3:13:50 PM12/3/01
to
Matthias Hanitzsch <Matthias....@dynamic.de> writes:

> i use CMUCL and (read-char) expects to have a RETURN after the
> character.

Actually, it doesn't:

* (cons (read-char) (read-char))
ab
(#\a . #\b)
*

> How can i change this to work without the RETURN ?

Do you want unbuffered I/O?

Regards,
--
Nils Goesche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x42B32FC9

Kaz Kylheku

unread,
Dec 3, 2001, 6:37:22 PM12/3/01
to
In article <lk4rn8q...@pc022.bln.elmeg.de>, Nils Goesche wrote:
>Matthias Hanitzsch <Matthias....@dynamic.de> writes:
>
>> i use CMUCL and (read-char) expects to have a RETURN after the
>> character.
>
>Actually, it doesn't:
>
>* (cons (read-char) (read-char))
>ab
>(#\a . #\b)
>*
>
>> How can i change this to work without the RETURN ?
>
>Do you want unbuffered I/O?

He probably wants the terminal driver to make its buffered input
available immediately, without accumulating it until a complete line
is formed.

A the C level, that's arranged using tcgetattr(), tcsetattr() and
struct termios.

mda...@andrew.cmu.edu

unread,
Dec 3, 2001, 7:21:42 PM12/3/01
to
>
> If there is a portable way to do it in Common Lisp, I am sure someone
> will say so. I don't see one, though. And I don't see any ready-made
> functions for it in CMUCL either, which means you must do the system
> call yourself. So you will have to learn to use ioctl() to turn off
> input line buffering, and to turn it back on afterwards. Thus this
> turns into a unix question, which is probably not appropriate in this
> newsgroup. Also, most likely the file descriptor hiding behind
> *standard-input* is 0 - but whether or not you can fiddle with ioctl()
> on file descriptor 0 behind cmucl's back without getting burnt, is
> anybody's guess. So you may have to open /dev/tty explicitly for this
> purpose. Check the Unix interface chapter in the CMUCL users manual,
> read the man pages (ioctl and termios), and if you get stuck ask for
> help on the cmucl mailing list.
>

My package "Line-Reader" uses the CMUCL/SBCL FFI to accomplish this,
in file setattr.c and terminfo.lisp. I decided not to implement the
termios structures in the FFI since they seem to be rather system-dependent.

See http://emu.res.cmu.edu/~mrd/line-reader/

Though this actually has problems on CMUCL, for some odd reason:
When you first compile and load the terminfo.lisp file it works fine,
but on subsequent reloads, it complains that "setupterm" is not a
defined foreign symbol. SBCL doesn't complain, go figure. I'm still
looking into it.


--
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Matthew Danish email: mda...@andrew.cmu.edu ;;
;; OpenPGP public key available from: 'finger m...@db.debian.org' ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Nils Goesche

unread,
Dec 4, 2001, 2:44:55 AM12/4/01
to
k...@ashi.footprints.net (Kaz Kylheku) writes:

That works in CMUCL, too. Use functions as unix:unix-tcsetattr.
It's been a while since I used them, but they seemed to work
pretty well.

Regards,
--
Nils Goesche
Ask not for whom the <CONTROL-G> tolls.

PGP key ID 0xC66D6E6F

Fred Gilham

unread,
Dec 4, 2001, 11:15:40 AM12/4/01
to

Here's some code that uses the CMUCL unix interface to turn echoing on
and off. I guess you could use the same idea to turn buffering on and
off. This code could at least give the idea of how it could be done.


;;; Function to get input without echoing---for inputting passwords and the like.
;;; Depends on CMUCL unix interface package.
(defun echo-off (fd)
(when (unix:unix-isatty fd)
(alien:with-alien ((tios (alien:struct unix:termios)))
(multiple-value-bind
(val err)
(unix:unix-tcgetattr fd (alien:alien-sap tios))
(when (null val)
(error "Could not tcgetattr, unix error ~S."
(unix:get-unix-error-msg err))))
(let ((old-c-lflag (alien:slot tios 'unix:c-lflag)))
(setf (alien:slot tios 'unix:c-lflag)
(logand (alien:slot tios 'unix:c-lflag)
(lognot (logior unix:tty-echo unix:tty-icanon))))
(multiple-value-bind
(val err)
(unix:unix-tcsetattr fd unix:tcsaflush (alien:alien-sap tios))
(when (null val)
(error "Could not tcsetattr, unix error ~S."
(unix:get-unix-error-msg err))))
old-c-lflag))))


(defun restore-c-lflag (fd old-c-lflag)
(when (unix:unix-isatty fd)
(alien:with-alien ((tios (alien:struct unix:termios)))
(multiple-value-bind
(val err)
(unix:unix-tcgetattr fd (alien:alien-sap tios))
(when (null val)
(error "Could not tcgetattr, unix error ~S."
(unix:get-unix-error-msg err))))
(setf (alien:slot tios 'unix:c-lflag) old-c-lflag)
(multiple-value-bind
(val err)
(unix:unix-tcsetattr fd unix:tcsaflush (alien:alien-sap tios))
(when (null val)
(error "Could not tcsetattr, unix error ~S."
(unix:get-unix-error-msg err))))))
(values))


(defun get-input-no-echo (stream)
(let ((input "")
(fd (system:fd-stream-fd (if (common-lisp::two-way-stream-p stream)
(two-way-stream-output-stream stream)
stream))))
(let ((old-c-lflag (echo-off fd)))
(unwind-protect
(setf input (read-line stream))
(restore-c-lflag fd old-c-lflag)))
input))


(defun prompt-and-read-reply (prompt)
(format t prompt)
(force-output)
(read-line))

(defun prompt-and-read-reply-no-echo (prompt)
(format t prompt)
(force-output)
(get-input-no-echo system:*tty*))


--
Fred Gilham gil...@csl.sri.com
"...If reason is no longer a faculty enabling us to discern some
cosmic design, then it is no longer clear what claim reason has upon
us, or upon our politics. On the contrary, the sorts of habits that we
associate with `reasoning' --- that is, reflecting and discussing and
trying to achieve some kind of coherence among our various opinions
--- can come to seem like nothing more than the mental preferences (or
prejudices) of a particular class of people --- the dogmatic
proceduralism of an educated elite." --- Steven D. Smith

0 new messages