To read the data for a PDS member we fist have to locate the directory entry that points to the data. We establish two loops to process through the directory. The outer loop reads the directory blocks and the inner loop steps through the directory entries contained in the block.
DIRBLOOP DS 0H SLR R1,R1 IC R1,R GET RECORD NUMBER LA R1,1(,R1) ADD STC R1,R ONE LA R1,IORB BAL R14,XIO * LTR R15,R15 BNZ DIREOF * * LA R2,INBUF POINTER TO PDS INDEX RECORD SLR R3,R3 GET LENGTH ICM R3,B'0011',0(R2) USED LA R2,2(,R2) POINT TO FIRST ENTRY S R3,=F'2' ADJUST LENGTH
This code established the processing for the outer loop (Directory Block Loop). It read through a directory one block at a time. Register 3 is set to contain the remaining length of data in the block. Register two is set to point to the next directory entry to be processed.
Our CCW chain for reading the directory blocks is a SEEK, SEARCH ID EQUAL, TIC, READ DATA (length=256). Because I allocated the data set and specified the number of directory blocks to be less than the number that will fit on a single track, I know there is no need to increment the track. In a more general approach we would have to deal with this issue.
DIRLOOP DS 0H C R3,=F'0' MORE DATA BNH DIRBLOOP AVAILABLE
*
CLC =XL8'FFFFFFFFFFFFFFFF',0(R2) END OF DIRECOTRY?
BE DIREOF * CLC =CL8'TXXNUC28',0(R2) IS THIS OUR ENTRY BE DIRFOUND * SLR R1,R1 ICM R1,B'0001',11(R2) GET C FIELD N R1,=A(X'1F') GET USER DATA LENGTH SLL R1,1 MULTIPLY BY 2 LA R1,12(,R1) ADD IN FIXED LENGTH AR R2,R1 POINT TO NEXT ENTRY SR R3,R1 ADJUST LENGTH B DIRLOOP PROCESS NEXT DIR ENTRY
This is the processing for the inner loop that steps through the directory entries contained in a single directory block. First we check to see if there is another directory entry to process. If not we go back to the outer loop and read another block.
If we have and entry to process we check to see if the member name matches the name we are searching for. If it matches we have found the entry we are looking for.
If it doesn’t match we calculate the length of the user data. We take the contents of the C field and mask off the top three bits. This leaves the number of halfwords that make up the user data. We can shift this value one bit to the left to multiply it by two which results in the number of bytes in the user data. We add 12 (the length of the member name and the TTRC) to the user data length to get the total length of the entry. We use this value to point to the next directory entry and to adjust the remaining length of data to process in the block.
Now that we have located the directory entry we have the relative offset (TTR) into the data set where the member data starts. We can use this and the extent information from the DSCB to point to the first block of data.
For now we will require the data set to only consist of a single extent which will simplify the code to calculate the actual CCHHR. A more general solution would require handling up to sixteen extents.
SLR R2,R2 SLR R1,R1 SLR R0,R0 ICM R2,B'0011',TTRC Relative Track Offset ICM R1,B'0011',BEGHH Extent Begin HH AR R1,R2 ICM R2,B'0011',BEGCC Extent Begin CC L R15,TRKCYL Tracks per Cylinder DR R0,R15 Calculate CC/HH AR R2,R1 Add in Cylinder Offset STCM R2,B'0011',CC Save CC STCM R0,B'0011',HH Save HH MVC R(1),TTRC+2 Move In Record Offset
To get the CCHHR for the first record of the member data we add the track offset (TT) value to the beginning head (HH) of the extent. We then divide by the number of tracks per cylinder. This give us the cylinder offset which we add to the beginning cylinder of the extent. The reminder is the track value. The record value simply copied from the TTR offset to complete the CCHHR value for the first block of data.