summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Objects/object.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/Objects/object.c b/Objects/object.c
index aa73740..f84e64f 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -790,3 +790,67 @@ PyMem_Free(p)
{
free(p);
}
+
+
+/* These methods are used to control infinite recursion in repr, str, print,
+ etc. Container objects that may recursively contain themselves,
+ e.g. builtin dictionaries and lists, should used Py_ReprEnter() and
+ Py_ReprLeave() to avoid infinite recursion.
+
+ Py_ReprEnter() returns 0 the first time it is called for a particular
+ object and 1 every time thereafter. It returns -1 if an exception
+ occurred. Py_ReprLeave() has no return value.
+
+ See dictobject.c and listobject.c for examples of use.
+*/
+
+#define KEY "Py_Repr"
+
+int
+Py_ReprEnter(obj)
+ PyObject *obj;
+{
+ PyObject *dict;
+ PyObject *list;
+ int i;
+
+ dict = PyThreadState_GetDict();
+ if (dict == NULL)
+ return -1;
+ list = PyDict_GetItemString(dict, KEY);
+ if (list == NULL) {
+ list = PyList_New(0);
+ if (list == NULL)
+ return -1;
+ if (PyDict_SetItemString(dict, KEY, list) < 0)
+ return -1;
+ Py_DECREF(list);
+ }
+ i = PyList_GET_SIZE(list);
+ while (--i >= 0) {
+ if (PyList_GET_ITEM(list, i) == obj)
+ return 1;
+ }
+ PyList_Append(list, obj);
+ return 0;
+}
+
+void
+Py_ReprLeave(obj)
+ PyObject *obj;
+{
+ PyObject *dict;
+ PyObject *list;
+ int i;
+
+ dict = PyThreadState_GetDict();
+ list = PyDict_GetItemString(dict, KEY);
+ i = PyList_GET_SIZE(list);
+ /* Count backwards because we always expect obj to be list[-1] */
+ while (--i >= 0) {
+ if (PyList_GET_ITEM(list, i) == obj) {
+ PyList_SetSlice(list, i, i + 1, NULL);
+ break;
+ }
+ }
+}