]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Redid arg/return handling (still not as I would like it to be, though).
authorJack Jansen <jack.jansen@cwi.nl>
Thu, 20 Feb 1997 15:18:32 +0000 (15:18 +0000)
committerJack Jansen <jack.jansen@cwi.nl>
Thu, 20 Feb 1997 15:18:32 +0000 (15:18 +0000)
Mac/Modules/calldll.c

index 02e016267a40150bf36bd8c96e1489f228167ca9..56f8c0bcb65b37b92cc555c2b74cf9fe65101426 100644 (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,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