	ALWAYS	23MAR4	HEX	<HEX - HEX mainline routine>			;23MAR4
	.SBTTL	INTRODUCTION							;**-1
;************************************************************************
;*									*
;*	HEX: Hex file management utility				*
;*									*
;*	Author: Kevin Angley						*
;*									*
;*	Date: 30-AUG-82							*
;*									*
;*	****	BASE LEVEL: 30-AUG-82					*
;*									*
;*	EDIT HISTORY:							*
;*									*
;*	29AUG3	Insert CR after each line in RSM (read summary message)	*
;*									*
;*	Dec-83 to Feb-84, Chris Doran, Sira Ltd.			*
;*		Support STEP/EVEN/ODD option in FROM-THRU.		*
;*		Move out some messages and keywords used once only to	*
;*		  appropriate modules for overlaying efficiency.	*
;*		Put MEMORY in its own PSECT, $$$$$$, which goes last,	*
;*		  so it can be allocated by an EXTTSK, saving 64 blocks	*
;*		  of task file space.					*
;*		Never time out if TIME = 0.				*
;*		Add new commands HELP, .(=CLI), NAME, CSUM, APPEND,	*
;*		  ECHO, NOECHO, EXIT, arithmetic operations.		*
;*		Use common command line compression routine, shared	*
;*		  with EDIT.						*
;*									*
;*	23MAR4	Scott Smith, Telex Computer Products, Raleigh NC	*	;23MAR4
;*		Included a conditional assembly block that changes most	*	;23MAR4
;*		.LDA default file extentions to .HEX and included	*	;23MAR4
;*		'USE FOR READ' modifications.				*	;23MAR4
;*									*	;23MAR4
;************************************************************************
	.PAGE
	.SBTTL	MCALLS AND LOCAL EQUATES
	.MCALL	FSRSZ$
	.MCALL	FINIT$
	.MCALL	FDOF$L,FCSBT$
	.MCALL	QIOW$,DIR$,CALLR						;23MAR4
	.MCALL	EXIT$S,GCMLB$,GCML$,GCMLD$,RCML$				;**-1
	.MCALL	FDBDF$,FDAT$A,FDRC$A,FDOP$A
	.MCALL	MRKT$C,ASTX$S,CMKT$S,QIOW$C,WTSE$C
;
;**** EQUATES
;
CMILUN	==	1		; LUN FOR COMMAND LINE INPUT
TILUN	==	2		; LUN for TI: I/O
IOLUN	==	3		; LUN FOR DISK I/O

; Set TIME to 0 to disable command timeouts.
TIME	=	0.		; NUMBER OF SECONDS TO WAIT FOR A COMMAND
MEMLOW	==	000000		; LOW LIMIT ON VIRTUAL MEMORY
MEMHIGH ==	077777		; MEMORY HIGH LIMIT (7FFFH)
MEMSIZE ==	040000		; SIZE OF VIRTUAL MEMORY IN WORDS

CR	==	15		; CARRIAGE RETURN
LF	==	12		; LINE FEED
SPACE	==	<' >		; SPACE
TAB	==	<'	>	; TAB
HYPHEN	==	'-

RECLEN	==	512.		; MAXIMUM SIZE OF RECORD BUFFER
	.PAGE
	.SBTTL	FILE CONTROL SERVICES DATA AREAS

	FSRSZ$	2			; DEFINE 2 FILE STORAGE REGIONS

FDB::	FDBDF$				; DEFINE THE FILE DESCRIPTOR BLOCK
	FDOF$L				; Define FDB offsets locally
	FCSBT$				; Define attribute bits locally

	FDAT$A	R.VAR,FD.CR		; INITIALIZE FILE ATTRIBUTES
	FDRC$A	,RECORD,RECLEN		; INITIALIZE RECORD ATTRIBUTES
	FDOP$A	IOLUN,DSPT		; FILE OPEN INITIALIZATION
	.PAGE
	.SBTTL	HEX - ENTRY AND INITIALIZATION
	.PSECT	HEX	I,RO

	.EVEN
START:
	FINIT$
	CALL	INITAL			; INITIALIZE MEMORY, CLEAR OFFSET
					;  TRANSFER, PROCESSOR (PROGRAM INITIATED)

CMD:
1$:
.IIF NE TIME,	MRKT$C	,TIME,2,TIMOUT,HEX	; ESTABLISH A TIMEOUT FOR COMMAND INPUT
	BISB	#GE.LC,GCLBLK+G.MODE	; Pass LC chars unchanged
	GCML$	#GCLBLK			; COLLECT COMMAND LINE
	BCC	3$
.IIF NE TIME,	CMKT$S				; CANCEL MARK TIME IF BAD COMMAND
	CMPB	#GE.EOF,GCLBLK+G.ERR	; CHECK STATUS
	BNE	2$			;  NE: REAL ERROR
	JMP	EXIT			; EOF, RETURN TO EXECUTIVE

2$:
	OUTPUT	CIE			; COMMAND INPUT ERROR ERROR
	BR	CMD			; GO GET ANOTHER


3$:
.IIF NE TIME,	CMKT$S				; CANCEL MARK TIME IF GOOD COMMAND
	MOV	GCLBLK+G.CMLD,R2	; COMMAND STRING LENGTH IN R2
	BLE	CMD			;  LE: NULL COMMAND - REPROMPT
	MOV	GCLBLK+G.CMLD+2,R0	; "FROM" ADDRESS IN R0
	MOVB	GCLBLK+F.RCTL,QUIET+1	; Hi byte of QUIET flag set
	BICB	#^CFD.TTY,QUIET+1	; if input from terminal
	MOV	R0,OUTDIR+Q.IOPL	; Load address and length to echo
	MOV	R2,OUTDIR+Q.IOPL+2	; command line, but don't do it yet
	MOV	%0,%1			; Copy start of command line
	ADD	%2,%1			; Point to end
	CLRB	@%1			;  and make it ASCIZ

; Check for a "." CLI command and execute it immediately if so, before line gets
; compressed. Note that the CLI command processor expects the command line
; length (including ".") to be in %2.
6$:	CALL	SPCTAB			; Trim leading spaces and tabs
	BNE	15$
