Redid arg/return handling (still not as I would like it to be, though).

This commit is contained in:
Jack Jansen 1997-02-20 15:18:32 +00:00
parent 78016145d6
commit e0e1f1a25d
1 changed files with 266 additions and 79 deletions

View File

@ -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,6 +109,14 @@ c2py_dummy(arg)
return 0;
}
/* Dummy routine for void return value */
static PyObject *
rv2py_none(arg)
anything arg;
{
return 0;
}
/* Routine to de-allocate storage for input-only arguments */
static PyObject *
c2py_free(arg)
@ -96,39 +128,21 @@ c2py_free(arg)
}
/*
** None
** OSErr return value.
*/
static PyObject *
c2py_none(arg)
rv2py_oserr(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;
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)
{
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;
}
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)
{
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