Trailing-Edge
-
PDP-10 Archives
-
704rmsf2
-
10,7/rms10/rmssrc/rmsfnd.b36
There are 6 other files named rmsfnd.b36 in the archive. Click here to see a list.
MODULE FINDER =
BEGIN
GLOBAL BIND FINDV = 1^24 + 0^18 + 13; !EDIT DATE: 7-SEP-78
%([
FUNCTION: THIS MODULE CONTAINS ALL ROUTINES WHICH PROCESS
THE $FIND MACRO IN RMS-20.
AUTHOR: S. BLOUNT
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
********** TABLE OF CONTENTS **************
ROUTINE FUNCTION
======= ========
$FIND DISPATCHER FOR $FIND MACRO
FINDASC PROCESSES $FIND FOR ASCII FILES
FINDSEQ PROCESSES $FIND FOR SEQUENTIAL FILES
FINDREL PROCESSES $FIND FOR RELATIVE FILES
FINDIDX PROCESSES $FIND FOR INDEXED FILES
REVISION HISTORY:
EDIT WHO DATE PURPOSE
==== === ==== =======
1 JK 5-AUG-76 NEW ASCII CHANGES.
2 SB 29-SEP-76 PUT REL RECORD # IN BKT FIELD ON FIND
3 SB 1-OCT-76 ADD CHECK FOR UPDPTR BIT IN FINDASC
4 SB 3-OCT-76 FIX BUG IN EDIT 2 (ZAP USER'S RFA)
5 SB 6-NOV-76 ADD RHDRDELETE BIT IN SEQ/REL REC HEADER
6 SB 1-MAR-77 PUT IN READ-AHEAD
7 SB 11-MAR-77 ACCOUNT FOR CHECK-BYTE
8 SB 23-MAR-77 UNDO EDIT 7
********** CODE FREEZE FOR RMS-20 RELEASE 1 ************
9 SB 25-MAR-77 CALL GTBYTE ONLY IF NEC IN FINDSEQ
10 SB 5-APR-77 SET UP RSZW FOR RELATIVE FILES, SPEED IT UP
*************************************************
* *
* NEW REVISION HISTORY *
* *
*************************************************
PRODUCT MODULE SPR
EDIT EDIT QAR DESCRIPTION
====== ====== ===== ===========
16 11 11856 A GET PAST THE LAST RECORD IN A SEQUENTIAL FILE
WILL PRODUCE EITHER: 1. A NEW PAGE IN THE FILE
(READ/WRITE ACCESS) AT CLOSE TIME, OR 2. AN
IMMEDIATE ILLEGAL MEMORY READ INTERRUPT (READ
ACCESS ONLY); IF THE LAST RECORD ENDS IN THE
LAST WORD OF THE LAST PAGE OF THE FILE.
20 12 12112 A RACE PROBLEM EXISTS BETWEEN THE TIME AN INDEXED
RECORD IS FOUND, AND LOCKED, ALLOWING SOME OTHER
USER TO POSSIBLY DELETE THE RECORD.
****************** Start RMS-10 V1.1 *********************
********************* TOPS-10 ONLY ***********************
PRODUCT MODULE SPR
EDIT EDIT QAR DESCRIPTION
====== ====== ===== ===========
100 13 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 DECLARATIONS ])%
EXTERNAL ROUTINE
CRASH,
GETWINDOW,
DOEOF,
DUMP,
NUMBERTORFA,
GETASCII,
GTBYTE,
LOCKIT,
! MAPIT,
! MOVEASCII,
RSETUP;
%([ ERROR MESSAGES REFERENCED WITHIN THIS MODULE ])%
EXTERNAL
MSGFAILURE, ! ROUTINE FAILURE
! MSGUNLOCKED, ! RECORD IS UNLOCKED
MSGCANTGETHERE, ! BAD CONTROL FLOW
MSGKEY, ! KEY ADDRESSING NOT DETECTED
MSGPTR, ! BAD POINTER RETURNED
MSGEOP; ! END OF PAGE FOUND
FORWARD ROUTINE FINDASC, ! FORWARD DECLARATIONS
FINDREL,
FINDSEQ;
REQUIRE 'RMSREQ';
EXTDECLARATIONS;
! $FIND
! =====
! PROCESSOR FOR $FIND MACRO.
! THIS ROUTINE PREFORMS ALL PROCESSING OF A $FIND MACRO.
! IT IS NOT CALLED DIRECTLY BY ANY OTHER ROUTINE WITHIN
! RMS-20, BUT IS CALLED ONLY FROM THE PRIMARY RMS DISPATCHER.
!
! FORMAT OF THE $FIND MACRO:
!
! $FIND <RAB-NAME> [,<ERROR-ADDRESS>]
!
! RAB FIELDS USED AS INPUT TO $FIND:
!
! ISI INTERNAL STREAM IDENTIFIER
! KBF KEY BUFFER ADDRESS (RELATIVE/INDEXED)
! KRF KEY OF REFERENCE (INDEXED)
! KSZ SIZE OF KEY IN BUFFER (INDEXED)
! RAC RECORD ACCESS
! RFA RECORD'S FILE ADDRESS
! ROP RECORD OPTIONS
! RB$RAH READ-AHEAD
! RB$KGT KEY IS GREATER THAN (INDEXED)
! RB$KGE KEY IS GREATER THAN OR EQUAL TO (INDEXED)
! RAB FIELDS WHICH ARE RETURNED BY $FIND:
!
! BKT RELATIVE RECORD NUMBER OF TARGET RECORD (RELATIVE)
! RFA RECORD'S FILE ADDRESS
! STS STATUS OF OPERATION
! STV ADDITIONAL STATUS INFORMATION
! INPUT:
! ADDRESS OF USER RECORD BLOCK ( RAB )
! ADDRESS OF USER ERROR ROUTINE
! OUTPUT:
! <STATUS FIELD>
! GLOBALS USED:
! FINDASC
! FINDREL
! FINDSEQ
GLOBAL ROUTINE %NAME('$FIND') ( BLOCK, ERRORRETURN ) =
BEGIN
ARGUMENT (BLOCK,BASEADD);
ARGUMENT (ERRORRETURN,BASEADD);
LOCAL
%IF INDX %THEN
RECDESC: FORMATS[ RDSIZE ], ! RECORD DESCRIPTOR FOR INDEXED FILES
%FI
DATABD: FORMATS[ BDSIZE ]; ! BUCKET DESCRIPTOR
%IF INDX %THEN
EXTERNAL ROUTINE
FINDIDX;
%FI
RMSENTRY ( $FIND );
%([ FETCH THE USER'S RAB AND ERROR ADDRESS ])%
RAB = .BLOCK; ! GET RAB ADDRESS
ERRADR = .ERRORRETURN; ! AND USER ERROR ADDRESS
CALLRSETUP ( PCI (TRUE )); ! A $FIND IS LEGAL ALWAYS
%([ WE NOW CAN DISPATCH TO THE CORRECT ROUTINE TO
LOCATE THE TARGET RECORD. NOTICE THAT FOR ALL
FILE ORGANIZATIONS EXCEPT INDEXED, ALL PARAMATERS
ARE STORED IN THE RST. HOWEVER, FOR INDEXED FILES,
WE MUST PASS A RECORD DESCRIPTOR PACKET AND A
BUCKET DESCRIPTOR. THESE ARGUMENTS ARE NOT USED BY
THIS ROUTINE, BUT SINCE THEY ARE REQUIRED FOR $GET,
THEY WILL BE PASSED TO FINDIDX. ])%
CASE FILEORG FROM 0 TO 3 OF
SET
[0]: %( ASCII )% CALLFINDASC;
[1]: %( SEQ )% CALLFINDSEQ;
[2]: %( REL )% CALLFINDREL;
%IF INDX %THEN
[3]: %( IDX )% CALLFINDIDX ( LCT ( RECDESC ), LCT ( DATABD ) )
%FI
TES; %( END OF CASE FILORG )%
SETSUCCESS;
USEREXIT %( EXIT TO USER )%
END; %( OF $FIND )%
! FINDASC
! ======
! PROCESSES $FIND MACRO FOR ASCII FILE
! INPUT:
! <NONE>
! OUTPUT:
! <NONE>
! IMPLICIT INPUTS:
!
! RSTDATARFA BYTE NUMBER OF CURRENT RECORD
! RSTRSZ SIZE IN BYTES OF CURRENT RECORD
!
! GLOBALS USED:
! GTBYTE
! SKIP
GLOBAL ROUTINE FINDASC =
BEGIN
LOCAL
SIZEOFLASTRECRD,
TEMP;
TRACE ( 'FINDASC' );
%([ IF WE ARE AT EOF, THEN FORGET THE WHOLE THING ])%
IF ENDOFFILE THEN ERROR ( ER$EOF );
%( [ IF THE LAST RMS OPERATION ISSUED WAS A
A $FIND, OR IF THE LAST RECORD FETCHED
WAS TOO BIG FOR THE USER'S BUFFER
(I.E., "PARTIAL" RECORD), THEN WE MUST
SKIP A RECORD AND POSITION OURSELVES TO THE
NEXT ONE. IN ALL OTHER CASES (I.E., THE
LAST JSYS WAS AN OPEN$ OR GET$). WE ARE
ALREADY POSITIONED AT THE CORRECT PLACE.
THIS MODULE ALSO MUST INSURE THAT THE CURRENT RECORD'S
STARTING ADDRESS IS MAINTAINED CORRECTLY. THIS PROCEDURE
VARIES DEPENDING UPON THE CURRENT FILE CONTEXT. FOR INSTANCE,
IF TWO SUCCESSIVE "$FIND"'S ARE DONE, A RECORD MUST BE SKIPPED
AND ITS LENGTH ADDED TO THE STARTING ADDRESS OF THE LAST RECORD.
IF THE LAST RECORD ACCESS WAS A "PARTIAL" RECORD, THE LENGTH
OF THAT RECORD MUST BE ADDED TO ITS STARTING ADDRESS, THEN
THE REST OF THE RECORD MUST BE SKIPPED AND THE AMOUNT
THAT WAS SKIPPED ALSO ADDED INTO THE CURRENT RFA ADDRESS.
FOR NORMAL CONDITIONS ( I.E., A $FIND IS DONE AFTER A SUCCESSFUL
$GET OR $FIND ), THEN THE LENGTH OF THE LAST RECORD ( I.E. CURRENT
RECORD TO THE USER ) MUST BE ADDED TO ITS STARTING BYTE NUMBER
TO PRODUCE THE ADDRESS OF THE NEXT RECORD, WHICH THEN IMMEDIATELY
BECOMES THE CURRENT RECORD.
THIS ENTIRE PROCESS MUST ALSO BE DONE FOR SEQUENCED FILES, EXCEPT
ALL BYTES ARE IN TERMS OF WORDS AND THE LINE-NUMBER MUST
BE ACCOUNTED FOR IN CERTAIN CALCULATIONS.
THE FOLLLOWING FIELDS WITHIN THE RST ARE USED BELOW:
RSTDATARFA STARTING BYTE # OF CURRENT RECORD
RSTRSZ SIZE IN ASCII BYTES OF CURRENT RECORD
=====
])%
IF ( .RST [ RSTLASTOPER ] IS C$FIND ) ! IF LAST RMS CALL WAS A $FIND
OR
( PARTIALFLAG ISON ) ! OR LAST RECORD WAS TOO BIG...
THEN
BEGIN %( TO SKIP A RECORD )%
IF PARTIALFLAG ISON
THEN %(WE MUST UPDATE CURRENT RFA)%
BEGIN
SIZEOFLASTRECRD = .RST [ RSTRSZ ]; ! GET LAST RECORD'S SIZE
RST [ RSTDATARFA ] = .RST [ RSTDATARFA ] + .SIZEOFLASTRECRD; ! COMPUTE START OF THIS RECORD
LOOKAT ( ' SIZEOFLAST: ', SIZEOFLASTRECRD )
END; %( OF IF PARTIALFLAG ISON )%
RST [ RSTRSZ ] = CALLGETASCII ( PCI ( FALSE )); ! SKIP A RECORD
CLRFLAG ( RST [ RSTFLAGS ], FLGPARTIAL ); ! CLEAR THE PARTIAL FLAG
END; %( OF IF LASTOPER = FIND OR PARTIALFLAG )%
%([ WE MUST NOW UPDATE THE RFA TO POINT TO THE CURRENT
RECORD'S STARTING ADDRESS ])%
RST [ RSTDATARFA ] = .RST [ RSTDATARFA ] + .RST [ RSTRSZ ]; ! COMPUTE START OF NEXT RECORD
%([ IF THIS IS A SEQUENCED FILE, AND IF WE NEED TO UPDATE
THE FILE POINTER (SUCH AS ON A $FIND-$FIND SEQUENCE,
THEN WE MUST NOW MOVE THE FILE POSITION TO THE NEXT FULL
WORD IN THE FILE. ])%
IF SEQUENCED AND ( CHKFLAG ( RST [ RSTFLAGS ], FLGUPDPTR ) ISON )
THEN
BEGIN %( MOVE TO NEXT FULL WORD )%
TEMP = ( 5 - .RST [ RSTDATARFA ] MOD 5 ) MOD 5;
RST [ RSTDATARFA ] = .RST [ RSTDATARFA ] + .TEMP;
RST [ RSTBYTECOUNT ] = .RST [ RSTBYTECOUNT ] - .TEMP;
TEMP = .RST [RSTPAGPTR]; !GET SUB-FIELD
IF .TEMP<30,6> NEQ 36 !WORD-ALIGNED ALREADY?
THEN RST [ RSTPAGPTR ] = POINT ( .RST [ RSTPAGPTR ] + 1, 36, 7);
%([ CLEAR THE "UPDATE THE PTR" FLAG ])%
CLRFLAG ( RST [ RSTFLAGS ], FLGUPDPTR )
END;
GOODRETURN
END; %( OF FINDASC )%
! FINDSEQ
! ======
! PROCESSES $FIND MACRO FOR SEQUENTIAL FILE
! INPUT:
! <NONE>
! OUTPUT:
! <NONE>
! IMPLICIT INPUTS:
!
! RSTDATARFA BYTE NUMBER OF CURRENT RECORD
! RSTRSZ SIZE IN BYTES OF CURRENT RECORD
! GLOBALS USED:
! GTBYTE
! DUMP
! LOCKIT
! NOTES:
!
! 1. THIS ROUTINE EXITS DIRECTLY TO THE USER ON AN ERROR.
GLOBAL ROUTINE FINDSEQ =
BEGIN
LOCAL
TEMP1,
RECORDLENGTH,
CRP: FORMAT, ! BYTE NUMBER OF CURRENT RECORD
RFAPAGENUM, ! PAGE NUMBER OF THE CURRENT RECORD
NRP, ! BYTE NUMBER OF NEXT RECORD
BYTESWORD, ! # OF BYTES IN ONE WORD
HEADER: FORMAT, ! STORAGE FOR RECORD HEADER
CHECKPAGEFLAG, ! ON FOR RFA ADDRESSING, OFF FOR SEQUENTIAL
VALID; ! FLAG FOR EXIT FROM LOOP
REGISTER TEMPAC;
TRACE ( 'FINDSEQ' );
!** [16] ROUTINE:FINDSEQ, AT LINE 7615, EGM, 27-JUL-78
%([16])% %([ FOR SEQUENTIAL ACCESS, WE CAN ASSUME THE NEXT PAGE EXISTS )%
%([16])% %( UNLESS THE CURRENT RECORD ADDRESS POINTS TO THE TOP OF )%
%([16])% %( A PAGE, IN WHICH CASE WE MUST CHECK FOR THAT PAGE )%
%([16])% %( HOWEVER, FOR RFA ADDRESSING, WE MUST CHECK IF THE TARGET PAGE
EXISTS BECAUSE IF THE FILE IS ONLY BEING READ, WE WILL GET
AN ILLEGAL INSTRUCTION TRAP IF THE PAGE DOESN'T EXIST.
WE CAN ALSO CLEAR THE USER'R RFA FIELD UNLESS HE
IS USING RFA ADDRESSING ])%
CHECKPAGEFLAG = FALSE;
IF RFAADR
THEN
CHECKPAGEFLAG = TRUE ! CHECK FOR RFA ADDRESSING
!** [16] ROUTINE:FINDSEQ, AT LINE 7626, EGM, 27-JUL-78
%([16])% ELSE %(MUST BE SEQUENTIAL ADDRESSING)%
%([16])% BEGIN
%([16])% RAB [ RABRFA ] = ZERO; ! CLEAR THE RFA FIELD
%([16])% TEMPAC = .RST [ RSTNRP ]; ! NEXT RECORD POINTER
%([16])% IF (.TEMPAC ^ W2P) ^ P2W EQL .TEMPAC ! TOP OF NEW PAGE
%([16])% THEN
%([16])% CHECKPAGEFLAG = TRUE; ! CHECK FOR EOF
%([16])% END; %(OF ELSE MUST BE SEQ ADRESSING)%
%( [ THIS IS THE MAIN LOOP. IT CONTINUES UNTIL ANY OF
THE FOLLOWING ARE FOUND:
1. RECORD UNAVAILABLE
2. EOF
3. VALID RECORD FOUND
] )%
VALID = FALSE; ! SET FLAG AS INVALID
WHILE .VALID IS FALSE DO
BEGIN %( TO FIND A RECORD )%
%([ FETCH THE USER'S RECORD-ACCESS PARAMETER (RAC)
AND USE IT TO DETERMINE THE LOCATION OF THE
NEXT RECORD. ])%
%( SAVE THE CURRENT RECORD ADDRESS )%
IF SEQADR
THEN
TEMPAC = .RST [ RSTNRP ] ! GET NRP
ELSE %(MUST BE RFA ADDRESSING)%
BEGIN
TEMPAC = .RAB [ RABRFA ]; ! GET USER'S RFA
%([ IF THE CURRENT RECORD ADDRESS IS LESS THAN
THE ADDRESS OF THE FIRST DATA RECORD, OR IS
GREATER THAN THE MAXIMUM RFA, THEN THERE IS
AN ERROR. THIS CHECK SHOULD NEVER FAIL UNLESS
RFA ADDRESSING WAS BEING USED ])%
IF ( .TEMPAC LSS .FST [ FSTLOBYTE ] ) ! MUST BE IN FILE DATA SPACE
OR
( .TEMPAC GEQ BITN ( 8 ) ) THEN USERERROR ( ER$RFA ); ! CHECK RFA
END; %(OF ELSE MUST BE RFA ADDRESSING)%
CRP = .TEMPAC;
%( [ DEQ CURRENT RECORD - NOTE THAT IF A
RECORD IS "FOUND" TWICE IN SUCCESSION, IT WILL
BE TREATED AS SEPARATE OPERATIONS (I.E. RECORD
WILL BE UNLOCKED AND LOCKED AGAIN
] )%
IF DATALOCKED THEN UNLOCK ( RST [ RSTDATARFA ] ); ! UNLOCK THE CURRENT RECORD
%([ FETCH THE RECORD POINTER AND MAKE IT CURRENT ])%
RST [ RSTDATARFA ] = .CRP; ! SAVE RP FOR USER
%([ IF THE CURRENT PAGE IS IN OUR WINDOW, THEN
WE DONT HAVE TO CALL AN EXTERNAL ROUTINE TO GET IT ])%
RFAPAGENUM = .CRP [ 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 )% LCI ( CHECKPAGEFLAG ) )
!** [16] ROUTINE:FINDSEQ, AT LINE 7692, EGM, 27-JUL-78
%([16])% IS FALSE THEN
%([16])% BEGIN %( PAGE DOES NOT EXIST )%
%([16])% IF RFAADR
%([16])% THEN ! RFA ERROR
%([16])% USERERROR ( ER$RFA )
%([16])% ELSE ! END OF FILE
%([16])% CALLDOEOF
%([16])% END; %( OF 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 ])%
TEMPAC = (RST [ RSTPAGPTR ] = ( .CURENTBUFFERADR ) + .CRP [ OFSET ]);
%([ THE RECORD IS NOW AVAILABLE TO US. WE MUST
PICK UP THE RECORD HEADER TO SEE IF IT IS A
VALID RECORD. ])%
HEADER = . .TEMPAC;
%([ IF THE HEADER IS AN END-OF-PAGE MARKER,
THEN WE NEED TO BUMP OUR POINTER TO THE
START OF THE NEXT FILE PAGE. THIS CONDITION
SHOULD OCCUR ONLY IF THE FILE HAS THE
"FB$BLK" ATTRIBUTE. ])%
IF .HEADER IS EOPMARKER ! CHECK FOR END-OF-PAGE
THEN
BEGIN %( WE HAVE FOUND A END-OF-PAGE MARKER )%
RTRACE (' END-OF-PAGE MARKER FOUND');
%([ FOR RFA ADDRESSING, WE CAN GIVE IMMEDIATE ERROR ])%
IF RFAADR THEN USERERROR ( ER$RFA );
IF BLOCKED
THEN %(WE CAN BUMP THE PTR TO THE NEXT FILE PAGE)%
NRP = ( .CRP OR OFSETMASK ) + %O'1' ! BUMP TO NEXT PAGE
ELSE
RMSBUG ( MSGEOP ); ! END-OF-PAGE MARKER FOUND
END %( OF IF HEADER IS EOPMARKER )%
ELSE %( HEADER ISNT EOPMARKER )%
BEGIN
LOOKAT ( ' HEADER READ = ', HEADER );
%([ CHECK THAT UNDEFINED BITS IN HEADER ARE OFF ])%
IF .HEADER [ RHDRUNDEF ] ISON THEN USERERROR ( ER$RFA ); ! CHECK UNUSED PORTION OF HEADER
%([ WE WILL NOW COMPUTE THE STARTING BYTE #
OF THE NEXT RECORD. WE WILL DO THIS BY
COMPUTING THE NUMBER OF FULL WORDS THIS
RECORD OCCUPIES AND ADDING THE SIZE OF
THE RECORD HEADER ])%
RECORDLENGTH = SIZEINWORDS ( .HEADER [ RHDRSIZE ], .FST [ FSTBSZ ] );
NRP = .CRP + .RECORDLENGTH + HEADERSIZE;
LOOKAT ( ' UPDATED NRP = ', NRP );
%([ WE MUST NOW CHECK TO SEE IF THIS RECORD
ACTUALLY EXISTS, OR IF IT HAS BEEN
DELETED SOMETIME IN THE PAST. BEFORE WE
CAN CHECK THE "VALID" BIT FOR SURE, WE
MUST LOCK THE RECORD SO NOONE ELSE CAN COME
IN AND DELETE IT AFTER WE HAVE ALREADY
EXAMINED THE DELETED BIT. HOWEVER, THE OVERHEAD
FOR LOCKING THE RECORD IS EXTREME. THEREFORE,
WE WILL CHECK THE BIT TO SEE IF THE RECORD
EXISTS OR NOT. IF SO, WE WILL LOCK THE RECORD
AND CHECK AGAIN. IF EITHER CHECK FAILS, THE
RECORD HAS BEEN DELETED. IF IT IS DELETED
AFTER WE HAVE CHECKED THE BIT BUT BEFORE WE
CAN LOCK IT, THAT'S OK BECAUSE WE WILL CONTINUE
AND THE RECORD WILL BE UNLOCKED DURING THE NEXT
PASS THRU THIS LOOP. ])%
%([ FIRST, CHECK THAT THIS RECORD HAS BEEN
WRITTEN (THE "VALID" BIT IS ON) ])%
IF ( .HEADER AND RHDRVALID ) IS OFF
THEN %(IS PROBABLY THE EOF)%
BEGIN
IF RFAADR THEN USERERROR ( ER$RFA ); ! BAD RFA
CALLDOEOF ! SEQ ACCESS MEANS EOF
END; %(OF IF VALID BIT IS OFF)%
IF ( .HEADER AND RHDRDELETE ) IS OFF
THEN
BEGIN
IF LOCKING THEN LOCKREC ( CRP ); ! LOCK RECORD
HEADER = . ( .RST [ RSTPAGPTR ] ) ! RE-FETCH HEADER
END; %( OF RECORD EXISTS )%
%([ WE NOW MUST CHECK THE HEADER AGAIN TO MAKE SURE ITS STILL GOOD ])%
IF ( .HEADER AND RHDRDELETE ) IS OFF
THEN
VALID = TRUE ! LEAVE THE LOOP
ELSE %(RECORD HAS BEEN DELETED)%
BEGIN
IF RFAADR THEN USERERROR ( ER$DEL )
END %(OF ELSE RECORD IS DELETED)%
END; %( OF IF HEADER ISNT EOPMARKER )%
%( UPDATE ALL DATA BASES )%
RST [ RSTRSZW ] = .RECORDLENGTH; ! SAVE RECORD SIZE IN WORDS
RST [ RSTRSZ ] = .HEADER [ RHDRSIZE ]; ! AND IN BYTES
IF CHKFLAG( RAB [RABROP], ROPNRP) ISON
THEN RST [RSTNRP] = .CRP !CAUSE SEQ GET TO ALW GET FND REC
ELSE IF ( SEQADR ) OR ( CURRENTJSYS IS C$GET )
THEN RST [ RSTNRP ]= .NRP; ! UPDATE THE NRP IF SEQUENTIAL ACCESS-MODE
END; %( OF WHILE LOOP )%
%( FALL THRU AS SOON AS A VALID RECORD
IS FOUND )%
LOOKAT ( ' RECORD FOUND AT: ', CRP );
LOOKAT ( ' NRP = ', NRP );
%([ SET UP THE USER'S RFA BECAUSE THE OPERATION WAS OK ])%
RAB [ RABRFA ] = .RST [ RSTDATARFA ];
GOODRETURN %( BACK TO $FIND )%
END; %( OF FINDSEQ )%
! FINDREL
! ======
! PROCESSOR FOR $FIND MACRO FOR A RELATIVE FILE
! INPUT:
! <NONE>
! OUTPUT:
! <NONE>
! IMPLICIT INPUTS:
!
! RSTDATARFA BYTE NUMBER OF CURRENT RECORD
! RSTRSZ SIZE IN BYTES OF CURRENT RECORD
!
! GLOBALS USED:
! NUMBERTORFA
! GTBYTE
! LOCKIT
GLOBAL ROUTINE FINDREL =
BEGIN
LOCAL
CRP,
TEMPNRP,
HEADER,
TEMP,
CURRENTEMTPAGE, ! PAGE NUMBER ALREADY CHECKED TO SEE IF IT EXISTS
VALID,
BYTENUM;
REGISTER
TEMPAC; ! AC USED FOR TEMPORARY CALCULATIONS
MAP
HEADER: FORMAT,
BYTENUM: FORMAT;
TRACE ( 'FINDREL' );
%([ LOOP UNTIL A VALID RECORD IS FOUND ])%
VALID = FALSE; ! ASSUME RECORD IS NOT VALID
CURRENTEMTPAGE = ZERO; ! CLEAR THIS VALUE
%([ IN THIS LOOP, WE WILL UPDATE THE USER'S PERMANENT
NRP ONLY WHEN A GOOD RECORD IS FOUND. THIS IS TO
AVOID THE SITUATION WHICH WOULD ARISE IF THE USER
TRIED TO READ A RECORD, WHEN HE WAS ALREADY AT THE
LAST RECORD IN THE FILE. IN SUCH A CASE, IT IS
IMPORTANT THAT HIS NRP NOT BE CHANGED FROM WHAT IT
WAS BEFORE HE ATTEMPTED TO READ THE RECORD. THERE
IS A SMALL DRAWBACK TO THIS TECHNIQUE, THOUGH.
IF THE USER TRIES TO READ A RECORD, AND THE ONLY ONE
ON THE CURRENT PAGE IS LOCKED BY SOMEONE ELSE, HE
WILL GET AN ERROR MESSAGE ( AS HE SHOULD ), BUT HIS
NRP WILL NOT HAVE BEEN CHANGED FROM WHAT IT WAS BEFORE
HE DID THE $GET. ])%
TEMPNRP = .RST [ RSTNRP ]; ! DONT UPDATE REAL NRP UNTIL OPERATION SUCCEEDS
WHILE .VALID IS FALSE
DO
BEGIN
%([ FETCH THE ADDRESS OF THE TARGET RECORD,
WHICH DEPENDS ON THE USER'S RECORD-ACCESS (RAC)
FIELD VALUE . ])%
CRP = ( CASE RECORDACCESS FROM 0 TO 2 OF
SET
[0]: %( SEQ )% .TEMPNRP; %( CRP = NRP )%
[1]: %( KEY )% . ( .RAB [ RABKBF ]); %( CRP = EA )%
[2]: %( RFA )% .RAB [ RABRFA ]; %( CRP = RFA )%
! ??? [3]:
TES); %( END OF SET RABADR )%
%([ UNLOCK THE CURRENT RECORD ])%
IF DATALOCKED THEN UNLOCK ( RST [ RSTDATARFA ] );
%([ STORE THE CURRENT RECORD NUMBER IN THE RST ])%
RST [ RSTDATARFA ] = .CRP ; ! SET CRP IN USER'S RAB
%([ FIND THE STARTING BYTE ADDRESS OF THIS RECORD ])%
IF (BYTENUM = CALLNUMBERTORFA ( LCI ( CRP ))) IS FALSE
THEN
BEGIN ! THE RECORD NUMBER WAS BEYOND THE MRN
%([ THE RECORD NUMBER OF THE TARGET RECORD
WAS .GTR. THAN THE MAXIMUM RECORD NUMBER
OF THE FILE. IF THE USER WAS PROCESSING THE
FILE SEQUENTIELLY, THEN HE SHOULD GET AN EOF
ERROR; OTHERWISE, HE SHOULD GET A RECORD-NOT
-FOUND ERROR. ])%
IF SEQADR THEN CALLDOEOF;
USRSTS = ER$KEY; ! ASSUME KEY ERROR
IF RFAADR THEN USRSTS = ER$RFA;
USEXITERR ! EXIT TO USER
END; %( OF IF NUMBERTORFA IS FALSE )%
%([ WE MUST NOW POSITION TO THE TARGET RECORD. HOWEVER,
WE MUST ALSO CHECK TO SEE IF THE PAGE EXISTS. IF NOT,
THEN WE MAY BE THRU (IF KEY ACCESS IS BEING USED).
IF IT DOES EXIST, THEN WE CAN GO AHEAD AND READ IT. ])%
IF CALLGTBYTE ( LCI ( BYTENUM ), %( RFA ADDRESS )%
PCI ( TRUE )) %( ABORT IF NON-EXISTENT )%
IS FALSE
THEN BEGIN %(WE HAVE FOUND A NON-EXISTENT PAGE)%
IF ( NOT SEQADR ) THEN USERERROR ( ER$RNF ); ! RECORD NOT FOUND
%([ THIS PAGE IS NON-EXISTENT. THIS COULD
BE CAUSED EITHER BY A SPARSE FILE,
OR BY THE TRUE LAST PAGE IN THE FILE.
IF THE FILE IS SPARSE ( THERE IS MORE
TO COME ), THEN WE WILL CONTINUE TO
PROCESS IT. BUT IF WE HAVE REACHED THE
LAST PAGE IN THE FILE, WE MUST GIVE AN
EOF ERROR RETURN ])%
IF ( TEMPAC = .BYTENUM [ RFAPAGE ] )
ISNT
( .CURRENTEMTPAGE )
THEN BEGIN %(WE MUST CHECK THIS PAGE)%
TEMPAC = $CALL (NEXTPAGE, .FST[FSTJFN], .TEMPAC);
IF .TEMPAC IS FALSE
THEN
CALLDOEOF %([ IF NO MORE PAGES EXIST, ITS THE EOF ])%
ELSE
CURRENTEMTPAGE = .TEMPAC; ! REMEMBER THIS PAGE
END %(OF IF WE HAVEN'T CHECKED THIS PAGE)%
END %( OF IF GTBYTE IS FALSE )%
ELSE %(WE HAVE MAPPED IN THE CORRECT PAGE)%
BEGIN
HEADER = . ( .RST [ RSTPAGPTR ] ); ! FETCH HEADER
IF .HEADER IS EOPMARKER THEN RMSBUG ( MSGPTR ); ! BAD HEADER FOUND
IF ( .HEADER [ RHDRUNDEF ] ISNT ZERO )
THEN USERERROR ( ER$RFA ); ! BAD RFA
%([ CHECK TO SEE IF THIS RECORD HAS BEEN WRITTEN ])%
IF ( .HEADER AND RHDRVALID ) IS OFF
THEN %(THE RECORD WAS NEVER CREATED)%
BEGIN
RAB [ RABRFA ] = ZERO; ! ZAP RFA
IF NOT SEQADR THEN USERERROR ( ER$RNF );
END %(OF IF VALID BIT IS OFF)%
ELSE %(THE RECORD WAS WRITTEN AT SOME TIME)%
BEGIN
IF ( .HEADER AND RHDRDELETE ) IS OFF
THEN
BEGIN
IF LOCKING THEN LOCKREC ( CRP );
HEADER = . ( .RST [ RSTPAGPTR ] )
END; %( OF IF RECORD EXISTS )%
%([ RE-CHECK THE RECORD HEADER ])%
IF ( .HEADER AND RHDRDELETE ) IS OFF
THEN
VALID = TRUE ! RESET THE FLAG SO WE'LL FALL THRU
ELSE %(THE RECORD IS DELETED)%
BEGIN
%([ DECIDE WHAT TO DO DEPENDING ON RAC VALUE ])%
CASE RECORDACCESS FROM 0 TO 2 OF
SET
[0]: %(SEQ)% 0; !DO NOTHING
[1]: %(KEY)% USERERROR ( ER$RNF );
[2]: %(RFA)% USERERROR ( ER$DEL )
TES; %(END OF CASE RECORDACCESS)%
RAB [ RABRFA ] = ZERO
END %(OF ELSE RECORD IS DELETED)%
END %( OF IF RECORD IS VALID)%
END; %( OF ELSE IF GTBYTE IS TRUE )%
LOOKAT ( ' RECORD HEADER: ', HEADER);
%([ UPDATE USERS PARAMETER BLOCK ])%
IF ( SEQADR ) OR ( CURRENTJSYS IS C$GET )
THEN TEMPNRP = .CRP +1; ! UPD LOOP VAR TO CRP+1
%([ STORE THE SIZE IN BYTES AND WORDS OF THIS RECORD ])%
RST [ RSTRSZ ] = .HEADER [ RHDRSIZE ]; ! SAVE SIZE OF THIS RECORD
RST [ RSTRSZW ] = SIZEINWORDS ( .RST [ RSTRSZ ], .FST [ FSTBSZ ] )
END; %( OF WHILE VALID IS FALSE LOOP )%
IF CHKFLAG( RAB [RABROP], ROPNRP) ISON
THEN RST [RSTNRP] = .CRP !CAUSE SEQ GET TO ALW BE FND REC
ELSE IF ( SEQADR ) OR ( CURRENTJSYS IS C$GET )
THEN RST [ RSTNRP ]= .CRP + 1; ! UPDATE THE NRP IF SEQ ACC-MODE
%([ STORE THE NUMBER OF THE CURRENT RECORD IN
THE BKT FIELD. NOTE THAT IF THERE IS AN ERROR
LATER DURING THE PROCESSING OF THIS RECORD,
THE BKT FIELD WILL STILL CONTAIN THE NUMBER
OF THE TARGET RECORD. THUS, USER'S SHOULD NOT
ASSUME THAT A NON-ZERO RECORD NUMBER IN BKT
REFLECTS A SUCCESSFUL OPERATION. ])%
RAB [ RABRFA ] = ( RAB [ RABBKT ] = .CRP);
GOODRETURN
END; %( OF FINDREL )%
! FINDIDX
! =======
! ROUTINE TO PROCESS THE $FIND MACRO FOR AN INDEXED FILE.
! THIS ROUTINE IS CALLED ALSO BY THE $GET PROCESSOR IN
! ORDER TO POSITION TO THE CORRECT RECORD.
! INPUT:
! RECDESC RECORD DESCRIPTOR PACKET
! <NO FIELDS USED AS INPUT>
!
! DATABD BUCKET DESCRIPTOR (RETURNED)
! OUTPUT:
! <NO STATUS RETURNED>
! INPUT ARGS MODIFIED:
! RECORD DESCRIPTOR:
! RFA RFA OF TARGET RECORD
! RRV RRV ADDRESS OF TARGET RECORD
!
! BUCKET DESCRIPTOR
! ALL FIELDS RETURNED
! ROUTINES CALLED:
! FIDXSEQ
! FBYKEY
! FBYRRV
! PUTBKT
! LOCKIT
! SETNRP
! RAB FIELDS REFERENCED:
! RAC RECORD ACCESS VALUE
! KRF KEY OF REFERENCE
! NOTE:
! 1. IF THERE WAS AN ERROR DURING THIS ROUTINE, IT WILL NOT
! RETURN. IT WILL EXIT DIRECTLY TO THE USER.
GLOBAL ROUTINE FINDIDX ( RECDESC, DATABD ): NOVALUE =
BEGIN
%IF INDX %THEN
ARGUMENT (RECDESC,BASEADD);
ARGUMENT (DATABD,BASEADD);
MAP
RECDESC: POINTER,
DATABD: POINTER;
EXTERNAL ROUTINE
FBYRFA,
FIDXSEQ, ! FIND SEQ RECORD
FRECRFA, ! FIND THE RECORD BY RFA ADDRESSNG
FBYKEY,
SETNRP,
PUTBKT;
LOCAL
BDPTR: POINTER, ! PTR TO CURRENT BUCKET DESC
SAVEDSTATUS, ! STORE STATUS HERE
NEXTBUCKET, ! NEXT BUCKET FOR READ-AHEAD
BUCKETSIZE, ! SIZE OF A BUCKET
TPTR: POINTER, ! TEMP POINTER
NEXTBD: FORMATS[ BDSIZE ], ! BUCKET DESC OF NEXT BUCKET
LOCKACCESS, ! SHARED/EXCLUSIVE
RECORDPTR: POINTER; ! PTR TO CURRENT RECORD
EXTERNAL ROUTINE
FBYRRV, ! LOCATE RECORD BY RRV ADDRESS
GETBKT;
TRACE ('FINDIDX');
%([ SET UP THE PRIMARY KEY DESCRIPTOR ])%
KDB = .FST [ FSTKDB ];
%([ CLEAR SOME FIELDS IN THE RECORD DESCRIPTOR WHICH
WE WILL PASS TO THE LOWER LEVEL ROUTINES ])%
%([ NOTE THAT BOTH THE FLAGS AND STATUS FIELDS ARE CLEARED ])%
RECDESC [ RDSTATUS ] = ZERO; ! CLEAR STATUS BITS
RECDESC [ RDFLAGS ] = RDFLGHORIZOK; ! HORIZONTAL SEARCH OK
%([ FETCH THE CURRENT BUCKET AND SET IT NULL (IN THE RST) ])%
FETCHCURRENTBKT ( DATABD );
%([ DISPATCH TO THE CORRECT ROUTINE ])%
IF SEQADR
THEN BEGIN !SEQ ACCESS
SETNULLBD ( CBD ); ! INDICATE THAT THERE IS NO CURRENT BKT
SAVEDSTATUS = CALLFIDXSEQ ( BPT ( RECDESC ),
BPT ( DATABD ) );
END %(OF IF SEQUENTIAL ACCESS)%
ELSE BEGIN !RANDOM ACCESS
%([ WE CAN RELEASE THE CURRENT BUCKET BECAUSE SINCE
THIS IS A RANDOM ACCESS, IT IS UNLIKELY THAT BOTH
THE TARGET RECORD AND THE CURRENT RECORD ARE IN THE
SAME BUCKET. ])%
RELEASCURENTBKT;
%([ WE NOW MUST LOCK THE ENTIRE INDEX STRUCTURE SO THAT
WE CAN MOVE AROUND THE FILE AT WILL UNTIL WE REACH
THE TARGET RECORD. ])%
IF LOCKING
THEN BEGIN
IF LOCKINDEX (ENQBLK, ENQSHR) IS FALSE ! WAIT, SHARED
THEN RETURNSTATUS ( ER$EDQ ); ! SHOULDN'T FAIL
END; %(OF IF LOCKING)%
%([ DISPATCH TO CORRECT ROUTINE DEPENDING ON RECORD ACCESS ])%
IF KEYADR
THEN SAVEDSTATUS = CALLFBYKEY ( BPT ( RECDESC ),
BPT ( DATABD ) )
ELSE SAVEDSTATUS = CALLFRECRFA ( BPT ( RECDESC ),
BPT ( DATABD ) );
END; %(OF ELSE KEY OR RFA ACCESS)%
%([ AT THIS POINT, WE HAVE EITHER SUCCEEDED OR FAILED IN
OUR EFFORTS TO LOCATE THE NEXT RECORD. HOWEVER, IN EITHER
CASE, WE MAY HAVE LOCKED THE INDEX OF THE FILE WHICH NOW
MUST BE UNLOCKED. ALSO, IF WE LOCATED THE TARGET RECORD,
WE MUST LOCK ITS BUCKET IF WE HAVE NOT ALREADY DONE SO. ])%
IF LOCKING AND .SAVEDSTATUS ISNT FALSE
THEN BEGIN %(WE MUST DO SOME UNLOCKING & LOCKING)%
IF ( NOT BKTLOCKED ( DATABD ) ) %([ LOCK THE BUCKET IF IT IS NOT LOCKED ])%
THEN BEGIN %(LOCK THE BUCKET DESCRIPTOR)%
LOCKACCESS = ENQSHR; ! ASSUME READ-ONLY
IF NOT INPUTMODE THEN LOCKACCESS = ENQEXC;
RTRACE (' LOCKING THE BUCKET...');
IF LOCKBD ( DATABD, ENQAA, .LOCKACCESS ) IS FALSE
THEN BEGIN
RTRACE (' ***LOCK AREADY LOCKED');
SAVEDSTATUS = FALSE; ! RETURN FAILURE
CALLPUTBKT ( %(NO)% PCI ( FALSE ),
%(BKT)% BPT ( DATABD ) );
USRSTS = ER$RLK ! SET ERROR CODE
END %(OF COULDNT LOCK BUCKET)%
END; %(OF IF NOT BKTLOCKED)%
!** [20] ROUTINE:FINDIDX, AT LINE 8219, EGM, 7-SEP-78
%([20])% %([ IT IS POSSIBLE THAT ANOTHER USER COULD HAVE DELETED ])%
%([20])% %([ THIS RECORD BETWEEN THE TIME WE FOUND IT AND LOCKED IT ])%
%([20])% %([ IF THIS IS THE CASE, UNLOCK THE BUFFER AND SAY THE ])%
%([20])% %([ RECORD WAS NEVER FOUND ])%
%([20])%
%([20])% RECORDPTR = .RECDESC [ RDRECPTR ];
%([20])% IF DELETEFLAG ( RECORDPTR ) IS ON
%([20])% THEN BEGIN !REC ACTU DELETED
%([20])% RTRACE (' UNLOCKING BKT - REC. DELETED!');
%([20])% UNLOCKBUCKET ( .DATABD [ BKDBKTNO ] );
%([20])% SAVEDSTATUS = FALSE; ! RETURN FAILURE
%([20])% USRSTS = ER$RNF ! SET ERROR CODE
%([20])% END; %(OF IF DELETEFLAG)%
%([20])%
END; %(OF IF LOCKING)%
%([ UNLOCK THE INDEX STRUCTURE, IF NECESSARY ])%
IF INDEXLOCKED THEN UNLOCKINDEX;
%([ WE HAVE NOW DONE THE $FIND. WAS IT OK? ])%
IF .SAVEDSTATUS IS FALSE
THEN BEGIN
RTRACE (' ERROR IN FIND...');
%([ CLEAR THE USER'S RFA AND OUR RECORD POINTER ])%
RST [ RSTDATARFA ] = ZERO;
IF NOT RFAADR THEN RAB [ RABRFA ] = ZERO;
USEXITERR ! EXIT TO USER
END; %(OF IF THE FIND FAILED)%
%([ THE $FIND WAS SUCCESSFUL. WE MUST NOW SAVE THE
CURRENT RFA AND THE CURRENT BUCKET. HOWEVER,
IF WE ARE CURRENTLY PROCESSING A $GET MACRO,
THEN WE SHOULD RETURN WITHOUT PEFORMING THE
NORMAL CLEAN-UP OPERATIONS, WHICH WILL BE
DONE IN THE $GET ROUTINE. ])%
SETCURRENTBKT ( DATABD ); ! SAVE CURRENT BKT
%([ SAVE THE PTR TO THE CURRENT RECORD AND SET THE
RECORD SIZE OF THIS RECORD (THIS IS USED ONLY ON
AN $UPDATE TO CHECK IF THE RECORD SIZE HAS BEEN
CHANGED BY THE USER. IF RECORD-LENGTH MODIFICATION
IS SUPPORTED, THEN THIS OPERTION IS UNNECESSARY) ])%
RST [ RSTPAGPTR ] = ( RECORDPTR = .RECDESC [ RDRECPTR ]); ! AND PTR TO CURRENT RECORD
IF FIXEDLENGTH
THEN RST [RSTRSZ] = .FST [ FSTMRS ]
ELSE RST [RSTRSZ] = .RECORDPTR [ DRRECSIZE ] ;
RST [ RSTRSZW ] = SIZEINWORDS ( .RST [ RSTRSZ ], .FST [ FSTBSZ ] );
IF CURRENTJSYS IS C$GET
THEN RETURN;
%([ UPDATE THE NEXT-RECORD-POINTER DATA IN THE RST ])%
CALLSETNRP ( BPT ( RECDESC ), BPT ( DATABD ) ); ! UPDATE DATA BASE
%([ SET UP THE RFA IN THE USER'S RAB ])%
RAB [ RABRFA ] = .RECDESC [ RDRRV ];
RETURN;
%FI
END; %(OF FINDIDX)%
END
ELUDOM