10$:	INC	%0			; Ignore either if found
	DEC	%2
	BEQ	CMD			; Give up if line is just blanks
	BR	6$			; Else keep looking

15$:	CMPB	(%0)+,#'.		; Did command start "." -- CLI command?
	BNE	20$			; No, go compress
	CALL	ECHOIF			; Echo command line if echo on
	CALL	CLI			; Issue CLI command
	JMP	50$			; Finish up as usual
20$:
	DEC	%0			; Point back to start of command
	CALL	COMPRESS		; Compress line and make UC

; Separate check again for NOECHO command, which isn't itself echoed if
; commands are coming from a file.
	CASE	NOECHO			; If NOECHO, process, then JMP 50$

; Return here only if not NOECHO.
	MOV	#RECORD,OUTDIR+Q.IOPL	; Uncompressed copy in RECORD should
	CALL	ECHOIF			; be echoed if echo on

	CMPB	#'*,(R0)		; IS THIS A DISPLAYABLE COMMENT?
	BNE	45$			;  NE: NEED TO DISPLAY
	JMP	50$			;  EQ: ALREADY DISPLAYED
45$:
;
	CASE	AND			; IF CMD, PROCESS, THEN JMP 50$
	CASE	APPEND			; IF CMD, PROCESS, THEN JMP 50$
	CASE	COMPARE			; IF CMD, PROCESS, THEN JMP 50$
	CASE	COMPLEMENT		; IF CMD, PROCESS, THEN JMP 50$
	CASE	COPY			; IF CMD, PROCESS, THEN JMP 50$
	CASE	CRC			; IF CMD, PROCESS, THEN JMP 50$
	CASE	CSUM			; IF CMD, PROCESS, THEN JMP 50$
	CASE	DECREMENT		; IF CMD, PROCESS, THEN JMP 50$
	CASE	DISPLAY			; IF CMD, PROCESS, THEN JMP 50$
	CASE	DIVIDE			; IF CMD, PROCESS, THEN JMP 50$
	CASE	ECHO			; IF CMD, PROCESS, THEN JMP 50$
	CASE	EDIT			; IF CMD, PROCESS, THEN JMP 50$
	CASE	EXIT			; IF CMD, PROCESS, THEN JMP 50$
	CASE	FILL			; IF CMD, PROCESS, THEN JMP 50$
	CASE	FORMAT			; IF CMD, PROCESS, THEN JMP 50$
	CASE	HELP			; IF CMD, PROCESS, THEN JMP 50$
	CASE	IDENT			; IF CMD, PROCESS, THEN JMP 50$
	CASE	INCREMENT		; IF CMD, PROCESS, THEN JMP 50$
	CASE	INIT			; IF CMD, PROCESS, THEN JMP 50$
	CASE	MOVE			; IF CMD, PROCESS, THEN JMP 50$
	CASE	MULTIPLY		; IF CMD, PROCESS, THEN JMP 50$
	CASE	NAME			; IF CMD, PROCESS, THEN JMP 50$
	CASE	NEGATE			; IF CMD, PROCESS, THEN JMP 50$
	CASE	OR			; IF CMD, PROCESS, THEN JMP 50$
	CASE	QM			; '?' = HELP
	CASE	READ			; IF CMD, PROCESS, THEN JMP 50$
	CASE	REMAINDER		; IF CMD, PROCESS, THEN JMP 50$
	CASE	REVERSE			; IF CMD, PROCESS, THEN JMP 50$
	CASE	ROTATE			; IF CMD, PROCESS, THEN JMP 50$
	CASE	SEARCH			; IF CMD, PROCESS, THEN JMP 50$
	CASE	SHIFT			; IF CMD, PROCESS, THEN JMP 50$
	CASE	SUM			; IF CMD, PROCESS, THEN JMP 50$
	CASE	OFFSET			; IF CMD, PROCESS, THEN JMP 50$
	CASE	TRANSFER		; IF CMD, PROCESS, THEN JMP 50$
	CASE	USE			; IF CMD, PROCESS, THEN JMP 50$		;23MAR4
	CASE	WRITE			; IF CMD, PROCESS, THEN JMP 50$
	CASE	XOR			; IF CMD, PROCESS, THEN JMP 50$

; ELSE - COMMAND NOT FOUND

	OUTPUT	IC			; ILLEGAL COMMAND
	SEC
;
; Common return point. If the operation failed (carry set) abort processing
; of a command file (if this is one).
50$:	BCC	255$			; Continue if all OK
.IIF DF P$$OFF,	MOV	#EX$ERR,EXSTAT		; Failed -- set error exit status
	TSTB	QUIET+1			; Command from TTY?
	BNE	255$			; Yes, just get another
	OUTPUT	CAB			; No, file, say "aborted"
	RCML$	#GCLBLK			; Back to top level
255$:
	JMP	CMD			;GO GET ANOTHER COMMAND


EXIT:
.IF DF P$$OFF
	MOV	EXSTAT,%0		; Load exit status
	CALLR	$EXST			; Exit with it
.IFF
	EXIT$S				; PROGRAM EXIT
.ENDC
	.PAGE
	.SBTTL	COMMAND LINE ECHO CONTROL

; Echo required.
ECHO:	MOVB	#377,QUIET		; Set at least lo byte of QUIET
	CLC				; Must succeed
	RETURN

; Suppress echo, but only if reading from file.
NOECHO:	CLRB	QUIET			; Clear lo byte
	RETURN				; That's all

; Display command line if echo is on (QUIET<>0) and it wasn't already done
; by a fetch from TI:
ECHOIF:	TSTB	QUIET+1			; Yes, see if we should echo
	BNE	10$			; Not if hi byte set, done by TI: fetch
	TSTB	QUIET			; Commands from file, ECHO on?
	BEQ	10$			;   EQ = no, just execute
	DIR$	#OUTDIR			;   NE = yes, echo now
10$:	RETURN				; Return anyway

	.PAGE
	.SBTTL	MATCH - MATCH KEYWORD IF POSSIBLE
