Steve Hay <[EMAIL PROTECTED]> writes:
>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.
The best strategy is not to do that unless you really have to ;-)
I assume the _real_ XS has to wrap a library which returns a FILE * ?
If so does that library have an alternate interface (say for reading
from in-memory)?
If you are writing the library it would be better to open file perl-side
and pass handle in, or use PerlIO * abstraction.
In devel track perl has its own IO system and using FILE * limits
what you can do. On the release track (as you have discovered) the
typemap entries for FILE * are a bit of a mess.
>
>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.
Perl needs to do different things for input and output and inout handles,
so one typemap for FILE * cannot solve the problem.
>
>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,
No, but you can create the appropriate "Scalar Value" (SV *) and return
that from your XS code - this is after all what xsubpp does with the typemap
stuff.
>so what is
>the best way around this?
Open the file in perl ?
>
>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,
Until you want to port to Win32 or some other place where fileno() is
an alien concept which does not work very well.
>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().
It isn't that hard, and you could use sysopen() anyway which takes O_*
type args.
>
>Is there a nice, general way of doing this which I'm missing?
Not really.
--
Nick Ing-Simmons
http://www.ni-s.u-net.com/