inlib  1.2.0
/Users/barrand/private/dev/softinex/old/inexlib-1.2/inlib/inlib/sys/plugin
Go to the documentation of this file.
00001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
00002 // See the file inlib.license for terms.
00003 
00004 #ifndef inlib_sys_plugin
00005 #define inlib_sys_plugin
00006 
00007 #include "../smanip"
00008 
00009 #include <ostream>
00010 #include <cstdlib>
00011 #include <cstring> //memcpy
00012 
00013 #ifdef WIN32
00014 #include <windows.h>
00015 #else
00016 #include <dlfcn.h>
00017 #endif
00018 
00019 namespace inlib {
00020 
00021 class plugin {
00022 public:
00023   plugin(const std::string& a_name,std::ostream& a_out,bool a_verbose = false,bool a_quiet = false)
00024   :m_module(0)
00025   ,m_out(a_out)
00026   ,m_name(a_name)
00027   ,m_verbose(a_verbose)
00028   {
00029     // a_name is the full name (path + libname).
00030     if(!open()) {
00031       if(!a_quiet) {
00032         m_out << "inlib::plugin :" 
00033               << " can't load " << sout(m_name) << " library." << std::endl;
00034         m_out << "inlib::plugin :" 
00035               << " error  : " << m_error 
00036               << std::endl;
00037       }
00038     }
00039   }
00040 
00041   virtual ~plugin(){close();}
00042 
00043 protected:
00044   plugin(const plugin& a_from):m_out(a_from.m_out){}
00045   plugin& operator=(const plugin&){return *this;}
00046 
00047 public:
00048   bool open() {
00049     m_error = "";
00050     std::string splg = m_name;  
00051     if(m_verbose) {
00052       m_out << "inlib::plugin :" 
00053             << " open " 
00054             << sout(splg) << "..." << std::endl;
00055     }
00056 #ifdef WIN32
00057     m_module = ::LoadLibrary(splg.c_str());
00058 #else
00059    {std::string path,name,sfx;
00060     path_name_suffix(m_name,path,name,sfx);
00061     if(path.empty()) { //Relative path
00062       std::string sfx = suffix(splg);
00063       if(sfx.empty()) {
00064         // Only the name "Xxx" had been given, we have to
00065 #if defined(__CYGWIN__) && defined(__GNUC__)
00066         // build the name "Xxx.dll" :      
00067         splg = m_name + ".dll";
00068 #elif defined(__APPLE__)
00069         splg = m_name + ".bundle";
00070 #else
00071         // build the name "libXxx.so" :      
00072         splg = "lib" + m_name + ".so";
00073 #endif
00074       }
00075     }}
00076     int flags = RTLD_NOW | RTLD_GLOBAL;
00077     m_module = ::dlopen(splg.c_str(),flags);
00078 #if defined(__APPLE__)
00079     if(!m_module) {
00080       std::vector<std::string> ps = paths(); 
00081       unsigned int pathn = ps.size();
00082       for(unsigned int index=0;index<pathn;index++) {
00083         splg = ps[index]+"/" + m_name + ".bundle";
00084         if(m_verbose) {
00085           m_out << "inlib::plugin::open :" 
00086                 << " open " 
00087                 << sout(splg) << "..." 
00088                 << std::endl;
00089         }
00090         m_module = ::dlopen(splg.c_str(),flags);
00091         if(m_module) break;
00092       }
00093     }
00094 #endif
00095     const char* cerror;
00096     if ((cerror=dlerror())!=NULL) m_error = cerror;
00097 #endif
00098     if(!m_module) return false;
00099     if(m_verbose) {
00100       m_out << "inlib::plugin :" 
00101             << " " << sout(splg) << " opened." << std::endl;
00102     }
00103     m_plugin = splg;  
00104     return true;
00105   }
00106 
00107   void close(){
00108     if(!m_module) return; //done
00109     if(m_verbose) {
00110       m_out << "inlib::close :" 
00111             << " close " << sout(m_name) << "..." << std::endl;
00112     }
00113 #ifdef WIN32
00114     ::FreeLibrary((HMODULE)m_module);
00115 #else
00116     if(::dlclose(m_module)) {
00117       m_out << "inlib::~plugin :" 
00118             << " error  : " << ::dlerror() << std::endl;
00119     }
00120 #endif
00121     if(m_verbose) {
00122       m_out << "inlib::~plugin :" 
00123             << " close " << sout(m_name) << " done." << std::endl;
00124     }
00125     m_module = 0;
00126   }
00127 
00128   bool is_opened() const {return m_module?true:false;}
00129 
00130   const std::string& file_name() const{return m_name;}
00131 
00132   typedef void (*procedure)();
00133 
00134   procedure find(const std::string& a_name,bool a_quiet = false) const {
00135     if(!m_module) return 0;
00136     std::string name = a_name;
00137     procedure p = 0;
00138     if(m_verbose) {
00139       m_out << "inlib::find :" 
00140             << " search symbol " 
00141             << sout(name) << "..." << std::endl;
00142     }
00143 #ifdef WIN32
00144     p = (procedure)::GetProcAddress((HMODULE)m_module,name.c_str());
00145     if (!p) {
00146       name = "_" + a_name;
00147       p = (procedure)::GetProcAddress((HMODULE)m_module,name.c_str());
00148       if (!p) {
00149         if(!a_quiet) {
00150           m_out << "Lib : Can't find symbol " << sout(a_name) << "." 
00151                 << std::endl;
00152         }
00153       }
00154     }
00155 #else
00156     void* a = ::dlsym(m_module,(char*)name.c_str());
00157     //trick to avoid the warning :
00158     //ISO C++ forbids casting between pointer-to-function and pointer-to-object
00159     ::memcpy(&p,&a,sizeof(void*)); //beurk
00160 
00161     const char* cerror;
00162     if ((cerror=dlerror())!=NULL) {
00163       std::string serror = cerror;
00164       name = "_" + a_name;
00165       void* a = ::dlsym(m_module,(char*)name.c_str());
00166       ::memcpy(&p,&a,sizeof(void*)); //rebeurk
00167 
00168       if ((cerror=dlerror())!=NULL) {
00169         if(!a_quiet) {
00170           m_out << "inlib::find :" 
00171                 << " problem when searching " << sout(a_name)
00172                 << " in " << sout(m_plugin) << "."
00173                 << " dlerror  : " << serror << std::endl;
00174         } 
00175       } 
00176     }
00177 #endif
00178     if(p && m_verbose) {
00179       m_out << "inlib::find :" 
00180             << " symbol " << sout(name) << " found." << std::endl;
00181     }
00182     return p;
00183   }
00184 
00185 public:
00186   static bool is_valid(const std::string& a_name,std::ostream& a_out) {
00187     plugin plg(a_name,a_out,0,true);
00188     bool status = plg.is_opened();
00189     plg.close();
00190     return status;
00191   }
00192 
00193 protected:
00194   static std::vector<std::string> paths() { //APPLE only.
00195     const char* env = ::getenv("DYLD_LIBRARY_PATH");
00196     if(!env) env = ::getenv("GDB_DYLD_LIBRARY_PATH");
00197     std::string senv = (env==NULL ? std::string("") : std::string(env));
00198     return words(senv,":");
00199   }
00200 
00201 protected:
00202   void* m_module;
00203   std::ostream& m_out;
00204   std::string m_name;
00205   std::string m_plugin;
00206   bool m_verbose;
00207   std::string m_error;
00208 };
00209 
00210 }
00211 
00212 #include <map>
00213 
00214 namespace inlib {
00215 
00216 class plugin_cache {
00217 public:
00218   virtual bool open(const std::string& a_name,plugin*& a_plugin){
00219     std::map<std::string,plugin*>::iterator it = m_cache.find(a_name);
00220     if(it!=m_cache.end()) { //a_name in the cache.
00221       a_plugin = (*it).second;
00222       return true;
00223     }
00224     a_plugin = new plugin(a_name,m_out);
00225     if(!a_plugin->is_opened()) {
00226       m_out << "inlib::can't open plugin " << a_name << std::endl;
00227       delete a_plugin;
00228       a_plugin = 0;
00229       return false;
00230     }
00231     m_cache[a_name] = a_plugin;
00232     return true;
00233   }
00234 public:
00235   plugin_cache(std::ostream& a_out)
00236   :m_out(a_out)
00237   {}
00238   virtual ~plugin_cache(){clear();}
00239 protected:
00240   plugin_cache(const plugin_cache& a_from)
00241   :m_out(a_from.m_out)
00242   {}
00243   plugin_cache& operator=(const plugin_cache&){return *this;}
00244 public:
00245   void clear() {
00246     std::map<std::string,plugin*>::iterator it;
00247     for(it = m_cache.begin();it!=m_cache.end();++it) {
00248       delete (*it).second;
00249     }
00250     m_cache.clear();
00251   }
00252 protected:
00253   std::ostream& m_out;
00254   std::map<std::string,plugin*> m_cache; 
00255 };
00256 
00257 
00258 }
00259 
00260 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines