? tests/hum
Index: docs/reference/glib/tmpl/option.sgml
===================================================================
RCS file: /cvs/gnome/glib/docs/reference/glib/tmpl/option.sgml,v
retrieving revision 1.10
diff -u -r1.10 option.sgml
--- docs/reference/glib/tmpl/option.sgml	18 Jun 2005 04:55:26 -0000	1.10
+++ docs/reference/glib/tmpl/option.sgml	24 Jun 2005 03:38:54 -0000
@@ -272,7 +272,10 @@
 @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
+   
 <!-- ##### MACRO G_OPTION_REMAINING ##### -->
 <para>
 If a long option in the main group has this name, it is not treated as a 
Index: glib/goption.c
===================================================================
RCS file: /cvs/gnome/glib/glib/goption.c,v
retrieving revision 1.43
diff -u -r1.43 goption.c
--- glib/goption.c	22 Jun 2005 17:09:31 -0000	1.43
+++ glib/goption.c	24 Jun 2005 03:38:55 -0000
@@ -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;
@@ -728,7 +731,7 @@
     case G_OPTION_ARG_STRING:
       {
 	gchar *data;
-
+	
 	data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
 
 	if (!data)
@@ -747,7 +750,7 @@
     case G_OPTION_ARG_STRING_ARRAY:
       {
 	gchar *data;
-	
+
 	data = g_locale_to_utf8 (value, -1, NULL, NULL, error);
 
 	if (!data)
@@ -853,13 +856,15 @@
       {
 	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 +872,8 @@
 	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) || (entry->flags & G_OPTION_FLAG_OPTIONAL_ARG)) 
+		&& !data)
 	  return FALSE;
 
 	retval = (* (GOptionArgFunc) entry->arg_data) (option_name, data, group->user_data, error);
@@ -929,9 +935,39 @@
 	      
 	      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 (strncmp ((*argv)[index + 1],"-",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);
+		          *new_index = index + 1;
+			}
+	            }
+		}
+	      else if (index >= *argc - 1 && OPTIONAL_ARG(&group->entries[j]))
+		{
+		    gboolean retval;
+		    retval = parse_arg (context, group, &group->entries[j],
+		          NULL, option_name, error);
+	  	    *parsed = TRUE;
+		    g_free (option_name);
+	   	    return retval;
 		}
 	      else
 		{
@@ -1002,11 +1038,42 @@
 
 	      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 (strncmp ((*argv)[*index + 1],"-",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
 		{
@@ -1025,7 +1092,7 @@
 
 	      g_free (option_name);
 	      *parsed = TRUE;
-	    }
+	    } 
 	}
     }
   
Index: glib/goption.h
===================================================================
RCS file: /cvs/gnome/glib/glib/goption.h,v
retrieving revision 1.9
diff -u -r1.9 goption.h
--- glib/goption.h	18 Jun 2005 04:55:25 -0000	1.9
+++ glib/goption.h	24 Jun 2005 03:38:55 -0000
@@ -32,11 +32,12 @@
 
 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
 } GOptionFlags;
 
 typedef enum
Index: tests/option-test.c
===================================================================
RCS file: /cvs/gnome/glib/tests/option-test.c,v
retrieving revision 1.13
diff -u -r1.13 option-test.c
--- tests/option-test.c	18 Jun 2005 04:55:26 -0000	1.13
+++ tests/option-test.c	24 Jun 2005 03:38:55 -0000
@@ -12,6 +12,9 @@
 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,80 @@
   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
 ignore_test1 (void)
 {
@@ -1016,6 +1093,10 @@
   callback_test1 ();
   callback_test2 ();
 
+  /* Test optional arg flag for callback */
+  callback_test_optional_1 ();
+  callback_test_optional_2 ();
+  
   /* Test ignoring options */
   ignore_test1 ();
   ignore_test2 ();
