Google
 

Trailing-Edge - PDP-10 Archives - bb-m836c-bm_tops20_v6_1_tools - tools/redit/redit.mac
There are 8 other files named redit.mac in the archive. Click here to see a list.
;<V-SOURCES>REDIT.MAC.15, 22-Sep-83 11:17:24, EDIT BY MURPHY
;Optional output of failed changes to file.
;<V-SOURCES>REDIT.MAC.14,  3-May-83 16:57:09, EDIT BY MURPHY
;Handle unexpected EOF in RED file during MERGE/UNMERGE.
;Note superfluous change in RED file.
;<V-SOURCES>REDIT.MAC.13, 29-Apr-83 18:12:53, EDIT BY MURPHY
;Check for superfluous changes and report them.
;<V-SOURCES>REDIT.MAC.12, 11-Oct-82 17:35:03, EDIT BY MURPHY
;Increase size of command line buffer.
;Increase number lines buffered.
;<MURPHY.1>REDIT.MAC.30,  7-Dec-81 11:55:09, EDIT BY MURPHY
;Fix handling of nulls in input files.
;<MURPHY.1>REDIT.MAC.29, 13-Oct-81 17:19:08, EDIT BY MURPHY
;Fix UNMERGE command.
;<MURPHY.1>REDIT.MAC.25,  3-Aug-81 16:36:39, EDIT BY MURPHY
;Fix bug with changes files having ***** in them.
;<MURPHY.1>REDIT.MAC.23, 20-Jul-81 12:06:30, EDIT BY MURPHY
;Fix bug in parse of MERGE command.
;<MURPHY.1>REDIT.MAC.22, 16-Jul-81 17:07:47, EDIT BY MURPHY
;Real entry vector and version number
;Header in RED file to identify source files.
;Check for ambiguous changes
;<MURPHY.1>REDIT.MAC.14, 14-Jul-81 14:27:38, EDIT BY MURPHY
;Get initialization in right place.
;<MURPHY.1>REDIT.MAC.13,  1-Jul-81 14:45:40, EDIT BY MURPHY
;UNMERGE COMMAND
;NOTE WHEN CHANGE ALREADY MADE
;USE RED AS DEFAULT EXTENSION
;HANDLE RESCAN LINE
;ASSUME INSERT AT BEGINNING ONLY IF FIRST LINES DON'T MATCH
;<MURPHY>REDIT.MAC.3, 13-Oct-80 12:25:30, EDIT BY MURPHY
;FIX ACVAR
;<MURPHY>REDIT.MAC.1,  8-Oct-80 12:33:59, EDIT BY MURPHY
;INCLUDE ONE LINE AFTER CHANGE TO DETECT INSERTION CONFLICTS
;<MURPHY.DDT>REDIT.MAC.3, 10-Jun-80 13:47:28, EDIT BY MURPHY
;NORMALIZE CRLF SEQUENCES
;<MURPHY>REDIT.MAC.31,  6-Jun-77 22:58:49, EDIT BY MURPHY
;<MURPHY>REDIT.MAC.28,  1-APR-76 17:56:40, EDIT BY MURPHY

	TITLE REDIT
	SALL
	.DIRECT FLBLST
	SEARCH MONSYM,MACSYM
	.REQUIRE SYS:MACREL
	SUBTTL DEFINITIONS

;VERSION INFO

VERS==1
VUPDAT==0
VEDIT==104
VCUST==0

;VARIOUS DEFS

DEFINE SCALL (NAM,ARGS)<
	..AC==T1
	IRP ARGS,<
	  MOVE ..AC,ARGS
	  ..AC=..AC+1>
	CALL NAM>

;GENERAL ERROR

DEFINE ERROR (TAG,MSG)<
	JRST [	TMSG <
MSG
>
		JRST TAG]>

;ERROR WITH JSYS MESSAGE

DEFINE ERRORJ (TAG,MSG)<
	JRST [	TMSG <
MSG, >
		CALL JSERRM
		JRST TAG]>

DEFINE TXTPTR (MSG)<POINT 7,[ASCIZ \MSG\]>
;INITIAL PARAMETERS

IMINDI==^D5			;MINIMUM DIFFERENCE
INMAT==^D5			;NUMBER LINES FOR MATCH
MAXCHL==^D140			;MAX CHARS/LINE

;ACS

T1=1
T2=2
T3=3
T4=4

P=17
;16,15 USED BY MACSYM
BP1=14				;BLOCK POINTER 1
BP2=13				;BLOCK POINTER 2
F=0				;FLAGS

;FLAGS

TOPF==1B0			;TOP OF FILE
UNMF==1B1			;UNMERGE COMMAND
TRYUF==1B2			;TRYING FOR CHANGE ALREADY MADE
RSCF==1B3			;DOING RESCAN COMMAND
SDUPF==1B4			;SEARCH FOR DUPLICATE IN PROGRESS
DUPF==1B5			;DO DUPLICATE SEARCHES
JUNKL==1B6			;JUNK LINE FOUND
JUNKC==1B7			;JUNK CHANGE POSSIBLE
BPEOF==1B8			;EOF DETECTED IN BUMPL

;STRUCTURE OF POINTER BLOCK

BFA==0				;LINE POINTER TABLE ORIGIN
BFA2==1				;MID-POINT OF LINE POINTER TABLE
NL==2				;NEXT LINE IN LINE POINTER TABLE
FRE==3				;FREE WORD IN LINE POINTER TABLE
INJFN==4			;INPUT JFN
SFRE==5				;STRING FREE ORIGIN
SBFR==6				;STRING BUFFER ORIGIN
ESBFR==7			;END OF STRING BUFFER
INCNT==10			;INPUT BUFFER COUNT
IPTR==11			;INPUT BYTE POINTER
BFADR==12			;ADDRESS OF FILE BUFFER
PAGLIN==13			;page number,,line number
IPAGLN==14			;paglin at start of difference
SAVECH==15			;SAVED CHARACTER FOR NEXT CIN
 NBPW==16			;NUMBER WORDS IN POINTER BLOCK
;STORAGE

PGSIZ==1000

	LOC 20000

MINDIF:	BLOCK 1			;MINIMUM NUMBER LINES DIFFERENCES OUTPUT
NMATCH:	BLOCK 1			;NUMBER LINES FOR MATCH AFTER DIFFERENCE
MAXDIF:	BLOCK 1			;MAXIMUM NUMBER LINES DIFFERENT
CNGNO:	BLOCK 1			;CHANGE NUMBER
NJUNK:	BLOCK 1			;NUMBER JUNK CHANGES FOUND

;COMND STORAGE

CBFSIZ==^D400/5
CBFR:	BLOCK CBFSIZ		;COMMAND LINE BUFFER
ACBSIZ==^D400/5
ACBFR:	BLOCK ACBSIZ		;ATOM BUFFER
CBLK:	BLOCK .CMGJB+1		;COMMAND STATE BLOCK
GJBLK:	BLOCK .GJBFP+1

DEFDIR:	BLOCK 10
DEFNAM:	BLOCK 10
DEFEXT:	BLOCK 10
DEFVER:	BLOCK 10

INL1:	BLOCK 1			;FIRST LINE OF DIFFERENCE
INL2:	BLOCK 1			; "
INL3:	BLOCK 1			;FIRST LINE OF CHANGE BLOCK
INL4:	BLOCK 1			;END OF CHANGE BLOCK

CINL1:	BLOCK 1			;SAVED VARIABLES DURING DUP SEARCH
CINL2:	BLOCK 1
CINL3:	BLOCK 1
CINL4:	BLOCK 1

BBP1:	BLOCK NBPW		;POINTER BLOCK
BBP2:	BLOCK NBPW

