diff options
-rw-r--r-- | Source/cmVariableWatch.cxx | 50 | ||||
-rw-r--r-- | Source/cmVariableWatch.h | 20 | ||||
-rw-r--r-- | Source/cmVariableWatchCommand.cxx | 141 | ||||
-rw-r--r-- | Source/cmVariableWatchCommand.h | 17 | ||||
-rw-r--r-- | Tests/RunCMake/variable_watch/RunCMakeTest.cmake | 1 | ||||
-rw-r--r-- | Tests/RunCMake/variable_watch/WatchTwice-stderr.txt | 2 | ||||
-rw-r--r-- | Tests/RunCMake/variable_watch/WatchTwice.cmake | 11 |
7 files changed, 156 insertions, 86 deletions
diff --git a/Source/cmVariableWatch.cxx b/Source/cmVariableWatch.cxx index 3905e9b..8ad6fce 100644 --- a/Source/cmVariableWatch.cxx +++ b/Source/cmVariableWatch.cxx @@ -37,37 +37,63 @@ cmVariableWatch::cmVariableWatch() cmVariableWatch::~cmVariableWatch() { + cmVariableWatch::StringToVectorOfPairs::iterator svp_it; + + for ( svp_it = this->WatchMap.begin(); + svp_it != this->WatchMap.end(); ++svp_it ) + { + cmVariableWatch::VectorOfPairs::iterator p_it; + + for ( p_it = svp_it->second.begin(); + p_it != svp_it->second.end(); ++p_it ) + { + delete *p_it; + } + } } -void cmVariableWatch::AddWatch(const std::string& variable, - WatchMethod method, void* client_data /*=0*/) +bool cmVariableWatch::AddWatch(const std::string& variable, + WatchMethod method, void* client_data /*=0*/, + DeleteData delete_data /*=0*/) { - cmVariableWatch::Pair p; - p.Method = method; - p.ClientData = client_data; + cmVariableWatch::Pair* p = new cmVariableWatch::Pair; + p->Method = method; + p->ClientData = client_data; + p->DeleteDataCall = delete_data; cmVariableWatch::VectorOfPairs* vp = &this->WatchMap[variable]; cmVariableWatch::VectorOfPairs::size_type cc; for ( cc = 0; cc < vp->size(); cc ++ ) { - cmVariableWatch::Pair* pair = &(*vp)[cc]; - if ( pair->Method == method ) + cmVariableWatch::Pair* pair = (*vp)[cc]; + if ( pair->Method == method && + client_data && client_data == pair->ClientData) { - (*vp)[cc] = p; - return; + // Callback already exists + return false; } } vp->push_back(p); + return true; } void cmVariableWatch::RemoveWatch(const std::string& variable, - WatchMethod method) + WatchMethod method, + void* client_data /*=0*/) { + if ( !this->WatchMap.count(variable) ) + { + return; + } cmVariableWatch::VectorOfPairs* vp = &this->WatchMap[variable]; cmVariableWatch::VectorOfPairs::iterator it; for ( it = vp->begin(); it != vp->end(); ++it ) { - if ( it->Method == method ) + if ( (*it)->Method == method && + // If client_data is NULL, we want to disconnect all watches against + // the given method; otherwise match ClientData as well. + (!client_data || (client_data == (*it)->ClientData))) { + delete *it; vp->erase(it); return; } @@ -87,7 +113,7 @@ void cmVariableWatch::VariableAccessed(const std::string& variable, cmVariableWatch::VectorOfPairs::const_iterator it; for ( it = vp->begin(); it != vp->end(); it ++ ) { - it->Method(variable, access_type, it->ClientData, + (*it)->Method(variable, access_type, (*it)->ClientData, newValue, mf); } } diff --git a/Source/cmVariableWatch.h b/Source/cmVariableWatch.h index 7dd4ac5..790c75a 100644 --- a/Source/cmVariableWatch.h +++ b/Source/cmVariableWatch.h @@ -26,6 +26,7 @@ class cmVariableWatch public: typedef void (*WatchMethod)(const std::string& variable, int access_type, void* client_data, const char* newValue, const cmMakefile* mf); + typedef void (*DeleteData)(void* client_data); cmVariableWatch(); ~cmVariableWatch(); @@ -33,9 +34,10 @@ public: /** * Add watch to the variable */ - void AddWatch(const std::string& variable, WatchMethod method, - void* client_data=0); - void RemoveWatch(const std::string& variable, WatchMethod method); + bool AddWatch(const std::string& variable, WatchMethod method, + void* client_data=0, DeleteData delete_data=0); + void RemoveWatch(const std::string& variable, WatchMethod method, + void* client_data=0); /** * This method is called when variable is accessed @@ -67,10 +69,18 @@ protected: { WatchMethod Method; void* ClientData; - Pair() : Method(0), ClientData(0) {} + DeleteData DeleteDataCall; + Pair() : Method(0), ClientData(0), DeleteDataCall(0) {} + ~Pair() + { + if (this->DeleteDataCall && this->ClientData) + { + this->DeleteDataCall(this->ClientData); + } + } }; - typedef std::vector< Pair > VectorOfPairs; + typedef std::vector< Pair* > VectorOfPairs; typedef std::map<cmStdString, VectorOfPairs > StringToVectorOfPairs; StringToVectorOfPairs WatchMap; diff --git a/Source/cmVariableWatchCommand.cxx b/Source/cmVariableWatchCommand.cxx index 297a92b..4eff19e 100644 --- a/Source/cmVariableWatchCommand.cxx +++ b/Source/cmVariableWatchCommand.cxx @@ -14,63 +14,27 @@ #include "cmVariableWatch.h" //---------------------------------------------------------------------------- -static void cmVariableWatchCommandVariableAccessed( - const std::string& variable, int access_type, void* client_data, - const char* newValue, const cmMakefile* mf) +struct cmVariableWatchCallbackData { - cmVariableWatchCommand* command - = static_cast<cmVariableWatchCommand*>(client_data); - command->VariableAccessed(variable, access_type, newValue, mf); -} + bool InCallback; + std::string Command; +}; //---------------------------------------------------------------------------- -cmVariableWatchCommand::cmVariableWatchCommand() +static void cmVariableWatchCommandVariableAccessed( + const std::string& variable, int access_type, void* client_data, + const char* newValue, const cmMakefile* mf) { - this->InCallback = false; -} + cmVariableWatchCallbackData* data + = static_cast<cmVariableWatchCallbackData*>(client_data); -//---------------------------------------------------------------------------- -bool cmVariableWatchCommand -::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) -{ - if ( args.size() < 1 ) - { - this->SetError("must be called with at least one argument."); - return false; - } - std::string variable = args[0]; - if ( args.size() > 1 ) - { - std::string command = args[1]; - this->Handlers[variable].Commands.push_back(args[1]); - } - if ( variable == "CMAKE_CURRENT_LIST_FILE" ) - { - cmOStringStream ostr; - ostr << "cannot be set on the variable: " << variable.c_str(); - this->SetError(ostr.str().c_str()); - return false; - } - - this->Makefile->GetCMakeInstance()->GetVariableWatch()->AddWatch( - variable, cmVariableWatchCommandVariableAccessed, this); - - return true; -} - -//---------------------------------------------------------------------------- -void cmVariableWatchCommand::VariableAccessed(const std::string& variable, - int access_type, const char* newValue, const cmMakefile* mf) -{ - if ( this->InCallback ) + if ( data->InCallback ) { return; } - this->InCallback = true; + data->InCallback = true; cmListFileFunction newLFF; - cmVariableWatchCommandHandler *handler = &this->Handlers[variable]; - cmVariableWatchCommandHandler::VectorOfCommands::iterator it; cmListFileArgument arg; bool processed = false; const char* accessString = cmVariableWatch::GetAccessAsString(access_type); @@ -80,10 +44,8 @@ void cmVariableWatchCommand::VariableAccessed(const std::string& variable, cmMakefile* makefile = const_cast<cmMakefile*>(mf); std::string stack = makefile->GetProperty("LISTFILE_STACK"); - for ( it = handler->Commands.begin(); it != handler->Commands.end(); - ++ it ) + if ( !data->Command.empty() ) { - std::string command = *it; newLFF.Arguments.clear(); newLFF.Arguments.push_back( cmListFileArgument(variable, true, "unknown", 9999)); @@ -95,7 +57,7 @@ void cmVariableWatchCommand::VariableAccessed(const std::string& variable, cmListFileArgument(currentListFile, true, "unknown", 9999)); newLFF.Arguments.push_back( cmListFileArgument(stack, true, "unknown", 9999)); - newLFF.Name = command; + newLFF.Name = data->Command; newLFF.FilePath = "Some weird path"; newLFF.Line = 9999; cmExecutionStatus status; @@ -106,10 +68,10 @@ void cmVariableWatchCommand::VariableAccessed(const std::string& variable, cmOStringStream error; error << "Error in cmake code at\n" << arg.FilePath << ":" << arg.Line << ":\n" - << "A command failed during the invocation of callback\"" - << command << "\"."; + << "A command failed during the invocation of callback \"" + << data->Command << "\"."; cmSystemTools::Error(error.str().c_str()); - this->InCallback = false; + data->InCallback = false; return; } processed = true; @@ -118,8 +80,75 @@ void cmVariableWatchCommand::VariableAccessed(const std::string& variable, { cmOStringStream msg; msg << "Variable \"" << variable.c_str() << "\" was accessed using " - << accessString << " with value \"" << newValue << "\"."; + << accessString << " with value \"" << (newValue?newValue:"") << "\"."; makefile->IssueMessage(cmake::LOG, msg.str()); } - this->InCallback = false; + + data->InCallback = false; +} + +//---------------------------------------------------------------------------- +static void deleteVariableWatchCallbackData(void* client_data) +{ + cmVariableWatchCallbackData* data + = static_cast<cmVariableWatchCallbackData*>(client_data); + delete data; +} + +//---------------------------------------------------------------------------- +cmVariableWatchCommand::cmVariableWatchCommand() +{ +} + +//---------------------------------------------------------------------------- +cmVariableWatchCommand::~cmVariableWatchCommand() +{ + std::set<std::string>::const_iterator it; + for ( it = this->WatchedVariables.begin(); + it != this->WatchedVariables.end(); + ++it ) + { + this->Makefile->GetCMakeInstance()->GetVariableWatch()->RemoveWatch( + *it, cmVariableWatchCommandVariableAccessed); + } +} + +//---------------------------------------------------------------------------- +bool cmVariableWatchCommand +::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) +{ + if ( args.size() < 1 ) + { + this->SetError("must be called with at least one argument."); + return false; + } + std::string variable = args[0]; + std::string command; + if ( args.size() > 1 ) + { + command = args[1]; + } + if ( variable == "CMAKE_CURRENT_LIST_FILE" ) + { + cmOStringStream ostr; + ostr << "cannot be set on the variable: " << variable.c_str(); + this->SetError(ostr.str().c_str()); + return false; + } + + cmVariableWatchCallbackData* data = new cmVariableWatchCallbackData; + + data->InCallback = false; + data->Command = command; + + this->WatchedVariables.insert(variable); + if ( !this->Makefile->GetCMakeInstance()->GetVariableWatch()->AddWatch( + variable, cmVariableWatchCommandVariableAccessed, + data, deleteVariableWatchCallbackData) ) + { + deleteVariableWatchCallbackData(data); + return false; + } + + return true; } diff --git a/Source/cmVariableWatchCommand.h b/Source/cmVariableWatchCommand.h index 3abc088..545535c 100644 --- a/Source/cmVariableWatchCommand.h +++ b/Source/cmVariableWatchCommand.h @@ -14,13 +14,6 @@ #include "cmCommand.h" -class cmVariableWatchCommandHandler -{ -public: - typedef std::vector<std::string> VectorOfCommands; - VectorOfCommands Commands; -}; - /** \class cmVariableWatchCommand * \brief Watch when the variable changes and invoke command * @@ -39,6 +32,9 @@ public: //! Default constructor cmVariableWatchCommand(); + //! Destructor. + ~cmVariableWatchCommand(); + /** * This is called when the command is first encountered in * the CMakeLists.txt file. @@ -83,13 +79,8 @@ public: cmTypeMacro(cmVariableWatchCommand, cmCommand); - void VariableAccessed(const std::string& variable, int access_type, - const char* newValue, const cmMakefile* mf); - protected: - std::map<std::string, cmVariableWatchCommandHandler> Handlers; - - bool InCallback; + std::set<std::string> WatchedVariables; }; diff --git a/Tests/RunCMake/variable_watch/RunCMakeTest.cmake b/Tests/RunCMake/variable_watch/RunCMakeTest.cmake index 8d20476..9becb4c 100644 --- a/Tests/RunCMake/variable_watch/RunCMakeTest.cmake +++ b/Tests/RunCMake/variable_watch/RunCMakeTest.cmake @@ -2,3 +2,4 @@ include(RunCMake) run_cmake(ModifiedAccess) run_cmake(NoWatcher) +run_cmake(WatchTwice) diff --git a/Tests/RunCMake/variable_watch/WatchTwice-stderr.txt b/Tests/RunCMake/variable_watch/WatchTwice-stderr.txt new file mode 100644 index 0000000..fa7d347 --- /dev/null +++ b/Tests/RunCMake/variable_watch/WatchTwice-stderr.txt @@ -0,0 +1,2 @@ +From watch1 +From watch2 diff --git a/Tests/RunCMake/variable_watch/WatchTwice.cmake b/Tests/RunCMake/variable_watch/WatchTwice.cmake new file mode 100644 index 0000000..540cfc1 --- /dev/null +++ b/Tests/RunCMake/variable_watch/WatchTwice.cmake @@ -0,0 +1,11 @@ +function (watch1) + message("From watch1") +endfunction () + +function (watch2) + message("From watch2") +endfunction () + +variable_watch(watched watch1) +variable_watch(watched watch2) +set(access "${watched}") |