;
;  PROGRAM NAME:  HELP
;  AUTHOR:  RICHARD CONN
;  DATE:  18 MAY 84
;  VERSION:  5.0
;  PREVIOUS VERSIONS:  None
;  DERIVATION:  HELP2.ASM 4.1 (23 MAY 83)
;  NOTE:  FOR USE WITH ZCPR3 ONLY
;
VERS    EQU     50
Z3ENV   SET     0F400H

;
;       HELP supports an online documentation system under ZCPR3.  Refer
; to the file HELP.HLP for more details.
;

FALSE           EQU     0
TRUE            EQU     NOT FALSE

;
; USER EQUATES:
;  Set this to TRUE if all files must be of type HLP
;
FORCEHLP                EQU     TRUE    ; TRUE IF FILES MUST BE OF TYPE HLP

;
;  Directory of Help Files if HELP Directory not found
;
HDISK                   EQU     'A'-'A' ; DISK
HUSER                   EQU     15      ; USER

;
;  Enter/Exit Standout Mode (Recommended that these values not be changed)
;
DIM                     EQU     'A'-'@' ; ^A TO ENTER STANDOUT
NOTDIM                  EQU     'B'-'@' ; ^B TO EXIT STANDOUT

;
;  SYSLIB ROUTINES
;
       EXT     Z3VINIT,CLS,STNDOUT,STNDEND
       EXT     GETCRT,GETPRT,PFIND,Z3LOG,DIRTDU
       EXT     CODEND
       EXT     LOGUD,RETUD,PUTUD,GETUD
       EXT     EPSTR,EPRINT,COUT,CIN,CAPS,PFN2,PAFDC
       EXT     INITFCB,F$EXIST,F$OPEN,F$READ,F$CLOSE

;
;  CP/M Constants
;
UDFLAG          EQU     4       ; ADDRESS OF USER/DISK FLAG
BDOS            EQU     5       ; ADDRESS OF BDOS ENTRY POINT
FCB             EQU     5CH     ; ADDRESS OF FILE CONTROL BLOCK
BUFF            EQU     80H     ; ADDRESS OF DMA BUFFER

CR              EQU     0DH     ; <CR>
LF              EQU     0AH     ; <LF>
BEL             EQU     'G'-'@' ; ^G
FF              EQU     'L'-'@' ; ^L = FORM FEED
CTRLZ           EQU     'Z'-'@' ; ^Z
CTRLC           EQU     'C'-'@' ; ^C

;
;  HELP Control Characters
;
IHCHAR          EQU     ';'     ; FLAG INDICATING INDEXED BY USER
SECTCHAR        EQU     ':'     ; DEFINED TO BE COLON
BACKUPCHAR      EQU     'L'     ; BACK UP TO PREVIOUS FRAME CHAR
STRTCHAR        EQU     'S'     ; JUMP TO START OF INFORMATION CHAR
MENUCHAR        EQU     'M'     ; CHAR TO ABORT TO MENU
CPMABORTCHAR    EQU     CTRLC   ; CHAR TO EXIT
LRCHAR          EQU     '^'     ; RETURN TO PREVIOUS HELP LEVEL
ROOTCHAR        EQU     '.'     ; RETURN TO ROOT OF HELP
PRCHAR          EQU     'P'     ; PRINT CURRENT FRAME
CPRCHAR         EQU     'P'-'@' ; PRINT CURRENT INFORMATION SECTION

;
; 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    z3vinit ;initialize the ZCPR3 Env and the VLIB Env
       jmp     startx
;
;  DEFAULT FILE NAME
;
HELPDIR:
DEFFN:
       DB      'HELP    '      ; BOTH HELP FILE AND HELP DIR SAME NAME
DEFTYP:
       DB      'HLP'

;
;  Start of Program
;
STARTX:
       LXI     H,0     ; GET SP
       DAD     SP
       SHLD    STACK
       CALL    CODEND  ; DETERMINE FREE MEMORY SPACE
       SHLD    HLPNSTK ; SET PTR TO HELP NAME STACK
       LXI     D,200H  ; ALLOW 25+ ELEMENT HELP NAME STACK AND LARGE STACK
       DAD     D
       SHLD    HLPBUF
       SPHL            ; SET STACK

       LDA     BDOS+2  ; BASE PAGE OF BDOS
       SUI     10      ; 2K + 2 PAGES
       STA     TPAEND

       XRA     A       ; A=0
       STA     HLPLVL  ; SET HELP LEVEL TO 0 (NO RETURN FILE)

       LXI     D,FCB   ; PT TO FCB
       CALL    Z3LOG   ; LOG INTO IT FOR DEFAULT
       CALL    PUTUD   ; SAVE HOME

       LXI     H,FCB+1 ; CHECK FOR FILE NAME
       MOV     A,M
       CPI     '/'     ; OPTION CAUGHT?
       JZ      STRT0
       CPI     ' '     ; NONE?
       JNZ     STRT1
;
;  INSERT 'HELP.HLP' INTO FCB OR CLEAR FCB
;
STRT0:
       LXI     D,DEFFN ; PT TO DEFAULT NAME
       MVI     B,11    ; 11 BYTES
       XCHG
       CALL    MOVE    ; MOVE (HL) TO (DE) FOR (B) BYTES

;
;  START/RESTART HELP PROGRAM (START ON INITIAL ENTRY, RESTART ON NODE LOAD)
;
STRT1:
       LHLD    HLPBUF  ; RESET STACK
       SPHL
;
;  CHECK FOR WILD CARDS IN FILE NAME -- ERROR IF SO
;
       LXI     H,FCB+1 ; PT TO FIRST BYTE OF FILE NAME
       MVI     B,11    ; 11 BYTES
