2!		PROGRAM		: FIT.BAS
5!		VERSION		: V10.1
6!		EDIT		: A
7!		EDIT DATE	: 10-MAY-91
10	EXTEND		! USE BASIC-PLUS EXTEND MODE
11!	&
  !	&
  !	&
  !			  C O P Y R I G H T &
  !	&
  !	&
  !		      Copyright (C) 1978, 1991 by &
  !	        Digital Equipment Corporation, Maynard, Mass. &
  !	&
  !	&
  !	This software is furnished under a license and may be used and &
  !	copied  only  in accordance with the terms of such license and &
  !	with the  inclusion  of  the  above  copyright  notice.   This &
  !	software  or  any  other copies thereof may not be provided or &
  !	otherwise made available to any other person.  No title to and &
  !	ownership of the software is hereby transferred. &
  !	&
  !	The information in this software is subject to change  without &
  !	notice  and should not be construed as a commitment by Digital &
  !	Equipment Corporation. &
  !	&
  !	DIGITAL assumes no responsibility for the use  or  reliability &
  !	of its software on equipment that is not supplied by DIGITAL. &
  !	&
  !******************************************************************* &

20	! &
	! &
	! &
	!	M O D I F I C A T I O N    H I S T O R T &
	! &

21	! VER/ED	EDIT DATE	REASON &
	! &
	! V9.0-08	08-OCT-84	(DP) Check if user has TMPPRV priv &
	! V9.0-10	25-Jan-85	(PRL) Fix help file loc -> HELP$: &
	&

100	! &
	! &
	! &
	!	G E N E R A L    D E S C R I P T I O N &
	! &
	! &
	! &
	! &
	!	FIT PROVIDES THE FOLLOWING FUNCTIONS: &
	! &
	! &
	!	1. TRANSFER FILES BETWEEN RT11 AND RSTS/E DIRECTORY DEVICES. &
	! &
	!	2. DELETE FILES ON, ZERO AND SQUEEZE RT11 DIRECTORY DEVICES. &
	! &
	!	3. TRANSFER FILES FROM DOS DISKS TO RSTS/E DEVICES. &
	! &
	!	4. LIST DIRECTORIES OF RSTS/E, RT11 AND DOS DIRECTORY DEVICES. &
	! &
	! &
	!	FOR TRANSFER AND DIRECTORY LISTING PURPOSES, FIT &
	!	RECOGNIZES THREE TYPES OF INPUT DEVICES: &
	! &
	!		1. RSTS/E DISKS. &
	!		2. RT11 DIRECTORY STRUCTURE (DISK, FLOPPY, DECTAPE). &
	!		3. DOS DIRECTORY STRUCTURE (DISK, TU56 DECTAPE). &
	! &
	!	FOR TRANSFER PURPOSES, FIT RECOGNIZES TWO TYPES OF &
	!	OUTPUT DEVICES: &
	! &
	!		1. RT11 DIRECTORY STRUCTURE. &
	!		2. RSTS/E OUTPUT. &
	! &
	!		RSTS/E OUTPUT INCLUDES RSTS/E DISKS, MAGTAPE, &
	!		TU56 DECTAPE, KEYBOARD, LINE PRINTER, ETC. &
	!		FIT OUTPUTS TO ALL THESE DEVICES SIMPLY BY OPENING &
	!		"DEV:FILNAM.TYP" AND WRITING.  THE ONLY SPECIAL &
	!		HANDLING IN THIS CATEGORY IS FOR DISKS, WHERE &
	!		ACCOUNTING INFORMATION AND ATTRIBUTES MAY BE &
	!		DIDDLED WITH. &
	! &
	!	THE ALGORITHM FIT USES TO OUTPUT TO AN RT11 DEVICE &
	!	REQUIRES THAT IT KNOW AHEAD OF TIME HOW MANY 512-BYTE &
	!	BLOCKS LONG THE FILE WILL BE.  FOR THIS REASON, &
	!	TRANSFER FROM A DOS DEVICE TO AN RT11 DEVICE IS DISALLOWED. &

900	! &
	! &
	! &
	!	D I M E N S I O N    S T A T E M E N T S &
	! &
	! &
	! &
	DIM Z%(40%), &
		! GENERAL PURPOSE ARRAY FOR SYS CALLS AND BUFFER DATA. &
	    Z1%(9%), &
		! FOR EXTRA BUFFER DATA. &
	    MATCH%(9%), &
		! FILENAME IN ASCII TO MATCH AGAINST. &
	    NAMTYP%(2%), &
		! FILENAME AND TYPE OF FILE BEING TRANSFERRED &
		! IN RADIX-50 (USING ARRAY ELEMENTS 0-2). &
	    EXTRA%(13%), &
		! TO HOLD RTS NAME AND ATTRIBUTES. &
	    DEV$(2%), &
		! THE NAMES OF THE INPUT AND OUTPUT DEVICES. &
	    DEV.SIZE(2%), &
		! SIZE OF DEVICE OPEN. &
	    DIR.ENT.LEN%(2%), &
		! LENGTH OF RT11 DIRECTORY ENTRIES. &
	    DIR.LINK%(2%), &
		! RT11 DIRECTORY ENTRY LINK. &
	    DIR.PTR%(2%), &
		! RT11 DIRECTORY BUFFER POINTER. &
	    DIR.SEG%(2%), &
		! RT11 DIRECTORY SEGMENT WE ARE PROCESSING. &
	    DIR.SIZE%(2%), &
		! NUMBER OF DIRECTORY SEGMENTS IN RT11 DEVICE. &
	    DIR.USED%(2%), &
		! NUMBER OF RT11 DIRECTORY SEGMENTS IN USE. &
	    FILE.REC%(2%), &
		! RECORD NUMBER AT WHICH FILE STARTS. &
	    FSS.SCAN$(4%) &
		! SCANNED DEVICE/FILE SPEC IN FSS FORM (30 BYTES). &

999	! &
	! &
	! &
	!	S T A R T    O F    P R O G R A M &
	! &
	! &
	! &

1000	ON ERROR GOTO 19000 &
	\ DUMMY$=SYS(CHR$(6%)+CHR$(-21%)+CHR$(255%)) &
		! SET UP STANDARD ERROR TRAP. &
		! DROP PRIVILEGES TEMPORARILY. &

1010	IDENT.STG$="V10.1-A" &
		! SET UP VERSION/EDIT FOR HEADER. &

1030	PRINT FNRET$;"FIT";CHR$(9%);IDENT.STG$;CHR$(9%);FNE$(0%) &
		UNLESS ENTRY.TYP% &
	\ CHANGE SYS(CHR$(12%)) TO Z% &
	\ PKG.LOC$="["+NUM1$(Z%(6%))+","+NUM1$(Z%(5%))+"]" &
	\ PKG.LOC$="_"+CHR$(Z%(23%))+CHR$(Z%(24%)) &
	    +NUM1$(Z%(25%))+":"+PKG.LOC$ &
		IF Z%(26%) AND 1% &
	\ IF FNFROM.Z%(3%)<>15%*2% THEN &
		PRINT "?Please 'RUN FIT'" &
	\	DUMMY$=SYS(CHR$(9%)) &
		! BUILD NAME OF DEVICE AND ACCOUNT OF LAST OPENED FILE. &
		! WE MUST HAVE COME FROM A COMPILED FILE SO WE CAN BE &
		! SURE THAT THIS MANE IS REALLY OUR PACKAGE LOCATION. &

1060	! &
	! &
	! &
	!	I N I T I A L I Z E &
	! &
	! &
	! &
	CHR.6$=CHR$(6%) &
	\ PRIV.OFF$=CHR.6$+CHR$(-21%)+CHR$(255%) &
	\ PRIV.ON$=CHR.6$+CHR$(-21%)+CHR$(0%) &
	\ DUMMY$=SYS(CHR.6$+CHR$(-7%)) &
	\ DUMMY$=SYS(PRIV.ON$) &
	\ RESTORE &
		! DEFINE CHR.6$ FOR USE IN SYS CALLS. &
		! SYS(PRIV.OFF$) WILL TEMPORARILY DROP PRIVILEGES. &
		! SYS(PRIV.ON$) WILL REGAIN TEMPORARILY DROPPED PRIVILEGES. &
		! SET CTRL/C TRAP. &
		! REGAIN TEMPORARY PRIVILEGES &
		! &

1070	READ PRIV$ &
	\ GOTO 1090 UNLESS LEN(PRIV$) &
	\ IF FNPRIV%(PRIV$) THEN &
		GOTO 1070 &
	  ELSE &
		PRINT &
	\	PRINT "?Program must be privileged" &
	\	GOTO 32767 &
		! &
		! MAKE SURE THE PROGRAM HAS ALL THE REQUIRED PRIVILEGES &
		! &

1080	DATA RDMEM,GREAD,WREAD,GWRITE,WWRITE,SYSIO,DATES,TUNE,GACNT, &
	     WACNT,DEVICE,"" &

1090	ACCNT%=PEEK(PEEK(PEEK(520%)+8%)+24%) &
		! GET THE USER'S ACCOUNT NUMBER &
	\ DUMMY$=SYS(PRIV.OFF$) &
	\ TMPPRV.PRIV%=FNPRIV%("TMPPRV") &
		! DETERMINE IF THE USER HAS TMPPRV PRIVILEGES &
	\ PROJ%=SWAP%(ACCNT%) AND 255% &
	\ PROG%=ACCNT% AND 255% &
		! FIND OUT OUR [PROJ%,PROG%]. &
	\ KB$="_KB:FIT.OUT" &
		! DEFINE A STRING FOR WHEN WE OPEN THE KB:. &
	\ WILD$="?????????" &
		! DEFINE WILDCARD MATCH STRING. &
	\ NO.MATCH$="?No files matching " &
		! ERROR MESSAGE FOR NO MATCH ON DIRECTORY LISTINGS. &
		! &
	\ DASH$=" - " &
	\ RSTS.EXTRA%,DIR.1%,MSB.LEN%,FOUND%,DOS.LINKED%, &
		IN.CLU.2%,OUT.CLU.2%, &
		PPN.COUNT%,FILE.COUNT%,USTAT%,FILE.CLU%=0% &
	\ NONE%,PPN%,OLD.IN%=-1% &
	\ STATUS.MATCH%=1024% &
	\ DIR.FILES,GRAND.FILES=0. &
	\ IN.CH%=1%+SWAP%(5%) &
	\ OUT.CH%=2%+SWAP%(5%) &
	\ IN.DIR%=1%+SWAP%(6%) &
	\ OUT.DIR%=2%+SWAP%(7%) &
		! DEFINE "CHANNEL NUMBERS" USED FOR FOREIGN BUFFERING: &
		!   NAME     CHANNEL  BUFFER CHANNEL &
		!  IN.CH%	1	5 &
		!  OUT.CH%	2	5 &
		!  IN.DIR%	1	6 &
		!  OUT.DIR%	2	7 &

1100	! &
	! &
	! &
	!	P R O C E S S    C O M M A N D &
	! &
	! &
	! &
	IF ENTRY.TYP%=0% THEN &
		DUMMY$=SYS(CHR$(0%)) &
	\	PRINT FNRET$;"FIT>"; &
	\	OPEN KB$ AS FILE 3% &
	\	INPUT LINE #3%, COMM.LINE$ &
	\	COMM.LINE$=CVT$$(COMM.LINE$,254%) &
	\	GOTO 1100 UNLESS LEN(COMM.LINE$) &
		! RUN ENTRY, SO GET USER'S COMMAND LINE. &
		! CANCEL CTRL/O EFFECT. &
		! REPROMPT UNTIL HE GIVES US SOMETHING. &

1110	SAVP%,SAVN%=0% &
	\ EQ%=INSTR(1%,COMM.LINE$,"=") &
	\ T2$=RIGHT(COMM.LINE$,EQ%+1%) &
	\ IN.STA%=FNSCAN%(T2$,1%) &
	\ DECTAPE%=(IN.STA%=4%) &
	\ GOTO 9000 IF LEN(ERR.MSG$) &
	\ IN.SW%=SW% &
	\ ERR.MSG$="?No input file" &
		UNLESS (FW2% AND 4233%) OR (IN.SW% AND 1632%) &
	\ ERR.MSG$="?Filename and type needed for /DE" &
		IF (FW2% AND 9%)<>9% AND (IN.SW% AND 128%) &
	\ T2$=LEFT(COMM.LINE$,EQ%-1%) &
	\ T2$=KB$ UNLESS EQ% &
	\ OUT.STA%=FNSCAN%(T2$,2%) &
	\ GOTO 9000 IF LEN(ERR.MSG$) &
	\ OUT.SW%=SW% &
	\ ERR.MSG$="?Illegal wildcards for output - "+T2$ &
		IF (FW2% AND 4%) OR (FW2% AND 64%) &
		OR ((FW2% AND 256%)*2% XOR (FW2% AND 512%)) &
	\ ERR.MSG$="?Operation does not take output spec" &
		IF EQ% AND (IN.SW% AND 224%)<>0% &
	\ ERR.MSG$="?/ZE must be specified with /N" &
		IF (IN.SW% AND 256%) AND (IN.SW% AND 64%)=0% &
	\ GOTO 9000 IF LEN(ERR.MSG$) &
	\ SKIP.BAD%=((IN.SW% AND 552%) OR (OUT.SW% AND 8%))=8% &
	\ IF (IN.SW% AND 1024%) THEN &
		COMM.LINE$="HELP$:FIT.HLP" &
	\	GOTO 1110 &
		! PARSE COMMAND LINE. &
		! MAKE SURE NOTHING ILLEGAL WAS REQUESTED. &
		! GO REPORT ERROR IF THERE IS ONE. &
		! IF HE WANTS HELP, SET UP COMMAND STRING TO &
		! PRINT THE HELP FILE ON THE TERMINAL AND GO DO IT. &

1120	IN.DEV%=FNOPEN.DEV%(1%) &
	\ GOTO 9000 IF LEN(ERR.MSG$) &
	\ RSTS%=(IN.DEV%=4%) &
	\ RSTS.EXTRA%=(RSTS.EXTRA% OR RSTS%) &
	\ RT11%=(IN.DEV%=8%) &
	\ DOS%=(IN.DEV% AND 16%)<>0% &
	\ IN.CLU.2%=(CLU%=2% AND NOT RSTS%) &
	\ OUT.DEV%=FNOPEN.DEV%(2%) &
	\ GOTO 9000 IF LEN(ERR.MSG$) &
	\ OUT.CLU.2%=(CLU%=2% AND OUT.DEV%<>4%) &
	\ ERR.MSG$="?Can't output to DOS" IF OUT.DEV%=16% &
	\ ERR.MSG$="?Illegal input for RT11 output" &
		IF DOS% AND OUT.DEV%=8% &
	\ GOTO 9000 IF LEN(ERR.MSG$) &
		! FIND OUT WHAT TYPE OF DEVICES THEY ARE AND SEE IF &
		! WE HAVE ANY ILLEGAL COMBINATIONS. &
		! &
	\ T0$=FNBUILD$(1%,768%) &
	\ CHANGE LEFT(T0$,6%)+RIGHT(T0$,8%) TO MATCH% &
	\ MATCH.PROJ%=Z%(6%) &
	\ MATCH.PROG%=Z%(5%) &
	\ WILD%=INSTR(1%,T0$,"?")<>0% &
		OR MATCH.PROJ%=255% &
		OR MATCH.PROG%=255% &
	\ FSS.SCAN$(0%),FSS.SCAN$(1%)= &
		SYS(CHR.6$+CHR$(-10%)+"_"+FNBUILD$(1%,-1%)) &
		! SET UP MATCH%() WITH THE ASCII VALUES OF &
		! FILENAME AND TYPE TO MATCH. &
		! LOAD MATCH.PROJ% AND MATCH.PROG% WITH PPN TO MATCH. &
		! &
	\ T0%=IN.SW% OR IN.DEV% &
	\ CH%=1% &
	\ IF (T0% AND 30688%) THEN &
		T1%=0% &
	\	T1%=1% IF T0%=41% &
	\	T1%=2% IF (T0% AND 52%)>32% &
	\	T1%=3% IF (T0% AND 137%)=137% &
	\	T1%=4% IF T0% AND 64% &
	\	T1%=5% IF T0%=521% &
	\	ERR.MSG$="?Illegal operation for device" UNLESS T1% &
	\	ON T1% GOSUB	12500,	13500,	12300, &
				12400,	12800	IF T1% &
	\	GOTO 9000 &
		! SET UP FOR WILDCARDS. &
		! IF SPECIAL SWITCHES ARE PRESENT, THIS SHOULD BE &
		! A SPECIAL (OTHER THAN COPY) OPERATION. &
		! IF WE DO NOT RECOGNIZE THE OPERATION, ERROR. ELSE: &
		!  12500 - LIST AN RT11 DEVICE DIRECTORY. &
		!  13500 - LIST A DOS DEVICE OR RSTS/E DISK DIRECTORY. &
		!  12300 - DELETE AN RT11 FILE. &
		!  12400 - ZERO AN RT11 DEVICE. &
		!  12800 - SQUEEZE AN RT11 DEVICE. &

1200	! &
	! &
	! &
	!	S E T    U P    A N D    D O    T R A N S F E R &
	! &
	! &
	! &
	CH%=1% &
	\ GOSUB 14400 IF RSTS% AND NOT FOUND% &
	\ GOSUB 12100 IF RT11% &
	\ GOSUB 13100 IF DOS% AND NOT FOUND% &
	\ IF (PPN% OR (FOUND% AND RT11%))=0% THEN &
		GOTO 9000 UNLESS NONE% &
	\	T0$=FNE$(5%) &
	\	T0$=NO.MATCH$ IF WILD% &
	\	ERR.MSG$=T0$+DASH$+FNBUILD$(1%,32767% AND NOT 2048%) &
	\	GOTO 9000 &
		! GET PPN (RSTS OR DOS) OR FILE (RT11). &
		! QUIT WILDCARD LOOP IF NO MATCH. &
		! RETURN ERROR IF NO FILE(S) FOUND. &

1220	GOSUB 14500 IF RSTS% &
	\ GOSUB 13200 IF DOS% &
	\ GOTO 1200 UNLESS FOUND% &
	\ NONE%=0% &
	\ T0%=FNSUB%(1%)+FNSUB%(2%) &
	\ GOSUB 14100 IF RSTS% &
	\ GOTO 9000 IF LEN(ERR.MSG$) &
		! GET NEXT DOS OR RSTS FILE. &
		! IF NO MORE WITH THIS PPN, GO GET NEXT PPN. &
		! &
	\ CH%=2% &
	\ FOREIGN.BUFF%=(OUT.STA%<>4% OR OUT.DEV%=8%) &
		AND NOT DOS.LINKED% &
		! &
		! DETERMINE WHETHER WE WILL USE FOREIGN BUFFERING; &
		! WE WILL UNLESS WE ARE DEALING WITH A DOS LINKED FILE &
		! OR OUTPUTTING TO DOS DECTAPE. &
		! &
	\ GOSUB 12600 IF OUT.DEV%=8% &
	\ GOSUB 14200 IF OUT.DEV%<>8% &
	\ GOTO 9000 IF LEN(ERR.MSG$) &
	\ GOSUB 11000 &
	\ GOTO 9000 IF LEN(ERR.MSG$) &
	\ GOSUB 12700 IF OUT.DEV%=8% &
	\ GOSUB 14300 IF OUT.DEV%=4% &
	\ CLOSE 2% IF (OUT.DEV% AND 1%) &
	\ PRINT FNRET$;"[File ";FNBUILD$(3%,-1%); &
		" copied to ";FNBUILD$(4%,-1%);"]" IF (IN.SW% AND 2048%) &
	\ GOTO 1200 IF WILD% AND RT11% &
	\ GOTO 1220 IF WILD% &
	\ GOTO 9000 &
		! OPEN THE RSTS/E OR RT11 OUTPUT FILE. &
		! GO DO THE TRANSFER. &
		! GO UPDATE THE DIRECTORY INFO IF RT11 OUTPUT FILE. &
		! GO SEE ABOUT COMPILED FILES IF RSTS/E OUTPUT FILE. &
		! GO TO COMPLETION ROUTINE. &

