*  PROGRAM NAME:  HELP
*  AUTHOR:  RICHARD CONN
*  DATE:  6 OCT 80
*  VERSION:  1.1
*  PREVIOUS VERSIONS:  1.0 (18 NOV 79)

*****************************************************************
*                                                               *
*  HELP -- DISPLAY HELP FILE INFORMATION TO USER ON CON:        *
*                                                               *
*       THE HELP COMMAND IS OF THE GENERAL FORM:                *
*               HELP <FILENAME>.<EXT>                           *
*                                                               *
*       <FILENAME>.<EXT> IS OPTIONAL; IF OMITTED COMPLETELY,    *
* 'HELP.HLP' IS ASSUMED; IF JUST <EXT> IS OMITTED, EXTENSION    *
* IS ASSUMED TO BE '.HLP'                                       *
*                                                               *
*       THE HELP COMMAND DISPLAYS THE INFORMATION IN A HELP     *
* FILE TO THE USER.  THERE ARE TWO BASIC TYPES OF HELP FILES -- *
* (1) INDEXED AND (2) NON-INDEXED.  INDEXED HELP FILES ARE      *
* THOSE WHICH CONTAIN SEVERAL SECTIONS; THE INDIVIDUAL MAY      *
* READ ALL OF SUCH A HELP FILE OR JUST SELECTED SECTIONS OF     *
* THIS FILE.  NON-INDEXED HELP FILES CONTAIN ONLY ONE SECTION.  *
*       STRUCTURALLY SPEAKING, HELP FILES CONSIST OF TWO PARTS: *
* THE HEADER PART AND THE INFORMATION PART.  THE INFORMATION    *
* PART OF A HELP FILE BEGINS WITH A LINE WHOSE FIRST CHARACTER  *
* IS A COLON.  THE TITLE OF THE INFORMATION SECTION IS ON THIS  *
* LINE.  THE INFORMATION SECTION CONTINUES UNTIL THE NEXT       *
* INFORMATION SECTION (LINE STARTING WITH A COLON) OR THE END   *
* OF THE FILE IS ENCOUNTERED.  THE HEADER PART CONSISTS OF A    *
* GROUP OF LINES BEFORE THE FIRST INFORMATION SECTION.  IF THE  *
* FIRST LINE OF A HELP FILE STARTS WITH A COLON, THEN THERE IS  *
* NO HEADER PART, AND THE HELP FILE IS DUMPED AS ONE            *
* INFORMATION SECTION.                                          *
*       THERE MUST BE THE SAME NUMBER OF LINES IN THE HEADER    *
* PART AS THERE ARE INFORMATION SECTIONS.  IF NOT, A HELP       *
* FILE ERROR WILL BE ISSUED IF THE HELP COMMAND ATTEMPTS TO     *
* READ BEYOND THE END OF THE HELP FILE IN ITS SEARCH FOR AN     *
* INFORMATION SECTION.                                          *
*                                                               *
*****************************************************************


*****************************************************************
*                                                               *
*  THE HELP PROGRAM IS COMPLETELY TRANSPORTABLE BETWEEN CP/M    *
*  SYSTEMS.                                                     *
*                                                               *
*****************************************************************



*****************************************************************
*  CP/M AND BASIC CHARACTER DEFINITIONS                         *
*****************************************************************

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>
FF              EQU     'L'-40H ; CTRL-L = FORM FEED
CTRLZ           EQU     'Z'-40H ; CTRL-Z
CTRLC           EQU     'C'-40H ; CTRL-C

*****************************************************************
*  CHARACTER WHICH MARKS START OF INFORMATION SECTION           *
*****************************************************************

SECT$CHAR       EQU     ':'     ; DEFINED TO BE COLON
ALL$CHAR        EQU     '*'     ; ALL OF HELP FILE DESIGNATOR

*****************************************************************
*  USER CUSTOMIZATION -- LINES PER SCREEN DISPLAY               *
*****************************************************************

LINES$PER$SCREEN        EQU     24      ; ASSUME 24 LINES/SCREEN


*****************************************************************
*  START OF PROGRAM                                             *
*****************************************************************

       ORG     100H

