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


#include "updbldh.h"
#pragma title UPDBLD
#pragma eject
/*--------------------------------------------------------------------+
|                                                                     |
|                 Copyright (c) 1996, SAS Institute Inc.              |
|                   Unpublished - All Rights Reserved                 |
|                                                                     |
|                     S A S / C  S A M P L E                          |
|                                                                     |
| Function  : updbld                                                  |
|                                                                     |
|   Language: C                                                       |
|                                                                     |
| Purpose   :                                                         |
|              This is the controlling function for creating the      |
|              IEBUPDTE input file.  The list of members in the PDS   |
|              is provided by pdsgetm() in the form of two skiplist.  |
|                                                                     |
|              The output DDN SYSPUNCH is verified to ensure the      |
|              attributes are LRECL=80 and RECFM=F, and BLKSIZE       |
|              is an even multiple of the LRECL.                      |
|                                                                     |
|              If there are alias members they are matched with their |
|              corresponding real member based on TTR.   Each real    |
|              member node has a pointer to a list of alias members   |
|              with matching TTR's.                                   |
|                                                                     |
|              The alias list is terminated with a sentinel node to   |
|              mark the end of the list.                              |
|                                                                     |
|              Any alias members left over are orphans.  Orphans are  |
|              added to the real member list and they will be treated |
|              'as if' they were real members.  It will be noted on   |
|              IEBUPDTE ADD statement that it was a an orphan alias.  |
|                                                                     |
|              The real member list is then sorted into alphabetic    |
|              order for final processing.                            |
|                                                                     |
|              Finally, we loop through the real member skiplist,     |
|              creating an ADD statement for each member, writing     |
|              data records for each member and writing out any       |
|              ALIAS statements that maybe needed for each member.    |
|                                                                     |
|              Each ADD statement will indicate if the member is      |
|              a 'real' member or an 'alias' member being treated     |
|              as a real member.  Additionaly, if a member, real      |
|              or alias, has no records it will be noted on the       |
|              ADD statement.                                         |
|                                                                     |
| Parameters:                                                         |
|            NODE * (*memlist)  -  pointer to pointer of skiplist     |
|                                  with the real member names         |
|                                                                     |
|            NODE * (*aliaslist)-  pointer to pointer of skiplist     |
|                                  with the alias member names        |
|                                                                     |
| Returns   :                                                         |
|            EXIT_SUCCESS       -  IEBUPDTE input file has been       |
|                                  created                            |
|                                                                     |
|            EXIT_FAILURE       -  A failure/error has occured.  A    |
|                                  unique message has been written to |
|                                  stderr describing the condition.   |
|                                                                     |
| Notes     :                                                         |
|            -                                                        |
|                                                                     |
|                                                                     |
+--------------------------------------------------------------------*/
int updbld ( NODE * (*memlist), NODE * (*aliaslist) )
{
 DCB_t  * input  = NULL;
 DCB_t  * output = NULL;

 int exit_rc = EXIT_SUCCESS;

 /*--------------------------------------------------------------------+
 | Ensure no null pointers are passed and that there is at least one   |
 | node in the memlist skiplist.                                       |
 +--------------------------------------------------------------------*/
 assert( (*memlist != NIL) && (aliaslist != NIL) );

 printf("\n\n--------------------------------------------\n\n");

#pragma eject
 /*--------------------------------------------------------------------+
 | Setup and open input/output DCB's.  Verify output DD DCB attributes |
 | are correct and setup SYNAD exit for both input/output datasets.    |
 | The input DD DCB attributes have already been verified by the       |
 | caller.                                                             |
 +--------------------------------------------------------------------*/
 exit_rc = updverfi();
 if (exit_rc == EXIT_SUCCESS)
   {
    exit_rc = updprep(&input, &output);
   };

 /*--------------------------------------------------------------------+
 | Determine which alias entries have a real member, attach the alias  |
 | to the real member node.  Alias members with no matching real       |
 | member will be added to the real member list and treated as if they |
 | are real members.  After this point, memlist has an entry for       |
 | all members that will be processed, aliaslist is no longer used.    |
 +--------------------------------------------------------------------*/
 if (exit_rc == EXIT_SUCCESS)
   {
    exit_rc = updaka(memlist, aliaslist);
   };

#pragma eject
 /*--------------------------------------------------------------------+
 | Build a file formatted as input to IEBUPDTE.                        |
 +--------------------------------------------------------------------*/
 if (exit_rc == EXIT_SUCCESS)
   {
    exit_rc = updproc(input, output, *memlist);
   };

 printf("\n\n--------------------------------------------\n\n");
 return(exit_rc);
}

