1/* 2 * Wrapper for simple global functions. Simple functions are those without 3 * arguments that require additional effort. 4 */ 5#include "pyobjc.h" 6 7/* XXX: move this to a header file */ 8static inline Py_ssize_t align(Py_ssize_t offset, Py_ssize_t alignment) 9{ 10 Py_ssize_t rest = offset % alignment; 11 if (rest == 0) return offset; 12 return offset + (alignment - rest); 13} 14 15 16typedef struct { 17 PyObject_HEAD 18 ffi_cif* cif; 19 PyObjCMethodSignature* methinfo; 20 void* function; 21 PyObject* doc; 22 PyObject* name; 23 PyObject* module; 24} func_object; 25 26 27 28PyDoc_STRVAR(func_metadata_doc, "Return a dict that describes the metadata for this function."); 29static PyObject* func_metadata(PyObject* self) 30{ 31 return PyObjCMethodSignature_AsDict(((func_object*)self)->methinfo); 32} 33 34static PyMethodDef func_methods[] = { 35 { 36 "__metadata__", 37 (PyCFunction)func_metadata, 38 METH_NOARGS, 39 func_metadata_doc 40 }, 41 { 0, 0, 0, 0 } 42}; 43 44 45 46static PyMemberDef func_members[] = { 47 { 48 "__doc__", 49 T_OBJECT, 50 offsetof(func_object, doc), 51 READONLY, 52 NULL 53 }, 54 { 55 "__name__", 56 T_OBJECT, 57 offsetof(func_object, name), 58 READONLY, 59 NULL 60 }, 61 { 62 "__module__", 63 T_OBJECT, 64 offsetof(func_object, module), 65 0, 66 NULL 67 }, 68 { 69 NULL, 70 0, 71 0, 72 0, 73 NULL 74 } 75}; 76 77static PyObject* func_repr(PyObject* _self) 78{ 79 func_object* self = (func_object*)_self; 80 81 if (self->name == NULL) { 82 return PyText_FromFormat("<objc.function object at %p>", self); 83#if PY_MAJOR_VERSION == 2 84 } else if (PyString_Check(self->name)) { 85 return PyString_FromFormat("<objc.function '%s' at %p>", PyString_AsString(self->name), self); 86#else 87 } else if (PyUnicode_Check(self->name)) { 88 return PyUnicode_FromFormat("<objc.function %R at %p>", self->name, self); 89#endif 90 } else { 91#if PY_MAJOR_VERSION == 2 92 PyObject* result; 93 PyObject* name_repr = PyObject_Repr(self->name); 94 if (name_repr == NULL) { 95 return NULL; 96 } 97 if (!PyString_Check(name_repr)) { 98 result = PyString_FromFormat("<objc.function object at %p>", self); 99 } else { 100 result = PyString_FromFormat("<objc.function '%s' at %p>", 101 PyString_AsString(name_repr), self); 102 } 103 Py_DECREF(name_repr); 104 return result; 105#else 106 return PyUnicode_FromFormat("<objc.function %R at %p>", self->name, self); 107#endif 108 } 109} 110 111 112static PyObject* 113func_call(PyObject* s, PyObject* args, PyObject* kwds) 114{ 115 func_object* self = (func_object*)s; 116 Py_ssize_t byref_in_count; 117 Py_ssize_t byref_out_count; 118 Py_ssize_t plain_count; 119 Py_ssize_t argbuf_len; 120 int r; 121 int cif_arg_count; 122 BOOL variadicAllArgs = NO; 123 124 unsigned char* argbuf = NULL; 125 ffi_type* arglist[64]; 126 void* values[64]; 127 void** byref = NULL; 128 struct byref_attr* byref_attr = NULL; 129 ffi_cif cif; 130 ffi_cif* volatile cifptr; 131 132 PyObject* retval; 133 134 if (self->methinfo->suggestion != NULL) { 135 PyErr_SetObject(PyExc_TypeError, self->methinfo->suggestion); 136 return NULL; 137 } 138 139 140 if (Py_SIZE(self->methinfo) >= 63) { 141 PyErr_Format(PyObjCExc_Error, 142 "wrapping a function with %"PY_FORMAT_SIZE_T"d arguments, at most 64 " 143 "are supported", Py_SIZE(self->methinfo)); 144 return NULL; 145 } 146 147 if (kwds != NULL && (!PyDict_Check(kwds) || PyDict_Size(kwds) != 0)) { 148 PyErr_SetString(PyExc_TypeError, 149 "keyword arguments not supported"); 150 return NULL; 151 } 152 153 argbuf_len = PyObjCRT_SizeOfReturnType(self->methinfo->rettype.type); 154 argbuf_len = align(argbuf_len, sizeof(void*)); 155 r = PyObjCFFI_CountArguments( 156 self->methinfo, 0, 157 &byref_in_count, &byref_out_count, &plain_count, 158 &argbuf_len, &variadicAllArgs); 159 if (r == -1) { 160 return NULL; 161 } 162 163 variadicAllArgs |= self->methinfo->variadic && (self->methinfo->null_terminated_array || self->methinfo->arrayArg != -1); 164 165 if (variadicAllArgs) { 166 if (byref_in_count != 0 || byref_out_count != 0) { 167 PyErr_Format(PyExc_TypeError, "Sorry, printf format with by-ref args not supported"); 168 return NULL; 169 } 170 if (PyTuple_Size(args) < Py_SIZE(self->methinfo)) { 171 PyErr_Format(PyExc_TypeError, "Need %"PY_FORMAT_SIZE_T"d arguments, got %"PY_FORMAT_SIZE_T"d", 172 Py_SIZE(self->methinfo) - 2, PyTuple_Size(args)); 173 return NULL; 174 } 175 } else if (PyTuple_Size(args) != Py_SIZE(self->methinfo)) { 176 PyErr_Format(PyExc_TypeError, "Need %"PY_FORMAT_SIZE_T"d arguments, got %"PY_FORMAT_SIZE_T"d", 177 Py_SIZE(self->methinfo), PyTuple_Size(args)); 178 return NULL; 179 } 180 181 182 argbuf = PyMem_Malloc(argbuf_len); 183 if (argbuf == NULL) { 184 PyErr_NoMemory(); 185 return NULL; 186 } 187 188 if (variadicAllArgs) { 189 if (PyObjCFFI_AllocByRef(Py_SIZE(self->methinfo)+PyTuple_Size(args), &byref, &byref_attr) < 0) { 190 goto error; 191 } 192 } else { 193 if (PyObjCFFI_AllocByRef(Py_SIZE(self->methinfo), &byref, &byref_attr) < 0) { 194 goto error; 195 } 196 } 197 198 cif_arg_count = PyObjCFFI_ParseArguments( 199 self->methinfo, 0, args, 200 align(PyObjCRT_SizeOfReturnType(self->methinfo->rettype.type), sizeof(void*)), 201 argbuf, argbuf_len, byref, byref_attr, arglist, values); 202 if (cif_arg_count == -1) { 203 goto error; 204 } 205 206 if (variadicAllArgs) { 207 r = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, cif_arg_count, 208 signature_to_ffi_return_type(self->methinfo->rettype.type), arglist); 209 if (r != FFI_OK) { 210 PyErr_Format(PyExc_RuntimeError, 211 "Cannot setup FFI CIF [%d]", r); 212 goto error; 213 } 214 cifptr = &cif; 215 216 } else { 217 cifptr = self->cif; 218 } 219 220 PyObjC_DURING 221 ffi_call(cifptr, FFI_FN(self->function), argbuf, values); 222 PyObjC_HANDLER 223 PyObjCErr_FromObjC(localException); 224 PyObjC_ENDHANDLER 225 226 if (PyErr_Occurred()) { 227 goto error; 228 } 229 230 retval = PyObjCFFI_BuildResult(self->methinfo, 0, argbuf, byref, 231 byref_attr, byref_out_count, NULL, 0, values); 232 233 if (variadicAllArgs) { 234 if (PyObjCFFI_FreeByRef(Py_SIZE(self->methinfo)+PyTuple_Size(args), byref, byref_attr) < 0) { 235 byref = NULL; byref_attr = NULL; 236 goto error; 237 } 238 } else { 239 if (PyObjCFFI_FreeByRef(Py_SIZE(self->methinfo), byref, byref_attr) < 0) { 240 byref = NULL; byref_attr = NULL; 241 goto error; 242 } 243 } 244 PyMem_Free(argbuf); argbuf = NULL; 245 return retval; 246 247error: 248 if (variadicAllArgs) { 249 if (PyObjCFFI_FreeByRef(PyTuple_Size(args), byref, byref_attr) < 0) { 250 byref = NULL; byref_attr = NULL; 251 goto error; 252 } 253 } else { 254 if (PyObjCFFI_FreeByRef(Py_SIZE(self->methinfo), byref, byref_attr) < 0) { 255 byref = NULL; byref_attr = NULL; 256 goto error; 257 } 258 } 259 if (argbuf) { 260 PyMem_Free(argbuf); 261 } 262 return NULL; 263} 264 265static void 266func_dealloc(PyObject* s) 267{ 268 func_object* self = (func_object*)s; 269 270 Py_XDECREF(self->doc); self->doc = NULL; 271 Py_XDECREF(self->name); self->name = NULL; 272 Py_XDECREF(self->module); self->module = NULL; 273 if (self->cif != NULL) { 274 PyObjCFFI_FreeCIF(self->cif); 275 } 276 Py_XDECREF(self->methinfo); 277 PyObject_Free(s); 278} 279 280PyTypeObject PyObjCFunc_Type = 281{ 282 PyVarObject_HEAD_INIT(&PyType_Type, 0) 283 "objc.function", /* tp_name */ 284 sizeof (func_object), /* tp_basicsize */ 285 0, /* tp_itemsize */ 286 287 /* methods */ 288 func_dealloc, /* tp_dealloc */ 289 0, /* tp_print */ 290 0, /* tp_getattr */ 291 0, /* tp_setattr */ 292 0, /* tp_compare */ 293 func_repr, /* tp_repr */ 294 0, /* tp_as_number */ 295 0, /* tp_as_sequence */ 296 0, /* tp_as_mapping */ 297 0, /* tp_hash */ 298 func_call, /* tp_call */ 299 0, /* tp_str */ 300 PyObject_GenericGetAttr, /* tp_getattro */ 301 0, /* tp_setattro */ 302 0, /* tp_as_buffer */ 303 Py_TPFLAGS_DEFAULT, /* tp_flags */ 304 "Wrapper around a Objective-C function",/* tp_doc */ 305 0, /* tp_traverse */ 306 0, /* tp_clear */ 307 0, /* tp_richcompare */ 308 0, /* tp_weaklistoffset */ 309 0, /* tp_iter */ 310 0, /* tp_iternext */ 311 func_methods, /* tp_methods */ 312 func_members, /* tp_members */ 313 0, /* tp_getset */ 314 0, /* tp_base */ 315 0, /* tp_dict */ 316 0, /* tp_descr_get */ 317 0, /* tp_descr_set */ 318 0, /* tp_dictoffset */ 319 0, /* tp_init */ 320 0, /* tp_alloc */ 321 0, /* tp_new */ 322 0, /* tp_free */ 323 0, /* tp_is_gc */ 324 0, /* tp_bases */ 325 0, /* tp_mro */ 326 0, /* tp_cache */ 327 0, /* tp_subclasses */ 328 0, /* tp_weaklist */ 329 0 /* tp_del */ 330#if PY_VERSION_HEX >= 0x02060000 331 , 0 /* tp_version_tag */ 332#endif 333 334}; 335 336PyObject* 337PyObjCFunc_WithMethodSignature(PyObject* name, void* func, PyObjCMethodSignature* methinfo) 338{ 339 func_object* result; 340 341 result = PyObject_NEW(func_object, &PyObjCFunc_Type); 342 if (result == NULL) return NULL; 343 344 result->function = func; 345 result->doc = NULL; 346 result->name = name; 347 Py_XINCREF(name); 348 result->module = NULL; 349 result->methinfo = methinfo; 350 Py_XINCREF(methinfo); 351 352 result->cif = PyObjCFFI_CIFForSignature(result->methinfo); 353 if (result->cif == NULL) { 354 Py_DECREF(result); 355 return NULL; 356 } 357 358 return (PyObject*)result; 359} 360 361 362PyObject* 363PyObjCFunc_New(PyObject* name, void* func, const char* signature, PyObject* doc, PyObject* meta) 364{ 365 func_object* result; 366 367 368 result = PyObject_NEW(func_object, &PyObjCFunc_Type); 369 if (result == NULL) return NULL; 370 371 result->function = NULL; 372 result->doc = NULL; 373 result->name = NULL; 374 result->module = NULL; 375 result->cif = NULL; 376 377 result->methinfo= PyObjCMethodSignature_WithMetaData(signature, meta, NO); 378 if (result->methinfo == NULL) { 379 Py_DECREF(result); 380 return NULL; 381 } 382 383 result->function = func; 384 385 result->doc = doc; 386 Py_XINCREF(doc); 387 388 result->name = name; 389 Py_XINCREF(name); 390 result->cif = PyObjCFFI_CIFForSignature(result->methinfo); 391 if (result->cif == NULL) { 392 Py_DECREF(result); 393 return NULL; 394 } 395 396 return (PyObject*)result; 397} 398 399PyObjCMethodSignature* PyObjCFunc_GetMethodSignature(PyObject* func) 400{ 401 return ((func_object*)func)->methinfo; 402} 403