Example: Diagnostic reporting

This ILE C program produces a diagnostic report of errors that occur when the Send Nonprogram Message (QMHSNDM) API is used to send a message to multiple message queues that do not exist.

The program calls the QMHSNDM API to send a message to message queues that do not exist. The QMHSNDM API returns a generic exception message, CPF2469. This message indicates that the API also returned one or more diagnostic messages describing the errors. After the program receives the exception message and verifies that it is message CPF2469, it uses the QMHCHGEM API to handle the exception message. The QMHRCVPM API is used to receive the diagnostic messages. The program prints the exception message, the diagnostic messages, and the message help.

Note: By using the code examples, you agree to the terms of the Code license and disclaimer information.

Diagnostic Report (DIAGRPT) program

/********************************************************************/
/*                                                                  */
/* MODULE NAME:  DIAGRPT - Diagnostic Report                        */
/* LANGUAGE:     ILE C                                              */
/*                                                                  */
/* FUNCTION:     This module will produce a diagnostic report that  */
/*               could be used in diagnosing the errors that        */
/*               occurred using the QMHSNDM API to send a message   */
/*               to multiple message queues.                        */
/*                                                                  */
/*               This program purposely causes the QMHSNDM API to   */
/*               try to send a message to message queues that do    */
/*               not exist.  As a result, the generic CPF2469       */
/*               exception is returned indicating that one or more  */
/*               diagnostic messages were returned identifying the  */
/*               error(s) on the send operation.                    */
/*                                                                  */
/*               The program looks for and handles the CPF2469      */
/*               exception.  It then receives and prints out the    */
/*               exception and the previous diagnostics.            */
/*                                                                  */
/* Dependency:   A print file must be created before calling        */
/*               program DIAGRPT.  The print file should be created */
/*               using the following command:                       */
/*                                                                  */
/*               CRTPRTF FILE(PRTDIAG) CTLCHAR(*FCFC)               */
/*                       CHLVAL((1 (13)))                           */
/********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <except.h>
#include <qmhchgem.h>                     /* From QSYSINC/H         */
#include <qmhrcvpm.h>                     /* From QSYSINC/H         */
#include <qmhsndm.h>                      /* From QSYSINC/H         */
#include <qusec.h>                        /* From QSYSINC/H         */

#define  DIAG_TYPE "02"
#define  BUF_SIZE  80

/*********************************************************************/
/* Type definition for error code structure                          */
/*********************************************************************/
typedef struct error_code_struct
  {
     Qus_EC_t   ec_fields;
     char       Exception_Data[100];
  } error_code_struct;

/*********************************************************************/
/* Type definition for qualified name structure                      */
/*********************************************************************/
typedef struct qual_name_struct
  {
   char  name[10];
   char  libr[10];
  } qual_name_struct;

/*********************************************************************/
/* Type definition for message information structure used on the     */
/* receive.  F is the fixed portion of the record  and V is the      */
/* variable length portion of the record.                            */
/*********************************************************************/
typedef struct msg_info_struct
  {
   Qmh_Rcvpm_RCVM0200_t   F;
   char                   V[1200];
  } msg_info_struct;

FILE  *prtf;
char  buf[80];
char  received[7];
int   exception_count;


/*********************************************************************/
/* Function to handle errors received on the API calls.              */
/*********************************************************************/
static void excp_handler(_INTRPT_Hndlr_Parms_T *excp_info)
 {
   error_code_struct Error_Code;

   /* If the exception is CPF2469, increment the exception counter,  */
   /* and mark the exception as handled by the QMHCHGEM API         */

   if (strncmp(excp_info->Msg_Id,"CPF2469",7) == 0) {
      memcpy(received,(excp_info->Msg_Id),7);
      exception_count++;
      QMHCHGEM(&(excp_info->Target), 0,
               (char *)(&(excp_info->Msg_Ref_Key)),
               "*HANDLE   ", "", 0, &Error_Code);
   }
 }


/********************************************************************/
/* BuildQList:  Routine to build the message queue list.            */
/********************************************************************/
void BuildQList(  qual_name_struct *QueueList, int NumQueue)
{
  int i;

  strncpy(QueueList[0].name,"QPGMR     ",10);
  strncpy(QueueList[1].name,"SNOOPY    ",10);
  strncpy(QueueList[2].name,"QSECOFR   ",10);
  strncpy(QueueList[3].name,"PEANUTS   ",10);
  strncpy(QueueList[4].name,"QUSER     ",10);

  for (i = 0; i < NumQueue ; i++ )
    {
     strncpy(QueueList[i].libr,"*LIBL     ",10);
    }
}


