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; } }