]>
Commit | Line | Data |
---|---|---|
e58a7a25 L |
1 | ; CPSTT.ASM\r |
2 | ; KERMIT - (Celtic for "FREE")\r | |
3 | ;\r | |
4 | ; This is the CP/M-80 implementation of the Columbia University\r | |
5 | ; KERMIT file transfer protocol.\r | |
6 | ;\r | |
7 | ; Version 4.0\r | |
8 | ;\r | |
9 | ; Copyright June 1981,1982,1983,1984,1985\r | |
10 | ; Columbia University\r | |
11 | ;\r | |
12 | ; Originally written by Bill Catchings of the Columbia University Center for\r | |
13 | ; Computing Activities, 612 W. 115th St., New York, NY 10025.\r | |
14 | ;\r | |
15 | ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben,\r | |
16 | ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many\r | |
17 | ; others. \r | |
18 | ;\r | |
19 | ; This file contains the code for the TRANSMIT and CONNECT commands,\r | |
20 | ; which communicate with a host which is not running KERMIT.\r | |
21 | ;\r | |
22 | ; revision history:\r | |
23 | ;\r | |
24 | ;edit 12, 31-Jan-1991 by MF. Delete call to "inbuf" after "xmit1" in\r | |
25 | ; the TRANSMIT command. "getfil" initializes various counters so that\r | |
26 | ; when "in1chr" is first called, "inbuf" will be called immediately\r | |
27 | ; and will read sectors of the file to be transmitted from disk.\r | |
28 | ; This, along with a fix to "in1chr" in CPSUTL.ASM, fixes a bug\r | |
29 | ; discovered by Lance Tagliapietra of the University of Wisconsin at\r | |
30 | ; Platteville wherein the TRANSMIT command was failing to transmit some\r | |
31 | ; characters in files over one sector in length. See CPSUTL.ASM,\r | |
32 | ; edit 29.\r | |
33 | ; edit 11, 10 September, a987, by OBSchou. Modified TRANSMIT command\r | |
34 | ; to TRANSMIT <file> <string>\r | |
35 | ;\r | |
36 | ; edit 10, 27 August, 1987 by OBSchou. Fixed bugs in Transmit, but I may\r | |
37 | ; be introducing problems for IBM/CMS or half duplex systems. What\r | |
38 | ; does this combination do??\r | |
39 | ;\r | |
40 | ; edit 9 30 March, 1987 by OBSchou to replace the TRANSMIT routine.\r | |
41 | ; Syntax is now TRANSMIT file after a previous \r | |
42 | ; INPUT <wait time> <string to wait for>\r | |
43 | ;\r | |
44 | ; edit 8 19 June, 1986 by OBSchou. Modified the interupt testing routine\r | |
45 | ; to see if the command was a 'D' (Drop the line), in which case also\r | |
46 | ; do a 'C', ie disconnect. This is really a little too much of a\r | |
47 | ; system dependent thing.\r | |
48 | ; For now, Ill leave it here, and possibly move it later.\r | |
49 | ;\r | |
50 | ; edit 7 30 May 1986 OBSchou. Moved xon/xoff control (ie XON/OFF sent to host)\r | |
51 | ; out to CPSUTL so that ther printer routine can use it too.\r | |
52 | ;\r | |
53 | ; edit 6 30 April, 1986 by OBSchou.\r | |
54 | ; Fixed transmit bug, so as soon as the protocol character is \r | |
55 | ; received from the host is received then another line is sent.\r | |
56 | ; added in a comchr (ds 1) to save the character read from the comm \r | |
57 | ; line in prtchr, and is restored in a on return.\r | |
58 | ;\r | |
59 | ; edit 5 7 March, 1986 by OBSchou Loughborough University. \r | |
60 | ; Need to save the E register before calling outmdm (in CPSSYS.ASM)\r | |
61 | ; if doing Half duplex. Push/pop DE should sort this problem\r | |
62 | ;\r | |
63 | ; edit 4: 13-Jan-85 by Vanya J.Cooper Pima Commun. College Tel: 602-884-6809\r | |
64 | ;\r | |
65 | ;pcc002 28-Dec-84 modules:cp4tt,cp4utl\r | |
66 | ; Add connect mode <esc>P command to toggle printer on\r | |
67 | ; and off. Conflicts with "official" recommended commands\r | |
68 | ; in protocol manual, but I don't think CP/M will ever get\r | |
69 | ; a PUSH command.\r | |
70 | ;\r | |
71 | ;pcc003-pcc005 2-Jan-85 vjc modules:cp4mit,cp4tt,cp4utl\r | |
72 | ; These edits must all be installed together and change the way\r | |
73 | ; logging is handled. The log file spec is moved to a separate\r | |
74 | ; fcb, and not opened until an actual CONNECT command is given.\r | |
75 | ; This takes care of a NASTY bug that if you used any other file\r | |
76 | ; command between the LOG and CONNECT, the log file would get\r | |
77 | ; written over the last file used. This also allows logging to\r | |
78 | ; be "permanently" enabled until an CLOSE (new command) for all\r | |
79 | ; CONNECT sessions, like most other kermits do. If a log file\r | |
80 | ; already exists, it will be appended to. Also add two new\r | |
81 | ; CONNECT mode commands <esc>Q to suspend logging and <esc>R to\r | |
82 | ; resume. <esc>R means something else during TRANSMIT, but\r | |
83 | ; logging is never on then, so there shouldn't be any conflict.\r | |
84 | ; I also changed the write code, so that it can handle one more\r | |
85 | ; character after the XOFF is send to stop the host. This allows\r | |
86 | ; a little "slop" for systems that don't stop immediately (such\r | |
87 | ; as TOPS10), but it didn't help much.\r | |
88 | ;\r | |
89 | ;pcc008 2-Jan-85 vjc modules:cp4def,cp4tt,cp4utl\r | |
90 | ; Keyboard input during CONNECT mode can get locked out if\r | |
91 | ; there is enough input from the modem port to keep prtchr\r | |
92 | ; busy. This can happen for example, if the printer is running\r | |
93 | ; at the same speed as the modem line, leaving you helpless to\r | |
94 | ; turn it off or abort the host. Add a fairness count, so that\r | |
95 | ; at least every prfair characters we look at console input.\r | |
96 | ;\r | |
97 | ;pcc012 4-Jan-85 vjc modules:cp4mit,cp4tt,cp4utl\r | |
98 | ; Use the big buffer for the log file. Move the log file back\r | |
99 | ; into the common fcb and only save the drive, name, and\r | |
100 | ; extension between connects. Add new routines to cp4utl to\r | |
101 | ; create or append to an existing file, and to conditionally\r | |
102 | ; advance buffers only if in memory. Remove edit pcc003 that\r | |
103 | ; allows one more character after the xoff, since it didn't\r | |
104 | ; really work very well and does not fit in well with the way\r | |
105 | ; the buffer advancing routines are set up. If someone still\r | |
106 | ; thinks this would be useful, it could be put back in with a\r | |
107 | ; little more work.\r | |
108 | ; \r | |
109 | ; While testing this edit, I also noticed another bug that\r | |
110 | ; the command parsing routines do not limit or check the\r | |
111 | ; length of command lines or file specs, trashing what ever\r | |
112 | ; comes after them. Currently because of where the fcb and\r | |
113 | ; command buffer are located, this does not usually cause a\r | |
114 | ; problem, but could if an extremely long line was typed in,\r | |
115 | ; or in the future multiple fcbs defined elsewhere in memory\r | |
116 | ; were used. Maybe this should be put on the bug list\r | |
117 | ; somewhere.\r | |
118 | ;\r | |
119 | ; edit 3: July 27, 1984\r | |
120 | ; Allow assembly with LASM: to CP4TT is linked by CP4PKT, and links\r | |
121 | ; to CP4CPM; remove exclamation points so as not to confuse LASM.\r | |
122 | ; Add Toad Hall TACtrap to TRANSMIT command (TAC intercept character\r | |
123 | ; is only doubled if it's data; when typed by the user, they're not\r | |
124 | ; automatically doubled)\r | |
125 | ;\r | |
126 | ; edit 2: June 7, 1984\r | |
127 | ; formatting and documentation; add module version number; make sure\r | |
128 | ; console is selected when leaving intchr.\r | |
129 | ;\r | |
130 | ; edit 1: May, 1984\r | |
131 | ; extracted from CPMBASE.M80 version 3.9; modifications are described\r | |
132 | ; in the accompanying .UPD file.\r | |
133 | \r | |
134 | ttver: db 'CPSTT.ASM (12) 31-Jan-1991$'\r | |
135 | \r | |
136 | ; This is the TRANSMIT command. It attempts to send a file, even\r | |
137 | ; though there is no KERMIT on the other side.\r | |
138 | ; here from: kermit\r | |
139 | ;\r | |
140 | ; [OBS] I have replaced the routine, so that TRANSMIT <filename> <wait string>\r | |
141 | ; will send a line at a time to the host in a manner similar to MSKERMIT\r | |
142 | ;\r | |
143 | ;\r | |
144 | xmit: mvi a,cmofi ;Parse an input file spec (non-wild).\r | |
145 | lxi d,fcb ;Give the address for the FCB.\r | |
146 | call comnd\r | |
147 | jmp kermit ;Give up on bad parse.\r | |
148 | ;\r | |
149 | lxi d,stbuff ; where to put the string\r | |
150 | mvi a,cmtxt ; get text\r | |
151 | call comnd\r | |
152 | jmp kermit ; not quite correct...\r | |
153 | sta strcnt ; string count returned in a\r | |
154 | ana a ; if its zero, make it 1 character (CR)\r | |
155 | jnz xmit0\r | |
156 | mvi a,1\r | |
157 | sta strcnt\r | |
158 | mvi a,cr\r | |
159 | sta stbuff\r | |
160 | ;\r | |
161 | xmit0: call cfmcmd\r | |
162 | call getfil ;Open file.\r | |
163 | cpi 0FFH ;Succeed?\r | |
164 | jnz xmit1\r | |
165 | lxi d,erms15\r | |
166 | call prtstr ;Display error msg.\r | |
167 | jmp kermit\r | |
168 | \r | |
169 | ;\r | |
170 | ; New TRANSMIT routine - transmit a file, line by line, to a remote host\r | |
171 | ; waiting each time for one or more characters to be returned\r | |
172 | ; as a remote host prompt. It could be as simple as a CR or LF\r | |
173 | ; character. Repeat until the complete file has been sent, then\r | |
174 | ; close the transmitted file, and drop into the connect state so the\r | |
175 | ; user can tidy up at the host end.\r | |
176 | ;get the file to send, open it up, and read first sector from disk\r | |
177 | \r | |
178 | xmit1: lxi d,inms19 ; say we are send a file to the host\r | |
179 | call prtstr\r | |
180 | \r | |
181 | xra a\r | |
182 | sta repcnt ; clear the host prompt chars. counter \r | |
183 | sta starc ; clear star count\r | |
184 | ;[MF][12]Delete the following call to "inbuf" as the call to "getfil"\r | |
185 | ;[MF][12]above will have initialized counters and flags so that when\r | |
186 | ;[MF][12]"in1chr" is called, "inbuf" will be called immediately and will\r | |
187 | ;[MF][12]immediately read from disk. Counters and flags will then be\r | |
188 | ;[MF][12]properly set up to read all characters of the file to be\r | |
189 | ;[MF][12]transmitted.\r | |
190 | ; call inbuf ; read one sector from disk\r | |
191 | ; jmp xmtex ; exit if error\r | |
192 | \r | |
193 | \r | |
194 | xmt10: xra a ; clear retransmit flag and count etc\r | |
195 | sta rexbfl ; retransmit flag (1=> retransmit)\r | |
196 | sta rexcnt ; character counter\r | |
197 | \r | |
198 | xmt1: call xmt1ch ; send a character\r | |
199 | ani 7fh ; strip any parity\r | |
200 | cpi cr ; have we reached the end of the line\r | |
201 | jnz xmt1 ; nope, loop around again\r | |
202 | \r | |
203 | ; Now wait for a string back from the host. Compare with STRING buffer\r | |
204 | ;\r | |
205 | xra a ; clear the character count\r | |
206 | sta rexcnt\r | |
207 | ;\r | |
208 | call selcon ; sent a line, send a star to console\r | |
209 | mvi e,'*'\r | |
210 | call outcon\r | |
211 | lda starc ; update star count\r | |
212 | inr a\r | |
213 | sta starc\r | |
214 | cpi 60 ; sent 60 stars?\r | |
215 | jnz xmt1a ; nope...\r | |
216 | xra a\r | |
217 | sta starc\r | |
218 | call prcrlf\r | |
219 | xmt1a:\r | |
220 | \r | |
221 | xmt3: lda eoflag ; have we hit end of file?\r | |
222 | ana a\r | |
223 | jnz xmtex ; yup, so quit.\r | |
224 | xra a\r | |
225 | sta repcnt ; clear the host prompt chars.counter\r | |
226 | xmt2: call rd1chl ; read a character from the line\r | |
227 | ani 7fh ; set flags\r | |
228 | jnz xmt4 ; Not zero => we have a character from host\r | |
229 | call ckchr ; see if *WE* have a character from console\r | |
230 | push psw ; restore to modem\r | |
231 | call selmdm\r | |
232 | pop psw\r | |
233 | ani 7fh ; stip parity (should not be there)\r | |
234 | jnz xmt2a ; if a null, try again\r | |
235 | lda strcnt ; if the string length is zero, dont wait.\r | |
236 | ana a\r | |
237 | jz xmt1 ; so loop back again\r | |
238 | jmp xmt4 ; else test for xon/off and incomming string\r | |
239 | \r | |
240 | xmt2a: cpi cntlc ; do we want to abort?\r | |
241 | jz xmtex ; in which case drop through to connect mode\r | |
242 | cpi cntlz ; if control z exit back to command loop\r | |
243 | jnz xmt2b ; else try for other characters\r | |
244 | lxi d,fcb ; close file before exiting to command loop\r | |
245 | mvi c,closf\r | |
246 | call bdos\r | |
247 | jmp kermit\r | |
248 | \r | |
249 | xmt2b: cpi cr ; a cr => resend last line\r | |
250 | jnz xmt2 ; nope, then ignore it\r | |
251 | mvi a,1\r | |
252 | sta rexbfl ; else we want to resend the line.\r | |
253 | jmp xmt1\r | |
254 | \r | |
255 | xmt4: jmp xmt6 ; skit xoff test for now...*****************\r | |
256 | \r | |
257 | cpi xoff ; xoff from host?\r | |
258 | jnz xmt6\r | |
259 | xmt5: call rd1chl ; else see if XOFF comming\r | |
260 | ani 7fh\r | |
261 | jnz xmt6 ; assume an xoff\r | |
262 | call ckchr ; anything at console?\r | |
263 | push psw\r | |
264 | call selmdm\r | |
265 | pop psw\r | |
266 | ani 7fh\r | |
267 | cpi cntlc ; control-c == abort & play terminal\r | |
268 | jz xmtex\r | |
269 | ana a ; anything else?\r | |
270 | jz xmt5 ;loop again\r | |
271 | \r | |
272 | xmt6: mov e,a ; save it for a while\r | |
273 | lda repcnt ; see if this character matches with one in buffer\r | |
274 | lxi h,stbuff ; point to string buffer\r | |
275 | add l ; make hl = hl + a\r | |
276 | mov l,a\r | |
277 | mvi a,0\r | |
278 | adc h\r | |
279 | mov h,a ; not using xra, as that clears the Carry flag\r | |
280 | mov a,e ; get the character back again\r | |
281 | cmp m ; is it = to what we expect?\r | |
282 | jnz xmt3 ; no, clear counter and try again\r | |
283 | lda repcnt ; yes, then update the pointer, and ...\r | |
284 | inr a ; ... see if we have received all ...\r | |
285 | sta repcnt ; ... we should have received\r | |
286 | mov e,a ; save length into E again\r | |
287 | lda strcnt ; get the length to compare\r | |
288 | sub e ; if (e) > string length, we have it\r | |
289 | jz xmt10 ; so send next line (clear counters etc)\r | |
290 | jmp xmt2 ; else wait for a little longer\r | |
291 | \r | |
292 | \r | |
293 | ;\r | |
294 | ; Routine below sends a character to the line. It sends up to a CR, and then\r | |
295 | ; it waits for a reply. This routine is called from xmt1, so if at \r | |
296 | ; end of file, return. Then XMT1 will drop through\r | |
297 | ; to connect.\r | |
298 | xmt1ch: ; send a character from the xmtbuf to the line\r | |
299 | call selmdm ; just in case it uses it\r | |
300 | lda eoflag ; have we hit end of file\r | |
301 | ana a ; set flags\r | |
302 | jnz xmt1c1 ; no, so dont...\r | |
303 | mvi a,cr ; load up a carriage return\r | |
304 | xmt1c1: call get1xc ; get the character to send\r | |
305 | cpi lf ; dont send line feeds\r | |
306 | ; jz xmt1c1\r | |
307 | cpi cntlz ; if control z, then we are at end of the file\r | |
308 | jz xmtex ; so close the file and drop into telcon\r | |
309 | cpi 20h ; control character?\r | |
310 | jp xmt11 ; no, so ok\r | |
311 | cpi cr ; cr, and tabs ok to send\r | |
312 | jz xmt11\r | |
313 | cpi tab\r | |
314 | jz xmt11\r | |
315 | jmp xmt1c1 ; else try for another character\r | |
316 | \r | |
317 | xmt11: call setpar ; else set parity etc\r | |
318 | push psw ; we want to keep this for a while\r | |
319 | mov e,a ; we need character in e\r | |
320 | call outmdm\r | |
321 | pop psw ; restore the character we sent\r | |
322 | mov e,a ; now, if a TAC is set on..\r | |
323 | lda tacflg\r | |
324 | ana a \r | |
325 | mov a,e ; (return must have sent character in a)\r | |
326 | jz xmt1c2 ; test for xon/off\r | |
327 | lda tacchr ;... get the tac character\r | |
328 | cmp e ; do we send it again?\r | |
329 | jnz xmt1c2 ; test for xon/off\r | |
330 | push psw ; save character for return. Already set E...\r | |
331 | call outmdm\r | |
332 | pop psw\r | |
333 | \r | |
334 | xmt1c2: ret\r | |
335 | \r | |
336 | get1xc: ; get a character from the sector or re-transmit buffer read \r | |
337 | ; into a. Read a new sector if we run out.\r | |
338 | ;\r | |
339 | ; First, see if we do a retransmit\r | |
340 | lda rexbfl\r | |
341 | ana a ; if zero, a genuine line\r | |
342 | jz get1x1\r | |
343 | ; have to retransmit a line\r | |
344 | lxi h,rexbuf\r | |
345 | lda rexcnt ; add counter to buffer base\r | |
346 | mvi d,0\r | |
347 | mov e,a\r | |
348 | dad d\r | |
349 | inr a ; update pointer\r | |
350 | sta rexcnt\r | |
351 | mov a,m ; get next character to send\r | |
352 | ret ; and exit\r | |
353 | \r | |
354 | get1x1: call in1chr ; get a character from the file. \r | |
355 | mov c,a ; save it to the retransmit buffer\r | |
356 | lda rexcnt\r | |
357 | mov e,a\r | |
358 | mvi d,0\r | |
359 | lxi h,rexbuf\r | |
360 | dad d ; point to next position\r | |
361 | inr a\r | |
362 | sta rexcnt ; update the character pointer\r | |
363 | mov a,c ; restore character to a\r | |
364 | mov m,c ; get character to c\r | |
365 | ret\r | |
366 | \r | |
367 | \r | |
368 | \r | |
369 | ; read a character from the line.\r | |
370 | rd1chl: \r | |
371 | call selmdm ; select the modem\r | |
372 | call inpmdm ; get input from the modem\r | |
373 | ani 7fh ; strip parity\r | |
374 | ; may UPPERCASE-ify if case sensitivity off\r | |
375 | ret ; return to caller\r | |
376 | \r | |
377 | ; End of transmit routine. Close input file name, and say we are dropping\r | |
378 | ; throught to telnet. Note that if eof not found, it is assumed that\r | |
379 | ; this is the ABORT exit.\r | |
380 | \r | |
381 | xmtex:\r | |
382 | lxi d,fcb ; close the transmitted file\r | |
383 | mvi c,closf\r | |
384 | call bdos\r | |
385 | call selcon ; make sure we are talking to the console\r | |
386 | \r | |
387 | lda eoflag ; end of file or abort exit?\r | |
388 | lxi d,inms22 ; assume eof...\r | |
389 | ana a\r | |
390 | jz xmtex1\r | |
391 | lxi d,inms29 ; we were wrong, its an abort.\r | |
392 | xmtex1: jmp telnt1 ; and drop through to connect mode\r | |
393 | ; telnet does the printing\r | |
394 | \r | |
395 | \r | |
396 | \r | |
397 | ;\f\r | |
398 | ; telnet - the CONNECT command.\r | |
399 | ; here from: kermit\r | |
400 | ; telnt1 - entry to connect mode from TRANSMIT command\r | |
401 | ; here from: xend\r | |
402 | \r | |
403 | telnet: call cfmcmd\r | |
404 | lxi d,infms7 ;Output start of message\r | |
405 | ; enter here from TRANSMIT command.\r | |
406 | telnt1: call prtstr\r | |
407 | call escpr ;Print the escape char.\r | |
408 | lxi d,infms8 ;Output some more of the message\r | |
409 | call prtstr\r | |
410 | call escpr ;Print the escape char again.\r | |
411 | lxi d,inms8a ;Print the remainder of the message\r | |
412 | call prtstr\r | |
413 | call syscon ;do system-dependent stuff\r | |
414 | lda logflg ;[pcc005] Want a log?\r | |
415 | ora a ;[pcc005]\r | |
416 | cnz logopn ;[pcc005] Open if so\r | |
417 | \r | |
418 | chrlup: call prtchr ;See if char at port (send to console).\r | |
419 | call conchr ;See if char at console (send to port).\r | |
420 | jmp kermit ;requested to end session - go to command loop.\r | |
421 | jmp chrlup ;Go do it again.\r | |
422 | ;\f\r | |
423 | ;\r | |
424 | ; prtchr - copy characters from comm line to console\r | |
425 | ; returns: nonskip, console selected.\r | |
426 | ; called by: xnext, rexmit, telnet\r | |
427 | ;\r | |
428 | \r | |
429 | prtchr: call selmdm ; select modem port\r | |
430 | call inpmdm ; try to get a character from it\r | |
431 | push psw ; restore to console\r | |
432 | call selcon ; select console\r | |
433 | pop psw ; restore the (possible character) read\r | |
434 | ora a ; test character\r | |
435 | jnz prtch0 ; if non-zero, process it.\r | |
436 | sta prtcnt ;[pcc008] zero out prt fairness count\r | |
437 | ret ; return.\r | |
438 | \r | |
439 | prtch0: ani 7FH ; drop parity bit.\r | |
440 | sta comchr ;[6] save it in case we need it again\r | |
441 | lda vtflg ;[9] get the vt52 emulation flag\r | |
442 | cpi vtdefe ;[9] are we doing external emulation?\r | |
443 | lda comchr ;[9] collect character again\r | |
444 | jz extern ;[9] jup, go do it.\r | |
445 | \r | |
446 | ana a ; set flags. it may be a null\r | |
447 | jz prtchr ; ignore null (filler)\r | |
448 | cpi del ; ignore delete, too\r | |
449 | jz prtchr\r | |
450 | cpi xon ;Is it an XON?\r | |
451 | jz prtxon ;yes\r | |
452 | cpi xoff ;Is it an XOFF?\r | |
453 | jz prtxof ;yes\r | |
454 | mov e,a ;Set the char aside.\r | |
455 | lda vtflg ;Get the VT52 emulation flag.\r | |
456 | cpi vtdefv ;Is the flag set for VT52 (ie 1)\r | |
457 | ;0 = none\r | |
458 | ;1 = VT52\r | |
459 | ;2 = external\r | |
460 | ;3 = dumb (traps non printing chars)\r | |
461 | ;0ffh not possible by local code (Will change)\r | |
462 | jnz prtch1 ;If not, don't do this stuff.\r | |
463 | lda escflg ;Get the escape flag.\r | |
464 | ora a ;Are we working on an escape sequence?\r | |
465 | jz prtch2 ;If not, continue.\r | |
466 | call vt52 ;If so, work on it some more\r | |
467 | jmp prtchr ;try for more characters.\r | |
468 | \r | |
469 | prtch2: mov a,e ;normal text.\r | |
470 | cpi esc ;Is the char an escape?\r | |
471 | jnz prtch1 ;If not skip on.\r | |
472 | mvi a,1\r | |
473 | sta escflg ;Set the escape flag: escape seen.\r | |
474 | jmp prtchr ;Get another char...\r | |
475 | \r | |
476 | prtch1: cpi vtdefe ; are we doing external emulation?\r | |
477 | jnz prtch3 ; assume we continue on\r | |
478 | lxi h,extern+1 ; get address of external emulator\r | |
479 | mov a,h ; se if address = 0 (not implemented)\r | |
480 | ora l\r | |
481 | jz prtch3 ; not external, assume we just carry on\r | |
482 | pchl ; go do external emulation. RET back to caller\r | |
483 | \r | |
484 | prtch3: cpi vtdefd ; are we trapping all non printing characters?\r | |
485 | jnz prtch4 ; nope, something else\r | |
486 | lda comchr ; Dumb terminal. Lets test the character\r | |
487 | cpi cr ; cr then ok\r | |
488 | jz prtch4 ; its ok\r | |
489 | cpi lf ; lf then ok\r | |
490 | jz prtch4\r | |
491 | cpi tab\r | |
492 | jz prtch4 ; assume tabs are expanded\r | |
493 | cpi space ; if less than 20H ignore it\r | |
494 | rm ; return if a control character\r | |
495 | \r | |
496 | prtch4: call sysflt ; ok to print this character (in E)?\r | |
497 | ora a\r | |
498 | jz prtchr ; no, skip it.\r | |
499 | lda logflg ;Get the log flag.\r | |
500 | cpi 81H ;[pcc003] Are we logging\r | |
501 | cz logit ;[pcc003] Do so if needed\r | |
502 | call selcon ; select console\r | |
503 | lda prnflg ;Get Print parallel flag\r | |
504 | ora a\r | |
505 | cnz outlpt ; output to printer if flag set\r | |
506 | call outcon ; output to console.\r | |
507 | lxi h,prtcnt ;[pcc008] point to prt fairness count\r | |
508 | inr m ;[pcc008] bump\r | |
509 | mov a,m ;[pcc008] get it in a\r | |
510 | cpi prfair+1 ;[pcc008] time to be fair?\r | |
511 | jm prtchr ;[pcc008] no, go around again.\r | |
512 | mvi m,0 ;[pcc008] reset count\r | |
513 | lda comchr ;[6] restore that character read from comm line\r | |
514 | ret ;[pcc008] and return\r | |
515 | \r | |
516 | ; I don't think we want to print xon/xoff - this should be\r | |
517 | ; flow control only across the link between us and the host.\r | |
518 | ; (besides, IBM host xon's don't make sense to most micros)\r | |
519 | ; remember xon/xoff state in xofflg (zero = xon, non-zero = xoff)\r | |
520 | prtxon: xra a ;Yes, reset XOFF flag\r | |
521 | prtxof: sta xofflg\r | |
522 | jmp prtchr ; look for another character\r | |
523 | ;\f;[pcc005] Log file routines\r | |
524 | \r | |
525 | ;[pcc005]\r | |
526 | ; logopn - open the log file\r | |
527 | ; Open the log file and append to it if it already exists\r | |
528 | ; or create one if not.\r | |
529 | \r | |
530 | logopn: \r | |
531 | mvi a,ctrlz ;[9] ignore control-z in log files\r | |
532 | cmp e ;[9] well, was it?\r | |
533 | rz ;[9] yes, to ignore it.\r | |
534 | lxi h,lognam ;[pcc012] copy name\r | |
535 | lxi d,fcb ;[pcc012] to fcb\r | |
536 | lxi b,12 ;[pcc012] 12 bytes\r | |
537 | call mover ;[pcc012] copy it\r | |
538 | call appfil ;[pcc012] open file for appending\r | |
539 | jmp logerr ;[pcc012] error\r | |
540 | lxi h,logflg ;[pcc005] point to log flag\r | |
541 | mvi a,80H ;[pcc005] file open flag\r | |
542 | ora m ;[pcc005] or in contents of logflg\r | |
543 | mov m,a ;[pcc005] and store back\r | |
544 | lxi d,inms28 ;[pcc005] assume logging is on\r | |
545 | cpi 81H ;[pcc005] check\r | |
546 | jz prtstr ;[pcc005] print msg if true\r | |
547 | lxi d,inms27 ;[pcc005] no, must be suspended\r | |
548 | jmp prtstr ;[pcc005] print and return\r | |
549 | \r | |
550 | ;\r | |
551 | ; logit - output character in E to log file.\r | |
552 | ; we assume the host recognizes xon/xoff. (we probably shouldn't)\r | |
553 | ; modem port is selected.\r | |
554 | ; preserves de\r | |
555 | ; called by: prtchr\r | |
556 | \r | |
557 | logit: lxi h,chrcnt ;[pcc012] point to buffer count\r | |
558 | dcr m ;[pcc012] and decrement\r | |
559 | jp logit1 ;[pcc012] continue if ok\r | |
560 | push d ;[pcc012] save de\r | |
561 | call outadv ;[pcc012] advance buffer if in memory\r | |
562 | call logwrt ;[pcc012] sigh, time to write to disk\r | |
563 | pop d ;[pcc012] restore de\r | |
564 | lda logflg ;[pcc012] get logging flag\r | |
565 | ora a ;[pcc012] Did we quit because of an error\r | |
566 | rz ;[pcc012] return now if so\r | |
567 | logit1: lhld bufpnt ;[pcc012] get buffer pointer\r | |
568 | mov m,e ;Store the char.\r | |
569 | inx h\r | |
570 | shld bufpnt\r | |
571 | ret ;[pcc012] and return\r | |
572 | \r | |
573 | ;[pcc012]\r | |
574 | ; logwrt - write to log file with XON/XOFF since it may take a while.\r | |
575 | \r | |
576 | logwrt: call sndxoff ;[7] send and xoff to host\r | |
577 | call outbuf ;[pcc012] output the buffer and advance\r | |
578 | call logerr ;[pcc005] quit if error\r | |
579 | call sndxon ;[send an xon to host\r | |
580 | ret ;[pcc012]\r | |
581 | \r | |
582 | ;[pcc005]\r | |
583 | ; logcls - Close the log file and reset the flag\r | |
584 | \r | |
585 | logcls: lxi d,infms6 ;[pcc005] Tell user we are closing file.\r | |
586 | call prtstr ;[pcc005]\r | |
587 | call clofil ;[pcc012] and do it\r | |
588 | jmp logerr ;[pcc005] jump if error\r | |
589 | lxi h,logflg ;[pcc005] point to flag\r | |
590 | mov a,m ;[pcc005] get it\r | |
591 | ani 7FH ;[pcc005] clear the open bit\r | |
592 | mov m,a ;[pcc005] and store back\r | |
593 | ret ;[pcc005]\r | |
594 | \r | |
595 | ;[pcc005]\r | |
596 | ; logerr - here on a variety of logging errors\r | |
597 | ; just close the file and disable logging\r | |
598 | ; called from logopn,logptr,logcls\r | |
599 | \r | |
600 | logerr: lxi d,erms22 ;[pcc005] Error message\r | |
601 | call prtstr ;[pcc005] print it\r | |
602 | mvi c,closf ;[pcc005] Close the file.\r | |
603 | lxi d,fcb ;[pcc012]\r | |
604 | call bdos ;[pcc005] \r | |
605 | xra a ;[pcc005] clear logflg\r | |
606 | sta logflg ;[pcc005] so don't try again\r | |
607 | ret ;[pcc005]\r | |
608 | ;\f\r | |
609 | ;\r | |
610 | ; VT52 emulation.\r | |
611 | ; called by: prtchr\r | |
612 | ; A/ contents of escflg (guaranteed non-zero)\r | |
613 | ; E/ current character\r | |
614 | ; modem is selected.\r | |
615 | ;\r | |
616 | vt52: cpi 1 ; first character after escape?\r | |
617 | jnz vt52y ; no, must be doing cursor positioning.\r | |
618 | ;\r | |
619 | ; E contains the character that followed the escape.\r | |
620 | ; valid characters are:\r | |
621 | ; A - cursor up\r | |
622 | ; B - cursor down\r | |
623 | ; C - cursor right\r | |
624 | ; D - cursor left\r | |
625 | ; F - enter graphics mode (hard to do on a non-vt52)\r | |
626 | ; G - exit graphics mode\r | |
627 | ; H - home\r | |
628 | ; I - reverse linefeed\r | |
629 | ; J - erase to end of screen\r | |
630 | ; K - erase to end of line\r | |
631 | ; Y - cursor positioning leadin\r | |
632 | ; Z - identify terminal as VT52\r | |
633 | ; [ - enter hold-screen mode (not supported)\r | |
634 | ; \ - exit hold-screen mode (not supported)\r | |
635 | ; > - enter alternate-keypad mode? (not supported)\r | |
636 | ; = - exit alternate-keypad mode? (not supported)\r | |
637 | ;\r | |
638 | ; Invalid sequences are handled as the VT52 does - the escape and\r | |
639 | ; the following character are swallowed, never to be seen again.\r | |
640 | ; For <esc>E, the translation table may contain just '$' (no action),\r | |
641 | ; or may be used as clear-and-home, as in the Heath/Zenith H19.\r | |
642 | ;\r | |
643 | mov a,e ; get the second character of the sequence.\r | |
644 | cpi 'Y' ; if cursor lead-in handle it.\r | |
645 | jnz vt52a ; if not, go on.\r | |
646 | mvi a,2 ; state = 2: row follows.\r | |
647 | sta escflg ; update the flag.\r | |
648 | ret ; back for another character\r | |
649 | \r | |
650 | vt52a: cpi 'Z' ; VT52 ID query?\r | |
651 | jz vt52id ; yes. claim to be one.\r | |
652 | cpi 'A' ;Less than an 'A'?\r | |
653 | jm vtig ;Yes - ignore.\r | |
654 | cpi 'K'+1 ;Greater than 'K'?\r | |
655 | jp vtig ;Yes - ignore.\r | |
656 | sui 'A' ;Else make into index.\r | |
657 | rlc ;Multiply by four.\r | |
658 | rlc ;(Shift left twice.)\r | |
659 | lhld pttab ;Load base addr of table.\r | |
660 | mov e,a ;Move a into de pair.\r | |
661 | mvi d,00H ;Zero out high byte.\r | |
662 | dad d ;Double add index+offset.\r | |
663 | xchg ;Exchange de with hl.\r | |
664 | call selcon ; select console\r | |
665 | call prtstr ;and syscall.\r | |
666 | vtig: ;Ignore escape sequence.\r | |
667 | xra a ;Reset the ol' escape flag.\r | |
668 | sta escflg\r | |
669 | ret ;Return home.\r | |
670 | \r | |
671 | ; here for <esc>Z. Tell the host we're a VT52. (Sure we are...)\r | |
672 | vt52id: mvi a,esc ; response is escape...\r | |
673 | call setpar ; (need correct parity)\r | |
674 | mov e,a\r | |
675 | call outmdm ; (console already selected)\r | |
676 | mvi a,'/' ; ... slash ...\r | |
677 | call setpar ; (with parity)\r | |
678 | mov e,a\r | |
679 | call outmdm\r | |
680 | mvi a,'K' ; ... K.\r | |
681 | call setpar\r | |
682 | mov e,a\r | |
683 | call outmdm\r | |
684 | jmp vtig ; clear escape-sequence flag and return.\r | |
685 | \r | |
686 | ; here when escflg isn't 0 or 1 - processing cursor positioning sequence.\r | |
687 | vt52y: cpi 2 ; looking for row? (y-coordinate)\r | |
688 | jnz vt52x ; no, must be column.\r | |
689 | mov a,e ; yes. get coordinate\r | |
690 | sui (' '-1) ; convert from ascii (1 = top line)\r | |
691 | sta vtyval ; store for later\r | |
692 | mvi a,3 ; advance to next state (x coord)\r | |
693 | sta escflg ; store it\r | |
694 | ret ; try for another character\r | |
695 | \r | |
696 | ; here when escflag isn't 0, 1, or 2 - it must be 3. (right?)\r | |
697 | ; E holds the last character of the cursor positioning sequence.\r | |
698 | vt52x: xra a ; end of escape sequence, reset state.\r | |
699 | sta escflg\r | |
700 | mov a,e ; get column (' ' is left margin)\r | |
701 | sui (' '-1) ; make left margin be one\r | |
702 | mov c,a ; stash column in c\r | |
703 | lda vtyval ; get row number\r | |
704 | mov b,a ; in b\r | |
705 | call selcon ; select console\r | |
706 | call csrpos ; call system-dependent cursor positioner\r | |
707 | ret ; all through.\r | |
708 | ;\f\r | |
709 | ;\r | |
710 | ; conchr - copy character from console to comm line, processing\r | |
711 | ; (kermit's) escape sequences.\r | |
712 | ; Enter and exit with console selected.\r | |
713 | ; nonskip return: transparent mode terminated.\r | |
714 | ; skip return: still in transparent mode.\r | |
715 | ; called by: rexmit, telnet\r | |
716 | \r | |
717 | conchr: call inpcon ;Try to get a character from the console\r | |
718 | ani 07FH ;Keep only 7 bits\r | |
719 | jz rskp ;Null means nothing there.\r | |
720 | mov e,a ;Move the char for comparison.\r | |
721 | sta lstchr ;Save it\r | |
722 | lda escchr ;Get the escape char.\r | |
723 | cmp e ;Is it an escape char?\r | |
724 | jz intchr ;If so go process it.\r | |
725 | call selmdm ; select the modem\r | |
726 | mov a,e ;Get the char.\r | |
727 | call setpar ;Set parity (if any).\r | |
728 | mov e,a ;Restore it.\r | |
729 | push d ; need to save e in case we are half dplx [5]\r | |
730 | call outmdm ;Output the char to the port.\r | |
731 | pop d ; Just in case we are half dplx [5]\r | |
732 | call selcon ; reselect console\r | |
733 | lda ecoflg ;Get the echo flag.\r | |
734 | ora a ;Is it turned on?\r | |
735 | jz rskp ;If not we're done here.\r | |
736 | mov a,e ;Get the char.\r | |
737 | ani 7FH ;Turn off the parity bit.\r | |
738 | mov e,a\r | |
739 | call outcon ; echo the character.\r | |
740 | jmp rskp ; use skip return\r | |
741 | ;\f\r | |
742 | ; transparent escape character has been typed. dispatch on second\r | |
743 | ; character. (console is still selected)\r | |
744 | ; here from: conchr\r | |
745 | \r | |
746 | intchr: call inpcon ; get another character from the console\r | |
747 | ora a ; zero means no character available yet.\r | |
748 | jz intchr ; If so, loop until we get a char.\r | |
749 | mov b,a ;Save the actual char.\r | |
750 | cpi ctrlc ;is it Control-C?\r | |
751 | jz contc ;yes\r | |
752 | ani 137O ;Convert to upper case.\r | |
753 | cpi 'C' ;Is it close?\r | |
754 | jnz intch0 ;If not proceed.\r | |
755 | contc: lxi d,infms9 ;Say we are back.\r | |
756 | call prtstr\r | |
757 | call syscls ; call system-dependent close routine\r | |
758 | lda logflg ;Get the log flag.\r | |
759 | ora a ;[pcc005] Check if open\r | |
760 | cm logcls ;[pcc005] Close if needed\r | |
761 | ret\r | |
762 | \r | |
763 | ;Here if not a 'C' or '^C'\r | |
764 | \r | |
765 | intch0: cpi 'S' ;Is it status?\r | |
766 | jnz inch01 ;If not, proceed.\r | |
767 | call stat01 ;Print out the status stuff.\r | |
768 | call prcrlf ;[pcc011] add a crlf\r | |
769 | jmp rskp ;return from conchr\r | |
770 | \r | |
771 | inch01:\r | |
772 | inch03: mov a,b ;Get the char.\r | |
773 | cpi '?' ;Is it a help request?\r | |
774 | jnz intch1 ;If not, go to the next check.\r | |
775 | inch3a: lda logflg ;[pcc003] Logging flag\r | |
776 | ora a ;[pcc003] see if active\r | |
777 | jp inch04 ;[pcc005] jump if no file open\r | |
778 | lxi d,loghlp ;[pcc003] yes, tell about R AND Q\r | |
779 | call prtstr ;[pcc003]\r | |
780 | inch04: lxi d,inthlp ;If so, get the address of the help message.\r | |
781 | call prtstr\r | |
782 | call sysinh ; print system-dependent help message\r | |
783 | lxi d,inhlp1 ; Tell about doubling the escape character\r | |
784 | call prtstr\r | |
785 | call escpr ;Print escape character\r | |
786 | lxi d,inhlp2 ;Print the rest\r | |
787 | call prtstr\r | |
788 | jmp intchr ;Get another char.\r | |
789 | \r | |
790 | intch1: mov a,b ;Get the character.\r | |
791 | cpi '0' ;Is it '0', to send a null?\r | |
792 | jnz intch3 ;No.\r | |
793 | xra a ;Yes, send an ASCII zero.\r | |
794 | call setpar ; with the correct parity\r | |
795 | mov e,a\r | |
796 | call selmdm ; (to the modem...)\r | |
797 | call outmdm\r | |
798 | call selcon ; return with console selected\r | |
799 | jmp rskp\r | |
800 | \r | |
801 | intch3: lda escchr ;Get the escape char.\r | |
802 | cmp b ;Is it the escape char?\r | |
803 | jnz intch4 ;[pcc002] jump if not\r | |
804 | mov a,b ;Get the char.\r | |
805 | call setpar\r | |
806 | mov e,a ;Restore it.\r | |
807 | call selmdm\r | |
808 | call outmdm ;Output it.\r | |
809 | call selcon ;We promised console would be selected...\r | |
810 | jmp rskp ;Return, we are done here.\r | |
811 | intch4: mov a,b ;[pcc002] get it again\r | |
812 | ani 137o ;[pcc002] in upper case\r | |
813 | cpi 'P' ;[pcc002] toggle printer?\r | |
814 | jnz intch5 ;[pcc003] nope\r | |
815 | lda prnflg ;[pcc002] get printer flag\r | |
816 | xri 01h ;[pcc002] complement it\r | |
817 | sta prnflg ;[pcc002] and put back\r | |
818 | jmp rskp ;[pcc002]\r | |
819 | intch5: lda logflg ;[pcc003] get log flag\r | |
820 | ora a ;[pcc003] See if open\r | |
821 | jp intch7 ;[pcc003] no, skip R and Q\r | |
822 | mov a,b ;[pcc003] get back chr\r | |
823 | ani 137o ;[pcc003] make upper case\r | |
824 | cpi 'R' ;[pcc003] Is it R\r | |
825 | jnz intch6 ;[pcc003] Jump if not\r | |
826 | mvi a,81H ;[pcc003] set flag for logging\r | |
827 | sta logflg ;[pcc003] put it back\r | |
828 | lxi d,inms28 ;[pcc003] message\r | |
829 | call prtstr ;[pcc003]\r | |
830 | jmp rskp ;[pcc003] done\r | |
831 | intch6: cpi 'Q' ;[pcc003] Quit logging?\r | |
832 | jnz intch7 ;[pcc003] no\r | |
833 | mvi a,82H ;[pcc003] flag for open, but suspended\r | |
834 | sta logflg ;[pcc003] store away\r | |
835 | lxi d,inms27 ;[pcc003] keep them informed\r | |
836 | call prtstr ;[pcc003]\r | |
837 | jmp rskp ;[pcc003]\r | |
838 | intch7: ;[pcc003]\r | |
839 | \r | |
840 | intchz: mov a,b ; not recognized. get saved copy back.\r | |
841 | push psw ;[8] save as we will want to test for 'D'\r | |
842 | call sysint ; interpret system-dependent sequences\r | |
843 | jmp intchy ; done. [10] Now see if D. If so, do a C.\r | |
844 | pop psw ;[10] tidy stack\r | |
845 | mvi e,'G'-100O ;Otherwise send a beep.\r | |
846 | call outcon ; to the console.\r | |
847 | jmp rskp\r | |
848 | \r | |
849 | intchy: pop psw ;[10] adjust stack\r | |
850 | ani 5fh ;[10] strip parity, make it upper case\r | |
851 | cpi 'D' ;[10] was it a D?\r | |
852 | jz contc ;[10] yup, so to the equivalent of an escape-C\r | |
853 | jmp rskp\r | |
854 | ;\f\r | |
855 | ; Little code to allow some expansion of code without changing\r | |
856 | ; every futher address, only up to the end of this file.\r | |
857 | ; TO BE REMOVED FOR RELEASE!\r | |
858 | \r | |
859 | ; org ($+100h) AND 0FF00H\r | |
860 | IF lasm\r | |
861 | LINK CPSCPM\r | |
862 | ENDIF;lasm\r |