Added 'description' class attribute to every command class (to help the
[python/dscho.git] / Python / traceback.c
blobca77eaa62a69cad4edfffb64243b1e30aad38aae
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_XDECREF(tb->tb_next);
72 Py_XDECREF(tb->tb_frame);
73 PyMem_DEL(tb);
76 #define Tracebacktype PyTraceBack_Type
77 #define is_tracebackobject PyTraceBack_Check
79 PyTypeObject Tracebacktype = {
80 PyObject_HEAD_INIT(&PyType_Type)
82 "traceback",
83 sizeof(tracebackobject),
85 (destructor)tb_dealloc, /*tp_dealloc*/
86 0, /*tp_print*/
87 (getattrfunc)tb_getattr, /*tp_getattr*/
88 0, /*tp_setattr*/
89 0, /*tp_compare*/
90 0, /*tp_repr*/
91 0, /*tp_as_number*/
92 0, /*tp_as_sequence*/
93 0, /*tp_as_mapping*/
96 static tracebackobject *
97 newtracebackobject(next, frame, lasti, lineno)
98 tracebackobject *next;
99 PyFrameObject *frame;
100 int lasti, lineno;
102 tracebackobject *tb;
103 if ((next != NULL && !is_tracebackobject(next)) ||
104 frame == NULL || !PyFrame_Check(frame)) {
105 PyErr_BadInternalCall();
106 return NULL;
108 tb = PyObject_NEW(tracebackobject, &Tracebacktype);
109 if (tb != NULL) {
110 Py_XINCREF(next);
111 tb->tb_next = next;
112 Py_XINCREF(frame);
113 tb->tb_frame = frame;
114 tb->tb_lasti = lasti;
115 tb->tb_lineno = lineno;
117 return tb;
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);
128 if (tb == NULL)
129 return -1;
130 tstate->curexc_traceback = (PyObject *)tb;
131 Py_XDECREF(oldtb);
132 return 0;
135 static int
136 tb_displayline(f, filename, lineno, name)
137 PyObject *f;
138 char *filename;
139 int lineno;
140 char *name;
142 int err = 0;
143 FILE *xfp;
144 char linebuf[1000];
145 int i;
146 if (filename == NULL || name == NULL)
147 return -1;
148 #ifdef MPW
149 /* This is needed by MPW's File and Line commands */
150 #define FMT " File \"%.900s\"; line %d # in %s\n"
151 #else
152 /* This is needed by Emacs' compile command */
153 #define FMT " File \"%.900s\", line %d, in %s\n"
154 #endif
155 xfp = fopen(filename, "r");
156 if (xfp == NULL) {
157 /* Search tail of filename in sys.path before giving up */
158 PyObject *path;
159 char *tail = strrchr(filename, SEP);
160 if (tail == NULL)
161 tail = filename;
162 else
163 tail++;
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);
171 if (v == NULL) {
172 PyErr_Clear();
173 break;
175 if (PyString_Check(v)) {
176 int len;
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");
187 if (xfp != NULL) {
188 filename = namebuf;
189 break;
195 sprintf(linebuf, FMT, filename, lineno, name);
196 err = PyFile_WriteString(linebuf, f);
197 if (xfp == NULL || err != 0)
198 return err;
199 for (i = 0; i < lineno; i++) {
200 char* pLastChar = &linebuf[sizeof(linebuf)-2];
201 do {
202 *pLastChar = '\0';
203 if (fgets(linebuf, sizeof linebuf, xfp) == NULL)
204 break;
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');
212 if (i == lineno) {
213 char *p = linebuf;
214 while (*p == ' ' || *p == '\t' || *p == '\014')
215 p++;
216 err = PyFile_WriteString(" ", f);
217 if (err == 0) {
218 err = PyFile_WriteString(p, f);
219 if (err == 0 && strchr(p, '\n') == NULL)
220 err = PyFile_WriteString("\n", f);
223 fclose(xfp);
224 return err;
227 static int
228 tb_printinternal(tb, f, limit)
229 tracebackobject *tb;
230 PyObject *f;
231 int limit;
233 int err = 0;
234 int depth = 0;
235 tracebackobject *tb1 = tb;
236 while (tb1 != NULL) {
237 depth++;
238 tb1 = tb1->tb_next;
240 while (tb != NULL && err == 0) {
241 if (depth <= limit) {
242 if (Py_OptimizeFlag)
243 tb->tb_lineno = PyCode_Addr2Line(
244 tb->tb_frame->f_code, tb->tb_lasti);
245 err = tb_displayline(f,
246 PyString_AsString(
247 tb->tb_frame->f_code->co_filename),
248 tb->tb_lineno,
249 PyString_AsString(tb->tb_frame->f_code->co_name));
251 depth--;
252 tb = tb->tb_next;
253 if (err == 0)
254 err = PyErr_CheckSignals();
256 return err;
260 PyTraceBack_Print(v, f)
261 PyObject *v;
262 PyObject *f;
264 int err;
265 PyObject *limitv;
266 int limit = 1000;
267 if (v == NULL)
268 return 0;
269 if (!is_tracebackobject(v)) {
270 PyErr_BadInternalCall();
271 return -1;
273 limitv = PySys_GetObject("tracebacklimit");
274 if (limitv && PyInt_Check(limitv)) {
275 limit = PyInt_AsLong(limitv);
276 if (limit <= 0)
277 return 0;
279 err = PyFile_WriteString("Traceback (innermost last):\n", f);
280 if (!err)
281 err = tb_printinternal((tracebackobject *)v, f, limit);
282 return err;