*+++++++++++++++++++++++++++++++++++++++++
*
*	*** LOOKUP.ASM ***
*	     Ver. 3
*
*	COPYRIGHT (C) 1985 JIM SCHENKEL
*	SEAMLESS WEB SOFTWARE
*	415/553-4000
*
*	Revision date: MARCH 6, 1987
*
*	RELEASED INTO THE PUBLIC DOMAIN
*	FOR NONCOMMERCIAL USE ONLY
*
*+++++++++++++++++++++++++++++++++++++++++

	ORG	100H
BDOS	EQU	0005H
FCB	EQU	005CH	;FILE CONTROL BLOCK
BUFF	EQU	80H	;DEFAULT INPUT BUFFER
CONSF	EQU	1	;READ CONSOLE
TYPEF	EQU	2	;TYPE CHAR TO CONSOLE
LISTF	EQU	5	;LIST CHAR TO PRINTER
DIRIOF	EQU	6	;DIRECT CONSOLE I/O
PRINTF	EQU	9	;PRINT STRING
RDBUFF	EQU	10	;READ CONSOLE BUFFER
OPENF	EQU	15	;OPEN FILE
READF	EQU	20	;SEQUENTIAL READ
DMAF	EQU	26	;SET DMA
BEL	EQU	07
BS	EQU	08
TAB	EQU	09
LF	EQU	0AH
UP	EQU	0BH
CR	EQU	0DH
EOF	EQU	1AH
ESC	EQU	1BH
DEL	EQU	07FH
DIM	EQU	29H	;SET HALF INTENSITY
BRITE	EQU	28H	;SET FULL INTENSITY
BLANK	EQU	54H	;ERASE TO END OF LINE
MAXLEN	EQU	7FH	;MAXIMUM LENGTH OF INCOMING STRING
WIDTH	EQU	128	;WIDTH OF OSBORNE 1 LINE
SCRWID	EQU	80	;WIDTH OF SCREEN

	JP	START

*CODES

;FILE NAME MUST BE EXACTLY 11 BYTES (NAMENAMETYP)
FILNAM	DB	'MAST    CAT'		;NAME OF DEFAULT FILE
;DELAY TIMERS (SECONDS *100)
SHORT	DW	600
LONG	DW	2000

*STORAGE

	DS	20	;STACK AREA
STACK	DW	0	;OLD STACK POINTER
TOP	DW	0	;TOP OF MEMORY
BUFLEN	DW	0	;LENGTH OF DATA BUFFER
BDMA	DW	0	;CURRENT DMA POINTER
TIMER	DW	0	;DELAY FACTOR
FLAG	DB	0	;INPUT FLAG
EFLAG	DB	0	;EXACT MATCH TOGGLE (FF=EXACT)


*MAIN PROGRAM

;INITIALIZE LOCAL STACK
START	LD	HL,0
	ADD	HL,SP
	LD	(STACK),HL
	LD	SP,STACK

;FLASH COPYRIGHT NOTICE
	CALL	CLEAR
	LD	DE,MINE
	CALL	PRINT

;CHECK FOR COMMAND LINE FILE NAME
	LD	A,(FCB+1)	;GET FIRST CHARACTER
	CP	' '		;IF IT'S NOT A SPACE
	JR	NZ,OPEN		;THEN USE THAT NAME

;MOVE THE DEFAULT FILE NAME INTO THE FCB
	LD	HL,FILNAM
	LD	DE,FCB+1
	LD	BC,11
	LDIR

;OPEN THE FILE
OPEN	LD	DE,FCB
	LD	C,OPENF
	CALL	BDOS
	LD	DE,NOFILE
	INC	A		;FF-->0 IF NO FILE
	JP	Z,ERROR

;CALCULATE THE TOP OF MEMORY
	LD	HL,(BDOS+1)	;GET BDOS LOCATION
	LD	DE,100H		;LEAVE ENOUGH ROOM
	SBC	HL,DE		;TO AVOID TROUBLE
	LD	(TOP),HL

;INITIALIZE THE POINTER TO THE DMA
	LD	DE,BUFFER	;POINT TO DATA AREA
	LD	(BDMA),DE	;STORE CURRENT POINTER
	LD	C,DMAF		;SET THE DMA
	CALL	BDOS
	XOR	A		;ZERO A
	LD	(FCB+32),A	;CLEAR "CR" IN DMA

