Term.mod 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. IMPLEMENTATION MODULE Term ;
  2. (* termios-based raw keyboard + ANSI screen output. *)
  3. FROM Posix IMPORT read, write, tcgetattr, tcsetattr, cfmakeraw, poll ;
  4. FROM SYSTEM IMPORT ADR, ADDRESS, BYTE ;
  5. FROM TermCfg IMPORT Cfg, Default, Load ;
  6. CONST
  7. TCSANOW = 0 ;
  8. STDIN = 0 ;
  9. STDOUT = 1 ;
  10. VAR
  11. saved : ARRAY [0..127] OF BYTE ;
  12. rawstate : ARRAY [0..127] OF BYTE ;
  13. haveSaved : BOOLEAN ;
  14. cfg : Cfg ;
  15. PROCEDURE Out (s : ARRAY OF CHAR) ;
  16. VAR i : CARDINAL ;
  17. n : LONGINT ;
  18. BEGIN
  19. i := 0 ;
  20. WHILE (i <= HIGH (s)) AND (s [i] # 0C) DO
  21. n := write (STDOUT, ADR (s [i]), 1) ;
  22. INC (i)
  23. END
  24. END Out ;
  25. PROCEDURE LoadCfg ;
  26. (* One fixed name, in the directory the shell is started from. A text file,
  27. read once, never written: the shell does not patch itself. *)
  28. VAR ok : BOOLEAN ;
  29. BEGIN
  30. Load ("TP3.TRM", cfg, ok) ;
  31. IF NOT ok THEN
  32. (* missing or malformed: Load has already left the ANSI defaults in
  33. place for anything it did not read *)
  34. END
  35. END LoadCfg ;
  36. PROCEDURE Open ;
  37. VAR r : INTEGER ;
  38. BEGIN
  39. LoadCfg ;
  40. r := tcgetattr (STDIN, ADR (saved)) ;
  41. rawstate := saved ;
  42. cfmakeraw (ADR (rawstate)) ;
  43. r := tcsetattr (STDIN, TCSANOW, ADR (rawstate)) ;
  44. haveSaved := TRUE ;
  45. Out (cfg.clear) (* clear screen, home *)
  46. END Open ;
  47. PROCEDURE Close ;
  48. VAR r : INTEGER ;
  49. BEGIN
  50. IF haveSaved THEN
  51. r := tcsetattr (STDIN, TCSANOW, ADR (saved)) ;
  52. haveSaved := FALSE
  53. END ;
  54. Out (cfg.normal) (* normal attribute *)
  55. END Close ;
  56. PROCEDURE ClrScr ;
  57. BEGIN
  58. Out (cfg.clear)
  59. END ClrScr ;
  60. PROCEDURE GotoXY (row, col : CARDINAL) ;
  61. (* cfg.moveTo with %r replaced by the row and %c by the column, both decimal
  62. and 1-based (TP3's GotoXY is 1-based); %% is a literal percent. *)
  63. VAR i : CARDINAL ;
  64. BEGIN
  65. i := 0 ;
  66. WHILE (i <= HIGH (cfg.moveTo)) AND (cfg.moveTo [i] # 0C) DO
  67. IF (cfg.moveTo [i] = '%') AND (i + 1 <= HIGH (cfg.moveTo)) THEN
  68. IF cfg.moveTo [i + 1] = 'r' THEN
  69. PutCard (row) ; INC (i, 2)
  70. ELSIF cfg.moveTo [i + 1] = 'c' THEN
  71. PutCard (col) ; INC (i, 2)
  72. ELSIF cfg.moveTo [i + 1] = 'R' THEN
  73. (* a single byte, row + 31: VT52's `ESC Y <row+32><col+32>' with a
  74. 1-based row/column *)
  75. PutCh (CHR (row + 31)) ; INC (i, 2)
  76. ELSIF cfg.moveTo [i + 1] = 'C' THEN
  77. PutCh (CHR (col + 31)) ; INC (i, 2)
  78. ELSIF cfg.moveTo [i + 1] = '%' THEN
  79. PutCh ('%') ; INC (i, 2)
  80. ELSE
  81. PutCh (cfg.moveTo [i]) ; INC (i)
  82. END
  83. ELSE
  84. PutCh (cfg.moveTo [i]) ; INC (i)
  85. END
  86. END
  87. END GotoXY ;
  88. PROCEDURE PutCh (ch : CHAR) ;
  89. VAR n : LONGINT ;
  90. BEGIN
  91. n := write (STDOUT, ADR (ch), 1)
  92. END PutCh ;
  93. PROCEDURE PutStr (s : ARRAY OF CHAR) ;
  94. VAR i : CARDINAL ;
  95. n : LONGINT ;
  96. BEGIN
  97. i := 0 ;
  98. WHILE (i <= HIGH (s)) AND (s [i] # 0C) DO
  99. n := write (STDOUT, ADR (s [i]), 1) ;
  100. INC (i)
  101. END
  102. END PutStr ;
  103. PROCEDURE PutCard (n : CARDINAL) ;
  104. VAR dig : ARRAY [0..9] OF CHAR ;
  105. i : CARDINAL ;
  106. BEGIN
  107. IF n = 0 THEN
  108. PutCh ("0")
  109. ELSE
  110. i := 0 ;
  111. WHILE n > 0 DO
  112. dig [i] := CHR (ORD ("0") + (n MOD 10)) ;
  113. n := n DIV 10 ;
  114. INC (i)
  115. END ;
  116. WHILE i > 0 DO
  117. DEC (i) ;
  118. PutCh (dig [i])
  119. END
  120. END
  121. END PutCard ;
  122. PROCEDURE PutLongCard (n : LONGCARD) ;
  123. VAR dig : ARRAY [0..19] OF CHAR ;
  124. i, m : CARDINAL ;
  125. BEGIN
  126. IF n = 0 THEN
  127. PutCh ("0")
  128. ELSE
  129. i := 0 ;
  130. WHILE n > 0 DO
  131. m := n MOD 10 ;
  132. dig [i] := CHR (ORD ("0") + m) ;
  133. n := n DIV 10 ;
  134. INC (i)
  135. END ;
  136. WHILE i > 0 DO
  137. DEC (i) ;
  138. PutCh (dig [i])
  139. END
  140. END
  141. END PutLongCard ;
  142. PROCEDURE ScrnWide (n : CARDINAL) ;
  143. VAR i : CARDINAL ;
  144. BEGIN
  145. i := 0 ;
  146. WHILE i < n DO
  147. PutCh (" ") ;
  148. INC (i)
  149. END
  150. END ScrnWide ;
  151. PROCEDURE Marked ;
  152. BEGIN
  153. Out (cfg.marked) (* highlighted attribute *)
  154. END Marked ;
  155. PROCEDURE Normal ;
  156. BEGIN
  157. Out (cfg.normal)
  158. END Normal ;
  159. PROCEDURE GetCh (VAR ch : CHAR) ;
  160. VAR n : LONGINT ;
  161. BEGIN
  162. n := read (STDIN, ADR (ch), 1) ;
  163. IF n # 1 THEN
  164. ch := 0C
  165. END
  166. END GetCh ;
  167. PROCEDURE Avail () : BOOLEAN ;
  168. TYPE PollFd = RECORD
  169. fd : CARDINAL ;
  170. events : SHORTCARD ;
  171. revents : SHORTCARD ;
  172. END ;
  173. VAR pfd : PollFd ;
  174. n : INTEGER ;
  175. BEGIN
  176. (* struct pollfd { int fd; short events; short revents; } *)
  177. pfd.fd := STDIN ;
  178. pfd.events := 1 ; (* POLLIN *)
  179. pfd.revents := 0 ;
  180. n := poll (ADR (pfd), 1, 0) ;
  181. RETURN n > 0
  182. END Avail ;
  183. PROCEDURE GetKey (VAR ch : CHAR) ;
  184. VAR n : LONGINT ;
  185. BEGIN
  186. IF Avail () THEN
  187. n := read (STDIN, ADR (ch), 1) ;
  188. IF n # 1 THEN
  189. ch := 0C
  190. END
  191. ELSE
  192. ch := 0C
  193. END
  194. END GetKey ;
  195. PROCEDURE Beep ;
  196. BEGIN
  197. Out (cfg.beep)
  198. END Beep ;
  199. BEGIN
  200. haveSaved := FALSE
  201. END Term.