Google
 

Trailing-Edge - PDP-10 Archives - 704rmsf2 - 10,7/rms10/rmssrc/rmsio.b36
There are 6 other files named rmsio.b36 in the archive. Click here to see a list.
MODULE RMSIO =


BEGIN

GLOBAL BIND	IOV = 1^24 + 0^18 + 10;		!EDIT DATE: 5-APR-77

%([
FUNCTION:	THIS MODULE CONTAINS ROUTINES WHICH INTERFACE
		TO THE MONITOR TO PERFORM VARIOUS I/O FUNCTIONS
		FOR SEQUENTIAL AND RELATIVE FILES.

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

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


AUTHOR:	S. BLOUNT


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




	ROUTINE			FUNCTION
	=======			========

	GTBYTE			POSITION FILE TO A BYTE LOCATION

	GETWINDOW		MAP IN A FILE PAGE

	MOVEREC			TRANSFER A RECORD FROM/TO USER BUFFER

	NOSPAN			CHECK A SEQUENTIAL FILE FOR PAGE OVERLAP


	NUMBERTORFA		CONVERT A RECORD NUMBER TO A BYTE ADDRESS

	WRITEBUFFER		OUTPUT A BUFFER FOR ASCII FILE

	READBUFFER		INPUT A BUFFER FOR ASCII FILE





REVISION HISTORY:

EDIT		DATE		WHO		PURPOSE
====		====		===		========

1		8-JUL-76	/JK	ADD READ AHEAD TO GETWINDOW AND MOVEREC
2		15-JUL-76	SEB	MOVE SETPLOG TO RMSFIL
3		27-JUL-76	JK	'PUTBUF' HAS 4 ARGS, NOT 3!!!
4		27-JUL-76	JK	'GETWINDOW' SHOULD ALWAYS ASK FOR PMAPRD.
5		5-AUG-76	JK	ADD NEW ASCII CHANGES.
6		7-FEB-77	SB	TAKE OUT FSTHSZ
7		21-FEB-77	SB	ADD ARG TO SINJSYS
8		14-MAR-77	SB	ADD CHECK-BYTE AT END OF RECORD
9		5-PAR-77	SB	TAKE OUT READ-AHEAD IN MOVEREC,
					MAKE NUMBERTORFA USE MRS, NOT RSZW

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

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

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

 100	  10	Dev		Make declarations for routine names
				be EXTERNAL ROUTINE so RMS will compile 
				under BLISS V4 (RMT, 10/22/85).



	***** END OF REVISION HISTORY *****




])%



EXTERNAL ROUTINE
    GETBUF,
    PUTBKT,
    GETBKT,		! FETCH A NEW FILE BUCKET
    CRASH,		! FOR DEBUGGING
    DUMP,
    ERRORROUTINE,	! HOLDS ADDRESS OF ROUTINE TO GO TO ON ERROR
    IOERROR;	! ROUTINE TO PROCESS READ ERRORS


%([ ERROR MESSAGES REFERENCED WITHIN THIS MODULE ])%

EXTERNAL
    MSGFAILURE,		! ROUTINE FAILURE
    MSGRFA,			! BAD RFA DETECTED
    MSGPTR,			! WINDOWPTR IS BAD
    MSGPAGE,		! BAD PAGE NUMBER
    MSGCOUNT,		! BAD COUNT VALUE
    MSGCORE,		! GETBUF COULDN'T GET FREE STORAGE
    MSGINPUT;		! BAD INPUT VALUES



FORWARD ROUTINE		READBUFFER: NOVALUE,
			WRITEBUFFER: NOVALUE,
			GETWINDOW;			! FORWARD DELCLARATIONS




REQUIRE 'RMSREQ';
EXTDECLARATIONS;



! GTBYTE
! ======

! THIS ROUTINE MAKES SURE THAT THE NEXT RECORD TO BE ACCESSED
!	IS POSITIONED CORRECTLY WITHIN THE FILE WINDOW.
!	THIS ROUTINE IS USED ONLY FOR SEQUENTIAL AND RELATIVE FILES.
!	IT IS CALLED BY ALMOST ALL RMS-20 RECORD VERB PROCESSORS
!	FOR SEQUENTIAL OR RELATIVE FILES. THIS ROUTINE IS NOT
!	CALLED AT ALL TO PROCESS INDEXED FILES.
!	ON INPUT, THE 'RECORD-FILE ADDRESS' (RFA) OF THE RECORD
!	IS PASSED.  ON OUTPUT, THE RECORD IS IN THE CURRENT BUCKET
!	AND THE "PAGPTR" FIELD OF THE RST CONTAINS THE ADDRESS
!	WITHIN THE WINDOW OF THE FIRST WORD OF THE RECORD
!	HEADER.
!

