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