Improved some error messages for command line processing.
[python/dscho.git] / Python / traceback.c
blob53b84f307ea3e45e9220f582a414d618cc96255a
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 if (fgets(linebuf, sizeof linebuf, xfp) == NULL)
201 break;
203 if (i == lineno) {
204 char *p = linebuf;
205 while (*p == ' ' || *p == '\t' || *p == '\014')
206 p++;
207 err = PyFile_WriteString(" ", f);
208 if (err == 0) {
209 err = PyFile_WriteString(p, f);
210 if (err == 0 && strchr(p, '\n') == NULL)
211 err = PyFile_WriteString("\n", f);
214 fclose(xfp);
215 return err;
218 static int
219 tb_printinternal(tb, f, limit)
220 tracebackobject *tb;
221 PyObject *f;
222 int limit;
224 int err = 0;
225 int depth = 0;
226 tracebackobject *tb1 = tb;
227 while (tb1 != NULL) {
228 depth++;
229 tb1 = tb1->tb_next;
231 while (tb != NULL && err == 0) {
232 if (depth <= limit) {
233 if (Py_OptimizeFlag)
234 tb->tb_lineno = PyCode_Addr2Line(
235 tb->tb_frame->f_code, tb->tb_lasti);
236 err = tb_displayline(f,
237 PyString_AsString(
238 tb->tb_frame->f_code->co_filename),
239 tb->tb_lineno,
240 PyString_AsString(tb->tb_frame->f_code->co_name));
242 depth--;
243 tb = tb->tb_next;
244 if (err == 0)
245 err = PyErr_CheckSignals();
247 return err;
251 PyTraceBack_Print(v, f)
252 PyObject *v;
253 PyObject *f;
255 int err;
256 PyObject *limitv;
257 int limit = 1000;
258 if (v == NULL)
259 return 0;
260 if (!is_tracebackobject(v)) {
261 PyErr_BadInternalCall();
262 return -1;
264 limitv = PySys_GetObject("tracebacklimit");
265 if (limitv && PyInt_Check(limitv)) {
266 limit = PyInt_AsLong(limitv);
267 if (limit <= 0)
268 return 0;
270 err = PyFile_WriteString("Traceback (innermost last):\n", f);
271 if (!err)
272 err = tb_printinternal((tracebackobject *)v, f, limit);
273 return err;