;READ DATA INTO MEMORY
READ	LD	DE,FCB		;GET RECORD
	LD	C,READF
	CALL	BDOS
	OR	A		;ZERO IF READ OK
	JR	NZ,BUFSIZ	;ELSE ENTIRE FILE WAS READ

;INCREMENT THE BUFFER POINTER
	LD	HL,(BDMA)	;GET THE CURRENT POINTER
	LD	DE,80H		;ADD 128 BYTES
	ADD	HL,DE		;AS OFFSET
	LD	(BDMA),HL	;STORE NEW POINTER
	PUSH	HL		;STORE ON STACK
	LD	DE,(TOP)	;GET UPPER BOUND
	SBC	HL,DE		;SUBTRACT FROM POINTER
	JR	C,XBF		;DE>HL, SO PROCEED
	LD	DE,OVRFLW	;HL>DE, SO GIVE
	CALL	PRINT		;MESSAGE AND
	JR	BUFSIZ		;DON'T READ ANY MORE
XBF	POP	DE		;PICK UP POINTER IN DE
	LD	C,DMAF		;UPDATE THE DMA
	CALL	BDOS		
	JR	READ		;DO IT AGAIN

;CALCULATE SIZE OF DATA BUFFER
BUFSIZ	LD	HL,(BDMA)	;GET LAST DMA
	LD	B,80H
	LD	DE,-80H		;SUBTRACT TO LOOK AT LAST BLOCK
	ADD	HL,DE
	LD	A,EOF		;CHECK FOR END OF FILE
CHEKEOF	CP	(HL)
	JR	Z,GOTEOF	;HL POINTS TO EOF NOW
	INC	HL
	DJNZ	CHEKEOF
GOTEOF	LD	DE,BUFFER	;GET START OF BUFFER
	OR	A		;CLEAR CARRY
	SBC	HL,DE		;SUBTRACT START FROM END
	LD	(BUFLEN),HL	;STORE BUFFER LENGTH

;FIX UP THE HIGH ORDER BITS
	PUSH	HL		;GET BUFFER LENGTH
	POP	BC		; COUNTER INTO BC
	LD	HL,BUFFER-1	;INITIALIZE POINTER
FIXBIT	INC	HL		;BUMP POINTER
	RES	7,(HL)		;ZERO HIGH BIT
	DEC	BC		;LOOP THROUGH
	LD	A,B		; THE ENTIRE
	OR	C		; BUFFER
	JR	NZ,FIXBIT

	CALL	CLEAR		;CLEAR THE SCREEN 

;GET INPUT STRING
NEWSTR	LD	A,(EFLAG)	;TEST EXACT MATCH FLAG
	OR	A		;EXACT MATCH REQUIRED?
	JR	Z,PRU		;NO, USE NORMAL PROMPT
	LD	DE,EPROMPT	;YES, USE EXACT PROMPT
	JR	PRE
PRU	LD	DE,PROMPT
PRE	CALL	GETSTR
	LD	A,(MX+1)	;GET STRING LENGTH
	OR	A		;TEST FOR ZERO
	JP	NZ,EXACT	;0 = TOGGLE EXACT MATCH FLAG
	LD	A,(EFLAG)
	CPL
	LD	(EFLAG),A
	LD	DE,CLRPMT	;CLEAR PROMPT
	CALL	PRINT
	
;TEST EXACT MATCH FLAG
EXACT	LD	A,(EFLAG)
	OR	A		;IF FLAG=FF
	JP	NZ,SEARCH	;THEN DON'T MAKE UPPER CASE

;CONVERT TO UPPER CASE
	LD	BC,(MX)		;GET CX IN B
	LD	HL,STRING	;POINT TO STRING
UPPER	LD	A,(HL)		;GET A CHARACTER
	CP	'a'		;CHECK FOR LOWER CASE
	JR	C,NOLO
	RES	5,(HL)		;CHANGE TO UPPER CASE
NOLO	INC	HL
	DJNZ	UPPER

