+++ /dev/null
-\r
-/* Traceback implementation */\r
-\r
-#include "Python.h"\r
-\r
-#include "code.h"\r
-#include "frameobject.h"\r
-#include "structmember.h"\r
-#include "osdefs.h"\r
-#include "traceback.h"\r
-\r
-#define OFF(x) offsetof(PyTracebackObject, x)\r
-\r
-static PyMemberDef tb_memberlist[] = {\r
- {"tb_next", T_OBJECT, OFF(tb_next), READONLY},\r
- {"tb_frame", T_OBJECT, OFF(tb_frame), READONLY},\r
- {"tb_lasti", T_INT, OFF(tb_lasti), READONLY},\r
- {"tb_lineno", T_INT, OFF(tb_lineno), READONLY},\r
- {NULL} /* Sentinel */\r
-};\r
-\r
-static void\r
-tb_dealloc(PyTracebackObject *tb)\r
-{\r
- PyObject_GC_UnTrack(tb);\r
- Py_TRASHCAN_SAFE_BEGIN(tb)\r
- Py_XDECREF(tb->tb_next);\r
- Py_XDECREF(tb->tb_frame);\r
- PyObject_GC_Del(tb);\r
- Py_TRASHCAN_SAFE_END(tb)\r
-}\r
-\r
-static int\r
-tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg)\r
-{\r
- Py_VISIT(tb->tb_next);\r
- Py_VISIT(tb->tb_frame);\r
- return 0;\r
-}\r
-\r
-static void\r
-tb_clear(PyTracebackObject *tb)\r
-{\r
- Py_CLEAR(tb->tb_next);\r
- Py_CLEAR(tb->tb_frame);\r
-}\r
-\r
-PyTypeObject PyTraceBack_Type = {\r
- PyVarObject_HEAD_INIT(&PyType_Type, 0)\r
- "traceback",\r
- sizeof(PyTracebackObject),\r
- 0,\r
- (destructor)tb_dealloc, /*tp_dealloc*/\r
- 0, /*tp_print*/\r
- 0, /*tp_getattr*/\r
- 0, /*tp_setattr*/\r
- 0, /*tp_compare*/\r
- 0, /*tp_repr*/\r
- 0, /*tp_as_number*/\r
- 0, /*tp_as_sequence*/\r
- 0, /*tp_as_mapping*/\r
- 0, /* tp_hash */\r
- 0, /* tp_call */\r
- 0, /* tp_str */\r
- 0, /* tp_getattro */\r
- 0, /* tp_setattro */\r
- 0, /* tp_as_buffer */\r
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */\r
- 0, /* tp_doc */\r
- (traverseproc)tb_traverse, /* tp_traverse */\r
- (inquiry)tb_clear, /* tp_clear */\r
- 0, /* tp_richcompare */\r
- 0, /* tp_weaklistoffset */\r
- 0, /* tp_iter */\r
- 0, /* tp_iternext */\r
- 0, /* tp_methods */\r
- tb_memberlist, /* tp_members */\r
- 0, /* tp_getset */\r
- 0, /* tp_base */\r
- 0, /* tp_dict */\r
-};\r
-\r
-static PyTracebackObject *\r
-newtracebackobject(PyTracebackObject *next, PyFrameObject *frame)\r
-{\r
- PyTracebackObject *tb;\r
- if ((next != NULL && !PyTraceBack_Check(next)) ||\r
- frame == NULL || !PyFrame_Check(frame)) {\r
- PyErr_BadInternalCall();\r
- return NULL;\r
- }\r
- tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type);\r
- if (tb != NULL) {\r
- Py_XINCREF(next);\r
- tb->tb_next = next;\r
- Py_XINCREF(frame);\r
- tb->tb_frame = frame;\r
- tb->tb_lasti = frame->f_lasti;\r
- tb->tb_lineno = PyFrame_GetLineNumber(frame);\r
- PyObject_GC_Track(tb);\r
- }\r
- return tb;\r
-}\r
-\r
-int\r
-PyTraceBack_Here(PyFrameObject *frame)\r
-{\r
- PyThreadState *tstate = PyThreadState_GET();\r
- PyTracebackObject *oldtb = (PyTracebackObject *) tstate->curexc_traceback;\r
- PyTracebackObject *tb = newtracebackobject(oldtb, frame);\r
- if (tb == NULL)\r
- return -1;\r
- tstate->curexc_traceback = (PyObject *)tb;\r
- Py_XDECREF(oldtb);\r
- return 0;\r
-}\r
-\r
-int\r
-_Py_DisplaySourceLine(PyObject *f, const char *filename, int lineno, int indent)\r
-{\r
- int err = 0;\r
- FILE *xfp = NULL;\r
- char linebuf[2000];\r
- int i;\r
- char namebuf[MAXPATHLEN+1];\r
-\r
- if (filename == NULL)\r
- return -1;\r
- /* This is needed by Emacs' compile command */\r
-#define FMT " File \"%.500s\", line %d, in %.500s\n"\r
- xfp = fopen(filename, "r" PY_STDIOTEXTMODE);\r
- if (xfp == NULL) {\r
- /* Search tail of filename in sys.path before giving up */\r
- PyObject *path;\r
- const char *tail = strrchr(filename, SEP);\r
- if (tail == NULL)\r
- tail = filename;\r
- else\r
- tail++;\r
- path = PySys_GetObject("path");\r
- if (path != NULL && PyList_Check(path)) {\r
- Py_ssize_t _npath = PyList_Size(path);\r
- int npath = Py_SAFE_DOWNCAST(_npath, Py_ssize_t, int);\r
- size_t taillen = strlen(tail);\r
- for (i = 0; i < npath; i++) {\r
- PyObject *v = PyList_GetItem(path, i);\r
- if (v == NULL) {\r
- PyErr_Clear();\r
- break;\r
- }\r
- if (PyString_Check(v)) {\r
- size_t len;\r
- len = PyString_GET_SIZE(v);\r
- if (len + 1 + taillen >= MAXPATHLEN)\r
- continue; /* Too long */\r
- strcpy(namebuf, PyString_AsString(v));\r
- if (strlen(namebuf) != len)\r
- continue; /* v contains '\0' */\r
- if (len > 0 && namebuf[len-1] != SEP)\r
- namebuf[len++] = SEP;\r
- strcpy(namebuf+len, tail);\r
- xfp = fopen(namebuf, "r" PY_STDIOTEXTMODE);\r
- if (xfp != NULL) {\r
- break;\r
- }\r
- }\r
- }\r
- }\r
- }\r
-\r
- if (xfp == NULL)\r
- return err;\r
- if (err != 0) {\r
- fclose(xfp);\r
- return err;\r
- }\r
-\r
- for (i = 0; i < lineno; i++) {\r
- char* pLastChar = &linebuf[sizeof(linebuf)-2];\r
- do {\r
- *pLastChar = '\0';\r
- if (Py_UniversalNewlineFgets(linebuf, sizeof linebuf, xfp, NULL) == NULL)\r
- break;\r
- /* fgets read *something*; if it didn't get as\r
- far as pLastChar, it must have found a newline\r
- or hit the end of the file; if pLastChar is \n,\r
- it obviously found a newline; else we haven't\r
- yet seen a newline, so must continue */\r
- } while (*pLastChar != '\0' && *pLastChar != '\n');\r
- }\r
- if (i == lineno) {\r
- char buf[11];\r
- char *p = linebuf;\r
- while (*p == ' ' || *p == '\t' || *p == '\014')\r
- p++;\r
-\r
- /* Write some spaces before the line */\r
- strcpy(buf, " ");\r
- assert (strlen(buf) == 10);\r
- while (indent > 0) {\r
- if(indent < 10)\r
- buf[indent] = '\0';\r
- err = PyFile_WriteString(buf, f);\r
- if (err != 0)\r
- break;\r
- indent -= 10;\r
- }\r
-\r
- if (err == 0)\r
- err = PyFile_WriteString(p, f);\r
- if (err == 0 && strchr(p, '\n') == NULL)\r
- err = PyFile_WriteString("\n", f);\r
- }\r
- fclose(xfp);\r
- return err;\r
-}\r
-\r
-static int\r
-tb_displayline(PyObject *f, const char *filename, int lineno, const char *name)\r
-{\r
- int err = 0;\r
- char linebuf[2000];\r
-\r
- if (filename == NULL || name == NULL)\r
- return -1;\r
- /* This is needed by Emacs' compile command */\r
-#define FMT " File \"%.500s\", line %d, in %.500s\n"\r
- PyOS_snprintf(linebuf, sizeof(linebuf), FMT, filename, lineno, name);\r
- err = PyFile_WriteString(linebuf, f);\r
- if (err != 0)\r
- return err;\r
- return _Py_DisplaySourceLine(f, filename, lineno, 4);\r
-}\r
-\r
-static int\r
-tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)\r
-{\r
- int err = 0;\r
- long depth = 0;\r
- PyTracebackObject *tb1 = tb;\r
- while (tb1 != NULL) {\r
- depth++;\r
- tb1 = tb1->tb_next;\r
- }\r
- while (tb != NULL && err == 0) {\r
- if (depth <= limit) {\r
- err = tb_displayline(f,\r
- PyString_AsString(\r
- tb->tb_frame->f_code->co_filename),\r
- tb->tb_lineno,\r
- PyString_AsString(tb->tb_frame->f_code->co_name));\r
- }\r
- depth--;\r
- tb = tb->tb_next;\r
- if (err == 0)\r
- err = PyErr_CheckSignals();\r
- }\r
- return err;\r
-}\r
-\r
-int\r
-PyTraceBack_Print(PyObject *v, PyObject *f)\r
-{\r
- int err;\r
- PyObject *limitv;\r
- long limit = 1000;\r
- if (v == NULL)\r
- return 0;\r
- if (!PyTraceBack_Check(v)) {\r
- PyErr_BadInternalCall();\r
- return -1;\r
- }\r
- limitv = PySys_GetObject("tracebacklimit");\r
- if (limitv && PyInt_Check(limitv)) {\r
- limit = PyInt_AsLong(limitv);\r
- if (limit <= 0)\r
- return 0;\r
- }\r
- err = PyFile_WriteString("Traceback (most recent call last):\n", f);\r
- if (!err)\r
- err = tb_printinternal((PyTracebackObject *)v, f, limit);\r
- return err;\r
-}\r