Add tests for the handling of non-option arguments, "--" and

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.
This commit is contained in:
Matthias Clasen 2004-10-29 20:19:06 +00:00 committed by Matthias Clasen
parent a0e217e94a
commit a9fa61a13e
8 changed files with 304 additions and 10 deletions

View 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>

View 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>

View 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>

View 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>

View 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>

View File

@ -19,9 +19,11 @@
* 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 *

View 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__ */

View 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;
}