Imported Upstream version 3.9.90
[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 #include "pygspawn.h"
31
32 struct _PyGChildSetupData {
33     PyObject *func;
34     PyObject *data;
35 };
36
37 PYGLIB_DEFINE_TYPE("gi._glib.Pid", PyGPid_Type, PYGLIB_PyLongObject)
38
39 static PyObject *
40 pyg_pid_close(PyObject *self, PyObject *args, PyObject *kwargs)
41 {
42     g_spawn_close_pid(PYGLIB_PyLong_AsLong(self));
43     Py_INCREF(Py_None);
44     return Py_None;
45 }
46
47 static PyMethodDef pyg_pid_methods[] = {
48     { "close", (PyCFunction)pyg_pid_close, METH_NOARGS },
49     { NULL, NULL, 0 }
50 };
51
52 static void
53 pyg_pid_free(PyObject *gpid)
54 {
55     g_spawn_close_pid((GPid) PYGLIB_PyLong_AsLong(gpid));
56     PYGLIB_PyLong_Type.tp_free((void *) gpid);
57 }
58
59 static int
60 pyg_pid_tp_init(PyObject *self, PyObject *args, PyObject *kwargs)
61 {
62     PyErr_SetString(PyExc_TypeError, "gi._glib.Pid cannot be manually instantiated");
63     return -1;
64 }
65
66 PyObject *
67 pyg_pid_new(GPid pid)
68 {
69     return PyObject_CallMethod((PyObject*)&PyGPid_Type, "__new__", "Oi",
70                                &PyGPid_Type, pid);
71 }
72
73 static void
74 _pyg_spawn_async_callback(gpointer user_data)
75 {
76     struct _PyGChildSetupData *data;
77     PyObject *retval;
78     PyGILState_STATE gil;
79
80     data = (struct _PyGChildSetupData *) user_data;
81     gil = pyglib_gil_state_ensure();
82     if (data->data)
83         retval = PyObject_CallFunction(data->func, "O", data->data);
84     else
85         retval = PyObject_CallFunction(data->func, NULL);
86     if (retval)
87         Py_DECREF(retval);
88     else
89         PyErr_Print();
90     Py_DECREF(data->func);
91     Py_XDECREF(data->data);
92     g_slice_free(struct _PyGChildSetupData, data);
93     pyglib_gil_state_release(gil);
94 }
95
96 PyObject *
97 pyglib_spawn_async(PyObject *object, PyObject *args, PyObject *kwargs)
98 {
99     static char *kwlist[] = { "argv", "envp", "working_directory", "flags",
100                               "child_setup", "user_data", "standard_input",
101                               "standard_output", "standard_error", NULL };
102     PyObject *pyargv, *pyenvp = NULL;
103     char **argv, **envp = NULL;
104     PyObject *func = Py_None, *user_data = NULL;
105     char *working_directory = NULL;
106     int flags = 0, _stdin = -1, _stdout = -1, _stderr = -1;
107     PyObject *pystdin = NULL, *pystdout = NULL, *pystderr = NULL;
108     gint *standard_input, *standard_output, *standard_error;
109     struct _PyGChildSetupData *callback_data = NULL;
110     GError *error = NULL;
111     GPid child_pid = -1;
112     Py_ssize_t len, i;
113
114     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OsiOOOOO:gi._glib.spawn_async",
115                                      kwlist,
116                                      &pyargv, &pyenvp, &working_directory, &flags,
117                                      &func, &user_data,
118                                      &pystdin, &pystdout, &pystderr))
119         return NULL;
120
121     if (pystdin && PyObject_IsTrue(pystdin))
122         standard_input = &_stdin;
123     else
124         standard_input = NULL;
125
126     if (pystdout && PyObject_IsTrue(pystdout))
127         standard_output = &_stdout;
128     else
129         standard_output = NULL;
130
131     if (pystderr && PyObject_IsTrue(pystderr))
132         standard_error = &_stderr;
133     else
134         standard_error = NULL;
135
136       /* parse argv */
137     if (!PySequence_Check(pyargv)) {
138         PyErr_SetString(PyExc_TypeError,
139                         "gi._glib.spawn_async: "
140                         "first argument must be a sequence of strings");
141         return NULL;
142     }
143     len = PySequence_Length(pyargv);
144     argv = g_new0(char *, len + 1);
145     for (i = 0; i < len; ++i) {
146         PyObject *tmp = PySequence_ITEM(pyargv, i);
147         if (tmp == NULL || !PYGLIB_PyUnicode_Check(tmp)) {
148             PyErr_SetString(PyExc_TypeError,
149                             "gi._glib.spawn_async: "
150                             "first argument must be a sequence of strings");
151             g_free(argv);
152             Py_XDECREF(tmp);
153             return NULL;
154         }
155         argv[i] = PYGLIB_PyUnicode_AsString(tmp);
156         Py_DECREF(tmp);
157     }
158
159       /* parse envp */
160     if (pyenvp) {
161         if (!PySequence_Check(pyenvp)) {
162             PyErr_SetString(PyExc_TypeError,
163                             "gi._glib.spawn_async: "
164                             "second argument must be a sequence of strings");
165             g_free(argv);
166             return NULL;
167         }
168         len = PySequence_Length(pyenvp);
169         envp = g_new0(char *, len + 1);
170         for (i = 0; i < len; ++i) {
171             PyObject *tmp = PySequence_ITEM(pyenvp, i);
172             if (tmp == NULL || !PYGLIB_PyUnicode_Check(tmp)) {
173                 PyErr_SetString(PyExc_TypeError,
174                                 "gi._glib.spawn_async: "
175                                 "second argument must be a sequence of strings");
176                 g_free(envp);
177                 Py_XDECREF(tmp);
178                 g_free(argv);
179                 return NULL;
180             }
181             envp[i] = PYGLIB_PyUnicode_AsString(tmp);
182             Py_DECREF(tmp);
183         }
184     }
185
186     if (func != Py_None) {
187         if (!PyCallable_Check(func)) {
188             PyErr_SetString(PyExc_TypeError, "child_setup parameter must be callable or None");
189             g_free(argv);
190             if (envp)
191                 g_free(envp);
192             return NULL;
193         }
194         callback_data = g_slice_new(struct _PyGChildSetupData);
195         callback_data->func = func;
196         callback_data->data = user_data;
197         Py_INCREF(callback_data->func);
198         if (callback_data->data)
199             Py_INCREF(callback_data->data);
200     }
201
202     if (!g_spawn_async_with_pipes(working_directory, argv, envp, flags,
203                                   (func != Py_None ? _pyg_spawn_async_callback : NULL),
204                                   callback_data, &child_pid,
205                                   standard_input,
206                                   standard_output,
207                                   standard_error,
208                                   &error))
209
210
211     {
212         g_free(argv);
213         if (envp) g_free(envp);
214         if (callback_data) {
215             Py_DECREF(callback_data->func);
216             Py_XDECREF(callback_data->data);
217             g_slice_free(struct _PyGChildSetupData, callback_data);
218         }
219         pyglib_error_check(&error);
220         return NULL;
221     }
222     g_free(argv);
223     if (envp) g_free(envp);
224
225     if (standard_input)
226         pystdin = PYGLIB_PyLong_FromLong(*standard_input);
227     else {
228         Py_INCREF(Py_None);
229         pystdin = Py_None;
230     }
231
232     if (standard_output)
233         pystdout = PYGLIB_PyLong_FromLong(*standard_output);
234     else {
235         Py_INCREF(Py_None);
236         pystdout = Py_None;
237     }
238
239     if (standard_error)
240         pystderr = PYGLIB_PyLong_FromLong(*standard_error);
241     else {
242         Py_INCREF(Py_None);
243         pystderr = Py_None;
244     }
245
246     return Py_BuildValue("NNNN", pyg_pid_new(child_pid), pystdin, pystdout, pystderr);
247 }
248
249 void
250 pyglib_spawn_register_types(PyObject *d)
251 {
252     PyGPid_Type.tp_base = &PYGLIB_PyLong_Type;
253     PyGPid_Type.tp_flags = Py_TPFLAGS_DEFAULT;
254     PyGPid_Type.tp_methods = pyg_pid_methods;
255     PyGPid_Type.tp_init = pyg_pid_tp_init;
256     PyGPid_Type.tp_free = (freefunc)pyg_pid_free;
257     PyGPid_Type.tp_new = PYGLIB_PyLong_Type.tp_new;
258     PYGLIB_REGISTER_TYPE(d, PyGPid_Type, "Pid");
259 }