#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);
}
|