; COPY - CP/M SINGLE DISK COPY UTILITY ; ORG 0100H JMP COPY DB '(C) 1979 - N D H HAMMOND' PRGNAME DB 'COPY VSN 2.1 OF 3JAN80',0DH,0AH,'$' ; ; ;SYSTEM ADDRESSES WBOOTE EQU 0000H ;REBOOT ADDRESS SFCB EQU 005CH ;SOURCE FILE CONTROL BLOCK SFCBEX EQU SFCB+12 ;CURRENT FILE EXTENT NO SFCBCR EQU SFCB+32 ;NEXT RECORD COUNTER TBUF EQU 0080H ;SYSTEM DEFAULT BUFFER ;CONSTANTS CCPL EQU (3200H-2900H) SHR 8 ;PAGES IN CCP TRUE EQU 0FFH ETX EQU 03H LF EQU 0AH CR EQU 0DH EOM EQU '$' ; ; MAIN PROGRAM ; COPY LXI H,0 ;SAVE OLD STACK POINTER DAD SP SHLD OLDSP LXI SP,STACK LXI D,PRGNAME CALL WRITESTRING CALL SETMODE COPYLP CALL GETARGS CALL INITVAR CALL SOURCEDISK CALL OPENSOURCE CALL LOADBUF CALL DESTDISK CALL MAKETEMP REPEAT CALL DUMPBUF LDA FINISH CPI TRUE JZ ENDCOPY CALL SOURCEDISK CALL LOADBUF CALL DESTDISK JMP REPEAT ENDCOPY CALL TERMINATE LDA MULTI CPI TRUE JNZ EXIT CALL PROMPT JMP COPYLP EXIT LHLD OLDSP SPHL RET ;RETURN TO CP/M ; ; SUBROUTINBS ; SETMODE ;SET SINGLE/MULTIPLE COPY MODE XRA A STA MULTI LDA TBUF ;WAS A FILE NAME SPECIFIED? CPI 0 JNZ SM1 ;NO - SET MULTIPLE MODE MVI A,TRUE STA MULTI CALL PROMPT RET SM1 ;YES - SINGLE MODE, MOVE COMMAND LINE TO RBUF LXI H,TBUF LXI D,RBUF+1 MVI B,30 CALL COPYSTRING ;LIMIT TO 29 CHARACTERS LDA RBUF+1 CPI 30 RM MVI A,29 STA RBUF+1 RET ; ; INITVAR ;INITIALIZE VARIABLES XRA A STA FINISH ;SET EXTENT TO CP/M CBASE LHLD ENTRY+1 ;HL:=FBASE MOV A,H SBI CCPL MOV H,A ;HL:=CBASE MOV A,L ;ENSURE EXTENT IS AT ANI 80H ; A PAGE BOUNDARY MOV L,A SHLD EXTENT ;ZERO EXTENT BIT IN SOURCE FCB XRA A STA SFCBEX RET ; ; GETARGS ;GET FILE NAMES FROM BUFFER LXI H,RBUF+1 ;HL:=^BUFFER LGTH MOV A,M ;A:=BUFFER LGTH CPI 0 ;CHECK FOR EMPTY JZ EXIT INX H ;HL:=^BUFFER ;SET SENTINEL AT END OF BUFFER PUSH H MOV C,A MVI B,0 DAD B MVI M,ETX ;GET SOURCE FILE NAME POP H CALL DEBLANK CPI ETX JZ ARGERR LXI D,SFCB+1 CALL GETFILE JC ARGERR ;GET DEST FILE NAME CALL DEBLANK CPI ETX JZ NODEST LXI D,DFCB+1 CALL GETFILE JC ARGERR CALL DEBLANK CPI ETX JNZ ARGERR RET NODEST ;SET DEST FILE = SOURCE FILE NAME LXI D,DFCB+1 LXI H,SFCB+1 MVI B,11 CALL COPYSTRING RET ARGERR ;REPORT ERROR AND RETRY LXI D,AEMSG CALL WRITESTRING CALL PROMPT JMP GETARGS ; ; DEBLANK ;SKIP BLANKS IN RBUF ;ENTRY: HL=^POSITION IN RBUF ;EXIT: HL=^FIRST NONBLANK ; A=HL^ MOV A,M CPI ' ' RNZ INX H JMP DEBLANK ; ; GETFILE ;GET FILE NAME FROM RBUF ;ENTRY: HL=^POSITION IN RBUF ; DE=^FCB FOR FILE ;EXIT: HL,DE=^UPDATED POSITION ; A=HL^ ( OR ) ; CYF=ERROR FLAG MVI C,8 CALL GETNAME RC CPI '.' JNZ NOEXT INX H MVI C,3 CALL GETNAME RET ;FILL FILE TYPE FIELD WITH BLANKS NOEXT MVI A,' ' STAX D INX D STAX D INX D STAX D MOV A,M ORA A ;CLEAR CYF RET ; ; GETNAME ;GET NAME FROM RBUF ;ENTRY: HL=^POSITION IN RBUF ; DE=^FCB POSITION ; C=MAX NO OF CHARACTERS ;EXIT: HL,DE=^UPDATED POSITION ; A=DELIMITER (HL^) ; CYF=ERROR FLAG MVI B,0 INR C ;TRANSFER NAME TO FCB NXTCH MOV A,M CPI ' '+1 JM CKBLK CPI '.' JZ CKBLK CALL UPCASE STAX D INX H INR B INX D MOV A,B CMP C JNZ NXTCH STC ;TOO MANY CHARS RET ;BLANK FILL IF REQD CKBLK DCR C BLKFL MOV A,B CMP C JZ GOTNM MVI A,' ' STAX D INR B INX D JMP BLKFL ;EXIT GOTNM MOV A,M ORA A ;CLEAR CYF RET ; ; UPCASE ;CONVERT ACC TO UPPER CASE CPI 61H ;'a' RM CPI 7BH ;'z'+1 RP ANI 5FH RET ; ; OPENSOURCE ;OPEN SOURCE FILE LXI D,SFCB CALL OPENFILE CPI 0FFH JNZ OPEN$OK MVI B,1 JMP ERROR OPEN$OK XRA A STA SFCBCR RET ; ; LOADBUF ;LOAD BUFFER FROM SOURCE FILE LXI D,BUFFER RDNXT PUSH D CALL SETDMA LXI D,SFCB CALL READREC POP D ORA A JZ RD$OK CPI 1 JZ EOF MVI B,3 JMP ERROR RD$OK LXI B,80H ;UPDATE BUFFER XCHG DAD B LXI B,EXTENT CALL COMPARE XCHG JNZ RDNXT RET EOF MVI A,TRUE STA FINISH XCHG SHLD EXTENT RET ; ; MAKETEMP ;CREATE TEMPORARY FILE COPY.$$$ LXI D,TFCB CALL MAKEFILE CPI 0FFH JNZ MAKE$OK MVI B,2 JMP ERROR MAKE$OK XRA A STA TFCBCR STA TFCBEX RET ; ; DUMPBUF ;DUMP BUFFER TO TEMP FILE LXI D,BUFFER WRNXT PUSH D CALL SETDMA LXI D,TFCB CALL WRITEREC POP D ORA A JZ WR$OK MVI B,2 JMP ERROR WR$OK LXI B,80H ;UPDATE BUFFER POSITION XCHG DAD B LXI B,EXTENT CALL COMPARE XCHG JNZ WRNXT RET ; ; TERMINATE ;CLOSE TEMP FILE LXI D,TFCB CALL CLOSEFILE ;DELETE OLD COPY OF DEST FILE (IF ANY) LXI D,DFCB CALL DELETEFILE ;RENAME DEST FILE = COPY.$$$ LXI H,DFCB+1 LXI D,TFCB+17 MVI B,11 CALL COPYSTRING LXI D,TFCB CALL RENAMEFILE ;ADVISE OPERATOR LXI D,TERMSG CALL WRITESTRING RET ; ; COPYSTRING ;COPY STRING OF LENGTH B ;FROM HL^ TO DE^ MOV A,M STAX D INX H INX D DCR B JNZ COPYSTRING RET ; ; ERROR ;PRINT ERROR MESSAGE LXI D,OPMSG MOV A,B CPI 1 JZ EPRINT LXI D,CRMSG CPI 2 JZ EPRINT LXI D,REMSG EPRINT CALL WRITESTRING ;EXIT (OR RESTART IF MULTIPLE COPY MODE) LDA MULTI CPI TRUE JNZ EXIT LXI SP,STACK CALL PROMPT JMP COPYLP ; ; COMPARE ;COMPARE BC^ AND HL - SET FLAGS INX B LDAX B DCX B CMP H RNZ LDAX B CMP L RET ; ; SOURCEDISK ;ADVISE OPERATOR, WAIT FOR RESPONSE, LXI D,SDMSG CALL WRITESTRING CALL WAIT RET ; ; DESTDISK ;ADVISE OPERATOR, WAIT FOR RESPONSE LXI D,DDMSG CALL WRITESTRING CALL WAIT ;RESET BDOS TO AVOID 'R/O ERROR' CALL INITBDOS RET ; ; PROMPT ;ISSUE PROMPT AND GET PARAMETERS MVI E,'*' CALL WRITECHAR LXI D,RBUF CALL READSTRING RET ; ; WAIT ;WAIT FOR OPERATOR TO TYPE RETURN CALL READCHAR CPI 03H JZ WBOOTE CPI CR JNZ WAIT RET ; ; CP/M COMMUNICATION ROUTINES ; ; ENTRY EQU 0005H ; BDOS ENTRY POINT ; ; READCHAR ; READ A CHARACTER FROM CONSOLE MVI C,1 JMP ENTRY ; ; WRITECHAR ; WRITE A CHARACTER TO CONSOLE MVI C,2 JMP ENTRY ; ; WRITESTRING ; WRITE A STRING ON CONSOLE MVI C,9 JMP ENTRY ; ; READSTRING ; READ STRING FROM CONSOLE MVI C,10 JMP ENTRY ; ; INITBDOS ;INITIALIZE BDOS, LOG IN DISK A MVI C,13 JMP ENTRY ; ; OPENFILE ; OPEN A NEW FILE MVI C,15 JMP ENTRY ; ; CLOSEFILE ; CLOSE FILE MVI C,16 JMP ENTRY ; ; DELETEFILE ; DELETE DIRECTORY ENTRY FOR FILE MVI C,19 JMP ENTRY ; ; READREC ; READ NEXT 128 BYTE RECORD MVI C,20 JMP ENTRY ; ; WRITEREC ; WRITE NEXT 128 BYTE RECORD MVI C,21 JMP ENTRY ; ; MAKEFILE ; CREATE NEW DIRECTORY ENTRY MVI C,22 JMP ENTRY ; ; RENAMEFILE ; CHANGE NAME IN DIRECTORY MVI C,23 JMP ENTRY ; ; SETDMA ; SET DMA ADDRESS FOR READ OR WRITE MVI C,26 JMP ENTRY ; ; ; ; DATA AREA ; OLDSP DS 2 RBUF DB 28 ;COMMAND INPUT BUFFER DS 31 TFCB DB 0 ;TEMP FCB DB 'COPY $$$' TFCBEX DB 0 DB 0,0,0 DS 16 TFCBCR DS 1 DFCB DB 0 ;DEST FCB DS 32 EXTENT DS 2 ;EXTENT OF COPY BUFFER MULTI DS 1 ;MULTIPLE COPY MODE FLAG FINISH DS 1 ;LAST BUFFER FLAG SDMSG DB LF,'INSERT SOURCE DISK, TO CONTINUE' DB CR,LF,EOM DDMSG DB 'INSERT DEST DISK, TO CONTINUE' DB CR,LF,EOM TERMSG DB 'COPY COMPLETE',CR,LF,EOM AEMSG DB LF,'WHAT?',CR,LF,EOM OPMSG DB LF,'SOURCE FILE NOT FOUND',CR,LF,EOM CRMSG DB LF,'DISK OR DIRECTORY FULL',CR,LF,EOM REMSG DB 'READ ERROR ON SOURCE',CR,LF,EOM DS 20H ;MINIMUM STACK SPACE ;SET START OF BUFFER TO MULTIPLE OF SECTOR SIZE ORG (($ + 7FH) / 80H) * 80H STACK EQU $ ;GROWS DOWN BUFFER EQU $ ;FILLS REST OF MEMORY TO CBASE END