FCBWCK:
       MOV     A,M     ; GET BYTE
       ANI     7FH     ; MASK
       CPI     '?'     ; WILD?
       JZ      FCBWERR
       INX     H       ; PT TO NEXT
       DCR     B
       JNZ     FCBWCK
;
;  CHECK FOR FILE TYPE
;
       LXI     H,FCB+9 ; CHECK FOR FILE TYPE

       IF      NOT FORCEHLP
       MOV     A,M     ; CHECK FOR FILE TYPE SPECIFIED
       CPI     ' '     ; NONE?
       JNZ     STRT2
       ENDIF
;
;  PLACE DEFAULT FILE TYPE OF '.HLP' IN FCB
;
       LXI     D,DEFTYP        ; DEFAULT FILE TYPE
       MVI     B,3
       XCHG
       CALL    MOVE    ; MOVE (HL) TO (DE) FOR (B) BYTES

;
;  FIND FILE
;
STRT2:
;
;  LOOK INTO DIRECTORY PTED TO BY USER (OR CURRENT IF USER DID NOT SPEC ONE)
;
       LXI     D,FCB           ; PT TO FCB
;       CALL    Z3LOG           ; LOG INTO DIRECTORY
       CALL    INITFCB         ; RESET FCB
       CALL    RETUD           ; GET HOME LOCATION
       CALL    F$EXIST         ; IS FILE THERE?
       JNZ     STRT3
;
;  LOOK ALONG PATH FROM CURRENT DIR (NOT INCLUDING CURRENT)
;
       CALL    GETUD           ; RETURN HOME
       LXI     D,FCB           ; PT TO FCB
       MVI     A,0             ; DON'T SEARCH CURRENT DIR ALSO
       CALL    PFIND           ; SEARCH FOR FILE
       JNZ     STRT3           ; FILE FOUND, SO PROCESS
;
;  LOOK IN HELP FILE DIRECTORY
;
       LXI     H,HELPDIR       ; LOOK FOR HELP DIRECTORY
       CALL    DIRTDU          ; CONVERT TO DU IN BC
       JNZ     LOGHLP          ; LOG INTO DU IN BC IF FOUND
       MVI     B,HDISK         ; LOG INTO HELP DIRECTORY
       MVI     C,HUSER
LOGHLP:
       CALL    LOGUD
       LXI     D,FCB           ; PT TO FCB
       CALL    F$EXIST         ; LOOK FOR FILE
       JNZ     STRT3           ; FILE FOUND
;
;  FILE NOT FOUND
;
       CALL    EPRINT
       DB      CR,LF,' File Not Found',0
       JMP     HLPEXIT

;
;  FILE CONTAINS WILD CARDS
;
FCBWERR:
       CALL    EPRINT
       DB      CR,LF,' AFN Not Allowed',0
       JMP     HLPEXIT

;
;  LOAD HELP FILE INFORMATION
;       ON INPUT, BC=DIRECTORY
;
STRT3:
       CALL    LOGUD           ; LOG INTO DIRECTORY
       LXI     D,FCB           ; OPEN FILE
       CALL    F$OPEN
       LHLD    HLPBUF  ; PT TO BUFFER
       SHLD    NEXTADR ; SET PTR
;
;  READ RECORDS UNTIL EOF
;
STRT4:
       CALL    READ    ; READ INFO
       JZ      STRT4   ; NOT DONE IF ZERO RETURN
       LXI     D,FCB   ; CLOSE FILE
       CALL    F$CLOSE
       CALL    GETUD   ; RESTORE CURRENT DISK AND USER IF CHANGED

;
;  START OF HELP PROGRAM
;
HELP:
       LHLD    HLPBUF  ; PT TO BUFFER
       SPHL            ; SET STACK
       MVI     A,0     ; SET NO FRAME
       STA     FRNUM
       MOV     A,M     ; NO HEADER SECTION?
       ANI     7FH     ; MASK OUT MSB
       CPI     SECTCHAR
       JNZ     HELP1   ; HEADER SECTION EXISTS
       CALL    CLS     ; NEW SCREEN
       CALL    PRINFO  ; PRINT HELP INFO PTED TO BY HL
       LDA     HLPLVL  ; CHECK TO SEE IF WE ARE NOT AT LEVEL 0
       ORA     A       ; 0=LEVEL 0
       JZ      HLPEXIT ; ABORT IF SO
       JMP     LRURN   ; GO TO PREVIOUS LEVEL IF NOT

;
;  EXIT POINT FOR ANY EXIT FROM THE REST OF THE HELP PROGRAM
;
HLPEXIT:
       CALL    GETUD   ; RESET CALLING DISK/USER NUMBER
       LHLD    STACK   ; GET CP/M SP
       SPHL
       RET             ; DONE

;
;  PRINT HEADER INFORMATION AND SELECT AN OPTION
;
HELP1:
       CALL    PRHEADER        ; PRINT HEADER
       PUSH    B               ; SAVE C (NUMBER OF VALID SELECTIONS)
       CALL    CRLF1           ; NEW LINE
       CALL    STNDOUT         ; GOTO DIM
       CALL    PRLEVEL         ; PRINT LEVEL NUMBER
       CALL    EPRINT
       DB      'Enter Selection  ',0
       CALL    PRP1            ; PRINT LEVEL MOVEMENT PROMPT
       CALL    STNDEND         ; GOTO BRIGHT
       POP     B               ; GET C
       CALL    CIN             ; GET RESPONSE
       CALL    CAPS            ; CAPITALIZE
       PUSH    PSW
       CALL    CLS             ; CLEAR SCREEN
       POP     PSW
       CPI     CTRLC           ; EXIT
       JZ      HLPEXIT
       CPI     ROOTCHAR        ; GO TO ROOT
       JZ      GOROOT
       CPI     LRCHAR          ; RETURN TO PREVIOUS LEVEL
       JZ      LRURN
       MOV     B,A             ; USER INPUT IN B
       LDA     HTYPE           ; TYPE OF HELP FILE
       CPI     IHCHAR          ; INDEXED BY USER?
       JZ      HELP5           ; FIND INFORMATION SECTION VIA INDEX SCAN
       MOV     A,B             ; FIND INFORMATION SECITON VIA COUNT
       SUI     'A'-1           ; ADJUST FOR COUNT
       MOV     B,A             ; SAVE COUNT
       JZ      BADRESPONSE
       JNC     HELP2
