#pragma eject
/*--------------------------------------------------------------------+
| |
| Copyright (c) 1996, SAS Institute Inc. |
| Unpublished - All Rights Reserved |
| |
| S A S / C S A M P L E |
| |
| |
| Name: PDSREAD |
| |
| Language: C |
| |
| EntryPoint: PDSREAD |
| |
| Entry Type: C Linkage |
| |
| Files Note: 'prefix' is the installation defined high level |
| qualifier for the SAS/C product. |
| |
| Function: 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. |
| |
| 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. |
| |
+--------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#define MEMBER_READY 2000 /* Member returned to process */
#define END_PDS_MEMBERS 2001 /* No more members to process */
#define MAX_MEMBER_NAME 8
#define LEN_TTR 3
#define TRUE 1
#define FALSE 0
#define TERMINATION_MEMBER "\xff\xff\xff\xff\xff\xff\xff\xff"
#pragma eject
/*--------------------------------------------------------------------+
| Partioned Data Set Member Information - extracted and reformatted |
| from the PDS directory |
+--------------------------------------------------------------------*/
typedef struct PDS_MBR
{
char member(|8+1|); /* member name in PDS */
int alias; /* TRUE if alias, FALSE otherwise */
char ttrpds(|3|); /* Pointer to first block of member */
}PDS_MBR;
/*--------------------------------------------------------------------+
| Member entry from a partioned data set directory |
+--------------------------------------------------------------------*/
struct MEMENTRY
{
char name(|8|); /* Member name. */
char ttrmem(|3|); /* TTR. */
char c; /* Information about user data field */
};
/*--------------------------------------------------------------------+
Ref: MVS/XA Data Administration Guide, IBM Publication GC26-4013
A Partitioned Data Set Directory Block
+----------+--------------------+--------------------+-------------...
|Number of | Member Entry | Member Entry | Member En
|Bytes Used| A | B | C
|(Maximum | | |
| 256) | | |
+----------+--------------------+--------------------+-------------...
<----2-----><----------------Maximum 254----------------------------->
A Partitioned Data Set Member Entry
+----------------+------+--+-----------------------------------------+
| Member | TTR |C | Optional User Data |
| Name | | | TTRN | TTRN | TTRN | |
+----------------+------+--+-----------------------------------------+
<-------8--------><--3--><1><------------0 to 31 halfwords----------->
Data in Member Entry 'C' Field Bitfield Definitions
+-----------+-------------+----------------------+
| 1 if | Number of | Number of User |
|Name is an | User Data | Data Halfwords |
| Alias | TTRNs | |
+-----------+-------------+----------------------+
0 1-2 3-7
+--------------------------------------------------------------------*/
#pragma eject
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 bytes used in */
/* 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));
strncpy(pds->member, member->name, MAX_MEMBER_NAME);
memcpy( pds->ttrpds, member->ttrmem, LEN_TTR);
/* Mark alias members */
if ( (member->c & 0x80) == FALSE )
{ /* 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 */
}
|