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