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 Py_TRASHCAN_SAFE_BEGIN(tb
)
39 Py_XDECREF(tb
->tb_next
);
40 Py_XDECREF(tb
->tb_frame
);
42 Py_TRASHCAN_SAFE_END(tb
)
45 #define Tracebacktype PyTraceBack_Type
46 #define is_tracebackobject PyTraceBack_Check
48 PyTypeObject Tracebacktype
= {
49 PyObject_HEAD_INIT(&PyType_Type
)
52 sizeof(tracebackobject
),
54 (destructor
)tb_dealloc
, /*tp_dealloc*/
56 (getattrfunc
)tb_getattr
, /*tp_getattr*/
65 static tracebackobject
*
66 newtracebackobject(tracebackobject
*next
, PyFrameObject
*frame
, int lasti
,
70 if ((next
!= NULL
&& !is_tracebackobject(next
)) ||
71 frame
== NULL
|| !PyFrame_Check(frame
)) {
72 PyErr_BadInternalCall();
75 tb
= PyObject_NEW(tracebackobject
, &Tracebacktype
);
82 tb
->tb_lineno
= lineno
;
88 PyTraceBack_Here(PyFrameObject
*frame
)
90 PyThreadState
*tstate
= frame
->f_tstate
;
91 tracebackobject
*oldtb
= (tracebackobject
*) tstate
->curexc_traceback
;
92 tracebackobject
*tb
= newtracebackobject(oldtb
,
93 frame
, frame
->f_lasti
, frame
->f_lineno
);
96 tstate
->curexc_traceback
= (PyObject
*)tb
;
102 tb_displayline(PyObject
*f
, char *filename
, int lineno
, char *name
)
108 if (filename
== NULL
|| name
== NULL
)
111 /* This is needed by MPW's File and Line commands */
112 #define FMT " File \"%.900s\"; line %d # in %s\n"
114 /* This is needed by Emacs' compile command */
115 #define FMT " File \"%.900s\", line %d, in %s\n"
117 xfp
= fopen(filename
, "r");
119 /* Search tail of filename in sys.path before giving up */
121 char *tail
= strrchr(filename
, SEP
);
126 path
= PySys_GetObject("path");
127 if (path
!= NULL
&& PyList_Check(path
)) {
128 int npath
= PyList_Size(path
);
129 size_t taillen
= strlen(tail
);
130 char namebuf
[MAXPATHLEN
+1];
131 for (i
= 0; i
< npath
; i
++) {
132 PyObject
*v
= PyList_GetItem(path
, i
);
137 if (PyString_Check(v
)) {
139 len
= PyString_Size(v
);
140 if (len
+ 1 + taillen
>= MAXPATHLEN
)
141 continue; /* Too long */
142 strcpy(namebuf
, PyString_AsString(v
));
143 if (strlen(namebuf
) != len
)
144 continue; /* v contains '\0' */
145 if (len
> 0 && namebuf
[len
-1] != SEP
)
146 namebuf
[len
++] = SEP
;
147 strcpy(namebuf
+len
, tail
);
148 xfp
= fopen(namebuf
, "r");
157 sprintf(linebuf
, FMT
, filename
, lineno
, name
);
158 err
= PyFile_WriteString(linebuf
, f
);
159 if (xfp
== NULL
|| err
!= 0)
161 for (i
= 0; i
< lineno
; i
++) {
162 char* pLastChar
= &linebuf
[sizeof(linebuf
)-2];
165 if (fgets(linebuf
, sizeof linebuf
, xfp
) == NULL
)
167 /* fgets read *something*; if it didn't get as
168 far as pLastChar, it must have found a newline
169 or hit the end of the file; if pLastChar is \n,
170 it obviously found a newline; else we haven't
171 yet seen a newline, so must continue */
172 } while (*pLastChar
!= '\0' && *pLastChar
!= '\n');
176 while (*p
== ' ' || *p
== '\t' || *p
== '\014')
178 err
= PyFile_WriteString(" ", f
);
180 err
= PyFile_WriteString(p
, f
);
181 if (err
== 0 && strchr(p
, '\n') == NULL
)
182 err
= PyFile_WriteString("\n", f
);
190 tb_printinternal(tracebackobject
*tb
, PyObject
*f
, int limit
)
194 tracebackobject
*tb1
= tb
;
195 while (tb1
!= NULL
) {
199 while (tb
!= NULL
&& err
== 0) {
200 if (depth
<= limit
) {
202 tb
->tb_lineno
= PyCode_Addr2Line(
203 tb
->tb_frame
->f_code
, tb
->tb_lasti
);
204 err
= tb_displayline(f
,
206 tb
->tb_frame
->f_code
->co_filename
),
208 PyString_AsString(tb
->tb_frame
->f_code
->co_name
));
213 err
= PyErr_CheckSignals();
219 PyTraceBack_Print(PyObject
*v
, PyObject
*f
)
226 if (!is_tracebackobject(v
)) {
227 PyErr_BadInternalCall();
230 limitv
= PySys_GetObject("tracebacklimit");
231 if (limitv
&& PyInt_Check(limitv
)) {
232 limit
= PyInt_AsLong(limitv
);
236 err
= PyFile_WriteString("Traceback (most recent call last):\n", f
);
238 err
= tb_printinternal((tracebackobject
*)v
, f
, limit
);