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
)
109 if ((next
!= NULL
&& !PyTraceBack_Check(next
)) ||
110 frame
== NULL
|| !PyFrame_Check(frame
)) {
111 PyErr_BadInternalCall();
114 tb
= PyObject_GC_New(tracebackobject
, &PyTraceBack_Type
);
119 tb
->tb_frame
= frame
;
120 tb
->tb_lasti
= frame
->f_lasti
;
121 tb
->tb_lineno
= PyCode_Addr2Line(frame
->f_code
,
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
, frame
);
136 tstate
->curexc_traceback
= (PyObject
*)tb
;
142 tb_displayline(PyObject
*f
, char *filename
, int lineno
, char *name
)
148 if (filename
== NULL
|| name
== NULL
)
151 /* This is needed by MPW's File and Line commands */
152 #define FMT " File \"%.500s\"; line %d # in %.500s\n"
154 /* This is needed by Emacs' compile command */
155 #define FMT " File \"%.500s\", line %d, in %.500s\n"
157 xfp
= fopen(filename
, "r" PY_STDIOTEXTMODE
);
159 /* Search tail of filename in sys.path before giving up */
161 char *tail
= strrchr(filename
, SEP
);
166 path
= PySys_GetObject("path");
167 if (path
!= NULL
&& PyList_Check(path
)) {
168 int npath
= PyList_Size(path
);
169 size_t taillen
= strlen(tail
);
170 char namebuf
[MAXPATHLEN
+1];
171 for (i
= 0; i
< npath
; i
++) {
172 PyObject
*v
= PyList_GetItem(path
, i
);
177 if (PyString_Check(v
)) {
179 len
= PyString_Size(v
);
180 if (len
+ 1 + taillen
>= MAXPATHLEN
)
181 continue; /* Too long */
182 strcpy(namebuf
, PyString_AsString(v
));
183 if (strlen(namebuf
) != len
)
184 continue; /* v contains '\0' */
185 if (len
> 0 && namebuf
[len
-1] != SEP
)
186 namebuf
[len
++] = SEP
;
187 strcpy(namebuf
+len
, tail
);
188 xfp
= fopen(namebuf
, "r" PY_STDIOTEXTMODE
);
197 PyOS_snprintf(linebuf
, sizeof(linebuf
), FMT
, filename
, lineno
, name
);
198 err
= PyFile_WriteString(linebuf
, f
);
199 if (xfp
== NULL
|| err
!= 0)
201 for (i
= 0; i
< lineno
; i
++) {
202 char* pLastChar
= &linebuf
[sizeof(linebuf
)-2];
205 if (Py_UniversalNewlineFgets(linebuf
, sizeof linebuf
, xfp
, NULL
) == NULL
)
207 /* fgets read *something*; if it didn't get as
208 far as pLastChar, it must have found a newline
209 or hit the end of the file; if pLastChar is \n,
210 it obviously found a newline; else we haven't
211 yet seen a newline, so must continue */
212 } while (*pLastChar
!= '\0' && *pLastChar
!= '\n');
216 while (*p
== ' ' || *p
== '\t' || *p
== '\014')
218 err
= PyFile_WriteString(" ", f
);
220 err
= PyFile_WriteString(p
, f
);
221 if (err
== 0 && strchr(p
, '\n') == NULL
)
222 err
= PyFile_WriteString("\n", f
);
230 tb_printinternal(tracebackobject
*tb
, PyObject
*f
, int limit
)
234 tracebackobject
*tb1
= tb
;
235 while (tb1
!= NULL
) {
239 while (tb
!= NULL
&& err
== 0) {
240 if (depth
<= limit
) {
241 err
= tb_displayline(f
,
243 tb
->tb_frame
->f_code
->co_filename
),
245 PyString_AsString(tb
->tb_frame
->f_code
->co_name
));
250 err
= PyErr_CheckSignals();
256 PyTraceBack_Print(PyObject
*v
, PyObject
*f
)
263 if (!PyTraceBack_Check(v
)) {
264 PyErr_BadInternalCall();
267 limitv
= PySys_GetObject("tracebacklimit");
268 if (limitv
&& PyInt_Check(limitv
)) {
269 limit
= PyInt_AsLong(limitv
);
273 err
= PyFile_WriteString("Traceback (most recent call last):\n", f
);
275 err
= tb_printinternal((tracebackobject
*)v
, f
, limit
);