;
;  PROGRAM:  DIFF
;  AUTHOR:  Richard Conn
;  VERSION:  1.6
;  DATE:  16 JAN 83
;  PREVIOUS VERSIONS:  1.5 (9 JAN 83), 1.4 (6 JAN 83), 1.3 (4 JAN 83)
;  PREVIOUS VERSIONS:  1.2 (19 DEC 82), 1.1 (8 DEC 82), 1.0 (24 JULY 82)
;  DERIVATION:  COMPARE, VERSION 1.1
;
VERS    EQU     16

;
;       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.
;


;
;       DIFF is designed to provide the user with a convenient method
; to compare the contents of two files.  It is invoked by one of two basic
; forms:
;
;               DIFF filename.typ
; or
;               DIFF file1.typ file2.typ
;
;       The first form compares the file named "filename.typ" on drive A:
; to the file of the same name on drive B:; the second form compares the
; file named "file1.typ" on drive A: to the file named "file2.typ" on drive
; B:.  Wild cards may NOT be used.  The listing generated by the program gives
; relative offsets (in hex and decimal) as well as the different byte values
; in hex, decimal, and ASCII.
;

;  TERMINAL CONSTANT
LSET    EQU     22      ; NUMBER OF LINES/SCREEN

;  SIZE OF BUFFER
BLIMIT  EQU     32      ; NUMBER OF 128-BYTE BLOCKS
BSIZE   EQU     BLIMIT*128      ; 4K

;  CP/M Constants
CPM     equ     0       ; CP/M Warm Boot
BUFF    equ     CPM+80H ; Temporary Buffer
CR      equ     0DH     ; <CR>
LF      equ     0AH     ; <LF>

;  CRC ROUTINES
       EXT     CRCCLR,CRCUPD,CRCDONE

;  SYSLIB ROUTINES
       EXT     PHL4HC,PHLDC,PA2HC,PADC
       EXT     BDOS,INITFCB
       EXT     LOGUD,RETUD
       EXT     F$OPEN,F$CLOSE,F$READ
       EXT     CAPS,CIN,COUT,CRLF,MOVEB,PRINT
       EXT     ZGPINS,ZFNAME
       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      000H    ; MULTIPLE COMMAND LINE?
MXREQD:
       DB      000H    ; MAX USER/DISK?
UDREQD:
       DB      000H    ; ALLOW USER/DISK CHANGE?
PUREQD:
       DB      000H    ; PRIVILEGED USER?
CDREQD:
       DB      0FFH    ; CURRENT INDIC AND DMA?
NDREQD:
       DB      0FFH    ; NAMED DIRECTORIES?
Z2CLASS:
       DB      0       ; CLASS 0
       DB      'ZCPR2'
       DS      10      ; RESERVED

;
;  END OF SINSFORM -- STANDARD DEFAULT PARAMETER DATA
;
;******************************************************************
;

;
;  Start of Program
;
START:
       CALL    ZGPINS  ; INIT ZCPR2 BUFFERS
       CALL    CODEND  ; ALLOCATE BUFFER SPACE
       SHLD    BUFF1   ; SOURCE 1 BUFFER
       LXI     D,BSIZE ; SIZE OF BUFFER
       INR     D       ; ADD 1
       DAD     D
       SHLD    BUFF2   ; SOURCE 2 BUFFER
       XRA     A       ; SET NO MULTIPLE RUN
       STA     MULT
       CALL    RETUD   ; GET CURRENT USER/DISK
       MOV     A,B     ; SAVE DISK
       STA     CDISK
       MOV     A,C     ; SAVE USER
       STA     CUSER
       LXI     H,BUFF  ; PROCESS OPTIONS IN BUFFER
       MOV     A,M     ; GET CHAR COUNT
       INX     H       ; PT TO FIRST CHAR
       PUSH    H       ; SAVE PTR TO FIRST CHAR
       ADD     L       ; HL=HL+A
       MOV     L,A
       MOV     A,H
       ACI     0
       MOV     H,A
       MVI     M,0     ; STORE ENDING ZERO
       POP     H       ; GET PTR TO FIRST CHAR
       LXI     D,INLINE        ; PT TO INPUT LINE BUFFER
       PUSH    D       ; SAVE PTR
