Trailing-Edge
-
PDP-10 Archives
-
RMS-10_T10_704_FT2_880425
-
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