<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">;REMSCRN.ASM
;
;WRITTEN 2/28/86 BY JOHN GOTSCHALL
;
;
;
;
;    GENERIC SCREEN CONTROL STRING FILTER
;    REPLACES OUTBOUND SCREEN COMMAND STRINGS WITH
;    STRINGS THAT PERFORM IDENTICLE FUNCTIONS ON A
;    REMOTE CONSOLE,  THIS PROGRAM WAS DEVELOPED FOR
;    USE IN AN APPLICATION WHERE A BUSINESS HAD A CP/M
;    MACHINE RUNNING DBASE II, THEY DID NOT WANT TO 
;    GET A MULTI-USER MACHINE, BUT THEY DID WANT
;    SIMULTANEOUS I/O TO A REMOTE HAZELTINE 1500, SO
;    THAT WHEN ONE TERMINAL WAS NOT IN USE THE OTHER COULD
;    BE USED, VERY SIMILAR IN FUNCTION TO A BYE PROGRAM,
;    WITH THE EXCEPTION THAT THERE WAS NO MODEM INVOLVED.
;    THE REMOTE IN THIS CASE HAD A DIFFERENT SET OF SCREEN COMMAND
;    SEQUENCES THAN THE LOCAL, NECESSITATING CONVERSION
;    OF THE LOCAL'S NATIVE COMMAND STRINGS INTO THE REMOTES
;    NATIVE TONGUE.  THIS MODULE PERFORMS THAT FUNCTION,
;    RATHER NICELY.  
;
;    I WROTE THIS LITTLE THING, AND AS IT IS MY VERY FIRST
;    100% SUCCESSFUL ASSEMBLY PROGRAM WITH PRACTICAL APPLICATION,
;    I HAVE MADE IT AVAILABLE TO THE GENERAL PUBLIC AND THUS
;    MAY BE USED BY ANY PERSON FOR NON-PROFIT USE.  IF YOU 
;    DO USE IT FOR PROFIT, YOU OWE ME ONE U.S. DOLLAR FOR
;    EVERY PERSON THAT USES IT. (PRETTY CHEAP HUH?, THAT'S NOT
;    ASKING A HECK OF A LOT.)
;
;    IF YOU OWE ME A BUCK SEND IT TO:
;
;     JOHN GOTSCHALL
;     PO BOX 2475
;     SEATTLE  WA  98111
;
;     ANYWAY, IMPLEMENTATION OF THIS CODE SHOULD BE PRETTY
;     OBVIOUS, JUST PATCH THE FIRST TABLE WITH THE VALUES
;     FOR YOUR LOCAL TERMINAL, THEN PLACE THE APPROPRIATE
;     REPLACEMENT VALUES INTO THE SECOND TABLE, WHEN OUTPUTTING
;     TO THE REMOTE, IF THE STRING THAT APPEARS IN THE FIRST
;     FOUR BYTES OF THE FIRST TABLE GETS SENT TO THE LOCAL,
;     THE CONTENTS OF THE FIRST FOUR BYTES OF THE SECOND
;     TABLE WILL BE SENT TO THE REMOTE IN PLACE OF WHAT WAS SENT
;     TO THE LOCAL.  IF YOU ARE USING A BYE PROGRAM, ALL YOU
;     NEED TO DO IS ADD THIS CODE TO YOUR BYE PROGRAM SOURCE
;     CODE (MAKING SURE TO FIX ANY DUPLICATED LABELS), THEN HAVE
;     YOUR BBS PROGRAM POKE THE VALUES FOR THE REMOTE'S
;     COMMAND STRINGS INTO THE SECOND TABLE, THEN YOUR BYE
;     MERGED WITH THIS PROGRAM WILL TAKE CARE OF MAKING
;     SURE THE REMOTE GETS SCREEN CONTROL SEQUENCES THAT IT CAN
;     UNDERSTAND, YET YOUR BBS PROGRAM NEED NOT DO ANYMORE
;     THAN PRETEND THAT YOUR LOCAL AND THE REMOTE HAVE THE
;     SAME SCREEN COMMAND SET.  WORKS PERFECT WITH THE
;     BUILT IN COMMANDS LIKE IN DBASE II AND TURBO PASCAL,
;     IT EVEN WORKED PERFECT WITH WORDSTAR IN MY APPLICATION.
;     WELL, IF YOU HAVE READ ALL OF THIS, I CERTAINLY HOPE YOU
;     CAN MAKE USE OF THIS PROGRAM, AS YOU ALREADY HAVE SOME
;     TIME INTO IT.
;
;     BE FORWARNED, WHILE THIS CODE NEVER USES A STACK,
;     IT WILL, WITHOUT A DOUBT DESTROY THE CONTENTS OF
;     THE CPU REGISTERS, SO SAVE ANYTHING YOU WANT TO KEEP
;     BEFORE CALLING THIS SUBROUTINE!!!!!
;
;     DELIVER OUTBOUND CHARACTERS TO THIS ROUTINE IN BOTH
;     THE A AND C REGISTERS !!
;
;
;=======================================================
;The following section of code filters the output to the remote,
;checking for the presence of screen command sequences, and when
;encountered, replaces the strings that are native to the local
;with strings that are native to the remote.  This is done
;through the use of two look-up tables.  The first of the two
;tables contains all of the sequences that are expected to be
;sent out, and are in code that is native to the local screen.
;the second table is where we patch in the corresponding strings,
;but there they are the strings that the remote will recognize
;as they are native to the remote.  
;=======================================================
;
;******************************************************
;There are many calls to a routine labeled 'REMOUT',
;you will not find remout in this listing, whenever this
;code calls remout, it thinks that it is delivering a 
;single character to the remote...  all waiting for status
;for the remote must take place in remout, your version
;of bye should already have a routine to output characters
;to the remote.....  THAT routine is the one that this code
;refers to when it calls remout.  The character to be sent to the
;renote from this code will be found in the C register whenever remout
;is called.
;********************************************************
;
;
;THE FOLLOWING TWO TABLES ARE 60 BYTES LONG, THEY ARE
;ORGANIZED SO THERE ARE 15 STRINGS OF 4 BYTES.  THE FIRST
;TABLE IS SCANNED PRIOR TO ANY OUTPUT TO THE REMOTE, IF
;THE CURRENT OUTBOUND CHARACTER MATCHES ANY OF THE CHARACTERS
;IN THE FIRST POSITIONS OF THE FIRST TABLE, THE CHARACTER IS
;BUFFERED, WHEN THE NEXT CHARACTER COMES THROUGH, A TEST IS
;MADE TO FIND ANY WHOLE MATCHING STRINGS, IF THERE IS A 
;POSSIBILITY OF A MATCH ON THE THIRD CHARACTER, THE SECOND
;CHARACTER IS BUFFERED, AND THE ROUTINE WAITS UNTIL THE
;THIRD CHARACTER COMES THROUGH, IT THEN TESTS TO SEE IF
;THERE IS A POSSIBILITY OF A COMPLETE MATCH.  ON CHARACTERS
;2, AND 3, CHECKS ARE MADE FOR BOTH PENDING MATCHES, AND
;COMPLETE MATCHES, ANY COMPLETE MATCHES WIN AND ARE IMMEDIATLY
;CONVERTED TO THE REMOTE'S COMMAND SET, AND ARE IMMEDIATLY SENT OUT
;TO THE REMOTE.
;
;IF THERE IS A MATCH IN ANY OF THE STRINGS IN THE FIRST TABLE
;THE STRING IS REPLACED WITH THE CONTENTS OF THE SAME POSITIONS
;IN THE SECOND TABLE...  ANY STRINGS MAY BE PUT IN ANY LOCATIONS,
;WITH THE EXCEPTION THAT THE LAST STRING OF 4 IN EACH TABLE IS
;RESERVED FOR THE CURSOR POSITIONING LEAD IN STRINGS, THE
;FOLLOWING THREE BYTES ARE FOR THE X AND Y COORDINATES AND
;THERE IS A FLAG THAT DENOTES WHICH COORDINATE COMES FIRST.
;
;THE MAXIMUM LENGTH FOR ANY COMMAND STRING IS FOUR BYTES!
;
INSTNG	EQU	$+OFFSET
	DB	01BH,045H,01BH,048H	;CLEAR AND HOME CURSOR		
	DB	01BH,05AH,0,0		;CLEAR TO EOL
	DB	01BH,04AH,0,0		;CLEAR TO EOS
	DB	27,69,0,0		;ANOTHER STRING THAT IS CL &amp; HME
	DB	01BH,048H,01BH,045H	;YET ANOTHER CL &amp; HOME STRING
	DB	01BH,'K',0,0		;IF LESS THAN 4 BYTES LONG,           
	DB	0,0,0,0                 ;LEAVE 0'S TO FILL THE EXTRAS,        
	DB	0,0,0,0                 ;THE ZEROS WON'T BE SENT OUT          
	DB	0,0,0,0
	DB	0,0,0,0
	DB	0,0,0,0
	DB	0,0,0,0
	DB	0,0,0,0
	DB	0,0,0,0
	DB	27,70,0,0	;**LEAD-IN** CHARACTERS FOR THE
				;LOCAL CONSOLE'S CURSOR POSITIONING
				;STRING, IF LESS THAN 4 BYTES LONG,
				;LEAVE A '0' TO FILL THE EXTRAS
;
ICCC	EQU	$+OFFSET
	DB	2  	;WHICH COORDINATE CARRIES THE COLUMN DATA?
			;THE FIRST OR THE SECOND
;
ICCO	EQU	$+OFFSET
	DB	32	;VALUE OF COLUMN OFFSET FOR LOCAL
;
ICRO	EQU	$+OFFSET
	DB	32	;VALUE OF ROW OFFSET FOR LOCAL
;
;
OUTSTNG	EQU	$+OFFSET
	DB	07EH,01CH,0A0H,0	;REPLACEMENT COMMAND STRINGS
	DB	07EH,0FH,0,0		;THAT ARE TO BE INSERTED IN THE
	DB	07EH,018H,0,0		;DATA FLOW TO THE REMOTE IN
	DB	07EH,01CH,0A0H,0	;IN PLACE OF THE COMMAND STRINGS
	DB	07EH,01CH,0A0H,0	;FOUND IN THE ABOVE TABLE.  THE
	DB	07EH,0FH,0,0		;STRINGS IN THE TABLE ABOVE MUST
	DB	0,0,0,0			;MATCH THE STRINGS THAT WILL BE
	DB	0,0,0,0			;SENT TO THE LOCAL CONSOLE, WHILE
	DB	0,0,0,0			;THESE MUST CARRY THE STRINGS FOR
	DB	0,0,0,0			;THE SAME FUNCTIONS, BUT IN THE 
	DB	0,0,0,0			;REMOTE'S NATIVE TONGUE.
	DB	0,0,0,0			;IF LESS THAN 4 BYTES LONG,   
	DB	0,0,0,0                 ;LEAVE 0'S TO FILL THE EXTRAS,        
	DB	0,0,0,0                 ;THE ZEROS WON'T BE SENT OUT          
	DB	07EH,011H,0,0	;**LEAD-IN** CHARACTERS FOR THE
				;REMOTE CONSOLE'S CURSOR POSITIONING
				;STRING, IF LESS THAN 4 BYTES LONG,
				;LEAVE 0'S TO FILL THE EXTRAS,
