1/* 2 * registry.m -- Storing and finding exception data. 3 * 4 * This file defines generic functionality to store exception data for 5 * a class/method. 6 */ 7#include "pyobjc.h" 8 9BOOL PyObjC_UpdatingMetaData = NO; 10 11PyObject* 12PyObjC_NewRegistry(void) 13{ 14 return PyDict_New(); 15} 16 17 18int 19PyObjC_AddToRegistry( 20 PyObject* registry, 21 PyObject* class_name, PyObject* selector, 22 PyObject* value) 23{ 24 PyObject* sublist; 25 PyObject* item = Py_BuildValue("(OO)", class_name, value); 26 if (item == NULL) { 27 return -1; 28 } 29 30 sublist = PyDict_GetItem(registry, selector); 31 if (sublist == NULL) { 32 sublist = PyList_New(0); 33 PyDict_SetItem(registry, selector, sublist); 34 Py_DECREF(sublist); 35 } 36 37 if (!PyObjC_UpdatingMetaData) { 38 PyObjC_MappingCount += 1; 39 } 40 int result = PyList_Append(sublist, item); 41 Py_DECREF(item); 42 return result; 43} 44 45PyObject* 46PyObjC_FindInRegistry(PyObject* registry, Class cls, SEL selector) 47{ 48 Py_ssize_t i; 49 Py_ssize_t len; 50 PyObject* cur; 51 Class found_class = nil; 52 PyObject* found_value = NULL; 53 PyObject* sublist; 54 55 if (registry == NULL) { 56 return NULL; 57 } 58 59 PyObject* k = PyBytes_FromString(sel_getName(selector)); 60 sublist = PyDict_GetItem(registry, k); 61 Py_DECREF(k); 62 if (sublist == NULL) return NULL; 63 64 65 len = PyList_Size(sublist); 66 for (i = 0; i < len; i++) { 67 Class cur_class; 68 69 cur = PyList_GET_ITEM(sublist, i); 70 if (cur == NULL) { 71 PyErr_Clear(); 72 continue; 73 } 74 75 if (!PyTuple_CheckExact(cur)) { 76 PyErr_SetString(PyObjCExc_InternalError, 77 "Exception registry element isn't a tuple"); 78 return NULL; 79 } 80 81 PyObject* nm = PyTuple_GET_ITEM(cur, 0); 82 if (PyUnicode_Check(nm)) { 83 PyObject* bytes = PyUnicode_AsEncodedString(nm, NULL, NULL); 84 if (bytes == NULL) { 85 return NULL; 86 } 87 cur_class = objc_lookUpClass(PyBytes_AsString(bytes)); 88 Py_DECREF(bytes); 89#if PY_MAJOR_VERSION == 2 90 } else if (PyString_Check(nm)) { 91 cur_class = objc_lookUpClass(PyString_AsString(nm)); 92#else 93 } else if (PyBytes_Check(nm)) { 94 cur_class = objc_lookUpClass(PyBytes_AsString(nm)); 95 96#endif 97 } else { 98 PyErr_SetString(PyExc_TypeError, "Exception registry class name is not a string"); 99 return NULL; 100 } 101 102 if (cur_class == nil) { 103 continue; 104 } 105 106 if (!class_isSubclassOf(cls, cur_class) && !class_isSubclassOf(cls, object_getClass(cur_class))) { 107 continue; 108 } 109 110 if (found_class != NULL && found_class != cur_class) { 111 if (class_isSubclassOf(found_class, cur_class)) { 112 continue; 113 } 114 } 115 116 found_class = cur_class; 117 Py_INCREF(PyTuple_GET_ITEM(cur, 1)); 118 Py_XDECREF(found_value); 119 found_value = PyTuple_GET_ITEM(cur, 1); 120 } 121 122 return found_value; 123} 124