Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_SRC_3_19910112 - utilities/peruse.mac
There are no other files named peruse.mac in the archive.
;ACCT:<SU-UTILITIES>PERUSE.MAC.18, 18-May-83 20:38:27, Edit by F.FMF
;Add top-level FIRST and LAST commands
;ACCT:<SU-UTILITIES>PERUSE.MAC.17, 18-Apr-83 16:52:01, Edit by F.FMF
;Flush CFIBF% to allow typeahead
;ACCT:<SU-UTILITIES>PERUSE.MAC.16, 30-Mar-83 15:18:23, Edit by F.FMF
;Add PREVIOUS command

TITLE PERUSE - A FILE PERUSER
SUBTTL DEFINITIONS

;WRITTEN JANUARY 1980 BY KIRK LOUGHEED
;CODE FOR STRING SEARCH ALGORITHM BY MAN CHOR KO

SEARCH MONSYM, MACSYM
.REQUIRE SYS:MACREL.REL
ASUPPRESS
XALL

;ASSEMBLY SWITCHES

;THE REGISTERS

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

CHAR=5				;CURRENT CHARACTER
FILBYT=6			;FOR INDEXING INTO BP TO ACCESS BYTES IN FILE
FILWRD=7			;CURRENT WORD IN FILE
TEMP=10				;USED ONLY IN FSRCH
PAGE1=11			;FIRST PAGE OF CURRENT RANGE
PAGE2=12			;LAST PAGE OF CURRENT RANGE
FPOS=13				;POSITION IN FIND ARRAY

P=17				;STACK POINTER
OPDEF SKPA [TRNA]

;PARAMETERS

PAGE==30			;PAGE USED BY PMAP
STKLEN==50			;STACK LENGTH
BUFLEN==50			;BUFFER LENGTH FOR VARIOUS BUFFERS
BUFCHR==BUFLEN*5-1		;NUMBER OF CHARS IN A BUFFER OF LENGTH BUFLEN
BPTBSZ==276			;SIZE OF INDEXING BYTE POINTER TABLE
ALPHSZ==^D128			;SIZE OF THE ALPHABET
MXPATL==^D97			;MAXIMUM SEARCH PATTERN LENGTH
PTBUFL==MXPATL/5+1		;PATTERN BUFFER LENGTH 
BIG=1750			;THIS WILL CAUSE DELTA1 TO INCREMENT BIG
MAXFP=2000			;LARGE ARRAY FOR PAGE RANGES FOUND
INFLG== GJ%OLD!GJ%DEL!GJ%IFG	;FLAGS FOR AN INPUT FILE SPEC
SUBTTL MACRO DEFINITIONS


;MACSYM-TYPE CHARACTER DEFINITIONS

.CHDQT==42			;DOUBLE QUOTE
.CHSQT==47			;SINGLE QUOTE


CM%HPP==CM%HPP!CM%SDH		;WITH OWN HELP, SUPPRESS NORMAL HELP
CM%FIX==0			;This feature may go away, so work without it.


;MACRO TO PRINT A CRLF ON THE SCREEN

DEFINE	OCRLF <
	CALL	[ TMSG	<
>				;OUTPUT A CRLF
		  RET ]
>

;MACRO TO CALL COMMAND JSYS SUBROUTINE

DEFINE PARSE (TYPE) <
	MOVEI	T2,TYPE		;THE OBVIOUS WAY
	CALL	PARSER		;DOES A COMND
>

;FIELD DESCRIPTOR BLOCK MACRO (A SHUFFLED VERSION OF FLDDB.)

DEFINE FIELD (FUNCTION,DATA,NEXT,HELP,FLAGS) <
	..XX==CM%FIX		;ALWAYS FIX UP IF AVAILABLE
	IFNB <FLAGS>,<..XX==FLAGS!CM%FIX>	;THROW IN FLAGS IF ANY
	FLDDB. FUNCTION,\..XX,<DATA>,<HELP>,,<NEXT>
>

;SPECIAL PARSE MACROS

DEFINE NOISE (STRING) <PARSE <[FIELD .CMNOI,<-1,,[ASCIZ STRING]>]>>
DEFINE CONFRM <
	CALL	[ MOVEI	T2,JUSTCR	;SLIGHTLY BETTER SEQUENCE FOR
		  CALLRET PARSER ]	;FREQUENTLY USED CALL
>

;MACRO USED IN BUILDING KEYWORD TABLES

DEFINE X (STRING,ADDRESS,FLAGS) <
	[IFNB <FLAGS>,<FLAGS!CM%FW!CM%INV>
	 ASCIZ STRING],,ADDRESS
>
SUBTTL COMMAND LOOP

;THINGS TO PARSE

SETUP:	FIELD	.CMINI
COMAND:	FIELD	.CMKEY,COMTAB
FILSPC:	FIELD	.CMFIL
JUSTCR:	FIELD	.CMCFM,,,<press RETURN>

;THE COMMAND TABLE

COMTAB:   COMLEN,,COMLEN
	X (ADVANCE,ADVANC)
	X (COPY,COPY)
	X (EXIT,EXIT)
	X (F,FNDCMD,CM%ABR)	;ABBREV FOR FIND
	X (FI,FIRCMD,CM%ABR)	;ABBREV FOR FIRST
FNDCMD:	X (FIND,FIND)
FIRCMD:	X (FIRST,FIRST)
	X (GET,GET)
	X (HELP,HELP)
	X (L,LASCMD,CM%ABR)	;ABBREV FOR LAST
LASCMD:	X (LAST,LAST)
	X (LIST,LISTIT)
	X (N,NEXCMD,CM%ABR)	;ABBREV FOR NEXT
NEXCMD:	X (NEXT,NEXTPG)
	X (NO-PAUSE,TENPAU)
	X (P,PRVCMD,CM%ABR)	;ABBREV FOR PREVIOUS
	X (PAUSE,TEPAU)
PRVCMD:	X (PREVIOUS,PREVPG)
	X (QUIT,QUIT)
	X (SHOW,SHOW)
	X (TYPE,TYPE)
COMLEN==.-COMTAB-1


START:	RESET%			;INITIALIZE WORLD
	MOVE	P,[IOWD STKLEN, STACK] ;SET UP THE STACK
	SETZM	STRBUF		;NO SEARCH STRING YET
	SETZM	JFN		;NO FILE YET
	CALL	SETINT		;SET UP INTERRUPT HANDLER

	CALL	CHKSCN		;CHECK RESCAN BUFFER
NEWCOM:	PARSE	SETUP		;INITIALIZE COMMAND STATE BLOCK
	HRRZ	T1,CSTATE	;SHOULD BE JUMP TO RPARSE, BUT OK IF NOT
	JRST	(T1)
RPARSE:	MOVE	P,[IOWD STKLEN, STACK] ;IN CASE OF REPARSE
	SETOM	OKINT		;PERMIT CTRL/O INTERRUPTS
	PARSE	COMAND
	HRRZ	T2,(T2)		;GET SUBROUTINE ADDRESS
	CALL	(T2)		;TRANSFER TO CORRECT SUBROUTINE
	JRST	NEWCOM		;CALL(T2) INSTEAD OF JRST(T2) PAYS DIVIDENDS
SUBTTL EXIT AND HELP COMMANDS

EXIT:	CONFRM
	RESET%
	SETZM JFN
	SETZM TJFN
	SKPA
QUIT:	 CONFRM
	HALTF%
	RET

;HERE ON THE HELP COMMAND

HELP:	CONFRM
	HRROI	T1,HLPMSG
	PSOUT%			;PRINT THE HELP MESSAGE
	RET			;RETURN TO COMMAND LOOP

	XLIST			;DON'T CREF THIS LITERAL
HLPMSG:	ASCIZ\

PERUSE is a general purpose file perusal program.  To get a file, type GET and
the file name to the PERUSE> prompt.  You may also use the rescan buffer,
i.e., by typing "peruse myfile.txt" to the EXEC you will enter PERUSE with
that file.  Wildcards (* and %) are permitted in the file specification, e.g.,

		PERUSE> GET myfile.txt
		PERUSE> GET *.pgo

