;
;  PROGRAM:  HELPPR
;  AUTHOR:  Richard Conn
;  VERSION:  1.0
;  DATE:  18 May 84
;  PREVIOUS VERSIONS:  None
;  DERIVATION:  PHELP 2.0 (28 Apr 83)
;
VERS    equ     10
z3env   SET     0f400h

FALSE   EQU     0
TRUE    EQU     NOT FALSE

timeok  equ     FALSE   ;TRUE if TIME enabled, FALSE if not

;
;       HELPPR is used to print out a HLP file.  It breaks pages on each
; information section and ignores form feeds, so the data is presented
; in a sequential fashion.  It is very convenient to provide online
; documentation in the form of HLP files, and this utility allows the user
; to readily print out this documentation.  HELPPR is preferred over PRINT
; for printing HLP files because of its knowledge of their structure and
; its special way of handling them.
;
;       HELPPR is invoked by a command line of the following form:
;               HELPPR file1,file2,...,filen o...
; where each "filen" is an ambiguous file name and "o" is zero or more of
; the following options:
;       H@head@ Heading Text
;                       The user may specify the text of the heading to
;                       appear at the top of every page
;       I       Inspect Files
;                       The user approves each file to be printed
;                       before the printing process begins
;       L       Toggle Line Numbering
;                       Each line may or may not begin with a line number
;       Snnnn   Skip to Specified Page
;                       Printing begins at the indicated page
;       T       Toggle Time Display
;                       Time/Date information is optionally included
;                       in the page header
;

;
;  BASIC SYSLIB ROUTINES NEEDED BY HELPPR
;
C$ESIZE EQU     16      ; SIZE OF DIR ENTRY (FROM SYSLIB DIRF ROUTINE)

       EXT     DIRQS   ; DIRECTORY PROCESSOR

       EXT     Z3INIT  ; INIT BUFFERS
       EXT     ZFNAME  ; FILE NAME PROCESSOR
       EXT     Z3LOG   ; LOG INTO DIR

       EXT     INITFCB ; INIT FCB
       EXT     RETUD   ; RETURN CURRENT USER/DISK
       EXT     PUTUD   ; SAVE CURRENT USER/DISK
       EXT     GETUD   ; RESTORE CURRENT USER/DISK
       EXT     EPRINT  ; PRINT STRING PTED TO BY RET ADR
       EXT     PADC    ; PRINT A AS DECIMAL CHARS
       EXT     COUT    ; CONSOLE OUTPUT ROUTINE
       EXT     CST     ; CONSOLE STATUS ROUTINE
       EXT     CIN     ; CONSOLE INPUT ROUTINE
       EXT     CAPS    ; CAPITALIZE ROUTINE
       EXT     CRLF    ; NEW LINE ROUTINE
       EXT     CODEND  ; CODE END COMPUTATION ROUTINE

       EXT     F$OPEN  ; FILE OPEN
       EXT     F$READ  ; BLOCK READ
       EXT     F$CLOSE ; FILE CLOSE

       ext     getprt
       ext     eval10
       ext     lcrlf
       ext     lpstr
       ext     lprint
       ext     lout
       ext     lhldc
       ext     condin
       ext     moveb
;
       if      timeok
       ext     time
       endif
;

;
;  Insert Function-Required Library References Here
;

;
;  CP/M EQUATES
;
CPM     EQU     0       ; WARM BOOT
BDOSE   EQU     CPM+5   ; BDOS ENTRY
FCB     EQU     CPM+5CH ; FCB
TBUFF   EQU     CPM+80H ; INPUT LINE BUFFER
DEL     EQU     7FH     ; <DEL>
CR      EQU     13      ; <CR>
FF      EQU     12      ; <FF>
LF      EQU     10      ; <LF>
CTRLC   EQU     'C'-'@' ; ^C
CTRLG   EQU     'G'-'@'
CTRLH   EQU     'H'-'@'
CTRLI   EQU     'I'-'@'
CTRLS   EQU     'S'-'@'
CTRLX   EQU     'X'-'@'
CTRLZ   EQU     'Z'-'@'
eold    equ     0FFH    ;End of Load Indicator

;
; 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
       jmp     startx
;
;  **** Special Initial Value Area for User Installation
;
LWIDTH:
       DB      132     ; PRINTER LINE WIDTH
LTPP:
       DB      44      ; LINES OF TEXT PER PAGE
LSPP:
       DB      5       ; LINES TO SKIP PER PAGE
LFF:
       DB      1       ; FORM FEED FLAG
;
;  NOTE:  LTPP + LSPP + 2 (HEADER SIZE) = TOTAL LINES PER PAGE ON PRINTER
;
DLNUMFL:
       DB      0       ; LINE NUMBER FLAG (DEFAULT TO NO)
DTIMEPFL:
       DB      0FFH    ; TIME PRINT FLAG (DEFAULT TO YES)
DINSPECT:
       DB      0       ; INSPECT FILES (DEFAULT TO NO)
;
;  WORKING BUFFERS
;
LNUMFL:
       DB      0       ; LINE NUMBER FLAG
TIMEPFL:
       DB      0FFH    ; TIME PRINT FLAG
INSPECT:
       DB      0       ; INSPECT FLAG
SKIPFL:
       DB      0       ; SKIP FLAG (DEFAULT TO NO)
SKIPNUM:
       DS      2       ; PAGE NUMBER TO SKIP TO
