improve bloom filter on send
[platform/upstream/glib.git] / gio / gapplicationcommandline.c
index af9d7a8..d5e508a 100644 (file)
+/*
+ * Copyright © 2010 Codethink Limited
+ *
+ * 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.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Ryan Lortie <desrt@desrt.ca>
+ */
+
+#include "config.h"
+
 #include "gapplicationcommandline.h"
 
+#include "glibintl.h"
+#include "gfile.h"
+
 #include <string.h>
 #include <stdio.h>
 
-G_DEFINE_TYPE (GApplicationCommandLine, g_application_command_line, G_TYPE_OBJECT)
-
+#ifdef G_OS_UNIX
+#include "gunixinputstream.h"
+#endif
+
+#ifdef G_OS_WIN32
+#include <windows.h>
+#undef environ
+#include "gwin32inputstream.h"
+#endif
+
+/**
+ * SECTION:gapplicationcommandline
+ * @title: GApplicationCommandLine
+ * @short_description: A command-line invocation of an application
+ * @include: gio/gio.h
+ * @see_also: #GApplication
+ *
+ * #GApplicationCommandLine represents a command-line invocation of
+ * an application.  It is created by #GApplication and emitted
+ * in the #GApplication::command-line signal and virtual function.
+ *
+ * The class contains the list of arguments that the program was invoked
+ * with.  It is also possible to query if the commandline invocation was
+ * local (ie: the current process is running in direct response to the
+ * invocation) or remote (ie: some other process forwarded the
+ * commandline to this process).
+ *
+ * The GApplicationCommandLine object can provide the @argc and @argv
+ * parameters for use with the #GOptionContext command-line parsing API,
+ * with the g_application_command_line_get_arguments() function. See
+ * [gapplication-example-cmdline3.c][gapplication-example-cmdline3]
+ * for an example.
+ *
+ * The exit status of the originally-invoked process may be set and
+ * messages can be printed to stdout or stderr of that process.  The
+ * lifecycle of the originally-invoked process is tied to the lifecycle
+ * of this object (ie: the process exits when the last reference is
+ * dropped).
+ *
+ * The main use for #GApplicationCommandLine (and the
+ * #GApplication::command-line signal) is 'Emacs server' like use cases:
+ * You can set the `EDITOR` environment variable to have e.g. git use
+ * your favourite editor to edit commit messages, and if you already
+ * have an instance of the editor running, the editing will happen
+ * in the running instance, instead of opening a new one. An important
+ * aspect of this use case is that the process that gets started by git
+ * does not return until the editing is done.
+ *
+ * Normally, the commandline is completely handled in the
+ * #GApplication::command-line handler. The launching instance exits
+ * once the signal handler in the primary instance has returned, and
+ * the return value of the signal handler becomes the exit status
+ * of the launching instance.
+ * |[<!-- language="C" -->
+ * static int
+ * command_line (GApplication            *application,
+ *               GApplicationCommandLine *cmdline)
+ * {
+ *   gchar **argv;
+ *   gint argc;
+ *   gint i;
+ *
+ *   argv = g_application_command_line_get_arguments (cmdline, &argc);
+ *
+ *   g_application_command_line_print (cmdline,
+ *                                     "This text is written back\n"
+ *                                     "to stdout of the caller\n");
+ *
+ *   for (i = 0; i < argc; i++)
+ *     g_print ("argument %d: %s\n", i, argv[i]);
+ *
+ *   g_strfreev (argv);
+ *
+ *   return 0;
+ * }
+ * ]|
+ * The complete example can be found here: 
+ * [gapplication-example-cmdline.c](https://git.gnome.org/browse/glib/tree/gio/tests/gapplication-example-cmdline.c)
+ *
+ * In more complicated cases, the handling of the comandline can be
+ * split between the launcher and the primary instance.
+ * |[<!-- language="C" -->
+ * static gboolean
+ *  test_local_cmdline (GApplication   *application,
+ *                      gchar        ***arguments,
+ *                      gint           *exit_status)
+ * {
+ *   gint i, j;
+ *   gchar **argv;
+ *
+ *   argv = *arguments;
+ *
+ *   i = 1;
+ *   while (argv[i])
+ *     {
+ *       if (g_str_has_prefix (argv[i], "--local-"))
+ *         {
+ *           g_print ("handling argument %s locally\n", argv[i]);
+ *           g_free (argv[i]);
+ *           for (j = i; argv[j]; j++)
+ *             argv[j] = argv[j + 1];
+ *         }
+ *       else
+ *         {
+ *           g_print ("not handling argument %s locally\n", argv[i]);
+ *           i++;
+ *         }
+ *     }
+ *
+ *   *exit_status = 0;
+ *
+ *   return FALSE;
+ * }
+ *
+ * static void
+ * test_application_class_init (TestApplicationClass *class)
+ * {
+ *   G_APPLICATION_CLASS (class)->local_command_line = test_local_cmdline;
+ *
+ *   ...
+ * }
+ * ]|
+ * In this example of split commandline handling, options that start
+ * with `--local-` are handled locally, all other options are passed
+ * to the #GApplication::command-line handler which runs in the primary
+ * instance.
+ *
+ * The complete example can be found here:
+ * [gapplication-example-cmdline2.c](https://git.gnome.org/browse/glib/tree/gio/tests/gapplication-example-cmdline2.c)
+ *
+ * If handling the commandline requires a lot of work, it may
+ * be better to defer it.
+ * |[<!-- language="C" -->
+ * static gboolean
+ * my_cmdline_handler (gpointer data)
+ * {
+ *   GApplicationCommandLine *cmdline = data;
+ *
+ *   // do the heavy lifting in an idle
+ *
+ *   g_application_command_line_set_exit_status (cmdline, 0);
+ *   g_object_unref (cmdline); // this releases the application
+ *
+ *   return G_SOURCE_REMOVE;
+ * }
+ *
+ * static int
+ * command_line (GApplication            *application,
+ *               GApplicationCommandLine *cmdline)
+ * {
+ *   // keep the application running until we are done with this commandline
+ *   g_application_hold (application);
+ *
+ *   g_object_set_data_full (G_OBJECT (cmdline),
+ *                           "application", application,
+ *                           (GDestroyNotify)g_application_release);
+ *
+ *   g_object_ref (cmdline);
+ *   g_idle_add (my_cmdline_handler, cmdline);
+ *
+ *   return 0;
+ * }
+ * ]|
+ * In this example the commandline is not completely handled before
+ * the #GApplication::command-line handler returns. Instead, we keep
+ * a reference to the #GApplicationCommandLine object and handle it
+ * later (in this example, in an idle). Note that it is necessary to
+ * hold the application until you are done with the commandline.
+ *
+ * The complete example can be found here:
+ * [gapplication-example-cmdline3.c](https://git.gnome.org/browse/glib/tree/gio/tests/gapplication-example-cmdline3.c)
+ */
+
+/**
+ * GApplicationCommandLineClass:
+ *
+ * The #GApplicationCommandLineClass-struct 
+ * contains private data only.
+ *
+ * Since: 2.28
+ **/
 enum
 {
   PROP_NONE,
   PROP_ARGUMENTS,
+  PROP_OPTIONS,
   PROP_PLATFORM_DATA,
   PROP_IS_REMOTE
 };