/********************************************************************/
/* PrintError: Routine to print error information and exit.         */
/********************************************************************/
void PrintError(char *errstring, char exception[7])
{

  memset(buf,' ',BUF_SIZE);
  buf[0] = '0';
  strncpy(buf+1,errstring,strlen(errstring));
  fwrite(buf,1,BUF_SIZE,prtf);

  memset(buf,' ',BUF_SIZE);
  buf[0] = '0';
  strncpy(buf+1,"Exception received->",20);
  strncpy(buf+21,exception,strlen(exception));
  fwrite(buf,1,BUF_SIZE,prtf);
  fclose(prtf);
  exit(1);
 }


/********************************************************************/
/* PrintData: Routine to print varying length character string data.*/
/********************************************************************/
void PrintData(char *strname, void *strptr, int strlgth)
{
  char *strdata = strptr;
  int i,lgth,remain;

  /* Write the description and the data that will fit on one line   */
  memset(buf,' ',BUF_SIZE);
  buf[0] = '0';
  lgth = strlen(strname);
  strncpy(buf+1,strname,lgth);
  lgth++;

  /* remain = MIN(strlgth,80 - lgth)  */
  remain = (strlgth < 80 - lgth) ? strlgth : 80 - lgth;
  strncpy(buf+lgth,strdata,remain);
  fwrite(buf,1,BUF_SIZE,prtf);

  /* Now write the remainder of the data */
  if (strlgth > (80 - lgth ))
    {
     /* Adjust pointer to data not printed yet */
     strdata = strdata + (80 - lgth);

     for (i = 0; i < strlgth; i = i + 70, strdata = strdata + 70 )
       {
        /* lgth = MIN(strlgth-i,70)  */
        lgth = (strlgth-i < 70) ? strlgth-i : 70;

        memset(buf,' ',BUF_SIZE);
        strncpy(buf,"0         ",10);
        memcpy(buf+10,strdata,lgth);
        fwrite(buf,1,BUF_SIZE,prtf);
       }

    }
}


/********************************************************************/
/* PrintMessage: Routine to print the message data and text.        */
/********************************************************************/
void PrintMessage(msg_info_struct *Msg)

{
  char *DataPtr;     /* Pointer to the varying length character data*/
  int  DataLen;      /* Length of the varying length character data */
  char CharType[10]; /* Message type as a string  */

  PrintData("Message ID->",Msg->F.Message_Id,7);
  /* Convert Message Type to a character string to be printed out   */
  if (memcmp(Msg->F.Message_Type,"02",2)==0)
    strncpy(CharType,"DIAGNOSTIC", 10);
  else if (memcmp(Msg->F.Message_Type,"15",2)==0)
    strncpy(CharType,"ESCAPE    ",10);
  PrintData("Message Type->",CharType,10);

  /* First point to the beginning of the message data               */
  /* in the structure and get the length of data returned.          */
  DataPtr = Msg->V;
  DataLen = Msg->F.Length_Data_Returned;
  /* If there is non-blank data, print it out                       */
  if ((DataLen > 0) && (strspn(DataPtr," ") < DataLen))
    PrintData("Message data received->",DataPtr,DataLen);

  /* Point to the beginning of the message text field and get the   */
  /* length of message text returned.                               */
  DataPtr += DataLen;
  DataLen = Msg->F.Length_Message_Returned;
  /* If there is non-blank text, print it out                       */
  if ((DataLen > 0) && (strspn( DataPtr," ") < DataLen))
    PrintData("Message text received->",DataPtr,DataLen);

  /* Now update to point to the beginning of the message            */
  /* help text field and get the length of message help text        */
  /* returned.                                                      */
  DataPtr += DataLen;
  DataLen = Msg->F.Length_Help_Returned;
  /* If there is non-blank message help text, print it out          */
  if ((DataLen > 0) && (strspn( DataPtr," ") < DataLen))
    PrintData("Message help text received->",DataPtr,DataLen);
  strncpy(buf,"-                                          ",43);
  fwrite(buf,1,BUF_SIZE,prtf);
}

 /*********************************************************************/
 /*                                                                   */
 /*  Start of main program.                                           */
 /*                                                                   */
 /*********************************************************************/

