[glib/wip/gsubprocess] GSubprocess: WIP
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/gsubprocess] GSubprocess: WIP
- Date: Wed, 16 May 2012 20:59:52 +0000 (UTC)
commit cd19b5a0c015b0d2531881a550b756c3a3c8ff20
Author: Colin Walters <walters verbum org>
Date: Wed May 16 16:58:58 2012 -0400
GSubprocess: WIP
gio/giotypes.h | 10 +
gio/gmemoryinputstream.c | 88 +++--
gio/gmemoryinputstream.h | 3 +
gio/gsubprocess.c | 912 ++++++++++++++++++++++++++++++++++++++++++++++
gio/gsubprocess.h | 174 +++++++++
5 files changed, 1149 insertions(+), 38 deletions(-)
---
diff --git a/gio/giotypes.h b/gio/giotypes.h
index 876d856..e4f38ec 100644
--- a/gio/giotypes.h
+++ b/gio/giotypes.h
@@ -135,6 +135,16 @@ typedef struct _GIOStream GIOStream;
typedef struct _GPollableInputStream GPollableInputStream; /* Dummy typedef */
typedef struct _GPollableOutputStream GPollableOutputStream; /* Dummy typedef */
typedef struct _GResolver GResolver;
+
+/**
+ * GSubprocess:
+ *
+ * A child process.
+ *
+ * Since: 2.34
+ */
+typedef struct _GSubprocess GSubprocess;
+
/**
* GResource:
*
diff --git a/gio/gmemoryinputstream.c b/gio/gmemoryinputstream.c
index dac0ac1..7523044 100644
--- a/gio/gmemoryinputstream.c
+++ b/gio/gmemoryinputstream.c
@@ -44,14 +44,6 @@
* #GPollableInputStream.
*/
-typedef struct _Chunk Chunk;
-
-struct _Chunk {
- guint8 *data;
- gsize len;
- GDestroyNotify destroy;
-};
-
struct _GMemoryInputStreamPrivate {
GSList *chunks;
gsize len;
@@ -140,17 +132,6 @@ g_memory_input_stream_class_init (GMemoryInputStreamClass *klass)
}
static void
-free_chunk (gpointer data)
-{
- Chunk *chunk = data;
-
- if (chunk->destroy)
- chunk->destroy (chunk->data);
-
- g_slice_free (Chunk, chunk);
-}
-
-static void
g_memory_input_stream_finalize (GObject *object)
{
GMemoryInputStream *stream;
@@ -159,7 +140,7 @@ g_memory_input_stream_finalize (GObject *object)
stream = G_MEMORY_INPUT_STREAM (object);
priv = stream->priv;
- g_slist_free_full (priv->chunks, free_chunk);
+ g_slist_free_full (priv->chunks, (GDestroyNotify)g_bytes_unref);
G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize (object);
}
@@ -232,6 +213,20 @@ g_memory_input_stream_new_from_data (const void *data,
}
/**
+ * g_memory_input_stream_new_from_bytes:
+ * @bytes: a #GBytes
+ *
+ * Creates a new #GMemoryInputStream with data from the given @bytes.
+ *
+ * Returns: new #GInputStream read from @bytes
+ **/
+GInputStream *
+g_memory_input_stream_new_from_bytes (GBytes bytes)
+{
+
+}
+
+/**
* g_memory_input_stream_add_data:
* @stream: a #GMemoryInputStream
* @data: (array length=len) (element-type guint8) (transfer full): input data
@@ -246,24 +241,35 @@ g_memory_input_stream_add_data (GMemoryInputStream *stream,
gssize len,
GDestroyNotify destroy)
{
+ GBytes *bytes;
+
+ bytes = g_bytes_new_with_free_func (data, len, destroy, NULL);
+
+ g_memory_input_stream_add_bytes (stream, bytes);
+
+ g_bytes_unref (bytes);
+}
+
+/**
+ * g_memory_input_stream_add_bytes:
+ * @stream: a #GMemoryInputStream
+ * @bytes: input data
+ *
+ * Appends @bytes to data that can be read from the input stream.
+ */
+void
+g_memory_input_stream_add_bytes (GMemoryInputStream *stream,
+ GBytes bytes)
+{
GMemoryInputStreamPrivate *priv;
- Chunk *chunk;
g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream));
g_return_if_fail (data != NULL);
priv = stream->priv;
- if (len == -1)
- len = strlen (data);
-
- chunk = g_slice_new (Chunk);
- chunk->data = (guint8 *)data;
- chunk->len = len;
- chunk->destroy = destroy;
-
- priv->chunks = g_slist_append (priv->chunks, chunk);
- priv->len += chunk->len;
+ priv->chunks = g_slist_append (priv->chunks, g_bytes_ref (bytes));
+ priv->len += g_bytes_get_size (bytes);
}
static gssize
@@ -276,7 +282,8 @@ g_memory_input_stream_read (GInputStream *stream,
GMemoryInputStream *memory_stream;
GMemoryInputStreamPrivate *priv;
GSList *l;
- Chunk *chunk;
+ GBytes *chunk;
+ gsize len;
gsize offset, start, rest, size;
memory_stream = G_MEMORY_INPUT_STREAM (stream);
@@ -287,12 +294,13 @@ g_memory_input_stream_read (GInputStream *stream,
offset = 0;
for (l = priv->chunks; l; l = l->next)
{
- chunk = (Chunk *)l->data;
+ chunk = (GBytes *)l->data;
+ len = g_bytes_get_size (chunk);
- if (offset + chunk->len > priv->pos)
+ if (offset + len > priv->pos)
break;
- offset += chunk->len;
+ offset += len;
}
start = priv->pos - offset;
@@ -300,10 +308,14 @@ g_memory_input_stream_read (GInputStream *stream,
for (; l && rest > 0; l = l->next)
{
- chunk = (Chunk *)l->data;
- size = MIN (rest, chunk->len - start);
+ guint8*chunk_data;
+ chunk = (GBytes *)l->data;
+
+ chunk_data = g_bytes_get_data (chunk, &len);
+
+ size = MIN (rest, len - start);
- memcpy ((guint8 *)buffer + (count - rest), chunk->data + start, size);
+ memcpy ((guint8 *)buffer + (count - rest), chunk_data + start, size);
rest -= size;
start = 0;
diff --git a/gio/gmemoryinputstream.h b/gio/gmemoryinputstream.h
index e629db1..de881f6 100644
--- a/gio/gmemoryinputstream.h
+++ b/gio/gmemoryinputstream.h
@@ -72,10 +72,13 @@ GInputStream * g_memory_input_stream_new (void);
GInputStream * g_memory_input_stream_new_from_data (const void *data,
gssize len,
GDestroyNotify destroy);
+GInputStream * g_memory_input_stream_new_from_bytes (GBytes bytes);
void g_memory_input_stream_add_data (GMemoryInputStream *stream,
const void *data,
gssize len,
GDestroyNotify destroy);
+void g_memory_input_stream_add_bytes (GMemoryInputStream *stream,
+ GBytes bytes);
G_END_DECLS
diff --git a/gio/gsubprocess.c b/gio/gsubprocess.c
new file mode 100644
index 0000000..91f7f8d
--- /dev/null
+++ b/gio/gsubprocess.c
@@ -0,0 +1,912 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright  2012 Red Hat, Inc.
+ *
+ * This program 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 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ */
+
+/**
+ * SECTION:gsubprocess
+ * @title: GSubprocess
+ * @short_description: Create child processes
+ *
+ * This class is primarily convenience API on top of the lower-level
+ * g_spawn_async_with_pipes() and related functions provided by GLib.
+ *
+ * Since: 2.34
+ */
+
+#include "config.h"
+#include "gsubprocess.h"
+#include "gasyncresult.h"
+#include "giostream.h"
+#include "glibintl.h"
+
+typedef struct _GSubprocessClass GSubprocessClass;
+
+typedef enum {
+ G_SUBPROCESS_STATE_BUILDING,
+ G_SUBPROCESS_STATE_RUNNING,
+ G_SUBPROCESS_STATE_TERMINATED
+} GSubprocessState;
+
+struct _GSubprocess
+{
+ GSubprocessState state;
+
+ gchar *child_argv0;
+ GPtrArray *child_argv;
+ gchar **child_envp;
+
+ gboolean search_path : 1;
+ gboolean leave_descriptors_open : 1;
+ gboolean stdin_to_devnull : 1;
+ gboolean stdout_to_devnull : 1;
+ gboolean stderr_to_devnull : 1;
+
+ gchar *working_directory;
+
+ GSpawnChildSetupFunc child_setup;
+ gpointer child_setup_user_data;
+
+ gint stdin_fd;
+ gchar *stdin_path;
+ GInputStream *stdin_stream;
+ gchar *stdout_path;
+ GInputStream *stdout_stream;
+ gchar *stderr_path;
+ GInputStream *stderr_stream;
+
+ GPid pid;
+}
+
+G_DEFINE_TYPE (GSubprocess, g_subprocess, G_TYPE_OBJECT);
+
+enum
+{
+ PROP_0
+};
+
+static void
+g_subprocess_init (GSubprocess *self)
+{
+ self->state = G_SUBPROCESS_STATE_BUILDING;
+ self->child_argv = g_ptr_array_new_with_free_func (g_free);
+ self->search_path = TRUE;
+ self->stdin_to_devnull = TRUE;
+}
+
+static void
+g_subprocess_dispose (GObject *object)
+{
+ GSubprocess *self = G_SUBPROCESS (object);
+
+ g_clear_object (&self->stdin_stream);
+ g_clear_object (&self->stdout_stream);
+ g_clear_object (&self->stderr_stream);
+
+ if (G_OBJECT_CLASS (g_subprocess_parent_class)->dispose != NULL)
+ G_OBJECT_CLASS (g_subprocess_parent_class)->dispose (object);
+}
+
+static void
+g_subprocess_finalize (GObject *object)
+{
+ GSubprocess *self = G_SUBPROCESS (object);
+
+ if (self->child_argv)
+ g_ptr_array_unref (self->child_argv);
+
+ g_strfreev (self->child_envp);
+
+ g_free (self->working_directory);
+}
+
+static void
+g_subprocess_class_init (GTcpConnectionClass *class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+ gobject_class->dispose = g_subprocess_dispose;
+ gobject_class->finalize = g_subprocess_finalize;
+}
+
+/**** Creation ****/
+
+/**
+ * g_subprocess_new:
+ *
+ * After calling this function, you must use one of the functions to
+ * initialize the argument vector, such as g_subprocess_set_argv().
+ *
+ * Returns: A new #GSubprocess
+ */
+GSubprocess *
+g_subprocess_new (void)
+{
+ return g_object_new (G_TYPE_SUBPROCESS, NULL);
+}
+
+/**
+ * g_subprocess_new_with_args:
+ * @first: (array zero-terminated=1) (element-type guint8): First argument
+ *
+ * See the documentation of g_subprocess_append_args_va() for details
+ * about child process arguments.
+ *
+ * After calling this function, you may append further arguments with
+ * e.g. g_subprocess_append_args().
+ *
+ * Returns: A new #GSubprocess with the provided arguments
+ */
+GSubprocess *
+g_subprocess_new_with_args (const gchar *first,
+ ...)
+{
+ va_list args;
+ GSubprocess *ret;
+
+ ret = g_subprocess_new ();
+
+ va_start (args, first);
+ g_subprocess_append_args_va (ret, args);
+ va_end (args);
+
+ return ret;
+}
+
+/**** Argument control ****/
+
+/**
+ * g_subprocess_set_argv:
+ * @self: a #GSubprocess:
+ * @argv: (array zero-terminated=1): Argument array, %NULL-terminated
+ *
+ * Set the arguments to be used by the child process. This will
+ * overwrite any previous calls to g_subprocess_append_args().
+ *
+ * Due to limitations of gobject-introspection, the provided argument
+ * is annotated as an array of strings, not an array of bytestrings.
+ *
+ * For language bindings, you can use calls to
+ * g_subprocess_append_arg() indivdually to provide non-UTF8
+ * arguments.
+ *
+ * For more information, see g_subprocess_append_args_va().
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_argv (GSubprocess *self,
+ gchar **argv)
+{
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (argv != NULL);
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+
+ g_ptr_array_set_size (self->child_argv, 0);
+
+ for (; *argv; argv++)
+ g_ptr_array_add (self->child_argv, g_strdup (*argv));
+}
+
+/**
+ * g_subprocess_set_argv0:
+ * @self: a #GSubprocess:
+ * @argv: (array zero-terminated=1) (element-type guint8): First argument
+ *
+ * On Unix, child processes receive a bytestring provided by the
+ * parent process as the first argument (i.e. argv[0]). By default,
+ * GLib will set this to whatever executable is run, but you may override
+ * it with this function.
+ *
+ * For example, some implementations of Unix have just one 'grep'
+ * executable which behaves differently when executed as 'grep' or
+ * 'fgrep'.
+ *
+ * See the discussion of %G_SPAWN_FILE_AND_ARGV_ZERO in the
+ * g_spawn_async_with_pipes() documentation.
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_argv0 (GSubprocess *self,
+ const gchar *argv0)
+{
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+
+ g_free (self->child_argv0);
+ self->child_argv0 = g_strdup (argv0);
+}
+
+/**
+ * g_subprocess_append_arg:
+ * @self: a #GSubprocess:
+ * @arg: (array zero-terminated=1) (element-type guint8): Argument
+ *
+ * Append an argument to the child process. On Unix, this argument is
+ * a bytestring. For more information, see
+ * g_subprocess_append_args_va().
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_append_arg (GSubprocess *self,
+ const gchar *arg)
+{
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+
+ g_ptr_array_add (self->child_argv, g_strdup (arg));
+}
+
+
+/**
+ * g_subprocess_append_args:
+ * @self: a #GSubprocess:
+ * @first: (array zero-terminated=1) (element-type guint8): First argument to be appended
+ *
+ * Appends arguments to the child process. For more information, see
+ * g_subprocess_append_args_va().
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_append_args (GSubprocess *self,
+ const gchar *first,
+ ...)
+{
+ va_list args;
+
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (first != NULL);
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+
+ g_subprocess_append_arg (self, first);
+
+ va_start (args, first);
+ g_subprocess_append_args_va (self, args);
+ va_end (args);
+}
+
+/**
+ * g_subprocess_append_args_va:
+ * @self: a #GSubprocess
+ * @args: List of %NULL-terminated arguments
+ *
+ * Append the provided @args to the child argument vector.
+ *
+ * On Unix, the arguments are bytestrings. Note though that while
+ * it's possible to pass arbitrary bytestrings to subprocesses on
+ * Unix, not all utility programs are written to handle this
+ * correctly. You should typically only pass strings which are valid
+ * in the current locale encoding; see g_locale_to_utf8().
+ *
+ * On Windows, the arguments are in the GLib filename encoding
+ * (i.e. UTF-8).
+ *
+ * For more information, about how arguments are processed, see the
+ * documentation of g_spawn_async_with_pipes().
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_append_args_va (GSubprocess *self,
+ va_list args)
+{
+ GPtrArray *child_argv = NULL;
+ GSubprocess *ret;
+ const char *arg;
+
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+
+ va_start (args, first);
+
+ arg = first;
+ do
+ {
+ g_ptr_array_add (self->child_argv, g_strdup (arg));
+ } while ((arg = va_arg (args, const char *)) != NULL);
+
+ va_end (args);
+}
+
+/**** GSpawnFlags wrappers ****/
+
+/**
+ * g_subprocess_set_search_path:
+ * @self: a #GSubprocess
+ * @do_search_path: %TRUE if the system path should be searched
+ *
+ * Unlike the g_spawn_async_with_pipes() and related functions,
+ * the default for #GSubprocess is to search the system path.
+ *
+ * See the documentation for %G_SPAWN_SEARCH_PATH for details; setting
+ * @do_search_path to %FALSE is equivalent to not providing that flag.
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_search_path (GSubprocess *self,
+ gboolean do_search_path)
+{
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+
+ self->search_path = do_search_path;
+}
+
+/**
+ * g_subprocess_set_leave_descriptors_open:
+ * @self: a #GSubprocess
+ * @do_leave_descriptors_open: %TRUE if file descriptors should be left open
+ *
+ * See the documentation for %G_SPAWN_LEAVE_DESCRIPTORS_OPEN for
+ * details.
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_search_path (GSubprocess *self,
+ gboolean do_leave_descriptors_open)
+{
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+
+ self->leave_descriptors_open = do_leave_descriptors_open;
+}
+
+/**** Envronment control ****/
+
+/**
+ * g_subprocess_setenv:
+ * @self: a #GSubprocess
+ * @variable: the environment variable to set, must not contain '='
+ * @value: the value for to set the variable to
+ * @overwrite: whether to change the variable if it already exists
+ *
+ * This modifies the environment child process will be run in; it has
+ * no effect on the current process. See the documentation of
+ * g_environ_setenv() for more information about environment
+ * variables.
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_setenv (GSubprocess *self,
+ gchar *variable,
+ gchar *value,
+ gboolean overwrite)
+{
+ gchar **new_envp;
+
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+ g_return_if_fail (variable != NULL);
+
+ if (self->child_envp == NULL)
+ self->child_envp = g_get_environ ();
+
+ new_envp = g_environ_setenv (self->child_envp, variable, value, overwrite);
+ g_strfreev (self->child_envp);
+ self->child_envp = new_envp;
+}
+
+/**
+ * g_subprocess_unsetenv:
+ * @self: a #GSubprocess
+ * @variable: the environment variable to set, must not contain '='
+ *
+ * This modifies the environment child process will be run in; it has
+ * no effect on the current process. See the documentation of
+ * g_environ_unsetenv() for more information about environment
+ * variables.
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_unsetenv (GSubprocess *self,
+ const gchar *variable)
+{
+ gchar **new_envp;
+
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+ g_return_if_fail (variable != NULL);
+
+ if (self->child_envp == NULL)
+ self->child_envp = g_get_environ ();
+
+ new_envp = g_environ_unsetenv (self->child_envp, variable);
+ g_strfreev (self->child_envp);
+ self->child_envp = new_envp;
+}
+
+/**
+ * g_subprocess_override_environ:
+ * @self: a #GSubprocess
+ * @envp: (array zero-terminated=1): An environment list
+ *
+ * This completely replaces the environment child process will be run
+ * in; it has no effect on the current process. See the documentation
+ * of g_environ_setenv() for more information about environment
+ * variables.
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_override_environ (GSubprocess *self,
+ gchar **envp)
+{
+ gchar **new_envp;
+
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+ g_return_if_fail (envp != NULL);
+
+ g_strfreev (self->child_envp);
+ self->child_envp = g_strdupv (envp);
+}
+
+/**
+ * g_subprocess_set_working_directory:
+ * @self: a #GSubprocess
+ * @working_directory: (allow-none): Path to working directory, in the GLib file name encoding
+ *
+ * By default, the child process will inherit the working
+ * directory of the current process. This function allows
+ * overriding that default.
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_working_directory (GSubprocess *self,
+ const gchar *working_directory)
+{
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+
+ g_free (self->working_directory);
+ self->working_directory = g_strdup (working_directory);
+}
+
+/**
+ * g_subprocess_set_child_setup:
+ * @self: a #GSubprocess
+ * @child_setup: (allow-none): Function to run in the context of just-forked child
+ *
+ * This functionality is only available on Unix. See the
+ * documentation of g_spawn_async_with_pipes() for more information
+ * about @child_setup.
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_child_setup (GSubprocess *self,
+ GSpawnChildSetupFunc child_setup,
+ gpointer user_data)
+{
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+
+ self->child_setup = child_setup;
+ self->child_setup_user_data = user_data;
+}
+
+/**** Input and Output ****/
+
+/**
+ * g_subprocess_set_standard_input_file_path:
+ * @self: a #GSubprocess
+ * @file_path: String containing path to file to use as standard input
+ *
+ * This function allows providing a file as input to the given
+ * subprocess. The file will not be opened until g_subprocess_start()
+ * has been called.
+ *
+ * Calling this function overrides any previous calls, as well as
+ * other related functions such as
+ * g_subprocess_set_standard_input_unix_fd(),
+ * g_subprocess_set_standard_input_stream(), and
+ * g_subprocess_set_standard_input_to_devnull().
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_standard_input_file_path (GSubprocess *self,
+ const gchar *file_path)
+{
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+ g_return_if_fail (file_path != NULL);
+
+ g_clear_object (&self->stdin_stream);
+ self->stdin_to_devnull = FALSE;
+ self->stdin_fd = -1;
+
+ g_free (self->stdin_path);
+ self->stdin_path = g_strdup (file_path);
+}
+
+/**
+ * g_subprocess_set_standard_input_unix_fd:
+ * @self: a #GSubprocess
+ * @fd: File descriptor to use as standard input
+ *
+ * This function allows providing a file descriptor as input to the given
+ * subprocess.
+ *
+ * Calling this function overrides any previous calls, as well as
+ * other related functions such as
+ * g_subprocess_set_standard_input_file_path().
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_standard_input_unix_fd (GSubprocess *self,
+ gint fd)
+{
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+
+ g_clear_object (&self->stdin_stream);
+ g_free (self->stdin_path);
+ self->stdin_path = NULL;
+ self->stdin_to_devnull = FALSE;
+
+ self->stdin_fd = fd;
+}
+
+/**
+ * g_subprocess_set_standard_input_to_devnull:
+ * @self: a #GSubprocess
+ * @to_devnull: If %TRUE, redirect input from null stream, if %FALSE, inherit
+ *
+ * The default is for child processes to have their input stream
+ * pointed at a null stream (e.g. on Unix, /dev/null), because having
+ * multiple processes read from an input stream creates race
+ * conditions and is generally nonsensical. See the documentation of
+ * g_spawn_async_with_pipes() and %G_SPAWN_CHILD_INHERITS_STDIN.
+ *
+ * If @to_devnull is %FALSE, then this function will cause the
+ * standard input of the child process to be inherited.
+ *
+ * Calling this function overrides any previous calls, as well as
+ * other related functions such as
+ * g_subprocess_set_standard_input_file_path().
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_standard_input_to_devnull (GSubprocess *self,
+ gboolean to_devnull)
+{
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+
+ g_clear_object (&self->stdin_stream);
+ g_free (self->stdin_path);
+ self->stdin_path = NULL;
+ self->stdin_fd = -1;
+
+ self->stdin_to_devnull = to_devnull;
+}
+
+/**
+ * g_subprocess_set_standard_input_stream:
+ * @self: a #GSubprocess
+ * @stream: an input stream
+ *
+ * Use the provided stream as input to the child process. The stream
+ * will not be closed upon completion by default; however, you may
+ * safely drop other references to @stream, and then it will be
+ * automatically closed when @self itself is unreferenced.
+ *
+ * <note>
+ * If your input stream is from a file, such as that returned
+ * by g_file_read(), it is significantly more efficient
+ * to cause the child process to read the file directly
+ * via g_subprocess_set_standard_input_file_path().
+ * </note>
+ *
+ * Calling this function overrides any previous calls, as well as
+ * other related functions such as
+ * g_subprocess_set_standard_input_file_path().
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_standard_input_stream (GSubprocess *self,
+ GInputStream *stream)
+{
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+ g_return_if_fail (stream != NULL);
+
+ g_free (self->stdin_path);
+ self->stdin_path = NULL;
+ self->stdin_fd = -1;
+ self->stdin_to_devnull = FALSE;
+
+ g_clear_object (&self->stdin_stream);
+ self->stdin_stream = g_object_ref (stream);
+}
+
+/**
+ * g_subprocess_set_standard_input_bytes:
+ * @self: a #GSubprocess
+ * @buf: Buffer to use as input
+ *
+ * Use the provided data as input to the child process. This
+ * function simply wraps g_subprocess_set_standard_input_stream()
+ * using g_memory_input_stream_new_from_bytes().
+ *
+ * Calling this function overrides any previous calls, as well as
+ * other related functions such as
+ * g_subprocess_set_standard_input_file_path().
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_standard_input_bytes (GSubprocess *self,
+ GBytes *buf)
+{
+ GMemoryInputStream *stream;
+
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+ g_return_if_fail (buf != NULL);
+
+ stream = g_memory_input_stream_new_from_bytes (buf);
+ g_subprocess_set_standard_input_stream (self, stream);
+ g_object_unref (stream);
+}
+
+/**
+ * g_subprocess_set_standard_input_str:
+ * @self: a #GSubprocess
+ * @str: (array zero-terminated=1) (element-type guint8): Buffer to use as input
+ *
+ * Use the provided data as input to the child process. This function
+ * simply wraps g_subprocess_set_standard_input_bytes().
+ *
+ * Calling this function overrides any previous calls, as well as
+ * other related functions such as
+ * g_subprocess_set_standard_input_file_path().
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_standard_input_str (GSubprocess *self,
+ const gchar *str)
+{
+ GBytes *bytes;
+
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+ g_return_if_fail (str != NULL);
+
+ bytes = g_bytes_new (str, strlen (str));
+ g_subprocess_set_standard_input_bytes (self, bytes);
+ g_bytes_unref (bytes);
+}
+
+/**
+ * g_subprocess_set_standard_output_to_devnull:
+ * @self: a #GSubprocess
+ * @to_devnull: If %TRUE, redirect process output to null stream
+ *
+ * The default is for the child process to inherit the standard output
+ * of the current process. Specify %TRUE for @to_devnull to redirect it
+ * to the operating system's null stream.
+ *
+ * Calling this function overrides any previous calls, as well as
+ * other related functions such as
+ * g_subprocess_set_standard_output_file_path().
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_standard_output_to_devnull (GSubprocess *self,
+ gboolean to_devnull)
+{
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+
+ g_free (self->stdout_path);
+ self->stdout_path = NULL;
+ self->stdout_fd = -1;
+ g_clear_object (&self->stdout_stream);
+
+ self->stdout_to_devnull = to_devnull;
+}
+
+/**
+ * g_subprocess_set_standard_output_file_path:
+ * @self: a #GSubprocess
+ * @file_path: String containing path to file to use as standard input
+ *
+ * This function allows providing a file as standard output for the
+ * given subprocess. The file will not be opened until
+ * g_subprocess_start() has been called.
+ *
+ * Calling this function overrides any previous calls, as well as
+ * other related functions such as
+ * g_subprocess_set_standard_output_to_devnull().
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_standard_output_file_path (GSubprocess *self,
+ const gchar *file_path)
+{
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+
+ g_free (self->stdout_path);
+ self->stdout_path = NULL;
+ self->stdout_fd = -1;
+ g_clear_object (&self->stdout_stream);
+
+ self->stdout_to_devnull = to_devnull;
+}
+
+/**
+ * g_subprocess_set_standard_output_unix_fd:
+ * @self: a #GSubprocess
+ * @fd: File descriptor
+ *
+ * This function allows providing a file descriptor as standard output
+ * for the given subprocess.
+ *
+ * Calling this function overrides any previous calls, as well as
+ * other related functions such as
+ * g_subprocess_set_standard_output_file_path().
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_standard_output_unix_fd (GSubprocess *self,
+ gint fd)
+{
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+
+ g_free (self->stdout_path);
+ self->stdout_path = NULL;
+ self->stdout_to_devnull = FALSE;
+ g_clear_object (&self->stdout_stream);
+
+ self->stdout_fd = fd;
+}
+
+/**
+ * g_subprocess_set_standard_error_to_devnull:
+ * @self: a #GSubprocess
+ * @to_devnull: If %TRUE, redirect process error output to null stream
+ *
+ * The default is for the child process to inherit the standard error
+ * of the current process. Specify %TRUE for @to_devnull to redirect
+ * it to the operating system's null stream.
+ *
+ * Calling this function overrides any previous calls, as well as
+ * other related functions such as
+ * g_subprocess_set_standard_error_file_path().
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_standard_error_to_devnull (GSubprocess *self,
+ gboolean to_devnull)
+{
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+
+ g_free (self->stderr_path);
+ self->stderr_path = NULL;
+ self->stderr_fd = -1;
+ g_clear_object (&self->stderr_stream);
+
+ self->stderr_to_devnull = to_devnull;
+}
+
+/**
+ * g_subprocess_set_standard_error_file_path:
+ * @self: a #GSubprocess
+ * @file_path: String containing path to file to use as standard input
+ *
+ * This function allows providing a file as standard error for the
+ * given subprocess. The file will not be opened until
+ * g_subprocess_start() has been called.
+ *
+ * Calling this function overrides any previous calls, as well as
+ * other related functions such as
+ * g_subprocess_set_standard_error_to_devnull().
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_standard_error_file_path (GSubprocess *self,
+ const gchar *file_path)
+{
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+
+ g_free (self->stderr_path);
+ self->stderr_path = NULL;
+ self->stderr_fd = -1;
+ g_clear_object (&self->stderr_stream);
+
+ self->stderr_to_devnull = to_devnull;
+}
+
+/**
+ * g_subprocess_set_standard_error_unix_fd:
+ * @self: a #GSubprocess
+ * @fd: File descriptor
+ *
+ * This function allows providing a file descriptor as standard error
+ * for the given subprocess.
+ *
+ * Calling this function overrides any previous calls, as well as
+ * other related functions such as
+ * g_subprocess_set_standard_error_file_path().
+ *
+ * It invalid to call this function after g_subprocess_start() has
+ * been called.
+ */
+void
+g_subprocess_set_standard_error_unix_fd (GSubprocess *self,
+ gint fd)
+{
+ g_return_if_fail (G_IS_SUBPROCESS (self));
+ g_return_if_fail (self->state == G_SUBPROCESS_STATE_BUILDING);
+
+ g_free (self->stderr_path);
+ self->stderr_path = NULL;
+ self->stderr_to_devnull = FALSE;
+ g_clear_object (&self->stderr_stream);
+
+ self->stderr_fd = fd;
+}
+
+GInputStream *
+g_subprocess_request_standard_output (GSubprocess *self)
+{
+
+}
+
+GInputStream *
+g_subprocess_request_standard_error (GSubprocess *self)
+{
+}
diff --git a/gio/gsubprocess.h b/gio/gsubprocess.h
new file mode 100644
index 0000000..be9064d
--- /dev/null
+++ b/gio/gsubprocess.h
@@ -0,0 +1,174 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2012 Colin Walters <walters verbum org>
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Colin Walters <walters verbum org>
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_SUBPROCESS_H__
+#define __G_SUBPROCESS_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_SUBPROCESS (g_subprocess_get_type ())
+#define G_SUBPROCESS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_SUBPROCESS, GSubprocess))
+#define G_IS_SUBPROCESS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_SUBPROCESS))
+
+GType g_subprocess_get_type (void) G_GNUC_CONST;
+
+/**** Creation ****/
+
+GSubprocess * g_subprocess_new (void);
+
+GSubprocess * g_subprocess_new_with_args (const gchar *first,
+ ...) G_GNUC_NULL_TERMINATED;
+
+/**** Argument control ****/
+
+void g_subprocess_set_argv (GSubprocess *self,
+ gchar **argv);
+
+void g_subprocess_set_argv0 (GSubprocess *self,
+ const gchar *argv0);
+
+void g_subprocess_append_arg (GSubprocess *self,
+ const gchar *arg);
+
+void g_subprocess_append_args (GSubprocess *self,
+ const gchar *first,
+ ...) G_GNUC_NULL_TERMINATED;
+
+void g_subprocess_append_args_va (GSubprocess *self,
+ va_list args);
+
+/**** Envronment control ****/
+
+void g_subprocess_set_search_path (GSubprocess *self,
+ gboolean do_search_path);
+
+void g_subprocess_set_leave_descriptors_open (GSubprocess *self,
+ gboolean do_leave_descriptors_open);
+
+void g_subprocess_setenv (GSubprocess *self,
+ gchar *variable,
+ gchar *value,
+ gboolean overwrite);
+
+void g_subprocess_unsetenv (GSubprocess *self,
+ const gchar *variable);
+
+void g_subprocess_override_environ (GSubprocess *self,
+ gchar **envp);
+
+void g_subprocess_set_working_directory (GSubprocess *self,
+ const gchar *working_directory);
+
+void g_subprocess_set_child_setup (GSubprocess *self,
+ GSpawnChildSetupFunc child_setup,
+ gpointer user_data);
+
+/**** Input and Output ****/
+
+void g_subprocess_set_standard_input_file_path (GSubprocess *self,
+ const gchar *file_path);
+
+#ifdef G_OS_UNIX
+void g_subprocess_set_standard_input_unix_fd (GSubprocess *self,
+ gint fd);
+#endif
+
+void g_subprocess_set_standard_input_to_devnull (GSubprocess *self,
+ gboolean to_devnull);
+
+void g_subprocess_set_standard_input_stream (GSubprocess *self,
+ GInputStream *stream);
+
+void g_subprocess_set_standard_input_bytes (GSubprocess *self,
+ GBytes *buf);
+
+void g_subprocess_set_standard_input_str (GSubprocess *self,
+ const gchar *str);
+
+void g_subprocess_set_standard_output_to_devnull (GSubprocess *self,
+ gboolean to_devnull);
+
+void g_subprocess_set_standard_output_file_path (GSubprocess *self,
+ const gchar *file_path);
+
+#ifdef G_OS_UNIX
+void g_subprocess_set_standard_output_unix_fd (GSubprocess *self,
+ gint fd);
+#endif
+
+void g_subprocess_set_standard_error_to_devnull (GSubprocess *self,
+ gboolean to_devnull);
+
+void g_subprocess_set_standard_error_file_path (GSubprocess *self,
+ const gchar *file_path);
+
+#ifdef G_OS_UNIX
+void g_subprocess_set_standard_error_unix_fd (GSubprocess *self,
+ gint fd);
+#endif
+
+GInputStream *g_subprocess_request_standard_output (GSubprocess *self);
+GInputStream *g_subprocess_request_standard_error (GSubprocess *self);
+
+/**** Running ****/
+
+gboolean g_subprocess_start (GSubprocess *self,
+ GError **error);
+
+GPid g_subprocess_get_pid (GSubprocess *self);
+
+void g_subprocess_wait_async (GSubprocess *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+void g_subprocess_wait_async_finish (GSubprocess *self,
+ GAsyncResult *result,
+ GError **error);
+
+gboolean g_subprocess_wait_sync (GSubprocess *self,
+ GCancellable *cancellable,
+ GError **error);
+
+gint g_subprocess_get_exit_code (GSubprocess *self);
+
+/**** Static utility functions ****/
+
+gboolean g_subprocess_spawn_sync_get_output_utf8 (gchar **argv,
+ gchar **output_utf8,
+ GCancellable *cancellable,
+ GError **error);
+
+gboolean g_subprocess_spawn_sync_get_output_bytes (gchar **argv,
+ GBytes **output_bytes,
+ GCancellable *cancellable,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __G_SUBPROCESS_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]