LNUM:
       DS      2       ; CURRENT LINE NUMBER
PNUM:
       DS      2       ; CURRENT PAGE NUMBER
HBUF:
       DS      2       ; BUFFER FOR HEADING
;
       if      timeok
TIMEBF:
       DS      100     ; BUFFER FOR TIME STAMP
       endif
;
;  Start of Program
;
STARTX:
       LXI     H,0     ; GET STACK PTR
       DAD     SP
       SHLD    V$STACK ; SAVE IT
       XRA     A       ; A=0
       STA     V$INSPECT       ; TURN OFF FILE INSPECTION
       CALL    PUTUD   ; SAVE CURRENT USER/DISK AWAY
       call    codend  ; determine free space
       shld    V$CMDLNE        ; set command line ptr
       lxi     d,100h  ; arbitrary size
       dad     d
       shld    HBUF    ; ptr to heading buffer
       dad     d
       shld    dirbuf  ; ptr to dir buffer
       sphl            ; new stack

;
;  Save Command Line
;
       lhld    V$CMDLNE        ; save command line
       LXI     D,TBUFF+1       ; SAVE COMMAND LINE
       xchg
       mvi     b,80h   ; 128 bytes
       call    moveb

;
;  Setup Printer Data
;
       call    getprt
       mov     a,m     ;get width
       sta     lwidth
       inx     h
       inx     h
       mov     a,m     ;get lines of text per page
       sta     ltpp
       mov     b,a     ;save in B
       dcx     h
       mov     a,m     ;get lines per page
       sub     b       ;compute difference
       sta     lspp    ;lines to skip per page
       inx     h
       inx     h
       mov     a,m     ;get form feed flag
       sta     lff

;
;  Banner of Program
;
       CALL    BANNER  ; PRINT BANNER
;
;  Check for Help Request
;
       LDA     FCB+1   ; GET FIRST CHAR OF FILE NAME
       CPI     ' '     ; NO FILE SPEC?
       JZ      T$HELPENT
       CPI     '/'     ; OPTION CAUGHT?
       JNZ     T$ECONT

;
;  Print Help Information
;
T$HELPENT:
       CALL    HELP    ; PRINT PROGRAM'S HELP MESSAGE

;
;  RETURN TO OS
;
T$RETURN:
       CALL    DINIT   ; DEINIT PROGRAM
       LHLD    V$STACK ; GET OLD STACK
       SPHL            ; SET IT
       RET

;
;  PROGRAM'S INIT ROUTINE
;
T$ECONT:
       CALL    INIT    ; PROG INIT ROUTINE
;
;  EXTRACT FLAGS IF PRESENT
;
       LXI     H,0     ; SET FILE COUNT
       SHLD    V$FILECNT
       LHLD    V$CMDLNE        ; PT TO BUFFER
;
;  SKIP TO FILE NAME STRING
;
       CALL    T$SBLANK        ; SKIP OVER BLANKS
;
;  SKIP TO END OF FILE NAME STRING
;
       CALL    T$SNBLANK       ; SKIP OVER NON-BLANKS
;
;  CHECK FOR LEADING SLASH ON OPTION AND SKIP IT IF SO
;
T$OPT:
       CPI     '/'     ; OPTION CHAR?
       JNZ     T$OPTION
       INX     H       ; SKIP SLASH
;
;  PROCESS LIST OF OPTIONS
;
T$OPTION:
       MOV     A,M     ; GET BYTE
       ORA     A       ; DONE?
       JZ      T$DSPEC
       INX     H       ; PT TO NEXT CHAR
       CPI     ' '     ; SKIP OVER SPACES
       JZ      T$OPTION
       MOV     C,A     ; COMMAND IN C
       LXI     D,OPTAB ; PT TO OPTION TABLE
T$OPTL:
       LDAX    D       ; GET OPTION LETTER
       ORA     A       ; END OF TABLE?
       JZ      T$HELPENT       ; HELP IF SO
       CMP     C       ; MATCH?
       JZ      T$OPTM  ; PROCESS IF SO
       INX     D       ; PT TO NEXT ENTRY
       INX     D
       INX     D
       JMP     T$OPTL
;
;  PROCESS OPTION
;
T$OPTM:
       PUSH    H       ; SAVE HL ON STACK
       LXI     H,T$OPTION      ; GET RETURN ADDRESS
       XTHL            ; ... ON STACK AND RESTORE HL
       INX     D       ; PT TO ADDRESS
       LDAX    D       ; GET ADDRESS LOW
       MOV     B,A     ; ... IN B
       INX     D
       LDAX    D       ; GET ADDRESS HIGH
       MOV     D,A     ; ... IN D
       MOV     E,B     ; LOW IN E
       PUSH    D       ; PUT ADDRESS ON STACK
       MOV     A,C     ; COMMAND IN A
       RET             ; "CALL" OPTION ROUTINE
;
;  BEGIN MOVING THROUGH FILE NAMES, SEPARATED BY COMMAS
;
T$DSPEC:
       LHLD    V$CMDLNE        ; PT TO FIRST BYTE
       CALL    T$SBLANK        ; SKIP TO NON-BLANK
