Google
 

Trailing-Edge - PDP-10 Archives - BB-M836C-BM - tools/scm/scm.mac
There are 3 other files named scm.mac in the archive. Click here to see a list.
	TITLE	SCM - Light speed .SCM file generation

;Compares files (similiar to FILCOM, but simpler and rather faster)
;21-Feb-83
;23-Jul-84	Add 2nd filename defaulting

	SEARCH	MONSYM,MACSYM
	SALL

	.MAJOR=2
	.MINOR=0
	.EDIT=3
	.WHO=0			;SM

	F==0			;FLAGS (F.xxx)
	T1==1			;THE USUAL SCRAP
	T2==2
	T3==3
	T4==4
	I==5			;INDEX INTO LINKED LIST DURING COMPARES
	FIL=6			;ACTIVE FILE NUMBER (0 OR 1)
	OFIL=7			;THE OTHER FILE
	READ==10		;CONTROLS LINE NEXT READ BY INLINE
	 READ0==10		 ;READ IS INDEXED BY 0 OR 1
	 READ1==11
	STOPAT==12		;WHERE SCANNING STOPS
	 STOP0==12		 ;ALSO INDEXED BY 0 OR 1
	 STOP1==13
	STLOC==14		;WHERE SCANNING STARTS
	 STLO0==14		 ;INDEX BY 0 OR 1
	 STLO1==15
	CNT==16			;COUNT OF LINES DURING PARANOIA CHECKS
	P=17			;STACK POINTER

;OFFSETS INTO THE DATA STRUCTURE
	D.NEXT==0		;ADDR OF NEXT STRING BLOCK
	D.WHR==1		;PAGE NUMBER,,LINE NUMBER IN PAGE
	D.LAB==2		;SIXBIT LABEL LAST SEEN
	D.OFF==3		;LINES DOWN FROM LAST LABEL SEEN
	D.STR==4		;THE BEGINNING OF THE LINE OF TEXT

;ASSEMBLY FLAGS
	FTAPPD==-1		;-1 TO MAKE APPENDED CHANGE STUFF PRETTY
	FTSTAT==0		;-1 TO GET STATS

	COINCI==3		;NUMBER OF LINES NEEDED TO BE THE SAME AFTER
				; A DIFFERENCE TO PROVE THAT THE DIFFERENCE
				; HAS ENDED (EG, HOW MANY CANT BE COINCIDENCE)

	NPAG==10		;NUMBER OF FILE PAGES TO HAUL IN AT ONCE

	PPAG==NPAG*2+WHRBFR
	PSIZ==<777-PPAG>*^D256	;WORDS AVAILABLE TO EACH POOL
				;TO FIT DDT IN, CHANGE 777 TO 750

	POOL1=PPAG*1000		;LOC TO START FIRST FILE POOL AT
	POOL2=POOL1+PSIZ	;LOC TO START OTHER FILE POOL AT

	F.RESC==1B0		;RESCAN ON ENTER PASSES COMMAND
	F.EXIT==1B1		;EXIT AT NEXT COMMAND TIME

	F.NMAC==1B35		;NOT MACRO IF LIT
	F.FILC==1B34		;FILCOM MODE IF LIT
	F.DIF==1B33		;DIFFERENCES SEEN
	F.EOF==1B32		;EOFS ON BOTH JFNS
	F.END==1B31		;EOF ON A JFN
	F.TTY==1B30		;OUT TO .CTTRM

	DEFINE	COPYRI(text),<ASCIZ ~text~>
VECT:	JRST	ST					;START
	JRST	REE					;REENTRY
	BYTE (3).WHO (9).MAJOR (6).MINOR (18).EDIT	;VERSION
	-1,,CPYRIG					;COPYRIGHT
	 VECLEN=.-VECT

CPYRIG:	COPYRI	<

	SCM - Fast and simple file comparer.
	Copyright (C) 1983 by Digital Equipment Corporation, Maynard, Mass.
>

REE:
ST:
 IFN FTSTAT,<
	MOVX	T1,.FHSLF
	RUNTM%
	MOVEM	T1,STTIME#
 >
	RESET%				;CLEAR THE UNIVERSE
	MOVEI	P,STACK-1		;SET STACK UP
	SETZB	F,MESFLG#		;NO FLAGS
	MOVE	T1,[ASCIZ/0)	/]
	MOVEM	T1,LEAD			;NORMAL LEAD STRING
	MOVX	T1,.RSINI		;ANY COMMANDS FOR ME HERE?
	RSCAN%				;..
	 ERJMP	GCMD2			;APPARENTLY NOT
	SKIPN	I,T1			;ANY CHARATERS COME BACK?
	JRST	GCMD2			;NO CHARACTERS THERE
	MOVE	T2,[POINT 7,[ASCIZ/SCM/]] ;MATCH THIS FOR RESCAN
RSCLOP:	SOJL	I,GCMD2			;COUNT DOWN THE CHARACTERS
	PBIN%
	CAIN	T1,.CHCRT		;IGNORE <CR>
	JRST	RSCLOP
	CAIG	T1," "
	JRST	TRMNR			;SPACE OR LESS TERMINATES PROGGY NAME
	MOVE	T1,CHRTAB(T1)
	TXNN	T1,CH%SYM
	 JRST	GARBAG
	ILDB	T3,T2			;CHECK...
	CAIN	T3,(T1)
	JRST	RSCLOP			;NEXT CHARACTER
	JRST	GARBAG			;NO MATCH
TRMNR:	CAIE	T1,.CHTAB
	CAIN	T1," "			;HOW DID IT END?
	TXOA	F,F.RESC		;YES, WE HAVE "progname "
	JRST	GARBAG			;IF ENDED WITH <LF>, NO RESCAN
	JRST	GCMD2
GARBAG:	JUMPE	I,GCMD2			;HERE TO TOSS UNWANTED RESCAN
	MOVX	T1,.CTTRM		;IF NONE LEFT, DON'T TRY
	SETZ	T2,
	MOVN	T3,I			;TOSS I CHARACTERS
	SIN%				;ALL GONE
	 ERJMP	.+1
	JRST	GCMD2

GCMD:	HLLZS	F
	TXNE	F,F.EXIT!F.RESC
	JRST	LEAVE
GCMD2:	TXNE	F,F.RESC		;NO PROMPT ON RESCAN
	SKIPA	T1,[POINT 7,ZERO]	;..	;< FOR BALANCE
	HRROI	T1,[ASCIZ/SCM>/]	;NORMAL PROMPT
	MOVEM	T1,CMDBLK+.CMRTY
	DMOVE	T1,[EXP CMDBLK,INIINB]
	CALL	PARSE			;PROMPT
	 JFCL				;SNH
	MOVEM	F,REALF#
	MOVEM	P,TMPP#
TRAPRP:	MOVE	P,TMPP			;FOR REPARSE
	MOVE	F,REALF
	MOVE	T1,[CZ%NIF+CZ%ABT+CZ%NUD+.FHSLF]
	CLZFF%				;CLOSE ANY OPEN FILES
	 ERJMP	.+1

	SETZ	FIL,
	MOVX	T1,GJ%OLD
	MOVEM	T1,GTJBLK+.GJGEN
	MOVSI	T4,-4
	SETZM	GTJBLK+.GJDEV(T4)
	AOBJN	T4,.-1
	JRST	FSTFLE

OTHFLE:	MOVSI	T4,-2		;NEED TO GET 2 FIELDS FROM JFNS
	MOVE	T1,[POINT 7,TMPSTR]
SDEFS:	MOVE	T3,JFSTAB(T4)
	MOVE	T2,INJFN+0
	MOVEM	T1,GTJBLK+.GJNAM(T4) ;STORE THE POINTER TO THE COMING STRING
	JFNS%			;OK, WRITE THE STRING
	CAMN	T1,GTJBLK+.GJNAM(T4) ;DID ANYTHING GET WRITTEN?
	SETZM	GTJBLK+.GJNAM(T4) ;NO, SO NO DEFAULT KNOWN
	IDPB	T3,T1		;THIS FORCES A NULL
	AOBJN	T4,SDEFS	;NEXT FIELD, PLEASE?
FSTFLE:	DMOVE	T1,[EXP CMDBLK,[<.CMCFM>B8+[<.CMFIL>B8]]]
	CALL	PARSE			;PARSE INPUT FILE
	 JRST	NOINFL
	CAIN	T3,.CMCFM
	JRST	LEAVE
	HRRZM	T2,INJFN(FIL)		;STORE JFN
	MOVE	T1,T2
	MOVX	T2,7B5+OF%RD		;ONLY NEED READ ACCESS FOR FILE WINDOWS
	OPENF%
	 ERJMP	NOINFL			;ERROR OUT
	SIZEF%
	 ERJMP	NOINFL
	JUMPE	T2,LEN0FL		;DON'T ACCEPT 0 LENGTH FILES
	MOVEM	T2,CHRFIL(FIL)
	HRRO	T1,[[ASCIZ/against/]
		    [ASCIZ/to file/]](FIL)
	CALL	GUIDE			;GIVE RIGHT GUIDE WORD
	TRCN	FIL,1			;DONE 2ND INPUT FILE YET?
	JRST	OTHFLE			;NO, GO DO

	SETZM	OUTJFN#
	MOVX	T1,GJ%FOU+GJ%MSG	;SET UP FOR OUTPUT FILE
	MOVEM	T1,GTJBLK+.GJGEN
	SETZM	GTJBLK+.GJDEV
	SETZM	GTJBLK+.GJDIR
	HRROI	T1,[ASCIZ/SCM/]		;.SCM DEFAULT
	MOVEM	T1,GTJBLK+.GJEXT
	HRROI	T1,[ASCIZ/DIFFERENCES/]
	MOVEM	T1,GTJBLK+.GJNAM
	DMOVE	T1,[EXP CMDBLK,OFLINB]
	CALL	PARSE			;PARSE IT
	 JRST	UNPARS
	CAIE	T3,.CMFIL
	JRST	NOFILE
	MOVEM	T2,OUTJFN
SWCCDE:	DMOVE	T1,[EXP CMDBLK,SWCINB]
	CALL	PARSE
	 JRST	UNPARS
NOFILE:	CAIN	T3,.CMCFM
	JRST	OKGO
	HRRZ	T2,(T2)
	JRST	(T2)

WINSWI:	DMOVE	T1,[EXP CMDBLK,NUMINB]
	CALL	PARSE
	 JRST	BADNQE
	CAIG	T2,0
	MOVEI	T2,COINCI
	MOVEM	T2,COINCH
	JRST	SWCCDE
MESSWI:	DMOVE	T1,[EXP CMDBLK,DNSINB]
	CALL	PARSE
	 JRST	BADYQE
	HRRZ	T2,(T2)
	MOVEM	T2,MESFLG
	JRST	SWCCDE
FILSWI:	MOVX	T4,F.FILC
	JRST	YNSWI
EXISWI:	TXO	F,F.EXIT
	JRST	SWCCDE
