*  PROGRAM:  BANNER
*  AUTHOR:  SCOTT HOLTZMAN
*  VERSION:  1.0
*  DATE:  07/09/83
*  PREVIOUS VERSIONS:  None

VERS	EQU	10	;VERSION NUMBER
*********************************
*				*
*   B A N N E R  P R I N T	*
*				*
*********************************
*
*  BANNER is a program which prints large (5x7) block letters
* on the LST: Device in response to user input from the
* keyboard.  BANNER is invoked in several ways:
*	BANNER <text>
*		-- <TEXT> is printed on the LST: device; ex:
*			BANNER HELLO
*	BANNER /T
*		-- Multi-Text Line Input Mode; the user may
*		   type several successive lines to be printed;
*		   the user exits by typing ^C
*	BANNER /?
*		-- Built-In HELP Information is printed
*

*********************************
*  User-Customized Parameters	*
*********************************

TEXT	EQU	'T'	;OPTION CHAR TO INVOKE TEXT ENTRY MODE
MCHARS	EQU	16	;MAX NUMBER OF CHARS/LINE

*********************************
*  Constants			*
*********************************

BDOS		EQU 		0005H
FCB		EQU		005CH
BUFF		EQU		0080H
CTRLC		EQU		03H
CR		EQU		0DH
LF		EQU		0AH
TAB		EQU		09H
READLN		EQU		10	;Input Line Editor
OUTL		EQU		5	;OUTPUT TO LST:
OUTC		EQU		2	;OUTPUT TO CON:

	ORG	100H
START:
	LXI	H,0	;SAVE STACK PTR
	DAD	SP	;HL=OLD SP
	SHLD	STACK
	LXI	SP,STACK	;NEW STACK
	CALL	PMSG
	DB	'BANNER  Version '
	DB	VERS/10+'0','.',(VERS MOD 10)+'0'
	DB	CR,LF
	DB	0
	LDA	FCB+1	;CHECK FOR OPTION
	CPI	'/'	;OPTION CAUGHT?
	JNZ	ONE$LINE	;IF NO OPTION, PROCESS ONLY 1 LINE
	LDA	FCB+2	;CHECK FOR TEXT INPUT
	CPI	TEXT	;TEXT CHAR?
	JZ	BTEXT	;INPUT TEXT LINES
;
;  Print BANNER Help Message
;
HELP:
	CALL	PMSG	;PRINT MESSAGE TO USER
	DB	CR,LF,'BANNER is invoked by a command line like:'
	DB	CR,LF,'		BANNER <text>'
	DB	CR,LF,'In which case <TEXT> will be printed and control '
	DB	CR,LF,'returned to CP/M, like "BANNER HELLO" to print'
	DB	CR,LF,'"HELLO", or'
	DB	CR,LF,'		BANNER /o'
	DB	CR,LF,'where ''/o'' is ''/T'' to invoke Text Entry'
	DB	CR,LF,'Mode in which the user may enter several sequential '
	DB	CR,LF,'Banner Lines to be printed.  Any other option '
	DB	CR,LF,'prints this Help Message and Exits.'
	DB	0
*
*  Exit BANNER
*
EXIT:
	LHLD	STACK	;GET OLD STACK PTR
	SPHL		;LOAD SP
	RET
*
*  PRINT BANNER WHEN CONTAINED IN COMMAND LINE
*
ONE$LINE:
	LXI	H,BUFF	;PT TO INPUT LINE
	MOV	A,M	;GET CHAR COUNT
	ORA	A	;PRINT HELP MESSAGE IF NO CHARS
	JZ	HELP
	MOV	B,A	;CHAR COUNT IN B
	DCR	B	;COUNT DOWN BY 1 TO ELIMINATE LEADING SPACE
	JZ	HELP
	LXI	D,BLINE	;PT TO BANNER LINE BUFFER
	MOV	A,B	;GET CHAR COUNT
	STAX	D	;STORE CHAR COUNT
	INX	H	;PT TO FIRST CHAR (SPACE)
	INX	H	;PT TO CHAR AFTER SPACE
	INX	D	;PT TO NEXT POSITION IN BUFFER
OL1:
	MOV	A,M	;GET NEXT CHAR
	STAX	D	;PUT IT
	INX	H	;PT TO NEXT
	INX	D
	DCR	B	;COUNT DOWN
	JNZ	OL1
	CALL	BANNER	;PRINT BANNER
	JMP	EXIT	;EXIT TO CP/M
*
*  Process Multiple Line Input
*
BTEXT:
	CALL	PMSG
	DB	CR,LF,'BANNER Multiple Line Input'
	DB	CR,LF,'	Input Line or ^C to Return to CP/M'
	DB	CR,LF
	DB	0
