Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_SRC_3_19910112 - utilities/srccom.mid
There are no other files named srccom.mid in the archive.
; -*-MIDAS-*-

TITLE SRCCOM

;;SRCCOM COMMAND ;; SRCCOM_/@/A/L/C/S
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;;	NOTE: THE CANONICAL SOURCE FOR THIS PROGRAM LIVES IN
;;;	[MIT-AI] SYSENG;SRCCOM >
;;;	ALL CHANGES, BUG FIXES, ETC SHOULD BE REFLECTED THERE.
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;WAS ONCE DEC SRCCOM VERSION 16, MINIMALLY ADAPTED TO ITS.
;ALMOST TOTALLY REWRITTEN BY RMS, DEC '75.
;MUNGED FOR 10X/20X ASSEMBLY BY KLH, MAR '79.

IF1 [
IFE .OSMIDAS-SIXBIT/ITS/,ITS==1
IFE .OSMIDAS-SIXBIT/TENEX/,TNX==1
IFE .OSMIDAS-SIXBIT/TWENEX/,TNX==1 ? TWX==1
IFNDEF ITS,ITS==0
IFNDEF TNX,TNX==0
IFE ITS,IFE TNX,DEC==1
IFNDEF DEC,DEC==0
IFNDEF TWX,TWX==0
]

IFN TNX,[
.DECSAV				; Why go through LINK?
DEFINE HLPFIL			; SPECIFIES LOC OF HELP FILE
ASCIZ "INFO:SRCCOM.INFO"!TERMIN
]

;I/O CHANNELS.  FOR TNX THESE ARE INDICES INTO JFNCHS.

CHTTI==0	;TTY INPUT.
CHIN1==1	;FIRST INPUT FILE
CHIN2==2	;SECOND INPUT FILE.
CHIN3==3	;THIRD INPUT FILE, FOR 3-WAY MERGES.
CHMRG==4	;/M OUTPUT DEVICE FOR MERGE FILE
CHTTO==5	;ITS NEEDS TYO CHANNEL
CHERR==6	;FOR ERR DEVICE.
CHOUT==7	;OUTPUT CHNL FOR DIFFERENCES.
CHCMD==10	;COMMAND FILE READING CHANNEL.
CHUIN1==11	;/$ USR INPUT
CHUIN2==12	;/$ USR INPUT
CHUO1==13	;/$ and output chans, since need both.
CHUO2==14	;/$

;MAIN AC DEFINITIONS

W1=1
W2=2
W3=3
F1=4	;LINE POINTER FILE 1 (CONTAINS ADDRESS OF LINE BLOCK)
F2=5	;DITTO FILE 2
F3=6	;DITTO FILE 3
FR=7	;FLAG REGISTER (LH) AND FILE #(0 OR 1 OR 2)(RH)
CS=10
C=11	;CONTAINS 1 CHAR FOR PROCESSING
T=12	;TEMPORARY AC (MUNGED BY XJSYS CALLS)
TT=13	;TEMP AC
BP=14	;      (RDLIN AC LOOP) BYTE POINTER IN FILENAME READER.
FP=15	; BP+1 (RDLIN AC LOOP) ADDR OF FILE BLK
;=16	; BP+2 (RDLIN AC LOOP)
P=17	;PUSH DOWN POINTER

	; ACC DEFS FOR TNX JSYS CODE
IFN TNX, R1=1 ? R2=2 ? R3=3 ? R4=4 ? R5=5
	; ACC DEFS FOR STUFF BORROWED FROM MIDAS
IFN TNX, AA=6 ? A=1 ? B=2 ? D=4 ? E=5 ? F=FP	; NOTE A NOT AA+1


	;ASCII CHARACTERS

TAB==11
ALTM==33	;/M ALT-MODE TO END TTY INPUT FOR MERGE(/M)
;FLAGS - LH OF AC FR:

FL==1,,525252	;BIT TYPEOUT MODE MASK.
FLINDR==1	;/@ - FILE NAME FOLLOWS THE STRING ";COMPARISON OF " IN SPEC'D FILE.
		 ;APPLIES TO 1ST INPUT FILE ONLY.
FLXCTF==2	;/X - OPEN A COMMAND FILE AND START EXECUTING FROM IT.
FLISWT==4	;/I - MERGE, BUT AUTOMATICALLY ANSWER "I" TO EVERY QUESTION
		 ;AND DON'T TYPE ON THE TTY.
FLARCH==10	;/A SWITCH - "ARCHIVE". APPEND OUTPUT TO FRONT OF EXISTING FILE.
FLLABL==20	;/L SWITCH - REMEMBER FOR EACH FILE AND LINE THE PREVIOUS LABEL,
		 ;AND PRINT IT IN THE HEADER LINE.
FLENDL==40	;/E SWITCH - PRINT OUT THE FIRST MATCHING LINE FROM EACH FILE
		 ;AFTER EACH RUN OF DIFFERENCES.
FLSPAC==100	;/S SWITCH - IGNORE SPACING
FLCMNT==200	;/C SWITCH - IGNORE COMMENTS
FLALL==400	;/B OR /M SWITCH (ALLOWS COMPARING BLANK LINES)
		; CR,LF,FF STORED LIKE DATA AND COMPARED
FLEOF1==1000	;EOF SEEN ON FILE 1
FLEOF2==2000	;EOF SEEN ON FILE 2
FLEOF3==4000	;EOF SEEN ON FILE 3
FLFNUM==10000	;/W SAYS PRINT FILE # ON EACH LINE OF DIFFERENCES.
FLFLAG==20000	;/F SAYS MAKE COPY OF FILE 2, FLAGGING CHANGED LINES WITH VERT. BARS.
FLCASE==40000	;/K SAYS IGNORE DIFFERENCES IN ALPHABETIC CASE
FLOVRD==100000	;/! SAYS DO THE COMPARISON EVEN IF FILE1 AND FILE2 ARE SAME FILE.
FLXLBL==200000	;/Y SAYS ANY UNINDENTED LINE NOT STARTING WITH A ";" IS A LABEL.
FLMERG==400000	;/M SWITCH-MERGE 2 FILES INTO ONE CONVERSATIONALLY

;RH OF FR TELLS CERTAIN FUNCTIONS WHICH INPUT FILE TO OPERATE ON: 0 => FILE 1, 1 => FILE 2.

; Memory flags (cuz no more room in LH of FR!)
.SCALAR FVBIN	; -1 if doing binary compare (like FILCOM /W)
.SCALAR FSBIN	; -1 if doing SBLK/CSAVE compare
.SCALAR QFLAG	; -1 if doing /Q message at end of compare

;NAMES OF THE HEADER WORDS OF A FILE LINE

LNNEXT==0	;MUST BE 0! ADDR OF HEADER OF NEXT LINE, OR 0 FOR LAST LINE.
LNSIZE==1	;# OF CHARACTERS IN THE LINE, NOT COUNTING TERMINATING ZERO.
LNLLBL==2	;1ST WORD OF ASCIZ OF MOST RECENT LABEL, OR 0.
LNLLB1==3	;2ND WORD OF ASCIZ.  COLON IS INCLUDED.
LNLLB2==4	;4 WORDS IN ALL FOR HOLDING A LABEL.
LNLLB3==5
   LNLBLN==4
LNPGNM==6	;PAGE # THIS LINE STARTED ON
LNLNNM==7	;LINE NUMBER THIS LINE STARTED ON
LNCHNM==10	;CHARACTER NUMBER IN FILE OF 1ST CHARACTER IN LINE
LNDATA==11	;INDEX OF THE FIRST DATA WORD.  THE DATA ARE AN ASCIZ STRING
		;THERE ARE ASSUMED TO BE JUST ENOUGH DATA WORDS
		;TO HOLD THE NUMBER OF CHARACTERS THAT LNSIZE SAYS THERE ARE.


;PARAMETERS

IFNDEF MATCH,MATCH==3		;# LINES TO BE MATCHED BEFORE RUN OF DIFFERENCES ENDS.
IFNDEF WPL,WPL==<40.*4>/5+1	;# WORDS FOR FILENAMES FOR HEADER LINES.
IFNDEF LPDL,LPDL==30		;LENGTH OF PUSH DOWN LIST
IFNDEF FILBFL,FILBFL==100	;LENGTH OF INPUT FILE BUFFERS.
MRGBSZ==FILBFL*5		;MERGE OUTPUT BUFFER LENGTH IN CHARS.

;/M THIS SRCCOM ALSO PERFORMS A MERGE FUNCTION IF /M IS TYPED
;/M DESTINATION FILE BECOMES MERGE OF 2 SOURCE FILES.
;/M DIFFERENCES ARE TYPED ON TTY, USER SELECTS WHICH HE WANTS
;/M AND IN WHAT ORDER BY TYPING IN 1 LINE COMMAND AFTER EACH PAIR
;/M OF DIFFERENCES IS TYPED OUT.
;/M HE MAY TYPE 1, 2, AND/OR T IN ANY ORDER FOLLOWED BY CR
;/M OR HE MAY CHANGE THE LAST COLUMN TYPED OUT TO ### BY TYPING
;/M C### FOLLOWED BY CR AS A SEPARATE COMMAND AFTER ANY PAIR OF DIFFERENCES
;/M TYPED OUT.  SRCCOM WILL RESPOND WITH ANOTHER *, SO THE USER CAN TYPE
;/M ANOTHER COMMAND TO SELECT WHICH DIFFERENCES HE WANTS. INITIALLY THE
;/M MAX. COLUMN IS SET TO 72 WHENEVER SRCCOM IS RESTARTED WITH START COMMAND
;/M IT IS NOT RESET AFTER EACH FILE COMPARED.
;/M SIMILARLY THE USER MAY SET THE MAXIMUM
;/M NUMBER OF LINES TYPED FROM EACH FILE WITH L###.
;OPDEFS

CALL=PUSHJ P,
RET=POPJ P,
SAVE=PUSH P,
REST=POP P,
PJRST==JRST
IFN ITS,ERRHLT==.LOSE
IFN TNX,ERRHLT==HALT

;MACROS

IFN ITS,[
DEFINE SYSCAL A,B
	.CALL [	SETZ ? SIXBIT/A/ ? B ((SETZ))]
TERMIN
]
; This may not work right on TENEX anymore, if so, fix the opsys flags
; so that we can tell 10x from 20x.
IFN TNX, .INSRT MID:XJSYS

DEFINE DBP7J AC,TAG=.+2
	ADD AC,[070000,,]
	JUMPGE AC,TAG
	SUB AC,[430000,,1]
IFSN [TAG].+2,JRST TAG
TERMIN

DEFINE INSIRP INSN,ADDRS
IRPS ADDR,,[ADDRS]
	INSN,ADDR
TERMIN TERMIN

;ADVANCE TO THE NEXT LINE IN FILE FILN, READING IT FROM THE FILE IF NECESSARY.
;GO TO EOFA IF THERE IS NO LINE DUE TO EOF.
DEFINE NEXTLN FILN,(EOFA)
	SKIPE LNNEXT(F1+FILN-1)
	 JRST .+4
	HRRI FR,FILN-1
	CALL RDLIN
IFNB EOFA, JRST EOFA
.ELSE	   CAIA
	     MOVE F1+FILN-1,LNNEXT(F1+FILN-1)
TERMIN
	; SOME MACROS TO MAKE I/O A LITTLE LESS SYSTEM DEPENDENT.
	; OPTIMIZED IN FAVOR OF ITS.
IFN ITS,[
DEFINE M.CLS CH		; CLOSE CHAN
.CLOSE CH,
TERMIN

DEFINE M.MVCH CH1,CH2	; MOVE CHANNEL FROM CH1 TO CH2
.IOPUS CH1,
.IOPOP CH2,
TERMIN

DEFINE MOUTC CH,?LOC	; SINGLE CHAR OUTPUT
.IOT CH,LOC
TERMIN

DEFINE M.BIN CH,LOC
.IOT CH,LOC
TERMIN

DEFINE M.SOUT CH,BPA,CNTA
SYSCAL SIOT,[MOVEI CH ? BPA ? CNTA]
 .LOSE %LSFIL
TERMIN

DEFINE M.SIN CH,BPA,CNTA
SYSCAL SIOT,[MOVEI CH ? BPA ? CNTA]
 .LOSE %LSFIL
TERMIN
] ;IFN ITS

IFN TNX,[
DEFINE M.CLS CH		; CLOSE CHAN
	SAVE R1
	SKIPLE R1,JFNCHS+CH
	 CLOSF
	  ERJMP .+1
	SETZM JFNCHS+CH
	REST R1
TERMIN

DEFINE M.MVCH CH1,CH2	; MOVE CHANNEL FROM CH1 TO CH2
	SAVE R1
	SETZ R1,
	EXCH R1,JFNCHS+CH1
	EXCH R1,JFNCHS+CH2
	CAILE R1,
	 CLOSF
	  ERJMP .+1
	REST R1
TERMIN

DEFINE MOUTC CH,?LOC	; OUTPUT BYTE AT LOC
CALL [	PUSH P,JFNCHS+CH
	PUSH P,LOC
	PJRST TOUTC]
TERMIN

DEFINE M.BIN CH,LOC	; INPUT BYTE TO LOC
CALL [	PUSH P,JFNCHS+CH
	PUSH P,[LOC]
	JRST TINC]
TERMIN

DEFINE M.SOUT CH,BPA,CNTA	; OUTPUT STRING
MOVNS CNTA
SYSCAL SOUT,[JFNCHS+CH ? BPA ? CNTA][JUNK ? BPA ? CNTA]
MOVNS CNTA
TERMIN

DEFINE M.SIN CH,BPA,CNTA	; INPUT STRING
MOVEI T,[JFNCHS+CH ? BPA ? CNTA]
CALL TINS
TERMIN

] ;IFN TNX

DEFINE MOUTI CH,VAL		; OUTPUT IMMEDIATE VALUE
MOUTC CH,[VAL]
TERMIN

	; SO MIDAS-BORROWED CODE WILL INTEGRATE BETTER.
DEFINE ETF ?ASCZ
JRST [	JSP T,ERRMSG
	ASCZ
]
TERMIN
DEFINE TYPE &STR
CALL [	PUSH P,[[ASCIZ STR]]
	PJRST TYPM]
TERMIN

DEFINE PRINTI &STR&
	MOVEI C,.LENGTH STR
	MOVE W2,[440700,,[ASCIZ STR]]
	CALL PNTCNT
