/* macdynload - Dynamic loading and C function calling routines. */
/* XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney */
/* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz */
/* You may give out copies of this software; for conditions see the */
/* file COPYING included with this distribution. */
/* Calling conventions are based on the conventions given in the New S */
/* book. */
#include "xlisp.h"
#include "xlstat.h"
#include "xlsx.h"
extern char buf[];
extern LVAL s_true;
typedef void (*pfv_t)(); /* pointer to function returning void. */
/************************************************************************/
/** **/
/** Resource File Handling Functions **/
/** **/
/************************************************************************/
LVAL xsopen_resfile(void)
{
char *name;
int fn;
name = (char *) getstring(xlgastring());
xllastarg();
CtoPstr(name);
fn = OpenResFile((StringPtr) name);
PtoCstr((StringPtr) name);
return((fn >= 0) ? cvfixnum((FIXTYPE) fn) : NIL);
}
LVAL xsclose_resfile(void)
{
int fn;
fn = getfixnum(xlgafixnum());
xllastarg();
CloseResFile(fn);
return(NIL);
}
/************************************************************************/
/** **/
/** Allocation and Error Signalling Functions **/
/** **/
/************************************************************************/
static LVAL current_allocs = NULL;
#define fixup_current_allocs \
{ if (current_allocs == NULL) current_allocs = NIL; }
/* allocate space that will be garbage collected after return */
static char *xscall_alloc(int n, int m)
{
LVAL adata;
char *p;
fixup_current_allocs;
adata = newadata(n, m, FALSE);
if (adata == NIL || (p = getadaddr(adata)) == nil)
xlfail("allocation failed");
current_allocs = cons(adata, current_allocs);
return(p);
}
/* error routine for use within C functions */
static VOID xscall_fail(char *s) { xlfail(s); }
/************************************************************************/
/** **/
/** Lisp to C/FORTRAN Data Conversion **/
/** **/
/************************************************************************/
#define IN 0
#define RE 1
typedef struct {
int type, size;
char *addr;
} call_arg;
/* convert lisp argument to allocated pointer */
static call_arg lisp2arg(LVAL x)
{
call_arg a;
LVAL elem, data;
int i;
xlprot1(x);
/* make sure x is a sequence and find its length */
if (! seqp(x)) x = consa(x);
a.size = seqlen(x);
/* determine the mode of the data */
for (i = 0, a.type = IN, data = x; i < a.size; i++) {
elem = getnextelement(&data, i);
if (floatp(elem)) a.type = RE;
#ifdef BIGNUMS
else if (ratiop(elem)) a.type = RE;
#endif
else if (! integerp(elem)) xlerror("not a real number", elem);
}
/* allocate space for the data */
a.addr = xscall_alloc(a.size, (a.type == IN) ? sizeof(int) : sizeof(double));
/* fill the space */
for (i = 0, data = x; i < a.size; i++) {
elem = getnextelement(&data, i);
if (a.type == IN) ((int *) a.addr)[i] = getfixnum(elem);
else ((double *) a.addr)[i] = makefloat(elem);
}
xlpop();
return(a);
}
/* copy allocated pointer back to new lisp list */
static LVAL arg2lisp(call_arg a)
{
LVAL x, next;
int i;
xlsave1(x);
x = mklist(a.size, NIL);
for (i = 0, next = x; i < a.size; i++, next = cdr(next)) {
if (a.type == IN) rplaca(next, cvfixnum((FIXTYPE) ((int *) a.addr)[i]));
else rplaca(next, cvflonum((FLOTYPE) ((double *) a.addr)[i]));
}
xlpop();
return(x);
}
/************************************************************************/
/** **/
/** Foreign Function Call Function **/
/** **/
/************************************************************************/
LVAL xscall_cfun(void)
{
LVAL result, Lname, old_allocs, next;
call_arg *args, *pargs;
int nargs, i;
Handle rhandle;
void (*routine) _((XLSXblock *));
char *name;
XLSXblock params;
fixup_current_allocs;
xlstkcheck(3);
xlsave(old_allocs);
xlprotect(current_allocs);
xlsave(result);
old_allocs = current_allocs;
current_allocs = NIL;
/* get the routine pointer */
Lname = xlgastring();
name = (char *) getstring(Lname);
CtoPstr(name);
rhandle = GetNamedResource('XLSX', (StringPtr) name);
PtoCstr((StringPtr) name);
if (! rhandle) xlerror("can't load XLSX resource", Lname);
/* convert the arguments to allocated pointers */
nargs = xlargc;
if (nargs == 0) xlfail("too few arguments");
args = (call_arg *) xscall_alloc(nargs, sizeof(call_arg));
params.argc = nargs;
params.argv = (char **) xscall_alloc(nargs, sizeof(char *));
for (i = 0; i < nargs; i++) {
args[i] = lisp2arg(xlgetarg());
params.argv[i] = args[i].addr;
}
/* make the call */
HLock(rhandle);
routine = (pfv_t) *rhandle;
(*routine)(¶ms);
HUnlock(rhandle);
/* convert the pointers back to lists, grouped in a list */
result = (nargs > 0) ? mklist(nargs, NIL) : NIL;
for (next = result, pargs = args; consp(next); next = cdr(next), pargs++)
rplaca(next, arg2lisp(*pargs));
current_allocs = old_allocs;
xlpopn(3);
return(result);
}
syntax highlighted by Code2HTML, v. 0.9.1