Alan Burlison <[EMAIL PROTECTED]> writes:
>I'm writing some code that is a wrapper around a C library that provides
>various ways of looking up and returning a C structure. I then flatten
>the structure and return it on the perl stack. Because the 'flatten'
>code is always the same, I want to push it down into a function. This
>function however will need to access the perl stack to push the return
>values onto it. I've passed SP into the flatten function so that it
>looks something like this:
>
>static int
>pushret_mystruct(const struct mystruct *myst)
>{
> dTARG;
> EXTEND(SP, 3);
> PUSHs(sv_2mortal(newSVpv(myst->fielda, 0)));
> PUSHs(sv_2mortal(newSViv(myst->fieldb)));
> PUSHs(sv_2mortal(newSVpv(myst->fieldc, 0)));
> return(3);
>}
>
>One of the calling calling XS routine then looks something like this:
>
>SV*
>getmystructbyid(id)
> char *id
>PREINIT:
> struct mystruct myst, *mystp;
>PPCODE:
> if (mystp = getmystructbyid(id)) {
> XSRETURN(pushret_mystruct(sp, mystp));
> } else {
> XSRETURN_EMPTY;
> }
>
>I've read all the dire warnings in perlcall about bracketing things with
>various macros to make sure the stack is balanced, calling SPAGAIN to
>refetch SP etc, but as I'm not actually calling a perl routine, and as
>I'm returning immediately after the call to pushret_myspec, does the
>above look sane?
You pass sp in the example call but don't expect it the example func.
Whether it is sane may depend on which you do!
The dire warnings are not just related to perl code - anything which grows
the stack is a possible snag. Thus your EXTEND(SP,3) may cause stack to move,
and indeed PUSHs's very reason for existance is to change the SP.
and hence XSRETURN* to do funny things to the _old_ stack.
I suggest you look at definitions of XSRETURN*
One key to understanding this stuff is that an xsub returns "void",
and XSRETURN* just diddles with variables - so there is no reason
why the called sub cannot do the diddling:
void
pushret_mystruct(const struct mystruct *myst)
{
dSP;
EXTEND(SP, 3);
PUSHs(sv_2mortal(newSVpv(myst->fielda, 0)));
PUSHs(sv_2mortal(newSViv(myst->fieldb)));
PUSHs(sv_2mortal(newSVpv(myst->fieldc, 0)));
PUTBACK; /* copy SP to PL_stack_sp which XSRETURN uses */
XSRETURN(3);
}
....
if (mystp = getmystructbyid(id)) {
pushret_mystruct(mystp);
return;
} else {
XSRETURN_EMPTY;
}
--
Nick Ing-Simmons