START:
       LXI     H,0     ; GET SP
       DAD     SP
       SHLD    STACK
       XRA     A       ; TURN OFF DEFAULT FILE FLAG
       STA     DFFLG
       LXI     D,HELPMS        ; PRINT OPENING MSG
       CALL    PRINT$MESSAGE
       LXI     H,FCB+1 ; CHECK FOR FILE NAME
       MOV     A,M
       CPI     ' '     ; NONE?
       JZ      DEFAULT$FN
       ORA     A       ; ALSO NONE
       JNZ     START1

*  INSERT 'HELP.HLP' INTO FCB
DEFAULT$FN:
       DCX     H       ; PT TO FCB
       LXI     D,DEFFN
       MVI     B,12    ; 12 BYTES
       XCHG
       CALL    MOVE    ; MOVE (HL) TO (DE) FOR (B) BYTES
       MVI     A,1     ; TURN ON DEFAULT FILE FLAG
       STA     DFFLG
       JMP     START2

*  CHECK FOR EXTENSION TO FILE NAME
START1:
       LXI     H,FCB+9 ; CHECK FOR EXTENSION
       MOV     A,M
       CPI     ' '     ; NONE?
       JZ      DEFAULT$EXT
       ORA     A       ; NONE ALSO
       JNZ     START2

*  PLACE DEFAULT EXTENSION OF '.HLP' IN FCB
DEFAULT$EXT:
       LXI     D,DEFEXT
       MVI     B,3
       XCHG
       CALL    MOVE    ; MOVE (HL) TO (DE) FOR (B) BYTES

*  OPEN FILE
START2:
       LXI     D,FCB   ; PT TO FCB
       MVI     C,15    ; OPEN FILE
       CALL    BDOS
       CPI     255     ; NOT PRESENT?
       JNZ     START3

*  CHECK FOR DEFAULT FILE SEARCH
       LDA     DFFLG   ; GET DEFAULT FILE FLAG
       ORA     A       ; 1=YES, SEARCH FOR DEFAULT FAILED
       JNZ     HELP    ; DISPLAY DEFAULT HELP FILE INFORMATION

*  FILE NOT FOUND -- FATAL ERROR
       LXI     D,ERR1  ; FILE NOT FOUND
       CALL    PRINT$MESSAGE
       RET

*  LOAD HELP FILE INFORMATION
START3:
       LXI     H,HELP$BUF      ; PT TO BUFFER
       SHLD    NEXT$ADR        ; SET PTR

*  READ RECORDS UNTIL EOF
START4:
       CALL    READ$RECORD     ; READ INFO
       ORA     A       ; DONE? 0=NO
       JZ      START4

*
*  START OF HELP PROGRAM
*
HELP:
       LXI     SP,STACK        ; RESET STACK
       LXI     H,HELP$BUF      ; PT TO BUFFER
       MOV     A,M     ; NO HEADER SECTION?
       CPI     SECT$CHAR
       JNZ     HELP1   ; HEADER SECTION EXISTS
       CALL    PRINT$INFO      ; PRINT HELP INFO PTED TO BY HL

*  EXIT POINT FOR ANY EXIT FROM THE REST OF THE HELP PROGRAM
HELP$EXIT:
       LHLD    STACK   ; GET CP/M SP
       SPHL
       RET             ; DONE

*  PRINT HEADER INFORMATION AND SELECT AN OPTION
HELP1:
       CALL    PRINT$HEADER    ; PRINT HEADER
       LXI     D,PROMPT$MESSAGE        ; PRINT PROMPT
       CALL    PRINT$MESSAGE
       CALL    CHAR$IN         ; GET RESPONSE
       CPI     CTRLC           ; RETURN TO CP/M
       JZ      HELP$EXIT
       CPI     ALL$CHAR        ; ALL OF HELP FILE?
       JZ      HELP$ALL
       ANI     0DFH    ; CAPITALIZE
       PUSH    PSW     ; SAVE CHAR
       CALL    CRLF1
       POP     PSW     ; GET CHAR
       SUI     'A'-1           ; ADJUST FOR COUNT
       MOV     B,A             ; SAVE COUNT
       JZ      BAD$RESPONSE
       JNC     HELP2

