| 
									
										
										
										
											2011-02-23 10:52:22 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2011-02-22 11:32:29 +00:00
										 |  |  |  * ***** BEGIN GPL LICENSE BLOCK ***** | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  |  * as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  |  * of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write to the Free Software Foundation, | 
					
						
							|  |  |  |  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * ***** END GPL LICENSE BLOCK ***** | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-27 20:10:08 +00:00
										 |  |  | /** \file blender/python/intern/bpy_traceback.c
 | 
					
						
							|  |  |  |  *  \ingroup pythonintern | 
					
						
							| 
									
										
										
										
											2011-11-05 08:21:12 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * This file contains utility functions for getting data from a python stack | 
					
						
							|  |  |  |  * trace. | 
					
						
							| 
									
										
										
										
											2011-02-27 20:10:08 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-22 11:32:29 +00:00
										 |  |  | #include <Python.h>
 | 
					
						
							|  |  |  | #include <frameobject.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "bpy_traceback.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-26 17:55:03 +00:00
										 |  |  | static const char *traceback_filepath(PyTracebackObject *tb, PyObject **coerce) | 
					
						
							| 
									
										
										
										
											2011-02-22 11:32:29 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-12-26 12:26:11 +00:00
										 |  |  | 	return PyBytes_AS_STRING((*coerce = PyUnicode_EncodeFSDefault(tb->tb_frame->f_code->co_filename))); | 
					
						
							| 
									
										
										
										
											2011-02-22 11:32:29 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* copied from pythonrun.c, 3.2.0 */ | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | parse_syntax_error(PyObject *err, PyObject **message, const char **filename, | 
					
						
							| 
									
										
										
										
											2011-04-21 13:11:51 +00:00
										 |  |  | 				   int *lineno, int *offset, const char **text) | 
					
						
							| 
									
										
										
										
											2011-02-22 11:32:29 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-04-21 13:11:51 +00:00
										 |  |  | 	long hold; | 
					
						
							|  |  |  | 	PyObject *v; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* old style errors */ | 
					
						
							|  |  |  | 	if (PyTuple_Check(err)) | 
					
						
							|  |  |  | 		return PyArg_ParseTuple(err, "O(ziiz)", message, filename, | 
					
						
							|  |  |  | 								lineno, offset, text); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* new style errors.  `err' is an instance */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (! (v = PyObject_GetAttrString(err, "msg"))) | 
					
						
							|  |  |  | 		goto finally; | 
					
						
							|  |  |  | 	*message = v; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(v = PyObject_GetAttrString(err, "filename"))) | 
					
						
							|  |  |  | 		goto finally; | 
					
						
							|  |  |  | 	if (v == Py_None) | 
					
						
							|  |  |  | 		*filename = NULL; | 
					
						
							|  |  |  | 	else if (! (*filename = _PyUnicode_AsString(v))) | 
					
						
							|  |  |  | 		goto finally; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Py_DECREF(v); | 
					
						
							|  |  |  | 	if (!(v = PyObject_GetAttrString(err, "lineno"))) | 
					
						
							|  |  |  | 		goto finally; | 
					
						
							|  |  |  | 	hold = PyLong_AsLong(v); | 
					
						
							|  |  |  | 	Py_DECREF(v); | 
					
						
							|  |  |  | 	v = NULL; | 
					
						
							|  |  |  | 	if (hold < 0 && PyErr_Occurred()) | 
					
						
							|  |  |  | 		goto finally; | 
					
						
							|  |  |  | 	*lineno = (int)hold; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(v = PyObject_GetAttrString(err, "offset"))) | 
					
						
							|  |  |  | 		goto finally; | 
					
						
							|  |  |  | 	if (v == Py_None) { | 
					
						
							|  |  |  | 		*offset = -1; | 
					
						
							|  |  |  | 		Py_DECREF(v); | 
					
						
							|  |  |  | 		v = NULL; | 
					
						
							| 
									
										
										
										
											2011-03-19 11:12:48 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							| 
									
										
										
										
											2011-04-21 13:11:51 +00:00
										 |  |  | 		hold = PyLong_AsLong(v); | 
					
						
							|  |  |  | 		Py_DECREF(v); | 
					
						
							|  |  |  | 		v = NULL; | 
					
						
							|  |  |  | 		if (hold < 0 && PyErr_Occurred()) | 
					
						
							|  |  |  | 			goto finally; | 
					
						
							|  |  |  | 		*offset = (int)hold; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(v = PyObject_GetAttrString(err, "text"))) | 
					
						
							|  |  |  | 		goto finally; | 
					
						
							|  |  |  | 	if (v == Py_None) | 
					
						
							|  |  |  | 		*text = NULL; | 
					
						
							|  |  |  | 	else if (!PyUnicode_Check(v) || | 
					
						
							|  |  |  | 			 !(*text = _PyUnicode_AsString(v))) | 
					
						
							|  |  |  | 		goto finally; | 
					
						
							|  |  |  | 	Py_DECREF(v); | 
					
						
							|  |  |  | 	return 1; | 
					
						
							| 
									
										
										
										
											2011-02-22 11:32:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | finally: | 
					
						
							| 
									
										
										
										
											2011-04-21 13:11:51 +00:00
										 |  |  | 	Py_XDECREF(v); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2011-02-22 11:32:29 +00:00
										 |  |  | } | 
					
						
							|  |  |  | /* end copied function! */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void python_script_error_jump(const char *filepath, int *lineno, int *offset) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	PyObject *exception, *value; | 
					
						
							|  |  |  | 	PyTracebackObject *tb; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-26 12:26:11 +00:00
										 |  |  | 	*lineno = -1; | 
					
						
							|  |  |  | 	*offset = 0; | 
					
						
							| 
									
										
										
										
											2011-02-22 11:32:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	PyErr_Fetch(&exception, &value, (PyObject **)&tb); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-13 01:29:08 +00:00
										 |  |  | 	if (exception && PyErr_GivenExceptionMatches(exception, PyExc_SyntaxError)) { | 
					
						
							| 
									
										
										
										
											2011-02-22 11:32:29 +00:00
										 |  |  | 		/* no traceback available when SyntaxError.
 | 
					
						
							|  |  |  | 		 * python has no api's to this. reference parse_syntax_error() from pythonrun.c */ | 
					
						
							|  |  |  | 		PyErr_NormalizeException(&exception, &value, (PyObject **)&tb); | 
					
						
							|  |  |  | 		PyErr_Restore(exception, value, (PyObject *)tb);	/* takes away reference! */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-13 01:29:08 +00:00
										 |  |  | 		if (value) { /* should always be true */ | 
					
						
							| 
									
										
										
										
											2011-02-22 11:32:29 +00:00
										 |  |  | 			PyObject *message; | 
					
						
							| 
									
										
										
										
											2011-04-21 13:11:51 +00:00
										 |  |  | 			const char *filename, *text; | 
					
						
							| 
									
										
										
										
											2011-02-22 11:32:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-13 01:29:08 +00:00
										 |  |  | 			if (parse_syntax_error(value, &message, &filename, lineno, offset, &text)) { | 
					
						
							| 
									
										
										
										
											2011-02-22 11:32:29 +00:00
										 |  |  | 				/* python adds a '/', prefix, so check for both */ | 
					
						
							| 
									
										
										
										
											2011-10-13 01:29:08 +00:00
										 |  |  | 				if ((strcmp(filename, filepath) == 0) || | 
					
						
							| 
									
										
										
										
											2011-02-22 11:32:29 +00:00
										 |  |  | 					((filename[0] == '\\' || filename[0] == '/') && strcmp(filename + 1, filepath) == 0) | 
					
						
							|  |  |  | 				) { | 
					
						
							|  |  |  | 					/* good */ | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				else { | 
					
						
							| 
									
										
										
										
											2011-12-26 12:26:11 +00:00
										 |  |  | 					*lineno = -1; | 
					
						
							| 
									
										
										
										
											2011-02-22 11:32:29 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else { | 
					
						
							| 
									
										
										
										
											2011-12-26 12:26:11 +00:00
										 |  |  | 				*lineno = -1; | 
					
						
							| 
									
										
										
										
											2011-02-22 11:32:29 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		PyErr_NormalizeException(&exception, &value, (PyObject **)&tb); | 
					
						
							|  |  |  | 		PyErr_Restore(exception, value, (PyObject *)tb);	/* takes away reference! */ | 
					
						
							|  |  |  | 		PyErr_Print(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-26 12:26:11 +00:00
										 |  |  | 		for (tb = (PyTracebackObject *)PySys_GetObject("last_traceback"); | 
					
						
							| 
									
										
										
										
											2011-11-26 15:18:30 +00:00
										 |  |  | 		     tb && (PyObject *)tb != Py_None; | 
					
						
							| 
									
										
										
										
											2011-12-26 12:26:11 +00:00
										 |  |  | 		     tb = tb->tb_next) | 
					
						
							| 
									
										
										
										
											2011-11-26 15:18:30 +00:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2011-08-26 17:55:03 +00:00
										 |  |  | 			PyObject *coerce; | 
					
						
							| 
									
										
										
										
											2011-12-26 12:26:11 +00:00
										 |  |  | 			const char *tb_filepath = traceback_filepath(tb, &coerce); | 
					
						
							|  |  |  | 			const int match = strcmp(tb_filepath, filepath) != 0; | 
					
						
							| 
									
										
										
										
											2011-08-26 17:55:03 +00:00
										 |  |  | 			Py_DECREF(coerce); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-13 01:29:08 +00:00
										 |  |  | 			if (match) { | 
					
						
							| 
									
										
										
										
											2011-12-26 12:26:11 +00:00
										 |  |  | 				*lineno = tb->tb_lineno; | 
					
						
							| 
									
										
										
										
											2011-02-22 11:32:29 +00:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |