/* -*- Mode: C; c-basic-offset: 4 -*- * pyglib - Python bindings for GLib toolkit. * Copyright (C) 1998-2003 James Henstridge * 2004-2008 Johan Dahlin * * pygspawn.c: wrapper for the glib library. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ #include #include #include "pygi-util.h" #include "pygi-basictype.h" #include "pygspawn.h" #include "pygi-error.h" struct _PyGChildSetupData { PyObject *func; PyObject *data; }; PYGI_DEFINE_TYPE("gi._gi.Pid", PyGPid_Type, PyLongObject) static GPid pyg_pid_get_pid (PyObject *self) { #ifdef G_OS_WIN32 return (GPid)PyLong_AsVoidPtr (self); #else return (GPid)PyLong_AsLong (self); #endif } static PyObject * pyg_pid_close(PyObject *self, PyObject *args, PyObject *kwargs) { g_spawn_close_pid(pyg_pid_get_pid (self)); Py_INCREF(Py_None); return Py_None; } static PyMethodDef pyg_pid_methods[] = { { "close", (PyCFunction)pyg_pid_close, METH_NOARGS }, { NULL, NULL, 0 } }; static void pyg_pid_free(PyObject *gpid) { g_spawn_close_pid(pyg_pid_get_pid (gpid)); PyLong_Type.tp_free((void *) gpid); } static int pyg_pid_tp_init(PyObject *self, PyObject *args, PyObject *kwargs) { PyErr_SetString(PyExc_TypeError, "gi._gi.Pid cannot be manually instantiated"); return -1; } PyObject * pyg_pid_new(GPid pid) { PyObject *long_val; #ifdef G_OS_WIN32 long_val = PyLong_FromVoidPtr (pid); #else long_val = pygi_gint_to_py (pid); #endif return PyObject_CallMethod((PyObject*)&PyGPid_Type, "__new__", "ON", &PyGPid_Type, long_val); } static void _pyg_spawn_async_callback(gpointer user_data) { struct _PyGChildSetupData *data; PyObject *retval; PyGILState_STATE gil; data = (struct _PyGChildSetupData *) user_data; gil = PyGILState_Ensure(); if (data->data) retval = PyObject_CallFunction(data->func, "O", data->data); else retval = PyObject_CallFunction(data->func, NULL); if (retval) Py_DECREF(retval); else PyErr_Print(); Py_DECREF(data->func); Py_XDECREF(data->data); g_slice_free(struct _PyGChildSetupData, data); PyGILState_Release(gil); } PyObject * pyglib_spawn_async(PyObject *object, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "argv", "envp", "working_directory", "flags", "child_setup", "user_data", "standard_input", "standard_output", "standard_error", NULL }; PyObject *pyargv, *pyenvp = NULL; char **argv, **envp = NULL; PyObject *func = Py_None, *user_data = NULL; char *working_directory = NULL; int flags = 0, _stdin = -1, _stdout = -1, _stderr = -1; PyObject *pystdin = NULL, *pystdout = NULL, *pystderr = NULL; gint *standard_input, *standard_output, *standard_error; struct _PyGChildSetupData *callback_data = NULL; GError *error = NULL; GPid child_pid = 0; Py_ssize_t len, i; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OsiOOOOO:gi._gi.spawn_async", kwlist, &pyargv, &pyenvp, &working_directory, &flags, &func, &user_data, &pystdin, &pystdout, &pystderr)) return NULL; if (pystdin && PyObject_IsTrue(pystdin)) standard_input = &_stdin; else standard_input = NULL; if (pystdout && PyObject_IsTrue(pystdout)) standard_output = &_stdout; else standard_output = NULL; if (pystderr && PyObject_IsTrue(pystderr)) standard_error = &_stderr; else standard_error = NULL; /* parse argv */ if (!PySequence_Check(pyargv)) { PyErr_SetString(PyExc_TypeError, "gi._gi.spawn_async: " "first argument must be a sequence of strings"); return NULL; } len = PySequence_Length(pyargv); argv = g_new0(char *, len + 1); for (i = 0; i < len; ++i) { PyObject *tmp = PySequence_ITEM(pyargv, i); if (tmp == NULL || !PyUnicode_Check (tmp)) { PyErr_SetString(PyExc_TypeError, "gi._gi.spawn_async: " "first argument must be a sequence of strings"); g_free(argv); Py_XDECREF(tmp); return NULL; } argv[i] = PyUnicode_AsUTF8 (tmp); Py_DECREF(tmp); } /* parse envp */ if (pyenvp) { if (!PySequence_Check(pyenvp)) { PyErr_SetString(PyExc_TypeError, "gi._gi.spawn_async: " "second argument must be a sequence of strings"); g_free(argv); return NULL; } len = PySequence_Length(pyenvp); envp = g_new0(char *, len + 1); for (i = 0; i < len; ++i) { PyObject *tmp = PySequence_ITEM(pyenvp, i); if (tmp == NULL || !PyUnicode_Check (tmp)) { PyErr_SetString(PyExc_TypeError, "gi._gi.spawn_async: " "second argument must be a sequence of strings"); g_free(envp); Py_XDECREF(tmp); g_free(argv); return NULL; } envp[i] = PyUnicode_AsUTF8 (tmp); Py_DECREF(tmp); } } if (func != Py_None) { if (!PyCallable_Check(func)) { PyErr_SetString(PyExc_TypeError, "child_setup parameter must be callable or None"); g_free(argv); if (envp) g_free(envp); return NULL; } callback_data = g_slice_new(struct _PyGChildSetupData); callback_data->func = func; callback_data->data = user_data; Py_INCREF(callback_data->func); if (callback_data->data) Py_INCREF(callback_data->data); } if (!g_spawn_async_with_pipes(working_directory, argv, envp, flags, (func != Py_None ? _pyg_spawn_async_callback : NULL), callback_data, &child_pid, standard_input, standard_output, standard_error, &error)) { g_free(argv); if (envp) g_free(envp); if (callback_data) { Py_DECREF(callback_data->func); Py_XDECREF(callback_data->data); g_slice_free(struct _PyGChildSetupData, callback_data); } pygi_error_check(&error); return NULL; } g_free(argv); if (envp) g_free(envp); if (standard_input) pystdin = pygi_gint_to_py(*standard_input); else { Py_INCREF(Py_None); pystdin = Py_None; } if (standard_output) pystdout = pygi_gint_to_py(*standard_output); else { Py_INCREF(Py_None); pystdout = Py_None; } if (standard_error) pystderr = pygi_gint_to_py(*standard_error); else { Py_INCREF(Py_None); pystderr = Py_None; } return Py_BuildValue("NNNN", pyg_pid_new(child_pid), pystdin, pystdout, pystderr); } /** * Returns 0 on success, or -1 and sets an exception. */ int pygi_spawn_register_types(PyObject *d) { PyGPid_Type.tp_base = &PyLong_Type; PyGPid_Type.tp_flags = Py_TPFLAGS_DEFAULT; PyGPid_Type.tp_methods = pyg_pid_methods; PyGPid_Type.tp_init = pyg_pid_tp_init; PyGPid_Type.tp_free = (freefunc)pyg_pid_free; PyGPid_Type.tp_new = PyLong_Type.tp_new; PyGPid_Type.tp_alloc = PyType_GenericAlloc; if (PyType_Ready(&PyGPid_Type)) return -1; PyDict_SetItemString(d, "Pid", (PyObject *)&PyGPid_Type); return 0; }