 CRCK    COM                  TERM    ALX   =	
         VOLUME51DOC   $            INTRO   DOC     INTRO   DOC  -!"#$%&           USE     DOC   	'(               STAGE2  COM   `)*+,-./01234     ALXTEST ALX   567             CK *.* F	Check all files and make file
		                of results <CRCKLIST.CRC>



$sCRCK ver 4.3 - 24K Buffer - 01/17/81 RBS
CTL-S pauses, CTL-C aborts

 :m 2F¨ CRCKLIST$$$  Check only MYFILE.A+ `
	^**}|N!  "*{z@* K\  <7=Ɓo&  K]  K2h 2| 2DD~$#~#xK	 :F°*}p">d <¨	 è
CANNOT CLOSE CRCFILE$ 

++ABORTED++$	 *)                                                  ALX-    DOC   89:              ALX     S2M   ~;<=>?@ABCDEFGHIJ CIO     ALX   KLMN             TERMSUP ASM   OPQ              MEMORY  INP   R                INTERACTS2M   ST               DEMO    S2M   UV               IOOP    SRC   WXYZ[\]^_`abcdef
CANNOT CLOSE CRCFILE$> CRCKLISTCRC 
DISK FULL: CRCFIL ] 	w#N !I
DONE$!e <ʨ!]  K!e  KsXXXXXXXX.XXX	CRC =  \  <V++OPEN FAILED++$!  "! "*|   \\  ! ~2   *"	+ (
DISK FULL: CRCFILE$  !  "**#"ɯ22! `"!  "  <¨	 (
NO DIR SPACE: CRCFILE$1)ͦp:V++FILE NOT FOUND++$:Ff*}"> <	 CRCK.COM 4.3 01/17/81 RBS!  9")1)̀:]  Y

++NO FILE NAME SPECIFIED++


To use this program:

	COMMANDS:   CRCK [drive:]<filename.filetype> [F]

	Examples:

		CRCK MYFILE.ASM Check only MYFILE.ASM

		CRCK *.ASM	Check all .ASM files

		CR IOOP    SRC                    DISKIO2 SRC   ghijklmnopqrstuv DISKIO2 SRC  w                DISKIO2-DOC   0xyz{|}           IOOP$   SUB   ~               #"?(:\> ͇:\̀èV++FILE READ ERROR++$*|):oX|g}o"e
n0Ç~͇#~t>͇>
_͛ :F{  2h 2| :!\  K:\ 2!\  K\  !\  K\  !\ REV EQU 25H ;	03/19/81  R. CURTISS	FOR NEW ALX STRUCTURES
;REV EQU 24H ;	06/17/79  R. CURTISS	RFOPEN:
;REV EQU 23H ;	06/17/79  R. CURTISS	FINISH RECEIVE FILE CODE
;REV EQU 22H ;	06/14/79  R. CURTISS	SABORT, ETAB
;REV EQU 21H ;	06/14/79  R. CURTISS	FINI
	CALL	CRLF
	RET
;
; -------------------------------------------- HELP
;
HELP:	DB	0DH,0AH,9,'B',9,'SEND BREAK TONE'
	DB	0DH,0AH,9,'E',9,'SEND CONTROL E'
	DB	0DH,0AH,9,'H',9,'HELP - LIST COMMANDS'
	DB	0DH,0AH,9,'Q',9,'QUIT - RETURN TO CP/M'
	DB	0D	; GET DATA
	MOV	E,A
	PUSH	D
	CALL	CO	; OUTPUT TO CONSOLE
	POP	D
	LDA	RLOG
	ORA	A
	IF ( NOT ZERO )	; RLOG = TRUE
	LHLD	MPOINT
	CALL	MEND	; CHECK FOR POINTER AT END OF MEMORY
	WHEN ( NO CARRY )	; NOT AT END
	MOV	M,E
	INX	H
	SHLD	MPOINT
	FIN
	 RETURN TO CP/M
	DB	DREV	; REVISION NUMBER OF DISKIO PACKAGE

	DB	0,0,0
	DB	SREV	; REVISION CODE FOR SUPPORT ROUTINES
;
; -----------------------
;
QUIT:	DS	1	; FLAG SET BY COMMAND TO STOP
SABORT:	DS	1	; FILE SENDING ABORT FLAG
ULTOG:	DS	1	; UPPEN
	( 'E' | 'E'-40H )
	MVI	E,5
	CALL	MO	; SEND CONTROL E
	FIN
	( 'H' )
	LXI	H,HELP
	CALL	MSG	; DISPLAY COMMAND LIST
	FIN
	( 'Q' )
	MVI	A,0FFH
	STA	QUIT	; QUIT = TRUE
	FIN
	( 'O' )  CALL ROPEN
	( 'L' )
	LDA	RFOPEN
	ORA	A
	IF ( NOT ZERO )	; RFILE BUFFER

	LXI	H,MSTART  ; START OF RECEIVE FILE BUFFER
	SHLD	MPOINT	; RECEIVE FILE POINTER

	CALL	SMODE	; INITIALIZE MODEM INTERFACE

	XRA	A
	STA	QUIT	; QUIT = FALSE
	STA	RLOG	; SAVE = FALSE
	CMA
	STA	ULTOG	; UPPER/LOWER SWITCH = TRUE
	REPESH REWRITE
;REV EQU 20H ;	06/13/79  R. CURTISS	ALX REWRITE FROM NORDATA1P
;REV EQU 14H ;	10/24/78  R. CURTISS	CI & CISTAT DIRECT TO BIOS
;REV EQU 13H ;	10/23/78  R. CURTISS	T,U,W   BDOS AND BIOS CI
;REV EQU 12H ;	08/09/78  R. CURTISS    FIX ERRORS
;RESOLE STATUS
	IF ( NOT ZERO )	; DATA READY
	CALL	CI	; GET DATA
	CPI	'E'-40H	; CONTROL E FOR COMMAND MODE
	WHEN ( ZERO )  CALL	CCP
	ELSE
	MOV	E,A
	CALL	MO	; SEND CHARACTER
	FIN
	FIN
	RET
PROCEDURE CCP
	CALL	CRLF	; NEW LINE
	MVI	E,':'
	CALL	CO	;ELSE
	MVI	E,'@'
	MOV	M,E
	CALL	CO	; WARNING FULL
	FIN
	FIN
	FIN
	RET
PROCEDURE MEND
	LDA	MEMEND+1
	SUB	H
	RC		; RETURN IF FULL
	RNZ		; RETURN IF NOT FULL CY=0

	LDA	MEMEND
	SUB	L	; CY=1 IF FULL
	RET
PROCEDURE CONCHK
	CALL	CISTAT	; GET CONR/LOWER CASE SWITCH FLAG
RFOPEN:	DS	1	; RECEIVE FILE OPEN FLAG
RLOG:	DS	1	; RECEIVE DATA SAVE FLAG
MSTART	EQU	1000H	; START OF RLOG AREA
POINT:	DS	2	; TEMPORARY POINTER FOR WRITE TO DISK
MPOINT:	DS	2	; POINTER FOR RLOG STORAGE
MEMEND:	DS	2	; POINTER ECEIVE FILE OPEN
	MVI	A,0FFH
	STA	RLOG	; RLOG = TRUE
	FIN
	FIN
	( 'N' )
	XRA	A
	STA	RLOG	; RLOG = FALSE
	FIN
	( 'C' )  CALL RCLOSE
	( 'S' )  CALL SEND
	( 'U' )
	LDA	ULTOG
	CMA
	STA	ULTOG
	FIN
	( OTHERWISE )
	MVI	E,'?'
	CALL	CO
	FIN
	FINAT
	CALL	RCVCHK	; CHECK FOR RECEIVE DATA
	CALL	CONCHK	; CHECK FOR CONSOLE DATA
	LDA	QUIT
	ORA	A
	UNTIL ( NOT ZERO )	; QUIT = TRUE
	JMP	EXIT	; RETURN TO CP/M
PROCEDURE RCVCHK
	CALL	MISTAT	; GET RECEIVE STATUS
	IF ( NOT ZERO )	; DATA READY
	CALL	MIV EQU 11H ;	08/09/78  R. CURTISS    MORE CODE
;REV EQU 10H ;	07/26/78  R. CURTISS	INITIAL CODING
;
;
; NORDATA TERMINAL PROGRAM WITH FILE TRANSFER (SEND AND RECEIVE)
;
;
	ORG	100H

	JMP	START
	DB	REV	; REVISION NUMBER IN CODE

EXIT:	JMP	0000H	; PROMPT TO CONSOLE

	CALL	CIE	; GET COMMAND CHARACTER FROM CONSOLE
	PUSH	PSW
	CALL	BLK	; SPACE TO CONSOLE
	POP	PSW
	SELECT
	( 'B' )
	CALL	BRK	; SEND BREAK TONE
	MVI	A,10
	CALL	DELAY	; DELAY FOR 1 SEC
	CALL	SMODE	; INITIALIZE MODEM INTERFACE
	FIRITE ACCESS CODE  DELETE OLD FILE

ACCE:	DB	1	; READ ACCESS CODE
FTAB:	DB	0,0,0,'R'
	DS	33	; FILE CONTROL BLOCK
	DS	128	; DATA BUFFER

	DS	40	; STACK SPACE
STACK:
PROCEDURE START
	LXI	SP,STACK
	LHLD	BDOS+1
	DCR	H
	SHLD	MEMEND	; END OF RECEIVE TO END OF RLOG AREA

BUFSIZ	EQU	20	; CONSOLE READ BUFFER SIZE
CBUFF:	DB	BUFSIZ	; BUFFER MAX SIZE
	DB	0	; CURRENT SIZE
	DS	BUFSIZ	; CONSOLE BUFFER

TAB:	DB	0	; TAB COLUMN COUNTER

XDATA:	DS	1	; TEMPORY STORAGE FOR READ/WRITE DATA

WACCE:	DB	3	; WH,0AH,9,'O',9,'OPEN RECEIVE FILE'
	DB	0DH,0AH,9,'L',9,'LOG RECEIVE DATA'
	DB	0DH,0AH,9,'N',9,'NO LOG RECEIVE DATA'
	DB	0DH,0AH,9,'C',9,'CLOSE RECEIVE FILE'
	DB	0DH,0AH,9,'S',9,'SEND FILE'
	DB	0DH,0AH,9,'U',9,'UPPER/LOWER CASE SWITCH'
	DB	0 ; END OF M GET CHARACTER AND IGNORE
	FIN
	FIN
	FIN
	RET
PROCEDURE HCHECK
	CALL	MISTAT	; CHECK RECEIVE STATUS
	IF ( NOT ZERO )	; DATA READY
	CALL	MI	; GET CHARACTER
	CPI	'S'-40H	; X-OFF
	WHEN ( ZERO )
	CALL	MI	; WAIT FOR ANOTHER RECEIVE CHARACTER
	CPI	'Q'ELETE
	( OTHERWISE )
	CPI	20H
	IF ( CARRY )	; CONTROL CHARACTER
	PUSH	PSW
	MVI	E,'^'
	CALL	MOUT	; SEND UP ARROW
	POP	PSW
	ADI	40H	; CHANGE TO NON CONTROL
	MOV	E,A
	FIN
	CALL	MOUT	; SEND CHARACTER
	CALL	CTAB	; TAKE CARE OF COUNTER FOR TAB EXPANSB	D
	BREAK IF ( NO CARRY )  ; POINT >= MPOINT      done
	MOV	A,M
	STA	XDATA
	INX	H
	SHLD	POINT
	LXI	H,FTAB
	LXI	D,XDATA
	CALL	BWRITE	; WRITE NEXT BYTE TO DISK
	ORA	A
	BREAK IF ( NOT ZERO )  ; WRITE ERROR
	FIN
	LXI	H,FTAB
	CALL	DCLOSE

	XRA	ACHECK	; CHECK HOST FOR DATA OR PAUSE (X-OFF)
	CALL	MOSTAT	; CHECK MODEM OUT STATUS
	UNTIL ( NOT ZERO )  ; SEND READY
	POP	D
	CALL	MO	; SEND THE CHARACTER
	RET
PROCEDURE KCHECK
	CALL	CISTAT	; CHECK CONSOLE STATUS
	IF ( NOT ZERO )  ; DATA READY
	CALESSAGE
PROCEDURE SEND
	LXI	B,ACCE
	CALL	OPENF	; OPEN FILE FOR READ
	IF ( ZERO )	; NO OPEN ERROR
	XRA	A
	STA	SABORT	; SEND ABORT = FALSE
	STA	TAB	; INIT TAB COLUMN COUNTER

	CALL	SREAD	; READ FIRST CHARACTER FROM FILE
	WHILE ( ZERO )	; NO ERROR OR	OPENF	; OPEN FILE FOR WRITE
	RNZ		; RETURN IF ERROR

	MVI	A,0FFH
	STA	RFOPEN	; RECEIVE FILE OPEN = TRUE
	STA	RLOG	; RLOG = TRUE

	LXI	H,MSTART  ; START OF RECEIVE FILE BUFFER
	SHLD	MPOINT	; RECEIVE FILE BUFFER POINTER
	RET
PROCEDURE RCLOSE
	LXI-40H	; X-ON
	WHILE ( NOT ZERO )  ; NOT X-ON
	MOV	E,A
	CALL	CO	; DISPLAY CHARACTER
	CALL	MI	; WAIT FOR NEXT CHARACTER
	CPI	'Q'-40H	; X-ON
	FIN
	FIN
	ELSE
	MOV	E,A
	CALL	CO	; DISPLAY CHARACTER
	FIN
	FIN
	RET
PROCEDURE ROPEN
	LXI	B,WACCE
	CALLION
	FIN
	FIN
	CALL	SREAD	; READ NEXT CHARACTER FROM FILE
	FIN
	MVI	A,10
	CALL	DELAY	; DELAY FOR 1 SECOND
	LXI	H,FTAB
	CALL	DCLOSE	; CLOSE FILE

	MVI	E,1AH
	CALL	MOUT	; SEND CONTROL Z
	FIN
	RET
PROCEDURE ETAB
	LDA	TAB
	DCR	A
	ANI	7
	INR	A
	STA	RFOPEN	; RECEIVE FILE OPEN = FALSE
	STA	RLOG	; RLOG = FALSE
	RET
;
;
END-OF-FILE
	CALL	BWRITE	; WRITE NEXT BYTE TO DISK
	ORA	A
	BREAK IF ( NOT ZERO )  ; WRITE ERROR
	FIN
	LXI	H,FTAB
	CALL	DCLOSE

	XRA	AL	CI	; GET KEYBOARD CHARACTER
	SELECT
	( 1AH )
	MVI	A,0FFH
	STA	SABORT	; SEND ABORT = TRUE
	FIN
	( 'S'-40H )
	REPEAT
	CALL	HCHECK	; CHECK FOR INCOMING DATA
	CALL	CISTAT	; CHECK CONSOLE STATUS
	UNTIL ( NOT ZERO )  ; ANY KEY TO CONTINUE
	CALL	CI	; EOF
	LDA	XDATA	; GET CHARACTER
	ANI	7FH
	MOV	E,A
	SELECT
	( 9 )	CALL	ETAB	; EXPAND TAB
	( 0DH )			; CARRIAGE RETURN
	CALL	MOUT	; SEND CARRIAGE RETURN
	XRA	A
	STA	TAB	; INITIAL TAB COLUMN COUNTER
	FIN
	( 0 | 0AH | 7FH )  NOP	; IGNORE NULL, LF, D	H,MSTART
	SHLD	POINT

	LDA	RFOPEN
	ORA	A
	RZ		; RETURN IF RECEIVE FILE NOT OPEN

	LOOP
	LHLD	MPOINT
	XCHG		; DE = MPOINT   end of received data storage
	LHLD	POINT	; HL = POINT    temp pointer for writing to disk
	MOV	A,L
	SUB	E
	MOV	A,H
	SBB
	LXI	D,XDATA
	CALL	BREAD	; READ NEXT BYTE
	ORA	A
	IF ( ZERO )	; NO ERROR OR EOF
	LDA	XDATA
	SUI	'Z'-40H	; CONTROL Z
	SUI	1
	SBB	A
	FIN
	FIN
	RET
PROCEDURE MOUT
	PUSH	D
	REPEAT
	CALL	KCHECK	; CHECK KEYBOARD FOR ABORT OR LOCAL PAUSE
	CALL	H
	MOV	D,A
	MVI	E,' '
	REPEAT
	PUSH	D
	CALL	MOUT	; SEND SPACE
	POP	D
	DCR	D
	UNTIL ( ZERO )
	XRA	A
	STA	TAB
	RET
PROCEDURE CTAB
	LDA	TAB
	DCR	A
	ANI	7
	STA	TAB
	RET
PROCEDURE SREAD
	LDA	SABORT
	ORA	A
	IF ( ZERO )	; NOT ABORT
	LXI	H,FTASTAGE2 IS:

	STAGE2 is a versatile macro processor developed by William
	M. Waite.  Operating on a generalized pattern recognition principle,
	it can be used for language translation, textual data filtering,
	limited printer output formatting, batch fis is to be used
			while reading the INTRO.DOC file.

IMPLEMENTATION FILES:

	IOOP.SRC	Initialization and input/output package

	DISKIO2.SRC	General CP/M disk input/output package
	DISKIO2-.DOC	Documentation for above

	IOOP$.SUB	Submit file for		8 bits (only two used)

	Since the value field is sometimes used to hold string length, strings
	are limited to 255 characters maximum.  Under some circumstances the
	value field is considered to be signed so that strings longer than
	127 charactersome applications are an order of magnitude simpler to implement
	with STAGE2 than with conventional algorithmic languages.

WEAK POINTS:

	A bit slow
	Uses lots of memory for large applications (language translation)
	Macro code is very cryptic in aS:

	ALX.S2M		Assembly Language eXtension translator macros
	ALX-.DOC	Notes on ALX.MAC

	ALXTEST.ALX	Test case for the ALX macros
	TERM.ALX	Sample program (incomplete)
	VDB.ALX		TDL video display driver for H19 emulation
	CIO.ALX		CP/M console I/O iage return terminates
			Line feeds are ignored
			Nulls are ignored
			Deletes are ignored

		Output lines
			Carriage return and line feed on every line

	Channel 5 implemented for console input and output

IMPLEMENTATION LIMITATIONS:

	STAGile editing and other text
	processing applications.

FEATURES:

	Pattern matching
	Symbol table (storage and retrieval under user control)
	Symbol generator
	Integer arithmetic
	Arithmetic expression evaluator
	Scan controlled iteration (search  character stored by STAGE2 takes 1 FLUB word or 4 bytes in this
	implementation.

CP/M VERSION AVAILABILITY:
	CP/M Users' Group
	1651 Third Avenue   
	New York, NY  10028

DISCLAIMER:

	)()!&(%$#"#"%!!$(%!##!(!$!!$=(00(!#=!! so there!
	Use it a may cause strange results, but NOT a crash.  STAGE2 
	seems to be extremely well protected against crashes.

	Since the pointer field is used for arithmetic operations, values are
	limited to the range -32767 to 32767.  -32768 causes trouble.

	Eachppearance

REFERENCES:

	STAGE2 is in the public domain and is documented by the author
	in the book:
		Implementing Software for Non-numeric Applications
		by W. M. Waite
		1973  Prentice Hall

	Chapter 9 and appendix A include STAGE2 user inforwith PMMI modem in "parallel"

	MEMORY.INP	Macros and source for memory demonstration

	INTERACT.S2M	Macros to demonstrate interactive use of STAGE2

	DEMO.S2M	Macros for interactive exercise of most conversions
			and a few processor functions.  ThE2 is modeled on an abstract machine called the FLUB machine.  FLUB
	stands for First Language Under Bootstrap.  The FLUB machine word is
	made up of three fields:
		Pointer field		16 bits in this CP/M implementation
		Value field		8 bits
		Flag fieldfor specific characters)
	Count controlled iteration
	Conditional and unconditional branching (skips)
	I/O channel control
	Limited output formatting
	Recursion
	Error traceback showing all macro calls

STRONG POINTS:

	Highly transportable

	St your own risk.

MORE INFORMATION:

	HELP.DOC	For the STAGE2 novice - start here

	USE.DOC		STAGE2 I/O summary and command line specification

	INTRO.DOC	Introduction to the STAGE2 processor

	IMPL.DOC	STAGE2 implementation notes

EXAMPLE FILEby:
		Dick Curtiss
		843 NW 54th
		Seattle, Washington  98107
		(206) 784-8018
					and is in the public domain.

DEVIATIONS FROM THE VERSION DISTRIBUTED BY WAITE:

	Variable length lines for input and output (132 char max)
		Input lines
			Carrmation, source
	listings and implementation directions.

	STAGE2 is also documented by the author in:
		"Communications of the ACM"
		Volume 13 / Number 7
		July 1970
		Pages 415-421

STAGE2 for CP/M:

	This 8080 implementation was accomplished  creating IOOP.HEX

	FLT1.FLB	FLUB translation test program 1
	FLD1.DAT	Test data for FLT1

	FLT2.FLB	FLUB translation test program 2
	FLD2.DAT	Test data for FLT2

	STG2.FLB	Source program for STAGE2
	ST2T.DAT	Test data for STAGE2

	FLUB8080.S2Mrsive macro call to parse rest of line
	% ------------------------- end of macro
	STATEMENT $;$#		To recognize and split statement with comment
	PROCESS !10%		    macro call to process single statement
	% ------------------------- end of macro
	STATEM macros designed to generate a
	sequence of assembler language instructions which evaluate the
	conditional expression.  Then a "jump if false" instruction would be
	generated to branch to the loop exit label.

	Next, the remainder of the line would bTATEMENT !30%		    macro call to parse remainder of line
		JUMP	LOOP!F13%   output loop jump
	EXIT:!F13%		    output loop exit label
	% ------------------------- end of macro
	CONDITION $<$#		To recognize less than compare
		LOAD	!10!F13%    output loE PROBLEM:
	Suppose it is desired to recognize the following WHILE statement
	and translate it into assembler type language.

		WHILE ( X < Y )  PRINT X*Y : X = X + 1  ; Comment

	A top level macro would be used to recognize the "WHILE" as a keyword.	STAGE2 macros for translating FLUB into 8080 code

	STG2SUP.ASM	Support routines for the FLUB machine

	STG2MATH.ASM	16 bit math routines for the FLUB machine

	FLUB$.SUB	Submit file for assembling FLT1, FLT2 or STG2

branch to the looping label.  Finally, "WHILE"
	statement processing is completed by generating a loop exit label.

EXAMPLE MACRO EXPANSION:
	LOOP:
		LOAD		X
		CMP-LT		Y
		J-FALSE		EXIT

		LOAD		X
		MULTIPLY	Y
		CALL		PRINT-RESULT

		LOAD		X
e passed on to macros designed
	to recursively break apart multiple statement lines and process each
	single statement with still other specialized macros.  After
	decomposition of the "WHILE" statement is complete, a jump instruction
	is generated to 			STAGE2 INTRODUCTION

COPYRIGHT:
	Written:  06/15/79
	Updated:  06/17/79

	This introductory material is the property of:
		Dick Curtiss
		843 NW 54th
		Seattle, Washington  98107

	Permission is granted to copy for personal use only.

	Thisad X instruction
		CMP-LT	!20!F13%    output compare Y instruction
	% ------------------------- end of macro
	STATEMENT $:$#		To recognize and split multiple statement
	PROCESS !10%		    macro call to process single statement
	STATEMENT !20%		    recu
	As part of the recognition process the statement would be broken into
	three parts, "WHILE", "X < Y", and the rest of the line.  The first
	step in the translation process is to generate a looping label.  Next,
	"X < Y" would be passed on to a set of		ADD		#1
		STORE		X

		JUMP		LOOP
	EXIT:

EXAMPLE MACROS:
	WHILE$($)$#		To recognize WHILE statement
	LOOP:!F13%		    output looping label
	CONDITION !20%		    macro call to parse conditional expression
		J-FALSE	EXIT!F13%   output exit jump
	SE2 forces a top down approach to problem solving using stepwise
	refinement and recursive descent.  Expect to read this material
	several times before it sinks in.  The best way to learn STAGE2 is
	to study examples and experiment.  Good luck!

EXAMPL material may NOT be used for publication without written
	permission of the author.

STAGE2 PROGRAMMING TECHNIQUE:
	STAGE2 is unlike conventional languages and requires getting
	used to a different way of approaching a problem.  By its nature,
	STAGENT $#		To recognize single statement
	PROCESS !10%		    macro call to process single statement
	% ------------------------- end of macro
	PROCESS PRINT$#		To recognize and process PRINT statement
		*** macro code not shown
	% ------------------------ersion "0" copies the
	parameter string unchanged to the constructed line.  The
	constructed line can be thought of as a scratch string which is
	empty at the start of a code body line scan.  In summary the
	three characters "!10" instruct STAGE2 to apin the
	example instructs STAGE2 to store parameter string 2 into the
	memory using parameter string 1 for access to memory.  In other words
	the string in parameter 1 is given a value in memory and that value
	is the string in parameter 2.

	Paramet body line end
	character.  An empty code body line (macro terminator) has the
	code body line end character in column 1.  A special escape
	character is used in code body lines for parameter reference
	and invocation of processor functions.

	Charac used to print information stored in the
	memory.

	PRINT MEM[$]#			4. Template line
	!10=!11!F14%			5. Extract info and output
	%				6. End of macro

	The template in line 4 contains 1 parameter flag which
	represents the string which will be usedharacters in the order shown in the
	template line.  The parameter flag characters, "$", will match
	any balanced strings including a null string.  A balanced string
	is one containing equal numbers of left and right bracketing
	characters, usually "("- end of macro
	PROCESS $=$#		To recognize and process assignment stmt.
		*** macro code not shown
	% ------------------------- end of macro

READING MACROS:
	Macros consist of a template line followed by one or more code
	body lines.  The macro is minator.

	Strings for a successful match:
		MEM[25]=TWENTY FIVE#
			Parameter 1 = "25"
			Parameter 2 = "TWENTY FIVE"
			Parameters 3-9 = ""

		MEM[ABC]=HELLO#
			P1 = "ABC"
			P2 = "HELLO"

		MEM[EQUATION]=A=2*(B+C)#
			P1 = "EQUATION"
			Per 1 is the string segment represented by the first "$"
	in the template and parameter 2 is the string segment represented
	by the second "$" in the template.  The maximum number of
	parameters is nine.

	Line 3 is an empty code body line or macro terters in a line following the special end characters are
	taken as comment only.

SPECIAL CHARACTERS:
	#  Template end of line
	$  Template parameter flag
	%  Code body end of line
	!  Code body escape
	(  Left bracket
	)  Right bracket

	These s to access the memory.

	The first escape character in line 5 is followed by a non-zero
	digit, "1", which is taken to be a reference to parameter string
	1.  The digit, "0", following the parameter reference is a
	conversion code (0-8 allowed).  Conv and ")".

	Line 2 contains a processor function request.  The escape
	character "!" folowed by "F" followed by a digit specifies one
	of ten possible functions.  The "F" can actually be any non-
	numeric or special character.  The function "3" shown terminated by an empty code body line.

	Macro templates, which are terminated by a special template end
	character, consist of character strings with special parameter
	flag characters interspersed.

	Code body lines are terminated by a special code2 = "A=2*(B+C)"

		MEM[X=Y]=Z#
			P1 = "X=Y"
			P2 = "Z"

	Strings for a match failure:
		MM[12]="E" MISSING#

		MEM [XYZ]=SPACE AFTER "MEM"#

		MEM[ABC)]=UNBALANCED STRING#

		MEM[ABC]=UNBALANCED (STRING#

MACRO EXAMPLE:
	This macro may bebuilt in memory.

	MEM[$]=$#			1. Template line
	!F3%				2. Store into memory
	%				3. End of macro

	The template in line 1 contains two parameter flags (maximum
	of nine allowed).  For a string to match the template it must
	contain the literal cpecial characters are user selectable on the first line
	of input to STAGE2.  The particular characters shown above were
	arbitrarily chosen for the examples which follow.

MACRO EXAMPLE:
	This macro may be used to store information into the STAGE2
	pend parameter 1 to
	the constructed line.

	The next character in line 5 is a literal "=" which is appended
	to the constructed line.  Next is another escape character
	followed by the digit "1".  This is another reference to
	parameter string 1.  TLANCED STRING#
		MEM[ABC]=UNBALANCED (STRING#
		PRINT MEM[25]#
		PRINT MEM[ABC]#
		PRINT MEM[PDQ]#
		FORMAT MEM[25]#
		FORMAT MEM[ABC]#
		FORMAT MEM[PDQ]#
		END#

		Note:	The "#" shown at the end of the input lines are
			optional in the CP/M immory using parameter 1 for access.

	The output request in line 9 is like that of line 5 except that
	the constructed line is empty (null).  This condition instructs
	STAGE2 to use the following code body line as a formatting
	template which should noifies
	the output function.  The following digit, "4", specifies the
	output channel.  "!F14" causes output of the constructed line to
	channel 4.  When the channel number is ommitted output is to
	channel 3 by default.  Processing of line 5 is now com
		PRINT MEM[$]#			4. Template line
		!10=!11!F14%			5. Extract info and output
		%				6. End of macro
		FORMAT MEM[$]#			7. Template line
		!11!26%				8. Extract info
		!F14%				9. Output
		1111111= 22222222222222222%	10. Format
		%				11. End of ine into the specified parameter.  This also
	results in clearing the constructed line to null.  Processing
	of line 8 is complete as the end of line character comes next.
	It is possible, however, to have more operations appear in that
	same code bodyhis time, however, the conversion digit
	is a "1" which instructs STAGE2 to append information from the
	memory to the constructed line using the specified
	parameter string for access.

	At this point 3 items have been appended to the constructed linding blanks are not suppressed) and blank
	filled or truncated on the right depending on parameter length
	and field width.

	Strings for successful match:
		FORMAT MEM[25]#
			Ch4 = "25     = TWENTY FIVE      "

		FORMAT MEM[ABC]#
			Ch4 = "ABC  t be confused with macro templates.
	Fields of numeric characters refer to corresponding parameter
	strings.  Non-numerics in the formatting template appear in the
	output line as is.  Parameter strings are inserted into the fields
	left justified (leaplete
	and line 6 terminates the macro.

	Strings for successful match:
		PRINT MEM[25]#
			Channel 4 output = "25=TWENTY FIVE"

		PRINT MEM[ABC]#
			Ch4 = "ABC=HELLO"

		PRINT MEM[PDQ]#
			Ch4 = "PDQ="       nothing stored previously

MACRO Emacro
		END#				12. Template line
		!F0%				13. Terminate processing
		%%				14. End of macros
		MEM[25]=TWENTY FIVE#
		MEM[ABC]=HELLO#
		MEM[EQUATION]=A=2*(B+C)#
		MEM[X=Y]=Z#
		MM[12]="E" MISSING#
		MEM [XYZ]=SPACE AFTER "MEM"#
		MEM[ABC)]=UNBA line (i.e. "!11!26 !F14#").  The character after
	the 6 in this alternative is ignored so a space is shown.

	At this point parameter 1 still has the string resulting from
	the template match and parameter 2 contains the string extracted
	from the mee:
	parameter string 1, "=", and a string from the memory.  The
	next character in line 5 is another escape.  This time, however,
	the following character is non-numeric indicating a processor
	function request.  The next character, the digit "1", spec  = HELLO            "

		FORMAT MEM[PDQ]#
			Ch4 = "PDQ    =                  "

EXAMPLE RUN:
	FILE "MEMORY.INP"
		#$%!0 (+-*/)			0. Special character selection
		MEM[$]=$#			1. Template line
		!F3%				2. Store into memory
		%				3. End of macro
	As in line 5, the "!11" in line 8 appends information from the
	memory to the constructed line using parameter 1 for
	access.  Then "!2" is a reference to parameter 2.  The
	following conversion digit, "6", instructs STAGE2 to copy the
	constructed lXAMPLE:
	This macro will also display information stored in the memory
	but formatted into fields.

	FORMAT MEM[$]#			7. Template line
	!11!26%				8. Extract info
	!F14%				9. Output
	1111111= 22222222222222222%	10. Format
	%				11. End of macro
plementation as carriage
			return is sufficient for an end of line condition.
			The special character when used is the same
			terminator used for macro template end of line.  It
			can be used if it is desired to allow comment
			information in theopied into the specified parameter.  The
		scanned string and break character are deleted from the CL.
		Break characters enclosed in brackets will not be recognized as
		the scanned string would not be balanced.  After scanning stops
		code body lines undefined
		symbol is treated as zero.  If null, P1 will be treated as
		zero.  A symbol with a non-numeric value will cause an error
		message and traceback.

	!15	Append LEN(P1) to the CL  ; Append a string of digits to the CL
		to represent the lessions and balanced strings)
	  8	  Addition operator
	  9	  Subtraction operator
	 10	  Multiplication operator
	 11	  Division operator
	 12	  Closing bracket (to match #7)


PARAMETER CONVERSIONS:

	There are a maximum of ten parameters, numbpply new values for the parameter.  The
		original value will will be restored after exit from the loop.

		The CL  is scanned for break characters which are specified
		following the digit "7".  All of the characters up to the end
		of line character) = S1  ; define from symbol generator
			S1 = S1 + 1   ; increment symbol generator
			Append MEM(P1)
			fin
		    ( otherwise )  Append MEM(P1) to the CL
		    fin

	!13	Useful only in conjunction with context-controlled iteration.
		(Described a source input stream.

	COMMAND LINES:
		STAGE2 CH3,CH4=MEMORY.INP
		TYPE CH3
		TYPE CH4

FLAG LINE:
	The first line read by STAGE2 is used to specify the user's special
	symbol selections.

	column	description
	  1	  End of template and sourcewing "!16" will be
		ignored.  If it is the end of code body line character
		processing will continue on the following line.  Otherwise,
		processing will continue with the next character.  When used
		inside of an iteration loop the string placed in ength of the parameter string.  A null string
		results in a single zero digit.

	!16	P1 = CL, CL = null  ; Copies the CL into parameter 1, replacing
		whatever might have been there before.  Also, the CL is
		cleared.  The character immediately folloered 0 through 9.
	Parameter 0 is a special case.
	There are nine possible parameter conversions, numbered 0 through
	8.  Most of this discussion will refer to specific parameters but
	the remarks apply generally to parameters 1 through 9.

	!10	Appe will be used as break characters.  If no
		break characters are specified the CL scan is broken on each
		character.  When a break character or the end of the CL is
		reached scanning stops and the scanned string (excluding the
		break character) is cfter !17)

	!14	Append EVAL(P1)  ; Evaluate the parameter string as an
		arithmetic expression and append a string of digits to the CL
		to represent the result.  Non-numeric items in the expression
		will be taken as symbols for memory reference.  An input lines
	  2	  Template parameter flag
	  3	  End of code body line
	  4	  Escape character for code body (parameter or function ref.)
	  5	  The character for zero
	  6	  Space character for formatted output
	  7	  Open bracket (arithmetic exprthe specified
		parameter is not retained from one iteration to the next or
		after exit from the loop.

	!17	This starts a context controlled iteration loop.  The current
		value of the specified parameter is saved as the iteration
		process will suundefined )  Append null to the CL
		    ( otherwise )  Append MEM(P1) to the CL
		    fin

	!12	Similar to conversion 1 except when P1 is undefined.
		CASE
		    ( P1 = null )  Generate error message and trace back
		    ( P1 undefined )
			MEM(P1nd parameter string 1 to the constructed line.

	!20	Append P2 to the CL.

	!11	Append MEM(P1) to the CL.  Using P1 for access, append the
		value of the symbol to the CL.
		CASE
		    ( P1 = null )  Generate error mesage and trace back
		    ( P1  are expanded within the loop which ends at an
		"!F8".  After all lines within the loop have been processed,
		scanning of the CL continues unless the CL is null.  When the
		CL is null the iteration loop is terminated.

	!F8	Processor function to de51   IF ( P1 <> P2 )  SKIP = EVAL(P3)


	!F6	Set skip counter based on the relative values of 2 arithmetic
		expressions.  The test condition is specified by a character
		following "!F6".

		!F6-   IF ( P1 <  P2 )  SKIP = EVAL(P3)
		!F60   IF ( P1 If P1 is null no
		copying takes place.  Copying continues up to an input line
		whose initial substring matches P1.  The line which matches
		P1 is ignored, copying stops and the input channel is 
		positioned to the line following the matched line. NERATOR:

	!0	Parameter  "0" is a reference to an internal symbol generator.
		Within a given macro expansion up to ten unique symbols
		(actually integers or strings of digits) are available; "!00"
		through "!09".  After the macro expansion is complcounter unconditionally.  The skip counter applies
		to macro code body lines.  The skip feature allows conditional
		expansion of portions of a macro code body.  Parameter string 1
		is evaluated as an arithmetic expression (see conversion 4
		descrips of identical digits.  "22222" is a five
		character field into which parameter string 2 will be inserted,
		left justified with blank fill or truncation on the right as
		required.  A given parameter may be referenced for more than
		one field in thefine the scope of an iteration loop.

	!13	Append BREAK(P1) to the CL  ; The break character is the 
		single character immediately following the specified
		parameter which represents a substring of the line being
		scanned.  When the end of line is 
		    copy to the specified channel
		    fin
		ELSE  copy to channel 3

		5!F2	CI = 5 , out is 3

		2R!F2	CI = 2 , Rewind 2 , out is 3

		!F24	CI unchanged , out is 4

		2!F23R	CI = 2 , out is 3 , Rewind 3 before copy

		In all cases no copy  If no
		match line is found end of file terminates the copy.

		WHEN ( input channel specified )
		    make it the new current input (CI) channel
		    fin
		ELSE  the current input channel number is unchanged

		WHEN ( output channel specified )ete the
		symbol generator is incremented so that future macro expansions
		will get different symbols.

PROCESSOR FUNCTIONS:

	There are eleven processor functions, numbered 0 through 9 and E.
	Some processor functions assume use of specific parametion) and the result is placed in the skip counter.

		SKIP = EVAL(P1)


	!F5	Set skip counter based on string compare for equality.  The
		test condition is specified by a character following "!F5".

		!F50   IF ( P1 == P2 )  SKIP = EVAL(P3)
		!F formatted line.

		!F14	Output the CL to channel 4.
		!F1	Output to channel 3 as default channel.
		!F12R	Output to channel 2 after rewind.

	!F2	Change I/O channels and copy text from the specified input
		channel to the specified output channel. reached, the break
		character is null.

	!18	Append a string of digits to the CL to represent the internal
		storage code for the character in P1.  Unless P1 contains
		exactly one character an error message and traceback will
		result.

SYMBOL GEtakes place if P1 is null.


	!F3	MEM(P1) = P2  ; Using parameter string 1 for access, store
		parameter string 2 into memory. (i.e. the value of P1 is
		defined to be P2).  If P1 is null an error message and
		traceback result.

	!F4	Set the skip  output.  A format line specifies exactly
		the number of characters in the line to be output.  Non-numeric
		characters in the format specification are output exactly as
		they are.  Parameter fields in the format specification are
		denoted by stringters.

	!F0	Terminate processing.

	!F1	Output request.  The output request must appear at the end of
		a code body line.  The CL is output if it is not null.  If it
		is null the following code body line will be used as a format
		specification for == P2 )  SKIP = EVAL(P3)
		!F61   IF ( P1 <> P2 )  SKIP = EVAL(P3)
		!F6+   IF ( P1  > P2 )  SKIP = EVAL(P3)


	!F7	Count-controlled iteration.  The CL is evaluated as an
		arithmetic expression (see conversion 4 description) and the
		resulting vadevices	disk	disk	disk	disk
			CON:		CON:	CON:	CON:
					LST:	LST:
					NUL:	NUL:

	default		error	disk	CON:	LST:	CON:


		channel 2 file name is fixed  STAGE2.CH2
		channel 5 is always the console

		additional device names accepted

			CON: put as can be seen in the above program.  Output, however,
	is under user control through macro body processing.  If STAGE2
	fails to match an input line against a macro template the line
	will be output to channel 3 as is and the processor will go on
r message and traceback.  All macro calls to the
		current level will be output in reverse order to channel 4.
		The last traceback line is the current input line.

-----------------------------------------------------------------------

STAGE2 PROGRt/output	console channel (for interactive use)

	6-9	not implemented   could be made additional scratch
				  and/or punch & reader devices


COMMAND LINE FORMAT:

	[<chan3>[,<chan4>]=]<chan1>[,<chan1>[,<chan1> ... ]]
				concatenation allowed on 
				 structure for the template matching
				 algorithm}

	    INPUT_NEXT_LINE	{gets first source line from input file
				 (channel 1) - this is the first line
				 following the last macro}

	    WHILE  NOT END_OF_FILE  DO

		BEGIN
		MATCH ( Llue is placed in an iteration counter.  The loop,
		which ends at an "!F8", is repeated with the iteration counter
		decremented for each iteration.  The loop terminates when the
		counter reaches zero.

	!F8	Defines the scope of count-controlled loop	to the next input line.
ails to match an input line against a macro template the line
	will be output to channel 3 as is and the processor will go on
AM:
	This is a highly simplified description of the STAGE2 algorithm.

	PROGRAM;

	PROCEDURE MATCH ( STRING );
	    BEGIN

	    attempt to match STRING against macro templates

	    IF  MATCH_SUCCESSFUL  THEN

		FOR  each line of macro code bodchannel 1
	   [ ] optional items

	examples:
		STAGE2 ALXTEST.ASM,LST:=ALX.S2M,ALXTEST.ALX
		STAGE2 TERM.ASM,TERM.LST=ALX.S2M,TERM.ALX
		STAGE2 DEMO.S2M
		STAGE2 CH3,CH4=MEMORY.INP
		STAGE2 INTERACT.S2M


	CHANNEL		  1	  2	  3	  4	  5

	valid INE );	{attempt to match the line against all
				 macro templates}

		INPUT_NEXT_LINE

		END;

	END.


	Except for switching channels or rewinding channels, the STAGE2
	user has no control over input.  The processor has a built in loop
	for ins and context-
		controlled loops.  Loop nesting is permitted.  Skipping out of
		loops is permitted.  Skipping over entire loops is tricky
		business (see Waite's book, page 398).

	!F9	Terminates expansion of the current macro.

	!FE	Force an erroINPUT/OUTPUT CHANNELS:

     channel
	0	output		bit bucket channel

	1	input		normal input channel (macros & text)

	2	input/output	scratch channel

	3	output		default output channel

	4	output		second output channel (usually printer)

	5	inpu-- program starts here ------------ }

	    INPUT_FLAG_LINE	{gets special character definitions from
				 the first line input from channel 1}

	    INPUT_MACROS	{reads macro code bodies into memory from
				 channel 1 and builds templates into treey  DO
		    BEGIN
		    scan code body line and perform operations
		    IF  CONSTRUCTED_LINE <> NULL  THEN
			MATCH ( CONSTRUCTED_LINE );	{note recursive call}
		    END

	    ELSE  output STRING to channel 3

	    END;

	BEGIN	{ --------------= KBD: = TTY: = CRT:

			LST: = LPT:

	Note: Tabs are NOT expanded for the list device (sorry about that).

		channel 2 file name is fixed  STAGE2.CH2
		channel 5 is always the console

		additional device names accepted

			CON: #6  >?=_.,:;<> 3*b  *b%  *b#>w=& o                                                                                                                                                                                                                    2                                                                                                                                                                    3                                    
~#~#
:g=2g"b"|!"e`i^#VNy2#^#V"*b~U#~U#"~l
Y
͗
M
:*w]]*~ͼ
:l

