changeset 354:5f38366c7654

Put back CMakeLists that was missing for mkunicode
author David Demelier <markand@malikania.fr>
date Tue, 28 Apr 2015 08:38:38 +0200
parents f1a333e2d2a1
children 9f1e9c69c223
files .hgignore C++/doc/Directory/Home.md C++/doc/Directory/class/Directory.md C++/doc/Directory/class/Directory/Constructor.md C++/doc/Directory/class/Directory/Flags.md C++/doc/Directory/class/Directory/OperatorEQ.md C++/doc/Directory/class/Directory/begin.md C++/doc/Directory/class/Directory/cbegin.md C++/doc/Directory/class/Directory/cend.md C++/doc/Directory/class/Directory/count.md C++/doc/Directory/class/Directory/end.md C++/doc/Directory/class/DirectoryEntry/DirectoryEntry.md C++/doc/Directory/class/DirectoryEntry/Type.md C++/modules/Parser/Parser.cpp C++/modules/Parser/Parser.h C++/modules/Treenode/TreeNode.h C++/tests/Parser/configs/multi.conf C++/tests/Parser/configs/simple.conf C++/tests/Parser/main.cpp C++/tests/Treenode/main.cpp CMakeLists.txt tools/CMakeLists.txt tools/mkunicode/CMakeLists.txt
diffstat 23 files changed, 363 insertions(+), 762 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Tue Apr 28 07:52:45 2015 +0200
+++ b/.hgignore	Tue Apr 28 08:38:38 2015 +0200
@@ -1,2 +1,1 @@
 _build_
-CMakeLists.txt.*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Directory/Home.md	Tue Apr 28 08:38:38 2015 +0200
@@ -0,0 +1,9 @@
+# Directory
+
+There is one class Directory which let you open and read directories.
+
+## API Reference
+
+### Classes
+
+- [Directory](Classes/Directory.md)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Directory/class/Directory.md	Tue Apr 28 08:38:38 2015 +0200
@@ -0,0 +1,24 @@
+# Directory
+
+The directory wrapper.
+
+## Class
+
+````cpp
+class Directory;
+````
+
+### Public member types
+
+- [Flags](Directory/Flags.md)
+- [Type](Directory/Type.md)
+
+### Public member functions
+
+- [(Constructor)](Directory/Constructor.md)
+- [begin](Directory/begin.md)
+- [cbegin](Directory/cbegin.md)
+- [end](Directory/end.md)
+- [cend](Directory/cend.md)
+- [count](Directory/count.md)
+- [operator==](Directory/OperatorEQ.md)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Directory/class/Directory/Constructor.md	Tue Apr 28 08:38:38 2015 +0200
@@ -0,0 +1,32 @@
+# Constructor
+
+Construct an empty directory.
+
+## Function
+
+### SYNOPSIS
+
+````cpp
+Directory();
+````
+
+# Constructor
+
+Construct a directory to the specified path.
+
+## Function
+
+### SYNOPSIS
+
+````cpp
+Directory(const std::string &path, Flags flags = 0);
+````
+
+### ARGUMENTS
+
+- path, the path to read
+- flags, optional flags (see [Flags](Flags.md))
+
+### THROWS
+
+- [std::runtime_error](http://en.cppreference.com/w/cpp/error/runtime_error) on failures.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Directory/class/Directory/Flags.md	Tue Apr 28 08:38:38 2015 +0200
@@ -0,0 +1,19 @@
+# Flags
+
+Optional flags for opening the directory.
+
+## Enum
+
+### SYNOPSIS
+
+````cpp
+enum {
+    Dot      = (1 << 0),
+    DotDot   = (1 << 1)
+};
+````
+
+### VALUES
+
+- **Dot**, lists "." path
+- **DotDot**, lists ".." path
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Directory/class/Directory/OperatorEQ.md	Tue Apr 28 08:38:38 2015 +0200
@@ -0,0 +1,20 @@
+# operator==
+
+Test equality.
+
+## Function
+
+### SYNOPSIS
+
+````cpp
+friend bool operator==(const Directory &d1, const Parser &d2);
+````
+
+### ARGUMENTS
+
+- d1, the first directory
+- d2, the second directory
+
+### RETURNS
+
+True if they equals.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Directory/class/Directory/begin.md	Tue Apr 28 08:38:38 2015 +0200
@@ -0,0 +1,15 @@
+# begin
+
+Return an iterator the beginning.
+
+## Function
+
+### SYNOPSIS
+
+````cpp
+List::iterator begin();
+````
+
+### RETURNS
+
+The iterator.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Directory/class/Directory/cbegin.md	Tue Apr 28 08:38:38 2015 +0200
@@ -0,0 +1,15 @@
+# cbegin
+
+Return a const iterator the beginning.
+
+## Function
+
+### SYNOPSIS
+
+````cpp
+List::const_iterator cbegin();
+````
+
+### RETURNS
+
+The iterator.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Directory/class/Directory/cend.md	Tue Apr 28 08:38:38 2015 +0200
@@ -0,0 +1,15 @@
+# cend
+
+Return a const iterator to past the end.
+
+## Function
+
+### SYNOPSIS
+
+````cpp
+List::const_iterator cend();
+````
+
+### RETURNS
+
+The iterator.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Directory/class/Directory/count.md	Tue Apr 28 08:38:38 2015 +0200
@@ -0,0 +1,15 @@
+# count
+
+Get the number of entries in the directory.
+
+## Function
+
+### SYNOPSIS
+
+````cpp
+int count() const;
+````
+
+### RETURNS
+
+The number of entries.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Directory/class/Directory/end.md	Tue Apr 28 08:38:38 2015 +0200
@@ -0,0 +1,15 @@
+# end
+
+Return an iterator to past the end.
+
+## Function
+
+### SYNOPSIS
+
+````cpp
+List::iterator end();
+````
+
+### RETURNS
+
+The iterator.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Directory/class/DirectoryEntry/DirectoryEntry.md	Tue Apr 28 08:38:38 2015 +0200
@@ -0,0 +1,19 @@
+# Entry
+
+A file or directory entry that holds several information.
+
+## Struct
+
+### SYNOPSIS
+
+````cpp
+struct Entry {
+    std::string name;
+    Type        type;
+};
+````
+
+### FIELDS
+
+- **name**, the base name of the file
+- **type**, the file type (see [Type](Type.md))
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/doc/Directory/class/DirectoryEntry/Type.md	Tue Apr 28 08:38:38 2015 +0200
@@ -0,0 +1,23 @@
+# Type
+
+The type of a file. Not all values are supported on all systems.
+
+## Enum
+
+### SYNOPSIS
+
+````cpp
+enum Type {
+	Unknown = 0,
+	File,
+	Directory,
+	Link
+};
+````
+
+### VALUES
+
+- **Unknown**, the entry is unknown on that system
+- **File**, the entry is a standard file
+- **Directory**, the entry is a directory
+- **Link**, the entry is a link
\ No newline at end of file
--- a/C++/modules/Parser/Parser.cpp	Tue Apr 28 07:52:45 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,299 +0,0 @@
-/*
- * Parser.h -- config file parser
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <cstring>
-#include <cerrno>
-#include <iostream>
-#include <fstream>
-
-#include "Parser.h"
-
-/* --------------------------------------------------------
- * Section public members
- * -------------------------------------------------------- */
-
-Section::Section()
-	: m_allowed(true)
-{
-}
-
-Section::Section(const std::string &name, bool allowed)
-	: m_name(name)
-	, m_allowed(allowed)
-{
-
-}
-
-const std::string &Section::getName() const
-{
-	return m_name;
-}
-
-bool Section::hasOption(const std::string &name) const
-{
-	return m_options.count(name) >= 1;
-}
-
-Section::Map::iterator Section::begin()
-{
-	return m_options.begin();
-}
-
-Section::Map::const_iterator Section::cbegin() const
-{
-	return m_options.cbegin();
-}
-
-Section::Map::iterator Section::end()
-{
-	return m_options.end();
-}
-
-Section::Map::const_iterator Section::cend() const
-{
-	return m_options.end();
-}
-
-bool operator==(const Section &s1, const Section &s2)
-{
-	return s1.m_name == s2.m_name && s1.m_options == s2.m_options;
-}
-
-/* --------------------------------------------------------
- * Parser private members
- * -------------------------------------------------------- */
-
-void Parser::addOption(const std::string &key, const std::string &value)
-{
-	m_sections.back().m_options.insert(std::make_pair(key, value));
-}
-
-void Parser::readSection(int lineno, const std::string &line)
-{
-	size_t end;
-
-	if ((end = line.find_first_of(']')) != std::string::npos) {
-		if (end > 1) {
-			auto name = line.substr(1, end - 1);
-
-			/*
-			 * Check if we can add a section, if redefinition is
-			 * disabled, we must disable the previous section so the
-			 * further read options should not be enabled until
-			 * a correct section is found again.
-			 */
-			if (hasSection(name) && (m_tuning & DisableRedefinition)) {
-				if (!(m_tuning & DisableVerbosity))
-					log(lineno, name, "redefinition not allowed");
-				m_sections.back().m_allowed = false;
-			} else {
-				m_sections.push_back(Section(name));
-			}
-		} else if (!(m_tuning & DisableVerbosity)) {
-			/*
-			 * Do not add options at this step because it will
-			 * corrupt the previous one.
-			 */
-			m_sections.back().m_allowed = false;
-			log(lineno, "", "empty section name");
-		}
-	}
-}
-
-void Parser::readOption(int lineno, const std::string &line)
-{
-	auto &current = m_sections.back();
-	size_t epos;
-	std::string key, value;
-
-	// Error on last section?
-	if (!current.m_allowed) {
-		/*
-		 * If it is the root section, this has been probably set by
-		 * DisableRootSection flag, otherwise an error has occured
-		 * so no need to log.
-		 */
-		if (current.m_name == "" && !(m_tuning == DisableVerbosity))
-			log(lineno, "", "option not allowed in that scope");
-
-		return;
-	}
-
-	if ((epos = line.find_first_of('=')) == std::string::npos) {
-		if (!(m_tuning & DisableVerbosity))
-			log(lineno, current.m_name, "missing `=' keyword");
-		return;
-	}
-
-	if (epos > 0) {
-		size_t i, begin, last;
-		char c;
-
-		key = line.substr(0, epos);
-		value = line.substr(epos + 1);
-
-		// clean option key
-		for (i = 0; !isspace(key[i]) && i < key.length(); ++i)
-			continue;
-		key = key.substr(0, i);
-
-		// clean option value
-		for (begin = 0; isspace(value[begin]) && begin < value.length(); ++begin)
-			continue;
-		value = value.substr(begin);
-	
-		c = value[0];
-		begin = 0;
-		if (c == '\'' || c == '"') {
-			for (last = begin = 1; value[last] != c && last < value.length(); ++last)
-				continue;
-			if (value[last] != c && !(m_tuning & DisableVerbosity))
-				if (!(m_tuning & DisableVerbosity))
-					log(lineno, current.m_name, "undisclosed std::string");
-		} else {
-			for (last = begin; !isspace(value[last]) && last < value.length(); ++last)
-				continue;
-		}
-
-		if (last - begin > 0)
-			value = value.substr(begin, last - begin);
-		else
-			value.clear();
-
-		// Add the option if the key is not empty
-		if (key.length() > 0)
-			addOption(key, value);
-	}
-}
-
-void Parser::readLine(int lineno, const std::string &line)
-{
-	size_t i;
-	std::string buffer;
-
-	// Skip default spaces
-	for (i = 0; isspace(line[i]) && i < line.length(); ++i)
-		continue;
-
-	buffer = line.substr(i);
-	if (buffer.length() > 0) {
-		if (buffer[0] != m_commentChar) {
-			if (buffer[0] == '[')
-				readSection(lineno, buffer);
-			else
-				readOption(lineno, buffer);
-		}
-	}
-}
-
-/* --------------------------------------------------------
- * Parser public methods
- * -------------------------------------------------------- */
-
-const char Parser::DEFAULT_COMMENT_CHAR = '#';
-
-void Parser::open()
-{
-	std::ifstream file;
-	std::string line;
-	int lineno = 1;
-
-	file.open(m_path.c_str());
-	if (!file.is_open())
-		throw std::runtime_error(m_path + ": " + std::string(std::strerror(errno)));
-
-	while (std::getline(file, line))
-		readLine(lineno++, line);
-
-	file.close();
-}
-
-Parser::Parser()
-{
-}
-
-Parser::Parser(const std::string &path, int tuning, char commentToken)
-	: m_path(path)
-	, m_tuning(tuning)
-	, m_commentChar(commentToken)
-{
-	m_sections.push_back(Section("", (tuning & DisableRootSection) ? false : true));
-	open();
-}
-
-Parser::~Parser()
-{
-}
-
-Parser::List::iterator Parser::begin()
-{
-	return m_sections.begin();
-}
-
-Parser::List::const_iterator Parser::cbegin() const
-{
-	return m_sections.cbegin();
-}
-
-Parser::List::iterator Parser::end()
-{
-	return m_sections.end();
-}
-
-Parser::List::const_iterator Parser::cend() const
-{
-	return m_sections.end();
-}
-
-void Parser::findSections(const std::string &name, FindFunc func) const
-{
-	for (const auto &s : m_sections)
-		if (s.m_name == name)
-			func(s);
-}
-
-bool Parser::hasSection(const std::string &name) const
-{
-	for (const auto &s : m_sections)
-		if (s.m_name == name)
-			return true;
-
-	return false;
-}
-
-const Section &Parser::getSection(const std::string &name) const
-{
-	for (const auto &s : m_sections)
-		if (s.m_name == name)
-			return s;
-
-	throw std::out_of_range(name + " not found");
-}
-
-void Parser::log(int number, const std::string &, const std::string &message)
-{
-	std::cout << "line " << number << ": " << message << std::endl;
-}
-
-bool operator==(const Parser &p1, const Parser &p2)
-{
-	return p1.m_sections == p2.m_sections &&
-	    p1.m_path == p2.m_path &&
-	    p1.m_tuning == p2.m_tuning &&
-	    p1.m_commentChar == p2.m_commentChar;
-}
--- a/C++/modules/Parser/Parser.h	Tue Apr 28 07:52:45 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,336 +0,0 @@
-/*
- * Parser.h -- config file parser
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _PARSER_H_
-#define _PARSER_H_
-
-#include <cstdlib>
-#include <functional>
-#include <stdexcept>
-#include <string>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-/**
- * @class Section
- * @brief The option container
- *
- * A list of section found in the file. If root
- * options are allowed (default behavior), the root
- * section is "".
- */
-class Section {
-public:
-	friend class Parser;
-
-	using Map = std::unordered_map<std::string, std::string>;
-
-	template <typename T>
-	struct Converter {
-		static const bool supported = false;
-	};
-
-private:
-	std::string	m_name;		/*! name of section */
-	Map		m_options;	/*! list of options inside */
-	bool		m_allowed;	/*! is authorized to push */
-
-public:
-	/**
-	 * Default constructor.
-	 */
-	Section();
-
-	/**
-	 * Named constructor.
-	 *
-	 * @param name the section name
-	 * @param allowed is allowed to push
-	 */
-	Section(const std::string &name, bool allowed = true);
-
-	/**
-	 * Tells if that section has the specified option name.
-	 *
-	 * @param name the option name
-	 * @return true if has
-	 */
-	bool hasOption(const std::string &name) const;
-
-	/**
-	 * Get the section name
-	 *
-	 * @return the section name
-	 */
-	const std::string &getName() const;
-
-	/**
-	 * Return an iterator to the beginning.
-	 *
-	 * @return the iterator.
-	 */
-	Map::iterator begin();
-
-	/**
-	 * Return a const iterator to the beginning.
-	 *
-	 * @return the iterator.
-	 */
-	Map::const_iterator cbegin() const;
-
-	/**
-	 * Return an iterator to the end.
-	 *
-	 * @return the iterator.
-	 */
-	Map::iterator end();
-	
-	/**
-	 * Return a const iterator to the end.
-	 *
-	 * @return the iterator.
-	 */
-	Map::const_iterator cend() const;
-
-	/**
-	 * Template all functions for retrieving options value.
-	 *
-	 * @param name the option name
-	 * @return the value if found
-	 */
-	template <typename T>
-	T getOption(const std::string &name) const
-	{
-		try {
-			return requireOption<T>(name);
-		} catch (...) {
-			// Catch any conversion error.
-		}
-
-		return T();
-	}
-
-	/**
-	 * Requires an option, this works like getOption except
-	 * that if an option is not found, an exception is
-	 * thrown.
-	 *
-	 * @param name the name
-	 * @return the value
-	 * @throw std::out_of_range if not found
-	 * @throw std::invalid_argument on conversion failures
-	 */
-	template <typename T>
-	T requireOption(const std::string &name) const
-	{
-		static_assert(Converter<T>::supported, "invalid type requested");
-
-		return Converter<T>::convert(m_options.at(name));
-	}
-
-	friend bool operator==(const Section &s1, const Section &s2);
-};
-
-template <>
-struct Section::Converter<bool> {
-	static const bool supported = true;
-
-	static bool convert(const std::string &value)
-	{
-		bool result(false);
-
-		if (value == "yes" || value == "true"|| value == "1")
-			result = true;
-		else if (value == "no" || value == "false" || value == "0")
-			result = false;
-
-		return result;
-	}
-};
-
-template <>
-struct Section::Converter<int> {
-	static const bool supported = true;
-
-	static int convert(const std::string &value)
-	{
-		return std::stoi(value);
-	}
-};
-
-template <>
-struct Section::Converter<float> {
-	static const bool supported = true;
-
-	static float convert(const std::string &value)
-	{
-		return std::stof(value);
-	}
-};
-
-template <>
-struct Section::Converter<double> {
-	static const bool supported = true;
-
-	static double convert(const std::string &value)
-	{
-		return std::stod(value);
-	}
-};
-
-template <>
-struct Section::Converter<std::string> {
-	static const bool supported = true;
-
-	static std::string convert(const std::string &value)
-	{
-		return value;
-	}
-};
-
-/**
- * @class Parser
- * @brief Config file parser
- *
- * Open and read .ini files.
- */
-class Parser {
-public:
-	/**
-	 * Options available for the parser.
-	 */
-	enum Tuning {
-		DisableRootSection	= 1,	/*! disable options on root */
-		DisableRedefinition	= 2,	/*! disable multiple redefinition */
-		DisableVerbosity	= 4	/*! be verbose by method */
-	};
-
-	using FindFunc	= std::function<void (const Section &)>;
-	using List	= std::vector<Section>;
-
-private:
-	List		m_sections;		/*! list of sections found */
-	std::string	m_path;			/*! path file */
-	int		m_tuning;		/*! options for parsing */
-	char		m_commentChar;		/*! the comment token default (#) */
-
-	void addSection(const std::string &name);
-	void addOption(const std::string &key, const std::string &value);
-
-	void readSection(int lineno, const std::string &line);
-	void readOption(int lineno, const std::string &line);
-
-	void readLine(int lineno, const std::string &line);
-
-	void open();
-
-public:
-	static const char DEFAULT_COMMENT_CHAR;
-
-	/**
-	 * Create a parser at the specified file path. Optional
-	 * options may be added.
-	 *
-	 * @param path the file path
-	 * @param tuning optional tuning flags
-	 * @param commentToken an optional comment delimiter
-	 * @throw std::runtime_error on errors
-	 * @see Tuning
-	 */
-	Parser(const std::string &path, int tuning = 0, char commentToken = Parser::DEFAULT_COMMENT_CHAR);
-
-	/**
-	 * Default constructor.
-	 */
-	Parser();
-
-	/**
-	 * Default destructor.
-	 */
-	virtual ~Parser();
-
-	/**
-	 * Return an iterator to the beginning.
-	 *
-	 * @return the iterator.
-	 */
-	List::iterator begin();
-
-	/**
-	 * Return a const iterator to the beginning.
-	 *
-	 * @return the iterator.
-	 */
-	List::const_iterator cbegin() const;
-
-	/**
-	 * Return an iterator to the end.
-	 *
-	 * @return the iterator.
-	 */
-	List::iterator end();
-	
-	/**
-	 * Return a const iterator to the end.
-	 *
-	 * @return the iterator.
-	 */
-	List::const_iterator cend() const;
-
-	/**
-	 * Find all sections matching the name.
-	 *
-	 * @param name the sections name
-	 * @param func the function 
-	 * @return a list of section with the options
-	 */
-	void findSections(const std::string &name, FindFunc func) const;
-
-	/**
-	 * Tell if a section is existing.
-	 *
-	 * @return true if exists
-	 */
-	bool hasSection(const std::string &name) const;
-
-	/**
-	 * Get a specified section.
-	 *
-	 * @param name the section name
-	 * @return a section
-	 * @throw std::out_of_range if not found
-	 */
-	const Section &getSection(const std::string &name) const;
-
-	/**
-	 * Logging function, used only if DisableVerbosity is not set. The
-	 * default behavior is to print to stdout something like:
-	 * line 10: syntax error
-	 * line 8: missing =
-	 *
-	 * @param number the line number
-	 * @param section the current section worked on
-	 * @param message the message
-	 */
-	virtual void log(int number, const std::string &section, const std::string &message);
-
-	friend bool operator==(const Parser &p1, const Parser &p2);
-};
-
-#endif // !_PARSER_H_
--- a/C++/modules/Treenode/TreeNode.h	Tue Apr 28 07:52:45 2015 +0200
+++ b/C++/modules/Treenode/TreeNode.h	Tue Apr 28 08:38:38 2015 +0200
@@ -424,6 +424,55 @@
 	}
 
 	/**
+	 * Move the other value to that node as children.
+	 *
+	 * Example, this is our tree:
+	 *
+	 *     a
+	 *    / \
+	 *   b   c
+	 *       \
+	 *        d
+	 *
+	 * Calling nodeB.move(nodeC) will end in the following tree:
+	 *
+	 *     a
+	 *    / \
+	 *   b   c
+	 *  /
+	 * d
+	 *
+	 * This function cannot be used accross different trees.
+	 *
+	 * @note moving a parent of that current not results in a loss of that node
+	 * @param other the other node to move, the node is emptied but may be reused
+	 * @param position position in that tree, -1 means end
+	 */
+	inline void take(T &other, int position = -1)
+	{
+		if (other.m_parent == nullptr) {
+			throw std::invalid_argument("can't move root node");
+		}
+		if (&other == static_cast<T *>(this)) {
+			throw std::invalid_argument("attempt to move node to itself");
+		}
+
+		auto it = std::find_if(other.m_parent->m_children.begin(), other.m_parent->m_children.end(), [&] (const std::unique_ptr<Object> &object) -> bool {
+			return &object->get() == &other;
+		});
+
+		if (it == other.m_parent->m_children.end()) {
+			throw std::invalid_argument("unable to find children node");
+		}
+
+		position = (position < 0) ? m_children.size() : position;
+
+		m_children.insert(m_children.begin() + position, std::move(*it));
+		other.m_parent->m_children.erase(it);
+		m_children[position]->get().m_parent = this;
+	}
+
+	/**
 	 * Iterate over all the nodes. The first node is also passed through
 	 * the callback.
 	 *
--- a/C++/tests/Parser/configs/multi.conf	Tue Apr 28 07:52:45 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-[entity]
-name	= "Player"
-version	= 1.0
-
-[entity]
-name	= "Subwinner"
-version	= 2.0
\ No newline at end of file
--- a/C++/tests/Parser/configs/simple.conf	Tue Apr 28 07:52:45 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-[general]
-option1=1
-option2 =2
-option3 = 3
--- a/C++/tests/Parser/main.cpp	Tue Apr 28 07:52:45 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-/*
- * TestParser.cpp -- test the config file parser
- *
- * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <iostream>
-
-#include <gtest/gtest.h>
-
-#include <Parser.h>
-
-TEST(Basic, simple)
-{
-	try {
-		Parser parser("Parser/simple.conf");
-
-		const auto &s = parser.getSection("general");
-		ASSERT_EQ("general", s.getName());
-
-		const auto &o1 = s.getOption<std::string>("option1");
-		ASSERT_EQ("1", o1);
-
-		const auto &o2 = s.getOption<std::string>("option2");
-		ASSERT_EQ("2", o2);
-
-		const auto &o3 = s.getOption<std::string>("option3");
-		ASSERT_EQ("3", o3);
-	} catch (const std::out_of_range &error) {
-		FAIL();
-	} catch (const std::runtime_error &error) {
-		FAIL() << error.what();
-	}
-}
-
-TEST(Basic, multi)
-{
-	try {
-		Parser parser("Parser/multi.conf");
-		int i(0);
-
-		parser.findSections("entity", [&] (const Section &s) {
-			if (i++ == 0) {
-				ASSERT_EQ("Player", s.getOption<std::string>("name"));
-				ASSERT_EQ("1.0", s.getOption<std::string>("version"));
-			} else {
-				ASSERT_EQ("Subwinner", s.getOption<std::string>("name"));
-				ASSERT_EQ("2.0", s.getOption<std::string>("version"));
-			}
-		});
-
-		ASSERT_EQ(2, i);
-	} catch (const std::out_of_range &error) {
-		FAIL();
-	} catch (const std::runtime_error &error) {
-		FAIL() << error.what();
-	}
-}
-
-TEST(Basic, multiNoredef)
-{
-	try {
-		Parser parser("Parser/multi.conf", Parser::DisableRedefinition);
-		int i(0);
-
-		parser.findSections("entity", [&] (const Section &s) {
-			if (i++ == 0) {
-				ASSERT_EQ("Player", s.getOption<std::string>("name"));
-				ASSERT_EQ("1.0", s.getOption<std::string>("version"));
-			}
-		});
-
-		ASSERT_EQ(1, i);
-	} catch (const std::out_of_range &error) {
-		FAIL();
-	} catch (const std::runtime_error &error) {
-		FAIL() << error.what();
-	}
-}
-
-int main(int argc, char **argv)
-{
-	testing::InitGoogleTest(&argc, argv);
-
-	return RUN_ALL_TESTS();
-}
--- a/C++/tests/Treenode/main.cpp	Tue Apr 28 07:52:45 2015 +0200
+++ b/C++/tests/Treenode/main.cpp	Tue Apr 28 08:38:38 2015 +0200
@@ -1493,6 +1493,60 @@
 }
 
 /* --------------------------------------------------------
+ * Take
+ * -------------------------------------------------------- */
+
+TEST(Take, correct)
+{
+	Object root("a");
+
+	root.appendNew("b");
+	root.appendNew("c");
+	root[1].appendNew("d");
+
+	try {
+		root[0].take(root[1][0]);
+	} catch (const std::exception &ex) {
+		FAIL() << ex.what();
+	}
+
+	ASSERT_EQ(0U, root[1].countChildren());
+	ASSERT_EQ(1U, root[0].countChildren());
+	ASSERT_EQ("d", root[0][0].name());
+	ASSERT_TRUE(&root[0][0].parent() == &root[0]);
+}
+
+TEST(Take, moveSelf)
+{
+	Object root("a");
+
+	root.appendNew("b");
+	root.appendNew("c");
+
+	try {
+		root[0].take(root[0]);
+		FAIL() << "Expected exception";
+	} catch (const std::exception &) {
+		// SUCCESS
+	}
+}
+
+TEST(Take, moveRoot)
+{
+	Object root("a");
+
+	root.appendNew("b");
+	root.appendNew("c");
+
+	try {
+		root[0].take(root);
+		FAIL() << "Expected exception";
+	} catch (const std::exception &) {
+		// SUCCESS
+	}
+}
+
+/* --------------------------------------------------------
  * Test inheritance
  * -------------------------------------------------------- */
 
