<commit_before>#ifndef __ARRAYS_HPP__
#define __ARRAYS_HPP__

#include <string>
#include <type_traits>
#include "../static-strings/static-strings.hpp"

#ifdef __CYGWIN__
#include <sstream>
namespace std {
	inline std::string to_string(unsigned long val) { ostringstream os; os << val; return os.str(); }
}
#endif

namespace {
namespace __typedecl {

struct split_string {
	std::string begin;
	std::string end;
	explicit operator std::string() const {
		return begin + end;
	}
};

inline split_string operator+(const std::string& s, const split_string& ss) {
	return { s + ss.begin, ss.end };
}

inline split_string operator+(const split_string& ss, const std::string& s) {
	return { ss.begin, ss.end + s };
}

using empty_ss = static_string::static_string<char>;

template <typename B, typename E>
struct sss {
	using begin = B;
	using end = E;
	inline static std::string string() {
		return begin::string() + end::string();
	}
};

using empty_sss = sss<empty_ss, empty_ss>;

template <typename, typename>
struct sssconcat_impl;

template <char... chars, typename SSS>
struct sssconcat_impl<static_string::static_string<char, chars...>, SSS> {
	using _begin = static_string::concat<
	                   static_string::static_string<char, chars...>,
	                   typename SSS::begin
	               >;
	using type = sss<_begin, typename SSS::end>;
};

template <typename T1, typename T2>
using sssconcat = typename sssconcat_impl<T1, T2>::type;

template <typename T>
struct impl;

template <typename T>
struct prefix_cv_qual_if_basictype {
	/*
	 * == SFINAE ==
	 * If impl<T> has a static member function named "value_with_cv_qual", then
	 * the forward() overload below is defined, and the call for forward() will
	 * prefer this overload over the other one that has varargs ("...").
	 * If impl<T> does not have such member, then the varargs overload is the
	 * only option.
	 */
	template <typename I>
	inline static split_string forward(const std::string& cv_qual, const split_string& suffix, decltype(I::value_with_cv_qual)*) {
		return I::value_with_cv_qual(cv_qual, suffix);
	}

	template <typename I>
	inline static split_string forward(const std::string& cv_qual, const split_string& suffix, ...) {
		return I::value(cv_qual + suffix);
	}

	inline static split_string value(const std::string& cv_qual, const split_string& suffix) {
		return forward<impl<T>>(cv_qual, suffix, nullptr);
	}
};

template <typename T>
struct impl<const T> {
	inline static split_string value(const split_string& suffix = {}) {
		return prefix_cv_qual_if_basictype<T>::value("const", suffix);
	}
};

template <typename T>
struct impl<volatile T> {
	inline static split_string value(const split_string& suffix = {}) {
		return prefix_cv_qual_if_basictype<T>::value("volatile", suffix);
	}
};

// Required to disambiguate between <const T> and <volatile T>
template <typename T>
struct impl<const volatile T> {
	inline static split_string value(const split_string& suffix = {}) {
		return prefix_cv_qual_if_basictype<T>::value("const volatile", suffix);
	}
};

template <typename T>
struct is_array_or_function : std::integral_constant<
	bool,
	std::is_array<T>::value || std::is_function<T>::value
> {};

template <typename T, bool = is_array_or_function<T>::value>
struct parenthesize_if_array_or_function;

template <typename T>
struct parenthesize_if_array_or_function<T, false> {
	inline static split_string value(const split_string& arg) {
		return impl<T>::value(arg);
	}
};

template <typename T>
struct parenthesize_if_array_or_function<T, true> {
	inline static split_string value(const split_string& arg) {
		return impl<T>::value("(" + arg + ")");
	}
};

template <typename T>
struct impl<T*> {
	inline static split_string value(const split_string& suffix = {}) {
		return parenthesize_if_array_or_function<T>::value("*" + suffix);
	}
};

template <typename T>
struct impl<T&> {
	inline static split_string value(const split_string& suffix = {}) {
		return parenthesize_if_array_or_function<T>::value("&" + suffix);
	}
};

template <typename T>
struct impl<T&&> {
	inline static split_string value(const split_string& suffix = {}) {
		return parenthesize_if_array_or_function<T>::value("&&" + suffix);
	}
};

template <typename T>
struct array_impl {
	inline static split_string value(const split_string& prefix = {}) {
		return impl<T>::value(prefix + "[]");
	}
};

template <typename T>
struct impl<T[]> : array_impl<T> {};

// Required to disambiguate between <const T> and <T[]>
template <typename T>
struct impl<const T[]> : array_impl<const T> {};

// Required to disambiguate between <volatile T> and <T[]>
template <typename T>
struct impl<volatile T[]> : array_impl<volatile T> {};

// Required to disambiguate between <const T>, <volatile T>, <const volatile T>,  <T[]>, <const T[]> and <volatile T[]>
template <typename T>
struct impl<const volatile T[]> : array_impl<const volatile T> {};

template <typename T, size_t N>
struct sized_array_impl {
	inline static split_string value(const split_string& prefix = {}) {
		return impl<T>::value(prefix + ("[" + std::to_string(N) + "]"));
	}
};

template <typename T, size_t N>
struct impl<T[N]> : sized_array_impl<T, N> {};

// Required to disambiguate between <const T> and <T[N]>
template <typename T, size_t N>
struct impl<const T[N]> : sized_array_impl<const T, N> {};

// Required to disambiguate between <volatile T> and <T[N]>
template <typename T, size_t N>
struct impl<volatile T[N]> : sized_array_impl<volatile T, N> {};

// Required to disambiguate between <const T>, <volatile T>, <const volatile T>,  <T[N]>, <const T[N]> and <volatile T[N]>
template <typename T, size_t N>
struct impl<const volatile T[N]> : sized_array_impl<const volatile T, N> {};

template <typename... T>
struct type_list_impl;

template <>
struct type_list_impl<> {
	inline static std::string value() {
		return "";
	}
};

struct varargs;

template <>
struct type_list_impl<varargs> {
	inline static std::string value() {
		return "...";
	}
};

template <typename T>
struct type_list_impl<T> {
	inline static std::string value() {
		return static_cast<std::string>(impl<T>::value());
	}
};

template <typename T1, typename T2, typename... U>
struct type_list_impl<T1, T2, U...> {
	inline static std::string value() {
		return type_list_impl<T1>::value() + ", " + type_list_impl<T2, U...>::value();
	}
};

template <bool RIsPtrOrRef, typename R, typename... A>
struct function_impl;

template <typename R, typename... A>
struct function_impl<false, R, A...> {
	inline static split_string value(const split_string& infix = {}) {
		return static_cast<std::string>(impl<R>::value()) + infix + "(" + type_list_impl<A...>::value() + ")";
	}
};

template <typename R, typename... A>
struct function_impl<true, R, A...> {
	inline static split_string value(const split_string& prefix = {}) {
		return impl<R>::value(prefix + "(" + type_list_impl<A...>::value() + ")");
	}
};

template <typename T>
struct is_pointer_or_reference : std::integral_constant<
	bool,
	std::is_pointer<T>::value || std::is_reference<T>::value
> {};

template <typename R, typename... A>
struct function_args_impl : function_impl<is_pointer_or_reference<typename std::remove_cv<R>::type>::value, R, A...> {};

template <typename R, typename... A>
struct impl<R(A...)>      : function_args_impl<R, A...> {};

template <typename R, typename... A>
struct impl<R(A..., ...)> : function_args_impl<R, A..., varargs> {};

template <typename T>
struct str_provider;

template <typename T>
struct impl_proxy {
	template <typename>
	struct Check;

	// SFINAE!
	template <typename I>
	constexpr static std::string value(const std::string& arg, Check<typename I::template ssstring<>>*) {
		using i_sss = typename I::template ssstring<>;
		return i_sss::begin::string() + arg + i_sss::end::string();
	}

	template <typename I>
	constexpr static std::string value(const std::string& arg, ...) {
		split_string ss = I::value();
		return ss.begin + arg + ss.end;
	}

	using _impl = impl<T>;
	inline static std::string value(const std::string& arg = "") {
		return value<_impl>(arg, nullptr);
	}
};

} /* namespace __typedecl */
} /* unnamed namespace */

template <typename T>
inline std::string typedecl() {
	return __typedecl::impl_proxy<T>::value();
}

template <typename T>
inline std::string namedecl(const std::string& name) {
	return __typedecl::impl_proxy<T>::value(' ' + name);
}