*  INVALID RESPONSE
BAD$RESPONSE:
       LXI     D,ERR2  ; INVALID RESPONSE
       CALL    PRINT$MESSAGE
       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     BAD$RESPONSE
       LHLD    FIRST$ENTRY     ; GET PTR TO FIRST ENTRY

*  PRINT INFORMATION WHEN COUNT IS ZERO
HELP3:
       DCR     B       ; COUNT DOWN
       JNZ     HELP4
       INX     H       ; SKIP OVER COLON
       CALL    PRINT$INFO      ; PRINT INFO PTED TO BY HL
       JMP     HELP1

*  LOCATE NEXT INFORMATION SECTION
HELP4:
       MOV     A,M     ; <CTRL-Z>?
       INX     H       ; PT TO NEXT BYTE
       CPI     CTRLZ
       JZ      HELP$ERR        ; HELP FILE FORMAT ERROR
       CPI     LF      ; LINE FEED (WS FILE)?
       JZ      HELP5
       CPI     CR      ; <CR>?
       JNZ     HELP4
       INX     H       ; 1ST BYTE OF NEXT LINE
HELP5   MOV     A,M     ; GET CHAR
       CPI     SECT$CHAR       ; NEW SECTION?
       JZ      HELP3   ; CONTINUE LOOP IF SO
       CPI     CTRLZ   ; EOF?
       JNZ     HELP4   ; CONTINUE IF NOT

*  ERROR -- REACHED END OF HELP FILE
HELP$ERR:
       LXI     D,ERR3  ; FORMAT ERROR
       CALL    PRINT$MESSAGE
       JMP     HELP1

*  PRINT ALL OF HELP FILE
HELP$ALL:
       LHLD    FIRST$ENTRY     ; PT TO FIRST ENTRY
       CALL    SET$LINE$CNT    ; SET LINE COUNT
*  EXECUTE UNTIL A CTRL-Z IS ENCOUNTERED
HA1:
       INX     H       ; SKIP OVER COLON
       CALL    PI1     ; PRINT INFO W/OUT LINE CNT INFO
       MOV     A,M     ; GET LAST CHAR
       CPI     CTRLZ
       JNZ     HA1
       JMP     HELP



*********************************************************
*                                                       *
*  HELP SUPPORT ROUTINE SECTION                         *
*                                                       *
*********************************************************

*
*  INPUT CHAR; CHAR IS IN A
*
CHAR$IN:
       PUSH B ! PUSH D ! PUSH H
       MVI     C,1     ; READ CHAR
       CALL    BDOS
       POP H ! POP D ! POP B
       PUSH    PSW     ; SAVE CHAR
       CALL    CRLF1
       POP     PSW     ; RESTORE CHAR
       RET

*
*  PRINT CHAR IN A ON CON:
*
CHAR$OUT:
       PUSH PSW ! PUSH B ! PUSH D ! PUSH H
       MVI     C,2     ; WRITE
       MOV     E,A     ; CHAR IN E
       CALL    BDOS
       POP H ! POP D ! POP B ! POP PSW
       RET

*
*  PRINT ERROR MSG PTED TO BY DE; ENDS IN '$'
*
PRINT$MESSAGE:
       PUSH B ! PUSH D ! PUSH H
       MVI     C,9     ; PRINT BUFFER
       CALL    BDOS
       POP H ! POP D ! POP B
       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       ; COUNT DOWN
       JNZ     MOVE
       RET

*
*  READ RECORD FROM DISK; NEXT$ADR CONTAINS ADDRESS TO READ TO
*       ON RETURN, BDOS ERROR CODE IS IN A (0=NO ERROR)
*
READ$RECORD:
       MVI     C,20    ; READ NEXT RECORD
       LXI     D,FCB   ; PT TO FCB
       CALL    BDOS
       PUSH    PSW     ; SAVE RETURN CODE
       LHLD    NEXT$ADR        ; PT TO LOAD ADDRESS
       LXI     D,BUFF  ; PT TO BUFFER TO LOAD FROM
       MVI     B,128   ; NUMBER OF BYTES TO MOVE
       XCHG
       CALL    MOVE
       XCHG
       SHLD    NEXT$ADR        ; PT TO NEXT LOAD ADDRESS
       POP     PSW     ; GET RETURN CODE
       RET

