Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mac, Linux, only editor build: OS.get_cmdline_args splits quoted strings with spaces #72935

Closed
Qubus0 opened this issue Feb 9, 2023 · 4 comments · Fixed by #75444
Closed

Comments

@Qubus0
Copy link

Qubus0 commented Feb 9, 2023

Godot version

3.5.stable, 4 rc1

System information

MacOS 12.6.1, Linux not sure which

Issue description

Command line args set in ProjectSettings editor/main_run_args are split at spaces, even if they are quoted.
This only occurs if started from the editor and only on Mac and Linux.

The only difference in 4 is that the main scene is also a command line arg (res://Main.tscn) for some reason.. That might be another bug

Here is a workaround to splice the args back together.

# Reverses a bug in Godot, which splits input strings at spaces even if they are quoted
# e.g. --arg="some value" becomes [ --arg="some, value" ]
# this only occurs with args in that format. --arg "some value" is safe
static func fix_godot_cmdline_args_string_space_splitting(args: PoolStringArray) -> PoolStringArray:
	if not OS.has_feature("editor"): # only happens in editor builds
		return args
	if OS.has_feature("Windows"): # windows is unaffected
		return args

	var fixed_args := PoolStringArray([])
	var fixed_arg := ""
	# if we encounter an argument that contains [code]=[/code] followed by a quote,
	# or an argument that starts with a quote, take all following args and
	# concatenate them into one, until we find the closing quote
	for arg in args:
		var arg_string := arg as String
		if '="' in arg_string or '="' in fixed_arg or \
				arg_string.begins_with('"') or fixed_arg.begins_with('"'):
			if not fixed_arg == "":
				fixed_arg += " "
			fixed_arg += arg_string
			if arg_string.ends_with('"'):
				fixed_args.append(fixed_arg.trim_prefix(" "))
				fixed_arg = ""
				continue
		# same thing for single quotes
		elif "='" in arg_string or "='" in fixed_arg \
				or arg_string.begins_with("'") or fixed_arg.begins_with("'"):
			if not fixed_arg == "":
				fixed_arg += " "
			fixed_arg += arg_string
			if arg_string.ends_with("'"):
				fixed_args.append(fixed_arg.trim_prefix(" "))
				fixed_arg = ""
				continue

		else:
			fixed_args.append(arg_string)

	return fixed_args

Steps to reproduce

Set some args with spaces in ProjectSettings editor/main_run_args.
E.g. --arg="string with spaces" --second-arg 'with spaces'

print them out

func _ready() -> void:
	print(OS.get_cmdline_args())
	for arg in OS.get_cmdline_args():
		printt("single arg:", arg)

	print("---")
	var fixed_args := fix_godot_cmdline_args_string_space_splitting(OS.get_cmdline_args())
	print(fixed_args)
	for arg in fixed_args:
		printt("fixed arg:", arg)

result

[--arg="string, with, spaces", --second-arg, 'with, spaces']
single arg:	--arg="string
single arg:	with
single arg:	spaces"
single arg:	--second-arg
single arg:	'with
single arg:	spaces'
---
[--arg="string with spaces", --second-arg, 'with spaces']
fixed arg:	--arg="string with spaces"
fixed arg:	--second-arg
fixed arg:	'with spaces'

Minimal reproduction project

Works in 3.5 and 4rc1 (the run args just have to be set again after conversion)
CmdLineArgSplitReproduction.zip

@Calinou
Copy link
Member

Calinou commented Feb 9, 2023

This only occurs if started from the editor

This is because Main Run Args is only applied when running the project from the editor.

We could have a separate project setting for command line arguments to pass even to an exported project (or if running the project directly from the command line in general), but that's proposal territory.

@Qubus0
Copy link
Author

Qubus0 commented Feb 9, 2023

Yep, the error lies in taking the project settings in and passing the arguments to the game, not in how they are handled from the command line.

@Calinou
Copy link
Member

Calinou commented Jun 20, 2023

I can confirm this on 4.1.beta 33957ae (Linux).

["res://Main.tscn", "-arg=\"string", "with", "spaces\"", "--second-arg", "\'with", "spaces\'"]
single arg:	res://Main.tscn
single arg:	-arg="string
single arg:	with
single arg:	spaces"
single arg:	--second-arg
single arg:	'with
single arg:	spaces'
---
["res://Main.tscn", "-arg=\"string with spaces\"", "--second-arg", "\'with spaces\'"]
fixed arg:	res://Main.tscn
fixed arg:	-arg="string with spaces"
fixed arg:	--second-arg
fixed arg:	'with spaces'

@geekley
Copy link

geekley commented Dec 21, 2023

If you happen to follow my proposal in the referencing issue above to convert that args setting to a string array, maybe it makes sense here too (and any other similar args settings everywhere). It's what e.g. VSCode's tasks.json does - it's simpler=safer to handle without mistakes, and clearer to the user too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants