/*---------------------------------------------------------------------+
| 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 <dfhbmsca.h> /* Useful BMS definitions */
#include <sascaga.h> /* C struct defining Map A, produced by DSECT2C*/
#include <sascagc.h> /* C struct defining Map C, produced by DSECT2C*/
#include <ctype.h> /* Standard C type header */
#include <string.h> /* 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' <ENTER>-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() */
|