MACSWI:	MOVX	T4,F.NMAC
YNSWI:	DMOVE	T1,[EXP CMDBLK,YNINB]
	CALL	PARSE
	 JRST	BADYQE
	HRRZ	T2,(T2)
	CAIE	T2,0
	TDZA	F,T4
	TDO	F,T4
	JRST	SWCCDE

OKGO:	SKIPE	T2,OUTJFN
	JRST	OUTJFO
	TXO	F,F.TTY
	MOVX	T2,.CTTRM
	MOVEM	T2,OUTJFN		;STORE JFN
	JRST	ALLSET
OUTJFO:	MOVE	T1,T2
	MOVX	T2,7B5+OF%WR		;WRITE ACCESS
	OPENF%
	 ERJMP	NOOUFL

	MOVX	T1,.FHSLF
	HRRO	T2,OUTJFN		;PRIMARY OUT TO FILE!
	SPJFN%

ALLSET:	SETZ	FIL,			;OUTPUT FILE HEADER
FILINF:	MOVEI	T1,1(FIL)
	DPB	T1,[POINT 2,FLEAD+1,6]
	HRROI	T1,FLEAD
	PSOUT%
	MOVX	T1,.PRIOU		;OUTPUT FILESPEC
	MOVE	T2,INJFN(FIL)
	SETZ	T3,
	JFNS%
	 ERJMP	.+1
	HRROI	T1,CRLF
	PSOUT%
	TRCN	FIL,1			;DONE BOTH FILENAMES?
	JRST	FILINF			;NO, GO AGAIN
	HRROI	T1,CRLF
	PSOUT%

	SETZB	READ0,READ1		;ZERO OUT AC BORNE VARIABLES
	MOVE	T1,[ZERO,,ZERO+1]
	BLT	T1,EZER			;ZERO OUT VAR SPACE

;SCAN STARTS WITH FIL CONTAINING ZERO
BFRCHK:	SKIPE	READ(FIL)		;IS THERE LIVE DATA OUT THERE?
	JRST	BFRCH2			;YES, DONT RESTART THE POOL
	MOVE	T1,BEGIN(FIL)		;CLOBBER POOL
	MOVEM	T1,WHERE(FIL)
	SETZM	LAST(FIL)		;THIS WILL BE POOLS FIRST LINE
BFRCH2:	CALL	INLINE			;READ IN A LINE
	 JRST	FINIS			;BOTH FILES HAVE HIT EOF
	TRCN	FIL,1			;SWITCH TO OTHER FILE
	JRST	BFRCHK			;GO BACK IF FILE 2 NOT READ YET
	DMOVE	T1,LINE			;GOT A LINE FROM EACH; COMPARE
	CALL	SAME			;..
	 JRST	BFRCHK			;THE SAME, GET ANOTHER PAIR
	TXO	F,F.DIF			;FILES ARE DIFFERENT, REAL OUTPUT FILE
	DMOVE	STLOC,WHRBLK
	MOVEI	OFIL,1			;FIL IS ZERO HERE
	MOVE	STOP1,WHRBLK+1		;SO SET UP THE OTHER FILE THIS WAY
FNEND:	CALL	INLINE			;READ A LINE FROM THIS FILE
	 JRST	ENDDIF			;BOTH HIT EOF. DUMP THE DIFFERENCES.
	MOVE	T1,WHRBLK(FIL)
	MOVEM	T1,STOPAT(FIL)
	SKIPA	I,STLOC(OFIL)
SCAN1:	MOVE	I,D.NEXT(I)
	MOVEI	T1,D.STR(I)
	MOVE	T2,STOPAT(FIL)
	MOVEI	T2,D.STR(T2)
	CALL	SAME
	 SKIPA	CNT,COINCH
	JRST	FMATCH
	MOVEI	T1,D.STR(I)
	HRLI	T1,(POINT 7,0,6)
	LDB	T2,T1
	CAIE	T2,.CHCRT
	JRST	NBLANK
	ILDB	T2,T1
	CAIN	T2,.CHLFD
	JRST	FMATCH
NBLANK:	MOVEM	FIL,FILTMP#
	MOVEM	I,SCNTMP#
	MOVE	T1,D.NEXT(I)
	MOVEM	T1,READ(OFIL)
	JUMPLE	CNT,GOTCON
MAYBE:	CALL	SKLINE
	 JRST	GOTCON
	CALL	SKLINE
	 JRST	GOTCON
	DMOVE	T1,LINE
	CALL	SAME
	 JRST	MAYBEC
FALSE:	MOVE	READ1,D.NEXT(STOP1)	;THESE ARE READ AND STOPAT, REMEMBER
	MOVE	READ0,D.NEXT(STOP0)
	MOVE	I,SCNTMP
 IFN FTSTAT,<	AOS	FMACNT>
FMATCH:	CAME	I,STOPAT(OFIL)
	JRST	SCAN1
	EXCH	FIL,OFIL
	JRST	FNEND
MAYBEC:	SOJG	CNT,MAYBE
GOTCON:	MOVE	T1,FILTMP
	MOVE	T1,STOPAT(T1)
	SETZM	D.NEXT(T1)
	MOVE	T1,SCNTMP
	SETZM	D.NEXT(T1)
ENDDIF:	SETZ	FIL,
BEGDMP:	MOVEI	T1,1(FIL)
	DPB	T1,[POINT 2,LEAD,6]	;BUILD LEADIN STRING WITH RIGHT FILE #
	SETOM	INPAGE#			;IMPOSSIBLE PAGE NUMBER
	SKIPA	I,STLOC(FIL)		;ENTER WITH FIRST POINTER
