Imported Upstream version 3.25.1
[platform/upstream/pygobject2.git] / gi / _glib / pygspawn.c
1 /* -*- Mode: C; c-basic-offset: 4 -*-
2  * pyglib - Python bindings for GLib toolkit.
3  * Copyright (C) 1998-2003  James Henstridge
4  *               2004-2008  Johan Dahlin
5  *
6  *   pygspawn.c: wrapper for the glib library.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21  * USA
22  */
23
24 #include <Python.h>
25 #include <glib.h>
26
27 #include "pyglib.h"
28 #include "pyglib-private.h"
29
30 struct _PyGChildSetupData {
31     PyObject *func;
32     PyObject *data;
33 };
34
35 PYGLIB_DEFINE_TYPE("gi._glib.Pid", PyGPid_Type, PYGLIB_PyLongObject)
36
37 static PyObject *
38 pyg_pid_close(PyObject *self, PyObject *args, PyObject *kwargs)
39 {
40     g_spawn_close_pid(PYGLIB_PyLong_AsLong(self));
41     Py_INCREF(Py_None);
42     return Py_None;
43 }
44
45 static PyMethodDef pyg_pid_methods[] = {
46     { "close", (PyCFunction)pyg_pid_close, METH_NOARGS },
47     { NULL, NULL, 0 }
48 };
49
50 static void
51 pyg_pid_free(PyObject *gpid)
52 {
53     g_spawn_close_pid((GPid) PYGLIB_PyLong_AsLong(gpid));
54     PYGLIB_PyLong_Type.tp_free((void *) gpid);
55 }
56
57 static int
58 pyg_pid_tp_init(PyObject *self, PyObject *args, PyObject *kwargs)
59 {
60     PyErr_SetString(PyExc_TypeError, "gi._glib.Pid cannot be manually instantiated");
61     return -1;
62 }
63
64 PyObject *
65 pyg_pid_new(GPid pid)
66 {
67     PYGLIB_PyLongObject *pygpid;
68
69 #if PY_VERSION_HEX >= 0x03000000
70     return PyObject_CallMethod((PyObject*)&PyGPid_Type, "__new__", "Oi",
71                                &PyGPid_Type, pid);
72 #else
73     pygpid = PyObject_NEW(PyIntObject, &PyGPid_Type);
74     pygpid->ob_ival = pid;
75 #endif
76     return (PyObject *) pygpid;
77 }
78
79 static void
80 _pyg_spawn_async_callback(gpointer user_data)
81 {
82     struct _PyGChildSetupData *data;
83     PyObject *retval;
84     PyGILState_STATE gil;
85
86     data = (struct _PyGChildSetupData *) user_data;
87     gil = pyglib_gil_state_ensure();
88     if (data->data)
89         retval = PyObject_CallFunction(data->func, "O", data->data);
90     else
91         retval = PyObject_CallFunction(data->func, NULL);
92     if (retval)
93         Py_DECREF(retval);
94     else
95         PyErr_Print();
96     Py_DECREF(data->func);
97     Py_XDECREF(data->data);
98     g_slice_free(struct _PyGChildSetupData, data);
99     pyglib_gil_state_release(gil);
100 }
101
102 PyObject *
103 pyglib_spawn_async(PyObject *object, PyObject *args, PyObject *kwargs)
104 {
105     static char *kwlist[] = { "argv", "envp", "working_directory", "flags",
106                               "child_setup", "user_data", "standard_input",
107                               "standard_output", "standard_error", NULL };
108     PyObject *pyargv, *pyenvp = NULL;
109     char **argv, **envp = NULL;
110     PyObject *func = Py_None, *user_data = NULL;
111     char *working_directory = NULL;
112     int flags = 0, _stdin = -1, _stdout = -1, _stderr = -1;
113     PyObject *pystdin = NULL, *pystdout = NULL, *pystderr = NULL;
114     gint *standard_input, *standard_output, *standard_error;
115     struct _PyGChildSetupData *callback_data = NULL;
116     GError *error = NULL;
117     GPid child_pid = -1;
118     Py_ssize_t len, i;
119
120     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OsiOOOOO:gi._glib.spawn_async",
121                                      kwlist,
122                                      &pyargv, &pyenvp, &working_directory, &flags,
123                                      &func, &user_data,
124                                      &pystdin, &pystdout, &pystderr))
125         return NULL;
126
127     if (pystdin && PyObject_IsTrue(pystdin))
128         standard_input = &_stdin;
129     else
130         standard_input = NULL;
131
132     if (pystdout && PyObject_IsTrue(pystdout))
133         standard_output = &_stdout;
134     else
135         standard_output = NULL;
136
137     if (pystderr && PyObject_IsTrue(pystderr))
138         standard_error = &_stderr;
139     else
140         standard_error = NULL;
141
142       /* parse argv */
143     if (!PySequence_Check(pyargv)) {
144         PyErr_SetString(PyExc_TypeError,
145                         "gi._glib.spawn_async: "
146                         "first argument must be a sequence of strings");
147         return NULL;
148     }
149     len = PySequence_Length(pyargv);
150     argv = g_new0(char *, len + 1);
151     for (i = 0; i < len; ++i) {
152         PyObject *tmp = PySequence_ITEM(pyargv, i);
153         if (tmp == NULL || !PYGLIB_PyUnicode_Check(tmp)) {
154             PyErr_SetString(PyExc_TypeError,
155                             "gi._glib.spawn_async: "
156                             "first argument must be a sequence of strings");
157             g_free(argv);
158             Py_XDECREF(tmp);
159             return NULL;
160         }
161         argv[i] = PYGLIB_PyUnicode_AsString(tmp);
162         Py_DECREF(tmp);
163     }
164
165       /* parse envp */
166     if (pyenvp) {
167         if (!PySequence_Check(pyenvp)) {
168             PyErr_SetString(PyExc_TypeError,
169                             "gi._glib.spawn_async: "
170                             "second argument must be a sequence of strings");
171             g_free(argv);
172             return NULL;
173         }
174         len = PySequence_Length(pyenvp);
175         envp = g_new0(char *, len + 1);
176         for (i = 0; i < len; ++i) {
177             PyObject *tmp = PySequence_ITEM(pyenvp, i);
178             if (tmp == NULL || !PYGLIB_PyUnicode_Check(tmp)) {
179                 PyErr_SetString(PyExc_TypeError,
180                                 "gi._glib.spawn_async: "
181                                 "second argument must be a sequence of strings");
182                 g_free(envp);
183                 Py_XDECREF(tmp);
184                 g_free(argv);
185                 return NULL;
186             }
187             envp[i] = PYGLIB_PyUnicode_AsString(tmp);
188             Py_DECREF(tmp);
189         }
190     }
191
192     if (func != Py_None) {
193         if (!PyCallable_Check(func)) {
194             PyErr_SetString(PyExc_TypeError, "child_setup parameter must be callable or None");
195             g_free(argv);
196             if (envp)
197                 g_free(envp);
198             return NULL;
199         }
200         callback_data = g_slice_new(struct _PyGChildSetupData);
201         callback_data->func = func;
202         callback_data->data = user_data;
203         Py_INCREF(callback_data->func);
204         if (callback_data->data)
205             Py_INCREF(callback_data->data);
206     }
207
208     if (!g_spawn_async_with_pipes(working_directory, argv, envp, flags,
209                                   (func != Py_None ? _pyg_spawn_async_callback : NULL),
210                                   callback_data, &child_pid,
211                                   standard_input,
212                                   standard_output,
213                                   standard_error,
214                                   &error))
215
216
217     {
218         g_free(argv);
219         if (envp) g_free(envp);
220         if (callback_data) {
221             Py_DECREF(callback_data->func);
222             Py_XDECREF(callback_data->data);
223             g_slice_free(struct _PyGChildSetupData, callback_data);
224         }
225         pyglib_error_check(&error);
226         return NULL;
227     }
228     g_free(argv);
229     if (envp) g_free(envp);
230
231     if (standard_input)
232         pystdin = PYGLIB_PyLong_FromLong(*standard_input);
233     else {
234         Py_INCREF(Py_None);
235         pystdin = Py_None;
236     }
237
238     if (standard_output)
239         pystdout = PYGLIB_PyLong_FromLong(*standard_output);
240     else {
241         Py_INCREF(Py_None);
242         pystdout = Py_None;
243     }
244
245     if (standard_error)
246         pystderr = PYGLIB_PyLong_FromLong(*standard_error);
247     else {
248         Py_INCREF(Py_None);
249         pystderr = Py_None;
250     }
251
252     return Py_BuildValue("NNNN", pyg_pid_new(child_pid), pystdin, pystdout, pystderr);
253 }
254
255 void
256 pyglib_spawn_register_types(PyObject *d)
257 {
258     PyGPid_Type.tp_base = &PYGLIB_PyLong_Type;
259     PyGPid_Type.tp_flags = Py_TPFLAGS_DEFAULT;
260     PyGPid_Type.tp_methods = pyg_pid_methods;
261     PyGPid_Type.tp_init = pyg_pid_tp_init;
262     PyGPid_Type.tp_free = (freefunc)pyg_pid_free;
263     PYGLIB_REGISTER_TYPE(d, PyGPid_Type, "Pid");
264 }