blob: e1148cd26284adccf162d18a9565e9b706e3c0d1 [file] [log] [blame]
Guido van Rossumf70e43a1991-02-19 12:39:46 +00001/***********************************************************
Guido van Rossum6d023c91995-01-04 19:12:13 +00002Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
Guido van Rossumf70e43a1991-02-19 12:39:46 +00004
5 All Rights Reserved
6
Guido van Rossumd266eb41996-10-25 14:44:06 +00007Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
Guido van Rossumf70e43a1991-02-19 12:39:46 +00009provided that the above copyright notice appear in all copies and that
Guido van Rossumd266eb41996-10-25 14:44:06 +000010both that copyright notice and this permission notice appear in
Guido van Rossumf70e43a1991-02-19 12:39:46 +000011supporting documentation, and that the names of Stichting Mathematisch
Guido van Rossumd266eb41996-10-25 14:44:06 +000012Centrum or CWI or Corporation for National Research Initiatives or
13CNRI not be used in advertising or publicity pertaining to
14distribution of the software without specific, written prior
15permission.
Guido van Rossumf70e43a1991-02-19 12:39:46 +000016
Guido van Rossumd266eb41996-10-25 14:44:06 +000017While CWI is the initial source for this software, a modified version
18is made available by the Corporation for National Research Initiatives
19(CNRI) at the Internet address ftp://ftp.python.org.
20
21STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28PERFORMANCE OF THIS SOFTWARE.
Guido van Rossumf70e43a1991-02-19 12:39:46 +000029
30******************************************************************/
31
Guido van Rossum3f5da241990-12-20 15:06:42 +000032/* Traceback implementation */
33
Guido van Rossum65bf9f21997-04-29 18:33:38 +000034#include "Python.h"
Guido van Rossum3f5da241990-12-20 15:06:42 +000035
36#include "compile.h"
37#include "frameobject.h"
Guido van Rossum3f5da241990-12-20 15:06:42 +000038#include "structmember.h"
Guido van Rossum7169dbb1992-02-26 15:17:59 +000039#include "osdefs.h"
Guido van Rossum3f5da241990-12-20 15:06:42 +000040
41typedef struct _tracebackobject {
Guido van Rossum65bf9f21997-04-29 18:33:38 +000042 PyObject_HEAD
Guido van Rossum3f5da241990-12-20 15:06:42 +000043 struct _tracebackobject *tb_next;
Guido van Rossum65bf9f21997-04-29 18:33:38 +000044 PyFrameObject *tb_frame;
Guido van Rossum3f5da241990-12-20 15:06:42 +000045 int tb_lasti;
46 int tb_lineno;
47} tracebackobject;
48
49#define OFF(x) offsetof(tracebackobject, x)
50
51static 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)},
56 {NULL} /* Sentinel */
57};
58
Guido van Rossum65bf9f21997-04-29 18:33:38 +000059static PyObject *
Guido van Rossum3f5da241990-12-20 15:06:42 +000060tb_getattr(tb, name)
61 tracebackobject *tb;
62 char *name;
63{
Guido van Rossum65bf9f21997-04-29 18:33:38 +000064 return PyMember_Get((char *)tb, tb_memberlist, name);
Guido van Rossum3f5da241990-12-20 15:06:42 +000065}
66
67static void
68tb_dealloc(tb)
69 tracebackobject *tb;
70{
Guido van Rossumd724b232000-03-13 16:01:29 +000071 Py_TRASHCAN_SAFE_BEGIN(tb)
Guido van Rossum65bf9f21997-04-29 18:33:38 +000072 Py_XDECREF(tb->tb_next);
73 Py_XDECREF(tb->tb_frame);
74 PyMem_DEL(tb);
Guido van Rossumd724b232000-03-13 16:01:29 +000075 Py_TRASHCAN_SAFE_END(tb)
Guido van Rossum3f5da241990-12-20 15:06:42 +000076}
77
Guido van Rossum9d78d8d1995-09-18 21:29:36 +000078#define Tracebacktype PyTraceBack_Type
79#define is_tracebackobject PyTraceBack_Check
Guido van Rossum681d79a1995-07-18 14:51:37 +000080
Guido van Rossum65bf9f21997-04-29 18:33:38 +000081PyTypeObject Tracebacktype = {
82 PyObject_HEAD_INIT(&PyType_Type)
Guido van Rossum3f5da241990-12-20 15:06:42 +000083 0,
84 "traceback",
85 sizeof(tracebackobject),
86 0,
Guido van Rossum13836d91994-08-29 12:09:58 +000087 (destructor)tb_dealloc, /*tp_dealloc*/
Guido van Rossum3f5da241990-12-20 15:06:42 +000088 0, /*tp_print*/
Guido van Rossum13836d91994-08-29 12:09:58 +000089 (getattrfunc)tb_getattr, /*tp_getattr*/
Guido van Rossum3f5da241990-12-20 15:06:42 +000090 0, /*tp_setattr*/
91 0, /*tp_compare*/
92 0, /*tp_repr*/
93 0, /*tp_as_number*/
94 0, /*tp_as_sequence*/
95 0, /*tp_as_mapping*/
96};
97
Guido van Rossum3f5da241990-12-20 15:06:42 +000098static tracebackobject *
99newtracebackobject(next, frame, lasti, lineno)
100 tracebackobject *next;
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000101 PyFrameObject *frame;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000102 int lasti, lineno;
103{
104 tracebackobject *tb;
105 if ((next != NULL && !is_tracebackobject(next)) ||
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000106 frame == NULL || !PyFrame_Check(frame)) {
107 PyErr_BadInternalCall();
Guido van Rossum3f5da241990-12-20 15:06:42 +0000108 return NULL;
109 }
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000110 tb = PyObject_NEW(tracebackobject, &Tracebacktype);
Guido van Rossum3f5da241990-12-20 15:06:42 +0000111 if (tb != NULL) {
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000112 Py_XINCREF(next);
Guido van Rossum3f5da241990-12-20 15:06:42 +0000113 tb->tb_next = next;
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000114 Py_XINCREF(frame);
Guido van Rossum3f5da241990-12-20 15:06:42 +0000115 tb->tb_frame = frame;
116 tb->tb_lasti = lasti;
117 tb->tb_lineno = lineno;
118 }
119 return tb;
120}
121
Guido van Rossum3f5da241990-12-20 15:06:42 +0000122int
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000123PyTraceBack_Here(frame)
124 PyFrameObject *frame;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000125{
Guido van Rossuma027efa1997-05-05 20:56:21 +0000126 PyThreadState *tstate = frame->f_tstate;
127 tracebackobject *oldtb = (tracebackobject *) tstate->curexc_traceback;
128 tracebackobject *tb = newtracebackobject(oldtb,
129 frame, frame->f_lasti, frame->f_lineno);
Guido van Rossum3f5da241990-12-20 15:06:42 +0000130 if (tb == NULL)
131 return -1;
Guido van Rossuma027efa1997-05-05 20:56:21 +0000132 tstate->curexc_traceback = (PyObject *)tb;
133 Py_XDECREF(oldtb);
Guido van Rossum3f5da241990-12-20 15:06:42 +0000134 return 0;
135}
136
Guido van Rossum7e8d26d1997-05-22 22:35:47 +0000137static int
Guido van Rossum13836d91994-08-29 12:09:58 +0000138tb_displayline(f, filename, lineno, name)
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000139 PyObject *f;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000140 char *filename;
141 int lineno;
Guido van Rossum13836d91994-08-29 12:09:58 +0000142 char *name;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000143{
Guido van Rossum7e8d26d1997-05-22 22:35:47 +0000144 int err = 0;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000145 FILE *xfp;
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000146 char linebuf[1000];
Guido van Rossum3f5da241990-12-20 15:06:42 +0000147 int i;
Guido van Rossum7e8d26d1997-05-22 22:35:47 +0000148 if (filename == NULL || name == NULL)
149 return -1;
Guido van Rossum13836d91994-08-29 12:09:58 +0000150#ifdef MPW
151 /* This is needed by MPW's File and Line commands */
152#define FMT " File \"%.900s\"; line %d # in %s\n"
153#else
154 /* This is needed by Emacs' compile command */
155#define FMT " File \"%.900s\", line %d, in %s\n"
156#endif
Guido van Rossum3f5da241990-12-20 15:06:42 +0000157 xfp = fopen(filename, "r");
158 if (xfp == NULL) {
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000159 /* Search tail of filename in sys.path before giving up */
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000160 PyObject *path;
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000161 char *tail = strrchr(filename, SEP);
162 if (tail == NULL)
163 tail = filename;
164 else
165 tail++;
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000166 path = PySys_GetObject("path");
167 if (path != NULL && PyList_Check(path)) {
168 int npath = PyList_Size(path);
Guido van Rossumbfd5d7551994-09-29 09:38:04 +0000169 int taillen = strlen(tail);
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000170 char namebuf[MAXPATHLEN+1];
171 for (i = 0; i < npath; i++) {
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000172 PyObject *v = PyList_GetItem(path, i);
Guido van Rossum7e8d26d1997-05-22 22:35:47 +0000173 if (v == NULL) {
174 PyErr_Clear();
175 break;
176 }
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000177 if (PyString_Check(v)) {
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000178 int len;
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000179 len = PyString_Size(v);
Guido van Rossumbfd5d7551994-09-29 09:38:04 +0000180 if (len + 1 + taillen >= MAXPATHLEN)
181 continue; /* Too long */
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000182 strcpy(namebuf, PyString_AsString(v));
Guido van Rossum6bf62da1997-04-11 20:37:35 +0000183 if ((int)strlen(namebuf) != len)
Guido van Rossumbfd5d7551994-09-29 09:38:04 +0000184 continue; /* v contains '\0' */
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000185 if (len > 0 && namebuf[len-1] != SEP)
186 namebuf[len++] = SEP;
187 strcpy(namebuf+len, tail);
188 xfp = fopen(namebuf, "r");
189 if (xfp != NULL) {
190 filename = namebuf;
191 break;
192 }
193 }
194 }
195 }
Guido van Rossum3f5da241990-12-20 15:06:42 +0000196 }
Guido van Rossum13836d91994-08-29 12:09:58 +0000197 sprintf(linebuf, FMT, filename, lineno, name);
Guido van Rossum7e8d26d1997-05-22 22:35:47 +0000198 err = PyFile_WriteString(linebuf, f);
199 if (xfp == NULL || err != 0)
200 return err;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000201 for (i = 0; i < lineno; i++) {
Guido van Rossum3aca6531999-09-18 20:49:39 +0000202 char* pLastChar = &linebuf[sizeof(linebuf)-2];
203 do {
204 *pLastChar = '\0';
205 if (fgets(linebuf, sizeof linebuf, xfp) == NULL)
206 break;
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');
Guido van Rossum3f5da241990-12-20 15:06:42 +0000213 }
214 if (i == lineno) {
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000215 char *p = linebuf;
Guido van Rossume78c5d01995-07-07 22:45:41 +0000216 while (*p == ' ' || *p == '\t' || *p == '\014')
Guido van Rossum3f5da241990-12-20 15:06:42 +0000217 p++;
Guido van Rossum7e8d26d1997-05-22 22:35:47 +0000218 err = PyFile_WriteString(" ", f);
219 if (err == 0) {
220 err = PyFile_WriteString(p, f);
221 if (err == 0 && strchr(p, '\n') == NULL)
222 err = PyFile_WriteString("\n", f);
223 }
Guido van Rossum3f5da241990-12-20 15:06:42 +0000224 }
225 fclose(xfp);
Guido van Rossum7e8d26d1997-05-22 22:35:47 +0000226 return err;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000227}
228
Guido van Rossum7e8d26d1997-05-22 22:35:47 +0000229static int
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000230tb_printinternal(tb, f, limit)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000231 tracebackobject *tb;
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000232 PyObject *f;
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000233 int limit;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000234{
Guido van Rossum7e8d26d1997-05-22 22:35:47 +0000235 int err = 0;
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000236 int depth = 0;
237 tracebackobject *tb1 = tb;
238 while (tb1 != NULL) {
239 depth++;
240 tb1 = tb1->tb_next;
241 }
Guido van Rossum7e8d26d1997-05-22 22:35:47 +0000242 while (tb != NULL && err == 0) {
Guido van Rossumb3f515a1997-01-24 04:02:55 +0000243 if (depth <= limit) {
Guido van Rossum73237c51997-05-05 20:53:25 +0000244 if (Py_OptimizeFlag)
245 tb->tb_lineno = PyCode_Addr2Line(
246 tb->tb_frame->f_code, tb->tb_lasti);
Guido van Rossum7e8d26d1997-05-22 22:35:47 +0000247 err = tb_displayline(f,
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000248 PyString_AsString(
249 tb->tb_frame->f_code->co_filename),
Guido van Rossum13836d91994-08-29 12:09:58 +0000250 tb->tb_lineno,
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000251 PyString_AsString(tb->tb_frame->f_code->co_name));
Guido van Rossumb3f515a1997-01-24 04:02:55 +0000252 }
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000253 depth--;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000254 tb = tb->tb_next;
Guido van Rossum7e8d26d1997-05-22 22:35:47 +0000255 if (err == 0)
256 err = PyErr_CheckSignals();
Guido van Rossum3f5da241990-12-20 15:06:42 +0000257 }
Guido van Rossum7e8d26d1997-05-22 22:35:47 +0000258 return err;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000259}
260
261int
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000262PyTraceBack_Print(v, f)
263 PyObject *v;
264 PyObject *f;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000265{
Guido van Rossum7e8d26d1997-05-22 22:35:47 +0000266 int err;
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000267 PyObject *limitv;
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000268 int limit = 1000;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000269 if (v == NULL)
270 return 0;
271 if (!is_tracebackobject(v)) {
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000272 PyErr_BadInternalCall();
Guido van Rossum3f5da241990-12-20 15:06:42 +0000273 return -1;
274 }
Guido van Rossum65bf9f21997-04-29 18:33:38 +0000275 limitv = PySys_GetObject("tracebacklimit");
276 if (limitv && PyInt_Check(limitv)) {
277 limit = PyInt_AsLong(limitv);
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000278 if (limit <= 0)
279 return 0;
280 }
Guido van Rossum6d108872000-03-31 00:39:23 +0000281 err = PyFile_WriteString("Traceback (most recent call last):\n", f);
Guido van Rossum7e8d26d1997-05-22 22:35:47 +0000282 if (!err)
283 err = tb_printinternal((tracebackobject *)v, f, limit);
284 return err;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000285}