;SEARCH FOR THE STRING
SEARCH	LD	HL,BUFFER	;POINT TO BUFFER
	LD	BC,(BUFLEN)	;COUNTER FOR LENGTH
LOOK	LD	DE,STRING	;POINT TO SEARCH STRING
	LD	A,(DE)		;GET FIRST CHARACTER
	CPIR			;LOOK FOR A MATCH
	JR	Z,GOT1		;FOUND A MATCH
	JP	PO,NEWSTR	;COUNTER HAS REACHED ZERO
				;SO ASK FOR ANOTHER STRING

;FOUND MATCH FOR FIRST CHARACTER, SO
;CHECK THE REST OF THE SEARCH STRING
GOT1	PUSH	BC		;SAVE BUFLEN COUNTER
	LD	BC,(MX)		;GET CX IN B
	DEC	B		;ALLOW FOR FIRST CHARACTER
	JR	Z,SHOW		;PRINT IF ONLY 1
GOT2	INC	DE		;BUMP POINTER TO STRING
	LD	A,(DE)		;GET A CHARACTER
	CP	'?'		;WILD CARD?
	JR	Z,WILD		;YES, SO IGNORE MATCH
	CP	(HL)		;DOES IT MATCH?
	JR	NZ,NOPE		;NO, TRY AGAIN
WILD	INC	HL
	DJNZ	GOT2
	JR	SHOW		;ALL CHARACTERS MATCH

NOPE	POP	BC		;RESTORE BUFLEN COUNTER
	JR	LOOK		;AND KEEP LOOKING

;PRINT THE RECORD
;AND UPDATE THE DATA POINTER AND COUNTER TO
;THE END OF THE RECORD
SHOW	CALL	CONSIO		;ABORT?
	JP	NZ,NEWSTR	;YES
	POP	BC		;RESTORE BUFLEN COUNTER
SHOW1	DEC	HL		;BACK UP A CHARACTER
	PUSH	HL		;SAVE POINTER TO BUFFER
	LD	DE,BUFFER	;BEGINNING OF BUFFER
	OR	A		;CLEAR THE CARRY
	SBC	HL,DE		;ARE WE AT THE BEGINNING?
	POP	HL		;(RESTORE THE POINTER)
	LD	A,(HL)		;(PICK UP A CHARACTER)
	JR	Z,NEXTCH	;YES, SO PRINT 1ST RECORD
	INC	BC		;ELSE INCREMENT COUNTER
	CP	EOF		;END OF FILE?
	JR	Z,NEWSTR	;MUST BE A MISTAKE
	CP	CR		;GOT A CARRIAGE RETURN?
	JR	NZ,SHOW1	;NO, SO GO BACK FURTHER
NEXTCH	CP	EOF		;END OF FILE?
	JP	Z,NEWSTR	;THEN GET ANOTHER STRING
	CP	1EH		;GET RID OF WORDSTAR'S
	JR	NZ,NOSOFT	;SOFT HYPHENS
	LD	A,'-'
NOSOFT	LD	E,A		;READY TO PRINT CHARACTER
	CALL	PRCHR		;START PRINTING THE RECORD
	INC	HL		; BYTE BY BYTE
	DEC	BC		; KEEPING TRACK OF LENGTH
	LD	A,B		;IF BC GOES TO ZERO
	OR	C		; THEN WE'RE AT THE
	JP	Z,NEWSTR	; END OF THE DATA BUFFER
	LD	A,(HL)		;GET ANOTHER CHARACTER
	CP	CR		;END OF RECORD?
	JR	NZ,NEXTCH	;NO, GET ANOTHER CHARACTER
	JR	LOOK		;YES, SO GO LOOK SOME MORE

;WRAP IT UP AND BAIL OUT
ERROR	CALL	PRINT		;PRINT ERROR MESSAGE
QUIT	LD	HL,(STACK)	;RESTORE OLD STACK POINTER
	LD	SP,HL
	RET			;RETURN TO CCP



*SUBROUTINES

;CLEAR THE SCREEN (falls into prchr)
CLEAR	LD	E,26		;CLEAR SCREEN CHARACTER

;PRINT CHARACTER IN REGISTER E
PRCHR	PUSH	AF
	PUSH	BC
	PUSH	DE
	PUSH	HL
	LD	C,TYPEF
	CALL	BDOS
	POP	HL
	POP	DE
	POP	BC
	POP	AF
	RET

