![]() Chapter Contents |
![]() Previous |
![]() Next |
| Examples |
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| |
| 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.