gio: New API for GFile from remote commandline arg
[platform/upstream/glib.git] / gio / gapplicationcommandline.c
1 /*
2  * Copyright © 2010 Codethink Limited
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * licence or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
17  * USA.
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 G_DEFINE_TYPE (GApplicationCommandLine, g_application_command_line, G_TYPE_OBJECT)
33
34 /**
35  * SECTION:gapplicationcommandline
36  * @title: GApplicationCommandLine
37  * @short_description: A command-line invocation of an application
38  * @see_also: #GApplication
39  *
40  * #GApplicationCommandLine represents a command-line invocation of
41  * an application.  It is created by #GApplication and emitted
42  * in the #GApplication::command-line signal and virtual function.
43  *
44  * The class contains the list of arguments that the program was invoked
45  * with.  It is also possible to query if the commandline invocation was
46  * local (ie: the current process is running in direct response to the
47  * invocation) or remote (ie: some other process forwarded the
48  * commandline to this process).
49  *
50  * The GApplicationCommandLine object can provide the @argc and @argv
51  * parameters for use with the #GOptionContext command-line parsing API,
52  * with the g_application_command_line_get_arguments() function. See
53  * <xref linkend="gapplication-example-cmdline3"/> for an example.
54  *
55  * The exit status of the originally-invoked process may be set and
56  * messages can be printed to stdout or stderr of that process.  The
57  * lifecycle of the originally-invoked process is tied to the lifecycle
58  * of this object (ie: the process exits when the last reference is
59  * dropped).
60  *
61  * The main use for #GApplicationCommandLine (and the
62  * #GApplication::command-line signal) is 'Emacs server' like use cases:
63  * You can set the <envar>EDITOR</envar> environment variable to have
64  * e.g. git use your favourite editor to edit commit messages, and if you
65  * already have an instance of the editor running, the editing will happen
66  * in the running instance, instead of opening a new one. An important
67  * aspect of this use case is that the process that gets started by git
68  * does not return until the editing is done.
69  *
70  * <example id="gapplication-example-cmdline"><title>Handling commandline arguments with GApplication</title>
71  * <para>
72  * A simple example where the commandline is completely handled
73  * in the #GApplication::command-line handler. The launching instance exits
74  * once the signal handler in the primary instance has returned, and the
75  * return value of the signal handler becomes the exit status of the launching
76  * instance.
77  * </para>
78  * <programlisting>
79  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gapplication-example-cmdline.c">
80  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
81  * </xi:include>
82  * </programlisting>
83  * </example>
84  *
85  * <example id="gapplication-example-cmdline2"><title>Split commandline handling</title>
86  * <para>
87  * An example of split commandline handling. Options that start with
88  * <literal>--local-</literal> are handled locally, all other options are
89  * passed to the #GApplication::command-line handler which runs in the primary
90  * instance.
91  * </para>
92  * <programlisting>
93  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gapplication-example-cmdline2.c">
94  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
95  * </xi:include>
96  * </programlisting>
97  * </example>
98  *
99  * <example id="gapplication-example-cmdline3"><title>Deferred commandline handling</title>
100  * <para>
101  * An example of deferred commandline handling. Here, the commandline is
102  * not completely handled before the #GApplication::command-line handler
103  * returns. Instead, we keep a reference to the GApplicationCommandLine
104  * object and handle it later(in this example, in an idle). Note that it
105  * is necessary to hold the application until you are done with the
106  * commandline.
107  * </para>
108  * <para>
109  * This example also shows how to use #GOptionContext for parsing the
110  * commandline arguments. Note that it is necessary to disable the
111  * built-in help-handling of #GOptionContext, since it calls exit()
112  * after printing help, which is not what you want to happen in
113  * the primary instance.
114  * </para>
115  * <programlisting>
116  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gapplication-example-cmdline3.c">
117  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
118  * </xi:include>
119  * </programlisting>
120  * </example>
121  **/
122
123 /**
124  * GApplicationCommandLineClass:
125  *
126  * The <structname>GApplicationCommandLineClass</structname> structure
127  * contains private data only
128  *
129  * Since: 2.28
130  **/
131 enum
132 {
133   PROP_NONE,
134   PROP_ARGUMENTS,
135   PROP_PLATFORM_DATA,
136   PROP_IS_REMOTE
137 };
138
139 struct _GApplicationCommandLinePrivate
140 {
141   GVariant *platform_data;
142   GVariant *arguments;
143   gchar *cwd;
144
145   gchar **environ;
146   gint exit_status;
147 };
148
149 /* All subclasses represent remote invocations of some kind. */
150 #define IS_REMOTE(cmdline) (G_TYPE_FROM_INSTANCE (cmdline) != \
151                             G_TYPE_APPLICATION_COMMAND_LINE)
152
153 static void
154 grok_platform_data (GApplicationCommandLine *cmdline)
155 {
156   GVariantIter iter;
157   const gchar *key;
158   GVariant *value;
159
160   g_variant_iter_init (&iter, cmdline->priv->platform_data);
161
162   while (g_variant_iter_loop (&iter, "{&sv}", &key, &value))
163     if (strcmp (key, "cwd") == 0)
164       {
165         if (!cmdline->priv->cwd)
166           cmdline->priv->cwd = g_variant_dup_bytestring (value, NULL);
167       }
168
169     else if (strcmp (key, "environ") == 0)
170       {
171         if (!cmdline->priv->environ)
172           cmdline->priv->environ =
173             g_variant_dup_bytestring_array (value, NULL);
174       }
175 }
176
177 static void
178 g_application_command_line_real_print_literal (GApplicationCommandLine *cmdline,
179                                                const gchar             *message)
180 {
181   g_print ("%s", message);
182 }
183
184 static void
185 g_application_command_line_real_printerr_literal (GApplicationCommandLine *cmdline,
186                                                   const gchar             *message)
187 {
188   g_printerr ("%s", message);
189 }
190
191 static void
192 g_application_command_line_get_property (GObject    *object,
193                                          guint       prop_id,
194                                          GValue     *value,
195                                          GParamSpec *pspec)
196 {
197   GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
198
199   switch (prop_id)
200     {
201     case PROP_ARGUMENTS:
202       g_value_set_variant (value, cmdline->priv->arguments);
203       break;
204
205     case PROP_PLATFORM_DATA:
206       g_value_set_variant (value, cmdline->priv->platform_data);
207       break;
208
209     case PROP_IS_REMOTE:
210       g_value_set_boolean (value, IS_REMOTE (cmdline));
211       break;
212
213     default:
214       g_assert_not_reached ();
215     }
216 }
217
218 static void
219 g_application_command_line_set_property (GObject      *object,
220                                          guint         prop_id,
221                                          const GValue *value,
222                                          GParamSpec   *pspec)
223 {
224   GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
225
226   switch (prop_id)
227     {
228     case PROP_ARGUMENTS:
229       g_assert (cmdline->priv->arguments == NULL);
230       cmdline->priv->arguments = g_value_dup_variant (value);
231       break;
232
233     case PROP_PLATFORM_DATA:
234       g_assert (cmdline->priv->platform_data == NULL);
235       cmdline->priv->platform_data = g_value_dup_variant (value);
236       if (cmdline->priv->platform_data != NULL)
237         grok_platform_data (cmdline);
238       break;
239
240     default:
241       g_assert_not_reached ();
242     }
243 }
244
245 static void
246 g_application_command_line_finalize (GObject *object)
247 {
248   GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
249
250   if (cmdline->priv->platform_data)
251     g_variant_unref (cmdline->priv->platform_data);
252   if (cmdline->priv->arguments)
253     g_variant_unref (cmdline->priv->arguments);
254
255   g_free (cmdline->priv->cwd);
256   g_strfreev (cmdline->priv->environ);
257
258   G_OBJECT_CLASS (g_application_command_line_parent_class)
259     ->finalize (object);
260 }
261
262 static void
263 g_application_command_line_init (GApplicationCommandLine *cmdline)
264 {
265   cmdline->priv =
266     G_TYPE_INSTANCE_GET_PRIVATE (cmdline,
267                                  G_TYPE_APPLICATION_COMMAND_LINE,
268                                  GApplicationCommandLinePrivate);
269 }
270
271 static void
272 g_application_command_line_constructed (GObject *object)
273 {
274   GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
275
276   if (IS_REMOTE (cmdline))
277     return;
278
279   /* In the local case, set cmd and environ */
280   if (!cmdline->priv->cwd)
281     cmdline->priv->cwd = g_get_current_dir ();
282
283   if (!cmdline->priv->environ)
284     cmdline->priv->environ = g_get_environ ();
285 }
286
287 static void
288 g_application_command_line_class_init (GApplicationCommandLineClass *class)
289 {
290   GObjectClass *object_class = G_OBJECT_CLASS (class);
291
292   object_class->get_property = g_application_command_line_get_property;
293   object_class->set_property = g_application_command_line_set_property;
294   object_class->finalize = g_application_command_line_finalize;
295   object_class->constructed = g_application_command_line_constructed;
296
297   class->printerr_literal = g_application_command_line_real_printerr_literal;
298   class->print_literal = g_application_command_line_real_print_literal;
299
300   g_object_class_install_property (object_class, PROP_ARGUMENTS,
301     g_param_spec_variant ("arguments",
302                           P_("Commandline arguments"),
303                           P_("The commandline that caused this ::command-line signal emission"),
304                           G_VARIANT_TYPE_BYTESTRING_ARRAY, NULL,
305                           G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
306                           G_PARAM_STATIC_STRINGS));
307
308   g_object_class_install_property (object_class, PROP_PLATFORM_DATA,
309     g_param_spec_variant ("platform-data",
310                           P_("Platform data"),
311                           P_("Platform-specific data for the commandline"),
312                           G_VARIANT_TYPE ("a{sv}"), NULL,
313                           G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
314                           G_PARAM_STATIC_STRINGS));
315
316   g_object_class_install_property (object_class, PROP_IS_REMOTE,
317     g_param_spec_boolean ("is-remote",
318                           P_("Is remote"),
319                           P_("TRUE if this is a remote commandline"),
320                           FALSE,
321                           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
322
323   g_type_class_add_private (class, sizeof (GApplicationCommandLinePrivate));
324 }
325
326
327 /**
328  * g_application_command_line_get_arguments:
329  * @cmdline: a #GApplicationCommandLine
330  * @argc: (out) (allow-none): the length of the arguments array, or %NULL
331  *
332  * Gets the list of arguments that was passed on the command line.
333  *
334  * The strings in the array may contain non-utf8 data.
335  *
336  * The return value is %NULL-terminated and should be freed using
337  * g_strfreev().
338  *
339  * Returns: (array length=argc) (transfer full): the string array
340  * containing the arguments (the argv)
341  *
342  * Since: 2.28
343  **/
344 gchar **
345 g_application_command_line_get_arguments (GApplicationCommandLine *cmdline,
346                                           int                     *argc)
347 {
348   gchar **argv;
349   gsize len;
350
351   g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), NULL);
352
353   argv = g_variant_dup_bytestring_array (cmdline->priv->arguments, &len);
354
355   if (argc)
356     *argc = len;
357
358   return argv;
359 }
360
361 /**
362  * g_application_command_line_get_cwd:
363  * @cmdline: a #GApplicationCommandLine
364  *
365  * Gets the working directory of the command line invocation.
366  * The string may contain non-utf8 data.
367  *
368  * It is possible that the remote application did not send a working
369  * directory, so this may be %NULL.
370  *
371  * The return value should not be modified or freed and is valid for as
372  * long as @cmdline exists.
373  *
374  * Returns: the current directory, or %NULL
375  *
376  * Since: 2.28
377  **/
378 const gchar *
379 g_application_command_line_get_cwd (GApplicationCommandLine *cmdline)
380 {
381   return cmdline->priv->cwd;
382 }
383
384 /**
385  * g_application_command_line_get_environ:
386  * @cmdline: a #GApplicationCommandLine
387  *
388  * Gets the contents of the 'environ' variable of the command line
389  * invocation, as would be returned by g_get_environ(), ie as a
390  * %NULL-terminated list of strings in the form 'NAME=VALUE'.
391  * The strings may contain non-utf8 data.
392  *
393  * The remote application usually does not send an environment.  Use
394  * %G_APPLICATION_SEND_ENVIRONMENT to affect that.  Even with this flag
395  * set it is possible that the environment is still not available (due
396  * to invocation messages from other applications).
397  *
398  * The return value should not be modified or freed and is valid for as
399  * long as @cmdline exists.
400  *
401  * See g_application_command_line_getenv() if you are only interested
402  * in the value of a single environment variable.
403  *
404  * Returns: (array zero-terminated=1) (transfer none): the environment
405  * strings, or %NULL if they were not sent
406  *
407  * Since: 2.28
408  **/
409 const gchar * const *
410 g_application_command_line_get_environ (GApplicationCommandLine *cmdline)
411 {
412   return (const gchar **)cmdline->priv->environ;
413 }
414
415 /**
416  * g_application_command_line_getenv:
417  * @cmdline: a #GApplicationCommandLine
418  * @name: the environment variable to get
419  *
420  * Gets the value of a particular environment variable of the command
421  * line invocation, as would be returned by g_getenv().  The strings may
422  * contain non-utf8 data.
423  *
424  * The remote application usually does not send an environment.  Use
425  * %G_APPLICATION_SEND_ENVIRONMENT to affect that.  Even with this flag
426  * set it is possible that the environment is still not available (due
427  * to invocation messages from other applications).
428  *
429  * The return value should not be modified or freed and is valid for as
430  * long as @cmdline exists.
431  *
432  * Returns: the value of the variable, or %NULL if unset or unsent
433  *
434  * Since: 2.28
435  **/
436 const gchar *
437 g_application_command_line_getenv (GApplicationCommandLine *cmdline,
438                                    const gchar             *name)
439 {
440   gint length = strlen (name);
441   gint i;
442
443   /* TODO: expand on windows */
444   if (cmdline->priv->environ)
445     for (i = 0; cmdline->priv->environ[i]; i++)
446       if (strncmp (cmdline->priv->environ[i], name, length) == 0 &&
447           cmdline->priv->environ[i][length] == '=')
448         return cmdline->priv->environ[i] + length + 1;
449
450   return NULL;
451 }
452
453 /**
454  * g_application_command_line_get_is_remote:
455  * @cmdline: a #GApplicationCommandLine
456  *
457  * Determines if @cmdline represents a remote invocation.
458  *
459  * Returns: %TRUE if the invocation was remote
460  *
461  * Since: 2.28
462  **/
463 gboolean
464 g_application_command_line_get_is_remote (GApplicationCommandLine *cmdline)
465 {
466   return IS_REMOTE (cmdline);
467 }
468
469 /**
470  * g_application_command_line_print:
471  * @cmdline: a #GApplicationCommandLine
472  * @format: a printf-style format string
473  * @...: arguments, as per @format
474  *
475  * Formats a message and prints it using the stdout print handler in the
476  * invoking process.
477  *
478  * If @cmdline is a local invocation then this is exactly equivalent to
479  * g_print().  If @cmdline is remote then this is equivalent to calling
480  * g_print() in the invoking process.
481  *
482  * Since: 2.28
483  **/
484 void
485 g_application_command_line_print (GApplicationCommandLine *cmdline,
486                                   const gchar             *format,
487                                   ...)
488 {
489   gchar *message;
490   va_list ap;
491
492   g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
493   g_return_if_fail (format != NULL);
494
495   va_start (ap, format);
496   message = g_strdup_vprintf (format, ap);
497   va_end (ap);
498
499   G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
500     ->print_literal (cmdline, message);
501   g_free (message);
502 }
503
504 /**
505  * g_application_command_line_printerr:
506  * @cmdline: a #GApplicationCommandLine
507  * @format: a printf-style format string
508  * @...: arguments, as per @format
509  *
510  * Formats a message and prints it using the stderr print handler in the
511  * invoking process.
512  *
513  * If @cmdline is a local invocation then this is exactly equivalent to
514  * g_printerr().  If @cmdline is remote then this is equivalent to
515  * calling g_printerr() in the invoking process.
516  *
517  * Since: 2.28
518  **/
519 void
520 g_application_command_line_printerr (GApplicationCommandLine *cmdline,
521                                      const gchar             *format,
522                                      ...)
523 {
524   gchar *message;
525   va_list ap;
526
527   g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
528   g_return_if_fail (format != NULL);
529
530   va_start (ap, format);
531   message = g_strdup_vprintf (format, ap);
532   va_end (ap);
533
534   G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)
535     ->printerr_literal (cmdline, message);
536   g_free (message);
537 }
538
539 /**
540  * g_application_command_line_set_exit_status:
541  * @cmdline: a #GApplicationCommandLine
542  * @exit_status: the exit status
543  *
544  * Sets the exit status that will be used when the invoking process
545  * exits.
546  *
547  * The return value of the #GApplication::command-line signal is
548  * passed to this function when the handler returns.  This is the usual
549  * way of setting the exit status.
550  *
551  * In the event that you want the remote invocation to continue running
552  * and want to decide on the exit status in the future, you can use this
553  * call.  For the case of a remote invocation, the remote process will
554  * typically exit when the last reference is dropped on @cmdline.  The
555  * exit status of the remote process will be equal to the last value
556  * that was set with this function.
557  *
558  * In the case that the commandline invocation is local, the situation
559  * is slightly more complicated.  If the commandline invocation results
560  * in the mainloop running (ie: because the use-count of the application
561  * increased to a non-zero value) then the application is considered to
562  * have been 'successful' in a certain sense, and the exit status is
563  * always zero.  If the application use count is zero, though, the exit
564  * status of the local #GApplicationCommandLine is used.
565  *
566  * Since: 2.28
567  **/
568 void
569 g_application_command_line_set_exit_status (GApplicationCommandLine *cmdline,
570                                             int                      exit_status)
571 {
572   g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline));
573
574   cmdline->priv->exit_status = exit_status;
575 }
576
577 /**
578  * g_application_command_line_get_exit_status:
579  * @cmdline: a #GApplicationCommandLine
580  *
581  * Gets the exit status of @cmdline.  See
582  * g_application_command_line_set_exit_status() for more information.
583  *
584  * Returns: the exit status
585  *
586  * Since: 2.28
587  **/
588 int
589 g_application_command_line_get_exit_status (GApplicationCommandLine *cmdline)
590 {
591   g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), -1);
592
593   return cmdline->priv->exit_status;
594 }
595
596 /**
597  * g_application_command_line_get_platform_data:
598  * @cmdline: #GApplicationCommandLine
599  *
600  * Gets the platform data associated with the invocation of @cmdline.
601  *
602  * This is a #GVariant dictionary containing information about the
603  * context in which the invocation occurred.  It typically contains
604  * information like the current working directory and the startup
605  * notification ID.
606  *
607  * For local invocation, it will be %NULL.
608  *
609  * Returns: (allow-none): the platform data, or %NULL
610  *
611  * Since: 2.28
612  **/
613 GVariant *
614 g_application_command_line_get_platform_data (GApplicationCommandLine *cmdline)
615 {
616   g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), NULL);
617
618   if (cmdline->priv->platform_data)
619     return g_variant_ref (cmdline->priv->platform_data);
620   else
621       return NULL;
622 }
623
624 /**
625  * g_application_command_line_create_file_for_arg:
626  * @cmdline: a #GApplicationCommandLine
627  * @arg: an argument from @cmdline
628  *
629  * Creates a #GFile corresponding to a filename that was given as part
630  * of the invocation of @cmdline.
631  *
632  * This differs from g_file_new_for_commandline_arg() in that it
633  * resolves relative pathnames using the current working directory of
634  * the invoking process rather than the local process.
635  *
636  * Returns: (transfer full): a new #GFile
637  *
638  * Since: 2.36
639  **/
640 GFile *
641 g_application_command_line_create_file_for_arg (GApplicationCommandLine *cmdline,
642                                                 const gchar             *arg)
643 {
644   g_return_val_if_fail (arg != NULL, NULL);
645
646   if (cmdline->priv->cwd)
647     return g_file_new_for_commandline_arg_and_cwd (arg, cmdline->priv->cwd);
648
649   g_warning ("Requested creation of GFile for commandline invocation that did not send cwd. "
650              "Using cwd of local process to resolve relative path names.");
651
652   return g_file_new_for_commandline_arg (arg);
653 }