Index: trunk/src/library.cc
===================================================================
--- trunk/src/library.cc	(revision 4)
+++ trunk/src/library.cc	(revision 4)
@@ -0,0 +1,127 @@
+// Copyright (C) 2012 Kornel Kisielewicz
+// This file is part of NV Libraries.
+// For conditions of distribution and use, see copyright notice in nv.hh
+
+#include "nv/library.hh"
+
+#include <string.h>
+
+#if NV_PLATFORM == NV_WINDOWS
+#   define WIN32_LEAN_AND_MEAN
+#   include <windows.h>
+#   define NV_LIB_EXT ".dll"
+#   define NV_LIB_HANDLE HMODULE
+#   define NV_LIB_OPEN( name ) LoadLibraryEx( name, NULL, LOAD_WITH_ALTERED_SEARCH_PATH )
+#   define NV_LIB_GET( handle, name ) GetProcAddress( handle, name )
+#   define NV_LIB_CLOSE( name ) !FreeLibrary( name )
+#elif NV_PLATFORM == NV_LINUX
+#   include <dlfcn.h>
+#   define NV_LIB_EXT ".so"
+#   define NV_LIB_HANDLE void*
+#   define NV_LIB_OPEN( name ) dlopen( name, RTLD_LAZY | RTLD_GLOBAL)
+#   define NV_LIB_GET( handle, name ) dlsym( handle, name )
+#   define NV_LIB_CLOSE( name ) dlclose( name )
+#elif NV_PLATFORM == NV_APPLE
+#   include "macUtils.h"
+#   include <dlfcn.h>
+#   define NV_LIB_EXT ".dylib"
+#   define NV_LIB_HANDLE CFBundleRef
+#   define NV_LIB_OPEN( name ) mac_loadExeBundle( name )
+#   define NV_LIB_GET( handle, name ) mac_getBundleSym( handle, name )
+#   define NV_LIB_CLOSE( name ) mac_unloadExeBundle( name )
+#endif
+
+#include "nv/logging.hh"
+
+using namespace nv;
+
+library::library( const std::string& name ) 
+    : m_name( name )
+{
+    m_handle = NULL;
+    open();
+}
+
+void library::open( const std::string& name )
+{
+	m_name = name;
+	open();
+}
+
+const std::string& library::get_name() const
+{
+    return m_name;
+}
+
+void library::open()
+{
+    if ( m_handle != NULL )
+    {
+        return;
+    }
+    NV_LOG( LOG_NOTICE, "library : loading '" + m_name + "'..." );
+
+    std::string name = m_name;
+    std::string ext  = NV_LIB_EXT;
+    size_t ext_len   = ext.length();
+
+    if ( name.length() < ext_len || name.substr( name.length() - ext_len, ext_len ) != ext ) 
+    {
+        name += ext;
+    }
+
+    m_handle = (void*)NV_LIB_OPEN( name.c_str() );
+
+    if ( m_handle == NULL )
+    {
+        throw library_error( "Can't load library!", name );
+    }
+    NV_LOG( LOG_NOTICE, "library : '" + name + "' loaded." );
+}
+
+void* library::get( const std::string& symbol )
+{
+	void* result = (void*) NV_LIB_GET( (NV_LIB_HANDLE) m_handle, symbol.c_str() );
+    if ( !result )
+    {
+        throw library_error( "Can't find symbol " + symbol + "!", m_name );
+    }
+	return result;
+}
+
+
+
+void library::close()
+{
+    if ( NV_LIB_CLOSE( (NV_LIB_HANDLE)m_handle ) )
+    {
+        NV_LOG( LOG_ERROR, "library : can't close library '" + m_name + "'!" );
+    }
+    m_handle = NULL;
+    NV_LOG( LOG_NOTICE, "library : '" + m_name + "' closed." );
+}
+
+library::~library()
+{
+    if ( m_handle != NULL )
+    {
+        close();
+    }
+}
+
+std::string library::get_error()
+{
+#if NV_PLATFORM == NV_WINDOWS
+    // We do hate WinAPI for code like this, don't we?
+    LPVOID buffer;
+    FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+        NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buffer, 0, NULL );
+    std::string msg( (char*)buffer );
+    LocalFree( buffer );
+    return msg;
+#elif NV_PLATFORM == NV_LINUX || NV_PLATFORM == NV_APPLE
+    return std::string(dlerror());
+#else
+    return std::string("");
+#endif
+}
Index: trunk/src/logger.cc
===================================================================
--- trunk/src/logger.cc	(revision 4)
+++ trunk/src/logger.cc	(revision 4)
@@ -0,0 +1,150 @@
+// Copyright (C) 2011 Kornel Kisielewicz
+// This file is part of NV Libraries.
+// For conditions of distribution and use, see copyright notice in nv.hh
+
+#include "nv/logger.hh"
+
+#include <iostream>
+#include <utility>
+#include <algorithm>
+#include <fstream>
+#include <nv/exception.hh>
+
+using namespace nv;
+
+// log level names
+const char *log_level_names[] =
+{
+	"NONE",
+	"FATAL",
+	"CRITICAL",
+	"ERROR",
+	"WARNING",
+	"NOTICE",
+	"INFO",
+	"INFO",
+	"DEBUG",
+	"DEBUG2",
+	"TRACE"
+};
+
+// helper macro to access log_level_names
+#define NV_LOG_LEVEL_NAME(level) (log_level_names[ (level) / 10 ])
+
+// log function
+void logger::log( log_level level, const std::string& message )
+{
+	// get the iterator to the beginning of the log_sink list
+	log_sink_list::reverse_iterator it = m_log_sinks.rbegin();
+
+	// iterate
+	while ( it != m_log_sinks.rend() )
+	{
+		// if we have a log sink with high enough level...
+		if ( it->first >= level )
+		{
+			// log and iterate
+			it->second->log( level, message );
+		}
+		else 
+		{
+			// otherwise return, the list is sorted by log level
+			return;
+		}
+		++it;
+	}
+}
+
+// add a new sink
+void logger::add_sink( log_sink* sink, int level )
+{
+	// add a sink
+	m_log_sinks.push_back( std::make_pair( log_level(level), sink ) );
+	// and sort the list (default sort of pairs is by first element)
+	m_log_sinks.sort();
+}
+
+// remove existing sink
+bool logger::remove_sink( log_sink* sink )
+{
+	// get the iterator to the beginning of the log_sink list
+	log_sink_list::iterator it = m_log_sinks.begin();
+
+	// iterate
+	while ( it != m_log_sinks.end() )
+	{
+		// found?
+		if ( it->second == sink ) 
+		{
+			// erase and return true to report success
+			m_log_sinks.erase(it);
+			return true;
+		}
+		++it;
+	}
+
+	// not found, return false
+	return false;
+}
+
+// destructor
+logger::~logger()
+{
+	// while we have sinks
+	while ( !m_log_sinks.empty() )
+	{
+		// delete the last one
+		delete m_log_sinks.back().second;
+		// and pop it
+		m_log_sinks.pop_back();
+	}
+}
+
+
+// console logging
+void log_console_sink::log( log_level level, const std::string& message )
+{
+	std::cout << "[" << NV_LOG_LEVEL_NAME(level) << "] " << message << std::endl;
+}
+
+// stream logging
+void log_stream_sink::log( log_level level, const std::string& message )
+{
+	// if flushing is enabled
+	if ( m_flush )
+	{
+		// write and flush using std::endl
+		*m_stream << "[" << NV_LOG_LEVEL_NAME(level) << "] " << message << std::endl;
+	}
+	else
+	{
+		// write and end with "\n" (no flush)
+		*m_stream << "[" << NV_LOG_LEVEL_NAME(level) << "] " << message << "\n";
+	}
+}
+
+// file logging
+log_file_sink::log_file_sink( const std::string file_name, bool flush_always /*= true */ )
+	: log_stream_sink( nullptr, flush_always )
+{
+	// create the stream manually
+	std::ofstream* fstream = new std::ofstream( file_name );
+
+	// check if it's open
+	if ( !fstream->is_open() )
+	{
+		// throw if not open
+		throw runtime_error( "Could not open file \""+file_name+"\" for logging!" );
+	}
+
+	m_stream = fstream;
+}
+
+// file logger destructor
+log_file_sink::~log_file_sink()
+{
+	// close the file
+	dynamic_cast< std::ofstream* >(m_stream)->close();
+	// dispose of the stream
+	delete m_stream;
+}
