Google
 

Trailing-Edge - PDP-10 Archives - tops20-v7-ft-dist1-clock - 7-sources/rmsio.b36
There are 6 other files named rmsio.b36 in the archive. Click here to see a list.
%TITLE 'R M S I O   -- SEQ/REL I/O'
!<BLF/REQUIRE 'RMSBLF.REQ'>
MODULE rmsio (IDENT = '3.0'
		) =
BEGIN
!+
!
!    FUNCTION:	THIS MODULE CONTAINS ROUTINES WHICH INTERFACE
!    TO THE MONITOR TO PERFORM VARIOUS I/O FUNCTIONS
!    FOR SEQUENTIAL AND RELATIVE FILES.
!
!
!
!	COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1977, 1986.
!	ALL RIGHTS RESERVED.
!
!	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.
!
!
!
!    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		*
!    *						*
!    *************************************************
!
!    PRODUCT	MODULE	 SPR
!    EDIT	 EDIT	 QAR		DESCRIPTION
!    ======	======	=====		===========
!
!
!
!    ***** BEGIN VERSION 2 DEVELOPMENT *****
!
!
!    PRODUCT	MODULE	 SPR
!    EDIT	 EDIT	 QAR		DESCRIPTION
!    ======	======	=====		===========
!
!    301	300	XXXXX		SUPPORT EXTENDED ADDRESSING.
!
!    400	400	xxxxx		Clean up BLISS code (RL, 22-Apr-83)
!
!    504                                Image mode
!    570                                Image mode fix
!
!    ***** END OF REVISION HISTORY *****
!
!-

REQUIRE 'RMSREQ';
%SBTTL 'GTBYTE - position to next record'

GLOBAL ROUTINE gtbyte (rfa, abortflag) =
! 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.
    BEGIN

    LOCAL
	newpagptr,
	arg1,
	arg2,
	arg3,
	rfapagenum;

    MAP
	rfa : BLOCK [];

    TRACE ('GTBYTE');

    !+
    !    CHECK INPUT PARAMETERS
    !-

    checkinput (rfa, GEQ, 0);			! RFA MUST BE POSITIVE
    checkinput (rfa, LSS, bitn (8));		! AND ...

    !+
    !    CHECK IF PAGE IS CURRENTLY IN WINDOW
    !-

    rfapagenum = .rfa [rfapage];

    IF (.currentwindow EQL 0)			! THERE IS NO CURRENT BUCKET
	OR (.currentfilepage NEQ .rfapagenum)
    THEN
	BEGIN
	%( GET THE NEW PAGE )%

	IF getwindow (%( PAGE NO. )%.rfapagenum, %( PAGE MUST EXIST )%.abortflag) EQL false
	THEN
	    RETURN false			! 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];
    RETURN true;				! Return to caller
    END;

%( OF GTBYTE	)%
%SBTTL 'GETWINDOW - position page in window'

GLOBAL ROUTINE getwindow (fpage, abortf) =
! GETWINDOW
! ======
!  THIS ROUTINE MAKES SURE THAT THE SPECIFIED FILE PAGE IS 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
    BEGIN

    LOCAL
	bpage,
	bfdadr,
	incore,
	arg;

    TRACE ('GETWINDOW ');%( CHECK INPUT PARAMETERS )%
    checkinput (fpage, GEQ, 0);			! 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)%putbkt (%(NO UPDATE)%false, %(BKT DESC)%.cbd);

    !+
    !    CHECK IF SPECIFIED FILE PAGE EXISTS (IF CALLER WANTS US TO)
    !-

    IF .abortf NEQ false
    THEN
	BEGIN
	%( CHECK IF PAGE EXISTS )%

	!+
	!    READ THE PAGE'S ACCESSIBILITY
	!-

	IF pagexist (.fst [fstjfn], .fpage) EQL false	! JFN + PAGE NO
	THEN
	    RETURN false;			! Page non-existent

	END;%( OF CHECK IF PAGE EXISTS )%

    !+
    !    WE CAN NOW FETCH THE NEW BUCKET AND MAKE IT "CURRENT"
    !-

    IF getbkt (%(BKT NUM)%.fpage, %(SIZE)%seqbktsize, %(LOCK)%false, %(BD)%.cbd) EQL false
    THEN
	rmsbug (msgfailure);

    RETURN true					! RETURN FROM GETWINDOW
    END;

%( OF GETWINDOW )%
%SBTTL 'MOVEREC - move a record around'

GLOBAL ROUTINE moverec (windowptr, useradr, putflag, bytes, bytesize) =
! 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.
    BEGIN

    LOCAL
	wordcount,				! COUNTER OF WORDS TO MOVE
	bytesword,
	room,					! AMOUNT OF ROOM LEFT ON CURRENT PAGE
	temp2,
	extrabytes,
	SOURCE,
	dest,
	buf2ptr : VECTOR [2];			!TWO-WORD BP IF NEEDED

    REGISTER
	temp;

    TRACE ('MOVEREC');%( CHECK INPUT PARAMETERS )%

%IF dbug
%THEN

    IF (.bytes LSS 0) OR (.bytesize LEQ 0) 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 NEQ 0)
	THEN
	    BEGIN
	    wordcount = .wordcount + 1;		! BUMP THE WORDCOUNT
	    extrabytes = 0			! 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 NEQ 0 DO
	BEGIN

	!+
	!    COMPUTE HOW MUCH SPACE WE HAVE LEFT ON THIS PAGE
	!-

	room = (.curentbufferadr + pagesize) - .windowptr;

