Google
 

Trailing-Edge - PDP-10 Archives - scratch - 10,7/unscsp/sos/sosfas.mac
There are 3 other files named sosfas.mac in the archive. Click here to see a list.
	TITLE	SOSFAS - Find and Search commands
; 	-----------------------------
; 
; This file contains the processing for Find and Substitute:
; 1. The find (F) command
; 2. The substitute (S) command
; 3. Common routines for searching files
; 
 
	SEARCH	SOSTCS
	$INIT
 
	SUBTTL	THE FIND (F) COMMAND
 
SEARCH::TLZ	FL,ASSMF	; Clear all flags
	SETZM	SRCNT		; Start with zero
	SETZM	CSW##		; Clear alter command string switch
	SETZM	ZSW0		; CLEAR SWITCHES
	MOVE	T1,[ZSW0,,ZSW0+1];Setup for blt
	BLT	T1,ZSW1		;And zero them
	MOVE	T1,[2,,[ASCIZ/F*/]]
	MOVEM	T1,FNDPMT	; Save find prompt
	TLO	FL2,L2.NAB	; Allow rubout of first altmode
	MOVE	T1,[POINT 9,SRBUF]; Set up byte pointer
	MOVEI	T3,SRPNT	; And pointer to byte pointer table
	PUSHJ	P,SSTRNG	; Get a search string
	JRST	[SKIPN SRPNT	; Was string set?
		NERROR	NSG	; No, tell him
		CAIN	C,12
		JRST	ASSMD1	; Special continue mode
		JRST	.+1]	; Yes, use old one
	TLZ	FL,NUMSRF!ALTSRF!EXCTSR; Clear flags
	SKIPE	EXACTF		; All searches to be exact?
	TLO	FL,EXCTSR	; Yes, set the exact bit
	PUSHJ	P,SCAN##	; Check for what comes after
	TRNN	FL,TERMF	; If terminator
	CAIN	C,","		; Or ,
	JRST	ASSMDT		; Set up limits specially
	CAIE	C,"!"
	CAIN	C,":"
	JRST	ASSMDT		; Let him specify 2nd half of range
	PUSHJ	P,GET2##	; Else call usual limit routine
SRC4:	MOVE	T1,HILN 	; Save end of range
	MOVEM	T1,SRHILN
	MOVE	T1,HIPG
	MOVEM	T1,SRHIPG
;Here to scan for switches in any order
SRCS1:	CAIE	C,","		;Something there
	  JRST	SRC1		;No
	PUSHJ	P,SCAN		;Yes--See what it is
	TRNN	FL,NUMF		;A NUMBER?
	  JRST	SRCS4		;No
	MOVEM	T2,SRCNT	;Yes--Save count
	JRST	SRCS3		;And continue
SRCS4:	TRNN	FL,IDF		;An indent?
	  JRST	SRCS2		;No
	MOVS	T1,ACCUM	;Yes--Get ident
	MOVE	T2,[-LNFSWT,,FSWT];Point to switches
	PUSHJ	P,DOSW		;Handle them
	  NERROR ILC		;No match
	JRST	SRCS3		;And continue
SRCS2:	SKIPN	NEWCMD		;See if in /compatibile mode
	 CAIE	C,"-"		;Yes--See if find not
	  JRST	SRCS2A		;No
	SETOM	FNSW		;Yes--Flag find not
	JRST	SRCS3		;And continue
SRCS2A:	CAIE	C,"*"		;Special check for infin repeate
	  NERROR ILC		;No--You lose
	HRLOI	T1,377777	;Yes--Set for lots
	MOVEM	T1,SRCNT	;Save
SRCS3:	PUSHJ	P,SCAN		;Read next token
	JRST	SRCS1		;And process
;End of switch scanning
SRC1:	TLNN	FL,ALTSRF	;Alter this linn
	 SKIPGE DSW		;Or delete?
	  TRNN FL,READOF	;Yes--See if readonly
	   CAIA			;No
	    NERROR IRO		;Yes--Illegal
	SKIPGE	MSW		;See if mark
	 TRNN	FL,READOF	;Yes--See if readonly
	  CAIA			;No
	   NERROR IRO		;Yes--Illegal
	SKIPGE	MSW		;See if mark
	 SKIPL	DSW		;And delete
	  CAIA			;No
	   NERROR ILC		;Yes--Illegal
	PUSHJ	P,CKTRMF##	; Make sure it terminates correctly
	SKIPE	CSW##		; Command alter mode?
	  PUSHJ	P,ACSTR##	; Yes--Get alter command string
SRCH1A: MOVEI	T1,SRPNT	; Get pointer to strings
	PUSHJ	P,CODSR 	; And generate code
	MOVE	T1,LOPG 	; Get set to hunt it
	MOVEM	T1,SRPG 	; Flag to say if we should print page
	TLO	FL2,NORENT	; Play it safe - no arbitrary reentering
	PUSHJ	P,FINDL1##	; Find first line of range
	TRZ	FL,LINSN	; No lines yet
	SETZM	FNDFLG		; No matches either
ONSRC:: PUSHJ	P,ONMOV##	; Check range
	  JRST	ENDSRC		; Done
	TLZE	FL,ASSMF	; First time and want .+1?
	JRST	[CAME T1,LOLN	; Is there exact match?
		JRST	.+1	; No, this is .+1
		AOS	SVCNT	; Pretend we didnt see it
		JRST	SRNXT]	; And take next
	TRO	FL,LINSN	; We saw one
	CAMN	T1,PGMK 	; Pages are special
	JRST	SRNXT		; Proceed
	MOVEI	T2,SRPNT	; Pointer to strings
	PUSHJ	P,COMTST	; Go search this line
	  JRST	SRNXT		; Loser
	SKIPE	FNSW		;See if find not
	  MOVEI	T3,0		;Yes--Clear alter count
	AOS	FNDFLG		; Found!
	MOVEM	T3,SVCCNT	; Save away the character count
	MOVE	T2,CPG		; Get current page
	CAME	T2,SRPG 	; And see if we should print it
	 SKIPE	SLSW		;But first see if silence
	  CAIA
	   PUSHJ P,PGPRN##	; Yes
	MOVE	T2,CPG		; Now set it as current
	MOVEM	T2,CPGL
	MOVEM	T2,SRPG 	; Also reset flag
	MOVE	T2,(PNTR)	; Also set line
	MOVEM	T2,CLN
	TLNE	FL,ALTSRF	; Are we going to edit?
	JRST	SRCALT		; Yes, go set things up
	SKIPE	SLSW		;Silence?
	  JRST	SRNXTC		;Yes--No print
	TLNE	FL,NUMSRF	; Do we want only line numbers?
	JRST	SRCNUM		; Yes
	PUSHJ	P,OUTLIN##
SRNXTC:	SKIPE	DSW		;See if delete
	  JRST	SRCDEL		;Yes--Go delete
	SKIPE	MSW		;See if mark
	  JRST	SRCMAR		;Yes--Go mark
	SOSG	SRCNT		; Have we found enough
	JRST	SRFND		; Yes, give up (we have seen at least one)
SRNXT:	PUSHJ	P,FINDN##	; Get next line to look a
	JRST	ONSRC
 
SRCNUM: MOVE	T1,(PNTR)	; Print sequence number
	MOVEM	T1,PRNTO1
	OUTSTR	PRNTO1
	JRST	SRNXTC		; And go
 
ENDSRC: TRZN	FL,LINSN	; Did we see one?
	NERROR	NLN		; Null range
SRFND:	SKIPE	T2,FNDFLG	; Find any?
	  JRST	SRFND1		;Yes!
	RERROR	SRF		; No: tell him
	JRST	COMND##		;And return
SRFND1:	SKIPE	DSW		;See if delete
	 SKIPN	INFFLG##	;Yes--See if /noinform
	  CAIA			;No
	   CAIA			;Yes--Dummy totals
	    SKIPE TSW		;See if totals wanted
	     CAIA		;Yes
	      JRST COMND##	;No--Just return
	PUSHJ	P,DPRNT##	;Print number
	OUTSTR	[ASCIZ/ line/]	;Give it
	SOSE	FNDFLG		;Just 1?
	  OUTCHR ["s"]		;No--Fix it up
	MOVEI	T1,[ASCIZ/ found/];Assume just find
	SKIPE	DSW		;See if delete
	  MOVEI	T1,[ASCIZ/ deleted/];Yes
	SKIPE	MSW		;See if mark
	  MOVEI	T1,[ASCIZ/ marked/];Yes
	TLNE	FL,ALTSRF	;See if alter
	  MOVEI	T1,[ASCIZ/ altered/];Yes
	OUTSTR	(T1)		;Type
	OUTSTR	[BYTE (7) 15,12];Finish off
	JRST	COMND##		;And return
 
 
SRCDEL:	MOVE	T1,(PNTR)	;Get current line
	PUSHJ	P,DODEL##	;Delete it
	PUSHJ	P,FINDN1##	;Find next line
	JRST	FNDEND		;And continue onward

SRCMAR:	PUSHJ	P,MARK1##	;Mark the page
	PUSHJ	P,FINDN##	;Find next line
	JRST	FNDEND		;And continue

SRCALT:	MOVEI	T5,[SKIPLE T2,SVCCNT 	; Get count 
		    PJRST ALTSP##
		    POPJ P,]		; Space over correctly
	PUSHJ	P,ALTLIN##
	JRST	LEVINS##	; He said altmode
	PUSHJ	P,INSED##	; Insert it
	PUSHJ	P,FINDN
FNDEND:	SOS	SAVEN		; Decrement save counter
	SOSG	SRCNT
	JRST	SRFND		; DONE
	JRST	ONSRC		; Go on

ASSMD1: TROA	FL,CNTF 	; Mark as keep end of range
ASSMDT: TRZ	FL,CNTF 	; Just in case
	TLO	FL,ASSMF	; We assume .+1
	MOVE	T1,CLN		; Set things up for . to infinity
	MOVEM	T1,LOLN
	MOVEM	T1,HILN 	; As good as anything with the page we will
	MOVE	T1,CPGL 	; Use
	MOVEM	T1,LOPG
	TRZE	FL,CNTF 	; Keep end?
	JRST	NOSPC		; Yes
	CAIE	C,":"		; If a : or !
	CAIN	C,"!"
	JRST	HALFSP		; Get the second half (.+1 to given)
	MOVSI	T1,377777	; Get a large page
	MOVEM	T1,HIPG
	JRST	SRC4		; Back into things

HALFSP: MOVEM	T1,HIPG 	; Set top as /.
	PUSHJ	P,GET2HF##	; Get the second half
	JRST	SRC4		; And go

NOSPC:	MOVE	T1,SRHIPG
	MOVEM	T1,HIPG 	; Put back end
	MOVE	T1,SRHILN
	MOVEM	T1,HILN
	JRST	SRCH1A

;Call: t1=sixbit
;	T2=-LEN,,TABLE

DOSW:	HLRZ	T3,(T2)		;Get sixbit
	CAIE	T1,(T3)		;Match?
	  AOBJN	T2,DOSW		;No--Loop
	JUMPG	T2,CPOPJ##	;Error if not found
	HRRZ	T3,(T2)		;Get routine
	XCT	(T3)		;Do it
	JRST	CPOPJ1		;And return

FSWT:	'A  ',,[TLO FL,ALTSRF]	;Alter this line
	'C  ',,[PUSHJ P,DOCSW]	;Alter this line with command string
	'D  ',,[SETOM DSW]	;Delete this line
	'E  ',,[TLO FL,EXCTSR]	;Exact case match
	'L  ',,[TLO FL,NUMSRF]	;Print line number only
	'M  ',,[SETOM MSW]	;Insert page mark before this line
	'N  ',,[PUSHJ P,DOFN]	;Find not
	'S  ',,[SETOM SLSW]	;Print nothing
	'T  ',,[SETOM TSW]	;Print totals
	'U  ',,[TRO FL2,SUPN]	;Print line w/o line number
LNFSWT==.-FSWT

DOCSW:	SETOM	CSW
	TLO	FL,ALTSRF
	POPJ	P,

DOFN:	SKIPN	NEWCMD		;Compatible mode?
	 TLOA	FL,NUMSRF	;Yes--Like "l"
	  SETOM	FNSW		;No--Set find not
	POPJ	P,		;And return
	SUBTTL	THE SUBSTITUTE (S) COMMAND
 
; Substitute a string
 
SUBST:: TLZ	FL,ASSMF	; Do not assume anything yet
	SETZM	PARCNT		; Zero count for sequential partials
	MOVE	T1,[2,,[ASCIZ/S*/]]
	MOVEM	T1,FNDPMT	; Save for multiple string prompt
	TLO	FL2,L2.NAB	; Allow rubout of first altmode
	HRLOI	T1,377777	; Set for lots
	MOVEM	T1,RPCNT
	MOVE	T1,[POINT 9,R1BUF]
	MOVEI	T3,R1PNT
	PUSHJ	P,SSTRNG	; This code is just like search
	JRST	[SKIPE R2PNT	; Both strings must have been given
		SKIPN	R1PNT
		NERROR	NSG	; Else there has been an error
		CAIN	C,12	; Check for just a crret
		JRST	ASBMD1	; And do a continue
		JRST	NOSTR]	; There is no string
	MOVE	T1,[POINT 9,R2BUF]; Get string to replace by
	MOVEI	T3,R2PNT
	PUSHJ	P,SSTRNG
	JRST	[CAIN C,12
		JRST	[PUSH P,[.]	; Set up return
			JRST	RETSTR]	; And read more (first null)
		MOVEM	T1,R2PNT	; Null string means delete
		MOVEI	T2,0	; So set a real null string
		IDPB	T2,T1
		JRST	.+1]
	SUBI	T3,R2PNT	; Generate number of replacement strings
	MOVEM	T3,RSTRCT	; And save for later
NOSTR:	TLZ	FL,NOPRN!DECID!EXCTS1; Clear flags
	SETZM	TSW		;Clear total switch
	SETZM	LSW		;And print line # only switch
	SKIPE	EXACTF		; All searches exact?
	TLO	FL,EXCTS1	; Yes, set the exact mode bit
	PUSHJ	P,SCAN		; And start looking for more junk
	TRNN	FL,TERMF	; Nothing
	CAIN	C,","		; Or just a comma
	JRST	ASBMDT		; Then search from here to eternity
	CAIE	C,"!"		; He only wants to give a stopping point
	CAIN	C,":"
	JRST	ASBMDT
	PUSHJ	P,GET2		; Go get a range
REP4:	MOVE	T1,HILN 	; Save for possible continue
	MOVEM	T1,RPHILN
	MOVE	T1,HIPG
	MOVEM	T1,RPHIPG
;Here to scan for switches in any order
REPS1:	CAIE	C,","		;Something there
	  JRST	REP1		;No
	PUSHJ	P,SCAN		;Yes--See what it is
	TRNN	FL,NUMF		;A NUMBER?
	  JRST	REPS4		;No
	MOVEM	T2,RPCNT	;Yes--Save count
	JRST	REPS3		;And continue
REPS4:	TRNN	FL,IDF		;An indent?
	  NERROR ILC		;No--Lose
	MOVS	T1,ACCUM	;Yes--Get ident
	MOVE	T2,[-LNSWT,,SLSWT];Point to switches
	PUSHJ	P,DOSW		;Handle them
	  NERROR ILC		;No match
REPS3:	PUSHJ	P,SCAN		;Read next token
	JRST	REPS1		;And process
;End of switch scanning
REP1:	PUSHJ	P,CKTRMF	; Make sure it terminates correctly
REP1A:	TLO	FL2,NORENT	; Don't allow arbitrary reenter from here on
	MOVEI	T1,R1PNT	; Get the search code
	PUSHJ	P,CODSR
	MOVE	T1,LOPG
	MOVEM	T1,RPPG 	; For print outs
	PUSHJ	P,FINDLO##	; Get first line of range
	TRZ	FL,LINSN	; Nothing yet
	SETZM	FNDFLG		; No how
	TLNE	FL2,PDECID
	TLO	FL,DECID	; Set if perm mode on
ONREP:	PUSHJ	P,ONMOV 	; Check for still in range
	JRST	ENDREP		; Finally
	TLZE	FL,ASSMF	; Should we start with .+1
	JRST	[CAME T1,LOLN	; Is it the one we asked for
		JRST	.+1	; No, use it
		AOS	SVCNT	; Just in case a ! type of range
		JRST	RPNXT]
	TRO	FL,LINSN	; This line is good enough
	CAMN	T1,PGMK
	JRST	RPNXT		; Go take care of page marks
	MOVEI	T2,R1PNT	; Do the search
	PUSHJ	P,COMSRC
	JRST	RPNXT
	AOS	FNDFLG		; Found
	SKIPGE	T3		; Protect agains special killing tab
	IBP	ALTP
	PUSH	P,T3		; Save count of how far into line
	MOVE	T3,(PNTR)	; Set up current line
	MOVEM	T3,CLN
	MOVE	T3,CPG
	MOVEM	T3,CPGL
	MOVE	T2,[XWD LIBUF,LIBUF+1]; Clear it out
	SETZM	LIBUF
	BLT	T2,LIBUF+MXWPL+1; We will do replace here
	MOVE	T2,PNTR 	; Get the pointer to the line
	MOVE	T3,(T2) 	; Pick up the first word
	MOVEI	T4,LIBUF	; The place to put it
	JRST	SBALT3		; Transfer
