DSN8ED8

Demonstrates how to use an application program to call DSNUTILU, the Db2 Utilities Unicode parser.

 /*********************************************************************
 * Module name = DSN8ED8 (sample program)                             *
 *                                                                    *
 * DESCRIPTIVE NAME: Sample client for:                               *
 *                   DSNTUTILU (DB2 Utilities Unicode Parser)         *
 *                                                                    *
 *     LICENSED MATERIALS - PROPERTY OF IBM                           *
 *     5650-DB2                                                       *
 *     (C) COPYRIGHT 1982, 2016 IBM CORP.  ALL RIGHTS RESERVED.       *
 *                                                                    *
 *     STATUS = VERSION 12                                            *
 *                                                                    *
 * Function: Demonstrates how to use an application program to call   *
 *           DSNUTILU, the DB2 Utilities Unicode parser.  DSN8ED8     *
 *           performs the following tasks:                            *
 *           - Collects the user-provided utility id, restart option, *
 *             and utility statement in EBCDIC format (CCSID 37)      *
 *             * A utility statement of up to 32K can be passed via   *
 *               the UTILSTMT DD. Input records must be RECFM=FB,     *
 *               LRECL=80. Columns 73 - 80 of each record are         *
 *               ignored.                                             *
 *           - Calls z/OS UNICODE Services to convert these values to *
 *             UNICODE (CCSID 1208)                                   *
 *           - Calls DSNUTILU, passing the converted values as parms  *
 *           - Receives and processes the result set from DSNUTILU,   *
 *             converting the data from UNICODE to EBCDIC and         *
 *             printing the results.                                  *
 *                                                                    *
 * Notes:                                                             *
 *   Dependencies: z/OS Unicode Conversion Services                   *
 *                 - Note: conversion for 37->1208 and 1208-> 37 must *
 *                   be available.                                    *
 *                 SYSPROC.DSNUTILU                                   *
 *                                                                    *
 *   Restrictions:                                                    *
 *                                                                    *
 * Module type: C program                                             *
 *   Processor: DB2 Precompiler                                       *
 *              IBM C/C++ for z/OS V1R3 or higher                     *
 * Module size: See linkedit output                                   *
 *  Attributes: Reentrant and reusable                                *
 *                                                                    *
 * Entry point: DSN8ED8                                               *
 *     Purpose: See Function                                          *
 *     Linkage: Standard MVS program invocation, no parameters.       *
 *                                                                    *
 *  Parameters: None                                                  *
 *                                                                    *
 *      Inputs: DSN8ED8 allocates these input DDs:                    *
 *              - UTILID  : Specify utility ID                        *
 *              - RESTART : Specify utility RESTART option            *
 *              - UTILSTMT: Specify utility statement                 *
 *                                                                    *
 *     Outputs: DSN8ED8 allocates these output DD                     *
 *              - REPORT  : Results from running utility              *
 *              - SYSPRINT: Call summary                              *
 *                                                                    *
 * Normal Exit: Return Code: 0000                                     *
 *              - Message: DSNUTILU has completed with return code 0  *
 *                                                                    *
 * Normal with Warnings Exit: Return Code: 0004                   +@04*
 *              - Message: DSNUTILU has completed with return code 4  *
 *                                                                    *
 *  Error Exit: Return Code: 0012                                     *
 *              - Message: DSNUTILU has completed with return code <n>*
 *              - Message: The length of the argument specified for   *
 *                         the <parameter-name> does not fall within  *
 *                         the required bounds of <minimum-length>    *
 *                         and <maximum-length>                       *
 *              - Message: Unable to open <DD-name>                   *
 *              - Message: Unable to close <DD-name>                  *
 *              - Message: Unable to read <DD-name>                   *
 *              - Message: Unable to convert the string x<string>     *
 *                         from CCSID <sourceCCSID>                   *
 *                         to CCSID <targetCCSID>                     *
 *                         Conversion returned code = <code>,         *
 *                         reason = <reason>                          *
 *              - Message: <formatted SQL text from DSNTIAR>          *
 *                                                                    *
 * External References:                                               *
 *              - Routines/Services: DSNTIAR: DB2 msg text formatter  *
 *              - Data areas       : None                             *
 *              - Control blocks   : None                             *
 *                                                                    *
 *                                                                    *
 * Pseudocode:                                                        *
 *   DSN8ED8:                                                         *
 *     - writeReportHeader                                            *
 *     - readDSNUTILUparms                                            *
 *       - readUtilityId                                              *
 *         - convertEncodingScheme                                    *
 *       - readRestartOption                                          *
 *         - convertEncodingScheme                                    *
 *       - readUtilityStatement                                       *
 *         - convertEncodingScheme                                    *
 *     - callDSNUTILU                                                 *
 *     - processDSNUTILUresultSet                                     *
 *       - associateResultSetLocator                                  *
 *       - allocateResultSetCursor                                    *
 *       - writeDSNUTILUreport                                        *
 *         - openReportDataSet                                        *
 *         - while unprocessed result set records                     *
 *           - fetchFromResultSetCursor                               *
 *           - convertEncodingScheme                                  *
 *           - write report line                                      *
 *         - closeReportDataSet                                       *
 *     - if return code from DSNUTILU was 0 or 4                      *
 *       - processSqlCommit                                           *
 *     - else                                                         *
 *       - processSqlRollback                                         *
 *   End DSN8ED8                                                      *
 *                                                                    *
 *                                                                    *
 *  Change activity =                                                 *
 *    07/26/2014 Add UTILFILE DD for passing the  s20128_inst1 s20128 *
 *               name of a data set having the                        *
 *               utility control statement.                           *
 *    06/22/2015 Remove UTILFILE DD               s25173_inst1 s25173 *
 *                                                                    *
 *********************************************************************/

 #pragma runopts(POSIX(ON),TRAP(OFF))
 #define _XOPEN_SOURCE_EXTENDED 1

 /********************** C library definitions ***********************/
 #include        <errno.h>
 #include        <stdio.h>
 #include        <stdlib.h>
 #include        <string.h>
 #include        <cunhc.h>             /* UNICODE services           */

 /**************************** Constants *****************************/
 #define         NULLCHAR         '\0' /* Null character             */
 #define         RETNRM             0  /* Normal  return code        */
 #define         RETWRN             4  /* Warning return code        */
 #define         RETERR             8  /* Error return code          */
 #define         RETSEV            12  /* Severe error return code   */
 #define         UNIBLANK       '\x20' /* UNICODE Blank character    */

 enum flag                  {No, Yes}; /* Settings for flags         */


 /**************** Output: DSNUTILU result set report ****************/
 FILE            *reportDD;            /* Pointer to report DD       */
 char            reportDDName[12];     /* For report DD name         */
 unsigned short  reportLRECL;          /* length req'd for output rec*/


 /************************ Working variables *************************/
 unsigned short  resultSetReturned = 0;/* DSNUTILU result set status */
 long int        DSNUTILU_rc     = -1; /* DSNUTILU return code       */
 long int        rc               = 0; /* program return code        */


 char            utilityId[17];        /*                            */
 char            restartOption[9];     /*                            */
 char            utilityStmt[32705];   /*                            */

 /******************** DB2 SQL Communication Area ********************/
 EXEC SQL INCLUDE SQLCA;


 /************************ DB2 Host Variables ************************/
 EXEC SQL BEGIN DECLARE SECTION;

   struct                              /* DSNUTILU utility ID        */
     { short int length;               /*   length                   */
       char      data[17];             /*   value                    */
     }           UTILITY_ID;

   struct                              /* DSNUTILU restart point     */
     { short int length;               /*   length                   */
       char      data[9];              /*   value                    */
     }           RESTART;

   struct                              /* DSNUTILU utility statement */
     { short int length;               /*   length                   */
       char      data[32705];          /*   value                    */
     }           UTSTMT;

   long int      RETCODE;              /* DSNUTILU return code       */

   struct                              /* DSNUTILU result set        */
     { short int length;               /*   length                   */
       char      data[254];            /*   value                    */
     }           TEXT;

   long int      SEQNO;                /* Result set row sequence no.*/

 EXEC SQL END DECLARE SECTION;


 /*************** DB2 Result Set Locator Host Variables **************/
 EXEC SQL BEGIN DECLARE SECTION;
   static volatile SQL TYPE IS RESULT_SET_LOCATOR *DSNUTILU_rs_loc1;
 EXEC SQL END DECLARE SECTION;


 /********************** DSN8ED8 Function Models *********************/
 int main                              /* DSN8ED8 driver             */
   ( int argc,                         /* - Input argument count     */
     char *argv[]                      /* - Input argument vector    */
   );
 void writeReportHeader( void );       /* Write the report header    */
 void readDSNUTILUparms( void );       /* Get data for DSNUTILU call */
 void readUtilityId                    /* Read Utility ID            */
   ( char *utilityId                   /* -out: utility ID           */
   );
 void readRestartOption                /* Read restart point         */
   ( char *restartOption               /* -out: restart point        */
   );
 void readUtilityStatement             /* Read utility statement     */
   ( char *utilityStmt                 /* -out: utility statement    */
   );
 void callDSNUTILU( void );            /* Run DSNUTILU               */
 void processDSNUTILUresultSet( void );/* Process DSNUTILU rslt set  */
 void associateResultSetLocator(void); /* Assoc DSNUTILU RS locator  */
 void allocateResultSetCursor( void ); /* Alloc DSNUTILU RS cursor   */
 void writeDSNUTILUreport( void );     /* Output a DSNUTILU report   */
 void fetchFromResultSetCursor( void );/* Read DSNTSPMP RS cursor    */
 void openReportDataSet( void );       /* Alloc DD for report        */
 void closeReportDataSet( void );      /* Dealloc DD for report      */
 char * trimTrailingBlanks             /* Strip off trailing blanks  */
   ( char            *string           /* - in: string to be trimmed */
   );
 void processSqlCommit( void );        /* Commit SQL changes      @04*/
 void processSqlRollback( void );      /* Rollback SQL changes    @04*/
 void issueDataSetClosingError         /* Handler for ds close error */
   ( char            *DDname,          /* - in: name of errant DD    */
     int             LEerrno           /* - in: LE diagnostic errno  */
   );
 void issueDataSetOpeningError         /* Handler for ds open error  */
   ( char            *DDname,          /* - in: name of errant DD    */
     int             LEerrno           /* - in: LE diagnostic errno  */
   );
 void issueDataSetReadingError         /* Handler for ds read error  */
   ( char            *DDname,          /* - in: name of errant DD    */
     int             LEerrno           /* - in: LE diagnostic errno  */
   );
 void issueInvalidParmLengthError      /* Handler for parm len error */
   ( char            *parmName,        /* - in: identify of parm     */
     int             minLength,        /* - in: min valid length     */
     int             maxLength         /* - in: max valid length     */
   );
 void issueSqlError                    /* Handler for SQL error      */
   ( char            *locMsg           /* - in: Call location        */
   );
 void convertEncodingScheme
   ( char            *string,          /* - in/out: string to convert*/
     short int       stringLength,     /* - in: length of string     */
     unsigned long   sourceCCSID,      /* - in: CCSID to convert from*/
     unsigned long   targetCCSID       /* - in: CCSID to convert to  */
   );


 int main                              /* DSN8ED8 driver             */
   ( int argc,                         /* - Input argument count     */
     char *argv[]                      /* - Input argument vector    */
   )
   /*******************************************************************
   * Main Driver:                                                     *
   * - Reads data to be passed to DSNUTILU                            *
   * - Calls DSNUTILU                                                 *
   * - Processes the result set returned from DSNUTILU                *
   *                                                                  *
   *******************************************************************/
   { /*****************************************************************
     * Write the report header                                        *
     *****************************************************************/
     writeReportHeader();

     /*****************************************************************
     * Read data for DSNUTILU parm arguments                          *
     *****************************************************************/
     readDSNUTILUparms();

     /*****************************************************************
     * Call DSNUTILU                                                  *
     *****************************************************************/
     if( rc < RETSEV )
       callDSNUTILU();

     /*****************************************************************
     * Process the result set, if any, from DSNUTILU                  *
     *****************************************************************/
     if( resultSetReturned )
       processDSNUTILUresultSet();

     /*****************************************************************
     * If DSNUTILU returns either 0 (normal) or 4 (warnings), perform *
     * a COMMIT; Otherwise, perform a ROLLBACK                        *
     *****************************************************************/
     if( DSNUTILU_rc == RETNRM || DSNUTILU_rc == RETWRN )
       { processSqlCommit();
         if( rc < DSNUTILU_rc )
           rc = DSNUTILU_rc;
       }
     else
       { processSqlRollback();
         if( rc < RETSEV )
           rc = RETSEV;
       }

     /*****************************************************************
     * Return highest completion code                                 *
     *****************************************************************/
     return( rc );

   } /* end of main */


 void writeReportHeader( void )        /* Write the report header    */
   /*******************************************************************
   * Writes the report header                                         *
   *******************************************************************/
   {
     printf( "****************************************"
             "****************************************\n" );
     printf( "* DSN8ED8 is now invoking the DB2 Utilities UNICODE "
             "Parser (SYSPROC.DSNUTILU)\n" );
     printf( "*\n" );
   } /* end of writeReportHeader */


 void readDSNUTILUparms( void )        /* Get DSNUTILU parms         */
   /*******************************************************************
   * Collects the arguments for parms to be passed to DSNUTILU        *
   *******************************************************************/
   {
     UTILITY_ID.length = 0;
     memset( UTILITY_ID.data, NULLCHAR, 17 );
     RESTART.length = 0;
     memset( RESTART.data, NULLCHAR, 9 );
     UTSTMT.length = 0;
     memset( UTSTMT.data, NULLCHAR, 32704 );

     readUtilityId( utilityId );
     if( rc < RETSEV )
       { strcpy( UTILITY_ID.data, utilityId );
         UTILITY_ID.length = strlen(utilityId);
       }

     if( rc < RETSEV )
       { readRestartOption( restartOption );
       }

     if( rc < RETSEV )
       { strcpy( RESTART.data, restartOption );
         RESTART.length = strlen(restartOption);
       }

     if( rc < RETSEV )
       { readUtilityStatement( utilityStmt );
       }

     if( rc < RETSEV )
       { strcpy( UTSTMT.data, utilityStmt );
         UTSTMT.length = strlen(utilityStmt);
       }
   } /* end of readDSNUTILUparms */


 void readUtilityId                    /* Read Utility ID            */
   ( char *utilityId                   /* -out: utility ID           */
   )
   /*******************************************************************
   * Reads a utility ID value of 1-16 bytes from the UTILID DD        *
   *******************************************************************/
   { FILE           *utilIdFile;       /* Ptr to UTILID DD           */
     char           utilIdDD[12];      /* DD handle                  */
     char           utilIdRec[80];     /* UTILID file input record   */
     short int      recordLength  = 0; /* Length of record           */
     unsigned short moreRecords = Yes; /* EOF indicator              */

     strcpy( utilIdDD,"DD:UTILID   " );

     errno = 0;                        /* clear LE errno             */
     utilIdFile = fopen( utilIdDD,
                         "rb,lrecl=80,type=record" );
     if( utilIdFile == NULL )
       issueDataSetOpeningError( utilIdDD,errno );

     while( moreRecords == Yes  &&  rc < RETSEV )
       { recordLength
           = fread( utilIdRec,         /* Read into UTILID rec area  */
                    1,                 /* ..1 record                 */
                    80,                /* ..of 80 bytes              */
                    utilIdFile );      /* ..from UTILID file         */

                                       /* Discard bytes 73-80        */
         memset(&utilIdRec[72], NULLCHAR, 8);

         if( ferror(utilIdFile) )      /* Handle IO errors           */
            issueDataSetReadingError( utilIdDD,errno );

         else if( feof(utilIdFile) )   /* Handle EOF                 */
            moreRecords = No;
                                       /* Don't overfill return area */
         else if( rc < RETSEV  &&
                  (strlen(utilityId) +
                   strlen(trimTrailingBlanks( utilIdRec ))) > 16 )
            issueInvalidParmLengthError( "UTILID",1,16 );

         else                          /* Strip off trailing blanks  */
            strcat( utilityId, trimTrailingBlanks( utilIdRec ) );
       }

     if( rc < RETSEV )
       if( fclose( utilIdFile ) != 0 )
         issueDataSetClosingError( utilIdDD,errno );

     if( rc < RETSEV )
       { printf( "* Utility ID: %s\n", utilityId );
         printf( "*\n" );
         convertEncodingScheme( utilityId, strlen(utilityId),
                                37,1208 );
        }

   } /* end of readUtilityId */


 void readRestartOption                /* Read restart point         */
   ( char *restartOption               /* -out: restart point        */
   )
   /*******************************************************************
   * Reads a restart point value of 0-8 bytes from the RESTART DD     *
   *******************************************************************/
   { FILE           *restartOptFile;   /* Ptr to RESTART DD          */
     char           restartOptDD[12];  /* DD handle                  */
     char           restartOptRec[80]; /* RESTART file input record  */
     short int      recordLength  = 0; /* Length of record           */
     unsigned short moreRecords = Yes; /* EOF indicator              */

     strcpy( restartOptDD,"DD:RESTART " );

     errno = 0;                        /* clear LE errno             */
     restartOptFile = fopen( restartOptDD,
                             "rb,lrecl=80,type=record" );
     if( restartOptFile == NULL )
       issueDataSetOpeningError( restartOptDD,errno );

     while( moreRecords == Yes  &&  rc < RETSEV )
       { recordLength
           = fread( restartOptRec,     /* Read into RESTART rec area */
                    1,                 /* ..1 record                 */
                    80,                /* ..of 80 bytes              */
                    restartOptFile );  /* ..from RESTART file        */

                                       /* Discard bytes 73-80        */
         memset(&restartOptRec[72], NULLCHAR, 8);

         if( ferror(restartOptFile) )  /* Handle IO errors           */
            issueDataSetReadingError( restartOptDD,errno );

         else if(feof(restartOptFile)) /* Handle EOF                 */
            moreRecords = No;
                                       /* Don't overfill return area */
         else if( rc < RETSEV  &&
                  (strlen(restartOption) +
                   strlen(trimTrailingBlanks( restartOptRec ))) > 8 )
            issueInvalidParmLengthError( "RESTART",0,8 );

         else                          /* Strip off trailing blanks  */
            strcat( restartOption,
                    trimTrailingBlanks( restartOptRec ) );
       }

     if( rc < RETSEV )
       if( fclose( restartOptFile ) != 0 )
         issueDataSetClosingError( restartOptDD,errno );

     if( rc < RETSEV )
       { printf( "* Restart point: %s\n", restartOption );
         printf( "*\n" );
         convertEncodingScheme( restartOption, strlen(restartOption),
                                37,1208 );
        }

   } /* end of readRestartOption */


 void readUtilityStatement             /* Read utility statement     */
   ( char *utilityStmt                 /* -out: utility statement    */
   )
   /*******************************************************************
   * Reads a utility statement of 0-32704 bytes from the UTILSTMT DD  *
   *******************************************************************/
   { FILE           *utilStmtFile;     /* Ptr to UTILSTMT DD         */
     char           utilStmtDD[12];    /* DD handle                  */
     char           utilStmtRec[80];   /* UTILSTMT file input record */
     short int      recordLength  = 0; /* Length of record           */
     unsigned short moreRecords = Yes; /* EOF indicator              */

     memset( utilityStmt, NULLCHAR, 32705 );

     strcpy( utilStmtDD,"DD:UTILSTMT" );

     errno = 0;                        /* clear LE errno             */
     utilStmtFile = fopen( utilStmtDD,
                           "rb,lrecl=80,type=record" );
     if( utilStmtFile == NULL )
       issueDataSetOpeningError( utilStmtDD,errno );

     while( moreRecords == Yes  &&  rc < RETSEV )
       { recordLength
           = fread( utilStmtRec,       /* Read into UTILSTMT rec area*/
                    1,                 /* ..1 record                 */
                    80,                /* ..of 80 bytes              */
                    utilStmtFile );    /* ..from UTILSTMT file       */

                                       /* Discard bytes 73-80        */
         memset(&utilStmtRec[72], NULLCHAR, 8);

         if( ferror(utilStmtFile) )    /* Handle IO errors           */
            issueDataSetReadingError( utilStmtDD,errno );

         else if(feof(utilStmtFile)) /* Handle EOF                   */
            moreRecords = No;
                                       /* Don't overfill return area */
         else if( rc < RETSEV  &&
                  (strlen(utilityStmt) +
                   strlen(utilStmtRec)) > 32704 )
            issueInvalidParmLengthError( "UTILSTMT",1,32704 );

         else
            strcat( utilityStmt,utilStmtRec );
       }

     if( rc < RETSEV )
       if( fclose( utilStmtFile ) != 0 )
         issueDataSetClosingError( utilStmtDD,errno );

     if( rc < RETSEV )
       { printf( "* Utility statement: %s\n", utilityStmt );
         printf( "*\n" );
         convertEncodingScheme( utilityStmt, strlen(utilityStmt),
                                37,1208 );
        }

   } /* end of readUtilityStatement */


 void callDSNUTILU( void )             /* Run DSNUTILU               */
   /*******************************************************************
   * Calls DSNUTILU                                                   *
   *******************************************************************/
   { EXEC SQL
       CALL SYSPROC.DSNUTILU( :UTILITY_ID
                             ,:RESTART
                             ,:UTSTMT
                             ,:RETCODE );

     /*****************************************************************
     * Analyze status codes from DSNUTILU                             *
     *****************************************************************/
     printf( "* DSNUTILU has completed with return code %i\n",
                RETCODE );
     if( SQLCODE != 0  &&  SQLCODE != 466 )
       { issueSqlError( "Call to DSNUTILU failed" );
       }
     else
       { DSNUTILU_rc = RETCODE;
         if( SQLCODE == 466 )
           { printf( "* A result set was returned\n" );
             resultSetReturned = Yes;
           }
         else /* SQLCODE == 0 */
           { printf( "* No result sets were returned\n" );
             resultSetReturned = No;
           }
       }

   } /* end of callDSNUTILU */


 void processDSNUTILUresultSet( void ) /* Handle DSNUTILU result set */
   /*******************************************************************
   * Outputs data from the result set returned by DSNUTILU            *
   *******************************************************************/
   {
     /*****************************************************************
     * Associate a locator with the result set from DSNUTILU          *
     *****************************************************************/
     associateResultSetLocator();

     /*****************************************************************
     * Allocate a cursor for the result set                           *
     *****************************************************************/
     if( rc < RETSEV )
       allocateResultSetCursor();

     /*****************************************************************
     * Output reports returned in the result set                      *
     *****************************************************************/
     if( rc < RETSEV )
       writeDSNUTILUreport();

   } /* end of processDSNUTILUresultSet */


 void associateResultSetLocator(void)  /* Assoc DSNUTILU RS locator  */
   /*******************************************************************
   * Associates the result set from DSNUTILU with a result set locator*
   *******************************************************************/
   { EXEC SQL
       ASSOCIATE
         LOCATORS( :DSNUTILU_rs_loc1 )
       WITH PROCEDURE SYSPROC.DSNUTILU;

     if( SQLCODE != 0 )
       { issueSqlError( "Associate locator call failed" );
       }

   } /* end of associateResultSetLocator */


 void allocateResultSetCursor( void )  /* Alloc DSNUTILU RS cursor   */
   /*******************************************************************
   * Allocates a cursor to the locator for the DSNUTILU result set    *
   *******************************************************************/
   { EXEC SQL
       ALLOCATE DSNUTILU_RS_CSR1
         CURSOR FOR RESULT SET :DSNUTILU_rs_loc1;

     if( SQLCODE != 0 )
       { issueSqlError( "Allocate result set cursor "
                                 "call failed" );
       }

   } /* end of allocateResultSetCursor */


 void writeDSNUTILUreport( void )      /* Print DSNUTILU report      */
   /*******************************************************************
   * Outputs the contents of the result set from DSNUTILU             *
   *******************************************************************/
   { short int recordLength = 0;       /* Length of record           */
     char      recordText[256];        /* Text of record             */

     /*****************************************************************
     * Get the first entry in the result set                          *
     *****************************************************************/
     fetchFromResultSetCursor();

     /*****************************************************************
     * Allocate an outout DD for the report                           *
     *****************************************************************/
     if( rc < RETSEV )
       openReportDataSet();

     /*****************************************************************
     * Process all rows in the result set                             *
     *****************************************************************/
     while( SQLCODE == 0  &&  rc < RETSEV )
       { /*************************************************************
         * Convert the current report line from UNICODE to EBCDIC     *
         *************************************************************/
         convertEncodingScheme( TEXT.data, TEXT.length,
                                1208, 37 );

         /*************************************************************
         * Write the current report line                              *
         *************************************************************/
         memset( recordText,' ',256 );
         memcpy( recordText,TEXT.data,TEXT.length );
         if( rc < RETSEV )
           { recordLength
               = fwrite( recordText,   /* write from TEXT.data       */
                         1,            /* ..a record                 */
                         sizeof( recordText ),
                         reportDD );   /* ..into the report data set */
           }
         if( rc < RETSEV )
           { fetchFromResultSetCursor();
           }
       }

     if( rc < RETSEV )
       { closeReportDataSet();
       }

   } /* end of writeDSNUTILUreport */


 void fetchFromResultSetCursor( void ) /* Read DSNUTILU RS cursor    */
   /*******************************************************************
   * Reads the cursor for the DSNUTILU result set                     *
   *******************************************************************/
   { memset( TEXT.data,NULLCHAR,254 );

     EXEC SQL
       FETCH DSNUTILU_RS_CSR1
       INTO  :SEQNO,
             :TEXT;

     if( SQLCODE != 0  &&  SQLCODE != 100  &&  rc < RETSEV )
       { issueSqlError( "*** Fetch from "
                                 "result set cursor failed" );
       }
   } /* end of fetchFromResultSetCursor */


 void openReportDataSet( void )        /* Alloc DD for report        */
   /*******************************************************************
   * Opens the DD REPORT and associates it with the file handler      *
   * reportDD.                                                        *
   *******************************************************************/
   { char          reportDDdcb[36];    /* for generated DCB          */

     sprintf( reportDDName,            /* Generate DD name REPORT    */
              "DD:REPORT" );

     if( TEXT.data[0] == '1' )         /* Does this look like FBA?   */
       sprintf( reportDDdcb,           /* Yes: Specify               */
                "wb,recfm=FBA,"        /* ..record output, recfm=fba */
                "lrecl=256" );         /* ..and lrecl 255            */
     else
       sprintf( reportDDdcb,           /* No: Specify                */
                "wb,recfm=FB,"         /* ..record output, recfm=fb  */
                "lrecl=256" );         /* ..and lrecl 255            */

     errno = 0;                        /* clear LE errno             */
     reportDD = fopen( reportDDName,reportDDdcb );

     if( reportDD == NULL )            /* If unable to open data set */
       issueDataSetOpeningError( reportDDName,errno );
   } /* end of openReportDataSet */


 void closeReportDataSet( void )       /* Dealloc DD for report      */
   /*******************************************************************
   * Closes the DD associated with the file handler reportDD.         *
   *******************************************************************/
   { if( fclose(reportDD) != 0 )
       issueDataSetClosingError( reportDDName,errno );
   } /* end of closeReportDataSet */


 char * trimTrailingBlanks             /* Strip off trailing blanks  */
   ( char            *string           /* - in: string to be trimmed */
   )
   /*******************************************************************
   * Strips trailing blanks from a string                             *
   *******************************************************************/
   { int             i;
     for( i = strlen(string) - 1; string[i] == ' '; i-- );
     string[++i] = '\0';

     return string;
   } /* end of trimTrailingBlanks */


 void processSqlCommit( void )         /* Commit SQL changes         */
   /*******************************************************************
   * Commits the current unit of SQL work                             *
   *******************************************************************/
   { EXEC SQL
       COMMIT;

     if( SQLCODE != 0 )
       { issueSqlError( "*** Commit failed " );
       }

   } /* end of processSqlCommit */


 void processSqlRollback( void )       /* Rollback SQL changes       */
   /*******************************************************************
   * Rolls back the current unit of SQL work                          *
   *******************************************************************/
   { EXEC SQL
       ROLLBACK;

     if( SQLCODE != 0 )
       { issueSqlError( "*** Rollback failed " );
       }

   } /* end of processSqlRollback */


 void issueDataSetClosingError         /* Handler for ds close error */
   ( char            *DDname,          /* - in: name of errant DD    */
     int             LEerrno           /* - in: LE diagnostic errno  */
   )
   /*******************************************************************
   * Called when a TSO data set cannot be closed                      *
   *******************************************************************/
   { printf( "ERROR: Unable to close %s\n", DDname );
     printf( "%s \n",strerror(LEerrno) );
     printf( "-----> Processing halted\n" );
     rc = RETSEV;
   } /* end of issueDataSetClosingError */


 void issueDataSetOpeningError         /* Handler for ds open error  */
   ( char            *DDname,          /* - in: name of errant DD    */
     int             LEerrno           /* - in: LE diagnostic errno  */
   )
   /*******************************************************************
   * Called when a TSO data set cannot be opened                      *
   *******************************************************************/
   { printf( "ERROR: Unable to open %s\n", DDname );
     printf( "%s \n",strerror(LEerrno) );
     printf( "-----> Processing halted\n" );
     rc = RETSEV;
   } /* end of issueDataSetOpeningError */


 void issueDataSetReadingError         /* Handler for ds read error  */
   ( char            *DDname,          /* - in: name of errant DD    */
     int             LEerrno           /* - in: LE diagnostic errno  */
   )
   /*******************************************************************
   * Called when a TSO data set cannot be read                        *
   *******************************************************************/
   { printf( "ERROR: Unable to read %s\n", DDname );
     printf( "%s \n",strerror(LEerrno) );
     printf( "-----> Processing halted\n" );
     rc = RETSEV;
   } /* end of issueDataSetReadingError */


 void issueInvalidParmLengthError      /* Handler for parm len error */
   ( char *parmName,                   /* - in: identify of parm     */
     int minLength,                    /* - in: min valid length     */
     int maxLength                     /* - in: max valid length     */
   )
   /*******************************************************************
   * Called when the length of an argument specified for a DSNTPSMP   *
   * parameter (parmName) does not fall within the valid bounds for   *
   * size (minLength and maxLength) for that parameter                *
   *******************************************************************/
   { printf( "ERROR: The length of the argument specified for the %s "
                    "parameter\n",parmName );
     printf( "       does not fall within the required bounds of %i "
                    "and %i\n",minLength,maxLength );
     printf( "-----> Processing halted\n" );
     rc = RETSEV;
   } /* end of issueInvalidParmLengthError */


 #pragma linkage(dsntiar, OS)
 void issueSqlError                    /* Handler for SQL error      */
   ( char *locMsg                      /* - in: Call location        */
   )
   /*******************************************************************
   * Called when an unexpected SQLCODE is returned from a DB2 call    *
   *******************************************************************/
   { struct      error_struct {        /* DSNTIAR message structure  */
       short int   error_len;
       char        error_text[10][80];
       }         error_message = {10 * 80};

     extern short int dsntiar( struct      sqlca         *sqlca,
                               struct      error_struct  *msg,
                               int                       *len );

     short int   DSNTIARrc;            /* DSNTIAR Return code        */
     int         j;                    /* Loop control               */
     static int  lrecl = 80;           /* Width of message lines     */

     /*****************************************************************
     * print the locator message                                      *
     *****************************************************************/
     printf( "ERROR: %-80s\n", locMsg );
     printf( "-----> Processing halted\n" );

     /*****************************************************************
     * format and print the SQL message                               *
     *****************************************************************/
     DSNTIARrc = dsntiar( &sqlca, &error_message, &lrecl );
     if( DSNTIARrc == 0 )
       for( j = 0; j <= 10; j++ )
         printf( " %.80s\n", error_message.error_text[j] );
     else
       {
         printf( " *** ERROR: DSNTIAR could not format the message\n" );
         printf( " ***        SQLCODE is %d\n",SQLCODE );
         printf( " ***        SQLERRM is \n" );
         for( j=0; j<sqlca.sqlerrml; j++ )
           printf( "%c", sqlca.sqlerrmc[j] );
         printf( "\n" );
       }

     /*****************************************************************
     * set severe error code                                          *
     *****************************************************************/
     rc = RETSEV;

   } /* end of issueSqlError */


 void convertEncodingScheme
   ( char            *string,          /* - in/out: string to convert*/
     short int       stringLength,     /* - in: length of string     */
     unsigned long   sourceCCSID,      /* - in: CCSID to convert from*/
     unsigned long   targetCCSID       /* - in: CCSID to convert to  */
   )
   /*******************************************************************
   * Call z/OS conversion services to convert string from sourceCCSID *
   * to targetCCSID                                                   *
   *******************************************************************/
   { char            sourcebuffer[32704];
     char            targetbuffer[32704];
     char            DDA[CUNBCPRM_DDA_REQ];
     char            workbuffer[32704];
     CUNBCPRM        convParm = {CUNBCPRM_DEFAULT};
     short int       ii;

     /*****************************************************************
     * initialize work areas                                          *
     *****************************************************************/
     memset( sourcebuffer,NULLCHAR,32704 );
     memset( targetbuffer,NULLCHAR,32704 );
     memset( workbuffer,NULLCHAR,32704 );
     strncpy( sourcebuffer,string,stringLength );

     /*****************************************************************
     * establish work area pointers for conversion services           *
     *****************************************************************/
     convParm.Src_Buf_Ptr  = sourcebuffer;
     convParm.Src_Buf_Len  = stringLength;
     convParm.Targ_Buf_Ptr = targetbuffer;
     convParm.Targ_Buf_Len = 32704;
     convParm.Src_CCSID    = sourceCCSID;
     convParm.Targ_CCSID   = targetCCSID;
     memcpy(convParm.Technique,"ER",2);
     convParm.Wrk_Buf_Ptr  = workbuffer;
     convParm.Wrk_Buf_Len  = 32704;
     convParm.DDA_Buf_Ptr  = DDA;  /* used for service internal data */
     convParm.DDA_Buf_Len  = CUNBCPRM_DDA_REQ;

     /*****************************************************************
     * call conversion services                                       *
     *****************************************************************/
     CUNLCNV ( & convParm );

     if( convParm.Return_Code == CUN_RC_OK )
       strcpy( string,targetbuffer );
     else
       { printf( "ERROR: Unable to convert the string: x<" );
         for( ii=0; ii<stringLength; ii++ )
           printf( "%0x",TEXT.data[ii] );
         printf( ">\n" );
         printf( "       from CCSID %u to CCSID %u\n",
                         sourceCCSID, targetCCSID );
         printf( "       Conversion returned code = %d, reason = %d\n",
                         convParm.Return_Code, convParm.Reason_Code);
         printf( "-----> Processing halted\n" );
         rc = RETSEV;
       }
   } /* end of convertEncodingScheme */