home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
BEEHIVE
/
COMMS
/
CP411SRC.ARK
/
cpscmd.asm
< prev
next >
Wrap
Assembly Source File
|
1991-04-23
|
33KB
|
1,141 lines
; CPSCMD.ASM
; KERMIT - (Celtic for "FREE")
;
; This is the CP/M-80 implementation of the Columbia University
; KERMIT file transfer protocol.
;
; Version 4.0
;
; Copyright June 1981,1982,1983,1984,1985
; Columbia University
;
; Originally written by Bill Catchings of the Columbia University Center for
; Computing Activities, 612 W. 115th St., New York, NY 10025.
;
; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben,
; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many
; others.
;
;
; This file provides a user oriented way of parsing commands.
; It is similar to that of the COMND JSYS in TOPS-20.
;
; revision history (latest first):
;
;edit 13, 17-Jan-1991 by MF. Modified "cmifil" routine to zero the entire
; fcb (not just the extent) to fix a bug in the COPY command which
; prevented successive COPY commands from working properly.
;edit 12, 16-Jan-1991 by MF. Modified routine "cmkeyw" to ignore leading
; spaces/tabs before a keyword. This apparently was the intent in
; "prompt" and "repars" (at least for command-lines) as the variable
; "cmsflg "is set upon command parse and reparse. The intent was ,
; subverted, however, as "cmkeyw" did not reset the flag to ignore
; leading white space for each search thru the key tables (even though
; the buffer pointer to the keyword entered was reset). The fix was
; to reset the "spaces seen" flag (cmsflg) after "cmkey2" so that
; it is reset each time a new table entry is compared to the text
; the user has entered from the keyboard/TAKE-file etc. The upshot
; of all this is that the kluge code in "cminbf" at "cminb0" designed
; to force Kermit to ignore leading white space on command-lines in
; TAKE-files and on the CP/M command-line is no longer needed and,
; therefore, has been eliminated. Also modify "comnd" to expect leading
; spaces for functions other than "get keyword".
;edit 11, 26-Dec-1990 by MF. Modified routines to ignore leading white space
; in lines from TAKE-files as well as during input from the CP/M
; command-line (form-feeds are now considered white space under these
; circumstances).
;edit 10, 8-Sep-1990 by Mike Freeman. Modified routines to ignore leading
; spaces/tabs when processing Kermit commands from the CP/M
; command-line.
; Added flag CMBFLG to allow initial word on a command-line
; to be blank (useful for Remote commands such as Remote CWD etc).
; Added flag cmqflg to prevent character-echoing while entering
; commands so Remote CWD etc can have nonechoing password entry.
; edit 9, 15 June, 1987 by OBSchou. Bug fixing to allow a second filename
; (quiet) be entered as d:<blank>. Previous revision put the drive name
; in first character of FCB, I put that character back to a space.
;
; edit 8, 12 June, 1987 by OBSchou. Addedin code in cmkeyw to print
; 20 lines of help, then pause for a key from the user befor
; proceeding with help.
;
; edit 7, 11 March, 1987 by OBSchou for Richard Russell, BBC. He writes:
; Bug in cmtext which prevented use of octal characters (\nnn) fixed.
;
; edit 6, 18 June, 1986 by OBSchou, Loughborough University, Leics. UK
; added code to parse a number from user input. Added check to make
; sure the input command buffer does not overflow the limit.
;
; edit 5a: 7 March, 1986. OBSchou. Added stuff rom MJ Carter. He writes:
; 7th May 85, MJ Carter [majoc], Nottingham University
; Code in cmifil() put one too many spaces in the FCB; this caused
; the BDOS of the British Micro Mimi to search for exteny 32,
; rather than extent 0, so era() always said "can't find file"
; Puttig a null at the point in question ought to fix 9 it.
;
; edit 5: 6-Feb-85 by Charles Carvalho
; Make ffussy a runtime (rather than assembly-time) switch, to
; eliminate conditional assembly in system-independent module.
; Don't allow _%|()/\ in filenames if ffussy set; my CP/M manual
; disallows those, too.
;
; edit 4: 13-Jan-85 by Vanya J.Cooper Pima Commun. College Tel: 602-884-6809
;
;pcc006 2-jan-85 VJC modules:cp4cmd,cp4utl
; Problems with "?" in filespecs. On reparse, may cause action
; flag to be reset at wrong point, requiring multiple <CR>'s
; to terminate the line or other weird stuff. Also need to
; check flag and complain if wild-cards illegal.
;pcc007 2-Jan-85 vjc modules:cp4def,cp4cmd
; Cmifil is too fussy about what characters to accept in a
; filespec. My CP/M manual says any printable character is ok
; except <>.,;:?*[], and lower case. In practice, even those work
; sometimes. Kermit itself uses '&' if file warning is on,
; and then won't let you reference the file. Allow all
; printable characters except those above. Add conditional
; ffussy, so that if not ffussy, all special characters will be
; allowed, just convert lower to upper-case.
; edit 3: July 8, 1984 (CJC)
; integrate Toad Hall changes for LASM compatibility: CP4CPM is linked
; by CP4WLD, and links CP4UTL.
;
; edit 2: June 5, 1984 (CJC)
; formatting and documentation; delete unnecessary code at cminb7; add
; module version string.
;
; edit 1: May, 1984 (CJC)
; extracted from CPMBASE.M80 version 3.9; modifications are described in
; the accompanying .UPD file.
cmdver: db 'CPSCMD.ASM (13) 17-Jan-1991$' ; name, edit number, date
; This routine prints the prompt in DE and specifies the reparse
; address.
; called by: kermit
prompt: pop h ;Get the return address.
push h ;Put it on the stack again.
shld cmrprs ;Save it as the address to go to on reparse.
lxi h,0 ;Clear out hl pair.
dad sp ;Get the present stack pointer.
shld cmostp ;Save for later restoral.
xchg ;Save the pointer to the prompt.
shld cmprmp
xchg
lxi h,cmdbuf
shld cmcptr ;Initialize the command pointer.
shld cmdptr
xra a
sta cmaflg ;Zero the flags.
sta cmccnt
; mvi a,0FFH ;Try it this way (Daphne.)
; sta cmsflg
call prcrlf ;Print a CR/LF [Toad Hall]
jmp prprmp ;Print the prompt. [Toad Hall]
;
; This address is jumped to on reparse.
; here from: cmcfrm, cmkeyw, cmifil, cminbf
repars: lhld cmostp ;Get the old stack pointer.
sphl ;Make it the present one.
lxi h,cmdbuf
shld cmdptr
; mvi a,0FFH ;Try it this way (Daphne.)
; sta cmsflg
lhld cmrprs ;Get the reparse address.
pchl ;Go there.
; This address can be jumped to on a parsing error.
; here from: cmkeyw, cminbf
prserr: lhld cmostp ;Get the old stack pointer.
sphl ;Make it the present one.
lxi h,cmdbuf
shld cmcptr ;Initialize the command pointer.
shld cmdptr
xra a
sta cmaflg ;Zero the flags.
sta cmccnt
; mvi a,0FFH ;Try it this way (Daphne.)
; sta cmsflg
call prcrlf ;Print a CR/LF [Toad Hall]
call prprmp ;Print the prompt [Toad Hall]
;* Instead return to before the prompt call.
lhld cmrprs
pchl
;
; This routine parses the specified function in A. Any additional
; information is in DE and HL.
; Returns +1 on success
; +4 on failure (assumes a JMP follows the call)
; called by: log, setcom, read, send, xmit, dir, era, keycmd, cfmcmd
; and CPSREM
comnd: sta cmstat ;Save what we are presently parsing.
call cminbf ;Get chars until an action or a erase char.
push psw ;[MF]Save function
mvi a,0ffh ;[MF]Expect leading spaces
sta cmsflg ;[MF]...
pop psw ;[MF]Restore function
cpi cmcfm ;Parse a confirm?
jz cmcfrm ;Go get one.
cpi cmkey ;Parse a keyword?
jz cmkeyw ;Try and get one.
cpi cmifi ;Parse an input file spec?
jz cmifil ;Go get one.
cpi cmifin ;Input file-spec silent?
jz cmifil ;do as he wishes
cpi cmofi ;Output file spec?
jz cmofil ;Go get one.
cpi cmtxt ;Parse arbitrary text?
jz cmtext ;Go do it.
cpi cmnum ;[7] Parse a number?
jz cmnumb ;[7] go do it
lxi d,cmer00 ;"?Unrecognized COMND call"
call prtstr
ret
;
; This routine parses arbitrary text up to a CR.
; Accepts DE: address to put text
; Returns in A: number of chars in text (may be 0)
; DE: updated pointer
; called by: comnd
cmtext: xra a ; clear counters erc for slashes etc
sta slshsn ; if we are in a slash sequence
sta slashn ; the octal number being entered
sta slashc ; number of characters entered
xchg ;Put the pointer to the dest in HL.
shld cmptab ;Save the pointer.
mvi b,0 ;Init the char count
cmtxt1: call cmgtch ;Get a char.
ora a ;Terminator?
jp cmtx3 ;No, put in user space. [rtr] was cmtx5
ani 7FH ;Turn off minus bit.
cpi esc ;An escape?
jnz cmtxt2 ;No.
mvi c,conout
mvi e,bell ;Get a bell.
call bdos
xra a
sta cmaflg ;Turn off the action flag.
lhld cmcptr ;Move the pointer to before the escape.
dcx h
shld cmcptr
shld cmdptr
lxi h,cmccnt ;Get the char count.
dcr m ;Decrement it by one.
jmp cmtxt1 ;Try again.
cmtxt2: cpi '?' ;Is it a question mark?
jz cmtxt4 ;If so put it in the text. [rtr] was cmtx3
cpi ff ;Is it a formfeed?
cz clrtop ;If so blank the screen.
mov a,b ;Return the count.
lhld cmptab ;Return updated pointer in HL.
xchg
jmp rskp ;Return success.
cmtx3: cpi '\' ; slash?
jnz cmtx3a ; nope, so try something else
lda slshsn ; a slash already entered?
ana a
cma ;[rtr]
jnz cmtx3a ; yes, so assume its a valid slash to enter
sta slshsn ; make sure the flag is set for next time routnd
jmp cmtxt1 ; get another character
cmtx3a:
; lxi h,cmaflg ;Point to the action flag.
; mvi m,0 ;Set it to zero.
mov e,a ; save it in case we are interpreting a slash
lda slshsn ; slash already entered?
ana a ; test flag
mov a,e ; restore it in case...
jz cmtx5 ; not a slash seen, so enter as a normal character
cpi '\'
jnz cmtx3b ; \\ not detected
lda slashn ; else get number
jmp cmtx5b ; and enter it ( in the case of \n or \nn)
; here if an octal number of 1 or 2 digits
; entered instead of 3, followed by \ again
cmtx3b:
sui 30h ; else it should be an octal number
jm cmtxt6 ; if not a digit complain
cpi 8 ; ditto
jp cmtxt6 ;[rtr] was cmtxt
mov e,a ; else add it to the number already entered
lda slashn
add a
add a
add a ; multiply by 8
add e
sta slashn
lda slashc ; get the count
inr a
sta slashc ; plus one. If three then a number entered
cpi 3
lda slashn ; get the number in case...
jz cmtx5
jmp cmtxt1 ; else loop
cmtxt4: lhld cmdptr ;[rtr] Get a pointer into the buffer
inx h ;[rtr] Bump past '?'
shld cmdptr ;[rtr]
cmtx5: call cmtx5c
jmp cmtxt1 ; put this into a subroutine
cmtx5b:
call cmtx5c ; here if we see \n\ or \nn\ rather than \nnn\
mvi a,'\' ; so send slash number to buffer,
sta slshsn ; re-store a slash seen
jmp cmtxt1 ; try next one
cmtx5c:
inr b ;Increment the count.
lhld cmptab ;Get the pointer.
mov m,a ;Put the char in the array.
inx h
shld cmptab ;Save the updated pointer.
xra a ; clear slash counters etc
sta slashc
sta slashn
sta slshsn
ret ; and exit
cmtxt6: lxi d,cmer05 ; complain - not a valid \ parameter
call prtstr
jmp kermit ; and try another command
ds 20h ; for debugging
;
; This routine gets a number from user input.
; Called by: comnd
;
cmnumb: lxi h,0 ; make sure the number is zero to start with
shld number
cmnum0: call cmgtch ; get another character
ora a ; if negative then its an action
jp cmnum1 ; nope, so (possibly) valid input
ani 7fh ; else lets see what it is...
cpi esc ; do not know what to do with this one...
cpi ' ' ; if it is a space then either a return or more
jnz cmnum2 ; else
jmp rskp ; space is a deliminter
dw 0 ; set three bytes aside for a jump/call
dw 0 ; and then another three just in case...
dw 0 ; making 6 bytes
cmnum2: cpi '?' ; user is curious
jz gnum2
cpi cr ; end of input?
jz cmnumx
gnum1: jmp prserr ; did not under stand this, so error
cmnumx: dw 0
dw 0
jmp rskp ; return ok
gnum2: lhld number ; get the number.. if at all entered
mov a,l
ora h ; if hl = 0 then possibly no number entered
lxi d,cmin02 ; say confirm...or more on line
jnz gnum21 ; else say enter a return
lxi d,cmin01 ; say enter a number
gnum21: call prtstr ; say it
call prcrlf ; do a lf
call prprmp ; another reprompt
lhld cmdptr ; get pointer of string already entered
mvi m,'$' ; dollar it to set end of line
lhld cmcptr
dcx h ; decrement and save the buffer pointer
shld cmcptr
lxi d,cmdbuf
call prtstr ; print what has already been entered
xra a
sta cmaflg ; turn the action flag off
jmp repars ; and try again
mvi a,cmcfm ; parse a confirm
dw 0
dw 0
dw 0
dw 0
dw 0 ; some space to patch...
dw 0
cmnum1: ani 7fh ; here for a (potentially) valid number
sui '0' ; less ascii bias
jc gnum3
cpi 10 ; if 10 or more its still bad
jnc gnum3
cmc
lhld number ; now multiply number by ten and add the new value
push h
pop d
dad h ; hl = hl * 2
dad h ; * 4
dad d ; * 5
dad h ; * 10
mvi d,0
mov e,a ; add de to hl...
dad d
shld number
jmp cmnum0
;
gnum3: lxi d,cmer04 ; invalid number...
call prtstr
jmp rskp
;
;
; This routine gets a confirm.
; called by: comnd
cmcfrm: call cmgtch ;Get a char.
ora a ;Is it negative (a terminator;a space or
;a tab will not be returned here as they
;will be seen as leading white space.)
rp ;If not, return failure.
ani 7FH ;Turn off the minus bit.
cpi esc ;Is it an escape?
jnz cmcfr2
mvi c,conout
mvi e,bell ;Get a bell.
call bdos
xra a
sta cmaflg ;Turn off the action flag.
lhld cmcptr ;Move the pointer to before the escape.
dcx h
shld cmcptr
shld cmdptr
lxi h,cmccnt ;Get the char count.
dcr m ;Decrement it by one.
jmp cmcfrm ;Try again.
cmcfr2: cpi '?' ;Curious?
jnz cmcfr3
lxi d,cmin00 ;Print something useful.
call prtstr
call prcrlf ;Print a crlf. [Toad Hall]
call prprmp ;Reprint the prompt [Toad Hall]
lhld cmdptr ;Get the pointer into the buffer.
mvi a,'$' ;Put a $ there for printing.
mov m,a
lhld cmcptr
dcx h ;Decrement and save the buffer pointer.
shld cmcptr
lxi d,cmdbuf
call prtstr
xra a ;Turn off the action flag.
sta cmaflg
jmp repars ;Reparse everything.
cmcfr3: cpi ff ;Is it a form feed?
cz clrtop ;If so blank the screen.
jmp rskp
;
; This routine parses a keyword from the table pointed
; to in DE. The format of the table is as follows:
;
; addr: db n ;Where n is the # of entries in the table.
; db m ;M is the size of the keyword.
; db 'string$' ;Where string is the keyword.
; db a,b ;Where a & b are pieces of data
; ;to be returned. (Must be two of them.)
;
; The keywords must be in alphabetical order.
;**** Note: The data value a is returned in registers A and E. The
;**** data value b is returned in register D. This allows the two data
; bytes to be stored as:
; dw xxx
; and result in a correctly formatted 16-bit value in register pair
; DE.
; called by: comnd
cmkeyw: shld cmhlp ;Save the help.
xchg ;Get the address of the table.
shld cmptab ;Save the beginning of keyword tab for '?'.
mov b,m ;Get the number of entries in the table.
inx h
shld cmkptr
lhld cmdptr ;Save the command pointer.
shld cmsptr
cmkey2: mov a,b ;Get the number of entries left.
ora a ;Any left?
rz ;If not we failed.
mvi a,0ffh ;[MF]Make sure we ignore leading spaces
sta cmsflg ;[MF]...
lhld cmkptr
mov e,m ;Get the length of the keyword.
inx h
cmkey3: dcr e ;Decrement the number of chars left.
mov a,e
cpi 0FFH ;Have we passed the end?
jm cmkey5 ;If so go to the next.
call cmgtch ;Get a char.
ora a ;Is it a terminator?
jp cmkey4 ;If positive, it is not.
ani 7FH ;Turn off the minus bit.
cpi '?'
jnz cmky31
xra a
sta cmaflg ;Turn off the action flag.
lxi h,cmccnt ;Decrement the char count.
dcr m
;* Must go through the keyword table and print them.
lhld cmhlp ;For now print the help text.
xchg
call p20ln ;[8] print at most 20 lines then pause
; call prtstr
call prcrlf ;Print a crlf [Toad Hall]
call prprmp ;Reprint the prompt [Toad Hall]
lhld cmdptr ;Get the pointer into the buffer.
mvi a,'$' ;Put a $ there for printing.
mov m,a
lhld cmcptr
dcx h ;Decrement and save the buffer pointer.
shld cmcptr
lxi d,cmdbuf
call prtstr
jmp repars ;Reparse everything.
cmky31: cpi esc ;Is it an escape?
jnz cmky35
xra a
sta cmaflg ;Turn off the action flag.
push d
push b
push h
call cmambg
jmp cmky32 ;Not ambiguous.
mvi c,conout
mvi e,bell
call bdos ;Ring the bell.
lhld cmcptr ;Move the pointer to before the escape.
dcx h
shld cmcptr
shld cmdptr
lxi h,cmccnt ;Get the char count.
dcr m ;Decrement it by one.
pop h
pop b
pop d
inr e ;Increment the left to parse char count.
jmp cmkey3
cmky32: lhld cmcptr ;Pointer into buffer.
dcx h ;Backup to the escape.
xchg
pop h
push h
cmky33: mov a,m ;Get the next char.
cpi '$' ;Finished?
jz cmky34
inx h
xchg
mov m,a ;Move it into the buffer.
inx h
xchg
lda cmccnt ;Increment the char count.
inr a
sta cmccnt
jmp cmky33
cmky34: lda cmccnt ;Get the character count.
inr a ;Increment and save it.
sta cmccnt
xchg ;Put the command buffer pointer in HL.
mvi a,' ' ;Get a blank.
mov m,a ;Put it in the command buffer.
inx h ;Increment the pointer
shld cmcptr ;Save the updated pointer.
shld cmdptr
pop h
push h
xchg
call prtstr ;Print the rest of the keyword.
mvi c,conout
mvi e,' '
call bdos ;Print a blank.
pop h
pop b
pop d
jmp cmky37
cmky35: push h
push d
call cmambg
jmp cmky36
lxi d,cmer01
call prtstr ;Say its ambiguous.
jmp prserr ;Give up.
cmky36: pop d
pop h
cmky37: inr e ;Add one incase it is negative.
mvi d,0
dad d ;Increment past the keyword.
inx h ;Past the $.
mov e,m ;Get the data.
inx h
mov d,m
mov a,e
jmp rskp
cmkey4: cpi 'a' ;Is it less than a?
jm cmky41 ;If so don't capitalize it.
cpi 'z'+1 ;Is it more than z?
jp cmky41 ;If so don't capitalize it.
ani 137O ;Capitalize it.
cmky41: mov d,m ;Get the next char of the keyword.
inx h
cmp d ;Match?
jz cmkey3 ;If so get the next letter.
cmkey5: mvi d,0
mov a,e ;Get the number of chars left.
ora a ;Is it negative?
jp cmky51
mvi d,0FFH ;If so, sign extend.
cmky51: dad d ;Increment past the keyword.
lxi d,0003H ;Plus the $ and data.
dad d
shld cmkptr
dcr b ;Decrement the number of entries left.
lhld cmsptr ;Get the old cmdptr.
shld cmdptr ;Restore it.
;* check so we don't pass it.
jmp cmkey2 ;Go check the next keyword.
;
; Test keyword for ambiguity.
; returns: nonskip if ambiguous, skip if OK.
; called by: cmkeyw
cmambg: dcr b ;Decrement the number of entries left.
rm ;If none left then it is not ambiguous.
inr e ;This is off by one;adjust.
mov c,e ;Save the char count.
mov a,e
ora a ;Any chars left?
rz ;No, it can't be ambiguous.
mvi d,0
dad d ;Increment past the keyword.
mvi e,3 ;Plus the $ and data.
dad d
mov b,m ;Get the length of the keyword.
inx h
xchg
lhld cmkptr ;Get pointer to keyword entry.
mov a,m ;Get the length of the keyword.
sub c ;Subtract how many left.
mov c,a ;Save the count.
cmp b
jz cmamb0
rp ;If larger than the new word then not amb.
cmamb0: lhld cmsptr ;Get the pointer to what parsed.
cmamb1: dcr c ;Decrement the count.
jm rskp ;If we are done then it is ambiguous.
xchg ;Exchange the pointers.
mov b,m ;Get the next char of the keyword
inx h
xchg ;Exchange the pointers.
mov a,m ;Get the next parsed char.
inx h
cpi 'a' ;Is it less than a?
jm cmamb2 ;If so don't capitalize it.
cpi 'z'+1 ;Is it more than z?
jp cmamb2 ;If so don't capitalize it.
ani 137O
cmamb2: cmp b ;Are they equal?
rnz ;If not then its not ambiguous.
jmp cmamb1 ;Check the next char.
;
; cmofil - parse output filespec
; cmifil - parse input filespec
; here from: comnd
cmofil: mvi a,0 ;Don't allow wildcards.
; jmp cmifil ;For now, the same as CMIFI.
cmifil: sta cmfwld ;Set wildcard flag
xchg ;Get the fcb address.
shld cmfcb ;Save it.
mvi e,0 ;Initialize char count.
mvi m,0 ;Set the drive to default to current.
inx h
shld cmfcb2
xra a ;Initialize counter.
cmifi0: mvi m,' ' ;Blank the FCB.
inx h
inr a
; cpi 0CH ;Twelve? [5a dont use this]
cpi 0Bh ; [majoc 850585] Eleven?
jm cmifi0
cmif0a: ;[MF]Zero entire fcb, not just the extent
mvi m,0 ; [majoc 850507] Specify extent 0
inx h ;[MF]Increment fcb byte pointer
inr a ;[MF]Increment fcb byte count
cpi 32 ;[MF]Done with fcb?
jm cmif0a ;[MF]No, zero until done
cmifi1: call cmgtch ;Get another char.
ora a ;Is it an action character?
jp cmifi2
ani 7FH ;Turn off the action bit.
cpi '?' ;A question mark?
jnz cmif12
lda cmfwld ;[pcc006] Wildcards allowed?
ora a ;[pcc006]
jz cmif11 ;[pcc006] complain if not
lhld cmdptr ;[jd] Increment buffer pointer
inx h ;[jd] that was decremented in cmgtch
shld cmdptr ;[jd] since we want this chr
lda cmcptr ;[pcc006] get lsb of real input pointer
cmp l ;[pcc006] is this the last chr input?
jnz cmif1a ;[pcc006] no, don't reset action flag
xra a ;[pcc006] yes, reset action flag
sta cmaflg ;[pcc006]
cmif1a: mvi a,'?' ;[pcc006] get it back in A
jmp cmifi8 ;Treat like any other character
cmif12: cpi esc ;An escape?
jnz cmif13
;Try to recognize file-spec a'la TOPS-20
xra a
sta cmaflg ;Turn off the action flag.
lhld cmcptr ;Move the pointer to before the escape.
dcx h
shld cmcptr
shld cmdptr
lxi h,cmccnt ;Get the char count.
dcr m ;Decrement it by one.
mov a,e ;Save character count up to now.
sta temp1
cpi 9 ;Past '.'?
jm cmfrec ;No.
dcr a ;Yes, don't count point.
cmfrec: lhld cmfcb2 ;Fill the rest with CP/M wildcards.
cmfrc1: cpi 11 ;Done?
jp cmfrc2 ;Yes.
mvi m,'?'
inx h
inr a
jmp cmfrc1
cmfrc2: mvi c,sfirst ;Find first matching file?
lhld cmfcb
xchg
call bdos
cpi 0FFH
jz cmfrc9 ;No, lose.
lxi h,fcbblk ;Copy first file spec.
call fspcop
lxi h,fcbblk+10H ;Get another copy (in case not ambiguous).
call fspcop
mvi c,snext ;More matching specs?
lhld cmfcb
xchg
call bdos
cpi 0FFH
jz cmfrc3 ;Only one.
lxi h,fcbblk+10H ;Copy second file spec.
call fspcop
cmfrc3: lxi d,fcbblk ;Start comparing file names.
lxi h,fcbblk+10H
lda temp1 ;Bypass characters typed.
cpi 9 ;Past '.'?
jm cmfrc4 ;No.
dcr a ;Yes, don't count point.
cmfrc4: mvi c,0
cmfrl1: cmp c ;Bypassed?
jz cmfrl2 ;Yes.
inx d
inx h
inr c
jmp cmfrl1 ;Repeat.
cmfrl2: mov a,c ;Get file name characters processed.
cpi 11 ;All done?
jz cmfrc5 ;Yes.
cpi 8 ;End of file name?
jnz cmfrl3 ;No.
lda temp1 ;Exactly at point?
cpi 9
jz cmfrl3 ;Yes, don't output a second point.
mvi a,'.' ;Output separator.
call cmfput
cmfrl3: ldax d ;Get a character from first file spec.
inx d
mov b,m ;Get from second file spec.
inx h
cmp b ;Compare.
jnz cmfrc5 ;Ambiguous.
inr c ;Same, count.
cpi ' ' ;Blank?
jz cmfrl2 ;Yes, don't output.
call cmfput ;Put character into buffer.
jmp cmfrl2 ;Repeat.
cmfrc5: mov a,c ;Get count of characters processed.
sta temp1 ;Save it.
mvi a,'$' ;Get terminator.
call cmfput ;Put it into buffer.
lhld cmdptr ;Output recognized characters.
xchg
mvi c,prstr
call bdos
lhld cmcptr ;Remove terminator from buffer.
dcx h
shld cmcptr
lxi h,cmccnt
dcr m
lda temp1 ;Characters processed.
cpi 11 ;Complete file name.
jz repars ;Yes, don't beep.
cmfrc9: mvi c,conout
mvi e,bell
call bdos ;Ring the bell.
jmp repars
;
; Continue file spec parsing.
cmif13: mov a,e ;It must be a terminator.
ora a ;Test the length of the file name.
jz cmifi9 ;If zero complain.
cpi 0DH
jp cmifi9 ;If too long complain.
jmp rskp ;Otherwise we have succeeded.
cmifi2: cpi '.'
jnz cmifi3
inr e
mov a,e
cpi 1H ;Any chars yet?
jz cmifi9 ;No, give error.
cpi 0AH ;Tenth char?
jp cmifi9 ;Past it, give an error.
mvi c,9H
mvi b,0
lhld cmfcb
dad b ;Point to file type field.
shld cmfcb2
mvi e,9H ;Say we've gotten nine.
jmp cmifi1 ;Get the next char.
cmifi3: cpi ':'
jnz cmifi4
inr e
mov a,e
cpi 2H ;Is it in the right place for a drive?
jnz cmifi9 ;If not, complain.
lhld cmfcb2
dcx h ;Point to previous character.
mov a,m ;Get the drive name.
sui '@' ;Get the drive number.
shld cmfcb2 ;Save pointer to beginning of name field.
mvi m,space ;[obs] restore a space in FCB
dcx h ;Point to drive number.
mov m,a ;Put it in the fcb.
mvi e,0 ;Start character count over.
jmp cmifi1
cmifi4: cpi '*'
jnz cmifi7
lda cmfwld ;Wildcards allowed?
cpi 0
jz cmif11 ;No,complain
mov a,e
cpi 8H ;Is this in the name or type field?
jz cmifi9 ;If its where the dot should be give up.
jp cmifi5 ;Type.
mvi b,8H ;Eight chars.
jmp cmifi6
cmifi5: mvi b,0CH ;Three chars.
cmifi6: lhld cmfcb2 ;Get a pointer into the FCB.
mvi a,'?'
mov m,a ;Put a question mark in.
inx h
shld cmfcb2
inr e
mov a,e
cmp b
jm cmifi6 ;Go fill in another.
jmp cmifi1 ;Get the next char.
cmifi7: cpi '!' ;[pcc007] control chr or space?
jm cmifi9 ;[pcc007] yes, illegal
mov h,a ;[5] stash input char for a bit
lda ffussy ;[5] while we check the fussy flag
ora a ;[5] set the flags accordingly
mov a,h ;[5] restore the input character
jz cmif7a ;[5] if ffussy=0, allow <>.,;:?*[]
;[5] So far, we've eliminated "action characters" (including question),
;[5] period, colon, asterisk, control characters, and space.
;[5] That leaves us %(),/;<=>[\]_| to check for.
cpi '%' ;[5]
jz cmifi9 ;[5]
cpi '(' ;[5]
jz cmifi9 ;[5]
cpi ')' ;[5]
jz cmifi9 ;[5]
cpi ',' ;[pcc007] weed out comma
jz cmifi9 ;[pcc007]
cpi '/' ;[5]
jz cmifi9 ;[5]
cpi '9'+1 ;[pcc007] anything else 21H-39H is ok
jm cmifi8 ;[pcc007] except '*' never gets here
cpi '@' ;[pcc007] all of 3AH-3FH is illegal
jm cmifi9 ;[pcc007]
cpi '[' ;[pcc007] [\] also illegal
jm cmifi8 ;[pcc007]
cpi ']'+1 ;[pcc007]
jm cmifi9 ;[pcc007]
cpi '_' ;[5]
jz cmifi9 ;[5] (If I was doing CP/M, I would have
cpi '|' ;[5] just eliminated all them funny chars
jz cmifi9 ;[5] instead of a random selection)
cmif7a: ;[5]
cpi 'a' ;[pcc007] if not lower case its ok
jm cmifi8 ;[pcc007] (DEL never gets here)
cpi 'z'+1 ;[pcc007] only convert letters
jp cmifi8 ;[pcc007]
ani 137O ;Capitalize.
cmifi8: lhld cmfcb2 ;Get the pointer into the FCB.
mov m,a ;Put the char there.
inx h
shld cmfcb2
inr e
jmp cmifi1
cmifi9: lda cmstat
cpi cmifin ;"silent"?
jz r ;Yes,let him go w/o check
lxi d,cmer02
cmif10: mvi c,prstr
call bdos
ret
cmif11: lxi d,cmer03 ;Complain about wildcards.
jmp cmif10
;
; copy filename from buffer
; called with HL = destination, A = position (0-3) in buffer
; called by: cmifil
fspcop: push psw ;Save A.
lxi d,buff ;Get the right offset in the buffer.
rlc
rlc
rlc
rlc
rlc
add e
inr a ;Bypass drive spec.
mov e,a
mvi b,11 ;Copy file name.
fspcp1: ldax d
inx d
mov m,a
inx h
dcr b
jnz fspcp1
pop psw ;Restore A.
ret
; append character in A to command buffer
; called by: cmifil
cmfput: push h ;Save H.
lhld cmcptr ;Get buffer pointer.
mov m,a ;Store in buffer.
inx h
shld cmcptr
lxi h,cmccnt ;Count it.
inr m
pop h ;Restore H.
ret
;
; Read characters from the command buffer.
; called by: cmtext, cmcfrm, cmkeyw, cmifil
cmgtch: push h
push b
cmgtc1: lda cmaflg
ora a ;Is it set.
cz cminbf ;If the action char flag is not set get more.
lhld cmdptr ;Get a pointer into the buffer.
mov a,m ;Get the next char.
inx h
shld cmdptr
cpi ' ' ;Is it a space?
jz cmgtc2
cpi tab ;Or a tab?
jnz cmgtc3
cmgtc2: lda cmsflg ;Get the space flag.
ora a ;Was the last char a space?
jnz cmgtc1 ;Yes, get another char.
mvi a,0FFH ;Set the space flag.
sta cmsflg
mvi a,' '
pop b
pop h
jmp cmgtc5
cmgtc3: push psw
xra a
sta cmsflg ;Zero the space flag.
pop psw
pop b
pop h
cpi esc
jz cmgtc5
cpi '?' ;Is the user curious?
jz cmgtc4
cpi cr
jz cmgtc4
cpi lf
jz cmgtc4
cpi ff
rnz ;Not an action char, just return.
cmgtc4: push h
lhld cmdptr
dcx h
shld cmdptr
pop h
cmgtc5: ori 80H ;Make the char negative to indicate it is
ret ;a terminator.
;
; Read characters from console into command buffer, processing
; editing characters (^H, ^M, ^J, ^L, ^U, ^X, ?, del).
; called by: comnd, cmgtch
cminbf: push psw
push d
push h
lda cmaflg ;Is the action char flag set?
ora a
jnz cminb9 ;If so get no more chars.
cminb1: lxi h,cmccnt ;Increment the char count.
inr m
mvi c,conin ;Get a char.
lda cmqflg ;[MF]but do we want it echoed?
ora a ;[MF]...
jz cmin1b ;[MF]Yup, proceed normally
cmin1c: mvi e,0ffH ;[MF]Nope, do it with Direct
mvi c,dconio ;[MF]Console I/O
call bdos ;[MF]...
ora a ;[MF]Did the user type anything?
jz cmin1c ;[MF]No, don't go on until he/she does.
jmp cmin1a ;[MF]We got a character
cmin1b: call bdos
cmin1a: lhld cmcptr ;Get the pointer into the buffer.
mov m,a ;Put it in the buffer.
inx h
shld cmcptr
cpi 25O ;Is it a ^U?
jz cmnb12 ;Yes.
cpi 30O ;Is it a ^X?
jnz cminb2
cmnb12: call clrlin ;Clear the line.
call prprmp ;Print the prompt [Toad Hall]
lxi h,cmdbuf
shld cmcptr ;Reset the point to the start.
lxi h,cmccnt ;Zero the count.
mvi m,0
jmp repars ;Go start over.
cminb2: cpi 10O ;Backspace?
jz cminb3
cpi del ;or Delete?
jnz cminb4
lda cmqflg ;[MF]If we are echoing characters,
ora a ;[MF]...
cz delchr ;Print the delete string. [MF]
cminb3: lda cmccnt ;Decrement the char count by two.
dcr a
dcr a
ora a ;Have we gone too far?
jp cmnb32 ;If not proceed.
mvi c,conout ;Ring the bell.
mvi e,bell
call bdos
jmp cmnb12 ;Go reprint prompt and reparse.
cmnb32: sta cmccnt ;Save the new char count.
lda cmqflg ;[MF]Echoing characters?
ora a ;[MF]If we are, then
cz clrspc ;Erase the character. [MF]
lhld cmcptr ;Get the pointer into the buffer.
dcx h ;Back up in the buffer.
dcx h
shld cmcptr
jmp repars ;Go reparse everything.
cminb4: cpi '?' ;Is it a question mark.
jz cminb6
cpi esc ;Is it an escape?
jz cminb6
cpi cr ;Is it a carriage return?
jz cminb5
cpi lf ;Is it a line feed?
jz cminb5
cpi ff ;Is it a formfeed?
jnz cminb8 ;no - just store it and
;test if buffer overflowing, else get another character.
call clrtop
cminb5: lda cmbflg ;[MF]Allowing initial blank word (<cr>)?
ora a ;[MF]...
jnz cminb6 ;[MF]Yes
lda cmccnt ;Have we parsed any chars yet?
cpi 1
jz prserr ;If not, just start over.
cminb6: mvi a,0FFH ;Set the action flag.
sta cmaflg
jmp cminb9
cminb8:
lda cmccnt ; get the command character count
cpi cmbufl ; check for comand buffer length
jm cminb1 ; if less, then all ok
mvi e,bell ; else beep at user
call outcon ; send it to the console
lda cmccnt ; back up one character
dcr a
sta cmccnt
lhld cmcptr ; ditto pointer
dcx h
shld cmcptr ; save it again
jmp cminb1 ; and try again
cminb9: pop h
pop d
pop psw
ret
;
;Little utility to print the prompt. (We do a LOT of these.) [Toad Hall]
;Enters with nothing.
;Destroys HL (and I suppose B and DE and A).
prprmp: mvi e,cr ; do a cr first
mvi c,dconio
call bdos
lhld cmprmp ;Get the prompt.
xchg
call prtstr
ret
; Little code to allow some expansion of code without changing
; every futher address, only up to the end of this file.
; TO BE REMOVED FOR RELEASE!
; org ($+100h) AND 0FF00H
IF lasm
LINK CPSUTL
ENDIF ;lasm [Toad Hall]