Google
 

Trailing-Edge - PDP-10 Archives - RMS-10_T10_704_FT2_880425 - 10,7/rms10/rmssrc/rmsosb.b36
There are 6 other files named rmsosb.b36 in the archive. Click here to see a list.
MODULE OSCALL =

BEGIN

GLOBAL BIND	OSCV = 1^24 + 0^18 + 2;	!EDIT DATE: 20-DEC-79

%([

FUNCT:	THIS MODULE CONTAINS ALL OPERATING-SYSTEM CALLS EXCEPT
	FOR THOSE MODULES WHOSE OVERALL FLOW IS MONITOR-DEPENDENT,
	NAMELY RMSOPN AND MORE?.

AUTHOR:	S. COHEN, A. UDDIN

THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.

!COPYRIGHT (C) 1979, 1980 BY DIGITAL EQUIPMENT CORPORATION


**********	TABLE OF CONTENTS	**************


	ROUTINE			FUNCTION
	=======			========
	ABORTFILE		ABORTIVELY CLOSES FILE
	ADJEOF			ADJUST EOF PTR OF FILE
	ASCREAD			READ STREAM OF BYTES FROM SPEC FILE
	ASCWRITE		WRITE STREAM OF BYTES TO SPEC FILE
	CLOSEFILE		CLOSE THE FILE
	CREPAGE			CREATES A PAGE ON THE TOPS-10(PAGE. UUO)
	DATOFILE		RETURN DATES (EG. CREATE TIME) OF FILE
	DEVCHAR			RETURNS DEV CHAR WORD IN TOPS-20 FMT
	IOERROR			MAP JSYS I/O ERROR TO RMS STATUS CODE
	KILLPAGE		REMOVE PAGE FROM PROCESS (DO IO ON 10)?
	LOFFALL			CLEAR ALL THE LOCKS
	NEXTPAGE		RETS NEXT EXISTING P# IN FILE (IF NONE RETS -1)
	PAGEXIST		RETS TRUE IF SPECIFIED PAGE EXISTS
	PAGIN			READS ONE OR MORE PAGES INTO MEMORY
	PAGOUT			WRITES PAGES TO DISK
	POSASCFIL		SET THE CURRENT LOC OF FILE TO BEGIN OR END
	READTTY			READ STREAM OF ASCII BYTES FROM TTY
	SIZEFILE		RETURNS # OF BYTES IN SPECIFIED FILE
	TRUNCFILE		DELETE TRAILING PAGES FROM A FILE


*************************************************
*						*
*		NEW REVISION HISTORY		*
*						*
*************************************************

****************** Start RMS-10 V1.1 *********************
********************* TOPS-10 ONLY ***********************

PRODUCT	MODULE	 SPR
 EDIT	 EDIT	 QAR		DESCRIPTION
======	======	=====		===========

107	 2	10-32354	(RMT, 12/2/85) PAGOUT code for TOPS-10 is
				wrong.  Always output whole page. V3 edit
				64.

112	 3	Dev		(WXD, 3/28/86) When paging in a file, clear
				all pages rather than just a single page.

	***** END OF REVISION HISTORY *****
])%
	%([	FORWARD DECLARATIONS		])%




	FORWARD	ROUTINE


		ABORTFILE:	NOVALUE,
		ADJEOF:		NOVALUE,
		CLOSEFILE:	NOVALUE,	
		crepAGE:	NOVALUE,
		DATOFILE:	NOVALUE,
		DEVCHAR,
		IOERROR:	NOVALUE,
		KILLPAGE:	NOVALUE,
		LOFFALL:	NOVALUE,
		NEXTPAGE,
		PAGEXIST,
		PAGIN:		NOVALUE,
		PAGOUT:		NOVALUE,
		POSASCFIL:	NOVALUE,
		READTTY,
		SIZEFILE,
		TRUNCFILE:	NOVALUE;



	%([ MODULE-LEVEL DECLARATIONS ])%

REQUIRE 'RMSREQ';
REQUIRE	'RMSOSD';				!THIS MODULE IS OS-DEPENDENT

EXTDECLARATIONS;

! ABORTFILE
! ======

!	CLOSES A  FILE ABORTIVELY

! INPUT:	1. VALUE OF JFN.
!		2. ADDR OF USER'S FAB.


! OUTPUT:	NONE

GLOBAL ROUTINE ABORTFILE ( FILE_ID, USER_FAB ) : NOVALUE=
BEGIN

!	ARGUMENT ( FILE_ID, VALUE );
!	ARGUMENT ( USER_FAB, POINTER );
MAP	USER_FAB:	POINTER;
REGS;

	TRACE ( 'ABORTFILE' );

	%IF TOPS10
	%THEN
		!DO NOT SUPPORT USER JFN ON 10
		AC1 = .FILE_ID;		!GET FILE TO CLOSE
		DO_UUO( RESDV$(AC1));
	%FI

	%IF TOPS20
	%THEN
		AC1 = .FILE_ID OR CZ_ABT;			! SET ABORT BIT FOR CLOSF JSYS
		IF .USER_FAB [ FABJFN ] ISNT ZERO		! HE GAVE US A JFN
		THEN
			AC1 = .AC1 OR CO_NRJ;			! DON'T RELEASE JFN
		IF JSYS (-1, CLOSF, AC1) IS FALSE	!CLOSE THE FILE
		THEN BEGIN				!OOPS
			IF .AC1 ISNT ADDR(CLSX1)	!ONLY GTJFN DONE?
			THEN RETURN;			!NO, BUT IGN ERR SO AS
							!NOT TO HIDE ORIG ERR
			AC1 = .FILE_ID;			!GET JFN AGAIN
			JSYS (-1, RLJFN, AC1);		!RELEASE JFN
		END;
	%FI
	RETURN;

END; %( OF ABORTFILE ROUTINE )%