START0:
       MOV     A,M     ; COPY INPUT LINE SO BUFF MAY BE USED
       STAX    D       ; PUT BYTE
       INX     H       ; PT TO NEXT
       INX     D
       ORA     A       ; EOL?
       JNZ     START0
       POP     H       ; PT TO FIRST CHAR
       CALL    SBLANK  ; SKIP SPACES
       ORA     A       ; EOL?
       JZ      PRHELP  ; PRINT HELP IF SO
       CPI     '/'     ; ASKING FOR HELP?
       JZ      PRHELP
       LXI     D,FCBS  ; PT TO SOURCE FCB
       CALL    ZFNAME  ; EXTRACT NAME AND DIRECTORY DATA
       JNZ     START1
UDERR:
       CALL    PRINT
       DB      CR,LF,'Invalid Disk or User -- Aborting',0
       RET
START1:
       MOV     A,B     ; SAVE SOURCE DISK
       CPI     0FFH    ; CHECK FOR CURRENT
       JNZ     SDISK1
       LDA     CDISK   ; SPECIFY CURRENT DISK INSTEAD
       INR     A       ; ADD 1 FOR FOLLOWING DECREMENT
SDISK1:
       DCR     A       ; DOWN 1 SO RANGE IS 0-F
       STA     SDISK
       MOV     A,C     ; SAVE SOURCE USER
       CPI     0FFH    ; CHECK FOR CURRENT
       JZ      SUSER0
       CPI     '?'     ; WILD IS CURRENT
       JNZ     SUSER1
SUSER0:
       LDA     CUSER   ; GET CURRENT USER
SUSER1:
       STA     SUSER
       MOV     A,M     ; GET SEPARATION CHAR
       CPI     ','     ; COMMA IF SECOND NAME SPECIFIED
       JZ      START2
       PUSH    H       ; SAVE PTR
       LXI     H,FCBS+1        ; NO 2ND NAME, SO SET IT TO SAME AS FIRST
       LXI     D,FCBD+1
       MVI     B,11    ; 11 BYTES
       CALL    MOVEB
       LDA     CDISK   ; SET DISK AND USER TO CURRENT
       STA     DDISK
       LDA     CUSER
       STA     DUSER
       POP     H       ; GET PTR
       JMP     START3
START2:
       INX     H       ; PT TO NEXT CHAR AFTER COMMA
       LXI     D,FCBD  ; SET DEST FCB
       CALL    ZFNAME  ; PROCESS NAME
       JZ      UDERR
       LDA     FCBD+1  ; CHECK FOR AMBIGUOUS NAME
       CPI     '?'     ; ASSUME ALL IS AMBIGUOUS IF FIRST CHAR IS
       JNZ     NOSET
       PUSH    H       ; SAVE PTR
       PUSH    B       ; SAVE USER/DISK
       LXI     H,FCBS+1        ; SET NAMES THE SAME
       LXI     D,FCBD+1        ; COPY SOURCE TO DEST
       MVI     B,11    ; 11 BYTES
       CALL    MOVEB
       POP     B       ; RESTORE BC
       POP     H       ; RESTORE PTR
NOSET:
       MOV     A,B     ; GET DISK
       CPI     0FFH
       JNZ     DDISK1
       LDA     CDISK   ; SELECT CURRENT DISK IF DEFAULT
       INR     A       ; ADD 1 FOR FOLLOWING DECREMENT
DDISK1:
       DCR     A
       STA     DDISK
       MOV     A,C     ; GET USER
       CPI     0FFH    ; CURRENT?
       JZ      DUSER0
       CPI     '?'     ; WILD IS CURRENT
       JNZ     DUSER1
DUSER0:
       LDA     CUSER
DUSER1:
       STA     DUSER   ; SET DEST USER
START3:
       CALL    SBLANK  ; SKIP SPACES
       CPI     'M'     ; MULTIPLE OPTION?
       JNZ     START4
       MVI     A,0FFH  ; SET FLAG
       STA     MULT
START4:
       LXI     H,FCBS  ; SET UP SOURCE FCB
       CALL    QCHECK  ; NO AMBIGUOUS ENTRIES PERMITTED
       LXI     H,FCBD  ; SET UP DESTINATION FCB
       CALL    QCHECK  ; NO AMBIGUOUS ENTRIES PERMITTED
