2 /* Traceback implementation */
7 #include "frameobject.h"
8 #include "structmember.h"
11 typedef struct _tracebackobject
{
13 struct _tracebackobject
*tb_next
;
14 PyFrameObject
*tb_frame
;
19 #define OFF(x) offsetof(tracebackobject, x)
21 static struct memberlist tb_memberlist
[] = {
22 {"tb_next", T_OBJECT
, OFF(tb_next
)},
23 {"tb_frame", T_OBJECT
, OFF(tb_frame
)},
24 {"tb_lasti", T_INT
, OFF(tb_lasti
)},
25 {"tb_lineno", T_INT
, OFF(tb_lineno
)},
30 tb_getattr(tracebackobject
*tb
, char *name
)
32 return PyMember_Get((char *)tb
, tb_memberlist
, name
);
36 tb_dealloc(tracebackobject
*tb
)
38 PyObject_GC_UnTrack(tb
);
39 Py_TRASHCAN_SAFE_BEGIN(tb
)
40 Py_XDECREF(tb
->tb_next
);
41 Py_XDECREF(tb
->tb_frame
);
43 Py_TRASHCAN_SAFE_END(tb
)
47 tb_traverse(tracebackobject
*tb
, visitproc visit
, void *arg
)
51 err
= visit((PyObject
*)tb
->tb_next
, arg
);
56 err
= visit((PyObject
*)tb
->tb_frame
, arg
);
61 tb_clear(tracebackobject
*tb
)
63 Py_XDECREF(tb
->tb_next
);
64 Py_XDECREF(tb
->tb_frame
);
69 PyTypeObject PyTraceBack_Type
= {
70 PyObject_HEAD_INIT(&PyType_Type
)
73 sizeof(tracebackobject
),
75 (destructor
)tb_dealloc
, /*tp_dealloc*/
77 (getattrfunc
)tb_getattr
, /*tp_getattr*/
90 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
,/* tp_flags */
92 (traverseproc
)tb_traverse
, /* tp_traverse */
93 (inquiry
)tb_clear
, /* tp_clear */
94 0, /* tp_richcompare */
95 0, /* tp_weaklistoffset */
105 static tracebackobject
*
106 newtracebackobject(tracebackobject
*next
, PyFrameObject
*frame
, int lasti
,
110 if ((next
!= NULL
&& !PyTraceBack_Check(next
)) ||
111 frame
== NULL
|| !PyFrame_Check(frame
)) {
112 PyErr_BadInternalCall();
115 tb
= PyObject_GC_New(tracebackobject
, &PyTraceBack_Type
);
120 tb
->tb_frame
= frame
;
121 tb
->tb_lasti
= lasti
;
122 tb
->tb_lineno
= lineno
;
123 PyObject_GC_Track(tb
);
129 PyTraceBack_Here(PyFrameObject
*frame
)
131 PyThreadState
*tstate
= frame
->f_tstate
;
132 tracebackobject
*oldtb
= (tracebackobject
*) tstate
->curexc_traceback
;
133 tracebackobject
*tb
= newtracebackobject(oldtb
,
134 frame
, frame
->f_lasti
, frame
->f_lineno
);
137 tstate
->curexc_traceback
= (PyObject
*)tb
;
143 tb_displayline(PyObject
*f
, char *filename
, int lineno
, char *name
)
149 if (filename
== NULL
|| name
== NULL
)
152 /* This is needed by MPW's File and Line commands */
153 #define FMT " File \"%.500s\"; line %d # in %.500s\n"
155 /* This is needed by Emacs' compile command */
156 #define FMT " File \"%.500s\", line %d, in %.500s\n"
158 xfp
= fopen(filename
, "r" PY_STDIOTEXTMODE
);
160 /* Search tail of filename in sys.path before giving up */
162 char *tail
= strrchr(filename
, SEP
);
167 path
= PySys_GetObject("path");
168 if (path
!= NULL
&& PyList_Check(path
)) {
169 int npath
= PyList_Size(path
);
170 size_t taillen
= strlen(tail
);
171 char namebuf
[MAXPATHLEN
+1];
172 for (i
= 0; i
< npath
; i
++) {
173 PyObject
*v
= PyList_GetItem(path
, i
);
178 if (PyString_Check(v
)) {
180 len
= PyString_Size(v
);
181 if (len
+ 1 + taillen
>= MAXPATHLEN
)
182 continue; /* Too long */
183 strcpy(namebuf
, PyString_AsString(v
));
184 if (strlen(namebuf
) != len
)
185 continue; /* v contains '\0' */
186 if (len
> 0 && namebuf
[len
-1] != SEP
)
187 namebuf
[len
++] = SEP
;
188 strcpy(namebuf
+len
, tail
);
189 xfp
= fopen(namebuf
, "r" PY_STDIOTEXTMODE
);
198 PyOS_snprintf(linebuf
, sizeof(linebuf
), FMT
, filename
, lineno
, name
);
199 err
= PyFile_WriteString(linebuf
, f
);
200 if (xfp
== NULL
|| err
!= 0)
202 for (i
= 0; i
< lineno
; i
++) {
203 char* pLastChar
= &linebuf
[sizeof(linebuf
)-2];
206 if (Py_UniversalNewlineFgets(linebuf
, sizeof linebuf
, xfp
, NULL
) == NULL
)
208 /* fgets read *something*; if it didn't get as
209 far as pLastChar, it must have found a newline
210 or hit the end of the file; if pLastChar is \n,
211 it obviously found a newline; else we haven't
212 yet seen a newline, so must continue */
213 } while (*pLastChar
!= '\0' && *pLastChar
!= '\n');
217 while (*p
== ' ' || *p
== '\t' || *p
== '\014')
219 err
= PyFile_WriteString(" ", f
);
221 err
= PyFile_WriteString(p
, f
);
222 if (err
== 0 && strchr(p
, '\n') == NULL
)
223 err
= PyFile_WriteString("\n", f
);
231 tb_printinternal(tracebackobject
*tb
, PyObject
*f
, int limit
)
235 tracebackobject
*tb1
= tb
;
236 while (tb1
!= NULL
) {
240 while (tb
!= NULL
&& err
== 0) {
241 if (depth
<= limit
) {
243 tb
->tb_lineno
= PyCode_Addr2Line(
244 tb
->tb_frame
->f_code
, tb
->tb_lasti
);
245 err
= tb_displayline(f
,
247 tb
->tb_frame
->f_code
->co_filename
),
249 PyString_AsString(tb
->tb_frame
->f_code
->co_name
));
254 err
= PyErr_CheckSignals();
260 PyTraceBack_Print(PyObject
*v
, PyObject
*f
)
267 if (!PyTraceBack_Check(v
)) {
268 PyErr_BadInternalCall();
271 limitv
= PySys_GetObject("tracebacklimit");
272 if (limitv
&& PyInt_Check(limitv
)) {
273 limit
= PyInt_AsLong(limitv
);
277 err
= PyFile_WriteString("Traceback (most recent call last):\n", f
);
279 err
= tb_printinternal((tracebackobject
*)v
, f
, limit
);