Below is a summary of the commands.  Note that a page refers to a disk page.


GET	Get the first file of the file group specified.  A file group is
	obtained by using a wildcard such as '*' in the file specification,
	e.g. <s.smith>*.pgo is the file group consisting of all files with
	the 'pgo' extension in the directory <s.smith>.

ADVANCE	Advance to the next file in the file group.

TYPE	Type a page or range of pages in the current file.  You may specify
	only one page, a range of pages, the next page, the previous page, the
	first page, the last page, or all pages.  If no page is specified,
	then the current page is used.  You may also specify NEXT without
	first saying TYPE.  Below are some examples.

		PERUSE> TYPE (PAGE) 1
		PERUSE> TYPE (PAGE) 3 (TO PAGE) 10
		PERUSE> TYPE (PAGE) NEXT
		PERUSE> TYPE (PAGE) PREVIOUS
		PERUSE> TYPE (PAGE) FIRST
		PERUSE> TYPE (PAGE) LAST
		PERUSE> TYPE (PAGE) ALL
		PERUSE> NEXT (PAGE)

	CTRL/O will abort the typeout of the current page.

FIND	Search the entire file for a string, reporting the pages on which it
	occurs, if any.  Once a search string is specified, the FIND command
	will default to that string until a new search string is given.  The
	search string is remembered from file to file.

		PERUSE> FIND (STRING) Foo Bar
		"FOO BAR" occurs on page(s) 3,4,10
		PERUSE> ADVANCE (TO NEXT FILE IN GROUP)
		PERUSE> FIND
		"FOO BAR" occurs on page(s) 1,3

SHOW	Display information on the current file, including the file group
	specification, the current file specification, the file length, and
	the current page.  The current page is what is typed if you do not
	give an argument to the TYPE command.

COPY	Copy a range of pages into another file.  This command can be used to
	break up extremely large files into smaller components.

		PERUSE> COPY (INTO FILE) myfile.out (PAGE) 45 (TO PAGE) 63

LIST	List a range of pages on the lineprinter.

		PERUSE> LIST (PAGE) 45 (TO PAGE) 50

PAUSE	When your screen fills up, terminal output will pause until you type
	^Q (hold down CTRL and press Q).  This is the normal case, and you
	need do nothing in order to get this mode.

NO-PAUSE   Terminal output will not pause when your screen fills up, but you
	   may still type ^S (hold down CTRL and press S) to make the output
	pause.  As usual, type ^Q to resume the output.

QUIT	Leave PERUSE.  

EXIT	Flush current file and group, then leave PERUSE.

\
	LIST			;RESUME CREFFING
SUBTTL RESCAN BUFFER ROUTINE

;HERE TO CHECK RESCAN BUFFER FOR A FILE SPEC.
;RETURNS +1 ALWAYS

CHKSCN:	STKVAR	<<RSCBUF,20>>
	MOVEI	T1,.RSINI	;READ FROM RESCAN BUFFER
	RSCAN%			;DO IT
	 ERJMP	CHKX		;BOMBED, RETURN NOW
	JUMPE   T1,R		;NOTHING IN RESCAN BUFFER, JUST RETURN
CHKSN1:	MOVNM	T1,T3		;PUT -COUNT INTO C
	MOVEI	T1,.PRIIN
	HRROI	T2,RSCBUF	;PUT IT IN THIS BUFFER
	SIN%			;GET THE INPUT
	MOVE	T2,[POINT 7,RSCBUF]
	DO.
	 ILDB	T1,T2		;GET A BYTE
	 CAIN	T1,.CHLFD	;A LINE FEED?
	  RET			;GO BACK NOW
	 CAIE	T1," "		;A SPACE?
	  CAIN	T1,.CHTAB	;OR A TAB?
	   SKPA
	    LOOP.		;IF NEITHER, THEN LOOKS LIKE WE NEED MORE
	ENDDO.
	DO.
	 MOVEM	T2,T3		;SAVE POINTER
	 ILDB	T1,T2		;GET A CHAR
	 CAIN	T1," "		;A SPACE?
	  LOOP.			;YES, GET ANOTHER
	ENDDO.
	MOVE	T2,T3		;NO, RESTORE POINTER
	DO.
	 ILDB	T1,T3		;GET A CHAR
	 CAIE	T1,.CHLFD	;A LF?
	  CAIN	T1,.CHCRT	;OR A CR?
	   EXIT.		;EITHER, GO OUT
	 LOOP.			;OTHERWISE LOOP
	ENDDO.
	SETZ	T1,		;GET A NULL
	DPB	T1,T3		;DROP END OF FILE SPEC WITH NULL
	MOVX	T1,INFLG!GJ%SHT	;WANT SHORT FORM FOR INPUT FILESPEC
GETJFN:	GTJFN%
	 ERJMP	CHKX		;BOMBED

USEJFN:	MOVEM	T1,JFN		;WE'RE COMMITTED TO THIS JFN
	CALL	MAKSTR		;STORE TEXT FORM OF JFN
	CALL	OPEN		;TRY TO OPEN FILE
	 JRST	GETX		;GO SEE IF ANY WILDCARDS
FILLEN:	CALL	FILE		;PRINT FILE NAME
	CALLRET	LENGTH		;AND SIZE, AND RETURN

;HERE ON VARIOUS JSYS ERRORS

CHKX:	CALL	WARN		;WHAT HAPPENED
ZJFN:	HRRZ	T1,JFN		;RELEASE JFN, IF ANY
	RLJFN%
	 NOP			;IGNORE ERROR
	SETZM	JFN		;SIGNAL NO FILE
	RET


;HERE ON OPEN FAILURE, TRY NEXT FILE IN GROUP

GETX:	MOVE	T1,JFN		;GET THE OFFENDING JFN
	TLNE	T1,(GJ%DEV!GJ%DIR!GJ%NAM!GJ%EXT!GJ%VER)	;WILDCARDS?
	 JRST	ADV1		;YES, TRY NEXT FILE IN GROUP
	JRST	ZJFN		;SET NO JFN FLAG AND RETURN TO COMMAND LOOP
SUBTTL GET A FILE

;HERE TO GET A NEW FILE

GET:	NOISE	(FILES IN GROUP)
	CALL	IFILE		;PARSE INPUT FILE
	CONFRM
	CALL	CLOSE		;DISPOSE OF THE OLD ONE
	MOVE	T1,TJFN		;NEW JFN
	JRST	USEJFN		;SET UP FILE GROUP AND RETURN TO COMMAND

COMMENT \
;TOP (OF FILE GROUP) COMMAND
TOP:	CALL	CHKFIL		;WANT TO BE ABLE TO ASSUME REALLY HAVE ONE
	 RET			;GO HOME IF NONE YET
	NOISE	(OF FILE GROUP)
	CONFRM
	CALL	CLOSE		;DISPOSE OF OLD ONE
	MOVSI	T1,(INFLG!GJ%SHT)  ;SHORT FORM ON IN-CORE STRING
	HRROI	T2,JFNSTR
\

;HERE ON THE ADVANCE COMMAND

ADVANC:	CALL	CHKFIL		;SKIP IF WE HAVE A FILE
	 RET			;NO FILE SPEC GIVEN YET
	NOISE	(TO NEXT FILE IN GROUP)
	CONFRM
ADV1:	MOVSI	T1,(CO%NRJ)	;SET RETAIN JFN BIT
	HRR	T1,JFN		;DON'T CLOBBER THAT BIT
	CLOSF%			;CLOSE THE FILE
	 NOP			;NOT INTERESTED IN FAILURE HERE
ADV2:	MOVE	T1,JFN		;USE FULL JFN
	GNJFN%			;GET NEXT FILE
	 ERJMP	ADVDON		;LOOKS LIKE WE'RE DONE
	CALL	OPEN		;NOW TRY TO OPEN
	 JRST	ADV2		;FAILED, SO LOOK AT NEXT FILE
	JRST	FILLEN		;DISPLAY FILE NAME AND ITS LENGTH

