365 lines · 8.0 KB · C
RawDownload
 /* Method object implementation */ #include "Python.h"#include "structmember.h" static PyCFunctionObject *free_list = NULL; PyObject *PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module){	PyCFunctionObject *op;	op = free_list;	if (op != NULL) {		free_list = (PyCFunctionObject *)(op->m_self);		PyObject_INIT(op, &PyCFunction_Type);	}	else {		op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type);		if (op == NULL)			return NULL;	}	op->m_ml = ml;	Py_XINCREF(self);	op->m_self = self;	Py_XINCREF(module);	op->m_module = module;	_PyObject_GC_TRACK(op);	return (PyObject *)op;} PyCFunctionPyCFunction_GetFunction(PyObject *op){	if (!PyCFunction_Check(op)) {		PyErr_BadInternalCall();		return NULL;	}	return ((PyCFunctionObject *)op) -> m_ml -> ml_meth;} PyObject *PyCFunction_GetSelf(PyObject *op){	if (!PyCFunction_Check(op)) {		PyErr_BadInternalCall();		return NULL;	}	return ((PyCFunctionObject *)op) -> m_self;} intPyCFunction_GetFlags(PyObject *op){	if (!PyCFunction_Check(op)) {		PyErr_BadInternalCall();		return -1;	}	return ((PyCFunctionObject *)op) -> m_ml -> ml_flags;} PyObject *PyCFunction_Call(PyObject *func, PyObject *arg, PyObject *kw){	PyCFunctionObject* f = (PyCFunctionObject*)func;	PyCFunction meth = PyCFunction_GET_FUNCTION(func);	PyObject *self = PyCFunction_GET_SELF(func);	Py_ssize_t size; 	switch (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)) {	case METH_VARARGS:		if (kw == NULL || PyDict_Size(kw) == 0)			return (*meth)(self, arg);		break;	case METH_VARARGS | METH_KEYWORDS:	case METH_OLDARGS | METH_KEYWORDS:		return (*(PyCFunctionWithKeywords)meth)(self, arg, kw);	case METH_NOARGS:		if (kw == NULL || PyDict_Size(kw) == 0) {			size = PyTuple_GET_SIZE(arg);			if (size == 0)				return (*meth)(self, NULL);			PyErr_Format(PyExc_TypeError,			    "%.200s() takes no arguments (%zd given)",			    f->m_ml->ml_name, size);			return NULL;		}		break;	case METH_O:		if (kw == NULL || PyDict_Size(kw) == 0) {			size = PyTuple_GET_SIZE(arg);			if (size == 1)				return (*meth)(self, PyTuple_GET_ITEM(arg, 0));			PyErr_Format(PyExc_TypeError,			    "%.200s() takes exactly one argument (%zd given)",			    f->m_ml->ml_name, size);			return NULL;		}		break;	case METH_OLDARGS:		/* the really old style */		if (kw == NULL || PyDict_Size(kw) == 0) {			size = PyTuple_GET_SIZE(arg);			if (size == 1)				arg = PyTuple_GET_ITEM(arg, 0);			else if (size == 0)				arg = NULL;			return (*meth)(self, arg);		}		break;	default:		PyErr_BadInternalCall();		return NULL;	}	PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",		     f->m_ml->ml_name);	return NULL;} /* Methods (the standard built-in methods, that is) */ static voidmeth_dealloc(PyCFunctionObject *m){	_PyObject_GC_UNTRACK(m);	Py_XDECREF(m->m_self);	Py_XDECREF(m->m_module);	m->m_self = (PyObject *)free_list;	free_list = m;} static PyObject *meth_get__doc__(PyCFunctionObject *m, void *closure){	const char *doc = m->m_ml->ml_doc; 	if (doc != NULL)		return PyString_FromString(doc);	Py_INCREF(Py_None);	return Py_None;} static PyObject *meth_get__name__(PyCFunctionObject *m, void *closure){	return PyString_FromString(m->m_ml->ml_name);} static intmeth_traverse(PyCFunctionObject *m, visitproc visit, void *arg){	Py_VISIT(m->m_self);	Py_VISIT(m->m_module);	return 0;} static PyObject *meth_get__self__(PyCFunctionObject *m, void *closure){	PyObject *self;	if (PyEval_GetRestricted()) {		PyErr_SetString(PyExc_RuntimeError,			"method.__self__ not accessible in restricted mode");		return NULL;	}	self = m->m_self;	if (self == NULL)		self = Py_None;	Py_INCREF(self);	return self;} static PyGetSetDef meth_getsets [] = {	{"__doc__",  (getter)meth_get__doc__,  NULL, NULL},	{"__name__", (getter)meth_get__name__, NULL, NULL},	{"__self__", (getter)meth_get__self__, NULL, NULL},	{0}}; #define OFF(x) offsetof(PyCFunctionObject, x) static PyMemberDef meth_members[] = {	{"__module__",    T_OBJECT,     OFF(m_module), WRITE_RESTRICTED},	{NULL}}; static PyObject *meth_repr(PyCFunctionObject *m){	if (m->m_self == NULL)		return PyString_FromFormat("<built-in function %s>",					   m->m_ml->ml_name);	return PyString_FromFormat("<built-in method %s of %s object at %p>",				   m->m_ml->ml_name,				   m->m_self->ob_type->tp_name,				   m->m_self);} static intmeth_compare(PyCFunctionObject *a, PyCFunctionObject *b){	if (a->m_self != b->m_self)		return (a->m_self < b->m_self) ? -1 : 1;	if (a->m_ml->ml_meth == b->m_ml->ml_meth)		return 0;	if (strcmp(a->m_ml->ml_name, b->m_ml->ml_name) < 0)		return -1;	else		return 1;} static longmeth_hash(PyCFunctionObject *a){	long x,y;	if (a->m_self == NULL)		x = 0;	else {		x = PyObject_Hash(a->m_self);		if (x == -1)			return -1;	}	y = _Py_HashPointer((void*)(a->m_ml->ml_meth));	if (y == -1)		return -1;	x ^= y;	if (x == -1)		x = -2;	return x;}  PyTypeObject PyCFunction_Type = {	PyObject_HEAD_INIT(&PyType_Type)	0,	"builtin_function_or_method",	sizeof(PyCFunctionObject),	0,	(destructor)meth_dealloc, 		/* tp_dealloc */	0,					/* tp_print */	0,					/* tp_getattr */	0,					/* tp_setattr */	(cmpfunc)meth_compare,			/* tp_compare */	(reprfunc)meth_repr,			/* tp_repr */	0,					/* tp_as_number */	0,					/* tp_as_sequence */	0,					/* tp_as_mapping */	(hashfunc)meth_hash,			/* tp_hash */	PyCFunction_Call,			/* tp_call */	0,					/* tp_str */	PyObject_GenericGetAttr,		/* tp_getattro */	0,					/* tp_setattro */	0,					/* tp_as_buffer */	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ 	0,					/* tp_doc */ 	(traverseproc)meth_traverse,		/* tp_traverse */	0,					/* tp_clear */	0,					/* tp_richcompare */	0,					/* tp_weaklistoffset */	0,					/* tp_iter */	0,					/* tp_iternext */	0,					/* tp_methods */	meth_members,				/* tp_members */	meth_getsets,				/* tp_getset */	0,					/* tp_base */	0,					/* tp_dict */}; /* List all methods in a chain -- helper for findmethodinchain */ static PyObject *listmethodchain(PyMethodChain *chain){	PyMethodChain *c;	PyMethodDef *ml;	int i, n;	PyObject *v; 	n = 0;	for (c = chain; c != NULL; c = c->link) {		for (ml = c->methods; ml->ml_name != NULL; ml++)			n++;	}	v = PyList_New(n);	if (v == NULL)		return NULL;	i = 0;	for (c = chain; c != NULL; c = c->link) {		for (ml = c->methods; ml->ml_name != NULL; ml++) {			PyList_SetItem(v, i, PyString_FromString(ml->ml_name));			i++;		}	}	if (PyErr_Occurred()) {		Py_DECREF(v);		return NULL;	}	PyList_Sort(v);	return v;} /* Find a method in a method chain */ PyObject *Py_FindMethodInChain(PyMethodChain *chain, PyObject *self, const char *name){	if (name[0] == '_' && name[1] == '_') {		if (strcmp(name, "__methods__") == 0)			return listmethodchain(chain);		if (strcmp(name, "__doc__") == 0) {			const char *doc = self->ob_type->tp_doc;			if (doc != NULL)				return PyString_FromString(doc);		}	}	while (chain != NULL) {		PyMethodDef *ml = chain->methods;		for (; ml->ml_name != NULL; ml++) {			if (name[0] == ml->ml_name[0] &&			    strcmp(name+1, ml->ml_name+1) == 0)				/* XXX */				return PyCFunction_New(ml, self);		}		chain = chain->link;	}	PyErr_SetString(PyExc_AttributeError, name);	return NULL;} /* Find a method in a single method list */ PyObject *Py_FindMethod(PyMethodDef *methods, PyObject *self, const char *name){	PyMethodChain chain;	chain.methods = methods;	chain.link = NULL;	return Py_FindMethodInChain(&chain, self, name);} /* Clear out the free list */ voidPyCFunction_Fini(void){	while (free_list) {		PyCFunctionObject *v = free_list;		free_list = (PyCFunctionObject *)(v->m_self);		PyObject_GC_Del(v);	}} /* PyCFunction_New() is now just a macro that calls PyCFunction_NewEx(),   but it's part of the API so we need to keep a function around that   existing C extensions can call.*/   #undef PyCFunction_NewPyAPI_FUNC(PyObject *) PyCFunction_New(PyMethodDef *, PyObject *); PyObject *PyCFunction_New(PyMethodDef *ml, PyObject *self){	return PyCFunction_NewEx(ml, self, NULL);}