#pragma eject
/*--------------------------------------------------------------------+
|                                                                     |
| Function  : updproc                                                 |
|                                                                     |
| Language  : C                                                       |
|                                                                     |
| Purpose   : updproc() positions the dataset to process each         |
|             member.  It then calls updio() to create the IEBUPDTE   |
|             records for each member.                                |
|                                                                     |
|             updproc() detects that an alias is being treated as     |
|             real member and writes a message to stderr indicating   |
|             this anomaly has been detected.  This is NOT an error.  |
|                                                                     |
|             If updio() detects a member that has no records, empty  |
|             member, it signals this to updproc() via return code    |
|             and updproc() writes a message to stderr indicating     |
|             this anomaly has been detected at completion.  This     |
|             is not a 'error' condition.                             |
|                                                                     |
|             After all members are processed the ENDUP statement     |
|             is written as the last record in the IEBUPDTE input     |
|             file and the total records in the output file is        |
|             written to stdout.                                      |
|                                                                     |
| Parameters:                                                         |
|            DCB_t * input       - DCB for input DDN SYSLIB           |
|                                                                     |
|            DCB_t * output      - DCB for output DDN SYSPUNCH        |
|                                                                     |
|            NODE * memlist      - Skiplist of members to process,    |
|                                  this list will contain:            |
|                                  1) all real members found with     |
|                                     a list of its associated alias  |
|                                     members.                        |
|                                  2) Orhpaned alias members being    |
|                                     treated as if they are real     |
|                                     members.                        |
|                                                                     |
| Returns   :                                                         |
|             EXIT_SUCCESS       - Normal successful completion.      |
|                                                                     |
|             ANOMALY            - Normal successful completion but   |
|                                  there were orphaned alias members  |
|                                  and/or there were real members     |
|                                  that had no records, empty dataset.|
|                                                                     |
|             EXIT_FAILURE       - A error/failure has occured.  A    |
|                                  unique message will the written to |
|                                  stderr describing the condition.   |
|                                                                     |
| Notes     :                                                         |
|                                                                     |
+--------------------------------------------------------------------*/
static int updproc ( DCB_t * input, DCB_t * output, NODE * memlist)
{
 int exit_rc = EXIT_SUCCESS;
 int osput_rc = EXIT_SUCCESS;
 NODE   * list;           /* Pointer to next member to process  */
 NODE   * walk;           /* Pointer to member being processed  */
 int mem_records   = 0;
 int total_records = 0;
 int orphan_alias  = 0;
 int empty_member  = FALSE;
 int alias_as_real = FALSE;
 char endup_stmt[]      = "./ ENDUP";
 char out_rec[LRECL];

#pragma eject
 /*------------------------------------------------------------------+
 | Build IEBUPDTE input from the PDS members.  Each member will get  |
 | ADD statement, then the data, then an ALIAS statement for each    |
 | existing alias(if any).  All members searched for must be found.  |
 +------------------------------------------------------------------*/
 list = memlist;
 while ( exit_rc == EXIT_SUCCESS)
  {
   walk = list->pointers[0];
   ospoint(input,walk->data.ttr_data.ttrz); /* look by ttrz         */
   if (walk->data.alias == TRUE)
     {
      alias_as_real = TRUE;
      orphan_alias += 1;
     };

   exit_rc = updio(input, output, walk, &mem_records);
   total_records += mem_records;
   mem_records = 0;

   list = walk;

   /*-----------------------------------------------------------------+
   | An empty member is ok, we just need to ensure the return code    |
   | gets set to indicate an anomaly has occured when we finish.      |
   +-----------------------------------------------------------------*/
   if (exit_rc == ANOMALY)
     {
      exit_rc = EXIT_SUCCESS;
      empty_member = TRUE;
     };

   /*-----------------------------------------------------------------+
   |  Terminate the loop if this was the last node or if the return   |
   |  was not EXIT_SUCCESS.                                           |
   +-----------------------------------------------------------------*/
   if (exit_rc == EXIT_SUCCESS && list->pointers[0] == NIL)
     {
      exit_rc = LIST_END;
     };
  };

#pragma eject
 /*--------------------------------------------------------------------+
 | If all is well up to this point, close datasets and handle anomaly  |
 | conditions.                                                         |
 +--------------------------------------------------------------------*/
 if (exit_rc == LIST_END)
   {
    exit_rc = EXIT_SUCCESS;

    /*----------------------------------------------------------------+
    | There are two conditions which are called an ANOMALY.  Each     |
    | condition is noted on the ADD statement, in the stdout listing  |
    | for that member and a note is placed in stderr indicating that  |
    | one or both conditions have been detected.                      |
    | 1) Empty member, this can be a real member or an orpahned alias |
    |    member being treated as a real member                        |
    | 2) Orphaned alias member.  These are alias members which have   |
    |    no corresponding real member which is based on ttr.  Orphan  |
    |    alias members are treated as real and may be empty.          |
    +----------------------------------------------------------------*/
    if (exit_rc == EXIT_SUCCESS)
      {
       if ( empty_member == TRUE)
         {
          fprintf(stderr,"\n\nThere are members which have no data"
                         " records (empty member)!\n");
           fprintf(stderr,"Look for string '%s' in stdout.\n\n",
                          SOURCE_DS_EMPTY);
           exit_rc = ANOMALY;
         };
       if ( alias_as_real == TRUE)
         {
          fprintf(stderr,"\n\nThere are orphaned alias entries "
                         "which were treated as real members!\n");
          fprintf(stderr,"Look for string '%s' in stdout. \n\n",
                         ALIAS_REAL);
          fprintf(stderr,
            "\nNOTE: An orphaned alias member is an alias that\n");
          fprintf(stderr,
            "      has no corresponding real member based on TTR.\n\n");
          exit_rc = ANOMALY;
         };
      };

#pragma eject
   /*-----------------------------------------------------------------+
   | Write out ENDUP statment.                                        |
   +-----------------------------------------------------------------*/
    memset(out_rec, ' ', LRECL);
    memcpy(out_rec, endup_stmt, sizeof(endup_stmt)-1);
    osput_rc = osput(output, out_rec, LRECL);
    total_records += 1;
    if (osput_rc != OSXXX_SUCCESS)
      {
       fprintf(stderr,"osput failed for %s\n", DDN_SYSPUNCH);
       exit_rc = EXIT_FAILURE;
      };

    osclose(input,"disp");
    osclose(output,"disp");

    printf("\nTotal Records in output: %8d\n", total_records);

   };

 return(exit_rc);
}

