Subscribe for automatic updates: RSS icon RSS

Login icon Sign in for full access | Help icon Help
Advanced search

Pages: [1]
  Reply  |  Print  
Author Topic: Dynamic function calls  (Read 12872 times)
Snorri B.
Posts: 103


« on: July 18, 2008, 04:11:21 pm »

Hi everyone.

Is there an [un]documented way in BDL to call a function dynamically, like

call CallFunction("funcname", "[parameters...]") returning .....

I recall some discussion about this few years ago, but I can't find it.

Best regards,
-Snorri
David H.
Posts: 158


« Reply #1 on: July 18, 2008, 05:00:13 pm »

Hi Snorri,

I use fCall() directly or in Genero v2+ a #defined fCall (to fglcapi_call4gl(aName,anArgC)) in our C runner to give us this functionality. I discovered this whilst poking around in fglext.h one day. You have to push/pop your parameters. We use this to provide a dynamic callback mechanism in our central picklist control and its works very well.

Something built directly into BDL would be nice in a future version. Hopefully something for v2.20+..!

Regards,

David
Snorri B.
Posts: 103


« Reply #2 on: July 18, 2008, 05:33:32 pm »

Thanks David.

Could you perhaps (if it's not too much work for you) send me an example how this works?

Best regards, and have a nice weekend
-Snorri
David H.
Posts: 158


« Reply #3 on: July 21, 2008, 11:05:17 am »

Hi Snorri,

Hope this brief example will give you a better idea. Apart from the odd typo it should work... Allegedly!

C Runner...

Code
  1. //for Genero V2+
  2. #define fCall(aName,anArgC)   fglcapi_call4gl(aName,anArgC)
  3. //Simple function call with 1 parameter and single return parameter.
  4. int call_4gl(int nargs)
  5.  
  6. { char funcname[100];
  7.  long recno;
  8.  short status;
  9.  
  10.  poplong(&recno);            //get argument for 4GL call
  11.  popvchar(funcname,99);      //get function name for 4GL call
  12.  pushlong(recno);            //push argument for call to 4GL
  13.  fCall(funcname,1);          //call 4gl function with single parameter
  14.  popshort(&status);          //get functions return parameter
  15.  retshort(status);           //return to caller
  16.  return(1);
  17. }


4GL

   
Code
  1.    FUNCTION fetch_prod(l_prod_unique_key)
  2.  
  3.        DEFINE l_prod_unique_key INTEGER
  4.  
  5.        SELECT * INTO g_prod_rec.*
  6.            WHERE prod_unique_key = l_prod_unique_key
  7.  
  8.        RETURN status = 0
  9.  
  10.    END FUNCTION
  11.  
  12.  
  13.    MAIN
  14.  
  15.        DEFINE l_ok         SMALLINT
  16.        DEFINE l_unique_key INTEGER
  17.  
  18.        PROMPT "Record to fetch?" FOR l_unique_key
  19.        CALL call_4gl("fetch_prod",l_unique_key) RETURNING l_ok
  20.  
  21.    END MAIN

Regards,

David

Snorri B.
Posts: 103


« Reply #4 on: July 21, 2008, 11:54:51 am »

Thanks a lot!

I will try this out ASAP.

Regards,
-Snorri
Andrew C.
Posts: 48


« Reply #5 on: August 12, 2008, 08:11:42 am »

Or you might like this variation which supports any number of arguments and return values

int c_call_fz(int nargs) {
    char ftn[51];

    if(nargs-- == 0)
        cfgl_fatal("usage: c_call_fz([args, ...] ftnname char(*)) [returning values...]");
    poptrim(ftn, sizeof(ftn));
    return fglcapi_call4gl(ftn, nargs);
}   /* c_call_fz */

poptrim() is just a little function of mine which pops a char string and blank-trims it, no trouble for anyone to write that.

cfgl_fatal() is a function I use for uniform reporting of failure to call a C function properly, followed by program termination (programmers better deal with the fault Codd-damn it or they ain't getting a running program!)

You'll notice that the name of the function is at the end (reflected in my mnemonic _fz wart at the end of the function name). I did this because getting it from the bottom of the stack is too much hard work. I had a version that would do that, but it could not cope with data types like datetimes, etc. So I decided to put the function name at the end, and indicate it's a dodgy interim version of the function by naming it with the _fz wart. One day a first-class c_call might be possible...

In your fglext.c, you just need

    { "c_call_fz",              c_call_fz,                  -1,  -1 },

to make fgl2p happy compiling this function with variable arg and return lists, you need to use the -z flag and a file that lists this function:


    fgl2p -z /somewhere/varargftns.lst thingy.4gl

where my /somewhere/varargftns.lst contains something like

c_call_fz -1 -1

amongst others


given all the conditions mentioned above, the same .4gl file can call


    call c_call_fz("ftn1")
    call c_call_fz(1, 2, "ftn2") returning a, b, c

and so on without getting compile time errors.
Pages: [1]
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines