Signaling and handling a condition in a C/C++ routine

The next program shows how a user-written condition handler gains control for a condition that was signaled using CEESGL, and calls CEEGQDT to access a data structure that was set up in the signaling routine. The CEEMRCR callable service resets the resume cursor, and execution resumes at the new point.
/*Module/File Name:  EDCSIGH */
/**********************************************************************/
/* This example shows how several of the Language Environment         */
/* condition management callable services are used.  The services     */
/* shown are:                                                         */
/* CEEHDLR  -- register a user condition handler                      */
/* CEESGL   -- signal a condition to the condition manager            */
/* CEEGQDT  -- get the q_data_token                                   */
/* CEEMRCR  -- move the resume cursor                                 */
/*                                                                    */
/* The example also shows how to directly construct a condition token */
/* and provides a sample user condition handler.                      */
/**********************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <leawi.h>
#include <ceeedcct.h>

void b(void);

#ifdef __cplusplus
extern "C" {
#endif

void handler(_FEEDBACK *,_INT4 *,_INT4 *,_FEEDBACK *);

#ifdef __cplusplus
}
#endif

typedef struct {          /* condition info structure */
   int   error_value;
   char err_msg[80];
   int   retcode;
} info_struct;

int main(void) {

  printf("In main program\n");
   b();
  /* CEEMRCR should put the resume cursor at this point */
  printf("Finished\n");
}
void b(void) {

  _FEEDBACK fc,condtok;
  _ENTRY routine;
  _INT4 token,qdata;
  info_struct *info;
  _INT2 c_1,c_2,cond_case,sev,control;
  _CHAR3 facid;
  _INT4 isi;
  printf("In routine b\n");
  token = 99;
  routine.address = (_POINTER)&handler;
  routine.nesting = NULL;
  /* register the condition handler: */
  CEEHDLR(&routine,&token,&fc);

  if ( _FBCHECK ( fc , CEE000 ) != 0 ) {
     printf("CEEHDLR failed with message number %d\n",
            fc.tok_msgno);
     exit(2999);
  }

  /* build the condition token */
  c_1 = 1;
  c_2 = 99;
  cond_case = 1;
  sev = 1;
  control = 0;
  memcpy(facid,"ZZZ",3);
  isi = 0;

  CEENCOD(&c_1,&c_2,&cond_case,&sev,&control,
          facid,&isi,&condtok,&fc);
  if ( _FBCHECK ( fc , CEE000 ) != 0 ) {
     printf("CEENCOD failed with message number %d\n",
            fc.tok_msgno);
     exit(2999);
  }

  /* set up the condition info structure */
  info = (info_struct *)malloc(sizeof(info_struct));
  if (info == NULL) {
     printf("error allocating info_struct\n");
     exit(2399);
  }
  memset(info->err_msg,' ',79);
  info->err_msg[79] = '\0';
  info->error_value = 86;
  memcpy(info->err_msg,"Test message",12);
  info->retcode = 99;

  /* set qdata to be the condition info structure */
  qdata = (int)info;
  /* signal the condition */
  CEESGL(&condtok,&qdata,NULL);

  printf("Failed: handler should have moved resume cursor past this\n");
}
/**********************************************************************/
/* User condition handler                                             */
/**********************************************************************/
void handler(_FEEDBACK *fc, _INT4 *token, _INT4 *result,
             _FEEDBACK *newfc) {

   _FEEDBACK cursorfc, orig_fc;
   _INT4 type;
   _INT4 qdata;


   /* if the condition is not mine (ZZZ facid) then percolate */
   if (memcmp(fc->tok_facid,"ZZZ",3) != 0) {
      *result = 20;
      return;
   }
   printf("%d is handling the condition for Control\n",*token);

   /* get the q_data_token */
   CEEGQDT(fc,&qdata,NULL);

   /* look at the q_data_token and print out a message if the */
   /* error_value was 86                                      */
   if (((info_struct *)qdata)->error_value == 86)
      printf("%.80s\n",((info_struct*)qdata)->err_msg);

   /* move the resume cursor to the caller of the routine */
   /* that registered this handler                        */
   type = 1;
   CEEMRCR(&type,&cursorfc);
  if ( _FBCHECK ( cursorfc , CEE000 ) != 0 ) {
     printf("CEEMRCR failed with message number %d\n",
            cursorfc.tok_msgno);
     exit(2999);
  }

   /* mark the condition as handled and return */
   printf("Condition handled\n");
   *result = 10;
   return;
}