OTMA C/I sample program for synchronous processing

The program below shows how to use the OTMA C/I for synchronous (one in-one out) processing.

In this sample program, the otma_send_receive API is used to send and receive IMS data.

#pragma langlvl(extended)
/*********************************************************************/
/*                                                                   */
/* Callable Interface sample program using synchronous APIs          */        
/*                                                                   */        
/* Parameters:                                                       */        
/*         Server Name                                               */ 
/*         Client Name                                               */
/*         User Name                                                 */
/*         Iterations                                                */
/*         Transaction                                               */
/*         User Group                                                */
/*         OTMA Data                                                 */
/*                                                                   */
/* Note:  The send buffer is sent as a file with a ddname of         */
/*        SENDBUFn in the invoking JCL.                              */
/*                                                                   */
/* Example:  //SENDBUF0 DD *,DLM=$$                                  */
/*           SEND OTMA TO SKS1                                       */
/*           $$                                                      */
/*                                                                   */
/* Note: COMPAR1 is the DDNAME of an input file used to compare      */
/*       actual output with expected output. '?' is used to delimit  */
/*       the compare string and '|' is used to ignore a char compare */
/*                                                                   */
/* Example:  //COMPAR0  DD *,DLM=$$                                  */
/*           SEND OTMA TO SKS1?                                      */
/*           $$                                                      */
/*                                                                   */
/*********************************************************************/

/********************************************************************/
/*   Entry...                                                       */
/*                                                                  */
/*     This test program is callable from JCL                       */
/*                                                                  */
/* //NA1OTMA  JOB CLASS=A,MSGLEVEL=(1,1),MSGCLASS=H,REGION=2M       */
/* //************************************************************** */
/* //* PARM=server_member_name tpipe_name client_member_name        */
/* //*      iterations command groupid OTMA_Data                    */
/* //MINISAMP EXEC PGM=NA1OTMA,                                     */
/* // PARM='TRAP(OFF)/IMS61CR1 IMSTESR G214992 1 /DISP groupid      */
/* //      OTMAData'                                                */
/* //STEPLIB  DD DISP=SHR,DSN=OTMA.TEST.LOAD                        */
/* //SYSUDUMP DD SYSOUT=*                                           */
/* //STDOUT   DD SYSOUT=*                                           */
/* //STDERR   DD SYSOUT=*                                           */
/* //CEEDUMP  DD SYSOUT=*                                           */
/* //COMPAR1  DD *,DLM=$$                                           */
/* EXPECTED OUTPUT GOES HERE                                        */
/* $$                                                               */
/* //SENDBUF0 DD *,DLM=$$                                           */
/* SEND DATA GOES HERE                                              */
/* $$                                                               */
/*                                                                  */
/* Note: TRAP(OFF)/ Passes LE run-time option TRAP(OFF) which turns */
/*       off LE condition handling. To get a LE dump on abend set   */
/*       TRAP ON and provide a CEEDUMP DDNAME.                      */
/*                                                                  */
/* Note: COMPAR1 is the DDNAME of an input file used to compare     */
/*       actual output with expected output. '?' is used to delimit */
/*       the compare string and '|' is used to ignore a char compare*/
/*                                                                  */
/********************************************************************/
 
/*********************************************************************/
/* An example for using the OTMA Client API in C lang.               */
/*   This program is broken into the following parts:                */
/*      Declarations for special support                             */
/*      Process invocation parameters                                */
/*      Setup for C signal handling                                  */
/*      Do XCF open processing and analysis                          */
/*      Do session allocate processing                               */
/*      Execute a command or transaction per invocation parm         */
/*      Do session free processing                                   */
/*      Do close                                                     */
/*      End                                                          */
/*********************************************************************/

/*********************************************************************/
/* API's for non-authorized OTMA caller                              */
/*********************************************************************/
#include "dfsyc0.h"              /* Non-authorized OTMA API's        */
#include <stdlib.h>              /* Standard C Header file           */         
#include <stddef.h>              /* Standard C Header file           */         
#include <stdio.h>               /* Standard C Header file           */         
 
/*********************************************************************/
/* Internal functions                                                */
/*********************************************************************/
int  memc(char *comp_buf, char *rec_buf1 );
 