! INPUT:
!	RFA		RFA OF TARGET RECORD
!	ABORTFLAG 	FLAG TO DETERMINE IF PAGE EXISTS
!		TRUE: ABORT IF NEXT PAGE IS NON-EXISTENT
!		FALSE: DONT ABORT

! OUTPUT:
!	TRUE:	OK
!	FALSE:	ERROR
!
! ROUTINES USED:
!	GETWINDOW
!
! NOTES:
!
!	1.	THE FOLLOWING SYMBOLS ARE MACROS WHICH ARE DEFINED
!		IN "RST.REQ". DO NOT CONFUSE THEM WITH LOCAL VARIABLES:
!
!			CURRENTFILEPAGE
!			CURRENTWINDOW
!			CURENTBUFFERADR
!
!	2.	THE RFA WHICH IS PASSED TO THIS ROUTINE IS ACTUALLY
!		THE BYTE NUMBER OF THE STARTING ADDRESS OF THE TARGET
!		RECORD. FOR SEQUENTIAL FILES, THIS BYTE NUMBER IS ALSO
!		THE RFA, BUT FOR RELATIVE FILES, THE RFA (RECORD NUMBER)
!		MUST BE CONVERTED INTO A BYTE NUMBER BEFORE THIS ROUTINE
!		IS CALLED.
!
!	3.	"ABORTFLAG" IS PASSED DIRECTLY TO GETWINDOW AND IS NOT
!		USED BY THIS ROUTINE.


GLOBAL ROUTINE GTBYTE ( RFA, ABORTFLAG ) =
BEGIN
	ARGUMENT (RFA,VALUE);				! BYTE ADDRESS OF RECORD TO BE FETCHED
	ARGUMENT (ABORTFLAG,VALUE);			! FLAG FOR WHETHER TO ABORT IF PAGE DOESNT EXIST

LOCAL
    NEWPAGPTR,
    ARG1,
    ARG2,
    ARG3,
    RFAPAGENUM;


MAP
    RFA:	FORMATA;


	TRACE ( 'GTBYTE' );

	%([ CHECK INPUT PARAMETERS ])%

	CHECKINPUT ( RFA,GEQ,ZERO );			! RFA MUST BE POSITIVE
	CHECKINPUT ( RFA,LSS,BITN(8));			! AND ...


	%([ CHECK IF PAGE IS CURRENTLY IN WINDOW ])%

	RFAPAGENUM = .RFA [ RFAPAGE ];
	IF ( .CURRENTWINDOW IS ZERO )			! THERE IS NO CURRENT BUCKET
		OR
	   ( .CURRENTFILEPAGE ISNT .RFAPAGENUM )
	THEN
		BEGIN %( GET THE NEW PAGE )%
		IF CALLGETWINDOW ( %( PAGE NO. )%         LCI ( RFAPAGENUM ),
		                %( PAGE MUST EXIST )%  VCI ( ABORTFLAG )) IS FALSE
		THEN BADRETURN			! BADRETURN IF PAGE DOESN'T EXIST
		END;  %( OF GET THE NEW PAGE )%

	%([ NOW, THE PAGE WE WANT IS IN OUR WINDOW .
	   WE MUST SET UP A POINTER TO IT IN THE RST ])%

	RST [ RSTPAGPTR ] = ( .CURENTBUFFERADR ) + .RFA [ OFSET ];

	GOODRETURN  %(RETURN FROM GTBYTE)%

END;	%( OF GTBYTE	)%


! GETWINDOW
! ======

!  THIS ROUTINE MAKES SURE THAT THE SPECIFIED FILE PAGE IN IN THE WINDOW.
! 'GETBKT' IS CALLED TO CHECK IF THE FILE PAGE IS ALREADY MAPPED INTO OUR
! PROCESS (OTHERWISE, THE FILE PAGE WILL BE MAPPED IN.)  'PUTBKT' WILL BE
! CALLED TO RELEASE THE BUFFER CONTAINING THE FILE PAGE WHICH IS CURRENTLY
! IN THE WINDOW.
!
!	IF THE ABORT-FLAG IS ON, THEN A PRELIMINARY CHECK IS
!	TO INSURE THAT THE TARGET FILE PAGE ACTAULLY EXISTS.
!	IF THE PAGE DOES NOT EXIST, AN ERROR RETURN IS TAKEN.

