1 /***********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI or Corporation for National Research Initiatives or
13 CNRI not be used in advertising or publicity pertaining to
14 distribution of the software without specific, written prior
17 While CWI is the initial source for this software, a modified version
18 is made available by the Corporation for National Research Initiatives
19 (CNRI) at the Internet address ftp://ftp.python.org.
21 STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22 REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23 MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24 CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28 PERFORMANCE OF THIS SOFTWARE.
30 ******************************************************************/
32 /* Traceback implementation */
37 #include "frameobject.h"
38 #include "structmember.h"
41 typedef struct _tracebackobject
{
43 struct _tracebackobject
*tb_next
;
44 PyFrameObject
*tb_frame
;
49 #define OFF(x) offsetof(tracebackobject, x)
51 static struct memberlist tb_memberlist
[] = {
52 {"tb_next", T_OBJECT
, OFF(tb_next
)},
53 {"tb_frame", T_OBJECT
, OFF(tb_frame
)},
54 {"tb_lasti", T_INT
, OFF(tb_lasti
)},
55 {"tb_lineno", T_INT
, OFF(tb_lineno
)},
64 return PyMember_Get((char *)tb
, tb_memberlist
, name
);
71 Py_XDECREF(tb
->tb_next
);
72 Py_XDECREF(tb
->tb_frame
);
76 #define Tracebacktype PyTraceBack_Type
77 #define is_tracebackobject PyTraceBack_Check
79 PyTypeObject Tracebacktype
= {
80 PyObject_HEAD_INIT(&PyType_Type
)
83 sizeof(tracebackobject
),
85 (destructor
)tb_dealloc
, /*tp_dealloc*/
87 (getattrfunc
)tb_getattr
, /*tp_getattr*/
96 static tracebackobject
*
97 newtracebackobject(next
, frame
, lasti
, lineno
)
98 tracebackobject
*next
;
103 if ((next
!= NULL
&& !is_tracebackobject(next
)) ||
104 frame
== NULL
|| !PyFrame_Check(frame
)) {
105 PyErr_BadInternalCall();
108 tb
= PyObject_NEW(tracebackobject
, &Tracebacktype
);
113 tb
->tb_frame
= frame
;
114 tb
->tb_lasti
= lasti
;
115 tb
->tb_lineno
= lineno
;
121 PyTraceBack_Here(frame
)
122 PyFrameObject
*frame
;
124 PyThreadState
*tstate
= frame
->f_tstate
;
125 tracebackobject
*oldtb
= (tracebackobject
*) tstate
->curexc_traceback
;
126 tracebackobject
*tb
= newtracebackobject(oldtb
,
127 frame
, frame
->f_lasti
, frame
->f_lineno
);
130 tstate
->curexc_traceback
= (PyObject
*)tb
;
136 tb_displayline(f
, filename
, lineno
, name
)
146 if (filename
== NULL
|| name
== NULL
)
149 /* This is needed by MPW's File and Line commands */
150 #define FMT " File \"%.900s\"; line %d # in %s\n"
152 /* This is needed by Emacs' compile command */
153 #define FMT " File \"%.900s\", line %d, in %s\n"
155 xfp
= fopen(filename
, "r");
157 /* Search tail of filename in sys.path before giving up */
159 char *tail
= strrchr(filename
, SEP
);
164 path
= PySys_GetObject("path");
165 if (path
!= NULL
&& PyList_Check(path
)) {
166 int npath
= PyList_Size(path
);
167 int taillen
= strlen(tail
);
168 char namebuf
[MAXPATHLEN
+1];
169 for (i
= 0; i
< npath
; i
++) {
170 PyObject
*v
= PyList_GetItem(path
, i
);
175 if (PyString_Check(v
)) {
177 len
= PyString_Size(v
);
178 if (len
+ 1 + taillen
>= MAXPATHLEN
)
179 continue; /* Too long */
180 strcpy(namebuf
, PyString_AsString(v
));
181 if ((int)strlen(namebuf
) != len
)
182 continue; /* v contains '\0' */
183 if (len
> 0 && namebuf
[len
-1] != SEP
)
184 namebuf
[len
++] = SEP
;
185 strcpy(namebuf
+len
, tail
);
186 xfp
= fopen(namebuf
, "r");
195 sprintf(linebuf
, FMT
, filename
, lineno
, name
);
196 err
= PyFile_WriteString(linebuf
, f
);
197 if (xfp
== NULL
|| err
!= 0)
199 for (i
= 0; i
< lineno
; i
++) {
200 char* pLastChar
= &linebuf
[sizeof(linebuf
)-2];
203 if (fgets(linebuf
, sizeof linebuf
, xfp
) == NULL
)
205 /* fgets read *something*; if it didn't get as
206 far as pLastChar, it must have found a newline
207 or hit the end of the file; if pLastChar is \n,
208 it obviously found a newline; else we haven't
209 yet seen a newline, so must continue */
210 } while (*pLastChar
!= '\0' && *pLastChar
!= '\n');
214 while (*p
== ' ' || *p
== '\t' || *p
== '\014')
216 err
= PyFile_WriteString(" ", f
);
218 err
= PyFile_WriteString(p
, f
);
219 if (err
== 0 && strchr(p
, '\n') == NULL
)
220 err
= PyFile_WriteString("\n", f
);
228 tb_printinternal(tb
, f
, 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(v
, f
)
269 if (!is_tracebackobject(v
)) {
270 PyErr_BadInternalCall();
273 limitv
= PySys_GetObject("tracebacklimit");
274 if (limitv
&& PyInt_Check(limitv
)) {
275 limit
= PyInt_AsLong(limitv
);
279 err
= PyFile_WriteString("Traceback (innermost last):\n", f
);
281 err
= tb_printinternal((tracebackobject
*)v
, f
, limit
);