SBALT2: SKIPE	T3,(T2)
	TRNE	T3,1		; Is it the end of the line
	JRST	SBALT1
SBALT3: MOVEM	T3,(T4) 	; Put it away
	ADDI	T4,1
	AOJA	T2,SBALT2

SBALT1: SUBI	T4,LIBUF	; Get size line used to be
	MOVEM	T4,OCNT
	POP	P,CCNT		; Get the number of chrs into line
	SKIPGE	CCNT		; Must be .ge. 0
	SETZM	CCNT
	SUBI	ALTP,(PNTR)	; Convert pointer to libuf
	ADD	ALTP,[XWD 70000,LIBUF]; And back up one
NXTRPL: SETZM	PARCNT		; Zero for next rep
	LDB	T1,[POINT 4,-1(T1),12]; Get string number
	CAMLE	T1,RSTRCT	; Is it larger
	MOVE	T1,RSTRCT	; Then use last
	MOVE	T1,R2PNT(T1)
	MOVSI	T4,70000	; Decrement pointer
	ADDM	T4,SRCALP
REPSTR: ILDB	C,T1		; Get the next chr
	JUMPE	C,ENDRP 	; The end of the replace string
	TRZE	C,PT.PAT	;See if special
	 JRST	[TRZE C,PT.NUM	;Number coming?
		  JRST	REPNUM	;Yes--Go handle
		 CAILE	C,PATLEN;In range?
		  JRST	ERRIRS	;No--Error
		 JRST	@PATOUT(C)];And dispatch
PUTSTR: IDPB	C,ALTP		; Put in the replacement
	AOS	C,CCNT		; Advance count
	CAIL	C,MXWPL*5	; Check against max
	NERROR	LTL		; And lose
	JRST	REPSTR
ENDRP:	MOVE	T3,CCNT 	; Get count so search can go on
	PUSH	P,ALTP		; Save replace pointer
	PUSH	P,SRCALP	; And the end of input pointer
	MOVE	ALTP,SRCALP	; Continue from here
	ILDB	T1,SRCALP	; See what char we stopped on
	CAIE	T1,12		; Have we gone too far?
	PUSHJ	P,COMSRT	; This will continue
	JRST	FINLIN		; All done with matches, finish up
	CAIL	T3,MXWPL*5	; Are there too many?
	NERROR	LTL
	POP	P,T2
DOMOV:	ILDB	C,T2		; Move the chrs that did not match
	CAMN	T2,ALTP 	; Have we gotten to the next match
	JRST	DONMOV		; Yes
	IDPB	C,(P)		; The byte pointer is still in the stack
	JRST	DOMOV
DONMOV: MOVEM	T3,CCNT 	; Put the count back in core
	POP	P,ALTP		; This is now the deposit pointer
	JRST	NXTRPL		; Go do a replace

SLSWT:	'Q  ',,[TLO FL,DECID]	;Decide mode
	'E  ',,[TLO FL,EXCTS1]	;Exact case match
	'L  ',,[SETOM LSW]	;Print only line numbers
	'S  ',,[TLO FL,NOPRN]	;Print nothing
	'T  ',,[SETOM TSW]	;Give totals at the end
	'U  ',,[TRO FL2,SUPN]	;Print w/o line number
	'N  ',,[PUSHJ P,DOSN]	;In compatible mode, like s
	'D  ',,[PUSHJ P,DODS]	;In compatible mode, like q
LNSWT==.-SLSWT

DOSN:	SKIPE	NEWCMD##	;Compatible?
	  NERROR ILC		;No--Error
	TLO	FL,NOPRN	;Yes--Like s
	POPJ	P,		;And return

DODS:	SKIPE	NEWCMD##	;Compatible?
	  NERROR ILC		;No--Error
	TLO	FL,DECID	;Yes--Like q
	POPJ	P,		;And return

REPNUM:	CAILE	C,PATLEN	;In range?
	 JRST	ERRIRS		;No--Error
	ILDB	CS,T1		;Get count
	JRST	@PATNUM(C)	;And dispatch
FINLIN: POP	P,SRCALP	; Get set to move to end
	POP	P,ALTP
	ILDB	C,2(P)		; We just happen to know its still there
	CAIE	C,12		; If so we have eaten a return
	JRST	ENDFIN		; All is ok
FINL2:	MOVEI	C,15
	SKIPA			; So put it in
ENDFIN: ILDB	C,SRCALP
	IDPB	C,ALTP
	AOS	CS,CCNT
	CAIL	CS,MXWPL*5
	NERROR	LTL
	CAIE	C,12
	JRST	ENDFIN		; Done when we see the line feed
	MOVEI	T1,0		; Zero out rest of this line
DOZER:	TLNN	ALTP,760000	; Pointer at end of line?
	JRST	ZEROD
	IDPB	T1,ALTP
	JRST	DOZER
ZEROD:	SUBI	ALTP,LIBUF	; Movei ac,1-libuf(ac)
	MOVEI	ALTP,1(ALTP)	; Get count
	MOVEM	ALTP,NCNT
	TLNE	FL,NOPRN	; Did he want printing supressed
	JRST	NOPLIN
	MOVE	T2,CPG		; Get this page
	CAMN	T2,RPPG 	; Is it one we started on
	JRST	NOPPRN		; Yes, do not print 'page #'
	MOVEM	T2,RPPG 	; Save for next time
	PUSHJ	P,PGPRN
NOPPRN: SKIPL	LSW		;Print just line numbers?
	  JRST	NOPP2		;No
	MOVE	T1,LIBUF		;Get line number
	MOVEM	T1,PRNTO1	;Save for printer
	OUTSTR	PRNTO1		;Type it
	JRST	NOPP1		;And continue
NOPP2:	MOVEI	T2,LIBUF	; Print the line
	HRRZ	T1,NCNT		; Length of the line
	PUSHJ	P,OUTLN1##
NOPP1:	TLNN	FL,DECID	; Does he want the option of saying no
	JRST	NOPLIN		; No, insert it
NOVCMD: PUSHJ	P,GETONE##
	CAIN	T1,177		; Did he say rubout(do not insert)?
	JRST	REJECT		; Yes, just ignore this line
	CAIN	T1,15		; Did he say <CR>?
	INCHRW	T1		; Yes, flush out the line feed
	CAIE	T1,12
	CAIN	T1," "		; Space means use it
	JRST	ACCEPT
	ANDI	T1,137		; Force upper case
	OCRLF			; Need carriage return line feed now
	CAIN	T1,"N"		;See if no
	 JRST	REJECT		;Yes--Reject
	CAIN	T1,"Y"		;See if yes
	 JRST	ACCEPT		;Yes--Accept
	CAIN	T1,"H"		;See if help
	 JRST	HELP		;Yes
	CAIE	T1,"Q"
	CAIN	T1,"E"		; Does he want out
	JRST	ENDREP		; Yes: quit
	CAIN	T1,"A"
	JRST	RPALT
	CAIN	T1,"G"		; Get out of decide mode
	JRST	[TLZ FL,DECID	; Leave decide mode
		 JRST NOPLIN]
	OUTSTR	[BYTE (7) "?"," ",7,0,0]
	CLRBFI			; Clear him out
	JRST	NOVCMD		; Try again
HELP:	OUTSTR	[ASCIZ/
Type one of the following without carriage return

<space>	  Accept the change
<CR>	  Accept the change
<delete>  Restore original line and continue search
E	  Restore original line and end search
G	  Accept this change and all the rest without asking
N	  Restore original line and continue search
Q	  Restore original line and end search
Y	  Accept the change and continue
/]
	CLRBFI			;Flush buffer
	JRST	NOVCMD		;And try again
 
REJECT: 
IFN XSARSW,<
	SKIPN	EXPFLG		; Print correct reject message
