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