l
l
ʓ
ʕ
>*|w#"|"b"e6~U#~ U#~_<w{

U] *b % ~*ew]I=  *LDF!E^ #!EN#~'wa{ !F=͙P!F""!:"&!?"(s6 #""!F"&,͙m!?"(s6 #"(*"ʖʖ*&*(~ȷʤ#Ù<ʰ:=_ !"^#V>*c~+ O###>:                                    *    STAGE2.CH2 NUL: CON: LST:                                                                                                                                   
>>>>> COMMAND ERROR - REENTER
$ $"b~ U
2d*b 	                                                                                                                                4                                                                                                                               PÜ$Ô ×                                                              1Pbͱ	Pv!_w#j       * %2}"~x2="!d~G:}:x!b~ͫ!d6:}>>x==2b#>w"b~U#~U#
O0GQQ
Q"bG~U#~ U#~_<w # p > ]oU]I=  *b#>w3@G:ʪ6 ìp.¿#6 ¿#6  #~?x#*6?w
=!cqy NULCONTTYCRTKBDLSTLPT~,~=~ #+x_ 
 	                                         3}   1                                                                                                              U:d=5		2d=+	U=U=U=U*b$ 6 	*b:dw#w#w]"b~q	͙	z	z	U]U	*bNw#w#w]=U]##~ /Ɓ6+=¦	o:g!h^#VZ	ñ	:g
	<2g=_ !h*bs#r*b!h:gO
