in reply to Re: XS: How to enable passing ref or undef?
in thread XS: How to enable passing ref or undef?

Thanks - I appreciate the effort. But that isn't the approach I need here.

I have made this work by making the declaration variadic, which gives me the unfettered ability to process the third argument. But it also required me to copy all the ugly casts that the xs compiler did to convert to the structure pointer.

routine(a, b=4,...) char * a; int b PREINIT: foo_t * c = NULL; CODE: if (items > 2 ) { if (SvOK(ST(2))) { /* defined */ if (SvROK(ST(2))) { /* reference */ IV tmp = SvIV((SV*)SvRV(ST(2))); c = INT2PTR(foo_t *,tmp); } else Perl_croak(aTHX_ "c is not a reference"); } } ... continuing as before
There must be some typemap magic that would have the same effect with less mumbling. But the documentation is sparse and the crystal is cloudy...

This communication may not represent my employer's views, if any, on the matters discussed.

Replies are listed 'Best First'.
Re^3: XS: How to enable passing ref or undef?
by juster (Friar) on Oct 18, 2010 at 23:15 UTC
    Here is some typemap code I copied from my own project. I mostly figured this out (aka copy/pasted) from the perlxstut manpage I think.
    TYPEMAP # You need a typedef for BarPointOrNull in your .xs file or a header.. +. # Like this: typedef bar_t * BarPointerOrNull; # Then you can use it in the XS parameter list: # routine( a, b, c ) # char * a # int b # BarPointerOrNull c BarPointerOrNull T_BAR_OR_NULL INPUT #--------------------------------------------------------------------- +-------- # Map a perl reference to a C pointer... #--------------------------------------------------------------------- +-------- T_BAR_OR_NULL if ( ! SvOK( $arg )) { $var = NULL; } /* Make sure we are given an object of class Bar::Class... */ else if ( sv_derived_from( $arg, \"Bar::Class\" )) { IV tmp = SvIV( (SV *) SvRV( $arg )); $var = INT2PTR( $type, tmp ); } /* Holy crap! I must have copied this from the manpage... nice. */ else { Perl_croak(aTHX_ \"%s: %s is not of type %s\", ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, \"$var\", \"Bar::Class\") } OUTPUT #--------------------------------------------------------------------- +-------- # Map a C pointer to a perl reference... #--------------------------------------------------------------------- +-------- T_BAR_OR_NULL if ( $var == NULL ) { $arg = &PL_sv_unef; } else { /* We bless the pointer as a Bar::Class object... can be handy * for wrapping structures in objects. */ sv_setref_pv( $arg, \"Bar::Class\", (void *)$var ); } # $var is the C variable, $type is the C type, $arg is the perl variab +le # Um that's all I know. OH and always escape your double-quotes!
    EDIT On second thought... this won't work. The XS function will complain about not enough arguments if you don't give it a third argument. You could always wrap it in a pure-perl function, though...
    # Silly really... but so easy! sub myroutine { my ($a, $b, $c) = @_; routine( $a, $b, $c ); }