This commit was manufactured by cvs2svn to create tag 'r16a1'.
[python/dscho.git] / Python / traceback.c
blobe1148cd26284adccf162d18a9565e9b706e3c0d1
1 /***********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3 The Netherlands.
5 All Rights Reserved
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
15 permission.
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 */
34 #include "Python.h"
36 #include "compile.h"
37 #include "frameobject.h"
38 #include "structmember.h"
39 #include "osdefs.h"
41 typedef struct _tracebackobject {
42 PyObject_HEAD
43 struct _tracebackobject *tb_next;
44 PyFrameObject *tb_frame;
45 int tb_lasti;
46 int tb_lineno;
47 } tracebackobject;
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)},
56 {NULL} /* Sentinel */
59 static PyObject *
60 tb_getattr(tb, name)
61 tracebackobject *tb;
62 char *name;
64 return PyMember_Get((char *)tb, tb_memberlist, name);
67 static void
68 tb_dealloc(tb)
69 tracebackobject *tb;
71 Py_TRASHCAN_SAFE_BEGIN(tb)
72 Py_XDECREF(tb->tb_next);
73 Py_XDECREF(tb->tb_frame);
74 PyMem_DEL(tb);
75 Py_TRASHCAN_SAFE_END(tb)
78 #define Tracebacktype PyTraceBack_Type
79 #define is_tracebackobject PyTraceBack_Check
81 PyTypeObject Tracebacktype = {
82 PyObject_HEAD_INIT(&PyType_Type)
84 "traceback",
85 sizeof(tracebackobject),
87 (destructor)tb_dealloc, /*tp_dealloc*/
88 0, /*tp_print*/
89 (getattrfunc)tb_getattr, /*tp_getattr*/
90 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*/
98 static tracebackobject *
99 newtracebackobject(next, frame, lasti, lineno)
100 tracebackobject *next;
101 PyFrameObject *frame;
102 int lasti, lineno;
104 tracebackobject *tb;
105 if ((next != NULL && !is_tracebackobject(next)) ||
106 frame == NULL || !PyFrame_Check(frame)) {
107 PyErr_BadInternalCall();
108 return NULL;
110 tb = PyObject_NEW(tracebackobject, &Tracebacktype);
111 if (tb != NULL) {
112 Py_XINCREF(next);
113 tb->tb_next = next;
114 Py_XINCREF(frame);
115 tb->tb_frame = frame;
116 tb->tb_lasti = lasti;
117 tb->tb_lineno = lineno;
119 return tb;
123 PyTraceBack_Here(frame)
124 PyFrameObject *frame;
126 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);
130 if (tb == NULL)
131 return -1;
132 tstate->curexc_traceback = (PyObject *)tb;
133 Py_XDECREF(oldtb);
134 return 0;
137 static int
138 tb_displayline(f, filename, lineno, name)
139 PyObject *f;
140 char *filename;
141 int lineno;
142 char *name;
144 int err = 0;
145 FILE *xfp;
146 char linebuf[1000];
147 int i;
148 if (filename == NULL || name == NULL)
149 return -1;
150 #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
157 xfp = fopen(filename, "r");
158 if (xfp == NULL) {
159 /* Search tail of filename in sys.path before giving up */
160 PyObject *path;
161 char *tail = strrchr(filename, SEP);
162 if (tail == NULL)
163 tail = filename;
164 else
165 tail++;
166 path = PySys_GetObject("path");
167 if (path != NULL && PyList_Check(path)) {
168 int npath = PyList_Size(path);
169 int taillen = strlen(tail);
170 char namebuf[MAXPATHLEN+1];
171 for (i = 0; i < npath; i++) {
172 PyObject *v = PyList_GetItem(path, i);
173 if (v == NULL) {
174 PyErr_Clear();
175 break;
177 if (PyString_Check(v)) {
178 int len;
179 len = PyString_Size(v);
180 if (len + 1 + taillen >= MAXPATHLEN)
181 continue; /* Too long */
182 strcpy(namebuf, PyString_AsString(v));
183 if ((int)strlen(namebuf) != len)
184 continue; /* v contains '\0' */
185 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;
197 sprintf(linebuf, FMT, filename, lineno, name);
198 err = PyFile_WriteString(linebuf, f);
199 if (xfp == NULL || err != 0)
200 return err;
201 for (i = 0; i < lineno; i++) {
202 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');
214 if (i == lineno) {
215 char *p = linebuf;
216 while (*p == ' ' || *p == '\t' || *p == '\014')
217 p++;
218 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);
225 fclose(xfp);
226 return err;
229 static int
230 tb_printinternal(tb, f, limit)
231 tracebackobject *tb;
232 PyObject *f;
233 int limit;
235 int err = 0;
236 int depth = 0;
237 tracebackobject *tb1 = tb;
238 while (tb1 != NULL) {
239 depth++;
240 tb1 = tb1->tb_next;
242 while (tb != NULL && err == 0) {
243 if (depth <= limit) {
244 if (Py_OptimizeFlag)
245 tb->tb_lineno = PyCode_Addr2Line(
246 tb->tb_frame->f_code, tb->tb_lasti);
247 err = tb_displayline(f,
248 PyString_AsString(
249 tb->tb_frame->f_code->co_filename),
250 tb->tb_lineno,
251 PyString_AsString(tb->tb_frame->f_code->co_name));
253 depth--;
254 tb = tb->tb_next;
255 if (err == 0)
256 err = PyErr_CheckSignals();
258 return err;
262 PyTraceBack_Print(v, f)
263 PyObject *v;
264 PyObject *f;
266 int err;
267 PyObject *limitv;
268 int limit = 1000;
269 if (v == NULL)
270 return 0;
271 if (!is_tracebackobject(v)) {
272 PyErr_BadInternalCall();
273 return -1;
275 limitv = PySys_GetObject("tracebacklimit");
276 if (limitv && PyInt_Check(limitv)) {
277 limit = PyInt_AsLong(limitv);
278 if (limit <= 0)
279 return 0;
281 err = PyFile_WriteString("Traceback (most recent call last):\n", f);
282 if (!err)
283 err = tb_printinternal((tracebackobject *)v, f, limit);
284 return err;