Hi,

I'm new to XS and was wondering what the best strategy is for opening a
file in C as a file stream (FILE *) and returning that to Perl as a
filehandle.

I wrote a simple module called Foo in which Foo.xs defines the following
function, a simple wrapper to C's fopen():

FILE *
foo(file, mode)
        char *    file;
        char *    mode;
    CODE:
        RETVAL = fopen(file, mode);
    OUTPUT:
        RETVAL

If I now call Foo::foo() in the Perl as follows:

    my $fh = Foo::foo("test.txt", "r");

then I can read OK from $fh, but if I try to use:

    my $fh = Foo::foo("test.txt", "w");

then I can't write to $fh - I get a warning that "Filehandle Foo::_GEN_0
opened only for input".

I believe this is because ExtUtils's "typemap" maps "FILE *" to "T_IN"
which opens the file for reading only.

Obviously I can't define the XS foo() to return different types (T_IN,
T_OUT, T_INOUT) depending on what the "mode" argument was, so what is
the best way around this?

I tried returning the fileno() of the C file stream from the XS foo()
and then effectively doing an fdopen() on that back in the Perl:

    my $fd = Foo::foo("test.txt", "r");
    open(my $fh, "<&=$fd");

(in which the "<" is deduced from the "r").

This works OK, but it's not pretty, and what if a wanted a Perl wrapper
to C's open()?  It's not so easy to work out the "(+)<|>|>>" mode for
Perl's open() from the O_* flag argument to C's open().

Is there a nice, general way of doing this which I'm missing?

Thanks,

Steve Hay


Reply via email to