home *** CD-ROM | disk | FTP | other *** search
- ; 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)<TABLE(ADDR2) THEN GO TO LOOP2
- * TEMP=TABLE(ADDR1)
- * TABLE(ADDR1)=TABLE(ADDR2)
- * TABLE(ADDR2)=TEMP
- * GO TO LOOP2
- *SORTED RETURN
- *
- *NOW THAT THIS LOGIC IS INTUITIVELY OBVIOUS, HERE'S THE NOT SO
- *OBVIOUS CODE:
-
- SORT
- LXI H,0000 ;INITIALIZE COUNT
- SHLD MAX1 ;SINCE IT WILL DECREMENT FIRST
- LXI D,-RECSIZE ;SUBTRACT RECSIZE FROM THE BEGINNING
- LXI H,RAM ;OF THE TABLE SINCE IT WILL ADD
- DAD D ;RECSIZE TO IT FIRST
- SHLD ADDR1
- LOOP1 LHLD ADDR1 ;GET THE CURRENT ADDRESS
- LXI D,RECSIZE ;INCREMENT IT BY RECSIZE
- DAD D ;PAST THE NEXT ENTRY
- SHLD ADDR1
- LHLD MAX1 ;SEE IF THE COUNT HAS REACHED THE LIMIT
- INX H ;INCREMENT THE COUNTER
- SHLD MAX1
- XCHG ;MOVE TO DE TO COMPARE TO LIMIT
- LHLD TABCNT
- DCX H ; IS MAX1 > TABCNT - 1 ???
- CALL COMPREG ;COMPARE DE (CURRENT COUNT) TO HL (TABCNT-1)
- JC SORTED ;FINISHED WHEN MAX1 > TABCNT-1
- LHLD ADDR1 ;SETUP FOR THE INNER LOOP
- SHLD ADDR2
- LHLD MAX1
- SHLD MAX2
- LOOP2 LHLD ADDR2 ;START WITH ONE ENTRY GREATER THEN
- LXI D,RECSIZE ;THE OUTER LOOP AND INCREMENT
- DAD D ;BY RECSIZE EACH TIME PAST THE NEXT RECORD
- SHLD ADDR2 ;POINTER TO THE CURRENT RECORD
- LHLD MAX2 ;LIKEWISE SEE IF THE COUNTER FOR THE
- INX H
- SHLD MAX2
- XCHG
- LHLD TABCNT
- CALL COMPREG
- JC LOOP1 ;WHEN FINISHED, INCREMENT OUTER LOOP
- LHLD ADDR2
- XCHG ;ADDR2 NOW IN DE
- LHLD ADDR1
- CALL COMPARE ;COMPARE STRINGS POINTED TO BY DE/HL
- JNC LOOP2 ;TABLE(HL) < TABLE (DE)
- * EXCHANGE THE TWO ENTRIES VIA A TEMPORARY RECORD
- LXI D,TEMP
- LHLD ADDR1
- MVI B,RECSIZE
- CALL MOVE ;TEMP=TABLE(ADDR1)
- XCHG ;ADDR1=DESTINATION
- LHLD ADDR2 ;ADDR2=SOURCE
- CALL MOVE ;TABLE(ADDR1)=TABLE(ADDR2)
- XCHG ;ADDR2 = DESTINATION
- LXI H,TEMP
- CALL MOVE ;TABLE(ADDR2)=TEMP
- JMP LOOP2
- SORTED RET ;FINISHED SORTING
-
-
-
- KILLDUPS EQU $ ;KILL DUPLICATE ENTRIES FROM MULTIPLE EXTENTS
- LXI H,RAM
- SHLD ADDR1 ;SET THE START OF THE TABLE
- NEXTEQUAL LHLD ADDR1 ;CHECK EACH ENTRY AGAINST THE NEXT
- LXI D,RECSIZE
- DAD D
- SHLD ADDR2
- NEXTCHK MOV A,M ;CHECK FOR END OF TABLE
- CPI 1AH
- RZ
- XCHG
- LHLD ADDR1 ;COMPARE ADDR1 WITH ADDR2
- MVI B,RECSIZE
- CALL COMPARE
- JNZ SAVELAST
- PUSH H ;SAVE CURRENT POSITION
- LHLD ADDR2 ;SET UP FOR MOVING LIST
- SHLD ADDR1 ;DOWN ONE ENTRY
- LXI D,RECSIZE
- DAD D ;MOVE THIRD ENTRY TO THE SECOND
- SHLD ADDR2
- CALL MOVELIST
- LHLD TABCNT
- DCX H
- SHLD TABCNT
- POP H ;RESTORE CURRENT POSITION
- SHLD ADDR1 ;NOW COMPARE 1ST & 3RD
- JMP NEXTEQUAL
- SAVELAST LHLD ADDR2 ;MAKE NEW ONE THE CURRENT ONE
- SHLD ADDR1
- JMP NEXTEQUAL ;COMPARE
-
- MOVELIST LHLD ADDR2 ;MOVE THE TABLE FROM ADDR2 DOWN
- XCHG ;TO ADDR1 THEREBY ELIMINATING
- LHLD ADDR1 ;UNWANTED ENTRIES
- MOVENEXT LDAX D ;AND MAKING MORE ROOM FOR THE
- MOV M,A
- CPI 1AH
- RZ
- INX H
- INX D
- JMP MOVENEXT
-
-
- * ASSORTED ROUTINES
-
-
- LOADBUFF EQU $ ;THIS ROUTINE LOADS AS MUCH OF
- LXI H,0000 ;MEMORY WITH THE FILE AS POSSIBLE
- SHLD MAX1
- LHLD ADDR3 ;NEW TOP OF TABLE +2
- SHLD TEMP
- XRA A
- STA EOF ;CLEAR EOF FLAG
- LOADNEXT LHLD TEMP
- XCHG ;SET DMA ADDRESS
- MVI C,1AH
- CALL BDOS
- LXI D,HDFCB ;READ HARD DISK
- MVI C,14H
- CALL BDOS
- ORA A
- JNZ HDEOF ;EOF?
- LHLD MAX1
- INX H ;INCREMENT RECORD COUNT
- SHLD MAX1
- LHLD TEMP ;SEE IF NEXT RECORD WOULD EXCEED THE
- LXI D,128 ;TPA AREA
- DAD D
- SHLD TEMP
- DAD D ;WILL THE NEXT RECORD OVERWRITE BDOS?
- XCHG
- LHLD BDOS+1 ;FIND THE TOP OF MEMORY
- CALL COMPREG ;COMPARE REGISTERS
- RC ;RETURN IF MEMORY ALREADY FULL
- JMP LOADNEXT ;GET ANOTHER RECORD
- HDEOF MVI A,1 ;SET FILE EOF
- STA EOF
- RET
-
- WRITEBUF EQU $ ;WRITE FROM THE MEMORY BUFFER
- LHLD ADDR3
- SHLD TEMP
- LHLD MAX1 ;ALLOW FOR FILES THAT HAVE NO
- LXI D,0000 ;RECORDS SUCH AS RESTART
- CALL COMPREG
- RZ
- WRITENEXT LHLD TEMP
- XCHG ;SET DMA ADDRESS
- MVI C,1AH
- CALL BDOS
- LXI D,FPFCB
- MVI C,15H ;WRITE SEQUENTIAL
- CALL BDOS
- ORA A
- JNZ FPFULL ;FLOPPY DISK FULL
- LHLD MAX1 ;DECREASE RECORD COUNT
- DCX H
- SHLD MAX1
- LXI D,0000 ;CHECK FOR NO MORE TO WRITE
- CALL COMPREG
- RZ
- LHLD TEMP
- LXI D,128 ;INCREMENT WRITE ADDRESS
- DAD D
- SHLD TEMP
- JMP WRITENEXT
- FPFULL MVI A,2 ;FULL DISKETTE
- STA EOF
- RET
-
- FORMAT LXI D,PRNTYPE ;FORMAT THE ENTRY FROM THE TABLE
- MVI B,3 ;FORMAT TO THE PRINT FORMAT
- CALL MOVE ;THE TABLE ADDRESS IS ASSUMMED TO BE
- LXI D,3 ;IN HL. FIRST MOVE THE TYPE
- DAD D ;NOW POSITION TO THE FILE NAME
- LXI D,PRNFILE ;MOVE THE FILE NAME
- MVI B,8
- CALL MOVE
- LXI D,8 ;POSITION TO THE DISK ID
- DAD D
- LDA SRCE
- ORI 40H
- STA PRNTREC
- MVI A,':'
- STA PRNTREC+1
- MVI A,'.'
- STA PRNTYPE-1
- RET
-
- COMPREG MOV A,H ;COMPARE HL TO DE
- CMP D
- RNZ
- MOV A,L
- CMP E
- RET
-
- OUTPUT PUSH D ;PUT OUT A CRLF
- LXI D,CRLF
- MVI C,09
- CALL BDOS
- POP D ;NOW PUT OUT THE MESSAGE
- OUT1 MVI C,09
- JMP BDOS
-
-
- QUESTION CALL OUTPUT ;PUT OUT THE QUESTION
- LXI D,INBUF
- MVI C,0AH ;INPUT THE REPLY
- CALL BDOS
- LDA INCNT ;SEE IF ANYTHING WAS ENTERED
- RET
-
- MOVE PUSH H ;MOVE DATA POINTED TO IN HL
- PUSH D ;TO THE AREA POINTED TO IN DE
- PUSH B ;BY THE BYTE COUNT IN B
- MOVE1 MOV A,M
- ANI 7FH ;RESET THE HIGH ORDER BIT BECAUSE IT
- ;MAY HAVE BEEN TURNED ON FOR THE TYPE
- STAX D
- INX H
- INX D
- DCR B
- JNZ MOVE1
- POP B ;RESTORE THE TOTAL ENVIRONMENT
- POP D
- POP H
- RET
-
- COMPARE PUSH H ;COMPARE THE STRINGS POINTED TO IN HL
- PUSH D ;TO THE STRING POINTED TO IN DE
- PUSH B ;FOR A LENGTH OF B CHARACTERS
- COMP1 LDAX D ; JC IF HL > DE
- CMP M ; JZ IF HL = DE
- JNZ COMP2 ;JNC IF HL < DE
- INX H
- INX D
- DCR B
- JNZ COMP1
- COMP2 POP B
- POP D
- POP H
- RET
-
-
- SIGNON DB 'MULTIPLE FILE COPY PROGRAM '
- DB '10/9/82$'
- ERRNOMSK DB 'ERROR...NO FILE MASK IN COMMAND'
- DB CR,LF,'COMMAND MUST BE IN THE FORMAT "MULTCOPY *.*"'
- DB CR,LF,'$'
- NFMSG DB 'FILE NOT FOUND...ABORTING$'
- DMNTMSG DB 'DISMOUNT DISKETTE AND ENTER RETURN$'
- MNTBLANK DB 'MOUNT A FORMATTED BLANK DISKETTE AND ENTER RETURN$'
- PRNTREC DS 1
- DB ':'
- PRNFILE DS 8
- DB '.'
- PRNTYPE DS 3
- DB ' $'
- CRLFLFLF DB 0DH,0AH,0AH,0AH,'$'
- CRLF DB 0DH,0AH,'$'
- BIGMSG DB 0DH,0AH,'FILE TOO LARGE TO FIT ON ONE DISKETTE '
- DB 'SO NOT BACKED UP **** $'
- DESTFLPMSG DB 'DESTINATION FLOPPY DRIVE (DEFAULT='
- DESTFLP DB 'D) $'
- HDFCB DS 1
- HDFILE DS 8
- HDTYPE DS 3
- DS 24
- FPFCB DS 36
- FLOPPY DS 1
- SRCE DS 1
- DEST DS 1
- INBUF DB 30
- INCNT DS 1
- INREC DS 30
- STACK DS 80
- EOF DS 1
- ABORT DS 1
- LINECNT DS 1
- LASTTYPE DS 3
- LASTFILE DS 8
- TABADDR DS 2
- TABCNT DS 2
- SELFLAG DS 1
- TOOBIG DS 1
- ADDR1 DS 2
- ADDR2 DS 2
- ADDR3 DS 2
- MAX1 DS 2
- MAX2 DS 2
- RTYPE DS 3
- RFILE DS 8
- RDISK DS 3
- DB '$'
- TEMP DS RECSIZE
- DISKBUF DS 128
- COMPSIZE DS 1
- CR EQU 0DH
- LF EQU 0AH
- RAM EQU $
- END 100H
-