www.sas.com > Service and Support > Technical Support
 
Technical Support SAS - The power to know(tm)
  TS Home | Intro to Services | News and Info | Contact TS | Site Map | FAQ | Feedback


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

Copyright (c) 2000 SAS Institute Inc. All Rights Reserved.
Terms of Use & Legal Information | Privacy Statement