;
;  PROGRAM:  DIFF
;  AUTHOR:  Richard Conn
;  VERSION:  2.0
;  DATE:  18 MAY 84
;  PREVIOUS VERSIONS:  1.6 (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     20
z3env   SET     0f400h

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

;  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>
CTRLC   EQU     'C'-'@'
CTRLX   EQU     'X'-'@'

;  SYSLIB and Z3LIB ROUTINES
       EXT     Z3INIT,ZFNAME,GETCRT
       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     CODEND

;
; Environment Definition
;
       if      z3env ne 0
;
; External ZCPR3 Environment Descriptor
;
       jmp     start
       db      'Z3ENV' ;This is a ZCPR3 Utility
       db      1       ;External Environment Descriptor
z3eadr:
       dw      z3env
start:
       lhld    z3eadr  ;pt to ZCPR3 environment
;
       else
;
; Internal ZCPR3 Environment Descriptor
;
       MACLIB  Z3BASE.LIB
       MACLIB  SYSENV.LIB
z3eadr:
       jmp     start
       SYSENV
start:
       lxi     h,z3eadr        ;pt to ZCPR3 environment
       endif

;
; Start of Program -- Initialize ZCPR3 Environment
;
       call    z3init  ;initialize the ZCPR3 Env and the VLIB Env
;
;  SET BUFFER LOCATIONS
;
       CALL    CODEND  ; ALLOCATE BUFFER SPACE
       SHLD    INLINE  ; SET PTR TO INPUT LINE
       LXI     D,100H  ; BUFFER SIZE
       DAD     D
       SHLD    BUFF1   ; SOURCE 1 BUFFER
       LXI     D,BSIZE ; SIZE OF BUFFER
       INR     D       ; ADD 1
       DAD     D
       SHLD    BUFF2   ; SOURCE 2 BUFFER
;
;  SET OPERATIONS FLAGS
;
       XRA     A       ; A=0
       STA     MULT    ; SET NO MULTIPLE RUN
       STA     COMP    ; SET NO COMPARE ONLY
       CALL    GETCRT  ; GET CRT CHARACTERISTICS
       INX     H       ; PT TO TEXT LINE COUNT
       INX     H
       MOV     A,M     ; GET COUNT
       STA     LSET    ; SET COUNTER
;
;  EXTRACT COMMAND LINE INFORMATION
;
       LHLD    INLINE  ; PT TO INPUT LINE BUFFER
       XCHG            ; ... IN DE
       LXI     H,BUFF+1        ; PROCESS OPTIONS IN BUFFER
       MVI     B,80H   ; ARBITRARY 80H BYTES
       CALL    MOVEB
       XCHG            ; PT TO FIRST CHAR WITH HL
       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
       MVI     A,0     ; DIR BEFORE DU
       CALL    ZFNAME  ; EXTRACT NAME AND DIRECTORY DATA
       MOV     A,M     ; GET NEXT CHAR
       CPI     ','
       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
       CALL    RETUD   ; GET CURRENT USER/DISK
       MOV     A,B     ; GET DISK
       INR     A       ; A=1
       STA     FCBD    ; SET DISK
       MOV     A,C     ; GET USER
       STA     FCBD+13 ; PT TO S1 FOR USER
       POP     H       ; GET PTR
       JMP     START3
START2:
       INX     H       ; PT TO NEXT CHAR AFTER COMMA
       LXI     D,FCBD  ; SET DEST FCB
       MVI     A,0     ; DIR BEFORE DU
       CALL    ZFNAME  ; PROCESS NAME
       LDA     FCBD+1  ; CHECK FOR NO NAME
       CPI     ' '     ; SPACE MEANS NO NAME
       JNZ     START3
       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
START3:
       CALL    SBLANK  ; SKIP SPACES
       CALL    OPTS    ; PROCESS OPTIONS
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
       CALL    RETUD   ; GET CURRENT DU IN BC
       LXI     H,FCBS  ; PT TO SOURCE DISK
       MOV     A,M     ; GET SOURCE DISK
       ORA     A       ; CURRENT?
       JNZ     START5
       MOV     A,B     ; SET CURRENT DISK
       INR     A       ; ADJUST FOR A=1
START5:
       STA     SDISK
       MVI     M,0     ; CLEAR SOURCE DISK
       LDA     FCBS+13 ; GET USER
       STA     SUSER
       LXI     H,FCBD  ; GET DESTINATION DISK
       MOV     A,M     ; GET DEST DISK
       ORA     A       ; CURRENT?
       JNZ     START6
       MOV     A,B     ; SET CURRENT DISK
       INR     A       ; ADJUST FOR A=1
START6:
       STA     DDISK
       MVI     M,0     ; CLEAR DEST DISK
       LDA     FCBD+13 ; GET USER
       STA     DUSER
MLOOP:
       CALL    BANNER  ; PRINT BANNER
       CALL    PRS1    ; PRINT SOURCE FILE NAMES
       CALL    PRS2
       LDA     MULT    ; MULTIPLE RUNS
       ORA     A
       JZ      MLOOP1
       CALL    PRINT
       DB      CR,LF,' Type ^C to Abort or RETURN to Proceed - ',0
       CALL    CIN     ; GET RESPONSE
       CALL    CAPS    ; CAPITALIZE
       CPI     CTRLC   ; ABORT?
       RZ
       MVI     C,13    ; RESET DISKS
       CALL    BDOS
MLOOP1:
       CALL    LOGS    ; LOG IN SOURCE
       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,' Files are Identical',0
MLOOP2:
       LDA     MULT    ; CHECK FOR MULTIPLE RUNS
       ORA     A       ; 0=NO
       RZ
       CALL    CRLF    ; NEW LINES
       CALL    CRLF
       JMP     MLOOP
FERR:
       CALL    PRINT
       DB      CR,LF,' File Not Found -- ',0
       CALL    PRFN
       JMP     MLOOP2

;
;  PROCESS OPTIONS
;
OPTS:
       MOV     A,M     ; GET NEXT OPTION CHAR
       INX     H       ; PT TO NEXT
       ORA     A       ; END OF LINE?
       RZ
       CPI     ' '     ; SKIP SPACES
       JZ      OPTS
       LXI     D,OTAB  ; PT TO OPTION TABLE
       MOV     B,A     ; OPTION CHAR IN B
OPTS1:
       LDAX    D       ; GET TABLE CHAR
       ORA     A       ; OPTION NOT FOUND?
       JZ      OPTSE   ; PROCESS ERROR
       CMP     B       ; MATCH?
       JZ      OPTS2
       INX     D       ; SKIP TO NEXT
       INX     D
       INX     D
       JMP     OPTS1
OPTS2:
       XCHG            ; USE HL
       INX     H       ; GET ADDRESS
       MOV     A,M     ; GET LOW
       INX     H
       MOV     H,M     ; GET HIGH
       MOV     L,A     ; PUT LOW
       XCHG            ; DE PTS TO OPTION ADDRESS, HL TO NEXT BYTE
       LXI     B,OPTS  ; SET UP RETURN ADDRESS
       PUSH    B
       PUSH    D       ; SET UP OPTION ADDRESS
       RET             ; "RUN" OPTION
OPTSE:
       CALL    PRHELP  ; PRINT HELP MESSAGE
       POP     PSW     ; CLEAR RETURN ADDRESS
       RET             ; RETURN TO OPSYS
;
;  OPTION TABLE
;
OTAB:
       DB      'C'     ; COMPARE ONLY
       DW      SCOMPF
       DB      'M'     ; MULTIPLE RUN
       DW      SMULTF
       DB      0       ; END OF TABLE
;
;  SET COMPARE FLAG
;
SCOMPF:
       MVI     A,0FFH  ; SET FLAG
       STA     COMP
       RET
;
;  SET MULTIPLE RUN FLAG
;
SMULTF:
       MVI     A,0FFH  ; SET FLAG
       STA     MULT
       RET
;
;  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,'Syntax:'
       DB      CR,LF,'  DIFF ufn1,ufn2 o...  -or-  DIFF ufn o...'
       db      cr,lf,'Options:'
       db      cr,lf,'  C  Compare Files Only (Stop at First Difference)'
       db      cr,lf,'  M  Multiple Runs (Keep on prompting for disks)'
       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    CRLF
       CALL    PRFN    ; PRINT FILE NAME
       CALL    PRINT
       DB      ' AFN 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 1 -- ',0
       LXI     H,SDISK ; PT TO FIRST BYTE
       CALL    PRUD
       LXI     D,FCBS  ; SOURCE FCB
       JMP     PRFN    ; PRINT FILE NAME
PRS2:
       CALL    PRINT
       DB      CR,LF,'Source 2 -- ',0
       LXI     H,DDISK ; PT TO FIRST BYTE
       CALL    PRUD
       LXI     D,FCBD  ; 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 ',0
       MOV     A,C
       CALL    COUT    ; PRINT LETTER
       CALL    PRINT
       DB      ' has terminated prematurely',0
       JMP     DABORT
;  MATCH ERROR
NOMATCH:
       LDA     COMP    ; GET COMPARE FLAG
       ORA     A       ; NZ=SIMPLE COMPARE
       JNZ     CABORT
       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 -- Strike RETURN to Continue, '
       DB      '^C to Abort, or ^X to Advance - ',0
       CALL    CIN     ; GET RESPONSE
       CALL    CAPS
       CPI     CTRLC   ; ABORT?
       JZ      NMAT00
       CPI     CTRLX   ; ADVANCE?
       JNZ     NMAT0
       POP     B       ; CLEAR REGS
       POP     D
       POP     H
       POP     D       ; CLEAR STACK
       CALL    PRINT
       DB      CR,LF,' DIFF Advancing',0
       RET             ; RETURN TO VERIFY CALLER
NMAT00:
       POP     B       ; CLEAR REGS
       POP     D
       POP     H
       POP     D       ; CLEAR STACK
       POP     D
DABORT:
       CALL    PRINT
       DB      CR,LF,' DIFF Aborting',0
       RET             ; RETURN TO OPSYS
CABORT:
       POP     D       ; CLEAR STACK
       MVI     A,1     ; SET ERROR FLAG
       STA     FIRST
       CALL    PRINT
       DB      CR,LF,' Files are Different',0
       RET             ; RETURN TO VERIFY CALLER
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
       LDA     LSET    ; SET LINE COUNT
       SUI     1       ; 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
       DCR     A       ; A=0
       MOV     B,A
       LDA     SUSER   ; GET USER
       MOV     C,A
       CALL    LOGUD   ; LOG IN
       RET
LOGD:
       LDA     DDISK   ; GET DISK
       DCR     A       ; A=0
       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'-1   ; 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
LSET:
       DS      1       ; NUMBER OF TEXT LINES ON SCREEN
LCNT:
       DS      1       ; LINE COUNT
COMP:
       DS      1       ; COMPARE FLAG (0=NO SIMPLE COMPARE)
MULT:
       DS      1       ; MULTIPLE RUN FLAG (0=NO MULT RUNS)
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
BCNT:
       DS      1       ; BUFFER COUNT
BCNT1:
       DS      1       ; SECOND BUFFER COUNT
INLINE:
       DS      2       ; PTR TO INPUT LINE BUFFER

       END