*  PROGRAM NAME:  HELP
*  AUTHOR:  RICHARD CONN  Update for USQ by Dave Rand
*  DATE:  12 OCT 83
*  VERSION:  1.8
*  PREVIOUS VERSIONS:  1.6 (9 SEP 81), 1.7 (10 SEP 81)
*  PREVIOUS VERSIONS:  1.5 (9 SEP 81), 1.4 (8 SEP 81), 1.3 (8 SEP 81)
*  PREVIOUS VERSIONS:  1.2 (7 SEP 81), 1.1 (6 OCT 80), 1.0 (18 NOV 79)

VERS	EQU	18	; VERSION NUMBER

*****************************************************************
*								*
*  HELP -- DISPLAY HELP FILE INFORMATION TO USER ON CON:	*
*								*
*  -- Command Format --						*
*	THE HELP COMMAND IS OF THE GENERAL FORM:		*
*		HELP <FILENAME>.<TYP>				*
*								*
*	<FILENAME>.<TYP> IS OPTIONAL; IF OMITTED COMPLETELY,	*
* 'HELP.HLP' IS ASSUMED; IF JUST <TYP> IS OMITTED, FILE TYPE	*
* IS ASSUMED TO BE '.HLP'					*
*								*
*  -- Basic Background Information --				*
*	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.						*
*	THE INFORMATION SECTION IS ITSELF DIVIDED INTO PARTS,	*
* CALLED FRAMES.  A FRAME IS ONE SCREEN DISPLAY, THE SIZE OF	*
* WHICH IS SET BY AN EQUATE.  IF THE HELP FILE CONTAINS A FORM	*
* FEED CHARACTER, THEN THE CURRENT FRAME IS ABRUPTLY TERMINATED	*
* AND THE RESET OF THE SCREEN DISPLAY IS FILLED WITH BLANK	*
* LINES.  OTHERWISE, WHEN THE INDICATED NUMBER OF LINES HAVE	*
* BEEN DISPLAYED, THE HELP PROGRAM PAUSES TO ALLOW THE USER TO	*
* VIEW THE INFORMATION AND SELECT THE NEXT DIRECTION IN WHICH	*
* TO GO.							*
*								*
*  -- Traversing the HELP File --				*
*	WHILE IN THE HELP SYSTEM, THE USER IS GIVEN SEVERAL	*
* OPTIONS AT ALL TIMES AS TO WHAT HE CAN DO.			*
*	AT THE MENU LEVEL OF INDEXED HELP FILES, THE USER CAN	*
* MOVE IN THE FOLLOWING DIRECTIONS:				*
*		1. SELECTION OF A MENU ITEM, IN WHICH CASE	*
* HE ENTERS THAT INFORMATION SECTION				*
*		2. MOVE UP TO THE PREVIOUS LEVEL.  IF THE HELP	*
* FILE THE USER IS IN WAS REACHED THROUGH ANOTHER HELP FILE,	*
* THE USER CAN RETURN TO THAT HELP FILE (MOVE UP A LEVEL).	*
* IF THE USER WAS IN THE "SELECT ALL ITEMS" MODE, HE CONTINUES	*
* WITH THE PREVIOUS HELP FILE WHERE HE LEFT OFF; IF THE USER	*
* WAS LOOKING AT A SPECIFIC MENU ITEM (WHICH CALLED THE HELP	*
* FILE HE IS IN NOW), HE IS RETURNED TO THE MENU OF THE CALLING	*
* HELP FILE.							*
*		3. EXIT TO CP/M.  AT ALL TIMES, THE USER IS	*
* ALLOWED TO RETURN TO CP/M.					*
*	WHILE IN AN INFORMATION SECTION, THE USER MAY		*
* MOVE IN THE FOLLOWING DIRECTIONS:				*
*		1. FORWARD TO THE NEXT FRAME.  IF AT THE END	*
* OF THE INFORMATION SECTION, THIS RETURNS THE USER TO THE	*
* MENU IF IT IS AN INDEXED HELP FILE, TO CP/M IF THE USER IS	*
* IN A NON-INDEXED HELP FILE AT LEVEL 0 (NOT CALLED BY ANOTHER	*
* HELP FILE), OR TO THE CALLING HELP FILE IF NOT AT LEVEL 0.	*
*		2. BACKWARD TO THE PREVIOUS FRAME.  IF AT THE	*
* BEGINNING OF AN INFORMATION SECTION, AN ERROR MESSAGE IS	*
* PRINTED.							*
*		3. TO THE MENU IF IN AN INDEXED HELP FILE.	*
*		4. TO THE START OF THE CURRENT INFORMATION	*
* SECTION DIRECTLY.						*
*		5. TO THE PREVIOUS LEVEL (CALLING HELP FILE).	*
*								*
*  -- Nodes and Help File Nesting --				*
*	AN INFORMATION SECTION MAY BEGIN WITH A DOUBLE COLON	*
* (::), AND THIS DESIGNATOR IS FOLLOWING BY THE FILE NAME OF A	*
* HELP FILE WHICH IS TO BE LOADED AS A NODE.  NODES TO THE HELP	*
* PROGRAM ARE COMPLETE HELP FILES IN THEMSELVES, AND THEY MAY	*
* REFER TO OTHER NODES AS WELL.  IN THIS WAY, A TREE STRUCTURE	*
* MAY BE DESIGNED BY THE AUTHOR OF A HELP FILE, EACH NODE OF	*
* THE TREE BEING A HELP FILE IN ITS OWN RIGHT (WHICH MAY BE	*
* ACCESSED INDEPENDENTLY).  NODES MAY BE NESTED A NUMBER OF	*
* LEVELS, SPECIFIED BY THE HELP$MAX EQUATE.			*
*	TO VIEW THIS CONCEPT MORE CLEARLY, THE FOLLOWING DIAGRAM*
* IS OFFERED:							*
*		-- Basic HELP File --				*
* :Info Sect 1	:Info Sect 2	:Info Sect 3	:Info Sect 4 :	*
* : Text	: HELP File	: Text		: HELP File  :	*
*		   /      \			   /    \	*
*	    -- SubHelp File 1 --	    -- SubHelp File 2 --*
*	:Info Sect 1 :Info Sect 2 :	:Info Sect 1 :Info Sect2*
*	: Text	     : HELP File  :	: Text	     : Text	*
*			/    \					*
*		-- SubSubHelp File 1 --				*
*	:Info Sect 1 :Info Sect 2 :Info Sect 3 :		*
*	: Text	     : HELP File  : HELP File  :		*
*			/  \	     /    \			*
*	-- Sub3Help File 1 --  -- Sub3Help File 2 --		*
*	:Info Sect :		:Info Sect 1 :Info Sect 2:	*
*	: Text     :		: Text	     : HELP File :	*
*						/    \		*
*					-- Sub4Help File --	*
*				:Info Sect 1 :Info Sect 2:	*
*				: Text	     : Text	 :	*
*								*
*	AS THE USER CAN SEE, TREE STRUCTURES ARE NOW POSSIBLE.	*
* ONE HELP FILE CAN REFERENCE ANOTHER WHICH INTURN REFERENCES	*
* ANOTHER AND SO ON.  THERE IS A LIMIT TO HOW DEEP THE NESTING	*
* MAY GO, AND THAT IS SPECIFIED IN THE EQUATE FOR HELP$MAX.	*
*								*
*  -- What Help Can Do --					*
*	SINCE A HELP FILE MUST BE MEMORY RESIDENT, THIS IS	*
* CONVENIENT IN TWO WAYS:  (1) "MASTER" HELP FILES MAY BE	*
* CREATED WHICH REFERENCE OTHER HELP FILES, AND THE INFORMATION	*
* ACCESSED FROM A MASTER HELP FILE MAY ENCOMPASS ALL OF THE	*
* USER'S HELP FILE AND (2) IF THE USER NEEDS INFORMATION	*
* IN A SPECIFIC SUBJECT AREA AND KNOWS WHICH HELP FILE REFERS	*
* TO THE INFORMATION HE NEEDS, HE NEED NOT LOAD THE MASTER	*
* AND THEN TRAVERSE THE TREE TO THE INFORMATION HE NEEDS; HE	*
* MAY SPECIFY THE SPECIFIC HELP FILE DIRECTLY.			*
*								*
*  -- Command-Search Hierarchy --				*
*	ONE OTHER POINT TO NOTE IS THAT THE HELP PROGRAM NOW	*
* EMPLOYS A COMMAND-SEARCH HIERARCHY IN LOCATING A REFERENCED	*
* HELP FILE.  ONCE A FILE SPECIFICATION IS GIVEN, THE HELP	*
* PROGRAM SEARCHES THE CURRENT USER AREA ON THE CURRENT DISK FOR*
* THE FILE; IF NOT FOUND, IT DROPS TO USER AREA 0 (MAY BE	*
* CHANGED) ON THE CURRENT DISK IF THE USER IS NOT ALREADY THERE	*
* AND LOOKS FOR THE FILE; IF NOT FOUND THIS TIME, IT DROPS TO	*
* USER AREA 0 OF THE DISK ON DRIVE A: AND SEARCHES FOR THE FILE.*
* IF NOT FOUND AT THIS POINT, HELP CHECKS TO SEE IF THE REFER-	*
* ENCED FILE WAS HELP.HLP, IN WHICH CASE IT PRESENTS THE BUILT-	*
* IN DOCUMENTATION (SEE END OF PROGRAM); FINALLY, IF NONE OF THE*
* ABOVE ARE TRUE, HELP ABORTS WITH AN ERROR MESSAGE.		*
*								*
*  -- HELP File Structure Warning --				*
*	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

