TermCfg.mod 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. IMPLEMENTATION MODULE TermCfg ;
  2. FROM Posix IMPORT open, read, close ;
  3. FROM SYSTEM IMPORT ADR, BYTE ;
  4. CONST
  5. ESC = 27 ;
  6. CR = 13 ;
  7. LF = 10 ;
  8. BS = 92 ; (* backslash, as a number: Modula-2 string escaping is
  9. not something to rely on for a single character *)
  10. MaxFile = 4095 ;
  11. PROCEDURE Clear (VAR s : ARRAY OF CHAR) ;
  12. VAR i : CARDINAL ;
  13. BEGIN
  14. i := 0 ;
  15. WHILE i <= HIGH (s) DO
  16. s [i] := 0C ;
  17. INC (i)
  18. END
  19. END Clear ;
  20. PROCEDURE Copy (VAR dst : ARRAY OF CHAR ; src : ARRAY OF CHAR) ;
  21. VAR i : CARDINAL ;
  22. BEGIN
  23. i := 0 ;
  24. WHILE (i <= HIGH (dst)) AND (i <= HIGH (src)) AND (src [i] # 0C) DO
  25. dst [i] := src [i] ;
  26. INC (i)
  27. END ;
  28. IF i <= HIGH (dst) THEN
  29. dst [i] := 0C
  30. END
  31. END Copy ;
  32. PROCEDURE Up (ch : CHAR) : CHAR ;
  33. BEGIN
  34. IF (ch >= 'a') AND (ch <= 'z') THEN
  35. RETURN CHR (ORD (ch) - 32)
  36. END ;
  37. RETURN ch
  38. END Up ;
  39. PROCEDURE KeyIs (key : ARRAY OF CHAR ; want : ARRAY OF CHAR) : BOOLEAN ;
  40. VAR i : CARDINAL ;
  41. BEGIN
  42. i := 0 ;
  43. LOOP
  44. IF (i > HIGH (key)) OR (i > HIGH (want)) THEN
  45. RETURN FALSE
  46. END ;
  47. IF Up (key [i]) # Up (want [i]) THEN
  48. RETURN FALSE
  49. END ;
  50. IF want [i] = 0C THEN
  51. RETURN TRUE
  52. END ;
  53. INC (i)
  54. END
  55. END KeyIs ;
  56. PROCEDURE ParseValue (src : ARRAY OF CHAR ; VAR dst : ARRAY OF CHAR) ;
  57. (* \e, \r, \n, \t, \\, ^X; everything else is a literal character. *)
  58. VAR i, o, c : CARDINAL ; ch : CHAR ;
  59. BEGIN
  60. i := 0 ; o := 0 ;
  61. WHILE (i <= HIGH (src)) AND (src [i] # 0C) DO
  62. ch := src [i] ;
  63. IF (ORD (ch) = BS) AND (i + 1 <= HIGH (src)) AND (src [i + 1] # 0C) THEN
  64. INC (i) ;
  65. ch := src [i] ;
  66. IF (ch = 'e') OR (ch = 'E') THEN
  67. c := ESC
  68. ELSIF ch = 'r' THEN
  69. c := CR
  70. ELSIF ch = 'n' THEN
  71. c := LF
  72. ELSIF ch = 't' THEN
  73. c := 9
  74. ELSIF ORD (ch) = BS THEN
  75. c := BS
  76. ELSE
  77. c := ORD (ch)
  78. END
  79. ELSIF (ch = '^') AND (i + 1 <= HIGH (src)) AND (src [i + 1] # 0C) THEN
  80. INC (i) ;
  81. c := ORD (Up (src [i])) - 64
  82. ELSE
  83. c := ORD (ch)
  84. END ;
  85. IF o <= HIGH (dst) THEN
  86. dst [o] := CHR (c) ;
  87. INC (o)
  88. END ;
  89. INC (i)
  90. END ;
  91. IF o <= HIGH (dst) THEN
  92. dst [o] := 0C
  93. END
  94. END ParseValue ;
  95. PROCEDURE Apply (VAR c : Cfg ; key, val : ARRAY OF CHAR) ;
  96. BEGIN
  97. IF KeyIs (key, "NAME") THEN
  98. Copy (c.name, val)
  99. ELSIF KeyIs (key, "CLEAR") THEN
  100. ParseValue (val, c.clear)
  101. ELSIF KeyIs (key, "HOME") THEN
  102. ParseValue (val, c.home)
  103. ELSIF KeyIs (key, "GOTO") OR KeyIs (key, "MOVETO") THEN
  104. ParseValue (val, c.moveTo)
  105. ELSIF KeyIs (key, "NORMAL") THEN
  106. ParseValue (val, c.normal)
  107. ELSIF KeyIs (key, "MARKED") THEN
  108. ParseValue (val, c.marked)
  109. ELSIF KeyIs (key, "BEEP") THEN
  110. ParseValue (val, c.beep)
  111. END
  112. (* an unknown key is ignored on purpose: TINST's files and ours can then
  113. share a file without one rejecting the other's fields *)
  114. END Apply ;
  115. PROCEDURE Default (VAR c : Cfg) ;
  116. BEGIN
  117. Copy (c.name, "ANSI") ;
  118. ParseValue ("\e[2J\e[H", c.clear) ;
  119. ParseValue ("\e[H", c.home) ;
  120. ParseValue ("\e[%r;%cH", c.moveTo) ;
  121. ParseValue ("\e[0m", c.normal) ;
  122. ParseValue ("\e[1;7m", c.marked) ;
  123. ParseValue ("^G", c.beep)
  124. END Default ;
  125. PROCEDURE Load (path : ARRAY OF CHAR ; VAR c : Cfg ; VAR ok : BOOLEAN) ;
  126. VAR fd : INTEGER ;
  127. k : LONGINT ;
  128. b : BYTE ;
  129. buf : ARRAY [0..MaxFile] OF CHAR ;
  130. n, i, ls, le, eq, j : CARDINAL ;
  131. key : ARRAY [0..31] OF CHAR ;
  132. val : ARRAY [0..255] OF CHAR ;
  133. bad : BOOLEAN ;
  134. BEGIN
  135. Default (c) ;
  136. ok := FALSE ;
  137. fd := open (ADR (path), 0, 0) ;
  138. IF fd < 0 THEN
  139. RETURN
  140. END ;
  141. n := 0 ;
  142. LOOP
  143. k := read (fd, ADR (b), 1) ;
  144. IF k # 1 THEN
  145. EXIT
  146. END ;
  147. IF b = 26 THEN (* ^Z ends the text *)
  148. EXIT
  149. END ;
  150. IF n <= HIGH (buf) THEN
  151. buf [n] := CHR (ORD (b)) ;
  152. INC (n)
  153. END
  154. END ;
  155. k := close (fd) ;
  156. bad := FALSE ;
  157. i := 0 ;
  158. WHILE i < n DO
  159. ls := i ;
  160. WHILE (i < n) AND (buf [i] # CHR (CR)) AND (buf [i] # CHR (LF)) DO
  161. INC (i)
  162. END ;
  163. le := i ;
  164. WHILE (i < n) AND ((buf [i] = CHR (CR)) OR (buf [i] = CHR (LF))) DO
  165. INC (i)
  166. END ;
  167. (* trim blanks *)
  168. WHILE (ls < le) AND ((buf [ls] = ' ') OR (buf [ls] = CHR (9))) DO
  169. INC (ls)
  170. END ;
  171. WHILE (le > ls) AND ((buf [le - 1] = ' ') OR (buf [le - 1] = CHR (9))) DO
  172. DEC (le)
  173. END ;
  174. IF (ls < le) AND (buf [ls] # ';') THEN
  175. eq := ls ;
  176. WHILE (eq < le) AND (buf [eq] # '=') DO
  177. INC (eq)
  178. END ;
  179. IF eq = le THEN
  180. bad := TRUE (* a line with no '=' *)
  181. ELSE
  182. j := 0 ;
  183. WHILE (ls < eq) AND (j <= HIGH (key)) DO
  184. key [j] := buf [ls] ;
  185. INC (j) ;
  186. INC (ls)
  187. END ;
  188. key [j] := 0C ;
  189. INC (eq) ; (* skip '=' *)
  190. j := 0 ;
  191. WHILE (eq < le) AND (j <= HIGH (val)) DO
  192. val [j] := buf [eq] ;
  193. INC (j) ;
  194. INC (eq)
  195. END ;
  196. val [j] := 0C ;
  197. Apply (c, key, val)
  198. END
  199. END
  200. END ;
  201. ok := NOT bad
  202. END Load ;
  203. END TermCfg.