#define DEFINE_TYPEDECL(T) \
	namespace { \
	namespace __typedecl { \
	template <> \
	struct str_provider<T> { \
		static constexpr const char* str() { return #T; } \
	}; \
	template <> \
	struct impl<T> { \
		using _token_ss = static_string::from_provider<str_provider<T>>; \
		template <typename SuffixSSS = empty_sss> using ssstring = sssconcat<_token_ss, SuffixSSS>; \
		inline static split_string value(const split_string& suffix = {}) { \
			return #T + suffix; \
		} \
		inline static split_string value_with_cv_qual(const std::string& cv_qual, const split_string& suffix) { \
			return (cv_qual + " " #T) + suffix; \
		} \
	}; \
	} /* namespace __typedecl */ \
	} /* unnamed namespace */

DEFINE_TYPEDECL(void);
DEFINE_TYPEDECL(char);
DEFINE_TYPEDECL(int);

#endif
<commit_msg>typedecl: Implement impl<const T> with static-strings<commit_after>#ifndef __ARRAYS_HPP__
#define __ARRAYS_HPP__

#include <string>
#include <type_traits>
#include "../static-strings/static-strings.hpp"

#ifdef __CYGWIN__
#include <sstream>
namespace std {
	inline std::string to_string(unsigned long val) { ostringstream os; os << val; return os.str(); }
}
#endif

namespace {
namespace __typedecl {

struct split_string {
	std::string begin;
	std::string end;
	explicit operator std::string() const {
		return begin + end;
	}
};

inline split_string operator+(const std::string& s, const split_string& ss) {
	return { s + ss.begin, ss.end };
}

inline split_string operator+(const split_string& ss, const std::string& s) {
	return { ss.begin, ss.end + s };
}

using empty_ss = static_string::static_string<char>;
using space_ss = static_string::static_string<char, ' '>;

template <typename B, typename E>
struct sss {
	using begin = B;
	using end = E;
	inline static std::string string() {
		return begin::string() + end::string();
	}
};

using empty_sss = sss<empty_ss, empty_ss>;

template <typename, typename>
struct sssconcat_impl;

template <char... chars, typename SSS>
struct sssconcat_impl<static_string::static_string<char, chars...>, SSS> {
	using _begin = static_string::concat<
	                   static_string::static_string<char, chars...>,
	                   typename SSS::begin
	               >;
	using type = sss<_begin, typename SSS::end>;
};

template <typename T1, typename T2>
using sssconcat = typename sssconcat_impl<T1, T2>::type;

template <typename T>
struct impl;

template <typename T>
struct is_basic_type {
	// SFINAE!
	template <typename I>
	static constexpr bool test(typename I::template ssstring_with_cv_qual<empty_ss, empty_sss> *) {
		return true;
	}

	template <typename I>
	static constexpr bool test(...) {
		return false;
	}

	enum { value = test<impl<T>>(nullptr) };
};

template <typename T, typename SuffixSSS, typename CVQualSS, bool = is_basic_type<T>::value>
struct prefix_cv_qual_if_basictype;

template <typename T, typename SuffixSSS, typename CVQualSS>
struct prefix_cv_qual_if_basictype<T, SuffixSSS, CVQualSS, true> {
	using ssstring = typename impl<T>::template ssstring_with_cv_qual<CVQualSS, SuffixSSS>;
};

template <typename T, typename SuffixSSS, typename CVQualSS>
struct prefix_cv_qual_if_basictype<T, SuffixSSS, CVQualSS, false> {
	using ssstring = typename impl<T>::template ssstring<sssconcat<CVQualSS, SuffixSSS>>;
};

template <typename T>
struct _prefix_cv_qual_if_basictype {
	/*
	 * == SFINAE ==
	 * If impl<T> has a static member function named "value_with_cv_qual", then
	 * the forward() overload below is defined, and the call for forward() will
	 * prefer this overload over the other one that has varargs ("...").
	 * If impl<T> does not have such member, then the varargs overload is the
	 * only option.
	 */
	template <typename I>
	inline static split_string forward(const std::string& cv_qual, const split_string& suffix, decltype(I::value_with_cv_qual)*) {
		return I::value_with_cv_qual(cv_qual, suffix);
	}

	template <typename I>
	inline static split_string forward(const std::string& cv_qual, const split_string& suffix, ...) {
		return I::value(cv_qual + suffix);
	}

	inline static split_string value(const std::string& cv_qual, const split_string& suffix) {
		return forward<impl<T>>(cv_qual, suffix, nullptr);
	}
};

template <typename T>
struct has_ssstring {
	template <typename TT>
	constexpr static bool test(typename TT::template ssstring<>*) { return true; }

	template <typename TT>
	constexpr static bool test(...) { return false; }

	enum { value = test<impl<T>>(nullptr) };
};

template <typename T, bool = has_ssstring<T>::value>
struct const_impl;

template <typename T>
struct const_impl<T, true> {
	using _token_ss = static_string::static_string<char, 'c','o','n','s','t'>;

	template <typename SuffixSSS = empty_sss>
	using ssstring = typename prefix_cv_qual_if_basictype<T, SuffixSSS, _token_ss>::ssstring;
};

template <typename T>
struct const_impl<T, false> {};

template <typename T>
struct impl<const T> : const_impl<T> {
	inline static split_string value(const split_string& suffix = {}) {
		return _prefix_cv_qual_if_basictype<T>::value("const", suffix);
	}
};

template <typename T>
struct impl<volatile T> {
	inline static split_string value(const split_string& suffix = {}) {
		return _prefix_cv_qual_if_basictype<T>::value("volatile", suffix);
	}
};

// Required to disambiguate between <const T> and <volatile T>
template <typename T>
struct impl<const volatile T> {
	inline static split_string value(const split_string& suffix = {}) {
		return _prefix_cv_qual_if_basictype<T>::value("const volatile", suffix);
	}
};

template <typename T>
struct is_array_or_function : std::integral_constant<
	bool,
	std::is_array<T>::value || std::is_function<T>::value
> {};

template <typename T, bool = is_array_or_function<T>::value>
struct parenthesize_if_array_or_function;

template <typename T>
struct parenthesize_if_array_or_function<T, false> {
	inline static split_string value(const split_string& arg) {
		return impl<T>::value(arg);
	}
};

template <typename T>
struct parenthesize_if_array_or_function<T, true> {
	inline static split_string value(const split_string& arg) {
		return impl<T>::value("(" + arg + ")");
	}
};

template <typename T>
struct impl<T*> {
	inline static split_string value(const split_string& suffix = {}) {
		return parenthesize_if_array_or_function<T>::value("*" + suffix);
	}
};

template <typename T>
struct impl<T&> {
	inline static split_string value(const split_string& suffix = {}) {
		return parenthesize_if_array_or_function<T>::value("&" + suffix);
	}
};

template <typename T>
struct impl<T&&> {
	inline static split_string value(const split_string& suffix = {}) {
		return parenthesize_if_array_or_function<T>::value("&&" + suffix);
	}
};

template <typename T>
struct array_impl {
	inline static split_string value(const split_string& prefix = {}) {
		return impl<T>::value(prefix + "[]");
	}
};

template <typename T>
struct impl<T[]> : array_impl<T> {};

// Required to disambiguate between <const T> and <T[]>
template <typename T>
struct impl<const T[]> : array_impl<const T> {};

// Required to disambiguate between <volatile T> and <T[]>
template <typename T>
struct impl<volatile T[]> : array_impl<volatile T> {};

// Required to disambiguate between <const T>, <volatile T>, <const volatile T>,  <T[]>, <const T[]> and <volatile T[]>
template <typename T>
struct impl<const volatile T[]> : array_impl<const volatile T> {};

template <typename T, size_t N>
struct sized_array_impl {
	inline static split_string value(const split_string& prefix = {}) {
		return impl<T>::value(prefix + ("[" + std::to_string(N) + "]"));
	}
};

template <typename T, size_t N>
struct impl<T[N]> : sized_array_impl<T, N> {};

// Required to disambiguate between <const T> and <T[N]>
template <typename T, size_t N>
struct impl<const T[N]> : sized_array_impl<const T, N> {};

// Required to disambiguate between <volatile T> and <T[N]>
template <typename T, size_t N>
struct impl<volatile T[N]> : sized_array_impl<volatile T, N> {};

// Required to disambiguate between <const T>, <volatile T>, <const volatile T>,  <T[N]>, <const T[N]> and <volatile T[N]>
template <typename T, size_t N>
struct impl<const volatile T[N]> : sized_array_impl<const volatile T, N> {};

template <typename... T>
struct type_list_impl;

template <>
struct type_list_impl<> {
	inline static std::string value() {
		return "";
	}
};

struct varargs;

template <>
struct type_list_impl<varargs> {
	inline static std::string value() {
		return "...";
	}
};

template <typename T>
struct type_list_impl<T> {
	inline static std::string value() {
		return static_cast<std::string>(impl<T>::value());
	}
};

template <typename T1, typename T2, typename... U>
struct type_list_impl<T1, T2, U...> {
	inline static std::string value() {
		return type_list_impl<T1>::value() + ", " + type_list_impl<T2, U...>::value();
	}
};

template <bool RIsPtrOrRef, typename R, typename... A>
struct function_impl;

template <typename R, typename... A>
struct function_impl<false, R, A...> {
	inline static split_string value(const split_string& infix = {}) {
		return static_cast<std::string>(impl<R>::value()) + infix + "(" + type_list_impl<A...>::value() + ")";
	}
};

template <typename R, typename... A>
struct function_impl<true, R, A...> {
	inline static split_string value(const split_string& prefix = {}) {
		return impl<R>::value(prefix + "(" + type_list_impl<A...>::value() + ")");
	}
};

template <typename T>
struct is_pointer_or_reference : std::integral_constant<
	bool,
	std::is_pointer<T>::value || std::is_reference<T>::value
> {};

template <typename R, typename... A>
struct function_args_impl : function_impl<is_pointer_or_reference<typename std::remove_cv<R>::type>::value, R, A...> {};

template <typename R, typename... A>
struct impl<R(A...)>      : function_args_impl<R, A...> {};

template <typename R, typename... A>
struct impl<R(A..., ...)> : function_args_impl<R, A..., varargs> {};

template <typename T>
struct str_provider;

template <typename T, bool = has_ssstring<T>::value>
struct impl_proxy;

template <typename T>
struct impl_proxy<T, true> {
	inline static std::string value(const std::string& arg = "") {
		using i_sss = typename impl<T>::template ssstring<>;
		return i_sss::begin::string() + arg + i_sss::end::string();
	}
};

template <typename T>
struct impl_proxy<T, false> {
	inline static std::string value(const std::string& arg = "") {
		split_string ss = impl<T>::value();
		return ss.begin + arg + ss.end;
	}
};

} /* namespace __typedecl */
} /* unnamed namespace */

template <typename T>
inline std::string typedecl() {
	return __typedecl::impl_proxy<T>::value();
}

template <typename T>
inline std::string namedecl(const std::string& name) {
	return __typedecl::impl_proxy<T>::value(' ' + name);
}

#define DEFINE_TYPEDECL(T) \
	namespace { \
	namespace __typedecl { \
	template <> \
	struct str_provider<T> { \
		static constexpr const char* str() { return #T; } \
	}; \
	template <> \
	struct impl<T> { \
		using _token_ss = static_string::from_provider<str_provider<T>>; \
		template <typename SuffixSSS = empty_sss> using ssstring = sssconcat<_token_ss, SuffixSSS>; \
		template <typename CVQualSS, typename SuffixSSS> \
		using ssstring_with_cv_qual = sssconcat< \
		                                  static_string::concat<CVQualSS, space_ss, _token_ss>, \
		                                  SuffixSSS \
		                              >; \
		inline static split_string value(const split_string& suffix = {}) { \
			return #T + suffix; \
		} \
		inline static split_string value_with_cv_qual(const std::string& cv_qual, const split_string& suffix) { \
			return (cv_qual + " " #T) + suffix; \
		} \
	}; \
	} /* namespace __typedecl */ \
	} /* unnamed namespace */

DEFINE_TYPEDECL(void);
DEFINE_TYPEDECL(char);
DEFINE_TYPEDECL(int);

#endif
<|endoftext|>


<commit_before>#include <QtWidgets>
#include <QtWebKitWidgets>
#include "mainwindow.h"

const QString MainWindow::header = QString("");
const QString MainWindow::footer = QString("");

MainWindow::MainWindow(QStringList files, QUrl styleUrl) : styleUrl(styleUrl)
{
	// setup webview
	view = new QWebView(this);
	// open links in external browser
	view->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
	// disable right click menu
	view->setContextMenuPolicy(Qt::NoContextMenu);

	// setup markdown renderer
	renderer = hoedown_html_renderer_new(hoedown_html_flags(0), 0);
	// github style exensions
	hoedown_extensions ext = hoedown_extensions(HOEDOWN_EXT_TABLES |
			HOEDOWN_EXT_FENCED_CODE | HOEDOWN_EXT_AUTOLINK |
			HOEDOWN_EXT_STRIKETHROUGH | HOEDOWN_EXT_NO_INTRA_EMPHASIS);
	document = hoedown_document_new(renderer, ext, 16);

	watcher = new QFileSystemWatcher();
	connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(reload()));
	connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(reload()));
	connect(view, SIGNAL(linkClicked(QUrl)), this, SLOT(openExtern(QUrl)));

	setCentralWidget(view);

	if (files.size() == 0) {
		view->setHtml(header+"Open new file with o"+footer);
		return;
	}

	for (int i = 1; i < files.size(); i++) {
		if (!watcher->addPath(files.at(i)))
			qWarning("Error watching %s.", qPrintable(files.at(i)));
	}

	loadNewFile(files.at(0));
}

void MainWindow::requestNewFile() {
	QString dirName;
	if (info)
		dirName = info->canonicalPath();
	if (dirName.isEmpty())
		dirName = QDir::homePath();
	QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),
			dirName,
			tr("Markdown (*.md);;All Files (*)"));

	if (fileName.isEmpty())
		return;

	loadNewFile(fileName);
}

