cmake: escape json input string

Escape the json input string given to `to_yaml()` function and the
content given to `yaml_set()` function.

This ensures that a string like `foo\bar` becomes `foo\\bar` during
internal CMake json processing and when written to the file it becomes
`foo\bar`.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
This commit is contained in:
Torsten Rasmussen 2025-02-19 12:07:34 +01:00 committed by Fabio Baltieri
commit cdbe424eca
2 changed files with 26 additions and 4 deletions

View file

@ -3037,6 +3037,16 @@ endfunction()
# This function extends the CMake string function by providing additional
# manipulation arguments to CMake string.
#
# ESCAPE: Ensure that any single '\' in the input string is escaped with the
# escape char '\'. For example the string 'foo\bar' will be escaped
# so that it becomes 'foo\\bar'.
# Backslashes which are already escaped will not be escaped further,
# for example 'foo\\bar' will not be modified.
# This is useful for handling of windows path separator in strings or
# when strings contains newline escapes such as '\n' and this can
# cause issues when writing to a file where a '\n' is desired in the
# string instead of a newline.
#
# SANITIZE: Ensure that the output string does not contain any special
# characters. Special characters, such as -, +, =, $, etc. are
# converted to underscores '_'.
@ -3048,9 +3058,11 @@ endfunction()
#
# returns the updated string
function(zephyr_string)
set(options SANITIZE TOUPPER)
set(options SANITIZE TOUPPER ESCAPE)
cmake_parse_arguments(ZEPHYR_STRING "${options}" "" "" ${ARGN})
zephyr_check_flags_exclusive(${CMAKE_CURRENT_FUNCTION} ZEPHYR_STRING SANITIZE ESCAPE)
if (NOT ZEPHYR_STRING_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Function zephyr_string() called without a return variable")
endif()
@ -3068,6 +3080,13 @@ function(zephyr_string)
string(TOUPPER ${work_string} work_string)
endif()
if(ZEPHYR_STRING_ESCAPE)
# If a single '\' is discovered, such as 'foo\bar', then it must be escaped like: 'foo\\bar'
# \\1 and \\2 are keeping the match patterns, the \\\\ --> \\ meaning an escaped '\',
# which then becomes a single '\' in the final string.
string(REGEX REPLACE "([^\\][\\])([^\\])" "\\1\\\\\\2" work_string "${ZEPHYR_STRING_UNPARSED_ARGUMENTS}")
endif()
set(${return_arg} ${work_string} PARENT_SCOPE)
endfunction()

View file

@ -422,9 +422,11 @@ function(yaml_set)
internal_yaml_list_initializer(json_string ${genex})
string(JSON json_content SET "${json_content}" ${ARG_YAML_KEY} "${json_string}")
endif()
internal_yaml_list_append(json_content ${genex} "${ARG_YAML_KEY}" ${ARG_YAML_LIST})
zephyr_string(ESCAPE escape_list "${ARG_YAML_LIST}")
internal_yaml_list_append(json_content ${genex} "${ARG_YAML_KEY}" ${escape_list})
else()
string(JSON json_content SET "${json_content}" ${ARG_YAML_KEY} "\"${ARG_YAML_VALUE}\"")
zephyr_string(ESCAPE escape_value "${ARG_YAML_VALUE}")
string(JSON json_content SET "${json_content}" ${ARG_YAML_KEY} "\"${escape_value}\"")
endif()
zephyr_set(JSON "${json_content}" SCOPE ${ARG_YAML_NAME})
@ -539,7 +541,8 @@ function(yaml_save)
endif()
endfunction()
function(to_yaml json level yaml genex)
function(to_yaml in_json level yaml genex)
zephyr_string(ESCAPE json "${in_json}")
if(level GREATER 0)
math(EXPR level_dec "${level} - 1")
set(indent_${level} "${indent_${level_dec}} ")