--- a/CMakeLists.txt	Tue Apr 28 07:52:45 2015 +0200
+++ b/CMakeLists.txt	Tue Apr 28 08:38:38 2015 +0200
@@ -307,22 +307,6 @@
 )
 
 # ---------------------------------------------------------
-# Parser (DEPRECATED)
-# ---------------------------------------------------------
-
-define_module(
-	TARGET parser
-	NAME Parser
-	DIRECTORY Parser
-	RESOURCES
-		${code_SOURCE_DIR}/C++/tests/Parser/configs/simple.conf
-		${code_SOURCE_DIR}/C++/tests/Parser/configs/multi.conf
-	SOURCES
-		${code_SOURCE_DIR}/C++/modules/Parser/Parser.cpp
-		${code_SOURCE_DIR}/C++/modules/Parser/Parser.h
-)
-
-# ---------------------------------------------------------
 # Sockets
 # ---------------------------------------------------------
 
--- a/tools/CMakeLists.txt	Tue Apr 28 07:52:45 2015 +0200
+++ b/tools/CMakeLists.txt	Tue Apr 28 08:38:38 2015 +0200
@@ -20,4 +20,4 @@
 
 add_executable(cccat cccat.cpp)
 add_executable(mdtohtml mdtohtml.cpp)
-#add_subdirectory(mkunicode)
+add_subdirectory(mkunicode)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/mkunicode/CMakeLists.txt	Tue Apr 28 08:38:38 2015 +0200
@@ -0,0 +1,38 @@
+#
+# CMakeLists.txt -- code building for common code
+#
+# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+project(mkunicode)
+
+add_executable(
+	mkunicode
+	src/mkunicode.c
+	src/utf.h
+	src/utfdef.h
+)
+
+add_custom_target(
+	generate-unicode
+	COMMAND
+		$<TARGET_FILE:cccat> ${mkunicode_SOURCE_DIR}/Unicode-before.cpp > ${code_SOURCE_DIR}/C++/Modules/Unicode/Unicode.cpp
+	COMMAND
+		$<TARGET_FILE:mkunicode> ${mkunicode_SOURCE_DIR}/UnicodeData.txt >> ${code_SOURCE_DIR}/C++/Modules/Unicode/Unicode.cpp
+	COMMAND
+		$<TARGET_FILE:cccat> ${mkunicode_SOURCE_DIR}/Unicode-after.cpp >> ${code_SOURCE_DIR}/C++/Modules/Unicode/Unicode.cpp
+	COMMAND
+		${CMAKE_COMMAND} -E copy ${mkunicode_SOURCE_DIR}/Unicode.h ${code_SOURCE_DIR}/C++/Modules/Unicode
+)
\ No newline at end of file