Chapter Contents

Previous

Next
Examples

SASCALL: Perform Inquiry and Update Functions

The SASCALL program corresponds to the IBM programs DFH$xALL (where x has the same values as discussed in the previous section). It is the program that does the individual record inquiry, adds new records, and updates old ones.

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|                                                            |
|                     S A S / C  S A M P L E                 |
|                                                            |
|         NAME: SASCALL                                      |
|      PURPOSE: Traditional CICS FILEA sample program        |
| INSTALLATION: Assemble the associated BMS maps             |
|               (SASCAMA, SASCAMB) and then use DSECT2C to   |
|               create C headers that define those maps.     |
|               Use the sample PPT input (SASCTBLS) to       |
|               define the resources to CICS.                |
|      COMPILE: Use the CICS translator procedure LCCCPCL    |
|      EXECUTE: Via transaction SMNU                         |
|        USAGE:                                              |
| SYSTEM NOTES:                                              |
|                                                            |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include <dfhbmsca.h>   /* useful BMS definitions */

   /* C struct defining Map A, produced by DSECT2C */
#include <sascaga.h>

   /* C struct defining Map B, produced by DSECT2C */
#include <sascagb.h>
#include <string.h>     /* standard string header file */

   /* general-purpose variables */
char messages[39];      /* message-holding area */

   /* The following two strings are used to validate input data. */
char *valid_name_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ .-'";
char *valid_amount_chars = "0123456789.$";

short comlen;           /* length of the CICS COMMAREA */
char keynum[6];         /* record key, the account number */
int i;

   /* FILEA record layout */
struct FILEA{
   char stat;
   char numb[6];
   char name[20];
   char addrx[20];
   char phone[8];
   char datex[8];
   char amount[8];
   char comment[9];
} filea;


struct FILEA commarea;  /* definition of the COMMAREA */

   /* function prototypes */
void data_error(void);
void map_build(void);
void map_send(void);
void cics_control(void);
void notmodf(void);
void duprec(void);
void badleng(void);
void badchars(void);
void notfound(void);
void mfail(void);
void errors(void);
void smnu(void);

   /* The main function begins here. */
