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