9000	! &
	! &
	! &
	!	E X I T    O R    R E P R O M P T &
	! &
	! &
	! &
	CLOSE -1%, -2% IF LEN(ERR.MSG$) OR ERR=28% &
	\ CLOSE T0% FOR T0%=1% TO 12% &
	\ PRINT FNRET$;ERR.MSG$ IF LEN(ERR.MSG$) &
	\ ERR.MSG$="" &
	\ IF ENTRY.TYP% THEN &
		GOTO 32767 &
	  ELSE	GOTO 1060 &
		! RESET THE INPUT AND OUTPUT DEVICES IF ERROR. &
		! CLOSE THE INPUT AND OUTPUT DEVICES. &
		! PRINT AN ERROR MESSAGE IF THERE IS ONE. &
		! IF NOT A RUN ENTRY, EXIT. &
		! IF A RUN ENTRY, GO BACK TO INITIALIZE AND REPROMPT. &

11000	! &
	! &
	! &
	!	T R A N S F E R    A    F I L E &
	! &
	! &
	! &
	! THIS ROUTINE DOES THE ACTUAL FILE TRANSFER. &
	! A LARGE BUFFER SIZE IS USED WHERE POSSIBLE. &
	! WHERE POSSIBLE, FOREIGN BUFFERING IS USED TO AVOID MOVING STRINGS. &
	! &
	OUT.REC%=(OUT.DEV%=8% OR (IN.SW% AND 512%)<>0%) &
	\ IN.START=FNFLOAT(IN.START%) &
	\ OUT.START=FNFLOAT(OUT.START%) &
	\ T1=FILE.LEN-1% &
	\ BUF.BLOCKS%=4% &
	\ BUF.BLOCKS%=FILE.LEN% IF FILE.LEN<BUF.BLOCKS% &
	\ BUF.BLOCKS%=1% IF DOS.LINKED% &
		OR DECTAPE% OR OUT.STA%=4% OR OUT.STA%=14% &
		OR IN.CLU.2% OR OUT.CLU.2% &
	\ BUF.SIZE%=512%*BUF.BLOCKS% &
	\ T0%=FNBUFF%(5%,BUF.SIZE%) &
	\ FIELD #5%, BUF.SIZE% AS DATA.BUFF$ &
	\ IF DOS.LINKED% THEN &
		FIELD #5%, 2% AS LINK$, 510% AS DATA.BUFF$ &
	\	LSET LINK$=CVT%$(SWAP%(IN.START%)) &
		! &
		! REC.MASK% FLAGS WHEATHER WE SHOULD USE OUTPUT RECORD &
		!	NO'S (ONLY FOR RT11 OUTPUT FILES.) &
		! USE A LARGE BUFFER SIZE UNLESS DOS LINKED INPUT OR WE ARE &
		!	DEALING WITH DECTAPE OR MAGTAPE OR RP02 DISK. &
		! GET THE BUFFER ON CHANNEL 5. &
		! FIELD THE BUFFER IN CASE WE NEED IT. (DECTAPE, RP02, ...) &

11010	FOR T0=0. TO T1 STEP BUF.BLOCKS% &
	\	IF FILE.LEN-T0<BUF.BLOCKS% THEN &
			T0%=512%*(FILE.LEN-T0) &
	\		T2%=FNBUFF%(5%,T0%) &
	\		FIELD #5%, T0% AS DATA.BUFF$ &
		! &
		! IF LESS THAN A BUFFER LEFT TO INPUT, ADJUST BUFFER SIZE &
		!	SO WE GET ONLY WHAT IS LEFT IN THE FILE TO TRANSFER. &

11020		IF IN.CLU.2% THEN &
			T0%=FNGET.CLU.2%(T0+IN.START) &
		ELSE	IF NOT DOS.LINKED% THEN &
				GET #IN.CH%, BLOCK T0+IN.START &
			ELSE	GET #IN.CH%, RECORD SWAP%(CVT$%(LINK$)) &
			\	IF T0=T1 THEN &
				    T3%=((FILE.LEN%-1%)*2% AND 511%) &
			\	    FIELD #5%, 2% AS LINK$, &
					T3% AS DATA.BUFF$ &
					IF (RIGHT(DATA.BUFF$,T3%+1%)= &
					    STRING$(510%-T3%,0%)) AND T3% &
		! GET THE BLOCK FROM THE INPUT FILE. &
		! IF IT IS NOT DOS LINKED, GET NEXT SEQUENTIAL BLOCK. &
		! IF DOS LINKED, GET BY LAST LINK. &
		! IF LAST DOS LINKED BLOCK, DO FUNNY STUFF: &
		!	FIGURE OUT HOW MANY BYTES WE HAVE LEFT TO GO &
		!	IN THE 512-BYTE BLOCK WE ARE PRINTING OUT TO. &
		!	IF THE REST IS JUST NULLS, DISCARD IT. &
		!	(T3% IS THE NUMBER OF BYTES WE WOULD EXPECT TO BE &
		!	SIGNIFICANT IF WE COPIED THE FILE FROM A 512-BYTE &
		!	BLOCK DEVICE TO THE DOS DEVICE IN THE FIRST PLACE.) &

11030		IF FOREIGN.BUFF% THEN &
			IF OUT.REC% THEN &
				IF OUT.CLU.2% THEN &
					T0%=FNPUT.CLU.2%(OUT.CH%,T0+OUT.START) &
				ELSE	PUT #OUT.CH%, BLOCK T0+OUT.START &
			ELSE	PUT #OUT.CH% &
		ELSE	PRINT #2%, DATA.BUFF$; &
		! &
		! IF WE CAN USE FOREIGN BUFFERING, THEN PUT FROM THE BUFFER. &
		! USE RECORD NUMBER ONLY IF WE SHOULD. &
		! DO SPECIAL ROUTINE IF OUTPUT DEVICE CLUSTER SIZE = 2. &
		! IF BUFFERS ARE NOT COMPATIBLE, PRINT OUT THE DATA. &

11040	NEXT T0 &
	\ CLOSE 5% &
	\ RETURN &
		! UNTIL THE WHOLE FILE IS TRANSFERRED. &

11800	! &
	! &
	! &
	!	P R I N T    A    D I R E C T O R Y    E N T R Y &
	! &
	! &
	! &
	DIR.FILES=DIR.FILES+1% UNLESS UNUSED% &
	\ DIR.BLOCKS=DIR.BLOCKS+FILE.LEN UNLESS UNUSED% &
	\ DIR.FREE=DIR.FREE+FILE.LEN IF UNUSED% &
	\ RETURN IF UNUSED% AND FILES.ONLY% &
	\ PRINT IF CCPOS(0%) &
	\ PRINT RAD$(NAMTYP%(0%));RAD$(NAMTYP%(1%));"."; &
		RAD$(NAMTYP%(2%)); UNLESS UNUSED% &
	\ PRINT "< UNUSED >"; IF UNUSED% &
	\ PRINT FNNUMBER$(FILE.LEN%,MSB.LEN%,8%); &
		MID("C ",(DOS% AND NOT DOS.LINKED% &
			OR (USTAT% AND 16%)<>0%)+2%,1%); &
	\ PRINT "  <";FNNUMBER$(FILE.PROT%,0%,3%);">"; UNLESS RT11% &
	\ PRINT "  ";DATE$(FILE.DATE%); UNLESS UNUSED% &
	\ PRINT SPACE$(11%); IF UNUSED% &
	\ PRINT "   ";RAD$(EXTRA%(12%));RAD$(EXTRA%(13%)); &
		IF RSTS.EXTRA% AND NOT UNUSED% &
	\ PRINT SPACE$(9%); IF RSTS.EXTRA% AND UNUSED% &
	\ PRINT FNNUMBER$(IN.START%,0%,6%); UNLESS RSTS% &
		! &
		! PRINT NAME AND TYPE OR <UNUSED> IF RT11 UNUSED SPACE. &
		!	FILE LENGTH FOLLOWED BY "C" IF DOS CONTIGUOUS. &
		!	PROTECTION CODE IF DOS. &
		!	DATE OF CREATION. &
		!	STARTING BLOCK NUMBER. &
		! &
	\ IF RSTS.EXTRA% AND NO.ATTR% THEN &
		PRINT &
	\	T1%=EXTRA%(1%) AND 15% &
	\	T1%=5% IF T1%>5% &
	\	PRINT " RF:";MID("UDFFIXVARVFCSTM???",T1%*3%+1%,3%); &
	\	PRINT "=";FNNUMBER$(EXTRA%(9%),0%,0%); IF EXTRA%(9%) &
		  ! RECORD FORMAT FROM ATTRIBUTE WORD 1, BITS 0-3. &
		  !  0 - UDF	UNDEFINED &
		  !  1 - FIX	FIXED &
		  !  2 - VAR	VARIABLE &
		  !  3 - VFC	FARIABLE WITH FIXED CONTROL FIELD &
		  !  4 - STM	STREAM ASCII &
		  !  5 - ???	NOT DEFINED &
		  !   ...	NOT DEFINED &
		  ! 15 - ???	NOT DEFINED &
		  ! IF THERE IS A MAXIMUM SIZE IMPOSED, PRINT "=MAXIMUM" &
		  ! AFTER THE RECORD FORMAT. &
	&
	\	T1%=EXTRA%(1%)/16% AND 15% &
	\	T1%=3% IF T1%>3% &
	\	PRINT TAB(12%);" FO:";MID("SEQRELIDX???",T1%*3%+1%,3%); &
			TAB(22%);"USED:";FNNUMBER$(EXTRA%(6%),EXTRA%(5%),0%); &
				":";FNNUMBER$(EXTRA%(7%),0%,0%); &
			TAB(37%);" RECSI:";FNNUMBER$(EXTRA%(2%),0%,0%); &
		  ! FILE ORGANIZATION FROM ATTRIBUTE WORD 1, BITS 4-7 &
		  !  0 - SEQ	SEQUENTIAL &
		  !  1 - REL	RELATIVE &
		  !  2 - IDX	INDEXED &
		  !  3 - ???	NOT DEFINED &
		  !   ...	NOT DEFINED &
		  ! 15 - ???	NOT DEFINED &
		  ! SHOW HOW MANY BLOCKS IN USE AND HOW MANY BYTES BEING &
		  ! USED IN LAST BLOCK. &
		  ! GIVE THE RECORD SIZE, IF FIXED, OR MAXIMUM RECORD SIZE, &
		  ! IF VARIABLE. &
	&
	\	T1%=EXTRA%(1%)/256% AND 7% &
	\	T1%=3% IF T1%>4% &
	\	PRINT TAB(52%);"CC:";MID("FORIMP???PRN",T1%*3%-2%,3%); IF T1% &
		  ! SPECIAL CARRIAGE CONTROL, IF ANY, BITS 8-10 OF WORD 1. &
		  !  0 -	NO SPECIAL CC; DON'T PRINT ANYTHING. &
		  !  1 - FOR	FORTRAN &
		  !  2 - IMP	IMPLIED CR-LF AT END OF EACH RECORD &
		  !  3 - ???	NOT DEFINED &
		  !  4 - PRN	PRINT FORMAT (VAX) &
		  !  5 - ???	NOT DEFINED &
		  !  6 - ???	NOT DEFINED &
		  !  7 - ???	NOT DEFINED &
	&
	\	PRINT TAB(62%);"NOSPAN"; IF (EXTRA%(1%) AND 2048%) &
		  ! NOSPAN IF BIT 10 OF ATTRIBUTE WORD 1. &
	&
	\	PRINT &
	\	T1%=EXTRA%(8%) AND 255% &
	\	PRINT "  BK:";NUM1$(T1%); IF T1% AND T1%<>1% &
		  ! PRINT BUCKED SIZE IF NOT DEFAULT OF 1 RECORD. &
	&
	\	T1%=SWAP%(EXTRA%(8%)) AND 255% &
	\	PRINT TAB(13%);"HS:";NUM1$(T1%); IF T1% AND T1%<>2% &
		  ! PRINT HEADER SIZE IF NOT DEFAULT OF 2 BYTES. &
	&
	\	T1%=EXTRA%(10%) &
	\	PRINT TAB(22%);"EX:";NUM1$(T1%); IF T1% &
		  ! PRINT TYPE QUANTITY IF NOT DEFAULT. &
		  ! ATTRIBUTES ALL PRINTED SYMBOLICALLY. &

11810	PRINT IF CCPOS(0%) &
	\ RETURN &
		  ! A DIRECTORY ENTRY HAS BEEN PRINTED. &

11850	! &
	! &
	! &
	!	P R I N T    D I R E C T O R Y    H E A D E R &
	! &
	! &
	! &
	DIR.BLOCKS,DIR.FILES=0. &
	\ IF NOT DIR.1% THEN &
		PRINT FNRET$;"Directory of ";FNBUILD$(1%,10140%); &
	\	PRINT " (DOS Format)"; IF DOS% AND NOT DECTAPE% &
	\	PRINT " (RT11 Format)"; IF RT11% AND DEFAULT%<>8% &
	\	PRINT &
	\	GRAND.BLOCKS,GRAND.FILES,DIR.FREE=0. &
	\	DIR.1%=-1% &
		! FIRST TIME THROUGH, PRINT DEVICE HEADER. &

11855	PRINT &
	\ PRINT "Name  .Typ    Size "; &
	\ PRINT "  Prot "; UNLESS RT11% &
	\ PRINT "    Date   "; &
	\ PRINT "    RTS  "; IF RSTS.EXTRA% &
	\ PRINT "   Pos"; UNLESS RSTS% &
	\ PRINT "  ";DEV$(1%);PPN$; UNLESS RT11% &
	\ PRINT &
	\ RETURN &
		! PRINT HEADER FOR DIRECTORY LISTING. &

11860	! &
	! &
	! &
	!	P R I N T    D I R E C T O R Y    T O T A L S &
	! &
	! &
	! &
	PRINT &
	\ PRINT "Total of";DIR.BLOCKS;"block";FNPLURAL$(DIR.BLOCKS); &
		" in";DIR.FILES;"file";FNPLURAL$(DIR.FILES); &
		" in ";DEV$(1%); &
	\ PRINT PPN$; UNLESS RT11% &
	\ PRINT &
	\ PRINT "Total of";DIR.FREE;"free block";FNPLURAL$(DIR.FREE); &
		" in ";DEV$(1%) IF RT11% &
		! PRINT THE SUMMARY INFORMATION. &
		! IF NOT RT11, PRINT THE UIC OR PPN. &
		! IF RT11, PRINT THE NUMBER OF FREE BLOCKS. &
	\ PRINT &
	\ GRAND.BLOCKS=GRAND.BLOCKS+DIR.BLOCKS &
	\ GRAND.FILES=GRAND.FILES+DIR.FILES &
	\ DIR.BLOCKS,DIR.FILES=0. &
	\ RETURN &

11870	! &
	! &
	! &
	!	P R I N T    G R A N D    T O T A L S &
	! &
	! &
	! &
	PRINT "Grand total of";GRAND.BLOCKS;"block";FNPLURAL$(GRAND.BLOCKS); &
		" in";GRAND.FILES;"file";FNPLURAL$(GRAND.FILES); &
		" in ";FNBUILD$(1%,9216%) &
	\ PRINT &
	\ RETURN &

12100	! &
	! &
	! &
	!	F I N D    N E X T    R T 1 1    F I L E &
	! &
	! &
	! &
	FOUND%=-1% &
	\ FILE.STATUS%,PPN%=0% &
	\ IF DIR.PTR%(CH%)<0% THEN &
		DIR.PTR%(CH%)=0% &
	\	T0%=FNBUFF%(CH%+5%,1024%) &
	\	T0%=FNGET.RT.DIR%(CH%+SWAP%(CH%+5%),DIR.SEG%(CH%)) &
	\	T0%=FNGET.WORDS%(CH%+5%,0%,5%) &
	\	DIR.LINK%(CH%)=Z%(1%) &
	\	FILE.REC%(CH%)=Z%(4%) &
	\	IF	T0%<>DIR.SIZE%(CH%) &
		OR	Z%(1%)>T0% OR Z%(1%)<0% &
		OR	Z%(3%)<>(DIR.ENT.LEN%(CH%)-7%)*2% THEN &
			FOUND%=0% &
	\		ERR.MSG$="?Directory corrupted - "+DEV$(CH%) &
	\		RETURN &
		! &
		! INITIALIZE. &
		! GET THE NEXT DIRECTORY SEGMENT IF WE NEED TO. &
		! READ IN THE VALUES FROM THE BEGINNING OF THE BLOCK. &
		! DO A CONSISTENCY CHECK AND ABORT IF NOT GOOD. &
		! EACH DIRECTORY SEGMENT CONTAINS A FIVE-WORD HEADER &
		! FOLLOWED BY FILE ENTRIES.  THE HEADER IS: &
		!     WORD	MEANING &
		!	0	NUMBER OF SEGMENTS AVAILABLE FOR ENTRIES. &
		!	1	LINK TO NEXT SEGMENT (SEGMENT NUMBER). &
		!	2	HIGHEST NUMBERED SEGMENT CURRENTLY USED &
		!		(UPDATED ONLY IN FIIST SEGMENT). &
		!	3	NUMBER OF EXTRA BYTES PER FILE ENTRY. &
		!	4	BLOCK NUMBER AT WHICH FILES DESCRIBED &
		!		IN THIS SEGMENT BEGIN. &

12110	T2%=DIR.ENT.LEN%(CH%) &
	\ T3%=20% &
	\ T3%=7% IF T2%<>20% &
	\ FOR T0%=DIR.PTR%(CH%) UNTIL (FILE.STATUS% AND 2048%) &
			OR (T0%+1%)*T2%>507% &
	\	FILE.STATUS%=FNGET.WORDS%(CH%+5%,5%+T0%*T2%,T3%) &
	\	FILE.REC%(CH%)=FILE.REC%(CH%)+Z%(4%) &
	\	GOTO 12120 IF (FILE.STATUS% AND STATUS.MATCH%) &
				AND FNMATCH%(1%) &
			OR (FILE.STATUS% AND STATUS.MATCH% AND 768%) &
	\ NEXT T0% &
	\ GOTO 12120 IF STATUS.MATCH%=2048% &
	\ DIR.PTR%(CH%)=-1% &
	\ DIR.SEG%(CH%)=DIR.LINK%(CH%) &
	\ IF DIR.SEG%(CH%) THEN &
		GOTO 12100 &
	  ELSE	FOUND%=0% &
		! SEARCH THROUGH THE REMAINING DIRECTORY ENTRIES IN THE &
		! SEGMENT UNTIL A MATCH IS FOUND. &
		! IF NO MATCH, SEE IF THERE IS ANOTHER DIRECTORY SEGMENT. &
		! IF ANOTHER SEGMENT, GO GET IT. &
		! IF END OF DIRECTORY, RETURN FOUND%=0%. &
		! EACH FILE ENTRY HAS THE FOLLOWING FORMAT: &
		!     WORD	MEANING &
		!	0	STATUS WORD. &
		!     1-2	FILENAME (RADIX-50). &
		!	3	TYPE (RADIX-50). &
		!	4	FILE LENGTH. &
		!	5	JOB#, CH# (RESERVED IN RSTS/E). &
		!	6	DATE OF CREATION (RT11 FORMAT). &
		! &
		! THE LOW BYTE OF THE STATUS WORD IS RESERVED. &
		! THE HIGH BYTE HAS THE FOLLOWING MEANINGS: &
		!  AS BYTE  AS WORD	MEANING &
		!     1       256	TENTATIVE FILE (OPENED FOR &
		!			OUTPUT AND NOT YET CLOSED). &
		!			(CONSIDERED UNUSED). &
		!     2       512	EMPTY FILE (UNUSED). &
		!     4      1024	PERMANENT ENTRY. &
		!     8      2048	LAST ENTRY IN SEGMENT &
		!			(DUMMY ENTRY). &

