Google
 

Trailing-Edge - PDP-10 Archives - cuspjul86upd_bb-jf24a-bb - 10,7/fscopy/fscopy.mac
There are 3 other files named fscopy.mac in the archive. Click here to see a list.
	TITLE	FSCOPY - A PROGRAM TO COPY FIL;E
	SUBTTL	BILL MEIER  8-SEP-77

	SEARCH	JOBDAT,MACTEN,SCNMAC,UUOSYM

	FSYVER==1
	FSYMIN==0
	FSYWHO==0
	FSYEDT==26

	LOC	.JBVER
	VRSN.	(FSY)

	TWOSEG
	RELOC	400000

	.TEXT	",REL:SCAN/SEARCH, REL:WILD, REL:HELPER"

;AC'S
	F=0			;FLAGS
	T4=<1+<T3=1+<T2=1+<T1=1>>>> ;FOUR CONSECUTIVE TEMPORARY ACS
	P4=<1+<P3=1+<P2=1+<P1=5>>>> ;FOUR CONSECUTIVE PRESERVED ACS
	N=P3			;SCANNING WORD RESULT
	C=P4			;SCANNING CHARACTER RESULT
	MP=11
	DP=12
	L=13
	P=17			;PUSH DOWN LIST POINTER

;SOFTWARE CHANNELS
	OC==1			;OUTPUT CHANNEL
	IC==2			;INPUT CHANNEL

;ASSEMBLY PARAMETERS
	ND	LN$PDL,^D100
	ND	LN$LEN,.RBAC8+1	;INCLUDE ACCOUNT STRING
	ND	LN$DSK,.DCSMT+1

;FLAGS
	FL.PSI==1B0		;PSISER BROKEN
	FL.EXI==1B1		;EXIT WHEN DONE
	FL.CC== 1B2		;^C CONTINUE TYPED
	FR.STO==1B18		;KSCOPY IS STOPPED
	FR.ABO==1B19		;ABORT COPING THIS FILE
	FR.FE=  1B20		;COPYING FE.SYS FILE
	FR.SWT==1B21		;SOME /BEFORE/SINCE SWITCHES (FOR WHAT)

;MONITOR PARAMETERS (FROM COMMOD.MAC)
	ND	FBOOTB,4	;FIRST BLOCK FOR BOOTB
	ND	NBOOTB,4	;NUMBER OF BOOT BLOCKS

	ND	LBNHM1,1	;LOGICAL BLOCK NUMBER FIRST HOME BLOCK
	ND	LBNHM2,12	;LOGICAL BLOCK NUMBER SECOND HOME BLOCK

	ND	HOMNAM,0	;LOCATION OF SIXBIT/HOM/
	ND	HOMFEA,61	;LOCATION OF FE.SYS
	  ND	HM$VAL,1B2	;BIT THAT SAYS ITS VALID
	ND	HOMFES,62	;SIZE OF FE.SYS
	ND	HOMCOD,176	;UNLIKELY CODE OFFSET
	ND	CODHOM,707070	;THAT UNLIKELY CODE VALUE
	ND	HOMSLF,177	;SELF BLOCK NUMBER

	ND	.RBSLF,177	;SELF BLOCK NUMBER OF RIB
	ND	NM$RIB,2	;NUMBER OF RIBS (PRIME+SPARE)

	ND	JACCT,1B17	;BIT IN JBTSTS (.GTSTS) FOR JACCT
	SUBTTL	EDIT HISTORY

;8-Sep-77
;
;1	FSCOPY -- The fast disk-2-disk copy utility
;2	Improve command scanning a little
;3	Fix ?ILL MEM REF when copying 0 block SFD's
;4	Allow FSCOPY to copy boot blocks (0,4-7) and FE.SYS
;5	Implement /SINCE/BEFORE/ASINCE/ABEFORE/MSINCE/MBEFORE
;6	Do Checkpointing for better restarting
;7	Add SUPERSEDE (ALWAYS, OLDER, NEVER)
;10	Fix ?Quota exceeded message
;6-Sep-78
;11	Dont hang in TI after ^C^C  CONTinue sequence
;12	Add EXIT when done in interactive mode
;13	Dont abort transfer of UFD if input read errors
;14	Add /EXCLUDE [P,PN] to exclude copying of PPN
;15	Give %No files/%No UFDs match message if thats the case
;16	Default [*,*] if [1,2] or [,] if not. Also handle [,123] etc
;17	Handle NUL: better
;
;20-25	Mysteriously lost
;
;26	Convert to use standard SCAN and WILD.
;
;END EDIT HISTORY
DEFINE	$FATAL	(PFX,TXT,MOR,CON<.FMSGE##>),<ERR	(0,PFX,<TXT>,MOR,CON)>
DEFINE	$WARN	(PFX,TXT,MOR,CON<.+1>),<ERR	(1,PFX,<TXT>,MOR,CON)>
DEFINE	$INFO	(PFX,TXT,MOR,CON<.+1>),<ERR	(2,PFX,<TXT>,MOR,CON)>

DEFINE	ERR	(TYP,PFX,TXT,MOR,CON),<
E$$'PFX:PUSHJ	P,[XLIST
		   PUSHJ P,ERROR
		   XWD	''PFX'',[ASCIZ |TXT|]
		   XWD	TYP,CON
		   XWD	MOR,0
		   LIST]
>


DEFINE	WRD2BK	(AC,E),<
IFNB <E>,<MOVE	AC,E>
	ADDI	AC,177
	LSH	AC,-7
>
	SUBTTL	SCAN	DEFINITIONS

	DEFINE	SWTCHS,<
	SN	ALLOCATE,S.ALLOC,FS.NFS
	SP	BUFFERSIZE,S.BUFF,.BLOKW##,BUF,FS.NFS!FS.LRG
	SN	BOOTS,S.BOOT,FS.NFS
	SP	CHECKPOINT,S.CHECK,.SWDEC##,CHK,FS.NFS
	SP	COPY,,$COPY,,FS.NFS!FS.VRQ!FS.HEL
	SS	DIRECTORY,S.LEVEL,%DIRECTORY,FS.NFS
	SP	DSKPRI,S.DSKP,.SWDEC##,DSK,FS.NFS
	SP	EXCLUDE,S.EXCLUDE,.SWFIL##,EXCL,FS.NFS!FS.VRQ
	SN	FESYS,S.FESYS,FS.NFS
	SS	FILES,S.LEVEL,%FILES,FS.NFS
	SP	HPQ,S.HPQ,.SWDEC,HPQ,FS.NFS
	SP	INITIAL,S.INIT,.SWFIL##,INIT,FS.NFS!FS.VRQ
	SP	MBEFORE,S.MBFR,.SWDTP##,,FS.NFS
	SP	MSINCE,S.MSNC,.SWDTP##,,FS.NFS
	SP	RETRY,S.RETRY,.SWDEC##,RET,FS.NFS!FS.LRG
	SS	SILENCE,S.LEVEL,%SILENCE,FS.NFS
	SN	SINGLE,S.SINGLE,FS.NFS
	SP	SORT,,$SORT,,FS.NFS!FS.HEL
	SL	SUPERSEDE,S.SUPER,SUP,,FS.VRQ
	SP	WHAT,,$WHAT,,FS.NFS
>

	KEYS	(SRT,<FILES,DIRECTORY>)
	KEYS	(SRTK,<NONE,NAME,EXTENSION,LOCATION>)
	KEYS	(SUP,<ALWAYS,OLDER,NEVER>)

	%SILENCE==0
	%DIRECTORY==1
	%FILES==2

	DM	BUF,^D1000*200,^D100*200,^D200*200
	DM	INIT,.FXLEN,.FXLEN,.FXLEN
	DM	EXCL,.FXLEN,.FXLEN,.FXLEN
	DM	HPQ,17,0,1
	DM	DSK,3,0,1
	DM	RET,.INFIN,.INFIN,5
	DM	CHK,^D60,^D10,^D5

IBLK:	IOWD	1,[SIXBIT/FSCOPY/]
	OFFSET,,'FSY'
	EXP	.TOCHR##
	LN$IBLK==.-IBLK

OBLK:!
VBLK:	IOWD	FSY.L,FSY.N
	XWD	FSY.D,FSY.M
	EXP	FSY.P
	EXP	-1
	LN$OBLK==.-OBLK
	LN$VBLK==.-VBLK

	DOSCAN	(FSY.)
	SUBTTL	INITIALIZE

FSCOPY:	TDZA	T1,T1			;FLAG NORMAL ENTRY
	  MOVEI	T1,1			;FLAG CCL ENTRY
	MOVEM	T1,OFFSET		;SAVE STARTING OFFSET
	RESET				;RESET THE WORLD
	MOVEI	F,0			;CLEAR FLAGS
	MOVE	T1,[S.ZER,,S.ZER+1]	;SET UP BLT
	SETZM	S.ZER			;CLEAR FIRST WORD
	BLT	T1,S.ZERM		;CLEAR CORE
	MOVE	T1,[S.ONE,,S.ONE+1]	;SET UP BLT
	SETO	S.ONE			;INIT FIRST WORD
	BLT	T1,S.ONEM		;RESET SWITCHES
	MOVE	P,[IOWD LN$PDL,PDL]	;SETUP A STACK
	PUSHJ	P,.TOINI##		;INIT BUFFERED OUTSTR
	MOVE	T1,[LN$IBLK,,IBLK]	;POINT TO .ISCAN BLOCK
	PUSHJ	P,.ISCAN##		;INITIALIZE COMMAND SCANNER
	MOVE	T1,[LN$OBLK,,OBLK]	;POINT TO .OSCAN BLOCK
	PUSHJ	P,.OSCAN##		;READ SWITCH.INI
	MOVE	T1,.JBFF		;GET INITAIL .JBFF
	MOVEM	T1,SAVFF		;SAVE AWAY FOR LATER
	PUSHJ	P,I$INIT		;INIT VARIABLES
	PUSHJ	P,SWTDEF		;DEFAULT THE SWITCHES

MAINLP:	MOVE	P,[IOWD LN$PDL,PDL]	;FIX STACK
	MOVE	T1,[LN$VBLK,,VBLK]	;POINT TO .VSCAN BLOCK
	PUSHJ	P,.VSCAN##		;DO ALL THE WORK
	PUSHJ	P,.MONRT##		;RETURN TO MONITOR
	JRST	MAINLP			;RESTART IN CASE CONTINUE
	SUBTTL	SWTDEF -- DEFAULT THE SWITCHES

SWTDEF:	MOVEI	T1,%DIRECTORY		;ASSUME LEVEL=DIRECTORY
	SKIPGE	S.LEVEL			;SEE IF SPECIFIED
	  MOVEM	T1,S.LEVEL		;NO--STORE DEFAULT
	MOVEI	T1,1			;DEFAULT /ALLOCATE
	SKIPGE	S.ALLOCATE		;SEE IF GIVEN
	  MOVEM	T1,S.ALLOCATE		;NO--STORE DEFAULT
	MOVEI	T1,SRTKNAME		;/SORT:DIRECTORY:NAME
	SKIPG	S.DSRT			;SEE IF GIVEN
	  MOVEM	T1,S.DSRT		;NO--STORE
	MOVEI	T1,SRTKNONE		;/SORT:FILES:NONE
	SKIPG	S.FSRT			;SEE IF GIVEN
	  MOVEM	T1,S.FSRT		;NO--STORE DEFAULT
	MOVX	T1,AD.RET		;GET ABSENT DEFAULT
	SKIPGE	S.RETRY			;SEE IF GIVEN
	  MOVEM	T1,S.RETRY		;NO--STORE DEFAULT
	MOVX	T1,AD.CHK		;GET ABSENT DEFAULT
	SKIPG	S.CHECK			;SEE IF GIVEN
	  MOVEM	T1,S.CHECK		;NO--STORE DEFAULT
	MOVX	T1,SUPALWAYS		;GET DEFAULT
	SKIPG	S.SUPER			;SEE IF GIVEN
	  MOVEM	T1,S.SUPER		;NO--STORE DEFAULT
	POPJ	P,			;AND RETURN
	SUBTTL	CPYDEF -- FILL IN DEFAULTS AFTER COPY

CPYDEF:	MOVEI	T1,S.INITIAL		;GET /INITIAL SPEC
	PUSHJ	P,DEFPPN		;FILL IN DEFAULTS
	MOVEI	T1,S.EXCLUDE		;GET /EXCLUDE SPEC
	PUSHJ	P,DEFPPN		;FILL IN DEFAULTS
	MOVX	T1,FX.DIR		;GET DIRECTORY BIT
	TDNN	T1,I.SPEC+.FXMOD	;SEE IF GIVEN ON INPUT
	  PUSHJ	P,FIXPPN		;NO--DEFAULT IT
	MOVEI	T1,I.SPEC		;GET INPUT SCAN BLOCK
	PUSHJ	P,DEFPPN		;DEFAULT IT

;Default /BOOTS/FESYS if [1,2], full wildcard, and no /INITIAL

	SKIPE	S.INIT+.FXDIR		;/INITIAL GIVEN?
	  JRST	CPYD.1			;YES
	MOVE	T1,.MYPPN##		;GET ME
	CAMN	T1,OPRPPN		;[1,2]?
	SKIPE	I.SPEC+.FXDIM		;YES--FULL WILDCARD?
CPYD.1:	  TDZA	T1,T1			;NO--CLEAR T1
	MOVEI	T1,1			;YES--SET /YES
	SKIPGE	S.BOOTS			;/BOOTS GIVEN?
	  MOVEM	T1,S.BOOTS		;NO--DEFAULT IT
	SKIPGE	S.FESYS			;/FESYS GIVEN?
	  MOVEM	T1,S.FESYS		;NO--DEFAULT IT
	POPJ	P,			;AND RETURN

;DEFPPN fills in the users PPN for constructions like [,],[123,],[,123]

DEFPPN:	MOVX	T2,FX.DIR		;GET DIRECTORY BIT
	TDNN	T2,.FXMOD(T1)		;SEE IF GIVEN
	  POPJ	P,			;NO--RETURN
	MOVE	T2,.FXDIR(T1)		;GET PPN
	TLNN	T2,-1			;SEE IF PROJ
	  HRROS	.FXDIM(T1)		;NO--CLEAR WILDCARDS
	TLNN	T2,-1			;CHECK AGAIN
	  HLL	T2,.MYPPN##		;NO--USE MINE
	TRNN	T2,-1			;SEE IF PROG
	  HLLOS	.FXDIM(T1)		;NO--CLEAR WILDCARDS
	TRNN	T2,-1			;CHECK AGAIN
	  HRR	T2,.MYPPN##		;NO--USE MINE
	MOVEM	T2,.FXDIR(T1)		;STORE PPN
	POPJ	P,			;AND RETURN

;FIXPPN defaults [*,*] if [1,2] and [,] if not

FIXPPN:	MOVE	T1,.MYPPN##		;GET ME
	CAME	T1,OPRPPN		;GOD?
	  JRST	FIXP.1			;NO
	SETOM	I.SPEC+.FXDIR		;YES--FORCE WILD
	JRST	FIXP.2			;AND SET DIR BIT
FIXP.1:	MOVEM	T1,I.SPEC+.FXDIR	;NO--SET MY PPN
	SETOM	I.SPEC+.FXDIM		;AND CLEAR WILDS
FIXP.2:	MOVX	T1,FX.DIR		;GET DIRECTORY BIT
	IORM	T1,I.SPEC+.FXMOD	;SET
	POPJ	P,			;AND RETURN
	SUBTTL	COPY -- COPY THE FILE STRUCTURE

	[ASCIZ/OUTPUT=INPUT/]
