home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 15 / AACD15.ISO / AACD / Programming / Python2 / Python20_source / Python / traceback.c < prev   
Encoding:
C/C++ Source or Header  |  2000-10-25  |  5.5 KB  |  241 lines

  1.  
  2. /* Traceback implementation */
  3.  
  4. #include "Python.h"
  5.  
  6. #include "compile.h"
  7. #include "frameobject.h"
  8. #include "structmember.h"
  9. #include "osdefs.h"
  10.  
  11. typedef struct _tracebackobject {
  12.     PyObject_HEAD
  13.     struct _tracebackobject *tb_next;
  14.     PyFrameObject *tb_frame;
  15.     int tb_lasti;
  16.     int tb_lineno;
  17. } tracebackobject;
  18.  
  19. #define OFF(x) offsetof(tracebackobject, x)
  20.  
  21. static struct memberlist tb_memberlist[] = {
  22.     {"tb_next",    T_OBJECT,    OFF(tb_next)},
  23.     {"tb_frame",    T_OBJECT,    OFF(tb_frame)},
  24.     {"tb_lasti",    T_INT,        OFF(tb_lasti)},
  25.     {"tb_lineno",    T_INT,        OFF(tb_lineno)},
  26.     {NULL}    /* Sentinel */
  27. };
  28.  
  29. static PyObject *
  30. tb_getattr(tracebackobject *tb, char *name)
  31. {
  32.     return PyMember_Get((char *)tb, tb_memberlist, name);
  33. }
  34.  
  35. static void
  36. tb_dealloc(tracebackobject *tb)
  37. {
  38.     Py_TRASHCAN_SAFE_BEGIN(tb)
  39.     Py_XDECREF(tb->tb_next);
  40.     Py_XDECREF(tb->tb_frame);
  41.     PyObject_DEL(tb);
  42.     Py_TRASHCAN_SAFE_END(tb)
  43. }
  44.  
  45. #define Tracebacktype PyTraceBack_Type
  46. #define is_tracebackobject PyTraceBack_Check
  47.  
  48. PyTypeObject Tracebacktype = {
  49.     PyObject_HEAD_INIT(&PyType_Type)
  50.     0,
  51.     "traceback",
  52.     sizeof(tracebackobject),
  53.     0,
  54.     (destructor)tb_dealloc, /*tp_dealloc*/
  55.     0,        /*tp_print*/
  56.     (getattrfunc)tb_getattr, /*tp_getattr*/
  57.     0,        /*tp_setattr*/
  58.     0,        /*tp_compare*/
  59.     0,        /*tp_repr*/
  60.     0,        /*tp_as_number*/
  61.     0,        /*tp_as_sequence*/
  62.     0,        /*tp_as_mapping*/
  63. };
  64.  
  65. static tracebackobject *
  66. newtracebackobject(tracebackobject *next, PyFrameObject *frame, int lasti,
  67.            int lineno)
  68. {
  69.     tracebackobject *tb;
  70.     if ((next != NULL && !is_tracebackobject(next)) ||
  71.             frame == NULL || !PyFrame_Check(frame)) {
  72.         PyErr_BadInternalCall();
  73.         return NULL;
  74.     }
  75.     tb = PyObject_NEW(tracebackobject, &Tracebacktype);
  76.     if (tb != NULL) {
  77.         Py_XINCREF(next);
  78.         tb->tb_next = next;
  79.         Py_XINCREF(frame);
  80.         tb->tb_frame = frame;
  81.         tb->tb_lasti = lasti;
  82.         tb->tb_lineno = lineno;
  83.     }
  84.     return tb;
  85. }
  86.  
  87. int
  88. PyTraceBack_Here(PyFrameObject *frame)
  89. {
  90.     PyThreadState *tstate = frame->f_tstate;
  91.     tracebackobject *oldtb = (tracebackobject *) tstate->curexc_traceback;
  92.     tracebackobject *tb = newtracebackobject(oldtb,
  93.                 frame, frame->f_lasti, frame->f_lineno);
  94.     if (tb == NULL)
  95.         return -1;
  96.     tstate->curexc_traceback = (PyObject *)tb;
  97.     Py_XDECREF(oldtb);
  98.     return 0;
  99. }
  100.  
  101. static int
  102. tb_displayline(PyObject *f, char *filename, int lineno, char *name)
  103. {
  104.     int err = 0;
  105.     FILE *xfp;
  106.     char linebuf[1000];
  107.     int i;
  108.     if (filename == NULL || name == NULL)
  109.         return -1;
  110. #ifdef MPW
  111.     /* This is needed by MPW's File and Line commands */
  112. #define FMT "  File \"%.900s\"; line %d # in %s\n"
  113. #else
  114.     /* This is needed by Emacs' compile command */
  115. #define FMT "  File \"%.900s\", line %d, in %s\n"
  116. #endif
  117.     xfp = fopen(filename, "r");
  118.     if (xfp == NULL) {
  119.         /* Search tail of filename in sys.path before giving up */
  120.         PyObject *path;
  121.         char *tail = strrchr(filename, SEP);
  122.         if (tail == NULL)
  123.             tail = filename;
  124.         else
  125.             tail++;
  126.         path = PySys_GetObject("path");
  127.         if (path != NULL && PyList_Check(path)) {
  128.             int npath = PyList_Size(path);
  129.             size_t taillen = strlen(tail);
  130.             char namebuf[MAXPATHLEN+1];
  131.             for (i = 0; i < npath; i++) {
  132.                 PyObject *v = PyList_GetItem(path, i);
  133.                 if (v == NULL) {
  134.                     PyErr_Clear();
  135.                     break;
  136.                 }
  137.                 if (PyString_Check(v)) {
  138.                     size_t len;
  139.                     len = PyString_Size(v);
  140.                     if (len + 1 + taillen >= MAXPATHLEN)
  141.                         continue; /* Too long */
  142.                     strcpy(namebuf, PyString_AsString(v));
  143.                     if (strlen(namebuf) != len)
  144.                         continue; /* v contains '\0' */
  145.                     if (len > 0 && namebuf[len-1] != SEP)
  146.                         namebuf[len++] = SEP;
  147.                     strcpy(namebuf+len, tail);
  148.                     xfp = fopen(namebuf, "r");
  149.                     if (xfp != NULL) {
  150.                         filename = namebuf;
  151.                         break;
  152.                     }
  153.                 }
  154.             }
  155.         }
  156.     }
  157.     sprintf(linebuf, FMT, filename, lineno, name);
  158.     err = PyFile_WriteString(linebuf, f);
  159.     if (xfp == NULL || err != 0)
  160.         return err;
  161.     for (i = 0; i < lineno; i++) {
  162.         char* pLastChar = &linebuf[sizeof(linebuf)-2];
  163.         do {
  164.             *pLastChar = '\0';
  165.             if (fgets(linebuf, sizeof linebuf, xfp) == NULL)
  166.                 break;
  167.             /* fgets read *something*; if it didn't get as
  168.                far as pLastChar, it must have found a newline
  169.                or hit the end of the file;    if pLastChar is \n,
  170.                it obviously found a newline; else we haven't
  171.                yet seen a newline, so must continue */
  172.         } while (*pLastChar != '\0' && *pLastChar != '\n');
  173.     }
  174.     if (i == lineno) {
  175.         char *p = linebuf;
  176.         while (*p == ' ' || *p == '\t' || *p == '\014')
  177.             p++;
  178.         err = PyFile_WriteString("    ", f);
  179.         if (err == 0) {
  180.             err = PyFile_WriteString(p, f);
  181.             if (err == 0 && strchr(p, '\n') == NULL)
  182.                 err = PyFile_WriteString("\n", f);
  183.         }
  184.     }
  185.     fclose(xfp);
  186.     return err;
  187. }
  188.  
  189. static int
  190. tb_printinternal(tracebackobject *tb, PyObject *f, int limit)
  191. {
  192.     int err = 0;
  193.     int depth = 0;
  194.     tracebackobject *tb1 = tb;
  195.     while (tb1 != NULL) {
  196.         depth++;
  197.         tb1 = tb1->tb_next;
  198.     }
  199.     while (tb != NULL && err == 0) {
  200.         if (depth <= limit) {
  201.             if (Py_OptimizeFlag)
  202.                 tb->tb_lineno = PyCode_Addr2Line(
  203.                     tb->tb_frame->f_code, tb->tb_lasti);
  204.             err = tb_displayline(f,
  205.                 PyString_AsString(
  206.                     tb->tb_frame->f_code->co_filename),
  207.                 tb->tb_lineno,
  208.                 PyString_AsString(tb->tb_frame->f_code->co_name));
  209.         }
  210.         depth--;
  211.         tb = tb->tb_next;
  212.         if (err == 0)
  213.             err = PyErr_CheckSignals();
  214.     }
  215.     return err;
  216. }
  217.  
  218. int
  219. PyTraceBack_Print(PyObject *v, PyObject *f)
  220. {
  221.     int err;
  222.     PyObject *limitv;
  223.     int limit = 1000;
  224.     if (v == NULL)
  225.         return 0;
  226.     if (!is_tracebackobject(v)) {
  227.         PyErr_BadInternalCall();
  228.         return -1;
  229.     }
  230.     limitv = PySys_GetObject("tracebacklimit");
  231.     if (limitv && PyInt_Check(limitv)) {
  232.         limit = PyInt_AsLong(limitv);
  233.         if (limit <= 0)
  234.             return 0;
  235.     }
  236.     err = PyFile_WriteString("Traceback (most recent call last):\n", f);
  237.     if (!err)
  238.         err = tb_printinternal((tracebackobject *)v, f, limit);
  239.     return err;
  240. }
  241.