NLMAX==^D1600			;MAX NUMBER LINES BUFFERED
LPTR1:	BLOCK NLMAX*^D20		;LINE POINTER TABLES
LPTR2:	BLOCK NLMAX

NBUF==NLMAX*^D10		;SIZE OF STRING BUFFERS
BUF1:	BLOCK NBUF*^D10		;STRING BUFFERS
EBUF1:	BLOCK 0
BUF2:	BLOCK NBUF
EBUF2:	BLOCK 0

FBUF1:	BLOCK PGSIZ		;FILE BUFFERS
FBUF2:	BLOCK PGSIZ
FBUFO:	BLOCK PGSIZ
NCHBF==PGSIZ*5

OUTCNT:	BLOCK 1			;OUTPUT FILE BUFFER COUNT
OPTR:	BLOCK 1			;OUTPUT BYTE PTR
OUTJFN:	BLOCK 1			;OUTPUT JFN
FAIJFN:	BLOCK 1			;JFN FOR FAILED CHANGES
LSTRNG==^D200			;TEMP STRING BUFFER
STRING:	BLOCK LSTRNG/5

NPDL==100			;SIZE OF PDL
PDL:	BLOCK NPDL		;PDL

	RELOC 0
	SUBTTL START AND INITIALIZE

EVEC:	JRST START
	JRST START
	BYTE (3)VCUST(9)VERS(6)VUPDAT(18)VEDIT
LEVEC==.-EVEC

;DEFAULT FLAGS

DEFF:	DUPF			;DO DUPLICATE SEARCHES

START:
	MOVE P,[IOWD NPDL,PDL]
	RESET
	MOVEI T1,IMINDI
	MOVEM T1,MINDIF
	MOVEI T1,INMAT
	MOVEM T1,NMATCH
	MOVE F,DEFF		;DEFAULT FLAGS
	MOVEI T1,NLMAX-^D100
	MOVEM T1,MAXDIF
	MOVEI T1,.RSINI
	RSCAN%			;GET RESCAN LINE IF ANY
	 ERJMP .+1
	MOVEI T1,.RSCNT
	RSCAN%			;SEE IF RESCAN CHARACTERS
	 SETZ T1,		;ASSUME NO
	CAIE T1,0		;ARE THERE?
	TXO F,RSCF		;YES
	MOVE T1,[ICBLK,,CBLK]	;INIT COMMAND STATE BLOCK
	BLT T1,CBLK+.CMGJB
	SETO T1,
	CLOSF
	 JFCL
	RLJFN
	 JFCL
	SETOM FAIJFN
	; ..
;TOP OF COMMAND LOOP

RESTRT:	MOVE P,[IOWD NPDL,PDL]	;RESET STACK
	SETZM CNGNO
	SETZM NJUNK
	CALL INIBLK		;INIT BUFFER BLOCKS
	MOVEI T1,CBLK
	IFXN. F,RSCF		;DOING RESCAN LINE?
	  MOVEI T2,.NULIO	;YES, NO TTY OUTPUT
	  HRRM T2,.CMIOJ(T1)
	ENDIF.
	MOVEI T2,[FLDDB. .CMINI]
	COMND
REPAR1:	MOVEI T1,CBLK
	IFXN. F,RSCF		;DOING RESCAN LINE?
	  MOVEI T2,[FLDDB. .CMTOK,,<TXTPTR <REDIT>>]
	  COMND			;YES, SHOULD START WITH PROGRAM NAME
	  TXNE T1,CM%NOP	;DID IT?
	  JRST NORSC		;NO
	ENDIF.
	MOVEI T2,[FLDDB. .CMKEY,,CTBL,<COMMAND NAME>]
	COMND			;GET KEYWORD
	TXNN T1,CM%NOP
	IFSKP.
	  JXN F,RSCF,NORSC	;NOT A VALID RESCAN LINE, FORGET IT
	  ERROR RESTRT,<?NOT A DEFINED COMMAND>
	ENDIF.
	HRRZ T2,0(T2)		;GET DISPATCH
	JRST 0(T2)		;DO IT

;REPARSE DISPATCH

REPAR0:	JRST REPAR1		;RETRY

;REJECT RESCAN LINE

NORSC:	MOVEI T2,.PRIIN		;FLUSH RESCAN LINE, DO NORMAL COMMAND
	HRRM T2,.CMIOJ(T1)
	TXZ F,RSCF
	JRST RESTRT

;COMMAND COMPLETED

CDONE:	TXZE F,RSCF		;WAS A RESCAN COMMAND?
	HALTF			;YES, DONE
	JRST RESTRT
;CONFRM - PRESERVES ALL ACS

CONFRM:	PUSH P,T1
	PUSH P,T2
	PUSH P,T3
	MOVEI T1,CBLK
	MOVEI T2,[FLDDB. .CMCFM]
	COMND
	TXNE T1,CM%NOP
	ERROR RESTRT,<?NOT CONFIRMED>
	POP P,T3
	POP P,T2
	POP P,T1
	RET

;INITIAL COMND STATE BLOCK

ICBLK:	REPAR0
	.PRIIN,,.PRIOU
	POINT 7,[ASCIZ /REDIT>/]
	POINT 7,CBFR
	POINT 7,CBFR
	CBFSIZ*5
	0
	POINT 7,ACBFR
	ACBSIZ*5
	GJBLK
;COMMAND DISPATCH TABLE

DEFINE TB (DAT,TXT)<
	XWD [ASCIZ \TXT\],DAT>

CTBL:	NCTBL,,NCTBL
	TB $CMP,<COMPARE>
	TB $EXIT,<EXIT>
	TB $FAICH,<FAILED-CHANGES>
	TB $HELP,<HELP>
	TB $MERGE,<MERGE>
	TB $MINM,<MINIMUM>
	TB $NOVER,<NOVERIFY>
	TB $UNMRG,<UNMERGE>
	TB $VERIF,<VERIFY>
NCTBL==.-CTBL-1

;COMMANDS...

;EXIT

$EXIT:	CALL CONFRM
	HALTF
	JRST CDONE

;HELP

$HELP:	CALL CONFRM
	HRROI T1,HLPMSG
	PSOUT
	JRST CDONE

HLPMSG:	ASCIZ /
REDIT is used to duplicate changes which have been made in source
files.  If there is a source A and a modified version A', and
we wish to make the same modifications to a related source B so
as to produce B', the following steps are performed:

1. COMPARE A' with A to produce the changes file C.

2. MERGE the changes file C with source B to produce B'.

This assumes that A and B are similar, perhaps derived from
a single source via different development paths.  In particular,
the areas which were modified in A to produce A' must be
present in B.  If this is not so, an error message will be
produced during the MERGE for any change which could not
be duplicated.  This typically occurs because changes were made
in the same areas in both A and B, and manual resolution of
the conflict is required.

The commands are:

"COMPARE" compares a "new source" with a previous version to
	produce a "changes file" which can be given to a subsequent
	"MERGE".

"MERGE" merges a "changes file" with a related source to
	produce a new version of the source.

"UNMERGE" removes the changes represented by a "changes file"
	from a source.  This undoes the effects of a MERGE
	of the same changes file.

"MINIMUM" sets the number of lines of 'context' to be found
	for each change.  The number of lines of text preceding
	the actual change will be included in the changes file.

"FAILED-CHANGES" specifies an output filespec to be used during
	the next MERGE or UNMERGE operation.  Any changes which
	are not found will be written to this file in standard
	RED format so that additional attempts at merging
	these changes may be made.

"VERIFY" is effective only during a MERGE or UNMERGE command.  It causes
	REDIT to verify that the context for each change is not
	ambiguous by searching the entire file for the context.
	The context must be found exactly once.  If it is found
	multiple times, the change is flagged as ambiguous as
	is not made.  "NOVERIFY" causes REDIT to accept the first
	matching context found and not check for multiple matching contexts.