! ADJEOF
! ======
!
! ROUTINE TO ADJUST THE FILE'S EOF POINTER IN THE FILE DESCRIPTOR BLOCK (FDB)
!	THIS ROUTINE IS CALLED ONLY IF WE HAVE WRITTEN INTO THE FILE
!	WITH THE CURRENT STREAM, OR IF THERE WAS A $TRUNCATE DONE ON
!	THE STREAM. THIS ROUTINE MUST CHECK THE FILE EOF POINTER IN
!	THE FDB AND DETERMINE IF OUR NEW EOF IS GREATER THAN THE
!	OLD ONE. IF SO, THE FDB EOF IS CHANGED; IF NOT, NO ACTION
!	IS PERFORMED.
!
! INPUT:
!	FILE_ID		=	FILE ID
!	OUR_EOFBYTE	=	THE EOF BYTE THAT WE HAVE WRITTEN INTO
!	TRUNC_FLAG	=	FLAG TO INDICATE IF TRUNCATE WAS DONE
! OUTPUT:
!	<NO STATUS RETURNED>
!
! NOTES:
!
!	1.	THERE IS CURRENTLY NO SYNCHRONIZATION ON THE OPERATION
!		OF UPDATING THE FILE'S EOF POINTER. THUS, BETWEEN THE
!		TIME THAT WE CHECK THE FDB VALUE AND THEN WE CHANGE IT,
!		SOMEONE ELSE COULD SLIP IN AND CHANGE IT ALSO. HOWEVER,
!		THIS IS NOT REALLY A PROBLEM SINCE THE EOF WILL BECOME
!		CORRECT AGAIN AS SOON AS SOMEONE WRITES INTO THE FILE.
!		ALSO, THE QUEUEING OVERHEAD OF THE LOCK TO ACHIEVE
!		MUTUAL EXCLUSION IS EXCESSIVE AND IS NOT DEEMED SUFFICIENT.
!

GLOBAL ROUTINE ADJEOF ( FILE_ID, OUR_EOFBYTE, TRUNC_FLAG ): NOVALUE =
BEGIN
!	ARGUMENT	( FILE_ID, VALUE );
!	ARGUMENT	( OUR_EOFBYTE, VALUE );
!	ARGUMENT	( TRUNC_FLAG, VALUE );
LOCAL
    EOFBYTE;	! THE REAL EOF BYTE IN THE FDB

REGS;


	TRACE ('ADJEOF');

	%IF TOPS10
	%THEN
		!ON THE 10, THE MONITOR MAINTAINS COMPLETE CONTROL OF EOF
		!SO THIS ROUTINE JUST RETURNS ON 10
	%FI

	%IF TOPS20
	%THEN

	%([ READ THE FILE FDB EOF POINTER ])%

		AC1 = .FILE_ID;			! SET UP ACS FOR GTFDB
		AC2 = 1 ^ 18 OR $FBSIZ;	! ONE WORD TO READ, NAMELY EOF
		AC3 = ADDR (EOFBYTE);		! PLACE TO READ IT INTO
		DO_JSYS ( GTFDB );

	%([ SHOULD WE UPDATE IT? ])%

	IF ( .OUR_EOFBYTE GTR .EOFBYTE ) 
		OR
	   ( .TRUNC_FLAG ISON ) THEN		! OR IF WE DID A $TRUNCATE
	BEGIN
		AC1 = .FILE_ID OR CF_NUD;			! FILE ID AND NO UPDATE
		AC1 < 18, 9 > = $FBSIZ ;	! DISPLACEMENT IN FDB
		AC2 = ALLONES;				! MASK
		AC3 = .OUR_EOFBYTE;			! NEW VALUE
		DO_JSYS ( CHFDB )
	END;
	%FI

	%([ TELL US ABOUT IT ])%

	LOOKAT ( '	HYBYTE = ', OUREOFBYTE );
	LOOKAT ( '	EOF # = ', EOFBYTE );

	RETURN 
END;	%(OF ADJEOF)%

! ASCREAD
! =======
!	READ IN BUCKET ENCOMPASSED BY SPECIFIED BYTE IN FILE

! INPUT:	1. FILE ID 
!		2. NUMBER OF BKT WE WANT TO READ
!		3. ADDRESS OF BUFFER TO READ INTO
!		4. LENGTH OF BUFFER IN CHARS

! OUTPUT:	1. COUNT OF CHARS READ
!
! NOTES:	1. ASSUMES THAT A FILE IS ALWAYS READ WITH SAME SIZE BUFFER
!
!
GLOBAL ROUTINE ASCREAD ( FILE_ID, BKT_TO_USE, BUF_PTR, CH_IN_BUF ) :=
BEGIN

LOCAL
	TEMP;
LOCAL
	W_IN_BUF,			!WORDS IN A BUFFER
	COUNT,				!# OF WORDS TO READ
	FOPBLK: VECTOR[2],		!FILOP BLK FOR NON-FILE-MGT TASKS
	IOWDLST: VECTOR[2];		!HOW MUCH, WHERE TO DO I/O IN FILE
EXTERNAL
	ACC$1,			! GLOBALS USED TO STORE JSYS AC'S
	ACC$2,
	ACC$3;

