Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number

C Functions with variable argument list in perlxs

by Temeschwarrior (Novice)
on May 05, 2008 at 12:19 UTC ( #684623=perlquestion: print w/replies, xml ) Need Help??
Temeschwarrior has asked for the wisdom of the Perl Monks concerning the following question:

Hello com,

Im writing an interface for a shared library, but i have a
little problem to handle C functions with variable argument list,
becouse i dont know how to build an xsub with that.

For example i have an function FWriteF(file, fmt, ...) its
imposibel to call and if i have an function like
VAWriteF(file, fmt, va_list) i cant do it too because an xsub like this:

int FWriteF(file,fmt, ...) FILE* file const char * fmt CODE: I32 i; va_list args for(i = items, i < items; i++) args ?= ST(i); //how do i pass to args? RETVAL =VAWriteF(file,fmt,args); OUTPUT: RETVAL

dont work

so how can i handle this?

regards Temesch

Replies are listed 'Best First'.
Re: C Functions with variable argument list in perlxs
by tachyon-II (Chaplain) on May 05, 2008 at 13:03 UTC
Re: C Functions with variable argument list in perlxs
by Thelonius (Priest) on May 05, 2008 at 13:11 UTC
    There are a few libraries that can help with this.

    There are two portable, non-Perl specific libraries: One is libffi. The other is ffcall (ftp server not responding as I write this).

    There is a Perl interface to ffcall: FFI.

    If you are using Windows, you can use Win32::API.

    If you use the FFI or Win32::API Perl modules, you may not need to write any XS code of your own.

    Also, I can email a copy of ffcall-1.10.tar.gz if you have trouble downloading it. Just email me at kahirsch at cpan dot org.

Re: C Functions with variable argument list in perlxs
by syphilis (Chancellor) on May 05, 2008 at 13:40 UTC
    It need not be too bad. Here's an Inline::C demo where the function has a FILE* as it's first argument, a string as its second argument, and a variable number of following arguments (all of which are unsigned integers). If you want to see what a valid XS file looks like just uncomment  # CLEAN_AFTER_BUILD => 0, (before you have run the script) and take a look in the _Inline/build directory at the XS file that was autogenerated.
    Update: Script modified slightly from when first posted
    ### ### use warnings; use Inline C => Config => # CLEAN_AFTER_BUILD => 0, BUILD_NOISY => 1; use Inline C => <<'EOC'; void foo(FILE * fh, SV* sv, ...) { dXSARGS; int i, arg; printf("%s ", SvPV_nolen(ST(1))); for (i = 2; i < items; i++) { arg = SvUV(ST(i)); printf("%d ", arg); } XSRETURN(0); } EOC open($rd, '<', '') or die $!; $fmt = "foobar"; foo($rd, $fmt, 1 .. 5); print "\n"; foo($rd, $fmt, 21 .. 32); print "\n";
    But there's a problem ... what if the third and subsequent args aren't all unsigned integers ? What if they're an ad hoc mixture of integers, doubles, and strings ?

    That obviously complicates things. You might be able to convert each of those arguments to the appropriate C type by examining the flags associated with them. Or, you might be able to derive that info by decoding the fmt string (2nd arg). Either way, it's not all that pretty. (I don't know of any other way - but that doesn't mean that an alternative doesn't exist.)

Re: C Functions with variable argument list in perlxs
by derby (Abbot) on May 05, 2008 at 12:53 UTC

    uhh ... typo?

    for( i = items, i < items; i++ )
    should be
    for( i = 0; i < items; i++ )


    Update: ... well actually it should be i = 2, since you have file and fmt.

Re: C Functions with variable argument list in perlxs
by Temeschwarrior (Novice) on May 05, 2008 at 17:55 UTC
    Thx guys but i need an interface to call an existing c function with varieble arguments not to create one.

    Uh well the suggestion from Thelonius seems to be someting that would help.

Re: C Functions with variable argument list in perlxs
by salva (Abbot) on May 07, 2008 at 08:29 UTC
    That is not a simple thing to do.

    If your function expects a variable length list of arguments of different types, the best approach would probably be to replace it by another function accepting a list of SVs, implemented using lower level functions.

    Another option would be to implement the formating part in Perl, for instance:

    sub FWriteF { my $file = shift; my $fmt = shift; my $text = sprintf($fmt, @_); _FRwriteF($file, $text); # calls C function as # FWriteF($file, "%s", $text); }

    If your function expects a variable list of arguments of the same type, sometimes it is acceptable to set a limit on the number or arguments so you can use something like this:

    int FWriteF(file, fmt, a0=0, a1=0, a2=0, a3=0,...., a10=0) FILE *file, const char *fmt int a0 int a1 ... int a10 CODE: switch (items - 2) { case 0: RETVAL = FWriteF(file, fmt); break; case 1: RETVAL = FWriteF(file, fmt, a1); break; case 0: RETVAL = FWriteF(file, fmt, a1, a2); break; ... case 10: RETVAL = FWriteF(file, fmt, a1, a2, a3, ..., a10); break; } OUTPUT: RETVAL
    If I recall correctly, that's how SWIG does, for instance.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://684623]
Approved by almut
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (6)
As of 2017-02-21 09:01 GMT
Find Nodes?
    Voting Booth?
    Before electricity was invented, what was the Electric Eel called?

    Results (309 votes). Check out past polls.