void MainWindow::loadNewFile(const QString &fileName) {
	// remove old watcher
	if (info)
		watcher->removePath(info->fileName());

	file = new QFile(fileName);
	info = new QFileInfo(fileName);
	if (!info->exists()) {
		view->setHtml(header+QString("File %1 doesn't exist!").arg(fileName)+footer);
		return;
	}

	// use css style sheet if markdown
	if (info->suffix() == "md")
		view->settings()->setUserStyleSheetUrl(styleUrl);
	else
		view->settings()->setUserStyleSheetUrl(QUrl(""));

	this->setWindowTitle(fileName + " - ViewDown");

	baseUrl = QUrl("file://"+info->canonicalPath()+"/");

	if (!watcher->addPath(fileName))
		qWarning("Error watching %s.", qPrintable(fileName));

	reload();
}

void MainWindow::reload() {
	QWebSettings::clearMemoryCaches();

	info->refresh();
	if (!file->open(QFile::ReadOnly | QFile::Text)){
		view->setHtml(header+QString("Failed to open  %1!").arg(info->fileName())+footer);
		return;
	}
	QTextStream in(file);
	QString data = in.readAll();
	file->close();

	if (info->suffix() == "md")
		parseMarkdown(data);

	// restore scroll position
	QPoint point = view->page()->mainFrame()->scrollPosition();
	view->setHtml(data, baseUrl);
	view->page()->mainFrame()->setScrollPosition(point);
}

void MainWindow::parseMarkdown(QString &data) {
	QByteArray ba = data.toLocal8Bit();

	hoebuf = hoedown_buffer_new(16);
	hoedown_document_render(document, hoebuf, (unsigned char*)ba.constData(), ba.size());

	const QString md = QString::fromLocal8Bit((char*)hoebuf->data, hoebuf->size);
	hoedown_buffer_free(hoebuf);
	data = header + md + footer;
}

void MainWindow::openExtern(const QUrl &url) {
	QDesktopServices::openUrl(url);
}

void MainWindow::toggleInspector() {
	if (!inspector) {
		view->page()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
		inspector = new QWebInspector;
		inspector->setPage(view->page());
	}
	if (inspector->isVisible())
		inspector->setVisible(false);
	else
		inspector->setVisible(true);
}

void MainWindow::keyPressEvent(QKeyEvent *event) {
	switch (event->key()) {
		case Qt::Key_Q:
			close();
			break;
		case Qt::Key_R:
			reload();
			break;
		case Qt::Key_O:
			requestNewFile();
			break;
		case Qt::Key_I:
			toggleInspector();
			break;
		default:
			QMainWindow::keyPressEvent(event);
	}
}

void MainWindow::closeEvent(QCloseEvent *event) {
	if (inspector)
		inspector->close();
	QMainWindow::closeEvent(event);
}

MainWindow::~MainWindow() {
	hoedown_document_free(document);
	hoedown_html_renderer_free(renderer);
}
<commit_msg>fix error messages, add .html to open dialog<commit_after>#include <QtWidgets>
#include <QtWebKitWidgets>
#include "mainwindow.h"

const QString MainWindow::header = QString("");
const QString MainWindow::footer = QString("");

MainWindow::MainWindow(QStringList files, QUrl styleUrl) : styleUrl(styleUrl)
{
	// setup webview
	view = new QWebView(this);
	// open links in external browser
	view->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
	// disable right click menu
	view->setContextMenuPolicy(Qt::NoContextMenu);

	// setup markdown renderer
	renderer = hoedown_html_renderer_new(hoedown_html_flags(0), 0);
	// github style exensions
	hoedown_extensions ext = hoedown_extensions(HOEDOWN_EXT_TABLES |
			HOEDOWN_EXT_FENCED_CODE | HOEDOWN_EXT_AUTOLINK |
			HOEDOWN_EXT_STRIKETHROUGH | HOEDOWN_EXT_NO_INTRA_EMPHASIS);
	document = hoedown_document_new(renderer, ext, 16);

	watcher = new QFileSystemWatcher();
	connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(reload()));
	connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(reload()));
	connect(view, SIGNAL(linkClicked(QUrl)), this, SLOT(openExtern(QUrl)));

	setCentralWidget(view);

	if (files.size() == 0) {
		view->setHtml(header+"Open new file with o"+footer);
		return;
	}

	for (int i = 1; i < files.size(); i++) {
		if (!watcher->addPath(files.at(i)))
			qWarning("Error watching '%s'.", qPrintable(files.at(i)));
	}

	loadNewFile(files.at(0));
}

void MainWindow::requestNewFile() {
	QString dirName;
	if (info)
		dirName = info->canonicalPath();
	if (dirName.isEmpty())
		dirName = QDir::homePath();
	QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),
			dirName,
			tr("Markdown (*.md);;HTML (*.html);;All Files (*)"));

	if (fileName.isEmpty())
		return;

	loadNewFile(fileName);
}

void MainWindow::loadNewFile(const QString &fileName) {
	// remove old watcher
	if (info)
		watcher->removePath(info->fileName());

	file = new QFile(fileName);
	info = new QFileInfo(fileName);
	if (!info->exists()) {
		view->setHtml(header+QString("File `%1` doesn't exist!").arg(fileName)+footer);
		return;
	}

	// use css style sheet if markdown
	if (info->suffix() == "md")
		view->settings()->setUserStyleSheetUrl(styleUrl);
	else
		view->settings()->setUserStyleSheetUrl(QUrl(""));

	this->setWindowTitle(fileName + " - ViewDown");

	baseUrl = QUrl("file://"+info->canonicalPath()+"/");

	if (!watcher->addPath(fileName))
		qWarning("Error watching %s.", qPrintable(fileName));

	reload();
}

void MainWindow::reload() {
	QWebSettings::clearMemoryCaches();

	info->refresh();
	if (!file->open(QFile::ReadOnly | QFile::Text)){
		view->setHtml(header+QString("Failed to open `%1`!").arg(info->fileName())+footer);
		return;
	}
	QTextStream in(file);
	QString data = in.readAll();
	file->close();

	if (info->suffix() == "md")
		parseMarkdown(data);

	// restore scroll position
	QPoint point = view->page()->mainFrame()->scrollPosition();
	view->setHtml(data, baseUrl);
	view->page()->mainFrame()->setScrollPosition(point);
}

void MainWindow::parseMarkdown(QString &data) {
	QByteArray ba = data.toLocal8Bit();

	hoebuf = hoedown_buffer_new(16);
	hoedown_document_render(document, hoebuf, (unsigned char*)ba.constData(), ba.size());

	const QString md = QString::fromLocal8Bit((char*)hoebuf->data, hoebuf->size);
	hoedown_buffer_free(hoebuf);
	data = header + md + footer;
}

void MainWindow::openExtern(const QUrl &url) {
	QDesktopServices::openUrl(url);
}

void MainWindow::toggleInspector() {
	if (!inspector) {
		view->page()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
		inspector = new QWebInspector;
		inspector->setPage(view->page());
	}
	if (inspector->isVisible())
		inspector->setVisible(false);
	else
		inspector->setVisible(true);
}

void MainWindow::keyPressEvent(QKeyEvent *event) {
	switch (event->key()) {
		case Qt::Key_Q:
			close();
			break;
		case Qt::Key_R:
			reload();
			break;
		case Qt::Key_O:
			requestNewFile();
			break;
		case Qt::Key_I:
			toggleInspector();
			break;
		default:
			QMainWindow::keyPressEvent(event);
	}
}

void MainWindow::closeEvent(QCloseEvent *event) {
	if (inspector)
		inspector->close();
	QMainWindow::closeEvent(event);
}

MainWindow::~MainWindow() {
	hoedown_document_free(document);
	hoedown_html_renderer_free(renderer);
}
<|endoftext|>


<commit_before>
#include <sys/eventfd.h>
#include "config/args.hpp"
#include "config/code.hpp"
#include "message_hub.hpp"
#include "event_queue.hpp"
#include "worker_pool.hpp"

int key_to_cpu(btree_key *key, unsigned int ncpus)
{
    // TODO: we better find a good hash function or the whole
    // concurrency model goes to crap.

    //FIXME: This temporary hash results in uneven distribution
    return key->contents[key->size-1] % ncpus;
}

void message_hub_t::init(unsigned int cpu_id, unsigned int _ncpus, worker_t *workers[])
{
    current_cpu = cpu_id;
    ncpus = _ncpus;
    check("Can't support so many CPUs", ncpus > MAX_CPUS);
    for(unsigned int i = 0; i < ncpus; i++) {
        pthread_spin_init(&queues[i].lock, PTHREAD_PROCESS_PRIVATE);
        // TODO: unit tests currently don't mock the event queue, but
        // pass NULL instead. Make event_queue mockable.
        if(workers) {
            queues[i].eq = workers[i]->event_queue;
        } else {
            queues[i].eq = NULL;
        }
    }
}

message_hub_t::~message_hub_t() {
    for(unsigned int i = 0; i < ncpus; i++) {
        pthread_spin_destroy(&queues[i].lock);
    }
}

// Collects a message for a given CPU onto a local list.
void message_hub_t::store_message(unsigned int ncpu, cpu_message_t *msg) {
    assert(ncpu < ncpus);
    msg->return_cpu = current_cpu;
    queues[ncpu].msg_local_list.push_back(msg);
}

// Pushes messages collected locally global lists available to all
// CPUs.
void message_hub_t::push_messages() {
    for(unsigned int i = 0; i < ncpus; i++) {
        // Append the local list for ith cpu to that cpu's global
        // message list.
        cpu_queue_t *queue = &queues[i];
        if(!queue->msg_local_list.empty()) {
            pthread_spin_lock(&queue->lock);
            queue->msg_global_list.append_and_clear(&queue->msg_local_list);
            pthread_spin_unlock(&queue->lock);

            // TODO: event queue isn't mockable right now, so unit
            // tests pass NULL instead. When we refactor
            // event_queue_t, we should refactor other places so that
            // we can pass a mock version instead.
            if(queue->eq) {
                // Wakey wakey eggs and bakey
                int res = eventfd_write(queue->eq->core_notify_fd, 1);
                if(res != 0) {
                    // Perhaps the fd is overflown, let's clear it and try writing again
                    eventfd_t temp;
                    res = eventfd_read(queue->eq->core_notify_fd, &temp);
                    check("Could not clear an overflown core_notify_fd", res != 0);

                    // If it doesn't work this time, we're fucked beyond recovery
                    res = eventfd_write(queue->eq->core_notify_fd, 1);
                    check("Could not send a core notification via core_notify_fd", res != 0);
                }
            }
        }

        // TODO: we should use regular mutexes on single core CPU
        // instead of spinlocks
    }
}