;
;  INVALID RESPONSE
;
BADRESPONSE:
       CALL    SAK             ; RING BELL
       JMP     HELP1

;
;  VALID RESPONSE -- LOOK FOR AND PRINT INFORMATION SECTION
;
HELP2:
       INR     C               ; 1 MORE THAN NUMBER OF POSSIBLE SELECTIONS
       CMP     C               ; GREATER THAN NUMBER OF POSSIBLE SELECTIONS?
       JNC     BADRESPONSE
       LHLD    FIRSTENTRY      ; GET PTR TO FIRST ENTRY

;
;  PRINT INFORMATION WHEN COUNT IS ZERO
;
HELP3:
       DCR     B       ; COUNT DOWN SELECTIONS
       JNZ     HELP4
       CALL    PRINFO  ; PRINT INFO PTED TO BY HL
       JMP     HELP1
;
;  LOCATE NEXT INFORMATION SECTION
;
HELP4:
       CALL    FINDI   ; SKIP TO NEXT INFORMATION SECTION
       CPI     CTRLZ   ; END OF FILE?
       JNZ     HELP3   ; CONTINUE LOOPING IF NOT ELSE FALL THRU TO HELPERR
;
;  ERROR -- REACHED END OF HELP FILE
;
HELPERR:
       CALL    EPRINT
       DB      CR,LF,' EOF on Help File',0
       JMP     HELP1

;
;  LOCATE NEXT INFORMATION SECTION VIA INDEX SCAN
;
HELP5:
       LHLD    FIRSTENTRY      ; PT TO FIRST ENTRY
;
;  LOOK FOR USER INDEX
;
HELP6:
       PUSH    H               ; SAVE PTR TO THIS LINE
HELP7:
       INX     H               ; SKIP OVER SECTION CHAR
       MOV     A,M             ; GET CHAR
       ANI     7FH             ; MASK OUT MSB
       CALL    CAPS            ; CAPITALIZE
       CPI     ' '             ; SKIP SPACES
       JZ      HELP7
       CPI     SECTCHAR        ; NEW SECTION?
       JZ      HELP8           ; FIND NEXT SECTION
       CPI     CR              ; END OF LINE?
       JZ      HELP8           ; FIND NEXT SECTION
       CPI     CTRLZ           ; EOF?
       JZ      HELP8
       CMP     B               ; CHECK FOR USER INPUT
       JNZ     HELP7
       POP     H               ; FOUND IT -- PRINT IT
       INX     H               ; SKIP OVER SECTION CHAR
HELP7A:
       MOV     A,M             ; SKIP TO BEGINNING FOR 1ST LINE
       INX     H               ; PT TO NEXT
       ANI     7FH
       CPI     CTRLZ           ; TRAP EOF
       JZ      BADRESPONSE
       CPI     SECTCHAR        ; FILE SPECIFIED?
       JZ      HELP7B          ; PROCESS IT
       CPI     LF              ; BEGIN NEW LINE
       JZ      HELP7C
       CPI     CR              ; AT END OF INDEX LINE?
       JNZ     HELP7A
       MOV     A,M             ; GET LF
       ANI     7FH
       CPI     LF              ; SKIP FOLLOWING LF IF ANY
       JNZ     HELP7C
       INX     H               ; SKIP LF
       JMP     HELP7C
;
;  LOAD NEXT HELP LEVEL
;
HELP7B:
       DCX     H               ; PT TO SECTION CHAR
       DCX     H               ; PT TO BEFORE SECTION CHAR FOR PRINFO
;
;  PROCESS HELP LEVEL OR LOAD AND PROCESS NEXT LEVEL PTED TO BY HL
;
HELP7C:
       CALL    PRINFO          ; PRINT INFORMATION SECTION
       JMP     HELP1           ; RESUME
HELP8:
       POP     H               ; PT TO INFO SECTION
       CALL    FINDI           ; FIND NEXT INFO SECTION
       CPI     CTRLZ           ; EOF?
       JNZ     HELP6           ; KEEP LOOKING
       JMP     BADRESPONSE

;
;  SKIP TO NEXT INFORMATION SECTIONS
;    RETURN WITH A=SECTCHAR IF FOUND OR A=^Z IF NOT
;
FINDI:
       MOV     A,M     ; <CTRL-Z>?
       ANI     7FH     ; MASK OUT MSB
       INX     H       ; PT TO NEXT BYTE
       CPI     CTRLZ
       RZ
       CPI     LF      ; LINE FEED?
       JZ      FINDI1
       CPI     CR      ; <CR>?
       JNZ     FINDI
       MOV     A,M     ; MAKE SURE LF
       ANI     7FH
       CPI     LF
       JNZ     FINDI1
       INX     H       ; SKIP OVER LF
FINDI1:
       MOV     A,M     ; GET CHAR
       ANI     7FH     ; MASK OUT MSB
       CPI     SECTCHAR        ; NEW SECTION?
       JNZ     FINDI   ; CONTINUE LOOPING
       RET

;
;  HELP SUPPORT ROUTINE SECTION
;

;
;  PRINT ERROR MSG PTED TO BY DE; ENDS IN 0
;
PRMSG:
       XCHG            ; MSG PTED TO BY HL
       CALL    EPSTR
       XCHG
       RET

