Nick Ing-Simmons wrote:

> 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.

Alas, I'm not writing the C library.  I'm writing a Perl module to wrap a
(Microsoft C) Win32 file open function called _fsopen(), which works very much
like the standard C fopen(), but provides file locking.  (The "s" in the name is
for "sharing", I think.)  It returns a FILE * the same as fopen() itself does.

> [snip]
> >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.

I had a look at doing this.  It involves inspecting the "mode" argument and
doing slightly different things in the XS accordingly, exactly like the Perl
"fdopen()" below has to inspect the "mode" and perform accordingly.  So there's
no real gain, and the XS stuff is messier than the Perl "fdopen()".

> [snip]
> >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.

Not so.  As Tye McQueen says in another e-mail, fileno() does work fine on
Win32.  I have, of course (now that you know I'm working on Win32), done exactly
this already!  And presumably, I'll never be porting this to any other system
where fileno() really doesn't work, because _fsopen() probably doesn't exist
anywhere else anyway.  (My fault - I should have mentioned the dreaded
"Microsoft" word in my original mail.)

> >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.
>

I thought of that, but isn't it the case that Perl's open() does some magic
stuff with the FILENAME argument so that it _interprets_ "<&=$fd", whereas
Perl's sysopen() does no such magic and would actually open a file called, say,
"&=3"?

How do I do the effective fdopen()-like thing with Perl's sysopen()?

(BTW, as you might have guessed by now, I am also trying to provide a Perl
wrapper to another MS C function called _sopen(), which is again analogous to
the standard C open(), but with sharing/locking.)

Steve Hay


Reply via email to