12120	DIR.PTR%(CH%)=T0%+1% &
	\ RETURN IF CH%=2% &
	\ NAMTYP%(T0%)=Z%(T0%+1%) FOR T0%=0% TO 2% &
	\ FILE.LEN%=Z%(4%) &
	\ FILE.LEN=FNFLOAT(FILE.LEN%) &
	\ IN.START%=FILE.REC%(1%)-FILE.LEN% &
	\ FILE.DATE%=FNRSTS.DATE%(Z%(6%)) &
	\ UNUSED%=(FILE.STATUS% AND 768%)<>0% &
	\ EXTRA%(T0%)=Z%(T0%+6%) FOR T0%=1% TO 13% &
	\ NO.ATTR%=0% &
	\ NO.ATTR%=T0% IF EXTRA%(T0%) FOR T0%=1% TO 11% &
	\ EXTRA%(13%)=0% UNLESS EXTRA%(12%) &
	\ RETURN IF	(T2%=20%) &
		AND	(EXTRA%(3%) OR EXTRA%(5%))=0% &
		AND	(NOT UNUSED%) &
	\ NO.ATTR%=0% &
	\ EXTRA%(T0%)=0% FOR T0%=1% TO 11% &
	\ EXTRA%(12%)=29631% &
	\ EXTRA%(13%)=-15936% &
	\ RETURN &
		! RETURN THE DIRECTORY INFORMATION FOR THE FILE FOUND. &
		! IF THIS IS OUTPUT, DON'T GET ALL THE INFO. &
		! FIND THE NUMBER OF ATTRIBUTES PRESENT. &
		! MAKE SURE WE HAVE A LEGAL RUN-TIME-SYSTEM NAME. &
		! DO A SANITY CHECK ON EXTRA INFO TO SEE IF IT LOOKS RSTS: &
		! THERE MUST BE 20 WORDS TOTAL IN THE DIRECTORY ENTRY, &
		! THE HIGHEST WORD OF "SIZE" AND "IN USE" MUST BE ZERO. &
		!	(PLEASE, NO LARGE FILES HERE.) &
		! IF EXTRA WORDS NOT GOOD, DEFINE ATTRIBUTES AS ALL ZERO &
		!	AND RTS NAME AS "RT11" (IN RAD-50). &

12300	! &
	! &
	! &
	!	D E L E T E    R T 1 1    F I L E ( S ) &
	! &
	! &
	! &
	STATUS.MATCH%=1024% &
	\ GOSUB 12100 &
	\ T0%=FNSUB%(1%)+FNSUB%(2%) &
	\ ERR.MSG$=FNE$(5%)+DASH$+FNBUILD$(1%,9985%) &
		UNLESS FOUND% OR FILE.COUNT% &
	\ RETURN IF NOT FOUND% OR LEN(ERR.MSG$) &
	\ OUT.ENT.LEN%=DIR.ENT.LEN%(1%) &
	\ DEL.OFF%=5%+(DIR.PTR%(1%)-1%)*OUT.ENT.LEN% &
	\ GOSUB 12310 &
	\ T0%=FNPUT.RT.DIR%(IN.DIR%,DIR.SEG%(1%)) &
	\ PRINT FNRET$;"[File ";FNBUILD$(3%,-1%);" deleted]" &
		IF (IN.SW% AND 2048%) &
	\ RETURN UNLESS WILD% &
	\ FILE.COUNT%=FILE.COUNT%+1% &
	\ DIR.PTR%(1%)=0% &
	\ GOTO 12300 &
		! SEARCH FOR THE FILE. &
		! REUTRN "CAN'T FIND FILE OR ACCOUNT" IF NOT FOUND. &
		! GOSUB FOLLOWING ROUTINE TO TAKE THE ENTRY OUT &
		!	OF THE BUFFER. &
		! REPLACE THE DIRECTORY BLOCK AND RETURN. &

12310	! &
	!	DELETE ENTRY AT DEL.OFF% IN BUFFER ON CHANNEL CH%+5%. &
	! &
	FREE.BLOCK%=0% &
	\ T0%=DEL.OFF%+OUT.ENT.LEN% &
	\ GOSUB 12320 UNLESS T0%>505% &
	\ T0%=DEL.OFF%-OUT.ENT.LEN% &
	\ GOSUB 12320 UNLESS T0%<0% &
	\ FIELD #CH%+5%, DEL.OFF%*2% AS B0$, 2% AS B0$, 6% AS B1$, 2% AS B1$ &
	\ LSET B0$=CVT%$(2%) &
	\ LSET B1$=CVT%$(SWAP%(SWAP%(CVT$%(B1$))+FREE.BLOCK%)) &
	\ RETURN &
		! CHECK NEXT ENTRY TO SEE IF <UNUSED>. &
		! CHECK PREVIOUS ENTRY TO SEE IF <UNUSED>. &
		! IF EITHER IS UNUSED, THE ENTRIES WILL BE COMBINED. &
		! SET THE STATUS WORD TO <UNUSED>. &
		! UPDATE THE ENTRY SIZE IN CASE IT HAS INCREASED. &
		! NOTE THAT THIS SUBROUTINE IS ALSO USED BY THE &
		!	CLOSE RT11 OUTPUT FILE ROUTINE. &

12320	! &
	!	IF ENTRY AT T0% IS UNUSED, MERGE IT WITH ENTRY AT DEL.OFF%. &
	! &
	RETURN UNLESS (FNGET.WORDS%(CH%+5%,T0%,5%) AND 768%) &
	\ FREE.BLOCK%=FREE.BLOCK%+Z%(4%) &
	\ T1%=(T0%+OUT.ENT.LEN%)*2% &
	\ FIELD #CH%+5%, T1% AS B0$, 1024%-T1% AS B0$ &
	\ B1$=SPACE$(LEN(B0$)) &
	\ LSET B1$=B0$ &
	\ FIELD #CH%+5%, T0%*2% AS B0$, 1024%-T0%*2% AS B0$ &
	\ LSET B0$=B1$ &
	\ DEL.OFF%=T0% IF T0%<DEL.OFF% &
	\ RETURN &
		! IF ENTRY AT OFFSET T0% IS UNUSED, &
		! ADD THE LENGTH OF THE ENTRY TO FREE.BLOCK% &
		! AND REMOVE THE ENTRY FROM THE BUFFER. &
		! IF THIS WAS THE ENTRY BEFORE THE ONE TO DELETE, &
		! UPDATE THE POINTER TO THE ENTRY TO DELETE. &

12400	! &
	! &
	! &
	!	Z E R O    A N    R T 1 1    D E V I C E &
	! &
	! &
	! &
	ERR.MSG$="?Device too large - "+DEV$(1%) IF DEV.SIZE(1%)>65535. &
	\ RETURN IF LEN(ERR.MSG$) &
	\ PRINT FNRET$;"Really zero ";DEV$(1%); &
	\ PRINT "/RT11"; UNLESS DEFAULT%=8% &
	\ PRINT " (Currently RSTS/E format)"; IF (IN.DEV% AND 7%) &
	\ PRINT " (Currently DOS format)"; IF IN.DEV%=16% &
	\ ERR.MSG$="%Zero Aborted" &
	\ INPUT LINE T0$ &
	\ T0$=CVT$$(T0$,254%) &
	\ RETURN UNLESS INSTR(1%,"YES",T0$)=1% AND LEN(T0$) &
	\ ERR.MSG$="" &
	\ T0%=FNBUFF%(5%,512%) &
	\ FIELD #5%, 472% AS B0$, 24% AS B1$, 16% AS B2$ &
	\ LSET B0$=CVT%$(0%) &
	\ RSTSVER$=CVT$$(FNE$(0%),2%) &
	\ LSET B1$=LEFT(RSTSVER$,INSTR(1%,RSTSVER$,".")+1%) &
	\ LSET B2$="DECRT11A" &
	\ PUT #IN.CH%, RECORD 1% UNLESS IN.CLU.2% &
	\ FIELD #5%, 512% AS DATA.BUFF$ &
	\ T0=0. &
	\ T0%=FNPUT.CLU.2%(1%,1.) IF IN.CLU.2% &
		! &
		! WRITE OUT THE RT11 "HOME BLOCK", DEVICE BLOCK 1. &
		! WRITE 0 IN WORD 1, "RSTS??" (?? REPRESENTS THE VERSION &
		! NUMBER OF THE RSTS/E MONITOR) AS VOLUME IDENTIFICATION, &
		! AND "DECRT11A" AS FORMAT TYPE. &
		! &
	\ IF N%=0% THEN &
		N%=31% &
	\	N%=16% IF DEV.SIZE(1%)<10000% AND ZE%<13% &
	\	N%=4% IF DEV.SIZE(1%)<1000% &
	\	N%=10% IF DEV.SIZE(1%)<1000% AND ZE%>=13% &
		! IF NO /N: SWITCH GIVEN, FIGURE OUT THE NUMBER &
		! OF DIRECTORY SEGMENTS WE ARE GOING TO HAVE. &

12410	T0%=FNBUFF%(5%,1024%) &
	\ FIELD #5%, 1024% AS B0$ &
	\ LSET B0$="" &
	\ Z%(T0%)=0% FOR T0%=0% TO 11% &
	\ Z%(0%)=N% &
	\ Z%(2%)=1% &
	\ Z%(3%)=ZE%*2% &
	\ Z%(4%)=6%+N%*2% &
	\ Z%(5%)=512% &
	\ Z%(9%)=FNINTEGER%(DEV.SIZE(1%)-Z%(4%)+1%) &
	\ T0%=FNPUT.WORDS%(5%,0%,12%) &
	\ FIELD #5%, 24%+ZE%*2% AS B0$, 2% AS B0$ &
	\ LSET B0$=CVT%$(8%) &
	\ T0%=FNPUT.RT.DIR%(IN.CH%,1%) &
		! &
		! WRITE OUT A SINGLE DIRECTORY ENTRY IN BLOCK 6. &
		! THE ENTRY WILL BE UNUSED AND HAVE A SIZE OF &
		! THE REST OF THE DEVICE. &
		! WRITE AN END-OF-SEGMENT MARKER. &
		! &
	\ T0%=FNBUFF%(5%,512%) &
	\ FIELD #5%, 512% AS B0$ &
	\ LSET B0$=STRING$(512%,0%) &
	\ T0%=FNPUT.CLU.2%(1%,2.) IF IN.CLU.2% &
	\ RETURN UNLESS DECTAPE% &
	\ PUT #IN.CH%, RECORD T0% FOR T0%=64% TO 67% &
	\ LSET B0$=STRING$(512%,255%) &
	\ PUT #IN.CH%, RECORD 68% &
	\ RETURN &
		! &
		! IN TU56 DECTAPE AND RP02'S, THE RT11 HOME BLOCK &
		! DOES NOT CORRESPOND WITH THE RSTS/E MFD HOME BLOCK. &
		! IN BOTH THESE CASES, WE WANT TO SCRIBBLE ON THE &
		! RSTS/E STRUCTURE SO THE DEVICE WILL NOT HAVE BOTH VALID &
		! FILE STRUCTURES ON IT.  ON OPENING EITHER OF THESE &
		! TWO DEVICES, WE FIRST LOOK FOR THE RSTS/E STRUCTURE. &
		! THEREFORE, ANY PIECE OF MEDIA SHOULD BE UNAMBIGUOUSLY &
		! RECOGNIZED BY ALL RSTS/E SOFTWARE AS HAVING THE &
		! SAME FORMAT. &
		! &
		! IF WE ARE ZEROING AN RP02, WRITE NULLS IN THE &
		! FIRST BLOCK OF THE RSTS/E MFD. &
		! &
		! IF WE ARE ZEROING A DECTAPE, ALSO ZERO THE DOS MFD &
		! AND SET ALL THE BITS IN THE MASTER BIT MAP. &

12500	! &
	! &
	! &
	!	L I S T    A N    R T 1 1    D I R E C T O R Y &
	! &
	! &
	! &
	STATUS.MATCH%=1792% &
	\ FILES.ONLY%=0% &
	\ FILES.ONLY%=-1% IF MATCH%(T0%)<>63% FOR T0%=1% TO 9% &
	\ GOSUB 12100 &
	\ IF FOUND% THEN &
		GOSUB 11850 &
	  ELSE	ERR.MSG$=NO.MATCH$+FNBUILD$(1%,-1%) &
	\	RETURN &
		! SET UP FOR DIRECTORY SEARCH. &
		! FOR A COMPLETE DIRECTORY, LIST ALL <UNUSED> ENTRIES. &
		! IF THE MATCH IS NOT "??????.???", LIST ONLY PERMANENT &
		!	ENTRIES. &
		! PRINT DIRECTORY HEADER OR ERROR MESSAGE. &

12510	WHILE FOUND% AND LEN(ERR.MSG$)=0% &
	\	GOSUB 11800 &
	\	GOSUB 12100 &
	\ NEXT &
	\ GOSUB 11860 UNLESS LEN(ERR.MSG$) &
	\ RETURN &
		! PRINT OUT THE DIRECTORY ENTRY AND GET THE NEXT, &
		! UNTIL THERE ARE NO MORE. &

12600	! &
	! &
	! &
	!	O P E N    R T 1 1    F I L E    F O R    O U T P U T &
	! &
	! &
	! &
	CH%=2% &
	\ STATUS.MATCH%=768% &
	\ CHANGE MATCH% TO T2$ &
	\ CHANGE WILD$ TO MATCH% &
	\ GOSUB 12100 &
	\ GOSUB 12100 WHILE FOUND% &
		AND (Z%(4%) EQV 32767%) < (FILE.LEN% EQV 32767%) &
	\ FREE.BLOCK%=Z%(4%) &
	\ ERR.MSG$="?Device full - "+DEV$(2%) IF MSB.LEN% OR NOT FOUND% &
	\ RETURN IF LEN(ERR.MSG$) &
	\ OUT.OFF%=5%+(DIR.PTR%(2%)-1%)*OUT.ENT.LEN% &
	\ OUT.START%=FILE.REC%(2%)-FREE.BLOCK% &
		! &
		! SEARCH THROUGH DIRECTORY UNTIL AN UNUSED SPACE &
		! LARGE ENOUGH FOR THE FILE IS FOUND.  RETURN &
		! "DEVICE FULL" ERROR IF THERE IS NONE OR IF A &
		! "LARGE FILE" (>65535 BLOCKS) WAS SPECIFIED. &
		! &
	\ STATUS.MATCH%=2048% &
	\ GOSUB 12100 &
	\ CHANGE T2$ TO MATCH% &
	\ OUT.END%=6%+(DIR.PTR%(2%)-1%)*OUT.ENT.LEN% &
	\ OUT.SEG%=DIR.SEG%(2%) &
	\ CH%=7% &
	\ IF (OUT.END%+OUT.ENT.LEN%<512%) OR (FILE.LEN%=FREE.BLOCK%) THEN &
		GOSUB 12640 &
	\	GOSUB 12650 IF FILE.LEN%<>FREE.BLOCK% &
	\	T0%=FNPUT.RT.DIR%(OUT.DIR%,OUT.SEG%) &
	\	CLOSE 7% &
	\	RETURN &
		! &
		! FIND THE END OF THIS DIRECTORY SEGMENT. &
		! RESTORE THE INPUT FILE MATCH STRING WE JUST BORROWED. &
		! WE DON'T HAVE TO SPLIT THIS SEGMENT IF: &
		!	1.  THERE IS ROOM IN IT FOR ANOTHER ENTRY. &
		! OR	2.  THE FILE EXACTLY FITS IN THE FREE ENTRY. &
		! IF THIS IS THE CASE, THEN: &
		!	CREATE THE TENTATIVE ENTRY. &
		!	CREATE THE FOLLOWING UNUSED ENTRY IF NEEDED. &
		!	REWRITE THE DIRECTORY SEGMENT. &
		!	CLOSE THE DIRECTORY CHANNEL AND RETURN. &

12610	IF DIR.USED%(2%)=DIR.SIZE%(2%) THEN &
		ERR.MSG$="?Directory overflow - "+DEV$(2%) &
	\	RETURN &
		! IF THERE ARE NO EXTRA DIRECTORY SEGMENTS, THEN &
		! RETURN THE "?DIRECTORY OVERFLOW" MESSAGE. &

12620	! &
	!	SPLIT THE DIRECTORY SEGMENT INTO TWO SEGMENTS. &
	!	    WRITE OUT THE NEW ENTRIES AND RETURN. &
	! &
	T0%=FNBUFF%(5%,1024%) &
	\ CUT%=(254%/OUT.ENT.LEN%)*OUT.ENT.LEN%+5% &
	\ T2%=FNGET.WORDS%(7%,4%,1%) &
	\ T2%=T2%+FNGET.WORDS%(7%,T0%,1%) &
		FOR T0%=9% TO CUT% STEP OUT.ENT.LEN% &
	\ Z%(0%)=DIR.SIZE%(2%) &
	\ Z%(1%)=DIR.LINK%(2%) &
	\ Z%(2%)=0% &
	\ Z%(3%)=(OUT.ENT.LEN%-7%)*2% &
	\ Z%(4%)=T2% &
	\ T0%=FNPUT.WORDS%(5%,0%,5%) &
	\ FIELD #5%, 10% AS B0$, 1014% AS B0$ &
	\ FIELD #7%, CUT%*2% AS B1$, 1024%-CUT%*2% AS B1$ &
	\ LSET B0$=B1$ &
	\ LSET B1$=CVT%$(8%) &
	\ DIR.USED%(2%)=DIR.USED%(2%)+1% &
	\ Z%(0%)=DIR.USED%(2%) &
	\ T0%=FNPUT.WORDS%(7%,1%,1%) &
	\ IF OUT.OFF%<CUT% THEN &
		OUT.END%=CUT%+1% &
	  ELSE	CH%=5% &
	\	OUT.SEG%=DIR.USED%(2%) &
	\	OUT.OFF%=OUT.OFF%-CUT%+5% &
	\	OUT.END%=OUT.END%-CUT%+5% &
		! &
		! DETERMINE WHERE SEGMENT WILL BE CUT. &
		! CALCULATE BLOCK NUMBER WHERE FILES IN THE &
		!	NEW SEGMENT WILL BEGIN. &
		! SET UP THE NEW DIRECTORY SEGMENT HEADER. &
		! MOVE THE ENTRIES INTO THE NEW SEGMENT. &
		! MAKE A NEW END-OF-SEGMENT MARKER IN THE OLD SEGMENT. &
		! UPDATE OUR POINTER TO NEW LAST DIRECTORY SEGMENT. &
		! LINK THE OLD SEGMENT TO THE NEW SEGMENT. &
		! ADJUST POINTERS AS TO WHETHER THE OUTPUT FILE TO OPEN &
		!	WILL BE IN THE NEW OR OLD SEGMENTS. &

12630	GOSUB 12640 &
	\ GOSUB 12650 &
	\ CH%=2% &
	\ T0%=FNPUT.RT.DIR%(OUT.CH%,DIR.USED%(2%)) &
	\ T0%=FNGET.RT.DIR%(OUT.CH%,1%) UNLESS DIR.SEG%(2%)=1% &
	\ Z%(0%)=DIR.USED%(2%) &
	\ T0%=5% &
	\ T0%=7% IF DIR.SEG%(2%)=1% &
	\ T0%=FNPUT.WORDS%(T0%,2%,1%) &
	\ T0%=FNPUT.RT.DIR%(OUT.CH%,1%) UNLESS DIR.SEG%(2%)=1% &
	\ T0%=FNPUT.RT.DIR%(OUT.DIR%,DIR.SEG%(2%)) &
	\ CLOSE 7% &
	\ RETURN &
		! GO SET UP THE ENTRIES IN BUFFER ON CHANNEL CH%. &
		! WRITE THE NEW DIRECTORY SEGMENT. &
		! UPDATE THE "LAST USED" POINTER IN SEGMENT 1. &
		! UPDATE THE OLD DIRECTORY SEGMENT. &
		! THE WORST THAT COULD HAPPEN WITH A CTRL/C IN THE &
		! WRONG PLACE HERE IS THAT THE NEW DIRECTORY SEGMENT &
		! COULD BE LISTED IN SEGMENT 1 AS BEING USED, BUT &
		! NOT BE IN THE LINKED LIST.  HENCE IT WOULD BECOME &
		! "DEAD SPACE" UNTIL A FIT SQUEZE OPERATION. &
		! IF OLD SEGMENT IS SEGMENT 1, NO PROBLEM. &
		! CLOSE THE DIRECTORY CHANNEL AND RETURN. &