Definition: A superfluous difference is one which exists only
	because blanks have been added to or removed from the
	end of lines.

/
;FAILED-CHANGES (TO FILE)

$FAICH:	MOVEI T2,[FLDDB. .CMNOI,,<TXTPTR <TO FILE>>]
	COMND
	SETZM GJBLK+.GJDIR	;FLUSH DEFAULTS
	SETZM GJBLK+.GJNAM
	HRROI T2,[ASCIZ /RED/]
	MOVEM T2,GJBLK+.GJEXT	;SET USUAL DEFAULT EXT
	MOVX T2,GJ%FOU+GJ%MSG
	MOVEM T2,GJBLK+.GJGEN
	MOVEI T2,[FLDDB. .CMFIL,,,<NAME OF OUTPUT FILE FOR FAILED CHANGES>]
	COMND
	TXNE T1,CM%NOP
	ERRORJ RESTRT,<?INVALID DESTINATION FILE>
	CALL CONFRM
	MOVEM T2,FAIJFN		;SET THE JFN
	MOVE T1,FAIJFN
	MOVX T2,<FLD(7,OF%BSZ)+OF%WR>
	OPENF
	 JSHLT
	JRST CDONE

;MINIMUM LINES FOR MATCH

$MINM:	MOVEI T2,[FLDDB. .CMNOI,,<TXTPTR <LINES TO MATCH>>]
	COMND
	MOVEI T2,[FLDDB. .CMNUM,,^D10]
	COMND
	TXNE T1,CM%NOP
	ERROR RESTRT,<?NOT A DECIMAL NUMBER>
	CALL CONFRM
	MOVEM T2,MINDIF
	JRST CDONE

;VERIFY/NOVERIFY CHANGE CONTEXT

$NOVER:	TDZA T4,T4
$VERIF:	SETO T4,
	MOVEI T2,[FLDDB. .CMNOI,,<TXTPTR <CHANGE CONTEXT>>]
	COMND
	CALL CONFRM
	SKIPE T4
	TXOA F,DUPF		;VERIFY
	TXZ F,DUPF		;NO VERIFY
	JRST CDONE
;COMPARE NEW-SOURCE OLD-SOURCE DIFFERENCES

$CMP:	MOVEI T2,[FLDDB. .CMNOI,,<TXTPTR <NEW SOURCE FILE>>]
	COMND
	SETZM GJBLK+.GJDIR	;FLUSH DEFAULTS
	SETZM GJBLK+.GJNAM
	SETZM GJBLK+.GJEXT
	MOVX T2,GJ%OLD
	MOVEM T2,GJBLK+.GJGEN	;SET TO GET EXISTING FILE
	MOVEI T2,[FLDDB. .CMFIL,,,<NEW SOURCE FILE>]
	COMND
	TXNE T1,CM%NOP
	ERRORJ RESTRT,<?INVALID SOURCE FILE>
	MOVEM T2,INJFN(BP2)
	MOVEI T2,[FLDDB. .CMNOI,,<TXTPTR <WITH FILE>>]
	COMND
	SCALL SETFDF,<INJFN(BP2)> ;SET DEFAULTS FROM FIRST FILE
   REPEAT 0,<			;default to previous generation - not used
	HRROI T1,DEFVER		;GET GENERATION NUMBER FROM FIRST FILE
	MOVE T2,INJFN(BP2)
	MOVX T3,1B14
	JFNS
	HRROI T1,DEFVER
	MOVEI T3,^D10
	NIN
	 JSERR
	SOS T2			;DEFAULT TO ONE BEFORE THAT
	MOVEM T2,GJBLK+.GJGEN
   >				;end repeat 0
	MOVX T2,GJ%OLD
	MOVEM T2,GJBLK+.GJGEN
	MOVEI T1,CBLK
	MOVEI T2,[FLDDB. .CMFIL,,,<OLD VERSION OF SOURCE>]
	COMND
	TXNE T1,CM%NOP
	ERRORJ RESTRT,<?INVALID SOURCE FILE>
	MOVEM T2,INJFN(BP1)
	MOVEI T2,[FLDDB. .CMNOI,,<TXTPTR <CHANGES TO>>]
	COMND
	HRROI T2,[ASCIZ /RED/]
	MOVEM T2,GJBLK+.GJEXT	;SET SPECIFIC DEFAULT EXT
	MOVX T2,GJ%FOU+GJ%MSG
	MOVEM T2,GJBLK+.GJGEN
	MOVEI T2,[FLDDB. .CMFIL,,,<CHANGE FILE>]
	COMND
	TXNE T1,CM%NOP
	ERRORJ RESTRT,<?INVALID DESTINATION FILE>
	MOVEM T2,OUTJFN
	CALL CONFRM
	CALL FILSET		;OPEN FILES
	CALL WRFID		;WRITE FILE ID LINES
	CALL CMP		;DO THE WORK
	CALL FILFIN		;CLOSE FILES
	JRST CDONE
;WRITE IDENTIFICATION LINES AT BEGINNING OF CHANGE FILE

WRFID:	HRROI T1,[ASCIZ /REDIT /]
	CALL STOUT
	HRROI T1,STRING
	LOAD T2,VI%MAJ,EVEC+2	;MAJOR VERSION
	MOVEI T3,^D8
	NOUT
	 JSERR
	LOAD T2,VI%MIN,EVEC+2
	IFN. T2
	  ADDI T2,"A"-1
	  IDPB T2,T1
	ENDIF.
	MOVEI T2,"("
	IDPB T2,T1
	LOAD T2,VI%EDN,EVEC+2
	NOUT
	 JSERR
	MOVEI T2,")"
	IDPB T2,T1
	SETZ T2,
	IDPB T2,T1
	HRROI T1,STRING
	CALL STOUT
	HRROI T1,[ASCIZ / COMPARE by user /]
	CALL STOUT
	GJINF%
	MOVE T2,T1
	HRROI T1,STRING
	DIRST%
	 JSHLT
	HRROI T1,STRING
	CALL STOUT
	HRROI T1,[ASCIZ /, /]
	CALL STOUT
	HRROI T1,STRING
	SETO T2,		;CURRENT TAD
	MOVX T3,<OT%SCL>	;NO TABS
	ODTIM%
	 ERJMP [JSERR
		JRST .+1]
	HRROI T1,STRING
	CALL STOUT
	HRROI T1,[ASCIZ /
File 1: /]
	CALL STOUT
	HRROI T1,STRING
	MOVE T2,INJFN(BP1)	;OLD SOURCE
	MOVE T3,JSFLGS
	JFNS%			;RENDER FILE NAME
	HRROI T1,STRING
	CALL STOUT		;SEND IT TO RED FILE
	HRROI T1,[ASCIZ /
File 2: /]
	CALL STOUT
	HRROI T1,STRING
	MOVE T2,INJFN(BP2)	;NEW SOURCE
	MOVE T3,JSFLGS
	JFNS%
	HRROI T1,STRING
	CALL STOUT
	HRROI T1,[ASCIZ /
/]
	CALL STOUT
	RET

JSFLGS:	1B2+1B5+1B8+1B11+1B14+JS%PAF
;UPDATE DIFFERENCES SOURCE NEW-SOURCE

