Kaydet (Commit) b3928d2f authored tarafından Jack Jansen's avatar Jack Jansen

An initial stab at calling random C routines from Python

üst ce7fc98d
/***********************************************************
Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
The Netherlands.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the names of Stichting Mathematisch
Centrum or CWI or Corporation for National Research Initiatives or
CNRI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
While CWI is the initial source for this software, a modified version
is made available by the Corporation for National Research Initiatives
(CNRI) at the Internet address ftp://ftp.python.org.
STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
******************************************************************/
#include "Python.h"
#include "macglue.h"
#include "macdefs.h"
extern PyObject *ResObj_New Py_PROTO((Handle));
extern int ResObj_Convert Py_PROTO((PyObject *, Handle *));
#include <CodeFragments.h>
static PyObject *ErrorObject;
#define PARANOID(arg) \
if ( arg == 0 ) {PyErr_SetString(ErrorObject, "Internal error: NULL arg!"); return 0; }
/* Prototype we use for routines */
typedef long anything;
typedef anything (*anyroutine) Py_PROTO((...));
#define MAXNAME 31 /* Maximum size of names, for printing only */
#define MAXARG 8 /* Maximum number of arguments */
/*
** Routines to convert arguments between Python and C
*/
typedef anything (*py2c_converter) Py_PROTO((PyObject *));
typedef PyObject *(*c2py_converter) Py_PROTO((anything));
/* Dummy routine for arguments that are output-only */
static anything
py2c_dummy(arg)
PyObject *arg;
{
return 0;
}
/* Routine to allocate storage for output integers */
static anything
py2c_alloc(arg)
PyObject *arg;
{
char *ptr;
if( (ptr=malloc(sizeof(anything))) == 0 )
PyErr_NoMemory();
return (anything)ptr;
}
/* Dummy routine for arguments that are input-only */
static PyObject *
c2py_dummy(arg)
anything arg;
{
return 0;
}
/* Routine to de-allocate storage for input-only arguments */
static PyObject *
c2py_free(arg)
anything arg;
{
if ( arg )
free((char *)arg);
return 0;
}
/*
** None
*/
static PyObject *
c2py_none(arg)
anything arg;
{
if ( arg )
free((char *)arg);
Py_INCREF(Py_None);
return Py_None;
}
/*
** OSErr
*/
static PyObject *
c2py_oserr(arg)
anything arg;
{
OSErr *ptr = (OSErr *)arg;
PARANOID(arg);
if (*ptr) {
PyErr_Mac(PyMac_OSErrException, *ptr);
free(ptr);
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
/*
** integers of all sizes (PPC only)
*/
static anything
py2c_in_int(arg)
PyObject *arg;
{
return PyInt_AsLong(arg);
}
static PyObject *
c2py_out_long(arg)
anything arg;
{
PyObject *rv;
PARANOID(arg);
rv = PyInt_FromLong(*(long *)arg);
free((char *)arg);
return rv;
}
static PyObject *
c2py_out_short(arg)
anything arg;
{
PyObject *rv;
PARANOID(arg);
rv = PyInt_FromLong((long)*(short *)arg);
free((char *)arg);
return rv;
}
static PyObject *
c2py_out_byte(arg)
anything arg;
{
PyObject *rv;
PARANOID(arg);
rv = PyInt_FromLong((long)*(char *)arg);
free((char *)arg);
return rv;
}
/*
** Strings
*/
static anything
py2c_in_string(arg)
PyObject *arg;
{
return (anything)PyString_AsString(arg);
}
/*
** Pascal-style strings
*/
static anything
py2c_in_pstring(arg)
PyObject *arg;
{
unsigned char *p;
int size;
if( (size = PyString_Size(arg)) < 0)
return 0;
if ( size > 255 ) {
PyErr_SetString(ErrorObject, "Pstring must be <= 255 chars");
return 0;
}
if( (p=(unsigned char *)malloc(256)) == 0 ) {
PyErr_NoMemory();
return 0;
}
p[0] = size;
memcpy(p+1, PyString_AsString(arg), size);
return (anything)p;
}
static anything
py2c_out_pstring(arg)
PyObject *arg;
{
unsigned char *p;
if( (p=(unsigned char *)malloc(256)) == 0 ) {
PyErr_NoMemory();
return 0;
}
p[0] = 0;
return (anything)p;
}
static PyObject *
c2py_out_pstring(arg)
anything arg;
{
unsigned char *p = (unsigned char *)arg;
PyObject *rv;
PARANOID(arg);
rv = PyString_FromStringAndSize((char *)p+1, p[0]);
free(p);
return rv;
}
/*
** C objects.
*/
static anything
py2c_in_cobject(arg)
PyObject *arg;
{
if ( arg == Py_None )
return 0;
return (anything)PyCObject_AsVoidPtr(arg);
}
static PyObject *
c2py_out_cobject(arg)
anything arg;
{
void **ptr = (void **)arg;
PyObject *rv;
PARANOID(arg);
if ( *ptr == 0 ) {
Py_INCREF(Py_None);
rv = Py_None;
} else {
rv = PyCObject_FromVoidPtr(*ptr, 0);
}
free((char *)ptr);
return rv;
}
/*
** Handles.
*/
static anything
py2c_in_handle(arg)
PyObject *arg;
{
Handle h = 0;
ResObj_Convert(arg, &h);
return (anything)h;
}
static PyObject *
c2py_out_handle(arg)
anything arg;
{
Handle *rv = (Handle *)arg;
PyObject *prv;
PARANOID(arg);
if ( *rv == 0 ) {
Py_INCREF(Py_None);
prv = Py_None;
} else {
prv = ResObj_New(*rv);
}
free((char *)rv);
return prv;
}
typedef struct {
char *name; /* Name */
py2c_converter get; /* Get argument */
int get_uses_arg; /* True if the above consumes an argument */
c2py_converter put; /* Put result value */
int put_gives_result; /* True if above produces a result */
} conventry;
static conventry converters[] = {
{"OutNone", py2c_alloc, 0, c2py_none, 1},
{"OutOSErr", py2c_alloc, 0, c2py_oserr, 1},
#define OSERRORCONVERTER (&converters[1])
{"InInt", py2c_in_int, 1, c2py_dummy, 0},
{"OutLong", py2c_alloc, 0, c2py_out_long, 1},
{"OutShort", py2c_alloc, 0, c2py_out_short, 1},
{"OutByte", py2c_alloc, 0, c2py_out_byte, 1},
{"InString", py2c_in_string, 1, c2py_dummy, 0},
{"InPstring", py2c_in_pstring,1, c2py_free, 0},
{"OutPstring", py2c_out_pstring,0, c2py_out_pstring,1},
{"InCobject", py2c_in_cobject,1, c2py_dummy, 0},
{"OutCobject", py2c_alloc, 0, c2py_out_cobject,0},
{"InHandle", py2c_in_handle, 1, c2py_dummy, 0},
{"OutHandle", py2c_alloc, 0, c2py_out_handle,1},
{0, 0, 0, 0, 0}
};
static conventry *
getconverter(name)
char *name;
{
int i;
char buf[256];
for(i=0; converters[i].name; i++ )
if ( strcmp(name, converters[i].name) == 0 )
return &converters[i];
sprintf(buf, "Unknown argtype: %s", name);
PyErr_SetString(ErrorObject, buf);
return 0;
}
static int
argparse_conv(obj, ptr)
PyObject *obj;
conventry **ptr;
{
char *name;
int i;
conventry *item;
if( (name=PyString_AsString(obj)) == NULL )
return 0;
if( (item=getconverter(name)) == NULL )
return 0;
*ptr = item;
return 1;
}
/* ----------------------------------------------------- */
/* Declarations for objects of type fragment */
typedef struct {
PyObject_HEAD
CFragConnectionID conn_id;
char name[MAXNAME+1];
} cdfobject;
staticforward PyTypeObject Cdftype;
/* ---------------------------------------------------------------- */
/* Declarations for objects of type routine */
typedef struct {
PyObject_HEAD
anyroutine rtn;
char name[MAXNAME+1];
} cdrobject;
staticforward PyTypeObject Cdrtype;
/* ---------------------------------------------------------------- */
/* Declarations for objects of type callable */
typedef struct {
PyObject_HEAD
cdrobject *routine; /* The routine to call */
int npargs; /* Python argument count */
int npreturn; /* Python return value count */
int ncargs; /* C argument count + 1 */
conventry *argconv[MAXARG+1]; /* Value converter list */
} cdcobject;
staticforward PyTypeObject Cdctype;
/* -------------------------------------------------------- */
static struct PyMethodDef cdr_methods[] = {
{NULL, NULL} /* sentinel */
};
/* ---------- */
static cdrobject *
newcdrobject(name, routine)
unsigned char *name;
anyroutine routine;
{
cdrobject *self;
int nlen;
self = PyObject_NEW(cdrobject, &Cdrtype);
if (self == NULL)
return NULL;
if ( name[0] > MAXNAME )
nlen = MAXNAME;
else
nlen = name[0];
memcpy(self->name, name+1, nlen);
self->name[nlen] = '\0';
self->rtn = routine;
return self;
}
static void
cdr_dealloc(self)
cdrobject *self;
{
PyMem_DEL(self);
}
static PyObject *
cdr_repr(self)
cdrobject *self;
{
PyObject *s;
char buf[256];
sprintf(buf, "<Calldll routine %s address 0x%x>", self->name, self->rtn);
s = PyString_FromString(buf);
return s;
}
static char Cdrtype__doc__[] =
"C Routine address"
;
static PyTypeObject Cdrtype = {
PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/
"routine", /*tp_name*/
sizeof(cdrobject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)cdr_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)0, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc)cdr_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/
/* Space for future expansion */
0L,0L,0L,0L,
Cdrtype__doc__ /* Documentation string */
};
/* End of code for routine objects */
/* -------------------------------------------------------- */
static struct PyMethodDef cdc_methods[] = {
{NULL, NULL} /* sentinel */
};
/* ---------- */
static cdcobject *
newcdcobject(routine, npargs, npreturn, ncargs, argconv)
cdrobject *routine;
int npargs;
int npreturn;
int ncargs;
conventry *argconv[];
{
cdcobject *self;
int i;
self = PyObject_NEW(cdcobject, &Cdctype);
if (self == NULL)
return NULL;
self->routine = routine;
Py_INCREF(routine);
self->npargs = npargs;
self->npreturn = npreturn;
self->ncargs = ncargs;
for(i=0; i<MAXARG+1; i++)
if ( i < ncargs )
self->argconv[i] = argconv[i];
else
self->argconv[i] = 0;
return self;
}
static void
cdc_dealloc(self)
cdcobject *self;
{
Py_XDECREF(self->routine);
PyMem_DEL(self);
}
static PyObject *
cdc_repr(self)
cdcobject *self;
{
PyObject *s;
char buf[256];
int i;
sprintf(buf, "<callable %s = %s(", self->argconv[0]->name, self->routine->name);
for(i=1; i< self->ncargs; i++) {
strcat(buf, self->argconv[i]->name);
if ( i < self->ncargs-1 )
strcat(buf, ", ");
}
strcat(buf, ") >");
s = PyString_FromString(buf);
return s;
}
/*
** And this is what we all do it for: call a C function.
*/
static PyObject *
cdc_call(self, args, kwargs)
cdcobject *self;
PyObject *args;
PyObject *kwargs;
{
char buf[256];
int i, pargindex;
anything c_args[MAXARG+1] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
conventry *cp;
PyObject *curarg;
anyroutine func;
PyObject *rv0, *rv;
if( kwargs ) {
PyErr_SetString(PyExc_TypeError, "Keyword args not allowed");
return 0;
}
if( !PyTuple_Check(args) ) {
PyErr_SetString(PyExc_TypeError, "Arguments not in tuple");
return 0;
}
if( PyTuple_Size(args) != self->npargs ) {
sprintf(buf, "%d arguments, expected %d", PyTuple_Size(args), self->npargs);
PyErr_SetString(PyExc_TypeError, buf);
return 0;
}
/* Decode arguments */
pargindex = 0;
for(i=0; i<self->ncargs; i++) {
cp = self->argconv[i];
if ( cp->get_uses_arg ) {
curarg = PyTuple_GET_ITEM(args, pargindex);
pargindex++;
} else {
curarg = (PyObject *)NULL;
}
c_args[i] = (*cp->get)(curarg);
}
if (PyErr_Occurred())
return 0;
/* Call function */
func = self->routine->rtn;
*(anything *)c_args[0] = (*func)(c_args[1], c_args[2], c_args[3], c_args[4],
c_args[5], c_args[6], c_args[7], c_args[8]);
/* Build return tuple (always a tuple, for now */
if( (rv=PyTuple_New(self->npreturn)) == NULL )
return NULL;
pargindex = 0;
for(i=0; i<self->ncargs; i++) {
cp = self->argconv[i];
curarg = (*cp->put)(c_args[i]);
if( cp->put_gives_result )
PyTuple_SET_ITEM(rv, pargindex, curarg);
/* NOTE: We only check errors at the end (so we free() everything) */
}
if ( PyErr_Occurred() ) {
Py_DECREF(rv);
return NULL;
}
return rv;
}
static char Cdctype__doc__[] =
""
;
static PyTypeObject Cdctype = {
PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/
"callable", /*tp_name*/
sizeof(cdcobject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)cdc_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)0, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc)cdc_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)cdc_call, /*tp_call*/
(reprfunc)0, /*tp_str*/
/* Space for future expansion */
0L,0L,0L,0L,
Cdctype__doc__ /* Documentation string */
};
/* End of code for callable objects */
/* ---------------------------------------------------------------- */
static struct PyMethodDef cdf_methods[] = {
{NULL, NULL} /* sentinel */
};
/* ---------- */
static cdfobject *
newcdfobject(conn_id, name)
CFragConnectionID conn_id;
unsigned char *name;
{
cdfobject *self;
int nlen;
self = PyObject_NEW(cdfobject, &Cdftype);
if (self == NULL)
return NULL;
self->conn_id = conn_id;
if ( name[0] > MAXNAME )
nlen = MAXNAME;
else
nlen = name[0];
strncpy(self->name, (char *)name+1, nlen);
self->name[nlen] = '\0';
return self;
}
static void
cdf_dealloc(self)
cdfobject *self;
{
PyMem_DEL(self);
}
static PyObject *
cdf_repr(self)
cdfobject *self;
{
PyObject *s;
char buf[256];
sprintf(buf, "<fragment %s connection, id 0x%x>", self->name, self->conn_id);
s = PyString_FromString(buf);
return s;
}
static PyObject *
cdf_getattr(self, name)
cdfobject *self;
char *name;
{
unsigned char *rtn_name;
anyroutine rtn;
OSErr err;
Str255 errMessage;
CFragSymbolClass class;
char buf[256];
rtn_name = Pstring(name);
err = FindSymbol(self->conn_id, rtn_name, (Ptr *)&rtn, &class);
if ( err ) {
sprintf(buf, "%.*s: %s", rtn_name[0], rtn_name+1, PyMac_StrError(err));
PyErr_SetString(ErrorObject, buf);
return NULL;
}
if( class != kTVectorCFragSymbol ) {
PyErr_SetString(ErrorObject, "Symbol is not a routine");
return NULL;
}
return (PyObject *)newcdrobject(rtn_name, rtn);
}
/* -------------------------------------------------------- */
static char Cdftype__doc__[] =
"Code Fragment library symbol table"
;
static PyTypeObject Cdftype = {
PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/
"fragment", /*tp_name*/
sizeof(cdfobject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)cdf_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)cdf_getattr, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc)cdf_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/
/* Space for future expansion */
0L,0L,0L,0L,
Cdftype__doc__ /* Documentation string */
};
/* End of code for fragment objects */
/* -------------------------------------------------------- */
static char cdll_getlibrary__doc__[] =
"Load a shared library fragment and return the symbol table"
;
static PyObject *
cdll_getlibrary(self, args)
PyObject *self; /* Not used */
PyObject *args;
{
Str255 frag_name;
OSErr err;
Str255 errMessage;
Ptr main_addr;
CFragConnectionID conn_id;
char buf[256];
if (!PyArg_ParseTuple(args, "O&", PyMac_GetStr255, frag_name))
return NULL;
/* Find the library connection ID */
err = GetSharedLibrary(frag_name, kCurrentCFragArch, kLoadCFrag, &conn_id, &main_addr,
errMessage);
if ( err ) {
sprintf(buf, "%.*s: %s", errMessage[0], errMessage+1, PyMac_StrError(err));
PyErr_SetString(ErrorObject, buf);
return NULL;
}
return (PyObject *)newcdfobject(conn_id, frag_name);
}
static char cdll_getdiskfragment__doc__[] =
"Load a fragment from a disk file and return the symbol table"
;
static PyObject *
cdll_getdiskfragment(self, args)
PyObject *self; /* Not used */
PyObject *args;
{
FSSpec fsspec;
Str255 frag_name;
OSErr err;
Str255 errMessage;
Ptr main_addr;
CFragConnectionID conn_id;
char buf[256];
Boolean isfolder, didsomething;
if (!PyArg_ParseTuple(args, "O&O&", PyMac_GetFSSpec, &fsspec,
PyMac_GetStr255, frag_name))
return NULL;
err = ResolveAliasFile(&fsspec, 1, &isfolder, &didsomething);
if ( err )
return PyErr_Mac(ErrorObject, err);
/* Load the fragment (or return the connID if it is already loaded */
err = GetDiskFragment(&fsspec, 0, 0, frag_name,
kLoadCFrag, &conn_id, &main_addr,
errMessage);
if ( err ) {
sprintf(buf, "%.*s: %s", errMessage[0], errMessage+1, PyMac_StrError(err));
PyErr_SetString(ErrorObject, buf);
return NULL;
}
return (PyObject *)newcdfobject(conn_id, frag_name);
}
static char cdll_newcall__doc__[] =
""
;
static PyObject *
cdll_newcall(self, args)
PyObject *self; /* Not used */
PyObject *args;
{
cdrobject *routine;
conventry *argconv[MAXARG+1] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
int npargs, npreturn, ncargs;
/* Note: the next format depends on MAXARG+1 */
if (!PyArg_ParseTuple(args, "O!O&|O&O&O&O&O&O&O&O&", &Cdrtype, &routine,
argparse_conv, &argconv[0], argparse_conv, &argconv[1],
argparse_conv, &argconv[2], argparse_conv, &argconv[3],
argparse_conv, &argconv[4], argparse_conv, &argconv[5],
argparse_conv, &argconv[6], argparse_conv, &argconv[7],
argparse_conv, &argconv[8]))
return NULL;
npargs = npreturn = 0;
for(ncargs=0; ncargs < MAXARG+1 && argconv[ncargs]; ncargs++) {
if( argconv[ncargs]->get_uses_arg ) npargs++;
if( argconv[ncargs]->put_gives_result ) npreturn++;
}
return (PyObject *)newcdcobject(routine, npargs, npreturn, ncargs, argconv);
}
/* List of methods defined in the module */
static struct PyMethodDef cdll_methods[] = {
{"getlibrary", (PyCFunction)cdll_getlibrary, METH_VARARGS,
cdll_getlibrary__doc__},
{"getdiskfragment", (PyCFunction)cdll_getdiskfragment, METH_VARARGS,
cdll_getdiskfragment__doc__},
{"newcall", (PyCFunction)cdll_newcall, METH_VARARGS,
cdll_newcall__doc__},
{NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */
};
/* Initialization function for the module (*must* be called initcalldll) */
static char calldll_module_documentation[] =
""
;
void
initcalldll()
{
PyObject *m, *d;
/* Create the module and add the functions */
m = Py_InitModule4("calldll", cdll_methods,
calldll_module_documentation,
(PyObject*)NULL,PYTHON_API_VERSION);
/* Add some symbolic constants to the module */
d = PyModule_GetDict(m);
ErrorObject = PyString_FromString("calldll.error");
PyDict_SetItemString(d, "error", ErrorObject);
/* XXXX Add constants here */
/* Check for errors */
if (PyErr_Occurred())
Py_FatalError("can't initialize module calldll");
}
/* Test routine */
int calldlltester(int a1,int a2,int a3,int a4,int a5,int a6,int a7,int a8)
{
printf("Tester1: %x %x %x %x %x %x %x %x\n", a1, a2, a3, a4, a5, a6, a7, a8);
return a1;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment