/*---------------------------------------------------------------------+ | Copyright (c) 1995, SAS Institute Inc. | | Unpublished - All Rights Reserved | | S A S / C S A M P L E | | | | | | NAME: SASCBRW | | LANGUAGE: C (CICS) | | PURPOSE: Traditional CICS FILEA sample program used in | | Appendix 1, Second Edition, of the SAS/C CICS User's | | Guide. See this appendix for a more detailed | | explanation of the SASCALL, SASCMNU, SASCBRW samples | | as well as the SASCAMA, SASCAMB, and SASCAMC BMS | | maps. | | MVS - | | PREPROCESS, COMPILE, LINK: Submit prefix.SAMPLE.AUX(SASCBRW) | | where "prefix" is the installation defined | | high-level qualifier for the SAS/C product. | | EXECUTE: See Appendix 1, Second Edition, of the SAS/C CICS | | User's Guide for additional information. Use the | | sample PPT input (prefix.SAMPLE.AUX(SASCTBLS) to | | define the resources to CICS. | | TSO - | | PREPROCESS: LCCCP CLIST | | COMPILE: LC370 CLIST using the RENT and EXTNAME options. | | LINK: CLK370B CLIST using the CICS, and RENT options. | | EXECUTE: see EXECUTE under MVS above | | CMS - | | PREPROCESS: LCCCP EXEC | | COMPILE: LC370 EXEC using the RENT and EXTNAME options. | | CLINK: CLINK EXEC using the CICS option; resulting object code| | must be ported to an MVS operating system for final | | link-editing with the CICS Execution Interface stub | | routines. | | LINK: Use the LCCCXXL cataloged procedure using the NOCLINK | | and RENT options. Input must be specified via the | | SYSLIN DD statement, not the SYSIN DD statement. | | EXECUTE: see EXECUTE under MVS above | | | +---------------------------------------------------------------------*/ #include /* Useful BMS definitions */ #include /* C struct defining Map A, produced by DSECT2C*/ #include /* C struct defining Map C, produced by DSECT2C*/ #include /* Standard C type header */ #include /* Standard C string handling header */ /* General purpose variables */ short i; char rid[6] = "000000"; /* Record key, the account number */ char ridb[6] = "000000"; /* Record key, used in backward paging */ char ridf[6] = "000000"; /* Record key, used in forward paging */ char currop; /* Indicates in which direction the */ /* browsing is currently moving; F or B */ char lastop; /* Indicates the previous browsing direction*/ char status; /* File status, 'H', 'L', or ' ' */ char messages[39]; /* Message holding area */ short comlen; /* Length of CICS commarea */ char keynum[6]; /* Record key, the account number */ /* The 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; /* Function prototypes */ void errors(void); void smnu(void); void smsg(void); void not_found(void); void build_next(void); void build_prev(void); void page_forward(void); void page_backward(void); void receive(void); void too_high(void); void too_low(void); /* The main function begins here */ void main() { /* Prepare to handle paging requests via PF-keys */ EXEC CICS HANDLE AID CLEAR(smsg) PF1(page_forward) PF2(page_backward); /* Prepare to handle error conditions */ EXEC CICS HANDLE CONDITION ERROR(errors) MAPFAIL(smsg) NOTFND(not_found); /* Read the initial screen */ EXEC CICS RECEIVE MAP("SASCAGA"); /* Was a starting account number provided? */ if (memcmp(sascaga.keyl,"\0\0",2) == 0) { /* No, so default to zero */ strcpy(rid,"000000"); strcpy(ridf,"000000"); } else { /* Yes, so validate all of its digits */ 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 starting account number for use in either direction */ memcpy(rid,sascaga.keyi,6); memcpy(ridf,sascaga.keyi,6); memcpy(ridb,sascaga.keyi,6); } /* Initiate the VSAM browse file operation */ EXEC CICS STARTBR DATASET("FILEA") RIDFLD(rid); /* Is the current account number 999999(i.e., the absolute maximum)?*/ if (memcmp(rid,"999999",6) != 0) { /* No, so page forward */ page_forward(); } else { /* Yes, so set the status to "High" and page backward */ status = 'H'; page_backward(); } receive(); /* there is no return from receive() */ } /* end of main function */ /* This function processes a forward paging request */ void page_forward() { currop = 'F'; /* Set the indicator to forward paging mode */ /* Prepare to handle reading past the end of the file */ EXEC CICS HANDLE CONDITION ENDFILE(too_high); memset(&sascagc,'\0',SASCAGCE); /* Clear Map C */ memcpy(rid,ridf,6); build_next(); /* Cause more records to be read */ memcpy(ridf,rid,6); EXEC CICS SEND MAP("SASCAGC") ERASE; /* Display Map C */ } /* end of page_forward function */ /* This function processes a backward paging request */ void page_backward() { currop = 'B'; /* Set the indicator to backward paging mode */ /* Prepare to handle reading before the beginning of the file */ EXEC CICS HANDLE CONDITION ENDFILE(too_low); memset(&sascagc,'\0',SASCAGCE); /* Clear map C */ memcpy(rid,ridb,6); memcpy(ridf,ridb,6); /* READPREV commands will re-read the last record that was */ /* read by a READNEXT command, so do an extra READPREV to */ /* account for this behaviour */ if ((lastop == 'F') && (status != 'H')) { EXEC CICS READPREV DATASET("FILEA") INTO(&filea) RIDFLD(rid) LENGTH(sizeof(struct FILEA)) KEYLENGTH(sizeof(rid)); } build_prev(); /* Cause more records to be read */ memcpy(ridb,rid,6); EXEC CICS SEND MAP("SASCAGC") ERASE; /* Display Map C */ } /* end of page_backward function */ /* This function controls the continual processing of page requests. */ /* Keep in mind that the user could decide to press PF1 or PF2 at */ /* anytime. Pressing these keys is an implicit request for forward */ /* or backward paging, respectivly. When a PF-key is pressed, the */ /* appropriate function is driven; then control returns to the next */ /* executable statement within the for(;;) loop. From that point */ /* normal 'F'/'B' -key processing continues. */ void receive() { for(;;) /* Continue to process page requests until CLEAR is pressed */ /* or the user does not enter a direction indicator */ { lastop = currop; /* Remember which direction the reading is going */ /* Read the latest screen */ EXEC CICS RECEIVE MAP("SASCAGC"); /* When the MAPFAIL condition occurs here, the browse operation will*/ /* end. smsg() will be driven. */ status = ' '; /* Did the user enter a forward page request by keying an 'F' ? */ if (memcmp(sascagc.diri,"F",1) == 0) { /* Yes, so cause forward paging to occur */ page_forward(); } /* Did the user enter a backward page request by keying a 'B' ? */ else if (memcmp(sascagc.diri,"B",1) == 0) { /* Yes, so cause backward paging to occur */ page_backward(); } else { /* Neither 'F' nor 'B' was keyed, so re-send the map */ /* This will eventually result in a MAPFAIL condition*/ /* and therefore the end of the browse operation */ EXEC CICS SEND MAP("SASCAGC"); } } /* end of for(;;) loop */ } /* end of receive() */ /* This function is called when a read past the end of the file */ /* is attempted. */ void too_high() { status = 'H'; /* Set the status so that further reads are prevented */ memcpy(ridf,rid,6); memcpy(ridb,rid,6); sascagc.diro = ' '; /* Indicate that forward paging has ceased */ strcpy(sascagc.msg1o,"Hi-End of File"); /* Prepare an informative msg */ sascagc.msg1a= DFHBMASB; } /* end of too_high */ /* This function is called when a read before the beginning of */ /* the file is attempted. */ void too_low() { status = 'L'; /* Set the status so that further reads are prevented */ strcpy(ridf,"000000"); strcpy(ridb,"000000"); sascagc.diro = ' '; /* Indicate that backward paging has ceased */ strcpy(sascagc.msg2o,"Lo-End of File"); /* Prepare an informative msg */ sascagc.msg2a = DFHBMASB; } /* end of too_high */ /* This function is called when the specified starting account */ /* number is not found. The VSAM browse operation is ended */ /* and appropriate messages are prepared. */ void not_found() { strcpy(messages,"End of File - Please Restart"); EXEC CICS ENDBR DATASET("FILEA"); smnu(); /* no return from smnu() */ } /* end of not_found() */ /* This function prepares an informative message and calls smnu */ void smsg() { strcpy(messages,"Press CLEAR to Exit"); smnu(); /* no return from smnu() */ } /* end of smsg() */ /* This function is called when a severe and unrecoverable error */ /* is detected. It causes a CICS transaction dump to be taken */ /* and prepares an error message. */ void errors() { EXEC CICS DUMP DUMPCODE("ERRS"); strcpy(messages,"Transaction Terminated"); smnu(); /* no return from smnu() */ } /* end of errors() */ /* This function causes the main menu to be displayed on the screen */ /* and returns control to CICS */ void smnu() { memset(&sascaga,'\0',SASCAGAE); /* Clear Map A */ sascaga.msga = DFHBMASB; memcpy(sascaga.msgo,messages,strlen(messages)); /* Move the message */ /* to the map */ memset(messages,'\0',39); /* Clear the message variable */ EXEC CICS SEND MAP("SASCAGA") ERASE; EXEC CICS RETURN; } /* end of smnu() */ /* This function performs up to 4 READNEXT commands to fill the */ /* screen in a forward paging mode. */ void build_next() { int i; for(i=1; i<= 4; i++) /* 4 iterations to fill the screen */ { EXEC CICS READNEXT DATASET("FILEA") INTO(&filea) RIDFLD(rid) LENGTH(sizeof(struct FILEA)) KEYLENGTH(sizeof(rid)); if (status == 'H') /* If we read past the end of the file, STOP! */ break; switch(i) { case 1: { /* Move the record fields to line 1 of the map */ memcpy(sascagc.number1o,filea.numb,sizeof(filea.numb)); memcpy(sascagc.name1o,filea.name,sizeof(filea.name)); memcpy(sascagc.amount1o,filea.amount,sizeof(filea.amount)); memcpy(ridb,rid,6); break; } /* end of case: 1 */ case 2: { /* Move the record fields to line 2 of the map */ memcpy(sascagc.number2o,filea.numb,sizeof(filea.numb)); memcpy(sascagc.name2o,filea.name,sizeof(filea.name)); memcpy(sascagc.amount2o,filea.amount,sizeof(filea.amount)); break; } /* end of case: 2 */ case 3: { /* Move the record fields to line 3 of the map */ memcpy(sascagc.number3o,filea.numb,sizeof(filea.numb)); memcpy(sascagc.name3o,filea.name,sizeof(filea.name)); memcpy(sascagc.amount3o,filea.amount,sizeof(filea.amount)); break; } /* end of case: 3 */ case 4: { /* Move the record fields to line 4 of the map */ memcpy(sascagc.number4o,filea.numb,sizeof(filea.numb)); memcpy(sascagc.name4o,filea.name,sizeof(filea.name)); memcpy(sascagc.amount4o,filea.amount,sizeof(filea.amount)); break; } /* end of case: 4 */ } /* end of switch(i) */ } /* end of for loop */ } /* end of build_next() */ /* This function performs up to 4 READPREV commands to fill the */ /* screen in a backward paging mode. */ void build_prev() { int i; for(i=1; i <= 4; i++) /* 4 iterations to fill the screen */ { EXEC CICS READPREV DATASET("FILEA") INTO(&filea) RIDFLD(rid) LENGTH(sizeof(struct FILEA)) KEYLENGTH(sizeof(rid)); if (status == 'L') /* If we read before the beginning of the */ break; /* file, STOP! */ switch(i) /* The records will be displayed in ASCECNDING order */ { /* So, put the last one read at the top of the screen*/ case 4: { /* Move the record fields to line 1 of the map */ memcpy(sascagc.number1o,filea.numb,sizeof(filea.numb)); memcpy(sascagc.name1o,filea.name,sizeof(filea.name)); memcpy(sascagc.amount1o,filea.amount,sizeof(filea.amount)); break; } /* end of case: 4 */ case 3: { /* Move the record fields to line 2 of the map */ memcpy(sascagc.number2o,filea.numb,sizeof(filea.numb)); memcpy(sascagc.name2o,filea.name,sizeof(filea.name)); memcpy(sascagc.amount2o,filea.amount,sizeof(filea.amount)); break; } /* end of case: 3 */ case 2: { /* Move the record fields to line 3 of the map */ memcpy(sascagc.number3o,filea.numb,sizeof(filea.numb)); memcpy(sascagc.name3o,filea.name,sizeof(filea.name)); memcpy(sascagc.amount3o,filea.amount,sizeof(filea.amount)); break; } /* end of case: 2 */ case 1: { /* Move the record fields to line 4 of the map */ memcpy(sascagc.number4o,filea.numb,sizeof(filea.numb)); memcpy(sascagc.name4o,filea.name,sizeof(filea.name)); memcpy(sascagc.amount4o,filea.amount,sizeof(filea.amount)); break; } /* end of case: 1 */ } /* end of switch(i) */ } /* end of for loop */ } /* end of build_prev() */