#pragma eject
/*--------------------------------------------------------------------+
|                                                                     |
| Function  : updprep                                                 |
|                                                                     |
| Language  : C                                                       |
|                                                                     |
| Purpose   : Creates and opens the DCB's for input DDN SYSLIB        |
|             and output DDN SYSPUNCH.                                |
|                                                                     |
| Parameters:                                                         |
|            DCB_t * (*input)    - DCB for input DDN SYSLIB           |
|                                                                     |
|            DCB_t * (*output)   - DCB for output DDN SYSPUNCH        |
|                                                                     |
| Returns   :                                                         |
|             EXIT_SUCCESS       - normal successful completion       |
|                                                                     |
|             EXIT_FAILURE       - A error/failure has occured.  A    |
|                                  unique message will be written to  |
|                                  stderr describing the condition.   |
|                                                                     |
| Notes     :                                                         |
|                                                                     |
+--------------------------------------------------------------------*/
static int updprep ( DCB_t * (*input), DCB_t * (*output))
{
 int exit_rc = EXIT_SUCCESS;
 DCB_t * prep_input;
 DCB_t * prep_output;
 int open_input_rc = 0;
 int open_output_rc = 0;
 exit_t inpt_exit_list[1] = {LAST | SYNAD, &synad_exit};
 exit_t outp_exit_list[2] = {
                      {SYNAD, &synad_exit       },
                      {LAST | ABEND, &abend_exit}
                     };
 /*--------------------------------------------------------------------+
 | Setup DCB for input DD and open the dataset.                        |
 +--------------------------------------------------------------------*/
 prep_input = osdcb(DDN_SYSLIB, "DSORG=PO", inpt_exit_list, 0);
 if (prep_input == NULL)
   {
    fprintf(stderr,"osdcb failed for: %s \n", DDN_SYSLIB);
    exit_rc = EXIT_FAILURE;
    *input = NULL;
   }
  else
   {
    open_input_rc = osopen(prep_input, "input", 0);
    if (open_input_rc == OSXXX_SUCCESS)
      {
       *input = prep_input;
      }
     else
      {
       fprintf(stderr,"osopen failed for: %s \n", DDN_SYSLIB);
       exit_rc = EXIT_FAILURE;
       *input = NULL;
      };
   };

#pragma eject
 /*--------------------------------------------------------------------+
 | Setup DCB for output DD and open the dataset.                       |
 +--------------------------------------------------------------------*/
 prep_output =
    osdcb(DDN_SYSPUNCH, "LRECL=80,RECFM=F",outp_exit_list, 0);
 if (prep_output == NULL)
   {
    fprintf(stderr,"osdcb failed for: %s \n", DDN_SYSPUNCH);
    exit_rc = EXIT_FAILURE;
    *output = NULL;
   }
  else
   {
    open_output_rc = osopen(prep_output, "output",0);
    if (open_output_rc == OSXXX_SUCCESS)
      {
       *output = prep_output;
      }
     else
      {
       fprintf(stderr,"osopen failed for: %s \n", DDN_SYSPUNCH);
       exit_rc = EXIT_FAILURE;
       *input = NULL;
      };
   };

 return(exit_rc);
}

