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.