// Pulls the messages stored in global lists for a given CPU.
void message_hub_t::pull_messages(unsigned int ncpu, msg_list_t *msg_list) {
    // Store the pointers to the elements in a temporary variable,
    // and clear the list while the whole shebang is locked.
    cpu_queue_t *queue = &queues[ncpu];
    pthread_spin_lock(&queue->lock);
    if(!queue->msg_global_list.empty()) {
        *msg_list = queue->msg_global_list;
        queue->msg_global_list.clear();
    } else {
        msg_list->clear();
    }
    pthread_spin_unlock(&queue->lock);

    // TODO: we should use regular mutexes on single core CPU
    // instead of spinlocks
}
<commit_msg>Adds hashing functions for both cpu and slice.<commit_after>
#include <sys/eventfd.h>
#include "config/args.hpp"
#include "config/code.hpp"
#include "message_hub.hpp"
#include "event_queue.hpp"
#include "worker_pool.hpp"

int hash(btree_key *key)
{
    // TODO: we better find a good hash function or the whole
    // concurrency model goes to crap.

    //FIXME: This temporary hash results in uneven distribution
    return key->contents[key->size-1];
}

int key_to_cpu(btree_key *key, unsigned int ncpus)
{
    return hash(key) % ncpus;
}

int key_to_chache(btree_key *key, unsigned int ncpus, unsigned int ncache) {
    // this avoids hash correlation that would occur if ncpus and ncache weren't coprime
    // (which is likely since they'll most likely be powers of 2)
    return (hash(key) / ncpus) % ncache;
}

void message_hub_t::init(unsigned int cpu_id, unsigned int _ncpus, worker_t *workers[])
{
    current_cpu = cpu_id;
    ncpus = _ncpus;
    check("Can't support so many CPUs", ncpus > MAX_CPUS);
    for(unsigned int i = 0; i < ncpus; i++) {
        pthread_spin_init(&queues[i].lock, PTHREAD_PROCESS_PRIVATE);
        // TODO: unit tests currently don't mock the event queue, but
        // pass NULL instead. Make event_queue mockable.
        if(workers) {
            queues[i].eq = workers[i]->event_queue;
        } else {
            queues[i].eq = NULL;
        }
    }
}

message_hub_t::~message_hub_t() {
    for(unsigned int i = 0; i < ncpus; i++) {
        pthread_spin_destroy(&queues[i].lock);
    }
}

// Collects a message for a given CPU onto a local list.
void message_hub_t::store_message(unsigned int ncpu, cpu_message_t *msg) {
    assert(ncpu < ncpus);
    msg->return_cpu = current_cpu;
    queues[ncpu].msg_local_list.push_back(msg);
}

// Pushes messages collected locally global lists available to all
// CPUs.
void message_hub_t::push_messages() {
    for(unsigned int i = 0; i < ncpus; i++) {
        // Append the local list for ith cpu to that cpu's global
        // message list.
        cpu_queue_t *queue = &queues[i];
        if(!queue->msg_local_list.empty()) {
            pthread_spin_lock(&queue->lock);
            queue->msg_global_list.append_and_clear(&queue->msg_local_list);
            pthread_spin_unlock(&queue->lock);

            // TODO: event queue isn't mockable right now, so unit
            // tests pass NULL instead. When we refactor
            // event_queue_t, we should refactor other places so that
            // we can pass a mock version instead.
            if(queue->eq) {
                // Wakey wakey eggs and bakey
                int res = eventfd_write(queue->eq->core_notify_fd, 1);
                if(res != 0) {
                    // Perhaps the fd is overflown, let's clear it and try writing again
                    eventfd_t temp;
                    res = eventfd_read(queue->eq->core_notify_fd, &temp);
                    check("Could not clear an overflown core_notify_fd", res != 0);

                    // If it doesn't work this time, we're fucked beyond recovery
                    res = eventfd_write(queue->eq->core_notify_fd, 1);
                    check("Could not send a core notification via core_notify_fd", res != 0);
                }
            }
        }

        // TODO: we should use regular mutexes on single core CPU
        // instead of spinlocks
    }
}

// Pulls the messages stored in global lists for a given CPU.
void message_hub_t::pull_messages(unsigned int ncpu, msg_list_t *msg_list) {
    // Store the pointers to the elements in a temporary variable,
    // and clear the list while the whole shebang is locked.
    cpu_queue_t *queue = &queues[ncpu];
    pthread_spin_lock(&queue->lock);
    if(!queue->msg_global_list.empty()) {
        *msg_list = queue->msg_global_list;
        queue->msg_global_list.clear();
    } else {
        msg_list->clear();
    }
    pthread_spin_unlock(&queue->lock);

    // TODO: we should use regular mutexes on single core CPU
    // instead of spinlocks
}
<|endoftext|>


<commit_before>#pragma once

#include <vector>
#include <memory>

template <typename T>
class MessageBusProxy;

template <typename MessageType>
class MessageBus {
	public:
		void push(const MessageType& message);

		static std::shared_ptr<MessageBus>&& getBus();

		MessageBus()=default;
	private:

		std::vector<MessageType> m_messages;
		std::vector<MessageBusProxy<MessageType>*> m_proxys;

		static std::weak_ptr<MessageBus<MessageType>> m_bus;
};

template <typename MessageType>
void MessageBus<MessageType>::push(const MessageType& message)
{
	m_messages.push_back(message);
	// TODO: stack
}

template <typename MessageType>
std::shared_ptr<MessageBus<MessageType>>&& MessageBus<MessageType>::getBus()
{
	if (m_bus.expired())
	{
		auto ptr = std::make_shared<MessageBus<MessageType>>();

	}
}

template <typename MessageType>
std::weak_ptr<MessageBus<MessageType>> MessageBus<MessageType>::m_bus;<commit_msg>Fix brutal close.<commit_after>#pragma once

#include <vector>
#include <memory>
#include <iostream>

template <typename T>
class MessageBusProxy;

template <typename MessageType>
class MessageBus {
	public:
		void push(const MessageType& message);

		static std::shared_ptr<MessageBus>&& getBus();

		MessageBus()=default;
	private:

		std::vector<MessageType> m_messages;
		std::vector<MessageBusProxy<MessageType>*> m_proxys;

		static std::weak_ptr<MessageBus<MessageType>> m_bus;
};

template <typename MessageType>
void MessageBus<MessageType>::push(const MessageType& message)
{
	if (m_proxys.empty())
		return;
	m_messages.push_back(message);
	// TODO: stack
}

template <typename MessageType>
std::shared_ptr<MessageBus<MessageType>>&& MessageBus<MessageType>::getBus()
{
	if (m_bus.expired())
	{
		std::cout << "bus expired"<< std::endl;
		auto ptr = std::make_shared<MessageBus<MessageType>>();
		m_bus = std::weak_ptr<MessageBus<MessageType>>(ptr);
		return std::move(ptr);
	}
	return std::move(m_bus.lock());
}

template <typename MessageType>
std::weak_ptr<MessageBus<MessageType>> MessageBus<MessageType>::m_bus;
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2010 Hermann Kraus
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// Mapnik
#include <mapnik/metawriter.hpp>
#include <mapnik/metawriter_json.hpp>

// Boost
#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>

// STL
#include <iomanip>
#include <cstdio>

namespace mapnik {

metawriter_json::metawriter_json(metawriter_properties dflt_properties, std::string fn)
    : metawriter(dflt_properties), fn_(fn), count(0)
{

}

metawriter_json::~metawriter_json()
{
     stop();
}

void metawriter_json::start()
{
    if (f.is_open())
    {
        std::cerr << "ERROR: GeoJSON metawriter is already active!\n";
    }
    f.open(fn_.c_str(), std::fstream::out | std::fstream::trunc);
    if (f.fail()) perror((std::string("Failed to open file ") + fn_).c_str());
    f << "{ \"type\": \"FeatureCollection\", \"features\": [\n";
}

void metawriter_json::stop()
{
    if (f.is_open())
    {
        f << " ] }\n";
        f.close();
    }
}

void metawriter_json::add_box(box2d<double> box, Feature const &feature,
                              proj_transform const& prj_trans, CoordTransform const &t,
                              const metawriter_properties& properties)
{
    metawriter_properties props;
    if (properties.empty())
    {
        props = dflt_properties_;
    }
    else
    {
        props = properties;
    }
    if (props.empty())
    {
        std::cerr << "WARNING: No expression available for GeoJSON metawriter.\n";
        return;
    }

    /* Coordinate transform in renderer:
       input: layer srs
       prj_trans.backwards()   [prj_trans: map -> layer]
       intermediate: map srs
       t_.forward()
       output: pixels

       Our transform:
       input: pixels
       t_.backward()
       intermediate: map srs (available via prj_trans.source())
       trans.forward()
       output: WGS84
    */

    proj_transform trans(prj_trans.source(), projection("+proj=latlong +datum=WGS84"));
    //t_ coord transform has transform for box2d combined with prj_trans
    box = t.backward(box, trans);

    double minx = box.minx();
    double miny = box.miny();
    double maxx = box.maxx();
    double maxy = box.maxy();

    if (count++) f << ",\n";
    f << std::fixed << std::setprecision(8) << "{ \"type\": \"Feature\",\n  \"geometry\": { \"type\": \"Polygon\",\n    \"coordinates\": [ [ [" <<
            minx << ", " << miny << "], [" <<
            maxx << ", " << miny << "], [" <<
            maxx << ", " << maxy << "], [" <<
            minx << ", " << maxy << "] ] ] }," <<
            "\n  \"properties\": {";
    std::map<std::string, value> fprops = feature.props();
    int i = 0;
    BOOST_FOREACH(std::string p, props)
    {
        std::map<std::string, value>::const_iterator itr = fprops.find(p);
        std::string text;
        if (itr != fprops.end())
        {
            //Property found
            text = boost::replace_all_copy(boost::replace_all_copy(itr->second.to_string(), "\\", "\\\\"), "\"", "\\\"");
        }
        if (i++) f << ",";
        f << "\n    \"" << p << "\":\"" << text << "\"";
    }

    f << "\n} }";
}

metawriter_properties metawriter::parse_properties(boost::optional<std::string> str)
{
    metawriter_properties properties;
    if (str) {
        std::string str_ = boost::algorithm::erase_all_copy(*str, " ");
        boost::split(properties, str_, boost::is_any_of(","), boost::token_compress_on);
    }
    return properties;
}
};
<commit_msg>Undo accidential change.<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2010 Hermann Kraus
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// Mapnik
#include <mapnik/metawriter.hpp>
#include <mapnik/metawriter_json.hpp>

