0001e706811ff0c4a9d7e0672106fadc78ce3c72
[platform/upstream/glib.git] / glib / goption.c
1 /* goption.c - Option parser
2  *
3  *  Copyright (C) 1999, 2003 Red Hat Software
4  *  Copyright (C) 2004       Anders Carlsson <andersca@gnome.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /**
23  * SECTION:option
24  * @Short_description: parses commandline options
25  * @Title: Commandline option parser
26  *
27  * The GOption commandline parser is intended to be a simpler replacement
28  * for the popt library. It supports short and long commandline options,
29  * as shown in the following example:
30  *
31  * <literal>testtreemodel -r 1 --max-size 20 --rand --display=:1.0 -vb -- file1 file2</literal>
32  *
33  * The example demonstrates a number of features of the GOption
34  * commandline parser
35  * <itemizedlist><listitem><para>
36  *   Options can be single letters, prefixed by a single dash. Multiple
37  *   short options can be grouped behind a single dash.
38  * </para></listitem><listitem><para>
39  *   Long options are prefixed by two consecutive dashes.
40  * </para></listitem><listitem><para>
41  *   Options can have an extra argument, which can be a number, a string or
42  *   a filename. For long options, the extra argument can be appended with
43  *   an equals sign after the option name, which is useful if the extra
44  *   argument starts with a dash, which would otherwise cause it to be
45  *   interpreted as another option.
46  * </para></listitem><listitem><para>
47  *   Non-option arguments are returned to the application as rest arguments.
48  * </para></listitem><listitem><para>
49  *   An argument consisting solely of two dashes turns off further parsing,
50  *   any remaining arguments (even those starting with a dash) are returned
51  *   to the application as rest arguments.
52  * </para></listitem></itemizedlist>
53  *
54  * Another important feature of GOption is that it can automatically
55  * generate nicely formatted help output. Unless it is explicitly turned
56  * off with g_option_context_set_help_enabled(), GOption will recognize
57  * the <option>--help</option>, <option>-?</option>,
58  * <option>--help-all</option> and
59  * <option>--help-</option><replaceable>groupname</replaceable> options
60  * (where <replaceable>groupname</replaceable> is the name of a
61  * #GOptionGroup) and write a text similar to the one shown in the
62  * following example to stdout.
63  *
64  * <informalexample><screen>
65  * Usage:
66  *   testtreemodel [OPTION...] - test tree model performance
67  *  
68  * Help Options:
69  *   -h, --help               Show help options
70  *   --help-all               Show all help options
71  *   --help-gtk               Show GTK+ Options
72  *  
73  * Application Options:
74  *   -r, --repeats=N          Average over N repetitions
75  *   -m, --max-size=M         Test up to 2^M items
76  *   --display=DISPLAY        X display to use
77  *   -v, --verbose            Be verbose
78  *   -b, --beep               Beep when done
79  *   --rand                   Randomize the data
80  * </screen></informalexample>
81  *
82  * GOption groups options in #GOptionGroup<!-- -->s, which makes it easy to
83  * incorporate options from multiple sources. The intended use for this is
84  * to let applications collect option groups from the libraries it uses,
85  * add them to their #GOptionContext, and parse all options by a single call
86  * to g_option_context_parse(). See gtk_get_option_group() for an example.
87  *
88  * If an option is declared to be of type string or filename, GOption takes
89  * care of converting it to the right encoding; strings are returned in
90  * UTF-8, filenames are returned in the GLib filename encoding. Note that
91  * this only works if setlocale() has been called before
92  * g_option_context_parse().
93  *
94  * Here is a complete example of setting up GOption to parse the example
95  * commandline above and produce the example help output.
96  *
97  * <informalexample><programlisting>
98  * static gint repeats = 2;
99  * static gint max_size = 8;
100  * static gboolean verbose = FALSE;
101  * static gboolean beep = FALSE;
102  * static gboolean randomize = FALSE;
103  *
104  * static GOptionEntry entries[] =
105  * {
106  *   { "repeats", 'r', 0, G_OPTION_ARG_INT, &repeats, "Average over N repetitions", "N" },
107  *   { "max-size", 'm', 0, G_OPTION_ARG_INT, &max_size, "Test up to 2^M items", "M" },
108  *   { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL },
109  *   { "beep", 'b', 0, G_OPTION_ARG_NONE, &beep, "Beep when done", NULL },
110  *   { "rand", 0, 0, G_OPTION_ARG_NONE, &randomize, "Randomize the data", NULL },
111  *   { NULL }
112  * };
113  *
114  * int
115  * main (int argc, char *argv[])
116  * {
117  *   GError *error = NULL;
118  *   GOptionContext *context;
119  *
120  *   context = g_option_context_new ("- test tree model performance");
121  *   g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
122  *   g_option_context_add_group (context, gtk_get_option_group (TRUE));
123  *   if (!g_option_context_parse (context, &argc, &argv, &error))
124  *     {
125  *       g_print ("option parsing failed: %s\n", error->message);
126  *       exit (1);
127  *     }
128  *
129  *   /&ast; ... &ast;/
130  *
131  * }
132  * </programlisting></informalexample>
133  */
134
135 #include "config.h"
136
137 #include <string.h>
138 #include <stdlib.h>
139 #include <stdio.h>
140 #include <errno.h>
141
142 #if defined __OpenBSD__
143 #include <sys/types.h>
144 #include <unistd.h>
145 #include <sys/param.h>
146 #include <sys/sysctl.h>
147 #endif
148
149 #include "goption.h"
150
151 #include "gprintf.h"
152 #include "glibintl.h"
153
154 #define TRANSLATE(group, str) (((group)->translate_func ? (* (group)->translate_func) ((str), (group)->translate_data) : (str)))
155
156 #define NO_ARG(entry) ((entry)->arg == G_OPTION_ARG_NONE ||       \
157                        ((entry)->arg == G_OPTION_ARG_CALLBACK &&  \
158                         ((entry)->flags & G_OPTION_FLAG_NO_ARG)))
159
160 #define OPTIONAL_ARG(entry) ((entry)->arg == G_OPTION_ARG_CALLBACK &&  \
161                        (entry)->flags & G_OPTION_FLAG_OPTIONAL_ARG)
162
163 typedef struct
164 {
165   GOptionArg arg_type;
166   gpointer arg_data;
167   union
168   {
169     gboolean bool;
170     gint integer;
171     gchar *str;
172     gchar **array;
173     gdouble dbl;
174     gint64 int64;
175   } prev;
176   union
177   {
178     gchar *str;
179     struct
180     {
181       gint len;
182       gchar **data;
183     } array;
184   } allocated;
185 } Change;
186
187 typedef struct
188 {
189   gchar **ptr;
190   gchar *value;
191 } PendingNull;
192
193 struct _GOptionContext
194 {
195   GList           *groups;
196
197   gchar           *parameter_string;
198   gchar           *summary;
199   gchar           *description;
200
201   GTranslateFunc   translate_func;
202   GDestroyNotify   translate_notify;
203   gpointer         translate_data;
204
205   guint            help_enabled   : 1;
206   guint            ignore_unknown : 1;
207   guint            strv_mode      : 1;
208
209   GOptionGroup    *main_group;
210
211   /* We keep a list of change so we can revert them */
212   GList           *changes;
213
214   /* We also keep track of all argv elements
215    * that should be NULLed or modified.
216    */
217   GList           *pending_nulls;
218 };
219
220 struct _GOptionGroup
221 {
222   gchar           *name;
223   gchar           *description;
224   gchar           *help_description;
225
226   GDestroyNotify   destroy_notify;
227   gpointer         user_data;
228
229   GTranslateFunc   translate_func;
230   GDestroyNotify   translate_notify;
231   gpointer         translate_data;
232
233   GOptionEntry    *entries;
234   gint             n_entries;
235
236   GOptionParseFunc pre_parse_func;
237   GOptionParseFunc post_parse_func;
238   GOptionErrorFunc error_func;
239 };
240
241 static void free_changes_list (GOptionContext *context,
242                                gboolean        revert);
243 static void free_pending_nulls (GOptionContext *context,
244                                 gboolean        perform_nulls);
245
246
247 static int
248 _g_unichar_get_width (gunichar c)
249 {
250   if (G_UNLIKELY (g_unichar_iszerowidth (c)))
251     return 0;
252
253   /* we ignore the fact that we should call g_unichar_iswide_cjk() under
254    * some locales (legacy East Asian ones) */
255   if (g_unichar_iswide (c))
256     return 2;
257
258   return 1;
259 }
260
261 static glong
262 _g_utf8_strwidth (const gchar *p)
263 {
264   glong len = 0;
265   g_return_val_if_fail (p != NULL, 0);
266
267   while (*p)
268     {
269       len += _g_unichar_get_width (g_utf8_get_char (p));
270       p = g_utf8_next_char (p);
271     }
272
273   return len;
274 }
275
276 G_DEFINE_QUARK (g-option-context-error-quark, g_option_error)
277
278 /**
279  * g_option_context_new:
280  * @parameter_string: (allow-none): a string which is displayed in
281  *    the first line of <option>--help</option> output, after the
282  *    usage summary
283  *    <literal><replaceable>programname</replaceable> [OPTION...]</literal>
284  *
285  * Creates a new option context.
286  *
287  * The @parameter_string can serve multiple purposes. It can be used
288  * to add descriptions for "rest" arguments, which are not parsed by
289  * the #GOptionContext, typically something like "FILES" or
290  * "FILE1 FILE2...". If you are using #G_OPTION_REMAINING for
291  * collecting "rest" arguments, GLib handles this automatically by
292  * using the @arg_description of the corresponding #GOptionEntry in
293  * the usage summary.
294  *
295  * Another usage is to give a short summary of the program
296  * functionality, like " - frob the strings", which will be displayed
297  * in the same line as the usage. For a longer description of the
298  * program functionality that should be displayed as a paragraph
299  * below the usage line, use g_option_context_set_summary().
300  *
301  * Note that the @parameter_string is translated using the
302  * function set with g_option_context_set_translate_func(), so
303  * it should normally be passed untranslated.
304  *
305  * Returns: a newly created #GOptionContext, which must be
306  *    freed with g_option_context_free() after use.
307  *
308  * Since: 2.6
309  */
310 GOptionContext *
311 g_option_context_new (const gchar *parameter_string)
312
313 {
314   GOptionContext *context;
315
316   context = g_new0 (GOptionContext, 1);
317
318   context->parameter_string = g_strdup (parameter_string);
319   context->help_enabled = TRUE;
320   context->ignore_unknown = FALSE;
321
322   return context;
323 }
324
325 /**
326  * g_option_context_free:
327  * @context: a #GOptionContext
328  *
329  * Frees context and all the groups which have been
330  * added to it.
331  *
332  * Please note that parsed arguments need to be freed separately (see
333  * #GOptionEntry).
334  *
335  * Since: 2.6
336  */
337 void g_option_context_free (GOptionContext *context)
338 {
339   g_return_if_fail (context != NULL);
340
341   g_list_free_full (context->groups, (GDestroyNotify) g_option_group_free);
342
343   if (context->main_group)
344     g_option_group_free (context->main_group);
345
346   free_changes_list (context, FALSE);
347   free_pending_nulls (context, FALSE);
348
349   g_free (context->parameter_string);
350   g_free (context->summary);
351   g_free (context->description);
352
353   if (context->translate_notify)
354     (* context->translate_notify) (context->translate_data);
355
356   g_free (context);
357 }
358
359
360 /**
361  * g_option_context_set_help_enabled:
362  * @context: a #GOptionContext
363  * @help_enabled: %TRUE to enable <option>--help</option>, %FALSE to disable it
364  *
365  * Enables or disables automatic generation of <option>--help</option>
366  * output. By default, g_option_context_parse() recognizes
367  * <option>--help</option>, <option>-h</option>,
368  * <option>-?</option>, <option>--help-all</option>
369  * and <option>--help-</option><replaceable>groupname</replaceable> and creates
370  * suitable output to stdout.
371  *
372  * Since: 2.6
373  */
374 void g_option_context_set_help_enabled (GOptionContext *context,
375                                         gboolean        help_enabled)
376
377 {
378   g_return_if_fail (context != NULL);
379
380   context->help_enabled = help_enabled;
381 }
382
383 /**
384  * g_option_context_get_help_enabled:
385  * @context: a #GOptionContext
386  *
387  * Returns whether automatic <option>--help</option> generation
388  * is turned on for @context. See g_option_context_set_help_enabled().
389  *
390  * Returns: %TRUE if automatic help generation is turned on.
391  *
392  * Since: 2.6
393  */
394 gboolean
395 g_option_context_get_help_enabled (GOptionContext *context)
396 {
397   g_return_val_if_fail (context != NULL, FALSE);
398
399   return context->help_enabled;
400 }
401
402 /**
403  * g_option_context_set_ignore_unknown_options:
404  * @context: a #GOptionContext
405  * @ignore_unknown: %TRUE to ignore unknown options, %FALSE to produce
406  *    an error when unknown options are met
407  *
408  * Sets whether to ignore unknown options or not. If an argument is
409  * ignored, it is left in the @argv array after parsing. By default,
410  * g_option_context_parse() treats unknown options as error.
411  *
412  * This setting does not affect non-option arguments (i.e. arguments
413  * which don't start with a dash). But note that GOption cannot reliably
414  * determine whether a non-option belongs to a preceding unknown option.
415  *
416  * Since: 2.6
417  **/
418 void
419 g_option_context_set_ignore_unknown_options (GOptionContext *context,
420                                              gboolean        ignore_unknown)
421 {
422   g_return_if_fail (context != NULL);
423
424   context->ignore_unknown = ignore_unknown;
425 }
426
427 /**
428  * g_option_context_get_ignore_unknown_options:
429  * @context: a #GOptionContext
430  *
431  * Returns whether unknown options are ignored or not. See
432  * g_option_context_set_ignore_unknown_options().
433  *
434  * Returns: %TRUE if unknown options are ignored.
435  *
436  * Since: 2.6
437  **/
438 gboolean
439 g_option_context_get_ignore_unknown_options (GOptionContext *context)
440 {
441   g_return_val_if_fail (context != NULL, FALSE);
442
443   return context->ignore_unknown;
444 }
445
446 /**
447  * g_option_context_add_group:
448  * @context: a #GOptionContext
449  * @group: the group to add
450  *
451  * Adds a #GOptionGroup to the @context, so that parsing with @context
452  * will recognize the options in the group. Note that the group will
453  * be freed together with the context when g_option_context_free() is
454  * called, so you must not free the group yourself after adding it
455  * to a context.
456  *
457  * Since: 2.6
458  **/
459 void
460 g_option_context_add_group (GOptionContext *context,
461                             GOptionGroup   *group)
462 {
463   GList *list;
464
465   g_return_if_fail (context != NULL);
466   g_return_if_fail (group != NULL);
467   g_return_if_fail (group->name != NULL);
468   g_return_if_fail (group->description != NULL);
469   g_return_if_fail (group->help_description != NULL);
470
471   for (list = context->groups; list; list = list->next)
472     {
473       GOptionGroup *g = (GOptionGroup *)list->data;
474
475       if ((group->name == NULL && g->name == NULL) ||
476           (group->name && g->name && strcmp (group->name, g->name) == 0))
477         g_warning ("A group named \"%s\" is already part of this GOptionContext",
478                    group->name);
479     }
480
481   context->groups = g_list_append (context->groups, group);
482 }
483
484 /**
485  * g_option_context_set_main_group:
486  * @context: a #GOptionContext
487  * @group: the group to set as main group
488  *
489  * Sets a #GOptionGroup as main group of the @context.
490  * This has the same effect as calling g_option_context_add_group(),
491  * the only difference is that the options in the main group are
492  * treated differently when generating <option>--help</option> output.
493  *
494  * Since: 2.6
495  **/
496 void
497 g_option_context_set_main_group (GOptionContext *context,
498                                  GOptionGroup   *group)
499 {
500   g_return_if_fail (context != NULL);
501   g_return_if_fail (group != NULL);
502
503   if (context->main_group)
504     {
505       g_warning ("This GOptionContext already has a main group");
506
507       return;
508     }
509
510   context->main_group = group;
511 }
512
513 /**
514  * g_option_context_get_main_group:
515  * @context: a #GOptionContext
516  *
517  * Returns a pointer to the main group of @context.
518  *
519  * Return value: the main group of @context, or %NULL if @context doesn't
520  *  have a main group. Note that group belongs to @context and should
521  *  not be modified or freed.
522  *
523  * Since: 2.6
524  **/
525 GOptionGroup *
526 g_option_context_get_main_group (GOptionContext *context)
527 {
528   g_return_val_if_fail (context != NULL, NULL);
529
530   return context->main_group;
531 }
532
533 /**
534  * g_option_context_add_main_entries:
535  * @context: a #GOptionContext
536  * @entries: a %NULL-terminated array of #GOptionEntry<!-- -->s
537  * @translation_domain: (allow-none): a translation domain to use for translating
538  *    the <option>--help</option> output for the options in @entries
539  *    with gettext(), or %NULL
540  *
541  * A convenience function which creates a main group if it doesn't
542  * exist, adds the @entries to it and sets the translation domain.
543  *
544  * Since: 2.6
545  **/
546 void
547 g_option_context_add_main_entries (GOptionContext      *context,
548                                    const GOptionEntry  *entries,
549                                    const gchar         *translation_domain)
550 {
551   g_return_if_fail (entries != NULL);
552
553   if (!context->main_group)
554     context->main_group = g_option_group_new (NULL, NULL, NULL, NULL, NULL);
555
556   g_option_group_add_entries (context->main_group, entries);
557   g_option_group_set_translation_domain (context->main_group, translation_domain);
558 }
559
560 static gint
561 calculate_max_length (GOptionGroup *group,
562                       GHashTable   *aliases)
563 {
564   GOptionEntry *entry;
565   gint i, len, max_length;
566   const gchar *long_name;
567
568   max_length = 0;
569
570   for (i = 0; i < group->n_entries; i++)
571     {
572       entry = &group->entries[i];
573
574       if (entry->flags & G_OPTION_FLAG_HIDDEN)
575         continue;
576
577       long_name = g_hash_table_lookup (aliases, &entry->long_name);
578       if (!long_name)
579         long_name = entry->long_name;
580       len = _g_utf8_strwidth (long_name);
581
582       if (entry->short_name)
583         len += 4;
584
585       if (!NO_ARG (entry) && entry->arg_description)
586         len += 1 + _g_utf8_strwidth (TRANSLATE (group, entry->arg_description));
587
588       max_length = MAX (max_length, len);
589     }
590
591   return max_length;
592 }
593
594 static void
595 print_entry (GOptionGroup       *group,
596              gint                max_length,
597              const GOptionEntry *entry,
598              GString            *string,
599              GHashTable         *aliases)
600 {
601   GString *str;
602   const gchar *long_name;
603
604   if (entry->flags & G_OPTION_FLAG_HIDDEN)
605     return;
606
607   if (entry->long_name[0] == 0)
608     return;
609
610   long_name = g_hash_table_lookup (aliases, &entry->long_name);
611   if (!long_name)
612     long_name = entry->long_name;
613
614   str = g_string_new (NULL);
615
616   if (entry->short_name)
617     g_string_append_printf (str, "  -%c, --%s", entry->short_name, long_name);
618   else
619     g_string_append_printf (str, "  --%s", long_name);
620
621   if (entry->arg_description)
622     g_string_append_printf (str, "=%s", TRANSLATE (group, entry->arg_description));
623
624   g_string_append_printf (string, "%s%*s %s\n", str->str,
625                           (int) (max_length + 4 - _g_utf8_strwidth (str->str)), "",
626                           entry->description ? TRANSLATE (group, entry->description) : "");
627   g_string_free (str, TRUE);
628 }
629
630 static gboolean
631 group_has_visible_entries (GOptionContext *context,
632                            GOptionGroup *group,
633                            gboolean      main_entries)
634 {
635   GOptionFlags reject_filter = G_OPTION_FLAG_HIDDEN;
636   GOptionEntry *entry;
637   gint i, l;
638   gboolean main_group = group == context->main_group;
639
640   if (!main_entries)
641     reject_filter |= G_OPTION_FLAG_IN_MAIN;
642
643   for (i = 0, l = (group ? group->n_entries : 0); i < l; i++)
644     {
645       entry = &group->entries[i];
646
647       if (main_entries && !main_group && !(entry->flags & G_OPTION_FLAG_IN_MAIN))
648         continue;
649       if (entry->long_name[0] == 0) /* ignore rest entry */
650         continue;
651       if (!(entry->flags & reject_filter))
652         return TRUE;
653     }
654
655   return FALSE;
656 }
657
658 static gboolean
659 group_list_has_visible_entries (GOptionContext *context,
660                                 GList          *group_list,
661                                 gboolean       main_entries)
662 {
663   while (group_list)
664     {
665       if (group_has_visible_entries (context, group_list->data, main_entries))
666         return TRUE;
667
668       group_list = group_list->next;
669     }
670
671   return FALSE;
672 }
673
674 static gboolean
675 context_has_h_entry (GOptionContext *context)
676 {
677   gsize i;
678   GList *list;
679
680   if (context->main_group)
681     {
682       for (i = 0; i < context->main_group->n_entries; i++)
683         {
684           if (context->main_group->entries[i].short_name == 'h')
685             return TRUE;
686         }
687     }
688
689   for (list = context->groups; list != NULL; list = g_list_next (list))
690     {
691      GOptionGroup *group;
692
693       group = (GOptionGroup*)list->data;
694       for (i = 0; i < group->n_entries; i++)
695         {
696           if (group->entries[i].short_name == 'h')
697             return TRUE;
698         }
699     }
700   return FALSE;
701 }
702
703 /**
704  * g_option_context_get_help:
705  * @context: a #GOptionContext
706  * @main_help: if %TRUE, only include the main group
707  * @group: (allow-none): the #GOptionGroup to create help for, or %NULL
708  *
709  * Returns a formatted, translated help text for the given context.
710  * To obtain the text produced by <option>--help</option>, call
711  * <literal>g_option_context_get_help (context, TRUE, NULL)</literal>.
712  * To obtain the text produced by <option>--help-all</option>, call
713  * <literal>g_option_context_get_help (context, FALSE, NULL)</literal>.
714  * To obtain the help text for an option group, call
715  * <literal>g_option_context_get_help (context, FALSE, group)</literal>.
716  *
717  * Returns: A newly allocated string containing the help text
718  *
719  * Since: 2.14
720  */
721 gchar *
722 g_option_context_get_help (GOptionContext *context,
723                            gboolean        main_help,
724                            GOptionGroup   *group)
725 {
726   GList *list;
727   gint max_length = 0, len;
728   gint i;
729   GOptionEntry *entry;
730   GHashTable *shadow_map;
731   GHashTable *aliases;
732   gboolean seen[256];
733   const gchar *rest_description;
734   GString *string;
735   guchar token;
736
737   string = g_string_sized_new (1024);
738
739   rest_description = NULL;
740   if (context->main_group)
741     {
742
743       for (i = 0; i < context->main_group->n_entries; i++)
744         {
745           entry = &context->main_group->entries[i];
746           if (entry->long_name[0] == 0)
747             {
748               rest_description = TRANSLATE (context->main_group, entry->arg_description);
749               break;
750             }
751         }
752     }
753
754   g_string_append_printf (string, "%s\n  %s %s",
755                           _("Usage:"), g_get_prgname(), _("[OPTION...]"));
756
757   if (rest_description)
758     {
759       g_string_append (string, " ");
760       g_string_append (string, rest_description);
761     }
762
763   if (context->parameter_string)
764     {
765       g_string_append (string, " ");
766       g_string_append (string, TRANSLATE (context, context->parameter_string));
767     }
768
769   g_string_append (string, "\n\n");
770
771   if (context->summary)
772     {
773       g_string_append (string, TRANSLATE (context, context->summary));
774       g_string_append (string, "\n\n");
775     }
776
777   memset (seen, 0, sizeof (gboolean) * 256);
778   shadow_map = g_hash_table_new (g_str_hash, g_str_equal);
779   aliases = g_hash_table_new_full (NULL, NULL, NULL, g_free);
780
781   if (context->main_group)
782     {
783       for (i = 0; i < context->main_group->n_entries; i++)
784         {
785           entry = &context->main_group->entries[i];
786           g_hash_table_insert (shadow_map,
787                                (gpointer)entry->long_name,
788                                entry);
789
790           if (seen[(guchar)entry->short_name])
791             entry->short_name = 0;
792           else
793             seen[(guchar)entry->short_name] = TRUE;
794         }
795     }
796
797   list = context->groups;
798   while (list != NULL)
799     {
800       GOptionGroup *g = list->data;
801       for (i = 0; i < g->n_entries; i++)
802         {
803           entry = &g->entries[i];
804           if (g_hash_table_lookup (shadow_map, entry->long_name) &&
805               !(entry->flags & G_OPTION_FLAG_NOALIAS))
806             {
807               g_hash_table_insert (aliases, &entry->long_name,
808                                    g_strdup_printf ("%s-%s", g->name, entry->long_name));
809             }
810           else
811             g_hash_table_insert (shadow_map, (gpointer)entry->long_name, entry);
812
813           if (seen[(guchar)entry->short_name] &&
814               !(entry->flags & G_OPTION_FLAG_NOALIAS))
815             entry->short_name = 0;
816           else
817             seen[(guchar)entry->short_name] = TRUE;
818         }
819       list = list->next;
820     }
821
822   g_hash_table_destroy (shadow_map);
823
824   list = context->groups;
825
826   if (context->help_enabled)
827     {
828       max_length = _g_utf8_strwidth ("-?, --help");
829
830       if (list)
831         {
832           len = _g_utf8_strwidth ("--help-all");
833           max_length = MAX (max_length, len);
834         }
835     }
836
837   if (context->main_group)
838     {
839       len = calculate_max_length (context->main_group, aliases);
840       max_length = MAX (max_length, len);
841     }
842
843   while (list != NULL)
844     {
845       GOptionGroup *g = list->data;
846
847       if (context->help_enabled)
848         {
849           /* First, we check the --help-<groupname> options */
850           len = _g_utf8_strwidth ("--help-") + _g_utf8_strwidth (g->name);
851           max_length = MAX (max_length, len);
852         }
853
854       /* Then we go through the entries */
855       len = calculate_max_length (g, aliases);
856       max_length = MAX (max_length, len);
857
858       list = list->next;
859     }
860
861   /* Add a bit of padding */
862   max_length += 4;
863
864   if (!group && context->help_enabled)
865     {
866       list = context->groups;
867
868       token = context_has_h_entry (context) ? '?' : 'h';
869
870       g_string_append_printf (string, "%s\n  -%c, --%-*s %s\n",
871                               _("Help Options:"), token, max_length - 4, "help",
872                               _("Show help options"));
873
874       /* We only want --help-all when there are groups */
875       if (list)
876         g_string_append_printf (string, "  --%-*s %s\n",
877                                 max_length, "help-all",
878                                 _("Show all help options"));
879
880       while (list)
881         {
882           GOptionGroup *g = list->data;
883
884           if (group_has_visible_entries (context, g, FALSE))
885             g_string_append_printf (string, "  --help-%-*s %s\n",
886                                     max_length - 5, g->name,
887                                     TRANSLATE (g, g->help_description));
888
889           list = list->next;
890         }
891
892       g_string_append (string, "\n");
893     }
894
895   if (group)
896     {
897       /* Print a certain group */
898
899       if (group_has_visible_entries (context, group, FALSE))
900         {
901           g_string_append (string, TRANSLATE (group, group->description));
902           g_string_append (string, "\n");
903           for (i = 0; i < group->n_entries; i++)
904             print_entry (group, max_length, &group->entries[i], string, aliases);
905           g_string_append (string, "\n");
906         }
907     }
908   else if (!main_help)
909     {
910       /* Print all groups */
911
912       list = context->groups;
913
914       while (list)
915         {
916           GOptionGroup *g = list->data;
917
918           if (group_has_visible_entries (context, g, FALSE))
919             {
920               g_string_append (string, g->description);
921               g_string_append (string, "\n");
922               for (i = 0; i < g->n_entries; i++)
923                 if (!(g->entries[i].flags & G_OPTION_FLAG_IN_MAIN))
924                   print_entry (g, max_length, &g->entries[i], string, aliases);
925
926               g_string_append (string, "\n");
927             }
928
929           list = list->next;
930         }
931     }
932
933   /* Print application options if --help or --help-all has been specified */
934   if ((main_help || !group) &&
935       (group_has_visible_entries (context, context->main_group, TRUE) ||
936        group_list_has_visible_entries (context, context->groups, TRUE)))
937     {
938       list = context->groups;
939
940       g_string_append (string,  _("Application Options:"));
941       g_string_append (string, "\n");
942       if (context->main_group)
943         for (i = 0; i < context->main_group->n_entries; i++)
944           print_entry (context->main_group, max_length,
945                        &context->main_group->entries[i], string, aliases);
946
947       while (list != NULL)
948         {
949           GOptionGroup *g = list->data;
950
951           /* Print main entries from other groups */
952           for (i = 0; i < g->n_entries; i++)
953             if (g->entries[i].flags & G_OPTION_FLAG_IN_MAIN)
954               print_entry (g, max_length, &g->entries[i], string, aliases);
955
956           list = list->next;
957         }
958
959       g_string_append (string, "\n");
960     }
961
962   if (context->description)
963     {
964       g_string_append (string, TRANSLATE (context, context->description));
965       g_string_append (string, "\n");
966     }
967
968   g_hash_table_destroy (aliases);
969
970   return g_string_free (string, FALSE);
971 }
972
973 G_GNUC_NORETURN
974 static void
975 print_help (GOptionContext *context,
976             gboolean        main_help,
977             GOptionGroup   *group)
978 {
979   gchar *help;
980
981   help = g_option_context_get_help (context, main_help, group);
982   g_print ("%s", help);
983   g_free (help);
984
985   exit (0);
986 }
987
988 static gboolean
989 parse_int (const gchar *arg_name,
990            const gchar *arg,
991            gint        *result,
992            GError     **error)
993 {
994   gchar *end;
995   glong tmp;
996
997   errno = 0;
998   tmp = strtol (arg, &end, 0);
999
1000   if (*arg == '\0' || *end != '\0')
1001     {
1002       g_set_error (error,
1003                    G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1004                    _("Cannot parse integer value '%s' for %s"),
1005                    arg, arg_name);
1006       return FALSE;
1007     }
1008
1009   *result = tmp;
1010   if (*result != tmp || errno == ERANGE)
1011     {
1012       g_set_error (error,
1013                    G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1014                    _("Integer value '%s' for %s out of range"),
1015                    arg, arg_name);
1016       return FALSE;
1017     }
1018
1019   return TRUE;
1020 }
1021
1022
1023 static gboolean
1024 parse_double (const gchar *arg_name,
1025            const gchar *arg,
1026            gdouble        *result,
1027            GError     **error)
1028 {
1029   gchar *end;
1030   gdouble tmp;
1031
1032   errno = 0;
1033   tmp = g_strtod (arg, &end);
1034
1035   if (*arg == '\0' || *end != '\0')
1036     {
1037       g_set_error (error,
1038                    G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1039                    _("Cannot parse double value '%s' for %s"),
1040                    arg, arg_name);
1041       return FALSE;
1042     }
1043   if (errno == ERANGE)
1044     {
1045       g_set_error (error,
1046                    G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1047                    _("Double value '%s' for %s out of range"),
1048                    arg, arg_name);
1049       return FALSE;
1050     }
1051
1052   *result = tmp;
1053
1054   return TRUE;
1055 }
1056
1057
1058 static gboolean
1059 parse_int64 (const gchar *arg_name,
1060              const gchar *arg,
1061              gint64      *result,
1062              GError     **error)
1063 {
1064   gchar *end;
1065   gint64 tmp;
1066
1067   errno = 0;
1068   tmp = g_ascii_strtoll (arg, &end, 0);
1069
1070   if (*arg == '\0' || *end != '\0')
1071     {
1072       g_set_error (error,
1073                    G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1074                    _("Cannot parse integer value '%s' for %s"),
1075                    arg, arg_name);
1076       return FALSE;
1077     }
1078   if (errno == ERANGE)
1079     {
1080       g_set_error (error,
1081                    G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1082                    _("Integer value '%s' for %s out of range"),
1083                    arg, arg_name);
1084       return FALSE;
1085     }
1086
1087   *result = tmp;
1088
1089   return TRUE;
1090 }
1091
1092
1093 static Change *
1094 get_change (GOptionContext *context,
1095             GOptionArg      arg_type,
1096             gpointer        arg_data)
1097 {
1098   GList *list;
1099   Change *change = NULL;
1100
1101   for (list = context->changes; list != NULL; list = list->next)
1102     {
1103       change = list->data;
1104
1105       if (change->arg_data == arg_data)
1106         goto found;
1107     }
1108
1109   change = g_new0 (Change, 1);
1110   change->arg_type = arg_type;
1111   change->arg_data = arg_data;
1112
1113   context->changes = g_list_prepend (context->changes, change);
1114
1115  found:
1116
1117   return change;
1118 }
1119
1120 static void
1121 add_pending_null (GOptionContext *context,
1122                   gchar         **ptr,
1123                   gchar          *value)
1124 {
1125   PendingNull *n;
1126
1127   n = g_new0 (PendingNull, 1);
1128   n->ptr = ptr;
1129   n->value = value;
1130
1131   context->pending_nulls = g_list_prepend (context->pending_nulls, n);
1132 }
1133
1134 static gboolean
1135 parse_arg (GOptionContext *context,
1136            GOptionGroup   *group,
1137            GOptionEntry   *entry,
1138            const gchar    *value,
1139            const gchar    *option_name,
1140            GError        **error)
1141
1142 {
1143   Change *change;
1144
1145   g_assert (value || OPTIONAL_ARG (entry) || NO_ARG (entry));
1146
1147   switch (entry->arg)
1148     {
1149     case G_OPTION_ARG_NONE:
1150       {
1151         change = get_change (context, G_OPTION_ARG_NONE,
1152                              entry->arg_data);
1153
1154         *(gboolean *)entry->arg_data = !(entry->flags & G_OPTION_FLAG_REVERSE);
1155         break;
1156       }
1157     case G_OPTION_ARG_STRING:
1158       {
1159         gchar *data;
1160
1161         data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
1162
1163         if (!data)
1164           return FALSE;
1165
1166         change = get_change (context, G_OPTION_ARG_STRING,
1167                              entry->arg_data);
1168         g_free (change->allocated.str);
1169
1170         change->prev.str = *(gchar **)entry->arg_data;
1171         change->allocated.str = data;
1172
1173         *(gchar **)entry->arg_data = data;
1174         break;
1175       }
1176     case G_OPTION_ARG_STRING_ARRAY:
1177       {
1178         gchar *data;
1179
1180         data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
1181
1182         if (!data)
1183           return FALSE;
1184
1185         change = get_change (context, G_OPTION_ARG_STRING_ARRAY,
1186                              entry->arg_data);
1187
1188         if (change->allocated.array.len == 0)
1189           {
1190             change->prev.array = *(gchar ***)entry->arg_data;
1191             change->allocated.array.data = g_new (gchar *, 2);
1192           }
1193         else
1194           change->allocated.array.data =
1195             g_renew (gchar *, change->allocated.array.data,
1196                      change->allocated.array.len + 2);
1197
1198         change->allocated.array.data[change->allocated.array.len] = data;
1199         change->allocated.array.data[change->allocated.array.len + 1] = NULL;
1200
1201         change->allocated.array.len ++;
1202
1203         *(gchar ***)entry->arg_data = change->allocated.array.data;
1204
1205         break;
1206       }
1207
1208     case G_OPTION_ARG_FILENAME:
1209       {
1210         gchar *data;
1211
1212 #ifdef G_OS_WIN32
1213         data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
1214
1215         if (!data)
1216           return FALSE;
1217 #else
1218         data = g_strdup (value);
1219 #endif
1220         change = get_change (context, G_OPTION_ARG_FILENAME,
1221                              entry->arg_data);
1222         g_free (change->allocated.str);
1223
1224         change->prev.str = *(gchar **)entry->arg_data;
1225         change->allocated.str = data;
1226
1227         *(gchar **)entry->arg_data = data;
1228         break;
1229       }
1230
1231     case G_OPTION_ARG_FILENAME_ARRAY:
1232       {
1233         gchar *data;
1234
1235 #ifdef G_OS_WIN32
1236         data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
1237
1238         if (!data)
1239           return FALSE;
1240 #else
1241         data = g_strdup (value);
1242 #endif
1243         change = get_change (context, G_OPTION_ARG_STRING_ARRAY,
1244                              entry->arg_data);
1245
1246         if (change->allocated.array.len == 0)
1247           {
1248             change->prev.array = *(gchar ***)entry->arg_data;
1249             change->allocated.array.data = g_new (gchar *, 2);
1250           }
1251         else
1252           change->allocated.array.data =
1253             g_renew (gchar *, change->allocated.array.data,
1254                      change->allocated.array.len + 2);
1255
1256         change->allocated.array.data[change->allocated.array.len] = data;
1257         change->allocated.array.data[change->allocated.array.len + 1] = NULL;
1258
1259         change->allocated.array.len ++;
1260
1261         *(gchar ***)entry->arg_data = change->allocated.array.data;
1262
1263         break;
1264       }
1265
1266     case G_OPTION_ARG_INT:
1267       {
1268         gint data;
1269
1270         if (!parse_int (option_name, value,
1271                         &data,
1272                         error))
1273           return FALSE;
1274
1275         change = get_change (context, G_OPTION_ARG_INT,
1276                              entry->arg_data);
1277         change->prev.integer = *(gint *)entry->arg_data;
1278         *(gint *)entry->arg_data = data;
1279         break;
1280       }
1281     case G_OPTION_ARG_CALLBACK:
1282       {
1283         gchar *data;
1284         gboolean retval;
1285
1286         if (!value && entry->flags & G_OPTION_FLAG_OPTIONAL_ARG)
1287           data = NULL;
1288         else if (entry->flags & G_OPTION_FLAG_NO_ARG)
1289           data = NULL;
1290         else if (entry->flags & G_OPTION_FLAG_FILENAME)
1291           {
1292 #ifdef G_OS_WIN32
1293             data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
1294 #else
1295             data = g_strdup (value);
1296 #endif
1297           }
1298         else
1299           data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
1300
1301         if (!(entry->flags & (G_OPTION_FLAG_NO_ARG|G_OPTION_FLAG_OPTIONAL_ARG)) &&
1302             !data)
1303           return FALSE;
1304
1305         retval = (* (GOptionArgFunc) entry->arg_data) (option_name, data, group->user_data, error);
1306
1307         if (!retval && error != NULL && *error == NULL)
1308           g_set_error (error,
1309                        G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
1310                        _("Error parsing option %s"), option_name);
1311
1312         g_free (data);
1313
1314         return retval;
1315
1316         break;
1317       }
1318     case G_OPTION_ARG_DOUBLE:
1319       {
1320         gdouble data;
1321
1322         if (!parse_double (option_name, value,
1323                         &data,
1324                         error))
1325           {
1326             return FALSE;
1327           }
1328
1329         change = get_change (context, G_OPTION_ARG_DOUBLE,
1330                              entry->arg_data);
1331         change->prev.dbl = *(gdouble *)entry->arg_data;
1332         *(gdouble *)entry->arg_data = data;
1333         break;
1334       }
1335     case G_OPTION_ARG_INT64:
1336       {
1337         gint64 data;
1338
1339         if (!parse_int64 (option_name, value,
1340                          &data,
1341                          error))
1342           {
1343             return FALSE;
1344           }
1345
1346         change = get_change (context, G_OPTION_ARG_INT64,
1347                              entry->arg_data);
1348         change->prev.int64 = *(gint64 *)entry->arg_data;
1349         *(gint64 *)entry->arg_data = data;
1350         break;
1351       }
1352     default:
1353       g_assert_not_reached ();
1354     }
1355
1356   return TRUE;
1357 }
1358
1359 static gboolean
1360 parse_short_option (GOptionContext *context,
1361                     GOptionGroup   *group,
1362                     gint            idx,
1363                     gint           *new_idx,
1364                     gchar           arg,
1365                     gint           *argc,
1366                     gchar        ***argv,
1367                     GError        **error,
1368                     gboolean       *parsed)
1369 {
1370   gint j;
1371
1372   for (j = 0; j < group->n_entries; j++)
1373     {
1374       if (arg == group->entries[j].short_name)
1375         {
1376           gchar *option_name;
1377           gchar *value = NULL;
1378
1379           option_name = g_strdup_printf ("-%c", group->entries[j].short_name);
1380
1381           if (NO_ARG (&group->entries[j]))
1382             value = NULL;
1383           else
1384             {
1385               if (*new_idx > idx)
1386                 {
1387                   g_set_error (error,
1388                                G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
1389                                _("Error parsing option %s"), option_name);
1390                   g_free (option_name);
1391                   return FALSE;
1392                 }
1393
1394               if (idx < *argc - 1)
1395                 {
1396                   if (!OPTIONAL_ARG (&group->entries[j]))
1397                     {
1398                       value = (*argv)[idx + 1];
1399                       add_pending_null (context, &((*argv)[idx + 1]), NULL);
1400                       *new_idx = idx + 1;
1401                     }
1402                   else
1403                     {
1404                       if ((*argv)[idx + 1][0] == '-')
1405                         value = NULL;
1406                       else
1407                         {
1408                           value = (*argv)[idx + 1];
1409                           add_pending_null (context, &((*argv)[idx + 1]), NULL);
1410                           *new_idx = idx + 1;
1411                         }
1412                     }
1413                 }
1414               else if (idx >= *argc - 1 && OPTIONAL_ARG (&group->entries[j]))
1415                 value = NULL;
1416               else
1417                 {
1418                   g_set_error (error,
1419                                G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1420                                _("Missing argument for %s"), option_name);
1421                   g_free (option_name);
1422                   return FALSE;
1423                 }
1424             }
1425
1426           if (!parse_arg (context, group, &group->entries[j],
1427                           value, option_name, error))
1428             {
1429               g_free (option_name);
1430               return FALSE;
1431             }
1432
1433           g_free (option_name);
1434           *parsed = TRUE;
1435         }
1436     }
1437
1438   return TRUE;
1439 }
1440
1441 static gboolean
1442 parse_long_option (GOptionContext *context,
1443                    GOptionGroup   *group,
1444                    gint           *idx,
1445                    gchar          *arg,
1446                    gboolean        aliased,
1447                    gint           *argc,
1448                    gchar        ***argv,
1449                    GError        **error,
1450                    gboolean       *parsed)
1451 {
1452   gint j;
1453
1454   for (j = 0; j < group->n_entries; j++)
1455     {
1456       if (*idx >= *argc)
1457         return TRUE;
1458
1459       if (aliased && (group->entries[j].flags & G_OPTION_FLAG_NOALIAS))
1460         continue;
1461
1462       if (NO_ARG (&group->entries[j]) &&
1463           strcmp (arg, group->entries[j].long_name) == 0)
1464         {
1465           gchar *option_name;
1466           gboolean retval;
1467
1468           option_name = g_strconcat ("--", group->entries[j].long_name, NULL);
1469           retval = parse_arg (context, group, &group->entries[j],
1470                               NULL, option_name, error);
1471           g_free (option_name);
1472
1473           add_pending_null (context, &((*argv)[*idx]), NULL);
1474           *parsed = TRUE;
1475
1476           return retval;
1477         }
1478       else
1479         {
1480           gint len = strlen (group->entries[j].long_name);
1481
1482           if (strncmp (arg, group->entries[j].long_name, len) == 0 &&
1483               (arg[len] == '=' || arg[len] == 0))
1484             {
1485               gchar *value = NULL;
1486               gchar *option_name;
1487
1488               add_pending_null (context, &((*argv)[*idx]), NULL);
1489               option_name = g_strconcat ("--", group->entries[j].long_name, NULL);
1490
1491               if (arg[len] == '=')
1492                 value = arg + len + 1;
1493               else if (*idx < *argc - 1)
1494                 {
1495                   if (!OPTIONAL_ARG (&group->entries[j]))
1496                     {
1497                       value = (*argv)[*idx + 1];
1498                       add_pending_null (context, &((*argv)[*idx + 1]), NULL);
1499                       (*idx)++;
1500                     }
1501                   else
1502                     {
1503                       if ((*argv)[*idx + 1][0] == '-')
1504                         {
1505                           gboolean retval;
1506                           retval = parse_arg (context, group, &group->entries[j],
1507                                               NULL, option_name, error);
1508                           *parsed = TRUE;
1509                           g_free (option_name);
1510                           return retval;
1511                         }
1512                       else
1513                         {
1514                           value = (*argv)[*idx + 1];
1515                           add_pending_null (context, &((*argv)[*idx + 1]), NULL);
1516                           (*idx)++;
1517                         }
1518                     }
1519                 }
1520               else if (*idx >= *argc - 1 && OPTIONAL_ARG (&group->entries[j]))
1521                 {
1522                     gboolean retval;
1523                     retval = parse_arg (context, group, &group->entries[j],
1524                                         NULL, option_name, error);
1525                     *parsed = TRUE;
1526                     g_free (option_name);
1527                     return retval;
1528                 }
1529               else
1530                 {
1531                   g_set_error (error,
1532                                G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
1533                                _("Missing argument for %s"), option_name);
1534                   g_free (option_name);
1535                   return FALSE;
1536                 }
1537
1538               if (!parse_arg (context, group, &group->entries[j],
1539                               value, option_name, error))
1540                 {
1541                   g_free (option_name);
1542                   return FALSE;
1543                 }
1544
1545               g_free (option_name);
1546               *parsed = TRUE;
1547             }
1548         }
1549     }
1550
1551   return TRUE;
1552 }
1553
1554 static gboolean
1555 parse_remaining_arg (GOptionContext *context,
1556                      GOptionGroup   *group,
1557                      gint           *idx,
1558                      gint           *argc,
1559                      gchar        ***argv,
1560                      GError        **error,
1561                      gboolean       *parsed)
1562 {
1563   gint j;
1564
1565   for (j = 0; j < group->n_entries; j++)
1566     {
1567       if (*idx >= *argc)
1568         return TRUE;
1569
1570       if (group->entries[j].long_name[0])
1571         continue;
1572
1573       g_return_val_if_fail (group->entries[j].arg == G_OPTION_ARG_CALLBACK ||
1574                             group->entries[j].arg == G_OPTION_ARG_STRING_ARRAY ||
1575                             group->entries[j].arg == G_OPTION_ARG_FILENAME_ARRAY, FALSE);
1576
1577       add_pending_null (context, &((*argv)[*idx]), NULL);
1578
1579       if (!parse_arg (context, group, &group->entries[j], (*argv)[*idx], "", error))
1580         return FALSE;
1581
1582       *parsed = TRUE;
1583       return TRUE;
1584     }
1585
1586   return TRUE;
1587 }
1588
1589 static void
1590 free_changes_list (GOptionContext *context,
1591                    gboolean        revert)
1592 {
1593   GList *list;
1594
1595   for (list = context->changes; list != NULL; list = list->next)
1596     {
1597       Change *change = list->data;
1598
1599       if (revert)
1600         {
1601           switch (change->arg_type)
1602             {
1603             case G_OPTION_ARG_NONE:
1604               *(gboolean *)change->arg_data = change->prev.bool;
1605               break;
1606             case G_OPTION_ARG_INT:
1607               *(gint *)change->arg_data = change->prev.integer;
1608               break;
1609             case G_OPTION_ARG_STRING:
1610             case G_OPTION_ARG_FILENAME:
1611               g_free (change->allocated.str);
1612               *(gchar **)change->arg_data = change->prev.str;
1613               break;
1614             case G_OPTION_ARG_STRING_ARRAY:
1615             case G_OPTION_ARG_FILENAME_ARRAY:
1616               g_strfreev (change->allocated.array.data);
1617               *(gchar ***)change->arg_data = change->prev.array;
1618               break;
1619             case G_OPTION_ARG_DOUBLE:
1620               *(gdouble *)change->arg_data = change->prev.dbl;
1621               break;
1622             case G_OPTION_ARG_INT64:
1623               *(gint64 *)change->arg_data = change->prev.int64;
1624               break;
1625             default:
1626               g_assert_not_reached ();
1627             }
1628         }
1629
1630       g_free (change);
1631     }
1632
1633   g_list_free (context->changes);
1634   context->changes = NULL;
1635 }
1636
1637 static void
1638 free_pending_nulls (GOptionContext *context,
1639                     gboolean        perform_nulls)
1640 {
1641   GList *list;
1642
1643   for (list = context->pending_nulls; list != NULL; list = list->next)
1644     {
1645       PendingNull *n = list->data;
1646
1647       if (perform_nulls)
1648         {
1649           if (context->strv_mode)
1650             g_free (*n->ptr);
1651
1652           if (n->value)
1653             {
1654               /* Copy back the short options */
1655               *(n->ptr)[0] = '-';
1656               strcpy (*n->ptr + 1, n->value);
1657             }
1658           else
1659             *n->ptr = NULL;
1660         }
1661
1662       g_free (n->value);
1663       g_free (n);
1664     }
1665
1666   g_list_free (context->pending_nulls);
1667   context->pending_nulls = NULL;
1668 }
1669
1670 /* Use a platform-specific mechanism to look up the first argument to
1671  * the current process. 
1672  * Note if you implement this for other platforms, also add it to
1673  * tests/option-argv0.c
1674  */
1675 static char *
1676 platform_get_argv0 (void)
1677 {
1678 #if defined __linux
1679   char *cmdline;
1680   char *base_arg0;
1681   gsize len;
1682
1683   if (!g_file_get_contents ("/proc/self/cmdline",
1684                             &cmdline,
1685                             &len,
1686                             NULL))
1687     return NULL;
1688   /* Sanity check for a NUL terminator. */
1689   if (!memchr (cmdline, 0, len))
1690     return NULL;
1691   /* We could just return cmdline, but I think it's better
1692    * to hold on to a smaller malloc block; the arguments
1693    * could be large.
1694    */
1695   base_arg0 = g_path_get_basename (cmdline);
1696   g_free (cmdline);
1697   return base_arg0;
1698 #elif defined __OpenBSD__
1699   char **cmdline = NULL;
1700   char *base_arg0;
1701   gsize len = PATH_MAX;
1702
1703   int mib[] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV };
1704
1705   cmdline = (char **) realloc (cmdline, len);
1706
1707   if (sysctl (mib, G_N_ELEMENTS (mib), cmdline, &len, NULL, 0) == -1)
1708     {
1709       g_free (cmdline);
1710       return NULL;
1711     }
1712
1713   /* We could just return cmdline, but I think it's better
1714    * to hold on to a smaller malloc block; the arguments
1715    * could be large.
1716    */
1717   base_arg0 = g_path_get_basename (*cmdline);
1718   g_free (cmdline);
1719   return base_arg0;
1720 #endif
1721
1722   return NULL;
1723 }
1724
1725 /**
1726  * g_option_context_parse:
1727  * @context: a #GOptionContext
1728  * @argc: (inout) (allow-none): a pointer to the number of command line arguments
1729  * @argv: (inout) (array length=argc) (allow-none): a pointer to the array of command line arguments
1730  * @error: a return location for errors
1731  *
1732  * Parses the command line arguments, recognizing options
1733  * which have been added to @context. A side-effect of
1734  * calling this function is that g_set_prgname() will be
1735  * called.
1736  *
1737  * If the parsing is successful, any parsed arguments are
1738  * removed from the array and @argc and @argv are updated
1739  * accordingly. A '--' option is stripped from @argv
1740  * unless there are unparsed options before and after it,
1741  * or some of the options after it start with '-'. In case
1742  * of an error, @argc and @argv are left unmodified.
1743  *
1744  * If automatic <option>--help</option> support is enabled
1745  * (see g_option_context_set_help_enabled()), and the
1746  * @argv array contains one of the recognized help options,
1747  * this function will produce help output to stdout and
1748  * call <literal>exit (0)</literal>.
1749  *
1750  * Note that function depends on the
1751  * <link linkend="setlocale">current locale</link> for
1752  * automatic character set conversion of string and filename
1753  * arguments.
1754  *
1755  * Return value: %TRUE if the parsing was successful,
1756  *               %FALSE if an error occurred
1757  *
1758  * Since: 2.6
1759  **/
1760 gboolean
1761 g_option_context_parse (GOptionContext   *context,
1762                         gint             *argc,
1763                         gchar          ***argv,
1764                         GError          **error)
1765 {
1766   gint i, j, k;
1767   GList *list;
1768
1769   /* Set program name */
1770   if (!g_get_prgname())
1771     {
1772       gchar *prgname;
1773
1774       if (argc && argv && *argc)
1775         prgname = g_path_get_basename ((*argv)[0]);
1776       else
1777         prgname = platform_get_argv0 ();
1778
1779       if (prgname)
1780         g_set_prgname (prgname);
1781       else
1782         g_set_prgname ("<unknown>");
1783
1784       g_free (prgname);
1785     }
1786
1787   /* Call pre-parse hooks */
1788   list = context->groups;
1789   while (list)
1790     {
1791       GOptionGroup *group = list->data;
1792
1793       if (group->pre_parse_func)
1794         {
1795           if (!(* group->pre_parse_func) (context, group,
1796                                           group->user_data, error))
1797             goto fail;
1798         }
1799
1800       list = list->next;
1801     }
1802
1803   if (context->main_group && context->main_group->pre_parse_func)
1804     {
1805       if (!(* context->main_group->pre_parse_func) (context, context->main_group,
1806                                                     context->main_group->user_data, error))
1807         goto fail;
1808     }
1809
1810   if (argc && argv)
1811     {
1812       gboolean stop_parsing = FALSE;
1813       gboolean has_unknown = FALSE;
1814       gint separator_pos = 0;
1815
1816       for (i = 1; i < *argc; i++)
1817         {
1818           gchar *arg, *dash;
1819           gboolean parsed = FALSE;
1820
1821           if ((*argv)[i][0] == '-' && (*argv)[i][1] != '\0' && !stop_parsing)
1822             {
1823               if ((*argv)[i][1] == '-')
1824                 {
1825                   /* -- option */
1826
1827                   arg = (*argv)[i] + 2;
1828
1829                   /* '--' terminates list of arguments */
1830                   if (*arg == 0)
1831                     {
1832                       separator_pos = i;
1833                       stop_parsing = TRUE;
1834                       continue;
1835                     }
1836
1837                   /* Handle help options */
1838                   if (context->help_enabled)
1839                     {
1840                       if (strcmp (arg, "help") == 0)
1841                         print_help (context, TRUE, NULL);
1842                       else if (strcmp (arg, "help-all") == 0)
1843                         print_help (context, FALSE, NULL);
1844                       else if (strncmp (arg, "help-", 5) == 0)
1845                         {
1846                           list = context->groups;
1847
1848                           while (list)
1849                             {
1850                               GOptionGroup *group = list->data;
1851
1852                               if (strcmp (arg + 5, group->name) == 0)
1853                                 print_help (context, FALSE, group);
1854
1855                               list = list->next;
1856                             }
1857                         }
1858                     }
1859
1860                   if (context->main_group &&
1861                       !parse_long_option (context, context->main_group, &i, arg,
1862                                           FALSE, argc, argv, error, &parsed))
1863                     goto fail;
1864
1865                   if (parsed)
1866                     continue;
1867
1868                   /* Try the groups */
1869                   list = context->groups;
1870                   while (list)
1871                     {
1872                       GOptionGroup *group = list->data;
1873
1874                       if (!parse_long_option (context, group, &i, arg,
1875                                               FALSE, argc, argv, error, &parsed))
1876                         goto fail;
1877
1878                       if (parsed)
1879                         break;
1880
1881                       list = list->next;
1882                     }
1883
1884                   if (parsed)
1885                     continue;
1886
1887                   /* Now look for --<group>-<option> */
1888                   dash = strchr (arg, '-');
1889                   if (dash)
1890                     {
1891                       /* Try the groups */
1892                       list = context->groups;
1893                       while (list)
1894                         {
1895                           GOptionGroup *group = list->data;
1896
1897                           if (strncmp (group->name, arg, dash - arg) == 0)
1898                             {
1899                               if (!parse_long_option (context, group, &i, dash + 1,
1900                                                       TRUE, argc, argv, error, &parsed))
1901                                 goto fail;
1902
1903                               if (parsed)
1904                                 break;
1905                             }
1906
1907                           list = list->next;
1908                         }
1909                     }
1910
1911                   if (context->ignore_unknown)
1912                     continue;
1913                 }
1914               else
1915                 { /* short option */
1916                   gint new_i = i, arg_length;
1917                   gboolean *nulled_out = NULL;
1918                   gboolean has_h_entry = context_has_h_entry (context);
1919                   arg = (*argv)[i] + 1;
1920                   arg_length = strlen (arg);
1921                   nulled_out = g_newa (gboolean, arg_length);
1922                   memset (nulled_out, 0, arg_length * sizeof (gboolean));
1923                   for (j = 0; j < arg_length; j++)
1924                     {
1925                       if (context->help_enabled && (arg[j] == '?' ||
1926                         (arg[j] == 'h' && !has_h_entry)))
1927                         print_help (context, TRUE, NULL);
1928                       parsed = FALSE;
1929                       if (context->main_group &&
1930                           !parse_short_option (context, context->main_group,
1931                                                i, &new_i, arg[j],
1932                                                argc, argv, error, &parsed))
1933                         goto fail;
1934                       if (!parsed)
1935                         {
1936                           /* Try the groups */
1937                           list = context->groups;
1938                           while (list)
1939                             {
1940                               GOptionGroup *group = list->data;
1941                               if (!parse_short_option (context, group, i, &new_i, arg[j],
1942                                                        argc, argv, error, &parsed))
1943                                 goto fail;
1944                               if (parsed)
1945                                 break;
1946                               list = list->next;
1947                             }
1948                         }
1949
1950                       if (context->ignore_unknown && parsed)
1951                         nulled_out[j] = TRUE;
1952                       else if (context->ignore_unknown)
1953                         continue;
1954                       else if (!parsed)
1955                         break;
1956                       /* !context->ignore_unknown && parsed */
1957                     }
1958                   if (context->ignore_unknown)
1959                     {
1960                       gchar *new_arg = NULL;
1961                       gint arg_index = 0;
1962                       for (j = 0; j < arg_length; j++)
1963                         {
1964                           if (!nulled_out[j])
1965                             {
1966                               if (!new_arg)
1967                                 new_arg = g_malloc (arg_length + 1);
1968                               new_arg[arg_index++] = arg[j];
1969                             }
1970                         }
1971                       if (new_arg)
1972                         new_arg[arg_index] = '\0';
1973                       add_pending_null (context, &((*argv)[i]), new_arg);
1974                     }
1975                   else if (parsed)
1976                     {
1977                       add_pending_null (context, &((*argv)[i]), NULL);
1978                       i = new_i;
1979                     }
1980                 }
1981
1982               if (!parsed)
1983                 has_unknown = TRUE;
1984
1985               if (!parsed && !context->ignore_unknown)
1986                 {
1987                   g_set_error (error,
1988                                G_OPTION_ERROR, G_OPTION_ERROR_UNKNOWN_OPTION,
1989                                    _("Unknown option %s"), (*argv)[i]);
1990                   goto fail;
1991                 }
1992             }
1993           else
1994             {
1995               /* Collect remaining args */
1996               if (context->main_group &&
1997                   !parse_remaining_arg (context, context->main_group, &i,
1998                                         argc, argv, error, &parsed))
1999                 goto fail;
2000
2001               if (!parsed && (has_unknown || (*argv)[i][0] == '-'))
2002                 separator_pos = 0;
2003             }
2004         }
2005
2006       if (separator_pos > 0)
2007         add_pending_null (context, &((*argv)[separator_pos]), NULL);
2008
2009     }
2010
2011   /* Call post-parse hooks */
2012   list = context->groups;
2013   while (list)
2014     {
2015       GOptionGroup *group = list->data;
2016
2017       if (group->post_parse_func)
2018         {
2019           if (!(* group->post_parse_func) (context, group,
2020                                            group->user_data, error))
2021             goto fail;
2022         }
2023
2024       list = list->next;
2025     }
2026
2027   if (context->main_group && context->main_group->post_parse_func)
2028     {
2029       if (!(* context->main_group->post_parse_func) (context, context->main_group,
2030                                                      context->main_group->user_data, error))
2031         goto fail;
2032     }
2033
2034   if (argc && argv)
2035     {
2036       free_pending_nulls (context, TRUE);
2037
2038       for (i = 1; i < *argc; i++)
2039         {
2040           for (k = i; k < *argc; k++)
2041             if ((*argv)[k] != NULL)
2042               break;
2043
2044           if (k > i)
2045             {
2046               k -= i;
2047               for (j = i + k; j < *argc; j++)
2048                 {
2049                   (*argv)[j-k] = (*argv)[j];
2050                   (*argv)[j] = NULL;
2051                 }
2052               *argc -= k;
2053             }
2054         }
2055     }
2056
2057   return TRUE;
2058
2059  fail:
2060
2061   /* Call error hooks */
2062   list = context->groups;
2063   while (list)
2064     {
2065       GOptionGroup *group = list->data;
2066
2067       if (group->error_func)
2068         (* group->error_func) (context, group,
2069                                group->user_data, error);
2070
2071       list = list->next;
2072     }
2073
2074   if (context->main_group && context->main_group->error_func)
2075     (* context->main_group->error_func) (context, context->main_group,
2076                                          context->main_group->user_data, error);
2077
2078   free_changes_list (context, TRUE);
2079   free_pending_nulls (context, FALSE);
2080
2081   return FALSE;
2082 }
2083
2084 /**
2085  * g_option_group_new:
2086  * @name: the name for the option group, this is used to provide
2087  *   help for the options in this group with <option>--help-</option>@name
2088  * @description: a description for this group to be shown in
2089  *   <option>--help</option>. This string is translated using the translation
2090  *   domain or translation function of the group
2091  * @help_description: a description for the <option>--help-</option>@name option.
2092  *   This string is translated using the translation domain or translation function
2093  *   of the group
2094  * @user_data: (allow-none): user data that will be passed to the pre- and post-parse hooks,
2095  *   the error hook and to callbacks of %G_OPTION_ARG_CALLBACK options, or %NULL
2096  * @destroy: (allow-none): a function that will be called to free @user_data, or %NULL
2097  *
2098  * Creates a new #GOptionGroup.
2099  *
2100  * Return value: a newly created option group. It should be added
2101  *   to a #GOptionContext or freed with g_option_group_free().
2102  *
2103  * Since: 2.6
2104  **/
2105 GOptionGroup *
2106 g_option_group_new (const gchar    *name,
2107                     const gchar    *description,
2108                     const gchar    *help_description,
2109                     gpointer        user_data,
2110                     GDestroyNotify  destroy)
2111
2112 {
2113   GOptionGroup *group;
2114
2115   group = g_new0 (GOptionGroup, 1);
2116   group->name = g_strdup (name);
2117   group->description = g_strdup (description);
2118   group->help_description = g_strdup (help_description);
2119   group->user_data = user_data;
2120   group->destroy_notify = destroy;
2121
2122   return group;
2123 }
2124
2125
2126 /**
2127  * g_option_group_free:
2128  * @group: a #GOptionGroup
2129  *
2130  * Frees a #GOptionGroup. Note that you must <emphasis>not</emphasis>
2131  * free groups which have been added to a #GOptionContext.
2132  *
2133  * Since: 2.6
2134  **/
2135 void
2136 g_option_group_free (GOptionGroup *group)
2137 {
2138   g_return_if_fail (group != NULL);
2139
2140   g_free (group->name);
2141   g_free (group->description);
2142   g_free (group->help_description);
2143
2144   g_free (group->entries);
2145
2146   if (group->destroy_notify)
2147     (* group->destroy_notify) (group->user_data);
2148
2149   if (group->translate_notify)
2150     (* group->translate_notify) (group->translate_data);
2151
2152   g_free (group);
2153 }
2154
2155
2156 /**
2157  * g_option_group_add_entries:
2158  * @group: a #GOptionGroup
2159  * @entries: a %NULL-terminated array of #GOptionEntry<!-- -->s
2160  *
2161  * Adds the options specified in @entries to @group.
2162  *
2163  * Since: 2.6
2164  **/
2165 void
2166 g_option_group_add_entries (GOptionGroup       *group,
2167                             const GOptionEntry *entries)
2168 {
2169   gint i, n_entries;
2170
2171   g_return_if_fail (entries != NULL);
2172
2173   for (n_entries = 0; entries[n_entries].long_name != NULL; n_entries++) ;
2174
2175   group->entries = g_renew (GOptionEntry, group->entries, group->n_entries + n_entries);
2176
2177   memcpy (group->entries + group->n_entries, entries, sizeof (GOptionEntry) * n_entries);
2178
2179   for (i = group->n_entries; i < group->n_entries + n_entries; i++)
2180     {
2181       gchar c = group->entries[i].short_name;
2182
2183       if (c == '-' || (c != 0 && !g_ascii_isprint (c)))
2184         {
2185           g_warning (G_STRLOC ": ignoring invalid short option '%c' (%d) in entry %s:%s",
2186               c, c, group->name, group->entries[i].long_name);
2187           group->entries[i].short_name = '\0';
2188         }
2189
2190       if (group->entries[i].arg != G_OPTION_ARG_NONE &&
2191           (group->entries[i].flags & G_OPTION_FLAG_REVERSE) != 0)
2192         {
2193           g_warning (G_STRLOC ": ignoring reverse flag on option of arg-type %d in entry %s:%s",
2194               group->entries[i].arg, group->name, group->entries[i].long_name);
2195
2196           group->entries[i].flags &= ~G_OPTION_FLAG_REVERSE;
2197         }
2198
2199       if (group->entries[i].arg != G_OPTION_ARG_CALLBACK &&
2200           (group->entries[i].flags & (G_OPTION_FLAG_NO_ARG|G_OPTION_FLAG_OPTIONAL_ARG|G_OPTION_FLAG_FILENAME)) != 0)
2201         {
2202           g_warning (G_STRLOC ": ignoring no-arg, optional-arg or filename flags (%d) on option of arg-type %d in entry %s:%s",
2203               group->entries[i].flags, group->entries[i].arg, group->name, group->entries[i].long_name);
2204
2205           group->entries[i].flags &= ~(G_OPTION_FLAG_NO_ARG|G_OPTION_FLAG_OPTIONAL_ARG|G_OPTION_FLAG_FILENAME);
2206         }
2207     }
2208
2209   group->n_entries += n_entries;
2210 }
2211
2212 /**
2213  * g_option_group_set_parse_hooks:
2214  * @group: a #GOptionGroup
2215  * @pre_parse_func: (allow-none): a function to call before parsing, or %NULL
2216  * @post_parse_func: (allow-none): a function to call after parsing, or %NULL
2217  *
2218  * Associates two functions with @group which will be called
2219  * from g_option_context_parse() before the first option is parsed
2220  * and after the last option has been parsed, respectively.
2221  *
2222  * Note that the user data to be passed to @pre_parse_func and
2223  * @post_parse_func can be specified when constructing the group
2224  * with g_option_group_new().
2225  *
2226  * Since: 2.6
2227  **/
2228 void
2229 g_option_group_set_parse_hooks (GOptionGroup     *group,
2230                                 GOptionParseFunc  pre_parse_func,
2231                                 GOptionParseFunc  post_parse_func)
2232 {
2233   g_return_if_fail (group != NULL);
2234
2235   group->pre_parse_func = pre_parse_func;
2236   group->post_parse_func = post_parse_func;
2237 }
2238
2239 /**
2240  * g_option_group_set_error_hook:
2241  * @group: a #GOptionGroup
2242  * @error_func: a function to call when an error occurs
2243  *
2244  * Associates a function with @group which will be called
2245  * from g_option_context_parse() when an error occurs.
2246  *
2247  * Note that the user data to be passed to @error_func can be
2248  * specified when constructing the group with g_option_group_new().
2249  *
2250  * Since: 2.6
2251  **/
2252 void
2253 g_option_group_set_error_hook (GOptionGroup     *group,
2254                                GOptionErrorFunc  error_func)
2255 {
2256   g_return_if_fail (group != NULL);
2257
2258   group->error_func = error_func;
2259 }
2260
2261
2262 /**
2263  * g_option_group_set_translate_func:
2264  * @group: a #GOptionGroup
2265  * @func: (allow-none): the #GTranslateFunc, or %NULL
2266  * @data: (allow-none): user data to pass to @func, or %NULL
2267  * @destroy_notify: (allow-none): a function which gets called to free @data, or %NULL
2268  *
2269  * Sets the function which is used to translate user-visible
2270  * strings, for <option>--help</option> output. Different
2271  * groups can use different #GTranslateFunc<!-- -->s. If @func
2272  * is %NULL, strings are not translated.
2273  *
2274  * If you are using gettext(), you only need to set the translation
2275  * domain, see g_option_group_set_translation_domain().
2276  *
2277  * Since: 2.6
2278  **/
2279 void
2280 g_option_group_set_translate_func (GOptionGroup   *group,
2281                                    GTranslateFunc  func,
2282                                    gpointer        data,
2283                                    GDestroyNotify  destroy_notify)
2284 {
2285   g_return_if_fail (group != NULL);
2286
2287   if (group->translate_notify)
2288     group->translate_notify (group->translate_data);
2289
2290   group->translate_func = func;
2291   group->translate_data = data;
2292   group->translate_notify = destroy_notify;
2293 }
2294
2295 static const gchar *
2296 dgettext_swapped (const gchar *msgid,
2297                   const gchar *domainname)
2298 {
2299   return g_dgettext (domainname, msgid);
2300 }
2301
2302 /**
2303  * g_option_group_set_translation_domain:
2304  * @group: a #GOptionGroup
2305  * @domain: the domain to use
2306  *
2307  * A convenience function to use gettext() for translating
2308  * user-visible strings.
2309  *
2310  * Since: 2.6
2311  **/
2312 void
2313 g_option_group_set_translation_domain (GOptionGroup *group,
2314                                        const gchar  *domain)
2315 {
2316   g_return_if_fail (group != NULL);
2317
2318   g_option_group_set_translate_func (group,
2319                                      (GTranslateFunc)dgettext_swapped,
2320                                      g_strdup (domain),
2321                                      g_free);
2322 }
2323
2324 /**
2325  * g_option_context_set_translate_func:
2326  * @context: a #GOptionContext
2327  * @func: (allow-none): the #GTranslateFunc, or %NULL
2328  * @data: (allow-none): user data to pass to @func, or %NULL
2329  * @destroy_notify: (allow-none): a function which gets called to free @data, or %NULL
2330  *
2331  * Sets the function which is used to translate the contexts
2332  * user-visible strings, for <option>--help</option> output.
2333  * If @func is %NULL, strings are not translated.
2334  *
2335  * Note that option groups have their own translation functions,
2336  * this function only affects the @parameter_string (see g_option_context_new()),
2337  * the summary (see g_option_context_set_summary()) and the description
2338  * (see g_option_context_set_description()).
2339  *
2340  * If you are using gettext(), you only need to set the translation
2341  * domain, see g_option_context_set_translation_domain().
2342  *
2343  * Since: 2.12
2344  **/
2345 void
2346 g_option_context_set_translate_func (GOptionContext *context,
2347                                      GTranslateFunc func,
2348                                      gpointer       data,
2349                                      GDestroyNotify destroy_notify)
2350 {
2351   g_return_if_fail (context != NULL);
2352
2353   if (context->translate_notify)
2354     context->translate_notify (context->translate_data);
2355
2356   context->translate_func = func;
2357   context->translate_data = data;
2358   context->translate_notify = destroy_notify;
2359 }
2360
2361 /**
2362  * g_option_context_set_translation_domain:
2363  * @context: a #GOptionContext
2364  * @domain: the domain to use
2365  *
2366  * A convenience function to use gettext() for translating
2367  * user-visible strings.
2368  *
2369  * Since: 2.12
2370  **/
2371 void
2372 g_option_context_set_translation_domain (GOptionContext *context,
2373                                          const gchar     *domain)
2374 {
2375   g_return_if_fail (context != NULL);
2376
2377   g_option_context_set_translate_func (context,
2378                                        (GTranslateFunc)dgettext_swapped,
2379                                        g_strdup (domain),
2380                                        g_free);
2381 }
2382
2383 /**
2384  * g_option_context_set_summary:
2385  * @context: a #GOptionContext
2386  * @summary: (allow-none): a string to be shown in <option>--help</option> output
2387  *  before the list of options, or %NULL
2388  *
2389  * Adds a string to be displayed in <option>--help</option> output
2390  * before the list of options. This is typically a summary of the
2391  * program functionality.
2392  *
2393  * Note that the summary is translated (see
2394  * g_option_context_set_translate_func() and
2395  * g_option_context_set_translation_domain()).
2396  *
2397  * Since: 2.12
2398  */
2399 void
2400 g_option_context_set_summary (GOptionContext *context,
2401                               const gchar    *summary)
2402 {
2403   g_return_if_fail (context != NULL);
2404
2405   g_free (context->summary);
2406   context->summary = g_strdup (summary);
2407 }
2408
2409
2410 /**
2411  * g_option_context_get_summary:
2412  * @context: a #GOptionContext
2413  *
2414  * Returns the summary. See g_option_context_set_summary().
2415  *
2416  * Returns: the summary
2417  *
2418  * Since: 2.12
2419  */
2420 const gchar *
2421 g_option_context_get_summary (GOptionContext *context)
2422 {
2423   g_return_val_if_fail (context != NULL, NULL);
2424
2425   return context->summary;
2426 }
2427
2428 /**
2429  * g_option_context_set_description:
2430  * @context: a #GOptionContext
2431  * @description: (allow-none): a string to be shown in <option>--help</option> output
2432  *   after the list of options, or %NULL
2433  *
2434  * Adds a string to be displayed in <option>--help</option> output
2435  * after the list of options. This text often includes a bug reporting
2436  * address.
2437  *
2438  * Note that the summary is translated (see
2439  * g_option_context_set_translate_func()).
2440  *
2441  * Since: 2.12
2442  */
2443 void
2444 g_option_context_set_description (GOptionContext *context,
2445                                   const gchar    *description)
2446 {
2447   g_return_if_fail (context != NULL);
2448
2449   g_free (context->description);
2450   context->description = g_strdup (description);
2451 }
2452
2453
2454 /**
2455  * g_option_context_get_description:
2456  * @context: a #GOptionContext
2457  *
2458  * Returns the description. See g_option_context_set_description().
2459  *
2460  * Returns: the description
2461  *
2462  * Since: 2.12
2463  */
2464 const gchar *
2465 g_option_context_get_description (GOptionContext *context)
2466 {
2467   g_return_val_if_fail (context != NULL, NULL);
2468
2469   return context->description;
2470 }
2471
2472 /**
2473  * g_option_context_parse_strv:
2474  * @context: a #GOptionContext
2475  * @arguments: (inout) (array null-terminated=1): a pointer to the command line arguments
2476  * @error: a return location for errors
2477  *
2478  * Parses the command line arguments.
2479  *
2480  * This function is similar to g_option_context_parse() except that it
2481  * respects the normal memory rules when dealing with a strv instead of
2482  * assuming that the passed-in array is the argv of the main function.
2483  *
2484  * In particular, strings that are removed from the arguments list will
2485  * be freed using g_free().
2486  *
2487  * This function is useful if you are trying to use #GOptionContext with
2488  * #GApplication.
2489  *
2490  * Returns: %TRUE if the parsing was successful,
2491  *          %FALSE if an error occurred
2492  *
2493  * Since: 2.40
2494  **/
2495 gboolean
2496 g_option_context_parse_strv (GOptionContext   *context,
2497                              gchar          ***arguments,
2498                              GError          **error)
2499 {
2500   gboolean success;
2501   gint argc;
2502
2503   context->strv_mode = TRUE;
2504   argc = g_strv_length (*arguments);
2505   success = g_option_context_parse (context, &argc, arguments, error);
2506   context->strv_mode = FALSE;
2507
2508   return success;
2509 }