hp2648a.sl 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2. %
  3. % HP2648A.SL - Terminal Interface
  4. %
  5. % Author: Alan Snyder
  6. % Hewlett-Packard/CRC
  7. % Date: 16 August 1982
  8. %
  9. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  10. (BothTimes (load objects))
  11. (CompileTime (load display-char fast-int fast-vectors))
  12. (defflavor hp2648a (
  13. (height 24) % number of rows (0 indexed)
  14. (maxrow 23) % highest numbered row
  15. (width 80) % number of columns (0 indexed)
  16. (maxcol 79) % highest numbered column
  17. (cursor-row 0) % cursor position
  18. (cursor-column 0) % cursor position
  19. (raw-mode NIL)
  20. markers % vector indicating locations of field markers
  21. (marker-table % table for generating markers
  22. (Vector
  23. (char @) (char B) (char A) (char C)
  24. (char D) (char F) (char E) (char G)
  25. (char H) (char J) (char I) (char K)
  26. (char L) (char N) (char M) (char O)
  27. ))
  28. )
  29. ()
  30. (gettable-instance-variables height width maxrow maxcol raw-mode)
  31. )
  32. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  33. (CompileTime
  34. (defmacro out-n (n)
  35. `(progn
  36. (if (> ,n 9)
  37. (PBOUT (+ (char 0) (/ ,n 10))))
  38. (PBOUT (+ (char 0) (// ,n 10))))))
  39. (CompileTime
  40. (defmacro out-char (ch)
  41. `(PBOUT (char ,ch))))
  42. (CompileTime
  43. (dm out-chars (form)
  44. (for (in ch (cdr form))
  45. (with L)
  46. (collect (list 'out-char ch) L)
  47. (returns (cons 'progn L)))))
  48. (CompileTime
  49. (defmacro out-move ()
  50. `(out-chars ESC & !a)))
  51. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  52. (defmethod (hp2648a get-character) ()
  53. (& (PBIN) 8#377)
  54. )
  55. (defmethod (hp2648a ring-bell) ()
  56. (out-char BELL)
  57. )
  58. (defmethod (hp2648a move-cursor) (row column)
  59. (cond ((< row 0) (setf row 0))
  60. ((>= row height) (setf row maxrow)))
  61. (cond ((< column 0) (setf column 0))
  62. ((>= column width) (setf column maxcol)))
  63. (cond ((and (= row cursor-row) (= column cursor-column))) % no action needed
  64. ((and (= row 0) (= column 0))
  65. (out-chars ESC H)) % cursor HOME
  66. ((= row cursor-row) % movement on current row
  67. (cond ((= column 0)
  68. (out-char CR)) % move to left margin
  69. ((= column (- cursor-column 1))
  70. (out-chars ESC D)) % move LEFT
  71. ((= column (+ cursor-column 1))
  72. (out-chars ESC C)) % move RIGHT
  73. (t (out-move) (out-n column) (out-char C))))
  74. ((= column cursor-column) % movement on same column
  75. (cond ((= row (- cursor-row 1))
  76. (out-chars ESC A)) % move UP
  77. ((= row (+ cursor-row 1))
  78. (out-char LF)) % move DOWN
  79. (t (out-move) (out-n row) (out-char R))))
  80. (t % arbitrary movement
  81. (out-move) (out-n row) (out-char (lower R))
  82. (out-n column) (out-char C)))
  83. (setf cursor-row row)
  84. (setf cursor-column column)
  85. )
  86. (defmethod (hp2648a enter-raw-mode) ()
  87. (when (not raw-mode)
  88. (EchoOff)
  89. (out-chars ESC & !s 1 A) % Enable Keypad
  90. (setf raw-mode T)))
  91. (defmethod (hp2648a leave-raw-mode) ()
  92. (when raw-mode
  93. (setf raw-mode NIL)
  94. (out-chars ESC & !s 0 A) % Disable Keypad
  95. (EchoOn)))
  96. (defmethod (hp2648a erase) ()
  97. % This method should be invoked to initialize the screen to a known state.
  98. (out-chars ESC H ESC J)
  99. (setf cursor-row 0)
  100. (setf cursor-column 0)
  101. (for (from row 0 maxrow)
  102. (do (let ((marker-line (vector-fetch markers row)))
  103. (for (from col 0 maxcol)
  104. (do (vector-store marker-line col NIL))
  105. ))))
  106. )
  107. (defmethod (hp2648a clear-line) ()
  108. (out-chars ESC K)
  109. (let ((marker-line (vector-fetch markers cursor-row)))
  110. (for (from col cursor-column maxcol)
  111. (do (vector-store marker-line col NIL))
  112. )))
  113. (defmethod (hp2648a convert-character) (ch)
  114. (setq ch (& ch (display-character-cons
  115. (dc-make-enhancement-mask INVERSE-VIDEO
  116. BLINK
  117. UNDERLINE
  118. INTENSIFY)
  119. (dc-make-font-mask 0)
  120. 16#FF)))
  121. (let ((code (dc-character-code ch)))
  122. (if (or (< code #\space) (= code (char rubout)))
  123. (setq ch #\space)))
  124. ch)
  125. (defmethod (hp2648a normal-enhancement) ()
  126. (dc-make-enhancement-mask)
  127. )
  128. (defmethod (hp2648a highlighted-enhancement) ()
  129. (dc-make-enhancement-mask INVERSE-VIDEO)
  130. )
  131. (defmethod (hp2648a supported-enhancements) ()
  132. (dc-make-enhancement-mask INVERSE-VIDEO BLINK UNDERLINE INTENSIFY)
  133. )
  134. (defmethod (hp2648a update-line) (row old-line new-line columns)
  135. % Old-Line is updated.
  136. % This code is particularly complicated because of the way HP terminals
  137. % implement display enhancements using field markers. Most terminals
  138. % don't require this level of complexity.
  139. (prog (last-nonblank-column col terminal-enhancement old new marker-line
  140. first-col last-col)
  141. (setf first-col (car columns))
  142. (setf last-col (cdr columns))
  143. (setf marker-line (vector-fetch markers row))
  144. % Find out the minimal actual bounds:
  145. (while (and (<= first-col last-col)
  146. (= (vector-fetch new-line last-col) (vector-fetch old-line last-col)))
  147. (setf last-col (- last-col 1))
  148. )
  149. (if (> first-col last-col) (return NIL)) % No change at all!
  150. (while (and (<= first-col last-col)
  151. (= (vector-fetch new-line first-col) (vector-fetch old-line first-col)))
  152. (setf first-col (+ first-col 1))
  153. )
  154. % The purpose of the following code is to determine whether or not to use
  155. % ClearEOL. If we decide to use ClearEOL, then we will set the variable
  156. % LAST-NONBLANK-COLUMN to the obvious index; otherwise, we will set it to
  157. % NIL. If we decide to use ClearEOL, then we will clear out the OLD-LINE
  158. % now, but do the actual ClearEOL later.
  159. % Use of ClearEOL is appropriate if the rightmost changed character has
  160. % been changed to a space, and the remainder of the line is blank. It
  161. % is appropriate only if it replaces writing at least 3 blanks.
  162. % Using ClearEOL can cause problems when display enhancements are used. If
  163. % you write to the position just to the right of the terminal's
  164. % end-of-line, the existing field will be extended. To avoid this problem,
  165. % we will avoid using ClearEOL where the immediately preceding character
  166. % has a non-zero enhancement.
  167. (when (= (vector-fetch new-line last-col) #\space)
  168. (setf last-nonblank-column (vector-upper-bound new-line))
  169. (while (and (>= last-nonblank-column 0)
  170. (= (vector-fetch new-line last-nonblank-column) #\space)
  171. )
  172. (setf last-nonblank-column (- last-nonblank-column 1))
  173. )
  174. % We have computed the column containing the rightmost non-blank
  175. % character. Now, we can decide whether we want to do a ClearEOL or not.
  176. (if (and (< last-nonblank-column (- last-col 2))
  177. (or (<= last-nonblank-column 0)
  178. (~= (dc-enhancement-mask
  179. (vector-fetch old-line last-nonblank-column)) 0)))
  180. % then
  181. (while (> last-col last-nonblank-column)
  182. (vector-store old-line last-col #\space)
  183. (setf last-col (- last-col 1))
  184. )
  185. % else
  186. (setf last-nonblank-column NIL)
  187. ))
  188. % Output all changed characters (other than those that will be taken care
  189. % of by ClearEOL):
  190. (setf col first-col) % current column under examination
  191. (setf old (vector-fetch old-line col)) % terminal's contents at that location
  192. (setf new (vector-fetch new-line col)) % new contents for that location
  193. (setf terminal-enhancement (dc-enhancement-mask old))
  194. % terminal's enhancement for that location
  195. % (enhancement in OLD will not always be correct as we go)
  196. (if (not (and (= cursor-row row) (<= cursor-column col)))
  197. (=> self move-cursor row col))
  198. (while (<= col last-col)
  199. % First, we check to see if we need to write a new field marker.
  200. % A field marker is needed if the terminal's idea of the current
  201. % character's enhancement is different than the desired enhancement.
  202. (when (~= terminal-enhancement (dc-enhancement-mask new))
  203. (=> self move-cursor-forward col old-line)
  204. (=> self write-field-marker new)
  205. )
  206. % Next, we check to see if we need to write a new character code.
  207. (when (~= old new) % check this first for efficiency
  208. (let ((old-code (dc-character-code old))
  209. (new-code (dc-character-code new))
  210. )
  211. (when (or (and (= new-code #\space) (= col last-col))
  212. % last SPACE must be written (may extend EOL)
  213. (~= old-code new-code))
  214. (=> self move-cursor-forward col old-line)
  215. (PBOUT new-code)
  216. (setf cursor-column (+ cursor-column 1))
  217. (when (> cursor-column maxcol)
  218. (setf cursor-column 0)
  219. (setf cursor-row (+ cursor-row 1))
  220. (if (> cursor-row maxrow)
  221. (=> self move-cursor 0 0)))
  222. ))
  223. (vector-store old-line col new)
  224. )
  225. % The following code is executed only if there is a next character.
  226. (if (< col maxcol)
  227. (let* ((next-col (+ col 1))
  228. (next-old (vector-fetch old-line next-col))
  229. (next-new (vector-fetch new-line next-col))
  230. )
  231. % Compute the terminal's idea of the enhancement for the next
  232. % character. This is invalid if we are about to ClearEOL, but
  233. % that case doesn't matter.
  234. (setf terminal-enhancement
  235. (if (vector-fetch marker-line next-col) % field marker there
  236. (dc-enhancement-mask next-old)
  237. (dc-enhancement-mask new)))
  238. (setf old next-old)
  239. (setf new next-new)
  240. ))
  241. (setf col (+ col 1))
  242. )
  243. % Check to see if a final field marker is needed.
  244. (when (and (<= col maxcol)
  245. (or (null last-nonblank-column) (<= col last-nonblank-column))
  246. (~= terminal-enhancement (dc-enhancement-mask old)))
  247. (=> self move-cursor-forward col old-line)
  248. (=> self write-field-marker new)
  249. )
  250. % Do the ClearEOL, if that's what we decided to do.
  251. (when last-nonblank-column
  252. (=> self move-cursor-forward (+ last-nonblank-column 1) old-line)
  253. (=> self clear-line)
  254. )
  255. ))
  256. % The following methods are provided for INTERNAL use only!
  257. (defmethod (hp2648a init) ()
  258. (setf markers (MkVect maxrow))
  259. (for (from row 0 maxrow)
  260. (do (vector-store markers row (MkVect maxcol)))
  261. )
  262. )
  263. (defmethod (hp2648a move-cursor-forward) (column line)
  264. (cond ((> (- column cursor-column) 4)
  265. (out-move) (out-n column) (out-char C)
  266. (setf cursor-column column))
  267. (t (while (< cursor-column column)
  268. (PBOUT (dc-character-code (vector-fetch line cursor-column)))
  269. (setf cursor-column (+ cursor-column 1))
  270. ))))
  271. (defmethod (hp2648a write-field-marker) (ch)
  272. (out-chars ESC & !d)
  273. (PBOUT (vector-fetch marker-table (dc-enhancement-index ch)))
  274. (vector-store (vector-fetch markers cursor-row) cursor-column T)
  275. )