;
;  MAJOR REENTRY POINT WHEN FILE SPECS ARE SEPARATED BY COMMAS
;    HL PTS TO FIRST BYTE OF NEXT FILE SPEC
;
T$DSPEC1:
       shld    hltemp  ; save HL
       lhld    dirbuf  ; reset stack
       sphl
       lhld    hltemp  ; restore HL
       CALL    GETUD   ; RESET USER IF NECESSARY
       LXI     D,V$NTFCB       ; PT TO FCB IN DE, PT TO 1ST CHAR OF FN IN HL
       MVI     A,0     ; DIR before DU
       CALL    ZFNAME  ; EXTRACT FILE NAME INTO FCB, AND GET DISK AND USER

       push    b       ;save disk/user
       push    h       ;save others
       push    d
       lxi     h,hlptyp        ;optionally set default HLP type
       lxi     d,V$NTFCB+9     ;check for any specified
       ldax    d       ;' ' means none
       cpi     ' '
       jnz     hlpskp
       mvi     b,3     ;3 chars
       call    moveb
hlpskp:
       pop     d       ;restore others
       pop     h
       pop     b       ;restore disk/user
       SHLD    V$NEXTCH        ; SAVE PTR TO DELIMITER WHICH ENDED SCAN

;
;  LOAD DIRECTORY AND PERFORM FUNCTION
;
T$FCT:
       LXI     D,V$NTFCB       ; PT TO FCB
       CALL    Z3LOG   ; LOG INTO ACCOUNT
       LHLD    DIRBUF  ; PT TO DIR BUFFER
       MVI     A,11000000B     ; SELECT SYS AND NON-SYS FILES
       LXI     D,V$NTFCB       ; PT TO FCB
       CALL    INITFCB ; INIT THE FCB
       CALL    DIRQS   ; LOAD DIR, SELECT FILES, PACK, AND ALPHABETIZE
;
;  DETERMINE BEGINNING OF SCRATCH AREA (SCRATCH) AND SIZE IN PAGES (BCNT)
;
       PUSH    H       ; SAVE PTR AND COUNT
       PUSH    B
       LXI     D,C$ESIZE       ; SET PTR TO NEXT FREE BLOCK
T$FCTFRE:
       MOV     A,B     ; DONE?
       ORA     C
       JZ      T$FCTFR1
       DAD     D       ; PT TO NEXT
       DCX     B       ; COUNT DOWN
       JMP     T$FCTFRE
T$FCTFR1:
       INR     H       ; NEXT PAGE
       MVI     L,0
       SHLD    V$SCRATCH       ; SET PTR TO SCRATCH AREA
       XCHG            ; PTR IN DE
       LHLD    BDOSE+1 ; COMPUTE BLOCK BUFFER SIZE
       MOV     A,H     ; ADJUST FOR ZCPR3
       SUI     10
       SUB     D       ; A=SIZE IN BLOCKS
       STA     V$BCNT  ; SET BLOCK COUNT
       POP     B       ; RESTORE AND SAVE REGS
       POP     H
;
;  ALLOW USER TO INSPECT FILES
;
       PUSH    H
       PUSH    B
       CALL    T$ICHECK        ; CHECK FOR INSPECT OPTION AND INSPECT IF SET
       POP     B       ; RESTORE COUNT AND PTR
       POP     H

;
;  PERFORM FUNCTION; HL PTS TO FILE AND BC CONTAINS NUMBER OF FILES
;
T$FCTL:
       MOV     A,B             ; CHECK FOR COMPLETION (COUNT = 0)
       ORA     C
       JZ      T$FCTL1
       DCX     B               ; COUNT DOWN
       SHLD    HLTEMP          ; SET STACK
       LHLD    DIRBUF
       SPHL
       LHLD    HLTEMP
       PUSH    B               ; SAVE COUNT AND PTR
       PUSH    H
       MOV     A,M             ; SELECTED FILE?
       ORA     A               ; 0=YES
       CZ      FUNCTION        ; PERFORM FUNCTION
;
;  ENTRY POINT TO SKIP TO NEXT FILE IN LIST
;
E$FCTLNXT:
       LHLD    DIRBUF          ; RESTORE STACK
       LXI     D,-4            ; 4 DOWN
       DAD     D
       SPHL
       POP     H               ; RESTORE PTR
       POP     B               ; RESTORE COUNT
       LXI     D,C$ESIZE       ; PT TO NEXT ENTRY
       DAD     D
       JMP     T$FCTL

;
;  CHECK FOR NEXT FILE SPEC
;
T$FCTL1:
       CALL    GETUD   ; RETURN TO BASE USER/DISK
       LHLD    V$NEXTCH        ; GET PTR
       MOV     A,M     ; GET DELIM
       CPI     ','     ; ANOTHER FILE?
       JNZ     T$RETURN
       INX     H       ; PT TO CHAR AFTER COMMA
       JMP     T$DSPEC1        ; CONTINUE PROCESSING
;
;  INSPECT FILES -- THIS ROUTINE IS TO PERFORM A FILE INSPECTION
;       ON INPUT, HL PTS TO FIRST 16-BYTE ENTRY AND BC=NUMBER OF ENTRIES
;
T$ICHECK:
       MOV     A,B     ;ANY FILES?
       ORA     C       ;0=NO
       RZ
       PUSH    H       ;SAVE PTRS
       PUSH    B
       LXI     D,C$ESIZE       ;SIZE OF ENTRY
