system-io.red 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. %
  2. % SYSTEM-IO.RED - System dependent IO routines for Dec-20 PSL
  3. %
  4. % Author: Eric Benson
  5. % Symbolic Computation Group
  6. % Computer Science Dept.
  7. % University of Utah
  8. % Date: 16 September 1981
  9. % Copyright (c) 1981 University of Utah
  10. %
  11. global '(IN!* OUT!*);
  12. LoadTime <<
  13. IN!* := 0;
  14. OUT!* := 1;
  15. >>;
  16. fluid '(StdIN!* StdOUT!* ErrOUT!* !*Echo);
  17. LoadTime <<
  18. StdIN!* := 0;
  19. StdOUT!* := 1;
  20. ErrOUT!* := 1;
  21. >>;
  22. CompileTime flag('(RDTTY FindFreeChannel Dec20Open ContOpenError ClearIO1),
  23. 'InternalFunction);
  24. on SysLisp;
  25. external WArray JFNOfChannel, ReadFunction, WriteFunction, CLoseFunction;
  26. if_system(Tops20,
  27. lap '((!*entry Dec20ReadChar expr 1)
  28. (!*MOVE (MEMORY (reg 1) (WConst JFNOfChannel)) (reg 1))
  29. Loop % get JFN for channel
  30. (bin) % read a character
  31. (erjmp CheckEOF) % check for end-of-file on error
  32. (!*JUMPEQ (Label Loop) (reg 2) (WConst 0))% try again if it's null char
  33. (!*JUMPEQ (Label Loop) (reg 2) (WConst 8#15))% or carriage return
  34. (!*MOVE (reg 2) (reg 1)) % move char to reg 1
  35. (camn (reg nil) (fluid !*ECHO)) % is echo on?
  36. (!*EXIT 0) % no, just return char
  37. (!*PUSH (reg 1)) % yes, save char
  38. (!*CALL WriteChar) % and write it
  39. (!*POP (reg 1)) % restore it
  40. (!*EXIT 0) % and return
  41. CheckEOF
  42. (gtsts) % check file status
  43. (tlnn (reg 2) 2#000000001000000000) % gs%eof
  44. (!*JUMP (Label ReadError))
  45. (!*MOVE (WConst 26) (reg 1)) % return EOF char
  46. (!*EXIT 0)
  47. ReadError
  48. (!*MOVE (QUOTE "Attempt to read from file failed") (reg 1))
  49. (!*JCALL IoError)
  50. ));
  51. if_system(Tenex,
  52. lap '((!*entry Dec20ReadChar expr 1)
  53. (!*MOVE (MEMORY (reg 1) (WConst JFNOfChannel)) (reg 1))
  54. Loop % get JFN for channel
  55. (bin) % read a character
  56. (erjmp CheckEOF) % check for end-of-file on error
  57. (!*JUMPEQ (Label Loop) (reg 2) (WConst 0))% try again if it's null char
  58. (!*JUMPEQ (Label Loop) (reg 2) (WConst 8#15))% or carriage return
  59. (cain (reg 2) (WConst 8#37)) % TENEX EOL
  60. (!*MOVE (WConst 8#12) (reg 2)) % replace it with a linefeed
  61. (!*MOVE (reg 2) (reg 1)) % move char to reg 1
  62. (camn (reg nil) (fluid !*ECHO)) % is echo on?
  63. (!*EXIT 0) % no, just return char
  64. (!*PUSH (reg 1)) % yes, save char
  65. (!*CALL WriteChar) % and write it
  66. (!*POP (reg 1)) % restore it
  67. (!*EXIT 0) % and return
  68. CheckEOF
  69. (gtsts) % check file status
  70. (tlnn (reg 2) 2#000000001000000000) % gs%eof
  71. (!*JUMP (Label ReadError))
  72. (!*MOVE (WConst 26) (reg 1)) % return EOF char
  73. (!*EXIT 0)
  74. ReadError
  75. (!*MOVE (QUOTE "Attempt to read from file failed") (reg 1))
  76. (!*JCALL IoError)
  77. ));
  78. lap '((!*entry Dec20WriteChar expr 2)
  79. (!*MOVE (MEMORY (reg 1) (WConst JFNOfChannel)) (reg 1))
  80. % get JFN for channel
  81. (!*JUMPEQ (Label CRLF) (reg 2) (WConst 8#12)) % if LF, echo CRLF
  82. (bout) % no, just echo char
  83. (!*EXIT 0) % return
  84. CRLF
  85. (!*MOVE (WConst 8#15) (reg 2)) % write carriage-return
  86. (bout)
  87. (!*MOVE (WConst 8#12) (reg 2)) % write linefeed
  88. (bout)
  89. (!*EXIT 0) % return
  90. );
  91. internal WConst MaxTerminalBuffer = 200;
  92. internal WVar NextTerminalChar = 1;
  93. internal WString TerminalInputBuffer[MaxTerminalBuffer];
  94. lap '((!*entry ClearIO1 expr 0)
  95. %
  96. % ^C from RDTTY and restart causes trouble, but we don't want a full RESET
  97. % (don't want to close files or kill forks), so we'll just do the
  98. % part of RESET that we want, for terminal input
  99. %
  100. (!*MOVE (WConst 8#100) (reg 1)) % .priin
  101. (rfmod)
  102. (tro 2 2#001111100001000000) % tt%wak + tt%eco + .ttasi, like RESET
  103. (sfmod)
  104. (!*EXIT 0)
  105. );
  106. syslsp procedure ClearIO();
  107. << ClearIO1();
  108. TerminalInputBuffer[0] := -1;
  109. NextTerminalChar := 0;
  110. LispVar IN!* := LispVar STDIN!*;
  111. LispVar OUT!* := LispVar STDOUT!* >>;
  112. if_system(Tops20,
  113. lap '((!*entry RDTTY expr 3)
  114. (dmove (reg t1) (reg 1))
  115. (!*MOVE (WConst 8#101) (reg 1)) % .priou
  116. (rfmod) % read mode word
  117. (tlze (reg 2) 2#100000000000000000) % if tt%osp is 0, then skip
  118. (sfmod) % otherwise turn on output
  119. (dmove (reg 1) (reg t1))
  120. (!*MOVE (reg 2) (reg 4)) % save original count in r4
  121. (!*WPLUS2 (reg 1) (WConst 1)) % make input buffer into byte pointer
  122. (hrli (reg 1) 8#440700)
  123. (!*WPLUS2 (reg 3) (WConst 1)) % make prompt string into byte pointer
  124. (hrli (reg 3) 8#440700)
  125. (!*MOVE (reg 1) (reg 5)) % print it once
  126. (!*MOVE (reg 3) (reg 1))
  127. (psout)
  128. (!*MOVE (reg 5) (reg 1))
  129. (hrli (reg 2) 2#000110000000000000) % rd%bel + rd%crf
  130. (jsys 8#523) % RDTTY
  131. (!*JUMP (Label CantRDTTY))
  132. (!*MOVE (reg 4) (reg 1)) % move original count to r1
  133. (hrrzs (reg 2)) % clear flag bits in r2
  134. (!*WDIFFERENCE (reg 1) (reg 2)) % return # chars read, not # available
  135. (!*EXIT 0)
  136. CantRDTTY
  137. (!*MOVE (QUOTE "Can't read from terminal") (reg 1))
  138. (!*JCALL IOError)
  139. ));
  140. if_system(Tenex,
  141. lap '((!*entry RDTTY expr 3)
  142. (move (reg t1) (reg 1))
  143. (move (reg t2) (reg 2))
  144. (!*MOVE (WConst 8#101) (reg 1)) % .priou
  145. (rfmod) % read mode word
  146. (tlze (reg 2) 2#100000000000000000) % if tt%osp is 0, then skip
  147. (sfmod) % otherwise turn on output
  148. (move (reg 1) (reg t1))
  149. (move (reg 2) (reg t2))
  150. (!*MOVE (reg 2) (reg 4)) % save original count in r4
  151. (!*WPLUS2 (reg 1) (WConst 1)) % make input buffer into byte pointer
  152. (hrli (reg 1) 8#440700)
  153. (!*WPLUS2 (reg 3) (WConst 1)) % make prompt string into byte pointer
  154. (hrli (reg 3) 8#440700)
  155. (!*MOVE (reg 1) (reg 5)) % print it once
  156. (!*MOVE (reg 3) (reg 1))
  157. (psout)
  158. (!*MOVE (reg 5) (reg 1))
  159. % (hrli (reg 2) 2#000110000000000000) % rd%bel + rd%crf
  160. % (jsys 8#523) % RDTTY
  161. % (!*JUMP (Label CantRDTTY))
  162. (!*MOVE (WConst MaxTerminalBuffer) (reg 2)) % # of chars
  163. (setz 3 0) % clear 3
  164. (jsys 8#611) % PSTIN, IMSSS JSYS
  165. (!*MOVE (WConst 8#12) (reg 3)) % put linefeed at end of buffer
  166. (dpb (reg 3) (reg 1)) % 1 points to end of what's been read
  167. (!*MOVE (reg 4) (reg 1)) % move original count to r1
  168. (hrrzs (reg 2)) % clear flag bits in r2
  169. (!*WDIFFERENCE (reg 1) (reg 2)) % return # chars read, not # available
  170. (!*EXIT 0)
  171. ));
  172. syslsp procedure TerminalInputHandler Chn;
  173. begin scalar Ch;
  174. while NextTerminalChar >= StrLen TerminalInputBuffer do
  175. << NextTerminalChar := 0;
  176. TerminalInputBuffer[0] := RDTTY(TerminalInputBuffer,
  177. MaxTerminalBuffer,
  178. if StringP LispVar PromptString!*
  179. then LispVar PromptString!*
  180. else ">") >>;
  181. Ch := StrByt(TerminalInputBuffer, NextTerminalChar);
  182. NextTerminalChar := NextTerminalChar + 1;
  183. return Ch;
  184. end;
  185. syslsp procedure FindFreeChannel();
  186. begin scalar Chn;
  187. Chn := 0;
  188. while JfnOfChannel[Chn] neq 0 do
  189. << if Chn >= MaxChannels then IOError("No free channels left");
  190. Chn := Chn + 1 >>;
  191. return Chn;
  192. end;
  193. syslsp procedure SystemMarkAsClosedChannel FileDes;
  194. JFNOfChannel[IntInf FileDes] := 0;
  195. lap '((!*entry Dec20CloseChannel expr 1)
  196. (!*MOVE (reg 1) (reg 2)) % save in case of error
  197. (!*MOVE (MEMORY (reg 1) (WConst JFNOfChannel)) (reg 1))
  198. (closf)
  199. (!*JUMP (Label CloseError))
  200. (!*EXIT 0)
  201. CloseError
  202. (!*MOVE (QUOTE "Channel could not be closed") (reg 1))
  203. (!*JCALL ChannelError)
  204. );
  205. syslsp procedure SystemOpenFileSpecial FileName;
  206. << JFNOfChannel[FileName := FindFreeChannel()] := -1;
  207. FileName >>;
  208. syslsp procedure SystemOpenFileForInput FileName;
  209. begin scalar Chn, JFN;
  210. Chn := FindFreeChannel();
  211. JFN := Dec20Open(FileName,
  212. % gj%old gj%sht
  213. 2#001000000000000001000000000000000000,
  214. % 7*of%bsz of%rd
  215. 2#000111000000000000010000000000000000);
  216. if JFN eq 0 then return ContOpenError(FileName, 'INPUT);
  217. JFNOfChannel[Chn] := JFN;
  218. ReadFunction[Chn] := 'Dec20ReadChar;
  219. CloseFunction[Chn] := 'Dec20CloseChannel;
  220. return Chn;
  221. end;
  222. syslsp procedure SystemOpenFileForOutput FileName;
  223. begin scalar Chn, JFN;
  224. Chn := FindFreeChannel();
  225. JFN := Dec20Open(FileName,
  226. % gj%fou gj%new gj%sht
  227. 2#110000000000000001000000000000000000,
  228. % 7*of%bsz of%wr
  229. 2#000111000000000000001000000000000000);
  230. if JFN eq 0 then return ContOpenError(FileName, 'OUTPUT);
  231. JFNOfChannel[Chn] := JFN;
  232. WriteFunction[Chn] := 'Dec20WriteChar;
  233. CloseFunction[Chn] := 'Dec20CloseChannel;
  234. return Chn;
  235. end;
  236. lap '((!*entry Dec20Open expr 3)
  237. %
  238. % Dec20Open(Filename string, GTJFN bits, OPENF bits)
  239. %
  240. (!*WPLUS2 (reg 1) (WConst 1)) % increment r1 to point to characters
  241. (hrli (reg 1) 8#440700) % turn r1 into a byte pointer
  242. (!*MOVE (reg 1) (reg 4)) % save filename string in r4
  243. (!*MOVE (reg 2) (reg 1)) % GTJFN flag bits in r1
  244. (!*MOVE (reg 4) (reg 2)) % string in r2
  245. (gtjfn)
  246. (!*JUMP (Label CantOpen))
  247. (!*MOVE (reg 3) (reg 2)) % OPENF bits in r2, JFN in r1
  248. (openf)
  249. CantOpen
  250. (!*MOVE (WConst 0) (reg 1)) % return 0 on error
  251. (!*EXIT 0) % else return the JFN
  252. );
  253. off SysLisp;
  254. lisp procedure ContOpenError(FileName, AccessMode);
  255. ContinuableError(99,
  256. BldMsg("`%s' cannot be open for %w",
  257. FileName, AccessMode),
  258. list('OPEN, MkSTR FileName, MkQuote AccessMode));
  259. END;