12640	! &
	!	CREATE THE ENTRY IN BUFFER ON CHANNEL CH%. &
	! &
	FIELD #CH%, OUT.OFF%*2% AS B0$, OUT.ENT.LEN%*2% AS B0$ &
	\ LSET B0$="" &
	\ CHANGE FSS.SCAN$(4%) TO Z% &
	\ Z%(T0%)=FNFROM.Z%(T0%*2%+5%) FOR T0%=1% TO 3% &
	\ Z%(T0%)=0% FOR T0%=4% TO 19% &
	\ Z%(0%)=256% &
	\ Z%(4%)=FILE.LEN% &
	\ Z%(6%)=FNRT11.DATE%(FILE.DATE%) &
	\ Z%(T0%)=EXTRA%(T0%-6%) FOR T0%=7% TO 19% &
	\ T0%=7% &
	\ T0%=20% IF OUT.ENT.LEN%=20% &
	\ T0%=FNPUT.WORDS%(CH%,OUT.OFF%,T0%) &
	\ RETURN &
		! CREATE THE TENTATIVE ENTRY FOR THE FILE. &
		! CLEAR IT FIRST BY FILLING IT WITH SPACES. &
		! FILL IN THE APPROPRIATE INFORMATION. &
		! INCLUDE ATTRIBUTES AND RUN-TIME SYSTEM IF &
		! THE DIRECTORY ENTRY LENGTH IS RIGHT. &

12650	! &
	!	CREATE THE EMPTY ENTRY FOLLOWING THE &
	!		TENTATIVE ENTRY. &
	! &
	T0%=(OUT.OFF%+OUT.ENT.LEN%)*2% &
	\ FIELD #CH%, T0% AS B0$, OUT.END%*2%-T0% AS B0$ &
	\ B1$=SPACE$(LEN(B0$)) &
	\ LSET B1$=B0$ &
	\ FIELD #CH%, T0% AS B0$, OUT.ENT.LEN%*2% AS B2$, LEN(B1$) AS B3$ &
	\ LSET B3$=B1$ &
	\ LSET B2$="" &
		! &
		! MOVE THE DIRECTORY ENTRIES IN THE CURRENT SEGMENT &
		! SO THAT SPACE FOR A NEW ENTRY IS CREATED FOLLOWING &
		! THE TENTATIVE ENTRY.  CLEAR OUT THE NEW ENTRY BY &
		! INSERTING SPACES IN IT. &
		! &
	\ Z%(0%)=512% &
	\ Z%(T0%)=0% FOR T0%=1% TO 6% &
	\ Z%(4%)=FREE.BLOCK%-FILE.LEN% &
	\ T0%=FNPUT.WORDS%(CH%,OUT.OFF%+OUT.ENT.LEN%,7%) &
	\ RETURN &
		! &
		! CREATE THE EMPTY ENTRY THAT FOLLOWS THE &
		! TENTATIVE ENTRY. &

12700	! &
	! &
	! &
	!	C L O S E    R T 1 1    O U T P U T    F I L E &
	! &
	! &
	! &
	T0%=FNBUFF%(5%,1024%) &
	\ T0%=FNGET.RT.DIR%(OUT.CH%,OUT.SEG%) &
	\ Z%(0%)=1024% &
	\ T1%=FNPUT.WORDS%(5%,OUT.OFF%,1%) &
		! &
		! READ IN DIRECTORY SEGMENT WITH OUTPUT FILE. &
		! MARK THE ENTRY IN THE BUFFER AS PERMANENT. &
		! &
	\ DIR.SEG%(2%)=1% &
	\ DIR.PTR%(2%)=-1% &
	\ STATUS.MATCH%=1024% &
	\ CH%=2% &
	\ CHANGE MATCH% TO T2$ &
	\ T1$=FNBUILD$(4%,789%) &
	\ CHANGE LEFT(T1$,6%)+RIGHT(T1$,8%) TO MATCH% &
	\ GOSUB 12100 &
	\ CHANGE T2$ TO MATCH% &
		! &
		! SET UP TO LOOK FOR DUPLICATE ENTRY ON THE DEVICE. &
		! GO LOOK FOR IT. &
		! &
	\ CH%=0% IF DIR.SEG%(2%)=OUT.SEG% &
	\ DEL.OFF%=5%+(DIR.PTR%(2%)-1%)*OUT.ENT.LEN% &
	\ GOSUB 12310 IF FOUND% &
	\ T0%=FNPUT.RT.DIR%(OUT.CH%,OUT.SEG%) &
	\ T0%=FNPUT.RT.DIR%(OUT.DIR%,DIR.SEG%(2%)) IF FOUND% AND CH% &
	\ DIR.SEG%(2%)=1% &
	\ DIR.PTR%(2%)=-1% &
	\ RETURN &
		! IF DUPLICATE ENTRY, GO DELETE IT FROM BUFFER. &
		! DELETE FROM CH 5 BUFFER IF SAME SEGMENT AS NEW FILE. &
		! WRITE OUT THE ONE OR TWO NEW SEGMENTS. &
		! RESET THE POINTERS TO POINT TO THE BEGINNING OF &
		! THE DEVICE IN CASE WE ARE IN A WILDCARD SEQUENCE. &

12800	! &
	! &
	! &
	!	S Q U E E Z E    A N    R T 1 1    D E V I C E &
	! &
	! &
	! &
	CHANGE "??????BAD" TO MATCH% &
	\ STATUS.MATCH%=1024% &
	\ GOSUB 12100 IF (IN.SW% AND 8%) &
	\ ERR.MSG$="?Device has .BAD file(s) - "+DEV$(1%) IF FOUND% &
	\ RETURN IF FOUND% &
	\ PRINT FNRET$;"Really squeeze ";DEV$(1%); &
	\ ERR.MSG$="%Squeeze aborted" &
	\ INPUT LINE T0$ &
	\ T0$=CVT$$(T0$,254%) &
	\ RETURN UNLESS INSTR(1%,"YES",T0$)=1% AND LEN(T0$) &
	\ ERR.MSG$="" &
	\ OPEN KB$ AS FILE 3%, RECORDSIZE 2%, MODE 16% &
		! &
		! IF WE ARE NOT SUPPOSED TO SQUEEZE .BAD FILES, DON'T. &
		! ASK FOR CONFIRMATION BEFORE SQUEEZING. &
		! RETURN IF NOT REALLY. &
		! PROTECT AGAINST CTRL/C'S IF WE ARE REALLY GOING TO. &
		! &
	\ T1%=FNBUFF%(5%,1024%)+FNBUFF%(7%,1024%) &
	\ FIELD #5%, 2% AS B0$, 2% AS LINK$ &
	\ T0%=FNGET.RT.DIR%(IN.CH%,1%) &
	\ OUT.START%=FNGET.WORDS%(5%,4%,1%) &
	\ OUT.SEG%,DIR.SEG%(1%)=1% &
	\ DIR.PTR%(1%)=-1% &
	\ CHANGED%=0% &
	\ CHANGE WILD$ TO MATCH% &
	\ STATUS.MATCH%=1792% &
	\ Z%(T0%)=T0% FOR T0%=1% TO 31% &
		! &
		! INITIALIZE FOR THE SQUEEZE OPERATION. &
		! &

12810	! &
	!	REORDER THE SEGMENTS IN THE DIRECTORY SO THAT &
	!	ALL THE LINKS ARE SEQUENTIAL. &
	! &
	LINK%=SWAP%(CVT$%(LINK$)) &
	\ GOTO 12830 UNLESS LINK% &
	\ OUT.SEG%=OUT.SEG%+1% &
	\ LSET LINK$=CVT%$(SWAP%(OUT.SEG%)) &
	\ T0%=FNPUT.RT.DIR%(IN.CH%,OUT.SEG%-1%) &
		IF CHANGED% OR LINK%<>OUT.SEG% &
	\ RETURN IF LEN(ERR.MSG$) &
	\ CHANGED%=0% &
	\ IF Z%(LINK%)=OUT.SEG% THEN &
		T0%=FNGET.RT.DIR%(IN.CH%,OUT.SEG%) &
	\	GOTO 12810 &
		! &
		! GET THE LINK FROM THE SEGMENT. &
		! REWRITE THE SEGMENT IF THE LINK NEEDS UPDATING &
		! OR IF WE HAVE SHUFFLED IN THIS SEGMENT FROM ELSEWHERE. &
		! IF THE NEXT LOGICAL SEGMENT IS THE NEXT PHYSICAL SEGMENT &
		! THEN READ IT IN AND ITERATE.  IF NOT, WE WILL HAVE TO &
		! DO SOME SHUFFLING. &

12820	T0%=FNGET.RT.DIR%(IN.CH%,Z%(LINK%)) &
	\ T0%=FNGET.RT.DIR%(IN.DIR%,OUT.SEG%) &
	\ RETURN IF LEN(ERR.MSG$) &
	\ T0%=FNPUT.RT.DIR%(IN.DIR%,Z%(LINK%)) &
	\ T0%=1% &
	\ T0%=T0%+1% UNTIL Z%(T0%)=OUT.SEG% &
	\ Z%(T0%)=Z%(LINK%) &
	\ Z%(LINK%)=0% &
	\ CHANGED%=-1% &
	\ GOTO 12810 &
		! &
		! DO THE SHUFFLE. &
		! READ IN THE NEXT LOGICAL SEGMENT. &
		! SHUFFLE THE NEXT PHYSICAL SEGMENT TO WHERE WE JUST &
		! GOT THE NEXT LOGICAL SEGMENT, AND FLAG THAT IT IS THERE. &
		! FLAG THAT WE HAVE TO WRITE THIS NEXT SEGMENT WHEN &
		! WE'RE THROUGH WITH IT. &

12830	! &
	!	NOW SQUEEZE THE DIRECTORY INFO AND THE DATA. &
	!	CREATE OUTPUT DIRECTORY ON CHANNEL 7 BUFFER. &
	! &
	OUT.CH%=IN.CH% &
	\ OUT.ENT.LEN%=DIR.ENT.LEN%(1%) &
	\ RSTS.EXTRA%=(OUT.ENT.LEN%=20%) &
	\ T0%=FNGET.WORDS%(6%,0%,4%) &
	\ FREE.BLOCK%,LAST.LEN%,OUT.SEG%,Z%(2%)=0% &
	\ T0%=FNPUT.WORDS%(7%,0%,4%) &
	\ OUT.OFF%=5% &
	\ FOREIGN.BUFF%,DIR.PTR%(1%)=-1% &
	\ GOSUB 12890 &
		! &
		! INITIALIZE FOR THE MAIN SQUEEZE OPERATION. &
		! SET UP A BUFFER ON CHANNEL 7 WITH A DIRECTORY &
		! HEADER (WITH "LAST SEGMENT IN USE" NOT SET YET). &

12840	GOSUB 12100 &
	\ RETURN IF LEN(ERR.MSG$) &
	\ GOTO 12860 UNLESS FOUND% &
	\ IF UNUSED% THEN &
		FREE.BLOCK%=FREE.BLOCK%+FILE.LEN% &
	\	GOTO 12840 &
		! &
		! GET THE NEXT DIRECTORY ENTRY. &
		! IF THERE ARE NO MORE, GO FINISH UP. &
		! IF UNUSED, SIMPLY UPDATE OUR FREE BLOCK COUNT. &

12850	GOSUB 12880 &
	\ RETURN IF LEN(ERR.MSG$) &
	\ GOSUB 11000 UNLESS IN.START%=OUT.START% &
	\ GOTO 12840 &
		! &
		! GO CREATE THE OUTPUT DIRECTORY ENTRY. &
		! GO MAKE THE TRANSFER UNLESS ALREADY IN PLACE. &

12860	! &
	!	CLEAN UP; EXIT SQUEEZE OPERATION. &
	! &
	Z%(T0%)=0% FOR T0%=1% TO 6% &
	\ Z%(0%)=512% &
	\ Z%(4%)=FREE.BLOCK% &
	\ GOSUB 12880 IF FREE.BLOCK% &
		! &
		! CREATE AN UNUSED ENTRY FOR THE END OF THE DEVICE &
		! (IF THERE IS ANY SPACE LEFT), POINTING TO ALL &
		! THE FREE SPACE.  WRITE THE LAST SEGMENT. &
		! &
	\ LINK%=0% &
	\ GOSUB 12890 &
		! &
		! PUT A ZERO LINK IN THE LAST SEGMENT. &
		! GO WRITE THE LAST SEGMENT. &
		! &
	\ T0%=FNGET.RT.DIR%(IN.DIR%,1%) &
	\ Z%(0%)=OUT.SEG%-1% &
	\ T0%=FNPUT.WORDS%(6%,2%,1%) &
	\ T0%=FNPUT.RT.DIR%(IN.DIR%,1%) &
	\ CLOSE 3% &
	\ RETURN &
		! SET THE POINTER IN THE FIRST SEGMENT TO POINT TO &
		! THE LAST SEGMENT IN USE. &
		! GIVE THE POOR USER BACK HIS TERMINAL. &
		! RETURN FROM SQUEEZE OPERATION. &

12880	! &
	!	CREATE A NEW DIRECTORY ENTRY. &
	! &
	GOSUB 12890 IF OUT.OFF%+OUT.ENT.LEN%>512% &
	\ T0%=20% &
	\ T0%=7% UNLESS RSTS.EXTRA% &
	\ T0%=FNPUT.WORDS%(7%,OUT.OFF%,T0%) &
	\ OUT.START%=OUT.START%+LAST.LEN% &
	\ OUT.OFF%=OUT.OFF%+OUT.ENT.LEN% &
	\ LAST.LEN%=FILE.LEN% &
	\ RETURN &
		! PUT THE NEW ENTRY INTO THE BUFFER. &
		! UPDATE OUT.START% TO SHOW WHERE THIS ENTRY BEGINS. &
		! REMEMBER THIS ENTRY'S LENGTH SO WE KNOW WHERE &
		! THE NEXT ENTRY STARTS. &

12890	! &
	!	WRITE OUT THE OUTPUT DIRECTORY SEGMENT &
	!	AND INITIALIZE FOR A NEW ONE. &
	! &
	FIELD #7%, 2% AS B0$, 2% AS B1$, OUT.OFF%*2%-4% AS B0$, 2% AS B0$ &
	\ LSET B1$=CVT%$(SWAP%(LINK%)) &
	\ LSET B0$=CVT%$(8%) &
	\ T0%=FNPUT.RT.DIR%(1%+SWAP%(7%),OUT.SEG%) IF OUT.SEG% &
	\ OUT.SEG%=OUT.SEG%+1% &
	\ LINK%=OUT.SEG%+1% &
	\ FIELD #7%, 8% AS B0$, 2% AS B2$, 1014% AS B0$ &
	\ LSET B2$=CVT%$(SWAP%(OUT.START%+LAST.LEN%)) &
	\ LSET B0$="" &
	\ OUT.OFF%=5% &
	\ RETURN &
		! &
		! PUT AN END-OF-SEGMENT MARKER ON THE CURRENT SEGMENT. &
		! WRITE OUT THE CURRENT SEGMENT (UNLESS WE ARE JUST STARTING). &
		! SET UP THE NEW SEGMENT TO POINT TO THE FOLLOWING ONE. &
		! FILL IN THE STARTING BLOCK NUMBER FOR THE SEGMENT. &
		! FILL SEGMENT AFTER HEADER INFO WITH SPACES. &

13100	! &
	! &
	! &
	!	F I N D    N E X T    D O S    U F D &
	! &
	! &
	! &
	IF MFD.REC% THEN &
		T0%=FNBUFF%(7%,512%) &
	\	GET #1%+SWAP%(7%), RECORD MFD.REC% &
	\	MFD.REC%,MFD.PTR%=0% &
		! IF WE NEED A NEW MFD BLOCK, GET IT. &

13110	FOR T0%=MFD.PTR% TO 62% &
	\	FIELD #7%, 2%+T0%*8% AS B0$, 1% AS B2$, 1% AS B1$, 2% AS B0$ &
	\	GOTO 13120 IF (ASCII(B1$)=MATCH.PROJ% OR MATCH.PROJ%=255%) &
			  AND (ASCII(B2$)=MATCH.PROG% OR MATCH.PROG%=255%) &
			  AND CVT$%(B0$) &
	\ NEXT T0% &
	\ MFD.REC%=FNGET.WORDS%(7%,0%,1%) &
	\ IF MFD.REC% THEN &
		GOTO 13100 &
	  ELSE	PPN%=0% &
	\	RETURN &
		! SEARCH THROUGH THE REMAINING UFD ENTRIES IN THE MFD &
		! UNTIL A MATCH IS FOUND. &
		! IF NO MATCH, SEE IF THERE IS ANOTHER MFD BLOCK. &
		! IF THERE IS ANOTHER MFD BLOCK, GO GET IT. &
		! IF END OF MFD, THEN RETURN PPN%=0%. &
		! THE FIRST WORD OF EACH MFD BLOCK IS THE BLOCK NUMBER &
		! OF THE NEXT MFD BLOCK, OR ZERO IF THIS IS THE LAST. &
		! THE REST OF THE MFD IS DIVIDED INTO 4-WORD ACCOUNT &
		! ENTRIES WITH THE FOLLOWING FORMAT: &
		!     WORD	MEANING &
		!	0	UIC (USER IDENTIFICATION CODE). &
		!	1	BLOCK # OF 1ST UFD BLOCK FOR ACCOUNT. &
		!	2	# OF WORDS PER FILE ENTRY IN UFD &
		!		(ALWAYS = 9). &
		!	3	ALWAYS ZERO. &

13120	MFD.PTR%=T0%+1% &
	\ PPN%=FNGET.WORDS%(7%,1%+T0%*4%,2%) &
	\ UFD.REC%=Z%(1%) &
	\ RETURN &
		! GET THE STARTING RECORD NUMBER OF THE UFD. &
		! GET THE UIC FOR THE ACCOUNT. &
		! POINT PAST THIS ENTRY IN THE MFD BLOCK. &

13200	! &
	! &
	! &
	!	F I N D    N E X T    D O S    F I L E &
	! &
	! &
	! &
	FOUND%=-1% &
	\ IF UFD.REC% THEN &
		T0%=FNBUFF%(6%,512%) &
	\	GET #IN.DIR%, RECORD UFD.REC% &
	\	UFD.REC%,UFD.PTR%=0% &
		! INITIALIZE THE "FOUND" POINTER. &
		! IF WE NEED A NEW UFD BLOCK, GET IT. &

13210	FOR T0%=UFD.PTR% TO 27% &
	\	T1%=FNGET.WORDS%(6%,9%*T0%+1%,9%) &
	\	GOTO 13220 IF FNMATCH%(0%) AND T1% &
	\ NEXT T0% &
	\ UFD.REC%=FNGET.WORDS%(6%,0%,1%) &
	\ IF UFD.REC% THEN &
		GOTO 13200 &
	  ELSE	FOUND%=0% &
		! LOOK THROUGH THIS UFD BLOCK UNTIL WE FIND A MATCH. &
		! IF WE DON'T THEN GET THE NEXT UFD BLOCK. &
		! IF THERE IS ANOTHER, GO GET IT. &
		! IF THIS IS THE LAST UFD BLOCK, RETURN FOUND%=0%. &
		! THE FIRST WORD IN EACH UFD BLOCK IS A POINTER TO THE &
		! NEXT UFD BLOCK, OR ZERO IF THIS IS THE LAST. &
		! THE REST OF THE UFD BLOCK IS DIVIDED INTO 9-WORD FILE &
		! ENTRIES WITH FORMAT AS FOLLOWS: &
		!     WORD	MEANING &
		!     0-1	FILENAME (RADIX-50). &
		!	2	TYPE (RADIX-50). &
		!	3	DATE (SEE BELOW). &
		!	4	LOCK AND USAGE COUNT (NOT USED HERE). &
		!	5	BLOCK # OF FIRST BLOCK OF THE FILE. &
		!	6	LENGTH OF FILE IN BLOCKS. &
		!	7	BLOCK # OF LAST BLOCK OF THE FILE. &
		!	8	HIGH BYTE - USED WORD COUNT IN LAST BLOCK. &
		!		LOW BYTE - PROTECTION CODE. &
		! THE SIGN BIT OF WORD 3 IS SET TO MARK A CONTIGUOUS FILE, &
		! ZERO TO MARK A LINKED FILE.  THE OTHER 15 BITS OF WORD &
		! 3 DESCRIBE THE DATE OF CREATION (SAME FORMAT AS RSTS/E). &
		! &
		! THE HIGH ORDER BYTE OF WORD 8 IS ZERO TO INDICATE THAT &
		! ALL BYTES IN THE LAST BLOCK HAVE SIGNIFICANT DATA. &
		! IF NONZERO, THIS BYTE TELLS HOW MANY WORDS IN THE LAST &
		! BLOCK CONTAIN MEANINGFUL DATA. &