LINOUT:	MOVE	I,D.NEXT(I)		;NEXT POINTER, PLEASE
	JUMPE	I,OTHFIL		;IF NO MORE LINES, TRY OTHER FILE
	LDB	T2,[POINT 7,D.STR(I),6]	;IS THIS LINE LACKING CHARACTER(S)?
	JUMPE	T2,LINOUT		;NO LINE, SKIP OUTPUT
	TXNN	F,F.FILC
	JRST	SCMLED
	HRRZ	T2,D.WHR(I)
	ADDI	T2,1
	MOVE	T4,[POINT 7,LEAD,13]
	CAMN	T2,INPAGE
	JRST	NOPAGN
	MOVEM	T2,INPAGE
	CALL	DECOUT
NOPAGN:	MOVX	T1,.CHTAB
	IDPB	T1,T4
	SETZ	T1,
	IDPB	T1,T4
SCMLED:	HRROI	T1,LEAD
LEDOUT:	PSOUT%
	HRROI	T1,D.STR(I)		;OUT THE LINE
	PSOUT%
	SETO	T2,			;FIND OUT IF LAST LINE ENDED WITH <LF>
	ADJBP	T2,T1			;..
	LDB	T2,T2			;..
	CAIN	T2,.CHLFD
	JRST	LINOUT
	HRROI	T1,CRLF			;DIDN'T. WE'LL ADD ONE FOR READABILITY
	PSOUT%
	JRST	LINOUT			;NEXT LINE...
OTHFIL:	JUMPN	FIL,ENDWRI		;IF BOTH FILES DONE, QUIT
	TXNN	F,F.FILC
	JRST	SCMOUT
	HRROI	T1,FILMID
	JRST	DMPBAR
SCMOUT:	MOVE	T4,[POINT 7,MIDLIN+2,20]
	MOVE	I,STLOC
	MOVE	T2,D.WHR(I)		;WITH LINE AND PAGE COUNTS FOR FUN
	MOVEM	T2,TMP#			;....
	MOVEI	T2,1(T2)
	CALL	DECOUT
	MOVE	T1,[POINT 7,[ASCIZ/, line /]]
	CALL	CSTRA
	HLRZ	T2,TMP
	CALL	DECOUT
	SKIPN	T3,D.LAB(I)
	JRST	NOLABM
	MOVE	T1,[POINT 7,[ASCIZ/ **** /]]
	CALL	CSTRA
	MOVE	T2,[POINT 6,T3]
LABO:	ILDB	T1,T2
	JUMPE	T1,ELABO
	ADDI	T1," "
	IDPB	T1,T4
	TLNE	T2,770K
	JRST	LABO
ELABO:	MOVEI	T1,":"
	IDPB	T1,T4
	SKIPN	T2,D.OFF(I)
	JRST	NOLABM
	MOVEI	T1,"+"
	IDPB	T1,T4
	CALL	DECOUT
	MOVEI	T1,"L"
	IDPB	T1,T4
NOLABM:	MOVEI	T1,.CHCRT		;FASTER THAN CSTR WITH CRLF
	IDPB	T1,T4
	MOVEI	T1,.CHLFD
	IDPB	T1,T4
	SETZ	T1,
	IDPB	T1,T4
	HRROI	T1,MIDLIN
DMPBAR:	PSOUT%				;NOPE, OUT SEPARATOR
	AOJA	FIL,BEGDMP		;SET FIL TO 1 AND DO OTHER FILE

ENDWRI:	HRROI	T1,BARLIN
	PSOUT%
	TXNN	F,F.EOF			;ALL DONE?
	SOJA	FIL,BFRCHK		;NO, KEEP SCANNING

FINIS:	TXNN	F,F.TTY			;IF OUT TO TTY, NO CLOSE STUFF
	JRST	GOCLOS
	TXNE	F,F.DIF
	JRST	DIFER
	JRST	NODIFS
GOCLOS:	SETO	T2,			;RESTORE PRIMARY JFNS
	MOVX	T1,.FHSLF
	SPJFN%
	 ERJMP	.+1
	TXNN	F,F.DIF			;IF NO DIF'S SEEN, LET FALL PREY...
	JRST	NODIFS			;..TO LEAVE CODE,...
	MOVE	T1,OUTJFN
	CLOSF%				;...ELSE CLOSE HERE.
	 ERJMP	.+1			;SNH
DIFER:	MOVE	T2,MESFLG
	CAIE	T2,M.DIF
	JRST	GCMD
	HRROI	T1,[ASCIZ/?Files are different./]
	JRST	LEAMSG
NODIFS:	HRROI	T1,[ASCIZ/?Files are identical./]
	MOVE	T2,MESFLG
	CAIN	T2,M.SAME
LEAMSG:	PSOUT%				;ELSE IF THE SAME, SAY SO
	JRST	GCMD

LEAVE:	SETO	T1,
	MOVE	T2,[.FHSLF,,WHRBFR]
	MOVE	T3,[1B0+777-WHRBFR+1]
	PMAP%
	 ERJMP	.+1
	MOVE	T1,[CZ%ABT+CZ%NUD+CZ%NIF+.FHSLF]
	CLZFF%				;BLOW AWAY ANYTHING LEFT AROUND
	RESET%				;BLOW HARDER
 IFN FTSTAT,<
	MOVX	T1,.FHSLF
	RUNTM%
	SUB	T1,STTIME
	MOVE	T2,T1
	HRROI	T1,[ASCIZ/
Runtime: /]
	CALL	SDECOT
	HRROI	T1,[ASCIZ/ ms.
Number of false alarms: /]
	PSOUT%
	MOVE	T2,FMACNT
	CALL	SDECOT
	SETZ	FIL,
	HRROI	T1,[ASCIZ ~
Number of rereads/lines:~]
	PSOUT%
