IF1 %%SCAN==0		;so files .insrt'ing can do right thing; should
IF2 %%SCAN==1		;have their .INSRT as follows:
			; if1 ifndef %%scan, .insrt ksc;nscan >
			; if2 ife %%scan, .insrt ksc;nscan >

ifndef pushae,[
DEFINE PUSHAE AC,LIST
IRP LOC,,[LIST]
PUSH AC,LOC
TERMIN
TERMIN

DEFINE POPAE AC,LIST
IRP LOC,,[LIST]
POP AC,LOC
TERMIN
TERMIN
]
DEFINE SCAN ?INPUT,BRKTBL,RESULT,BRKCHR
PUSH P,[BRKCHR]
PUSH P,[RESULT]
PUSH P,[BRKTBL]
PUSH P,[INPUT]
PUSHJ P,SCANRT
TERMIN

%BRKAD==1		;break char flag for appending to result
SCBRAD:	TLO A,%BRKAD
	JRST 2(B)	;return to right place in SCANRT
%BRKSK==2		;break char flag for skip of break char
SCBRSK:	TLO A,%BRKSK
	JRST 2(B)
%BRKLV==4		;break char flag for leaving on front of input
SCBRLV:	TLO A,%BRKLV
	JRST 2(B)
%BRKQT==10		;break char flag for gobbling following char
SCBRQT:	TLO A,%BRKQT
	JRST 2(B)

SCANRT:
.begin scnblk
define arg1
(p)-5!termin
define arg2
arg1-1!termin
define arg3
arg2-1!termin
define arg4
arg3-1!termin

	PUSHAE P,[A,B,C,D]
	MOVE D,ARG1		;get addr of input string
	MOVE C,1(D)		;get BP
	HRRZ D,(D)		;get char cnt
	JUMPE D,[MOVE A,[-1,,3]	;none left? Then EOS, no result string.
		MOVEM A,@ARG4	;store -1,,3 as "break char"
		SETZM @ARG3	;and clear 1st descriptor wd of result string (count)
		JRST SCNR90]	;and return.

SCNR20:	ILDB A,C		;get char from input string
	JSP B,@ARG2		;execute break table.
	SOJG D,SCNR20		;no break, continue
	JRST SCNR70		;again none left, EOS.

	;break char found! decipher flag(s) and return
	TLNE A,%BRKQT		; quote next
	 JRST SCNR45
	TLNE A,%BRKSK
	 JRST SCNR50		;skip break char.
	TLNE A,%BRKAD
	 JRST SCNR55		;go append break char to result
	TLNE A,%BRKLV
	 JRST SCNR60		;leave break char on front of input.
	JRST SCNR20		;no flags found?! continue.

	; quote next char
SCNR45:	SOJLE D,SCNR70		; jump if none left.
	ILDB A,C		; get it, ignore it.
	SOJG D,SCNR20		; get next.
	JRST SCNR70

	;skip break char - goes on neither result nor input.
SCNR50:	SOS @ARG1		;D is subtracted from this for result cnt, so ensure brkchar
				;isn't included within result.

	;append break char to result string
SCNR55:	SUBI D,1		;D becomes new input cnt, so ensure brkchr isn't included.
	JRST SCNR80		;and return thusly.

	;retain break char on front of input string
SCNR60:	ADD C,[70000,,0]	;must decrement bp to point back at brkchar.
	CAIG C,
	 SUB C,[430000,,1]	;(reset if go off wd edge)
	JRST SCNR80

	;EOS found and non-null result string.
SCNR70:	MOVE A,[-1,,3]		;"break char".
	MOVEM A,@ARG4
	JRST .+2

	;return result and update input as determined by count in D.
	;if control came directly here, result string would contain everything up to
	;break char, and input string cnt would include brk char but bp would point
	;immediately after it.
SCNR80:	HRRZM A,@ARG4		;store break char
	MOVE A,ARG1		;get addr of input string again.
	MOVE B,(A)		;get 1st wd of descriptor before clobbering.
	HRRM D,(A)		;store updated input string count.
	SUB B,D			;get descriptor with proper result string cnt
	EXCH C,1(A)		;exchange bp's to update input and get bp for result.
	MOVE A,ARG3		;get addr of result string now
	MOVEM B,(A)		;store 1st descriptor wd
	MOVEM C,1(A)		;and 2nd (bp).
SCNR90:	POPAE P,[D,C,B,A]
	SUB P,[5,,5]		;flush args and return addr
	JRST @5(P)		;and return.
.end scnblk