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