RETYP:	MOVEI	T1,.CHTAB
	PBOUT%
	MOVE	T2,RERCNT(FIL)
	CALL	SDECOT
	MOVEI	T1,"/"
	PBOUT%
	SKIPE	T2,LINCNT(FIL)
	CALL	SDECOT
	TRCN	FIL,1
	JRST	RETYP
	HRROI	T1,[ASCIZ/
Max use of pools:/]
	PSOUT%
POLUSE:	MOVE	T2,PL1MAX(FIL)
	SUB	T2,BEGIN(FIL)
	MOVE	T3,BEGIN+1(FIL)
	SUB	T3,BEGIN(FIL)
	IMULI	T2,^D100
	IDIV	T2,T3
	CAIG	T2,0
	MOVEI	T2,1
	MOVEI	T1,.CHTAB
	PBOUT%
	CALL	SDECOT
	MOVEI	T1,"%"
	PBOUT%
	TRCN	FIL,1
	JRST	POLUSE
 >
	HALTF%				;DONE
	JRST	ST

;Subroutines and such like

;Probably faster than NOUT%
DECOUT:	PUSH	P,ZERO
DECOU2:	IDIVI	T2,^D10
	ADDI	T3,"0"
	PUSH	P,T3
	JUMPN	T2,DECOU2
DECOU3:	POP	P,T2
	JUMPE	T2,CPOPJ
	IDPB	T2,T4
	JRST	DECOU3

 IFN FTSTAT,<
SDECOT:	MOVEI	T3,^D10
	MOVX	T1,.PRIOU
	NOUT%
	 ERJMP	.+1
	RET
 >

;INLINE and SKLINE.
;Read a line and link it into the list. T2 returned pointing to the block
; so linked in. SKLINE switches input first, INLINE leaves it alone.
SKLINE:	TRC	FIL,1			;FLIP INPUT FIRST
	;..

INLINE:	SKIPN	T2,READ(FIL)		;ARE WE READING STUFF ALREADY IN CORE?
	JRST	INPUT			;NO
 IFN FTSTAT,<
	AOS	RERCNT(FIL)
 >
	MOVEM	T2,WHRBLK(FIL)		;YES, RESET THE POINTER
	MOVEI	T1,D.STR(T2)
	MOVEM	T1,LINE(FIL)		;STORE STRING POINTER
	MOVE	T1,D.NEXT(T2)		;AND ADVANCE "READ"
	MOVEM	T1,READ(FIL)
	JRST	CPOPJ1			;ALL DONE
INPUT:	SKIPG	INJFN(FIL)		;AT EOF?
	JRST	CPOPJ1			;YES, ALL DONE
	MOVE	T2,WHERE(FIL)		;WHERE TO BUILD NEW LINE BLOCK
	MOVEM	T2,WHRBLK(FIL)		;..
	SETZM	D.NEXT(T2)		;IT HAS NO NEXT YET
	MOVE	T1,PAGCNT(FIL)
	HRL	T1,LINCNT(FIL)
	MOVEM	T1,D.WHR(T2)		;STORE PAGE AND LINE STUFF
	MOVEI	T2,D.STR(T2)
	SETZM	(T2)			;STRING IS NULL
	MOVEM	T2,LINE(FIL)		;STORE NEW STRING ADDRESS
	HRLI	T2,(POINT 7)		;MAKE A POINTER
NONULL:	SOSL	BFRCNT(FIL)		;ANY CHARACTERS TO COPY?
	JRST	CHRIB			;NEW BUFFER NOT NEEDED
	MOVEM	T2,TMP			;STORE STRING POINTER FOR LATER
	SKIPG	T1,CHRFIL(FIL)		;ANY CHARACTERS LEFT TO READ
	JRST	EOFFLG			;NOPE, EOF
	MOVE	T2,T1			;COPY NUMBER OF CHARS.
	SUBI	T1,5*1000*NPAG		;DECR BY NUMBER THAT FIT IN BUFFER
	MOVEM	T1,CHRFIL(FIL)		;DECR FILE COUNT
	CAILE	T2,5*1000*NPAG		;MORE THAN A BUFFER LEFT?
	MOVEI	T2,5*1000*NPAG		;YES, BUT WE ONLY HAVE A BUFFER HERE
	SUBI	T2,1			;DECR FOR CHARACTER READ BELOW
	MOVEM	T2,BFRCNT(FIL)		;AND STORE COUNT
	MOVE	T1,ATPAG(FIL)		;USUAL ADVANCE THROUGH FILE PAGE STUFF
	HRL	T1,INJFN(FIL)
	MOVE	T2,[EXP WHRBFR,WHRBFR+NPAG](FIL)
	HRLI	T2,.FHSLF
	MOVX	T3,PM%CNT+PM%RD+PM%EPN+NPAG
	PMAP%
	 ERJMP	EOFFLG
	LSH	T2,9			;BUILD BYTE POINTER TO BUFFER
	HRLI	T2,(POINT 7)
	MOVEM	T2,BFRPTR(FIL)		;AND STORE
	MOVEI	T2,NPAG			;ADVANCE FILE COUNT
	ADDM	T2,ATPAG(FIL)
	MOVE	T2,TMP			;RESTORE T2
CHRIB:	ILDB	T1,BFRPTR(FIL)		;GET A CHARACTER!
	JUMPE	T1,NONULL		;WE DON'T TAKE NULLS
	CAIE	T1,.CHFFD		;FORMFEED?
	JRST	NFFD			;NO, TREAT NORMALLY
	AOS	PAGCNT(FIL)
	SETZM	LINCNT(FIL)
	MOVEI	T1,"^"
	IDPB	T1,T2
	TLNN	T2,760000
	SETZM	1(T2)
	MOVEI	T1,"L"