ADVDON:	CALL	NEWLIN
	TMSG	<No more files in this group
>				;SAY WHAT PROBABLY HAPPENED
	JRST	ZJFN		;FLAG NOT CURRENT JFN AND RETURN
SUBTTL TYPE, LIST, AND COPY COMMANDS

;HERE ON THE TYPE COMMAND

TYPE:	CALL	RANGE		;GET OUR RANGE
	 RET			;ILLEGAL RANGE
TYPO:	MOVEI	T2,.PRIOU	;OUTPUT JFN
	MOVEM	T2,TJFN
	CALL	COPPAG		;COPY THE RANGE OF PAGES TO THE SCREEN
	OCRLF			;A PARTING CRLF
	RET			;RETURN TO COMMAND LEVEL

NEXTPG:	CALL	CHKFIL		;DO WE HAVE AN INPUT FILE?
	 RET			;NO FILE
	NOISE	(PAGE)
	CONFRM
	CALL	RNGNXT		;CALCULATE NEXT PAGE
	CAMLE	T2,SIZE		;CHECK IT
	 CALLRET  RNGOVR
	MOVE	T1,T2		;DUPLICATE IT
	DMOVEM	T1,PAGE1	;SET IT
	JRST	TYPO		;DO IT

PREVPG:	CALL	CHKFIL		;DO WE HAVE AN INPUT FILE?
	 RET			;NO FILE
	NOISE	(PAGE)
	CONFRM
	CALL	RNGPRV		;CALCULATE PREVIOUS PAGE
	SKIPG	T1,T2		;DO WE HAVE A VALID PAGE NUMBER?
	 CALLRET  RNGUND
	DMOVEM	T1,PAGE1	;SET IT
	JRST	TYPO		;DO IT

FIRST:	CALL	CHKFIL		;DO WE HAVE AN INPUT FILE?
	 RET			;NO FILE
	NOISE	(PAGE)		;GUIDE WORD
	CONFRM
	MOVEI	PAGE1,1		;FIRST PAGE IS PAGE 1
	MOVEI	PAGE2,1		;AND LAST PAGE IN RANGE
	JRST	TYPO		;TYPE IT OUT

LAST:	CALL	CHKFIL		;DO WE HAVE AN INPUT FILE?
	 RET			;NO
	NOISE	(PAGE)
	CONFRM
	MOVE	PAGE1,SIZE	;GET THE LAST PAGE AS FIRST PAGE IN RANGE
	MOVE	PAGE2,SIZE	;AND LAST PAGE IN RANGE
	JRST	TYPO		;TYPE IT OUT

;HERE ON THE LIST COMMAND

LISTIT:	CALL	RANGE		;GET A RANGE
	 RET			;ILLEGAL RANGE
	CALL	CHKEXT		;ILLEGAL FILE?
	 RET			;BAG IT
	MOVSI	T1,(GJ%SHT)	;SHORT GTJFN
	HRROI	T2,[ASCIZ/LPT:/] ;THE LINE PRINTER
	GTJFN%			;GET A JFN
	 ERJMP	FAIL		;BOMBED
	MOVEM	T1,TJFN		;STORE JFN
	JRST	COPYIT		;SUCCESS, GO JOIN THE COPY CODE
;HERE ON THE COPY COMMAND

COPY:	CALL	CHKFIL		;DO WE HAVE A FILE?
	 RET			;NO...
	NOISE	(INTO FILE)	;NOISE
	CALL	OFILE		;PARSE OUTPUT FILE
	CALL	RANGE		;READ PAGE RANGE
	 JRST	NEWCOM		;ABORT
COPYIT:	CALL	TJOPEN		;OPEN IT
	CALL	COPPAG		;COPY PAGES
CLOSET:	HRRZ	T1,TJFN		;GET THE JFN OF THE TEMPORARY FILE
	CLOSF%			;CLOSE IT
	 ERJMP	WARN		;MAKE NOISE IF SOMETHING BOMBED
	RET			;RETURN TO COMMAND LEVEL
SUBTTL TERMINAL PAUSE COMMANDS

