Add tests for the handling of non-option arguments, "--" and
authorMatthias Clasen <mclasen@redhat.com>
Fri, 29 Oct 2004 20:19:06 +0000 (20:19 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Fri, 29 Oct 2004 20:19:06 +0000 (20:19 +0000)
2004-10-29  Matthias Clasen  <mclasen@redhat.com>

* tests/option-test.c: Add tests for the handling of
non-option arguments, "--" and G_OPTION_REMAINING.

* glib/goption.[hc]: #define G_OPTION_REMAINING, which is
a special long option name, which can be used for an option
in the main group which collects the non-option arguments.
It must be of type G_OPTION_ARG_STRING_ARRAY or
G_OPTION_ARG_FILENAME_ARRAY. If the main group doesn't contain
an option whose name is G_OPTION_REMAINING, the non-option
arguments are left behind in argv as before.

ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-6
ChangeLog.pre-2-8
glib/goption.c
glib/goption.h
tests/option-test.c

index d191bb7..09f5489 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
 2004-10-29  Matthias Clasen  <mclasen@redhat.com>
 
+       * tests/option-test.c: Add tests for the handling of
+       non-option arguments, "--" and G_OPTION_REMAINING.
+
+       * glib/goption.[hc]: #define G_OPTION_REMAINING, which is
+       a special long option name, which can be used for an option
+       in the main group which collects the non-option arguments.
+       It must be of type G_OPTION_ARG_STRING_ARRAY or 
+       G_OPTION_ARG_FILENAME_ARRAY. If the main group doesn't contain
+       an option whose name is G_OPTION_REMAINING, the non-option
+       arguments are left behind in argv as before.
+
        * glib/goption.c: Add documentation.
 
 2004-10-28  Matthias Clasen  <mclasen@redhat.com>
index d191bb7..09f5489 100644 (file)
@@ -1,5 +1,16 @@
 2004-10-29  Matthias Clasen  <mclasen@redhat.com>
 
+       * tests/option-test.c: Add tests for the handling of
+       non-option arguments, "--" and G_OPTION_REMAINING.
+
+       * glib/goption.[hc]: #define G_OPTION_REMAINING, which is
+       a special long option name, which can be used for an option
+       in the main group which collects the non-option arguments.
+       It must be of type G_OPTION_ARG_STRING_ARRAY or 
+       G_OPTION_ARG_FILENAME_ARRAY. If the main group doesn't contain
+       an option whose name is G_OPTION_REMAINING, the non-option
+       arguments are left behind in argv as before.
+
        * glib/goption.c: Add documentation.
 
 2004-10-28  Matthias Clasen  <mclasen@redhat.com>
index d191bb7..09f5489 100644 (file)
@@ -1,5 +1,16 @@
 2004-10-29  Matthias Clasen  <mclasen@redhat.com>
 
+       * tests/option-test.c: Add tests for the handling of
+       non-option arguments, "--" and G_OPTION_REMAINING.
+
+       * glib/goption.[hc]: #define G_OPTION_REMAINING, which is
+       a special long option name, which can be used for an option
+       in the main group which collects the non-option arguments.
+       It must be of type G_OPTION_ARG_STRING_ARRAY or 
+       G_OPTION_ARG_FILENAME_ARRAY. If the main group doesn't contain
+       an option whose name is G_OPTION_REMAINING, the non-option
+       arguments are left behind in argv as before.
+
        * glib/goption.c: Add documentation.
 
 2004-10-28  Matthias Clasen  <mclasen@redhat.com>
index d191bb7..09f5489 100644 (file)
@@ -1,5 +1,16 @@
 2004-10-29  Matthias Clasen  <mclasen@redhat.com>
 
+       * tests/option-test.c: Add tests for the handling of
+       non-option arguments, "--" and G_OPTION_REMAINING.
+
+       * glib/goption.[hc]: #define G_OPTION_REMAINING, which is
+       a special long option name, which can be used for an option
+       in the main group which collects the non-option arguments.
+       It must be of type G_OPTION_ARG_STRING_ARRAY or 
+       G_OPTION_ARG_FILENAME_ARRAY. If the main group doesn't contain
+       an option whose name is G_OPTION_REMAINING, the non-option
+       arguments are left behind in argv as before.
+
        * glib/goption.c: Add documentation.
 
 2004-10-28  Matthias Clasen  <mclasen@redhat.com>
index d191bb7..09f5489 100644 (file)
@@ -1,5 +1,16 @@
 2004-10-29  Matthias Clasen  <mclasen@redhat.com>
 
+       * tests/option-test.c: Add tests for the handling of
+       non-option arguments, "--" and G_OPTION_REMAINING.
+
+       * glib/goption.[hc]: #define G_OPTION_REMAINING, which is
+       a special long option name, which can be used for an option
+       in the main group which collects the non-option arguments.
+       It must be of type G_OPTION_ARG_STRING_ARRAY or 
+       G_OPTION_ARG_FILENAME_ARRAY. If the main group doesn't contain
+       an option whose name is G_OPTION_REMAINING, the non-option
+       arguments are left behind in argv as before.
+
        * glib/goption.c: Add documentation.
 
 2004-10-28  Matthias Clasen  <mclasen@redhat.com>
index 7210a2c..931d5c8 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
-#include "goption.h"
+#include "config.h"
 
 #include "galias.h"
+
+#include "goption.h"
 #include "glib.h"
 #include "gi18n.h"
 
@@ -148,8 +150,9 @@ g_option_context_new (const gchar *parameter_string)
  *
  * Since: 2.6
  */
-void g_option_context_free (GOptionContext *context) {
-g_return_if_fail (context != NULL);
+void g_option_context_free (GOptionContext *context) 
+{
+  g_return_if_fail (context != NULL);
 
   g_list_foreach (context->groups, (GFunc)g_option_group_free, NULL);
   g_list_free (context->groups);
@@ -404,6 +407,9 @@ print_help (GOptionContext *context,
       /* Then we go through the entries */
       for (i = 0; i < group->n_entries; i++)
        {
+         if (group->entries[i].flags & G_OPTION_FLAG_HIDDEN)
+           continue;
+
          len = g_utf8_strlen (group->entries[i].long_name, -1);
 
          if (group->entries[i].short_name)
@@ -862,6 +868,40 @@ parse_long_option (GOptionContext *context,
   return TRUE;
 }
 
+static gboolean
+parse_remaining_arg (GOptionContext *context,
+                    GOptionGroup   *group,
+                    gint           *index,
+                    gint           *argc,
+                    gchar        ***argv,
+                    GError        **error,
+                    gboolean       *parsed)
+{
+  gint j;
+
+  for (j = 0; j < group->n_entries; j++)
+    {
+      if (*index >= *argc)
+       return TRUE;
+
+      if (group->entries[j].long_name[0])
+       continue;
+
+      g_return_val_if_fail (group->entries[j].arg == G_OPTION_ARG_STRING_ARRAY ||
+                           group->entries[j].arg == G_OPTION_ARG_FILENAME_ARRAY, FALSE);
+      
+      add_pending_null (context, &((*argv)[*index]), NULL);
+      
+      if (!parse_arg (context, group, &group->entries[j], (*argv)[*index], "", error))
+       return FALSE;
+      
+      *parsed = TRUE;
+      return TRUE;
+    }
+
+  return TRUE;
+}
+
 static void
 free_changes_list (GOptionContext *context,
                   gboolean        revert)
@@ -1004,12 +1044,14 @@ g_option_context_parse (GOptionContext   *context,
 
   if (argc && argv)
     {
+      gboolean stop_parsing = FALSE;
+
       for (i = 1; i < *argc; i++)
        {
          gchar *arg;
          gboolean parsed = FALSE;
 
-         if ((*argv)[i][0] == '-')
+         if ((*argv)[i][0] == '-' && !stop_parsing)
            {
              if ((*argv)[i][1] == '-')
                {
@@ -1021,7 +1063,8 @@ g_option_context_parse (GOptionContext   *context,
                  if (*arg == 0)
                    {
                      add_pending_null (context, &((*argv)[i]), NULL);
-                     break;
+                     stop_parsing = TRUE;
+                     continue;
                    }
 
                  /* Handle help options */
@@ -1167,6 +1210,15 @@ g_option_context_parse (GOptionContext   *context,
                  goto fail;
                }
            }
+         else
+           {
+             /* Collect remaining args */
+             if (context->main_group &&
+                 !parse_remaining_arg (context, context->main_group, &i,
+                                       argc, argv, error, &parsed))
+               goto fail;
+             
+           }
        }
 
       /* Call post-parse hooks */
@@ -1204,7 +1256,10 @@ g_option_context_parse (GOptionContext   *context,
            {
              k -= i;
              for (j = i + k; j < *argc; j++)
-               (*argv)[j-k] = (*argv)[j];
+               {
+                 (*argv)[j-k] = (*argv)[j];
+                 (*argv)[j] = NULL;
+               }
              *argc -= k;
            }
        }      
@@ -1415,7 +1470,7 @@ g_option_group_set_translate_func (GOptionGroup   *group,
       
   group->translate_func = func;
   group->translate_data = data;
-  group->translate_notify = notify;
+  group->translate_notify = destroy_notify;
 }
 
 static gchar *
index f1ffd0f..1b62d7c 100644 (file)
@@ -87,6 +87,8 @@ struct _GOptionEntry
   const gchar *arg_description;
 };
 
+#define G_OPTION_REMAINING ""
+
 GOptionContext *g_option_context_new              (const gchar         *parameter_string);
 void            g_option_context_free             (GOptionContext      *context);
 void           g_option_context_set_help_enabled (GOptionContext      *context,
@@ -132,9 +134,6 @@ void          g_option_group_set_translation_domain (GOptionGroup       *group,
                                                     const gchar        *domain);
 
 
-
-
-
 G_END_DECLS
 
 #endif /* __G_OPTION_H__ */
index daf7591..38f8266 100644 (file)
@@ -524,6 +524,184 @@ empty_test3 (void)
   g_option_context_free (context);
 }
 
+/* check that non-option arguments are left in argv by default */
+void
+rest_test1 (void)
+{
+  GOptionContext *context;
+  gboolean retval;
+  GError *error = NULL;
+  gchar **argv;
+  int argc;
+  GOptionEntry entries [] = { 
+      { "test", 0, 0, G_OPTION_ARG_NONE, &ignore_test1_boolean, 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 foo --test bar", &argc);
+  
+  retval = g_option_context_parse (context, &argc, &argv, &error);
+  g_assert (retval);
+
+  /* Check array */
+  g_assert (ignore_test1_boolean);
+  g_assert (strcmp (argv[0], "program") == 0);
+  g_assert (strcmp (argv[1], "foo") == 0);
+  g_assert (strcmp (argv[2], "bar") == 0);
+  g_assert (argv[3] == NULL);
+
+  g_strfreev (argv);
+  g_option_context_free (context);
+}
+
+/* check that -- works */
+void
+rest_test2 (void)
+{
+  GOptionContext *context;
+  gboolean retval;
+  GError *error = NULL;
+  gchar **argv;
+  int argc;
+  GOptionEntry entries [] = { 
+      { "test", 0, 0, G_OPTION_ARG_NONE, &ignore_test1_boolean, 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 foo --test -- -bar", &argc);
+  
+  retval = g_option_context_parse (context, &argc, &argv, &error);
+  g_assert (retval);
+
+  /* Check array */
+  g_assert (ignore_test1_boolean);
+  g_assert (strcmp (argv[0], "program") == 0);
+  g_assert (strcmp (argv[1], "foo") == 0);
+  g_assert (strcmp (argv[2], "-bar") == 0);
+  g_assert (argv[3] == NULL);
+
+  g_strfreev (argv);
+  g_option_context_free (context);
+}
+
+/* check that G_OPTION_REMAINING collects non-option arguments */
+void
+rest_test3 (void)
+{
+  GOptionContext *context;
+  gboolean retval;
+  GError *error = NULL;
+  gchar **argv;
+  int argc;
+  GOptionEntry entries [] = { 
+      { "test", 0, 0, G_OPTION_ARG_NONE, &ignore_test1_boolean, NULL, NULL },
+      { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &array_test1_array, 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 foo --test bar", &argc);
+  
+  retval = g_option_context_parse (context, &argc, &argv, &error);
+  g_assert (retval);
+
+  /* Check array */
+  g_assert (ignore_test1_boolean);
+  g_assert (strcmp (array_test1_array[0], "foo") == 0);
+  g_assert (strcmp (array_test1_array[1], "bar") == 0);
+  g_assert (array_test1_array[2] == NULL);
+
+  g_strfreev (array_test1_array);
+  
+  g_strfreev (argv);
+  g_option_context_free (context);
+}
+
+
+/* check that G_OPTION_REMAINING and -- work together */
+void
+rest_test4 (void)
+{
+  GOptionContext *context;
+  gboolean retval;
+  GError *error = NULL;
+  gchar **argv;
+  int argc;
+  GOptionEntry entries [] = { 
+      { "test", 0, 0, G_OPTION_ARG_NONE, &ignore_test1_boolean, NULL, NULL },
+      { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &array_test1_array, 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 foo --test -- -bar", &argc);
+  
+  retval = g_option_context_parse (context, &argc, &argv, &error);
+  g_assert (retval);
+
+  /* Check array */
+  g_assert (ignore_test1_boolean);
+  g_assert (strcmp (array_test1_array[0], "foo") == 0);
+  g_assert (strcmp (array_test1_array[1], "-bar") == 0);
+  g_assert (array_test1_array[2] == NULL);
+
+  g_strfreev (array_test1_array);
+  
+  g_strfreev (argv);
+  g_option_context_free (context);
+}
+
+/* test that G_OPTION_REMAINING works with G_OPTION_ARG_FILENAME_ARRAY */
+void
+rest_test5 (void)
+{
+  GOptionContext *context;
+  gboolean retval;
+  GError *error = NULL;
+  gchar **argv;
+  int argc;
+  GOptionEntry entries [] = { 
+      { "test", 0, 0, G_OPTION_ARG_NONE, &ignore_test1_boolean, NULL, NULL },
+      { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &array_test1_array, 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 foo --test bar", &argc);
+  
+  retval = g_option_context_parse (context, &argc, &argv, &error);
+  g_assert (retval);
+
+  /* Check array */
+  g_assert (ignore_test1_boolean);
+  g_assert (strcmp (array_test1_array[0], "foo") == 0);
+  g_assert (strcmp (array_test1_array[1], "bar") == 0);
+  g_assert (array_test1_array[2] == NULL);
+
+  g_strfreev (array_test1_array);
+  
+  g_strfreev (argv);
+  g_option_context_free (context);
+}
+
+
 int
 main (int argc, char **argv)
 {
@@ -555,5 +733,12 @@ main (int argc, char **argv)
   empty_test2 ();
   empty_test3 ();
 
+  /* Test handling of rest args */
+  rest_test1 ();
+  rest_test2 ();
+  rest_test3 ();
+  rest_test4 ();
+  rest_test5 ();
+
   return 0;
 }