DSN8EDXU

Updates the description record for a specified product id in the sample XML database .

 /*********************************************************************
 * Module name = DSN8EDXU (DB2 sample program)                        *
 *                                                                    *
 * DESCRIPTIVE NAME = Sample XML record update program                *
 *                                                                    *
 *    LICENSED MATERIALS - PROPERTY OF IBM                            *
 *    5675-DB2                                                        *
 *    (C) COPYRIGHT 1999, 2000 IBM CORP. ALL RIGHTS RESERVED.         *
 *                                                                    *
 *    STATUS = VERSION 9                                              *
 *                                                                    *
 * Function: Updates the description record for a specified product   *
 *           id in the sample XML database                            *
 *                                                                    *
 * Notes:                                                             *
 *   Dependencies: Requires IBM C/C++ for z/OS                        *
 *                                                                    *
 *   Restrictions:                                                    *
 *                                                                    *
 * Module type: C program                                             *
 *   Processor: IBM C/C++ for z/OS                                    *
 * Module size: See linkedit output                                   *
 *  Attributes: Re-entrant and re-usable                              *
 *                                                                    *
 * Entry Point: DSN8EDXU                                              *
 *     Purpose: See Function                                          *
 *     Linkage: Standard z/OS linkage                                 *
 *                                                                    *
 *                                                                    *
 *  Parameters: None                                                  *
 *                                                                    *
 * Normal Exit: Return Code: 0000                                     *
 *              - Message: none                                       *
 *                                                                    *
 *  Error Exit: Return Code: 0012                                     *
 *              - Message: Unable to open <DD-name>                   *
 *              - Message: Unable to close <DD-name>                  *
 *              - Message: <formatted SQL text from DSNTIAR>          *
 *                                                                    *
 *    External References:                                            *
 *             - Routines/Services: DSNTIAR: DB2 msg text formatter   *
 *             - Data areas       : None                              *
 *             - Control blocks   : None                              *
 *                                                                    *
 *  Pseudocode:                                                       *
 *   DSN8EDXU:                                                        *
 *   - Call printGreeting to output the DSN8EDXU greeting             *
 *   - Call readProductId to get the ID of the product to be updated  *
 *   - Call getProductDescriptionRecord to fetch the current descrip- *
 *     tion of the product for the inputted product ID.               *
 *   - Call displayProductDescriptionRecord to format and display     *
 *     the current product description record                         *
 *   - Call readProductDescriptionUpdateRequest to read the update    *
 *     request                                                        *
 *   - Call updateProductDescription to update the record             *
 *   - Call getProductDescriptionRecord to fetch the updated descrip- *
 *     tion of the product                                            *
 *   - Call displayProductDescriptionRecord to format and display     *
 *     the updated product description record                         *
 *   - Rollback the change to preserve the sample table               *
 *     - If unexpected SQLCODE, call issueSqlError                    *
 *   - Call getProductDescriptionRecord to fetch the restored descrip-*
 *     tion of the product                                            *
 *   - Call displayProductDescriptionRecord to format and display     *
 *     the restored product description record                        *
 *   End DSN8EDXU                                                     *
 *                                                                    *
 *   printGreeting:                                                   *
 *   - Output the DSN8EDXU greeting                                   *
 *                                                                    *
 *   readProductId:                                                   *
 *   - Open the file allocated to the PRODID DD                       *
 *     - If an error occurs, call issueDataSetOpeningError            *
 *   - Read the file                                                  *
 *     - If an error occurs, call issueDataSetReadingError            *
 *   - Call trimLeadingBlanks to remove leading blanks from the entry *
 *   - Call trimTrailingBlanks to remove trailing blanks from the     *
 *     entry                                                          *
 *   - Validate the length of the entry                               *
 *     - Call issueInvalidDataLengthError if length is unexpected     *
 *   - Close the file allocated to the PRODID DD                      *
 *     - If an error occurs, call issueDataSetClosingError            *
 *                                                                    *
 *   getProductDescriptionRecord:                                     *
 *   - Fetch the description of the product for the inputted product  *
 *     ID.                                                            *
 *     - If unexpected SQLCODE, call issueSqlError                    *
 *                                                                    *
 *   displayProductDescriptionRecord:                                 *
 *   - Call getToken to locate the product section                    *
 *     - If not found, issue an diagnostic message                    *
 *   - Call getToken to locate the description section and return the *
 *     product attributes                                             *
 *     - If not found, issue an diagnostic message                    *
 *   - Call getToken for locate and return the name and setting of    *
 *     each element in the product description section                *
 *   - Output the product and description sections followed by the    *
 *     name and setting of each element in the description section    *
 *                                                                    *
 *   readProductDescriptionUpdateRequest:                             *
 *   - Open the file allocated to the DESCUPDT DD                     *
 *     - If an error occurs, call issueDataSetOpeningError            *
 *   - Read the file                                                  *
 *     - If an error occurs, call issueDataSetReadingError            *
 *   - Call trimLeadingBlanks to remove leading blanks from the entry *
 *   - Call trimTrailingBlanks to remove trailing blanks from the     *
 *     entry                                                          *
 *   - Validate the length of the entry                               *
 *     - Call issueInvalidDataLengthError if length is unexpected     *
 *   - Close the file allocated to the PRODID DD                      *
 *     - If an error occurs, call issueDataSetClosingError            *
 *                                                                    *
 *   updateProductDescription:                                        *
 *   - locate the element to be updated in the product description    *
 *     - issue a diagnostic message if not found                      *
 *   - update the element                                             *
 *     - If unexpected SQLCODE, call issueSqlError                    *
 *                                                                    *
 *   issueSqlError:                                                   *
 *   - call DSNTIAR to format the unexpected SQLCODE.                 *
 *                                                                    *
 *   issueDataSetOpeningError                                         *
 *   - Write a diagnostic message for error when opening a data set   *
 *                                                                    *
 *   issueDataSetReadingError                                         *
 *   - Write a diagnostic message for error when reading a data set   *
 *                                                                    *
 *   trimLeadingBlanks                                                *
 *   - Remove leading blanks from a string                            *
 *                                                                    *
 *   trimTrailingBlanks                                               *
 *   - Remove trailing blanks from a string                           *
 *                                                                    *
 *   issueInvalidDataLengthError                                      *
 *   - Write a diagnostic message when the length of inputted data    *
 *     is too long or too short                                       *
 *                                                                    *
 *   issueDataSetClosingError                                         *
 *   - Write a diagnostic message for error when closing a data set   *
 *                                                                    *
 *   getToken                                                         *
 *   - Locate the search argument in the buffer and optionally        *
 *     return the tokens up to and including the search argument      *
 *                                                                    *
 * Change log:                                                        *
 *                                                                    *
 *********************************************************************/
 /**************************** Equates *******************************/
 #define         BLANK        ' '      /* Blank character            */
 #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   */

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

 /********************** C library definitions ***********************/
 #include        <decimal.h>
 #include        <errno.h>
 #include        <stdio.h>
 #include        <stdlib.h>
 #include        <string.h>

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

 /************************ DB2 Host Variables ************************/

 EXEC SQL BEGIN DECLARE SECTION;
   struct
       { struct
           { short int  PID_len;
             char       PID_data[10];
           }            PID;
         struct
           { short int  NAME_len;
             char       NAME_data[128];
           }            NAME;
         decimal(30,2)  PRICE;
         decimal(30,2)  PROMOPRICE;
         char       PROMOSTART[11];
         char       PROMOEND[11];
         SQL TYPE IS XML AS CLOB(1M) DESCRIPTION;
       } PRODUCT;

   SQL TYPE IS XML AS CLOB(1M) workBuffer;
   char           *workBufPtr;

 EXEC SQL END DECLARE SECTION;

 /******************** DSN8EDXU Global Variables *********************/
 long int        rc               = 0; /* program return code        */

 typedef struct item
   { char        *element;             /* ptr to element name        */
     char        *value;               /* ptr to string value        */
     int         allocated;            /* mem alloc indicator        */
   }           item;

 /*simple structure to hold a list of elements and values*/
 typedef struct prodList
   { char        *productElement;
     char        productId[11];
     int         elements;             /* num elements in the list   */
     item        itemList[10];         /* list of elements           */
   }           prodList;

     prodList        prodDesc;         /* gets product description   */


 /******************* DSN8EDXU Function Prototypes *******************/
 int main( int argc, char *argv[] );
 void printGreeting( void );           /* Write welcome message      */
 void readProductId                    /* Read product identifier    */
   ( char            *productId,       /* -out: product identifier   */
     short           *productIdLen     /* -out: Length of product id */
   );
 void getProductDescriptionRecord      /* Fetch product descr record */
   ( void
   );
 void displayProductDescriptionRecord
   ( void
   );
 void readProductDescriptionUpdateRequest
   ( char            *request          /* -out: update request text  */
   );
 void updateProductDescription
   ( char            *request          /* -in: update request text   */
   );
 void clearBuffers( void );            /* Initialize work buffers    */
 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 issueInvalidDataLengthError      /* Handler for data len error */
   ( char            *DdName,          /* - in: identify of DD       */
     int             minLength,        /* - in: min valid length     */
     unsigned long   maxLength         /* - in: max valid length     */
   );
 void issueSqlError                    /* Handler for SQL error      */
   ( char            *locMsg           /* - in: Call location        */
   );
 void trimLeadingBlanks                /* Strip off leading blanks   */
   ( char            *string           /* - in: string to be trimmed */
   );
 void trimTrailingBlanks               /* Strip off trailing blanks  */
   ( char            *string           /* - in: string to be trimmed */
   );
 char *getToken                        /* Gets token from a string   */
   ( char            *tokPtrR,         /* -in: Ptr to start of token */
     char            *string,          /* -in: String to break on    */
     unsigned short  returnToken,      /* -in: token suppression     */
     char            *token            /* -out: Token                */
   );

 /*********************************************************************
 * List the current product description, update it, relist, rollback  *
 *********************************************************************/
 int main( int argc, char *argv[] )
   { char            request[73];      /* Area for update text       */

     clearBuffers();

     printGreeting();                  /* Say hello                  */
                                       /* Read in the product id of  */
                                       /* the record to be updated   */
     readProductId( PRODUCT.PID.PID_data,
                    &PRODUCT.PID.PID_len );

     if( rc < RETSEV )                 /* If all is well so far..    */
       { getProductDescriptionRecord();/* ..fetch product desc record*/
       }
     if( rc < RETSEV )                 /* If all is well so far..    */
       {                               /* ..show the product descr.  */
         printf( "(1) Display the product description to be updated\n");
         displayProductDescriptionRecord();
         printf( " \n" );
       }

     if( rc < RETSEV )                 /* If all is well so far..    */
       {                                /* ..get the update request   */
         readProductDescriptionUpdateRequest( request );
       }
     if( rc < RETSEV )                 /* If all is well so far..    */
       { printf( "(2) Display the update request:\n%s\n",request );
         printf( " \n" );
       }
     if( rc < RETSEV )                 /* If all is well so far..    */
       {                               /* ..apply the update         */
         updateProductDescription( request );
       }
     if( rc < RETSEV )                 /* If all is well so far..    */
       { getProductDescriptionRecord();/* ..fetch product desc record*/
       }
     if( rc < RETSEV )                 /* If all is well so far..    */
       {                               /* ..show updated prod descr. */
         printf( "(3) Display the updated product description\n" );
         displayProductDescriptionRecord();
         printf( " \n" );
       }
     EXEC SQL                          /* Rollback changes so program*/
       ROLLBACK;                       /* will run clean next time   */
     if( SQLCODE != 0 )                /* Report error, if any       */
       issueSqlError( "DSN8EDXU: Error "
                      "performing ROLLBACK" );

     if( rc < RETSEV )                 /* If all is well so far..    */
       { getProductDescriptionRecord();/* ..fetch product desc record*/
       }
     if( rc < RETSEV )                 /* If all is well so far..    */
                                       /* ..show restored prod descr.*/
       { printf( "(4) Rollback the change (for next time) "
                 "and display the original product description\n" );
         displayProductDescriptionRecord();
         printf( " \n" );
       }

     return( rc );                     /* Set return code and exit   */
   } /* end of main routine */


 void printGreeting( void )            /* Write welcome message      */
   /*******************************************************************
   * Writes a greeting when the program is started                    *
   *******************************************************************/
   { printf( "**************************************************"
             "******************************\n" );
     printf( "DSN8EDXU: Updates a record in the PRODUCT table "
             "of the DB2 sample XML database\n" );
     printf( "**************************************************"
             "******************************\n" );
   } /* End of printGreeting */


 void clearBuffers( void )             /* Initialize work buffers    */
   /*******************************************************************
   * Initializes work buffers for next use                            *
   *******************************************************************/
   { memset( PRODUCT.DESCRIPTION.data,
             NULLCHAR,
             sizeof(PRODUCT.DESCRIPTION.data) );
     PRODUCT.DESCRIPTION.length = 0;
     memset( workBuffer.data,NULLCHAR,sizeof(workBuffer.data) );
   } /* End of clearBuffers */


 void readProductId                    /* Read product identifier    */
   ( char            *productId,       /* -out: product identifier   */
     short           *productIdLen     /* -out: Length of product id */
   )
   /*******************************************************************
   * Reads id of product description to be updated from the PRODID DD *
   *******************************************************************/
   { FILE           *prodIdFile;       /* Ptr to PRODID DD           */
     char           prodIdDD[12];      /* DD handle                  */
     char           prodIdRec[80];     /* PRODID file input record   */
     short int      recordLength  = 0; /* Length of record           */
     unsigned short moreRecords = Yes; /* EOF indicator              */

     strcpy( prodIdDD,"DD:PRODID" );

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

     if( rc < RETSEV )
       { recordLength
           = fread( prodIdRec,         /* Read into PRODID rec area  */
                    1,                 /* ..1 record                 */
                    80,                /* ..of 80 bytes              */
                    prodIdFile );      /* ..from PRODID file         */

         if( ferror(prodIdFile) )      /* Handle IO errors           */
            issueDataSetReadingError( prodIdDD,errno );

         else if(feof(prodIdFile)) /* Handle EOF                     */
            moreRecords = No;
                                       /* Discard bytes 73-80 and    */
         else                          /* strip off trailing blanks  */
           { strncat( productId,prodIdRec,72 );
             trimLeadingBlanks( productId );
             trimTrailingBlanks( productId );
           }
                                       /* Don't overfill return area */
         if( rc < RETSEV && strlen(productId) > 10 )
           issueInvalidDataLengthError( "PRODID",1,10 );
       }

     if( rc < RETSEV )
       { *productIdLen = strlen(productId);
         if( fclose( prodIdFile ) != 0 )
           issueDataSetClosingError( prodIdDD,errno );
       }

   } /* end of readProductId */


 void getProductDescriptionRecord      /* Fetch product descr record */
   ( void
   )
   /*******************************************************************
   * Gets the product description record to be updated                *
   *******************************************************************/
   { EXEC SQL                          /* Fetch DESCRIPTION record  */
       SELECT DESCRIPTION              /* for requested product id  */
         INTO :PRODUCT.DESCRIPTION
         FROM PRODUCT
        WHERE PID = :PRODUCT.PID;

     if( SQLCODE != 0 )                /* Report error, if any       */
       issueSqlError( "DSN8EDXU: Error selecting from PRODUCT table" );
   }


 void displayProductDescriptionRecord
   ( void
   )
   /*******************************************************************
   * Shows the selected product description record                    *
   *******************************************************************/
   { int             i;                /* for array indexing         */
     char            *tokPtr;          /* string ptr for token parser*/

     workBufPtr = &workBuffer.data[0];

     tokPtr = getToken( PRODUCT.DESCRIPTION.data,
                        "<product ",
                        No,
                        NULL );
     if( tokPtr == NULL )
       { printf("Error Parsing product XML Could not find product\n");
         rc = RETERR;
       }
     else
       { tokPtr = getToken( tokPtr,
                            "<description>",
                            Yes,
                            workBufPtr );

         if( tokPtr == NULL )
           { printf("Error Parsing product XML "
                    "Could not find description\n");
             rc = RETERR;
           }
         else
           { trimLeadingBlanks( workBufPtr );
             trimTrailingBlanks( workBufPtr );
             prodDesc.productElement = workBufPtr;
             workBufPtr = workBufPtr + strlen(workBufPtr) + 1;
           }
       }

     /*****************************************************************
     * Parse out each element in the <description>. Data looks like:  *
     * <elem-1>data-1</elem-1>...<elem-n>data-n</elem-n></description>*
     *****************************************************************/
     for( i=0; i < 10 && rc == RETNRM && tokPtr != NULL; i++ )
       { tokPtr = getToken( tokPtr,"<",No,NULL );
         if( tokPtr != NULL )
           { tokPtr = getToken( tokPtr,
                                ">",
                                Yes,
                                workBufPtr );
           }
         if( tokPtr != NULL )
           { if( !strcmp( workBufPtr,"/description"))
               tokPtr = NULL;
             else
               { prodDesc.itemList[i].element = workBufPtr;
                 workBufPtr = workBufPtr + strlen(workBufPtr) + 1;
               }
           }
         if( tokPtr != NULL )
           { tokPtr = getToken( tokPtr,
                                "<",
                                Yes,
                                workBufPtr );
           }
         if( tokPtr != NULL )
           { prodDesc.itemList[i].value = workBufPtr;
             workBufPtr = workBufPtr + strlen(workBufPtr) + 1;
             prodDesc.itemList[i].allocated = No;
           }
       }
     prodDesc.elements = --i;

     printf( "<product %s\n  <description>\n",
             prodDesc.productElement );
     for( i=0; i < prodDesc.elements; i++ )
       { printf( "    <%s>%s</%s>\n",
                 prodDesc.itemList[i].element,
                 prodDesc.itemList[i].value,
                 prodDesc.itemList[i].element );
       }
     printf( "  </description>\n" );
     printf( "</product>\n" );

   } /* end of displayProductDescriptionRecord */


 void readProductDescriptionUpdateRequest
   ( char            *request          /* -out: update request text  */
   )
   /*******************************************************************
   * Reads a product description update request from the DESCUPDT DD  *
   *******************************************************************/
   { FILE           *descUpFile;       /* Ptr to DESCUPDT DD         */
     char           descUpDD[12];      /* DD handle                  */
     char           descUpRec[80];     /* DESCUPDT file input record */
     short int      recordLength  = 0; /* Length of record           */
     unsigned short moreRecords = Yes; /* EOF indicator              */

     strcpy( descUpDD,"DD:DESCUPDT" );

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

     if( rc < RETSEV )
       { recordLength
           = fread( descUpRec,         /* Read into DESCUPDT rec area*/
                    1,                 /* ..1 record                 */
                    80,                /* ..of 80 bytes              */
                    descUpFile );      /* ..from DESCUPDT file       */

         if( ferror(descUpFile) )      /* Handle IO errors           */
            issueDataSetReadingError( descUpDD,errno );

         else if(feof(descUpFile)) /* Handle EOF                     */
            moreRecords = No;
                                       /* Discard bytes 73-80 and    */
         else                          /* strip off trailing blanks  */
           { strncat( request,descUpRec,72 );
             trimLeadingBlanks( request );
             trimTrailingBlanks( request );
           }
                                       /* Don't overfill return area */
         if( rc < RETSEV && strlen(request) > 72 )
           issueInvalidDataLengthError( "DESCUPDT",1,72 );
       }

     if( rc < RETSEV )
       { if( fclose( descUpFile ) != 0 )
           issueDataSetClosingError( descUpDD,errno );
       }
   } /* end of readProductDescriptionUpdateRequest */


 void updateProductDescription
   ( char            *request          /* -in: update request text   */
   )
   /*******************************************************************
   * Applies a requested update to the product description record     *
   *******************************************************************/
   { int             i;
     char            *tokPtr;          /* string ptr for token parser*/
     char            editElement[101]; /*                            */
     char            editValue[101];   /*                            */
     unsigned short  matched = No;     /*                            */


     if( request[0] == '<' )              /* If first byte is '<'    */
       { request++;                       /* ..skip over it          */
         tokPtr = strtok( request,">" );  /* ..parse to next '>'     */
       }
     else                                 /* If first byte is not '<'*/
       { tokPtr = strtok( request,"<" );  /* ..parse to next '<'     */
         tokPtr = strtok( NULL,">" );     /* ..parse to next '>'     */
       }
     strcpy( editElement,tokPtr );        /* ..copy over element name*/
     tokPtr = strtok( NULL,"<" );         /* ..parse to next '<'     */
     strcpy( editValue,tokPtr );          /* ..copy over element data*/
     tokPtr = NULL;                       /* .. then all done        */

     for( i=0; i<prodDesc.elements && matched == No; i++ )
       if( strcmp(prodDesc.itemList[i].element,editElement) == 0 )
         { matched = Yes;
           strcpy(workBufPtr,editValue);
           prodDesc.itemList[i].value = workBufPtr;
         }
     if( matched == No )
       { printf( "ERROR: Requested update element, <%s>, not found\n",
         editElement );
         printf( "-----> Processing halted\n" );
         rc = RETSEV;
       }

     if( rc < RETSEV )
       { memset( PRODUCT.DESCRIPTION.data,
                 NULLCHAR,
                 sizeof(PRODUCT.DESCRIPTION.data) );

         strcpy( PRODUCT.DESCRIPTION.data,"<product " );
         strcat( PRODUCT.DESCRIPTION.data,prodDesc.productElement );
         strcat( PRODUCT.DESCRIPTION.data,"<description>" );

         for( i=0; i < prodDesc.elements; i++ )
           { strcat( PRODUCT.DESCRIPTION.data,"<" );
             strcat( PRODUCT.DESCRIPTION.data,
                     prodDesc.itemList[i].element );
             strcat( PRODUCT.DESCRIPTION.data,">" );
             strcat( PRODUCT.DESCRIPTION.data,
                     prodDesc.itemList[i].value );
             strcat( PRODUCT.DESCRIPTION.data,"</" );
             strcat( PRODUCT.DESCRIPTION.data,
                     prodDesc.itemList[i].element );
             strcat( PRODUCT.DESCRIPTION.data,">" );
           }
         strcat( PRODUCT.DESCRIPTION.data,"</description>" );
         strcat( PRODUCT.DESCRIPTION.data,"</product>" );

         PRODUCT.DESCRIPTION.length = strlen(PRODUCT.DESCRIPTION.data);
       }

     if( rc < RETSEV )
       { EXEC SQL
           UPDATE PRODUCT
              SET DESCRIPTION = :PRODUCT.DESCRIPTION
            WHERE PID = :PRODUCT.PID;

         if( SQLCODE != 0 )            /* Report error, if any       */
           issueSqlError( "DSN8EDXU: Error "
                          "performing UPDATE" );
       }

   } /* end of updateProductDescription */


 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 issueInvalidDataLengthError      /* Handler for data len error */
   ( char            *DdName,          /* - in: identify of DD       */
     int             minLength,        /* - in: min valid length     */
     unsigned long   maxLength         /* - in: max valid length     */
   )
   /*******************************************************************
   * Called when the length of data read from a DSN8EDXU input file   *
   * (identified by DdName) does not fall within the valid bounds for *
   * size (minLength and maxLength).                                  *
   *******************************************************************/
   { printf( "ERROR: The length of the data read for read from the %s "
                    "DD \n",DdName );
     printf( "       does not fall within the required bounds of %i "
                    "and %u\n",minLength,maxLength );
     printf( "-----> Processing halted\n" );
     rc = RETSEV;
   } /* end of issueInvalidDataLengthError */


 #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 trimLeadingBlanks                /* Strip off leading blanks   */
   ( char            *string           /* - in: string to be trimmed */
   )
   /*******************************************************************
   * Strips leading blanks from a string                              *
   *******************************************************************/
   { int             i;
     char           *p;
     for( i = 0; i < strlen(string) && string[i] == ' '; i++ );
     p = &string[i];
     strcpy( string,p );
   } /* end of trimLeadingBlanks */


 void 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';
   } /* end of trimTrailingBlanks */


 char *getToken                        /* Gets token from a string   */
   ( char            *tokPtrR,         /* -in: Ptr to start of token */
     char            *string,          /* -in: String to break on    */
     unsigned short  returnToken,      /* -in: token suppression     */
     char            *token            /* -out: Token                */
   )
   /*******************************************************************
   * Locates string 'string' in source string pointed to by 'tokPtrR'.*
   * Places token in 'token' if 'returntoken' is Yes on function call.*
   * Returns pointer past location of 'string' if 'string' found,     *
   * otherwise null.                                                  *
   *******************************************************************/
   { char    *tokPtrL = tokPtrR;
     int     tokLen;

     tokPtrR = strstr( tokPtrL,string );
     if( tokPtrR == NULLCHAR )
       return NULL;
     else
       { if( returnToken == Yes )
         { tokLen = tokPtrR-tokPtrL;
             strncpy( token,tokPtrL,tokLen );
             token[tokLen] = '\0';
           }
         tokPtrR = tokPtrR + strlen(string);
         return tokPtrR;
       }
   }