// Boost
#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>

// STL
#include <iomanip>
#include <cstdio>

namespace mapnik {

metawriter_json::metawriter_json(metawriter_properties dflt_properties, std::string fn)
    : metawriter(dflt_properties), fn_(fn), count(0)
{

}

metawriter_json::~metawriter_json()
{
    stop();
}

void metawriter_json::start()
{
    if (f.is_open())
    {
        std::cerr << "ERROR: GeoJSON metawriter is already active!\n";
    }
    f.open(fn_.c_str(), std::fstream::out | std::fstream::trunc);
    if (f.fail()) perror((std::string("Failed to open file ") + fn_).c_str());
    f << "{ \"type\": \"FeatureCollection\", \"features\": [\n";
}

void metawriter_json::stop()
{
    if (f.is_open())
    {
        f << " ] }\n";
        f.close();
    }
}

void metawriter_json::add_box(box2d<double> box, Feature const &feature,
                              proj_transform const& prj_trans, CoordTransform const &t,
                              const metawriter_properties& properties)
{
    metawriter_properties props;
    if (properties.empty())
    {
        props = dflt_properties_;
    }
    else
    {
        props = properties;
    }
    if (props.empty())
    {
        std::cerr << "WARNING: No expression available for GeoJSON metawriter.\n";
        return;
    }

    /* Coordinate transform in renderer:
       input: layer srs
       prj_trans.backwards()   [prj_trans: map -> layer]
       intermediate: map srs
       t_.forward()
       output: pixels

       Our transform:
       input: pixels
       t_.backward()
       intermediate: map srs (available via prj_trans.source())
       trans.forward()
       output: WGS84
    */

    proj_transform trans(prj_trans.source(), projection("+proj=latlong +datum=WGS84"));
    //t_ coord transform has transform for box2d combined with prj_trans
    box = t.backward(box, trans);

    double minx = box.minx();
    double miny = box.miny();
    double maxx = box.maxx();
    double maxy = box.maxy();

    if (count++) f << ",\n";
    f << std::fixed << std::setprecision(8) << "{ \"type\": \"Feature\",\n  \"geometry\": { \"type\": \"Polygon\",\n    \"coordinates\": [ [ [" <<
            minx << ", " << miny << "], [" <<
            maxx << ", " << miny << "], [" <<
            maxx << ", " << maxy << "], [" <<
            minx << ", " << maxy << "] ] ] }," <<
            "\n  \"properties\": {";
    std::map<std::string, value> fprops = feature.props();
    int i = 0;
    BOOST_FOREACH(std::string p, props)
    {
        std::map<std::string, value>::const_iterator itr = fprops.find(p);
        std::string text;
        if (itr != fprops.end())
        {
            //Property found
            text = boost::replace_all_copy(boost::replace_all_copy(itr->second.to_string(), "\\", "\\\\"), "\"", "\\\"");
        }
        if (i++) f << ",";
        f << "\n    \"" << p << "\":\"" << text << "\"";
    }

    f << "\n} }";
}

metawriter_properties metawriter::parse_properties(boost::optional<std::string> str)
{
    metawriter_properties properties;
    if (str) {
        std::string str_ = boost::algorithm::erase_all_copy(*str, " ");
        boost::split(properties, str_, boost::is_any_of(","), boost::token_compress_on);
    }
    return properties;
}
};
<|endoftext|>


<commit_before>/*
* mod_compare - compares apache requests
*
* Copyright (C) 2013 Orange
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <httpd.h>
#include <http_config.h>
#include <http_request.h>
#include <http_protocol.h>
#include <http_connection.h>
#include <apr_pools.h>
#include <apr_hooks.h>
#include "apr_strings.h"
#include <unistd.h>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <exception>
#include <set>
#include <sstream>
#include <sys/syscall.h>
#include <algorithm>
#include <boost/tokenizer.hpp>
#include <fstream>

#include "mod_compare.hh"

namespace alg = boost::algorithm;

namespace CompareModule {

const char *gName = "Compare";
const char *c_COMPONENT_VERSION = "Compare/1.0";
const char* c_UNIQUE_ID = "UNIQUE_ID";

std::ofstream gFile;
const char * gFilePath;
boost::interprocess::named_mutex gMutex(boost::interprocess::open_or_create, "mod_compare_log_mutex");

CompareConf::CompareConf(): mCompareDisabled(false) {
}

apr_status_t CompareConf::cleaner(void *self) {
    if(self){
        CompareConf *c = reinterpret_cast<CompareConf *>(self);

        c->~CompareConf();
    }
    return 0;
}

/**
 * @brief allocate a pointer to a string which will hold the path for the dir config if mod_compare is active on it
 * @param pPool the apache pool on which to allocate data
 * @param pDirName the directory name for which to create data
 * @return a void pointer to newly allocated object
 */
void *
createDirConfig(apr_pool_t *pPool, char *pDirName)
{
    void *addr= apr_pcalloc(pPool, sizeof(class CompareConf));
    new (addr) CompareConf();
    apr_pool_cleanup_register(pPool, addr, CompareConf::cleaner,  apr_pool_cleanup_null);
    return addr;
}

/**
 * @brief Initialize logging post-config
 * @param pPool the apache pool
 * @param pServer the corresponding server record
 * @return Always OK
 */
int
postConfig(apr_pool_t * pPool, apr_pool_t * pLog, apr_pool_t * pTemp, server_rec * pServer) {
    Log::init();

    ap_add_version_component(pPool, c_COMPONENT_VERSION) ;
    return OK;
}

apr_status_t
closeLogFile(void *) {

    gFile.close();
    return APR_SUCCESS;
}

apr_status_t openLogFile(const char * filepath,std::ios_base::openmode mode) {
    gFile.open(filepath,mode);
    if (!gFile.is_open()){
    	Log::warn(43,"Couldn't open correctly the file, we'll now attempt to close and reopen it");
    	gFile.close();
    	gFile.open(filepath,mode);
    	if (!gFile.is_open()){
    		Log::error(43,std::string("Couldn't open the file :").append(filepath).c_str());
    		throw std::ofstream::failure(std::string("Couldn't open the file :").append(filepath));
    	}
    }
    return APR_SUCCESS;
}

void
childInit(apr_pool_t *pPool, server_rec *pServer)
{
    gFile.open(gFilePath, std::ofstream::out | std::ofstream::app );
    apr_pool_cleanup_register(pPool, NULL, apr_pool_cleanup_null, closeLogFile);
}

/**
 * @brief Set the list of errors which stop the comparison
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pListType the type of list (STOP or IGNORE)
 * @param pValue the reg_ex to insert in the list
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setBodyList(cmd_parms* pParams, void* pCfg, const char* pListType, const char* pValue) {
    if (!pValue || strlen(pValue) == 0) {
        return "Missing reg_ex value for the body";
    }

    if (!pListType || strlen(pListType) == 0) {
        return "Missing the type of list";
    }

    CompareConf *lConf = reinterpret_cast<CompareConf *>(pCfg);
    std::string lListType(pListType);
    std::string lValue(pValue);

    if (strcmp("STOP", pListType) == 0)
    {
        lConf->mCompBody.addStopRegex(lValue);
    }
    else if(strcmp("IGNORE", pListType) == 0)
    {
        lConf->mCompBody.addIgnoreRegex(lValue);
    }
    else
    {
        return "Invalid value for the list type";
    }

    return NULL;
}

/**
 * @brief Set the list of errors to ignore in the comparison
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pListType the type of list (STOP or IGNORE)
 * @param pHeader the header for which to apply the regex
 * @param pValue the reg_ex to insert in the list
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char* setHeaderList(cmd_parms* pParams, void* pCfg, const char* pListType, const char* pAffectedKey,const char* pValue) {
    if (!pValue || strlen(pValue) == 0) {
        return "Missing reg_ex value for the header";
    }

    if (!pAffectedKey || strlen(pAffectedKey) == 0) {
            return "Missing header value";
        }

    if (!pListType || strlen(pListType) == 0) {
        return "Missing the type list";
    }

    CompareConf *lConf = reinterpret_cast<CompareConf *>(pCfg);
    std::string lHeader(pAffectedKey);
    std::string lValue(pValue);

    if (strcmp("STOP", pListType) == 0)
    {
        lConf->mCompHeader.addStopRegex(lHeader, lValue);
    }
    else if(strcmp("IGNORE", pListType) == 0)
    {
        lConf->mCompHeader.addIgnoreRegex(lHeader, lValue);
    }
    else
    {
        return "Invalid value for the list type";
    }

    return NULL;
}

/**
 * @brief Set the list of errors to ignore in the comparison
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pListType the type of list (Header or Body)
 * @param pValue the value to insert in the list
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char* setFilePath(cmd_parms* pParams, void* pCfg, const char* pPath) {
    if (!pPath || strlen(pPath) == 0) {
        return "Missing path value";
    }
    Log::init();
    gFilePath = pPath;
    std::string lPath(gFilePath);
    Log::error(12, "ecco qui il percorso del file %s", lPath.c_str());

    return NULL;
}

/**
 * @brief Enable/Disable the utilization of the libws-diff tools
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pValue the value
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setDisableLibwsdiff(cmd_parms* pParams, void* pCfg, const char* pValue) {
	CompareConf *lConf = reinterpret_cast<CompareConf *>(pCfg);
	lConf->mCompareDisabled= strcmp(pValue, "1")==0 || strcmp(pValue, "true")==0;
    if(lConf->mCompareDisabled){
    	Log::warn(42,"The use of the diffing library libws-diff has been disabled!");
    }
    return NULL;
}

/** @brief Declaration of configuration commands */
    command_rec gCmds[] = {
        // AP_INIT_(directive,
        //          function,
        //          void * extra data,
        //          overrides to allow in order to enable,
        //          help message),
        AP_INIT_TAKE2("BodyList",
                      reinterpret_cast<const char *(*)()>(&setBodyList),
                      0,
                      ACCESS_CONF,
                      "List of reg_ex to apply to the body for the comparison."),
        AP_INIT_TAKE3("HeaderList",
                      reinterpret_cast<const char *(*)()>(&setHeaderList),
                      0,
                      ACCESS_CONF,
                      "List of reg_ex to apply to the Header for the comparison."),
        AP_INIT_TAKE1("FilePath",
                      reinterpret_cast<const char *(*)()>(&setFilePath),
                      0,
                      OR_ALL,
                      "Path of file where the differences will be logged."),
        AP_INIT_TAKE1("DisableLibwsdiff",
                      reinterpret_cast<const char *(*)()>(&setDisableLibwsdiff),
                      0,
                      OR_ALL,
                      "Disable the use of libws-diff tools. Print raw serialization of the data in the log file."),
        {0}
    };

/**
 * @brief register hooks in apache
 * @param pPool the apache pool
 */