MLOOP:
       CALL    BANNER  ; PRINT BANNER
       LDA     MULT    ; MULTIPLE RUNS
       ORA     A
       JZ      MLOOP1
       CALL    PRS1    ; PRINT SOURCE FILE 1
       CALL    PRS2    ; PRINT SOURCE FILE 2
       CALL    PRINT
       DB      CR,LF,'  Change Disks if Desired and Type ^C or A to Abort or '
       DB      '<RETURN> to Continue - ',0
       CALL    CIN     ; GET RESPONSE
       CALL    CAPS    ; CAPITALIZE
       CPI     3       ; ABORT?
       RZ
       CPI     'A'     ; ABORT?
       RZ
       MVI     C,13    ; RESET DISKS
       CALL    BDOS
MLOOP1:
       CALL    PRS1    ; PRINT FILE NAMES
       CALL    PRS2
       CALL    LOGS    ; LOG IN SOURCE DISK/USER
       LXI     D,FCBS  ; TRY TO OPEN SOURCE 1
       CALL    INITFCB ; INIT FCB
       CALL    F$OPEN  ; Z IF NO ERROR
       JNZ     FERR
       CALL    LOGD    ; LOG IN DEST DISK/USER
       LXI     D,FCBD  ; TRY TO OPEN SOURCE 2
       CALL    INITFCB ; INIT FCB
       CALL    F$OPEN
       JNZ     FERR
       XRA     A       ; A=0
       STA     FIRST   ; SET FLAG FOR FIRST ERROR
       LXI     H,0     ; INIT OFFSET
       SHLD    OFFSET
       CALL    VERIFY  ; PERFORM VERIFICATION
       LDA     FIRST   ; ANY ERRORS?
       ORA     A       ; 0=NO ERRORS
       JNZ     MLOOP2
       CALL    PRINT
       DB      CR,LF,'NO Differences Noted in Files',0
       CALL    CRLF    ; NEW LINE
MLOOP2:
       CALL    CRLF
       LDA     MULT    ; CHECK FOR MULTIPLE RUNS
       ORA     A       ; 0=NO
       JNZ     MLOOP
       RET
FERR:
       CALL    PRINT
       DB      CR,LF,'File Not Found -- ',0
       CALL    PRFN
       JMP     MLOOP2

;
;  SKIP TO NON-BLANK CHAR
;
SBLANK:
       MOV     A,M     ; GET CHAR
       INX     H       ; PT TO NEXT
       CPI     ' '     ; BLANK?
       JZ      SBLANK
       DCX     H       ; PT TO NON-BLANK
       RET

;
;  PRINT HELP MESSAGE
;
PRHELP:
       CALL    BANNER  ; PRINT BANNER
       CALL    PRINT
       DB      CR,LF
       DB      CR,LF,'DIFF is used to display all relative differences '
       DB      'between two files'
       DB      CR,LF
       DB      CR,LF,'DIFF is invoked by a command like:'
       DB      CR,LF,' DIFF dir:file1.typ,dir:file2.typ M'
       DB      CR,LF,'where:'
       DB      CR,LF,'   "file1.typ" must be specified and is unambiguous'
       DB      CR,LF,'   "dir:" is an optional named directory (or DU:)'
       DB      CR,LF,'   "file2.typ" is optional and set equal to '
       DB      '"file1.typ" if omitted'
       DB      CR,LF,'   "M" is optional and allows Multiple Runs if given'
       DB      CR,LF
       DB      CR,LF,'Examples:'
       DB      CR,LF,'Command                  Files Compared'
       DB      CR,LF,'DIFF T.COM,A1:        $$:T.COM, A1:T.COM'
       DB      CR,LF,'DIFF A:T.COM          A$:T.COM, $$:T.COM'
       DB      CR,LF,'DIFF A:T.COM,ROOT:    A$:T.COM, ROOT:T.COM'
       DB      CR,LF,'DIFF A:T.COM,B:S.COM  A$:T.COM, B$:S.COM'
       DB      0
       RET

;
;  CHECK FOR ANY QUESTION MARKS FROM HL+1 TO HL+11
;  AFFECT ONLY AF REGISTERS IF OK
;
QCHECK:
       PUSH    H       ; SAVE HL
       PUSH    B       ; SAVE BC
       INX     H       ; PT TO FIRST CHAR
       MVI     B,11    ; 11 BYTES
       MVI     C,'?'   ; SCAN FOR '?'
QC:
       MOV     A,M     ; GET BYTE
       CMP     C       ; '?'?
       JZ      QC1
       INX     H       ; PT TO NEXT
       DCR     B       ; COUNT DOWN
       JNZ     QC
       POP     B       ; RESTORE
       POP     H
       RET
