2 * Copyright (c) 2008-2009 Christian Hammond
3 * Copyright (c) 2008-2009 David Trowbridge
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 #include "claws-features.h"
30 #include <pygobject.h>
31 #include <pygtk/pygtk.h>
32 #endif // ENABLE_PYTHON
35 #include <glib/gi18n.h>
41 #include "python-hooks.h"
44 static gboolean python_enabled = FALSE;
47 static GString *captured_stdout = NULL;
48 static GString *captured_stderr = NULL;
52 capture_stdout(PyObject *self, PyObject *args)
56 if (!PyArg_ParseTuple(args, "s", &str))
59 g_string_append(captured_stdout, str);
66 capture_stderr(PyObject *self, PyObject *args)
70 if (!PyArg_ParseTuple(args, "s", &str))
73 g_string_append(captured_stderr, str);
80 capture_stdin(PyObject *self, PyObject *args)
82 /* Return an empty string.
83 * This is what read() returns when hitting EOF. */
84 return PyString_FromString("");
88 wrap_gobj(PyObject *self, PyObject *args)
93 if (!PyArg_ParseTuple(args, "l", &addr))
96 if (!G_IS_OBJECT(addr))
104 return pygobject_new(obj);
107 static PyMethodDef parasite_python_methods[] = {
108 {"capture_stdout", capture_stdout, METH_VARARGS, "Captures stdout"},
109 {"capture_stderr", capture_stderr, METH_VARARGS, "Captures stderr"},
110 {"capture_stdin", capture_stdin, METH_VARARGS, "Captures stdin"},
111 {"gobj", wrap_gobj, METH_VARARGS, "Wraps a C GObject"},
112 {NULL, NULL, 0, NULL}
119 const char *prgname = g_get_prgname();
121 return (!strcmp(prgname, "gimp"));
123 #endif // ENABLE_PYTHON
126 parasite_python_init(char **error)
129 struct sigaction old_sigint;
132 if (is_blacklisted()) {
133 *error = g_strdup("Application is blacklisted");
137 /* This prevents errors such as "undefined symbol: PyExc_ImportError" */
138 if (!dlopen(PYTHON_SHARED_LIB, RTLD_NOW | RTLD_GLOBAL))
140 *error = g_strdup_printf("Parasite: Error on dlopen(): %s\n", dlerror());
144 captured_stdout = g_string_new("");
145 captured_stderr = g_string_new("");
147 /* Back up and later restore SIGINT so Python doesn't steal it from us. */
148 sigaction(SIGINT, NULL, &old_sigint);
150 if (!Py_IsInitialized())
153 sigaction(SIGINT, &old_sigint, NULL);
155 Py_InitModule("parasite", parasite_python_methods);
156 if(PyRun_SimpleString(
160 "class StdoutCatcher:\n"
161 " def write(self, str):\n"
162 " parasite.capture_stdout(str)\n"
163 " def flush(self):\n"
166 "class StderrCatcher:\n"
167 " def write(self, str):\n"
168 " parasite.capture_stderr(str)\n"
169 " def flush(self):\n"
172 "class StdinCatcher:\n"
173 " def readline(self, size=-1):\n"
174 " return parasite.capture_stdin(size)\n"
175 " def read(self, size=-1):\n"
176 " return parasite.capture_stdin(size)\n"
177 " def flush(self):\n"
183 if (!pygobject_init(-1, -1, -1))
186 pygtk = PyImport_ImportModule("gtk");
190 PyObject *module_dict = PyModule_GetDict(pygtk);
191 PyObject *cobject = PyDict_GetItemString(module_dict, "_PyGtk_API");
194 * This seems to be NULL when we're running a PyGTK program.
195 * We really need to find out why.
199 if (PyCObject_Check(cobject)) {
200 _PyGtk_API = (struct _PyGtk_FunctionStruct*)
201 PyCObject_AsVoidPtr(cobject);
203 #if PY_VERSION_HEX >= 0x02070000
204 else if (PyCapsule_IsValid(cobject, "gtk._gtk._PyGtk_API")) {
205 _PyGtk_API = (struct _PyGtk_FunctionStruct*)PyCapsule_GetPointer(cobject, "gtk._gtk._PyGtk_API");
209 *error = g_strdup("Parasite: Could not find _PyGtk_API object");
214 *error = g_strdup("Parasite: Could not import gtk");
218 python_enabled = TRUE;
219 #endif // ENABLE_PYTHON
224 parasite_python_run(const char *command,
225 ParasitePythonLogger stdout_logger,
226 ParasitePythonLogger stderr_logger,
230 PyGILState_STATE gstate;
236 /* empty string as command is a noop */
237 if(!strcmp(command, ""))
240 /* if first non-whitespace character is '#', command is also a noop */
242 while(cp && (*cp != '\0') && g_ascii_isspace(*cp))
247 gstate = PyGILState_Ensure();
249 module = PyImport_AddModule("__main__");
250 dict = PyModule_GetDict(module);
252 PyRun_SimpleString("old_stdout = sys.stdout\n"
253 "old_stderr = sys.stderr\n"
254 "old_stdin = sys.stdin\n"
255 "sys.stdout = StdoutCatcher()\n"
256 "sys.stderr = StderrCatcher()\n"
257 "sys.stdin = StdinCatcher()\n");
259 obj = PyRun_String(command, Py_single_input, dict, dict);
262 PyRun_SimpleString("sys.stdout = old_stdout\n"
263 "sys.stderr = old_stderr\n"
264 "sys.stdin = old_stdin\n");
266 if (stdout_logger != NULL)
267 stdout_logger(captured_stdout->str, user_data);
269 if (stderr_logger != NULL)
270 stderr_logger(captured_stderr->str, user_data);
272 // Print any returned object
273 if (obj != NULL && obj != Py_None) {
274 PyObject *repr = PyObject_Repr(obj);
276 char *string = PyString_AsString(repr);
278 stdout_logger(string, user_data);
279 stdout_logger("\n", user_data);
286 PyGILState_Release(gstate);
287 g_string_erase(captured_stdout, 0, -1);
288 g_string_erase(captured_stderr, 0, -1);
289 #endif // ENABLE_PYTHON
293 parasite_python_is_enabled(void)
295 return python_enabled;
298 // vim: set et sw=4 ts=4: