You can write a Rexx external function in C, have it process the parameters, and return data.
I found writing a program to do this was non trivial, and used bits of C I was not familiar with.
See Calling C from Rexx – accessing variables.
If you use the address… environment, the C program does not pass parameters using the normal “main” interface;
int main( int argc, char **argv ){}
because the parameters are passed in via register 1, and you need a different technique.
Header files
There are header files in SYS1.SIEAHDR.H for the Rexx facilities.
#include <irxefpl.h> // REXX External Functions Parameter List
#include <irxargtb.h> // REXX Argument Table control block mapping
#include <irxshvb.h> // REXX Shared Variable Request Block
#include <irxenvb.h> // REXX Environment Block
#include <irxexte.h> // REXX access to shared variables etc
Program for address link …
With this, the parameters are passed in one string. The program is given the address and the length of the string.
#pragma runopts(plist(os))
struct plistlink {
char ** pData;
int * len;
};
int main() {
struct plistlink * pLink = (struct plistlink *)__R1;
int k = * pLink -> len;
char * pc = *pLink -> pData;
printf("plistlink length %i %.*s\n",k,k,pc);
return 0;
}
The important things to note here are
- #pragma runopts(plist(os)) this says that the parameters are in standard z/OS parameter format based off register 1.
- int main() this defines the entry point, and sets up the C environment.
- __R1 is a special #define which returns the value of register one on entry to the routine.
- struct plistlink * pLink = (struct plistlink *)__R1; defines the input parameter list.
Program for address linkmvs…
Thanks to David Crayford for his assistance in this.
With address linkmvs the specified parameters are treated as variables and their values substituted. If a variable does not exist with the name, the value is passed as-is.
On entry register 1 points to a list of pointers to data. The last element in the list has the top bit on. Process the list until the top bit is on. For example for the parameter list with values “AAA BB C” (which are not substituted)
- addr1 -> 0X0003″AAA”
- addr2 -> 0X0002″BB”
- *addr3 -> 0x001″C”
where * has the top bit on.
If there are no parameters the parameter list is
- *addr -> 0x0000…
#pragma runopts(plist(os))
#define EOL(a) (((unsigned int)a) & 0x80000000)
struct plist {
short len;
char parm[0];
};
int main() {
for ( i = 0; ; i++ ) {
struct plist *p = __osplist[i];
if ( p->len ==0 ) printf("parm %i is Null\n",i);
if ( p->len > 0 )
printf( "parm %i >%.*s<\n",i, p->len, p->parm );
if ( EOL(__osplist[i]) ) break;
}
Where __osplist is a special #define for the parameters based off register 1.
Return code
In both cases you can use the C return … to return an integer value.
One thought on “Calling C from Rexx – writing the program.”