;				;THE ZEROS WON'T BE SENT OUT          
;
OCCC	EQU	$+OFFSET
	DB	1 	;POSITION IN CURSOR POSITIONING
			;STRING THAT CARRIES THE COLUMN
			;FOR REMOTE
;
OCCO	EQU	$+OFFSET
	DB	0	;VALUE OF COLUMN OFFSET FOR REMOTE
;
OCRO	EQU	$+OFFSET
	DB	0	;VALUE OF ROW OFFSET FOR REMOTE
;
;
;MOVE (HL) TO (DE) LENGTH IN (B)
;
;THE FOLLOWING IS COMMENTED OUT, THIS ROUTINE IS DUPLICATED EXACTLY
;IN MY VERSION OF BYE.COM, SO I DON'T NEED THIS AGAIN, BUT IF YOUR
;VERSION OF BYE.COM DOES NOT HAVE THIS ROUTINE IN IT, USE THIS ONE
;OR IF YOU MAKE AN OVERLAY OF THIS FILE YOU WILL NEED IT
;
;
;MOVE	EQU	$+OFFSET
;	MOV	A,M	;GET A BYTE
;	STAX	D	;PUT IT IN NEW HOME
;	INX	D	;BUMP POINTERS
;	INX	H
;	DCR	B	;DEC BYTE COUNT
;	JNZ	MOVE	;IF MORE, DO IT
;	RET		;IF NOT, RETURN
;
;**************************************************
;**************************************************
;*  MAIN PROGRAM SECTION, THIS IS THE PART THAT   *
;*  DOES ALL THE FILTERING OF CURSOR COMMAND      *
;*  SEQUENCES.......                              *
;**************************************************
;
;
;the call to vconout below calls the routine that is already
;in my version of bye.  I replaced the call for vconout in
;my version of bye with a call for 'OUTPUT' below, so that the
;program comes here just prior to outputing to the local.
;
OUTPUT	EQU	$+OFFSET
	CALL	STRT		;STORE CHAR IN FIRST EMPTY BUFFER LOC
	CALL	VCONOUT		;SEND IT TO THE LOCAL
;
MT1	EQU	$+OFFSET
	LDA	CLCF		;POINT TO CURSOR LOCATION COMMAND FLG
	CPI	1		;ARE WE AWAITING A CURSOR COMMAND?
	JZ	CPF		;YES, GOTO CURSOR POS.FILTER
MT2	EQU	$+OFFSET
 	LDA	MTSTR		;POINT TO MATCHSTRING
	CPI	01H		;IS IT A 1?
	JZ	MMF		;THERE WAS A PRIVIOUS MATCH, AND NOT A CURSOR
				;COMMAND, SO
				;LETS TAKE THIS CHAR TO THE MAIN
				;MATCH FINDER
MT3	EQU	$+OFFSET
	JMP	QCHK		;NOTHING MATCHED LAST TIME
				;WE OUTPUTTED, AND WER'E NOT LOOKIN
				;FOR A CURSOR COORDINATE, SO LET'S JUST
				;QUICKLY SCAN FOR A FIRST
				;CHAR MATCH
;
QCHK	EQU	$+OFFSET
	LXI	H,BUFLOC	;GET THE ADDRESS OF THE BUFFER
	SHLD	BUFPTR		;PUT IT IN THE BUFFERPOINTER
	LXI	H,INSTNG	;GET THE ADDRESS OF INSTING
	SHLD	INSPTR		;PUT IT IN THE POINTER
	MOV	B,C		;SAVE THE CHAR IN B
	MVI	A,0
	STA	COUNT
	STA	COUNT1
	LXI	H,INSTNG	;POINT TO THE BEGINNING OF THE INSTING
QCHCK1	EQU	$+OFFSET
	MOV	A,M		;GET THE CONTENTS
	CMP	C		;IS IT THE SAME AS OUR CHAR?
	JZ	ST1MT		;IT'S A MATCH
QCHK2	EQU	$+OFFSET
	INX	H	;BUMP
	INX	H	;UP TO THE
	INX	H	;BEGINNING OF THE NEXT
	INX	H	;STRING OF FOUR BYTES
	LDA	COUNT
	INR	A
	STA	COUNT	;KEEP TRACK OF WHICH GROUP OF FOUR WERE' ON
	CPI	0FH	;PAST 15 YET?, IF SO, THEN THERE IS NO POSSIBLE
	JZ	DONE	;MATCH SO GO DUMP THE CHARACTER FROM THE BUFFER
	JMP	QCHCK1
ST1MT	EQU	$+OFFSET
	LXI	H,MTSTR	;THERE IS A MATCH IN ONE OF THE FIRST
	MVI	A,1	;POSITIONS OF THE INSTRING LINES
	MOV	M,A	;LEAVE NOTE OF THIS IN THE MTSTR GROUP.
	RET		;TO CP/M, WE'LL SEND OUT THIS CHAR LATER..
