(root)/
glib-2.79.0/
gio/
gapplicationcommandline.c
       1  /*
       2   * Copyright © 2010 Codethink Limited
       3   *
       4   * SPDX-License-Identifier: LGPL-2.1-or-later
       5   *
       6   * This library is free software; you can redistribute it and/or
       7   * modify it under the terms of the GNU Lesser General Public
       8   * License as published by the Free Software Foundation; either
       9   * version 2.1 of the License, or (at your option) any later version.
      10   *
      11   * This library is distributed in the hope that it will be useful, but
      12   * WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14   * Lesser General Public License for more details.
      15   *
      16   * You should have received a copy of the GNU Lesser General Public
      17   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18   *
      19   * Authors: Ryan Lortie <desrt@desrt.ca>
      20   */
      21  
      22  #include "config.h"
      23  
      24  #include "gapplicationcommandline.h"
      25  
      26  #include "glibintl.h"
      27  #include "gfile.h"
      28  
      29  #include <string.h>
      30  #include <stdio.h>
      31  
      32  #ifdef G_OS_UNIX
      33  #include "gunixinputstream.h"
      34  #endif
      35  
      36  #ifdef G_OS_WIN32
      37  #include <windows.h>
      38  #undef environ
      39  #include "gwin32inputstream.h"
      40  #endif
      41  
      42  /**
      43   * GApplicationCommandLine:
      44   *
      45   * `GApplicationCommandLine` represents a command-line invocation of
      46   * an application.
      47   *
      48   * It is created by [class@Gio.Application] and emitted
      49   * in the [signal@Gio.Application::command-line] signal and virtual function.
      50   *
      51   * The class contains the list of arguments that the program was invoked
      52   * with. It is also possible to query if the commandline invocation was
      53   * local (ie: the current process is running in direct response to the
      54   * invocation) or remote (ie: some other process forwarded the
      55   * commandline to this process).
      56   *
      57   * The `GApplicationCommandLine` object can provide the @argc and @argv
      58   * parameters for use with the [struct@Glib.OptionContext] command-line parsing API,
      59   * with the [method@Gio.ApplicationCommandLine.get_arguments] function. See
      60   * [gapplication-example-cmdline3.c][gapplication-example-cmdline3]
      61   * for an example.
      62   *
      63   * The exit status of the originally-invoked process may be set and
      64   * messages can be printed to stdout or stderr of that process.
      65   *
      66   * For remote invocation, the originally-invoked process exits when
      67   * [method@Gio.ApplicationCommandLine.done] method is called. This method is
      68   * also automatically called when the object is disposed.
      69   *
      70   * The main use for `GApplicationCommandLine` (and the
      71   * [signal@Gio.Application::command-line] signal) is 'Emacs server' like use cases:
      72   * You can set the `EDITOR` environment variable to have e.g. git use
      73   * your favourite editor to edit commit messages, and if you already
      74   * have an instance of the editor running, the editing will happen
      75   * in the running instance, instead of opening a new one. An important
      76   * aspect of this use case is that the process that gets started by git
      77   * does not return until the editing is done.
      78   *
      79   * Normally, the commandline is completely handled in the
      80   * [signal@Gio.Application::command-line] handler. The launching instance exits
      81   * once the signal handler in the primary instance has returned, and
      82   * the return value of the signal handler becomes the exit status
      83   * of the launching instance.
      84   *
      85   * ```c
      86   * static int
      87   * command_line (GApplication            *application,
      88   *               GApplicationCommandLine *cmdline)
      89   * {
      90   *   gchar **argv;
      91   *   gint argc;
      92   *   gint i;
      93   *
      94   *   argv = g_application_command_line_get_arguments (cmdline, &argc);
      95   *
      96   *   g_application_command_line_print (cmdline,
      97   *                                     "This text is written back\n"
      98   *                                     "to stdout of the caller\n");
      99   *
     100   *   for (i = 0; i < argc; i++)
     101   *     g_print ("argument %d: %s\n", i, argv[i]);
     102   *
     103   *   g_strfreev (argv);
     104   *
     105   *   return 0;
     106   * }
     107   * ```
     108   *
     109   * The complete example can be found here:
     110   * [gapplication-example-cmdline.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gapplication-example-cmdline.c)
     111   *
     112   * In more complicated cases, the handling of the commandline can be
     113   * split between the launcher and the primary instance.
     114   *
     115   * ```c
     116   * static gboolean
     117   *  test_local_cmdline (GApplication   *application,
     118   *                      gchar        ***arguments,
     119   *                      gint           *exit_status)
     120   * {
     121   *   gint i, j;
     122   *   gchar **argv;
     123   *
     124   *   argv = *arguments;
     125   *
     126   *   if (argv[0] == NULL)
     127   *     {
     128   *       *exit_status = 0;
     129   *       return FALSE;
     130   *     }
     131   *
     132   *   i = 1;
     133   *   while (argv[i])
     134   *     {
     135   *       if (g_str_has_prefix (argv[i], "--local-"))
     136   *         {
     137   *           g_print ("handling argument %s locally\n", argv[i]);
     138   *           g_free (argv[i]);
     139   *           for (j = i; argv[j]; j++)
     140   *             argv[j] = argv[j + 1];
     141   *         }
     142   *       else
     143   *         {
     144   *           g_print ("not handling argument %s locally\n", argv[i]);
     145   *           i++;
     146   *         }
     147   *     }
     148   *
     149   *   *exit_status = 0;
     150   *
     151   *   return FALSE;
     152   * }
     153   *
     154   * static void
     155   * test_application_class_init (TestApplicationClass *class)
     156   * {
     157   *   G_APPLICATION_CLASS (class)->local_command_line = test_local_cmdline;
     158   *
     159   *   ...
     160   * }
     161   * ```
     162   *
     163   * In this example of split commandline handling, options that start
     164   * with `--local-` are handled locally, all other options are passed
     165   * to the [signal@Gio.Application::command-line] handler which runs in the primary
     166   * instance.
     167   *
     168   * The complete example can be found here:
     169   * [gapplication-example-cmdline2.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gapplication-example-cmdline2.c)
     170   *
     171   * If handling the commandline requires a lot of work, it may be better to defer it.
     172   *
     173   * ```c
     174   * static gboolean
     175   * my_cmdline_handler (gpointer data)
     176   * {
     177   *   GApplicationCommandLine *cmdline = data;
     178   *
     179   *   // do the heavy lifting in an idle
     180   *
     181   *   g_application_command_line_set_exit_status (cmdline, 0);
     182   *   g_object_unref (cmdline); // this releases the application
     183   *
     184   *   return G_SOURCE_REMOVE;
     185   * }
     186   *
     187   * static int
     188   * command_line (GApplication            *application,
     189   *               GApplicationCommandLine *cmdline)
     190   * {
     191   *   // keep the application running until we are done with this commandline
     192   *   g_application_hold (application);
     193   *
     194   *   g_object_set_data_full (G_OBJECT (cmdline),
     195   *                           "application", application,
     196   *                           (GDestroyNotify)g_application_release);
     197   *
     198   *   g_object_ref (cmdline);
     199   *   g_idle_add (my_cmdline_handler, cmdline);
     200   *
     201   *   return 0;
     202   * }
     203   * ```
     204   *
     205   * In this example the commandline is not completely handled before
     206   * the [signal@Gio.Application::command-line] handler returns. Instead, we keep
     207   * a reference to the `GApplicationCommandLine` object and handle it
     208   * later (in this example, in an idle). Note that it is necessary to
     209   * hold the application until you are done with the commandline.
     210   *
     211   * The complete example can be found here:
     212   * [gapplication-example-cmdline3.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gapplication-example-cmdline3.c)
     213   */
     214  
     215  /**
     216   * GApplicationCommandLineClass:
     217   *
     218   * The #GApplicationCommandLineClass-struct 
     219   * contains private data only.
     220   *
     221   * Since: 2.28
     222   **/
     223  enum
     224  {
     225    PROP_NONE,
     226    PROP_ARGUMENTS,
     227    PROP_OPTIONS,
     228    PROP_PLATFORM_DATA,
     229    PROP_IS_REMOTE
     230  };
     231  
     232  struct _GApplicationCommandLinePrivate
     233  {
     234    GVariant *platform_data;
     235    GVariant *arguments;
     236    GVariant *options;
     237    GVariantDict *options_dict;
     238    gchar *cwd;  /* in GLib filename encoding, not UTF-8 */
     239  
     240    gchar **environ;
     241    gint exit_status;
     242    gboolean done;
     243  };
     244  
     245  G_DEFINE_TYPE_WITH_PRIVATE (GApplicationCommandLine, g_application_command_line, G_TYPE_OBJECT)
     246  
     247  /* All subclasses represent remote invocations of some kind. */
     248  #define IS_REMOTE(cmdline) (G_TYPE_FROM_INSTANCE (cmdline) != \
     249                              G_TYPE_APPLICATION_COMMAND_LINE)
     250  
     251  static void
     252  grok_platform_data (GApplicationCommandLine *cmdline)
     253  {
     254    GVariantIter iter;
     255    const gchar *key;
     256    GVariant *value;
     257  
     258    g_variant_iter_init (&iter, cmdline->priv->platform_data);
     259  
     260    while (g_variant_iter_loop (&iter, "{&sv}", &key, &value))
     261      if (strcmp (key, "cwd") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BYTESTRING))
     262        {
     263          if (!cmdline->priv->cwd)
     264            cmdline->priv->cwd = g_variant_dup_bytestring (value, NULL);
     265        }
     266  
     267      else if (strcmp (key, "environ") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BYTESTRING_ARRAY))
     268        {
     269          if (!cmdline->priv->environ)
     270            cmdline->priv->environ =
     271              g_variant_dup_bytestring_array (value, NULL);
     272        }
     273  
     274      else if (strcmp (key, "options") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_VARDICT))
     275        {
     276          if (!cmdline->priv->options)
     277            cmdline->priv->options = g_variant_ref (value);
     278        }
     279  }
     280  
     281  static void
     282  g_application_command_line_real_print_literal (GApplicationCommandLine *cmdline,
     283                                                 const gchar             *message)
     284  {
     285    g_print ("%s", message);
     286  }
     287  
     288  static void
     289  g_application_command_line_real_printerr_literal (GApplicationCommandLine *cmdline,
     290                                                    const gchar             *message)
     291  {
     292    g_printerr ("%s", message);
     293  }
     294  
     295  static GInputStream *
     296  g_application_command_line_real_get_stdin (GApplicationCommandLine *cmdline)
     297  {
     298  #ifdef G_OS_UNIX
     299    return g_unix_input_stream_new (0, FALSE);
     300  #else
     301    return g_win32_input_stream_new (GetStdHandle (STD_INPUT_HANDLE), FALSE);
     302  #endif
     303  }
     304  
     305  static void
     306  g_application_command_line_real_done (GApplicationCommandLine *cmdline)
     307  {
     308  }
     309  
     310  static void
     311  g_application_command_line_get_property (GObject    *object,
     312                                           guint       prop_id,
     313                                           GValue     *value,
     314                                           GParamSpec *pspec)
     315  {
     316    GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
     317  
     318    switch (prop_id)
     319      {
     320      case PROP_ARGUMENTS:
     321        g_value_set_variant (value, cmdline->priv->arguments);
     322        break;
     323  
     324      case PROP_PLATFORM_DATA:
     325        g_value_set_variant (value, cmdline->priv->platform_data);
     326        break;
     327  
     328      case PROP_IS_REMOTE:
     329        g_value_set_boolean (value, IS_REMOTE (cmdline));
     330        break;
     331  
     332      default:
     333        g_assert_not_reached ();
     334      }
     335  }
     336  
     337  static void
     338  g_application_command_line_set_property (GObject      *object,
     339                                           guint         prop_id,
     340                                           const GValue *value,
     341                                           GParamSpec   *pspec)
     342  {
     343    GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
     344  
     345    switch (prop_id)
     346      {
     347      case PROP_ARGUMENTS:
     348        g_assert (cmdline->priv->arguments == NULL);
     349        cmdline->priv->arguments = g_value_dup_variant (value);
     350        break;
     351  
     352      case PROP_OPTIONS:
     353        g_assert (cmdline->priv->options == NULL);
     354        cmdline->priv->options = g_value_dup_variant (value);
     355        break;
     356  
     357      case PROP_PLATFORM_DATA:
     358        g_assert (cmdline->priv->platform_data == NULL);
     359        cmdline->priv->platform_data = g_value_dup_variant (value);
     360        if (cmdline->priv->platform_data != NULL)
     361          grok_platform_data (cmdline);
     362        break;
     363  
     364      default:
     365        g_assert_not_reached ();
     366      }
     367  }
     368  
     369  static void
     370  g_application_command_line_dispose (GObject *object)
     371  {
     372    GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
     373  
     374    g_application_command_line_done (cmdline);
     375  
     376    G_OBJECT_CLASS (g_application_command_line_parent_class)->dispose (object);
     377  }
     378  
     379  static void
     380  g_application_command_line_finalize (GObject *object)
     381  {
     382    GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
     383  
     384    if (cmdline->priv->options_dict)
     385      g_variant_dict_unref (cmdline->priv->options_dict);
     386  
     387    if (cmdline->priv->options)
     388        g_variant_unref (cmdline->priv->options);
     389  
     390    if (cmdline->priv->platform_data)
     391      g_variant_unref (cmdline->priv->platform_data);
     392    if (cmdline->priv->arguments)
     393      g_variant_unref (cmdline->priv->arguments);
     394  
     395    g_free (cmdline->priv->cwd);
     396    g_strfreev (cmdline->priv->environ);
     397  
     398    G_OBJECT_CLASS (g_application_command_line_parent_class)
     399      ->finalize (object);
     400  }
     401  
     402  static void
     403  g_application_command_line_init (GApplicationCommandLine *cmdline)
     404  {
     405    cmdline->priv = g_application_command_line_get_instance_private (cmdline);
     406  }
     407  
     408  static void
     409  g_application_command_line_constructed (GObject *object)
     410  {
     411    GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
     412  
     413    if (IS_REMOTE (cmdline))
     414      return;
     415  
     416    /* In the local case, set cmd and environ */
     417    if (!cmdline->priv->cwd)
     418      cmdline->priv->cwd = g_get_current_dir ();
     419  
     420    if (!cmdline->priv->environ)
     421      cmdline->priv->environ = g_get_environ ();
     422  }
     423  
     424  static void
     425  g_application_command_line_class_init (GApplicationCommandLineClass *class)
     426  {
     427    GObjectClass *object_class = G_OBJECT_CLASS (class);
     428  
     429    object_class->get_property = g_application_command_line_get_property;
     430    object_class->set_property = g_application_command_line_set_property;
     431    object_class->finalize = g_application_command_line_finalize;
     432    object_class->dispose = g_application_command_line_dispose;
     433    object_class->constructed = g_application_command_line_constructed;
     434  
     435    class->printerr_literal = g_application_command_line_real_printerr_literal;
     436    class->print_literal = g_application_command_line_real_print_literal;
     437    class->get_stdin = g_application_command_line_real_get_stdin;
     438  
     439    class->done = g_application_command_line_real_done;
     440  
     441    /**
     442     * GApplicationCommandLine:arguments:
     443     *
     444     * The commandline that caused this [signal@Gio.Application::command-line]
     445     * signal emission.
     446     *
     447     * Since: 2.28
     448     */
     449    g_object_class_install_property (object_class, PROP_ARGUMENTS,
     450      g_param_spec_variant ("arguments", NULL, NULL,
     451                            G_VARIANT_TYPE_BYTESTRING_ARRAY, NULL,
     452                            G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
     453                            G_PARAM_STATIC_STRINGS));
     454  
     455    /**
     456     * GApplicationCommandLine:options:
     457     *
     458     * The options sent along with the commandline.
     459     *
     460     * Since: 2.28
     461     */
     462    g_object_class_install_property (object_class, PROP_OPTIONS,
     463      g_param_spec_variant ("options", NULL, NULL,
     464                            G_VARIANT_TYPE_VARDICT, NULL, G_PARAM_WRITABLE |
     465                            G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
     466  
     467    /**
     468     * GApplicationCommandLine:platform-data:
     469     *
     470     * Platform-specific data for the commandline.
     471     *
     472     * Since: 2.28
     473     */
     474    g_object_class_install_property (object_class, PROP_PLATFORM_DATA,
     475      g_param_spec_variant ("platform-data", NULL, NULL,
     476                            G_VARIANT_TYPE ("a{sv}"), NULL,
     477                            G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
     478                            G_PARAM_STATIC_STRINGS));
     479  
     480    /**
     481     * GApplicationCommandLine:is-remote:
     482     *
     483     * Whether this is a remote commandline.
     484     *
     485     * Since: 2.28
     486     */
     487    g_object_class_install_property (object_class, PROP_IS_REMOTE,
     488      g_param_spec_boolean ("is-remote", NULL, NULL,
     489                            FALSE,
     490                            G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
     491  }
     492  
     493  
     494  /**
     495   * g_application_command_line_get_arguments:
     496   * @cmdline: a #GApplicationCommandLine
     497   * @argc: (out) (optional): the length of the arguments array, or %NULL
     498   *
     499   * Gets the list of arguments that was passed on the command line.
     500   *
     501   * The strings in the array may contain non-UTF-8 data on UNIX (such as
     502   * filenames or arguments given in the system locale) but are always in
     503   * UTF-8 on Windows.
     504   *
     505   * If you wish to use the return value with #GOptionContext, you must
     506   * use g_option_context_parse_strv().
     507   *
     508   * The return value is %NULL-terminated and should be freed using
     509   * g_strfreev().
     510   *
     511   * Returns: (array length=argc) (element-type filename) (transfer full)
     512   *      the string array containing the arguments (the argv)
     513   *
     514   * Since: 2.28
     515   **/
     516  gchar **
     517  g_application_command_line_get_arguments (GApplicationCommandLine *cmdline,
     518                                            int                     *argc)
     519  {
     520    gchar **argv;
     521    gsize len;
     522  
     523    g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), NULL);
     524  
     525    argv = g_variant_dup_bytestring_array (cmdline->priv->arguments, &len);
     526  
     527    if (argc)
     528      *argc = len;
     529  
     530    return argv;
     531  }
     532  
     533  /**
     534   * g_application_command_line_get_options_dict:
     535   * @cmdline: a #GApplicationCommandLine
     536   *
     537   * Gets the options that were passed to g_application_command_line().
     538   *
     539   * If you did not override local_command_line() then these are the same
     540   * options that were parsed according to the #GOptionEntrys added to the
     541   * application with g_application_add_main_option_entries() and possibly
     542   * modified from your GApplication::handle-local-options handler.
     543   *
     544   * If no options were sent then an empty dictionary is returned so that
     545   * you don't need to check for %NULL.
     546   *
     547   * The data has been passed via an untrusted external process, so the types of
     548   * all values must be checked before being used.
     549   *
     550   * Returns: (transfer none): a #GVariantDict with the options
     551   *
     552   * Since: 2.40
     553   **/
     554  GVariantDict *
     555  g_application_command_line_get_options_dict (GApplicationCommandLine *cmdline)
     556  {
     557    g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), NULL);
     558  
     559    if (!cmdline->priv->options_dict)
     560      cmdline->priv->options_dict = g_variant_dict_new (cmdline->priv->options);
     561  
     562    return cmdline->priv->options_dict;
     563  }
     564  
     565  /**
     566   * g_application_command_line_get_stdin:
     567   * @cmdline: a #GApplicationCommandLine
     568   *
     569   * Gets the stdin of the invoking process.
     570   *
     571   * The #GInputStream can be used to read data passed to the standard
     572   * input of the invoking process.
     573   * This doesn't work on all platforms.  Presently, it is only available
     574   * on UNIX when using a D-Bus daemon capable of passing file descriptors.
     575   * If stdin is not available then %NULL will be returned.  In the
     576   * future, support may be expanded to other platforms.
     577   *
     578   * You must only call this function once per commandline invocation.
     579   *
     580   * Returns: (nullable) (transfer full): a #GInputStream for stdin
     581   *
     582   * Since: 2.34
     583   **/
     584  GInputStream *
     585  g_application_command_line_get_stdin (GApplicationCommandLine *cmdline)
     586  {
     587    return G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)->get_stdin (cmdline);
     588  }
     589  
     590  /**
     591   * g_application_command_line_get_cwd:
     592   * @cmdline: a #GApplicationCommandLine
     593   *
     594   * Gets the working directory of the command line invocation.
     595   * The string may contain non-utf8 data.
     596   *
     597   * It is possible that the remote application did not send a working
     598   * directory, so this may be %NULL.
     599   *
     600   * The return value should not be modified or freed and is valid for as
     601   * long as @cmdline exists.
     602   *
     603   * Returns: (nullable) (type filename): the current directory, or %NULL
     604   *
     605   * Since: 2.28
     606   **/
     607  const gchar *
     608  g_application_command_line_get_cwd (GApplicationCommandLine *cmdline)
     609  {
     610    return cmdline->priv->cwd;
     611  }
     612  
     613  /**
     614   * g_application_command_line_get_environ:
     615   * @cmdline: a #GApplicationCommandLine
     616   *
     617   * Gets the contents of the 'environ' variable of the command line
     618   * invocation, as would be returned by g_get_environ(), ie as a
     619   * %NULL-terminated list of strings in the form 'NAME=VALUE'.
     620   * The strings may contain non-utf8 data.
     621   *
     622   * The remote application usually does not send an environment.  Use
     623   * %G_APPLICATION_SEND_ENVIRONMENT to affect that.  Even with this flag
     624   * set it is possible that the environment is still not available (due
     625   * to invocation messages from other applications).
     626   *
     627   * The return value should not be modified or freed and is valid for as
     628   * long as @cmdline exists.
     629   *
     630   * See g_application_command_line_getenv() if you are only interested
     631   * in the value of a single environment variable.
     632   *
     633   * Returns: (array zero-terminated=1) (element-type filename) (transfer none):
     634   *     the environment strings, or %NULL if they were not sent
     635   *
     636   * Since: 2.28
     637   **/
     638  const gchar * const *
     639  g_application_command_line_get_environ (GApplicationCommandLine *cmdline)
     640  {
     641    return (const gchar **)cmdline->priv->environ;
     642  }
     643  
     644  /**
     645   * g_application_command_line_getenv:
     646   * @cmdline: a #GApplicationCommandLine
     647   * @name: (type filename): the environment variable to get
     648   *
     649   * Gets the value of a particular environment variable of the command
     650   * line invocation, as would be returned by g_getenv().  The strings may
     651   * contain non-utf8 data.
     652   *
     653   * The remote application usually does not send an environment.  Use
     654   * %G_APPLICATION_SEND_ENVIRONMENT to affect that.  Even with this flag
     655   * set it is possible that the environment is still not available (due
     656   * to invocation messages from other applications).
     657   *
     658   * The return value should not be modified or freed and is valid for as
     659   * long as @cmdline exists.
     660   *
     661   * Returns: (nullable): the value of the variable, or %NULL if unset or unsent
     662   *
     663   * Since: 2.28
     664   **/
     665  const gchar *
     666  g_application_command_line_getenv (GApplicationCommandLine *cmdline,
     667                                     const gchar             *name)
     668  {
     669    gint length = strlen (name);
     670    gint i;
     671  
     672    /* TODO: expand on windows */
     673    if (cmdline->priv->environ)
     674      for (i = 0; cmdline->priv->environ[i]; i++)
     675        if (strncmp (cmdline->priv->environ[i], name, length) == 0 &&
     676            cmdline->priv->environ[i][length] == '=')
     677          return cmdline->priv->environ[i] + length + 1;
     678  
     679    return NULL;
     680  }
     681  
     682  /**
     683   * g_application_command_line_get_is_remote:
     684   * @cmdline: a #GApplicationCommandLine
     685   *
     686   * Determines if @cmdline represents a remote invocation.
     687   *
     688   * Returns: %TRUE if the invocation was remote
     689   *
     690   * Since: 2.28
     691   **/
     692  gboolean
     693  g_application_command_line_get_is_remote (GApplicationCommandLine *cmdline)
     694  {
     695    return IS_REMOTE (cmdline);
     696  }
     697  
     698  /**
     699   * g_application_command_line_print_literal:
     700   * @cmdline: a #GApplicationCommandLine
     701   * @message: the message
     702   *
     703   * Prints a message using the stdout print handler in the invoking process.
     704   *
     705   * Unlike g_application_command_line_print(), @message is not a `printf()`-style
     706   * format string. Use this function if @message contains text you don't have
     707   * control over, that could include `printf()` escape sequences.
     708   *
     709   * Since: 2.80
     710   **/
     711  void
     712  g_application_command_line_print_literal (GApplicationCommandLine *cmdline,
     713                                            const gchar             *message)
     714  {
     715    g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
     716    g_return_if_fail (message != NULL);
     717  
     718    G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
     719      ->print_literal (cmdline, message);
     720  }
     721  
     722  /**
     723   * g_application_command_line_printerr_literal:
     724   * @cmdline: a #GApplicationCommandLine
     725   * @message: the message
     726   *
     727   * Prints a message using the stderr print handler in the invoking process.
     728   *
     729   * Unlike g_application_command_line_printerr(), @message is not
     730   * a `printf()`-style format string. Use this function if @message contains text
     731   * you don't have control over, that could include `printf()` escape sequences.
     732   *
     733   * Since: 2.80
     734   **/
     735  void
     736  g_application_command_line_printerr_literal (GApplicationCommandLine *cmdline,
     737                                               const gchar             *message)
     738  {
     739    g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
     740    g_return_if_fail (message != NULL);
     741  
     742    G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
     743      ->printerr_literal (cmdline, message);
     744  }
     745  
     746  /**
     747   * g_application_command_line_print:
     748   * @cmdline: a #GApplicationCommandLine
     749   * @format: a printf-style format string
     750   * @...: arguments, as per @format
     751   *
     752   * Formats a message and prints it using the stdout print handler in the
     753   * invoking process.
     754   *
     755   * If @cmdline is a local invocation then this is exactly equivalent to
     756   * g_print().  If @cmdline is remote then this is equivalent to calling
     757   * g_print() in the invoking process.
     758   *
     759   * Since: 2.28
     760   **/
     761  void
     762  g_application_command_line_print (GApplicationCommandLine *cmdline,
     763                                    const gchar             *format,
     764                                    ...)
     765  {
     766    gchar *message;
     767    va_list ap;
     768  
     769    g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
     770    g_return_if_fail (format != NULL);
     771  
     772    va_start (ap, format);
     773    message = g_strdup_vprintf (format, ap);
     774    va_end (ap);
     775  
     776    G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
     777      ->print_literal (cmdline, message);
     778    g_free (message);
     779  }
     780  
     781  /**
     782   * g_application_command_line_printerr:
     783   * @cmdline: a #GApplicationCommandLine
     784   * @format: a printf-style format string
     785   * @...: arguments, as per @format
     786   *
     787   * Formats a message and prints it using the stderr print handler in the
     788   * invoking process.
     789   *
     790   * If @cmdline is a local invocation then this is exactly equivalent to
     791   * g_printerr().  If @cmdline is remote then this is equivalent to
     792   * calling g_printerr() in the invoking process.
     793   *
     794   * Since: 2.28
     795   **/
     796  void
     797  g_application_command_line_printerr (GApplicationCommandLine *cmdline,
     798                                       const gchar             *format,
     799                                       ...)
     800  {
     801    gchar *message;
     802    va_list ap;
     803  
     804    g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
     805    g_return_if_fail (format != NULL);
     806  
     807    va_start (ap, format);
     808    message = g_strdup_vprintf (format, ap);
     809    va_end (ap);
     810  
     811    G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
     812      ->printerr_literal (cmdline, message);
     813    g_free (message);
     814  }
     815  
     816  /**
     817   * g_application_command_line_set_exit_status:
     818   * @cmdline: a #GApplicationCommandLine
     819   * @exit_status: the exit status
     820   *
     821   * Sets the exit status that will be used when the invoking process
     822   * exits.
     823   *
     824   * The return value of the #GApplication::command-line signal is
     825   * passed to this function when the handler returns.  This is the usual
     826   * way of setting the exit status.
     827   *
     828   * In the event that you want the remote invocation to continue running
     829   * and want to decide on the exit status in the future, you can use this
     830   * call.  For the case of a remote invocation, the remote process will
     831   * typically exit when the last reference is dropped on @cmdline.  The
     832   * exit status of the remote process will be equal to the last value
     833   * that was set with this function.
     834   *
     835   * In the case that the commandline invocation is local, the situation
     836   * is slightly more complicated.  If the commandline invocation results
     837   * in the mainloop running (ie: because the use-count of the application
     838   * increased to a non-zero value) then the application is considered to
     839   * have been 'successful' in a certain sense, and the exit status is
     840   * always zero.  If the application use count is zero, though, the exit
     841   * status of the local #GApplicationCommandLine is used.
     842   *
     843   * This method is a no-op if g_application_command_line_done() has
     844   * been called.
     845   *
     846   * Since: 2.28
     847   **/
     848  void
     849  g_application_command_line_set_exit_status (GApplicationCommandLine *cmdline,
     850                                              int                      exit_status)
     851  {
     852    g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
     853  
     854    if (cmdline->priv->done)
     855      return;
     856  
     857    cmdline->priv->exit_status = exit_status;
     858  }
     859  
     860  /**
     861   * g_application_command_line_get_exit_status:
     862   * @cmdline: a #GApplicationCommandLine
     863   *
     864   * Gets the exit status of @cmdline.  See
     865   * g_application_command_line_set_exit_status() for more information.
     866   *
     867   * Returns: the exit status
     868   *
     869   * Since: 2.28
     870   **/
     871  int
     872  g_application_command_line_get_exit_status (GApplicationCommandLine *cmdline)
     873  {
     874    g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), -1);
     875  
     876    return cmdline->priv->exit_status;
     877  }
     878  
     879  /**
     880   * g_application_command_line_get_platform_data:
     881   * @cmdline: #GApplicationCommandLine
     882   *
     883   * Gets the platform data associated with the invocation of @cmdline.
     884   *
     885   * This is a #GVariant dictionary containing information about the
     886   * context in which the invocation occurred.  It typically contains
     887   * information like the current working directory and the startup
     888   * notification ID.
     889   *
     890   * It comes from an untrusted external process and hence the types of all
     891   * values must be validated before being used.
     892   *
     893   * For local invocation, it will be %NULL.
     894   *
     895   * Returns: (nullable) (transfer full): the platform data, or %NULL
     896   *
     897   * Since: 2.28
     898   **/
     899  GVariant *
     900  g_application_command_line_get_platform_data (GApplicationCommandLine *cmdline)
     901  {
     902    g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), NULL);
     903  
     904    if (cmdline->priv->platform_data)
     905      return g_variant_ref (cmdline->priv->platform_data);
     906    else
     907        return NULL;
     908  }
     909  
     910  /**
     911   * g_application_command_line_create_file_for_arg:
     912   * @cmdline: a #GApplicationCommandLine
     913   * @arg: (type filename): an argument from @cmdline
     914   *
     915   * Creates a #GFile corresponding to a filename that was given as part
     916   * of the invocation of @cmdline.
     917   *
     918   * This differs from g_file_new_for_commandline_arg() in that it
     919   * resolves relative pathnames using the current working directory of
     920   * the invoking process rather than the local process.
     921   *
     922   * Returns: (transfer full): a new #GFile
     923   *
     924   * Since: 2.36
     925   **/
     926  GFile *
     927  g_application_command_line_create_file_for_arg (GApplicationCommandLine *cmdline,
     928                                                  const gchar             *arg)
     929  {
     930    g_return_val_if_fail (arg != NULL, NULL);
     931  
     932    if (cmdline->priv->cwd)
     933      return g_file_new_for_commandline_arg_and_cwd (arg, cmdline->priv->cwd);
     934  
     935    g_warning ("Requested creation of GFile for commandline invocation that did not send cwd. "
     936               "Using cwd of local process to resolve relative path names.");
     937  
     938    return g_file_new_for_commandline_arg (arg);
     939  }
     940  
     941  /**
     942   * g_application_command_line_done:
     943   * @cmdline: a #GApplicationCommandLine
     944   *
     945   * Signals that command line processing is completed.
     946   *
     947   * For remote invocation, it causes the invoking process to terminate.
     948   *
     949   * For local invocation, it does nothing.
     950   *
     951   * This method should be called in the [signal@Gio.Application::command-line]
     952   * handler, after the exit status is set and all messages are printed.
     953   *
     954   * After this call, g_application_command_line_set_exit_status() has no effect.
     955   * Subsequent calls to this method are no-ops.
     956   *
     957   * This method is automatically called when the #GApplicationCommandLine
     958   * object is disposed — so you can omit the call in non-garbage collected
     959   * languages.
     960   *
     961   * Since: 2.80
     962   **/
     963  void
     964  g_application_command_line_done (GApplicationCommandLine *cmdline)
     965  {
     966    g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
     967  
     968    if (cmdline->priv->done)
     969      return;
     970  
     971    G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)->done (cmdline);
     972  
     973    cmdline->priv->done = TRUE;
     974  }