diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/cmListCommand.cxx | 192 |
1 files changed, 189 insertions, 3 deletions
diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx index 1ac2cc2..ba0c843 100644 --- a/Source/cmListCommand.cxx +++ b/Source/cmListCommand.cxx @@ -963,14 +963,193 @@ bool cmListCommand::HandleTransformCommand( return true; } +class cmStringSorter +{ +public: + enum class Order + { + UNINITIALIZED, + ASCENDING, + DESCENDING, + }; + + enum class Compare + { + UNINITIALIZED, + STRING, + FILE_BASENAME, + }; + enum class CaseSensitivity + { + UNINITIALIZED, + SENSITIVE, + INSENSITIVE, + }; + +protected: + typedef std::string (*StringFilter)(const std::string& in); + StringFilter GetCompareFilter(Compare compare) + { + return (compare == Compare::FILE_BASENAME) ? cmSystemTools::GetFilenameName + : nullptr; + } + + StringFilter GetCaseFilter(CaseSensitivity sensitivity) + { + return (sensitivity == CaseSensitivity::INSENSITIVE) + ? cmSystemTools::LowerCase + : nullptr; + } + +public: + cmStringSorter(Compare compare, CaseSensitivity caseSensitivity, + Order desc = Order::ASCENDING) + : filters{ GetCompareFilter(compare), GetCaseFilter(caseSensitivity) } + , descending(desc == Order::DESCENDING) + { + } + + std::string ApplyFilter(const std::string& argument) + { + std::string result = argument; + for (auto filter : filters) { + if (filter != nullptr) { + result = filter(result); + } + } + return result; + } + + bool operator()(const std::string& a, const std::string& b) + { + std::string af = ApplyFilter(a); + std::string bf = ApplyFilter(b); + bool result; + if (descending) { + result = bf < af; + } else { + result = af < bf; + } + return result; + } + +protected: + StringFilter filters[2] = { nullptr, nullptr }; + bool descending; +}; + bool cmListCommand::HandleSortCommand(std::vector<std::string> const& args) { assert(args.size() >= 2); - if (args.size() > 2) { - this->SetError("sub-command SORT only takes one argument."); + if (args.size() > 8) { + this->SetError("sub-command SORT only takes up to six arguments."); return false; } + auto sortCompare = cmStringSorter::Compare::UNINITIALIZED; + auto sortCaseSensitivity = cmStringSorter::CaseSensitivity::UNINITIALIZED; + auto sortOrder = cmStringSorter::Order::UNINITIALIZED; + + size_t argumentIndex = 2; + const std::string messageHint = "sub-command SORT "; + + while (argumentIndex < args.size()) { + const std::string option = args[argumentIndex++]; + if (option == "COMPARE") { + if (sortCompare != cmStringSorter::Compare::UNINITIALIZED) { + std::string error = messageHint + "option \"" + option + + "\" has been specified multiple times."; + this->SetError(error); + return false; + } + if (argumentIndex < args.size()) { + const std::string argument = args[argumentIndex++]; + if (argument == "STRING") { + sortCompare = cmStringSorter::Compare::STRING; + } else if (argument == "FILE_BASENAME") { + sortCompare = cmStringSorter::Compare::FILE_BASENAME; + } else { + std::string error = messageHint + "value \"" + argument + + "\" for option \"" + option + "\" is invalid."; + this->SetError(error); + return false; + } + } else { + std::string error = + messageHint + "missing argument for option \"" + option + "\"."; + this->SetError(error); + return false; + } + } else if (option == "CASE") { + if (sortCaseSensitivity != + cmStringSorter::CaseSensitivity::UNINITIALIZED) { + std::string error = messageHint + "option \"" + option + + "\" has been specified multiple times."; + this->SetError(error); + return false; + } + if (argumentIndex < args.size()) { + const std::string argument = args[argumentIndex++]; + if (argument == "SENSITIVE") { + sortCaseSensitivity = cmStringSorter::CaseSensitivity::SENSITIVE; + } else if (argument == "INSENSITIVE") { + sortCaseSensitivity = cmStringSorter::CaseSensitivity::INSENSITIVE; + } else { + std::string error = messageHint + "value \"" + argument + + "\" for option \"" + option + "\" is invalid."; + this->SetError(error); + return false; + } + } else { + std::string error = + messageHint + "missing argument for option \"" + option + "\"."; + this->SetError(error); + return false; + } + } else if (option == "ORDER") { + + if (sortOrder != cmStringSorter::Order::UNINITIALIZED) { + std::string error = messageHint + "option \"" + option + + "\" has been specified multiple times."; + this->SetError(error); + return false; + } + if (argumentIndex < args.size()) { + const std::string argument = args[argumentIndex++]; + if (argument == "ASCENDING") { + sortOrder = cmStringSorter::Order::ASCENDING; + } else if (argument == "DESCENDING") { + sortOrder = cmStringSorter::Order::DESCENDING; + } else { + std::string error = messageHint + "value \"" + argument + + "\" for option \"" + option + "\" is invalid."; + this->SetError(error); + return false; + } + } else { + std::string error = + messageHint + "missing argument for option \"" + option + "\"."; + this->SetError(error); + return false; + } + } else { + std::string error = + messageHint + "option \"" + option + "\" is unknown."; + this->SetError(error); + return false; + } + } + // set Default Values if Option is not given + if (sortCompare == cmStringSorter::Compare::UNINITIALIZED) { + sortCompare = cmStringSorter::Compare::STRING; + } + if (sortCaseSensitivity == cmStringSorter::CaseSensitivity::UNINITIALIZED) { + sortCaseSensitivity = cmStringSorter::CaseSensitivity::SENSITIVE; + } + if (sortOrder == cmStringSorter::Order::UNINITIALIZED) { + sortOrder = cmStringSorter::Order::ASCENDING; + } + const std::string& listName = args[1]; // expand the variable std::vector<std::string> varArgsExpanded; @@ -979,7 +1158,14 @@ bool cmListCommand::HandleSortCommand(std::vector<std::string> const& args) return false; } - std::sort(varArgsExpanded.begin(), varArgsExpanded.end()); + if ((sortCompare == cmStringSorter::Compare::STRING) && + (sortCaseSensitivity == cmStringSorter::CaseSensitivity::SENSITIVE) && + (sortOrder == cmStringSorter::Order::ASCENDING)) { + std::sort(varArgsExpanded.begin(), varArgsExpanded.end()); + } else { + cmStringSorter sorter(sortCompare, sortCaseSensitivity, sortOrder); + std::sort(varArgsExpanded.begin(), varArgsExpanded.end(), sorter); + } std::string value = cmJoin(varArgsExpanded, ";"); this->Makefile->AddDefinition(listName, value.c_str()); |