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

Add str.to_quoted #10417

Open
emersion opened this issue May 23, 2022 · 9 comments
Open

Add str.to_quoted #10417

emersion opened this issue May 23, 2022 · 9 comments

Comments

@emersion
Copy link
Contributor

Allow adding quotes to a string with a new str.to_quoted method. This would be useful for things like:

cargs = ['-DMY_VAR=@0@'.format(arbitrary_string.to_quoted())]

which would behave properly even if arbitrary_string contains a " or a \.

@xclaesse
Copy link
Member

xclaesse commented May 23, 2022

It would do python's shlex.quote() basically, right? aka shell escaping,

@xclaesse
Copy link
Member

AFAIK, Meson will already shell quote every args it pass to the compiler for you. Have you tried and it does not work?

@emersion
Copy link
Contributor Author

It would do python's shlex.quote() basically, right? aka shell escaping,

Yeah. Same as cfg_data.set_quoted().

AFAIK, Meson will already shell quote every args it pass to the compiler for you. Have you tried and it does not work?

Nah, this won't work, the value needs to be quoted as well for the C parser to recognize it as a C string and not another kind of literal. Example:

project('test', 'c')

myvar = 'a b " c'
add_project_arguments('-DMYVAR=' + myvar, language: 'c')

executable('main', 'main.c')
#include <stdio.h>

int main(void) {
	printf("MYVAR = %s\n", MYVAR);
}

@eli-schwartz
Copy link
Member

Yeah. Same as cfg_data.set_quoted().

Configuration data uses C-style escaping, and the specific implementation details are:

  • replace all double-quote chars with a backslash-escaped one
  • double-quote the string

This is not what shlex does at all, because shells use different rules that need to account for pretty different things. Particularly worth noting is that shlex will not quote at all, if it is given a string that doesn't have any whitespace/quoting/shell special characters, e.g.

shlex.quote('foo') # -> foo
confdata.set_quoted('foo') # -> "foo"

@jpakkane
Copy link
Member

As a general guide, try to avoid passing things via command line arguments. They are a constant source of trouble even when things are working. It is a lot easier to use a configuration header instead. Just the fact that you can debug its contents without needing to manually unwrap several layers of different quotings makes things so much simpler.

@emersion
Copy link
Contributor Author

I would tend to agree, at least when -Wundef is enabled and #ifdef is not used (otherwise it's too easy to forget to include the config header). But note that there aren't more quoting levels when using CLI args. There is one level of quoting (for C strings) for each element in the argv array. Maybe ninja adds an additional level of quoting in its -v pretty-printing.

@xclaesse
Copy link
Member

Ok, so here we talk about C string level quoting, not shlex, wasn't sure. Makes much more sense.

@eli-schwartz
Copy link
Member

There is one level of quoting (for C strings) for each element in the argv array. Maybe ninja adds an additional level of quoting in its -v pretty-printing.

ninja runs in a shell, and meson writes out shell-escaped command lines. So there are two levels of quoting:

  • the double quotes in the macro definition
  • a pair of single quotes around the argv element

Plus whatever any unusual individual chooses to add in the string, because someone out there is totally going to do

'ab$\'c d"""!e'.to_quoted()

And expect it to work. They're also probably going to expect it to work regardless of whether it's being stuck in a c_args or formatted into run_command('sh', '-c', 'some complicated command'), because people do in fact actually do this and it's pain.

Spoiler: it won't work for both. :(

@emersion
Copy link
Contributor Author

Oh. I didn't know ninja was dealing with sh. That's unfortunate.

Indeed, shell quoting doesn't work like C quoting. Would a function named to_c_quoted() to to_quoted(language: 'c') be any better?

Or something like add_project_define('MYVAR', value) which automatically escapes if the value is a string?

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

No branches or pull requests

4 participants