T$ICHK1:
       MVI     M,0     ;CLEAR MSBYTES
       DAD     D       ;PT TO NEXT
       DCX     B       ;COUNT DOWN
       MOV     A,B     ;DONE?
       ORA     C
       JNZ     T$ICHK1
       POP     B       ;RESTORE PTRS
       POP     H
       LDA     V$INSPECT       ;INSPECT?
       ORA     A       ;0=NO
       RZ
       CALL    EPRINT
       DB      CR,LF,' File Inspect Mode'
       db      cr,lf,' Cmd     Function     Cmd Function'
       DB      CR,LF,'  Y(def) Select File   Q  Select Rest of Files'
       DB      CR,LF,'  N      Don''t Select  S  Skip Rest of Files'
       db      cr,lf,0
T$ICHK2:
       CALL    EPRINT
       DB      CR,LF,'Select ',0
       CALL    E$PRFN  ;PRINT FILE NAME
       CALL    EPRINT
       DB      ' -- (Y/N/Q/S)? '
       DB      0
       CALL    CIN     ;GET RESPONSE
       CALL    CAPS    ;CAPITALIZE
       CALL    COUT    ;ECHO
       CPI     'Q'     ;SELECT REST?
       JZ      T$ICHKYR
       CPI     'S'     ;SKIP REST
       JZ      T$ICHKNR
       CPI     'N'     ;NO TO THIS ONE?
       JNZ     T$ICHK3
       MVI     M,0FFH  ;SET NO FLAG IN FILE FCB
T$ICHK3:
       DAD     D       ;PT TO NEXT ONE
       DCX     B       ;COUNT DOWN
       MOV     A,B     ;DONE?
       ORA     C
       JNZ     T$ICHK2
       RET
;  CHECK REST OF FILES AS SELECTED
T$ICHKYR:
       CALL    EPRINT
       DB      CR,LF,' Rest of Files Selected',0
       RET
;  CHECK REST OF FILES AS NOT SELECTED
T$ICHKNR:
       MVI     M,0FFH  ;SET NO FLAG
       DAD     D       ;PT TO NEXT
       DCX     B       ;COUNT DOWN
       MOV     A,B     ;DONE?
       ORA     C
       JNZ     T$ICHKNR
       CALL    EPRINT
       DB      CR,LF,' Rest of Files NOT Selected',0
       RET
;
;  UTILITIES
;       T$SBLANK  -- SKIP BLANKS PTED TO BY HL UNTIL NON-BLANK ENCOUNTERED; HL
;       T$SNBLANK -- SKIP NON-BLANKS PTED TO BY HL UNTIL BLANK OR EOL; HL
;       E$PRFN    -- PRINT FILE NAME PTED TO BY HL; AFFECT NOTHING

;
;  SKIP UNTIL NON-BLANK
;
T$SBLANK:
       MOV     A,M     ; LOOK FOR BLANK
       INX     H       ; PT TO NEXT
       CPI     ' '     ; BLANK?
       JZ      T$SBLANK
       DCX     H       ; BACK UP
       RET

;
;  SKIP UNTIL BLANK OR EOL
;
T$SNBLANK:
       MOV     A,M     ; GET CHAR
       INX     H       ; PT TO NEXT
       CPI     ' '     ; BLANK?
       JZ      T$SNB1
       ORA     A       ; EOL?
       JNZ     T$SNBLANK
T$SNB1:
       DCX     H       ; BACK UP
       RET

;
;  PRINT FILE NAME PTED TO BY HL
;       OUTPUT TO CON:
;
E$PRFN:
       PUSH    H       ; SAVE REGS
       PUSH    B
       CALL    RETUD   ; GET CURRENT USER/DISK
       MOV     A,B     ; GET DISK NUMBER
       ADI     'A'     ; CONVERT TO LETTER
       CALL    COUT    ; PRINT LETTER
       MOV     A,C     ; GET USER NUMBER
       CALL    PADC    ; PRINT USER NUMBER
       CALL    EPRINT
       DB      ': ',0
       INX     H       ; PT TO FILE NAME
       MVI     B,8     ; PRINT NAME
       CALL    T$PRNT
       MVI     A,'.'   ; DECIMAL
       CALL    COUT
       MVI     B,3     ; PRINT TYPE
       CALL    T$PRNT
       POP     B       ; GET REGS
       POP     H
       RET

;
;  PRINT CHARS PTED TO BY HL FOR B BYTES
;       OUTPUT TO CON:
;
T$PRNT:
       MOV     A,M     ; GET CHAR
       CALL    COUT
       INX     H       ; PT TO NEXT
       DCR     B       ; COUNT DOWN
       JNZ     T$PRNT
       RET

;***********************************************
;*  Application-Specific Section
;***********************************************

;****************************************************
;*
;*  Function-Specific Routines
;*      These routines need to be customized for the
;* specific function being performed.  These, in
;* effect, implement the function.  Other Entry Points
;* useful to the programmer are:
;*              E$FCTLNXT -- Clean Abort of Current
;*                              Processing and Skip
;*                              to Next File in List;
;*                              This is a Clean Way to
;*                              Abort FUNCTION for the
;*                              Next File
;*              E$PRFN    -- Print File Name Pted to
;*                              by HL; No Regs Affected
;*
;****************************************************

;
;  **** EMERGENCY ABORT
;
ABORT:
       CALL    EPRINT
       db      cr,lf,' HELPPR Abort'
       DB      0
       mvi     a,cr    ; new line
       call    lout
       mvi     a,lf
       call    lout
       CALL    GETUD   ; RETURN HOME
       JMP     T$RETURN