$UNMRG:	TXOA F,UNMF		;SAY WHICH COMMAND
$MERGE:	TXZ F,UNMF
	MOVEI T2,[FLDDB. .CMNOI,,<TXTPTR <CHANGES FROM>>]
	COMND
	SETZM GJBLK+.GJDIR	;FLUSH DEFAULTS
	SETZM GJBLK+.GJNAM
	HRROI T2,[ASCIZ /RED/]
	MOVEM T2,GJBLK+.GJEXT	;STANDARD DEFAULT EXT
	MOVX T2,GJ%OLD
	MOVEM T2,GJBLK+.GJGEN
	MOVEI T2,[FLDDB. .CMFIL,,,<REDIT CHANGE FILE>]
	COMND
	TXNE T1,CM%NOP
	ERRORJ RESTRT,<?INVALID CHANGE FILESPEC>
	MOVEM T2,INJFN(BP2)
	MOVEI T2,[FLDDB. .CMNOI,,<TXTPTR <WITH SOURCE>>]
	COMND
	SCALL SETFDF,<INJFN(BP2)> ;SET DEFAULTS FROM FIRST FILE
	SETZM GJBLK+.GJEXT	;BUT NOT EXTENSION
	MOVX T2,GJ%OLD
	MOVEM T2,GJBLK+.GJGEN
	MOVEI T1,CBLK
	MOVEI T2,[FLDDB. .CMFIL,,,<SOURCE TO BE UPDATED>]
	COMND
	TXNE T1,CM%NOP
	ERRORJ RESTRT,<?INVALID SOURCE FILESPEC>
	MOVEM T2,INJFN(BP1)
	MOVEI T2,[FLDDB. .CMNOI,,<TXTPTR <TO>>]
	COMND
	SCALL SETFDF,<INJFN(BP1)> ;SET DEFAULTS FROM SECOND FILE
	MOVX T2,GJ%FOU+GJ%MSG
	MOVEM T2,GJBLK+.GJGEN
	MOVEI T1,CBLK
	MOVEI T2,[FLDDB. .CMFIL,,,<NEW SOURCE>]
	COMND
	TXNE T1,CM%NOP
	ERRORJ RESTRT,<?INVALID DESTINATION FILE>
	MOVEM T2,OUTJFN
	CALL CONFRM
	CALL FILSET		;OPEN FILES
	CALL SCH		;DO THE WORK
	CALL FILFIN		;CLOSE FILES
	JRST CDONE
;SETUP FILES

FILSET:	MOVE T1,INJFN(BP1)
	MOVX T2,<FLD(7,OF%BSZ)+OF%RD>
	OPENF
	 JSHLT
	MOVE T1,INJFN(BP2)
	MOVX T2,<FLD(7,OF%BSZ)+OF%RD>
	OPENF
	 JSHLT
	MOVE T1,OUTJFN
	MOVX T2,<FLD(7,OF%BSZ)+OF%WR>
	OPENF
	 JSHLT
	SETZM INCNT(BP1)	;INIT BUFFERS
	SETZM INCNT(BP2)
	CALLRET FBFINI

;FINISH FILES

FILFIN:	CALL FBFOUT		;DUMP LAST BUFFER
	MOVE T1,OUTJFN
	CLOSF
	 JFCL
	SKIPL T1,INJFN(BP1)
	CLOSF
	 JFCL
	SKIPL T1,INJFN(BP2)
	CLOSF
	 JFCL
	RET

;SET FILE DEFAULTS
; T1/ JFN

SETFDF:	ACVAR <JFN,P1>
	MOVEM T1,JFN		;SAVE SOURCE JFN
	MOVSI P1,-NJFLD		;NUMBER OF FIELDS TO DO
SETFD1:	HRRO T1,JFLD1(P1)	;DEFAULT STRING BUFFER
	MOVEM T1,GJBLK+.GJNAM(P1)
	MOVE T2,JFN
	MOVE T3,JFLD2(P1)	;BIT FOR JFNS
	JFNS
	AOBJN P1,SETFD1
	RET

JFLD1:	GJ%NAM+DEFNAM
	GJ%EXT+DEFEXT
NJFLD==.-JFLD1

JFLD2:	1B8
	1B11

	ENDAV.
	SUBTTL MAIN COMPARE LOOP

CMP:	ACVAR <P1,P2>
	TXO F,TOPF		;NOTE NOW AT TOP
	TXZ F,JUNKC		;NO JUNK CHANGE YET
	MOVE T1,[1,,1]		;init page and line numbers
	MOVEM T1,PAGLIN(BP1)
	MOVEM T1,PAGLIN(BP2)
CMPLP:	SCALL FILL,<BP1>	;FILL BOTH BUFFERS IF NECESSARY
	SCALL FILL,<BP2>
	SCALL LCOMP,<NL(BP1),NL(BP2)> ;COMPARE ONE LINE
	JUMPN T1,DIF1		;JUMP IF DIFFERENT
	TXZ F,TOPF		;NORMAL CHANGE HEREAFTER
	SCALL BUMPL,<BP1>	;INCREMENT LINE
	MOVE T1,NL(BP1)
	CAML T1,BFA2(BP1)	;LINE BUFFER HALF FULL?
	JRST [	SCALL SHIFT,<BP1> ;YES, SHIFT IT DOWN
		JRST .+1]
	SCALL BUMPL,<BP2>	;INCREMENT LINE
	MOVE T1,NL(BP2)
	CAML T1,BFA2(BP2)	;DITTO
	JRST [	SCALL SHIFT,<BP2>
		JRST .+1]
	MOVE T1,NL(BP1)
	MOVE T2,NL(BP2)
	CAML T1,FRE(BP1)	;BOTH AT EOF?
	CAMGE T2,FRE(BP2)
	JRST CMPLP		;NO, CONTINUE SCAN
	MOVE T2,CNGNO		;DONE, SEE HOW MANY CHANGES
	CAIE T2,1		;EXACTLY ONE?
	IFSKP.
	  TMSG <There was one change found>
				;GET THE GRAMMAR RIGHT
	ELSE.
	IFE. T2
	  TMSG <There were no changes found>
	ELSE.
	  TMSG <There were >
	  MOVEI T1,.PRIOU
	  MOVE T2,CNGNO
	  MOVEI T3,^D10
	  NOUT
	   NOP
	  TMSG < changes found>
	ENDIF.
	ENDIF.
	SKIPG NJUNK		;ANY JUNK CHANGES?
	IFSKP.
	  TMSG <,
 of which >
	  MOVE T2,NJUNK
	  CAIE T2,1		;GET THE GRAMMAR RIGHT
	  IFSKP.
	   TMSG <one was superfluous>
	  ELSE.
	   MOVEI T1,.PRIOU
	   MOVEI T3,^D10
	   NOUT
	    NOP
	   TMSG < were superfluous>
	  ENDIF.
	ENDIF.
	TMSG <.
>
	RET			;YES, DONE
;FOUND ONE LINE DIFFERENT, BEGIN SCAN TO LOOK FOR MATCH

DIF1:	TXNE F,JUNKL		;A JUNK DIFFERENCE?
	TXO F,JUNKC		;YES, POSSIBLE JUNK CHANGE HERE
	SCALL SHIFT,<BP1>	;SHIFT OUT ALL GOOD STUFF
	SCALL SHIFT,<BP2>
	MV. PAGLIN(BP1),IPAGLN(BP1) ;and line numbers
	MV. PAGLIN(BP2),IPAGLN(BP2)
	MV. NL(BP1),INL1		;SAVE START OF DIFFERENCE AREA
	MV. NL(BP2),INL2
	MOVE P2,MAXDIF		;INIT COUNT
DIF4:	SCALL BUMPX,<BP1>	;MOVE TO NEXT LINE IN EACH FILE
	SCALL BUMPX,<BP2>
	SCALL FILL,<BP1>	;ADD TEXT TO BUFFERS
	SCALL FILL,<BP2>
	SCALL LCOMPN,<NL(BP1),NL(BP2)> ;COMPARE LAST GROUP IN EACH FILE
	JUMPE T1,MCH
	TXNE F,JUNKL		;A JUNK DIFFERENCE?
	TXON F,JUNKC		;YES, STILL POSSIBLE JUNK CHANGE
	TXZ F,JUNKC		;NOT POSSIBLE JUNK CHANGE
	MOVE P1,NL(BP2)		;COMPARE FILE 1 WITH ALL GROUPS IN FILE 2
