]> cloudbase.mooo.com Git - kermit-80.git/blame - cpscmd.asm
Bugfix in outmdm (output buffer flush)
[kermit-80.git] / cpscmd.asm
CommitLineData
e58a7a25
L
1; CPSCMD.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;\r
20; This file provides a user oriented way of parsing commands.\r
21; It is similar to that of the COMND JSYS in TOPS-20.\r
22;\r
23; revision history (latest first):\r
24;\r
25;edit 13, 17-Jan-1991 by MF. Modified "cmifil" routine to zero the entire\r
26; fcb (not just the extent) to fix a bug in the COPY command which\r
27; prevented successive COPY commands from working properly.\r
28;edit 12, 16-Jan-1991 by MF. Modified routine "cmkeyw" to ignore leading\r
29; spaces/tabs before a keyword. This apparently was the intent in\r
30; "prompt" and "repars" (at least for command-lines) as the variable \r
31; "cmsflg "is set upon command parse and reparse. The intent was ,\r
32; subverted, however, as "cmkeyw" did not reset the flag to ignore\r
33; leading white space for each search thru the key tables (even though\r
34; the buffer pointer to the keyword entered was reset). The fix was\r
35; to reset the "spaces seen" flag (cmsflg) after "cmkey2" so that\r
36; it is reset each time a new table entry is compared to the text\r
37; the user has entered from the keyboard/TAKE-file etc. The upshot\r
38; of all this is that the kluge code in "cminbf" at "cminb0" designed\r
39; to force Kermit to ignore leading white space on command-lines in\r
40; TAKE-files and on the CP/M command-line is no longer needed and,\r
41; therefore, has been eliminated. Also modify "comnd" to expect leading\r
42; spaces for functions other than "get keyword".\r
43;edit 11, 26-Dec-1990 by MF. Modified routines to ignore leading white space\r
44; in lines from TAKE-files as well as during input from the CP/M\r
45; command-line (form-feeds are now considered white space under these\r
46; circumstances).\r
47;edit 10, 8-Sep-1990 by Mike Freeman. Modified routines to ignore leading\r
48; spaces/tabs when processing Kermit commands from the CP/M\r
49; command-line.\r
50; Added flag CMBFLG to allow initial word on a command-line\r
51; to be blank (useful for Remote commands such as Remote CWD etc).\r
52; Added flag cmqflg to prevent character-echoing while entering\r
53; commands so Remote CWD etc can have nonechoing password entry.\r
54; edit 9, 15 June, 1987 by OBSchou. Bug fixing to allow a second filename\r
55; (quiet) be entered as d:<blank>. Previous revision put the drive name \r
56; in first character of FCB, I put that character back to a space.\r
57;\r
58; edit 8, 12 June, 1987 by OBSchou. Addedin code in cmkeyw to print\r
59; 20 lines of help, then pause for a key from the user befor\r
60; proceeding with help.\r
61;\r
62; edit 7, 11 March, 1987 by OBSchou for Richard Russell, BBC. He writes:\r
63; Bug in cmtext which prevented use of octal characters (\nnn) fixed.\r
64;\r
65; edit 6, 18 June, 1986 by OBSchou, Loughborough University, Leics. UK\r
66; added code to parse a number from user input. Added check to make \r
67; sure the input command buffer does not overflow the limit.\r
68;\r
69; edit 5a: 7 March, 1986. OBSchou. Added stuff rom MJ Carter. He writes:\r
70; 7th May 85, MJ Carter [majoc], Nottingham University\r
71; Code in cmifil() put one too many spaces in the FCB; this caused \r
72; the BDOS of the British Micro Mimi to search for exteny 32,\r
73; rather than extent 0, so era() always said "can't find file"\r
74; Puttig a null at the point in question ought to fix 9 it.\r
75;\r
76; edit 5: 6-Feb-85 by Charles Carvalho\r
77; Make ffussy a runtime (rather than assembly-time) switch, to\r
78; eliminate conditional assembly in system-independent module.\r
79; Don't allow _%|()/\ in filenames if ffussy set; my CP/M manual\r
80; disallows those, too.\r
81;\r
82; edit 4: 13-Jan-85 by Vanya J.Cooper Pima Commun. College Tel: 602-884-6809\r
83;\r
84;pcc006 2-jan-85 VJC modules:cp4cmd,cp4utl\r
85; Problems with "?" in filespecs. On reparse, may cause action\r
86; flag to be reset at wrong point, requiring multiple <CR>'s\r
87; to terminate the line or other weird stuff. Also need to\r
88; check flag and complain if wild-cards illegal.\r
89\r
90;pcc007 2-Jan-85 vjc modules:cp4def,cp4cmd\r
91; Cmifil is too fussy about what characters to accept in a\r
92; filespec. My CP/M manual says any printable character is ok\r
93; except <>.,;:?*[], and lower case. In practice, even those work\r
94; sometimes. Kermit itself uses '&' if file warning is on,\r
95; and then won't let you reference the file. Allow all\r
96; printable characters except those above. Add conditional\r
97; ffussy, so that if not ffussy, all special characters will be\r
98; allowed, just convert lower to upper-case.\r
99\r
100; edit 3: July 8, 1984 (CJC)\r
101; integrate Toad Hall changes for LASM compatibility: CP4CPM is linked\r
102; by CP4WLD, and links CP4UTL.\r
103; \r
104; edit 2: June 5, 1984 (CJC)\r
105; formatting and documentation; delete unnecessary code at cminb7; add\r
106; module version string.\r
107;\r
108; edit 1: May, 1984 (CJC)\r
109; extracted from CPMBASE.M80 version 3.9; modifications are described in\r
110; the accompanying .UPD file.\r
111\r
112cmdver: db 'CPSCMD.ASM (13) 17-Jan-1991$' ; name, edit number, date\r
113\r
114; This routine prints the prompt in DE and specifies the reparse\r
115; address.\r
116; called by: kermit\r
117\r
118prompt: pop h ;Get the return address.\r
119 push h ;Put it on the stack again.\r
120 shld cmrprs ;Save it as the address to go to on reparse.\r
121 lxi h,0 ;Clear out hl pair.\r
122 dad sp ;Get the present stack pointer.\r
123 shld cmostp ;Save for later restoral.\r
124 xchg ;Save the pointer to the prompt.\r
125 shld cmprmp\r
126 xchg\r
127 lxi h,cmdbuf\r
128 shld cmcptr ;Initialize the command pointer.\r
129 shld cmdptr\r
130 xra a\r
131 sta cmaflg ;Zero the flags.\r
132 sta cmccnt\r
133; mvi a,0FFH ;Try it this way (Daphne.)\r
134; sta cmsflg\r
135 call prcrlf ;Print a CR/LF [Toad Hall]\r
136 jmp prprmp ;Print the prompt. [Toad Hall]\r
137;\f\r
138; This address is jumped to on reparse.\r
139; here from: cmcfrm, cmkeyw, cmifil, cminbf\r
140\r
141repars: lhld cmostp ;Get the old stack pointer.\r
142 sphl ;Make it the present one.\r
143 lxi h,cmdbuf\r
144 shld cmdptr\r
145; mvi a,0FFH ;Try it this way (Daphne.)\r
146; sta cmsflg\r
147 lhld cmrprs ;Get the reparse address.\r
148 pchl ;Go there.\r
149\r
150; This address can be jumped to on a parsing error.\r
151; here from: cmkeyw, cminbf\r
152\r
153prserr: lhld cmostp ;Get the old stack pointer.\r
154 sphl ;Make it the present one.\r
155 lxi h,cmdbuf\r
156 shld cmcptr ;Initialize the command pointer.\r
157 shld cmdptr\r
158 xra a\r
159 sta cmaflg ;Zero the flags.\r
160 sta cmccnt\r
161; mvi a,0FFH ;Try it this way (Daphne.)\r
162; sta cmsflg\r
163 call prcrlf ;Print a CR/LF [Toad Hall]\r
164 call prprmp ;Print the prompt [Toad Hall]\r
165;* Instead return to before the prompt call.\r
166 lhld cmrprs\r
167 pchl\r
168;\f\r
169; This routine parses the specified function in A. Any additional\r
170; information is in DE and HL.\r
171; Returns +1 on success\r
172; +4 on failure (assumes a JMP follows the call)\r
173; called by: log, setcom, read, send, xmit, dir, era, keycmd, cfmcmd\r
174; and CPSREM\r
175\r
176comnd: sta cmstat ;Save what we are presently parsing.\r
177 call cminbf ;Get chars until an action or a erase char.\r
178 push psw ;[MF]Save function\r
179 mvi a,0ffh ;[MF]Expect leading spaces\r
180 sta cmsflg ;[MF]...\r
181 pop psw ;[MF]Restore function\r
182 cpi cmcfm ;Parse a confirm?\r
183 jz cmcfrm ;Go get one.\r
184 cpi cmkey ;Parse a keyword?\r
185 jz cmkeyw ;Try and get one.\r
186 cpi cmifi ;Parse an input file spec?\r
187 jz cmifil ;Go get one.\r
188 cpi cmifin ;Input file-spec silent?\r
189 jz cmifil ;do as he wishes\r
190 cpi cmofi ;Output file spec?\r
191 jz cmofil ;Go get one.\r
192 cpi cmtxt ;Parse arbitrary text?\r
193 jz cmtext ;Go do it.\r
194 cpi cmnum ;[7] Parse a number?\r
195 jz cmnumb ;[7] go do it\r
196 lxi d,cmer00 ;"?Unrecognized COMND call"\r
197 call prtstr\r
198 ret\r
199;\f\r
200; This routine parses arbitrary text up to a CR.\r
201; Accepts DE: address to put text\r
202; Returns in A: number of chars in text (may be 0)\r
203; DE: updated pointer\r
204; called by: comnd\r
205\r
206cmtext: xra a ; clear counters erc for slashes etc\r
207 sta slshsn ; if we are in a slash sequence\r
208 sta slashn ; the octal number being entered\r
209 sta slashc ; number of characters entered\r
210\r
211 xchg ;Put the pointer to the dest in HL.\r
212 shld cmptab ;Save the pointer.\r
213 mvi b,0 ;Init the char count\r
214cmtxt1: call cmgtch ;Get a char.\r
215 ora a ;Terminator?\r
216 jp cmtx3 ;No, put in user space. [rtr] was cmtx5\r
217 ani 7FH ;Turn off minus bit.\r
218 cpi esc ;An escape?\r
219 jnz cmtxt2 ;No.\r
220 mvi c,conout\r
221 mvi e,bell ;Get a bell.\r
222 call bdos\r
223 xra a\r
224 sta cmaflg ;Turn off the action flag.\r
225 lhld cmcptr ;Move the pointer to before the escape.\r
226 dcx h\r
227 shld cmcptr\r
228 shld cmdptr\r
229 lxi h,cmccnt ;Get the char count.\r
230 dcr m ;Decrement it by one.\r
231 jmp cmtxt1 ;Try again.\r
232\r
233cmtxt2: cpi '?' ;Is it a question mark?\r
234 jz cmtxt4 ;If so put it in the text. [rtr] was cmtx3\r
235 cpi ff ;Is it a formfeed?\r
236 cz clrtop ;If so blank the screen.\r
237 mov a,b ;Return the count.\r
238 lhld cmptab ;Return updated pointer in HL.\r
239 xchg\r
240 jmp rskp ;Return success.\r
241\r
242cmtx3: cpi '\' ; slash?\r
243 jnz cmtx3a ; nope, so try something else\r
244 lda slshsn ; a slash already entered?\r
245 ana a\r
246 cma ;[rtr]\r
247 jnz cmtx3a ; yes, so assume its a valid slash to enter\r
248 sta slshsn ; make sure the flag is set for next time routnd\r
249 jmp cmtxt1 ; get another character\r
250\r
251cmtx3a:\r
252; lxi h,cmaflg ;Point to the action flag.\r
253; mvi m,0 ;Set it to zero.\r
254 mov e,a ; save it in case we are interpreting a slash\r
255 lda slshsn ; slash already entered?\r
256 ana a ; test flag\r
257 mov a,e ; restore it in case...\r
258 jz cmtx5 ; not a slash seen, so enter as a normal character\r
259 cpi '\'\r
260 jnz cmtx3b ; \\ not detected\r
261 lda slashn ; else get number\r
262 jmp cmtx5b ; and enter it ( in the case of \n or \nn)\r
263 ; here if an octal number of 1 or 2 digits\r
264 ; entered instead of 3, followed by \ again\r
265\r
266cmtx3b:\r
267 sui 30h ; else it should be an octal number\r
268 jm cmtxt6 ; if not a digit complain\r
269 cpi 8 ; ditto\r
270 jp cmtxt6 ;[rtr] was cmtxt\r
271 mov e,a ; else add it to the number already entered\r
272 lda slashn\r
273 add a\r
274 add a\r
275 add a ; multiply by 8\r
276 add e\r
277 sta slashn\r
278 lda slashc ; get the count\r
279 inr a\r
280 sta slashc ; plus one. If three then a number entered\r
281 cpi 3\r
282 lda slashn ; get the number in case...\r
283 jz cmtx5\r
284 jmp cmtxt1 ; else loop\r
285\r
286cmtxt4: lhld cmdptr ;[rtr] Get a pointer into the buffer\r
287 inx h ;[rtr] Bump past '?'\r
288 shld cmdptr ;[rtr]\r
289cmtx5: call cmtx5c\r
290 jmp cmtxt1 ; put this into a subroutine\r
291\r
292cmtx5b:\r
293 call cmtx5c ; here if we see \n\ or \nn\ rather than \nnn\\r
294 mvi a,'\' ; so send slash number to buffer, \r
295 sta slshsn ; re-store a slash seen\r
296 jmp cmtxt1 ; try next one\r
297\r
298cmtx5c:\r
299 inr b ;Increment the count.\r
300 lhld cmptab ;Get the pointer.\r
301 mov m,a ;Put the char in the array.\r
302 inx h\r
303 shld cmptab ;Save the updated pointer.\r
304 xra a ; clear slash counters etc\r
305 sta slashc\r
306 sta slashn\r
307 sta slshsn\r
308 ret ; and exit\r
309\r
310cmtxt6: lxi d,cmer05 ; complain - not a valid \ parameter\r
311 call prtstr\r
312 jmp kermit ; and try another command\r
313 ds 20h ; for debugging\r
314;\f\r
315; This routine gets a number from user input.\r
316; Called by: comnd\r
317;\r
318cmnumb: lxi h,0 ; make sure the number is zero to start with\r
319 shld number\r
320cmnum0: call cmgtch ; get another character\r
321 ora a ; if negative then its an action\r
322 jp cmnum1 ; nope, so (possibly) valid input\r
323 ani 7fh ; else lets see what it is...\r
324 cpi esc ; do not know what to do with this one...\r
325 cpi ' ' ; if it is a space then either a return or more\r
326 jnz cmnum2 ; else\r
327 jmp rskp ; space is a deliminter\r
328 dw 0 ; set three bytes aside for a jump/call\r
329 dw 0 ; and then another three just in case...\r
330 dw 0 ; making 6 bytes\r
331cmnum2: cpi '?' ; user is curious\r
332 jz gnum2\r
333 cpi cr ; end of input?\r
334 jz cmnumx\r
335gnum1: jmp prserr ; did not under stand this, so error\r
336cmnumx: dw 0\r
337 dw 0\r
338 jmp rskp ; return ok\r
339\r
340gnum2: lhld number ; get the number.. if at all entered\r
341 mov a,l\r
342 ora h ; if hl = 0 then possibly no number entered\r
343 lxi d,cmin02 ; say confirm...or more on line\r
344 jnz gnum21 ; else say enter a return\r
345 lxi d,cmin01 ; say enter a number\r
346gnum21: call prtstr ; say it\r
347 call prcrlf ; do a lf\r
348 call prprmp ; another reprompt\r
349 lhld cmdptr ; get pointer of string already entered\r
350 mvi m,'$' ; dollar it to set end of line\r
351 lhld cmcptr\r
352 dcx h ; decrement and save the buffer pointer\r
353 shld cmcptr\r
354 lxi d,cmdbuf\r
355 call prtstr ; print what has already been entered\r
356 xra a\r
357 sta cmaflg ; turn the action flag off\r
358 jmp repars ; and try again\r
359\r
360 mvi a,cmcfm ; parse a confirm\r
361dw 0\r
362dw 0\r
363dw 0\r
364dw 0\r
365dw 0 ; some space to patch...\r
366dw 0\r
367\r
368cmnum1: ani 7fh ; here for a (potentially) valid number\r
369 sui '0' ; less ascii bias\r
370 jc gnum3\r
371 cpi 10 ; if 10 or more its still bad\r
372 jnc gnum3\r
373 cmc\r
374 lhld number ; now multiply number by ten and add the new value\r
375 push h\r
376 pop d\r
377 dad h ; hl = hl * 2\r
378 dad h ; * 4\r
379 dad d ; * 5\r
380 dad h ; * 10\r
381 mvi d,0\r
382 mov e,a ; add de to hl...\r
383 dad d\r
384 shld number\r
385 jmp cmnum0\r
386;\r
387gnum3: lxi d,cmer04 ; invalid number...\r
388 call prtstr\r
389 jmp rskp\r
390;\r
391\r
392;\f\r
393; This routine gets a confirm.\r
394; called by: comnd\r
395\r
396cmcfrm: call cmgtch ;Get a char.\r
397 ora a ;Is it negative (a terminator;a space or\r
398 ;a tab will not be returned here as they\r
399 ;will be seen as leading white space.)\r
400 rp ;If not, return failure.\r
401 ani 7FH ;Turn off the minus bit.\r
402 cpi esc ;Is it an escape?\r
403 jnz cmcfr2\r
404 mvi c,conout\r
405 mvi e,bell ;Get a bell.\r
406 call bdos\r
407 xra a\r
408 sta cmaflg ;Turn off the action flag.\r
409 lhld cmcptr ;Move the pointer to before the escape.\r
410 dcx h\r
411 shld cmcptr\r
412 shld cmdptr\r
413 lxi h,cmccnt ;Get the char count.\r
414 dcr m ;Decrement it by one.\r
415 jmp cmcfrm ;Try again.\r
416\r
417cmcfr2: cpi '?' ;Curious?\r
418 jnz cmcfr3\r
419 lxi d,cmin00 ;Print something useful.\r
420 call prtstr\r
421 call prcrlf ;Print a crlf. [Toad Hall]\r
422 call prprmp ;Reprint the prompt [Toad Hall]\r
423 lhld cmdptr ;Get the pointer into the buffer.\r
424 mvi a,'$' ;Put a $ there for printing.\r
425 mov m,a\r
426 lhld cmcptr\r
427 dcx h ;Decrement and save the buffer pointer.\r
428 shld cmcptr\r
429 lxi d,cmdbuf\r
430 call prtstr\r
431 xra a ;Turn off the action flag.\r
432 sta cmaflg\r
433 jmp repars ;Reparse everything.\r
434\r
435cmcfr3: cpi ff ;Is it a form feed?\r
436 cz clrtop ;If so blank the screen.\r
437 jmp rskp\r
438;\f\r
439; This routine parses a keyword from the table pointed\r
440; to in DE. The format of the table is as follows:\r
441;\r
442; addr: db n ;Where n is the # of entries in the table.\r
443; db m ;M is the size of the keyword.\r
444; db 'string$' ;Where string is the keyword.\r
445; db a,b ;Where a & b are pieces of data\r
446; ;to be returned. (Must be two of them.)\r
447;\r
448; The keywords must be in alphabetical order.\r
449;**** Note: The data value a is returned in registers A and E. The\r
450;**** data value b is returned in register D. This allows the two data\r
451; bytes to be stored as:\r
452; dw xxx\r
453; and result in a correctly formatted 16-bit value in register pair\r
454; DE.\r
455; called by: comnd\r
456\r
457cmkeyw: shld cmhlp ;Save the help.\r
458 xchg ;Get the address of the table.\r
459 shld cmptab ;Save the beginning of keyword tab for '?'.\r
460 mov b,m ;Get the number of entries in the table.\r
461 inx h\r
462 shld cmkptr\r
463 lhld cmdptr ;Save the command pointer.\r
464 shld cmsptr\r
465cmkey2: mov a,b ;Get the number of entries left.\r
466 ora a ;Any left?\r
467 rz ;If not we failed.\r
468 mvi a,0ffh ;[MF]Make sure we ignore leading spaces\r
469 sta cmsflg ;[MF]...\r
470 lhld cmkptr\r
471 mov e,m ;Get the length of the keyword.\r
472 inx h\r
473cmkey3: dcr e ;Decrement the number of chars left.\r
474 mov a,e\r
475 cpi 0FFH ;Have we passed the end?\r
476 jm cmkey5 ;If so go to the next.\r
477 call cmgtch ;Get a char.\r
478 ora a ;Is it a terminator?\r
479 jp cmkey4 ;If positive, it is not.\r
480 ani 7FH ;Turn off the minus bit.\r
481 cpi '?'\r
482 jnz cmky31\r
483 xra a\r
484 sta cmaflg ;Turn off the action flag.\r
485 lxi h,cmccnt ;Decrement the char count.\r
486 dcr m\r
487;* Must go through the keyword table and print them.\r
488 lhld cmhlp ;For now print the help text.\r
489 xchg\r
490 call p20ln ;[8] print at most 20 lines then pause\r
491; call prtstr\r
492 call prcrlf ;Print a crlf [Toad Hall]\r
493 call prprmp ;Reprint the prompt [Toad Hall]\r
494 lhld cmdptr ;Get the pointer into the buffer.\r
495 mvi a,'$' ;Put a $ there for printing.\r
496 mov m,a\r
497 lhld cmcptr\r
498 dcx h ;Decrement and save the buffer pointer.\r
499 shld cmcptr\r
500 lxi d,cmdbuf\r
501 call prtstr\r
502 jmp repars ;Reparse everything.\r
503\r
504cmky31: cpi esc ;Is it an escape?\r
505 jnz cmky35\r
506 xra a\r
507 sta cmaflg ;Turn off the action flag.\r
508 push d\r
509 push b\r
510 push h\r
511 call cmambg\r
512 jmp cmky32 ;Not ambiguous.\r
513 mvi c,conout\r
514 mvi e,bell\r
515 call bdos ;Ring the bell.\r
516 lhld cmcptr ;Move the pointer to before the escape.\r
517 dcx h\r
518 shld cmcptr\r
519 shld cmdptr\r
520 lxi h,cmccnt ;Get the char count.\r
521 dcr m ;Decrement it by one.\r
522 pop h\r
523 pop b\r
524 pop d\r
525 inr e ;Increment the left to parse char count.\r
526 jmp cmkey3\r
527\r
528cmky32: lhld cmcptr ;Pointer into buffer.\r
529 dcx h ;Backup to the escape.\r
530 xchg\r
531 pop h\r
532 push h\r
533cmky33: mov a,m ;Get the next char.\r
534 cpi '$' ;Finished?\r
535 jz cmky34\r
536 inx h\r
537 xchg\r
538 mov m,a ;Move it into the buffer.\r
539 inx h\r
540 xchg\r
541 lda cmccnt ;Increment the char count.\r
542 inr a\r
543 sta cmccnt\r
544 jmp cmky33\r
545\r
546cmky34: lda cmccnt ;Get the character count.\r
547 inr a ;Increment and save it.\r
548 sta cmccnt\r
549 xchg ;Put the command buffer pointer in HL.\r
550 mvi a,' ' ;Get a blank.\r
551 mov m,a ;Put it in the command buffer.\r
552 inx h ;Increment the pointer\r
553 shld cmcptr ;Save the updated pointer.\r
554 shld cmdptr\r
555 pop h\r
556 push h\r
557 xchg\r
558 call prtstr ;Print the rest of the keyword.\r
559 mvi c,conout\r
560 mvi e,' '\r
561 call bdos ;Print a blank.\r
562 pop h\r
563 pop b\r
564 pop d\r
565 jmp cmky37\r
566\r
567cmky35: push h\r
568 push d\r
569 call cmambg\r
570 jmp cmky36\r
571 lxi d,cmer01\r
572 call prtstr ;Say its ambiguous.\r
573 jmp prserr ;Give up.\r
574\r
575cmky36: pop d\r
576 pop h\r
577cmky37: inr e ;Add one incase it is negative.\r
578 mvi d,0\r
579 dad d ;Increment past the keyword.\r
580 inx h ;Past the $.\r
581 mov e,m ;Get the data.\r
582 inx h\r
583 mov d,m\r
584 mov a,e\r
585 jmp rskp\r
586\r
587cmkey4: cpi 'a' ;Is it less than a?\r
588 jm cmky41 ;If so don't capitalize it.\r
589 cpi 'z'+1 ;Is it more than z?\r
590 jp cmky41 ;If so don't capitalize it.\r
591 ani 137O ;Capitalize it.\r
592cmky41: mov d,m ;Get the next char of the keyword.\r
593 inx h\r
594 cmp d ;Match?\r
595 jz cmkey3 ;If so get the next letter.\r
596\r
597cmkey5: mvi d,0\r
598 mov a,e ;Get the number of chars left.\r
599 ora a ;Is it negative?\r
600 jp cmky51\r
601 mvi d,0FFH ;If so, sign extend.\r
602cmky51: dad d ;Increment past the keyword.\r
603 lxi d,0003H ;Plus the $ and data.\r
604 dad d\r
605 shld cmkptr\r
606 dcr b ;Decrement the number of entries left.\r
607 lhld cmsptr ;Get the old cmdptr.\r
608 shld cmdptr ;Restore it.\r
609;* check so we don't pass it.\r
610 jmp cmkey2 ;Go check the next keyword.\r
611;\f\r
612; Test keyword for ambiguity.\r
613; returns: nonskip if ambiguous, skip if OK.\r
614; called by: cmkeyw\r
615\r
616cmambg: dcr b ;Decrement the number of entries left.\r
617 rm ;If none left then it is not ambiguous.\r
618 inr e ;This is off by one;adjust.\r
619 mov c,e ;Save the char count.\r
620 mov a,e\r
621 ora a ;Any chars left?\r
622 rz ;No, it can't be ambiguous.\r
623 mvi d,0\r
624 dad d ;Increment past the keyword.\r
625 mvi e,3 ;Plus the $ and data.\r
626 dad d\r
627 mov b,m ;Get the length of the keyword.\r
628 inx h\r
629 xchg\r
630 lhld cmkptr ;Get pointer to keyword entry.\r
631 mov a,m ;Get the length of the keyword.\r
632 sub c ;Subtract how many left.\r
633 mov c,a ;Save the count.\r
634 cmp b\r
635 jz cmamb0\r
636 rp ;If larger than the new word then not amb.\r
637cmamb0: lhld cmsptr ;Get the pointer to what parsed.\r
638cmamb1: dcr c ;Decrement the count.\r
639 jm rskp ;If we are done then it is ambiguous.\r
640 xchg ;Exchange the pointers.\r
641 mov b,m ;Get the next char of the keyword\r
642 inx h\r
643 xchg ;Exchange the pointers.\r
644 mov a,m ;Get the next parsed char.\r
645 inx h\r
646 cpi 'a' ;Is it less than a?\r
647 jm cmamb2 ;If so don't capitalize it.\r
648 cpi 'z'+1 ;Is it more than z?\r
649 jp cmamb2 ;If so don't capitalize it.\r
650 ani 137O\r
651cmamb2: cmp b ;Are they equal?\r
652 rnz ;If not then its not ambiguous.\r
653 jmp cmamb1 ;Check the next char.\r
654;\f\r
655; cmofil - parse output filespec\r
656; cmifil - parse input filespec\r
657; here from: comnd\r
658\r
659cmofil: mvi a,0 ;Don't allow wildcards.\r
660; jmp cmifil ;For now, the same as CMIFI.\r
661cmifil: sta cmfwld ;Set wildcard flag\r
662 xchg ;Get the fcb address.\r
663 shld cmfcb ;Save it.\r
664 mvi e,0 ;Initialize char count.\r
665 mvi m,0 ;Set the drive to default to current.\r
666 inx h\r
667 shld cmfcb2\r
668 xra a ;Initialize counter.\r
669cmifi0: mvi m,' ' ;Blank the FCB.\r
670 inx h\r
671 inr a\r
672; cpi 0CH ;Twelve? [5a dont use this]\r
673 cpi 0Bh ; [majoc 850585] Eleven?\r
674 jm cmifi0\r
675cmif0a: ;[MF]Zero entire fcb, not just the extent\r
676 mvi m,0 ; [majoc 850507] Specify extent 0\r
677 inx h ;[MF]Increment fcb byte pointer\r
678 inr a ;[MF]Increment fcb byte count\r
679 cpi 32 ;[MF]Done with fcb?\r
680 jm cmif0a ;[MF]No, zero until done\r
681cmifi1: call cmgtch ;Get another char.\r
682 ora a ;Is it an action character?\r
683 jp cmifi2\r
684 ani 7FH ;Turn off the action bit.\r
685 cpi '?' ;A question mark?\r
686 jnz cmif12\r
687 lda cmfwld ;[pcc006] Wildcards allowed?\r
688 ora a ;[pcc006]\r
689 jz cmif11 ;[pcc006] complain if not\r
690 lhld cmdptr ;[jd] Increment buffer pointer\r
691 inx h ;[jd] that was decremented in cmgtch\r
692 shld cmdptr ;[jd] since we want this chr\r
693 lda cmcptr ;[pcc006] get lsb of real input pointer\r
694 cmp l ;[pcc006] is this the last chr input?\r
695 jnz cmif1a ;[pcc006] no, don't reset action flag\r
696 xra a ;[pcc006] yes, reset action flag\r
697 sta cmaflg ;[pcc006] \r
698cmif1a: mvi a,'?' ;[pcc006] get it back in A\r
699 jmp cmifi8 ;Treat like any other character\r
700\r
701cmif12: cpi esc ;An escape?\r
702 jnz cmif13\r
703;Try to recognize file-spec a'la TOPS-20\r
704 xra a\r
705 sta cmaflg ;Turn off the action flag.\r
706 lhld cmcptr ;Move the pointer to before the escape.\r
707 dcx h\r
708 shld cmcptr\r
709 shld cmdptr\r
710 lxi h,cmccnt ;Get the char count.\r
711 dcr m ;Decrement it by one.\r
712 mov a,e ;Save character count up to now.\r
713 sta temp1\r
714 cpi 9 ;Past '.'?\r
715 jm cmfrec ;No.\r
716 dcr a ;Yes, don't count point.\r
717cmfrec: lhld cmfcb2 ;Fill the rest with CP/M wildcards.\r
718cmfrc1: cpi 11 ;Done?\r
719 jp cmfrc2 ;Yes.\r
720 mvi m,'?'\r
721 inx h\r
722 inr a\r
723 jmp cmfrc1\r
724\r
725cmfrc2: mvi c,sfirst ;Find first matching file?\r
726 lhld cmfcb\r
727 xchg\r
728 call bdos\r
729 cpi 0FFH\r
730 jz cmfrc9 ;No, lose.\r
731 lxi h,fcbblk ;Copy first file spec.\r
732 call fspcop\r
733 lxi h,fcbblk+10H ;Get another copy (in case not ambiguous).\r
734 call fspcop\r
735 mvi c,snext ;More matching specs?\r
736 lhld cmfcb\r
737 xchg\r
738 call bdos\r
739 cpi 0FFH\r
740 jz cmfrc3 ;Only one.\r
741 lxi h,fcbblk+10H ;Copy second file spec.\r
742 call fspcop\r
743cmfrc3: lxi d,fcbblk ;Start comparing file names.\r
744 lxi h,fcbblk+10H\r
745 lda temp1 ;Bypass characters typed.\r
746 cpi 9 ;Past '.'?\r
747 jm cmfrc4 ;No.\r
748 dcr a ;Yes, don't count point.\r
749cmfrc4: mvi c,0\r
750cmfrl1: cmp c ;Bypassed?\r
751 jz cmfrl2 ;Yes.\r
752 inx d\r
753 inx h\r
754 inr c\r
755 jmp cmfrl1 ;Repeat.\r
756\r
757cmfrl2: mov a,c ;Get file name characters processed.\r
758 cpi 11 ;All done?\r
759 jz cmfrc5 ;Yes.\r
760 cpi 8 ;End of file name?\r
761 jnz cmfrl3 ;No.\r
762 lda temp1 ;Exactly at point?\r
763 cpi 9\r
764 jz cmfrl3 ;Yes, don't output a second point.\r
765 mvi a,'.' ;Output separator.\r
766 call cmfput\r
767cmfrl3: ldax d ;Get a character from first file spec.\r
768 inx d\r
769 mov b,m ;Get from second file spec.\r
770 inx h\r
771 cmp b ;Compare.\r
772 jnz cmfrc5 ;Ambiguous.\r
773 inr c ;Same, count.\r
774 cpi ' ' ;Blank?\r
775 jz cmfrl2 ;Yes, don't output.\r
776 call cmfput ;Put character into buffer.\r
777 jmp cmfrl2 ;Repeat.\r
778\r
779cmfrc5: mov a,c ;Get count of characters processed.\r
780 sta temp1 ;Save it.\r
781 mvi a,'$' ;Get terminator.\r
782 call cmfput ;Put it into buffer.\r
783 lhld cmdptr ;Output recognized characters.\r
784 xchg\r
785 mvi c,prstr\r
786 call bdos\r
787 lhld cmcptr ;Remove terminator from buffer.\r
788 dcx h\r
789 shld cmcptr\r
790 lxi h,cmccnt\r
791 dcr m\r
792 lda temp1 ;Characters processed.\r
793 cpi 11 ;Complete file name.\r
794 jz repars ;Yes, don't beep.\r
795\r
796cmfrc9: mvi c,conout\r
797 mvi e,bell\r
798 call bdos ;Ring the bell.\r
799 jmp repars\r
800;\f\r
801; Continue file spec parsing.\r
802\r
803cmif13: mov a,e ;It must be a terminator.\r
804 ora a ;Test the length of the file name.\r
805 jz cmifi9 ;If zero complain.\r
806 cpi 0DH\r
807 jp cmifi9 ;If too long complain.\r
808 jmp rskp ;Otherwise we have succeeded.\r
809\r
810cmifi2: cpi '.'\r
811 jnz cmifi3\r
812 inr e\r
813 mov a,e\r
814 cpi 1H ;Any chars yet?\r
815 jz cmifi9 ;No, give error.\r
816 cpi 0AH ;Tenth char?\r
817 jp cmifi9 ;Past it, give an error.\r
818 mvi c,9H\r
819 mvi b,0\r
820 lhld cmfcb\r
821 dad b ;Point to file type field.\r
822 shld cmfcb2\r
823 mvi e,9H ;Say we've gotten nine.\r
824 jmp cmifi1 ;Get the next char.\r
825\r
826cmifi3: cpi ':'\r
827 jnz cmifi4\r
828 inr e\r
829 mov a,e\r
830 cpi 2H ;Is it in the right place for a drive?\r
831 jnz cmifi9 ;If not, complain.\r
832 lhld cmfcb2\r
833 dcx h ;Point to previous character.\r
834 mov a,m ;Get the drive name.\r
835 sui '@' ;Get the drive number.\r
836 shld cmfcb2 ;Save pointer to beginning of name field.\r
837 mvi m,space ;[obs] restore a space in FCB\r
838 dcx h ;Point to drive number.\r
839 mov m,a ;Put it in the fcb.\r
840 mvi e,0 ;Start character count over.\r
841 jmp cmifi1\r
842\r
843cmifi4: cpi '*'\r
844 jnz cmifi7\r
845 lda cmfwld ;Wildcards allowed?\r
846 cpi 0\r
847 jz cmif11 ;No,complain\r
848 mov a,e\r
849 cpi 8H ;Is this in the name or type field?\r
850 jz cmifi9 ;If its where the dot should be give up.\r
851 jp cmifi5 ;Type.\r
852 mvi b,8H ;Eight chars.\r
853 jmp cmifi6\r
854\r
855cmifi5: mvi b,0CH ;Three chars.\r
856cmifi6: lhld cmfcb2 ;Get a pointer into the FCB.\r
857 mvi a,'?'\r
858 mov m,a ;Put a question mark in.\r
859 inx h\r
860 shld cmfcb2\r
861 inr e\r
862 mov a,e\r
863 cmp b\r
864 jm cmifi6 ;Go fill in another.\r
865 jmp cmifi1 ;Get the next char.\r
866\r
867cmifi7: cpi '!' ;[pcc007] control chr or space?\r
868 jm cmifi9 ;[pcc007] yes, illegal\r
869 mov h,a ;[5] stash input char for a bit\r
870 lda ffussy ;[5] while we check the fussy flag\r
871 ora a ;[5] set the flags accordingly\r
872 mov a,h ;[5] restore the input character\r
873 jz cmif7a ;[5] if ffussy=0, allow <>.,;:?*[]\r
874;[5] So far, we've eliminated "action characters" (including question),\r
875;[5] period, colon, asterisk, control characters, and space.\r
876;[5] That leaves us %(),/;<=>[\]_| to check for.\r
877 cpi '%' ;[5]\r
878 jz cmifi9 ;[5]\r
879 cpi '(' ;[5]\r
880 jz cmifi9 ;[5]\r
881 cpi ')' ;[5]\r
882 jz cmifi9 ;[5]\r
883 cpi ',' ;[pcc007] weed out comma\r
884 jz cmifi9 ;[pcc007]\r
885 cpi '/' ;[5]\r
886 jz cmifi9 ;[5]\r
887 cpi '9'+1 ;[pcc007] anything else 21H-39H is ok\r
888 jm cmifi8 ;[pcc007] except '*' never gets here\r
889 cpi '@' ;[pcc007] all of 3AH-3FH is illegal\r
890 jm cmifi9 ;[pcc007]\r
891 cpi '[' ;[pcc007] [\] also illegal\r
892 jm cmifi8 ;[pcc007]\r
893 cpi ']'+1 ;[pcc007]\r
894 jm cmifi9 ;[pcc007]\r
895 cpi '_' ;[5]\r
896 jz cmifi9 ;[5] (If I was doing CP/M, I would have\r
897 cpi '|' ;[5] just eliminated all them funny chars\r
898 jz cmifi9 ;[5] instead of a random selection)\r
899cmif7a: ;[5]\r
900 cpi 'a' ;[pcc007] if not lower case its ok\r
901 jm cmifi8 ;[pcc007] (DEL never gets here)\r
902 cpi 'z'+1 ;[pcc007] only convert letters\r
903 jp cmifi8 ;[pcc007]\r
904 ani 137O ;Capitalize.\r
905cmifi8: lhld cmfcb2 ;Get the pointer into the FCB.\r
906 mov m,a ;Put the char there.\r
907 inx h\r
908 shld cmfcb2\r
909 inr e\r
910 jmp cmifi1\r
911\r
912cmifi9: lda cmstat\r
913 cpi cmifin ;"silent"?\r
914 jz r ;Yes,let him go w/o check\r
915 lxi d,cmer02\r
916cmif10: mvi c,prstr\r
917 call bdos\r
918 ret\r
919\r
920cmif11: lxi d,cmer03 ;Complain about wildcards.\r
921 jmp cmif10\r
922\r
923;\f\r
924\r
925; copy filename from buffer\r
926; called with HL = destination, A = position (0-3) in buffer\r
927; called by: cmifil\r
928\r
929fspcop: push psw ;Save A.\r
930 lxi d,buff ;Get the right offset in the buffer.\r
931 rlc\r
932 rlc\r
933 rlc\r
934 rlc\r
935 rlc\r
936 add e\r
937 inr a ;Bypass drive spec.\r
938 mov e,a\r
939 mvi b,11 ;Copy file name.\r
940fspcp1: ldax d\r
941 inx d\r
942 mov m,a\r
943 inx h\r
944 dcr b\r
945 jnz fspcp1\r
946 pop psw ;Restore A.\r
947 ret\r
948\r
949; append character in A to command buffer\r
950; called by: cmifil\r
951\r
952cmfput: push h ;Save H.\r
953 lhld cmcptr ;Get buffer pointer.\r
954 mov m,a ;Store in buffer.\r
955 inx h\r
956 shld cmcptr\r
957 lxi h,cmccnt ;Count it.\r
958 inr m\r
959 pop h ;Restore H.\r
960 ret\r
961;\f\r
962; Read characters from the command buffer.\r
963; called by: cmtext, cmcfrm, cmkeyw, cmifil\r
964\r
965cmgtch: push h\r
966 push b\r
967cmgtc1: lda cmaflg\r
968 ora a ;Is it set.\r
969 cz cminbf ;If the action char flag is not set get more.\r
970 lhld cmdptr ;Get a pointer into the buffer.\r
971 mov a,m ;Get the next char.\r
972 inx h\r
973 shld cmdptr\r
974 cpi ' ' ;Is it a space?\r
975 jz cmgtc2\r
976 cpi tab ;Or a tab?\r
977 jnz cmgtc3\r
978cmgtc2: lda cmsflg ;Get the space flag.\r
979 ora a ;Was the last char a space?\r
980 jnz cmgtc1 ;Yes, get another char.\r
981 mvi a,0FFH ;Set the space flag.\r
982 sta cmsflg\r
983 mvi a,' '\r
984 pop b\r
985 pop h\r
986 jmp cmgtc5\r
987\r
988cmgtc3: push psw\r
989 xra a\r
990 sta cmsflg ;Zero the space flag.\r
991 pop psw\r
992 pop b\r
993 pop h\r
994 cpi esc\r
995 jz cmgtc5\r
996 cpi '?' ;Is the user curious?\r
997 jz cmgtc4\r
998 cpi cr\r
999 jz cmgtc4\r
1000 cpi lf\r
1001 jz cmgtc4\r
1002 cpi ff\r
1003 rnz ;Not an action char, just return.\r
1004cmgtc4: push h\r
1005 lhld cmdptr\r
1006 dcx h\r
1007 shld cmdptr\r
1008 pop h\r
1009cmgtc5: ori 80H ;Make the char negative to indicate it is\r
1010 ret ;a terminator.\r
1011;\f\r
1012; Read characters from console into command buffer, processing\r
1013; editing characters (^H, ^M, ^J, ^L, ^U, ^X, ?, del).\r
1014; called by: comnd, cmgtch\r
1015\r
1016cminbf: push psw\r
1017 push d\r
1018 push h\r
1019 lda cmaflg ;Is the action char flag set?\r
1020 ora a\r
1021 jnz cminb9 ;If so get no more chars.\r
1022cminb1: lxi h,cmccnt ;Increment the char count.\r
1023 inr m\r
1024 mvi c,conin ;Get a char.\r
1025 lda cmqflg ;[MF]but do we want it echoed?\r
1026 ora a ;[MF]...\r
1027 jz cmin1b ;[MF]Yup, proceed normally\r
1028cmin1c: mvi e,0ffH ;[MF]Nope, do it with Direct\r
1029 mvi c,dconio ;[MF]Console I/O\r
1030 call bdos ;[MF]...\r
1031 ora a ;[MF]Did the user type anything?\r
1032 jz cmin1c ;[MF]No, don't go on until he/she does.\r
1033 jmp cmin1a ;[MF]We got a character\r
1034cmin1b: call bdos\r
1035cmin1a: lhld cmcptr ;Get the pointer into the buffer.\r
1036 mov m,a ;Put it in the buffer.\r
1037 inx h\r
1038 shld cmcptr\r
1039 cpi 25O ;Is it a ^U?\r
1040 jz cmnb12 ;Yes.\r
1041 cpi 30O ;Is it a ^X?\r
1042 jnz cminb2\r
1043cmnb12: call clrlin ;Clear the line.\r
1044 call prprmp ;Print the prompt [Toad Hall]\r
1045 lxi h,cmdbuf\r
1046 shld cmcptr ;Reset the point to the start.\r
1047 lxi h,cmccnt ;Zero the count.\r
1048 mvi m,0\r
1049 jmp repars ;Go start over.\r
1050\r
1051cminb2: cpi 10O ;Backspace?\r
1052 jz cminb3\r
1053 cpi del ;or Delete?\r
1054 jnz cminb4\r
1055 lda cmqflg ;[MF]If we are echoing characters,\r
1056 ora a ;[MF]...\r
1057 cz delchr ;Print the delete string. [MF]\r
1058cminb3: lda cmccnt ;Decrement the char count by two.\r
1059 dcr a\r
1060 dcr a\r
1061 ora a ;Have we gone too far?\r
1062 jp cmnb32 ;If not proceed.\r
1063 mvi c,conout ;Ring the bell.\r
1064 mvi e,bell\r
1065 call bdos\r
1066 jmp cmnb12 ;Go reprint prompt and reparse.\r
1067\r
1068cmnb32: sta cmccnt ;Save the new char count.\r
1069 lda cmqflg ;[MF]Echoing characters?\r
1070 ora a ;[MF]If we are, then\r
1071 cz clrspc ;Erase the character. [MF]\r
1072 lhld cmcptr ;Get the pointer into the buffer.\r
1073 dcx h ;Back up in the buffer.\r
1074 dcx h\r
1075 shld cmcptr\r
1076 jmp repars ;Go reparse everything.\r
1077\r
1078cminb4: cpi '?' ;Is it a question mark.\r
1079 jz cminb6\r
1080 cpi esc ;Is it an escape?\r
1081 jz cminb6\r
1082 cpi cr ;Is it a carriage return?\r
1083 jz cminb5\r
1084 cpi lf ;Is it a line feed?\r
1085 jz cminb5\r
1086 cpi ff ;Is it a formfeed?\r
1087 jnz cminb8 ;no - just store it and \r
1088 ;test if buffer overflowing, else get another character.\r
1089 call clrtop\r
1090cminb5: lda cmbflg ;[MF]Allowing initial blank word (<cr>)?\r
1091 ora a ;[MF]...\r
1092 jnz cminb6 ;[MF]Yes\r
1093 lda cmccnt ;Have we parsed any chars yet?\r
1094 cpi 1\r
1095 jz prserr ;If not, just start over.\r
1096cminb6: mvi a,0FFH ;Set the action flag.\r
1097 sta cmaflg\r
1098 jmp cminb9\r
1099\r
1100cminb8:\r
1101 lda cmccnt ; get the command character count\r
1102 cpi cmbufl ; check for comand buffer length\r
1103 jm cminb1 ; if less, then all ok\r
1104 mvi e,bell ; else beep at user\r
1105 call outcon ; send it to the console\r
1106 lda cmccnt ; back up one character\r
1107 dcr a\r
1108 sta cmccnt\r
1109 lhld cmcptr ; ditto pointer\r
1110 dcx h\r
1111 shld cmcptr ; save it again\r
1112 jmp cminb1 ; and try again\r
1113\r
1114cminb9: pop h\r
1115 pop d\r
1116 pop psw\r
1117 ret\r
1118;\f\r
1119;Little utility to print the prompt. (We do a LOT of these.) [Toad Hall]\r
1120;Enters with nothing.\r
1121;Destroys HL (and I suppose B and DE and A).\r
1122 \r
1123prprmp: mvi e,cr ; do a cr first\r
1124 mvi c,dconio\r
1125 call bdos\r
1126 lhld cmprmp ;Get the prompt.\r
1127 xchg\r
1128 call prtstr\r
1129 ret\r
1130\r
1131; Little code to allow some expansion of code without changing\r
1132; every futher address, only up to the end of this file.\r
1133; TO BE REMOVED FOR RELEASE!\r
1134\r
1135; org ($+100h) AND 0FF00H\r
1136\r
1137\r
1138IF lasm\r
1139LINK CPSUTL\r
1140ENDIF ;lasm [Toad Hall]\r