;
;  **** BANNER -- PRINT BANNER FOR PROGRAM (PROGRAM NAME ET AL)
;
BANNER:
       CALL    EPRINT
       db      'HELPPR  Version '
       db      (vers/10)+'0','.',(vers mod 10)+'0'
       DB      0
       RET
;
;  **** HELP -- PRINT PROGRAM'S HELP MESSAGE
;
HELP:
       CALL    EPRINT
       db      cr,lf,'Syntax:'
       db      cr,lf,'   HELPPR afn1,afn2,... o...'
       db      cr,lf,'Options:'
       db      cr,lf,'  H@head@ -- Use "head" as header on every page'
       db      cr,lf,'  I       -- Inspect Files for Printing'
       db      cr,lf,'  L       -- Number Each Line'
       db      cr,lf,'  Onn     -- Offset Each Line by nn Spaces'
       db      cr,lf,'  Snn     -- Skip to Page nn and Start Printing'
       db      cr,lf,'  T       -- Toggle Time Display'
       DB      0
       RET
;
;  **** PROGRAM INIT ROUTINE
;       THIS ROUTINE IS USED BY THE PROGRAM TO PERFORM ANY NECESSARY
;       INITIALIZATIONS
;
INIT:
       lxi     h,dlnumfl       ;copy defaults into buffers
       lxi     d,lnumfl
       mvi     b,3     ;3 bytes
       call    moveb
       xra     a       ;A=0
       sta     skipfl  ;set no skip
       sta     offset  ;set no offset
       push    h
       lhld    hbuf    ;pt to heading buffer
       mov     m,a     ;store zero to set no heading
       pop     h
;
       if      timeok
       call    time    ;get time string
       lxi     d,timebf        ;store in buffer
initt:
       mov     a,m     ;get byte
       stax    d
       inx     h       ;pt to next
       inx     d
       ora     a       ;done?
       jnz     initt
       endif
;
       RET
;
;  **** FUNCTION COMPLETE -- CLEANUP AND EXIT
;       FILL THIS IN WITH CLEANUP CODE FOR EXIT
;
DINIT:
       RET
;
;  **** OPTION TABLE USED TO PROCESS COMMAND LINE
;       EACH OPTION IS A CAPITAL LETTER OR SPECIAL CHAR FOLLOWED BY
;               AN ADDRESS; THE TABLE IS TERMINATED BY A BINARY ZERO
;
OPTAB:
       DB      'I'     ; FILE INSPECTION OPTION
       DW      OPTINSP ; REMOVE THESE TWO LINES AND THE FOLLOWING ROUTINE
                       ;   IF YOU DO NOT WANT FILE INSPECTION OPTION IN
                       ;   COMMAND LINE
       db      'H'     ;heading
       dw      opthead
       db      'L'     ;line numbers
       dw      optln
       db      'O'     ;offset
       dw      optoffs
       db      'S'     ;skip
       dw      optskip
;
       if      timeok
       db      'T'     ;time display
       dw      opttime
       endif
;
       DB      0       ; END OF TABLE
;
;  **** OPTION ROUTINES
;       EACH ROUTINE IS PROVIDED THE OPTION CHARACTER IN THE A REGISTER
;       AND A POINTER TO THE NEXT CHARACTER IN THE COMMAND LINE IN THE
;       HL REGISTER PAIR; ONLY HL NEED TO BE PRESERVED (WITH OPTIONAL
;       ADVANCEMENT TO THE NEXT OPTION) ON EXIT
;
OPTINSP:
       MVI     A,0FFH  ; TURN ON FILE INSPECTION OPTION
       STA     V$INSPECT       ; THIS IS PROVIDED AS A SAMPLE ROUTINE
                               ;   AND FOR THE INDICATED FUNCTION
       RET
;
;  Set Page Offset
;
optoffs:
       call    eval10  ;get number
       mov     a,e     ;get low-order byte
       sta     offset  ;set offset
       ret
;
;  Option:  H (Set Heading)
;
opthead:
       xchg
       lhld    hbuf    ;pt to heading buffer
       xchg
       mov     a,m     ;get delim
       ora     a       ;none?
       rz
       mov     b,a     ;delim in B
       inx     h       ;pt to next char
opthd1:
       mov     a,m     ;get next char
       ora     a       ;done?
       jz      opthd3
       cmp     b       ;done?
       jz      opthd2
       stax    d       ;save char
       inx     h       ;pt to next
       inx     d
       jmp     opthd1
opthd2:
       inx     h       ;skip over delim
opthd3:
       xra     a       ;store ending 0
       stax    d
       ret
;
;  Option:  L (Set Line Numbering)
;
optln:
       lda     lnumfl  ;flip flag
       cma
       sta     lnumfl
       ret
;
;  Option:  S (Skip Lines)
;
optskip:
       mvi     a,0ffh  ;set flag
       sta     skipfl
       call    eval10  ;get number
       xchg
       shld    skipnum ;set page number to skip to
       xchg            ;HL pts to next char
       mov     a,d     ;see if page number was zero
       ora     e
       rnz
       xra     a       ;if zero, turn off skip flag
       sta     skipfl
       ret
;
       if      timeok
;
;  Set Time Flag
;
o
pttime:
       lda     timepfl ;flip flag
       cma
       sta     timepfl
       ret
;
       endif
;
;  **** FUNCTION -- MAIN FUNCTION OF TEMPLATE
;       ON ENTRY, HL PTS TO NAME OF FILE (16 BYTES) AND USER IS LOGGED INTO
;               DIRECTORY CONTAINING INDICATED FILE
;
FUNCTION:
;
;  HELP FILE PRINT Routine -- Print the Help File Whose Name is Pointed to by
;       HL; we are already logged into the correct directory
;
       call    prinit  ;init print buffers
       call    fload   ;load buffer initially
       call    prhead  ;print heading line
       lhld    V$SCRATCH       ;pt to first char in file
       shld    nxtln   ;set pointer to next line
       mvi     a,0ffh  ;first line
       sta     firstf
       call    prline  ;print first line (special case)
       xra     a       ;not first line now
       sta     firstf
fprloop:
       call    prline  ;print line of file
       jnz     fprloop ;done if EOF
       call    page    ;advance to top of next page
       ret
;
;  Init Print Buffers and Print File Name
;
prinit:
       lxi     d,tfcb  ;set up FCB
       mvi     b,12    ;12 bytes
       call    moveb
       lxi     h,0     ;HL=0
       shld    lnum    ;set line number
       inx     h       ;HL=1
       shld    pnum    ;set page number
       lda     ltpp    ;set line count
       sta     lcount
       call    eprint
       db      cr,lf,' Printing Help File ',0
       lxi     h,tfcb  ;pt to FCB
       call    e$prfn  ;print file name
       ret
;
;  FILE LOAD (FLOAD) Routine -- Initial Load of memory buffer
;
fload:
       lxi     d,tfcb  ;pt to file fcb
       call    initfcb ;init file's fcb
       call    f$open  ;open file for input
       jz      fload1  ;open was OK
       call    eprint
       db      cr,lf,' File ',0
       xchg            ;HL pts to FCB
       call    e$prfn  ;print file name
       call    eprint
       db      ' NOT Found',0
       pop     d       ;clear return address
       ret             ;abort printout of this file
;
;  This is an entry point for further memory loads of the file
;
fload1:
       lda     V$BCNT  ;get number of blocks to load
       mov     c,a     ;... in C
       lhld    V$SCRATCH       ;get address of first block to load into
       shld    nxtblk  ;set pointer to next block to load
fload2:
       call    rdblk   ;read a block (128 bytes)
       jnz     eof     ;eof encountered?
       call    rdblk   ;read another block (128 bytes)
       jnz     eof     ;eof encountered?
       dcr     c       ;count down
       jnz     fload2
       lhld    nxtblk  ;pt to next byte to load
       mvi     m,eold  ;mark end of load
       ret
eof:
       lxi     d,tfcb  ;close file
       call    f$close
       lhld    nxtblk  ;ensure ^Z
       mvi     m,ctrlz
       ret
rdblk:
       lxi     d,tfcb  ;pt to FCB
       call    f$read  ;read next block
       ora     a       ;error?
       rnz
       lhld    nxtblk  ;get ptr to next block
       xchg            ; as dest
       lxi     h,tbuff ;ptr to DMA address
       mvi     b,128   ;copy 128 bytes
rdblk1:
       mov     a,m     ;get byte
       ani     7fh     ;mask out msb
       stax    d       ;put byte
       inx     h       ;pt to next
       inx     d
       dcr     b       ;count down
       jnz     rdblk1
       xchg            ;new nxtblock
       shld    nxtblk
       ret

;
;  Line Print Routine
;       Print Next Line with Optional Disk Load
;       Input Parameter is NXTLN, which is the address of the first char
; on the next line
;       Output Parameter is Zero Flag, with Z meaning done with print, NZ
; meaning more yet to print
;
prline:
       lhld    lnum    ;increment line number
       inx     h
       shld    lnum
prl0:
       lhld    nxtln   ;pt to first char of next line
       lda     firstf  ;first char?
       ora     a       ;0=no
       jnz     prl01
       mov     a,m     ;get first char of line
       cpi     ':'     ;new information section?
       cz      page    ;page eject with heading
prl01:
       call    proffs  ;print offset
       mvi     c,0     ;init char count
       mov     a,m     ;get first char of line
       cpi     ctrlz   ;EOF?
       cnz     prlnum  ;print line number (optional)
prl1:
       mov     a,m     ;get char
       cpi     eold    ;end of load?
       jz      prload
       cpi     ctrlz   ;eof?
       jz      prexit
       inx     h       ;pt to next char
       cpi     ctrli   ;tab?
       jz      prtab
       cpi     cr      ;<CR>?
       jz      prldn
       cpi     ff      ;form feed?
       jz      prldn
       cpi     lf      ;end of line?
       jz      prl1
       cpi     ctrlh   ;back space?
       jz      prbs
       cpi     ctrlg   ;ring bell?
       jz      prbell
       cpi     del     ;delete char?
       jz      prl1    ;skip it
       cpi     ' '     ;other control char?
       jc      prl1    ;skip if other control char
       call    prout   ;print char
       inr     c       ;increment char count
       call    eoltest ;check to see if at end of line and newline if so
       jmp     prl1
;
;  End of Load Reached -- Load More of File from Disk
;
prload:
       push    b       ;save char count
       call    fload1  ;use load routine
       pop     b       ;get char count
       lhld    V$SCRATCH       ;next byte is here
       jmp     prl1    ;continue processing
;
;  Tabulate
;
prtab:
       mvi     a,' '   ;space
       call    prout
       inr     c       ;new char
       call    eoltest ;process EOL
       mov     a,c     ;done?
       ani     7
       jnz     prtab   ;continue tabulation
       jmp     prl1    ;continue processing
;
;  Exit with Zero Flag Set if Done
;
prexit:
       xra     a       ;set zero flag
       ret
;
;  Carriage Return -- End of Routine
;
prldn:
       mov     a,m     ;skip to non-LF
       cpi     lf
       jnz     prldn1
       inx     h       ;skip to first char of next line
prldn1:
       mvi     a,cr    ;output <CR>
       call    prout
       mvi     a,lf    ;output <LF>
       call    prout   ;echo LF to printer
       shld    nxtln   ;set ptr to first char of next line
       mvi     a,0ffh  ;set not done
       ora     a       ;set flags
       ret
;
;  Backspace on Printer
;
prbs:
       mov     a,c     ;check for beginning of line
       ora     a
       jz      prl1    ;continue if at BOL
       mvi     a,ctrlh ;backspace
       call    prout
       dcr     c       ;back up char position
       jmp     prl1    ;continue
;
;  Ring Bell on Printer
;
prbell:
       call    prout   ;ring the bell
       jmp     prl1    ;continue without advancing char position
;
;  Test for End of Line and Process if so
;
eoltest:
       lda     offset  ;get offset
       mov     b,a     ;... in B
       lda     lwidth  ;get line width
       sub     b       ;subtract offset
       sui     4       ;4 chars less for continuation mark
       mov     b,a     ;result in B
       lda     lnumfl  ;line numbering (lines are 7 chars shorter if so)
       ora     a       ;0=no
       jz      eolt1
       mov     a,b     ;reduce by 7 for line numbers
       sui     7
       mov     b,a
eolt1:
       mov     a,b     ;get line width
       cmp     c       ;there?
       rnz             ;continue if not
       mov     a,m     ;get next char
       cpi     cr      ;new line next?
       rz              ;continue if so
       cpi     ctrlh   ;backspace next?
       rz              ;continue if so
       mvi     b,3     ;look ahead 3 chars
       push    h
eolt2:
       inx     h       ;pt to next
       mov     a,m     ;get char
       cpi     cr      ;EOL?
       jz      eolt3
       dcr     b       ;count down
       jnz     eolt2
       jmp     eolt4
eolt3:
       pop     h       ;restore ptr
       ret
eolt4:
       pop     h       ;restore ptr
       mvi     a,' '   ;print continuation chars
       call    prout
       mvi     a,'<'
       call    prout
       mvi     a,'<'
       call    prout
       mvi     a,cr    ;new line
       call    prout
       mvi     a,lf
       call    prout
       mvi     c,0     ;reset char position
       lda     skipfl  ;skipping?
       ora     a       ;0=no
       rnz
       call    proffs  ;print offset
       lda     lnumfl  ;printing line numbers?
       ora     a       ;0=no
       rz
       call    lprint
       db      '     : ',0
       ret
;
;  Output a character to the printer
;       A = Character
;
prout:
       mov     b,a     ;char in B
       call    condin  ;check for abort
       jz      prout1
       cpi     ctrlc   ;abort?
       jz      abort
       cpi     ctrlx   ;abort this one file?
       jz      cxabort
prout1:
       lda     skipfl  ;skipping?
       ora     a       ;set flags (Z=no skip=print char)
       mov     a,b     ;restore char
       cz      lout    ;send character to printer
       cpi     lf      ;special tests if it is a line feed
       rnz             ;done if non-LF char
       lda     lcount  ;decrement line counter
       dcr     a
       sta     lcount
       rnz
;
;  Paging Required
;       Skip to top of next page; reset LCOUNT (Lines Left on Page Count);
;       print header
;
prout0:
       lda     ltpp    ;get number of text lines per page
       sta     lcount  ;set as new line count
       push    h       ;save ptr
       lhld    pnum    ;increment page number
       inx     h
       shld    pnum
       lda     lspp    ;get number of lines to skip per page
       call    lineskp ;skip lines
       pop     h       ;restore ptr
       mov     a,m     ;check next character
       cpi     ctrlz   ;EOF?
       cnz     prhead  ;print 2-line heading if NOT EOF
       ret
;
;  Abort current file with final page eject
;
cxabort:
       lda     lcount  ;get count of remaining lines
       call    lineskp ;skip lines
       lda     lff     ;form feed?
       ora     a       ;NZ=yes
       jnz     e$fctlnxt       ;continue with next file since already FF
       lda     lspp    ;number of lines to skip per page
       call    lineskp ;skip lines
       jmp     e$fctlnxt       ;continue with next file
;
;  Skip out rest of page
;       Form Feed Function
;
page:
       lda     lff     ;form feed?
       ora     a       ;NZ=yes
       jnz     prout0  ;PROUT0 will FF
       lda     lcount  ;get count of remaining lines
       call    lineskp ;skip lines
       jmp     prout0  ;process top of new page
;
;  Skip out lines on page
;       A = number of lines to skip
;
lineskp:
       mov     b,a     ;line count in B
       ora     a       ;any?
       rz
       lda     skipfl  ;skipping?
       ora     a
       rnz
       lda     lff     ;form feed?
       ora     a       ;NZ=yes
       jnz     lines2
lines1:
       mvi     a,cr    ;output new line to printer
       call    lout
       mvi     a,lf
       call    lout
       dcr     b       ;count down
       jnz     lines1
       ret
