; MULTIPLE FILE COPY PROGRAM ; COPYRIGHT 1982, G. YOUNG, INC. ; UPDATED 10/9/82 * * TO EXECUTE, ENTER THE PROGRAM NAME FOLLOWED BY THE FILE MASK: * A>MULTCOPY *.COM * * THE PURPOSE OF THIS PROGRAM IS TO COPY MULTIPLE FILES TO A FLOPPY DISK * FROM A HARD DISK. IF YOU USED PIP FOR D:=*.COM AND THER WERE MORE * COM FILES THAN WOULD FIT ON ONE DISK, PIP WOULD STOP WHEN THE FIRST * DISK WAS FULL. IF MULTCOPY, WHEN ONE DISK WAS FULL, IT WOULD ASK * YOU TO MOUNT A NEW DISK AND CONTINUE COPYING. THE FLOPPY DISK DRIVE * IS HARD CODED INTO THE PROGRAM. THE SOURCE MAY BE ANY HARD DISK. * EXAMPLE MULTCOPY B:LN*.ASM * CHANGED 10/9/82 TO ASK DESTINATION FLOPPY DRIVE * WRITTEN BY GARY YOUNG, BOX 3218, NO. HOLLYWOOD, CA 91609 TITLE '*** MULTCOPY FILE COPY PROGRAM ***' BDOS EQU 5 RECSIZE EQU 12 BOOT EQU 0 ORG 100H JMP START DB 'COPYRIGHT 1982, G. YOUNG, INC.' START LXI SP,STACK+80 LDA 5DH ;SEE IF A MASK WAS ENTERED CPI 20H ;BUFFER WILL BE BLANK IF NOT JZ NOMASK MVI C,0DH ;DISK RESET CALL BDOS LXI H,RAM ;SET UP TABLE ADDRESS SHLD TABADDR LXI H,0000H SHLD TABCNT XRA A ;THE TABLE REFERS TO THE REMAINING AREA STA ABORT ;OF RAM TO HOLD AS MANY DIRECTORY ENTRIES STA EOF ;AS POSSIBLE LXI D,SIGNON ;PRINT SIGNON MESSAGE CALL OUTPUT LXI D,DESTFLPMSG CALL QUESTION ORA A JNZ QUEST1A LDA DESTFLP JMP QUEST1B QUEST1A LDA INREC QUEST1B STA FLOPPY CALL EXTRACT ;GET DIRECTORY ENTRIES NOMORE CALL SORT CALL KILLDUPS ;REMOVE ENTRIES FROM MULTIPLE EXTENTS LDA 5CH ;SOURCE DISK STA SRCE LDA FLOPPY ;FLOPPY DISK IS ALWAYS THE DESTINATION ANI 0FH STA DEST LXI D,MNTBLANK CALL QUESTION MVI C,0DH CALL BDOS CALL CPYFILE JMP BOOT ;RESET AND RETURN TO CPM NOMASK LXI D,ERRNOMSK CALL OUTPUT JMP BOOT * * THE EXTRACT ROUTINE SCANS THE DIRECTORY ON THE FLOPPY DISK * AND CREATES A LIST OF FILES TO BE COPIED. AFTERS SORTING, * DUPLICATE ENTRIES RESULTING FROM MULTIPLE EXTENT ENTRIES WILL * BE REMOVED. * * THE DUMMYFCB SETS UP A SKELETON TO READ ALL FILES ON THE DIRECTORY * TO BE MODIFIED BY THE SKELATON SETUP IN THE CALL (EX: FLOPCOPY *.ASC). * DUMMYFCB DB 0,'????????????',0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 EXTRACT EQU $ LXI D,DUMMYFCB ;COPY THE MASK SET UP BY CCP LXI H,5CH ;OVER THE DUMMY FCB TO LIMIT WHAT IS COPIED MVI B,12 CALL MOVE LDA DUMMYFCB ORI 40H STA RDISK LXI D,DISKBUF ;SET A DMA ADDRESS FOR DIRECTORY ENTRIES MVI C,1AH CALL BDOS ;SET DMA LXI D,DUMMYFCB ;GET FIRST DIRECTORY ENTRY MVI C,11H CALL BDOS ;GET DIRECTORY INR A RZ JMP GETFCB ;EXTRACT DATA FROM FCB NEXTFCB LXI D,DUMMYFCB ;GET NEXT ENTRY AFTER THE FIRST MVI C,12H CALL BDOS INR A RZ GETFCB LXI D,32 ;EACH ENTRY IS 32 BYTES LONG LXI H,DISKBUF ;DIRECTORY RECORD IS IN DISKBUF CPI 1 ;FIRST ENTRY IN RECORD??? JZ FORMREC ;YES DAD D ;ADD 32 TO ADDRESS IN RECORD CPI 2 ;SECOND ENTRY IN RECORD??? JZ FORMREC DAD D ;ADD 64 TO ADDRESS OF RECORD CPI 3 ;THIRD ENTRY IN RECORD??? JZ FORMREC DAD D ;ADD 96 TO ADDRESS OF RECORD FORMREC INX H ;PASS DRIVE BYTE LXI D,RFILE ;MOVE FILE NAME MVI B,8 ;MOVE 8 CHARACTERS CALL MOVE LXI D,8 ;POSITION PAST NAME TO TYPE DAD D LXI D,RTYPE ;MOVE TYPE MVI B,3 ;MOVE 3 CHARACTERS CALL MOVE INX H ;POSITION TO THE EXTENT NUMBER INX H INX H LXI H,RTYPE ;STRIP OFF THE HIGH BIT SET BY MVI B,11 ;THE VERSION PROGRAM STRIP MOV A,M ANI 07FH MOV M,A INX H DCR B JNZ STRIP LXI H,RTYPE ;SKIP OVER JUNK DISK ENTRIES MVI B,11 ;CONTAINING NONPRINTING CHARACTERS NONPRNT MOV A,M CPI 20H ;ANY CHAR LESS THAN A BLANK JC NEXTFCB ;GO TO NEXT ONE IF SO INX H DCR B JNZ NONPRNT FIRSTEXT EQU $ ;GOT THE FIRST EXTENT LHLD TABADDR ;GET MEMORY TABLE ADDRESS LXI D,RTYPE ;GET MEMORY RECORD ADDRESS XCHG ;RTYPE (HL) TO TABADDR (DE) MVI B,RECSIZE ;MOVE RECSIZE BYTES CALL MOVE LHLD TABADDR ;INCREMENT FOR NEXT ENTRY LXI D,RECSIZE ;RECSIZE BYTES IN RECORD DAD D SHLD TABADDR ;SAVE NEW ADDRESS MVI M,1AH ;SET AN END-OF-TABLE INDICATOR LHLD TABCNT ;GET RECORD COUNT INX H SHLD TABCNT ;INCREMENT RECORD COUNT LHLD TABADDR ;SEE IF NEW ADDRESS IS GREATER XCHG ;THAN THE TOP OF TPA-128 LHLD BDOS+1 ;HL=TOP...DE=TABLE+RECSIZE LXI B,-128 DAD B ;SUBTRACT 128 FROM TOP CALL COMPREG ;COMPARE REGISTER VALUES JNC NEXTFCB ;THERE IS ROOM FOR MORE MVI A,1 ;NO MORE ROOM...ABORT NOW STA ABORT RET * COPY THE FILE FROM ONE DISK TO ANOTHER * THIS CODE WAS TAKEN FROM BACKUP.ASM SO HDFCB REFERS TO THE SOURCE DISK * AND FPFCB REFERS TO THE DESTINATION DISK REGARDLESS OF FLOPPY OR HARD. CPYFILE EQU $ LHLD ADDR2 ;GET THE CURRENT END OF TABLE INX H ;PLUS ONE FOR THE START OF THE SHLD ADDR3 ;READ/WRITE BUFFER LXI H,RAM ;SET THE ADDRESS OF THE FIRST ENTRY SHLD ADDR1 JMP PASSMOVE NEXTFILE EQU $ LHLD ADDR1 LXI D,RECSIZE DAD D SHLD ADDR1 PASSMOVE LHLD ADDR1 MOV A,M CPI 1AH RZ FORMFCB LXI D,HDFCB ;CLEAR THE FCB MVI B,36 XRA A ZEROFCB STAX D INX D DCR B JNZ ZEROFCB LHLD ADDR1 ;GET ADDRESS OF TABLE ENTRY LXI D,HDTYPE ;MOVE IN THE TYPE MVI B,3 CALL MOVE INX H INX H ;POSITION TO NAME INX H LXI D,HDFILE ;MOVE THE FILE NAME MVI B,8 CALL MOVE LXI D,8 DAD D ;POSITION TO DISK ID, A:, B: ETC LDA SRCE STA HDFCB LXI D,FPFCB ;COPY THE HDFCB TO THE FLOPPY FCB LXI H,HDFCB MVI B,36 CALL MOVE LDA DEST STA FPFCB LHLD ADDR1 CALL FORMAT LXI D,PRNTREC CALL OUTPUT LXI D,HDFCB ;OPEN THE SOURCE FILE DRIVE MVI C,0FH CALL BDOS INR A JZ NOTFOUND LXI D,FPFCB ;SEE IF THE FILE IS ON THE DESTINATION DRV MVI C,0FH CALL BDOS ;DUMMY OPEN INR A JZ MAKEIT ;NOT THERE...MAKE IT ERAIT EQU $ LXI D,FPFCB ;DELETE THE FILE ON FLOPPY IF IT MVI C,13H ;EXISTS CALL BDOS MAKEIT EQU $ LXI D,FPFCB ;CREATE THE FILE ON FLOPPY MVI C,16H CALL BDOS ;MAKE FILE INR A JZ DISKFULL COPYLOOP CALL LOADBUFF ;LOAD MEMORY WITH FILE CALL WRITEBUF ;WRITE MEMORY FILE LDA EOF CPI 1 JZ ENDOFFILE CPI 2 JZ DISKFULL JMP COPYLOOP ENDOFFILE LXI D,FPFCB ;CLOSE FLOPPY FILE MVI C,10H CALL BDOS ;CLOSE JMP NEXTFILE DISKFULL LXI D,FPFCB MVI C,13H ;DELETE FILE ON FLOPPY CALL BDOS LXI D,MNTBLANK CALL QUESTION MVI C,0DH CALL BDOS JMP FORMFCB NOTFOUND LHLD ADDR1 CALL FORMAT LXI D,NFMSG CALL OUTPUT LXI D,PRNTREC CALL OUTPUT RET * THE FOLLOWING ROUTINE IS A BUBBLE SORT. IN PSEUDOBASIC * IS WOULD BE DONE AS FOLLOWS: *SORT ADDR1=BOTTOM(RAM)-RECSIZE (RECSIZE IS COUNT OF BYTES IN ONE RECORD) * MAX1=0 *LOOP1 MAX1=MAX1+1 * ADDR1=ADDR1+RECSIZE (FIRST TIME THIS WOULD BE THE BOTTOM) * IF MAX1>TABCNT-1 THEN GO TO SORTED * ADDR2=ADDR1 * MAX2=MAX1 *LOOP2 MAX2=MAX2+1 * ADDR2=ADDR2+RECSIZE * IF MAX2>TABCNT THEN GO TO LOOP1 * IF TABLE(ADDR1)