kenneth kahn - 2004-04-27

I've created an external REXX function library to act as a 'glue module' to an existing shared library (both libraries are available on AIX, Solaris, HP-UX and Linux).  Some of the API's in the shared library return a pointer to storage area that the API fills in with API specific data.

The REXX function library maps these API's to a REXX function via RexxRegisterFunctionExe as follows:

   RexxRegisterFunctionExe("get_CB",(PFN)RX_get_CB);

   char Buffer[512];
   extern int get_CB(char *);

   APIRET RX_get_CB(PSZ fct_name,ULONG ArgC,RXSTRING ArgV[],
                    PSZ Queue_Name,PRXSTRING RetStr) {
     SHVBLOCK shvb;
     memset(Buffer,0,512);
     get_CB(Buffer);
     /* return Buffer to REXX program via variable pool using REXX variable ArgV[0] */
     shvb.shvnext            = NULL;                 
     shvb.shvname.strptr     = (char *)ArgV[0].strptr;      
     shvb.shvname.strlength  = strlen(ArgV[0].strptr);     
     shvb.shvvalue.strptr    = (char *)Buffer;    
     shvb.shvvalue.strlength = 512;     
     shvb.shvnamelen         = shvb.shvname.strlength;
     shvb.shvvaluelen        = shvb.shvvalue.strlength;
     shvb.shvcode            = RXSHV_SET;             
     RexxVariablePool(&shvb);                        
   }

The REXX program currrently invokes this external function as get_CB("Buffer").  As shown in the sample code, RX_get_CB will copy the data from the returned storage area (Buffer) into the REXX variable "Buffer".
This all works fine; however, I'm assuming that 'under the covers' REXX must be allocating a storage area
equal to shvvalue.strlength with the name ArgV[0].strptr; so right after the call to RXSHV_SET, there will be two storage areas of the same size allocated.  The problem is that some of these returned storage areas are
*very* large, sometimes a few hundred MBs, so having 2 such areas around at the same time is not something I'd prefer to do.

So I'd like to see if there's an alternate way to do this.  Is there some way I can assign the returned storage area directly to a REXX variable; sort of like the way I can use "PRXSTRING RetStr".  Perhaps, is there some way I can obtain the address of a REXX variable instead of just it's value?

One thing I was thinking, but wasn't sure if it would work; in the above example, if instead of invoking the functions as RX_get_CB("REXX_var") I invoke it as

     Buffer = copies(d2c(0),512);   /* allocate 512-byte buffer */
     Call RX_get_CB(Buffer);

The function could then change to

  APIRET RX_get_CB(PSZ fct_name,ULONG ArgC,RXSTRING ArgV[],
                    PSZ Queue_Name,PRXSTRING RetStr) {
     SHVBLOCK shvb;
     get_CB(ArgV[0].strptr);
  }

Trying a simple experiment

  APIRET RX_get_CB (RX_API_Parms) {

  strcpy(ArgV[0].strptr,"returned string");
  ArgV[0].strlength = strlen(ArgV[0].strptr);

  return 0;
  }
 
and invoking the function as above

     Buffer = copies(d2c(0),512);   /* allocate 512-byte buffer */
     Call RX_get_CB(Buffer);
     say "buffer="Buffer

returns "Buffer=" which makes me think that ArgV[0].strptr doesn't really point to the address of the actual variable "Buffer".

Does all/any of this make sense?