#pragma title PDSREAD #include "pdsreadh.h" #pragma eject /*--------------------------------------------------------------------+ | | | Copyright (c) 1996, SAS Institute Inc. | | Unpublished - All Rights Reserved | | | | S A S / C S A M P L E | | | | Function : pdsgetm | | | | Language: C | | | | Purpose : This is the controlling function for building a list | | of PDS members, both real and alias. Successful | | completion will result in at least one and possibly | | two skiplists being built as follows: | | | | 1) A skiplist with one entry for each real member name. | | | | Note: A real member is a member that is NOT an | | alias. | | | | 2) If one or more aliases exist, a skiplist will be | | built with one entry for each alias member found. | | It is not an error if no alias entries exist. | | | | Parameters: | | | | NODE * (*memlist) - Entry: Pointer to pointer of the | | skiplist header for 'real' | | PDS members. | | | | Exit : With return EXIT_SUCCESS | | the skiplist may contain | | none or more than one | | element of type | | struct NODE. | | | | Each element contains the | | member name and ttr. | | | | Order: Member TTR | | | | NODE * (*alialist) - Entry: Pointer to pointer of the | | skiplist header for | | 'alias' PDS members. | | | | Exit : With return EXIT_SUCCESS | | the skiplist may contain | | one or more elements of | | type struct NODE. | | | | Each element contains the | | member name, ttr, and | | alias status. | | | | Order: Member name | | | | Returns : | | | | EXIT_SUCCESS - Members were found and the skiplist(s) | | are ready for additional processing. | | | | EXIT_FAILURE - An error/failure occured. A unique | | message describing the condition was | | written to stderr. | | | | FuncCalls : External - insert_node() | | | | Internal - pdsverfi() | | pdsread() | | Notes : | | - The PDS processed must have at least one member, either| | a real member or an alias will do. | | | +--------------------------------------------------------------------*/ #pragma eject int pdsgetm(NODE * (*memlist), NODE * (*aliaslist) ) { int exit_rc = EXIT_SUCCESS; int memcount = 0; int aliascount = 0; PDS_MBR pds; FILE * fp_syslib = NULL; NODE * member_list = NULL; NODE * alias_list = NULL; NODE * new_node = NULL; /*----------------------------------------------------------------+ | Ensure the caller does not give us NULL pointers. | +----------------------------------------------------------------*/ assert( (memlist != NULL) && (aliaslist != NULL) ); /*----------------------------------------------------------------+ | Setup a header node for both skiplist, validate the input DD, | | and open the dataset for processing. | +----------------------------------------------------------------*/ member_list = newlist(); alias_list = newlist(); exit_rc = pdsverfi(&fp_syslib); /* make sure dd is a good one */ if (exit_rc == EXIT_SUCCESS) /* input dd ok to process? */ { /* Input dd dataset is ready, set exit_rc so that */ /* we start reading members from the pds directory. */ exit_rc = MEMBER_READY; }; #pragma eject /*----------------------------------------------------------------+ | If the dataset is ready, process all member entries and build a | | skiplist of entires for real members and a skiplist of alias | | member entries(if they exist). | +----------------------------------------------------------------*/ while (exit_rc == MEMBER_READY) { exit_rc = pdsread(&pds, fp_syslib); /* one member please */ if (exit_rc == MEMBER_READY) { /* Normal return from PDSREAD, handle the member returned */ if (pds.alias == TRUE) { /* Alias member found, insert in alias skiplist. */ new_node = insert_node(compare_by_name, alias_list, &pds); assert(new_node != NIL); aliascount++; } else { /* Real member found, insert into real member skiplist. */ new_node = insert_node(compare_by_ttr, member_list, &pds); assert(new_node != NIL); memcount++; }; }; }; #pragma eject /*----------------------------------------------------------------+ | There must be at least one member, either a real member or an | | alias member. | +----------------------------------------------------------------*/ if (memcount < 1 && aliascount < 1 && exit_rc == END_PDS_MEMBERS) { fprintf(stderr, "Input DD SYSLIB dataset had no members to process!\n"); exit_rc = EXIT_FAILURE; }; /*----------------------------------------------------------------+ | See how we finished up reading the PDS directory, if all is | | well print statistics and return. If all is NOT WELL, then | | cleanup and leave with exit_rc as we found it. | +----------------------------------------------------------------*/ if (exit_rc == END_PDS_MEMBERS) { /* Processing has completed successfully, setup for exit */ exit_rc = EXIT_SUCCESS; /* Indicate all is well! */ *memlist = member_list; /* Tell'm where real members are*/ *aliaslist = alias_list; /* ..ditto for alias members */ printf("\nReal members : %5d\n",memcount); printf( "AliasMembers : %5d\n",aliascount); printf( "Total Members : %5d\n\n", aliascount+memcount); } else { /* An error has occured, cleanup before exiting */ freelist(member_list); /* free real member skiplist */ freelist(alias_list); /* free alias member skiplist */ *memlist = NULL; /* ensure caller does not use the.. */ *aliaslist = NULL; /* ..skiplist pointers on return */ }; if (fp_syslib != NULL) fclose(fp_syslib); /* Close input DD SYSLIB*/ return(exit_rc); } #pragma eject /*--------------------------------------------------------------------+ | | | Function : pdsread | | | | Purpose : Read the PDS directory one block at a time. Decode | | each block and copy the member name, ttr, and alias | | status to the struct PDS_MBR provided by the caller. | | | | Update static variables in preparation for next call. | | | | Language : C | | | | Parameters: | | PDS_MBR * pds - pointer to PDS_MBR struct where | | member name, ttr, and alias status| | will be returned | | | | FILE * fp - file pointer to a PDS which has | | been opened for directory access | | | | Returns : | | | | MEMBER_READY - Struct PDS_MBR has been updated with | | member information. | | END_PDS_MEMBERS - All members have been processed. | | EXIT_FAILURE - A error/failure has occured. A unique | | message describing the error has been | | written to stderr | | | | Notes : | | - If pdsread() has I/O errors, any type, reading the | | input dataset a message is displayed and the program | | terminates immediately. | | | +--------------------------------------------------------------------*/ #pragma eject static int pdsread( PDS_MBR * pds, /* ptr to member information */ FILE * fp /* PDS directory FILE pointer */ ) { /*-----------------------------------------------------------------+ | The following are static because their value must be retained | | across calls to this function. | +-----------------------------------------------------------------*/ static struct MEMENTRY *member;/* Partial PDS member entry */ static char dirbuf[256]; /* Directory block buffer */ static int ud; /* Number of halfwords in user */ /* data field of member entry */ static int blk_last_entry; /* "Not last entry" flag */ static int ld; /* Length of directory block */ static short nb = 0; /* Number of 256 byte blocks read */ /* directory block. */ /* NOTE: Must be initialized to */ /* zero so that the first */ /* time PDSREAD is called */ /* a block will be read! */ static int od = 0; /* Current offset into directory */ /* block */ static int exit_rc = /* Exit return code */ EXIT_SUCCESS; /* NOTE: Must be initialized to */ /* EXIT_SUCCESS! */ static int blocks_read = 0; /* Block read total */ #pragma eject /*-----------------------------------------------------------------+ | Read another directory block if necessary. | | | | Note: | | MVS: DCB parameters - RECFM=FB,BLKSIZE=256 | | CMS: FILEDEF options - RECFM U BLKSIZE 256 | +-----------------------------------------------------------------*/ if ( nb <= 0 ) { ld = afread(dirbuf,256,1,fp); if (ld == 1) /* Was 1 block of 256 bytes read? */ { nb = *((short *) dirbuf) - 2; od = 2; blocks_read += 1; /* bump block read count */ } else { /*-----------------------------------------------------------+ | We should have read exactly one block, we didn't, this | | should not happen and is serious. | +-----------------------------------------------------------*/ fprintf(stderr,"\nERROR - Block Read Error, read: %d\n\n",ld); if ( (ferror(fp)) != 0) { fprintf(stderr, "\nERROR - ferror() also reports an error\n"); }; exit_rc = EXIT_FAILURE; }; }; /*-----------------------------------------------------------------+ | The last member of the last directory block will be 8 hex | | digits of 'FF'. See if the current member is the last member, | | if it is indicate last member and display blocks processed. | +-----------------------------------------------------------------*/ blk_last_entry = memcmp((dirbuf+od),TERMINATION_MEMBER,8); if (blk_last_entry == 0 ) /* Have we reached the end of the pds? */ { exit_rc = END_PDS_MEMBERS; /* Indicate last member... */ printf("Directory Blocks Processed: %5d\n", blocks_read); } else { exit_rc = MEMBER_READY; }; #pragma eject /*-----------------------------------------------------------------+ | If exit_rc is MEMBER_READY, there is a PDS directory member to | | process. At this time we will also prepare for the next call. | | Do nothing if not MEMBER_READY. | +-----------------------------------------------------------------*/ if (exit_rc == MEMBER_READY) { /* Process current entry */ member = (struct MEMENTRY *) (dirbuf + od); memset(pds,'\0',sizeof(PDS_MBR)); memcpy(pds->member, member->name, 8); /*--------------------------------------------------------------+ | Copy the 3 bytes of ttr from the real member to the first 3 | | bytes of pds. It then becomes a ttrz for use by ospoint(). | +--------------------------------------------------------------*/ memcpy(pds->ttr_data.ttrpds, member->ttrmem, LEN_TTR); /* Mark alias members */ if ( (member->c & ALIAS_BIT) == 0 ) { /* Mark as real member. */ pds->alias = FALSE; } else { /* Mark as alais member. */ pds->alias = TRUE; }; /* Setup for next call, adjust to next directory member entry */ ud = 2 * (member->c & 0x1f); /* Number of half words in */ /* user data field */ od += sizeof(struct MEMENTRY) + ud; /* Adjust offset into dir */ nb -= sizeof(struct MEMENTRY) + ud; /* Adjust number of bytes */ /* used */ }; return(exit_rc); /* return with the last return code set */ } #pragma eject /*--------------------------------------------------------------------+ | | | Function : pdsverfi | | | | Purpose : Verify that the dataset allocated to the input DD: | | - is present | | - does point to a real dataset | | - dataset is NOT RECFM=U | | - that the RECFM is EITHER F, FB, or FBS | | - dataset is LRECL=80 | | - is DSORG=PO | | - dataset can be opend 'rb' (read/binary) | | | | Language : C | | | | Parameters: | | FILE * (*fp_syslib) - Return input DD file pointer here | | if open is successful, otherwise | | return NULL. | | Returns : | | EXIT_SUCCESS - Indicates the dataset is open and ready | | for the caller to process. | | EXIT_FAILURE - An error/failure has occured. A unique | | message has been written to stderr | | describing the condition. | | | | Notes : | | | +--------------------------------------------------------------------*/ static int pdsverfi( FILE * (*fp_syslib) /* file pointer to input dd */ ) { char recfm; unsigned short dsorg; int lrecl; int blksize; int exit_rc = EXIT_SUCCESS; char dsname[44+1]; char member_name[9]; #pragma eject /*------------------------------------------------------------------+ | Using osddinfo() and osdsinfo() determine attributes of the | | input DD and the dataset allocated to it. | +------------------------------------------------------------------*/ memset(member_name,NULL,sizeof(member_name)); exit_rc = osddinfo(DDN_SYSLIB,dsname,member_name,NULL,NULL,NULL); if (exit_rc == 0) { /* Use osdsinfo() to get dsorg, lrecl, recfm */ exit_rc = osdsinfo(dsname,0,&dsorg,&recfm,&lrecl,&blksize); if (exit_rc != 0) { /* osdsinfo() failed, give message and exit */ exit_rc = EXIT_FAILURE; fprintf(stderr,"\nERROR: OSDSINFO failed for input dataset!\n"); fprintf(stderr,"\nFilename via OSDDINFO: %s\n", dsname); }; } else { /* osddinfo() has failed, give message and exit */ exit_rc = EXIT_FAILURE; fprintf(stderr,"\nERROR: OSDDINFO failed for input dd %s!\n", DDN_SYSLIB); }; #pragma eject /*------------------------------------------------------------------+ | Validate the dataset attributes. | +------------------------------------------------------------------*/ if (exit_rc == EXIT_SUCCESS) /* Continue if all is ok to this point*/ { /*-------------------------------------------------------------+ | The file is present and we have all information necessary to | | validate. Check for DSORG=PO, LRECL=80, BLKSIZE=multiple of | | 80, and RECFM=F. | | | | Also, verify that there was no member name specified on the | | DSN parameter. | | | | NOTE: RECFM_U must be specifically tested for FRIST, as it is| | RECFM_F or'ed with RECFM_V. | +-------------------------------------------------------------*/ printf("\nFile being processed via input DD %s: %s\n\n", DDN_SYSLIB, dsname); if ( (dsorg & DSORG_PO) != DSORG_PO ) { exit_rc = EXIT_FAILURE; fprintf(stderr,"\nFile being processed via input DD %s: %s\n\n", DDN_SYSLIB, dsname); fprintf(stderr,"ERROR: File was not DSORG=PO!\n"); }; if ( strlen(member_name) != 0 ) { exit_rc = EXIT_FAILURE; fprintf(stderr,"\nFile being processed via input DD %s: %s\n\n", DDN_SYSLIB, dsname); fprintf(stderr,"ERROR: DSN specified with a member name.\n"); }; if ( lrecl == 80) { if ( (blksize%lrecl) != 0 ) { fprintf(stderr, "\nFile being processed via input DD %s: %s\n\n", DDN_SYSLIB, dsname); exit_rc = EXIT_FAILURE; fprintf(stderr,"ERROR: BLKSIZE not a multiple of LRECL!\n"); }; } else { fprintf(stderr,"\nFile being processed via input DD %s: %s\n\n", DDN_SYSLIB, dsname); exit_rc = EXIT_FAILURE; fprintf(stderr,"ERROR: File LRECL was not 80!\n"); }; #pragma eject if ( (recfm & RECFM_U ) == RECFM_U ) { fprintf(stderr,"\nFile being processed via input DD %s: %s\n\n", DDN_SYSLIB, dsname); exit_rc = EXIT_FAILURE; fprintf(stderr,"ERROR: File was RECFM=U, only FIXED allowed!\n"); } else { if ( (recfm & RECFM_F) != RECFM_F ) { fprintf(stderr, "\nFile being processed via input DD %s: %s\n\n", DDN_SYSLIB, dsname); exit_rc = EXIT_FAILURE; fprintf(stderr,"ERROR: File was not RECFM=F, or FB!\n"); }; }; /*-------------------------------------------------------------+ | If the input dataset has been verified ok, open it and put | | the file pointer in callers variable. If the dataset opened | | normally return with EXIT_SUCCESS, otherwise return with | | EXIT_FAILURE. | +-------------------------------------------------------------*/ if (exit_rc == EXIT_SUCCESS) { *fp_syslib = fopen(DDN_SYSLIB,SYSLIB_MODE); if (*fp_syslib == NULL) { exit_rc = EXIT_FAILURE; fprintf(stderr,"ERROR: fopen() failed for input dd %s!\n", DDN_SYSLIB); }; }; }; return(exit_rc); }