#pragma eject
/*--------------------------------------------------------------------+
|                                                                     |
| Function  : updverfi                                                |
|                                                                     |
| Language  : C                                                       |
|                                                                     |
| Purpose   : Verify datasets exist for input DDN SYSLIB and output   |
|             DDN SYSPUNCH.  Verify the dataset attributes for        |
|             the output DDN SYSPUNCH.  Input DDN SYSLIB attributes   |
|             were verified when the PDS directory was processed.     |
|                                                                     |
| Parameters:                                                         |
|            None                                                     |
|                                                                     |
| Returns   :                                                         |
|             EXIT_SUCCESS       - Normal successful completion       |
|                                                                     |
|             EXIT_FAILURE       - A error/failure occured.  A unique |
|                                  message will be written to stderr  |
|                                  describing the condition.          |
|                                                                     |
| Notes     :                                                         |
|                                                                     |
+--------------------------------------------------------------------*/
static int updverfi( void )
{
 int exit_rc = EXIT_SUCCESS;
 char recfm;
 unsigned short dsorg;
 int lrecl;
 int blksize;
 char dsname[44+1];

#pragma eject
 /*------------------------------------------------------------------+
 | Using osddinfo() and osdsinfo() determine attributes of the output|
 | dataset.                                                          |
 +------------------------------------------------------------------*/
 /* use osddinfo() to get the dsname                                */
 exit_rc = osddinfo(DDN_SYSPUNCH,dsname,NULL,NULL,NULL,NULL);

 /*------------------------------------------------------------------+
 | If there is no dsname returned from osddinfo() the DDN points     |
 | to something other than a dasd data set, i.e. SYSOUT, tape, etc.  |
 |                                                                   |
 | If this is the case then set exit_rc such that normal checking    |
 | will not be done, indicate to stdout what is going on, and        |
 | why.                                                              |
 +------------------------------------------------------------------*/
 if ( (strlen(dsname) < 1)  && exit_rc == 0)
   {
    printf("\nFile being processed via output DD %s: "
           "No Data Set Name Available!  Data set is likely SYSOUT.",
           DDN_SYSPUNCH);
    printf("\n     Note: normal checks for LRECL/DSORG/RECFM will be"
           " suspended for this execution!\n\n\n");
    exit_rc = NOT_A_DATASET;
   }
  else
   {
    if (exit_rc == 0)
      {
       /* Use osdsinfo() to get dsorg, lrecl, recfm, and blksize     */
       exit_rc = osdsinfo(dsname,0,&dsorg,&recfm,&lrecl,&blksize);

       if (exit_rc != 0)
         {
          /* osdsinfo() failed, tell'm about it and exit            */
          fprintf(stderr,"\nOSDSINFO failed for output dataset!\n");
          fprintf(stderr,"\nFilename via OSDDINFO: %s\n", dsname);
          exit_rc = EXIT_FAILURE;
         };
      }
     else
      {
       /* osddinfo() has failed, tell'm about it and exit           */
       fprintf(stderr,"\nOSDDINFO failed for output DD %s!\n",
               DDN_SYSPUNCH);
       exit_rc = EXIT_FAILURE;
      };
   };

#pragma eject
 /*------------------------------------------------------------------+
 | Validate output 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 RECFM=F, LRECL=80, and a BLKSIZE that     |
    | is a multiple of LRECL.                                        |
    |                                                                |
    | NOTE: RECFM_U must be specifically tested for first, as it is  |
    |       RECFM_F or'ed with RECFM_V.                              |
    +---------------------------------------------------------------*/
    printf("\nFile being processed via output DD %s: %s\n\n",
           DDN_SYSPUNCH, dsname);

    if ( (recfm &  RECFM_U ) ==  RECFM_U )
      {
       fprintf(stderr,
                "\nFile being processed via output DD %s: %s\n\n",
                DDN_SYSPUNCH, dsname);
       exit_rc = EXIT_FAILURE;
       fprintf(stderr,"File ->was<- RECFM=U, only FIXED allowed!\n");
      };

    if (  lrecl !=  LRECL)
      {
       fprintf(stderr,
                "\nFile being processed via output DD %s: %s\n\n",
                DDN_SYSPUNCH, dsname);
       fprintf(stderr,"File LRECL was not 80!\n");
       exit_rc = EXIT_FAILURE;
       if ( (blksize%lrecl) != 0)
         {
          fprintf(stderr,
                   "\nFile being processed via output DD %s: %s\n\n",
                   DDN_SYSPUNCH, dsname);
          exit_rc = EXIT_FAILURE;
          fprintf(stderr,"File BLKSIZE is not a multiple of LRECL)!\n");
         };
      };

    if (  (recfm &  RECFM_F) !=  RECFM_F  )
      {
       fprintf(stderr,
                "\nFile being processed via output DD %s: %s\n\n",
                DDN_SYSPUNCH, dsname);
       fprintf(stderr,"File was not RECFM=F!\n");
       exit_rc = EXIT_FAILURE;
      };
   };

 /*------------------------------------------------------------------+
 | If the only thing detected was the fact that this is not a dasd   |
 | dataset, then set return to EXIT_SUCCESS.                         |
 +------------------------------------------------------------------*/
 if (exit_rc == NOT_A_DATASET)
   {
    exit_rc = EXIT_SUCCESS;
   };

 return(exit_rc);
}

#pragma eject
/*--------------------------------------------------------------------+
|                                                                     |
| Function  : updio                                                   |
|                                                                     |
| Language  : C                                                       |
|                                                                     |
| Purpose   : This function creates the ADD statement, writes out     |
|             the data records for the member(if any exist), and      |
|             creates ALIAS statements if there are alias members.    |
|                                                                     |
|             updio() determines the source for the member, it will   |
|             be either 'REAL MEMBER' or 'ALIAS AS REAL', and notes   |
|             it on the ADD statement as well as the entry written    |
|             to stdout for this member.                              |
|                                                                     |
|             In creating the ADD statement updio() determines if     |
|             the member is empty (no data records).  It the member   |
|             is empty, it is noted on the ADD statement and in the   |
|             entry in stdout for this member.                        |
|                                                                     |
|             A member that is empty (no records) is considered       |
|             an anomaly, not an error.  This condition is signaled   |
|             to the caller with a return code of ANOMALY.            |
|                                                                     |
| Parameters:                                                         |
|            DCB_t * input       - opened input dataset DDN SYSLIB    |
|                                                                     |
|            DCB_t * output      - opened output dataset DDN SYSPUNCH |
|                                                                     |
|            NODE  * real_member - node address of the member to      |
|                                  be processed                       |
|                                                                     |
|            int   * mem_records - total records written for this     |
|                                  member, inlcudes ADD and any ALIAS |
|                                  statements needed, plus data       |
|                                  records, if any                    |
|                                                                     |
| Returns   :                                                         |
|             EXIT_SUCCESS       - Normal successful completion.      |
|                                                                     |
|             ANOMALY            - Normal successful completion that  |
|                                  indicates that the member being    |
|                                  processed is empty.                |
|                                                                     |
|             EXIT_FAILURE       - A error/failure has occured.  A    |
|                                  unique message will be written to  |
|                                  stderr describing the condition.   |
|                                                                     |
| Notes     :                                                         |
|             - IEBUPDTE will not accept empty members, although      |
|               empty member are valid.                               |
|                                                                     |
|                                                                     |
+--------------------------------------------------------------------*/
static int updio ( DCB_t * input, DCB_t * output, NODE * real_member,
                   int * mem_records)
{
 void * rec_data = NULL;

 int    rec_len;
 int exit_rc = OSXXX_SUCCESS;
 int member_empty = FALSE;

 ALIAS_DATA * listalias;
 ALIAS_DATA * freealias;

 char add_stmt[]        = "./ ADD   NAME=";
 char alias_stmt[]      = "./ ALIAS NAME=";
 char out_rec[LRECL];

#pragma eject
 /*------------------------------------------------------------------+
 | Start building the ADD statement, it will be completed after      |
 | we determine if there are records in the member.                  |
 +------------------------------------------------------------------*/
 memset(out_rec, ' ', LRECL);
 memcpy(out_rec, add_stmt, sizeof(add_stmt)-1);
 memcpy(&out_rec[sizeof(add_stmt)-1],
              real_member->data.member, 8);
 printf("Member: %.8s  ", real_member->data.member);

 /*------------------------------------------------------------------+
 | Mark member as real or alias as real, note it in stdout and on    |
 | the ADD statement.                                                |
 +------------------------------------------------------------------*/
 if (real_member->data.alias == TRUE)
   {
    printf("%s", ALIAS_REAL);
    memcpy(&out_rec[ (sizeof(add_stmt)-1) + 8 + 2],
            ALIAS_REAL, sizeof(ALIAS_REAL)  - 1 );
   }
  else
   {
    printf("%s", REAL_MEMBER);
    memcpy(&out_rec[(sizeof(REAL_MEMBER)-1) + 8 + 2],
            REAL_MEMBER, sizeof(REAL_MEMBER) - 1 );
   };

#pragma eject
 /*------------------------------------------------------------------+
 | Complete the ADD statement by determining if the member has       |
 | records or if it is empty.                                        |
 |                                                                   |
 | 1) If the member has records:                                     |
 |    - write out the ADD statment as is, stdout will be completed   |
 |      later when the number of records in the member has been      |
 |      determined.                                                  |
 |                                                                   |
 | 2) If the member is empty:                                        |
 |    - turn on empty member switch, indicates an anomaly condition  |
 |    - indicate in ADD statment that it is an empty member          |
 |    - ditto for stdout                                             |
 |    - write out the ADD statment                                   |
 |                                                                   |
 +------------------------------------------------------------------*/
 exit_rc = osget(input, &rec_data, &rec_len);
 *mem_records = 0;
 switch(exit_rc)
  {
   case OSGET_EOF:            /* Handle emtpy member                */
        member_empty = TRUE;
        memcpy(&out_rec[48],SOURCE_DS_EMPTY,
                    sizeof(SOURCE_DS_EMPTY)-1);
        printf("  Records: %s\n", SOURCE_DS_EMPTY);
        exit_rc = osput(output, out_rec, LRECL);   /* ADD statement */
        if (exit_rc == OSXXX_SUCCESS)
          {
           exit_rc = OSGET_EOF; /* fall thru records processing     */
          }
         else
          {
           fprintf(stderr,"osput failed for %s\n", DDN_SYSPUNCH);
           exit_rc = EXIT_FAILURE;
          };
        break;

   case OSXXX_SUCCESS:        /* Handle member with records         */
        exit_rc = osput(output, out_rec, LRECL);   /* ADD statement */
        if (exit_rc != OSXXX_SUCCESS)
          {
           fprintf(stderr,"osput failed for %s\n", DDN_SYSPUNCH);
           exit_rc = EXIT_FAILURE;
          };
        break;

   default:
        fprintf(stderr,"osget failed for %s\n", DDN_SYSLIB);
        exit_rc = EXIT_FAILURE;
  };

#pragma eject
 /*------------------------------------------------------------------+
 | If the member has records, process them by reading and writing    |
 | each record, 'as is'.  Note, the first record will already be     |
 | in the buffer at entry to the while_loop.                         |
 +------------------------------------------------------------------*/
 while(exit_rc == OSXXX_SUCCESS)
   {
    exit_rc = osput(output, rec_data, rec_len);
    *mem_records += 1;              /* Member records ONLY          */
    if (exit_rc == OSXXX_SUCCESS)
      {
       exit_rc = osget(input, &rec_data, &rec_len);
       if ( (exit_rc != OSXXX_SUCCESS) && (exit_rc != OSGET_EOF) )
         {
          fprintf(stderr,"osget failed for %s\n", DDN_SYSLIB);
          exit_rc = EXIT_FAILURE;
         };
      }
     else
      {
       fprintf(stderr,"osput failed for %s\n", DDN_SYSPUNCH);
       exit_rc = EXIT_FAILURE;
      };
   };

#pragma eject
 /*------------------------------------------------------------------+
 | Display number of records for this member which completes the     |
 | stdout 'member name' line.  If there are alias entries, write out |
 | an ALIAS statment for them and display their names in stdout.   |
 +------------------------------------------------------------------*/
 if ( exit_rc == OSGET_EOF )
   {
    if ( *mem_records > 0 )
        printf("  Records: %8d\n", *mem_records);

    *mem_records += 1;  /* account for ADD statment in total records */

    /*---------------------------------------------------------------+
    | Write an ALIAS statement for each alias member that exist for  |
    | this member.  Free each alias node as we write it.             |
    +---------------------------------------------------------------*/
    if (real_member->data.alias_list != NULL)
      {
       printf("  Alias entries for this member: \n");

       /* Setup alias processing loop and build the alias statement */
       listalias = real_member->data.alias_list;
       exit_rc = OSXXX_SUCCESS;
       memset(out_rec,' ',LRECL);
       memcpy(out_rec, alias_stmt, sizeof(alias_stmt)-1);

       while( ( listalias->next_alias) != NULL
                && exit_rc == OSXXX_SUCCESS)
         {
          memcpy(&out_rec[14], listalias->member, 8);
          exit_rc = osput(output, out_rec, LRECL);
          if (exit_rc != OSXXX_SUCCESS)
            {
             fprintf(stderr,"osput failed for %s\n", DDN_SYSPUNCH);
             exit_rc = EXIT_FAILURE;
            };

          *mem_records += 1; /* account for ALIAS statment in total */
          printf("     AliasName: %s\n", listalias->member);

          freealias = listalias;
          listalias=listalias->next_alias;
          free(freealias);
         };

       if (exit_rc == OSXXX_SUCCESS)
         {
          exit_rc = EXIT_SUCCESS;
         };
       /* The last member of the alias list is a sentinel node      */
       /* which allowed the last real member of the list to be      */
       /* processed.  We must now free the sentinel member also.    */
       free(listalias);  /* free the sentinel node */
      }
     else
      {
       /* No alias members to process and all else went ok           */
       exit_rc = EXIT_SUCCESS;
      };
   };

 /*-------------------------------------------------------------------+
 | If exit_rc is EXIT_SUCCESS, there have been no errors/failures to  |
 | this point.  We then determine if there ANOMALY conditons we need  |
 | inform the caller about.                                           |
 +-------------------------------------------------------------------*/
 if (member_empty == TRUE && exit_rc == EXIT_SUCCESS)
   {
    exit_rc = ANOMALY;          /* Anomaly conditions exist, say so! */
   };

 return(exit_rc);
}