*****************************************************************
*  SPECIAL CONTROL CHARACTERS WHICH MAY BE RESET BY USER	*
*****************************************************************

SECT$CHAR	EQU	':'	; DEFINED TO BE COLON
BACKUP$CHAR	EQU	'L'	; BACK UP TO PREVIOUS FRAME CHAR
START$CHAR	EQU	'S'	; JUMP TO START OF INFORMATION CHAR
MENU$CHAR	EQU	'M'	; CHAR TO ABORT TO MENU
CPM$ABORT$CHAR	EQU	CTRLC	; CHAR TO ABORT TO CP/M
LEVEL$RET$CHAR	EQU	'^'	; RETURN TO PREVIOUS HELP LEVEL
ROOT$CHAR	EQU	'.'	; RETURN TO ROOT OF HELP

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

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

*****************************************************************
*  USER CUSTOMIZATION -- DEFAULT USER NUMBER			*
*****************************************************************

DEFAULT$USER		EQU	0	; DEFAULT USER NUMBER = 0

*****************************************************************
*  USER CUSTOMIZATION -- DEFAULT DISK				*
*****************************************************************

DEFAULT$DISK		EQU	'A'	; DEFAULT DISK = A:

*****************************************************************
*  USER CUSTOMIZATION -- NUMBER OF NODES (LEVELS) IN HELP TREE	*
*****************************************************************

HELP$MAX		EQU	10	; DEFAULT = 10 (SPACE=11*HELP$MAX)



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

	ORG	100H

START:
	LXI	H,0	; GET SP
	DAD	SP
	SHLD	STACK
	LXI	SP,STACK	; NEW STACK
	LDA	BDOS+2	; BASE PAGE OF BDOS
	SUI	10	; 2K + 2 PAGES
	STA	TPA$END
	XRA	A	; A=0
	STA	DFFLG	; TURN OFF DEFAULT FILE FLAG
	STA	HELP$LEVEL	; SET HELP LEVEL TO 0 (NO RETURN FILE)
	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