;
;
;###########################
;
; MMF (MAIN MATCH FINDER,
;  ROUTINE CHECKS ENTIRE INSTRING, COMPARES TO THE CONTENTS OF THE
;  BUFFER TO THE INSTNG TABLE, MAKES NOTATION TO SHOW POSSIBLE
;  PENDING MATCHES, OR PARTIAL BUT IMPOSSIBLE MATCHES, AND MAKES
;  THE FINAL DECISION ON WHETHER OR NOT THERE IS A MATCH OF
;  AN ENTIRE STRING.
;
;
;
MMF	EQU 	$+OFFSET
	LXI	H,INSTNG	;GET ADDRESS OF INSTNG INTO (D,E)
	SHLD	INSPTR		;RESET POINTER
	LXI	H,BUFLOC	;POINT TO FIRST BUFFER POSITION
	SHLD	BUFPTR		;RESET BUFPTR
	MVI	A,0		;GET A 0
	STA	POSMTCH		;RESET POSSIBLE MATCH FLAG
	STA	COUNT		;RESET COUNT FLAG
	STA	COUNT1
ENT	EQU	$+OFFSET
	LDA	COUNT1		;REACHED END OF INSTNG?
	CPI	15	
	JZ	ANT1		;YEP...GO AND CHECK FOR A PENDING MATCH...
				;IT MAY BE THAT WE NEED TO WAIT FOR MORE
				;CHARACTERS TO COME THROUGH...
	LHLD	BUFPTR		;POINT TO THE CURRENT BUFFER ADDRESS
;
;COME INTO ENT1 WITH THE CURRENT BUFFER ADDR IN HL
;
ENT1	EQU	$+OFFSET
	MOV	A,M		;GET VALUE OF CHAR AT BUFFER
	LHLD	INSPTR		;POINT TO TABLE
	CMP	M		;DOES BUFFER CHAR MATCH TABLE CHAR?
	JNZ	ENT7		;NOPE...
ENT2	EQU	$+OFFSET
	LDA	COUNT		;IF WE ARE AT THE FIRST OF 4,
	CPI	0		;COUNT WILL BE 0
	JNZ	ENT6		;NOPE...
ENT3	EQU	$+OFFSET
	MVI	A,1		;SINCE THERE IS A MATCH IN THE
	STA	POSMTCH		;FIRST OF 4 IN THE TABLE, MAKE
				;A NOTE OF IT
ENT4	EQU	$+OFFSET
	LXI	H,MTSTR		;POINT TO MATCHSTRING
	LDA	COUNT		;ALSO MAKE NOTE IN THE MATCHSTRING
	MOV	B,A		;ADD COUNT TO MATCHSTR LOCATION
ENT4A 	EQU	$+OFFSET
	MOV	A,B		;MAKE SURE WE STILL HAVE IT
	CPI	0		;MATCHING LOCATIONS YET?
	JZ	ENT4B 		;YEP
	INX	H		;BUMP POINTER
	DCR	B		;COUNTDOWN
	JMP	ENT4A 
ENT4B 	EQU	$+OFFSET
	MVI	A,1		;GET A ONE
	MOV	M,A		;PUT THE FLAG INTO THE MATCHSTRING
ENT5	EQU	$+OFFSET		
	LDA	COUNT		;CECK TO SEE IF THIS IS THE
	CPI	3		;4TH CHAR IN THE STRING
	JNZ	ENT8		;NOPE, GO DO SOME MORE....
	JMP	WHM		;WE HAVE A FULL MATCH FOR A WHOLE
				;STRING OF FOUR !!!!!!!
ENT6	EQU	$+OFFSET
	LDA	POSMTCH		;IS THERE A POSSIBLE MATCH?
	CPI	1		;
	JZ	ENT4
	JMP	ENT8
ENT7	EQU	$+OFFSET
	LXI	H,POSMTCH	;POINT TO POSMTCH
	MVI	A,0		;GET A 0
	MOV	M,A		;RESET POSMTCH
ENT8	EQU	$+OFFSET
	LHLD	BUFPTR		;GET THE ADDRESS IN THE BUFFER POINTER
	INX	H		;INCREMENT IT
	SHLD	BUFPTR		;PUT IT BACK
	LHLD	INSPTR		;GET THE ADDRESS IN THE INSTRING POINTER
	INX	H		;INCREMENT IT
	SHLD	INSPTR		;PUT IT BACK
	LDA	COUNT		;GET THE COUNT
	INR	A		;INCREMENT IT
	STA	COUNT		;PUT IT BACK
ENT9	EQU	$+OFFSET
	LDA	COUNT		;MAKE SURE WE HAVE THE COUNT
	CPI	4		;PAST THE 4TH CHAR YET?
	JNZ	ENT		;NOPE , GO DO MORE
ENT10	EQU	$+OFFSET
	MVI	A,0		;WE'RE AT HE 4TH, SO
	STA	COUNT		;RESET COUNT
	LDA	COUNT1		;WERE LOOKING AT THE NEXT
	INR	A		;STRING IN THE TABLE, SO
	STA	COUNT1		;MAKE NOTE OF THAT
	LXI 	H,BUFLOC	;ALSO, ON THE NEXT PASS,
	SHLD	BUFPTR		;WE WANT TO POINT TO
				;THE FIRST CHAR IN THE BUFFER
	JMP	ENT
;################################################
;
;END OF MATCH FINDER, IF THERE WAS NO EXACT MATCH,
;WE MAY JUST NOT HAVE ALL THE CHARACTERS YET, SO NOW WE CHECK TO
;SEE IF ANY PARTIAL MATCH IS A POSSIBLE MATCH
;
ANT1	EQU	$+OFFSET
	LXI	H,MTSTR		;POINT TO THE FIRST POS OF MTSTR
	MOV	A,M		;GET THE CONTENTS
	CPI	1		;IS IT A ONE?
	JNZ	DONE		;NOPE, GO EMPTY BUFFER TO REMOTE,
				;THERE IS NO CHANCE OF A MATCH..
ANT2	EQU	$+OFFSET
	INX	H		;POINT TO NEXT LOCATION IN MTSTR
	MOV	A,M		;IS IT A ONE?
	CPI	1		;NOPE, 
	JNZ	BZ		;GO CHECK BUFFER STRING
ANT3	EQU	$+OFFSET
	INX	H		;POINT TO NEXT LOCATION
	MOV	A,M		;GET CONTENTS
	CPI	1	
	JNZ	BZ1		;GO CHECK BUFFER STRING
	JMP	BZ2
BZ	EQU	$+OFFSET
	LXI	H,BUFLOC		;POINT TO BUFFER
	INX	H		;POINT TO 2ND CHAR
	MOV	A,M		;GET THE CHAR
	CPI	0		;IS THE POSITION IN THE BUFFER EMPTY?
	RZ			;YES, THEN RETURN TO CP/M, LEAVE ALL AS IT
                                ;IS, THERE MAY BE MORE CHARACTERS NEEDE TO
				;MAKE A MATCHING STRING
	JMP	DONE		;THERE IS NO POSSIBILITY OF A MATCH,
				;SO GO DUMP THE BUFFER
BZ1	EQU	$+OFFSET
	LXI	H,BUFLOC		;POINT TO THE
	INX	H		;3RD CHAR IN BUFFER
	INX	H		;THERE WE ARE.....
	MOV	A,M		;GET THE CHAR, IS IT EMPTY?
	CPI	0
	RZ			;YEP, SAME AS IN BZ....
	JMP	DONE
BZ2	EQU	$+OFFSET
	LXI	H,BUFLOC	;SAME AS BZ &amp; BZ1,
	INX	H
	INX	H
	INX	H		;BUT CHECK THE LAST CHAR IN BUFFER
	MOV	A,M		;GET THE CHAR..
	CPI	0		;IS THE POSITION EMPTY?
	RZ			;STILL EMPTY,GO TO CP/M AND TO IT AGIN,
	JMP	DONE		;BUFFER IS FULL AND NO MATCHES, SO GO EMPTY
				;THE BUFFER.
;*****************************************
;END OF MAIN MATCH FINDER.....
;****************************************
;   
;
;
;****************************************
;THIS IS WHERE WE GO WHEN WE HAVE A MATCH
;WE NEED TO SEND OUT THE STRING THAT CORRESPONDS TO
;THE STRING THAT MATCHED IN THE TABLE, IF IT WAS THE 
;CURSOR POSITIONING STRING, WE WILL HAVE TO HANDLE THAT HERE ALSO.
;
WHM	EQU	$+OFFSET
	LXI	H,BUFLOC	;POINT TO BUFFER
	XCHG			;MOVE TO DE
WHM1	EQU	$+OFFSET
	LXI	H,COUNT1
	MOV	B,M		;PUT THE VALUE INTO B:
	LXI	H,OUTSTNG	;GET THE ADDRESS OF THE TABLE
WHM2	EQU	$+OFFSET
	MOV	A,B		;PUT B INTO A
	CPI	0		;POINTING TO THE CORRECT SUBSTRING?
	JZ	WHM3		;YEP
	INX	H		;MOVE POINTER UP 
	INX	H		;BYE FOUR, THUS
	INX	H		;POINTING AT
	INX	H		;THE NEXT SUBSTRING IN THE OUTSTNG
	DCR	B		;BUMP B DOWN
	JMP	WHM2		;LOOP SOME MORE
WHM3	EQU	$+OFFSET
	MVI	B,4		;4 BYTES TO MOVE
	CALL	MOVE		;MOVE THE CONTENTS TO THE BUFFER
;******************************
;DONE MOVING THE NEW STRING INTO THE BUFFER, NOW LET'S
;SEE IF IT IS A CURSOR POSITIONING STRING....
;
	LDA	COUNT1		;GET THE TABLE STRING POINTER
	CPI	14		;IS IT A CURSOR COMMAND?
	JNZ	DONE		;NOPE, SO GO EMPTY BUFFER &amp; RESET ALL
	MVI	A,1		;GET A 1
	STA	CLCF		;SET CURSOR COMMAND FLAG TO TRUE
	JMP	DONE		;GO EMPTY THE BUFFER TO THE REMOTE....
;********************************
;SINCE WE JUST SET THE CLCF, WE WILL COME HERE ON
;THE NEXT 2 CONSOLE OUTPUT CALLS....
;OUR VALUE IS IN THE BUFFER, BUT IF THE SECOND BUFFER POSITION
;IS EMPTY, THEN WE NEED ONE MORE CHARACTER...
;ALSO, SINCE ONE OR BOTH OF OUR CURSOR AND ROW VALUES
;MAY BE A 0, WE'LL DUMP THE BUFFER HERE INSTEAD OF USING
;THE 'DONE ' ROUTINE....
;WE ARE COUNTING ON GETTING AN OFFSET OF &gt;0 FROM THE LOCAL
;FOR THE FIRST POSITION...
CPF	EQU	$+OFFSET
	LXI	H,BUFLOC	;POINT TO THE BUFFER'S
	INX	H		;SECOND POSITION
	MOV	A,M		;GET THE CHAR
	CPI	0		;IS THERE A CHAR THERE?
	RZ			;NOPE, GOTO CP/M AND AWAIT ANOTHER
CPF1	EQU	$+OFFSET	;NOW WE HAVE THE TWO CHARACTERS WE WANT
	LXI	H,OCCC  	;POINT TO THE FIRST BUFFER LOCATION
	MOV	B,M		;GET THE VALUE INTO B
	LDA	ICCC		;GET THE OTHER ONE
	CMP	B		;DO THEY MATCH?
	JZ 	CPF2		;YEP,DON'T NEED TO REVERSE THE BUFFER CONTENTS
	LDA	BUFLOC		;GET THE FIRST CHAR
	MOV	B,A		;SAVE IT IN B
	LDA	BUFLOC+1	;GET THE NEXT ONE
	STA	BUFLOC		;PUT IT WHERE THE FIRST ONE WAS
	MOV	A,B		;GET THE ONE THAT WAS THE FIRST
	STA	BUFLOC+1	;AND PUT IT IN THE SECOND POSITION
;
;NOW MODIFY THE X,Y COORDINATE VALUES
;BY STRIPPING THEM OF THEIR ORIGINAL OFFSET(S)
;
CPF2	EQU	$+OFFSET
	LXI	H,ICCO		;POINT TO VAL OF LOCAL OFFSET
	LDA	BUFLOC		;GET THE FIRST CHAR
	SUB	M		;SUBTRACT THE OFFSET
	STA	BUFLOC		;PUT IT BACK
	LXI	H,ICRO		;POINT TO VAL OF 2ND LOCAL OFFSET
	LDA	BUFLOC+1	;GET 2ND VAL FROM BUFFER
	SUB	M		;SUBTRACT THE OFFSET
	STA	BUFLOC	+1	;PUT IT BACK
;
;NOW ADD THE NEW OFFSETS TO THEM
;
CPF3	EQU	$+OFFSET
	LXI	H,OCCO		;POINT TO THE OUTSTNG VALUE
	LDA	BUFLOC		;GET THE VALUE OF THE 1ST CHAR
	ADD	M		;ADD THE NEW OFFSET
	STA	BUFLOC
	LXI	H,OCRO		;POINT TO THE OTHER ONE
	LDA	BUFLOC+1	;GET THE SECOND VAL FROM BUFFER
	ADD	M		;ADD THE NEW OFFSET
	STA	BUFLOC+1	;PUT IT BACK
	LDA	BUFLOC		;GET 1ST CHAR
	MOV	C,A		;PUT IT IN C
	CALL	REMOUT		;SEND IT OUT
	LDA	BUFLOC+1	;GET SECOND
	MOV	C,A		;PUT IT IN C
	CALL	REMOUT		;SEND IT OUT
	MVI	A,0		;NOW KILL THE CHARS IN THE BUFFER
	STA	BUFLOC
	STA	BUFLOC+1
	CALL	DONE2		;USE DONE'S ROUTINES TO CLEAR THINGS
INIT9	EQU	$+OFFSET
	LXI	H,CLCF		;POINT TO THE FIRST OF THE FLAGS AND BUFFERS
	LXI	B,BUFPTR-CLCF	;# OF VARIABLES TO CLEAR
	MVI	A,0		;GET A ZERO
INIT10	EQU	$+OFFSET
	MOV	M,A		;PUT IT IN THE VAR OR FLAG
	DCX	B		;BUMP COUNTER
	MOV	B,A
	CPI	0
	RZ			;ALLDONE, BACK TO CP/M
	INX	H		;POINT TO NEXT BYTE
	MVI	A,0		;GET THE ZERO BACK
	JMP	INIT10
;********************************************
;DONE OUTPUTTING ANYTHING THAT COMES ALONG, CONVERTED AS NECESSARY
;******************************************
;
;COME HERE WITH A NEW CHARACTER, BEFORE OUTPUTING IT TO
;THE LOCAL
;
STRT	EQU	$+OFFSET
	MVI	A,0
	STA	COUNT		;ZERO THE COUNTER
	LXI	H,BUFLOC	;POINT TO THE BUFFER
STRT1	EQU	$+OFFSET
	MOV	A,M		;GET THE CONTENTS
	CPI	0		;IS THERE A 0 THERE?
	JZ	STRT2		;YES, BUFFER IS EMPTY
	LDA	COUNT		;NO? THEN HOW MANY CHAR IN IT?
	INR	A		;LETS LOOK AT THEM AND COUNT
	STA	COUNT		;THE CHARACTERS
	CPI	6		;BETTER NOT BE MORE THAN 6
	JZ	ERRXIT		;OOPS, GOT A PROBLEM
	INX	H		;POINT TO NEXT POSITION
	JMP	STRT1		;MORE CHARS TO CHECK
STRT2	EQU	$+OFFSET
	MOV	M,C		;PUT OUTBOUND CHAR INTO BUFFER
	RET
;**************************************
;
;DONE... THIS IS WERE WE END UP WHEN WE WANT TO DUMP THE BUFFER TO
;        THE REMOTE.....
;
DONE	EQU	$+OFFSET
	MVI	B,0		;SET COUNT TO 0
	LXI	H,BUFLOC	;POINT TO THE BUFFER
DONE1	EQU	$+OFFSET
	MOV	A,M		;GET THE CHAR
	CPI	0		;IS IT A 0?
	JZ	DONE2		;RETURN IF 0
	MOV	C,M		;NOT A 0 SO GET THE CHAR
	CALL	REMOUT		;GO OUTPUT IT
	MVI	A,0
	MOV	M,A		;KILL THE BUFFER CHAR
	INX	H		;POINT TO NEXT CHAR
	JMP	DONE1
DONE2	EQU	$+OFFSET
	LXI	H,POSMTCH	;POINT TO POSMTCH FLAG
	MOV	M,A		;PUT A ZERO THERE
	LXI	H,MTSTR		;POINT TO MATCH STR
	MVI	B,5		;SET COUNT
DONE3	EQU	$+OFFSET
	MOV	M,A		;ZERO THE MTSTR ALSO	
	DCR	B
	CMP	B		;IS B A 0 YET?
	JZ	DONE4		;ALL DONE
	INX	H		;POINT TO NEXT
	MVI	A,0		;GET A 0
	JMP	DONE3		;
DONE4	EQU	$+OFFSET
	RET
;
CLCF	EQU	$+OFFSET
	DB	0
POSMTCH	EQU	$+OFFSET
	DB	0
OSPTR	EQU	$+OFFSET
	DB	0,0
INSPTR	EQU	$+OFFSET
	DB	0,0
MTSTR	EQU	$+OFFSET
	DB	0,0,0,0,0,0
COUNT	EQU	$+OFFSET
	DB	0
COUNT1	EQU	$+OFFSET
	DB	0
BUFLOC	EQU	$+OFFSET	;LOCATION OF OUTBOUND BUFFERED STRING
	DB	0,0,0,0,0,0,0
BUFPTR	EQU	$+OFFSET
	DB	0,0
;==========================================================
;END OF SCREEN COMMAND STRING FILTER SECTION.
;==========================================================</pre></body></html>