*
*  PRINT ONE LINE OF INFO SECTION; HL PTS TO LINE UPON ENTRY;
*       HL PTS TO FIRST CHAR OF NEXT LINE UPON EXIT
*
PRINT$LINE:
       MOV     A,M     ; GET CHAR
       CPI     CR      ; EOL?
       JZ      CRLF
       CPI     LF      ; LINE FEED? (WS FILE)
       JZ      CRLF0
       CALL    CHAR$OUT        ; PRINT CHAR
       INX     H       ; PT TO NEXT
       JMP     PRINT$LINE

*
*  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     LINE$CNT        ; GET LINE COUNT
       DCR     A
       STA     LINE$CNT
       RNZ             ; OK -- CONTINUE
       LXI     D,PAGEMS
       CALL    PRINT$MESSAGE   ; PRINT PAGE MESSAGE
       CALL    CHAR$IN ; GET RESPONSE
       ANI     0DFH    ; CAPITALIZE
       CPI     'A'     ; ABORT?
       JZ      HELP    ; START OVER IF SO
       CPI     CTRLC   ; CP/M ABORT
       JZ      HELP$EXIT
       CALL    SET$LINE$CNT
       CALL    CRLF1   ; NEW LINE
       RET

*
*  PRINT CR AND LF ONLY
*
CRLF1:
       MVI     A,CR    ; PRINT CR
       CALL    CHAR$OUT
       MVI     A,LF    ; PRINT LF
       CALL    CHAR$OUT
       RET

*
*  SET LINE$CNT VARIABLE TO SCREEN SIZE
*
SET$LINE$CNT:
       MVI     A,LINES$PER$SCREEN-1
       STA     LINE$CNT
       RET

*
*  PRINT THE HEADER SECTION AND LOAD FIRST$ENTRY PTR
*
PRINT$HEADER:
       LXI     H,HELP$BUF
       CALL    SET$LINE$CNT
       MVI     A,'A'   ; INIT SELECTION CHAR
       STA     SEL$CHAR
       LXI     D,SELECTMS
       CALL    PRINT$MESSAGE
       MVI     C,0     ; COUNT NUMBER OF SELECTIONS

* PRINT LINE UNTIL FIRST INFORMATION SECTION FOUND
PH1:
       MOV     A,M     ; GET CHAR
       CPI     SECT$CHAR
       JZ      PH2
       CPI     CTRLZ   ; EOF? -- ABORT
       JZ      HELP$EXIT
       INR     C       ; INCREMENT SELECTION COUNT
       LDA     SEL$CHAR        ; DISPLAY SELECTION CHAR
       CALL    CHAR$OUT
       INR     A       ; INCR CHAR
       STA     SEL$CHAR
       MVI     A,'.'
       CALL    CHAR$OUT
       MVI     A,' '
       CALL    CHAR$OUT
       CALL    PRINT$LINE      ; PRINT HEADER LINE
       JMP     PH1

*  SAVE PTR TO FIRST ENTRY
PH2:
       SHLD    FIRST$ENTRY
       RET

*
*  PRINT AN INFORMATION SECTION
*
PRINT$INFO:
       CALL    SET$LINE$CNT
PI1:
       CALL    PRINT$LINE      ; PRINT LINE FROM INFO FILE
       MOV     A,M     ; DONE?
       CPI     CTRLZ   ; EOF?
       JZ      PI2
       CPI     SECT$CHAR       ; NEXT SECTION
       JZ      PI2
       CPI     FF      ; FORM FEED?
       JNZ     PI1
       CALL    FORM$FEED       ; FEED SCREEN
       JMP     PI1

*  FORM FEED SCREEN
FORM$FEED:
       LDA     LINE$CNT        ; GET LINE COUNT
       MOV     B,A     ; ... IN B
