Ilya Zakharevich on Fri, 21 Nov 1997 06:20:13 +0100


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

Re: Math::Pari 0.91 released


Karim Belabas writes:
> > > (a technical question by the way, since I don't have the time to check it
> > > myself now: do you still rely on the 'x' code in identifier and the foreign*
> > > autoloading mechanism ?
> > 
> > Sure.  Though I found a big deficiency: the actual number of args is not
> > reported to the foreigh function.  If somebody else uses 'x' [...]
> 
> I don't think anybody else uses it. PariPython does not, neither does CLISP,
> and neither do we. So feel free to send a patch. Could you post an example of
> foreignHandler so that I see how you use it precisely ? (and maybe we could
> document the whole mechanism after all this time...).

Saving you a peak into Pari.xs,

   pariErr = &perlErr;
   foreignHandler = (void*)&callPerlFunction;
   foreignAutoload = &autoloadPerlFunction;
   foreignExprSwitch = (char)SVt_PVCV;
   foreignExprHandler = &exprHandler_Perl;
   foreignFuncFree = &freePerlFunction;


GEN
callPerlFunction(entree *ep, ...)
{
    va_list args;
    char *s = ep->code;
    int numargs = ep->code[-1];
    SV *cv = (SV*) ep->value;
    GEN res;
    int i;
    dSP;
    int count ;
    long oldavma = avma;
    SV *oPariStack = PariStack;
    SV *sv;

    va_start(args, ep);
    ENTER ;
    SAVETMPS;
    SAVEINT(sentinel);
    sentinel = avma;
    PUSHMARK(sp);
    EXTEND(sp, numargs + 1);
    for (i = 0; i < numargs; i++) {
	PUSHs(pari2mortalsv(va_arg(args, GEN), oldavma));
    }
    va_end(args);
    PUTBACK;
    count = perl_call_sv(cv, G_SCALAR);

    SPAGAIN;
    if (count != 1)
	croak("Perl function exported into PARI did not return a value");

    sv = SvREFCNT_inc(POPs);		/* Preserve the guy. */

    PUTBACK ;
    FREETMPS ;
    LEAVE ;
    /* Now PARI data created inside this subroutine sits above
       oldavma, but the caller is going to unwind the stack: */
    if (PariStack != oPariStack)
	moveoffstack_newer_than(oPariStack);
    /* Now, when everything is moved off stack, and avma is reset, we
       can get the answer: */
    res = sv2pari(sv);			/* XXXX When to decrement the count? */
    /* We need to copy it back to stack, otherwise we cannot decrement
     the count.  XXXX not necessary! */
    avma -= taille(res)<<TWOPOTBYTES_IN_LONG;
    brutcopy(res, avma);
    SvREFCNT_dec(sv);
    
    return (GEN)avma;
}

/* Currently with <=6 arguments only! */

long
autoloadPerlFunction(char *s, long len)
{
    CV *cv;
    SV* name = sv_2mortal(newSVpv(s, len));

    cv = perl_get_cv(SvPVX(name), FALSE);
    if (cv == Nullcv) {
	return 0;
    }
    /* Got it! */
    installPerlFunction((SV*)cv, SvPVX(name), -1, NULL); /* -1 gives variable. */
    return 1;
}

GEN
exprHandler_Perl(char *s)
{
    SV* dummy;
    SV* cv = (SV*)(s - LSB_in_U32 - 
		   ((char*)&(dummy->sv_flags) - ((char*)dummy)));
    GEN res;
    long count;
    dSP;
    SV *sv;
    SV *oPariStack = PariStack;

    ENTER ;
    SAVETMPS;
    PUSHMARK(sp);
    SAVEINT(sentinel);
    sentinel = avma;
    count = perl_call_sv(cv, G_SCALAR);

    SPAGAIN;
    sv = SvREFCNT_inc(POPs);		/* Preserve it through FREETMPS */

    PUTBACK ;
    FREETMPS ;
    LEAVE ;

    /* Now PARI data created inside this subroutine sits above
       oldavma, but the caller is going to unwind the stack: */
    if (PariStack != oPariStack)
	moveoffstack_newer_than(oPariStack);
    /* Now, when everything is moved off stack, and avma is reset, we
       can get the answer: */
    res = sv2pari(sv);
    /* We need to copy it back to stack, otherwise we cannot decrement
     the count. */
    avma -= taille(res)<<TWOPOTBYTES_IN_LONG;
    brutcopy(res, avma);
    SvREFCNT_dec(sv);
    
    return (GEN)avma;
}

> If you wish (although the Configure checks for a libgnuplo.a which of course
> it never finds...). I had a casual look at this plotgnuplot.c long ago (had
> many many other pressing things to do at the time...), and it seemed to me it
> needed to be linked with some other library hacked from the GNU package,
> right ? And this is definitely not included yet. If I can figure out how it
> works, I'll try to include it in one of the next alpha updates.

Well, if you use the newer variant from 0.91, you do not need to link
with anything.  ;-) ;-) Really.  You can load gnuplot at runtime (but
the DLL should be compiled nevertheless, of course - with enough
hacking power to call a correct fixup function one can probably even
use Perl's Term::Gnuplot DLL without any recompile).

Makemakefile of pari-small.zip contained all the necessary logic: you
need to have the directory with the source of gnuplot3.5 handy, you
need to compile 3 or 4 files from this distribution, and link against
them.

Ilya