; -*-MIDAS-*-

.SYMTAB 4999.,3000.
TITLE SRCCOM

;;; THIS IS PHIL BUDNE'S VERSION W/ COMND JSYS
;;; WAS ONCE MC: SYSENG; SRCCOM 125

; STUFF TO DO:
;  NATIVE-20 MERGE MODE PROMPT (INPUT TEXT BROKEN?)
;  DUCUMENT IN ISRCCOM.INFO FILE (MORE THAN JUST HEADER)
;  CHECK TENEX & ITS ASSEMBLY
;  NATIVE EXECUTE COMMAND STRINGS?? (;;ISRCCOM COMMAND ;; <FOO>)
;  PMAP windows for /BINARY too. (didn't I do this?)
;  PMAP WINDOWS FOR TEXT!!!
;  MULTIPLE PAGE PMAP WINDOWS!!
;  DUMP MODE UNDER TOPS-10?
;  MORE VERBOSE HEADER? (CREATION/WRITE DATE???)

; STUFF TO MAKE WORK: ((MAYBE) NEVER DID UNDER TNX)
; /@, ARCHIVE, 3WAY

;;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.
;MANGLED FOR COMND JSYS BY BUDD, MAR '83. (My first COMND program)
;TOPS-10 (7.02 ONLY) ALSO BY BUDD@DEC

IF1 [
IFE .OSMIDAS-SIXBIT/ITS/,ITS==1
IFE .OSMIDAS-SIXBIT/TENEX/,TNX==<10X==1>
IFE .OSMIDAS-SIXBIT/TWENEX/,TNX==<20X==1>
IFE .OSMIDAS-SIXBIT/DEC/,DEC==1
IFNDEF ITS,ITS==0
IFNDEF TNX,TNX==0
IFNDEF 10X,10X==0
IFNDEF 20X,20X==0
IFNDEF DEC,DEC==0
IFNDEF KLP,KLP==20X\DEC		; DON'T RUN IN THE AC'S ON A KL
IFN TNX, .DECSAVE		; BYPASS RINK ROADING
IFN ITS+TNX+DEC-1,.FATAL MORE THAN ONE SYSTEM SPECIFIED
IFE ITS+TNX+DEC+10X+20X,.FATAL NO SYSTEM SPECIFIED
IFN TNX,IFE 10X+20X,.FATAL TNX BUT BUT 10X OR 20X
] ;IF1

IFN 20X,[
IFNDEF RSMAP,RSMAP=JSYS 610
DEFINE HLPFIL			; SPECIFIES LOC OF HELP FILE
ASCIZ "INFO:ISRCCOM.INFO"!TERMIN
] ;IFN 20X

IFN 10X,[
DEFINE HLPFIL			; SPECIFIES LOC OF HELP FILE
ASCIZ "<INFO>SRCCOM.INFO"!TERMIN
] ;IFN 10X

;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	;/$
NUMCHN==15
;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\DEC, 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

;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.
IFNDEF FILBFL,FILBFL==5000	;**** TEST **** LENGTH OF INPUT FILE BUFFERS.
MRGBSZ==FILBFL*5		;MERGE OUTPUT BUFFER LENGTH IN CHARS.

; BUFFER SEGMENT BASE ADDRESSES
SEG1A=101000			;START OF SEGMENT FOR FILE 1 LINES
SEG2A=301000			;START OF SEGMENT FOR FILE 2 LINES
SEG3A=501000			;START OF SEGMENT FOR FILE 3 LINES


;/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=JUMPA 11,
IFN ITS,ERRHLT==.LOSE

IFE ITS,[
DEFINE ERRHLT
	HALT .
TERMIN
] ;IFE ITS

;MACROS

IFN ITS,[
DEFINE SYSCAL A,B
	.CALL [	SETZ ? SIXBIT/A/ ? B ((SETZ))]
TERMIN
]
IFN TNX, .INSRT XJSYS
IFN DEC,[
; SOME NEW UUOSYM-BOLS
UU.LBF==2000,,		; USE LARGE DISK BUFFERS ON OPEN
.PTSFD==3		; SFD OFFSET IN PATH. BLOCK
FO.ASC==200000,,	; ASSIGN A CHANNEL FOR FILOP.
FO.CHN==000777,,	; CHANNEL IN FILOP. BLOCK
.FOINP==17		; FILOP. IN UUO
.FOOUT==20		; FILOP. OUT UUO
.FOREL==23		; FILOP. RELEASE UUO
.FOFIL==33		; FILOP. RETURN FILE NAME BLOCK
 .FOFSP==10		; OFFSET IN FILOP. BLOCK FOR NAME PTR
  .FOFND==0		; OFFSET IN NAME BLOCK FOR NODE (RESERVED)
  .FOFDV==1		; DEVICE
  .FOFFN==2		; FILE NAME
  .FOFEX==3		; EXTENSION
  .FOFPP==4		; PPN
  .FOFSF==5		; FIRST SFD
  .FOFMX==.FOFSP+<.PTMAX-.PTSFD-1>
] ;DEC

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

DEFINE M.STAT STATE
	.SUSET [.SWHO2,,[SIXBIT /STATE/]]
TERMIN
] ;IFN ITS

IFN TNX,[
DEFINE M.CLS CH		; CLOSE CHAN
	MOVEI T, CH
	CALL M$CLS
TERMIN

DEFINE M.MVCH CH1,CH2	; MOVE CHANNEL FROM CH1 TO CH2
	SAVE R1
	SETZ R1,
	EXCH R1,JFNCHS+CH1
	EXCH R1,JFNCHS+CH2
	CAIL R1, .FHSLF
	 ERRHLT
	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 (TNX)
CALL [	PUSH P,JFNCHS+CH
	PUSH P,[LOC]
	JRST TINC]
TERMIN

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

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

DEFINE M.STAT STATE
	PUSH P, [SIXBIT /STATE/]
	POP P, STSWRD
TERMIN
] ;IFN TNX

IFN DEC,[
DEFINE M.CLS CH			; CLOSE CHAN (DEC) CHAN 0 NEVER USED
	SKIPLE T,JFNCHS+CH
	 CALL M$CLS
	SETZM JFNCHS+CH
TERMIN

DEFINE M.MVCH CH1,CH2		; MOVE CHANNEL FROM CH1 TO CH2 (DEC)
	SETZ T,
	EXCH T,JFNCHS+CH1
	EXCH T,JFNCHS+CH2
	CAILE T,0
	 CALL M$CLS
TERMIN

DEFINE MOUTC CH,?LOC		; OUTPUT BYTE AT LOC (DEC)
CALL [	PUSH P,[CH]
	PUSH P,LOC
	PJRST TOUTC]
TERMIN

DEFINE M.BIN CH,LOC		; INPUT BYTE TO LOC (DEC)
CALL [	PUSH P,[CH]
	PUSH P,[LOC]
	JRST TINC]
TERMIN

DEFINE M.SOUT CH,BPA,CNTA	; OUTPUT STRING (DEC)
	PUSH P,[CH]
	PUSH P,BPA
	PUSH P,CNTA
	CALL M$SOUT
	POP P,CNTA
	POP P,BPA
	POP P,(P)
TERMIN

DEFINE M.SIN CH,BPA,CNTA	; INPUT STRING (DEC)
	PUSH P,R2
	PUSH P,[CH]
	PUSH P,BPA
	PUSH P,CNTA
	CALL M$SIN
	POP P,CNTA
	POP P,BPA
	POP P,(P)
	POP P,R2
TERMIN

DEFINE M.STAT STATE
TERMIN
] ;IFN DEC

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.

DEFINE DS NAME,SIZE=1
NAME==:.%.
.%.==.%.+SIZE
TERMIN
.%.==0

IFN ITS\DEC,[
; Lots of crocks depend on the exact order of these 4 items.
IFN DEC,[
DS	$FNODE			; SIXBIT NODE (RESERVED)
]
DS	$F6DEV			; SIXBIT Device name
DS	$F6FN1			; SIXBIT Filename (on ITS, FN1)
DS	$F6FN2			; SIXBIT Extension (on ITS, FN2)
DS	$F6DIR			; SIXBIT Directory (may be numerical PPN)
IFN DEC,[
DS	$FSFD,6			; MAX SFDS +1 (MUST BE AFTER DIR)
]
$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.
DS	$FDEV		; Device name
DS	$FDIR		; Directory name
DS	$FNAME		; File name (i.e. main name)
DS	$FEXT		; File type (or extension)
DS	$FVERS		; File version (or generation).  NUMBER, not string.
DS	$FTEMP		; -1 => File is a temporary file.
DS	$FACCT		; Account string
DS	$FPROT		; Protection string
DS	$FJFN		; JFN for file (may be <desired JFN>,,<temp JFN>)
]
L$FBLK==.%.	; Length of a FILBLK.
.VECTOR	INFB (L$FBLK), LSTFB

IFN TNX\DEC,[
.VECTOR JFNCHS (NUMCHN)		; INDEXED BY CHAN #, HOLDS JFNS/DEC CHANS
]
IFN DEC,[
.VECTOR CHNHDR (NUMCHN*3)	; PER CHANNEL BUFFER HEADERS
]

IFN TNX,[
LEVTAB:	PC1 ? PC2 ? PC3		; POINTERS TO INTERUPT PC'S
.SCALAR PC1, PC2, PC3
.VECTOR CHNTAB(36.)

IFN 20X,[
DEFINE CMD STR,DATA,FLGS=0
IFE FLGS,[
 IFB [DATA][ [ASCIZ |STR|],,<.!STR> ]
 .ELSE [ [ASCIZ |STR|],,DATA ] ]
.ELSE [
 IFSE [DATA][ [CM%FW\FLGS ? ASCIZ |STR|],,<.!STR> ]
 .ELSE [ [CM%FW\FLGS ? ASCIZ |STR|],,DATA]]
TERMIN

DEFINE NOISE TEXT
	HRROI A, [ASCIZ ~TEXT~]
	CALL XNOISE
TERMIN

DEFINE IFILE TEXT
	HRROI A, [ASCIZ ~TEXT~]
	CALL XIFILE
TERMIN

DEFINE OFILE TEXT
	HRROI A, [ASCIZ ~TEXT~]
	CALL XOFILE
TERMIN

DEFINE FILE TEXT
	HRROI A, [ASCIZ ~TEXT~]
	CALL XFILE
TERMIN

DEFINE FLD (VAL,MASK)
<.DPB <VAL>,<.BP <MASK>,>,0,>!TERMIN

DEFINE FLDDB. TYP=0,FLGS=0,DATA=0,HLPM,DEFM,LST=0
 MASK%%==IFNB [HLPM][CM%HPP\]<<TYP>_27.>\<FLGS>
 IFB [DEFM][MASK%%\<0,,<LST>>] .ELSE CM%DPP\MASK%%\<0,,<LST>>
 DATA
 IFB [HLPM][0] .ELSE [-1,,[ASCIZ HLPM]]
 IFB [DEFM][0] .ELSE [-1,,[ASCIZ DEFM]]
 0
TERMIN
] ;IFN 20X
] ;IFN TNX

;SRCCOM STARTS HERE

IFN TNX,[
EVEC:	JRST BEG
	JRST BEG
	400000+.FVERS
]

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
	MOVEM W1,JFNCHS+CHOUT

	MOVEI	R1, .FHSLF
	MOVE	R2, [LEVTAB,,CHNTAB]
	SIR
	EIR
	RUNTM			; FORK RUNTIME
	MOVEM	R1, RUNSAV	; SAVE FORK RUNTIME
	MOVEM	R3, CONSAV	; SAVE CONSOLE TIME
	MOVE W1, [1,,CTRLY]	; LEVEL,,ADDR
	MOVEM W1, CHNTAB+0	; FOR CHAN 0
	MOVE W1, [1,,CTRLE]	; LEVEL,,ADDR
	MOVEM W1, CHNTAB+1	; FOR CHAN 1
	MOVSI R1, .TICCY	; CTRL/Y ON CHAN 0
	ATI
	MOVE R1, [.TICCE,,1]	; CTRL/E ON CHAN 1
	ATI

	CALL UNMAP
.SCALAR RUNSAV, CONSAV		; SAVED RUN & CONSOLE TIMES
] ;TNX
IFN DEC,[
	RESET			; DOES GOOD THINGS
	MOVEI W1, VECTOR	; ADDR OF PSI VECTOR
	PIINI. W1,		; SET IT
	 ERRHLT			; PERHAPS NOT!
	MOVEI W1, IMRTRP
	MOVEM W1, VECTOR+.PSVNP	; SAVE NEW PC
	SETZM VECTOR+.PSVFL	; CLEAR ALL FLAGS
	MOVE  W1, [PS.FON\PS.FAC+[.PCIMR ? 0 ? 0]] ; ON, ADD IMR
	PISYS. W1,		; SET IMR CONDITION
	 ERRHLT	

	HRLZ W1, .JBFF		;GET LAST USED WORD
	HRR W1, .JBREL		;AND LAST WORD OF CORE
	MOVEM W1, JOBFF		;SAVE FOR CUTBACKS

.VECTOR	VECTOR(4)		; PISYS VECTOR
] ;DEC
	SETZM CTLCF		; STAY AROUND, UNLESS WE HAVE JCL
	CALL GETJCL		; LOOK FOR JCL, SKIP IF FOUND
	 CAIA			; NONE
	  JRST RESTR1		; HAVE SOME, GO EXECUTE.

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

RESTRT:	SETZM TTIBUF
	MOVEI W1, MATCH-1	; DEFAULT NUMLIN
	SKIPN CMDFIL		; IN AN EXECUTE?
	 MOVEM W1, NUMLIN	; NO, RESET IT
IFN 20X,[
	MOVE W1, [.PRIIN,,.PRIOU]
	MOVEM W1, CMJFN
]
RESTR1:	MOVE P,[-LPDL,,PPSET-1]	;SET UP PUSH DOWN LIST
IFN ITS,[
	.SUSET [.SWHO1,,[0]]	;CLEAR USER-SPEC'D WHOLINE FIELDS.
	.SUSET [.SMEMT,,[ENDCOR]]
]
	SETZB FR,BEGP		;THIS ZERO WILL BE "BLT"ED TO CLEAR CORE
	MOVE 0,[BEGP,,BEGP+1]
	BLT ENDP-1
IFN TNX,[
	MOVEI R1, .FHSLF	; US
	MOVSI R2, (SETZ)	; ACTIVATE CHAN 0
	AIC
	SKIPE CMDFIL		;IN AN EXECUTE?
	 JRST RESTR2		;YES, KEEP DYNAMIC DATA
	MOVE 0,[FNZER,,FNZER+1]	; NO, CLEAR STRING SPACE
	SETZM FNZER		; ONLY BLT DYNAMIC DATA
	BLT 0,FNBUF+LFNBUF-1
	MOVSI R2, (MOVE)	; CHAN 1
	DIC			; DEACTIVATE
];TNX
IFN DEC,[
	SKIPE CMDFIL		; EXECUTING A COMMAND?
	 JRST RESTR2		; YES, LEAVE CORE ALONE
	SETOM JFNCHS+CHTTI
	SETOM JFNCHS+CHTTO
	SETOM JFNCHS+CHOUT
	MOVE W1, JOBFF		; GET ORIGINAL CORE
	HLRZM W1, .JBFF		; RESTORE LAST USED WORD
	MOVEI W1, (W1)		; AND LAST WORD OF CORE
	CORE W1,		; CUTBACK
	 JFCL			; HO HUM
] ;DEC
RESTR2:	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

IFN 20X,[
	SKIPN CMDFIL		; IN AN EXECUTE FILE?
	JRST TOP		; NO, GO DO COMND SCANNER
]
	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,"=
	 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.
IFN 20X,[
	SKIPG	TTICNT
	 SETZM	INFB+$FJFN	;BLAT OLDER JFN
]
	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\DEC,[
	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::
] ;TNX\DEC

;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.
]
	M.STAT HEADER
IFN TNX,[
	MOVEI R1, .FHSLF	; THIS FORK
	MOVSI R2, (MOVE)	; CHAN 1
	AIC			; ACTIVATE!
]
	SKIPE 3WAY		;3-WAY MERGES HAVE A SPECIAL MAIN LOOP.
	 JRST 3LOOP
	TLNE FR,FLMERG
	 JRST ENTERX
	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

IFE 20X,[
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
]
IFN 20X,[
	MOVEI W1,[ASCIZ 'COMPARE']
	TLNE FR,FLARCH
	 MOVEI W1,[ASCIZ 'ARCHIVE']
	CALL PRINT		; PRINT COMMAND TYPE
				; MERGE & FLAG DON'T GET HEADERS

IRPS X,,FLALL FLCASE FLENDL FLCMNT FLLABL FLSPAC FLFNUM FLXLBL,Y,,ALL CASE ENDLINE NOCOMMENTS LABEL SPACE WHICH XLABEL
	MOVEI W1,[ASCIZ * /Y*]
	TLNE FR,X
	 CALL PRINT
TERMIN
]
IFE 20X,MOVEI W1,[ASCIZ " /#"]
IFN 20X,MOVEI W1,[ASCIZ ' /BIN']
	SKIPE FVBIN
	 CALL PRINT
IFE 20X,MOVEI W1,[ASCIZ " /$"]
IFN 20X,MOVEI W1,[ASCIZ ' /SAVE']
	SKIPE FSBIN
	 CALL PRINT
	MOVE T, NUMLIN
	CAIN T, MATCH-1		; DEFAULT?
	 JRST CMD2.1		; YES, FORGET TO PRINT NUMLIN
