blob: bea0b19b57e7608d389474f8e1342603b3d30590 [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
71static typeobject Tracebacktype = {
72 OB_HEAD_INIT(&Typetype)
73 0,
74 "traceback",
75 sizeof(tracebackobject),
76 0,
Guido van Rossum13836d91994-08-29 12:09:58 +000077 (destructor)tb_dealloc, /*tp_dealloc*/
Guido van Rossum3f5da241990-12-20 15:06:42 +000078 0, /*tp_print*/
Guido van Rossum13836d91994-08-29 12:09:58 +000079 (getattrfunc)tb_getattr, /*tp_getattr*/
Guido van Rossum3f5da241990-12-20 15:06:42 +000080 0, /*tp_setattr*/
81 0, /*tp_compare*/
82 0, /*tp_repr*/
83 0, /*tp_as_number*/
84 0, /*tp_as_sequence*/
85 0, /*tp_as_mapping*/
86};
87
88#define is_tracebackobject(v) ((v)->ob_type == &Tracebacktype)
89
90static tracebackobject *
91newtracebackobject(next, frame, lasti, lineno)
92 tracebackobject *next;
93 frameobject *frame;
94 int lasti, lineno;
95{
96 tracebackobject *tb;
97 if ((next != NULL && !is_tracebackobject(next)) ||
98 frame == NULL || !is_frameobject(frame)) {
99 err_badcall();
100 return NULL;
101 }
102 tb = NEWOBJ(tracebackobject, &Tracebacktype);
103 if (tb != NULL) {
104 XINCREF(next);
105 tb->tb_next = next;
106 XINCREF(frame);
107 tb->tb_frame = frame;
108 tb->tb_lasti = lasti;
109 tb->tb_lineno = lineno;
110 }
111 return tb;
112}
113
114static tracebackobject *tb_current = NULL;
115
116int
Guido van Rossumc6515d11992-01-14 18:44:48 +0000117tb_here(frame)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000118 frameobject *frame;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000119{
120 tracebackobject *tb;
Guido van Rossumc6515d11992-01-14 18:44:48 +0000121 tb = newtracebackobject(tb_current, frame, frame->f_lasti, frame->f_lineno);
Guido van Rossum3f5da241990-12-20 15:06:42 +0000122 if (tb == NULL)
123 return -1;
124 XDECREF(tb_current);
125 tb_current = tb;
126 return 0;
127}
128
129object *
130tb_fetch()
131{
132 object *v;
133 v = (object *)tb_current;
134 tb_current = NULL;
135 return v;
136}
137
138int
139tb_store(v)
140 object *v;
141{
142 if (v != NULL && !is_tracebackobject(v)) {
143 err_badcall();
144 return -1;
145 }
146 XDECREF(tb_current);
147 XINCREF(v);
148 tb_current = (tracebackobject *)v;
149 return 0;
150}
151
152static void
Guido van Rossum13836d91994-08-29 12:09:58 +0000153tb_displayline(f, filename, lineno, name)
Guido van Rossum3165fe61992-09-25 21:59:05 +0000154 object *f;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000155 char *filename;
156 int lineno;
Guido van Rossum13836d91994-08-29 12:09:58 +0000157 char *name;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000158{
159 FILE *xfp;
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000160 char linebuf[1000];
Guido van Rossum3f5da241990-12-20 15:06:42 +0000161 int i;
Guido van Rossum13836d91994-08-29 12:09:58 +0000162#ifdef MPW
163 /* This is needed by MPW's File and Line commands */
164#define FMT " File \"%.900s\"; line %d # in %s\n"
165#else
166 /* This is needed by Emacs' compile command */
167#define FMT " File \"%.900s\", line %d, in %s\n"
168#endif
Guido van Rossum3f5da241990-12-20 15:06:42 +0000169 xfp = fopen(filename, "r");
170 if (xfp == NULL) {
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000171 /* Search tail of filename in sys.path before giving up */
172 object *path;
173 char *tail = strrchr(filename, SEP);
174 if (tail == NULL)
175 tail = filename;
176 else
177 tail++;
178 path = sysget("path");
179 if (path != NULL && is_listobject(path)) {
180 int npath = getlistsize(path);
Guido van Rossumbfd5d7551994-09-29 09:38:04 +0000181 int taillen = strlen(tail);
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000182 char namebuf[MAXPATHLEN+1];
183 for (i = 0; i < npath; i++) {
184 object *v = getlistitem(path, i);
185 if (is_stringobject(v)) {
186 int len;
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000187 len = getstringsize(v);
Guido van Rossumbfd5d7551994-09-29 09:38:04 +0000188 if (len + 1 + taillen >= MAXPATHLEN)
189 continue; /* Too long */
190 strcpy(namebuf, getstringvalue(v));
191 if (strlen(namebuf) != len)
192 continue; /* v contains '\0' */
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000193 if (len > 0 && namebuf[len-1] != SEP)
194 namebuf[len++] = SEP;
195 strcpy(namebuf+len, tail);
196 xfp = fopen(namebuf, "r");
197 if (xfp != NULL) {
198 filename = namebuf;
199 break;
200 }
201 }
202 }
203 }
Guido van Rossum3f5da241990-12-20 15:06:42 +0000204 }
Guido van Rossum13836d91994-08-29 12:09:58 +0000205 sprintf(linebuf, FMT, filename, lineno, name);
Guido van Rossum3165fe61992-09-25 21:59:05 +0000206 writestring(linebuf, f);
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000207 if (xfp == NULL)
208 return;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000209 for (i = 0; i < lineno; i++) {
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000210 if (fgets(linebuf, sizeof linebuf, xfp) == NULL)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000211 break;
212 }
213 if (i == lineno) {
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000214 char *p = linebuf;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000215 while (*p == ' ' || *p == '\t')
216 p++;
Guido van Rossum3165fe61992-09-25 21:59:05 +0000217 writestring(" ", f);
218 writestring(p, f);
Guido van Rossum3f5da241990-12-20 15:06:42 +0000219 if (strchr(p, '\n') == NULL)
Guido van Rossum3165fe61992-09-25 21:59:05 +0000220 writestring("\n", f);
Guido van Rossum3f5da241990-12-20 15:06:42 +0000221 }
222 fclose(xfp);
223}
224
225static void
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000226tb_printinternal(tb, f, limit)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000227 tracebackobject *tb;
Guido van Rossum3165fe61992-09-25 21:59:05 +0000228 object *f;
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000229 int limit;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000230{
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000231 int depth = 0;
232 tracebackobject *tb1 = tb;
233 while (tb1 != NULL) {
234 depth++;
235 tb1 = tb1->tb_next;
236 }
Guido van Rossum7169dbb1992-02-26 15:17:59 +0000237 while (tb != NULL && !intrcheck()) {
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000238 if (depth <= limit)
239 tb_displayline(f,
240 getstringvalue(tb->tb_frame->f_code->co_filename),
Guido van Rossum13836d91994-08-29 12:09:58 +0000241 tb->tb_lineno,
242 getstringvalue(tb->tb_frame->f_code->co_name));
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000243 depth--;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000244 tb = tb->tb_next;
245 }
246}
247
248int
Guido van Rossum3165fe61992-09-25 21:59:05 +0000249tb_print(v, f)
Guido van Rossum3f5da241990-12-20 15:06:42 +0000250 object *v;
Guido van Rossum3165fe61992-09-25 21:59:05 +0000251 object *f;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000252{
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000253 object *limitv;
254 int limit = 1000;
Guido van Rossum3f5da241990-12-20 15:06:42 +0000255 if (v == NULL)
256 return 0;
257 if (!is_tracebackobject(v)) {
258 err_badcall();
259 return -1;
260 }
Guido van Rossum67a5fdb1993-12-17 12:09:14 +0000261 limitv = sysget("tracebacklimit");
262 if (limitv && is_intobject(limitv)) {
263 limit = getintvalue(limitv);
264 if (limit <= 0)
265 return 0;
266 }
267 writestring("Traceback (innermost last):\n", f);
268 tb_printinternal((tracebackobject *)v, f, limit);
Guido van Rossum3f5da241990-12-20 15:06:42 +0000269 return 0;
270}