1#include "pyobjc.h" 2 3typedef struct { 4 PyObject_HEAD 5 IMP imp; 6 PyObjC_CallFunc callfunc; 7 PyObjCMethodSignature* signature; 8 SEL selector; 9 int flags; 10} PyObjCIMPObject; 11 12PyObject* PyObjCIMP_New( 13 IMP imp, 14 SEL selector, 15 PyObjC_CallFunc callfunc, 16 PyObjCMethodSignature* signature, 17 int flags) 18{ 19 PyObjCIMPObject* result; 20 21 result = PyObject_New(PyObjCIMPObject, &PyObjCIMP_Type); 22 if (result == NULL) return NULL; 23 24 result->imp = imp; 25 result->selector = selector; 26 result->callfunc = callfunc; 27 result->signature = signature; 28 if (signature) { 29 Py_INCREF(signature); 30 } 31 result->flags = flags; 32 return (PyObject*)result; 33} 34 35SEL PyObjCIMP_GetSelector(PyObject* self) 36{ 37 if (!PyObjCIMP_Check(self)) { 38 PyErr_BadInternalCall(); 39 return NULL; 40 } 41 42 return ((PyObjCIMPObject*)self)->selector; 43} 44 45IMP PyObjCIMP_GetIMP(PyObject* self) 46{ 47 if (!PyObjCIMP_Check(self)) { 48 PyErr_BadInternalCall(); 49 return NULL; 50 } 51 52 return ((PyObjCIMPObject*)self)->imp; 53} 54 55int PyObjCIMP_GetFlags(PyObject* self) 56{ 57 if (!PyObjCIMP_Check(self)) { 58 PyErr_BadInternalCall(); 59 return -1; 60 } 61 62 return ((PyObjCIMPObject*)self)->flags; 63} 64 65PyObjC_CallFunc PyObjCIMP_GetCallFunc(PyObject* self) 66{ 67 if (!PyObjCIMP_Check(self)) { 68 PyErr_BadInternalCall(); 69 return NULL; 70 } 71 72 return ((PyObjCIMPObject*)self)->callfunc; 73} 74 75PyObjCMethodSignature* PyObjCIMP_GetSignature(PyObject* self) 76{ 77 if (!PyObjCIMP_Check(self)) { 78 PyErr_BadInternalCall(); 79 return NULL; 80 } 81 82 return ((PyObjCIMPObject*)self)->signature; 83} 84 85/* ========================================================================= */ 86 87 88static PyObject* 89imp_call(PyObject* _self, PyObject* args, PyObject* kwds) 90{ 91 PyObjCIMPObject* self = (PyObjCIMPObject*)_self; 92 PyObject* pyself; 93 PyObjC_CallFunc execute = NULL; 94 PyObject* res; 95 PyObject* pyres; 96 Py_ssize_t argslen; 97 PyObject* arglist; 98 Py_ssize_t i; 99 100 if (kwds != NULL && PyObject_Size(kwds) != 0) { 101 PyErr_SetString(PyExc_TypeError, 102 "Objective-C selectors don't support keyword arguments"); 103 return NULL; 104 } 105 106 argslen = PyTuple_Size(args); 107 if (argslen < 1) { 108 PyErr_SetString(PyExc_TypeError, "Missing argument: self"); 109 return NULL; 110 } 111 112 pyself = PyTuple_GET_ITEM(args, 0); 113 if (pyself == NULL) { 114 return NULL; 115 } 116 117 execute = self->callfunc; 118 119 arglist = PyTuple_New(argslen - 1); 120 for (i = 1; i < argslen; i++) { 121 PyObject* v = PyTuple_GET_ITEM(args, i); 122 if (v == NULL) { 123 Py_DECREF(arglist); 124 return NULL; 125 } 126 127 PyTuple_SET_ITEM(arglist, i-1, v); 128 Py_INCREF(v); 129 } 130 131 pyres = res = execute((PyObject*)self, pyself, arglist); 132 Py_DECREF(arglist); 133 134 if (pyres != NULL 135 && PyTuple_Check(pyres) 136 && PyTuple_GET_SIZE(pyres) > 1 137 && PyTuple_GET_ITEM(pyres, 0) == pyself) { 138 pyres = pyself; 139 } 140 141 if (PyObjCObject_Check(pyself) && (((PyObjCObject*)pyself)->flags & PyObjCObject_kUNINITIALIZED)) { 142 if (pyself != pyres && !PyErr_Occurred()) { 143 PyObjCObject_ClearObject(pyself); 144 } 145 } 146 147 if (pyres && PyObjCObject_Check(res)) { 148 if (self->flags & PyObjCSelector_kRETURNS_UNINITIALIZED) { 149 ((PyObjCObject*)pyres)->flags |= PyObjCObject_kUNINITIALIZED; 150 } else if (((PyObjCObject*)pyres)->flags & PyObjCObject_kUNINITIALIZED) { 151 ((PyObjCObject*)pyres)->flags &= 152 ~PyObjCObject_kUNINITIALIZED; 153 if (pyself && pyself != pyres && PyObjCObject_Check(pyself) && !PyErr_Occurred()) { 154 PyObjCObject_ClearObject(pyself); 155 } 156 } 157 } 158 159 return res; 160} 161 162static PyObject* 163imp_repr(PyObject* _self) 164{ 165 PyObjCIMPObject* self = (PyObjCIMPObject*)_self; 166 return PyText_FromFormat("<IMP %s at %p for %p>", 167 sel_getName(self->selector), 168 self, self->imp); 169} 170 171static void 172imp_dealloc(PyObject* _self) 173{ 174 PyObjCIMPObject* self = (PyObjCIMPObject*)_self; 175 Py_XDECREF(self->signature); 176 PyObject_Free(self); 177} 178 179PyDoc_STRVAR(imp_signature_doc, "Objective-C signature for the IMP"); 180static PyObject* 181imp_signature(PyObject* _self, void* closure __attribute__((__unused__))) 182{ 183 PyObjCIMPObject* self = (PyObjCIMPObject*)_self; 184 if (self->signature) { 185 return PyBytes_FromString(self->signature->signature); 186 } else { 187 Py_INCREF(Py_None); 188 return Py_None; 189 } 190} 191 192PyDoc_STRVAR(imp_selector_doc, "Objective-C name for the IMP"); 193static PyObject* 194imp_selector(PyObject* _self, void* closure __attribute__((__unused__))) 195{ 196 PyObjCIMPObject* self = (PyObjCIMPObject*)_self; 197 return PyBytes_FromString(sel_getName(self->selector)); 198} 199 200PyDoc_STRVAR(imp_class_method_doc, 201 "True if this is a class method, False otherwise"); 202static PyObject* 203imp_class_method(PyObject* _self, void* closure __attribute__((__unused__))) 204{ 205 PyObjCIMPObject* self = (PyObjCIMPObject*)_self; 206 return PyBool_FromLong(0 != (self->flags & PyObjCSelector_kCLASS_METHOD)); 207} 208 209PyDoc_STRVAR(imp_is_alloc_doc, 210"True if this is method returns a a freshly allocated object (uninitialized)\n" 211"\n" 212"NOTE: This field is used by the implementation." 213); 214static PyObject* 215imp_is_alloc(PyObject* _self, void* closure __attribute__((__unused__))) 216{ 217 PyObjCIMPObject* self = (PyObjCIMPObject*)_self; 218 return PyBool_FromLong(0 != (self->flags & PyObjCSelector_kRETURNS_UNINITIALIZED)); 219} 220 221 222static PyGetSetDef imp_getset[] = { 223 { 224 "isAlloc", 225 imp_is_alloc, 226 0, 227 imp_is_alloc_doc, 228 0 229 }, 230 { 231 "isClassMethod", 232 imp_class_method, 233 0, 234 imp_class_method_doc, 235 0 236 }, 237 { 238 "signature", 239 imp_signature, 240 0, 241 imp_signature_doc, 242 0 243 }, 244 { 245 "selector", 246 imp_selector, 247 0, 248 imp_selector_doc, 249 0 250 }, 251 { 252 "__name__", 253 imp_selector, 254 0, 255 imp_selector_doc, 256 0 257 }, 258 { 0, 0, 0, 0, 0 } 259}; 260 261static PyObject* 262imp_metadata(PyObject* self) 263{ 264 PyObject* result = PyObjCMethodSignature_AsDict( 265 ((PyObjCIMPObject*)self)->signature); 266 int r; 267 if (((PyObjCIMPObject*)self)->flags & PyObjCSelector_kCLASS_METHOD) { 268 r = PyDict_SetItemString(result, "classmethod", Py_True); 269 } else { 270 r = PyDict_SetItemString(result, "classmethod", Py_False); 271 } 272 if (r == -1) { 273 Py_DECREF(result); 274 return NULL; 275 } 276 277 278 if (((PyObjCIMPObject*)self)->flags & PyObjCSelector_kRETURNS_UNINITIALIZED) { 279 r = PyDict_SetItemString(result, "return_unitialized_object", Py_True); 280 if (r == -1) { 281 Py_DECREF(result); 282 return NULL; 283 } 284 } 285 286 return result; 287} 288 289static PyMethodDef imp_methods[] = { 290 { 291 "__metadata__", 292 (PyCFunction)imp_metadata, 293 METH_NOARGS, 294 "Return metadata for the method", 295 }, 296 { 0, 0, 0, 0} 297}; 298 299 300PyTypeObject PyObjCIMP_Type = { 301 PyVarObject_HEAD_INIT(NULL, 0) 302 "objc.IMP", /* tp_name */ 303 sizeof(PyObjCIMPObject), /* tp_basicsize */ 304 0, /* tp_itemsize */ 305 /* methods */ 306 imp_dealloc, /* tp_dealloc */ 307 0, /* tp_print */ 308 0, /* tp_getattr */ 309 0, /* tp_setattr */ 310 0, /* tp_compare */ 311 imp_repr, /* tp_repr */ 312 0, /* tp_as_number */ 313 0, /* tp_as_sequence */ 314 0, /* tp_as_mapping */ 315 0, /* tp_hash */ 316 imp_call, /* tp_call */ 317 0, /* tp_str */ 318 PyObject_GenericGetAttr, /* tp_getattro */ 319 0, /* tp_setattro */ 320 0, /* tp_as_buffer */ 321 Py_TPFLAGS_DEFAULT, /* tp_flags */ 322 0, /* tp_doc */ 323 0, /* tp_traverse */ 324 0, /* tp_clear */ 325 0, /* tp_richcompare */ 326 0, /* tp_weaklistoffset */ 327 0, /* tp_iter */ 328 0, /* tp_iternext */ 329 imp_methods, /* tp_methods */ 330 0, /* tp_members */ 331 imp_getset, /* tp_getset */ 332 0, /* tp_base */ 333 0, /* tp_dict */ 334 0, /* tp_descr_get */ 335 0, /* tp_descr_set */ 336 0, /* tp_dictoffset */ 337 0, /* tp_init */ 338 0, /* tp_alloc */ 339 0, /* tp_new */ 340 0, /* tp_free */ 341 0, /* tp_is_gc */ 342 0, /* tp_bases */ 343 0, /* tp_mro */ 344 0, /* tp_cache */ 345 0, /* tp_subclasses */ 346 0, /* tp_weaklist */ 347 0 /* tp_del */ 348#if PY_VERSION_HEX >= 0x02060000 349 , 0 /* tp_version_tag */ 350#endif 351 352}; 353 354 355/* ========================================================================= */ 356 357static PyObject* 358call_instanceMethodForSelector_(PyObject* method, PyObject* self, PyObject* args) 359{ 360 PyObject* sel; 361 SEL selector; 362 IMP retval; 363 PyObject* attr; 364 PyObject* res; 365 366 if (!PyArg_ParseTuple(args, "O", &sel)) { 367 return NULL; 368 } 369 370 if (depythonify_c_value(@encode(SEL), sel, &selector) == -1) { 371 return NULL; 372 } 373 374 if (!PyObjCClass_Check(self)) { 375 PyErr_Format(PyExc_TypeError, 376 "Expecting instance of 'objc.objc_class' as 'self', " 377 "got '%s'", Py_TYPE(self)->tp_name); 378 return NULL; 379 } 380 381 PyObjC_DURING 382 retval = (IMP)objc_msgSend(PyObjCClass_GetClass(self), 383 PyObjCSelector_GetSelector(method), 384 selector); 385 PyObjC_HANDLER 386 PyObjCErr_FromObjC(localException); 387 retval = NULL; 388 389 PyObjC_ENDHANDLER 390 391 if (retval == NULL) { 392 if (PyErr_Occurred()) { 393 return NULL; 394 } 395 Py_INCREF(Py_None); 396 return Py_None; 397 } 398 399 attr = PyObjCClass_FindSelector(self, selector, NO); 400 if (attr == NULL) { 401 return NULL; 402 } 403 404 /* 405 * XXX: what if the method is implemented in Python. We should be able to deal with that!!! 406 */ 407 408 if (!PyObjCNativeSelector_Check(attr)) { 409 PyErr_Format(PyExc_TypeError, "Cannot locate Python representation of %s", 410 sel_getName(selector)); 411 return NULL; 412 } 413 414 if (((PyObjCNativeSelector*)attr)->sel_call_func == NULL) { 415 ((PyObjCNativeSelector*)attr)->sel_call_func = PyObjC_FindCallFunc(((PyObjCNativeSelector*)attr)->sel_class, ((PyObjCNativeSelector*)attr)->sel_selector); 416 if (((PyObjCNativeSelector*)attr)->sel_call_func == NULL) { 417 return NULL; 418 } 419 } 420 421 res = PyObjCIMP_New( 422 retval, 423 selector, 424 ((PyObjCNativeSelector*)attr)->sel_call_func, 425 PyObjCSelector_GetMetadata(attr), 426 PyObjCSelector_GetFlags(attr) 427 ); 428 Py_DECREF(attr); 429 return res; 430} 431 432static PyObject* 433call_methodForSelector_(PyObject* method, PyObject* self, PyObject* args) 434{ 435 PyObject* sel; 436 SEL selector; 437 struct objc_super super; 438 IMP retval; 439 PyObject* attr; 440 PyObject* res; 441 442 if (!PyArg_ParseTuple(args, "O", &sel)) { 443 return NULL; 444 } 445 446 if (depythonify_c_value(@encode(SEL), sel, &selector) == -1) { 447 return NULL; 448 } 449 450 if (PyObjCClass_Check(self)) { 451 objc_superSetReceiver(super, PyObjCClass_GetClass(self)); 452 } else { 453 objc_superSetReceiver(super, PyObjCObject_GetObject(self)); 454 } 455 objc_superSetClass(super, object_getClass(objc_superGetReceiver(super))); 456 457 PyObjC_DURING 458 retval = (IMP)objc_msgSendSuper(&super, 459 PyObjCSelector_GetSelector(method), 460 selector); 461 PyObjC_HANDLER 462 PyObjCErr_FromObjC(localException); 463 retval = NULL; 464 PyObjC_ENDHANDLER 465 466 if (retval == NULL) { 467 if (PyErr_Occurred()) { 468 return NULL; 469 } 470 Py_INCREF(Py_None); 471 return Py_None; 472 } 473 474 if (PyObjCClass_Check(self)) { 475 attr = PyObjCClass_FindSelector(self, selector, YES); 476 } else { 477 attr = PyObjCObject_FindSelector(self, selector); 478 } 479 if (attr == NULL) { 480 return NULL; 481 } 482 483 /* FIXME: We should be able to deal with Python methods as well */ 484 485 if (!PyObjCNativeSelector_Check(attr)) { 486 PyErr_Format(PyExc_TypeError, "Cannot locate Python representation of %s", 487 sel_getName(selector)); 488 return NULL; 489 } 490 491 492 /* FIXME: there should be a function for retrieving the call function */ 493 if (((PyObjCNativeSelector*)attr)->sel_call_func == NULL) { 494 ((PyObjCNativeSelector*)attr)->sel_call_func = PyObjC_FindCallFunc(((PyObjCNativeSelector*)attr)->sel_class, ((PyObjCNativeSelector*)attr)->sel_selector); 495 if (((PyObjCNativeSelector*)attr)->sel_call_func == NULL) { 496 return NULL; 497 } 498 } 499 500 501 res = PyObjCIMP_New( 502 retval, 503 selector, 504 ((PyObjCNativeSelector*)attr)->sel_call_func, 505 PyObjCSelector_GetMetadata(attr), 506 PyObjCSelector_GetFlags(attr) 507 ); 508 Py_DECREF(attr); 509 return res; 510} 511 512int PyObjCIMP_SetUpMethodWrappers(void) 513{ 514 int r; 515 516 r = PyObjC_RegisterMethodMapping( 517 nil, 518 @selector(instanceMethodForSelector:), 519 call_instanceMethodForSelector_, 520 PyObjCUnsupportedMethod_IMP); 521 if (r == -1) return -1; 522 523 r = PyObjC_RegisterMethodMapping( 524 nil, 525 @selector(methodForSelector:), 526 call_methodForSelector_, 527 PyObjCUnsupportedMethod_IMP); 528 if (r == -1) return -1; 529 530 return 0; 531} 532