Steve Hay <[EMAIL PROTECTED]> writes:
>Any comments on this, anyone?
>
>- Steve
>
>-------- Original Message --------
>Subject: Returning a list from an XSUB
>Date: Mon, 08 Sep 2003 15:05:20 +0100
>From: Steve Hay <[EMAIL PROTECTED]>
>To: [EMAIL PROTECTED]
>
>
>
>Hi,
>
>I have an XSUB that calls a C function to get three integers, and then
>returns them (in list context). In scalar context it just returns a
>Boolean to indicate whether the C function succeeded or not. It
>currently looks like this:
>
>void
>my_func()
> PREINIT:
> I32 gimme;
> int one, two, three;
>
> PPCODE:
> gimme = GIMME_V;
> if (My_Func(&one, &two, &three) == 0) {
> if (gimme == G_SCALAR) {
> XSRETURN_YES;
> }
> else if (gimme == G_ARRAY) {
> EXTEND(SP, 3);
> PUSHs(sv_2mortal(newSViv(one)));
> PUSHs(sv_2mortal(newSViv(two)));
> PUSHs(sv_2mortal(newSViv(three)));
> }
> }
> else {
> if (gimme == G_SCALAR)
> XSRETURN_NO;
> else if (gimme == G_ARRAY)
> XSRETURN_EMPTY;
> }
>
>I have a few questions about this:
>
>- Am I correct in just ignoring the G_VOID case, or would it be better
>to return somehow immediately rather than waste time calling the C
>function (given that the C function has no side effects beyond setting
>the three integers)?
Up to you whether you call the C function.
I would be tempted to put in the extra
else
XSRETURN_EMPTY;
for the void case.
>
>- Is the EXTEND(SP, 3) call correct for the 3 subsequent PUSHs() calls?
>I thought it was OK to call PUSHs() once without needing to call
>EXTEND(SP, 1),
You can in general push as many return values as you had args + 1
Currently when called from perl code you will I think get an extra slot
for method calls. If you ever get called by someone elses XS code
it isn't clear you will get a "free" push, so it is good practice
to EXTEND to what you need.
>so perhaps I should only call EXTEND(SP, 2) when I have 3
>values to return?
3 is correct - it is how many you want to push, perl doesn't know
context of EXTEND macro, so can't allow for "free" pushes.
>
>- Do I need the "else" case of the main "if" block at all? Presumably
>just falling off the end of the XSUB when the C function failed would
>achieve the same thing? Or is it better style to code it explicitly as
>above?
>
>- Are the XSRETURN_* macros OK in a PPCODE section?
PPCODE sections normally PUSHs their args onto a perl stack which
has been unwound to point at ST(0) slot. It is possible that
XSRETURN_NO/XSRETURN_YES might be confused by that.
You could use a CODE: version as you know the return counts in advance.
>The Perl manpages
>seem to say it's OK, but I read something somewhere (can't remember
>where) that it wasn't a good idea because the C code generated contains
>"return" statements in a void() subroutine.
All XSes are void subroutines.
XSRETURN_XXXX just do various perl-stack twiddling then "return" in C.
void
my_func()
CODE:
{
I32 gimme = GIMME_V;
int one, two, three;
if (My_Func(&one, &two, &three) == 0) {
if (gimme == G_SCALAR) {
XSRETURN_YES;
}
else if (gimme == G_ARRAY) {
EXTEND(SP, 3);
ST(0) = sv_2mortal(newSViv(one));
ST(1) = sv_2mortal(newSViv(two));
ST(2) = sv_2mortal(newSViv(three));
XSRETURN(3);
}
else {
XSRETURN_EMPTY;
}
}
else {
if (gimme == G_SCALAR)
XSRETURN_NO;
else
XSRETURN_EMPTY;
}
}