@@ -17,147 +221,79 @@ struct _GApplicationCommandLinePrivate
 {
   GVariant *platform_data;
   GVariant *arguments;
-  GVariant *cwd;
+  GVariant *options;
+  GVariantDict *options_dict;
+  gchar *cwd;
+
+  gchar **environ;
   gint exit_status;
 };
 
-#define IS_REMOTE(cmdline) ((cmdline)->priv->platform_data != NULL)
+G_DEFINE_TYPE_WITH_PRIVATE (GApplicationCommandLine, g_application_command_line, G_TYPE_OBJECT)
 
-void
-g_application_command_line_get_argc_argv (GApplicationCommandLine   *cmdline,
-                                          int                       *argc,
-                                          char                    ***argv)
-{
-  gsize len;
+/* All subclasses represent remote invocations of some kind. */
+#define IS_REMOTE(cmdline) (G_TYPE_FROM_INSTANCE (cmdline) != \
+                            G_TYPE_APPLICATION_COMMAND_LINE)
 
-  g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
-  g_return_if_fail (argc != NULL && argv != NULL);
-
-  *argv = g_variant_dup_bytestring_array (cmdline->priv->arguments, &len);
-  *argc = len;
-}
-
-GVariant *
-g_application_command_line_get_arguments (GApplicationCommandLine *cmdline)
+static void
+grok_platform_data (GApplicationCommandLine *cmdline)
 {
-  return g_variant_ref (cmdline->priv->arguments);
-}
+  GVariantIter iter;
+  const gchar *key;
+  GVariant *value;
 