REGS;

	TRACE ( 'ASCREAD' );

	W_IN_BUF = (.CH_IN_BUF+4)/5;		!GET BUFF SIZE IN WORDS

	IF .BKT_TO_USE NEQ .FST [FSTSEQBKT]	!POSIT TO RIGHT PLACE?
	THEN BEGIN				!NO

	%IF TOPS10
	%THEN
		COUNT = .W_IN_BUF/128;		!BLKS/BKT=WDS/BKT / WDS/BLK
		FOPBLK[0] = .FILE_ID^18 OR $FOUSI;	!FILE AND FUNCTION
		FOPBLK[1] = (.COUNT*.BKT_TO_USE) + 1;	!CONV BKT# TO BLK# (1ST BLK=1)
		AC1=2^18 OR FOPBLK;		!PTR TO ARGLST
		IF NOT UUO(1, FILOP$(AC1))
		THEN
			BEGIN
			$CALL ( IOERROR, .FILE_ID );	!IF RETS, THEN JUST EOF
			RETURN 0;		!ENTIRE PAGE BEYOND EOF
			END;
	END;					!END BKT NEW SEQBKT

		FOPBLK[0] = .FILE_ID^18 OR $FOINP;	!RESET OPERATION CODE
		FOPBLK[1] = IOWDLST;		!STORE PTR TO IOWD LIST
		IOWDLST[0] = (-.W_IN_BUF)^18	!# OF WORDS TO READ
			 OR .BUF_PTR-1;		!PICKUP ADDR OF BLK
		IOWDLST[1] = 0;			!TERM I/O CMDS
		AC1=2^18 OR FOPBLK;		!RE-INIT ARG PTR
		IF NOT UUO(1, FILOP$(AC1))
		THEN
			BEGIN
			FST [FSTSEQBKT] = -1;	!AFT ERR, TREAT FIL POS AS UNDEF
			$CALL ( IOERROR, .FILE_ID );	!IF RETS, THEN JUST EOF
			RETURN ($CALL (SIZEFILE,.FILE_ID) MOD .CH_IN_BUF);
						!SET CHARS IN BUF BY BRUTE FORCE
			END;
		IF .SIZEOFFILE LSS .W_IN_BUF*(.BKT_TO_USE + 1)
		THEN
			BEGIN
			FST [FSTSEQBKT] = -1;		! AFT EOF,TREAT FIL POS AS UNDEFINED
			RETURN ($CALL (SIZEFILE,.FILE_ID) MOD .CH_IN_BUF);
							! SET CHARS BY BRUTE FORCE
			END
		ELSE
			TEMP = .CH_IN_BUF;
	%FI

	%IF TOPS20
	%THEN
		TEMP = .BKT_TO_USE * .CBD[BKDBKTSIZE] * CH_IN_P;	!POS OF 1ST BYTE IN BKT
		IF SEQUENCED
		THEN
			TEMP = (.TEMP+4)/5;
		IF NOT TTY
		THEN
			BEGIN
			AC1 = .FILE_ID;		! JFN OF THE FILE
			AC2=.TEMP;
			DO_JSYS ( SFPTR );
			END;
	END;					!END BKT POS OPTIM
		IF SEQUENCED
		THEN
			BEGIN
			TEMP = POINT (.BUF_PTR, 36, 36 );
			AC3 = -( .CH_IN_BUF + 4 ) / 5
			END  %( OF SETUP SOUT STUFF FOR LSA FILE )%
		ELSE
			BEGIN
			TEMP = POINT (.BUF_PTR, 36, 7);
			AC3 = -.CH_IN_BUF;
			END;	%(OF ASCII STREAM )%

		AC1 = .FILE_ID;			! SET UP ACS FOR SIN
		AC2 = .TEMP;			!GET BYTE PTR
		AC4 = 0;
		IF NOT JSYS ( -1, SIN, AC1, AC2, AC3, AC4 )  THEN
			BEGIN
			ACC$1 = .AC1;			! SAVE JSYS REGISTERS
			ACC$2 = .AC2;
			ACC$3 = .AC3;
			$CALL ( IOERROR, .FILE_ID )		! PROCESS JSYS ERROR
			END
		ELSE
			ACC$3 = .AC3;			! NO OF BYTES TO READ
		IF SEQUENCED 
		THEN TEMP = -.ACC$3 * ASCIIBYTPERWORD	! CONVERT WORDS TO CHARACTERS FOR LSA FILE
		ELSE TEMP = -.ACC$3;			! GET CHARS READ FOR ASCII FILE
		TEMP = .CH_IN_BUF - .TEMP;		!CHARS READ = MAX - RESIDUE

	%FI
	CURRENTFILEPAGE = .BKT_TO_USE*ASCIIBKTSIZE;	!KEEP TRACK OF CURR P
	FST [FSTSEQBKT] = .CURRENTFILEPAGE + ASCIIBKTSIZE;	!NOW AFTER IT
	RETURN	.TEMP

END; %( OF ASCREAD ROUTINE )%

! ASCWRITE
! =========
!	WRITE A STREAM OF BYTES TO THE SPECIFIED FILE

! INPUT:	1. FILE ID
!		2. NUMBER OF BKT WE WANT TO WRITE
!		3. POINTER TO BUFF TO OUTPUT IN CALLERS ADDRESS SPACE
!		3. LENGTH OF STRING TO OUTPUT

! OUTPUT:	<NONE>
!
!
!
!
GLOBAL ROUTINE ASCWRITE ( FILE_ID, BKT_TO_USE, BUF_PTR, CH_IN_BUF ) :NOVALUE=
BEGIN

EXTERNAL
	ACC$1,		! GLOBALS USED TO STORE JSYS AC'S
	ACC$2,
	ACC$3;
LOCAL
	N,			!NUM OF BITS OF CRUFT
	LW,			!PTR TO LAST PARTIAL WD IN BUF
	TEMP;
LOCAL
	COUNT,				!# OF WORDS TO WRITE
	W_IN_BUF,			!DATA WORDS IN THIS BUFFER
	FOPBLK: VECTOR[2],		!FILOP BLK FOR NON-FILE-MGT TASKS
	IOWDLST: VECTOR[2];		!HOW MUCH, WHERE TO DO I/O IN FILE
REGS;

	TRACE ( 'ASCWRITE' );

	%IF TOPS10
	%THEN
		IF TTY				!DO HACK FOR TTY OUTPUT
		THEN BEGIN			!HERE WE GO
			$CALLM (TTYHACK, .BUF_PTR, .CH_IN_BUF);
						!DO ACTU OUTSTR
			RETURN;
		END;
	%FI					!TOPS10 TTY HACK

	W_IN_BUF = (.CH_IN_BUF+4)/5;		!GET WORDS OF DATA
	IF .BKT_TO_USE NEQ .FST [FSTSEQBKT]	!POSIT TO RIGHT PLACE?
	THEN BEGIN				!NO

	%IF TOPS10
	%THEN
		COUNT = ASCIIBKTSIZE * 4;	!BLKS/BKT =P/BKT * BLK/P
		FOPBLK[0] = .FILE_ID^18 OR $FOUSO;	!FILE AND FUNCTION
		FOPBLK[1] = (.COUNT*.BKT_TO_USE) + 1;	!CONV BKT# TO BLK# (1ST BLK=1)
		AC1=2^18 OR FOPBLK;		!PTR TO ARGLST
		DO_FILOP;			!POSITION THE FILE
	END;					!END BKT NEW SEQBKT
		N = .CH_IN_BUF MOD 5;		!0 OR NUM CHARS IN PART USED WD
		IF .N NEQ 0			!WORD-ALIGNED?
		THEN BEGIN
		 LW = .BUF_PTR+.W_IN_BUF-1;	!SETUP PTR TO LAST PARTIAL WD
		 N = 36 - .N*7;			!PREP TO ELIM CRUFT IN LAST WD
		 .LW = (..LW^-.N)^.N;		!SHIFT CRUFT OUT AND 0'S BK IN
		END;

		FOPBLK[0] = .FILE_ID^18 OR $FOOUT;	!RESET OPERATION CODE
		FOPBLK[1] = IOWDLST;		!STORE PTR TO IOWD LIST
		IOWDLST[0] = (-.W_IN_BUF)^18	!# OF WORDS TO READ
			 OR .BUF_PTR-1;		!PICKUP ADDR OF BLK
		IOWDLST[1] = 0;			!TERM I/O CMDS
		AC1=2^18 OR FOPBLK;		!RE-INIT ARG PTR
		DO_FILOP;			!READ THE PAGE(S)
		IF .BKT_TO_USE*.COUNT + .W_IN_BUF GTR .SIZEOFFILE	!EXTENDING?
		THEN SIZEOFFILE = .BKT_TO_USE*.COUNT + .W_IN_BUF;	!YES
	%FI

	%IF TOPS20
	%THEN
		TEMP = .BKT_TO_USE * .CBD[BKDBKTSIZE] * CH_IN_P;	!POS OF 1ST BYTE IN BKT
		IF SEQUENCED
		THEN
			TEMP = (.TEMP+4)/5;
		IF NOT TTY
		THEN
			BEGIN
			AC1 = .FILE_ID;		! JFN OF THE FILE
			AC2=.TEMP;
			DO_JSYS ( SFPTR );
			END;
	END;					!END BKT POS OPTIM
		IF SEQUENCED
		THEN	BEGIN
			TEMP = POINT (.BUF_PTR, 36, 36 );
			AC3 = -( .CH_IN_BUF + 4 ) / 5
		END  %( OF SETUP SOUT STUFF FOR LSA FILE )%
		ELSE	BEGIN
			TEMP = POINT (.BUF_PTR, 36, 7);
			AC3 = -.CH_IN_BUF;
		END;	%(OF ASCII STREAM )%

		AC1 = .FILE_ID;			! SET UP ACS FOR SOUT
		AC2 = .TEMP;			!BYTE PTR
		AC4 = ZERO;
		IF NOT JSYS ( -1, SOUT, AC1, AC2, AC3, AC4 ) THEN
		BEGIN
			ACC$1 = .AC1;			! SAVE JSYS REGISTERS
			ACC$2 = .AC2;
			ACC$3 = .AC3;
			$CALL ( IOERROR, .FILE_ID )
		END;

	%FI
	CURRENTFILEPAGE = .BKT_TO_USE*ASCIIBKTSIZE;	!KEEP TRACK OF CURR P
	FST [FSTSEQBKT] = .CURRENTFILEPAGE + ASCIIBKTSIZE;	!NOW AFTER IT
	RETURN