NFFD:	IDPB	T1,T2			;WRITE TO NEW LINE BLOCK
	TLNN	T2,760000		;IF LAST BYTE OF THIS WORD,...
	SETZM	1(T2)			;CLEAR NEXT WORD
	CAIE	T1,.CHLFD		;LINEFEED?
	JRST	NONULL			;NO, TRY AGAIN
NOEOF:	TXZA	F,F.END			;LINE COPIED, NO EOF
EOFFLG:	TXO	F,F.END			;HERE IF CHAR COUNT EXHAUSTED
	MOVEI	T2,2(T2)
	MOVEM	T2,WHERE(FIL)
 IFN FTAPPD,<
; This is here so the last line of a file is marked as unique - ie, the
;  last line of file 0 can only match the exact same text in file 1, if
;  that line in file 1 is also file 1's last line. The only effect this has
;  is that, if (for instance) file 1 is only different from file 0 in that
;  it is longer, then the last line of file 0 is typed out as differing.
; For instance, if file 0 is
;QQ
; And file 1 is
;QQ
;A
;B
; then the typeout would be
;1)	QQ
;*****
;2)	QQ
;2)	A
;2)	B
; instead of just
;2)	A
;2)	B
; This behaviour is different from FILCOM, and can be stopped by changing
;  the value of FTAPPD

	SKIPG	BFRCNT(FIL)		;IS THIS BUFFER NOW EMPTY?
	SKIPLE	CHRFIL(FIL)		;AND ARE THERE UNREAD BUFFERS OUT THERE?
	 JRST	.+2			;ONE'S FALSE. MORE CHARACTERS LEFT
	AOS	@LINE(FIL)		;JUST READ LAST LINE. MARK 1B35 IN IT
> ;End of FTAPPD

	CAMLE	T2,BEGIN+1(FIL)		;IS FILE INTO NEXT POOL?
	JRST	CURSE			;YES, GO DIE HIDEOUSLY
 IFN FTSTAT,<
	CAMLE	T2,PL1MAX(FIL)
	MOVEM	T2,PL1MAX(FIL)
>
	SETZB	T4,LABEL
	JUMPN	FIL,ESCAN
	TXNE	F,F.NMAC!F.FILC		;NOT A .MAC FILE? OR /SCM?
	JRST	ESCAN
	MOVE	T1,LINE(FIL)
	HRLI	T1,(POINT 7)
	MOVE	T2,[POINT 6,LABEL]
SCANL:	ILDB	T3,T1
	SKIPL	T3,CHRTAB(T3)
	JRST	ISNSYM
	SUBI	T3," "
	TLNE	T2,770K
	IDPB	T3,T2
	JRST	SCANL
ISNSYM:	CAIE	T3,":"
	SETZM	LABEL
ESCAN:	SKIPN	T1,LABEL
	JRST	NNLAB
	MOVEM	T1,OLDLAB
	SETZM	OFFSET
	JRST	NOLAB2
NNLAB:	AOS	OFFSET
NOLAB2:	TXNN	F,F.END			;IF AT EOF...
	AOS	LINCNT(FIL)			;DONT INCR LINE COUNT
FILE1:	MOVE	T2,WHRBLK(FIL)		;WHERE DOES THIS NEW BLOCK START?
	JUMPN	FIL,FILE1A
	MOVE	T1,OFFSET
	MOVEM	T1,D.OFF(T2)
	MOVE	T1,OLDLAB
	MOVEM	T1,D.LAB(T2)
FILE1A:	SKIPE	T1,LAST(FIL)		;IS THERE A LAST BLOCK TO POINT TO IT?
	MOVEM	T2,D.NEXT(T1)		;YES, LINK UP
EBLK:	MOVEM	T2,LAST(FIL)		;THIS IS NOW THE LAST BLOCK
	TXNN	F,F.END			;EOF CHECKS NOW?
	JRST	CPOPJ1			;NO, DONE
	;..
EOFFIL:	MOVE	T1,INJFN(FIL)		;EOF. CLOSE THIS FILE...
	CLOSF%
	 ERJMP	.+1
	SETOM	INJFN(FIL)		;MARK NO FILE HERE
	MOVNI	T1,-1(FIL)		;T1/ TRASH,,?xOTHER FILE NUMBER
	SKIPGE	INJFN(T1)		;IS THE OTHER FILE GONE TOO?
	TXOA	F,F.EOF			;YES, MARK DONE AND SING. RET
	AOS	(P)			;NO, SKIP RET
	RET

;SINGLE RET IF THE SAME, +2 IF DIF.
SAME:	MOVE	T3,(T1)
	CAME	T3,(T2)
	AOSA	(P)			;ANY DIFFERENCE IS A DIFFERENCE
	TRNN	T3,177*2		;ASCIZ NULL, 5TH POSITION
	RET
	ADDI	T1,1
	AOJA	T2,SAME

;WHYDIF:
; IFN FTAPPD,<
;	XOR	T3,(T2)			;IS 1B35 LIT FOR ONE BUT NOT THE OTHER?
;	TRNE	T3,1B35			;1B35 MARKS EOF
;	JRST	CPOPJ1			;YES, DIFFERENT, NO EXCUSES
; > ;END IFN FTAPPD
;	HRLI	T1,(POINT 7)		;NO, CHECK FOR TRAILING SPACE STUFF
;	HRLI	T2,(POINT 7)
;SAME1:	ILDB	T3,T1
;	ILDB	T4,T2
;	CAIE	T3,(T4)
;	JRST	DEFSEN
;	JUMPN	T3,SAME1
;	JRST	CPOPJ1
;DEFSEN:	JUMPE	T3,MAYOK
;TRAILS:	CAIE	T3,.CHCRT
;	CAIN	T3," "
;	JRST	MAYOK
;	CAIE	T3,.CHTAB
;	CAIN	T3,.CHLFD
;	JRST	MAYOK
;	JRST	CPOPJ1		;NOT THE SAME
;MAYOK:	JUMPE	T4,ISOK
;	CAIE	T4,.CHCRT
;	CAIN	T4,.CHLFD
;	JRST	ISOK
;	CAIE	T4," "
;	CAIN	T4,.CHTAB
;	JRST	ISOK
;	JRST	CPOPJ1
;ISOK:	CAIE	T3,0
;	ILDB	T3,T1
;	CAIE	T4,0
;	ILDB	T4,T2
;	JUMPN	T3,TRAILS
;	JUMPN	T4,TRAILS
;	RET

CSTRA:	ILDB	T2,T1			;COPY STRING REF'D BY T1 TO T4
	JUMPE	T2,CPOPJ		;DON'T COPY NULL
	IDPB	T2,T4
	JRST	CSTRA


INIINB:	<.CMINI>B8
CONINB:	<.CMCFM>B8
OFLINB:	<.CMCFM>B8+OF2INB
OF2INB:	<.CMFIL>B8+SWIINB
SWCINB:	<.CMCFM>B8+SWIINB
SWIINB:	<.CMSWI>B8
	EXP SWILST

SWILST:	SWILEN,,SWILEN
	[ASCIZ/EXIT/],,EXISWI
	[ASCIZ/MACRO:/],,MACSWI
	[ASCIZ/MESSAGE:/],,MESSWI
	[ASCIZ/SCM:/],,FILSWI
	[ASCIZ/WINDOW:/],,WINSWI
	SWILEN=.-SWILST-1

NUMINB:	<.CMNUM>B8
	^D10

DNSINB:	<.CMKEY>B8
	EXP	DNSLST

	M.SAME==0		;DEFAULT
	M.DIF==1		;DIFFERENT
	M.SHH==2

DNSLST:	DNSLEN,,DNSLEN
	[ASCIZ/DIFFERENT/],,M.DIF
	[ASCIZ/NONE/],,M.SHH
	[ASCIZ/SAME/],,M.SAME
	DNSLEN=.-DNSINB-1

YNINB:	<.CMKEY>B8
	EXP	YNLST

YNLST:	YNLEN,,YNLEN
	[ASCIZ/NO/],,0
	[ASCIZ/YES/],,1
	YNLEN==.-YNLST-1

;CALL TO PARSE WHATEVER.
PARSE:	COMND%
HITME:	 ERJMP	[SETO	T3,		;EOF (assumed) RETS -1
		 MOVX	T1,CM%NOP	;AND PARSE FAILURE
		 RET]
	HRRZS	T3
	LDB	T3,[POINT 9,(T3),8]
	TXNN	T1,CM%NOP
CPOPJ1:	AOS	(P)
CPOPJ:	RET

;CALL TO CONFIRM
CONFRM:	DMOVEM	T1,1(P)
	MOVEM	T3,3(P)
	DMOVE	T1,[EXP CMDBLK,CONINB]
	COMND%
	MOVE	T3,3(P)
	DMOVE	T1,1(P)
	RET

GUIDE:	HRROM	T1,GUIINB+.CMDAT
	DMOVEM	T2,1(P)
	DMOVE	T1,[EXP CMDBLK,GUIINB]
	COMND%
	DMOVE	T2,1(P)
	RET

