diff options
-rw-r--r-- | Mac/Modules/calldll.c | 339 |
1 files changed, 263 insertions, 76 deletions
diff --git a/Mac/Modules/calldll.c b/Mac/Modules/calldll.c index 02e0162..56f8c0b 100644 --- a/Mac/Modules/calldll.c +++ b/Mac/Modules/calldll.c @@ -29,33 +29,57 @@ PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ +/* Sanity check */ +#ifndef __powerc +#error Please port this code to your architecture first... +#endif + +/* +** Define to include testroutines (at the end) +*/ +#define TESTSUPPORT + #include "Python.h" #include "macglue.h" #include "macdefs.h" +#include <CodeFragments.h> +/* Prototypes for routines not in any include file (shame, shame) */ extern PyObject *ResObj_New Py_PROTO((Handle)); extern int ResObj_Convert Py_PROTO((PyObject *, Handle *)); -#include <CodeFragments.h> - static PyObject *ErrorObject; +/* Debugging macro */ +#ifdef TESTSUPPORT #define PARANOID(arg) \ if ( arg == 0 ) {PyErr_SetString(ErrorObject, "Internal error: NULL arg!"); return 0; } - -/* Prototype we use for routines */ +#else +#define PARANOID(arg) /*pass*/ +#endif + +/* Prototypes we use for routines and arguments */ typedef long anything; typedef anything (*anyroutine) Py_PROTO((...)); +/* Other constants */ #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 +** Routines to convert arguments between Python and C. +** Note return-value converters return NULL if this argument (or return value) +** doesn't return anything. The call-wrapper code collects all return values, +** and does the expected thing based on the number of return values: return None, a single +** value or a tuple of values. +** +** Hence, optional return values are also implementable. */ typedef anything (*py2c_converter) Py_PROTO((PyObject *)); typedef PyObject *(*c2py_converter) Py_PROTO((anything)); +typedef PyObject *(*rv2py_converter) Py_PROTO((anything)); + /* Dummy routine for arguments that are output-only */ static anything @@ -85,50 +109,40 @@ c2py_dummy(arg) return 0; } -/* Routine to de-allocate storage for input-only arguments */ +/* Dummy routine for void return value */ static PyObject * -c2py_free(arg) +rv2py_none(arg) anything arg; { - if ( arg ) - free((char *)arg); return 0; } -/* -** None -*/ +/* Routine to de-allocate storage for input-only arguments */ static PyObject * -c2py_none(arg) +c2py_free(arg) anything arg; { if ( arg ) free((char *)arg); - Py_INCREF(Py_None); - return Py_None; + return 0; } /* -** OSErr +** OSErr return value. */ static PyObject * -c2py_oserr(arg) +rv2py_oserr(arg) anything arg; { - OSErr *ptr = (OSErr *)arg; + OSErr err = (OSErr)arg; - PARANOID(arg); - if (*ptr) { - PyErr_Mac(PyMac_OSErrException, *ptr); - free(ptr); - return NULL; - } - Py_INCREF(Py_None); - return Py_None; + if (err) + return PyMac_Error(err); + return 0; } /* -** integers of all sizes (PPC only) +** Input integers of all sizes (PPC only) */ static anything py2c_in_int(arg) @@ -137,6 +151,19 @@ py2c_in_int(arg) return PyInt_AsLong(arg); } +/* +** Integer return values of all sizes (PPC only) +*/ +static PyObject * +rv2py_int(arg) + anything arg; +{ + return PyInt_FromLong((long)arg); +} + +/* +** Integer output parameters +*/ static PyObject * c2py_out_long(arg) anything arg; @@ -235,6 +262,18 @@ c2py_out_pstring(arg) return rv; } +static PyObject * +rv2py_pstring(arg) + anything arg; +{ + unsigned char *p = (unsigned char *)arg; + PyObject *rv; + + if ( arg == NULL ) return NULL; + rv = PyString_FromStringAndSize((char *)p+1, p[0]); + return rv; +} + /* ** C objects. */ @@ -265,6 +304,18 @@ c2py_out_cobject(arg) return rv; } +static PyObject * +rv2py_cobject(arg) + anything arg; +{ + void *ptr = (void *)arg; + PyObject *rv; + + if ( ptr == 0 ) return NULL; + rv = PyCObject_FromVoidPtr(ptr, 0); + return rv; +} + /* ** Handles. */ @@ -295,30 +346,55 @@ c2py_out_handle(arg) return prv; } +static PyObject * +rv2py_handle(arg) + anything arg; +{ + Handle rv = (Handle)arg; + + if ( rv == NULL ) return NULL; + return ResObj_New(rv); +} + 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} + {"InByte", py2c_in_int, 1, c2py_dummy}, + {"InShort", py2c_in_int, 1, c2py_dummy}, + {"InLong", py2c_in_int, 1, c2py_dummy}, + {"OutLong", py2c_alloc, 0, c2py_out_long}, + {"OutShort", py2c_alloc, 0, c2py_out_short}, + {"OutByte", py2c_alloc, 0, c2py_out_byte}, + {"InString", py2c_in_string, 1, c2py_dummy}, + {"InPstring", py2c_in_pstring,1, c2py_free}, + {"OutPstring", py2c_out_pstring,0, c2py_out_pstring}, + {"InCobject", py2c_in_cobject,1, c2py_dummy}, + {"OutCobject", py2c_alloc, 0, c2py_out_cobject}, + {"InHandle", py2c_in_handle, 1, c2py_dummy}, + {"OutHandle", py2c_alloc, 0, c2py_out_handle}, + {0, 0, 0, 0} +}; + +typedef struct { + char *name; + rv2py_converter rtn; +} rvconventry; + +static rvconventry rvconverters[] = { + {"None", rv2py_none}, + {"OSErr", rv2py_oserr}, + {"Byte", rv2py_int}, + {"Short", rv2py_int}, + {"Long", rv2py_int}, + {"Pstring", rv2py_pstring}, + {"Cobject", rv2py_cobject}, + {"Handle", rv2py_handle}, + {0, 0} }; static conventry * @@ -336,6 +412,21 @@ getconverter(name) return 0; } +static rvconventry * +getrvconverter(name) + char *name; +{ + int i; + char buf[256]; + + for(i=0; rvconverters[i].name; i++ ) + if ( strcmp(name, rvconverters[i].name) == 0 ) + return &rvconverters[i]; + sprintf(buf, "Unknown return value type: %s", name); + PyErr_SetString(ErrorObject, buf); + return 0; +} + static int argparse_conv(obj, ptr) PyObject *obj; @@ -353,6 +444,23 @@ argparse_conv(obj, ptr) return 1; } +static int +argparse_rvconv(obj, ptr) + PyObject *obj; + rvconventry **ptr; +{ + char *name; + int i; + rvconventry *item; + + if( (name=PyString_AsString(obj)) == NULL ) + return 0; + if( (item=getrvconverter(name)) == NULL ) + return 0; + *ptr = item; + return 1; +} + /* ----------------------------------------------------- */ /* Declarations for objects of type fragment */ @@ -385,13 +493,14 @@ 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 */ + cdrobject *routine; /* The routine to call */ + int npargs; /* Python argument count */ + int ncargs; /* C argument count + 1 */ + rvconventry *rvconv; /* Return value converter */ + conventry *argconv[MAXARG]; /* Value converter list */ } cdcobject; staticforward PyTypeObject Cdctype; @@ -491,11 +600,11 @@ static struct PyMethodDef cdc_methods[] = { static cdcobject * -newcdcobject(routine, npargs, npreturn, ncargs, argconv) +newcdcobject(routine, npargs, ncargs, rvconv, argconv) cdrobject *routine; int npargs; - int npreturn; int ncargs; + rvconventry *rvconv; conventry *argconv[]; { cdcobject *self; @@ -507,9 +616,9 @@ newcdcobject(routine, npargs, npreturn, ncargs, argconv) self->routine = routine; Py_INCREF(routine); self->npargs = npargs; - self->npreturn = npreturn; self->ncargs = ncargs; - for(i=0; i<MAXARG+1; i++) + self->rvconv = rvconv; + for(i=0; i<MAXARG; i++) if ( i < ncargs ) self->argconv[i] = argconv[i]; else @@ -534,8 +643,8 @@ cdc_repr(self) char buf[256]; int i; - sprintf(buf, "<callable %s = %s(", self->argconv[0]->name, self->routine->name); - for(i=1; i< self->ncargs; i++) { + sprintf(buf, "<callable %s = %s(", self->rvconv->name, self->routine->name); + for(i=0; i< self->ncargs; i++) { strcat(buf, self->argconv[i]->name); if ( i < self->ncargs-1 ) strcat(buf, ", "); @@ -557,11 +666,13 @@ cdc_call(self, args, kwargs) { char buf[256]; int i, pargindex; - anything c_args[MAXARG+1] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; + anything c_args[MAXARG] = {0, 0, 0, 0, 0, 0, 0, 0}; + anything c_rv; conventry *cp; PyObject *curarg; anyroutine func; - PyObject *rv0, *rv; + PyObject *returnvalues[MAXARG+1]; + PyObject *rv; if( kwargs ) { PyErr_SetString(PyExc_TypeError, "Keyword args not allowed"); @@ -594,24 +705,45 @@ cdc_call(self, args, kwargs) /* 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]); + c_rv = (*func)(c_args[0], c_args[1], c_args[2], c_args[3], + c_args[4], c_args[5], c_args[6], c_args[7]); - /* Build return tuple (always a tuple, for now */ - if( (rv=PyTuple_New(self->npreturn)) == NULL ) - return NULL; + /* Decode return value, and store into returnvalues if needed */ pargindex = 0; + curarg = (*self->rvconv->rtn)(c_rv); + if ( curarg ) + returnvalues[pargindex++] = curarg; + + /* Decode returnvalue parameters and cleanup any storage allocated */ 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); + if(curarg) + returnvalues[pargindex++] = curarg; /* NOTE: We only check errors at the end (so we free() everything) */ } if ( PyErr_Occurred() ) { - Py_DECREF(rv); + /* An error did occur. Free the python objects created */ + for(i=0; i<pargindex; i++) + Py_XDECREF(returnvalues[i]); return NULL; } + + /* Zero and one return values cases are special: */ + if ( pargindex == 0 ) { + Py_INCREF(Py_None); + return Py_None; + } + if ( pargindex == 1 ) + return returnvalues[0]; + + /* More than one return value: put in a tuple */ + rv = PyTuple_New(pargindex); + for(i=0; i<pargindex; i++) + if(rv) + PyTuple_SET_ITEM(rv, i, returnvalues[i]); + else + Py_XDECREF(returnvalues[i]); return rv; } @@ -833,23 +965,23 @@ cdll_newcall(self, args) PyObject *args; { cdrobject *routine; - conventry *argconv[MAXARG+1] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; - int npargs, npreturn, ncargs; + conventry *argconv[MAXARG] = {0, 0, 0, 0, 0, 0, 0, 0}; + rv2py_converter rvconv; + int npargs, ncargs; - /* Note: the next format depends on MAXARG+1 */ + /* Note: the next format depends on MAXARG */ if (!PyArg_ParseTuple(args, "O!O&|O&O&O&O&O&O&O&O&", &Cdrtype, &routine, + argparse_rvconv, &rvconv, 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])) + argparse_conv, &argconv[6], argparse_conv, &argconv[7])) return NULL; - npargs = npreturn = 0; - for(ncargs=0; ncargs < MAXARG+1 && argconv[ncargs]; ncargs++) { + npargs = 0; + for(ncargs=0; ncargs < MAXARG && 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); + return (PyObject *)newcdcobject(routine, npargs, ncargs, rvconv, argconv); } /* List of methods defined in the module */ @@ -894,10 +1026,65 @@ initcalldll() Py_FatalError("can't initialize module calldll"); } +#ifdef TESTSUPPORT + /* Test routine */ -int calldlltester(int a1,int a2,int a3,int a4,int a5,int a6,int a7,int a8) +int cdll_b_bbbbbbbb(char a1,char a2,char a3,char a4,char a5,char a6,char a7,char a8) +{ + return a1+a2+a3+a4+a5+a6+a7+a8; +} + +short cdll_h_hhhhhhhh(short a1,short a2,short a3,short a4,short a5,short a6,short a7,short a8) +{ + return a1+a2+a3+a4+a5+a6+a7+a8; +} + +int cdll_l_llllllll(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; + return a1+a2+a3+a4+a5+a6+a7+a8; } +void cdll_N_ssssssss(char *a1,char *a2,char *a3,char *a4,char *a5,char *a6,char *a7,char *a8) +{ + printf("cdll_N_ssssssss args: %s %s %s %s %s %s %s %s\n", a1, a2, a3, a4, + a5, a6, a7, a8); +} + +OSErr cdll_o_l(long l) +{ + return (OSErr)l; +} + +void cdll_N_pp(unsigned char *in, unsigned char *out) +{ + out[0] = in[0] + 5; + strcpy((char *)out+1, "Was: "); + memcpy(out+6, in+1, in[0]); +} + +void cdll_N_bb(char a1, char *a2) +{ + *a2 = a1; +} + +void cdll_N_hh(short a1, short *a2) +{ + *a2 = a1; +} + +void cdll_N_ll(long a1, long *a2) +{ + *a2 = a1; +} + +void cdll_N_sH(char *a1, Handle a2) +{ + int len; + + len = strlen(a1); + SetHandleSize(a2, len); + HLock(a2); + memcpy(*a2, a1, len); + HUnlock(a2); +} +#endif |