/* Function object implementation */ #include "Python.h" #include "compile.h" #include "structmember.h" PyObject * PyFunction_New(PyObject *code, PyObject *globals) { PyFunctionObject *op = PyObject_NEW(PyFunctionObject, &PyFunction_Type); if (op != NULL) { PyObject *doc; PyObject *consts; Py_INCREF(code); op->func_code = code; Py_INCREF(globals); op->func_globals = globals; op->func_name = ((PyCodeObject *)code)->co_name; Py_INCREF(op->func_name); op->func_defaults = NULL; /* No default arguments */ consts = ((PyCodeObject *)code)->co_consts; if (PyTuple_Size(consts) >= 1) { doc = PyTuple_GetItem(consts, 0); if (!PyString_Check(doc) && !PyUnicode_Check(doc)) doc = Py_None; } else doc = Py_None; Py_INCREF(doc); op->func_doc = doc; op->func_dict = NULL; } else return NULL; PyObject_GC_Init(op); return (PyObject *)op; } PyObject * PyFunction_GetCode(PyObject *op) { if (!PyFunction_Check(op)) { PyErr_BadInternalCall(); return NULL; } return ((PyFunctionObject *) op) -> func_code; } PyObject * PyFunction_GetGlobals(PyObject *op) { if (!PyFunction_Check(op)) { PyErr_BadInternalCall(); return NULL; } return ((PyFunctionObject *) op) -> func_globals; } PyObject * PyFunction_GetDefaults(PyObject *op) { if (!PyFunction_Check(op)) { PyErr_BadInternalCall(); return NULL; } return ((PyFunctionObject *) op) -> func_defaults; } int PyFunction_SetDefaults(PyObject *op, PyObject *defaults) { if (!PyFunction_Check(op)) { PyErr_BadInternalCall(); return -1; } if (defaults == Py_None) defaults = NULL; else if (PyTuple_Check(defaults)) { Py_XINCREF(defaults); } else { PyErr_SetString(PyExc_SystemError, "non-tuple default args"); return -1; } Py_XDECREF(((PyFunctionObject *) op) -> func_defaults); ((PyFunctionObject *) op) -> func_defaults = defaults; return 0; } /* Methods */ #define OFF(x) offsetof(PyFunctionObject, x) static struct memberlist func_memberlist[] = { {"func_code", T_OBJECT, OFF(func_code)}, {"func_globals",T_OBJECT, OFF(func_globals), READONLY}, {"func_name", T_OBJECT, OFF(func_name), READONLY}, {"__name__", T_OBJECT, OFF(func_name), READONLY}, {"func_defaults",T_OBJECT, OFF(func_defaults)}, {"func_doc", T_OBJECT, OFF(func_doc)}, {"__doc__", T_OBJECT, OFF(func_doc)}, {NULL} /* Sentinel */ }; static PyObject * func_getattro(PyFunctionObject *op, PyObject *name) { PyObject *rtn; char *sname = PyString_AsString(name); if (sname[0] != '_' && PyEval_GetRestricted()) { PyErr_SetString(PyExc_RuntimeError, "function attributes not accessible in restricted mode"); return NULL; } if (!strcmp(sname, "__dict__") || !strcmp(sname, "func_dict")) { if (op->func_dict == NULL) rtn = Py_None; else rtn = op->func_dict; Py_INCREF(rtn); return rtn; } /* no API for PyMember_HasAttr() */ rtn = PyMember_Get((char *)op, func_memberlist, sname); if (rtn == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Clear(); if (op->func_dict != NULL) { rtn = PyDict_GetItem(op->func_dict, name); Py_XINCREF(rtn); } if (rtn == NULL) PyErr_SetObject(PyExc_AttributeError, name); } return rtn; } static int func_setattro(PyFunctionObject *op, PyObject *name, PyObject *value) { int rtn; char *sname = PyString_AsString(name); if (PyEval_GetRestricted()) { PyErr_SetString(PyExc_RuntimeError, "function attributes not settable in restricted mode"); return -1; } if (strcmp(sname, "func_code") == 0) { if (value == NULL || !PyCode_Check(value)) { PyErr_SetString( PyExc_TypeError, "func_code must be set to a code object"); return -1; } } else if (strcmp(sname, "func_defaults") == 0) { if (value != Py_None && !PyTuple_Check(value)) { PyErr_SetString( PyExc_TypeError, "func_defaults must be set to a tuple object"); return -1; } if (value == Py_None) value = NULL; } else if (!strcmp(sname, "func_dict") || !strcmp(sname, "__dict__")) { if (value != Py_None && !PyDict_Check(value)) { PyErr_SetString( PyExc_TypeError, "func_dict must be set to a dict object"); return -1; } if (value == Py_None) value = NULL; Py_XDECREF(op->func_dict); Py_XINCREF(value); op->func_dict = value; return 0; } rtn = PyMember_Set((char *)op, func_memberlist, sname, value); if (rtn < 0 && PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Clear(); if (op->func_dict == NULL) { op->func_dict = PyDict_New(); if (op->func_dict == NULL) return -1; } rtn = PyDict_SetItem(op->func_dict, name, value); } return rtn; } static void func_dealloc(PyFunctionObject *op) { PyObject_GC_Fini(op); Py_DECREF(op->func_code); Py_DECREF(op->func_globals); Py_DECREF(op->func_name); Py_XDECREF(op->func_defaults); Py_XDECREF(op->func_doc); Py_XDECREF(op->func_dict); op = (PyFunctionObject *) PyObject_AS_GC(op); PyObject_DEL(op); } static PyObject* func_repr(PyFunctionObject *op) { char buf[140]; if (op->func_name == Py_None) sprintf(buf, "", op); else sprintf(buf, "", PyString_AsString(op->func_name), op); return PyString_FromString(buf); } static int func_compare(PyFunctionObject *f, PyFunctionObject *g) { int c; if (f->func_globals != g->func_globals) return (f->func_globals < g->func_globals) ? -1 : 1; if (f->func_defaults != g->func_defaults) { if (f->func_defaults == NULL) return -1; if (g->func_defaults == NULL) return 1; c = PyObject_Compare(f->func_defaults, g->func_defaults); if (c != 0) return c; } return PyObject_Compare(f->func_code, g->func_code); } static long func_hash(PyFunctionObject *f) { long h,x; h = PyObject_Hash(f->func_code); if (h == -1) return h; x = _Py_HashPointer(f->func_globals); if (x == -1) return x; h ^= x; if (h == -1) h = -2; return h; } static int func_traverse(PyFunctionObject *f, visitproc visit, void *arg) { int err; if (f->func_code) { err = visit(f->func_code, arg); if (err) return err; } if (f->func_globals) { err = visit(f->func_globals, arg); if (err) return err; } if (f->func_defaults) { err = visit(f->func_defaults, arg); if (err) return err; } if (f->func_doc) { err = visit(f->func_doc, arg); if (err) return err; } if (f->func_name) { err = visit(f->func_name, arg); if (err) return err; } if (f->func_dict) { err = visit(f->func_dict, arg); if (err) return err; } return 0; } PyTypeObject PyFunction_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, "function", sizeof(PyFunctionObject) + PyGC_HEAD_SIZE, 0, (destructor)func_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ (cmpfunc)func_compare, /*tp_compare*/ (reprfunc)func_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ (hashfunc)func_hash, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ (getattrofunc)func_getattro, /*tp_getattro*/ (setattrofunc)func_setattro, /*tp_setattro*/ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/ 0, /* tp_doc */ (traverseproc)func_traverse, /* tp_traverse */ };