-const gchar *
-g_application_command_line_get_cwd (GApplicationCommandLine *cmdline)
-{
-  if (cmdline->priv->cwd)
-    return g_variant_get_bytestring (cmdline->priv->cwd);
-  else
-    return NULL;
-}
+  g_variant_iter_init (&iter, cmdline->priv->platform_data);
 
-GVariant *
-g_application_command_line_get_cwd_variant (GApplicationCommandLine *cmdline)
-{
-  if (cmdline->priv->cwd)
-    return g_variant_ref (cmdline->priv->cwd);
-  else
-    return NULL;
-}
+  while (g_variant_iter_loop (&iter, "{&sv}", &key, &value))
+    if (strcmp (key, "cwd") == 0)
+      {
+        if (!cmdline->priv->cwd)
+          cmdline->priv->cwd = g_variant_dup_bytestring (value, NULL);
+      }
 
-gboolean
-g_application_command_line_get_is_remote (GApplicationCommandLine *cmdline)
-{
-  return IS_REMOTE (cmdline);
+    else if (strcmp (key, "environ") == 0)
+      {
+        if (!cmdline->priv->environ)
+          cmdline->priv->environ =
+            g_variant_dup_bytestring_array (value, NULL);
+      }
+
+    else if (strcmp (key, "options") == 0)
+      {
+        if (!cmdline->priv->options)
+          cmdline->priv->options = g_variant_ref (value);
+      }
 }
 
 static void
 g_application_command_line_real_print_literal (GApplicationCommandLine *cmdline,
                                                const gchar             *message)
 {
-  g_print ("%s\n", message);
+  g_print ("%s", message);
 }
 
 static void
 g_application_command_line_real_printerr_literal (GApplicationCommandLine *cmdline,
                                                   const gchar             *message)
 {
-  g_printerr ("%s\n", message);
+  g_printerr ("%s", message);
 }
 
-void
-g_application_command_line_print (GApplicationCommandLine *cmdline,
-                                  const gchar             *format,
-                                  ...)
+static GInputStream *
+g_application_command_line_real_get_stdin (GApplicationCommandLine *cmdline)
 {
-  gchar *message;
-  va_list ap;
-
-  g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
-  g_return_if_fail (format != NULL);
-
-  va_start (ap, format);
-  message = g_strdup_vprintf (format, ap);
-  va_end (ap);
-
-  G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
-    ->print_literal (cmdline, message);
-  g_free (message);
-}
-
-void
-g_application_command_line_printerr (GApplicationCommandLine *cmdline,
-                                     const gchar             *format,
-                                     ...)
-{
-  gchar *message;
-  va_list ap;
-
-  g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
-  g_return_if_fail (format != NULL);
-
-  va_start (ap, format);
-  message = g_strdup_vprintf (format, ap);
-  va_end (ap);
-
-  G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
-    ->printerr_literal (cmdline, message);
-  g_free (message);
-}
-
-void
-g_application_command_line_set_exit_status (GApplicationCommandLine *cmdline,
-                                            int                      exit_status)
-{
-  g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
-
-  cmdline->priv->exit_status = exit_status;
-}
-
-int
-g_application_command_line_get_exit_status (GApplicationCommandLine *cmdline)
-{
-  g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), -1);
-
-  return cmdline->priv->exit_status;
+#ifdef G_OS_UNIX
+  return g_unix_input_stream_new (0, FALSE);
+#else
+  return g_win32_input_stream_new (GetStdHandle (STD_INPUT_HANDLE), FALSE);
+#endif
 }
 
 static void