DIF2:	SOS P1			;BACKUP ONE LINE IN FILE 2
	SCALL LCOMPN,<NL(BP1),P1> ;COMPARE GROUP OF LINES
	JUMPE T1,[MOVEM P1,NL(BP2) ;MATCH, UPDATE CURRENT LINE
		TXZ F,JUNKC	;NOT A JUNK CHANGE IF LINE ADDED
		JRST MCH]
	CAMLE P1,INL2		;DONE ALL GROUPS IN FILE 2?
	JRST DIF2		;NO
	MOVE P1,NL(BP1)		;COMPARE FILE 2 WITH ALL GROUPS IN FILE 1
DIF3:	SOS P1			;BACKUP ONE LINE IN FILE 1
	SCALL LCOMPN,<P1,NL(BP2)> ;COMPARE GROUP OF LINES
	JUMPE T1,[MOVEM P1,NL(BP1) ;MATCH, UPDATE CURRENT LINE
		TXZ F,JUNKC	;NOT A JUNK CHANGE IF LINE ADDED
		JRST MCH]
	CAMLE P1,INL1		;DONE ALL GROUPS IN FILE 1?
	JRST DIF3		;NO
	SOJG P2,DIF4		;YES, STILL NO MATCH
	TMSG <?APPARENT CHANGE OF At LEAST >
	MOVEI T1,.PRIOU
	MOVE T2,MAXDIF
	MOVX T3,^D10
	NOUT
	 JSERR
	TMSG < LINES, FILES CANNOT BE COMPARED.
>
	HALTF
;HAVE FOUND MATCH, OUTPUT DIFFERENCES TO FILE

