Support autovivified filehandle as arguments to Perl XS routine
Asked Answered
C

1

7

Question

How can I support autovivified filehandle arguments in an XS function?

I'm XS-wrapping a C function which returns a file descriptor, and I'd like to present that file descriptor as a perl filehandle argument in the manner of open(). E.g.,

myfunc(my $fh) or die "Error: $!";
do_something_with_fh($fh);

What I've done so far

Right now I'm using a perl wrapper on top of the XS function:

# -- in perl
sub myfunc {
    my $fd = _myfunc();
    return open($_[0], '+<&=', $fd) if defined($fd);
}

/* -- in XS */
SysRet
_myfunc()
    CODE:
    RETVAL = some_c_function_returning_an_fd();

    OUTPUT:
    RETVAL

This works Just Fine (tm), but, again, I'd like to move the implementation entirely into XS.

So far I've tried sv_2io on an argument typemapped as SV *, but that throws an exception on undefined scalars. I have not tried mapping the first argument to a FILE * or PerlIO * object, since I don't know how I'd "fdreopen" (if you will) those objects.

Cretin answered 21/12, 2012 at 20:20 Comment(3)
Maybe look at the autovivification module search.cpan.org/dist/autovivificationAgrobiology
I don't see any easy way of creating an IO object from the PerlIO returned by PerlIO_fdopen. The code behind Perl's open does it itself rather than calling a library function. Eventually, you'd call sv_replace(fh, rv) to move what you created into the argument (given myfunc(SV* fh)).Straight
@Rob, that's a neat pragma, but it doesn't address the issue here.Cretin
H
3

I would keep the myfunc() wrapper in Perl, it works and shouldn't be a bottleneck.

Reimplementing open() is tricky and requires usage of undocumented/internal API. I think this is a pretty close implementation. newGVgen() and do_openn() is part of the public API but undocumented and subject to change.

void
myfunc(sv)
    SV *sv
  PPCODE:
    {
        GV *gv = newGVgen("Mypackage");
        SV *rv = sv_2mortal(newRV_noinc((SV *)gv));
        SV *fd = sv_2mortal(newSViv(some_c_function_returning_an_fd()));

        if (!do_openn(gv, "+<&=", 4, FALSE, 0, 0, NULL, &fd, 1))
            croak("Could not fdopen descriptor: '%s'", Strerror(errno)); /* or XSRETURN_NO; */

        sv_setsv(sv, rv);
        SvSETMAGIC(sv);
        XSRETURN_YES;
    }
Hellbox answered 6/1, 2013 at 20:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.