>
	OUTSTR	[ASCIZ '[Rejected]
']
	JRST	RPNXT1		; Get next line
 
ACCEPT: 
IFN XSARSW,<
	SKIPN	EXPFLG		; Print correct accept message
>
	OUTSTR	[ASCIZ '[Accepted]
']
 
NOPLIN: PUSHJ	P,INSED 	; Insert the new line
	PUSHJ	P,FINDN 	; Get next
	SOSG	RPCNT		; See if out of count
	JRST	COMND
	MOVE	T1,(PNTR)	; Get pointer back
	JRST	ONREP

RPALT:	MOVE	T1,OCNT 	; Save count
	PUSHJ	P,RPSALT##
	PUSHJ	P,ALTLN1## 	; Do alter
	JRST	[OCRLF		; Quit
	      JRST ENDREP]
	JRST	NOPLINE 	; Use it now
ASBMD1: TROA	FL,CNTF 	; Mark as keep end of range
ASBMDT: TRZ	FL,CNTF 	; Just in case
	TLO	FL,ASSMF	; We assume .+1
	MOVE	T1,CLN
	MOVEM	T1,LOLN 	; Set for here to eternity
	MOVEM	T1,HILN
	MOVE	T1,CPGL
	MOVEM	T1,LOPG
	MOVEI	T1,1		; Set for only one
	MOVEM	T1,RPCNT
	TRZE	FL,CNTF 	; Keep end?
	JRST	NOSPSB
	CAIE	C,":"		; If a : or a !
	CAIN	C,"!"
	JRST	HALFSB		; Get the second half (.+1 to given)
	MOVSI	T1,377777	; Get a large page
	MOVEM	T1,HIPG
	JRST	REP4		; Onward
 
HALFSB: MOVEM	T1,HIPG 	; Set to as /.
	PUSHJ	P,GET2HF	; Get the second half
	JRST	REP4		; And go

NOSPSB: MOVE	T1,RPHIPG
	MOVEM	T1,HIPG
	MOVE	T1,RPHILN
	MOVEM	T1,HILN
	JRST	REP1A
QUOOUT:	ILDB	C,T1		; Get next chr
	JUMPN	C,PUTSTR	; Must not be 0
	JRST	ERRIRS		;This string is illegal

QUONUM:	ILDB	C,T1		;Get next char
	PUSH	P,T1		;Save byte pointer
QUONU1:	IDPB	C,ALTP		;Store char
	AOS	T1,CCNT		;Advance count
	CAIL	T1,MXWPL*5	;Check against max
	NERROR	LTL		;And lose
	SOJG	CS,QUONU1	;Loop for repeat count
	POP	P,T1		;Restore byte pointer
	JRST	REPSTR		;And continue

NXSOUT: AOS	CS,PARCNT	; Get next partial
DLMNUM: CAILE	CS,0
	 CAMLE	CS,ARBCNT	; Is it in range
	  JRST	ERRIRS		;No such partial string
	MOVE	T4,ARBPTR-1(CS)	;Get correct string pointer
FNDRST: ILDB	C,T4		; Now insert that string
	JUMPE	C,REPSTR	; Go finish the replacement string
	IDPB	C,ALTP
	AOS	C,CCNT
	CAIL	C,MXWPL*5
	NERROR	LTL
	JRST	FNDRST

UCLOUT:	AOS	CS,PARCNT	;Get next partial
	MOVE	C,[TRZ C," "]	;Upper case function
	JRST	XXXOUT
LCLOUT:	AOS	CS,PARCNT	;Get next partial
	MOVE	C,[TRO C," "]	;Lower case function
	JRST	XXXOUT
VCLOUT:	AOS	CS,PARCNT	;Get next partail
	MOVE	C,[TRC C," "]	;Invert case function
	JRST	XXXOUT

UCLNUM:	MOVE	C,[TRZ C," "]	;Upper case function
	JRST	XXXOUT
LCLNUM:	MOVE	C,[TRO C," "]	;Lower case function
	JRST	XXXOUT
VCLNUM:	MOVE	C,[TRC C," "]	;Invert case function

XXXOUT:	CAILE	CS,0		;Check range
	 CAMLE	CS,ARBCNT	;..
	  JRST	ERRIRS		;Error
	MOVEM	C,INOCHR##	;"AS GOOD A PLACE AS ANY"
	MOVE	T4,ARBPTR-1(CS)	;Get correct string pointer
XXXRST:	ILDB	C,T4		;Get a char
	JUMPE	C,REPSTR	;Jump if the end
	MOVE	CS,CTBL(C)	;Get bits
	TLNE	CS,LETF_16	;This a letter?
	 XCT	INOCHR##	;Yes--Do conversion
	IDPB	C,ALTP		;Store char
	AOS	C,CCNT		;Count chars
	CAIL	C,MXWPL*5	;See if too long
	 NERROR	LTL		;Yes--Die
	JRST	XXXRST		;No--Loop
RPNXT1: SOSG	RPCNT
	JRST	RPFND
RPNXT:	PUSHJ	P,FINDN
	JRST	ONREP		; Continue looking at lines

ENDREP: TRZN	FL,LINSN	; Were there any?
	NERROR	NLN
RPFND:	SKIPE	T2,FNDFLG	; Find any?
	  JRST	RPFND1		;Yes!
	RERROR	SRF		; Nope
	JRST	COMND		; Go on
RPFND1:	SKIPN	TSW		;Total wanted?
	  JRST	COMND		;No
	PUSHJ	P,DPRNT##	;Print number
	OUTSTR	[ASCIZ/ line/]	;Give it
	SOSE	FNDFLG		;Just 1?
	  OUTCHR ["s"]		;No--Fix it up
	OUTSTR	[ASCIZ/ substituted
/]
	JRST	COMND		;And return
	SUBTTL	COMMON ROUTINES FOR SEARCHING FILES
 
; This routine generates code for finding a match
; for the first character of a search string. The pointer
; to a set of byte pointers for search strings is in T1

CODSR::	MOVE	T2,[POINT 7,ARBBUF]	;Setup for first string
	MOVEM	T2,ARBPTR		;Store
	MOVEI	T2,CODEBF	; Set up pointer to place to put code
	MOVEI	ALTP,0		; The number of the current string
	HRLI	T1,-SRNUM	; The number of strings
CODS5:	TLZ	FL,NEGF!DEMCHR	; Turn off the ^E seen flag
	MOVE	T3,(T1)		; Get a pointer
	JUMPE	T3,ENDCOD	; A ZERO BYTE POINTER IS END OF CODE
READCD:	PUSHJ	P,CODCHR	;Get a char handling specials
READC1:	JUMPN	T5,(T5)		;Dispatch if special
COMLET:	MOVE	CS,CTBL(C)	; Get the majic bits
	TLNN	FL,EXCTS1!EXCTSR	; Is this an exact search?
	TLNN	CS,LETF_16	; Or not a letter
	JRST	NORMCR		; Yes just the test
	HRLI	C,(<CAIE C,>)	; Do a caie
	MOVEM	C,(T2)
	XOR	C,[XWD 4000,40]	; Cain .xor. caie = 4000,,0
	MOVEM	C,1(T2)
	TLNE	FL,NEGF		; ^E THAT CHR
	JRST	GENSKP		; Generate a skipa
COMXCT:	MOVE	C,[XCT JSPR]	; The call to search further
	DPB	ALTP,[POINT 4,C,12]	; Ac field gives string number
	MOVEM	C,2(T2)
	ADDI	T2,3		; Advance output pointer
ENDSTR:	ADDI	ALTP,1		; Next string
	AOBJN	T1,CODS5	; If any
ENDCOD:	MOVE	C,[JRST COMSRT]	; A RETURN
	MOVEM	C,(T2)
	POPJ	P,

CODCHR:	ILDB	C,T3		;Get next char
	JUMPE	C,ERRISS	;Error if nul
	MOVEI	T5,0		;Setup dispatch
	TRZN	C,PT.PAT	;Special pattern match char?
	 POPJ	P,		;No--Return
	TRZE	C,PT.NUM	;See if number following
	 IBP	T3		;Yes--Eat past it
	CAILE	C,PATLEN	;Yes--See if in range
	 JRST	ERRISS		;No--Illegal string
	MOVE	T5,PATCOD(C)	;Get dispatch
	POPJ	P,		;And return
SEPCOD:	MOVE	C,[SKIPG CS,CTBL(C)]	; Get bits
	MOVEM	C,(T2)
	MOVE	C,[TRNE CS,NSEPF]	; Check for %,$,or .
	TRNE	FL2,QSEPF		; Separators?
	MOVSI	C,(<SKIPA>)	; Yes; 
TSTNNS:				; Here to generate 'negative non-skip' code
	MOVEM	C,1(T2)
	TLNE	FL,NEGF		; Skipa in normal case
	JRST	COMXCT
GENSKP:	MOVSI	C,(<SKIPA>)
	MOVEM	C,2(T2)
	AOJA	T2,COMXCT	; So XCT will go in right place

QUOCOD:	ILDB	C,T3		; Get next chr
	JUMPE	C,ERRISS	;Error if end
	JRST	NORMCR		;And require exact case match regardless

BOLCOD:	HRRI	C,215		; GET SPECAIL BOL CHAR
	JRST	NORMCR		; AND CONTINUE
EOLCOD:	SKIPA	C,[CAIE C,15]	; Get <CR> char in rh of c & skip (lh irrelevant)
ANYCOD:	SKIPA	C,[CAIE C,15]	; Get special instr for <EOL> & skip
NORMCR:	HRLI	C,(<CAIN C,>)	; Exact or not letter
GENIVT:				; Here to invert txne/txnn or caie/cain
	TLNE	FL,NEGF
	TLC	C,4000		; Cain .xor. caie = 4000,,0
NORMC1:	MOVEM	C,(T2)
	SOJA	T2,COMXCT	; Make the XCT go in right pl@ce


INFCOD:	PUSHJ	P,CODCHR	;Get next char
	JUMPE	T5,READCD	;Nothing special
	CAIN	C,.PTNOT		; Just check validity
	 JRST	INFCOD
	CAIE	C,.PTINF	; Test for 'any number of'
	 CAIN	C,.PTMR1	; Test for '1 or more'
	  JRST	ERRISS		;Yes--Illegal format
	CAIN	C,.PTQUO
	 ILDB	C,T3
	JUMPE	C,ERRISS	;End of string error
	JRST	READCD		; Look for first other chr

JSPR:	JSP	T1,SRCRET	; Call continue search


SPCCOD:	MOVE	C,[CAIE C,11]	; The 'tab' test
	MOVEM	C,(T2)
	MOVE	C,[CAIN C,40]	; The 'space' test
	MOVEM	C,1(T2)
TSTNSK:	TLNE	FL,NEGF		; Test for negative
	JRST	GENSKP		; Yes, generate a skip
	JRST	COMXCT		; No, next instruction if successful

DGTCOD:	MOVE	C,[CAIL C,"0"]	; Lower-bound test
	MOVEM	C,(T2)
	MOVE	C,[CAILE C,"9"]	; Upper-bound test
	JRST	TSTNNS		; Fail gets no skip

LCLCOD:	MOVE	C,[CAIL C,"A"+40] ; Lower-bound test
	MOVEM	C,(T2)
	MOVE	C,[CAILE C,"Z"+40] ; Upper-bound test
	JRST	TSTNNS		; Fail gets no skip

UCLCOD:	MOVE	C,[CAIL C,"A"] ; Lower-bound test
	MOVEM	C,(T2)
	MOVE	C,[CAILE C,"Z"] ; Upper-bound test
	JRST	TSTNNS		; Fail gets no skip

LTRCOD:	MOVE	C,[MOVE CS,CTBL(C)] ; Get char status bits
	MOVEM	C,(T2)
	MOVE	C,[TLNE CS,LETF_16] ; Test for letter
	AOJA	T2,GENIVT	; Incr pc & jump to check - sign

ALMCOD:	MOVE	C,[MOVE CS,CTBL(C)] ; Get char status bits
	MOVEM	C,(T2)
	MOVE	C,[TLNE CS,<LETF!SNUMF>_16] ; Test for letter/number
	AOJA	T2,GENIVT	; Incr pc & jump to check - sign

MR1COD:	PUSHJ	P,CODCHR	;Get next char
	JUMPE	T5,READC1	;Ok
	CAIE	C,.PTINF	; Test for 'any # of'
	 CAIN	C,.PTMR1	; Test for '1 or more'
	  JRST	ERRISS		;Yes--Illegal
	JRST	READC1		;And look for it

NOTCOD:	TLC	FL,NEGF		; Invert the '-' sign
	JRST	READCD		; & CONTINUE READING

LSTCOD:	ILDB	T5,T3		;Get char count
LSTC.1:	ILDB	C,T3		;Get a char to match
	TLO	C,(CAIN C,)	;Generate instr to compare
	MOVEM	C,(T2)		;Store
	SOJLE	T5,[SOJA T2,TSTNSK]	;Return if end
	MOVEI	T4,1(T5)	;Copy
	LSH	T4,1		;Double
	ADDI	T4,-1(T2)	;Form address
	TLO	T4,(JRST)	;Make jrst
	MOVEM	T4,1(T2)	;Stode
	ADDI	T2,2		;Advance code
	JRST	LSTC.1		;And loop
; Read in the strings to search for
; T3 has place to put pointers, T1 a byte pointer for strings

 
SSTRNG::MOVEI	T2,SRBLG	; The permissible length
	HRLI	T3,-SRNUM	; T3 has pointer to place byte pointers
SSTR0:	MOVEM	T1,SVPT 	; Save the pointer for end of string
SSTR1:	PUSHJ	P,GNCH##	; Get a chr
	PUSHJ	P,ECHR		;Process if ^e special char
	 JRST	SSTR1		;It was--Get next char
	CAIN	C,200		; Altmode terminates
	 JRST	SSTEND
	CAIN	C,15		; Ignore returns
	 JRST	SSTR1
	CAIN	C,12		; Line feed is end of one string
	 JRST	SSTR2
	PUSHJ	P,SSCHR		;Store the char
	JRST	SSTR1		;And loop

SSTR2:	CAMN	T1,SVPT		; Null string?
	JRST	[HLRZ C,T3	; First one?
		CAIE	C,-SRNUM	; Well?
		JRST	.+1	; No
		MOVEI	C,12	; Return a line feed
		POPJ	P,]
RETSTR:	MOVEI	C,0		; Terminate string with 0
	PUSHJ	P,SSCHR		;Store the null
	MOVE	C,SVPT		; Set up pointer
	MOVEM	C,(T3)
	AOBJP	T3,[RERROR TMS
		    JRST SSERR]
	PUSH	P,T1
	MOVE	T1,FNDPMT	; x*, x={F,S,L}
	SKIPN	COMFLF		; Don't prompt if in command file
	PUSHJ	P,PROMPT##	; Prompt for next string
	POP	P,T1
	JRST	SSTR0

SSTEND: CAIN	T2,SRBLG	; Did we see any?
	POPJ	P,		; No, return
	MOVEI	C,0		; Yes, terminate last
	IDPB	C,T1
	MOVE	T1,SVPT
	MOVEM	T1,(T3)		; Set pointer
SSTR5:	AOBJP	T3,CPOPJ1	; Zero out other pointers
	SETZM	(T3)
	JRST	SSTR5

;Here to store C in the search string (pointed by T1) and give error
;if the string is too long

SSCHR:	IDPB	C,T1		;Store the char
	SOJG	T2,CPOPJ##	;Return if ok
	RERROR	STL		;String is too long
				;Fall into sserr

;Here to clean up after a scanning error (STL or TMS)

SSERR:	HRLZ	T1,T3		; Zero out first pointer
	MOVNS	T1
	ADDI	T1,-SRNUM(T3)	; Find start
	SETZM	(T1)		;And clear
	JRST	COMND
	SUBTTL	PSEUDO ^E CHARACTER HANDLING

ECHR:	CAIE	C,.PTPAT	;Special match char?
	 JRST	CPOPJ1		;No--Return
	SETZM	ENUM		;Clear number
	PUSH	P,T1		;Save some acs
	PUSHJ	P,GCHR		;Get upper case char
	PUSHJ	P,GETNUM	;Get number if there
	MOVEM	T1,ENUM		;Save number
	CAIN	C,"V"		;Flag for next letter coming?
	  JRST	VCHR		;Yes
	CAIN	C,"<"		;Open angle bracket?
	  JRST	ACHR		;Yes
	CAIN	C,"M"		;Flag for n'th match
	 SKIPE	ENUM		;And no number?
	  CAIA			;No
	   JRST	MCHR		;Yes--Go handle
	CAIN	C,"Q"		;Quote the char?
	 JRST	QCHR		;Yes
	CAIN	C,"["		;Bracket list?
	 JRST	LCHR		;Yes
	MOVSI	T1,-ELEN	;Get etable length
	CAIE	C,@ETAB(T1)	;Match?
	AOBJN	T1,.-1		;No--Loop
	JUMPG	T1,ERRISS	;Error if not found
	MOVE	C,ETAB(T1)	;Get char bits
EPATP:	POP	P,T1		;Restore byte pointer
				;Fall into epat
;Epat - add pattern char and number into string
;Call: t1=byte pointer, c=char bits
EPAT:	TLNE	C,(ET.NMI)	;See if number illegal
	 SKIPN	ENUM		;Yes--See if number given
	  CAIA			;Ok
	   JRST	ERRISS		;Yes--Error
	TLNE	C,(ET.NMR)	;See if number required
	 SKIPE	ENUM		;Yes--See if number given
	  CAIA			;Ok
	   JRST	ERRISS		;No--Error
;;	LDB	C,[POINTR (C,ET.COD)];Get pattern code
	LDB	C,[POINT 9,C,8]	;Get pattern code
	TRO	C,PT.PAT	;Flag special
	SKIPE	ENUM		;See if number
	 TRO	C,PT.NUM	;Yes--Flag its following
	PUSHJ	P,SSCHR		;Store the pattern char
	SKIPE	C,ENUM		;Get the number
	 PUSHJ	P,SSCHR		;Store if given
	POPJ	P,		;And return

MCHR:	PUSHJ	P,GCHR			;Get next char
	PUSHJ	P,GETNUM		;Get number
	MOVEM	T1,ENUM			;Save number
	JUMPE	T1,ERRISS		;Error if zero
	CAIE	C,.PTPAT		;^E NEXT?
	 JRST	ERRISS			;No--Error
	PUSHJ	P,GCHR			;Get next char
	CAIE	C,"M"			;End of string?
	 JRST	ERRISS			;No--Error
	MOVE	C,TABDLM		;Get .ptdlm bits
	JRST	EPATP			;And store

VCHR:	PUSHJ	P,GCHR		;Get a char
	CAIN	C,"V"
	 MOVE	C,TABVCL		;Get .ptvcl bits
	CAIN	C,"L"
	 MOVE	C,TABLCL		;Get .ptlcl bits
	CAIN	C,"U"
	 MOVE	C,TABUCL		;Get .ptucl bits
	CAIG	C,177
	 JRST	ERRISS
	JRST	EPATP

QCHR:	MOVE	C,TABQUO		;Get .ptquo bits
	POP	P,T1			;Get byte pointer back
	PUSHJ	P,EPAT			;Store pattern char
	PUSHJ	P,GNCH		;Get a char
	CAIN	C,200		;See if <esc>
	 MOVEI	C,33		;Yes--Convert
	PJRST	SSCHR		;And go store

LCHR:	POP	P,T1			;Get byte pointer back
	MOVE	C,TABLST		;Get .ptlst bits
	PUSHJ	P,EPAT			;Store
	MOVSI	T4,-^D100		;Get max
LCHR1:	PUSHJ	P,GNCH			;Get a char
	MOVEM	C,CHRBLK(T4)		;No--Save it
	PUSHJ	P,GNCH			;Get a char
	AOBJP	T4,ERRISS		;Error if too many
	CAIN	C,"]"			;End?
	 JRST	LCHR2			;Yes
	CAIN	C,","			;Terminate?
	 JRST	LCHR1			;Yes
	JRST	ERRISS			;No--Error
LCHR2:	MOVEI	C,(T4)			;Get count
	MOVN	T4,C			;Get -count
	HRLZI	T4,(T4)			;Get -count,,0
	PUSHJ	P,SSCHR			;Store the count
LCHR3:	MOVE	C,CHRBLK(T4)		;Get a char
	PUSHJ	P,SSCHR			;Store
	AOBJN	T4,LCHR3		;Loop
	POPJ	P,			;And return
ACHR:	MOVEI	T1,0			;Clear number
ACHR1:	PUSHJ	P,GCHR			;Get next char
	CAIL	C,"0"			;See if digit
	 CAILE	C,"7"			;..
	  JRST	ACHR2			;No
	LSH	T1,3			;Shift digits over
	ADDI	T1,-"0"(C)		;Combine
	JRST	ACHR1			;And loop
ACHR2:	CAIG	T1,177			;Too big?
	 CAIE	C,">"			;Close angle bracket?
	 JRST	ERRISS
	EXCH	T1,(P)			;Get byte pointer,save number
	MOVE	C,TABQUO		;Get .ptquo bits
	PUSHJ	P,EPAT			;Handle pattern char
	POP	P,C			;Restore number
	PJRST	SSCHR			;Store and return
GETNUM:	MOVEI	T1,0			;Clear number
GETNM1:	CAIL	C,"0"			;Digit?
	 CAILE	C,"9"			;..
	  POPJ	P,			;No--Return
	IMULI	T1,^D10			;Accumulate digits
	ADDI	T1,-"0"(C)		;,,
	PUSHJ	P,GCHR			;Get next char
	JRST	GETNM1			;And loop

GCHR:	PUSHJ	P,GNCH##	;Get next char
	TRZ	C,200		;Clear special chars
	MOVE	CS,CTBL(C)	;Get bits
	TLNE	CS,LETF_16	;Letter?
	 TRZ	C,40		;Yes--Make upper case
	POPJ	P,		;And return

;Pattern match table
;Define code,char,number illegal,number required
;
DEFINE XX(CODE,CHAR,NUMI,NUMR),<
	EXP	CODE*ET.COD+<"CHAR">*ET.CHR+NUMI*ET.NMI+NUMR*ET.NMR
>

ET.COD==1B8
ET.NMI==1B9
ET.NMR==1B10
ET.CHR==1

ETAB::	XX .PTLTR,<L>,0,0
	XX .PTNXS,<X>,0,0
	XX .PTNOT,<N>,1,0
	XX .PTINF,<*>,1,0
TABDLM:	XX .PTDLM,<M>,0,1
	XX .PTDGT,<D>,0,0
	XX .PTANY,<C>,0,0
	XX .PTMR1,<+>,1,0
	XX .PTALM,<A>,0,0
	XX .PTSPC,< >,0,0
	XX .PTEOL,<Z>,1,0
	XX .PTBOL,<B>,1,0
	XX .PTSEP,<S>,0,0
TABLCL:	XX .PTLCL,<\>,0,0
TABUCL:	XX .PTUCL,<^>,0,0
TABVCL:	XX .PTVCL,<V>,0,0
TABQUO:	XX .PTQUO,<Q>,0,0
TABLST:	XX .PTLST,<[>,0,0
ELEN==:.-ETAB
COMTST:	PUSHJ	P,COMSRC	;Do the search
	 TDZA	T1,T1		;Failure--Set to 0
	  MOVEI	T1,1		;Success--Set to 1
	SKIPE	FNSW		;See if find not
	  XORI	T1,1		;Yes--Invert answer
	ADDM	T1,(P)		;Modify return of success
	POPJ	P,		;And return

; The search itself

COMSRC::MOVEM	T2,BUFSAV	; Save the pointer to strings
	CAML	PNTR,BUFBLL	; Is this line known to be in core?
	PUSHJ	P,GETLTH##	; No, make sure line is in core
	MOVNI	T3,1		; The count of how far into line we are
	MOVEI	ALTP,1(PNTR)	; Set byte pointer
	HRLI	ALTP,(<POINT 7,0,6>)
	MOVEI	C,215		; Start with a line delimiter
	JRST	CODEBF		; Go scan
COMSRT:	ILDB	C,ALTP		; We return here if no match for this one
	CAIE	C,12		; Done?
	AOJA	T3,CODEBF	; No, go on
	POPJ	P,		; Yes, non-match retunr

SRCRET:	PUSH	P,T1		; Save the return address
	PUSH	P,ALTP		; And the string pointer
	PUSH	P,C		; And the character
	LDB	T1,[POINT 4,-1(T1),12]	; Get string number
	ADD	T1,BUFSAV	; Point to byte pointer
	SKIPN	T1,(T1)		; Get it
	ERROR	ICN		; There should be one there
	MOVE	T2,[POINT 7,ARBBUF]	; Set up arbit match
	MOVEI	T4,MXWPL*^D10	; Pointer and count
	SETZM	ARBCNT		; The number of arbitrary matches seen
	TLZ	FL,ARBITG	; Off at start
	PUSHJ	P,LINMAT	; Go check for match
	JRST	LOSE		; We lose, continue scan
	MOVEM	ALTP,SRCALP	; Pointer to end of string
	POP	P,C		; Restore
	POP	P,ALTP
T1PPJ1::	POP	P,T1
CPOPJ1::	AOS	(P)	; Skip return
	POPJ	P,
LOSE:	POP	P,C		; Restore
	JRST	APOPJ##
NXTCHR:	CAIN	C,12		; Was that last of line?
	 POPJ	P,		; Yes, lose 
	ILDB	C,ALTP		; No, try next
LINMAT:	PUSHJ	P,CHRMAT	; Check for match
	 POPJ	P,		; None, return
	JUMPN	CS,NXTCHR	;Jump if more
	AOS	(P)		; SAVE A JRST CPOPJ1
	POPJ	P,		;Skip return


CHRMAT:	TLZ	FL,NEGF!DEMCHR	; No ^E seen and chr can be 0
READCH:	ILDB	CS,T1		; Get next
	JUMPE	CS,MATCH	;Jump if end of string
	TRZE	CS,PT.PAT	;See if special
	 JRST	[TRZE CS,PT.NUM	;Number coming?
		  JRST	NUMCON	;Yes
		 CAILE	CS,PATLEN;No--See if in range
		  JRST	ERRISS	;No--Error
		 JRST	@PATCON(CS)]	;And process
TSTCHR:	CAIN	C,(CS)		;Are they the same?
	 JRST	ISTRU1		; Yes, check negf
	MOVE	T5,CTBL(CS)	; Get bits
	TLNN	FL,EXCTS1!EXCTSR	; Exact?
	TLNN	T5,LETF_16	; Or not let
	JRST	ISFALS		; No match
	XORI	CS,40		; Check other case
EXACHR:	CAIN	C,(CS)
	 JRST	ISTRU1
	JRST	ISFALS		; Lose

MATCH:	TLNE	FL,DEMCHR	; Did we need a character there?
	 JRST	ERRISS		;Yes, illegal string
	JRST	CPOPJ1	; Ok return
; Pattern match special character branch table

.PTPAT=="E"-100		;^E = SPECIAL PATTERN FLAG IE NEXT CHAR IS .PT???
PT.NUM==200	;Number byte following 
PT.PAT==400	;Special pattern in last 7 bits

	DEFINE	PATS,<
	XLIST
PATC <NUL,LTR,NXS,NOT,UCL,INF,DLM,DGT,ANY,MR1,LCL,ALM,BOL,SPC,EOL,VCL,QUO,SEP,LST>
	LIST
>

DEFINE	PATC(LIST),<
	IRP LIST,<
	IF1,<BLOCK 1>
	IF2,<
		IFDEF LIST'COD,<EXP LIST'COD>
		IFNDEF LIST'COD,<EXP ERRISS>
	>
>
>

PATCOD:	PATS

DEFINE	PATC(LIST),<
	IRP LIST,<
	IF1,<BLOCK 1>
	IF2,<
		IFDEF LIST'CON,<EXP LIST'CON>
		IFNDEF LIST'CON,<EXP ERRISS>
	>
	>
>

PATCON:	PATS

DEFINE	PATC(LIST),<
	IRP LIST,<
	IF1,<BLOCK 1>
	IF2,<
		IFDEF LIST'OUT,<EXP LIST'OUT>
		IFNDEF LIST'OUT,<EXP ERRIRS>
	>
	>
>

PATOUT:	PATS

DEFINE	PATC(LIST),<
	IRP LIST,<
	IF1,<BLOCK 1>
	IF2,<
		IFDEF LIST'NUM,<EXP LIST'NUM>
		IFNDEF LIST'NUM,<EXP ERRIRS>
	>
	>
>

PATNUM:	PATS

DEFINE	PATC(LIST),<
	IRP LIST,<
	IF1,<BLOCK 1>
	IF2,<
		IFDEF LIST'CUM,<EXP LIST'CUM>
		IFNDEF LIST'CUM,<EXP ERRISS>
	>
	>
>

PATCUM:	PATS
	PATLEN==-1		;So +1 starts with zero
DEFINE	PATC(LIST),<IRP LIST,<.PT'LIST==<PATLEN==PATLEN+1>>>

	PATS

ERRISS:	NERROR	ISS
ERRIRS:	NERROR	IRS
	SUBTTL	F/S CONTINUATION CHECKING ROUTINES

LTRCON:	MOVE	T5,CTBL(C)	; Get char bits
	TLNE	T5,LETF_16	; Test for a letter
	JRST	ISTRU		; Yes, jump
	JRST	ISFALS		; No, jump

NOTCON:	TLC	FL,NEGF		; Invert the negative flag
	TLO	FL,DEMCHR	; Require a next char
	JRST	READCH		; & READ ON

UCLCON:	TDZA	T5,T5		; Set zero for upper case
LCLCON:	MOVEI	T5,40		; Set 40 for lower case
	CAIL	C,"A"(T5)	; Test for letter
	CAILE	C,"Z"(T5)	; Test for letter
	JRST	ISFALS		; No, jump
	JRST	ISTRU		; Yes, jump

DGTCON:	CAIL	C,"0"		; Test for a decimal digit
	CAILE	C,"9"		; Test for a decimal digit
	JRST	ISFALS		; No, jump
	JRST	ISTRU		; Yes, jump

ALMCON:	MOVE	T5,CTBL(C)	; Get char bits
	TLNE	T5,<LETF!SNUMF>_16 ; Test for letter/number
	JRST	ISTRU		; Yes, jump
	JRST	ISFALS		; No, jump

SPCCON:	CAIE	C,40		; Test for space
	CAIN	C,11		; Test for tab
	JRST	ISTRU		; Yes, jump
	JRST	ISFALS		; No, jump

EOLCON:	CAIE	C,15		; Test for end of line
	JRST	ISFALS		; No, jump
	JRST	ISTRU		; Yes, jump

BOLCON:	CAIE	C,215		; TEST FOR BOL
	JRST	ISFAL1		; NO, JUMP
	JRST	ISTRU1		; YES, JUMP

QUOCON:	ILDB	CS,T1		;Get next char
	JUMPE	CS,ERRISS	;Error if zero
	JRST	EXACHR		;And go test

ANYCON:	CAIE	C,15			;Eol
	 CAIN	C,215			;Bol
	  JRST	ISFALS			;Yes--Lose
	JRST	ISTRU			;No--Win

SEPCON:	MOVE	T5,CTBL(C)		; Get table ent
	JUMPG	T5,ISFALS		; Not a sep
	TRNN	FL2,QSEPF		; Check . % $
	TRNN	T5,NSEPF		; Checking - do we have one?
	JRST	ISTRU		; No: sep
	JRST	ISFALS		; Yes: not a sep

LSTCON:	ILDB	T5,T1		;Get repeat count
LSTN.1:	ILDB	CS,T1		;Get a char
	CAIN	CS,(C)		;Match?
	 JRST	LSTN.2		;Yes--Win
	SOJG	T5,LSTN.1	;No--Loop
	JRST	ISFALS		;And lose
LSTN.2:	SUBI	T5,1		;Fix up count
	ADJBP	T5,T1		;Advance pointer
	MOVE	T1,T5		;Position back in t1
	JRST	ISTRU		;And win
	SUBTTL	NUMCON -- HANDLE ^EN<PATTERN>

;These routine tries to find n of the specified pattern character
;If they do, the string is stored in arbbuf and arbcnt is incremented
;Once only and the skip return is taken.  failure takes the non-skip
;Return, with the arbbuf setup anyway.

NUMCON:	ILDB	CN,T1			;Get count
	SOJE	CN,@PATCON(CS)		;Dispatch if just one
	JRST	NUMC.2			;And skip fetch char
NUMC.1: ILDB	C,ALTP			;Get a new char
	CAIN	C,12			;See if eol
	 JRST	ISTRU1			;Yes
NUMC.2:	PUSHJ	P,@PATCUM(CS)		;See if matches
	 JRST	ISFAL1			;Fail unless not
	SOJG	CN,NUMC.1		;Yes--Loop for all
	ILDB	C,ALTP			;Get last
	PJRST	@PATCON(CS)		;And dispatch
	SUBTTL	F/S CUMTINUATION CHECKING ROUTINES (NUMBERS)

;These routines are just like xxxcon routines except they dispatch
;To nstru/nsfals instead of istru/isfals as the former routines
;Do not terminate the arbtrary string nor increment the arbcnt 
;Counter. they are duplicated for speed only, vs having a flag
;In the xxxcon routines to control storage.

LTRCUM:	MOVE	T5,CTBL(C)	; Get char bits
	TLNE	T5,LETF_16	; Test for a letter
	JRST	NSTRU		; Yes, jump
	JRST	NSFALS		; No, jump

UCLCUM:	TDZA	T5,T5		; Set zero for upper case
LCLCUM:	MOVEI	T5,40		; Set 40 for lower case
	CAIL	C,"A"(T5)	; Test for letter
	CAILE	C,"Z"(T5)	; Test for letter
	JRST	NSFALS		; No, jump
	JRST	NSTRU		; Yes, jump

DGTCUM:	CAIL	C,"0"		; Test for a decimal digit
	CAILE	C,"9"		; Test for a decimal digit
	JRST	NSFALS		; No, jump
	JRST	NSTRU		; Yes, jump

ALMCUM:	MOVE	T5,CTBL(C)	; Get char bits
	TLNE	T5,<LETF!SNUMF>_16 ; Test for letter/number
	JRST	NSTRU		; Yes, jump
	JRST	NSFALS		; No, jump

SPCCUM:	CAIE	C,40		; Test for space
	CAIN	C,11		; Test for tab
	JRST	NSTRU		; Yes, jump
	JRST	NSFALS		; No, jump

EOLCUM:	CAIE	C,15		; Test for end of line
	JRST	NSFALS		; No, jump
	JRST	NSTRU		; Yes, jump

BOLCUM:	CAIE	C,215		; TEST FOR BOL
	JRST	NSFAL1		; NO, JUMP
	JRST	NSTRU1		; YES, JUMP

QUOCUM:	ILDB	CS,T1		;Get next char
	JUMPE	CS,ERRISS	;Error if zero
	JRST	TSTCHR		;And go test

ANYCUM:	CAIE	C,15			;Eol
	 CAIN	C,215			;Bol
	  JRST	NSFALS			;Yes--Lose
	JRST	NSTRU			;No--Win

SEPCUM:	MOVE	T5,CTBL(C)		; Get table ent
	JUMPG	T5,NSFALS		; Not a sep
	TRNN	FL2,QSEPF		; Check . % $
	TRNN	T5,NSEPF		; Checking - do we have one?
	JRST	NSTRU		; No: sep
	JRST	NSFALS		; Yes: not a sep
MR1CON:!
INFCON:	TLNN	FL,NEGF		; This has no meaning
	TLOE	FL,ARBITG	; Are we seeing 
	 JRST	ERRISS		;Yes, illeal string
	PUSH	P,T1		; Save search pointer
	MOVEI	T5,0		; Set arbitrary string to null
	IDPB	T5,T2
	SOJLE	T4,ILFMTR
	AOS	T5,ARBCNT
	MOVEM	T2,ARBPTR(T5)	;Save pointer to n'th string
	PUSH	P,ARBCNT	; Save in case we come back with no match
	PUSH	P,T2
	PUSH	P,T4
	PUSH	P,C
	CAIE	CS,.PTMR1	; Test for '1 or more'
	JRST	CHKTHS		; No, jump
	TLO	FL,DEMCHR	; Character demanded now
	PUSHJ	P,READCH	; Test for next character matches
	  JRST	ARBFAI		; No, then this doesn't match
	JRST	ARBAL1		; Yes, then treat as normal arbitrary
CHKTHS:	TLO	FL,DEMCHR	; Need a character now
	PUSHJ	P,READCH	; Call self recursively
	JRST	PROCED		; This could not match just scan on
ARBAL1:				; To here on first match
	MOVE	T2,-3(P)	; Restore arbit count
	MOVEM	T2,ARBCNT
	MOVE	T4,-1(P)	; And arbit chr count
	MOVE	T2,-2(P)	; And pointer
	PUSH	P,ALTP		; Save chr pointer
	TLZ	FL,ARBITG	; Can see another  now
	PUSHJ	P,LINMAT	; A MATCH
	JRST	RECUR		; No, try for another of that chr
	ADJSP	P,-7		; Get all that junk off stack
	JRST	CPOPJ1 		; And return to caller of linmat
RECUR:	POP	P,ALTP		; Get back pointer
	POP	P,C		; And chr
	MOVE	T4,-2(P)	; Restore count
	MOVEM	T4,ARBCNT
	POP	P,T4
	POP	P,T2		; Also chr counter and pointer
	DPB	C,T2		; Put in that chr
	MOVEI	T5,0		; And terminator
	IDPB	T5,T2
	SOJLE	T4,ILFMTR
	MOVE	T5,ARBCNT	;Get arbcnt
	MOVEM	T2,ARBPTR(T5)	;Save pointer to n'th string
	PUSH	P,T2
	PUSH	P,T4		; Resave
	MOVE	T1,-3(P)	; Restore search pointer
	ILDB	C,ALTP		; Get another chr
	PUSH	P,C		; Sav it
	TLZ	FL,NEGF		; Turn this off for recursion
	CAIE	C,12		; End of world?
	JRST	CHKTHS
ARBFAI:				; To here to fail the match
	ADJSP	P,-5		; Reduce stack
	POPJ	P,		; And error ret
PROCED:	TLZ	FL,ARBITG!NEGF	; Just go on
	POP	P,C
	POP	P,T4
	POP	P,T2
	POP	P,ARBCNT
	POP	P,(P)		; Get rid of extra pointer
	JRST	CHRMAT		; Continue match scanning
	SUBTTL	ISTRU/ISFALS

;These routines are called with  c/ char to store in arbitrary buffer.
;The buffer counter is terminated with a null following and arbcnt
;Count is incremented. istru returns cpopj
;If neg flag on, cpopj1 if neg flag off. isfals returns cpopj if neg
;Flag off, cpopj1 if neg flag on.

ISFALS:	CAIN	C,15		; Is it a return
	  AOJA	T4,.+2		; Adjust count and enter a null string
	IDPB	C,T2		; Save in arbit
	MOVEI	T5,0
	IDPB	T5,T2
	SUBI	T4,2		; Count them
	JUMPLE	T4,ILFMTR	; This line must have illegal format
	AOS	T5,ARBCNT	; One more seen
	MOVEM	T2,ARBPTR(T5)	;Store pointer to n'th string
ISFAL1:	TLNE	FL,NEGF		; Was neg flag on?
	 JRST	[CAIE	C,15	;Eol
		  CAIN	C,215	;Bol
		   POPJ P,	;Yes--Never win
		 AOS	(P)	;No--Skip return
		 POPJ	P,]	;..
	POPJ	P,

ISTRU:	CAIN	C,15
	  AOJA	T4,.+2
	IDPB	C,T2		; Save chr
	MOVEI	T5,0
	IDPB	T5,T2
	SUBI	T4,2
	JUMPLE	T4,ILFMTR
	AOS	T5,ARBCNT
	MOVEM	T2,ARBPTR(T5)	;Store pointer to n'th string
ISTRU1:	TLNN	FL,NEGF		; Negate?
	 AOS	(P)		; No, match
	POPJ	P,
	SUBTTL	NSTRU/NSFALS

;These routines are just like istru/isfals except that they do
;Not terminate the arbitrary string with a null nor is the
;Arbcnt counter incremented. these are used
;By the numcon continuation routine to treat ^e5d as 1 string

NSFALS:	CAIN	C,15		; Is it a return
	  AOJA	T4,.+2		; Adjust count and enter a null string
	IDPB	C,T2		; Save in arbit
	SOJLE	T4,ILFMTR	; This line must have illegal format
NSFAL1:	TLNE	FL,NEGF		; Was neg flag on?
	JRST	[CAIE	C,15	;Eol
		  CAIN	C,215	;Bol
		   POPJ P,	;Yes--Never win
		 AOS	(P)	;No--Skip return
		 POPJ	P,]	;..
	POPJ	P,

NSTRU:	CAIN	C,15
	  AOJA	T4,.+2
	IDPB	C,T2		; Save chr
	SOJLE	T4,ILFMTR
NSTRU1:	TLNN	FL,NEGF		; Negate?
	 AOS	(P)		; No, match
	POPJ	P,
ILFMTR: MOVE	T1,(PNTR)	; Give him an error message about
	MOVEM	T1,LINOUT	; This dirty line
	OUTSTR	LINOUT		; Poof
	MOVE	T2,CPG
	PUSHJ	P,DPRNT##
	NERROR	ILFMT
	XLIST
	LIT
	LIST
	RELOC	0

ENUM:	BLOCK	1
ARBPTR::	BLOCK	^D100
CHRBLK:	BLOCK	^D100
ZSW0:!
DSW:	BLOCK	1
MSW:	BLOCK	1
SLSW:	BLOCK	1
LSW:	BLOCK	1
TSW:	BLOCK	1
FNSW:	BLOCK	1
ZSW1==.-1

	END