/*========================================================================= Program: ParaView Module: vtkClientServerInterpreter.cxx Copyright (c) Kitware, Inc. All rights reserved. See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkClientServerInterpreter.h" #include "vtkClientServerStream.h" #include "vtkCommand.h" #include "vtkDynamicLoader.h" #include "vtkObjectFactory.h" #include #include #include #include #include vtkStandardNewMacro(vtkClientServerInterpreter); //---------------------------------------------------------------------------- class vtkClientServerInterpreterInternals { public: struct ContextInformation { ContextInformation(void* ctx, vtkContextFreeFunction freeFunction) { this->Context = ctx; this->FreeFunction = freeFunction; } ~ContextInformation() { if(this->FreeFunction) { this->FreeFunction(this->Context); } } void* Context; vtkContextFreeFunction FreeFunction; }; template struct FunctionWithContext { FunctionWithContext(FunctionType function, ContextInformation* ctx) { this->Function = function; this->Context = ctx; } ~FunctionWithContext() { delete this->Context; } FunctionType Function; ContextInformation* Context; private: FunctionWithContext(const FunctionWithContext&); // Not implemented. FunctionWithContext& operator=(const FunctionWithContext&); // Not implemented. }; typedef FunctionWithContext NewInstanceFunction; typedef FunctionWithContext CommandFunction; typedef std::map NewInstanceFunctionsType; typedef std::map ClassToFunctionMapType; typedef std::map IDToMessageMapType; NewInstanceFunctionsType NewInstanceFunctions; ClassToFunctionMapType ClassToFunctionMap; IDToMessageMapType IDToMessageMap; }; //---------------------------------------------------------------------------- vtkClientServerInterpreter::vtkClientServerInterpreter() { this->NextAvailableId = 0; this->Internal = new vtkClientServerInterpreterInternals; this->LastResultMessage = new vtkClientServerStream(this); this->LogStream = 0; this->LogFileStream = 0; } //---------------------------------------------------------------------------- vtkClientServerInterpreter::~vtkClientServerInterpreter() { // Delete any remaining instance functions. vtkClientServerInterpreterInternals::NewInstanceFunctionsType::iterator ni; for(ni = this->Internal->NewInstanceFunctions.begin(); ni != this->Internal->NewInstanceFunctions.end(); ++ni) { delete ni->second; } // Delete any remaining command functions. vtkClientServerInterpreterInternals::ClassToFunctionMapType::iterator ci; for(ci = this->Internal->ClassToFunctionMap.begin(); ci != this->Internal->ClassToFunctionMap.end(); ++ci) { delete ci->second; } // Delete any remaining messages. vtkClientServerInterpreterInternals::IDToMessageMapType::iterator hi; for(hi = this->Internal->IDToMessageMap.begin(); hi != this->Internal->IDToMessageMap.end(); ++hi) { delete hi->second; } // End logging. this->SetLogStream(0); delete this->LastResultMessage; this->LastResultMessage = 0; delete this->Internal; this->Internal = 0; } //---------------------------------------------------------------------------- vtkObjectBase* vtkClientServerInterpreter::GetObjectFromID(vtkClientServerID id, int noerror) { // Get the message corresponding to this ID. if(const vtkClientServerStream* tmp = this->GetMessageFromID(id)) { // Retrieve the object from the message. vtkObjectBase* obj = 0; if(tmp->GetNumberOfArguments(0) == 1 && tmp->GetArgument(0, 0, &obj)) { return obj; } else { if ( !noerror ) { vtkErrorMacro("Attempt to get an object for ID " << id.ID << " whose message does not contain exactly one object."); } return 0; } } else { if ( !noerror ) { vtkErrorMacro("Attempt to get object for ID " << id.ID << " that is not present in the hash table."); } return 0; } } //---------------------------------------------------------------------------- vtkClientServerID vtkClientServerInterpreter::GetIDFromObject(vtkObjectBase* key) { // Search the hash table for the given object. vtkClientServerID result; vtkClientServerInterpreterInternals::IDToMessageMapType::iterator hi; for(hi = this->Internal->IDToMessageMap.begin(); hi != this->Internal->IDToMessageMap.end(); ++hi) { vtkObjectBase* obj; if(hi->second->GetArgument(0, 0, &obj) && obj == key) { result.ID = hi->first; break; } } return result; } //---------------------------------------------------------------------------- void vtkClientServerInterpreter::SetLogFile(const char* name) { // Close any existing log. this->SetLogStream(0); // If a non-empty name was given, open a new log file. if(name && name[0]) { this->LogFileStream = new ofstream(name); if(this->LogFileStream && *this->LogFileStream) { this->LogStream = this->LogFileStream; } else { vtkErrorMacro("Error opening log file \"" << name << "\" for writing."); if(this->LogFileStream) { delete this->LogFileStream; this->LogFileStream = 0; } } } } //---------------------------------------------------------------------------- void vtkClientServerInterpreter::SetLogStream(ostream* ostr) { if(ostr != this->LogStream) { // Close the current log file, if any. if(this->LogStream && this->LogStream == this->LogFileStream) { delete this->LogFileStream; this->LogFileStream = 0; } // Set the log to use the given stream. this->LogStream = ostr; } } //---------------------------------------------------------------------------- int vtkClientServerInterpreter::ProcessStream(const unsigned char* msg, size_t msgLength) { vtkClientServerStream css; css.SetData(msg, msgLength); return this->ProcessStream(css); } //---------------------------------------------------------------------------- int vtkClientServerInterpreter::ProcessStream(const vtkClientServerStream& css) { for(int i=0; i < css.GetNumberOfMessages(); ++i) { if(!this->ProcessOneMessage(css, i)) { return 0; } } return 1; } //---------------------------------------------------------------------------- int vtkClientServerInterpreter::ProcessOneMessage(const vtkClientServerStream& css, int message) { // Log the message. if(this->LogStream) { *this->LogStream << "---------------------------------------" << "---------------------------------------\n"; *this->LogStream << "Processing "; css.PrintMessage(*this->LogStream, message); this->LogStream->flush(); } // Look for known commands in the message. int result = 0; vtkClientServerStream::Commands cmd = css.GetCommand(message); switch(cmd) { case vtkClientServerStream::New: result = this->ProcessCommandNew(css, message); break; case vtkClientServerStream::Invoke: result = this->ProcessCommandInvoke(css, message); break; case vtkClientServerStream::Delete: result = this->ProcessCommandDelete(css, message); break; case vtkClientServerStream::Assign: result = this->ProcessCommandAssign(css, message); break; default: { // Command is not known. std::ostringstream error; error << "Message with type " << vtkClientServerStream::GetStringFromCommand(cmd) << " cannot be executed." << ends; this->LastResultMessage->Reset(); *this->LastResultMessage << vtkClientServerStream::Error << error.str().c_str() << vtkClientServerStream::End; } break; } // Log the result of the message. if(this->LogStream) { if(this->LastResultMessage->GetNumberOfMessages() > 0) { *this->LogStream << "Result "; this->LastResultMessage->Print(*this->LogStream); } else { *this->LogStream << "Empty Result\n"; } this->LogStream->flush(); } // If the command failed with an error message, invoke the error // event so observers can handle the error. if(!result) { vtkClientServerInterpreterErrorCallbackInfo info = {&css, message}; this->InvokeEvent(vtkCommand::UserEvent, &info); } return result; } //---------------------------------------------------------------------------- int vtkClientServerInterpreter ::ProcessCommandNew(const vtkClientServerStream& css, int midx) { // This command ignores any previous result. this->LastResultMessage->Reset(); // Make sure we have some instance creation functions registered. if(this->Internal->NewInstanceFunctions.empty()) { *this->LastResultMessage << vtkClientServerStream::Error << "Attempt to create object with no registered class wrappers." << vtkClientServerStream::End; return 0; } // Get the class name and desired ID for the instance. const char* cname = 0; vtkClientServerID id; if(css.GetNumberOfArguments(midx) == 2 && css.GetArgument(midx, 0, &cname) && css.GetArgument(midx, 1, &id)) { // Make sure the given ID is valid. if(id.ID == 0) { *this->LastResultMessage << vtkClientServerStream::Error << "Cannot create object with ID 0." << vtkClientServerStream::End; return 0; } // Make sure the ID doesn't exist. if(this->Internal->IDToMessageMap.find(id.ID) != this->Internal->IDToMessageMap.end()) { std::ostringstream error; error << "Attempt to create object with existing ID " << id.ID << "." << ends; *this->LastResultMessage << vtkClientServerStream::Error << error.str().c_str() << vtkClientServerStream::End; return 0; } // Find a NewInstance function that knows about the class. int created = 0; if(this->Internal->NewInstanceFunctions.count(cname)) { const vtkClientServerInterpreterInternals::NewInstanceFunction* n = this->Internal->NewInstanceFunctions[cname]; vtkClientServerNewInstanceFunction function = n->Function; void* ctx = n->Context ? n->Context->Context : 0; this->NewInstance(function(ctx),id); created =1; } if(created) { // Object was created. Notify observers. vtkClientServerInterpreter::NewCallbackInfo info; info.Type = cname; info.ID = id.ID; this->InvokeEvent(vtkCommand::UserEvent+1, &info); return 1; } else { // Object was not created. std::ostringstream error; error << "Cannot create object of type \"" << cname << "\"." << ends; *this->LastResultMessage << vtkClientServerStream::Error << error.str().c_str() << vtkClientServerStream::End; } } else { *this->LastResultMessage << vtkClientServerStream::Error << "Invalid arguments to vtkClientServerStream::New. " "There must be exactly two arguments. The first must be a string and " "the second an id." << vtkClientServerStream::End; } return 0; } //---------------------------------------------------------------------------- int vtkClientServerInterpreter ::ProcessCommandInvoke(const vtkClientServerStream& css, int midx) { // Create a message with all known id_value arguments expanded. vtkClientServerStream msg; if(!this->ExpandMessage(css, midx, 0, msg)) { // ExpandMessage left an error in the LastResultMessage for us. return 0; } // Now that id_values have been expanded, we do not need the last // result. Reset the result to empty before processing the message. this->LastResultMessage->Reset(); // Get the object and method to be invoked. vtkObjectBase* obj; const char* method; if(msg.GetNumberOfArguments(0) >= 2 && msg.GetArgument(0, 0, &obj) && msg.GetArgument(0, 1, &method)) { // Log the expanded form of the message. if(this->LogStream) { *this->LogStream << "Invoking "; msg.Print(*this->LogStream); this->LogStream->flush(); } // Find the command function for this object's type. if(obj && this->HasCommandFunction(obj->GetClassName())) { if (this->CallCommandFunction(obj->GetClassName(), obj, method, msg, *this->LastResultMessage)) { return 1; } } else { // Command function was not found for the class. std::ostringstream error; const char* cname = obj? obj->GetClassName():"(vtk object is NULL)"; error << "Wrapper function not found for class \"" << cname << "\"." << ends; *this->LastResultMessage << vtkClientServerStream::Error << error.str().c_str() << vtkClientServerStream::End; } } else { *this->LastResultMessage << vtkClientServerStream::Error << "Invalid arguments to vtkClientServerStream::Invoke. " "There must be at least two arguments. The first must be an object " "and the second a string." << vtkClientServerStream::End; } return 0; } //---------------------------------------------------------------------------- int vtkClientServerInterpreter ::ProcessCommandDelete(const vtkClientServerStream& msg, int midx) { // This command ignores any previous result. if(this->LastResultMessage == NULL) { return 0; } this->LastResultMessage->Reset(); // Get the ID to delete. vtkClientServerID id; if(msg.GetNumberOfArguments(midx) == 1 && msg.GetArgument(midx, 0, &id)) { // Make sure the given ID is valid. if(id.ID == 0) { *this->LastResultMessage << vtkClientServerStream::Error << "Cannot delete object with ID 0." << vtkClientServerStream::End; return 0; } // Find the ID in the map. vtkClientServerStream* item = 0; vtkClientServerInterpreterInternals::IDToMessageMapType::iterator itemi; itemi = this->Internal->IDToMessageMap.find(id.ID); if(itemi != this->Internal->IDToMessageMap.end()) { item = itemi->second; } else { *this->LastResultMessage << vtkClientServerStream::Error << "Attempt to delete ID that does not exist." << vtkClientServerStream::End; return 0; } // If the value is an object, notify observers of deletion. vtkObjectBase* obj; if(item->GetArgument(0, 0, &obj) && obj) { vtkClientServerInterpreter::NewCallbackInfo info; info.Type = obj->GetClassName(); info.ID = id.ID; this->InvokeEvent(vtkCommand::UserEvent+2, &info); } // Remove the ID from the map. this->Internal->IDToMessageMap.erase(id.ID); // Delete the entry's value. delete item; return 1; } else { *this->LastResultMessage << vtkClientServerStream::Error << "Invalid arguments to vtkClientServerStream::Delete. " "There must be exactly one argument and it must be an id." << vtkClientServerStream::End; } return 0; } //---------------------------------------------------------------------------- int vtkClientServerInterpreter ::ProcessCommandAssign(const vtkClientServerStream& css, int midx) { // Create a message with all known id_value arguments expanded // except for the first argument. vtkClientServerStream msg; if(!this->ExpandMessage(css, midx, 1, msg)) { // ExpandMessage left an error in the LastResultMessage for us. return 0; } // Now that id_values have been expanded, we do not need the last // result. Reset the result to empty before processing the message. this->LastResultMessage->Reset(); // Make sure the first argument is an id. vtkClientServerID id; if(msg.GetNumberOfArguments(0) >= 1 && msg.GetArgument(0, 0, &id)) { // Make sure the given ID is valid. if(id.ID == 0) { *this->LastResultMessage << vtkClientServerStream::Error << "Cannot assign to ID 0." << vtkClientServerStream::End; return 0; } // Make sure the ID doesn't exist. if(this->Internal->IDToMessageMap.find(id.ID) != this->Internal->IDToMessageMap.end()) { std::ostringstream error; error << "Attempt to assign existing ID " << id.ID << "." << ends; *this->LastResultMessage << vtkClientServerStream::Error << error.str().c_str() << vtkClientServerStream::End; return 0; } // Copy the expanded message to the result message except for the // first argument. *this->LastResultMessage << vtkClientServerStream::Reply; for(int a=1; a < msg.GetNumberOfArguments(0); ++a) { *this->LastResultMessage << msg.GetArgument(0, a); } *this->LastResultMessage << vtkClientServerStream::End; // Copy the result to store it in the map. The result itself // remains unchanged. vtkClientServerStream* tmp; tmp = new vtkClientServerStream(*this->LastResultMessage, this); this->Internal->IDToMessageMap[id.ID] = tmp; return 1; } else { this->LastResultMessage->Reset(); *this->LastResultMessage << vtkClientServerStream::Error << "Invalid arguments to vtkClientServerStream::Assign. " "There must be at least one argument and it must be an id." << vtkClientServerStream::End; } return 0; } //---------------------------------------------------------------------------- int vtkClientServerInterpreter::ExpandMessage(const vtkClientServerStream& in, int inIndex, int startArgument, vtkClientServerStream& out) { // Reset the output and make sure we have input. out.Reset(); if(inIndex < 0 || inIndex >= in.GetNumberOfMessages()) { std::ostringstream error; error << "ExpandMessage called to expand message index " << inIndex << " in a stream with " << in.GetNumberOfMessages() << " messages." << ends; this->LastResultMessage->Reset(); *this->LastResultMessage << vtkClientServerStream::Error << error.str().c_str() << vtkClientServerStream::End; return 0; } // Copy the command. out << in.GetCommand(inIndex); // Just copy the first arguments. int a; for(a=0; a < startArgument && a < in.GetNumberOfArguments(inIndex); ++a) { out << in.GetArgument(inIndex, a); } // Expand id_value for remaining arguments. for(a=startArgument; a < in.GetNumberOfArguments(inIndex); ++a) { if(in.GetArgumentType(inIndex, a) == vtkClientServerStream::id_value) { vtkClientServerID id; in.GetArgument(inIndex, a, &id); // If the ID is in the map, expand it. Otherwise, leave it. if(const vtkClientServerStream* tmp = this->GetMessageFromID(id)) { for(int b=0; b < tmp->GetNumberOfArguments(0); ++b) { out << tmp->GetArgument(0, b); } } else { out << in.GetArgument(inIndex, a); } } else if(in.GetArgumentType(inIndex, a) == vtkClientServerStream::LastResult) { // Insert the last result value. for(int b=0; b < this->LastResultMessage->GetNumberOfArguments(0); ++b) { out << this->LastResultMessage->GetArgument(0, b); } } else if (in.GetArgumentType(inIndex, a) == vtkClientServerStream::stream_value) { // Evaluate the expression and insert the result. vtkClientServerStream *lastResult = this->LastResultMessage; this->LastResultMessage = new vtkClientServerStream(); vtkClientServerStream substream; in.GetArgument(inIndex, a, &substream); if (this->ProcessStream(substream)) { // Insert the last result value. for(int b=0; b < this->LastResultMessage->GetNumberOfArguments(0); ++b) { out << this->LastResultMessage->GetArgument(0, b); } } // restore last-result delete this->LastResultMessage; this->LastResultMessage = lastResult; } else { // Just copy the argument. out << in.GetArgument(inIndex, a); } } // End the message. out << vtkClientServerStream::End; return 1; } //---------------------------------------------------------------------------- const vtkClientServerStream* vtkClientServerInterpreter::GetMessageFromID(vtkClientServerID id) { // Find the message in the map. vtkClientServerInterpreterInternals::IDToMessageMapType::iterator tmp; tmp = this->Internal->IDToMessageMap.find(id.ID); if(id.ID > 0 && tmp != this->Internal->IDToMessageMap.end()) { return tmp->second; } else { return 0; } } //---------------------------------------------------------------------------- const vtkClientServerStream& vtkClientServerInterpreter::GetLastResult() const { return *this->LastResultMessage; } //---------------------------------------------------------------------------- int vtkClientServerInterpreter::NewInstance(vtkObjectBase* obj, vtkClientServerID id) { // Store the object in the last result. this->LastResultMessage->Reset(); *this->LastResultMessage << vtkClientServerStream::Reply << obj << vtkClientServerStream::End; // Last result holds a reference. Remove reference from ::New() // call in generated code. obj->Delete(); // Copy the result to store it in the map. The result itself // remains unchanged. The ProcessCommandNew method already checked // that the id does not exist in the map, so the insertion does not // have to be checked. vtkClientServerStream* entry = new vtkClientServerStream(*this->LastResultMessage, this); this->Internal->IDToMessageMap[id.ID] = entry; return 1; } //---------------------------------------------------------------------------- class vtkClientServerInterpreterCommand: public vtkCommand { public: static vtkClientServerInterpreterCommand* New() { return new vtkClientServerInterpreterCommand; } void Execute(vtkObject*, unsigned long, void *) { this->Interpreter->ProcessStream(this->Stream); } vtkClientServerStream Stream; vtkClientServerInterpreter* Interpreter; protected: vtkClientServerInterpreterCommand() {} ~vtkClientServerInterpreterCommand() {} private: vtkClientServerInterpreterCommand(const vtkClientServerInterpreterCommand&); void operator=(const vtkClientServerInterpreterCommand&); }; int vtkClientServerInterpreter::NewObserver(vtkObject* obj, const char* event, const vtkClientServerStream& css) { // Create the command object and add the observer. vtkClientServerInterpreterCommand* cmd = vtkClientServerInterpreterCommand::New(); cmd->Stream = css; cmd->Interpreter = this; unsigned long id = obj->AddObserver(event, cmd); cmd->Delete(); // Store the observer id as the last result. this->LastResultMessage->Reset(); *this->LastResultMessage << vtkClientServerStream::Reply << id << vtkClientServerStream::End; return 1; } //---------------------------------------------------------------------------- void vtkClientServerInterpreter ::AddCommandFunction(const char* cname, vtkClientServerCommandFunction func, void* ctx, vtkContextFreeFunction freeFunction) { vtkClientServerInterpreterInternals::ClassToFunctionMapType::const_iterator it = this->Internal->ClassToFunctionMap.find(cname); if(it != this->Internal->ClassToFunctionMap.end()) { if(it->second->Context == ctx && it->second->Function == func) { // we already have this EXACT definition available so don't add return; } vtkErrorMacro("Ignoring duplicate command function for " << cname); return; } vtkClientServerInterpreterInternals::ContextInformation* context = NULL; if(ctx || freeFunction) { context = new vtkClientServerInterpreterInternals::ContextInformation(ctx, freeFunction); } this->Internal->ClassToFunctionMap[cname] = new vtkClientServerInterpreterInternals::CommandFunction(func, context); } //---------------------------------------------------------------------------- bool vtkClientServerInterpreter::HasCommandFunction(const char* cname) { if (!cname) { return false; } return (this->Internal->ClassToFunctionMap.count(cname) > 0); } //---------------------------------------------------------------------------- int vtkClientServerInterpreter::CallCommandFunction(const char* cname, vtkObjectBase* ptr, const char* method, const vtkClientServerStream& msg, vtkClientServerStream& result) { vtkClientServerInterpreterInternals::ClassToFunctionMapType::const_iterator f = this->Internal->ClassToFunctionMap.find(cname); if (f == this->Internal->ClassToFunctionMap.end()) { vtkErrorMacro("Cannot find command function for \"" << cname << "\"."); return 1; } const vtkClientServerInterpreterInternals::CommandFunction* n = f->second; vtkClientServerCommandFunction function = n->Function; void* ctx = n->Context ? n->Context->Context : 0; return function(this, ptr, method, msg, result, ctx); } void vtkClientServerInterpreter::AddNewInstanceFunction(const char* name, vtkClientServerNewInstanceFunction f, void* ctx, vtkContextFreeFunction freeFunction) { vtkClientServerInterpreterInternals::NewInstanceFunctionsType::const_iterator it= this->Internal->NewInstanceFunctions.find(name); if(it != this->Internal->NewInstanceFunctions.end()) { if(it->second->Context == ctx && it->second->Function == f) { // we already have this EXACT definition available so don't add return; } vtkErrorMacro("Ignoring duplicate instance function for " << name); return; } vtkClientServerInterpreterInternals::ContextInformation* context = NULL; if(ctx || freeFunction) { context = new vtkClientServerInterpreterInternals::ContextInformation(ctx, freeFunction); } this->Internal->NewInstanceFunctions[name] = new vtkClientServerInterpreterInternals::NewInstanceFunction(f, context); } //---------------------------------------------------------------------------- int vtkClientServerInterpreter::Load(const char* moduleName) { int ret = LoadImpl(moduleName); if (ret) { ret = this->Load(moduleName, 0); } return ret; } //---------------------------------------------------------------------------- static void vtkClientServerInterpreterSplit(const char* path, char split, char slash, std::vector& paths) { std::string str = path?path:""; std::string::size_type lpos = 0; std::string::size_type rpos = str.npos; while((rpos = str.find(split, lpos)) != str.npos) { if(lpos < rpos) { std::string dir = str.substr(lpos, rpos-lpos); if(*(dir.end()-1) != slash) { dir += slash; } paths.push_back(dir); } lpos = rpos+1; } if(lpos < str.length()) { std::string dir = str.substr(lpos); if(*(dir.end()-1) != slash) { dir += slash; } paths.push_back(dir); } } //---------------------------------------------------------------------------- int vtkClientServerInterpreter::Load(const char* moduleName, const char*const* optionalPaths) { // The library search path. typedef std::vector PathsType; PathsType paths; // Try user-specified paths if any. if(optionalPaths) { for(const char*const* p = optionalPaths; *p; ++p) { std::string path = *p; if(path.length() > 0) { char end = *(path.end()-1); if(end != '/' && end != '\\') { path += "/"; } paths.push_back(path); } } } // Try system paths. #if defined(_WIN32) && !defined(__CYGWIN__) vtkClientServerInterpreterSplit(getenv("PATH"), ';', '\\', paths); #else vtkClientServerInterpreterSplit(getenv("LD_LIBRARY_PATH"), ':', '/', paths); vtkClientServerInterpreterSplit(getenv("PATH"), ':', '/', paths); paths.push_back("/usr/lib/"); paths.push_back("/usr/lib/vtk/"); paths.push_back("/usr/local/lib/"); paths.push_back("/usr/local/lib/vtk/"); #endif // Search for the module. std::string searched; std::string libName = vtkDynamicLoader::LibPrefix(); libName += moduleName; libName += vtkDynamicLoader::LibExtension(); for(PathsType::iterator p = paths.begin(); p != paths.end(); ++p) { struct stat data; std::string fullPath = *p; #if defined(CMAKE_INTDIR) // Look in the subdirectory for the configuration in which this // interpreter was built. std::string fullPathWithIntDir = fullPath; fullPathWithIntDir += CMAKE_INTDIR "/"; fullPathWithIntDir += libName; if(stat(fullPathWithIntDir.c_str(), &data) == 0) { return this->LoadInternal(moduleName, fullPathWithIntDir.c_str()); } searched += p->substr(0, p->length()-1); searched += "/" CMAKE_INTDIR; searched += "\n"; #endif // Look in the directory specified. fullPath += libName; if(stat(fullPath.c_str(), &data) == 0) { return this->LoadInternal(moduleName, fullPath.c_str()); } searched += p->substr(0, p->length()-1); searched += "\n"; } vtkErrorMacro("Cannot find module \"" << libName.c_str() << "\". " << "The following paths were searched:\n" << searched.c_str()); return 0; } //---------------------------------------------------------------------------- int vtkClientServerInterpreter::LoadInternal(const char* moduleName, const char* fullPath) { // The type of a module initializer function. typedef void (*InitFunction)(vtkClientServerInterpreter*); // Load the library dynamically. vtkLibHandle lib = vtkDynamicLoader::OpenLibrary(fullPath); if(!lib) { vtkErrorMacro("Cannot load module \"" << moduleName << "\" from \"" << fullPath << "\"."); const char* error = vtkDynamicLoader::LastError(); if (error) { vtkErrorMacro(<(&pfunc); if(!func) { vtkErrorMacro("Cannot find function \"" << initFuncName.c_str() << "\" in \"" << fullPath << "\"."); return 0; } // Call the init function. func(this); return 1; } //---------------------------------------------------------------------------- void vtkClientServerInterpreter::ClearLastResult() { this->LastResultMessage->Reset(); } //---------------------------------------------------------------------------- vtkClientServerID vtkClientServerInterpreter::GetNextAvailableId() { return vtkClientServerID(++this->NextAvailableId); } //---------------------------------------------------------------------------- vtkObjectBase* vtkClientServerInterpreter::NewInstance(const char* classname) { if(!this->Internal->NewInstanceFunctions.count(classname)) { return NULL; } const vtkClientServerInterpreterInternals::NewInstanceFunction* n = this->Internal->NewInstanceFunctions[classname]; vtkClientServerNewInstanceFunction function = n->Function; void* ctx = n->Context ? n->Context->Context : 0; return function(ctx); } //---------------------------------------------------------------------------- void vtkClientServerInterpreter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); }