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

 

Reply via email to