cmake_minimum_required(VERSION 3.20) if(NOT UPDATE_CLIENT_SCAN_ROOT) message(FATAL_ERROR "UPDATE_CLIENT_SCAN_ROOT is required.") endif() cmake_path( ABSOLUTE_PATH UPDATE_CLIENT_SCAN_ROOT NORMALIZE OUTPUT_VARIABLE _scan_root ) if(NOT IS_DIRECTORY "${_scan_root}") message(FATAL_ERROR "Production source scan root does not exist: ${_scan_root}") endif() file(GLOB_RECURSE _all_files LIST_DIRECTORIES FALSE "${_scan_root}/*") set(_production_files) foreach(_candidate IN LISTS _all_files) cmake_path(CONVERT "${_candidate}" TO_CMAKE_PATH_LIST _normalized_candidate NORMALIZE) cmake_path( RELATIVE_PATH _normalized_candidate BASE_DIRECTORY "${_scan_root}" OUTPUT_VARIABLE _relative_candidate ) string(TOLOWER "${_relative_candidate}" _candidate_lower) if(_candidate_lower MATCHES "(^|/)(translations|docs|out|build|generated|cmake-build[^/]*|\\.git)(/|$)") continue() endif() if(_candidate_lower STREQUAL "bootstrap/bootstrap.rc") continue() endif() cmake_path(GET _normalized_candidate FILENAME _file_name) cmake_path(GET _normalized_candidate EXTENSION _file_extension) string(TOLOWER "${_file_extension}" _file_extension) if(NOT _file_name STREQUAL "CMakeLists.txt" AND NOT _file_extension MATCHES "^\\.(c|cc|cpp|cxx|h|hh|hpp|cmake|ui|qrc|manifest|rc|json)$") continue() endif() list(APPEND _production_files "${_candidate}") endforeach() set(_han_utf8_regex "(e3:[9ab][0-9a-f]:[89ab][0-9a-f]:" "|e[4-9]:[89ab][0-9a-f]:[89ab][0-9a-f]:" "|ef:a[4-9ab]:[89ab][0-9a-f]:" "|f0:a[0-9a-f]:[89ab][0-9a-f]:[89ab][0-9a-f]:" "|f0:b[01]:[89ab][0-9a-f]:[89ab][0-9a-f]:)" ) string(JOIN "" _han_utf8_regex ${_han_utf8_regex}) set(_violations) foreach(_production_file IN LISTS _production_files) file(READ "${_production_file}" _file_hex HEX) string(TOLOWER "${_file_hex}" _file_hex) string(REGEX REPLACE "([0-9a-f][0-9a-f])" "\\1:" _file_bytes "${_file_hex}") if(_file_bytes MATCHES "${_han_utf8_regex}") cmake_path( RELATIVE_PATH _production_file BASE_DIRECTORY "${_scan_root}" OUTPUT_VARIABLE _relative_file ) list(APPEND _violations "${_relative_file}") endif() endforeach() if(_violations) list(JOIN _violations "\n " _violation_list) message(FATAL_ERROR "Han characters are forbidden in update-client production sources:\n" " ${_violation_list}\n" "Move user-visible text to the Qt translation catalog or the approved " "Bootstrap STRINGTABLE resource." ) endif() list(LENGTH _production_files _production_file_count) message(STATUS "No-Han production source check passed (${_production_file_count} files)." )