;  PROGRAM NAME:  HELP
;  AUTHOR:  RICHARD CONN
;  DATE:  6 July 1982
;  VERSION:  1.4
;  PREVIOUS VERSIONS, Latest version first:
;
; 16/Jul/82  Changed default HLP file to THIS-SYS and modified
;       internal messages for RCPM use. Version 1.4. Bill Bolton
;
; 06/Jun/82 Modifications for RCPM system use. Line noise
;	was resulting in false answers to "go on" prompts.
;	Test for <CR> response changed to accept only <CR>.
;	Messages tightened up and an alternative end of
;	category message added for the "all categories"
;	condition. Console input changed to Direct Console
;	I/O (BDOS 6) making CP/M 2.2 or later mandatory.
;	Version 1.3. Bill Bolton
;
; 22/Jun/81 Added code for standard or modified CP/M.  Changed "*"
;	in Col 1 to ";".  Changed labels so that the program would
;	assemble with other assemblers. Version 1.2 Ted Shapin.
;
; 06/Oct/80 Version 1.1 (changes undocumented). Richard Conn.
;
; 18/Nov/79 Version 1.0 Original release. Richard Conn.
;
;
;****************************************************************
;*								*
;*  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,	*
;* 'THIS-SYS.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			*
;****************************************************************

BIAS	EQU	0		; STANDARD CP/M
;BIAS	EQU	4200H		; OFFSET CP/M

BDOS	EQU	5+BIAS		; ADDRESS OF BDOS ENTRY POINT
FCB	EQU	5CH+BIAS	; ADDRESS OF FILE CONTROL BLOCK
BUFF	EQU	80H+BIAS	; 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 + BIAS

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 'THIS-SYS.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:
	MVI	A,0
	STA	ALLFLAG		; RESET ALL CATEGORIES FLAG
	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
	CALL	CHAR$OUT	; DISPLAY ENTERED CHAR
	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:
	STA	ALLFLAG		; FOR LATER
	CALL	CRLF1		; START ON NEW LINE
	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,6	; DIRECT CONSOLE I/O
	MVI	E,0FFH	; INPUT
	CALL	BDOS
	POP	H
	POP	D
	POP	B
	ORA	A	; CHARACTER?
	JZ	CHAR$IN	; NO, KEEP LOOKING
	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
NXTLOOP:
	CALL	CHAR$IN	; GET RESPONSE
	ANI	0DFH	; CAPITALIZE
	CPI	'A'	; ABORT?
	JZ	HELP	; YES, START OVER
	CPI	CTRLC	; CP/M ABORT
	JZ	HELP$EXIT
	CPI	CR	; NEXT PAGE?
	JNZ	NXTLOOP	; NO, TRY AGAIN
	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
	LDA	ALLFLAG
	ORA	A		; DISPLAY ALL CATEGORIES?
	LXI	D,CONTMS
	JNZ	PI2CONT		; YES
	LXI	D,ENDMS		; PRINT END OF INFORMATION MSG
PI2CONT:
	CALL	PRINT$MESSAGE
PI2LOOP:
	CALL	CHAR$IN	; GET ANY CHAR
	CPI	CTRLC	; CP/M ABORT
	JZ	HELP$EXIT
	CPI	CR	; BACK TO MENU
	JNZ	PI2LOOP	; NO, KEEP LOOKING
	CALL	CRLF1	; NEW LINE
	CALL	SET$LINE$CNT	; RESET LINE COUNT IN CASE OF ALL
	RET

;********************************************************
;*  MESSAGE AND BUFFER SECTION				*
;********************************************************

HELPMS:
	DB	'HELP V1.4',CR,LF,'$'
ENDMS:
	DB	'+ End of Category +'
	DB	'	Type CTRL-C=CP/M, <CR>=Menu --$'
CONTMS:
	DB	'+ End of Category +'
	DB	'	Type CTRL-C=CP/M, <CR>=Next Category -$'

SELECTMS:
	DB	CR,LF,'  HELP File Selections are --',CR,LF,'$'
DEFFN:
	DB	0,'THIS-SYS'
DEFEXT:
	DB	'HLP'
PAGEMS:
	DB	'	Type "A"=Abort, CTRL-C=CP/M, <CR>=More -$'
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 exit to CP/M, "*" to select'
	DB	' all, or category -$'

ALLFLAG:
	DS	1	; DISPLAY ALL CATEGORIES FLAG
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',CR,LF
	DB	'     This  is HELP,  the Online Documentation  Subsystem.  The',CR,LF
	DB	'purpose  of  HELP is to allow you to interactively  query  the',CR,LF
	DB	'*.HLP  files  on this system to get information  summaries  on',CR,LF
	DB	'various aspects of the system, CP/M, applications programs and',CR,LF
	DB	'languages.',CR,LF
	DB	CR,LF
	DB	'     When  you  type  ''HELP'',  a search is done for  the  file',CR,LF
	DB	'''THIS-SYS.HLP''.   If found, the contents of this HELP File are',CR,LF
	DB	'displayed for you;  if not found, the HELP Information you are',CR,LF
	DB	'now reading is displayed.',CR,LF
	DB	CR,LF
	DB	'     If  you  desire information on a specific topic and  have',CR,LF
	DB	'found  a  HELP File in the system directory with  a  promising',CR,LF
	DB	'name (ie, CPM.HLP is a HELP File on CP/M), try the command:',CR,LF
	DB	CR,LF
	DB	'               HELP d:topic',CR,LF
	DB	'Where:',CR,LF
	DB	'     "d:"      is the disk the HELP File resides on (optional)',CR,LF
	DB	'     "topic"   is the name of the HELP File (like CPM.HLP).',CR,LF
	DB	'',CR,LF
	DB	'Please refer to the HELP File "HELP.HLP" for more information.',CR,LF
	DB	CTRLZ		; END OF FILE

	END