#pragma eject
/*--------------------------------------------------------------------+
|                                                                     |
| Function  : updaka                                                  |
|                                                                     |
| Language  : C                                                       |
|                                                                     |
| Purpose   : Locate and attach alias entries to their corresponding  |
|             real member.  When a match is found based on TTR,       |
|             the alias member name is added to the list of alias     |
|             names for the real member, the list is pointed too by   |
|             the node.                                               |
|                                                                     |
|             Any alias member left over are considered orphaned and  |
|             are added to the real member list as a 'normal' member. |
|             From this point on, they will be treated as 'real'      |
|             members.                                                |
|                                                                     |
|             The memlist is resorted in alphabetical order for       |
|             final processing.                                       |
|                                                                     |
|                                                                     |
| Parameters:                                                         |
|            NODE * (*memlist)  -  pointer to pointer of skiplist     |
|                                  with the real member names         |
|                                                                     |
|            NODE * (*aliaslist)-  pointer to pointer of skiplist     |
|                                  with the alias member names        |
|                                                                     |
| Returns   : EXIT_SUCCESS  - alias members have been processed.      |
|             EXIT_FAILURE  - insert_alias() ran out of memory.       |
|                                                                     |
| Notes     :                                                         |
|                                                                     |
+--------------------------------------------------------------------*/
static int updaka ( NODE * (*memlist), NODE * (*aliaslist) )
{
 int exit_rc = EXIT_SUCCESS;
 int compare_rc = EXIT_SUCCESS;
 NODE * list_by_name = NULL;
 NODE * new_node = NULL;
 NODE * list  = NULL;
 NODE * temp  = NULL;
 NODE * match_node = NULL;

 /*------------------------------------------------------------------+
 | If a real member exist for this alias (based on TTR) insert the   |
 | alais name in the list provided for in each real member node.     |
 +------------------------------------------------------------------*/
 list = *aliaslist;
 while( ((temp = list->pointers[0]) != NIL) && exit_rc == EXIT_SUCCESS)
  {
   match_node = search_node(compare_by_ttr, *memlist, &temp->data);
   if (match_node != NIL)
     {
      exit_rc = insert_alias(match_node, &temp->data);
     };
   list = temp;
  };

 /*------------------------------------------------------------------+
 | Reorder real member list by member name.                          |
 +------------------------------------------------------------------*/
 if (exit_rc == EXIT_SUCCESS)
   {
    list = *memlist;            /* walking node pointer             */
    list_by_name = newlist();   /* Initial new for member order     */

    while( (temp = list->pointers[0]) != NIL)
     {
      new_node = insert_node(compare_by_name,
                        list_by_name, &temp->data);
      list = temp;                       /* Next list member please */
     };

    freelist(*memlist);       /* Free original real member skiplist */

    *memlist = list_by_name;  /* Replace it with the new skiplist   */
   };

 /*------------------------------------------------------------------+
 | Alias members left in the aliaslist (member names are other than  |
 | REALMEMB) will be added to the real member skiplist, they will be |
 | processed as 'real' members, with a comment indicating they       |
 | are really 'alias' members which were orphaned.                   |
 +------------------------------------------------------------------*/
 if (exit_rc == EXIT_SUCCESS)
   {
    list = *aliaslist;
    while( (temp = list->pointers[0]) != NIL )
      {
       compare_rc = memcmp(temp->data.member,REALMEMB, 8);
       if (compare_rc != EQUAL )
         {
           new_node = insert_node(compare_by_name,
                                  list_by_name, &temp->data);
         };
       list = temp;
      };
   };

 return(exit_rc);
}