main()
{


 error_code_struct ErrorCode;

 qual_name_struct  MsgQList[5];
 qual_name_struct  MsgFile;
 qual_name_struct  RpyMsgQ;

 msg_info_struct   MsgInfo;

 char MsgData[128];
 char MsgText[512];
 char MsgHelp[512];
 char PgmMsgQ[10];
 char MsgType[10];
 char MsgAction[10];
 char Format[8];
 char MsgId[7];
 char MsgKey[4];

 int  MsgTextLen;
 int  MsgInfoLen;
 int  NumMsgQ;
 int  PgmCount;
 int  WaitTime;
 int  morediag;


 /* Initialize variables */
 exception_count = 0;
 memcpy(ErrorCode.ec_fields.Exception_Id,"       ",7);
 ErrorCode.ec_fields.Bytes_Provided = 0;

 memcpy(MsgId,"       ",7);
 memcpy(MsgFile.name,"          ",10);
 memcpy(MsgFile.libr,"          ",10);
 strcpy(MsgText,"This is an immediate, informational message");
 MsgTextLen = strlen(MsgText);
 memcpy(MsgType,"*INFO     ",10);
 memcpy(RpyMsgQ.name,"          ",10);
 memcpy(RpyMsgQ.libr,"          ",10);

 /* Build the list of message queues to send the message to         */
 NumMsgQ = 5;
 BuildQList(MsgQList,NumMsgQ);


 /* Enable the exception handler around the call to QMHSNDM         */
 #pragma exception_handler(excp_handler, 0, 0, _C2_MH_ESCAPE)

 /* Send the message to the list of message queues.                 */
 QMHSNDM( MsgId,
         &MsgFile,
          MsgText,
          MsgTextLen,
          MsgType,
         &MsgQList,
          NumMsgQ,
         &RpyMsgQ,
         &MsgKey,
         &ErrorCode);

 /* Disable the exception handler                                   */
 #pragma disable_handler

 /* If an error occurred on the send, produce an exception report   */
 /* identifying what errors occurred.                               */
 if (exception_count != 0)
   {

    /* Open printer file using first character forms control and    */
    /* write the header information.                                */
    prtf = fopen ("PRTDIAG", "wb type=record recfm=FA lrecl=80");
    memset(buf,' ',BUF_SIZE);
    strncpy(buf,"1                         DIAGNOSTIC REPORT",43);
    fwrite(buf,1,BUF_SIZE,prtf);
    strncpy(buf,"                          -----------------",43);
    fwrite(buf,1,BUF_SIZE,prtf);
    strncpy(buf,"-                                          ",43);
    fwrite(buf,1,BUF_SIZE,prtf);

    /* Do the setup to first receive the exception signalled.       */
    memcpy(Format,"RCVM0200",8);
    memcpy(PgmMsgQ,"*         ",10);
    memcpy(MsgType,"*EXCP     ",10);
    memcpy(MsgKey,"    ",4);
    memcpy(MsgAction,"*OLD      ",10);
    PgmCount = 0;
    WaitTime = 0;
    MsgInfoLen = 1276;

    /* Now change bytes_provided to 116 so that if any errors occur */
    /* on the receive, the error information will be returned in the*/
    /* error code structure instead of generating more exceptions   */
    /* which will clutter up the program message queue.             */
    ErrorCode.ec_fields.Bytes_Provided = 116;

    /* Receive the last exception type message on the program       */
    /* message queue                                                */
    QMHRCVPM(&MsgInfo,
              MsgInfoLen,
              Format,
              PgmMsgQ,
              PgmCount,
              MsgType,
              MsgKey,
              WaitTime,
              MsgAction,
             &ErrorCode);

    /* Test for any errors on the receive */
    if (ErrorCode.ec_fields.Bytes_Available > 0)
      {
       PrintError("QMHRCVPM - Did not complete successfully",
                  ErrorCode.ec_fields.Exception_Id);
      }

    /* An exception message was received successfully.  Now see if  */
    /* the message received is the same exception that was signalled*/
    /* If not, there is an error.                                   */
    if (strncmp(MsgInfo.F.Message_Id,received,7) != 0)
      {
       PrintError("QMHRCVPM - Wrong exception received",
                  MsgInfo.F.Message_Id);
      }


    /* The exception message was received successfully.             */
    /* Print the message data and text for the exception message.   */
    PrintMessage(&MsgInfo);

    /* If the message was the generic CPF2469, there are one or     */
    /* more diagnostic messages to go with the CPF2469 on the queue.*/
    /* Receive the diagnostic messages previous to the CPF2469 until*/
    /* a non-diagnostic message is received or there are no more    */
    /* messages.                                                    */
    if (strncmp(MsgInfo.F.Message_Id,"CPF2469",7) == 0)
      {
       memcpy(MsgType,"*PRV      ",10);
       memcpy(MsgKey,MsgInfo.F.Message_Key,4);
       morediag = 1;

       while(morediag)
         {
          /* Receive the previous diagnostic */
          QMHRCVPM(&MsgInfo,
                   MsgInfoLen,
                   Format,
                   PgmMsgQ,
                   PgmCount,
                   MsgType,
                   MsgKey,
                   WaitTime,
                   MsgAction,
                   &ErrorCode);

          /* Test for error on the receive */
          if (ErrorCode.ec_fields.Bytes_Available > 0)
            {
             PrintError("QMHRCVPM - Did not complete successfully",
                        ErrorCode.ec_fields.Exception_Id);
            }

          /* If bytes available = 0 OR the next message is not a    */
          /* diagnostic message, we are done.                       */
          if ((MsgInfo.F.Bytes_Available == 0) ||
              (strncmp(MsgInfo.F.Message_Type,DIAG_TYPE,2) != 0) )
            {
             morediag = 0;
            }
          else                /* A diagnostic was received          */
            {
             /* Print the message data and text for the diagnostic  */
             /* message                                             */
             PrintMessage(&MsgInfo);

             /* Now copy the message key of the diagnostic message  */
             /* received to the MsgKey parameter to use on the next */
             /* call to QMHRCVPM.                                   */
             memcpy(MsgKey,MsgInfo.F.Message_Key,7);
            }

         }                        /* End of while morediag = 1      */

      }                           /* End of if CPF2469 received     */

    /* Write trailer */
    memset(buf,' ',BUF_SIZE);
    strncpy(buf,"-                       END OF DIAGNOSTIC REPORT",48);
    fwrite(buf,1,BUF_SIZE,prtf);

    /* Close the print file */
    fclose(prtf);

   }                              /* End of if error on send        */

}                                 /* End mainline                   */

Printed diagnostic report

The DIAGRPT program produces a report like this:

Message ID->CPF2469
Message Type->ESCAPE
Message text received->Error occurred when sending message.
Message help text received->Recovery  . . . :   See messages
          previously listed for a description of the error.
          Correct the error, and then try the
          command again.

Message ID->CPF2403
Message Type->DIAGNOSTIC
Message data received->PEANUTS   *LIBL
Message text received->Message queue PEANUTS in *LIBL not found.
Message help text received->Cause . . . . . :   The message queue you
        specified was not found in the library you specified.  One
        of the following occurred: -- The queue name was not
        entered correctly. -- The queue does not exist in the
        specified library. -- You specified the wrong library name.
        Recovery  . . . :   Do one of the following and try the
        request again: -- Correct or change the message queue
        name or library name used in the message queue (MSGQ)
        parameter or the to-message queue (TOMSGQ) parameter.
        -- Create the message queue using the Create Message
        Queue (CRTMSGQ) command.


Message ID->CPF2403
Message Type->DIAGNOSTIC
Message data received->SNOOPY    *LIBL
Message text received->Message queue SNOOPY in *LIBL not found.
Message help text received->Cause . . . . . :   The message queue
          you specified was not found in the library you specified.
          One of the following occurred: -- The queue name was not
          entered correctly. -- The queue does not exist in the
          specified library. -- You specified the wrong library
          name. Recovery  . . . :   Do one of the following and
          try the request again: -- Correct or change the message
          queue name or library name used in the message queue
          (MSGQ) parameter or the to-message queue (TOMSGQ)
          parameter. -- Create the message queue using the Create
          Message Queue (CRTMSGQ) command.
                     End of Diagnostic Report