;
;	ENTRY PARAMETERS:
;
;	R0 POINTS TO THE ASCIZ COMMAND LINE BEING PROCESSED
;	R1 POINTS TO THE TARGET KEYWORD ASCIZ STRING
;
;	IF THE KEYWORD BEGINS AT (R0), THE Z FLAG IS SET TO INDICATE
;	EQUALITY. ELSE, THE Z FLAG IS RESET TO INDICATE DIFFERENCE.
;
;	EXIT PARAMETERS:
;
;	R0 (IF MATCH) POINTS TO NEXT BYTE AFTER KEYWORD IN COMMAND STRING
;	R0 (IF NO MATCH) SAME AS ON ENTRY
;	R1 (EITHER CASE) GARBAGE
;
MATCH::
	PUSH	R0		; SAVE COMMAND STRING POINTER
10$:
	TSTB	(R1)		; DONE WITH MATCH IF END OF KEYWORD
	BEQ	30$		;  YES - RETURN MATCH
	TSTB	(R0)		; NO MATCH IF NO MORE COMMAND STRING
	BEQ	20$		;  YES - RETURN NO MATCH
	CMPB	(R0)+,(R1)+	; KEEP COMPARING CHARACTERS
	BEQ	10$		;  YES - SAME, SO KEEP LOOKING
				;  NO - NO MATCH
20$:
	POP	R0		; NO MATCH - RESTORE COMMAND STRING POINTER
	CLZ			; CLEAR ZERO FLAG TO SHOW NOT EQUAL
	RETURN
30$:
	TST	(SP)+		; CLEAN UP THE STACK
	SEZ			; SET ZERO FLAG TO SHOW MATCH
	RETURN
	.PAGE
	.SBTTL	VALID - OFFSET AND VALIDATE INPUT ADDR
;
;	ENTRY PARAMETERS:
;
;	R3 CONTAINS THE LOW WORD OF A 32-BIT ADDRESS
;	R4 CONTAINS THE HIGH WORD OF A 32-BIT ADDRESS
;
;	EXIT PARAMETERS:
;
;	R2 CONTAINS THE 16-BIT OFFSETTED ADDRESS
;	R3 CONTAINS THE LOW WORD OF A 32-BIT ADDRESS
;	R4 CONTAINS THE HIGH WORD OF A 32-BIT ADDRESS
;	NO OTHER REGISTERS ARE AFFECTED
;	CARRY FLAG INDICATES VALID (CLEAR) OR NOT VALID (SET)
;
VALID::
	PUSH	R3		; SAVE REAL 32-BIT ADDRESS
	PUSH	R4
	SUB	OFFST,R3	; SUBTRACT OFFSET (LOW WORD)
	SBC	R4		; SUBTRACT CARRY FROM HIGH WORD
	SUB	OFFST+2,R4	; SUBTRACT OFFSET (HIGH WORD)
	CMP	#16.,MODE	; ARE WE IN 16-BIT MODE?
	BEQ	5$		;  EQ: NEED NOT (SHOULD NOT) TEST HIGH WORD
	CMP	#24.,MODE	; ARE WE IN 24-BIT MODE?
	BNE	3$		;  NE: NO
				; FOR 24-BIT MODE, TO ALLOW WRAP AT FFFFFF,
	BIC	#177400,R4	;  CLEAR HIGH BYTE OF HIGH WORD
3$:
	TST	R4		; R3/R4 SHOULD NOW BE A 15-BIT VALUE
	BNE	8$		;  NE: ADDRESS MUST BE OUT OF RANGE
5$:
	MOV	R3,R2		; KEEP 16-BIT OFFSETTED ADDRESS IN R2
	ROL	R3		; IS HIGH BIT ON?
	BCC	10$		; CC: NO
8$:
	OUTPUT	AOR		; ADDRESS OUT OF RANGE
	SEC			; SET CARRY
10$:
	POP	R4		; RESTORE REAL 32-BIT ADDRESS
	POP	R3		; (Carry unaffected by POP = MOV)
	RETURN			; EXIT
	.PAGE
	.SBTTL	UNOFFSET - UNOFFSET OFFSETTED 16-BIT ADDRESS INTO 32-BIT
;
;	ENTRY PARAMETERS:
;
;	R2 CONTAINS THE 16-BIT OFFSETTED ADDRESS
;
;	EXIT PARAMETERS:
;
;	R2 CONTAINS THE 16-BIT OFFSETTED ADDRESS
;	R3 CONTAINS THE 32-BIT ADDRESS (LOW WORD)
;	R4 CONTAINS THE 32-BIT ADDRESS (HIGH WORD)
;	NO OTHER REGISTERS ARE AFFECTED
;
UNOFFSET::
	MOV	OFFST,R3	; SET UP OFFSET IN R3/R4
	MOV	OFFST+2,R4
	ADD	R2,R3		; ADD OFFSETTED ADDRESS
	ADC	R4		; ADD CARRY TO HIGH WORD
	RETURN			; EXIT
	.PAGE
	.SBTTL	FROMTH - COLLECT FROM/THRU ADDRESSES
;
;	ENTRY PARAMETERS:
;
;	R0 POINTS TO THE ASCIZ COMMAND LINE IN PROCESS
;
;	EXIT PARAMETERS:
;
;	R0 POINTS JUST BEYOND THE "THRU" ADDRESS
;					(IF SUCCESSFUL)
;	R1 and FROM contain the offsetted FROM address
;	R2 and THRU contain the offsetted THRU address
;	LOBOUND contains unoffsetted FROM address, for READ
;	HIBOUND contains unoffsetted THRU address, ditto
;	STEP contains the STEP value (2 if ODD/EVEN option given), default 1
;	R3 and COUNT contain (THRU-FROM+1)/STEP count
;
;	R4 and R5 are preserved.
;
;	IF THE CARRY FLAG IS CLEAR UPON EXIT, THE
;	FOLLOWING CONDITIONS ARE ASSURED:
;
;	1) THE KEYWORDS/ADDRESSES WERE FOUND
;	2) THE HEX CONVERSION WAS SUCCESSFUL
;	3) THRU>=FROM AND BOTH ARE VALID
;
;	IF THERE ARE ERRORS, THE CARRY
;	FLAG IS SET, AND A MESSAGE PUT OUT.
;
FROMTH::
	MOV	#2,STEP		; Default STEP is 2 if ODD or EVEN
	CLR	MASK		; EVEN requires MASK 000000
	PUSH	R4
	GETKEY	EVEN		; See if EVEN
	BEQ	5$		; Yes, keep STEP/MASK
	INC	MASK		; No, set flag to 000001 for ODD
	GETKEY	ODD		; ODD keyword?
	BEQ	5$		; Yes, branch
	COM	MASK		; No, set MASK -ve for normal case
	DEC	STEP		; When default STEP is 1