main(struct EIBLK *eib_pointer, void *commarea_pointer)

   /* Note that __commptr, __eibptr, and __dibptr are             */
   /* implementation-provided global external variables available */
   /* to all SAS/C CICS programs. You can also, as demonstrated   */
   /* in this program, define your own pointers to these commonly */
   /* used areas.                                                 */
{
      /* Second time through? */
   if (commarea_pointer) goto read_input;

   /* If first time through, present the initial screen. */
   EXEC CICS HANDLE CONDITION ERROR(errors) MAPFAIL(mfail);

   EXEC CICS RECEIVE MAP("SASCAGA");

      /* A key must be provided. */
   if (memcmp(sascaga.keyl,"\0 \0",2) == 0){
      badleng();         /* no return from badleng() */
   }

      /* Verify that all six digits of the key are numeric. */
   for(i=0;i<=5;i++){
      if (isdigit((int) sascaga.KEYI[i]) == 0){
         strcpy(messages,"ACCOUNT NUMBER MUST BE NUMERIC");
         smnu();          /* There is no return from smnu(). */
      }
   }

      /* Save the key. */
   memcpy(keynum,sascaga.KEYI,sizeof(sascaga.KEYI));
   memset(&sascagb,'\0',SASCAGBE);  /* Clear the map. */

      /* Is this an add? */
   if (memcmp(eib_pointer->EIBTRNID,"SADD",4) == 0){

         /* Set up Map B for an add operation. */
      strcpy(sascagb.titleo,"FILE ADD");
      strcpy(sascagb.msg3o,"ENTER DATA AND PRESS ENTER KEY");
      memcpy(&sascagb.numbo,sascaga.KEYI,sizeof(sascaga.KEYI));
      memcpy(&commarea.numb,sascaga.KEYI,sizeof(sascaga.KEYI));
      sascagb.amounta = DFHBMUNN;

         /* The COMMAREA contains only status and account no. */
      comlen = 7;
      map_send();         /* Display Map B. */
      cics_control();     /* Pass control back to CICS. */
   }
   else

         /* Is this a query? */
      if (memcmp(eib_pointer->EIBTRNID,"SINQ",4) == 0){

            /* Try to read the record specified, but be */
            /* prepared if it is not found.             */
         EXEC CICS HANDLE CONDITION NOTFND(notfound);

         EXEC CICS READ DATASET("FILEA") INTO(&filea)
                   RIDFLD(keynum) LENGTH(sizeof(struct FILEA))
                   KEYLENGTH(sizeof(keynum));

            /* The record was found, so set up Map B for a query. */
         strcpy(sascagb.titleo,"FILE INQUIRY");
         strcpy(sascagb.msg3o,"PRESS ENTER TO CONTINUE");

            /* Move the data from the record */
            /* area into the map fields.     */

         map_build();

            /* Protect all the fields. */
         sascagb.namea    = DFHBMPRO;
         sascagb.addra    = DFHBMPRO;
         sascagb.phonea   = DFHBMPRO;
         sascagb.datea    = DFHBMPRO;
         sascagb.amounta  = DFHBMPRO;
         sascagb.commenta = DFHBMPRO;
         map_send();       /* Display Map B. */

            /* Return to CICS and display the main menu again. */
         EXEC CICS RETURN TRANSID("SMNU");
   }
   else

            /* Is this an update? */
         if (memcmp(eib_pointer->EIBTRNID,"SUPD",4) == 0){

               /* Try to read the record specified, but be */
               /* prepared if it is not found.             */
            EXEC CICS HANDLE CONDITION NOTFND(notfound);

            EXEC CICS READ DATASET("FILEA") INTO(&filea)
                      RIDFLD(keynum) LENGTH((short) sizeof(struct FILEA))
                      KEYLENGTH((short) sizeof(keynum));

            /* The record was found, so set up Map B for an update. */
         strcpy(sascagb.titleo,"FILE UPDATE");
         strcpy(sascagb.msg3o,"CHANGE FIELDS AND PRESS ENTER");

            /* Save the record in the COMMAREA for later comparison. */
         memcpy(&commarea,&filea,sizeof(struct FILEA));

         map_build();      /* Move the data from the record */
                           /*  area into the map fields.    */

         map_send();       /* Display Map B. */

         comlen = 80;      /* The COMMAREA contains the entire record. */

         cics_control();   /* Pass control back to CICS. */
      }
      else{
         errors();         /* The transaction ID was not recognized. */
                           /* There is no return from errors().      */
      }

   /* Things begin to happen the second time through. */
read_input:

   /* Retrieve the COMMAREA. */
memcpy(&commarea,commarea_pointer,sizeof(commarea));

   /* Prepare to handle error conditions. */
EXEC CICS HANDLE CONDITION MAPFAIL(notmodf) DUPREC(duprec)
                           ERROR(errors) NOTFND(notfound);

   /* Read the input map. */
EXEC CICS RECEIVE MAP("SASCAGB");

   /* Is this an update? */
if (memcmp(eib_pointer->EIBTRNID,"SUPD",4) == 0){

      /* Try to read the specified record with intent to update. */
   EXEC CICS READ UPDATE DATASET("FILEA") INTO(&filea)
             RIDFLD(commarea.numb)
             LENGTH((short) sizeof(struct FILEA))
             KEYLENGTH((short) sizeof(commarea.numb));

      /* If the record just read does not exactly match the */
      /* one read during the first pass, another user must  */
      /* have updated the record while this transaction was */
      /* rolled out.  If so, refuse to update the record.   */                                                           */
   if (memcmp(&filea,&commarea,sizeof(struct FILEA))){

         /* Refuse to update and prepare screen for another attempt. */
      strcpy(sascagb.msg1o,"RECORD UPDATED BY OTHER USER, TRY AGAIN");
      sascagb.msg1a = DFHBMASB;
      sascagb.msg3a = DFHPROTN;

         /* Move the data from the record area into the map fields. */
      map_build();

         /* Resend only the data portion of the map. */
      EXEC CICS SEND MAP("SASCAGB") DATAONLY;

         /* Make sure that the same record is used */
         /* during the next pass.                  */
      commarea = filea;
      comlen = 80;
      cics_control();    /* Pass control back to CICS. */
   }

   else{

         /* It is OK to update the record.  Note on the next screen. */
      filea.stat = 'U';
      strcpy(messages,"RECORD UPDATED");
   }
}
      /* Is this an add? */
   else
      if (memcmp(eib_pointer->EIBTRNID,"SADD",4) == 0) {

            /* Yes, it's an add.  Note on the next screen. */
         filea.stat = 'A';
         strcpy(messages,"RECORD ADDED");
      }
   else{

         /* The transaction ID was not recognized. There is */
         /* no return from errors().                        */
      errors();
   }

   /* Check to see if any of the fields were modified. */
if (memcmp(sascagb.namel,"\0 \0",2)    == 0 &&
    memcmp(sascagb.addrl,"\0 \0",2)   == 0 &&
    memcmp(sascagb.phonel,"\0 \0",2)  == 0 &&
    memcmp(sascagb.datel,"\0 \0",2)   == 0 &&
    memcmp(sascagb.amountl,"\0 \0",2) == 0 &&
    memcmp(sascagb.commentl,"\0 \0",2) == 0){

       /* No fields were modified, so take no action. */
    notmodf();    /* There is no return from notmodf(). */
}

   /* Is this an add? */
if (memcmp(eib_pointer->EIBTRNID,"SADD",4) == 0){

      /* It's an add, so validate the name field. */
   for(i=0;i < *(short *) sascagb.namel ;i++){
      if (strchr(valid_name_chars,sascagb.NAMEI[i]) == 0){
         data_error();  /* There is no return from data_error. */
      }
   }
      /* Enforce the account number to be what */
      /* was originally stated.                */
   memcpy(&filea.numb,&commarea.numb,sizeof(commarea.numb));
   }
else

      /* Is this an update? */
   if (memcmp(eib_pointer->EIBTRNID,"SUPD",4) == 0){

         /* It's an update, so validate the name */
         /* field if it was changed.             */
      if (memcmp(sascagb.namel,"\0 \0",2) != 0){
         for(i=0;i < *(short *) sascagb.namel ;i++){
            if (strchr(valid_name_chars,sascagb.NAMEI[i]) == 0){
               data_error();  /* There is no return from data_error. */
            }
         }
      }

         /* Also, validate the amount field if it was changed. */
      if (memcmp(sascagb.amountl,"0",2) != 0){
         for(i=0;i < *(short *) sascagb.amountl ;i++){
            if (strchr(valid_amount_chars,sascagb.AMOUNTI[ ]= 0){
               data_error();  /* There is no return from data_error. */
            }
      }
   }
}

   /* Update the record area with any fields that */
   /* were changed on screen.                     */
if (memcmp(sascagb.namel,"\0 \0",2) != 0){
   memcpy(&filea.name,sascagb.nameo,sizeof(sascagb.nameo));
}
if (memcmp(sascagb.addrl,"\0 \0",2) !=0){
   memcpy(&filea.addrx,sascagb.addro,sizeof(sascagb.addro));
}
if (memcmp(sascagb.phonel,"\0 \0",2) !=0){
   memcpy(&filea.phone,sascagb.phoneo,sizeof(sascagb.phoneo));
}
if (memcmp(sascagb.datel,"\0 \0",2) !=0){
   memcpy(&filea.datex,sascagb.dateo,sizeof(sascagb.dateo));
}
if (memcmp(sascagb.amountl,"\0 \0",2) !=0){
   memcpy(&filea.amount,sascagb.amounto,sizeof(sascagb.amounto));
}
else{

      /* For an add, fill in the default amount. */
   if (memcmp(eib_pointer->EIBTRNID,"SADD",4) == 0){
      strcpy(filea.amount,"$0000.00");
   }
}
if (memcmp(sascagb.commentl,"\0 \0",2) !=0){
   memcpy(&filea.comment,sascagb.commento,sizeof(sascagb.commento));
}

   /* If this is an update, rewrite the record to the file. */
   /* If this is an add, write the record to the file for   */
   /* the first time.                                       */
if (memcmp(eib_pointer->EIBTRNID,"SUPD",4) == 0){
   EXEC CICS REWRITE DATASET("FILEA") FROM(&filea)
                     LENGTH((short) sizeof(filea));
}
else{
   EXEC CICS WRITE DATASET("FILEA") FROM(&filea)
                   RIDFLD(commarea.numb) LENGTH((short) sizeof(filea));
}
smnu();            /* There is no return from smnu(). */
}                  /* End of main() */

   /* The data_error function is called when invalid */
   /* data is entered in one of the Map B fields.    */
   /* The data error message is added, and the       */
   /* screen is refreshed for another attempt.       */
void data_error()
{
   sascagb.msg3a    = DFHBMASB;
   strcpy(sascagb.msg3o,"DATA ERROR - CORRECT AND PRESS ENTER");
   sascagb.amounta  = DFHUNNUM;
   sascagb.namea    = DFHBMFSE;
   sascagb.addra    = DFHBMFSE;
   sascagb.phonea   = DFHBMFSE;
   sascagb.datea    = DFHBMFSE;
   sascagb.commenta = DFHBMFSE;

   EXEC CICS SEND MAP("SASCAGB") DATAONLY;

   /* Note that in the following statement, the */
   /* implementation-defined global external    */
   /* variable _eibptr is used instead of the   */
   /* application-defined local variable        */
   /* eib_pointer from main().                  */
if (memcmp(_eibptr->EIBTRNID,"SADD",4) == 0){
   comlen = 7; /* If it's an add, only the account number is passed. */
}
else{
   comlen = 80; /* Otherwise, the entire record is passed. */
}
cics_control();      /* Pass control back to CICS. */
}                    /* end of data_error() */

   /* This function moves all the fields from the */
   /* record area into the map areas.             */
void map_build(void)
{
   memcpy(sascagb.numbo,filea.numb,sizeof(filea.numb));
   memcpy(sascagb.nameo,filea.name,sizeof(filea.name));
   memcpy(sascagb.addro,filea.addrx,sizeof(filea.addrx));
   memcpy(sascagb.phoneo,filea.phone,sizeof(filea.phone));
   memcpy(sascagb.dateo,filea.datex,sizeof(filea.datex));
   memcpy(sascagb.amounto,filea.amount,sizeof(filea.amount));
   memcpy(sascagb.commento,filea.comment,sizeof(filea.comment));
   return;
}      /* end of map_build() */



   /* This function displays Map B on the screen. */
void map_send(void)
{
   EXEC CICS SEND MAP("SASCAGB") ERASE;
return;
}      /* end of map_send() */

   /* This function returns control to CICS.  It causes */
   /* the same transaction to be reinitiated with a     */
   /* COMMAREA.  This is commonly known as a            */
   /* pseudo-conversational rollout.                    */
void cics_control(void)
{

   /* Note that in the following statement, the */
   /* implementation-defined global external    */
   /* variable _eibptr is used instead of the   */
   /* application-defined local variable        */
   /* eib_pointer from main()/                  */
EXEC CICS RETURN TRANSID(_eibptr->EIBTRNID) COMMAREA(&commarea)
                 LENGTH(comlen);
}  /* end of cics_control() */

   /* This function prepares an error message and calls smnu(). */
void notmodf(void)
{
   strcpy(messages,"RECORD NOT MODIFIED");
   smnu();     /* There is no return from smnu(). */
}              /* end of notmodf() */

   /* This function prepares an error message and calls smnu(). */
void duprec(void)
{
   strcpy(messages,"DUPLICATE RECORD");
   smnu();     /* There is no return from smnu(). */
}              /* end of duprec() */

   /* This function prepares an error message and calls smnu(). */
void badleng(void)
{
   strcpy(messages,"PLEASE ENTER AN ACCOUNT NUMBER");
   smnu();     /* There is no return from smnu(). */
}              /* end of badleng() */

   /* This function prepares an error message and calls smnu(). */
void badchars(void)
{
   strcpy(messages,"ACCOUNT NUMBER MUST BE NUMERIC");
   smnu();     /* There is no return from smnu(). */
}              /* end of badchars() */

   /* This function prepares an error message and calls smnu(). */
void notfound(void)
{
   strcpy(messages,"INVALID NUMBER - PLEASE REENTER");
   smnu();     /* There is no return from smnu(). */
}              /* end of notfound() */

   /* This function prepares an informational message */
   /* and calls smnu().                               */
void mfail(void)
{
   strcpy(messages,"PRESS CLEAR TO EXIT");
   smnu();     /* There is no return from smnu(). */
}              /* end of mfail() */

   /* This function prepares an error message and calls smnu(). */
void errors(void)
{
   EXEC CICS DUMP DUMPCODE("ERRS"); /* Cause a transaction dump. */
   strcpy(messages,"TRANSACTION TERMINATED");
   smnu();     /* There is no return from smnu(). */
}              /* end of errors() */

   /* This function displays the main menu on the screen. */
void smnu(void)
{
   memset(&sascaga,',SASCAGAE);  /* Clear Map A. */

      /* Set the message attribute byte. */
   sascaga.msga = DFHBMASB;

      /* Move the message. */
   memcpy(&sascaga.msgo,&messages,strlen(messages));

      /* Send the map and return to CICS.*/
   EXEC CICS SEND MAP("SASCAGA") ERASE;
   EXEC CICS RETURN;

}              /* end of smnu() */


Chapter Contents

Previous

Next

Top of Page

Copyright © 2001 by SAS Institute Inc., Cary, NC, USA. All rights reserved.