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