Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.lisp > #61317

:sbcl-posix and termios

From steve g <Sgonedes1977@gmail.com>
Newsgroups comp.lang.lisp
Subject :sbcl-posix and termios
Date 2026-08-06 20:12 -0400
Message-ID <87ecga94bw.fsf@gmail.com> (permalink)

Show all headers | View raw


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.

Back to comp.lang.lisp | Previous | NextNext in thread | Find similar | Unroll thread


Thread

:sbcl-posix and termios steve g <Sgonedes1977@gmail.com> - 2026-08-06 20:12 -0400
  Re: :sbcl-posix and termios Johann 'Myrkraverk' Oskarsson <johann@myrkraverk.invalid> - 2026-08-07 19:05 +0800
    Re: :sbcl-posix and termios steve g <Sgonedes1977@gmail.com> - 2026-08-07 11:02 -0400
      Re: :sbcl-posix and termios Johann 'Myrkraverk' Oskarsson <johann@myrkraverk.invalid> - 2026-08-08 01:32 +0800
        Re: :sbcl-posix and termios steve g <Sgonedes1977@gmail.com> - 2026-08-08 01:32 -0400
      Re: :sbcl-posix and termios Johann 'Myrkraverk' Oskarsson <johann@myrkraverk.invalid> - 2026-08-08 21:36 +0800
        Re: :sbcl-posix and termios steve g <Sgonedes1977@gmail.com> - 2026-08-09 17:53 -0400

csiph-web