~#G~#	T]͘>!`F++6?X=?=Z=y>*~:ZBK	>+Nm#^R]R
R+Nʌ#^X|X
Xͦ>!d6Z	>ɯ*!c~*~:=_ !~#fo !E: <Ow#6 0==2=!_~!d6!a~2͘ѷ̓yx=R==t=t=!`~!d6!a~t͘ѷ!d6ʒ=ʕ=ʵ>+"+"
ʃ    F
R*~~ʪ:=>*",͙>#""=Z	*"                                                                                                                                                                                                                                                                *l#"l*l"``*ͪ*+"*ͤ:2*ͪ*l"t*t"*"**t":2:2*"t:[<2[*0#"0*0ͪ**t<*0ͤ*0+"0:[=2[:!S2*4+"*4ͪ*"4:[!*ͤ:=2:!o:!*4+"*+"*ͪ*+"*ͪ*+"*ͪ*+"*ͪ*+"*ͪ*+"*"4*4*0q0*@ͤ*ͤ:2*@"!"D(:F!&:!t(*4ͪ*\*4"4d*4ͪ*\*4"d*4+"4H*4ͪ*4+"4L*4ͪ*4+"4h*4ͪ             
             	                                                                                                                        *** I/O ERROR ****** EXPRESSION ERROR ****** CONVERSION ERROR ****** MEMO=2:!*`ͤ*4+"``*4ͪ*`"4*4*0q0:=2:2F*Tͤ*T"!c"D(:2F*ͤ:!*0":2*l#"l*l"*4#":2*"*"**":2*"*+"*ͪ:<2**0q0**¢*2b:b!02C*0"@`*@ͪ:2F2G2K*4"H2O2S:So/<g"P2W*@#"T*Tͪ:2[*$"\:2f*"d:2n:=2o*"l2s*"p:2v2w:2z2{222*"*,#" *T#"0!"L*@`ͤ:c2b:b!                                                                                                                                                                                                                                                                h#"h*h`ͤ:b!:b!g*4+"``*4ͪ*`"4*4*0q0:b!*4*H"*"*+":2*H":c!*\*d"4*4dͤ*4+"4*4Hͤ*4+"4*4Lͤ*4+"4*4hͤ*4+"4*4ͤ*L*`*d":c!+*ͤ:c!/*"h*4+"4*4ͪ*"*4+"H*H*0q0!:"L:*H"4*"**p*h#"*hhͤ*h`ͤ:c!ʀ*p+"p*ͤ:!F*#":!/F*+":!3F*+"**F**F*+"*ͤ:!&*"H*ͤ:*RY FULL ERROR ***/---------------------  STAGE2  --  8080 VERSION1~#N#F#
`
`D0:k!3"+"-"/220 }o#"0}o#"4))ì))w#w#w#wG> G>!3"+!2^ #"-63}22*+~#"+*-Gͤ*#":!S2*0#"*0ͪ*"0**4*0ͪ*0#"0*4*0q0*ͪ*ͤ:2b!|"|,**t<*4+"x*x*0q0x*4ͪ*x"4*t*"t<*ͤ:!*+":!c¼*"t<*\*"*d*0*H"`:2*H"**p/*p+"p*`"42c*4+"`*`*0q0`*4ͪ:c!o:c!Cʏ:<2:c!G/*`"DD*4ͪ/*`"42c*4+"``*4ͪ*`*0q0:c!o*4+"*ͪ*+"*ͪ*+"*ͪ*+"*                                                                                                                                                                                                                                                                #:!*ͤ:c!:c!ʝ:c!E:c!#s*":c!:o/<g"t:c!'<:!:o/<g"t:c!3<:#!#2"!"D/*4#"*Tͤ*T"!"D(:!:2b*ͤ:!*`ͤ*4+"*4ͪ*"4:  P))|gz_ |))))))l?g ʹʹFøDM!  >zU	=))O ʹʹ̀͸ø̀"!6  {_zW5>  )D*OxGҪ	!?Ì   ||/g}/o#2IDSCMF!N#D:'!#2&n:2b:2c*"`:cp#"-6"->G>!3"-G>#333                                                                                                                                                2}o|g|}|||} ʹT])))ø ʹ͸ø**0q0*4ͪ*"4l*4ͪ*h#"h*4*H"*":2:2*H"*ͪ*4+"H:*d"**`ʼ:c!7ʀ*#"*h#"h:c!:c!:c!a :c!##:c!'ʣ!:c!+E":c!/1#:c!3ʉ%:c!:#!#2"!"DD*4"x:2*"*":!/,*"t*|:s2:!ʯ/*ͤ*":2:!s,*4ͪ*4+"4*4*0q0:=2*"/,:!w,:!{,:!,:!,:!,:<2*ͤ:!,:2:<2:2g*"t:!2:=2ͤ!&"DT&* *"*ͤ* *"**0q0*ͤ*ͪ::!1):2:=2:2*#"*ͪ*#"*ͪ*D:!ʡ#*#"*ͤ*#"*ͤ*ͪ*#"*Hͤ*#"*ͤ::2:o2*0+"0":c2b:b!::b!0:!::=2*ͤ2:!! :2:!Ç0*ͤ:!:!:*ͤ:2F*Tͤ*T"! "D(:2F:2*"*"*#"*ͤ:!*":2:2:!N!*ͪ:!*0q0*ͪ:2*ͪ:2(:2*#"*ͪ*#":2:2*"*ͪ1):!+:!+*ͤ:<2:=2*":!s*:2:<2:!+*ͤ:=2*":<2:!sʧ*:!®*:=2:!®**"*":2:2*H"*4+"4:2F*"D:2:2*,":2:2*"*4+":<2*4ͪ*4+"4*4ͪ*4+"4D*4ͪ*4+"4*h#"h*h`ͤ*4*"``*4ͪ*4"*4+"4*4*0q0:b!]$D*4ͪ:2F*4"*4+"4:s2/*hͤ:2:!R*h#"h:!S2*hͤ:!R:ͻ2*h#"h:c!ʏl*4ͪ*H"*4*H(*h#"h*h`ͤ:b!*h+"h:co/<g"*P*"*$*i**i:c2*"**d"*ͤ:!C**"`*0#"0`*0ͪ:c!O':c!K'*0"*ͪ*0ͪ*0#"0*4*0q02c:c!Kp(:2F*L:2*H"*ͤ:2:!(:2:!0:!op(:2À(**"**1):F!W+*4*S+*ͤ*'2c`*0ͪ:c!Kʉ':c!Oʉ':c!S2c:22:!S2:co/<g"*0ͪ**҉'*$*҉':2*"*0ͪ*0#"0*4*0q02c`*0ͪ:c!O':c!o':c!K'*0"*ͪ*0"*@`ͤ:c2b:b!02c:*ͤ*"*ͤ:2*ͪ:=2**N!:!!:*0"*ͪ*0#"0*4*0q0*"*ͤ*":=2:!oN!*ͪ:*h`ͤ:b!*h#"h*ͤ*#"*ͤ:!:!*#":!":!ͤ*ͪ*ͪ1)*ͪ*+"*#"*#"(:!(*#"*ͤ*D**0"*ͪ:!ʺ+:=2*"*"*0ͪ*0#"0*4*0q0*ͤ:!w+:2*"*0ͪ*0#":2*"*ͪ*#"0*4*0q0**4ͪ*4+"4*4ͪ*4+"4H*4ͪ*4+"4*4ͪ*4+"4*4ͪ*4+"*ͪ*+"4*4ͪ* *4"4h*4ͪ*+"ß%**:*ͤ*+"*ͤ:!ʡ#:!ʕ&:!ʕ&*ͪ* *"*hͤ*"*+"4*4"H*ͤ:!C:2*ͤ:=2*h#"h*h`ͤ:c!Ü:W2V*h#"h*h`ͤ:c!CÜ:b!ʀ(:c2b*h#"h*h`ͤÜ*@`ͤ*4*H*Hͤ:!S2c`*@ͪ*4*:cͻ2b:b!0*ͤ:!::!:*ͤ*ͤ:!+*:!f**#"*#"*ͤ:!9+:!):!(:!(**ʻ):!ʻ):F!ʻ)*+"*+"**0q0*ͪ**"*ͪ:=2*"*ͤ*#"1):!ʻ):F!(*+"*+"*:*ͤ:!:!:!(#"|,*t"p:*4*H"*":2:!*H"!c#"|,:2:2*t#"*Hͪ*"*H"* *H"Hh*Hͪ*"H*"*+"**:*H"*H+"H*Hͪ*H+"H*Hhͤ*H+"H:l*4ͪ*4*H8"*"*ͤ*ͤ:!":=2:!":c!S:#*h`ͤ:b!*h#"h*ͤ:!!{""|,*t"`* *d"*ͤ:!!""|,* *d"*#"*`*t"t**t8"**t":c!{:":c!w::c!S*":!8.*ͤ:o/<g"*P*"*$*N-**-*4#"*Tͤ:2*T"!s-"D(:!8.:!8.*ͤ:2v:!{
.:2v*"*ͤ:o/<g"*P*"**-*$*ү/**ү/*t"t*OOP
	CALL	GETCH
	CPI	3	; CONTROL C
	BREAK IF ( ZERO )  ; BREAK OUT OF LOOP ON CONTROL C
	CALL	DOIT
	FIN
;
	WHILE ( CARRY )	RLC
;
	WHILE ( CARRY )
	MOV	A,M
	INX	H
	RLC
	FIN
;
	REPEAT
	MOV	E,M
	CALL	DOIT
	INX	H
	SUI	1
	UNTIL ( CARRY )
	R2:!/:#2":"!0:!o;0:2/**S+*\*"*+"*ͤ*ͤ/:#!#2"!0"D/:#!#2"!0"D/                                                                                                   RET
;
	END
END-OF-FILE

;
	IF (ZERO)
	('B')	CALL	NOGOOD
	STA	XYZ
	FIN
;
	WHILE (NOT ZERO)
	DCR	B
	UNTIL ( CARRY )
	FIN
;
	FIN
	FIN
	FIN
	TA	T2
;
LBL:	MOV	B,A
	RLC
	ADD	B
	RET
;
	SELECT
	('Q')	CALL	QQQ
	('A'|7|'Z')	CALL	A7Z
	(OTHERWISE)	CALL	OTHER
	FIN