13220	UFD.PTR%=T0%+1% &
	\ NAMTYP%(T0%)=Z%(T0%) FOR T0%=0% TO 2% &
	\ FILE.DATE%=(Z%(3%) AND 32767%) &
	\ IN.START%=Z%(5%) &
	\ FILE.LEN%=Z%(6%) &
	\ FILE.LEN=FNFLOAT(FILE.LEN%) &
	\ FILE.PROT%=Z%(8%) AND 255% &
	\ DOS.LINKED%=(Z%(3%)>=0%) &
	\ NO.ATTR%=0% &
	\ EXTRA%(T0%)=0% FOR T0%=1% TO 13% &
	\ EXTRA%(12%)=7019% &
	\ RETURN &
		! NEXT DOS FILE FOUND. &
		! RETURN ATTRIBUTES AS ALL ZERO, RTS NAME AS "DOS". &

13500	! &
	! &
	! &
	!	L I S T    D O S    O R    R S T S / E    D I R E C T O R Y &
	! &
	! &
	! &
	GOSUB 13100 IF DOS% &
	\ GOSUB 14400 IF RSTS% &
	\ WHILE PPN% AND LEN(ERR.MSG$)=0% &
	\	PPN$="["+NUM1$(SWAP%(PPN%) AND 255%)+"," &
			+NUM1$(PPN% AND 255%)+"]" &
	\	GOSUB 13200 IF DOS% &
	\	GOSUB 14500 IF RSTS% &
	\	GOSUB 11850 IF FOUND% &
	\	UNTIL LEN(ERR.MSG$) OR NOT FOUND% &
	\		GOSUB 11800 &
	\		GOSUB 13200 IF DOS% &
	\		GOSUB 14500 IF RSTS% &
	\	NEXT &
	\	GOSUB 11860 UNLESS LEN(ERR.MSG$) OR DIR.FILES=0. &
	\	GOSUB 13100 IF DOS% &
	\	GOSUB 14400 IF RSTS% &
	\ NEXT &
	\ ERR.MSG$=NO.MATCH$+FNBUILD$(1%,-1%) IF GRAND.FILES=0. &
	\ GOSUB 11870 &
	    UNLESS LEN(ERR.MSG$) OR (MATCH.PROJ%<>255% AND MATCH.PROG%<>255%) &
	\ RETURN &
		! LOOK UP EACH UIC/PPN.  FOR EACH UIC/PPN, LIST THE FILES. &
		! PRINT OUT THE GRAND TOTALS IF MORE THAN ONE UIC/PPN. &
		! RETURN. &

14100	! &
	! &
	! &
	!	O P E N    R S T S    F I L E    F O R    I N P U T &
	! &
	! &
	! &
	OPEN "_"+FNBUILD$(3%,9985%) FOR INPUT AS FILE 1%, &
		RECORDSIZE (2% EQV 32767%) &
	\ NAMTYP%(T0%)=FNFROM.Z%(T0%*2%+7%) FOR T0%=0% TO 2% &
	\ CHANGE SYS(CHR$(12%)) TO Z% &
	\ FILE.LEN%=FNFROM.Z%(13%) &
	\ MSB.LEN%=Z%(4%) &
	\ FILE.LEN=FNFLOAT(FILE.LEN%)+65536.*MSB.LEN% &
	\ FILE.CLU%=Z%(21%) &
	\ FILE.CLU%=256% UNLESS FILE.CLU% &
	\ FILE.PROT%=Z%(22%) &
	\ CHANGE SYS(CHR.6$+CHR$(-26%)+CHR$(1%)+CHR$(0%)) TO Z% &
	\ EXTRA%(T0%)=FNFROM.Z%(2%*T0%+3%) FOR T0%=1% TO 13% &
	\ NO.ATTR%=0% &
	\ NO.ATTR%=T0% IF EXTRA%(T0%) FOR T0%=1% TO 11% &
	\ IN.START%=1% &
	\ FOUND%,RSTS.EXTRA%=-1% &
	\ RETURN &
		! OPEN THE FILE. &
		! GET FILE'S SIZE AND PROTECTION CODE. &
		! GET FILE'S ATTRIBUTES AND RUN-TIME SYSTEM NAME. &
		! FLAG TO START WITH THE FIRST BLOCK. &
		! SET THE "FOUND" FLAG, SAYING WE WERE SUCCESSFUL. &

14200	! &
	! &
	! &
	!	O P E N    R S T S    F I L E    F O R    O U T P U T &
	! &
	! &
	! &
	T0$=FNBUILD$(4%,-3%) &
	\ T0$=T0$+"/SI:"+NUM1$(FILE.LEN) &
		UNLESS (Z%(27%) AND 4%) OR DOS.LINKED% &
	\ T0%=FNFROM.Z%(17%) &
		OR ((OUT.STA%=0%) AND &
		     (32% OR (64% AND &
		   ((USTAT% AND 16%)<>0% OR (DOS% AND NOT DOS.LINKED%))))) &
	! &
	! MODE% = OUT.MODE% &
	!	OR (RSTS.DISK.OUT% AND &
	!	     (TENTATIVE% OR (CONDITIONAL.CONTIGUOUS% AND &
	!		CONTIGUOUS.INPUT%))) &
	! &
	\ OPEN "_"+T0$ FOR OUTPUT AS FILE 2%, &
		RECORDSIZE ((2% EQV 32767%) AND FOREIGN.BUFF%), &
		CLUSTERSIZE -FILE.CLU%, &
		MODE T0% &
	\ RETURN IF OUT.STA% &
	\ Z%(0%)=30% &
	\ Z%(1%)=6% &
	\ Z%(2%)=-26% &
	\ Z%(3%)=2% &
	\ Z%(4%)=12% &
	\ Z%(4%)=4% IF DECTAPE% AND NOT RT11% &
	\ Z%(T1%)=0% FOR T1%=5% TO 30% &
	\ T1%=FNTO.Z%(FILE.DATE%,19%) UNLESS INSTR(1%,DATE$(FILE.DATE%),"X") &
	\ T1%=FNTO.Z%(FILE.TIME%,21%) UNLESS IN.STA% OR NOT RSTS% &
	\ T1%=FNTO.Z%(EXTRA%(12%),13%) AND FNTO.Z%(EXTRA%(13%),15%) &
	\ CHANGE Z% TO T0$ &
	\ DUMMY$=SYS(PRIV.ON$) &
	\ T0$=SYS(T0$) &
	\ DUMMY$=SYS(PRIV.OFF$) &
		! OPEN THE RSTS/E OUTPUT FILE. &
		! BUFFERSIZE 2 UNLESS DOS LINKED INPUT, IN WHICH CASE &
		!	USE DEFAULT BUFFERSIZE AS WE MUST 'PRINT' OUT. &
		! TENTATIVE MODE, IF DISK. &
		! IF IT IS DISK, WE WILL DO SOME MODIFICATION OF &
		! THE DIRECTORY INFO. &
		! SET UP FOR THE FILE PLACEMENT AND MODIFICATION SYS CALL. &
		! WE WILL CHANGE FILE BACKUP STATISTICS. &
		! IF WE HAVE A RTS NAME TO OUTPUT, WE WILL CHANGE THAT TOO. &
		! WE CHANGE CREATION DATE TO INPUT FILE'S CREATION DATE. &
		! IF WE CAME FROM A RSTS/E DISK, WE CAN CHANGE CREATION TIME. &
		! LOAD THE RUN-TIME SYSTEM NAME. &
		! DO THE SYS CALL. &
	\ RETURN UNLESS NO.ATTR% &
	\ Z%(2%)=-25% &
	\ Z%(4%)=NO.ATTR% &
	\ T1%=FNTO.Z%(EXTRA%(T0%),3%+2%*T0%) FOR T0%=1% TO NO.ATTR% &
	\ CHANGE Z% TO T0$ &
	\ T0$=SYS(T0$) &
	\ RETURN &
		! IF THE INPUT FILE HAS ATTRIBUTES, WRITE THEM OUT &
		! TO THE OUTPUT RSTS/E DISK FILE. &

14300	! &
	! &
	! &
	!	C L O S E    R S T S    O U T P U T    D I S K    F I L E &
	! &
	! &
	! &
	CLOSE 2% &
	\ IF RSTS% THEN &
		CHANGE FSS.SCAN$(4%) TO Z% &
	\	IF ((Z%(22%) OR FILE.PROT%) AND 64%) THEN &
			GOTO 14330 &
		ELSE	GOTO 14340 &
		! IF WE CAME FROM A RSTS/E DEVICE, LOOK AT OUR INPUT &
		! AND OUTPUT PROTECTION CODES TO DETERMINE WHETHER OR NOT &
		! WE SHOULD SET A COMPILED PROTECTION CODE ON OUTPUT. &
		! IF EITHER HAS IT SET, WE WILL SET IT ON OUTPUT. &

14310	DUMMY$=SYS(PRIV.ON$) &
	\ CHANGE SYS(CHR.6$+CHR$(-12%)) TO Z% &
	\ T0%=FNFROM.Z%(15%) &
	\ CHANGE FSS.SCAN$(4%) TO Z% &
	\ T1%=FNFROM.Z%(11%) &
	\ WHILE T0% &
	\	T0%=PEEK(T0%) &
	\	IF	EXTRA%(12%)=PEEK(T0%+2%) &
		AND	EXTRA%(13%)=PEEK(T0%+4%) THEN &
			IF T1%=PEEK(T0%+6%) THEN &
				GOTO 14330 &
			ELSE	GOTO 14340
14320	NEXT &
	\ GOTO 14340 &
		! GET THE ROOT OF THE MONITOR'S RTS LIST. &
		! GET THE TYPE OF THE OUTPUT FILE. &
		! LOOK FOR THE FILE'S RTS NAME IN THE MONITOR &
		! LINKED LIST.  WHEN WE FIND IT, SEE IF THE &
		! FILE'S TYPE IS THE RUNNABLE TYPE. &
		! IF NOT, RETURN.  IF SO, WE WILL TWEEK THE PROT CODE. &

14330	DUMMY$=SYS(PRIV.ON$) &
	\ Z%(22%)=60% UNLESS (Z%(30%) AND 4%) &
	\ Z%(22%)=Z%(22%) OR 64% &
	\ Z%(28%)=Z%(28%) OR 8% &
	\ Z%(22%)=Z%(22%) AND (NOT 128%) UNLESS TMPPRV.PRIV% &
	\ CHANGE Z% TO FSS.SCAN$(4%) &
	\ T0$=FNBUILD$(4%,-256%) &
	\ NAME T0$ AS T0$ &
		! USE A DEFAULT PROTECTION CODE OF <60> IF NONE &
		! SPECIFIED.  SET THE COMPILED BIT ON THE CODE &
		! AND THE FLAG THAT SAYS WE SHOULD INCLUDE IT. &
		! CLEAR THE PRIV BIT IF THE USER DOESN'T HAVE TMPPRV PRIVS. &
		! RENAME THE FILE TO INCLUDE THE COMPILED BIT. &

14340	DUMMY$=SYS(PRIV.OFF$) &
	\ RETURN &
		! DROP PRIVILEGES AGAIN AND RETURN. &

14400	! &
	! &
	! &
	!	F I N D    N E X T    R S T S    P P N &
	! &
	! &
	! &
	PPN%=0% &
	\ CHANGE FSS.SCAN$(1%) TO Z% &
	\ Z%(1%)=6% &
	\ Z%(2%)=25% &
	\ T0%=FNTO.Z%(PPN.COUNT%,3%) &
	\ PPN.COUNT%=PPN.COUNT%+1% &
	\ FILE.COUNT%=0% &
	\ CHANGE Z% TO T0$ &
	\ T0$=SYS(T0$) &
	\ FSS.SCAN$(0%),T0$=LEFT(FSS.SCAN$(1%),4%)+MID(T0$,5%,2%)+ &
			RIGHT(FSS.SCAN$(1%),7%) &
	\ CHANGE T0$ TO Z% &
	\ PPN%=FNFROM.Z%(5%) &
	\ RETURN &
		! GET THE NEXT MATCHING PPN FROM THE PPN WILD CARD &
		! LOOKUP SYS CALL. &

14500	! &
	! &
	! &
	!	F I N D    N E X T    R S T S    F I L E &
	! &
	! &
	! &
	FOUND%=0% &
	\ CHANGE FSS.SCAN$(0%) TO Z% &
	\ Z%(1%)=6% &
	\ Z%(2%)=17% &
	\ T0%=FNTO.Z%(FILE.COUNT%,3%) &
	\ FILE.COUNT%=FILE.COUNT%+1% &
	\ CHANGE Z% TO T0$ &
	\ CHANGE SYS(T0$) TO Z% &
	\ NAMTYP%(T0%)=FNFROM.Z%(T0%*2%+7%) FOR T0%=0% TO 2% &
	\ GOTO 14500 IF NAMTYP%(2%)=3244% AND SKIP.BAD% &
	\ FILE.LEN%=FNFROM.Z%(13%) &
	\ MSB.LEN%=Z%(16%) &
	\ FILE.LEN=FNFLOAT(FILE.LEN%)+65536.*MSB.LEN% &
	\ FILE.DATE%=FNFROM.Z%(19%) &
	\ FILE.TIME%=FNFROM.Z%(21%) &
	\ FILE.PROT%=Z%(15%) &
	\ USTAT%=Z%(30%) &
	\ FOUND%=-1% &
	\ RETURN UNLESS (IN.SW% AND 32%) &
		! GET THE NEXT MATCHING FILESPEC FROM THE DISK &
		! WILD CARD DIRECTORY LOOKUP.  ALSO GET THE DATE &
		! AND TIME OF CREATION AND THE DATE OF LAST ACCESS. &
		! SKIP ".BAD" FILES IF WE SHOULD. &
	\ Z%(1%)=6% &
	\ Z%(2%)=-26% &
	\ Z%(3%),Z%(15%)=0% &
	\ Z%(4%)=16% &
	\ T0%=FNTO.Z%(1%,13%) &
	\ CHANGE Z% TO T0$ &
	\ CHANGE SYS(T0$) TO Z% &
	\ IN.START%=FNFROM.Z%(3%) &
	\ EXTRA%(T0%)=FNFROM.Z%(2%*T0%+3%) FOR T0%=1% TO 13% &
	\ RETURN &
		! IF THIS IS FOR A DIRECTORY LISTING, GET THE &
		! ADDITIONAL INFORMATION NOW, AS WE WON'T BE GETTING &
		! IT BY OPENING THE FILE LATER. &

15000	! &
	! &
	! &
	!	O P E N    A N D    I D E N T I F Y    D E V I C E &
	! &
	! &
	!		F N O P E N . D E V % ( C H % ) &
	! &
	! &
	! &
	! FUNCTION:	ATTEMPTS TO DETERMINE WHAT TYPE OF DEVICE HAS BEEN &
	!		  SPECIFIED TO BE USED ON A CHANNEL. &
	!		IF IT IS NOT A MOUNTED RSTS/E DISK, THE DEVICE &
	!		  IS OPENED WITH A RECORDSIZE OF 2. &
	!		IF THE DEVICE IS AN RT11 FORMAT RP02, IT IS &
	!		  REOPENED WITH A RECORDSIZE OF 1024. &
	!		IF THE DEVICE HAS DOS OR RT11 FORMAT, THE DOS &
	!		  OR RT11 DIRECTORY POINTERS ARE INITIALIZED. &
	! &
	! PARAMETERS:	CH%	THE CHANNEL NUMBER ON WHICH TO OPERATE. &
	! &
	! LOCAL &
	! VARIABLES &
	! USED:		T0%	WORK VARIABLE. &
	!		T1%	=FNOPEN.DEV%. &
	!		T2%	WORK VARIABLE. &
	!		T0	=TOTAL DEVICE SIZE (DEV.SIZE(CH%)+1.). &
	!		T0$	WORK VARIABLE. &
	!		T1$	WORK VARIABLE. &
	!		T2$	DEVICE NAME. &
	!		Z%()	USED IN EXAMINING DATA ON DEVICE. &
	!		Z1%()	USED TO COMPARE DOS DISK POINTERS. &
	! GLOBAL &
	! VARIABLES &
	! AFFECTED:	STA%		SET TO IN.STA% OR OUT.STA% &
	!		DEFAULT%	DEFAULT DEV TYPE IF CH%=1% &
	!		CLU%		THE DEVICE CLUSTER SIZE. &
	!		DEV.SIZE(CH%)	SET TO # OF LAST BLOCK IN DEVICE, &
	!				IF DEVICE IS OPENED. &
	!		ERR.MSG$	FILLS WITH ERROR MESSAGE, IF ANY. &
	! &
	! RETURNS:	  0	UNIDENTIFIABLE FILE STRUCTURE. &
	!		  1	WOULDN'T EXPECT A FILE STRUCTURE ON DEVICE. &
	!		  2	RSTS/E DIRECTORY STRUCTURE (NOT MOUNTED). &
	!		  4	MOUNTED RSTS/E DISK. &
	!		  8	DECRT11A FILE STRUCTURE. &
	!		 16	DOS FILE STRUCTURE. &
	! &
	DEF* FNOPEN.DEV%(CH%) &
	\ FNOPEN.DEV%,T1%,T2%=0% &
	\ DEV$(CH%),T2$=FNBUILD$(CH%,8192%) &
	\ STA%=OUT.STA% &
	\ STA%=IN.STA% IF CH%=1% &
	\ T2%=4% IF STA%=0% OR STA%=4% &
	\ T2%=8% IF STA%=18% OR STA%=30% &
	\ DEFAULT%=T2% IF CH%=1% &
	\ IF T2%=0% THEN &
		FNOPEN.DEV%,T1%=1% &
	\	GOTO 15080 &
		! &
		! INITIALIZE FUNCTION. &
		! GET THE DEVICE NAME. &
		! FIGURE OUT THE DEFAULT DEVICE TYPE. &
		! IF NO DEFAULT TYPE, THEN SAY SO AND GO END. &

15010	ON ERROR GOTO 15090 &
		! SET LOCAL ERROR TRAP. &
	\ IF STA%=0% THEN &
		CHANGE FSS.SCAN$(CH%) TO Z% &
	\	Z%(1%)=6% &
	\	Z%(2%)=25% &
	\	Z%(3%),Z%(4%)=0% &
	\	Z%(5%),Z%(6%)=255% &
	\	CHANGE Z% TO T0$ &
	\	T0$=SYS(T0$) &
	\	FNOPEN.DEV%,T1%=4% &
	\	GOTO 15080 &
		! &
		! SET LOCAL ERROR TRAP. &
		! IF IT IS A DISK, SEE IF IT IS A RSTS/E MOUNTED DISK &
		! BY DOING A WILDCARD ACCOUNT LOOKUP FOR THE 1ST ACCOUNT. &
		! IF WE SUCCEED, FLAG THAT THAT'S WHAT IT WAS AND EXIT. &