END; %( OF ASCWRITE ROUTINE )%

! CLOSEFILE
! =========

!	CLOSES A  FILE

! INPUT:	1. FILE ID OF THE FILE TO BE CLOSED (JFN ON 20)
!		2. POINTER TO USER'S FAB.

! OUTPUT:	1. TRUE IF MON SUCCEEDED, ELSE ERROR CODE

GLOBAL ROUTINE CLOSEFILE( FILE_ID, USER_FAB) : NOVALUE=
BEGIN
!	ARGUMENT ( FILE_ID, VALUE);
!	ARGUMENT ( USER_FAB, POINTER);
MAP	USER_FAB:	POINTER;

LOCAL
	TEMP;

REGS;

	TRACE ( 'CLOSEFILE' );

	%IF TOPS10
	%THEN
		!USER SUPPLIED JFN NOT SUPPORTED ON 10
		TEMP = .FILE_ID^18 OR $FOREL;	!RELEASE FILE
		AC1 = 1^18 OR TEMP;		!ARGPTR
		DO_FILOP;			!DO THE WORK
	%FI

	%IF TOPS20
	%THEN

	%([ WE WILL  SET UP THE FLAGS AND THE JFN FOR THE CLOSF JSYS.
	   THEN, WE WILL CHECK TO SEE IF THE USER WANTS US TO KEEP
	   HIS JFN FOR HIM WHEN WE CLOSE THE FILE. ])%

	TEMP = .FILE_ID OR CZ_NUD OR CO_NRJ;	! SET UP ARG TO CLOSF JSYS
	IF .USER_FAB [FABJFN] IS ZERO
	THEN					! HE DIDNT WANT TO SAVE THE JFN
		CLRFLAG ( TEMP, CO_NRJ );

	%([ CLOSE THE FILE  ])%


	AC1 = .TEMP;
	DO_JSYS ( CLOSF );
	%FI

	RETURN;

END; %( OF CLOSEFILE ROUTINE )%

! CREPAGE
!============
!	CREATES A PAGE ON THE TOPS-10. A NO-OP ON THE -20.
! 
! INPUT:	1. PAGE NO.OF THE FIRST PAGE OF THE BLOCK TO BE CREATED
!		2. NO OF PAGES IN THE BLOCK
!
! 
! OUTPUT:	<NONE>
!
!
GLOBAL ROUTINE crepAGE ( PAGE_NUM, PAGES  ): NOVALUE=
BEGIN
!
!	ARGUMENT ( PAGE_NUM, VALUE);
!	ARGUMENT ( PAGES, VALUE );

REGS;
LOCAL
	ARG:	VECTOR[2];	! ARGUMENT BLOCK FOR PAGE$ UUO

	TRACE ( 'CREPAGE' );

	%IF TOPS10
	%THEN
		ARG[0] = 1;				! ARG=(NO OF ARGS -1)
		INCR I FROM .PAGE_NUM TO .PAGE_NUM + .PAGES -1 
		DO
			BEGIN
			ARG[1] = .I;			! CREATE FUNC AND PAGE NO.
			AC1 = $PAGCD ^ 18 OR ARG;	!SET UP AC1
			DO_UUO ( PAGE$(AC1));
			END;
	%FI

	%IF TOPS20
	%THEN
		!WHEREAS THE 10 REQS AN EXPLIC OS CALL TO CRE A PROCESS PAGE,
		!THE 20 DOES IT AUTOMATICALLY WHEN YOU ACCESS A WORD IN THE PAGE
	%FI


	RETURN
END;	%( OF crepAGE ROUTINE )%
! DATOFILE
! =========
!	RETURNS DATES AND TIMES ASSOCIATED WITH THE SPECIFIED FILE.

! INPUT:	1. FILE ID OF THE FILE IN FST.
!		2. POINTER TO A BLOCK THAT WILL CONTAIN DATES
!		3. SIZE OF THE BLOCK
!
!
!
! OUTPUT:	INDIRECTLY, DATES AND TIMES IN THE BLOCK
!
!
!
!
!
GLOBAL ROUTINE DATOFILE ( FST_JFN, DATE_BLK, DATE_BLK_SIZ ) :NOVALUE=
BEGIN
!	ARGUMENT ( FST_JFN, VALUE);
!	ARGUMENT ( DATE_BLK, BASEADD);
!	ARGUMENT ( DATE_BLK_SIZ, VALUE);


MAP	DATE_BLK:	POINTER;
REGS;		! DECLARE ALL REGISTERS FOR USE BY MON CALLS

	TRACE ( 'DATOFILE' );

	%IF TOPS10
	%THEN

	%([** RETURN DATES WHICH WERE SAVED PREVIOUSLY FROM THE LOOKUP BLOCK **])%

	DATE_BLK [ 0,wrd ] = DATELASTACC;
	DATE_BLK [ 1,wrd ] = CREATIME;

	%FI

	%IF TOPS20
	%THEN
