Add implementations of Py_Repr{Enter,Leave}.

(Jeremy will hardly recognize his patch :-)
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 @@
 {
 	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;
+		}
+	}
+}