BTEXTL:
	CALL	PMSG
	DB	'BANNER? ',0
	LXI	D,INLINE	;INPUT LINE
	MVI	C,READLN	;BDOS READLN FUNCTION
	CALL	BDOS
	CALL	PMSG		;NEW LINE
	DB	CR,LF,0
	CALL	BANNER		;PRINT BANNER LINE
	JMP	BTEXTL		;CONTINUE
*
*  PRINT BANNER CONTAINED IN BLINE BUFFER (BLINE=CHAR CNT)
*
BANNER:
	LXI	H,BLINE	;STORE ENDING <NULL>
	MOV	A,M	;GET CHAR COUNT
	CPI	MCHARS+1	;BEYOND CHAR LIMIT?
	JC	BANNER1	;CONTINUE IF NOT
	CALL	PMSG
	DB	CR,LF,'Truncation Error -- Line too long',CR,LF
	DB	0
	JMP	EXIT	;RETURN TO CALLER
BANNER1:
	INX	H	;PT TO FIRST CHAR
	ADD	L	;ADD TO LOW-ORDER BYTE
	MOV	L,A	;PT TO BYTE
	MVI	M,0	;STORE <NULL>
	MVI	D,80H	;PT TO MSB+1
CBAN:
	LXI	H,BLINE+1	;SET PTR TO FIRST CHAR
	MOV	A,M		;CHECK FOR NO CHARS
	ORA	A		;ENDING ZERO?
	JZ	CB4		;4 CRLF'S IF SO
	SHLD	NEXTCH
	CALL	CRLF	;NEW LINE
	MOV	A,D	;GET BIT PTR
	RRC		;ROTATE
	ANI	7FH	;MASK OUT MSB
	MOV	D,A	;SET BIT PTR
	JZ	CB2	;NEW LINE AND THEN EXIT
CB1:
	CALL	CONIN	;GET NEXT CHAR
	CALL	CAPS	;CAPITALIZE
	MOV	C,A	;CHAR IN C
	ORA	A	;DONE?
	JZ	CBAN	;DO NEXT LINE IF SO
	CALL	CONV	;GET ADDRESS OF DATA IN HL
	JC	CB1	;SKIP IF ERROR
	CALL	PRINT	;PRINT 5 CHARS FOLLOWED BY TWO SPACES
	JMP	CB1	;CONTINUE
CB4:
	CALL	CRLF	;4 <CR> <LF>
	CALL	CRLF
	CALL	CRLF
CB2:
	CALL	CRLF	;1 CRLF
	RET

*
*  COMPUTE POINTER TO TABLE ENTRY OF CHAR IN REG A
*    ON INPUT, A=CHAR; ON OUTPUT, HL=PTR TO TABLE ENTRY (1ST BYTE)
*
CONV:
	PUSH	B		;SAVE BC
	PUSH	D		;SAVE DE
	SUI	' '		;CONVERT <SP> TO 0
	RC			;INVALID CHAR
	CPI	7BH-' '		;IN RANGE?
	JNC	CNVER		;INVALID CHAR
	MOV	E,A		;VALUE IN E
	MVI	D,0		;VALUE IN DE
	MOV	H,D		;VALUE IN HL
	MOV	L,E
	DAD	H		;VALUE * 2
	DAD	H		;VALUE * 4
	DAD	D		;HL = VALUE * 5
	LXI	D,CHARS		;POINT TO BEGINNING OF TABLE
	DAD	D		;HL PTS TO ELEMENT IN TABLE
	POP	D		;RESTORE DE
	POP	B		;RESTORE BC
	ORA	A		;CLEAR CARRY
	RET
CNVER:
	STC			;SET CARRY FOR INVALID CHAR
	POP	D		;RESTORE DE
	POP	B		;RESTORE BC
	RET
*
*  CAPITALIZE CHAR IN A
*
CAPS:
	CPI	61H		;LOWER CASE?
	RC
	ANI	5FH		;MASK OUT BIT 5
	RET
*
*  PRINT CHAR IN C ACCORDING TO THE ENTRY PTED TO BY HL
*    BIT MASK IS IN D
*
PRINT:
	PUSH	B		;SAVE BC (C=CHAR)
	MVI	B,5		;5 BYTES/CHAR
PRINT1:
	MOV	A,M		;GET BIT SET
	ANA	D		;MASK FOR BIT IN QUESTION
	JZ	PRINT3		;IF ZERO, PRINT <SP>
	CALL	LSTOUT		;PRINT CHAR IN C