;PRINT A PROMPT AND READ A STRING INTO INPUT BUFFER
;	ENTRY:	DE POINTS TO PROMPT
;	EXIT:	NEW STRING IN INPUT BUFFER
;		DE CLOBBERED, MAYBE OTHER REGISTERS TOO
GETSTR	CALL	CLSTR		;CLEAR THE SEARCH STRING
	LD	C,PRINTF
	CALL	BDOS
	LD	DE,MX
	LD	C,RDBUFF
	CALL	BDOS
	RET

;CLEAR THE INPUT STRING
;	CLOBBERS A, BC, HL
CLSTR	LD	B,MAXLEN	;MAXIMUM STRING LENGTH
	LD	HL,STRING
	XOR	A
CLR2	LD	(HL),A		;ZERO A BYTE
	INC	HL		;BUMP POINTER
	DJNZ	CLR2		;AND LOOP
	RET

;CLEAR A PROMPT LINE
;	CLOBBERS DE
CLINE	LD	DE,CLRLIN	;FALLS INTO PRINT SUBRT.

;PRINT A STRING TERMINATED BY '$'
PRINT	PUSH	AF
	PUSH	BC
	PUSH	DE
	PUSH	HL
	LD	C,PRINTF
	CALL	BDOS
	POP	HL
	POP	DE
	POP	BC
	POP	AF
	RET

;LONG DELAY
;	INPUT: BC = HUNDREDTHS OF A SECOND
SLOWER	PUSH	AF
SLOWEST	CALL	SLOW
	DEC	BC
	LD	A,B
	OR	C
	JR	NZ,SLOWEST
	POP	AF
	RET

;SHORT DELAY
; 	(ABOUT .01 SECOND)
SLOW	PUSH	AF
	PUSH	HL
	LD	HL,1365
SLOW1	DEC	HL
	LD	A,H
	OR	L
	JR	NZ,SLOW1
	POP	HL
	POP	AF
	RET

;SUBROUTINE TO DO DIRECT CONSOLE INPUT, NO SCREEN ECHO
;	WAITS UNTIL ANY KEY PRESSED
;	EXIT:	A = CHARACTER TYPED
GETD	CALL	CONSIO
	JR	Z,GETD		;Z = NO INPUT
	RET

;DIRECT I/O INPUT
;	EXIT:	Z FLAG SET IF NO INPUT
CONSIO	PUSH	BC
	PUSH	DE
	PUSH	HL
	LD	E,0FFH
	LD	C,DIRIOF
	CALL	BDOS
	OR	A		;SET FLAGS
	POP	HL
	POP	DE
	POP	BC
	RET

*MESSAGES

MINE	DB	CR,LF,LF,LF,LF,LF,TAB,TAB,'*** LOOKUP3 ***',CR,LF,LF,ESC,')'
	DB	'Copyright 1987 Jim Schenkel, Seamless Web Software'
	DB	CR,LF,TAB,'Revision date: March 6, 1987',ESC,'('
	DB	CR,'$'
NOFILE	DB	BEL,CR,LF,TAB,'+++Cannot find the data file+++',CR,LF,'$'
OVRFLW	DB	BEL,CR,LF,LF,TAB,'    +++File overflow+++',CR,LF
	DB	TAB,'Data file has been truncated',CR,LF,'$'
PROMPT	DB	CR,LF,LF,ESC,DIM,'--> ',ESC,BRITE,'$'
EPROMPT	DB	CR,LF,LF,ESC,DIM,'==> ',ESC,BRITE,'$'
CLRPMT	DB	CR,UP,UP,'$'
CLRLIN	DB	CR,ESC,BLANK,'$'

*BUFFER SPACE

;READ BUFFER--MX,CX AND STRING MUST BE IN THIS ORDER
MX	DB	MAXLEN	;MAX LENGTH OF INPUT STRING
CX	DB	0	;RESERVED FOR ACTUAL LENGTH
STRING	EQU	$	;INPUT STRING GOES HERE

BUFFER	EQU	$+MAXLEN	;BEGIN DATA BUFFER HERE

	END
