;			MENU PROGRAM
;			   FOR
;		MACHINE LANGUAGE OR BASIC PROGRAMS
;
;			   BY
;			JAMES J. FRANTZ
;			  MAY 31, 1979	
;
;
	ORG	0100H
;
;
BASIC$PROG	EQU	0		;SET TO 0 FOR MACHINE
;
	LXI	SP,STACK$AREA		;SET UP A STACK
	MVI	C,17			;'SEARCH FIRST' COMMAND
;
SORT$LOOP:
	LXI	D,SRCH$FCB		;POINT FILE CONTROL BLOCK
	CALL	BDOS			;USE CP/M ENTRY POINT
;
;
	ORA	A			;TEST FOR -1
	JM	ASSIGN$MENU$NBR		;PRINT EMPTY
	RRC				;THIS IS THE SAME AS
	RRC				;5 "ADD A'S"
	RRC
	ANI	60H 			;MASK CORRECT BITS
	ADI	80H			;ADD BASE ADDRESS(0080H)
	MOV	E,A			;PUT POINTER IN (DE)
	MVI	D,0			;AS 16 BIT VALUE
	LXI	H,DIRTABLE		;POINT START OF TABLE OF
					;SORTED NAMES
	INX	D			;POINT PAST ERASE FIELD
;
COMPARE$LOOP:
;
	PUSH	D			;SAVE POINTER TO NEXT
					;ENTRY FROM DISK DIRECTORY
	MVI	C,8			;LENGTH OF COMPARE
	PUSH	H			;SAVE POINTER TO TABLE
;
COMPARE1:
	LDAX	D			;GET TRIAL NAME CHAR
	CMP	M			;MATCH?
	JNZ	END$COMPARE		;IF NOT, TRY NEXT ENTRY
	INX	H			;ADVANCE POINTERS
	INX	D				
	DCR	C			;ONE LESS CHAR TO COMPARE	
	JNZ	COMPARE1		;KEEP TESTING	
END$COMPARE:	
	POP	B			;RESTORE TABLE POINTER
	JC	INSERT$NAME		;DIRECTORY NAME GOES IN	
					;FRONT OF CURRENT TABLE
					;ENTRY IF LOWER(CY=1)
	LXI	H,14			;LENGTH OF TABLE ENTRY
	DAD	B			;(HL) TO NEXT TABLE ENTRY
	POP	D			;RECOVER TRAILER NAME POINT
	JMP	COMPARE$LOOP		;LOOP AGAIN
;	
;
INSERT$NAME:
	LXI	H,FILE$COUNT		;COUNT THE NUMBER OF FILES
	INR	M			;TO BE DISPLAYED
	LHLD	END$OF$TABLE		;GET POINTER TO TABLE
	XCHG
	LXI	H,14			;DISTANCE TO MOVE
	DAD	D			;(HL) POINT DESTINATION
	SHLD	END$OF$TABLE		;SAVE THE NEW END OF TABLE
	INX	H
	INX	D
MOVE$UP:
	DCX	D
	DCX	H
	LDAX	D			;GET BYTE TO MOVE
	MOV	M,A			;PUT IN NEW SPOT
	MOV	A,C			;TEST FOR DONE
	CMP	E			;(BC)=(DE)?
	JNZ	MOVE$UP
	MOV	A,B
	CMP	D
	JNZ	MOVE$UP
	POP	H			;RECOVER POINTER
	MVI	C,8
	CALL	BLOCK$MOVE		;INSERT NAME IN TABLE
;
	LXI	H,MENU$BUFF		;POINT MENU NUMBER BLOCK
	MVI	C,6			;LENGTH OF MOVEK
	CALL	BLOCK$MOVE		;INSERT TEXT IN TABLE
;
	MVI	C,18			;'SEARCH NEXT' COMMAND
	JMP	SORT$LOOP
;
ASSIGN$MENU$NBR:
	LDA	FILE$COUNT
	MOV	B,A			;SAVE IN (B)
	PUSH	PSW			;AND ON STACK
	MVI	C,0			;INITIAL FILE NUMBER
	LXI	H,DIRTABLE+11		;POINT FIRST FILE NUMBER
	LXI	D,13			;OFFSET TO OTHER NUMBERS
;
NUMBER$FILES:
	MOV	A,C			;PUT FILE NUMBER IN (A)
	ADI	1			;INCREMENT
	DAA				;DECIMAL CONVERT
	MOV	C,A			;RESAVE	IN (C)
	RRC				;GET TENS DIGIT INTO
	RRC				;PROPER PLACE
	RRC				;
	RRC
	ANI	0FH			;ADD MASK
	JZ	USE$BLANK		;SUPRESS LEADING ZERO BY
	ADI	10H			;ADD EITHER 20H(ASCII ' ')
USE$BLANK:
	ADI	' '			;OR 20H + 10H FOR NUMERAL
	MOV	M,A			;PUT IN TEXT STREAM
	MOV	A,C			;GET UNITS PORTION
	ANI	0FH			;MASK OFF TENS PORTION
	ADI	'0'			;CONVERT TO ASCII
	INX	H			
	MOV	M,A
	DAD	D			;REPEAT UNTIL ALL FILES
	DCR	B			;ARE SEQUENTIALLY NUMBERED
	JNZ	NUMBER$FILES
;	
	POP	PSW			;GET FILE$COUNT FROM STACK
	PUSH	PSW			;AND SAVE AGAIN FOR LATER
;
;
	ADI	NBR$COL-1
	MVI	B,255			;(B) ACCUMULATES QUOTIENT
					;SO SET TO -1 FOR AT LEAST
					;1 PASS THRU GIVES 0
;
DIVX:
	INR	B			;
	SUI	NBR$COL			;DIVIDE (FILE$COUNT+3)BY
					;FOUT TO GET OFFSET1
;
	JP	DIVX
	ADI	NBR$COL			;SUBSTRACTED ONCE TOO MUCH
					;SO ADD IT BACK ON
	LXI	H,OFFSET1		
	MOV	M,B			;INSERT OFFSET1 INTO TABLE
	INX	H			;POINT OFFSET2 LOCATION
	JNZ	SETOFFSET2		;SAME AS OFFSET1 IF NON-
					;ZERO REMAINDER
	DCR	B			;ELSE OFFSET2=OFFSET1-1
;:
SETOFFSET2:
	MOV	M,B			;PUT OFFSET2 IN TABLE
	INX	H			;POINT OFFSET	FOR COL 3
	DCR	A			;TEST FOR REMAINDER OF 1
	JNZ	SETOFFSET3		;IF REMAINDER <> 1, USE
					;OFFSET3=OFFSET2-1
	DCR	B			;ELSE OFFSET3=OFFSET2-1Y
;
SETOFFSET3:
	MOV	M,B			;ELSE OFFSET TO COLUMN 4
;	
;	
REPRINT:
	POP	PSW			;RECOVER FILE COUNT
;
REPRINT1:	
	PUSH	PSW			;SAVE AGAIN FOR LATER USE
	STA	FILE$COUNT		;SAVE FOR COUNTING	
	MVI	A,SCREEN$HGT		;SET FOR VIDEO DISPLAY SIZE
	STA	LINE$COUNT		;
	LXI	D,HEADING
	MVI	C,9			;BUFFER PRINTER COMMAND
	CALL	BDOS			;CP/M PRINTS HEADING
;	
	LXI	H,DIR$TABLE - 14	;POINT DUMMY 0TH ENTRY
;	
PRINT$LINE:
	PUSH	H			;SAVE BASE ADDRESS
	LXI	D,OFFSET0		;POINT OFFSET TABLE
	MVI	A,NBR$COL		;4 COLUMN PER LINE
;
PRINT$NAME:
	STA	COLUMN$CNT		;SAVE COUNT OF COLUMNS
	PUSH	H			;SAVE CURRENT NAME POINTER
	PUSH	D			;SAVE OFFSET TABLE POINTER
	LXI	D,DOUBL$SPACE		;PRINT 2 BLANKS
	MVI	C,9			;'PRINT BUFFER' COMMAND
	CALL	BDOS			;USE CP/M 
	POP	D			;GET OFFSET TABLE POINTER
	POP	H			;GET NAME POINTER
	LDAX	D			;GET OFFSET VALUE
;
	LXI	B,14			;EACH NAME IS 14 LONG
;
MULT$14:
	DAD	B			;ADD 14 FOR EACH OFFSET
	DCR	A			;UNTIL OFFSET = 0
	JNZ	MULT$14
	PUSH	H			;SAVE NEW NAME POINTER
	PUSH	D			;SAVE OFFSET POINTER
	XCHG				;POINTER NAME TO PRINT W/(DE)
	MVI	C,9			;PRINT BUFFER
	CALL	BDOS			;PRINT FILE NAME
					;AND IT'S MENU NO.
;
TEST$FINISH:
	LXI	H,FILE$COUNT		;SEE IF DONE PRINTING
	DCR	M			;BY TESTING COUNT OF FILES
	POP	D			;GET OFFSET POINTER
	POP	H			;GET POINTER TO LAST NAME
	JZ	FINISH			;NO MORE TO PRINT
	INX	D			;ADVANCE OFFSET POINTER
	LDA	COLUMN$CNT
	DCR	A			;SEE IF COLUMN LEFT = 0
	JNZ	PRINT$NAME		;PRINT ANOTHER SAVE LINE 
	CALL	CRLF			
	POP	H			;GET BASE OF PREVIOUS LINE
	LXI	D,14			;ADD OFFSET
	DAD	D	
	JMP	PRINT$LINE
;
;
;
FINISH:
	POP	H			;UNJUNK STACK
;
LF$LOOP:
	CALL	CRLF
	JP	LF$LOOP			;OMIT THIS LINE IF DESIRED
	LXI	D,PROMPT		;POINT INSTRUCTION MESSAGE
	MVI	C,9			
	CALL	BDOS
	LXI	D,INPUT$BUFF
	MVI	A,10			;10 CHRS MAX
	STAX	D
	MVI	C,10			;'READ BUFFER' COMMAND
	CALL	BDOS
;
;
;
	LXI	H,INPUT$BUFF+1		;POINT TO CHR COUNTER
	MOV	A,M			;GET IT AND SEE IF >2 
	CPI	3
	JNC	REPRINT			;REPRINT THE MENU
	MOV	C,A			;COUNT OF DIGITS TO (C)
	MVI	B,0
;
GET$MENU$NBR:
	INX	H			;POINT ASCII DIGIT
	MOV	A,M			;GET IT
	CALL	ASCII$CONVERT		;CONVERT TO BINARY
	JC	REPRINT			;RE-DISPLAY ON ERROR
	DCR	C		
	JNZ	GET$MENU$NBR
;
;
	POP	PSW			;RECOVER FILE COUNTER
	CMP	B			;FILE$ COUNT- REQUEST NO.
	JC	REPRINT1		;REDISPLAY MENU IF ILLEGAL
;
	LXI	D,14			;INC BETWEEN NAMES
	LXI	H,DIR$TABLE-14		;POINT DUMMY 0TH ENTRY
;
FIND$NAME:
	DAD	D			;ADD OFFSET B TIMES
	DCR	B			
	JNZ	FIND$NAME
