Blender V2.61 - r43446

bpy_traceback.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * ***** END GPL LICENSE BLOCK *****
00019  */
00020 
00029 #include <Python.h>
00030 #include <frameobject.h>
00031 
00032 #include "bpy_traceback.h"
00033 
00034 static const char *traceback_filepath(PyTracebackObject *tb, PyObject **coerce)
00035 {
00036     return PyBytes_AS_STRING((*coerce = PyUnicode_EncodeFSDefault(tb->tb_frame->f_code->co_filename)));
00037 }
00038 
00039 /* copied from pythonrun.c, 3.2.0 */
00040 static int
00041 parse_syntax_error(PyObject *err, PyObject **message, const char **filename,
00042                    int *lineno, int *offset, const char **text)
00043 {
00044     long hold;
00045     PyObject *v;
00046 
00047     /* old style errors */
00048     if (PyTuple_Check(err))
00049         return PyArg_ParseTuple(err, "O(ziiz)", message, filename,
00050                                 lineno, offset, text);
00051 
00052     /* new style errors.  `err' is an instance */
00053 
00054     if (! (v = PyObject_GetAttrString(err, "msg")))
00055         goto finally;
00056     *message = v;
00057 
00058     if (!(v = PyObject_GetAttrString(err, "filename")))
00059         goto finally;
00060     if (v == Py_None)
00061         *filename = NULL;
00062     else if (! (*filename = _PyUnicode_AsString(v)))
00063         goto finally;
00064 
00065     Py_DECREF(v);
00066     if (!(v = PyObject_GetAttrString(err, "lineno")))
00067         goto finally;
00068     hold = PyLong_AsLong(v);
00069     Py_DECREF(v);
00070     v = NULL;
00071     if (hold < 0 && PyErr_Occurred())
00072         goto finally;
00073     *lineno = (int)hold;
00074 
00075     if (!(v = PyObject_GetAttrString(err, "offset")))
00076         goto finally;
00077     if (v == Py_None) {
00078         *offset = -1;
00079         Py_DECREF(v);
00080         v = NULL;
00081     }
00082     else {
00083         hold = PyLong_AsLong(v);
00084         Py_DECREF(v);
00085         v = NULL;
00086         if (hold < 0 && PyErr_Occurred())
00087             goto finally;
00088         *offset = (int)hold;
00089     }
00090 
00091     if (!(v = PyObject_GetAttrString(err, "text")))
00092         goto finally;
00093     if (v == Py_None)
00094         *text = NULL;
00095     else if (!PyUnicode_Check(v) ||
00096              !(*text = _PyUnicode_AsString(v)))
00097         goto finally;
00098     Py_DECREF(v);
00099     return 1;
00100 
00101 finally:
00102     Py_XDECREF(v);
00103     return 0;
00104 }
00105 /* end copied function! */
00106 
00107 
00108 void python_script_error_jump(const char *filepath, int *lineno, int *offset)
00109 {
00110     PyObject *exception, *value;
00111     PyTracebackObject *tb;
00112 
00113     *lineno = -1;
00114     *offset = 0;
00115 
00116     PyErr_Fetch(&exception, &value, (PyObject **)&tb);
00117 
00118     if (exception && PyErr_GivenExceptionMatches(exception, PyExc_SyntaxError)) {
00119         /* no traceback available when SyntaxError.
00120          * python has no api's to this. reference parse_syntax_error() from pythonrun.c */
00121         PyErr_NormalizeException(&exception, &value, (PyObject **)&tb);
00122         PyErr_Restore(exception, value, (PyObject *)tb);    /* takes away reference! */
00123 
00124         if (value) { /* should always be true */
00125             PyObject *message;
00126             const char *filename, *text;
00127 
00128             if (parse_syntax_error(value, &message, &filename, lineno, offset, &text)) {
00129                 /* python adds a '/', prefix, so check for both */
00130                 if ((strcmp(filename, filepath) == 0) ||
00131                     ((filename[0] == '\\' || filename[0] == '/') && strcmp(filename + 1, filepath) == 0)
00132                 ) {
00133                     /* good */
00134                 }
00135                 else {
00136                     *lineno = -1;
00137                 }
00138             }
00139             else {
00140                 *lineno = -1;
00141             }
00142         }
00143     }
00144     else {
00145         PyErr_NormalizeException(&exception, &value, (PyObject **)&tb);
00146         PyErr_Restore(exception, value, (PyObject *)tb);    /* takes away reference! */
00147         PyErr_Print();
00148 
00149         for (tb = (PyTracebackObject *)PySys_GetObject("last_traceback");
00150              tb && (PyObject *)tb != Py_None;
00151              tb = tb->tb_next)
00152         {
00153             PyObject *coerce;
00154             const char *tb_filepath = traceback_filepath(tb, &coerce);
00155             const int match = strcmp(tb_filepath, filepath) != 0;
00156             Py_DECREF(coerce);
00157 
00158             if (match) {
00159                 *lineno = tb->tb_lineno;
00160                 break;
00161             }
00162         }
00163     }
00164 }