[ctypes-commit] ctypes/source ctypes.h,1.74.2.7,1.74.2.8 callproc.c,1.127.2.16,1.127.2.17 callbacks.
Brought to you by:
theller
From: Thomas H. <th...@us...> - 2006-01-02 19:03:13
|
Update of /cvsroot/ctypes/ctypes/source In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1328 Modified Files: Tag: branch_1_0 ctypes.h callproc.c callbacks.c _ctypes.c Log Message: Subtypes of simple types (the c_int and c_char variations, c_void_p, c_char_p and c_wchar_p) behave different now. XXX More explanations needed. Index: ctypes.h =================================================================== RCS file: /cvsroot/ctypes/ctypes/source/ctypes.h,v retrieving revision 1.74.2.7 retrieving revision 1.74.2.8 diff -C2 -d -r1.74.2.7 -r1.74.2.8 *** ctypes.h 29 Nov 2005 20:15:17 -0000 1.74.2.7 --- ctypes.h 2 Jan 2006 19:02:52 -0000 1.74.2.8 *************** *** 377,380 **** --- 377,384 ---- extern PyObject *CData_FromBaseObj(PyObject *type, PyObject *base, int index, char *adr); + /* XXX better name needed! */ + extern int IsSimpleSubType(PyObject *obj); + + #ifdef MS_WIN32 extern PyObject *ComError; Index: callbacks.c =================================================================== RCS file: /cvsroot/ctypes/ctypes/source/callbacks.c,v retrieving revision 1.71.2.7 retrieving revision 1.71.2.8 diff -C2 -d -r1.71.2.7 -r1.71.2.8 *** callbacks.c 30 Dec 2005 17:22:49 -0000 1.71.2.7 --- callbacks.c 2 Jan 2006 19:02:52 -0000 1.71.2.8 *************** *** 151,155 **** } ! if (dict && dict->getfunc) { PyObject *v = dict->getfunc(*pArgs, dict->size); if (!v) { --- 151,155 ---- } ! if (dict && dict->getfunc && !IsSimpleSubType(cnv)) { PyObject *v = dict->getfunc(*pArgs, dict->size); if (!v) { Index: callproc.c =================================================================== RCS file: /cvsroot/ctypes/ctypes/source/callproc.c,v retrieving revision 1.127.2.16 retrieving revision 1.127.2.17 diff -C2 -d -r1.127.2.16 -r1.127.2.17 *** callproc.c 30 Dec 2005 17:22:49 -0000 1.127.2.16 --- callproc.c 2 Jan 2006 19:02:52 -0000 1.127.2.17 *************** *** 24,30 **** COM method, are 'paramflags' available). ! 3. If [out] parameters are present in paramflags, _build_callargs also ! creates and returns another object, which is either a single object or a ! tuple, whcih will later be used to build the function return value. 4. _CallProc is then called with the 'callargs' tuple. _CallProc first --- 24,30 ---- COM method, are 'paramflags' available). ! 3. _build_callargs also calculates bitarrays containing indexes into ! the callargs tuple, specifying how to build the return value(s) of ! the function. 4. _CallProc is then called with the 'callargs' tuple. _CallProc first *************** *** 716,720 **** return PyObject_CallFunction(restype, "i", *(int *)result); ! if (dict->getfunc) retval = dict->getfunc(result, dict->size); else --- 716,720 ---- return PyObject_CallFunction(restype, "i", *(int *)result); ! if (dict->getfunc && !IsSimpleSubType(restype)) retval = dict->getfunc(result, dict->size); else *************** *** 807,813 **** progid = NULL; - #ifndef _WIN32_WCE ProgIDFromCLSID(&guid, &progid); - #endif /* XXX Is COMError derived from WindowsError or not? */ --- 807,811 ---- *************** *** 1028,1032 **** name = PyString_AsString(nameobj); if(!name) ! return NULL; #endif --- 1026,1030 ---- name = PyString_AsString(nameobj); if(!name) ! return NULL; #endif *************** *** 1387,1391 **** static char set_conversion_mode_doc[] = ! "set_conversion_mode(encoding, errors) -> (previous-encoding, previous-errors)\n\ \n\ Set the encoding and error handling ctypes uses when converting\n\ --- 1385,1389 ---- static char set_conversion_mode_doc[] = ! "FormatError(encoding, errors) -> (previous-encoding, previous-errors)\n\ \n\ Set the encoding and error handling ctypes uses when converting\n\ Index: _ctypes.c =================================================================== RCS file: /cvsroot/ctypes/ctypes/source/_ctypes.c,v retrieving revision 1.226.2.40 retrieving revision 1.226.2.41 diff -C2 -d -r1.226.2.40 -r1.226.2.41 *** _ctypes.c 2 Jan 2006 15:06:40 -0000 1.226.2.40 --- _ctypes.c 2 Jan 2006 19:02:52 -0000 1.226.2.41 *************** *** 2024,2042 **** } PyObject * CData_get(PyObject *type, GETFUNC getfunc, PyObject *src, int index, int size, char *adr) { if (getfunc) return getfunc(adr, size); ! if (type) { ! StgDictObject *dict; ! dict = PyType_stgdict(type); ! if (dict && dict->getfunc) ! return dict->getfunc(adr, size); ! return CData_FromBaseObj(type, src, index, adr); ! } ! assert (getfunc); ! return getfunc(adr, size); } --- 2024,2053 ---- } + /* + This function returns TRUE for c_int, c_void_p, and these kind of + classes. FALSE otherwise FALSE also for subclasses of c_int and + such. + */ + int IsSimpleSubType(PyObject *obj) + { + PyTypeObject *type = (PyTypeObject *)obj; + + if (SimpleTypeObject_Check(type)) + return type->tp_base != &Simple_Type; + return 0; + } + PyObject * CData_get(PyObject *type, GETFUNC getfunc, PyObject *src, int index, int size, char *adr) { + StgDictObject *dict; if (getfunc) return getfunc(adr, size); ! assert(type); ! dict = PyType_stgdict(type); ! if (dict && dict->getfunc && !IsSimpleSubType(type)) ! return dict->getfunc(adr, size); ! return CData_FromBaseObj(type, src, index, adr); } *************** *** 2369,2400 **** #endif ! /* Return 1 if usable, 0 else. */ static int _check_outarg_type(PyObject *arg, int index) { - #if 0 StgDictObject *dict; - #endif if (PointerTypeObject_Check(arg)) return 1; ! #if 0 ! /* This is also disabled, because _build_callargs does not handle ! these correctly. */ if (ArrayTypeObject_Check(arg)) return 1; ! #endif ! #if 0 ! /* This is also disabled, because _build_callargs does not handle ! these correctly. */ dict = PyType_stgdict(arg); ! if (dict) { ! if (PyString_Check(dict->proto) ! && (strchr("sPzUZXO", PyString_AS_STRING(dict->proto)[0]))) { ! /* simple pointer types, c_void_p, c_wchar_p, BSTR, ... */ ! return 1; ! } } ! #endif PyErr_Format(PyExc_TypeError, "'out' parameter %d must be a pointer type, not %s", --- 2380,2404 ---- #endif ! /* Return 1 if usable, 0 else and exception set. */ static int _check_outarg_type(PyObject *arg, int index) { StgDictObject *dict; if (PointerTypeObject_Check(arg)) return 1; ! if (ArrayTypeObject_Check(arg)) return 1; ! dict = PyType_stgdict(arg); ! if (dict ! /* simple pointer types, c_void_p, c_wchar_p, BSTR, ... */ ! && PyString_Check(dict->proto) ! /* We only allow c_void_p, c_char_p and c_wchar_p as a simple output parameter type */ ! && (strchr("PzZ", PyString_AS_STRING(dict->proto)[0]))) { ! return 1; } ! PyErr_Format(PyExc_TypeError, "'out' parameter %d must be a pointer type, not %s", *************** *** 2446,2452 **** case PARAMFLAG_FIN: case PARAMFLAG_FIN | PARAMFLAG_FLCID: break; case PARAMFLAG_FOUT: - case (PARAMFLAG_FIN | PARAMFLAG_FOUT): if (!_check_outarg_type(typ, i+1)) return 0; --- 2450,2456 ---- case PARAMFLAG_FIN: case PARAMFLAG_FIN | PARAMFLAG_FLCID: + case PARAMFLAG_FIN | PARAMFLAG_FOUT: break; case PARAMFLAG_FOUT: if (!_check_outarg_type(typ, i+1)) return 0; *************** *** 2743,2758 **** missing in the function call. ! Note: keyword args not yet implemented! ! ! This function builds a new tuple 'callargs' which contains the parameters to ! use in the call. Items on this tuple are copied from the 'inargs' tuple for ! 'in' parameters, and constructed from the 'argtypes' tuple for 'out' ! parameters. ! */ static PyObject * _build_callargs(CFuncPtrObject *self, PyObject *argtypes, PyObject *inargs, PyObject *kwds, ! PyObject **poutargs) { PyObject *paramflags = self->paramflags; --- 2747,2763 ---- missing in the function call. ! This function builds and returns a new tuple 'callargs' which contains the ! parameters to use in the call. Items on this tuple are copied from the ! 'inargs' tuple for 'in' and 'in, out' parameters, and constructed from the ! 'argtypes' tuple for 'out' parameters. It also calculates numretvals which ! is the number of return values for the function, outmask/inoutmask are ! bitmasks containing indexes into the callargs tuple specifying which ! parameters have to be returned. _build_result builds the return value of the ! function. */ static PyObject * _build_callargs(CFuncPtrObject *self, PyObject *argtypes, PyObject *inargs, PyObject *kwds, ! int *poutmask, int *pinoutmask, int *pnumretvals) { PyObject *paramflags = self->paramflags; *************** *** 2761,2765 **** int i, len; int inargs_index = 0; - int outmask = 0; /* It's a little bit difficult to determine how many arguments the function call requires/accepts. For simplicity, we count the consumed --- 2766,2769 ---- *************** *** 2767,2771 **** int actual_args; ! *poutargs = NULL; /* Trivial cases, where we either return inargs itself, or a slice of it. */ if (argtypes == NULL || paramflags == NULL || PyTuple_GET_SIZE(argtypes) == 0) { --- 2771,2778 ---- int actual_args; ! *poutmask = 0; ! *pinoutmask = 0; ! *pnumretvals = 0; ! /* Trivial cases, where we either return inargs itself, or a slice of it. */ if (argtypes == NULL || paramflags == NULL || PyTuple_GET_SIZE(argtypes) == 0) { *************** *** 2791,2811 **** for (i = 0; i < len; ++i) { PyObject *item = PyTuple_GET_ITEM(paramflags, i); ! PyObject *ob, *v; int flag; char *name = NULL; PyObject *defval = NULL; ! if (!PyArg_ParseTuple(item, "i|zO", &flag, &name, &defval)) { ! /* Hm. Either we should raise a more specific error ! here, or we should validate the paramflags tuple ! when it is set */ ! _AddTraceback("_build_callargs", __FILE__, __LINE__-4); ! goto error; ! } switch (flag & (PARAMFLAG_FIN | PARAMFLAG_FOUT | PARAMFLAG_FLCID)) { case PARAMFLAG_FIN | PARAMFLAG_FLCID: ! /* ['in', 'lcid'] parameeter. Always taken from defval */ Py_INCREF(defval); PyTuple_SET_ITEM(callargs, i, defval); break; case 0: case PARAMFLAG_FIN: --- 2798,2824 ---- for (i = 0; i < len; ++i) { PyObject *item = PyTuple_GET_ITEM(paramflags, i); ! PyObject *ob; int flag; char *name = NULL; PyObject *defval = NULL; ! ! /* This way seems to be ~2 us faster than the PyArg_ParseTuple ! calls below. */ ! /* We HAVE already checked that the tuple can be parsed with "i|zO", so... */ ! int tsize = PyTuple_GET_SIZE(item); ! flag = PyInt_AS_LONG(PyTuple_GET_ITEM(item, 0)); ! name = tsize > 1 ? PyString_AS_STRING(PyTuple_GET_ITEM(item, 1)) : NULL; ! defval = tsize > 2 ? PyTuple_GET_ITEM(item, 2) : NULL; ! switch (flag & (PARAMFLAG_FIN | PARAMFLAG_FOUT | PARAMFLAG_FLCID)) { case PARAMFLAG_FIN | PARAMFLAG_FLCID: ! /* ['in', 'lcid'] parameter. Always taken from defval */ Py_INCREF(defval); PyTuple_SET_ITEM(callargs, i, defval); break; + case (PARAMFLAG_FIN | PARAMFLAG_FOUT): + *pinoutmask |= (1 << i); /* mark as inout arg */ + (*pnumretvals)++; + /* fall through to PARAMFLAG_FIN... */ case 0: case PARAMFLAG_FIN: *************** *** 2817,2833 **** break; case PARAMFLAG_FOUT: /* 'out' parameter. argtypes[i] must be a POINTER to a c type. */ ob = PyTuple_GET_ITEM(argtypes, i); dict = PyType_stgdict(ob); ! /* Create an instance of the pointed-to type */ ! ob = PyObject_CallObject(dict->proto, NULL); ! /* XXX The above only works as intended for POINTER ! types. For ARRAY types, we should create an ! intance of the type itself, not of the itemtype. ! ! But that is not enough: ! We must not pass a byref() to the array then but the array instance itself. Then, we cannot retrive --- 2830,2866 ---- break; case PARAMFLAG_FOUT: + /* XXX Refactor this code into a separate function. */ /* 'out' parameter. argtypes[i] must be a POINTER to a c type. + + Cannot by supplied in inargs, but a defval will be used + if available. XXX Should we support getting it from kwds? */ + if (defval) { + /* XXX Using mutable objects as defval will + make the function non-threadsafe, unless we + copy the object in each invocation */ + Py_INCREF(defval); + PyTuple_SET_ITEM(callargs, i, defval); + *poutmask |= (1 << i); /* mark as out arg */ + (*pnumretvals)++; + break; + } ob = PyTuple_GET_ITEM(argtypes, i); dict = PyType_stgdict(ob); ! if (PyString_Check(dict->proto)) { ! PyErr_Format( ! PyExc_TypeError, ! "%s 'out' parameter must be passed as default value", ! ((PyTypeObject *)ob)->tp_name); ! goto error; ! } ! if (ArrayTypeObject_Check(ob)) ! ob = PyObject_CallObject(ob, NULL); ! else ! /* Create an instance of the pointed-to type */ ! ob = PyObject_CallObject(dict->proto, NULL); ! /* ! XXX Is the following correct any longer? We must not pass a byref() to the array then but the array instance itself. Then, we cannot retrive *************** *** 2836,2872 **** if (ob == NULL) goto error; ! /* Insert as byref parameter */ ! ob = _byref(ob); ! if (ob == NULL) ! goto error; ! PyTuple_SET_ITEM(callargs, i, ob); ! outmask |= (1 << i); ! break; ! case (PARAMFLAG_FIN | PARAMFLAG_FOUT): ! /* for [in, out] parameters, we should probably ! - call _get_arg to get the [in] value ! - create an object with the [in] value as parameter ! - and then proceed in the same way as for an [out] parameter ! */ ! ob = PyTuple_GET_ITEM(argtypes, i); ! dict = PyType_stgdict(ob); ! /* Create an instance of the pointed-to type */ ! v = _get_arg(&inargs_index, name, defval, inargs, kwds); ! if (v == 0) ! goto error; ! /* XXX But this looks wrong. Shouldn't we call ! <type>.from_param(<value>) ? ! */ ! ob = PyObject_CallFunctionObjArgs(dict->proto, ! v, ! NULL); ! Py_DECREF(v); ! if (ob == 0) ! goto error; ! ob = _byref(ob); ! if (ob == NULL) ! goto error; PyTuple_SET_ITEM(callargs, i, ob); ! outmask |= (1 << i); break; default: --- 2869,2877 ---- if (ob == NULL) goto error; ! /* The .from_param call that will ocurr later will pass this ! as a byref parameter. */ PyTuple_SET_ITEM(callargs, i, ob); ! *poutmask |= (1 << i); /* mark as out arg */ ! (*pnumretvals)++; break; default: *************** *** 2896,2934 **** these indexes contain values to return. */ - - len = 0; - for (i = 0; i < 32; ++i) { - if (outmask & (1 << i)) - ++len; - } - - switch (len) { - int j; - case 0: - *poutargs = NULL; - break; - case 1: - for (i = 0; i < 32; ++i) { - if (outmask & (1 << i)) { - *poutargs = PyTuple_GET_ITEM(callargs, i); - Py_INCREF(*poutargs); - break; - } - } - break; - default: - *poutargs = PyTuple_New(len); - j = 0; - for (i = 0; i < 32; ++i) { - PyObject *ob; - if (outmask & (1 << i)) { - ob = PyTuple_GET_ITEM(callargs, i); - Py_INCREF(ob); - PyTuple_SET_ITEM(*poutargs, j, ob); - ++j; - } - } - } - return callargs; error: --- 2901,2904 ---- *************** *** 2940,2982 **** http://msdn.microsoft.com/library/en-us/com/html/769127a1-1a14-4ed4-9d38-7cf3e571b661.asp */ static PyObject * _get_one(PyObject *obj) { /* __ctypes_from_outparam__ lets of specify how 'out' parameters are retrieved from COM method class. */ ! PyCArgObject *arg = (PyCArgObject *)obj; ! return PyObject_CallMethod(arg->obj, "__ctypes_from_outparam__", NULL); } static PyObject * ! _build_result(PyObject *result, PyObject *outargs) { ! int i, len; ! if (outargs == NULL) return result; - if (result == NULL) { - Py_DECREF(outargs); - return NULL; } Py_DECREF(result); ! if (!PyTuple_CheckExact(outargs)) { ! PyObject *v = _get_one(outargs); ! Py_DECREF(outargs); ! return v; } ! assert (outargs->ob_refcnt == 1); ! /* We know we are sole owner of the outargs tuple. So, we can replace ! the values in it instead of allocating a new one. ! */ ! len = PyTuple_GET_SIZE(outargs); ! for (i = 0; i < len; ++i) { ! PyObject *ob = _get_one(PyTuple_GET_ITEM(outargs, i)); ! PyTuple_SetItem(outargs, i, ob); } ! return outargs; } --- 2910,2987 ---- http://msdn.microsoft.com/library/en-us/com/html/769127a1-1a14-4ed4-9d38-7cf3e571b661.asp */ + /* + XXX BUG: [in, out] parameters MUST be returned as-is. + */ static PyObject * _get_one(PyObject *obj) { + if (PyCArg_CheckExact(obj)) { + PyCArgObject *arg = (PyCArgObject *)obj; + obj = arg->obj; + } /* __ctypes_from_outparam__ lets of specify how 'out' parameters are retrieved from COM method class. */ ! return PyObject_CallMethod(obj, "__ctypes_from_outparam__", NULL); } + /* + Build return value of a function. + + Consumes the refcount on result and callargs. + */ static PyObject * ! _build_result(PyObject *result, PyObject *callargs, ! int outmask, int inoutmask, int numretvals) { ! int i, index, bit; ! PyObject *tup; ! if (callargs == NULL) ! return result; ! if (result == NULL || numretvals == 0) { ! Py_DECREF(callargs); return result; } Py_DECREF(result); ! /* allocate tuple to hold the result */ ! if (numretvals > 1) { ! tup = PyTuple_New(numretvals); ! if (tup == NULL) { ! Py_DECREF(callargs); ! return NULL; ! } } ! ! index = 0; ! for (bit = 1, i = 0; i < 32; ++i, bit <<= 1) { ! PyObject *v; ! if (bit & inoutmask) { ! v = PyTuple_GET_ITEM(callargs, i); ! Py_INCREF(v); ! if (numretvals == 1) { ! Py_DECREF(callargs); ! return v; ! } ! PyTuple_SET_ITEM(tup, index, v); ! index++; ! } else if (bit & outmask) { ! v = PyTuple_GET_ITEM(callargs, i); ! v = PyObject_CallMethod(v, "__ctypes_from_outparam__", NULL); ! if (v == NULL || numretvals == 1) { ! Py_DECREF(callargs); ! return v; ! } ! PyTuple_SET_ITEM(tup, index, v); ! index++; ! } ! if (index == numretvals) ! break; } ! ! Py_DECREF(callargs); ! return tup; } *************** *** 2991,2995 **** PyObject *result; PyObject *callargs; - PyObject *outargs; PyObject *errcheck; #ifdef MS_WIN32 --- 2996,2999 ---- *************** *** 2998,3001 **** --- 3002,3009 ---- void *pProc = NULL; + int inoutmask; + int outmask; + int numretvals; + assert(dict); /* if not, it's a bug */ restype = self->restype ? self->restype : dict->restype; *************** *** 3039,3047 **** } #endif ! callargs = _build_callargs(self, argtypes, inargs, kwds, &outargs); ! if (callargs == NULL) { ! Py_XDECREF(outargs); return NULL; - } if (converters) { --- 3047,3055 ---- } #endif ! callargs = _build_callargs(self, argtypes, ! inargs, kwds, ! &outmask, &inoutmask, &numretvals); ! if (callargs == NULL) return NULL; if (converters) { *************** *** 3089,3106 **** self, callargs, - outargs, NULL); ! Py_DECREF(result); ! Py_DECREF(callargs); ! Py_XDECREF(outargs); ! return v; } ! Py_DECREF(callargs); ! /* _build_result assumes that we are the sole owner of the outargs ! tuple. Since _build_result is never called when errcheck is used ! (see above), this assumtion is still true. ! */ ! return _build_result(result, outargs); } --- 3097,3117 ---- self, callargs, NULL); ! /* If the errcheck funtion failed, return NULL. ! If the errcheck function returned callargs unchanged, ! continue normal processing. ! If the errcheck function returned something else, ! use that as result. ! */ ! if (v == NULL || v != callargs) { ! Py_DECREF(result); ! Py_DECREF(callargs); ! return v; ! } ! Py_DECREF(v); } ! return _build_result(result, callargs, ! outmask, inoutmask, numretvals); } *************** *** 3731,3736 **** Simple_get_value(CDataObject *self) { ! StgDictObject *dict = PyObject_stgdict((PyObject *)self); assert(dict->getfunc); return dict->getfunc(self->b_ptr, self->b_size); } --- 3742,3749 ---- Simple_get_value(CDataObject *self) { ! StgDictObject *dict; ! dict = PyObject_stgdict((PyObject *)self); assert(dict->getfunc); + dict = PyObject_stgdict((PyObject *)self); return dict->getfunc(self->b_ptr, self->b_size); } *************** *** 3771,3774 **** --- 3784,3791 ---- Simple_from_outparm(PyObject *self, PyObject *args) { + if (IsSimpleSubType((PyObject *)self->ob_type)) { + Py_INCREF(self); + return self; + } /* call stgdict->getfunc */ return Simple_get_value((CDataObject *)self); |