-grok_platform_data (GApplicationCommandLine *cmdline)
-{
-  GVariantIter iter;
-  const gchar *key;
-  GVariant *value;
-
-  g_variant_iter_init (&iter, cmdline->priv->platform_data);
-
-  while (g_variant_iter_loop (&iter, "{&sv}", &key, &value))
-    if (strcmp (key, "cwd") == 0)
-      {
-        if (!cmdline->priv->cwd)
-          cmdline->priv->cwd = g_variant_ref (value);
-      }
-}
-
-static void
-g_application_command_line_get_property (GObject *object, guint prop_id,
-                                         GValue *value, GParamSpec *pspec)
+g_application_command_line_get_property (GObject    *object,
+                                         guint       prop_id,
+                                         GValue     *value,
+                                         GParamSpec *pspec)
 {
   GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
 
@@ -181,8 +317,10 @@ g_application_command_line_get_property (GObject *object, guint prop_id,
 }
 
 static void
-g_application_command_line_set_property (GObject *object, guint prop_id,
-                                         const GValue *value, GParamSpec *pspec)
+g_application_command_line_set_property (GObject      *object,
+                                         guint         prop_id,
+                                         const GValue *value,
+                                         GParamSpec   *pspec)
 {
   GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
 
@@ -193,6 +331,11 @@ g_application_command_line_set_property (GObject *object, guint prop_id,
       cmdline->priv->arguments = g_value_dup_variant (value);
       break;
 
+    case PROP_OPTIONS:
+      g_assert (cmdline->priv->options == NULL);
+      cmdline->priv->options = g_value_dup_variant (value);
+      break;
+
     case PROP_PLATFORM_DATA:
       g_assert (cmdline->priv->platform_data == NULL);
       cmdline->priv->platform_data = g_value_dup_variant (value);
@@ -210,12 +353,19 @@ g_application_command_line_finalize (GObject *object)
 {
   GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
 
+  if (cmdline->priv->options_dict)
+    g_variant_dict_unref (cmdline->priv->options_dict);
+
+  if (cmdline->priv->options)
+      g_variant_unref (cmdline->priv->options);
+
   if (cmdline->priv->platform_data)
     g_variant_unref (cmdline->priv->platform_data);
   if (cmdline->priv->arguments)
     g_variant_unref (cmdline->priv->arguments);
-  if (cmdline->priv->cwd)
-    g_variant_unref (cmdline->priv->cwd);
+
+  g_free (cmdline->priv->cwd);
+  g_strfreev (cmdline->priv->environ);
 
   G_OBJECT_CLASS (g_application_command_line_parent_class)
     ->finalize (object);
@@ -224,10 +374,23 @@ g_application_command_line_finalize (GObject *object)
 static void
 g_application_command_line_init (GApplicationCommandLine *cmdline)
 {
-  cmdline->priv =
-    G_TYPE_INSTANCE_GET_PRIVATE (cmdline,
-                                 G_TYPE_APPLICATION_COMMAND_LINE,
-                                 GApplicationCommandLinePrivate);
+  cmdline->priv = g_application_command_line_get_instance_private (cmdline);
+}
+
+static void
+g_application_command_line_constructed (GObject *object)
+{
+  GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
+
+  if (IS_REMOTE (cmdline))
+    return;
+
+  /* In the local case, set cmd and environ */
+  if (!cmdline->priv->cwd)
+    cmdline->priv->cwd = g_get_current_dir ();
+
+  if (!cmdline->priv->environ)
+    cmdline->priv->environ = g_get_environ ();
 }
 
 static void
@@ -238,36 +401,427 @@ g_application_command_line_class_init (GApplicationCommandLineClass *class)
   object_class->get_property = g_application_command_line_get_property;
   object_class->set_property = g_application_command_line_set_property;
   object_class->finalize = g_application_command_line_finalize;
+  object_class->constructed = g_application_command_line_constructed;
+
   class->printerr_literal = g_application_command_line_real_printerr_literal;
   class->print_literal = g_application_command_line_real_print_literal;
+  class->get_stdin = g_application_command_line_real_get_stdin;
 
   g_object_class_install_property (object_class, PROP_ARGUMENTS,
-    g_param_spec_variant ("arguments", "commandline arguments",
-                          "the commandline that caused this cmdline",
+    g_param_spec_variant ("arguments",
+                          P_("Commandline arguments"),
+                          P_("The commandline that caused this ::command-line signal emission"),
                           G_VARIANT_TYPE_BYTESTRING_ARRAY, NULL,
                           G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
                           G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (object_class, PROP_OPTIONS,
+    g_param_spec_variant ("options",
+                          P_("Options"),
+                          P_("The options sent along with the commandline"),
+                          G_VARIANT_TYPE_VARDICT, NULL, G_PARAM_WRITABLE |
+                          G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
   g_object_class_install_property (object_class, PROP_PLATFORM_DATA,
-    g_param_spec_variant ("platform-data", "platform data",
-                          "platform-specific data for the cmdline",
+    g_param_spec_variant ("platform-data",
+                          P_("Platform data"),
+                          P_("Platform-specific data for the commandline"),
                           G_VARIANT_TYPE ("a{sv}"), NULL,
                           G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
                           G_PARAM_STATIC_STRINGS));
 
   g_object_class_install_property (object_class, PROP_IS_REMOTE,
-    g_param_spec_boolean ("is-remote", "is remote",
-                          "TRUE if this is a remote cmdline", FALSE,
+    g_param_spec_boolean ("is-remote",
+                          P_("Is remote"),
+                          P_("TRUE if this is a remote commandline"),
+                          FALSE,
                           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+}
+
 
-  g_type_class_add_private (class, sizeof (GApplicationCommandLinePrivate));
+/**
+ * g_application_command_line_get_arguments:
+ * @cmdline: a #GApplicationCommandLine
+ * @argc: (out) (allow-none): the length of the arguments array, or %NULL
+ *
+ * Gets the list of arguments that was passed on the command line.
+ *
+ * The strings in the array may contain non-UTF-8 data on UNIX (such as
+ * filenames or arguments given in the system locale) but are always in
+ * UTF-8 on Windows.
+ *
+ * If you wish to use the return value with #GOptionContext, you must
+ * use g_option_context_parse_strv().
+ *
+ * The return value is %NULL-terminated and should be freed using
+ * g_strfreev().
+ *
+ * Returns: (array length=argc) (transfer full): the string array
+ * containing the arguments (the argv)
+ *
+ * Since: 2.28
+ **/
+gchar **
+g_application_command_line_get_arguments (GApplicationCommandLine *cmdline,
+                                          int                     *argc)
+{
+  gchar **argv;
+  gsize len;
+
+  g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), NULL);
+
+  argv = g_variant_dup_bytestring_array (cmdline->priv->arguments, &len);
+
+  if (argc)
+    *argc = len;
+
+  return argv;
 }
 
+/**
+ * g_application_command_line_get_options_dict:
+ * @cmdline: a #GApplicationCommandLine
+ *
+ * Gets the options there were passed to g_application_command_line().
+ *
+ * If you did not override local_command_line() then these are the same
+ * options that were parsed according to the #GOptionEntrys added to the
+ * application with g_application_add_main_option_entries() and possibly
+ * modified from your GApplication::handle-local-options handler.
+ *
+ * If no options were sent then an empty dictionary is returned so that
+ * you don't need to check for %NULL.
+ *
+ * Returns: (transfer none): a #GVariantDict with the options
+ *
+ * Since: 2.40
+ **/
+GVariantDict *
+g_application_command_line_get_options_dict (GApplicationCommandLine *cmdline)
+{
+  g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), NULL);
+
+  if (!cmdline->priv->options_dict)
+    cmdline->priv->options_dict = g_variant_dict_new (cmdline->priv->options);
+
+  return cmdline->priv->options_dict;
+}
+
+/**
+ * g_application_command_line_get_stdin:
+ * @cmdline: a #GApplicationCommandLine
+ *
+ * Gets the stdin of the invoking process.
+ *
+ * The #GInputStream can be used to read data passed to the standard
+ * input of the invoking process.
+ * This doesn't work on all platforms.  Presently, it is only available
+ * on UNIX when using a DBus daemon capable of passing file descriptors.
+ * If stdin is not available then %NULL will be returned.  In the
+ * future, support may be expanded to other platforms.
+ *
+ * You must only call this function once per commandline invocation.
+ *
+ * Returns: (transfer full): a #GInputStream for stdin
+ *
+ * Since: 2.34
+ **/
+GInputStream *
+g_application_command_line_get_stdin (GApplicationCommandLine *cmdline)
+{
+  return G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)->get_stdin (cmdline);
+}
+
+/**
+ * g_application_command_line_get_cwd:
+ * @cmdline: a #GApplicationCommandLine
+ *
+ * Gets the working directory of the command line invocation.
+ * The string may contain non-utf8 data.
+ *
+ * It is possible that the remote application did not send a working
+ * directory, so this may be %NULL.
+ *
+ * The return value should not be modified or freed and is valid for as
+ * long as @cmdline exists.
+ *
+ * Returns: the current directory, or %NULL
+ *
+ * Since: 2.28
+ **/
+const gchar *
+g_application_command_line_get_cwd (GApplicationCommandLine *cmdline)
+{
+  return cmdline->priv->cwd;
+}
+
+/**
+ * g_application_command_line_get_environ:
+ * @cmdline: a #GApplicationCommandLine
+ *
+ * Gets the contents of the 'environ' variable of the command line
+ * invocation, as would be returned by g_get_environ(), ie as a
+ * %NULL-terminated list of strings in the form 'NAME=VALUE'.
+ * The strings may contain non-utf8 data.
+ *
+ * The remote application usually does not send an environment.  Use
+ * %G_APPLICATION_SEND_ENVIRONMENT to affect that.  Even with this flag
+ * set it is possible that the environment is still not available (due
+ * to invocation messages from other applications).
+ *
+ * The return value should not be modified or freed and is valid for as
+ * long as @cmdline exists.
+ *
+ * See g_application_command_line_getenv() if you are only interested
+ * in the value of a single environment variable.
+ *
+ * Returns: (array zero-terminated=1) (transfer none): the environment
+ * strings, or %NULL if they were not sent
+ *
+ * Since: 2.28
+ **/
+const gchar * const *
+g_application_command_line_get_environ (GApplicationCommandLine *cmdline)
+{
+  return (const gchar **)cmdline->priv->environ;
+}
+
+/**
+ * g_application_command_line_getenv:
+ * @cmdline: a #GApplicationCommandLine
+ * @name: the environment variable to get
+ *
+ * Gets the value of a particular environment variable of the command
+ * line invocation, as would be returned by g_getenv().  The strings may
+ * contain non-utf8 data.
+ *
+ * The remote application usually does not send an environment.  Use
+ * %G_APPLICATION_SEND_ENVIRONMENT to affect that.  Even with this flag
+ * set it is possible that the environment is still not available (due
+ * to invocation messages from other applications).
+ *
+ * The return value should not be modified or freed and is valid for as
+ * long as @cmdline exists.
+ *
+ * Returns: the value of the variable, or %NULL if unset or unsent
+ *
+ * Since: 2.28
+ **/
+const gchar *
+g_application_command_line_getenv (GApplicationCommandLine *cmdline,
+                                   const gchar             *name)
+{
+  gint length = strlen (name);
+  gint i;
+
+  /* TODO: expand on windows */
+  if (cmdline->priv->environ)
+    for (i = 0; cmdline->priv->environ[i]; i++)
+      if (strncmp (cmdline->priv->environ[i], name, length) == 0 &&
+          cmdline->priv->environ[i][length] == '=')
+        return cmdline->priv->environ[i] + length + 1;
+
+  return NULL;
+}
+
+/**
+ * g_application_command_line_get_is_remote:
+ * @cmdline: a #GApplicationCommandLine
+ *
+ * Determines if @cmdline represents a remote invocation.
+ *
+ * Returns: %TRUE if the invocation was remote
+ *
+ * Since: 2.28
+ **/
+gboolean
+g_application_command_line_get_is_remote (GApplicationCommandLine *cmdline)
+{
+  return IS_REMOTE (cmdline);
+}
+
+/**
+ * g_application_command_line_print:
+ * @cmdline: a #GApplicationCommandLine
+ * @format: a printf-style format string
+ * @...: arguments, as per @format
+ *
+ * Formats a message and prints it using the stdout print handler in the
+ * invoking process.
+ *
+ * If @cmdline is a local invocation then this is exactly equivalent to
+ * g_print().  If @cmdline is remote then this is equivalent to calling
+ * g_print() in the invoking process.
+ *
+ * Since: 2.28
+ **/
+void
+g_application_command_line_print (GApplicationCommandLine *cmdline,
+                                  const gchar             *format,
+                                  ...)
+{
+  gchar *message;
+  va_list ap;
+
+  g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
+  g_return_if_fail (format != NULL);
+
+  va_start (ap, format);
+  message = g_strdup_vprintf (format, ap);
+  va_end (ap);
+
+  G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
+    ->print_literal (cmdline, message);
+  g_free (message);
+}
+
+/**
+ * g_application_command_line_printerr:
+ * @cmdline: a #GApplicationCommandLine
+ * @format: a printf-style format string
+ * @...: arguments, as per @format
+ *
+ * Formats a message and prints it using the stderr print handler in the
+ * invoking process.
+ *
+ * If @cmdline is a local invocation then this is exactly equivalent to
+ * g_printerr().  If @cmdline is remote then this is equivalent to
+ * calling g_printerr() in the invoking process.
+ *
+ * Since: 2.28
+ **/
+void
+g_application_command_line_printerr (GApplicationCommandLine *cmdline,
+                                     const gchar             *format,
+                                     ...)
+{
+  gchar *message;
+  va_list ap;
+
+  g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
+  g_return_if_fail (format != NULL);
+
+  va_start (ap, format);
+  message = g_strdup_vprintf (format, ap);
+  va_end (ap);
+
+  G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
+    ->printerr_literal (cmdline, message);
+  g_free (message);
+}
+
+/**
+ * g_application_command_line_set_exit_status:
+ * @cmdline: a #GApplicationCommandLine
+ * @exit_status: the exit status
+ *
+ * Sets the exit status that will be used when the invoking process
+ * exits.
+ *
+ * The return value of the #GApplication::command-line signal is
+ * passed to this function when the handler returns.  This is the usual
+ * way of setting the exit status.
+ *
+ * In the event that you want the remote invocation to continue running
+ * and want to decide on the exit status in the future, you can use this
+ * call.  For the case of a remote invocation, the remote process will
+ * typically exit when the last reference is dropped on @cmdline.  The
+ * exit status of the remote process will be equal to the last value
+ * that was set with this function.
+ *
+ * In the case that the commandline invocation is local, the situation
+ * is slightly more complicated.  If the commandline invocation results
+ * in the mainloop running (ie: because the use-count of the application
+ * increased to a non-zero value) then the application is considered to
+ * have been 'successful' in a certain sense, and the exit status is
+ * always zero.  If the application use count is zero, though, the exit
+ * status of the local #GApplicationCommandLine is used.
+ *
+ * Since: 2.28
+ **/
+void
+g_application_command_line_set_exit_status (GApplicationCommandLine *cmdline,
+                                            int                      exit_status)
+{
+  g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
+
+  cmdline->priv->exit_status = exit_status;
+}
+
+/**
+ * g_application_command_line_get_exit_status:
+ * @cmdline: a #GApplicationCommandLine
+ *
+ * Gets the exit status of @cmdline.  See
+ * g_application_command_line_set_exit_status() for more information.
+ *
+ * Returns: the exit status
+ *
+ * Since: 2.28
+ **/
+int
+g_application_command_line_get_exit_status (GApplicationCommandLine *cmdline)
+{
+  g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), -1);
+
+  return cmdline->priv->exit_status;
+}
+
+/**
+ * g_application_command_line_get_platform_data:
+ * @cmdline: #GApplicationCommandLine
+ *
+ * Gets the platform data associated with the invocation of @cmdline.
+ *
+ * This is a #GVariant dictionary containing information about the
+ * context in which the invocation occurred.  It typically contains
+ * information like the current working directory and the startup
+ * notification ID.
+ *
+ * For local invocation, it will be %NULL.
+ *
+ * Returns: (nullable): the platform data, or %NULL
+ *
+ * Since: 2.28
+ **/
 GVariant *
 g_application_command_line_get_platform_data (GApplicationCommandLine *cmdline)
 {
   g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), NULL);
-  g_return_val_if_fail (IS_REMOTE (cmdline), NULL);
 
-  return g_variant_ref (cmdline->priv->platform_data);
+  if (cmdline->priv->platform_data)
+    return g_variant_ref (cmdline->priv->platform_data);
+  else
+      return NULL;
+}
+
+/**
+ * g_application_command_line_create_file_for_arg:
+ * @cmdline: a #GApplicationCommandLine
+ * @arg: an argument from @cmdline
+ *
+ * Creates a #GFile corresponding to a filename that was given as part
+ * of the invocation of @cmdline.
+ *
+ * This differs from g_file_new_for_commandline_arg() in that it
+ * resolves relative pathnames using the current working directory of
+ * the invoking process rather than the local process.
+ *
+ * Returns: (transfer full): a new #GFile
+ *
+ * Since: 2.36
+ **/
+GFile *
+g_application_command_line_create_file_for_arg (GApplicationCommandLine *cmdline,
+                                                const gchar             *arg)
+{
+  g_return_val_if_fail (arg != NULL, NULL);
+
+  if (cmdline->priv->cwd)
+    return g_file_new_for_commandline_arg_and_cwd (arg, cmdline->priv->cwd);
+
+  g_warning ("Requested creation of GFile for commandline invocation that did not send cwd. "
+             "Using cwd of local process to resolve relative path names.");
+
+  return g_file_new_for_commandline_arg (arg);
 }