! INPUT:
!	FPAGE		PAGE NO. OF FILE PAGE
!	ABORTF		FLAG TO DETERMINE IF PAGE EXISTS
!		TRUE =  PAGE MUST EXIST
!	 	FALSE = PAGE DOESN'T HAVE TO EXIST

! OUTPUT:
!	TRUE :	OK
!	FALSE:	PAGE NON-EXISTENT

GLOBAL ROUTINE GETWINDOW ( FPAGE, ABORTF ) =
BEGIN %( GETWINDOW )%


	ARGUMENT (FPAGE,VALUE);			! FILE PAGE NO.
	ARGUMENT (ABORTF,VALUE);		! TRUE MEANS PAGE MUST EXIST

LOCAL
    BPAGE,
    BFDADR,
    INCORE,
    ARG;



	TRACE ( 'GETWINDOW ');

	%( CHECK INPUT PARAMETERS )%

	CHECKINPUT ( FPAGE,GEQ,ZERO );		! PAGE #'S ARE POSITIVE
	CHECKINPUT ( FPAGE,LSS,BITN(17) );	! 2**18 FILE PAGES


	%([ IF THERE IS A PAGE IN THE WINDOW, RELEASE IT ])%

	IF NOT NULLBD ( CBD )
	THEN	%(THERE IS A CURRENT BUCKET)%

		CALLPUTBKT (	%(NO UPDATE)%	PCI ( FALSE ),
				%(BKT DESC)%	GPT ( CBD ) );

	%([ CHECK IF SPECIFIED FILE PAGE EXISTS (IF CALLER WANTS US TO) ])%

	IF .ABORTF ISNT FALSE
	THEN	BEGIN %( CHECK IF PAGE EXISTS )%

		%([ READ THE PAGE'S ACCESSIBILITY ])%

		IF $CALL (PAGEXIST, .FST [ FSTJFN ], .FPAGE) IS FALSE	! JFN + PAGE NO
		THEN BADRETURN;		%([ PAGE NON-EXISTENT ])%

	END;   %( OF CHECK IF PAGE EXISTS )%


	%([ WE CAN NOW FETCH THE NEW BUCKET AND MAKE IT "CURRENT" ])%

	IF CALLGETBKT (	%(BKT NUM)%	VCI ( FPAGE ),
			%(SIZE)%		PCI ( SEQBKTSIZE ),
			%(LOCK)%		PCI ( FALSE ),
			%(BD)%		GPT ( CBD ) ) IS FALSE

	THEN RMSBUG ( MSGFAILURE );


	GOODRETURN			! RETURN FROM GETWINDOW

END;	%( OF GETWINDOW )%


! MOVEREC
! =======

! THIS ROUTINE TRANSFERS A RECORD FROM ONE PLACE TO ANOTHER.
!	IT IS USED ON BOTH INPUT AND OUTPUT FOR SEQUENTIAL AND
!	RELATIVE FILES. IT IS NOT CALLED FOR INDEXED FILES.
!
!	ALL PAGE BOUNDARY PROBLEMS ARE HANDLED BY SWITCHING
!	WINDOW PAGES. NO INDICATION IS GIVEN IF A NON-EXISTENT
!	PAGE IS FOUND.

! INPUT:
!	ADDRESS OF RECORD IN SYSTEM BUFFER
!	ADDRESS OF USER BUFFER
!	PUT-FLAG:
!		TRUE :	MOVE FROM USER TO WINDOW
!		FALSE:	MOVE FROM WINDOW TO USER
!	# BYTES TO MOVE
!	BYTE-SIZE OF RECORD

! OUTPUT:
!	TRUE ALWAYS
!
! ROUTINES USED:
!	GETWINDOW

! NOTES:
!
!	1.	THE FOLLOWING SYMBOLS ARE MACROS WHICH ARE DEFINED
!		IN "RST.REQ". DO NOT CONFUSE THEM WITH LOCAL VARIABLES:
!
!			CURRENTFILEPAGE
!			CURRENTWINDOW
!			CURENTBUFFERADR
!
!	2.	ON A $PUT OPERATION, THIS ROUTINE WILL MOVE FULL
!		WORDS FROM THE USER'S BUFFER TO THE SYSTEM FILE
!		BUFFER. ON A $GET, ONLY THE EXACT NUMBER OF BYTES
!		IN THE RECORD ARE MOVED. THUS, THE USER'S BUFFER
!		DOES NOT GET DESTROYED PAST THE END OF HIS RECORD.


GLOBAL ROUTINE MOVEREC ( WINDOWPTR, USERADR, PUTFLAG, BYTES, BYTESIZE ) =
BEGIN %( MOVEREC )%
	ARGUMENT (WINDOWPTR,VALUE);			! ADDRESS OF RECORD
	ARGUMENT (USERADR,VALUE);			! ADDRESS OF USER BUFFER
	ARGUMENT (PUTFLAG ,VALUE);			! PUT-FLAG
	ARGUMENT (BYTES,VALUE);				! # OF BYTES TO MOVE
	ARGUMENT (BYTESIZE,VALUE);			! BYTESIZE

LOCAL
    WORDCOUNT,					! COUNTER OF WORDS TO MOVE
    BYTESWORD,
    ROOM,						! AMOUNT OF ROOM LEFT ON CURRENT PAGE
    TEMP,
    TEMP2,
    EXTRABYTES,
    SOURCE,
    DEST;




	TRACE ( 'MOVEREC' );


	%( CHECK INPUT PARAMETERS )%
	%IF DBUG %THEN
	IF ( .BYTES LSS ZERO ) OR ( .BYTESIZE LEQ ZERO ) OR ( .BYTESIZE GTR 36 )
		THEN RMSBUG ( MSGINPUT );			! BAD INPUT VALUES
	%FI

	BYTESWORD = 36/.BYTESIZE;			! FIND # OF BYTES IN WORD
	WORDCOUNT = .BYTES / .BYTESWORD;		! # OF WORDS TO MOVE
	EXTRABYTES = .BYTES - ( .WORDCOUNT * .BYTESWORD );

	%([ FOR A $PUT OPERATION, WE WILL MOVE THE RECORD BY USING
	   A BLT INSTEAD OF A ILDB-IDPB LOOP. WHEN WE ARE LATER
	   READING THE RECORD, WE MUST INSURE THAT WE DON'T MOVE
	   THE EXTRA GARBAGE BYTES IN THE RECORD ])%

	IF	( .PUTFLAG ) THEN IF ( .EXTRABYTES ISNT ZERO )
	THEN 
		BEGIN
		INC ( WORDCOUNT, 1 );		! BUMP THE WORDCOUNT
		EXTRABYTES = ZERO		! NO EXTRA BYTES
		END;

	%( PRINT OUT THE RESULTS, SO FAR )%
	LOOKAT ( '	WORDCOUNT: ', WORDCOUNT );
	LOOKAT ( '	EXTRA: ', EXTRABYTES  );



	%( LOOP FOR ALL FULL WORD MOVES...ONE LOOP FOR EACH PAGE
	  ONTO WHICH THE RECORD IS MOVED ])%

	WHILE .WORDCOUNT ISNT ZERO 
	DO
		BEGIN

		%([ COMPUTE HOW MUCH SPACE WE HAVE LEFT ON THIS PAGE ])%

		ROOM = ( .CURENTBUFFERADR + PAGESIZE )  - .WINDOWPTR ;
		%IF DBUG %THEN
		IF ( .ROOM LSS ZERO  ) OR ( .ROOM GTR PAGESIZE ) THEN RMSBUG ( MSGCOUNT );
		IF .WORDCOUNT LSS ZERO THEN RMSBUG ( MSGCOUNT );	! BAD VALUE FOR WORDCOUNT
		%FI


		%([ WE MUST NOW CHECK TO SEE IF THE FILE PAGE IS COMPLETELY FULL ])%

		IF .ROOM IS ZERO
		THEN %( WE MUST GET NEXT PAGE )%
			BEGIN
			TEMP =  .CURRENTFILEPAGE  + 1;		! GET # OF NEXT PAGE IN FILE

			RTRACE ( %STRING(' 	SWITCHING PAGES...',%CHAR(13),%CHAR(10),' '));
			%([ LOAD THE PAGE WE WANT RIGHT NOW. ])%

			CALLGETWINDOW (	%( PAGE NO. )%        LCI ( TEMP ),
					%( DON'T ABORT )%      PCI ( FALSE ));

			WINDOWPTR = .CURENTBUFFERADR;		! RESET PTR TO START OF FILE BUFFER
			ROOM = PAGESIZE				! AND AMOUNT LEFT
			END; %( OF IF ROOM IS ZERO )%

		%( FIND THE LESSER OF RECORD SIZE, OR AMOUNT ON PAGE )%

		IF .WORDCOUNT LSS .ROOM THEN ROOM = .WORDCOUNT;

		%([ ASSUME THAT THIS IS A $GET AND SET UP OUT POINTERS ])%

		SOURCE = .WINDOWPTR;				! MOVE FROM FILE PAGE...
		DEST = .USERADR;				! ...TO USER BUFFER
		IF .PUTFLAG ISNT FALSE %( MOVE FROM USER TO WINDOW )%
		THEN
			BEGIN
			SETBFDUPD(CBD[BKDBFDADR]);		!INDIC FILE PAGE UPD
			SOURCE = .USERADR;			! GET ADDRESS
			DEST = .WINDOWPTR			! AND DESTINATION
			END; %( OF IF PUTFLAG IS TRUE )%

		%([ NOW, MOVE THIS RECORD SEGMENT FROM/TO USER BUFFER ])%

		MOVEWORDS (	%(FROM)%	.SOURCE,
				%(TO)%	.DEST,
				%(SIZE)%	.ROOM );


		USERADR = .USERADR + .ROOM;			! BUMP USER BUFFER POINTER
		WINDOWPTR = .WINDOWPTR + .ROOM;			! AND WINDOW POINTER
		WORDCOUNT = .WORDCOUNT - .ROOM
		END; %( OF WHILE WORDCOUNT NEQ ZERO )%


	%( WE HAVE NOW MOVED ALL FULL WORDS IN THE RECORD. WE MUST
	  THEN SEE IF THERE WERE ANY BYTES LEFT OVER TO MOVE ])%

	IF .EXTRABYTES IS ZERO THEN GOODRETURN; %( NONE TO MOVE )%


	%([ FIRST, WE MUST CHECK TO SEE IF THESE LAST FEW BYTES
	   WILL OVERLAP INTO THE NEXT PAGE OF THE FILE. IF SO,
	   WE MUST MAP IN THE NEXT FILE PAGE AND MOVE THE BYTES
	   IN THE NEW PAGE ])%


	IF ( ( .CURENTBUFFERADR + PAGESIZE ) IS .WINDOWPTR ) 

	THEN
		BEGIN
		TEMP =	( .CURRENTFILEPAGE + 1 ) ;		! GET # OF NEXT FILE PAGE

		RTRACE ( %STRING('	CURRENT PAGE EXHAUSTED...',%CHAR(13),%CHAR(10),' '));
		IF CALLGETWINDOW ( %( PAGE NO. )%        LCI ( TEMP ),
			           %( DON'T ABORT )%     PCI ( FALSE ) )
			IS FALSE THEN RMSBUG ( MSGFAILURE );
		WINDOWPTR = .CURENTBUFFERADR			! RESET ADDRESS
		END; %( OF IF WINDOW IS EXHAUSTED )%


	%([ SET UP AN APPROPRIATE BYTE POINTER ])%

	WINDOWPTR = POINT ( .WINDOWPTR, 36, .BYTESIZE );	! FORM BYTE POINTER
	USERADR = POINT ( .USERADR, 36, .BYTESIZE );
	DECR J FROM .EXTRABYTES -1  TO ZERO DO
		BEGIN
		%(MOVE FROM WINDOW TO USER)%
		COPYII( WINDOWPTR, USERADR )
		END; %( OF DECR J )%

	GOODRETURN


END;	%( OF MOVEREC )%



! NOSPAN
! ======

! THIS ROUTINE PERFORMS CALCULATION ON THE NRP
!	OF A SEQUENTIAL FILE WHEN A RECORD IS TO BE WRITTEN.
!	IF THE "BLOCKED" ATTRIBUTE ( FB$BLK) IS NOT
!	DEFINED FOR THIS FILE, THIS ROUTINE IS NOT CALLED.
!	ON INPUT TO THE ROUTINE, THE NRP IS PASSED AS AN ARGUMENT.
!	THIS ROUTINE COMPUTES IF THE RECORD TO BE WRITTEN
!	CAN FIT ON THE CURRENT PAGE. IF SO, THE NRP
!	VALUE WHICH WAS PASSED TO THIS ROUTINE IS RETURNED
!	UNCHANGED.  IF NOT, IT RETURNS
!	THE NEW VALUE OF THE NRP.
!	IN THIS CASE, AN "END-OF-PAGE" MARKER WILL BE WRITTEN INTO
!	THE FILE AT THE PLACE WHERE THIS RECORD WAS TO BE PLACED.

! INPUT:
!	CURRENT NRP VALUE

! OUTPUT:
!	UPDATED NRP
!
! GLOBALS USED:
!	<NONE>

! NOTES:
!
!	1.	THE FOLLOWING SYMBOLS ARE MACROS WHICH ARE DEFINED
!		IN "RST.REQ". DO NOT CONFUSE THEM WITH LOCAL VARIABLES:
!
!			CURRENTWINDOW


GLOBAL ROUTINE NOSPAN ( NRP ) =
BEGIN
	ARGUMENT (NRP,VALUE);

LOCAL
    NEWNRP;

MAP
    NEWNRP:	FORMAT;
MAP
    NRP:	FORMATA;


	TRACE ( 'NOSPAN' );

	%([ WE WILL NOW DEFINE A NEW BEGIN-END BLOCK IN ORDER
	   TO REMAP NRP ONTO ANOTHER STRUCTURE LATER. ])%

	BEGIN %( A NEW BLOCK TO ALLOW RE-MAPPING OF NRP )%


	%([ COMPUTE AMOUNT OF SPACE REQUIRED FOR RECORD ])%

	NEWNRP = .NRP + .RST [ RSTRSZW ] + HEADERSIZE -1;	! FIND END OF THIS RECORD

	IF .NEWNRP [PAGE] IS .NRP[PAGE] %( NO PAGE OVERLAP )%	! CHECK IF IT SLOPS OVER TO NEXT PAGE
		THEN RETURN .NRP;



	%([ WE NOW KNOW THAT THE NEXT RECORD TO BE WRITTEN
	   CANNOT FIT ON THE CURRENT PAGE. SO, WE WILL
	   BUMP THE NRP TO THE NEXT PAGE, AND STICK AN
	   END-OF-PAGE MARKER AT THE END OF THIS PAGE ])%

	NEWNRP = ( .NRP OR OFSETMASK ) + 1;			! COMPUTE START OF NEXT PAGE
	NRP[PAGE] = .CURRENTWINDOW;				! FORM ADDRESS OF PLACE TO PUT EOP
	END; %( OF BEGIN BLOCK )%

	BEGIN %( A NEW BLOCK )%

	MAP
	    NRP:	POINTER;

	%([ STORE THE END-OF-PAGE MARKER (-1) AT THE END
	   OF THE LAST PAGE ])%

	NRP[WHOLEWORD] = EOPMARKER;				! STORE MARKER

	%([ RETURN THE VALUE OF THE UPDATED POINTER TO THE
	   NEXT PAGE ])%

	RETURN .NEWNRP;						! RETURN THE NEW VALUE
	END;

END;	%( OF NOSPAN )%





! NUMBERTORFA
! ===========

! THIS ROUTINE COMPUTES THE ABSOLUTE BYTE ADDRESS OF A RECORD
!	IN A RELATIVE FILE.  IT MUST COMPUTE THIS ADDRESS
!	DEPENDING UPON WHETHER THE FILE HAS THE "BLK" ATTRIBUTE
!	OR NOT.

! INPUT:
!	RECNUM =	RECORD NUMBER

! OUTPUT:
!	NOT FALSE :	RFA OF RECORD
!	FALSE:		BAD RECORD NUMBER

! GLOBALS USED:
!	< NONE >

! USER ERRORS:
!	BYTE NUMBER OF RECORD .GTR. FILE ADDRESS SPACE


GLOBAL ROUTINE NUMBERTORFA ( RECNUM ) =
BEGIN

	ARGUMENT (RECNUM,VALUE);

LOCAL
    STARTOFDATA,		! MOVING VALUE WHICH DENOTES THE START OF THE DATA WITHIN THE FILE
    BYTENUM,		! BYTENUMBER OF RECORD
    SIZEOFRECORD,		! SIZE OF THE CURRENT RECORD
    RECSONANYPAGE,		! NUMBER OF RECORDS ON ANY PAGE OF THE FILE
    RECSONPAGE0,		! NUMBER OF RECORDS ON THE FIRST FILE PAGE ( PAGE 0 )
    TEMP;


MAP
    RECNUM:	FORMATA;

	TRACE ( 'NUMBERTORFA');

	%([ PRINT OUT THE INPUT VALUE ])%

	LOOKAT ('	INPUT RECORD #: ', RECNUM );

	%([ COMPUTE THE TOTAL SIZE OF A RECORD IN THIS FILE ])%

	SIZEOFRECORD = SIZEINWORDS (  .FST [ FSTMRS ], .FST [ FSTBSZ ] ) + HEADERSIZE;	! COMPUTE TOTAL LENGTH OF RECORD

	%([ WE MUST NOW CHECK TO SEE IF THIS RECORD NUMBER IS
	   WITHIN THE ACCEPTABLE RANGE FOR THIS FILE. FOR
	   INSTANCE, IT MAY BE .GTR. THE MAX-RECORD-NUMBER. ])%

	IF (	( .FST [ FSTMRN ] ISNT ZERO )
			AND
		( .RECNUM GTR .FST [ FSTMRN ] ) )
			OR
	( .RECNUM LEQ ZERO )  THEN BADRETURN;


	%([ COMPUTE THE ADDRESS OF THIS RECORD ])%

	STARTOFDATA = .FST [ FSTLOBYTE ];			! 1ST BYTE AFTER PROLOGUE

	%([ DETERMINE THE # OF RECORDS WHICH WILL EXIST ON PAGE 0 ])%

	RECSONPAGE0 = ( PAGESIZE - .STARTOFDATA ) / ( .SIZEOFRECORD );		! FIND # OF RECORDS ON PAGE 1


	%([ IF THIS FILE HAS THE FB$BLK ATTRIBUTE, AND THIS
	   RECORD IS NOT ON THE FIRST PAGE OF THE FILE, THEN
	   WE MUST FIND THE PAGE ON WHICH IT LIVES.  EACH PAGE
	   AFTER PAGE 0 WILL HAVE THE SAME NUMBER OF RECORDS ON IT.
	   THAT IS WHY WE MUST TREAT THE FIRST PAGE DIFFERENTLY
	   THAN THE OTHER PAGES OF THE FILE.	])%

	IF ( BLOCKED )
		AND
	 .RECNUM GTR .RECSONPAGE0 
	THEN							! ITS NOT ON PAGE 1

		BEGIN
		RECNUM = .RECNUM - .RECSONPAGE0;		! SUBTRACT 1 PAGE OF RECORDS
		RECSONANYPAGE = 512 / .SIZEOFRECORD;		! # OF RECORDS ON ANY FILE PAGE
		TEMP = (.RECNUM - 1 )/.RECSONANYPAGE;		! FIND WHERE RECORD BEGINS
		BYTENUM = (.TEMP + 1 )^P2W +
	 		 ((.RECNUM - 1 ) MOD .RECSONANYPAGE ) *
		  .SIZEOFRECORD;			! COMPUTE OFFSET INTO THAT PAGE
		END %( OF IF .RECNUM GTR RECSONPAGE0 )%

	ELSE
		%([ THIS FILE DOES NOT HAVE THE "FB$BLK" ATTRIBUTE,
		   SO WE CAN COMPUTE THE START OF THE RECORD DIRECTLY ])%


		BYTENUM = ( ( .RECNUM -1 ) * ( .SIZEOFRECORD ) ) + .STARTOFDATA;

	%(LET'S SEE IT)%
	LOOKAT ( '	BYTE #: ', BYTENUM);


	%([ MAKE ONE LAST CHECK TO SEE IF THIS RECORD IS OFF THE END OF THE WORLD ])%

	IF .BYTENUM GEQ BITN ( 8 ) THEN BADRETURN;

	RETURN .BYTENUM						! GIVE BACK THE BYTE ADDRESS

END; %( OF NUMBERTORFA )%



! WRITEBUFFER
! ===========

! THIS ROUTINE WRITES OUT THE CURRENT BUFFER FOR FILES ON A SEQUENTIAL
!	DEVICE, OR FOR ASCII ( LINE-SEQUENCED OR STREAM ) FILES.

! INPUT:
!	<NONE>

! OUTPUT:
!	<NONE>

! IMPLICIT INPUTS:
!
!	RSTBYTECOUNT =		NUMBER OF BYTES REMAINING IN FILE BUFFER
!
! ON EXIT, THE FILE BUFFER POINTER ( PAGPTR ) WILL BE RESET TO
!	THE TOP OF THE FILE BUFFER. ALSO, THE BUFFER WILL BE
!	SET TO INDICATE THAT IT IS EMPTY ( BYTECOUNT WILL BE SET
!	TO THE SIZE OF AN EMPTY BUFFER )

! NOTES:
!
!	1.	THE FOLLOWING SYMBOLS ARE MACROS WHICH ARE DEFINED
!		IN "RST.REQ". DO NOT CONFUSE THEM WITH LOCAL VARIABLES:
!
!			CURENTBUFFERADR

GLOBAL ROUTINE WRITEBUFFER:NOVALUE  =
BEGIN


REGISTER BUFADD;		!FOR CURRENT BUF ADDR

	TRACE ( 'WRITEBUFFER' );

	%([ DETERMINE THE NUMBER OF BYTES WE HAVE TO WRITE OUT ])%

	BUFADD = .CURENTBUFFERADR;

	RTRACE ( 'FLUSHING BUFFERS');		%([ USE FOR DEBUGGING ])%

	IF .RST [RSTBYTECOUNT] GTR ZERO		!ANYTHING THERE TO WRITE?
	THEN BEGIN				!YES
		$CALL (ASCWRITE, .FST [FSTJFN], .RST [RSTNRP], .BUFADD, .RST [RSTBYTECOUNT]);
		IF .RST [RSTBYTECOUNT] EQL CH_IN_P
		THEN BEGIN			!WRITING FULL PAGE, SO POSIT TO NEXT P
			RST[RSTNRP]=.RST[RSTNRP]+1;	!DONE (RE)WRITING THIS PAGE, POSIT TO NXT
			RST [ RSTPAGPTR ] = POINT(.BUFADD, 36, 7);
							!RESET PTR TO TOP OF BUF
			RST [ RSTBYTECOUNT ] = ZERO;	! RESET NUMBER OF BYTES IN BUFFER

	%([ CLEAR ENTIRE BUFFER TO RESET ALL BIT 35'S.
	   THIS IS NECESSARY SO THAT THE SECOND BUFFER WE WRITE
	   DOESNT HAVE RANDOM BIT 35'S SET IN IT  ])%

			IF SEQUENCED
			THEN CLEAR (.BUFADD, PAGESIZE);
		END;				!END FULL PAGE
	END;					!END NON-EMPTY PAGE

	RETURN

END; %( OF WRITEBUFFER )%



! READBUFFER
! ==========

! THIS ROUTINE READS IN A NEW BUFFER FOR RMS-20 FILES ON
!	A SEQUENTIAL DEVICE OR FOR ASCII FILES.
!
! INPUT:
!	<NONE>
!
! OUTPUT:
!	<NONE>
!
! NOTES:
!
!	1.	FOR INPUT FROM THE TTY, A <CONTROL-Z> WILL RETURN
!		AN ER$EOF ERROR CODE, BUT FURTHER INPUT FROM THE TTY
!		WILL BE ALLOWED.

GLOBAL ROUTINE READBUFFER:NOVALUE  =
BEGIN

REGISTER BUFADD;

	TRACE ( 'READBUFFER' );

	%([ IF WE ARE ALREADY AT EOF, DONT BOTHER... ])%

	IF ENDOFFILE THEN RETURN;

	BUFADD = .CURENTBUFFERADR;		!USE A LOCAL

	! REPOSITION TO BEGIN OF BUFFER
	RST [ RSTPAGPTR ] = POINT ( .BUFADD , 36, 7 );

	%([ FOR DEBUGGING ])%

	RTRACE ( 'READING BUFFER...');

	%([ IF WE ARE READING FROM THE TTY, PROCESS ONE RECORD AT A TIME 
		ELSE TRY TO FILL ENTIRE BUFFER ])%

	IF TTY 
	THEN	RST [RSTBYTECOUNT] = $CALL (READTTY, .BUFADD, CH_IN_P)
	ELSE	BEGIN
		RST [RSTBYTECOUNT] = $CALL (ASCREAD, .FST [FSTJFN], .RST[RSTNRP], .BUFADD, CH_IN_P);
		RST[RSTNRP]=.RST[RSTNRP]+1;		!NEXT GROUP OF RECORDS IN NEXT BKT
	END;

	IF .RST [ RSTBYTECOUNT ] IS ZERO
	THEN BEGIN
		SETFLAG ( RST [ RSTFLAGS ], FLGEOF );	! SET EOF FLAG
		IF DASD					!DISK FILE?
		THEN $CALL (POSASCFIL, .FST [FSTJFN],
					$CALL (SIZEFILE, .FST [FSTJFN]));
							!POSIT TO APPEND
	END;
	RETURN

END; %(OF READBUFFER)%

END
ELUDOM