mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +00:00 
			
		
		
		
	
		
			
	
	
		
			855 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			855 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /* Descriptors -- a new, flexible way to describe attributes */ | ||
|  | 
 | ||
|  | #include "Python.h"
 | ||
|  | #include "structmember.h" /* Why is this not included in Python.h? */
 | ||
|  | 
 | ||
|  | /* Various kinds of descriptor objects */ | ||
|  | 
 | ||
|  | #define COMMON \
 | ||
|  | 	PyObject_HEAD \ | ||
|  | 	PyTypeObject *d_type; \ | ||
|  | 	PyObject *d_name | ||
|  | 
 | ||
|  | typedef struct { | ||
|  | 	COMMON; | ||
|  | } PyDescrObject; | ||
|  | 
 | ||
|  | typedef struct { | ||
|  | 	COMMON; | ||
|  | 	PyMethodDef *d_method; | ||
|  | } PyMethodDescrObject; | ||
|  | 
 | ||
|  | typedef struct { | ||
|  | 	COMMON; | ||
|  | 	struct memberlist *d_member; | ||
|  | } PyMemberDescrObject; | ||
|  | 
 | ||
|  | typedef struct { | ||
|  | 	COMMON; | ||
|  | 	struct getsetlist *d_getset; | ||
|  | } PyGetSetDescrObject; | ||
|  | 
 | ||
|  | typedef struct { | ||
|  | 	COMMON; | ||
|  | 	struct wrapperbase *d_base; | ||
|  | 	void *d_wrapped; /* This can be any function pointer */ | ||
|  | } PyWrapperDescrObject; | ||
|  | 
 | ||
|  | static void | ||
|  | descr_dealloc(PyDescrObject *descr) | ||
|  | { | ||
|  | 	Py_XDECREF(descr->d_type); | ||
|  | 	Py_XDECREF(descr->d_name); | ||
|  | 	PyObject_DEL(descr); | ||
|  | } | ||
|  | 
 | ||
