Redid arg/return handling (still not as I would like it to be, though).
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 @@
 
 ******************************************************************/
 
+/* 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 @@
 	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 @@
 }
 
 /*
-** 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 
 /* 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 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 @@
 	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 @@
 	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 @@
 {
 	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 @@
 		
 	/* 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 @@
 	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 @@
 		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