diff options
Diffstat (limited to 'Source/cmListCommand.cxx')
-rw-r--r-- | Source/cmListCommand.cxx | 608 |
1 files changed, 608 insertions, 0 deletions
diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx new file mode 100644 index 0000000..f1ea088 --- /dev/null +++ b/Source/cmListCommand.cxx @@ -0,0 +1,608 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmListCommand.h" +#include <cmsys/RegularExpression.hxx> +#include <cmsys/SystemTools.hxx> + +#include <stdlib.h> // required for atoi +#include <ctype.h> +#include <assert.h> +//---------------------------------------------------------------------------- +bool cmListCommand +::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) +{ + if(args.size() < 2) + { + this->SetError("must be called with at least two arguments."); + return false; + } + + const std::string &subCommand = args[0]; + if(subCommand == "LENGTH") + { + return this->HandleLengthCommand(args); + } + if(subCommand == "GET") + { + return this->HandleGetCommand(args); + } + if(subCommand == "APPEND") + { + return this->HandleAppendCommand(args); + } + if(subCommand == "FIND") + { + return this->HandleFindCommand(args); + } + if(subCommand == "INSERT") + { + return this->HandleInsertCommand(args); + } + if(subCommand == "REMOVE_AT") + { + return this->HandleRemoveAtCommand(args); + } + if(subCommand == "REMOVE_ITEM") + { + return this->HandleRemoveItemCommand(args); + } + if(subCommand == "REMOVE_DUPLICATES") + { + return this->HandleRemoveDuplicatesCommand(args); + } + if(subCommand == "SORT") + { + return this->HandleSortCommand(args); + } + if(subCommand == "REVERSE") + { + return this->HandleReverseCommand(args); + } + + std::string e = "does not recognize sub-command "+subCommand; + this->SetError(e); + return false; +} + +//---------------------------------------------------------------------------- +bool cmListCommand::GetListString(std::string& listString, + const std::string& var) +{ + // get the old value + const char* cacheValue + = this->Makefile->GetDefinition(var); + if(!cacheValue) + { + return false; + } + listString = cacheValue; + return true; +} + +//---------------------------------------------------------------------------- +bool cmListCommand::GetList(std::vector<std::string>& list, + const std::string& var) +{ + std::string listString; + if ( !this->GetListString(listString, var) ) + { + return false; + } + // if the size of the list + if(listString.size() == 0) + { + return true; + } + // expand the variable into a list + cmSystemTools::ExpandListArgument(listString, list, true); + // check the list for empty values + bool hasEmpty = false; + for(std::vector<std::string>::iterator i = list.begin(); + i != list.end(); ++i) + { + if(i->size() == 0) + { + hasEmpty = true; + break; + } + } + // if no empty elements then just return + if(!hasEmpty) + { + return true; + } + // if we have empty elements we need to check policy CMP0007 + switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0007)) + { + case cmPolicies::WARN: + { + // Default is to warn and use old behavior + // OLD behavior is to allow compatibility, so recall + // ExpandListArgument without the true which will remove + // empty values + list.clear(); + cmSystemTools::ExpandListArgument(listString, list); + std::string warn = this->Makefile->GetPolicies()-> + GetPolicyWarning(cmPolicies::CMP0007); + warn += " List has value = ["; + warn += listString; + warn += "]."; + this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, + warn); + return true; + } + case cmPolicies::OLD: + // OLD behavior is to allow compatibility, so recall + // ExpandListArgument without the true which will remove + // empty values + list.clear(); + cmSystemTools::ExpandListArgument(listString, list); + return true; + case cmPolicies::NEW: + return true; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + this->Makefile->GetPolicies() + ->GetRequiredPolicyError(cmPolicies::CMP0007) + ); + return false; + } + return true; +} + +//---------------------------------------------------------------------------- +bool cmListCommand::HandleLengthCommand(std::vector<std::string> const& args) +{ + if(args.size() != 3) + { + this->SetError("sub-command LENGTH requires two arguments."); + return false; + } + + const std::string& listName = args[1]; + const std::string& variableName = args[args.size() - 1]; + std::vector<std::string> varArgsExpanded; + // do not check the return value here + // if the list var is not found varArgsExpanded will have size 0 + // and we will return 0 + this->GetList(varArgsExpanded, listName); + size_t length = varArgsExpanded.size(); + char buffer[1024]; + sprintf(buffer, "%d", static_cast<int>(length)); + + this->Makefile->AddDefinition(variableName, buffer); + return true; +} + +//---------------------------------------------------------------------------- +bool cmListCommand::HandleGetCommand(std::vector<std::string> const& args) +{ + if(args.size() < 4) + { + this->SetError("sub-command GET requires at least three arguments."); + return false; + } + + const std::string& listName = args[1]; + const std::string& variableName = args[args.size() - 1]; + // expand the variable + std::vector<std::string> varArgsExpanded; + if ( !this->GetList(varArgsExpanded, listName) ) + { + this->Makefile->AddDefinition(variableName, "NOTFOUND"); + return true; + } + // FIXME: Add policy to make non-existing lists an error like empty lists. + if(varArgsExpanded.empty()) + { + this->SetError("GET given empty list"); + return false; + } + + std::string value; + size_t cc; + const char* sep = ""; + for ( cc = 2; cc < args.size()-1; cc ++ ) + { + int item = atoi(args[cc].c_str()); + value += sep; + sep = ";"; + size_t nitem = varArgsExpanded.size(); + if ( item < 0 ) + { + item = (int)nitem + item; + } + if ( item < 0 || nitem <= (size_t)item ) + { + cmOStringStream str; + str << "index: " << item << " out of range (-" + << varArgsExpanded.size() << ", " + << varArgsExpanded.size()-1 << ")"; + this->SetError(str.str()); + return false; + } + value += varArgsExpanded[item]; + } + + this->Makefile->AddDefinition(variableName, value.c_str()); + return true; +} + +//---------------------------------------------------------------------------- +bool cmListCommand::HandleAppendCommand(std::vector<std::string> const& args) +{ + assert(args.size() >= 2); + + // Skip if nothing to append. + if(args.size() < 3) + { + return true; + } + + const std::string& listName = args[1]; + // expand the variable + std::string listString; + this->GetListString(listString, listName); + size_t cc; + for ( cc = 2; cc < args.size(); ++ cc ) + { + if(listString.size()) + { + listString += ";"; + } + listString += args[cc]; + } + + this->Makefile->AddDefinition(listName, listString.c_str()); + return true; +} + +//---------------------------------------------------------------------------- +bool cmListCommand::HandleFindCommand(std::vector<std::string> const& args) +{ + if(args.size() != 4) + { + this->SetError("sub-command FIND requires three arguments."); + return false; + } + + const std::string& listName = args[1]; + const std::string& variableName = args[args.size() - 1]; + // expand the variable + std::vector<std::string> varArgsExpanded; + if ( !this->GetList(varArgsExpanded, listName) ) + { + this->Makefile->AddDefinition(variableName, "-1"); + return true; + } + + std::vector<std::string>::iterator it; + unsigned int index = 0; + for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it ) + { + if ( *it == args[2] ) + { + char indexString[32]; + sprintf(indexString, "%d", index); + this->Makefile->AddDefinition(variableName, indexString); + return true; + } + index++; + } + + this->Makefile->AddDefinition(variableName, "-1"); + return true; +} + +//---------------------------------------------------------------------------- +bool cmListCommand::HandleInsertCommand(std::vector<std::string> const& args) +{ + if(args.size() < 4) + { + this->SetError("sub-command INSERT requires at least three arguments."); + return false; + } + + const std::string& listName = args[1]; + + // expand the variable + int item = atoi(args[2].c_str()); + std::vector<std::string> varArgsExpanded; + if((!this->GetList(varArgsExpanded, listName) + || varArgsExpanded.empty()) && item != 0) + { + cmOStringStream str; + str << "index: " << item << " out of range (0, 0)"; + this->SetError(str.str()); + return false; + } + + if ( varArgsExpanded.size() != 0 ) + { + size_t nitem = varArgsExpanded.size(); + if ( item < 0 ) + { + item = (int)nitem + item; + } + if ( item < 0 || nitem <= (size_t)item ) + { + cmOStringStream str; + str << "index: " << item << " out of range (-" + << varArgsExpanded.size() << ", " + << (varArgsExpanded.size() == 0?0:(varArgsExpanded.size()-1)) << ")"; + this->SetError(str.str()); + return false; + } + } + size_t cc; + size_t cnt = 0; + for ( cc = 3; cc < args.size(); ++ cc ) + { + varArgsExpanded.insert(varArgsExpanded.begin()+item+cnt, args[cc]); + cnt ++; + } + + std::string value; + const char* sep = ""; + for ( cc = 0; cc < varArgsExpanded.size(); cc ++ ) + { + value += sep; + value += varArgsExpanded[cc]; + sep = ";"; + } + + this->Makefile->AddDefinition(listName, value.c_str()); + return true; +} + +//---------------------------------------------------------------------------- +bool cmListCommand +::HandleRemoveItemCommand(std::vector<std::string> const& args) +{ + if(args.size() < 3) + { + this->SetError("sub-command REMOVE_ITEM requires two or more arguments."); + return false; + } + + const std::string& listName = args[1]; + // expand the variable + std::vector<std::string> varArgsExpanded; + if ( !this->GetList(varArgsExpanded, listName) ) + { + this->SetError("sub-command REMOVE_ITEM requires list to be present."); + return false; + } + + size_t cc; + for ( cc = 2; cc < args.size(); ++ cc ) + { + size_t kk = 0; + while ( kk < varArgsExpanded.size() ) + { + if ( varArgsExpanded[kk] == args[cc] ) + { + varArgsExpanded.erase(varArgsExpanded.begin()+kk); + } + else + { + kk ++; + } + } + } + + std::string value; + const char* sep = ""; + for ( cc = 0; cc < varArgsExpanded.size(); cc ++ ) + { + value += sep; + value += varArgsExpanded[cc]; + sep = ";"; + } + + this->Makefile->AddDefinition(listName, value.c_str()); + return true; +} + +//---------------------------------------------------------------------------- +bool cmListCommand +::HandleReverseCommand(std::vector<std::string> const& args) +{ + assert(args.size() >= 2); + if(args.size() > 2) + { + this->SetError( + "sub-command REVERSE only takes one argument."); + return false; + } + + const std::string& listName = args[1]; + // expand the variable + std::vector<std::string> varArgsExpanded; + if ( !this->GetList(varArgsExpanded, listName) ) + { + this->SetError("sub-command REVERSE requires list to be present."); + return false; + } + + std::string value; + std::vector<std::string>::reverse_iterator it; + const char* sep = ""; + for ( it = varArgsExpanded.rbegin(); it != varArgsExpanded.rend(); ++ it ) + { + value += sep; + value += it->c_str(); + sep = ";"; + } + + this->Makefile->AddDefinition(listName, value.c_str()); + return true; +} + +//---------------------------------------------------------------------------- +bool cmListCommand +::HandleRemoveDuplicatesCommand(std::vector<std::string> const& args) +{ + assert(args.size() >= 2); + if(args.size() > 2) + { + this->SetError( + "sub-command REMOVE_DUPLICATES only takes one argument."); + return false; + } + + const std::string& listName = args[1]; + // expand the variable + std::vector<std::string> varArgsExpanded; + if ( !this->GetList(varArgsExpanded, listName) ) + { + this->SetError( + "sub-command REMOVE_DUPLICATES requires list to be present."); + return false; + } + + std::string value; + + + std::set<std::string> unique; + std::vector<std::string>::iterator it; + const char* sep = ""; + for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it ) + { + if (unique.find(*it) != unique.end()) + { + continue; + } + unique.insert(*it); + value += sep; + value += it->c_str(); + sep = ";"; + } + + + this->Makefile->AddDefinition(listName, value.c_str()); + return true; +} + +//---------------------------------------------------------------------------- +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."); + return false; + } + + const std::string& listName = args[1]; + // expand the variable + std::vector<std::string> varArgsExpanded; + if ( !this->GetList(varArgsExpanded, listName) ) + { + this->SetError("sub-command SORT requires list to be present."); + return false; + } + + std::sort(varArgsExpanded.begin(), varArgsExpanded.end()); + + std::string value; + std::vector<std::string>::iterator it; + const char* sep = ""; + for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it ) + { + value += sep; + value += it->c_str(); + sep = ";"; + } + + this->Makefile->AddDefinition(listName, value.c_str()); + return true; +} + +//---------------------------------------------------------------------------- +bool cmListCommand::HandleRemoveAtCommand( + std::vector<std::string> const& args) +{ + if(args.size() < 3) + { + this->SetError("sub-command REMOVE_AT requires at least " + "two arguments."); + return false; + } + + const std::string& listName = args[1]; + // expand the variable + std::vector<std::string> varArgsExpanded; + if ( !this->GetList(varArgsExpanded, listName) ) + { + this->SetError("sub-command REMOVE_AT requires list to be present."); + return false; + } + // FIXME: Add policy to make non-existing lists an error like empty lists. + if(varArgsExpanded.empty()) + { + this->SetError("REMOVE_AT given empty list"); + return false; + } + + size_t cc; + std::vector<size_t> removed; + for ( cc = 2; cc < args.size(); ++ cc ) + { + int item = atoi(args[cc].c_str()); + size_t nitem = varArgsExpanded.size(); + if ( item < 0 ) + { + item = (int)nitem + item; + } + if ( item < 0 || nitem <= (size_t)item ) + { + cmOStringStream str; + str << "index: " << item << " out of range (-" + << varArgsExpanded.size() << ", " + << varArgsExpanded.size()-1 << ")"; + this->SetError(str.str()); + return false; + } + removed.push_back(static_cast<size_t>(item)); + } + + std::string value; + const char* sep = ""; + for ( cc = 0; cc < varArgsExpanded.size(); ++ cc ) + { + size_t kk; + bool found = false; + for ( kk = 0; kk < removed.size(); ++ kk ) + { + if ( cc == removed[kk] ) + { + found = true; + } + } + + if ( !found ) + { + value += sep; + value += varArgsExpanded[cc]; + sep = ";"; + } + } + + this->Makefile->AddDefinition(listName, value.c_str()); + return true; +} + |