void
registerHooks(apr_pool_t *pPool) {
#ifndef UNIT_TESTING
    ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_child_init(&childInit, NULL, NULL, APR_HOOK_MIDDLE);
    ap_register_input_filter(gName, inputFilterHandler, NULL, AP_FTYPE_RESOURCE);
    ap_register_output_filter(gName, outputFilterHandler, NULL, AP_FTYPE_RESOURCE);
#endif
}

} // End namespace

/// Apache module declaration
module AP_MODULE_DECLARE_DATA compare_module = {
    STANDARD20_MODULE_STUFF,
    CompareModule::createDirConfig,
    0, // merge_dir_config
    0, // create_server_config
    0, // merge_server_config
    CompareModule::gCmds,
    CompareModule::registerHooks
};
<commit_msg>removed log of file path<commit_after>/*
* mod_compare - compares apache requests
*
* Copyright (C) 2013 Orange
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <httpd.h>
#include <http_config.h>
#include <http_request.h>
#include <http_protocol.h>
#include <http_connection.h>
#include <apr_pools.h>
#include <apr_hooks.h>
#include "apr_strings.h"
#include <unistd.h>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <exception>
#include <set>
#include <sstream>
#include <sys/syscall.h>
#include <algorithm>
#include <boost/tokenizer.hpp>
#include <fstream>

#include "mod_compare.hh"

namespace alg = boost::algorithm;

namespace CompareModule {

const char *gName = "Compare";
const char *c_COMPONENT_VERSION = "Compare/1.0";
const char* c_UNIQUE_ID = "UNIQUE_ID";

std::ofstream gFile;
const char * gFilePath;
boost::interprocess::named_mutex gMutex(boost::interprocess::open_or_create, "mod_compare_log_mutex");

CompareConf::CompareConf(): mCompareDisabled(false) {
}

apr_status_t CompareConf::cleaner(void *self) {
    if(self){
        CompareConf *c = reinterpret_cast<CompareConf *>(self);

        c->~CompareConf();
    }
    return 0;
}

/**
 * @brief allocate a pointer to a string which will hold the path for the dir config if mod_compare is active on it
 * @param pPool the apache pool on which to allocate data
 * @param pDirName the directory name for which to create data
 * @return a void pointer to newly allocated object
 */
void *
createDirConfig(apr_pool_t *pPool, char *pDirName)
{
    void *addr= apr_pcalloc(pPool, sizeof(class CompareConf));
    new (addr) CompareConf();
    apr_pool_cleanup_register(pPool, addr, CompareConf::cleaner,  apr_pool_cleanup_null);
    return addr;
}

/**
 * @brief Initialize logging post-config
 * @param pPool the apache pool
 * @param pServer the corresponding server record
 * @return Always OK
 */
int
postConfig(apr_pool_t * pPool, apr_pool_t * pLog, apr_pool_t * pTemp, server_rec * pServer) {
    Log::init();

    ap_add_version_component(pPool, c_COMPONENT_VERSION) ;
    return OK;
}

apr_status_t
closeLogFile(void *) {

    gFile.close();
    return APR_SUCCESS;
}

apr_status_t openLogFile(const char * filepath,std::ios_base::openmode mode) {
    gFile.open(filepath,mode);
    if (!gFile.is_open()){
    	Log::warn(43,"Couldn't open correctly the file, we'll now attempt to close and reopen it");
    	gFile.close();
    	gFile.open(filepath,mode);
    	if (!gFile.is_open()){
    		Log::error(43,std::string("Couldn't open the file :").append(filepath).c_str());
    		throw std::ofstream::failure(std::string("Couldn't open the file :").append(filepath));
    	}
    }
    return APR_SUCCESS;
}

void
childInit(apr_pool_t *pPool, server_rec *pServer)
{
    gFile.open(gFilePath, std::ofstream::out | std::ofstream::app );
    apr_pool_cleanup_register(pPool, NULL, apr_pool_cleanup_null, closeLogFile);
}

/**
 * @brief Set the list of errors which stop the comparison
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pListType the type of list (STOP or IGNORE)
 * @param pValue the reg_ex to insert in the list
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setBodyList(cmd_parms* pParams, void* pCfg, const char* pListType, const char* pValue) {
    if (!pValue || strlen(pValue) == 0) {
        return "Missing reg_ex value for the body";
    }

    if (!pListType || strlen(pListType) == 0) {
        return "Missing the type of list";
    }

    CompareConf *lConf = reinterpret_cast<CompareConf *>(pCfg);
    std::string lListType(pListType);
    std::string lValue(pValue);

    if (strcmp("STOP", pListType) == 0)
    {
        lConf->mCompBody.addStopRegex(lValue);
    }
    else if(strcmp("IGNORE", pListType) == 0)
    {
        lConf->mCompBody.addIgnoreRegex(lValue);
    }
    else
    {
        return "Invalid value for the list type";
    }

    return NULL;
}

/**
 * @brief Set the list of errors to ignore in the comparison
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pListType the type of list (STOP or IGNORE)
 * @param pHeader the header for which to apply the regex
 * @param pValue the reg_ex to insert in the list
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char* setHeaderList(cmd_parms* pParams, void* pCfg, const char* pListType, const char* pAffectedKey,const char* pValue) {
    if (!pValue || strlen(pValue) == 0) {
        return "Missing reg_ex value for the header";
    }

    if (!pAffectedKey || strlen(pAffectedKey) == 0) {
            return "Missing header value";
        }

    if (!pListType || strlen(pListType) == 0) {
        return "Missing the type list";
    }

    CompareConf *lConf = reinterpret_cast<CompareConf *>(pCfg);
    std::string lHeader(pAffectedKey);
    std::string lValue(pValue);

    if (strcmp("STOP", pListType) == 0)
    {
        lConf->mCompHeader.addStopRegex(lHeader, lValue);
    }
    else if(strcmp("IGNORE", pListType) == 0)
    {
        lConf->mCompHeader.addIgnoreRegex(lHeader, lValue);
    }
    else
    {
        return "Invalid value for the list type";
    }

    return NULL;
}

/**
 * @brief Set the list of errors to ignore in the comparison
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pListType the type of list (Header or Body)
 * @param pValue the value to insert in the list
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char* setFilePath(cmd_parms* pParams, void* pCfg, const char* pPath) {
    if (!pPath || strlen(pPath) == 0) {
        return "Missing path value";
    }
    Log::init();
    gFilePath = pPath;
    std::string lPath(gFilePath);
    //Log::error(12, "File path %s", lPath.c_str());

    return NULL;
}

/**
 * @brief Enable/Disable the utilization of the libws-diff tools
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pValue the value
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setDisableLibwsdiff(cmd_parms* pParams, void* pCfg, const char* pValue) {
	CompareConf *lConf = reinterpret_cast<CompareConf *>(pCfg);
	lConf->mCompareDisabled= strcmp(pValue, "1")==0 || strcmp(pValue, "true")==0;
    if(lConf->mCompareDisabled){
    	Log::warn(42,"The use of the diffing library libws-diff has been disabled!");
    }
    return NULL;
}

/** @brief Declaration of configuration commands */
    command_rec gCmds[] = {
        // AP_INIT_(directive,
        //          function,
        //          void * extra data,
        //          overrides to allow in order to enable,
        //          help message),
        AP_INIT_TAKE2("BodyList",
                      reinterpret_cast<const char *(*)()>(&setBodyList),
                      0,
                      ACCESS_CONF,
                      "List of reg_ex to apply to the body for the comparison."),
        AP_INIT_TAKE3("HeaderList",
                      reinterpret_cast<const char *(*)()>(&setHeaderList),
                      0,
                      ACCESS_CONF,
                      "List of reg_ex to apply to the Header for the comparison."),
        AP_INIT_TAKE1("FilePath",
                      reinterpret_cast<const char *(*)()>(&setFilePath),
                      0,
                      OR_ALL,
                      "Path of file where the differences will be logged."),
        AP_INIT_TAKE1("DisableLibwsdiff",
                      reinterpret_cast<const char *(*)()>(&setDisableLibwsdiff),
                      0,
                      OR_ALL,
                      "Disable the use of libws-diff tools. Print raw serialization of the data in the log file."),
        {0}
    };

/**
 * @brief register hooks in apache
 * @param pPool the apache pool
 */
void
registerHooks(apr_pool_t *pPool) {
#ifndef UNIT_TESTING
    ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_child_init(&childInit, NULL, NULL, APR_HOOK_MIDDLE);
    ap_register_input_filter(gName, inputFilterHandler, NULL, AP_FTYPE_RESOURCE);
    ap_register_output_filter(gName, outputFilterHandler, NULL, AP_FTYPE_RESOURCE);
#endif
}

} // End namespace

/// Apache module declaration
module AP_MODULE_DECLARE_DATA compare_module = {
    STANDARD20_MODULE_STUFF,
    CompareModule::createDirConfig,
    0, // merge_dir_config
    0, // create_server_config
    0, // merge_server_config
    CompareModule::gCmds,
    CompareModule::registerHooks
};
<|endoftext|>


<commit_before>/*
 * Source MUD
 * Copyright (C) 2000-2005  Sean Middleditch
 * See the file COPYING for license details
 * http://www.sourcemud.org
 */

#include "common.h"
#include "common/string.h"
#include "common/strbuf.h"
#include "common/log.h"
#include "mud/filetab.h"

int File::TabReader::open(const std::string& filename)
{
	// open
	in.open(filename.c_str());
	if (!in) {
		Log::Error << "Failed to open " << filename;
		return -1;
	}
	// finish
	TabReader::filename = filename;
	line = 1;
	return 0;
}

int File::TabReader::load()
{
	std::vector<std::string> cent;
	std::ostringstream cword;
	enum {
		WS,
		WORD,
		QUOTE,
		COMMENT
	} state = WS;
	int c;

	while (!in.eof()) {
		c = in.get();
		if (!isprint(c) && c != '\n')
			continue;

		switch (state) {
		case WS:
			if (c == '\n') {
				if (!cent.empty()) {
					entries.push_back(Entry(line, cent));
					cent.clear();
				}
				++line;
			} else if (c == '"')
				state = QUOTE;
			else if (c == '#')
				state = COMMENT;
			else if (!isspace(c)) {
				cword << (char)c;
				state = WORD;
			}
			break;
		case WORD:
			if (isspace(c) || c == '#') {
				cent.push_back(cword.str());
				cword.clear();
			}
			if (c == '\n') {
				entries.push_back(Entry(line, cent));
				cent.clear();
				++line;
				state = WS;
			} else if (c == '#') {
				state = COMMENT;
			} else if (c == '"') {
				state = QUOTE;
			} else if (isspace(c)) {
				state = WS;
			} else {
				cword << (char)c;
			}
			break;
		case QUOTE:
			if (c == '\n') {
				cent.push_back(cword.str());
				cword.clear();
				entries.push_back(Entry(line, cent));
				cent.clear();
				Log::Warning << "Unterminated quoted string at " << filename << ":" << line;
				++line;
				state = WS;
			} else if (c == '"') {
				state = WORD;
			} else {
				cword << (char)c;
			}
			break;
		case COMMENT:
			if (c == '\n') {
				if (!cent.empty()) {
					entries.push_back(Entry(line, cent));
					cent.clear();
				}
				state = WS;
				++line;
			}
			break;
		}
	}

	if (state != WS) {
		Log::Warning << "Unterminated line at " << filename << ":" << line;
		if (state == WORD || state == QUOTE)
			cent.push_back(cword.str());
		if (!cent.empty())
			entries.push_back(Entry(line, cent));
	}

	return 0;
}