TEPAU:	SKIPA	T1,[.MOONX]	;TERMINAL PAUSE (ON) END-OF-PAGE
TENPAU:	 MOVEI	T1,.MOOFF	;TERMINAL NO PAUSE (ON) END-OF-PAGE
	PUSH	P,T1		;SAVE MODE OF CHOICE
	NOISE	(ON END OF PAGE)
	CONFRM
	POP	P,T3		;GET BACK MODE
	MOVEI	T1,.PRIOU	;USER'S TTY
	MOVEI	T2,.MOXOF	;XON/XOFF FLAG (THAT'S THE PAGE PAUSE FEATURE)
	MTOPR%			;PRETEND TTY IS A MAGTAPE (OH WELL!)
	RET
;HERE TO CHECK IF THE EXTENSION INDICATES A POSSIBLE BINARY FILE
;SKIPS IF THE FILE IS PROBABLY GOOD

CHKEXT:	SETZM	TMPBLK		;CLEAR THE FIRST WORD OF THE TEMP BUFFER
	HRROI	T1,TMPBLK	;DUMP THE STRING HERE
	HRRZ	T2,JFN		;THE FILE JFN
	MOVE	T3,[1B11]	;WANT ONLY THE FILE EXTENSION
	JFNS%			;WRITE THE STRING
	MOVSI	T2,-BADNUM	;NUMBER OF BAD EXTENSIONS
	MOVE	T1,TMPBLK	;OPTIMIZE LOOP
CHKGOD:	CAMN	T1,BADEXT(T2)	;SKIP IF IT DOESN'T MATCH OUR EXTENSION
	 JRST	CHKBAD		;LOOKS LIKE A BADDIE
	AOBJN	T2,CHKGOD	;LOOP UNTIL DONE
	RETSKP			;PROBABLY A GOOD FILE, SKIP RETURN

CHKBAD:	CALL	NEWLIN
	TMSG	<%Ignoring possible binary file - >
	MOVEI	T1,.PRIOU	;SEND TO THE TTY
	HRRZ	T2,JFN		;THE GUILTY JFN
	MOVE	T3,[1B2+1B5+1B8+1B11+1B14+1B35]	;FORMAT FLAGS
	JFNS%			;WRITE THE FILE SPEC
	OCRLF
	RET			;AND MAKE AN ERROR RETURN

;THIS IS THE LIST OF SUSPICIOUS FILE EXTENSIONS

BADEXT:	ASCII/REL/
	ASCII/EXE/
	ASCII/BIN/
	ASCII/FUN/
	ASCII/UNV/
	ASCII/SAV/
	ASCII/FAS/
BADNUM==.-BADEXT
SUBTTL SHOW COMMAND

SHOW:	CALL	CHKFIL		;SKIP IF WE HAVE A FILE
	 RET	
	NOISE	(INFORMATION ON CURRENT FILE)
	CONFRM
	CALL	GROUP		;FILE GROUP
	CALL	FILE		;CURRENT FILE
	CALL	LENGTH		;NUMBER OF DISK PAGES
	CALL	CURPAG		;CURRENT VALUE OF PAGE1
	CALLRET	STRING		;CURRENT SEARCH STRING AND RETURN


;HERE TO OUTPUT THE FILE GROUP

GROUP:	TMSG	<Group:  >
	HRROI	T1,JFNSTR
	PSOUT%			;SEND THE GROUP STRING
	OCRLF
	RET

;HERE TO OUTPUT THE CURRENT FILE

FILE:	TMSG	<File:   >
	MOVE	T1,FDBBLK+.FBCTL
	TLNN	T1,(FB%DEL)	;DELETED?
	 JRST	FILE1		;NO, SKIP THE MESSAGE
	TMSG	<%File is deleted - >
FILE1:	MOVEI	T1,.PRIOU
	HRRZ	T2,JFN
	SETZ	T3,0
	JFNS%			;WRITE OUT CURRENT FILE SPEC.
	OCRLF
	RET
;HERE TO SAY HOW LONG THE FILE IS

LENGTH:	TMSG	<Length: >
	MOVEI	T1,.PRIOU
	HRRZ	T2,SIZE
	MOVEI	T3,12
	NOUT%
	 ERCAL	WARN
	TMSG	< disk page(s)
>
	RET


;HERE TO PRINT THE CURRENT PAGE

CURPAG:	TMSG	<Page:   >
	MOVEI	T1,.PRIOU
	MOVE	T2,PAGE1
	MOVEI	T3,12
	NOUT%
	 ERCAL	WARN
	OCRLF
	RET


;HERE TO PRINT THE CURRENT SEARCH STRING

STRING:	TMSG	<String: ">
	HRROI	T1,STRBUF
	PSOUT%
	TMSG	<"
>
	RET
SUBTTL THE FIND COMMAND

;PARSE FIELDS

QUOTE:	FIELD	.CMQST,,REFIND,<string pattern to find>
REFIND:	FIELD	.CMCFM,,TEXT,<press RETURN to repeat last search>
TEXT:	FIELD	.CMTXT,,,,CM%SDH

FIND:	CALL	CHKFIL		;SKIP IF WE HAVE A FILE
	 RET			;RETURN TO COMMAND LOOP
	NOISE	(STRING)
	PARSE	QUOTE		;PARSE TEXT STRING WITHOUT QUOTES
	HRRZS	T3		;CLEAR FLAGS ON LEFT
	CAIN	T3,REFIND	;TYPED A CRLF?
	 JRST	FNDDEF		;YES, USE THE DEFAULT, IF ANY
	CONFRM			;WAIT FOR CONFIRMATION
	CALL INISTR		;INITIALIZE SEARCH STRING
FIND1:	SETZM OKINT		;DON'T INTERRUPT US
	SETZM NOSRCH		;ASSUME SEARCH NEED DID NOT COMPLETE
	SETZM DIDONE		;WE HAVE NOT PRINTED HEADER OR NUMBER
	SETZM LOPG		;LOW PAGE IN FILE
	SETZM FLASTP		;HAVE NOT SEEN END OF FILE
	SETZM SPAGE		;NO FIRST FIRST PAGE IN PAGE TABLE
	SETZM EPAGE
	MOVSI FPOS,-MAXFP	;POSITION AT FIRST ENTRY IN PAGE TABLE
FINDLP:	CALL FMAP		;MAP IN SOME PAGES
	MOVNI FILBYT,BPTBSZ+1
	MOVEI FILWRD,PAGE*1000	;ADDRESS OF FIRST WORD IN FILE
SLOOP:	CALL FSRCH		;DO A FAST SEARCH
	 JRST FNDMOR		;YES
	CAMN T1,EPAGE(FPOS)	;NO, FOUND SOMETHING.  IS IT NEW?
	 JRST SLOOP		;NOT NEW, LOOK FOR MORE
	SKIPN SPAGE(FPOS)	;ANY RANGE CURRENT?
	 JRST FSET		;NO RANGE START, VERY FIRST SET
	AOS EPAGE(FPOS)		;CHECK IF EXACTLY 1 GREATER THAN END OF RANGE
	CAMN T1,EPAGE(FPOS)
	 JRST SLOOP		;YES, WE DONE GOOD
	SOS EPAGE(FPOS)		;NO, MAKE PAGE CORRECT AGAIN
	AOBJN FPOS,FSET		;GET A NEW FPOS AND DO BOUNDS CHECK
	SUBI FPOS,1		;EXCEEDED BOUNDS, DUMP PAGE TABLE THEN ENTER
	PUSH P,T1
	CALL FNDOUT
	POP P,T1
	MOVSI FPOS,-MAXFP	;ENTER THE PAGE AT BEGINNING OF TABLE
FSET:	MOVEM T1,SPAGE(FPOS)	;START A NEW RANGE
	MOVEM T1,EPAGE(FPOS)
	JRST SLOOP		;AND KEEP UP THE GOOD WORK

FNDMOR:	SKIPE FLASTP		;DONE?
	 JRST FNDEND
	MOVEI T3,764-PAGE	;ONE-PAGE OVERLAP
	ADDM T3,LOPG
	JRST FINDLP
;HERE TO REPORT THE RESULTS

FNDEND:	CALL UNMAP		;UNMAP THE FILE
	SETOM OKINT		;REALLOW CTRL/O
	SETOM NOSRCH		;ASSUME NOT DIDONE AND SO NO NEED TO RE-SEARCH
FNDOUT:	SKIPN DIDONE		;IF ON, ALREADY PRINTED LEADER
	 JRST FNDND1
	SETZM NOSRCH		;AND THAT MEANS WE NEED TO RE-SEARCH
	JRST FNDOU2

FNDND1:	MOVEI T1,42		;SEND A DOUBLE QUOTE
	PBOUT%
	HRROI T1,STRBUF		;PRINT THE STRING
	PSOUT%
	SKIPE SPAGE
	 JRST FNDOU1
	TMSG <" does not occur in this file>
	RET

FNDOU1:	TMSG <" occurs on page(s) >
FNDOU2:	MOVNI T4,1(FPOS)	;MAKE LOOP POINTER INTO FILE RANGE
	MOVSI T4,(T4)
	MOVEI T1,.PRIOU
	MOVEI T2,","
	SKIPE DIDONE		;IF NOT DIDONE, SUPPRESS COMMA
FOUTLP:	 BOUT%
	MOVE T2,SPAGE(T4)	;GET FIRST PAGE
	MOVEI T3,12		;DECIMAL
	NOUT%
	 ERCAL WARN
	CAMN T2,EPAGE(T4)	;START AND END THE SAME?
	 JRST FOUNXT		;YES, GO ON TO NEXT
	MOVEI T2,":"		;NO, THEY ARE DIFFERENT
	BOUT%
	MOVE T2,EPAGE(T4)
	NOUT%
	 ERCAL WARN
FOUNXT:	MOVEI T2,","		;GET A COMMA FOR NEXT ARGUMENT
	AOBJN T4,FOUTLP		;AND LOOP FOR ANY MORE
	SETOM DIDONE		;FLAG THAT WE DID (AT LEAST) ONE
	RET

;HERE IF NO STRING WAS SPECIFIED

FNDDEF:	SKIPN	STRBUF		;SKIP IF WE HAVE A DEFAULT
	 JRST	FNDDFX		;NO DEFAULT SEARCH STRING
	SETZM DIDONE		;HAVEN'T PRINTED FIRST THING YET
	SKIPE	NOSRCH		;SKIP IF WE HAVE TO SEARCH
	 JRST	FNDND1		;ALREADY SEARCHED, JUST READ RESULTS
	JRST	FIND1		;NEW FILE, MUST RESEARCH

FNDDFX:	CALL	NEWLIN
	TMSG	<?No default search string>
	RET			;RETURN TO COMMAND LOOP

FMAP:	MOVE T3,SIZE		;CAN WE FIT ALL THAT'S LEFT INTO CORE?
	SUB T3,LOPG
	CAIG T3,765-PAGE	;COMPARE TO CORE SPACE
	 JRST FMAP1
	MOVEI T3,765-PAGE	;NO, SO USE ALL OF CORE
	MOVEI T2,765001		;THIS IS THE MAXWRD WE WANT TO USE
	JRST FMAP0

FMAP1:	SETOM FLASTP		;FITS, MARK AS LAST PAGE SEEN
	MOVE T1,LOPG		;FIGURE MAXWRD = MMAXWD - (LOPG - PAGE)*1000
	SUBI T1,PAGE
	IMULI T1,1000
	MOVE T2,MMAXWD
	SUB T2,T1
FMAP0:	MOVEM T2,MAXWRD		;SAVE MAXWRD
	SETZM (T2)
	MOVE T1,LOPG		;JFN,,FILE PAGE
	HRL T1,JFN
	MOVE T2,[.FHSLF,,PAGE]	;PROCESS,,PROCESS PAGE
	HRLI T3,(PM%CNT!PM%PLD!PM%RD!PM%CPY)  ;FLAGS,,NUMBER OF PAGES
	PMAP%
	 ERJMP FAIL
	RET

;HERE TO UNMAP THE FILE

UNMAP:	SETO	T1,-1		;UNMAPPING
	MOVE	T2,[.FHSLF,,PAGE] ;PROCESS,,PAGE
	MOVE T3,SIZE		;NUMBER OF PAGES MAPPED
	ADDI T3,1
	CAILE T3,766-PAGE	;WE MAPPED ALL THIS IN MAYBE?
	 MOVEI T3,766-PAGE
	HRLI T3,(PM%CNT)
	PMAP%
	 ERCAL	WARN
	RET
;HERE IS THE ACTUAL SEARCHING CODE

FSRCH:	ADD	FILBYT,PATLEN
FAST:	LDB	CHAR,BP(FILBYT)
	MOVE	CHAR,UPPER(CHAR)	;FORCE UPPER CASE
FAST1:	ADD	FILBYT,DELTA1(CHAR)
FAST2:	JUMPL	FILBYT,FAST
	CAILE	FILBYT,764
	 JRST	SLOW
	SUBI	FILBYT,BPTBSZ
	ADDI	FILWRD,BPTBSZ/5
	CAMG	FILWRD,MAXWRD
	 JRST	FAST
	RET			;RETURN +1 FOR FAILURE

SLOW:	SUBI	FILBYT,BIG
	MOVEI	T1,2
CHKWIN:	CAMLE	T1,PATLEN
	 JRST	WIN
	SUBI	FILBYT,1
	CAMGE	FILBYT,[-BPTBSZ]
	 JRST	BACKUP
SLOWLP:	LDB	CHAR,BP(FILBYT)
	MOVE	CHAR,UPPER(CHAR)	;FORCE UPPERCASE
	CAMN	CHAR,PAT-1(T1)
	AOJA	T1,CHKWIN
	MOVE	T2,DELTA1(CHAR)
	CAIN	T2,BIG
	 JRST	USED2
	CAML	T2,DELTA2-1(T1)
	 JRST	FAST1
USED2:	ADD	FILBYT,DELTA2-1(T1)
	JRST	FAST2

BACKUP:	ADDI	FILBYT,BPTBSZ
	SUBI	FILWRD,46
	JRST	SLOWLP

WIN:	MOVE T1,FILWRD		;CURRENT WORD IN FILE
	ADD T1,BP(FILBYT)
	HRRZS T1
	LSH T1,-^D9		;MAKE IT A PAGE NUMBER
	SUBI T1,PAGE-1		;SUBTRACT THE PAGE OFFSET
	ADD T1,LOPG		;MAKE IT A FILE PAGE
	RETSKP			;RETURN +2 FOR SUCCESS

;HERE TO MOVE STRING FROM ATOM BUFFER TO STRING BUFFER
;CHARACTERS ARE COUNTED AND UPPERCASE IS FORCED
;THE STRING IS ALSO STORED IN REVERSE ORDER IN PAT

INISTR:	MOVE T1,[POINT 7,ATMBUF]  ;COPY ATMBUF TO STRBUF
	MOVE T2,[POINT 7,STRBUF]  ;NOW COPY IT BACKWARDS
	MOVSI T3,-MXPATL	;SET COUNT TO 0
INIST1:	ILDB T4,T1		;GET A CHAR FROM ATOM BUFFER
	MOVE T4,UPPER(T4)	;FORCE UPPERCASE
	IDPB T4,T2		;TRANSFER IT
	CAIE T4,0		;STOP ON ZEROBYTE
	 AOBJN T3,INIST1	;COUNT UP ANOTHER ONE
	HRRZS T3		;NULL SEARCH FAILS
	JUMPE T3,R
	MOVEM T3,PATLEN		;SAVE COUNT
	MOVE T1,[POINT 7,STRBUF]  ;NOW COPY IT BACKWARDS
INIST2:	ILDB T2,T1		;GET A BYTE
	MOVEM T2,PAT-1(T3)	;STORE THE BYTE IN REVERSE ORDER
	SOJG T3,INIST2		;LOOP UNTIL DONE
;fallin	CALL IDLTA1
;fallin	CALLRET IDLTA2

;INITIALIZE DELTA1 TABLE

IDLTA1:	MOVE	T1,PATLEN
	MOVEM	T1,DELTA1
	MOVE	T1,[DELTA1,,DELTA1+1]
	BLT	T1,DELTA1+ALPHSZ-1 ;NOW EVERY ENTRY = PATLEN
	MOVE	T1,PATLEN
	SUBI	T1,1
SETDT1:	HRR	CHAR,PAT(T1)	;SCAN PAT LEFT TO RIGHT
	HRRM	T1,DELTA1(CHAR)	;PUT POSITION INTO TABLE
	SOJGE	T1,SETDT1
	HRR	CHAR,PAT	;TERMINAL CHARACTER
	MOVEI	T2,BIG		;THIS IS THE BIG HACK
	HRRM	T2,DELTA1(CHAR)	;THIS WILL CAUSE EXIT FROM FAST
;fallin	CALLRET IDLTA2
;INITIALIZE DELTA2 TABLE
; THIS IS THE 'RIGHTMOST PLAUSIBLE REOCCURENCE' TABLE.
; ONE ENTRY FOR EACH POSITION IN PAT.


;AC DEFINITIONS USED ONLY IN IDLTA2

STRBEG==2
STREND==3
PATEND==4
J==14
K==15


IDLTA2:	DMOVE	STRBEG,[ REPEAT 2,<1> ]
	MOVEI	PATEND,1
STD2LP:	CAMN	PATEND,PATLEN	;DONE?
 	 RET
	CAML	STREND,PATLEN	;FALL OFF THE LEFT END?
	AOJA	STREND,FINDPT
	MOVE	CHAR,PAT(STREND)
	CAMN	CHAR,PAT-1(PATEND)
	 JRST	 FINDPT
FINDBG:	ADDI	STRBEG,1
	MOVE	K,STRBEG	;K INDEX FOR POSSIBLY RPR
	MOVEI	J,1		;J IND FOR TERMINAL SUBPAT
MATCH:	CAMLE	J,PATEND	;NOTE: EVEN WHEN J=PATEND ALL WE KNOW
				; IS THAT WE HAVE AN 'OCCURENCE' WE
				; STILL HAVE TO CHECK FOR PLAUSIBILITY
	 JRST	FOUND
	CAMLE	K,PATLEN	;CASE OF RPR FALLING OFF THE LEFT END?
	 JRST	FOUND		;YES - NO PRECEDING CHARACTER THEN.
	MOVE	CHAR,PAT-1(J)	;NO - 
	CAME	CHAR,PAT-1(K)
	 JRST	FINDBG		;LOOK FOR TERMINAL CHAR
	ADDI	J,1		;FOUND TERM CH,DOES NEXT CH MATCHES TOO?
	AOJA	K,MATCH

FOUND:	MOVE	STREND,PATEND	;LENGTH OF SUBPAT 
	ADD	STREND,STRBEG	;POSITION OF RIGHT MOST CH OF RPR
	SUBI	STREND,1	;THIS IS K
FINDPT: MOVEM	STREND,DELTA2(PATEND)
	AOJA	PATEND,STD2LP
SUBTTL RANGE PARSER

;+1 IF ILLEGAL RANGE
;+2 SUCCESS

PAGEN1:	FIELD	.CMKEY,RNGTB1,NUMBER
PAGEN2:	FIELD	.CMKEY,RNGTB2,NUMBER
NUMBER:	FIELD	.CMNUM,^D10,JUSTCR

RNGTB1:	RNGLN1,,RNGLN1
	X (ALL,RNGALL)
	X (CURRENT,THIS1)
	X (FIRST,RNGFIR)
	X (LAST,RNGLAS)
	X (NEXT,RNGNXT)
	X (PREVIOUS,RNGPRV)
RNGLN1==.-RNGTB1-1

RNGTB2:	RNGLN2,,RNGLN2
	X (CURRENT,THIS1)
	X (FIRST,RNGFIR)
	X (LAST,RNGLAS)
	X (NEXT,RNGNXT)
	X (PREVIOUS,RNGPRV)
RNGLN2==.-RNGTB2-1

RANGE:	CALL	CHKFIL		;DO WE HAVE AN INPUT FILE?
	 RET			;NO FILE
	NOISE	(PAGE)
	PARSE	PAGEN1		;PARSE FIRST PAGE
	HRRZS	T3		;CLEAR FLAGS ON LEFT
	CAIN	T3,JUSTCR	;PARSED A CRLF?
	 RETSKP			;YES, USE CURRENT PAGE
	CAIN	T3,NUMBER	;PARSED A NUMBER?
	 JRST	RNG1		;YES
	HRRZ	T2,(T2)		;GET SUBROUTINE ADDRESS
	CALL	(T2)		;EVALUATE KEYWORD TO PAGE
RNG1:	PUSH	P,T2		;STORE PAGE NUMBER
	NOISE	(TO PAGE)
	PARSE	PAGEN2		;SECOND PAGE
	HRRZS	T3
	CAIN	T3,JUSTCR	;TYPED A CRLF?
	 JRST	RNGONE		;YES
	CAIN	T3,NUMBER
	 JRST	RNG2
	HRRZ	T2,(T2)		;EVALUATE KEYWORD TO PAGE
	CALL	(T2)
RNG2:	PUSH	P,T2		;STORE SECOND PAGE NUMBER
	CONFRM
	POP	P,T2		;GET BACK SECOND PAGE NUMBER
	POP	P,T1		;GET BACK FIRST PAGE NUMBER
RNGCHK:	JUMPLE	T1,RNGUND	;CANNOT BE ZERO OR LESS
	JUMPLE	T2,RNGUND
	CAMG	T1,SIZE		;CANNOT BE LARGER THAN FILE
	CAMLE	T2,SIZE
	 JRST	RNGOVR
	CAMLE	T1,T2		;PAGES CANNOT BE OUT OF ORDER
	 JRST	RNGX
	DMOVEM	T1,PAGE1	;CHECKS OUT, SAVE THEM
	RETSKP			;SKIP RETURN, ALL IS OKAY
;HERE TO HANDLE ILLEGAL RANGE SPEC

RNGUND:	CALL	NEWLIN
	TMSG	<?Page number specified is zero or less>
	RET

RNGOVR:	CALL	NEWLIN
	TMSG	<?Page number specified is beyond last page of file>
	RET

RNGX:	CALL	NEWLIN
	TMSG	<?Page numbers specified are out of order>
	RET

;HERE TO DECODE NAMED PAGES

THIS1:	MOVE	T2,PAGE1	;THIS VERY PAGE
	RET

RNGFIR:	MOVEI	T2,1		;FIRST PAGE
	RET

RNGLAS:	MOVE	T2,SIZE		;LAST PAGE
	RET

RNGNXT:	MOVE	T2,PAGE1	;NEXT PAGE
	ADDI	T2,1
	RET

RNGPRV:	MOVE	T2,PAGE1	;PREVIOUS PAGE
	SUBI	T2,1
	RET

;HERE IF "ALL" WAS TYPED

RNGALL:	CONFRM
	MOVEI	PAGE1,1		;THIS IS THE RANGE
	MOVE	PAGE2,SIZE
	POP	P,(P)		;DON'T USE RET ADDR
	RETSKP

;HERE IF ONLY ONE PAGE WAS SPECIFIED

RNGONE:	POP	P,T1		;GET THAT PAGE
	MOVE	T2,T1		;DUPLICATE IT
	JRST	RNGCHK
SUBTTL PAGE COPYING ROUTINE

;CALLED BY THE TYPE, COPY, AND LIST COMMANDS
;PAGE1, PAGE2 - RANGE OF PAGES TO BE COPIED

;RETURNS +1 IF JSYS FAILURE
;	 +2 ON SUCCESS

COPPAG:	SKIPG	SIZE		;JUST GO HOME IF ZERO (OR FEWER!) PAGES
	 RET
	CAMLE	PAGE1,PAGE2	;REDUNDANT CONSISTENCY CHECK
	 JRST	[DMOVE	PAGE1,[REPEAT 2,<1>]	;RESET PAGES TO 1
		 JRST	RNGX]	;RETURN ERROR
	MOVEI	T4,1000*5	;NUMBER OF CHARS TO SEND ON OTHER PAGES
COPLOP:	CAML	PAGE1,SIZE	;IS IT LAST PAGE?
	 MOVE	T4,BYTREM	;IF SO SEND ONLY THIS MANY BYTES
	MOVEI	T1,-1(PAGE1)	;ADJUST PAGE NUMBER FOR PMAP
	HRL	T1,JFN		;JFN OF INPUT FILE
	MOVE	T2,[.FHSLF,,PAGE]  ;MAP TO THIS PROCESS AND PAGE
	MOVSI	T3,(PM%PLD!PM%RD)  ;READ ACCESS BITS
	PMAP%			;MAP THE PAGE
	 ERJMP	WARN		;RETURN ON ERROR
	HRRZ	T1,TJFN		;OUTPUT JFN
	HRROI	T2,PAGE*1000	;BEGINNING OF THE PAGE
	MOVN	T3,T4		;SEND EXACTLY THIS MANY CHARS
	SOUT%
	 ERJMP	WARN		;ERROR PROBABLY IS EOF
	SETO	T1,-1		;WE ARE UNMAPPING
	MOVE	T2,[.FHSLF,,PAGE] ;PROCESS HANDLE AND PAGE
	MOVEI	T3,0		;NO PAGE COUNT
	PMAP%			;UNMAP THE PAGE
	 ERJMP	WARN		;RETURN ON ERROR
	CAME	PAGE1,PAGE2	;REACHED PAGE2?
	 AOJA	PAGE1,COPLOP	;NO, DO IT AGAIN
	RET			;DONE
SUBTTL FILE OPENING ROUTINE

;HERE TO OPEN AN INPUT FILE AND RECORD ITS LENGTH IN PAGES AND BYTES
;+1 ON FAILURE WITH ERROR MESSAGE PRINTED ON SCREEN
;+2 ON SUCCESS

OPEN: 	HRRZ	T1,JFN		;THE JFN
	MOVE	T2,[7B5+OF%RD!OF%PDT]  ;MODE FLAGS
	OPENF%			;OPEN THE FILE
	 ERCAL	OPX		;CAN'T
	HRRZ	T1,JFN		;THE JFN
	HRLZI	T2,.FBLEN	;LENGTH OF FDB AND OFFSET
	MOVEI	T3,FDBBLK	;ADDRESS OF FDB STORAGE BLOCK
	GTFDB%			;GET THE FILE DESCRIPTOR BLOCK
	HRRZ T1,FDBBLK+.FBBYV	;PAGE COUNT TO T1
	HRRZM T1,SIZE		;SAVE IT
	LDB T2,[POINT 6,FDBBLK+.FBBYV,11]  ;BYTE SIZE TO T2
	MOVE T3,FDBBLK+.FBSIZ	;BYTE COUNT TO T3
	CAIN T2,7		;7-BIT BYTES?
	 JRST BS7
	MOVEI T2,-1(T1)		;SECOND TO LAST PAGE
	IMULI T2,1000		;WORDS NOT INCLUDING LAST PAGE
	CAMGE T2,T3		;IS IT STILL BIGGER THAN WORD COUNT?
	 SKIPA T2,T3		;NO, USE WORD COUNT AS IS
	  ADDI T2,1000		;YES, COUNT TOO SMALL, USE 1000*SIZE
	MOVEM T2,MMAXWD		;STORE AS HIGHEST FILE WORD
	IDIVI T2,1000		;NUMBER OF WORDS ON LAST PAGE
	SKIPN T3		;ZERO?
	 SKIPA T3,[5000]	;YES, SHOULD BE 5000
	  IMULI T3,5		;NO, CONVERT WORDS TO BYTES
	MOVEM T3,BYTREM		;SAVE THIS AS NUMBER BYTES ON LAST PAGE
OP1:	SETZM	NOSRCH		;MUST SEARCH FILE FOR ANY STRING
	DMOVE	PAGE1,[ REPEAT 2,<1> ]  ;SET BOTH PAGES TO 1
	RETSKP

BS7:	MOVEI T2,-1(T1)		;SECOND TO LAST PAGE
	IMULI T2,5000		;BYTES NOT INCLUDING LAST PAGE
	CAMGE T2,T3		;IS IT STILL BIGGER THAN BYTE COUNT?
	 SKIPA T2,T3		;NO, USE BYTE COUNT AS IS
	  ADDI T2,5000		;YES, COUNT TOO SMALL, USE 5000*SIZE
	MOVE T3,T2		;BYTE COUNT
	IDIVI T3,5000		;NUMBER OF BYTES ON LAST PAGE
	SKIPN T4		;IF ZERO, SHOULD BE 5000
	 MOVEI T4,5000
	MOVEM T4,BYTREM		;SAVE THIS AS NUMBER BYTES ON LAST PAGE
	ADDI T2,4		;CONVERT BYTES TO WORDS, ROUNDED UP
	IDIVI T2,5
	MOVEM T2,MMAXWD		;STORE AS HIGHEST FILE WORD
	JRST OP1		;FINISH UP

OPX:	HRRZ T1,JFN		;GET THE JFN BACK
	TRO T2,OF%THW		;TRY FOR THAWED ACCESS THIS TIME
	OPENF%
	 JRST OPX1		;STILL NO GO
	RET			;GOT IT!
OPX1:	POP P,(P)		;DON'T NEED THIS RETURN ADDRESS ANY MORE
	CALL	NEWLIN
	TMSG	<%Could not open >
	MOVEI	T1,.PRIOU
	HRRZ	T2,JFN
	SETZ	T3,0
	JFNS%			;PRINT OUT FILE NAME
	TMSG	< - >
	CALL	ERRHAN
	OCRLF
	RET			;SINGLE RETURN TO CALLER
SUBTTL ASSORTED UTILITY ROUTINES

;HERE IS THE ERSTR PRINTING ROUTINE

ERRHAN:	MOVEI	T1,.PRIOU	;TO THE TTY
	HRLOI	T2,.FHSLF	;THIS PROCESS,,LAST ERROR
	SETZ	T3,0		;LONG MSGS 
	ERSTR%			;PRINT THE ERROR MSG
	 ERJMP	WHA		;CAN'T EVEN SAY WHAT HAPPENED.
	 ERJMP	FAIL
	RET

WHA:	CALL	NEWLIN		;GET TO CLEAR LINE
	TMSG	<%There was an undefined error within an error!  Watch out!>
	RET

;MAKE SURE ON A NEW LINE

NEWLIN:	MOVEI	T1,.PRIOU	;CURSOR POSITION AS VERT,,HORIZ
	RFPOS%
	TRNE	T2,-1		;OK ONLY IF ALL RH BITS 0
	 OCRLF			;FLUNKED, FORCE FRESH LINE
	RET

;HERE FOR A WARNING MESSAGE ON A JSYS ERROR

WARN:	CALL	NEWLIN		;WANT FRESH LINE
	TMSG	<%Warning - >
	CALL	ERRHAN
	OCRLF
	RET


;HERE TO RETURN TO COMMAND LOOP ON JSYS ERROR

FAIL:	CALL	NEWLIN		;WANT FRESH LINE
	TMSG	<%Failure - >
	CALL	ERRHAN
	JRST	NEWCOM


;HERE TO CHECK FOR JFN, SKIP RETURN IF ALL OKAY

CHKFIL:	SKIPE	JFN		;ZERO JFN MEANS NO FILE
	 RETSKP
	CALL	NEWLIN		;MAKE SURE OF A FRESH LINE
	TMSG	<?You must GET a file or file group first>
	RET			;ERROR RETURN
;HERE TO EXECUTE THE COMND JSYS
;THIS NONSENSE WOULD NOT BE NECESSARY IF DEC USED CM%FIX
;AT LEAST, NOT THE EXTRA JUNK -- THE SUBROUTINE DOES HAVE A RAISON D'ETRE

PARSER:	MOVEI T1,CSTATE		;ADDRESS OF COMMAND STATE BLOCK
	COMND%			;PARSE A FIELD
IFN CM%FIX, <
	RET			;RETURN RIGHT NOW
> ;IFN CM%FIX
IFE CM%FIX, <
	TXNN T1,CM%NOP		;COULD WE PARSE IT?
	 RET			;YES, RETURN TO CALLER
	CALL NEWLIN		;MAKE SURE OF A NEW LINE
	TMSG <?Unrecognized command - >
	CALL ERRHAN		;GIVE SYSTEM HELPFUL ERROR DIAGNOSIS
	LDB T1,[POINT 7,ATMBUF,6]  ;DON'T PRINT NULL ATOM
	JUMPE T1,PRSX1
	TMSG < - ">		;PRINT OFFENDING TEXT IF WE CAN
	HRROI T1,ATMBUF
	PSOUT%
	MOVEI T1,.CHDQT
	PBOUT%
PRSX1:	TMSG <
(Hint:  For help type BACKSPACE and a question mark.)>
	JRST NEWCOM		;RETURN FOR A REPARSE
> ;IFE CM%FIX

;HERE TO WRITE A JFN STRING INTO JFNSTR

MAKSTR:	HRROI	T1,JFNSTR	;DESTINATION OF STRING
	MOVE	T2,JFN		;THE JFN
	MOVE	T3,[1B2+1B5+1B8+1B11+1B14+1B35]	;FORMAT FLAGS
	JFNS%			;WRITE THE STRING
	MOVE	T1,[POINT 7,JFNSTR]
	MOVE	T2,[POINT 7,IDEV]
	MOVEM	T2,IJFNBK+.GJDEV
	MOVEI	T3,":"
	CALL	CPYFLD
	IBP	T1
	MOVE	T2,[POINT 7,IDIR]
	MOVEM	T2,IJFNBK+.GJDIR
	MOVEI	T3,">"
	CALL	CPYFLD
	MOVE	T2,[POINT 7,INAM]
	MOVEI	T3,"."
	CALL	CPYFLD
	MOVE	T2,[POINT 7,IEXT]
	CALL	CPYFLD
	RET

CPYFLD:	ILDB	0,T1
	CAMN	0,T3
	 JRST	CPYFL1
	IDPB	0,T2
	JRST	CPYFLD
CPYFL1:	SETZ	0,
	IDPB	0,T2
	RET

;HERE TO PARSE AN OUTPUT FILE NAME USING COMND JSYS

IFILE:	SKIPA	T1,[IJFNBK]	;TO PARSE INPUT FILE
OFILE:	 MOVEI	T1,OJFNBK	;TO PARSE OUTPUT FILE
	MOVEM	T1,CSTATE+.CMGJB
	PARSE	FILSPC		;GET JFN ON FILE
	MOVEM	T2,TJFN		;SAVE IT
	MOVEI	T1,UNJFN	;CHANGE REPARSE ADDRESS
	MOVEM	T1,CSTATE
	RET

;HERE TO OPEN THE TEMPORARY JFN

TJOPEN:	MOVE	T1,TJFN		;GET OUTPUT FILE JFN
	MOVE	T2,[7B5+OF%WR]	;SET ACCESS MODE
	OPENF%			;OPEN THE FILE
	 ERJMP	TJOPX		;BOMBED, SKIP TO ERROR ROUTINE
	RET			;SUCCESS RETURN

TJOPX:	CALL	WARN		;SAY WHAT WENT WRONG
	JRST	NEWCOM		;GO REINITIALIZE

UNJFN:	MOVE	T1,TJFN		;RELEASE THE TEMPORARY JFN
	RLJFN%
	 NOP			;IGNORE ERRORS
	SETZM	TJFN		;NO TEMP JFN TO RELEASE
	MOVEI	T1,RPARSE	;SET CORRECT REPARSE ADDRESS
	MOVEM	T1,CSTATE
	JRST	RPARSE

;HERE TO CLOSE THE JFN

CLOSE:	HRRZ	T1,JFN		;HERE WE HAVE IT
	CLOSF%			;BYE BYE
	 NOP			;WHAT COULD GO WRONG?
	RET
SUBTTL INTERRUPT HANDLING

;HERE TO SET UP OUR INTERRUPT SYSTEM

SETINT:	MOVEI	T1,.FHSLF	;CURRENT PROCESS
	MOVE	T2,[LEVTAB,,CHNTAB] ;INTERRUPT TABLES
	SIR%			;SET INTERRUPTS
	EIR%			;ENABLE INTERRUPTS
	MOVE	T2,[1B0+1B16]	;ACTIVATE CHANNELS 0 AND 16
	AIC%
	MOVE	T1,[.TICCO,,0]	;CONTROL-O ASSIGNED TO CHANNEL 0
	ATI%
	RET


;HERE IS THE ROUTINE TO FAKE A CONTROL-O

SHUTOF:	AOSE	OKINT		;SKIP IF ALLOWING INTERRUPTS
	 DEBRK%
	MOVEI	T1,.PRIOU	;OUR OUTPUT FILE
	CFOBF%			;ZAP IT
	TMSG	<^O...
>
SHUT:	SETO	T1,-1
	MOVE	T2,[.FHSLF,,PAGE]
	MOVEI T3,0
	PMAP%			;UNMAP THE SPECIAL PAGE
	 ERCAL	WARN
	MOVEI	T1,NEWCOM	;DEBREAK TO COMMAND LOOP
	MOVEM	T1,PCSAVE
	SETOM	OKINT		;ALLOW INTERRUPTS
	DEBRK%			;RETURN FROM INTERRUPT


;HERE ON ILLEGAL MEMORY READ

MEMX:	CALL	NEWLIN		;MAKE SURE ON NEW LINE
	MOVEI	T1,"%"
	PBOUT%
	CALL	ERRHAN		;PRINT OUT ERROR MESSAGE
	TMSG	< - probably pages after end of file
>
	JRST	SHUT		;GO UNMAP AND DEBREAK TO COMMAND LOOP


;INTERRUPT TABLES

CHNTAB:	1,,SHUTOF		;CHANNEL 0 FOR CTRL-O
	BLOCK 17
	1,,MEMX			;CHANNEL 16 IS ILLEGAL MEMORY READ
	BLOCK 23
SUBTTL STORAGE (PURE AND IMPURE)

;STORE THE LITERALS HERE, JUST BEFORE THE IMPURE STORAGE
;DON'T SEND THEM TO THE CREF LISTING

XLIST
LIT
LIST

;UPPERCASING TABLE

UPPER:	XXZ==0
REPEAT <"a">,<XXZ
	XXZ==XXZ+1>		;UPPERCASE ALREADY OR IRRELEVANT, NO CHANGE
REPEAT <"z"-"a"+1>,<XXZ-40
	XXZ==XXZ+1>		;LOWERCASE, RAISE
REPEAT <177-"z">,<XXZ
	XXZ==XXZ+1>		;IRRELEVANT, NO CHANGE


;LEVEL TABLE FOR THE INTERRUPT SYSTEM

LEVTAB:	PCSAVE
	BLOCK 2


;THE COMMAND STATE BLOCK

CSTATE:	0,,RPARSE		;THE REPARSE ADDRESS
	.PRIIN,,.PRIOU		;I/O JFNS
	-1,,[ASCIZ/PERUSE> /]	;CONTROL-R BUFFER 
	-1,,COMBUF		;CAN'T EDIT PAST THIS POINT
	-1,,COMBUF		;POINTER TO NEXT FIELD
	BUFCHR			;REMAINING SPACE IN COMMAND BUFFER
	0			;REMAINING UNPARSED CHARACTERS
	-1,,ATMBUF		;LAST FIELD PARSED
	BUFCHR			;SIZE OF ATOM BUFFER
	IJFNBK			;ADDRESS OF JFN BLOCK



;THE ARGUMENT BLOCK FOR THE LONG FORM GTJFN

IJFNBK:	INFLG!GJ%XTN+.GJALL	;0 - .GJGEN
	.PRIIN,,.PRIOU		;1 - .GJSRC
	0			;2 - .GJDEV
	0			;3 - .GJDIR
	-1,,INAM		;4 - .GJNAM
	-1,,IEXT		;5 - .GJEXT
	0			;6 - .GJPRO
	0			;7 - .GJACT
	0			;10 - .GJJFN
	G1%IIN			;11 - .GJF2
	BLOCK IJFNBK+.GJATR+1-.

OJFNBK:	GJ%FOU!GJ%XTN+.GJDEF
	BLOCK OJFNBK+.GJATR+1-.
;VARIABLES

JFN:	BLOCK 1			;CURRENT JFN
TJFN:	BLOCK 1			;JFN OF COPY FILE
IDEV:	BLOCK 8
IDIR:	BLOCK 8
INAM:	ASCIZ "*"
	BLOCK INAM+8-.
IEXT:	ASCIZ "*"
	BLOCK IEXT+8-.
PCSAVE:	BLOCK 1			;SAVE PC HERE ON CTRL/O
OKINT:	BLOCK 1			;^O INTERRUPT-PERMITTED SEMAPHORE
SIZE:	BLOCK 1			;NUMBER OF PAGES IN CURRENT FILE
LOPG:	BLOCK 1			;LOW PAGE NUMBER USED BY FIND
NOSRCH:	BLOCK 1			;FLAG USED BY FIND COMMAND
PATLEN:	BLOCK 1			;NUMBER OF CHARACTERS IN SEARCH STRING
MMAXWD:	BLOCK 1			;ADDRESS OF LAST WORD IN THE FILE
MAXWRD:	BLOCK 1			;ADDRESS OF LAST WORD TO SEARCH
FLASTP:	BLOCK 1			;FLAG TO SIGNAL EOF SEARCHED
DIDONE:	BLOCK 1			;FLAG USED TO DETERMINE WHETHER COMMA NEEDED

;LARGE BUFFERS

STACK:	BLOCK STKLEN		;SUBROUTINE STACK
COMBUF:	BLOCK BUFLEN		;COMMAND BUFFER
ATMBUF:	BLOCK BUFLEN		;ATOM BUFFER
STRBUF:	BLOCK BUFLEN		;STRING BUFFER
JFNSTR: BLOCK BUFLEN		;STRING ASSOCIATED WITH FIRST JFN
TMPBLK:	BLOCK BUFLEN		;TEMPORARY STORAGE
SPAGE:	BLOCK MAXFP		;STARTING PAGES FOR FIND
EPAGE:	BLOCK MAXFP		;ENDING PAGES FOR FIND
PATBUF:	BLOCK PTBUFL		;PATTERN BUFFER
BP00:
I==0
REPEAT 46,<
	X==0
	REPEAT 5,<
		POINT 7,I(FILWRD),7*X+6 
	X==X+1>
I==I+1>
BP==.
DELTA1:	BLOCK ALPHSZ		;ONE ENTRY FOR EACH ALPHABET
PAT:	BLOCK MXPATL		;ARRAY FOR UNPACKING OUR PATTERN TO BE MATCHED
DELTA2:	BLOCK MXPATL
FDBBLK:	BLOCK .FBLEN		;STORE CURRENT FILE'S FDB HERE
BYTREM:	BLOCK 1			;NUMBER OF BYTES IN FILE'S LAST PAGE

	END	START