;
;  MOVE BYTES PTED TO BY HL TO AREA PTED TO BY DE; B BYTES TO MOVE
;
MOVE:
       MOV     A,M     ; GET BYTE
       ANI     7FH     ; MASK OFF MSB -- IN CASE A WS FILE
       STAX    D       ; PUT BYTE
       INX     H       ; PT TO NEXT
       INX     D
       DCR     B
       JNZ     MOVE
       RET

;
;  READ RECORD FROM DISK; NEXTADR CONTAINS ADDRESS TO READ TO
;       ON RETURN, BDOS ERROR CODE IS IN A (0=NO ERROR)
;
READ:
       LXI     D,FCB   ; PT TO FCB
       CALL    F$READ  ; READ NEXT RECORD
       PUSH    PSW     ; SAVE RETURN CODE
       LHLD    NEXTADR ; PT TO LOAD ADDRESS
       LDA     TPAEND  ; CHECK AGAINST END PAGE OF TPA
       CMP     H       ; IF AT SAME PAGE, YES
       JZ      READERROR
       LXI     D,BUFF  ; PT TO BUFFER TO LOAD FROM
       MVI     B,128   ; NUMBER OF BYTES TO MOVE
       XCHG
       CALL    MOVE
       XCHG
       MVI     M,CTRLZ ; STORE ENDING CTRLZ IN CASE OF EOF
       POP     PSW     ; GET RETURN CODE
       ORA     A       ; DONE?  <>0 IF SO
;
;  READ DONE -- SAVE PTR TO NEXT BLOCK
;
       SHLD    NEXTADR ; SET NEXT ADDRESS
       RET

READERROR:
       CALL    EPRINT
       DB      CR,LF,' Mem Full',0
       JMP     HLPEXIT

;
;  PRINT ONE LINE OF INFO SECTION; HL PTS TO LINE UPON ENTRY;
;       HL PTS TO FIRST CHAR OF NEXT LINE UPON EXIT
;
PRLINE:
       MOV     A,M     ; GET CHAR
       ANI     7FH     ; MASK OUT MSB
       CPI     CR      ; EOL?
       JZ      CRLF
       CPI     LF      ; LINE FEED? (WS FILE)
       JZ      CRLF0
       CPI     CTRLZ   ; END OF FILE?
       JZ      CRLFC   ; DONE IF SO
       INX     H       ; PT TO NEXT
       CPI     DIM     ; GOTO STANDOUT MODE?
       JZ      PRLDIM
       CPI     NOTDIM  ; GOTO NORMAL MODE?
       JZ      PRLNDIM
       CALL    COUT    ; PRINT CHAR
       JMP     PRLINE
PRLDIM:
       CALL    STNDOUT ; ENTER STANDOUT MODE
       JMP     PRLINE
PRLNDIM:
       CALL    STNDEND ; END STANDOUT MODE
       JMP     PRLINE
;
;  PRINT CRLF, PT TO FIRST CHAR OF NEXT LINE, AND PAGE IF NECESSARY
;
CRLF:
       INX     H       ; PT TO LF
CRLF0:
       INX     H       ; PT TO 1ST CHAR OF NEXT LINE
CRLFC:
       CALL    CRLF1   ; PRINT CRLF
       LDA     LCOUNT  ; GET LINE COUNT
       DCR     A
       STA     LCOUNT
       RNZ             ; OK -- CONTINUE
       MOV     A,M     ; SET MSB OF FIRST CHAR OF NEXT LINE
       ORI     80H
       MOV     M,A     ; MSB IS SET FOR LATER BACKUP
       CALL    PRPROMPT        ; PRINT PROMPT AND PROCESS COMMON OPTIONS
       CPI     BACKUPCHAR      ; BACK UP?
       JZ      FBACKUP
       CPI     STRTCHAR        ; JUMP TO START OF INFO
       JZ      INFOSTRT
FRESUME:
       SHLD    STRTFRAME
       JMP     SETLCOUNT
;
;  PRINT PROMPT AND PROCESS COMMON OPTIONS
;
PRPROMPT:
       CALL    STNDOUT ; GOTO DIM
       CALL    PRLEVEL ; PRINT LEVEL NUMBER
       LDA     FRNUM   ; INCREMENT FRAME NUMBER
       INR     A
       STA     FRNUM
       CALL    PRP1    ; PRINT FUNDAMENTAL LEVEL DATA PROMPT
       CALL    EPRINT
       DB      MENUCHAR,'=Menu '       ; ABORT TO MENU CHAR
       DB      STRTCHAR,'=Start '      ; JUMP TO START OF INFORMATION CHAR
       DB      BACKUPCHAR,'=Last '     ; BACK UP TO PREVIOUS FRAME CHAR
       DB      PRCHAR,'=Print '        ; PRINT CURRENT FRAME
       DB      0
       CALL    STNDEND ; GOTO BRIGHT
       CALL    CIN     ; GET RESPONSE
       CALL    CAPS
       PUSH    PSW
       CALL    CLS             ; CLEAR SCREEN
       POP     PSW
       POP     D               ; CLEAR STACK
       CPI     MENUCHAR        ; ABORT?
       JZ      HELP            ; START OVER IF SO
       CPI     CPMABORTCHAR    ; ABORT TO OS
       JZ      HLPEXIT
       CPI     PRCHAR          ; PRINT FRAME?
       JZ      LIST0INFO
       CPI     CPRCHAR         ; PRINT INFORMATION SECTION?
       JZ      LIST1INFO
       CPI     ROOTCHAR        ; GO TO ROOT
       JZ      GOROOT
       CPI     LRCHAR          ; RETURN TO HIGHER LEVEL
       JZ      LRURN
       PUSH    D               ; RESTORE STACK
       RET