*  START/RESTART HELP PROGRAM (START ON INITIAL ENTRY, RESTART ON NODE LOAD)
START1:
	LXI	SP,STACK	; SET STACK POINTER

*  CLEAR NON-NAME/TYPE BYTES IN FCB
	LXI	H,FCB	; INITIAL ZERO
	MVI	M,0	; STORE 0 FOR DRIVE (CURRENT LOGGED-IN)
	LXI	D,12	; SKIP TO EXTENT
	DAD	D
	MVI	B,24	; FILL 24 BYTES
FCB$FILL:
	MVI	M,0	; ZERO FILL
	INX	H	; PT TO NEXT
	DCR	B	; COUNT DOWN
	JNZ	FCB$FILL

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

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

*  OPEN FILE
START2:
	MVI	A,0FFH	; SET NO CHANGE FLAG
	STA	CUR$USER	; SET NO USER CHANGE
	STA	CUR$DISK	; SET NO DISK CHANGE

*  OPTION 1:  TRY TO OPEN FILE IN CURRENT USER NUMBER ON CURRENT DISK
	LXI	D,FCB	; PT TO FCB
	MVI	C,15	; OPEN FILE
	CALL	BDOS
	CPI	255	; NOT PRESENT?
	JNZ	START3
	MVI	C,12	; GET VERSION NUMBER
	CALL	BDOS
	MOV	A,H	; CP/M 1.X?
	ORA	L
	JZ	START2$DISK	; CHECK FOR DEFAULT DISK IF SO

*  OPTION 2:  TRY TO OPEN FILE IN USER 0 ON CURRENT DISK
	MVI	E,0FFH	; GET CURRENT USER NUMBER
	MVI	C,32	; GET/SET USER CODE
	CALL	BDOS
	CPI	DEFAULT$USER	; CHECK IF AT USER 0 (OR DEFAULT USER)
	JZ	START2$DISK	; DON'T TRY IF AT USER 0
	STA	CUR$USER	; SAVE FOR LATER
	MVI	E,DEFAULT$USER	; SET USER 0 (OR DEFAULT USER)
	MVI	C,32	; GET/SET USER CODE
	CALL	BDOS
	LXI	D,FCB	; TRY TO OPEN FILE AGAIN
	MVI	C,15	; OPEN FILE
	CALL	BDOS
	CPI	255	; NOT PRESENT?
	JNZ	START3

*  OPTION 3:  TRY TO OPEN FILE IN USER 0 ON DEFAULT DISK IF NOT CURRENT DISK
START2$DISK:
	MVI	C,25	; DETERMINE CURRENT DISK
	CALL	BDOS
	CPI	DEFAULT$DISK-'A'	; ON DEFAULT DISK?
	JZ	START2$DEFAULT
	STA	CUR$DISK	; SAVE DISK NUMBER IN BYTE
	MVI	E,DEFAULT$DISK-'A'	; SELECT DISK A:
	MVI	C,14	; SELECT DISK
	CALL	BDOS
	LXI	D,FCB	; TRY TO OPEN FILE ONE LAST TIME
	MVI	C,15	; OPEN FILE
	CALL	BDOS
	CPI	255	; NOT PRESENT?
	JNZ	START3

*  CHECK FOR DEFAULT FILE SEARCH
START2$DEFAULT:
	CALL	RESET$SYSTEM	; RESTORE CURRENT DISK AND USER IF CHANGED

* File not found, look for HQP files

	lxi	h,fcb+1+8+1	;see if already Q
	mov	a,m
	ani	127
	mvi	m,'Q'
	cpi	'Q'
	jnz	start2		;skip back, and try again


	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
	JMP	HELP$EXIT

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

	lda	fcb+1+8+1	;see if sq file
	ani	127
	cpi	'Q'
	jnz	start4
	call	usq
	jmp	start4a

*  READ RECORDS UNTIL EOF
START4:
	CALL	READ$RECORD	; READ INFO
	ORA	A	; DONE? 0=NO
	JZ	START4
start4a:
	LXI	D,FCB	; CLOSE FILE
	MVI	C,16	; CLOSE
	CALL	BDOS
	CALL	RESET$SYSTEM	; RESTORE CURRENT DISK AND USER IF CHANGED

*
*  START OF HELP PROGRAM
*
HELP:
	LXI	SP,STACK	; RESET STACK
	MVI	A,0	; SET NO FRAME
	STA	FRAME$NUMBER
	LXI	H,HELP$BUF	; PT TO BUFFER
	MOV	A,M	; NO HEADER SECTION?
	ANI	7FH	; MASK OUT MSB
	CPI	SECT$CHAR
	JNZ	HELP1	; HEADER SECTION EXISTS
	CALL	PRINT$INFO	; PRINT HELP INFO PTED TO BY HL
	LDA	HELP$LEVEL	; CHECK TO SEE IF WE ARE NOT AT LEVEL 0
	ORA	A	; 0=LEVEL 0
	JZ	HELP$EXIT	; ABORT IF SO
	JMP	LEVEL$RETURN	; GO TO PREVIOUS LEVEL IF NOT

*  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
	PUSH	B	; SAVE C (NUMBER OF VALID SELECTIONS)
	CALL	CRLF1	; NEW LINE
	CALL	PR$LEVEL	; PRINT LEVEL NUMBER
	LXI	D,PROMPT1$MESSAGE	; PRINT PROMPT
	CALL	PRINT$MESSAGE
	LXI	D,PROMPT2$MESSAGE	; LEVEL COMMAND
	LDA	HELP$LEVEL	; CURRENT LEVEL = 0?
	ORA	A	; SET FLAGS
	JZ	HELP1A
	CALL	PRINT$MESSAGE
