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