;
;  PRINT FUNDAMENTAL LEVEL PROMPT
;
PRP1:
       LDA     HLPLVL          ; DON'T PRINT IF AT LEVEL 0
       ORA     A
       RZ
       CALL    EPRINT
       DB      LRCHAR,'=Level '        ; RETURN TO HIGHER NODE
       DB      ROOTCHAR,'=Root '               ; RETURN TO ROOT
       DB      0
       RET

;
;  JUMP TO START OF INFORMATION
;
INFOSTRT:
       LHLD    STRTINFO        ; PT TO START OF INFO
       MVI     A,1             ; RESET FRAME COUNT
       STA     FRNUM
       JMP     FRESUME ; CONTINUE PROCESSING

;
;  BACK UP TO PREVIOUS FRAME
;
FBACKUP:
       CALL    BOICHECK        ; AT BEGINNING OF INFORMATION?
       JZ      INFOSTRT
FB1:
       DCX     H       ; BACK UP UNTIL BYTE WITH MSB SET IS FOUND
       MOV     A,M     ; GET BYTE
       ANI     80H
       JZ      FB1
       LDA     FRNUM   ; DECREMENT FRAME NUMBER
       DCR     A               ; BACK UP TO CURRENT FRAME NUMBER
       DCR     A               ; BACK UP TO PREVIOUS FRAME NUMBER
       STA     FRNUM
       JMP     FRESUME ; CONTINUE PROCESSING
;
;  PRINT CR AND LF ONLY
;
CRLF1:
       MVI     A,CR    ; PRINT CR
       CALL    COUT
       MVI     A,LF    ; PRINT LF
       JMP     COUT

;
;  SET LCOUNT VARIABLE TO SCREEN SIZE
;
SETLCOUNT:
       PUSH    H       ; SAVE HL
       CALL    GETCRT  ; GET CRT DATA
       INX     H       ; PT TO LINE COUNT
       MOV     A,M     ; GET LINE COUNT
       POP     H       ; RESTORE HL
       DCR     A       ; 1 LESS FOR PROMPT
       STA     LCOUNT
       RET

;
;  PRINT THE HEADER SECTION AND LOAD FIRSTENTRY PTR
;    ON RETURN, C=NUMBER OF POSSIBLE SELECTIONS
;
PRHEADER:
       MVI     A,0     ; SET NO FRAME
       STA     FRNUM
       CALL    SETLCOUNT
       LDA     LCOUNT
       SUI     3       ; -3 lines for top and bottom
       STA     LCOUNT
       MVI     A,'A'   ; INIT SELECTION CHAR
       STA     SELCHAR
       CALL    CLS     ; CLEAR SCREEN
       CALL    EPRINT
       DB      'HELP '
       db      (vers/10)+'0','.',(vers mod 10)+'0'
       DB      '    ',0
       LXI     D,FCB+1 ; PT TO FCB
       CALL    PFN2    ; PRINT WITH NO SPACES
       CALL    EPRINT
       db      ' Index',CR,LF,CR,LF,0
       MVI     C,0     ; COUNT NUMBER OF SELECTIONS
       LHLD    HLPBUF  ; PT TO BUFFER
       MOV     A,M     ; GET FIRST CHAR
       STA     HTYPE   ; SET TYPE OF HELP FILE
       CPI     IHCHAR  ; INDEXED HELP TYPE?
       JNZ     PH1
       INX     H       ; SKIP OVER INDEX HELP TYPE FLAG
;
; PRINT LINE UNTIL FIRST INFORMATION SECTION FOUND
;
PH1:
       MOV     A,M     ; GET CHAR
       ANI     7FH     ; MASK OUT MSB
       CPI     SECTCHAR
       JZ      PH2
       CPI     CTRLZ   ; EOF? -- ABORT
       JZ      HLPEXIT
       INR     C       ; INCREMENT SELECTION COUNT
       LDA     HTYPE   ; CHECK FOR INDEX
       CPI     IHCHAR
       JZ      PH1A    ; SKIP LETTERS IF INDEXED
       LDA     SELCHAR ; DISPLAY SELECTION CHAR
       CALL    COUT
       INR     A       ; INCR CHAR
       STA     SELCHAR
       CALL    EPRINT
       DB      '. ',0
PH1A:
       CALL    PRLINE  ; PRINT HEADER LINE
       JMP     PH1
;
;  SAVE PTR TO FIRST ENTRY
;
PH2:
       SHLD    FIRSTENTRY
       LDA     LCOUNT          ; GET COUNT OF REMAINING LINES
       MOV     B,A             ; ... IN B
       ORA     A               ; ANY LEFT?
       RZ
PH3:
       CALL    CRLF1           ; NEW LINE
       DCR     B
       JNZ     PH3
       RET

;
;  PRINT AN INFORMATION SECTION
;    INFORMATION SECTION IS PTED TO BY HL
;
PRINFO:
       SHLD    STRTINFO        ; SET START OF INFORMATION POINTER
       CALL    LDNOD   ; LOAD NEW NODE IF DUAL SECTCHAR
       SHLD    STRTFRAME       ; SET FRAME POINTER
       MOV     A,M     ; SET MSB
       ORI     80H
       MOV     M,A
       CALL    SETLCOUNT
       MVI     A,1             ; A=1
       STA     FRNUM   ; SET FRAME NUMBER
PI1:
       CALL    PRLINE  ; PRINT LINE FROM INFO FILE
       MOV     A,M     ; DONE?
       ANI     7FH     ; MASK OUT MSB
       CPI     CTRLZ   ; EOF?
       JZ      PI2
       CPI     SECTCHAR        ; NEXT SECTION
       JZ      PI2
       CPI     FF      ; FORM FEED?
       JNZ     PI1
       INX     H       ; PT TO CHAR AFTER FORM FEED
       CALL    FORMFEED        ; FEED SCREEN
       JMP     PI1
