// Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2019 Alexey Edelev // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "options.h" #include "utils.h" #include #include using namespace ::qtprotoccommon; static const char QmlPluginOption[] = "QML"; static const char CommentsGenerationOption[] = "COPY_COMMENTS"; static const char FolderGenerationOption[] = "GENERATE_PACKAGE_SUBFOLDERS"; static const char FieldEnumGenerationOption[] = "FIELD_ENUM"; static const char ExtraNamespaceGenerationOption[] = "EXTRA_NAMESPACE"; static const char ExportMacroGenerationOption[] = "EXPORT_MACRO"; static const char HeaderGuardOption[] = "HEADER_GUARD"; static const char MutableGetterConflicts[] = "ALLOW_MUTABLE_GETTER_CONFLICTS"; static const char ExportSuffix[] = "_exports.qpb.h"; static constexpr std::string_view HeaderGuardPragma = "pragma"; static constexpr std::string_view HeaderGuardProtoFilename = "filename"; Options::Options() : m_generateComments(false), m_isFolder(false), m_generateFieldEnum(true), m_generateMacroExportFile(false), m_qml(false), m_mutableGetterConflicts(false) { } Options::~Options() = default; Options &Options::mutableInstance() { static Options _instance; return _instance; } const Options &Options::instance() { return mutableInstance(); } std::string extractCompositeOptionValue(const std::string &option) { std::vector compositeOption = utils::split(option, "="); if (compositeOption.size() != 2) return {}; const std::string &optionValue = compositeOption.back(); if (utils::startsWith(optionValue, '\"') && utils::endsWith(optionValue, '\"')) { return optionValue.substr(1, optionValue.size() - 2); } return optionValue; } void Options::setFromString(const std::string &options, GeneratorType /*unused*/, std::string *error) { Options &instance = mutableInstance(); for (const auto &option : utils::split(options, ";")) { QT_PROTOBUF_DEBUG("option: " << option); if (option == CommentsGenerationOption) { QT_PROTOBUF_DEBUG("set m_generateComments: true"); instance.m_generateComments = true; } else if (option == FolderGenerationOption) { QT_PROTOBUF_DEBUG("set m_isFolder: true"); instance.m_isFolder = true; } else if (option == FieldEnumGenerationOption) { // TODO: Opt in this option by default since it's required for // Oneof fields. // QT_PROTOBUF_DEBUG("set m_generateFieldEnum: true"); // instance.m_generateFieldEnum = true; } else if (option.find(ExtraNamespaceGenerationOption) == 0) { instance.m_extraNamespace = extractCompositeOptionValue(option); QT_PROTOBUF_DEBUG("set m_extraNamespace: " << instance.m_extraNamespace); } else if (option.find(ExportMacroGenerationOption) == 0) { auto export_macro_values = utils::split(extractCompositeOptionValue(option), ":"); if (!export_macro_values.empty()) { static const std::regex valid_c_identifier("[a-zA-Z_][0-9a-zA-Z_]*"); if (!std::regex_match(export_macro_values[0], valid_c_identifier)) { *error = "EXPORT_MACRO '" + export_macro_values[0] + "' is not a valid C identifier."; return; } instance.m_exportMacro = export_macro_values[0]; QT_PROTOBUF_DEBUG("set m_exportMacro: " << instance.m_exportMacro); if (export_macro_values.size() > 1) { instance.m_exportMacroFilename = export_macro_values[1]; QT_PROTOBUF_DEBUG("set m_exportMacroFilename: " << instance.m_exportMacroFilename); if (export_macro_values.size() > 2) { instance.m_generateMacroExportFile = export_macro_values[2] == "true"; QT_PROTOBUF_DEBUG("set m_generateMacroExportFile: " << instance.m_generateMacroExportFile); } } if (instance.m_exportMacroFilename.empty()) { std::string exportMacroLower = instance.m_exportMacro; utils::asciiToLower(exportMacroLower); instance.m_exportMacroFilename = exportMacroLower + ExportSuffix; QT_PROTOBUF_DEBUG("set m_exportMacroFilename: " << instance.m_exportMacroFilename); } } } else if (option == QmlPluginOption) { instance.m_qml = true; QT_PROTOBUF_DEBUG("set m_qml: true"); } else if (option.find(HeaderGuardOption) == 0) { const auto headerGuardValue = extractCompositeOptionValue(option); if (headerGuardValue == HeaderGuardPragma) { instance.m_headerGuard = Options::HeaderGuardType::Pragma; } else if (headerGuardValue != HeaderGuardProtoFilename) { QT_PROTOBUF_DEBUG("Unknown HEADER_GUARD option value"); } } else if (option == MutableGetterConflicts) { instance.m_mutableGetterConflicts = true; } } }