QC1:
       POP     B       ; RESTORE AND ABORT
       POP     H
       POP     D       ; CLEAR RETURN ADDRESS
       XCHG            ; FCB PTR IN DE
       CALL    BANNER  ; PRINT BANNER
       CALL    CRLF
       CALL    PRFN    ; PRINT FILE NAME
       CALL    PRINT
       DB      '  Ambiguous File Name not Allowed',CR,LF,0
       RET

;
;  PRINT BANNER
;
BANNER:
       CALL    PRINT
       DB      'DIFF  Version '
       DB      VERS/10+'0','.',(VERS MOD 10)+'0'
       DB      0
       RET

;
;  PRINT NAMES OF SOURCE FILES
;    PRS1 -- SOURCE FILE 1
;    PRS2 -- SOURCE FILE 2
;
PRS1:
       CALL    PRINT
       DB      CR,LF,'Source File 1 -- ',0
       LXI     H,SDISK ; PT TO FIRST BYTE
       CALL    PRUD
       LXI     D,FCBS  ; COMPUTE CRC FOR SOURCE FCB
       JMP     PRFN    ; PRINT FILE NAME
PRS2:
       CALL    PRINT
       DB      CR,LF,'Source File 2 -- ',0
       LXI     H,DDISK ; PT TO FIRST BYTE
       CALL    PRUD
       LXI     D,FCBD  ; COMPUTE CRC FOR DESTINATION FCB
       JMP     PRFN    ; PRINT FILE NAME

;
;  MAIN VERIFY ROUTINE
;
VERIFY:
       LHLD    BUFF1   ; PT TO BUFFER 1
       PUSH    H       ; SAVE PTR
       CALL    LOGS    ; LOG IN SOURCE 1
       LXI     D,FCBS  ; SOURCE 1 FCB
       CALL    LOAD    ; READ IN BLOCK
       LDA     BCNT    ; GET OLD BLOCK COUNT
       STA     BCNT1   ; SAVE IT
       LHLD    BUFF2   ; PT TO BUFFER 2
       PUSH    H       ; SAVE PTR
       CALL    LOGD    ; LOG IN SOURCE 2
       LXI     D,FCBD  ; SOURCE 2 FCB
       CALL    LOAD    ; READ IN BLOCK
       POP     D       ; DE PTS TO BUFF 2
       POP     H       ; HL PTS TO BUFF 1
       LDA     BCNT    ; CHECK FOR NO BLOCK READ
       MOV     B,A
       LDA     BCNT1
       ORA     B
       RZ              ; DONE IF NONE READ
;
;  VERIFY LOADED BUFFERS BY COMPARING THEM AND PRINTING DIFFERENCES
;
VERBLOCK:
       MVI     B,128   ; SCAN ONE BLOCK
VERBL:
       LDAX    D       ; GET BYTE
       CMP     M       ; COMPARE
       CNZ     NOMATCH ; PRINT DIFFERENCE
       PUSH    H       ; INC OFFSET
       LHLD    OFFSET
       INX     H
       SHLD    OFFSET
       POP     H
       INX     H       ; PT TO NEXT
       INX     D
       DCR     B       ; COUNT DOWN
       JNZ     VERBL
       LDA     BCNT    ; COUNT DOWN
       DCR     A
       STA     BCNT
       LDA     BCNT1
       DCR     A
       STA     BCNT1
       JZ      VEREQ
       LDA     BCNT    ; CHECK FIRST BUFFER COUNT
       ORA     A
       JNZ     VERBLOCK        ; CONTINUE COMPARE IF NOT EMPTY
VEREQ:
       LDA     BCNT    ; CHECK FOR BOTH DONE
       MOV     B,A
       LDA     BCNT1
       ORA     B       ; IF ZERO, BOTH DONE AT SAME TIME AND CONTINUE
       JZ      VERIFY
       LDA     BCNT1   ; CHECK FOR ONE DONE BEFORE THE OTHER
       ORA     A       ; 2ND DONE?
       MVI     C,'2'   ; GET LETTER
       JZ      DONE1
       MVI     C,'1'   ; GET LETTER
;  ONE FILE IS SHORTER THAN THE OTHER -- SAY SO
DONE1:
       CALL    PRINT
       DB      CR,LF,'Source File ',0
       MOV     A,C
       CALL    COUT    ; PRINT LETTER
       CALL    PRINT
       DB      ' has terminated before the other -- DIFF Aborting',0
       RET