%([	SET UP AC'S FOR RFTAD JSYS	])%
	AC1 = .FST_JFN;			! FILE_ID
	AC2 = .DATE_BLK;		! ADDR OF DATE BLOCK
	AC3 = .DATE_BLK_SIZ;		! AND ITS SIZE
	DO_JSYS ( RFTAD );		! ON RETURN DATE_BLK WILL HAVE DATES AND TIMES
	%FI


	RETURN

END; %( OF DATOFILE ROUTINE )%

! DEVCHAR
! =========
!	RETURNS DEVCHAR FLAGS IN 20 FORMAT

! INPUT:	1. JFN OF THE DESIRED DEVICE
!
! OUTPUT:	THE 20-FORMAT FLAG WORD
!
GLOBAL ROUTINE DEVCHAR (FILID) =
BEGIN
	ARGUMENT ( FILID, VALUE);

REGS;		! DECLARE ALL REGISTERS FOR USE BY MON CALLS

	TRACE ( 'DEVCHAR' );

	%IF TOPS10
	%THEN
		AC1 = .FILID;		!PICKUP 6BIT DEV NAME
		UUO(0,DEVCHR(AC1));	!DO THE UUO
		AC2 = 1^18;		!DEFAULT VALUE (ILLEGAL DEV)
		IF CHKFLAG(AC1,DV$DSK) ISON THEN AC2<18,9>=DVDSK;
		IF CHKFLAG(AC1,DV$MTA) ISON THEN AC2<18,9>=DVMTA;
		IF CHKFLAG(AC1,DV$TTY) ISON THEN AC2<18,9>=DVTTY;
		IF CHKFLAG(AC1,DV$IN) ISON THEN SETFLAG(AC2,DVIN);
		IF CHKFLAG(AC1,DV$OUT) ISON THEN SETFLAG(AC2,DVOUT);
		IF CHKFLAG(AC1,DV$DIR) ISON THEN SETFLAG(AC2,DVDIR);
		IF CHKFLAG(AC1,DV$ASC) ISON THEN SETFLAG(AC2,DEVASN);
		RETURN .AC2;
	%FI

	%IF TOPS20
	%THEN
		AC1 = .FILID;		!IDENT FILE
		AC2 = ZERO;
		DO_JSYS ( DVCHR );
		RETURN .AC2;		!RET DEVICE FLAGS
	%FI

END; %( OF DATOFILE ROUTINE )%

! IOERROR
! =========
!
!  THIS ROUTINE PROCESSES AN ERROR RETURN FROM EITHER  THE SIN JSYS
!	OR THE SOUT JSYS. EACH MONITOR ERROR CODE IS MAPPED INTO
!	A CORRESPONDING RMS-20 ERROR CODE. THE MAPPING IS AS FOLLOWS:
!
!		MONITOR CODE	MEANING		RMS-20 CODE
!		============	=======		===========
!
!		IOX4		EOF		<NO MAPPING DONE>
!		IOX5		DATA ERROR	ER$RER, ER$WER
!		ALL OTHERS	INTERNAL BUG	ER$BUG
!

!
! INPUT:
!	1. JFN OF FILE THAT HAD IO ERROR
!
! OUTPUT:
!	<NONE>

! NOTES:
!
!	1.	THE STV FIELD WILL ALWAYS BE SET TO BE THE MONITOR CODE
!		RETURNED.
!
!	2.	THIS ROUTINE EXITS TO THE USER UNLESS THE ERROR WAS ER$EOF
!
GLOBAL ROUTINE IOERROR (FILE_ID): NOVALUE  =
BEGIN

LOCAL
	FOPARG: VECTOR[2],
	TEMP;
REGS;


	TRACE ( 'IOERROR ' );

	%IF TOPS10
	%THEN
		FOPARG[0] = .FILE_ID^18 OR $FOGET;	!GET STS
		AC1 = 1^18 OR FOPARG;		!ARG PTR
		DO_FILOP;			!RET STATUS
		TEMP = .AC1;			!PRESERVE STATUS BEF CLEAR IT
		FOPARG[0] = .FILE_ID^18 OR $FOSET;
		FOPARG[1] = $IODMP;		!JUST LEAVE IO MODE
		AC1 = 2^18 OR FOPARG;		!SETUP TO DO SETSTS
		DO_FILOP;			!DO IT
		IF CHKFLAG(TEMP,IO$EOF) ISON
		THEN RETURN;			!JUST EOF
		USRSTV = .TEMP;			!RET STATUS TO USER
		IF CHKFLAG(TEMP,IO$DER OR IO$DTE) ISON	!DATA ERROR?
	%FI
	
	%IF TOPS20
	%THEN
		AC1 = $FHSLF;		! PROCESS ID
		AC2 = 0;
		DO_JSYS ( GETER );	! GET THE LAST ERROR CODE
		TEMP = .AC2;

	%([ IS THIS AN EOF? IF SO, WE CAN IGNORE IT BECAUSE THE
	   USER PROBABLY WON'T SEE AN EOF UNTIL HE READS ALL THE
	   RECORDS IN THE CURRENT BUFFER. ])%

		IF .TEMP<RH> IS ADDR (IOX4)		! SUPPRESS BYTE POINTER
		THEN RETURN;				! RETURN ON  EOF

		USRSTV = .TEMP<RH>;			! SAVE CODE IN STV
		IF .USRSTV IS ADDR (IOX5 )
	%FI

	!COMMON 10/20 CODE
	THEN	%(IT'S A DATA ERROR)%
		BEGIN
		USRSTS = ER$RER;			! ASSUME READ ERROR
		IF CURRENTJSYS IS C$PUT THEN USRSTS = ER$WER
	END	%(OF IF DATA ERROR)%
	ELSE	BEGIN
		USRSTS = ER$BUG;			! SHOW IT'S A BUG
		IF $CALL (PRICHK, .USRSTV)		!DISPLAYING INT ERRS?
		THEN TXTOUT (RM$IOM, .USRSTV);		!YES, STREAM I/O ERR
	END;

	USEXITERR					!DO FAILURE RET TO USER

END; %( OF IOERROR )%

! KILLPAGE
! =======

!	UNMAPS (KILLS) A FILE'S PAGES IN A PROCESS.

! INPUT:	1. PAGE NUMBER OF THE FIRST PAGE OF THE BLOCK TO BE KILLED
!		2. NO. OF PAGES TO BE UNMAPPED

! OUTPUT:	<NONE>
!
!
!
!
GLOBAL ROUTINE KILLPAGE( PAGE_NUM, PAGES ) :NOVALUE=
BEGIN
!	ARGUMENT ( PAGE_NUM, VALUE );
!	ARGUMENT ( PAGES, VALUE );

REGS;

LOCAL
	ARG:	VECTOR[2];		!ARGUMENT BLOCK FOR PAGE$ UUO

	TRACE ( 'KILLPAGE' );

	%IF TOPS10
	%THEN
		ARG[0] = 1;		! ARG1 = (NO OF ARGS-1)
		INCR I FROM .PAGE_NUM TO .PAGE_NUM+.PAGES-1 
		DO
			BEGIN				!KILL 1 PAGE  AT A TIME
			ARG[1] = BITN(0) OR .I;		!IDENT CURR PAGE
			AC1 = $PAGCD^18 OR ARG;	!ARGBLK PTR
			DO_UUO (PAGE$(AC1));
			END;
	%FI

	%IF TOPS20
	%THEN			%( SET UP AC'S FOR PMAP JSYS )%
		AC1 = -1;			! KILL PAGE
		AC2 = ($FHSLF ^ 18 OR .PAGE_NUM);	! PROCESS HANDLE & PAGE NO.
		AC3 = (BITN ( 0 ) OR .PAGES);	! PAGES TO KILL
		DO_JSYS ( PMAP );

	%FI


	RETURN

END; %( OF KILLPAGE ROUTINE )%

! LOFFALL
! =======

!	TURNS OFF ALL LOCKS ON RECORDS OF A STREAM

! INPUT:	1. RESUEST ID. THIS IS THE SAME REQUEST ID USED TO LOCK THE RECORDS

! OUTPUT:	<NONE>
!
!
GLOBAL ROUTINE LOFFALL ( REQUEST_ID):NOVALUE =
BEGIN
!	ARGUMENT ( REQUEST_ID, POINTER );

REGS;

	TRACE ( 'LOFFALL' );

	%IF TOPS10
	%THEN
		AC1 = $DEQID ^ 18 OR .REQUEST_ID;
		DO_UUO ( DEQ$(AC1));
	%FI

	%IF TOPS20
	%THEN
		AC1 = $DEQID ;			!K ID
		AC2 = .REQUEST_ID;			! USE STREAM ID
		DO_JSYS ( DEQ );

	%FI
	RETURN;

END; %( OF LOFFALL ROUTINE )%

! NEXTPAGE
! ========
!	RETURNS THE NEXT USED PAGE IN THE FILE. APPLIES TO 20 ONLY.

! INPUT:	1. VALUE OF JFN IN FST.
!		2. PAGE NUMBER OF PAGE TO FIND.

! OUTPUT:	1. PAGE NUMBER, IF IT EXISTS
!		2. ELSE, FALSE
!
!
!
!
GLOBAL ROUTINE NEXTPAGE ( FST_JFN, PAGE_NO ) :=
BEGIN
!	ARGUMENT ( FST_JFN, VALUE );
!	ARGUMENT ( PAGE_NO, VALUE );


REGS;

	TRACE ( 'NEXTPAGE' );

	%IF TOPS10
	%THEN
		RETURN FALSE				!ALWAYS EOF ON 10
	%FI

	%IF TOPS20
	%THEN
		AC1 = .FST_JFN ^ 18 OR .PAGE_NO;		!FILE ID AND WHERE TO START SEARCH
		RETURN	IF JSYS ( -1, FFUFP, AC1, AC2 )	! DO THE SEARCH
			THEN
				.AC2			! RETURN PAGE # FOUND
			ELSE
				FALSE			! RETURN FALSE FOR EOF
	%FI


END; %( OF NEXTPAGE ROUTINE )%

! PAGEXIST
! ========
!	CHECKS TO SEE WHETHER A PARTICULAR PAGE OF A FILE EXISTS.

! INPUT:	1. FILE ID
!		2. PAGE NO. TO CHECK

! OUTPUT:	1. TRUE IF THE PAGE EXISTS.
!		2. FALSE OTHERWISE
!
!
!
!
GLOBAL ROUTINE PAGEXIST ( FILE_ID, P_TO_CHK ) :=
BEGIN
!	ARGUMENT ( FILE_ID, VALUE );
!	ARGUMENT ( P_TO_CHK, VALUE);


LOCAL
	ARG;		! ARGUMENT BLOCK FOR DISK$
REGS;

	TRACE ( 'PAGEXIST' );

	%IF TOPS10
	%THEN
		ARG = .FILE_ID;
		AC1 = $DULEN ^ 18 OR ARG;		! FUNC CODE & CHANNEL NO
		DO_UUO ( DISK$(AC1) );			! UUO RETURNS IN AC1 LAST BLOCK OF FILE
		RETURN	IF .AC1 GTR (.P_TO_CHK * 4)
			THEN
				TRUE			!AT LEAST 1 BLK OF PAGE EXISTS

			ELSE
				FALSE
	%FI

	%IF TOPS20
	%THEN
		AC1 = .FILE_ID ^ 18 OR .P_TO_CHK;	! JFN OF FILE ,, PAGE NO.
		AC2 = 0;
		DO_JSYS ( RPACS);
		RETURN	IF ( CHKFLAG (AC2,  PA_PEX) IS OFF)
			THEN 
				FALSE
			ELSE
				TRUE
	%FI


END; %( OF PAGEXIST ROUTINE )%

! PAGIN
! =====

!	READ ONE OR MORE CONSECUTIVE PAGES INTO MEMORY
!	DOES "IN" ON 10 AND "PMAP" ON 20

! INPUT:
!	FILE TO READ (JFN OR CHANNEL)
!	PAGE IN FILE TO READ (0 IS 1ST PAGE)
!	WHERE TO PUT IT (PAGE NUMBER)
!	LEVEL OF ACCESS TO PAGE
!	NUMBER OF PAGES (=512 WORDS) TO READ

! OUTPUT:	(IMPLICITLY)
!	DATA IN MEMORY PAGE(S)

GLOBAL ROUTINE PAGIN (FILID, FILPAGE, MEMPAGE, PAGACC, COUNT):NOVALUE =
BEGIN
!	ARGUMENT (FILID,VALUE);
!	ARGUMENT (FILPAGE,VALUE);
!	ARGUMENT (MEMPAGE,VALUE);
!	ARGUMENT (PAGACC,VALUE);
!	ARGUMENT (COUNT,VALUE);


LOCAL
	FOPBLK: VECTOR[2],		!FILOP BLK FOR NON-FILE-MGT TASKS
	IOWDLST: VECTOR[2];		!HOW MUCH, WHERE TO DO I/O IN FILE

REGS;

	TRACE ( 'PAGIN' );

	%IF TOPS10
	%THEN
		FOPBLK[0] = .FILID^18 OR $FOUSI;	!FILE AND FUNCTION
		FOPBLK[1] = (.FILPAGE)*4 + 1;	!CONV BYTE PTR TO BLK#
		AC1=2^18 OR FOPBLK;		!PTR TO ARGLST
		IF NOT UUO(1, FILOP$(AC1))	!POSIT THE FILE
		THEN BEGIN				!ENTIRE PAGE BEYOND EOF
			$CALL ( IOERROR, .FILID );	!IF RETS, THEN JUST EOF
			CLEAR ( .MEMPAGE ^ P2W, .COUNT*512 );	!PUT CANON VALS IN BUFF
			RETURN;
		END;

		IF .FILPAGE GEQ .SIZEOFFILE^W2P	!STUPID 10 DOES NOT 0 BUFFER
		THEN CLEAR (.MEMPAGE^P2W, .COUNT*512);	!PAST LAST USED BLK IN PAGE

		FOPBLK[0] = .FILID^18 OR $FOINP;	!RESET OPERATION CODE
		FOPBLK[1] = IOWDLST;		!STORE PTR TO IOWD LIST
		IOWDLST[0] = (-.COUNT*PAGESIZE)^18	!# OF WORDS TO READ
		 OR ((.MEMPAGE^P2W) - 1);	!CONVERT P# TO ADDRESS
		IOWDLST[1] = 0;			!TERM I/O CMDS
		AC1=2^18 OR FOPBLK;		!RE-INIT ARG PTR
		IF NOT UUO(1, FILOP$(AC1))	!READ PAGE
		THEN BEGIN			!ERR, PROB PARTIAL READ PAST EOF
			$CALL(IOERROR, .FILID);	!IF RETS, THEN JUST EOF
		END;
	%FI

	%IF TOPS20
	%THEN
		AC2=$FHSLF^18 OR .MEMPAGE;	!FORK & MEM PAGE #
		IF (.PAGACC AND AXWRT ) IS ZERO		%(IF INPUT MODE )%
		THEN
			AC3 = PM_RD OR PM_PLD		! READ ACCESS & PRELOAD
		ELSE
			AC3 = PM_RD OR PM_WR OR PM_PLD;	! ELSE WRITE ACCESS ALSO

		AC3 = .AC3 OR .COUNT OR BITN(0);		!ACCESS BITS & NUM OF P TO READ
		AC1 = .FILID ^ 18 OR .FILPAGE;		! JFN & PAGE #
		DO_JSYS(PMAP);
		$CALLM (OKCREATE, .MEMPAGE^P2W, .FILPAGE);
							!PREV ILL MEM READ
	%FI
	RETURN

END; %( OF PAGIN ROUTINE )%

! PAGOUT
! ======
!
!	UPDATE PAGES OF THE SPECIFIED FILE.

! INPUT:
! -----
!	1. FILE ID 
!	2. PAGE NUMBER IN FILE TO BE UPDATED.
!	3. [10 ONLY] THE CORRESPONDING PAGE NO. IN CORE, -1 IMPLIES JUST UPD RIB
!	4. COUNT OF PAGES TO UPDATED

! OUTPUT:
! ------
!	<NONE>
!
!
GLOBAL ROUTINE PAGOUT (FILID, FILPAGE, MEMPAGE, COUNT):NOVALUE =
BEGIN
!	ARGUMENT (FILID,VALUE);
!	ARGUMENT (FILPAGE,VALUE);
!	ARGUMENT (MEMPAGE,VALUE);
!	ARGUMENT (COUNT,VALUE);

LOCAL
	SIZOUT,				!# OF WORDS TO ACTU WRITE, ALWAYS BKT
					!SIZE UNLESS EXTENDING FILE
	FOPBLK: VECTOR[2],		!FILOP BLK FOR NON-FILE-MGT TASKS
	IOWDLST: VECTOR[2];		!HOW MUCH, WHERE TO DO I/O IN FILE

REGS;

	TRACE ( 'PAGOUT' );

	%IF TOPS10
	%THEN
	    IF .MEMPAGE GEQ 0			!WRITING A PAGE?
	    THEN BEGIN				!YES
		FOPBLK[0] =.FILID^18 OR $FOUSO;	!FILE AND FUNCTION
		FOPBLK[1] = (.FILPAGE)*4 + 1;	!CONV BYTE PTR TO BLK#
		AC1=2^18 OR FOPBLK;		!PTR TO ARGLST
		DO_FILOP;			!POSITION THE FILE

!		IF (.FILPAGE+.COUNT)^P2W LSS .SIZEOFFILE
!						!EXTENDING FILE?
!		THEN SIZOUT = .COUNT*PAGESIZE	!NO
!		ELSE SIZOUT = .SIZEOFFILE - (.FILPAGE^P2W);
!						!YES, OUTPUT AMT OF EXTEND ONLY

		SIZOUT = .COUNT*PAGESIZE;	! Put out whole pages 

		IOWDLST[0] = (-.SIZOUT^18)	!# OF WORDS TO WRITE
			 OR .MEMPAGE*PAGESIZE-1;	!CONVERT P# TO ADDRESS
		IOWDLST[1] = 0;			!TERM I/O CMDS

		FOPBLK[0] = .FILID^18 OR $FOOUT;	!RESET OPERATION CODE
		FOPBLK[1] = IOWDLST;		!STORE PTR TO IOWD LIST
		AC1=2^18 OR FOPBLK;		!RE-INIT ARG PTR
		DO_FILOP;			!READ THE PAGE(S)
	    END;

	    IF (.FILPAGE+.COUNT)^P2W LSS .SIZEOFFILE
	    THEN RETURN;			!NOT EXTENDING FILE, SO DONE
	    FOPBLK[0] = .FILID^18 OR $FORRC;	!UPD RIB AS NECES
	    AC1 = 1^18 OR FOPBLK;		!PT TO ARG LIST
	    DO_FILOP;				!DO IT
	%FI

	%IF TOPS20
	%THEN
		AC1=.FILID^18 OR .FILPAGE;	!JFN & PAGE #
		AC2=UF_NOW OR .COUNT;		!NUMBER TO PUT OUT
		DO_JSYS(UFPGS);			!UF_NOW MAKES IT NON-BLKING
	%FI

	RETURN
END; %( OF PAGOUT ROUTINE )%

! POSASCFIL
! =========
!
!	DETERMINE PAGE # OF DESIRED BYTE AND READ IT IN.
!	THEN SETUP BYTE PTR TO IT IN MEMORY.
!	ALSO SETUP COUNT OF CHARACTERS IN BUFFER

! INPUT:	1. FILE ID
!		2. BYTE NO IN FILE TO POSITION TO


! OUTPUT:	<NONE>

GLOBAL ROUTINE POSASCFIL ( FILE_ID, BYTE_NO ) :NOVALUE=
BEGIN
!	ARGUMENT ( FILE_ID, VALUE );
!	ARGUMENT ( BYTE_NO, VALUE );

LOCAL
	BKT_TO_USE,			!BKT# IN WHICH DESIRED BYTE IS
	CH_PER_BKT,			!# OF CHARS IN BUCKET
	CC_IN_BUF,			!OFFSET OF BYTE_NO(TH) CHAR IN BUFF
	TEMP;

	TRACE ( 'POSASCFIL' );
	
	CH_PER_BKT = .CBD [BKDBKTSIZE] * CH_IN_P;	!CALC BUFF SIZE IN CHARS
	CC_IN_BUF = .BYTE_NO MOD .CH_PER_BKT;	!OFFSET OF BYTE WITHIN ITS PAGE
	BKT_TO_USE = .BYTE_NO / .CH_PER_BKT;	!CALC BKT TO POS TO (1ST BKT=0)
	TEMP =		 			!READ BKT & RET CHARS IN IT
	  $CALL (ASCREAD, .FILE_ID, .BKT_TO_USE, .CURENTBUFFERADR, .CH_PER_BKT);
	IF ENDOFFILE				!IF SO, GETS NO LONGER POSSIB
	THEN BEGIN
		RST [RSTNRP] = .BKT_TO_USE;	!NEXT I/O WILL BE REWRITE OF THIS BKT
		RST[RSTBYTECOUNT] = .CC_IN_BUF;	!INDIC FULLNESS OF BKT
	END
	ELSE BEGIN
		RST [RSTNRP] = .BKT_TO_USE+1;	!NEXT I/O WILL BE READ OF SUBS BKT
		RST [RSTBYTECOUNT] = .TEMP - .CC_IN_BUF	!CHARS LEFT TO READ
	END;
	RST [RSTPAGPTR] = CH$PTR(.CURENTBUFFERADR, .CC_IN_BUF, 7);
						!PT TO DESIRED BYTE
	RETURN

END; %( OF POSASCFIL ROUTINE )%

! READTTY
! =======
!	ROUTINE TO READ A LINE FROM THE TTY.

! INPUT:	1. A BYTE POINTER TO AREA IN CALLERS ADDRES SPACE TO MOVE STRING
!		2. NO OF BYTES IN STRING

! OUTPUT:	1. REMAINING BYTE COUNT
!
!
!
!
GLOBAL ROUTINE READTTY ( STRING_PTR, SIZE ) :=
BEGIN
!	ARGUMENT ( STRING_PTR, POINTER );
!	ARGUMENT ( SIZE, VALUE );

LOCAL
	TEMP1,
	TEMP2;

REGS;

	TRACE ( 'READTTY' );

	%IF TOPS10
	%THEN
		ERROR(ER$DEV);			!DONT SUPPORT TTY ON 10
	%FI

	%IF TOPS20
	%THEN
		AC1 = POINT (.STRING_PTR,36,7);	! GET BYTE POINTER
		AC2 = RD_TOP OR .SIZE;		! BREAK SET & NO OF BYTES
		AC3 = ZERO;			! NO CONTROL-R BUFFER
		DO_JSYS ( RDTTY );		! READ IT
		TEMP1 = .AC1;			! UPDATED STRING POINTER
		TEMP2 = .AC2<RH>;		! AND LENGTH
	
	%([ CHECK FOR CONTROL-Z, WHICH WILL GENERATE AN EOF 	])%

		LDB ( AC1, TEMP1 );		! GET THE CHARACTER
		IF .AC1 IS CHARCNTZ	%( TERMINATING CHARACTER ^Z? )%
		THEN USRSTS = ER$EOF;
	%FI

	RETURN	.SIZE - .TEMP2;			!CHARS READ = MAX-RESIDUE

END; %( OF READTTY ROUTINE )%

! SIZEFILE
! ======
!	RETURNS THE LENGTH OF AN EXISTING FILE

! INPUT:	1. FILE ID

! OUTPUT:	1. NO OF BYTES IN THE FILE:
!			WORDS FOR RMS FILES
!			CHARS FOR LSA AND ASCII FILES


GLOBAL ROUTINE SIZEFILE ( FILE_ID ):=
BEGIN

!	ARGUMENT ( FILE_ID, VALUE );
LOCAL
	TEMP;
REGS;

	TRACE ( 'SIZEFILE' );

	%IF TOPS10
	%THEN
		TEMP = .SIZEOFFILE;			!GET SIZE RETR FROM LOOKUP BLK 
		IF ASCIIFILE THEN TEMP = .TEMP*5;	!!! NOTE: *5 MEANS IMPRECISION
	%FI

	%IF TOPS20
	%THEN
		AC1 = .FILE_ID;		! JFN OF FILE
		AC2 = 0;		! INITIALIZE AC2 AND AC3
		AC3 = 0;
		DO_JSYS ( SIZEF );
		TEMP = .AC2;		! BYTE COUNT THAT REFERENCED LAST BYTE
		IF SEQUENCED THEN TEMP = .TEMP*5;	!ON 20, ASCII SIZ ALR IN CHARS
	%FI

	RETURN	.TEMP

END; %( OF SIZEFILE ROUTINE )%

! TRUNCFILE
! =========
!	DELETE TRAILING PAGES FROM A FILE

! INPUT:	1. FILE ID OF FILE TO BE TRUNCATED
!		2. PAGE NO OF FIRST PAGE OF A BLOCK OF PAGES TO BE KILLED
!		3. NO OF PAGES TO BE KILLED

! OUTPUT:	<NONE>

GLOBAL ROUTINE TRUNCFILE ( FILE_ID, PAGE_NO, NO_OF_PAGES ) : NOVALUE=
BEGIN
!	ARGUMENT ( FILE_ID, VALUE );
!	ARGUMENT ( PAGE_NO, VALUE );
!	ARGUMENT ( NO_OF_PAGES, VALUE );

REGS;

	TRACE ( 'TRUNCFILE' );

	%IF TOPS10
	%THEN
		!THERE IS CURRENTLY NO GOOD WAY TO DYNAMICALLY ADJUST FILE SIZE
		!ON THE 10. CONSEQUENTLY, $TRUNC IS NOT SUPPORTED ON 10
		ERROR ( er$iop);
	%FI

	%IF TOPS20
	%THEN
		! TRUNCATION HAS TWO ASPECTS, SETTING EOF PTR AND
		! PHYSICALLY DESTROYING PAGES FOR EFFIC'S SAKE.
		! UNFORTUNATELY THE 20 ONLY
		!HAS FACILITY FOR DESTROYING PAGES LT 777(OCTAL)

		AC2 = .FILE_ID ^ 18 OR .PAGE_NO;		! FILE ID & PAGE NO
		AC3 = BITN (0) OR .NO_OF_PAGES;		! NO OF PAGES TO KILL
		AC1 = -1;				! KILL PAGES
		DO_JSYS ( PMAP );

	%FI

	RETURN

END; %( OF TRUNCFILE ROUTINE )%

END ELUDOM