mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-25 15:06:14 +01:00
Merge branch 'empty-argv' into 'main'
Various minor fixes for empty argv handling See merge request GNOME/glib!2466
This commit is contained in:
commit
cb18e6b969
@ -106,7 +106,7 @@
|
||||
* The complete example can be found here:
|
||||
* [gapplication-example-cmdline.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gapplication-example-cmdline.c)
|
||||
*
|
||||
* In more complicated cases, the handling of the comandline can be
|
||||
* In more complicated cases, the handling of the commandline can be
|
||||
* split between the launcher and the primary instance.
|
||||
* |[<!-- language="C" -->
|
||||
* static gboolean
|
||||
@ -119,6 +119,12 @@
|
||||
*
|
||||
* argv = *arguments;
|
||||
*
|
||||
* if (argv[0] == NULL)
|
||||
* {
|
||||
* *exit_status = 0;
|
||||
* return FALSE;
|
||||
* }
|
||||
*
|
||||
* i = 1;
|
||||
* while (argv[i])
|
||||
* {
|
||||
|
@ -107,7 +107,7 @@ usage (gint *argc, gchar **argv[], gboolean use_stdout)
|
||||
g_option_context_set_help_enabled (o, FALSE);
|
||||
/* Ignore parsing result */
|
||||
g_option_context_parse (o, argc, argv, NULL);
|
||||
program_name = g_path_get_basename ((*argv)[0]);
|
||||
program_name = (*argc > 0) ? g_path_get_basename ((*argv)[0]) : g_strdup ("gdbus-tool");
|
||||
s = g_strdup_printf (_("Commands:\n"
|
||||
" help Shows this information\n"
|
||||
" introspect Introspect a remote object\n"
|
||||
@ -141,6 +141,7 @@ modify_argv0_for_command (gint *argc, gchar **argv[], const gchar *command)
|
||||
* 2. save old argv[0] and restore later
|
||||
*/
|
||||
|
||||
g_assert (*argc > 1);
|
||||
g_assert (g_strcmp0 ((*argv)[1], command) == 0);
|
||||
remove_arg (1, argc, argv);
|
||||
|
||||
|
@ -1880,6 +1880,10 @@ g_desktop_app_info_load_from_keyfile (GDesktopAppInfo *info,
|
||||
else
|
||||
{
|
||||
char *t;
|
||||
|
||||
/* Since @exec is not an empty string, there must be at least one
|
||||
* argument, so dereferencing argv[0] should return non-NULL. */
|
||||
g_assert (argc > 0);
|
||||
t = g_find_program_in_path (argv[0]);
|
||||
g_strfreev (argv);
|
||||
|
||||
|
@ -161,7 +161,7 @@ main (gint argc,
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argc == 1)
|
||||
if (argc <= 1)
|
||||
{
|
||||
g_print ("Usage: gio-querymodules <directory1> [<directory2> ...]\n");
|
||||
g_print ("Will update giomodule.cache in the listed directories\n");
|
||||
|
@ -463,7 +463,8 @@ main (int argc,
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
g_warning ("Usage: %s filename prefix1 [prefix2 ...]", argv[0]);
|
||||
g_warning ("Usage: %s filename prefix1 [prefix2 ...]",
|
||||
(argc > 0) ? argv[0] : "gcompletion");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -646,6 +646,11 @@ tokenize_command_line (const gchar *command_line,
|
||||
*
|
||||
* Possible errors are those from the %G_SHELL_ERROR domain.
|
||||
*
|
||||
* In particular, if @command_line is an empty string (or a string containing
|
||||
* only whitespace), %G_SHELL_ERROR_EMPTY_STRING will be returned. It’s
|
||||
* guaranteed that @argvp will be a non-empty array if this function returns
|
||||
* successfully.
|
||||
*
|
||||
* Free the returned vector with g_strfreev().
|
||||
*
|
||||
* Returns: %TRUE on success, %FALSE if error set
|
||||
@ -702,7 +707,10 @@ g_shell_parse_argv (const gchar *command_line,
|
||||
}
|
||||
|
||||
g_slist_free_full (tokens, g_free);
|
||||
|
||||
|
||||
g_assert (argc > 0);
|
||||
g_assert (argv != NULL && argv[0] != NULL);
|
||||
|
||||
if (argcp)
|
||||
*argcp = argc;
|
||||
|
||||
|
@ -236,7 +236,7 @@ g_spawn_async (const gchar *working_directory,
|
||||
GPid *child_pid,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (argv != NULL, FALSE);
|
||||
g_return_val_if_fail (argv != NULL && argv[0] != NULL, FALSE);
|
||||
|
||||
return g_spawn_async_with_pipes (working_directory,
|
||||
argv, envp,
|
||||
@ -460,6 +460,8 @@ do_spawn_directly (gint *exit_status,
|
||||
gint conv_error_index;
|
||||
wchar_t *wargv0, **wargv, **wenvp;
|
||||
|
||||
g_assert (argv != NULL && argv[0] != NULL);
|
||||
|
||||
new_argv = (flags & G_SPAWN_FILE_AND_ARGV_ZERO) ? protected_argv + 1 : protected_argv;
|
||||
|
||||
wargv0 = g_utf8_to_utf16 (argv[0], -1, NULL, NULL, &conv_error);
|
||||
@ -601,6 +603,7 @@ fork_exec (gint *exit_status,
|
||||
int stdout_pipe[2] = { -1, -1 };
|
||||
int stderr_pipe[2] = { -1, -1 };
|
||||
|
||||
g_assert (argv != NULL && argv[0] != NULL);
|
||||
g_assert (stdin_pipe_out == NULL || stdin_fd < 0);
|
||||
g_assert (stdout_pipe_out == NULL || stdout_fd < 0);
|
||||
g_assert (stderr_pipe_out == NULL || stderr_fd < 0);
|
||||
@ -989,7 +992,7 @@ g_spawn_sync (const gchar *working_directory,
|
||||
gboolean failed;
|
||||
gint status;
|
||||
|
||||
g_return_val_if_fail (argv != NULL, FALSE);
|
||||
g_return_val_if_fail (argv != NULL && argv[0] != NULL, FALSE);
|
||||
g_return_val_if_fail (!(flags & G_SPAWN_DO_NOT_REAP_CHILD), FALSE);
|
||||
g_return_val_if_fail (standard_output == NULL ||
|
||||
!(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
|
||||
@ -1221,7 +1224,7 @@ g_spawn_async_with_pipes (const gchar *working_directory,
|
||||
gint *standard_error,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (argv != NULL, FALSE);
|
||||
g_return_val_if_fail (argv != NULL && argv[0] != NULL, FALSE);
|
||||
g_return_val_if_fail (standard_output == NULL ||
|
||||
!(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
|
||||
g_return_val_if_fail (standard_error == NULL ||
|
||||
@ -1263,7 +1266,7 @@ g_spawn_async_with_fds (const gchar *working_directory,
|
||||
gint stderr_fd,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (argv != NULL, FALSE);
|
||||
g_return_val_if_fail (argv != NULL && argv[0] != NULL, FALSE);
|
||||
g_return_val_if_fail (stdin_fd == -1 ||
|
||||
!(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
|
||||
g_return_val_if_fail (stderr_fd == -1 ||
|
||||
@ -1312,7 +1315,7 @@ g_spawn_async_with_pipes_and_fds (const gchar *working_directory,
|
||||
gint *stderr_pipe_out,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (argv != NULL, FALSE);
|
||||
g_return_val_if_fail (argv != NULL && argv[0] != NULL, FALSE);
|
||||
g_return_val_if_fail (stdout_pipe_out == NULL ||
|
||||
!(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
|
||||
g_return_val_if_fail (stderr_pipe_out == NULL ||
|
||||
@ -1359,6 +1362,7 @@ g_spawn_command_line_sync (const gchar *command_line,
|
||||
|
||||
g_return_val_if_fail (command_line != NULL, FALSE);
|
||||
|
||||
/* This will return a runtime error if @command_line is the empty string. */
|
||||
if (!g_shell_parse_argv (command_line,
|
||||
NULL, &argv,
|
||||
error))
|
||||
@ -1388,6 +1392,7 @@ g_spawn_command_line_async (const gchar *command_line,
|
||||
|
||||
g_return_val_if_fail (command_line != NULL, FALSE);
|
||||
|
||||
/* This will return a runtime error if @command_line is the empty string. */
|
||||
if (!g_shell_parse_argv (command_line,
|
||||
NULL, &argv,
|
||||
error))
|
||||
|
@ -319,7 +319,7 @@ read_data (GString *str,
|
||||
* @working_directory: (type filename) (nullable): child's current working
|
||||
* directory, or %NULL to inherit parent's
|
||||
* @argv: (array zero-terminated=1) (element-type filename):
|
||||
* child's argument vector
|
||||
* child's argument vector, which must be non-empty and %NULL-terminated
|
||||
* @envp: (array zero-terminated=1) (element-type filename) (nullable):
|
||||
* child's environment, or %NULL to inherit parent's
|
||||
* @flags: flags from #GSpawnFlags
|
||||
@ -378,6 +378,7 @@ g_spawn_sync (const gchar *working_directory,
|
||||
gint status;
|
||||
|
||||
g_return_val_if_fail (argv != NULL, FALSE);
|
||||
g_return_val_if_fail (argv[0] != NULL, FALSE);
|
||||
g_return_val_if_fail (!(flags & G_SPAWN_DO_NOT_REAP_CHILD), FALSE);
|
||||
g_return_val_if_fail (standard_output == NULL ||
|
||||
!(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
|
||||
@ -578,7 +579,7 @@ g_spawn_sync (const gchar *working_directory,
|
||||
* @working_directory: (type filename) (nullable): child's current working
|
||||
* directory, or %NULL to inherit parent's, in the GLib file name encoding
|
||||
* @argv: (array zero-terminated=1) (element-type filename): child's argument
|
||||
* vector, in the GLib file name encoding
|
||||
* vector, in the GLib file name encoding; it must be non-empty and %NULL-terminated
|
||||
* @envp: (array zero-terminated=1) (element-type filename) (nullable):
|
||||
* child's environment, or %NULL to inherit parent's, in the GLib file
|
||||
* name encoding
|
||||
@ -610,6 +611,7 @@ g_spawn_async_with_pipes (const gchar *working_directory,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (argv != NULL, FALSE);
|
||||
g_return_val_if_fail (argv[0] != NULL, FALSE);
|
||||
g_return_val_if_fail (standard_output == NULL ||
|
||||
!(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
|
||||
g_return_val_if_fail (standard_error == NULL ||
|
||||
@ -646,7 +648,7 @@ g_spawn_async_with_pipes (const gchar *working_directory,
|
||||
* @working_directory: (type filename) (nullable): child's current working
|
||||
* directory, or %NULL to inherit parent's, in the GLib file name encoding
|
||||
* @argv: (array zero-terminated=1) (element-type filename): child's argument
|
||||
* vector, in the GLib file name encoding
|
||||
* vector, in the GLib file name encoding; it must be non-empty and %NULL-terminated
|
||||
* @envp: (array zero-terminated=1) (element-type filename) (nullable):
|
||||
* child's environment, or %NULL to inherit parent's, in the GLib file
|
||||
* name encoding
|
||||
@ -880,6 +882,7 @@ g_spawn_async_with_pipes_and_fds (const gchar *working_directory,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (argv != NULL, FALSE);
|
||||
g_return_val_if_fail (argv[0] != NULL, FALSE);
|
||||
g_return_val_if_fail (stdout_pipe_out == NULL ||
|
||||
!(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
|
||||
g_return_val_if_fail (stderr_pipe_out == NULL ||
|
||||
@ -922,7 +925,8 @@ g_spawn_async_with_pipes_and_fds (const gchar *working_directory,
|
||||
/**
|
||||
* g_spawn_async_with_fds:
|
||||
* @working_directory: (type filename) (nullable): child's current working directory, or %NULL to inherit parent's, in the GLib file name encoding
|
||||
* @argv: (array zero-terminated=1): child's argument vector, in the GLib file name encoding
|
||||
* @argv: (array zero-terminated=1): child's argument vector, in the GLib file name encoding;
|
||||
* it must be non-empty and %NULL-terminated
|
||||
* @envp: (array zero-terminated=1) (nullable): child's environment, or %NULL to inherit parent's, in the GLib file name encoding
|
||||
* @flags: flags from #GSpawnFlags
|
||||
* @child_setup: (scope async) (nullable): function to run in the child just before exec()
|
||||
@ -956,6 +960,7 @@ g_spawn_async_with_fds (const gchar *working_directory,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (argv != NULL, FALSE);
|
||||
g_return_val_if_fail (argv[0] != NULL, FALSE);
|
||||
g_return_val_if_fail (stdout_fd < 0 ||
|
||||
!(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
|
||||
g_return_val_if_fail (stderr_fd < 0 ||
|
||||
@ -1039,6 +1044,7 @@ g_spawn_command_line_sync (const gchar *command_line,
|
||||
|
||||
g_return_val_if_fail (command_line != NULL, FALSE);
|
||||
|
||||
/* This will return a runtime error if @command_line is the empty string. */
|
||||
if (!g_shell_parse_argv (command_line,
|
||||
NULL, &argv,
|
||||
error))
|
||||
@ -1086,6 +1092,7 @@ g_spawn_command_line_async (const gchar *command_line,
|
||||
|
||||
g_return_val_if_fail (command_line != NULL, FALSE);
|
||||
|
||||
/* This will return a runtime error if @command_line is the empty string. */
|
||||
if (!g_shell_parse_argv (command_line,
|
||||
NULL, &argv,
|
||||
error))
|
||||
@ -1636,7 +1643,9 @@ enum
|
||||
};
|
||||
|
||||
/* This function is called between fork() and exec() and hence must be
|
||||
* async-signal-safe (see signal-safety(7)) until it calls exec(). */
|
||||
* async-signal-safe (see signal-safety(7)) until it calls exec().
|
||||
*
|
||||
* All callers must guarantee that @argv and @argv[0] are non-NULL. */
|
||||
static void
|
||||
do_exec (gint child_err_report_fd,
|
||||
gint stdin_fd,
|
||||
@ -1926,6 +1935,8 @@ do_posix_spawn (const gchar * const *argv,
|
||||
gsize i;
|
||||
int r;
|
||||
|
||||
g_assert (argv != NULL && argv[0] != NULL);
|
||||
|
||||
if (*argv[0] == '\0')
|
||||
{
|
||||
/* We check the simple case first. */
|
||||
@ -2176,6 +2187,7 @@ fork_exec (gboolean intermediate_child,
|
||||
gint n_child_close_fds = 0;
|
||||
gint *source_fds_copy = NULL;
|
||||
|
||||
g_assert (argv != NULL && argv[0] != NULL);
|
||||
g_assert (stdin_pipe_out == NULL || stdin_fd < 0);
|
||||
g_assert (stdout_pipe_out == NULL || stdout_fd < 0);
|
||||
g_assert (stderr_pipe_out == NULL || stderr_fd < 0);
|
||||
@ -2734,7 +2746,7 @@ g_execute (const gchar *file,
|
||||
gchar *search_path_buffer,
|
||||
gsize search_path_buffer_len)
|
||||
{
|
||||
if (*file == '\0')
|
||||
if (file == NULL || *file == '\0')
|
||||
{
|
||||
/* We check the simple case first. */
|
||||
errno = ENOENT;
|
||||
|
@ -668,8 +668,8 @@ parse_args (gint *argc_p,
|
||||
}
|
||||
}
|
||||
/* collapse argv */
|
||||
e = 1;
|
||||
for (i = 1; i < argc; i++)
|
||||
e = 0;
|
||||
for (i = 0; i < argc; i++)
|
||||
if (argv[i])
|
||||
{
|
||||
argv[e++] = argv[i];
|
||||
|
@ -890,7 +890,7 @@ static gboolean test_debug_log = FALSE;
|
||||
static gboolean test_tap_log = TRUE; /* default to TAP as of GLib 2.62; see #1619; the non-TAP output mode is deprecated */
|
||||
static gboolean test_nonfatal_assertions = FALSE;
|
||||
static DestroyEntry *test_destroy_queue = NULL;
|
||||
static const char *test_argv0 = NULL; /* points into global argv */
|
||||
static const char *test_argv0 = NULL; /* (nullable), points into global argv */
|
||||
static char *test_argv0_dirname = NULL; /* owned by GLib */
|
||||
static const char *test_disted_files_dir; /* points into test_argv0_dirname or an environment variable */
|
||||
static const char *test_built_files_dir; /* points into test_argv0_dirname or an environment variable */
|
||||
@ -1138,7 +1138,7 @@ parse_args (gint *argc_p,
|
||||
gchar **argv = *argv_p;
|
||||
guint i, e;
|
||||
|
||||
test_argv0 = argv[0];
|
||||
test_argv0 = argv[0]; /* will be NULL iff argc == 0 */
|
||||
test_initial_cwd = g_get_current_dir ();
|
||||
|
||||
/* parse known args */
|
||||
@ -1382,8 +1382,8 @@ parse_args (gint *argc_p,
|
||||
test_paths = g_slist_reverse (test_paths);
|
||||
|
||||
/* collapse argv */
|
||||
e = 1;
|
||||
for (i = 1; i < argc; i++)
|
||||
e = 0;
|
||||
for (i = 0; i < argc; i++)
|
||||
if (argv[i])
|
||||
{
|
||||
argv[e++] = argv[i];
|
||||
@ -1732,7 +1732,7 @@ void
|
||||
g_log_set_default_handler (gtest_default_log_handler, NULL);
|
||||
g_test_log (G_TEST_LOG_START_BINARY, g_get_prgname(), test_run_seedstr, 0, NULL);
|
||||
|
||||
test_argv0_dirname = g_path_get_dirname (test_argv0);
|
||||
test_argv0_dirname = (test_argv0 != NULL) ? g_path_get_dirname (test_argv0) : g_strdup (".");
|
||||
|
||||
/* Make sure we get the real dirname that the test was run from */
|
||||
if (g_str_has_suffix (test_argv0_dirname, "/.libs"))
|
||||
@ -3828,6 +3828,9 @@ g_test_trap_subprocess (const char *test_path,
|
||||
test_trap_clear ();
|
||||
test_trap_last_subprocess = g_strdup (test_path);
|
||||
|
||||
if (test_argv0 == NULL)
|
||||
g_error ("g_test_trap_subprocess() requires argv0 to be passed to g_test_init()");
|
||||
|
||||
argv = g_ptr_array_new ();
|
||||
g_ptr_array_add (argv, (char *) test_argv0);
|
||||
g_ptr_array_add (argv, "-q");
|
||||
|
@ -102,6 +102,24 @@ main (int argc,
|
||||
argc -= 1;
|
||||
argv[argc] = NULL;
|
||||
|
||||
if (g_strcmp0 (argv1, "init-null-argv0") == 0)
|
||||
{
|
||||
int test_argc = 0;
|
||||
char *test_argva[1] = { NULL };
|
||||
char **test_argv = test_argva;
|
||||
|
||||
/* Test that `g_test_init()` can handle being called with an empty argv
|
||||
* and argc == 0. While this isn’t recommended, it is possible for another
|
||||
* process to use execve() to call a gtest process this way, so we’d
|
||||
* better handle it gracefully.
|
||||
*
|
||||
* This test can’t be run after `g_test_init()` has been called normally,
|
||||
* as it isn’t allowed to be called more than once in a process. */
|
||||
g_test_init (&test_argc, &test_argv, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
g_test_set_nonfatal_assertions ();
|
||||
|
||||
|
@ -1585,6 +1585,40 @@ test_tap_summary (void)
|
||||
g_ptr_array_unref (argv);
|
||||
}
|
||||
|
||||
static void
|
||||
test_init_no_argv0 (void)
|
||||
{
|
||||
const char *testing_helper;
|
||||
GPtrArray *argv;
|
||||
GError *error = NULL;
|
||||
int status;
|
||||
gchar *output;
|
||||
|
||||
g_test_summary ("Test that g_test_init() can be called safely with argc == 0.");
|
||||
|
||||
testing_helper = g_test_get_filename (G_TEST_BUILT, "testing-helper" EXEEXT, NULL);
|
||||
|
||||
argv = g_ptr_array_new ();
|
||||
g_ptr_array_add (argv, (char *) testing_helper);
|
||||
g_ptr_array_add (argv, "init-null-argv0");
|
||||
g_ptr_array_add (argv, NULL);
|
||||
|
||||
/* This has to be spawned manually and can’t be run with g_test_subprocess()
|
||||
* because the test helper can’t be run after `g_test_init()` has been called
|
||||
* in the process. */
|
||||
g_spawn_sync (NULL, (char **) argv->pdata, NULL,
|
||||
G_SPAWN_STDERR_TO_DEV_NULL,
|
||||
NULL, NULL, &output, NULL, &status,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_spawn_check_wait_status (status, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_nonnull (strstr (output, "# random seed:"));
|
||||
g_free (output);
|
||||
g_ptr_array_unref (argv);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
@ -1682,6 +1716,8 @@ main (int argc,
|
||||
g_test_add_func ("/tap", test_tap);
|
||||
g_test_add_func ("/tap/summary", test_tap_summary);
|
||||
|
||||
g_test_add_func ("/init/no_argv0", test_init_no_argv0);
|
||||
|
||||
ret = g_test_run ();
|
||||
|
||||
/* We can't test for https://gitlab.gnome.org/GNOME/glib/-/issues/2563
|
||||
|
@ -2034,7 +2034,8 @@ main(int argc, char **argv)
|
||||
|
||||
if (fromcode == NULL || tocode == NULL)
|
||||
{
|
||||
printf("usage: %s [-c] -f from-enc -t to-enc [file]\n", argv[0]);
|
||||
printf("usage: %s [-c] -f from-enc -t to-enc [file]\n",
|
||||
(argc > 0) ? argv[0] : "win_iconv");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -196,7 +196,7 @@ main (gint argc,
|
||||
}
|
||||
|
||||
if (!gen_froots && !gen_tree)
|
||||
return help (argv[i-1]);
|
||||
return help ((argc > 0) ? argv[i-1] : NULL);
|
||||
|
||||
if (!indent_inc)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user