From Newsgroup: comp.lang.lisp
I have been going crazy over this (over the years...)
I remeber that the Linux OS would put a pad of 0 bytes into the terminfo struct. Really mean :)
I've enclosed a postscript because I like the colors better.
TINFO> (setq xyz (make-instance 'sb-posix:termios))
#<SB-POSIX:TERMIOS {12046E7FF3}>
TINFO> xyz
#<SB-POSIX:TERMIOS {12046E7FF3}>
TINFO> (sb-posix:termios-iflags xyz)
; Evaluation aborted on #<SB-INT:SIMPLE-READER-PACKAGE-ERROR "Symbol ~S not found in the ~A package." {1205C17CE3}>.
TINFO> (sb-posix:termios-iflag xyz)
; Evaluation aborted on #<UNBOUND-SLOT IFLAG {12092D2853}>.
TINFO> (sb-posix:termios-oflag xyz)
; Evaluation aborted on #<UNBOUND-SLOT OFLAG {1209D299F3}>.
TINFO> (sb-posix::termios-oflag xyz)
; Evaluation aborted on #<UNBOUND-SLOT OFLAG {120AB905C3}>.
TINFO> (sb-posix:termios-lflag xyz)
; Evaluation aborted on #<UNBOUND-SLOT LFLAG {120B12B4D3}>.
TINFO> (current-tidevice)
#S(TIDEVICE
:NAME "New Device"
:STREAM-OUTPUT #<SB-SYS:FD-STREAM for "Device Output" {120C838393}>
:STREAM-INPUT #<SB-SYS:FD-STREAM for "Device Input" {120C838543}>
:OFD 8
:IFD 9
:ROWS 31
:COLS 193
:BAUD-RATE-INPUT 9600
:BAUD-RATE-OUTPUT 9600
:UPC 1042
:OBUFSIZE 1066
:TERMIOS-OLD #<SB-POSIX:TERMIOS {12127FEC53}>
:TERMIOS-NEW #<SB-POSIX:TERMIOS {12127FEC63}>
:CLOSED NIL)
TINFO> (termios-old (current-tidevice))
; Evaluation aborted on #<UNDEFINED-FUNCTION TERMIOS-OLD {12013D86D3}>.
TINFO> (tidevice-termios-old (current-tidevice))
#<SB-POSIX:TERMIOS {1200DA7D23}>
TINFO> (posix:iflag (tidevice-termios-old (current-tidevice)))
; Evaluation aborted on #<SB-INT:SIMPLE-READER-PACKAGE-ERROR "Package ~A does not exist." {1201A2F533}>.
TINFO> (sb-posix:iflag (tidevice-termios-old (current-tidevice)))
; Evaluation aborted on #<SB-INT:SIMPLE-READER-PACKAGE-ERROR "The symbol ~S is not external in the ~A package." {1205E29353}>.
TINFO> (import :sb-posix)
T
TINFO> (sb-posix:iflag (tidevice-termios-old (current-tidevice)))
; Evaluation aborted on #<SB-INT:SIMPLE-READER-PACKAGE-ERROR "The symbol ~S is not external in the ~A package." {1205FD6933}>.
TINFO> (sb-posix::iflag (tidevice-termios-old (current-tidevice)))
; Evaluation aborted on #<UNDEFINED-FUNCTION IFLAG {1207681D03}>.
TINFO>
Should I just move terminfo to a shared library?
The following is the code I have that does work.
(defun tidevice-open (tty)
(let ((curdev (current-tidevice)))
;; This should raise a condition
(if (null tty) (setq tty "/dev/pts/1"))
(setq tty (namestring tty))
(let* ((ofd (sb-posix:open tty sb-posix::o-wronly (logior
sb-posix::o-noctty
sb-posix::o-nonblock
Sb-POSIX::O-DIRECT SB-POSIX::O-NDELAY
)))
(ifd (sb-posix:open tty sb-posix::o-rdonly (logior sb-posix::o-noctty sb-posix::o-nonblock)
))
;; this needs to be fixed for input
(output (sb-sys:make-fd-stream ofd
:name "Device Output" :auto-close t
:output t :input nil :buffering :none
:element-type 'character :external-format :ascii))
(input (sb-sys:make-fd-stream ifd
:name "Device Input" :auto-close t
:buffering :none :output nil :input t
:element-type '(unsigned-byte 8)
:timeout 1.25
)))
(setf (tidevice-stream-input curdev) input)
(setf (tidevice-stream-output curdev) output)
(setf (tidevice-ofd curdev) ofd)
(setf (tidevice-ifd curdev) ifd)
(setf (tidevice-closed curdev) nil)
;; FIXME: check the input
(sb-posix:tcgetattr ifd (tidevice-termios-old curdev))
(sb-posix:tcgetattr ifd (tidevice-termios-new curdev))
;; device shardware
(let ((rows (get-window-size-rows ofd))
(cols (get-window-size-columns ofd))
(baud-input (get-input-baud-rate (tidevice-termios-new curdev)))
(baud-output (get-output-baud-rate (tidevice-termios-new curdev))))
;; device size
(setf (tidevice-rows curdev) rows)
(setf (tidevice-cols curdev) cols)
;; set baud
(setf (tidevice-baud-rate-output curdev) baud-output
(tidevice-baud-rate-input curdev) baud-input)
;; set upc mmUPC and buffer size
(setf (tidevice-upc curdev) (baud-get-upc baud-input baud-DIVIDEND))
(setf (tidevice-obufsize curdev) (baud-get-bufsize baud-TIMES (tidevice-upc curdev)))
))))
;;;; This code does not work anymore. I might be using a older version. I
really want to clean this up but I still think doing it in C is the best
option - I'd rather just use sbcl.
(deftype termios-mode-p ()
`(member :CBREAK :CBREAK-ON :CANONICAL :QIFLUSH-OFF :QIFLUSH-ON :ECHO-ON :ECHO-OFF :CR-TO-NL :NL-TO-CR
:ASCII :META-ON :ESC-ON :PACKET :RESET :CLOSE :ESC)
)
(defun tty-device-termios-set (&optional (mode :packet))
"Set terminal attributes for fildes in <*current-screen> based on mode. :CLOSE Close termios.
:RESET Reset current termios with open time termios.
:CBREAK Noncanonical Mode (Example libc). :CBREAk-OFF Cannon mode normal.
:RAW Enables raw mode.
:QIFLUSH-OFF Enabling flushing of buffers on INTR QUIT or SUSP (QIFLUSH Mode) disabled
:QIFLUSH :QIFLUSH-ON Disable flushing of buffers on INTR QUIT or SUSP (QIFLUSH Mode) enabled
:CRNL :CR-to-N Enabling Carriage Return to New line Mode. :NLCR :NL-to-CR Disabling Carriage Return to New line Mode. :SIGNAL-ON Enabled editing interupts
:SIGNAL-OFF Disable editinhg interrupts
:META-ON :ESC-ON Meta Mode enabled
:ESC-OFF :META-OFF Meta Mode disabled.
:ASCII ASCII Mode enabled.
:PACKET my favorite mix.
:ECHO-ON Enable echo.
:ECHO-OFF Disable echo (for reading passwords, etc).
When using GNU/Linux they keyboard is also set via ioctl to the accoodating mode."
(let* ((curscr (current-screen))
(termios (screen-termios-new curscr)))
(sb-posix::tcsetattr (screen-ofd curscr) SB-POSIX::TCSANOW termios)
(sb-posix::tcsetattr (screen-ifd curscr) SB-POSIX::TCSANOW termios)
;; curs_inopts (3x)
(ccase mode
(:close
(terminfo::debugging-motion-macros "Closing IO")
(finish-output (screen-output curscr))
(clear-input (screen-input curscr))
(sb-posix::tcsetattr (screen-ofd curscr) SB-POSIX::TCSANOW termios)
(sb-posix::tcsetattr (screen-ifd curscr) SB-POSIX::TCSANOW termios)
(sb-posix:close (screen-ifd curscr))
(sb-posix:close (screen-ofd curscr))
;; (attr-reset (screen-attr-flag curscr))
;; (stat-reset (screen-stat-flag curscr))
(return-from tty-device-termios-set mode))
(:reset
(terminfo::debugging-motion-macros "Restting IO to UNICODE")
(let ((oldtermios (screen-termios-old curscr)))
(setf (sb-posix:termios-iflag termios)
(sb-posix:termios-iflag oldtermios))
(setf (sb-posix:termios-oflag termios) (sb-posix:termios-oflag oldtermios))
(setf (sb-posix:termios-cflag termios) (sb-posix:termios-cflag oldtermios))
(setf (sb-posix:termios-Lflag termios) (sb-posix:termios-Lflag oldtermios))
(setf (aref (sb-posix:termios-cc termios) sb-posix:vmin)
(aref (sb-posix:termios-cc oldtermios) sb-posix:vmin))
(setf (aref (sb-posix:termios-cc termios) sb-posix:vtime)
(aref (sb-posix:termios-cc oldtermios) sb-posix:vtime))
(sb-posix:tcflush (screen-ofd curscr) sb-posix:tcsanow )
(sb-posix:tcflush (screen-ifd curscr) sb-posix:tcsanow )
(terminfo::set-keyboard-mode (screen-ifd curscr) terminfo::K_UNICODE))
;; (attr-reset (screen-attr-flag curscr))
;; (stat-reset (screen-stat-flag curscr)))
)
((:CBREAK :NONCANONICAL)
(terminfo::debugging-motion-macros "CBREAK Mode enabled")
(terminfo::set-keyboard-mode (screen-ifd curscr) terminfo::K_MEDIUMRAW)
(terminfo::debugging-motion-macros "Set keyboard into Medium Raw")
;; set cannon mode
(setf (sb-posix:termios-Lflag termios)
(logior (sb-posix::termios-Lflag termios) sb-posix::icanon))
;; set nl/cr
(setf (sb-posix::termios-iflag termios)
(logior (sb-posix::termios-iflag termios) sb-posix::icrnl))
;; turn off input is UTF8 mode when available
(when (boundp 'terminfo::IUTF8)
(setf (sb-posix::termios-iflag termios)
(logior (sb-posix:termios-iflag termios) terminfo::IUTF8)))
(setf (aref (sb-posix:termios-cc termios) sb-posix:vmin) 1)
(setf (aref (sb-posix:termios-cc termios) sb-posix:vtime) 1)
)
((:CBREAK-OFF :CANNON-OFF)
(terminfo::debugging-motion-macros "CBREAK Mode disabled")
(terminfo::set-keyboard-mode (screen-ifd curscr) terminfo::K_UNICODE)
;; set non-cannon mode, no echo, no flush on signal
;; set cannon mode, no echo, no flush on signal
(setf (sb-posix:termios-Lflag termios)
(logand (sb-posix:termios-Lflag termios) (lognot sb-posix:icanon)))
;; set read time/bytes
(setf (aref (sb-posix:termios-cc termios) sb-posix:vmin) 4)
(setf (aref (sb-posix:termios-cc termios) sb-posix:vtime) 1)
;; set ignore nl/cr
(setf (sb-posix::termios-iflag termios)
(logior (sb-posix:termios-iflag termios) sb-posix:icrnl))
;; turn on input to UTF8 mode when available
(when (boundp 'terminfo::IUTF8)
(setf (sb-posix::termios-iflag termios)
(logior (sb-posix:termios-iflag termios) terminfo::IUTF8)))
)
(:RAW
;; use with caution
(terminfo::debugging-motion-macros "RAW Mode enabled")
(terminfo::set-keyboard-mode (screen-ifd curscr) terminfo::K_RAW)
(setf (sb-posix:termios-Lflag termios)
(logior (sb-posix:termios-Lflag termios) (logior sb-posix:ISIG sb-posix:ICANON)))
(setf (sb-posix::termios-iflag termios)
(logior (sb-posix:termios-iflag termios)
(logior sb-posix:ISIG sb-posix:ICANON sb-posix:IEXTEN))))
((:QIFLUSH :QIFLUSH-ON)
(terminfo::debugging-motion-macros "Disable flushing of buffers on INTR QUIT or SUSP (QIFLUSH Mode) enabled")
(setf (sb-posix:termios-Lflag termios)
(logand (sb-posix:termios-Lflag termios) (lognot sb-posix:noflsh))))
(:QIFLUSH-OFF
(terminfo::debugging-motion-macros
"Enabling flushing of buffers on INTR QUIT or SUSP (QIFLUSH Mode disabled)")
(setf (sb-posix:termios-Lflag termios)
(logior (sb-posix:termios-Lflag termios) sb-posix:noflsh)))
((:CRNL :CR-TO-NL)
(terminfo::debugging-motion-macros "Enabling Carriage Return to New line Mode.")
;; ignore carriage returns
(when (logand (sb-posix:termios-iflag termios) sb-posix:INLCR)
(setf (sb-posix::termios-iflag termios)
(logior (sb-posix:termios-iflag termios) sb-posix:INLCR)))
(setf (sb-posix:termios-iflag termios)
(logand (sb-posix::termios-iflag termios) (lognot sb-posix:IGNCR)))
(setf (sb-posix:termios-oflag termios)
(logand (sb-posix:termios-oflag termios) (lognot sb-posix:OCRNL))))
((:NLCR :NL-to-CR)
(terminfo::debugging-motion-macros "Disabling Carriage Return to New line Mode.")
;; if ignore CR is set, unset it
(when (logand (sb-posix::termios-iflag termios) sb-posix:INLCR)
;; turn off ignore cr when set
(setf (sb-posix:termios-iflag termios)
(logior (sb-posix:termios-iflag termios) sb-posix:IGNCR)))
(setf (sb-posix::termios-iflag termios)
(logand (sb-posix:termios-iflag termios) (lognot sb-posix:IGNCR)))
(setf (sb-posix:termios-oflag termios)
(logand (sb-posix:termios-oflag termios) (lognot sb-posix:IGNCR))))
((:META-ON :ESC-ON)
(terminfo::debugging-motion-macros "Meta Mode enabled.")
(setf (sb-posix:termios-cflag termios)
(logand (sb-posix:termios-cflag termios) (lognot sb-POSIX:CS8))))
((:ESC-OFF :META-OFF)
(terminfo::debugging-motion-macros "Meta Mode disabled.")
(setf (sb-posix:termios-cflag termios)
(logior (sb-posix:termios-cflag termios) sb-posix:CS8)))
(:ASCII
(terminfo::debugging-motion-macros "ASCII Mode enabled")
(setf (sb-posix:termios-Lflag termios)
(logand (sb-posix:termios-Lflag termios) (lognot sb-posix::icanon )))
(setf (sb-posix:termios-Lflag termios)
(logior (sb-posix::termios-Lflag termios)
(logior sb-posix:echo terminfo::ECHOCTL)))
(setf (aref (sb-posix:termios-cc termios) sb-posix:vmin) 1)
(setf (aref (sb-posix:termios-cc termios) sb-posix:vtime) 0)
(terminfo::set-keyboard-mode (screen-ifd curscr) terminfo::K_XLATE))
(:SIGNAL-OFF
(setf (sb-posix:termios-lflag termios)
(logand (sb-posix:termios-Lflag termios)
(lognot (logior sb-posix:isig))))
(terminfo::debugging-motion-macros "Editing signals disabled"))
(:SIGNAL-ON
(setf (sb-posix:termios-lflag termios)
(logior (sb-posix:termios-Lflag termios) sb-posix:isig))
(terminfo::debugging-motion-macros "Editing signals enabled"))
(:PACKET
#|
Best for packet mode/no signals
Old Flags New Flags
------------------------
i_flags; 25862 => 25606
O_flags; 5 => 5
C_flags; 1215 => 1215
L_flags; 35387 => 35377
|#
;; ioctl KDSKBMODE: set to unicode/medium-raw input
(terminfo::debugging-motion-macros "Packet Mode enabled")
(setf (sb-posix:termios-lflag termios)
(logand (sb-posix:termios-Lflag termios)
(lognot (logior
;; sb-posix:isig
sb-posix:icanon sb-posix:echo terminfo::echoctl))))
;; size of byte 8
(setf (sb-posix:termios-cflag termios)
(logand (sb-posix:termios-cflag termios) sb-posix:CS8))
(setf (aref (sb-posix:termios-cc termios) sb-posix:vmin) 1)
(setf (aref (sb-posix:termios-cc termios) sb-posix:vtime) 1)
(sb-posix:tcflush (screen-ifd curscr) sb-posix:tcsanow )
(sb-posix:tcflush (screen-ofd curscr) sb-posix:tcsanow )
(terminfo::set-keyboard-mode (screen-ifd curscr) terminfo::K_MEDIUMRAW)
)
(:ECHO-ON
(setf (sb-posix:termios-Lflag termios)
(logior (sb-posix:termios-Lflag termios) sb-posix:echo))
(terminfo::debugging-motion-macros "Echo Mode enabled"))
(:ECHO-OFF
(terminfo::debugging-motion-macros "Echo Mode disabled")
(setf (sb-posix:termios-Lflag termios)
(logand (sb-posix:termios-Lflag termios) (lognot sb-posix:echo))))
)
;; flush the streams before filedescriptors
(clear-input (screen-input curscr))
(force-output (screen-output curscr))
(sb-posix::tcsetattr (screen-ofd curscr) sb-posix:tcsaflush termios)
(sb-posix::tcsetattr (screen-ifd curscr) sb-posix:tcsaflush termios)))
(defvar *termios-print-string*
(mapconcat #'identity '(
"Old Flags New Flags"
"------------------------"
"i_flags; ~d => ~d"
"O_flags; ~d => ~d"
"C_flags; ~d => ~d"
"L_flags; ~d => ~d")
(string #\Newline)
))
(defun tty-device-termios-display (&optional (stream t))
"Print the current bits in a terminfo structure."
(let ((oldtermios (screen-termios-old (current-screen)))
(newtermios (screen-termios-new (current-screen))))
(format stream *termios-print-string*
(sb-posix:termios-iflag oldtermios) (sb-posix:termios-iflag newtermios)
(sb-posix:termios-oflag oldtermios) (sb-posix:termios-oflag newtermios)
(sb-posix:termios-cflag oldtermios) (sb-posix:termios-cflag newtermios)
(sb-posix:termios-lflag oldtermios) (sb-posix:termios-lflag newtermios))))
TINFO> (tty-device-termios-display t)
The slot SB-POSIX::IFLAG is unbound in the object
#<TERMIOS {1200FBDA63}>.
[Condition of type UNBOUND-SLOT]
;;; Inspection results.
TINFO> (current-tidevice)
#S(TIDEVICE
:NAME "New Device"
:STREAM-OUTPUT #<SB-SYS:FD-STREAM for "Device Output" {120C838393}>
:STREAM-INPUT #<SB-SYS:FD-STREAM for "Device Input" {120C838543}>
:OFD 8
:IFD 9
:ROWS 31
:COLS 193
:BAUD-RATE-INPUT 9600
:BAUD-RATE-OUTPUT 9600
:UPC 1042
:OBUFSIZE 1066
:TERMIOS-OLD #<SB-POSIX:TERMIOS {12127FEC53}>
:TERMIOS-NEW #<SB-POSIX:TERMIOS {12127FEC63}>
:CLOSED NIL)
TINFO> (termios-old (current-tidevice))
; Evaluation aborted on #<UNDEFINED-FUNCTION TERMIOS-OLD {12013D86D3}>.
TINFO> (tidevice-termios-old (current-tidevice))
#<SB-POSIX:TERMIOS {1200DA7D23}>
TINFO> (posix:iflag (tidevice-termios-old (current-tidevice)))
; Evaluation aborted on #<SB-INT:SIMPLE-READER-PACKAGE-ERROR "Package ~A does not exist." {1201A2F533}>.
TINFO> (sb-posix:iflag (tidevice-termios-old (current-tidevice)))
; Evaluation aborted on #<SB-INT:SIMPLE-READER-PACKAGE-ERROR "The symbol ~S is not external in the ~A package." {1205E29353}>.
TINFO> (import :sb-posix)
T
TINFO> (sb-posix:iflag (tidevice-termios-old (current-tidevice)))
; Evaluation aborted on #<SB-INT:SIMPLE-READER-PACKAGE-ERROR "The symbol ~S is not external in the ~A package." {1205FD6933}>.
TINFO> (sb-posix::iflag (tidevice-termios-old (current-tidevice)))
; Evaluation aborted on #<UNDEFINED-FUNCTION IFLAG {1207681D03}>.
TINFO>
; No value
TINFO>
; No value
TINFO>
; No value
TINFO> (tty-device-termios-display t)
; Evaluation aborted on #<UNBOUND-SLOT IFLAG {12032FB663}>.
TINFO>
; No value
TINFO> (inspect (current-tidevice))
The object is a STRUCTURE-OBJECT of type TIDEVICE.
0. NAME: New Device
1. STREAM-OUTPUT: #<FD-STREAM for "Device Output" {1200DA7AA3}>
2. STREAM-INPUT: #<FD-STREAM for "Device Input" {1200DA7BE3}>
3. OFD: 8
4. IFD: 9
5. ROWS: 31
6. COLS: 193
7. BAUD-RATE-INPUT: 9600
8. BAUD-RATE-OUTPUT: 9600
9. UPC: 1042
10. OBUFSIZE: 1066
11. TERMIOS-OLD: #<TERMIOS {1200DA7D23}>
12. TERMIOS-NEW: #<TERMIOS {1200DA7D33}>
13. CLOSED: NIL
11
The object is a STANDARD-OBJECT of type SB-POSIX:TERMIOS.
0. IFLAG: 17408
1. OFLAG: 5
2. CFLAG: 983231
3. LFLAG: 35377
4. CC: #(3 28 127 21 4 0 1 0 17 19 26 0 18 0 23 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
5. REMAINING-FIELDS: #(0 0 0 0 0 150 0 0 0 150 0 0)
q
any help would be useful. sorry for the postscript my email does not like me today.
--- Synchronet 3.22a-Linux NewsLink 1.2