Add and implement a new flag to turn off the automatic <groupname>-

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.
This commit is contained in:
Matthias Clasen 2005-07-12 18:56:25 +00:00 committed by Matthias Clasen
parent 392980c783
commit 58dd4814b2
8 changed files with 475 additions and 48 deletions

View File

@ -1,3 +1,21 @@
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

View File

@ -1,3 +1,21 @@
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

View File

@ -1,3 +1,21 @@
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

View File

@ -1,3 +1,21 @@
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

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

View 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;
}
g_free (option_name);
*parsed = TRUE;
}
if (!parse_arg (context, group, &group->entries[j],
value, option_name, error))
{
g_free (option_name);
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)

View 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

View 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 ();