1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 /** \file
18  * \ingroup pythonintern
19  */
20 
21 #include <stdio.h>
22 
23 #include <Python.h>
24 
25 #include "MEM_guardedalloc.h"
26 
27 #include "BLI_fileops.h"
28 #include "BLI_listbase.h"
29 #include "BLI_path_util.h"
30 #include "BLI_string.h"
31 
32 #include "BKE_context.h"
33 #include "BKE_main.h"
34 #include "BKE_text.h"
35 
36 #include "DNA_text_types.h"
37 
38 #include "BPY_extern.h"
39 #include "BPY_extern_run.h"
40 
41 #include "bpy_capi_utils.h"
42 #include "bpy_intern_string.h"
43 #include "bpy_traceback.h"
44 
45 #include "../generic/py_capi_utils.h"
46 
47 /* -------------------------------------------------------------------- */
48 /** \name Private Utilities
49  * \{ */
50 
python_script_error_jump_text(Text * text)51 static void python_script_error_jump_text(Text *text)
52 {
53   int lineno;
54   int offset;
55   python_script_error_jump(text->id.name + 2, &lineno, &offset);
56   if (lineno != -1) {
57     /* select the line with the error */
58     txt_move_to(text, lineno - 1, INT_MAX, false);
59     txt_move_to(text, lineno - 1, offset, true);
60   }
61 }
62 
63 /* returns a dummy filename for a textblock so we can tell what file a text block comes from */
bpy_text_filename_get(char * fn,const Main * bmain,size_t fn_len,const Text * text)64 static void bpy_text_filename_get(char *fn, const Main *bmain, size_t fn_len, const Text *text)
65 {
66   BLI_snprintf(fn, fn_len, "%s%c%s", ID_BLEND_PATH(bmain, &text->id), SEP, text->id.name + 2);
67 }
68 
69 /* Very annoying! Undo #_PyModule_Clear(), see T23871. */
70 #define PYMODULE_CLEAR_WORKAROUND
71 
72 #ifdef PYMODULE_CLEAR_WORKAROUND
73 /* bad!, we should never do this, but currently only safe way I could find to keep namespace.
74  * from being cleared. - campbell */
75 typedef struct {
76   PyObject_HEAD PyObject *md_dict;
77   /* omit other values, we only want the dict. */
78 } PyModuleObject;
79 #endif
80 
python_script_exec(bContext * C,const char * fn,struct Text * text,struct ReportList * reports,const bool do_jump)81 static bool python_script_exec(
82     bContext *C, const char *fn, struct Text *text, struct ReportList *reports, const bool do_jump)
83 {
84   Main *bmain_old = CTX_data_main(C);
85   PyObject *main_mod = NULL;
86   PyObject *py_dict = NULL, *py_result = NULL;
87   PyGILState_STATE gilstate;
88 
89   BLI_assert(fn || text);
90 
91   if (fn == NULL && text == NULL) {
92     return 0;
93   }
94 
95   bpy_context_set(C, &gilstate);
96 
97   PyC_MainModule_Backup(&main_mod);
98 
99   if (text) {
100     char fn_dummy[FILE_MAXDIR];
101     bpy_text_filename_get(fn_dummy, bmain_old, sizeof(fn_dummy), text);
102 
103     if (text->compiled == NULL) { /* if it wasn't already compiled, do it now */
104       char *buf;
105       PyObject *fn_dummy_py;
106 
107       fn_dummy_py = PyC_UnicodeFromByte(fn_dummy);
108 
109       buf = txt_to_buf(text, NULL);
110       text->compiled = Py_CompileStringObject(buf, fn_dummy_py, Py_file_input, NULL, -1);
111       MEM_freeN(buf);
112 
113       Py_DECREF(fn_dummy_py);
114 
115       if (PyErr_Occurred()) {
116         if (do_jump) {
117           python_script_error_jump_text(text);
118         }
119         BPY_text_free_code(text);
120       }
121     }
122 
123     if (text->compiled) {
124       py_dict = PyC_DefaultNameSpace(fn_dummy);
125       py_result = PyEval_EvalCode(text->compiled, py_dict, py_dict);
126     }
127   }
128   else {
129     FILE *fp = BLI_fopen(fn, "r");
130 
131     if (fp) {
132       py_dict = PyC_DefaultNameSpace(fn);
133 
134 #ifdef _WIN32
135       /* Previously we used PyRun_File to run directly the code on a FILE
136        * object, but as written in the Python/C API Ref Manual, chapter 2,
137        * 'FILE structs for different C libraries can be different and
138        * incompatible'.
139        * So now we load the script file data to a buffer.
140        *
141        * Note on use of 'globals()', it's important not copy the dictionary because
142        * tools may inspect 'sys.modules["__main__"]' for variables defined in the code
143        * where using a copy of 'globals()' causes code execution
144        * to leave the main namespace untouched. see: T51444
145        *
146        * This leaves us with the problem of variables being included,
147        * currently this is worked around using 'dict.__del__' it's ugly but works.
148        */
149       {
150         const char *pystring =
151             "with open(__file__, 'rb') as f:"
152             "exec(compile(f.read(), __file__, 'exec'), globals().__delitem__('f') or globals())";
153 
154         fclose(fp);
155 
156         py_result = PyRun_String(pystring, Py_file_input, py_dict, py_dict);
157       }
158 #else
159       py_result = PyRun_File(fp, fn, Py_file_input, py_dict, py_dict);
160       fclose(fp);
161 #endif
162     }
163     else {
164       PyErr_Format(
165           PyExc_IOError, "Python file \"%s\" could not be opened: %s", fn, strerror(errno));
166       py_result = NULL;
167     }
168   }
169 
170   if (!py_result) {
171     if (text) {
172       if (do_jump) {
173         /* ensure text is valid before use, the script may have freed its self */
174         Main *bmain_new = CTX_data_main(C);
175         if ((bmain_old == bmain_new) && (BLI_findindex(&bmain_new->texts, text) != -1)) {
176           python_script_error_jump_text(text);
177         }
178       }
179     }
180     BPy_errors_to_report(reports);
181   }
182   else {
183     Py_DECREF(py_result);
184   }
185 
186   if (py_dict) {
187 #ifdef PYMODULE_CLEAR_WORKAROUND
188     PyModuleObject *mmod = (PyModuleObject *)PyDict_GetItem(PyImport_GetModuleDict(),
189                                                             bpy_intern_str___main__);
190     PyObject *dict_back = mmod->md_dict;
191     /* freeing the module will clear the namespace,
192      * gives problems running classes defined in this namespace being used later. */
193     mmod->md_dict = NULL;
194     Py_DECREF(dict_back);
195 #endif
196 
197 #undef PYMODULE_CLEAR_WORKAROUND
198   }
199 
200   PyC_MainModule_Restore(main_mod);
201 
202   bpy_context_clear(C, &gilstate);
203 
204   return (py_result != NULL);
205 }
206 
207 /** \} */
208 
209 /* -------------------------------------------------------------------- */
210 /** \name Run Text / Filename / String
211  * \{ */
212 
213 /* Can run a file or text block */
BPY_run_filepath(bContext * C,const char * filepath,struct ReportList * reports)214 bool BPY_run_filepath(bContext *C, const char *filepath, struct ReportList *reports)
215 {
216   return python_script_exec(C, filepath, NULL, reports, false);
217 }
218 
BPY_run_text(bContext * C,struct Text * text,struct ReportList * reports,const bool do_jump)219 bool BPY_run_text(bContext *C, struct Text *text, struct ReportList *reports, const bool do_jump)
220 {
221   return python_script_exec(C, NULL, text, reports, do_jump);
222 }
223 
224 /**
225  * \param mode: Passed to #PyRun_String, matches Python's `compile` functions mode argument.
226  * #Py_eval_input for `eval`, #Py_file_input for `exec`.
227  */
bpy_run_string_impl(bContext * C,const char * imports[],const char * expr,const int mode)228 static bool bpy_run_string_impl(bContext *C,
229                                 const char *imports[],
230                                 const char *expr,
231                                 const int mode)
232 {
233   BLI_assert(expr);
234   PyGILState_STATE gilstate;
235   PyObject *main_mod = NULL;
236   PyObject *py_dict, *retval;
237   bool ok = true;
238 
239   if (expr[0] == '\0') {
240     return ok;
241   }
242 
243   bpy_context_set(C, &gilstate);
244 
245   PyC_MainModule_Backup(&main_mod);
246 
247   py_dict = PyC_DefaultNameSpace("<blender string>");
248 
249   if (imports && (!PyC_NameSpace_ImportArray(py_dict, imports))) {
250     Py_DECREF(py_dict);
251     retval = NULL;
252   }
253   else {
254     retval = PyRun_String(expr, mode, py_dict, py_dict);
255   }
256 
257   if (retval == NULL) {
258     ok = false;
259     BPy_errors_to_report(CTX_wm_reports(C));
260   }
261   else {
262     Py_DECREF(retval);
263   }
264 
265   PyC_MainModule_Restore(main_mod);
266 
267   bpy_context_clear(C, &gilstate);
268 
269   return ok;
270 }
271 
272 /**
273  * Run an expression, matches: `exec(compile(..., "eval"))`
274  */
BPY_run_string_eval(bContext * C,const char * imports[],const char * expr)275 bool BPY_run_string_eval(bContext *C, const char *imports[], const char *expr)
276 {
277   return bpy_run_string_impl(C, imports, expr, Py_eval_input);
278 }
279 
280 /**
281  * Run an entire script, matches: `exec(compile(..., "exec"))`
282  */
BPY_run_string_exec(bContext * C,const char * imports[],const char * expr)283 bool BPY_run_string_exec(bContext *C, const char *imports[], const char *expr)
284 {
285   return bpy_run_string_impl(C, imports, expr, Py_file_input);
286 }
287 
288 /** \} */
289 
290 /* -------------------------------------------------------------------- */
291 /** \name Run Python & Evaluate Utilities
292  *
293  * Return values as plain C types, useful to run Python scripts
294  * in code that doesn't deal with Python data-types.
295  * \{ */
296 
297 /**
298  * \return success
299  */
BPY_run_string_as_number(bContext * C,const char * imports[],const char * expr,const char * report_prefix,double * r_value)300 bool BPY_run_string_as_number(bContext *C,
301                               const char *imports[],
302                               const char *expr,
303                               const char *report_prefix,
304                               double *r_value)
305 {
306   PyGILState_STATE gilstate;
307   bool ok = true;
308 
309   if (!r_value || !expr) {
310     return -1;
311   }
312 
313   if (expr[0] == '\0') {
314     *r_value = 0.0;
315     return ok;
316   }
317 
318   bpy_context_set(C, &gilstate);
319 
320   ok = PyC_RunString_AsNumber(imports, expr, "<expr as number>", r_value);
321 
322   if (ok == false) {
323     if (report_prefix != NULL) {
324       BPy_errors_to_report_ex(CTX_wm_reports(C), report_prefix, false, false);
325     }
326     else {
327       PyErr_Clear();
328     }
329   }
330 
331   bpy_context_clear(C, &gilstate);
332 
333   return ok;
334 }
335 
336 /**
337  * \return success
338  */
BPY_run_string_as_string_and_size(bContext * C,const char * imports[],const char * expr,const char * report_prefix,char ** r_value,size_t * r_value_size)339 bool BPY_run_string_as_string_and_size(bContext *C,
340                                        const char *imports[],
341                                        const char *expr,
342                                        const char *report_prefix,
343                                        char **r_value,
344                                        size_t *r_value_size)
345 {
346   BLI_assert(r_value && expr);
347   PyGILState_STATE gilstate;
348   bool ok = true;
349 
350   if (expr[0] == '\0') {
351     *r_value = NULL;
352     return ok;
353   }
354 
355   bpy_context_set(C, &gilstate);
356 
357   ok = PyC_RunString_AsStringAndSize(imports, expr, "<expr as str>", r_value, r_value_size);
358 
359   if (ok == false) {
360     if (report_prefix != NULL) {
361       BPy_errors_to_report_ex(CTX_wm_reports(C), false, false, report_prefix);
362     }
363     else {
364       PyErr_Clear();
365     }
366   }
367 
368   bpy_context_clear(C, &gilstate);
369 
370   return ok;
371 }
372 
BPY_run_string_as_string(bContext * C,const char * imports[],const char * expr,const char * report_prefix,char ** r_value)373 bool BPY_run_string_as_string(bContext *C,
374                               const char *imports[],
375                               const char *expr,
376                               const char *report_prefix,
377                               char **r_value)
378 {
379   size_t value_dummy_size;
380   return BPY_run_string_as_string_and_size(
381       C, imports, expr, report_prefix, r_value, &value_dummy_size);
382 }
383 
384 /**
385  * Support both int and pointers.
386  *
387  * \return success
388  */
BPY_run_string_as_intptr(bContext * C,const char * imports[],const char * expr,const char * report_prefix,intptr_t * r_value)389 bool BPY_run_string_as_intptr(bContext *C,
390                               const char *imports[],
391                               const char *expr,
392                               const char *report_prefix,
393                               intptr_t *r_value)
394 {
395   BLI_assert(r_value && expr);
396   PyGILState_STATE gilstate;
397   bool ok = true;
398 
399   if (expr[0] == '\0') {
400     *r_value = 0;
401     return ok;
402   }
403 
404   bpy_context_set(C, &gilstate);
405 
406   ok = PyC_RunString_AsIntPtr(imports, expr, "<expr as intptr>", r_value);
407 
408   if (ok == false) {
409     if (report_prefix != NULL) {
410       BPy_errors_to_report_ex(CTX_wm_reports(C), report_prefix, false, false);
411     }
412     else {
413       PyErr_Clear();
414     }
415   }
416 
417   bpy_context_clear(C, &gilstate);
418 
419   return ok;
420 }
421 
422 /** \} */
423