NOINFL:	HRROI	T1,[ASCIZ/
?Can't access file /]
	PSOUT%
	MOVEI	T1,"1"(FIL)
	PBOUT%
	HRROI	T1,[ASCIZ/: /]
	JRST	LSTERR
LEN0FL:	HRROI	T1,[ASCIZ/
?File /]
	PSOUT%
	MOVEI	T1,"1"(FIL)
	PBOUT%
	MOVX	T1,.FHSLF
	MOVX	T2,BOTX04
	SETER%			;CONVENIENT ERROR MESSAGE CODE
	 ERJMP	.+1
	HRROI	T1,[ASCIZ/ is empty: /]
	JRST	LSTERR
NOOUFL:	HRROI	T1,[ASCIZ/
?Cant open output file: /]
	;..
LSTERR:	PSOUT%
	MOVX	T1,.PRIOU
	HRLOI	T2,.FHSLF
	SETZ	T3,
	ERSTR%
	JRST	GCMD
	JRST	GCMD
	JRST	GCMD

BADYQE:	HRROI	T1,[ASCIZ/
?Bad option to a switch./]
	JRST	LEAMSG

BADNQE:	HRROI	T1,[ASCIZ/
?Garbage for numeric input./]
	JRST	LEAMSG

UNPARS:	HRROI	T1,[ASCIZ/
?Unable to parse confirm, filename, or switch where expected./]
	JRST	LEAMSG

CURSE:	HRROI	T1,[ASCIZ/
?Internal buffer overflow./]
	JRST	LEAMSG
BARLIN: ASCIZ/***********************************************
/
FILMID:	ASCIZ	/****
/
BEGIN:	EXP	POOL1,POOL2,777700
CRLF:	ASCIZ/
/

;Character information. CH%SYM must be 1B0.
	CH%SYM==1B0
	CH%EOL==1B1
	CH%DIG==1B2
	CH%UPR==1B3
	CH%DWN==1B4

CHRTAB:		0
		1
		2
		3
		4
		5
		6
		7
		10
		11
	CH%EOL!	12
		13
	CH%EOL!	14
	CH%EOL!	15
		16
		17
		20
		21
		22
		23
		24
		25
		26
		27
		30
		31
		32
		33
		34
		35
		36
		37
		40
		41
		42
		43
	CH%SYM!	44
	CH%SYM!	45
		46
		47
		50
		51
		52
		53
		54
		55
	CH%SYM!	56
		57
	CH%DIG!CH%SYM!	60
	CH%DIG!CH%SYM!	61
	CH%DIG!CH%SYM!	62
	CH%DIG!CH%SYM!	63
	CH%DIG!CH%SYM!	64
	CH%DIG!CH%SYM!	65
	CH%DIG!CH%SYM!	66
	CH%DIG!CH%SYM!	67
	CH%DIG!CH%SYM!	70
	CH%DIG!CH%SYM!	71
		72
		73
		74
		75
		76
		77
		100
	CH%UPR!CH%SYM!	101
	CH%UPR!CH%SYM!	102
	CH%UPR!CH%SYM!	103
	CH%UPR!CH%SYM!	104
	CH%UPR!CH%SYM!	105
	CH%UPR!CH%SYM!	106
	CH%UPR!CH%SYM!	107
	CH%UPR!CH%SYM!	110
	CH%UPR!CH%SYM!	111
	CH%UPR!CH%SYM!	112
	CH%UPR!CH%SYM!	113
	CH%UPR!CH%SYM!	114
	CH%UPR!CH%SYM!	115
	CH%UPR!CH%SYM!	116
	CH%UPR!CH%SYM!	117
	CH%UPR!CH%SYM!	120
	CH%UPR!CH%SYM!	121
	CH%UPR!CH%SYM!	122
	CH%UPR!CH%SYM!	123
	CH%UPR!CH%SYM!	124
	CH%UPR!CH%SYM!	125
	CH%UPR!CH%SYM!	126
	CH%UPR!CH%SYM!	127
	CH%UPR!CH%SYM!	130
	CH%UPR!CH%SYM!	131
	CH%UPR!CH%SYM!	132
		133
		134
		135
		136
		137
		140
	CH%DWN!CH%SYM!	101
	CH%DWN!CH%SYM!	102
	CH%DWN!CH%SYM!	103
	CH%DWN!CH%SYM!	104
	CH%DWN!CH%SYM!	105
	CH%DWN!CH%SYM!	106
	CH%DWN!CH%SYM!	107
	CH%DWN!CH%SYM!	110
	CH%DWN!CH%SYM!	111
	CH%DWN!CH%SYM!	112
	CH%DWN!CH%SYM!	113
	CH%DWN!CH%SYM!	114
	CH%DWN!CH%SYM!	115
	CH%DWN!CH%SYM!	116
	CH%DWN!CH%SYM!	117
	CH%DWN!CH%SYM!	120
	CH%DWN!CH%SYM!	121
	CH%DWN!CH%SYM!	122
	CH%DWN!CH%SYM!	123
	CH%DWN!CH%SYM!	124
	CH%DWN!CH%SYM!	125
	CH%DWN!CH%SYM!	126
	CH%DWN!CH%SYM!	127
	CH%DWN!CH%SYM!	130
	CH%DWN!CH%SYM!	131
	CH%DWN!CH%SYM!	132
		173
		174
		175
		176
		177

JFSTAB:	1B8			;FILENAME FOR JFNS
	1B11			;EXTENSION FOR JFNS

	XLIST
	 LIT
	LIST

;WRITABLES
COINCH:	COINCI-1
MIDLIN:	ASCIZ	/**** On Page /
	BLOCK	^D80/5

LEAD:	BLOCK	2			;GETS SET UP AT RUN TIME
FLEAD:	ASCIZ	/File 0)	/

	BFRSIZ==^D50

CMDBLK:	0,,TRAPRP
	.PRIIN,,.PRIOU
	BLOCK	1			;PROMPT FILLED IN AT RUNTIME
	-1,,BFFR
	-1,,BFFR
	BFRSIZ*5-1
	BFRSIZ*5-1
	-1,,ATOM
	BFRSIZ*5-1
	GTJBLK

GUIINB:	<.CMNOI>B8
	BLOCK	1

GTJBLK:	BLOCK	16
ATOM:	BLOCK	BFRSIZ
BFFR:	BLOCK	BFRSIZ

CHRFIL:	BLOCK	2
BFRPTR:	BLOCK	2
INJFN:	BLOCK	2
WHERE:	BLOCK	2

TMPSTR:	BLOCK	50
ZERO:	BLOCK	1
LABEL:	BLOCK	1
OLDLAB:	BLOCK	1
OFFSET:	BLOCK	1
ATPAG:	BLOCK	2
BFRCNT:	BLOCK	2
LINE:	BLOCK	2
LAST:	BLOCK	2
WHRBLK:	BLOCK	2
LINCNT:	BLOCK	2
PAGCNT:	BLOCK	2
 IFN FTSTAT,<
RERCNT:	BLOCK	2
PL1MAX:	BLOCK	2
FMACNT:	BLOCK	1
 >
	 EZER=.-1

STACK:	BLOCK	15

	LIT			;JUST IN CASE
	VAR			;and all those vars...
ENDPRG:
	WHRBFR==<ENDPRG+100+2000>/1000+1	;PAGE TO START FILE BUFFERS AT
		 ;SPACE FOR PATCHING AND SYMBOLS

	END	<VECLEN,,VECT>