FEED$LOOP:
       PUSH    B       ; SAVE B
       CALL    CRLFC   ; NEW LINE
       POP     B       ; GET B
       DCR     B       ; COUNT DOWN
       JNZ     FEED$LOOP
       RET

*  END OF INFO
PI2:
       CALL    CRLF1   ; NEW LINE
       LDA     LINE$CNT        ; COUNT DOWN
       DCR     A
       STA     LINE$CNT
       JNZ     PI2
       LXI     D,ENDMS         ; PRINT END OF INFORMATION MSG
       CALL    PRINT$MESSAGE
       CALL    CHAR$IN ; GET ANY CHAR
       CPI     CTRLC   ; CP/M ABORT
       JZ      HELP$EXIT
       CALL    SET$LINE$CNT    ; RESET LINE COUNT IN CASE OF ALL
       RET

*********************************************************
*  MESSAGE AND BUFFER SECTION                           *
*********************************************************

HELPMS:
       DB      'HELP V1.1',CR,LF,'$'
ENDMS:
       DB      '   ++ EOI ++'
       DB      '       Type CTRL-C to return to CP/M, <CR> to continue -$'
SELECTMS:
       DB      CR,LF,'  HELP File Selections are --',CR,LF,'$'
DEFFN:
       DB      0,'HELP    '
DEFEXT:
       DB      'HLP'
PAGEMS:
       DB      '   Type "A"=Abort, CTRL-C=CP/M, <CR>=Cont -$'
ERR1:
       DB      CR,LF,'HELP FATAL ERROR -- File not Found$'
ERR2:
       DB      CR,LF,'HELP ERROR -- Invalid Response',CR,LF,'$'
ERR3:
       DB      CR,LF,'HELP ERROR -- EOF on HELP File',CR,LF,'$'
PROMPT$MESSAGE:
       DB      CR,LF,'  Type CTRL-C to return to CP/M, "*" to select'
       DB      ' all, or enter selection - $'

SEL$CHAR:
       DS      1       ; SELECTION TABLE OPTION CHAR
FIRST$ENTRY:
       DS      2       ; PTR TO FIRST ENTRY OF INFORMATION SECTION
LINE$CNT:
       DS      1       ; LINE COUNT BUFFER
DFFLG:
       DS      1       ; DEFAULT FILE FLAG (0=NOT SEARCH FOR, 1=YES)
NEXT$ADR:
       DS      2       ; NEXT LOAD ADDRESS
       DS      80      ; STACK SPACE
STACK:
       DS      2       ; CP/M STACK PTR


*
*  DEFAULT HELP MESSAGE
*
HELP$BUF:
       DB      ':The HELP Subsystem for Online Documentation'
       DB      CR,LF,'     This is HELP, the Online Documentation Subsystem.'
       DB      CR,LF,'The purpose of HELP is to allow the user to '
       DB      'interactively'
       DB      CR,LF,'query the *.HLP files of the system in order to receive'
       DB      CR,LF,'information summaries on various aspects of the user''s'
       DB      CR,LF,'working environment, such as the language systems he is'
       DB      CR,LF,'using and certain subsystems available to him.'
       DB      CR,LF,LF,'     When the user types ''HELP'', a search is done'
       DB      CR,LF,'for the file ''HELP.HLP''.  If found, the contents of'
       DB      CR,LF,'this HELP File is displayed to the user; if not found,'
       DB      CR,LF,'the HELP Information you are now reading is displayed.'
       DB      CR,LF,LF,'     If the user desires information on a specific'
       DB      CR,LF,'topic and he has a HELP File of that name (ie, CPM.HLP'
       DB      CR,LF,'is a HELP File on CP/M), he may issue of HELP Command'
       DB      CR,LF,'of the form --'
       DB      CR,LF,'               HELP d:topic'
       DB      CR,LF,'where "d:" is the disk the HELP File resides on'
       DB      ' (optional)'
       DB      CR,LF,'and "topic" is the name of the HELP File (topic.HLP,'
       DB      CR,LF,'like CPM.HLP).'
       DB      CR,LF,'     Please refer to the HELP File "HELP.HLP" for'
       DB      ' more information.'

       DB      CR,LF,CTRLZ     ; END OF FILE


       END