Add and implement a new flag to turn off the automatic <groupname>-
authorMatthias Clasen <mclasen@redhat.com>
Tue, 12 Jul 2005 18:56:25 +0000 (18:56 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Tue, 12 Jul 2005 18:56:25 +0000 (18:56 +0000)
2005-07-12  Matthias Clasen  <mclasen@redhat.com>

* glib/goption.h (G_OPTION_FLAG_NOALIAS):
* glib/goption.c: Add and implement a new flag
to turn off the automatic <groupname>- prefixing
for conflict resolution of long option names. (#171840,
Adam McLaurin)

All optional callback arguments  (#308886, Pawel
Sliwowski)

* glib/goption.h (G_OPTION_FLAG_OPTIONAL_ARG):
* glib/goption.c: Add and implement a new flag
to indicate that a callback *optionally* takes another
argument.

* tests/option-test.c: Add tests for optional arguments.

ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-8
docs/reference/glib/tmpl/option.sgml
glib/goption.c
glib/goption.h
tests/option-test.c

index abb3bfe..59b77ae 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,23 @@
 2005-07-12  Matthias Clasen  <mclasen@redhat.com>
 
+       * glib/goption.h (G_OPTION_FLAG_NOALIAS): 
+       * glib/goption.c: Add and implement a new flag
+       to turn off the automatic <groupname>- prefixing
+       for conflict resolution of long option names. (#171840,
+       Adam McLaurin)
+       
+       All optional callback arguments  (#308886, Pawel
+       Sliwowski)
+
+       * glib/goption.h (G_OPTION_FLAG_OPTIONAL_ARG): 
+       * glib/goption.c: Add and implement a new flag
+       to indicate that a callback *optionally* takes another
+       argument.
+
+       * tests/option-test.c: Add tests for optional arguments.
+
+2005-07-12  Matthias Clasen  <mclasen@redhat.com>
+
        * glib/gthread.c (g_static_rec_mutex_lock_full): Don't lock
        if depth is zero.  (#310148, Wim Taymans)
 
index abb3bfe..59b77ae 100644 (file)
@@ -1,5 +1,23 @@
 2005-07-12  Matthias Clasen  <mclasen@redhat.com>
 
+       * glib/goption.h (G_OPTION_FLAG_NOALIAS): 
+       * glib/goption.c: Add and implement a new flag
+       to turn off the automatic <groupname>- prefixing
+       for conflict resolution of long option names. (#171840,
+       Adam McLaurin)
+       
+       All optional callback arguments  (#308886, Pawel
+       Sliwowski)
+
+       * glib/goption.h (G_OPTION_FLAG_OPTIONAL_ARG): 
+       * glib/goption.c: Add and implement a new flag
+       to indicate that a callback *optionally* takes another
+       argument.
+
+       * tests/option-test.c: Add tests for optional arguments.
+
+2005-07-12  Matthias Clasen  <mclasen@redhat.com>
+
        * glib/gthread.c (g_static_rec_mutex_lock_full): Don't lock
        if depth is zero.  (#310148, Wim Taymans)
 
index abb3bfe..59b77ae 100644 (file)
@@ -1,5 +1,23 @@
 2005-07-12  Matthias Clasen  <mclasen@redhat.com>
 
+       * glib/goption.h (G_OPTION_FLAG_NOALIAS): 
+       * glib/goption.c: Add and implement a new flag
+       to turn off the automatic <groupname>- prefixing
+       for conflict resolution of long option names. (#171840,
+       Adam McLaurin)
+       
+       All optional callback arguments  (#308886, Pawel
+       Sliwowski)
+
+       * glib/goption.h (G_OPTION_FLAG_OPTIONAL_ARG): 
+       * glib/goption.c: Add and implement a new flag
+       to indicate that a callback *optionally* takes another
+       argument.
+
+       * tests/option-test.c: Add tests for optional arguments.
+
+2005-07-12  Matthias Clasen  <mclasen@redhat.com>
+
        * glib/gthread.c (g_static_rec_mutex_lock_full): Don't lock
        if depth is zero.  (#310148, Wim Taymans)
 
index abb3bfe..59b77ae 100644 (file)
@@ -1,5 +1,23 @@
 2005-07-12  Matthias Clasen  <mclasen@redhat.com>
 
+       * glib/goption.h (G_OPTION_FLAG_NOALIAS): 
+       * glib/goption.c: Add and implement a new flag
+       to turn off the automatic <groupname>- prefixing
+       for conflict resolution of long option names. (#171840,
+       Adam McLaurin)
+       
+       All optional callback arguments  (#308886, Pawel
+       Sliwowski)
+
+       * glib/goption.h (G_OPTION_FLAG_OPTIONAL_ARG): 
+       * glib/goption.c: Add and implement a new flag
+       to indicate that a callback *optionally* takes another
+       argument.
+
+       * tests/option-test.c: Add tests for optional arguments.
+
+2005-07-12  Matthias Clasen  <mclasen@redhat.com>
+
        * glib/gthread.c (g_static_rec_mutex_lock_full): Don't lock
        if depth is zero.  (#310148, Wim Taymans)
 
index a4fa8f8..3014b3a 100644 (file)
@@ -275,6 +275,15 @@ Flags which modify individual options.
 @G_OPTION_FLAG_FILENAME: For options of the %G_OPTION_ARG_CALLBACK
    kind, this flag indicates that the argument should be passed to the
    callback in the GLib filename encoding rather than UTF-8. Since 2.8
+@G_OPTION_FLAG_OPTIONAL_ARG: For options of the %G_OPTION_ARG_CALLBACK 
+   kind, this flag indicates that the argument supply is optional. If no argument
+   is given then data of %GOptionParseFunc will be set to NULL. Since 2.8
+@G_OPTION_FLAG_NOALIAS: This flag turns off the automatic conflict resolution
+   which prefixes long option names with <literal>groupname-</literal> if 
+   there is a conflict. This option should only be used in situations where
+   aliasing is necessary to model some legacy commandline interface. It is
+   not safe to use this option, unless all option groups are under your 
+   direct control. Since 2.8.
 
 <!-- ##### MACRO G_OPTION_REMAINING ##### -->
 <para>
index efa4271..b0536e2 100644 (file)
@@ -37,6 +37,9 @@
                        ((entry)->arg == G_OPTION_ARG_CALLBACK &&  \
                         ((entry)->flags & G_OPTION_FLAG_NO_ARG)))
 
+#define OPTIONAL_ARG(entry) ((entry)->arg == G_OPTION_ARG_CALLBACK &&  \
+                       (entry)->flags & G_OPTION_FLAG_OPTIONAL_ARG)
+
 typedef struct 
 {
   GOptionArg arg_type;
@@ -494,12 +497,14 @@ print_help (GOptionContext *context,
       for (i = 0; i < group->n_entries; i++)
        {
          entry = &group->entries[i];
-         if (g_hash_table_lookup (shadow_map, entry->long_name))
+         if (g_hash_table_lookup (shadow_map, entry->long_name) && 
+             !(entry->flags && G_OPTION_FLAG_NOALIAS))
            entry->long_name = g_strdup_printf ("%s-%s", group->name, entry->long_name);
          else  
            g_hash_table_insert (shadow_map, (gpointer)entry->long_name, entry);
 
-         if (seen[(guchar)entry->short_name])
+         if (seen[(guchar)entry->short_name] && 
+             !(entry->flags && G_OPTION_FLAG_NOALIAS))
            entry->short_name = 0;
          else
            seen[(guchar)entry->short_name] = TRUE;
@@ -728,7 +733,7 @@ parse_arg (GOptionContext *context,
     case G_OPTION_ARG_STRING:
       {
        gchar *data;
-
+       
        data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
 
        if (!data)
@@ -747,7 +752,7 @@ parse_arg (GOptionContext *context,
     case G_OPTION_ARG_STRING_ARRAY:
       {
        gchar *data;
-       
+
        data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
 
        if (!data)
@@ -853,13 +858,15 @@ parse_arg (GOptionContext *context,
       {
        gchar *data;
        gboolean retval;
-       
-       if (entry->flags & G_OPTION_FLAG_NO_ARG)
+
+       if (!value && entry->flags & G_OPTION_FLAG_OPTIONAL_ARG)
+         data = NULL;
+       else if (entry->flags & G_OPTION_FLAG_NO_ARG)
          data = NULL;
        else if (entry->flags & G_OPTION_FLAG_FILENAME)
          {
 #ifdef G_OS_WIN32
-           data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
+           data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
 #else
            data = g_strdup (value);
 #endif
@@ -867,7 +874,8 @@ parse_arg (GOptionContext *context,
        else
          data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
 
-       if (!(entry->flags & G_OPTION_FLAG_NO_ARG) && !data)
+       if (!(entry->flags & (G_OPTION_FLAG_NO_ARG|G_OPTION_FLAG_OPTIONAL_ARG)) && 
+           !data)
          return FALSE;
 
        retval = (* (GOptionArgFunc) entry->arg_data) (option_name, data, group->user_data, error);
@@ -902,22 +910,15 @@ parse_short_option (GOptionContext *context,
     {
       if (arg == group->entries[j].short_name)
        {
-         if (NO_ARG (&group->entries[j]))
-           {
-             gchar *option_name;
+         gchar *option_name;
+         gchar *value = NULL;
+         
+         option_name = g_strdup_printf ("-%c", group->entries[j].short_name);
 
-             option_name = g_strdup_printf ("-%c", group->entries[j].short_name);
-             parse_arg (context, group, &group->entries[j],
-                        NULL, option_name, error);
-             g_free (option_name);
-             
-             *parsed = TRUE;
-           }
+         if (NO_ARG (&group->entries[j]))
+           value = NULL;
          else
            {
-             gchar *value = NULL;
-             gchar *option_name;
-             
              if (*new_index > index)
                {
                  g_warning ("FIXME: figure out the correct error here");
@@ -929,10 +930,26 @@ parse_short_option (GOptionContext *context,
              
              if (index < *argc - 1)
                {
-                 value = (*argv)[index + 1];
-                 add_pending_null (context, &((*argv)[index + 1]), NULL);
-                 *new_index = index + 1;
+                 if (!OPTIONAL_ARG (&group->entries[j]))       
+                   {    
+                     value = (*argv)[index + 1];
+                     add_pending_null (context, &((*argv)[index + 1]), NULL);
+                     *new_index = index+1;
+                   }
+                 else
+                   {
+                      if ((*argv)[index + 1][0] == '-') 
+                       value = NULL;
+                     else
+                       {
+                         value = (*argv)[index + 1];
+                         add_pending_null (context, &((*argv)[index + 1]), NULL);
+                         *new_index = index + 1;
+                       }
+                   }
                }
+             else if (index >= *argc - 1 && OPTIONAL_ARG (&group->entries[j]))
+               value = NULL;
              else
                {
                  g_set_error (error, 
@@ -941,16 +958,17 @@ parse_short_option (GOptionContext *context,
                  g_free (option_name);
                  return FALSE;
                }
-             
-             if (!parse_arg (context, group, &group->entries[j], value, option_name, error))
-               {
-                 g_free (option_name);
-                 return FALSE;
-               }
+           }
 
+         if (!parse_arg (context, group, &group->entries[j], 
+                         value, option_name, error))
+           {
              g_free (option_name);
-             *parsed = TRUE;
+             return FALSE;
            }
+         
+         g_free (option_name);
+         *parsed = TRUE;
        }
     }
 
@@ -962,6 +980,7 @@ parse_long_option (GOptionContext *context,
                   GOptionGroup   *group,
                   gint           *index,
                   gchar          *arg,
+                  gboolean        aliased,
                   gint           *argc,
                   gchar        ***argv,
                   GError        **error,
@@ -974,6 +993,9 @@ parse_long_option (GOptionContext *context,
       if (*index >= *argc)
        return TRUE;
 
+      if (aliased && (group->entries[j].flags & G_OPTION_FLAG_NOALIAS))
+       continue;
+
       if (NO_ARG (&group->entries[j]) &&
          strcmp (arg, group->entries[j].long_name) == 0)
        {
@@ -1002,11 +1024,42 @@ parse_long_option (GOptionContext *context,
 
              if (arg[len] == '=')
                value = arg + len + 1;
-             else if (*index < *argc - 1)
+             else if (*index < *argc - 1) 
                {
-                 value = (*argv)[*index + 1];
-                 add_pending_null (context, &((*argv)[*index + 1]), NULL);
-                 (*index)++;
+                 if (!(group->entries[j].flags & G_OPTION_FLAG_OPTIONAL_ARG))  
+                   {    
+                     value = (*argv)[*index + 1];
+                     add_pending_null (context, &((*argv)[*index + 1]), NULL);
+                     (*index)++;
+                   }
+                 else
+                   {
+                      if ((*argv)[*index + 1][0] == '-') 
+                       {
+                         gboolean retval;
+                         retval = parse_arg (context, group, &group->entries[j],
+                                             NULL, option_name, error);
+                         *parsed = TRUE;
+                         g_free (option_name);
+                         return retval;
+                       }
+                     else
+                       {
+                         value = (*argv)[*index + 1];
+                         add_pending_null (context, &((*argv)[*index + 1]), NULL);
+                         (*index)++;
+                       }
+                   }
+               }
+             else if (*index >= *argc - 1 &&
+                      group->entries[j].flags & G_OPTION_FLAG_OPTIONAL_ARG)
+               {
+                   gboolean retval;
+                   retval = parse_arg (context, group, &group->entries[j],
+                                       NULL, option_name, error);
+                   *parsed = TRUE;
+                   g_free (option_name);
+                   return retval;
                }
              else
                {
@@ -1017,7 +1070,8 @@ parse_long_option (GOptionContext *context,
                  return FALSE;
                }
 
-             if (!parse_arg (context, group, &group->entries[j], value, option_name, error))
+             if (!parse_arg (context, group, &group->entries[j], 
+                             value, option_name, error))
                {
                  g_free (option_name);
                  return FALSE;
@@ -1025,7 +1079,7 @@ parse_long_option (GOptionContext *context,
 
              g_free (option_name);
              *parsed = TRUE;
-           }
+           } 
        }
     }
   
@@ -1268,7 +1322,7 @@ g_option_context_parse (GOptionContext   *context,
 
                  if (context->main_group &&
                      !parse_long_option (context, context->main_group, &i, arg,
-                                         argc, argv, error, &parsed))
+                                         FALSE, argc, argv, error, &parsed))
                    goto fail;
 
                  if (parsed)
@@ -1280,8 +1334,8 @@ g_option_context_parse (GOptionContext   *context,
                    {
                      GOptionGroup *group = list->data;
                      
-                     if (!parse_long_option (context, group, &i, arg,
-                                             argc, argv, error, &parsed))
+                     if (!parse_long_option (context, group, &i, arg, 
+                                             FALSE, argc, argv, error, &parsed))
                        goto fail;
                      
                      if (parsed)
@@ -1306,7 +1360,7 @@ g_option_context_parse (GOptionContext   *context,
                          if (strncmp (group->name, arg, dash - arg) == 0)
                            {
                              if (!parse_long_option (context, group, &i, dash + 1,
-                                                     argc, argv, error, &parsed))
+                                                     TRUE, argc, argv, error, &parsed))
                                goto fail;
                              
                              if (parsed)
index dcd36e4..4448fd0 100644 (file)
@@ -32,11 +32,13 @@ typedef struct _GOptionEntry   GOptionEntry;
 
 typedef enum
 {
-  G_OPTION_FLAG_HIDDEN       = 1 << 0,
-  G_OPTION_FLAG_IN_MAIN      = 1 << 1,
-  G_OPTION_FLAG_REVERSE      = 1 << 2,
-  G_OPTION_FLAG_NO_ARG       = 1 << 3,
-  G_OPTION_FLAG_FILENAME     = 1 << 4
+  G_OPTION_FLAG_HIDDEN         = 1 << 0,
+  G_OPTION_FLAG_IN_MAIN                = 1 << 1,
+  G_OPTION_FLAG_REVERSE                = 1 << 2,
+  G_OPTION_FLAG_NO_ARG         = 1 << 3,
+  G_OPTION_FLAG_FILENAME       = 1 << 4,
+  G_OPTION_FLAG_OPTIONAL_ARG    = 1 << 5,
+  G_OPTION_FLAG_NOALIAS                = 1 << 6
 } GOptionFlags;
 
 typedef enum
index ffd1761..4699afd 100644 (file)
@@ -12,6 +12,9 @@ gchar *arg_test3_filename;
 gchar *callback_test1_string;
 gboolean callback_test2_int;
 
+gchar *callback_test_optional_string;
+gboolean callback_test_optional_boolean;
+
 gchar **array_test1_array;
 
 gboolean ignore_test1_boolean;
@@ -399,6 +402,283 @@ callback_test2 (void)
   g_option_context_free (context);
 }
 
+static gboolean
+callback_parse_optional (const gchar *option_name, const gchar *value,
+                gpointer data, GError **error)
+{
+       callback_test_optional_boolean = TRUE;
+       if (value)
+               callback_test_optional_string = g_strdup (value);
+       else
+               callback_test_optional_string = NULL;
+       return TRUE;
+}
+
+void
+callback_test_optional_1 (void)
+{
+  GOptionContext *context;
+  gboolean retval;
+  GError *error = NULL;
+  gchar **argv;
+  int argc;
+  GOptionEntry entries [] =
+    { { "test", 0, G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, 
+       callback_parse_optional, NULL, NULL },
+      { NULL } };
+  
+  context = g_option_context_new (NULL);
+  g_option_context_add_main_entries (context, entries, NULL);
+
+  /* Now try parsing */
+  argv = split_string ("program --test foo.txt", &argc);
+  
+  retval = g_option_context_parse (context, &argc, &argv, &error);
+  g_assert (retval);
+
+  g_assert (strcmp (callback_test_optional_string, "foo.txt") == 0);
+  
+  g_assert (callback_test_optional_boolean);
+
+  g_free (callback_test_optional_string);
+  
+  g_strfreev (argv);
+  g_option_context_free (context);
+}
+
+void
+callback_test_optional_2 (void)
+{
+  GOptionContext *context;
+  gboolean retval;
+  GError *error = NULL;
+  gchar **argv;
+  int argc;
+  GOptionEntry entries [] =
+    { { "test", 0, G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, 
+       callback_parse_optional, NULL, NULL },
+      { NULL } };
+  
+  context = g_option_context_new (NULL);
+  g_option_context_add_main_entries (context, entries, NULL);
+
+  /* Now try parsing */
+  argv = split_string ("program --test", &argc);
+  
+  retval = g_option_context_parse (context, &argc, &argv, &error);
+  g_assert (retval);
+
+  g_assert (callback_test_optional_string == NULL);
+  
+  g_assert (callback_test_optional_boolean);
+
+  g_free (callback_test_optional_string);
+  
+  g_strfreev (argv);
+  g_option_context_free (context);
+}
+
+void
+callback_test_optional_3 (void)
+{
+  GOptionContext *context;
+  gboolean retval;
+  GError *error = NULL;
+  gchar **argv;
+  int argc;
+  GOptionEntry entries [] =
+    { { "test", 't', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, 
+       callback_parse_optional, NULL, NULL },
+      { NULL } };
+  
+  context = g_option_context_new (NULL);
+  g_option_context_add_main_entries (context, entries, NULL);
+
+  /* Now try parsing */
+  argv = split_string ("program -t foo.txt", &argc);
+  
+  retval = g_option_context_parse (context, &argc, &argv, &error);
+  g_assert (retval);
+
+  g_assert (strcmp (callback_test_optional_string, "foo.txt") == 0);
+  
+  g_assert (callback_test_optional_boolean);
+
+  g_free (callback_test_optional_string);
+  
+  g_strfreev (argv);
+  g_option_context_free (context);
+}
+
+
+void
+callback_test_optional_4 (void)
+{
+  GOptionContext *context;
+  gboolean retval;
+  GError *error = NULL;
+  gchar **argv;
+  int argc;
+  GOptionEntry entries [] =
+    { { "test", 't', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, 
+       callback_parse_optional, NULL, NULL },
+      { NULL } };
+  
+  context = g_option_context_new (NULL);
+  g_option_context_add_main_entries (context, entries, NULL);
+
+  /* Now try parsing */
+  argv = split_string ("program -t", &argc);
+  
+  retval = g_option_context_parse (context, &argc, &argv, &error);
+  g_assert (retval);
+
+  g_assert (callback_test_optional_string == NULL);
+  
+  g_assert (callback_test_optional_boolean);
+
+  g_free (callback_test_optional_string);
+  
+  g_strfreev (argv);
+  g_option_context_free (context);
+}
+
+void
+callback_test_optional_5 (void)
+{
+  GOptionContext *context;
+  gboolean dummy;
+  gboolean retval;
+  GError *error = NULL;
+  gchar **argv;
+  int argc;
+  GOptionEntry entries [] =
+    { { "dummy", 'd', 0, G_OPTION_ARG_NONE, &dummy, NULL },
+      { "test", 't', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, 
+       callback_parse_optional, NULL, NULL },
+      { NULL } };
+  
+  context = g_option_context_new (NULL);
+  g_option_context_add_main_entries (context, entries, NULL);
+
+  /* Now try parsing */
+  argv = split_string ("program --test --dummy", &argc);
+  
+  retval = g_option_context_parse (context, &argc, &argv, &error);
+  g_assert (retval);
+
+  g_assert (callback_test_optional_string == NULL);
+  
+  g_assert (callback_test_optional_boolean);
+
+  g_free (callback_test_optional_string);
+  
+  g_strfreev (argv);
+  g_option_context_free (context);
+}
+
+void
+callback_test_optional_6 (void)
+{
+  GOptionContext *context;
+  gboolean dummy;
+  gboolean retval;
+  GError *error = NULL;
+  gchar **argv;
+  int argc;
+  GOptionEntry entries [] =
+    { { "dummy", 'd', 0, G_OPTION_ARG_NONE, &dummy, NULL },
+      { "test", 't', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, 
+       callback_parse_optional, NULL, NULL },
+      { NULL } };
+  
+  context = g_option_context_new (NULL);
+  g_option_context_add_main_entries (context, entries, NULL);
+
+  /* Now try parsing */
+  argv = split_string ("program -t -d", &argc);
+  
+  retval = g_option_context_parse (context, &argc, &argv, &error);
+  g_assert (retval);
+
+  g_assert (callback_test_optional_string == NULL);
+  
+  g_assert (callback_test_optional_boolean);
+
+  g_free (callback_test_optional_string);
+  
+  g_strfreev (argv);
+  g_option_context_free (context);
+}
+
+void
+callback_test_optional_7 (void)
+{
+  GOptionContext *context;
+  gboolean dummy;
+  gboolean retval;
+  GError *error = NULL;
+  gchar **argv;
+  int argc;
+  GOptionEntry entries [] =
+    { { "dummy", 'd', 0, G_OPTION_ARG_NONE, &dummy, NULL },
+      { "test", 't', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, 
+       callback_parse_optional, NULL, NULL },
+      { NULL } };
+  
+  context = g_option_context_new (NULL);
+  g_option_context_add_main_entries (context, entries, NULL);
+
+  /* Now try parsing */
+  argv = split_string ("program -td", &argc);
+  
+  retval = g_option_context_parse (context, &argc, &argv, &error);
+  g_assert (retval);
+
+  g_assert (callback_test_optional_string == NULL);
+  
+  g_assert (callback_test_optional_boolean);
+
+  g_free (callback_test_optional_string);
+  
+  g_strfreev (argv);
+  g_option_context_free (context);
+}
+
+void
+callback_test_optional_8 (void)
+{
+  GOptionContext *context;
+  gboolean dummy;
+  gboolean retval;
+  GError *error = NULL;
+  gchar **argv;
+  int argc;
+  GOptionEntry entries [] =
+    { { "dummy", 'd', 0, G_OPTION_ARG_NONE, &dummy, NULL },
+      { "test", 't', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, 
+       callback_parse_optional, NULL, NULL },
+      { NULL } };
+  
+  context = g_option_context_new (NULL);
+  g_option_context_add_main_entries (context, entries, NULL);
+
+  /* Now try parsing */
+  argv = split_string ("program -dt foo.txt", &argc);
+  
+  retval = g_option_context_parse (context, &argc, &argv, &error);
+  g_assert (retval);
+
+  g_assert (callback_test_optional_string);
+  
+  g_assert (callback_test_optional_boolean);
+
+  g_free (callback_test_optional_string);
+  
+  g_strfreev (argv);
+  g_option_context_free (context);
+}
+
 void
 ignore_test1 (void)
 {
@@ -1016,6 +1296,16 @@ main (int argc, char **argv)
   callback_test1 ();
   callback_test2 ();
 
+  /* Test optional arg flag for callback */
+  callback_test_optional_1 ();
+  callback_test_optional_2 ();
+  callback_test_optional_3 ();
+  callback_test_optional_4 ();
+  callback_test_optional_5 ();
+  callback_test_optional_6 ();
+  callback_test_optional_7 ();
+  callback_test_optional_8 ();
+  
   /* Test ignoring options */
   ignore_test1 ();
   ignore_test2 ();