Handle conflicts between options in different groups. (#156808)
[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 #include "config.h"
23
24 #include "galias.h"
25
26 #include "goption.h"
27 #include "glib.h"
28 #include "gi18n.h"
29
30 #include <string.h>
31 #include <stdlib.h>
32 #include <errno.h>
33
34 #define TRANSLATE(group, str) (((group)->translate_func ? (* (group)->translate_func) ((str), (group)->translate_data) : (str)))
35
36 typedef struct {
37   GOptionArg arg_type;
38   gpointer arg_data;  
39   union {
40     gboolean bool;
41     gint integer;
42     gchar *str;
43     gchar **array;
44   } prev;
45   union {
46     gchar *str;
47     struct {
48       gint len;
49       gchar **data;
50     } array;
51   } allocated;
52 } Change;
53
54 typedef struct
55 {
56   gchar **ptr;
57   gchar *value;
58 } PendingNull;
59
60 struct _GOptionContext
61 {
62   GList *groups;
63
64   gchar *parameter_string;
65
66   gboolean help_enabled;
67   gboolean ignore_unknown;
68   
69   GOptionGroup *main_group;
70
71   /* We keep a list of change so we can revert them */
72   GList *changes;
73   
74   /* We also keep track of all argv elements that should be NULLed or
75    * modified.
76    */
77   GList *pending_nulls;
78 };
79
80 struct _GOptionGroup
81 {
82   gchar *name;
83   gchar *description;
84   gchar *help_description;
85
86   GDestroyNotify  destroy_notify;
87   gpointer        user_data;
88
89   GTranslateFunc  translate_func;
90   GDestroyNotify  translate_notify;
91   gpointer        translate_data;
92
93   GOptionEntry *entries;
94   gint         n_entries;
95
96   GOptionParseFunc pre_parse_func;
97   GOptionParseFunc post_parse_func;
98   GOptionErrorFunc error_func;
99 };
100
101 static void free_changes_list (GOptionContext *context,
102                                gboolean        revert);
103 static void free_pending_nulls (GOptionContext *context,
104                                 gboolean        perform_nulls);
105
106 GQuark
107 g_option_error_quark (void)
108 {
109   static GQuark q = 0;
110   
111   if (q == 0)
112     q = g_quark_from_static_string ("g-option-context-error-quark");
113
114   return q;
115 }
116
117 /**
118  * g_option_context_new:
119  * @parameter_string: the parameter string to be used in 
120  *    <option>--help</option> output.
121  *
122  * Creates a new option context. 
123  *
124  * Returns: a newly created #GOptionContext, which must be
125  *    freed with g_option_context_free() after use.
126  *
127  * Since: 2.6
128  */
129 GOptionContext *
130 g_option_context_new (const gchar *parameter_string)
131
132 {
133   GOptionContext *context;
134
135   context = g_new0 (GOptionContext, 1);
136
137   context->parameter_string = g_strdup (parameter_string);
138   context->help_enabled = TRUE;
139   context->ignore_unknown = FALSE;
140
141   return context;
142 }
143
144 /**
145  * g_option_context_free:
146  * @context: a #GOptionContext 
147  *
148  * Frees context and all the groups which have been 
149  * added to it.
150  *
151  * Since: 2.6
152  */
153 void g_option_context_free (GOptionContext *context) 
154 {
155   g_return_if_fail (context != NULL);
156
157   g_list_foreach (context->groups, (GFunc)g_option_group_free, NULL);
158   g_list_free (context->groups);
159
160   if (context->main_group) 
161     g_option_group_free (context->main_group);
162
163   free_changes_list (context, FALSE);
164   free_pending_nulls (context, FALSE);
165   
166   g_free (context->parameter_string);
167   
168   g_free (context);
169 }
170
171
172 /**
173  * g_option_context_set_help_enabled:
174  * @context: a #GOptionContext
175  * @help_enabled: %TRUE to enable <option>--help</option>, %FALSE to disable it
176  *
177  * Enables or disables automatic generation of <option>--help</option> 
178  * output. By default, g_option_context_parse() recognizes
179  * <option>--help</option>, <option>-?</option>, <option>--help-all</option>
180  * and <option>--help-</option><replaceable>groupname</replaceable> and creates
181  * suitable output to stdout. 
182  *
183  * Since: 2.6
184  */
185 void g_option_context_set_help_enabled (GOptionContext *context,
186                                         gboolean        help_enabled)
187
188 {
189   g_return_if_fail (context != NULL);
190
191   context->help_enabled = help_enabled;
192 }
193
194 /**
195  * g_option_context_get_help_enabled:
196  * @context: a #GOptionContext
197  * 
198  * Returns whether automatic <option>--help</option> generation
199  * is turned on for @context. See g_option_context_set_help_enabled().
200  * 
201  * Returns: %TRUE if automatic help generation is turned on.
202  *
203  * Since: 2.6
204  */
205 gboolean 
206 g_option_context_get_help_enabled (GOptionContext *context) 
207 {
208   g_return_val_if_fail (context != NULL, FALSE);
209   
210   return context->help_enabled;
211 }
212
213 /**
214  * g_option_context_set_ignore_unknown_options:
215  * @context: a #GOptionContext
216  * @ignore_unknown: %TRUE to ignore unknown options, %FALSE to produce
217  *    an error when unknown options are met
218  * 
219  * Sets whether to ignore unknown options or not. If an argument is 
220  * ignored, it is left in the @argv array after parsing. By default, 
221  * g_option_context_parse() treats unknown options as error.
222  * 
223  * This setting does not affect non-option arguments (i.e. arguments 
224  * which don't start with a dash). But note that GOption cannot reliably
225  * determine whether a non-option belongs to a preceding unknown option.
226  *
227  * Since: 2.6
228  **/
229 void
230 g_option_context_set_ignore_unknown_options (GOptionContext *context,
231                                              gboolean        ignore_unknown)
232 {
233   g_return_if_fail (context != NULL);
234
235   context->ignore_unknown = ignore_unknown;
236 }
237
238 /**
239  * g_option_context_get_ignore_unknown_options:
240  * @context: a #GOptionContext
241  * 
242  * Returns whether unknown options are ignored or not. See
243  * g_option_context_set_ignore_unknown_options().
244  * 
245  * Returns: %TRUE if unknown options are ignored.
246  * 
247  * Since: 2.6
248  **/
249 gboolean
250 g_option_context_get_ignore_unknown_options (GOptionContext *context)
251 {
252   g_return_val_if_fail (context != NULL, FALSE);
253
254   return context->ignore_unknown;
255 }
256
257 /**
258  * g_option_context_add_group:
259  * @context: a #GOptionContext
260  * @group: the group to add
261  * 
262  * Adds a #GOptionGroup to the @context, so that parsing with @context
263  * will recognize the options in the group. Note that the group will
264  * be freed together with the context when g_option_context_free() is
265  * called, so you must not free the group yourself after adding it
266  * to a context.
267  *
268  * Since: 2.6
269  **/
270 void
271 g_option_context_add_group (GOptionContext *context,
272                             GOptionGroup   *group)
273 {
274   GList *list;
275
276   g_return_if_fail (context != NULL);
277   g_return_if_fail (group != NULL);
278   g_return_if_fail (group->name != NULL);
279   g_return_if_fail (group->description != NULL);
280   g_return_if_fail (group->help_description != NULL);
281
282   for (list = context->groups; list; list = list->next)
283     {
284       GOptionGroup *g = (GOptionGroup *)list->data;
285
286       if ((group->name == NULL && g->name == NULL) ||
287           (group->name && g->name && strcmp (group->name, g->name) == 0))
288         g_warning ("A group named \"%s\" is already part of this GOptionContext", 
289                    group->name);
290     }
291
292   context->groups = g_list_append (context->groups, group);
293 }
294
295 /**
296  * g_option_context_set_main_group:
297  * @context: a #GOptionContext
298  * @group: the group to set as main group
299  * 
300  * Sets a #GOptionGroup as main group of the @context. 
301  * This has the same effect as calling g_option_context_add_group(), 
302  * the only difference is that the options in the main group are 
303  * treated differently when generating <option>--help</option> output.
304  *
305  * Since: 2.6
306  **/
307 void
308 g_option_context_set_main_group (GOptionContext *context,
309                                  GOptionGroup   *group)
310 {
311   g_return_if_fail (context != NULL);
312   g_return_if_fail (group != NULL);
313
314   context->main_group = group;
315 }
316
317 /**
318  * g_option_context_get_main_group:
319  * @context: a #GOptionContext
320  * 
321  * Returns a pointer to the main group of @context.
322  * 
323  * Return value: the main group of @context, or %NULL if @context doesn't
324  *  have a main group. Note that group belongs to @context and should
325  *  not be modified or freed.
326  *
327  * Since: 2.6
328  **/
329 GOptionGroup *
330 g_option_context_get_main_group (GOptionContext *context)
331 {
332   g_return_val_if_fail (context != NULL, NULL);
333
334   return context->main_group;
335 }
336
337 /**
338  * g_option_context_add_main_entries:
339  * @context: a #GOptionContext
340  * @entries: a %NULL-terminated array of #GOptionEntry<!-- -->s
341  * @translation_domain: a translation domain to use for translating
342  *    the <option>--help</option> output for the options in @entries
343  *    with gettext(), or %NULL
344  * 
345  * A convenience function which creates a main group if it doesn't 
346  * exist, adds the @entries to it and sets the translation domain.
347  * 
348  * Since: 2.6
349  **/
350 void
351 g_option_context_add_main_entries (GOptionContext      *context,
352                                    const GOptionEntry  *entries,
353                                    const gchar         *translation_domain)
354 {
355   g_return_if_fail (entries != NULL);
356
357   if (!context->main_group)
358     context->main_group = g_option_group_new (NULL, NULL, NULL, NULL, NULL);
359   
360   g_option_group_add_entries (context->main_group, entries);
361   g_option_group_set_translation_domain (context->main_group, translation_domain);
362 }
363
364 static void
365 print_entry (GOptionGroup       *group,
366              gint                max_length,
367              const GOptionEntry *entry)
368 {
369   GString *str;
370
371   if (entry->flags & G_OPTION_FLAG_HIDDEN)
372     return;
373
374   str = g_string_new (NULL);
375   
376   if (entry->short_name)
377     g_string_append_printf (str, "  -%c, --%s", entry->short_name, entry->long_name);
378   else
379     g_string_append_printf (str, "  --%s", entry->long_name);
380   
381   if (entry->arg_description)
382     g_string_append_printf (str, "=%s", TRANSLATE (group, entry->arg_description));
383   
384   g_print ("%-*s %s\n", max_length + 4, str->str,
385            entry->description ? TRANSLATE (group, entry->description) : "");
386   g_string_free (str, TRUE);  
387 }
388
389 static void
390 print_help (GOptionContext *context,
391             gboolean        main_help,
392             GOptionGroup   *group)
393 {
394   GList *list;
395   gint max_length, len;
396   gint i;
397   GHashTable *shadow_map;
398   gboolean seen[256];
399   
400   g_print ("%s\n  %s %s %s\n\n", 
401            _("Usage:"), g_get_prgname(), _("[OPTION...]"),
402            context->parameter_string ? context->parameter_string : "");
403
404   memset (seen, 0, sizeof (gboolean) * 256);
405   shadow_map = g_hash_table_new (g_str_hash, g_str_equal);
406
407   if (context->main_group)
408     {
409       for (i = 0; i < context->main_group->n_entries; i++)
410         {
411           g_hash_table_insert (shadow_map, 
412                                (gpointer)context->main_group->entries[i].long_name, 
413                                context->main_group->entries + i);
414           
415           if (seen[(guchar)context->main_group->entries[i].short_name])
416             context->main_group->entries[i].short_name = 0;
417           else
418             seen[(guchar)context->main_group->entries[i].short_name] = TRUE;
419         }
420     }
421
422   list = context->groups;
423   while (list != NULL)
424     {
425       GOptionGroup *group = list->data;
426       for (i = 0; i < group->n_entries; i++)
427         {
428           if (g_hash_table_lookup (shadow_map, group->entries[i].long_name))
429             group->entries[i].long_name = g_strdup_printf ("%s-%s", group->name, group->entries[i].long_name);
430           else  
431             g_hash_table_insert (shadow_map, (gpointer)group->entries[i].long_name, group->entries + i);
432
433           if (seen[(guchar)group->entries[i].short_name])
434             group->entries[i].short_name = 0;
435           else
436             seen[(guchar)group->entries[i].short_name] = TRUE;
437         }
438       list = list->next;
439     }
440
441   g_hash_table_destroy (shadow_map);
442
443   list = context->groups;
444
445   max_length = g_utf8_strlen ("--help, -?", -1);
446
447   if (list)
448     {
449       len = g_utf8_strlen ("--help-all", -1);
450       max_length = MAX (max_length, len);
451     }
452
453   while (list != NULL)
454     {
455       GOptionGroup *group = list->data;
456       
457       /* First, we check the --help-<groupname> options */
458       len = g_utf8_strlen ("--help-", -1) + g_utf8_strlen (group->name, -1);
459       max_length = MAX (max_length, len);
460
461       /* Then we go through the entries */
462       for (i = 0; i < group->n_entries; i++)
463         {
464           if (group->entries[i].flags & G_OPTION_FLAG_HIDDEN)
465             continue;
466
467           len = g_utf8_strlen (group->entries[i].long_name, -1);
468
469           if (group->entries[i].short_name)
470             len += 4;
471
472           if (group->entries[i].arg != G_OPTION_ARG_NONE &&
473               group->entries[i].arg_description)
474             len += 1 + g_utf8_strlen (TRANSLATE (group, group->entries[i].arg_description), -1);
475
476           max_length = MAX (max_length, len);
477         }
478       
479       list = list->next;
480     }
481
482   /* Add a bit of padding */
483   max_length += 4;
484   
485   list = context->groups;
486
487   g_print ("%s\n  --%-*s %s\n", 
488            _("Help Options:"), max_length, "help", _("Show help options"));
489
490   /* We only want --help-all when there are groups */
491   if (list)
492     g_print ("  --%-*s %s\n", max_length, "help-all", _("Show all help options"));
493
494   while (list)
495     {
496       GOptionGroup *group = list->data;
497
498       g_print ("  --help-%-*s %s\n", max_length - 5, group->name, TRANSLATE (group, group->help_description));
499       
500       list = list->next;
501     }
502
503   g_print ("\n");
504
505   if (group)
506     {
507       /* Print a certain group */
508       
509       g_print ("%s\n", TRANSLATE (group, group->description));
510       for (i = 0; i < group->n_entries; i++)
511         print_entry (group, max_length, &group->entries[i]);
512       g_print ("\n");
513     }
514   else if (!main_help)
515     {
516       /* Print all groups */
517
518       list = context->groups;
519
520       while (list)
521         {
522           GOptionGroup *group = list->data;
523
524           g_print ("%s\n", group->description);
525
526           for (i = 0; i < group->n_entries; i++)
527             if (!(group->entries[i].flags & G_OPTION_FLAG_IN_MAIN))
528               print_entry (group, max_length, &group->entries[i]);
529           
530           g_print ("\n");
531           list = list->next;
532         }
533     }
534   
535   /* Print application options if --help or --help-all has been specified */
536   if (main_help || !group)
537     {
538       list = context->groups;
539
540       g_print ("%s\n", _("Application Options:"));
541
542       if (context->main_group)
543         for (i = 0; i < context->main_group->n_entries; i++) 
544           print_entry (context->main_group, max_length, &context->main_group->entries[i]);
545
546       while (list != NULL)
547         {
548           GOptionGroup *group = list->data;
549
550           /* Print main entries from other groups */
551           for (i = 0; i < group->n_entries; i++)
552             if (group->entries[i].flags & G_OPTION_FLAG_IN_MAIN)
553               print_entry (group, max_length, &group->entries[i]);
554           
555           list = list->next;
556         }
557
558       g_print ("\n");
559     }
560   
561   exit (0);
562 }
563
564 static gboolean
565 parse_int (const gchar *arg_name,
566            const gchar *arg,
567            gint        *result,
568            GError     **error)
569 {
570   gchar *end;
571   glong tmp = strtol (arg, &end, 0);
572
573   errno = 0;
574   
575   if (*arg == '\0' || *end != '\0')
576     {
577       g_set_error (error,
578                    G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
579                    _("Cannot parse integer value '%s' for --%s"),
580                    arg, arg_name);
581       return FALSE;
582     }
583
584   *result = tmp;
585   if (*result != tmp || errno == ERANGE)
586     {
587       g_set_error (error,
588                    G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
589                    _("Integer value '%s' for %s out of range"),
590                    arg, arg_name);
591       return FALSE;
592     }
593
594   return TRUE;
595 }
596
597 static Change *
598 get_change (GOptionContext *context,
599             GOptionArg      arg_type,
600             gpointer        arg_data)
601 {
602   GList *list;
603   Change *change = NULL;
604   
605   for (list = context->changes; list != NULL; list = list->next)
606     {
607       change = list->data;
608
609       if (change->arg_data == arg_data)
610         goto found;
611     }
612
613   change = g_new0 (Change, 1);
614   change->arg_type = arg_type;
615   change->arg_data = arg_data;
616   
617   context->changes = g_list_prepend (context->changes, change);
618   
619  found:
620
621   return change;
622 }
623
624 static void
625 add_pending_null (GOptionContext *context,
626                   gchar         **ptr,
627                   gchar          *value)
628 {
629   PendingNull *n;
630
631   n = g_new0 (PendingNull, 1);
632   n->ptr = ptr;
633   n->value = value;
634
635   context->pending_nulls = g_list_prepend (context->pending_nulls, n);
636 }
637                   
638 static gboolean
639 parse_arg (GOptionContext *context,
640            GOptionGroup   *group,
641            GOptionEntry   *entry,
642            const gchar    *value,
643            const gchar    *option_name,
644            GError        **error)
645      
646 {
647   Change *change;
648   
649   switch (entry->arg)
650     {
651     case G_OPTION_ARG_NONE:
652       {
653         change = get_change (context, G_OPTION_ARG_NONE,
654                              entry->arg_data);
655
656         *(gboolean *)entry->arg_data = TRUE;
657         break;
658       }      
659     case G_OPTION_ARG_STRING:
660       {
661         gchar *data;
662
663         data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
664
665         if (!data)
666           return FALSE;
667
668         change = get_change (context, G_OPTION_ARG_STRING,
669                              entry->arg_data);
670         g_free (change->allocated.str);
671         
672         change->prev.str = *(gchar **)entry->arg_data;
673         change->allocated.str = data;
674         
675         *(gchar **)entry->arg_data = data;
676         break;
677       }
678     case G_OPTION_ARG_STRING_ARRAY:
679       {
680         gchar *data;
681         
682         data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
683
684         if (!data)
685           return FALSE;
686
687         change = get_change (context, G_OPTION_ARG_STRING_ARRAY,
688                              entry->arg_data);
689
690         if (change->allocated.array.len == 0)
691           {
692             change->prev.array = entry->arg_data;
693             change->allocated.array.data = g_new (gchar *, 2);
694           }
695         else
696           change->allocated.array.data =
697             g_renew (gchar *, change->allocated.array.data,
698                      change->allocated.array.len + 2);
699
700         change->allocated.array.data[change->allocated.array.len] = data;
701         change->allocated.array.data[change->allocated.array.len + 1] = NULL;
702
703         change->allocated.array.len ++;
704
705         *(gchar ***)entry->arg_data = change->allocated.array.data;
706
707         break;
708       }
709       
710     case G_OPTION_ARG_FILENAME:
711       {
712         gchar *data;
713
714 #ifdef G_OS_WIN32
715         data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
716         
717         if (!data)
718           return FALSE;
719 #else
720         data = g_strdup (value);
721 #endif
722         change = get_change (context, G_OPTION_ARG_FILENAME,
723                              entry->arg_data);
724         g_free (change->allocated.str);
725         
726         change->prev.str = *(gchar **)entry->arg_data;
727         change->allocated.str = data;
728
729         *(gchar **)entry->arg_data = data;
730         break;
731       }
732
733     case G_OPTION_ARG_FILENAME_ARRAY:
734       {
735         gchar *data;
736         
737 #ifdef G_OS_WIN32
738         data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
739         
740         if (!data)
741           return FALSE;
742 #else
743         data = g_strdup (value);
744 #endif
745         change = get_change (context, G_OPTION_ARG_STRING_ARRAY,
746                              entry->arg_data);
747
748         if (change->allocated.array.len == 0)
749           {
750             change->prev.array = entry->arg_data;
751             change->allocated.array.data = g_new (gchar *, 2);
752           }
753         else
754           change->allocated.array.data =
755             g_renew (gchar *, change->allocated.array.data,
756                      change->allocated.array.len + 2);
757
758         change->allocated.array.data[change->allocated.array.len] = data;
759         change->allocated.array.data[change->allocated.array.len + 1] = NULL;
760
761         change->allocated.array.len ++;
762
763         *(gchar ***)entry->arg_data = change->allocated.array.data;
764
765         break;
766       }
767       
768     case G_OPTION_ARG_INT:
769       {
770         gint data;
771
772         if (!parse_int (option_name, value,
773                         &data,
774                         error))
775           return FALSE;
776
777         change = get_change (context, G_OPTION_ARG_INT,
778                              entry->arg_data);
779         change->prev.integer = *(gint *)entry->arg_data;
780         *(gint *)entry->arg_data = data;
781         break;
782       }
783     case G_OPTION_ARG_CALLBACK:
784       {
785         gchar *tmp;
786         gboolean retval;
787         
788         tmp = g_locale_to_utf8 (value, -1, NULL, NULL, error);
789
790         if (!value)
791           return FALSE;
792
793         retval = (* (GOptionArgFunc) entry->arg_data) (option_name, tmp, group->user_data, error);
794         
795         g_free (tmp);
796         
797         return retval;
798         
799         break;
800       }
801     default:
802       g_assert_not_reached ();
803     }
804
805   return TRUE;
806 }
807
808 static gboolean
809 parse_short_option (GOptionContext *context,
810                     GOptionGroup   *group,
811                     gint            index,
812                     gint           *new_index,
813                     gchar           arg,
814                     gint           *argc,
815                     gchar        ***argv,
816                     GError        **error,
817                     gboolean       *parsed)
818 {
819   gint j;
820     
821   for (j = 0; j < group->n_entries; j++)
822     {
823       if (arg == group->entries[j].short_name)
824         {
825           if (group->entries[j].arg == G_OPTION_ARG_NONE)
826             {
827               parse_arg (context, group, &group->entries[j],
828                          NULL, NULL, error);
829               *parsed = TRUE;
830             }
831           else
832             {
833               gchar *value = NULL;
834               gchar *option_name;
835               
836               if (*new_index > index)
837                 {
838                   g_warning ("FIXME: figure out the correct error here");
839
840                   return FALSE;
841                 }
842               
843               if (index < *argc - 1)
844                 {
845                   value = (*argv)[index + 1];
846                   add_pending_null (context, &((*argv)[index + 1]), NULL);
847                   *new_index = index + 1;
848                 }
849               else
850                 value = "";
851
852
853               option_name = g_strdup_printf ("-%c", group->entries[j].short_name);
854               
855               if (!parse_arg (context, group, &group->entries[j], value, option_name, error))
856                 {
857                   g_free (option_name);
858                   return FALSE;
859                 }
860
861               g_free (option_name);
862               *parsed = TRUE;
863             }
864         }
865     }
866
867   return TRUE;
868 }
869
870 static gboolean
871 parse_long_option (GOptionContext *context,
872                    GOptionGroup   *group,
873                    gint           *index,
874                    gchar          *arg,
875                    gint           *argc,
876                    gchar        ***argv,
877                    GError        **error,
878                    gboolean       *parsed)
879 {
880   gint j;
881
882   for (j = 0; j < group->n_entries; j++)
883     {
884       if (*index >= *argc)
885         return TRUE;
886
887       if (group->entries[j].arg == G_OPTION_ARG_NONE &&
888           strcmp (arg, group->entries[j].long_name) == 0)
889         {
890           parse_arg (context, group, &group->entries[j],
891                      NULL, NULL, error);
892           
893           add_pending_null (context, &((*argv)[*index]), NULL);
894           *parsed = TRUE;
895         }
896       else
897         {
898           gint len = strlen (group->entries[j].long_name);
899           
900           if (strncmp (arg, group->entries[j].long_name, len) == 0 &&
901               (arg[len] == '=' || arg[len] == 0))
902             {
903               gchar *value = NULL;
904               gchar *option_name;
905
906               add_pending_null (context, &((*argv)[*index]), NULL);
907               
908               if (arg[len] == '=')
909                 value = arg + len + 1;
910               else if (*index < *argc - 1)
911                 {
912                   value = (*argv)[*index + 1];
913                   add_pending_null (context, &((*argv)[*index + 1]), NULL);
914                   (*index)++;
915                 }
916               else
917                 value = "";
918
919               option_name = g_strconcat ("--", group->entries[j].long_name, NULL);
920               
921               if (!parse_arg (context, group, &group->entries[j], value, option_name, error))
922                 {
923                   g_free (option_name);
924                   return FALSE;
925                 }
926
927               g_free (option_name);
928               *parsed = TRUE;
929             }
930         }
931     }
932   
933   return TRUE;
934 }
935
936 static gboolean
937 parse_remaining_arg (GOptionContext *context,
938                      GOptionGroup   *group,
939                      gint           *index,
940                      gint           *argc,
941                      gchar        ***argv,
942                      GError        **error,
943                      gboolean       *parsed)
944 {
945   gint j;
946
947   for (j = 0; j < group->n_entries; j++)
948     {
949       if (*index >= *argc)
950         return TRUE;
951
952       if (group->entries[j].long_name[0])
953         continue;
954
955       g_return_val_if_fail (group->entries[j].arg == G_OPTION_ARG_STRING_ARRAY ||
956                             group->entries[j].arg == G_OPTION_ARG_FILENAME_ARRAY, FALSE);
957       
958       add_pending_null (context, &((*argv)[*index]), NULL);
959       
960       if (!parse_arg (context, group, &group->entries[j], (*argv)[*index], "", error))
961         return FALSE;
962       
963       *parsed = TRUE;
964       return TRUE;
965     }
966
967   return TRUE;
968 }
969
970 static void
971 free_changes_list (GOptionContext *context,
972                    gboolean        revert)
973 {
974   GList *list;
975
976   for (list = context->changes; list != NULL; list = list->next)
977     {
978       Change *change = list->data;
979
980       if (revert)
981         {
982           switch (change->arg_type)
983             {
984             case G_OPTION_ARG_NONE:
985               *(gboolean *)change->arg_data = change->prev.bool;
986               break;
987             case G_OPTION_ARG_INT:
988               *(gint *)change->arg_data = change->prev.integer;
989               break;
990             case G_OPTION_ARG_STRING:
991             case G_OPTION_ARG_FILENAME:
992               g_free (change->allocated.str);
993               *(gchar **)change->arg_data = change->prev.str;
994               break;
995             case G_OPTION_ARG_STRING_ARRAY:
996             case G_OPTION_ARG_FILENAME_ARRAY:
997               g_strfreev (change->allocated.array.data);
998               *(gchar ***)change->arg_data = change->prev.array;
999               break;
1000             default:
1001               g_assert_not_reached ();
1002             }
1003         }
1004       
1005       g_free (change);
1006     }
1007
1008   g_list_free (context->changes);
1009   context->changes = NULL;
1010 }
1011
1012 static void
1013 free_pending_nulls (GOptionContext *context,
1014                     gboolean        perform_nulls)
1015 {
1016   GList *list;
1017
1018   for (list = context->pending_nulls; list != NULL; list = list->next)
1019     {
1020       PendingNull *n = list->data;
1021
1022       if (perform_nulls)
1023         {
1024           if (n->value)
1025             {
1026               /* Copy back the short options */
1027               *(n->ptr)[0] = '-';             
1028               strcpy (*n->ptr + 1, n->value);
1029             }
1030           else
1031             *n->ptr = NULL;
1032         }
1033       
1034       g_free (n->value);
1035       g_free (n);
1036     }
1037
1038   g_list_free (context->pending_nulls);
1039   context->pending_nulls = NULL;
1040 }
1041
1042 /**
1043  * g_option_context_parse:
1044  * @context: a #GOptionContext
1045  * @argc: a pointer to the number of command line arguments.
1046  * @argv: a pointer to the array of command line arguments.
1047  * @error: a return location for errors 
1048  * 
1049  * Parses the command line arguments, recognizing options
1050  * which have been added to @context. A side-effect of 
1051  * calling this function is that g_set_prgname() will be
1052  * called.
1053  *
1054  * If the parsing is successful, any parsed arguments are
1055  * removed from the array and @argc and @argv are updated 
1056  * accordingly. In case of an error, @argc and @argv are
1057  * left unmodified.
1058  * 
1059  * Return value: %TRUE if the parsing was successful, 
1060  *               %FALSE if an error occurred
1061  *
1062  * Since: 2.6
1063  **/
1064 gboolean
1065 g_option_context_parse (GOptionContext   *context,
1066                         gint             *argc,
1067                         gchar          ***argv,
1068                         GError          **error)
1069 {
1070   gint i, j, k;
1071   GList *list;
1072
1073   /* Set program name */
1074   if (argc && argv && *argc)
1075     {
1076       gchar *prgname;
1077       
1078       prgname = g_path_get_basename ((*argv)[0]);
1079       g_set_prgname (prgname);
1080       g_free (prgname);
1081     }
1082   else
1083     {
1084       g_set_prgname ("<unknown>");
1085     }
1086   
1087   /* Call pre-parse hooks */
1088   list = context->groups;
1089   while (list)
1090     {
1091       GOptionGroup *group = list->data;
1092       
1093       if (group->pre_parse_func)
1094         {
1095           if (!(* group->pre_parse_func) (context, group,
1096                                           group->user_data, error))
1097             goto fail;
1098         }
1099       
1100       list = list->next;
1101     }
1102
1103   if (context->main_group && context->main_group->pre_parse_func)
1104     {
1105       if (!(* context->main_group->pre_parse_func) (context, context->main_group,
1106                                                     context->main_group->user_data, error))
1107         goto fail;
1108     }
1109
1110   if (argc && argv)
1111     {
1112       gboolean stop_parsing = FALSE;
1113
1114       for (i = 1; i < *argc; i++)
1115         {
1116           gchar *arg, *dash;
1117           gboolean parsed = FALSE;
1118
1119           if ((*argv)[i][0] == '-' && !stop_parsing)
1120             {
1121               if ((*argv)[i][1] == '-')
1122                 {
1123                   /* -- option */
1124
1125                   arg = (*argv)[i] + 2;
1126
1127                   /* '--' terminates list of arguments */
1128                   if (*arg == 0)
1129                     {
1130                       add_pending_null (context, &((*argv)[i]), NULL);
1131                       stop_parsing = TRUE;
1132                       continue;
1133                     }
1134
1135                   /* Handle help options */
1136                   if (context->help_enabled)
1137                     {
1138                       if (strcmp (arg, "help") == 0)
1139                         print_help (context, TRUE, NULL);
1140                       else if (strcmp (arg, "help-all") == 0)
1141                         print_help (context, FALSE, NULL);                    
1142                       else if (strncmp (arg, "help-", 5) == 0)
1143                         {
1144                           GList *list;
1145                           
1146                           list = context->groups;
1147                           
1148                           while (list)
1149                             {
1150                               GOptionGroup *group = list->data;
1151                               
1152                               if (strcmp (arg + 5, group->name) == 0)
1153                                 print_help (context, FALSE, group);                                           
1154                               
1155                               list = list->next;
1156                             }
1157                         }
1158                     }
1159
1160                   if (context->main_group &&
1161                       !parse_long_option (context, context->main_group, &i, arg,
1162                                           argc, argv, error, &parsed))
1163                     goto fail;
1164
1165                   if (parsed)
1166                     continue;
1167                   
1168                   /* Try the groups */
1169                   list = context->groups;
1170                   while (list)
1171                     {
1172                       GOptionGroup *group = list->data;
1173                       
1174                       if (!parse_long_option (context, group, &i, arg,
1175                                               argc, argv, error, &parsed))
1176                         goto fail;
1177                       
1178                       if (parsed)
1179                         break;
1180                       
1181                       list = list->next;
1182                     }
1183                   
1184                   if (parsed)
1185                     continue;
1186
1187                   /* Now look for --<group>-<option> */
1188                   dash = strchr (arg, '-');
1189                   if (dash)
1190                     {
1191                       /* Try the groups */
1192                       list = context->groups;
1193                       while (list)
1194                         {
1195                           GOptionGroup *group = list->data;
1196                           
1197                           if (strncmp (group->name, arg, dash - arg) == 0)
1198                             {
1199                               if (!parse_long_option (context, group, &i, dash + 1,
1200                                                       argc, argv, error, &parsed))
1201                                 goto fail;
1202                               
1203                               if (parsed)
1204                                 break;
1205                             }
1206                           
1207                           list = list->next;
1208                         }
1209                     }
1210                   
1211                   if (context->ignore_unknown)
1212                     continue;
1213                 }
1214               else
1215                 {
1216                   /* short option */
1217
1218                   gint new_i, j;
1219                   gboolean *nulled_out = NULL;
1220                   
1221                   arg = (*argv)[i] + 1;
1222
1223                   new_i = i;
1224
1225                   if (context->ignore_unknown)
1226                     nulled_out = g_new0 (gboolean, strlen (arg));
1227                   
1228                   for (j = 0; j < strlen (arg); j++)
1229                     {
1230                       parsed = FALSE;
1231                       
1232                       if (context->main_group &&
1233                           !parse_short_option (context, context->main_group,
1234                                                i, &new_i, arg[j],
1235                                                argc, argv, error, &parsed))
1236                         {
1237
1238                           g_free (nulled_out);
1239                           goto fail;
1240                         }
1241
1242                       if (!parsed)
1243                         {
1244                           /* Try the groups */
1245                           list = context->groups;
1246                           while (list)
1247                             {
1248                               GOptionGroup *group = list->data;
1249                               
1250                               if (!parse_short_option (context, group, i, &new_i, arg[j],
1251                                                        argc, argv, error, &parsed))
1252                                 goto fail;
1253                               
1254                               if (parsed)
1255                                 break;
1256                           
1257                               list = list->next;
1258                             }
1259                         }
1260
1261                       if (context->ignore_unknown)
1262                         {
1263                           if (parsed)
1264                             nulled_out[j] = TRUE;
1265                           else
1266                             continue;
1267                         }
1268
1269                       if (!parsed)
1270                         break;
1271                     }
1272
1273                   if (context->ignore_unknown)
1274                     {
1275                       gchar *new_arg = NULL; 
1276                       gint arg_index = 0;
1277                       
1278                       for (j = 0; j < strlen (arg); j++)
1279                         {
1280                           if (!nulled_out[j])
1281                             {
1282                               if (!new_arg)
1283                                 new_arg = g_malloc (strlen (arg));
1284                               new_arg[arg_index++] = arg[j];
1285                             }
1286                         }
1287                       if (new_arg)
1288                         new_arg[arg_index] = '\0';
1289                       
1290                       add_pending_null (context, &((*argv)[i]), new_arg);
1291                     }
1292                   else if (parsed)
1293                     {
1294                       add_pending_null (context, &((*argv)[i]), NULL);
1295                       i = new_i;
1296                     }
1297                 }
1298               
1299               if (!parsed && !context->ignore_unknown)
1300                 {
1301                   g_set_error (error,
1302                                G_OPTION_ERROR, G_OPTION_ERROR_UNKNOWN_OPTION,
1303                                _("Unknown option %s"), (*argv)[i]);
1304                   goto fail;
1305                 }
1306             }
1307           else
1308             {
1309               /* Collect remaining args */
1310               if (context->main_group &&
1311                   !parse_remaining_arg (context, context->main_group, &i,
1312                                         argc, argv, error, &parsed))
1313                 goto fail;
1314               
1315             }
1316         }
1317
1318       /* Call post-parse hooks */
1319       list = context->groups;
1320       while (list)
1321         {
1322           GOptionGroup *group = list->data;
1323
1324           if (group->post_parse_func)
1325             {
1326               if (!(* group->post_parse_func) (context, group,
1327                                                group->user_data, error))
1328                 goto fail;
1329             }
1330           
1331           list = list->next;
1332         }
1333
1334       if (context->main_group && context->main_group->post_parse_func)
1335         {
1336           if (!(* context->main_group->post_parse_func) (context, context->main_group,
1337                                                          context->main_group->user_data, error))
1338             goto fail;
1339         }
1340
1341       free_pending_nulls (context, TRUE);
1342       
1343       for (i = 1; i < *argc; i++)
1344         {
1345           for (k = i; k < *argc; k++)
1346             if ((*argv)[k] != NULL)
1347               break;
1348           
1349           if (k > i)
1350             {
1351               k -= i;
1352               for (j = i + k; j < *argc; j++)
1353                 {
1354                   (*argv)[j-k] = (*argv)[j];
1355                   (*argv)[j] = NULL;
1356                 }
1357               *argc -= k;
1358             }
1359         }      
1360     }
1361
1362   return TRUE;
1363
1364  fail:
1365   
1366   /* Call error hooks */
1367   list = context->groups;
1368   while (list)
1369     {
1370       GOptionGroup *group = list->data;
1371       
1372       if (group->error_func)
1373         (* group->error_func) (context, group,
1374                                group->user_data, error);
1375       
1376       list = list->next;
1377     }
1378
1379   if (context->main_group && context->main_group->error_func)
1380     (* context->main_group->error_func) (context, context->main_group,
1381                                          context->main_group->user_data, error);
1382   
1383   free_changes_list (context, TRUE);
1384   free_pending_nulls (context, FALSE);
1385
1386   return FALSE;
1387 }
1388                                    
1389 /**
1390  * g_option_group_new:
1391  * @name: the name for the option group, this is used to provide
1392  *   help for the options in this group with <option>--help-</option>@name
1393  * @description: a description for this group to be shown in 
1394  *   <option>--help</option>. This string is translated using the translation
1395  *   domain or translation function of the group
1396  * @help_description: a description for the <option>--help-</option>@name option.
1397  *   This string is translated using the translation domain or translation function
1398  *   of the group
1399  * @user_data: user data that will be passed to the pre- and post-parse hooks,
1400  *   the error hook and to callbacks of %G_OPTION_ARG_CALLBACK options, or %NULL
1401  * @destroy: a function that will be called to free @user_data, or %NULL
1402  * 
1403  * Creates a new #GOptionGroup.
1404  * 
1405  * Return value: a newly created option group. It should be added 
1406  *   to a #GOptionContext or freed with g_option_group_free().
1407  *
1408  * Since: 2.6
1409  **/
1410 GOptionGroup *
1411 g_option_group_new (const gchar    *name,
1412                     const gchar    *description,
1413                     const gchar    *help_description,
1414                     gpointer        user_data,
1415                     GDestroyNotify  destroy)
1416
1417 {
1418   GOptionGroup *group;
1419
1420   group = g_new0 (GOptionGroup, 1);
1421   group->name = g_strdup (name);
1422   group->description = g_strdup (description);
1423   group->help_description = g_strdup (help_description);
1424   group->user_data = user_data;
1425   group->destroy_notify = destroy;
1426   
1427   return group;
1428 }
1429
1430
1431 /**
1432  * g_option_group_free:
1433  * @group: a #GOptionGroup
1434  * 
1435  * Frees a #GOptionGroup. Note that you must <emphasis>not</emphasis>
1436  * free groups which have been added to a #GOptionContext.
1437  *
1438  * Since: 2.6
1439  **/
1440 void
1441 g_option_group_free (GOptionGroup *group)
1442 {
1443   g_return_if_fail (group != NULL);
1444
1445   g_free (group->name);
1446   g_free (group->description);
1447   g_free (group->help_description);
1448
1449   g_free (group->entries);
1450   
1451   if (group->destroy_notify)
1452     (* group->destroy_notify) (group->user_data);
1453
1454   if (group->translate_notify)
1455     (* group->translate_notify) (group->translate_data);
1456   
1457   g_free (group);
1458 }
1459
1460
1461 /**
1462  * g_option_group_add_entries:
1463  * @group: a #GOptionGroup
1464  * @entries: a %NULL-terminated array of #GOptionEntry<!-- -->s
1465  * 
1466  * Adds the options specified in @entries to @group.
1467  *
1468  * Since: 2.6
1469  **/
1470 void
1471 g_option_group_add_entries (GOptionGroup       *group,
1472                             const GOptionEntry *entries)
1473 {
1474   gint n_entries;
1475   
1476   g_return_if_fail (entries != NULL);
1477
1478   for (n_entries = 0; entries[n_entries].long_name != NULL; n_entries++);
1479
1480   group->entries = g_renew (GOptionEntry, group->entries, group->n_entries + n_entries);
1481
1482   memcpy (group->entries + group->n_entries, entries, sizeof (GOptionEntry) * n_entries);
1483
1484   group->n_entries += n_entries;
1485 }
1486
1487 /**
1488  * g_option_group_set_parse_hooks:
1489  * @group: a #GOptionGroup
1490  * @pre_parse_func: a function to call before parsing, or %NULL
1491  * @post_parse_func: a function to call after parsing, or %NULL
1492  * 
1493  * Associates two functions with @group which will be called 
1494  * from g_option_context_parse() before the first option is parsed
1495  * and after the last option has been parsed, respectively.
1496  *
1497  * Note that the user data to be passed to @pre_parse_func and
1498  * @post_parse_func can be specified when constructing the group
1499  * with g_option_group_new().
1500  *
1501  * Since: 2.6
1502  **/
1503 void
1504 g_option_group_set_parse_hooks (GOptionGroup     *group,
1505                                 GOptionParseFunc  pre_parse_func,
1506                                 GOptionParseFunc  post_parse_func)
1507 {
1508   g_return_if_fail (group != NULL);
1509
1510   group->pre_parse_func = pre_parse_func;
1511   group->post_parse_func = post_parse_func;  
1512 }
1513
1514 /**
1515  * g_option_group_set_error_hook:
1516  * @group: a #GOptionGroup
1517  * @error_func: a function to call when an error occurs
1518  * 
1519  * Associates a function with @group which will be called 
1520  * from g_option_context_parse() when an error occurs.
1521  *
1522  * Note that the user data to be passed to @pre_parse_func and
1523  * @post_parse_func can be specified when constructing the group
1524  * with g_option_group_new().
1525  *
1526  * Since: 2.6
1527  **/
1528 void
1529 g_option_group_set_error_hook (GOptionGroup     *group,
1530                                GOptionErrorFunc  error_func)
1531 {
1532   g_return_if_fail (group != NULL);
1533
1534   group->error_func = error_func;  
1535 }
1536
1537
1538 /**
1539  * g_option_group_set_translate_func:
1540  * @group: a #GOptionGroup
1541  * @func: the #GTranslateFunc, or %NULL 
1542  * @data: user data to pass to @func, or %NULL
1543  * @destroy_notify: a function which gets called to free @data, or %NULL
1544  * 
1545  * Sets the function which is used to translate user-visible
1546  * strings, for <option>--help</option> output. Different
1547  * groups can use different #GTranslateFunc<!-- -->s. If @func
1548  * is %NULL, strings are not translated.
1549  *
1550  * If you are using gettext(), you only need to set the translation
1551  * domain, see g_option_group_set_translation_domain().
1552  *
1553  * Since: 2.6
1554  **/
1555 void
1556 g_option_group_set_translate_func (GOptionGroup   *group,
1557                                    GTranslateFunc  func,
1558                                    gpointer        data,
1559                                    GDestroyNotify  destroy_notify)
1560 {
1561   g_return_if_fail (group != NULL);
1562   
1563   if (group->translate_notify)
1564     group->translate_notify (group->translate_data);
1565       
1566   group->translate_func = func;
1567   group->translate_data = data;
1568   group->translate_notify = destroy_notify;
1569 }
1570
1571 static gchar *
1572 dgettext_swapped (const gchar *msgid, 
1573                   const gchar *domainname)
1574 {
1575   return dgettext (domainname, msgid);
1576 }
1577
1578 /**
1579  * g_option_group_set_translation_domain:
1580  * @group: a #GOptionGroup
1581  * @domain: the domain to use
1582  * 
1583  * A convenience function to use gettext() for translating
1584  * user-visible strings. 
1585  * 
1586  * Since: 2.6
1587  **/
1588 void
1589 g_option_group_set_translation_domain (GOptionGroup *group,
1590                                        const gchar  *domain)
1591 {
1592   g_return_if_fail (group != NULL);
1593
1594   g_option_group_set_translate_func (group, 
1595                                      (GTranslateFunc)dgettext_swapped,
1596                                      g_strdup (domain),
1597                                      g_free);
1598
1599