PRINT2:
	INX	H		;PT TO NEXT BYTE
	DCR	B		;COUNT DOWN
	JNZ	PRINT1
	MVI	C,' '		;PRINT THREE SPACES
	CALL	LSTOUT
	CALL	LSTOUT
	CALL	LSTOUT
	POP	B		;RESTORE BC
	RET
PRINT3:
	MOV	E,C		;SAVE CHAR
	MVI	C,' '		;PRINT <SP>
	CALL	LSTOUT
	MOV	C,E		;GET CHAR
	JMP	PRINT2
*
*  SUPPORT ROUTINES
*
PMSG:
	XTHL		;GET PTR TO STRING
	MVI	B,0	;SET TAB COUNTER
PMSG1:
	MOV	A,M	;GET NEXT BYTE
	INX	H	;PT TO NEXT
	ORA	A	;DONE?
	JZ	PMSG2
	CPI	TAB	;TABULATE?
	JZ	PMSG$TAB
	MOV	C,A	;CHAR IN C
	CALL	CONOUT	;PRINT CHAR
	INR	B	;INCR CHAR COUNT
	JMP	PMSG1
PMSG$TAB:
	MVI	C,' '	;PRINT <SP>
	CALL	CONOUT	;PRINT
	INR	B	;INCR POSITION COUNT
	MOV	A,B	;GET IT
	ANI	7	;DONE?
	JNZ	PMSG$TAB
	JMP	PMSG1	;PROCESS NEXT CHAR
PMSG2:
	XTHL		;RESTORE HL, PTR
	RET
CRLF:
	MVI	C,CR
	CALL	LSTOUT
	MVI	C,LF
	JMP	LSTOUT
LSTOUT:
	PUSH H ! PUSH B ! PUSH D
	MOV	E,C
	MVI	C,OUTL		;OUTPUT TO LST:
	CALL	BDOS
	POP D ! POP B ! POP H
	RET
CONOUT:
	PUSH H ! PUSH B ! PUSH D
	MOV	E,C
	MVI	C,OUTC		;OUTPUT TO CON:
	CALL	BDOS
	POP D ! POP B ! POP H
	RET
CONIN:
	PUSH H ! PUSH D ! PUSH B
	LHLD	NEXTCH	;GET NEXT CHAR PTR
	MOV	A,M	;GET CHAR
	INX	H	;PT TO NEXT
	SHLD	NEXTCH
	ANI	7FH	;MASK MSB IF ANY
	POP B ! POP D ! POP H
	RET
