Index: trunk/nv/library.hh
===================================================================
--- trunk/nv/library.hh	(revision 4)
+++ trunk/nv/library.hh	(revision 4)
@@ -0,0 +1,114 @@
+// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
+// http://chaosforge.org/
+//
+// This file is part of NV Libraries.
+// For conditions of distribution and use, see copyright notice in nv.hh
+
+/**
+ * @file library.hh
+ * @author Kornel Kisielewicz
+ * @brief Implements a dynamic library class
+ */
+
+#ifndef NV_LIBRARY_HH
+#define NV_LIBRARY_HH
+
+#include <nv/exception.hh>
+#include <string>
+
+namespace nv
+{
+	/**
+	 * library
+	 * @brief Class representing a dynamically loaded library
+	 */
+	class library 
+	{
+	public:
+
+		/**
+		 * Library constructor
+		 *
+		 * Opens the library
+		 */
+		library( const std::string& name );
+
+		/**
+		 * Opens the library
+		 */
+		void open( const std::string& name );
+
+		/**
+		 * Returns library name
+		 */
+		const std::string& get_name() const;
+
+		/**
+		 * Get symbol from library
+		 */
+		void* get( const std::string& symbol );
+
+		/**
+		 * Destructor
+		 *
+		 * Closes the library if open.
+		 */
+		~library();
+
+		/**
+		 * Returns library loading error if present
+		 *
+		 * Exact implementation depends on platform/compiler.
+		 */
+		static std::string get_error();
+
+	protected:
+		/**
+		 * Opens the library
+		 *
+		 * Opens the library and prepares it for getting symbols.
+		 * Needs to be done before any get call.
+		 */
+		void open();
+
+		/**
+		 * @brief Closes the library
+		 *
+		 * Closes the library. Any further get calls or operations on
+		 * received symbols are invalid!
+		 */
+		void close();
+
+		/// Library handle
+		void* m_handle;
+
+		/// Library name
+		std::string m_name;
+
+	};  // class Library
+
+	class library_error : public runtime_error
+	{
+		/// Library name
+		std::string m_name;
+	public:
+		/**
+		 * Constructor
+		 */
+		library_error( const std::string& message, const std::string& name )
+			: runtime_error( "Library (" + name + ") : " + message + " [ " + library::get_error() + " ]"), m_name( name )
+		{
+		}
+
+		/**
+		 * Returns library name
+		 */
+		const std::string& get_name()
+		{
+			return m_name;
+		}
+	};
+
+} // namespace nv
+
+#endif // NV_LIBRARY_HH
Index: trunk/nv/logger.hh
===================================================================
--- trunk/nv/logger.hh	(revision 4)
+++ trunk/nv/logger.hh	(revision 4)
@@ -0,0 +1,192 @@
+// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
+// http://chaosforge.org/
+//
+// This file is part of NV Libraries.
+// For conditions of distribution and use, see copyright notice in nv.hh
+
+/**
+ * @file logger.hh
+ * @author Kornel Kisielewicz epyon@chaosforge.org
+ * @brief logger implementation
+ */
+
+#ifndef NV_LOGGER_HH
+#define NV_LOGGER_HH
+
+#include <string>
+#include <iosfwd>
+#include <list>
+#include <nv/logging.hh>
+
+namespace nv
+{
+	/**
+	 * Class representing log output.
+	 *
+	 * Base class for all logging output targets.
+	 */
+	class log_sink
+	{
+	public:
+		/**
+		 * Logging function.
+		 *
+		 * @param level level on which to log.
+		 * @param message message to be logged.
+		 */
+		virtual void log( log_level level, const std::string& message ) = 0;
+		/**
+		 * Enforcement of virtual destructor.
+		 */
+		virtual ~log_sink() {};
+	};
+
+	/**
+	 * Logger class.
+	 *
+	 * Allows to catch all logging in ORE and in the application using ORE
+	 * logging macros. Initially does nothing, needs to have some log sinks
+	 * added.
+	 */
+	class logger : public logger_base
+	{
+	public:
+		/**
+		 * Constructor, taking the minimum level for logging.
+		 *
+		 * No matter what level sinks you add, the passed level is the
+		 * overriding cutoff.
+		 */
+		explicit logger( int llevel )
+		{
+			level = llevel;
+		}
+
+		/**
+		 * Logging function.
+		 *
+		 * Goes over all registered log sinks and prints to them depending
+		 * on the log level of the sink. Messages that are lower level than
+		 * the initial level passed to the constructor never even reach this
+		 * function.
+		 *
+		 * @param level level on which to log.
+		 * @param message message to be logged.
+		 */
+		virtual void log( log_level level, const std::string& message );
+
+		/** 
+		 * Log sink registering.
+		 * 
+		 * Registers a new log sink. Ownership is passed to logger - log sink
+		 * will be disposed at program shutdown.
+		 *
+		 * @param sink log sink to be registered.
+		 * @param level level on which the sink should log.
+		 */
+		virtual void add_sink( log_sink* sink, int level );
+
+		/** 
+		 * Log sink removal.
+		 * 
+		 * Removes a log sink. If log sink doesn't exist, nothing will 
+		 * happen.
+		 *
+		 * @param sink log sink to be removed.
+		 * @returns true if sink was found, false otherwise
+		 */
+		virtual bool remove_sink( log_sink* sink );
+
+		/**
+		 * Destructor.
+		 * 
+		 * Also destroys all file sinks.
+		 */
+		virtual ~logger();
+
+	protected:
+		/** Type for the log sink list. */
+		typedef std::list< std::pair< log_level, log_sink* > > log_sink_list;
+
+		/** Log sink list. */
+		log_sink_list m_log_sinks;
+	};
+
+	/**
+	 * Console logger sink.
+	 *
+	 * Logs to std::out -- be sure a console window is open, or std::out redirected!
+	 */
+	class log_console_sink : public log_sink
+	{
+	public:
+		/**
+		 * Logging function.
+		 */
+		virtual void log( log_level level, const std::string& message );
+	};
+
+	/**
+	 * General stream sink.
+	 *
+	 * Logs to passed stream.
+	 */
+	class log_stream_sink : public log_sink
+	{
+	public:
+		/**
+		 * Constructor.
+		 *
+		 * Logs to the passed stream. The stream is NOT disposed at destruction.
+		 * Flushing can be controlled by optional flush parameter.
+		 *
+		 * @param stream stream to be logged to.
+		 * @param flush_always if set to false, wont flush after each line.
+		 */
+		log_stream_sink( std::ostream* stream, bool flush_always ) 
+			: m_stream(stream), m_flush(flush_always) {}
+
+		/**
+		 * Logging function.
+		 */
+		virtual void log( log_level level, const std::string& message );
+
+	protected:
+		/** Stored stream. */
+		std::ostream* m_stream;
+		/** Controls flushing. */
+		bool m_flush;
+	};
+
+	/**
+	 * File logger sink.
+	 *
+	 * Logs to std::out -- be sure a console window is open, or std::out redirected!
+	 */
+	class log_file_sink : public log_stream_sink
+	{
+	public:
+		/**
+		 * Constructor.
+		 *
+		 * Logs to the file passed. File is closed and disposed of after ending.
+		 * File is not appended, it's overwritten. If file is not creatable,
+		 * the constructor will throw!
+		 *
+		 * @param file_name file to be logged to.
+		 * @param flush_always if set to false, wont flush after each line.
+		 * @throws runtime_error if file_name cannot be opened.
+		 */
+		log_file_sink( const std::string file_name, bool flush_always = true );
+
+		/**
+		 * Destructor.
+		 *
+		 * Flushes, closes file and disposes of the stream.
+		 */
+		virtual ~log_file_sink();
+	};
+
+}
+
+#endif // NV_LOGGER_HH
Index: trunk/nv/logging.hh
===================================================================
--- trunk/nv/logging.hh	(revision 4)
+++ trunk/nv/logging.hh	(revision 4)
@@ -0,0 +1,77 @@
+// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
+// http://chaosforge.org/
+//
+// This file is part of NV Libraries.
+// For conditions of distribution and use, see copyright notice in nv.hh
+
+/**
+ * @file logging.hh
+ * @author Kornel Kisielewicz epyon@chaosforge.org
+ * @brief logging interfaces
+ */
+
+#ifndef NV_LOGGING_HH
+#define NV_LOGGING_HH
+
+#include <nv/common.hh>
+#include <nv/singleton.hh>
+#include <sstream>
+#include <string>
+
+namespace nv
+{
+
+    enum log_level
+    {
+		LOG_NONE     = 0,
+        LOG_FATAL    = 10,
+        LOG_CRITICAL = 20,
+        LOG_ERROR    = 30,
+        LOG_WARNING  = 40,
+        LOG_NOTICE   = 50,
+        LOG_INFO     = 60,
+        LOG_DEBUG    = 80,
+        LOG_TRACE    = 100
+    };
+
+	class logger_base : public singleton< logger_base >
+	{
+	public:
+		unsigned int get_level()
+		{
+			return level;
+		};
+		void set_level( unsigned int level )
+		{
+			level = level;
+		};
+		virtual void log( log_level level, const std::string& message ) = 0;
+	protected:
+		unsigned int level;
+	};
+
+} // namespace nv
+
+#define NV_LOG(level, message_stream) \
+    if ( nv::logger_base::is_valid() && \
+		(unsigned int)nv::logger_base::reference().get_level() >= level ) \
+    {       \
+        std::stringstream ss; \
+        ss << message_stream; \
+        nv::logger_base::reference().log( level, ss.str() ); \
+    }
+
+#if NV_DEBUG == 1
+#define NV_DEBUG_LOG(level, message_stream) \
+	if ( nv::logger_base::is_valid() && \
+		(unsigned int)nv::logger_base::reference().get_level() >= level ) \
+	{       \
+		std::stringstream ss; \
+		ss << message_stream; \
+		nv::logger_base::reference().log( level, ss.str() ); \
+	}
+#else
+#define NV_DEBUG_LOG(level, message_stream)
+#endif
+
+#endif // NV_LOGGING_HH
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;
+}
