//-- FILE:   plugin.h
//-- CODER:  KUBO Takuya (kubo@ees.hokudai.ac.jp)
//-- 
//-- (C)opyright 2000 KUBO Takuya (kubo@ees.hokudai.ac.jp).
//--    All rights are reserved.
//--    Do not modify without amending copyright,
//--    distribute freely but retain this paragraph.
//-- 
//-- CHANGE: Thu Aug 31 20:33:35 2000

#if !defined(___Class_PLUGIN)
#define ___Class_PLUGIN

#include        <string>
#include        <dlfcn.h>       // dlopen, dlsym, dlclose
#include        <unistd.h>      // unlink

using namespace std;

template <class ReturnType, class ParamType, class DataType>
class Plugin
{
private:
        ReturnType      ( *plugin_function )( ParamType&, DataType& );
        void*   DLSym( void*, const string&, const string& );
        void*   handle;
public:
        Plugin( const string&, const string& );
        ~Plugin( void ) { dlclose( handle ); };

        ReturnType      Val( ParamType& param, DataType& data ) {
                return ( *plugin_function )( param, data );
        }
};

// Constructor
template <class ReturnType, class ParamType, class DataType>
Plugin<ReturnType, ParamType, DataType>::Plugin(
        const string&   plugin_function_so,
        const string&   function_namekey
) :
handle( NULL )
{
        // dlopen
        handle = dlopen( plugin_function_so.c_str(), RTLD_LAZY );
        if ( !handle ) {
                cerr << dlerror() << endl;
                exit( 1 );
        }
        plugin_function = ( ReturnType ( * )( ParamType&, DataType& ) )
                DLSym( handle, plugin_function_so, function_namekey );
}

// DLSym : return void*
template <class ReturnType, class ParamType, class DataType>
void* Plugin<ReturnType, ParamType, DataType>::DLSym(
        void*   handle,
        const string&   plugin_function_so,
        const string&   function_namekey
) {
        // nm plugin_function_so | grep 'T function' > tmp_file
        string  tmp_file( "./tmp_tmp_tmp_file" );
        string  command( "nm " );
        command += plugin_function_so;
        command += " | grep 'T " + function_namekey + "' > " + tmp_file;
        system( command.c_str() );
        // A sample of 'nm | grep function' line
        // 000026e0 T function__FR10ParametersRt6vector2ZdZt9allocator1Zd

        // Reading tmp_file and get f_name
        ifstream        input_stream;
        input_stream.open( tmp_file.c_str(), ios::in );
        string  f_name, dummy;
        input_stream >> dummy >> dummy >> f_name;
        input_stream.close();
        unlink( tmp_file.c_str() ); // remove tmp_file

        // dlsym
        void*   pointer_to_function( dlsym( handle, f_name.c_str() ) );
        char*   error( dlerror() );
        if ( error != NULL ) {
                cerr << error << endl;
                exit( 1 );
        }
        return pointer_to_function;
}

#endif