;
	SELECT
	('Q')
	LDA	XYZ
	CALL	QQQ
	FIN
	('A'|7|'Z')
	LDA	PDQ
	CALL	A7Z
	FIN
	(OTHERWISE)
	LDA	ABC
	CALL	OTHER
	FIN*t"t:=2:!¬-:v!8.:2v*t*"t:g!0/:!s.:g!.:g!.:!ʬ.:!ʜ.:!{ʌ.*t*"ù.*t*"ù.*t*1"ù.*t*`":g2:g!5,*"t*4#"4*4ͤ0/:!ʜ.:!ʬ.*4ͪ*A	ABC
	ORA	A
	WHEN ( NOT ZERO )  CALL BBBB
	ELSE
	MVI	A,32
	STA	ABC
	FIN
	FIN
	FIN
	FIN
	RET
PROCEDURE ERRORS    ; ALX SHOULD PRODUCE SOME ERROR MESSAGES
	WHEN ( CARRY )
	IF (MINUS)	CALL	HELP
	WHILE (PLUS)
	ADI	3
	FIN
	FIN
	SBB	1
	IF ( CET
PROCEDURE NESTING
	LOOP
	REPEAT
	IN	0
	ANI	1
	UNTIL ( NOT ZERO )
	IN	1
	ANI	7FH
	CPI	3
	BREAK IF ( ZERO )  ; CONTROL C
	SELECT
	( 'A' | 'a' )  CALL AAAA
	( 'Q' )
	MVI	A,0FFH
	STA	QUIT
	FIN
	( 1AH )  CALL CTLZPROCESS
	( OTHERWISE )
	LD; THIS IS A TEST FOR THE ASSEMBLY LANGUAGE EXTENSION PREPROCESSOR
;
;		THE FOLLOWING BEGIN CAUSES ALX TO DISPLAY REVISION INFO
BEGIN
;
;		THE FOLLOWING PRESETS THE LABEL GENERATOR TO 24
;		MUST USE THIS IF SEPERATE MODULES ARE TO BE  RUN THROUGH ALX
	FIN
	RET
PROCEDURE STATEMACHINE
	EXECUTE ( NSTATE )
	( ST1 )
	LDA	PDQ
	CPI	'X'
	IF ( ZERO )
	SETNEXT ( NSTATE = ST2 )
	FIN
	FIN
	( ST2 )
	LDA	PDQ
	CPI	'Y'
	IF ( ZERO )
	SETNEXT ( NSTATE = ST1 )
	FIN
	FIN
	FIN
	RET
PROCEDURE LOOPS
	L4+"4*4*0q0:g2*t"5,:!¯/*|:!s`.*x*4"/*4#"4*4ͤ:!0/*ͤ:=2*":2g:g!0/:g!w8.:g!{8.:g!8.:g!8.:#!#2"*"t*x"4!/"D/*|*H"*d"*H*4;0l*4ͪ*ͤ:ARRY )	ADI	5
	ELSE
	IF (MINUS)	CALL	HELP
	STA	ABC
	FIN
;
	SELECT
	REPEAT
	INR	A
	UNTIL	(ZERO)
	('A')	CALL	HELLO
	FIN
;
	IF (ZERO)
	('B')	CALL	NOGOOD
	STA	XYZ
	FIN
;
	WHILE (NOT ZERO)
	DCR	B
	UNTIL ( CARRY )
	FIN
;
	FIN
	FIN
	FIN
	HEN ( CARRY )	LDA	XYZ
	ELSE	LDA	PDQ
;
	WHEN ( CARRY )
	LDA	XYZ
	STA	PDQ
	FIN
	ELSE
	LDA	PDQ
	STA	XYZ
	FIN
	RET
PROCEDURE MULTIPLEBRANCHES
	BRANCH
	( 'W' )  LWW
	( 'A' | 'Z' )  LAZY
	( OTHERWISE )  LBL
	FIN
;
LWW:	STA	T1
	RET
;
LAZY:	S
;		THEN CONCATENATED AFTERWORDS.
;		BETTER TO USE SOMETHING LIKE M80 AND LINKER.
.LSKIP 23
;
PROCEDURE ONEBRANCH
	IF ( CARRY )	LDA	XYZ
;
LABEL:
LABEL2:	IF ( CARRY )	LDA	PDQ
;
	IF ( CARRY )
	LDA	XYZ
	STA	PDQ
	FIN
	RET
PROCEDURE TWOBRANCH
	W		ASSEMBLY LANGUAGE EXTENSION PREPROCESSOR

This application of STAGE2 to enhance assembly language programs with a few
control structures is included with this STAGE2 package mainly for example.
No user documentation is provided but it should not be d---------------------------
 `~				;To accept line starting with space
	`10~			;    change space to tab
~ ---------------------------------------
BEGIN`~
.HELLO~
BEGIN`10`F14~
~ ---------------------------------------
`:`~				;To accept line with l^K ^n		    FIN			n:

	-----------------------------------------------------------

	>B		BRANCH

			    ( V1 )  L1			CPI	V1
							JZ	L1

			    ( V2 | V3 | V4 )  L2	CPI	V2
							JZ	L2
							CPI	V3
							JZ	L2
							CPI	V4
							JZ	L2

--------------------------------------
	`~			;To accept an input line starting with tab
.TRIM `10~			;    remove leading spaces or tabs
^IND`76 ^TRIM`86~		;    indentation an line reference
>>	`71`81~			;    output to listing channel
.STM `81~			;    -------------

	Statement is allowed if top of stack is one of the following:
	I,K,L,O,R,W,*.  Otherwise particular control statements are
	expected.

		I,K,L,O,W	statement or FIN

		R		statement or UNTIL

		E		ELSE only

		S		SELECT ITEM or FIifficult to see how
to use it by trying the examples provided.

	Examples:
		STAGE2 ALXTEST.ASM,ALXTEST.LST=ALX.MAC,ALXTEST.ALX

		STAGE2 BOUT.ASM,BOUT.LST=ALX.MAC,BOUT.ALX


IMPLEMENTATION NOTES:

	> means push   ^ means pop   C means condition			    ( OTHERWISE )  L3		JMP	L3

	^B		    FIN

	-----------------------------------------------------------

	>n >S		SELECT

	>n+1 >I		    ( V1 )			CPI	V1
							JNZ	n+1

	^I ^n+1			FIN			JMP	n
						n+1:

	>n+3 >I		    ( V2 | V3 | V4 )		CPIprocess statement
.DUMP STACK~
~ ---------------------------------------
>>`| FIN`~
`10|_FIN`20`F14~
~ ---------------------------------------
>>`| UNTIL`~
`10|_UNTIL`20`F14~
~ ---------------------------------------
>>`~
`10`F14~
~ ------------N

		B		BRANCH ITEM or FIN
tatements are
	expected.

		I,K,L,O,W	statement or FIN

		R		statement or UNTIL

		E		ELSE only

		S		SELECT ITEM or FI

	Stack		Source Statements	Generated Code

	>n >K		IF ( C )			JCF	n

	^K ^n		    FIN			n:

	-----------------------------------------------------------

	>n >n+1 >W	WHEN ( C )			JCF	n+1

	^W >E		    FIN				JMP	n

	^E ^n+1 >K	ELSE			n+1:

	~`~`0 (+-*/)	MACROS FOR 8080 ASSEMBLY LANGUAGE EXTENSION PREPROCESSOR
.HELLO~
-- ALX 2.6a  03/19/81  For CPMUG`F15~
~ ------------------------------------
.LSKIP `~			;To increment label counter by P1
`10`F7~
.INCSYM~
`F8~
~
.INCSYM~
`01`16~
~ -

	>n >n+1 >L	WHILE ( C )		n+1:	JCF	n

	^L ^n+1 ^n	    FIN				JMP	n+1
						n:

	-----------------------------------------------------------

	>n >R		REPEAT			n:

	^R ^n		    UNTIL ( C )			JCF	n

	----------------------------------------------	V2
							JZ	n+2
							CPI	V3
							JZ	n+2
							CPI	V4
							JNZ	n+3
						n+2:

	^I ^n+3			FIN			JMP	n
						n+3:

	>O		    ( OTHERWISE )

	^O			FIN

	^S ^n		    FIN			n:

	-----------------------------------------------------------abel
`10:`F14~			;    output label to listing channel
`10:`F13~			;    output label to ASM file
.IF `20= SKIP 1~
	`20~			;    pass on rest of statement for processing
~ ---------------------------------------
PROCEDURE `~			;To recognize PROCEDURE de
.. JZ `30~			;	output jump if match instruction
`F8~				;	end of loop
~ ---------------------------------------
.ITEM B(`OTHERWISE`)`~		;To recognize BRANCH catch all ITEM
.. JMP `30~			;    output jump instruction
~ ---------------------------------ck
.PUSH K~			;    push code "K" - IF or WHEN ELSE term.
~ ---------------------------------------
.ELSE `~
.PUSH `10~			;    restore stack
.SERR ELSE~
~ ---------------------------------------
.STM BRANCH`~			;To recognize BRANCH statement
...BRAN-------------------
.PROC  `~
.PROC `10~
~ ---------------------------------------
.PROC `~
`10`27 ;	~		;    scan with break on " " or ";" or TAB
.STO ^PROC=`20~
~ ---------------------------------------
;`~				;To accept comment line
;`10`F14~			(`)`~			;To recognize SELECT or BRANCH ITEM
...(`10)`20~			;    output comment line to ASM file
.TOS~
^CSI`36 .ITEM `31(`10)`20~
~ ---------------------------------------
.ITEM B(`)`~			;To recognize simple BRANCH ITEM
.. CPI `10~			;    output compal n
.PUSH `02~			;    push label n+1
.PUSH W~			;    push code "W" - WHEN
.JCF `20,`02~			;    output conditional jump to n+1
.XSTM `30~			;    process remainder of line
~ ---------------------------------------
.STM ELSE`~			;To recognize ELSE stateclaration
.IF ^CSP<1 SKIP 4~
^DBG`86 `81`86 .STO ^DBG=T~
.DUMP STACK~
.STO ^DBG=`80~
.ERR STACK NOT EMPTY -- CHECK CONTROL STRUCTURES~
.LET ^CSP=0~			;    clear control stack
.LET ^LEV=0~			;    control structure level
.STO ^IND=~			;    clear inde
.CHECK SELECT~
.PUSH `01~			;    push label n
.PUSH S~			;    push code "S" - SELECT
.INCLEV~
~ ---------------------------------------
.STM EXECUTE`(`)`~		;To recognize EXECUTE statement
.PUSH `01~			;    push label n
.PUSH X~			;    push code "XCH`10~			;    output comment line to ASM file
.CHECK BRANCH~
.PUSH B~			;    push code "B" - BRANCH
.INCLEV~
~ ---------------------------------------
.STM SELECT`~			;To recognize SELECT statement
...SELECT`10~			;    output comment line to ASM file;    output to listing channel
~ ---------------------------------------
`~				;To accept any other line
.IF `10-= SKIP 1~		;    if P1 is null
 `16~				;	P1 = " "
`10`F14~			;    output to listing channel
`10`F13~			;    output to ASM file
~ -------re instruction
.. JZ `20~			;    output jump if match instruction
~ ---------------------------------------
.ITEM B(`|`)`~			;To recognize BRANCH ITEM with OR
`10|`20`47|~			;    scan with break on OR symbol
.. CPI `40~			;	output compare instructionment
...ELSE`10~			;    output comment line to ASM file
.POP~
^CSI`96 .ELSE `91~		;    process else or flag error
.XSTM `10~			;    process remainder of line
~ ---------------------------------------
.ELSE E~
.POPL~				;    output label n+1 from stantation string
^PROC`86 .PROC `10~
 `F14~
   - - - - - - - - - - - - - - - - - - - - - - - - - - `81`F14~
 `F14~
PROCEDURE `10`F14~		;    output to listing channel
 `F14~
`81:  ; - - - - - - - - - - - - - - PROCEDURE `10`F13~
~ --------------------" - EXECUTE
.INCLEV~
.. LHLD `20~
.. PCHL ~
~ ---------------------------------------
.STM SETNEXT`(`=`)`~		;To recognize SETNEXT statement
^TRIM`86 .TRIM `30~
.. LXI H,`81~
.TRIM `20~
.. SHLD `81~
~ ---------------------------------------
.STM onditional jump to n
.XSTM `30~			;    process remainder of line
~ ---------------------------------------
.STM WHEN`(`)`~			;To recognize WHEN statement
...WHEN (`20)`30~		;    output comment line to ASM file
.CHECK WHEN~
.PUSH `01~			;    push labe--------------------------------
.STM IF`(`)`~			;To recognize IF statement
...IF (`20)`30~			;    output comment line to ASM file
.CHECK IF~
.PUSH `01~			;    push label n
.PUSH K~			;    push code "K" - IF or WHEN ELSE
.JCF `20,`01~			;    output c------
.ITEM S(`)`~			;To recognize simple SELECT ITEM
.PUSH `01~			;    push label n+x
.PUSH I~			;    push code "I" - SELECT ITEM
.. CPI `10~			;    output compare instruction
.. JNZ LLZ`01~			;    output JNZ n+x
.XSTM `20~			;    process remainder	;    success:  point to exit label on stack
.STO ^CSI=`81~			;	save exit label
~ ---------------------------------------
.STM FIN`~			;To recognize FIN terminator
...FIN`10~			;    output comment line to ASM file
.DECLEV~
.POP~
^CSI`96 .FIN `91~		;.LOOP `,`~			;To setup loop for WHILE, REPEAT or LOOP
.PUSH `10~			;    put exit label on stack
.PUSH `01~			;    put loop label on stack
.PUSH `20~			;    put structure code on stack
..LLZ`01:  ~			;    output loop label
~ ---------------------------for match
.XSTM `30~			;    process remainder of line
~ ---------------------------------------
.ITEM S(`OTHERWISE`)`~		;To recognize SELECT catch all ITEM
.PUSH O~			;    push code "O" - OTHERWISE
.XSTM `30~			;    process remainder of line
~ --------------------------------------
.BRK~				;To search control stack for exit label
.IF ^CSP>0 SKIP 2~		;    when stack empty
.SERR BREAK~			;	BREAK out of place
`F9~				;    else
.LET ^CSB=^CSP+1~		;	search pointer = stack pointer + 1
^CSB`96~
^CSP`Fss remainder of line
~ ---------------------------------------
.STM LOOP`~			;To recognize unconditional LOOP statement
...LOOP`10~			;    output comment line to ASM file
.CHECK LOOP~
.LOOP `01,L~			;    setup loop
.XSTM `10~			;    process remainder of line
~ ---------------------------------------
.ITEM S(`|`)`~			;To recognize SELECT ITEM with OR
.PUSH `02~			;    push label n+x+1
.PUSH I~			;    push code "I" - SELECT ITEM
`10|`20`47|~			;    scan with break on OR symbol
.. CPI `40~			;	outpNTIL R,`~
.DECLEV~
.POP~
^CSI`96 .JCF `10,`91~		;    output conditional jump to n
.POPL~				;    output label from stack
~ ---------------------------------------
.UNTIL `,`~
.PUSH `10~			;    restore stack
.SERR UNTIL~
~ -------------------------------------
.STM UNTIL`(`)`~		;To recognize UNTIL termination of REPEAT
...UNTIL (`20)`30~		;    output comment line to ASM file
.POP~
^CSI`96 .UNTIL `91,`20~		;    generate conditional jump or flag error
~ ---------------------------------------
.U---------------------------------
.ITEM X(`)`~			;To recognize EXECUTE item (state)
.PUSH Y~
^LABEL`86 .LABEL `10~
..`81:  ~
.XSTM `20~			;    process remainder of line
~ ---------------------------------------
.LABEL  `~
.LABEL `10~
~ -----------7~			;	for i = 1 to stack size
.LET ^CSB=^CSB-1~		;	    decrement search pointer
^CS`91`86 ^BRK`81`86~
.IF `81-= SKIP 3~		;	    if loop code found goto success
`F8~				;	    fin
.SERR BREAK~			;	BREAK out of place
`F9~				;	exit
`91-2`96 ^CS`94`86~	 of line
~ ---------------------------------------
.STM REPEAT`~			;To recognize REPEAT statement
...REPEAT`10~			;    output comment line to ASM file
.CHECK REPEAT~
.LOOP `01,R~			;    setup loop
.INCLEV~
~ ---------------------------------------
ut compare instruction
.IF `43-=| SKIP 2~		;	if break char. is OR
.. JZ LLZ`01~			;	    output jump to match
.SKIP 1~			;	else end of line
.. JNZ LLZ`02~			;	    output jump to nomatch
`F8~				;	end of scan loop
..LLZ`01:  ~			;    output label n+x: --------------
.STM BREAK`IF`(`)`~		;To recognize loop BREAKout statement
...BREAK IF (`30)~		;    output comment line to ASM file
.CHECK BREAK IF~
.BRK~				;    search stack for exit label
^CSI`86 .JCT `30,`81~		;    GEN conditional branch
~ ---------------------------------
.STM WHILE`(`)`~		;To recognize WHILE statement
...WHILE (`20)`30~		;    output comment line to ASM file
.CHECK WHILE~
.LOOP `01,L~			;    setup loop
.JCF `20,`01~			;    output conditional jump to n
.XSTM `30~			;    proce----------------------------
.LABEL `~
`10`27 :	~
.STO ^LABEL=`20~
~ ---------------------------------------
.ITEM `(`)`~			;To recognize SELECT ITEM out of place
.SERR SELECT, BRANCH ITEM~
.ITEM S(`20)`30~		;    process line anyway
~ -------------    process FIN by code found on stack
~ ---------------------------------------
.FIN B~				;To terminate BRANCH
~ ---------------------------------------
.FIN I~				;To terminate SELECT ITEM
.POP~
^CSI`96 `91`96~			;    pop label n+x
.POP~
^CSI`86^CSP=^CSP-1~
`F9~
.STO ^CSI=*~
`FE~
~ ---------------------------------------
.TOS~
^CSP`96 .IF `91<1 SKIP 2~
^CS`91`86 .STO ^CSI=`81~
`F9~
.STO ^CSI=*~
~ ---------------------------------------
.JCT `,`~			;To output jump condition true
.STO ^YSTM ~
~ ---------------------------------------
.YSTM ;`~
~ ---------------------------------------
.YSTM `~
.CHECK `10~
	`10`F13~		;    output to ASM file
.STM FIN~			;    generate a FIN statement
~ ---------------------------------------
.TRIM  O~				;To terminate SELECT OTHERWISE ITEM
~ ---------------------------------------
.FIN S~				;To terminate SELECT
.POPL~				;    output label n: from stack
~ ---------------------------------------
.FIN W~				;To terminate WHEN branch
.POP~
^CSI`ck
.LET ^CSP=^CSP+1~
^CSP`96 .STO ^CS`91=`10~
~ ---------------------------------------
.POPL~				;To output label from stack
.POP~
^CSI`96 ..LLZ`91:  ~
~ ---------------------------------------
.POPJ~				;To output jump to label from stack
.POP~R STACK NOT EMPTY -- CHECK CONTROL STRUCTURES~
.STO ^DBG=T~			;	set debug mode
.DUMP STACK~			;	send stack contents to LST file
LLZ`01 Next label not used`F15~
`F0~				;    stop processing
~ ---------------------------------------
.STM `~				;To reco `81`86~			;    pop code "S"
.TOSJ~				;    output jump to label n (stack top)
.PUSH `80~			;    push code "S" back on stack
..LLZ`90:  ~			;    output label n+x:
~ ---------------------------------------
.FIN K~				;To terminate IF or WHEN ELSE
.POP------------------------------------
.INCLEV~
.LET ^LEV=^LEV+1~
.CAT ^IND, | ~			;    append to indentation string
~ ---------------------------------------
.DECLEV~			;To decrement control structure level
^LEV`16 .IF `11<1 SKIP 2~
.LET ^LEV=^LEV-1~ `~			;To strip leading space
.TRIM `10~
~ ---------------------------------------
.TRIM 	`~			;To strip leading tab
.TRIM `10~
~ ---------------------------------------
.TRIM `~			;To save line without leading spaces and tabs
.STO ^TRIM=`10~
~ ---96 `91`96~			;    pop label n+1
.TOSJ~				;    output jump to label n (stack top)
.PUSH `90~			;    put label n+1 back on the stack
.PUSH E~			;    push code "E" - ELSE
~ ---------------------------------------
.FIN X~				;To terminate EXECUTE
.POPL~
^CSI`96 .. JMP LLZ`91~
~ ---------------------------------------
.TOSJ~				;To output jump to label on stack top
.TOS~
^CSI`96 .. JMP LLZ`91~
~ ---------------------------------------
.POP~
^CSP`96 .IF `91<1 SKIP 3~
^CS`91`86 .STO ^CSI=`81~
.LET gnize non control statements
.CHECK `10~
	`10`F13~		;    output to ASM file
~ ---------------------------------------
.XSTM `~
.INCLEV~
.TRIM `10~			;    strip leading spaces and tabs
^TRIM`26 .YSTM `21~
~ ---------------------------------------
.L~				;    output label n: from stack
~ ---------------------------------------
.FIN L~				;To terminate WHILE loop
.POPJ~				;    output jump to n+1: from stack
.POPL~				;    output label n: from stack
~ ---------------------------------------
.FIN
^IND`26 .UND `21~		;    remove " | " from indentation string
~ ---------------------------------------
.UND ` | ~			;To remove one level of indentation
.STO ^IND=`10~
~ ---------------------------------------
.PUSH `~			;To push something on the sta-----------
.FIN `~				;To recognize a wayward FIN
.INCLEV~
.PUSH `10~			;    restore stack
.SERR FIN~
~ ---------------------------------------
END-`~				;To recognize END-OF-FILE
END-`10`F14~
^CSP`26 .IF `21<1 SKIP 3~	;    if stack not empty
.ER
~ ---------------------------------------
.FIN Y~				;To terminate EXECUTE ITEM
.POP~
^CSI`86 `81`86~			;    pop code "X"
.TOSJ~				;    output jump to label n (stack top)
.PUSH `80~			;    push code "X" back on stack
~ ----------------------------TMP=~			;    set string to null
`10`37 	~			;    scan and break on space or tab
.CAT ^TMP,`30~			;	save non space or tab characters
`F8~				;	end of loop
^TMP`16 `11`16~			;    retrieve compressed condition string
.. `11 LLZ`20~			;    get jump inst.  moves rate register to int mask reg
MCONT	EQU	PMMI+3	; modem control register
PROCEDURE CONST
	CALL	DJTSTAT
	MVI	A,0FFH
	RZ		; return if terminal input data ready

	CALL	MISTAT	; check modem input status
	RET
PROCEDURE CONOUT
	PUSH	B
	CALL	FLUS
.STO ^^R=SOK~
.STO ^^W=SOK~
.STO ^^Y=SOK~
.STO ^^*=SOK~
.STO ^BRKL=LOOP~	BREAK OK FOR LOOP, OR WHILE
.STO ^BRKR=LOOP~	BREAK OK FOR REPEAT
.STO CARRY=JC~
.STO NOCARRY=JNC~
.STO PLUS=JP~
.STO MINUS=JM~
.STO ZERO=JZ~
.STO NOTZERO=JNZ~
.STO EVEN=6 `11`F7~
^CNT`26 ^CS`21`36~
^CS`21	"`31"`F14~
.LET ^CNT=^CNT-1~
`F8~
^LEV`46~
^LEV	=`41`F14~
~ ---------------------------------------
.DEBUG~
.STO ^DBG=T~
~ ---------------------------------------
.UNBUG~
.STO ^DBG=F~
~ ---------------------
; Local data storage (initialized)
;
CONNECT: DB	0	; false - modem not connected
;
; Terminal access
;
DJROM	EQU	0F800H
DJCIN	EQU	DJROM+3
DJCOUT	EQU	DJROM+6
DJTSTAT	EQU	DJROM+21H
;
; Modem access
;
PMMI	EQU	0C0H	; base port address
USTAT	EQ
~
.IF `=` SKIP `~
`F50~
~
.IF `-=` SKIP `~
`F51~
~
.IF `<` SKIP `~
`F6-~
~
.IF `==` SKIP `~
`F60~
~
.IF `<>` SKIP `~
`F61~
~
.IF `>` SKIP `~
`F6+~
~~ ------------ END OF MACROS ------------------- END OF MACROS ------------
.LET ^ERR=0~from table and output
~ ---------------------------------------
.JCF `,`~			;To output jump on condition false
.STO ^TMP=~			;    set string to null
`10`37 	~			;    scan and break on space or tab
.CAT ^TMP,`30~			;	save non space or tab characters
`JPE~
.STO ODD=JPO~
.STO -CARRY=JNC~		CONDITIONAL JUMP LOOK UP TABLE
.STO -NOCARRY=JC~
.STO -PLUS=JM~
.STO -MINUS=JP~
.STO -ZERO=JNZ~
.STO -NOTZERO=JZ~
.STO -EVEN=JPO~
.STO -ODD=JPE~
------------------
...`~				;To output comment line to ASM file
;;			`10`F13~
~ ---------------------------------------
..` ` `~			;To output line to ASM file
`10	`20	`30`F13~
~ ---------------------------------------
.SERR `~
.ERR "`10" NOT ALLOWEU	PMMI	; uart status input
UCONT	EQU	PMMI	; uart and modem control output
UDATA	EQU	PMMI+1	; uart incoming and outgoing data
MSTAT	EQU	PMMI+2	; modem status input
MRATE	EQU	PMMI+2	; timer rate regester and temp reg for int mask
MINT	EQU	PMMI+3	; input
.LET ^LEV=0~		CONTROL STRUCTURE LEVEL
.STO ^IND=~		EMPTY INDENTATION STRING
.LET ^CSP=0~		EMPTY STACK
.STO ^CS0=*~		EMPTY STACK ENTRY
.STO ^DBG=F~		DEBUG OFF
.STO ^^I=SOK~		STATEMENT OK IF "I" IS ON STACK
.STO ^^K=SOK~
.STO ^^L=SOK~
.STO ^^O=SOK~F8~				;	end of loop
^TMP`16 -`11`16~		;    retrieve compressed condition string
.. `11 LLZ`20~			;    get jump inst. from table and output
~ ---------------------------------------
.DUMP STACK~
^DBG`56 .IF `51=T SKIP 1~
`F9~
.LET ^CNT=^CSP~
^CSP`1; CP/M console I/O module supporting terminal and modem in "parallel"
;
;	Terminal is attached to Disk Jockey serial port
;	Modem is PMMI S100 board
;
BEGIN
;
; Entry points
;
	ENTRY	CONST,CONIN,CONOUT
;
; External references
;
	EXTRN	FLUSH
;-------
.CHECK `~			;To check top of stack for stmt allowed
.TOS~
^CSI`26 ^^`21`26~
.IF `21=SOK SKIP 1~
.SERR `10~
~ ---------------------------------------
.CAT `,`~
`11`20`26 `F3~
~
.STO `=`~
`F3~
~
.LET `=`~
`24`26 `F3~
~
.SKIP `~
`F4~D HERE~
~ ---------------------------------------
.ERR `~				;To output error messages
>>> ERROR <<< `10`26~
`20`F13~			;    to ASM file
`20`F14~			;    to listing file
`20`F15~			;    to console
.LET ^ERR=^ERR+1~
~ --------------------------------H
	POP	B
	CALL	DJCOUT	; output character to terminal
	CALL	MOUT	; output character to modem if connected
	RET
