Use 'aay' instead of 'as' for environ
[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 class representing a command-line invocation of
37  *                     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 exit status of the originally-invoked process may be set and
51  * messages can be printed to stdout or stderr of that process.  The
52  * lifecycle of the originally-invoked process is tied to the lifecycle
53  * of this object (ie: the process exits when the last reference is
54  * dropped).
55  *
56  * <example id="gapplication-example-cmdline"><title>Handling commandline arguments with GApplication</title>
57  * <programlisting>
58  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gapplication-example-cmdline.c">
59  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
60  * </xi:include>
61  * </programlisting>
62  * </example>
63  *
64  * <example id="gapplication-example-cmdline2"><title>Complicated commandline handling</title>
65  * <programlisting>
66  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gapplication-example-cmdline2.c">
67  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
68  * </xi:include>
69  * </programlisting>
70  * </example>
71  **/
72
73 enum
74 {
75   PROP_NONE,
76   PROP_ARGUMENTS,
77   PROP_PLATFORM_DATA,
78   PROP_IS_REMOTE
79 };
80
81 struct _GApplicationCommandLinePrivate
82 {
83   GVariant *platform_data;
84   GVariant *arguments;
85   GVariant *cwd;
86
87   const gchar **environ;
88   gint exit_status;
89 };
90
91 /* All subclasses represent remote invocations of some kind. */
92 #define IS_REMOTE(cmdline) (G_TYPE_FROM_INSTANCE (cmdline) != \
93                             G_TYPE_APPLICATION_COMMAND_LINE)
94
95 static void
96 grok_platform_data (GApplicationCommandLine *cmdline)
97 {
98   GVariantIter iter;
99   const gchar *key;
100   GVariant *value;
101
102   g_variant_iter_init (&iter, cmdline->priv->platform_data);
103
104   while (g_variant_iter_loop (&iter, "{&sv}", &key, &value))
105     if (strcmp (key, "cwd") == 0)
106       {
107         if (!cmdline->priv->cwd)
108           cmdline->priv->cwd = g_variant_ref (value);
109       }
110
111     else if (strcmp (key, "environ") == 0)
112       {
113         if (!cmdline->priv->environ)
114           cmdline->priv->environ =
115             g_variant_get_bytestring_array (value, NULL);
116       }
117 }
118
119 static void
120 g_application_command_line_real_print_literal (GApplicationCommandLine *cmdline,
121                                                const gchar             *message)
122 {
123   g_print ("%s\n", message);
124 }
125
126 static void
127 g_application_command_line_real_printerr_literal (GApplicationCommandLine *cmdline,
128                                                   const gchar             *message)
129 {
130   g_printerr ("%s\n", message);
131 }
132
133 static void
134 g_application_command_line_get_property (GObject    *object,
135                                          guint       prop_id,
136                                          GValue     *value,
137                                          GParamSpec *pspec)
138 {
139   GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
140
141   switch (prop_id)
142     {
143     case PROP_ARGUMENTS:
144       g_value_set_variant (value, cmdline->priv->arguments);
145       break;
146
147     case PROP_PLATFORM_DATA:
148       g_value_set_variant (value, cmdline->priv->platform_data);
149       break;
150
151     case PROP_IS_REMOTE:
152       g_value_set_boolean (value, IS_REMOTE (cmdline));
153       break;
154
155     default:
156       g_assert_not_reached ();
157     }
158 }
159
160 static void
161 g_application_command_line_set_property (GObject      *object,
162                                          guint         prop_id,
163                                          const GValue *value,
164                                          GParamSpec   *pspec)
165 {
166   GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
167
168   switch (prop_id)
169     {
170     case PROP_ARGUMENTS:
171       g_assert (cmdline->priv->arguments == NULL);
172       cmdline->priv->arguments = g_value_dup_variant (value);
173       break;
174
175     case PROP_PLATFORM_DATA:
176       g_assert (cmdline->priv->platform_data == NULL);
177       cmdline->priv->platform_data = g_value_dup_variant (value);
178       if (cmdline->priv->platform_data != NULL)
179         grok_platform_data (cmdline);
180       break;
181
182     default:
183       g_assert_not_reached ();
184     }
185 }
186
187 static void
188 g_application_command_line_finalize (GObject *object)
189 {
190   GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object);
191
192   if (cmdline->priv->platform_data)
193     g_variant_unref (cmdline->priv->platform_data);
194   if (cmdline->priv->arguments)
195     g_variant_unref (cmdline->priv->arguments);
196   if (cmdline->priv->cwd)
197     g_variant_unref (cmdline->priv->cwd);
198
199   G_OBJECT_CLASS (g_application_command_line_parent_class)
200     ->finalize (object);
201 }
202
203 static void
204 g_application_command_line_init (GApplicationCommandLine *cmdline)
205 {
206   cmdline->priv =
207     G_TYPE_INSTANCE_GET_PRIVATE (cmdline,
208                                  G_TYPE_APPLICATION_COMMAND_LINE,
209                                  GApplicationCommandLinePrivate);
210 }
211
212 static void
213 g_application_command_line_class_init (GApplicationCommandLineClass *class)
214 {
215   GObjectClass *object_class = G_OBJECT_CLASS (class);
216
217   object_class->get_property = g_application_command_line_get_property;
218   object_class->set_property = g_application_command_line_set_property;
219   object_class->finalize = g_application_command_line_finalize;
220   class->printerr_literal = g_application_command_line_real_printerr_literal;
221   class->print_literal = g_application_command_line_real_print_literal;
222
223   g_object_class_install_property (object_class, PROP_ARGUMENTS,
224     g_param_spec_variant ("arguments",
225                           P_("Commandline arguments"),
226                           P_("The commandline that caused this ::command-line signal emission"),
227                           G_VARIANT_TYPE_BYTESTRING_ARRAY, NULL,
228                           G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
229                           G_PARAM_STATIC_STRINGS));
230
231   g_object_class_install_property (object_class, PROP_PLATFORM_DATA,
232     g_param_spec_variant ("platform-data",
233                           P_("Platform data"),
234                           P_("Platform-specific data for the commandline"),
235                           G_VARIANT_TYPE ("a{sv}"), NULL,
236                           G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
237                           G_PARAM_STATIC_STRINGS));
238
239   g_object_class_install_property (object_class, PROP_IS_REMOTE,
240     g_param_spec_boolean ("is-remote",
241                           P_("Is remote"),
242                           P_("TRUE if this is a remote commandline"),
243                           FALSE,
244                           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
245
246   g_type_class_add_private (class, sizeof (GApplicationCommandLinePrivate));
247 }
248
249
250 /**
251  * g_application_command_line_get_arguments:
252  * @cmdline: a #GApplicationCommandLine
253  * @argc: the length of the arguments array, or %NULL
254  *
255  * Gets the list of arguments that was passed on the command line.
256  *
257  * The strings in the array may contain non-utf8 data.
258  *
259  * The return value is %NULL-terminated and should be freed using
260  * g_strfreev().
261  *
262  * Returns: the string array containing the arguments (the argv)
263  *
264  * Since: 2.28
265  **/
266 gchar **
267 g_application_command_line_get_arguments (GApplicationCommandLine *cmdline,
268                                           int                     *argc)
269 {
270   gchar **argv;
271   gsize len;
272
273   g_return_val_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline), NULL);
274
275   argv = g_variant_dup_bytestring_array (cmdline->priv->arguments, &len);
276
277   if (argc)
278     *argc = len;
279
280   return argv;
281 }
282
283 /**
284  * g_application_command_line_get_cwd:
285  * @cmdline: a #GApplicationCommandLine
286  *
287  * Gets the working directory of the command line invocation.  The
288  * string may contain non-utf8 data.
289  *
290  * It is possible that the remote application did not send a working
291  * directory, so this may be %NULL.
292  *
293  * The return value should not be modified or freed and is valid for as
294  * long as @cmdline exists.
295  *
296  * Returns: the current directory, or %NULL
297  *
298  * Since: 2.28
299  **/
300 const gchar *
301 g_application_command_line_get_cwd (GApplicationCommandLine *cmdline)
302 {
303   if (cmdline->priv->cwd)
304     return g_variant_get_bytestring (cmdline->priv->cwd);
305   else
306     return NULL;
307 }
308
309 /**
310  * g_application_command_line_get_environ:
311  * @cmdline: a #GApplicationCommandLine
312  *
313  * Gets the contents of the 'environ' variable of the command line
314  * invocation, as would be returned by g_get_environ().  The strings may
315  * contain non-utf8 data.
316  *
317  * The remote application usually does not send an environment.  Use
318  * %G_APPLICATION_SEND_ENVIRONMENT to affect that.  Even with this flag
319  * set it is possible that the environment is still not available (due
320  * to invocation messages from other applications).
321  *
322  * The return value should not be modified or freed and is valid for as
323  * long as @cmdline exists.
324  *
325  * Returns: the environment strings, or %NULL if they were not sent
326  * 
327  * Since: 2.28
328  **/
329 const gchar * const *
330 g_application_command_line_get_environ (GApplicationCommandLine *cmdline)
331 {
332   return cmdline->priv->environ;
333 }
334
335 /**
336  * g_application_command_line_getenv:
337  * @cmdline: a #GApplicationCommandLine
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 }