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