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