; PROGRAM: MCOPY ; AUTHOR: RICHARD CONN ; VERSION: 3.0 ; DATE: 16 JAN 83 ; PREVIOUS VERSIONS: 2.8 (14 JAN 83), 2.7 (11 JAN 83) ; PREVIOUS VERSIONS: 2.6 (9 JAN 83), 2.5 (8 JAN 83), 2.4 (7 JAN 83) ; PREVIOUS VERSIONS: 2.3 (6 JAN 83), 2.2 (19 DEC 82) ; PREVIOUS VERSIONS: 2.1 (7 DEC 82), 2.0 (14 NOV 82), 1.7 (21 JULY 82) ; PREVIOUS VERSIONS: 1.6 (12 JULY 82), 1.5 (12 JULY 82) ; PREVIOUS VERSIONS: 1.4 (10 JULY 82), 1.3 (9 JULY 82) ; PREVIOUS VERSIONS: 1.0 (27 Oct 80), 1.1 (2 NOV 80), 1.2 (11 APR 81) VERS equ 30 ; ; This program is Copyright (c) 1982, 1983 by Richard Conn ; All Rights Reserved ; ; ZCPR2 and its utilities, including this one, are released ; to the public domain. Anyone who wishes to USE them may do so with ; no strings attached. The author assumes no responsibility or ; liability for the use of ZCPR2 and its utilities. ; ; The author, Richard Conn, has sole rights to this program. ; ZCPR2 and its utilities may not be sold without the express, ; written permission of the author. ; ; ; MCOPY is a program which repeatedly copies a file from drive ; A: onto drive B:. It prompts the user to mount a disk in drive B:, ; copies the file from drive A: to drive B:, verifies the copy (if not ; overridden), and then performs the function again. ; ; MCOPY performs its function in the following steps: ; 1. If CP/M 2.x or MP/M, MCOPY determines the attributes ; of the destination file (if it exists) and clears them (file becomes ; R/W and DIR) ; 2. MCOPY deletes the destination file (if it exists) ; 3. MCOPY copies the source file to the destination ; 4. If CP/M 2.x or MP/M, MCOPY determines the attributes ; of the source file and makes the attributes of the destination file ; identical to those of the source ; 5. MCOPY reads both the source and destination files and ; compares them byte-for-byte ; ; CP/M Constants CPM EQU 0 ; CP/M WARM BOOT BDOSE EQU CPM+5 ; BDOS ENTRY POINT FCB EQU CPM+5CH ; SPECIFIED FCB BUFF EQU CPM+80H ; DEFAULT BUFFER AND INPUT LINE ; ASCII Constants, et al ON EQU 0FFH ; ON CODE OFF EQU 0 ; OFF CODE CR EQU 0DH ; LF EQU 0AH ; CTRLC EQU 'C'-'@' ; ^C CTRLZ EQU 'Z'-'@' ; ^Z OPTC EQU '/' ; OPTION DELIMITER DIV EQU '!' ; COPY/VERIFY PHASE DELIMITER FLIMIT EQU 1024 ; 1024 FILES PERMITTED ; ; SYSLIB ROUTINES ; EXT CLINE,COMPHD,ZGPINS,RETUD,LOGUD,BLINE EXT ZFNAME,DPARAMS,DIRF,DIRFS,FSIZE,DFREE EXT DIRPACK,INITFCB,F$EXIST EXT EVAL,CRCCLR,CRCUPD,CRCDONE EXT BDOS,CIN,COUT EXT F$DELETE,F$OPEN,F$MAKE,F$CLOSE,F$READ,F$WRITE EXT PHLDC,PADC,PSTR,PRINT EXT MOVEB,CAPS,CRLF EXT CODEND ; ; Branch to Start of Program ; JMP START ; ;****************************************************************** ; ; SINSFORM -- ZCPR2 Utility Standard General Purpose Initialization Format ; ; This data block precisely defines the data format for ; initial features of a ZCPR2 system which are required for proper ; initialization of the ZCPR2-Specific Routines in SYSLIB. ; ; ; EXTERNAL PATH DATA ; EPAVAIL: DB 0FFH ; IS EXTERNAL PATH AVAILABLE? (0=NO, 0FFH=YES) EPADR: DW 40H ; ADDRESS OF EXTERNAL PATH IF AVAILABLE ; ; INTERNAL PATH DATA ; INTPATH: DB 0,0 ; DISK, USER FOR FIRST PATH ELEMENT ; DISK = 1 FOR A, '$' FOR CURRENT ; USER = NUMBER, '$' FOR CURRENT DB 0,0 DB 0,0 DB 0,0 DB 0,0 DB 0,0 DB 0,0 DB 0,0 ; DISK, USER FOR 8TH PATH ELEMENT DB 0 ; END OF PATH ; ; MULTIPLE COMMAND LINE BUFFER DATA ; MCAVAIL: DB 0FFH ; IS MULTIPLE COMMAND LINE BUFFER AVAILABLE? MCADR: DW 0FF00H ; ADDRESS OF MULTIPLE COMMAND LINE BUFFER IF AVAILABLE ; ; DISK/USER LIMITS ; MDISK: DB 4 ; MAXIMUM NUMBER OF DISKS MUSER: DB 31 ; MAXIMUM USER NUMBER ; ; FLAGS TO PERMIT LOG IN FOR DIFFERENT USER AREA OR DISK ; DOK: DB 0FFH ; ALLOW DISK CHANGE? (0=NO, 0FFH=YES) UOK: DB 0FFH ; ALLOW USER CHANGE? (0=NO, 0FFH=YES) ; ; PRIVILEGED USER DATA ; PUSER: DB 10 ; BEGINNING OF PRIVILEGED USER AREAS PPASS: DB 'chdir',0 ; PASSWORD FOR MOVING INTO PRIV USER AREAS DS 41-($-PPASS) ; 40 CHARS MAX IN BUFFER + 1 for ending NULL ; ; CURRENT USER/DISK INDICATOR ; CINDIC: DB '$' ; USUAL VALUE (FOR PATH EXPRESSIONS) ; ; DMA ADDRESS FOR DISK TRANSFERS ; DMADR: DW 80H ; TBUFF AREA ; ; NAMED DIRECTORY INFORMATION ; NDRADR: DW 00000H ; ADDRESS OF MEMORY-RESIDENT NAMED DIRECTORY NDNAMES: DB 64 ; MAX NUMBER OF DIRECTORY NAMES DNFILE: DB 'NAMES ' ; NAME OF DISK NAME FILE DB 'DIR' ; TYPE OF DISK NAME FILE ; ; REQUIREMENTS FLAGS ; EPREQD: DB 0FFH ; EXTERNAL PATH? MCREQD: DB 0FFH ; MULTIPLE COMMAND LINE? MXREQD: DB 0FFH ; MAX USER/DISK? UDREQD: DB 0FFH ; ALLOW USER/DISK CHANGE? PUREQD: DB 0FFH ; PRIVILEGED USER? CDREQD: DB 0FFH ; CURRENT INDIC AND DMA? NDREQD: DB 0FFH ; NAMED DIRECTORIES? Z2CLASS: DB 2 ; CLASS 2 DB 'ZCPR2' DS 10 ; RESERVED ; ; END OF SINSFORM -- STANDARD DEFAULT PARAMETER DATA ; ;****************************************************************** ; ; ; USER-DEFINABLE INITIAL FLAG CONDITIONS ; THE DEFAULT CONDITIONS FOR MCOPY MAY BE READILY PATCHED BY THE USER ; VIA DDT FOR HIS DESIRED DEFAULT VALUES ; DVERFLG: DB ON ; SET VERIFY OPTION DINSP: DB OFF ; SET NO INSPECT DQUIET: DB OFF ; SET NO QUIET OPERATION DNCOPY: DB OFF ; SET NO MULTIPLE COPIES BY DEFAULT DDDISK: DB 'C'-'A' ; DEFAULT DESTINATION DISK IS C DDUSER: DB 0 ; DEFAULT DESTINATION USER IS 0 ; ; BEGINNING OF MCOPY PROGRAM ; START: CALL ZGPINS ; INIT ZCPR2 BUFFERS ; ; PRINT BANNER ; CALL BANNER ; ; SET DEFAULT FLAGS ; LDA DVERFLG ; VERIFY STA VERFLG LDA DINSP ; INSPECT STA INSP LDA DQUIET ; QUIET STA QUIET LDA DNCOPY ; MULTIPLE COPIES STA NCOPY LDA DDDISK ; GET DEFAULT DEST DISK STA DDISK ; SET DEST DISK LDA DDUSER ; GET DEFAULT DEST USER STA DUSER ; SET DEST USER ; ; OBTAIN AND SAVE CURRENT USER AND DISK ; CALL RETUD ; GET USER/DISK MOV A,B ; SAVE DISK STA CDISK STA SDISK ; SET DEFAULT SOURCE DISK MOV A,C ; SAVE USER STA CUSER STA SUSER ; SAVE DEFAULT SOURCE USER LXI H,BUFF ; PT TO COMMAND LINE CHAR COUNT CALL CLINE ; SAVE COMMAND LINE AS STRING ; ; SET OTHER FLAGS ; XRA A ; A=0 STA EXIST ; TURN OFF EXIST TEST ; ; CHECK FOR EMPTY COMMAND LINE AND PROCESS COMMAND MODE IF SO ; ON ENTRY, HL PTS TO FIRST CHAR OF STRING FROM CLINE ; START1: MOV A,M ; GET CHAR ORA A ; EOL? JZ MRUNNER ; INTERACTIVE COMMAND SESSION INX H ; PT TO NEXT CPI ' ' ; JUST SPACES? JZ START1 ; ; COMMAND LINE WAS NOT EMPTY -- CHECK FOR HELP REQUEST ; DCX H ; PT TO FIRST CHAR CPI '/' ; IF OPENING OPTION, MUST BE HELP JZ MHELP ; ; SEE IF OPTIONS ARE AVAILABLE IN THE COMMAND LINE ; SHLD MFPTR ; SET PTR TO FIRST CHAR OF FILE NAME SPECS ; ; SKIP TO END OF FILE NAME SPECS ; START2: MOV A,M ; SKIP TO OR EOL INX H ; PT TO NEXT CPI ' '+1 ; OR LESS? JNC START2 ORA A ; AT EOL? JZ MCOPY0 ; PERFORM DEFAULT MCOPY FUNCTION IF AT EOL ; ; SCAN FOR OPTION ; OPTION: MOV A,M ; GET OPTION CHAR ORA A ; EOL? JZ MCOPY0 ; DO MCOPY INX H ; PT TO NEXT PUSH H ; SAVE PTR LXI H,OPTTAB ; PT TO OPTION TABLE CALL CMDER ; PROCESS COMMAND POP H ; GET PTR JMP OPTION ; COMMAND PROCESSOR -- COMMAND LETTER IN A, HL PTS TO TABLE CMDER: PUSH B ; SAVE BC CALL CAPS ; CAPITALIZE COMMAND MOV B,A ; COMMAND IN B CMDER1: MOV A,M ; GET COMMAND LETTER ORA A ; DONE? JZ CMDER2 CMP B ; MATCH? JNZ CMDER3 CMDER2: INX H ; PT TO ADDRESS MOV E,M ; GET IT IN DE INX H MOV D,M XCHG ; HL PTS TO COMMAND ADDRESS POP B ; RESTORE BC PCHL ; RUN COMMAND CMDER3: INX H ; SKIP TO NEXT ENTRY IN TABLE INX H INX H JMP CMDER1 ; OPTION COMMAND TABLE OPTTAB: DB ' ' ; DONE DW OPTS DB OPTC ; SKIP OPTC DW OPTS DB 'E' ; EXIST TEST DW OPTE DB 'I' ; INSPECT DW OPTI DB 'M' ; MULTIPLE COPY DW OPTM DB 'Q' ; QUIET DW OPTQ DB 'V' ; VERIFY DW OPTV DB 0 ; END OF TABLE DW OHELP ; INVALID OPTION CHAR -- CLEAR STACK (RET ADR AND HL) AND PRINT HELP OHELP: POP H ; CLEAR RET ADR POP H ; CLEAR HL ; PRINT HELP MESSAGE MHELP: CALL PRINT DB 'MCOPY -- Multiple File Copy Program',CR,LF DB ' MCOPY copies files from the disk on Drive A: to several' DB CR,LF,'other disks, successively mounted on Drive ' DB 'B:',CR,LF DB ' MCOPY command line is:',CR,LF,LF DB ' MCOPY [dir:=][dir:]filename.typ[,[dir:]fn.typ][,...]' DB ' [ooo]',CR,LF,LF DB 'where options are enclosed by "[]", "dir:" is a named dir of ' DB 'the form:',CR,LF DB ' direct: (named dir) or du: (disk/user)',CR,LF DB '"filename.typ" is the ambiguous file spec of the files to ' DB 'copy ',CR,LF DB 'and "o" is none or more of:',CR,LF DB ' E -- Test of Existence of File and Allow User to ' db 'Approve',CR,LF DB ' I -- Allow User to Approve Each File (Inspect)',CR,LF DB ' M -- Enable Multiple Copy Feature',CR,LF DB ' Q -- Quiet Operation (No Activity Display)',CR,LF DB ' V -- Disable Automatic Verify',CR,LF DB ' ? -- Print this HELP information',CR,LF DB ' If "dir:=" is specified, MCOPY copies to the indicated ' DB 'directory,',CR,LF DB 'else it copies to the default directory.',CR,LF DB ' The user may interact directly with MCOPY by using just' DB CR,LF,'"MCOPY" as his command.',CR,LF DB 0 RET ; RETURN TO ZCPR2 ; VERIFY FLAG TOGGLE OPTION OPTV: CALL VT ; TOGGLE VERFLG ; SKIP OPTION OPTS: RET ; EXIST TEST TOGGLE OPTION OPTE: CALL ET ; TOGGLE EXIST RET ; NCOPY FLAG TOGGLE OPTION OPTM: CALL MT ; TOGGLE NCOPY RET ; INSPECT FLAG TOGGLE OPTION OPTI: CALL IT ; TOGGLE INSPECT RET ; QUIET FLAG TOGGLE OPTION OPTQ: CALL QT ; TOGGLE QUIET RET ; ; **** INTERACTIVE MCOPY LOOP **** ; MRUNNER: LXI SP,STACK ; RESET STACK CALL PRINT DB CR,LF,'MCOPY Status: ',0 LDA EXIST ; EXISTENCE TEST ORA A ; 0=NO MVI A,'E' ; PREP FOR CHAR CALL PMODE LDA INSP ; FILE INSPECTION ORA A ; 0=NO MVI A,'I' ; PREP FOR CHAR CALL PMODE LDA NCOPY ; MULTIPLE COPIES ORA A ; 0=NO MVI A,'M' ; PREP FOR CHAR CALL PMODE LDA QUIET ; QUIET MODE ORA A ; 0=NO MVI A,'Q' ; PREP FOR CHAR CALL PMODE LDA VERFLG ; VERIFY ORA A ; 0=NO MVI A,'V' ; PREP FOR CHAR CALL PMODE CALL PRINT DB ' -- MCOPY Command (? for Help)? ',0 CALL CIN ; GET RESPONSE CALL COUT ; ECHO LXI H,CMDTBL ; PT TO MCOPY COMMAND TABLE CALL CMDER ; PROCESS COMMANDS JMP MRUNNER ; CONTINUE ; ; MCOPY COMMAND TABLE AND EXECUTED ROUTINES ; CMDTBL: DB 'C' ; COPY DW CMDC DB 'D' ; DIRECTORY DW CMDD DB 'E' ; EXISTENCE TEST DW CMDE DB 'F' ; FREE SPACE DW CMDF DB 'I' ; INSPECT DW CMDI DB 'L' ; LOG IN DISK DW CMDL DB 'M' ; MULTIPLE COPIES DW CMDM DB 'Q' ; QUIET DW CMDQ DB 'S' ; STATUS DW CMDS DB 'V' ; VERIFY DW CMDV DB 'X' ; EXIT DW CMDX DB 'C'-'@' ; ^C DW CMDX DB 0 ; END OF TABLE DW MCPYHLP ; HELP MESSAGE ; COPY COMMAND TO COPY A SET OF FILES CMDC: CALL PRINT DB 0DH,0AH,' File Spec (=Abort)? ',0 LXI H,INBUF ; INPUT LINE BUFFER MVI A,0FFH ; CAPITALIZE INPUT CALL BLINE ; GET LINE FROM USER ORA A ; ABORT IF NONE RZ CMDC1: MOV A,M ; SKIP OVER SPACES INX H ; PT TO NEXT CPI ' ' JZ CMDC1 DCX H ; PT TO NON-SPACE CHAR ORA A ; EOL? RZ SHLD MFPTR ; PT TO FIRST CHAR OF FILE NAME SPEC CALL COPY ; COPY FILES RET ; DISPLAY DIRECTORY CMDD: CALL PRINT DB CR,LF,'** Directory Display **',0 MVI C,13 ; RESET SYSTEM CALL BDOS LXI H,0 ; SET TOTAL FILE SIZES SHLD FTOTAL CALL PRINT DB CR,LF,' File Spec (=',0 LDA DDISK ; PRINT DISK/USER ADI 'A' CALL COUT LDA DUSER CALL PADC CALL PRINT DB ':*.*)? ',0 LXI H,INBUF ; INPUT LINE BUFFER MVI A,0FFH ; CAPITALIZE INPUT CALL BLINE ; GET LINE FROM USER ORA A ; WILD IF NONE JNZ CMDD1 LXI D,WILD ; MAKE FILE SPEC WILD XCHG ; COPY INTO BUFFER MVI B,4 ; 4 BYTES CALL MOVEB XCHG ; PT TO FIRST CHAR WITH HL CMDD1: PUSH H ; SAVE PTR CALL CODEND ; GET SCRATCH AREA ADDRESS MOV B,H ; ... IN BC MOV C,L POP H LXI D,FCBS ; LOAD FCB CALL ZFNAME ; EXTRACT FILE NAME INFO JZ CMDUDER ; ERROR? MOV A,B ; GET DISK CPI 0FFH ; CURRENT DISK? JNZ CMDD2 LDA DDISK ; GET DEST DISK INR A ; ADJUST CMDD2: DCR A ; ADJUST FOR SELECT STA DDISK ; SET DEST DISK MOV A,C ; GET USER CPI '?' ; '?' IS INVALID JZ CMDUDER CPI 0FFH ; CURRENT USER? JNZ CMDD3 LDA DUSER ; GET DEST USER CMDD3: STA DUSER ; SET DEST USER CALL LOGD ; LOG IN DEST CALL CODEND ; HL PTS TO BUFFER LXI D,FCBS ; DE PTS TO FCB LDA DUSER ; GET USER ORI 0C0H ; SELECT BOTH NON-SYS AND SYS FILES CALL DIRFS ; LOAD WITH SIZING INFO JZ CMDTPA ; TPA OVERFLOW MOV A,B ; ANY FILES? ORA C ; 0=NONE JNZ CMDD4 CALL PRINT DB CR,LF,'No Matching Files',0 RET CMDD4: XRA A ; SET COUNT STA BCNT CALL CRLF ; NEW LINE CMDD5: INX H ; PT TO FILE NAME CALL PRFN ; PRINT FILE NAME DCX H ; PT TO USER CALL FSIZE ; COMPUTE FILE SIZE PUSH H ; SAVE HL LHLD FTOTAL ; GET ACCUMULATED TOTAL DAD D ; ADD IN NEW FILE SHLD FTOTAL ; NEW TOTAL POP H ; GET PTR XCHG ; FILE SIZE IN HL CALL PHLDC ; PRINT AS DECIMAL MVI A,'K' CALL COUT LXI H,16 ; PT TO NEXT ENTRY DAD D ; HL PTS TO NEXT ENTRY DCX B ; COUNT DOWN MOV A,B ; DONE? ORA C JZ CMDD6 LDA BCNT ; NEW LINE COUNT INR A STA BCNT ANI 3 ; NEW LINE EVERY 4 ENTRIES JZ CMDD5A CALL PRINT ; PRINT FENCE SINCE NOT NEW LINE DB ' ',0 JMP CMDD5 CMDD5A: CALL CRLF ; NEW LINE JMP CMDD5 CMDD6: CALL PRINT DB CR,LF,'** ',0 LHLD FTOTAL ; PRINT TOTAL SPACE USED CALL PHLDC ; PRINT AS DECIMAL CALL PRINT DB 'K Occupied by Displayed Files, ',0 CALL DFREE ; COMPUTE AMOUNT OF FREE SPACE LEFT ON DISK XCHG ; HL=FREE SPACE CALL PHLDC ; PRINT AS DEC CALL PRINT DB 'K Remaining on Disk ',0 LDA DDISK ; PRINT DISK LETTER ADI 'A' CALL COUT CALL PRINT DB ' **',0 RET CMDUDER: CALL PRINT DB CR,LF,'Invalid User or Disk Specified',0 RET CMDTPA: CALL PRINT DB CR,LF,'TPA Overflow',0 RET WILD: DB '*.*',0 ; COMPUTE AMOUNT OF FREE SPACE LEFT ON DESTINATION DISK CMDF: CALL PRINT DB CR,LF,'** Free Space Data **',0 MVI C,13 ; RESET SYSTEM CALL BDOS CALL PRINT DB CR,LF,' Disk (=',0 LDA DDISK ; GET DEST DISK ADI 'A' ; CONVERT TO LETTER CALL COUT CALL PRINT DB ')? ',0 CALL CIN ; GET RESPONSE CALL CAPS CALL COUT CALL CRLF ; NEW LINE CPI CR ; SOURCE DISK? JZ CMDF1 CPI ' ' ; SOURCE DISK? JZ CMDF1 SUI 'A' ; CONVERT TO DISK NUMBER STA DDISK ; SET DISK JC CMDFER MOV B,A ; SAVE IN B LDA MDISK ; COMPARE AGAINST MAX CMP B JC CMDFER CMDF1: CALL LOGD ; LOG IN DEST CALL DPARAMS ; GET DISK PARAMETERS CALL DFREE ; COMPUTE FREE SPACE XCHG ; HL=SPACE CALL CRLF CALL PHLDC ; PRINT AS DECIMAL CALL PRINT DB 'K Bytes Remaining on Disk ',0 LDA DDISK ADI 'A' CALL COUT RET CMDFER: CALL PRINT DB CR,LF,'Error -- Disk Letter Invalid',0 RET ; TOGGLE INSPECT CMDI: CALL ITOG ; TOGGLE WITH MESSAGE RET ; LOG IN NEW USER/DISK CMDL: CALL PRINT DB CR,LF,'Select Current Disk/User --',0 LXI H,CDISK ; PT TO ENTRY CALL CMDL0 CALL PRINT DB CR,LF,'Select Source Disk/User --',0 LXI H,SDISK ; PT TO ENTRY CALL CMDL0 CALL PRINT DB CR,LF,'Select Destination Disk/User --',0 LXI H,DDISK ; PT TO ENTRY CMDL0: CALL PRINT DB CR,LF,' New Disk (=',0 MOV A,M ; GET DISK ADI 'A' CALL COUT CALL PRINT DB ')? ',0 CALL CIN ; GET RESPONSE CALL CAPS CALL COUT CALL CRLF CPI CR JZ CMDL1 CPI ' ' JZ CMDL1 SUI 'A' ; CONVERT TO NUMBER JC CMDLER MOV B,A LDA MDISK ; CHECK AGAINST MAX CMP B JC CMDLER MOV A,B ; GET SELECTED DISK MOV M,A ; PUT DISK CMDL1: INX H ; PT TO USER CMDL2: PUSH H ; SAVE PTR CALL PRINT DB ' New User (=',0 MOV A,M ; GET USER NUMBER CALL PADC CALL PRINT DB ')? ',0 LXI H,INBUF ; GET INTO INPUT LINE BUFFER MVI A,0FFH ; CAPITALIZE CALL BLINE POP D ; GET PTR TO USER ORA A ; ANY RESPONSE? RZ PUSH D ; SAVE PTR TO USER CALL EVAL ; EVALUATE POP H ; GET PTR TO USER MOV A,D ; GET RESULT ORA A ; MUST BE ZERO HIGH JNZ CMDLUER LDA MUSER ; CHECK AGAINST MAX CMP E JC CMDLUER MOV A,E ; GET NUMBER MOV M,A ; PUT USER RET CMDLER: CALL PRINT DB CR,LF,'Invalid Disk -- Reenter',0 JMP CMDL0 CMDLUER: CALL PRINT DB CR,LF,'Invalid User -- Reenter',0 JMP CMDL2 ; TOGGLE EXIST CMDE: CALL ETOG ; TOGGLE WITH MESSAGE RET ; TOGGLE NCOPY CMDM: CALL MTOG ; TOGGLE WITH MESSAGE RET ; TOGGLE QUIET CMDQ: CALL QTOG ; TOGGLE WITH MESSAGE RET ; DISPLAY STATUS CMDS: CALL PRINT DB CR,LF,'Current Disk/User is ',0 LXI H,CDISK CALL CMDS1 CALL PRINT DB CR,LF,'Source Disk/User is ',0 LXI H,SDISK CALL CMDS1 CALL PRINT DB CR,LF,'Destination Disk/User is ',0 LXI H,DDISK CMDS1: MOV A,M ; GET DISK ADI 'A' CALL COUT INX H MOV A,M ; GET USER CALL PADC MVI A,':' CALL COUT RET ; TOGGLE VERIFY CMDV: CALL VTOG ; TOGGLE WITH MESSAGE RET ; EXIT TO CP/M CMDX: CALL PRINT DB CR,LF,'** MCOPY Exiting **',0 JMP CPM ; TOGGLE QUIET FUNCTION QT: LDA QUIET ; GET FLAG CMA ; FLIP IT STA QUIET ; PUT FLAG RET ; TOGGLE EXIST TEST FUNCTION ET: LDA EXIST ; GET FLAG CMA ; FLIP IT STA EXIST ; PUT FLAG RET ; TOGGLE NCOPY FUNCTION (MULTIPLE COPIES) MT: LDA NCOPY ; GET FLAG CMA ; FLIP IT STA NCOPY ; PUT FLAG RET ; TOGGLE INSPECT FUNCTION IT: LDA INSP ; GET FLAG CMA ; FLIP IT STA INSP ; PUT FLAG RET ; TOGGLE VERIFY FUNCTION VT: LDA VERFLG ; GET FLAG CMA ; FLIP IT STA VERFLG ; PUT FLAG RET ; TOGGLE INSPECT MODE AND PRINT MESSAGE ITOG: CALL IT ; TOGGLE AND FALL THRU TO PRINT ; PRINT INSPECT MESSAGE IMSG: CALL PRINT DB CR,LF,' File Selection Inspect Mode ',0 LDA INSP ENPRT: ORA A ; 0=NO JZ ENPRT1 CALL PRINT DB 'Enabled',0 RET ENPRT1: CALL PRINT DB 'Disabled',0 RET ; TOGGLE EXIST TEST AND PRINT MESSAGE ETOG: CALL ET ; TOGGLE AND FALL THRU TO PRINT ; PRINT EXIST STATUS EMSG: CALL PRINT DB CR,LF,' Existence Test Function ',0 LDA EXIST JMP ENPRT ; TOGGLE MULTIPLE COPY AND PRINT MESSAGE MTOG: CALL MT ; TOGGLE AND FALL THRU TO PRINT ; PRINT MCOPY STATUS MMSG: CALL PRINT DB CR,LF,' Multiple Copy Function ',0 LDA NCOPY JMP ENPRT ; TOGGLE QUIET AND PRINT MESSAGE QTOG: CALL QT ; TOGGLE AND FALL THRU TO PRINT ; PRINT QUIET STATUS QMSG: CALL PRINT DB CR,LF,' Quiet Operation ',0 LDA QUIET JMP ENPRT ; TOGGLE VERIFY AND PRINT MESSAGE VTOG: CALL VT ; TOGGLE AND FALL THRU TO PRINT ; PRINT VERIFY STATUS VMSG: CALL PRINT DB CR,LF,' Copy Verification ',0 LDA VERFLG JMP ENPRT ; PRINT MCOPY COMMAND HELP MESSAGE MCPYHLP: CALL PRINT DB CR,LF,' MCOPY Status: E I M Q V' DB CR,LF,'These Status Characters have the following meanings:' DB CR,LF,' E - File Existence Test Mode is ON' DB CR,LF,' I - File Selection Inspect Mode is ON' DB CR,LF,' M - Multiple Copy Function Mode is ON' DB CR,LF,' Q - Quiet Mode is ON' DB CR,LF,' V - Verify Mode is ON' DB CR,LF DB CR,LF,'The Status Characters, as commands, toggle their ' DB 'respective modes.' DB CR,LF,'Other valid MCOPY Commands are:' DB CR,LF,' C - Copy a File or Set of Files' DB CR,LF,' D - Directory Display' DB CR,LF,' F - Compute Amount of Free Space on Disk' DB CR,LF,' L - Log in New User/Disks' DB CR,LF,' S - Display MCOPY Status (Cur and Dest User/Disk)' DB CR,LF,' X or ^C - Exit MCOPY' DB 0 RET ; PRINT CHAR IN A IF NZ, ELSE PRINT PMODE: JZ PMODE1 ; PRINT JMP COUT ; PRINT CHAR PMODE1: MVI A,' ' ; PRINT JMP COUT ; ; PRINT MCOPY BANNER ; BANNER: CALL PRINT DB 'MCOPY Version ' DB VERS/10+'0','.',(VERS MOD 10)+'0',0 RET ; ; **** MCOPY of COMMAND LINE **** ; MCOPY0: LXI SP,STACK ; SET STACK LDA NCOPY ; MULTIPLE COPIES? ORA A ; 0=NO JZ NOPAUSE CALL SAKCHK ; STRIKE ANY KEY CHECK JZ CPM ; WARM BOOT IF ABORT NOPAUSE: CALL COPY ; DO THE COPY JMP CPM ; WARM BOOT WHEN DONE ; ; **** Begin Multiple Copy Procedure **** ; COPY: LHLD MFPTR ; PT TO FIRST FILE NAME SHLD NXTPTR ; SET PTR TO NEXT FILE NAME LXI H,0 ; HL=0 SHLD FCOUNT ; ZERO FILE COUNT SHLD VERCNT ; ZERO ERROR COUNT LDA EXIST ; IF EXIST, THEN MUST NOT BE QUIET ORA A ; 0=NO EXIST JZ MCOPY XRA A ; SET NO QUIET STA QUIET ; ; **** MAIN COPY LOOP **** ; MCOPY: LHLD NXTPTR ; GET PTR TO NEXT FILE NAME MOV A,M ; GET FIRST CHAR CPI ' '+1 ; DONE IF OR LESS JNC MCOPY1 ; CONTINUE WITH PROCEDURE ; ; MCOPY OF FILE SPECS IS NOW DONE ; DONE WITH COPY PROCEDURE -- CONTINUE? ; COPYT: CALL PRINT DB CR,LF,'**** MCOPY Complete ****',CR,LF,' ',0 LHLD FCOUNT ; GET FILE COUNT CALL PHLDC ; PRINT AS DECIMAL CALL PRINT DB ' File',0 MOV A,H ; 1 FILE? ORA A JNZ COPYT1 MOV A,L CPI 1 ; 1 FILE? JZ COPYT2 COPYT1: MVI A,'s' ; ENDING S CALL COUT COPYT2: CALL PRINT DB ' Copied ',0 LHLD VERCNT ; GET ERROR COUNT CALL PHLDC ; PRINT AS DECIMAL CALL PRINT DB ' Copy Errors',0 LDA NCOPY ; MULTIPLE COPIES? ORA A ; 0=NO RZ CALL SAKCHK ; CHECK FOR STRIKE OF ANY KEY RZ ; RETURN IF ABORT JMP COPY ; COPY AGAIN FROM THE BEGINNING ; ; BEGIN COPY OF FILE GROUP ; MCOPY1: CPI ',' ; SKIP COMMA SEPARATOR IF THERE JNZ MCPY0 INX H ; PT TO CHAR AFTER COMMA MCPY0: MOV A,M ; GET NEXT CHAR CPI ' '+1 ; CHECK FOR ERROR JC FORMERR PUSH H ; SAVE PTR TO NEXT FILE NAME CALL CODEND ; GET ADDRESS OF SCRATCH AREA MOV B,H ; BC=ADDRESS OF SCRATCH AREA MOV C,L LXI D,FCBS ; GET POSSIBLE SOURCE FCB POP H ; GET PTR TO NEXT FILE SPEC CALL ZFNAME ; EXTRACT FILE NAME DATA JZ UDERR ; ERROR? MOV A,M ; GET DELIMITER CPI '=' ; IF '=', WE HAVE A NEW DISK/USER JNZ MCOPY2 ; FORM IS DIRS:FN.FT IF NO '=' ; ; FORM IS DIRD:=DIRS:FN.FT, SO SET DEST DISK/USER ; MOV A,B ; CHECK FOR ANY DISK OR USER CHANGE ANA C ; IF BOTH FF, THEN NO CHANGE CPI 0FFH ; BOTH FF? JZ MCPY2 LDA CDISK ; SET DEST TO CURRENT SINCE A CHANGE IS EXPECTED STA DDISK ; ... IN THIS WAY, A NEW DEST OF U: OR D: IS LDA CUSER ; ... INTERPRETED AS $U: OR D$: (I.E., IF LOGGED INTO STA DUSER ; ... B, A DEST OF 1: IS B1:) MOV A,B ; CHECK FOR DISK CHANGE CPI 0FFH ; 0FFH=NO CHANGE JZ MCPY1 DCR A ; ADJUST STA DDISK ; SET NEW DEFAULT DISK MCPY1: MOV A,C ; CHECK FOR USER CHANGE CPI 0FFH ; 0FFH=NO CHANGE JZ MCPY2 CPI '?' ; ALL USERS NOT PERMITTED JZ UDERR STA DUSER ; SET NEW DEFAULT USER ; ; NOW DERIVE DIRS:FN.FT FORM AFTER THE '=' ; MCPY2: INX H ; PT TO CHAR BEYOND '=' MOV A,M ; GET CHAR CPI ' '+1 ; FORMAT ERROR? JC FORMERR PUSH H ; SAVE PTR CALL CODEND ; GET END OF CODE MOV B,H ; ... IN BC MOV C,L POP H ; GET PTR TO NAME LXI D,FCBS ; LOAD FCB CALL ZFNAME ; GET SOURCE NAME JZ UDERR ; ERROR? ; ; SAVE PTR TO NEXT CHAR AFTER DIRS:FN.FT, AND SET SOURCE DISK/USER ; MCOPY2: SHLD NXTPTR ; SAVE PTR TO NEXT CHAR MOV A,B ; CHECK FOR NO DISK OR USER CHANGE ANA C CPI 0FFH ; BOTH FF? JZ MCPY22 LDA CDISK ; IF CHANGE IN EITHER, ASSUME OLD SOURCE TO BE CURRENT STA SDISK LDA CUSER STA SUSER MOV A,B ; CHECK FOR DISK CHANGE CPI 0FFH ; 0FFH=NO CHANGE JZ MCPY21 DCR A ; ADJUST STA SDISK ; SET NEW DEFAULT DISK MCPY21: MOV A,C ; CHECK FOR USER CHANGE CPI 0FFH ; 0FFH=NO CHANGE JZ MCPY22 CPI '?' ; ALL USERS NOT PERMITTED JZ UDERR STA SUSER ; SET NEW DEFAULT USER MCPY22: CALL PRINT DB CR,LF,' Copy ',0 LDA SDISK ; GET NUMBER ADI 'A' ; CONVERT TO LETTER CALL COUT ; PRINT LDA SUSER ; PRINT USER NUMBER CALL PADC MVI A,':' ; SEPARATOR CALL COUT MVI A,' ' CALL COUT LXI H,FCBS+1 ; PRINT FILE SPEC CALL PRFN CALL PRINT DB ' to ',0 LDA DDISK ; GET NUMBER ADI 'A' ; CONVERT TO LETTER CALL COUT ; PRINT LDA DUSER ; PRINT USER NUMBER CALL PADC MVI A,':' CALL COUT MVI C,13 ; RESET DISK SYSTEM CALL BDOS CALL LOGS ; LOG IN SOURCE USER/DISK LXI D,FCBS ; PT TO SOURCE FCB CALL INITFCB ; INIT FCB CALL CODEND ; PT TO BUFFER AREA LDA SUSER ; PREPARE FLAG FOR SELECTION ANI 1FH ; ONLY USER NUMBER ORI 0C0H ; SELECT NON-SYS AND SYS FILES CALL DIRF ; LOAD DIR, SELECT FILES, SORT, ETC JZ TPAOVFL ; TPA OVERFLOW ERROR? LDA INSP ; INSPECT FILES? ORA A ; 0=NO CNZ INSPF ; INSPECT FILES IF OPTION SELECTED MOV A,B ; CHECK FOR ANY FILES TO COPY ORA C ; 0=NONE JNZ MCPY24 MCPY23: CALL PRINT DB CR,LF,'** NO Files Selected **' DB CR,LF,'** Strike ^C to Abort, Anything Else to Continue: ',0 CALL CIN ; GET RESPONSE CPI 'C'-'@' ; ABORT? JZ COPYT ; END TEST JMP MCOPY ; CONTINUE WITH NEXT MCPY24: PUSH H ; SAVE PTR AND COUNT PUSH B LXI D,16 ; SKIP TO END OF LOADED FILES AND MARK BEGINNING OF ; WORK AREA MCPY25: DAD D ; PT TO NEXT DCX B ; COUNT DOWN MOV A,B ; DONE? ORA C JNZ MCPY25 MVI A,64 ; SET PAGE LIMIT TO 16K STA PAGLIM SHLD WORKBF ; SAVE PTR TO BEGINNING OF WORK BUFFER LDA BDOSE+2 ; GET BASE PAGE OF BDOS SUI 10 ; GET BELOW BASE PAGE OF CCP SUB H ; COMPUTE SIZE OF BUFFER AREA CPI 64 ; 64 PAGES LEFT? JNC PAGOK STA PAGLIM ; SET PAGE LIMIT PAGOK: POP B ; RESTORE PTRS POP H ; ; MAIN COPYING LOOP ; FILE NAMES ARE PTED TO BY HL AND BC=NUMBER OF FILES ; MCPY26: PUSH H ; SAVE REGS PUSH B CALL MCOPYX ; COPY SOURCE (HL) TO DESTINATION USING WORK BUFFER LDA QUIET ; CHECK FOR QUIET ORA A ; NZ=QUIET JNZ MCPY27 CALL PRINT DB CR,LF,' Copy Complete',0 MCPY27: LDA LSTCPY ; LAST FILE COPIED? ORA A ; 0=NO JZ MCPY28 LDA VERFLG ; VERIFY? ORA A ; 0=NO CNZ MCOPYV ; DO VERIFY LHLD FCOUNT ; COUNT FILES INX H SHLD FCOUNT MCPY28: POP B ; GET REGS POP H LXI D,16 ; PT TO NEXT FILE DAD D ; HL PTS TO NEXT FILE DCX B ; COUNT DOWN MOV A,B ORA C JNZ MCPY26 JMP MCOPY ; COPY NEXT FILE SPEC ; ; COPY SOURCE FILE PTED TO BY HL TO DESTINATION ; MCOPYX: XRA A ; SET NO COPY OF LAST FILE STA LSTCPY ; SET FLAG LXI D,FCBS ; SET SOURCE FCB MVI B,12 ; 12 BYTES CALL MOVEB CALL INITFCB ; INIT SOURCE FCB LXI D,FCBD ; SET DESTINATION FCB MVI B,12 ; 12 BYTES CALL MOVEB CALL DRW ; CLEAR ATTRIBUTES IN FCB CALL INITFCB ; INIT DESTINATION FCB CALL LOGD ; LOG IN DESTINATION LXI D,FCBD ; PT TO FCB CALL F$EXIST ; DOES DEST EXIST? JZ FNF ; FILE NOT FOUND IF ZERO LDA QUIET ; QUIET? ORA A ; 0=NO JNZ FFND CALL PRINT DB CR,LF,'Original File ',0 LXI H,FCBD+1 ; PRINT FILE NAME CALL PRFN CALL PRINT DB ' on Destination',0 FFND: CALL EATEST ; EXIST APPROVED TEST? RZ ; NOT APPROVED, SO ABORT CALL DESTRW ; MAKE DESTINATION R/W IF NOT ALREADY CALL F$DELETE ; DELETE FILE CALL INITFCB ; REINIT FCB JMP FNF1 ; CREATE NEW FILE AND CONTINUE FNF: LDA QUIET ; QUIET? ORA A ; 0=NO JNZ FNF1 CALL PRINT DB CR,LF,'No Original File ',0 LXI H,FCBD+1 ; PRINT FILE NAME CALL PRFN CALL PRINT DB ' on Destination',0 CALL EATEST ; EXIST APPROVED? RZ ; NO? FNF1: MVI A,0FFH ; SET COPY OF LAST FILE STA LSTCPY ; SET FLAG CALL F$MAKE ; CREATE NEW FILE ; ; OPEN SOURCE FILE IN PREP FOR COPY ; CALL CRCCLR ; CLEAR CRC VALUE CALL LOGS ; LOG IN SOURCE DISK LXI D,FCBS ; INIT FCB CALL INITFCB CALL F$OPEN ; OPEN FILE CALL CRLF ; NEW LINE LXI H,0 SHLD RKCNT ; SET READ K COUNT SHLD WKCNT ; SET WRITE K COUNT ; ; THIS LOOP, WHICH STARTS AT MCPYX, COPIES THE FILE FROM SOURCE TO DEST ; MCPYX: CALL LOGS ; LOG IN SOURCE LXI D,FCBS ; PT TO SOURCE FCB LHLD WORKBF ; PT TO BUFFER TO COPY INTO CALL LOAD ; LOAD FILE INTO WORKBF LDA BCNT ; IF COUNT=0, THEN DONE ORA A JZ MC2DONE ; ; COPY TO DISK ; MCPYD: CALL LOGD ; LOG IN DESTINATION LDA QUIET ; CHECK FOR QUIET ORA A ; Z=NOT QUIET JNZ MCPYD0 CALL PRINT DB ' Writing .....K',0 MCPYD0: LHLD WORKBF ; PT TO BUFFER MCPYD1: LXI D,BUFF ; COPY DATA TO BUFFER MVI B,128 ; 128 BYTES CALL MOVEB ; COPY IT LXI D,128 ; INCR HL BY 128 DAD D ; HL PTS TO NEXT BLOCK LXI D,FCBD ; WRITE TO DESTINATION FILE CALL F$WRITE ORA A ; OK? JNZ MCPYDERR ; COUNT DOWN TO NEXT BLOCK LDA BCNT ; PRINT BLIPS ANI 7 ; MASK JNZ MCPYD2 LDA QUIET ; CHECK FOR QUIET ORA A ; Z=NOT QUIET JNZ MCPYD2 PUSH H ; SAVE HL LHLD WKCNT ; INCREMENT WRITE K COUNT INX H SHLD WKCNT CALL PRKCNT ; PRINT K COUNT POP H MCPYD2: LDA BCNT ; GET BLOCK COUNT DCR A ; COUNT DOWN STA BCNT JNZ MCPYD1 LDA QUIET ; CHECK FOR QUIET OPERATION ORA A ; Z=NOT QUIET CZ CRLF ; NEW LINE LDA CONT ; CONTINUE? ORA A ; CONT IF NOT ZERO JNZ MCPYX ; ; END OF COPY LOOP ; MC2DONE: CALL LOGS ; LOG IN SOURCE LXI D,FCBS ; CLOSE SOURCE CALL F$CLOSE CALL LOGD ; LOG IN DESTINATION LXI D,FCBD ; CLOSE DESTINATION CALL F$CLOSE CALL CRCDONE ; GET CRCK VALUE SHLD CRCVAL ; SAVE CRC VALUE CALL LOGS ; LOG IN SOURCE DRIVE LXI D,FCBS ; FIND SOURCE MVI C,17 ; SEARCH FOR FIRST CALL BDOS RLC ; MULTIPLY BY 32 TO GET OFFSET RLC RLC RLC RLC ANI 0E0H ; MASK OUT LSB MOV L,A ; VALUE IN L MVI H,0 LXI D,BUFF ; ADD IN BUFFER BASE DAD D LXI D,FCBT MVI B,16 ; MOVE 16 BYTES CALL MOVEB CALL LOGD ; LOG IN DESTINATION DRIVE LXI D,FCBT CALL INITFCB ; INIT FCB MVI C,30 ; SET FILE ATTRIBUTES CALL BDOS RET ; MCOPYX RETURN ; FORMAT ERROR FORMERR: CALL PRINT DB CR,LF,'MCOPY -- Format Error in Command Line' DB CR,LF,'Error Starts at: ',0 CALL PSTR ; PRINT ERROR RET ; USER/DISK ERROR UDERR: CALL PRINT DB CR,LF,'MCOPY -- Error in User Number or Disk Letter',0 RET ; TPA OVERFLOW TPAOVFL: CALL PRINT DB CR,LF,'MCOPY -- TPA Overflow -- Aborting',0 JMP CPM ; WRITE ERROR MCPYDERR: CALL PRINT DB CR,LF,'MCOPY -- Error in Creating Destination File',0 JMP CPM ; TEST FOR EXISTENCE REQUIREMENT AND GET USER RESPONSE EATEST: LDA EXIST ; EXISTENCE TEST ON? ORA A ; 0=NO JZ EAT1 CALL PRINT DB CR,LF,' -- Approve Copy (Y/N/other=Y)? ',0 CALL CIN ; GET RESPONSE CALL CAPS CPI CR ; YES? JZ EAT1 ; COPY IF SO CALL COUT CPI 'N' ; NO? JNZ EAT1 ; COPY IF NOT NO CALL PRINT DB ' -- Disapproved',0 XRA A ; ZERO FOR NOT APPROVED RET EAT1: MVI A,0FFH ; SET NZ FOR APPROVED ORA A ; SET FLAGS RET ; ; MAKE DESTINATION FCB ENTRY R/W AND DIR ; DRW: LXI H,FCBD+9 ; CLEAR ATTRIBUTES OF DEST MOV A,M ; GET IT ANI 7FH ; CLEAR IT MOV M,A INX H ; SAME TO NEXT MOV A,M ; GET IT AND CLEAR IT ANI 7FH MOV M,A RET DESTRW: CALL DRW ; MAKE ATTRIBUTES R/W AND NON-SYS LXI D,FCBD ; SET ATTRIBUTES MVI C,30 CALL BDOS RET ; ; LOAD BUFFER PTED TO BY HL FROM FILE WHOSE FCB IS PTED TO BY DE ; ON OUTPUT, BCNT=NUMBER OF BLOCKS LOADED (UP TO 128) AND ; CONT=0 IF DONE OR 128 IF NOT DONE ; LOAD: XRA A ; A=0 STA BCNT ; SET BLOCK COUNT STA CONT ; TURN OFF CONTINUATION FLAG LDA QUIET ; QUIET? ORA A ; 0=NO JNZ MCPY CALL PRINT DB 'Reading .....K',0 ; MAIN COPY LOOP MCPY: CALL F$READ ; READ BLOCK ORA A ; END OF FILE? RNZ ; RETURN PUSH D ; SAVE PTR TO FCB XCHG ; SAVE PTR TO DESTINATION BUFFER IN DE LHLD BDOSE+1 ; GET TOP OF TPA XCHG ; ... IN DE, DEST IN HL MOV A,H ; IF SAME PAGE, WE ARE IN OVERFLOW CMP D ; D MUST BE > H JNC TPAOVFL ; OVERFLOW IF D<=H LXI D,BUFF ; PT TO BUFFER TO COPY FROM MVI B,128 ; COPY 128 BYTES XCHG ; HL PTS TO SOURCE, DE PTS TO DESTINATION MCPYCRC: MOV A,M ; GET BYTE STAX D ; PUT BYTE CALL CRCUPD ; UPDATE CRC INX H ; PT TO NEXT INX D DCR B ; COUNT DOWN JNZ MCPYCRC XCHG ; HL PTS TO DESTINATION AGAIN POP D ; GET PTR TO FCB LDA BCNT ; GET BLOCK COUNT INR A ; INCREMENT IT STA BCNT ; SET IT PUSH PSW ; PRINT BLIP FOR EVERY 1K ANI 7 ; CHECK FOR EVERY 8 BLOCKS JNZ NOBLIP LDA QUIET ; CHECK FOR QUIET ORA A ; Z=NOT QUIET JNZ NOBLIP PUSH H ; SAVE HL LHLD RKCNT ; INCREMENT READ K COUNT INX H SHLD RKCNT CALL PRKCNT ; PRINT K COUNT POP H NOBLIP: LDA PAGLIM ; GET PAGE LIMIT ADD A ; DOUBLE IT FOR BLOCKS MOV B,A ; LIMIT IN B POP PSW ; GET BLOCK COUNT CMP B ; BUFFER FULL? JNZ MCPY STA CONT ; SET CONTINUATION FLAG RET ; ; VERIFY PHASE ; MCOPYV: LDA QUIET ; CHECK FOR QUIET ORA A ; NZ=QUIET JNZ MCPYV CALL PRINT DB ', Verify Phase --',CR,LF,0 LXI H,0 ; SET READ K COUNT SHLD RKCNT MCPYV: CALL CRCCLR ; CLEAR CRCK VALUE CALL LOGD ; LOG IN DESTINATION LXI D,FCBD ; CLEAR DESTINATION FCB CALL INITFCB ; INIT FCB CALL F$OPEN ; OPEN FILE ; **** MAIN VERIFY LOOP **** VERLOOP: LHLD WORKBF ; LOAD INPUT BUFFER FROM DESTINATION LXI D,FCBD CALL LOAD ; LOAD AND COMPUTE CRC VALUE LDA BCNT ; DONE IF NO BYTES LOADED ORA A JZ VERCRC LDA QUIET ; NEW LINE IF NOT QUIET ORA A ; 0=NOT QUIET CZ CRLF LDA CONT ; CONTINUE? ORA A ; 0=NO JNZ VERLOOP ; VERIFY DONE VERCRC: LHLD CRCVAL ; GET OLD CRC VALUE XCHG ; ... IN DE CALL CRCDONE ; UPDATE COMPLETE CALL COMPHD ; COMPARE HL TO DE JNZ VERERR LDA QUIET ; CHECK FOR QUIET ORA A ; NZ=QUIET RNZ CALL PRINT DB ' Verify Complete',0 RET ; VERIFY ERROR VERERR: LHLD VERCNT ; INCREMENT ERROR COUNT INX H SHLD VERCNT CALL PRINT DB ' ** Verify Error **',7,0 RET ; ; **** MCOPY Utilities **** ; ; ; PRINT K COUNT -- BACK UP 6 SPACES AND PRINT NUMBER IN HL FOLLOWED BY A K ; PRKCNT: PUSH B ; SAVE BC MVI B,6 ; BACK UP MVI A,'H'-'@' ; ^H=BACKSPACE PRKCNT1: CALL COUT ; BACK UP DCR B ; COUNT DOWN JNZ PRKCNT1 CALL PHLDC ; PRINT AS DECIMAL MVI A,'K' ; PRINT ENDING K CALL COUT POP B RET ; ; CHECK TO SEE IF USER WANTS TO CONTINUE ; SAKCHK: CALL PRINT DB CR,LF,' Strike RETURN when Ready or ^C or A to Abort - ',0 CALL CIN ; GET RESPONSE CALL CRLF ; NEW LINE CALL CAPS ; CAPITALIZE CPI 'C'-'@' ; ^C? RZ CPI 'A' ; ABORT? RET ; ; ALLOW USER TO INSPECT FILES FOR COPY ; FIRST FILE NAME PTED TO BY HL, BC = NUMBER OF FILES ; ON EXIT, BC = NUMBER OF SELECTED FILES ; INSPF: PUSH H ; SAVE PTR TO FIRST FILE PUSH B ; SAVE FILE COUNT LXI D,16 ; ENTRIES ARE 16 BYTES APART INSPF0: MOV A,M ; MARK FILE FOR NO COPY ANI 7FH ; CLEAR MSB FOR NO COPY MOV M,A DAD D ; PT TO NEXT DCX B ; COUNT DOWN MOV A,B ; DONE? ORA C JNZ INSPF0 POP B ; RESTORE AND SAVE AGAIN POP H PUSH H PUSH B INSPF1: PUSH H ; SAVE PTR TO FILE INX H ; PT TO FN CALL CRLF ; NEW LINE CALL PRFN ; PRINT IT POP H ; GET PTR TO FILE CALL PRINT DB ' -- Copy (Y/N/S=Skip Rest/=Y)? ',0 CALL CIN ; GET RESPONSE CALL CAPS ; CAPITALIZE CALL COUT ; ECHO CPI 'S' ; SKIP? JZ INSPFA CPI 'N' ; NO? JZ INSPF2 MOV A,M ; GET USER NUMBER ORI 80H ; MARK FILE MOV M,A ; SET USER NUMBER INSPF2: LXI D,16 ; PT TO NEXT FILE DAD D DCX B ; COUNT DOWN MOV A,B ; DONE? ORA C JNZ INSPF1 INSPFA: POP B ; GET COUNT POP H ; GET PTR TO FIRST FILE JMP DIRPACK ; REPACK DIRECTORY ; ; LOG IN SOURCE USER/DISK ; LOGS: LDA SUSER ; USER MOV C,A ; ... IN C LDA SDISK ; DISK MOV B,A ; ... IN B JMP LOGUD ; LOG IN USER/DISK ; ; LOG IN DESTINATION USER/DISK ; LOGD: LDA DUSER ; USER MOV C,A ; ... IN C LDA DDISK ; DISK MOV B,A ; ... IN B JMP LOGUD ; LOG IN USER/DISK ; ; PRINT FILE NAME ; PRFN: PUSH H ; SAVE REGS PUSH B MVI B,8 ; PRINT 8 CHARS CALL PRFN1 MVI A,'.' ; DOT CALL COUT MVI B,3 ; PRINT 3 CHARS CALL PRFN1 POP B ; GET REGS POP H RET PRFN1: MOV A,M ; GET CHAR INX H ; PT TO NEXT CALL COUT ; PRINT IT DCR B ; COUNT DOWN JNZ PRFN1 RET ; ; **** BUFFERS **** ; ; COMMAND LINE BUFFER BUFSIZ EQU 200 ; SIZE OF COMMAND LINE BUFFER INBUF: DB BUFSIZ ; FOR USE WITH INPUT LINE EDITOR DB 0 DS BUFSIZ+1 ; INPUT COMMAND LINE ; POINTERS MFPTR: DS 2 ; PTR TO FIRST CHAR OF NEXT FN SPEC NXTPTR: DS 2 ; PTR TO NEXT FN SPEC IN LINE WORKBF: DS 2 ; PTR TO BEGINNING OF WORK BUFFER ; FLAGS COPIED FROM DEFAULTS VERFLG: DS 1 ; VERIFY INSP: DS 1 ; INSPECT QUIET: DS 1 ; QUIET NCOPY: DS 1 ; MULTIPLE COPY ; DISKS AND USERS -- ORDER IS IMPORTANT -- cUSER MUST FOLLOW cDISK CDISK: DS 1 ; CURRENT DISK CUSER: DS 1 ; CURRENT USER SDISK: DS 1 ; SOURCE DISK SUSER: DS 1 ; SOURCE USER DDISK: DS 1 ; DESTINATION DISK DUSER: DS 1 ; DESTINATION USER ; CRC VALUE CRCVAL: DS 2 ; CRC CHECK VALUE ; FCBS FCBS: DS 40 ; SOURCE FCB FCBD: DS 40 ; DESTINATION FCB FCBT: DS 40 ; TEMPORARY FCB FOR ATTRIBUTE SETTINGS ; COUNTS AND FLAGS RKCNT: DS 2 ; READ K COUNT WKCNT: DS 2 ; WRITE K COUNT PAGLIM: DS 1 ; MAX NUMBER OF PAGES IN WORK BUFFER LSTCPY: DS 1 ; LAST FILE WAS COPIED FLAG EXIST: DS 1 ; TEST FOR EXISTENCE FLAG FTOTAL: DS 2 ; TOTAL SIZE OF FILES FCOUNT: DS 2 ; NUMBER OF FILES VERCNT: DS 2 ; ERROR COUNT BCNT: DS 1 ; BLOCK COUNT CONT: DS 1 ; CONTINUE FLAG (0=NO, 0FFH=YES) ; STACK AREA DS 100 ; 50-ELEMENT STACK STACK EQU $ DB 0 ; END OF MAINLINE END