Files
ThirdParty-6/ParaView-5.0.1/ParaViewCore/ClientServerStream/vtkClientServerInterpreter.cxx

1076 lines
32 KiB
C++

/*=========================================================================
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 <map>
#include <string>
#include <vector>
#include <sstream>
#include <sys/stat.h>
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 <typename FunctionType>
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<vtkClientServerNewInstanceFunction> NewInstanceFunction;
typedef FunctionWithContext<vtkClientServerCommandFunction> CommandFunction;
typedef std::map<std::string, const NewInstanceFunction*> NewInstanceFunctionsType;
typedef std::map<std::string, const CommandFunction*> ClassToFunctionMapType;
typedef std::map<vtkTypeUInt32, vtkClientServerStream*> 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<std::string>& 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<std::string> 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(<<error);
}
return 0;
}
// Get the init function.
std::string initFuncName = moduleName;
initFuncName += "_Initialize";
void* pfunc = vtkDynamicLoader::GetSymbolAddress(lib, initFuncName.c_str());
InitFunction func = *reinterpret_cast<InitFunction*>(&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);
}