mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 11:26:16 +01:00
GOption: add strict posix mode
Add a "posixly correct" mode to GOption to stop parsing arguments as soon as the first non-option argument is encountered. We determine the default value on the basis of duplicating the behaviour of the system getopt() implementation (which we directly check the behaviour of at runtime). On GNU systems this allows the user to modify our behaviour using POSIXLY_CORRECT. The user can change the value by g_option_context_set_strict_posix(), which might be useful for some usecases of GOptionContext (as mentioned in the doc string of this new function). https://bugzilla.gnome.org/show_bug.cgi?id=723160
This commit is contained in:
parent
f2786908a8
commit
ae52ab3d11
@ -183,6 +183,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined __OpenBSD__
|
||||
#include <unistd.h>
|
||||
@ -248,6 +249,7 @@ struct _GOptionContext
|
||||
guint help_enabled : 1;
|
||||
guint ignore_unknown : 1;
|
||||
guint strv_mode : 1;
|
||||
guint strict_posix : 1;
|
||||
|
||||
GOptionGroup *main_group;
|
||||
|
||||
@ -358,6 +360,14 @@ g_option_context_new (const gchar *parameter_string)
|
||||
context = g_new0 (GOptionContext, 1);
|
||||
|
||||
context->parameter_string = g_strdup (parameter_string);
|
||||
{
|
||||
const char *argv[] = { "./a", "a", "-a", NULL };
|
||||
/* Check to see if getopt will parse the "-a" or not. If it finds
|
||||
* no arguments then we are in strict POSIX mode.
|
||||
*/
|
||||
optind = 1;
|
||||
context->strict_posix = getopt (3, (char **) argv, "a") != 'a';
|
||||
}
|
||||
context->help_enabled = TRUE;
|
||||
context->ignore_unknown = FALSE;
|
||||
|
||||
@ -483,6 +493,65 @@ g_option_context_get_ignore_unknown_options (GOptionContext *context)
|
||||
return context->ignore_unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_option_context_set_strict_posix:
|
||||
* @context: a #GoptionContext
|
||||
*
|
||||
* Sets strict POSIX mode.
|
||||
*
|
||||
* In strict POSIX mode, the first non-argument parameter encountered
|
||||
* (eg: filename) terminates argument processing. Remaining arguments
|
||||
* are treated as non-options and are not attempted to be parsed.
|
||||
*
|
||||
* If strict POSIX mode is disabled then parsing is done in the GNU way
|
||||
* where option arguments can be freely mixed with non-options.
|
||||
*
|
||||
* As an example, consider "ls foo -l". With GNU style parsing, this
|
||||
* will list "foo" in long mode. In strict POSIX style, this will list
|
||||
* the files named "foo" and "-l".
|
||||
*
|
||||
* The default is system-dependent. In particular, on some systems, it
|
||||
* may be modified by the POSIXLY_CORRECT environment variable.
|
||||
*
|
||||
* It may be useful to force strict POSIX mode when creating "verb
|
||||
* style" command line tools. For example, the "gsettings" command line
|
||||
* tool supports the global option "--schemadir" as well as many
|
||||
* subcommands ("get", "set", etc.) which each have their own set of
|
||||
* arguments. Using strict POSIX mode will allow parsing the global
|
||||
* options up to the verb name while leaving the remaining options to be
|
||||
* parsed by the relevant subcommand (which can be determined by
|
||||
* examining the verb name, which should be present in argv[1] after
|
||||
* parsing).
|
||||
*
|
||||
* Since: 2.44
|
||||
**/
|
||||
void
|
||||
g_option_context_set_strict_posix (GOptionContext *context,
|
||||
gboolean strict_posix)
|
||||
{
|
||||
g_return_if_fail (context != NULL);
|
||||
|
||||
context->strict_posix = strict_posix;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_option_context_get_strict_posix:
|
||||
* @context: a #GoptionContext
|
||||
*
|
||||
* Returns whether strict POSIX code is enabled.
|
||||
*
|
||||
* See g_option_context_set_strict_posix() for more information.
|
||||
*
|
||||
* Since: 2.44
|
||||
**/
|
||||
gboolean
|
||||
g_option_context_get_strict_posix (GOptionContext *context)
|
||||
{
|
||||
g_return_val_if_fail (context != NULL, FALSE);
|
||||
|
||||
return context->strict_posix;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_option_context_add_group:
|
||||
* @context: a #GOptionContext
|
||||
@ -2060,6 +2129,9 @@ g_option_context_parse (GOptionContext *context,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (context->strict_posix)
|
||||
stop_parsing = TRUE;
|
||||
|
||||
/* Collect remaining args */
|
||||
if (context->main_group &&
|
||||
!parse_remaining_arg (context, context->main_group, &i,
|
||||
|
@ -310,6 +310,12 @@ void g_option_context_set_ignore_unknown_options (GOptionContext *context,
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
gboolean g_option_context_get_ignore_unknown_options (GOptionContext *context);
|
||||
|
||||
GLIB_AVAILABLE_IN_2_44
|
||||
void g_option_context_set_strict_posix (GOptionContext *context,
|
||||
gboolean strict_posix);
|
||||
GLIB_AVAILABLE_IN_2_44
|
||||
gboolean g_option_context_get_strict_posix (GOptionContext *context);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_option_context_add_main_entries (GOptionContext *context,
|
||||
const GOptionEntry *entries,
|
||||
|
@ -2300,6 +2300,71 @@ test_group_parse (void)
|
||||
g_option_context_free (context);
|
||||
}
|
||||
|
||||
static gint
|
||||
option_context_parse_command_line (GOptionContext *context,
|
||||
const gchar *command_line)
|
||||
{
|
||||
gchar **argv;
|
||||
guint argv_len, argv_new_len;
|
||||
gboolean success;
|
||||
|
||||
argv = split_string (command_line, NULL);
|
||||
argv_len = g_strv_length (argv);
|
||||
|
||||
success = g_option_context_parse_strv (context, &argv, NULL);
|
||||
argv_new_len = g_strv_length (argv);
|
||||
|
||||
g_strfreev (argv);
|
||||
return success ? argv_len - argv_new_len : -1;
|
||||
}
|
||||
|
||||
static void
|
||||
test_strict_posix (void)
|
||||
{
|
||||
GOptionContext *context;
|
||||
gboolean foo;
|
||||
gboolean bar;
|
||||
GOptionEntry entries[] = {
|
||||
{ "foo", 'f', 0, G_OPTION_ARG_NONE, &foo, NULL, NULL },
|
||||
{ "bar", 'b', 0, G_OPTION_ARG_NONE, &bar, NULL, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
gint n_parsed;
|
||||
|
||||
context = g_option_context_new (NULL);
|
||||
g_option_context_add_main_entries (context, entries, NULL);
|
||||
|
||||
foo = bar = FALSE;
|
||||
g_option_context_set_strict_posix (context, FALSE);
|
||||
n_parsed = option_context_parse_command_line (context, "program --foo command --bar");
|
||||
g_assert_cmpint (n_parsed, ==, 2);
|
||||
g_assert (foo == TRUE);
|
||||
g_assert (bar == TRUE);
|
||||
|
||||
foo = bar = FALSE;
|
||||
g_option_context_set_strict_posix (context, TRUE);
|
||||
n_parsed = option_context_parse_command_line (context, "program --foo command --bar");
|
||||
g_assert_cmpint (n_parsed, ==, 1);
|
||||
g_assert (foo == TRUE);
|
||||
g_assert (bar == FALSE);
|
||||
|
||||
foo = bar = FALSE;
|
||||
g_option_context_set_strict_posix (context, TRUE);
|
||||
n_parsed = option_context_parse_command_line (context, "program --foo --bar command");
|
||||
g_assert_cmpint (n_parsed, ==, 2);
|
||||
g_assert (foo == TRUE);
|
||||
g_assert (bar == TRUE);
|
||||
|
||||
foo = bar = FALSE;
|
||||
g_option_context_set_strict_posix (context, TRUE);
|
||||
n_parsed = option_context_parse_command_line (context, "program command --foo --bar");
|
||||
g_assert_cmpint (n_parsed, ==, 0);
|
||||
g_assert (foo == FALSE);
|
||||
g_assert (bar == FALSE);
|
||||
|
||||
g_option_context_free (context);
|
||||
}
|
||||
|
||||
static void
|
||||
flag_reverse_string (void)
|
||||
{
|
||||
@ -2454,6 +2519,7 @@ main (int argc,
|
||||
g_test_add_func ("/option/group/main", test_main_group);
|
||||
g_test_add_func ("/option/group/error-hook", test_error_hook);
|
||||
g_test_add_func ("/option/group/parse", test_group_parse);
|
||||
g_test_add_func ("/option/strict-posix", test_strict_posix);
|
||||
|
||||
/* Test that restoration on failure works */
|
||||
g_test_add_func ("/option/restoration/int", error_test1);
|
||||
|
Loading…
Reference in New Issue
Block a user