%IF dbug
%THEN

	IF (.room LSS 0) OR (.room GTR pagesize) THEN rmsbug (msgcount);

	IF .wordcount LSS 0 THEN rmsbug (msgcount);	! BAD VALUE FOR WORDCOUNT

%FI

	!+
	!    WE MUST NOW CHECK TO SEE IF THE FILE PAGE IS COMPLETELY FULL
	!-

	IF .room EQL 0
	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.
	    !-

	    getwindow (%( PAGE NO. )%.temp, %( DON'T ABORT )%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 NEQ 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
	!-

	IF .rmssec NEQ 0
	THEN
	    xcopy (%(FROM)%.SOURCE, %(TO)%.dest, %(SIZE)%.room)
	ELSE
	    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 EQL 0 THEN RETURN true;	! No extra bytes 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) EQL .windowptr)
    THEN
	BEGIN
	temp = (.currentfilepage + 1);		! GET # OF NEXT FILE PAGE
	rtrace (%STRING ('	CURRENT PAGE EXHAUSTED...', %CHAR (13), %CHAR (10), ' '));

	IF getwindow (%( PAGE NO. )%.temp, %( DON'T ABORT )%false) EQL false THEN rmsbug (msgfailure);

	windowptr = .curentbufferadr		! RESET ADDRESS
	END;%( OF IF WINDOW IS EXHAUSTED )%

    !+
    !    SET UP AN APPROPRIATE BYTE POINTER
    !-

    temp = .bytesize*.extrabytes;		! # OF BITS TO MOVE
    temp = (.temp^6) + nullbp;			! FORM LH OF PTR
    windowptr<lh> = .temp;			!GET LOCAL BP TO WINDOW

    IF .rmssec NEQ 0
    THEN
	BEGIN
	buf2ptr [1] = .useradr;
	buf2ptr<lh> = .temp OR %O'40';		!2-WORD BP
	buf2ptr<rh> = 0;
	ildb (temp, windowptr);
	idpb (temp, buf2ptr)
	END
    ELSE
	BEGIN
	useradr<lh> = .temp;			! STORE IN POINTERS
	ildb (temp, windowptr);
	idpb (temp, useradr)
	END;

    RETURN true
    END;

%( OF MOVEREC )%
%SBTTL 'NOSPAN - Calculate sequential NRP'

GLOBAL ROUTINE nospan (nrp) =
! 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
    BEGIN

    LOCAL
	newnrp;

    MAP
	newnrp : BLOCK [1];

    MAP
	nrp : BLOCK [];

    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] EQL .nrp [page]		! 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 : REF BLOCK;

!+
!    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 )%
%SBTTL 'NUMBERTORFA - calculate relative record address'

GLOBAL ROUTINE numbertorfa (recnum) =
! 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
    BEGIN

    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 : BLOCK [];

    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] NEQ 0) AND (.recnum GTR .fst [fstmrn])) OR (.recnum LEQ 0) THEN RETURN false;

    !+
    !    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 RETURN false;

    RETURN .bytenum				! GIVE BACK THE BYTE ADDRESS
    END;

%( OF NUMBERTORFA )%
%SBTTL 'WRITEBUFFER - Write non-indexed buffer'

GLOBAL ROUTINE writebuffer : NOVALUE =
! 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
    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 0		!ANYTHING THERE TO WRITE?
    THEN
	BEGIN					!YES
	ascwrite (.fst [fstjfn], .rst [rstnrp], .bufadd, .rst [rstbytecount]);

	IF .rst[rst$h_byte_count]
          EQL ( ( %BPVAL / .fst[fst$h_bsz] ) * rms$k_page_size )          !m570
	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,   !m504
                                     36,
                                     .Fst[Fst$h_Bsz]); !RESET PTR TO TOP OF BUF
	    rst [rstbytecount] = 0;		! 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 )%
%SBTTL 'READBUFFER - read non-indexed buffer'

GLOBAL ROUTINE readbuffer : NOVALUE =
! 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.
    BEGIN

    LOCAL
        bytes_per_page;                 ! # of byte per page !a504

    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, .Fst[Fst$h_bsz] ); !M504

    !+
    !    FOR DEBUGGING
    !-

    rtrace ('READING BUFFER...');

    bytes_per_page = (%BPUNIT/.Fst[Fst$h_Bsz])*pagesize;  !a504

!+
!    IF WE ARE READING FROM THE TTY, PROCESS ONE RECORD AT A TIME
!    ELSE TRY TO FILL ENTIRE BUFFER
!-

    IF tty
    THEN
	rst [rstbytecount] = readtty ( .bufadd, .bytes_per_page )
    ELSE
	BEGIN
	rst [rstbytecount] = ascread (.fst [fstjfn],
                                      .rst [rstnrp],
                                      .bufadd,
                                      .bytes_per_page );        !m504

	rst [rstnrp] = .rst [rstnrp] + 1;	!NEXT GROUP OF RECORDS IN NEXT BKT
	END;

    IF .rst [rstbytecount] EQL 0
    THEN
	BEGIN
	setflag (rst [rstflags], flgeof);	! SET EOF FLAG

	IF dasd					!DISK FILE?
	THEN
	    posascfil (.fst [fstjfn], sizefile (.fst [fstjfn]));	!POSIT TO APPEND

	END;

    RETURN
    END;

%(OF READBUFFER)%
END

ELUDOM