;;; -*- Mode:LISP; Package:USER; Base:10; Readtable:CL -*- (defvar *supdup-server-default-rubout-handler* nil) ;:CLEAR-BETWEEN-CURSORPOSES ;:INSERT-STRING (optional) ;:DELETE-STRING (optional) (defconst %tdmov #o200 "move: oldv oldh newv newh") (defconst %tdmv1 #o201 "move: newv newh") (defconst %tdeof #o202 "clear to end of screen") (defconst %tdeol #o203 "clear rest of line") (defconst %tddlf #o204 "clear current char") (defconst %tdcrl #o205 "fresh line") (defconst %tdnop #o210) (defconst %tdors #o214 "output reset") (defconst %tdqot #o215 "quote one char") (defconst %tdfs #o216 "nondestructive forward space") (defconst %tdmv0 #o217 "move: newv newh") (defconst %tdclr #o220 "erase screen and home") (defconst %tdbel #o221 "bell") (defconst %tdilp #o223 "insert n lines") (defconst %tddlp #o224 "delete n lines") (defconst %tdicp #o225 "insert n chars") (defconst %tddcp #o226 "delete n chars") (defconst %tdbow #o227 "black chars on white screen") (defconst %tdrst #o230 "reset bow and others") (defconst %%tocid (byte 1 0)) ;character insert/delete (defconst %%tolid (byte 1 1)) ;line insert/delete (defconst %%tofci (byte 1 3)) ;generates real control-meta (defconst %%tolwr (byte 1 4)) ;can send lowercase (defconst %%torol (byte 1 6)) ;scroll if possible (defconst %%tomor (byte 1 7)) ;do more processing (defconst %%tomvu (byte 1 8)) ;can move cursor up (defconst %%toovr (byte 1 9)) ;overstrikes (defconst %%tosa1 (byte 1 10.)) ;display sail characters (defconst %%tosai (byte 1 11.)) ;sail characters (defconst %%tomvb (byte 1 12.)) ;can backspace (defconst %%toers (byte 1 14.)) ;can erase (defconst %%toclc (byte 1 15.)) ;convert lower to upper case (defconst %%toalt (byte 1 16.)) ;convert #o175 and #o176 to #o33 (defconst %%tpcbs (byte 1 23.)) ;intelligent terminal protocol "must be on" (defconst %%tpors (byte 1 21.)) ;do output resets (defflavor t-stream (io-buffer input-process conn net-stream (tv:rubout-handler-buffer (tv:make-rubout-handler-buffer)) (tv:old-typeahead nil) (cursor-x 0) (cursor-y 0) location tctyp ttyopt height width ttyrol ttysmt bucky-state bucky-bits (output-pending nil) (lock nil) ) () :settable-instance-variables (:default-handler t-stream-default-message-handler) ) (defflavor t-stream-insert-mixin () ()) (defun t-stream-default-message-handler (operation &rest args) args (process-wait (format nil "oops ~s" operation) #'false)) (defun make-t-stream (conn net-stream input-process io-buffer) (make-instance 't-stream :io-buffer io-buffer :input-process input-process :net-stream net-stream :conn conn)) (defmethod (t-stream :send-move) () (with-lock (lock) (send net-stream :tyo %tdmv0) (send net-stream :tyo cursor-y) (send net-stream :tyo cursor-x) (setq output-pending t))) (defconst *lozenged-table* '((#\resume . "") (#\break . "") (#\abort . "") )) (defun fake-lozenged (c) (let ((entry (assq (int-char c) *lozenged-table*))) (cond ((null entry) (format nil "<~o>" (char-code c))) (t (cdr entry))))) (defmethod (t-stream :tyo) (char &optional font) font (with-lock (lock) (let ((c (char-code char)) (sail-p (ldb-test %%tosai ttyopt))) (cond ((and (not sail-p) (< c #o40)) (send self :string-out (aref chaos:*telnet-output-translation-table* c))) ((and (not sail-p) (= c #o177)) (send self :tyo #\^) (send self :tyo #\?)) ((< c #o200) (send net-stream :tyo c) (incf cursor-x) (when (>= cursor-x width) (setq cursor-x 0) (incf cursor-y) (when (>= cursor-y height) (setq cursor-y 0)) (send self :send-move) (send net-stream :tyo %tdeol)) (setq output-pending t)) ((= c #\return) (setq cursor-x 0) (incf cursor-y) (when (>= cursor-y height) (setq cursor-y 0)) (send self :send-move) (send net-stream :tyo %tdeol) (setq output-pending t)) ((= c #\form) (send self :clear-screen)) (t (send self :string-out (fake-lozenged c)))))) char) (defvar *sail-bitmap* (let ((x (make-array 256. :type :art-1b :initial-element 1))) ;;this makes first 128. easy, rest hard (dotimes (i 128.) (aset 0 x i)) x)) (defvar *ascii-bitmap* (let ((x (make-array 256. :type :art-1b))) (dotimes (i 256.) (cond ((< i #o40) (aset 1 x i)) ((< i 127.) (aset 0 x i)) (t (aset 1 x i)))) x)) (defun string-search-bitmap-slow (bitmap string start end) (when (null end) (setq end (string-length string))) (do ((i start (1+ i))) ((= i end)) (if (not (zerop (aref bitmap (aref string i)))) (return i)))) (defconst *string-search-bitmap-function* 'string-search-bitmap-slow) ;this will turn on the microcode assist - it doesn't seem to really be needed though ;(when (and (find-package "MICRO") ; (not (eq (find-package "MICRO") (find-package "UA")))) ; (let ((func (intern "STRING-SEARCH-BITMAP" "MICRO"))) ; (when (fboundp func) ; (setq *string-search-bitmap-function* (symbol-function func))))) (defmethod (t-stream :string-out) (string &optional (init-start 0) end) (when (null end) (setq end (string-length string))) (with-lock (lock) (do ((start init-start) ) ((>= start end)) (let ((next-hard (min (or (funcall *string-search-bitmap-function* (if (ldb-test %%tosai ttyopt) *sail-bitmap* *ascii-bitmap*) string start nil) end) (+ start (- width cursor-x)) ))) (cond ((> next-hard start) (send net-stream :string-out string start next-hard) (incf cursor-x (- next-hard start)) (setq start next-hard)) (t (send self :tyo (aref string start)) (incf start))))) (setq output-pending t))) (defmethod (t-stream :line-out) (string &optional (start 0) end) (send self :string-out string start end) (send self :tyo #\return) ) (defmethod (t-stream :any-tyi) () (send self :tyi)) (defmethod (t-stream :tyi) (&optional eof-error-p &aux index) eof-error-p (cond ((> (tv:rhb-fill-pointer) (setq index (tv:rhb-scan-pointer))) (setf (tv:rhb-scan-pointer) (1+ index)) (aref tv:rubout-handler-buffer index)) ((not (eq rubout-handler self)) (let ((char (tv:io-buffer-get io-buffer))) (cond ((and (eq tv:rubout-handler-inside self) (eq tv:old-typeahead t) (consp char) (not (eq (car char) 'tv:redisplay-rubout-handler))) (multiple-value-bind (string index) (send self :save-rubout-handler-buffer) (setq tv:old-typeahead (list string index)) (send self :untyi char) (char-int #\clear-input))) (t (char-int char))))) (t (send self :rubout-handler-tyi)))) (defmethod (t-stream :untyi) (ch) (cond ((and (eq rubout-handler self) (<= (tv:rhb-scan-pointer) (tv:rhb-fill-pointer)) (eq ch (aref tv:rubout-handler-buffer (1- (tv:rhb-scan-pointer))))) (decf (tv:rhb-scan-pointer))) (t (tv:io-buffer-unget io-buffer ch))) ch) (defmethod (t-stream :clear-input) () (setf (tv:rhb-fill-pointer) 0) (setf (tv:rhb-scan-pointer) 0) (tv:io-buffer-clear io-buffer)) (defmethod (t-stream :backward-char) (&optional char) char (when (> cursor-x 0) (setq cursor-x (1- cursor-x))) (send self :send-move)) (defvar *t-stream-prompt-starting-x*) (defvar *t-stream-prompt-starting-y*) (defvar *t-stream-activation-character*) (defmethod (t-stream :rubout-handler-tyi) () (block top (setf (tv:rhb-typein-pointer) nil) ;mark that simple rubout handler is in use (when (= (tv:rhb-scan-pointer) most-positive-fixnum) (setf (tv:rhb-scan-pointer) 0) (throw 'tv:rubout-handler t)) (let ((status (tv:rhb-status)) (rubbed-out-some nil) (rubout-handler nil)) (setf (tv:rhb-status) nil) (when (memq status '(:initial-entry :restored)) (let ((prompt-option (assq :prompt rubout-handler-options))) (when prompt-option (tv::rubout-handler-prompt (cadr prompt-option) self nil))) (multiple-value (tv:rubout-handler-starting-x tv:rubout-handler-starting-y) (send self :read-cursorpos)) (when (plusp (tv:rhb-fill-pointer)) (send self :string-out tv:rubout-handler-buffer)) (let ((initial-input (cadr (assq :initial-input rubout-handler-options)))) (when initial-input (string-nconc tv:rubout-handler-buffer initial-input)))) (or (prog1 tv:rubout-handler-activation-character (setq tv:rubout-handler-activation-character nil)) (do ((editing-command (cdr (assq :editing-command rubout-handler-options))) (do-not-echo (cdr (assq :do-not-echo rubout-handler-options))) (pass-through (cdr (assq :pass-through rubout-handler-options))) (command-handler (assq :command rubout-handler-options)) (preemptable (assq :preemptable rubout-handler-options)) (activation-handler (assq :activation rubout-handler-options)) ch len) (nil) (setq ch (send self :any-tyi)) (cond ((eq (car-safe ch) 'tv:redisplay-rubout-handler) (send self :set-cursorpos tv:prompt-starting-x tv:prompt-starting-y) (send self :clear-rest-of-line) (and (setq len (or (assq :reprompt rubout-handler-options) (assq :prompt rubout-handler-options))) (tv:rubout-handler-prompt (cadr len) self ch)) (multiple-value (tv:rubout-handler-starting-x tv:rubout-handler-starting-y) (send self :read-cursorpos)) (send self :string-out tv:rubout-handler-buffer)) ((consp ch) (when preemptable (setf (tv:rhb-scan-pointer) 0) (throw 'tv:return-from-rubout-handler (values ch (cadr preemptable))))) ((and command-handler (apply (cadr command-handler) ch (cddr command-handler))) (setf (tv:rhb-scan-pointer) 0) (throw 'tv::return-from-rubout-handler (values `(:command ,ch 1) :command))) ;; Don't touch this character, just return it to caller. ((or (memq ch editing-command) (si:assq-careful ch editing-command)) ;; Cause rubout handler rescan next time the user does :TYI. (if rubbed-out-some (setf (tv:rhb-scan-pointer) most-positive-fixnum)) (return ch)) ((and (not (or (memq ch do-not-echo) (memq ch pass-through) (and activation-handler (apply (cadr activation-handler) ch (cddr activation-handler))))) (or (not (zerop (char-bits ch))) (member ch '(#\Rubout #\Clear-input #\Clear-screen #\Delete) :test #'char-equal))) (cond ((member ch '(#\Form #\Delete #\c-L) :test #'char-equal) ;Retype buffered input (if (not (char-equal ch #\Delete)) (send self :clear-window) (send self :tyo #\Return)) (multiple-value (tv:prompt-starting-x tv:prompt-starting-y) (send self :read-cursorpos)) (let ((prompt (cadr (or (assq :reprompt rubout-handler-options) (assq :prompt rubout-handler-options))))) (when prompt (tv::rubout-handler-prompt prompt self ch))) (multiple-value (tv:rubout-handler-starting-x tv:rubout-handler-starting-y) (send self :read-cursorpos)) (send self :string-out tv:rubout-handler-buffer)) ((member ch '(#\rubout #\clear-input #\c-U) :test #'char-equal) (cond ((not (zerop (setq len (tv:rhb-fill-pointer)))) (setf (tv:rhb-fill-pointer) (setq len (case (int-char ch) (#\rubout (1- len)) ((#\clear-input #\c-U) 0)))) (setf rubbed-out-some t (tv:rhb-status) :rubout) (multiple-value-bind (x y) (send self :compute-motion tv:rubout-handler-buffer 0 len tv:rubout-handler-starting-x tv:rubout-handler-starting-y) (if tv:rubout-handler-re-echo-flag (setq x tv:rubout-handler-starting-x y tv:rubout-handler-starting-y)) (multiple-value-bind (cx cy) (send self :read-cursorpos) (send self :clear-between-cursorposes x y cx cy)) (send self :set-cursorpos x y) (and tv:rubout-handler-re-echo-flag (send self :string-out tv:rubout-handler-buffer)))))) (t (send self :tyo #\!) (send self :beep))) (cond ((and (zerop (tv:rhb-fill-pointer)) (assq :full-rubout rubout-handler-options)) (setf (tv:rhb-scan-pointer) 0) (throw 'rubout-handler t)))) (t ;; It's a self-inserting character. ;; If this is first character typed in, re-get starting cursorpos since while ;; waiting for input a notification may have been typed out. (when (zerop (tv:rhb-fill-pointer)) (multiple-value (tv:rubout-handler-starting-x tv:rubout-handler-starting-y) (send self :read-cursorpos))) (cond ((memq ch do-not-echo) (setq tv:rubout-handler-activation-character ch)) ((and activation-handler (apply (cadr activation-handler) ch (cddr activation-handler))) (setq ch `(:activation ,ch 1)) (setq tv:rubout-handler-activation-character ch)) ((not (zerop (char-bits ch))) (send self :tyo #\=) (send self :beep)) (t (send self :tyo ch) (array-push-extend tv:rubout-handler-buffer ch))) (cond (rubbed-out-some (setf (tv:rhb-scan-pointer) 0) (throw 'rubout-handler t)) (t (setf (tv:rhb-scan-pointer) (tv:rhb-fill-pointer)) (setq tv:rubout-handler-activation-character nil) (return ch)))))))))) (defmethod (t-stream :rubout-handler) (options function &rest args) (declare (arglist rubout-handler-options function &rest args)) (if (and (eq rubout-handler self) (not (cdr (assq :nonrecursive options)))) (let ((rubout-handler-options (append options rubout-handler-options))) (apply function args)) (let ((rubout-handler-options options)) (if (<= (tv:rhb-fill-pointer) (tv:rhb-scan-pointer)) (setf (tv:rhb-fill-pointer) 0) (copy-array-portion tv:rubout-handler-buffer (tv:rhb-scan-pointer) (tv:rhb-fill-pointer) tv:rubout-handler-buffer 0 (array-length tv:rubout-handler-buffer)) (if (numberp (tv:rhb-typein-pointer)) (decf (tv:rhb-typein-pointer) (tv:rhb-scan-pointer))) (decf (tv:rhb-fill-pointer) (tv:rhb-scan-pointer))) (setf (tv:rhb-scan-pointer) 0 (tv:rhb-status) :initial-entry) (catch 'tv::return-from-rubout-handler (let (tv:prompt-starting-x tv:prompt-starting-y tv:rubout-handler-starting-x tv:rubout-handler-starting-y (tv:rubout-handler self) (tv:rubout-handler-inside self) (tv:rubout-handler-re-echo-flag nil) (tv:rubout-handler-activation-character nil)) (multiple-value (tv:prompt-starting-x tv:prompt-starting-y) (send self :read-cursorpos)) (setq tv:rubout-handler-starting-x tv:prompt-starting-x tv:rubout-handler-starting-y tv:prompt-starting-y) (do-forever (setq tv:rubout-handler-re-echo-flag nil) (catch 'tv:rubout-handler ;Throw here when rubbing out (condition-case (error) (return (multiple-value-prog1 (apply function args) ;Call read type function (setf (tv:rhb-fill-pointer) (tv:rhb-scan-pointer)) (and (tv:rhb-typein-pointer) (> (tv:rhb-typein-pointer) (tv:rhb-fill-pointer)) (setf (tv:rhb-typein-pointer) (tv:rhb-fill-pointer))))) (si:parse-error (send self :fresh-line) (princ ">>ERROR: " self) (send error :report self) (send self :fresh-line) (setq tv:rubout-handler-re-echo-flag t) (do-forever (send self :tyi))))) ;If error, force user to rub out ;;Maybe return when user rubs all the way back (and (zerop (tv:rhb-fill-pointer)) (let ((full-rubout-option (assq :full-rubout rubout-handler-options))) (when full-rubout-option ;; Get rid of the prompt, if any. (multiple-value-bind (x y) (send self :cursorpos) (send self :clear-between-cursorposes tv:prompt-starting-x tv:prompt-starting-y x y)) (return (values nil (cadr full-rubout-option)))))))))))) (defmethod (t-stream :read-cursorpos) (&optional (units :pixel)) (cond ((eq units :pixel) (values (* cursor-x 8) (* cursor-y 14.))) (t (values cursor-x cursor-y)))) (defmethod (t-stream :set-cursorpos) (x y &optional (units :pixel)) (when (eq units :pixel) (setq x (floor x 8)) (setq y (floor y 14.))) (when (>= x width) (setq x 0)) (when (>= y height) (setq y 0)) (setq cursor-x x) (setq cursor-y y) (send self :send-move)) (defmethod (t-stream :clear-between-cursorposes) (start-x start-y end-x end-y) (with-lock (lock) (setq start-x (floor start-x 8)) (setq start-y (floor start-y 14.)) (setq end-x (floor end-x 8)) (setq end-y (floor end-y 14.)) (when (and (< start-x width) (<= end-x width) (< start-y height) (<= end-y height)) (let ((old-x cursor-x) (old-y cursor-y)) (cond ((= start-y end-y) (when (< start-x end-x) (setq cursor-x start-x) (setq cursor-y start-y) (send self :send-move) (cond ((ldb-test %%toovr ttyopt) (dotimes (i (- end-x start-x)) (send net-stream :tyo %tddlf) (send net-stream :tyo #\space))) (t (dotimes (i (- end-x start-x)) (send net-stream :tyo #\space)))))) (t (setq cursor-x start-x) (setq cursor-y start-y) (send self :send-move) (send net-stream :tyo %tdeol) (setq cursor-x 0) (incf cursor-y) (when (>= cursor-y height) (setq cursor-y 0)) (send self :send-move) (do () ((= cursor-y end-y)) (send self :send-move) (send net-stream :tyo %tdeol) (incf cursor-y) (when (>= cursor-y height) (setq cursor-y 0))) (send self :send-move) (cond ((ldb-test %%toovr ttyopt) (dotimes (i end-x) (send net-stream :tyo %tddlf) (send net-stream :tyo #\space))) (t (dotimes (i end-x) (send net-stream :tyo #\space)))))) (setq cursor-x old-x) (setq cursor-y old-y) (send self :send-move) (setq output-pending t))))) (defmethod (t-stream :compute-motion) (string &optional (start 0) (end nil) x y (cr-at-end-p nil) (stop-x 0) (stop-y nil) bottom-limit right-limit font (line-ht 14.) (tab-width (* 8 8)) &aux (char-width 8) final-index max-x) (declare (values final-x final-y final-string-index maximum-x)) font (when (null end) (setq end (string-length string))) (when (null x) (setq x (* cursor-x char-width))) (when (null y) (setq y (* cursor-y line-ht))) (when (null stop-y) (setq stop-y (* height line-ht))) (when (null bottom-limit) (setq bottom-limit (* (1- height) line-ht))) (when (null right-limit) (setq right-limit (* width char-width))) (setq max-x x) (let ((sail-p (ldb-test %%tosai ttyopt))) (catch 'done (labels ((do-string (str s e top-level) (do ((index s (1+ index))) ((>= index e)) (when top-level (setq final-index index)) (let ((c (char-code (aref str index)))) (cond ((and (not sail-p) (< c #o40)) (let ((str (aref chaos:*telnet-output-translation-table* c))) (do-string str 0 (string-length str) nil))) ((and (not sail-p) (= c #o177)) (do-string "^?" 0 2 nil)) ((< c #o200) (setq x (+ x char-width)) (when (>= x right-limit) (setq x 0) (setq y (+ y line-ht)) (when (>= y bottom-limit) (setq y 0))) (setq max-x (max x max-x)) (when (and (> x stop-x) (> y stop-y)) (throw 'done nil))) ((= c #\return) (setq x 0) (setq y (+ y line-ht)) (when (>= y bottom-limit) (setq y 0)) (when (> y stop-y) (throw 'done nil))) ((= c #\tab) (setq x (* (ceiling x tab-width) tab-width)) (when (>= x right-limit) (setq x 0) (setq y (+ y line-ht)) (when (>= y bottom-limit) (setq y 0))) (setq max-x (max x max-x)) (when (and (> x stop-x) (> y stop-y)) (throw 'done nil))) ((= c #\form) (setq x 0) (setq y 0)) (t (let ((loz (fake-lozenged c))) (do-string loz 0 (string-length loz) nil)))))))) (do-string string start end t) (when cr-at-end-p (setq final-index t) (do-string #.(format nil "~%") 0 1 nil)) (setq final-index nil)) )) (values x y final-index max-x)) (defmethod (t-stream :beep) (&optional beep-type) beep-type (with-lock (lock) (send net-stream :tyo %tdbel) (setq output-pending t))) (defmethod (t-stream :clear-screen) () (with-lock (lock) (send net-stream :tyo %tdclr) (setq cursor-x 0) (setq cursor-y 0) (setq output-pending t))) (defmethod (t-stream :clear-window) () (with-lock (lock) (send net-stream :tyo %tdclr) (setq cursor-x 0) (setq cursor-y 0) (setq output-pending t))) (defmethod (t-stream :fresh-line) () (when (not (zerop cursor-x)) (send self :tyo #\return))) (defmethod (t-stream :clear-rest-of-line) () (with-lock (lock) (send net-stream :tyo %tdeol) (setq output-pending t))) (defmethod (t-stream :quit) () (send self :clear-screen) (format self "Bye.~%") (with-lock (lock) (send net-stream :finish) (send net-stream :close))) (defun user:quit () (send-if-handles terminal-io :quit)) ;fancy rubout handler stuff ;------ (defmethod (t-stream :save-rubout-handler-buffer) () (when (eq tv:rubout-handler-inside self) ;; Give rubout handler function a chance to put its internal data ;; into RUBOUT-HANDLER-BUFFER where we look for it. (values (copy-seq tv:rubout-handler-buffer) (tv:rhb-typein-pointer)))) (defmethod (t-stream :restore-rubout-handler-buffer) (string &optional pointer) (let ((length (array-active-length string))) (or ( (array-length tv:rubout-handler-buffer) length) (adjust-array-size tv:rubout-handler-buffer length)) (copy-array-contents string tv:rubout-handler-buffer) (setf (tv:rhb-fill-pointer) length)) (setf (tv:rhb-typein-pointer) pointer) (send self :refresh-rubout-handler) (setf (tv:rhb-scan-pointer) 0) ;(setf (rhb-status) :restored) (throw 'tv:rubout-handler t)) (defmethod (t-stream :refresh-rubout-handler) (&optional discard-last-character) (if discard-last-character (setf (tv:rhb-fill-pointer) (max 0 (1- (tv:rhb-fill-pointer))))) (if (tv:rhb-typein-pointer) (setf (tv:rhb-typein-pointer) (min (tv:rhb-typein-pointer) (tv:rhb-fill-pointer)))) (send self :fresh-line) (let ((prompt (or (assq :reprompt rubout-handler-options) (assq :prompt rubout-handler-options)))) (when prompt (tv:rubout-handler-prompt (cadr prompt) self #\Delete))) (multiple-value (tv:rubout-handler-starting-x tv:rubout-handler-starting-y) (send self :read-cursorpos)) (send self :string-out tv:rubout-handler-buffer)) ;------ (defun supdup-lisp-top-level (stream) (si:lisp-top-level1 stream)) (defun supdup-server-function () (let (conn) (setq conn (chaos:listen "SUPDUP")) (let ((lose (chaos:disallow-connection? "SUPDUP" conn (list chaos:telnet-server-on :reject-unwanted)))) (when lose (chaos:reject conn lose) (return-from supdup-server-function nil)) (chaos:accept conn) (push conn chaos:eval-server-connections) (send tv:who-line-file-state-sheet :add-server conn "SUPDUP") (with-open-stream (net-stream (chaos:make-stream conn)) (send net-stream :string-out "Lisp Machine Supdup") (send net-stream :tyo #o15) (send net-stream :tyo #o12) (send net-stream :tyo %tdnop) (send net-stream :force-output) (let ((lisp-proc (make-process "Lisp for SUPDUP" :regular-pdl-size (array-length (si:sg-regular-pdl (send si:initial-process :initial-stack-group))))) (io-buffer (tv:make-io-buffer 100.))) (let* ((t-stream (make-t-stream conn net-stream current-process io-buffer)) (lock-location (si:locate-in-instance t-stream 'lock)) error-p) (read-supdup-parameters net-stream t-stream) (send t-stream :clear-screen) (print-herald t-stream) (format t-stream "~2&") (send lisp-proc :preset #'supdup-lisp-top-level t-stream) (process-reset-and-enable lisp-proc) (send t-stream :set-bucky-state nil) (do-forever (let (start-time) (process-wait "Net Input" #'(lambda () (block top (when (send t-stream :output-pending) (cond ((null start-time) (setq start-time (time))) ((> (time-difference (time) start-time) 15.) (return-from top t)))) (multiple-value-bind (input-p err-p) (ignore-errors (send net-stream :listen)) (when err-p (setq error-p t)) (or input-p err-p)))))) (unwind-protect (progn (when (null (%store-conditional lock-location nil current-process)) (process-lock lock-location current-process "Lock" (* 60. 30.))) (if (or error-p (not (eq (chaos:state conn) 'chaos:open-state))) (return nil)) (send net-stream :force-output) (when (send net-stream :listen) (let ((c (send net-stream :tyi))) (cond ((= c #o300) (process-supdup-escape net-stream t-stream)) (t (process-net-input c io-buffer t-stream)))))) (%store-conditional lock-location current-process nil))) (send lisp-proc :kill) (send net-stream :close t))))))) (defun process-net-input (c io-buffer t-stream) (ecase (send t-stream :bucky-state) (:bits (cond ((= c #o34) (tv:io-buffer-put io-buffer #o34)) (t (send t-stream :set-bucky-bits c) (send t-stream :set-bucky-state :char)))) (:char (let* ((bits (send t-stream :bucky-bits)) (control-p (ldb-test (byte 1 0) bits)) (meta-p (ldb-test (byte 1 1) bits))) (when (or control-p meta-p) (setq c (char-flipcase c))) (when control-p (setq c (set-char-bit c :control t))) (when meta-p (setq c (set-char-bit c :meta t)))) ;;bit (byte 1 4) is TOP, but I can't figure out how to use it (tv:io-buffer-put io-buffer c) (send t-stream :set-bucky-state nil)) (:metaify (setq c (set-char-bit (char-flipcase c) :meta t)) (tv:io-buffer-put io-buffer c) (send t-stream :set-bucky-state nil)) (nil (cond ((= c #o34) (send t-stream :set-bucky-state :bits)) ((= c #o15) (tv:io-buffer-put io-buffer #\return)) ((= c #o177) (tv:io-buffer-put io-buffer #\rubout)) ((zerop (ldb %%tofci (send t-stream :ttyopt))) ;;terminal can't generate real control/meta (setq c (logand c #o177)) (cond ((= c #o33) (send t-stream :set-bucky-state :metaify)) ((< c #o40) (setq c (tv:set-char-bit (+ c #\@) :control t)) (tv:io-buffer-put io-buffer c)) (t (tv:io-buffer-put io-buffer c)))) (t (tv:io-buffer-put io-buffer c)))))) (defun process-supdup-escape (stream t-stream) (let ((command (send stream :tyi))) (case command (#o302 (send t-stream :set-location (with-output-to-string (s) (do ((c (send stream :tyi) (send stream :tyi))) ((zerop c)) (send s :tyo c))))) ))) (defun read-18-bits (stream) (let* ((b0 (send stream :tyi)) (b1 (send stream :tyi)) (b2 (send stream :tyi))) (+ (ash b0 12.) (ash b1 6) b2))) (defun read-supdup-parameters (stream t-stream) (let ((nwords (dpb (read-18-bits stream) (byte 18. 0) -1))) (read-18-bits stream) (when (< nwords 0) (let* ((x (read-18-bits stream)) (y (read-18-bits stream))) x (send t-stream :set-tctyp y)) (incf nwords)) (when (< nwords 0) (let* ((x (read-18-bits stream)) (y (read-18-bits stream))) (send t-stream :set-ttyopt (dpb y (byte 18. 18.) x))) (incf nwords)) (when (< nwords 0) (let* ((x (read-18-bits stream)) (y (read-18-bits stream))) x (send t-stream :set-height y)) (incf nwords)) (when (< nwords 0) (let* ((x (read-18-bits stream)) (y (read-18-bits stream))) x (send t-stream :set-width y)) (incf nwords)) (when (< nwords 0) (let* ((x (read-18-bits stream)) (y (read-18-bits stream))) x (send t-stream :set-ttyrol y)) (incf nwords)) (when (< nwords 0) (let* ((x (read-18-bits stream)) (y (read-18-bits stream))) (send t-stream :set-ttysmt (dpb y (byte 18. 18.) x))) (incf nwords)) (do () ((zerop nwords)) (read-18-bits stream) (read-18-bits stream) (incf nwords)))) (add-initialization "SUPDUP" '(process-run-function "SUPDUP Server" 'supdup-server-function) NIL 'chaos:server-alist)