;  MATCH ERROR
NOMATCH:
       PUSH    H       ; SAVE REGS
       PUSH    D
       PUSH    B
       LDA     FIRST   ; FIRST TIME THRU?
       ORA     A       ; 0=YES
       JZ      NMAT0
       LDA     LCNT    ; CHECK FOR NEW SCREEN
       ORA     A       ; ZERO IF DONE
       JNZ     NMAT1
       CALL    PRINT
       DB      CR,LF,'DIFF Pause -- Type <RETURN> to Continue or '
       DB      '^C or A to Abort - ',0
       CALL    CIN     ; GET RESPONSE
       CALL    CAPS
       CPI     'A'     ; ABORT?
       JZ      NMAT00
       CPI     3       ; ABORT?
       JNZ     NMAT0
NMAT00:
       POP     B       ; CLEAR REGS
       POP     D
       POP     H
       POP     D       ; CLEAR STACK
       POP     D
       CALL    PRINT
       DB      CR,LF,'DIFF Aborting',0
       RET
NMAT0:
       MVI     A,0FFH  ; CLEAR FIRST TIME FLAG
       STA     FIRST
       CALL    HEADER  ; PRINT HEADING AND RETURN NEW LINE COUNT
NMAT1:
       DCR     A       ; COUNT DOWN 1 LINE
       STA     LCNT    ; NEW LINE COUNT
       CALL    CRLF
       PUSH    H       ; SAVE HL
       LHLD    OFFSET  ; PRINT OFFSET VALUE
       CALL    PHL4HC  ; PRINT AS HEX
       CALL    SPACER  ; PRINT SPACES
       CALL    PHLDC   ; PRINT AS DEC
       POP     H       ; RESTORE HL
       CALL    SPACER
       CALL    SPACER
       MVI     A,' '
       CALL    COUT
       MOV     A,M     ; GET SOURCE 1 VALUE
       CALL    PRVAL   ; PRINT AS HEX, DEC, ASCII
       CALL    SPACER  ; 10 SPACES
       CALL    SPACER
       CALL    SPACER
       CALL    SPACER
       CALL    SPACER
       LDAX    D       ; GET SOURCE 2 VALUE
       CALL    PRVAL   ; PRINT AS HEX, DEC, ASCII
       POP     B       ; RESTORE REGS
       POP     D
       POP     H
       RET

;  PRINT HEADER AND RETURN NEW LINE COUNT IN A
HEADER:
       PUSH    D       ; SAVE REGS
       PUSH    H
       CALL    PRINT
       DB      CR,LF,' Rel Offset   ',0
       LXI     H,SDISK ; PRINT DISK/USER
       CALL    PRUD
       LXI     D,FCBS
       CALL    PRFN    ; PRINT FILE NAME
       CALL    SPACER  ; 5 SPACES
       CALL    SPACER
       CALL    SPACE1
       LXI     H,DDISK ; PRINT DISK/USER
       CALL    PRUD
       LXI     D,FCBD
       CALL    PRFN    ; PRINT FILE NAME
       CALL    PRINT
       DB      CR,LF,' Hex    Dec       Hex  Dec Asc           Hex  Dec Asc',0
       MVI     A,LSET  ; SET LINE COUNT
       SUI     3       ; ADJUST FOR HEADING AND FOOTER
       STA     LCNT
       POP     H
       POP     D       ; RESTORE REGS
       RET

;  PRINT A AS HEX, DEC, AND ASCII
PRVAL:
       CALL    SPACER  ; 3 SPACES
       CALL    SPACE1
       CALL    PA2HC   ; PRINT AS HEX
       CALL    SPACER
       CALL    PADC    ; PRINT AS DEC
       CALL    SPACER
       ANI     7FH     ; MASK OUT MSB
       CPI     7FH     ; DOT FOR <DEL>
       JZ      PRDOT
       CPI     ' '     ; PRINT DOT IF LESS THAN <SP>
       JNC     COUT
PRDOT:
       MVI     A,'.'   ; PRINT DOT
       JMP     COUT
;  PRINT 2 SPACES
SPACER:
       PUSH    PSW     ; SAVE A
       MVI     A,' '   ; <SP>
       CALL    COUT
       POP     PSW
SPACE1:
       PUSH    PSW
       MVI     A,' '
       CALL    COUT
       POP     PSW
       RET

