| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| #include "cmQtAutoGen.h" |
| #include "cmAlgorithms.h" |
| #include "cmSystemTools.h" |
| |
| #include "cmsys/RegularExpression.hxx" |
| |
| #include <algorithm> |
| #include <iterator> |
| #include <sstream> |
| |
| // - Static variables |
| |
| std::string const genNameGen = "AutoGen"; |
| std::string const genNameMoc = "AutoMoc"; |
| std::string const genNameUic = "AutoUic"; |
| std::string const genNameRcc = "AutoRcc"; |
| |
| // - Static functions |
| |
| /// @brief Merges newOpts into baseOpts |
| /// @arg valueOpts list of options that accept a value |
| void MergeOptions(std::vector<std::string>& baseOpts, |
| std::vector<std::string> const& newOpts, |
| std::vector<std::string> const& valueOpts, bool isQt5) |
| { |
| typedef std::vector<std::string>::iterator Iter; |
| typedef std::vector<std::string>::const_iterator CIter; |
| if (newOpts.empty()) { |
| return; |
| } |
| if (baseOpts.empty()) { |
| baseOpts = newOpts; |
| return; |
| } |
| |
| std::vector<std::string> extraOpts; |
| for (CIter fit = newOpts.begin(), fitEnd = newOpts.end(); fit != fitEnd; |
| ++fit) { |
| std::string const& newOpt = *fit; |
| Iter existIt = std::find(baseOpts.begin(), baseOpts.end(), newOpt); |
| if (existIt != baseOpts.end()) { |
| if (newOpt.size() >= 2) { |
| // Acquire the option name |
| std::string optName; |
| { |
| auto oit = newOpt.begin(); |
| if (*oit == '-') { |
| ++oit; |
| if (isQt5 && (*oit == '-')) { |
| ++oit; |
| } |
| optName.assign(oit, newOpt.end()); |
| } |
| } |
| // Test if this is a value option and change the existing value |
| if (!optName.empty() && (std::find(valueOpts.begin(), valueOpts.end(), |
| optName) != valueOpts.end())) { |
| const Iter existItNext(existIt + 1); |
| const CIter fitNext(fit + 1); |
| if ((existItNext != baseOpts.end()) && (fitNext != fitEnd)) { |
| *existItNext = *fitNext; |
| ++fit; |
| } |
| } |
| } |
| } else { |
| extraOpts.push_back(newOpt); |
| } |
| } |
| // Append options |
| baseOpts.insert(baseOpts.end(), extraOpts.begin(), extraOpts.end()); |
| } |
| |
| // - Class definitions |
| |
| std::string const cmQtAutoGen::ListSep = "<<<S>>>"; |
| unsigned int const cmQtAutoGen::ParallelMax = 64; |
| |
| std::string const& cmQtAutoGen::GeneratorName(GeneratorT type) |
| { |
| switch (type) { |
| case GeneratorT::GEN: |
| return genNameGen; |
| case GeneratorT::MOC: |
| return genNameMoc; |
| case GeneratorT::UIC: |
| return genNameUic; |
| case GeneratorT::RCC: |
| return genNameRcc; |
| } |
| return genNameGen; |
| } |
| |
| std::string cmQtAutoGen::GeneratorNameUpper(GeneratorT genType) |
| { |
| return cmSystemTools::UpperCase(cmQtAutoGen::GeneratorName(genType)); |
| } |
| |
| std::string cmQtAutoGen::Quoted(std::string const& text) |
| { |
| static const char* rep[18] = { "\\", "\\\\", "\"", "\\\"", "\a", "\\a", |
| "\b", "\\b", "\f", "\\f", "\n", "\\n", |
| "\r", "\\r", "\t", "\\t", "\v", "\\v" }; |
| |
| std::string res = text; |
| for (const char* const* it = cm::cbegin(rep); it != cm::cend(rep); it += 2) { |
| cmSystemTools::ReplaceString(res, *it, *(it + 1)); |
| } |
| res = '"' + res; |
| res += '"'; |
| return res; |
| } |
| |
| std::string cmQtAutoGen::QuotedCommand(std::vector<std::string> const& command) |
| { |
| std::string res; |
| for (std::string const& item : command) { |
| if (!res.empty()) { |
| res.push_back(' '); |
| } |
| std::string const cesc = cmQtAutoGen::Quoted(item); |
| if (item.empty() || (cesc.size() > (item.size() + 2)) || |
| (cesc.find(' ') != std::string::npos)) { |
| res += cesc; |
| } else { |
| res += item; |
| } |
| } |
| return res; |
| } |
| |
| std::string cmQtAutoGen::SubDirPrefix(std::string const& filename) |
| { |
| std::string res(cmSystemTools::GetFilenamePath(filename)); |
| if (!res.empty()) { |
| res += '/'; |
| } |
| return res; |
| } |
| |
| std::string cmQtAutoGen::AppendFilenameSuffix(std::string const& filename, |
| std::string const& suffix) |
| { |
| std::string res; |
| auto pos = filename.rfind('.'); |
| if (pos != std::string::npos) { |
| const auto it_dot = filename.begin() + pos; |
| res.assign(filename.begin(), it_dot); |
| res.append(suffix); |
| res.append(it_dot, filename.end()); |
| } else { |
| res = filename; |
| res.append(suffix); |
| } |
| return res; |
| } |
| |
| void cmQtAutoGen::UicMergeOptions(std::vector<std::string>& baseOpts, |
| std::vector<std::string> const& newOpts, |
| bool isQt5) |
| { |
| static std::vector<std::string> const valueOpts = { |
| "tr", "translate", "postfix", "generator", |
| "include", // Since Qt 5.3 |
| "g" |
| }; |
| MergeOptions(baseOpts, newOpts, valueOpts, isQt5); |
| } |
| |
| void cmQtAutoGen::RccMergeOptions(std::vector<std::string>& baseOpts, |
| std::vector<std::string> const& newOpts, |
| bool isQt5) |
| { |
| static std::vector<std::string> const valueOpts = { "name", "root", |
| "compress", |
| "threshold" }; |
| MergeOptions(baseOpts, newOpts, valueOpts, isQt5); |
| } |
| |
| void cmQtAutoGen::RccListParseContent(std::string const& content, |
| std::vector<std::string>& files) |
| { |
| cmsys::RegularExpression fileMatchRegex("(<file[^<]+)"); |
| cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)"); |
| |
| const char* contentChars = content.c_str(); |
| while (fileMatchRegex.find(contentChars)) { |
| std::string const qrcEntry = fileMatchRegex.match(1); |
| contentChars += qrcEntry.size(); |
| { |
| fileReplaceRegex.find(qrcEntry); |
| std::string const tag = fileReplaceRegex.match(1); |
| files.push_back(qrcEntry.substr(tag.size())); |
| } |
| } |
| } |
| |
| bool cmQtAutoGen::RccListParseOutput(std::string const& rccStdOut, |
| std::string const& rccStdErr, |
| std::vector<std::string>& files, |
| std::string& error) |
| { |
| // Lambda to strip CR characters |
| auto StripCR = [](std::string& line) { |
| std::string::size_type cr = line.find('\r'); |
| if (cr != std::string::npos) { |
| line = line.substr(0, cr); |
| } |
| }; |
| |
| // Parse rcc std output |
| { |
| std::istringstream ostr(rccStdOut); |
| std::string oline; |
| while (std::getline(ostr, oline)) { |
| StripCR(oline); |
| if (!oline.empty()) { |
| files.push_back(oline); |
| } |
| } |
| } |
| // Parse rcc error output |
| { |
| std::istringstream estr(rccStdErr); |
| std::string eline; |
| while (std::getline(estr, eline)) { |
| StripCR(eline); |
| if (cmHasLiteralPrefix(eline, "RCC: Error in")) { |
| static std::string const searchString = "Cannot find file '"; |
| |
| std::string::size_type pos = eline.find(searchString); |
| if (pos == std::string::npos) { |
| error = "rcc lists unparsable output:\n"; |
| error += cmQtAutoGen::Quoted(eline); |
| error += "\n"; |
| return false; |
| } |
| pos += searchString.length(); |
| std::string::size_type sz = eline.size() - pos - 1; |
| files.push_back(eline.substr(pos, sz)); |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| void cmQtAutoGen::RccListConvertFullPath(std::string const& qrcFileDir, |
| std::vector<std::string>& files) |
| { |
| for (std::string& entry : files) { |
| std::string tmp = cmSystemTools::CollapseCombinedPath(qrcFileDir, entry); |
| entry = std::move(tmp); |
| } |
| } |