C++ Library containing a lot of needful things: Stack Trace, Command Line Parser, Resource Handling, Configuration Files, Unix Command Execution, Directories, Regular Expressions, Tokenizer, Function Trace, Standard Extensions.
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
326 lines
11 KiB
326 lines
11 KiB
20 years ago
|
/** @file
|
||
|
|
||
|
$Id$
|
||
|
|
||
|
$Date$
|
||
|
$Author$
|
||
|
|
||
|
@copy © Marc Wäckerlin
|
||
|
@license LGPL, see file <a href="license.html">COPYING</a>
|
||
|
|
||
|
$Log$
|
||
20 years ago
|
Revision 1.3 2005/11/29 12:39:42 marc
|
||
|
make it compilable with gcc 4.0.2 and newer doxygen
|
||
|
|
||
20 years ago
|
Revision 1.2 2005/02/21 16:16:47 marc
|
||
|
finished and documented
|
||
|
|
||
20 years ago
|
Revision 1.1 2005/02/18 15:53:56 marc
|
||
|
initial release
|
||
|
|
||
|
|
||
|
1 2 3 4 5 6 7 8
|
||
|
5678901234567890123456789012345678901234567890123456789012345678901234567890
|
||
|
*/
|
||
|
|
||
|
#ifndef __MRW_DYNAMICLIBRARY_HPP__
|
||
|
#define __MRW_DYNAMICLIBRARY_HPP__
|
||
|
|
||
|
#include <ltdl.h>
|
||
14 years ago
|
#include <mrw/string.hxx>
|
||
|
#include <mrw/stdext.hxx>
|
||
|
#include <mrw/exception.hxx>
|
||
20 years ago
|
|
||
|
namespace mrw {
|
||
|
|
||
20 years ago
|
/** @defgroup dll Dynamic Library Loading (ltdl)
|
||
|
|
||
|
Implements a C++ wrapper around the Libtool's
|
||
|
platform independent dynamic library loading library named
|
||
|
libltdl. See <code>info libtool</code> for more
|
||
|
information.
|
||
|
|
||
|
Loading a symbol from a shared library:
|
||
|
|
||
|
@code
|
||
|
void fn() throw(mrw::DynamicLibrary::failure) {
|
||
|
static DynamicLibrary lib("libsomething");
|
||
|
static void(*theRealFunction)() =
|
||
|
(void(*)())lib.symbol("theRealFunction");
|
||
|
(*theRealFunction)(); // call the loaded function
|
||
|
}
|
||
|
@endcode
|
||
|
|
||
14 years ago
|
@pre \#include <mrw/dynamiclibrary.hxx>
|
||
20 years ago
|
|
||
|
@pre Files that use this wrapper must be linked with libltdl,
|
||
|
with GNU g++ on UNIX, this is link option: @c -lltdl
|
||
|
*/
|
||
|
//@{
|
||
|
|
||
|
//============================================================================
|
||
|
/** @brief Dynamic Library loaded from the filesystem at runtime.
|
||
|
|
||
|
This class is responsible for loading dynamic / shared
|
||
|
libraries from the filesystem and extract symbols, means
|
||
|
functions to assign them to function pointers that can then be
|
||
|
accessed.
|
||
|
|
||
|
@copydoc dll
|
||
|
*/
|
||
20 years ago
|
class DynamicLibrary {
|
||
20 years ago
|
|
||
|
//............................................................... typedefs
|
||
20 years ago
|
public:
|
||
20 years ago
|
/// failure in access to shared libraries
|
||
20 years ago
|
class failure: public mrw::runtime_error {
|
||
|
public:
|
||
|
failure(const std::string& arg) throw(std::bad_exception):
|
||
|
mrw::runtime_error("DynamicLibrary failure "+arg
|
||
|
+"; ltdl reason: "+
|
||
|
+mrw::ifelse(lt_dlerror(), "<none>")) {
|
||
|
}
|
||
|
};
|
||
20 years ago
|
|
||
|
//................................................................ methods
|
||
20 years ago
|
public:
|
||
20 years ago
|
|
||
|
/** @brief initialize, but open dynamic library later
|
||
|
@throw failure if initialisation fails
|
||
|
*/
|
||
20 years ago
|
DynamicLibrary() throw(std::exception): _opened(false) {
|
||
|
if (lt_dlinit()>0)
|
||
|
throw failure("cannot initialize dynamic library loader");
|
||
|
_opened = true;
|
||
|
}
|
||
20 years ago
|
|
||
|
/** @brief load a dynamic library from a file
|
||
|
|
||
|
It is not necessary to specify the extension, the system
|
||
|
dependant shared object / dynamic library extension is
|
||
|
automatically added. Also, if no path is given, the library
|
||
|
is automatically looked for in your system's library
|
||
|
paths. You can also specify additional paths to look in,
|
||
|
e.g. with addSearchDir.
|
||
|
|
||
|
@param lib the name of the library without the extension
|
||
|
@throw failure if initialisation fails
|
||
|
@throw failure if opeing the library fails
|
||
|
*/
|
||
20 years ago
|
DynamicLibrary(const std::string& lib) throw(std::exception):
|
||
|
_opened(false) {
|
||
|
if (lt_dlinit()>0)
|
||
|
throw failure("cannot initialize dynamic library loader");
|
||
|
_opened = true;
|
||
|
_lib.open(lib);
|
||
|
}
|
||
20 years ago
|
|
||
|
/// close and clean up
|
||
20 years ago
|
~DynamicLibrary() throw() {
|
||
|
try {close();} catch (...) {}
|
||
|
if (_opened) lt_dlexit();
|
||
|
}
|
||
20 years ago
|
|
||
|
/** @brief load a dynamic library from a file
|
||
|
|
||
|
It is not necessary to specify the extension, the system
|
||
|
dependant shared object / dynamic library extension is
|
||
|
automatically added. Also, if no path is given, the library
|
||
|
is automatically looked for in your system's library
|
||
|
paths. You can also specify additional paths to look in,
|
||
|
e.g. with addSearchDir.
|
||
|
|
||
|
@param lib the name of the library without the extension
|
||
|
@throw failure if opeing the library fails
|
||
|
*/
|
||
20 years ago
|
DynamicLibrary& open(const std::string& lib) throw(std::exception) {
|
||
|
_lib.open(lib);
|
||
|
return *this;
|
||
|
}
|
||
20 years ago
|
|
||
|
/** @brief close the dynamic library
|
||
|
@throw failure if the library was open and close failed
|
||
|
*/
|
||
20 years ago
|
DynamicLibrary& close() throw(std::exception) {
|
||
20 years ago
|
if (!isResident()) _lib.close();
|
||
20 years ago
|
return *this;
|
||
|
}
|
||
20 years ago
|
|
||
|
/** @brief make the library resident
|
||
|
|
||
|
Makes the library resident, so that it cannot be
|
||
|
closed. This can be useful if a module implements some core
|
||
|
functionality in your project, which would cause your code
|
||
|
to crash if removed.
|
||
|
|
||
|
@throw failure in case of an error
|
||
|
*/
|
||
20 years ago
|
DynamicLibrary& resident() throw(std::exception) {
|
||
|
if (lt_dlmakeresident(_lib.handle())!=0)
|
||
|
throw failure("cannot make library resident");
|
||
|
return *this;
|
||
|
}
|
||
20 years ago
|
|
||
|
/** @brief check whether the library is resident
|
||
|
@throw failure if the library is not open */
|
||
20 years ago
|
bool isResident() throw(std::exception) {
|
||
|
return lt_dlisresident(_lib.handle())==1;
|
||
|
}
|
||
20 years ago
|
|
||
|
/** @brief load a symbol from the library
|
||
|
|
||
|
@warning The symbol is returned as void* and must be
|
||
|
converted to the correct function pointer. If this
|
||
|
conversion is wrong, then your process will crash, or even
|
||
|
worse, behave in an unexpected way, so be careful!
|
||
|
*/
|
||
20 years ago
|
lt_ptr symbol(const std::string& name) throw(std::exception) {
|
||
|
lt_ptr sym(lt_dlsym(_lib.handle(), name.c_str()));
|
||
|
if (!sym)
|
||
|
throw failure("cannot load dynamic library symbol: "+name);
|
||
|
return sym;
|
||
|
}
|
||
20 years ago
|
|
||
|
/** register a list of preloaded modules
|
||
|
|
||
|
@code
|
||
|
const lt_dlsymlist symbols[] = {
|
||
|
{"symbol1", &fnptr1}, {"symbol2", &fnptr2}, 0
|
||
|
}
|
||
|
lib.preload(symbols);
|
||
|
@endcode
|
||
|
|
||
|
@param symbols a null terminated C array of structs of name
|
||
|
character pointer and function pointer
|
||
|
@note if symbols is @c 0, all previousely registered
|
||
|
symbols except the list set by preloadDefault are deleted
|
||
20 years ago
|
*/
|
||
20 years ago
|
DynamicLibrary& preload(const lt_dlsymlist symbols[])
|
||
20 years ago
|
throw(std::exception) {
|
||
|
if (lt_dlpreload(symbols)!=0)
|
||
|
throw failure("error in preloading libraries");
|
||
|
return *this;
|
||
|
}
|
||
20 years ago
|
|
||
|
/** register the default list of preloaded modules
|
||
|
|
||
|
@code
|
||
|
const lt_dlsymlist symbols[] = {
|
||
|
{"symbol1", &fnptr1}, {"symbol2", &fnptr2}, 0
|
||
|
}
|
||
|
lib.preloadDefault(symbols);
|
||
|
@endcode
|
||
|
|
||
|
@param symbols a null terminated C array of structs of name
|
||
|
character pointer and function pointer
|
||
20 years ago
|
*/
|
||
20 years ago
|
static void preloadDefault(const lt_dlsymlist symbols[])
|
||
20 years ago
|
throw(std::exception) {
|
||
|
if (lt_dlpreload_default(symbols)!=0)
|
||
|
throw failure("error in preloading libraries");
|
||
|
}
|
||
20 years ago
|
|
||
|
/** @brief set the default list of preloaded symbols */
|
||
|
static void preloadedSymbols() throw(std::bad_exception) {
|
||
|
LTDL_SET_PRELOADED_SYMBOLS();
|
||
20 years ago
|
}
|
||
20 years ago
|
|
||
|
/** @brief append a directory to the library search path */
|
||
20 years ago
|
static void addSearchDir(const std::string& dir) throw(std::exception) {
|
||
|
if (lt_dladdsearchdir(dir.c_str())!=0)
|
||
|
throw failure("cannot add search dir: "+dir);
|
||
|
}
|
||
20 years ago
|
|
||
|
/** @brief insert a directory at a given position to the library
|
||
|
search path */
|
||
20 years ago
|
static void insertSearchDir(const std::string& before,
|
||
|
const std::string& dir)
|
||
|
throw(std::exception) {
|
||
|
if (lt_dlinsertsearchdir(before.c_str(), dir.c_str())!=0)
|
||
|
throw failure("cannot add search dir: "+dir);
|
||
|
}
|
||
20 years ago
|
|
||
|
/** @brief set the library search path
|
||
|
|
||
|
The search path is a colon separated list of paths. */
|
||
|
static void setSearchPath(const std::string& dirs) throw() {
|
||
|
if (lt_dlsetsearchpath(dirs.c_str()))
|
||
|
throw failure("cannot set search path to "+dirs);
|
||
|
}
|
||
|
|
||
|
/** @brief get the library search path */
|
||
|
static std::string getSearchPath() throw() {
|
||
|
char const * const path(lt_dlgetsearchpath());
|
||
|
if (!path)
|
||
|
throw failure("cannot get search path");
|
||
|
return path;
|
||
|
}
|
||
|
|
||
|
/** @brief calls a callback function for all directories in a
|
||
|
search path
|
||
|
|
||
|
In some applications you may not want to load individual
|
||
|
modules with known names, but rather find all of the modules
|
||
|
in a set of directories and load them all during
|
||
|
initialisation. With this function you can have
|
||
|
DynamicLibrary scan the colon delimited directory list in
|
||
|
searchPath for candidates, and pass them, along with data to
|
||
|
your own callback function, function. If searchPath is @c 0,
|
||
|
then search all of the standard locations that open would
|
||
|
examine. This function will continue to make calls to
|
||
|
function for each file that it discovers in searchPath until
|
||
|
one of these calls returns non-zero, or until the files are
|
||
|
exhausted.
|
||
|
|
||
|
@return value returned by the last call made to function
|
||
|
*/
|
||
|
int foreachfile(const char* searchPath,
|
||
|
int(*function)(const char*, lt_ptr),
|
||
|
lt_ptr data) throw() {
|
||
|
return lt_dlforeachfile(searchPath, function, data);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
class Lib {
|
||
|
Lib() throw(): _lib(0) {}
|
||
|
Lib(const std::string& lib) throw(std::exception): _lib(0) {
|
||
|
open(lib);
|
||
|
}
|
||
|
~Lib() throw() {
|
||
|
try {close();} catch(...) {}
|
||
|
}
|
||
|
operator bool() throw() {
|
||
|
return _lib;
|
||
|
}
|
||
|
Lib& open(const std::string& lib) throw(std::exception) {
|
||
|
close();
|
||
|
if (!(_lib = lt_dlopenext(lib.c_str())))
|
||
|
throw failure("cannot open dynamic library "+lib);
|
||
|
return *this;
|
||
|
}
|
||
|
Lib& close() throw(std::exception) {
|
||
|
if (_lib && lt_dlclose(_lib)!=0)
|
||
|
throw failure("cannot close dynamic library");
|
||
|
_lib = 0;
|
||
|
return *this;
|
||
|
}
|
||
|
private:
|
||
|
friend class DynamicLibrary;
|
||
|
lt_dlhandle handle() throw(std::exception) {
|
||
|
if (!_lib)
|
||
|
throw failure("library not open");
|
||
|
return _lib;
|
||
|
}
|
||
|
private:
|
||
|
lt_dlhandle _lib;
|
||
|
};
|
||
20 years ago
|
private:
|
||
|
bool _opened;
|
||
|
Lib _lib;
|
||
|
};
|
||
20 years ago
|
|
||
|
//@}
|
||
20 years ago
|
}
|
||
|
|
||
|
#endif
|