diff options
-rw-r--r-- | mesonbuild/utils/universal.py | 39 | ||||
-rw-r--r-- | test cases/common/14 configure file/config6.h.in | 37 | ||||
-rw-r--r-- | test cases/common/14 configure file/meson.build | 2 | ||||
-rw-r--r-- | test cases/common/14 configure file/prog6.c | 12 |
4 files changed, 64 insertions, 26 deletions
diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py index c831169..6aee268 100644 --- a/mesonbuild/utils/universal.py +++ b/mesonbuild/utils/universal.py @@ -1182,24 +1182,21 @@ def do_replacement(regex: T.Pattern[str], line: str, variable_format: Literal['meson', 'cmake', 'cmake@'], confdata: T.Union[T.Dict[str, T.Tuple[str, T.Optional[str]]], 'ConfigurationData']) -> T.Tuple[str, T.Set[str]]: missing_variables: T.Set[str] = set() - if variable_format == 'cmake': - start_tag = '${' - backslash_tag = '\\${' - else: - start_tag = '@' - backslash_tag = '\\@' def variable_replace(match: T.Match[str]) -> str: - # Pairs of escape characters before '@' or '\@' + # Pairs of escape characters before '@', '\@', '${' or '\${' if match.group(0).endswith('\\'): num_escapes = match.end(0) - match.start(0) return '\\' * (num_escapes // 2) - # Single escape character and '@' - elif match.group(0) == backslash_tag: - return start_tag - # Template variable to be replaced + # Handle cmake escaped \${} tags + elif variable_format == 'cmake' and match.group(0) == '\\${': + return '${' + # \@escaped\@ variables + elif match.groupdict().get('escaped') is not None: + return match.group('escaped')[1:-2]+'@' else: - varname = match.group(1) + # Template variable to be replaced + varname = match.group('variable') var_str = '' if varname in confdata: var, _ = confdata.get(varname) @@ -1280,11 +1277,23 @@ def do_define(regex: T.Pattern[str], line: str, confdata: 'ConfigurationData', def get_variable_regex(variable_format: Literal['meson', 'cmake', 'cmake@'] = 'meson') -> T.Pattern[str]: # Only allow (a-z, A-Z, 0-9, _, -) as valid characters for a define - # Also allow escaping '@' with '\@' if variable_format in {'meson', 'cmake@'}: - regex = re.compile(r'(?:\\\\)+(?=\\?@)|\\@|@([-a-zA-Z0-9_]+)@') + # Also allow escaping pairs of '@' with '\@' + regex = re.compile(r''' + (?:\\\\)+(?=\\?@) # Matches multiple backslashes followed by an @ symbol + | # OR + (?<!\\)@(?P<variable>[-a-zA-Z0-9_]+)@ # Match a variable enclosed in @ symbols and capture the variable name; no matches beginning with '\@' + | # OR + (?P<escaped>\\@[-a-zA-Z0-9_]+\\@) # Match an escaped variable enclosed in @ symbols + ''', re.VERBOSE) else: - regex = re.compile(r'(?:\\\\)+(?=\\?\$)|\\\${|\${([-a-zA-Z0-9_]+)}') + regex = re.compile(r''' + (?:\\\\)+(?=\\?\$) # Match multiple backslashes followed by a dollar sign + | # OR + \\\${ # Match a backslash followed by a dollar sign and an opening curly brace + | # OR + \${(?P<variable>[-a-zA-Z0-9_]+)} # Match a variable enclosed in curly braces and capture the variable name + ''', re.VERBOSE) return regex def do_conf_str(src: str, data: T.List[str], confdata: 'ConfigurationData', diff --git a/test cases/common/14 configure file/config6.h.in b/test cases/common/14 configure file/config6.h.in index 9719f87..0a91542 100644 --- a/test cases/common/14 configure file/config6.h.in +++ b/test cases/common/14 configure file/config6.h.in @@ -1,19 +1,40 @@ /* No escape */ #define MESSAGE1 "@var1@" -/* Single escape means no replace */ -#define MESSAGE2 "\@var1@" +/* Escaped whole variable */ +#define MESSAGE2 "\\@var1\\@" /* Replace pairs of escapes before '@' or '\@' with escape characters * (note we have to double number of pairs due to C string escaping) */ #define MESSAGE3 "\\\\@var1@" -/* Pairs of escapes and then single escape to avoid replace */ -#define MESSAGE4 "\\\\\@var1@" +/* Pairs of escapes and then an escaped variable */ +#define MESSAGE4 "\\\\\@var1\@" -/* Check escaped variable does not overlap following variable */ -#define MESSAGE5 "\@var1@var2@" +/* We don't gobble \@ prefixing some text */ +#define MESSAGE5 "\\\\@var1" -/* Check escape character outside variables */ -#define MESSAGE6 "\\ @ \@ \\\\@ \\\\\@" +/* Check escape character outside variables + \ @ \@ */ +#define MESSAGE6 "\\ @ \\\\@" + +/* Catch any edge cases */ + +/* no substitution - not a variable */ +#define MESSAGE7 "@var1" + +/* Escaped variable followed by another variable */ +#define MESSAGE8 "\\\\@var1@var2@" + +/* Variable followed by another variable */ +#define MESSAGE9 "@var1@var2@" + +/* Variable followed by another variable and escaped */ +#define MESSAGE10 "@var1@var2\\\\@" + +/* Lots of substitutions in a row*/ +#define MESSAGE11 "@var1@@var2@@var3@@var4@" + +/* This should never happen in the real world, right? */ +#define MESSAGE12 "@var1@var2\\\\@var3@var4\\\\@" diff --git a/test cases/common/14 configure file/meson.build b/test cases/common/14 configure file/meson.build index 90a468f..8e7d429 100644 --- a/test cases/common/14 configure file/meson.build +++ b/test cases/common/14 configure file/meson.build @@ -143,6 +143,8 @@ test('test5', executable('prog5', 'prog5.c')) conf6 = configuration_data() conf6.set('var1', 'foo') conf6.set('var2', 'bar') +conf6.set('var3', 'baz') +conf6.set('var4', 'qux') configure_file( input : 'config6.h.in', output : '@BASENAME@', diff --git a/test cases/common/14 configure file/prog6.c b/test cases/common/14 configure file/prog6.c index 57f5586..b39f9da 100644 --- a/test cases/common/14 configure file/prog6.c +++ b/test cases/common/14 configure file/prog6.c @@ -4,8 +4,14 @@ int main(void) { return strcmp(MESSAGE1, "foo") || strcmp(MESSAGE2, "@var1@") - || strcmp(MESSAGE3, "\\foo") + || strcmp(MESSAGE3, "\\@var1@") || strcmp(MESSAGE4, "\\@var1@") - || strcmp(MESSAGE5, "@var1bar") - || strcmp(MESSAGE6, "\\ @ @ \\@ \\@"); + || strcmp(MESSAGE5, "\\@var1") + || strcmp(MESSAGE6, "\\ @ \\@") + || strcmp(MESSAGE7, "@var1") + || strcmp(MESSAGE8, "\\@var1bar") + || strcmp(MESSAGE9, "foovar2@") + || strcmp(MESSAGE10, "foovar2\\@") + || strcmp(MESSAGE11, "foobarbazqux") + || strcmp(MESSAGE12, "foovar2\\@var3@var4\\@"); } |