HELP1A:
	LXI	D,PROMPT3$MESSAGE
	CALL	PRINT$MESSAGE
	POP	B	; GET C
	CALL	CHAR$IN		; GET RESPONSE
	CPI	CTRLC		; RETURN TO CP/M
	JZ	HELP$EXIT
	CPI	ROOT$CHAR	; GO TO ROOT
	JZ	GO$ROOT
	CPI	LEVEL$RET$CHAR	; RETURN TO PREVIOUS LEVEL
	JZ	LEVEL$RETURN
	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
	CALL	PRINT$INFO	; PRINT INFO PTED TO BY HL
	JMP	HELP1

*  LOCATE NEXT INFORMATION SECTION
HELP4:
	MOV	A,M	; <CTRL-Z>?
	ANI	7FH	; MASK OUT MSB
	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
	ANI	7FH	; MASK OUT MSB
	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


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

*
*  RESTORE CURRENT DISK AND CURRENT USER IF CHANGED
*
RESET$SYSTEM:
	LDA	CUR$DISK	; CHECK DISK
	CPI	0FFH	; 0FFH=NO CHANGE
	JZ	RESET$SYS1
	MOV	E,A	; DISK IN E
	MVI	C,14	; SELECT DISK
	CALL	BDOS
RESET$SYS1:
	LDA	CUR$USER	; CHECK USER
	CPI	0FFH	; 0FFH=NO CHANGE
	RZ
	MOV	E,A	; USER IN E
	MVI	C,32	; GET/SET USER CODE
	CALL	BDOS
	RET

*
*  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
*
*  CAPITALIZE CHAR IN A
*
CAPS:
	ANI	7FH	; MASK OUT MSB
	CPI	61H	; LESS THAN SMALL A?
	RC
	CPI	7BH	; LESS THAN LEFT BRACE?
	RNC
	ANI	5FH	; CAPITALIZE
	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
	LDA	TPA$END	; CHECK AGAINST END PAGE OF TPA
	CMP	H	; IF AT SAME PAGE, YES
	JZ	READ$ERROR
	LXI	D,BUFF	; PT TO BUFFER TO LOAD FROM
	MVI	B,128	; NUMBER OF BYTES TO MOVE
	XCHG
	CALL	MOVE
	XCHG
	POP	PSW	; GET RETURN CODE
	ORA	A	; DONE?
	JZ	READ$DONE	; RETURN IF NOT

*  CHECK FOR CTRLZ
	PUSH	H	; SAVE PTR TO NEXT ADDRESS
	LHLD	NEXT$ADR	; PT TO BEGINNING OF BLOCK
	MVI	B,128	; CHECK 128 BYTES
CTRLZ$CHECK:
	MOV	A,M	; GET BYTE
	ANI	7FH	; MASK OUT MSB
	INX	H	; PT TO NEXT
	CPI	CTRLZ	; EOF?
	JZ	CTRLZ$FOUND
	DCR	B	; COUNT DOWN
	JNZ	CTRLZ$CHECK
	LXI	D,CTRLZERR
	CALL	PRINT$MESSAGE	; NO CTRLZ ERROR
	JMP	HELP$EXIT

*  FILL REST OF BLOCK WITH CTRLZ
CTRLZ$FOUND:
	DCR	B	; COUNT DOWN
	JZ	CTRLZ$DONE
	MVI	M,CTRLZ	; FILL REST OF BLOCK WITH CTRLZ
	INX	H	; PT TO NEXT
	JMP	CTRLZ$FOUND
CTRLZ$DONE:
	POP	H	; PT TO NEXT BLOCK ADDRESS

*  READ OK -- SAVE PTR TO NEXT BLOCK
READ$DONE:
	SHLD	NEXT$ADR	; SET NEXT ADDRESS
	RET

READ$ERROR:
	LXI	D,READERR
	CALL	PRINT$MESSAGE
	JMP	HELP$EXIT

*
*  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
	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
	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
	MOV	A,M	; SET MSB OF FIRST CHAR OF NEXT LINE
	ORI	80H
	MOV	M,A	; MSB IS SET FOR LATER BACKUP
FRAME$PAUSE:
	CALL	PR$LEVEL	; PRINT LEVEL NUMBER
	LDA	FRAME$NUMBER	; INCREMENT FRAME NUMBER
	INR	A
	STA	FRAME$NUMBER
	LXI	D,PAGEMS
	CALL	PRINT$MESSAGE	; PRINT PAGE MESSAGE
	LXI	D,PAGE1MS	; NOT LEVEL 0?
	LDA	HELP$LEVEL	; GET LEVEL NUMBER
	ORA	A	; SET FLAGS
	JZ	FP1
	CALL	PRINT$MESSAGE
FP1:
	LXI	D,PAGE2MS
	CALL	PRINT$MESSAGE
	CALL	CHAR$IN	; GET RESPONSE
	CPI	MENU$CHAR	; ABORT?
	JZ	HELP	; START OVER IF SO
	CPI	CPM$ABORT$CHAR	; CP/M ABORT
	JZ	HELP$EXIT
	CPI	ROOT$CHAR	; GO TO ROOT
	JZ	GO$ROOT
	CPI	LEVEL$RET$CHAR	; RETURN TO HIGHER LEVEL
	JZ	LEVEL$RETURN
	CPI	BACKUP$CHAR	; BACK UP?
	JZ	FRAME$BACKUP
	CPI	START$CHAR	; JUMP TO START OF INFO
	JZ	INFO$START
FRAME$RESUME:
	SHLD	START$OF$FRAME
	CALL	SET$LINE$CNT
	CALL	CRLF1	; NEW LINE
	RET

*  JUMP TO START OF INFORMATION
INFO$START:
	LHLD	START$OF$INFO	; PT TO START OF INFO
	JMP	FRAME$RESUME	; CONTINUE PROCESSING

*  BACK UP TO PREVIOUS FRAME
FRAME$BACKUP:
	CALL	BOI$CHECK	; AT BEGINNING OF INFORMATION?
	JNZ	FB1		; CONTINUE IF NOT
	JMP	FRAME$PAUSE
FB1:
	DCX	H	; BACK UP UNTIL BYTE WITH MSB SET IS FOUND
	MOV	A,M	; GET BYTE
	ANI	80H
	JZ	FB1
	LDA	FRAME$NUMBER	; DECREMENT FRAME NUMBER
	DCR	A		; BACK UP TO CURRENT FRAME NUMBER
	DCR	A		; BACK UP TO PREVIOUS FRAME NUMBER
	STA	FRAME$NUMBER
	JMP	FRAME$RESUME	; CONTINUE PROCESSING
*
*  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
*    ON RETURN, C=NUMBER OF POSSIBLE SELECTIONS
*
PRINT$HEADER:
	MVI	A,0	; SET NO FRAME
	STA	FRAME$NUMBER
	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
	ANI	7FH	; MASK OUT MSB
	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
*    INFORMATION SECTION IS PTED TO BY HL
*
PRINT$INFO:
	SHLD	START$OF$INFO	; SET START OF INFORMATION POINTER
	CALL	LOAD$NODE	; LOAD NEW NODE IF DUAL SECT$CHAR
	SHLD	START$OF$FRAME	; SET FRAME POINTER
	MOV	A,M	; SET MSB
	ORI	80H
	MOV	M,A
	CALL	SET$LINE$CNT
	MVI	A,1		; A=1
	STA	FRAME$NUMBER	; SET FRAME NUMBER
PI1:
	CALL	PRINT$LINE	; PRINT LINE FROM INFO FILE
	MOV	A,M	; DONE?
	ANI	7FH	; MASK OUT MSB
	CPI	CTRLZ	; EOF?
	JZ	PI2
	CPI	SECT$CHAR	; NEXT SECTION
	JZ	PI2
	CPI	FF	; FORM FEED?
	JNZ	PI1
	INX	H	; PT TO CHAR AFTER FORM FEED
	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:
	MOV	A,M	; SET MSB OF NEXT BYTE
	ORI	80H
	MOV	M,A
PI2A:
	CALL	CRLF1	; NEW LINE
	LDA	LINE$CNT	; COUNT DOWN
	DCR	A
	STA	LINE$CNT
	JNZ	PI2A
PI2$MSG:
	CALL	PR$LEVEL	; PRINT LEVEL NUMBER
	LDA	FRAME$NUMBER	; INCREMENT FRAME NUMBER
	INR	A
	STA	FRAME$NUMBER
	LXI	D,ENDMS		; PRINT END OF INFORMATION MSG
	CALL	PRINT$MESSAGE
	LXI	D,PAGE1MS	; PRINT LEVEL UP MESSAGE OPTIONALLY
	LDA	HELP$LEVEL	; GET CURRENT HELP LEVEL
	ORA	A	; SET FLAGS
	JZ	PI2$MSG1
	CALL	PRINT$MESSAGE
PI2$MSG1:
	LXI	D,PAGE2MS	; PRINT REST OF INFO MESSAGE
	CALL	PRINT$MESSAGE
	CALL	CHAR$IN	; GET ANY CHAR
	CPI	MENU$CHAR	; MENU ABORT
	JZ	HELP
	CPI	CPM$ABORT$CHAR	; CP/M ABORT
	JZ	HELP$EXIT
	CPI	ROOT$CHAR	; GO TO ROOT
	JZ	GO$ROOT
	CPI	LEVEL$RET$CHAR	; RETURN TO HIGHER LEVEL
	JZ	LEVEL$RETURN
	CPI	BACKUP$CHAR	; BACK UP FROM EOI?
	JZ	PI2$BACKUP
	CPI	START$CHAR	; START OF INFO?
	JZ	PI2$START
	CALL	SET$LINE$CNT	; RESET LINE COUNT IN CASE OF ALL
	RET

*  JUMP TO START OF INFO
PI2$START:
	LHLD	START$OF$INFO	; PT TO START OF INFO
	CALL	FRAME$RESUME	; RESET POINTERS
	JMP	PI1	; CONTINUE PROCESSING

*  BACK UP TO PREVIOUS FRAME
PI2$BACKUP:
	CALL	BOI$CHECK	; AT BEGINNING OF INFORMATION?
	JNZ	PI2$BACK	; CONTINUE IF NOT
	JMP	PI2$MSG
PI2$BACK:
	CALL	FB1	; BACK UP TO PREVIOUS FRAME
	JMP	PI1	; CONTINUE PROCESSING

*
*  CHECK FOR POSITION AT BEGINNING OF INFORMATION SECTION
*    IF SO, PRINT BACKUP ERROR MESSAGE AND RETURN W/ZERO SET
*
BOI$CHECK:
	LHLD	START$OF$INFO	; START ADDRESS
	XCHG			; ... IN DE
	LHLD	START$OF$FRAME	; FRAME ADDRESS
	MOV	A,D		; EQUAL?
	CMP	H
	RNZ
	MOV	A,E
	CMP	L
	RNZ
	LXI	D,BACKERR	; BACKUP ERROR
	CALL	PRINT$MESSAGE
	XRA	A		; ZERO FLAG SET
	STA	FRAME$NUMBER	; SET FRAME NUMBER
	RET

*
*  AT THE BEGINNING OF AN INFORMATION SECTION (HL PTS TO FIRST CHAR)
*    CHECK TO SEE IF ANOTHER SECT$CHAR FOLLOWS, AND, IF SO, LOAD THE
*    SPECIFIED FILE AS A NEW NODE AND BEGIN PROCESSING IT
*
LOAD$NODE:
	INX	H	; PT TO POSSIBLE 2ND SECT$CHAR
	MOV	A,M	; GET IT
	DCX	H	; PREP FOR RETURN
	ANI	7FH	; MASK MSB
	CPI	SECT$CHAR	; ANOTHER ONE?
	RNZ		; PROCESS NORMALLY IF NOT