/* macro to move string to blank filled left justified char field    */
#define splat(t,s) \
  {\
  memset((char*)&(t),' ',sizeof(t));\
  strncpy((char*)&(t), s ,strlen(s));}
 
/* standard math routines                                            */
#define   min(a,b)        ((a)<(b)?(a):(b))
#define   max(a,b)        ((a)>(b)?(a):(b))
 
main(int argc,char *argv[])
{
 
   /*         Following fields used by all Functions                 */
 
 otma_anchor_t    anchor;         /*  Handle returned by create      */
                                  /*  and used by all others.        */
 otma_retrsn_t    retrsn;         /*  Return code returned by all.   */
 long int         retsave;        /*  Return code save area          */
 
   /*     Following fields used by several Functions      */
 
 sess_handle_t     sess_handle;   /* Handle returned by allocate     */
                                  /* used by send_receive and free.  */
 otma_grp_name_t   grp_name;      /* API XCF Group Member Name.      */
 otma_clt_name_t   clt_name;      /* API XCF Client Member Name.     */
 otma_srv_name_t   srv_name;      /* API XCF Server Member Name.     */
                                  /*   (the IMS XCF member name).      */
 racf_uid_t        userid;        /* Our z/OS logon ID.              */
 racf_prf_t        groupid;       /* RACF Group ID                   */
 otma_user_t       otma_data;     /* Otma Data                       */

 lterm_name_t  lterm;                  /* Lterm name                 */
 mod_name_t    modname;                  /* ModName                  */

 unsigned char error_message_text[120];/* IMS error msg field        */
                                  /* A place to receive any IMS      */
                                  /* DFS error messages.             */
 unsigned char *error_message = (unsigned char*)&error_message_text;
                                  /* a pointer to which is parameter */
                                  /* on send_receive.                */
 
 char         *tran;              /* Transaction Name / IMS Command  */
 tran_name_t  tran_name;          /* Transaction Name / IMS Command  */

#define BUFFER_LEN  4096          /* set our buffer sizes           */
#define NUM_BUFFER  60
#define COM_BUFFER  80
#define GROUP_NAME  "HARRY"       /* Set XCF group name to join     */
 
 char compare_buf[NUM_BUFFER + 1]; /* Compare buffer                */
 int long      buffer_length = 0;
 int long      rec_buffer_len = BUFFER_LEN;
 char          rec_buf[BUFFER_LEN];
 long int      rec_data_len = 0;
 char          send_buf[BUFFER_LEN];
 char          temp_buf[NUM_BUFFER];
 
 context_t     context = {0x00000000000000000000000000000000};
                      /* This test is not distributed sync point.   */
                      /* Too complicated for here.                  */
                      /* Normally this is obtained from RRS         */

/*********************************************************************/
/*  The callable interface makes use of z/OS Event Control Blocks.   */
/*  Any language which call the interface must deal with this.       */
/*********************************************************************/
 
 unsigned long  *(ecb_list[2]);        /* z/OS pause stuff           */
 unsigned long **pecb_list;
 
 ecb_t         ecbOPEN   = 0L;     /* ecb to be posted by OTMA API   */
 ecb_t         ecbIO     = 0L;     /* ecb to be posted by OTMA API   */
 ecb_t         signal    = 0L;     /* ecb to be posted by C runtime  */
 
 ecb_t         temp_ecb  = 0L;     /* used by compare and swap       */
 ecb_t         reset_ecb = 0L;     /* used by compare and swap       */
 
/*********************************************************************/
/*    Local variables                                                */
/*********************************************************************/
 
 int           iterations;
 int           loop_count;
 int           compare_result;
 long int      retcode;
 
 signed long   sessions;        /* number of sessions to support     */
 tpipe_prfx_t  tpipe_prefix;       /* first part of tpipe NAME       */

 FILE * stream;
 int num;       /* number of characters read from stream */
 
 
/*******************************************************************/
/* To support test functions - names of parms                      */
/* Print the parms out for documentation                           */
/*******************************************************************/

 char * argdefs[8]={ "pgm name",          /* 1                     */
                     "server name",       /* 2                     */
                     "client name",       /* 3                     */
                     "userid     ",       /* 4                     */
                     "iterations ",       /* 5                     */
                     "transaction",       /* 6                     */
                     "group id   ",       /* 7                     */
                     "otma data  ",       /* 8                     */
                     };
 
/*******************************************************************/
/*  Declare an array of compare file ddnames to                    */
/*  compare actual output received with expected output.           */
/*******************************************************************/
 
 char * infiledd[4]={"DD:COMPAR0",        /* 1                   */
                     "DD:COMPAR1" ,       /* 2                   */
                     "DD:COMPAR2" ,       /* 3                   */
                     "DD:COMPAR3" ,       /* 4                   */
                     };
 
/*******************************************************************/
/*  Declare an array of send file ddnames to                       */
/*  send application data to OTMA.                                 */
/*******************************************************************/
 
 char * sndfiledd[4]= {"DD:SENDBUF0",        /* 1                   */
                       "DD:SENDBUF1" ,       /* 2                   */
                       "DD:SENDBUF2" ,       /* 3                   */
                       "DD:SENDBUF3" ,       /* 4                   */
                      };
 
/* ---------------------------------------------------------------- */
/* Anounce the startup of the test program.                         */
/* ---------------------------------------------------------------- */
   printf("Otmci01   Starting, version %s %s\n" ,__DATE__,__TIME__ );
 
/* ---------------------------------------------------------------- */
/* z/OS Pause Init - do this first, in case it fails bail out.      */
/* This sets up a C environment for signaling from the API.         */
/* ---------------------------------------------------------------- */
 
  ecb_list[0] = (unsigned long *) &(signal); /* post by C signal    */
  ecb_list[1] = (unsigned long *)            /* post by OTMA        */
                 ((unsigned long)&(ecbOPEN) |
                  (unsigned long)0x80000000);/* end of list         */
  pecb_list = &ecb_list[0];                  /* pointer to list     */
                                             /* define callable I/F */
 
/*******************************************************************/          
/* Begin Test Case...                                              */          
/* Anounce the startup of the test program.                        */         
/*******************************************************************/          
   printf("OTMCI01 Run Date: %s Run Time: %s\n" ,__DATE__,__TIME__ );           
                                                                                
/*******************************************************************/         
/* Process parms/command line arguments.                           */         
/*******************************************************************/         
                                                                                
  /* First, print the parameters. */                                              
  printf("Invocation parameters = \n");
   for (i=1 ; i<(min(8,argc));i++)
   {
     printf("%d   %s = ", i, argdefs[i]);
     printf("%s.\n", argv[i]);
   }
 
   if (argc>1)  splat( srv_name, argv[1])      /* XCF memname of IMS */
   else         splat( srv_name, "IMS61CR1");  /* hard coded default */
   if (argc>2)  splat( clt_name, argv[2])      /* Client name        */
   else         splat( clt_name, "XCFTEST"  ); /* hard coded default */
   if (argc>3)  splat( userid  , argv[3])      /* ID to use          */
   else         splat( userid  , "XCFTEST"  ); /* hard coded default */
  if (argc>4)   iterations = atoi(argv[4]);    /* loop count         */
   else         iterations = 1;                /* hard coded default */
  if (argc>5)   tran = argv[5];                /* Transaction/IMS CMD*/
   else         tran = "";                     /* hard coded default */  
   if (argc>6)  splat( groupid, argv[6])       /* Group ID to use    */
   else         splat( groupid, "        " );  /* hard coded default */
   if (argc>7)  splat( otma_data, argv[7])     /* OTMA Data          */
   else         splat( otma_data, "" );        /* hard coded default */
 
   /* -----------------------------------------------------------*/
   /* Open the file with the ddname SENDBUF0 supplied in the     */
   /* JCL which invoked this C driver.  Then read the file into  */
   /* temp_buf.                                                  */
   /* -----------------------------------------------------------*/
 
   if (( stream = fopen("DD:SENDBUF0","rb")) != NULL )
   {
     num = fread( temp_buf, sizeof( char ), NUM_BUFFER, stream );
    printf("BUFF SIZE = %d.\n", num);
     if (num == NUM_BUFFER) {
       printf( "Number of characters read = %i\n", num );
       fclose( stream );
     }
     else {
       if ( ferror(stream) )
         printf( "Error reading DDNAME sendbuf0/n");
       else if ( feof(stream)) {
         printf( "EOF found\n" );
         printf( "Number of characters read %d\n", num );
         printf( "temp_buf = %.*s\n", num, temp_buf);
         fclose( stream );
       }
     }
   }
   else
     printf( "ERROR opening DDNAME sendbuf0/n" );
 
   /*  Initialize API parameters and buffers.                        */
   splat( grp_name,GROUP_NAME );               /* XCF Group Name     */
   splat( tpipe_prefix,"TPAS" );               /* tpipe Prefix Name  */
   splat( tran_name,tran );                    /* do scan here       */
   strncat(send_buf, temp_buf,num);   /* Copy temp_buf into send_buf */
   buffer_length = strlen(send_buf);  /* Set send buffer length      */
  
  /*******************************************************************/
  /* Example of setting up parms to Open the XCF Link                */
  /*******************************************************************/
 
    retrsn.ret    = -1;
    retrsn.rsn[0] = -1;
    retrsn.rsn[1] = -1;
    retrsn.rsn[2] = -1;
    retrsn.rsn[3] = -1;
 
    sessions      = 10;    /* OTMA supports multiple parallel        */
                           /* sessions (TPIPES) How many do you want?*/
 
  /*******************************************************************/
  /*BEGIN:                                                           */
  /* We have a CREATE function to set up storage and                 */
  /* an OPEN function to start the protocol.                         */
  /* If you do not need to customize the environment you can start    */
  /* with the OPEN function, the CREATE will be done by OPEN.        */
  /*******************************************************************/
 
    printf("-\n");
    otma_create(&anchor,      /* (out) ptr to addr to receive ancho*/
           &retrsn,           /* (out) return code                 */
           (ecb_t *) &ecbOPEN,/* not posted by create but stored   */
 
           &grp_name,         /* (in) ptr to valid groupname       */
           &clt_name,         /* (in) Our member name              */
           &srv_name,         /* (in) Our server name              */
 
           &sessions,         /* (in) number of sessions to support*/
           &tpipe_prefix      /* (in) first part of tpipe name     */
           );

     printf("OTMA_CREATE issued. ret = %d rsn = %.8x,%.8x,%.8x,%.8x\n"
            "  anchor is at %.8x.\n",
            retrsn.ret,
            retrsn.rsn[0],
            retrsn.rsn[1],
            retrsn.rsn[2],
            retrsn.rsn[3],
            anchor);
 
 
   printf("-\n");
 
  /*******************************************************************/
  /*  Connect to IMS                                                 */
  /*******************************************************************/
  
   otma_open(&anchor,        /* out ptr to addr to receive anchor  */
           &retrsn,           /* out return code                   */
           (ecb_t *)&ecbOPEN, /* out posted by open if failure     */
                              /*     else posted by exit pgm       */
           &grp_name,         /* in ptr to valid XCF groupname     */
           &clt_name,         /* in Our member name                */
           &srv_name,         /* in Our server name                */
 
           &sessions,         /* in number of sessions to support  */
           &tpipe_prefix      /* in first part of tpipe name       */
           );
 
    printf("OTMA_OPEN issued. ret = %.8x rsn = %.8x,%.8x,%.8x,%.8x\n"
            " Waiting for ecb at %.8x.=%.8x.\n",
            retrsn.ret,
            retrsn.rsn[1],
            retrsn.rsn[2],
            retrsn.rsn[3],
            ecb_list[1],
            *ecb_list[1]
            );
 
   printf("-\n");
 
 /* ---------------------------------------------------------------- */
 /* Here we wait for Open to signal complete                         */
 /* ---------------------------------------------------------------- */
     DFSYCWAT(ecb_list[1]);   /* WAIT on ecb                         */
 
      printf("OPEN_OTMA done. ret = %.8x rsn = %.8x,%.8x,%.8x,%.8x \n"
             "\nEcb at %.8x.= %.8x.\n",
             retrsn.ret,
             retrsn.rsn[0],
             retrsn.rsn[1],
             retrsn.rsn[2],
             retrsn.rsn[3],
             ecb_list[1], *ecb_list[1]
             );
 
      printf("Local Area Anchor at %8.8X = %8.8X\n",
                  &anchor, anchor);
 
      printf("-\n");
 
   /* -----------------------------------------------------------*/
   /* The post code from open indicates success or failure       */
   /* -----------------------------------------------------------*/
      if (0!=(0x00ffffff & ecbOPEN))
        {
          printf("OPEN_OTMA ecb is posted failure.\n");
          return(retrsn.rsn[0]);
        }
 
   /* -----------------------------------------------------------*/
   /* Set userid to blanks if userid = bobdavis                  */
   /* -----------------------------------------------------------*/
 
    printf(" Trans  = %.8s,\n  ", tran_name );
    printf(" Userid = %.8s,\n  ", userid );
    printf("Groupid = %.8s,\n  ", groupid );
 
   /**************************************************************/
   /* Like CREATE the ALLOC function just creates control blocks */
   /* and stores data in them. Other functions may be invented   */
   /* to modify these structures before the command-of-execution,*/
   /* SEND_RECEIVE is issued.                                    */
   /**************************************************************/
 
    otma_alloc(
               &anchor,               /* in   ptr to global word   */
               &retrsn,               /* out  rc,reason(1-4)       */
 
               &sess_handle,          /* out  session id           */
               NULL,                  /* in   default overrides    */
 
               &tran_name,            /* in   IMS tp name or cmd   */
               &userid,               /* in   RACFid  or blanks    */
               &groupid               /* in   RACF group id or blnk*/
     );

     printf("OTMA_ALLOC done. ret = %.8x rsn = %.8x,%.8x,%.8x,%.8x\n",
            retrsn.ret,
            retrsn.rsn[0],
            retrsn.rsn[1],
            retrsn.rsn[2],
            retrsn.rsn[3]
            );
 
   /**************************************************************/
   /*   Even if ALLOC fails we go on here just to prove the      */
   /*   API will reject the call.                                */
   /**************************************************************/
 
   /**************************************************************/
   /* This is the call that sends the data and prepares to       */
   /* receive the answer from IMS.                               */
   /*                                                            */
   /* This test program can iterate with multiple calls here.    */
   /**************************************************************/
 
   /* ___Send message wait for reply______________________       */
  for (loop_count = 0 ; loop_count<iterations ; loop_count++)
  {
   /* ___Change the environment to wait for ecbIO                */
   ecbIO = 0;                            /* clear ecb for reuse  */
   ecb_list[1] = (unsigned long *)         /* posted by OTMA     */
                    ((unsigned long)&(ecbIO) |
                     (unsigned long)0x80000000);  /* end of list */
 
    if (loop_count != 0)
     {
 
      /* -----------------------------------------------------------*/
      /* If looping more than once open the next file to send       */
      /* and read it into the send_buf.                             */
      /* -----------------------------------------------------------*/
 
      if (( stream = fopen(sndfiledd[loop_count],"rb")) != NULL )
       {
        num = fread( temp_buf, sizeof( char ), NUM_BUFFER, stream );
        printf("BUFF SIZE = %d.\n", num);
        if (num == NUM_BUFFER) {
          fclose( stream );
        }
        else {
         if ( ferror(stream) )
          printf( "Error opening file  
          else if ( feof(stream)) {
            printf( "EOF found\n" );
            printf( "Number of characters read %d\n", num );
            printf( "temp_buf = %.*s\n", num, temp_buf);
            fclose( stream );
          }
        }
       }
      else
       printf( "Error opening file %s\n", sndfiledd[loop_count]);
      /*  Initialize send and receiving buffers.       */
      memset(rec_buf ,0, sizeof(rec_buf));
      memset(send_buf ,0, sizeof(send_buf));
      strcat(send_buf, temp_buf );
      strcat(send_buf, " " );
      buffer_length = strlen(send_buf);
      printf("
      printf ("buffer length = %d\n", buffer_length);
     }  /* end if loop_count != 0    */
 
    /* Print otma_send_receive parms and start of API  */
    memset(error_message_text ,0, sizeof(error_message_text));
    printf("Send buf at %.8x.\n", &send_buf);
    printf("Send buf = %s.\n", send_buf);
    printf("Receive buf at %.8x.\n", &rec_buf);
    printf("Lterm = %.8s.\n", lterm );
    printf("Modname = %.8s.\n", modname );
 
    printf("-\n");
    otma_send_receivex(
                     &anchor,          /* (in)  anchor block         */
                     &retrsn,          /* (out) return status        */
                     &ecbIO,           /* (in)  ecb address          */
 
                     &sess_handle,     /* (in)  session handle       */
                     &lterm,           /* (in/out)  logical terminal */
                     &modname,         /* (in/out)  module name      */
 
   (unsigned char *) &send_buf,        /* (in)  send buffer          */
                     &buffer_length,   /* (in)  size of send buffer  */
                     0,                /* (in)  send_segment_list    */
 
   (unsigned char *) &rec_buf,         /* (in)  receive buffer       */
                     &rec_buffer_len,  /* (in)  size of buffer       */
                     &rec_data_len,    /* (out) received data length */
                     0,                /* (in/out) receive seg list  */
 
                     &context,         /* (in)  context id           */
                     &error_message,   /* (out) ims message          */
                     &otma_data);      /* (in)  Otma Data            */
 
     printf("OTMA_SEND done. ret = %.8x rsn = %.8x,%.8x,%.8x,%.8x\n",
             retrsn.ret,
             retrsn.rsn[0],
             retrsn.rsn[1],
             retrsn.rsn[2],
             retrsn.rsn[3]);
 
 /* ---------------------------------------------------------------- */
 /* Here we wait for receive to signal complete                      */
 /* An application can go do other thing while IMS is processing and */
 /* while the XCF scheduled SRBs are returning data to the caller's  */
 /* buffers. DO NOT DEALLOCATE THE BUFERS WHILE THIS IS GOING ON!    */
 /* None of the output areas of the SEND_RECIEVE can be freed until  */
 /* the ECB is posted complete.                                      */
 /* ---------------------------------------------------------------- */
 
    DFSYCWAT(ecb_list[1]);      /* WAIT on ecb                    */
 
    retsave = retrsn.ret;       /* Save Receive return code       */
 
     printf("OTMA_RECEIVE done. ret = %.8x rsn = %.8x,%.8x,%.8x,%.8x\n"
             "\nEcb at %.8x.= %.8x.\n",
             retrsn.ret,
             retrsn.rsn[0],
             retrsn.rsn[1],
             retrsn.rsn[2],
             retrsn.rsn[3],
             ecb_list[1],
             *ecb_list[1]
             );

     if (retrsn.ret != 0)
     {
 
      /* ___Error path Free allocated session _____________________ */
      printf("-error path retrsn.ret=
      printf("-\n");
      printf( "Error message = %s\n", error_message );
      otma_free(
                     & anchor,        /* (out)  ptr to global word   */
                     & retrsn,        /* (out)  rc,reason (1-4)      */
                     & sess_handle    /* (in)   unique path id       */
               );
 
      printf("OTMA_FREE done. ret = %.8x rsn = %.8x,%.8x,%.8x,%.8x \n",
             retrsn.ret,
             retrsn.rsn[0],
             retrsn.rsn[1],
             retrsn.rsn[2],
             retrsn.rsn[3]
             );
 
      /* ___Sever IMS connection ____________________________       */
      printf("-\n");
      otma_close(
                     & anchor,        /* (in,out) tr to otma anchor */
                     & retrsn         /* (out) rc,reason (1-4)      */
              );
 
      printf("OTMA_CLOSE done. ret = %.8x rsn = %.8x,%.8x,%.8x,%.8x\n",
             retrsn.ret,
             retrsn.rsn[0],
             retrsn.rsn[1],
             retrsn.rsn[2],
             retrsn.rsn[3]
             );
 
      return (retsave);      /* EXIT with receive API return code */
     }
 
   /* -----------------------------------------------------------*/
   /*  If SEND_RECEIVE worked ..                                 */
   /* -----------------------------------------------------------*/
 
 
   /* -----------------------------------------------------------*/
   /*  Open the compare file containing the expected output      */
   /*  of the receive buffer.  Compare the expected output       */
   /*  with the actual output and return the result.             */
   /* -----------------------------------------------------------*/
 
  rec_buf[0] = ' ';         /* Remove possible NL ie x'15' */
  printf( "infiledd = %s\n", infiledd[loop_count] );
 
  if (( stream = fopen(infiledd[loop_count],"rb")) != NULL )
  {
    num = fread( compare_buf, sizeof( char ), COM_BUFFER, stream );
    if (num == COM_BUFFER) {  /* fread success */
      printf( "compare_buf = %s\n", compare_buf );
      printf( "    rec_buf = %s\n", rec_buf );
      fclose( stream );
      compare_result = memc( compare_buf, rec_buf );
      printf( "compare_result = 
      if (compare_result != 0)
        return(compare_result);        /* Exit if NO COMPARE    */
    }
    else {  /* fread() failed */
      if ( ferror(stream) )         /* possibility 1 */
        printf( "Error reading file %s\n", infiledd[loop_count]);
      else if ( feof(stream)) {     /* possibility 2 */
        printf( "EOF found\n" );
        printf( "Number of characters read %d\n", num );
        printf( "compare_buf = %.*s\n", num, compare_buf);
      }
    }
  }
  else
    printf( "Error opening file %s\n", infiledd[loop_count]);
}      /* end of loop */
 
  /*****************************************************************/
  /* Once a message is sent to IMS and the answer received it      */
  /* is usual to release the tpipe for use by other transactions.  */
  /* For conversational trans an application would keep using      */
  /* the handle to continue a conversational transaction with IMS. */
  /* The Transaction name is specified in the ALLOC and it is      */
  /* intended that a FREE be done at the end of each transaction   */
  /* and a new ALLOC be done for the next one. This is not         */
  /* expensive.                                                    */
  /*****************************************************************/
 
    printf("-\n");
    otma_free(
                     & anchor,        /* (out)  ptr to global word   */
                     & retrsn,        /* (out)  rc,reason (1-4)      */
                     & sess_handle    /* (in)   unique path id       */
             );
 
     printf("OTMA_FREE done. ret = %.8x rsn = %.8x,%.8x,%.8x,%.8x \n",
            retrsn.ret,
            retrsn.rsn[0],
            retrsn.rsn[1],
            retrsn.rsn[2],
            retrsn.rsn[3]
            );
 
    printf("-\n");
 
   /*                                                               */
   /* Finally, CLOSE severs the connection with IMS and frees the   */
   /* Storage used by the OTMA API.                                 */
   /*  This will be done at job-step termination but its untidy.    */
   /*                                                               */
 
    otma_close(
                     & anchor,        /* (in,out) ptr to otma anchor */
                     & retrsn         /* (out)  rc,reason (1-4)      */
              );
    printf("OTMA_CLOSE done. ret = %.8x rsn = %.8x,%.8x,%.8x,%.8x \n",
            retrsn.ret,
            retrsn.rsn[0],
            retrsn.rsn[1],
            retrsn.rsn[2],
            retrsn.rsn[3]
            );
 
    return (compare_result);          /* Retern return code         */
} /* end of main */
 
/*===================================================================*/
/*      Subroutine to compare expected results(compare_buf)          */
/*      with actual results(err_msg) the "|" is used to signify      */
/*      an ignore compare and "?" is used to mark the end of string. */
/* Note: Compare starts using an index i=1 ie. the 2nd character     */
/*       because the 1st character was blanked out. ( NL x'15' )     */
/*===================================================================*/
 
 
int memc(char *comp_buf, char *rec_buf1)
{
 
 int j;
 int i;
 
  j = 0;
 
  for (i=1;
      ( (j==0) && (comp_buf[i] != '?') );
       i++ )
    {
      if( comp_buf[i] != '|' )                   /* Ignore compare  */
      {
        if( comp_buf[i] != rec_buf1[i])          /* compare ok ?    */
        {
          j++;                                   /* No              */
          printf( "MISCOMPARE !!!   \n" );
          printf( "comp_buf[%d] = %c\n", i, comp_buf[i] );
          printf( "rec_buf1[%d] = %c\n", i, rec_buf1[i] );
        }
        else
          ;
      }
      else
        ;                                       /* Else null        */
    }
 
 return (j);
}