Merged release21-maint changes.
[python/dscho.git] / Objects / methodobject.c
blob56fbcc22fd9a05b6046effc5caa10c14cd54e905
2 /* Method object implementation */
4 #include "Python.h"
6 static PyCFunctionObject *free_list = NULL;
8 PyObject *
9 PyCFunction_New(PyMethodDef *ml, PyObject *self)
11 PyCFunctionObject *op;
12 op = free_list;
13 if (op != NULL) {
14 free_list = (PyCFunctionObject *)(op->m_self);
15 PyObject_INIT(op, &PyCFunction_Type);
17 else {
18 op = PyObject_NEW(PyCFunctionObject, &PyCFunction_Type);
19 if (op == NULL)
20 return NULL;
22 op->m_ml = ml;
23 Py_XINCREF(self);
24 op->m_self = self;
25 PyObject_GC_Init(op);
26 return (PyObject *)op;
29 PyCFunction
30 PyCFunction_GetFunction(PyObject *op)
32 if (!PyCFunction_Check(op)) {
33 PyErr_BadInternalCall();
34 return NULL;
36 return ((PyCFunctionObject *)op) -> m_ml -> ml_meth;
39 PyObject *
40 PyCFunction_GetSelf(PyObject *op)
42 if (!PyCFunction_Check(op)) {
43 PyErr_BadInternalCall();
44 return NULL;
46 return ((PyCFunctionObject *)op) -> m_self;
49 int
50 PyCFunction_GetFlags(PyObject *op)
52 if (!PyCFunction_Check(op)) {
53 PyErr_BadInternalCall();
54 return -1;
56 return ((PyCFunctionObject *)op) -> m_ml -> ml_flags;
59 /* Methods (the standard built-in methods, that is) */
61 static void
62 meth_dealloc(PyCFunctionObject *m)
64 PyObject_GC_Fini(m);
65 Py_XDECREF(m->m_self);
66 m->m_self = (PyObject *)free_list;
67 free_list = m;
70 static PyObject *
71 meth_get__doc__(PyCFunctionObject *m, void *closure)
73 char *doc = m->m_ml->ml_doc;
75 if (doc != NULL)
76 return PyString_FromString(doc);
77 Py_INCREF(Py_None);
78 return Py_None;
81 static PyObject *
82 meth_get__name__(PyCFunctionObject *m, void *closure)
84 return PyString_FromString(m->m_ml->ml_name);
87 static int
88 meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
90 if (m->m_self != NULL)
91 return visit(m->m_self, arg);
92 else
93 return 0;
96 static PyObject *
97 meth_get__self__(PyCFunctionObject *m, void *closure)
99 PyObject *self;
100 if (PyEval_GetRestricted()) {
101 PyErr_SetString(PyExc_RuntimeError,
102 "method.__self__ not accessible in restricted mode");
103 return NULL;
105 self = m->m_self;
106 if (self == NULL)
107 self = Py_None;
108 Py_INCREF(self);
109 return self;
112 static struct getsetlist meth_getsets [] = {
113 {"__doc__", (getter)meth_get__doc__, NULL, NULL},
114 {"__name__", (getter)meth_get__name__, NULL, NULL},
115 {"__self__", (getter)meth_get__self__, NULL, NULL},
119 static PyObject *
120 meth_repr(PyCFunctionObject *m)
122 char buf[200];
123 if (m->m_self == NULL)
124 sprintf(buf, "<built-in function %.80s>", m->m_ml->ml_name);
125 else
126 sprintf(buf,
127 "<built-in method %.80s of %.80s object at %p>",
128 m->m_ml->ml_name, m->m_self->ob_type->tp_name,
129 m->m_self);
130 return PyString_FromString(buf);
133 static int
134 meth_compare(PyCFunctionObject *a, PyCFunctionObject *b)
136 if (a->m_self != b->m_self)
137 return (a->m_self < b->m_self) ? -1 : 1;
138 if (a->m_ml->ml_meth == b->m_ml->ml_meth)
139 return 0;
140 if (strcmp(a->m_ml->ml_name, b->m_ml->ml_name) < 0)
141 return -1;
142 else
143 return 1;
146 static long
147 meth_hash(PyCFunctionObject *a)
149 long x,y;
150 if (a->m_self == NULL)
151 x = 0;
152 else {
153 x = PyObject_Hash(a->m_self);
154 if (x == -1)
155 return -1;
157 y = _Py_HashPointer((void*)(a->m_ml->ml_meth));
158 if (y == -1)
159 return -1;
160 x ^= y;
161 if (x == -1)
162 x = -2;
163 return x;
166 static PyObject *
167 meth_call(PyObject *func, PyObject *arg, PyObject *kw)
169 PyCFunctionObject* f = (PyCFunctionObject*)func;
170 PyCFunction meth = PyCFunction_GET_FUNCTION(func);
171 PyObject *self = PyCFunction_GET_SELF(func);
172 int flags = PyCFunction_GET_FLAGS(func);
174 if (flags & METH_KEYWORDS) {
175 return (*(PyCFunctionWithKeywords)meth)(self, arg, kw);
177 if (kw != NULL && PyDict_Size(kw) != 0) {
178 PyErr_Format(PyExc_TypeError,
179 "%.200s() takes no keyword arguments",
180 f->m_ml->ml_name);
181 return NULL;
183 if (flags & METH_VARARGS) {
184 return (*meth)(self, arg);
186 if (!(flags & METH_VARARGS)) {
187 /* the really old style */
188 int size = PyTuple_GET_SIZE(arg);
189 if (size == 1)
190 arg = PyTuple_GET_ITEM(arg, 0);
191 else if (size == 0)
192 arg = NULL;
193 return (*meth)(self, arg);
195 /* should never get here ??? */
196 PyErr_BadInternalCall();
197 return NULL;
201 PyTypeObject PyCFunction_Type = {
202 PyObject_HEAD_INIT(&PyType_Type)
204 "builtin_function_or_method",
205 sizeof(PyCFunctionObject) + PyGC_HEAD_SIZE,
207 (destructor)meth_dealloc, /* tp_dealloc */
208 0, /* tp_print */
209 0, /* tp_getattr */
210 0, /* tp_setattr */
211 (cmpfunc)meth_compare, /* tp_compare */
212 (reprfunc)meth_repr, /* tp_repr */
213 0, /* tp_as_number */
214 0, /* tp_as_sequence */
215 0, /* tp_as_mapping */
216 (hashfunc)meth_hash, /* tp_hash */
217 meth_call, /* tp_call */
218 0, /* tp_str */
219 PyObject_GenericGetAttr, /* tp_getattro */
220 0, /* tp_setattro */
221 0, /* tp_as_buffer */
222 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */
223 0, /* tp_doc */
224 (traverseproc)meth_traverse, /* tp_traverse */
225 0, /* tp_clear */
226 0, /* tp_richcompare */
227 0, /* tp_weaklistoffset */
228 0, /* tp_iter */
229 0, /* tp_iternext */
230 0, /* tp_methods */
231 0, /* tp_members */
232 meth_getsets, /* tp_getset */
233 0, /* tp_base */
234 0, /* tp_dict */
237 /* List all methods in a chain -- helper for findmethodinchain */
239 static PyObject *
240 listmethodchain(PyMethodChain *chain)
242 PyMethodChain *c;
243 PyMethodDef *ml;
244 int i, n;
245 PyObject *v;
247 n = 0;
248 for (c = chain; c != NULL; c = c->link) {
249 for (ml = c->methods; ml->ml_name != NULL; ml++)
250 n++;
252 v = PyList_New(n);
253 if (v == NULL)
254 return NULL;
255 i = 0;
256 for (c = chain; c != NULL; c = c->link) {
257 for (ml = c->methods; ml->ml_name != NULL; ml++) {
258 PyList_SetItem(v, i, PyString_FromString(ml->ml_name));
259 i++;
262 if (PyErr_Occurred()) {
263 Py_DECREF(v);
264 return NULL;
266 PyList_Sort(v);
267 return v;
270 /* Find a method in a method chain */
272 PyObject *
273 Py_FindMethodInChain(PyMethodChain *chain, PyObject *self, char *name)
275 if (name[0] == '_' && name[1] == '_') {
276 if (strcmp(name, "__methods__") == 0)
277 return listmethodchain(chain);
278 if (strcmp(name, "__doc__") == 0) {
279 char *doc = self->ob_type->tp_doc;
280 if (doc != NULL)
281 return PyString_FromString(doc);
284 while (chain != NULL) {
285 PyMethodDef *ml = chain->methods;
286 for (; ml->ml_name != NULL; ml++) {
287 if (name[0] == ml->ml_name[0] &&
288 strcmp(name+1, ml->ml_name+1) == 0)
289 return PyCFunction_New(ml, self);
291 chain = chain->link;
293 PyErr_SetString(PyExc_AttributeError, name);
294 return NULL;
297 /* Find a method in a single method list */
299 PyObject *
300 Py_FindMethod(PyMethodDef *methods, PyObject *self, char *name)
302 PyMethodChain chain;
303 chain.methods = methods;
304 chain.link = NULL;
305 return Py_FindMethodInChain(&chain, self, name);
308 /* Clear out the free list */
310 void
311 PyCFunction_Fini(void)
313 while (free_list) {
314 PyCFunctionObject *v = free_list;
315 free_list = (PyCFunctionObject *)(v->m_self);
316 v = (PyCFunctionObject *) PyObject_AS_GC(v);
317 PyObject_DEL(v);