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