PROCEDURE CONIN
	CALL	FLUSH
	LOOP
	CALL	DJTSTAT
	IF ( ZERO )     ; data waiting
	CALL	DJCIN	; get data from terminal
	ANI	7FH
	RET
	FECEIVE STATUS  1=READY  0=NOT READY
;
MISTAT:	IN	SIO
	ANI	1	; RECEIVER READY STATUS BIT
	RET
;
;
; CHECK SEND READY STATUS
;
MOSTAT:	IN	SIO
	ANI	2
	RET
;
;
; CHECK CONSOLE READY STATUS  1=READY  0=NOT READY
;
CISTAT:	IN	KBD
	ANI	2
	RZ

	2	; data available (low true)
	SUI	1	; if ( DAV = 0 ) A=FF
	SBB	A	; else           A=0
	FIN
	FIN
	ORA	A	; set zero flag
	RET
PROCEDURE CONSEQ
	MVI	A,7FH	; DTR,300,ESS
	OUT	MCONT

	CALL	DELAY

	MVI	A,5EH	; 2s, NP, 8 bits, Answer
	OUT	UCONT

	MVI	D,0
	DAD	D
	INX	H
	MVI	M,0	; MAKE SURE DELIMITER AT END OF NAME

	LXI	H,FTAB
	LXI	D,CBUFF+2
	CALL	DOPEN
	RET
;
;
;
CRLF:	MVI	E,0DH
	CALL	CO
	MVI	E,0AH
	CALL	CO
	RET
;
;
;
BLK:	MVI	E,' '
	JMP	CO
;
;
BDOS	EQU	0005H	; BDOS ENTRY 	RET
PROCEDURE MOUT
	LDA	CONNECT
	ORA	A
	IF ( NOT ZERO )  ; connected
	REPEAT
	IN	MSTAT
	ANI	4
	BREAK IF ( NOT ZERO )  ; carrier lost
	IN	USTAT
	ANI	1
	UNTIL ( NOT ZERO )     ; transmit buffer empty (TBMT)
	CPI	1	; TBMT
	IF ( ZERO )
	MOV	A,CIN
	CALL	MISTAT
	IF ( NOT ZERO ) ; data waiting
	CALL	MINP	; get data from modem
	ANI	7FH
	RET
	FIN
	FIN
PROCEDURE MISTAT
	LDA	CONNECT
	ORA	A
	WHEN ( ZERO )   ; modem disconnected
	IN	MSTAT
	ANI	2
	IF ( ZERO )     ; ringing
	CALL	CONSEQ	; st
	PUSH	B
	MVI	B,150	; 15 seconds
	REPEAT
	CALL	DELAY
	IN	MSTAT
	ANI	4
	BREAK IF ( ZERO )  ; carrier detected
	DCR	B
	UNTIL ( ZERO )
	POP	B

	CALL	DELAY
	IN	UDATA
	IN	UDATA	; clear uart receiver

	MVI	A,52	; 300 baud
	OUT	MRATE

	MVI	A,5CHPOINT
KBD	EQU	02H	; KEYBOARD PORT
SIO	EQU	50H	; 2SIO BOARD ORIGIN
;
;
; OUTPUT TO CONSOLE
;
CO:	MVI	C,2
	CALL	BDOS
	RET
;
;
; OUTPUT (E) TO MODEM
;
MO:	IN	SIO
	ANI	2	; TRANSMIT READY BIT
	JZ	MO

	MOV	A,E
	OUT	SIO+1
	RET
;
;
; CHECK R
	OUT	UDATA	; send data through modem
	FIN
	FIN
	MOV	A,C
	RET
PROCEDURE MINP
	IN	UDATA
	RET
	END
END-OF-FILE
 carrier lost
	IN	USTAT
	ANI	1
	UNTIL ( NOT ZERO )     ; transmit buffer empty (TBMT)
	CPI	1	; TBMT
	IF ( ZERO )
	MOV	A,Cart connect sequence
	STA	CONNECT
	FIN
	MVI	A,0	; no data waiting
	FIN
	ELSE
	IN	MSTAT
	ANI	4
	WHEN ( NOT ZERO ) ; carrier lost
	CALL	DCONSEQ	; start disconnect sequence
	STA	CONNECT
	MVI	A,0	; no data waiting
	FIN
	ELSE
	IN	USTAT
	CMA
	ANISREV EQU 20H ;	06/14/79  R. CURTISS	DERIVED FROM NORDATA1
;
;
; OPEN FILE FOR READ OR WRITE
;
OPENF:	PUSH	B	; SAVE ACCESS CODE
	MVI	C,10
	LXI	D,CBUFF
	CALL	BDOS	; GET FILE NAME FROM CONSOLE
	POP	B

	LXI	H,CBUFF+1  ; CHAR COUNT POINTER
	MOV	E,M1 sec
	OUT	MRATE
	REPEAT
	IN	MSTAT
	ANI	80H
	UNTIL ( ZERO )  ; timer bit low
	REPEAT
	IN	MSTAT
	ANI	80H
	UNTIL ( NOT ZERO )  ; timer bit high
	RET
PROCEDURE DCONSEQ
	MVI	A,3FH	; 300, ESS
	OUT	MCONT	; force hangup
	XRA	A	; connect false flag
	; 2s, NP, 8 bits, Normal (auto hangup if carrier lost)
	OUT	UCONT

	IN	MSTAT
	ANI	4
	MVI	A,0
	RNZ		; return if no carrier

;+++++++++++++ send signon message and password request

	MVI	A,0FFH	; connect flag
	RET
PROCEDURE DELAY
	MVI	A,250	; .	ORI	0FFH
	RET
;
;
; GET DATA FROM MODEM
;
MI:	IN	SIO	; GET STATUS
	ANI	1
	JZ	MI

	IN	SIO+1
	RET
;
;
; GET DATA FROM CONSOLE
;
CIE:	CALL	CI
	MOV	E,A
	PUSH	PSW
	CALL	CO	; ECHO INPUT
	POP	PSW
	RET

CI:	CALL	CISTAT	; GET KEYBOARD STATUS-------------------------------
.ADD $=$#
:CAT $10 $20#
# -------------------------------------------
:CAT $ $#
:STO $10=$11;$20#
# -------------------------------------------
:STO $=$#
$F3#
# ----------------------------------------
:IF $=$ SKIP line
!11!26%				8. Extract info
!F14%				9. Output
1111111= 22222222222222222%	10. Format
%				11. End of macro
END#				12. Template line
!F0%				13. Terminate processing
%%				14. End of macros
MEM[25]=TWENTY FIVE#
MEM[ABC]=HELLO#
MEM[EQUATION]
;	100      8 BITS, 2 STOP, NO PARITY
;    00		 /RTS LOW, XMIT INT. DISABLE
;    11		 /RTS HIGH, BREAK LEVEL TRANSMIT
;  0		 RCV. INTERRUPT DISABLE
;
;
; TRANSMIT BREAK LEVEL
;
BRK:	MVI	A,71H
	OUT	SIO
	RET
;
;
; INITIALIZE SIO FOR NORMAL OPER#
$F3#
# -----------------------------------------
.DUMP#
.DUMP KLIST#
# ------------------------------------------
.DUMP $#
$11$47;#
:IF $40= SKIP 4#
 $F15#
............ $40$F15#
 $F15#
.RECALL $40#
$F8#
# -----------------------------------B
	DCR	B
	JNZ	MSG4

MSG5:	XRA	A
	STA	TAB	; RESET TAB COLUMN COUNT
	RET
;
;
URN
	JMP	MSG5

MSG2:	CALL	CO	; OUTPUT CHARACTER
	RET

MSG3:	INR	B	; TAB COUNT

MSG4:	PUSH	B
	MVI	E,' '
	CALL	CO
	POP	
	JZ	CI	; JUMP IF NO DATA READY

	IN	KBD+1	; GET KBD DATA
	ANI	7FH
	PUSH	PSW
	LDA	ULTOG	; UPPER/LOWER CASE TOGGLE
	ORA	A
	JNZ	CIX	; JUMP IF CASE SWITCH REQUIRED

	POP	PSW
	RET

CIX:	POP	PSW
	CPI	'A'
	RC		; RETURN IF < 'A'
	CPI	'Z'+1
	JC	KI=A=2*(B+C)#