;
;
	XCHG				;SAVE POINTER TO FILE NAME
	LHLD	6			;GET BDOS ENTRY POINT
	LXI	B,-CCP$LEN		;OFFSET TO START OF CM/M
	DAD	B
	PUSH	H			;SAVE CP/M ENTRY POINT
					;ON STACK FOR BRANCH
	LXI	B,8			;OFFSET TO COMMAND BUFFER
	DAD	B			;(HL) POINTS PLACE TO PUT 
					;NAME OF .COM FILE TO BE
					;EXECUTED
	PUSH	D			;SAVE POINTER TO FILE NAME
	XCHG				;(DE) POINTS COMMAND BUDFER
;
;
;
	LXI	H,128			;OFFSET TO END OF CMD BUFF
					;WHERE POINTER IS STORED
	DAD	D			;(HL) POIN TS STORAGE PLACE
	MOV	M,E			;UPDATE BUFFER POINTER TO
	INX	H			;THE START OF THE COMMAND
	MOV	M,D			;BUFF SO CP/M WILL READ
;	
	IF	BASIC$PROG
;
	LXI	H,COMMAND$NAME		;POINT COMMAND NAME
	MVI	C,LEN$CMD$NAME		;LENGHT OF COMMAND NAME
	CALL	BLOCK$MOVE
;
	ENDIF
;
	POP	H			;POINT SELECTED FILE NAME
	MVI	C,8			;LENGTH OF FILE NAME
	CALL	BLOCK$MOVE
;
;
	IF	BASIC$PROG
;
	LXI	H, SPEC$TYPE
	MVI	C,4
	CALL	BLOCK$MOVE 
;
	ENDIF
;
	XRA	A			;NEEDS A 0 AT END
	STAX	D			;OF COMMAND LINE
;
	RET
;
;
;SUBROUTINES
;
BLOCK$MOVE:
	MOV	A,M
	STAX	D
	INX	D
	INX	H
	DCR	C
	JNZ	BLOCK$MOVE
	RET
;
ASCII$CONVERT:
	SUI	'0'			;SUBTRACT ASCII BIAS
	CPI	9+1			;BE SURE IT'S NUMERIC
	CMC
	RC
	MOV	D,A
	MOV	A,B
	RLC
	RLC
	RLC
	ADD	B
	RC
	ADD	B
	RC
	ADD	D
	MOV	B,A
	RET
;
CRLF:
	LXI	D,CRLFMSG
	MVI	C,9
	CALL	BDOS
	LXI	H,LINE$COUNT
	DCR	M
	RET
;
;
CRLFMSG	DB	0DH,0AH,'$'
;
HEADING	DB	0AH,9,9,9,'	MENU',0DH,0AH,0AH,'$'
;
	IF	BASIC$PROG
;
COMMAND$NAME:
	DB	'BASIC '
;
LEN$CMD$NAME	EQU	$-COMMAND$NAME
;
SPEC$TYPE:
	DB	'.BAS'
;
	ENDIF
;
PROMPT:
	DB	'ENTER MENU NUMBER & PRESS RETURN''$'
;
DOUBL$SPACE:
	DB	' $'
;
MENU$BUFF:
	DB	' - 0$'
;
OFFSET0	DB	1
OFFSET1	DB	0,0,0
;
END$OF$TABLE:
	DW	DIRTABLE
;
FILE$COUNT:
	DB	0
COLUMN$CNT:
	DB	4
LINE$COUNT:
	DB	0
;
	IF	BASIC$PROG
;
SRCH$FCB:
	DB	0,'????????BAS',0
;
	ENDIF
;
SRCH$FCB:
	DB	0,'????????COM',0
;

;
DIR$TABLE:
	DB	255
;
STACK$AREA	EQU	200*14 + 30
;
INPUT$BUFF	EQU	STACK$AREA
;
;
;	EQUATES:
;
BDOS	EQU	5
NBR$COL	EQU	4
CCP$LEN	EQU	3C06H-3400H
SCREEN$SIZE	EQU	24
SCREEN$HGT	EQU	80
;
;
;
;

	END