*  WE HAVE A NEW NODE -- CHECK TO SEE IF WE CAN NEST AGAIN
	LDA	HELP$LEVEL	; GET CURRENT HELP LEVEL
	CPI	HELP$MAX	; AT MAXIMUM?
	JNZ	LOAD$NODE1
	LXI	D,LEVELERR	; LEVEL ERROR MESSAGE
	CALL	PRINT$MESSAGE
	JMP	HELP$EXIT

*  WE HAVE NOT REACHED LEVEL LIMIT, SO CONTINUE
*  AT THIS TIME, A=HELP LEVEL INDEX AND HL = PTR TO CURRENT SECTION (::)
LOAD$NODE1:

*  SAVE CURRENT HELP FILE NAME FOR RETURN
	INX	H	; PT TO SECTION SECT$CHAR
	INX	H	; NOW POINTING TO FILE NAME
	PUSH	H	; SAVE PTR
	CALL	COMP$HELP$NAME$PTR	; 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	HELP$LEVEL	; GET OLD LEVEL
	INR	A	; SET NEW LEVEL
	STA	HELP$LEVEL

*  SET UP FCB FOR NEW FILE
	LXI	D,LOADING$MSG
	CALL	PRINT$MESSAGE
	POP	H	; GET PTR TO NEW FILE NAME
	LXI	D,FCB+1	; PT TO FCB NAME
	MVI	B,8	; 8 CHARS MAX
	CALL	LOAD$FCB	; PLACE INTO FCB WITH ERROR CHECKING
	MVI	A,'.'	; DECIMAL BETWEEN FILE NAME AND TYPE
	CALL	CHAR$OUT
	MVI	B,3	; 3 CHARS MAX FOR TYPE
	CALL	LOAD$FCB	; PLACE INTO FCB WITH ERROR CHECKING
	CALL	CRLF1	; NEW LINE
	JMP	START1	; LOAD NEW HELP FILE

*
*  LOAD FCB PTED TO BY DE WITH "NORMAL" FILE NAME PTED TO BY HL FOR B BYTES
*
LOAD$FCB:
	MOV	A,M	; GET CHAR
	INX	H	; PT TO NEXT
	CPI	'.'	; DONE IF DECIMAL
	JZ	LOAD$FCB$FILL
	CPI	' '+1	; DONE IF < <SP>
	JC	LOAD$FCB$FILL
	CALL	CAPS	; CAPITALIZE
	CALL	CHAR$OUT	; PRINT FILE NAME AND TYPE
	STAX	D	; STORE CHAR
	INX	D	; PT TO NEXT
	DCR	B	; COUNT DOWN
	JNZ	LOAD$FCB
	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
	LXI	D,LOADERR
	CALL	PRINT$MESSAGE
	JMP	HELP$EXIT
LOAD$FCB$FILL:
	MOV	C,A	; SAVE CHAR THAT TERMINATED STRING
LOAD$FCB$LOOP:
	MVI	A,' '	; <SP> FILL REST OF FCB
	STAX	D	; STORE <SP>
	INX	D	; PT TO NEXT
	DCR	B	; COUNT DOWN
	JNZ	LOAD$FCB$LOOP
	MOV	A,C	; GET CHAR THAT TERMINATED STRING
	RET

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

*
*  RETURN TO PREVIOUS HELP LEVEL
*
LEVEL$RETURN:
	LDA	HELP$LEVEL	; ARE WE AT THE LOWEST LEVEL?
	ORA	A	; 0=YES
	JNZ	LRET
	LXI	D,LRETERR
	CALL	PRINT$MESSAGE
	JMP	HELP

*  SET NEW HELP LEVEL
LRET:
	DCR	A	; DOWN 1

*  GO TO HELP LEVEL INDEXED IN A
GORET:
	STA	HELP$LEVEL	; SET NEW HELP LEVEL
	CALL	COMP$HELP$NAME$PTR	; HL=POINTER TO TARGET HELP FILE NAME
	PUSH	H	; SAVE PTR TO FILE NAME
	LXI	D,LOADING$MSG	; PRINT NAME OF FILE TO BE LOADED
	CALL	PRINT$MESSAGE
	MVI	B,8	; 8 CHARS TO FILE NAME
GORET$NAME:
	MOV	A,M	; GET CHAR
	CPI	' '	; END OF NAME?
	INX	H	; PT TO NEXT
	JZ	GORET$NAME0
	CALL	CHAR$OUT	; PRINT FILE NAME
	DCR	B	; DONE?
	JNZ	GORET$NAME
	JMP	GORET$NAME1
GORET$NAME0:
	DCR	B	; COUNT DOWN
	JZ	GORET$NAME1
	INX	H	; SKIP NEXT SPACE
	JMP	GORET$NAME0
GORET$NAME1:
	MVI	A,'.'	; PRINT DECIMAL
	CALL	CHAR$OUT
	MVI	B,3	; PRINT FILE TYPE
GORET$NAME2:
	MOV	A,M	; GET CHAR
	INX	H	; PT TO NEXT
	CALL	CHAR$OUT	; PRINT IT
	DCR	B	; COUNT DOWN
	JNZ	GORET$NAME2
	CALL	CRLF1	; NEW LINE
	POP	H	; GET PTR TO FILE NAME
	LXI	D,FCB+1	; COPY ELEMENT INTO FCB
	MVI	B,11	; 11 BYTES
	CALL	MOVE
	JMP	START1	; LOAD ENTRY