15020	OPEN "_"+T2$ AS FILE CH%, RECORDSIZE (2% EQV 32767%) &
		! &
		! OPEN THE DEVICE, RECORDSIZE "REALLY" 2%. &
		! &
	\ T0=0. &
	\ T0=576. IF STA%=4% &
	\ T0=512. IF STA%=30% &
	\ T0=494%*(SPEC%(0%,0%,CH%,STA%) AND 255%) IF STA%=18% &
	\ CLU%=1% &
	\ IF T0=0. THEN &
		CHANGE SYS(CHR$(12%)) TO Z% &
	\	T0=65536.*Z%(4%)+256.*Z%(14%)+Z%(13%) &
	\	CLU%=Z%(21%) IF Z%(21%) &
	\	T0=T0*CLU% &
		! &
		! DETERMINE THE SIZE OF THE OPENED DEVICE: &
		! 576 BLOCKS IF TU56 DECTAPE. &
		! 512 BLOCKS IF TU58 DECTAPE II. &
		! 494 BLOCKS IF FLOPPY DISK, SINGLE DENSITY. &
		! 988 BLOCKS IF RX02 FLOPPY DISK, DOUBLE DENSITY. &
		! ELSE GET SIZE FROM "LAST OPENED INFO" SYS CALL. &
		! NOTE THAT T0 IS THE TOTAL NUMBER OF BLOCKS ON THE &
		! DEVICE, INCLUDING BLOCK ZERO. &

15030	DEV.SIZE(CH%)=T0-1. &
	\ BUF%=CH%+5% &
	\ CH.BUF%=CH%+SWAP%(BUF%) &
	\ GOTO 15060 IF STA%=4% &
		! FINISH INITIALIZING. &
		! NOTE THAT DEV.SIZE(CH%) IS THE BLOCK NUMBER OF THE &
		! LAST BLOCK ON THE DEVICE. &

15040	ON ERROR GOTO 15090 &
	\ GOTO 15080 IF STA%=4% &
	\ T0%=FNBUFF%(BUF%,512%) &
	\ GET #CH.BUF%, RECORD 1% &
	\ T0%=FNGET.WORDS%(BUF%,0%,8%) &
	\ IF	STA%=0%			AND &
		T0%<>0%			AND &
		Z%(1%)=-1%		AND &
		(Z%(2%) OR Z%(3%))=0%	AND &
		Z%(4%)>0% AND Z%(4%)<=16% AND &
		(Z%(4%)-1% AND Z%(4%))=0% AND &
		Z%(6%)<>0% &
		THEN	FNOPEN.DEV%,T1%=2% &
	\		GOTO 15080 &
		! &
		! LOOK AT WHAT WOULD BE THE MFD LABEL ENTRY OF A RSTS/E &
		! DISK.  IF IT LOOKS LIKE ONE, THEN FLAG RSTS/E. &
		! WE SHOULD FIND: &
		!     WORD	MEANING &
		!	0	LINK TO 1ST NAME ENTRY IN MFD. &
		!	1	-1 (TO MARK ENTRY IN USE). &
		!	2	 0 &
		!	3	 0 &
		!	4	PACK CLUSTER SIZE - A POWER OF 2 <= 16. &
		!	6	1ST WORD OF PACK ID (NON-ZERO). &

15050	ON ERROR GOTO 19000 &
	\ T0%=FNBUFF%(BUF%,1024%) &
	\ T0%=FNGET.RT.DIR%(CH.BUF%,1%) IF CLU%=1% &
	\ GET #CH.BUF%, RECORD 3% IF CLU%<>1% &
	\ ERR.MSG$=LEFT(ERR.MSG$,INSTR(1%,ERR.MSG$,":")) IF LEN(ERR.MSG$) &
	\ GOTO 15085 IF LEN(ERR.MSG$) &
		! &
		! IF THERE WAS AN ERROR ON THE GET, RETURN THE ERROR MESSAGE &
		! SPECIFYING ONLY THE DEVICE, NOT THE FILE SPEC. &
		! &
	\ T0%=FNGET.WORDS%(BUF%,0%,10%) &
	\ IF	T0%>0% AND T0%<=31% &
	  AND	Z%(1%)<=T0% AND Z%(1%)>=0% &
	  AND	Z%(2%)<=T0% AND Z%(2%)>0% AND Z%(2%)>=Z%(1%) &
	  AND	Z%(3%)<=1000% AND Z%(3%)>=0% AND (Z%(3%) AND 1%)=0% &
	  AND	Z%(4%)=6%+T0%*2% &
	  AND	Z%(9%)<DEV.SIZE(CH%) THEN &
		FNOPEN.DEV%,T1%=8% &
	\	OPEN "_"+T2$ AS FILE CH%, RECORDSIZE 1024% &
			UNLESS CLU%=1% OR ((IN.SW% AND 64%) AND CH%=1%) &
	\	DIR.SEG%(CH%)=1% &
	\	DIR.PTR%(CH%)=0% &
	\	DIR.SIZE%(CH%)=T0% &
	\	DIR.LINK%(CH%)=Z%(1%) &
	\	DIR.USED%(CH%)=Z%(2%) &
	\	DIR.ENT.LEN%(CH%),T0%=7%+Z%(3%)/2% &
	\	OUT.ENT.LEN%=T0% IF CH%=2% &
	\	RSTS.EXTRA%=(T0%=20% AND CH%=1%) &
	\	FILE.REC%(CH%)=Z%(4%) &
	\	DEV.SIZE(CH%)=T0-67. IF T0=27104. OR T0=53768. &
	\	DEV.SIZE(CH%)=T0-41. IF T0=10220. OR T0=20460. &
	\	GOTO 15080 &
		! &
		! READ BLOCKS 6-7 OF THE DEVICE.  IF THIS IS AN RT11 &
		! DEVICE, THIS WILL BE THE FIRST DIRECTORY SEGMENT. &
		! WE SHOULD FIND: &
		!     WORD	MEANING &
		!	0	NO. OF AVAILABLE DIRECTORY SEGMENTS 1-31. &
		!	1	NO. OF NEXT DIRECTORY SEGMENT 0-31. &
		!	2	NO. OF DIR SEGMENTS IN USE. &
		!	3	NO. OF EXTRA BYTES PER DIR ENTRY. &
		!	4	BLOCK NO. WHERE FILES BEGIN. &
		!	9	SIZE OF FIRST ENTRY. &
		! &
		! IF THIS IS AN RP02, RE-OPEN IT WITH BUFFERSIZE OF 2 BLOCKS. &
		! FOR CERTAIN DEVICES, THE DEVICE SIZE WE WILL CONSIDER WILL &
		!	BE SMALLER THAN THE TOTAL DEVICE SIZE, AS RT11 &
		!	RESERVES BLOCKS AT THE END FOR BAD BLOCK SUBSTITUTION. &
		!	THE NUMBER OF BLOCKS RESERVED FOR THESE DEVICES ARE: &
		!	       DEVICE	     TOTAL SIZE  RESERVED BLOCKS &
		!		RL01		10220		40 &
		!		RL02		20460		40 &
		!		RK06		27104		66 &
		!		RK07		53768		66 &

