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