Как проверить, состоит ли строка исключительно из символов ASCII в CMake? - PullRequest
0 голосов
/ 11 января 2019

Мы используем CMake для компиляции нашей библиотеки программного обеспечения. Проблема в том, что несколько новых людей были приняты в команду, и они используют диакритические знаки в именах своих файлов / папок.

Такие символы, как á,ř,š,ě,ž, часто неправильно читаются генераторами CMake, и в результате сборка завершается с неясным поведением (создание новых папок с искаженными именами и т. Д.).


Мои вопросы

  1. Есть ли способ изменить поведение CMake для приема этих символов? Меня особенно интересует значение CMAKE_CURRENT_LIST_DIR.
  2. Если точка 1 невозможна, есть ли способ проверить строку, чтобы обнаружить эти символы, не входящие в ASCII, и впоследствии выдать сообщение об ошибке?

1 Ответ

0 голосов
/ 15 января 2019
  1. Не то чтобы я об этом знал, и я ничего не мог найти об этом.
  2. Да. Это не красиво, но в следующем примере проверяется входная строка на наличие недопустимых символов и возникает ошибка сборки, если она находит. В этом простом примере это позволяет A-Z, a-z, 0-9, '\', '/', '-', '_', ':' and ' ' (space).

Пошаговое описание этого конкретного решения может быть:

  • Установить допустимые специальные символы (это действительно должно быть указано пользователем через параметр)
  • Получить длину ввода и вычесть 1 (индекс с нуля)
  • итерируйте [i..length-of-string - 1] и получите соответствующий символ в этой позиции из _name
  • попробуйте сопоставить символ с A-Z или a-z, если найден, перейдите к следующему символу
  • попробуйте сопоставить символ с 0-9, если найден, перейдите к следующему символу
  • попробуйте сопоставить символ с любым из указанных специальных символов, если он найден, перейти к следующему символу
  • повысить ошибку сборки, поскольку текущий символ недопустим
#
# validate_name(<name>)
#   Checks if the specified string consists of legal ASCII characters.
#   If an illegal character is found, then a build error is produced.
#   Legal characters are: A-Z, a-z, 0-9 and '\', '/', '-', '_', ':' and ' '.
#
#   _name:    The string to examine
#
#   Example: validate_name("C:\\foo\\bar")
#            validate_name("/home/user/code/project")
#
function(validate_name _name)
    # For simplicity, set all valid special characters here.
    set(valid_specials "\\\\/-_: ")
    string(LENGTH "${_name}" name_length)
    math(EXPR name_length "${name_length}-1")
    foreach(i RANGE 0 ${name_length})
        # Get next character.
        string(SUBSTRING "${_name}" ${i} 1 current_char)
        # Convert said character to lowercase. This way we don't have to consider
        # A-Z explicitly.
        string(TOLOWER ${current_char} current_char)
        # Is it A-Z or a-z?
        if (NOT (("${current_char}" STRLESS "a") OR ("${current_char}" STRGREATER "z")))
            # It's A-Z or a-z.
            continue()
        endif()
        # Is it a number?
        if (NOT (("${current_char}" STRLESS "0") OR ("${current_char}" STRGREATER "9")))
            # It's a number.
            continue()
        endif()
        # Is it a valid "special" character?
        string(FIND "${valid_specials}" "${current_char}" valid_special_found)
        if (valid_special_found GREATER -1)
            continue()
        endif()
        message(FATAL_ERROR "'${current_char}' is not a legal character in this context.")
    endforeach()
endfunction()

Если вы хотите уменьшить размер кода, вы можете поместить все разрешенные символы в одну строку и использовать string(FIND ...), очень похоже на то, что делается со специальными символами. В любом случае производительность не будет иметь большого значения. Я сделал это так, чтобы вы знали о STRLESS и т. Д.

Наконец, в вашем случае вы бы назвали его с помощью: validate_name(${CMAKE_CURRENT_LIST_DIR})

Другое возможное решение - просто использовать регулярное выражение:

set(NAME "home/user/path")
string(REGEX MATCH "[A-Za-z0-9 \\\\/:_-]*" MATCH "${NAME}")
if (NOT "${MATCH}" STREQUAL "${NAME}")
    message(FATAL_ERROR "Illegal character(s) found.")
endif()

Будет получена другая строка, если найдены какие-либо символы, не определенные правилом. Если строка верна, то MATCH == NAME. Обратите внимание, что если первый символ недопустим, CMake выдаст свою ошибку. Я далеко не эксперт по регулярным выражениям, поэтому уверен, что есть более элегантное решение.

Во всяком случае, я думаю, что это должно как минимум начать. Дайте мне знать, если вам нужны дальнейшие разъяснения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...