5$:	GETKEY	FROM		; COLLECT "FROM" KEYWORD
	BEQ	10$		; EQ: YES
	OUTPUT	MSK		; MISSING "FROM" KEYWORD
	JMP	250$		; ERROR EXIT
10$:
	GETKEY	LOW		; TRY FOR "LOW" KEYWORD
	BNE	15$		;  NE: MUST BE REAL VALUE
	MOV	LOADDR,R1	; GET LOW ADDRESS LOW WORD
	MOV	LOADDR+2,R2	; GET LOW ADDRESS HIGH WORD
	BR	18$		; SKIP GETTING REAL VALUE
15$:
	CALL	GETHXL		; GET "FROM" ADDRESS
	BCS	250$		; CS: FAILURE
18$:
; If ODD/EVEN option given, advance FROM to appropriate boundary.
	MOV	MASK,%3		; Copy and check flag
	BMI	19$		; -ve means no ODD/EVEN
	XOR	%1,%3		; See if MASK and FROM lo
	ROR	%3		; Have same bit 0 setting
	ADC	%1		; Increment %1 (lo),
	ADC	%2		; with carry to %2 (hi) if not
19$:
	MOV	R1,LOBOUND	; SAVE "FROM" ADDRESS IN DP
	MOV	R2,LOBOUND+2	; FOR READ BOUNDS
	GETKEY	THRU		; COLLECT "THRU" KEYWORD
	BEQ	20$		; EQ: YES
	OUTPUT	MSK		; MISSING "THRU" KEYWORD
	BR	250$		; ERROR EXIT
20$:
	GETKEY	HIGH		; TRY FOR "HIGH" KEYWORD
	BNE	25$		;  NE: MUST BE REAL VALUE
	MOV	HIADDR,R1	; GET HIGH ADDRESS LOW WORD
	MOV	HIADDR+2,R2	; GET HIGH ADDRESS HIGH WORD
	BR	28$		; SKIP GETTING REAL VALUE
25$:
	CALL	GETHXL		; GET TO ADDRESS
	BCS	250$		; ERROR EXIT
28$:
	MOV	R1,R3		; PUT REAL ADDRESS WHERE IT BELONGS
	MOV	R2,R4

	GETKEY	STEP		; See if we have a STEP option
	BNE	30$		; No, keep default set above
	CALL	GETHX2		; Yes, get 2-digit STEP value
	BCS	250$		; with error check
	MOVB	%1,STEP		; OK, save required value
; Compute number of steps = (THRU-FROM+1)/STEP, reducing THRU if necessary, so
; that end address is exact.
30$:	PUSH	%0		; Save pointer
.IF DF M$$EIS
LO=%1				; Lo and
HI=%0				; high word registers for DIV instruction
QUOT=%0				; Quotient appears in %0
REM=%1				; and remainder in %1
.IFF
LO=%2				; Lo and
HI=%1				; high word registers for $DDIV routine
QUOT=%2				; Quotient (lo) appears in %2 (hi in %1)
REM=%0				; and remainder in %0
.IFTF
	MOV	%3,LO		; Copy lo
	MOV	%4,HI		; and hi words of THRU
	SUB	LOBOUND,LO	; Subtract FROM
	SBC	HI		; in double-precision
	SUB	LOBOUND+2,HI	; Giving THRU-FROM
.IFT
	DIV	STEP,%0		; Divide by STEP
	BVC	35$		; Make sure it doesn't overflow
.IFF
	MOV	STEP,%0		; Get STEP
	CALL	$DDIV		; and divide by it
	TST	%1		; Must have a 16-bit result
	BEQ	35$		; OK if so
.ENDC
	OUTPUT	AOR		; Else step out of range
	POP	%0		; Restore line pointer
	BR	250$		; Exit cs
35$:
	INC	QUOT		; OK, add 1 to count for inclusive operations
	MOV	QUOT,COUNT	; Save for later
	DECR34	REM		; Reduce THRU by remainder for exact end addr
	MOV	%3,HIBOUND	; Set in hi bound for READ
	MOV	%4,HIBOUND+2
	POP	%0		; Restore line pointer
	CALL	VALID		; VALIDATE "THRU" ADDRESS
	BCS	250$		; ERROR EXIT WITH STACK CLEANUP
				; "THRU" ADDR GOES IN R2
	MOV	LOBOUND+2,R4	; RESTORE "FROM" ADDRESS
	MOV	LOBOUND,R3
	MOV	R2,THRU		; SAVE "THRU" OFFSETTED ADDRESS
	CALL	VALID		; VALIDATE "FROM" ADDRESS
	BCS	250$		; CS: BAD FROM ADDRESS - TAKE ERROR EXIT
				; ERROR EXIT WITH STACK CLEANUP
	MOV	R2,FROM		; SAVE IN GLOBAL VARIABLE FROM
	MOV	R2,R1		; PUT OFFSETTED "FROM" ADDRESS IN R1
	MOV	THRU,R2		; RESTORE OFFSETTED "THRU" ADDRESS
	CMP	R2,R1		; THRU > FROM?
	BHIS	40$		; HS: O.K.
	OUTPUT	AOR		; ADDRESS OUT OF RANGE
	BR	250$		; ERROR EXIT
40$:
	MOV	COUNT,R3	; PUT COUNT IN R3
	TST	(PC)+		; Clear carry and skip SEC
250$:
	SEC			; ERROR EXIT-SET CARRY
255$:
	POP	R4		; RESTORE R4
	RETURN
	.PAGE
	.SBTTL	EXTRA - PROCESS SUPERFLUOUS COMMAND STRING
