home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
CPM
/
ZCPR2
/
MCOPY.MAC
< prev
next >
Wrap
Text File
|
2000-06-30
|
37KB
|
1,723 lines
; 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 ; <CR>
LF EQU 0AH ; <LF>
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 <SP> OR EOL
INX H ; PT TO NEXT
CPI ' '+1 ; <SP> 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 (<CR>=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 (<CR>=',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 (<CR>=',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 (<CR>=',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 (<CR>=',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 <SP>
PMODE:
JZ PMODE1 ; PRINT <SP>
JMP COUT ; PRINT CHAR
PMODE1:
MVI A,' ' ; PRINT <SP>
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 <SP> 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/<CR>=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