diff options
Diffstat (limited to 'Source/cmSourceGroupCommand.cxx')
-rw-r--r-- | Source/cmSourceGroupCommand.cxx | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx new file mode 100644 index 0000000..69983a8 --- /dev/null +++ b/Source/cmSourceGroupCommand.cxx @@ -0,0 +1,255 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmSourceGroupCommand.h" + +#include <set> +#include <sstream> +#include <stddef.h> + +#include "cmMakefile.h" +#include "cmSourceGroup.h" +#include "cmSystemTools.h" + +namespace { +const size_t RootIndex = 1; +const size_t FilesWithoutPrefixKeywordIndex = 2; +const size_t FilesWithPrefixKeywordIndex = 4; +const size_t PrefixKeywordIndex = 2; + +std::vector<std::string> tokenizePath(const std::string& path) +{ + return cmSystemTools::tokenize(path, "\\/"); +} + +std::string getFullFilePath(const std::string& currentPath, + const std::string& path) +{ + std::string fullPath = path; + + if (!cmSystemTools::FileIsFullPath(path.c_str())) { + fullPath = currentPath; + fullPath += "/"; + fullPath += path; + } + + return cmSystemTools::CollapseFullPath(fullPath); +} + +std::set<std::string> getSourceGroupFilesPaths( + const std::string& root, const std::vector<std::string>& files) +{ + std::set<std::string> ret; + const std::string::size_type rootLength = root.length(); + + for (std::string const& file : files) { + ret.insert(file.substr(rootLength + 1)); // +1 to also omnit last '/' + } + + return ret; +} + +bool rootIsPrefix(const std::string& root, + const std::vector<std::string>& files, std::string& error) +{ + for (std::string const& file : files) { + if (!cmSystemTools::StringStartsWith(file, root.c_str())) { + error = "ROOT: " + root + " is not a prefix of file: " + file; + return false; + } + } + + return true; +} + +std::string prepareFilePathForTree(const std::string& path, + const std::string& currentSourceDir) +{ + if (!cmSystemTools::FileIsFullPath(path)) { + return cmSystemTools::CollapseFullPath(currentSourceDir + "/" + path); + } + return cmSystemTools::CollapseFullPath(path); +} + +std::vector<std::string> prepareFilesPathsForTree( + std::vector<std::string>::const_iterator begin, + std::vector<std::string>::const_iterator end, + const std::string& currentSourceDir) +{ + std::vector<std::string> prepared; + + for (; begin != end; ++begin) { + prepared.push_back(prepareFilePathForTree(*begin, currentSourceDir)); + } + + return prepared; +} + +bool addFilesToItsSourceGroups(const std::string& root, + const std::set<std::string>& sgFilesPaths, + const std::string& prefix, cmMakefile& makefile, + std::string& errorMsg) +{ + cmSourceGroup* sg; + + for (std::string const& sgFilesPath : sgFilesPaths) { + + std::vector<std::string> tokenizedPath; + if (!prefix.empty()) { + tokenizedPath = tokenizePath(prefix + '/' + sgFilesPath); + } else { + tokenizedPath = tokenizePath(sgFilesPath); + } + + if (tokenizedPath.size() > 1) { + tokenizedPath.pop_back(); + + sg = makefile.GetOrCreateSourceGroup(tokenizedPath); + + if (!sg) { + errorMsg = "Could not create source group for file: " + sgFilesPath; + return false; + } + const std::string fullPath = getFullFilePath(root, sgFilesPath); + sg->AddGroupFile(fullPath); + } + } + + return true; +} +} + +class cmExecutionStatus; + +// cmSourceGroupCommand +bool cmSourceGroupCommand::InitialPass(std::vector<std::string> const& args, + cmExecutionStatus&) +{ + if (args.empty()) { + this->SetError("called with incorrect number of arguments"); + return false; + } + + if (args[0] == "TREE") { + std::string error; + + if (!processTree(args, error)) { + this->SetError(error); + return false; + } + + return true; + } + + cmSourceGroup* sg = this->Makefile->GetOrCreateSourceGroup(args[0]); + + if (!sg) { + this->SetError("Could not create or find source group"); + return false; + } + // If only two arguments are given, the pre-1.8 version of the + // command is being invoked. + if (args.size() == 2 && args[1] != "FILES") { + sg->SetGroupRegex(args[1].c_str()); + return true; + } + + // Process arguments. + bool doingFiles = false; + for (unsigned int i = 1; i < args.size(); ++i) { + if (args[i] == "REGULAR_EXPRESSION") { + // Next argument must specify the regex. + if (i + 1 < args.size()) { + ++i; + sg->SetGroupRegex(args[i].c_str()); + } else { + this->SetError("REGULAR_EXPRESSION argument given without a regex."); + return false; + } + doingFiles = false; + } else if (args[i] == "FILES") { + // Next arguments will specify files. + doingFiles = true; + } else if (doingFiles) { + // Convert name to full path and add to the group's list. + std::string src = args[i]; + if (!cmSystemTools::FileIsFullPath(src.c_str())) { + src = this->Makefile->GetCurrentSourceDirectory(); + src += "/"; + src += args[i]; + } + src = cmSystemTools::CollapseFullPath(src); + sg->AddGroupFile(src); + } else { + std::ostringstream err; + err << "Unknown argument \"" << args[i] << "\". " + << "Perhaps the FILES keyword is missing.\n"; + this->SetError(err.str()); + return false; + } + } + + return true; +} + +bool cmSourceGroupCommand::checkTreeArgumentsPreconditions( + const std::vector<std::string>& args, std::string& errorMsg) const +{ + if (args.size() == 1) { + errorMsg = "TREE argument given without a root."; + return false; + } + + if (args.size() < 3) { + errorMsg = "Missing FILES arguments."; + return false; + } + + if (args[FilesWithoutPrefixKeywordIndex] != "FILES" && + args[PrefixKeywordIndex] != "PREFIX") { + errorMsg = "Unknown argument \"" + args[2] + + "\". Perhaps the FILES keyword is missing.\n"; + return false; + } + + if (args[PrefixKeywordIndex] == "PREFIX" && + (args.size() < 5 || args[FilesWithPrefixKeywordIndex] != "FILES")) { + errorMsg = "Missing FILES arguments."; + return false; + } + + return true; +} + +bool cmSourceGroupCommand::processTree(const std::vector<std::string>& args, + std::string& errorMsg) +{ + if (!checkTreeArgumentsPreconditions(args, errorMsg)) { + return false; + } + + const std::string root = cmSystemTools::CollapseFullPath(args[RootIndex]); + std::string prefix; + size_t filesBegin = FilesWithoutPrefixKeywordIndex + 1; + if (args[PrefixKeywordIndex] == "PREFIX") { + prefix = args[PrefixKeywordIndex + 1]; + filesBegin = FilesWithPrefixKeywordIndex + 1; + } + + const std::vector<std::string> filesVector = + prepareFilesPathsForTree(args.begin() + filesBegin, args.end(), + this->Makefile->GetCurrentSourceDirectory()); + + if (!rootIsPrefix(root, filesVector, errorMsg)) { + return false; + } + + std::set<std::string> sourceGroupPaths = + getSourceGroupFilesPaths(root, filesVector); + + if (!addFilesToItsSourceGroups(root, sourceGroupPaths, prefix, + *(this->Makefile), errorMsg)) { + return false; + } + + return true; +} |