]> granicus.if.org Git - python/commitdiff
An initial stab at calling random C routines from Python
authorJack Jansen <jack.jansen@cwi.nl>
Mon, 17 Feb 1997 16:56:56 +0000 (16:56 +0000)
committerJack Jansen <jack.jansen@cwi.nl>
Mon, 17 Feb 1997 16:56:56 +0000 (16:56 +0000)
Mac/Modules/calldll.c [new file with mode: 0644]

diff --git a/Mac/Modules/calldll.c b/Mac/Modules/calldll.c
new file mode 100644 (file)
index 0000000..02e0162
--- /dev/null
@@ -0,0 +1,903 @@
+/***********************************************************
+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;
+}
+