;
;  LOAD BUFFER FROM FILE WHOSE FCB IS PTED TO BY DE
;    ON OUTPUT, BCNT=NUMBER OF BLOCKS LOADED (UP TO BLIMIT)
;
LOAD:
       XRA     A       ; A=0
       STA     BCNT    ; SET BLOCK COUNT

;  MAIN LOAD LOOP
LOAD1:
       CALL    F$READ  ; READ A BLOCK
       ORA     A       ; END OF FILE?
       RNZ             ; RETURN IF DONE
       PUSH    D       ; SAVE FCB PTR
       LXI     D,BUFF  ; PT TO BUFFER
       MVI     B,128   ; COPY 128 BYTES
LOAD2:
       LDAX    D       ; GET BYTE READ
       MOV     M,A     ; PUT BYTE
       INX     H       ; PT TO NEXT
       INX     D
       DCR     B       ; COUNT DOWN
       JNZ     LOAD2
       POP     D       ; GET FCB PTR
       LDA     BCNT    ; GET BLOCK COUNT
       INR     A       ; INCREMENT IT
       STA     BCNT    ; SET IT
       CPI     BLIMIT  ; LAST BLOCK READ?
       JNZ     LOAD1
       RET

;
;  LOG IN SOURCE (LOGS) AND DESTINATION (LOGD) DRIVES/USERS
;
LOGS:
       LDA     SDISK   ; GET DISK
       MOV     B,A
       LDA     SUSER   ; GET USER
       MOV     C,A
       CALL    LOGUD   ; LOG IN
       RET
LOGD:
       LDA     DDISK   ; GET DISK
       MOV     B,A
       LDA     DUSER   ; GET USER
       MOV     C,A
       CALL    LOGUD   ; LOG IN
       RET

;
;  PRINT DISK/USER PTED TO BY HL (2 BYTES)
;
PRUD:
       MOV     A,M     ; GET DISK
       ADI     'A'     ; CONVERT TO LETTER
       CALL    COUT
       INX     H       ; PT TO USER
       MOV     A,M     ; GET USER
       CALL    PADC    ; PRINT AS DEC
       CALL    PRINT
       DB      ': ',0
       RET

;
;  PRINT FILE NAME WHOSE FCB IS PTED TO BY DE
;
PRFN:
       PUSH    H       ; SAVE REGS
       PUSH    D
       PUSH    B
       XCHG            ; FN PTED TO BY HL
       INX     H       ; PT TO FIRST CHAR
       MVI     B,8     ; 8 CHARS
       CALL    PRFN1
       MVI     A,'.'
       CALL    COUT
       MVI     B,3     ; 3 CHARS FOR FILE TYPE
       CALL    PRFN1
       POP     B       ; RESTORE REGS
       POP     D
       POP     H
       RET
PRFN1:
       MOV     A,M     ; GET CHAR
       INX     H       ; PT TO NEXT
       CALL    COUT    ; PRINT
       DCR     B       ; COUNT DOWN
       JNZ     PRFN1
       RET

;
;  BUFFERS
;
BUFF1:
       DS      2       ; PTR TO BUFFER 1
BUFF2:
       DS      2       ; PTR TO BUFFER 2
OFFSET:
       DS      2       ; RELATIVE OFFSET
FIRST:
       DS      1       ; ERROR INDIC
LCNT:
       DS      1       ; LINE COUNT
MULT:
       DS      1       ; MULTIPLE RUN FLAG (0=NO MULT RUNS)
CDISK:
       DS      1       ; CURRENT DISK
CUSER:
       DS      1       ; CURRENT USER
SDISK:
       DS      1       ; SOURCE DISK (MUST BE FOLLOWED BY SUSER)
SUSER:
       DS      1       ; SOURCE USER
FCBS:
       DS      36      ; SOURCE FCB
DDISK:
       DS      1       ; DEST DISK (MUST BE FOLLOWED BY DUSER)
DUSER:
       DS      1       ; DEST USER
FCBD:
       DS      36      ; DESTINATION FCB
CRCVAL:
       DS      2       ; CRC VALUE
CURDISK:

       DS      1       ; CURRENT DISK NUMBER
BCNT:
       DS      1       ; BUFFER COUNT
BCNT1:
       DS      1       ; SECOND BUFFER COUNT
INLINE:
       DS      200     ; INPUT LINE BUFFER

       END