;
;	ENTRY PARAMETERS:
;
;	R0 POINTS TO THE COMMAND STRING IN PROCESS
;	Carry is set if an error already found, else clear.
;
;	EXIT PARAMETERS:
;
;	CARRY: Clear if no junk found, else as on entry.
;
;	FUNCTION: AT THIS POINT, ALL USEFUL INFORMATION HAS BEEN PROCESSED
;	FROM THE COMMAND LINE. THIS ROUTINE MERELY INFORMS THE USER IF THEIR
;	IS SUPERFLUOUS INFORMATION REMAINING IN THE COMMAND LINE.
;
;	DESTROYS: R0
;
EXTRA::
	ROL	-(SP)		; Save entry value of carry
	TSTB	(R0)		; IS THERE SOME EXTRA INFO ?
	BEQ	255$		;  EQ: NO - JUST RETURN, CC FROM TST
	PUSH	R1		; SAVE R1
	CLR	R1		; INITIAL COUNT OF GARBAGE IS ZERO
	PUSH	R0		; SAVE POINTER TO EXCESS
10$:
	INC	R1		; INCREMENT GARBAGE COUNT
	TSTB	(R0)+		; LOOK FOR THE END
	BNE	10$		;  NE: NOT YET
	OUTPUT	SCI		; SUPERFLUOUS COMMAND STRING IGNORED
	POP	R0		; RESTORE POINTER TO BEGINNING OF EXCESS
	MOV	R0,OUTDIR+Q.IOPL ; SET UP TO SHOW USER
	MOV	R1,OUTDIR+Q.IOPL+2
	DIR$	#OUTDIR
	POP	R1		; RESTORE R1
	BIS	#1,@SP		; Set error flag definately
255$:	ROR	(SP)+		; Return error flag in carry
	RETURN
	.PAGE
	.SBTTL	PARSE - PARSE FILE DESCRIPTOR INTO NAMEBLOCK
;
;	PARSE - PARSE FILE DESCRIPTOR INTO NAMEBLOCK
;
;	INPUT PARAMETERS:
;
;	R0 POINTS TO COMMAND LINE IN PROCESS
;
;	OUTPUT PARAMETERS:
;
;	R0 POINTS JUST BEYOND FILE DESCRIPTOR (IF SUCCESSFUL)
;
;	CARRY FLAG INDICATES SUCCESS (CLEAR) OR FAILURE (SET)
;
;	FUNCTION: SETS UP DATASET DESCRIPTOR BLOCK DSPT ACCORDING TO FILE
;		  SPECIFICATION IN COMMAND LINE. IF NO DEVICE/UIC IS
;		  SPECIFIED, THE ENTRY FOR DEVICE/UIC IS ZEROED.
;
;	AUTHOR: KEVIN ANGLEY
;
;	DATE:	06-JUL-82
;
;	REVISED BY: Chris Doran, Sira Ltd
;
;	DATE:	23-Dec-83
;		Set up file access modes according to FORMAT to allow for
;		  binary files.
;		FORMAT also determines default filetype appropriate to
;		  assembler/linker.

PARSE::
	MOV	#DSPT,R1	; MAKE SOME DEFAULT ASSUMPTIONS
	MOV	#SYSLEN,(R1)+	; SY: IS THE DEVICE
	MOV	#SYS,(R1)+
	CLR	(R1)		; AND NO UIC (DEFAULT IS CURRENT)
	MOV	R0,R1		; SAVE POINTER TO SPECIFICATION
10$:				; PARSE DEVICE SPEC (IF ANY)
	TSTB	(R1)		; AT THE END YET?
	BEQ	20$		;  EQ: YES, AND NO DEVICE SPEC
	CMPB	#':,(R1)+	; HAVE WE SEEN A COLON?
	BNE	10$		;  NE: NO, KEEP LOOKING
	MOV	R0,DSPTDP	; START OF SPEC IS START OF DEVICE SPEC
	PUSH	R1		; SAVE POINTER TO UIC/NAME SPEC
	SUB	R0,R1		; COMPUTE LENGTH OF DEVICE SPEC
	MOV	R1,DSPTDL	; SET DEVICE SPEC LENGTH
	POP	R0		; RESTORE POINTER TO UIC/NAME SPEC TO R0
20$:				; PARSE UIC SPECIFICATION
	CMPB	#'[,(R0)	; DO WE HAVE A UIC SPECIFIED?
	BNE	30$		;  NE: NO, GO PROCESS NAME
	MOV	R0,DSPTUP	; SET START OF UIC SPECIFICATION
	INC	R0		; MOVE PAST THE LEFT BRACKET
25$:
	TSTB	(R0)		; AT THE END YET?
	BNE	28$		; NO, KEEP LOOKING
	OUTPUT	FNS		; FILE NAME SYNTAX ERROR
	BR	250$
28$:
	CMPB	#'],(R0)+	; SEARCH FOR RIGHT BRACKET
	BNE	25$		;  NE: KEEP LOOKING
	PUSH	R0		; GOT IT - SAVE POINTER TO NAME SPEC
	SUB	DSPTUP,R0	; COMPUTE LENGTH OF UIC SPEC
	MOV	R0,DSPTUL	; SET UIC SPEC LENGTH
	POP	R0		; RESTORE POINTER TO NAME SPEC
30$:				; PARSE NAME SPECIFICATION
	MOV	#RECORD,R1	; USE RECORD FOR FILENAME WORK AREA
	MOV	R1,DSPTNP	; SET POINTER TO FILENAME
; File access modes and default filetype are given in FILTPS list, q.v.
	PUSH	%2		; Save %2
	MOV	RWFORMAT,%2	; For format code
	ASL	%2		; *2
	ADD	#FILTPS,%2	; Point to FILTPS table entry for this FORMAT
	MOVB	#R.VAR,FDB+F.RTYP ; Variable length records
	MOVB	#FD.CR,FDB+F.RATT ; Printed with CR+LF's
	MOVB	(%2)+,FDB+F.RACC ; Load record access -- FD.PLC, or 0
	BEQ	35$		; 0 => variable length records
	MOVB	#R.FIX,FDB+F.RTYP ; <>0 (FD.PLC) => fixed