*
*  COMPUTE POINTER TO HELP NAME ENTRY INDEXED BY HELP LEVEL IN A
*
COMP$HELP$NAME$PTR:
	CALL	COMP$OFFSET	; COMPUTE OFFSET IN TABLE
	LXI	D,HELP$NAME$STACK	; PT TO BASE OF HELP NAMES
	DAD	D	; ADD IN OFFSET
	RET

*
*  COMPUTE OFFSET INTO TABLE BASED ON INDEX A
*    OFFSET = A * 11
*
COMP$OFFSET:
	MOV	L,A	; VALUE IN HL
	MVI	H,0
	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
	RET

*
*  PRINT LEVEL NUMBER
*
PR$LEVEL:
	LDA	HELP$LEVEL	; DON'T PRINT LEVEL 0
	ORA	A	; 0?
	JZ	PR$FRAME
	LXI	D,LEVEL$MESSAGE	; PRINT HEADER
	CALL	PRINT$MESSAGE
	LDA	HELP$LEVEL	; GET NUMBER
	CALL	PR$DEC		; PRINT AS DECIMAL
	LXI	D,LEVEL2$MESSAGE	; PRINT END HEADER
	CALL	PRINT$MESSAGE
PR$FRAME:
	LDA	FRAME$NUMBER	; GET CURRENT FRAME NUMBER
	ORA	A	; SET FLAGS
	RZ		; NO FRAME?
	CALL	PR$DEC	; PRINT AS DECIMAL
	LXI	D,LEVEL3$MESSAGE
	CALL	PRINT$MESSAGE
	RET
*  PRINT A AS DECIMAL
PR$DEC:
	PUSH	PSW	; SAVE VALUE
	XRA	A
	STA	LD$SPACE
	POP	PSW	; GET VALUE
	MVI	B,100	; PRINT 100'S
	CALL	PDEC
	MVI	B,10	; PRINT 10'S
	CALL	PDEC
	ADI	'0'	; PRINT 1'S
	JMP	CHAR$OUT
PDEC:
	MVI	C,0	; SET VALUE
PDEC1:
	SUB	B	; SUBTRACT POWER
	JC	PDEC2
	INR	C	; INCREMENT VALUE
	JMP	PDEC1
PDEC2:
	ADD	B	; ADD POWER BACK IN
	MOV	B,A	; SAVE A IN B
	LDA	LD$SPACE	; GET LEADING <SP> FLAG
	ORA	A	; NON-ZERO=PRINT
	JNZ	PDEC3
	MOV	A,C	; GET DIGIT
	STA	LD$SPACE	; NEW FLAG
	ORA	A	; ZERO?
	JNZ	PDEC3	; PRINT BYTE IN C
	MVI	A,' '	; PRINT LEADING SPACE
	JMP	PDEC4
PDEC3:
	MOV	A,C	; GET VALUE
	ADI	'0'	; CONVERT TO ASCII
PDEC4:
	CALL	CHAR$OUT	; PRINT CHAR
	MOV	A,B	; RESTORE A
	RET



*******************************************************
* USQ support code                                    *
* Added 10/12/83 by Dave Rand                         *
*******************************************************


eof:		equ	1ah
dle:		equ	090h


;this is start of baseline USQ code

usq:		xra	a		;force init char read
		sta	numlft
		sta	rcnt		;and zero repeats
		lhld	lastmem
		shld	sob
		shld	eob
		call	getw
usq1:		call	getw		;get cksum, and store
		shld	filecrc
usq2:		call	get1
		jnz	help$exit
		ora	a
		jnz	usq2

usq3a:		call	getw
		shld	numvals
		lxi	d,258
		call	cmpdehl
		jc	usq3b
		call	errext
		db	13,10,'Files has illegal decode size. Aborting.',0
usq3b:		lxi	d,table
usq4:		shld	max
		mov	a,h
		ora	l
		jz	usq5
		push	d
		call	getw
		pop	d
		xchg
		mov	m,e
		inx	h
		mov	m,d
		inx	h
		push	h
		call	getw
		xchg
		pop	h
		mov	m,e
		inx	h
		mov	m,d
		inx	h
		xchg
		lhld	max
		dcx	h
		jmp	usq4

usq5:		lxi	h,0
usq6:		push	h
		call	getnxt
		pop	h
		jnz	usq8
		mov	e,a
		mvi	d,0
		dad	d
		push	h
	push	psw
	LHLD	NEXT$ADR	; PT TO LOAD ADDRESS
	LDA	TPA$END	; CHECK AGAINST END PAGE OF TPA
	CMP	H	; IF AT SAME PAGE, YES
	JZ	READ$ERROR
	pop	psw
	mov	m,a
	inx	h
	shld	next$adr

		pop	h
		jmp	usq6

usq8:		xchg
		lhld	filecrc
		call	cmpdehl

usq9:		rz
		call	ilprt
		db	13,10,'ERROR - Checksum error in file ',0
		jmp	help$exit


errext:		pop	h
		mov	a,m
		ora	a
		jz	help$exit
		inx	h
		push	h
		call	conout
		jmp	errext

conout:		ani	127
		mov	e,a
		mvi	c,2
		call	bdos
		ret


cmpdehl:	mov	a,h
		cmp	d
		rnz
		mov	a,l
		cmp	e
		ret

ilprt:		pop	h
		mov	a,m
		ora	a
		inx	h
		push	h
		rz
		call	conout
		jmp	ilprt

get1:		lhld	eob
		xchg
		lhld	sob
		call	cmpdehl
		jz	get1r
		mov	a,m
		inx	h
		shld	sob
		cmp	a
		ret

get1r:		mvi	a,'.'
		call	conout
		lhld	lastmem
		shld	sob
		shld	eob
get1r1:		push	h
		xchg
		mvi	c,26
		call	bdos
		lxi	d,fcb
		mvi	c,20
		call	bdos
		pop	h
		ora	a
		jnz	get1r2
		lxi	d,128
		dad	d
		xchg
		lhld	endmem
		call	cmpdehl
		xchg
		jnc	get1r1
