summaryrefslogtreecommitdiffstats
path: root/Python/traceback.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/traceback.c')
-rw-r--r--Python/traceback.c193
1 files changed, 193 insertions, 0 deletions
diff --git a/Python/traceback.c b/Python/traceback.c
new file mode 100644
index 0000000..f32dcf6
--- /dev/null
+++ b/Python/traceback.c
@@ -0,0 +1,193 @@
+/* Traceback implementation */
+
+#include "allobjects.h"
+
+#include "compile.h"
+#include "frameobject.h"
+#include "traceback.h"
+#include "structmember.h"
+
+typedef struct _tracebackobject {
+ OB_HEAD
+ struct _tracebackobject *tb_next;
+ frameobject *tb_frame;
+ int tb_lasti;
+ int tb_lineno;
+} tracebackobject;
+
+#define OFF(x) offsetof(tracebackobject, x)
+
+static struct memberlist tb_memberlist[] = {
+ {"tb_next", T_OBJECT, OFF(tb_next)},
+ {"tb_frame", T_OBJECT, OFF(tb_frame)},
+ {"tb_lasti", T_INT, OFF(tb_lasti)},
+ {"tb_lineno", T_INT, OFF(tb_lineno)},
+ {NULL} /* Sentinel */
+};
+
+static object *
+tb_getattr(tb, name)
+ tracebackobject *tb;
+ char *name;
+{
+ return getmember((char *)tb, tb_memberlist, name);
+}
+
+static void
+tb_dealloc(tb)
+ tracebackobject *tb;
+{
+ XDECREF(tb->tb_next);
+ XDECREF(tb->tb_frame);
+ DEL(tb);
+}
+
+static typeobject Tracebacktype = {
+ OB_HEAD_INIT(&Typetype)
+ 0,
+ "traceback",
+ sizeof(tracebackobject),
+ 0,
+ tb_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ tb_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+};
+
+#define is_tracebackobject(v) ((v)->ob_type == &Tracebacktype)
+
+static tracebackobject *
+newtracebackobject(next, frame, lasti, lineno)
+ tracebackobject *next;
+ frameobject *frame;
+ int lasti, lineno;
+{
+ tracebackobject *tb;
+ if ((next != NULL && !is_tracebackobject(next)) ||
+ frame == NULL || !is_frameobject(frame)) {
+ err_badcall();
+ return NULL;
+ }
+ tb = NEWOBJ(tracebackobject, &Tracebacktype);
+ if (tb != NULL) {
+ XINCREF(next);
+ tb->tb_next = next;
+ XINCREF(frame);
+ tb->tb_frame = frame;
+ tb->tb_lasti = lasti;
+ tb->tb_lineno = lineno;
+ }
+ return tb;
+}
+
+static tracebackobject *tb_current = NULL;
+
+int
+tb_here(frame, lasti, lineno)
+ frameobject *frame;
+ int lasti;
+ int lineno;
+{
+ tracebackobject *tb;
+ tb = newtracebackobject(tb_current, frame, lasti, lineno);
+ if (tb == NULL)
+ return -1;
+ XDECREF(tb_current);
+ tb_current = tb;
+ return 0;
+}
+
+object *
+tb_fetch()
+{
+ object *v;
+ v = (object *)tb_current;
+ tb_current = NULL;
+ return v;
+}
+
+int
+tb_store(v)
+ object *v;
+{
+ if (v != NULL && !is_tracebackobject(v)) {
+ err_badcall();
+ return -1;
+ }
+ XDECREF(tb_current);
+ XINCREF(v);
+ tb_current = (tracebackobject *)v;
+ return 0;
+}
+
+static void
+tb_displayline(fp, filename, lineno)
+ FILE *fp;
+ char *filename;
+ int lineno;
+{
+ FILE *xfp;
+ char buf[1000];
+ int i;
+ if (filename[0] == '<' && filename[strlen(filename)-1] == '>')
+ return;
+ xfp = fopen(filename, "r");
+ if (xfp == NULL) {
+ fprintf(fp, " (cannot open \"%s\")\n", filename);
+ return;
+ }
+ for (i = 0; i < lineno; i++) {
+ if (fgets(buf, sizeof buf, xfp) == NULL)
+ break;
+ }
+ if (i == lineno) {
+ char *p = buf;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ fprintf(fp, " %s", p);
+ if (strchr(p, '\n') == NULL)
+ fprintf(fp, "\n");
+ }
+ fclose(xfp);
+}
+
+static void
+tb_printinternal(tb, fp)
+ tracebackobject *tb;
+ FILE *fp;
+{
+ while (tb != NULL) {
+ if (intrcheck()) {
+ fprintf(fp, "[interrupted]\n");
+ break;
+ }
+ fprintf(fp, " File \"");
+ printobject(tb->tb_frame->f_code->co_filename, fp, PRINT_RAW);
+ fprintf(fp, "\", line %d\n", tb->tb_lineno);
+ tb_displayline(fp,
+ getstringvalue(tb->tb_frame->f_code->co_filename),
+ tb->tb_lineno);
+ tb = tb->tb_next;
+ }
+}
+
+int
+tb_print(v, fp)
+ object *v;
+ FILE *fp;
+{
+ if (v == NULL)
+ return 0;
+ if (!is_tracebackobject(v)) {
+ err_badcall();
+ return -1;
+ }
+ sysset("last_traceback", v);
+ tb_printinternal((tracebackobject *)v, fp);
+ return 0;
+}