MEM[X=Y]=Z#
MM[12]="E" MISSING#
MEM [XYZ]=SPACE AFTER "MEM"#
MEM[ABC)]=UNBALANCED STRING#
MEM[ABC]=UNBALANCED (STRING#
PRINT MEM[25]#
PRINT MEM[ABC]#
PRINT MEM[PDQ]#
FORMAT MEM[25]#
FORMAT MEM[ABC]#
FORMAT MEM[PDQ]#
END#
ATION
;
SMODE:	MVI	A,03H
	OUT	SIO	; RESET

	MVI	A,11H	; NORMAL OPERATION
	OUT	SIO
	RET
;
;
; DELAY 100*(A) MILLESECONDS
;
DELAY:	LXI	B,29B4H	; Z80 VALUE

D1:	DCX	B
	INR	B
	DCR	B
	JNZ	D1

	DCR	A
	JNZ	DELAY

	RET
;
;
; TYPE MESSAGE W-------
.STOP#
$F0#
# ------------------------------------------
.WRITE#
KLIST$16 $11$47;#
:IF $40= SKIP 1#
.SAVE $40=$41$F13#
$F8#
# ------------------------------------------
.RECALL $#
$11$27;#
                 $20$F15#
$F8#
# ------------#$%!0 (+-*/)			0. Special character selection
MEM[$]=$#			1. Template line
!F3%				2. Store into memory
%				3. End of macro
PRINT MEM[$]#			4. Template line
!10=!11!F14%			5. Extract info and output
%				6. End of macro
FORMAT MEM[$]#			7. TemplateNV	; JUMP IF IN RANGE 'A'-'Z'

	CPI	'A'+20H
	RC		; RETURN IF < LOWER CASE 'A'
	CPI	'Z'+21H
	RNC		; RETURN IF > LOWER CASE 'Z'

KINV:	XRI	20H	; FLIP CASE BIT
	RET
;
;
; CONTROL BYTE FOR SIO
;  X XX XXX XX
;	    01   /16
;	    11   MASTER RESET#$#$0 (+-*/)    SPECIAL SYMBOL SELECTION FOR FOLLOWING MACROS
.SAVE $=$#
$F3#
:CAT KLIST $10#		    ADD ITEM TO DIRECTORY LIST
# ------------------------------------------
.CLEAR $#
:STO $10=#
# ------------------------------------------
.RESAVE $=$A,E
	CPI	'I'-40H
	JZ	MSG3	; JUMP IF TAB

	CPI	0DH
	JNZ	MSG2	; JUMP IF NOT CARRIAGE RETURN

	CALL	CO	; OUTPUT CARRIAGE RETURN
	JMP	MSG5

MSG2:	CALL	CO	; OUTPUT CHARACTER
	RET

MSG3:	INR	B	; TAB COUNT

MSG4:	PUSH	B
	MVI	E,' '
	CALL	CO
	POP	ITH TABS EXPANDED
;
MSG:	MOV	A,M	; GET NEXT CHARACTER OF MESSAGE
	ORA	A
	RZ		; RETURN IF END OF MESSAGE (NULL)

	PUSH	H
	MOV	E,A
	CALL	MSG1
	POP	H
	INX	H
	JMP	MSG

MSG1:	LDA	TAB	; TAB COLUMN COUNTER
	DCR	A
	ANI	7
	STA	TAB
	MOV	B,A

	MOV	 $#
$F50#
# -----------------------------------------
.$#
WHAT IS THE MEANING OF THIS ??? $10$F15#
# -------------------------------------------
$#
.$10#
][ ................................................][$F15#
# --------------------------------	JMP	MEMSET	; ENTRY POINT - SET UP FLUB MEMORY BOUNDS
	NOP

PROGRM:	JMP	PROGR	; EXTERNAL REFERENCE - STAGE2, FLT1, FLT2
	NOP

EXIT:	JMP	0000H	; EXTERNAL REFERENCE - RETURN TO CP/M
	NOP
;
; -------------------------------------
;
; MAIN PROGRAM
22222222222
# ----------------
..$#
    $10$F15#
#                
$#
..>>> NO EXAMPLE PREPARED#
#                
.CONSOLE#
5$F2#
##               
HELP#
..READY FOR INPUT FROM CONSOLE#
.CONSOLE#
QU 12H ;	05/29/79  R. CURTISS	IWRT5,MCHOFF

;REV EQU 11H ;	05/29/79  R. CURTISS	MORE,FPRS,FNAME

;REV EQU 10H ;	05/29/79  R. CURTISS	NEW VERSION
;
; STAGE2 MAIN PROGRAM AND I/O OPERATION PACKAGE
;
; REVISION B02  03/15/78  R. CURTISS   ADD COMMENTSRAMETER#
.L C2 $$/GET FROM MEMORY USING PARAMETER - GEN IF UNDEFINED#
.L C4 $$/EVALUATE EXPRESSION#
.L C5 $$/GET LENGTH OF EXPRESSION#
.L C6 $$/REPLACE PARAMETER#
.L C7 $$/CONTEXT CONTROLLED ITERATION - BREAK ON , ;#
.L C8 $$/GET INTERNAL CODE FOR CH---------
.DIR$#
.RECALL KLIST#
# ----------------------------------------
.HELP#
.RECALL HELP#
# ---------------------------------------
.CONSOLE#
5$F2#
#
DISK#
1$F2#
## ----------- END OF MACROS -------------------------
:STO HELP=ADD <ID>=<#$#$0 (+-*/)
C0 $#
.."$10"#
#                
C1 $#
.."$11"#
#                
C2 $#
.."$12"#
#                
C4 $#
.."$14"#
#                
C5 $#
.."$15"#
#                
C6 $#
YOUR STRING REPLACED BY THIS$16#
.."$10"#
#          
;
MAIN	EQU	100H
PROGR	EQU	1000H

	ORG	MAIN

	JMP	F4IO	; MAIN ENTRY POINT - PROGRAM STARTUP
	DB	REV	; IOOP REVISION

	JMP	IOOP	; ENTRY POINT - I/O PACKAGE
	DB	DREV	; DISK I/O REVISION

	JMP	TRAP	; ENTRY POINT - END OF MACROS DETECTED
	NOP

ARACTER#
.L F0/TERMINATE PROCESSING#
.L F1/OUTPUT REQUEST#
.L F3 $$=$$/STORE INTO MEMORY#
.L F7 $$/COUNT CONTROLLED ITERATION#
.L FE/FORCE ERROR TRACE BACK#
# ----------------
.L $/$#
$F15#
        1111111122222222222222222222222222222222222222222INFO>;DIR;HELP;RECALL <ID>;SAVE <ID>=<INFO>;WRITE;RESAVE <ID>=<INFO>;CLEAR <ID>;STOP;DUMP
.ADD HELP=  <INFO> IS STRINGS SEPERATED BY SEMICOLONS
:STO KLIST=
HELP
.CONSOLE
REV EQU 16H ;	06/13/79  R. CURTISS	NO ERR ON REWIND CLOSED FILE

;REV EQU 15H ;	06/10/79  R. CURTISS	DREV, C, ICNTL

;REV EQU 14H ;	05/31/79  R. CURTISS	FIX LF, MORE, XDEVC, GBPDEV

;REV EQU 13H ;	05/30/79  R. CURTISS	XDEVC FIX, PATCH SPACE

;REV E$F7#
..REPEAT $10 TIMES#
$F8#
#                
FE#
$FE#
# -----------------
HELP#
..S - SYMBOL GEN    C - CONVERSION    F - PROCESSOR FUNCTION#
.L S/REQUEST NEXT SYMBOL FROM GENERATOR#
.L C0 $$/PARAMETER AS IS#
.L C1 $$/GET FROM MEMORY USING PA      
C7 $#
$10$27,;#
.."$20"    "$23"#
$F8#
#                
C8 $#
.."$18"#
#                
S#
.."$01"#
#                
F0#
$F0#
#                
F1#
..OUTPUT REQUEST#
#                
F3 $=$#
$F3#
#                
F7 $#
$10;
	DS	38H	; STACK SPACE

F4IO:	LXI	SP,F4IO
;
	CALL	INIT
	CALL	PROGRM
;
;	 CLOSE ALL CHANNELS
;
	CALL	GCLOSE

	CALL	EXIT
	JMP	F4IO
;
; --------------------------------------
;
; INITIALIZE CHANNEL I/O TABLE
;
INIT:
	MVI	B,6*MAXCH
	LXI	D
	RET
;
LL7:
	MVI	A,2	; ILLEGAL OPERATION STATUS
	RET
;
; ---------------------------------
;
;	 READ OPERATION
;
LL10:
	MOV	A,B	; GET CHANNEL STATUS
	DCR	A
	JZ	LL11	; JUMP IF CLOSED
	DCR	A
	JZ	LL12	; JUMP IF OPEN FOR READ
	DCR	A
	JZ	LL7	; WRITE OPERATION
;	REGISTER	BEFORE		AFTER
;	    A		   1		STATUS
;	    B		CHANNEL
;	   HL		START OF LINE
;	BUFFER		LENGTH
;			LINE DATA
;
; CLOSE/REWIND OPERATION
;	REGISTER	BEFORE		AFTER
;	    A		  0		STATUS
;	    B		CHANNEL
;
IOOP:
	STA	JOP	  KCH+1  READ ACCESS
;		0 - ILLEGAL
;		1 - CHANNEL AVAILABLE FOR READ
;
;	W  KCH+2  WRITE ACCESS
;		0 - ILLEGAL
;		1 - MACHINE READABLE OUTPUT
;		2 - HUMAN READABLE OUTPUT
;		3 - FIRST LINE OF HUMAN READABLE OUTPUT
;		    ALLOWS TOP OF FORM
;
;	D	D
	MOV	A,M	; CONTROL ACCESS = JCHAN(KCH+4)
;
	ORA	A
	JZ	LL3	; JUMP IF CONTROL OPERATION UNAVAILABLE
;
	PUSH	D	; SAVE KCH
	CALL	ICNTL	; PERFORM CONTROL OPERATION
	POP	D	; RESTORE KCH
	RET
;
LL3:
	LXI	H,JCHAN+6  ; SET CHANNEL STATUS TO INACTIVE-------
;
;	I/O SUPERVISOR
;
;  OPERATION CODE
;	0 - CLOSE
;	1 - WRITE
;      -1 - READ
;
;  OPERATION STATUS
;	0 - NORMAL
;	1 - EOF OR END OF MEDIUM
;	2 - ILLEGAL OPERATION
;	3+  ERROR CODE
;
;  STATUS = IOOP ( OPERATION , CHANNEL , BUFFER ,CHAN
	LXI	H,JCHAN+1
;
INIT1:
	LDAX	D
	MOV	M,A
	INX	D
	INX	H
	DCR	B
	JNZ	INIT1
;
	CALL	FINIT	; GET FILES FROM COMMAND LINE
	RET
;
; -----------------------------------------
;
; INITIAL VALUES FOR CHANNEL CONTROL TABLE
;
CHAN:
;		R W O CIF CHANNEL > MAX CHANNEL
;
	CALL	MCHOFF	; MAKE CHANNEL OFFSET
	XCHG
	SHLD	CHOFF	; CHANNEL OFFSET
	XCHG
;
	LXI	H,JCHAN+6  ; STATUS = JCHAN(KCH+6)
	DAD	D
	MOV	A,M
	ORA	A
	JZ	LL7	; JUMP IF STATUS = UNAVAILABLE
;
	MOV	B,A	; SAVE CHANNEL STATUS
	L; SAVE OPERATION CODE
	SHLD	POINT	; SAVE BUFFER POINTER
	MOV	A,B
	STA	NCHAN	; SAVE CHANNEL NUMBER
	ORA	A	; TEST CHANNEL NUMBER
	JM	LL7	; JUMP IF < 0   ERROR CONDITION
	JZ	LL5	; JUMP IF = 0   NULL CHANNEL   BIT BUCKET
;
	CPI	MAXCH+1
	JP	LL7	; JUMP O  KCH+3  OPEN ACCESS
;		0 - NO ACTION REQUIRED
;		1 - OPEN REQUIRED
;
;	C  KCH+4  CONTROL ACCESS (CLOSE)
;		0 - NO ACTION REQUIRED
;		1 - CLOSE REQUIRED
;
;	U  KCH+5  DEVICE CODE
;		0 - NULL DEVICE
;		1 - DISK
;		2 - CONSOLE
;		3 - LIST DEVICE
	DAD	D
	MVI	M,1	;    JCHAN(KCH+6) = 1
;
LL4:			; NORMAL TERMINATION
	XRA	A	;    SET OPERATION STATUS TO ZERO
	RET
;
LL5:			; NULL CHANNEL I/O
	LDA	JOP
	ORA	A
	JP	LL4	; JUMP IF NOT READ OPERATION
;
LL6:
	MVI	A,1	; EOF STATUS OR END OF MEDIUM)
;		      (A)        (B)      (HL)     
;
;	MAXLEN:	DB	N
;	LENGTH:	DS	1
;	BUFFER:	DS	N+1
;
; READ OPERATION
;	REGISTER	BEFORE		AFTER
;	    A		  -1		STATUS
;	    B		CHANNEL
;	   HL		START OF LINE	
;	BUFFER		MAXLEN		LENGTH
;					LINE DATA
;
; U S
	DB	1,0,1,1,2,1	;	CHANNEL 1 - INPUT FILE
	DB	1,1,1,1,1,1	;	CHANNEL 2 - SCRATCH FILE
	DB	0,1,1,1,2,1	;	CHANNEL 3 - OUTPUT FILE
	DB	0,1,1,1,3,1	;	CHANNEL 4 - LISTING FILE
	DB	1,1,0,0,2,4	;	CHANNEL 5 - CONSOLE I/O
;
MAXCH	EQU	($-CHAN)/6
;
;
;	RDA	JOP
	ORA	A
	JM	LL10	; JUMP IF READ OPERATION
	JNZ	LL20	; JUMP IF WRITE OPERATION
;
; -------------------------------------
;
;	 CONTROL OPERATION
;
	MOV	A,B	; GET CHANNEL STATUS
	CPI	1
	JZ	LL4	; JUMP IF STATUS = CLOSED
;
	LXI	H,JCHAN+4
	DAEADING
	NOP
	RET
;
; --------------------------------------
;
; SET FLUB MEMORY BOUNDS
;	DE  LOW LIMIT
;	HL  HIGH LIMIT
;
MEMSET:	LHLD	0006H	; GET BDOS ENTRY ADDRESS
	DCR	H	; ONE PAGE LESS TO BE SAFE
	RET
;
; ---------------------------------
;
;	S  KCH+6  CHANNEL STATUS
;		0 - NOT AVAILABLE
;		1 - CLOSED
;		2 - OPEN FOR READ
;		3 - OPEN FOR WRITE
;		5 - END OF FILE ON READ
;		    END OF MEDIUM ON WRITE
;
; -------------------------------------
;
TRAP:	NOP		; TRAP AT END OF MACRO R JUMP IF OPEN FOR WRITE   ERROR
	DCR	A
	JZ	LL12	; JUMP IF OPEN FOR BOTH READ AND WRITE
	DCR	A
	JZ	LL6	; JUMP IF END OF FILE
	JMP	LL7	; ERROR
;
LL11:
	LXI	H,JCHAN+1
	DAD	D
	MOV	A,M	; GET READ ACCESS PERMISSION
;
	ORA	A
	JZ	LL7	; JUMP IF READINGR
IWRTA:
IWRTB:	CALL	GBPDEV	; HL - BUFFER POINTER
	ORA	A	; A  - DEVICE CODE
	RZ		; RETURN IF 0 - NULL DEVICE

	DCR	A
	JZ	IWRT1	; JUMP IF 1 - DISK DEVICE

	DCR	A
	JZ	IWRT2	; JUMP IF 2 - CONSOLE OUT

	DCR	A
	JZ	IWRT3	; JUMP IF 3 - LIST DEVICE
NTER
	DW	0	; ACTUAL LINE LENGTH POINTER
;
; GET LINE FROM CONSOLE
;
IRED2:	XCHG
	DCX	D
	DCX	D
	CALL	CIB	; INPUT BUFFER FROM CONSOLE
	MVI	E,0AH
	CALL	CO	; SEND LINE FEED TO CONSOLE
	LHLD	POINT
	MOV	A,M
	CPI	1AH	; CONTROL Z
	JZ	IREOF	; JUMP IF 	JZ	LL21	; JUMP IF CLOSED
	DCR	A
	JZ	LL7	; JUMP IF OPEN FOR READ
	DCR	A
	JZ	LL22	; JUMP IF OPEN FOR WRITE
	DCR	A
	JZ	LL22	; JUMP IF OPEN FOR READ OR WRITE
	DCR	A
	JZ	LL6	; JUMP IF AT END OF MEDIUM
	JMP	LL7	; ERROR
;
LL21:
	LXI	H,JCHAN+2
	DAD	DET
;
; -------------------------------------
;
;	BUFFER WRITE ROUTINE
;
IWRIT:
	LXI	H,JCHAN+2	; GET WRITE ACCESS
	DAD	D
	MOV	B,M	; JHOW = JCHAN(KCH+2)
;
	DCR	B
	JZ	IWRTB	; JUMP IF JHOW = 1  MACHINE READABLE FILE
;
	DCR	B
	JZ	IWRTA	; JUMP IF K

	DCR	A
	JZ	IRED2	; JUMP IF 2 - CONSOLE IN

IRED0:	MVI	A,1	; END OF FILE OR ERROR CONDITION
	RET
;
;
IRED1:	PUSH	H
	DCX	H
	SHLD	ARGLST+2  ; SET LENGTH POINTER
	DCX	H
	SHLD	ARGLST	  ; SET MAX LENGTH POINTER
	CALL	GFTAB	; HL = FILE TABLE POIN NOT ALLOWED
;
	LXI	H,JCHAN+6
	DAD	D
	MVI	M,2	; SET CHANNEL STATUS OPEN FOR READ
;
	LXI	H,JCHAN+3
	DAD	D
	MOV	A,M	; GET OPEN ACCESS FOR CHANNEL
	ORA	A
	JZ	LL12	; JUMP IF OPEN NOT REQUIRED
;
	PUSH	D	; SAVE KCH
	LXI	B,IACCE	; READ ACCESS
	CALL	P
	MVI	C,','
	CALL	SCAN
	JZ	MORE2	; JUMP IF ',' FOUND

	MVI	A,1	; END OF FILE
	RET

MORE2:	INX	H
	SHLD	FNPTR1	; IP = P+1

	CALL	GDEVIC	; GET DEVICE CODE
	DCR	A
	JNZ	MORE3	; JUMP UNLESS 1 - DISK

	CALL	GFTAB	; HL = FILE TABLE POINTER
	CALL	DFIRST CHAR IN BUFFER IS ^Z

	XRA	A	; NO ERROR
	RET
;
; ------------------------------------
;
; CHECK FOR CHANNEL 1 MULTIPLE INPUTS
;
MORE:	LDA	NCHAN
	DCR	A
	JZ	MORE1	; JUMP IF CHAN 1

	MVI	A,1	; END OF FILE
	RET

MORE1:	LHLD	FNPTR1	; P = I
	MOV	A,M	; GET WRITE ACCESS
	ORA	A
	JZ	LL7	; JUMP IF WRITING NOT POSSIBLE
;
	LXI	H,JCHAN+6
	DAD	D
	MVI	M,3	; SET CHANNEL OPEN FOR WRITE
;
	LXI	H,JCHAN+3
	DAD	D
	MOV	A,M	; GET OPEN ACCESS
	ORA	A
	JZ	LL22	; JUMP IF NO OPEN REQUIRED
;
	PUSH	D	JHOW = 2  HUMAN READABLE OUTPUT
;
;	***	MAYBE OUTPUT FORM FEED
	MVI	M,2	; SET JHOW TO 2   TOP OF FORM DONE
	CALL	GBPDEV	; HL - BUFFER POINTER
	CPI	3	; A  - DEVICE CODE
	JNZ	IWRT1	; JUMP UNLESS LIST DEVICE

	MVI	E,0CH
	CALL	LO	; FORM FEED TO PRINTETER
	POP	D	; DE = BUFFER POINTER
	LXI	B,ARGLST
	CALL	LREAD	; READ LINE
	ORA	A
	RZ		; RETURN IF NO ERROR OR EOF

IREOF:	CALL	MORE	; CHECK FOR CHAN 1 MULTIPLE INPUTS
	JZ	IREAD	; JUMP IF ANOTHER INPUT FILE

	RET

ARGLST:	DW	0	; MAX LINE LENGTH POIIOPEN
	POP	D
	ORA	A
	RNZ		; RETURN IF OPEN ERROR
;
LL12:
	PUSH	D	; SAVE KCH
	CALL	IREAD	; PERFORM READ OPERATION
	POP	D
	JMP	LL30
;
; -------------------------------------
;
;	 WRITE OPERATION
;
LL20:
	MOV	A,B	; GET CHANNEL STATUS
	DCR	A
CLOSE	; CLOSE DISK FILE

MORE3:	LHLD	FNPTR
	MVI	B,1
	CALL	XDEVC	; LU(1) = XUNIT(IP)
	ORA	A
	JZ	MORE8	; ERROR IF NUL:

	CPI	3
	JZ	MORE	; ERROR IF LIST DEVICE

	LXI	B,IACCE
	CALL	IOPEN	; OPEN FILE IF DISK
	RET

MORE8:	MVI	A,1	; END OF FILE
	RD
	MVI	M,5	; SET STATUS TO EOF OR EOM
	RET
;
; --------------------------------------
;
;	BUFFER READ ROUTINE
;
IREAD:	CALL	GBPDEV	; HL = BUFFER POINTER
	ORA	A	; A  = DEVICE CODE
	JZ	IRED0	; JUMP IF 0 - NULL

	DCR	A
	JZ	IRED1	; JUMP IF 1 - DIS; SAVE KCH
	LXI	B,OACCE	; WRITE ACCESS
	CALL	IOPEN
	POP	D
	ORA	A
	RNZ		; RETURN IF OPEN ERROR
;
LL22:
	PUSH	D	; SAVE KCH
	CALL	IWRIT	; PERFORM WRITE OPERATION
	POP	D
;
;
LL30:
	CPI	1
	RNZ		; RETURN IF NOT EOF OR EOM
;
	LXI	H,JCHAN+6
	DAD	
	MVI	A,1	; ERROR CONDITION
	RET
;
;
IWRT1:	LHLD	POINT	; RECALL BUFFER POINTER
	LDA	NCHAN	; RECALL CHANNEL NUMBER
	CPI	5
	JZ	IWRT2	; JUMP IF CONSOLE CHANNEL

	PUSH	H
	CALL	GFTAB	; HL = FILE TABLE POINTER
	POP	D	; DE = BUFFER POINTER
	MOV	B,D
	PTR3
	MVI	B,3
	CALL	XDEVC	; LU(3) = XUNIT(OP)

	LHLD	FNPTR4
	MVI	B,4
	CALL	XDEVC	; LU(4) = XUNIT(LP)

	XRA	A	; NO COMMAND ERROR DETECTED
	RET

FPRS8:	ORI	1	; COMMAND ERROR DETECTED
	RET
;
; -------------------------------------
;
SCAN:	MOV		M,A
	INX	H
	INX	D
	DCR	C
	JNZ	FINIT1

FINIT2:	MVI	M,0	; TERMINATE LINE WITH NULL
	CALL	FINIT3	; CONVERT TO UPPER CASE
	CALL	FPRS	; PARSE COMMAND LINE
	RZ		; RETURN IF NO COMMAND LINE ERROR

	LXI	D,COMERR
	CALL	COB	; ERROR MESSAGE TO CONSOLE
	
	MOV	E,M
	PUSH	B
	PUSH	H
	CALL	LO
	POP	H
	POP	B
	JMP	IWRT3L

IWRT3D:	MVI	E,0DH
	CALL	LO
	MVI	E,0AH
	CALL	LO
	XRA	A
	RET
;
; -------------------------------------
;
;	OPEN CHANNEL
;
IOPEN:
	PUSH	B	; BC POINTS TO ACCESS CODE
	CALL	GFTAM,0	; MEM(P) = 0
	INX	H	; P = P + 1
	SHLD	FNPTR1	; IP = P

	LXI	H,COMLIN  ; P = ^COM
	SHLD	FNPTR3	; OP = ^CHANNEL 3 SPECIFICATION
	MVI	C,','
	CALL	SCAN
	JZ	FPRS2	; JUMP IF ',' FOUND

	LXI	H,FNLST
	SHLD	FNPTR4	; LP = ^'LST:'
	JMP	FPRS3

FPRS2:HANNEL OFFSET
	XCHG
	LXI	H,JCHAN+5
	DAD	D	; ADD CHANNEL OFFSET
	MOV	A,M	; DEVICE CODE
	LHLD	POINT
	RET
;
; ---------------------------------
;
; GET FILE TABLE POINTER
;
GFTAB:	LDA	NCHAN	; GET CHANNEL NUMBER
	DCR	A
	ADD	A
	MOV	E,A
	MVI	D,0MOV	C,E
	DCX	B	; BC = POINTER TO LINE LENGTH
	CALL	LWRITE	; WRITE LINE
	ORA	A
	RZ		; RETURN IF NO ERROR

	MVI	A,1
	RET
;
; SEND LINE TO CONSOLE
;
IWRT2:	DCX	H
	MOV	C,M	; GET LINE LENGTH
	INR	C

IWRT2L:	DCR	C
	JZ	IWRT2D

	INX	H
	MOV	E,M
 LINE

	MOV	A,M	; GET CHARACTER
	CALL	FINIT5	; CONVERT IF LOWER CASE
	MOV	M,A
	JMP	FINIT4

FINIT5:	CPI	'A'+20H
	RC		; RETURN IF < 'a'
	CPI	'Z'+21H
	RNC		; RETURN IF > 'z'
	SUI	20H
	RET
;
; --------------------------------------
;
; PARSE COLXI	D,COMLIN-2
	CALL	CIB	; GET NEW COMMAND LINE
	LXI	H,COMLIN-1
	MOV	E,M	; GET LINE LENGTH
	MVI	D,0
	INX	H
	DAD	D
	JMP	FINIT2


FINIT3:	LXI	H,COMLIN-1
	MOV	C,M	; LENGTH OF COMMAND LINE
	INX	H
	INR	C

FINIT4:	DCR	C
	RZ		; RETURN IF AT END OFB	; HL = FILE TABLE POINTER
	PUSH	H
	CALL	FNAME	; DE = FILE NAME POINTER
	POP	H
	POP	B
	RZ		; RETURN UNLESS DISK DEVICE

	CALL	DOPEN	; OPEN FILE
	ORA	A
	RZ		; RETURN IF NO ERROR

	MVI	A,1
;	***	***	ERROR MESSAGE
	RET
;
; --------------------	MVI	M,0	; MEM(P) = 0
	INX	H	; P = P + 1
	SHLD	FNPTR4	; LP = ^CHANNEL 4 SPECIFICATION

FPRS3:	LHLD	FNPTR1
	MVI	B,1
	CALL	XDEVC	; LU(1) = XUNIT(IP)
	ORA	A
	JZ	FPRS8	; ERROR IF NUL: SPECIFIED

	CPI	3
	JZ	FPRS8	; ERROR IF LST: SPECIFIED

	LHLD	FN
	LXI	H,FTABP
	DAD	D
	MOV	A,M
	INX	H
	MOV	H,M
	MOV	L,A
	RET
;
; -------------------------------------
;
; GET FILE NAMES FROM COMMAND LINE
;
FINIT:	LXI	D,80H
	LXI	H,COMLIN-1
	LDA	80H
	INR	A
	MOV	C,A	; # OF CHARACTERS

FINIT1:	LDAX	D
	MOV	PUSH	B
	PUSH	H
	CALL	CO
	POP	H
	POP	B
	JMP	IWRT2L

IWRT2D:	MVI	E,0DH
	CALL	CO
	MVI	E,0AH
	CALL	CO
	XRA	A	; NO ERROR
	RET
;
; SEND LINE TO LIST DEVICE
;
IWRT3:	DCX	H
	MOV	C,M	; GET LINE LENGTH
	INR	C

IWRT3L:	DCR	C
	JZ	IWRT3D

	INX	HMMAND LINE
;
FPRS:	LXI	H,COMLIN  ; P = ^COM
	MVI	C,'='
	CALL	SCAN
	JZ	FPRS1	; JUMP IF '=' FOUND

	LXI	H,COMLIN
	SHLD	FNPTR1	; IP = ^COM
	LXI	H,FNCON
	SHLD	FNPTR3	; OP = ^'CON:'
	LXI	H,FNLST
	SHLD	FNPTR4	; LP = ^'LST:'
	JMP	FPRS3

FPRS1:	MVI		DCLOSE	; CLOSE FILE
	ORA	A
	RZ		; RETURN IF NO ERROR

	MVI	A,1
	RET

ICNT3:
	XRA	A	; SET OPERATION STATUS = 0
	RET
;
; ------------------------------------
;
; GET BUFFER POINTER & DEVICE CODE NUMBER
;		HL	A
;
GBPDEV:	LHLD	CHOFF	; RECALL C------------------
;
;	CLOSE CHANNEL
;
ICNTL:	CALL	GBPDEV	; HL - BUFFER POINTER
	CPI	1	; A  - DEVICE CODE
	JNZ	ICNT3	; JUMP UNLESS 1 - DISK DEVICE

	LXI	H,JCHAN+6
	DAD	D
	MVI	M,1	; SET STATUS CLOSED

	CALL	GFTAB	; HL = FILE TABLE POINTER
	CALLA,M
	CMP	C
	RZ		; RETURN IF SEARCH SUCCESSFUL

	ORA	A
	JZ	SCAN1	; JUMP IF END OF STRING

	INX	H
	JMP	SCAN

SCAN1:	INR	A	; Z=0 - SEARCH FAILS
	RET
;
; -------------------------------------
;
; GET FILE NAME POINTER FOR OPEN
;
FNAME:	CALL	GDLINE, WRITE LINE, GENERAL CLOSE
;
;	3. ALLOW THE FOLLOWING FOR FILE NAMES:
;		CON:  - CONSOLE  IN/OUT
;		RDR:  - READER   IN
;		PUN:  - PUNCH       OUT
;		LST:  - LISTING     OUT
;
;
; TO OPEN DISK FILE
;	ERROR IF FILE ALREADY OPEN
;	ERROR IF BAODE
POINT:	DS	2	; BUFFER POINTER
NCHAN:	DS	1	; STORAGE FRO CHANNEL NUMBER
LEN:	DS	1	; LINE LENGTH
CHOFF:	DS	2	; CHANNEL TABLE OFFSET
;
IACCE:	DB	1	; READ ACCESS CODE
OACCE:	DB	3	; WRITE ACCESS CODE WITH DELETE

FTABP:	DW	FTAB1
	DW	FTAB2
	DW	FTAB
	JZ	XDEVC4	; JUMP IF , = OR NULL FOUND

	PUSH	H
	LXI	D,XDVTBL-2  ; SPECIAL DEVICE CODE TABLE

XDEVC2:	INX	D
XDEVC1:	INX	D
XDEVC0:	LDAX	D
	MOV	C,A
	CPI	1
	JZ	XDEVC3	; JUMP IF END OF TABLE

	POP	H
	PUSH	H
	INX	D

	LDAX	D
	INX	D
	CMP	M
	JDITIONS
;
;DREV EQU 20H ;	08/17/78  R. CURTISS	INITIAL CODING
;
;DREV EQU 15H ;	07/26/78  R. CURTISS	BWRITE - MVI A,0 JNZ
;
;DREV EQU 14H ;	07/25/78  R. CURTISS	OPEN- NR=0
;
;DREV EQU 13H ;	07/25/78  R. CURTISS	FIX ERROR IN READ
;					AND OTHER CH--
;
MCHOFF:	DCR	B	; COMPUTE CHANNEL OFFSET
	MOV	A,B	;    FOR TABLE LOOKUP
	RLC		;    KCH = (JCH-1)*6
	ADD	B
	RLC
	MOV	E,A
	MVI	D,0
	RET
;
; -------------------------------------
;
; CONSOLE I/O
;
BDOS	EQU	0005H

CIB:	MVI	C,10
	CALL	BDOSEVIC	; GET DEVICE CODE
	CPI	1
	JZ	FNAME1	; JUMP IF DISK DEVICE

	XRA	A
	RET

FNAME1:	LDA	NCHAN
	DCR	A
	ADD	A
	MOV	E,A
	MVI	D,0
	LXI	H,FNPTR  ; FILE NAME POINTER TABLE
	DAD	D
	MOV	E,M
	INX	H
	MOV	D,M
	MVI	A,1
	ORA	A
	RET

GDEVIC:	LHLD	C'STAGE2.CH2',0

FNNUL:	DB	'NUL:',0
FNCON:	DB	'CON:',0
FNLST:	DB	'LST:',0

	DB	128,0
COMLIN:	DS	129	; STORAGE FOR COMMAND LINE

COMERR:	DB	0DH,0AH,'>>>>> COMMAND ERROR - REENTER'
	DB	0DH,0AH,'$',0
;
;
3
	DW	FTAB4

FTAB1:	DB	0,0,0,'1'	; CHAN 1 FILE TABLE
	DS	33+128

FTAB2:	DB	0,0,0,'2'
	DS	33+128

FTAB3:	DB	0,0,0,'3'
	DS	33+128

FTAB4:	DB	0,0,0,'4'
	DS	33+128

FNPTR:
FNPTR1:	DS	2
FNPTR2:	DW	FNCH2
FNPTR3:	DS	2
FNPTR4:	DS	2

FNCH2:	DB	NZ	XDEVC2	; JUMP IF NO MATCH

	INX	H
	LDAX	D
	INX	D
	CMP	M
	JNZ	XDEVC1	; JUMP IF NO MATCH

	INX	H
	LDAX	D
	INX	D
	CMP	M
	JNZ	XDEVC0	; JUMP IF NO MATCH

	INX	H	; TABLE MATCH FOUND
	MVI	A,':'
	CMP	M
	JZ	XDEVC3	; JUMP IF COLON

	MVI	C,1	; DANGES
;
;DREV EQU 12H ;	07/01/78  R. CURTISS	FIX ERRORS
;
;DREV EQU 11H ;	07/01/78  R. CURTISS	INITIAL CODING
;
; CP/M DISK I/O PACKAGE
;	1. INITIAL IMPLEMENTATION
;	  OPEN, CLOSE, READ BYTE, WRITE BYTE
;
;	2. NEXT STAGE OF DEVELOPMENT
;	  READ 
	RET

COB:	MVI	C,9
	CALL	BDOS
	RET

CO:	MVI	C,2
	CALL	BDOS
	RET

LO:	MVI	C,5
	CALL	BDOS
	RET
;
; ------------------------------------
;
;	STORAGE
;
JCHAN:	DS	6*MAXCH+1  ; WORKING STORAGE FOR I/O TABLE
JOP:	DS	1	; STORAGE FOR OPERATION CHOFF	; CHANNEL TABLE OFFSET
	LXI	D,JCHAN+5
	DAD	D
	MOV	A,M
	RET
;
; --------------------------------------
;
;	HL - POINTER TO FILE NAME
;	B  - CHANNEL NUMBER

;	A  - DEVICE CODE NUMBER
;
XDEVC:	CALL	SKIPB	; SKIP BLANKS
	MVI	C,0	; NULL DEVICEDREV EQU 24H ;	06/13/79  R. CURTISS	"," FOR DELIMITER ALSO

;DREV EQU 23H ;	06/10/79  R. CURTISS	DCLOSE XRA A, NOT IF READ

;DREV EQU 22H ;	08/19/78  R. CURTISS	DEF. DMA = 80 AFTER
;					READS AND WRITES
;DREV EQU 21H ;	08/19/78  R. CURTISS	GCLOSE ADL'
	DB	2,'CON'
	DB	2,'TTY'
	DB	2,'CRT'
	DB	2,'KBD'
	DB	3,'LST'
	DB	3,'LPT'
	DB	1
;
;
SKIPB:	MOV	A,M
	ORA	A
	RZ

	SUI	','
	RZ

	MOV	A,M
	SUI	'='
	RZ

	MOV	A,M
	CPI	' '
	RNZ

	INX	H
	JMP	SKIPB
;
; ---------------------------------ISK DEVICE ASSUMED

XDEVC3:	POP	H	; RESTORE STACK

XDEVC4:	PUSH	B	; B - CHAN #   C - DEVICE CODE #
	CALL	MCHOFF	; MAKE CHANNEL OFFSET POINTER
	POP	B
	LXI	H,JCHAN+5
	DAD	D
	MOV	M,C	; JCHAN(CH+5) = DEVICE CODE
	MOV	A,C
	RET
;
;
XDVTBL:	DB	0,'NUD FILE NAME
;	SELECT ( ACCESS )
;	   ( 1 = READ ) CONTINUE
;	   ( 3 = WRITE )
;		ACCESS = 2
;		DELETE FILE IF PRESENT
;		CREATE FILE
;		ERROR IF NO DIRECTORY SPACE
;		FIN
;	   ( 2 = WRITE )
;		ERROR IF FILE IS PRESENT
;		CREATE FILE
;		ERROR IFATION STATUS
;	(Z)     = CONDITION OF (A)
;
GCLOSE:	LDA	LSIZE	; RECALL OPEN FILE COUNT
	ORA	A
	RZ		; RETURN IF LIST IS EMPTY

	LXI	H,FLIST	; GET FIRST FILLE TABLE POINTER
	MOV	E,M
	INX	H
	MOV	D,M
	XCHG
	CALL	DCLOSE	; CLOSE AND DELETE FILE FROM :
;    (HL) POINTS TO FILE TABLE ORIGIN
;
;  OUTPUTS:
;    (A)=(HL)= OPERATION STATUS
;    (Z)     = CONDITION OF (A)
;
DCLOSE:	SHLD	FTABLE	; SAVE FILE TABLE POINTER

	MOV	A,M	; GET ACCESS CODE FROM FILE TABLE
	CPI	2
	JNZ	CLOSE1	; JUMP IF NOT OPRATING SYSTEM
 

	DB	DREV	; PUT REVISION NUMBER IN CODE


DOPEN:	SHLD	FTABLE	; SAVE FILE TABLE POINTER

	MOV	A,M	; GET ACCESS CODE FROM FILE TABLE
	CPI	0
	JNZ	ERR	; JUMP IF FILE ALREADY OPEN

	LDAX	B	; GET OPEN ACCESS CODE
	STA	ACCESS

	LHLDTER
	ANI	7FH	; MSB SHOULD BE 0 BUT BE SAFE
	RZ		; RETURN IF BUFFER IS EMPTY (Z)=1

	LXI	D,BUFF+127-2  ; -2 FOR 2 (INX HL) ABOVE
	DAD	D	; (HL) POINTS TO LAST BUFFER BYTE
	CMA
	ADI	128+1	; PAD COUNT = 128 - POINTER

CLOSE6:	MVI	M,1AH	; PAD BUFFER WID
	MVI	M,0	; NEXT RECORD NUMBER IN FCB
 
	CALL	GCLADD	; ADD FILE TABLE TO OPEN LIST

	LHLD	FTABLE	; RECALL FILE TABLE POINTER
	LDA	ACCESS
	MOV	M,A	; SET ACCESS CODE IN FILE TABLE

	INX	H
	XRA	A
	MOV	M,A	; SET STATUS TO ZERO (NORMAL)

	INX	H
	 NO DIRECTORY SPACE
;		FIN
;	   ( OTHER ) ERROR  ILLEGAL ACCESS CODE
;	   FIN
;	OPEN FILE
;	ERROR IF NOT PRESENT
;	STATUS = 0   NORMAL
;	POINTER = 0    BUFFER EMPTY
;	FIN
;
;  INPUTS:
;    (HL) POINTS TO FILE TABLE ORIGIN
;    (DE) POINTS TO FI	ERR	; JUMP IF INVALID ACCESS CODE

CLOSE2:	CALL	GCLREM	; REMOVE FILE TABLE FROM OPEN LIST

	LHLD	FTABLE	; RECALL FILE TABLE POINTER
	XRA	A
	MOV	C,M	; GET ACCESS CODE
	MOV	M,A	; ACCESS = 0 - FILE NOT OPEN

	INX	H
	MOV	M,A	; STATUS = 0 - NORMAL
EN FOR WRITE

	CALL	CLOSE4	; OUTPUT LAST BUFFER IF NOT EMPTY
	JZ	CLOSE2	; JUMP IF NO WRITE ERROR

	PUSH	PSW	; SAVE ERROR CONDITION
	CALL	CLOSE2	; CLOSE THE FILE
	POP	PSW
	JMP	ERR

CLOSE1:	ORA	A
	JZ	RETURN	; JUMP IF ALREADY CLOSED

	CPI	1
	JNZ	FTABLE	; RECALL FILE TABLE POINTER
	LXI	B,FCBOFF  ; FCB OFFSET IN FILE TABLE
	DAD	B
	CALL	GETNAM	; GET FILE NAME
	JNZ	ERR	; JUMP IF NAME ERROR

	LDA	ACCESS
	DCR	A
	JZ	OPEN6	; JUMP IF READ ACCESS DESIRED

	CPI	2
	JNZ	OPEN2	; JUMP IF NOT WRITE WITH CONTROL Z
	DCX	H
	DCR	A
	JNZ	CLOSE6

	CALL	WRITE2	; OUTPUT LAST BUFFER
	RET		; (Z)=1 IF WRITE IS OK
;
;
; TO CLOSE ALL OPEN FILES
;	FOR EACH OPEN FILE
;	    CLOSE FILE
;	    FIN
;	FIN
;
;  INPUTS:
;	NONE
;
;  OUTPUTS:
;	(A)=(HL)= OPERMOV	M,A	; SET BUFFER POINTER TO ZERO

	JMP	RETURN
;
;
; TO CLOSE FILE
;	OUTPUT LAST BUFFER IF OPEN FOR WRITE
;	ERROR IF ACCESS < 1 OR > 2
;	CLOSE FILE IF OPEN FOR WRITE
;	ERROR IF NOT PRESENT
;	ACCESS = 0
;	BUFFER POINTER = 0
;	FIN
;
;  INPUTLE NAME STRING
;    (BC) POINTS TO ACCESS CODE
;
;  OUTPUTS:
;    (A)=(HL)= OPERATION STATUS
;    (Z)     = CONDITION OF (A)
;
;
FCBOFF	EQU	4	; FCB OFFSET IN FILE TABLE
BUFF	EQU	37	; BUFFER OFFSET IN FILE TABLE
BDOS	EQU	0005H	; ENTRY POINT TO OPE
	INX	H
	MOV	M,A	; BUFFER POINTER = 0

	DCR	C
	JZ	RETURN	; JUMP IF OPEN FOR READ

	MVI	C,16
	CALL	BDOS1	; CLOSE FILE
	CPI	255
	JZ	ERR	; JUMP IF FILE NOT PRESENT

	XRA	A	; NO ERROR
	JMP	RETURN

CLOSE4:	INX	H
	INX	H
	MOV	A,M	; GET BUFFER POIN PRESENT

OPEN4:	MVI	C,22
	CALL	BDOS1	; CREATE FILE
	CPI	255
	JZ	ERR	; JUMP IF NO DIRECTORY SPACE

OPEN6:	MVI	C,15
	CALL	BDOS1	; OPEN FILE
	CPI	255
	JZ	ERR	; JUMP IF NOT PRESENT

	LHLD	FTABLE	; RECALL FILE TABLE POINTER
	LXI	D,FCBOFF+32
	DAD	TH DELETE

	STA	ACCESS	; ACCESS = 2

	MVI	C,19
	CALL	BDOS1	; DELETE FILE IF PRESENT

	JMP	OPEN4

OPEN2:	CPI	1
	JNZ	ERR	; JUMP IF INVALID ACCESS CODE

	MVI	C,17
	CALL	BDOS1	; CHECK TO SEE IF FILE IS PRESENT
	CPI	255
	JNZ	ERR	; JUMP IF FILE ISLIST
	JMP	GCLOSE
;
;
;	ADD FILE TABLE TO OPEN FILE LIST
;
GCLADD:	LDA	LSIZE	; GET OPEN FILE COUNT
	CPI	LMAX	; FILE LIST MAX SIZE
	JNC	GCLA9	; JUMP IF LIST IS FULL

	INR	A
	STA	LSIZE	; LSIZE = LSIZE + 1
	DCR	A
	ADD	A	; A = A*2
	MOV	E,A
	MVI	D    (HL) POINTS TO FILE TABLE ORIGIN
;    (DE) POINTS TO DATA BYTE STORAGE
;
;  OUTPUTS:
;    (A)=(HL)= OPERATION STATUS
;    (Z)     = CONDITION OF (A)
;    ((DE))  = DATA BYTE RETURNED
;
BREAD:	SHLD	FTABLE	; SAVE FILE TABLE POINTER
	XCHG
	SHLD	OR READ

	INX	H
	MOV	A,M	; GET STATUS CODE
	ORA	A
	JNZ	ERR	; JUMP IF NOT NORMAL

	INX	H	; (HL) POINTS TO BUFFER POINTER
	SHLD	BPOINT	; SAVE IT

LREAD1:	CALL	LREAD5	; GET NEXT BYTE FROM DISK
	JNZ	LREAD2	; JUMP IF EOL,EOF,ERR

	CALL	LREAD8	; STOIST

	MOV	A,M
	INX	H
	XRA	E
	MOV	B,A

	MOV	A,M
	INX	H
	XRA	D
	ORA	B
	JNZ	GCLR1	; JUMP IF NO MATCH

	MOV	D,H
	MOV	E,L
	DCX	D
	DCX	D

GCLR2:	DCR	C
	JZ	GCLR8	; JUMP IF END OF LIST

	MOV	A,M
	STAX	D
	INX	H
	INX	D
	MOV	A,M
	STAX	D	; LIETURN

LREAD6:	MVI	A,255	; END OF FILE

LREAD7:	ORA	A	; END OF LINE
	RET
;
;	STORE NEXT BYTE IN LINE
;
LREAD8:	INR	C
	DCR	C
	RZ		; RETURN IF LINE BUFFER FULL

	LHLD	LPOINT	; RECALL LINE BUFFER POINTER
	MOV	M,A
	INX	H
	SHLD	LPOINT
	DCR	C
	FILE TABLE POINTER
	XCHG
	SHLD	LPOINT	; SAVE LINE POINTER

	LXI	H,DBYTE
	SHLD	DATA	; DATA RETURN POINTER

	MOV	H,B
	MOV	L,C

	MOV	E,M
	INX	H
	MOV	D,M	; (DE) POINTS TO 3RD ARG

	XCHG
	MOV	C,M	; (C) HOLDS MAX LINE LENGTH
	MOV	A,C
	STA	CMAX	;,0
	LXI	H,FLIST
	DAD	D	; (HL) POINTS TO NEXT LIST ENTRY POS.

	XCHG
	LHLD	FTABLE	; RECALL FILE TABLE POINTER
	XCHG

	MOV	M,E
	INX	H
	MOV	M,D	; LIST(LSIZE) = FILE TABLE POINTER
	RET

GCLA9:	; ****************** NEED EROR MESSAGE
	RET
;
;
;	A
	JMP	RETURN	; NORMAL RETURN
;
;	GET NEXT BYTE
;
LREAD5:	LHLD	BPOINT	; RECALL BUFFER POINTER POINTER
	PUSH	B	; SAVE LINE SPACE COUNT
	CALL	BRXXX	; GET NEXT BYTE FROM DISK
	POP	B
	RNZ		; RETURN IF EOF,ERR

	LDA	DBYTE	; GET BYTE JUST READ
	ANI	7RE BYTE INTO LINE
	JMP	LREAD1

LREAD2:	PUSH	PSW	; SAVE READ STATUS
	LDA	CMAX	; RECALL MAX CHARACTER COUNT
	SUB	C
	LHLD	ACTP
	MOV	M,A	; RETURN ACTUAL CHARACTER COUNT
	POP	PSW

	CPI	0DH	; CARRIAGE RETURN
	JNZ	RETURN	; RETURN IF EOF OR ERR

	XRA	ST(M-1) = LIST(M)
	INX	H
	INX	D	; M = M + 1
	JMP	GCLR2

GCLR8:	LDA	LSIZE
	DCR	A
	STA	LSIZE
	RET

GCLR9:	; ****************** NEED ERROR MESSAGE
	RET
;
;
; TO READ A LINE
;	ERROR IF ACCESS <> "READ"
;	ERROR IF STATUS <> "NORMAL"
;	I = 1
;	RET
;
;
; TO READ BYTE
;	ERROR IF ACCESS <> "READ"
;	ERROR IF STATUS <> "ZERO"
;	IF ( BUFFER EMPTY )
;	   GET NEXT BUFFER LOAD
;	   POINT = 0
;	   RETURN IF "EOF"
;	   FIN
;	GET NEXT BYTE FROM BUFFER
;	POINT = POINT + 1
;	FIN
;
;  INPUTS:
; SAVE MAX LINE LENGTH
	XCHG

	INX	H
	MOV	E,M
	INX	H
	MOV	D,M	; (DE) POINTS TO 4TH ARG

	XCHG
	SHLD	ACTP	; SAVE POINTER FOR ACTUAL LENGTH

	LHLD	FTABLE	; RECALL FILE TABLE POINTER
	MOV	A,M	; GET ACCESS CODE
	CPI	1
	JNZ	ERR	; JUMP IF NOT OPEN FREMOVE FILE TABLE POINTER FROM OPEN FILE LIST
;
GCLREM:	LHLD	FTABLE	; RECALL FILE TABLE POINTER
	XCHG
	LXI	H,FLIST	; ORIGIN OF OPEN FILE LIST
	LDA	LSIZE	; RECALL OPEN FILE COUNT
	MOV	C,A
	INR	C

GCLR1:	DCR	C
	JZ	GCLR9	; JUMP IF END OF OPEN FILE LFH
	JZ	LREAD5	; IGNORE NULL

	CPI	0AH
	JZ	LREAD5	; IGNORE LINE FEED

	CPI	7FH
	JZ	LREAD5	; IGNORE RUBBOUT

	CPI	1AH	; CONTROL Z
	JZ	LREAD6	; JUMP IF END OF FILE

	CPI	0DH
	JZ	LREAD7	; JUMP IF CARRIAGE RETURN

	CMP	A	; (Z)=1
	RET		; NORMAL RE BUFFER ORIGIN
;	(BC) POINTS TO PARAMETER LIST
;		3RD  POINTS TO MAX CHARACTER COUNT (255 MAX)
;		4TH  POINTS TO ACTUAL CHARACTER COUNT (255 MAX)
;
;  OUTPUTS:
;	(A)=(HL)= OPERATION STATUS
;	(Z)     = CONDITION OF (A)
;
LREAD:	SHLD	FTABLE	; SAVE GET-NEXT-BYTE
;	UNTIL ( EOL,EOF,ERR )
;	    IF ( I <= MAX-CHARACTER-COUNT )
;		LINE(I) = BYTE
;		I = I + 1
;		FIN
;	    GET-NEXT-BYTE
;	    FIN
;	RETURN-ACTUAL-CHARACTER-COUNT
;	FIN
;
;  INPUTS:
;	(HL) POINTS TO FILE TABLE
;	(DE) POINTS TO LINDATA	; SAVE DATABYTE POINTER
	MVI	M,1AH	; TENTATIVELY RETURN CONTROL Z

	XCHG
	MOV	A,M	; GET ACCESS CODE
	CPI	1
	JNZ	ERR	; JUMP IF NOT READ ACCESS

	INX	H
	MOV	A,M	; GET STATUS CODE
	CPI	0
	JNZ	ERR	; JUMP IF NOT NORMAL

	INX	H

BRXXX:	MOV	A,	CPI	2	; END OF DISK
	RNZ		; RETURN IF ERROR (A)=1,>2  (Z)=0

	LHLD	FTABLE	; RECALL FILE TABLE POINTER
	INX	H
	MVI	A,255	; END OF MEDIUM
	MOV	M,A	; SET STATUS

	CPI	255	; SET ZERO FLAG FOR NO ERROR
	RET		; (A)=255  (Z)=1
;
;
; SCAN FILE NAME
;
	PUSH	H
	CALL	BWXXX	; WRITE CARRIAGE RETURN TO DISK
	POP	H
	RNZ		; RETURN IF WRITE ERROR

	MVI	B,0AH
	CALL	BWXXX	; WRITE LINE FEED TO DISK
	RET
;
;
; TO WRITE BYTE
;	ERROR IF ACCESS <> "WRITE"
;	ERROR IF STATUS <> "ZERO"
;	PUT BYTE INTO BUFFE IN BUFFER

	MOV	A,M	; GET NEXT DATA BYTE
	LHLD	DATA	; RECALL DATA RETURN POINTER
	MOV	M,A	; RETURN DATA BYTE TO CALLER

	XRA	A	; (A)=0   (Z)=1
	JMP	RETURN	; NORMAL RETURN


READ4:	MVI	C,26
	CALL	BDOS2	; SET DMA ADDRESS

	MVI	C,20
	CALL	BDOS1,BUFF-2  ; -2 FOR 2 (INX HL) ABOVE
	DAD	D	; (HL) = FTABLE+BUFF+POINT
	MOV	M,B	; STORE DATA BYTE INTO BUFFER

	CPI	0
	MVI	A,0	; NO ERROR
	JNZ	RETURN	; JUMP IF BUFFER NOT FULL

	CALL	WRITE2	; WRITE BUFFER TO DISK
	JNZ	ERR	; JUMP IF WRITE ERROR

	JE FILE TABLE POINTER

	MOV	A,M	; GET ACCESS CODE
	CPI	2
	JNZ	ERR	; JUMP IF NOT OPEN FOR WRITE

	INX	H
	MOV	A,M	; GET STATUS CODE
	ORA	A
	JNZ	ERR	; JUMP IF NOT NORMAL

	INX	H	; POINTS TO BUFFER POINTER

	LDAX	B	; CHARACTER COUNT
	MOV	C,A
	INRM	; GET BUFFER POINTER
	MOV	E,A	; SAVE CURRENT POINTER
	INR	A
	ANI	7FH
	MOV	M,A	; POINTER = (POINTER + 1) MOD 128

	MOV	A,E	; GET CURRENT POINTER
	ORA	A
	JNZ	READ2	; JUMP IF BUFFER NOT EMPTY

	CALL	READ4	; GET NEXT BUFFER LOAD
	JNZ	ERR	; JUMP IFZ)     = CONDITION OF (A)