#pragma eject
/*--------------------------------------------------------------------+
|                                                                     |
| Function  : insert_alias                                            |
|                                                                     |
| Language  : C                                                       |
|                                                                     |
| Purpose   : Insert an alias member in the list for its matching     |
|             real member.  If no alias list exist, one is            |
|             initialized and then the alias member name node is      |
|             added to the list.                                      |
|                                                                     |
|             Alias members are added to a list anchored by a pointer |
|             in the match_node structure.  The list is terminated    |
|             by a sentinel node which is null.  The purpose of the   |
|             sentinel node is to provide a simple way for other      |
|             functions using the list to find the end.   Alias       |
|             members are added to the list between the last node     |
|             and the sentinel node, this keeps the list in the       |
|             order in which the alias members were added.            |
|                                                                     |
| Parameters:                                                         |
|            NODE * match_node   - matching node for the alias        |
|                                                                     |
|            PDS_MBR * alias_mem - alias member information           |
|                                                                     |
| Returns   :  EXIT_SUCCESS - alias was added to the list             |
|              EXIT_FAILURE - ran out of memory                       |
|                                                                     |
| Notes     :                                                         |
|                                                                     |
|                                                                     |
+--------------------------------------------------------------------*/
static int insert_alias ( NODE * match_node, PDS_MBR * alias_mem )
{
 int exit_rc = EXIT_SUCCESS;
 ALIAS_DATA * new_alias;

 /*------------------------------------------------------------------+
 | Build an alias node and insert it into the list of alias members  |
 | for this matching real member.                                    |
 +------------------------------------------------------------------*/
 new_alias = calloc(1,sizeof(ALIAS_DATA));

 if (new_alias == NULL)
   {
    fprintf(stderr,"\nNULL pointer returned from calloc().\n\n");
    fprintf(stderr,"\n  At line %d in %s\n", __LINE__,__FILE__);
    exit_rc = EXIT_FAILURE;
   }
  else
   {
    memcpy(new_alias->member, alias_mem->member, 8);
    if (match_node->data.alias_list == NULL)
      {
       /* Alloacate a sentinel node to mark the end of the list     */
       /* and chain it behind the newly created alias node          */
       new_alias->next_alias = calloc(1,sizeof(ALIAS_DATA));
       if (new_alias->next_alias == NULL)
         {
          fprintf(stderr,"\nNULL pointer returned from calloc().\n\n");
          fprintf(stderr,"\n  At line %d in %s\n", __LINE__,__FILE__);
          exit_rc = EXIT_FAILURE;
         }
        else
         {
          /* Initialize the alias_list and alias_last to new node   */
          match_node->data.alias_list = new_alias;
          match_node->data.alias_last = new_alias;
         };
      }
     else
      {
       /* Chain new alias to sentinel node.                         */
       new_alias->next_alias = match_node->data.alias_last->next_alias;

       /* Chain last alias to new alias                             */
       match_node->data.alias_last->next_alias = new_alias;

       /* Make new alias the last alias in the list                 */
       match_node->data.alias_last = new_alias;
      };

    /*---------------------------------------------------------------+
    | Mark this alias as having a matching real member.              |
    +---------------------------------------------------------------*/
    memcpy(alias_mem->member, REALMEMB, 8);
   };

 return(exit_rc);
}

