aboutsummaryrefslogtreecommitdiff
path: root/src/cpscpm.asm
diff options
context:
space:
mode:
authorJeff Armstrong <jeff@approximatrix.com>2026-10-25 17:42:06 -0400
committerJeff Armstrong <jeff@approximatrix.com>2026-10-25 17:42:06 -0400
commitebb2ff2af569d5822b70ee555a32d27cf7494816 (patch)
tree7ac5e7b3fa73f7a8d996129086932ecce66374ad /src/cpscpm.asm
downloadkermit-80-main.tar.gz
kermit-80-main.zip
Initial import of 4.11HEADmain
Diffstat (limited to 'src/cpscpm.asm')
-rw-r--r--src/cpscpm.asm932
1 files changed, 932 insertions, 0 deletions
diff --git a/src/cpscpm.asm b/src/cpscpm.asm
new file mode 100644
index 0000000..49df54f
--- /dev/null
+++ b/src/cpscpm.asm
@@ -0,0 +1,932 @@
+; CPSCPM.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
+; 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 duplicates the CP/M DIR and ERA functions so we don't have
+; to exit.
+;
+; revision history:
+;
+;edit 14, 1-Apr-1991 by MF. Correct a bug which crept in with edit 13 which
+; caused any control-key other than ^Y or ^Z to act like ^X after a key
+; had been depressed to halt output of the TYPE/PRINT commands.
+;edit 13, 25-Mar-1991 by MF. Make the TYPE command always abort to Kermit
+; command-level if ^C is entered on the console even if multiple files
+; are being typed via wild-cards. Make ^X typed on the console abort
+; typeout of the current file and begin typeout of the next file,
+; if any, otherwise go back to Kermit command-level.
+; The foregoing also applies to the PRINT command.
+;edit 12, 14-Feb-1991 by MF. Call "clrtop" in TYPE command at "type1"
+; rather than sending a <ff> directly to the terminal as some
+; terminals don't respond to <ff> characters. Thus the screen will be
+; cleared (if the terminal allows) before each file is typed.
+; Also use "getfil" rather than the bdos "openf" call to open
+; files for typing (label "type2"). This tightens up the code.
+; Zero "fcbcnt" before starting to type files (label "type0b").
+; This apparently fixes a phantom bug which caused incorrect lookup (and
+; hence garbage typeout) of files occassionally after a new disk
+; was inserted and a SET DEFAULT-DISK was performed to reset the disk
+; system. (It looked like parts of other files were being typed, as
+; if the directory had been misread or had not been reset.)
+;edit 11, 8-Feb-1991 by MF. Cause the bdos call for direct console input
+; in "ckchr" **not** to go thru the bdos trap but to call bdos at 0005h
+; directly. This corrects a bug wherein if commands such as INPUT
+; (which check to see if a keyboard key has been pressed) were executed
+; from a TAKE-file, the character following the terminator of such
+; commands was being interpreted as that keyboard input, thus causing
+; the next command in the TAKE-file to be unrecognized since its
+; first character had been eaten as a result of the keyboard check.
+; This bug **may** be the cause of a report received by Dr. Martin
+; J. Carter of Nottingham University in the U.K. in which Kermit
+; was reported to have read a character beyond a command terminator
+; in a TAKE-file, making the subsequent command unrecognizable since
+; its first character was missing.
+;edit 10, 29-Jan-1991 by MF. Use the big buffer for TYPE/PRINT commands.
+; Thus, edit 9 has been superseded.
+;edit 9, 29-Jan-1991 by MF. Corrected EOF check in TYPE command routine
+; following label "type20". a READF call, if successful, gives A=0
+; (not A=0FFH) and A not zero if failure. Thus the "INR A" instruction
+; checking for EOF was **always** nonzero. The reason the TYPE command
+; worked is that CP/M text files indicate the text end-of-file with a
+; Control-Z, in which case the TYPE routine branched correctly. In
+; other words, this edit is more for aesthetic purposes to satisfy
+; purists than something brought about by dire necessity!
+;edit 8, 28-Jan-1991 by MF. Added code courtesy of Dr. Martin J. Carter
+; of Nottingham University, UK, to use the big buffer for the COPY
+; command.
+;edit 7, 18-Sep-1990 by MF. Added RENAME routine to implement the
+; RENAME (FRENAME) command to rename a CP/M file.
+; Modified COPY routine to explicitly reject wild-carded filenames
+; by using COMND function CMOFI rather than functions CMIFI and
+; CMIFIN to get input and output filenames.
+; Modified ERA and COPY routines to not act upon the respective
+; commands until a "confirm" is typed. This prevents these
+; routines from taking off upon recognition of action characters
+; like "?", which can be quite annoying if one is an inexperienced user.
+; edit 6, March 11, 1987 by OBSchou. Added in the TYPE and PRINT commands
+; Both type to the screen, print also echoes to printer.
+;
+; edit 5 20 June, 1986. Added support for multiple file FCB buffering.
+;
+; edit 4: June 16, 1986 OBSchou at Loughborough University, UK
+; added in a test to prevent a DIR command issued from a TAKE command
+; being interruped by the next character in the take command buffer.
+; Also added code for USER nn. (Well, its OS related,is it not?)
+;
+; edit 3: July 8, 1984 (CJC)
+; Merge modifications from Toad Hall: support LASM (linked by CPSTT,
+; links to CPSWLD), use prcrlf where appropriate.
+;
+; edit 2: June 5, 1984 (CJC)
+; documentation and formatting; delete unused code (dir13); add module
+; version string.
+;
+; edit 1: May, 1984 (CJC)
+; extracted from CPMBASE.M80 version 3.9; modifications are described in
+; the accompanying .UPD file.
+;
+cpmver: db 'CPSCPM.ASM (14) 1-Apr-1991$' ; name, edit number, date
+
+npl EQU 04H ;Number of names per line for dir command.
+
+; This is the DIR command. Display the name and size of all files
+; matching the filespec.
+; here from: kermit
+;
+; Note: This is abstracted from Keith Peterson's DIRF.ASM
+; directory print function. Thanks again Keith.
+;
+;
+dir: lxi d,fcb ;Where to put the data, if any.
+ mvi a,cmifin
+ call comnd ;Parse a full or piece of file-spec
+ jmp dir2 ;Didn't get a FULL file-spec
+ jmp dir4 ;lets do it
+;
+;
+;Make FCB all '?' to match any file
+dir2: lda fcb
+ cpi ' ' ;CMIFIN leaves that as ' '
+ jnz dir2a ;he typed at least x:
+ xra a
+ sta fcb ;default drive
+dir2a: lxi h,fcb+1
+ mvi b,11 ;FN+FT count.
+
+dir3: mvi m,'?' ;Store '?'s in FCB.
+ inx h
+ dcr b
+ jnz dir3
+;Print signon message and drive name
+dir4: call getun ; get current user number
+ lda fcb
+ ora a ;if not zero, get default
+ jnz dir4a
+ lda curdsk ;get default
+dir4a: adi 'A'-1 ;Asciize it
+ sta dnam14+2 ;[4] add in user no, and Save it in message.
+ lda temp1+1 ;[4] most sig. user number
+ cpi '0' ;[4] if zero set space
+ jnz dir4b
+ mvi a,' ' ;[4] space
+dir4b: sta dnam14 ;[4]
+ lda temp1
+ sta dnam14+1 ;[4] ls user number digit
+ call prcrlf
+ lxi d,inms14 ;Point to message
+ call prtstr
+;
+;Initialize number of names per line counter
+ mvi a,npl ;Nr. names per line.
+ sta nnams ;Init counter.
+ lda hidefs ; are we doing file size?
+ ana a
+ jnz dir4c ; we are not showing file size,
+ lda nnams
+ inr a
+ sta nnams ; so we can show another name per line
+
+dir4c: xra a ; clear the flags ready for multi-sector buffering
+ sta fcbcnt ; clear fcb counter
+ sta mfflg1
+ sta mfflg2
+ sta mfflg3
+ lxi h,fcb0 ; reset pointer for fcb save space
+ shld xfcbptr
+;
+ call dir26 ;Get disk parameters
+ xra a ;[5] say first time round, so no spare fcbs
+ sta fcbcnt ;[5]
+dir5: call mfname ;get some names
+ jnc dir6 ;got one
+ jmp dir17 ;got none - do summary
+
+dir6: ;Check for console break
+ lda takflg ;[4] ... but not if issued from TAKE....
+ ana a ;[4]
+ jnz dir6a ;[4] we do the lot regardless.
+
+ mvi c,consta ;Ck status of kbd.
+ call bdos
+ ora a ;Any key pressed?
+ jz dir6a ;nope, keep going
+ mvi c,conin
+ call bdos ;gobble key
+ jmp dir17 ;and print summary only
+
+;Print an entry
+dir6a:
+ lxi h,fcb+1 ;point to Filename
+ mvi b,8 ;File name length.
+ call dir11 ;Type filename.
+ mvi a,'.' ;Period after FN.
+ call dir10
+ mvi b,3 ;Get the filetype.
+ call dir11
+ call dir25 ;print size
+ lxi h,nnams ;Point to names counter.
+ dcr m ;One less on this line.
+ push psw
+ cnz dir7 ;No cr-lf needed, do fence.
+ pop psw
+ cz dir12 ;Cr-lf needed.
+ jmp dir5
+
+;Print space, fence character, then space
+dir7: call dir9
+ mvi a,':' ;Fence character.
+ call dir10
+ jmp dir9
+
+; dir8 - Print two spaces
+; dir9 - Print one space
+; dir10 - Type char in A register
+dir8: call dir9
+dir9: mvi a,' '
+dir10: push b
+ push d
+ push h
+ mov e,a ;Char to E for CP/M.
+ mvi c,conout ;Write char to console function.
+ call bdos
+ pop h
+ pop d
+ pop b
+ ret
+
+;Type (B) characters from memory (HL)
+dir11: mov a,m
+ ani 7FH ;Remove CP/M 2.x attributes.
+ call dir10
+ inx h
+ dcr b
+ jnz dir11
+ ret
+
+;CR-LF routine. HL=NNAMS upon entry
+dir12: push b
+ push d
+ push h
+ call prcrlf ;Print CR/LF [Toad Hall]
+ pop h ;(did use call to dir10, but slooow)
+ pop d
+ pop b
+ mvi m,npl ;Number of names per line.
+ lda hidefs ; are we showing file size?
+ ana a
+ rnz ; no, so all ok
+ inr m ; else show another file per line
+ ret
+
+;Exit - All done, return via jmp (as for all main commands)
+dir16: call prcrlf
+ lda curdsk
+ dcr a ;relative to 0
+ mov e,a
+ mvi c,logdsk
+ call bdos ;back to "logged in" disk
+ jmp kermit ;...and return to kermit.
+
+;
+;Determines free space remaining
+;
+dir17: xra a
+ sta mfflg1 ;clean up MFNAME
+ sta mfflg2
+ lda fcb ; get drive number from FCB
+ ora a
+ jz dir18 ; default?
+ dcr a ; no, make requested drive current drive.
+ mov e,a
+ mvi c,logdsk
+ call bdos
+dir18: call sysspc ; get space available for current drive
+ push h
+ lxi d,inms15 ;"Drive "
+ call prtstr
+ lda fcb ;If no drive, get
+ ora a ;logged in drive
+ jnz dir24
+ mvi c,rddrv
+ call bdos
+ inr a
+dir24: adi 'A'-1
+ sta inms16
+ lxi d,inms16 ;"x has "
+ call prtstr
+ pop h ;Get number of bytes available
+ call nout
+ lxi d,inms17 ;"K bytes free"
+ call prtstr
+ jmp dir16 ;all done
+
+;Compute the size of the file
+
+dir25: lda hidefs ; do we show file size?
+ ana a ; if non zero, we dont.
+ rz ; so just return
+ mvi c,cflsz ;get file-size
+ lxi d,fcb
+ call bdos
+ lda fcbrno ;shift least sign. part
+ lxi b,0 ;init bc
+ mov l,a
+ ani 7
+ jz dir250 ;even K
+ lxi b,1 ;save for later
+dir250: push b ;save 0 or 1 to add to size
+ mvi b,3 ;shift 3 bits
+dir25a: xra a ;clear sign
+ lda fcbrno+1 ;get most sig byte
+ rar ;shift right
+ sta fcbrno+1 ;put back
+ lda fcbrno ;get least sig part
+ rar
+ sta fcbrno
+ dcr b ;loop 3 times
+ jnz dir25a
+ mov l,a ;size in HL
+ lda fcbrno+1
+ mov h,a
+ pop b ;get 0 or 1
+ dad b ;round up to KB used
+ lda bmask ;get (sectors/block)-1
+ rrc
+ rrc ;get (K/block)-1
+ rrc
+ ani 1FH
+ mov c,a
+ dad b ;add (K/block)-1 to size to round up
+ cma ;make a mask
+ ana l ;truncate after rounding up
+ mov l,a
+ push h
+ lxi b,-10 ;subtract 10
+ dad b
+ jc dir25d ;>= 10
+ call dir8 ; print a leading space
+ jmp dir25e
+
+dir25d: pop h ;get size again
+ push h
+ lxi b,-100 ;subtract 100
+ dad b
+ jc dir25e ;>= 100
+ call dir9 ; print another leading space
+dir25e: call dir9 ;a space
+ pop h ;get size back
+ call nout ;..go print it
+ mvi a,'k' ;..and follow with K size
+ call dir10
+ ret
+
+dir26: mvi c,gtdpar ;current DISK PARAMETER BLOCK
+ call bdos
+ inx h
+ inx h
+ mov a,m ;Get Block Shift Factor
+ sta bshiftf
+ inx h ;Bump to Block Mask
+ mov a,m ;get it
+ sta bmask
+ inx h
+ inx h
+ mov e,m ;Get Max Block number
+ inx h
+ mov d,m
+ xchg
+ shld bmax ;Put it away
+ ret
+;
+; ERA command - erase a CP/M file
+; here from: kermit
+
+era: mvi a,cmifi ;Parse a file-spec
+ lxi d,fcb ;into FCB
+ call comnd
+ jmp kermit ;bad parse
+ mvi a,cmcfm ;[MF]Get a confirm from the user
+ call comnd ;[MF]...
+ jmp kermit ;[MF]NO? try another command
+ lxi d,fcb
+ mvi c,sfirst ;check if valid
+ call bdos
+ inr a ;0 if FILE not found
+ jnz era1 ;found at least one
+ lxi d,erms15 ;"unable to find file"
+ call prtstr
+ jmp kermit
+
+era1: lxi d,fcb
+ mvi c,delf
+ call bdos
+ lxi d,inms18 ;" File(s) erased"
+ call prtstr
+ jmp kermit
+
+; USER - select a new user. This is an unusual routine in that the user
+; enters a number. The others take on/off or filename (except
+; set escape
+;
+user: mvi a,cmnum ; go parse a number
+ call comnd
+ jmp kermit ; if we can not do it, quit to command loop
+ mvi a,cmcfm ; get a confirm from the user
+ call comnd
+ jmp kermit ; if no, then try another command
+ lhld number ; else get the number...
+ xchg ; until a non valid digit is typed (eg cr)
+ lxi h,-32 ; if a carry, then ok
+ dad d ; ... else its above 32
+ jc user1
+ xchg ; restor number in hl again
+ mov a,l ; Lets save it
+ sta curusr ; as current user number
+ mov e,l ; get user no to e...
+ mvi c,usrcod
+ call bdos
+ call getun ; get user number to temp1 and temp2
+ lda temp2
+ cpi '0'
+ jnz user0 ; dont do ms digit if a zero
+ mvi a,' '
+user0: sta kerm1 ; save into string etc
+ sta dnam14 ; also for dir command
+ lda temp1
+ sta kerm1+1
+ sta dnam14+1 ; also for dir command
+ jmp kermit
+
+user1: lxi d,erms23 ; tell user sorry
+ call prtstr
+ jmp kermit
+
+
+;
+; TYPE - type a file or files to the console.
+;
+; This utility also used by print, where the characters printed to
+; the console are also copied to the printer if the prnfl flag
+; is non-zero. Uses mfname to type (print) multiple names.
+; Each file is preceeded with a formfeed character (usually clears
+; the screen on a VDU)
+;
+
+type: mvi a,cmifi ; parse a file name
+ lxi d,fcb ; let the parser know where the FCB is
+ call comnd
+ jmp type02 ; if error say so
+
+type0b:
+ xra a ; clear some flags for mfname
+ sta mfflg1
+ sta mfflg2
+ sta mfflg3
+ sta fcbcnt ;[12]...
+ lxi h,fcb0 ; reset the fcb pointers etc
+ shld fcbptr
+ call mfname
+ jc type02 ; match not found
+
+;[MF][10]The following code to type a file using a 1-sector buffer has
+;[MF][10]been replaced by code to use the "big buffer" -- 30-Jan-1991
+;type1: lxi d,buff ; point to the default DMA address
+; mvi c,setdma
+; call bdos ; tell bdos where to put the dma address
+; mvi a,ff ; do a form feed
+; call typit
+; xra a ; clear the character count
+; sta chrcnt
+;
+;type2: mvi c,openf ; open the file for reading
+; lxi d,fcb
+; xra a ; but first clear bits of fcb...
+; sta fcb+12
+; sta fcb+14
+; sta fcb+15
+; sta fcb+32
+; call bdos ; NOW open the file
+;
+;type20: mvi c,readf ; open up the file and read first sector
+; lxi d,fcb
+; call bdos
+;;[MF][9]Correct EOF test below (next two instructions)
+;; inr a ; if 0ffh returned, error. Assume EOF
+;; jz typex ; so exit from here
+; ora a ;[MF][9]If error, assume EOF
+; jnz typex ;[MF][9]so exit
+; lxi h,0 ; else clear the pointer into the file
+; shld typptr
+;
+;
+;type2a: lxi d,buff ;ok, so lets get the byte to print
+; lhld typptr
+; dad d ; add offset to the DMA base
+; mov a,m ; and get character to type (print)
+; ani 7fh ; make sure it is printable
+; cpi 20h ; is it a control character?
+; jp type3
+; cpi 09h ; if its a tab, then expand it
+; jnz type2b
+;
+;type2c: mvi a,' ' ; send a space
+; call typit ; type it
+; lda chrcnt ; get the number of chrs so far
+; ani 7h ; see of an 8th pos?
+; jnz type2c ; loop until all spaces done, then exit
+; jmp type4
+;
+;type2b: cpi cr ; is it a cr or lf?
+; jnz type2d
+; call typit ; do a cr
+; xra a
+; sta chrcnt ; cr of lf => clear character count
+; jmp type4 ; and exit
+;
+;type2d: cpi lf
+; jnz type2e
+; call typit ; print the character
+; xra a
+; sta chrcnt ; cr or lf clears the character count
+; jmp type4
+;
+;type2e: cpi cntlz ; is it end of file?
+; jnz type2f
+; jmp typex ; yes, so close and try for another file
+;
+;type2f: push psw ; control char - save the character
+; mvi a,'^' ; send control chars as ^A, for ex.
+; call typit
+; pop psw
+;
+;type3: call typit
+;
+;
+;type4: lhld typptr ; get the pointer
+; inx h
+; shld typptr ; up it by one character, and save it.
+; mov a,l ; lets see if the sector has been typed
+; ana a
+; jm type20 ; if 80h => read new sector
+; jmp type2a ; else just continue along
+
+;[MF][10]The following code uses the "big buffer" to read the file
+;[MF][10]which is to be typed
+;[12]Clear the screen explicitly as some terminals don't respond
+;[12]to the <ff> character.
+;type1: mvi a,ff ; do a form feed
+; call typit
+type1: call clrtop ;[12] Clear the screen
+ xra a ; clear the character count
+ sta temp1 ;[MF]alias column counter
+
+type2:
+;[12]Eliminate call to openf in favor of call to "getfil"
+; mvi c,openf ; open the file for reading
+ lxi d,fcb
+; xra a ; but first clear bits of fcb...
+; sta fcb+12
+; sta fcb+14
+; sta fcb+15
+; sta fcb+32
+; call bdos ; NOW open the file
+ call getfil ;[12] NOW open the file
+
+type20: call inbuf ;[MF]Fill input buffers
+ jmp typex ;[MF]Tru end-of-file reached
+ jmp type21 ;[MF]Begin typing/printing characters
+
+type2a: lda chrcnt ;[MF]Get buffer character counter
+ dcr a ;[MF]and decrement it
+ jm type20 ;[MF]Get more characters if needed
+type21: sta chrcnt ;[MF]else remember new buffer character counter
+ lhld bufpnt ;[MF]Now get character pointer
+ mov a,m ; and get character to type (print)
+ inx h ;[MF]Increment the pointer
+ shld bufpnt ;[MF]and remember it
+ ani 7fh ; make sure character is printable
+ cpi 20h ; is it a control character?
+ jp type3
+ cpi 09h ; if its a tab, then expand it
+ jnz type2b
+
+type2c: mvi a,' ' ; send a space
+ call typit ; type it
+ lda temp1 ;[MF]Get the number of characters so far
+ ani 7h ; see if an 8th pos?
+ jnz type2c ; loop until all spaces done, then exit
+ jmp type2a ;[MF]and continue
+
+type2b: cpi cr ; is it a cr or lf?
+ jnz type2d
+ call typit ; do a cr
+ xra a
+ sta temp1 ; cr or lf => clear character count
+ jmp type2a ;[MF]and continue
+
+type2d: cpi lf
+ jnz type2e
+ call typit ; print the character
+ xra a
+ sta temp1 ; cr or lf clears the character count
+ jmp type2a ;[MF]and continue
+
+type2e: cpi cntlz ; is it end of file?
+ jnz type2f
+ jmp typex ; yes, so close and try for another file
+
+type2f: push psw ; control char - save the character
+ mvi a,'^' ; send control chars as ^A, for ex.
+ call typit
+ pop psw
+
+type3: call typit
+ jmp type2a ; and continue along
+
+typex: mvi c,closf
+ lxi d,fcb
+ call bdos ; close the file
+ mvi a,cr ; send cr lf to screen/printer to clear buffers
+ call typit
+ mvi a,lf
+ call typit
+ call mfname ; and see if there are other files to type
+ jnc type1 ; yup, so go do it
+ xra a ; make sure the flag is reset
+ sta prnfl
+ jmp kermit ; then exit.
+
+typex0: mvi c,closf ;[MF]Close the file
+ lxi d,fcb ;[MF]...
+ call bdos ;[MF]...
+ mvi a,cr ;[MF]Clear buffers
+ call typit ;[MF]...
+ mvi a,lf ;[MF]...
+ call typit ;[MF]...
+ xra a ;[MF]Clear flag
+ sta prnfl ;[MF]...
+ lda takflg ;[MF]See if we're TAKEing commands
+ ani 1 ;[MF]from a file
+ cnz closet ;[MF]If we are, abort TAKE-file processing
+ jmp kermit ;[MF]Back to Kermit command-level
+
+; error for file not found for type
+type02: lxi d,nofile ; say no file name (its invalid)
+ call prtstr
+ xra a
+ sta prnfl ; clear the flag
+ jmp kermit ; so abort
+
+
+typit: mov e,a
+ call ckqtyp ; see if a cntl-c or other character from user
+ jmp typit2 ;[MF] Control-C entered, abort
+ jc typit1 ; CNTL-X entered, so abort file [MF]
+ push d ; save for a bit
+ call outcon ; send it to the console
+ lda temp1 ; update the number of characters sent[MF]
+ inr a
+ sta temp1 ;[MF]
+ pop d
+ lda prnfl ; see if we have to print it too
+ ana a
+ rz
+ call outprn ; send character to printer (buffer)
+ ret
+
+typit1: pop d ; adjust stack again
+ jmp typex ; and say we are done (for this file)
+
+typit2: pop d ;[MF] Adjust the stack
+ jmp typex0 ;[MF] and abort file typeout completely
+
+
+; CKQTYP - CHeck for requested Quiet TYPe (ie hang on a second)
+; Routine sees if the user has typed ANY key. If a key HAS been pressed
+; see if its a Control-c. If so, flag for an abort, else wait for
+; a second entry from the user. If its a Control C, flag an abort
+; else continue with the print.
+; note: only the DE registers maintained. All others destroyed.
+; **NOTE** CKQTYP now gives a nonskip return if Control-C is typed,
+; a skip-return with carry set if a Control-X is typed and a skip-return
+; with carry clear if any other character is typed as the second
+; character.
+
+ckqtyp: push d ; save the character to be printed
+ call ckchr ; see if user entered a character
+ ani 7fh ; strip parity etc
+ jz ckqty3 ; nothing entered, so go on as usual (See below)
+ cpi ctrlc ; control c?
+ jz ckqt1a ;[MF] Yup, give nonskip return
+ cpi 'X'-100o ;[MF] If Control-X,
+ jz ckqty1 ; yup, set carry and exit
+ckqty2: call ckchr ; another character to wait for (ie pause)
+ ani 7fh
+ jz ckqty2 ; wait until some input
+ cpi ctrlc ; if control c, abort
+ jz ckqt1a ;[MF] ...
+ cpi 'X'-100o ;[MF] Control-X?
+ jz ckqty1 ; yuss, so flag abort file [MF]
+ckqty3: pop d ; else restore the character to be typed [MF]
+; ret ; no, so continue with type/print
+ stc ;[MF]Set carry
+ cmc ;[MF]Then clear it
+ jmp rskp ;[MF] Continue with type/print (skip ret)
+
+ckqty1: pop d ; restore stack again
+ stc ; set carry and return
+; ret
+ jmp rskp ;[MF] ...
+
+ckqt1a: pop d ;[MF] Adjust stack
+ ret ;[MF] and return
+
+;[MF][14]No longer need these lines
+;ckqty3: pop d ; restore stack again
+;; ret
+; stc ;[MF] Clear carry
+; cmc ;[MF] ...
+; jmp rskp ;[MF] and give skip return
+
+ckchr: call selcon ; make sure we are talking to the console
+ mvi e,0ffh ; see if user has any input for us
+ mvi c,dconio
+; call bdos ;[11]Don't go thru bdos trap
+ call 0005h ;[11]Call bdos directly
+ ret ; This routine does not care what comes back
+
+
+;
+; COPY - routine to copy from a source file to a destination file
+; from the Kermit command state.
+;
+; Note. This could be tricky, as there are several forms of copy
+; copy d:source.ext d:dest.ext (Easy one)
+; copy d:source.ext d: (File to another drive)
+; copy d:source.??? d: (several files)
+; copy d:*.* d: (Several files)
+;
+; Initially, lets make it top one, and see how we go, ok?
+;
+;
+;Things to do for copy:
+; 1) get source name
+; 2) get target name
+; 3) if both source and destination = abort
+; 4) if source does not exist abort
+; 5) attempt to delete destination file if it exists
+; 6) open source and destination files
+; 7) copy file across
+; 8) close all files
+; 9) return to command mode
+;
+copy: ; Here goes...
+; 1) get source file name
+ mvi a,cmofi ; go parse a file name
+ ;[MF]Nonwild
+ lxi d,cfcbs ; use the source for copy FCB (Allows copy
+ call comnd ; from a TAKE file etc)
+ jmp kermit ; if error, abort
+
+; 2) get target name
+ mvi a,cmofi ; go parse a target file name
+ ;[MF]Again, nonwild
+ lxi d,cfcbd ; use destination fcb
+ call comnd ; get it
+ jmp kermit ;[MF]Couldn't.
+ mvi a,cmcfm ;[MF]Get a confirm from the user
+ call comnd ;[MF]...
+ jmp kermit ;[MF]No? try another command
+
+; 3) see if both target and source are equal
+copy0: mvi b,12 ; we are gonna test drive, file and extention
+ lxi d,cfcbs ; from source file name...
+ lxi h,cfcbd ; to destination file name
+ xra a ; clear flag for difference found
+ sta equflg
+copy1: ldax d ; get source file name character
+ cmp m ; test with targer file name
+ jz copy2 ; if equal, do nothing
+ lda equflg ; else update flage (ie files are different)
+ inr a
+ sta equflg
+copy2: inx h
+ inx d
+ dcr b
+ jnz copy1 ; up pointers and test for next char
+
+ lda equflg ; if still null, then its a daft thing to do
+ ana a
+ jnz copy3 ; its not a daft thing to do
+ lxi d,samems ; load up "File source and destination the same"
+ call prtstr ; tell user
+ jmp kermit ; and try again
+
+; 4) If source does not exist, abort. Assume we have a full file name.
+copy3:
+ lxi d,cfcbs ; load up source fcb
+ mvi c,openf ; open file
+ call bdos
+ inr a ; error on open?
+ jnz copy4
+ lxi d,nofile ; assume file not found
+ call prtstr
+ jmp kermit ; and die
+
+copy4: lxi d,cfcbd ; load up destination fcb
+ mvi c,delf ; destroy target name if it exists
+ call bdos ; ignore error messages
+ lxi d,cfcbd ; load up destination fcb
+ mvi c,makef ; make a file
+ call bdos
+ inr a ; make error?
+ jnz copy4a
+ lxi d,erms12 ; no directory space
+ call prtstr
+ jmp copy7 ; close source file
+
+copy4a: lxi d,cfcbd ; load up destination fcb...
+ mvi c,openf ; for open
+ call bdos
+ inr a ; error on open?
+ jnz copy5 ; could do with better error detection...
+ lxi d,erms15 ;... but assume its a disk full
+ call prtstr
+ jmp copy7 ; close source file and jmp kermit
+
+;copy5: lxi d,buff ; set default dma address to 80h
+; mvi c,setdma
+; call bdos
+;
+;copy6: lxi d,cfcbs ; copy routine proper.. get a sector
+; mvi c,readf
+; call bdos
+; ana a ; error reading the file?
+; jnz copy8 ; yes, then cope with it (could be EOF)
+; [MaJoC 910128] The above code, which reads single logical sectors,
+; is grossly inefficient with systems (most of them) with larger physical
+; disk blocks and a single shared read/write buffer. Use of INBUF below
+; is functionally equivalent at this level, but does actual disk reads
+; by the Big Buffer-ful.
+copy5:
+ xra a ; Initialise INBUF, to force reading of
+ sta seccnt ; the first Big Buffer-ful. Redundant
+ sta endsts ; if file opened by GETFIL (or variant).
+ sta eoflag ;[MF]...
+ lxi h,cfcbs ;[MF]Copy source fcb to default fcb
+ lxi d,fcb ;[MF]since INBUF uses the default fcb
+ lxi b,33 ;[MF]...
+ call mover ;[MF]...
+copy6:
+; INBUF returns a pointer to the next logical bufferful via bufpnt, filling
+; the Big Buffer as necessary, with skip return for success and nonskip on
+; error or EOF.
+ call inbuf ; Start of copy proper: get bufferful.
+ jmp copy8 ; Nonskip return: treat as EOF.
+ lhld bufpnt ; Skip return => OK: pick up buffer pointer.
+ xchg
+ mvi c, setdma ; Tell system where to write from.
+ call bdos
+; [majoc 910128: end]
+ lxi d,cfcbd ; send sector to destination
+ mvi c,writef
+ call bdos
+ ana a ; error on write (disk full?)
+ jz copy6 ; no error, so do another sector.
+ lxi d,erms17 ; say disk is full
+ call prtstr
+ lxi d,cfcbd ; close the output file...
+ mvi c,closf
+ call bdos
+ lxi d,cfcbd ; ... and then delete it
+ mvi c,delf
+ call bdos ; ... and then drop through to...
+
+copy7: lxi d,cfcbs ; here to close the source FCB
+ mvi c,closf
+ call bdos
+ jmp kermit
+
+copy8: lxi d,cfcbd ; orderly close of destination file
+ mvi c,closf
+ call bdos
+ jmp copy7 ; now close the source file as well.
+
+;
+;[MF]RENAME - Rename a file
+;
+rename: mvi a,cmofi ;[MF]Get nonwild filename
+ lxi d,cfcbs ;[MF]Use "COPY" fcb's
+ call comnd ;[MF]...
+ jmp kermit ;[MF]Couldn't get it.
+ mvi a,cmofi ;[MF]Get filespec to rename it to
+ lxi d,cfcbd ;[MF]...
+ call comnd ;[MF]...
+ jmp kermit ;[MF]Couldn't.
+renam0: lxi d,cfcbs ;[MF]See if file to be renamed exists
+ mvi c,openf ;[MF]by trying to open it
+ call bdos ;[MF]...
+ inr a ;[MF]Does the file exist?
+ jnz renam1 ;[MF]Yes
+ lxi d,nofile ;[MF]No, inform the user
+ call prtstr ;[MF]...
+ jmp kermit ;[MF]and bomb
+renam1: lxi d,cfcbd ;[MF]Point to rename filespec
+ mvi c,openf ;[MF]Set function code to
+ call bdos ;[MF]See if rename file exists
+ inr a ;[MF]Does it?
+ jz renam2 ;[MF]No
+ lxi d,erms31 ;[MF]Yes, complain
+ call prtstr ;[MF]...
+ jmp kermit ;[MF]and depart with tail between legs
+renam2: lxi h,cfcbd ;[MF]Now get rename filespec again
+ lxi d,cfcbs+16 ;[MF]and where to copy it to
+ lxi b,16 ;[MF]We copy drive, filename, filetype, extent
+ call mover ;[MF]...
+ lxi d,cfcbs ;[MF]Point to fcb for rename
+ mvi c,renam ;[MF]Get rename function
+ call bdos ;[MF]Try to rename the file
+ inr a ;[MF]Did we succeed?
+ jnz kermit ;[MF]Yes, done
+ lxi d,erms16 ;[MF]No, complain
+ call prtstr ;[MF]...
+ jmp kermit ;[MF]and start over
+
+
+IF lasm
+ LINK CPSWLD
+ENDIF;lasm [Toad Hall]