35$:
	TSTB	(R0)		; AT END OF COMMAND LINE?
	BEQ	40$		;  EQ: yes - put in default filetype
	CMPB	#'.,(R0)	; . SPECIFIED?
	BEQ	50$		;  EQ: YES - JUST COPY REMAINDER
	CMPB	#';,(R0)	; VERSION SPECIFIED?
	BEQ	40$		;  EQ: YES, INSERT .HEX, THEN COPY REMAINDER
	MOVB	(R0)+,(R1)+	; GARDEN VARIETY CHARACTER
	BR	35$		; KEEP PROCESSING PRE-EXTENSION PART

40$:
	CMPB	@%2,#SPACE	; Unless filetype is explicitly blank
	BEQ	50$		; which causes an OPEN$ error
	MOVB	#'.,(R1)+	; INSERT .
	MOVB	(%2)+,(R1)+	; and three letters
	MOVB	(%2)+,(R1)+	; INSERT of default filetype
	MOVB	(%2)+,(R1)+

50$:				; COPY REMAINDER OF STRING
	TSTB	(R0)		; AT END OF SOURCE STRING?
	BEQ	60$		;  EQ: YES, THAT'S ALL
	MOVB	(R0)+,(R1)+	; COPY STRING
	BR	50$		; KEEP PROCESSING POST-EXTENSION PART

60$:				; END OF STRING - COMPUTE LENGTH
	POP	%2		; Finished with table
	SUB	#RECORD,R1	; SUBTRACT BEGINNING
	MOV	R1,DSPTNL	; SET NAME LENGTH
	CLC			; SET SUCCESS FLAG
	BR	255$		; AND EXIT
250$:				; ERROR EXIT
	SEC			; SET CARRY FLAG
255$:
	RETURN
.PAGE
	.SBTTL	COMPRESS - COMPRESS COMMAND LINE
