MVS/zOS: Calling C Language from COBOL

As I promissed in a previous post, I will now give you an example of some C code in the mainframe, and mainly how to call from Cobol to C and deal with Cobol copybooks inside C.

First of all, a description of my environment:

  • AD/Cycle C/370 V1R2 (note it’s old - released in 1994 - there are new versions)
  • MVS (3.9 if I remember correctly)
  • VS COBOL II (3.2 I guess)

Generally speaking, every MVS or z/OS should have a C compiler. If it doesn’t, there are some free GCC ports to the mainframe ( SPFTOOLS, GCCESA). Since C has a long padronization history, there shouldn’t be many differences about code from my versions to yours.

Let’s begin with a simple example:

#include 
#include 
#pragma linkage(my_entrypoint, COBOL)
 
/* The linkage directive explains that my_entrypoint will be callable by a COBOL module */
 
/* prototypes */
void func1(char* ent);
void func2(char* ent);
 
/**********************************************
 Main entry-point
**********************************************/
void my_entrypoint(char* ent) {
 int func;
 func = *((int*)(ent+0));
 
 switch(func) {
 case 1:
 func1(ent);
 break;
 case 2:
 func2(ent);
 break;
 default:
 break;
 }
 return;
}
 
void func1(char *ent) {
 *((double*)(ent+12)) = log(*((double*)(ent+4)));
}
 
void func2(char *ent) {
 *((double*)(ent+12)) = log10(*((double*)(ent+4)));
}
 
 
/* End. */

Explanation: my_entrypoint is the only entry-point public to COBOL. It receives a cobol copybook (which in general words is just a byte buffer), and reads an int (see the pointer typecasting) from the byte buffer in the first position (offset 0). That int indicates what type of function (method) the C module should perform. Then, acording to this indicator, we call the apropriate method passing the same byte buffer we received.

Note that the copybook from cobol comes as a by-reference parameter (pointer to char array).

Then, each of our methods work reading and writing variables in the bytebuffer (char array). Note that both of my methods are reading a double from offset 4 (which is right after our int indicator), and writing a double to offset 8 (which is right after the double we have just read).

This method, using offsets, ensures us that we are dealing with the correct variable in the cobol copybook. Other methods rely on the byte-alignment that the compiler does, and suggest you to use directives to force the byte-alignment, then tell you to map each cobol copybook field to a c parameter inside a struct (then you would receive a pointer to that struct). I don’t like that method, and didn’t have a good experience with it either.

In that example, our cobol call should use a copybook like this:

01 BOOK-LN.
 03 FILLER PIC S9(9) COMP VALUE 1.
 03 LN-INPUT COMP-2 .
 03 LN-OUTPUT COMP-2 .

And the dynamic-call (with the module name declared in the working section) should be:

MOVE input TO LN-INPUT
CALL modulename USING BOOK-LN

And the result would be in LN-OUTPUT field.

I’ll write some more tips in the next post.

Hope you enjoy.

comments powered by Disqus