blob: 57502a148c0ecd960c60bc11c4189af8024e9240 [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
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
24
Guido van Rossum3f5da241990-12-20 15:06:42 +000025/* Traceback implementation */
26
27#include "allobjects.h"
28
Guido van Rossum7169dbb1992-02-26 15:17:59 +000029#include "sysmodule.h"
Guido van Rossum3f5da241990-12-20 15:06:42 +000030#include "compile.h"
31#include "frameobject.h"
32#include "traceback.h"
33#include "structmember.h"
Guido van Rossum7169dbb1992-02-26 15:17:59 +000034#include "osdefs.h"
Guido van Rossum3f5da241990-12-20 15:06:42 +000035
36typedef struct _tracebackobject {
37 OB_HEAD
38 struct _tracebackobject *tb_next;
39 frameobject *tb_frame;
40 int tb_lasti;
41 int tb_lineno;
42} tracebackobject;
43
44#define OFF(x) offsetof(tracebackobject, x)
45
46static struct memberlist tb_memberlist[] = {
47 {"tb_next", T_OBJECT, OFF(tb_next)},
48 {"tb_frame", T_OBJECT, OFF(tb_frame)},
49 {"tb_lasti", T_INT, OFF(tb_lasti)},
50 {"tb_lineno", T_INT, OFF(tb_lineno)},
51 {NULL} /* Sentinel */
52};
53
54static object *
55tb_getattr(tb, name)
56 tracebackobject *tb;
57 char *name;
58{
59 return getmember((char *)tb, tb_memberlist, name);
60}
61
62static void
63tb_dealloc(tb)
64 tracebackobject *tb;
65{
66 XDECREF(tb->tb_next);
67 XDECREF(tb->tb_frame);
68 DEL(tb);
69}
70
Guido van Rossum9d78d8d1995-09-18 21:29:36 +000071#define Tracebacktype PyTraceBack_Type
72#define is_tracebackobject PyTraceBack_Check
Guido van Rossum681d79a1995-07-18 14:51:37 +000073
74typeobject Tracebacktype = {
Guido van Rossum3f5da241990-12-20 15:06:42 +000075 OB_HEAD_INIT(&Typetype)
76 0,
77 "traceback",
78 sizeof(tracebackobject),
79 0,
Guido van Rossum13836d91994-08-29 12:09:58 +000080 (destructor)tb_dealloc, /*tp_dealloc*/
Guido van Rossum3f5da241990-12-20 15:06:42 +000081 0, /*tp_print*/
Guido van Rossum13836d91994-08-29 12:09:58 +000082 (getattrfunc)tb_getattr, /*tp_getattr*/
Guido van Rossum3f5da241990-12-20 15:06:42 +000083 0, /*tp_setattr*/
84 0, /*tp_compare*/
85 0, /*tp_repr*/
86 0, /*tp_as_number*/
87 0, /*tp_as_sequence*/
88 0, /*tp_as_mapping*/
89};
90
Guido van Rossum3f5da241990-12-20 15:06:42 +000091static tracebackobject *
92newtracebackobject(next, frame, lasti, lineno)
93 tracebackobject *next;
94 frameobject *frame;
95 int lasti, lineno;
96{
97 tracebackobject *tb;
98 if ((next != NULL && !is_tracebackobject(next)) ||
99 frame == NULL || !is_frameobject(frame)) {
100 err_badcall();
101 return NULL;
102 }
103 tb = NEWOBJ(tracebackobject, &Tracebacktype);
104 if (tb != NULL) {
105 XINCREF(next);
106 tb->tb_next = next;
107 XINCREF(frame);
108 tb->tb_frame = frame;
109 tb->tb_lasti = lasti;
110 tb->tb_lineno = lineno;
111 }
112 return tb;
113}
114
115static tracebackobject *tb_current = NULL;
116
117int
Guido van Rossumc6515d11992-01-14 18:44:48 +0000118tb_here(frame)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000119 frameobject *frame;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000120{
121 tracebackobject *tb;
Guido van Rossumc6515d11992-01-14 18:44:48 +0000122 tb = newtracebackobject(tb_current, frame, frame->f_lasti, frame->f_lineno);
Guido van Rossum3f5da241990-12-20 15:06:42 +0000123 if (tb == NULL)
124 return -1;
125 XDECREF(tb_current);
126 tb_current = tb;
127 return 0;
128}
129
130object *
131tb_fetch()
132{
133 object *v;
134 v = (object *)tb_current;
135 tb_current = NULL;
136 return v;
137}
138
139int
140tb_store(v)
141 object *v;
142{
143 if (v != NULL && !is_tracebackobject(v)) {
144 err_badcall();
145 return -1;
146 }
147 XDECREF(tb_current);
148 XINCREF(v);
149 tb_current = (tracebackobject *)v;
150 return 0;
151}
152
153static void
Guido van Rossum13836d91994-08-29 12:09:58 +0000154tb_displayline(f, filename, lineno, name)
Guido van Rossum3165fe61992-09-25 21:59:05 +0000155 object *f;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000156 char *filename;
157 int lineno;
Guido van Rossum13836d91994-08-29 12:09:58 +0000158 char *name;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000159{
160 FILE *xfp;
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000161 char linebuf[1000];
Guido van Rossum3f5da241990-12-20 15:06:42 +0000162 int i;
Guido van Rossum13836d91994-08-29 12:09:58 +0000163#ifdef MPW
164 /* This is needed by MPW's File and Line commands */
165#define FMT " File \"%.900s\"; line %d # in %s\n"
166#else
167 /* This is needed by Emacs' compile command */
168#define FMT " File \"%.900s\", line %d, in %s\n"
169#endif
Guido van Rossum3f5da241990-12-20 15:06:42 +0000170 xfp = fopen(filename, "r");
171 if (xfp == NULL) {
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000172 /* Search tail of filename in sys.path before giving up */
173 object *path;
174 char *tail = strrchr(filename, SEP);
175 if (tail == NULL)
176 tail = filename;
177 else
178 tail++;
179 path = sysget("path");
180 if (path != NULL && is_listobject(path)) {
181 int npath = getlistsize(path);
Guido van Rossumbfd5d7551994-09-29 09:38:04 +0000182 int taillen = strlen(tail);
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000183 char namebuf[MAXPATHLEN+1];
184 for (i = 0; i < npath; i++) {
185 object *v = getlistitem(path, i);
186 if (is_stringobject(v)) {
187 int len;
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000188 len = getstringsize(v);
Guido van Rossumbfd5d7551994-09-29 09:38:04 +0000189 if (len + 1 + taillen >= MAXPATHLEN)
190 continue; /* Too long */
191 strcpy(namebuf, getstringvalue(v));
192 if (strlen(namebuf) != len)
193 continue; /* v contains '\0' */
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000194 if (len > 0 && namebuf[len-1] != SEP)
195 namebuf[len++] = SEP;
196 strcpy(namebuf+len, tail);
197 xfp = fopen(namebuf, "r");
198 if (xfp != NULL) {
199 filename = namebuf;
200 break;
201 }
202 }
203 }
204 }
Guido van Rossum3f5da241990-12-20 15:06:42 +0000205 }
Guido van Rossum13836d91994-08-29 12:09:58 +0000206 sprintf(linebuf, FMT, filename, lineno, name);
Guido van Rossum3165fe61992-09-25 21:59:05 +0000207 writestring(linebuf, f);
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000208 if (xfp == NULL)
209 return;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000210 for (i = 0; i < lineno; i++) {
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000211 if (fgets(linebuf, sizeof linebuf, xfp) == NULL)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000212 break;
213 }
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 Rossum3165fe61992-09-25 21:59:05 +0000218 writestring(" ", f);
219 writestring(p, f);
Guido van Rossum3f5da241990-12-20 15:06:42 +0000220 if (strchr(p, '\n') == NULL)
Guido van Rossum3165fe61992-09-25 21:59:05 +0000221 writestring("\n", f);
Guido van Rossum3f5da241990-12-20 15:06:42 +0000222 }
223 fclose(xfp);
224}
225
226static void
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000227tb_printinternal(tb, f, limit)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000228 tracebackobject *tb;
Guido van Rossum3165fe61992-09-25 21:59:05 +0000229 object *f;
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000230 int limit;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000231{
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000232 int depth = 0;
233 tracebackobject *tb1 = tb;
234 while (tb1 != NULL) {
235 depth++;
236 tb1 = tb1->tb_next;
237 }
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000238 while (tb != NULL && !intrcheck()) {
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000239 if (depth <= limit)
240 tb_displayline(f,
241 getstringvalue(tb->tb_frame->f_code->co_filename),
Guido van Rossum13836d91994-08-29 12:09:58 +0000242 tb->tb_lineno,
243 getstringvalue(tb->tb_frame->f_code->co_name));
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000244 depth--;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000245 tb = tb->tb_next;
246 }
247}
248
249int
Guido van Rossum3165fe61992-09-25 21:59:05 +0000250tb_print(v, f)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000251 object *v;
Guido van Rossum3165fe61992-09-25 21:59:05 +0000252 object *f;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000253{
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000254 object *limitv;
255 int limit = 1000;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000256 if (v == NULL)
257 return 0;
258 if (!is_tracebackobject(v)) {
259 err_badcall();
260 return -1;
261 }
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000262 limitv = sysget("tracebacklimit");
263 if (limitv && is_intobject(limitv)) {
264 limit = getintvalue(limitv);
265 if (limit <= 0)
266 return 0;
267 }
268 writestring("Traceback (innermost last):\n", f);
269 tb_printinternal((tracebackobject *)v, f, limit);
Guido van Rossum3f5da241990-12-20 15:06:42 +0000270 return 0;
271}