;
;	COMPRESS - Compress command line in place
;
;	INPUT PARAMETER:
;
;	%0 points to .ASCIZ command line to compress.
;
;	OUTPUT PARAMETERS:
;
;	%1 points to terminating null of compressed line.
;	RECORD contains a copy of the uncompressed line, for possible echo.
;
;	DESTROYS:	%3
;
;	All other registers (including entry value of %0) are preserved.
;
;	FUNCTION: Removes embedded spaces and tabs in a command line, and
;		  converts all lower-case letters to upper-case, except that
;		  the single character after a quote ('), minus (-), tilde (~),
;		  or caret (^), or the pair after double-quote (") are copied
;		  unchanged. Used by mainline code to pre-process the command
;		  line, and by EDIT, for replacement value pre-processing.
;
;	AUTHOR: Chris Doran
;
;	DATE:	05-Jan-84

COMPRESS::
	PUSH	%0		; Save start of line pointer
	MOV	R0,R1		; Copy it
	MOV	#RECORD,%3	; Load pointer to copy area
30$:
	MOVB	(R0),(%3)+	; Copy char. At the end yet?
	BEQ	50$		;  EQ: yes - done
	CALL	SPCTAB		; See if space or tab
	BEQ	35$		;  EQ: yes - ignore
	MOVB	@R0,(R1)+	; Copy byte
	CMPB	@%0,#'a		; Lower-case?
	BLO	35$		; Not if < 'a'
	CMPB	@%0,#'z		; or > 'z'
	BHI	35$
	BICB	#40,-(%1)	; Yes, convert to upper case
	CMPB	(%0)+,(%1)+	; Advance pointers
	BR	30$		; and repeat
35$:
	CMPB	#'',@%0		; Is it a prime?
	BEQ	45$		; Yes, copy 1 more char
	CMPB	#'^,@%0		; No, caret?
	BEQ	45$		; Yes, one more
	CMPB	#'-,@%0		; Minus
	BEQ	45$		; ditto
	CMPB	#'~,@%0		; All prefix a non-compressible char
	BEQ	45$
40$:	CMPB	#'",(%0)+	; No, double-prime?
	BNE	30$		; No, try next
	MOVB	@%0,(%1)+	; Yes, copy characters
	MOVB	@%0,(%3)+
	BEQ	49$		; unless null
45$:	INC	%0		; Address next char
	MOVB	@%0,(%1)+	; without any translation/compression
	MOVB	(%0)+,(%3)+
	BNE	30$		; Repeat
49$:	DEC	%1		; Unless null, when point to it
50$:
	CLRB	@%1		; Make sure output line is ASCIZ
	POP	%0		; Restore start of line pointer
	RETURN			; and return with it

; SUBROUTINE SPCTAB:
;
; Return z set if character addressed by %0 is space or tab, else clear.
; No registers affected.
SPCTAB:	CMPB	#SPACE,(R0)	; Is it a space?
	BEQ	10$		;  EQ: yes - return z set
	CMPB	#TAB,(R0)	; Is it a tab?
10$:	RETURN			; Return with flags
.IF NE TIME
	.PAGE
	.SBTTL	TIMOUT - HANDLE COMMAND TIMEOUT AST


;	AST SERVICE ROUTINE
;	TASK ENTERS AST WITH STACK AS FOLLOWS
;		SP+10	EVENT FLAG MASK WORD
;		SP+ 6	PS OF TASK PRIOR TO AST
;		SP+ 4	PC OF TASK PRIOR TO AST
;		SP+ 2	DSW OF TASK PRIOR TO AST
;		SP+ 0	EVENT FLAG NUMBER OF ZERO

TIMOUT: QIOW$C	IO.KIL,CMILUN,3,,,,,HEX ; KILL ALL I/O ON LUN CMILUN
	WTSE$C	3,HEX		; WAIT FOR I/O TO BE CLEANED UP
	OUTPUT	CIT		; COMMAND INPUT TIMEOUT MESSAGE
	MOV	#EXIT,4(SP)	; WILL CONTINUE EXECUTION AT 'EXIT'
	TST	(SP)+		; EF MUST BE REMOVED
	ASTX$S			; EXIT AST
.ENDC	; Command timeout processor
	.PAGE
	.SBTTL	DATA - HEX DATA AREAS
	.PSECT	DATA


	.EVEN

MODE::	.WORD	16.		; Size (in bits) of maximum address allowed.
				; Possibilities are: 16, 24, and 32.
				; Default is 16.
				; This is set by the offset command and
				;	is not reset by INIT.

OFFST:: .BLKW			; CURRENT OFFSET VALUE - LOW WORD
	.BLKW			; CURRENT OFFSET VALUE - HIGH WORD

TRNSFR:: .BLKW			; CURRENT TRANSFER VALUE - LOW WORD
	.BLKW			; CURRENT TRANSFER VALUE - HIGH WORD

FROM::	.BLKW			; STORED VALUE FROM LAST FROM/THRU/STEP PARSE
THRU::	.BLKW			; STORED VALUE THRU LAST FROM/THRU/STEP PARSE
LOBOUND:: .BLKL			; Unoffsetted FROM
HIBOUND:: .BLKL			; Unoffsetted THRU
STEP::	.BLKW			; Stored value STEP last FROM/THRU/STEP parse
COUNT::	.BLKW			; Stored value (THRU-FROM+1)/STEP
MASK=COUNT			; Used temporarily for ODD/EVEN mask

RWFORMAT::	.WORD	F.INTEL ; READ/WRITE object format
SEPTOR::	.BYTE	SPACE	; Data separator for HEX/OCTAL formats
		.EVEN

LOADDR:: .BLKL			; LOWEST ADDRESS ENCOUNTERED SO FAR
HIADDR:: .BLKL			; HIGHEST ADDRESS ENCOUNTERED SO FAR

RDDOM::	 .BLKW			; Domain used for read				;23MAR4
RDRAN::	 .BLKW			; Range used for read				;23MAR4
;	PSEUDO-REGISTERS 00-FF
REGISTER::	.BLKB	256.

;
	.EVEN					; RECORD MUST BE ON EVEN BOUNDARY

BCOUNT::	.BLKW		; NUMBER OF BYTES LOADED THIS READ		;23MAR4
USECNT::	.BLKW		; 'USE FOR READ' Place counter			;23MAR4
	.EVEN									;**-5
RCD::						; RCD = RECORD, for OUTPUT macro;23MAR4
RECORD::	.BLKB	RECLEN+1		; A GENERAL BUFFER FOR RECORD PR;23MAR4
						; + 1 null for .ASCIZ'ing	;23MAR4
	.EVEN									;**-2
GCLBLK::	GCMLB$	1,HEX,CMDBUF,CMILUN	; GET COMMAND LINE CONTROL BLOCK;23MAR4
PROMPT==GCLBLK+G.DPRM+2				; Start of HEX> for GBLPAT	;23MAR4
	.EVEN									;23MAR4
CMDBUF::	.BLKB	80.			; COMMAND LINE BUFFER
;
;
;
DSPT::						; FILE NAME DESCRIPTOR BLOCK
DSPTDL::	.WORD				; DEVICE DESCRIPTOR LENGTH
DSPTDP::	.WORD				; DEVICE DESCRIPTOR POINTER
DSPTUL::	.WORD				; UIC DESCRIPTOR LENGTH
DSPTUP::	.WORD				; UIC DESCRIPTOR POINTER
DSPTNL::	.WORD				; NAME DESCRIPTOR LENGTH
DSPTNP::	.WORD				; NAME DESCRIPTOR POINTER

; Putting memory in its own PSECT makes it possible to overlay it with a NODSK
; option if overlaid, or (by calling it $$$$$$) at the top of a non-overlaid
; task, where it can be EXTTSK'd, saving 64 blocks of task file space.
	.PSECT	$$$$$$,RW,D,GBL

MEMORY::					; VIRTUAL MEMORY ARRAY
	.PAGE
	.SBTTL	PURE - PURE DATA AREAS (READ ONLY)
	.PSECT	PURE	RO,D
;
KEYTBL::			; KEYWORD ASCIZ TABLE
;
;	*** COMMAND KEYWORDS ***
;
	KEY	AND
	KEY	APPEND
	KEY	COMPARE
	KEY	COMPLEMENT
	KEY	COPY
	KEY	CRC
	KEY	CSUM
	KEY	DECREMENT
	KEY	DISPLAY
	KEY	DIVIDE
KNOECHO:.ASCII	"NO"
	KEY	ECHO
	KEY	EDIT
	KEY	EXIT
	KEY	FILL
	KEY	FORMAT
	KEY	HELP
	KEY	IDENT
	KEY	INCREMENT
	KEY	INIT
	KEY	MOVE
	KEY	MULTIPLY
	KEY	NAME
	KEY	NEGATE
	KEY	OFFSET
	KEY	OR
	KEY	READ
	KEY	REMAINDER
	KEY	ROTATE
	KEY	SEARCH
	KEY	SHIFT
	KEY	SUM
	KEY	USE								;23MAR4
	KEY	TRANSFER
	KEY	WRITE
	KEY	XOR
KQM:	.ASCIZ	"?"			; ? = HELP


;
;	*** COMMON ARGUMENT KEYWORDS (others in specific modules) ***
;
	KEY	FILE
	KEY	FROM
	KEY	HIGH
	KEY	LOW
	KEY	MINUS
	KEY	OF								;23MAR4
	KEY	PARTIAL
	KEY	PLUS
	KEY	REVERSE
	KEY	THRU
	KEY	TO
	KEY	ODD
	KEY	EVEN
	KEY	STEP
	KEY	WITH


; Define format type codes. Note that FILTPS table here, and corresponding
; ones in FORMAT, READ, and WRITE, must match these codes. They are all
; EVEN, for word table lookups.
F.LIST		==	-2	; Special code for DISPLAY's list file
F.INTEL		==	0	; Intel
F.MOTOROLA	==	2	; Motorola
F.ROCKWELL	==	4	; Rockwell
F.RCA		==	6	; RCA
F.TEKHEX	==	10	; Standard Tektronix (Tekhex)
F.EXTENDED	==	12	; Extended Tekhex
F.TEXAS		==	14	; Texas
F.MOSTEK	==	16	; Mostek
F.WHITESMITHS	==	20	; Whitesmiths'
F.RIM		==	22	; PDP-8 Read-In-Mode
F.BIN		==	24	; PDP-8 binary
F.HEX		==	26	; Hex
F.OCTAL		==	30	; Octal
F.TCI		==	32	; TCI
F.SIRA		==	34	; Sira binary
F.OBJECT	==	36	; DEC MACRO assembler ABS output
F.ABSOLUTE	==	40	; DEC absolute loader format (RT-11 LINK /L)
F.TASK		==	42	; RSX-11M TKB output
F.MAX		==	42	; Largest allocated

; Default record access bytes, and filetypes depending on FILFMT.
; 0 for PUT$/GET$ move mode, FD.RWM for READ$/WRITE$ +  3 letters of type.
.MACRO	TYPE	FILTYP,ACCESS
	.ASCII	<ACCESS>"FILTYP"
.ENDM	TYPE

	TYPE	LST	0	; -2 special code for DISPLAY's list file
	.IF	DF	TCP							;23MAR4
FILTPS:	TYPE	HEX	0	;  0 Intel					;23MAR4
	TYPE	HEX	0	;  2 Motorola					;23MAR4
	TYPE	HEX	0	;  4 Rockwell					;23MAR4
	TYPE	HEX	0	;  6 RCA					;23MAR4
	TYPE	HEX	0	; 10 Standard Tektronix (Tekhex)		;23MAR4
	TYPE	HEX	0	; 12 Extended Tekhex				;23MAR4
	TYPE	OBJ	0	; 14 Texas					;**-6
	TYPE	HEX	0	; 16 Mostek					;23MAR4
	TYPE	<   >	FD.PLC	; 20 Whitesmiths' (XEQ.)			;**-1
	TYPE	RIM	0	; 22 PDP-8 RIM
	TYPE	BIN	0	; 24 PDP-8 Binary
	TYPE	PRM	0	; 26 Hex-space
	TYPE	PRM	0	; 30 Octal-space
	TYPE	HEX	0	; 32 TCI					;23MAR4
	.IFF									;23MAR4
FILTPS:	TYPE	LDA	0	;  0 Intel					;23MAR4
	TYPE	LDA	0	;  2 Motorola					;23MAR4
	TYPE	LDA	0	;  4 Rockwell					;23MAR4
	TYPE	LDA	0	;  6 RCA					;23MAR4
	TYPE	LDA	0	; 10 Standard Tektronix (Tekhex)		;23MAR4
	TYPE	LDA	0	; 12 Extended Tekhex				;23MAR4
	TYPE	OBJ	0	; 14 Texas					;23MAR4
	TYPE	LDA	0	; 16 Mostek					;23MAR4
	TYPE	<   >	FD.PLC	; 20 Whitesmiths' (XEQ.)			;23MAR4
	TYPE	RIM	0	; 22 PDP-8 RIM					;23MAR4
	TYPE	BIN	0	; 24 PDP-8 Binary				;23MAR4
	TYPE	PRM	0	; 26 Hex-space					;23MAR4
	TYPE	PRM	0	; 30 Octal-space				;23MAR4
	TYPE	LDA	0	; 32 TCI
	.ENDC									;23MAR4
	TYPE	LDA	0	; 34 Sira binary
	TYPE	OBJ	0	; 36 MACRO-11 absolute binary
	TYPE	LDA	0	; 40 PDP-11 paper-tape absolute loader
	TYPE	SYS	FD.PLC	; 42 TKB output

.IIF NE TIME,	DEFM	CIT	<Command input timeout>
	DEFM	IC	<Illegal command>
	DEFM	AOR	<Address out of range>
	DEFM	HCE	<Conversion error>
	DEFM	MSK	<Missing keyword>
	DEFM	SCI	<Extra ignored:>
	DEFM	CIE	<Command input error>
	DEFM	FNS	<File name syntax error>
	DEFM	UFS	<Unsupported format>
	DEFM	BET	<Invalid character for Extended TekHex>
	DEFM	CAB	<Command file processing aborted>

	.EVEN
	.PAGE
	.SBTTL	DIRECTIVES AND MESSAGES

	.EVEN
	.PSECT	DATA	D,RW

OUTDIR::	QIOW$	IO.WVB,TILUN,1,,,,<0,0,40>	; SKELETAL OUTPUT DIRECTIVE

.IIF DF P$$OFF,EXSTAT::	.WORD	EX$SUC		; Exit status -- default success
	.EVEN			; Put next 2 bytes on word boundary for TST
QUIET::	.BYTE	377		; <>0 = echo all commands from file
	.BYTE	FD.TTY		; <>0 = ignore NOECHO if from TI:

	DEFM	FOE	<File open error 0000>
	DEFM	IOE	<I/O error 0000>

RSM::
	DEFM	RDL	<Low: 00000000	>	; RSM MESSAGES ARE ORDERED!
	.BYTE	CR
	.BYTE	LF
	DEFM	RDH	<High: 00000000	>
	.BYTE	CR
	.BYTE	LF
	DEFM	RDC	<Count: 0000	>
	.BYTE	CR
	.BYTE	LF
	DEFM	RDS	<Sum: 0000	>
SMO==RDS		; Same message for SMO
SMOLEN==10.		; But only up to end of 0000
RSSLEN==.-RSM		; Short RSM w/o transfer address (not given)
	.BYTE	CR
	.BYTE	LF
	DEFM	RDT	<Transfer: 00000000>
RSMLEN	==	.-RSM
FLT::	.ASCII		\	File: 00000000\
FLTLEN	==	.-FLT
	DEFM	ADR	<00000000>
	DEFM	BGO	<Bit group out of range>				;23MAR4
;;	DEFM	NYI	<Command not yet implemented>
	DEFM	FNM	<Name:         >
PRGNAM==FNM+FNMLEN-8.
RNM::	.ASCII		"       File:         "
RNMLEN==.-RNM

SYS::	.ASCII	\SY:\
SYSLEN	==	.-SYS
	.EVEN

	.END	START