TERMIN
SUBTTL File Description Storage (FILBLK's)


	; Definitions for indices into a FILBLK.

	; Scratch block FB is formed while defining indices...
	OFFSET -.
		; Lots of crocks depend on the exact order of these 4 items.
IFN ITS\DEC,[
$F6DEV:: 0			; SIXBIT Device name
$F6FN1:: 0			; SIXBIT Filename (on ITS, FN1)
$F6FN2:: 0			; SIXBIT Extension (on ITS, FN2)
$F6DIR:: 0			; SIXBIT Directory (may be numerical PPN)
$FDEV==:$F6DEV		; These definitions made so some common code can do
$FDIR==:$F6DIR		; the right things.
$FNAME==:$F6FN1
$FEXT==:$F6FN2
$FVERS==:$F6FN2
]
IFN TNX,[		; Almost all entries here are BP's to ASCIZ strings.
$FDEV::  0		; Device name
$FDIR::  0		; Directory name
$FNAME:: 0		; File name (i.e. main name)
$FEXT::	 0		; File type (or extension)
$FVERS:: 0		; File version (or generation).  NUMBER, not string.
$FTEMP:: 0		; -1 => File is a temporary file.
$FACCT:: 0		; Account string
$FPROT:: 0		; Protection string
$FJFN::  0		; JFN for file (may be <desired JFN>,,<temp JFN>)
]
	L$FBLK==.	; Length of a FILBLK.
	OFFSET 0	; End of index definitions.


INFB:	BLOCK L$FBLK
LSTFB:	BLOCK L$FBLK

IFN TNX,[
JFNCHS:	BLOCK 20	; INDEXED BY CHAN #, HOLDS JFNS
]
;SRCCOM STARTS HERE

BEG:	MOVE	P,[-LPDL,,PPSET-1]	;SET UP PDL.

IFN ITS,[
	.OPEN	CHTTI,[.UAI,,'TTY]
	 ERRHLT
	.OPEN	CHTTO,[.UAO,,'TTY]
	 ERRHLT
	.SUSET	[.RSNAM,,DEFDIR]	;GET DEFAULT DIR.
	.SUSET	[.ROPTIO,,W1]
	TLO	W1,OPTOPC
	.SUSET	[.SOPTIO,,W1]
	.SUSET	[.SMASK,,[%PIMPV]]
	.SUSET	[.SMSK2,,[1_CHTTO+1_CHOUT]] ;ENABLE --MORE-- INTERRUPTS
] ;IFN ITS

IFN TNX,[
	RESET
	CALL SEE20X		; SEE IF 10X OR 20X.
	MOVEI W1,.PRIIN
	MOVEM W1,JFNCHS+CHTTI
	MOVEI W1,.PRIOU
	MOVEM W1,JFNCHS+CHTTO
]
	CALL GETJCL		; LOOK FOR JCL, SKIP IF FOUND
	 CAIA			; NONE
	  JRST RESTR1		; HAVE SOME, GO EXECUTE.

	MOVE	0,[SIXBIT/SRCCOM/] ;NO COMMAND STRING FROM SUPERIOR:
	CALL	TTOSIX		;IDENTIFY SELF TO USER.
	MOUTI	CHTTO,40	;SPACE
IFDEF .FVERS,[
	MOVE 0,[.FVERS]
	CALL	TTODEC
]
.ELSE [
	MOVE	0,[.FNAM2]	;PRINT VERSION NUMBER.
	CALL	TTOSIX
]
	JRST	RESTRT
;COME HERE FOR A NEW COMMAND, AFTER FINISHED OR ERROR.

RESTRT:	SETZM TTIBUF
RESTR1:	MOVE P,[-LPDL,,PPSET-1]	;SET UP PUSH DOWN LIST
IFN ITS,.SUSET [.SWHO1,,[0]]	;CLEAR USER-SPEC'D WHOLINE FIELDS.
IFN ITS,.SUSET [.SMEMT,,[ENDCOR]]
	SETZB FR,BEGP		;THIS IS THE ZERO WHICH WILL
				;BE "BLT"ED TO CLEAR CORE
	MOVE 0,[BEGP,,BEGP+1]
	BLT ENDP-1
IFN TNX,[
	MOVE 0,[FNBUF,,FNBUF+1]
	SETZM FNBUF
	BLT 0,FNBUF+LFNBUF-1
];TNX

	MOVE W1,[440700,,MRGBF]
	MOVEM W1,MRGBP
	MOVEI W1,MRGBSZ
	MOVEM W1,MRGCT
	MOVE W1,SEG1
	MOVEM W1,LBUFP1
	MOVE W1,SEG2
	MOVEM W1,LBUFP2
	MOVE W1,SEG3
	MOVEM W1,LBUFP3
	AOS PAGNUM+0		;ZEROED BY BLT ABOVE-1ST PAGE IS 1
	AOS PAGNUM+1		;DITTO FOR SECOND FILE
	AOS PAGNUM+2
	AOS LINNUM+0		;SAME TRUE FOR 1ST LINE
	AOS LINNUM+1
	AOS LINNUM+2
	SKIPE	TTIBUF		;IF HAVE A JCL COMMAND,
	 SETOM	CTLCF		;SAY RETURN AFTER JUST THIS CMD.
	SKIPN	TTIBUF
	 CALL	CMDLIN		;NO DDT CMD, READ TTY LINE.
	CALL	TRYHLP		;IF COMMAND IS JUST "?" OR "HELP", PRINT HELP.
	MOVE	C,FSTTY		;OUTPUT DEFAULTS TO TTY IF NOT SPEC'D,
	SKIPN	CMDFIL		;UNLESS WE'RE IN A COMMAND FILE.
	 MOVEM	C,LSTFB+$FDEV
	MOVEI	FP,INFB
	CALL	RFILE		;READ FILE NAME
	CAIE	C,"=
IFE TWX,[			;Don't recognize "_" on Twenex, screws filenames
	 CAIN	C,"_		;IF FOLLOWED BY "_", IS OUTPUT SPEC,
	  CAIA
]
	  JRST	CMD3
	MOVE	C,[INFB,,LSTFB]
	BLT	C,LSTFB+L$FBLK-1	;SO USE AS LST FILE NAMES.
	SETOM	LSTEXP		;SAY LST FILE WAS EXPLICITLY SPECIFIED.
	SETZM	INFB+$FDEV
	SKIPE	CMDFIL		;IF NOT IN A COMMAND FILE, 1ST INPUT FILE SNAME
	 SETZM	INFB+$FDIR	;DEFAULTS TO OUTPUT FILE SNAME.
	CALL	RFILE		;AND READ ANOTHER SPEC FOR 1ST INPUT FILE.
	JRST	CMD3
;NOW HAVE READ WHAT IS CERTAINLY THE 1ST INPUT SPEC.
CMD3:	MOVE	W2,DEFDIR	;DEFAULT THE OUTPUT FILE DEV AND SNAME NOW.
	SKIPE	CMDFIL		;CAN DO IT SINCE IT DOESN'T DEPEND ON SWITCH SETTINGS
	 MOVE	W2,CMDOS	;AND MUST DO IT SINCE MIGHT GO TO CMDXCT AND WANT
	SKIPN	LSTFB+$FDIR	;TO KNOW THEIR FINAL VALUES.
	 MOVEM	W2,LSTFB+$FDIR
	MOVE	W2,FSDSK
	SKIPE	CMDFIL
	 MOVE	W2,CMDOD
	SKIPN	LSTFB+$FDEV
	 MOVEM	W2,LSTFB+$FDEV
	TLNN	FR,FLINDR	;IF THE FIRST INPUT FILE IS INDIRECT, DEFAULT THE FN2
	 JRST	CMD6		;OF THE FILE TO GO INDIRECT THROUGH TO
	MOVE	W1,FSCMP	;TO THE FN2 OF THE LISTING FILE, AS WELL AS WE CAN.
	TLNE	FR,FLARCH	;CAN LOSE IN OBSCURE SITUATIONS THAT THE DOCUMENTATION
	 MOVE	W1,FSCMPA	;WARNS USERS TO AVOID.
	SKIPE	LSTFB+$FEXT
	 MOVE	W1,LSTFB+$FEXT
	SKIPN	INFB+$FEXT
	 MOVEM	W1,INFB+$FEXT
	MOVE	W1,LSTFB+$FDIR	;ALSO DEFAULT SNAME AND DEV THAT WAY, BUT NEVER USE TTY:
	SKIPN	INFB+$FDIR	;NOTE THAT THE FN1 WILL DEFAULT TO THE LIST FILE'S
	 MOVEM	W1,INFB+$FDIR	;ANYWAY.
	MOVE	W1,LSTFB+$FDEV
	CAMN	W1,FSTTY
	 MOVE	W1,FSDSK
	SKIPN	INFB+$FDEV
	 MOVEM	W1,INFB+$FDEV
CMD6:	MOVE	W1,CMDIS
	SKIPN	CMDFIL
	 MOVE	W1,DEFDIR
	SKIPN	INFB+$FDIR
	 MOVEM	W1,INFB+$FDIR
	MOVE	W1,CMDID	;DEFAULT DEVICE FOR 1ST INPUT FILE DEPENDS ON
	SKIPN	CMDFIL		;WHETHER WE'RE IN A COMMAND FILE.
	 MOVE	W1,FSDSK
	SKIPN	INFB+$FDEV
	 MOVEM	W1,INFB+$FDEV
	SKIPN	W1,INFB+$FVERS
	 MOVE	W1,FVLOW	;IF ONLY ONE INPUT FILE SPECIFIED, DEFAULT ITS FN2 TO "<",
	SKIPG	TTICNT		;SINCE 2ND INPUT FILE WILL BE THE ">" OF THE SAME FILE.
	 MOVEM	W1,INFB+$FVERS
RFIND1:	MOVEI	W1,CHIN1
	CALL	INOPEN		;NOW OPEN CHANNEL CHIN1.
	TLNE	FR,FLXCTF	;IS THIS AN EXECUTE FILE?
	 JRST	CMDXCT
	TLNE	FR,FLINDR	;MAYBE THE FILE WE OPENED JUST HAS THE NAMES OF THE
	 JRST	RFINDR		;REAL 1ST INPUT FILE.  IF SO, READ THEM.
	CALL	RFILE		;READ NAMES OF & OPEN 2ND INPUT.
	MOVEI	W1,CHIN2
	CALL	INOPEN
	TLNE	FR,FLINDR\FLXCTF
	 JRST	ERRIN2		;FILE 2 INDIRECT?  THAT ISN'T ALLOWED.
	SKIPG	TTICNT		;MORE FILES?  MUST BE A 3-WAY MERGE.
	 JRST	CMD4
	CALL	RFILE		;READ THE THIRD FILE'S NAME.
	TLNN	FR,FLMERG
	 JRST	ERR3NM		;ERROR IF /M NOT SPECIFIED.
	SETOM	3WAY
	MOVEI	W1,CHIN3
	CALL	INOPEN
	TLNE	FR,FLINDR\FLXCTF ;ERROR IF THIRD FILE IS INDIRECT.
	 JRST	ERRIN3
	SKIPG	TTICNT		;ERROR IF ANYTHING LEFT AFTER THIRD FILE NAME.
	 JRST	ERRXTRA
	JRST	CMD4
;NOW OPEN THE OUTPUT FILE.
CMD4:	MOVEI FP,LSTFB
	MOVE W2,FSCMP		;NORMAL DEFAULT OUTPUT FN2.
	TLNE FR,FLARCH
	 MOVE W2,FSCMPA
	MOVEI W1,CHOUT			;NORMALLY, SPEC'D FILE IS OUTPUT FILE,
	TLNN FR,FLMERG
	 JRST CMD5
	TLNE FR,FLARCH
	 JRST ERRARC
	MOVEI W1,CHMRG			;BUT IF /M, IT IS MERE FILE NAME,
IFN ITS,[
	.OPEN CHOUT,[.UAO,,'TTY]	;AND OUTPUT IS TO TTY:
	 ERRHLT
]
IFN TNX,[
	PUSH P,JFNCHS+CHTTO
	POP P,JFNCHS+CHOUT
]
	MOVE W2,FSDMF2
	TLNE FR,FLFLAG			;ALSO, WE HAVE DIFFERENT DEFAULT FN2'S
	 MOVE W2,FSFLGD
	MOVE T,FSTTY
	SKIPL LSTEXP			;AND DON'T DEFAULT TO TTY:; USE DSK: INSTEAD.
	 CAME T,LSTFB+$FDEV
	  JRST CMD5
	MOVE T,FSDSK
	MOVEM T,LSTFB+$FDEV
CMD5:	SKIPN LSTFB+$FEXT		;DEFAULT THE FN2 IF NEC.
	 MOVEM W2,LSTFB+$FEXT
IFN ITS,[
	SYSCAL TRANS,[
		$FDEV(FP) ? $FNAME(FP) ? $FEXT(FP) ? $FDIR(FP)
		MOVEI .UAO
		MOVEM $FDEV(FP) ? MOVEM $FNAME(FP)
		MOVEM $FEXT(FP) ? MOVEM $FDIR(FP)]
	 CALL OPENL
	SYSCAL OPEN,[5000,,.UAO ? W1
		$FDEV(FP) ? ['_SRCCO] ? ['OUTPUT] ? $FDIR(FP)]
	 CALL OPENL		;ERROR RTN, IN CASE FAILED.
	SYSCAL TTYGET,[MOVEI CHOUT ? MOVEM TTYST1 ? MOVEM TTYST2 ? MOVEM W1]
	 JRST CMD2		;JUMP IF OUTPUT FILE ISN'T A TTY.
	SETOM OUTTTY
	MOVEM W1,TTYSTS		;IT IS A TTY; SAVE THE TTYSTS TO RESTORE LATER
	TLZE W1,%TSMOR		;AND TURN ON **MORE**'ING NOW.
	 SYSCAL TTYSET,[MOVEI CHOUT ? TTYST1 ? TTYST2 ? W1]
	  JFCL
] ;IFN ITS
IFN TNX,[
	MOVE T,FSTTY
	CAMN T,LSTFB+$FDEV	; ABOUT TO OPEN TTY FOR OUTPUT?
	 JRST [	PUSH P,JFNCHS+CHTTO	; IF SO JUST DUPLICATE TTY JFN
		POP P,JFNCHS+CHOUT
		SETOM OUTTTY
		JRST CMD20]
	MOVEI FP,LSTFB
	HRLI FP,(W1)		; GET <CHAN>,,<FB PTR>
	CALL OPNWR
	 CALL OPENL
CMD20:
]

;FINAL INITIALISATION, AND PRINTING OF THE FILE HEADER.
CMD2:	SETZB F1,F2		;RIGHT NOW WE HAVE NO LINES OF EITHER FILE IN CORE.
	TLNE FR,FLMERG		;IF MERGING, LINES FLUSHED FROM FILE 1
	 SETOM MRGOUT+0		;GO OUT TO THE MERGE FILE.
	SETZ 0,
IFN ITS,[
	.SUSET [.SWHO1,,[.BYTE 8 ? 166 ? 0 ? 55 ? ",]]
	.SUSET [.SWHO3,,[1,,1]]	;INITIALIZE THE USER WHO-LINE FIELDS.
	.SUSET [.SWHO2,,['HEADER]]
]
	SKIPE 3WAY		;3-WAY MERGES HAVE A SPECIAL MAIN LOOP.
	 JRST 3LOOP
	TLNE FR,FLMERG
	 JRST ENTER
	MOVSI W1,-WPL
	MOVE T,HBUF1(W1)	;LOOK FOR DIFFERENCES BETWEEN REAL FILE NAMES
	CAMN T,HBUF2(W1)	;OF OUR TWO INPUT FILES.
	 AOBJN W1,.-2
	TLNN FR,FLOVRD		;UNLESS FORCED BY /!,
	 JUMPGE W1,FIN5		;IF THE NAMES ARE THE SAME, DON'T WASTE TIME COMPARING.
	MOVEI W1,[ASCIZ /
;COMPARISON OF /]
	CALL PRINT
	MOVE W1,RCHSTP
	CALL PRINT
	MOVEI W1,[ASCIZ / AND /];RFINDR DEPENDS ON EXACT STRINGS USED HERE.
	CALL PRINT
	MOVE W1,RCHSTP+1
	CALL PRINT
	MOVEI W1,[ASCIZ /
;OPTIONS ARE   /]		;NOTE RFINDR DEPENDS ON PRECISE STRING USED HERE.
	CALL PRINT
IRPS X,,FLARCH FLALL FLCMNT FLENDL FLCASE FLLABL FLSPAC FLFNUM FLXLBL,Y,,A B C E K L S W Y
	MOVEI W1,[ASCIZ * /Y*]
	TLNE FR,X
	 CALL PRINT
TERMIN
	MOVEI W1,[ASCIZ " /#"]
	SKIPE FVBIN
	 CALL PRINT
	MOVEI W1,[ASCIZ " /$"]
	SKIPE FSBIN
	 CALL PRINT
	MOVEI W1,[ASCIZ * /*]
	CALL PRINT
	MOVE T,NUMLIN
	AOS T
	CALL PNTDEC
	CALL PCRLF
	CALL PCRLF
	JRST ENTER
ENTER:
IFN ITS,.SUSET [.SWHO2,,[SIXBIT/SAME/]]
	SKIPE FVBIN		; Normally no binary compare
	 JRST BSAME		; Gadzooks!  Use special routine.
	SKIPE FSBIN
	 JRST SBSAME		; Use special SBLK compare routine

;THIS IS THE MAIN LOOP OF SRCCOM.

;COME HERE WHEN THE LAST TWO LINES MATCHED, TO TRY THE NEXT TWO.
SAME:	SKIPE F1,LNNEXT(F1)	;ADVANCE PAST THE LINE THAT MATCHED
	 JRST SAME1
	TRZ FR,-1		;IF NO MORE LINES IN CORE, FLUSH ALL
	SKIPE MRGOUT+0		;THE LINES WE PASSED BY,
	 CALL MOVEUP
	SETZM NLINE1		;(IN THE SIMPLE COMMON CASE, FLUSH THEM FAST)
	CALL RDLIN		;AND READ ANOTHER.
	 JRST END0		;EOF => CHECK FILE 2 FOR EOF.
	 ERRHLT
SAME1:	SKIPE F2,LNNEXT(F2)	;SIMILAR FOR F2,
	 JRST SAME2
	SETZM NLINE2		;BUT SINCE MRGOUT+1 SHOULD BE ZERO, IT'S SIMPLE.
	HRRI FR,1
	CALL RDLIN
	 JRST DIFF		;EOF IN FILE 2 BUT NOT IN FILE 1 => IT'S A DIFFERENCE.
	 ERRHLT
SAME2:	CALL COMPL
	 JRST SAME		;THE TWO LINES ARE IDENTICAL; KEEP SCANNING.
	JRST DIFF		;ELSE SEE HOW BIG THIS RUN OF DIFFERENCES IS.

; BINARY COMPARE - Main loop.

BSAME:	TRZ FR,-1
	CALL RDWRD		; Get word in W1
	 JRST BEND0		; EOF => check file 2 for EOF
	MOVE W2,W1
	HRRI FR,1
	CALL RDWRD		; Get another word from file 2
	 JRST BEND1		; EOF on file 2, it"s a difference.
	CAMN W1,W2		; Compare words
	 JRST BSAME		; Won, get next one.
	JRST BDIFF
BEND0:	MOVE W2,W1	; EOF on file 1, check file 2
	HRRI F1,1
	CALL RDWRD
	 JRST FIN2	; If EOF on file 2 also, win!
	PRINTI "        EOF on file 1
"
	AOS ERRCNT
	JRST FIN2
BEND1:	PRINTI "                          EOF on file 2
"
	AOS ERRCNT
	JRST FIN2

	; Words are different.  Must print out and show
	; addr: <wd 1> <wd 2>  <xor>
BDIFF:	AOS ERRCNT		; Bump count of diffs
	PUSH P,W1
	PUSH P,W2
	MOVE T,GWORDL(FR)
	SUB T,GWORDC(FR)	; Find # words read thus far
	CALL PNTOCT
	PRINTI ": "
	MOVE T,(P)
	CALL PNTHWD
	PRINTI "    "
	MOVE T,-1(P)
	CALL PNTHWD
	PRINTI "  XOR= "
	POP P,T
	XOR T,(P)
	CALL PNTHWD
	POP P,T
	CALL PCRLF
	JRST BSAME
; Program ("SBLK") BINARY COMPARE - Main loop.

.SCALAR GWADR		; Address of word to get


SBSAME:	TRZ FR,-1
	CALL RDUWRD		; Get word in W1
	 JRST SBEND0		; EOF => check file 2 for EOF
	MOVE W2,W1
	HRRI FR,1
	CALL RDUWRD		; Get another word from file 2
	 JRST SBEND1		; EOF on file 2, it"s a difference.
	CAME W1,W2		; Compare words
	 JRST SBDIFF
SBSAM0:	AOS W1,GWADR
	CAIG W1,-1
	 JRST SBSAME
	JRST FIN2

SBEND0:	MOVE W2,W1	; EOF on file 1, check file 2
	HRRI F1,1
	CALL RDWRD
	 JRST FIN2	; If EOF on file 2 also, win!
	PRINTI "        EOF on file 1
"
	AOS ERRCNT
	JRST FIN2
SBEND1:	PRINTI "                          EOF on file 2
"
	AOS ERRCNT
	JRST FIN2

	; Words are different.  Must print out and show
	; addr: <wd 1> <wd 2>  <xor>
SBDIFF:	AOS ERRCNT		; Bump count of diffs
	PUSH P,W2
	PUSH P,W1
	MOVE T,GWADR	; Find # words read thus far
	CALL PNTOCT
	PRINTI ": "
	MOVE T,-1(P)	; Get wd from file 1
	CALL PNTHWD
	PRINTI "    "
	MOVE T,(P)	; Then wd from file 2
	CALL PNTHWD
	PRINTI "  XOR= "
	POP P,T
	XOR T,(P)
	CALL PNTHWD
	POP P,T
	CALL PCRLF
	JRST SBSAM0
;COME HERE WHEN A DIFFERENCE IS SEEN. F1 AND F2 POINT TO THE 1ST PAIR OF NON-MATCHING
;LINES, OR ARE ZERO TO SAY THAT AN ENTIRE FILE HAS BEEN MATCHED OFF.
DIFF:	CALL MOVEUP	;FLUSH ANY MATCHING LINES STILL IN CORE BEFORE THOSE TWO.
	TRC FR,1
	CALL MOVEUP
	SKIPE 0		;0 SHOULD ALWAYS HOLD 0 FOR NEXTLN'S SAKE.
	 ERRHLT
IFN ITS,.SUSET [.SWHO2,,[SIXBIT/DIFF/]]
	SETZM NCOMP1	;NCOMP1 GETS NUMBER OF LINES OF FILE 1 WE HAVE FOR
	SKIPE F1	;CONSIDERATION.
	 AOS NCOMP1
	SETZM NCOMP2	;NCOMP2 GETS THE SAME THING FOR FILE 2.
	SKIPE F2
	 AOS NCOMP2
DIFFRD:	NEXTLN 1,END2	;READ ANOTHER LINE FROM EACH FILE.
	AOS NCOMP1
	NEXTLN 2,DIFF2	;NO NEW LINE FROM FILE 2 => DON'T COMPARE FILE 1 WITH IT
DIFF3:	AOS NCOMP2
	SKIPN CS,NCOMP1	;HOW MANY FILE 1 LINES SHOULD WE CONSIDER?
	 JRST DIFFRD	 ;NONE?
	SKIPA F1,LBUFP1	;ELSE COMPARE ALL THE NON-MATCHING LINES OF FILE 1, 1 AT A TIME,
DIFF0:	 MOVE F1,W1	;WITH THE NEW LINE FROM FILE 2.
	CALL COMPL
	 CALL MULTI	;MATCH => CHECK FOR MULTI-LINE MATCH, GO TO SAME IF FOUND.
	SKIPE W1,LNNEXT(F1)
	 SOJG CS,DIFF0
;AFTER COMPARING ALL THE FILE 1 LINES WITH THE NEW FILE 2 LINE, OR IF THERE IS NO NEW
;FILE 2 LINE, COME HERE TO COMPARE THE NEW FILE 1 LINE WITH ALL THE FILE 2 LINES.
;F1 IS ALREADY POINTING AT THE NEW FILE 1 LINE ("NEW" MEANS THAT DIFFRD GOT IT.
;IT MIGHT HAVE BEEN IN CORE ALREADY DUE TO NEXTLN'S DONE INSIDE MULTI).
DIFF2:	SKIPE EOFFL1	;BUT DON'T DO IT IF NO NEW FILE 1 LINE.
	 JRST DIFFRD
	SKIPN CS,NCOMP2	;HOW MANY LINES ARE WE CONSIDERING YET FROM FILE 2?
	 JRST DIFFRD	 ;NONE => NOTHING TO COMPARE WITH THE NEW LINE FROM 1.
	SKIPA F2,LBUFP2	;(MAY NOT BE SAME AS NLINE2, IF MULTI READ SOME LINES.)
DIFF1:	 MOVE F2,W1	;ELSE LOOP HERE OVER THE FILE 2 LINES.
	CALL COMPL
	 CALL MULTI
	SKIPE W1,LNNEXT(F2)
	 SOJG CS,DIFF1
	JRST DIFFRD	;NO MATCH => READ ANOTHER PAIR OF LINES AND TRY MATCHING THEM.

END0:	SKIPE F2,LNNEXT(F2)	;HERE WHEN EOF IN FILE 1 AT SAME.
	 JRST DIFF	;MORE LINES IN FILE 2 => THEY'RE DIFFERENT.
	SETZM NLINE2
	HRRI FR,1
	CALL RDLIN
	 JRST FIN2	;EOF IN FILE 2 => ALL DONE.
	 ERRHLT
	JRST DIFF

END2:	NEXTLN 2,FINDIF	;NO NEW FILE 1 LINE IN DIFFRD. NO NEW FILE 2 LINE EITHER =>
	JRST DIFF3	;ALL THE NON-MATCHING LINES WE HAVE ARE DIFFERENCES.
			;NEW LINE FROM FILE 2 => TRY MATCHING IT AGAINST FILE 1 LINES.
;AT THIS POINT NEITHER FILE HAS ANY MORE LINES TO BE READ.
;PRINT AS DIFFERENCES ANY LINES REMAINING FOR EITHER FILE.

FINDIF:	SETZB F1,F2		;MAKE SURE ALL LINES PRINTED IN CASE NO /E.
	CALL COMSPC		;SEE IF DIFFERENCES VANISH IF WE IGNORE SPACES AND COMMENTS.
	 JRST FIN2		 ;THEY DO;  DON'T PRINT AS DIFFERENCES.
	CALL PNTBTH		;PRINT ANY LINES
	CALL TRYMRG
	 JRST FIN2
	MOVEI W1,[ASCIZ/***************
/]
	CALL PRINT

;COME HERE WHEN THE OUTPUT AND MERGE FILES ARE ALL GENERATED.
FIN2:	TRZ FR,-1		;OUTPUT THE STUFF IN FILE 1, IN CASE IN /M MODE.
	CALL MOVEUP
	TLNN FR,FLARCH		;IF SUPOSED TO BE ARCHIVING, DO THE APPEND NOW.
	 JRST FIN3
	SKIPN ERRCNT		;BUT IF NO NEW STUFF TO APPEND, DO NOTHING,
	 JRST FIN5		;AND THROW AWAY OUR 0-BLOCK FILE.
	MOVE FP,[CHIN1,,LSTFB]
	CALL OPNRDA
	 JRST FIN3		;NO OLD FILE => JUST MAKE NEW ONE.
	MOUTI CHOUT,^L
FIN4:	MOVE W2,GCHARB		;IF SO, IF WE'RE ABOUT TO OVERWRITE A FILE,
	MOVEI C,FILBFL*5	;APPEND ITS OLD CONTENTS TO OUR OUTPUT, WITH ^L BETWEEN.
	M.SIN CHIN1,W2,C		; INPUT
	MOVNS C
	ADDI C,FILBFL*5
	JUMPE C,FIN3
	MOVE W2,GCHARB
	CALL PNTCNT
	JRST FIN4

FIN5:
	M.CLS CHOUT
IFN ITS,[
	SYSCAL DELETE,[LSTFB+$FDEV ? ['_SRCCO] ? ['OUTPUT] ? LSTFB+$FDIR]
	 JFCL
]

FIN3:	TLNE FR,FLMERG
	 CALL MRGFRC		;IF MERGING, FORCE OUT OUR BUFFER.
	MOVEI W1,CHOUT		;WHICH CHANNEL IS OUR MOST IMPORTANT OUTPUT FILE ON?
	TLNE FR,FLMERG
	 MOVEI W1,CHMRG
	CALL RENMLO
	MOVEI T,[ASCIZ /NO DIFFERENCES ENCOUNTERED/]
	SKIPN ERRCNT		;ANY DIFFERENCES?
	 CALL TYPMS0		;NO, PRINT MESSAGE
	MOVEI T,[ASCIZ /? FILES ARE DIFFERENT/]
	SKIPE QFLAG		;/Q MODE ON?
	 SKIPN ERRCNT		;/Q YES, ANY DIFFERNCES
	  SKIPA			;/Q NO
	   CALL TYPMS0		;/Q YES
	SKIPE ERRCNT		;/M ANY DIFFERENCES?
	 TLNN FR,FLMERG		;/M YES, MERGE IN PROGRESS?
	  JRST RELDEV		;/M NO, END OF SOURCE COMPARE
	MOVEI T,[ASCIZ /END OF MERGE/]
	TLNN FR,FLISWT\FLFLAG
	 CALL TYPMSG		;/M YES, PRINT END OF MERGE
	JRST RELDEV		;END OF SOURCE COMPARE
;CALL MULTI TO CHECK FOR A MULTI-LINE MATCH, IF NECESSARY.
;IF THERE IS ONE, OR IT ISNT NECESSARY (NUMLIN = 0), RETURNS TO SAME
;AFTER PRINTING THE DIFFERENCES. IF THE MATCH FAILS, IT RETURNS
;NON-SKIPPING TO ITS CALLER.

;IN A 3-WAY MERGE, WE ARE USED TO COMPARE FILES 1 AND 2.
;WHEN WE FIND A MULTI-LINE MATCH, WE PUSH AN ENTRY ON
;12MTAB, THE TABLE OF PLACES WHERE FILES 1 AND 2 MATCH.
;EACH SUCH PLACE GETS COMPARED AGAINST FILE 3 LATER.

MULTI:	SAVE CS
	MOVEM F1,TEMPF1		;SAVE CURRENT POINTERS
	MOVEM F2,TEMPF2
	SKIPG NUMLIN		;MULTIPLE LINE TEST?
	 JRST MULT8		;NO
	SETZM NUMTMP		;INIT MULTI-LINE COUNTER
MULT2:	NEXTLN 1,MULTE		;MUST GET A NEW LINE FROM BOTH FILES
	NEXTLN 2,MULT4		;TO CONTINUE THE MULTI-LINE MATCH.
	CALL COMPL		;COMPARE THEM
	  JRST MULT6		;MATCH, TEST MULTI COUNTER
MULT4:	SKIPE F1,TEMPF1		;NO MATCH, RESET REGS
	 SETZM EOFFL1		;IF NO LONGER AT LAST LINE, CAN'T BE AT EOF.
	SKIPE F2,TEMPF2
	 SETZM EOFFL2
	REST CS
	RET

MULTE:	NEXTLN 2,MULT8
	JRST MULT4

MULT6:	AOS W1,NUMTMP		;INDEX MULTI-LINE COUNTER
	CAMGE W1,NUMLIN		;TEST FOR ENOUGH LINES MATCHED
	 JRST MULT2		;COMPARE NEXT TWO.
MULT8:	SKIPE 3WAY
	 JRST [	MOVE W1,TEMPF2	;IN A 3-WAY MERGE, RECORD THIS MATCH OF FILES 1 AND 2
		HRL W1,TEMPF1
		IDPB W1,12MTBP
		JRST MULT4]	;AND RETURN TO OUR CALLER (JUST AS IF WE HAD FAILED).
	EXCH F1,TEMPF1		;REMEMBER WHERE THE MULTI-LINE MATCH STOPPED,
	EXCH F2,TEMPF2		;GO BACK TO WHERE IT STARTED.
	SUB P,[2,,2]		;FLUSH MULTI'S RETURN ADDRESS.
	CALL COMSPC		;SEE IFF ALL DIFFERENCES VANISH WHEN IGNORE SPACES & COMMENTS.
	 JRST MULT10
	CALL PNTBTH		;PRINT DIFFERENCES

;THE TEXT OF DIFFERENCES HAS BEEN PRINTED--PUT IN ******
;AND A CARRIAGE RETURN-LINE FEED AND GO BACK AND START COMPARING
;WHEN WE START COMPARING AGAIN THE LINE POINTERA WILL
;BE POINTING TO THE FIRST TWO LINES AFTER THE MATCHING LINES

	CALL TRYMRG		;/M CHECK IF /M IN EFFECT, ASK FOR COMMAND
				;/M AND OUTPUT IF YES
	  JRST	MULT10		;/M IN EFFECT
	MOVE W1,[440700,,[ASCIZ /***************

/]]
	CALL PRINT
MULT10:	SKIPE F1,TEMPF1		;NOW MOVE FORWARD PAST THE LINES MATCHED
	 SETZM EOFFL1		;IN THE MULTI-LINE MATCH.
	SKIPE F2,TEMPF2
	 SETZM EOFFL2
	JRST ENTER
;AFTER FINDING A RUN OF DIFFERENCES, SEE WHETHER THE FILES ARE IDENTICAL
;WHEN WE IGNORE SPACES AND COMMENTS ACCORDING TO THE /S AND /C SWITCHES.
;IF SO, RETURNS NON-SKIPPING.  SKIPS IF THE DIFFERENCE SHOULD BE PRINTED.
;EVEN IF /S AND /C ARE NOT SET, THIS ROUTINE TAKES CARE OF IGNORING
;DIFFERENCES IN BLANK LINES.  ALSO, IF /K, IGNORES DIFFERENCES IN CASE.

COMSPC:	TLNE FR,FLSPAC		;THIS ROUTINE CAN MAKE A DIFFERENCE IF
	 TLNE FR,FLALL		;WE ARE IGNORING BOTH SPACING AND BLANK LINES
	  TLNE FR,FLCMNT	;OR WE ARE IGNORING COMMENTS.
	   CAIA
	    JRST POPJ1		;NOTHING IGNORED => DO PRINT.
	SAVE F1
	SAVE F2
	SKIPE F1,NLINES+0	;MAKE F1 AND F2 POINT AT THE FIRST DIFFERING LINES.
	 MOVE F1,LBUFP+0
	SKIPE F2,NLINES+1
	 MOVE F2,LBUFP+1
COMSPL:	CAMN F1,-1(P)		;HAVE WE CONSIDERED ALL THE LINES FROM FILE 1?
	 JRST COMSP2
	HRRI FR,0		;NO.
	TLNN FR,FLALL		;DON'T SKIP LINES WITH JUST COMMENTS IF NOT IGNORING BLANK LINES!
	 CALL BLANKP		;FIRST, TRY TO IGNORE ESSENTIALLY BLANK LINES
	  JRST COMSP2		 ;IN FILE 1.
	MOVE F1,LNNEXT(F1)	;FOUND ONE => SKIP PAST IT.
	JRST COMSPL

COMSP2:	CAMN F2,(P)		;THEN TRY FOR BLANK LINES IN FILE 2
	 JRST COMSPX		;NO LINES IN FILE 2 => CAN'T WIN.
	HRRI FR,1
	TLNN FR,FLALL
	 CALL BLANKP
	  JRST COMSP3
	MOVE F2,LNNEXT(F2)
	JRST COMSPL

COMSP3:	CAMN F1,-1(P)		;IF BOTH FILES HAVE LINES,
	 JRST COMSPX
	CALL COMPCS		;SEE IF THEY ARE EQUAL WHEN SPACES & COMMENTS ARE IGNORED.
	 JRST COMSPF
;HERE WHEN WE CAN'T ELIMINATE ANY MORE LINES BY IGNORING SPACES & COMMENTS
COMSPX:	CAMN F1,-1(P)		;IF NO LINES LEFT FROM EITHER FILE, WE WIN
	 CAME F2,(P)
	  AOS -2(P)		;OTHERWISE, THE DIFFERENCES ARE ESSENTIAL.
	REST F2
	REST F1
	RET

;COME HERE IF TWO LINES MATCH WHEN WE IGNORE APPROPRIATE STUFF.
COMSPF:	MOVE F1,LNNEXT(F1)	;SKIP BOTH LINES.
	MOVE F2,LNNEXT(F2)
	JRST COMSPL

;SKIP IF THE LINE F1(FR) POINTS AT IS BLANK WHEN
;SPACES AND COMMENTS ARE IGNORED ACCORDING TO SWITCH SETTINGS.
BLANKP:	HRRZ W1,F1(FR)
	MOVE C,LNSIZE(W1)
	ADD W1,[440700,,LNDATA]
BLANK1:	ILDB T,W1
	SOJLE C,POPJ1	;WE WIN IF EXHAUST THE LINE AFTER JUST SPACES AND CRLFS.
	CAIE T,^M
	 CAIN T,^J
	  JRST BLANK1
	CAIE T,40
	 CAIN T,^I
	  TLNN FR,FLSPAC
	   CAIA
	    JRST BLANK1
	TLNE FR,FLCMNT	;IF /C, WE ALSO WIN IF WE FIND A SEMICOLON.
	 CAIE T,";
	  RET
	JRST POPJ1
3LOOP:
IFN ITS,.SUSET [.SWHO2,,[SIXBIT/SAME/]]

;THIS IS THE MAIN LOOP OF 3-WAY MERGING.

;COME HERE WHEN THE LAST LINES OF ALL 3 FILES MATCHED, TO TRY THE NEXT LINES OF ALL 3.
3SAME:	SKIPE F1,LNNEXT(F1)	;ADVANCE PAST THE LINE THAT MATCHED
	 JRST 3SAME1
	TRZ FR,-1		;IF NO MORE LINES IN CORE, FLUSH ALL
	SKIPE MRGOUT+0		;THE LINES WE PASSED BY,
	 CALL MOVEUP
	SETZM NLINE1		;(IN THE SIMPLE COMMON CASE, FLUSH THEM FAST)
	CALL RDLIN		;AND READ ANOTHER.
	 CAIA
	 JFCL
3SAME1:	SKIPE F2,LNNEXT(F2)	;SIMILAR FOR F2,
	 JRST 3SAME2
	SETZM NLINE2		;BUT SINCE MRGOUT+1 SHOULD BE ZERO, IT'S SIMPLE.
	HRRI FR,1
	CALL RDLIN
	 CAIA
	 JFCL
3SAME2:	SKIPE F3,LNNEXT(F3)	;FOR F3, JUST LIKE F2.
	 JRST 3SAME3
	SETZM NLINE3
	HRRI FR,3
	CALL RDLIN
	 CAIA
	 JFCL
3SAME3:	MOVE W1,EOFFL1		;UNLESS EITHER ALL 3 FILES ARE ENDING OR NONE,
	CAMN W1,EOFFL2		;IT'S A DIFFERENCE.
	 CAME W1,EOFFL3
	  JRST 3DIFF
	CALL COMPL		;COMPARE LINE FROM FILE 1 WITH THAT FROM FILE 2.
	 CAIA
	  JRST 3DIFF
	EXCH F2,F3
	CALL COMPL		;COMPARE FILE 1 WITH FILE 3.
	 CAIA
	  JRST [ EXCH F2,F3
		 JRST 3DIFF]
	EXCH F2,F3		;1 MATCHES 2 AND MATCHES 3 => ALL 3 STILL THE SAME.
	SKIPE EOFFL1
	 JRST FIN2
	JRST 3SAME
;COME HERE, DURING A 3-WAY MERGE, WHEN A DIFFERENCE IS SEEN.
;THAT IS, WHEN ALL 3 FILES CEASE TO BE IDENTICAL.
;F1, F2, F3 POINT AT THE FIRST NON-MATCHING LINES,
;OR ARE ZERO TO SAY THAT AN ENTIRE FILE HAS BEEN MATCHED OFF.
;COME HERE WHEN A DIFFERENCE IS SEEN. F1 AND F2 POINT TO THE 1ST PAIR OF NON-MATCHING
;LINES, OR ARE ZERO TO SAY THAT AN ENTIRE FILE HAS BEEN MATCHED OFF.
3DIFF:	HRRI FR,0
	CALL MOVEUP	;FLUSH ANY MATCHING LINES STILL IN CORE BEFORE THOSE TWO.
	HRRI FR,1
	CALL MOVEUP
	HRRI FR,2
	CALL MOVEUP
	SKIPE 0		;0 SHOULD ALWAYS HOLD 0 FOR NEXTLN'S SAKE.
	 ERRHLT
IFN ITS,.SUSET [.SWHO2,,[SIXBIT/DIFF/]]
	SETZM NCOMP1
	SKIPL EOFFL1
	 AOS NCOMP1
	SETZM NCOMP2
	SKIPL EOFFL2
	 AOS NCOMP2
	SETZM NCOMP3
	SKIPL EOFFL3
	 AOS NCOMP3
	MOVE W1,12MTBB	;CLEAR THE TABLE OF MATCHES BETWEEN FILES 1 AND 2.
	MOVEM W1,12MTBP
3DIFFR:	NEXTLN 1	;READ ANOTHER LINE FROM EACH FILE.
	SKIPL EOFFL1
	 AOS NCOMP1
	NEXTLN 2
	SKIPL EOFFL2
	 AOS NCOMP2
	NEXTLN 3
	SKIPL EOFFL3
	 AOS NCOMP3
	SKIPE EOFFL2
	 JRST 3DIFF2
	SKIPN CS,NCOMP1	;HOW MANY FILE 1 LINES SHOULD WE CONSIDER?
	 JRST 3DIFF2
	SKIPA F1,LBUFP1	;COMPARE ALL THE NON-MATCHING LINES OF FILE 1, 1 AT A TIME,
3DIFF0:	 MOVE F1,W1	;WITH THE NEW LINE FROM FILE 2.
	CALL COMPL
	 CALL MULTI	;MATCH => CHECK FOR MULTI-LINE MATCH, PUT IN 12MTAB IF FOUND.
	SKIPE W1,LNNEXT(F1)
	 SOJG CS,3DIFF0
;AFTER COMPARING ALL THE FILE 1 LINES WITH THE NEW FILE 2 LINE, OR IF THERE IS NO NEW
;FILE 2 LINE, COME HERE TO COMPARE THE NEW FILE 1 LINE WITH ALL THE FILE 2 LINES.
;F1 IS ALREADY POINTING AT THE NEW FILE 1 LINE ("NEW" MEANS THAT DIFFRD GOT IT.
;IT MIGHT HAVE BEEN IN CORE ALREADY DUE TO NEXTLN'S DONE INSIDE MULTI).
3DIFF2:	SKIPE EOFFL1	;BUT DON'T DO IT IF NO NEW FILE 1 LINE.
	 JRST 3DIFF3
	SKIPN CS,NCOMP2	;HOW MANY LINES ARE WE CONSIDERING YET FROM FILE 2?
	 JRST 3DIFF3
	SKIPA F2,LBUFP2	;(MAY NOT BE SAME AS NLINE2, IF MULTI READ SOME LINES.)
3DIFF1:	 MOVE F2,W1	;ELSE LOOP HERE OVER THE FILE 2 LINES.
	CALL COMPL
	 CALL MULTI	;IF MULTI-LINE MATCH FOUND, PUT IT IN 12MTAB.
	SKIPE W1,LNNEXT(F2)
	 SOJG CS,3DIFF1
;NOW WE KNOW ABOUT THE PLACES WHERE FILES 1 AND 2 MATCH.
;EACH SUCH PLACE (WITHIN THE RANGE BEING CONSIDERED) IS LISTED IN 12MTAB.
;WE NOW COMPARE EACH OF THOSE PLACES AGAINST WHAT WE HAVE OF FILE 3.
3DIFF3:	PUSH P,F1
	PUSH P,F2
	MOVE W1,12MTBB
3DIFF6:	CAMN W1,12MTBP
	 JRST 3DIFF4	;NO MATCH => READ ANOTHER PAIR OF LINES AND TRY MATCHING THEM.
	ILDB F2,W1
	PUSH P,W1
	ANDI F2,-1	;FIND THE FILE 2 LOCATION OF THE NEXT 1-2 MATCH.
	MOVE CS,NCOMP3
	SKIPA F1,LBUFP3
3DIFF5:	 MOVE F1,W1
	CALL COMPL	;COMPARE THAT AGAINST EACH POINT OF FILE 3.
	 CALL 3MULTI	;NOTE THAT WE ARE USING F1 TO HOLD THE FILE 3 POINTER.
	SKIPE W1,LNNEXT(F1)
	 SOJG CS,3DIFF5
	POP P,W1
	JRST 3DIFF6	

3DIFF4:	POP P,F2
	POP P,F1	;NO MATCH FOUND.
	SKIPE EOFFL1	;NORMALLY, READ ANOTHER LINE FROM EACH FILE.
	 SKIPL EOFFL2
	  JRST 3DIFFR
	SKIPL EOFFL3
	 JRST 3DIFFR
	JRST 3ALDIF	;BUT IF ALL ARE AT EOF, TAKE ALL REMAINING LINES OF ALL FILES AS DIFFS.

	; THIS IS A COLLECTION OF STUFF THAT WAS UNDEFINED AT THE
	; TIME CONVERSION TO TNX WAS DONE.  VALUES ARE FURNISHED HERE
	; JUST TO MINIMIZE ASSEMBLY BARFAGE, BUT SOMEDAY PRESUMABLY
	; SOMEONE WILL REPLACE WITH THE PROPER THINGS.
3ALDIF:
3MULTI:	RET		; NOP FOR NOW
.SCALAR 3WAY	; -1 IF DOING 3-WAY COMPARE
.SCALAR 12MTBP	; SOMETHING TO DO WITH 3WAY MERGE?
.SCALAR 12MTBB	; DITTO
;/M ROUTINE TO TEST IF MERGE IN EFFECT AND IF YES
;/M ACCPT COMMAND AND PASS TO MERGE OUTPUT FILE
;/M COMMANDS ARE ANY COMBINATION OF 1,2,I AND/OR T (WITH NO COMMAS)
;/M ALL OTHER CHARACTERS ARE ILLEGAL
;/M CALL:	CALL TRYMRG
;		  MERGER DONE RETURN
;		/M NOT IN EFFECT RETURN

TRYMRG:	TLNN FR,FLMERG		;/M  /M SWITCH IN EFFECT?
	 JRST POPJ1		;/M NO, SKIP RETURN
IFN ITS,.SUSET [.SWHO2,,[SIXBIT/MERGE/]]
	TLNE FR,FLISWT		;/I => ASSUME "I" AS AN ANSWER.
	 JRST MRGI1
	TLNE FR,FLFLAG		;/F => PUT OUT THE FILE 2 STUFF WITH FLAGS.
	 JRST MRGU1
	CALL GETMRG		;/M TYPE *,GET ALL OF MERGE COMMAND(CHECK SYNTAX)
LISTEN:	CALL MRGIN		;/M GET NEXT MERGE COMMAND INPUT CHAR
	CAIE C,"1		;/M DID HE TYPE 1?
	 CAIN C,"2		;/M DID HE TYPE 2?
	  JRST MRG5		;YES FOR ONE OF THEM!
	CAIN C,"I
	 JRST MRGI		;"I"=> PUT IN BOTH FILES' TEXTS AND IDENTIFYING MARKS.
	CAIE C,"T		;/M "T" TYPED?
	 JRST MRG4		;/M NO, CHECK FOR END OF COMMAND
MRG3B:	CALL TTILIN
MRG3A:	CALL TTICHR		;GET TTY INPUT CHAR.
	CAIE C,^C		;/M EOF OR
	 CAIN C,ALTM		;/M ALT-MODE?
	  JRST LISTEN		;/M YES, END OF INSERT FROM TTY
	CALL MRGO		;/M NO, OUTPUT CHAR TO MERGE FILE
	CAIE C,^M		;CR -> SPECIAL.
	 JRST MRG3A		;ELSE GET MORE
	MOVEI C,^J		;PUT IN ^J AFTER ^M.
	CALL MRGO
	JRST MRG3B		;GET NEXT TTY LINE.

MRG4:	CAIE C,0		;/M MUST BE NULL(END OF COMMAND)
	 ERRHLT			;/M NO SOME THING IS VERY WRONG
	HRRI FR,0		;/M FLUSH DIFFERENCES IN FILE ONE IF NOT ALREADY
	SETZM MRGOUT(FR)	;/M BUT DO NOT OUTPUT ON MERGE FILE
	CALL MOVEUP		;/M NO, OUTPUT DIFFERENCES AND FLUSH
	HRRI FR,1		;/M FLUSH DIFFERENCES IN FILE TWO IF NOT ALREADY
	SETZM MRGOUT(FR)	;BUT DO NOT OUTPUT ON MERGE FILE
	CALL MOVEUP		;/M NO, OUTPUT DIFFERENCES AND FLUSH
	SETOM MRGOUT+0
	RET			;/M RETURN, LEAVING MATCH LINES STILL IN BUFFER

MRG5:	HRRI FR,-"1(C)
	SETOM MRGOUT(FR)	;/M YES, SET FLAG SO MOVEUP WILL OUTPUT
	CALL MOVEUP		;/M MOVE BUFFER UP OVER DIFFERENCES USER WANTS
	JRST LISTEN		;/M GO GET ANOTHER CHARACTER
;/F => WHEN DIFFERENCES ARE FOUND, OUTPUT THE LINES FROM FILE 2
;WITH A "|" AT THE FRONT OF EACH ONE.
MRGU1:	SETOM MRGOUT+1
	HRRI FR,1
	SETOM MRGUFL		;TELL MOVEUP TO INSERT "|"'S
	PUSH P,F1(FR)
	CALL MOVEUP		;OUTPUT THE STUFF FROM FILE 2
	REST W1
	MOVEI W2,[ASCIZ /^^^^/]	;THEN OUTPUT "^^^^" IN FRONT OF NEXT LINE
	CAMN W1,F1(FR)		;IF THERE WERE NO LINES FROM FILE 2 (A DELETION).
	 CALL MRGPNT
	SETZB C,MRGUFL
	JRST MRG4		;THROW AWAY STUFF FROM FILE 1 AND RETURN.

;"I" MERGE COMMAND - PUT IN THE MERGE FILE THE FOLLOWING:
;*** MERGE LOSSAGE ***
;*** FILE FOOBAR 1001 HAS:
;<TEXT FROM FILE 1>
;*** FILE FOOBAR 1002 HAS:
;<TEXT FROM FILE 2>
;*** END OF MERGE LOSSAGE ***

MRGI:	SAVE [LISTEN]
MRGI1:	MOVEI W2,[ASCIZ /*** MERGE LOSSAGE ***
*** FILE /]
	CALL MRGPNT
	MOVE W2,RCHSTP		;-> NAMES OF FILE 1.
	CALL MRGPNT
	MOVEI W2,[ASCIZ / HAS:
/]
	CALL MRGPNT
	SETOM MRGOUT		;OUTPUT THE TEXT OF FILE 1
	HRRI FR,0
	CALL MOVEUP
	MOVEI W2,[ASCIZ /*** FILE /]
	CALL MRGPNT
	MOVE W2,RCHSTP+1	;-> NAMES OF FILE 2.
	CALL MRGPNT
	MOVEI W2,[ASCIZ / HAS:
/]
	CALL MRGPNT
	SETOM MRGOUT+1		;OUTPUT TEXT FROM FILE 2.
	HRRI FR,1
	CALL MOVEUP
	SETZM MRGOUT+1		;CLEAR THIS OR WE'D GET 2 COPIES OF FURTHER UNCHANGED TEXT!
	MOVEI W2,[ASCIZ /*** END OF MERGE LOSSAGE ***
/]
	JRST MRGPNT

;PRINT ASCIZ STRING <- W2 ON THE MERGE FILE.
MRGPNT:	HRLI W2,440700
MRGPN1:	ILDB C,W2
	JUMPE C,CPOPJ
	CALL MRGO
	JRST MRGPN1

;OUTPUT STRING <- W2 WITH # CHARS IN C.
MRGCNT:	SAVE W1
	SKIPN W1,C
	 JRST POPW1J
MRGCN1:	ILDB C,W2
	CALL MRGO
	SOJG W1,MRGCN1
	JRST POPW1J

;HERE TO OUTPUT ONE CHARACTER TO CHMRG VIA BUFFER.
MRGO:	IDPB C,MRGBP
	SOSLE MRGCT
	 RET

;EMPTY OUT OUR CHMRG BUFFER.
MRGFRC:	SAVE W1
	SAVE W2
	MOVE W1,[440700,,MRGBF]
	MOVEM W1,MRGBP
	MOVEI W2,MRGBSZ
	SUB W2,MRGCT		;# CHARS FILLED IN IT.
	ADDM W2,MRGCT		;MARK IT EMPTY (AFTER WE WRITE DATA).
	JUMPE W2,MRGFR1
	M.SOUT CHMRG,W1,W2	; OUTPUT STRING
MRGFR1:	REST W2
POPW1J:	REST W1
	RET
;/M ROUTINE TO GET INPUT FOR MERGE COMMAND
;/M STORES ENTIRE COMMAND IN SPECIAL BUFFER
;/M IN CASE USER TYPES T COMMAND AS ONE OF COMMANDS
;/M WHICH WILL SLAO REQUIRE TTY INPUT
;/M CHECK SYSTAX, DO NOT RTURN UNTIL GOOD COMMAND LINE TYPED IN

GTMRG0:	HLRZ C,(P)
	MOVEM W1,(C)
GETMRG:	CALL TTILNA		;READ TTY LINE, PROMPTING WITH A "*".
	MOVE W1,[440700,,MRGCOM]	;/M SET UP BYTE POINTER TO MERGE
				;/M COMMAND BUFFER
GTMRG1:	MOVEI C,0		;/M IN CASE TOO LONG COMMAND
	CAME W1,[350700,,MRGCOM+MRGLEN-1]
	 CALL TTICHU
	CAIGE C,40		;/M ALTM,LF?
	 MOVEI C,0		;/M YES, FLAG END OF MERGE COMAND WITH NULL
	IDPB C,W1		;/M STORE CHAR
	CAIE C,"1		;/M IS IT "1"?
	 CAIN C,"2		;/M OR "2"?
	  JRST GTMRG1		;/M YES, GET ANOTHER
	CAIE C,"I
	 CAIN C,"T		;/M NO, IS IT "T"?
	  JRST GTMRG1		;/M YES, GET ANOTHER
	CAIN C,"L
	 JRST GTMRGL
	CAIE C,"C		;/M C?
	 JRST GTMRG3		;/M NO
	SKIPA W1,[COLMAX]
GTMRGL:	 MOVEI W1,LINMAX
	HRLM W1,(P)
	MOVEI W1,0
GTMRG2:	CALL TTICHR		;/M GE CHAR
	CAIGE C,40		;/M END OFLINE CHAR?
	 JRST GTMRG0		;/M YES STORE NEW MAX.
	CAIL C,"0		;/M NO, A DECIMAL  DIGIT?
	 CAILE C,"9		;/M
	  JRST GTMRG4		;/M NO, PRINT ERROR
	IMULI W1,12		;/M YES CONVERT TO BINARY
	ADDI W1,-"0(C)		;/M ADD IN THIS DIGIT
	JRST GTMRG2		;/M GO GET NEXT DIGIT

GTMRG3:	MOVE W1,[440700,,MRGCOM]	;/M ASSUME IT IS END OF LINE
	MOVEM W1,MRGBYT		;/M AND STORE BYTE POINTER TO SCANNED STRING
	JUMPE C,CPOPJ		;/M IS IT?
GTMRG4:	MOVE W1,[440700,,[ASCIZ "?ONLY 1, 2, I, AND/OR T ARE LEGAL IN MERGE COMMANDS
OR C### TO SET MAX. COL. OR L### TO SET MAX. LINES TYPED.
"]]
	CALL PRINT		;/M PRINT ERROR
	JRST GETMRG		;/M AND ASK FOR COMMAND OVER AGAIN

;/M ROUTINE TO GET NEXT CHAR FROM MERGE COMMAND BUFFER
;/M CALL:	CALL MRGIN
;/M		RETURN	WITH CHAR IN C

MRGIN:	ILDB C,MRGBYT		;/M GET NEXT CHAR
	RET
;MOVEUP FLUSHES ALL THE LINES OF THE FILE SPECIFIED BY RH(FR)
;THAT ARE BEFORE THE LINE POINTED BY F1 OR F2 OR F3.
;IF THERE ARE ANY LINES AFTER F1 OR F2 OR F3, THEY HAVE TO BE BLT'ED DOWN
;TO THE BEGINNING OF THE FILE'S SEGMENT.  IF THERE ARE NONE,
;ONLY POINTER RELOCATION TAKES PLACE.
;F1 OR F2 OR F3 CONTINUES TO POINT AT THE SAME LINE, OR REMAINS 0.
;IF MRGOUT(FR) IS NONZERO, THE FLUSHED LINES ARE OUTPUT TO THE
;MERGE FILE.

MOVEUP:	SKIPN FSBIN
	 SKIPE FVBIN
	  RET			; Ignore if doing binary compare.
	SKIPE MRGOUT(FR)	;SKIP IF SHOULD OUTPUT TO MERGE FILE,
	 CALL MOVEU1		;DO SO.
	SKIPE W1,F1(FR)		;GET ADDR OF 1ST LINE NOT TO FLUSH.
	 JRST MOVEU5
	SETZM NLINES(FR)	;FLUSHING ALL LINES => JUST SAY THERE ARE NONE.
	RET

MOVEU5:	MOVEI T,1		;T COUNTS THE NUMBER OF LINES LEFT.
	MOVN C,W1		;WE MUST BLT FROM C(W1) TO C(LBUFP(FR))
	ADD C,LBUFP(FR)		;HOW FAR IS THAT?
MOVEU3:	MOVE W2,W1		;W2 REMEMBERS THE LAST LINE'S ADDR
	CAMN W1,TEMPF1(FR)	;RELOCATE TEMPF1 IF IT POINTS AT THIS LINE.
	 ADDM C,TEMPF1(FR)
	SKIPN W1,LNNEXT(W1)	;FIND THE NEXT LINE WHERE IT NOW IS
	 JRST MOVEU4
	ADDM C,LNNEXT(W2)	;RELOCATE POINTER -> WHERE IT WILL BE BLT'ED TO.
	AOJA T,MOVEU3		;ANOTHER LINE => COUNT IT.

MOVEU4:	MOVEM T,NLINES(FR)
	HRLZ W1,F1(FR)		;LH(W1) GETS CURRENT ADDRESS OF 1ST LINE TO KEEP
	HRR W1,LBUFP(FR)	;RH GETS NEW ADDR
	MOVE T,LNSIZE(W2)	;FIND END OF LAST LINE
	ADDI T,5
	IDIVI T,5		;FIRST FIND LENGTH IN WORDS
	ADDI W2,LNDATA-1(T)	;ADD ADDR OF START OF LINE
	ADD W2,C		;FIND WHERE THAT END IS BEING RELOCATED TO.
	BLT W1,(W2)		;COPY THE LINES THAT ARE LEFT TO THEIR NEW HOMES.
	MOVE W1,LBUFP(FR)
	MOVEM W1,F1(FR)		;NOW RELOCATE F1(FR).
	RET

;OUTPUT THE LINES UP THE FILE IN FR THAT ARE BEFORE F1 OR F2 OR F3 TO THE MERGE FILE.
MOVEU1:	MOVE W1,LBUFP(FR)	;GET ADDR OF 1ST LINE TO BE FLUSHED.
	SKIPN NLINES(FR)
	 SETZ W1,
MOVEU2:	CAMN W1,F1(FR)		;REACHED 1ST LINE NOT TO BE FLUSHED?
	 RET			;NO, OUTPUT LINE W1 POINTS AT.
	TLNE FR,FLFLAG
	 SKIPGE LPHONY		;IF THIS LINE IS PHONY (NOT FIRST AFTER A CRLF)
	  JRST MOVEU6		 ;OMIT ANY /F HACKERY.
	SKIPLE LPHONY		;IF FOLLOWS A STRAY CR, JUST PUT IN A TAB.
	 JRST MOVEU7
	MOVEI C,"|
	SKIPE MRGUFL		;IF OUTPUTTING DIFFERENCES IN /F MODE, PREFIX WITH "|".
	 CALL MRGO
	TLNN FR,FLFLAG		;IN /F MODE, PUT A TAB BEFORE EVERY LINE
	 JRST MOVEU6

MOVEU7:	MOVEI C,^I		;SO "|"'S AND "^"'S CAN STAND OUT.
	CALL MRGO
MOVEU6:	MOVEI W2,LNDATA(W1)
	HRLI W2,440700		;GET ADDR OF 1ST DATA WORD
	MOVE C,LNSIZE(W1)	;AND # OF CHARACTERS.
	SETZM LPHONY		;SET LPHONY FOR NEXT LINE UNLESS THIS ONE ENDS IN A CRLF.
	CAIGE C,2
	 SETOM LPHONY
	CALL MRGCNT		;TRANSFER THE CHARACTERS.
	SOS W2
	REPEAT 3,IBP W2		;DECREMENT W2 TWICE.
	ILDB C,W2
	CAIE C,^M
	 SETOM LPHONY		;CHECK FOR THE TERMINAL CRLF.
	ILDB C,W2
	CAIE C,^J
	 SETOM LPHONY
	CAIN C,^M
	 MOVNS LPHONY		;LEAVE 1 IN LPHONY IF LINE ENDS IN JUST CR.
	MOVE W1,LNNEXT(W1)	;GO TRY THE NEXT LINE.
	JRST MOVEU2
;SKIP UNLESS THE TWO CURRENT LINES ARE EQUAL.  IGNORES CASE CHANGES AND
;SPACING CHANGES IF SPECIFIED, BUT NEVER IGNORES COMMENTS.
;MUSTN'T CLOBBER CS.
COMPL:	MOVE C,LNSIZE(F1)	;FIRST TEST FOR EXACT MATCH.
	CAME C,LNSIZE(F2)
	 JRST COMPUL		;LINE LENGTHS DIFFER => NO EXACT MATCH,
	MOVEI W1,5(C)		;ELSE COMPARE THE LINES WORD-BY-WORD.
	IDIVI W1,5
	MOVNS W1		;-<# WDS OF DATA IN LINE>
	HRLZS W1
	HRRI W1,LNDATA(F1)	;AOBJN POINTER TO DATAT IN FILE 1 LINE.
	MOVEI W2,LNDATA(F2)	;AND POINTER TO DATA OF FILE 2 LINE.
	SUB W2,W1
	HRRM W2,COMPLX
COMPL1:	MOVE C,(W1)		;COMPARE WORD BY WORD, IGNORING LOW BITS.
COMPLX:	XOR C,(W1)		;ADDR FIELD MAKES E.A. POINT TO SECOND FILE'S LINE.
	TDNE C,[-2]
	 JRST COMPUL		;JUMP IF NO EXACT MATCH.
	AOBJN W1,COMPL1
	RET

COMPUL:	TLNN FR,FLCASE\FLSPAC	;NO EXACT MATCH.  CAN WE TRY IGNORING STUFF?
	 JRST POPJ1		;NO, SO MUST RETURN "NO MATCH".
;IGNORING CASE OR SPACING => WE GET A SECOND CHANCE.
	MOVEI W1,LNDATA(F1)
	MOVEI W2,LNDATA(F2)
	HRLI W1,440700
	HRLI W2,440700
COMPU1:	ILDB T,W1		;GET A CHARACTER FROM LINE FROM FIRST FILE
	ILDB TT,W2		;AND ONE FROM SECOND FILE
	CAME T,TT		;THEY'RE EXACTLY EQUAL => KEEP LOOKING
	 JRST COMPU2
	JUMPN T,COMPU1		;BUT DON'T LOOK PAST ENDS OF THE LINES.
	POPJ P,			;REACH ENDS OF LINES => LINES MATCH.

COMPU2:	TLNN FR,FLSPAC
	 JRST COMPU4
	CAIE T,40		;IF SUPPOSED TO IGNORE CHANGES IN SPACING, DO SO
	 CAIN T,^I		;BY SKIPPING ALL SPACES & TABS IN BOTH FILES.
	  JRST [ILDB T,W1
		JRST .-2]
	CAIE TT,40
	 CAIN TT,^I
	  JRST [ILDB TT,W2
		JRST .-2]
COMPU4:	TLNN FR,FLCASE
	 JRST COMPU3
	CAIL T,"A+40		;IF SUPPOSED TO IGNORE CHANGES IN CASE, CONVERT TO U.C.
	 CAILE T,"Z+40
	  CAIA
	   SUBI T,40
	CAIL TT,"A+40
	 CAILE TT,"Z+40
	  CAIA
	   SUBI TT,40
COMPU3:	CAMN T,TT		;DO THEY MATCH NOW?
	 JRST COMPU1
	JRST POPJ1		;NO => LINES DON'T MATCH.
;SKIP UNLESS THE TWO CURRENT LINES ARE THE SAME WHEN APPROPRIATE
;STUFF IS IGNORED (SPACES AND COMMENTS, OR ALPHABETIC CASE,
; ACCORDING TO SWITCHES).
COMPCS:	MOVEI W1,LNDATA(F1)
	MOVEI W2,LNDATA(F2)
	HRLI W1,440700
	HRLI W2,440700
COMPL3:	ILDB T,W1		;GET A CHARACTER FROM LINE FROM FIRST FILE
COMPL6:	ILDB TT,W2		;AND ONE FROM SECOND FILE
	CAME TT,T		;THIS IS THE BIG TEST--ARE THEY EQUAL
	 JRST COMPL4		;NO
COMPL7:	CAIN T,";		;YES, COMMENT?
	 TLNN FR,FLCMNT		;YES, SUPPRESS COMMENTS?
	  JUMPN T,COMPL3	;NO,NO. TEST FOR END OF LINE
	RET			;LINES MATCH, RETURN

COMPL4:	TLNN FR,FLSPAC		;CHARS DIFFER: MAYBE TRY IGNORING SPACING
	 JRST COMPL8
	CAIE TT,40		;SPACE IN FILE 2, OR TAB?
	 CAIN TT,TAB
	  JRST COMPL6		;IF SO, SKIP IT.
COMPL5:	CAIE T,40		;SPACE IN FILE 1?
	 CAIN T,TAB		;OR TAB?
	  JRST [ILDB T,W1	;SKIP TO FIRST NON-SPACE NON-TAB.
		JRST COMPL5]
	CAMN T,TT		;ARE THE CHARACTERS NOW THE SAME?
	 JRST COMPL7		;YES, TEST FOR END OF LINES
COMPL8:	TLNN FR,FLCASE		;SPACES DIDN'T HELP - ARE WE IGNORING CASE?
	 JRST COMPL2
	CAIL T,"A+40		;CHARS DON'T MATCH => WE STILL HAVE A CHANCE
	 CAILE T,"Z+40		;IF THEY'RE BOTH LETTERS;  CONVERT BOTH TO UPPER CASE.
	  CAIA
	   SUBI T,40
	CAIL TT,"A+40
	 CAILE TT,"Z+40
	  CAIA
	   SUBI TT,40
	CAMN T,TT		;IF THIS HELPED, KEEP GOING
	 JRST COMPL3		;NO USE CHECKING FOR EOL - THESE MUST BE BOTH LETTERS.	
;LAST CHANCE - MAYBE ONE FILE HAS A COMMENT AND THE OTHER IS AT END OF LINE.
COMPL2:	CAIE T,";		;COMMENT IN FILE 1?
	 CAIN TT,";		;OR IN FILE 2?
	  TLNN FR,FLCMNT	;AND ARE COMMENTS BEING IGNORED?
	   JRST POPJ1		;NO, FILES DON'T MATCH, SKIP RETURN
	JUMPE T,CPOPJ		;YES, OTHER CHAR MUST BE NULL OR ELSE ONE
	JUMPE TT,CPOPJ		;  LINE IS LONGER THAN OTHER AND FILES DIFFER
POPJ1:	AOS (P)
APOPJ:
CPOPJ:	RET
;WHEN WE GET TO THIS POINT WE HAVE FOUND 
;THE EXTENT OF THE DIFFERENCES AND WE ARE READY TO PRINT
;THESE DIFFERENCES OUT. F1 AND F2 POINT AT THE TWO MATCHING LINES
;THAT END THE RUN OF DIFFERENCES.

PNTBTH:	AOS ERRCNT		;INCREMENT # OF RUNS OF DIFFERENCES.
	TLNE FR,FLISWT+FLFLAG
	 RET			;DON'T TYPE ON TTY IF /I OR /F.
IFN ITS,.SUSET [.SWHO2,,[SIXBIT/PRINT/]]
	MOVEM P,FLUSHP		;SUPPLY P FOR --MORE--FLUSHED TO POPJ FROM.
	TRZ FR,-1		;OUTPUT FILE 1
	CALL PNTTXT		;PRINT FILE 1 DIFFERENCES
	HRRI FR,1		;THEN PRINT FILE 2 DIFFERENCES
	CALL PNTTXT
	SETZM FLUSHP
	RET

;OUTPUT THE LINES OF FILE (FR) BEFORE F1(FR), WITH A HEADER LINE.
;IF FLENDL=1, ALSO PRINTS THE LINE F1(FR) POINTS AT, IF ANY.
PNTTXT:	CALL PNTHDL		;FIRST, THE HEADER LINE.
	SKIPN NLINES(FR)
	 RET			;NO LINES => THAT'S ALL.
	MOVE W1,LBUFP(FR)
	SETZ W3,
	SKIPE CS,F1(FR)		;CS GETS LINE TO STOP AT.
	 TLNN FR,FLENDL
	  CAIA
	   MOVE CS,LNNEXT(CS)
PNTTX1:	CAME W1,CS		;REACHED 1ST LINE NOT TO OUTPUT => DONE.
	 CAML W3,LINMAX		;PRINTED MAX # OF LINES => STOP.
	  RET
	TLNN FR,FLFNUM		;IF USER WANTS FILE # ON EVERY LINE,
	 JRST PNTTX2
	SAVE W1
	MOVEI W1,FNUMBR(FR)	;PRINT IT FOR HIM.
	CALL PRINT
	REST W1
PNTTX2:	MOVEI W2,LNDATA(W1)
	HRLI W2,440700
	MOVE C,LNSIZE(W1)
	CAML C,COLMAX		;IN /M MODE, LIMIT CHARS PRINTED TO COLMAX.
	 MOVE C,COLMAX
	TLNN FR,FLMERG
	 MOVE C,LNSIZE(W1)
	CALL PNTCNT		;OUTPUT THE TEXT OF THE LINE.
	TLNN FR,FLALL		;IN /B MODE, THE CRLF IF ANY IS IN THE LINE.
	 CALL PCRLF		;OTHERWISE, MUST SUPPLY IT.
	MOVE W1,LNNEXT(W1)	;MOVE TO NEXT LINE.
	AOJA W3,PNTTX1		;COUNT # LINES OUTPUT SO FAR.

FNUMBR:	ASCIZ /1)	/	;FILE NUMBER OF FILE, FOR PRINTING.
	ASCIZ /2)	/
IFN .-FNUMBR-2,.ERR STRING TOO LONG


;OUTPUT A CRLF TO THE DIFFERENCE FILE.
PCRLF:	MOVE W2,[440700,,[.BYTE 7 ? ^M ? ^J]]
	MOVEI C,2
PNTCNT:	M.SOUT CHOUT,W2,C
	RET
;OUTPUT A HEADER LINE TO THE DIFFERENCE FILE, FOR INPUT FILE (FR).
PNTHDL:	MOVE W2,[440700,,[ASCIZ/**** FILE /]]
	MOVEI C,10.
	CALL PNTCNT
	MOVE W1,RCHSTP(FR)
	CALL PRINT		;PRINT THE ASCIZ STRING CONTAINING THE FILE'S NAMES.
	MOVE W2,[440700,,[ASCIZ /, /]]
	MOVEI C,2
	CALL PNTCNT
	MOVE W1,LBUFP(FR)	;GET THE PAGE # OF THE FIRST LINE FROM THE FILE.
	SKIPN NLINES(FR)
	 SKIPA T,PAGNUM(FR)	;OR THE .IOT'ING PAGE # IF THERE AR NONE.
	  MOVE T,LNPGNM(W1)
	CALL PNTDEC
	MOUTI CHOUT,"-
	SKIPN NLINES(FR)	;THEN THE LINE NUMBER
	 SKIPA T,LINNUM(FR)
	  MOVE T,LNLNNM(W1)
	CALL PNTDEC
	MOVEI W1,[ASCIZ/ (/]	;AND, IN PARENS, THE CHARACTER NUMBER.
	CALL PRINT
	MOVE W1,LBUFP(FR)
	SKIPN NLINES(FR)
	 SKIPA T,CHRNUM(FR)
	  MOVE T,LNCHNM(W1)
	CALL PNTDEC
	MOUTI CHOUT,51		; RIGHT PAREN (SCREWS MACRO)
	TLNN FR,FLLABL\FLXLBL
	 JRST PCRLF
	MOVE W1,LBUFP(FR)	;IF THE LAST LABEL IS KNOWN, PRINT IT TOO.
	SKIPN NLINES(FR)
	 JRST [	MOVEI T,(FR)
		IMULI T,LNLBLN
		ADDI T,LLABEL
		JRST PNTHD1]
	MOVEI T,LNLLBL(W1)
PNTHD1:	SKIPN (T)
	 JRST PCRLF
	MOVEI W1,[ASCIZ / AFTER /]
	SAVE T
	CALL PRINT
	REST W1
	TLNE FR,FLXLBL
	 MOUTI CHOUT,""
	SAVE LNLBLN(W1)
	SETZM LNLBLN(W1)	;SUPPLY A ZERO TO END THE ASCIZ.
	CALL PRINT
	REST LNLBLN(W1)
	TLNE FR,FLXLBL
	 MOUTI CHOUT,""
	JRST PCRLF

; PNTHWD - Output number in T in halfword format.

PNTHWD:	PUSH P,T
	HLRZS T
	CALL PNTOCT
	MOVEI C,2
	MOVE W2,[440700,,[ASCIZ /,,/]]
	CALL PNTCNT
	POP P,T
	JRST PNTOCT

; Print number in T in octal to difference file
; Use RH only, pad to 6 positions.
PNTOCT:	MOVE W2,[440700,,PNTDBF]
	PUSH P,T
	MOVE TT,[220300,,(P)]
	MOVSI C,-6
PNTOC2:	ILDB T,TT
	JUMPN T,PNTOC3
	MOVEI T,40
	IDPB T,W2		; PAD OUT WITH SPACES
	AOBJN C,PNTOC2
	MOVEI T,"0
	DPB T,W2
	JRST PNTOC5
PNTOC4:	ILDB T,TT
PNTOC3:	ADDI T,"0
	IDPB T,W2
	AOBJN C,PNTOC4
PNTOC5:	MOVEI C,6
	MOVE W2,[440700,,PNTDBF]
	POP P,T
	JRST PNTCNT


;PRINT NUMBER IN T IN DECIMAL TO DIFFERENCE FILE
PNTDEC:	MOVE W2,[440700,,PNTDBF]
	SETZ C,
	CALL PNTDE1
	MOVE W2,[440700,,PNTDBF]
	JRST PNTCNT

PNTDE1:	IDIVI T,10.
	HRLM TT,(P)
	SKIPE T
	 CALL PNTDE1
	HLRZ TT,(P)
	ADDI TT,"0
	IDPB TT,W2
	AOJA C,CPOPJ

;RH(W1) IS ADDR OF ASCIZ STRING; PRINT IT ON DIFFERENCE FILE.
PRINT:	MOVEI W2,(W1)
	HRLI W2,440700
	SETZ C,		;FIRST COUNT CHARS IN THE STRING,
	ILDB T,W2
	SKIPE T
	 AOJA C,.-2
	MOVEI W2,(W1)	;THEN OUTPUT THE STRING.
	HRLI W2,440700
	JRST PNTCNT
;ASSUMING THAT F1(FR) POINTS TO THE LAST LINE IN FILE (FR),
;READ ANOTHER LINE AND MAKE F1(FR) POINT AT IT.
;ALSO OK IS IF WE HAVE NO LINES FROM THAT FILE AND F1(FR) IS 0.
;SKIPS TWICE IF SUCCESSFUL. CAN FAIL AND NOT SKIP IF CAN'T GET A LINE
;BECAUSE OF EOF; WILL RETURN WITH F1(FR) UNCHANGED AND EOFFL1(FR) NONZERO.
;WE DON'T EXPLICITLY GET CORE - THE MPV INT HANDER DOES THAT.
;THE MPV INT HANDLER CHECKS THE PC - ANY INSN THAT CAN LEGITIMATELY GET AN MPV
;SHOULD HAVE A LABEL SUCH AS "MPVOK1" AND BE MADE KNOWN TO THE INT HANDLER.

RDLIN:	TDNE FR,EOFTBL(FR)	;GIVE UP IF AT EOF IN FILE.
	 JRST [	SETOM EOFFL1(FR)
		RET]
	MOVE W1,LBUFP(FR)	;IF NO LINES IN CORE, NEXT LINE GOES AT START OF SEG.
	SKIPN NLINES(FR)
	 JRST RDLIN0
	SKIPN W1,F1(FR)		;ELSE, GET POINTER TO CURRENT LINE
	 ERRHLT
	MOVE T,LNSIZE(W1)	;FIND WORD AFTER THE END OF IT
	ADDI T,5
	IDIVI T,5
	ADDI W1,LNDATA(T)	;THAT WILL BE THE ADDRESS OF THE NEW LINE.
RDLIN0:	SETZ W3,			;COUNT # OF CHARS WE SKIP IN T.
	MOVE CS,@GCHARP(FR)	;SWAP THE FILE B.P. INTO AN AC FOR SPEED.
RDLIN1:	ILDB C,CS
	CAIG C,^M
	 XCT RDLT1(C)		;LOOP TILL 1ST CHAR OF NON-NULL LINE SEEN.
RDLIN4:	ADDB W3,CHRNUM(FR)	;INITIALIZE THE LINE'S DATA,
MPVOK0:	MOVEM W3,LNCHNM(W1)	;STORING THE LAST WORD FIRST TO MAKE SURE CORE EXISTS.
IFN LNDATA-LNCHNM-1,.ERR
	TLNN FR,FLLABL\FLXLBL	;SAVE TIME IF LABEL FEATURE NOT IN USE.
	 JRST RDLIN5
	MOVEI W3,LNLLBL(W1)
	DPB FR,[240100,,W3]	;PUT 4*RH(FR) IN LH(W3)
	ADD W3,[LLABEL,,]	.SEE LNLBLN ;4 WORDS OF LABEL STRING.
	BLT W3,LNLLB3(W1)
RDLIN5:	MOVE W2,PAGNUM(FR)
	MOVEM W2,LNPGNM(W1)
	MOVE W2,LINNUM(FR)
	MOVEM W2,LNLNNM(W1)
	SETZM LNNEXT(W1)
	MOVEI W2,LNDATA(W1)
	HRLI W2,440700		;THEN MAKE W2 A B.P. TO IDPB THE DATA AREA,
	MOVE RDLIN7,[RDLIN6,,BP]
	BLT RDLIN7,RDLIN7
	TDZ W3,W3		;AND COUNT CHARS STORED IN LINE IN W3.
	JRST MPVOK1

RDLIN6:		OFFSET BP-.
RDLIN2::	ILDB C,CS
MPVOK1::	XCT RDLT2(C)	;USUALLY IDPB C,W2, BUT MAY EXIT TO RDLIN3.
RDLIN7::	AOJA W3,RDLIN2
		OFFSET 0

RDLIN3:	AOS NLINES(FR)		;WHEN WE GET HERE, THE LINE REALLY EXISTS,
	SKIPE F1(FR)		;SO PUT IT IN THE CHAIN
	 MOVEM W1,@F1(FR)
IFN LNNEXT,.ERR
	MOVEM W1,F1(FR)		;AND POINT AT IT.
	MOVEM W3,LNSIZE(W1)	;REMEMBER # CHARS IN THIS LINE.
	ADDM W3,CHRNUM(FR)	;UPDATE CHAR POSITION IN FILE
	MOVEM CS,@GCHARP(FR)	;STORE BACK THE FILE'S BUFFER B.P.
	SETZB T,TT
MPVOK6:	IDPB T,W2		;STORE A TRAILING ZERO, THEN
	LDB T,[360600,,W2]	;ZERO OUT REST OF LAST WORD.
	DPB T,[301400,,W2]
	DPB TT,W2
	TLNE FR,FLXLBL		;IF ANY UNINDENTED NON-COMMENT LINE IS A LABEL
	 CALL LABEL		;GO SET UP LLABEL WITH THIS LINE'S LABEL IF IT HAS ONE.
	AOS (P)
	JRST POPJ1
;DISPATCH TABLE FOR FINDING A NON-NULL LINE.
RDLT1:	JFCL
	JFCL
	JFCL
	JRST RDLINC	;^C
REPEAT 6,JFCL
	JRST RDLINJ	;^J
	JFCL
	JRST RDLINL	;^L
	JRST RDLINM	;^M
IFN .-RDLT1-^M-1,.ERR WRONG LENGTH TABLE

;DISPATCH TABLE FOR ADDING MORE CHARS TO A LINE.
RDLT2:	REPEAT 200,IDPB C,W2
LOC RDLT2+^C ? JRST RDLILC
LOC RDLT2+^J ? JRST RDLILJ
LOC RDLT2+^L ? JRST RDLILL
LOC RDLT2+^M ? JRST RDLILM
LOC RDLT2+": ? JRST RDLCLN
LOC RDLT2+200

;^J, ^L OR ^M WHEN LOOKING FOR START OF LINE:
;UPDATE PAGE OR LINE NUMBER, AND IGNORE CHAR UNLESS /B.
RDLINL:	TLNE FR,FLALL
	 JRST RDLIN4
	SETZM LINNUM(FR)
	AOS PAGNUM(FR)
	AOS LINNUM(FR)
IFN ITS,[
	HRLZ T,PAGNUM+0
	HRR T,PAGNUM+1
	.SUSET [.SWHO3,,T]
]
	AOJA W3,RDLIN1

RDLINJ:	TLNE FR,FLALL
	 JRST RDLIN4
	AOS LINNUM(FR)
	AOJA W3,RDLIN1

RDLINM:	TLNN FR,FLALL
	 AOJA W3,RDLIN1	;NO /B; SKIP THE CHAR, BUT COUNT IT IN # THAT WERE SKIPPED.
	JRST RDLIN4	;/B, ANY CHAR STARTS A LINE.

;^J, ^L OR ^M WHEN ADDING TO A NON-NULL LINE:
;UPDATE PAGE OR LINE NUM, AND END THE LINE, STORING CHAR IFF /B.
RDLILL:	SETZM LINNUM(FR)
	AOS PAGNUM(FR)
IFN ITS,[
	HRLZ T,PAGNUM+0
	HRR T,PAGNUM+1
	.SUSET [.SWHO3,,T]
]
RDLILJ:	AOS LINNUM(FR)
	TLNN FR,FLALL
	 JRST RDLIL1
MPVOK2:	IDPB C,W2
	AOJA W3,RDLIN3

RDLIL1:	AOS CHRNUM(FR)	;NOT /B: MUST UPDATE # CHARS FROM FILE SINCE RDLIN3 WON'T.
	JRST RDLIN3

RDLILM:	TLNN FR,FLALL	;^M INSIDE A LINE.
	 JRST RDLIL1
MPVOK3:	IDPB C,W2	;IN /B MODE, STORE IT AND LOOK FOR FOLLOWING ^J.
RDLIL2:	ILDB C,CS
	CAIN C,^J
	 AOJA W3,RDLILJ	;FOUND => STORE IT TOO.
	CAMN CS,GCHARE(FR)	;DON'T LOSE BECAUSE OF WRAPAROUND IN BUFFER.
	 JRST [	CALL RELOAD
		JRST RDLIL2]
	AOJ W3,
	DBP7J CS,RDLIN3
;HANDLE COLON IN A LINE.  IF /L, MAYBE SET THE FILE'S LLABEL VARIABLE.
RDLCLN:	TLNN FR,FLLABL
	 JRST MPVOK4	;COLON JUST GOES INTO LINE IF LABEL FEATURE OFF.
	JUMPE W3,MPVOK4	;COLON AT BEGINNING OF LINE ISN'T A LABEL.
	MOVEI T,LNDATA(W1)	;MAKE SURE THERE ARE NO SPACES, TABS, COLONS OR SEMIS
	HRLI T,440700		;BEFORE THIS COLON.
RDLCL0:	ILDB TT,T
	CAIG TT,40
	 JRST MPVOK4
	CAIE TT,":
	 CAIN TT,";
	  JRST MPVOK4	;IT LOSES - IT'S JUST A NORMAL COLON.
	CAME T,W2	;SKIP IF IT WINS.  MAKE IT THIS FILE'S LAST LABEL.
	 JRST RDLCL0
MPVOK5:	MOVES LNDATA+1(W1)	;MAKE SURE AT LEAST 2 WORDS OF CORE EXIST
MPVOK7:	MOVES 1(T)		;MAKE SURE THERE'S SPACE FOR THE COLON AND TRAILING 0.
	MOVEI TT,":
	IDPB TT,T		;STORE THE COLON IN THE LINE.
	SETZ TT,		;STORE A ^@ AFTER THE COLON. IT WILL GET OVERWRITTEN
	IDPB TT,T		;BY LINE'S NEXT CHAR, BUT WILL LIVE ON IN LLABEL.
	HRRZ T,FR
	LSH T,2
	ADDI T,LLABEL-1		;T GETS LLABEL-1, PLUS 4 TIMES FILE NUMBER.
	PUSH T,LNDATA(W1)	;STORE 1ST 2 WORDS OF THIS LINE'S DATA THERE.
	PUSH T,LNDATA+1(W1)
REPEAT LNLBLN-2,PUSH T,[0]	;2 WORDS ARE ENOUGH FOR A MIDAS LABEL, SO ZERO OUT THE REST.
	JRST MPVOK4

;HERE IF /Y, AFTER READING IN THE LINE, TO SEE IF IT HAS A LABEL.
;A LINE HAS A LABEL IN /Y MODE IF IT STARTS WITH ANYTHING BUT A SPACE, TAB OR ;.
;W1 POINTS AT THE LINE.
LABEL:	SKIPN W3,LNSIZE(W1)
	 RET			;IGNORE EMPTY LINES.
	LDB T,[350700,,LNDATA(W1)]	;GET THE LINE'S FIRST CHARACTER.
	CAILE T,40
	 JRST LABEL1		;STARTS WITH NON-CONTROL NOT SPACE => PROBABLY A LABEL.
	CAIN T,40
	 RET
	CAIE T,^I
	 CAIN T,^L		;BUT LINES STARTING WITH FORMATTERS AREN'T.
	  RET
	CAIE T,^M		;IN /B MODE A LINE CAN BE JUST ONE OF THESE.  THEY AREN'T.
	 CAIN T,^J
	  RET
LABEL1:	CAIN T,";		;CHECK ; HERE - SAVES TIME FOR INDENTED LINES.
	 RET
	HRRZ T,FR
	IMULI T,LNLBLN
	ADDI T,LLABEL-1		;GET -1 + ADDR OF PLACE TO PUT LABEL.
	MOVE TT,T		;SAVE THIS FOR LABEL2 WHICH ALSO NEEDS IT.
REPEAT LNLBLN,[
	CAIL W3,.RPCNT*5+1	;COPY START OF LINE INTO IT, BUT DON'T GO PAST END OF LINE
	 PUSH T,.RPCNT+LNDATA(W1)	;IF IT IS A SHORT ONE.
]				;NO NEED TO ZERO OUT REST OF WORDS CAUSE IF LINE IS SHORT
	TLNN FR,FLALL		;THEN THE REAL DATA MUST HAVE A ^@ AFTER IT ANYWAY.
	 RET
	MOVEI T,1(TT)		;IN /B MODE, THE LINE MAY HAVE A REAL ^M^J IN IT,
	HRLI T,440700		;AND IF IT IS SHORT THEN THE ^M^J WAS COPIED INTO THE LABEL.
	MOVEI W3,5*LNLBLN	;SO REPLACE IT WITH A NULL, IN THE LABEL.
LABEL2:	ILDB TT,T
	JUMPE TT,CPOPJ		;LABEL ENDS WITH NULL AND HAS NO ^M OR ^J?
	CAIE TT,^M
	 CAIN TT,^J
	  CAIA
	   SOJG W3,LABEL2	;MAYBE WE EXHAUST THE WORDS OF LABEL AND THERE IS NONE.
	JUMPE W3,CPOPJ
	SETZ TT,		;IF THERE IS A ^M OR ^J, TRUNCATE LABEL AT THAT POINT.
	DPB TT,T
	RET
;HANDLE ^C WHEN LOOKING FOR START OF LINE.
RDLINC:	CAMN CS,GCHARE(FR)	;IS THIS THE ^C AFTER THE BUFFER?
	 JRST [	CALL RELOAD	;YES, RELOAD THE BUFFER AND TRY AGAIN.
		JRST RDLIN1]
	CAME CS,@GCHARZ(FR)	;IS THIS EOF, OR A ^C IN THE FILE?
	 JRST RDLIN4		;^C IN FILE STARTS A LINE.
	IOR FR,EOFTBL(FR)	;IT IS EOF.
RDLIL5:	SETOM EOFFL1(FR)
	MOVEM CS,@GCHARP(FR)
	RET

;HANDLE ^C WHEN ADDING TO A LINE.
RDLILC:	CAMN CS,GCHARE(FR)
	 JRST [	CALL RELOAD
		JRST RDLIN2]
	CAME CS,@GCHARZ(FR)	;^C IN FILE GOES IN THE LINE.
	 JRST MPVOK4
	IOR FR,EOFTBL(FR)	;EOF IN MIDDLE OF LINE: SAY EOF WAS REACHED.
	MOVEI T,LNDATA-1(W1)
RDLIL4:	CAIN T,(W2)		;FLUSH ALL ^C'S AND ^@'S OFF THE END OF THE LINE.
	 JRST RDLIL5		;LINE WAS NOTHING BUT ^C'S AND ^@'S? SAY THERE WAS NO LINE.
	LDB C,W2
	CAIE C,^C
	 JUMPN C,RDLIN3		;LINE HAS SOMETHING ELSE, SO RETURN IT.
	SOJ W3,
	DBP7J W2,RDLIL4

MPVOK4:	IDPB C,W2		;COME HERE TO INSERT A ^C OR : IN A LINE,
	AOJA W3,RDLIN2		;WITHOUT THE SPECIAL HANDLING THEY SOMETIMES GET.
; RDWRD - Read a word from file.  This is completely independent of
;	RDLIN and RELOAD.
; Returns .+1 if EOF
; Returns .+2 otherwise,
;	W1/ word

RDWRD:	SOSGE GWORDC(FR)	; Decrement total cnt for file
	 JRST [	SETOM EOFFL1(FR)	; Hit EOF.
		SETOM GWORDB(FR)
		SETZM GWORDC(FR)	; Keep this normalized.
		RET]
	AOSE W1,GWORDB(FR)	; Skip for initial loadup
	 CAMLE W1,GWORDE(FR)
	  JRST RDWRD2		; Load up the buffer.
	MOVE W1,(W1)
	AOS (P)
	RET
RDWRD2:	MOVEI CS,FILBFL
	MOVE C,GWORDI(FR)
	HRRZM C,GWORDB(FR)
	CALL @GCHARX(FR)	; Read another bufferful
	MOVE W1,@GWORDB(FR)	; Get 1st wd of buffer
	AOS (P)
	RET

GWORDL:	BLOCK 3			; # words length of file
GWORDC:	BLOCK 3			; # words left in file
GWORDB:	-1 ? -1 ? -1
GWORDI:	444400,,FILBF1
	444400,,FILBF2
	444400,,FILBF3
GWORDE:	FILBE1 ? FILBE2 ? FILBE3
; RUDWRD - Read a word from inferior process.
;	  This is completely independent of RDLIN and RELOAD.
; Returns .+1 if EOF
; Returns .+2 otherwise,
;	W1/ word

RDUWRD:	SOSGE GWORDC(FR)	; Decrement total cnt for file
	 JRST [	SETOM EOFFL1(FR)	; Hit EOF.
		SETOM GWORDB(FR)
		SETZM GWORDC(FR)	; Keep this normalized.
		RET]
	AOSE W1,GWORDB(FR)	; Skip for initial loadup
	 CAMLE W1,GWORDE(FR)
	  JRST RDUWD2		; Load up the buffer.
	MOVE W1,(W1)
	AOS (P)
	RET
RDUWD2:	MOVEI CS,FILBFL
	MOVE C,GWORDI(FR)
	HRRZM C,GWORDB(FR)
	CALL RDUBUF
	MOVE W1,@GWORDB(FR)	; Get 1st wd of buffer
	AOS (P)
	RET

RDUBUF:	
IFN ITS,[
	M.SIN CHUIN1(FR),C,CS
	RET
] ;IFN ITS
IFN TNX,[
	TYPE "Error - TNX version doesn't have /$ feature yet
"
	HALT
] ;IFN TNX
;REFILL THE BUFFER OF THE FILE (FR).  WORKS WHETHER READING IN CHAR
;OR WORD MODE, ON BOTH ITS AND TNX (WHICH UPDATE BP'S DIFFERENTLY).
RELOAD:	MOVE C,GCHARI(FR)	;YES, JUST REFILL THE BUFFER.  GET BP
	MOVEI CS,FILBFL		;AND COUNT
	CALL @GCHARX(FR)	;INPUT THE STUFF
	TLZ C,7700
	TLO C,0700		;MAKE BP A CHAR B.P. (IF NOT ALREADY)
	MOVEI CS,^C
	IDPB CS,C		;PUT A ^C AFTER WHAT WE INPUT.
	MOVEM C,@GCHARZ(FR)	;AND SAVE BP TO EOF CHAR.
	MOVE CS,GCHARB(FR)	;RE-INIT THE B.P.
	RET

GCHARP:	FILPT1		;ADDRESS OF BUFFER BP OF FILE.
	FILPT2
	FILPT3

GCHARZ:	FILEP1		;ADDR OF B.P. TO THE ^C AFTER WHAT WAS READ IN.
	FILEP2
	FILEP3

GCHARI:	444400,,FILBF1	; BP TO IDPB 1ST WD OF BUFFER.
	444400,,FILBF2
	444400,,FILBF3

GCHARB:	440700,,FILBF1	;B.P. TO ILDB 1ST CHAR OF BUFFER.
	440700,,FILBF2
	440700,,FILBF3

GCHARE:	350700,,FILBE1+1 ;B.P. TO ^C AFTER END OF BUFFER.
	350700,,FILBE2+1
	350700,,FILBE3+1

GCHARX:	[M.SIN CHIN1,C,CS	;INSTRS TO INPUT ON CHIN1
		RET]
	[M.SIN CHIN2,C,CS	;DITTO FOR CHIN2
		RET]
	[M.SIN CHIN3,C,CS
		RET]

EOFTBL:	FLEOF1,,	;EOF FLAG FOR FILE 1
	FLEOF2,,	;EOF FLAG FOR FILE 2
	FLEOF3,,

RCHSTP:	440700,,HBUF1	;BYTE POINTERS TO HEADER TABLES
	440700,,HBUF2
	440700,,HBUF3
; INT HANDLER, ITS ONLY - HANDLES MPV AND --MORE-- INTERRUPTS.
; TNX DOESN'T NEED MPV HANDLER (ALTHO IT MAKES ERRORS HARDER TO FIND)
; AND DOESN'T HAVE --MORE-- INTERRUPTS...

IFN ITS,[

TSINT:
	LOC 42 ? JSR TSINT ? LOC TSINT	; ENSURE INT VECTOR SET UP
	0
	0
	EXCH W1,TSINT
	JUMPL W1,MORINT
	CAIE W1,%PIMPV
	 ERRHLT
	HRRZ W1,TSINT+1	;MPV INTERRUPTS TO GET MORE CORE ARE LEGAL
	CAIE W1,MPVOK7	;ONLY FROM CERTAIN SPOTS.
	 CAIN W1,MPVOK6
	  JRST TSINT2
	CAIE W1,MPVOK5
	 CAIN W1,MPVOK4
	  JRST TSINT2
	CAIE W1,MPVOK3
	 CAIN W1,MPVOK2
	  JRST TSINT2
	CAIE W1,MPVOK1
	 CAIN W1,MPVOK0
	  CAIA
	   ERRHLT
TSINT2:	.SUSET [.RMPVA,,W1]
	LSH W1,-10.
	SYSCAL CORBLK,[MOVEI 400000 ? MOVEI -1 ? W1 ? MOVEI 400001]
	 JRST [	CALL TYLERR ? JRST ERRFIN]
	MOVE W1,TSINT
	.DISMI TSINT+1

MORINT:	MOVE W1,TSINT
	INSIRP PUSH P,C T
	MOVEI T,[ASCIZ /--MORE--/]
	CALL TYPMS0
	SYSCAL IOT,[MOVEI CHTTI ? MOVE C ? 5000,,%TIPEK]
	 .LOSE 1000
	CAIN C,^C
	 JRST MORKIL
	CAIE C,40
	 CAIN C,177
	  .IOT CHTTI,C		;SPACE OR RUBOUT IS GOBBLED.
	SKIPE FLUSHP
	 CAIN C,40		;IF IT ISN'T SPACE, AND WE CAN FLUSH, DO SO.
	  JRST MORPRC
	MOVEI T,[ASCIZ /FLUSHED
/]
	CALL TYPMS0
	MOVE P,FLUSHP
	SETZM FLUSHP
	.DISMI [CPOPJ]

MORKIL:	.IOT CHTTI,C		;^C => GOBBLE IT AND KILL THE SRCCOM.
	.LOGOUT
	.BREAK 16,160000

MORPRC:	MOVEI T,[ASCIZ /
/]
	CALL TYPMS0
	INSIRP POP P,T C
	.DISMI TSINT+1

] ;IFN ITS
;OPEN INPUT FILE ON CHNL IN W1.

INOPEN:	MOVEI FP,INFB
	HRLI FP,(W1)		;MAKE <CH>,,<FB ADDR>
IFN ITS,[
	MOVSI W2,(SIXBIT/>/)
	SKIPN $F6FN2(FP)	;DEFAULT THE FN2 TO ">".
	 MOVEM W2,$F6FN2(FP)
]
	MOVEI W2,OPNRDA		;USE UNIT MODE FOR /X FILES,
	TLNN FR,FLXCTF
	 MOVEI W2,OPNRDW	;USE BLOCK MODE FOR OTHER INPUT FILES.
	CALL (W2)
	 CALL OPENL		; LOST?? REPORT ERROR.
	MOVE W2,INOPT3-CHIN1(W1)	;GET ADDR OF LAST WORD OF BUFFER.
	MOVEI W1,(W2)
	HRLI W1,10700		;MAKE B.P. TO END OF BUFFER,
	MOVEM W1,FILPT1-FILBE1(W2)
	MOVE W1,[ASCIC//]
	MOVEM W1,1(W2)
	HRRI FR,0		;PUT NUMBER OF FILE INTO FR.
	CAIE W2,FILBE1
	 HRRI FR,1
	PJRST RCHST		;SET UP FILE'S HEADER.

INOPT3: FILBE1
	FILBE2
	FILBE3

;COME HERE WHEN /@ IS SPECIFIED FOR THE 1ST INPUT FILE.
;THAT MEANS TO TREAT THE SPECIFIED 1ST INPUT FILE AS A COMPARISON
;FILE, EXTRACT THE NAME OF THE SECOND FILE USED IN THAT COMPARISON,
;AND USE THAT FILE AS OUR 1ST INPUT FILE THIS TIME.
;JUMPS BACK TO THE COMMAND PROCESSING LEVEL TO OPEN THE REAL 1ST INPUT FILE.
RFINDR:	MOVE W1,GCHARI
	MOVEI W2,FILBFL
	M.SIN CHIN1,W1,W2	;READ IN SOME OF THE FILE.
	ADDI W1,1
	ANDI W1,-1		;MAKE SURE IT LOOKS LIKE A COMPARISON FILE.
	CAIGE W1,FILBF1+10.
	 JRST ERRIND
	MOVE W1,FILBF1
	MOVE W2,FILBF1+1
	CAMN W1,[ASCII /
;CO/]
	 CAME W2,[ASCII /MPARI/]
	  JRST ERRIND
	MOVE W1,FILBF1+2
	CAME W1,[ASCII /SON O/]
	 JRST ERRIND
	MOVE W1,[350700,,FILBF1+3] ;POINT AT THE SPACE AFTER THE "OF".
	MOVEI W2,4
RFIND2:	ILDB C,W1		;THEN SKIP PAST 3 SPACES, TO BE AFTER THE "AND".
	CAIE C,40
	 JRST RFIND2
	SOJG W2,RFIND2
	SAVE TTIPNT		;WHICH IS JUST AT THE SECOND COMPARED FILE'S NAME.
	SAVE TTICNT
	HRLZM P,TTICNT
	MOVEM W1,TTIPNT		;READ IN THAT FILE NAME
	CALL RFILE		;RFILE RETURNS AFTER THE FN2 SINCE FLINDR=1.
	ILDB C,TTIPNT
	CAIE C,^J
	 JRST .-2		;PASS THE LINEFEED OF THAT LINE
	MOVEI C,3
	ADDM C,TTIPNT		;SKIP THE ";OPTIONS ARE   "
	CALL RFILSW		;READ THE SWITCHES FROM THE COMPARISON FILE
	REST TTICNT
	REST TTIPNT
	TLZ FR,FLINDR
	JRST RFIND1
IFN ITS,[

;PUT FILE DESCRIPTION IN ASCII INTO HBUF FOR THIS FILE
RCHST:	SYSCAL RFNAME,[	MOVEI CHIN1(FR)
		2000,,RCHSTB
		2000,,RCHSTB+1
		2000,,RCHSTB+2
		2000,,RCHSTB+3]
	 .LOSE 1000
	SYSCAL FILLEN,[MOVEI CHIN1(FR) ? MOVEM W2]
	 .LOSE 1000
	MOVEM W2,GWORDL(FR)	; Set length of file
	MOVEM W2,GWORDC(FR)	; Also # of words left to read

	MOVE W2,RCHSTP(FR)	;NOW SET UP BYTE POINTER TO HEADER AREA TO READ INTO
	MOVE T,RCHSTB	;GET THE CHOSEN DEVICE NAME
	JSP W1,RCHST6	;DEVICE NAME
	    ":		;END WITH COLON
	MOVE T,RCHSTB+3
	JSP W1,RCHST6	;SYSTEM NAME
	    ";		;TERMINATED BY SEMICOLON
	SKIPN T,RCHSTB+1
	 MOVE T,INFB+$FNAME		;IF REALLY NONE, USE SPEC'D.
	SKIPN LSTFB+$FNAME		;DEFAULT OUTPUT FN1 TO INPUT.
	 MOVEM T,LSTFB+$FNAME
	JSP W1,RCHST6	;FNAM1
	    40		;TERMINATED (ITS CONVENTION) BY SPACE
	SKIPN T,RCHSTB+2
	 MOVE T,INFB+$FEXT
	JSP W1,RCHST6	;FNAM2
	    0		;DON'T PRINT TERMINATING CHAR
	MOVEI C,0
	IDPB C,W2	;MARK END OF STRING
	SKIPN FSBIN	; If hacking inferior process addr space, skip
	 RET		; else return, done.

	SKIPN UNQNAM
	.SUSET [.RJNAME,,UNQNAM]
	AOS UNQNAM
	MOVEI T,CHUO1(FR)
	HRLI T,.UIO
	SYSCAL OPEN,[T ? ['USR,,] ? [0] ? UNQNAM]
	 .LOSE 1000
	MOVEI T,CHUIN1(FR)
	HRLI T,.UII
	SYSCAL OPEN,[T ? ['USR,,] ? [0] ? UNQNAM]
	 .LOSE 1000
	SYSCAL LOAD,[MOVEI (T) ? MOVEI CHIN1(FR)]
	 .LOSE 1000
	SYSCAL ACCESS,[MOVEI (T) ? [0]]
	 .LOSE 1000
	SYSCAL USRVAR,[MOVEI (T) ? [SIXBIT /MEMT/] ? MOVEM W2]
	 .LOSE 1000
	MOVEM W2,GWORDL(FR)
	MOVEM W2,GWORDC(FR)
	RET
.SCALAR UNQNAM

		;JSP W1,RCHST6	;PRINT (IDPB ASCII VIA W2) SIXBIT WORD IN T
		; "<TERMINATING CHAR OR 0>	;FOLLOW WITH TERMINATING CHAR UNLESS SIXBIT IS NULL
			; ^ DOESN'T PRINT TRAILING SPACES

RCHST6:	JUMPE T,1(W1)	;RETURN ON NULL ARG
RCHS6A:	MOVEI C,0	;CLEAR OUT C TO RECEIVE CHAR
	LSHC C,6	;SHIFT IN NEXT CHAR
	ADDI C,40	;CONVERT TO ASCII
	IDPB C,W2	;DEPOSIT WHEREVER IT'S GOING
	JUMPN T,RCHS6A	;LOOP UNTIL WORD EMPTY
	SKIPE C,(W1)	;NOW GET TERMINATOR
	 IDPB C,W2	;NOT NULL, USE IT
	JRST 1(W1)
] ;IFN ITS
;READ IN A COMMAND, PROCESSING RUBOUTS, PROMPTING WITH "#".
CMDLIN:	SKIPE	CMDFIL
	 JRST	TTIFIL		;IF IN COMMAND FILE, READ FROM IT INSTEAD OF TTY.
TTILIN:	HRROS	(P)		;PROMPT WITH "#".
	JRST TTILI1

TTILNA:	HRRZS	(P)		;FOR /M INPUT, PROMPT WITH "*"
	JRST TTILI1

;READ A CHAR OF TTY INPUT (OR ^M IF NONE LEFT).
TTICHR:	SOSGE	TTICNT		;IF NO CHARS LEFT,
	 SKIPA	C,[^M]		;SAY EOL.
	  ILDB	C,TTIPNT	;ELSE GET NEXT CHAR FROM BUFFER.
	RET

;READ AND UPCASE A CHAR OF INPUT.
TTICHU:	CALL	TTICHR		;GET CHAR
	CAIL	C,"A+40		;SKIP IF LESS THAN LOWER CASE A
	 CAILE	C,"Z+40		;SKIP IF IN RANGE A-Z
	  CAIA			;SKIP IF NOT A-Z (LC)
	   SUBI	C,40		;LOWER CASE TO UPPER CASE
	RET

IFN ITS,[
RUBOUT"A=1
RUBOUT"B=2
RUBOUT"C=3
RUBOUT"D=4

RUBOUT"$$PROMPT==1

.INSRT SYSENG;RUBOUT

RUBOUT"INCHR:
	.IOT CHTTI,RUBOUT"A
	RET

RUBOUT"OUTCHR:
	SYSCAL IOT,[%CLIMM,,CHTTO ? RUBOUT"A ? %CLBIT,,%TJMOR]
	 .LOSE %LSFIL
	RET

RUBOUT"DISPLAY:
	SYSCAL IOT,[%CLIMM,,CHTTO ? RUBOUT"A ? %CLBIT,,%TJMOR+%TJDIS]
	 .LOSE %LSFIL
	RET

RUBOUT"PROMPT:
	MOVEI RUBOUT"A,"#
	SKIPL PRMNUM
	 MOVEI RUBOUT"A,"*
	JRST RUBOUT"OUTCHR

RUBOUT"DISPATCH:
	CAIN RUBOUT"A,%TXCTL+"Q	;MAKE ^Q NOT SPECIAL FOR RUBOUT PROCESSING.
	 JRST RUBOUT"INSECH	;THAT IS, IT WON'T QUOTE A RUBOUT.
	CAIN RUBOUT"A,%TXCTL+"M	;^M SHOULD JUST INSERT A ^M, NOT ^M^J
	 JRST RUBOUT"BRKINS
	JRST RUBOUT"RB$DSP

.SCALAR PRMNUM			;NEGATIVE => PROMPT WITH #.  POS OR ZERO => PROMPT WITH *.
.VECTOR RBBLK(RUBOUT"RB.LEN)	;RUBOUT PROCESSOR ARGUMENT BLOCK.

;READ A LINE BY CALLING THE RUBOUT PACKAGE.  ASSUMES LH OF (P) NEGATIVE => PROMPT WITH #.
TTILI1:	CALL CRLF
	MOVE W1,(P)
	MOVEM W1,PRMNUM
TTILI9:	CALL RUBOUT"PROMPT
	MOVE W1,[010700,,TTIBUF-1]
	MOVEM W1,TTIPNT		;SET UP FOR FETCHING CHARS LATER.
	MOVEM W1,RBBLK+RUBOUT"RB.BEG
	ADDI W1,TTIBFL
	MOVEM W1,RBBLK+RUBOUT"RB.END
	MOVEI RUBOUT"A,CHTTO
	MOVEI RUBOUT"B,RBBLK
	CALL RUBOUT"INIT
TTILI8:	CALL RUBOUT"READ	;READ CHARACTERS UP TO BREAK CHAR.
	CAMN RUBOUT"A,[-1]
	 JRST [	.IOT CHTTO,[^G]	;BUFFER FULL: DING, AND LET USER RUB OUT SOME.
		JRST TTILI8]
	JUMPL RUBOUT"A,TTILI1	;OVER-RUBOUT => CRLF AND TRY AGAIN.
	MOVEI W2,0
	DPB W2,RBBLK+RUBOUT"RB.PTR	;REPLACE BREAK CHAR WITH 0.
	CAIN RUBOUT"A,%TXCTL+"M
	 JRST TTILI4
	CALL CRLF		;IF BREAK WASN'T A CR, TYPE A CR,
	TLNN FR,FLMERG		;AND IF READING A COMMAND, REMEMBER TO RETURN TO DDT
	 SETOM	CTLCF		;AFTER EXECUTING IT.
TTILI4:	MOVE W1,TTIPNT		;COUNT THE CHARACTERS WE GOT.  SET UP TTICNT.
	SETZM TTICNT
TTILI2:	CAMN W1,RBBLK+RUBOUT"RB.PTR
	 JRST TTILI3
	IBP W1
	AOS TTICNT
	JRST TTILI2

TTILI3:	SOSE TTICNT		;DON'T COUNT THE TERMINAL 0 IN TTICNT.
	 RET			;RETURN IF LINE IS NON NULL.
	SKIPL (P)		;IF IT ISN'T A COMMAND, RETURN IT EVEN THOUGH NULL.
	 RET
	SKIPGE CTLCF		;NULL COMMAND LINE ENDED BY ^C MEANS EXIT.
	 JRST QUIT
	JRST TTILI9		;OTHERWISE READ ANOTHER COMMAND LINE.
]
IFN TNX,[
TTILI1:	CALL CRLF
TTILI2:	SKIPE FLG20X		;ON A 20?
	 JRST TTIL20		;YES
;COME HERE AFTER NULL LINE.
	SETZM	TTICNT		;NO CHARS READ YET.
	SKIPGE	(P)
	 MOUTI	CHTTO,"#
	SKIPL	(P)
	 MOUTI	CHTTO,"*
	MOVE	C,[440700,,TTIBUF]
	MOVEM	C,TTIPNT
TTILUP:	CALL	TYI 		;READ A CHAR FROM TTY.
	CAIN	C,^M
	 JRST	TTICR		;^M MEANS ALL READ.
	CAIE	C,^D
	 CAIN	C,^U
	  JRST	TTILI1		;^U CANCELS CMD.
	CAIN	C,177
	 JRST	TTIRUB
	CAIN	C,^L		;IF USER TYPES ^L, RETYPE THE BUFFERED INPUT.
	 JRST	TTICTL
	CAIE	C,^Z
	 CAIN	C,^C
	  JRST	TTICTC		;^C MEANS DO CMD, THEN VALRET :KILL.
	IDPB	C,TTIPNT	;NORMAL CHAR.
	AOS	TTICNT
	JRST	TTILUP

TTICTC:	CALL	CRLF		;INDICATE COMMAND HAS BEEN TERMINATED.
	TLNN	FR,FLMERG	;^C DOES NOTHING IF INPUT TO MERGE.
	 SETOM	CTLCF		;REMEMBER TO VALRET WHEN CMD DONE.
;HERE AFTER ORDINARY LINE TERMINATOR.
TTICR:	SKIPL	(P)
	 JRST	TTICR1
	SKIPN	TTICNT		;IF NULL COMMAND LINE, RETRY.
	 JRST	TTILI3
TTICR1:	SETZ C,
	IDPB C,TTIPNT		; TERMINATE WITH ASCIZ
	MOVE	C,[440700,,TTIBUF]
	MOVEM	C,TTIPNT	;SET UP FOR REMOVAL OF CHARS.
	RET

TTILI3:	SKIPE	CTLCF		;NULL LINE:
	 JRST	QUIT		;...IF ^C ENDED LINE.
	JRST	TTILI2

TTICTL:	MOVEI	T,[ASCIZ /#/]	;COME HERE FOR ^L.  SCREEN ALREADY CLEARED ON DISPLAY.
	SKIPL	(P)
	 MOVEI	T,[ASCIZ /*/]
	CALL	TYPMSG		;PRINT CRLF AND ASTERISK.
	MOVE	TT,[440700,,TTIBUF]
	MOVE	C,TTICNT	;THEN RETYPE THE BUFFERED INPUT.
	M.SOUT CHTTO,TT,C
	JRST	TTILUP

TTIRUB:	SOSGE	TTICNT		;IF NO CHAR TO RUB, RETRY.
	 JRST	TTILI1
	LDB	C,TTIPNT
	MOUTC	CHTTO,C 	;PRINT RUBBED CHAR.
	MOVSI	C,070000
	ADD	C,TTIPNT
	JUMPGE	C,TTIRU1	;IF STILL IN SAME WD.
	MOVEI	C,-1(C )	;ELSE, MOVE TO END OF PREV. WD.
	HRLI	C,010700
TTIRU1:	MOVEM	C,TTIPNT
	JRST	TTILUP

;USE SYSTEM ROUTINES ON A 20
TTIL20:	HRROI	R3,[ASCIZ /#/]	;PROMPTING TEXT
	SKIPL	(P)
	 HRROI	R3,[ASCIZ /*/]
	MOVE	R1,R3		;HAVE TO OUTPUT PROMPT BY HAND, SIGH
	PSOUT
	HRROI	R1,TTIBUF
	MOVE 	R2,[RD%TOP+5*TTIBFL]
	RDTTY
	 JRST	RESTRT
	TLZ 	R2,-1		;FIGURE COUNT
	SUBI	R2,5*TTIBFL
	LDB C,R1
	CAIE C,^J
	 JRST TTIL21
	MOVNI R3,1
	ADJBP R3,R1
	LDB C,R3
	CAIE C,^M
	 JRST TTIL21
	MOVE R1,R3
	ADDI R2,1
TTIL21:	MOVNI R3,1
	ADJBP R3,R1
	MOVEM R3,TTIPNT
	SETCAM R2,TTICNT	; TTICNT := -R2-1
	CAIE C,^Z
	 JRST TTICR
	JRST TTICTC
] ;IFN TNX
;COME HERE TO SEE IF THE COMMAND STRING IS JUST "?" OR "HELP".
;IF NOT, RETURNS. IF SO, PRINTS HELP (FROM INFO;SRCCOM >)
;AND RETURNS TO RELDEV.
TRYHLP:	SAVE TTIPNT
	SAVE TTICNT
	CALL TTINSP	;GO PAST INITIAL SPACES.
	CAIN C,"?
	 JRST TRYHL1	;"?" MIGHT BE START OF GOOD STUFF
	CAIE C,"H	;SO MIGHT "H".
	 JRST TRYHLL	;ANYTHING ELSE => USER ISN'T ASKING FOR HELP.
	CALL TTICHU
	CAIE C,"E
	 JRST TRYHLL
	CALL TTICHU
	CAIE C,"L
	 JRST TRYHLL
	CALL TTICHU
	CAIE C,"P
	 JRST TRYHLL
TRYHL1:	CALL TTINSP
	CAIE C,^M
	 CAIN C,^C
	  CAIA
	   JRST TRYHLL
;USER WANTS HELP - GIVE IT TO HIM.
	CALL OPNHLP
	 JRST ERRHLP
TRYHL3:	M.BIN CHIN1,C
	CAIN C,^L
	 JRST RELDEV
	JUMPL C,RELDEV
	MOUTC CHTTO,C
	JRST TRYHL3

TRYHLL:	REST TTICNT
	REST TTIPNT
	RET

;READ 1 CHAR FROM THE COMMAND STRING, THEN KEEP READING TILL READ A NON-SPACE.
;CONVERTS TO UPPER CASE.
TTINSP:	CALL TTICHU
	CAIN C,40
	 JRST TTINSP
	RET
;COME HERE TO HANDLE A COMMAND WITH /X IN IT.
CMDXCT:	SKIPE CMDFIL
	 JRST ERRXCT	;/X INSIDE AN EXECUTE FILE??
	SKIPLE TTICNT	;ANY EXTRA FILES SPECIFIED?
	 JRST ERRXTRA
	M.MVCH CHIN1,CHCMD	;MAKE THE ALREADY OPEN 1ST INPUT FILE BE OUR COMMAND FILE.
	MOVE W1,INFB+$FDIR
	MOVEM W1,CMDIS	;MAKE INPUT DEV AND SNAME THE INPUT DEFAULTS
	MOVE W1,INFB+$FDEV
	MOVEM W1,CMDID
	MOVE W1,LSTFB+$FDIR
	MOVEM W1,CMDOS	;AND OUR OUTPUT DEV AND SNAME THE OUTPUT DEFAULTS
	MOVE W1,LSTFB+$FDEV
	CAMN W1,FSTTY
	 MOVE W1,FSDSK
	MOVEM W1,CMDOD
	SETOM CMDFIL	;SAY WE ARE NOW EXECUTING A COMMAND FILE.
	JRST RELDEV	;GO READ THE NEXT COMMAND.

;COME HERE TO READ A COMMAND LINE FROM A COMMAND FILE.
TTIFIL:	SETZM TTICNT		;INITIALIZE THE COMMAND BUFFER EMPTY.
	MOVE BP,[440700,,TTIBUF]
	MOVEM BP,TTIPNT
;NOW SEE IF THERE ARE ANY MORE COMMANDS IN THE FILE.
TTIFI0:	M.BIN CHCMD,C
TTIFI1:	ANDI C,-1
	CAIE C,^C		;EOF OR END OF 1ST PAGE => COMMAND FILE IS OVER.
	 CAIN C,^L
	  JRST TTIEOF
	CAIE C,";		;ELSE, A COMAND LINE IS IDENTIFIED BY
	 JRST TTIFI0		;STARTING WITH ";;SRCCOM COMMAND ;;"
IRPC X,,[;SRCCOM COMMAND ;;]
	M.BIN CHCMD,C
	CAIE C,"X
	 JRST TTIFI1
TERMIN
;WE FOUND ANOTHER COMMAND LINE'S BEGINNING.
;NOW, EVERYTHING UP TO NEXT ^C, ^L, ^M OR ";;" IS PART OF THE COMMAND.
	TDZA W1,W1
TTIFI2:	 MOVE W1,C	;REMEMBER THE PREVIOUS CHAR FOR FINDING ";;".
	M.BIN CHCMD,C
	ANDI C,-1
	CAIE C,^C
	 CAIN C,^M
	  JRST TTIFI3
	CAIN C,^L	;STOP BEFORE A ^C, ^L OR ^M.
	 JRST TTIFI3
	CAIN C,";	;BEFORE THE SECOND ";" OF A ";;",
	 CAIE W1,";
	  AOSA TTICNT
	   JRST TTIFI4	;MUST STOP, AND FLUSH THE PREVIOUS ";".
	IDPB C,BP	;ELSE STORE THE CHAR AND COUNT IT.
	JRST TTIFI2

TTIFI4:	SOS TTICNT
	DBP7J BP,
TTIFI3:	SETZ C,		;NOW WE HAVE READ IN A WHOLE LINE.
	IDPB C,BP	;SO MAKE IT ASCIZ
	MOVEI T,TTIBUF	;AND TYPE IT ON THE TTY SO USER CAN MONITOR PROGRESS.
	CALL TYPMS0
	JRST CRLF

TTIEOF:	M.CLS CHCMD	;HERE AT END OF COMMAND FILE.
	SETZM CMDFIL	;STOP TRYING TO USE IT, AND COMMIT SUICIDE IF A ^C
	SKIPE CTLCF	;IS STILL LEFT FROM WHEN IT WAS SPECIFIED.
	 JRST QUIT
	JRST TTILIN	;ELSE, READ FROM TTY.
SUBTTL ITS - FILESPEC READER

;READ FILE SPEC.

IFN ITS,[

RFILE:	SETZM	$F6FN2(FP)	;DEFAULT FN2 UP TO CALLER.
RFILSW:	SETZ	CS,
RFNAME:	MOVE	BP,[440600,,0]
	MOVEI	0,6		;SET UP TO READ IN A FILENAME.
	MOVEM	0,RFILC
	SETZ	0,
RFLOOP:	CALL	TTICHU		;READ A CHAR. UPPER CASE
	CAIN	C,^Q
	 JRST	RFCTQ		;^Q QUOTES NEXT CHAR.
	CAIE	C,"=
	 CAIN	C,",
	  JRST	RFSPAC		;COMMAS TERMINATE SPEC.
	CAIE	C,"_
	 CAIG	C," 
	  JRST	RFSPAC		;THESE ALSO.
	CAIN	C,":
	 JRST	RFCOL		;COLON SETS DEV.
	CAIN	C,";
	 JRST	RFSEM		;SEMI SETS SNAME.
	CAIN	C,"/
	 JRST	RFSPAC		;SLASH ENDS NAME.
	JRST	RFNORM		;ALL OTHER CHARS.

RFCTQ:	CALL	TTICHU		;READ UPPER CASE CHAR
	CAIGE	C,40
	 JRST 	RFSPAC		;DON'T TRY TO QUOTE A CONTROL CHARACTER.
RFNORM:	MOVEI	C,-40(C)	;CONV. TO SIXBIT.
	SOSL	RFILC		;PUT IN NAME IF ROOM LEFT.
	IDPB	C,BP
	JRST	RFLOOP

RFXCTB:	MOVEM	0,$F6FN1(FP)
	MOVEM	0,$F6FN2(FP)
	MOVEM	0,$F6DEV(FP)
	MOVEM	0,$F6DIR(FP)
	SKIPA

RFCOL:	SKIPE	0
	 MOVEM	0,$F6DEV(FP)		;SET DEVICE FIELD.
	JRST	RFNAME

RFSEM:	SKIPE	0
	 MOVEM	0,$F6DIR(FP)
	JRST	RFNAME

RFSPAC:	JUMPE	0,RFSPA0	;IF NAME WAS READ,
	XCT	RFXCTB(CS)	;STORE IT,
	AOJ	CS,		;INCR. STORING POS.
	TLNN	FR,FLINDR
	 JRST	RFSPA0
	CAIN	CS,2
	 RET
RFSPA0:	CAIN	C,^X		;AS 1ST NAME AVOIDS SETTING IT, ALLOWS FN2 TO BE SET.
	 JRST [	JUMPN CS,RFNAME
		AOJA CS,RFNAME]
	CAIN	C,40
	 JRST	RFNAME		;SPACE -- GET ANOTHER NAME.
	CAIN	C,^C
	 MOVEI	C,^M
	CAIE	C,"/
	 RET			;NOT SLASH, RETURN.
	CALL RDSW		; AHA, READ SWITCH.
	JRST RFNAME		; THEN RETURN TO LOOP.
] ;IFN ITS
SUBTTL TNX - FILESPEC READER

IFN TNX,[

RFILE:	SETZM $FVERS(FP)	; DEFAULT VERSION UP TO CALLER
RFILSW:	SETZM RDFLG	; SAY HAVEN'T READ FILESPEC YET.
RFILE2:	CALL TTICHR	; READ CHAR FROM LINE
	CAIE C,^J
	 CAIN C,^M	; EOL?
	  JRST RFILE8	; YES, EXIT
	CAIE C,^C
	 CAIN C,0
	  JRST RFILE8
	CAIN C,",	; COMMA?
	 JRST RFILE8	; ALSO EXIT
IFE TWX,CAIE C,"_	; Not on Twenex, thank you
	 CAIN C,"=	; EITHER OF THESE ARE VALID OUTPUT FILSPEC INDICATORS.
	  JRST RFILE8
	CAIN C,"/	; START OF SWITCH?
	 JRST [	CALL RDSW	; YES, READ IT & CONTINUE.
		JRST RFILE2]
	CAIE C,^I
	 CAIN C,40
	  JRST RFILE2		; FLUSH WHITESPACE

	; HERE HAVE FIRST CHAR OF FILENAME...
	MOVE W2,[440700,,RFLBUF]
RFILE3:	IDPB C,W2
	CALL TTICHR		;ACCUMULATE CHARACTERS VALID IN FILE NAME
	CAIE C,^J
	 CAIN C,^M
	  JRST RFILE4
	CAIE C,^C
	 CAIN C,0
	  JRST RFILE4
	CAIE C,",
	 CAIN C,"/
	  JRST RFILE4
IFE TWX,CAIE C,"_		; Not on Twenex, thank you
	 CAIN C,"=
	  JRST RFILE4
	CAIE C,^I
	 CAIN C,40
	  JRST RFILE4
	CAIE C,^V
	 JRST RFILE3
	IDPB C,W2
	CALL TTICHR
	JRST RFILE3

RFILE4:	MOVEI A,0		;MARK END OF ASCIZ STRING
	IDPB A,W2
	MOVE W2,TTIPNT
	DBP7J W2,		; SKIP BACK ONE
	MOVEM W2,TTIPNT
	AOS TTICNT
RFILE5:	SKIPE RDFLG		; ALREADY READ A FILESPEC?
	 JRST RFILE8		; YES, DON'T READ THIS SPEC YET...
	HRROI W2,RFLBUF
	SYSCAL GTJFN,[[GJ%OFG+GJ%SHT] ? W2][$FJFN(FP) ? W2]
	 JRST RFILE9		; SOME SORT OF SYNTAX ERROR
	;HERE COULD COMPARE W2 AGAINST TTIPNT IN CASE EXTRA GARBAGE IN FILENAME
	CALL JFNSTB		; STORE FILENAME SPEC IN FB
	SYSCAL RLJFN,[$FJFN(FP)]
	 JFCL
	SETZM $FJFN(FP)

	; FILESPEC READ...
	SETOM RDFLG		; SAY SO, SO IF SEE ANOTHER WILL STOP
	JRST RFILE2

RFILE8:	RET			; RETURN
	
RFILE9:	HRROI W1,RFLBUF
	PSOUT
	MOUTI CHTTO,^I
	CALL TYLERR		;TYPE LAST ERROR
	JRST ERRFIN

.SCALAR RDFLG	; -1 WHEN FILESPEC READ
.VECTOR RFLBUF(20.)	;BUFFER FOR READING FILENAME INTO FOR GTJFN
] ;IFN TNX
SUBTTL SWITCH PROCESSING

;FOR SWITCH "A, SET OR CLEAR BIT D ACCORDING TO B.
DEFINE	SWITCH	A,B,D
	CAIN	C,"A
	HRR!B!I	BP,D
TERMIN

RDSW:	CALL	TTICHU		; READ A SWITCH (SHOULD BE NEXT CHAR).
	SETZ	BP,
	SWITCH	!,O,FLOVRD		;/! - FORCE COMPARISON BETWEEN A FILE AND ITSELF
	SWITCH	@,O,FLINDR		;/@ - GO INDIRECT THROUGH A COMPARISON FILE
					 ;TO FIND THE FILE NAMES TO USE.
	CAIN C,"#			;/# - Binary compare (= FILCOM /W)
	 JRST [	SETOM FVBIN		;	Set memory flag (sigh)
		RET]
	CAIN C,"$			;/$ - SBLK or CSAVE compare
	 JRST [	SETOM FSBIN
		RET]
	CAIN C,"Q			;/Q - Like FILCOM /Q, gives error
	 JRST [	SETOM QFLAG		;	if files are different
		RET]			;	(for BATCON, mostly)
	SWITCH	B,O,FLALL		;/B - DON'T IGNORE BLANK LINES.
	SWITCH	C,O,FLCMNT		;/C - IGNORE COMMENTS.
	CAIN	C,"D
	 PJRST	SWDISN			;/D - DISOWN SELF.
	SWITCH	E,O,FLENDL		;/E - PRINT THE MATCHING LINES THAT END THE
					;RUN OF DIFFERENCES.
	SWITCH	F,O,FLFLAG+FLALL+FLMERG	;/F - GEN COPY OF FILE 2 WITH CHANGED LINES
					 ;FLAGGED WITH VERTICAL BARS.
	SWITCH	I,O,FLMERG+FLISWT+FLALL	;/I - /M, BUT ANSWER ALL QUESTIONS WITH "I".
	SWITCH	K,O,FLCASE		;/K - IGNORE ALPHABETIC CASE DIFFERENCES
	SWITCH	L,O,FLLABL		;/L - EACH HEADER LINE MENTIONS PREVIOUS LABEL.
	SWITCH	M,O,FLALL+FLMERG	;/M - MERGE FILES.
	SWITCH	S,O,FLSPAC		;/S - IGNORE SPACES.
	SWITCH	W,O,FLFNUM		;/W - PRINT FILE # ON EACH LINE.
	SWITCH	X,O,FLXCTF		;/X - EXECUTE COMMANDS FROM FILE
	SWITCH	Y,O,FLXLBL		;/Y - ANY UNINDENTED TEXT IS A LABEL.
	CAIL	C,"1			;DIGIT - SET NUMLIN.
	 CAILE	C,"9
	  CAIA
	   JRST	[MOVEI	C,-"1(C)	;SET NUM. EXTRA LINES TO MATCH
		MOVEM	C,NUMLIN	;TO THE DIGIT, -1.
		RET]
	JUMPE	BP,ERRSW	;ERROR UNLESS ONE OF ABOVE SWITCHES.
	TLO	FR,(BP)		;SET THE FLG.
	RET			;SWITCH DONE, RETURN.
SUBTTL ERROR MESSAGES/HANDLING

;COME HERE AFTER FAILING INPUT OR OUTPUT OPEN.

OPENL:
IFN ITS,.LOGOUT
	CALL LSTFIL		;PRINT NAME OF LOSING FILE (WHAT FP POINTS TO).
	MOUTI CHTTO,^I
	CALL TYLERR		;TYPE LAST ERROR
	JRST ERRFIN


ERRXTR:	JSP T,ERRMSG
	ASCIZ "Extra input files specified"

ERRHLP:	MOVEI T,[ASCIZ "Can't find help file!"]
	CALL TYPMSG
;	JRST OPENL
	JRST ERRFIN

ERRIND:	JSP T,ERRMSG
	ASCIZ "Bad format /@ indirect file"

ERRIN2:	JSP T,ERRMSG
	ASCIZ "Can't use /@ or /X with second input file"

ERRIN3:	JSP T,ERRMSG
	ASCIZ "Can't use /@ or /X with third input file"

ERR3NM:	JSP T,ERRMSG
	ASCIZ "Three input files but /M not specified"

ERRXCT:	JSP T,ERRMSG
	ASCIZ "Recursive /X attempted"

ERRARC:	JSP T,ERRMSG
	ASCIZ "Can't archive and merge at once"

ERRSW:	JSP T,ERRMSG
	ASCIZ "Illegal switch"



ERRMSG:	CALL TYPMSG		;FOR SIMPLE ERROR MESSAGES; TYPE & DROP THRU

;ALL ERROR MESSAGES COME THROUGH HERE.

ERRFIN:
IFN ITS,.RESET CHTTI,		; FLUSH TTY INPUT BUFFER
IFN TNX,CFIBF
	SETZM CMDFIL		;STOP READING COMMAND FILE.
	M.CLS CHCMD
	SETZM CTLCF		;DON'T KILL SELF; READ ANOTHER CMD STRING INSTEAD.

;COMMAND TERMINATION, SUCCESSFUL OR NOT, ALWAYS COMES THROUGH HERE.

RELDEV:	M.CLS CHIN1
	M.CLS CHIN2
	M.CLS CHMRG
IFN ITS,[
	MOVE W1,TTYSTS
	TLNE W1,%TSMOR
	 SYSCAL TTYSET,[MOVEI CHOUT ? TTYST1 ? TTYST2 ? W1]
	  JFCL
]
	M.CLS CHOUT
	SKIPE CMDFIL		;EXECUTING A FILE => READ MORE FROM IT.
	 JRST RELDE1
IFN ITS,.LOGOUT			;CAN'T GET ANOTHER CMD IF DISOWNED.
	SKIPE CTLCF		;EXIT IF USER GAVE ^C.
	 JRST QUITX

RELDE1:	CALL CRLF
	JRST RESTRT		;ELSE, GET NEW CMD.


;ROUTINES FOR OUTPUTING ERROR MESSAGES

TYPMSG:
IFN ITS,.LOGOUT			;CAN'T PRINT MSG WITHOUT TTY.
	CALL CRLF		;OUTPUT A CARRIAGE RETURN
TYPMS0:	HRLI T,440700		;THIS IS POINTER FOR ERROR MESSAGE
TYPMS1:	ILDB C,T
	JUMPE C,CPOPJ
	CALL TYO
	JRST TYPMS1

; TYPM - FOR USE WITH "TYPE" MACRO.  STACK HAS ADDR OF ASCIZ STR.
TYPM:	PUSH P,C
	PUSH P,T
	MOVE T,-2(P)	; GET ADDR OF ASCIZ
	CALL TYPMSG	; OUTPUT
	POP P,T
	POP P,C
	SUB P,[1,,1]	; FLUSH ARG
	RET

;OUTPUT 6BIT WD IN 0 TO TTY.
TTOSIX:	MOVE	BP,0
TTOSI0:	SETZ	TT,
	ROTC	TT,6		;GET NEXT CHAR.
	MOVEI	TT," (TT)	;CONV. 6BIT TO ASCII.
	MOUTC	CHTTO,TT
	JUMPN	BP,TTOSI0
	RET

; OUTPUT DECIMAL # IN 0 TO TTY.

TTODEC:	IDIVI 0,10.
	HRLM W1,(P)
	SKIPE 0
	 CALL TTODEC
	HLRZ W1,(P)
	ADDI W1,"0
	MOUTC CHTTO,W1
	RET

TYO:	MOUTC	CHTTO,C
	RET

CRLF:	MOUTI	CHTTO,^M
	MOUTI	CHTTO,^J
	RET
SUBTTL Auxiliary ITS Routines

IFN ITS,[

; GETJCL - Get JCL input
; W1/ <.OPTION var>

GETJCL:	SETZM	TTIBUF
	TLNE	W1,OPTCMD	; Don't do the .BREAK unless superior says so.
	 .BREAK	12,[5,,TTIBUF]
	SKIPN	TTIBUF
	 RET
	MOVE	W1,[440700,,TTIBUF] ; If have command string from superior,
	MOVEM	W1,TTIPNT	; set up to read from it.
	SETZ	CS,
GTJCL2:	ILDB	C,W1		; Count chars. in it.
	CAIE	C,^M
	 CAIN	C,0
	  CAIA
	   AOJA	CS,GTJCL2
	MOVEM	CS,TTICNT	; Save num. chars to read.
	AOS (P)			; Success return.
	RET


; TYLERR - Type last error

TYLERR:	.SUSET [.RBCHN,,C]
	SYSCAL STATUS,[C ? MOVEM ERRFIL+2]
	 ERRHLT
	.OPEN CHERR,ERRFIL
	 ERRHLT
TYLER2:	M.BIN CHERR,C
	CAIN C,^M
	 RET
	MOUTC CHTTO,C
	JRST TYLER2

ERRFIL:	SIXBIT/   ERR/
	3 ? 0


; LSTFIL - Print name of current file on LST ior TTY.

LSTFIL:	MOVE	0,$F6DEV(FP)
	CAMN	0,FSDSK
	 JRST	LSTFI1
	CALL	TTOSIX		; Print dev if not DSK.
	MOUTI	CHTTO,":
LSTFI1:	MOVE	0,$F6DIR(FP)	; Print sname
	CAMN	0,DEFDIR	; If different from user's.
	 JRST	LSTFI2
	CALL	TTOSIX
	MOUTI	CHTTO,73	; ";
LSTFI2:	MOVE	0,$F6FN1(FP)
	CALL	TTOSIX		; Print 1st name.
	MOUTI	CHTTO,40	; Space
	MOVE	0,$F6FN2(FP)
	JRST	TTOSIX		; , 2nd name.


SWDISN:	.OPEN	CHTTI,[SIXBIT/   NUL/]
	 ERRHLT
	.OPEN	CHTTO,[SIXBIT/  !NUL/]
	 ERRHLT
	.VALUE	[ASCIZ/:DISOWN :VK /]	; Give back tty.
	RET

; TYI - Read char from TTY, return in C

TYI:	.IOT CHTTI,C
	RET

; OPNRDW - Open filblk for reading, word mode
; OPNRDA - Open filblk for reading, ascii mode
; FP/ <ch>,,<fb addr>
; Skip returns if opened.

OPNRDW:	SAVE W1
	HRLZI W1,.UII
	JRST OPNRD2
OPNRDA:	SAVE W1
	HRLZI W1,.UAI	; Actually 0
OPNRD2:	HLR W1,FP
	SYSCAL OPEN,[W1 ? $F6DEV(FP) ? $F6FN1(FP) ? $F6FN2(FP) ? $F6DIR(FP)]
	 CAIA
	  AOS -1(P)
	REST W1
	RET

; RENMLO - Rename listing file
; W1/ <ch>

RENMLO:	SYSCAL RENMWO,[W1 ? LSTFB+$FNAME ? LSTFB+$FEXT]
	 JFCL
	RET

QUIT:	.BREAK 16,140000	; Die and echo ":KILL"
QUITX:	.BREAK 16,160000	; Die, announce "Finished" if not current

OPNHLP:	SYSCAL OPEN,[MOVEI CHIN1 ? ['DSK,,]
		['SRCCOM] ? [SIXBIT/>/] ? [SIXBIT/INFO/]]
	 RET
	AOS (P)
	RET
] ;IFN ITS
SUBTTL TNX - Auxiliary Routines

IFN TNX,[

; SEE20X - See if running under 20x or 10x

.SCALAR FLG20X		; -1 if 20x, 0 if 10x.
SEE20X:	SETZM FLG20X
	SYSCAL SYSGT,[['LOADTB]][B ? B]
	SKIPN B		; If LOADTB is not defined
	 SETOM FLG20X	; It must be a twenex
	RET

QUIT:
QUITX:

; Tell an MIT EXEC to flush this fork, like .BREAK 16,160000 on ITS
; This PRARG% code should be meaningless to (and ignored by) non-MIT EXECs.

IFDEF PRARG%,{		; I don't know if PRARG% exists on 10X or not

IFNDEF .PRKIL, .PRKIL==:2

	MOVE	1,[.PRAST,,.FHSLF]
	MOVEI	2,[.PRKIL,,0]
	MOVEI	3,1
	PRARG%		; Tell the EXEC that we have a death wish
	 ERJMP	.+1	; Oh well

};IFNDEF PRARG%

	HALTF
	JRST RESTRT

; OPNWR - Open filblk for writing, ascii mode
; FP/ <ch>,,<fb addr>

OPNWR:	SAVE W1
	SAVE W2
	MOVE W2,[070000,,OF%WR]	; Mode for char write
	CALL GETJFO		; Get output jfn
	 JRST OPNRD8
	JRST OPNRD5		; Rest is same as OPNRD.

; OPNRDW - Open filblk for reading, word mode
; OPNRDA - Open filblk for reading, ascii mode
; FP/ <ch>,,<fb addr>
; Skip returns if opened.

OPNRDW:	SAVE W1
	SAVE W2
	MOVE W2,[440000,,OF%RD]	; Mode for full-wd
	JRST OPNRD2
OPNRDA:	SAVE W1
	SAVE W2
	MOVE W2,[070000,,OF%RD]	; Mode for char
OPNRD2:	CALL GETJFI		; Get input jfn
	 JRST OPNRD8		; Failed
OPNRD5:	SYSCAL OPENF,[$FJFN(FP) ? W2]
	 JRST [	SYSCAL CLOSF,[$FJFN(FP)]
		 JFCL
		JRST OPNRD8]
	PUSH P,$FJFN(FP)
	HLRZ W1,FP
	POP P,JFNCHS(W1)
	CALL JFNSTB
	AOS -2(P)
OPNRD8:	REST W2
	REST W1
	RET

OPNHLP:	PUSH P,R1
	PUSH P,R2
	MOVSI R1,(GJ%OLD+GJ%SHT)
	HRROI R2,[HLPFIL]		; Filename defined as macro
	GTJFN
	 JRST OPNHL7		; Failed.
	HRRZS R1
	PUSH P,R1
	MOVE B,[070000,,OF%RD]
	OPENF
	 JRST [	POP P,R1
		CLOSF
		 JFCL
		JRST OPNHL7]
	POP P,R1
	MOVEM R1,JFNCHS+CHIN1
	AOS -2(P)
OPNHL7:	POP P,R2
	POP P,R1
	POPJ P,

; RENMLO - Rename listing file
; For moment, we don't hack temp filename, so this is a no-op.

RENMLO:	RET

TYI:	SAVE R1
TYI2:	PBIN
	CAIN R1,37
	 MOVEI R1,^M
	CAIN R1,^J	; Actually for 20x only
	 JRST TYI2
	MOVE C,R1
	REST R1
	RET

SWDISN:	TYPE "Cannot disown on this losing system; continuing."
	RET

LSTFIL:	PJRST TYPFB

; TYLERR - Type last error

TYLERR:	SKIPA A,[-1]
TERSTR:	 MOVE A,ERRCOD
	HRLI A,.FHSLF
	SYSCAL ERSTR,[[-1,,ERSTRB] ? A ? [-LERSTR,,]][A ? B ? B]
	 JRST TERST7	; undefined err #?
	 HALT		; destination bad?
	SETZ B,
	IDPB B,A	; Ensure ASCIZ.
	MOVEI T,ERSTRB
	PJRST TYPMSG
;	TYPR ERSTRB
;	POPJ P,
TERST7:	TYPE "Unknown error"
	POPJ P,

	LERSTR==80.
.VECTOR ERSTRB(<LERSTR+4>/5)


; RCHST - Set up filename string of input file as part of header output.
;	Also set length vars.

RCHST:	MOVEI A,CHIN1(FR)	; What a crock.
	MOVE A,JFNCHS(A)	; Get jfn for file
	PUSH P,A
	MOVE B,RCHSTP(FR)	; Get bp to dest buffer
	SYSCAL JFNS,[B ? A ? [111110,,1]][B]
	SETZ A,
	IDPB A,B		; Ensure asciz
	POP P,A			; Get JFN again
	SYSCAL SFPTR,[A ? [-1]][A]	; Set pointer to EOF
	 JFCL
	SYSCAL RFPTR,[A][A ? B]	; Get # words to read
	 JFCL
	MOVEM B,GWORDL(FR)	; Set length of file
	MOVEM B,GWORDC(FR)	; Also # of words left to read
	SYSCAL SFPTR,[A ? [0]]	; Point back to beg of file
	 JFCL
	RET

] ;IFN TNX
SUBTTL TNX JCL reading

; This routine is taken from MIDAS and so has some CCL hackery that
; currently is commented out, but at some future time might prove useful.
IFN TNX,[

; GETJCL - Read "JCL" - RSCAN buffer or nnnMID.TMP file (from CCL)

GETJCL:	SETZM TTIPNT
IFN 0,[
	SKIPE CCLFLG		; Started at CCL location?
	 JRST JCLIN5		; Yep, go snarf stuff specially.
]
	SKIPN FLG20X		; Is this Tenex?
	 JRST [	MOVEI R1,.PRIIN	; Yes
		BKJFN		; see what previous character was
		 RET		; *Gasp*
		PBIN
		CAIE R1,^_	; Tenex newline?
		 SETOM TTIPNT	; No, set flag saying "TTY but no prompt"
		RET]		; and skip the Twenex hackery below
	SETZ R1,		; If not, check RSCAN.
	RSCAN			; See if have anything in RSCAN buffer.
	 RET			; Huh?  Shouldn't happen, but ignore it.
	JUMPLE R1,APOPJ		; Also return if char cnt says nothing there.
	MOVNI R3,(R1)		; Aha, set up cnt for SIN
	HRROI R2,TTIBUF
	MOVEI R1,.PRIIN		; Now ready for business...
	SIN
	LDB R1,R2		; Now examine wages thereof
	CAIE R1,^J		; Last char LF?
	 JRST [	MOVEI R1,^J
		IDPB R1,R2	; If not, make it so.
		JRST .+1]

;;; Don't try to change the terminating character from LF to CR without
;;;   giving it careful thought.  GTJFN likes the filename to be terminated
;;;   with LF, and can be quite intransigent in its behavior.
;;; Instead, make the other scan routines accept LF. --WBA

	SETZ R1,
	IDPB R1,R2		; Must also ensure ASCIZ.
	MOVE B,[440700,,TTIBUF]	; If the rescan line starts with "RUN ", skip that.
IRPC X,,[RUN ]
	ILDB A,B
	TRZ A,40		; Convert to upper case
	CAIE A,"X
	 JRST JCLIN4
TERMIN
	CAIA
JCLIN4:	 MOVE B,[440700,,TTIBUF]	; Now flush the name of the file we were run from.
	ILDB A,B
	CAILE A,40
	 JRST .-2		; Flush until random ctl seen (space, ^M)
	CAIE A,40		; If it wasn't a space,
	 RET			; then forget about the whole thing.
JCLIN3:	MOVE C,B		; Now flush spaces.  Save last ptr for chars.
	ILDB A,B
	CAIN A,40
	 JRST JCLIN3
	CAIN A,^J		; And is first non-space something besides LF?
	 RET			; Bah, there wasn't anything in the JCL!!
	MOVEM C,TTIPNT		; Else save ptr to start of real goods.

	MOVE W1,C
	SETZ CS,
GTJCL2:	ILDB C,W1		; Count chars. in it.
	JUMPE C,GTJCL3		; Null? (Shouldn't happen, but...)
	CAIE C,^M		; CR or LF?
	 CAIN C,^J
	  CAIA			; Yes, must convert to null
	   AOJA CS,GTJCL2	; Otherwise just count it
	SETZ C,
	DPB C,W1
GTJCL3:	MOVEM CS,TTICNT		; Save num. chars to read.
	AOS (P)			; Success return.
	RET

IFN 0,[
	; TNX snarf of CCL file.  No such thing as tmpcor, so just
	; look for real file with appropriate name.
JCLIN5:	SETZM CCLFLG	; Want 0 in case abort out, will reset if win.
	GJINF		; Get job # in R3
	HRROI R1,CMBUF	; Use CMBUF to form filename string.
	MOVEI R2,(R3)
	MOVE R3,[NO%LFL+NO%ZRO+<3_18.>+10.]
	NOUT		; ship out job num in 3 digits, radix 10.
	 HALT
	HRROI R2,[ASCIZ /MID.TMP/]
	SETZ R3,
	SOUT		; Flesh out rest of filename string.
	SETZ R2,	; Make sure it's ASCIZ.
	BOUT
	MOVE R1,[GJ%OLD+GJ%SHT]	; Use short-form GTJFN
	HRROI R2,CMBUF		; and gobble name from CMBUF.
	GTJFN
	 RET			; If failed, forget it.
	MOVE R2,[070000,,OF%RD]	; Read 7-bit bytes
	OPENF
	 RET			; Bah
	HRROI R2,CMBUF		; Gobble stuff up.
	MOVEI R3,CMBFL*5	; Read until buffer full,
	MOVEI R4,^J		; or LF seen.
	SIN
	JUMPLE R3,APOPJ		; Forget it if too big for buffer!!

	MOVE R2,[440700,,CMBUF]	; Aha, we've got something, so set
	MOVEM R2,CMPTR		; pointer to slurped stuff.
	SETOM CCLFLG
	HRROI R2,UTIBUF		; Slurp rest into larger buffer,
	MOVNI R3,UTIBFL*5	; using count only.
	SIN
	JUMPGE R3,APOPJ		; Refuse to hack grossly large file.
	ADDI R3,UTIBFL*5
	JUMPLE R3,APOPJ		; if nothing read, need write nothing out.
	HRLI R1,(CO%NRJ)	; Don't release JFN,
	CLOSF			; but stop reading from file.
	 RET
	MOVE R2,[070000,,OF%WR]	; Now try to hack write access.
	OPENF
	 RET
	MOVE R2,R1		; Source becomes destination...
	HRROI R1,UTIBUF		; and UTIBUF becomes source,
	MOVNS R3		; for just as many bytes as were read.
	SOUT
	MOVEI R1,(R2)		; done, now just close file.
	CLOSF			; (this time, release JFN).
	 RET
	SETOM CCLMOR		; say that more CCL remains.
	RET
] ;IFN 0 FOR NOW

] ;IFN TNX
SUBTTL TENEX misc. Filename Routines, FS string storage

IFN TNX,[	.SEE FSDSK	; Part of this page is NOT conditionalized!!

; To handle filenames of ASCIZ strings instead of SIXBIT words, each
; word has instead a byte pointer to an ASCIZ string.  For purposes of
; easy comparison, all of these bp's point into FNBUF, and a routine
; (FNCHK) is provided which checks a just-stored string and returns a bp
; to either this string, if unique, or to a previously stored string if
; it is the same as the one just stored (which is then flushed).  Thus
; strings can be compared for equality simply by a comparison of their
; byte pointers.  While not necessary, strings are stored beginning on
; word boundaries for easier hacking.

	; <# files>*<avg # strings/file>*<avg # words/string>+<# wds for constants>
IFNDEF MAXIND,MAXIND==10	; # files
LFNBUF==<MAXIND+5>*5*3+20	; Enough to hold strings for all output files,
		; all translated files, and all .insrt files encountered.
		; Later a GC'er can be hacked up so that of the latter only
		; enough for the max .insrt level need be allocated.

FNBUF:	BLOCK LFNBUF

	; Macro to easily define constant strings for comparison purposes
DEFINE DEFSTR &STR&
440700,,%%FNLC
%%LSAV==.
LOC %%FNLC
ASCIZ STR
%%FNLC==.
LOC %%LSAV
TERMIN
	%%FNLC==FNBUF
] ; IFN TNX!!!

	; If not assembling for TENEX, the following strings become
	; simple SIXBIT values.  This makes it possible to write simple
	; code to work for both TENEX and non-TENEX without messy conditionals.

IFE TNX,[
DEFINE	DEFSTR &X&
.1STWD SIXBIT X!TERMIN
]

	; This stuff defines various BP's into FNBUF to
	; use for comparison purposes later.
FSDSK:	DEFSTR /DSK/
FSTTY:	DEFSTR /TTY/
FSNUL:	DEFSTR /NUL/
FSCMP:	DEFSTR /COMPARE/
FSCMPA:	DEFSTR /CMPARC/
FSFLGD:	DEFSTR /FLAGGD/

IFN ITS, FSDMF2:DEFSTR />/	; default merge FN2
IFN TNX, FSDMF2:DEFSTR //
IFN ITS, FVLOW:	DEFSTR /</
IFN TNX, FVLOW:	.GJLEG		; -2 for lowest version


IFN TNX,[
FNBBP:	440700,,FNBUF	; Points to beg of FNBUF (hook for dynamic alloc)
FNBEP:	FNBUF+LFNBUF-1	; Points to last wd in FNBUF (address, not BP)
FNBWP:	440700,,%%FNLC	; Write Pointer into FNBUF.
FNBLWP:	440700,,%%FNLC	; Last Write Pointer, points to beg of string being stored
EXPUNG %%FNLC

; NOTE - provided MIDAS never restarts, no initialization is necessary to
; start using FNCHK.  (Unless of course FNBUF is dynamically allocated someday)

; FNCHK - Check out just-stored filename.  Returns BP in A to ASCIZ string,
;	which will be "canonical" for comparison purposes.
;	Clobbers A,B,T,TT,AA
; FNCHKZ - Makes sure just-writ string is ASCIZ'd out before FNCHK'ing.

FNCHKZ:	MOVE B,FNBWP		; Get write ptr,
	LDB A,B			; see if last char was 0,
	JUMPE A,FNCHK0		; if so can skip one clobberage.
	SETZ A,
	IDPB A,B		; zero out bytes,
FNCHK0:	TLNE B,760000		; until at end of word.
	 JRST .-2
	ADD B,[<440700,,1>-<010700,,>]	; bump BP to point canonically at next.
	MOVEM B,FNBWP

FNCHK:	HRRZ B,FNBWP		; See if write ptr
	CAML B,FNBEP		; has hit end of FNBUF, and
	 ETF [ASCIZ /Filename buffer overflow/]	; barf horribly if so.
	MOVE A,FNBBP		; A  - bp to start of existing string
	MOVE AA,FNBLWP		; AA - bp to start of new string to store
FNCHK2:	MOVEI T,(A)		; T  - current addr being checked, existing str
	MOVEI TT,(AA)		; TT - current addr, new str
	CAIL T,(TT)		; If addrs are same, or overran somehow,
	 JRST [	MOVE A,AA	; didn't find any match, accept new string.
		MOVE B,FNBWP
		MOVEM B,FNBLWP	; Set up new last-write-ptr
		POPJ P,]
FNCHK3:	MOVE B,(T)
	CAMN B,(TT)		; Compare strings, full word swoops.
	 JRST [	TRNE B,377			; equal, last char zero?
		 AOJA T,[AOJA TT,FNCHK3]	; no, continue for whole string
		; Found it!  Flush just-stored string, don't want duplicate.
		MOVEM AA,FNBWP		; Clobber write ptr to previous value.
		POPJ P,]
	; Not equal, move to next string to compare
	MOVEI B,377	; Check for ASCIZ,
	TDNE B,(T)	; moving to end of current string
	 AOJA T,.-1
	HRRI A,1(T)	; and updating BP to point at new string.
	JRST FNCHK2	; (T gets pointed there too at FNCHK2).
] ;IFN TNX
IFN TNX,[

; TYPFB - Type out FB pointed to by F

TYPFB:	SKIPE B,$FDEV(F)	; First, device name?
	 JRST [	PUSHJ P,TYPZ
		MOVEI A,":
		PUSHJ P,TYOERR
		JRST .+1]
	SKIPE B,$FDIR(F)	; Directory?
	 JRST [	MOVEI A,"<
		PUSHJ P,TYOERR
		PUSHJ P,TYPZ
		MOVEI A,">
		PUSHJ P,TYOERR
		JRST .+1]
	SKIPE B,$FNAME(F)
	 PUSHJ P,TYPZ
	MOVEI A,".
	PUSHJ P,TYOERR
	SKIPE B,$FEXT(F)
	 PUSHJ P,TYPZ
	MOVEI A,".		; 20X uses "." to set off version,
	SKIPN FLG20X		; but 10X uses ";".
	 MOVEI A,";
	PUSHJ P,TYOERR
	HRRE A,$FVERS(F)
	JUMPL A,[MOVM B,A	; Is possible to have -1, -2, etc.
		MOVEI A,"-
		PUSHJ P,TYOERR
		MOVE A,B
		JRST .+1]
	PUSHJ P,DPNT		; Version # output in decimal.
	SKIPE $FTEMP(F)
	 TYPE ";T"		; May be temporary.
	SKIPE B,$FPROT(F)
	 JRST [	TYPE ";P"
		PUSHJ P,TYPZ
		JRST .+1]
	SKIPE B,$FACCT(F)
	 JRST [	TYPE ";A"
		PUSHJ P,TYPZ
		JRST .+1]
	POPJ P,

	; Takes BP in B, outputs to TYOERR until zero byte seen.
TYPZ:	CAIA
	 PUSHJ P,TYOERR
	ILDB A,B
	JUMPN A,TYPZ+1
	POPJ P,

DPNT:	MOVE 0,A	; This entry pt for code borrowed from midas
	PJRST TTODEC

TYOERR:	MOVE C,A	; Ditto.
	PJRST TYO
] ; IFN TNX
IFN TNX,[
; JFNSTR - Get filename strings for active JFN.
;	A/ active JFN
;	F/ addr of filename block to clobber.
; JFNSTB - Same, but ignores A and assumes JFN is already stored in block.
;	Clobbers A,C

JFNSTB:	SKIPA A,$FJFN(F)	; JFNSTB gets the JFN from block itself.
JFNSTR:	 MOVEM A,$FJFN(F)	; whereas JFNSTR stores it there...
	MOVSI D,-NJSTRF		; Set up aobjn thru table.
JFNST2:	PUSH P,T
	SYSCAL JFNS,[FNBWP ? $FJFN(F) ? JSTRFX+1(D)][FNBWP]
	POP P,T
	MOVE C,JSTRFX(D)	; Now get index to place it belongs in file block,
	CAIN C,$FVERS		; and check for this, because
	 JRST [	MOVE A,FNBLWP	; it wants to be a number, not a string.
		MOVEM A,FNBWP	; Zap write pointer back to forget string,
		PUSHJ P,CVSDEC	; and quickly convert before anything clobbers it.
		JRST JFNST4]	; Skip over the FNCHKZ call.
	
	MOVE A,FNBLWP		; Get previous write ptr
	CAMN A,FNBWP		; and compare to make sure something written.
	 TDZA A,A		; If nothing, store zero.
	  PUSHJ P,FNCHKZ	; Fix up string, and get BP to it.
JFNST4:	ADDI C,(F)		; make it an addr, and
	MOVEM A,(C)		; store BP. (or value, for $FVERS)
	ADDI D,1
	AOBJN D,JFNST2
	POPJ P,

	; Filblk idx, output format wd for JFNS call
JSTRFX:	$FDEV	? 100000,,
	$FDIR	? 010000,,
	$FNAME	? 001000,,
	$FEXT	? 000100,,
	$FVERS	? 000010,,
NJSTRF==<.-JSTRFX>/2

; CVSDEC - Converts ASCIZ string to decimal, assumes only digits seen, with
;	a possible minus-sign prefix (ie negative # is allowed).
;	A/ BP to ASCIZ
;	Returns value in A, clobbers nothing else.

CVSDEC:	PUSH P,B
	PUSH P,C
	MOVE C,A
	SETZ A,
	ILDB B,C		; Get 1st char
	JUMPE B,CVSDC9
	CAIN B,"-		; Minus sign?
	 JRST [	MOVE A,C	; Yes, parse rest of number
		PUSHJ P,CVSDEC
		MOVNS A		; and negate result.
		JRST CVSDC9]
CVSDC2:	IMULI A,10.
	ADDI A,-"0(B)
	ILDB B,C
	JUMPN B,CVSDC2
CVSDC9:	POP P,C
	POP P,B
	POPJ P,

; CVSSIX - Converts ASCIZ string to SIXBIT word.
;	A/ BP to ASCIZ string,
;	Returns SIXBIT word in A.  Clobbers nothing else.

CVSSIX:	PUSH P,B
	PUSH P,C
	PUSH P,D
	MOVE D,A
	SETZ A,
	MOVE B,[440600,,A]
	JRST CVSSX3
CVSSX2:	CAIL C,140
	 SUBI C,40		; Uppercase force
	SUBI C,40		; cvt to 6bit
	IDPB C,B		; deposit
	TLNN B,770000		; If BP at end of word,
	 JRST CVSSX5		; leave loop.
CVSSX3:	ILDB C,D
	JUMPN C,CVSSX2
CVSSX5:	POP P,D
	POP P,C
	POP P,B
	POPJ P,

] ; IFN TNX
IFN TNX,[
	; Get a JFN for current FILBLK (in F) and stick it into $FJFN(F).
	; A should hold flags in LH to use in 1st wd of block.
	; GETJFI - sets usual flags for input
	; GETJFO - sets " " output
	; GETJFN - takes whatever A holds.

GETJFO:	SKIPA A,[GJ%FOU+GJ%NEW]	; If hacking output, ask for new version.
GETJFI:	 MOVSI A,(GJ%OLD)	; If hacking input, file must exist.
GETJFN:	PUSHJ P,TFMAP	; Stick filblk stuff into GTJFN scratch block.
	PUSH P,R1
	PUSH P,R2
	MOVEI R1,GTJBLK
	SETZ R2,
	GTJFN
	 JRST [	MOVEM R1,ERRCOD	; failure, save error code.
		JRST GETJF5]
	HRRM R1,$FJFN(F)	; Win, save JFN.
	AOS -2(P)
GETJF5:	POP P,R2	; Can't return in ACs cuz don't know what R1 etc are,
	POP P,R1	; and might clobber them here.
	POPJ P,
.SCALAR ERRCOD

; TFMAP - Map Tenex filenames from filblk pointed to by F into
;	standard scratch block for long-form GTJFN.
;	A/ <flags>,,0	; flags will go into LH of .GJGEN.
;	Clobbers only A.

TFMAP:	HRR A,$FVERS(F)		; Put version # in RH
	SKIPE $FTEMP(F)		; If asking for temp file,
	 TLO A,(GJ%TMP)		; set appropriate flag.
	MOVEM A,GTJBLK+.GJGEN
IRP FROM,,[$FDEV,$FDIR,$FNAME,$FEXT,$FPROT,$FACCT,$FJFN]TO,,[.GJDEV,.GJDIR,.GJNAM,.GJEXT,.GJPRO,.GJACT,.GJJFN]
	MOVE A,FROM(F)
	MOVEM A,GTJBLK+TO
TERMIN
	MOVE A,[.NULIO,,.NULIO]
	MOVEM A,GTJBLK+.GJSRC	; Don't hack I/O in gtjfn.
	POPJ P,

.VECTOR GTJBLK(10.)	; Need exactly this many wds for non-extended long call
] ;IFN TNX
SUBTTL TNX - SUPPORT FOR I/O MACROS

IFN TNX,[
	; TAKES -1(P)/ <JFN>, (P)/ <CHAR> AND OUTPUTS
TOUTC:	EXCH R1,-1(P)	; GET JFN
	EXCH R2,(P)	; AND CHAR
	BOUT		; OUT IT GOES.
	REST R2		; RESTORE ACS AND RETURN
	REST R1
	RET

; TINC - TAKES -1(P)/ <JFN>, (P)/ <LOC> AND INPUTS FROM CHAN TO LOC

TINC:	EXCH R1,-1(P)		; GET JFN
	PUSH P,R2
	BIN
	 ERJMP [HRROI R2,^C	; EOF (20X ONLY)
		JRST .+1]
	MOVEM R2,@-1(P)		; STORE BYTE IN DESIRED LOC
	POP P,R2
	SUB P,[1,,1]		; FLUSH LOC FROM STACK
	POP P,R1
	RET

; TINS - INPUT STRING
; TAKES T/ ADDR--> <JFN ADDR> ? <BP ADDR> ? <CNT ADDR>

TINS:	SAVE R1
	SAVE R2
	SAVE R3
	MOVE R1,@(T)		; GET JFN
	MOVE R2,@1(T)		; AND BP
	MOVN R3,@2(T)		; AND -COUNT
	SIN
	 ERJMP .+1		; ASSUME EOF AND PTRS UPDATED PROPERLY.
				; THIS ONLY WINS ON 20X!
	MOVNM R3,@2(T)		; RESTORE NEW CNT
	MOVEM R2,@1(T)		; AND NEW BP
	REST R3
	REST R2
	REST R1
	RET
] ;IFN TNX
PATCH:	BLOCK 100

CONSTA				;ITS

BEGP::			;BEGINNING OF STORAGE ZEROED AT INIT.
JUNK:	0
PPSET:	BLOCK	LPDL	;PUSH DOWN LIST STORAGE
	BLOCK	20


FLUSHP:	BLOCK	1	;P SAVED FOR RESTORATION IF A --MORE-- IS FLUSHED.
			;0 => NOT POSSIBLE TO FLUSH NOW.

ERRCNT:	BLOCK	1	;DIFFERENCES COUNTER (0 MEANS NO DIFFERENCES)

LBUFP:
LBUFP1::BLOCK	1	;POINTER TO BEGINNING OF LINE STORAGE FOR FILE #1
LBUFP2:	BLOCK	1	;DITTO FILE #2
LBUFP3:	BLOCK 	1

NLINES:
NLINE1::BLOCK	1	;# OF LINES OF FILE 1 NOW IN CORE
NLINE2:	BLOCK	1
NLINE3:	BLOCK	1

EOFFL1:	BLOCK	1	;-1 => LAST NEXTLN ON FILE 1 WAS NO-OP'ED DUE TO EOF.
EOFFL2:	BLOCK	1
EOFFL3:	BLOCK	1

NCOMP1:	BLOCK	1	;HOW MANY LINES DIFF IS CONSIDERING FROM FILE 1
NCOMP2:	BLOCK	1
NCOMP3:	BLOCK	1

HBUF1:	BLOCK	WPL	;HOLDS TITLE FROM FIRST FILE
HBUF2:	BLOCK	WPL	;FROM SECOND FILE
HBUF3:	BLOCK	WPL
IFN ITS,[
RCHSTB:	BLOCK 10.	;BLOCK WRITTEN INTO BY .RCHST
		;WORD 0 RH DEV NAME, LH IF NON-ZERO THEN DEVICE NAME TO PRINT
		;WRD 1 FNAM1
		;WRD 2 FNAM2
		;WRD 3 SYSTEM NAME
		;WRD 4 NON-NEGATIVE => .ACCESS POINTER
		;REST ROOM FOR EXPANSION OF SYSTEM CALL
]
PAGNUM:	BLOCK 3		;PAGE NUMBERS FOR THE TWO FILES, AT THE LEVEL OF RDLINE.
			;THAT IS, THE PAGE # THAT THE NEXT LINE READ WILL START ON.
LINNUM:	BLOCK 3		;LINE NUMBERS FOR THE FILES, AT RDLINE LEVEL.
CHRNUM:	BLOCK 3		;# OF CHARS RDLINE HAS READ SO FAR FROM EACH FILE.
LLABEL:	BLOCK 3*LNLBLN	;LNLBLN (4) WDS/FILE, 0 OR ASCIZ OF LAST LABEL AND A COLON.
MRGOUT:	BLOCK 3		;/M NON-ZERO MEANS OUTPUT TO MERGE FILE ALL
			;/M LINES BEFORE WIPING OUT IN "MOVEUP" ROUTINE
			;/M ALWAYS 0 IF /M NOT TYPED
LPHONY:	BLOCK 1		; -1 IFF LAST LINE OUTPUT BY MOVEUP DIDN'T END IN A CRLF,
			;EXCEPT 1 => ENDED IN JUST A CR.  0 => ENDED IN A CRLF.
MRGLEN==2		;/M LEAVE ROOM FOR 2 WORDS (10 CHAR) OF MERGE COMMAND.
MRGCOM:	BLOCK	MRGLEN	;/M BUFFER FOR MERGE COMMAND
	BLOCK	1	;/M GUARANTEE A NULL TERMINATION
MRGBYT:	BLOCK	1	;/M BYTE POINTER TO MERGE COMMAND STRING
MRGUFL:	BLOCK 1		;-1 => OUTPUTTING DIFFERENCES IN /F MODE; FROM MRGU1 TO MOVEUP.

OUTTTY:	BLOCK 1		;-1 => CHOUT IS OUTPUTTING TO A TTY.
IFN ITS,[
TTYSTS:	BLOCK 1		;SAVED TTYSET OF CHANNEL CHOUT, FOR RESTORATION AT RELDEV.
TTYST1:	BLOCK 1
TTYST2:	BLOCK 1
]

NUMTMP:	BLOCK	1	;TEMP FOR NUMLIN
TEMPF1:	BLOCK	1	;TEMP FOR F1
TEMPF2:	BLOCK	1	;TEMP FOR F2
TEMPF3:	BLOCK	1
RFILC:	0		;TEMP. FOR RFILE.
LSTEXP:	0		;-1 => A BACKARROW WAS PRESENT IN COMMAND STRING.


FILBF1:	BLOCK	FILBFL	;FILE 1 BUFFER.
FILBE1=.-1
	ASCIC//
FILPT1:	0		;FILE 1 BUFFER PTR.
FILEP1:	0		;FILE 1 B.P. TO THE ^C AFTERWHAT WAS READ IN.

FILBF2:	BLOCK	FILBFL	;FILE 2 BUFFER,
FILBE2=.-1
	ASCIC//
FILPT2:	0		;FILE 2 BUFFER PTR.
FILEP2:	0

FILBF3:	BLOCK	FILBFL	;FILE 3 BUFFER.
FILBE3=.-1
	ASCIC//
FILPT3:	0		;FILE 3 BUFFER PTR.
FILEP3:	0		;FILE 3 B.P. TO THE ^C.

MRGBF:	BLOCK MRGBSZ/5	;BUFFER FOR MERGE OUTPUT
MRGBP:	0		;B.P. FOR STUFFING BUFFER.
MRGCT:	0		;# CHARS SPACE LEFT IN BUFFER.

PNTDBF:	BLOCK 12./5+1	;BUFFER FOR DECIMAL PRINT.

ENDP::		;END OF STORAGE THAT'S ZEROED BEFORE EVERY COMMAND.

DEFDIR:	0		;INITIAL (DEFAULT) DIRECTORY.

CMDFIL:	0		;-1 => READING FROM THE FILE OPEN ON CHCMD
CMDIS:	0		;DEFAULT INPUT DIR WHILE EXECUTING COMMAND FILE
CMDID:	0		;DEFAULT INPUT DEVICE
CMDOS:	0		;DEFAULT OUTPUT DIR
CMDOD:	0		;DEFAULT OUTPUT DEVICE

CTLCF:	0		;IF NOT 0, COMMIT SUICIDE AFTER FINISHING COMMAND.

COLMAX:	<-1>_-1		;/M MAX COLUMN TYPED OUT ON /M DIALOG
			;/M CHANGED BY C COMMAND
LINMAX:	<-1>_-1		;/M MAX LINS TO TYPE OUT ON /M
NUMLIN:	MATCH-1		;# LINES FOR A MATCH

SEG1:	10000		;START OF SEGMENT FOR FILE 1 LINES
SEG2:	201000		;START OF SEGMENT FOR FILE 2 LINES
SEG3:	401000		;START OF SEGMENT FOR FILE 3 LINES

TTIBUF:	BLOCK	30	;COMMAND BUFFER.
TTIBFL==.-TTIBUF
TTIPNT:	0		;BYTE POINTER INTO TTIBUF.
TTICNT:	0		;NUM. UNREAD CHARS LEFT IN TTIBUF.

CONSTANTS

FOO:
VARIABLES

	-1
ENDCOR:

END BEG