;
BWRITE:	SHLD	FTABLE	; SAVE FILE TABLE POINTER
	LDAX	D	; GET DATA BYTE
	MOV	B,A	; SAVE IN B

	MOV	A,M	; GET ACCESS CODE
	CPI	2
	JNZ	ERR	; JUMP IF NOT WRITE ACCESS

	INX	H
	MOV	A,M	; GET STATUS CODE
	CPI	0
	JNZ	ERR	; R
;	POINT = POINT + 1
;	IF ( BUFFER FULL )
;	   WRITE NEXT BUFFER LOAD
;	   POINT = 0
;	   FIN
;	FIN
;
;  INPUTS:
;    (HL) POINTS TO FILE TABLE ORIGIN
;    (DE) POINTS TO DATA BYTE STORAGE
;
;  OUTPUTS:
;    (A)=(HL)= OPERATION STATUS
;    (	; READ NEXT DISK RECORD

	PUSH	PSW
	MVI	C,26
	LXI	D,80H
	CALL	BDOS	; RESTORE DMA ADDR TO DEFAULT
	POP	PSW

	ORA	A
	RZ		; RETURN IF OK  (Z)=1

	CPI	1	; EOF
	RNZ		; RETURN IF ERROR (A)>1  (Z)=0

	LHLD	FTABLE	; RECALL FILE TABLE POINTER
	INX	HMP	RETURN


WRITE2:	MVI	C,26
	CALL	BDOS2	; SET DMA ADDRESS

	MVI	C,21
	CALL	BDOS1	; WRITE NEXT DISK RECORD

	PUSH	PSW
	MVI	C,26
	LXI	D,80H
	CALL	BDOS	; RESTORE DMA ADDR. TO DEFAULT
	POP	PSW

	ORA	A
	RZ		; RETURN IF WRITE OK (A)=0  (Z)=1

	C

LWRIT1:	DCR	C
	JZ	LWRIT2	; JUMP IF END OF LINE

	PUSH	H
	PUSH	D
	PUSH	B
	LDAX	D	; GET NEXT DATA BYTE
	MOV	B,A
	CALL	BWXXX	; WRITE BYTE TO DISK
	POP	B
	POP	D
	POP	H
	RNZ		; RETURN IF WRITE ERROR

	INX	D
	JMP	LWRIT1

LWRIT2:	MVI	B,0DH READ ERROR

	ORA	A
	JNZ	RETURN	; JUMP IF END OF FILE

	MVI	E,0	; CURRENT POINTER

READ2:	LHLD	FTABLE	; RECALL FILE TABLE POINTER
	MVI	D,0	; (E) IS BUFFER POINTER
	DAD	D
	LXI	D,BUFF	; BUFFER OFFSET IN FILE TABLE
	DAD	D	; (HL) POINTS TO NEXT BYTEJUMP IF NOT NORMAL

	INX	H
;
;		(HL) POINTS TO BUFFER POINTER
;		(B)  DATA BYTE FOR OUTPUT
;
BWXXX:	MOV	A,M	; GET BUFFER POINTER
	MOV	E,A	; SAVE CURRENT POINTER
	INR	A
	ANI	7FH
	MOV	M,A	; POINTER = (POINTER+1) MOD 128

	MVI	D,0
	DAD	D
	LXI	DI)
