Hi all,
In my XS I have two methods that basically mimic the behaviour of Perl's
localtime() and gmtime(). To avoid some duplicate code in the XSUBs I
thought I let them call a C function with an additional argument
'method' (to determine whether to use gmtime(3) or localtime(3)) and
then let this C function push the returns values directly onto the Perl
stack. That wasn't quite that easy since it turned out that this
involves quite some knowledge about all the stack macros. I've finally
come up with a working solution but I am sceptical, especially since I
don't quite understand why it works. :-)
Here the C function and how it's called from one of the two XSUBs below:
int datify (FILETIME *wintime, int method) {
dXSARGS;
time_t time = FileTimeToUnixTime(wintime, NULL);
struct tm *tstruct;
SP -= items;
if (method == 0)
tstruct = localtime(&time);
else
tstruct = gmtime(&time);
PUSHMARK(SP);
if (GIMME == G_ARRAY) {
EXTEND(SP, 9);
PUSHs(sv_2mortal(newSViv(tstruct->tm_sec)));
[...] /* nine values overall */
PUSHs(sv_2mortal(newSViv(tstruct->tm_isdst)));
PUTBACK;
return 9;
} else {
SV *str = newSVpvf("%s %s %2d %02d:%02d:%02d %d",
dayname[tstruct->tm_wday],
[...]
tstruct->tm_year + 1900);
EXTEND(SP, 1);
PUSHs(sv_2mortal(str));
PUTBACK;
return 1;
}
}
[...]
MODULE = Mail::Transport::Dbx PACKAGE = Mail::Transport::Dbx::Email
void
date_local (self)
DBX_EMAIL *self;
PREINIT:
int count;
PPCODE:
count = datify(&(self->email->date), 0);
XSRETURN(count);
I encounter strange behaviour if I make slight changes, for instance
decrementing SP in date_local() instead of datify(). In this case, one
of the return values is dropped.
The only thing I know for sure so far is that I have to use dXSARGS or
dSP (probably depending on whether I use 'items') to be able to use the
Perl stack in a C function. But I am not at all sure about ENTER, LEAVE
SAVETMPS and FREETMPS. So what would be a minimum sceleton to call a
C-function from a XSUB and have the C-function set up the return stack
accordingly? Currently I would say:
int func(...) {
dXARGS;
int num_return_values;
SP -= items;
PUSHMARK(SP);
/* push stuff on stack using XPUSH or EXTEND/PUSH */
PUTBACK;
return num_return_values;
}
void XSfunc(...)
...
PPCODE:
XSRETURN(func());
Is that how it is supposed to work or do other ways exist? I would like
to know those as they might make the whole stack-thing clearer to me.
Thanks in advance for any explanations,
Tassilo
--
$_=q!",}])(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
pam{rekcahbus;})(rekcah{lrePbus;})(lreP{rehtonabus;})(rehtona{tsuJbus!;
$_=reverse;s/sub/(reverse"bus").chr(32)/xge;tr~\n~~d;eval;