#include <cpPlugins/Interface.h>
-#include <map>
-#include <set>
-#include <string>
-
#ifdef cpPlugins_SYS_WINDOWS
+# include <Windows.h>
#else // cpPlugins_SYS_WINDOWS
# include <dlfcn.h>
#endif // cpPlugins_SYS_WINDOWS
-
+#include <cpPlugins_dirent.h>
// -------------------------------------------------------------------------
cpPlugins::Interface::
return( this->m_Filters );
}
+// -------------------------------------------------------------------------
+bool cpPlugins::Interface::
+LoadConfiguration( const std::string& filename )
+{
+ std::ifstream in( filename.c_str( ) );
+ if( !in )
+ return( false );
+
+ this->UnloadAll( );
+ std::string line;
+ while( std::getline( in, line ) )
+ {
+ try
+ {
+ this->LoadPluginFile( line );
+ }
+ catch( ... )
+ {
+ // Do nothing
+
+ } // yrt
+
+ } // elihw
+ return( true );
+}
+
+// -------------------------------------------------------------------------
+bool cpPlugins::Interface::
+SaveConfiguration( const std::string& filename ) const
+{
+ std::ofstream out( filename.c_str( ) );
+ if( !out )
+ return( false );
+ auto dIt = this->m_DynLibraries.begin( );
+ for( ; dIt != this->m_DynLibraries.end( ); ++dIt )
+ out << dIt->first << std::endl;
+ out.close( );
+ return( true );
+}
+
// -------------------------------------------------------------------------
void cpPlugins::Interface::
LoadPluginFile( const std::string& filename )
{
+ // Open library with its canonical path name
auto canonical_fn = cpPlugins::PathHelper::CanonicalPath( filename );
- void* hnd = NULL;
- std::map< std::string, std::set< std::string > > filters;
-#ifdef cpPlugins_SYS_WINDOWS
- // TODO:
-#else // cpPlugins_SYS_WINDOWS
+ if( canonical_fn == "" )
+ throw std::runtime_error(
+ std::string( "cpPlugins::Interface: Library \"" ) +
+ filename +
+ std::string( "\" does not exist." )
+ );
+
+ // Check if it was already loaded
+ if( this->m_DynLibraries.find( canonical_fn ) != this->m_DynLibraries.end( ) )
+ return;
- // Try to load canonical filename and clean error messages
- hnd = dlopen( canonical_fn.c_str( ), RTLD_NOW | RTLD_GLOBAL );
+ // Ok, try to load the library
+ void* hnd = Self::_DLOpen( canonical_fn );
if( hnd == NULL )
throw std::runtime_error(
std::string( "cpPlugins::Interface: Could not load library \"" ) +
- canonical_fn +
+ filename +
std::string( "\"" )
);
- dlerror( );
- // Init plugins
- typedef const std::map< std::string, std::set< std::string > > ( *func_t )( );
- auto func = ( func_t ) dlsym( hnd, "LoadedFilters" );
- const char* func_error = dlerror( );
- if( func_error != NULL )
- {
- dlclose( hnd );
- throw std::runtime_error(
- std::string( "cpPlugins::Interface: Library \"" ) +
- canonical_fn +
- std::string( "\" not recognized as a cpPlugins library." )
- );
+ // Load filters
+ TFilters filters = Self::_DLGetFilters( hnd );
- } // fi
- filters = func( );
-#endif // cpPlugins_SYS_WINDOWS
- if( hnd != NULL )
+ // Save the loaded filters info
+ bool save_handler = false;
+ for( auto catIt = filters.begin( ); catIt != filters.end( ); ++catIt )
{
- // Save the loaded filters names
- for( auto cIt = filters.begin( ); cIt != filters.end( ); ++cIt )
+ // Check if the filter is completely new
+ auto act_catIt = this->m_Filters.find( catIt->first );
+ for(
+ auto clsIt = catIt->second.begin( );
+ clsIt != catIt->second.end( );
+ ++clsIt
+ )
{
- auto colIt = this->m_Filters.find( cIt->first );
- for( auto fIt = cIt->second.begin( ); fIt != cIt->second.end( ); ++fIt )
+ bool new_filter = true;
+ if( act_catIt != this->m_Filters.end( ) )
+ new_filter =
+ ( act_catIt->second.find( *clsIt ) == act_catIt->second.end( ) );
+
+ // Ok, it is new
+ if( new_filter )
{
- bool found = false;
- if( colIt != this->m_Filters.end( ) )
+ // Update filters container
+ auto creator = Self::_DLGetCreator( hnd, catIt->first, *clsIt );
+ if( creator != NULL )
{
- auto rowIt = colIt->second.find( *fIt );
- if( rowIt != colIt->second.end( ) )
- found = true;
+ this->m_DynFilters[ catIt->first][ *clsIt ] =
+ TDynFunc( canonical_fn, creator );
+ this->m_Filters[ catIt->first ].insert( *clsIt );
+ save_handler = true;
} // fi
- if( !found )
- this->m_Filters[ cIt->first ][ *fIt ] = canonical_fn;
- } // rof
+ } // fi
} // rof
- // Save the hnd
- this->m_Plugins[ canonical_fn ] = hnd;
+ } // rof
+
+ // Keep dynlib handler, if needed
+ if( save_handler )
+ this->m_DynLibraries[ canonical_fn ] = hnd;
+ else
+ Self::_DLClose( hnd );
+}
+
+// -------------------------------------------------------------------------
+unsigned int cpPlugins::Interface::
+LoadPluginDir( const std::string& dirname )
+{
+ DIR* dir;
+ struct dirent* ent;
+ unsigned int count = 0;
+ if( ( dir = opendir( dirname.c_str( ) ) ) != NULL )
+ {
+ while( ( ent = readdir( dir ) ) != NULL )
+ {
+ try
+ {
+ this->LoadPluginFile( ent->d_name );
+ count++;
+ }
+ catch( ... )
+ {
+ // Ignore errors
+ } // yrt
+ } // elihw
+ closedir( dir );
}
else
throw std::runtime_error(
- "cpPlugins::Interface: Operative system not yet supported."
+ std::string( "cpPlugins::Interface: Could not load directory " ) +
+ std::string( "\"" ) + dirname + std::string( "\"" )
);
+ return( count );
}
// -------------------------------------------------------------------------
void cpPlugins::Interface::
UnloadAll( )
{
- auto pIt = this->m_Plugins.begin( );
- for( ; pIt != this->m_Plugins.end( ); ++pIt )
- {
-#ifdef cpPlugins_SYS_WINDOWS
-#else // cpPlugins_SYS_WINDOWS
- dlclose( pIt->second );
-#endif // cpPlugins_SYS_WINDOWS
- } // rof
- this->m_Plugins.clear( );
+ for(
+ auto d = this->m_DynLibraries.begin( );
+ d != this->m_DynLibraries.end( );
+ ++d
+ )
+ Self::_DLClose( d->second );
+ this->m_DynLibraries.clear( );
+ this->m_DynFilters.clear( );
this->m_Filters.clear( );
}
cpPlugins::ProcessObject::Pointer cpPlugins::Interface::
Create( const std::string& category, const std::string& name )
{
- cpPlugins::ProcessObject::Pointer filter;
- auto cIt = this->m_Filters.find( category );
- if( cIt != this->m_Filters.end( ) )
+ typedef cpPlugins::ProcessObject::Pointer _TPointer;
+ _TPointer filter = NULL;
+ auto catIt = this->m_DynFilters.find( category );
+ if( catIt != this->m_DynFilters.end( ) )
{
- auto nIt = cIt->second.find( name );
- if( nIt != cIt->second.end( ) )
- {
- auto pIt = this->m_Plugins.find( nIt->second );
- if( pIt != this->m_Plugins.end( ) )
- {
+ auto clsIt = catIt->second.find( name );
+ if( clsIt != catIt->second.end( ) )
+ filter =
+ ( reinterpret_cast< _TPointer* >( clsIt->second.second( ) ) )->
+ GetPointer( );
+
+ } // fi
+ return( filter );
+}
+
+// -------------------------------------------------------------------------
+void* cpPlugins::Interface::
+_DLOpen( const std::string& fname )
+{
+ void* hnd = NULL;
#ifdef cpPlugins_SYS_WINDOWS
+ hnd = ::LoadLibraryA( fname.c_str( ) );
#else // cpPlugins_SYS_WINDOWS
- std::string func_name = category + "_" + name;
- typedef cpPlugins::ProcessObject::Pointer ( *func_t )( );
- auto func = ( func_t ) dlsym( pIt->second, func_name.c_str( ) );
- if( func == NULL )
- {
- throw std::runtime_error(
- std::string( "cpPlugins::Interface: Class \"" ) +
- category + std::string( ":" ) + name +
- std::string( "\" does not have a valid creator function." )
- );
-
- } // fi
- filter = func( );
+ hnd = dlopen( fname.c_str( ), RTLD_NOW | RTLD_GLOBAL );
+ dlerror( );
#endif // cpPlugins_SYS_WINDOWS
- } // fi
+ return( hnd );
+}
- } // fi
+// -------------------------------------------------------------------------
+cpPlugins::Interface::
+TFilters cpPlugins::Interface::
+_DLGetFilters( void* hnd )
+{
+ // Get descriptors
+ typedef const char* ( *f_t )( );
+ f_t f = NULL;
+#ifdef cpPlugins_SYS_WINDOWS
+ f = ( f_t )( ::GetProcAddress( ( HMODULE )hnd, "cpPlugins_LoadedFilters" ) );
+#else // cpPlugins_SYS_WINDOWS
+ f = ( f_t )( dlsym( hnd, "cpPlugins_LoadedFilters" ) );
+#endif // cpPlugins_SYS_WINDOWS
+ if( f == NULL )
+ {
+ Self::_DLClose( hnd );
+ throw std::runtime_error(
+ "cpPlugins::Interface: Library not recognized as a cpPlugins library: "
+ );
} // fi
- return( filter );
+ std::string descriptors = f( );
+
+ // Demangle descriptors
+ TFilters filters;
+ std::replace( descriptors.begin( ), descriptors.end( ), ';', ' ' );
+ std::istringstream str( descriptors );
+ while( str )
+ {
+ std::string value, category, name;
+ str >> value;
+ if( value == "" )
+ continue;
+ std::replace( value.begin( ), value.end( ), ':', ' ' );
+ std::istringstream value_str( value );
+ value_str >> category >> name;
+ filters[ category ].insert( name );
+
+ } // elihw
+ return( filters );
+}
+
+// -------------------------------------------------------------------------
+cpPlugins::Interface::
+TCreator cpPlugins::Interface::
+_DLGetCreator(
+ void* hnd, const std::string& category, const std::string& name
+ )
+{
+ TCreator c = NULL;
+ std::string func_name = category + "_" + name;
+#ifdef cpPlugins_SYS_WINDOWS
+ c = ( TCreator )( ::GetProcAddress( ( HMODULE )hnd, func_name.c_str( ) ) );
+#else // cpPlugins_SYS_WINDOWS
+ c = ( TCreator )( dlsym( hnd, func_name.c_str( ) ) );
+#endif // cpPlugins_SYS_WINDOWS
+ if( c == NULL )
+ throw std::runtime_error(
+ std::string( "cpPlugins::Interface: Class \"" ) +
+ category + std::string( ":" ) + name +
+ std::string( "\" does not have a valid creator function." )
+ );
+ return( c );
+}
+
+// -------------------------------------------------------------------------
+void cpPlugins::Interface::
+_DLClose( void* hnd )
+{
+#ifdef cpPlugins_SYS_WINDOWS
+ ::FreeLibrary( ( HMODULE )hnd );
+#else // cpPlugins_SYS_WINDOWS
+ dlclose( hnd );
+#endif // cpPlugins_SYS_WINDOWS
}
// eof - $RCSfile$