$COPY:	TRZ	F,-1			;CLEAR LOCAL FLAGS
	SETZM	S.ZER1			;ZERO PER COMMAND VARIABLES
	MOVE	T1,[S.ZER1,,S.ZER1+1]	;SETUP FOR BLT
	BLT	T1,S.ZERM		;CLEAR THEM OUT
	PUSHJ	P,CPYSCN		;SCAN THE COPY SPEC
	PUSHJ	P,CPYDEF		;DEFAULT SWITCHS AFTER COPY
	PUSHJ	P,CPYOPN		;OPEN CHANNELS
	PUSHJ	P,SETHPQ		;SET HPQ IF GIVEN
	PUSHJ	P,SETDSK		;SET DSKPRIORITY IF GIVEN
	PUSHJ	P,PIINIT		;INITIALIZE PSISER
	PUSHJ	P,SETCHK		;SETUP FOR CHECKPOINTING
	PUSHJ	P,FILDAE		;SEE IF FILDAE RUNNING
	PUSHJ	P,CBOOTS		;COPY BOOTS BLOCKS
	PUSHJ	P,CFESYS		;COPY FE.SYS
	PUSHJ	P,CPYMFD		;PROCESS THE MFD
	PUSHJ	P,CPYREL		;RELEASE THE CHANNELS
	PUSHJ	P,TOTALS		;GIVE TOTALS
	PUSHJ	P,CHKFIL		;CHECK TO SEE IF FILES FOUND
	PUSHJ	P,PIOFF			;TURN OFF PSISER
	PUSHJ	P,RSTPTH		;RESTORE PATH
	TLNE	F,(FL.EXIT)		;EXIT WHEN DONE?
	  PUSHJ	P,.MONRT##		;YES
	PJRST	.POPJ1##		;AND RETURN W/O STORE

	SUBTTL	CPYSCN  -- SCAN THE COPY SWITCH

CPYSCN:	PUSHJ	P,.CLRFL##		;CLEAR FILE AREA
	PUSHJ	P,.FILIN##		;READ A FILE SPEC
	CAIE	C,"="			;SEE IF EQUALS
	  JRST E$$CRO			;NO--COPY REQUIRES OUTPUT SPEC
	MOVEI	T1,O.SPEC		;POINT TO OUTPUT SPEC
	MOVEI	T2,.FXLEN		;INDICATE LENGTH
	PUSHJ	P,.GTSPC##		;COPY FROM SCAN
	PUSHJ	P,.FILIN##		;READ ANOTHER
	JUMPG	C,E.INCL##		;SHOULD BE <EOL> NOW
	MOVEI	T1,I.SPEC		;POINT TO INPUT SPEC
	MOVEI	T2,.FXLEN		;INDICATE LENGTH
	PUSHJ	P,.GTSPC##		;COPY FROM SCAN
	POPJ	P,

	$FATAL	(CRO,<COPY requires output specification>)
SETHPQ:	SKIPGE	T1,S.HPQ		;SEE IF HPQ GIVEN
	  POPJ	P,			;NO--RETURN
	HPQ	T1,			;TRY TO SET
	  SKIPA				;FAILED
	POPJ	P,			;LOOKS GOOD

	$WARN	(CSH,<Cant set HPQ >,E.CSH,.POPJ##)
E.CSH:	MOVE	T1,S.HPQ
	PJRST	.TDECW##


SETDSK:	SKIPGE	T1,S.DSKP		;SEE IF DSKPRI GIVEN
	  POPJ	P,			;NO--RETURN
	HRLI	T1,-1			;FOR ALL OPEN CHANNELS
	MOVE	T2,[.DUPRI,,T1]		;FUNCTION,,ADDR
	DISK.	T2,			;TRY
	  SKIPA				;FAILED
	POPJ	P,			;LOOKS GOOD

	$WARN	(CSP,<Cant set DSKPRI >,E.CSP,.POPJ##)
E.CSP:	MOVE	T1,S.DSKP
	PJRST	.TDECW##
	SUBTTL	$SORT -- SCAN THE SORT SWITCH

	[ASCIZ/SORT <TYPE> <KEY>/]
$SORT:	JUMPLE	C,SORT2			;DEFAULT IF NO KEYWORDS
	PUSHJ	P,.SIXSW##		;READ A SIXBIT READ
	MOVE	T1,[IOWD SRT.L,SRT.T]	;POINT TO TABLE
	PUSHJ	P,.NAME##		;LOOK LOOK
	  JRST	E$$USK			;UNKNOWN
	SUBI	T1,SRT.T-1		;REMOVE OFFSET
	TLZ	T1,-1			;KEEP RH ONLY
	PUSH	P,T1			;SAVE
	MOVEI	T2,SRTKNAME		;DEFAULT IS /SORT::NAME
	JUMPLE	C,SORT1			;YES--USE DEFAULT
	PUSHJ	P,.SIXSW##		;READ NEXT KEYWORD
	MOVE	T1,[IOWD SRTK.L,SRTK.T]	;POINT TO TABLE
	PUSHJ	P,.NAME##		;LOOK IN TABLE
	  JRST	E$$USK			;UNKNOWN
	SUBI	T1,SRTK.T-1		;REMOVE OFFSET
	MOVEI	T2,(T1)			;MOVE RH INTO T2
SORT1:	POP	P,T1
	CAIN	T1,SRTDIRECTORY-1
	  MOVEM	T2,S.DSRT
	CAIN	T1,SRTFILES-1
	  MOVEM	T2,S.FSRT
	JRST	.POPJ1##

SORT2:	MOVEI	T1,SRTKNAME		;DEFAULT /SORT::NAME
	MOVEM	T1,S.DSRT		;FOR /SORT:DIRECTORY
	MOVEM	T1,S.FSRT		;AND /SORT:FILES
	JRST	.POPJ1##		;AND RETURN

	$FATAL	(USK,<Unknown SORT keyword >,E.USK)
E.USK:	MOVE	T1,N
	PJRST	.TSIXN##
	SUBTTL	CPYOPN -- OPEN THE CHANNELS FOR COPY

CPYOPN:	MOVEI	T1,I.SPEC+.FXDEV	;GET INPUT DEVICE
	MOVEI	T2,I.DISK		;WHERE TO PUT DSKCHR INFO
	PUSHJ	P,DODSK			;DO DSKCHR
	MOVEI	T1,O.SPEC+.FXDEV	;GET OUTPUT DEVICE
	MOVEI	T2,O.DISK		;WHERE TO PUT DSKCHR INFO
	PUSHJ	P,DODSK			;DO DSKCHR
	LDB	T1,[POINTR (I.DISK+.DCUCH,DC.UCC)] ;GET INPUT BLOCKS/CLUSTER
	MOVEM	T1,ICLUST		;SAVE
	LDB	T2,[POINTR (O.DISK+.DCUCH,DC.UCC)] ;GET OUTPUT BLOCKS/CLUSTER
	MOVEM	T2,OCLUST		;SAVE
	JUMPE	T2,CPYOP2		;NO CHECK IF NUL:
	CAIE	T1,(T2)			;THE SAME?
	  $WARN	(CSD,<Cluster sizes differ; >,E.CSD)
CPYOP2:	MOVX	T1,.IODMP!UU.PHS	;WE USE DUMP MODE
	MOVEM	T1,I.OPEN+.OPMOD	;STORE FOR INPUT OPEN
	MOVEM	T1,O.OPEN+.OPMOD	;AND OUTPUT OPEN
	SETZM	I.OPEN+.OPBUF		;NO BUFFERS FOR DUMP MODE
	SETZM	O.OPEN+.OPBUF		;..
	MOVE	T1,I.SPEC+.FXDEV	;GET INPUT DEVICE
	MOVEM	T1,I.OPEN+.OPDEV	;TRANSFER
	MOVE	T1,O.SPEC+.FXDEV	;GET OUTPUT DEVICE
	MOVEM	T1,O.OPEN+.OPDEV	;TRANSFER
	OPEN	IC,I.OPEN		;OPEN THE INPUT CHANNEL
	  $FATAL (COI,<Can't OPEN input device >,E.COI)
	OPEN	OC,O.OPEN		;OPEN THE OUTPUT CHANNEL
	  $FATAL (COO,<Can't OPEN output device >,E.COO)
	MOVE	T1,SAVFF		;GET OLD CORE
	MOVEM	T1,.JBFF		;RESET CORE
	SKIPG	T1,S.BUFF		;GET BUFFER SIZE
	  MOVX	T1,AD.BUF		;NOT GIVEN--GET DEFAULT
	WRD2BK	T1			;CONVERT TO BLOCKS
	CAIGE	T1,NBOOTB		;SEE IF ENOUGH FOR BOOTS
	  MOVEI	T1,NBOOTB		;NO--MAKE BIG ENOUGH
	LSH	T1,7			;MAKE WORDS(MULTIPLE OF BLOCKS)
	MOVEM	T1,BUFSIZ		;STORE BUFFERSIZE
	PUSHJ	P,.GTMEM		;GET SOME CORE FOR THEM
	  $FATAL (NCB,<Need >,E.NCB)	;NO CORE FOR BUFFERS
	MOVEM	T1,BUFLOC		;SAVE ADDR OF BUFFER
	SETZM	NUFDS			;CLEAR COUNTS
	SETZM	NSFDS
	SETZM	NFILES
	SETZM	NBLKS
	MOVX	T1,%NSUPT		;GET UPTIME (JIFFIES)
	GETTAB	T1,
	  MOVEI	T1,0
	MOVEM	T1,UPTIME

;GET TOTAL DISK READS/WRITES FOR INCREMENTAL REPORTING

	HRROI	T1,.GTRCT		;GET DISK READS
	GETTAB	T1,			;..
	  MOVEI	T1,0			;FAILED
	ANDX	T1,RC.TTL		;MASK TO JUST TOTAL
	MOVEM	T1,READS		;AND SAVE
	HRROI	T1,.GTWCT		;GET DISK READS
	GETTAB	T1,			;..
	  MOVEI	T1,0			;FAILED
	ANDX	T1,WC.TTL		;MASK TO JUST TOTAL
	MOVEM	T1,WRITES		;AND SAVE
	POPJ	P,			;RETURN

E.COI:	MOVE	T1,I.OPEN+.OPDEV
	PJRST	.TSIXN##

E.COO:	MOVE	T1,O.OPEN+.OPDEV
	PJRST	.TSIXN##

E.NCB:	MOVE	T1,BUFSIZ		;GET BUFFER SIZE
	PUSHJ	P,.TCORW##		;TYPE AS CORE WORD
	MOVEI	T1,[ASCIZ/ core for buffers/];GET MESSAGE
	PJRST	.TSTRG##		;FINISH OFF AND RETURN

E.CSD:	MOVE	T1,I.DISK+.DCNAM	;GET NAME
	PUSHJ	P,.TSIXN##
	PUSHJ	P,.TCOLN##
	MOVE	T1,ICLUST
	PUSHJ	P,.TDECP
	MOVEI	T1,[ASCIZ/ and /]
	PUSHJ	P,.TSTRG##
	MOVE	T1,O.DISK+.DCNAM
	PUSHJ	P,.TSIXN##
	PUSHJ	P,.TCOLN##
	MOVE	T1,OCLUST
	PJRST	.TDECP
	SUBTTL	DODSK -- ROUTINE TO PERFORM DSKCHR UUO

;CALL:
;	MOVEI	T1,ADDR STRNAME
;	MOVEI	T2,DSKCHR ARG BLOCK

DODSK:	PUSHJ	P,.SAVE2##		;SAVE P1,P2
	MOVEI	P1,(T1)			;SAVE ADDR STRNAME
	MOVEI	P2,(T2)			;SAVE ADDR OF DSKCHR BLOCK
	MOVE	T1,(P1)			;GET STRNAME
	MOVEM	T1,.DCNAM(T2)		;STORE STR NAME
	DEVCHR	T1,			;SEE IF GOOD DEVICE
	JUMPE	T1,E$$NSD		;JUMP IF NO SUCH DEVICE
	TLC	T1,-1-<(DV.TTA)>	;SEE IF NUL:
	TLCN	T1,-1-<(DV.TTA)>	;..
	  JRST	[CAIN  P1,O.SPEC+.FXDEV	;YES--SEE IF OUTPUT SPEC
		  POPJ P,		;YES--JUST RETURN
		 JRST	E$$DND]		;NO--ERROR
	HRLI	T2,LN$DSK		;INDICATE LENGTH OF DSKCHR BLOCK
	DSKCHR	T2,			;TRY
	  $FATAL (DND,<Device not a disk >,E.DND)
	LDB	T1,[POINTR (T2,DC.TYP)]	;GET TYPE
	CAIE	T1,.DCTFS		;A FILE STR NAME?
	  $FATAL (DNF,<Device not a file structure >,E.DND)
	MOVE	T1,.DCSNM(P2)		;GET PHYSICAL STR NAME
	MOVEM	T1,(P1)			;SAVE AS USERS ARG
	SKIPG	S.SINGLE		;/SINGLE?
	  POPJ	P,			;NO--RETURN
	MOVX	T2,.FSRDF		;GET FUNCTION
	MOVEM	T2,STRBLK+.FSFCN	;STORE
	SETOM	STRBLK+.FSRJN		;ME
	SETOM	STRBLK+.FSRPP		;..
	MOVEM	T1,STRBLK+.FSRNM	;STORE STR NAME
	MOVX	T1,FS.RSA		;SET SINGLE ACCESS
	MOVEM	T1,STRBLK+.FSRST	;STORE FLAGS
	MOVE	T1,[5,,STRBLK]		;POINT TO ARGS
	STRUUO	T1,			;TRY SINGLE ACCESS
	  JRST	E.SUF			;CANT
	$INFO	(SSS,<Setting structure >,E.SSS,.POPJ##)
E.SSS:	MOVE	T1,(P1)			;GET STR NAME
	PUSHJ	P,.TSIXN##		;TYPE
	MOVEI	T1,[ASCIZ/ single access/];FINISH OFF
	PJRST	.TSTRG##		;AND RETURN

E.SUF:	$WARN	(CSS,<Cannot set single access for >,ESUF,.POPJ##)
ESUF:	MOVE	T1,(P1)			;GET STR NAME
	PJRST	.TSIXN##		;TYPE AND RETURN

	$FATAL	(NSD,<No such device >,E.DND)
E.DND:	MOVE	T1,.DCNAM(P2)		;GET USER ARG
	PJRST	.TSIXN##		;TYPE
	SUBTTL	FILDAE -- CHECK IF THE FILE DAEMON IS RUNNING

FILDAE:	MOVX	T1,%SIFDA		;GET FILDAE PID
	GETTAB	T1,			;FROM MONITOR
	  MOVEI	T1,0			;FAILED-ASSUME NOT THERE
	JUMPE	T1,.POPJ##		;RETURN IF NO FILDAE AROUND
	$WARN	(FDR,<File Daemon is running>);WARN HIM
	POPJ	P,			;AND RETURN
	SUBTTL	CPYREL  -- RELEASE THE CHANNELS FOR COPY

CPYREL:	RELEAS	IC,			;FREE INPUT CHANNEL
	RELEAS	OC,			;AND OUTPUT CHANNEL
	MOVE	T1,SAVFF		;GET OLD CORE SIZE
	PJRST	.PTMEM			;RESET CORE AND RETURN
	SUBTTL	CBOOTS -- COPY BOOTS IN BLOCKS 4-7

CBOOTS:	SKIPE	OCLUST			;SKIP IF OUTPUT TO NUL:
	SKIPG	S.BOOTS			;COPY BOOTS?
	  POPJ	P,			;NO
	MOVEI	T1,FBOOTB		;POINT TO FIRST BOOT BLOCK
	MOVEI	T2,NBOOTB		;SET NUMBER OF BOOT BLOCKS
	PUSHJ	P,BOOTB			;COPY
	  JRST	E$$ATB			;ERROR
	MOVEI	T1,0			;COPY BLOCK 0
	MOVEI	T2,1			;1 BLOCK
	PUSHJ	P,BOOTB			;COPY
	  $WARN	(ATB,<Aborting transfer of BOOT blocks>,,.POPJ##)
	$INFO	(BBC,<BOOT blocks copied>)
	POPJ	P,			;AND RETURN
;SUBROUTINE TO COPY BLOCKS
;CALL:
;	MOVEI	T1,STARTING BLOCK
;	MOVEI	T2,NUMBER OF BLOCKS
;	PUSHJ	P,BOOTB
;	  <ERROR>		;INPUT/OUTPUT/SUSET. FAILURE
;	<NORMAL>		;BLOCKS COPIED

BOOTB:	MOVEI	T3,IC			;GET CHANNEL
	DPB	T3,[POINTR (T1,SU.SCH)]	;STORE FOR SUSET.
	SUSET.	T1,			;SET TO READ BOOTS
	  JRST	E$$SUF			;FAILED!
	MOVEI	T3,OC			;GET CHANNEL
	DPB	T3,[POINTR (T1,SU.SCH)]	;STORE FOR SUSET.
	TXO	T1,SU.SOT		;INDICATE WRITE
	SUSET.	T1,			;SET TO WRITE BOOTS
	  JRST	E$$SUF			;FAILED!
	IMULI	T2,200			;MAKE WORDS
	MOVNS	T2			;NEGATE
	HRLZ	T1,T2			;POSITION
	HRR	T1,BUFLOC		;POINT TO BUFFER
	SUBI	T1,1			;MAKE IOWD
	MOVEI	T2,0			;CLEAR IO LIST
	IN	IC,T1			;READ BOOTS
	  SKIPA				;GOOD!
	JRST	E$$IRB			;INPUT ERROR READING BOOTS
	OUT	OC,T1			;WRITE BOOTS
	  JRST	.POPJ1##		;GOOD RETURN
	JRST	E$$OWB			;OUTPUT ERROR WRITING BOOTS

	$WARN	(SUF,<SUSET. UUO failure>,,.POPJ##)

	$WARN	(IRB,<>,E.IRB,.POPJ##)
E.IRB:	GETSTS	IC,T1
	PUSHJ	P,.TIOER
	MOVEI	T1,[ASCIZ/ reading BOOT blocks/]
	PJRST	.TSTRG##

	$WARN	(OWB,<>,E.OWB,.POPJ##)
E.OWB:	GETSTS	OC,T1
	PUSHJ	P,.TIOER
	MOVEI	T1,[ASCIZ/ writing BOOT blocks/]
	PJRST	.TSTRG##
	SUBTTL	CFESYS -- COPY FE.SYS

CFESYS:	SKIPE	OCLUST			;SKIP IF OUTPUT TO NUL:
	SKIPG	S.FESYS			;COPY FE.SYS?
	  POPJ	P,			;NO
	TRO	F,FR.FE			;FLAG COPING FE.SYS
	RELEAS	OC,			;RE-OPEN OUTPUT CHANNEL
	MOVX	T1,UU.DER		;DISABLE ERROR RETRY
	IORM	T1,O.OPEN+.OPMOD	;SET FOROPEN
	OPEN	OC,O.OPEN		;OPEN IT UP
	  JRST	E$$COO			;FAILED??
	MOVE	T1,SYSPPN		;GET SYS: PPN
	MOVEM	T1,I.PATH+.PTPPN	;SET
	SETZM	I.PATH+.PTPPN+1		;INSURE NO SFD'S
	MOVEI	DP,[SIXBIT/FE/		;SETUP FILENAME
		    SIXBIT/SYS/]	;AND EXTENSION
	PUSHJ	P,CPYFIL		;COPY THE FILE
	  JRST	E%ACF			;ERROR
	PUSHJ	P,FERIB			;FIX FE.SYS RIB
	  JRST	E$$ACF			;FAILED
	MOVEI	T1,LBNHM1		;GET 1ST HOME BLOCK
	PUSHJ	P,FEHOME		;PUT IN HOME BLOCK
	  JRST	E$$ACF			;FAILED
	MOVEI	T1,LBNHM2		;GET 2ND HOME BLOCK
	PUSHJ	P,FEHOME		;PUT IN HOME BLOCK
	  JRST	E$$ACF			;FAILED
	$INFO	(FEC,<Front end file FE.SYS copied>)
FEDONE:	TRZ	F,FR.FE			;FLAG DONE WITH FRE.SYS
	RELEAS	OC,			;RE-OPEN CHANNEL
	MOVX	T1,UU.DER		;ENABLING ERROR RETRY
	ANDCAM	T1,O.OPEN+.OPMOD	;..
	OPEN	OC,O.OPEN		;OPEN CHANNEL AGAIN
	  JRST	E$$COO			;FAIILED??
	POPJ	P,			;AND RETURN

E%ACF:	TRNE	F,FR.FE			;FILE NOT FOUND?(FR.FE FLAG)
	  $WARN	(ACF,<Aborting copying of front end file>)
	JRST	FEDONE
	SUBTTL	FE ROUTINES -- FIX RIB

FERIB:	LOOKUP	OC,I.LOOK		;LOOKUP FILE
	  POPJ	P,			;SHOULD NEVER HAPPEN
	USETI	OC,0			;READ THE PRIME RIB
	IN	OC,BLKIO
	  SKIPA
	HALT
	CLOSE	OC,CL.ACS!CL.DAT
	MOVX	T1,RP.NDL!RP.NFS!RP.ABC
	IORM	T1,BLK+.RBSTS
	MOVE	T1,BLK+.RBSLF		;GET RIB POSITION
	MOVEI	T3,OC			;GET CHANNEL
	DPB	T3,[POINTR (T1,SU.SCH)]	;STORE
	TXO	T1,SU.SOT		;INDICATE WRITE
	SUSET.	T1,			;SET TO WRITE
	  JRST	E$$SUF			;FAILED
	OUT	OC,BLKIO		;WRITE IT
	  SKIPA
	HALT
	JRST	.POPJ1##
	SUBTTL	FE ROUTINES -- FIX HOME BLOCKS

;CALL:	MOVEI	T1,HOME BLOCK NUMBER
;	PUSHJ	P,FEHOME
;	  <ERROR>
;	<NORMAL>

FEHOME:	PUSHJ	P,.SAVE1##		;SAVE P1
	MOVEI	P1,(T1)			;GET BLOCK NUMBER
	MOVEI	T1,OC			;GET CHANNEL
	DPB	T1,[POINTR (P1,SU.SCH)]	;STORE FOR SUSET.
	SUSET.	P1,			;SETUP TO READ HOME BLOCKS
	  JRST	E$$SUF			;FAILED!
	IN	OC,BLKIO		;READ HOME BLOCK
	  SKIPA				;GOOD!
	JRST	E$$IHB			;INPUT ERROR READING HOME BLOCKS
	PUSHJ	P,HOMCHK		;CHECK HOME BLOCKS
	  POPJ	P,			;CONSISTENCY FAILURE
	MOVE	T3,FEPOS		;GET FE.SYS POSTION
	ADDI	T3,1			;JUST PAST RIB
	PUSHJ	P,SPLTWO		;MAKE INTO 11 FORMAT
	TXO	T3,HM$VAL		;SAY ITS VALID
	MOVEM	T3,HOMFEA+BLK		;STORE FOR 11
	WRD2BK	T3,I.LOOK+.RBSIZ	;GET FILE SIZE IN BLOCKS
	PUSHJ	P,SPLTWO		;MAKE INTO 11 FORMAT
	MOVEM	T3,HOMFES+BLK		;STORE
	TXO	P1,SU.SOT		;SET TO WRITE
	SUSET.	P1,			;SHOOT
	  JRST	E$$SUF			;FAILED
	OUT	OC,BLKIO		;WRITE BLOCKS
	  JRST	.POPJ1##		;GOOD!
	$WARN	(OHB,<>,E.OHB,.POPJ##)
E.OHB:	GETSTS	OC,T1
	PUSHJ	P,.TIOER
	MOVEI	T1,[ASCIZ/ writing HOME blocks/]
	PJRST	.TSTRG##

	$WARN	(IHB,<>,E.IHB,.POPJ##)
E.IHB:	GETSTS	OC,T1
	PUSHJ	P,.TIOER
	MOVEI	T1,[ASCIZ/ reading HOME blocks/]
	PJRST	.TSTRG##

;ROUTINE TO SPLIT UP 36 BIT -10 WORD INTO TWO 16 BIT QUANTITIES, IN
; HALF WORDS

SPLTWO:	LDB	T4,[POINT 16,T3,35-16] 	;GET SECOND 16 BITS
	ANDI	T3,177777		;MASK OFF ALL BUT FIRST 16 BITS
	HRL	T3,T4			;MAKE HALF-WORDS SO -11 CAN SEE ALL
	POPJ	P,			;RETURN
	SUBTTL	HOME ROUTINES -- CHECK THE HOME BLOCK

HOMCHK:	MOVE	T3,HOMNAM+BLK
	CAME	T3,[SIXBIT/HOM/]
	  $WARN	(HBC,<HOME block consistency failure>,,.POPJ##)
	MOVE	T1,HOMCOD+BLK
	CAIE	T1,CODHOM
	  JRST	E$$HBC
	JRST	.POPJ1##
	SUBTTL	CPYMFD -- PROCESS THE MFD

CPYMFD:	MOVE	T1,MFDPPN		;GET MFD PPN
	MOVEM	T1,I.LOOK+.RBNAM	;SAVE AS FILENAME
	MOVEM	T1,I.PATH+.PTPPN	;STORE PATH
	SETZM	I.PATH+.PTPPN+1		;INSURE END
	MOVSI	T1,'UFD'		;GET UFD EXTENSION
	MOVEM	T1,I.LOOK+.RBEXT	;SET
	MOVEI	T1,I.PATH		;POINT TO PATH
	MOVEM	T1,I.LOOK+.RBPPN	;RESET
	MOVEI	T1,LN$LEN-1		;GET LENGTH OF LOOKUP
	MOVEM	T1,I.LOOK+.RBCNT	;SET
	PUSHJ	P,GETDIR		;LOOKUP AND READ DIRECTORY
	  POPJ	P,			;LOOKUP OR INPUT ERROR
	SKIPN	MP,T1			;GET AOBJN POINTER TO UFD LIST
	  POPJ	P,			;EMPTY--RETURN NOW

MFDLOP:	PUSHJ	P,CPYUFD		;COPY THE UFD
	AOBJN	MP,.+1			;ADVANCE
	AOBJN	MP,MFDLOP		;LOOP FOR ALL ENTRIES IN MFD
	POPJ	P,			;AND RETURN
	SUBTTL	CPYUFD -- PROCESS A UFD

CPYUFD:	MOVE	T1,[I.LOOK,,I.LOOK+1]	;SET UP BLT
	SETZM	I.LOOK			;CLEAR FIRST WORD
	BLT	T1,I.LOOK+LN$LEN-1	;CLEAR BLOCK
	SKIPN	T1,S.INIT+.FXDIR	;GET PPN
	  JRST	CPYUF1			;NO /INITIAL--GO
	CAME	T1,(MP)			;MATCH CURRENT PPN?
	  POPJ	P,			;NO--RETURN
	SETZM	S.INIT+.FXDIR		;YES--RESET
CPYUF1:	SKIPN	T1,(MP)			;GET PPN
	  POPJ	P,			;THAT WAS EASY!
	CAMN	T1,MFDPPN		;THE MFD?
	  POPJ	P,			;YES--SKIP THAT
	MOVEM	T1,I.LOOK+.RBNAM	;STORE
	XOR	T1,.FXDIR+I.SPEC	;COMPARE PPNS
	TDNE	T1,.FXDIM+I.SPEC	;CLEAR WILDCARDS
	  POPJ	P,			;DIDNT MATCH
	SKIPN	T1,.FXDIR+S.EXCLUDE	;GET DIRECTORY
	  JRST	CPYU.1			;NO /EXCLUDE
	XOR	T1,I.LOOK+.RBNAM	;COMPARE
	TDNN	T1,.FXDIM+S.EXCLUDE	;SEE IF MATCH
	  POPJ	P,			;YES--RETURN
CPYU.1:	MOVE	T1,MFDPPN		;GET MFDPPN
	MOVEM	T1,I.PATH+.PTPPN	;SET PATH
	SETZM	I.PATH+.PTPPN+1		;INSURE END
	MOVSI	T1,'UFD'		;GET UFD EXTENSION
	MOVEM	T1,I.LOOK+.RBEXT	;STORE
	MOVEI	T1,I.PATH		;GET PATH
	MOVEM	T1,I.LOOK+.RBPPN	;RESET
	MOVEI	T1,LN$LEN-1		;GET LENGTH OF LOOKUP
	MOVEM	T1,I.LOOK+.RBCNT	;STORE
	PUSH	P,.JBFF			;SAVE CURRENT CORE SIZE
	PUSHJ	P,GETDIR		;READ THE DIRECORY
	  JRST	UFDEND			;LOOKUP/INPUT ERROR
	MOVE	DP,T1			;GET AOBJN POINTER TO FILENAMES
	PUSHJ	P,MAKDIR		;ENTER NEW DIRECTORY
	  JRST	UFDEND			;FAILED
	AOS	NUFDS			;COUNT UFDS 
	JUMPE	DP,UFDEND		;IF EMPTY, NOTHING TO DO
	MOVE	T1,I.LOOK+.RBNAM	;GET UFD NAME
	MOVEM	T1,I.PATH+.PTPPN	;STORE FOR PATH
	SETZB	L,I.PATH+.PTPPN+1	;START AT LEVEL 0, CLEAR PATH
	PUSHJ	P,SETPTH		;SET DIRECTORY PATH FOR SPEED

UFDLOP:	PUSHJ	P,CPYFIL		;COPY FILE
	  JFCL				;ERROR--INGORE
	AOBJN	DP,.+1			;ADVANCE
	AOBJN	DP,UFDLOP		;LOOP FOR ALL
UFDEND:	POP	P,.JBFF			;RESTORE CORE SIZE
	POPJ	P,			;AND RETURN
	SUBTTL	CPYFIL -- PROCESS A FILE

CPYFIL:	PUSHJ	P,.SAVE4##
	MOVE	T1,S.RETRY		;GET RETRY COUNTER
	MOVEM	T1,NRETRY		;RESET
CPYAGN:	MOVE	T1,[I.LOOK,,I.LOOK+1]	;SET UP BLT
	SETZM	I.LOOK			;CLEAR FIRST WORD
	BLT	T1,I.LOOK+LN$LEN-1	;CLEAR BLOCK
	SETZM	CURBLK			;CLEAR BLOCK COUNT
	SKIPN	T1,(DP)			;GET FILENAME
	  JRST	.POPJ1##		;ALL DONE
	MOVEM	T1,I.LOOK+.RBNAM	;STORE NAME
	HLRZ	T1,1(DP)		;GET EXTENSION
	HRLZM	T1,I.LOOK+.RBEXT	;STORE EXTENSION
	MOVEI	T2,I.PATH		;POINT TO PATH
	MOVEM	T2,I.LOOK+.RBPPN	;STORE POINTER
	CAIN	T1,'SFD'		;SEE IF SFD
	  JRST	CPYSFD			;YES--HANDLE DIFFERENTLY
	MOVEI	T1,LN$LEN-1		;GET LENGTH OF LOOKUP
	MOVEM	T1,I.LOOK+.RBCNT	;SET
	LOOKUP	IC,I.LOOK		;LOOKUP FILE
	  JRST	CPYLOK			;HANDLE LOOKUP ERROR
	PUSHJ	P,CHKOPR		;SEE IF ANY COMMANDS
	PUSHJ	P,CHKTST		;CHECK /SINCE/BEFORE, ETC.
	  JRST	CPYSKP			;NO--SKIP THE COPY
	PUSHJ	P,CHKSUP		;CHECK /SUPERSEDE: ARG
	  JRST	CPYSKP			;NO--SKIP THE COPY
	TRNN	F,FR.FE			;SKIP IF DOING FE.SYS
	  PUSHJ	P,LSTFIL		;LIST FILE
	MOVE	T1,[I.LOOK,,O.ENTER]	;START AT .RBCNT
	BLT	T1,O.ENTER+LN$LEN-1	;BLT LOOKUP BLOCK
	SETZM	O.ENTER+.RBDEV		;CLEAR DEVICE
	SETZM	O.ENTER+.RBPOS		;CLEAR POSITION TO ALLOCATE
	SETZM	O.ENTER+.RBSTS		;CLEAR STATUS
	SETZM	O.ENTER+.RBXRA		;CLEAR NEXT RIB ADDR
	PUSHJ	P,GETALC		;GET FILE ALLOCATION
	  JRST	CPYIER			;INPUT READ ERROR (FE.SYS RIB)
	LDB	T1,[POINTR (I.LOOK+.RBPRV,RB.MOD)];GET FILE MODE
	SETSTS	OC,(T1)			;FOOL FILSER
	ENTER	OC,O.ENTER		;ENTER THE OUTPUT FILE
	  JRST	CPYENT			;HANDLE ENTER ERROR
	SETSTS	OC,.IODMP		;BACK TO DUMP MODE FOR TRANSFERS
	MOVE	P2,I.LOOK+.RBSIZ	;GET INPUT SIZE
	MOVEI	P4,0			;CLEAR IOWD LIST

CPYLOP:	JUMPLE	P2,CPYEND		;JUMP IF ALL DONE
	CAMG	P2,BUFSIZ		;TOO BIG FOR BUFFER?
	  SKIPA	P3,P2			;NO--USE WHATS LEFT
	MOVE	P3,BUFSIZ		;YES--JUST USE BUFSIZ
	MOVNS	P3			;MAKE IOWD
	HRLZS	P3			;..
	HRR	P3,BUFLOC		;GET ADDR OF BUFFERS
	SUBI	P3,1			;MINUS 1
	IN	IC,P3			;READ THE BUFFER
	  SKIPA				;OK
	JRST	CPYIER			;INPUT ERROR
	CAMG	P2,BUFSIZ
	  SKIPA	T1,P2
	WRD2BK	T1,BUFSIZ		;CONVERT BUFSIZ TO BLOCKS
	ADDM	T1,CURBLK		;ADVANCE BLOCK COUNTER
	OUT	OC,P3			;WRITE THE BUFFER
	  SKIPA				;OK
	JRST	CPYOER			;OUTPUT ERROR
	SUB	P2,BUFSIZ		;SUBTRACT WHAT WE DID
	TRZE	F,FR.ABORT		;ABORTED?
	  JRST	CPYABT			;YES
	PUSHJ	P,CHKOPR		;SEE IF ANY COMMANDS
	JRST	CPYLOP

CPYEND:	CLOSE	IC,CL.ACS!CL.DAT	;CLOSE INPUT FILE
	CLOSE	OC,CL.ACS!CL.DAT!CL.DLL	;CLOSE OUTPUT FILE
	GETSTS	OC,P1			;GET STATUS
	TXNE	P1,IO.ERR		;ANY ERRORS?
	  JRST	CPYCLS			;CLOSE ERROR
	AOS	NFILES			;COUNT FILES
	WRD2BK	T1,I.LOOK+.RBSIZ	;GET FILE SIZE
	ADDM	T1,NBLKS		;AND KEEP TOTALS
	JRST	.POPJ1##		;RETURN

CPYSKP:	CLOSE	IC,CL.ACS!CL.DAT	;CLOSE INPUT FILE
	JRST	.POPJ1##		;AND RETURN

CPYCLS:	PUSHJ	P,E$$OCE		;ISSUE CLOSE ERROR
	JRST	CPYTRY			;AND DO A RETRY

CPYLOK:	HRRZ	T1,I.LOOK+.RBEXT	;GET ERROR CODE
	TRZE	F,FR.FE			;DOING FE.SYS?
	  JUMPE	T1,.POPJ##		;YES--RETURN IF FILE NOT FOUND
	PUSHJ	P,E$$ILE		;ISSUE LOOKUP ERROR
	PJRST	E$$ATF			;ABORT FILE MESSAGE AND RETURN

CPYENT:	SETSTS	OC,.IODMP		;BACK TO DUMP MODE
	CLOSE	IC,CL.ACS!CL.DAT	;CLOSE INPUT CHANNEL
	PUSHJ	P,E$$OEE		;ISSUE ENTER ERROR
	PUSHJ	P,E$$ATF		;ABORT FILE MESSAGE
	HRRZ	T1,O.ENTER+.RBEXT	;GET ENTER ERROR
	CAIE	T1,ERNRM%		;NO MORE ROOM?
	  POPJ	P,			;NO--RETURN
	PJRST	CHKSTR			;YES--CHECK STR QUOTAS

CPYIER:	GETSTS	IC,P1			;GET STATUS
	PUSHJ	P,E$$IRE		;ISSUE INPUT READ ERROR
	CLOSE	IC,CL.ACS!CL.DAT	;CLOSE INPUT FILE
	CLOSE	OC,CL.RST!CL.DAT	;CLOSE AND ABORT OUTPUT FILE
	PJRST	E$$ATF			;ABORT FILE MESSAGE AND RETURN

CPYOER:	GETSTS	OC,P1			;GET STATUS
	PUSHJ	P,E$$OWE		;ISSUE OUTPUT ERROR
	CLOSE	IC,CL.ACS		;CLOSE INPUT FILE
	CLOSE	OC,CL.RST		;CLOSE AND ABORT OUTPUT FILE
	TXNE	P1,IO.BKT		;QUOTA EXCEEDED?
	  JRST	[PUSHJ P,CHKSTR		;YES--CHECK STR QUOTAS
		 JRST  E$$ATF]		;AND ABORT TRANSFER OF FILE
	JRST	CPYTRY			;NO--TRY AGAIN

CPYTRY:	SOSG	NRETRY			;COUNT RETRIES
	  PJRST	E$$ATF			;TOO MANY--ABORT FILE AND RETURN
	$INFO	(RCF,<Retrying copying file >,E.RCF,CPYAGN)
E.RCF:	MOVEI	T1,I.OPEN		;POINT TO OPEN BLOCK
	MOVEI	T2,I.LOOK		;POINT TO LOOKUP BLOCK
	PJRST	.TOLEB##		;TYPE AND RETURN

CPYABT:	CLOSE	IC,CL.ACS!CL.DAT	;CLOSE INPUT FILE
	CLOSE	OC,CL.RST!CL.DAT	;CLOSE AND DELETE OUTPUT FILE
	PJRST	E$$ATF			;ISSUE ABORT FILE ERROR AND RETURN
	SUBTTL	CHKTST -- SEE IF WE SHOULD COPY THE FILE

CHKTST:	TRNE	F,FR.FE			;SEE IF FE.SYS
	  JRST	.POPJ1##		;YES--ALWAYS WINS
	MOVE	T1,I.LOOK+.RBSTS	;GET FILE STATUS
	TXNE	T1,RP.NFS		;SEE IF NEVER FAILSAFE (FSCOPY?)
	  POPJ	P,			;YES--REJECT
	SKIPGE	I.SPEC+.FXSNC		;SEE IF /SINCE
	 SKIPL	I.SPEC+.FXBFR		;OR /BEFORE
	  SKIPA				;YES
	JRST	CHKT.1			;NO--SAVE SOME DATE CONVERSION

	MOVE	T2,I.LOOK+.RBPRV	;GET CREATION DATE/TIME
	LDB	T3,[POINTR (I.LOOK+.RBEXT,RB.CRX)] ;GET HIGH CREATION DATE
	LSH	T3,WID(RB.CRD)		;POSITION OVER
	LDB	T1,[POINTR (T2,RB.CRT)]	;GET CREATION TIME
	IMULI	T1,^D60000		;CONVERT TO MILLISECONDS
	ANDX	T2,RB.CRD		;MASK DATE
	ADD	T2,T3			;COMBINE WITH DATE EXTENSION
	PUSHJ	P,.CNVDT##		;CONVERT TO INTERNAL FORMAT
	SKIPLE	I.SPEC+.FXBFR		;SEE IF /BEFORE
	 CAMG	T1,I.SPEC+.FXBFR	;YES--SEE IF TOO YOUNG
	  CAMGE	T1,I.SPEC+.FXSNC	;SEE IF TOO OLD
	POPJ	P,			;NO--REJECT

CHKT.1:	SKIPGE	I.SPEC+.FXASN		;SEE IF /ASINCE
	 SKIPL	I.SPEC+.FXABF		;SEE IF /ABEFORE
	  SKIPA				;YES
	JRST	CHKT.2			;NO--SAVE SOME DATE CONVERSION

	LDB	T2,[POINTR (I.LOOK+.RBEXT,RB.ACD)] ;GET ACCESS DATE
	MOVEI	T1,0			;CLEAR TIME
	PUSHJ	P,.CNVDT##		;CONVERT TO INTERNAL FORMAT
	SKIPLE	I.SPEC+.FXABF		;SEE IF /ABEFORE
	 CAMG	T1,I.SPEC+.FXABF	;YES--SEE IF TOO YOUNG
	  CAMGE	T1,I.SPEC+.FXASN	;SEE IF TOO OLD
	POPJ	P,			;NO--REJECT

CHKT.2:	MOVE	T1,I.LOOK+.RBTIM	;GET INTERNAL DATE
	SKIPLE	S.MBFR			;SEE IF /MBEFORE
	 CAMG	T1,S.MBFR		;YES--SEE IF TOO YOUNG
	  CAMGE	T1,S.MSNC		;SEE IF TOO OLD
	POPJ	P,			;NO--REJECT
	JRST	.POPJ1##		;WINS!
	SUBTTL	CHKSUP -- See if you should SUPERSEDE the output file

CHKSUP:	PUSHJ	P,.SAVE1##		;SAVE P1
	MOVE	P1,S.SUPER		;GET /SUPERSEDE
	CAIN	P1,SUPALWAYS		;SEE IF /SUPERSEDE:ALWAYS
	  JRST	.POPJ1##		;YES
	MOVE	T1,[I.LOOK,,O.ENTER]	;BLT LOOKUP BLOCK
	BLT	T1,O.ENTER+LN$LEN-1	;..
	LOOKUP	OC,O.ENTER		;LOOKUP OUTPUT FILE
	  JRST	.POPJ1##		;FAILED--ASSUME SUPERSEDE
	CAIN	P1,SUPNEVER		;SEE IF /SUPERSEDE:NEVER
	  JRST	CHKS.1			;YES--DONT SUPERSEDE
	MOVEI	T1,O.ENTER		;POINT TO LOOKUP BLOCK
	PUSHJ	P,GETDAT		;CONVERT
	PUSH	P,T1			;SAVE
	MOVEI	T1,I.LOOK		;POINT TO LOOKUP BLOCK
	PUSHJ	P,GETDAT		;CONVERT
	POP	P,T2			;GET NEW DATE
	CAMG	T2,T1			;OUTPUT NEWER?
	  AOS	(P)			;NO--SUPERSEDE
CHKS.1:	CLOSE	OC,CL.ACS!CL.NMB	;CLOSE FILE
	POPJ	P,			;AND RETURN

GETDAT:	MOVEI	T4,(T1)			;SAVE ADDR BLOCK
	MOVE	T2,.RBPRV(T4)		;GET CREATION DATE/TIME
	LDB	T3,[POINTR (.RBEXT(T4),RB.CRX)] ;GET HIGH CREATION DATE
	LSH	T3,WID(RB.CRD)		;POSITION OVER
	LDB	T1,[POINTR (T2,RB.CRT)]	;GET CREATION TIME
	IMULI	T1,^D60000		;MAKE MILLSECONDS
	ANDX	T2,RB.CRD		;MASK DATE
	ADD	T2,T3			;CONBINE WITH DATE EXTENSION
	PJRST	.CNVDT##		;CONVERT TO INTERNAL FORMAT
	SUBTTL	GETALC -- Routine to set .RBEST, .RBALC, .RBPOS

;This routine computes the estimated file size based on the input
;and output cluster sizes, and the input file size.  If the output
;cluster size is greater than the input cluster size, the input
;.RBALC (allocated) is used as .RBEST (estimated) for output.  If the
;input cluster size is greater than the output cluster size, we
;determine if the input file is really allocated for more than it is
;written, or if the larger allocation is just due to the rounding
;involved with ribs, and cluster sizes.  If the file is not over
;allocated, its written size (rounded) is used as .RBEST (estimated)
;for the output file.  If the file is over allocated, the input .RBALC
;(allocated) is used as .RBEST (estimated) for output.

;However, if we are copying FE.SYS we must allocate it contigiously,
;and in the same position as the input FE.SYS

GETALC:	TRNE	F,FR.FE			;DOING FE.SYS?
	 JRST	GETA.1			;YES
	MOVE	T1,I.LOOK+.RBALC	;GET ALLOCATED SIZE
	MOVE	T2,ICLUST		;GET INPUT CLUSTER SIZE
	CAMG	T2,OCLUST		;BIGGER THAN OUTPUT CLUSTER?
	  JRST	GETA.2			;NO--USE INPUT ALOOCATED
	WRD2BK	T3,I.LOOK+.RBSIZ	;GET INPUT FILE SIZE
	ADDI	T3,NM$RIB		;ACCOUNT FOR RIBS
	PUSH	P,T3			;SAVE SIZE
	ADDI	T3,-1(T2)		;ROUND UP TO CLUSTER SIZE
	IDIVI	T3,(T2)			;TO INPUT CLUSTER SIZE
	IMULI	T3,(T2)			;..
	CAMG	T1,T3			;EXTRA ALLOCATION?
	  MOVE	T1,(P)			;NO--USE JUST ROUNDED WRITTEN
	POP	P,T3			;FIX STACK
GETA.2:	MOVEM	T1,O.ENTER+.RBEST	;STORE AS ESTIMATED
	SETZM	O.ENTER+.RBALC		;CLEAR ALLOCATED
	JRST	.POPJ1##		;GOOD RETURN

GETA.1:	SETZM	O.ENTER+.RBEST		;CLEAR EST SO ALC USED
	USETI	IC,0			;SET TO READ PRIME RIB
	IN	IC,BLKIO		;READ IT
	  SKIPA				;OK
	POPJ	P,			;INPUT READ ERROR
	MOVE	T1,BLK+.RBSLF		;GET SELF BLOCK
	MOVEM	T1,FEPOS		;SAVE FOR LATER
	MOVEM	T1,O.ENTER+.RBPOS	;AND SET FOR ENTER
	JRST	.POPJ1##		;GOOD RETURN
CHKSTR:	MOVE	T1,[LN$DSK,,O.DISK]	;DO DSKCHR ON OUTPUT STR
	DSKCHR	T1,			;..
	  POPJ	P,			;
	SKIPL	O.DISK+.DCFCT		;FILE STRF FULL?
	  POPJ	P,			;NO
	$FATAL	(FSF,<File structure >,E.FSF)
E.FSF:	MOVE	T1,O.OPEN+.OPDEV	;GET DEVICE
	PUSHJ	P,.TSIXN##		;TYPE
	MOVEI	T1,[ASCIZ/ is full/]
	PJRST	.TSTRG##
	SUBTTL	CPYSFD -- PROCESS AN SFD

CPYSFD:	SETZM	I.PATH+.PTPPN+1(L)	;INSURE END OF PATH
	PUSH	P,.JBFF			;SAVE .JBFF
	PUSHJ	P,GETDIR		;READ DIRECTORY
	  JRST	SFDEND			;LOOKUP/INPUT ERROR
	PUSH	P,DP			;SAVE OLD DIRECTORY POINTER
	MOVE	DP,T1			;GET NEW DIRECTORY POINTER
	PUSHJ	P,MAKDIR		;CREATE SFD
	  JRST	SFDEN1			;ERROR
	AOS	NSFDS			;COUNT SFDS
	JUMPE	DP,SFDEN1		;ALL DONE IF NULL SFD
	ADDI	L,1			;ADVANCE INTO SFD NESTING
	MOVE	T1,I.LOOK+.RBNAM	;GET SFD NAME
	MOVEM	T1,I.PATH+.PTPPN(L)	;SAVE
	SETZM	I.PATH+.PTPPN+1(L)	;INSURE END OF PATH
	PUSHJ	P,SETPTH		;SET DIRECTORY PATH FOR SPEED

SFDLOP:	PUSHJ	P,CPYFIL		;COPY FILE
	  JFCL				;ERROR--INGORE
	AOBJN	DP,.+1			;ADVANCE
	AOBJN	DP,SFDLOP		;LOOP FOR ALL FILES
	SUBI	L,1			;BACK UP TREE
	SETZM	I.PATH+.PTPPN+1(L)		;INSURE END OF PATH
SFDEN1:	POP	P,DP			;RESTORE OLD DIRECTORY POINTER
SFDEND:	POP	P,.JBFF			;RESTORE .JBFF
	PJRST	.POPJ1##		;AND RETURN
	SUBTTL	GETDIR -- LOOKUP AND READ DIRECTORY INTO CORE

;THIS ROUTINE LOOKS UP THE DIRECTORY (I.LOOK BLOCK ALREADY SET UP)
;IT READS IT INTO CORE WITH ONE DUMP IOWD, AND RETURNS AN AOBJN POINTER
;TO THE DIRECTORY IN T1. IF THIS IS ZERO, THE DIRECTORY IS EMPTY.

;CALL:
;	PUSHJ	P,GETDIR
;	  <ERROR>			;LOOKUP FAILURE OR INPUT READ ERROR
;	<RETURN>			;T1=AOBJN POINTER

GETDIR:	PUSHJ	P,.SAVE1##		;SAVE P1
	MOVEI	T1,LN$LEN-1		;GET LOOKUP LENGTH
	MOVEM	T1,I.LOOK+.RBCNT	;SET
	LOOKUP	IC,I.LOOK		;LOOKUP THE DIRECTORY
	  JRST	D$ILE			;PROCESS LOOKUP ERROR
	SKIPN	T1,I.LOOK+.RBSIZ	;GET SIZE OF DIRECTORY
	  JRST	GETDR2			;EMPTY--CLOSE AND RETURN
	PUSHJ	P,.GTMEM		;GET SOME CORE
	  JRST	E$$NCD			;NO CORE FOR DIRECTORY
	MOVN	T2,I.LOOK+.RBSIZ	;GET SIZE IN WORDS
	HRLZS	T2			;MAKE IOWD
	HRRI	T2,-1(T1)		;POINT TO FREE CORE
	MOVEI	T1,0			;CLEAR IOWD LIST
	EXCH	T1,T2			;REPOSITION ARGUMENTS
	INPUT	IC,T1			;READ THE UFD
	ADDI	T1,1			;MAKE INTO AOBJN FROM IOWD
	PUSH	P,T1			;SAVE AOBJN
	MOVE	T2,S.FSRT		;GET /SORT:FILES
	MOVE	T3,I.LOOK+.RBNAM	;GET DIRECTORY NAME
	CAMN	T3,MFDPPN		;SEE IF [1,1]
	  MOVE	T2,S.DSRT		;YES--USE /SORT:DIRECTORY
	PUSHJ	P,.SORT2		;SORT THE GUY
;	  $WARN (NCS,<No core for directory sort>)
	POP	P,T1			;RESTORE T1
GETDR2:	CLOSE	IC,CL.ACS		;AND CLOSE IT
	GETSTS	IC,P1			;GET CHANNEL STATUS
	TXNE	P1,IO.ERR		;ANY ERRORS?
	  PUSHJ	P,E$$IRE		;YES--REPORT THEM
	JRST	.POPJ1##		;NO--LOOKS GOOD
D$ILE:	PUSHJ	P,E$$ILE
	PJRST	E$$ATD

	$WARN	(NCD,<No core for directory>,,E$$ATD)

	$WARN	(ATD,<Aborting transfer of directory >,E.ATD,.POPJ##)
E.ATD:	MOVE	T1,I.OPEN+.OPDEV	;GET DEVICE
	PUSHJ	P,.TSIXN##		;TYPE
	PUSHJ	P,.TCOLN##		;TYPE COLON
	MOVE	T1,I.LOOK+.RBNAM	;GET DIRECTORY NAME
	HLRZ	T2,I.LOOK+.RBEXT	;GET UFD/SFD
	CAIN	T2,'UFD'		;UFD?
	  PJRST	.TPPNW##		;YES--TYPE AS PPN
	MOVE	T2,[I.PATH,,E.PATH]	;COPY CURRENT PATH
	BLT	T2,E.PATH+.PTMAX	;CLEAR OUT
	MOVEM	T1,E.PATH+.PTPPN+1(L)	;STORE SFD NAME
	SETZM	E.PATH+.PTPPN+2(L)	;INSURE END
	MOVEI	T1,[E.PATH]		;POINT TO PATH
	PJRST	.TDIRB##		;TYPE SPEC
	SUBTTL	SETPTH -- SET DEFAULT DIRECTORY PATH

SETPTH:	MOVX	T1,.PTFSD		;DEFINE DEFAULT PATH
	MOVEM	T1,I.PATH+.PTFCN
	SETZM	I.PATH+.PTSWT
	MOVE	T1,[2+.FXLND,,I.PATH]
	PATH.	T1,
	  JFCL
	POPJ	P,


RSTPTH:	MOVX	T1,.PTFSD		;DEFINE PATH
	MOVEM	T1,SVPATH+.PTFCN	;STORE
	MOVE	T1,[.PTMAX,,SVPATH]	;POINT TO BLOCK
	PATH.	T1,			;RESTORE PATH
	  JFCL				;PROBABLY NEVER CHANGED
	POPJ	P,			;AND RETURN
	SUBTTL	MAKDIR  --  CREATE A DIRECTORY

MAKDIR:	MOVE	T1,[I.LOOK,,O.ENTER]	;GET LOOKUP BLOCK
	BLT	T1,O.ENTER+LN$LEN-1	;BLT ACROSS
	SETZM	O.ENTER+.RBDEV		;CLEAR DEVICE
	SETZM	O.ENTER+.RBPOS		;AND POSITION
	MOVE	T1,O.ENTER+.RBALC	;GET ALOOCATED
	MOVEM	T1,O.ENTER+.RBEST	;STORE
	SETZM	O.ENTER+.RBALC		;CLEAR ALLOCATED
	SETZM	O.ENTER+.RBUSD		;CLEAR USED
	MOVX	T1,RP.DIR!RP.ABC	;GET DIRECTORY BITS
	MOVEM	T1,O.ENTER+.RBSTS	;SET
	ENTER	OC,O.ENTER		;ENTER FILE
	  JRST	DERR			;SOME ERROR
	USETO	OC,2			;WRITE A BLOCK
	MOVX	T1,CL.ACS		;GET CLOSE BITS
	SKIPE	S.ALLOCATE		;/ALLOCATE?
	  TXO	T1,CL.DLL		;YES--KEEP EXTRA SPACE
	CLOSE	OC,(T1)			;CLOSE FILE
	JRST	.POPJ1##		;AND RETURN

DERR:	HRRZ	T1,O.ENTER+.RBEXT	;GET ERROR CODE
	CAIE	T1,ERCSD%		;SEE IF CANT SIPERCEED DIRECTORY
	CAIN	T1,ERPRT%		;SEE IF PROTECTION FAILURE
	  JRST	.POPJ1##		;YES--THATS OK
	PUSHJ	P,E$$OEE		;ISSUE ENTER ERROR
	PJRST	E$$ATD			;GIVE ABORT ERROR AND RETURN
	
	SUBTTL	LSTFIL -- LIST A FILE SPEC

LSTFIL:	MOVE	T1,S.LEVEL		;GET LEVEL
	CAIN	T1,%SILENCE		;SEE IF SILENCE
	  POPJ	P,			;YES--DO NOTHING
	MOVSI	T2,-2-.FXLND		;GET PATH POINTER
LSTCHK:	MOVE	T3,I.PATH(T2)		;GET CURRENT PATH
	CAME	T3,C.PATH(T2)		;SEE IF SAME
	  JRST	LSTNEW			;NO--NEW PATH
	AOBJN	T2,LSTCHK		;LOOP FOR ALL
	JRST	LSTIT
LSTNEW:	MOVE	T1,[I.PATH,,C.PATH]	;GET PATH
	BLT	T1,C.PATH+1+.FXLND	;COPY
	MOVEI	T1,C.PATH+.PTPPN
	TLO	T1,1
	PUSHJ	P,.TDIRB##
	PUSHJ	P,.TCRLF##
LSTIT:	MOVE	T1,S.LEVEL
	CAIN	T1,%DIRECT
	  POPJ	P,
	MOVE	T1,I.LOOK+.RBNAM
	PUSHJ	P,.TSIXN##
	MOVEI	T1,"."
	PUSHJ	P,.TCHAR##
	HLLZ	T1,I.LOOK+.RBEXT
	PUSHJ	P,.TSIXN##
	PJRST	.TCRLF##
	SUBTTL	CHKFIL -- SEE IF FILES COPIED

CHKFIL:	MOVX	T1,FX.NOM		;GET /ER[OR]NONE
	TDNE	T1,.FXMOD+I.SPEC	;SEE IF GIVEN
	  POPJ	P,			;YES--OK
	SKIPN	NUFDS			;SEE IF ANY UFDS
	  $WARN (NUF,<No UFDs found to match >,E.NUF,.POPJ##)
	SKIPN	NFILES			;SEE IF ANY FILES
	  $WARN	(NFF,<No files found to match >,E.NFF,.POPJ##)
	POPJ	P,			;RETURN

E.NUF:	MOVE	T1,I.SPEC+.FXDEV	;GET INPUT DEVICE
	PUSHJ	P,.TDEVN##		;TYPE
	MOVEI	T1,I.SPEC+.FXDIR	;POINT TO PPN
	TLO	T1,2			;INDICATE BIWORDS
	PUSHJ	P,.TDIRB##		;TYPE
	MOVEI	T1,[ASCIZ/.UFD/]	;FINISH OFF
	PJRST	.TSTRG##		;TYPE AND RETURN

E.NFF:	MOVE	T1,I.SPEC+.FXDEV	;GET INPUT DEVICE
	PUSHJ	P,.TDEVN##		;TYPE
	MOVEI	T1,[ASCIZ/*.*/]		;LOAD FULL WILD
	PUSHJ	P,.TSTRG##		;TYPE
	MOVEI	T1,I.SPEC+.FXDIR	;POINT TO PPN
	TLO	T1,2			;INDICATE BIWORDS
	PJRST	.TDIRB##		;TYPE AND RETURN
	SUBTTL	ERRORS

	$WARN	(IRE,<>,E.IRE,.POPJ##)	;ISSUE INPUT READ ERROR
E.IRE:	MOVE	T1,[I.OPEN,,I.LOOK]	;POINT TO BLOCK
	MOVE	T2,P1			;GET ERROR BITS
	PJRST	.TIERR			;ISSUE MESSAGE

	$WARN	(OWE,<>,E.OWE,.POPJ##)	;ISSUE OUTPUT WRITE ERROR
E.OWE:	MOVE	T1,[O.OPEN,,O.ENTER]	;POINT TO BLOCK
	MOVE	T2,P1			;GET ERROR BITS
	PJRST	.TOERR			;ISSUE MESSAGE

	$WARN	(OCE,<>,E.OCE,.POPJ##)	;ISSUE OUTPUT CLOSE ERROR
E.OCE:	MOVE	T1,[O.OPEN,,O.ENTER]	;POINT TO BLOCK
	MOVE	T2,P1			;GET ERROR BITS
	PJRST	.TCERR			;ISSUE MESSAGE

	$WARN	(ILE,<>,E.ILE,.POPJ##)	;ISSUE INPUT LOOKUP ERROR
E.ILE:	MOVE	T1,[I.OPEN,,I.LOOK]	;POINT TO BLOCK
	PJRST	.TERRL			;ISSUE MESSAGE

	$WARN	(OEE,<>,E.OEE,.POPJ##)	;ISSUE OUTPUT ENTER ERROR
E.OEE:	MOVE	T1,[O.OPEN,,O.ENTER]	;POINT TO BLOCK
	PJRST	.TERRL			;ISSUE MESSAGE

	$WARN	(ATF,<Aborting transfer of file >,E.ATF,.POPJ##)
E.ATF:	MOVEI	T1,I.OPEN
	MOVEI	T2,I.LOOK
	PJRST	.TOLEB##
	SUBTTL	I$INIT -- INITIALIZE PROGRAM VARIABLES

I$INIT:

;GET MFD PPN (IF FAILED ASSUME [1,1])

	MOVX	T1,%LDMFD		;GET MFD PPN
	GETTAB	T1,			;FROM MONITOR
	  MOVE	T1,[1,,1]		;FAILED--ASSUME [1,1]
	MOVEM	T1,MFDPPN		;AND SAVE

;GET SYS PPN (IF FAILED ASSUME [1,4])

	MOVX	T1,%LDSYS		;GET SYS PPN
	GETTAB	T1,			;FROM MONITOR
	  MOVE	T1,[1,,4]		;FAILED!--ASSUME [1,4]
	MOVEM	T1,SYSPPN		;AND SAVE

;GET OPR PPN (IF FAILED ASSUME [1,2])

	MOVX	T1,%LDFFA		;GET OPR PPN
	GETTAB	T1,			;FROM MONITOR
	  MOVE	T1,[1,,2]		;FAILED!--ASSUME [1,2]
	MOVEM	T1,OPRPPN		;AND SAVE

;READ DEFAULT PATH FOR LATER RESTORE (DONT CARE IF FAILED)

	MOVX	T1,.PTFRD		;READ DEFAULT PATH
	MOVEM	T1,SVPATH+.PTFCN	;SAVE
	MOVE	T1,[.PTMAX,,SVPATH]	;POINT TO BLOCK
	PATH.	T1,			;READ IT
	  JFCL				;SO WHAT

;SETUP ^C TRAPPING TO RESET PATH. AT EXIT

	MOVE	T1,[4,,CCINT]		;ADDR OF INTERRUPT ROUTINE
	MOVEM	T1,CCBLK+.ERNPC		;SAVE
	MOVX	T1,ER.ICC		;BITS TO TRAP
	MOVEM	T1,CCBLK+.ERCLS		;STORE CLASS
	SETZM	CCBLK+.EROPC		;CLEAR OLD PC
	SETZM	CCBLK+.ERCCL		;AND STATUS
	MOVEI	T1,CCBLK		;POINT TO BLOCK
	MOVEM	T1,.JBINT		;INABLE INTERRUPTS

;GET TICKS/SECOND TO CONVERT UPTIME TO SECONDS

	MOVX	T1,%CNTIC		;GET TICKS/SECOND FROM MONITOR
	GETTAB	T1,			;..
	  MOVEI	T1,^D60			;ASSUME 60 CYCLE IF FAILED
	MOVEM	T1,TICKS		;AND SAVE

	POPJ	P,			;INITIALIZATION DONE, RETURN
	SUBTTL	PSISER ROUTINES

PIINIT:	MOVE	T1,[VECTOR,,VECTOR+1]	;SET UP BLT
	SETZM	VECTOR			;CLEAR FIRST WORD
	BLT	T1,VECTOR+LN$VEC-1	;CLEAR VECTORS
	MOVEI	T1,TTYSER		;GET ROUTINE TO HANDLE TTY
	MOVEM	T1,VECTOR+TTYBLK+.PSVNP	;SAVE PC
	MOVEI	T1,CHKPNT		;ROUTINE TO HANDLE CHECKPOINTS
	MOVEM	T1,VECTOR+CHKBLK+.PSVNP	;SAVE PC
	MOVEI	T1,VECTOR		;POINT TO BLOCK
	PIINI.	T1,			;TURN SYSTEM ON
	  TLO	F,(FL.PSI)		;FLAG PSISER BROKEN
REPEAT 0,<
	MOVSI	T1,'TTY'		;DEVICE TTY:
	MOVE	T2,[TTYBLK,,PS.RID]	;ON INPUT DONE
	MOVEI	T3,0			;MUST BE ZERO
	MOVE	T4,[PS.FON+PS.FAC+T1]	;POINT TO BLOCK
	TLNN	F,(FL.PSI)		;SKIP IF PSISER BROKEN
	 PISYS.	T4,			;TRY IT
	  TLO	F,(FL.PSI)		;FLAG PSISER BROKEN
>
	MOVX	T1,.PCWAK		;INTERRUPT ON WAKE UUO
	MOVSI	T2,CHKBLK		;OFFSET,,REASONS
	MOVEI	T3,0			;MUST BE ZERO
	MOVE	T4,[PS.FAC+T1]		;POINT TO BLOCK
	TLNN	F,(FL.PSI)		;SKIP IF PSISER BROKEN
	 PISYS.	T4,			;TRY IT
	  TLO	F,(FL.PSI)		;FLAG PSISER BROKEN
	POPJ	P,			;RETURN

PIOFF:	SKIPA	T1,[PS.FOF]		;TURN SYSTEM OFF
PION:	  MOVX	T1,PS.FON		;TURN SYSTEM ON
	TLNN	F,(FL.PSI)		;SKIP IF PSISER BROKEN
	 PISYS.	T1,			;DO IT
	  TLO	F,(FL.PSI)		;FLAG PSISER BROKEN
	POPJ	P,


TTYSER:	TLZN	F,(FL.CC)		;SEE IF ^C TYPED
	  SETOM	TTYFLG			;NO--FLAG SOMETHING TYPED
INTJEN:	DEBRK.				;RETURN
	  JFCL
	$FATAL	(CRI,<Can't return from interrupt>)

	SUBTTL	CHKPNT -- ROUTINES FOR CHECKPOINTING

;CHKPNT -- TAKE A CHECKPOINT NOW

CHKPNT:	PUSHJ	P,.PSH4T##		;SAVE T1-T4
	PUSHJ	P,CHKDAE		;SEE IF REALLY DAEMON
	  JRST	CHKP.1			;NO--JUST INGORE
	$INFO	(CHK,<Checkpoint at >,DOCHK)
	PUSHJ	P,SETCHK		;SETUP FOR NEXT CHECKPOINT
CHKP.1:	PUSHJ	P,.POP4T##		;RESTORE AC'S
	JRST	INTJEN			;AND RETURN

;SETCHK -- SETUP FOR NEXT CHECKPOINT

SETCHK:	MOVX	T2,.CLOCK		;CLOCK FUNCTION
	MOVE	T3,S.CHECK		;MINUTES BETWEEN CHECKPOINTS
	IMULI	T3,^D60			;MAKE SECONDS FOR DAEMON
	MOVE	T1,[2,,T2]		;POINT TO ARG BLOCK
	DAEMON	T1,			;DO IT
	  $WARN (DUF,<DAEMON UUO failure>)
	POPJ	P,

;CHKDAE -- SEE IF WAKER IS REALLY DAEMON

CHKDAE:	MOVS	T1,VECTOR+CHKBLK+.PSVIS	;GET JOB NUMBER OF WAKER
	HRRI	T1,.GTPRG		;GET PROGRAM NAME
	GETTAB	T1,			;TRY
	  JRST	.POPJ1##		;?? ASSUME OK
	CAME	T1,[SIXBIT/DAEMON/]	;PROGRAM=DAEMON?
	  POPJ	P,			;NO
	MOVS	T1,VECTOR+CHKBLK+.PSVIS	;GET JOB NUMBER AGAIN
	HRRI	T1,.GTSTS		;GET JOB STATUS
	GETTAB	T1,			;TRY
	  JRST	.POPJ1##		;?? ASSUME OK
	TXNN	T1,JACCT		;SEE IF JACCTED
	  POPJ	P,			;NO
	JRST	.POPJ1##		;YES--ITS THE REAL DAEMON!
CHKOPR:	JRST	CHKO.1
	TLNE	F,(FL.PSI)		;SEE IF PSISER WORKS
	  JRST	CHKO.1			;NO--DO THE HARD WAY
	MOVEI	T1,0			;LOAD A ZERO
	EXCH	T1,TTYFLG		;GET FLAG,,CLEAR IT
	JUMPE	T1,.POPJ##		;JUMP IF NO INPUT
CHKO.1:	SKPINL				;SEE IF LINE TYPED
	  POPJ	P,			;NO
	PUSHJ	P,TTYCOM		;YES--PROCESS A COMMAND
	JRST	CHKO.1			;AND SEE IF ANOTHER
	SUBTTL	TTY COMMAND PROCESSOR

TTYCOM:	PUSHJ	P,SIXIN			;READ A SIXBIT WORD
	CLRBFI
	JUMPE	T2,PROMPT		;JUMP IF NOTHING
	MOVE	T1,[IOWD LN$RUN,RUNCMD]	;GET POINTER TO KNOWN COMMANDS
	PUSHJ	P,.LKNAM##		;LOOK THEN UP
	  JRST	CMDERR			;NOT FOUND
	SUBI	T1,RUNCMD		;GET INDEX
	PUSHJ	P,@RUNDSP(T1)		;DISPATCH ON COMMAND
PROMPT:	TRNN	F,FR.STOP		;WE STOPPED?
	  OUTCHR ["!"]			;NO--GIVE "GO" PROMPT
	TRNE	F,FR.STOP		;WE STOPPED?
	  OUTCHR ["/"]			;YES--GIVE "STOPPED" PROMPT
	TRNE	F,FR.STOP		;WE STOPPED?
	  JRST	TTYCOM			;YES--WAIT FOR COMMAND
	POPJ	P,			;AND RETURN

CMDERR:	JUMPG	T1,E$$ARC
	$WARN	(URC,<Unknown runtime command>,,PROMPT)
	$WARN	(ARC,<Ambiguous runtime command>,,PROMPT)

	DEFINE	CMDS,<
	XLIST
	XX	WHAT,DOWHAT
	XX	SILENCE,DOSIL
	XX	DIRECTORY,DODIR
	XX	NODIRECTORY,DOSIL
	XX	FILES,DOFIL
	XX	NOFILE,DODIR
	XX	HELP,DOHELP
	XX	KILL,DOKILL
	XX	STOP,DOSTOP
	XX	GO,DOGO
	XX	CURRENT,DOCURR
	XX	ABORT,DOABORT
	XX	EXIT,DOEXIT
	LIST
>

	DEFINE	XX(NAME,DISPATCH),<EXP SIXBIT/NAME/>

RUNCMD:	CMDS
	LN$RUN==.-RUNCMD

	DEFINE	XX(NAME,DISPATCH),<EXP DISPATCH>

RUNDSP:	CMDS
	SUBTTL	RUNTIME COMMAND DISPATCH ROUTINES

DOSIL:	MOVEI	T1,%SILENCE
	JRST	SETLVL
DODIR:	SKIPA	T1,[%DIRECTORY]
DOFIL:	  MOVEI	T1,%FILES
SETLVL:	MOVEM	T1,S.LEVEL
	POPJ	P,

DOWHAT:	MOVEI	T1,[ASCIZ/Stopped
/]
	TRNE	F,FR.STOP
	  PUSHJ	P,.TSTRG##
	MOVEI	T1,[ASCIZ/Will EXIT when done
/]
	TLNE	F,(FL.EXIT)
	  PUSHJ	P,.TSTRG##
	PUSHJ	P,$WHAT
	PUSHJ	P,DOCURR
	PJRST	TOTALS


DOHELP:	OUTSTR	[ASCIZ/
[NO]FILES	Type files as processed
[NO]DIRECTORY	Type directories as processed
SILENCE		No progress message typeout
HELP		This text
KILL		Abort copying the file structure
ABORT		Stop copying this file only
CURRENT		Type current file spec being ocpied
WHAT		Type job statistics and current file
STOP		Stop FSCOPY now
GO		Continue from a STOP
EXIT		Exit from FSCOPY when done

/]
	POPJ	P,

DOKILL:	PUSHJ	P,E$$ATF		;GIVE ABORT FILE MESSAGE
	PUSHJ	P,CHKFIL		;SEE IF ANY FILES FOUND
	PUSHJ	P,RSTPTH		;RESTORE PATH
	RESET				;RESET THE WORLD
	TLNE	F,(FL.EXIT)		;EXIT WHEN DONE?
	  PUSHJ	P,.MONRT##		;YES--EXIT
	JRST	MAINLP			;AND START AGAIN

DOABORT:TRO	F,FR.ABORT
	SETZM	NRETRY
	POPJ	P,

DOEXIT:	TLO	F,(FL.EXIT)		;SET EXIT WHEN DONE
	POPJ	P,			;AND RETURN

DOSTOP:	TROA	F,FR.STOP
DOGO:	  TRZ	F,FR.STOP
	POPJ	P,

DOCURR:	PUSHJ	P,DOCHK
	PJRST	.TCRLF##

DOCHK:	SKIPN	T1,I.LOOK+.RBNAM
	  POPJ	P,
	MOVEI	T1,I.OPEN
	MOVEI	T2,I.LOOK
	PUSHJ	P,.TOLEB##
	MOVEI	T1,[ASCIZ/ (block=/]
	PUSHJ	P,.TSTRG##
	MOVE	T1,CURBLK
	PUSHJ	P,.TDECW##
	MOVEI	T1,"/"
	PUSHJ	P,.TCHAR##
	WRD2BK	T1,I.LOOK+.RBSIZ
	PUSHJ	P,.TDECW##
	MOVEI	T1,")"
	PJRST	.TCHAR##
$WHAT:	PUSHJ	P,.SAVE1##
	MOVE	T1,S.LEVEL
	MOVE	T1,[ [ASCIZ/Silence/]
		     [ASCIZ/Type Directories/]
		     [ASCIZ/Type Files/] ](T1)
	PUSHJ	P,.TSTRG##
	PUSHJ	P,.TCRLF##
	MOVE	T1,S.DSRT
	CAIN	T1,SRTKNONE
	  JRST	WHAT1
	MOVEI	T1,[ASCIZ/Sort Directories /]
	PUSHJ	P,.TSTRG##
	MOVE	T1,S.DSRT
	MOVE	T1,[ [ASCIZ/Name/]
		     [ASCIZ/Extension/]
		     [ASCIZ/Location/] ]-2(T1)
	PUSHJ	P,.TSTRG##
	PUSHJ	P,.TCRLF##
WHAT1:	MOVE	T1,S.FSRT
	CAIN	T1,SRTKNONE
	  JRST	WHAT2
	MOVEI	T1,[ASCIZ/Sort Files /]
	PUSHJ	P,.TSTRG##
	MOVE	T1,S.FSRT
	MOVE	T1,[ [ASCIZ/Name/]
		     [ASCIZ/Extension/]
		     [ASCIZ/Location/] ]-2(T1)
	PUSHJ	P,.TSTRG##
	PUSHJ	P,.TCRLF##
WHAT2:	MOVEI	T1,[ASCIZ/Copying BOOT blocks
/]
	SKIPLE	S.BOOTS
	  PUSHJ	P,.TSTRG##
	MOVEI	T1,[ASCIZ/Copying front end file FE.SYS
/]
	SKIPLE	S.FESYS
	  PUSHJ	P,.TSTRG##
	MOVEI	T1,[ASCIZ/Checkpointing every /]
	PUSHJ	P,.TSTRG##
	MOVE	T1,S.CHECK
	MOVEI	T2,[ASCIZ/minute/]
	PUSHJ	P,.TPLRS
	PUSHJ	P,.TCRLF##
	MOVSI	P1,-LN$WHT
	TRZ	F,FR.SWT
WHAT3:	SKIPG	@WHTSWT(P1)
	  JRST	WHAT4
	MOVEI	T1,[ASCIZ/Conditions  /]
	TRON	F,FR.SWT
	  PUSHJ	P,.TSTRG##
	MOVEI	T1,[ASCIZ/		/]
	PUSHJ	P,.TSTRG##
	MOVE	T1,WHTTXT(P1)
	PUSHJ	P,.TSTRG##
	PUSHJ	P,.TCOLN##
	MOVE	T1,@WHTSWT(P1)
	PUSHJ	P,.TDTTM##
	PUSHJ	P,.TCRLF##
WHAT4:	AOBJN	P1,WHAT3
	TRZE	F,FR.SWT
	  PUSHJ	P,.TCRLF##
	MOVEI	T1,[ASCIZ/SUPERSEDE /]
	PUSHJ	P,.TSTRG##
	MOVE	T1,S.SUPER
	MOVE	T1,[ [ASCIZ/Always/]
		     [ASCIZ/Older/]
		     [ASCIZ/Never/] ]-1(T1)
	PUSHJ	P,.TSTRG##
	PUSHJ	P,.TCRLF##
	POPJ	P,

	DEFINE	SWTS,<
	XLIST
	X	SINCE,.FXSNC+I.SPEC
	X	BEFORE,.FXBFR+I.SPEC
	X	ASINCE,.FXASN+I.SPEC
	X	ABEFORE,.FXABF+I.SPEC
	X	MSINCE,S.MSNC
	X	MBEFORE,S.MBFR
	LIST
>

	DEFINE	X(A,B),<EXP [ASCIZ/A/]>

WHTTXT:	SWTS
LN$WHT==.-WHTTXT

	DEFINE	X(A,B),<EXP B>

WHTSWT:	SWTS
	SUBTTL	RUNTIME COMMAND INPUT

SIXIN:	MOVEI	T2,0			;CLEAR WORD
	MOVE	T1,[POINT 6,T2]		;GET BYTE POINTER
SIXIN1:	INCHWL	T3			;GET A CHAR
	CAIL	T3,"a"			;SEE IF LOWER CASE
	CAILE	T3,"z"			;..
	  SKIPA				;NO
	SUBI	T1,"a"-"A"		;YES--MAKE UPPER CASE
	CAIL	T3,"A"			;ALPHABETIC?
	CAILE	T3,"Z"			;..
	  POPJ	P,			;NO--RETURN
	SUBI	T3," "-' '		;MAKE SIXBIT
	TLNE	T1,(77B5)		;POINTER OVERFLOW?
	  IDPB	T3,T1			;NO--STORE CHAR
	JRST	SIXIN1			;LOOP FOR MORE
	SUBTTL	SORT ROUTINES


;
; SOME NON-STANDARD AC DEFINITIONS
;
	I==T3		;INDEX TO LOW END OF SWAP LIST
	J==T4		;INDEX TO HIGH END OF SWAP LIST
	LL==P1		;POINTER TO LEFT END OF LIST TO SORT
	R==P2		;POINTER TO RIGHT END OF LIST TO SORT
	X1==P3		;HIGH ORDER VALUE TO SPLIT WITH
	X2==P4		;LOW ORDER VALUE TO SPLIT WITH
	Q==16		;FORTRAN ARG POINTER

; .SORT2 - SORT TWO WORD PAIRS INTO ASCENDING ORDER
;	INPUT:	T1/ AOBJN POINTER TO LIST TO BE SORTED
;		    MUST BE EVEN NUMBER OF WORDS
;		T2/ FLAGS,,SORT CODE
;			FLAGS ARE 400000 FOR UNSIGNED SORT
;			  	  200000 FOR DESCENDING SORT
;			SORT CODE IS
;				0 NONE
;				1 NONE
;				2 KEY IS 1234
;				3 KEY IS 3124
;				4 KEY IS 4123
;				WHERE HALF WORDS ARE NUMBERED 1-4 FOR
;				THE TWO WORD PAIR
;	CALL:	PUSHJ P,.SORT2##
;	RETURN:	NON-SKIP
;	OUTPUT:	NONE
;	USES:	T1-4
;
.SORT2:	PUSHJ P,.SAVE4##	;GET SOME ACS
	JUMPGE	T1,.POPJ##	;RETURN IF LIST EMPTY
	MOVEI	T3,(T2)		;GET JUST TYPE OF SORT
	CAIG	T3,1		;SEE IF ANYTHING TO DO
	 POPJ	P,		;NO--RETURN
	DMOVEM	T1,USRARG	;SAVE USERS ARGS
	HLRE	R,T1		;GET -LENGTH IN R
	MOVM	R,R		;MAKE +LENGTH
	SUBI	R,1		;SUBTRACT ONE, SO POINTING TO LAST PAIR
	CAIE	R,1		;SEE IF ONLY 1
	 TRNN	R,1B35		;ENSURE AN ODD COUNT NOW
	  POPJ	P,		;JUST RETURN
	MOVE	P1,USRARG	;GET IOWD POINTER
	PUSHJ	P,@INISRT-2(T2)	;DO INITIAL SETUP
	MOVE	P1,USRARG	;PICKUP IOWD POINTER AGAIN
	MOVE	T2,USRARG+1	;PICKUP USER FLAGS
	TLNE	T2,200000	;DESCENDING ORDER?
	 PUSHJ	P,NEGSRT	;YES--FIX UP
	MOVE	P1,USRARG	;PICKUP IOWD POINTER AGAIN
	MOVE	T2,USRARG+1	;PICKUP USER FLAGS
	TLNE	T2,400000	;USER WANT UNSIGNED?
	 PUSHJ	P,FLPSRT	;YES--FIX UP
	MOVE	T1,USRARG	;GET IOWD PNTR
	ADDI	R,-1(T1)	;ADD IN BASE ADR, GET ADR OF RIGHT END
	MOVEI	LL,(T1)		;GET BASE ADR IN L, ADR OF LEFT END
	MOVEM	P,SAVPDP	;STORE P FOR TERMINATION CHECK
	JRST	SOR.02		;JUMP INTO "SORT THIS L,R PAIR"
	SUBTTL	SORT A PARTITION
SOR.01:	POP	P,T1		;TAKE OFF TOP REQUEST
	HRRZI	R,(T1)		;EXTRACT RIGHT END ADR
	HLRZ	LL,T1		;EXTRACT LEFT END ADR
SOR.02:	MOVEI	I,(LL)		;SET UP POINTERS FOR THIS
	MOVEI	J,(R)		; SCAN AND SWAP SEQUENCE
	MOVE	X1,(LL)		;USE FIRST PAIR FOR SCAN AND SWAP
	MOVE	X2,1(LL)	; SO GET FIRST AND SECOND WORDS
	JRST	SOR.06		;AND SKIP TO CHECK RIGHT,SINCE LEFT .EQ.

SOR.03:	CAME	X1,(I)		;SEE IF HIGH ORDER MATCH
	JRST	SOR.05		;NO, USE THAT TO DECIDE
	CAMG	X2,1(I)		;YES, CHECK NEXT WORD
	JRST	SOR.06		;WE FOUND AN I ENTRY LESS THAN X
SOR.04:	ADDI	I,2		;MOVE UP TO NEXT SPOT
	JRST	SOR.03		;BACK TO FIND A SWAPPABLE ENTRY

SOR.05:	CAML	X1,(I)		;CHECK FIRST WORD AGAIN
	JRST	SOR.04		;NO SWAP, BACK TO INCREMENT AND LOOP
SOR.06:	CAME	X1,(J)		;NOW SAME PROCEDURE FOR RIGHT END
	JRST	SOR.08		;DON'T HAVE TO CHECK X2
	CAML	X2,1(J)		;CHECK LOW ORDER WORD
	JRST	SOR.09		;YES, MAKE A SWAP
SOR.07:	SUBI	J,2		;ELSE DECREMENT J
	JRST	SOR.06		;AND BACK TO FIND A SWAPPABLE ENTRY

SOR.08:	CAMG	X1,(J)		;CHECK FIRST ENTRY AGAIN, SINCE .NE.
	JRST	SOR.07		;NO SWAP, BACK TO DECREMENT AND LOOP
SOR.09:	CAILE	I,(J)		;CHECK IF POINTERS HAVE SWAPPED
	JRST	SOR.10		;YES, THIS SWAP AND SCAN COMPLETE
	DMOVE	T1,(I)		;NO, MAKE A SWAP
	EXCH	T1,(J)		;EXCH EACH WORD
	EXCH	T2,1(J)		; ...
	DMOVEM	T1,(I)		;FINISH THE EXCHANGE
	ADDI	I,2		;MOVE THE POINTERS
	SUBI	J,2		; TOWARD EACH OTHER
	CAILE	I,(J)		;CHECK IF POINTERS HAVE SWAPPED
	JRST	SOR.10		;YES, THIS SWAP AND SCAN COMPLETE
	JRST	SOR.03		;AND BACK TO CONTINUE
	SUBTTL	SELECT NEXT PARTITION FOR SORT
SOR.10:	MOVEI	T1,(J)		;CALCULATE J-LL
	SUBI	T1,(LL)		; ...
	MOVEI	T2,(R)		;AND CALCULATE R-I
	SUBI	T2,(I)		; ...
	CAML	T1,T2		;SEE WHICH IS LONGER
	JRST	SOR.11		;(J-LL) .GE. (R-I)
	CAIL	I,(R)		;IS I .LT. R? (IE, MORE TO SORT?)
	JRST	SOR.12		;NO, CHECK IF OTHER SIDE NEEDS
	MOVEI	T1,(R)		;STACK REQUEST TO SORT THIS
	HRLI	T1,(I)		;T1/ XWD I,R
	PUSH	P,T1		;STICK IT ON THE STACK
SOR.12:	MOVEI	R,(J)		;AND MOVE DOWN THE R POINTER
	JRST	SOR.13		;THEN GO CHECK IF DONE

SOR.11:	CAIL	LL,(J)		;IS LL .LT. J?
	JRST	SOR.14		;NO, GO MOVE UP THE L POINTER
	MOVEI	T1,(J)		;YES, STACK REQUEST TO SORT THIS
	HRLI	T1,(LL)		;FROM LL TO J
	PUSH	P,T1		;STACK IT
SOR.14:	MOVEI	LL,(I)		;MOVE UP LL, SINCE ALL BELOW SORTED
SOR.13:	CAIGE	LL,(R)		;ARE WE DONE WITH THIS PARTITION?
	JRST	SOR.02		;NO, BACK TO REPEAT THE WHOLE MESS
	CAME	P,SAVPDP	;YES, IS THE PARTITION THE WHOLE LIST?
	JRST	SOR.01		;NO, LOOP TO PICK NEXT REQUEST
	MOVE	P1,USRARG	;GET IOWD POINTER
	MOVE	T2,USRARG+1	;GET SORT TYPE
	TLNE	T2,400000	;USER WANT UNSIGNED?
	 PUSHJ	P,FLPSRT	;YES--FIX BACK
	MOVE	P1,USRARG	;GET IOWD POINTER
	MOVE	T2,USRARG+1	;GET SORT TYPE
	TLNE	T2,200000	;DESCENDING?
	 PUSHJ	P,NEGSRT	;YES--FIX BACK
	MOVE	P1,USRARG	;GET IOWD POINTER
	MOVE	T2,USRARG+1	;GET SORT TYPE
	PUSHJ	P,@FINSRT-2(T2)	;FINISH UP
	POPJ	P,		;AND RETURN
	SUBTTL	INITIAL/FINAL SORT ARRANGING ROUTINES

INISRT:	I1234
	I3124
	I4123

FINSRT:	F1234
	F3124
	F4123

I1234:
F1234:	POPJ	P,		;T1/ 1,,2  T2/ 3,,4

I3124:	DMOVE	T1,(P1)		;T1/ 1,,2  T2/ 3,,4
	MOVSS	T2		;T1/ 1,,2  T2/ 4,,3
	ROTC	T1,-^D18	;T1/ 3,,1  T2/ 2,,4
	DMOVEM	T1,(P1)		;STORE
	AOBJN	P1,.+1
	AOBJN	P1,I3124	;AND LOOP FOR ALL
	POPJ	P,

F3124:	DMOVE	T1,(P1)		;T1/ 3,,1  T2/ 2,,4
	ROTC	T1,^D18		;T1/ 1,,2  T2/ 4,,3
	MOVSS	T2		;T1/ 1,,2  T2/ 3,,4
	DMOVEM	T1,(P1)		;STORE
	AOBJN	P1,.+1
	AOBJN	P1,F3124	;AND LOOP FOR ALL
	POPJ	P,

I4123:	DMOVE	T1,(P1)		;T1/ 1,,2  T2/ 3,,4
	ROTC	T1,-^D18	;T1/ 4,,1  T2/ 2,,3
	DMOVEM	T1,(P1)		;STORE
	AOBJN	P1,.+1
	AOBJN	P1,I4123	;AND LOOP FOR ALL
	POPJ	P,

F4123:	DMOVE	T1,(P1)		;T1/ 4,,1  T2/ 2,,3
	ROTC	T1,^D18		;T1/ 1,,2  T2/ 3,,4
	DMOVEM	T1,(P1)		;STORE
	AOBJN	P1,.+1
	AOBJN	P1,F4123	;AND LOOP FOR ALL
	POPJ	P,

FLPSRT:	MOVSI	T1,(1B0)	;GET THE SIGN BIT
FLPS.1:	XORM	T1,(P1)		;TOGGLE SIGN BIT
	AOBJN	P1,.+1
	AOBJN	P1,FLPS.1	;AND LOOP FOR ALL
	POPJ	P,

NEGSRT:	SETCMM	(P1)		;NEGATE
	AOBJN	P1,.+1
	AOBJN	P1,NEGSRT	;AND LOOP FOR ALL
	POPJ	P,
;.GTMEM -- GET CORE
;CALL:	MOVEI	T1,WORDS TO GET
;	PUSHJ	P,.GTMEM
;	  (ERROR)
;	RETURN W/ T1=START OF ZEROED CORE, .JBFF UPDATED
;USES T1-3

.GTMEM:	PUSH	P,.JBFF			;SAVE FREE CORE ADR
	MOVE	T2,T1			;SAVE # WORDS
	ADDB	T1,.JBFF		;UPDATE .JBFF
	SUBI	T1,1			;SUBTRACT 1
	CAMG	T1,.JBREL		;SEE IF NEED CORE
	  JRST	GTMEM1			;NO
	TLNN	T1,-1			;SEE IF TOO BIG
	 CORE	T1,			;YES, GET IT
	  JRST	GTMEM2			;CAN'T
GTMEM1:	POP	P,T1			;GET BACK STARTING ADR
	HRLI	T3,(T1)			;GET STARTING ADR
	HRRI	T3,1(T1)		;GET STARTING ADR+1
	SETZM	(T1)			;ZERO THE FIRST WORD
	CAIN	T2,1			;SEE IF ONLY  1 WORD
	 JRST	.POPJ1##		;YES--RETURN NOW
	ADD	T2,T1			;FIND FINAL LOCATION
	BLT	T3,-1(T2)		;AND CLEAR IT ALL OUT
	JRST	.POPJ1##		;AND RETURN SUCCESSFUL

GTMEM2:	POP	P,.JBFF			;RESTORE .JBFF
	POPJ	P,			;AND ERROR RETURN
;.PTMEM -- RESET CORE BACK
;CALL:	MOVEI	T1,NEW .JBFF
;	PUSHJ	P,.PTMEM
;USES T1

.PTMEM:	MOVEM	T1,.JBFF		;STORE NEW .JBFF
	MOVNS	T1			;MAKE NEGATIVE
	ADD	T1,.JBREL		;ADD TO CURRECT SIZE
	CAIGE	T1,1000			;SEE IF DIFFERENCE A P
	  POPJ	P,			;NO
	MOVE	T1,.JBFF		;GET .JBFF
	SUBI	T1,1			;SUBTRACT ONE
	CORE	T1,			;REDUCE CORE
	  JFCL				;ERROR (DON'T CARE)
	POPJ	P,
	SUBTTL	ERROR PROCESSING


ERROR:	MOVEM	0,CRSHAC+0		;SAVE AC 0
	MOVE	0,[1,,CRSHAC+1]		;SET UP BLT
	BLT	0,CRSHAC+17		;SAVE THE ACS
	HRRZ	P1,(P)			;GET ADDRESS OF ARGS FROM CALL
	POP	P,(P)			;GET EXTRA PUSHJ OFF THE STACK
	HRRZ	T1,1(P1)		;GET CONTINUATION ADDRESS
	MOVEM	T1,(P)			;RETURN HERE
	MOVEM	P,CRSHAC+P		;UPDATE FOR LATER
	PUSHJ	P,.VERBO##		;GET VERBOSITY BITS
	PUSH	P,T1			;SAVE THEM FOR LATER
	PUSHJ	P,.TNEWL##		;START WITH A CRLF IF NEEDED
	HLRZ	T2,1(P1)		;GET MESSAGE TYPE
	SKIPN	T2			;SKIP IF WARN OR INFO
	PUSHJ	P,.CLRBF##		;MUST CLEAR TYPEAHEAD

ERROR1:	MOVE	T1,[EXP "?","%","["](T2) ; AND THE SEVERITY CHARACTER
	PUSHJ	P,.TCHAR##		;TYPE IT
	MOVE	T1,(P)			;GET VERBOSITY BITS
	TRNN	T1,JWW.PR		;/MESSAGE:PREFIX?
	JRST	ERROR2			;NO
	HRLZ	T1,IBLK+1		;GET OUR PREFIX
	HLR	T1,0(P1)		;INCLUDE ONE FOR MESSAGE
	PUSHJ	P,.TSIXN##		;TYPE IN SIXBIT

ERROR2:	PUSHJ	P,.TSPAC##		;SPACE
	POP	P,T1			;GET VERBOSITY BITS
	TRNN	T1,JWW.FL		;/MESSAGE:FIRST?
	JRST	ERROR4			;NO

ERROR3:	HRRZ	T1,0(P1)		;GET TEXT ADDRESS
	PUSHJ	P,.TSTRG##		;TYPE STRING
	HLRZ	T1,2(P1)		;GET ADDRESS FOR ADDITIONAL TYPEOUT
	JUMPE	T1,ERROR4		;JUMP IF NONE
	MOVEM	T1,ERRSUB		;SAVE ADDRESS
	MOVEM	P1,ERRSP1		;SAVE P1
	MOVSI	0,CRSHAC		;SET UP BLT
	BLT	0,17			;RESTORE THE ACS
	PUSHJ	P,@ERRSUB		;CALL ADDITIONAL TYPEOUT ROUTINE
	MOVE	P1,ERRSP1		;RELOAD P1
ERROR4:	HLRZ	T1,1(P1)		;GET ERROR TYPE
	CAIN	T1,2			;INFORMATIONAL?
	PUSHJ	P,.TRBRK##		;YES--TERMINATE WITH A BRACKET
	PUSHJ	P,.TCRLF##		;TYPE A CRLF
	MOVSI	0,CRSHAC		;SET UP BLT
	BLT	0,17			;RESTORE THE ACS
	POPJ	P,			;AND RETURN
	SUBTTL	^C AND ERROR TRAPPING

CCINT:	PUSH	P,CCBLK+.EROPC		;SAVE CURRENT PC
	SETZM	CCBLK+.EROPC		;AND RENABLE
	PUSHJ	P,.PSH4T##		;SAVE T1-T4
	PUSHJ	P,RSTPTH		;RESTORE PATH
	EXIT	1,			;AND EXIT
					;HERE IF CONTINUE
	PUSHJ	P,SETPTH		;SET PATH
	TLO	F,(FL.CC)		;FLAG ^C TYPED
	PUSHJ	P,.POP4T##		;RESTORE T1-T4
	POPJ	P,			;AND RETURN
TOTALS:	MOVEI	T2,[ASCIZ/UFD/]
	SKIPE	T1,NUFDS
	  PUSHJ	P,.TPLRS
	SKIPN	NSFDS
	  JRST	TOT1
	MOVEI	T1,[ASCIZ/, /]
	PUSHJ	P,.TSTRG##
	MOVE	T1,NSFDS
	MOVEI	T2,[ASCIZ/SFD/]
	PUSHJ	P,.TPLRS
TOT1:	SKIPN	NFILES
	  JRST	TOT2
	MOVEI	T1,[ASCIZ/, /]
	PUSHJ	P,.TSTRG##
	MOVE	T1,NFILES
	MOVEI	T2,[ASCIZ/file/]
	PUSHJ	P,.TPLRS
TOT2:	SKIPN	NBLKS
	  JRST	TOT3
	MOVEI	T1,[ASCIZ/, /]
	PUSHJ	P,.TSTRG##
	MOVE	T1,NBLKS
	MOVEI	T2,[ASCIZ/block/]
	PUSHJ	P,.TPLRS
TOT3:	PUSHJ	P,.TCRLF##
	MOVEI	T1,[ASCIZ/Elapsed time:/]
	PUSHJ	P,.TSTRG##
	MOVX	T1,%NSUPT		;GET UPTIME (TICKS)
	GETTAB	T1,
	  MOVEI	T1,0
	SUB	T1,UPTIME		;MINUS STARTING TIME
	IDIV	T1,TICKS		;INTO SECONDS
	IMULI	T1,^D1000		;INTO MILLSECONDS
	PUSHJ	P,.TTIME##		;TYPE TIME AS HH:MM:SS
	MOVEI	T1,[ASCIZ/, disk reads: /]
	PUSHJ	P,.TSTRG##
	HRROI	T1,.GTRCT
	GETTAB	T1,
	  MOVEI	T1,0
	ANDX	T1,RC.TTL
	SUB	T1,READS
	PUSHJ	P,.TDECW##
	MOVEI	T1,[ASCIZ/, writes: /]
	PUSHJ	P,.TSTRG##
	HRROI	T1,.GTWCT
	GETTAB	T1,
	  MOVEI	T1,0
	ANDX	T1,WC.TTL
	SUB	T1,WRITES
	PUSHJ	P,.TDECW##
	PJRST	.TCRLF##
.TERRL:	PUSHJ	P,.SAVE1##		;Save P1
	MOVE	P1,T1			;Remember arg
	HRRZ	T1,.RBEXT(P1)		;Get error code
	MOVSI	T2,-ERRLEN
	HLRZ	T3,ERRTAB(T2)
	CAIE	T1,(T3)
	AOBJN	T2,.-2
	HRRZ	T1,ERRTAB(T2)
	PUSHJ	P,.TSTRG##
	MOVEI	T1,[ASCIZ/ (/]		;Get string
	PUSHJ	P,.TSTRG##		;Type
	HRRZ	T1,.RBEXT(P1)		;Get error code
	PUSHJ	P,.TOCTW##		;Type in octal
	MOVEI	T1,[ASCIZ/) file /]	;Get string
	PUSHJ	P,.TSTRG##		;Type
	HLRZ	T1,P1			;Get OPEN block address
	HRR	T2,P1			;Get LOOKUP block address
	PJRST	.TOLEB##		;Type and return

ERRTAB:	ERFNF%,,[ASCIZ/Non-existent file/]
	ERIPP%,,[ASCIZ/Non-existent UFD/]
	ERPRT%,,[ASCIZ/Protection failure/]
	ERFBM%,,[ASCIZ/File being modified/]
	ERAEF%,,[ASCIZ/Already existing file/]
	ERISU%,,[ASCIZ/Illegal sequence of monitor calls/]
	ERTRN%,,[ASCIZ/Rib or directory read error/]
	ERNSF%,,[ASCIZ/Not a saved file/]
	ERNEC%,,[ASCIZ/Not enough core/]
	ERDNA%,,[ASCIZ/Device not availible/]
	ERNSD%,,[ASCIZ/No such device/]
	ERILU%,,[ASCIZ/No two register relocation capability/]
	ERNRM%,,[ASCIZ/No room or quota exceeded/]
	ERWLK%,,[ASCIZ/Write-lock error/]
	ERNET%,,[ASCIZ/Not enough free core/]
	ERPOA%,,[ASCIZ/Partial allocation only/]
	ERBNF%,,[ASCIZ/Block not free on allocated position/]
	ERCSD%,,[ASCIZ/Can't supersede existing directory/]
	ERDNE%,,[ASCIZ/Can't delete non-empty directory/]
	ERSNF%,,[ASCIZ/Non-existent SFD/]
	ERSLE%,,[ASCIZ/Search list empty/]
	ERLVL%,,[ASCIZ/SFD nested too deep/]
	ERNCE%,,[ASCIZ/No create/]
	ERSNS%,,[ASCIZ/Segment not on the swapping space/]
	ERFCU%,,[ASCIZ/Can't update file/]
	ERLOH%,,[ASCIZ/Low segment overlaps high segment/]
	ERNLI%,,[ASCIZ/Not logged in/]
	ERENQ%,,[ASCIZ/Outstanding locks set/]
	ERBED%,,[ASCIZ/Bad EXE file directory/]
	ERBEE%,,[ASCIZ/Bad EXE extension/]
	ERDTB%,,[ASCIZ/EXE directory too big/]
	ERENC%,,[ASCIZ/Network capacity exceeded/]
	ERTNA%,,[ASCIZ/Task not available/]
	ERUNN%,,[ASCIZ/Unknown network node/]
	ERSIU%,,[ASCIZ/SFD in use by another job/]
	ERNDR%,,[ASCIZ/NDR lock on/]
	ERJCH%,,[ASCIZ/Too many readers/]
	ERSSL%,,[ASCIZ/Cant rename SFD to lower level/]
	ERCNO%,,[ASCIZ/Channel not open/]
	ERDDU%,,[ASCIZ/Device detached/]
	ERDRS%,,[ASCIZ/Device is restricted/]
	ERDCM%,,[ASCIZ/Device is controlled by MDA/]
	ERDAJ%,,[ASCIZ/Device in use by another job/]
	ERIDM%,,[ASCIZ/Illegal data mode/]
	ERUOB%,,[ASCIZ/Undefined OPEN bits set/]
	ERDUM%,,[ASCIZ/Device in use on MPX channel/]
	ERNPC%,,[ASCIZ/No core for extended channel table/]
	ERNFC%,,[ASCIZ/No free channels available/]
	ERUFF%,,[ASCIZ/Unknown FILOP function/]
	ERCTB%,,[ASCIZ/Channel number too big/]
	ERCIF%,,[ASCIZ/Channel illegal for operation/]
ERRLEN==.-ERRTAB
	0,,[ASCIZ .Unknown LOOKUP/ENTER/RENAME error.]
.TOERR:	MOVEI	T3,2			;Flag OUTPUT error
	JRST	TERR			;And process
.TIERR:	TDZA	T3,T3			;Flag INPUT error
.TCERR:	 MOVEI	T3,1			;Flag CLOSE error
TERR:	PUSH	P,T1			;Save ADDR of FILOP. block
	PUSH	P,T3			;Save error type
	MOVE	T1,T2			;Get GETSTS word
	PUSHJ	P,.TIOER		;Issue message
	POP	P,T2			;Get error type
	MOVE	T1,[ [ASCIZ/ reading /]
		     [ASCIZ/ closing /]
		     [ASCIZ/ writing /] ](T2);Load corrosponding function
	PUSHJ	P,.TSTRG##		;Type it
	POP	P,T1			;GET OPEN,,LKP BLOCK
	HRRZ	T2,T1			;ISOLATE LKP
	HLRZS	T1			;AND OPEN
	PJRST	.TOLEB##		;TYPE AND RETURN
.TIOER:	MOVEI	T2,(T1)			;Save GETSTS word
	MOVEI	T1,[ASCIZ"I/O error "]	;Load general message
	TXNE	T2,IO.IMP		;See if IO.IMP
	 MOVEI	T1,[ASCIZ/Improper mode /];Yes--Load that text
	TXNE	T2,IO.DER		;See if IO.DER
	 MOVEI	T1,[ASCIZ/Hardware device error /];Yes--Load that text
	TXNE	T2,IO.DTE		;See if IO.DTE
	 MOVEI	T1,[ASCIZ/Parity error /];Yes--Load that text
	TXNE	T2,IO.BKT		;See if IO.BKT
	 MOVEI	T1,[ASCIZ/Block too large or quota exceeded /];Yes--Load that text
	PUSHJ	P,.TSTRG##		;Issue explaination of error
	MOVEI	T1,(T2)			;Get GETSTS word
;	PJRST	.TOCTP			;Type in parathesis and return

.TOCTP:	SKIPA	T2,[.TOCTW##]
.TDECP:	MOVEI	T2,.TDECW##
	PUSH	P,T1			;Save word
	MOVEI	T1,"("
	PUSHJ	P,.TCHAR##
	POP	P,T1			;Get word back
	PUSHJ	P,(T2)			;Call routine
	MOVEI	T1,")"
	PJRST	.TCHAR##

.TPLRS:	MOVEI	T3,[ASCIZ/s/]
	PUSH	P,T1
	PUSH	P,T3
	PUSH	P,T2
	PUSHJ	P,.TDECW##
	PUSHJ	P,.TSPAC##
	POP	P,T1
	PUSHJ	P,.TSTRG##
	POP	P,T1
	POP	P,T2
	CAIE	T2,1
	  PJRST	.TSTRG##
	POPJ	P,
	SUBTTL	IMPURE STORAGE

BLKIO:	IOWD	200,BLK
	Z

	RELOC	0

OFFSET:	BLOCK	1			;STARTING OFFSET FOR SCAN

S.ZER:!					;START OF VARIABLES ZEROD AT PROGRAM STARTUP

PDL:	BLOCK	LN$PDL			;THE STACK
CRSHAC:	BLOCK	20			;STORAGE FOR ACS ON ERRORS
ERRSP1:	BLOCK	1			;SPECIAL SAVED COPY OF P1
ERRSUB:	BLOCK	1			;ADDITIONAL TYPEOUT SUBROUTINE
SAVFF:	BLOCK	1			;.JBFF AFTER SCAN CALLS
MFDPPN:	BLOCK	1			;MFD [1,1] PPN
OPRPPN:	BLOCK	1			;FFA [1,2] PPN
SYSPPN:	BLOCK	1			;SYS [1,4] PPN
VECTOR:	TTYBLK==.-VECTOR		;SPACE FOR TTY BLOCK
	BLOCK	4
	CHKBLK==.-VECTOR		;SPACE FOR CHKPNT BLOCK
	BLOCK	4
LN$VEC==.-VECTOR
TTYFLG:	BLOCK	1			;-1 IF TTY INPUT TYPED
CCBLK:	BLOCK	4			;BLOCK FOR ^C AND OTHER TRAPPING
SVPATH:	BLOCK	.PTMAX			;ORIGINAL PATH
TICKS:	BLOCK	1			;TICKS/SECOND
SAVPDP:	BLOCK	1			;SAVED PDL FOR SORT
USRARG:	BLOCK	2			;SAVED ACS FOR SORT
S.INIT:	BLOCK	.FXLEN			;SPACE FOR /INITIAL:[PPN]
S.EXCL:	BLOCK	.FXLEN			;SPACE FOR /EXCLUDE:[PPN]

S.ZER1:!				;START OF VARIABLES ZEROED PER COPY COMMAND

BLK:	BLOCK	200
FEPOS:	BLOCK	1
BUFSIZ:	BLOCK	1
BUFLOC:	BLOCK	1
CURBLK:	BLOCK	1
NUFDS:	BLOCK	1
NSFDS:	BLOCK	1
NFILES:	BLOCK	1
NBLKS:	BLOCK	1
NRETRY:	BLOCK	1
UPTIME:	BLOCK	1
READS:	BLOCK	1
WRITES:	BLOCK	1
STRBLK:	BLOCK	5
C.PATH:	BLOCK	.PTMAX

O.SPEC:	BLOCK	.FXLEN
O.OPEN:	BLOCK	3
O.ENTER:BLOCK	LN$LEN
O.PATH:	BLOCK	.PTMAX
O.DISK:	BLOCK	LN$DSK
OCLUST:	BLOCK	1

I.SPEC:	BLOCK	.FXLEN
I.OPEN:	BLOCK	3
I.LOOK:	BLOCK	LN$LEN
I.PATH:	BLOCK	.PTMAX
I.DISK:	BLOCK	LN$DSK
ICLUST:	BLOCK	1
E.PATH:	BLOCK	.PTMAX+1
S.ZERM==.-1				;END OF VARIABLES TO BE ZEROED

S.ONE:!					;START OF AREA TO BE SET TO -1 (SCANS SWITCH AREA)

S.LEVEL:BLOCK	1
S.BUFF:	BLOCK	1
S.ALLOC:BLOCK	1
S.CHECK:BLOCK	1
S.DSKP:	BLOCK	1
S.HPQ:	BLOCK	1
S.MBFR:	BLOCK	1
S.MSNC:	BLOCK	1
S.BOOTS:BLOCK	1
S.FESYS:BLOCK	1
S.RETRY:BLOCK	1
S.FSRT:	BLOCK	1
S.DSRT:	BLOCK	1
S.SUPER:BLOCK	1
S.SING:	BLOCK	1
S.ONEM==.-1				;END OF SCANS SWITCH AREA

	END	FSCOPY