summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Rigo <arigo@tunes.org>2013-01-06 23:38:09 +0100
committerArmin Rigo <arigo@tunes.org>2013-01-06 23:38:09 +0100
commitddcfce7f6e3cefa6b67ca336a34f26f1e2839be2 (patch)
treeeb3180eb8612eda52684ac4c2af174d3b6414b95
parent62731835337e163268eb28befcc9aa297fabe271 (diff)
downloadcffi-ddcfce7f6e3cefa6b67ca336a34f26f1e2839be2.tar.gz
Code simplification: instead of allocating & freeing some strings around
the calls in some cases, just use alloca().
-rw-r--r--c/_cffi_backend.c94
1 files changed, 36 insertions, 58 deletions
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
index 759c970..57dea2c 100644
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -1914,17 +1914,20 @@ static CTypeDescrObject *_get_ct_int(void)
return ct_int;
}
-static int
+static Py_ssize_t
_prepare_pointer_call_argument(CTypeDescrObject *ctptr, PyObject *init,
char **output_data)
{
/* 'ctptr' is here a pointer type 'ITEM *'. Accept as argument an
initializer for an array 'ITEM[]'. This includes the case of
- passing a Python byte string to a 'char *' argument. */
+ passing a Python byte string to a 'char *' argument.
+
+ This function returns -1 if an error occurred,
+ 0 if conversion succeeded (into *output_data),
+ or N > 0 if conversion would require N bytes of storage.
+ */
Py_ssize_t length, datasize;
CTypeDescrObject *ctitem = ctptr->ct_itemdescr;
- PyObject *result;
- char *data;
/* XXX some code duplication, how to avoid it? */
if (PyBytes_Check(init)) {
@@ -1933,11 +1936,11 @@ _prepare_pointer_call_argument(CTypeDescrObject *ctptr, PyObject *init,
if ((ctptr->ct_flags & CT_CAST_ANYTHING) ||
((ctitem->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED))
&& (ctitem->ct_size == sizeof(char)))) {
- output_data[0] = PyBytes_AS_STRING(init);
- return 1;
+ *output_data = PyBytes_AS_STRING(init);
+ return 0;
}
else
- return 0;
+ goto convert_default;
}
else if (PyList_Check(init) || PyTuple_Check(init)) {
length = PySequence_Fast_GET_SIZE(init);
@@ -1947,39 +1950,31 @@ _prepare_pointer_call_argument(CTypeDescrObject *ctptr, PyObject *init,
length = _my_PyUnicode_SizeAsWideChar(init) + 1;
}
else if ((ctitem->ct_flags & CT_IS_FILE) && PyFile_Check(init)) {
- output_data[0] = (char *)PyFile_AsFile(init);
- if (output_data[0] == NULL && PyErr_Occurred())
+ *output_data = (char *)PyFile_AsFile(init);
+ if (*output_data == NULL && PyErr_Occurred())
return -1;
- return 1;
+ return 0;
}
else {
/* refuse to receive just an integer (and interpret it
as the array size) */
- return 0;
+ goto convert_default;
}
if (ctitem->ct_size <= 0)
- return 0;
+ goto convert_default;
datasize = length * ctitem->ct_size;
if ((datasize / ctitem->ct_size) != length) {
PyErr_SetString(PyExc_OverflowError,
"array size would overflow a Py_ssize_t");
return -1;
}
+ if (datasize <= 0)
+ datasize = 1;
+ return datasize;
- result = PyBytes_FromStringAndSize(NULL, datasize);
- if (result == NULL)
- return -1;
-
- data = PyBytes_AS_STRING(result);
- memset(data, 0, datasize);
- if (convert_array_from_object(data, ctptr, init) < 0) {
- Py_DECREF(result);
- return -1;
- }
- output_data[0] = data;
- output_data[1] = (char *)result;
- return 1;
+ convert_default:
+ return convert_from_object((char *)output_data, ctptr, init);
}
static PyObject*
@@ -1988,7 +1983,7 @@ cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds)
char *buffer;
void** buffer_array;
cif_description_t *cif_descr;
- Py_ssize_t i, nargs, nargs_declared, free_me_until = 0;
+ Py_ssize_t i, nargs, nargs_declared;
PyObject *signature, *res = NULL, *fvarargs;
CTypeDescrObject *fresult;
char *resultdata;
@@ -2098,22 +2093,23 @@ cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds)
else
argtype = (CTypeDescrObject *)PyTuple_GET_ITEM(fvarargs, i);
- if (argtype->ct_flags & CT_POINTER) {
- ((char **)data)[1] = NULL;
-
- if (!CData_Check(obj)) {
- int res = _prepare_pointer_call_argument(argtype, obj,
- (char **)data);
- if (res != 0) {
- if (res < 0)
- goto error;
- assert(i < nargs_declared); /* otherwise, obj is a CData */
- free_me_until = i + 1;
- continue;
- }
+ if ((argtype->ct_flags & CT_POINTER) && !CData_Check(obj)) {
+ char *tmpbuf;
+ Py_ssize_t datasize = _prepare_pointer_call_argument(
+ argtype, obj, (char **)data);
+ if (datasize == 0)
+ ; /* successfully filled '*data' */
+ else if (datasize < 0)
+ goto error;
+ else {
+ tmpbuf = alloca(datasize);
+ memset(tmpbuf, 0, datasize);
+ *(char **)data = tmpbuf;
+ if (convert_array_from_object(tmpbuf, argtype, obj) < 0)
+ goto error;
}
}
- if (convert_from_object(data, argtype, obj) < 0)
+ else if (convert_from_object(data, argtype, obj) < 0)
goto error;
}
@@ -2151,15 +2147,6 @@ cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds)
/* fall-through */
error:
- for (i=0; i<free_me_until; i++) {
- CTypeDescrObject *argtype;
- argtype = (CTypeDescrObject *)PyTuple_GET_ITEM(signature, 2 + i);
- if (argtype->ct_flags & CT_POINTER) {
- char *data = buffer + cif_descr->exchange_offset_arg[1 + i];
- PyObject *tmpobj_or_null = (PyObject *)(((char **)data)[1]);
- Py_XDECREF(tmpobj_or_null);
- }
- }
if (buffer)
PyObject_Free(buffer);
if (fvarargs != NULL) {
@@ -3667,15 +3654,6 @@ static int fb_build(struct funcbuilder_s *fb, PyObject *fargs,
exchange_offset = ALIGN_ARG(exchange_offset);
cif_descr->exchange_offset_arg[1 + i] = exchange_offset;
exchange_offset += atype->size;
- /* if 'farg' is a pointer type 'ITEM *', then we might receive
- as argument to the function call what is an initializer
- for an array 'ITEM[]'. This includes the case of passing a
- Python string to a 'char *' argument. In this case, we
- convert the initializer to a cdata 'ITEM[]' that gets
- temporarily stored here: */
- if (farg->ct_flags & CT_POINTER) {
- exchange_offset += sizeof(PyObject *);
- }
}
}