15060	T0%=FNBUFF%(BUF%,512%) &
	\ GET #CH.BUF%, RECORD 1% IF STA%<>4% &
	\ GET #CH.BUF%, RECORD 64% IF STA%=4% &
	\ T0%=FNGET.WORDS%(BUF%,0%,8%) &
	\ GOTO 15080 UNLESS &
		FNBLOCK%(0%)	AND &
		Z%(1%)<=8%	AND &
		FNBLOCK%(2%)	AND &
		Z%(2%)=Z%(3%)	AND &
		Z%(0%)<>Z%(3%) &
	\ Z1%(T0%)=Z%(T0%+2%) FOR T0%=1% TO 4% &
	\ MFD.REC%=Z%(0%) &
	\ T2%=Z%(2%) &
	\ FOR T0%=1% WHILE T2% AND T0%<=4% &
	\	GOTO 15080 UNLESS T2%=Z1%(T0%) AND FNBLOCK%(0%) &
	\	GET #CH.BUF%, RECORD T2% &
	\	T2%=FNGET.WORDS%(BUF%,0%,4%) &
	\	GOTO 15080 UNLESS &
			Z%(1%)=T0%	AND &
			Z%(3%)=Z1%(1%) &
	\ NEXT T0% &
	\ FNOPEN.DEV%,T1%=16% &
	\ FNOPEN.DEV%,T1%=21% IF STA%=4% &
		! &
		! IF THE FIRST BLOCK LOOKS LIKE A DOS MFD HOME BLOCK &
		! (OR THE 64'TH BLOCK LOOKS LIKE DOS IF DECTAPE), &
		! THEN CHECK OUT FOUR (IF THERE ARE THAT MANY) OF THE &
		! DEVICE BIT MAP BLOCKS TO SEE IF THEY LOOK PROPER. &
		! IF EVERYTHING LOOKS REASONABLE, CALL IT DOS. &
		! &
		! IF IT IS DOS DECTAPE, WE HAVE A SPECIAL CASE. &
		! IT WILL BE CONSIDERED A DOS DISK FOR INPUT AND &
		! A RANDOM RSTS/E DEVICE SUCH AS MAGTAPE FOR OUTPUT. &
		! &
		! IN THE FIRST BLOCK WE SHOULD FIND: &
		!     WORD	MEANING &
		!	0	BLOCK # OF 1ST MFD BLOCK WITH UIC ENTRIES. &
		!	1	INTERLEAVE FACTOR <= 10(8). &
		!	2	BLOCK # OF LINKED BIT MAP (SAME AS WORD 3). &
		!	3	BLOCK # OF BIT MAP BLOCK 1 (SAME AS WORD 2). &
		!	4	BLOCK # OF BIT MAP BLOCK 2. &
		!	n	BLOCK # OF BIT MAP BLOCK n-2. &
		! &
		! IN BIT MAP BLOCK n WE SHOULD FIND: &
		!     WORD	MEANING &
		!	0	BLOCK # OF BIT MAP BLOCK n+1. &
		!	1	n. &
		!	3	BLOCK # OF BIT MAP BLOCK 1. &

15080	GOTO 15050 IF STA%=4% AND BUFSIZ(BUF%)=512% AND T1%=0% &
		! &
		! IF THIS IS DECTAPE AND WE HAVEN'T TRIED RT11 FORMAT &
		! SO FAR, GO TRY IT NOW. &
		! &
	\ ERR.MSG$="?RSTS/E disk not mounted - "+T2$ &
		UNLESS T1%<>2% OR (IN.SW% AND 64%) &
	\ ERR.MSG$="?Device not allowed for input - "+T2$ &
		IF T1%=1% AND CH%=1% &
	\ ERR.MSG$="?Can't Zero a mounted RSTS/E disk - "+T2$ &
		IF T1%=4% AND (IN.SW% AND 64%) &
	\ ERR.MSG$="?Not a recognized directory structure - "+T2$ &
		UNLESS T1% OR (IN.SW% AND 64%) &
	\ SW%=OUT.SW% &
	\ SW%=IN.SW% IF CH%=1% &
	\ T0%=(SW% AND 28%) &
	\ IF ((T0% AND T1%) OR (IN.SW% AND 64%) OR LEN(ERR.MSG$))=0% &
			AND T0% THEN &
		T0$="RSTS/E" &
	\	T0$="RT11" IF T1%=8% &
	\	T0$="DOS" IF T1%=16% &
	\	ERR.MSG$="?Device "+T2$+" has "+T0$+" structure" &
		! IF DEVICE TYPE SWITCH WAS SPECIFIED, MAKE SURE &
		! WE HAVE THE RIGHT TYPE OF DEVICE OR RETURN AN ERROR. &

15085	ON ERROR GOTO 19000 &
	\ FNEND &
		! RETURN FROM FNOPEN.DEV%(CH%) &

15090	RESUME 15020 IF ERL=15010% &
	\ ERR.MSG$=FNE$(ERR)+DASH$+T2$ &
	\ RESUME 15085 &
		! IF IT WAS WILDCARD ACCOUNT FAILURE, &
		!	THEN DISK NOT RSTS/E MOUNTED. &
		! RETURN ALL OTHER ERRORS. &

15100	! &
	! &
	! &
	!	M A T C H    F I L E N A M E    &    E X T E N S I O N &
	! &
	! &
	!		F N M A T C H % ( T 0 % ) &
	! &
	! &
	! &
	! FUNCTION:	FILENAME AND TYPE MATCHING ROUTINE. &
	!		COMPARES THE FILENAME FOUND IN RADIX-50 &
	!		IN THE ARRAY Z%() STARTING AT T0% AGAINST &
	!		THE ASCII CHARACTERS FOUND IN MATCH%(). &
	! &
	! PARAMETERS:	T0%	WHERE FILENAME IS LOCATED IN Z%(). &
	! &
	! LOCAL &
	! VARIABLES &
	! USED:		Z1%()	HOLDS THE ASCII CHARACTERS OF FILENAME. &
	! &
	! RETURNS:	T0%	-1 IF MATCH, 0 IF NO MATCH. &
	! &
	DEF* FNMATCH%(T0%) &
	\ FNMATCH%=-1% &
	\ FNMATCH%=0% IF Z%(T0%+2%)=3244% AND SKIP.BAD% &
	\ CHANGE RAD$(Z%(T0%))+RAD$(Z%(T0%+1%))+RAD$(Z%(T0%+2%)) TO Z1% &
	\ FNMATCH%=0% IF Z1%(T0%)<>MATCH%(T0%) AND MATCH%(T0%)<>63% &
		FOR T0%=1% TO 9% &
		! &
		! IF WE SHOULD NOT ALLOW ".BAD" FILES, DON'T. &
		! GET AN ARRAY OF ASCII VALUES OF THE FILENAME. &
		! THERE IS NO MATCH IF ANY CHARACTER IN THE MATCH ARRAY &
		! DOES NOT MATCH THE CHARACTER IN THE FILENAME OR A "?". &

15110	FNEND &
		! END OF FNMATCH%(T0%). &

15120	! &
	! &
	! &
	!	G E T    W O R D S    F R O M    B U F F E R &
	! &
	! &
	!	F N G E T . W O R D S % ( C H % , T 0 % , T 1 % ) &
	! &
	! &
	! &
	! FUNCTION:	RETURNS WORDS FROM A BUFFER IN ARRAY Z%(). &
	! &
	! PARAMETERS:	CH%	CHANNEL IN WHICH BUFFER IS LOCATED. &
	!		T0%	WORD OFFSET INTO BUFFER TO START AT. &
	!		T1%	NUMBER OF WORDS TO RETURN. &
	! LOCAL &
	! VARIABLES &
	! USED:		Z%()	T1% CANNOT BE MORE THAN HALF THE &
	!			DIMENSION OF Z%(). &
	! &
	! RETURNS	THE FIRST WORD GOTTEN (=Z%(0%)). &
	! &
	DEF* FNGET.WORDS%(CH%,T0%,T1%) &
	\ FIELD #CH%, T0%*2% AS B0$, T1%*2% AS B0$ &
	\ CHANGE B0$ TO Z% &
	\ Z%(T0%)=FNFROM.Z%(2%*T0%+1%) FOR T0%=0% TO T1%-1% &
	\ FNGET.WORDS%=Z%(0%) &
		! FIELD THE BUFFER TO GET THE DESIRED FIELD. &
		! CHANGE IT TO A BYTE ARRAY. &
		! CHANGE THE BYTE ARRAY STARTING WITH BYTE 1 TO &
		! A WORD ARRAY STARTING WITH WORD 0. &

15130	FNEND &
		! END OF FNGET.WORDS%(CH%,T0%,T1%). &

15140	! &
	! &
	! &
	!	P U T    W O R D S    I N T O    B U F F E R &
	! &
	! &
	!	F N P U T . W O R D S % ( C H % , T 0 % , T 1 % ) &
	! &
	! &
	! &
	! FUNCTION:	PUTS WORDS FROM ARRAY Z%() INTO A BUFFER. &
	!		COMPLIMENTS THE ACTION OF FNGET.WORDS%(CH%,T0%,T1%). &
	! &
	! PARAMETERS:	CH%	CHANNEL IN WHICH BUFFER IS LOCATED. &
	!		T0%	WORD OFFSET INTO BUFFER TO START AT. &
	!		T1%	NUMBER OF WORDS TO PUT IN BUFFER. &
	! LOCAL &
	! VARIABLES &
	! USED:		Z%()	MUST HAVE DIMENSION AT LEAST TWICE T1%. &
	!			THE ORIGINIAL CONTENTS OF Z%() ARE ALTERED. &
	! &
	! RETURNS:	NOTHING MEANINGFUL. &
	! &
	DEF* FNPUT.WORDS%(CH%,T0%,T1%) &
	\ FIELD #CH%, T0%*2% AS B0$, T1%*2% AS B0$ &
	\ CH%=FNTO.Z%(Z%(T0%-1%),T0%*2%-1%) FOR T0%=T1% TO 1% STEP -1% &
	\ Z%(0%)=T1%*2% &
	\ CHANGE Z% TO B1$ &
	\ LSET B0$=B1$ &
		! FIELD THE BUFFER TO PUT THE DESIRED WORDS. &
		! CHANGE ARARY Z%() TO A BYTE ARRAY. &
		! CHANGE THE ARRAY TO A STRING AND INSERT INTO BUFFER. &

15150	FNEND &
		! END OF FNPUT.WORDS%(CH%,T0%,T1%) &

15160	! &
	! &
	! &
	!	P A C K    W O R D    I N T O    Z % ( ) &
	! &
	! &
	!	    F N T O . Z % ( T 0 % , T 1 % ) &
	! &
	! &
	! &
	! FUNCTION:	PACKS A WORD INTO TWO BYTES IN ARRAY Z%(). &
	! &
	! PARAMETERS:	T0%	WORD TO STORE IN ARRAY Z%(). &
	!		T1%	ADDRESS IN Z%() AT WHICH TO STORE IT. &
	! &
	! RETURNS:	NOTHING MEANINGFUL. &
	! &
	DEF* FNTO.Z%(T0%,T1%) &
	\ Z%(T1%)=(T0% AND 255%) &
	\ Z%(T1%+1%)=(SWAP%(T0%) AND 255%) &
		! PUT THE WORD IN THE TWO BYTES. &
	\ FNEND &
		! END OF FNTO.Z%(T0%,T1%). &

15170	! &
	! &
	! &
	!	G E T    W O R D    F R O M    B Y T E S    I N    Z % ( ) &
	! &
	! &
	!		F N F R O M . Z % ( T 0 % ) &
	! &
	! &
	! &
	! FUNCTION:	UNPACKS A WORD FROM TWO BYTES IN ARRAY Z%(). &
	!		COMPLIMENTS THE ACTION OF FNTO.Z%(T0%,T1%). &
	! &
	! PARAMETERS:	T0%	ADDRESS OF FIRST BYTE IN Z%(). &
	! &
	! RETURNS:	Z%(T0%)+SWAP%(Z%(T0%+1%)) &
	! &
	DEF* FNFROM.Z%(T0%)=Z%(T0%)+SWAP%(Z%(T0%+1%)) &
		! RETURN THE TWO BYTES AS A WORD. &

15180	! &
	! &
	! &
	!	C R E A T E    A    B U F F E R    W I T H    N L : &
	! &
	! &
	!		F N B U F F % ( C H % , T 0 % ) &
	! &
	! &
	! &
	! FUNCTION:	OPENS THE NULL DEVICE ON A CHANNEL WITH A &
	!		SPECIFIED BUFFER SIZE, UNLESS THAT CHANNEL &
	!		IS ALREADY OPEN WITH THAT BUFFERSIZE. &
	! &
	! PARAMETERS:	CH%	CHANNEL NUMBER FOR THE BUFFER. &
	!		T0%	BUFFER SIZE TO CREATE. &
	! &
	! RETURNS:	NOTHING. &
	! &
	DEF* FNBUFF%(CH%,T0%) &
	\ OPEN "_NL:FIT.BUF" AS FILE CH%, RECORDSIZE T0% &
		UNLESS BUFSIZ(CH%)=T0% AND T0% &
		! OPEN THE NULL DEVICE ON THE CHANNEL WITH THE &
		! DESIRED BUFFERSIZE UNLESS WE ALREADY HAVE. &

15190	FNEND &
		! END OF FNBUFF%(CH%,T0%) &

15200	! &
	! &
	! &
	!	C H E C K    B O U N D S    O N    B L O C K    N U M B E R &
	! &
	! &
	!		F N B L O C K % ( T 0 % ) &
	! &
	! &
	! &
	! FUNCTION:	CHECKS TO SEE IF A NUMBER IS IN RANGE AS A &
	!		BLOCK NUMBER AND IS NOT BLOCK 0 OR 1. &
	! &
	! PARAMETERS:	T0%	Z%(T0%) IS THE NUMBER TO CHECK. &
	! &
	! RETURNS:	-1 IF IT IS IN RANGE, 0 IF IT IS NOT. &
	! &
	DEF* FNBLOCK%(T0%)=(FNFLOAT(Z%(T0%))>1% &
			AND FNFLOAT(Z%(T0%))<DEV.SIZE(CH%)) &
		! CHECK TO SEE THAT AN ILLEGED BLOCK NUMBER IS &
		!	GREATER THAN 1 (AS AN UNSIGNED INTEGER), &
		! AND THAT IT IS LESS THAN THE DEVICE SIZE. &
	&

15210	! &
	! &
	! &
	!	C O N V E R T    D A T E    T O    R T 1 1    F O R M A T &
	! &
	! &
	!		F N R T 1 1 . D A T E % ( T 0 % ) &
	! &
	! &
	! &
	! FUNCTION:	CONVERTS A DATE IN RSTS/E INTEGER FORMAT TO &
	!		RT11 INTEGER FORMAT. &
	! &
	! PARAMETERS:	T0%	THE DATE IN RSTS/E FORMAT TO CONVERT. &
	!			IF T0%=0%, THE CURRENT DATE WILL BE &
	!			RETURNED IN RT11 FORMAT. &
	! LOCAL &
	! VARIABLES &
	! USED:		T0$	THE RSTS/E DATE IN STRING FORM. &
	! &
	! RETURNS	THE SPECIFIED DATE IN RT11 FORMAT. &
	! &
	DEF* FNRT11.DATE%(T0%) &
	\ T0$=DATE$(T0%) &
	\ IF INSTR(1%,T0$,"-") THEN &
		FNRT11.DATE%= &
		((INSTR(1%,"Xanebarprayunulugepctovec",MID(T0$,5%,2%))/2%)*32% &
		+VAL(LEFT(T0$,2%)))*32% &
		+VAL(RIGHT(T0$,8%))-72% &
	  ELSE	FNRT11.DATE%= &
		(VAL(MID(T0$,4%,2%))*32% &
		+VAL(RIGHT(T0$,7%)))*32% &
		+VAL(LEFT(T0$,2%))-72% &
		! &
		! GET THE RSTS DATE STRING FOR DATE T0%. &
		! PACK THE STRING INTO RT11 INTEGER DATE FORMAT. &
		! RT11 DATE FORMAT IS AS FOLLOWS: &
		!     BITS	MEANING &
		!     0-4	YEAR SINCE 1972. &
		!     5-9	DAY OF MONTH. &
		!    10-14	MONTH. &
		!      15	RESERVED. &

15220	FNEND &
		! END OF FNRT11.DATE%(T0%) &

15230	! &
	! &
	! &
	!	C O N V E R T    D A T E    T O    R S T S    F O R M A T &
	! &
	! &
	!		F N R S T S . D A T E % ( T 0 % ) &
	! &
	! &
	! &
	! FUNCTION:	CONVERTS A DATE IN RT11 INTEGER FORMAT TO &
	!		RSTS/E INTEGER FORMAT. &
	! LOCAL &
	! VARIABLES &
	! USED:		YR%	THE YEAR SINCE 1970. &
	!		MO%	THE MONTH. &
	!		DA%	THE DAY OF THE MONTH OR YEAR. &
	! &
	! RETURNS:	THE SPECIFIED DATE IN RSTS/E FORMAT. &
	! &
	DEF* FNRSTS.DATE%(T0%) &
	\ YR%=T0% AND 31% &
	\ DA%=T0%/32% AND 31% &
	\ MO%=T0%/1024% AND 15% &
	\ DA%=DA%+28%+VAL(MID("303232332323",T0%,1%)) FOR T0%=1% TO MO%-1% &
	\ DA%=DA%+1% UNLESS (YR% AND 3%) OR MO%<=2% &
	\ FNRSTS.DATE%=(YR%+2%)*1000%+DA% &
		! UNPACK THE RT11 DATE FORMAT GETTING YR%, DA% AND MO%. &
		! CONVERT DA% FROM DAY OF MONTH TO DAY OF YEAR. &
		! ACCOUNT FOR LEAP YEARS. &
		! PACK YEAR AND DAY OF YEAR INTO RSTS/E INTEGER DATE FORMAT. &

15240	FNEND &
		! END OF FNRSTS.DATE%(T0%) &

15300	! &
	! &
	! &
	!	F O R M A T    N U M B E R    F O R    P R I N T I N G &
	! &
	! &
	!	     F N N U M B E R $ ( T 0 % , T 1 % , T 2 % ) &
	! &
	! &
	! &
	! FUNCTION:	CONVERTS TWO INTEGERS INTO A DOUBLE PRECISION &
	!		UNSIGNED NUMBER AND RIGHT JUSTIFIES THAT NUMBER &
	!		WITH SPACES IN A STRING FOR PRINTING. &
	! &
	! PARAMETERS:	T0%	LOW ORDER WORD OF NUMBER. &
	!		T1%	HIGH ORDER WORD OF NUMBER. &
	!		T2%	LENGTH OF FIELD TO JUSTIFY NUMBER IN. &
	! &
	! RETURNS:	THE STRING WITH THE NUMBER JUSTIFIED IN IT. &
	! &
	DEF* FNNUMBER$(T0%,T1%,T2%) &
	\ T0$=NUM1$(65536.*FNFLOAT(T1%)+FNFLOAT(T0%)) &
	\ FNNUMBER$=SPACE$(T2%-LEN(T0$))+T0$ &
		! GET THE UNSIGNED NUMBER IN A STRING. &
		! RIGHT-JUSTIFY NUMBER IN STRING OF LENGTH T2% CHARACTERS. &

15310	FNEND &
		! END OF FNNUMBER$(T0%,T1%,T2%) &

15320	! &
	! &
	! &
	!	R E T U R N    " s "    I F    P L U R A L &
	! &
	! &
	!		F N P L U R A L $ ( T 0 ) &
	! &
	! &
	! &
	! FUNCTION:	RETURNS THE NULL STRING OR "s" DEPENDING ON &
	!		WHETHER A NUMBER IS EQUAL TO 1 OR NOT. &
	! &
	! PARAMETERS:	T0	THE NUMBER TO CHECK FOR PLURALITY. &
	! &
	! RETURNS:	"" OR "s". &
	! &
	DEF* FNPLURAL$(T0)=LEFT("s",(T0=1.)+1%) &
		! RETURN "" IF T0=1., "s" IF T0<>1. &

15360	! &
	! &
	! &
	!	C O N V E R T    I N T E G E R    T O    F L O A T I N G &
	! &
	! &
	!		F N F L O A T ( T 0 % ) &
	! &
	! &
	! FUNCTION:	RETURNS A FLOATING NUMBER IN RANGE 0-65535. &
	! &
	! PARAMETERS:	T0%	THE INTEGER TO CONVERT TO FLOATING. &
	! &
	! RETURNS:	THE UNSIGNED VALUE OF THE INTEGER T0% &
	! &
	DEF* FNFLOAT(T0%)=32768.+(T0% EQV 32767%) &
		! FLIP THE SIGN BIT OF THE INTEGER & ADD 32768. &

15370	! &
	! &
	! &
	!	C O N V E R T    F L O A T I N G    T O    I N T E G E R &
	! &
	! &
	!		F N I N T E G E R % ( T 0 ) &
	! &
	! &
	! &
	! FUNCTION:	CONVERTS FLOTING NUMBER 0-65535 TO INTEGER. &
	! &
	! PARAMETERS:	T0	MUST BE IN RANGE 0-65535. &
	! &
	! RETURNS:	THE INTEGER WHOSE UNSIGNED VALUE IS T0. &
	! &
	DEF* FNINTEGER%(T0)=T0+65536.*(T0>32767.) &
		! SUBTRACT 65536 TO MAKE NUMBER NEGATIVE IF T0>32767. &

15380	! &
	! &
	! &
	!	R E T U R N    E R R O R    M E S S A G E &
	! &
	! &
	!		F N E $ ( T 0 % ) &
	! &
	! &
	! &
	! FUNCTION:	RETURNS A RSTS/E ERROR MESSAGE. &
	! &
	! PARAMETERS:	T0%	NUMBER OF ERROR MESSAGE TO RETURN. &
	! &
	! RETURNS:	THE RSTS/E ERROR MESSAGE. &
	! &
	DEF* FNE$(T0%)=CVT$$(RIGHT(SYS(CHR$(6%)+CHR$(9%)+CHR$(T0%)),3%),4%) &
		! RETURN THE RSTS/E ERROR MESSAGE NUMBER T0%. &

15390	! &
	! &
	! &
	!	R E T U R N    C R - L F    I F    C A R R I A G E &
	! &
	!		 N E E D S    R E T U R N I N G &
	! &
	! &
	!		       F N R E T $ ( ) &
	! &
	! &
	! &
	! FUNCTION:	RETURNS <CR>-<LF> IF CCPOS(0%)<>0%, &
	!		"" IF CCPOS(0%)=0% &
	! &
	! PARAMETERS:	NONE &
	! &
	! RETURNS:	<CR>-<LF> OR "". &
	! &
	DEF* FNRET$=LEFT(CHR$(13%)+CHR$(10%),-2%*(CCPOS(0%)<>0%)) &
		! RETURN <CR>-<LF> IF CARRIAGE NEEDS RETURNING. &

15400	! &
	! &
	! &
	!	S C A N    F I L E S P E C    A N D    S W I T C H E S &
	! &
	! &
	! &
	DEF* FNSCAN%(T0$,CH%) &
	\ SW%=CH% &
	\ T0$=CVT$$(T0$,254%) &
	\ FSS.SCAN$(CH%),FSS.SCAN$(CH%+2%),T1$=SYS(CHR.6$+CHR$(-23%)+T0$) &
	\ FW2%=SWAP%(CVT$%(RIGHT(T1$,29%))) &
	\ ERR.MSG$=FNE$(6%)+DASH$+T0$ IF FW2%<0% &
	\ T1$=RIGHT(T0$,LEN(T0$)-RECOUNT+1%) &
	\ FNSCAN%=(STATUS AND 255%) &
		! INITIALIZE RETURN SWITCH FLAG. &
		! PUSH THE FILESPEC THROUGH FSS AND GET SWITCHES AND STATUS. &
		! IF DEVICE WAS UNTRANSLATABLE, RETURN "?Not a valid device". &

15410	WHILE LEN(T1$) AND T0$<>"eod" &
	\   READ T0$, T0%, T1%, T2% &
	\   T3%=INSTR(1%,T1$,LEFT(T0$,T0%)) &
	\   IF T3% THEN &
		T4%=T0% &
	\	T4%=T4%+1% WHILE T4%<=LEN(T0$) AND &
			MID(T0$,T4%,1%)=MID(T1$,T3%-1%+T4%,1%) &
	\	T1$=LEFT(T1$,T3%-1%)+RIGHT(T1$,T3%+T4%-1%) &
	\	ERR.MSG$="?Conflicting switch - "+T0$ &
			IF (SW% OR T2%)<>T2% &
	\	SW%=(SW% OR T1%) &
	\	GOSUB 15440 IF (T1% AND 16384%) &
		! READ SWITCH, LENGTH TO MATCH, VALUE TO ADD TO FLAG, &
		!	VALUES NOT ALLOWED FOR FLAG WITH THIS SWITCH. &
		! CHECK FOR MINIMAL SWITCH MATCH.  IF FOUND, REMOVE &
		!	HOWEVER MUCH OF THE SWITCH THAT MATCHES. &
		! CHECK LEGAL VALUES OF SW% WITH THE SWITCH. &
		! RETURN AN ERROR IF INVALID SWITCH COMBINATION. &
		! GOSUB VALUE ROUTINE IF SWITCH MIGHT HAVE VALUE. &

15420	NEXT &
	\ ERR.MSG$="?Unrecognized switch(es) - "+T1$ IF LEN(T1$) &
		! CHECK NEXT SWITCH. &
		! RETURN AN ERROR IF UNRECOGNIZED SWITCH PRESENT. &

15430	FNEND &
		! END OF FNSCAN$(T0$,CH%,T0%) &

15440	ON ERROR GOTO 15480 &
	\ T0%=ASCII(MID(T1$,T3%,1%)) &
	\ IF T0%=58% THEN &
		T2%=INSTR(T3%,T1$+"/","/") &
	\	T4%=VAL(MID(T1$,T3%+1%,T2%-T3%-1%)) &
	\	T1$=LEFT(T1$,T3%-1%)+RIGHT(T1$,T2%) &
		! IF A COLON FOUND, GET THE VALUE BETWEEN &
		! THE COLON AND NEXT SWITCH, OR END OF SWITCHES. &

15450	IF T0%<>58% AND T0$="/ZE" THEN &
		T0%=58% &
	\	T4%=13% &
		! IF /ZE AND NO ARG, FAKE A DEFAULT ARG OF 13. &

15460	IF T0%<>58% THEN &
		ERR.MSG$="?Argument needed for "+T0$ &
	ELSE	ZE%=T4% IF T0$="/ZE" &
	\	N%=T4% IF T0$="/N" &
	\	GOTO 15480 IF T4%<0% OR T4%>31% OR (T4%=0% AND T0$="/N") &
		! RETURN THE VALUE IN THE APPROPRIATE VARIABLE. &
		! RETURN AN ERROR IF VALUE NOT IN RANGE. &

15470	ON ERROR GOTO 19000 &
	\ RETURN &
		! RETURN FROM VALUE SUBROUTINE FOR FNSCAN$. &

15480	ERR.MSG$="?Illegal argument in "+T0$ &
	\ RESUME 15470 &
		! IF AN ERROR IN VAL() FUNCTION, RETURN SWITCH ERROR. &

15490	! &
	! SWITCH DATA FOR FNSCAN$(T0$,CH%,T0%) &
	! &
	! DATA ENTRIES ARE IN THE FORM T0$, T0%, T1%, T2% WHERE: &
	! &
	! T0$	IS THE SWITCH. &
	! T0%	IS THE MINIMUM NUMBER OF CHARACTERS TO MATCH. &
	! T1%	IS THE VALUE OF THE BIT(S) TO SET IN SW%. &
	! T2%	IS THE VALUE OF THE BIT(S) IN SW% THAT MAY &
	!	BE PRESENT BEFORE THE BIT(S) OF T1% IS ADDED. &
	!	T2% SHOULD ALSO INCLUDE VALUE 1 IF SWITCH IS LEGAL &
	!	ON INPUT AND VALUE 2 IF SWTICH IS LEGAL ON OUTPUT. &
	! &
	! BITS IN THE FLAG WORD ARE AS FOLLOWS: &
	!      BIT   VALUE	MEANING &
	!	0	1	SWITCH ALLOWED ON INPUT SPEC. &
	!	1	2	SWITCH ALLOWED ON OUTPUT SPEC. &
	!	2	4	/RSTS	CAN BE RSTS/E DEVICE. &
	!	3	8	/RT11	CAN BE RT11 DEVICE. &
	!	4      16	/DOS	CAN BE DOS DEVICE. &
	!	5      32	/DI,/LI	DIRECTORY LISTING. &
	!	6      64	/ZE	ZERO RT11 DEVICE. &
	!	7     128	/DE	DELETE RT11 FILE. &
	!	8     256	/N	ALLOCATE DIR SEGMENTS ON ZERO. &
	!	9     512	/SQ	SQUEEZE RT11 DEVICE. &
	!      10    1024	/HELP	PRINT HELP MESSAGE. &
	!      11    2048	/WATCH	LOG COPY/DEL OPERATION ON KB:. &
	!      14   16384	SWITCH TAKES NUMERIC ARGUMENT. &
	! &
	DATA	/RSTS,	3,	4,	18755, &
		/RT11,	3,	8,	19755, &
		/DOS,	3,	16,	18467, &
		/DE,	3,	128,	2057, &
		/DI,	3,	32,	29, &
		/LI,	2,	32,	29, &
		/ZE,	2,	16448,	16649, &
		/N,	2,	16640,	16457, &
		/SQ,	3,	512,	9, &
		/HELP,	2,	1024,	1, &
		/WATCH,	2,	2048,	157, &
		"eod",	3,	0,	0 &

16000	! &
	! &
	! &
	!	B U I L D    F I L E S P E C &
	! &
	! &
	!	F N B U I L D $ ( T 0 % , T 1 % ) &
	! &
	! &
	! &
	! FUNCTION:	BUILDS AN OPENABLE FILESPEC FROM A FSS FORMAT &
	!		(30 BYTE) STRING DESCRIBING THE FILESPEC. &
	!		A MASK IS USED TO DETERMINE WHICH PARTS OF THE &
	!		SPECIFICATION TO REBUILD. &
	!		IF NO PPN WAS FOUND, USER'S PPN WILL BE RETURNED. &
	!		IF NO FILENAME OR TYPE FOUND, WILDCARDS &
	!		WILL BE RETURNED.  IF DEVICE ASSOCIATED WITH &
	!		FILENAME IS RT11 STYLE, PPN WILL NOT BE RETURNED. &
	! &
	! PARAMETERS:	T0%	FSS.SPEC(T0%)  CONTAINS FSS STYLE FILESPEC. &
	!		T1%	FLAG WORD MASK FOR STRING TO BUILD: &
	!			BITS 0-11 AS IN FSS FLAG WORD 1. &
	!			BIT 13 - ACTUAL DEVICE NAME RETURNED. &
	!			BIT 15 - LOGICAL DEVICE NAME RETURNED. &
	! LOCAL &
	! VARIABLES &
	! USED:		T0$	TO BUILD THE FILEPSPEC. &
	!		Z%()	TO HOLD THE FSS INFORMATION. &
	! &
	! RETURNS:	THE REBUILT FILESPEC. &
	! &
	DEF* FNBUILD$(T0%,T1%) &
	\ CHANGE FSS.SCAN$(T0%) TO Z% &
	\ SAVP%=Z%(6%) IF Z%(6%) OR Z%(5%)>0% &
	\ SAVN%=Z%(5%) IF Z%(6%) OR Z%(5%)>0% &
	\ Z%(6%)=SAVP% &
	\ Z%(5%)=SAVN% &
	\ T1%=T1% AND (NOT 1024%) &
		IF (T0% AND 1%) AND RT11% &
		OR (T0% AND 1%)=0% AND OUT.DEV%=8% &
		OR (T0% AND 1%)=0% AND (Z%(29%) AND 128%)=0% &
				! MASK OFF REQUEST FOR PPN IF THIS FILESPEC &
				! DESCRIBES A FILE ON AN RT11 DEVICE &
				! &
	\ Z%(5%),Z%(6%)=255% IF DOS% AND &
			(T0% AND 1%) AND (Z%(29%) AND 128%)=0% &
				! USE WILDCARD PPN IF DOS AND NONE SPECIFIED. &
	\ T0%=FNFROM.Z%(29%) &
				! GET FLAG WORD 2. &
	\ T1%=T1% AND &
		((FNFROM.Z%(27%) AND 4095%) OR 9984% OR (T0% AND -2048%)) &
				! TAKE LOWEST 11 BITS OF FLAG WORD 1 &
				! AND HIGHEST 4 BITS OF FLAG WORD 2. &
				! MAKE SURE BITS 256%, 512% AND 1024% &
				! AND 8192% &
				! REMAIN SET IF THEY ARE SET IN T1%. &
				! THE USER'S PPN AND WILDCARDS FOR NAME &
				! AND TYPE WILL BE PLUGGED IN IF NEEDED. &
				! SY: WILL BE PLUGGED IN IF NO DEVICE. &
	\ T0$="" &
	\ IF (T1% AND 8192%) THEN &
		IF (T0% AND 4096%)=0% THEN &
			T0$="SY:" &
		ELSE	T0$=CHR$(Z%(23%))+CHR$(Z%(24%)) &
	\		T0$=T0$+NUM1$(Z%(25%)) IF Z%(26%) &
	\		T0$=T0$+":" &
				! PHYSICAL DEVICE. &

16010	T0$=RAD$(FNFROM.Z%(23%))+RAD$(FNFROM.Z%(25%))+":" &
			IF T1%<0% &
				! LOGICAL DEVICE. &
	\ Z%(6%)=PROJ% UNLESS (T0% AND 128%) OR Z%(6%) &
	\ Z%(5%)=PROG% UNLESS (T0% AND 128%) OR Z%(5%) &
				! FILL IN [P,PN] IF NONE SPECIFIED. &
	\ T0$=T0$+"["+FNWILD$(Z%(6%))+","+FNWILD$(Z%(5%))+"]" &
			IF (T1% AND 1024%) &
				! [P,PN]. &
	\ T0$=T0$+RAD$(FNFROM.Z%(7%))+RAD$(FNFROM.Z%(9%)) &
			IF (T1% AND 256%) AND (T0% AND 1%)<>0% &
				! FILENAME FOUND. &
	\ T0$=T0$+"??????" &
			IF (T1% AND 256%) AND (T0% AND 1%)=0% &
				! NO FILENAME FOUND - WILDCARD. &
	\ T0$=T0$+"."+RAD$(FNFROM.Z%(11%)) &
			IF (T1% AND 512%) AND (T0% AND 8%)<>0% &
				! .TYPE FOUND. &
	\ T0$=T0$+".???" &
			IF (T1% AND 512%) AND (T0% AND 8%)=0% &
				! NO TYPE FOUND - WILDCARD. &
	\ T0$=T0$+"<"+NUM1$(Z%(22%))+">" &
			IF (T1% AND 2048%) &
				! <PROTECTION CODE>. &
	\ T0$=T0$+"/MO:"+NUM1$(FNFROM.Z%(17%) AND 32767%) &
			IF (T1% AND 2%) &
				! /MO: SWITCH. &
	\ T0$=T0$+"/CL:"+NUM1$(FNFROM.Z%(15%)) &
			IF (T1% AND 1%) &
				! /CL: SWITCH. &
	\ T0$=T0$+"/SI:"+NUM1$(FNFROM.Z%(13%)) &
			IF (T1% AND 4%) &
				! /SI: SWITCH. &
	\ T0$=T0$+"/PO:"+NUM1$(FNFROM.Z%(19%)) &
			IF (T1% AND 8%) &
				! /PO: SWITCH. &
	\ FNBUILD$=T0$ &
		! RETURN THE BUILT FILESPEC. &

16020	FNEND &
		! END OF FNBUILD$(T0$,T1%). &

16030	DEF* FNWILD$(T0%) &
	\ FNWILD$=NUM1$(T0%) &
	\ FNWILD$="*" IF T0%=255% &
	\ FNEND &
		! USED WITH FNBUILD$ TO FILL IN A PROJECT OR PROGRAMMER &
		! NUMBER, OR "*" IF IT IS WILDCARDED. &

16100	! &
	! &
	! &
	!	S U B S T I T U T E    F O U N D    F I L E N A M E &
	! &
	! &
	!		F N S U B % ( C H % ) &
	! &
	! &
	! &
	! FUNCTION:	RETURNS A FILESPEC IN Z%() INTO WHICH HAS BEEN &
	!		SUBSTITUTED THE ACTUAL PPN AND FILESPEC FOUND &
	!		BY A WILDCARD MATCH, IF THEY WEREN'T SPECIFIED. &
	!		ALSO RETURNS THE FSS FORMAT STRING. &
	! &
	! PARAMETERS:	CH%	OPERATES ON FILESPEC FSS.SCAN$(CH%). &
	! &
	! LOCAL &
	! VARIABLES &
	! USED:		T0%	DUMMY TARGET FOR FUNCTION CALLS. &
	! &
	! RETURNS:	NOTHING MEANINGFUL IN FNSUB%, DATA IN Z%() &
	!		AND FSS.SCAN$(CH%+2%). &
	! &
	DEF* FNSUB%(CH%) &
	\ CHANGE FSS.SCAN$(CH%) TO Z% &
	\ T0%=FNTO.Z%(NAMTYP%(0%),7%)+FNTO.Z%(NAMTYP%(1%),9%) &
		IF (Z%(29%) AND 7%)<>1% &
	\ T0%=FNTO.Z%(NAMTYP%(2%),11%) IF (Z%(29%) AND 104%)<>8% &
	\ T0%=FNTO.Z%(PPN%,5%) IF (Z%(30%) AND 3%) &
	\ Z%(21%),Z%(22%)=FILE.PROT% IF RSTS% AND Z%(21%)=0% &
	\ Z%(29%)=(Z%(29%) AND 153%) OR 9% &
	\ CHANGE Z% TO FSS.SCAN$(CH%+2%) &
		! PUT IN FILENAME IF IT WAS WILDCARDED. &
		! PUT IN TYPE IF IT WAS WILDCARDED. &
		! PUT IN [P,PN] IF IT WAS WILDCARDED. &
		! UNSET BITS THAT SAY WILDCARDS WERE IN FILNAM.TYP. &
		! MAKE SURE BITS ARE SET THAT SAY FILNAM.TYP WAS FOUND. &

16110	FNEND &
		! END OF FNSUB%(T0%) &

17000	! &
	! &
	! &
	!	G E T    R T 1 1    D I R E C T O R Y    S E G M E N T &
	! &
	! &
	!	     F N G E T . R T . D I R % ( C H % , T 0 % ) &
	! &
	! &
	! &
	! FUNCTION:	READS RT11 DIRECTORY SEGMENT (TWO 512-BYTE BLOCKS). &
	!		IF DECTAPE, GETS EACH BLOCK SEPERATELY. &
	!		IF RP02, THE CLUSTER IS READ. &
	! &
	! PARAMETERS:	CH%	CHANNEL NUMBER (AND FOREIGN BUFFER CHANNEL). &
	!		T0%	THE SEGMENT NUMBER TO GET. &
	!			SEGMENT 1 = BLOCKS 6-7, 2 = BLOCKS 8-9, ETC. &
	! LOCAL &
	! VARIABLES &
	! USED:		EQ%	=-1 -> READ FROM THE DEVICE ON CHANNEL 1. &
	! &
	! RETURNS:	NOTHING MEANINGFUL. &
	! &
	DEF* FNGET.RT.DIR%(CH%,T0%) &
	\ GOTO 17010 IF LEN(ERR.MSG$) &
	\ T0%=4%+T0%*2% &
	\ EQ%=(CH% AND 255%)=1% &
	\ T0%=T0%/2% IF (IN.CLU.2% AND EQ%) OR (OUT.CLU.2% AND NOT EQ%) &
	\ GET #CH%, RECORD T0% &
	\ IF (DECTAPE% AND EQ%) OR (OUT.STA%=4% AND NOT EQ%) THEN &
		GOSUB 17040 &
	\	GET #CH%, RECORD T0%+1% &
	\	GOSUB 17040 &
		! GET THE SEGMENT.  IF DECTAPE, THEN WE ONLY GOT FIRST BLOCK, &
		! SO SHUFFLE AND GET THE SECOND BLOCK. &

17010	FNEND &
		! END OF FNGET.RT.DIR%(CH%,T0%) &

17020	! &
	! &
	! &
	!	P U T    R T 1 1    D I R E C T O R Y    S E G M E N T &
	! &
	! &
	!	     F N P U T . R T . D I R % ( C H % , T 0 % ) &
	! &
	! &
	! &
	! FUNCTION:	WRITES RT11 DIRECTORY SEGMENT (TWO 512-BYTE BLOCKS). &
	!		IF DECTAPE, DOES IT BLOCK BY BLOCK. &
	!		IF RP02, THE CLUSTER IS WRITTEN. &
	! &
	! PARAMETERS:	CH%	CHANNEL (AND FOREIGN BUFFER) FOR PUT. &
	!		T0%	SEGMENT NUMBER TO WRITE. &
	! LOCAL &
	! VARIABLES &
	! USED:		EQ%	=-1 -> WRITE TO THE DEVICE ON CHANNEL 1. &
	! &
	! RETURNS:	NOTHING MEANINGFUL. &
	! &
	DEF* FNPUT.RT.DIR%(CH%,T0%) &
	\ GOTO 17030 IF LEN(ERR.MSG$) &
	\ T0%=4%+T0%*2% &
	\ EQ%=(CH% AND 255%)=1% &
	\ T0%=T0%/2% IF (IN.CLU.2% AND EQ%) OR (OUT.CLU.2% AND NOT EQ%) &
	\ IF (NOT DECTAPE% AND EQ%) OR (OUT.STA%<>4% AND NOT EQ%) THEN &
		PUT #CH%, RECORD T0% &
	ELSE	PUT #CH%, RECORD T0%, COUNT 512% &
	\	GOSUB 17040 &
	\	PUT #CH%, RECORD T0%+1%, COUNT 512% &
	\	GOSUB 17040 &
		! IF NOT DECTAPE, SIMPLY WRITE THE SEGMENT. &
		! IF DECTAPE, WRITE IT IN TWO CHUNKS, JUGGLING THE &
		! DATA IN THE BUFFER. &

17030	FNEND &
		! END OF FNPUT.RT.DIR%(CH%,T0%) &

17040	! &
	!	SWAP BLOCKS IN 1024-BYTE BUFFER (FOR DECTAPE). &
	!	USED WITH FNGET.RT.DIR% AND FNPUT.RT.DIR%. &
	! &
	FIELD #(SWAP%(CH%) AND 255%), 512% AS B0$, 512% AS B1$ &
	\ B2$=SPACE$(512%) &
	\ LSET B2$=B0$ &
	\ LSET B0$=B1$ &
	\ LSET B1$=B2$ &
	\ B2$="" &
	\ RETURN &
		! SWAP THE BLOCKS IN THE BUFFER. &

17100	! &
	! &
	! &
	!	    G E T    B L O C K    F R O M    D E V I C E &
	! &
	!	W I T H    C L U S T E R S I Z E    2    ( R P 0 2 ) &
	! &
	! &
	!	      F N G E T . C L U . 2 % ( T 0 ) &
	! &
	! &
	! &
	! FUNCTION:	GETS A BLOCK FROM A DEVICE WITH DCS 2. &
	!		THE DEVICE MUST BE OPEN ON CHANNEL 1 WITH &
	!		A BUFFERSIZE OF 1024 BYTES.  AN ACTUAL &
	!		DISK READ WILL ONLY BE PERFORMED IF THE &
	!		CLUSTER IS NOT CURRENTLY BUFFERED. &
	! &
	! PARAMETERS:	T0	THE BLOCK NUMBER TO GET. &
	! &
	! LOCAL &
	! VARIABLES &
	! USED:		T0%	THE CLUSTER NUMBER TO GET FROM. &
	!		OLD.IN%	THE CURRENTLY BUFFERED CLUSTER. &
	! GLOBAL &
	! VARIABLES &
	! AFFECTED:	DATA.BUFF$	"LSET"S THE BLOCK INTO DATA.BUFF$ &
	! &
	! RETURNS:	NOTHING MEANINGFUL. &
	! &
	DEF* FNGET.CLU.2%(T0) &
	\ T0%=T0/2. &
	\ GET #1%, RECORD T0% UNLESS T0%=OLD.IN% &
	\ OLD.IN%=T0% &
	\ FIELD #1%, 512%*((T0=2.*T0%)+1%) AS B0$, 512% AS B0$ &
	\ LSET DATA.BUFF$=B0$ &
		! GET THE CLUSTER CONTAINING THE BLOCK IF NECESSARY. &
		! RETURN THE DATA. &

17110	FNEND &
		! END OF FNGET.CLU.2$(T0) &

17120	! &
	! &
	! &
	!	    P U T    B L O C K    T O    D E V I C E &
	! &
	!	W I T H    C L U S T E R S I Z E    2    ( R P 0 2 ) &
	! &
	! &
	!	     F N P U T . C L U . 2 % ( C H % , T 2 ) &
	! &
	! &
	! &
	! FUNCTION:	OUTPUTS DATA.BUFF$ (512 BYTES) TO A DEVICE HAVING &
	!		CLUSTER SIZE 2.  THE ROUTINE DOES AN ACTUAL DISK &
	!		WRITE ONLY WHEN THE SECOND BLOCK OF THE CLUSTER &
	!		IS BEING WRITTEN OR WHEN THE LAST BLOCK OF A FILE &
	!		IS BEING WRITTEN.  A READ IS DONE IF NECESSARY &
	!		AT THE BEGINNING OR END OF A FILE TO AVOID &
	!		CLOBBERING THE OTHER HALF OF THE CLUSTER IF IT &
	!		RESIDES IN ANOTHER FILE.  THE DEVICE MUST BE &
	!		OPEN ON CHANNEL 2 WITH A BUFFERSIZE OF 1024 BYTES. &
	! &
	! PARAMETERS:	CH%	THE CHANNEL ON WHICH TO PUT THE BLOCK. &
	!		T2	THE BLOCK NUMBER TO PUT. &
	! &
	! LOCAL &
	! VARIABLES &
	! USED:		T0%	THE CLUSTER NUMBER INVOLVED. &
	!		EQ%	=0  -> 1ST BLOCK IN CLUSTER IS INVOLVED. &
	!			=-1 -> 2ND BLOCK IN CLUSTER IS INVOLVED. &
	! GLOBAL &
	! VARIABLES &
	! USED:	    DATA.BUFF$	THE DATA TO BE WRITTEN. &
	!		T0	RECORD OFFSET IN FILE WE ARE WORKING ON &
	!			AS USED IN FOR LOOP IN SUBROUTINE AT 11000. &
	!		T1	OFFSET OF LAST RECORD IN FILE AS USED &
	!			IN FOR LOOP IN SUBROUTINE AT LINE 11000. &
	! &
	! RETURNS:	NOTHING MEANINGFUL. &
	! &
	DEF* FNPUT.CLU.2%(CH%,T2) &
	\ CH%=(CH% AND 255%) &
	\ T0%=T2/2. &
	\ EQ%=(T2<>2.*T0%) &
	\ FNPUT.CLU.2%=FNBUFF%(2%,1024%) &
	\ OPEN "_"+DEV$(CH%) AS FILE CH%, RECORDSIZE 1024% UNLESS T0% &
	\ GET #CH%+SWAP%(2%), RECORD T0% &
		IF (T0=0. AND EQ%) OR (T0=T1 AND NOT EQ%) &
	\ FIELD #2%, 512%*(-EQ%) AS B0$, 512% AS B0$ &
	\ LSET B0$=DATA.BUFF$ &
	\ OPEN "_"+DEV$(CH%) AS FILE CH%, RECORDSIZE 1024% UNLESS T0% &
	\ PUT #CH%+SWAP%(2%), RECORD T0% IF EQ% OR T0=T1 &
		! READ THE OLD CLUSTER IF NECESSARY. &
		! MOVE THE BLOCK INTO THE BUFFER. &
		! REOPEN THE DEVICE IF WE HAVE TO READ/WRITE THE FIRST &
		!	CLUSTER IN THE DEVICE (TO ZERO IT). &
		! RE-WRITE THE CLUSTER WITH THE NEW BLOCK IF NECESSARY. &
		! NOTE THAT WE ALWAYS USE CHANNEL 2 FOR THE BUFFER: &
		!	IF WE ARE OUTPUTTING TO CHANNEL 2, WE HAVE &
		!		ALREADY OPENED THE RP02 ON THE CHANNEL &
		!		WITH A BUFFERSIZE OF 1024, SO THE &
		!		FNBUFF% CALL IS A NO OP. &
		!	IF WE ARE OUTPUTTING TO CHANNEL 1, WE ARE &
		!		DOING A ZERO OR SQUEEZE, SO WE CAN &
		!		OPEN THE NULL DEVICE ON CHANNEL 2 &
		!		(FNBUFF%) AND NOT WORRY ABOUT IT. &

17130	FNEND &
		! END OF FNPUT.CLU.2%(CH%,T2) &
	&

17200	! &
	!	F N P R I V % ( )   F U N C T I O N &
	! &
	! Function checks to see if the program or job has the privilege &
	! passed as the argument. &
	! &
	! Return value: &
	! &
	!	0 = Does NOT have the privilege &
	!      -1 = Does have the privilege &
	&

17210	DEF* FNPRIV%(PRIV$) &
	\	TMP$=MID(SYS(CHR$(6%)+CHR$(32%)+CHR$(1%)+ &
			 STRING$(3%,0%)+PRIV$),3%,1%) &
	\	FNPRIV%=(ASCII(TMP$)=0%) &
	\ FNEND &
	&

19000	! &
	! &
	! &
	!	E R R O R    H A N D L I N G    R O U T I N E &
	! &
	! &
	! &
	ON ERROR GOTO 0 IF ERL=19010% &
	\ RESUME 19010 &
		! RESUME NEXT LINE UNLESS WE GOT AN ERROR THERE. &

19010	DUMMY$=SYS(PRIV.OFF$) IF LEN(PRIV.OFF$) &
	\ GOTO 32767 IF (ERL=1100% AND ERR=11%) OR (LINE=1100% AND ERR=28%) &
	\ GOTO 9000 IF ERR=28% &
	\ RETURN IF ERL=14310% OR ERL=14320% OR ERL=14400% OR ERL=14500% &
		OR ERR=11% AND (ERL=12400% OR ERL=12800%) &
	\ ERR.MSG$=FNE$(ERR) &
	\ IF ERL=15400% THEN &
		ERR.MSG$=ERR.MSG$+DASH$+T0$ &
	\	GOTO 15430 &
		! EXIT IF USER CTRL/Z OR CTRL/C TO "FIT>" PROMPT. &
		! GO TO "EXIT OR REPORMPT" IF CTRL/C ELSEWHERE. &
		! CONTINUE, RETURN NO ERROR MESSAGE IF IF: &
		!	ERROR IN SETTING COMPILED BIT ON RSTS FILE. &
		!	RSTS FILE OR ACCOUNT NOT FOUND. &
		!	USER CTRL/Z TO A "Really?" PROMPT. &
		! ERROR IN FILENAME STRING SCAN OF USER INPUT. &

19020	IF ERL=12400% OR ERL=12410% OR ERL=13100% OR ERL=13200% &
	OR (ERL>=14100 AND ERL<=14300%) OR ERL=11020% OR ERL=11030% &
	OR ERL/1000%=17% THEN &
		CH%=1% IF ERL=11020% OR CH%=6% &
	\	CH%=(OUT.CH% AND 255%) IF ERL=11030% OR CH%=7% &
	\	ERR.MSG$=ERR.MSG$+DASH$+FNBUILD$((CH% AND 255%)+2%,-1%) &
	\	GOTO 17010 IF ERL=17000% &
	\	GOTO 17030 IF ERL=17020% &
	\	GOTO 17110 IF ERL=17100% &
	\	GOTO 17130 IF ERL=17120% &
	\	RETURN &
		! A DEVICE ERROR.  RETURN THE RSTS/E ERROR MESSAGE &
		! FOLLOWED BY THE FILESPEC.  RETURN FROM ERRANT &
		! FUNCTION OR SUBROUTINE. &

19030	PRINT FNRET$;ERR.MSG$;" at line";ERL;"in FIT ";IDENT.STG$ &
	\ GOTO 32767 &
		! THAT WAS A BAD ONE. &

30000	! &
	! &
	! &
	!	C C L    E N T R Y    P O I N T &
	! &
	! &
	! &
	T0$=SYS(CHR$(7%)) &
	\ COMM.LINE$=RIGHT(T0$,4%) &
	\ T0%=ASCII(COMM.LINE$) &
	\ COMM.LINE$=CVT$$(COMM.LINE$,8%) &
	\ ENTRY.TYP%=2% IF LEN(COMM.LINE$) &
	\ GOTO 1000 IF LEFT(T0$,3%)="FIT" &
		AND (T0%=32% OR T0%=47% OR ENTRY.TYP%=0%) &
	\ PRINT "?Illegal CCL entry - ";T0$ &
	\ GOTO 32767 &
		! GET CORE COMMON. &
		! IF NO COMMAND THERE, FAKE A RUN ENTRY. &
		! IF AN ILLEGAL COMMAND THERE, SAY SOMETHING. &
		! IF ALL O.K., GO START. &

32767	END