;
;  FORM FEED SCREEN
;
FORMFEED:
       LDA     LCOUNT  ; GET LINE COUNT
       MOV     B,A     ; ... IN B
FEEDLOOP:
       PUSH    B       ; SAVE B
       CALL    CRLFC   ; NEW LINE
       POP     B       ; GET B
       DCR     B
       JNZ     FEEDLOOP
       RET

;
;  END OF INFO
;
PI2:
       MOV     A,M     ; SET MSB OF NEXT BYTE
       ORI     80H
       MOV     M,A
PI2A:
       CALL    CRLF1   ; NEW LINE
       LDA     LCOUNT          ; COUNT DOWN
       DCR     A
       STA     LCOUNT
       JNZ     PI2A
PI2MSG:
       CALL    EPRINT          ; PRINT END OF INFORMATION INDICATOR
       DB      'EOI ',0
       CALL    PRPROMPT        ; PRINT PROMPT AND PROCESS COMMON OPTIONS
       CPI     BACKUPCHAR      ; BACK UP FROM EOI?
       JZ      PI2BACKUP
       CPI     STRTCHAR        ; START OF INFO?
       JZ      PI2STRT
       JMP     SET
LCOUNT  ; RESET LINE COUNT IN CASE OF ALL

;
;  JUMP TO START OF INFO FROM EOI
;
PI2STRT:
       LHLD    STRTINFO        ; PT TO START OF INFO
       CALL    FRESUME ; RESET POINTERS
       MVI     A,1             ; RESET FRAME COUNT
       STA     FRNUM
       JMP     PI1             ; CONTINUE PROCESSING

;
;  BACK UP TO PREVIOUS FRAME FROM EOI
;
PI2BACKUP:
       CALL    BOICHECK        ; AT BEGINNING OF INFORMATION?
       JZ      PI2STRT
PI2BACK:
       CALL    FB1             ; BACK UP TO PREVIOUS FRAME
       JMP     PI1             ; CONTINUE PROCESSING

;
;  CHECK FOR POSITION AT BEGINNING OF INFORMATION SECTION
;    IF SO, PRINT BACKUP ERROR MSG AND RETURN W/ZERO SET
;
BOICHECK:
       LHLD    STRTINFO        ; START ADDRESS
       XCHG                    ; ... IN DE
       LHLD    STRTFRAME       ; FRAME ADDRESS
       MOV     A,D             ; EQUAL?
       CMP     H
       RNZ
       MOV     A,E
       CMP     L
       RNZ
       CALL    SAK             ; ERROR BELL
       XRA     A               ; ZERO FLAG SET
       STA     FRNUM           ; SET FRAME NUMBER
       RET

;
;  THIS BODY OF CODE LISTS INFORMATION FROM HELP2 TO THE
;  PRINTER
;

;
;  LIST ONE LINE OF INFO SECTION; HL PTS TO LINE UPON ENTRY;
;       HL PTS TO FIRST CHAR OF NEXT LINE UPON EXIT
;
LISTLINE:
       MOV     A,M     ; GET CHAR
       ANI     7FH     ; MASK OUT MSB
       CPI     CR      ; EOL?
       JZ      LCRLF
       CPI     LF      ; LINE FEED? (WS FILE)
       JZ      LCRLF0
       CPI     CTRLZ   ; END OF FILE?
       JZ      LCRLFC  ; DONE IF SO
       CALL    LSTOUT  ; PRINT CHAR
       RZ              ; ABORT
       INX     H       ; PT TO NEXT
       JMP     LISTLINE

;
;  LIST CRLF, PT TO FIRST CHAR OF NEXT LINE, AND PAGE IF NECESSARY
;
LCRLF:
       INX     H       ; PT TO LF
LCRLF0:
       INX     H       ; PT TO 1ST CHAR OF NEXT LINE
LCRLFC:
       CALL    LCRLF1  ; PRINT CRLF
       LDA     LCOUNT  ; GET LINE COUNT
       DCR     A
       STA     LCOUNT
       JNZ     LNOABT  ; OK -- CONTINUE
       CALL    LFORMFEED       ; ADVANCE TO NEXT PAGE
SETPLC:
       PUSH    H       ; SAVE HL
       CALL    GETPRT  ; GET PRINTER DATA
       INX     H       ; PT TO TEXT LINE COUNT
       INX     H
       MOV     A,M     ; GET TEXT LINE COUNT
       STA     LCOUNT  ; SET LINE COUNT
       POP     H       ; RESTORE HL
       RET
LCRLF1:
       MVI     A,CR    ; SEND <CRLF> TO PRINTER
       CALL    LSTOUT
       RZ              ; ABORT
       MVI     A,LF    ; FALL THRU TO LSTOUT

;
;  PRINT CHARACTER IN A ON PRINTER; AFFECT NO REGISTERS
;
LSTOUT:
       PUSH    H       ; SAVE REGS
       PUSH    D
       PUSH    B
       MOV     E,A     ; CHAR IN E
       MVI     C,5     ; BDOS PRER OUTPUT ROUTINE
       CALL    BDOS
       MVI     E,0FFH  ; CONDITIONAL INPUT
       MVI     C,6     ; DIRECT CONSOLE I/O
       CALL    BDOS
       POP     B       ; RESTORE REGS
       POP     D
       POP     H
       CPI     CTRLC   ; ABORT?
       RET
LNOABT:
       MVI     A,0FFH  ; SET NO ABORT RETURN
       ORA     A       ; SET FLAGS
       RET

;
;  LIST THE CURRENT INFORMATION SECTION
;    INFORMATION SECTION IS PTED TO BY STRTINFO
;
;  LIST0INFO -- LIST CURRENT FRAME ONLY
;  LIST1INFO -- LIST CURRENT INFORMATION SECTION
;
LIST0INFO:
       LHLD    STRTFRAME       ; LIST CURRENT FRAME ONLY
       MVI     A,0FFH          ; SET FLAG
       STA     LFRFLAG         ; LIST FRAME ONLY
       JMP     LIST2INFO
