Trailing-Edge
-
PDP-10 Archives
-
tops20-v7-ft-dist1-clock
-
7-sources/ffffnd.b36
There are 3 other files named ffffnd.b36 in the archive. Click here to see a list.
%TITLE 'FGNFND -- $FIND service routines for non-RMS file types'
!<BLF/REQUIRE 'BLI:BLF.REQ'>
MODULE ffffnd (IDENT = 'find'
) =
BEGIN
!
! COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1985, 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.
!
!
!
!
! ********** TABLE OF CONTENTS **********
!
!
!
! ROUTINE FUNCTION
! ------- --------
!
! F$FIND Dispatch to $FIND routines for each file type
! FINDSIX $FIND routines for ...
! FINDEBC
! FINDFBIN
! .
! .
! .
!
!
!
!+
! Need a require file similar to RMSREQ.R36
! which contains library of all FGNLIB
! routines.
!-
REQUIRE 'fffreq';
EXTERNAL
stksec; ! Stack's section
EXTERNAL ROUTINE
findisam, ! Find for Old Cobol Isam files
getsix,
getebc,
getfbin,
getisam,
getwindow,
six_rd_hdr, ! Read SIXBIT record header
g_byte,
ebc_rd_hdr,
ebc_new_block,
uaddr,
raddr,
checkeof; ! Error handlers
FORWARD ROUTINE
!
! $FIND processor
!
f$find,
!
! $FIND routines for foreign file types
!
findfbin,
findsix,
findebc, ! $FIND for EBCDIC files
fndefu, ! Fixed unblocked EBCDIC
fndevu, ! Variable unblocked EBCDIC
fndefb, ! Fixed blocked EBCDIC
fndevb; ! Variable blocked EBCDIC
%SBTTL 'F$FIND -- $FIND dispatcher'
GLOBAL ROUTINE f$find (usrrab : REF $rab_decl) =
BEGIN
LOCAL
findit;
rab = .usrrab;
rst = raddr (.rab [rab$a_isi]);
fst = raddr (.rst [rst$a_fst]);
cbd = raddr (rst [rst$z_current_bucket]);
!+
! Dispatch to the proper routine for this file organization
!-
findit = (CASE .fst [fst$h_file_class] FROM typ$k_fff_class_min TO
typ$k_fff_class_max OF
SET
[typ$k_sixbit] : findsix (); ! COBOL SIXBIT
[typ$k_ebcdic] : findebc (); ! COBOL EBCDIC
[typ$k_fortran_binary] : findfbin (); ! FORTRAN BINARY
[typ$k_isam] : findisam (); ! OLD COBOL ISAM
TES);
IF .findit EQL false THEN RETURN false;
setsuccess (op$k_find);
RETURN true;
END;
%SBTTL 'FINDFTNIMG -- $FIND for Fortran image files'
GLOBAL ROUTINE findftnimg =
BEGIN
LOCAL
crp : BLOCK [1],
rfapagenum,
nrp,
header : BLOCK [1],
recordlength,
usersize,
checkpageflag;
REGISTER
tempac;
checkpageflag = false;
tempac = .rst [rst$g_next_record_pointer]; ! Next record pointer
!+
! A relic from RMSFND (kept out of respect
! for this clever code --- 8/21/84).
!-
IF (.tempac^w2p)^p2w EQL .tempac ! Top of new page
THEN
checkpageflag = true; ! Check for EOF
!+
! Save the current record address.
!-
rst [rst$g_data_rfa] = (crp = .rst [rst$g_next_record_pointer]);
!+
!
! THIS SEEMS TO BE THE REAL CHECK FOR END OF FILE (8/21/84)
!-
!+
! If the current page is in our window, then we don't have
! to call an external routine to get it.
!-
rfapagenum = .crp [rfapage];
!+
! Check if this is the first page of the file buffers or
! a new page.
!
! If it points to a new page then we must FIRST check that
! the current record pointer is pointing to an actual record,
! not END OF FILE.
!
! NOTE:
! Because the buffers are statically allocated in the
! intermediate pages of the OWN storage of FORGN, the
! first page of the buffers will never be page 0.
!-
IF (.currentwindow EQL 1) OR ! There is no current bucket
(.currentfilepage NEQ .rfapagenum)
THEN
BEGIN
IF checkeof () ! End of file ?
THEN
SIGNAL (ff$_end_of_file);
!+
! Get the new page.
!-
IF getwindow (.rfapagenum, ! Page number
.checkpageflag) ! Page must exist
EQL false
THEN ! Page does not exist
SIGNAL (ff$_page_not_exist);
END;
!+
! Now, the page we want is in our window. We must set up
! a pointer to it in the RST.
!-
tempac = (rst [rst$g_page_pointer] = (.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.
!
! (no headers on Fortran image files)
!-
! header = ..tempac;
!++
! We will now compute the starting byte number 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 (if any).
!--
!+
! The record size (in bytes) was supplied by the user in the MRS field
! then compute the number of full words in this record
!-
usersize = .fst [fst$h_mrs];
!+
! Now, compute the number of full words, which is the
! total record size, in this case.
!-
recordlength = $size_in_words (.usersize, .fst [fst$h_bsz]);
nrp = .crp + .recordlength;
!+
! Update all data pages.
!-
rst [rst$h_record_size_words] = .recordlength; ! Save RSZ in words
rst [rst$h_record_size] = .usersize; ! And in bytes
rst [rst$g_next_record_pointer] = .nrp; ! Update the NRP always
! (if seq access-mode)
!+
! Update the count(s).
!-
.rst [rst$g_highest_byte] = .rst [rst$g_highest_byte] + .usersize;
RETURN true ! Record found
END; ! End of FINDFTNIMG
%SBTTL 'FINDFBIN -- $FIND for Fortran binary files'
GLOBAL ROUTINE findfbin =
BEGIN
LOCAL
this_lscw : REF $rms_lscw, !
next_lscw, ! Address of next LSCW
total_words, ! Length + LSCWs
words_in_record, ! Length of record
status;
!
! Set up RFA of this record
!
rst [rst$g_data_rfa] = .rst [rst$g_next_record_pointer];
words_in_record = total_words = 0;
!
! Line up the byte we want
!
IF g_byte (.rst [rst$g_data_rfa]) ! Status OK?
THEN
BEGIN
!
! This should be a code 1 LSCW
!
this_lscw = .rst [rst$g_page_pointer];
IF .this_lscw [lscw$b_code] NEQ 1 ! Bad code?
THEN
BEGIN ! Undefined file
rab [rab$h_sts] = rms$_udf; ! UDF error
RETURN false; ! Return an error
END;
!
! The next LSCW should be at the RFA of this
! record + the count in this LSCW.
!
next_lscw = .rst [rst$g_data_rfa] + .this_lscw [lscw$h_count_value];
!
! Set the initial record length and
! "data length" (LSCW count - 1).
!
words_in_record = .this_lscw [lscw$h_count_value] - 1;
total_words = .this_lscw [lscw$h_count_value];
!
! Fetch the next LSCW
!
IF NOT g_byte (.next_lscw) ! Get next LSCW
THEN
RETURN false; ! Bombed somewhere
this_lscw = .rst [rst$g_page_pointer]; ! Address of LSCW
!+
! We may at this point have one or more continuation
! LSCWs; we may have none at all and this could
! be a terminating LSCW. Loop to process any
! continuation LSCWs that come up.
!-
WHILE .this_lscw [lscw$b_code] EQL 2 DO
BEGIN
!
! Set the next LSCW's RFA and add the
! appropriate values to the counters.
!
next_lscw = .next_lscw + .this_lscw [lscw$h_count_value];
total_words = .total_words + .this_lscw [lscw$h_count_value];
words_in_record = .words_in_record + !
.this_lscw [lscw$h_count_value] - 1;
!+
! Go after the next LSCW.
!-
IF NOT g_byte (.next_lscw) ! Get next LSCW
THEN
RETURN false; ! Bombed somewhere
this_lscw = .rst [rst$g_page_pointer]; ! Address of LSCW
END;
!+
! We are here because THIS_LSCW is not a code 2
! (continuation) LSCW. We fervently hope that
! it is a code 3 (terminating) LSCW, and that
! the count contained therein is equal to the
! total number of words in the record (with LSCWs),
! which is contained in TOTAL_WORDS.
!-
IF .this_lscw [lscw$b_code] NEQ 3 ! Bad code?
THEN
BEGIN ! Undefined file
rab [rab$h_sts] = rms$_udf; ! UDF error
RETURN false; ! Return an error
END
ELSE
BEGIN
total_words = .total_words + 1;
IF .this_lscw [lscw$h_count_value] NEQ .total_words
THEN
BEGIN ! Undefined file
rab [rab$h_sts] = rms$_udf; ! UDF error
RETURN false; ! Return an error
END;
END;
!
! Set the next record pointer.
!
rst [rst$g_next_record_pointer] = .rst [rst$g_data_rfa] + .total_words;
!
! Set the record size
!
rst [rst$h_record_size] = .words_in_record;
!
! Reset the pointers
!
IF NOT g_byte (.rst [rst$g_data_rfa]) ! Get back to start of record
THEN
RETURN false; ! Just in case
!
! All OK, return same
!
rab [rab$g_rfa] = .rst [rst$g_data_rfa];
rab [rab$h_sts] = rms$_normal;
rab [rab$h_stv] = 0; ! Nothing special
rst [rst$v_last_operation] = op$k_find;
RETURN true
END
ELSE
RETURN false; ! Problem somewhere
END; ! End of FINDFTNBIN
%SBTTL 'FINDFTNASC -- $FIND for Fortran ascii files'
GLOBAL ROUTINE findfasc =
BEGIN
RETURN true
END;
%SBTTL 'FINDCASC -- $FIND for Cobol ascii files'
GLOBAL ROUTINE findcasc =
BEGIN
RETURN true
END;
%SBTTL 'FINDSIX -- $FIND for Cobol sixbit files'
GLOBAL ROUTINE findsix =
BEGIN
LOCAL
total_bytes, ! Record length + header length
offset_to_next, ! Bytes to next record
status;
STACKLOCAL
bytes_in_record; ! Length of record
!
! Set up RFA of this record
!
rst [rst$g_data_rfa] = .rst [rst$g_next_record_pointer];
!
! Line up the byte we want
!
IF g_byte (.rst [rst$g_data_rfa]) ! Status OK?
THEN
BEGIN
!+
! Get the record length
!-
IF NOT six_rd_hdr (.stksec OR bytes_in_record) ! Return on failure
THEN
RETURN false; ! May be EOF, UDF, etc.
!
! Set the Next Record Pointer
!
total_bytes = .rst [rst$v_rec_header_size] + .bytes_in_record;
offset_to_next = ((.total_bytes + rms$k_six_bpw - 1)/rms$k_six_bpw)*
rms$k_six_bpw;
rst [rst$g_next_record_pointer] = ! Set pointer
.rst [rst$g_next_record_pointer] + .offset_to_next;
!
! Set the record size
!
rst [rst$h_record_size] = .bytes_in_record;
!
! All OK, return same
!
rab [rab$g_rfa] = .rst [rst$g_data_rfa];
rab [rab$h_sts] = rms$_normal;
rab [rab$h_stv] = 0; ! Nothing special
rst [rst$v_last_operation] = op$k_find;
RETURN true
END
ELSE
RETURN false; ! Problem somewhere
END; ! End of FINDSIX
%SBTTL 'FINDEBC -- $FIND for Cobol ebcdic files'
GLOBAL ROUTINE findebc =
BEGIN
LOCAL
status;
!+
! Find the record according to file format.
!-
IF .fab [fab$v_bls] NEQ 0 ! Check blocking
THEN
IF .fst [fst$h_rfm] EQL fst$k_fix ! Blocked - what format?
THEN
status = fndefb () ! Fixed blocked
ELSE
status = fndevb () ! Variable blocked
ELSE
IF .fst [fst$h_rfm] EQL fst$k_fix ! Unblocked - what format?
THEN
status = fndefu () ! Fixed unblocked
ELSE
status = fndevu (); ! Variable unblocked
IF .status ! All OK?
THEN
BEGIN
rab [rab$g_rfa] = .rst [rst$g_data_rfa];
rab [rab$h_sts] = rms$_normal;
rab [rab$h_stv] = 0; ! Nothing special
rst [rst$v_last_operation] = op$k_find;
RETURN true;
END
ELSE
RETURN false;
END;
%SBTTL 'FNDEFU - $FIND for EBCDIC fixed unblocked records'
ROUTINE fndefu =
BEGIN
LOCAL
bytes_in_record; ! Length of record
!
! Set up RFA of this record
!
rst [rst$g_data_rfa] = .rst [rst$g_next_record_pointer];
!
! Get the length of this record
!
rst [rst$h_record_size] = bytes_in_record = .fst [fst$h_mrs];
!
! Set the Next Record Pointer
!
rst [rst$g_next_record_pointer] = ( ! Set pointer
.rst [rst$g_next_record_pointer] + ! From current position
.bytes_in_record); ! and record size
!
! Get this record into memory
!
RETURN g_byte (.rst [rst$g_data_rfa]);
END; ! End FNDEFU
%SBTTL 'FNDEVU - $FIND for EBCDIC variable unblocked records'
ROUTINE fndevu =
BEGIN
LOCAL
status;
STACKLOCAL
bytes_in_record; ! Length of record
!
! Set up RFA of this record
!
rst [rst$g_data_rfa] = .rst [rst$g_next_record_pointer];
!
! Line up the byte we want
!
IF g_byte (.rst [rst$g_data_rfa]) ! Status OK?
THEN
BEGIN
!+
! Get the record length
!-
IF NOT ebc_rd_hdr (.stksec OR bytes_in_record) ! Return on failure
THEN
RETURN false; ! May be EOF, UDF, etc.
!+
! Decrement the block byte count, in case we
! are in a blocked file.
!-
IF .fab [fab$v_bls] NEQ 0 ! Blocked?
THEN
rst [rst$g_blkbyt] = .rst [rst$g_blkbyt] - rms$k_header_ebc;
!
! Set the Next Record Pointer
!
rst [rst$g_next_record_pointer] = ( ! Set pointer
.rst [rst$g_next_record_pointer] + ! From current position
.rst [rst$v_rec_header_size] + ! Include header, if any
.bytes_in_record); ! and record size
!
! Set the record size
!
rst [rst$h_record_size] = .bytes_in_record;
!
! All OK, return same
!
RETURN true
END
ELSE
RETURN false; ! Problem somewhere
END; ! End FNDEVU
%SBTTL 'FNDEFB - $FIND for EBCDIC fixed blocked records'
ROUTINE fndefb =
BEGIN
LOCAL
status;
!+
! See if we have finished with this block,
! and skip to the next if so.
!-
IF .rst [rst$g_blkbyt] LEQ .rst [rst$v_rec_header_size] !
THEN
BEGIN
LOCAL
nrp, ! Current NRP
bytes_to_skip; ! Amount to add to it
nrp = .rst [rst$g_next_record_pointer];
bytes_to_skip = rms$k_ebc_b_p_bl - !
((.nrp + rms$k_ebc_b_p_bl) MOD rms$k_ebc_b_p_bl);
IF .bytes_to_skip EQL rms$k_ebc_b_p_bl ! Fix if on boundary
THEN
bytes_to_skip = 0;
nrp = .nrp + .bytes_to_skip; ! Point at next block
rst [rst$g_next_record_pointer] = .nrp; ! Set RST
!
! Reset block size count
!
rst [rst$g_blkbyt] = .fst [fst$h_mrs]*.fab [fab$v_bls];
END;
!+
! Find a record
!-
IF (status = fndefu ()) !
THEN
BEGIN
rst [rst$g_blkbyt] = .rst [rst$g_blkbyt] - .rst [rst$h_record_size];
RETURN true;
END
ELSE
RETURN .status;
END; ! End FNDEFB
%SBTTL 'FNDEVB - $FIND for EBCDIC variable blocked records'
ROUTINE fndevb =
BEGIN
LOCAL
status;
!+
! See if we have finished with this block,
! and skip to the next if so. One way to
! finish the block is to use up all its
! bytes (this is the obvious way). The
! other way is to suddenly come upon a
! record of zero length (this is a sneaky
! COBOL trick which destroys any pretense
! of clean dealing with these files).
!-
IF .rst [rst$g_blkbyt] LEQ .rst [rst$v_rec_header_size] !
THEN
BEGIN
IF NOT ebc_new_block () ! Get a new block in
THEN
RETURN false;
END
ELSE
BEGIN
!+
! We really hate to do this, but COBOL is rather beef-witted in its
! creation of these files -- COBOL neither puts a fixed number of
! records in a block (I KNOW what the user specified -- just trust
! me) nor does it put out variable-length blocks. It figures out
! the maximum block size (N records per block times maximum record
! size) and always writes that out, even if there are N 1-byte
! records in a block big enough to hold N 3000-byte records. Thus,
! we figure out that we have reached the end by searching for a null
! record header. This valuable exercise is brought to you courtesy
! of the original COBOL engineers from days gone by.
!-
STACKLOCAL
record_length;
IF NOT g_byte (.rst [rst$g_next_record_pointer]) ! Set us up
THEN
RETURN false;
IF NOT ebc_rd_hdr (.stksec OR record_length) ! Get the record length
THEN
RETURN false; ! Be thorough
IF .record_length EQL 0 ! No record?
THEN
BEGIN
IF NOT ebc_new_block () ! Get a new block
THEN
RETURN false;
END;
END;
IF (status = fndevu ()) !
THEN
BEGIN
rst [rst$g_blkbyt] = .rst [rst$g_blkbyt] - .rst [rst$h_record_size];
RETURN true;
END
ELSE
RETURN .status;
END; ! End FNDEVB
%SBTTL 'FINDCBIN -- $FIND for Cobol binary files'
GLOBAL ROUTINE findcblbin =
BEGIN
RETURN true
END;
%( This routine is sort of a template
GLOBAL ROUTINE findgeneric =
BEGIN
LOCAL
sizeoflastrecrd,
temp;
!+
! RFA access:
!-
![2] Using RFA from RAB, set up buffer, count, and pointers
IF .rab[Rab$b_rac] EQL Rab$k_Rfa
THEN
BEGIN
LOCAL
pagenum,
rfanum,
bytesperpage,
pagebyte;
Rst [Rst$v_Eof] = 0; ! Clear End-Of-File, this is random access
Rst [Rst$g_Data_Rfa] = rfanum = .Rab [Rab$g_Rfa];
bytesperpage = %BPVAL/.Fst[Fst$h_Bsz]*Rms$k_Page_Size;
pagenum = .rfanum/.bytesperpage; ! Get page number
pagebyte = .rfanum MOD .bytesperpage; ! and byte within page
Rst [Rst$g_Next_Record_Pointer] = .pagenum;
! Read page containing start of record
getwindow( .pagenum, true ); !!!!!! readbuffer ();
! Point page pointer to correct place in buffer
Rst [Rst$g_Page_Pointer] = CH$PLUS (.Rst [Rst$g_Page_Pointer], .pagebyte);
! Is RFA past end of file? If so, give EOF error
IF .Rst [Rst$h_Byte_count] LSS .pagebyte
THEN Usererror (Rms$_Eof); ! Record not found
! Update byte count
Rst [Rst$h_Byte_Count] = .Rst [Rst$h_Byte_Count] - .pagebyte;
RETURN true;
END;
!+
! SEQuential access:
!-
!+
! If we are at EOF, then don't try finding a record.
!-
IF .Rst[Rst$v_Eof]
THEN usererror (Rms$_Eof);
!+
! If the last RMS operation issued was 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 a $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 $FINDs 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.
!-
!+
! If last RMS call was a $FIND or last record was too big
! then skip record
!-
IF (.rst [Rst$v_Last_Operation] EQL op$k_find) OR .rst[rst$v_partial]
THEN
BEGIN ! To skip a record
IF .Rst[Rst$v_Partial]
THEN ! We must update current RFA
BEGIN
! Get last record's size
sizeoflastrecrd = .Rst [Rst$h_Record_Size];
! Compute start of this record
Rst [rst$g_Data_Rfa] =
.rst [rst$g_Data_Rfa]
+ .sizeoflastrecrd
+ .rst[rst$v_rec_header_size];
! lookat (' SIZEOFLAST: ', sizeoflastrecrd)
END;
rst [Rst$h_Record_Size] = getgeneric (false); ! Skip a record
rst [rst$v_partial] = 0; ! Clear the partial flag
END;
!+
! We must now update the RFA to point to the current
! record's starting address.
!-
rst [rst$g_Data_Rfa] = ! Compute start of next record
.Rst [rst$g_Data_Rfa] + .Rst [Rst$h_Record_Size];
!+
! Return RFA to user
!-
Rab [Rab$g_Rfa] = .Rst [rst$g_Data_Rfa]; ![2] Return RFA to user
RETURN true
END; ! End of FINDGENERIC
)%
END
ELUDOM