#pragma eject
/*--------------------------------------------------------------------+
|                                                                     |
| Function  : abend_exit                                              |
|                                                                     |
| Purpose   : Handle abends on output dataset for x37 only.           |
|                                                                     |
| Parameters:                                                         |
|   void * abend_info_ptr  - abend code and action                    |
|                                                                     |
| Returns   :  0 - always                                             |
|                                                                     |
| Notes     :                                                         |
|                                                                     |
+--------------------------------------------------------------------*/
static int abend_exit ( void *    abend_info_ptr, void * not_used)
{
 struct ABEND_INFO * abend_info;

 abend_info = (struct ABEND_INFO *) abend_info_ptr;

 if ( (abend_info->abend_code == 0xb37 ||
       abend_info->abend_code == 0xd37 ||
       abend_info->abend_code == 0xe37    ) &&
       abend_info->ok_to.ignore
    )
   {
    /* Ignore full condition and allow code to handle                */
    abend_info->action = 4;
    fprintf(stderr,"Output dataset is full for %s\n", DDN_SYSPUNCH);
   }
  else
   {
    /* Do not continue, abend now.  This can not be ingnored.        */
    abend_info->action = 4;
   };

 return(0);
}

#pragma eject
/*--------------------------------------------------------------------+
|                                                                     |
| Function  : synad_exit                                              |
|                                                                     |
| Language  : C                                                       |
|                                                                     |
| Purpose   : Handle I/O error condtions for SYSLIB and SYSPUNCH.     |
|             This allows for the full error message to be displayed. |
|                                                                     |
| Parameters:                                                         |
|   void * synadf_info_ptr - address of message constructed by        |
|                            SYNADF                                   |
|   void * decb_ptr        - DECB for the DD causing the SYNAD exit   |
|                            to be called                             |
|                                                                     |
| Returns   :  0 - always                                             |
|                                                                     |
| Notes     :                                                         |
|                                                                     |
|                                                                     |
+--------------------------------------------------------------------*/
static int synad_exit ( void * synadf_info_ptr, void * decb_ptr)
{
 struct SYNAD_INFO * synad_info;
 DECB_t             * decb;

 /* cast pointers to correct data types for processing               */
 synad_info = (struct SYNAD_INFO *) synadf_info_ptr;
 decb       = (DECB_t  *) decb_ptr;


 /*------------------------------------------------------------------+
 | Check for PDSE and handle the additional message data that is     |
 | provided for them.                                                |
 +------------------------------------------------------------------*/
 if (synad_info->msg1[113] == 'S')     /* 'S' is a PDSE.            */
    {
     fprintf(stderr,"I/O Error while processing a DSORG=PDSE "
                "data set, SYNAD message text follows - \n");
     fprintf(stderr,"\n Message  : %.114s\n", synad_info->msg1);
     fprintf(stderr,"\n PDSE-Info: %.40s\n\n", synad_info->msg2);
    }
   else
    {
     fprintf(stderr,"I/O Error while processing a DSORG=PO data set, "
                 " SYNAD message text follows - \n");
     fprintf(stderr,"\n Message  : %.114s\n\n", synad_info->msg1);
    };

 return(0);
}

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