DSN8DLRV

Prompts the user to choose an employee, then retrieves the resume data for that employee from the RESUME (CLOB) column of the EMP_PHOTO_RESUME table into a CLOB locator, uses LOB locator-handling functions to locate and break out data elements, and puts them in fields for display by ISPF.

 /*********************************************************************
 * Module name = DSN8DLRV (DB2 sample program)                        *
 *                                                                    *
 * DESCRIPTIVE NAME = Display the resume of a specified employee      *
 *                                                                    *
 *                                                                    *
 *  LICENSED MATERIALS - PROPERTY OF IBM                              *
 *  5675-DB2                                                          *
 *  (C) COPYRIGHT 1982, 2000 IBM CORP.  ALL RIGHTS RESERVED.          *
 *                                                                    *
 *  STATUS = VERSION 7                                                *
 *                                                                    *
 * Function: Prompts the user to choose an employee, then retrieves   *
 *           the resume data for that employee from the RESUME (CLOB) *
 *           column of the EMP_PHOTO_RESUME table into a CLOB locator,*
 *           uses LOB locator-handling functions to locate and break  *
 *           out data elements, and puts them in fields for display   *
 *           by ISPF.                                                 *
 *                                                                    *
 * Notes:                                                             *
 *   Dependencies: Requires IBM C/C++ for OS/390 V1R3 or higher       *
 *                                                                    *
 *   Restrictions:                                                    *
 *                                                                    *
 * Module type: C program                                             *
 *   Processor: IBM C/C++ for OS/390 V1R3 or subsequent release       *
 * Module size: See linkedit output                                   *
 *  Attributes: Re-entrant and re-usable                              *
 *                                                                    *
 * Entry Point: CEESTART (Language Environment entry point)           *
 *     Purpose: See Function                                          *
 *     Linkage: Standard MVS program invocation, no parameters        *
 *                                                                    *
 * Normal Exit: Return Code = 0000                                    *
 *              - Message: none                                       *
 *                                                                    *
 *  Error Exit: Return Code = 0008                                    *
 *              - Message: *** ERROR: DSN8DLRV DB2 Sample Program     *
 *                                    Unexpected SQLCODE encountered  *
 *                                    at location xxx                 *
 *                                    Error detailed below            *
 *                                    Processing terminated           *
 *                                    (DSNTIAR-formatted message here)*
 *                                                                    *
 *              - Message: *** ERROR: DSN8DLRV DB2 Sample Program     *
 *                                    No entry in the Employee Photo/ *
 *                                    Resume table for employee with  *
 *                                    empno = xxxxxx                  *
 *                                    Processing terminated           *
 *                                                                    *
 *              - Message: *** ERROR: DSN8DLRV DB2 Sample Program     *
 *                                    No resume data exists in        *
 *                                    the Employee Photo/Resume table *
 *                                    for the employee with empno =   *
 *                                    xxxxxx.                         *
 *                                    Processing terminated           *
 *                                                                    *
 *                                                                    *
 *    External References:                                            *
 *             - Routines/Services: DSNTIAR, ISPF                     *
 *             - Data areas       : DSNTIAR error_message             *
 *             - Control blocks   : None                              *
 *                                                                    *
 *                                                                    *
 *  Pseudocode:                                                       *
 *   DSN8DLRV:                                                        *
 *   - Call initISPFvars to establish ISPF variable sharing           *
 *   - Do until the user indicates termination                        *
 *     - Call clearISPFvars to reset the ISPF shared variables        *
 *     - Call getEmplNum to request an employee id                    *
 *     - Call getEmplResume to retrieve the resume                    *
 *     - Call formatEmplResume to populate the ISPF display panel     *
 *     - Call showEmplResume to display the resume                    *
 *   - Call freeISPFvars to terminate ISPF variable sharing           *
 *   End DSN8DLRV                                                     *
 *                                                                    *
 *   initISPFvars:                                                    *
 *   - Establish ISPF variable sharing                                *
 *   End initISPFvars                                                 *
 *                                                                    *
 *   clearISPFvars:                                                   *
 *   - Set ISPF vars to blank if character type or 0 if numeric       *
 *   End clearISPFvars                                                *
 *                                                                    *
 *   getEmplNum:                                                      *
 *   - prompt user to select an employee whose resume is to be viewed *
 *   End getEmplNum                                                   *
 *                                                                    *
 *   getEmplResume:                                                   *
 *   - Fetch the specified employee's resume from DB2 using a CLOB    *
 *     locator                                                        *
 *   End getEmplResume                                                *
 *                                                                    *
 *   formatEmplResume:                                                *
 *   - call getPersonalData to extract personal data from the resume  *
 *   - call getDepartmentData to extract department data              *
 *   - call getEducationData to extract education data                *
 *   - call getWorkHistoryData to extract work history data           *
 *   End formatEmplResume                                             *
 *                                                                    *
 *   showEmplResume:                                                  *
 *   - Display the ISPF panel with the specified employee's resume    *
 *   End showEmplResume                                               *
 *                                                                    *
 *   freeISPFvars:                                                    *
 *   - Terminate variable sharing with ISPF                           *
 *   End freeISPFvars                                                 *
 *                                                                    *
 *   getPersonalData:                                                 *
 *   - Parse the employee's name, address, home telephone no.,        *
 *     birthdate, sex, marital status, height, and weight into ISPF   *
 *     display variables                                              *
 *   End getPersonalData                                              *
 *                                                                    *
 *   getDepartmentData:                                               *
 *   - Parse the employee's department number, manager, job position, *
 *     work telephone no., and hire date into ISPF display variables. *
 *   End getDepartmentData                                            *
 *                                                                    *
 *   getEducationData:                                                *
 *   - Parse the employee's degree dates, descriptions, and schools   *
 *     into ISPF display variables.                                   *
 *   End getEducationData                                             *
 *                                                                    *
 *   getWorkHistoryData:                                              *
 *   - Parse the employee's job dates, titles, and descriptions into  *
 *     ISPF display variables.                                        *
 *   End getWorkHistoryData                                           *
 *                                                                    *
 *   sql_error:                                                       *
 *   - call DSNTIAR to format an unexpected SQLCODE.                  *
 *   End sql_error                                                    *
 *                                                                    *
 **********************************************************************
 * Assumptions:                                                       *
 * (1) Each employee has exactly 2 entries under "Education"          *
 * (2) Each employee has exactly 3 entries under "Work History"       *
 * (3) Each job description consists of a single sentence and that    *
 *     sentence ends with a period and that period is the only        *
 *     period in the sentence.                                        *
 *********************************************************************/

 /******************* C Program Product Libraries ********************/
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>


 /***************************** Equates ******************************/
 #define     NO                  0     /* False                      */
 #define     YES                 1     /* True                       */

 #define     NOT_OK              0     /* Run status indicator: Error*/
 #define     OK                  1     /* Run status indicator: Good */

 #define     TIAR_DIM           10     /* Max no. of DSNTIAR msgs    */
 #define     TIAR_LEN           80     /* Length of DSNTIAR messages */


 /************************** Global Storage **************************/
 int         keepViewing     = YES;    /* User status                */
 int         status          = OK;     /* Run status                 */

 short int   ISPFrc;                   /* For ISPF return code       */


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


 /********************** DB2 Message Formatter ***********************/
 struct      error_struct {            /* DSNTIAR message structure  */
   short int   error_len;
   char        error_text[TIAR_DIM][TIAR_LEN];
   }         error_message = {TIAR_DIM * (TIAR_LEN)};

 #pragma linkage(dsntiar, OS)

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


 /**************************** DB2 Tables ****************************/
 EXEC SQL DECLARE  EMP_PHOTO_RESUME  TABLE
   (        EMPNO  CHAR(06)     NOT NULL,
        EMP_ROWID  ROWID,
       PSEG_PHOTO  BLOB( 500K ),
        BMP_PHOTO  BLOB( 100K ),
           RESUME  CLOB(   5K )         );


 /************** DB2 Host and Null Indicator Variables ***************/
 EXEC SQL BEGIN DECLARE SECTION;
   char        hvEMPNO[7];             /* host var for emp ser no.   */

   long int    begSection;             /* ptr to beg of resume sec'n */
   char        *begField;              /* ptr to beg of fld in sec'n */
   long int    endSection;             /* ptr to end of resume sec'n */
   char        *endField;              /* ptr to end of fld in sec'n */

   SQL TYPE IS CLOB(5K) hvRESUME;      /* host var for RESUME CLOB   */
   char        *phvRESUME;             /* ptr to RESUME CLOB data    */
   short int   niRESUME = 0;           /* indic var for RESUME CLOB  */
 EXEC SQL END DECLARE SECTION;


 /******************** DB2 LOB Locator Variables *********************/
 EXEC SQL BEGIN DECLARE SECTION;
   SQL TYPE IS CLOB_LOCATOR clRESUME;  /* CLOB loc for RESUME column */
 EXEC SQL END DECLARE SECTION;


 /*************************** ISPF Linkage ***************************/
 #pragma linkage(isplink,OS)


 /*************************** ISPF Syntax ****************************/
 char        CHAR[9]      = "CHAR    ";
 char        DISPLAY[9]   = "DISPLAY ";
 char        VDEFINE[9]   = "VDEFINE ";
 char        VGET[9]      = "VGET    ";
 char        VRESET[9]    = "VRESET  ";


 /********************** ISPF Shared Variables ***********************/
 char        D8EMNAME[25];             /* employee's name            */
 char        D8EMNUMB[7];              /* employee's serial number   */
 char        D8EMADR1[25];             /* employee's address line 1  */
 char        D8EMDEPT[5];              /* employee's department      */
 char        D8EMADR2[25];             /* employee's address line 2  */
 char        D8MGRNAM[22];             /* employee's manager's name  */
 char        D8EMADR3[15];             /* employee's address line 3  */
 char        D8EMPOSN[22];             /* employee's job position    */
 char        D8EMBORN[19];             /* employee's date of birth   */
 char        D8EMPHON[15];             /* employee's home phone no.  */
 char        D8EMSEX[7];               /* employee's gender          */
 char        D8EMHIRE[11];             /* employee's hire date       */
 char        D8EMHGT[6];               /* employee's height          */
 char        D8EMWGT[9];               /* employee's weight          */
 char        D8EMPMST[9];              /* employee's marital status  */
 char        D8EMEDY1[5];              /* date of most recent degree */
 char        D8EMEDD1[35];             /* type of most recent degree */
 char        D8EMEDY2[5];              /* date of previous degree    */
 char        D8EMEDD2[35];             /* type of previous degree    */
 char        D8EMEDI1[35];             /* name of most recent school */
 char        D8EMEDI2[35];             /* name of previous school    */
 char        D8EMWHD1[17];             /* dates of 1st previous job  */
 char        D8EMWHJ1[63];             /* title of 1st previous job  */
 char        D8EMWHT1[63];             /* descr. of 1st previous job */
 char        D8EMWHD2[17];             /* dates of 2nd previous job  */
 char        D8EMWHJ2[63];             /* title of 2nd previous job  */
 char        D8EMWHT2[63];             /* descr. of 2nd previous job */
 char        D8EMWHD3[17];             /* dates of 3rd previous job  */
 char        D8EMWHJ3[63];             /* title of 3rd previous job  */
 char        D8EMWHT3[63];             /* descr. of 3rd previous job */


 /************************* Global Functions *************************/
 int  main( void );                    /* main logic                 */
 void initISPFvars( void );            /* establish ISPF vars        */
 void clearISPFvars( void );           /* blank/zero ISPF disp vars  */
 void getEmplNum( void );              /* prompt for employee ser no */
 void getEmplResume( void );           /* get resume from database   */
 void formatEmplResume( void );        /* build display panel        */
 void getPersonalData( void );         /* get personal data from res */
 void getDepartmentData( void );       /* get dept data from resume  */
 void getEducationData( void );        /* get educ data from resume  */
 void getWorkHistoryData( void );      /* get job hist from resume   */
 void showEmplResume( void );          /* display the ISPF panel     */
 void freeISPFvars( void );            /* drop ISPF vars             */
 void sql_error( char *locmsg );       /* generate SQL messages      */


 /*********************************************************************
 **************************** main routine ****************************
 *********************************************************************/
 int main( void )
 {
   /*******************************************************************
   * Establish variable sharing with ISPF                             *
   *******************************************************************/
   initISPFvars();

   /*******************************************************************
   * Display employee resumes until user indicates completion         *
   *******************************************************************/
   keepViewing = YES;
   while( keepViewing == YES )
     {
       clearISPFvars();
       /***************************************************************
       * prompt user to select employee whose resume is to be viewed  *
       ***************************************************************/
       getEmplNum();

       if( keepViewing == YES  &&  status == OK )
         {
           /***********************************************************
           * retrieve the employee's resume from DB2                  *
           ***********************************************************/
           getEmplResume();
           /***********************************************************
           * if successful, format the resume on ISPF                 *
           ***********************************************************/
           if( status == OK )
             formatEmplResume();
           /***********************************************************
           * if successful, display the resume on ISPF                *
           ***********************************************************/
           if( status == OK )
             showEmplResume();
           /***********************************************************
           * otherwise, exit this program                             *
           ***********************************************************/
           else
             keepViewing = NO;
         }
     }

   /*******************************************************************
   * Terminate variable sharing with ISPF                             *
   *******************************************************************/
   freeISPFvars();

 } /* end main */


 void initISPFvars( void )
 /*********************************************************************
 * Called by the main routine. Establishes variable sharing between   *
 * ISPF and this program.                                             *
 *********************************************************************/
 {
   ISPFrc = isplink( VDEFINE, "D8EMNAME", D8EMNAME, CHAR, 24 );
   ISPFrc = isplink( VDEFINE, "D8EMNUMB", D8EMNUMB, CHAR, 6 );
   ISPFrc = isplink( VDEFINE, "D8EMADR1", D8EMADR1, CHAR, 24 );
   ISPFrc = isplink( VDEFINE, "D8EMDEPT", D8EMDEPT, CHAR, 4 );
   ISPFrc = isplink( VDEFINE, "D8EMADR2", D8EMADR2, CHAR, 24 );
   ISPFrc = isplink( VDEFINE, "D8MGRNAM", D8MGRNAM, CHAR, 21 );
   ISPFrc = isplink( VDEFINE, "D8EMADR3", D8EMADR3, CHAR, 14 );
   ISPFrc = isplink( VDEFINE, "D8EMPOSN", D8EMPOSN, CHAR, 21 );
   ISPFrc = isplink( VDEFINE, "D8EMBORN", D8EMBORN, CHAR, 18 );
   ISPFrc = isplink( VDEFINE, "D8EMPHON", D8EMPHON, CHAR, 14 );
   ISPFrc = isplink( VDEFINE, "D8EMSEX ", D8EMSEX , CHAR, 6 );
   ISPFrc = isplink( VDEFINE, "D8EMHIRE", D8EMHIRE, CHAR, 10 );
   ISPFrc = isplink( VDEFINE, "D8EMHGT ", D8EMHGT , CHAR, 5 );
   ISPFrc = isplink( VDEFINE, "D8EMWGT ", D8EMWGT , CHAR, 8 );
   ISPFrc = isplink( VDEFINE, "D8EMPMST", D8EMPMST, CHAR, 8 );
   ISPFrc = isplink( VDEFINE, "D8EMEDY1", D8EMEDY1, CHAR, 4 );
   ISPFrc = isplink( VDEFINE, "D8EMEDD1", D8EMEDD1, CHAR, 34 );
   ISPFrc = isplink( VDEFINE, "D8EMEDY2", D8EMEDY2, CHAR, 4 );
   ISPFrc = isplink( VDEFINE, "D8EMEDD2", D8EMEDD2, CHAR, 34 );
   ISPFrc = isplink( VDEFINE, "D8EMEDI1", D8EMEDI1, CHAR, 34 );
   ISPFrc = isplink( VDEFINE, "D8EMEDI2", D8EMEDI2, CHAR, 34 );
   ISPFrc = isplink( VDEFINE, "D8EMWHD1", D8EMWHD1, CHAR, 16 );
   ISPFrc = isplink( VDEFINE, "D8EMWHJ1", D8EMWHJ1, CHAR, 62 );
   ISPFrc = isplink( VDEFINE, "D8EMWHT1", D8EMWHT1, CHAR, 62 );
   ISPFrc = isplink( VDEFINE, "D8EMWHD2", D8EMWHD2, CHAR, 16 );
   ISPFrc = isplink( VDEFINE, "D8EMWHJ2", D8EMWHJ2, CHAR, 62 );
   ISPFrc = isplink( VDEFINE, "D8EMWHT2", D8EMWHT2, CHAR, 62 );
   ISPFrc = isplink( VDEFINE, "D8EMWHD3", D8EMWHD3, CHAR, 16 );
   ISPFrc = isplink( VDEFINE, "D8EMWHJ3", D8EMWHJ3, CHAR, 62 );
   ISPFrc = isplink( VDEFINE, "D8EMWHT3", D8EMWHT3, CHAR, 62 );
 } /* end initISPFvars */


 void clearISPFvars( void )
 /*********************************************************************
 * Called by the main routine. Blanks out the ISPF shared variables.  *
 *********************************************************************/
 {
   memset( D8EMNAME, 0, 25 );
   memset( D8EMNUMB, 0, 7 );
   memset( D8EMADR1, 0, 25 );
   memset( D8EMDEPT, 0, 5 );
   memset( D8EMADR2, 0, 25 );
   memset( D8MGRNAM, 0, 22 );
   memset( D8EMADR3, 0, 15 );
   memset( D8EMPOSN, 0, 22 );
   memset( D8EMBORN, 0, 19 );
   memset( D8EMPHON, 0, 15 );
   memset( D8EMSEX , 0, 7 );
   memset( D8EMHIRE, 0, 11 );
   memset( D8EMHGT , 0, 9 );
   memset( D8EMWGT , 0, 8 );
   memset( D8EMPMST, 0, 9 );
   memset( D8EMEDY1, 0, 5 );
   memset( D8EMEDD1, 0, 35 );
   memset( D8EMEDY2, 0, 5 );
   memset( D8EMEDD2, 0, 35 );
   memset( D8EMEDI1, 0, 35 );
   memset( D8EMEDI2, 0, 35 );
   memset( D8EMWHD1, 0, 17 );
   memset( D8EMWHJ1, 0, 63 );
   memset( D8EMWHT1, 0, 63 );
   memset( D8EMWHD2, 0, 17 );
   memset( D8EMWHJ2, 0, 63 );
   memset( D8EMWHT2, 0, 63 );
   memset( D8EMWHD3, 0, 17 );
   memset( D8EMWHJ3, 0, 63 );
   memset( D8EMWHT3, 0, 63 );
 } /* end clearISPFvars */


 void getEmplNum( void )
 /*********************************************************************
 * Called by the main routine.  Displays an ISPF panels to prompt the *
 * user to select an employee whose resume is to be displayed.        *
 *********************************************************************/
 {
   /*******************************************************************
   * Display the prompt panel                                         *
   *******************************************************************/
   ISPFrc = isplink( "DISPLAY ","DSN8SSE " );
   if( ISPFrc != 0 )
     keepViewing = NO;

   /*******************************************************************
   * Save off the value of the ISPF shared variable                   *
   *******************************************************************/
   strcpy( hvEMPNO,D8EMNUMB );

 } /* end getEmplNum */


 void getEmplResume( void )
 /*********************************************************************
 * Called by the main routine.  Extracts a specified employee's       *
 * resume data from a CLOB column in the sample EMP_PHOTO_RESUME      *
 * table to a CLOB locator.                                           *
 *********************************************************************/
 {
   /*******************************************************************
   * Establish a CLOB locator on the resume of the specified empno    *
   *******************************************************************/
   EXEC SQL SELECT  RESUME
              INTO :clRESUME
              FROM  EMP_PHOTO_RESUME
             WHERE  EMPNO = :hvEMPNO;

   if( SQLCODE == 100 )
     {
       status = NOT_OK;
       printf( "*************************************************\n" );
       printf( "*** ERROR: DSN8DLRV DB2 Sample Program\n"            );
       printf( "***        No entry in the Employee Photo/Resume\n"  );
       printf( "***        table for employee with empno = %s\n",
                           hvEMPNO                                   );
       printf( "***        Processing terminated\n"                  );
       printf( "*************************************************\n" );
     }
   else if( SQLCODE == -305 )
     {
       status = NOT_OK;
       printf( "*************************************************\n" );
       printf( "*** ERROR: DSN8DLRV DB2 Sample Program\n"            );
       printf( "***        No resume data exists in the\n"           );
       printf( "***        Employee Photo/Resume table for the\n"    );
       printf( "***        employee with empno = %s\n",
                           hvEMPNO                                   );
       printf( "***        Processing terminated\n"                  );
       printf( "*************************************************\n" );
     }
   else if( SQLCODE != 0 )
     {
       status = NOT_OK;
       sql_error( "getEmplResume @ SELECT" );
     }

 } /* end getEmplResume */


 void formatEmplResume( void )
 /*********************************************************************
 * Called by the main routine.  Calls routines to parse out the       *
 * contents of the resume into ISPF-shared variables.                 *
 *********************************************************************/
 {
   /*******************************************************************
   * Get the employee's name, address, and other personal information *
   *******************************************************************/
   getPersonalData();

   /*******************************************************************
   * Get the employee's department no., manager, and other dept data  *
   *******************************************************************/
   if( status == OK )
     getDepartmentData();

   /*******************************************************************
   * Get the employee's education data                                *
   *******************************************************************/
   if( status == OK )
     getEducationData();

   /*******************************************************************
   * Get the employee's employment history                            *
   *******************************************************************/
   if( status == OK )
     getWorkHistoryData();

   /*******************************************************************
   * Free the CLOB locator for the resume                             *
   *******************************************************************/
   if( status == OK )
     {
       EXEC SQL FREE LOCATOR :clRESUME;
       if( SQLCODE != 0 )
         {
           status = NOT_OK;
           sql_error( "formatEmplResume @ FREE LOCATOR" );
         }
     }

 } /* end formatEmplResume */


 void getPersonalData( void )
 /*********************************************************************
 * Called by the formatEmplResume routine to parse the CLOB locator   *
 * data for the employee's name, address, home telephone no., birth-  *
 * date, sex, marital status, height, and weight into ISPF variables. *
 *********************************************************************/
 {
   /*******************************************************************
   * Extract the Personal Data section from the CLOB locator          *
   *******************************************************************/
   EXEC SQL SET :begSection            /* locate start of pers. data */
            = POSSTR( :clRESUME, '    Resume:  ' );
   if( SQLCODE != 0 )
     {
       status = NOT_OK;
       sql_error( "getPersonalData @ POSSTR 1" );
     }
   if( status == OK )
     {
       EXEC SQL SET :endSection        /* locate start of dept. data */
            = POSSTR( :clRESUME, '    Department Information   ' );
       if( SQLCODE != 0 )
         {
           status = NOT_OK;
           sql_error( "getPersonalData @ POSSTR 2" );
         }
     }
   if( status == OK )
     {
       EXEC SQL SET :hvRESUME          /* extract what's in between  */
            = SUBSTR( :clRESUME, :begSection, :endSection-:begSection );
       if( SQLCODE == 0 )
         hvRESUME.data[hvRESUME.length] = '\0';
       else
         {
           status = NOT_OK;
           sql_error( "getPersonalData @ SUBSTR" );
         }
     }
   /*******************************************************************
   * Get the employee's name                                          *
   *******************************************************************/
   if( status == OK )
     {
       phvRESUME = &hvRESUME.data[0];  /* set pointer to the data    */
       begField                        /* find Resume:  label        */
          = strstr( phvRESUME,"  Resume: " );
       begField = begField + 11;       /* skip past label            */
       endField                        /* find Personal Inf... label */
          = strstr( phvRESUME,"    Personal Information   " );
       strncpy( D8EMNAME,              /* get name from in between   */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get the employee's street address                                *
   *******************************************************************/
   if( status == OK )
     {
       begField                        /* find Address:  label       */
          = strstr( phvRESUME,"  Address:            " );
       begField = begField + 22;       /* skip past label            */
       endField                        /* find end of street addr    */
          = strstr( phvRESUME,"                      " );
       strncpy( D8EMADR1,              /* get addr from in between   */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get the employee's city, state, and zipcode                      *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 22;       /* set loc to city/st/zip dat */
       endField                        /* find end of ciy/st/zip     */
          = strstr( phvRESUME,"  Phone:              " );
       strncpy( D8EMADR2,              /* get data from in between   */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get the employee's home telephone number                         *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 22;       /* set loc to home phone data */
       endField                        /* find end of home phone no. */
          = strstr( phvRESUME,"  Birthdate:          " );
       strncpy( D8EMADR3,              /* get phone# from in between */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get the employee's birthdate                                     *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 22;       /* set loc to birthdate data  */
       endField                        /* find end of birthdate data */
          = strstr( phvRESUME,"  Sex:                " );
       strncpy( D8EMBORN,              /* get birthdate from in betw */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get the employee's sex                                           *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 22;       /* set loc to sex data        */
       endField                        /* find end of sex data       */
          = strstr( phvRESUME,"  Marital Status:     " );
       strncpy( D8EMSEX,               /* get sex data from in betw  */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get the employee's marital status                                *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 22;       /* set loc to marital status  */
       endField                        /* find end of marital stat.  */
          = strstr( phvRESUME,"  Height:             " );
       strncpy( D8EMPMST,              /* get mar stat from in betw  */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get the employee's height                                        *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 22;       /* set loc to height data     */
       endField                        /* find end of height data    */
          = strstr( phvRESUME,"  Weight:             " );
       strncpy( D8EMHGT,               /* get height from in between */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get the employee's weight                                        *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 22;       /* set loc to weight data     */
       strcpy( D8EMWGT,                /* weight is at end of string */
                begField );
     }
 } /* end getPersonalData */


 void getDepartmentData( void )
 /*********************************************************************
 * Called by the formatEmplResume routine to parse the CLOB locator   *
 * data for the employee's department number, manager, job position,  *
 * work telephone no., and hire date into ISPF variables.             *
 *********************************************************************/
 {
   /*******************************************************************
   * Extract the Department Data section from the CLOB locator        *
   *******************************************************************/
   begSection = endSection;            /* Locate start of Dept data  */
   EXEC SQL SET :endSection            /* Locate start of Educ data  */
            = POSSTR( :clRESUME, '    Education   ' );
   if( SQLCODE != 0 )
     {
       status = NOT_OK;
       sql_error( "getDepartmentData @ POSSTR" );
     }
   if( status == OK )
     {
       EXEC SQL SET :hvRESUME          /* extract what's in between  */
            = SUBSTR( :clRESUME, :begSection, :endSection-:begSection );
       if( SQLCODE == 0 )
         hvRESUME.data[hvRESUME.length] = '\0';
       else
         {
           status = NOT_OK;
           sql_error( "getDepartmentData @ SUBSTR" );
         }
     }
   /*******************************************************************
   * Get the employee's department number                             *
   *******************************************************************/
   if( status == OK )
     {
       phvRESUME = &hvRESUME.data[0];  /* set pointer to the data    */
       begField                        /* find Dept Number: label    */
          = strstr( phvRESUME,"  Dept Number:        " );
       begField = begField + 22;       /* skip past label            */
       endField                        /* find end of dept. no.      */
          = strstr( phvRESUME,"  Manager:            " );
       strncpy( D8EMDEPT,              /* get dept# from in between  */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get the employee's manager's name                                *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 22;       /* set loc to manager data    */
       endField                        /* find end of manager        */
          = strstr( phvRESUME,"  Position:           " );
       strncpy( D8MGRNAM,              /* get mgr name from in betw  */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get the employee's job position                                  *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 22;       /* set loc to position data   */
       phvRESUME = begField;           /* skip ahead in buffer       */
       endField                        /* find end of position data  */
          = strstr( phvRESUME,"  Phone:              " );
       strncpy( D8EMPOSN,              /* get position from in betw  */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get the employee's work telephone number                         *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 22;       /* set loc to work phone data */
       endField                        /* find end of work phone no. */
          = strstr( phvRESUME,"  Hire Date:          " );
       strncpy( D8EMPHON,              /* get work ph# from in betw  */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get the employee's hire date                                     *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 22;       /* set loc to hire date data  */
       strcpy( D8EMHIRE,               /* hire data is at end of str */
                begField );
     }
 } /* end getDepartmentData */


 void getEducationData( void )
 /*********************************************************************
 * Called by the formatEmplResume routine to parse the CLOB locator   *
 * data for the employee's degree dates, descriptions, and schools    *
 * into ISPF variables.                                               *
 *********************************************************************/
 {
   /*******************************************************************
   * Extract the Education Data section from the CLOB locator         *
   *******************************************************************/
   begSection = endSection;            /* Locate start of Educ data  */
   EXEC SQL SET :endSection            /* Locate start of Work Hist  */
            = POSSTR( :clRESUME, '    Work History   ' );
   if( SQLCODE != 0 )
     {
       status = NOT_OK;
       sql_error( "getEducationData @ POSSTR" );
     }
   if( status == OK )
     {
       EXEC SQL SET :hvRESUME          /* extract what's in between  */
            = SUBSTR( :clRESUME, :begSection, :endSection-:begSection );
       if( SQLCODE == 0 )
         hvRESUME.data[hvRESUME.length] = '\0';
       else
         {
           status = NOT_OK;
           sql_error( "getEducationData @ SUBSTR" );
         }
     }
   /*******************************************************************
   * Get year and description of employee's most recent degree        *
   *******************************************************************/
   if( status == OK )
     {
       phvRESUME = &hvRESUME.data[0];  /* set pointer to the data    */
       begField                        /* find Education label       */
          = strstr( phvRESUME,"    Education   " );
       begField = begField + 16;       /* skip past label            */
       endField                        /* find end of dept. no.      */
          = strstr( phvRESUME,"                " );
       strncpy( D8EMEDY1,              /* get dept# from in between  */
                begField,
                endField - begField );
       begField = endField + 16;       /* set loc to degree descript */
       endField                        /* find end of deg descr data */
          = strstr( phvRESUME,"                      " );
       strncpy( D8EMEDD1,              /* get deg descr from in betw */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get institution that granted employee's most recent degree       *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 22;       /* set loc to inst name data  */
       phvRESUME = begField;           /* point to beginning         */
       endField                        /* find end of inst name data */
          = strstr( phvRESUME,"   " );
       strncpy( D8EMEDI1,              /* get inst name from in betw */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get year and description of employee's previous degree           *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 3;        /* set loc to grad year data  */
       endField                        /* find end of grad year data */
          = strstr( phvRESUME,"                " );
       strncpy( D8EMEDY2,              /* get hire data from in betw */
                begField,
                endField - begField );
       begField = endField + 16;       /* set loc to degree descript */
       endField                        /* find end of deg descr data */
          = strstr( phvRESUME,"                      " );
       strncpy( D8EMEDD2,              /* get deg descr from in betw */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get institution that granted employee's previous degree          *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 22;       /* set loc to inst name data  */
       phvRESUME = begField;           /* reset starting point       */
       strcpy( D8EMEDI2,               /* inst name is at end of str */
                begField );
     }
 } /* end getEducationData */


 void getWorkHistoryData( void )
 /*********************************************************************
 * Called by the formatEmplResume routine to parse the CLOB locator   *
 * data for the employee's job dates, titles, and descriptions into   *
 * ISPF variables.                                                    *
 *********************************************************************/
 {
   /*******************************************************************
   * Extract the Work History Data section from the CLOB locator      *
   *******************************************************************/
   begSection = endSection;            /* Locate start of Work Hist  */
   EXEC SQL SET :endSection            /* Locate start of Interests  */
            = POSSTR( :clRESUME, '    Interests   ' );
   if( SQLCODE != 0 )
     {
       status = NOT_OK;
       sql_error( "getWorkHistoryData @ POSSTR" );
     }
   if( status == OK )
     {
       EXEC SQL SET :hvRESUME          /* extract what's in between  */
            = SUBSTR( :clRESUME, :begSection, :endSection-:begSection );
       if( SQLCODE == 0 )
         hvRESUME.data[hvRESUME.length] = '\0';
       else
         {
           status = NOT_OK;
           sql_error( "getWorkHistoryData @ SUBSTR" );
         }
     }
   /*******************************************************************
   * Get dates and title of employee's most recent job                *
   *******************************************************************/
   if( status == OK )
     {
       phvRESUME = &hvRESUME.data[0];  /* set pointer to the data    */
       begField                        /* find Work History label    */
          = strstr( phvRESUME,"    Work History   " );
       begField = begField + 19;       /* set loc to job 1 dates     */
       phvRESUME = begField;           /* reset starting point       */
       strncpy( D8EMWHD1,              /* job 1 dates, next 15 bytes */
                begField,
                15 );
       begField = begField + 20;       /* set loc to job 1 title     */
       endField                        /* find end of job 1 title    */
          = strstr( phvRESUME,"                      " );
       strncpy( D8EMWHT1,              /* get job 1 title from betw  */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get description of employee's most recent job                    *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 22;       /* set loc to job 1 descr.    */
       phvRESUME = begField;           /* reset starting point       */
       endField                        /* find end of job 1 descr.   */
          = strstr( phvRESUME,".   " );
       if( endField - begField < 62 )  /* job 1 descr has 1 part     */
           strncpy( D8EMWHJ1,          /* get job 1 descr from betw  */
                    begField,
                    endField - begField );
       else                            /* job 1 descr has 2 parts    */
         {
           endField                    /* find 1st part of job descr */
              = strstr( phvRESUME,"                      " );
           strncpy( D8EMWHJ1,          /* get job 1 descr from betw  */
                    begField,
                    endField - begField );
           begField = endField + 22;   /* set loc to 2nd part job des*/
           endField                    /* find end of job 1 descr.   */
              = strstr( phvRESUME,".   " );
           strncat( D8EMWHJ1,          /* get rest of job 1 descr.   */
                    begField-1,
                    endField - (begField-1) );
         }
     }
   /*******************************************************************
   * Get dates and title of employee's previous job                   *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 4;        /* set loc to job 2 dates     */
       phvRESUME = begField;           /* reset starting point       */
       strncpy( D8EMWHD2,              /* job 2 dates, next 15 bytes */
                begField,
                15 );
       begField = begField + 20;       /* set loc to job 2 title     */
       endField                        /* find end of job 2 title    */
          = strstr( phvRESUME,"                      " );
       strncpy( D8EMWHT2,              /* get job 2 title from betw  */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get description of employee's previous job                       *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 22;       /* set loc to job 2 descr.    */
       phvRESUME = begField;           /* reset starting point       */
       endField                        /* find end of job 2 descr.   */
          = strstr( phvRESUME,".   " );
       if( endField - begField < 62 )  /* job 2 descr has 1 part     */
           strncpy( D8EMWHJ2,          /* get job 2 title from betw  */
                    begField,
                    endField - begField );
       else                            /* job 2 descr has 2 parts    */
         {
           endField                    /* find 1st part of job descr */
              = strstr( phvRESUME,"                      " );
           strncpy( D8EMWHJ2,          /* get job 2 descr from betw  */
                    begField,
                    endField - begField );
           begField = endField + 22;   /* set loc to 2nd part job des*/
           endField                    /* find end of job 2 descr.   */
              = strstr( phvRESUME,".   " );
           strncat( D8EMWHJ2,          /* get rest of job 2 descr.   */
                    begField-1,
                    endField - (begField-1) );
         }
     }
   /*******************************************************************
   * Get dates and title of employee's other previous job             *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 4;        /* set loc to job 3 dates     */
       phvRESUME = begField;           /* reset starting point       */
       strncpy( D8EMWHD3,              /* job 3 dates, next 15 bytes */
                begField,
                15 );
       begField = begField + 20;       /* set loc to job 3 title     */
       endField                        /* find end of job 3 title    */
          = strstr( phvRESUME,"                      " );
       strncpy( D8EMWHT3,              /* get job 3 title from betw  */
                begField,
                endField - begField );
     }
   /*******************************************************************
   * Get description of employee's other previous job                 *
   *******************************************************************/
   if( status == OK )
     {
       begField = endField + 22;       /* set loc to job 3 descr.    */
       phvRESUME = begField;           /* reset starting point       */
       begField = phvRESUME;           /* reset starting point       */
       endField                        /* find end of job 3 descr.   */
          = strstr( phvRESUME,"." );
       if( endField - begField < 62 )  /* job 3 descr has 1 part     */
           strncpy( D8EMWHJ3,          /* get job 3 title from betw  */
                    begField,
                    endField - begField );
       else                            /* job 3 descr has 2 parts    */
         {
           endField                    /* find 1st part of job descr */
              = strstr( phvRESUME,"                      " );
           strncpy( D8EMWHJ3,          /* get job 3 descr from betw  */
                    begField,
                    endField - begField );
           begField = endField + 22;   /* set loc to 2nd part job des*/
           endField                    /* find end of job 3 descr.   */
              = strstr( phvRESUME,".   " );
           strncat( D8EMWHJ3,          /* get rest of job 3 descr.   */
                    begField-1,
                    endField - (begField-1) );
         }
     }
 } /* end getWorkHistoryData */


 void showEmplResume( void )
 /*********************************************************************
 * Called by the main routine.  Displays an ISPF panel that is for-   *
 * matted with the resume data for the employee specified.            *
 *********************************************************************/
 {

   ISPFrc = isplink( "DISPLAY ","DSN8SSR " );

 } /* end showEmplResume */


 void freeISPFvars( void )
 /*********************************************************************
 * Called by the main routine.  Frees the ISPF variables that were    *
 * established for running this application.                          *
 *********************************************************************/
 {

   ISPFrc = isplink( VRESET );

 } /* end freeISPFvars */


 void sql_error( char *locmsg )
 /*********************************************************************
 * SQL error handler                                                  *
 *********************************************************************/
 {
   short int   rc;                     /* DSNTIAR Return code        */
   int         j,k;                    /* Loop control               */
   static int  lrecl = TIAR_LEN;       /* Width of message lines     */

   /*******************************************************************
   * print the location message                                       *
   *******************************************************************/
   printf( "*****************************************************\n" );
   printf( "*** ERROR: DSN8DLRV DB2 Sample Program\n"                );
   printf( "***        Unexpected SQLCODE encountered at location\n" );
   printf( "***         %.68s\n", locmsg                             );
   printf( "***        Error detailed below\n"                       );
   printf( "***        Processing terminated\n"                      );
   printf( "*****************************************************\n" );

   /*******************************************************************
   * format and print the SQL message                                 *
   *******************************************************************/
   rc = dsntiar( &sqlca, &error_message, &lrecl );
   if( rc == 0 )
     for( j=0; j<TIAR_DIM; j++ )
       {
         for( k=0; k<TIAR_LEN; k++ )
           putchar(error_message.error_text[j][k] );
         putchar('\n');
       }
   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" );
     }

 } /* end sql_error */