LIST1INFO:
       LHLD    STRTINFO        ; PREPARE TO LIST ENTIRE INFO SECTION
       XRA     A               ; CLEAR FRAME LIST FLAG
       STA     LFRFLAG
LIST2INFO:
       CALL    LISTINFO        ; DO PRINT
       CALL    CLS             ; CLEAR SCREEN
       CALL    LFORMFEED       ; FORM FEED PRINTER
       LHLD    STRTFRAME       ; RETURN TO FRAME WE WERE ON
       CALL    FRESUME
       LDA     FRNUM           ; ADJUST FRAME NUMBERING
       DCR     A
       STA     FRNUM
       JMP     PI1             ; RESUME AT PI1
;
;  MAIN PRINT ROUTINE
;
LISTINFO:
       CALL    CLS             ; PRINT FRAME OR INFO SECTION
       CALL    EPRINT
       DB      CR,LF,' Printing ',0
       CALL    SETPLC          ; SET PRINTER LINE COUNT
LI1:
       CALL    LISTLINE        ; LIST LINE FROM INFO FILE
       CPI     CTRLC           ; ABORT?
       RZ                      ; FEED PRINTER AND EXIT
       MOV     A,M             ; DONE?
       ANI     7FH             ; MASK OUT MSB
       CPI     CTRLZ           ; EOF?
       RZ                      ; RESUME IF AT END OF INFO
       CPI     SECTCHAR        ; NEXT SECTION
       RZ                      ; RESUME IF AT END OF INFO
       CPI     FF              ; FORM FEED?
       JNZ     LI1
       LDA     LFRFLAG         ; LIST FRAME ONLY?
       ORA     A               ; 0=NO
       RNZ
       INX     H               ; PT TO CHAR AFTER FORM FEED
       CALL    LCRLFC          ; NEW LINE
       MVI     B,10            ; PRINT SEPARATOR
LI2:
       MVI     A,'-'           ; DASHES
       CALL    LSTOUT
       RZ                      ; ABORT?
       DCR     B               ; COUNT DOWN
       JNZ     LI2
       CALL    LCRLFC          ; 2 NEW LINES
       CALL    LCRLFC
       JMP     LI1

;
;  FORM FEED PRINTER
;
LFORMFEED:
       CALL    LCRLF1  ; NEW LINE
       MVI     A,FF    ; OUTPUT FORM FEED
       CALL    LSTOUT
       JMP     SETPLC  ; RESET LINE COUNT

;
;  END OF BODY OF CODE WHICH LISTS INFORMATION FROM HELP2 TO
;  THE PRINTER
;

;
;  AT THE BEGINNING OF AN INFORMATION SECTION (HL PTS TO FIRST CHAR)
;    CHECK TO SEE IF ANOTHER SECTCHAR FOLLOWS, AND, IF SO, LOAD THE
;    SPECIFIED FILE AS A NEW NODE AND BEGIN PROCESSING IT
;
LDNOD:
       INX     H       ; PT TO POSSIBLE 2ND SECTCHAR
       MOV     A,M     ; GET IT
       DCX     H       ; PREP FOR RETURN
       ANI     7FH     ; MASK MSB
       CPI     SECTCHAR        ; ANOTHER ONE?
       RNZ             ; PROCESS NORMALLY IF NOT
;
;  WE HAVE A NEW NODE -- CHECK TO SEE IF WE CAN NEST AGAIN
;
       LDA     HLPLVL  ; GET CURRENT HELP LEVEL
       CPI     25      ; AT MAXIMUM?
       JNZ     LDNOD1
       CALL    CLS     ; NEW SCREEN
       CALL    EPRINT
       db      cr,lf,' Node Level Limit',0
       JMP     HLPEXIT

;
;  WE HAVE NOT REACHED LEVEL LIMIT, SO CONTINUE
;  AT THIS TIME, A=HELP LEVEL INDEX AND HL = PTR TO CURRENT SECTION (::)
;
LDNOD1:
;
;  SAVE CURRENT HELP FILE NAME FOR RETURN
;
       INX     H       ; PT TO SECTION SECTCHAR
       INX     H       ; NOW POINTING TO FILE NAME
       PUSH    H       ; SAVE PTR
       CALL    COMPTR  ; HL=POINTER TO STACK ELT INDEXED BY A
       XCHG            ; DE=ADDRESS OF NEXT ELEMENT
;
;  COPY CURRENT NODE ELEMENT NAME INTO NEXT STACK ELEMENT
;
       LXI     H,FCB+1 ; PT TO FILE NAME
       MVI     B,11    ; 11 BYTES
       CALL    MOVE
;
;  INCREMENT HELP LEVEL
;
       LDA     HLPLVL  ; GET OLD LEVEL
       INR     A       ; SET NEW LEVEL
       STA     HLPLVL
;
;  SET UP FCB FOR NEW FILE
;
       POP     H       ; GET PTR TO NEW FILE NAME
       LXI     D,FCB+1 ; PT TO FCB NAME
       MVI     B,8     ; 8 CHARS MAX
       CALL    LDFCB   ; PLACE INTO FCB WITH ERROR CHECKING
       MVI     B,3     ; 3 CHARS MAX FOR TYPE
       CPI     '.'     ; CONTINUE IF FILE TYPE PRESENT
       CZ      LDFCB   ; PLACE INTO FCB WITH ERROR CHECKING
;
;  PRINT LOADING HELP FILE MESSAGE
;
PLHFM:
       CALL    EPRINT
       DB      CR,LF,' Loading HELP File ',0
       LXI     D,FCB+1 ; PRINT FILE NAME
       CALL    PFN2
       JMP     STRT1   ; LOAD NEW HELP FILE