|  | static char * | ||
|  | descr_name(PyDescrObject *descr) | ||
|  | { | ||
|  | 	if (descr->d_name != NULL && PyString_Check(descr->d_name)) | ||
|  | 		return PyString_AS_STRING(descr->d_name); | ||
|  | 	else | ||
|  | 		return "?"; | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | descr_repr(PyDescrObject *descr, char *format) | ||
|  | { | ||
|  | 	char buffer[500]; | ||
|  | 
 | ||
|  | 	sprintf(buffer, format, descr_name(descr), descr->d_type->tp_name); | ||
|  | 	return PyString_FromString(buffer); | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | method_repr(PyMethodDescrObject *descr) | ||
|  | { | ||
|  | 	return descr_repr((PyDescrObject *)descr,  | ||
|  | 			  "<method '%.300s' of '%.100s' objects>"); | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | member_repr(PyMemberDescrObject *descr) | ||
|  | { | ||
|  | 	return descr_repr((PyDescrObject *)descr,  | ||
|  | 			  "<member '%.300s' of '%.100s' objects>"); | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | getset_repr(PyGetSetDescrObject *descr) | ||
|  | { | ||
|  | 	return descr_repr((PyDescrObject *)descr,  | ||
|  | 			  "<attribute '%.300s' of '%.100s' objects>"); | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | wrapper_repr(PyWrapperDescrObject *descr) | ||
|  | { | ||
|  | 	return descr_repr((PyDescrObject *)descr,  | ||
|  | 			  "<slot wrapper '%.300s' of '%.100s' objects>"); | ||
|  | } | ||
|  | 
 | ||
|  | static int | ||
|  | descr_check(PyDescrObject *descr, PyObject *obj, PyTypeObject *type, | ||
|  | 	  PyObject **pres) | ||
|  | { | ||
|  | 	if (obj == NULL || obj == Py_None) { | ||
|  | 		Py_INCREF(descr); | ||
|  | 		*pres = (PyObject *)descr; | ||
|  | 		return 1; | ||
|  | 	} | ||
|  | 	if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) { | ||
|  | 		PyErr_Format(PyExc_TypeError, | ||
|  | 			     "descriptor '%.200s' for '%.100s' objects " | ||
|  | 			     "doesn't apply to '%.100s' object", | ||
|  | 			     descr_name((PyDescrObject *)descr), | ||
|  | 			     descr->d_type->tp_name, | ||
|  | 			     obj->ob_type->tp_name); | ||
|  | 		*pres = NULL; | ||
|  | 		return 1; | ||
|  | 	} | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | method_get(PyMethodDescrObject *descr, PyObject *obj, PyTypeObject *type) | ||
|  | { | ||
|  | 	PyObject *res; | ||
|  | 
 | ||
|  | 	if (descr_check((PyDescrObject *)descr, obj, type, &res)) | ||
|  | 		return res; | ||
|  | 	return PyCFunction_New(descr->d_method, obj); | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | member_get(PyMemberDescrObject *descr, PyObject *obj, PyTypeObject *type) | ||
|  | { | ||
|  | 	PyObject *res; | ||
|  | 
 | ||
|  | 	if (descr_check((PyDescrObject *)descr, obj, type, &res)) | ||
|  | 		return res; | ||
|  | 	return PyMember_Get((char *)obj, descr->d_member, | ||
|  | 			    descr->d_member->name); | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyTypeObject *type) | ||
|  | { | ||
|  | 	PyObject *res; | ||
|  | 
 | ||
|  | 	if (descr_check((PyDescrObject *)descr, obj, type, &res)) | ||
|  | 		return res; | ||
|  | 	if (descr->d_getset->get != NULL) | ||
|  | 		return descr->d_getset->get(obj, descr->d_getset->closure); | ||
|  | 	PyErr_Format(PyExc_TypeError, | ||
|  | 		     "attribute '%300s' of '%.100s' objects is not readable", | ||
|  | 		     descr_name((PyDescrObject *)descr), | ||
|  | 		     descr->d_type->tp_name); | ||
|  | 	return NULL; | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | wrapper_get(PyWrapperDescrObject *descr, PyObject *obj, PyTypeObject *type) | ||
|  | { | ||
|  | 	PyObject *res; | ||
|  | 
 | ||
|  | 	if (descr_check((PyDescrObject *)descr, obj, type, &res)) | ||
|  | 		return res; | ||
|  | 	return PyWrapper_New((PyObject *)descr, obj); | ||
|  | } | ||
|  | 
 | ||
|  | static int | ||
|  | descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value, | ||
|  | 	       int *pres) | ||
|  | { | ||
|  | 	assert(obj != NULL); | ||
|  | 	if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) { | ||
|  | 		PyErr_Format(PyExc_TypeError, | ||
|  | 			     "descriptor '%.200s' for '%.100s' objects " | ||
|  | 			     "doesn't apply to '%.100s' object", | ||
|  | 			     descr_name(descr), | ||
|  | 			     descr->d_type->tp_name, | ||
|  | 			     obj->ob_type->tp_name); | ||
|  | 		*pres = -1; | ||
|  | 		return 1; | ||
|  | 	} | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static int | ||
|  | member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value) | ||
|  | { | ||
|  | 	int res; | ||
|  | 
 | ||
|  | 	if (descr_setcheck((PyDescrObject *)descr, obj, value, &res)) | ||
|  | 		return res; | ||
|  | 	return PyMember_Set((char *)obj, descr->d_member, | ||
|  | 			    descr->d_member->name, value); | ||
|  | } | ||
|  | 
 | ||
|  | static int | ||
|  | getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value) | ||
|  | { | ||
|  | 	int res; | ||
|  | 
 | ||
|  | 	if (descr_setcheck((PyDescrObject *)descr, obj, value, &res)) | ||
|  | 		return res; | ||
|  | 	if (descr->d_getset->set != NULL) | ||
|  | 		return descr->d_getset->set(obj, value, | ||
|  | 					    descr->d_getset->closure); | ||
|  | 	PyErr_Format(PyExc_TypeError, | ||
|  | 		     "attribute '%300s' of '%.100s' objects is not writable", | ||
|  | 		     descr_name((PyDescrObject *)descr), | ||
|  | 		     descr->d_type->tp_name); | ||
|  | 	return -1; | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds) | ||
|  | { | ||
|  | 	int argc; | ||
|  | 	PyObject *self, *func, *result; | ||
|  | 
 | ||
|  | 	/* Make sure that the first argument is acceptable as 'self' */ | ||
|  | 	assert(PyTuple_Check(args)); | ||
|  | 	argc = PyTuple_GET_SIZE(args); | ||
|  | 	if (argc < 1) { | ||
|  | 		PyErr_Format(PyExc_TypeError, | ||
|  | 			     "descriptor '%.300s' of '%.100s' " | ||
|  | 			     "object needs an argument", | ||
|  | 			     descr_name((PyDescrObject *)descr), | ||
|  | 			     descr->d_type->tp_name); | ||
|  | 		return NULL; | ||
|  | 	} | ||
|  | 	self = PyTuple_GET_ITEM(args, 0); | ||
|  | 	if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) { | ||
|  | 		PyErr_Format(PyExc_TypeError, | ||
|  | 			     "descriptor '%.200s' " | ||
|  | 			     "requires a '%.100s' object " | ||
|  | 			     "but received a '%.100s'", | ||
|  | 			     descr_name((PyDescrObject *)descr), | ||
|  | 			     descr->d_type->tp_name, | ||
|  | 			     self->ob_type->tp_name); | ||
|  | 		return NULL; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	func = PyCFunction_New(descr->d_method, self); | ||
|  | 	if (func == NULL) | ||
|  | 		return NULL; | ||
|  | 	args = PyTuple_GetSlice(args, 1, argc); | ||
|  | 	if (args == NULL) { | ||
|  | 		Py_DECREF(func); | ||
|  | 		return NULL; | ||
|  | 	} | ||
|  | 	result = PyEval_CallObjectWithKeywords(func, args, kwds); | ||
|  | 	Py_DECREF(args); | ||
|  | 	Py_DECREF(func); | ||
|  | 	return result; | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds) | ||
|  | { | ||
|  | 	int argc; | ||
|  | 	PyObject *self, *func, *result; | ||
|  | 
 | ||
|  | 	/* Make sure that the first argument is acceptable as 'self' */ | ||
|  | 	assert(PyTuple_Check(args)); | ||
|  | 	argc = PyTuple_GET_SIZE(args); | ||
|  | 	if (argc < 1) { | ||
|  | 		PyErr_Format(PyExc_TypeError, | ||
|  | 			     "descriptor '%.300s' of '%.100s' " | ||
|  | 			     "object needs an argument", | ||
|  | 			     descr_name((PyDescrObject *)descr), | ||
|  | 			     descr->d_type->tp_name); | ||
|  | 		return NULL; | ||
|  | 	} | ||
|  | 	self = PyTuple_GET_ITEM(args, 0); | ||
|  | 	if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) { | ||
|  | 		PyErr_Format(PyExc_TypeError, | ||
|  | 			     "descriptor '%.200s' " | ||
|  | 			     "requires a '%.100s' object " | ||
|  | 			     "but received a '%.100s'", | ||
|  | 			     descr_name((PyDescrObject *)descr), | ||
|  | 			     descr->d_type->tp_name, | ||
|  | 			     self->ob_type->tp_name); | ||
|  | 		return NULL; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	func = PyWrapper_New((PyObject *)descr, self); | ||
|  | 	if (func == NULL) | ||
|  | 		return NULL; | ||
|  | 	args = PyTuple_GetSlice(args, 1, argc); | ||
|  | 	if (args == NULL) { | ||
|  | 		Py_DECREF(func); | ||
|  | 		return NULL; | ||
|  | 	} | ||
|  | 	result = PyEval_CallObjectWithKeywords(func, args, kwds); | ||
|  | 	Py_DECREF(args); | ||
|  | 	Py_DECREF(func); | ||
|  | 	return result; | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | member_get_doc(PyMethodDescrObject *descr, void *closure) | ||
|  | { | ||
|  | 	if (descr->d_method->ml_doc == NULL) { | ||
|  | 		Py_INCREF(Py_None); | ||
|  | 		return Py_None; | ||
|  | 	} | ||
|  | 	return PyString_FromString(descr->d_method->ml_doc); | ||
|  | } | ||
|  | 
 | ||
|  | static struct memberlist descr_members[] = { | ||
|  | 	{"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY}, | ||
|  | 	{"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY}, | ||
|  | 	{0} | ||
|  | }; | ||
|  | 
 | ||
|  | static struct getsetlist member_getset[] = { | ||
|  | 	{"__doc__", (getter)member_get_doc}, | ||
|  | 	{0} | ||
|  | }; | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | wrapper_get_doc(PyWrapperDescrObject *descr, void *closure) | ||
|  | { | ||
|  | 	if (descr->d_base->doc == NULL) { | ||
|  | 		Py_INCREF(Py_None); | ||
|  | 		return Py_None; | ||
|  | 	} | ||
|  | 	return PyString_FromString(descr->d_base->doc); | ||
|  | } | ||
|  | 
 | ||
|  | static struct getsetlist wrapper_getset[] = { | ||
|  | 	{"__doc__", (getter)wrapper_get_doc}, | ||
|  | 	{0} | ||
|  | }; | ||
|  | 
 | ||
|  | static PyTypeObject PyMethodDescr_Type = { | ||
|  | 	PyObject_HEAD_INIT(&PyType_Type) | ||
|  | 	0, | ||
|  | 	"method_descriptor", | ||
|  | 	sizeof(PyMethodDescrObject), | ||
|  | 	0, | ||
|  | 	(destructor)descr_dealloc,		/* tp_dealloc */ | ||
|  | 	0,					/* tp_print */ | ||
|  | 	0,					/* tp_getattr */ | ||
|  | 	0,					/* tp_setattr */ | ||
|  | 	0,					/* tp_compare */ | ||
|  | 	(reprfunc)method_repr,			/* tp_repr */ | ||
|  | 	0,					/* tp_as_number */ | ||
|  | 	0,					/* tp_as_sequence */ | ||
|  | 	0,					/* tp_as_mapping */ | ||
|  | 	0,					/* tp_hash */ | ||
|  | 	(ternaryfunc)methoddescr_call,		/* tp_call */ | ||
|  | 	0,					/* tp_str */ | ||
|  | 	PyObject_GenericGetAttr,		/* tp_getattro */ | ||
|  | 	0,					/* tp_setattro */ | ||
|  | 	0,					/* tp_as_buffer */ | ||
|  | 	Py_TPFLAGS_DEFAULT,			/* tp_flags */ | ||
|  | 	0,					/* tp_doc */ | ||
|  | 	0,					/* tp_traverse */ | ||
|  | 	0,					/* tp_clear */ | ||
|  | 	0,					/* tp_richcompare */ | ||
|  | 	0,					/* tp_weaklistoffset */ | ||
|  | 	0,					/* tp_iter */ | ||
|  | 	0,					/* tp_iternext */ | ||
|  | 	0,					/* tp_methods */ | ||
|  | 	descr_members,				/* tp_members */ | ||
|  | 	member_getset,				/* tp_getset */ | ||
|  | 	0,					/* tp_base */ | ||
|  | 	0,					/* tp_dict */ | ||
|  | 	(descrgetfunc)method_get,		/* tp_descr_get */ | ||
|  | 	0,					/* tp_descr_set */ | ||
|  | }; | ||
|  | 
 | ||
|  | static PyTypeObject PyMemberDescr_Type = { | ||
|  | 	PyObject_HEAD_INIT(&PyType_Type) | ||
|  | 	0, | ||
|  | 	"member_descriptor", | ||
|  | 	sizeof(PyMemberDescrObject), | ||
|  | 	0, | ||
|  | 	(destructor)descr_dealloc,		/* tp_dealloc */ | ||
|  | 	0,					/* tp_print */ | ||
|  | 	0,					/* tp_getattr */ | ||
|  | 	0,					/* tp_setattr */ | ||
|  | 	0,					/* tp_compare */ | ||
|  | 	(reprfunc)member_repr,			/* tp_repr */ | ||
|  | 	0,					/* tp_as_number */ | ||
|  | 	0,					/* tp_as_sequence */ | ||
|  | 	0,					/* tp_as_mapping */ | ||
|  | 	0,					/* tp_hash */ | ||
|  | 	(ternaryfunc)0,				/* tp_call */ | ||
|  | 	0,					/* tp_str */ | ||
|  | 	PyObject_GenericGetAttr,		/* tp_getattro */ | ||
|  | 	0,					/* tp_setattro */ | ||
|  | 	0,					/* tp_as_buffer */ | ||
|  | 	Py_TPFLAGS_DEFAULT,			/* tp_flags */ | ||
|  | 	0,					/* tp_doc */ | ||
|  | 	0,					/* tp_traverse */ | ||
|  | 	0,					/* tp_clear */ | ||
|  | 	0,					/* tp_richcompare */ | ||
|  | 	0,					/* tp_weaklistoffset */ | ||
|  | 	0,					/* tp_iter */ | ||
|  | 	0,					/* tp_iternext */ | ||
|  | 	0,					/* tp_methods */ | ||
|  | 	descr_members,				/* tp_members */ | ||
|  | 	0,					/* tp_getset */ | ||
|  | 	0,					/* tp_base */ | ||
|  | 	0,					/* tp_dict */ | ||
|  | 	(descrgetfunc)member_get,		/* tp_descr_get */ | ||
|  | 	(descrsetfunc)member_set,		/* tp_descr_set */ | ||
|  | }; | ||
|  | 
 | ||
|  | static PyTypeObject PyGetSetDescr_Type = { | ||
|  | 	PyObject_HEAD_INIT(&PyType_Type) | ||
|  | 	0, | ||
|  | 	"getset_descriptor", | ||
|  | 	sizeof(PyGetSetDescrObject), | ||
|  | 	0, | ||
|  | 	(destructor)descr_dealloc,		/* tp_dealloc */ | ||
|  | 	0,					/* tp_print */ | ||
|  | 	0,					/* tp_getattr */ | ||
|  | 	0,					/* tp_setattr */ | ||
|  | 	0,					/* tp_compare */ | ||
|  | 	(reprfunc)getset_repr,			/* tp_repr */ | ||
|  | 	0,					/* tp_as_number */ | ||
|  | 	0,					/* tp_as_sequence */ | ||
|  | 	0,					/* tp_as_mapping */ | ||
|  | 	0,					/* tp_hash */ | ||
|  | 	(ternaryfunc)0,				/* tp_call */ | ||
|  | 	0,					/* tp_str */ | ||
|  | 	PyObject_GenericGetAttr,		/* tp_getattro */ | ||
|  | 	0,					/* tp_setattro */ | ||
|  | 	0,					/* tp_as_buffer */ | ||
|  | 	Py_TPFLAGS_DEFAULT,			/* tp_flags */ | ||
|  | 	0,					/* tp_doc */ | ||
|  | 	0,					/* tp_traverse */ | ||
|  | 	0,					/* tp_clear */ | ||
|  | 	0,					/* tp_richcompare */ | ||
|  | 	0,					/* tp_weaklistoffset */ | ||
|  | 	0,					/* tp_iter */ | ||
|  | 	0,					/* tp_iternext */ | ||
|  | 	0,					/* tp_methods */ | ||
|  | 	descr_members,				/* tp_members */ | ||
|  | 	0,					/* tp_getset */ | ||
|  | 	0,					/* tp_base */ | ||
|  | 	0,					/* tp_dict */ | ||
|  | 	(descrgetfunc)getset_get,		/* tp_descr_get */ | ||
|  | 	(descrsetfunc)getset_set,		/* tp_descr_set */ | ||
|  | }; | ||
|  | 
 | ||
|  | static PyTypeObject PyWrapperDescr_Type = { | ||
|  | 	PyObject_HEAD_INIT(&PyType_Type) | ||
|  | 	0, | ||
|  | 	"wrapper_descriptor", | ||
|  | 	sizeof(PyWrapperDescrObject), | ||
|  | 	0, | ||
|  | 	(destructor)descr_dealloc,		/* tp_dealloc */ | ||
|  | 	0,					/* tp_print */ | ||
|  | 	0,					/* tp_getattr */ | ||
|  | 	0,					/* tp_setattr */ | ||
|  | 	0,					/* tp_compare */ | ||
|  | 	(reprfunc)wrapper_repr,			/* tp_repr */ | ||
|  | 	0,					/* tp_as_number */ | ||
|  | 	0,					/* tp_as_sequence */ | ||
|  | 	0,					/* tp_as_mapping */ | ||
|  | 	0,					/* tp_hash */ | ||
|  | 	(ternaryfunc)wrapperdescr_call,		/* tp_call */ | ||
|  | 	0,					/* tp_str */ | ||
|  | 	PyObject_GenericGetAttr,		/* tp_getattro */ | ||
|  | 	0,					/* tp_setattro */ | ||
|  | 	0,					/* tp_as_buffer */ | ||
|  | 	Py_TPFLAGS_DEFAULT,			/* tp_flags */ | ||
|  | 	0,					/* tp_doc */ | ||
|  | 	0,					/* tp_traverse */ | ||
|  | 	0,					/* tp_clear */ | ||
|  | 	0,					/* tp_richcompare */ | ||
|  | 	0,					/* tp_weaklistoffset */ | ||
|  | 	0,					/* tp_iter */ | ||
|  | 	0,					/* tp_iternext */ | ||
|  | 	0,					/* tp_methods */ | ||
|  | 	descr_members,				/* tp_members */ | ||
|  | 	wrapper_getset,				/* tp_getset */ | ||
|  | 	0,					/* tp_base */ | ||
|  | 	0,					/* tp_dict */ | ||
|  | 	(descrgetfunc)wrapper_get,		/* tp_descr_get */ | ||
|  | 	0,					/* tp_descr_set */ | ||
|  | }; | ||
|  | 
 | ||
|  | static PyDescrObject * | ||
|  | descr_new(PyTypeObject *descrtype, PyTypeObject *type, char *name) | ||
|  | { | ||
|  | 	PyDescrObject *descr; | ||
|  | 
 | ||
|  | 	descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0); | ||
|  | 	if (descr != NULL) { | ||
|  | 		Py_XINCREF(type); | ||
|  | 		descr->d_type = type; | ||
|  | 		descr->d_name = PyString_InternFromString(name); | ||
|  | 		if (descr->d_name == NULL) { | ||
|  | 			Py_DECREF(descr); | ||
|  | 			descr = NULL; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	return descr; | ||
|  | } | ||
|  | 
 | ||
|  | PyObject * | ||
|  | PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method) | ||
|  | { | ||
|  | 	PyMethodDescrObject *descr; | ||
|  | 
 | ||
|  | 	descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type, | ||
|  | 						 type, method->ml_name); | ||
|  | 	if (descr != NULL) | ||
|  | 		descr->d_method = method; | ||
|  | 	return (PyObject *)descr; | ||
|  | } | ||
|  | 
 | ||
|  | PyObject * | ||
|  | PyDescr_NewMember(PyTypeObject *type, struct memberlist *member) | ||
|  | { | ||
|  | 	PyMemberDescrObject *descr; | ||
|  | 
 | ||
|  | 	descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type, | ||
|  | 						 type, member->name); | ||
|  | 	if (descr != NULL) | ||
|  | 		descr->d_member = member; | ||
|  | 	return (PyObject *)descr; | ||
|  | } | ||
|  | 
 | ||
|  | PyObject * | ||
|  | PyDescr_NewGetSet(PyTypeObject *type, struct getsetlist *getset) | ||
|  | { | ||
|  | 	PyGetSetDescrObject *descr; | ||
|  | 
 | ||
|  | 	descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type, | ||
|  | 						 type, getset->name); | ||
|  | 	if (descr != NULL) | ||
|  | 		descr->d_getset = getset; | ||
|  | 	return (PyObject *)descr; | ||
|  | } | ||
|  | 
 | ||
|  | PyObject * | ||
|  | PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped) | ||
|  | { | ||
|  | 	PyWrapperDescrObject *descr; | ||
|  | 
 | ||
|  | 	descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type, | ||
|  | 						 type, base->name); | ||
|  | 	if (descr != NULL) { | ||
|  | 		descr->d_base = base; | ||
|  | 		descr->d_wrapped = wrapped; | ||
|  | 	} | ||
|  | 	return (PyObject *)descr; | ||
|  | } | ||
|  | 
 | ||
|  | int | ||
|  | PyDescr_IsData(PyObject *d) | ||
|  | { | ||
|  | 	return d->ob_type->tp_descr_set != NULL; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* --- Readonly proxy for dictionaries (actually any mapping) --- */ | ||
|  | 
 | ||
|  | /* This has no reason to be in this file except that adding new files is a
 | ||
|  |    bit of a pain */ | ||
|  | 
 | ||
|  | typedef struct { | ||
|  | 	PyObject_HEAD | ||
|  | 	PyObject *dict; | ||
|  | } proxyobject; | ||
|  | 
 | ||
|  | static int | ||
|  | proxy_len(proxyobject *pp) | ||
|  | { | ||
|  | 	return PyObject_Size(pp->dict); | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | proxy_getitem(proxyobject *pp, PyObject *key) | ||
|  | { | ||
|  | 	return PyObject_GetItem(pp->dict, key); | ||
|  | } | ||
|  | 
 | ||
|  | static PyMappingMethods proxy_as_mapping = { | ||
|  | 	(inquiry)proxy_len,			/* mp_length */ | ||
|  | 	(binaryfunc)proxy_getitem,		/* mp_subscript */ | ||
|  | 	0,					/* mp_ass_subscript */ | ||
|  | }; | ||
|  | 
 | ||
|  | static int | ||
|  | proxy_contains(proxyobject *pp, PyObject *key) | ||
|  | { | ||
|  | 	return PySequence_Contains(pp->dict, key); | ||
|  | } | ||
|  | 
 | ||
|  | static PySequenceMethods proxy_as_sequence = { | ||
|  | 	0,					/* sq_length */ | ||
|  | 	0,					/* sq_concat */ | ||
|  | 	0,					/* sq_repeat */ | ||
|  | 	0,					/* sq_item */ | ||
|  | 	0,					/* sq_slice */ | ||
|  | 	0,					/* sq_ass_item */ | ||
|  | 	0,					/* sq_ass_slice */ | ||
|  | 	(objobjproc)proxy_contains,		/* sq_contains */ | ||
|  | 	0,					/* sq_inplace_concat */ | ||
|  | 	0,					/* sq_inplace_repeat */ | ||
|  | }; | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | proxy_has_key(proxyobject *pp, PyObject *args) | ||
|  | { | ||
|  | 	PyObject *key; | ||
|  | 
 | ||
|  | 	if (!PyArg_ParseTuple(args, "O:has_key", &key)) | ||
|  | 		return NULL; | ||
|  | 	return PyInt_FromLong(PySequence_Contains(pp->dict, key)); | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | proxy_get(proxyobject *pp, PyObject *args) | ||
|  | { | ||
|  | 	PyObject *key, *def = Py_None; | ||
|  | 
 | ||
|  | 	if (!PyArg_ParseTuple(args, "O|O:get", &key, &def)) | ||
|  | 		return NULL; | ||
|  | 	return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def); | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | proxy_keys(proxyobject *pp, PyObject *args) | ||
|  | { | ||
|  | 	if (!PyArg_ParseTuple(args, ":keys")) | ||
|  | 		return NULL; | ||
|  | 	return PyMapping_Keys(pp->dict); | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | proxy_values(proxyobject *pp, PyObject *args) | ||
|  | { | ||
|  | 	if (!PyArg_ParseTuple(args, ":values")) | ||
|  | 		return NULL; | ||
|  | 	return PyMapping_Values(pp->dict); | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | proxy_items(proxyobject *pp, PyObject *args) | ||
|  | { | ||
|  | 	if (!PyArg_ParseTuple(args, ":items")) | ||
|  | 		return NULL; | ||
|  | 	return PyMapping_Items(pp->dict); | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | proxy_copy(proxyobject *pp, PyObject *args) | ||
|  | { | ||
|  | 	if (!PyArg_ParseTuple(args, ":copy")) | ||
|  | 		return NULL; | ||
|  | 	return PyObject_CallMethod(pp->dict, "copy", NULL); | ||
|  | } | ||
|  | 
 | ||
|  | static PyMethodDef proxy_methods[] = { | ||
|  | 	{"has_key", (PyCFunction)proxy_has_key, METH_VARARGS, "XXX"}, | ||
|  | 	{"get",	    (PyCFunction)proxy_get,     METH_VARARGS, "XXX"}, | ||
|  | 	{"keys",    (PyCFunction)proxy_keys,    METH_VARARGS, "XXX"}, | ||
|  | 	{"values",  (PyCFunction)proxy_values,  METH_VARARGS, "XXX"}, | ||
|  | 	{"items",   (PyCFunction)proxy_items,   METH_VARARGS, "XXX"}, | ||
|  | 	{"copy",    (PyCFunction)proxy_copy,    METH_VARARGS, "XXX"}, | ||
|  | 	{0} | ||
|  | }; | ||
|  | 
 | ||
|  | static void | ||
|  | proxy_dealloc(proxyobject *pp) | ||
|  | { | ||
|  | 	Py_DECREF(pp->dict); | ||
|  | 	PyObject_DEL(pp); | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | proxy_getiter(proxyobject *pp) | ||
|  | { | ||
|  | 	return PyObject_GetIter(pp->dict); | ||
|  | } | ||
|  | 
 | ||
|  | PyObject * | ||
|  | proxy_str(proxyobject *pp) | ||
|  | { | ||
|  | 	return PyObject_Str(pp->dict); | ||
|  | } | ||
|  | 
 | ||
|  | PyTypeObject proxytype = { | ||
|  | 	PyObject_HEAD_INIT(&PyType_Type) | ||
|  | 	0,					/* ob_size */ | ||
|  | 	"dict-proxy",				/* tp_name */ | ||
|  | 	sizeof(proxyobject),			/* tp_basicsize */ | ||
|  | 	0,					/* tp_itemsize */ | ||
|  | 	/* methods */ | ||
|  | 	(destructor)proxy_dealloc, 		/* tp_dealloc */ | ||
|  | 	0,					/* tp_print */ | ||
|  | 	0,					/* tp_getattr */ | ||
|  | 	0,					/* tp_setattr */ | ||
|  | 	0,					/* tp_compare */ | ||
|  | 	0,					/* tp_repr */ | ||
|  | 	0,					/* tp_as_number */ | ||
|  | 	&proxy_as_sequence,			/* tp_as_sequence */ | ||
|  | 	&proxy_as_mapping,			/* tp_as_mapping */ | ||
|  | 	0,					/* tp_hash */ | ||
|  | 	0,					/* tp_call */ | ||
|  | 	(reprfunc)proxy_str,			/* tp_str */ | ||
|  | 	PyObject_GenericGetAttr,		/* tp_getattro */ | ||
|  | 	0,					/* tp_setattro */ | ||
|  | 	0,					/* tp_as_buffer */ | ||
|  | 	Py_TPFLAGS_DEFAULT,			/* tp_flags */ | ||
|  |  	0,					/* tp_doc */ | ||
|  |  	0,					/* tp_traverse */ | ||
|  |  	0,					/* tp_clear */ | ||
|  | 	0,					/* tp_richcompare */ | ||
|  | 	0,					/* tp_weaklistoffset */ | ||
|  | 	(getiterfunc)proxy_getiter,		/* tp_iter */ | ||
|  | 	0,					/* tp_iternext */ | ||
|  | 	proxy_methods,				/* tp_methods */ | ||
|  | 	0,					/* tp_members */ | ||
|  | 	0,					/* tp_getset */ | ||
|  | 	0,					/* tp_base */ | ||
|  | 	0,					/* tp_dict */ | ||
|  | 	0,					/* tp_descr_get */ | ||
|  | 	0,					/* tp_descr_set */ | ||
|  | }; | ||
|  | 
 | ||
|  | PyObject * | ||
|  | PyDictProxy_New(PyObject *dict) | ||
|  | { | ||
|  | 	proxyobject *pp; | ||
|  | 
 | ||
|  | 	pp = PyObject_NEW(proxyobject, &proxytype); | ||
|  | 	if (pp != NULL) { | ||
|  | 		Py_INCREF(dict); | ||
|  | 		pp->dict = dict; | ||
|  | 	} | ||
|  | 	return (PyObject *)pp; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /* --- Wrapper object for "slot" methods --- */ | ||
|  | 
 | ||
|  | /* This has no reason to be in this file except that adding new files is a
 | ||
|  |    bit of a pain */ | ||
|  | 
 | ||
|  | typedef struct { | ||
|  | 	PyObject_HEAD | ||
|  | 	PyWrapperDescrObject *descr; | ||
|  | 	PyObject *self; | ||
|  | } wrapperobject; | ||
|  | 
 | ||
|  | static void | ||
|  | wrapper_dealloc(wrapperobject *wp) | ||
|  | { | ||
|  | 	Py_XDECREF(wp->descr); | ||
|  | 	Py_XDECREF(wp->self); | ||
|  | 	PyObject_DEL(wp); | ||
|  | } | ||
|  | 
 | ||
|  | static PyMethodDef wrapper_methods[] = { | ||
|  | 	{0} | ||
|  | }; | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | wrapper_name(wrapperobject *wp) | ||
|  | { | ||
|  | 	char *s = wp->descr->d_base->name; | ||
|  | 
 | ||
|  | 	return PyString_FromString(s); | ||
|  | } | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | wrapper_doc(wrapperobject *wp) | ||
|  | { | ||
|  | 	char *s = wp->descr->d_base->doc; | ||
|  | 
 | ||
|  | 	if (s == NULL) { | ||
|  | 		Py_INCREF(Py_None); | ||
|  | 		return Py_None; | ||
|  | 	} | ||
|  | 	else { | ||
|  | 		return PyString_FromString(s); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | static struct getsetlist wrapper_getsets[] = { | ||
|  | 	{"__name__", (getter)wrapper_name}, | ||
|  | 	{"__doc__", (getter)wrapper_doc}, | ||
|  | 	{0} | ||
|  | }; | ||
|  | 
 | ||
|  | static PyObject * | ||
|  | wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds) | ||
|  | { | ||
|  | 	wrapperfunc wrapper = wp->descr->d_base->wrapper; | ||
|  | 	PyObject *self = wp->self; | ||
|  | 
 | ||
|  | 	return (*wrapper)(self, args, wp->descr->d_wrapped); | ||
|  | } | ||
|  | 
 | ||
|  | PyTypeObject wrappertype = { | ||
|  | 	PyObject_HEAD_INIT(&PyType_Type) | ||
|  | 	0,					/* ob_size */ | ||
|  | 	"method-wrapper",			/* tp_name */ | ||
|  | 	sizeof(wrapperobject),			/* tp_basicsize */ | ||
|  | 	0,					/* tp_itemsize */ | ||
|  | 	/* methods */ | ||
|  | 	(destructor)wrapper_dealloc, 		/* tp_dealloc */ | ||
|  | 	0,					/* tp_print */ | ||
|  | 	0,					/* tp_getattr */ | ||
|  | 	0,					/* tp_setattr */ | ||
|  | 	0,					/* tp_compare */ | ||
|  | 	0,					/* tp_repr */ | ||
|  | 	0,					/* tp_as_number */ | ||
|  | 	0,					/* tp_as_sequence */ | ||
|  | 	0,		       			/* tp_as_mapping */ | ||
|  | 	0,					/* tp_hash */ | ||
|  | 	(ternaryfunc)wrapper_call,		/* tp_call */ | ||
|  | 	0,					/* tp_str */ | ||
|  | 	PyObject_GenericGetAttr,		/* tp_getattro */ | ||
|  | 	0,					/* tp_setattro */ | ||
|  | 	0,					/* tp_as_buffer */ | ||
|  | 	Py_TPFLAGS_DEFAULT,			/* tp_flags */ | ||
|  |  	0,					/* tp_doc */ | ||
|  |  	0,					/* tp_traverse */ | ||
|  |  	0,					/* tp_clear */ | ||
|  | 	0,					/* tp_richcompare */ | ||
|  | 	0,					/* tp_weaklistoffset */ | ||
|  | 	0,					/* tp_iter */ | ||
|  | 	0,					/* tp_iternext */ | ||
|  | 	wrapper_methods,			/* tp_methods */ | ||
|  | 	0,					/* tp_members */ | ||
|  | 	wrapper_getsets,			/* tp_getset */ | ||
|  | 	0,					/* tp_base */ | ||
|  | 	0,					/* tp_dict */ | ||
|  | 	0,					/* tp_descr_get */ | ||
|  | 	0,					/* tp_descr_set */ | ||
|  | }; | ||
|  | 
 | ||
|  | PyObject * | ||
|  | PyWrapper_New(PyObject *d, PyObject *self) | ||
|  | { | ||
|  | 	wrapperobject *wp; | ||
|  | 	PyWrapperDescrObject *descr; | ||
|  | 
 | ||
|  | 	assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type)); | ||
|  | 	descr = (PyWrapperDescrObject *)d; | ||
|  | 	assert(PyObject_IsInstance(self, (PyObject *)(descr->d_type))); | ||
|  | 
 | ||
|  | 	wp = PyObject_NEW(wrapperobject, &wrappertype); | ||
|  | 	if (wp != NULL) { | ||
|  | 		Py_INCREF(descr); | ||
|  | 		wp->descr = descr; | ||
|  | 		Py_INCREF(self); | ||
|  | 		wp->self = self; | ||
|  | 	} | ||
|  | 	return (PyObject *)wp; | ||
|  | } |