|
View previous topic :: View next topic
|
| Author |
Message |
HenriqueS
New User
Joined: 17 Feb 2007 Posts: 30 Location: Brazil
|
|
|
|
Hello folks,
We have a Natural program that is supposed to call a C program. In the very beginning I struggled because the Natural manuals gave a sample that does not take CICS into consideration.
Then I got to know about the CICS storage areas and how does CICS behaves when switching from one program to another under the same task. It just wipes the command line arguments sent from the caller and puts to the TWA (the choice on which area is based on some Natural setting). Then calls the target program supplying just a transaction id.
Still, I got some Cobol examples of retrieving the calling parameters from the TWA and also returning from it. But I do not grasp Cobol well.
So, I ask if anyone does have any C sample of acessing the TWA area or at least some documentation that shows its structure. The "CICS Programming Reference" nor the "CICS Programming Guide" detail it.
*I got a very simple C sample of getting a pointer to the TWA, but in that sample, the programmer had to parse the whole area and break the data every n bytes to get what he wanted. The Cobol sample seemed more elegant but I did not get the point on it...
Thanks in advance. |
|
| Back to top |
|
 |
dick scherrer
Moderator Emeritus

Joined: 23 Nov 2006 Posts: 19243 Location: Inside the Matrix
|
|
|
|
Hello and welcome to the forums,
If you post the COBOL sample code, someone here may be able to clarify it for you. |
|
| Back to top |
|
 |
HenriqueS
New User
Joined: 17 Feb 2007 Posts: 30 Location: Brazil
|
|
|
|
Below is the Cobol example of a program that retrieves data from the TWA. These data, according to the docs, is pushed automatically when the caller program invokes (along with the parameters) this one.
| Quote: |
IDENTIFICATION DIVISION.
PROGRAM-ID. TABSUB.
REMARKS. THIS PROGRAM PERFORMS A TABLE LOOK-UP AND
RETURNS A TEXT MESSAGE.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 MSG-TABLE.
03 FILLER PIC X(15) VALUE 'MESSAGE1 '.
03 FILLER PIC X(15) VALUE 'MESSAGE2 '.
03 FILLER PIC X(15) VALUE 'MESSAGE3 '.
03 FILLER PIC X(15) VALUE 'MESSAGE4 '.
03 FILLER PIC X(15) VALUE 'MESSAGE5 '.
03 FILLER PIC X(15) VALUE 'MESSAGE6 '.
03 FILLER PIC X(15) VALUE 'MESSAGE7 '.
01 TAB REDEFINES MSG-TABLE.
03 MESSAGE OCCURS 7 TIMES PIC X(15).
LINKAGE SECTION.
01 TWA-DATA.
03 PARM-POINTER USAGE IS POINTER.
01 PARM-LIST.
03 DATA-LOC-IN USAGE IS POINTER.
03 DATA-LOC-OUT USAGE IS POINTER.
01 INPUT-DATA.
03 INPUT-NUMBER PIC 99.
01 OUTPUT-DATA.
03 OUTPUT-MESSAGE PIC X(15).
PROCEDURE DIVISION.
100-INIT.
EXEC CICS ADDRESS TWA(ADDRESS OF TWA-DATA) END-EXEC.
SET ADDRESS OF PARM-LIST TO PARM-POINTER.
SET ADDRESS OF INPUT-DATA TO DATA-LOCIN.
SET ADDRESS OF OUTPUT-DATA TO DATA-LOC-OUT.
200-PROCESS.
MOVE MESSAGE (INPUT-NUMBER) TO OUTPUT-MESSAGE.
300-RETURN.
EXEC CICS RETURN END-EXEC.
400-DUMMY.
GO-BACK.
|
I found a C sample here, tried to run it, but I recovered some unrecognizable data:
| Code: |
int main(int argc, char *argv ){
/* (int argc, char *argv ) */
printf("\nTran id: %s", argv 0 );
char twadata 255 ;
memset(twadata, 0, 255);
int *twa;
unsigned char *dados;
EXEC CICS ADDRESS TWA(twa);
dados = (char *) *((int *) *twa);
memset(twadata, '\0', sizeof(twadata));
memcpy(twadata, dados, 255);
printf("\nTWA = %s, %s, %s", &twadata, *twadata, twadata);
printf("\nTWA int = %i, %i, %i", &twadata, *twadata, twadata);
printf("\nTWA hex = %x, %x, %x", &twadata, *twadata, twadata);
}
|
Below the output:
| Code: |
TCP2 20070816155903 Tran id: TCP2
TCP2 20070816155903 TWA = & , , &
TCP2 20070816155903 TWA int = 428015264, 80, 28015264
TCP2 20070816155903 TWA hex = 1982fea0, 50, 1982fea0
|
I really expected to get a bigger sample, since the parameters passes to the called app have more than 128 bytes...
Also, I talked to some people and they said me is very hard to browse the TWA contents during the task, because it is short lived (lasts for the task duration) and is not logged, since it generates too much data in a production environment.
Any ideas? |
|
| Back to top |
|
 |
HenriqueS
New User
Joined: 17 Feb 2007 Posts: 30 Location: Brazil
|
|
|
|
I´ve made a new try, to check if anything was in the commarea. I did this sort of struct-based map according to a sample I found on the net...no success....
| Code: |
struct mystruct {
unsigned char lda_label[65];
unsigned char lda_ex_data[4];
int lda_tam_exp;
unsigned char lda_return[128];
};
static struct mystruct *twaarea;
static struct mystruct *cwaarea;
int main(int argc, char *argv ){
/* (int argc, char *argv ) */
printf("\nTran id: %s", argv 0 ); /* nome da transa o */
char twadata 255 ;
memset(twadata, 0, 255);
int *twa;
unsigned char *dados;
EXEC CICS ADDRESS TWA(twa);
dados = (char *) *((int *) *twa);
memset(twadata, '\0', sizeof(twadata));
memcpy(twadata, dados, 255);
printf("\nTWA = %s, %s, %s", &twadata, *twadata, twadata);
printf("\nTWA int = %i, %i, %i", &twadata, *twadata, twadata);
printf("\nTWA hex = %x, %x, %x", &twadata, *twadata, twadata);
EXEC CICS ADDRESS TWA(twaarea);
printf("\nNew TWA = %s", twaarea->lda_label);
printf("\nNew TWA = %s", twaarea->lda_ex_data);
printf("\nNew TWA = %i", twaarea->lda_tam_exp);
printf("\nNew TWA = %s", twaarea->lda_return);
EXEC CICS ADDRESS COMMAREA(cwaarea);
printf("\nNew CWA = %s", cwaarea->lda_label);
printf("\nNew CWA = %s", cwaarea->lda_ex_data);
printf("\nNew CWA = %i", cwaarea->lda_tam_exp);
printf("\nNew CWA = %s", cwaarea->lda_return);
}
|
Output...:
| Code: |
TCP2 20070816170850 Tran id: TCP2
TCP2 20070816170850 TWA = & , , &
TCP2 20070816170850 TWA int = 428015264, 80, 428015264
TCP2 20070816170850 TWA hex = 1982fea0, 50, 1982fea0
TCP2 20070816170850 New TWA = t
TCP2 20070816170850 New TWA =
TCP2 20070816170850 New TWA = 0
TCP2 20070816170850 New TWA =
TCP2 20070816170850 New CWA = t
TCP2 20070816170850 New CWA =
TCP2 20070816170850 New CWA = 0
TCP2 20070816170850 New CWA =
|
|
|
| Back to top |
|
 |
HenriqueS
New User
Joined: 17 Feb 2007 Posts: 30 Location: Brazil
|
|
|
|
For the good of mankind, my working implementation below, I hope someone one day someone using a search engine for help will reach this...
Acessing the TWA using C:
| Code: |
struct mystruct{
unsigned char lda_label[65];
int lda_tam_exp;
unsigned char lda_ex_data[128];
unsigned char lda_md_data[128];
unsigned char lda_return 10 ;
};
struct mystruct *twaarea;
int main(int argc, char *argv ){
/* argc and argv are overwritten by CICS, Natural or CICS (not sure) will
store the CALL parameters (made in the Natural program) in an area calles TWA.
Argc under CICS returns '1' and argv[0] returns the transaction id */
printf("\nTransaction id: %s", argv 0 );
int *twa;
unsigned char *data;
EXEC CICS ADDRESS TWA(twa);
data = (unsigned char *) *((int *) *twa); /* weird casting copied from a friend */
/* EIB is a memory area that contains status information about the context in
which the transaction is running. The example below shows getting the current
transaction id. Notice that if the pointer variable to this area was not created
before, the CICS translator solves this, freeing the programmer.
EXEC CICS ADDRESS EIB(dfheiptr);
printf("\nT id %s", dfheiptr->eibtrnid); */
twaarea=(struct mystruct*)data;
printf("\nTWA lda_label = %s", twaarea->lda_label);
printf("\nTWA lda_tam_exp = %02X", twaarea->lda_tam_exp);
printf("\nTWA lda_ex_data =");
for(int i=0;i<128;i++){
printf("%02X", twaarea->lda_ex_data[i]);
}
printf("\nTWA lda_md_data =");
for(int i=0;i<128;i++){
printf("%02X", twaarea->lda_md_data[i]);
}
/* Shows TWA contents, used for interprocess communication between a caller
Natural module and a called C module. It has the size of 1024 bytes, defined
on CICS for each transaction (custom up to 32kbytes). */
printf("\nFull hex dump =\n");
for(int i=0;i<1024;i++){
if((i+1)%40==0) printf("\n"); /* break line */
printf("%02X", *(data+i));
}
/* Send return back to the Natural module */
strcpy(twaarea->lda_return, "RETURN");
EXEC CICS RETURN;
return(0);
}
}
|
|
|
| Back to top |
|
 |
dick scherrer
Moderator Emeritus

Joined: 23 Nov 2006 Posts: 19243 Location: Inside the Matrix
|
|
|
|
Hello,
Thank you for posting your solution.
What sort of output did you get when you executed your code? |
|
| Back to top |
|
 |
dbzTHEdinosauer
Global Moderator

Joined: 20 Oct 2006 Posts: 6965 Location: porcelain throne
|
|
|
|
HenriqueS,
thx. That is what I call a keeper. Print to PDF, save on my pc. |
|
| Back to top |
|
 |
HenriqueS
New User
Joined: 17 Feb 2007 Posts: 30 Location: Brazil
|
|
|
|
I got the C field structures filled exactly as the Natural ones sent as parameter with the CALL statement. In the last two fields, since they are plain bytes, I get the hex dump of them.
In Natural: CALL MYCMODULE LOCALSTRT
where LOCALSTRT is called a "local" under natural, it is basically a struct that is defined somewhere...(the previous lines fill them).
There must be an exact data-type relation between the Natural and C types (order, data type and size).
There also may arise some data-alignment issues (when fitting the data into the C struct, the runtime may get lost trying to fit the data and do some shift left or shift left fitting. To deal with this, in the Natural "local" structure you may need to put a padding field between the ones with problem. I did this in my case, since the first field is a char[65] which is not divisible by 4 (4 is the minimum byte displacement in the z/OS C compiler according to the redbook).
The last printf shows the entire TWA as an hex dump just to check if Natural/CICS sent the "local" structure correctly to the TWA.
| dick scherrer wrote: |
Hello,
Thank you for posting your solution.
What sort of output did you get when you executed your code? |
|
|
| Back to top |
|
 |
dick scherrer
Moderator Emeritus

Joined: 23 Nov 2006 Posts: 19243 Location: Inside the Matrix
|
|
|
|
Cool - thanks
d |
|
| Back to top |
|
 |
|
|
 |
All times are GMT + 6 Hours |
|