IFE 20X,MOVEI W1,[ASCIZ * /*]
IFN 20X,MOVEI W1,[ASCIZ ' /MATCH:']
	CALL PRINT
	MOVE T,NUMLIN
	AOS T
	CALL PNTDEC
CMD2.1:	CALL PCRLF
	CALL PCRLF
	JRST ENTERX

ENTERX:
	M.STAT 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
	M.STAT 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
	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

IFN TNX,[
	MOVEI R1, .PRIIN	; TERMINAL INPUT
	RFMOD			; GET TERMINAL MODES
	TLZ R2, (TT%OSP)	; CAN ^O
	SFMOD			; SIGH
]
IFN DEC,[
	SKPINC			; CAN ^O
	 TRN			; DON'T WORRY
]

; IS THERE ANY WAY OF REMOVING THE EFFECT OF ^S ON ITS ???

	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 ENTERX

;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:
	M.STAT 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
	M.STAT 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
	M.STAT 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.
	M.STAT 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,
IFE KLP,[
	MOVE RDLIN7,[RDLIN6,,BP]
	BLT RDLIN7,RDLIN7
]
	TDZ W3,W3		;AND COUNT CHARS STORED IN LINE IN W3.
	JRST MPVOK1

IFE KLP,[
RDLIN6:		OFFSET BP-.
]
RDLIN2::	ILDB C,CS
MPVOK1::	XCT RDLT2(C)	;USUALLY IDPB C,W2, BUT MAY EXIT TO RDLIN3.
RDLIN7::	AOJA W3,RDLIN2
IFE KLP,[
		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.

IFN ITS\DEC,[
; 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

GWORDI:	444400,,FILBF1
	444400,,FILBF2
	444400,,FILBF3
GWORDE:	FILBE1 ? FILBE2 ? FILBE3
] ;IFN ITS\DEC

IFN TNX,[
WLEN==1000			; WINDOW LENGTH (1P) (*DO NOT CHANGE!*)
				; LONGER WINDOWS ARE NOT HANDLES AT END OF FILE
				; AND MAKE TENEX ILL

GWORDI:	SEG1A ? SEG2A ? SEG3A	; BUFFER BEGININGS
GWORDE:	SEG1A+WLEN ? SEG2A+WLEN ? SEG3A+WLEN ; BUFFER ENDS
.VECTOR GWORDV(3)		; NON-ZERO IF THIS PAGE HAS VALID DATA
.VECTOR GWORFH(3)		; Fork handle
.VECTOR GWORDN(3)		; NEXT PAGE TO MAP
] ;IFN TNX

; RDUWRD - Read a word from inferior process.
;	  This is completely independent of RDLIN and RELOAD.
;	  Used for RDWRD also (binary) on TWENEX since PMAP is general!
; Returns .+1 if EOF
; Returns .+2 otherwise,
;	W1/ word

IFN TNX, RDWRD::		; FORKS & FILES SAME FOR 10X/20X!!
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 (WAS -1)
	 CAMLE W1,GWORDE(FR)	; PAST BUFFER END?
	  JRST RDUWD2		; Load up the buffer.
IFN TNX,[
	SKIPN GWORDV(FR)	; VALID PAGE?
	 TDZA W1, W1		; NO, RETURN 0
]
	MOVE W1,(W1)
	AOS (P)
	RET
RDUWD2:
IFN ITS,MOVEI CS,FILBFL		; GET COUNT
	MOVE C,GWORDI(FR)	; GET BUFFER BP
	HRRZM C,GWORDB(FR)	; RESET POINTER
	CALL RDUBUF		; READ BUFFER
IFN TNX,[
	SKIPN GWORDV(FR)	; REALLY WANT TO READ?
	 TDZA W1, W1		; NO
]
	MOVE W1,@GWORDB(FR)	; Get 1st wd of buffer
	AOS (P)			; GET HAPPY
	RET

; C/	BUFFER BP
; CS/	WORDS TO READ
RDUBUF:	
IFN ITS,[
	M.SIN CHUIN1(FR),C,CS
	RET
] ;IFN ITS
IFN TNX,[
	PUSH P, R2
	PUSH P, R3
	AOS R1, GWORDN(FR)	; AND NEXT PAGE
	HRL R1, GWORFH(FR)	; GET FORK HANDLE
	RPACS			; CHECK THE PAGE (GOOD FOR JFNS TOO!)
	 ERJMP RDUBF1		; PAGE NO GOOD
	JUMPE R2, RDUBF1	; OR NOT MAPPED
	MOVEI R2, (C)		; GET ADDR OF BUFFER
	LSH R2, -9.		; MAKE PAGE ADDR
	HRLI R2, .FHSLF		; IN US
;;;	MOVE R3, [PM%CNT\PM%RD\<WLEN_-9.>]
	MOVSI R3, (PM%RD)
	SETOM GWORDV(FR)	; SHOULD BE VALID
	PMAP
	 ERJMP RDUBF1
	TRNA
RDUBF1:	 SETZM GWORDV(FR)	; INVALIDATE PAGE (ZERO)
	POP P, R3
	POP P, R2
	RET
] ;TNX
IFN DEC,[
	TYPE "Error - DEC 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

; DEC INT HANDLER - MPV ONLY

IFN DEC,[
IMRTRP:	PUSH P, W1		; HERE ON ILL MEM REF
	HRRZ W1, VECTOR+.PSVOP	; GET TRAP PC
	CAIE W1, MPVOK7		; MPV INTERRUPTS TO GET MORE CORE ARE LEGAL
	 CAIN W1, MPVOK6	; ONLY FROM CERTAIN SPOTS
	  JRST IMRTR2
	CAIE W1, MPVOK5
	 CAIN W1, MPVOK4
	  JRST IMRTR2
	CAIE W1, MPVOK3
	 CAIN W1, MPVOK2
	  JRST IMRTR2
	CAIE W1, MPVOK1
	 CAIN W1, MPVOK0
	  JRST IMRTR2
IMRTR1:	MOVSI W1, (PS.FOF)	; TURN PSI OFF
	PISYS. W1,
	 TRN
	JRST IMRTR3		; GO FALL OVER
IMRTR2:	HRRZ W1, VECTOR+.PSVIS	; GET ADDR
	LSH W1, -9.		; GET PAGE NUMBER
	HRRZM W1, PAGBLK+1	; STORE FOR PAGE.
	MOVEI W1, 1		; ONE WORD
	MOVEM W1, PAGBLK
	MOVE W1, [.PAGCD,,PAGBLK]
	PAGE. W1,
	 JRST IMRTR1		; GO REMOVE TRAPS, AND DIE
IMRTR3:	POP P, W1		; RESTORE ACS
	DEBRK.
	 TRN
	ERRHLT

.VECTOR PAGBLK(2)	;ARG BLOCK FOR PAGE.
] ;IFN DEC

;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)
]
IFN TNX,[
	SKIPE FSBIN		; /SAVE (/$) ?
	 JRST INOPN1		; YES, SKIP OPENF
]
	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.
INOPN1:	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.
	CAIN W2,FILBE2
	 HRRI FR,1
	CAIN W2,FILBE3		;THIRD FILE?
	 HRRI FR,2
	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.

; This code will *NOT* work for T[W]ENEX or DEC since it assumes the file
; names are of fixed length. Sigh.

RFINDR:
IFE ITS,JRST ERRIND		;BE RUDE, SINCE IT IS *NOT* GOING TO WORK
	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
	SETOM GWORDB(FR)	; MAKE SURE WE READ FIRST BUFFER

	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

.SCALAR PMTFLG			; -1 TO PROMPT WITH '#'

;READ IN A COMMAND, PROCESSING RUBOUTS, PROMPTING WITH "#".
CMDLIN:	SKIPE	CMDFIL
	 JRST	TTIFIL		;IF IN COMMAND FILE, READ FROM IT INSTEAD OF TTY.
TTILIN:	SETOM PMTFLG		;PROMPT WITH "#".
	CAIA
TTILNA:	 SETZM PMTFLG		;FOR /M INPUT, PROMPT WITH "*"
IFN DEC,CALL CRLF
	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,PMTFLG
	HLLM 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 PMTFLG		;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	PMTFLG
	 MOUTI	CHTTO,"#
	SKIPL	PMTFLG
	 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	PMTFLG
	 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	PMTFLG
	 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	PMTFLG
	 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
IFN DEC,[
;COME HERE AFTER NULL LINE.
TTILI1:	SETZM	TTICNT		;NO CHARS READ YET.
	SKIPGE	PMTFLG
	 MOUTI	CHTTO,"#
	SKIPL	PMTFLG
	 MOUTI	CHTTO,"*
	MOVE	C,[440700,,TTIBUF]
	MOVEM	C,TTIPNT
TTILUP:	CALL	TYI 		;READ A CHAR FROM TTY.
	CAIN	C,^M
	 JRST	TTILUP		;^M MEANS ^J TO COME
	CAIE	C,^C		;EOF?
	 CAIN	C,^Z
	 JRST	TTICTC
	CAIE	C,33
	 CAIN	C,^J
	  JRST	TTICR		;^J MEANS ALL READ.
	IDPB	C,TTIPNT	;NORMAL CHAR.
	AOS	TTICNT
	JRST	TTILUP

TTICTC:	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	PMTFLG
	 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	TTILI1
] ;DEC

;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.
DOHELP:	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
	CAIE C,"=	; EITHER OF THESE ARE VALID OUTPUT FILSPEC INDICATORS.
	 CAIN C,"_
	  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
	CAIE C,"=
	 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 DEC - FILESPEC READER

;READ FILE SPEC.

IFN DEC,[

RFILE:	SETZM	$F6FN2(FP)	;DEFAULT FN2 UP TO CALLER.
RFILSW:	SETZ	CS,
RFNAME:	SKIPA	C,[6]		;SET UP TO READ IN A FILENAME.
RFEXT:	 MOVEI	C,3		;ONLY 3 CHARS IN AN EXT
	MOVEM	C,RFILC
	MOVE	BP,[440600,,0]
	SETZ	0,
RFLOOP:	CALL	TTICHU		;READ A CHAR. UPPER CASE
	CAIN	C,^V
	 JRST	RFCTQ		;^V QUOTES NEXT CHAR ALA TWENEX.
	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	RFDOT		; DOT SETS FILE
	CAIN	C,"/
	 JRST	RFSPAC		;SLASH ENDS NAME. (START SWITCHES)
	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:	OFFSET	-.
RXDEV::	MOVEM	0,$FDEV(FP)
RXNAM::	MOVEM	0,$FNAME(FP)
RXEXT::	HLLZM	0,$FEXT(FP)
RXDON::	SKIPA
	OFFSET	0

RFCOL:	CAIE	0,0
	 MOVEM	0,$FDEV(FP)	;SET DEVICE FIELD.
	MOVEI	CS,RXNAM	;NAME IS NEXT
	JRST	RFNAME

RFDOT:	CAIE	0,0
	 MOVEM	0,$F6FN1(FP)	;SET FILE NAME.
	MOVEI	CS,RXEXT	;NEXT IS EXT
	JRST	RFEXT		;GET AT MOST 3 CHARS

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
	 JRST [	CAIN CS,1	;ON FILE?
		 AOJA CS,RFEXT	;YES, LEAVE ALONE, DO EXT
		JRST RFNAME]	;NO, GO BACK
	CAIN	C,40
	 JRST	RFNAME		;SPACE -- GET ANOTHER NAME.
	CAIN	C,^Z
	 MOVEI	C,^M
	CAIE	C,"/
	 RET			;NOT SLASH, RETURN.
	CALL RDSW		; AHA, READ SWITCH.
	JRST RFNAME		; THEN RETURN TO LOOP.
] ;IFN DEC

	SUBTTL	COND INTERFACE -- TOPS-20 SCANNER
IFN 20X,[
.SCALAR PARSER			; ADDRESS OF PARSER RESTART

; NORMAL PARSE
TOP:	MOVEI W1, .		; NORMAL PARSER
	SKIPE GOTJCL		; ANY JCL?
	 MOVEI W1, FLUSH2	; YES, FLUSH ON ERROR
	MOVEM W1, PARSER	;  (RETURN HERE ON ERROR)

	MOVEI W1, .NULIO	; GET NUL: FOR OUTPUT
	SKIPE GOTJCL		; INCASE WE HAVE SOME JCL
	 HRRM W1, CMJFN

	HRROI W1, [ASCIZ 'ISRCCOM>'] ; OUR BANNER
	MOVEM W1, CMRTY		; STORE PROMPT

	MOVEI W1, TOPREP
	HRRM W1, CMDBLK		; SETUP REPARSE
	MOVEI R2, INIFDB
	SKIPN GOTJCL		; JCL?
	 PUSHJ P, XCOMND	; NO, DO INIT

; HERE ON REPARSE
TOPREP:	MOVE P,[-LPDL,,PPSET-1]	; SET UP PUSH DOWN LIST
	MOVEI W1, MATCH-1	; DEFAULT NUMLIN
	SKIPN CMDFIL		; IN AN EXECUTE?
	 MOVEM W1, NUMLIN	; NO, RESET IT
	M.CLS CHIN1		; CLOSE POTENTIAL FORKS
	M.CLS CHIN2
	M.CLS CHMRG
	SETO R1,
	CLOSF			; TOSS ALL JFNS
	 TRN
	SETZ FR,		; CLEAR ALL FLAGS
	SETZM FSBIN		; NOT /SAVE
	SETZM FVBIN		; NOT /BIN
	MOVEI R2, CMDFDB	; COMMAND FDB
	SKIPE GOTJCL		; JCL?
	 MOVEI R2, JCLFDB	; YES, GET JCL FDB
	PUSHJ P, XCOMND
	SETZ R1,
	EXCH R1, GOTJCL		; NO MORE JCL
	MOVEI R3, (R3)		; GET ACTUAL FDB
	CAIN R3, JCLFDB		; CONFIRM? (JCL ONLY)
	 JRST TYNAME		;  YES, GO TYPE VERSION
	CAIE R1, 0		; HAD JCL?
	 SETOM CTLCF		; YES, EXIT AFTER THIS COMMAND
	CAIN R3, CMPFD1		; INPUT FILE?
	 JRST .COMP1		;  YES, DO STRIGHT COMPARE
	HRRZ R2, (R2)		; MUST BE KEYWORD
	JUMPE R2, CPOPJ		; HMMM.. (NO ACTION)
	PJRST (R2)		; GO!

FLUSH2:	CALL FLUSH		; CLEAR INPUT
	JRST QUIT		; AND DIE ON JCL ERROR

INIFDB:	FLDDB. .CMINI
JCLFDB:	FLDDB. .CMCFM,,,,,CMDFDB
CMDFDB:	FLDDB. .CMKEY,,CMDTAB,,,CMPFD1
;CTRLZP==<-1,,[.BYTE 7 ? ^Z ? 0]>
;CMDFD1: FLDDB. .CMTOK,,CTRLZP

XIFILE:	MOVEM A, IFIBLK+.CMHLP
	MOVEI B, IFIBLK
	PJRST XCOMND

XOFILE:	MOVEM A, OFIBLK+.CMHLP
	MOVEI B, OFIBLK
	PJRST XCOMND

XFILE:	MOVEM A, FILBLK+.CMHLP
	MOVEI B, FILBLK
	PJRST XCOMND

XNOISE:	MOVEM A, NOIBLK+.CMDAT
	MOVEI B, NOIBLK
	PJRST XCOMND

CFMFDB:	FLDDB. .CMCFM
CONFM:	MOVEI B, CFMFDB		;HERE TO CONFIRM
XCOMND:	MOVEI R1, CMDBLK	;HERE TO DO COMND W/ ERR CHECK
	COMND
	 ERJMP .+2		; ERROR?
	TLNE R1, (CM%NOP)	; NO PARSE?
	 JRST [	CALL TYLERR	;  TYPE LAST ERROR
		JRST @PARSER]	;  TAKE ERROR JRST
	RET
	SUBTTL	COMND INTERFACE -- COMMANDS

CMDTAB:	CMDNUM,,CMDNUM
;;	[CM%FW\CM%INV\CM%ABR ? .BYTE 7 ? ^Z ? 0],,QUICMD
	CMD ARCHIVE			; /A (DOESN'T PREPEND)
	CMD COMPARE			; NORMAL COMPARE
	CMD E,EXTCMD,CM%ABR\CM%INV	; MAKE E INTO EXIT
	CMD EX,EXTCMD,CM%ABR\CM%INV	; MAKE EX INTO EXIT
	CMD EXECUTE			; /X
EXTCMD:	CMD EXIT			; GET ME OUTA HERE!
	CMD FILCOM			; BE MORE LIKE DEC FILCOM (/W)
	CMD FLAG			; /F - PUT IN CHANGE BARS
	CMD HELP			; PRINT INTERNAL HELP TEXT
	CMD MERGE			; /M - TWO WAY MERGE
QUICMD:	CMD QUIT			; EXIT AND :KILL
	CMD SRCCOM,.COMPARE		; SYNONYM FOR COMPARE
CMDNUM==.-CMDTAB-1

.EXIT:	NOISE [from ITS-SRCCOM]
	CALL CONFM
	JRST QUITX		; JUST EXIT

.QUIT:	NOISE [ITS-SRCCOM]
	CALL CONFM
	JRST QUIT		; DO :KILL

.HELP:	NOISE [with ITS-SRCCOM]
	CALL CONFM
	JRST DOHELP
	SUBTTL	COMND INTERFACE -- EXECUTE COMMAND
.EXECUTE:
	TLO FR, FLXCTF		; INPUT IS EXECUTE FILE
	NOISE [from]		; BE VERBOSE
	IFILE [command file]	; BE HELPFULL
	MOVEM R2, CHIN1+JFNCHS	; SAVE AS FIRST INPUT
	MOVE W1, R2		; JFN IN 1
	MOVEI FP, INFB		; USE INPUT FB
	PUSHJ P, JFNSTR		; DECOMPOSE

	NOISE [default output to]
	MOVSI W1, (GJ%FOU)	; NEWEST FILE
	MOVEM W1, CMDGTJ+.GJGEN
	MOVE W1, FSDSK		; DSK DEFAULT
	MOVEM W1, CMDGTJ+.GJDEV
	MOVE W1, INFB+$FDIR	; USE INPUT DIRECTORY
	MOVEM W1, CMDGTJ+.GJDIR
	MOVE W1, INFB+$FNAME	; AND FILENAME
	MOVEM W1, CMDGTJ+.GJNAM
	MOVE W1, FSCMP
	MOVEM W1, CMDGTJ+.GJEXT	; .COMPARE

	FILE [output file defaults]
	MOVEI FP, LSTFB
	MOVE W1, R2		; JFN IN 1
	MOVEM R2, CHOUT+JFNCHS	; OUTPUT CHNL FOR DIFFERENCES.
	PUSHJ P, JFNSTR		; BREAKING UP IS HARD...
	PUSHJ P, CONFM		; CONFIRM

	MOVEI W1, CHIN1		; COMMAND CHAN
	MOVEI FP, INFB		; INPUT FILE BLOCK
	PUSHJ P, INOPEN		; OPEN IT!
	M.MVCH CHIN1,CHCMD	;MAKE THE ALREADY OPEN 1ST INPUT FILE BE OUR COMMAND FILE.
	MOVE W1,INFB+$FDIR	;MAKE INPUT DEV AND DIR THE INPUT DEFAULTS
	MOVEM W1,CMDIS
	MOVE W1,INFB+$FDEV
	MOVEM W1,CMDID
	MOVE W1,LSTFB+$FDIR
	MOVEM W1,CMDOS		;AND OUR OUTPUT DEV AND DIR 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.
	SUBTTL	COMND INTERFACE -- COMPARE SWITCHES

DEFINE SWT &N&,(A)		;MACRO TO BUILD SWITCH TBLUK TABLE
	[ASCIZ N],,A
TERMIN

DEFINE ABV &N&,X
	[CM%FW\CM%INV\CM%ABR ? ASCIZ N],,X
TERMIN

DEFINE SET F			;MACRO TO SET A LEFT FLAG IN FR
TLO FR, FL!F !TERMIN

CMPSW:	CMPSWN,,CMPSWN				; ITS equiv.
	SWT 'ALL-LINES',[SET ALL] 		; /B - KEEP BLANK LINES
	SWT 'BINARY',[SETOM FVBIN]		; /#
	SWT 'CASE-IGNORED',[SET CASE]		; /K
;;	SWT 'DISOWN',[SETOM DISOWN]		; /D - DISOWN
;; COULD USE "CONTINUE" PRARG AT MIT
	SWT 'ENDLINE',[SET ENDL]		; /E
	SWT 'LABELS',[SET LABL]			; /L
	SWT 'MATCH:',[PUSHJ P, SWMATCH]		; /digit
	SWT 'NOCOMMENTS',[SET CMNT]		; /C - IGNORE COMMENTS
	SWT 'OVERRIDE',[SET OVRD]		; /!
	ABV 'S',$S
	SWT 'SAVE-FILE',[SETOM FSBIN]		; /$
$S:	SWT 'SPACING-IGNORED',[SET SPAC]	; /S
	SWT 'WHICH-FILE',[SET FNUM]		; /W
	SWT 'XLABEL',[SET XLBL]			; /Y
CMPSWN==.-CMPSW-1

	SUBTTL	COMND INTERFACE -- MERGE SWITCHES
MRGSW:	MRGSWN,,MRGSWN
	SWT 'CASE-IGNORED',[SET CASE]		; /K
;;	SWT 'DISOWN',[JRST SWDISN]		; /D - YOU WISH
;; COULD USE "CONTINUE" PRARG AT MIT
	SWT 'ENDLINE',[SET ENDL]		; /E
	SWT 'INDICATE',[SET ISWT]		; /I
	SWT 'LABELS',[SET LABL]			; /L
	SWT 'MATCH:',[PUSHJ P, SWMATCH]		; /digit
	SWT 'NOCOMMENTS',[SET CMNT]		; /C - IGNORE COMMENTS
	SWT 'OVERRIDE',[SET OVRD]		; /!
	SWT 'SPACING-IGNORED',[SET SPAC]	; /S
;;	SWT 'THREE-WAY',[SETOM 3WAY]		; 3 INPUT FILES/M
	SWT 'WHICH-FILE',[SET FNUM]		; /W
	SWT 'XLABEL',[SET XLBL]			; /Y
MRGSWN==.-MRGSW-1

MATFDB:	FLDDB. .CMNUM,CM%SDH,10.,[lines to match, 1 to 15]
SWMATCH:MOVEI B, MATFDB		; PARSE A NUMBER
	CALL XCOMND		; WELL TRY
	CAIL B, 1
	 CAILE B, 15.		; SOME REASONABLE NUMBER
	  JRST ERRMAT
	SUBI B, 1		; MINUS 1
	MOVEM B, NUMLIN		; SAVE AS EXTRA LINES TO MATCH
	POPJ P,

ERRMAT:	JSP T, ERRMSG
	ASCIZ "/MATCH: value must be from 1 to 15"

CMPFDB:	FLDDB. .CMSWI,,CMPSW,,,CMPFD1
MRSFDB:	FLDDB. .CMSWI,,MRGSW,,,CMPFD1
CMPFD1:	FLDDB. .CMIFI,CM%SDH,,[New file]

.SCALAR FDBSAV			; THE RIGHT SWITCH FDB
.VECTOR DEFBUF(20.)		; ABS DEFAULT FOR SECOND FILE

.FLAG:	TLO FR, FLFLAG		; FLAGGING.. ANOTHER COMPARE FLAVOR
	NOISE [changes]
	JRST .MERG0		; A MERGE SUB-FLAVOR

.MERGE:	NOISE [files]
.MERG0: TLO FR, FLMERG\FLALL	; MERGE IMPLIES FLALL
	MOVEI R2, MRSFDB	; MERGE SWITCHES & INPUT FILE
	JRST .COMPX

.FILCO:	TLOA FR, FLFNUM\FLENDL	; FILCOM IMPLIES /WHICH/ENDLINE
.ARCHI:	 TLO FR, FLARCH		; ARCHIVING... JUST LIKE COMPARE
.COMPA:	NOISE [files]		; NORMAL COMPARE HERE
.COMP0:	MOVEI R2, CMPFDB	; COMPARE SWITCHES
.COMPX:	MOVEM R2, FDBSAV	; SAVE FDB FOR NEXT? SWITCH
.COMPY:	PUSHJ P, XCOMND		; HERE FOR ALL COMMANDS
	TSZ R3, R3		; FIRST FDB?
	JUMPN R3, .COMP1	; NO, MUST BE A FILE
	HRRZ B, (B)		; GET ADDR OF SWITCH ACTION
	CAIE B, 0		; ANY ACTION?
	 XCT (B)		; YES, EXECUTE
	MOVE R2, FDBSAV		; RESTORE FDB
	JRST .COMP0		; LOOP FOR ANOTHER, OR FILE

.COMP1:	MOVEM R2, CHIN2+JFNCHS	; SAVE INPUT FILE JFN
	MOVE W1, R2		; JFN IN 1
	MOVEI FP, INFB		; USE INPUT FB
	PUSHJ P, JFNSTR		; DECOMPOSE
	HRROI R1, DEFBUF	; BUFFER FOR ABSENT DEFUALT STRING
	MOVE R2, JFNCHS+CHIN2	; JFN
	MOVE R3, [<021100,,>\JS%PAF] ; DIR, FILE, EXT, PUNCT
	JFNS			; GET JFN STRING, THEN APPEND .-2
IRPC X,,[.-2]
	MOVEI R2, "X
	IDPB R2, R1
TERMIN
	SETZ R2,		; MAKE ASCIZ
	IDPB R2, R1
	MOVEI W1, CHIN2		; USE THIS CHAN
	PUSHJ P, INOPEN		; CRACK OPEN

;;; Here to get second file
	NOISE [with]
	SETZM CMDGTJ+.GJGEN	; HIGHEST GEN
	MOVSI W1,(GJ%OLD)	; *** TEST -- DEMAND FILE EXISTS
	MOVEM W1,CMDGTJ+.GJGEN
	MOVE W1, [INFB+$FDEV,,CMDGTJ+.GJDEV] ; FILE1 DEVICE, DIR, FILE, EXT
	BLT W1, CMDGTJ+.GJEXT	; USED FOR DEFAULT, FOR ANY EMPTY FIELDS
;;	SETZM CMDGTJ+.GJEXT	; **** NO DEFAULT EXT ****

	HRROI R1, DEFBUF	; GET BP TO DEFAULT STRING
	MOVEM R1, DFIBLK+.CMDEF	; STORE DEFAULT
	MOVEI R2, DFIBLK	; GET BLOCK
	PUSHJ P, XCOMND		; PARSE

	MOVEM R2, CHIN1+JFNCHS	; SAVE SECOND INPUT CHAN
	MOVE W1, R2		; JFN IN 1
	MOVEI FP, INFB		; USE INPUT FB
	PUSHJ P, JFNSTR		; DECOMPOSE
	MOVEI W1, CHIN1		; USE THIS CHAN
	PUSHJ P, INOPEN		; CRACK OPEN

	SKIPN 3WAY		; CRAZY 3-WAY?
	 JRST .COMPZ		; NOPE

;;; Here for 3rd file
	PUSH P, CMDGTJ+.GJNAM	; SAVE FILE NAME FOR OUTPUT
	NOISE [and]
	IFILE [3rd input file]
	MOVEM R2, CHIN3+JFNCHS	; SAVE JFN
	MOVE W1, R2		; JFN IN 1
	MOVEI FP, INFB		; USE INPUT FB
	PUSHJ P, JFNSTR		; DECOMPOSE
	MOVEI W1, CHIN3		; USE THIS CHAN
	PUSHJ P, INOPEN		; CRACK OPEN

	POP P, CMDGTJ+.GJNAM	; RESTORE FILE NAME FOR OUTPUT

;;; Here to get output file
.COMPZ:	NOISE [to]
	MOVSI W1, (GJ%FOU)	; NEWEST FILE
	MOVEM W1, CMDGTJ+.GJGEN

	MOVE W1, FSTTY		; TTY DEFAULT
	TLNE FR, FLARCH\FLMERG	; ARCHIVE OR MERGE?
	 MOVE W1, FSDSK		;  .. USE DISK
	MOVEM W1, CMDGTJ+.GJDEV

	MOVE W1, FSCMP		; .COMPARE
	TLNE FR, FLARCH		; ARCHIVING?
	 MOVE W1, FSCMPA	;  .. MAKE IT .CMPARC
	TLNE FR, FLMERG		; MERGE ??
	 MOVE W1, FSDMF2	;  YES .MERGED
	TLNE FR, FLFLAG		; FLAGGING?
	 MOVE W1, FSFLGD	;  .. USE FLAGGD EXTENSTION
	MOVEM W1, CMDGTJ+.GJEXT

	FILE [output file]
	PUSH P, R2		; SAVE JFN
	PUSHJ P, CONFM		; CONFIRM IT

	MOVE T, JFNCHS+CHTTO	; GET TTY OUTPUT
	MOVEM T, JFNCHS+CHOUT	; MAKE DEFAULT OUTPUT IF MERGING

	MOVEI T,CHOUT		; NORMAL OUTPUT FILE
	TLNE FR, FLMERG		; BUT IF MERGING (FLAGGING)
	 MOVEI T, CHMRG		; OUTPUT MERGE CHAN

	POP P, W1		; GET JFN BACK
	PUSH P, T		; SAVE CHAN
	MOVEM W1, JFNCHS(T)	; SAVE OUTPUT JFN
	MOVEI FP,LSTFB		; LIST FILE BLOCK
	PUSHJ P, JFNSTR		; EXPLODE JFN

	POP P, W2		; RESTORE PROPER CHAN
	MOVEI FP, LSTFB
	MOVE T, FSTTY		; BP TO "TTY"
	CAMN T, LSTFB+$FDEV	; ABOUT TO OPEN TTY FOR OUTPUT?
	 JRST [	MOVE R1, JFNCHS+CHTTO ; IF SO JUST DUPLICATE TTY JFN
		EXCH R1, JFNCHS(W2) ; TO THE RIGHT CHANNEL
		RLJFN		; DUMP TTY: JFN
		 JFCL		; SIGH
		SETOM OUTTTY
		JRST .COMP3]
	HRLI FP,(W2)		; GET <CHAN>,,<FB PTR>
	CALL OPNWR		; OPEN FOR WRITE
	 CALL OPENL		;  TELL THEM IF NOT
.COMP3:	JRST CMD2		; HMMM... I GUESS WE ARE READY..

	SUBTTL	MERGE PARSE TOP-LEVEL

MRGTOP:	MOVEI W1, .		; HERE ON ERROR
	MOVEM W1, PARSER
	MOVEI W1, MRGREP	; SET REPARSE
	HRRM W1, CMDBLK		; "<" BALANCE WIDGETS FOR EMACS C-M-F
	HRROI W1, [ASCIZ 'MERGE>']
	MOVEM W1, CMRTY		; SET PROMPT
	MOVEI R2, INIFDB
	PUSHJ P, XCOMND
	MOVEM P, SAVEDP		; SAVE P FOR REPARSE

; HERE ON REPARSE
MRGREP:	MOVE P, SAVEDP
	MOVEI R2, MRGFDB
	PUSHJ P, XCOMND
	TSZ R3, R3		; SECOND?
	JUMPN R3, MRGFOO	; YES, WAS CONFM
	HRRZ R2, (R2)		;GET ADDR
	JUMPE R2, MRGTOP	;HMMM..
	PJRST (R2)		;GO!

MRGFOO:	JRST TOP		; HERE ON COMFIRM

MRGFDB:	FLDDB. .CMKEY,,MRGTAB,,,MRGFD1
MRGFD1:	FLDDB. .CMCFM,CM%SDH,,[End with confirm]
MR2FDB:	FLDDB. .CMKEY,,MR2TAB

MRGTAB:	MRGNUM,,MRGNUM
	CMD 1ST,0		; FIRST FILE
	CMD 2ND,0		; SECOND FILE
	CMD COLUMNS		; INPUT NUMBER OF COLS TO TYPE
	CMD INDICATE,0		; MERGE LOSSAGE - PUT IN BOTH
	CMD LINES		; LINES TO TYPE OUT
	CMD TYPE,0		; INPUT NUMBER OF LINES TO TYPE
MRGNUM==.-MRGTAB-1

MR2TAB:	MR2NUM,,MR2NUM
	CMD 1ST,0		; FIRST FILE
	CMD 2ND,0		; SECOND FILE
	CMD TYPE,0		; INPUT NUMBER OF LINES TO TYPE
MR2NUM==.-MR2TAB-1

.SCALAR SAVEDP
;; MERGE ACTIONS

DECFDB:	FLDDB. .CMNUM,,10.
.COLUMNS:
	NOISE [to type]
	MOVEI R2, DECFDB	; DECIMAL NUMBER
	CALL XCOMND		; FETCH
	PUSH P, R2		; SAVE NUMBER
	CALL CONFM		; CONFIRM IT
	POP P, COLMAX		; SAVE VALUE
	JRST MRGTOP		; GET ANOTHER COMMAND

.LINES:	NOISE [to type]
	MOVEI R2, DECFDB	; DECIMAL NUMBER
	CALL XCOMND		; FETCH
	PUSH P, R2		; SAVE NUMBER
	CALL CONFM		; CONFIRM IT
	POP P, LINMAX		; SAVE VALUE
	JRST MRGTOP		; GET ANOTHER COMMAND
] ;20x COMND stuff

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]
	SWITCH	A,O,FLARCH		;/A - APPEND OUTPUT TO FRONT OF EXISTING FILE.
	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 TYLERR		;TYPE LAST ERROR
	MOUTI CHTTO,":
	MOUTI CHTTO,40
	CALL LSTFIL		;PRINT NAME OF LOSING FILE (WHAT FP POINTS TO).
	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:
IFN TNX,CALL UNMAP
	M.CLS CHIN1
	M.CLS CHIN2
;;;	M.CLS CHIN3
	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.

IFN TNX,[
UNMAP:	SETO R1,
	MOVE R2, [.FHSLF,,<SEG1A_-9.>]
.SEE MLEN
	SETZ R3,
	PMAP

	SETO R1,
	MOVE R2, [.FHSLF,,<SEG2A_-9.>]
.SEE MLEN
	SETZ R3,
	PMAP

	SETO R1,
	MOVE R2, [.FHSLF,,<SEG3A_-9.>]
.SEE MLEN
	SETZ R3,
	PMAP
	RET
] ;TNX

;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

TTOOCT:	IDIVI 0,10
	HRLM W1,(P)
	CAIE 0,0
	 CALL TTOOCT
	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:	MOVSI 4, 2		; HERE FOR LOGOUT
	MOVE 1, [.PRAST,,.FHSLF]
	MOVEI 2,4
	MOVEI 3,1
	PRARG			; LEAVE :KILL MESSAGE
QUITX:	HALTF			; HERE FOR FINISHED
	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 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
		RLJFN
		 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
	SETOM GWORDB(FR)	; Make sure we read first binary buffer
	SETOM GWORDN(FR)	; Reset page number for binary read
	SKIPE FSBIN		; From a fork?
	 JRST RCHST2		; Yes, GET it
	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 R1, GWORFH(FR)	; SAVE JFN AS FORK
	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

RCHST2:	CFORK			; GET A FORK
	 TRN
	MOVEI R2, CHIN1(FR)	; GET CHAN
	MOVEM R1, JFNCHS(R2)	; SAVE HANDLE AS 'JFN'
	MOVEM R1, GWORFH(FR)	; SAVE INDEXED BY 'CHAN'
	MOVSI R1, (R1)		; FORK,,0
	POP P, R2		; RESTORE JFN
	HRR R1, R2		; FORK,,JFN
	GET			; LOAD IT
	 ERJMP SECLOS		; WE *TRIED*

IFN 20X,MOVEI R4, 37		; HIGHEST KL SECTION NUMBER
SECLOP:	CALL LSTPAG		; CHECK FOR LAST, IF ANY PAGES
	 TRNA			; NO PAGES HERE.
	  JRST SECLP2		; GOT ONE!
IFN 20X,SOJGE R4, SECLOP	; NO PAGES, TRY NEXT LOWEST SECTION
SECLOS:	SETZM GWORDL(FR)	; NO PAGES AT ALL!!
	SETZM GWORDC(FR)
	SETOM EOFFL1(FR)	; AT EOF NOW!
	RET

SECLP2:
IFN 20X,[
	LSH R4, 9.		; SECTIONIFY
	ADDI R4, (R3)		; ADD LAST PAGE FOUND
] ;20X
.ELSE	MOVEI R4, (R3)		; GET LAST PAGE FOUND
	LSH R4, 9.		; WORDIFY!
	MOVEM R4, GWORDL(FR)
	MOVEM R4, GWORDC(FR)
	RET

; CALL	R4/	SECTION
; RET+1	R3/	HIGHEST EXISTANT PAGE
LSTPAG:
IFN 20X,[
	HRLZ R1, GWORFH(FR)	; FORK
	HRRI R1, (R4)		; ,,SECTION
	RSMAP			; CHECK SECTION MAPPING
	 ERJMP CPOPJ		; GUESS NOT
	JUMPL R1, CPOPJ		; NO MAPPING
	MOVEI R3, 1(R4)		; GET SECTION +1
	LSH R3, 9.		; SECTIONIFY
	MOVEI R3, -1(R3)	; START AT TOP OF SECTION
] ;20X
.ELSE	MOVEI R3, 777		; END OF CORE
LSTPG1:	HRLZ R1, GWORFH(FR)	; FETCH FORK
	HRRI R1, (R3)		; ,, PAGE
	RMAP			; READ MAPPING
	JUMPN R2, POPJ1		; FOUND A PAGE!!
	SOJGE R3, LSTPG1	; NO PAGE, KEEP LOOKING
	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:
IFN 0,[
	SKIPE CCLFLG		; Started at CCL location?
	 JRST JCLIN5		; Yep, go snarf stuff specially.
]
IFN 10X,[
	SETZM TTIPNT
	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
] ;10X
IFN 20X,[
	SETZ R1,
	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.
	MOVEI W1, .NULIO
	HRRM W1, CMJFN		; OUTPUT TO NOWHERE
	MOVEI W1, FLUSH
	HRRM W1, CMFLG		; ON REPARSE, FLUSH
	MOVEM W1, PARSER	; ON ERROR, FLUSH
	HRROI W1, [0]		; NULL PROMPT
	MOVEM W1, CMRTY

	MOVEI R2, INIFDB	; INIT THE PARSE
	CALL XCOMND

	MOVEI R2, JNAFDB	; LIST OF LEGAL JNAMES
	MOVEI R1, CMDBLK
	COMND
	 ERJMP FLUSH
	TLNE R2, (CM%NOP)	; NO PARSE?
	 JRST FLUSH
	TSZ R3, R3		; SECOND BLOCK?
	 JUMPN R3, FLUSH	; YES, WAS CONFIRM
	SETOM GOTJCL		; INDICATE PRESENCE OF JCL
	AOS (P)			; Success return.
	RET

.SCALAR GOTJCL

FLUSH:	SETZM GOTJCL		; NO JCL TO SPEAK OF..
	MOVEI W1, .PRIIN
	CFIBF			; DUMP INPUT LINE
	RET			; RETURN FAILURE

JNAFDB:	FLDDB. .CMKEY,,JNAMES,,,CFMFDB
JNAMES:	NJNA,,NJNA
	CMD ISRCCOM,0
	CMD SRCCOM,0
NJNA==.-JNAMES-1
] ;20X
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.

IFN ITS\DEC,[
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
IFE ITS, FSDMF2:DEFSTR /MERGED/
IFN ITS, FVLOW:	DEFSTR /</
IFN TNX, FVLOW:	.GJLEG		; -2 for lowest version
IFN DEC, FVLOW: 0

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

FNZER==%%FNLC		; Save start of area to zero
EXPUNG %%FNLC

; 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.
;	A/ BP to ASCIZ
;	Returns value in A, clobbers nothing else.

CVSDEC:	PUSH P,B
	PUSH P,C
	MOVE C,A
	SETZ A,
	JRST CVSDC3
CVSDC2:	IMULI A,10.
	ADDI A,-"0(B)
CVSDC3:	ILDB B,C
	JUMPN B,CVSDC2
	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:	SKIPE $FJFN(F)		; JFN THERE?
	 JRST POPJ1		; YES, SUCCESS
	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

; CLOSE A CHAN IN T (MIGHT BE A FORK)
M$CLS:	SAVE R1
	SKIPG R1,JFNCHS(T)
	 JRST M$CLS1		; NOTHING OPEN
	CAIGE R1, .FHSLF	; LOOK LIKE A FORK?
	 JRST M$CLS0		; NO, CLOSE THE JFN
	KFORK
	 ERJMP .+1
	TRNA
M$CLS0:	 CLOSF
	  ERJMP .+1
M$CLS1:	SETZM JFNCHS(T)
	REST R1
	RET

CTRLE:	HRROI R1, [ASCIZ /
**ABORT**
/]
	PSOUT
	MOVEI W1, BEG
	MOVEM W1, PC1
	DEBRK

; HERE FOR INTERUPT LEVEL STATUS
CTRLY:	MOVEM 16, ACSAVE+16
	MOVEI 16, ACSAVE
	BLT 16, ACSAVE+15
	MOVEI R1, .FHSLF	; GET FORK RUNTIME ONLY
	RUNTM			; 1/ RUN 2/ 1000. 3/ CONN
	PUSH P, R1		; SAVE NEW RUNTIME
	SUB R3, CONSAV		; MAKE DELTA
	HRROI R1, [ASCIZ "Day: "]
	PSOUT
	PUSHJ P, TTIME		; TYPE CONNECT

	HRROI R1, [ASCIZ "  Run: "]
	PSOUT
	POP P, R3		; GET NEW RUN
	SUB R3, RUNSAV		; GET DELTA
	PUSHJ P, TTIME

	SKIPN STSWRD
	 JRST Y2
	HRROI R1, [ASCIZ "  State: "]
	PSOUT
	MOVE 0, STSWRD
	PUSHJ P, TTOSIX
Y2:	HRROI R1, [ASCIZ "  PC: "]
	PSOUT

;PERHAPS TYPE SYMBOLIC? OR TYPE INSTRUCTION (ESP. JSYS)
	MOVEI R1, .PRIOU
	HRRZ R2, PC1
	MOVE R3, [FLD(6,NO%COL)\NO%LFL\NO%ZRO\10]
	NOUT
	 JFCL
	HRROI R1, [ASCIZ "
"]
	PSOUT
	MOVEI R1, .FHSLF	; REMOVE ^Y TIME FROM ACCOUNTING!!!
	RUNTM			; UNLIKE LUSING EXEC
	MOVEM R1, RUNSAV
	MOVEM R3, CONSAV
DBK:	MOVSI 16, ACSAVE
	BLT 16, 16
	DEBRK

;TYPE TIME IN 3 (MSEC.) AS [[HRS:]MIN:]SEC.MSEC
TTIME:	MOVEI R1, .PRIOU	; OUT TO TTY
	IDIVI 3, 1000.		; 3/ SEC 4/ MSEC
	PUSH P, 4		; SAVE MSEC
	IDIVI 3, 60.		; 3/ MIN 4/ SEC
	PUSH P, 4		; ELSE SAVE SEC
	JUMPE 3, TTIME1		; NO MIN
	IDIVI 3, 60.		; 3/ HRS 4/ MIN
	JUMPE 3, TTIME2		; NO HRS
	MOVE 2, 3
	MOVEI 3, 10.
	NOUT			; TYPE HRS
	 JFCL
	MOVEI R2, ":
	BOUT
TTIME2:	MOVE R2, 4		; FETCH MINS
	MOVEI R3, 10.
	NOUT
	 JFCL
	MOVEI R2, ":
	BOUT
TTIME1:	POP P, R2		; RESTORE SEC
	MOVEI R3, 10.
	NOUT
	 JFCL
	POP P, R3
	JUMPE R3, CPOPJ
	MOVEI R2, ".
	BOUT
	MOVEI R2, (R3)		; MSEC
	IDIVI R2, 10.		; MAKE ONLY 1/100'S
	MOVE R3, [FLD(2,NO%COL)\NO%LFL\NO%ZRO\10.]
	NOUT
	 JFCL
	RET

.VECTOR ACSAVE(17)

] ;IFN TNX
	SUBTTL	Auxiliary DEC Routines

IFN DEC,[
; GETJCL - Get JCL input
GETJCL:	RESCAN 1		; GET A LINE?
	 SKPINC			; CHECK..
	  RET			; GUESS NOT
	MOVE	W1,[440700,,TTIBUF] ; If have command string from superior,
	MOVEM	W1,TTIPNT	; set up to read from it.
	SETZ	CS,
JCLIN:	INCHWL	C		; Input characters, line edited
	CAIN	C,^M
	 JRST	JCLIN
	CAIE	C,^L		; FF
	 CAIN	C,"		; OR ESC?
	  MOVEI	C,^J		; BASH TO ^J
	IDPB	C,W1
	CAIE	C,^J		; EOL?
	 AOJA	CS,JCLIN

	MOVE W2,[440700,,TTIBUF]
	ILDB W1,W2
	TRZ W1,40		; Convert to upper case
	CAIE W1,"R		; R or RUN ? (* KLUDGE *)
	 JRST JCLIN4		; no.
JCLIN1:	ILDB W1, W2
	CAIE W1,"!		; START OF COMMAND?
	 CAIN W1,";
	  JRST GTJCL1		; NOW HAVE CMD LINE
	JUMPN W1, JCLIN1	; ANY MORE?
	RET			; NO, NO COMMAND

JCLIN4:	MOVE W2,[440700,,TTIBUF] ; Flush file name we were run from.
	ILDB W1,W2
	CAILE W1,40
	 JRST .-2		; Flush until random ctl seen (space, ^M)
	CAIE W1,40		; If it wasn't a space,
	 RET			; then forget about the whole thing.
JCLIN3:	MOVE C,W2		; Now flush spaces.  Save last ptr for chars.
	ILDB W1,W2
	CAIN W1,40
	 JRST JCLIN3
	CAIN W1,^J		; And is first non-space something besides LF?
	 RET			; Bah, there wasn't anything in the JCL!!
GTJCL1:	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

; LSTFIL - Print name of current file on LST or TTY.
LSTFIL:	MOVE	0,$F6DEV(FP)
	CAMN	0,FSDSK
	 JRST	LSTFI1
	CALL	TTOSIX		; Print dev if not DSK.
	MOUTI	CHTTO,":
LSTFI1:	MOVE	0,$F6FN1(FP)
	CALL	TTOSIX		; Print name.
	MOUTI	CHTTO,".	; dot
	MOVE	0,$F6FN2(FP)
	CALL	TTOSIX		; ext
	SKIPN	$FDIR(FP)	; Any ppn?
	 RET			; no
	MOUTI	CHTTO,133
	HLRZ	0, $FDIR(FP)
	CALL	TTOOCT
	MOUTI	CHTTO,54
	HRRZ	0, $FDIR(FP)
	CALL	TTOOCT
	SETZ	T,		; List SFDs
LSTFI2:	SKIPN	$FSFD(T)
	 JRST	LSTFI3		; no maw
	MOUTI	CHTTO,54
	MOVE	0,$FSFD(T)
	CALL	TTOSIX
	AOJA	T, LSTFI2
LSTFI3:	MOUTI	CHTTO,135
	RET

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

; INPUT A CHARACTER FROM CONSOLE
TYI:	INCHWL C
	CAIN C, ^Z		; EOF ?
	 MOVEI c, ^C		; Yes, make look like ITS
	RET

; TYLERR - Type last error (using OPNBLK)

TYLERR:	HRRZ	W1, OPNBLK+.FOLEB ; GET ADDR OF LAST LOOKUP BLOCK
	MOVE	T, .RBCNT(W1)	; Get count word
	HRRZ	W2, .RBEXT(W1)	; Load error word for extended block
	TLNE	T, -1		; Look like a short block?
	 HRRZ	W2, 1(W1)	; Yes, get error from second word
	CAIL	W2, 0		; >= 0?
	 CAILE	W2, MAXERR	; <= MAX?
	  TDZA	W1, W1		; no, out of range
	   MOVE	T, ERRTAB(W2)	; yes, in range: get string (if any)
	CAIN	T, 0		; have a string?
	 MOVEI	T, [ASCIZ 'Unknown error'] ; no, get the default
	PJRST	TYPMSG
DEFINE X &S&
[ASCIZ S]!TERMIN

ERRTAB:
	X 'File not found'
	X 'Incorrect PPN'
	X 'Protection failure'
	X 'File being modified'
	X 'Already existing file name'
	0 ;ILLEGAL SEQUENCE OF UUOS
	0 ;TRANSMISSION ERROR
	0 ;NOT A SAVE FILE
	0 ;NOT ENOUGH CORE
	X 'Device not available'
	X 'No such device'
	0 ;ILLEGAL MONITOR CALL FOR GETSEG OR FILOP, OR SAVE.
	X 'No room'
	X 'Write-locked'
	0 ;NOT ENOUGH TABLE SPACE
	0 ;PATIAL ALLOCATION
	0 ;BLOCK NOT FREE
	0 ;CAN'T SUPERSEDE A DIRECTORY
	0 ;CAN'T DELETE NON-EMPTY DIRECTORY
	X 'SFD not found'
	X 'Search list empty'
	0 ;SFD NEST LEVEL TOO DEEP
	X 'No-create for all S/L'
	0 ;SEGMENT NOT ON SWAP SPACE OR JOB LOCKED
	0 ;CAN'T UPDATE FILE
	0 ;LOW SEG OVERLAPS HI SEG (GETSEG)
	0 ;NOT LOGGED IN (RUN, SAVE)
	0 ;FILE STILL HAS OUTSTANDING LOCKS SET
	0 ;BAD .EXE FILE DIRECTORY (GETSEG,RUN)
	0 ;BAD EXTENSION FOR .EXE FILE(GETSEG,RUN)
	0 ;.EXE DIRECTORY TOO BIG(GETSEG,RUN,SAVE.)
	0 ;TSK - EXCEEDED NETWORK CAPACITY
	0 ;TSK - TASK NOT AVAILABLE
	0 ;TSK - UNDEFINED NETWORK NODE
	0 ;RENAME - SFD IS IN USE
	0 ;DELETE - FILE HAS AN NDR LOCK
	0 ;JOB COUNT HIGH (A.T. READ COUNT OVERFLOW)
	0 ;CANNOT RENAME SFD TO A LOWER LEVEL
	X	'Channel Not OPENed' ;(FILOP.)
	X	'Device "down" and unuseable'
	X 'Device is restricted'
	X 'Device controlled by MDA'
	0 ;DEVICE ALLOCATED TO ANOTHER JOB
	X 'Illegal I/O data mode'
	X 'Unknown/undefined OPEN bits set'
	0 ;DEVICE IN USE ON AN MPX CHANNEL
	X 'No Per-process space for extended I/O channel table'
	X 'No free channels available'
	X 'Unknown FILOP. function'
;	0 ;CHANNEL TOO BIG
;	0 ;CHANNEL ILLEGAL FOR SPECIFIED FUNCTION
;	0 ;ADDRESS CHECK READING ARGUMENTS
;	0 ;ADDRESS CHECK STORING ANSWER
;	0 ;NEGATIVE OR ZERO ARGUMENT COUNT
;	0 ;ARGUMENT BLOCK TOO SHORT
MAXERR==.-ERRTAB-1

; NOT IN USE
RENMLO:	RET

OPNAP:	SKIPA T, [FO.ASC\.FOAPP] ; ASSIGN CHAN, APPEND
OPNWR:	SAVE [FO.ASC\.FOWRT]	; ASSIGN, WRITE
	SETZM OPNBLK+.FOIOS .SEE .IOASC ; ASCII MODE
	HLRZ T, FP		; GET CHAN
	IMULI T, 3		; BUFFER HEADER SIZE
	MOVEI T, CHNHDR(T)	; ADDR OF HEADER
	HRLZM T, OPNBLK+.FOBRH	; STORE BUFFER RING HEADERS
	MOVSI T, -1		; DEFAULT HEADER
	MOVEM T, OPNBLK+.FONBF
	REST T
	JRST OPNRD2

; OPEN FOR READ IN 'W'ORD OR 'A'SCII STREAM
; FP/ CHAN,,^FB
OPNRDA:	TDZA T, T .SEE .IOASC	; ASCII MODE
OPNRDW:	 MOVEI T, .IOBIN	; READ USING BINARY MODE (DSK ONLY?)
	HRLI T, (UU.LBF)	; USE LARGE BUFFERS ON INPUT
	MOVEM T, OPNBLK+.FOIOS	; STORE I/O STATUS
	HLRZ T, FP		; GET CHAN
	IMULI T, 3		; BUFFER HEADER SIZE
	MOVEI T, CHNHDR(T)	; ADDR OF HEADER
	HRRZM T, OPNBLK+.FOBRH	; STORE BUFFER RING HEADERS
	MOVEI T, -1		; DEFAULT BUFFERS
	MOVEM T, OPNBLK+.FONBF

	MOVE T, [FO.ASC\.FORED]	; ASK FOR CHAN, READ
OPNRD2:	MOVEM T, OPNBLK+.FOFNC	; STORE FUNCTION
	MOVE T, $FDEV(FP)	; FETCH DEVICE
	MOVEM T, OPNBLK+.FODEV	; STORE
	MOVEI T, LKBLK		; LOOKUP/ENTER BLOCK ADDR
	MOVEM T, OPNBLK+.FOLEB
	MOVEI T, $FDIR-.PTPPN(FP) ; POINTER TO PATH BLOCK
	HRLI T, .PTMAX		; FULL LENGTH
	MOVEM T, OPNBLK+.FOPAT
	MOVEI T, $FNODE(FP)	; ADDR OF FILE BLOCK
	HRLI T, .FOFMX+1	; AND LENGTH
	MOVEM T, OPNBLK+.FOFSP	; RETURN FILE NAME HERE
	DMOVE T, $FNAME(FP)	; GET NAME + EXT
	DMOVEM T, LKBLK+.RBNAM
	MOVE T, [.FOFSP+1,,OPNBLK]
	FILOP. T,
	 RET
	SAVE W1
	HLRZ W1, FP		; GET FILE #
	MOVE T, LKBLK+.RBSIZ	; GET SIZE IN WORDS
	MOVEM T, GWORDC(W1)	; SAVE WORD COUNT
	MOVEM T, GWORDL(W1)	; SAVE FILE LENGTH
	LDB T, [.BP FO.CHN,OPNBLK] ; FETCH CHAN
	MOVEM T, JFNCHS(W1)	; SAVE DEC CHAN
	REST W1
	AOS (P)
	RET

OPNHLP:	OPEN 1, [.IOASC ? SIXBIT 'HLP' ? CHIN1*3+CHNHDR]
	 RET
	LOOKUP 1, HLPFIL
	 RET
	MOVEI W1, 1
	MOVEM W1, JFNCHS+CHIN1
	AOS (P)
	RET

QUITX:	EXIT 1,			; HERE FOR NORMAL EXIT
QUIT:	EXIT			; HERE FOR :KILL


;PUT FILE DESCRIPTION IN ASCII INTO HBUF FOR THIS FILE
RCHST:	MOVEI W1, CHIN1(FR)	; GET ITS CHAN
	HRLZ W1, JFNCHS(W1)	; NOW GET DEC CHAN
	HRRI W1, .FOFIL		; PUT IN 7.02 MAGIC FUNCTION
	MOVE W2, [.FOFMX+1,,RCHSTB] ; POINTER BACK INTO BLOCK
	DMOVEM W1, RCHSTB	; SO MUCH FOR KA'S (7.02 DUMPS KI'S TOO)
	MOVE W1, [2,,RCHSTB]	; POINTER TO UUO ARGS
	FILOP. W1,
	 ERRHLT

	SETOM GWORDB(FR)	; MAKE SURE WE READ FIRST BINARY BUFFER

	MOVE W2,RCHSTP(FR)	;NOW SET UP BYTE POINTER TO AREA TO READ INTO
	MOVE T,RCHSTB+.FOFDV	;GET THE CHOSEN DEVICE NAME
	JSP W1,RCHST6		;DEVICE NAME
	    ":			;END WITH COLON
	SKIPN T,RCHSTB+.FOFFN
	 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		;FILE NAME
	    ".
	SKIPN T,RCHSTB+.FOFEX
	 MOVE T,INFB+$FEXT
	JSP W1,RCHST6		;EXTENSION
	    0			;DON'T PRINT TERMINATING CHAR
	SKIPN T,RCHSTB+.FOFPP	; GET A PPN
	 JRST RCHSTX		; IF NO PUNT NOW
	MOVEI C, 133
	IDPB C, W2
	HLRZ T, T
	CALL RCHST7		; TYPE PPN LEFT HALF
	MOVEI C, ",
	IDPB C, W2		; ","
	HRRZ T, RCHSTB+.FOFPP	; GET RIGHT HALF
	CALL RCHST7		; TYPE IT, TOO
	SETZ TT,		; TYPE SFDS, IF ANY
RCHST1:	SKIPN T, RCHSTB+.FOFSF(TT)
	 JRST RCHST2		; NO MORE SFDS
	MOVEI C,",		; PUT OUT A COMMA
	IDPB C, W2
	JSP W1, RCHST6		; TYPE SFD
	  0			; NOTHING AFTER IT
	AOJA TT, RCHST1		; LOOP UNTIL 0
RCHST2:	MOVEI C, 135		; CLOSE OF DIR
	IDPB C, W2
RCHSTX:	MOVEI C,0
	IDPB C,W2		;MARK END OF STRING
	RET

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

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)

; IDBP OCTAL IN T, INTO BP IN W2; MUSH TT
RCHST7:	IDIVI T, 10
	HRLM TT, (P)
	CAIE T, 0
	 CALL RCHST7
	HLRZ T, (P)
	MOVEI T, "0(T)
	IDPB T, W2
	RET
] ;DEC

SUBTTL DEC - SUPPORT FOR I/O MACROS

IFN DEC,[
; TOUTC - TAKES -1(P)/ <ITSCHAN>, (P)/ <CHAR> AND OUTPUTS
TOUTC:	EXCH R1,-1(P)	; GET ICHAN
	EXCH R2,(P)	; AND CHAR
	CALL $BOUT
	 TRN
	REST R2		; RESTORE ACS AND RETURN
	REST R1
	RET

; TINC - TAKES -1(P)/ <ICHAN>, (P)/ <LOC> AND INPUTS FROM CHAN TO LOC
TINC:	EXCH R1,-1(P)		; GET CHAN
	PUSH P,R2		; SAVE R2
	CALL $BIN
	 HRROI R2, ^C		; EOF
	MOVEM R2, @-1(P)	; STORE BYTE IN DESIRED LOC
	POP P,R2		; RESTORE R2
	POP P,(P)		; FLUSH LOC FROM STACK
	POP P,R1		; RESTORE R1
	RET

; T/	DEC CHAN
M$CLS:	HRLZ T, T		; GET CHAN,,0
	HRRI T, .FOREL		; RELEASE FUNCTION
	PUSH P, T		; SAVE
	MOVEI T, (P)		; GET ADDR OF ARG
	HRLI T, 1		; ONE WORD LONG
	FILOP. T,		; TRY IT
	 TRN			; GRR
	POP P, (P)		; TOSS TOS
	RET
	SUBTTL	TOPS-10 STRING I/O

; -1(P) == CNT, -2(P) == BP, -3(P) == ITSCHAN -- CRUSHES R2
M$SIN:	EXCH R1, -3(P)		; GET CHAN
	EXCH R3, -1(P)		; SAVE R3, GET COUNT
M$SIN0:	CALL $BIN		; GET A BYTE
	 JRST M$SIN1		; EOF
	IDPB R2, -2(P)		; STORE
	SOJG R3, M$SIN0		; LOOP, TILL BUFFER FULL
M$SIN1:	EXCH R3, -1(P)		; RESTORE COUNT, R3
	MOVE R1, -3(P)		; RESTORE R1
	RET

; -1(P) == CNT, -2(P) == BP, -3(P) == ITSCHAN -- CRUSHES R2
M$SOUT:	EXCH R1, -3(P)		; SWAP CHAN FOR R1
	EXCH R3, -1(P)		; SWAP COUNT FOR R3
M$SOU0:	ILDB R2, -2(P)		; LOAD A BYTE
	CALL $BOUT		; OUTPUT IT
	 TRNA			; EOF??
	  SOJG R3, M$SOU0	; LOOP FOR COUNT
	EXCH R3, -1(P)		; RESTORE COUNT, R3
	MOVE R1, -3(P)		; RESTORE R1
	RET

	SUBTTL	TOPS-10 CHARACTER I/O

; R1/	ITS CHAN	RETURNS CHAR IN R2 <<<SKIPS>>>
$BIN:	SAVE T			; PRESERVE T
	MOVEI T, (R1)		; GET ITS CHAN
	SKIPG JFNCHS(T)		; GET IS TTY?
	 JRST $BIN5		; YES
	IMULI T, 3		; * SIZE
	MOVEI T, CHNHDR(T)	; GET HEADER ADDR
$BIN2:	SOSGE .BFCTR(T)		; ANY CHARS LEFT?
	 JRST $BIN3		; NO, FILL A BUFFER
	ILDB R2, .BFPTR(T)	; YES, LOAD OUT A BYTE
	REST T
	JRST POPJ1		; RETURN HAPPY

$BIN3:	PUSH P, T		; SAVE HEADER ADDR
	MOVE T, JFNCHS(R1)	; GET DEC CHAN
	MOVSI T, (T)		; GET CHAN,,0
	HRRI T, .FOINP		;   FUNCTION
	PUSH P, T		; SAVE ARGLIST
	MOVEI T, (P)		; ADDR THEREOF
	HRLI T, 1		; LENGTH THEREOF
	FILOP. T,		; DO INPUT
	 JRST $BIN4
	POP P, (P)		; DISCARD
	POP P, T		; RESTORE T
	JRST $BIN2

$BIN4:	TRNE T, IO.ERR
	 JRST $BIN6
	POP P, (P)
	POP P, (P)
	POP P, T
	RET			; FAILURE

$BIN5:	INCHWL R2
	CAIN R2, ^Z		; Tops-10 EOF?
	 MOVEI R2, ^C		; Yes, convert to ITS flavour
	REST T
	JRST POPJ1

$BIN6:	OUTSTR	[ASCIZ 'FATAL I/O errors']
	ERRHLT

; R1/	ITS CHAN
; R2/	CHAR TO OUTPUT
; <<<SKIPS>>>
$BOUT:	SAVE T
	MOVEI T, (R1)		; GET CHAN
	SKIPG JFNCHS(T)		; TTY?
	 JRST $BOUT5		; LOOKS THAT WAY
	IMULI T, 3		; * SIZE
	MOVEI T, CHNHDR(T)	; GET HEADER ADDR
$BOUT2:	SOSGE .BFCTR(T)		; ANY ROOM LEFT
	 JRST $BOUT3		; NO, EMPTY BUFFER
	IDPB R2, .BFPTR(T)	; YES, STORE BYTE
	REST T
	JRST POPJ1		; RETURN HAPPY

$BOUT3:	PUSH P, T		; SAVE HEADER ADDR
	MOVE T, JFNCHS(R1)	; GET DEC CHAN
	MOVSI T, (T)		; GET CHAN,,
	HRRI T, .FOOUT		;   FUNCTION
	PUSH P, T		; SAVE ARGLIST
	MOVEI T, (P)		; ADDR THEREOF
	HRLI T, 1		; LENGTH THEREOF
	FILOP. T,		; DO INPUT
	 JRST $BIN4
	POP P, (P)		; DISCARD
	POP P, T		; RESTORE T
	JRST $BIN2

$BOUT5:	OUTCHR R2
	REST T
	JRST POPJ1
] ;DEC
	SUBTTL	PURE DATA

SEG1:	SEG1A		;START OF SEGMENT FOR FILE 1 LINES
SEG2:	SEG2A		;START OF SEGMENT FOR FILE 2 LINES
SEG3:	SEG3A		;START OF SEGMENT FOR FILE 3 LINES

	SUBTTL	IMPURE DATA

VARS::
VARIABLES

PATCH:	BLOCK 100

BEGP::				;BEGINNING OF STORAGE ZEROED AT INIT.
JUNK:	0			;BLACK HOLE FOR TNX I/O MACROS 
PPSET:	BLOCK	LPDL		;PUSH DOWN LIST STORAGE
	BLOCK	20		; PADDING?

IFN TNX,[
STSWRD:	BLOCK 1			; SIXBIT STATE WORD
]

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
]
IFN DEC,[
RCHSTB:	BLOCK .FOFMX+1		;RETURN FROM 7.02 .FOFIL FILOP
]
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

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

; FOR BINARY COMPARE MODE
GWORDL:	BLOCK 3			; # words length of file
GWORDC:	BLOCK 3			; # words left in file
GWORDB:	-1 ? -1 ? -1		; WORD POINTER INTO BUFFER

; 20X COMND STUFF
IFN 20X,[
LATMBF==20			; atom buffer length
LSTRBF==100			; string buffer length
CMDBLK:
CMFLG::	TOPREP			; FLAGS + REPARSE
CMJFN::	.PRIIN,,.PRIOU		; JFNS
CMRTY::	0			; BP TO PROMPT
	-1,,STRBUF
	-1,,STRBUF
CMCNT::	5*LSTRBF
	0
	-1,,ATMBUF
	5*LATMBF
	CMDGTJ

STRBUF:	BLOCK	LSTRBF
ATMBUF:	BLOCK	LATMBF
CMDGTJ:	BLOCK	20		; COMND GTJFN BLOCK

NOIBLK:	FLDDB. .CMNOI		;PROTOTYPE FOR NOISE; BLAM .CMDAT
IFIBLK:	FLDDB. .CMIFI,CM%SDH,,[INPUT FILE] ;PROTO INPUT FILE; BLAM .CMHLP
OFIBLK:	FLDDB. .CMOFI,CM%SDH,,[OUTPUT FILE] ;PROTO OUTPUT FILE; BLAM .CMHLP
FILBLK:	FLDDB. .CMFIL,CM%SDH,,[FILE] ;PROTO FILE; BLAM .CMHLP
DFIBLK:	FLDDB. .CMFIL,<CM%SDH\CM%DPP>,,[old file] ; proto file1; blam .CMDEF
] ;20X

IFN DEC,[
HLPFIL:	SIXBIT 'SRCCOM'
	SIXBIT 'HLP'
	0 ? 0
OPNBLK:	BLOCK .FOFSP+1
LKBLK:	.RBSIZ			; ARGS TO FOLLOW
	BLOCK .RBSIZ		; PPN, NAM, EXT, PRV, SIZ
JOBFF:	BLOCK 1			; COPY OF ORIGIBAL .JBFF
] ;DEC

CONST:
CONSTANTS

FOO::
VARIABLES
	-1
ENDCOR:
; Local modes:
; Comment begin:; 
; End:
IFN ITS\DEC,END BEG
IFN TNX,END <3,,EVEC>
