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