;	    FIN
;	FIN
;
;  INPUTS:
;	(HL) POINTS TO FILE TABLE
;	(DE) POINTS TO LINE BUFFER ORIGIN
;	(BC) POINTS TO LINE LENGTH IN BYTES (255 MAX)
;
;  OUTPUTS:
;	(A)=(HL)= OPERATION STATUS
;	(Z)     = CONDITION OF (A)
;
LWRITE:	SHLD	FTABLE	; SAV
	MVI	A,255
	MOV	M,A	; SET STATUS TO "EOF"

	CPI	255	; EOF  (A)=255  (Z)=1
	RET		; END OF FILE DETECTED
;
;
; TO WRITE A LINE
;	ERROR IF ACCESS <> "WRITE"
;	ERROR IF STATUS <> "ZERO" "NORMAL"
;	FOR I = 1 TO LENGTH OF LINE
;	    WRITE BYTE LINE(  INPUTS:
;	(HL) POINTS TO FCB
;	(DE) POINTS TO FILE NAME - LEADING SPACES OK
;
;  OUTPUTS:
;	(A) = COUNT OF "?" IN NAME
;	(Z) = CONDITION OF (A)
;	(DE)= POINTER TO END OF NAME DELIMITER
;
GETNAM:			; GET FILE REFERENCE
	PUSH	H
	CALL	LL35	; IGNOE POINTER
	LXI	D,FCBOFF
	DAD	D
	XCHG		; (DE) POINTS TO FILE CONTROL BLOCK
	CALL	BDOS
	RET
;
;
; BDOS FUNCTIONS USING BUFFER POINTER
;
BDOS2:	LHLD	FTABLE	; RECALL FILE TABLE POINTER
	LXI	D,BUFF	; BUFFER OFFSET
	DAD	D
	XCHG		; (DE) POINTS TO BUFX	H
	MVI	M,' '
	DCR	B
	JNZ	LLCF
LLD6:			; PUT THREE ZEROS IN FILE CONTROL BLOCK
	MVI	B,3
LLD8:
	INX	H
	MVI	M,0
	DCR	B
	JNZ	LLD8
	POP	H
	LXI	B,000BH
LLE7:			; CHECK FOR AMBIGUOUS FILE REFERENCE
	INX	H
	MOV	A,M
	CPI	'?'
	JNZ	LLEF
	INR	B
LL	D
	ORA	A	; NULL
	RZ
	CPI	' '	; SPACE
	JNC	LL16A	; JUMP IF NOT CONTROL CHARACTER
	MVI	A,'?'	; REPLACE CONTROL CHAR
	RET		; (Z)=0
LL16A:
	RZ
	CPI	'='
	RZ
	CPI	5FH	; BACK ARROW
	RZ
	CPI	'.'
	RZ
	CPI	','
	RZ
	CPI	':'
	RZ
	CPI	';'
	RZ
	CPIR LEADING BLANKS
	ORA	A	; NULL INDICATES END OF BUFFER
	JZ	LLA6A	; JUMP IF NULL
 
	SBI	'@'	; CHECK IF DRIVE SPECIFIED
	MOV	B,A
	INX	D
	LDAX	D
	CPI	':'
	JZ	LL76
 
	DCX	D
	MVI	M,0	; ZERO FOR CURRENT DRIVE
	JMP	LL7C
LL76:
	MOV	M,B	; SPECIFIED D
RETURN:	MVI	H,0
	MOV	L,A	; FORTRAN INTEGER FUNCTION RESULT
	ORA	A	; DETERMINE ZERO FLAG
	RET
;
;
; LOCAL TEMPORARY STORAGE
;
FTABLE:	DS	2	; FILE TABLE POINTER

ACCESS:	DS	1	; ACCESS CODE

DATA:	DS	2	; DATA BYTE POINTER

;
;
; STORAGE FOR OFER ORIGIN
	CALL	BDOS
	RET
;
;
; ALL ERROR CONDITIONS EXIT HERE
;
ERR:	LHLD	FTABLE	; RECALL FILE TABLE POINTER
;	....	.....	ADD ERROR MESSAGE SOMETIME
	INX	H
	MVI	A,255
	MOV	M,A	; SET STATUS TO EOF
	DCR	A	; (A) = 254  (UNSPECIFIED ERROR)
;
;EF:
	DCR	C
	JNZ	LLE7
	MOV	A,B
	ORA	A	; (A) IS COUNT OF '?' IN NAME
	RET		; (Z)=1 IF UNAMBIGUOUS NAME
;
;
; ---------------------
;
;	(B)= MAX CHARACTER COUNT
;
LL7E:			; SCAN FNAME OR FTYPE
	CALL	LL16
	JZ	LL9F	; JUMP IF DELIMITER FOUND
	INX		'<'
	RZ
	CPI	'>'
	RET
;
;	----------------
;
LL35:			; ADVANCE  TO FIRST NON-BLANK OR END
	LDAX	D
	ORA	A
	RZ
	CPI	' '
	RNZ
	INX	D
	JMP	LL35
;
;
;
; BDOS FUNCTIONS USING FILE CONTROL BLOCK POINTER
;
BDOS1:	LHLD	FTABLE	; RECALL FILE TABLRIVE
	INX	D
LL7C:			; GET FILENAME
	MVI	B,8
	CALL	LL7E	; SCAN FILE NAME

	MVI	B,3
	CPI	'.'	; FILE TYPE DELIMITER
	JNZ	LLCF	; JUMP IF NO FILE TYPE

	INX	D
	CALL	LL7E	; SCAN FILE TYPE
	JMP	LLD6

LLCF:			; FILL REST OF FILE TYPE WITH SPACES
	INPEN FILE LIST
;
LSIZE:	DB	0	; COUNT OF FLIST SIZE
LMAX	EQU	10	; MAX SIZE OF OPEN FILE TABLE
FLIST:	DS	LMAX*2	; LIST OF FILE TABLE POINTERS
;
;
; STORAGE FOR LREAD
;
LPOINT:	DS	2
BPOINT:	DS	2
ACTP:	DS	2
DBYTE:	DS	1
CMAX:	DS	1
;
;
; FILL REST OF FILENAME WITH SPACES
	INX	H
	MVI	M,' '
	DCR	B
	JNZ	LL9F
LLA6:
	RET
;
; ----------------------
;
LLA6A:
	POP	H
	ORI	255	; NO FILE NAME FOUND
	RET		; (Z)=0
;
; --------------------------
;
LL16:			; CHECK FOR DELIMITERS
	LDAXH
	CPI	'*'	; IF '*', FILL REST OF FILENAME WITH '?'
	JNZ	LL8F
	MVI	M,'?'
	JMP	LL91
LL8F:
	MOV	M,A	; STORE IN FCB
	INX	D
LL91:
	DCR	B	; CHARACTER COUNT
	JNZ	LL7E
LL95:			; IGNORE EXTRA CHARACTERS
	CALL	LL16
	JZ	LLA6
	INX	D
	JMP	LL95
LL9F:					CP/M DISK I/O PACKAGE

		VERSION 2.X   08/17/78

	   COMPATIBLE WITH MICROSOFT FORTRAN

				DICK CURTISS
				843 NW 54TH
				SEATTLE, WASHINGTON
						98107
				(206) 784 8018

  FORTRAN USAGE:
	INTEGER  DOPEN , DCLOSE , GCLOSE
	INTEGER  BR   OPEN DISK FILE:
		LXI	H,FILETABLE
		LXI	D,FILENAME
		LXI	B,ACCESS
		CALL	DOPEN		; OPEN FILE
		JNZ	ERROR


   CLOSE DISK FILE:
		LXI	H,FILETABLE
		CALL	DCLOSE		; CLOSE FILE
		JNZ	ERROR


   CLOSE ALL OPEN FILES:
		CALL	GCLOSE		; CLOSE ALL 
	  4. TWO OPTIONS ARE AVAILABLE FOR WRITE ACCESS.  IF
	     THE FILE ALREADY EXISTS AND THE ACCESS CODE IS 2,
	     AN ERROR WILL RESULT AND THE FILE WILL NOT BE
	     OPENED.  IF THE ACCESS CODE IS 3, AN EXISTING FILE
	     WILL BE DELETED BEFORE OPE = DCLOSE ( FILETABLE )
	IF ( STATUS .NE. 0 ) GO TO ...... ERROR

    CLOSE ALL OPEN FILES
	STATUS = GCLOSE ( 0 )

    READ BYTE FROM DISK FILE:
	DATABYTE = 0
	STATUS = BREAD ( FILETABLE , DATABYTE )
	IF ( STATUS .EQ. 255 ) GO TO ...... END OF FILMBLER USAGE:

	FILETABLE:
		DB	0	; ACCESS CODE STORAGE
		DB	0	; STATUS CODE STORAGE
		DS	1	; BUFFER INDEX OR POINTER
		DB	'X'	; FILE ID FOR ERROR MESSAGES
		DS	33	; CP/M FILE CONTROL BLOCK
		DS	128	; DATA BUFFER STORAGE

			1	  READ ACCESS
	ACCEOGRAM INITIALIZATION WHEN THE FIRST
	     2 BYTES SHOULD BE SET TO ZERO AND THE FOURTH BYTE
	     SET TO SOME CHARACTER WHICH WILL BE DISPLAYED IN
	     ANY ERROR MESSAGES.

	  3. "FILENAME" IS A CHARACTER STRING REPRESENTING A
	     VALID CP/M FILE EAD , BWRITE
	INTEGER  LREAD , LWRITE
	INTEGER  DATABYTE , LINE(40) , STATUS
	INTEGER  MCOUNT , ACOUNT
	INTEGER  FILETABLE(83) , FILENAME(6) 
 
	DATA     FILETABLE(1) , FILETABLE(2) / 0 , 'XX' /
 
	DATA     FILENAME / 'B:' , 'FN' , 'AM' , 'E.' , 'TS END OF FILE
		ASCII PARITY BIT IS REMOVED

	  7. LWRITE  --
		LINES ARE AUTOMATICALLY TERMINATED BY
		  CARRIAGE RETURN - LINE FEED

	  8. "DATABYTE" STORAGE FOR READ AND WRITE IS A SINGLE
	     BYTE AS FAR AS THE ROUTINES ARE CONCERNED.  PRIOR
N.

	  5. OPERATION "STATUS"
		0	NORMAL
		1-254	ERROR CODE - NOT PRESENTLY SPECIFIED
		255	END OF FILE ON READ
		255	END OF MEDIUM ON WRITE

	  6. LREAD  --
		CARRIAGE RETURN IS END OF LINE
		LINE FEED, NULL AND RUBBOUT ARE IGNORED
		CONTROL Z IE
	IF ( STATUS .NE.  0  ) GO TO ...... ERROR

    WRITE BYTE TO DISK FILE:
	STATUS = BWRITE ( FILETABLE , DATABYTE )
	IF ( STATUS .EQ. 255 ) GO TO ...... END OF MEDIUM
	IF ( STATUS .NE.  0  ) GO TO ...... ERROR
 
    READ LINE FROM DISK FILE:
	MCOSS:   DB    2	; WRITE ACCESS - NO DELETE
			3	  WRITE WITH DELETE
	FILENAME: DB	'B:FNAME.TXT '
	DATABYTE: DS	1	; STORAGE FOR DATABYTE
	MCOUNT:	  DB	80	; LENGTH OF READ BUFFER
	LINE:	  DS	80	; LINE BUFFER
	ACOUNT:	  DS	1	; LINE READ ACTUAL COUNT


NAME WITH OPTIONAL DISK SELECT AND
	     FILE TYPE.  LEADING SPACES ARE IGNORED AND THE
	     MAY BE TERMINATED BY A SPACE, CARRIAGE RETURN,
	     ",", OR "=".  STORAGE MUST BE A CONTIGUOUS STRING
	     OF BYTES - NOT ONE CHARACTER PER INTEGER WORD.
X' , 'T ' /

    OPEN DISK FILE:
						 1
	STATUS = DOPEN  ( FILETABLE , FILENAME , 2 )
						 3
			1 READ ACCESS
			2 WRITE ACCESS - NO DELETE
			3 WRITE ACCESS WITH DELETE
	IF ( STATUS .NE. 0 ) GO TO ...... ERROR

    CLOSE DISK FILE:
	STATUS	     TO READ THE MOST SIGNIFICANT BYTE OF "DATABYTE"
	     SHOULD BE SET TO ZERO IF THE DATA IS TO BE USED
	     IN INTEGER COMPARES, ETC.

	  9. "MCOUNT" AND "ACOUNT" ARE SINGLE BYTE INTEGERS
	     AS FAR AS THE ROUTINES ARE CONCERNED.



  ASSEF ( STATUS .EQ. 255 ) GO TO ...... END OF MEDIUM
	IF ( STATUS .NE.  0  ) GO TO ...... ERROR


	NOTES:
	  1. EACH FILE MUST HAVE ITS OWN "FILETABLE" OF
	     165 BYTES.

	  2. THE "FILETABLE" SHOULD NOT BE ALTERED BY THE USER
	     EXCEPT DURING PRUNT = 80
	STATUS = LREAD ( FILETABLE , LINE , MCOUNT , ACOUNT )
	IF ( STATUS .EQ. 255 ) GO TO ...... END OF FILE
	IF ( STATUS .NE.  0  ) GO TO ...... ERROR

    WRITE LINE TO DISK FILE:
	ACOUNT = 80
	STATUS = LWRITE ( FILETABLE , LINE , ACOUNT )
	IOPEN FILES
		JNZ	ERROR


   READ BYTE FROM DISK FILE:
		LXI	H,FILETABLE
		LXI	D,DATABYTE
		CALL	BREAD		; READ A BYTE
		INR	A
		JZ	ENDOFFILE
		DCR	A
		JNZ	ERROR


   WRITE BYTE TO DISK FILE:
		LXI	H,FILETABLE
		LXI	D,DATABYTE
		CALL	BWRITE	.

	  2. THE "FILETABLE" SHOULD NOT BE ALTERED BY THE USER
	     EXCEPT DURING PROGRAM INITIALIZATION WHEN THE FIRST
	     2 BYTES SHOULD BE SET TO ZERO AND THE FOURTH BYTE
	     SET TO SOME CHARACTER WHICH WILL BE DISPLAYED IN
	     ANY ERROR MESSAG, NULL AND RUBBOUT ARE IGNORED
		CONTROL Z IS END OF FILE
		ASCII PARITY BIT IS REMOVED

	  7. LWRITE  --
		LINES ARE AUTOMATICALLY TERMINATED BY
		  CARRIAGE RETURN - LINE FEED
	; WRITE A BYTE
		INR	A
		JZ	ENDOFMEDIUM
		DCR	A
		JNZ	ERROR

 

   READ LINE FROM DISK FILE:
		LXI	H,FILETABLE
		LXI	D,LINE
		LXI	B,ARGLIST
		CALL	LREAD		; READ A LINE
		INR	A
		JZ	ENDOFFILE
		DCR	A
		JNZ	ERROR

	ARGLIST:
		DW	MCOUNT
	ES.

	  3. "FILENAME" IS A CHARACTER STRING REPRESENTING A
	     VALID CP/M FILE NAME WITH OPTIONAL DISK SELECT AND
	     FILE TYPE.  LEADING SPACES ARE IGNORED AND THE STRING
	     MAY BE TERMINATED BY A SPACE, CARRIAGE RETURN,
	     ",", OR "=".
ERA IOOP.ASM
PIP IOOP.ASM=B:IOOP.SRC,B:DISKIO2.SRC
ASM IOOP.AAZ
 IOOP$   $$$                    	DW	ACOUNT


   WRITE LINE TO DISK FILE:
		LXI	H,FILETABLE
		LXI	D,LINE
		LXI	B,ACOUNT
		CALL	LWRITE		; WRITE A LINE
		INR	A
		JZ	ENDOFMEDIUM
		DCR	A
		JNZ	ERROR




	NOTES:
	  1. EACH FILE MUST HAVE ITS OWN "FILETABLE" OF
	     165 BYTESN.

	  5. OPERATION STATUS (HL), (A) AND (Z)
		(HL)
		(A)	(Z)
		0	1	NORMAL
		1-254	0	ERROR CODE - NOT PRESENTLY SPECIFIED
		255	0	END OF FILE ON READ
		255	0	END OF MEDIUM ON WRITE


	  6. LREAD  --
		CARRIAGE RETURN IS END OF LINE
		LINE FEED
	  4. TWO OPTIONS ARE AVAILABLE FOR WRITE ACCESS.  IF
	     THE FILE ALREADY EXISTS AND THE ACCESS CODE IS 2,
	     AN ERROR WILL RESULT AND THE FILE WILL NOT BE
	     OPENED.  IF THE ACCESS CODE IS 3, AN EXISTING FILE
	     WILL BE DELETED BEFORE OPE