std::string File::TabReader::get(size_t line, size_t col) const
{
	if (entries[line].second.size() <= col)
		return std::string();
	return entries[line].second[col];
}
<commit_msg>fix filetab reader<commit_after>/*
 * Source MUD
 * Copyright (C) 2000-2005  Sean Middleditch
 * See the file COPYING for license details
 * http://www.sourcemud.org
 */

#include "common.h"
#include "common/string.h"
#include "common/strbuf.h"
#include "common/log.h"
#include "mud/filetab.h"

int File::TabReader::open(const std::string& filename)
{
	// open
	in.open(filename.c_str());
	if (!in) {
		Log::Error << "Failed to open " << filename;
		return -1;
	}
	// finish
	TabReader::filename = filename;
	line = 1;
	return 0;
}

int File::TabReader::load()
{
	std::vector<std::string> cent;
	std::ostringstream cword;
	enum {
		WS,
		WORD,
		QUOTE,
		COMMENT
	} state = WS;
	int c;

	while (!in.eof()) {
		c = in.get();
		if (!isprint(c) && c != '\n')
			continue;

		switch (state) {
		case WS:
			if (c == '\n') {
				if (!cent.empty()) {
					entries.push_back(Entry(line, cent));
					cent.clear();
				}
				++line;
			} else if (c == '"')
				state = QUOTE;
			else if (c == '#')
				state = COMMENT;
			else if (!isspace(c)) {
				cword << (char)c;
				state = WORD;
			}
			break;
		case WORD:
			if (isspace(c) || c == '#') {
				cent.push_back(cword.str());
				cword.str("");
			}
			if (c == '\n') {
				entries.push_back(Entry(line, cent));
				cent.clear();
				++line;
				state = WS;
			} else if (c == '#') {
				state = COMMENT;
			} else if (c == '"') {
				state = QUOTE;
			} else if (isspace(c)) {
				state = WS;
			} else {
				cword << (char)c;
			}
			break;
		case QUOTE:
			if (c == '\n') {
				cent.push_back(cword.str());
				cword.str("");
				entries.push_back(Entry(line, cent));
				cent.clear();
				Log::Warning << "Unterminated quoted string at " << filename << ":" << line;
				++line;
				state = WS;
			} else if (c == '"') {
				state = WORD;
			} else {
				cword << (char)c;
			}
			break;
		case COMMENT:
			if (c == '\n') {
				if (!cent.empty()) {
					entries.push_back(Entry(line, cent));
					cent.clear();
				}
				state = WS;
				++line;
			}
			break;
		}
	}

	if (state != WS) {
		Log::Warning << "Unterminated line at " << filename << ":" << line;
		if (state == WORD || state == QUOTE)
			cent.push_back(cword.str());
		if (!cent.empty())
			entries.push_back(Entry(line, cent));
	}

	return 0;
}

std::string File::TabReader::get(size_t line, size_t col) const
{
	if (entries[line].second.size() <= col)
		return std::string();
	return entries[line].second[col];
}
<|endoftext|>


<commit_before>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#include "objecthost.hpp"

#include "boundobject.hpp"

qiLogCategory("qimessaging.objecthost");

namespace qi
{

ObjectHost::ObjectHost(unsigned int service)
 : _service(service)
 {}

 ObjectHost::~ObjectHost()
 {
   onDestroy();
 }

void ObjectHost::onMessage(const qi::Message &msg, TransportSocketPtr socket)
{
  BoundAnyObject obj;
  {
    boost::recursive_mutex::scoped_lock lock(_mutex);
    ObjectMap::iterator it = _objectMap.find(msg.object());
    if (it == _objectMap.end())
    {
      qiLogDebug() << "Object id not found " << msg.object();
      return;
    }
    qiLogDebug() << "ObjectHost forwarding " << msg.address();
    // Keep ptr alive while message is being processed, even if removeObject is called
    obj = it->second;
  }
  obj->onMessage(msg, socket);
}

unsigned int ObjectHost::addObject(BoundAnyObject obj, unsigned int id)
{
  boost::recursive_mutex::scoped_lock lock(_mutex);
  if (!id)
    id = ++_nextId;
  _objectMap[id] = obj;
  return id;
}

void ObjectHost::removeObject(unsigned int id)
{
  boost::recursive_mutex::scoped_lock lock(_mutex);
  _objectMap.erase(id);
}

void ObjectHost::clear()
{
  boost::recursive_mutex::scoped_lock lock(_mutex);
  for (ObjectMap::iterator it = _objectMap.begin(); it != _objectMap.end(); ++it)
  {
    ServiceBoundObject* sbo = dynamic_cast<ServiceBoundObject*>(it->second.get());
    if (sbo)
      sbo->_owner = 0;
  }
  _objectMap.clear();
}

Atomic<int> ObjectHost::_nextId(2);
}
<commit_msg>ObjectHost: Fix a nasty double-delete.<commit_after>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#include "objecthost.hpp"

#include "boundobject.hpp"

qiLogCategory("qimessaging.objecthost");

namespace qi
{

ObjectHost::ObjectHost(unsigned int service)
 : _service(service)
 {}

 ObjectHost::~ObjectHost()
 {
   onDestroy();
 }

void ObjectHost::onMessage(const qi::Message &msg, TransportSocketPtr socket)
{
  BoundAnyObject obj;
  {
    boost::recursive_mutex::scoped_lock lock(_mutex);
    ObjectMap::iterator it = _objectMap.find(msg.object());
    if (it == _objectMap.end())
    {
      qiLogDebug() << "Object id not found " << msg.object();
      return;
    }
    qiLogDebug() << "ObjectHost forwarding " << msg.address();
    // Keep ptr alive while message is being processed, even if removeObject is called
    obj = it->second;
  }
  obj->onMessage(msg, socket);
}

unsigned int ObjectHost::addObject(BoundAnyObject obj, unsigned int id)
{
  boost::recursive_mutex::scoped_lock lock(_mutex);
  if (!id)
    id = ++_nextId;
  _objectMap[id] = obj;
  return id;
}

void ObjectHost::removeObject(unsigned int id)
{
  /* Ensure we are not in the middle of iteration when
  *  removing our ref on BoundAnyObject.
  */
  boost::recursive_mutex::scoped_lock lock(_mutex);
  ObjectMap::iterator it = _objectMap.find(id);
  if (it == _objectMap.end())
    return;
  BoundAnyObject obj = it->second;
  _objectMap.erase(it);
}

void ObjectHost::clear()
{
  boost::recursive_mutex::scoped_lock lock(_mutex);
  for (ObjectMap::iterator it = _objectMap.begin(); it != _objectMap.end(); ++it)
  {
    ServiceBoundObject* sbo = dynamic_cast<ServiceBoundObject*>(it->second.get());
    if (sbo)
      sbo->_owner = 0;
  }
  _objectMap.clear();
}

Atomic<int> ObjectHost::_nextId(2);
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <mapnik/debug.hpp>
#include <mapnik/image_reader.hpp>
#include <mapnik/noncopyable.hpp>

extern "C"
{
#include <png.h>
}

#include <boost/scoped_array.hpp>

namespace mapnik
{
class png_reader : public image_reader
{
    struct png_file_guard
    {
        png_file_guard(FILE * fd)
            : fd_(fd) {}

        ~png_file_guard()
        {
            if (fd_) fclose(fd_);
        }
        FILE * fd_;
    };

    struct png_struct_guard
    {
        png_struct_guard(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
            : p_(png_ptr_ptr),
              i_(info_ptr_ptr) {}

        ~png_struct_guard()
        {
            png_destroy_read_struct(p_,i_,0);
        }
        png_structpp p_;
        png_infopp i_;
    };

private:
    std::string fileName_;
    unsigned width_;
    unsigned height_;
    int bit_depth_;
    int color_type_;
public:
    explicit png_reader(std::string const& fileName);
    ~png_reader();
    unsigned width() const;
    unsigned height() const;
    bool premultiplied_alpha() const { return false; } //http://www.libpng.org/pub/png/spec/1.1/PNG-Rationale.html
    void read(unsigned x,unsigned y,image_data_32& image);
private:
    void init();
};

namespace
{
image_reader* create_png_reader(std::string const& file)
{
    return new png_reader(file);
}
const bool registered = register_image_reader("png",create_png_reader);
}

png_reader::png_reader(std::string const& fileName)
    : fileName_(fileName),
      width_(0),
      height_(0),
      bit_depth_(0),
      color_type_(0)
{
    init();
}

png_reader::~png_reader() {}

void user_error_fn(png_structp png_ptr, png_const_charp error_msg)
{
    throw image_reader_exception("failed to read invalid png");
}

void user_warning_fn(png_structp png_ptr, png_const_charp warning_msg)
{
    MAPNIK_LOG_DEBUG(png_reader) << "libpng warning: '" << warning_msg << "'";
}

static void
png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
    png_size_t check;
    check = (png_size_t)fread(data, (png_size_t)1, length,
                              (FILE *)png_get_io_ptr(png_ptr));

    if (check != length)
    {
        png_error(png_ptr, "Read Error");
    }
}

void png_reader::init()
{
    FILE *fp=fopen(fileName_.c_str(),"rb");
    if (!fp) throw image_reader_exception("cannot open image file "+fileName_);
    png_file_guard guard(fp);

    png_byte header[8];
    memset(header,0,8);
    if ( fread(header,1,8,fp) != 8)
    {
        throw image_reader_exception("Could not read " + fileName_);
    }
    int is_png=!png_sig_cmp(header,0,8);
    if (!is_png)
    {
        throw image_reader_exception(fileName_ + " is not a png file");
    }
    png_structp png_ptr = png_create_read_struct
        (PNG_LIBPNG_VER_STRING,0,0,0);

    if (!png_ptr)
    {
        throw image_reader_exception("failed to allocate png_ptr");
    }

    // catch errors in a custom way to avoid the need for setjmp
    png_set_error_fn(png_ptr, png_get_error_ptr(png_ptr), user_error_fn, user_warning_fn);

    png_infop info_ptr;
    png_struct_guard sguard(&png_ptr,&info_ptr);
    info_ptr = png_create_info_struct(png_ptr);

    png_set_read_fn(png_ptr, (png_voidp)fp, png_read_data);

    png_set_sig_bytes(png_ptr,8);
    png_read_info(png_ptr, info_ptr);

    png_uint_32  width, height;
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth_, &color_type_,0,0,0);