*
*  CHARACTER TABLE
*    THE CHARACTERS REPRESENTED IN THIS TABLE ARE IN A 5X7 FORMAT
*    THE FIRST BYTE IN EACH ENTRY REPRESENTS THE FIRST CHAR TO PRINT, ETC
*    THE BITS 6 TO 0 REPRESENT LINES (SUCCESSIVE) TO PRINT FOR THE CHAR
*
*  FOR EXAMPLE, THE ENTRY FOR '*' IS 22H,14H,7FH,14H,22H; THIS GENERATES:
*
*	  *	00100	R	6
*	* * *	10101	E	5
*	 ***	01110	A	4
*	  *	00100	D	3
*	 ***	01110		2
*	* * *	10101	D	1
*	  *	00100	O	0
*		^^^^^	W
*		21712	N	^
*		24F42		B
*		HHHHH		I
*				T
*
CHARS:
	DB	00H,00H,00H,00H,00H	;<SP>
	DB	00H,00H,7DH,00H,00H	;EXCLAMATION MARK
	DB	00H,70H,00H,70H,00H	;"
	DB	14H,7FH,14H,7FH,14H	;#
	DB	12H,2AH,7FH,2AH,24H	;$
	DB	62H,64H,08H,13H,23H	;%
	DB	36H,49H,35H,02H,05H	;&
	DB	00H,00H,70H,00H,00H	;'
	DB	1CH,22H,41H,00H,00H	;(
	DB	00H,00H,41H,22H,1CH	;)
	DB	22H,14H,7FH,14H,22H	;*
	DB	08H,08H,3EH,08H,08H	;+
	DB	00H,01H,06H,00H,00H	;,
	DB	08H,08H,08H,08H,08H	;-
	DB	00H,03H,03H,00H,00H	;.
	DB	02H,04H,08H,10H,20H	;/
	DB	3EH,45H,49H,51H,3EH	;0
	DB	11H,31H,7FH,01H,01H	;1
	DB	21H,43H,45H,49H,31H	;2
	DB	22H,41H,49H,49H,36H	;3
	DB	0CH,14H,24H,7FH,04H	;4
	DB	7AH,49H,49H,49H,46H	;5
	DB	3EH,49H,49H,49H,26H	;6
	DB	43H,44H,48H,50H,60H	;7
	DB	36H,49H,49H,49H,36H	;8
	DB	30H,49H,49H,49H,3EH	;9
	DB	00H,00H,36H,00H,00H	;:
	DB	00H,01H,16H,00H,00H	;;
	DB	08H,14H,22H,41H,00H	;<
	DB	14H,14H,14H,14H,14H	;=
	DB	00H,41H,22H,14H,08H	;>
	DB	20H,40H,4DH,50H,20H	;?
	DB	7EH,41H,5DH,4DH,39H	;@
	DB	3FH,48H,48H,48H,3FH	;A
	DB	7FH,49H,49H,49H,36H	;B
	DB	7FH,41H,41H,41H,41H	;C
	DB	7FH,41H,41H,41H,3EH	;D
	DB	7FH,49H,49H,49H,41H	;E
	DB	7FH,48H,48H,48H,40H	;F
	DB	7FH,41H,41H,49H,4FH	;G
	DB	7FH,08H,08H,08H,7FH	;H
	DB	41H,7FH,41H,80H,80H	;I
	DB	03H,01H,01H,01H,7FH	;J
	DB	7FH,08H,14H,22H,41H	;K
	DB	7FH,01H,01H,01H,01H	;L
	DB	7FH,20H,10H,20H,7FH	;M
	DB	7FH,30H,08H,06H,7FH	;N
	DB	7FH,41H,41H,41H,7FH	;O
	DB	7FH,48H,48H,48H,78H	;P
	DB	7FH,41H,45H,43H,7FH	;Q
	DB	7FH,48H,4CH,4AH,79H	;R
	DB	32H,49H,49H,49H,26H	;S
	DB	40H,40H,7FH,40H,40H	;T
	DB	7FH,01H,01H,01H,7FH	;U
	DB	70H,0CH,03H,0CH,70H	;V
	DB	7FH,02H,04H,02H,7FH	;W
	DB	63H,14H,08H,14H,63H	;X
	DB	60H,10H,0FH,10H,60H	;Y
	DB	43H,45H,49H,51H,61H	;Z
	DB	7FH,41H,41H,41H,00H	;[
	DB	20H,10H,08H,04H,02H	;\
	DB	00H,41H,41H,41H,7FH	;]
	DB	04H,08H,10H,08H,04H	;^
	DB	01H,01H,01H,01H,01H	;_
	DB	00H,40H,20H,10H,00H	;'
	DB	3FH,48H,48H,48H,3FH	;A
	DB	7FH,49H,49H,49H,36H	;B
	DB	7FH,41H,41H,41H,41H	;C
	DB	7FH,41H,41H,41H,3EH	;D
	DB	7FH,49H,49H,49H,41H	;E
	DB	7FH,48H,48H,48H,40H	;F
	DB	7FH,41H,41H,49H,4FH	;G
	DB	7FH,08H,08H,08H,7FH	;H
	DB	41H,7FH,41H,80H,80H	;I
	DB	03H,01H,01H,01H,7FH	;J
	DB	7FH,08H,14H,22H,41H	;K
	DB	7FH,01H,01H,01H,01H	;L
	DB	7FH,20H,10H,20H,7FH	;M
	DB	7FH,30H,08H,06H,7FH	;N
	DB	7FH,41H,41H,41H,7FH	;O
	DB	7FH,48H,48H,48H,78H	;P
	DB	7FH,41H,45H,43H,7FH	;Q
	DB	7FH,48H,4CH,4AH,79H	;R
	DB	32H,49H,49H,49H,26H	;S
	DB	40H,40H,7FH,40H,40H	;T
	DB	7FH,01H,01H,01H,7FH	;U
	DB	70H,0CH,03H,0CH,70H	;V
	DB	7FH,02H,04H,02H,7FH	;W
	DB	63H,14H,08H,14H,63H	;X
	DB	60H,10H,0FH,10H,60H	;Y
	DB	43H,45H,49H,51H,61H	;Z

*
*  BUFFERS
*
	DS	40	;20-ELT STACK
STACK:
	DS	2	;TOP OF BANNER STACK; CP/M STACK
NEXTCH:
	DS	2
LLEN	EQU	80	;NUMBER OF CHARS IN LINE, MAX
INLINE:
	DB	LLEN	;CHAR COUNT FOR INLINE
BLINE:
	DS	LLEN+1	;NUMBER OF BYTES IN LINE
