Below is the file 'glib/ocaml-gspawn.c' from this revision. You can also download the file.
#include <glib.h> #ifdef G_OS_UNIX # include <sys/wait.h> #endif #include <caml/mlvalues.h> #include <caml/alloc.h> #include <caml/memory.h> #include <caml/fail.h> #include <caml/callback.h> #include <caml/signals.h> #include "wrappers.h" #include "ml_glib.h" #define Val_none Val_unit CAMLprim value ml_g_spawn_init (value unit) { ml_register_exn_map (G_SPAWN_ERROR, "g_spawn_error"); return Val_unit; } #include "gspawn_tags.h" #include "gspawn_tags.c" static Make_Flags_val(Spawn_flags_val) static gchar ** convert_stringv (value argv) { gchar **res; guint i, len; value l; for (l = argv, len = 0; l != Val_emptylist; l = Field(l, 1)) len++; res = g_new (gchar *, len + 1); for (i = 0; i < len; i++) { res[i] = g_strdup (String_val (Field (argv, 0))); argv = Field (argv, 1); } res[len] = NULL; return res; } static void ml_g_spawn_child_setup (gpointer user_data) { value *closure = user_data; callback_exn (*closure, Val_unit); } static value wrap_pid (GPid pid) { #if defined (G_OS_UNIX) return Val_int (pid); #elif defined (G_OS_WIN32) return Val_pointer (pid); #else # error "unsupported OS" #endif } #define copy_caml_string(v) g_strdup (String_val (v)) #define PIPE_IN (1 << (0 + 1)) #define PIPE_OUT (1 << (1 + 1)) #define PIPE_ERR (1 << (2 + 1)) CAMLprim value ml_g_spawn_async_with_pipes (value o_working_directory, value o_envp, value o_child_setup, value v_flags, value v_pipes, value v_argv) { GError *error = NULL; gchar *working_directory; gchar **argv; gchar **envp; GSpawnFlags flags; value child_setup; GPid pid, *child_pid; gint s_in, *p_in, s_out, *p_out, s_err, *p_err; flags = Flags_Spawn_flags_val (v_flags); if ( (v_pipes & PIPE_IN && flags & G_SPAWN_CHILD_INHERITS_STDIN) || (v_pipes & PIPE_OUT && flags & G_SPAWN_STDOUT_TO_DEV_NULL) || (v_pipes & PIPE_ERR && flags & G_SPAWN_STDERR_TO_DEV_NULL)) invalid_argument ("Gspawn.async_with_pipes: incompatible flags arguments"); working_directory = Option_val (o_working_directory, copy_caml_string, NULL); argv = convert_stringv (v_argv); envp = Option_val (o_envp, convert_stringv, NULL); p_in = v_pipes & PIPE_IN ? &s_in : NULL; p_out = v_pipes & PIPE_OUT ? &s_out : NULL; p_err = v_pipes & PIPE_ERR ? &s_err : NULL; child_setup = Option_val (o_child_setup, ID, 0); child_pid = flags & G_SPAWN_DO_NOT_REAP_CHILD ? &pid : NULL; g_spawn_async_with_pipes (working_directory, argv, envp, flags, child_setup ? ml_g_spawn_child_setup : NULL, &child_setup, child_pid, p_in, p_out, p_err, &error); g_free (working_directory); g_strfreev (argv); g_strfreev (envp); if (error) ml_raise_gerror (error); { CAMLparam0(); CAMLlocal5(res, v_pid, v_in, v_out, v_err); v_pid = child_pid ? ml_some (wrap_pid (pid)) : Val_none; v_in = p_in ? ml_some (Val_int (s_in)) : Val_none; v_out = p_out ? ml_some (Val_int (s_out)) : Val_none; v_err = p_err ? ml_some (Val_int (s_err)) : Val_none; res = alloc_small (4, 0); Field (res, 0) = v_pid; Field (res, 1) = v_in; Field (res, 2) = v_out; Field (res, 3) = v_err; CAMLreturn (res); } } ML_bc6 (ml_g_spawn_async_with_pipes) static value convert_exit_status (int status) { value r; #ifdef G_OS_UNIX if (WIFEXITED(status)) { r = alloc_small (1, 0); Field (r, 0) = Val_long (WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { r = alloc_small (1, 1); Field (r, 0) = Val_long (WTERMSIG(status)); } else if (WIFSTOPPED(status)) { r = alloc_small (1, 2); Field (r, 0) = Val_long (WSTOPSIG(status)); } else invalid_argument ("Gspawn.sync: don't know how to convert the exit status"); #else r = alloc_small (1, 0); Field (r, 0) = Val_long (status); #endif return r; } static value convert_sync_status (int exit_status, gchar *standard_output, gchar *standard_error) { CAMLparam0(); CAMLlocal4(res, status, out, err); status = convert_exit_status (exit_status); out = copy_string (standard_output ? standard_output : ""); g_free (standard_output); err = copy_string (standard_error ? standard_error : ""); g_free (standard_error); res = alloc_small (3, 0); Field (res, 0) = status; Field (res, 1) = out; Field (res, 2) = err; CAMLreturn (res); } CAMLprim value ml_g_spawn_sync (value o_working_directory, value o_envp, value o_child_setup, value v_flags, value v_argv) { GError *error = NULL; gchar *working_directory; gchar **argv; gchar **envp; GSpawnFlags flags; value child_setup; gchar *standard_output; gchar *standard_error; gint exit_status; flags = Flags_Spawn_flags_val (v_flags); working_directory = Option_val (o_working_directory, copy_caml_string, NULL); argv = convert_stringv (v_argv); envp = Option_val (o_envp, convert_stringv, NULL); child_setup = Option_val (o_child_setup, ID, 0); standard_output = NULL; standard_error = NULL; caml_enter_blocking_section (); g_spawn_sync (working_directory, argv, envp, flags, child_setup ? ml_g_spawn_child_setup : NULL, &child_setup, &standard_output, &standard_error, &exit_status, &error); caml_leave_blocking_section (); g_free (working_directory); g_strfreev (argv); g_strfreev (envp); if (error) ml_raise_gerror (error); return convert_sync_status (exit_status, standard_output, standard_error); } CAMLprim value ml_g_spawn_command_line_sync (value cmd) { GError *error = NULL; gchar *command; gchar *standard_output; gchar *standard_error; gint exit_status; standard_output = NULL; standard_error = NULL; command = copy_caml_string (cmd); caml_enter_blocking_section (); g_spawn_command_line_sync (command, &standard_output, &standard_error, &exit_status, &error); caml_leave_blocking_section (); g_free (command); if (error) ml_raise_gerror (error); return convert_sync_status (exit_status, standard_output, standard_error); } CAMLprim value ml_g_spawn_command_line_async (value cmd) { GError *error = NULL; gchar *command; command = copy_caml_string (cmd); caml_enter_blocking_section (); g_spawn_command_line_async (command, &error); caml_leave_blocking_section (); g_free (command); if (error) ml_raise_gerror (error); return Val_unit; } #if defined (G_OS_UNIX) # define GPid_val(v) (GPid)Int_val(v) #elif defined (G_OS_WIN32) # define GPid_val(v) (GPid)Pointer_val(v) #else # error "unsupported OS" #endif CAMLprim value ml_int_of_pid (value pid) { #ifndef G_OS_UNIX return Val_int (0); #else return pid; #endif } ML_1(g_spawn_close_pid, GPid_val, Unit) static void ml_g_child_watch_func (GPid pid, gint status, gpointer data) { value *closure = data; callback_exn (*closure, Val_int (status)); } CAMLprim value ml_g_add_child_watch_full (value o_prio, value pid, value callback) { guint id; id = g_child_watch_add_full (Option_val (o_prio, Int_val, G_PRIORITY_DEFAULT), GPid_val (pid), ml_g_child_watch_func, ml_global_root_new (callback), ml_global_root_destroy); return Val_long (id); }