diff options
| author | Jeff Armstrong <jeff@approximatrix.com> | 2026-10-25 17:42:06 -0400 |
|---|---|---|
| committer | Jeff Armstrong <jeff@approximatrix.com> | 2026-10-25 17:42:06 -0400 |
| commit | ebb2ff2af569d5822b70ee555a32d27cf7494816 (patch) | |
| tree | 7ac5e7b3fa73f7a8d996129086932ecce66374ad /src/cpscpm.asm | |
| download | kermit-80-main.tar.gz kermit-80-main.zip | |
Diffstat (limited to 'src/cpscpm.asm')
| -rw-r--r-- | src/cpscpm.asm | 932 |
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] |