;
;  LOAD FCB PTED TO BY DE WITH "NORMAL" FILE NAME PTED TO BY HL FOR B BYTES
;
LDFCB:
       MOV     A,M     ; GET CHAR
       INX     H       ; PT TO NEXT
       CPI     '.'     ; DONE IF DECIMAL
       JZ      LDFCB2
       CPI     ' '+1   ; DONE IF <= <SP>
       JC      LDFCB2
       CALL    CAPS    ; CAPITALIZE
       STAX    D       ; STORE CHAR
       INX     D       ; PT TO NEXT
       DCR     B
       JNZ     LDFCB
LDFCB1:
       MOV     A,M     ; CHECK FOR ERROR
       ANI     7FH     ; MASK MSB
       INX     H       ; PT TO NEXT CHAR
       CPI     '.'     ; OK IF '.'
       RZ
       CPI     ' '+1   ; OK IF <= <SP>
       RC
       JMP     LDFCB1
LDFCB2:
       MOV     C,A     ; SAVE CHAR THAT TERMINATED STRING
LDFCB3:
       MVI     A,' '   ; <SP> FILL REST OF FCB
       STAX    D       ; STORE <SP>
       INX     D       ; PT TO NEXT
       DCR     B
       JNZ     LDFCB3
       MOV     A,C     ; GET CHAR THAT TERMINATED STRING
       RET

;
;  GO TO ROOT
;
GOROOT:
       LDA     HLPLVL  ; AT ROOT?
       ORA     A       ; 0=YES
       JZ      HELP    ; RETURN TO HELP
       MVI     A,0     ; SET ROOT INDEX
       JMP     GORET

;
;  RETURN TO PREVIOUS HELP LEVEL
;
LRURN:
       LDA     HLPLVL  ; ARE WE AT THE LOWEST LEVEL?
       ORA     A       ; 0=YES
       JNZ     LRET
       CALL    SAK     ; ERROR BELL
       JMP     HELP

;
;  SET NEW HELP LEVEL
;
LRET:
       DCR     A       ; DOWN 1 AND FALL THRU TO GORET

;
;  GO TO HELP LEVEL INDEXED IN A
;
GORET:
       STA     HLPLVL  ; SET NEW HELP LEVEL
       CALL    COMPTR  ; HL=POINTER TO TARGET HELP FILE NAME
       LXI     D,FCB+1 ; COPY ELEMENT INTO FCB
       MVI     B,11    ; 11 BYTES
       CALL    MOVE
       JMP     PLHFM   ; PRINT LOADING MESSAGE AND LOAD

;
;  COMPUTE POINTER TO HELP NAME ENTRY INDEXED BY HELP LEVEL IN A
;
COMPTR:
       MOV     L,A     ; VALUE IN HL
       MVI     H,0     ; COMPUTE OFFSET AS INDEX*11
       MOV     E,L     ; DE=HL
       MOV     D,H
       DAD     H       ; *2
       DAD     H       ; *4
       DAD     H       ; *8
       DAD     D       ; *9
       DAD     D       ; *10
       DAD     D       ; *11
       XCHG            ; RESULT IN DE
       LHLD    HLPNSTK ; PT TO BASE OF HELP NAMES
       DAD     D       ; ADD IN OFFSET
       RET

;
;  PRINT LEVEL NUMBER
;
PRLEVEL:
       LDA     HLPLVL  ; DON'T PRINT LEVEL 0
       ORA     A       ; 0?
       JZ      PRFRAME
       CALL    EPRINT
       DB      'Level ',0
       LDA     HLPLVL  ; GET NUMBER
       CALL    PAFDC           ; PRINT AS DECIMAL
       LDA     FRNUM   ; GET FRAME NUMBER
       ORA     A       ; SET FLAGS
       MVI     A,'/'   ; PREP TO PRINT SLASH
       CNZ     COUT    ; PRINT SLASH IF FRAME IS NON-ZERO
PRFRAME:
       LDA     FRNUM   ; GET NUMBER
       ORA     A
       MVI     A,' '   ; PREP TO PRINT SPACE ON EXIT
       JZ      COUT
       LDA     FRNUM   ; GET FRAME NUMBER AGAIN
       CALL    PAFDC   ; PRINT AS DECIMAL
       CALL    EPRINT
       DB      ': ',0
       RET

;
;  RING ERROR BELL
;
SAK:
       MVI     A,BEL
       JMP     COUT

;
;  BUFFER SECTION
;
HTYPE:
       DS      1       ; TYPE OF HELP FILE (IF = IHCHAR, IT IS INDEXED BY USR)
LFRFLAG:
       DS      1       ; LIST FRAME ONLY FLAG (FOR PRINT FUNCTION)
TPAEND:
       DS      1       ; END PAGE ADDRESS OF TPA
STRTINFO:
       DS      2       ; PTR TO START OF CURRENT INFORMATION BLOCK
STRTFRAME:
       DS      2       ; PTR TO START OF CURRENT FRAME
SELCHAR:
       DS      1       ; SELECTION TABLE OPTION CHAR
FIRSTENTRY:
       DS      2       ; PTR TO FIRST ENTRY OF INFORMATION SECTION
LCOUNT:
       DS      1       ; LINE COUNT BUFFER
NEXTADR:
       DS      2       ; NEXT LOAD ADDRESS
HLPLVL:
       DS      1       ; NUMBER OF HELP LEVEL CURRENT NODE IS AT (0=BOTTOM)
FRNUM:
       DS      1       ; NUMBER OF CURRENT FRAME
HLPNSTK:
       DS      2       ; PTR TO STACK OF HELP FILE NAMES OF EACH LEVEL
HLPBUF:
       DS      2       ; PTR TO HELP BUFFER
STACK:
       DS      2       ; OPSYS STACK PTR

       END