    width_=width;
    height_=height;

    MAPNIK_LOG_DEBUG(png_reader) << "png_reader: bit_depth=" << bit_depth_ << ",color_type=" << color_type_;
}

unsigned png_reader::width() const
{
    return width_;
}

unsigned png_reader::height() const
{
    return height_;
}

void png_reader::read(unsigned x0, unsigned y0,image_data_32& image)
{
    FILE *fp=fopen(fileName_.c_str(),"rb");
    if (!fp) throw image_reader_exception("cannot open image file "+fileName_);
    png_file_guard guard(fp);

    png_structp png_ptr = png_create_read_struct
        (PNG_LIBPNG_VER_STRING,0,0,0);

    if (!png_ptr)
    {
        throw image_reader_exception("failed to allocate png_ptr");
    }

    // catch errors in a custom way to avoid the need for setjmp
    png_set_error_fn(png_ptr, png_get_error_ptr(png_ptr), user_error_fn, user_warning_fn);

    png_infop info_ptr;
    png_struct_guard sguard(&png_ptr,&info_ptr);
    info_ptr = png_create_info_struct(png_ptr);

    png_set_read_fn(png_ptr, (png_voidp)fp, png_read_data);
    png_read_info(png_ptr, info_ptr);

    if (color_type_ == PNG_COLOR_TYPE_PALETTE)
        png_set_expand(png_ptr);
    if (color_type_ == PNG_COLOR_TYPE_GRAY && bit_depth_ < 8)
        png_set_expand(png_ptr);
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
        png_set_expand(png_ptr);
    if (bit_depth_ == 16)
        png_set_strip_16(png_ptr);
    if (color_type_ == PNG_COLOR_TYPE_GRAY ||
        color_type_ == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png_ptr);

    // quick hack -- only work in >=libpng 1.2.7
    png_set_add_alpha(png_ptr,0xff,PNG_FILLER_AFTER); //rgba

    double gamma;
    if (png_get_gAMA(png_ptr, info_ptr, &gamma))
        png_set_gamma(png_ptr, 2.2, gamma);

    if (x0 == 0 && y0 == 0 && image.width() >= width_ && image.height() >= height_)
    {

        if (png_get_interlace_type(png_ptr,info_ptr) == PNG_INTERLACE_ADAM7)
        {
            png_set_interlace_handling(png_ptr); // FIXME: libpng bug?
            // according to docs png_read_image
            // "..automatically handles interlacing,
            // so you don't need to call png_set_interlace_handling()"
        }
        png_read_update_info(png_ptr, info_ptr);
        // we can read whole image at once
        // alloc row pointers
        boost::scoped_array<png_byte*> rows(new png_bytep[height_]);
        for (unsigned i=0; i<height_; ++i)
            rows[i] = (png_bytep)image.getRow(i);
        png_read_image(png_ptr, rows.get());
    }
    else
    {
        png_read_update_info(png_ptr, info_ptr);
        unsigned w=std::min(unsigned(image.width()),width_ - x0);
        unsigned h=std::min(unsigned(image.height()),height_ - y0);
        unsigned rowbytes=png_get_rowbytes(png_ptr, info_ptr);
        boost::scoped_array<png_byte> row(new png_byte[rowbytes]);
        //START read image rows
        for (unsigned i = 0;i < height_; ++i)
        {
            png_read_row(png_ptr,row.get(),0);
            if (i >= y0 && i < (y0 + h))
            {
                image.setRow(i-y0,reinterpret_cast<unsigned*>(&row[x0 * 4]),w);
            }
        }
        //END
    }
    png_read_end(png_ptr,0);
    png_destroy_read_struct(&png_ptr, &info_ptr,0);
}
}
<commit_msg>further cleanup png struct handling - refs #1783<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <mapnik/debug.hpp>
#include <mapnik/image_reader.hpp>
#include <mapnik/noncopyable.hpp>

extern "C"
{
#include <png.h>
}

#include <boost/scoped_array.hpp>

namespace mapnik
{
class png_reader : public image_reader
{
    struct png_file_guard
    {
        png_file_guard(FILE * fd)
            : fd_(fd) {}

        ~png_file_guard()
        {
            if (fd_) fclose(fd_);
        }
        FILE * fd_;
    };

    struct png_struct_guard
    {
        png_struct_guard(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
            : p_(png_ptr_ptr),
              i_(info_ptr_ptr) {}

        ~png_struct_guard()
        {
            png_destroy_read_struct(p_,i_,0);
        }
        png_structpp p_;
        png_infopp i_;
    };

private:
    std::string fileName_;
    unsigned width_;
    unsigned height_;
    int bit_depth_;
    int color_type_;
public:
    explicit png_reader(std::string const& fileName);
    ~png_reader();
    unsigned width() const;
    unsigned height() const;
    bool premultiplied_alpha() const { return false; } //http://www.libpng.org/pub/png/spec/1.1/PNG-Rationale.html
    void read(unsigned x,unsigned y,image_data_32& image);
private:
    void init();
};

namespace
{
image_reader* create_png_reader(std::string const& file)
{
    return new png_reader(file);
}
const bool registered = register_image_reader("png",create_png_reader);
}

png_reader::png_reader(std::string const& fileName)
    : fileName_(fileName),
      width_(0),
      height_(0),
      bit_depth_(0),
      color_type_(0)
{
    init();
}

png_reader::~png_reader() {}

void user_error_fn(png_structp png_ptr, png_const_charp error_msg)
{
    throw image_reader_exception("failed to read invalid png");
}

void user_warning_fn(png_structp png_ptr, png_const_charp warning_msg)
{
    MAPNIK_LOG_DEBUG(png_reader) << "libpng warning: '" << warning_msg << "'";
}

static void
png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
    png_size_t check;
    check = (png_size_t)fread(data, (png_size_t)1, length,
                              (FILE *)png_get_io_ptr(png_ptr));

    if (check != length)
    {
        png_error(png_ptr, "Read Error");
    }
}

void png_reader::init()
{
    FILE *fp=fopen(fileName_.c_str(),"rb");
    if (!fp) throw image_reader_exception("cannot open image file "+fileName_);
    png_file_guard guard(fp);

    png_byte header[8];
    memset(header,0,8);
    if ( fread(header,1,8,fp) != 8)
    {
        throw image_reader_exception("Could not read " + fileName_);
    }
    int is_png=!png_sig_cmp(header,0,8);
    if (!is_png)
    {
        throw image_reader_exception(fileName_ + " is not a png file");
    }
    png_structp png_ptr = png_create_read_struct
        (PNG_LIBPNG_VER_STRING,0,0,0);

    if (!png_ptr)
    {
        throw image_reader_exception("failed to allocate png_ptr");
    }

    // catch errors in a custom way to avoid the need for setjmp
    png_set_error_fn(png_ptr, png_get_error_ptr(png_ptr), user_error_fn, user_warning_fn);

    png_infop info_ptr;
    png_struct_guard sguard(&png_ptr,&info_ptr);
    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) throw image_reader_exception("failed to create info_ptr");

    png_set_read_fn(png_ptr, (png_voidp)fp, png_read_data);

    png_set_sig_bytes(png_ptr,8);
    png_read_info(png_ptr, info_ptr);

    png_uint_32  width, height;
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth_, &color_type_,0,0,0);

    width_=width;
    height_=height;

    MAPNIK_LOG_DEBUG(png_reader) << "png_reader: bit_depth=" << bit_depth_ << ",color_type=" << color_type_;
}

unsigned png_reader::width() const
{
    return width_;
}

unsigned png_reader::height() const
{
    return height_;
}

void png_reader::read(unsigned x0, unsigned y0,image_data_32& image)
{
    FILE *fp=fopen(fileName_.c_str(),"rb");
    if (!fp) throw image_reader_exception("cannot open image file "+fileName_);
    png_file_guard guard(fp);

    png_structp png_ptr = png_create_read_struct
        (PNG_LIBPNG_VER_STRING,0,0,0);

    if (!png_ptr)
    {
        throw image_reader_exception("failed to allocate png_ptr");
    }

    // catch errors in a custom way to avoid the need for setjmp
    png_set_error_fn(png_ptr, png_get_error_ptr(png_ptr), user_error_fn, user_warning_fn);

    png_infop info_ptr;
    png_struct_guard sguard(&png_ptr,&info_ptr);
    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) throw image_reader_exception("failed to create info_ptr");

    png_set_read_fn(png_ptr, (png_voidp)fp, png_read_data);
    png_read_info(png_ptr, info_ptr);

    if (color_type_ == PNG_COLOR_TYPE_PALETTE)
        png_set_expand(png_ptr);
    if (color_type_ == PNG_COLOR_TYPE_GRAY && bit_depth_ < 8)
        png_set_expand(png_ptr);
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
        png_set_expand(png_ptr);
    if (bit_depth_ == 16)
        png_set_strip_16(png_ptr);
    if (color_type_ == PNG_COLOR_TYPE_GRAY ||
        color_type_ == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png_ptr);

    // quick hack -- only work in >=libpng 1.2.7
    png_set_add_alpha(png_ptr,0xff,PNG_FILLER_AFTER); //rgba

    double gamma;
    if (png_get_gAMA(png_ptr, info_ptr, &gamma))
        png_set_gamma(png_ptr, 2.2, gamma);

    if (x0 == 0 && y0 == 0 && image.width() >= width_ && image.height() >= height_)
    {

        if (png_get_interlace_type(png_ptr,info_ptr) == PNG_INTERLACE_ADAM7)
        {
            png_set_interlace_handling(png_ptr); // FIXME: libpng bug?
            // according to docs png_read_image
            // "..automatically handles interlacing,
            // so you don't need to call png_set_interlace_handling()"
        }
        png_read_update_info(png_ptr, info_ptr);
        // we can read whole image at once
        // alloc row pointers
        boost::scoped_array<png_byte*> rows(new png_bytep[height_]);
        for (unsigned i=0; i<height_; ++i)
            rows[i] = (png_bytep)image.getRow(i);
        png_read_image(png_ptr, rows.get());
    }
    else
    {
        png_read_update_info(png_ptr, info_ptr);
        unsigned w=std::min(unsigned(image.width()),width_ - x0);
        unsigned h=std::min(unsigned(image.height()),height_ - y0);
        unsigned rowbytes=png_get_rowbytes(png_ptr, info_ptr);
        boost::scoped_array<png_byte> row(new png_byte[rowbytes]);
        //START read image rows
        for (unsigned i = 0;i < height_; ++i)
        {
            png_read_row(png_ptr,row.get(),0);
            if (i >= y0 && i < (y0 + h))
            {
                image.setRow(i-y0,reinterpret_cast<unsigned*>(&row[x0 * 4]),w);
            }
        }
        //END
    }
    png_read_end(png_ptr,0);
}
}
<|endoftext|>