lines2:
       mvi     a,cr    ;output new line
       call    lout
       mvi     a,ff    ;output form feed
       jmp     lout

;
;  Print Line Number (optional)
;
prlnum:
       lda     skipfl  ;skipping?
       ora     a       ;0=no
       rnz
       lda     lnumfl  ;get flag
       ora     a       ;0=don't number lines
       rz
       push    h       ;save ptr
       lhld    lnum    ;get line number
       call    lhldc   ;print line number
       call    lprint  ;print separator
       db      ': ',0
       pop     h       ;restore ptr
       ret
;
;  Print 2-line heading and control skipping
;
prhead:
       push    h       ;save ptr
       lda     skipfl  ;currently skipping?
       ora     a       ;0=no
       cnz     skiptst ;test for shut off
       call    proffs  ;print offset
       call    prpnum  ;print page heading and number
       call    e$prfname       ;print file name
;
       if      timeok  ;time available?
       lda     timepfl ;print time?
       ora     a       ;0=no
       cnz     prtime  ;print time
       endif
;
       push    h       ;get first char of heading
       lhld    hbuf
       mov     a,m
       pop     h
       ora     a       ;0=no
       cnz     prhdg   ;print heading
       pop     h       ;restore ptr
       lda     skipfl  ;skipping?
       ora     a
       rnz
       call    lcrlf   ;new line
       jmp     lcrlf
;
;  Test for completion of skipping
;
skiptst:
       lhld    pnum    ;get page number
       xchg            ;... in DE
       lhld    skipnum ;get page to skip to
       mov     a,h     ;compare them
       cmp     d
       rnz
       mov     a,l
       cmp     e
       rnz
       xra     a       ;A=0 to stop skipping
       sta     skipfl  ;set flag
       ret
;
;  Print Page Number
;
prpnum:
       lda     skipfl  ;skipping?
       ora     a
       rnz
       call    lprint  ;print header
       db      'Page ',0
       lhld    pnum    ;print current page number
       call    lhldc   ;print as decimal
       ret
;
;  Print File Name
;
e$prfname:
       lda     skipfl  ;skipping?
       ora     a
       rnz
       call    lprint  ;print separator
       db      ' -- Help File: ',0
       lxi     h,tfcb+1        ;pt to first char
       mvi     b,8     ;8 chars
       call    lfn1
       mvi     a,'.'
       call    lout
       mvi     b,3     ;3 chars
       call    lfn1
       ret
lfn1:
       mov     a,m     ;get char
       ani     7fh     ;mask
       call    lout    ;send to printer
       inx     h       ;pt to next
       dcr     b       ;count down
       jnz     lfn1
       ret
;
;  Print Separator
;
prdash:
       call    lprint
       db      ' -- ',0
       ret
;
       if      timeok
;
;  Print Time
;
prtime:
       lda     skipfl  ;skipping?
       ora     a
       rnz
       call    prdash  ;print separator
       lxi     h,timebf        ;pt to time stamp
       call    lpstr   ;print
       ret
;
       endif
;
;  Print Header
;
prhdg:
       lda     skipfl  ;skipping?
       ora     a
       rnz
       call    prdash  ;print separator
       lhld    hbuf    ;pt to heading
       call    lpstr   ;print
       ret
       RET
;
;  Print Line Offset
;
proffs:
       lda     skipfl  ;skipping?
       ora     a
       rnz
       push    b       ;save BC
       lda     offset  ;get offset
       ora     a       ;any?
       jz      proff2
       mov     c,a     ;offset in C
proff1:
       mvi     a,' '   ;space over
       call    prout
       dcr     c       ;count down
       jnz     proff1
proff2:
       pop     b
       ret
;
;  **** HELPPR BUFFERS
;
offset:
       ds      1       ;line offset
hltemp:
       ds      2       ;temporary save area for HL
dirbuf:
       ds      2       ;ptr to directory
firstf:
       ds      1       ;first line in file flag
tfcb:
       ds      36      ;FCB for current file
nxtblk:
       ds      2       ;ptr to next block to load
nxtln:
       ds      2       ;ptr to next line to read
lcount:
       ds      1       ;count of text lines left on page
hlptyp:
       db      'HLP'   ;file type of HLP file

;***********************************************
;*  End of Application-Specific Section
;***********************************************

;
;  BUFFERS
;
V$DISK:
       DS      1       ; HOME DISK NUMBER
V$USER:
       DS      1       ; HOME USER NUMBER
V$CDISK:
       DS      1       ; CURRENT DISK NUMBER
V$CUSER:
       DS      1       ; CURRENT USER NUMBER
V$CMDLNE:
       DS      2       ; PTR TO COMMAND LINE STRING
V$NEXTCH:
       DS      2       ; PTR TO NEXT CHAR IN MULTIFILE COMMAND LINE
V$FILECNT:
       DS      2       ; COUNT OF NUMBER OF FILES RENAMED
V$SCRATCH:
       DS      2       ; ADDRESS OF FIRST BYTE OF SCRATCH AREA
V$BCNT:
       DS      1       ; NUMBER OF PAGES IN SCRATCH AREA
V$INSPECT:
       DS      1       ; INSPECT FLAG
V$NTFCB:
       DS      36      ; FCB FOR NEW FILE
;
;  Stack
;
V$STACK:
       DS      2       ; OLD STACK PTR

       END