get1r2:		shld	eob
		xchg
		lhld	sob
		call	cmpdehl
		jnz	get1
		mvi	a,255
		ora	a
		ret



getw:		call	get1
		jnz	badr
		push	psw
		call	get1
		jnz	badr
		mov	h,a
		pop	psw
		mov	l,a
		ret

badr:		call	ilprt
		db	13,10,'Premature EOF on file... aborted.',0
		jmp	0

getnxt:		lda	rcnt		;see if in the middle of
		ora	a		;repeat sequence...
		jz	getn7
		dcr	a
		sta	rcnt
		lda	last
		cmp	a
		ret
getn7:		call	getn4
		cpi	dle
		jnz	getn5
		call	getn4
		ora	a
		jnz	getn6
		mvi	a,dle		;dle is encoded as dle,0
		cmp	a
		ret
getn6:		dcr	a
		dcr	a
		sta	rcnt
		lda	last
		cmp	a
		ret
getn5:		sta	last
		cmp	a
		ret


getn4:		lxi	d,0		;pointer @ sot
		lda	char
		mov	c,a
getn1:		lda	numlft
		ora	a
		jnz	getn2
		push	d
		call	get1
		jnz	badr
		pop	d
		mov	c,a
		mvi	a,8
getn2:		dcr	a
		sta	numlft
		mov	a,c
		rrc
		mov	c,a
		lxi	h,table
		jnc	getn3
		inx	h
		inx	h		;add 2 to point to right node
getn3:		dad	d
		dad	d
		dad	d
		dad	d		;ok.. pointing close to right plc..
		mov	e,m
		inx	h
		mov	d,m
		mov	a,d
		ani	128
		jz	getn1
		mov	a,c
		sta	char
		mov	a,d
		cpi	254		;is special eof?
		mvi	a,eof
		jz	geteof		;yup
		mov	a,e
		cma
		cmp	a
		ret

geteof:		pop	h
		ora	a
		ret


;end of baseline USQ code

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

HELPMS:
	DB	'HELP  Version ',(VERS/10)+'0','.',(VERS MOD 10)+'0',CR,LF,'$'
SELECTMS:
	DB	CR,LF,'  HELP File Selections are --',CR,LF,'$'
DEFFN:
	DB	0,'HELP    '
DEFTYP:
	DB	'HLP'
ENDMS:
	DB	'EOI '
PAGEMS:
	DB	'^C=CP/M $'		; ABORT TO CP/M CHAR
PAGE1MS:
	DB	LEVEL$RET$CHAR,'=Level '	; RETURN TO HIGHER NODE
	DB	ROOT$CHAR,'=Root $'		; RETURN TO ROOT
PAGE2MS:
	DB	MENU$CHAR,'=Menu '	; ABORT TO MENU CHAR
	DB	START$CHAR,'=Start '	; JUMP TO START OF INFORMATION CHAR
	DB	BACKUP$CHAR,'=Last '	; BACK UP TO PREVIOUS FRAME CHAR
	DB	'CR=Next $'
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,'$'
BACKERR:
	DB	CR,LF,'HELP ERROR -- Not Possible to Backup Before Start of '
	DB	'Info',CR,LF,'$'
LEVELERR:
	DB	CR,LF,'HELP ERROR -- Node Level Limit Reached -- Aborting'
	DB	CR,LF,'$'
LOADERR:
	DB	CR,LF,'HELP ERROR -- Invalid File Name in Load',CR,LF,'$'
LRETERR:
	DB	CR,LF,'HELP ERROR -- No Higher Level to Return to',CR,LF,'$'
READERR:
	DB	CR,LF,'HELP ERROR -- Not Enough Room for HELP File',CR,LF,'$'
CTRLZERR:
	DB	CR,LF,'HELP ERROR -- HELP File NOT Terminated by ^Z',CR,LF,'$'
LEVEL$MESSAGE:
	DB	'Level $'
LEVEL2$MESSAGE:
	DB	'/ $'
LEVEL3$MESSAGE:
	DB	': $'
PROMPT1$MESSAGE:
	DB	'Type  ^C=CP/M$'
PROMPT2$MESSAGE:
	DB	' ',LEVEL$RET$CHAR,'=Level '
	DB	ROOT$CHAR,'=Root$'
PROMPT3$MESSAGE:
	DB	' or Enter Selection $'
LOADING$MSG:
	DB	CR,LF,'Loading HELP File $'

lastmem:	dw	buff
endmem:		dw	buff+127
sob:		dw	buff
eob:		dw	buff

CUR$DISK:
	DS	1	; NUMBER OF CURRENT DISK IF CHANGED OR 0FFH=NO CHANGE
CUR$USER:
	DS	1	; NUMBER OF CURRENT USER IF CHANGED OR 0FFH=NO CHANGE
TPA$END:
	DS	1	; END PAGE ADDRESS OF TPA
START$OF$INFO:
	DS	2	; PTR TO START OF CURRENT INFORMATION BLOCK
START$OF$FRAME:
	DS	2	; PTR TO START OF CURRENT FRAME
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
LD$SPACE:
	DS	1	; LEADING SPACE FLAG FOR DECIMAL PRINT
HELP$LEVEL:
	DS	1	; NUMBER OF HELP LEVEL CURRENT NODE IS AT (0=BOTTOM)
FRAME$NUMBER:
	DS	1	; NUMBER OF CURRENT FRAME

numlft:	ds	1
rcnt:	ds	1
filecrc:ds	2
last:	ds	1
char:	ds	1
numvals:ds	2
max:	ds	2
table:	ds	258*4


HELP$NAME$STACK:
	DS	11*HELP$MAX	; STACK OF HELP FILE NAMES OF EACH LEVEL

	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