MCH:	HRROI T1,[ASCIZ /***** CHANGE #/]
	CALL STOUT
	AOS T1,CNGNO
	CALL NOUT10
	HRROI T1,[ASCIZ /; PAGE /]
	CALL STOUT
	HLRZ T1,IPAGLN(BP1)
	CALL NOUT10
	HRROI T1,[ASCIZ /, LINE /]
	CALL STOUT
	HRRZ T1,IPAGLN(BP1)
	CALL NOUT10
	HRROI T1,[ASCIZ /; PAGE /]
	CALL STOUT
	HLRZ T1,IPAGLN(BP2)
	CALL NOUT10
	HRROI T1,[ASCIZ /, LINE /]
	CALL STOUT
	HRRZ T1,IPAGLN(BP2)
	CALL NOUT10
	TXZN F,JUNKC		;A JUNK CHANGE?
	IFSKP.
	  AOS NJUNK		;YES
	  HRROI T1,[ASCIZ / (superfluous)/]
	  CALL STOUT
	ENDIF.
	MOVEI T1,.CHLFD
	CALL COUT
	TXZE F,TOPF		;WERE AT TOP?
	JRST MCH1		;YES, NO OUTPUT
	SCALL BUMPL,<BP1>	;INCLUDE ONE LINE AFTER CHANGE
	SCALL BUMPL,<BP2>
	SCALL BFOUT,<BP1>	;OUTPUT BUFFER 1
MCH1:	MOVEI T1,.CHESC
	CALL COUT
	HRROI T1,[ASCIZ / ---------------------------------
/]
	CALL STOUT
	SCALL BFOUT,<BP2>
	MOVEI T1,.CHESC
	CALL COUT
	MOVEI T1,.CHLFD
	CALL COUT
	MOVE P1,INL1		;reset to initial line
	EXCH P1,NL(BP1)
	CAMLE P1,NL(BP1)	;have moved past change?
	JRST [	SCALL BUMPL,<BP1> ;no, step line and account position
		JRST .-1]
	MOVE P1,INL2		;ditto
	EXCH P1,NL(BP2)
	CAMLE P1,NL(BP2)
	JRST [	SCALL BUMPL,<BP2>
		JRST .-1]
	SCALL SHIFTA,<BP1>	;SHIFT OUT COMPLETED STUFF
	SCALL SHIFTA,<BP2>
	JRST CMPLP

	ENDAV.
	SUBTTL MERGE and UNMERGE

;UPDATE SECTION, SEARCH AND REPLACE

SCH:
SCH0:	TXZ F,TRYUF!SDUPF	;NOT TRYING ALTERNATE MATCH OR SEARCH FOR DUP
	SCALL FILL,<BP2>	;GET MORE DIFFERENCES
	MOVE T1,NL(BP2)
	MOVEI T2,[ASCIZ /***** CHANGE #/]
	CALL SCOMP		;FIND BEGINNING OF NEXT REPLACE
	IFL. T1			;IF NO MATCH
	  SCALL BUMPL,<BP2>
	  MOVE T1,NL(BP2)
	  CAML T1,FRE(BP2)	;AT EOF?
	  JRST SCH8		;YES
	  JRST SCH0
	ENDIF.
	SCALL BUMPL,<BP2>
	JXN F,BPEOF,UXEOF	;CHECK FOR UNEXPECTED EOF
SCHTR:	MV. NL(BP2),INL3	;SAVE BEG OF CHANGE BLOCK
	IFXN. F,UNMF!TRYUF	;IF UNMERGE OR TRYING FOR ALTERNATE MATCH
	  SCALL STPESC,<BP2>	;STEP TO FIRST ESC IN CHANGE BLOCK
	  SCALL BUMPL,<BP2>	;AND SKIP DIVIDING LINE
	  JXN F,BPEOF,UXEOF	;CHECK FOR UNEXPECTED EOF
	ENDIF.
	; ..
;FIND FIRST MATCHING LINE

	; ..
SCHLP:	MOVE T1,@NL(BP2)	;CHECK FOR NULL SEARCH
	MOVE T2,0(T1)
	CAMN T2,[<.CHESC>B6]	;END OF STRING?
	JRST SCH9		;YES
	SCALL FILL,<BP1>	;GET MORE INPUT IF NECESSARY
	SCALL LCOMP,<NL(BP1),NL(BP2)>
	JUMPE T1,SCH1		;JUMP IF LINES MATCH
SCH3:	SCALL BUMPL,<BP1>	;NO MATCH, BUMP INPUT
	MOVE T1,NL(BP1)
	CAMGE T1,FRE(BP1)	;EOF?
	JRST SCHLP		;NO, KEEP SEARCHING
	JXN F,SDUPF,SCH11	;JUMP IF WERE SEARCHING FOR DUP
	MV. BFA(BP1),NL(BP1)	;RESET INPUT POINTER
	MV. INL3,NL(BP2)	;RESET TOP OF CHANGE BLOCK
	IFXE. F,UNMF		;IF NOT UNMERGE
	  TXCN F,TRYUF		;WERE TRYING FOR ALTERNATE MATCH?
	  JRST SCHTR		;NO, GO DO IT
	ENDIF.
	TMSG <?FAILED TO FIND >
	MOVE T1,NL(BP2)		;GET CURRENT LINE
	HRRO T1,-1(T1)		;CHANGE BANNER IS ONE BEFORE IT
	PSOUT
	SKIPGE FAIJFN		;WRITING FAILED CHANGES?
	JRST SKIPCH		;NO
	SOS NL(BP2)		;BACK UP TO BANNER
	SCALL WRESC,<BP2>	;WRITE OLD TEXT
	SCALL WRESC,<BP2>	;WRITE NEW TEXT
	MOVE T1,FAIJFN		;TERMINATE LAST ESC LINE
	HRROI T2,[ASCIZ /
/]
	SETZ T3,
	SOUT
	JRST SCH0		;GO ON TO NEXT CHANGE

;SKIP THIS CHANGE

SKIPCH:	SCALL STPESC,<BP2>	;PASS OLD TEXT
	SCALL STPESC,<BP2>	;PASS NEW TEXT
	JRST SCH0		;GO ON TO NEXT CHANGE
;FOUND FIRST MATCHING LINE, CHECK REMAINDER

SCH1:	MV. NL(BP1),INL1		;SAVE CURRENT POINTERS
	MV. NL(BP2),INL2
SCH2:	SCALL BUMPL,<BP1>	;STEP TO NEXT LINE
	SCALL BUMPL,<BP2>
	JXN F,BPEOF,UXEOF	;CHECK FOR UNEXPECTED EOF
	MOVE T1,@NL(BP2)
	MOVE T2,0(T1)
	CAMN T2,[<.CHESC>B6]	;END OF SEARCH?
	JRST SCHCD		;YES, COMPLETE MATCH
	SCALL FILL,<BP1>	;NO, GET MORE INPUT
	SCALL FILL,<BP2>
	SCALL LCOMP,<NL(BP1),NL(BP2)> ;CHECK NEXT LINE
	JUMPE T1,SCH2		;JUMP IF MATCH
SCH10:	MV. INL1,NL(BP1)	;NO MATCH, RESET POINTERS
	MV. INL2,NL(BP2)
	JRST SCH3

;SEARCH SUCCESSFUL, ANALYZE STATE

SCHCD:	JXE F,DUPF,SCH4		;IF NOT VERIFYING, GO DO INSERT
	IFXN. F,SDUPF		;WERE DOING DUP SEARCH?
	  MV. BFA(BP1),NL(BP1)	;RESET PTRS
	  MV. INL3,NL(BP2)
	  TMSG <?Ambiguous >	;YES, FOUND ANOTHER MATCH
	  MOVE T1,NL(BP2)
	  HRRO T1,-1(T1)	;MAKE PTR TO CHANGE ID LINE
	  PSOUT
	  TMSG < - this change skipped.
>
	  JRST SKIPCH		;GO ON TO NEXT CHANGE
	ENDIF.
	MV. INL1,CINL1		;SAVE VARIABLES
	MV. INL2,CINL2
	MV. NL(BP1),CINL3
	MV. NL(BP2),CINL4
	TXO F,SDUPF		;NOTE DOING DUP SEARCH
	JRST SCH10		;CONTINUE AS IF SEARCH FAILED

;HERE WHEN REACHED END OF FILE ON DUP SEARCH.  THAT MEANS WE
;DIDN'T FIND A SECOND MATCH, AND WE WILL GO AHEAD AND MAKE
;THE CHANGE WHERE THE ORIGINAL MATCH WAS FOUND.

SCH11:	MV. CINL1,INL1		;RESTORE VARIABLES
	MV. CINL2,INL2
	MV. CINL3,NL(BP1)
	MV. CINL4,NL(BP2)
	JRST SCH4
;COMPLETE MATCH, EFFECT REPLACEMENT

SCH9:	MV. NL(BP1),INL1		;SET BEG OF CHANGE POINTS
	MV. NL(BP2),INL2
SCH4:	IFXN. F,TRYUF		;IF TRYING ALTERNATE MATCH
	  TMSG <% >
	  MOVE T1,INL3		;TOP OF CHANGE BLOCK
	  HRRO T1,-1(T1)	;PTR TO CHANGE BANNER
	  PSOUT
	  TMSG <% has already been made.
>
	  SCALL BFOUT,<BP1>	;WRITE THROUGH CHANGE
	  SCALL SHIFTA,<BP1>	;AND FLUSH IT
	  JRST SCHU1		;DONE WITH THIS CHANGE
	ENDIF.
	SCALL BUMPL,<BP2>	;bypass junk
	MOVE T1,NL(BP1)		;SET POINTER TO BEG OF DELETION
	EXCH T1,INL1		;AND SAVE END OF DELETION
	CAMG T1,BFA(BP1)	;ANYTHING BEFORE DELETION?
	JRST SCH5		;NO
	MOVEM T1,NL(BP1)
	SCALL BFOUT,<BP1>
SCH5:	MV. INL1,NL(BP1)	;STEP POINTER BEYOND DELETION
	SCALL SHIFTA,<BP1>	;FLUSH EVERYTHING ALREADY PROCESSED
	IFXN. F,UNMF		;IF UNMERGE
	  MV. INL3,NL(BP2)	;INSERT FIRST PART OF CHANGE BLOCK
	ELSE.
	  SCALL BUMPL,<BP2>	;STEP TO FIRST LINE TO INSERT
	ENDIF.
	SCALL SHIFTA,<BP2>	;FLUSH EVERYTHING BEFORE THAT
	MV. NL(BP2),INL2		;SAVE TOP OF INSERT
SCH6:	SCALL FILL,<BP2>	;GET MORE INSERT TEXT
	MOVE T1,@NL(BP2)
	MOVE T2,0(T1)		;CHECK FOR END OF INSERT
	CAME T2,[<.CHESC>B6]
	JRST [	SCALL BUMPL,<BP2> ;NOT END, STEP LINE
		JXN F,BPEOF,UXEOF ;CHECK FOR UNEXPECTED EOF
		JRST SCH6]
	SCALL BFOUT,<BP2>	;OUTPUT INSERTION
SCHU1:	AOS NL(BP2)
	IFXN. F,UNMF		;IF UNMERGE,
	  SCALL STPESC,<BP2>	;GO TO END OF CHANGE BLOCK
	ENDIF.
	SCALL SHIFTA,<BP2>	;FLUSH EVERYTHING PROCESSED
	JRST SCH0		;DO NEXT CHANGE

;UNEXPECTED EOF IN DIFFERENCES FILE, I.E. BEFORE TERMINATING ESC'S

UXEOF:	TMSG <
?Unexpected EOF in differences file--probable missing ESC.
 Balance of source file will be copied to destination.
>
	; ..

;EOF IN DIFFERENCE FILE

SCH8:	MV. FRE(BP1),NL(BP1)	;SET CURRENT LINE TO END
	SCALL BFOUT,<BP1>	;DUMP ALL CURRENT BUFFER
	SKIPGE T1,FAIJFN
	IFSKP.
	  CLOSF
	   ERJMP .+1
	ENDIF.
SCH7:	SCALL CIN,<BP1>		;COPY REST OF FILE
	 RET			;DONE
	CALL COUT
	JRST SCH7
	SUBTTL SUBROUTINES

;STEP TO NEXT ESC IN CHANGE BLOCK
; T1/ LINE INDEX
; RETURNS +1 ALWAYS

STPESC:	ACVAR <P1>
	MOVEM T1,P1
      DO.
	SCALL FILL,<P1>
	MOVE T1,@NL(P1)		;LOOK AT BEGINNING OF LINE
	MOVE T2,0(T1)
	CAMN T2,[<.CHESC>B6]	;AN ESC?
	EXIT.			;YES
	SCALL BUMPL,<P1>	;NO, STEP TO NEXT LINE
	JXE F,BPEOF,TOP.	;LOOP IF NO EOF
      OD.
	SCALL BUMPL,<P1>	;STEP TO LINE AFTER ESC
	RET

	ENDAV.

;WRITE FROM CURRENT LINE TO NEXT ESC TO FAILED-CHANGES FILE
; T1/ LINE INDEX
; RETURNS +1 ALWAYS

WRESC:	ACVAR <P1>
	MOVEM T1,P1
      DO.
	SCALL FILL,<P1>
	MOVE T1,FAIJFN
	HRRO T2,@NL(P1)
	SETZ T3,
	SOUT			;WRITE THE LINE
	MOVE T1,@NL(P1)		;LOOK AT BEGINNING OF LINE
	MOVE T2,0(T1)
	CAMN T2,[<.CHESC>B6]	;AN ESC?
	EXIT.			;YES
	SCALL BUMPL,<P1>	;NO, STEP TO NEXT LINE
	JXE F,BPEOF,TOP.	;LOOP IF NO EOF
      OD.
	SCALL BUMPL,<P1>	;STEP TO LINE AFTER ESC
	RET

	ENDAV.
;COMPARE ROUTINES

;COMPARE ONE LINE
; T1/ LINE INDEX
; T2/ LINE INDEX
; RETURNS +1,
;  T1/ 0 IF LINES IDENTICAL, NON-0 IF LINES DIFFERENT

LCOMP:	ACVAR <P1,P2>
	TXZ F,JUNKL		;NOT JUNK DIFFERENCE YET
	CAML T1,FRE(BP1)	;AT EOF?
	JRST [	CAML T2,FRE(BP2) ;YES, BOTH FILES?
		TDZA T1,T1	;YES, EQUAL
		SETO T1,	;NO, DIFFERENT
		RET]
	CAML T2,FRE(BP2)	;AT EOF?
	JRST RETO		;YES, DIFFERENT
	MOVE P1,0(T1)		;GET STRING ADDRESSES
	MOVE P2,0(T2)
LCOM1:	MOVE T1,0(P1)
	CAME T1,0(P2)		;SAME?
	JRST LCOM2		;NO, SEE WHY
	AOS P1			;BUMP WORDS
	AOS P2
	TRNE T1,177B34		;LAST WORD?
	JRST LCOM1		;NO
RETZ:	SETZ T1,		;YES, LINES IDENTICAL
	RET

LCOM2:	HRLI P1,(POINT 7,0)
	HRLI P2,(POINT 7,0)	;SETUP TO CHECK EACH BYTE
      DO.
	ILDB T1,P1
	ILDB T2,P2
	CAMN T1,T2		;BYTES SAME?
	JUMPN T1,TOP.		;YES, LOOP IF NOT NULL
      ENDDO.
      DO.
	CAIN T1,.CHLFD
	JRST ENDLP.
	JUMPE T1,ENDLP.		;IF FIRST STRING ENDED, CHECK SECOND
	CAIN T1,.CHCRT		;CR EQUIVALENT TO BLANK
	MOVEI T1," "
	CAIE T1," "		;SEE IF FIRST STRING ENDS WITH BLANKS
	CAIN T1,.CHTAB
	IFNSK.
	  ILDB T1,P1		;MAYBE, KEEP CHECKING
	  JRST TOP.
	ENDIF.
	JRST RETO		;DIFFERENCE IS NON-BLANK CHARACTER
      ENDDO.
      DO.
	CAIE T2,.CHLFD		;IF SECOND STRING ENDED, JUNK DIFFERENCE
	CAIN T2,0
	IFNSK.
	  TXO F,JUNKL		;IF SECOND STRING ENDED, JUNK DIFFERENCE
	  JRST RETO
	ENDIF.
	CAIN T2,.CHCRT		;CR EQUIVALENT TO BLANK
	MOVEI T2," "
	CAIE T2," "
	CAIN T2,.CHTAB
	IFNSK.
	  ILDB T2,P2		;BLANK - KEEP CHECKING
	  JRST TOP.
	ENDIF.
	JRST RETO		;NON-BLANK, REAL DIFFERENCE.
      ENDDO.

	ENDAV.

;COMPARE 'NMATCH' LINES, SAME ARGS AS LCOMP

LCOMPN:	ACVAR <P1,P2,P3>
	MOVEM T1,P1
	MOVEM T2,P2
	MOVE P3,NMATCH
LCOMN1:	SCALL LCOMP,<P1,P2>
	JUMPN T1,R		;STOP NOW IF DIFFERENT
	AOS P1			;BUMP LINE INDEXES
	AOS P2
	SOJG P3,LCOMN1		;DO NEXT LINE
	RET			;ALL COMPARE OK

	ENDAV.
;COMPARE ONE LINE WITH LITERAL TEXT

; T1/ LINE INDEX
; T2/ ADR OF ASCIZ TEXT
; RETURNS +1,
;  T1/ 0 IF LINES IDENTICAL, 1 IF TEXT A SUBSTRING, -1 IF DIFFERENT

SCOMP:	ACVAR <P1,P2>
	MOVE P1,0(T1)		;GET STRING ADDRESSES
	MOVE P2,T2
      DO.
	MOVE T1,0(P1)
	CAME T1,0(P2)
	IFSKP.
	  AOS P1		;SAME SO FAR, STEP WORDS
	  AOS P2
	  TRNE T1,177B34	;LAST WORD?
	  LOOP.			;NO
	  SETZ T1,		;YES, IDENTICAL
	  RET
	ENDIF.
      OD.			;FALL OUT OF LOOP WHEN WORDS DIFFERENT
	HRLI P1,(POINT 7,0)	;MAKE BYTE PTRS
	HRLI P2,(POINT 7,0)
      DO.
	ILDB T1,P1		;GET BYTES
	ILDB T2,P2
	CAMN T1,T2		;SAME?
	LOOP.			;YES, FIND THE DIFFERENT ONE
      OD.
	IFE. T2			;TEXT STRING ENDED?
	  MOVEI T1,1		;YES, NOTE SUBSTRING
	  RET
	ENDIF.
RETO:	SETO T1,		;JUST DIFFERENT
	RET

	ENDAV.
;SHIFT OUT LINES ALREADY PROCESSED
; T1/ BLOCK ADDRESS

SHIFTA:	TDZA T2,T2		;SHIFT OUT EVERYTHING BEFORE CURRENT LINE
SHIFT:	MOVE T2,MINDIF		;SHIFT OUT UP TO MINDIF BEFORE CURRENT LINE
	ACVAR <BP>
	MOVEM T1,BP		;SAVE BLOCK ADDRESS
	MOVE T1,NL(BP)
	SUB T1,T2		;FIND FIRST LINE TO KIIP
	MOVN T3,T1
	ADD T3,BFA(BP)		;COMPUTE (NEG) NUMBER LINES TO DELETE
	JUMPGE T3,R		;QUIT IF NONE
	HRLZ T1,T1		;SETUP BLT FROM
	HRR T1,BFA(BP)		; .. TO
	ADDM T3,NL(BP)		;UPDATE POINTERS
	ADDM T3,FRE(BP)
	MOVE T2,FRE(BP)		;SETUP BLT FINAL ADR
	BLT T1,-1(T2)
	RET

	ENDAV.

;BUMP CURRENT LINE
; T1/ BLOCK ADDRESS
; RETURN +1, CHECKS FOR END OF BUFFER

BUMPL:	TXZ F,BPEOF		;INIT FLAG
	AOS T2,NL(T1)		;BUMP LINE POINTER
	CAMLE T2,FRE(T1)	;PAST END?
	JRST [	SOS T2,NL(T1)	;YES, UNDO IT
		TXO F,BPEOF	;NOTE EOF
		RET]
	MOVE T3,-1(T2)		;check previous line for ffd
	MOVE T3,0(T3)
	CAME T3,[<.chffd>B6]
	JRST BUMPL1
	MOVSI T3,1		;increment page number
	ADD T3,PAGLIN(T1)
	HLLZM T3,PAGLIN(T1)
BUMPL1:	AOS PAGLIN(T1)		;increment line number
	RET

;same as above but no position accounting - used during
;difference scan

BUMPX:	AOS T2,NL(T1)
	CAMLE T2,FRE(T1)
	SOS T2,NL(T1)
	RET
;FILL BUFFER SO THAT AT LEAST MINDIF LINES PRESENT FOLLOWING NL
; T1/ BLOCK ADDRESS

FILL:	ACVAR <BP,P1>
	MOVEM T1,BP		;SAVE BLOCK ADDRESS
FILL3:	MOVE T1,NL(BP)
	ADD T1,MINDIF
	CAMGE T1,FRE(BP)	;ENOUGH LINES PRESENT?
	RET			;YES, DONE
	SKIPGE INJFN(BP)	;HAVE A JFN?
	RET			;NO, ALREADY AT EOF
	MOVE P1,SFRE(BP)	;ASSIGN STRING STORAGE
	ADDI P1,MAXCHL/5	;SEE IF ENOUGH LEFT
	CAML P1,ESBFR(BP)
	JRST [	MOVE P1,SBFR(BP) ;NO, WRAPAROUND
		MOVEM P1,SFRE(BP)
		JRST .+1]
	MOVE P1,SFRE(BP)
	MOVEM P1,@FRE(BP)	;PUT ADDRESS IN LINE PTR TABLE
	HRLI P1,(POINT 7,0)
FILL1:	SCALL CIN,<BP>		;GET A CHAR
	 JRST [	MOVE T1,INJFN(BP) ;EOF
		CLOSF
		 JSERR
		SETOM INJFN(BP)	;NOTE NO JFN
		RET]
	IDPB T1,P1		;STORE CHAR
	CAIE T1,.CHLFD		;END OF LINE?
	CAIN T1,.CHFFD
	JRST FILL2		;YES
	CAIN T1,.CHESC		;ESC TREATED AS EOL
	JRST FILL2
	JRST FILL1		;NO

FILL2:	SETZ T1,		;TIE OFF LINE
	IDPB T1,P1
	TXNE P1,76B5		;FILLED WORD?
	JRST FILL2		;NO, KEEP APPENDING NULLS
	AOS P1			;UPDATE STRING FREE
	HRRM P1,SFRE(BP)
	AOS FRE(BP)
	JRST FILL3

	ENDAV.
;OUTPUT CONTENTS OF BUFFER FROM TOP TO CURRENT LINE
; T1/ BLOCK PTR
; RETURNS +1

BFOUT:	ACVAR <BP,P1,P2>
	MOVEM T1,BP
	MOVE P1,BFA(BP)		;GET FIRST LINE 
BFOU2:	CAML P1,NL(BP)		;BUFFER EMPTY?
	RET			;YES
	MOVE P2,0(P1)		;GET STRING ADDRESS
	HRLI P2,(POINT 7,0)
BFOU1:	ILDB T1,P2
	JUMPN T1,[CALL COUT	;OUTPUT CHAR
		JRST BFOU1]
	AOJA P1,BFOU2		;DO ALL LINES

	ENDAV.

;STRING OUT TO FILE
; T1/ POINTER

STOUT:	ACVAR <P1>
	HLRZ T2,T1
	CAIN T2,-1		;DEFAULT?
	HRLI T1,(POINT 7,0)	;YES
	MOVEM T1,P1
STOUT1:	ILDB T1,P1
	JUMPN T1,[CALL COUT	;OUTPUT A CHAR
		JRST STOUT1]
	RET

	ENDAV.

;NUMBER OUTPUT, DECIMAL
; T1/ NUMBER

NOUT10:	STKVAR <<NBF,3>>
	MOVE T2,T1		;SETUP NUMBER
	HRROI T1,NBF
	MOVEI T3,^D10
	NOUT			;WRITE TO TEMP STACK BUFFER
	 JSERR
	HRROI T1,NBF		;COPY BUFFER TO FILE
	CALLRET STOUT

	ENDSV.
;FILE IO
;CHARACTER IN
; T1/ BLOCK PTR
; RETURNS +1, END OF FILE
;	+2, SUCCESS, T1/ CHARACTER

CIN:	MOVEM T1,T4		;SAVE BLOCK PTR
	SKIPE T1,SAVECH(T4)	;SAVED CHAR FROM BEFORE?
	JRST [	SETZM SAVECH(T4) ;YES, ONCE ONLY
		RETSKP]		;RETURN IT
CIN1:	SOSGE INCNT(T4)		;CHAR IN BUFFER?
	JRST GBF1		;NO
	ILDB T1,IPTR(T4)	;GET IT
	JUMPE T1,CIN1		;FLUSH NULLS
	CAIN T1,.CHCRT		;FLUSH CR'S TO NORMALIZE CRLF SEQUENCE
	JRST CIN1
	CAIN T1,.CHLFD		;LF?
	JRST [	MOVEM T1,SAVECH(T4) ;YES, SAVE IT FOR NEXT TIME
		MOVEI T1,.CHCRT	;RETURN CR NOW
		JRST .+1]
	RETSKP

GBF1:	SKIPGE T1,INJFN(T4)
	RET			;FILE ALREADY CLOSED
	GTSTS			;GET FILE STATUS
	TXNE T2,GS%EOF		;AT EOF?
	RET			;YES
	MOVE T2,BFADR(T4)
	HRLI T2,(POINT 7,0)
	MOVEM T2,IPTR(T4)	;INIT PTR
	MOVNI T3,NCHBF
	SIN
	ADDI T3,NCHBF		;COMPUTE NUMBER BYTES STORED
	MOVEM T3,INCNT(T4)
	JRST CIN1

;CHARACTER OUT
; T1/ CHARACTER
; RETURNS +1

COUT:	SOSGE OUTCNT
	JRST [	SETZM OUTCNT
		CALL FBFOUT
		JRST COUT]
	IDPB T1,OPTR
	RET

FBFOUT:	STKVAR <CH>
	MOVEM T1,CH
	MOVE T1,OUTJFN
	HRROI T2,FBUFO
	MOVNI T3,NCHBF
	ADD T3,OUTCNT
	SOUT
	CALL FBFINI
	MOVE T1,CH
	RET

FBFINI:	MOVEI T1,NCHBF
	MOVEM T1,OUTCNT
	MOVE T1,[POINT 7,FBUFO]
	MOVEM T1,OPTR
	RET

	ENDSV.
;INIT BUFFER BLOCKS

INIBLK:	MOVEI BP1,BBP1		;SETUP BLOCK ADDRESSES
	MOVEI BP2,BBP2
	MOVEI T1,LPTR1		;INIT BLOCKS
	MOVEM T1,BFA(BP1)
	MOVEM T1,NL(BP1)
	MOVEM T1,FRE(BP1)
	MOVEI T1,LPTR2
	MOVEM T1,BFA(BP2)
	MOVEM T1,NL(BP2)
	MOVEM T1,FRE(BP2)
	MOVEI T1,LPTR1+NLMAX/2
	MOVEM T1,BFA2(BP1)
	MOVEI T1,LPTR2+NLMAX/2
	MOVEM T1,BFA2(BP2)
	MOVEI T1,BUF1
	MOVEM T1,SFRE(BP1)
	MOVEM T1,SBFR(BP1)
	MOVEI T1,EBUF1
	MOVEM T1,ESBFR(BP1)
	MOVEI T1,BUF2
	MOVEM T1,SFRE(BP2)
	MOVEM T1,SBFR(BP2)
	MOVEI T1,EBUF2
	MOVEM T1,ESBFR(BP2)
	MOVEI T1,FBUF1
	MOVEM T1,BFADR(BP1)
	MOVEI T1,FBUF2
	MOVEM T1,BFADR(BP2)
	RET

;JSYS ERROR MESSAGE

JSERRM:	MOVEI T1,.PRIOU
	HRLOI T2,.FHSLF		;THIS FORK, LAST ERROR
	SETZ T3,
	ERSTR
	 JFCL
	 JFCL
	TMSG <
>
	RET

	END LEVEC,,EVEC