<commit_before>#include "Http.hpp"
#include "Logger.hpp"
#include "misc.hpp"
#include "version.hpp"

#include <boost/asio/system_timer.hpp>
#include <boost/beast/version.hpp>
#include <date/date.h>

Http::Http(std::string token) :
	m_SslContext(asio::ssl::context::tlsv12_client),
	m_Token(token),
	m_NetworkThreadRunning(true),
	m_NetworkThread(std::bind(&Http::NetworkThreadFunc, this))
{

}

Http::~Http()
{
	m_NetworkThreadRunning = false;
	m_NetworkThread.join();

	// drain requests queue
	QueueEntry *entry;
	while (m_Queue.pop(entry))
		delete entry;
}

void Http::NetworkThreadFunc()
{
	std::unordered_map<std::string, TimePoint_t> path_ratelimit;
	unsigned int retry_counter = 0;
	unsigned int const MaxRetries = 3;
	bool skip_entry = false;

	if (!Connect())
		return;

	while (m_NetworkThreadRunning)
	{
		TimePoint_t current_time = std::chrono::steady_clock::now();
		std::list<QueueEntry*> skipped_entries;

		QueueEntry *entry;
		while (m_Queue.pop(entry))
		{
			// check if we're rate-limited
			auto pr_it = path_ratelimit.find(entry->Request->target().to_string());
			if (pr_it != path_ratelimit.end())
			{
				// rate-limit for this path exists
				// are we still within the rate-limit timepoint?
				if (current_time < pr_it->second)
				{
					// yes, ignore this request for now
					skipped_entries.push_back(entry);
					continue;
				}

				// no, delete rate-limit and go on
				path_ratelimit.erase(pr_it);
				Logger::Get()->Log(LogLevel::DEBUG, "rate-limit on path '{}' lifted",
					entry->Request->target().to_string());
			}

			boost::system::error_code error_code;
			Response_t response;
			Streambuf_t sb;
			retry_counter = 0;
			skip_entry = false;
			do
			{
				bool do_reconnect = false;
				beast::http::write(*m_SslStream, *entry->Request, error_code);
				if (error_code)
				{
					Logger::Get()->Log(LogLevel::ERROR, "Error while sending HTTP {} request to '{}': {}",
						entry->Request->method_string().to_string(),
						entry->Request->target().to_string(),
						error_code.message());

					do_reconnect = true;
				}
				else
				{
					beast::http::read(*m_SslStream, sb, response, error_code);
					if (error_code)
					{
						Logger::Get()->Log(LogLevel::ERROR, "Error while retrieving HTTP {} response from '{}': {}",
							entry->Request->method_string().to_string(),
							entry->Request->target().to_string(),
							error_code.message());

						do_reconnect = true;
					}
				}

				if (do_reconnect)
				{
					if (retry_counter++ >= MaxRetries || !ReconnectRetry())
					{
						// we failed to reconnect, discard this request
						Logger::Get()->Log(LogLevel::WARNING, "Failed to send request, discarding");
						skip_entry = true;
						break; // break out of do-while loop
					}
				}
			} while (error_code);
			if (skip_entry)
				continue; // continue queue loop

			auto it_r = response.find("X-RateLimit-Remaining");
			if (it_r != response.end())
			{
				if (it_r->value().compare("0") == 0)
				{
					// we're now officially rate-limited
					// the next call to this path will fail
					std::string limited_url = entry->Request->target().to_string();
					auto lit = path_ratelimit.find(limited_url);
					if (lit != path_ratelimit.end())
					{
						Logger::Get()->Log(LogLevel::ERROR,
							"Error while processing rate-limit: already rate-limited path '{}'",
							limited_url);

						// skip this request, we'll re-add it to the queue to retry later
						skipped_entries.push_back(entry);
						continue;
					}

					it_r = response.find("X-RateLimit-Reset");
					if (it_r != response.end())
					{
						auto date_str = response.find(boost::beast::http::field::date)->value().to_string();
						std::istringstream date_ss{ date_str };
						date::sys_seconds date_utc;
						date_ss >> date::parse("%a, %d %b %Y %T %Z", date_utc); // RFC2616 HTTP header date format

						std::chrono::seconds timepoint_now = date_utc.time_since_epoch();
						Logger::Get()->Log(LogLevel::DEBUG, "rate-limiting path {} until {} (current time: {})",
							limited_url,
							it_r->value().to_string(),
							timepoint_now.count());

						string const &reset_time_str = it_r->value().to_string();
						long long reset_time_secs = 0;
						ConvertStrToData(reset_time_str, reset_time_secs);
						TimePoint_t reset_time = std::chrono::steady_clock::now()
							+ std::chrono::seconds(reset_time_secs - timepoint_now.count() + 1); // add a buffer of 1 second

						path_ratelimit.insert({ limited_url, reset_time });
					}
				}
			}

			if (entry->Callback)
				entry->Callback(sb, response);

			delete entry;
			entry = nullptr;
		}

		// add skipped entries back to queue
		for (auto e : skipped_entries)
			m_Queue.push(e);

		std::this_thread::sleep_for(std::chrono::milliseconds(50));
	}

	Disconnect();
}

bool Http::Connect()
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::Connect");

	m_SslStream.reset(new SslStream_t(m_IoService, m_SslContext));

	const char *API_HOST = "discord.com";

	// Set SNI Hostname (many hosts need this to handshake successfully)
	if (!SSL_set_tlsext_host_name(m_SslStream->native_handle(), API_HOST))
	{
		beast::error_code ec{
			static_cast<int>(::ERR_get_error()),
			asio::error::get_ssl_category() };
		Logger::Get()->Log(LogLevel::ERROR,
			"Can't set SNI hostname for Discord API URL: {} ({})",
			ec.message(), ec.value());
		return false;
	}

	// connect to REST API
	asio::ip::tcp::resolver r{ m_IoService };
	boost::system::error_code error;
	auto target = r.resolve(API_HOST, "443", error);
	if (error)
	{
		Logger::Get()->Log(LogLevel::ERROR, "Can't resolve Discord API URL: {} ({})",
			error.message(), error.value());
		return false;
	}

	beast::get_lowest_layer(*m_SslStream).expires_after(std::chrono::seconds(30));
	beast::get_lowest_layer(*m_SslStream).connect(target, error);
	if (error)
	{
		Logger::Get()->Log(LogLevel::ERROR, "Can't connect to Discord API: {} ({})",
			error.message(), error.value());
		return false;
	}

	// SSL handshake
	m_SslStream->set_verify_mode(asio::ssl::verify_peer, error);
	if (error)
	{
		Logger::Get()->Log(LogLevel::ERROR,
			"Can't configure SSL stream peer verification mode for Discord API: {} ({})",
			error.message(), error.value());
		return false;
	}

	m_SslStream->handshake(asio::ssl::stream_base::client, error);
	if (error)
	{
		Logger::Get()->Log(LogLevel::ERROR, "Can't establish secured connection to Discord API: {} ({})",
			error.message(), error.value());
		return false;
	}

	return true;
}

void Http::Disconnect()
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::Disconnect");

	boost::system::error_code error;
	m_SslStream->shutdown(error);
	if (error && error != boost::asio::error::eof && error != boost::asio::ssl::error::stream_truncated)
	{
		Logger::Get()->Log(LogLevel::WARNING, "Error while shutting down SSL on HTTP connection: {} ({})",
			error.message(), error.value());
	}
}

bool Http::ReconnectRetry()
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::ReconnectRetry");

	unsigned int reconnect_counter = 0;
	do
	{
		Logger::Get()->Log(LogLevel::INFO, "trying reconnect #{}...", reconnect_counter + 1);

		Disconnect();
		if (Connect())
		{
			Logger::Get()->Log(LogLevel::INFO, "reconnect succeeded, resending request");
			return true;
		}
		else
		{
			unsigned int seconds_to_wait = static_cast<unsigned int>(std::pow(2U, reconnect_counter));
			Logger::Get()->Log(LogLevel::WARNING, "reconnect failed, waiting {} seconds...", seconds_to_wait);
			std::this_thread::sleep_for(std::chrono::seconds(seconds_to_wait));
		}
	} while (++reconnect_counter < 3);

	Logger::Get()->Log(LogLevel::ERROR, "Could not reconnect to Discord");
	return false;
}

Http::SharedRequest_t Http::PrepareRequest(beast::http::verb const method,
	std::string const &url, std::string const &content)
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::PrepareRequest");

	auto req = std::make_shared<Request_t>();
	req->method(method);
	req->target("/api/v6" + url);
	req->version(11);
	req->insert(beast::http::field::connection, "keep-alive");
	req->insert(beast::http::field::host, "discord.com");
	req->insert(beast::http::field::user_agent,
		"samp-discord-connector (" BOOST_BEAST_VERSION_STRING ")");
	if (!content.empty())
		req->insert(beast::http::field::content_type, "application/json");
	req->insert(beast::http::field::authorization, "Bot " + m_Token);
	req->body() = content;

	req->prepare_payload();

	return req;
}

void Http::SendRequest(beast::http::verb const method, std::string const &url,
	std::string const &content, ResponseCallback_t &&callback)
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::SendRequest");

	SharedRequest_t req = PrepareRequest(method, url, content);

	if (callback == nullptr && Logger::Get()->IsLogLevel(LogLevel::DEBUG))
	{
		callback = CreateResponseCallback([=](Response r)
		{
			Logger::Get()->Log(LogLevel::DEBUG, "{:s} {:s} [{:s}] --> {:d} {:s}: {:s}",
				beast::http::to_string(method).to_string(), url, content, r.status, r.reason, r.body);
		});
	}

	m_Queue.push(new QueueEntry(req, std::move(callback)));
}

Http::ResponseCallback_t Http::CreateResponseCallback(ResponseCb_t &&callback)
{
	if (callback == nullptr)
		return nullptr;

	return [callback](Streambuf_t &sb, Response_t &resp)
	{
		callback({ resp.result_int(), resp.reason().to_string(),
			beast::buffers_to_string(resp.body().data()), beast::buffers_to_string(sb.data()) });
	};
}

void Http::Get(std::string const &url, ResponseCb_t &&callback)
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::Get");

	SendRequest(beast::http::verb::get, url, "",
		CreateResponseCallback(std::move(callback)));
}

void Http::Post(std::string const &url, std::string const &content,
	ResponseCb_t &&callback /*= nullptr*/)
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::Post");

	SendRequest(beast::http::verb::post, url, content,
		CreateResponseCallback(std::move(callback)));
}

void Http::Delete(std::string const &url)
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::Delete");

	SendRequest(beast::http::verb::delete_, url, "", nullptr);
}

void Http::Put(std::string const &url)
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::Put");

	SendRequest(beast::http::verb::put, url, "", nullptr);
}

void Http::Patch(std::string const &url, std::string const &content)
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::Patch");

	SendRequest(beast::http::verb::patch, url, content, nullptr);
}
<commit_msg>remove certificate validation<commit_after>#include "Http.hpp"
#include "Logger.hpp"
#include "misc.hpp"
#include "version.hpp"

#include <boost/asio/system_timer.hpp>
#include <boost/beast/version.hpp>
#include <date/date.h>

Http::Http(std::string token) :
	m_SslContext(asio::ssl::context::tlsv12_client),
	m_Token(token),
	m_NetworkThreadRunning(true),
	m_NetworkThread(std::bind(&Http::NetworkThreadFunc, this))
{

}

Http::~Http()
{
	m_NetworkThreadRunning = false;
	m_NetworkThread.join();

	// drain requests queue
	QueueEntry *entry;
	while (m_Queue.pop(entry))
		delete entry;
}

void Http::NetworkThreadFunc()
{
	std::unordered_map<std::string, TimePoint_t> path_ratelimit;
	unsigned int retry_counter = 0;
	unsigned int const MaxRetries = 3;
	bool skip_entry = false;

	if (!Connect())
		return;

	while (m_NetworkThreadRunning)
	{
		TimePoint_t current_time = std::chrono::steady_clock::now();
		std::list<QueueEntry*> skipped_entries;

		QueueEntry *entry;
		while (m_Queue.pop(entry))
		{
			// check if we're rate-limited
			auto pr_it = path_ratelimit.find(entry->Request->target().to_string());
			if (pr_it != path_ratelimit.end())
			{
				// rate-limit for this path exists
				// are we still within the rate-limit timepoint?
				if (current_time < pr_it->second)
				{
					// yes, ignore this request for now
					skipped_entries.push_back(entry);
					continue;
				}

				// no, delete rate-limit and go on
				path_ratelimit.erase(pr_it);
				Logger::Get()->Log(LogLevel::DEBUG, "rate-limit on path '{}' lifted",
					entry->Request->target().to_string());
			}

			boost::system::error_code error_code;
			Response_t response;
			Streambuf_t sb;
			retry_counter = 0;
			skip_entry = false;
			do
			{
				bool do_reconnect = false;
				beast::http::write(*m_SslStream, *entry->Request, error_code);
				if (error_code)
				{
					Logger::Get()->Log(LogLevel::ERROR, "Error while sending HTTP {} request to '{}': {}",
						entry->Request->method_string().to_string(),
						entry->Request->target().to_string(),
						error_code.message());

					do_reconnect = true;
				}
				else
				{
					beast::http::read(*m_SslStream, sb, response, error_code);
					if (error_code)
					{
						Logger::Get()->Log(LogLevel::ERROR, "Error while retrieving HTTP {} response from '{}': {}",
							entry->Request->method_string().to_string(),
							entry->Request->target().to_string(),
							error_code.message());

						do_reconnect = true;
					}
				}

				if (do_reconnect)
				{
					if (retry_counter++ >= MaxRetries || !ReconnectRetry())
					{
						// we failed to reconnect, discard this request
						Logger::Get()->Log(LogLevel::WARNING, "Failed to send request, discarding");
						skip_entry = true;
						break; // break out of do-while loop
					}
				}
			} while (error_code);
			if (skip_entry)
				continue; // continue queue loop

			auto it_r = response.find("X-RateLimit-Remaining");
			if (it_r != response.end())
			{
				if (it_r->value().compare("0") == 0)
				{
					// we're now officially rate-limited
					// the next call to this path will fail
					std::string limited_url = entry->Request->target().to_string();
					auto lit = path_ratelimit.find(limited_url);
					if (lit != path_ratelimit.end())
					{
						Logger::Get()->Log(LogLevel::ERROR,
							"Error while processing rate-limit: already rate-limited path '{}'",
							limited_url);

						// skip this request, we'll re-add it to the queue to retry later
						skipped_entries.push_back(entry);
						continue;
					}

					it_r = response.find("X-RateLimit-Reset");
					if (it_r != response.end())
					{
						auto date_str = response.find(boost::beast::http::field::date)->value().to_string();
						std::istringstream date_ss{ date_str };
						date::sys_seconds date_utc;
						date_ss >> date::parse("%a, %d %b %Y %T %Z", date_utc); // RFC2616 HTTP header date format

						std::chrono::seconds timepoint_now = date_utc.time_since_epoch();
						Logger::Get()->Log(LogLevel::DEBUG, "rate-limiting path {} until {} (current time: {})",
							limited_url,
							it_r->value().to_string(),
							timepoint_now.count());

						string const &reset_time_str = it_r->value().to_string();
						long long reset_time_secs = 0;
						ConvertStrToData(reset_time_str, reset_time_secs);
						TimePoint_t reset_time = std::chrono::steady_clock::now()
							+ std::chrono::seconds(reset_time_secs - timepoint_now.count() + 1); // add a buffer of 1 second

						path_ratelimit.insert({ limited_url, reset_time });
					}
				}
			}

			if (entry->Callback)
				entry->Callback(sb, response);

			delete entry;
			entry = nullptr;
		}

		// add skipped entries back to queue
		for (auto e : skipped_entries)
			m_Queue.push(e);

		std::this_thread::sleep_for(std::chrono::milliseconds(50));
	}

	Disconnect();
}

bool Http::Connect()
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::Connect");

	m_SslStream.reset(new SslStream_t(m_IoService, m_SslContext));

	const char *API_HOST = "discord.com";

	// Set SNI Hostname (many hosts need this to handshake successfully)
	if (!SSL_set_tlsext_host_name(m_SslStream->native_handle(), API_HOST))
	{
		beast::error_code ec{
			static_cast<int>(::ERR_get_error()),
			asio::error::get_ssl_category() };
		Logger::Get()->Log(LogLevel::ERROR,
			"Can't set SNI hostname for Discord API URL: {} ({})",
			ec.message(), ec.value());
		return false;
	}

	// connect to REST API
	asio::ip::tcp::resolver r{ m_IoService };
	boost::system::error_code error;
	auto target = r.resolve(API_HOST, "443", error);
	if (error)
	{
		Logger::Get()->Log(LogLevel::ERROR, "Can't resolve Discord API URL: {} ({})",
			error.message(), error.value());
		return false;
	}

	beast::get_lowest_layer(*m_SslStream).expires_after(std::chrono::seconds(30));
	beast::get_lowest_layer(*m_SslStream).connect(target, error);
	if (error)
	{
		Logger::Get()->Log(LogLevel::ERROR, "Can't connect to Discord API: {} ({})",
			error.message(), error.value());
		return false;
	}

	// SSL handshake
	m_SslStream->handshake(asio::ssl::stream_base::client, error);
	if (error)
	{
		Logger::Get()->Log(LogLevel::ERROR, "Can't establish secured connection to Discord API: {} ({})",
			error.message(), error.value());
		return false;
	}

	return true;
}

void Http::Disconnect()
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::Disconnect");

	boost::system::error_code error;
	m_SslStream->shutdown(error);
	if (error && error != boost::asio::error::eof && error != boost::asio::ssl::error::stream_truncated)
	{
		Logger::Get()->Log(LogLevel::WARNING, "Error while shutting down SSL on HTTP connection: {} ({})",
			error.message(), error.value());
	}
}

bool Http::ReconnectRetry()
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::ReconnectRetry");

	unsigned int reconnect_counter = 0;
	do
	{
		Logger::Get()->Log(LogLevel::INFO, "trying reconnect #{}...", reconnect_counter + 1);

		Disconnect();
		if (Connect())
		{
			Logger::Get()->Log(LogLevel::INFO, "reconnect succeeded, resending request");
			return true;
		}
		else
		{
			unsigned int seconds_to_wait = static_cast<unsigned int>(std::pow(2U, reconnect_counter));
			Logger::Get()->Log(LogLevel::WARNING, "reconnect failed, waiting {} seconds...", seconds_to_wait);
			std::this_thread::sleep_for(std::chrono::seconds(seconds_to_wait));
		}
	} while (++reconnect_counter < 3);

	Logger::Get()->Log(LogLevel::ERROR, "Could not reconnect to Discord");
	return false;
}

Http::SharedRequest_t Http::PrepareRequest(beast::http::verb const method,
	std::string const &url, std::string const &content)
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::PrepareRequest");

	auto req = std::make_shared<Request_t>();
	req->method(method);
	req->target("/api/v6" + url);
	req->version(11);
	req->insert(beast::http::field::connection, "keep-alive");
	req->insert(beast::http::field::host, "discord.com");
	req->insert(beast::http::field::user_agent,
		"samp-discord-connector (" BOOST_BEAST_VERSION_STRING ")");
	if (!content.empty())
		req->insert(beast::http::field::content_type, "application/json");
	req->insert(beast::http::field::authorization, "Bot " + m_Token);
	req->body() = content;

	req->prepare_payload();

	return req;
}

void Http::SendRequest(beast::http::verb const method, std::string const &url,
	std::string const &content, ResponseCallback_t &&callback)
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::SendRequest");

	SharedRequest_t req = PrepareRequest(method, url, content);

	if (callback == nullptr && Logger::Get()->IsLogLevel(LogLevel::DEBUG))
	{
		callback = CreateResponseCallback([=](Response r)
		{
			Logger::Get()->Log(LogLevel::DEBUG, "{:s} {:s} [{:s}] --> {:d} {:s}: {:s}",
				beast::http::to_string(method).to_string(), url, content, r.status, r.reason, r.body);
		});
	}

	m_Queue.push(new QueueEntry(req, std::move(callback)));
}

Http::ResponseCallback_t Http::CreateResponseCallback(ResponseCb_t &&callback)
{
	if (callback == nullptr)
		return nullptr;

	return [callback](Streambuf_t &sb, Response_t &resp)
	{
		callback({ resp.result_int(), resp.reason().to_string(),
			beast::buffers_to_string(resp.body().data()), beast::buffers_to_string(sb.data()) });
	};
}

void Http::Get(std::string const &url, ResponseCb_t &&callback)
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::Get");

	SendRequest(beast::http::verb::get, url, "",
		CreateResponseCallback(std::move(callback)));
}

void Http::Post(std::string const &url, std::string const &content,
	ResponseCb_t &&callback /*= nullptr*/)
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::Post");

	SendRequest(beast::http::verb::post, url, content,
		CreateResponseCallback(std::move(callback)));
}

void Http::Delete(std::string const &url)
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::Delete");

	SendRequest(beast::http::verb::delete_, url, "", nullptr);
}

void Http::Put(std::string const &url)
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::Put");

	SendRequest(beast::http::verb::put, url, "", nullptr);
}

void Http::Patch(std::string const &url, std::string const &content)
{
	Logger::Get()->Log(LogLevel::DEBUG, "Http::Patch");

	SendRequest(beast::http::verb::patch, url, content, nullptr);
}
<|endoftext|>


<commit_before>#include <array>
#include <boost/fusion/adapted/array.hpp>
#include <boost/fusion/adapted/std_array.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>

#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <string>

using namespace boost::spirit;
using namespace std;

using box = std::array<int, 4>;

// According to https://wandbox.org/permlink/poeusnilIOwmiEBo
namespace boost {
	namespace spirit {
		namespace x3 {
			namespace traits {
				// It can't be specialized because X3 implements is_container as a template aliases,
				// thus we need QUITE TERRIBLE DIRTY hack for fixed length container.
				//template <> struct is_container<Vertex const> : mpl::false_ { };
				//template <> struct is_container<Vertex> : mpl::false_ { };
				namespace detail {
					template <> struct has_type_value_type<box> : mpl::false_ { };
				}
			}
		}
	}
}

template<class T> auto constexpr bracketize(T what)
{
	return '[' > what > ']';
}

// Vector of four ints
auto boxrule = bracketize(x3::int_ > ',' > x3::int_ > ',' > x3::int_ > ',' > x3::int_);
// Comma-separated list of such vectors
auto innerboxlist = (boxrule % ',');
auto fullboxlist = x3::lit("array") > '(' > bracketize(innerboxlist ) > ',' > "dtype" > '=' > "int64" > ')';
// The whole first section of the data file
auto boxes = bracketize(*(fullboxlist));

// Array of lists of doubles
auto scorelist = x3::lit("array") > '(' > bracketize(x3::double_ % ',') > ')';
auto scores = bracketize(*(scorelist));

template<class RuleType, class AttrType> void parseToEndWithError(istream& file, const RuleType& rule, AttrType& target)
{
	auto parseriter = boost::spirit::istream_iterator(file);
	boost::spirit::istream_iterator end;

	bool res = phrase_parse(parseriter, end, rule, x3::space - x3::eol, target);

	if (!res)
	{
		std::string val;
		file >> val;
		throw logic_error("Parsing failed. " + (std::string) __func__ + " " + val);
	}
}

struct wordmapper
{
private:
	map<string, int> mapping;
	map<int, string> inversemapping;
public:
	int getMapping(string word)
	{
		auto i = mapping.find(word);
		if (i != mapping.end())
		{
			return i->second;
		}

		int index = mapping.size();
		mapping[word] = index;
		inversemapping[index] = word;

		return index;
	}

	string getWord(int mapping)
	{
		return inversemapping[mapping];
	}
} wordmap;

// Coming in C++ 17
template <class T>
constexpr std::add_const_t<T>& as_const(const T& t) noexcept
{
	return t;
}

auto word_ = x3::lexeme[+(x3::char_ - x3::space)];
auto linefile = *(*word_ > eol);

int main(int argc, char** argv)
{
	if (argc < 2)
	{
		return -1;
	}
	ifstream file(argv[1]);
	vector<vector<box>> ourBoxes;
	vector<vector<double>> scoreVals;
	parseToEndWithError(file, boxes > scores, as_const(std::forward_as_tuple(ourBoxes, scoreVals)));
	cout << "Read " << ourBoxes.size() << " box lists and " << scoreVals.size() << " score lists." << "\n";

	file = ifstream(argv[2]);
	parseToEndWithError(file, boxes > scores, as_const(std::forward_as_tuple(ourBoxes, scoreVals)));
	vector<vector<int> > rows;
}<commit_msg>Semantic action magic coming along<commit_after>#include <array>
#include <boost/fusion/adapted/array.hpp>
#include <boost/fusion/adapted/std_array.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>

#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <string>

using namespace boost::spirit;
using namespace std;

using box = std::array<int, 4>;

// According to https://wandbox.org/permlink/poeusnilIOwmiEBo
namespace boost {
	namespace spirit {
		namespace x3 {
			namespace traits {
				// It can't be specialized because X3 implements is_container as a template aliases,
				// thus we need QUITE TERRIBLE DIRTY hack for fixed length container.
				//template <> struct is_container<Vertex const> : mpl::false_ { };
				//template <> struct is_container<Vertex> : mpl::false_ { };
				namespace detail {
					template <> struct has_type_value_type<box> : mpl::false_ { };
				}
			}
		}
	}
}

template<class T> auto constexpr bracketize(T what)
{
	return '[' > what > ']';
}

// Vector of four ints
auto boxrule = bracketize(x3::int_ > ',' > x3::int_ > ',' > x3::int_ > ',' > x3::int_);
// Comma-separated list of such vectors
auto innerboxlist = (boxrule % ',');
auto fullboxlist = x3::lit("array") > '(' > bracketize(innerboxlist ) > ',' > "dtype" > '=' > "int64" > ')';
// The whole first section of the data file
auto boxes = bracketize(*(fullboxlist));

// Array of lists of doubles
auto scorelist = x3::lit("array") > '(' > bracketize(x3::double_ % ',') > ')';
auto scores = bracketize(*(scorelist));

template<class RuleType, class AttrType> void parseToEndWithError(istream& file, const RuleType& rule, AttrType& target)
{
	auto parseriter = boost::spirit::istream_iterator(file);
	boost::spirit::istream_iterator end;

	bool res = phrase_parse(parseriter, end, rule, x3::space - x3::eol, target);

	if (!res)
	{
		std::string val;
		file >> val;
		throw logic_error("Parsing failed. " + (std::string) __func__ + " " + val);
	}
}

struct wordmapper
{
private:
	map<string, int> mapping;
	map<int, string> inversemapping;
public:
	int getMapping(string word)
	{
		auto i = mapping.find(word);
		if (i != mapping.end())
		{
			return i->second;
		}

		int index = mapping.size();
		mapping[word] = index;
		inversemapping[index] = word;

		return index;
	}

	string getWord(int mapping)
	{
		return inversemapping[mapping];
	}
} wordmap;

// Coming in C++ 17
template <class T>
constexpr std::add_const_t<T>& as_const(const T& t) noexcept
{
	return t;
}

auto word_ = x3::lexeme[+(x3::char_ - x3::space)];
auto on_word = [&](auto& ctx) {
	return wordmap.getMapping(x3::_attr(ctx));
};
auto linefile = *(*(word_[on_word]) > x3::eol);

int main(int argc, char** argv)
{
	if (argc < 2)
	{
		return -1;
	}
	ifstream file(argv[1]);
	vector<vector<box>> ourBoxes;
	vector<vector<double>> scoreVals;

	parseToEndWithError(file, boxes > scores, as_const(std::forward_as_tuple(ourBoxes, scoreVals)));
	cout << "Read " << ourBoxes.size() << " box lists and " << scoreVals.size() << " score lists." << "\n";

	file = ifstream(argv[2]);
	vector<vector<int>> rows;
	parseToEndWithError(file, linefile, rows);
}<|endoftext|>


<commit_before>/** Copyright (C) 2017 Ultimaker - Released under terms of the AGPLv3 License */
#include "Mold.h"
#include "utils/intpoint.h"

namespace cura
{

void Mold::process(Slicer& slicer, coord_t layer_height, double angle, coord_t width, coord_t open_polyline_width)
{
    Polygons mold_outline_above; // the outside of the mold

    coord_t inset = tan(angle / 180 * M_PI) * layer_height;
    for (int layer_nr = slicer.layers.size() - 1; layer_nr >= 0; layer_nr--)
    {
        SlicerLayer& layer = slicer.layers[layer_nr];
        Polygons model_outlines = layer.polygons.unionPolygons(layer.openPolylines.offsetPolyLine(open_polyline_width / 2));
        if (angle >= 90)
        {
            layer.polygons = model_outlines.offset(width).difference(model_outlines);
        }
        else
        {
            mold_outline_above = mold_outline_above.offset(-inset).unionPolygons(model_outlines.offset(width));
            layer.polygons = mold_outline_above.difference(model_outlines);
        }
    }

}

}//namespace cura
<commit_msg>fix: don't print open polylines when making molds (CURA-3512)<commit_after>/** Copyright (C) 2017 Ultimaker - Released under terms of the AGPLv3 License */
#include "Mold.h"
#include "utils/intpoint.h"

namespace cura
{

void Mold::process(Slicer& slicer, coord_t layer_height, double angle, coord_t width, coord_t open_polyline_width)
{
    Polygons mold_outline_above; // the outside of the mold

    coord_t inset = tan(angle / 180 * M_PI) * layer_height;
    for (int layer_nr = slicer.layers.size() - 1; layer_nr >= 0; layer_nr--)
    {
        SlicerLayer& layer = slicer.layers[layer_nr];
        Polygons model_outlines = layer.polygons.unionPolygons(layer.openPolylines.offsetPolyLine(open_polyline_width / 2));
        if (angle >= 90)
        {
            layer.polygons = model_outlines.offset(width).difference(model_outlines);
        }
        else
        {
            mold_outline_above = mold_outline_above.offset(-inset).unionPolygons(model_outlines.offset(width));
            layer.polygons = mold_outline_above.difference(model_outlines);
        }
        layer.openPolylines.clear();
    }

}

}//namespace cura
<|endoftext|>


<commit_before>#include "../includes/NSFW.h"

#if defined(_WIN32)
#include <windows.h>
#define sleep_for_ms(ms) Sleep(ms)
#else
#include <unistd.h>
#define sleep_for_ms(ms) usleep(ms * 1000)
#endif

#pragma unmanaged
Persistent<v8::Function> NSFW::constructor;

NSFW::NSFW(uint32_t debounceMS, std::string path, Callback *eventCallback, Callback *errorCallback):
  mDebounceMS(debounceMS),
  mErrorCallback(errorCallback),
  mEventCallback(eventCallback),
  mInterface(NULL),
  mInterfaceLockValid(false),
  mPath(path),
  mRunning(false),
  mQueue(std::make_shared<EventQueue>())
  {
    HandleScope scope;
    v8::Local<v8::Object> obj = New<v8::Object>();
    mPersistentHandle.Reset(obj);
    mInterfaceLockValid = uv_mutex_init(&mInterfaceLock) == 0;
  }

NSFW::~NSFW() {
  if (mInterface != NULL) {
    delete mInterface;
  }
  delete mEventCallback;
  delete mErrorCallback;

  if (mInterfaceLockValid) {
    uv_mutex_destroy(&mInterfaceLock);
  }
}

void NSFW::fireErrorCallback(uv_async_t *handle) {
  Nan::HandleScope scope;
  ErrorBaton *baton = (ErrorBaton *)handle->data;
  v8::Local<v8::Value> argv[] = {
    New<v8::String>(baton->error).ToLocalChecked()
  };
  baton->nsfw->mErrorCallback->Call(1, argv);
  delete baton;
}

void NSFW::fireEventCallback(uv_async_t *handle) {
  Nan::HandleScope scope;
  NSFW *nsfw = (NSFW *)handle->data;
  auto events = nsfw->mQueue->dequeueAll();
  if (events == nullptr) {
    return;
  }

  v8::Local<v8::Array> eventArray = New<v8::Array>((int)events->size());

  for (unsigned int i = 0; i < events->size(); ++i) {
    v8::Local<v8::Object> jsEvent = New<v8::Object>();

    jsEvent->Set(New<v8::String>("action").ToLocalChecked(), New<v8::Number>((*events)[i]->type));
    jsEvent->Set(New<v8::String>("directory").ToLocalChecked(), New<v8::String>((*events)[i]->fromDirectory).ToLocalChecked());

    if ((*events)[i]->type == RENAMED) {
      jsEvent->Set(New<v8::String>("oldFile").ToLocalChecked(), New<v8::String>((*events)[i]->fromFile).ToLocalChecked());
      jsEvent->Set(New<v8::String>("newDirectory").ToLocalChecked(), New<v8::String>((*events)[i]->toDirectory).ToLocalChecked());
      jsEvent->Set(New<v8::String>("newFile").ToLocalChecked(), New<v8::String>((*events)[i]->toFile).ToLocalChecked());
    } else {
      jsEvent->Set(New<v8::String>("file").ToLocalChecked(), New<v8::String>((*events)[i]->fromFile).ToLocalChecked());
    }

    eventArray->Set(i, jsEvent);
  }

  v8::Local<v8::Value> argv[] = {
    eventArray
  };

  nsfw->mEventCallback->Call(1, argv);
}

void NSFW::pollForEvents(void *arg) {
  NSFW *nsfw = (NSFW *)arg;
  while(nsfw->mRunning) {
    uv_mutex_lock(&nsfw->mInterfaceLock);

    if (nsfw->mInterface->hasErrored()) {
      ErrorBaton *baton = new ErrorBaton;
      baton->nsfw = nsfw;
      baton->error = nsfw->mInterface->getError();

      nsfw->mErrorCallbackAsync.data = (void *)baton;
      uv_async_send(&nsfw->mErrorCallbackAsync);
      nsfw->mRunning = false;
      uv_mutex_unlock(&nsfw->mInterfaceLock);
      break;
    }

    if (nsfw->mQueue->count() == 0) {
      uv_mutex_unlock(&nsfw->mInterfaceLock);
      sleep_for_ms(50);
      continue;
    }

    nsfw->mEventCallbackAsync.data = (void *)nsfw;
    uv_async_send(&nsfw->mEventCallbackAsync);

    uv_mutex_unlock(&nsfw->mInterfaceLock);

    sleep_for_ms(nsfw->mDebounceMS);
  }
}

NAN_MODULE_INIT(NSFW::Init) {
  Nan::HandleScope scope;

  v8::Local<v8::FunctionTemplate> tpl = New<v8::FunctionTemplate>(JSNew);
  tpl->SetClassName(New<v8::String>("NSFW").ToLocalChecked());
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  SetPrototypeMethod(tpl, "start", Start);
  SetPrototypeMethod(tpl, "stop", Stop);

  v8::Local<v8::Context> context = Nan::GetCurrentContext();
  constructor.Reset(tpl->GetFunction(context).ToLocalChecked());
  Set(target, New<v8::String>("NSFW").ToLocalChecked(), tpl->GetFunction(context).ToLocalChecked());
}

NAN_METHOD(NSFW::JSNew) {
  if (!info.IsConstructCall()) {
    const int argc = 4;
    v8::Isolate *isolate = info.GetIsolate();
    v8::Local<v8::Value> argv[argc] = {info[0], info[1], info[2], info[3]};
    v8::Local<v8::Context> context = isolate->GetCurrentContext();
    v8::Local<v8::Function> cons = v8::Local<v8::Function>::New(isolate, constructor);
    info.GetReturnValue().Set(cons->NewInstance(context, argc, argv).ToLocalChecked());
    return;
  }

  if (info.Length() < 1 || !info[0]->IsUint32()) {
    return ThrowError("First argument of constructor must be a positive integer.");
  }
  if (info.Length() < 2 || !info[1]->IsString()) {
    return ThrowError("Second argument of constructor must be a path.");
  }
  if (info.Length() < 3 || !info[2]->IsFunction()) {
    return ThrowError("Third argument of constructor must be a callback.");
  }
  if (info.Length() < 4 || !info[3]->IsFunction()) {
    return ThrowError("Fourth argument of constructor must be a callback.");
  }

  v8::Local<v8::Context> context = Nan::GetCurrentContext();
  uint32_t debounceMS = info[0]->Uint32Value(context).FromJust();
  Nan::Utf8String utf8Value(Nan::To<v8::String>(info[1]).ToLocalChecked());
  std::string path = std::string(*utf8Value);
  Callback *eventCallback = new Callback(info[2].As<v8::Function>());
  Callback *errorCallback = new Callback(info[3].As<v8::Function>());

  NSFW *nsfw = new NSFW(debounceMS, path, eventCallback, errorCallback);
  nsfw->Wrap(info.This());
  info.GetReturnValue().Set(info.This());
}

NAN_METHOD(NSFW::Start) {
  Nan::HandleScope scope;

  NSFW *nsfw = ObjectWrap::Unwrap<NSFW>(info.This());
  if (!nsfw->mInterfaceLockValid) {
    return ThrowError("NSFW failed to initialize properly. Try creating a new NSFW.");
  }

  if (
    info.Length() < 1 ||
    !info[0]->IsFunction()
  ) {
    return ThrowError("Must provide callback to start.");
  }

  Callback *callback = new Callback(info[0].As<v8::Function>());

  if (nsfw->mInterface != NULL) {
    v8::Local<v8::Value> argv[1] = {
      Nan::Error("This NSFW cannot be started, because it is already running.")
    };
    callback->Call(1, argv);
    delete callback;
    return;
  }

  New(nsfw->mPersistentHandle)->Set(New("nsfw").ToLocalChecked(), info.This());

  AsyncQueueWorker(new StartWorker(nsfw, callback));
}

NSFW::StartWorker::StartWorker(NSFW *nsfw, Callback *callback):
  AsyncWorker(callback), mNSFW(nsfw) {
    uv_async_init(uv_default_loop(), &nsfw->mErrorCallbackAsync, &NSFW::fireErrorCallback);
    uv_async_init(uv_default_loop(), &nsfw->mEventCallbackAsync, &NSFW::fireEventCallback);
  }

void NSFW::StartWorker::Execute() {
  uv_mutex_lock(&mNSFW->mInterfaceLock);

  if (mNSFW->mInterface != NULL) {
    uv_mutex_unlock(&mNSFW->mInterfaceLock);
    return;
  }

  mNSFW->mQueue->clear();
  mNSFW->mInterface = new NativeInterface(mNSFW->mPath, mNSFW->mQueue);
  if (mNSFW->mInterface->isWatching()) {
    mNSFW->mRunning = true;
    uv_thread_create(&mNSFW->mPollThread, NSFW::pollForEvents, mNSFW);
  } else {
    delete mNSFW->mInterface;
    mNSFW->mInterface = NULL;
  }

  uv_mutex_unlock(&mNSFW->mInterfaceLock);
}

void NSFW::StartWorker::HandleOKCallback() {
  HandleScope();
  if (mNSFW->mInterface == NULL) {
    if (!mNSFW->mPersistentHandle.IsEmpty()) {
      v8::Local<v8::Object> obj = New<v8::Object>();
      mNSFW->mPersistentHandle.Reset(obj);
    }
    v8::Local<v8::Value> argv[1] = {
      Nan::Error("NSFW was unable to start watching that directory.")
    };
    callback->Call(1, argv);
  } else {
    callback->Call(0, NULL);
  }
}

NAN_METHOD(NSFW::Stop) {
  Nan::HandleScope scope;

  NSFW *nsfw = ObjectWrap::Unwrap<NSFW>(info.This());
  if (!nsfw->mInterfaceLockValid) {
    return ThrowError("NSFW failed to initialize properly. Try creating a new NSFW.");
  }

  if (
    info.Length() < 1 ||
    !info[0]->IsFunction()
  ) {
    return ThrowError("Must provide callback to stop.");
  }

  Callback *callback = new Callback(info[0].As<v8::Function>());

  if (nsfw->mInterface == NULL) {
    v8::Local<v8::Value> argv[1] = {
      Nan::Error("This NSFW cannot be stopped, because it is not running.")
    };
    callback->Call(1, argv);
    delete callback;
    return;
  }

  AsyncQueueWorker(new StopWorker(nsfw, callback));
}

NSFW::StopWorker::StopWorker(NSFW *nsfw, Callback *callback):
  AsyncWorker(callback), mNSFW(nsfw) {}

void NSFW::StopWorker::Execute() {
  uv_mutex_lock(&mNSFW->mInterfaceLock);
  if (mNSFW->mInterface == NULL) {
    uv_mutex_unlock(&mNSFW->mInterfaceLock);
    return;
  }
  uv_mutex_unlock(&mNSFW->mInterfaceLock);

  // unlock the mInterfaceLock mutex while operate on the running identifier
  mNSFW->mRunning = false;

  uv_thread_join(&mNSFW->mPollThread);

  uv_mutex_lock(&mNSFW->mInterfaceLock);
  delete mNSFW->mInterface;
  mNSFW->mInterface = NULL;
  mNSFW->mQueue->clear();

  uv_mutex_unlock(&mNSFW->mInterfaceLock);
}

void NSFW::StopWorker::HandleOKCallback() {
  HandleScope();

  if (!mNSFW->mPersistentHandle.IsEmpty()) {
    v8::Local<v8::Object> obj = New<v8::Object>();
    mNSFW->mPersistentHandle.Reset(obj);
  }

  uv_close(reinterpret_cast<uv_handle_t*>(&mNSFW->mErrorCallbackAsync), nullptr);
  uv_close(reinterpret_cast<uv_handle_t*>(&mNSFW->mEventCallbackAsync), nullptr);

  callback->Call(0, NULL);
}

NODE_MODULE(nsfw, NSFW::Init)
<commit_msg>Replace deprecated calls in NSFW.cpp<commit_after>#include "../includes/NSFW.h"

#if defined(_WIN32)
#include <windows.h>
#define sleep_for_ms(ms) Sleep(ms)
#else
#include <unistd.h>
#define sleep_for_ms(ms) usleep(ms * 1000)
#endif

#pragma unmanaged
Persistent<v8::Function> NSFW::constructor;

NSFW::NSFW(uint32_t debounceMS, std::string path, Callback *eventCallback, Callback *errorCallback):
  mDebounceMS(debounceMS),
  mErrorCallback(errorCallback),
  mEventCallback(eventCallback),
  mInterface(NULL),
  mInterfaceLockValid(false),
  mPath(path),
  mRunning(false),
  mQueue(std::make_shared<EventQueue>())
  {
    HandleScope scope;
    v8::Local<v8::Object> obj = New<v8::Object>();
    mPersistentHandle.Reset(obj);
    mInterfaceLockValid = uv_mutex_init(&mInterfaceLock) == 0;
  }

NSFW::~NSFW() {
  if (mInterface != NULL) {
    delete mInterface;
  }
  delete mEventCallback;
  delete mErrorCallback;

  if (mInterfaceLockValid) {
    uv_mutex_destroy(&mInterfaceLock);
  }
}

void NSFW::fireErrorCallback(uv_async_t *handle) {
  Nan::HandleScope scope;
  ErrorBaton *baton = (ErrorBaton *)handle->data;
  v8::Local<v8::Value> argv[] = {
    New<v8::String>(baton->error).ToLocalChecked()
  };
  baton->nsfw->mErrorCallback->Call(1, argv);
  delete baton;
}

void NSFW::fireEventCallback(uv_async_t *handle) {
  Nan::HandleScope scope;
  NSFW *nsfw = (NSFW *)handle->data;
  auto events = nsfw->mQueue->dequeueAll();
  if (events == nullptr) {
    return;
  }

  v8::Local<v8::Array> eventArray = New<v8::Array>((int)events->size());

  for (unsigned int i = 0; i < events->size(); ++i) {
    v8::Local<v8::Object> jsEvent = New<v8::Object>();

    Nan::Set(jsEvent, Nan::New("action").ToLocalChecked(), Nan::New<v8::Number>((*events)[i]->type));
    Nan::Set(jsEvent, Nan::New("directory").ToLocalChecked(), Nan::New((*events)[i]->fromDirectory).ToLocalChecked());

    if ((*events)[i]->type == RENAMED) {
      Nan::Set(jsEvent, Nan::New("oldFile").ToLocalChecked(), Nan::New((*events)[i]->fromFile).ToLocalChecked());
      Nan::Set(jsEvent, Nan::New("newDirectory").ToLocalChecked(), Nan::New((*events)[i]->toDirectory).ToLocalChecked());
      Nan::Set(jsEvent, Nan::New("newFile").ToLocalChecked(), Nan::New((*events)[i]->toFile).ToLocalChecked());
    } else {
      Nan::Set(jsEvent, Nan::New("file").ToLocalChecked(), Nan::New((*events)[i]->fromFile).ToLocalChecked());
    }

    Nan::Set(eventArray, i, jsEvent);
  }

  v8::Local<v8::Value> argv[] = {
    eventArray
  };

  nsfw->mEventCallback->Call(1, argv);
}

void NSFW::pollForEvents(void *arg) {
  NSFW *nsfw = (NSFW *)arg;
  while(nsfw->mRunning) {
    uv_mutex_lock(&nsfw->mInterfaceLock);

    if (nsfw->mInterface->hasErrored()) {
      ErrorBaton *baton = new ErrorBaton;
      baton->nsfw = nsfw;
      baton->error = nsfw->mInterface->getError();

      nsfw->mErrorCallbackAsync.data = (void *)baton;
      uv_async_send(&nsfw->mErrorCallbackAsync);
      nsfw->mRunning = false;
      uv_mutex_unlock(&nsfw->mInterfaceLock);
      break;
    }

    if (nsfw->mQueue->count() == 0) {
      uv_mutex_unlock(&nsfw->mInterfaceLock);
      sleep_for_ms(50);
      continue;
    }

    nsfw->mEventCallbackAsync.data = (void *)nsfw;
    uv_async_send(&nsfw->mEventCallbackAsync);

    uv_mutex_unlock(&nsfw->mInterfaceLock);

    sleep_for_ms(nsfw->mDebounceMS);
  }
}

NAN_MODULE_INIT(NSFW::Init) {
  Nan::HandleScope scope;

  v8::Local<v8::FunctionTemplate> tpl = New<v8::FunctionTemplate>(JSNew);
  tpl->SetClassName(New<v8::String>("NSFW").ToLocalChecked());
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  SetPrototypeMethod(tpl, "start", Start);
  SetPrototypeMethod(tpl, "stop", Stop);

  v8::Local<v8::Context> context = Nan::GetCurrentContext();
  constructor.Reset(tpl->GetFunction(context).ToLocalChecked());
  Set(target, New<v8::String>("NSFW").ToLocalChecked(), tpl->GetFunction(context).ToLocalChecked());
}

NAN_METHOD(NSFW::JSNew) {
  if (!info.IsConstructCall()) {
    const int argc = 4;
    v8::Isolate *isolate = info.GetIsolate();
    v8::Local<v8::Value> argv[argc] = {info[0], info[1], info[2], info[3]};
    v8::Local<v8::Context> context = isolate->GetCurrentContext();
    v8::Local<v8::Function> cons = v8::Local<v8::Function>::New(isolate, constructor);
    info.GetReturnValue().Set(cons->NewInstance(context, argc, argv).ToLocalChecked());
    return;
  }

  if (info.Length() < 1 || !info[0]->IsUint32()) {
    return ThrowError("First argument of constructor must be a positive integer.");
  }
  if (info.Length() < 2 || !info[1]->IsString()) {
    return ThrowError("Second argument of constructor must be a path.");
  }
  if (info.Length() < 3 || !info[2]->IsFunction()) {
    return ThrowError("Third argument of constructor must be a callback.");
  }
  if (info.Length() < 4 || !info[3]->IsFunction()) {
    return ThrowError("Fourth argument of constructor must be a callback.");
  }

  v8::Local<v8::Context> context = Nan::GetCurrentContext();
  uint32_t debounceMS = info[0]->Uint32Value(context).FromJust();
  Nan::Utf8String utf8Value(Nan::To<v8::String>(info[1]).ToLocalChecked());
  std::string path = std::string(*utf8Value);
  Callback *eventCallback = new Callback(info[2].As<v8::Function>());
  Callback *errorCallback = new Callback(info[3].As<v8::Function>());

  NSFW *nsfw = new NSFW(debounceMS, path, eventCallback, errorCallback);
  nsfw->Wrap(info.This());
  info.GetReturnValue().Set(info.This());
}

NAN_METHOD(NSFW::Start) {
  Nan::HandleScope scope;

  NSFW *nsfw = ObjectWrap::Unwrap<NSFW>(info.This());
  if (!nsfw->mInterfaceLockValid) {
    return ThrowError("NSFW failed to initialize properly. Try creating a new NSFW.");
  }

  if (
    info.Length() < 1 ||
    !info[0]->IsFunction()
  ) {
    return ThrowError("Must provide callback to start.");
  }

  Callback *callback = new Callback(info[0].As<v8::Function>());

  if (nsfw->mInterface != NULL) {
    v8::Local<v8::Value> argv[1] = {
      Nan::Error("This NSFW cannot be started, because it is already running.")
    };
    callback->Call(1, argv);
    delete callback;
    return;
  }

  Nan::Set(Nan::New(nsfw->mPersistentHandle), Nan::New("nsfw").ToLocalChecked(), info.This());

  AsyncQueueWorker(new StartWorker(nsfw, callback));
}

NSFW::StartWorker::StartWorker(NSFW *nsfw, Callback *callback):
  AsyncWorker(callback), mNSFW(nsfw) {
    uv_async_init(uv_default_loop(), &nsfw->mErrorCallbackAsync, &NSFW::fireErrorCallback);
    uv_async_init(uv_default_loop(), &nsfw->mEventCallbackAsync, &NSFW::fireEventCallback);
  }

void NSFW::StartWorker::Execute() {
  uv_mutex_lock(&mNSFW->mInterfaceLock);

  if (mNSFW->mInterface != NULL) {
    uv_mutex_unlock(&mNSFW->mInterfaceLock);
    return;
  }

  mNSFW->mQueue->clear();
  mNSFW->mInterface = new NativeInterface(mNSFW->mPath, mNSFW->mQueue);
  if (mNSFW->mInterface->isWatching()) {
    mNSFW->mRunning = true;
    uv_thread_create(&mNSFW->mPollThread, NSFW::pollForEvents, mNSFW);
  } else {
    delete mNSFW->mInterface;
    mNSFW->mInterface = NULL;
  }

  uv_mutex_unlock(&mNSFW->mInterfaceLock);
}

void NSFW::StartWorker::HandleOKCallback() {
  HandleScope();
  if (mNSFW->mInterface == NULL) {
    if (!mNSFW->mPersistentHandle.IsEmpty()) {
      v8::Local<v8::Object> obj = New<v8::Object>();
      mNSFW->mPersistentHandle.Reset(obj);
    }
    v8::Local<v8::Value> argv[1] = {
      Nan::Error("NSFW was unable to start watching that directory.")
    };
    callback->Call(1, argv);
  } else {
    callback->Call(0, NULL);
  }
}

NAN_METHOD(NSFW::Stop) {
  Nan::HandleScope scope;

  NSFW *nsfw = ObjectWrap::Unwrap<NSFW>(info.This());
  if (!nsfw->mInterfaceLockValid) {
    return ThrowError("NSFW failed to initialize properly. Try creating a new NSFW.");
  }

  if (
    info.Length() < 1 ||
    !info[0]->IsFunction()
  ) {
    return ThrowError("Must provide callback to stop.");
  }

  Callback *callback = new Callback(info[0].As<v8::Function>());

  if (nsfw->mInterface == NULL) {
    v8::Local<v8::Value> argv[1] = {
      Nan::Error("This NSFW cannot be stopped, because it is not running.")
    };
    callback->Call(1, argv);
    delete callback;
    return;
  }

  AsyncQueueWorker(new StopWorker(nsfw, callback));
}

NSFW::StopWorker::StopWorker(NSFW *nsfw, Callback *callback):
  AsyncWorker(callback), mNSFW(nsfw) {}

void NSFW::StopWorker::Execute() {
  uv_mutex_lock(&mNSFW->mInterfaceLock);
  if (mNSFW->mInterface == NULL) {
    uv_mutex_unlock(&mNSFW->mInterfaceLock);
    return;
  }
  uv_mutex_unlock(&mNSFW->mInterfaceLock);

  // unlock the mInterfaceLock mutex while operate on the running identifier
  mNSFW->mRunning = false;

  uv_thread_join(&mNSFW->mPollThread);

  uv_mutex_lock(&mNSFW->mInterfaceLock);
  delete mNSFW->mInterface;
  mNSFW->mInterface = NULL;
  mNSFW->mQueue->clear();

  uv_mutex_unlock(&mNSFW->mInterfaceLock);
}

void NSFW::StopWorker::HandleOKCallback() {
  HandleScope();

  if (!mNSFW->mPersistentHandle.IsEmpty()) {
    v8::Local<v8::Object> obj = New<v8::Object>();
    mNSFW->mPersistentHandle.Reset(obj);
  }

  uv_close(reinterpret_cast<uv_handle_t*>(&mNSFW->mErrorCallbackAsync), nullptr);
  uv_close(reinterpret_cast<uv_handle_t*>(&mNSFW->mEventCallbackAsync), nullptr);

  callback->Call(0, NULL);
}

NODE_MODULE(nsfw, NSFW::Init)
<|endoftext|>


<commit_before>#include <SDL2/SDL.h>

#include "client.h"

client::client() :
    m_mouseLat(0.0f),
    m_mouseLon(0.0f),
    m_origin(0.0f, 150.0f, 0.0f),
    m_velocity(0.0f, 0.0f, 0.0f),
    m_isOnGround(false),
    m_isOnWall(false)
{

}

u::map<int, int> &getKeyState(int key = 0, bool keyDown = false, bool keyUp = false);
void getMouseDelta(int *deltaX, int *deltaY);

bool client::tryUnstick(const kdMap &map, float radius) {
    static const m::vec3 offsets[] = {
        m::vec3(-1.0f, 1.0f,-1.0f),
        m::vec3( 1.0f, 1.0f,-1.0f),
        m::vec3( 1.0f, 1.0f, 1.0f),
        m::vec3(-1.0f, 1.0f, 1.0f),
        m::vec3(-1.0f,-1.0f,-1.0f),
        m::vec3( 1.0f,-1.0f,-1.0f),
        m::vec3( 1.0f,-1.0f, 1.0f),
        m::vec3(-1.0f,-1.0f, 1.0f)
    };
    const float radiusScale = radius * 0.1f;
    for (size_t j = 1; j < 4; j++) {
        for (size_t i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++) {
            m::vec3 tryPosition = m_origin + j * radiusScale * offsets[i];
            if (map.isSphereStuck(tryPosition, radius))
                continue;
            m_origin = tryPosition;
            return true;
        }
    }
    return false;
}

void client::update(const kdMap &map, float dt) {
    static constexpr float kMaxVelocity = 80.0f;
    static constexpr m::vec3 kGravity(0.0f, -98.0f, 0.0f);
    static constexpr float kRadius = 5.0f;

    kdSphereTrace trace;
    trace.radius = kRadius;

    m::vec3 velocity = m_velocity;
    m::vec3 originalVelocity = m_velocity;
    m::vec3 primalVelocity = m_velocity;
    m::vec3 newVelocity;
    velocity.maxLength(kMaxVelocity);

    m::vec3 planes[kdMap::kMaxClippingPlanes];
    m::vec3 pos = m_origin;
    float timeLeft = dt;
    float allFraction = 0.0f;
    size_t numBumps = kdMap::kMaxBumps;
    size_t numPlanes = 0;

    bool wallHit = false;
    bool groundHit = false;
    for (size_t bumpCount = 0; bumpCount < numBumps; bumpCount++) {
        if (velocity == m::vec3(0.0f, 0.0f, 0.0f))
            break;

        trace.start = pos;
        trace.dir = timeLeft * velocity;
        map.traceSphere(&trace);

        float f = m::clamp(trace.fraction, 0.0f, 1.0f);
        allFraction += f;

        if (f > 0.0f) {
            pos += trace.dir * f * kdMap::kFractionScale;
            originalVelocity = velocity;
            numPlanes = 0;
        }

        if (f == 1.0f)
            break;

        wallHit = true;

        timeLeft = timeLeft * (1.0f - f);

        if (trace.plane.n[1] > 0.7f) {
            groundHit = true;
            //break;
        }

        if (numPlanes >= kdMap::kMaxClippingPlanes) {
            velocity = m::vec3(0.0f, 0.0f, 0.0f);
            break;
        }

        // next clipping plane
        planes[numPlanes++] = trace.plane.n;

        size_t i;
        for (i = 0; i < numPlanes; i++) {
            kdMap::clipVelocity(originalVelocity, planes[i], newVelocity, kdMap::kOverClip);
            size_t j;
            for (j = 0; j < numPlanes; j++) {
                if (j != i && !(planes[i] == planes[j])) {
                    if (newVelocity * planes[j] < 0.0f)
                        break;
                }
            }
            if (j == numPlanes)
                break;
        }

        // did we make it through the entire plane set?
        if (i != numPlanes)
            velocity = newVelocity;
        else {
            // go along the planes crease
            if (numPlanes != 2) {
                velocity = m::vec3(0.0f, 0.0f, 0.0f);
                break;
            }
            m::vec3 dir = planes[0] ^ planes[1];
            float d = dir * velocity;
            velocity = dir * d;
        }

        if (velocity * primalVelocity <= 0.0f) {
            velocity = m::vec3(0.0f, 0.0f, 0.0f);
            break;
        }
    }

    if (allFraction == 0.0f) {
        velocity = m::vec3(0.0f, 0.0f, 0.0f);
    }

    m_isOnGround = groundHit;
    m_isOnWall = wallHit;
    if (groundHit) {
        velocity.y = 0.0f;
    } else {
        velocity += kGravity * dt;
    }

    // we could be stuck
    if (map.isSphereStuck(pos, kRadius)) {
        m_origin = pos;
        tryUnstick(map, kRadius);
    }

    m_origin = pos;
    m_velocity = velocity;

    u::vector<clientCommands> commands;
    inputGetCommands(commands);
    inputMouseMove();

    move(commands);
}

void client::move(const u::vector<clientCommands> &commands) {
    m::vec3 velocity = m_velocity;
    m::vec3 direction;
    m::vec3 side;
    m::vec3 newDirection(0.0f, 0.0f, 0.0f);
    m::vec3 jump(0.0f, 0.0f, 0.0f);
    m::quat rotation = m_rotation;

    rotation.getOrient(&direction, nullptr, &side);

    m::vec3 upCamera;
    for (auto &it : commands) {
        switch (it) {
            case kCommandForward:
                newDirection += direction;
                break;
            case kCommandBackward:
                newDirection -= direction;
                break;
            case kCommandLeft:
                newDirection -= side;
                break;
            case kCommandRight:
                newDirection += side;
                break;
            case kCommandJump:
                jump = m::vec3(0.0f, 0.25f, 0.0f);
                break;
        }
    }

    const float kClientSpeed = 40.0f; // cm/s
    const float kJumpSpeed = 130.0f; // cm/s
    const float kStopSpeed = 90.0f; // -cm/s

    newDirection.y = 0.0f;
    if (newDirection.absSquared() > 0.1f)
        newDirection.setLength(kClientSpeed);
    newDirection.y += velocity.y;
    if (m_isOnGround) {
        newDirection += jump * kJumpSpeed;
    }
    if (commands.size() == 0) {
        m::vec3 slowDown = m_velocity * kStopSpeed * 0.01f;
        slowDown.y = 0.0f;
        newDirection += slowDown;
    }
    m_lastDirection = direction;
    m_velocity = newDirection;
}

void client::inputMouseMove(void) {
    static const float kSensitivity = 0.50f / 6.0f;
    static const bool kInvert = true;
    const float invert = kInvert ? -1.0f : 1.0f;

    int deltaX;
    int deltaY;
    getMouseDelta(&deltaX, &deltaY);

    m_mouseLat -= (float)deltaY * kSensitivity * invert;
    m_mouseLat = m::clamp(m_mouseLat, -89.0f, 89.0f);

    m_mouseLon -= (float)deltaX * kSensitivity * invert;

    m::quat qlat(m::vec3::xAxis, m_mouseLat * m::kDegToRad);
    m::quat qlon(m::vec3::yAxis, m_mouseLon * m::kDegToRad);

    setRotation(qlon * qlat);
}

void client::inputGetCommands(u::vector<clientCommands> &commands) {
    u::map<int, int> &keyState = getKeyState();
    commands.clear();
    if (keyState[SDLK_w])     commands.push_back(kCommandForward);
    if (keyState[SDLK_s])     commands.push_back(kCommandBackward);
    if (keyState[SDLK_a])     commands.push_back(kCommandLeft);
    if (keyState[SDLK_d])     commands.push_back(kCommandRight);
    if (keyState[SDLK_SPACE]) commands.push_back(kCommandJump);
}

void client::setRotation(const m::quat &rotation) {
    m_rotation = rotation;
}

void client::getDirection(m::vec3 *direction, m::vec3 *up, m::vec3 *side) const {
    return m_rotation.getOrient(direction, up, side);
}

const m::vec3 &client::getPosition(void) const {
    return m_origin;
}
<commit_msg>Limit physics to 60fps<commit_after>#include <SDL2/SDL.h>

#include "client.h"

client::client() :
    m_mouseLat(0.0f),
    m_mouseLon(0.0f),
    m_origin(0.0f, 150.0f, 0.0f),
    m_velocity(0.0f, 0.0f, 0.0f),
    m_isOnGround(false),
    m_isOnWall(false)
{

}

u::map<int, int> &getKeyState(int key = 0, bool keyDown = false, bool keyUp = false);
void getMouseDelta(int *deltaX, int *deltaY);

bool client::tryUnstick(const kdMap &map, float radius) {
    static const m::vec3 offsets[] = {
        m::vec3(-1.0f, 1.0f,-1.0f),
        m::vec3( 1.0f, 1.0f,-1.0f),
        m::vec3( 1.0f, 1.0f, 1.0f),
        m::vec3(-1.0f, 1.0f, 1.0f),
        m::vec3(-1.0f,-1.0f,-1.0f),
        m::vec3( 1.0f,-1.0f,-1.0f),
        m::vec3( 1.0f,-1.0f, 1.0f),
        m::vec3(-1.0f,-1.0f, 1.0f)
    };
    const float radiusScale = radius * 0.1f;
    for (size_t j = 1; j < 4; j++) {
        for (size_t i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++) {
            m::vec3 tryPosition = m_origin + j * radiusScale * offsets[i];
            if (map.isSphereStuck(tryPosition, radius))
                continue;
            m_origin = tryPosition;
            return true;
        }
    }
    return false;
}

void client::update(const kdMap &map, float dt) {
    // limit physics updates to 60fps
    const float rest = 1.0f / 60.0f - dt;
    if (rest > 0.0f)
        return;

    static constexpr float kMaxVelocity = 80.0f;
    static constexpr m::vec3 kGravity(0.0f, -98.0f, 0.0f);
    static constexpr float kRadius = 5.0f;

    kdSphereTrace trace;
    trace.radius = kRadius;

    m::vec3 velocity = m_velocity;
    m::vec3 originalVelocity = m_velocity;
    m::vec3 primalVelocity = m_velocity;
    m::vec3 newVelocity;
    velocity.maxLength(kMaxVelocity);

    m::vec3 planes[kdMap::kMaxClippingPlanes];
    m::vec3 pos = m_origin;
    float timeLeft = dt;
    float allFraction = 0.0f;
    size_t numBumps = kdMap::kMaxBumps;
    size_t numPlanes = 0;

    bool wallHit = false;
    bool groundHit = false;
    for (size_t bumpCount = 0; bumpCount < numBumps; bumpCount++) {
        if (velocity == m::vec3(0.0f, 0.0f, 0.0f))
            break;

        trace.start = pos;
        trace.dir = timeLeft * velocity;
        map.traceSphere(&trace);

        float f = m::clamp(trace.fraction, 0.0f, 1.0f);
        allFraction += f;

        if (f > 0.0f) {
            pos += trace.dir * f * kdMap::kFractionScale;
            originalVelocity = velocity;
            numPlanes = 0;
        }

        if (f == 1.0f)
            break;

        wallHit = true;

        timeLeft = timeLeft * (1.0f - f);

        if (trace.plane.n[1] > 0.7f) {
            groundHit = true;
            //break;
        }

        if (numPlanes >= kdMap::kMaxClippingPlanes) {
            velocity = m::vec3(0.0f, 0.0f, 0.0f);
            break;
        }

        // next clipping plane
        planes[numPlanes++] = trace.plane.n;

        size_t i;
        for (i = 0; i < numPlanes; i++) {
            kdMap::clipVelocity(originalVelocity, planes[i], newVelocity, kdMap::kOverClip);
            size_t j;
            for (j = 0; j < numPlanes; j++) {
                if (j != i && !(planes[i] == planes[j])) {
                    if (newVelocity * planes[j] < 0.0f)
                        break;
                }
            }
            if (j == numPlanes)
                break;
        }

        // did we make it through the entire plane set?
        if (i != numPlanes)
            velocity = newVelocity;
        else {
            // go along the planes crease
            if (numPlanes != 2) {
                velocity = m::vec3(0.0f, 0.0f, 0.0f);
                break;
            }
            m::vec3 dir = planes[0] ^ planes[1];
            float d = dir * velocity;
            velocity = dir * d;
        }

        if (velocity * primalVelocity <= 0.0f) {
            velocity = m::vec3(0.0f, 0.0f, 0.0f);
            break;
        }
    }

    if (allFraction == 0.0f) {
        velocity = m::vec3(0.0f, 0.0f, 0.0f);
    }

    m_isOnGround = groundHit;
    m_isOnWall = wallHit;
    if (groundHit) {
        velocity.y = 0.0f;
    } else {
        velocity += kGravity * dt;
    }

    // we could be stuck
    if (map.isSphereStuck(pos, kRadius)) {
        m_origin = pos;
        tryUnstick(map, kRadius);
    }

    m_origin = pos;
    m_velocity = velocity;

    u::vector<clientCommands> commands;
    inputGetCommands(commands);
    inputMouseMove();

    move(commands);
}

void client::move(const u::vector<clientCommands> &commands) {
    m::vec3 velocity = m_velocity;
    m::vec3 direction;
    m::vec3 side;
    m::vec3 newDirection(0.0f, 0.0f, 0.0f);
    m::vec3 jump(0.0f, 0.0f, 0.0f);
    m::quat rotation = m_rotation;

    rotation.getOrient(&direction, nullptr, &side);

    m::vec3 upCamera;
    for (auto &it : commands) {
        switch (it) {
            case kCommandForward:
                newDirection += direction;
                break;
            case kCommandBackward:
                newDirection -= direction;
                break;
            case kCommandLeft:
                newDirection -= side;
                break;
            case kCommandRight:
                newDirection += side;
                break;
            case kCommandJump:
                jump = m::vec3(0.0f, 0.25f, 0.0f);
                break;
        }
    }

    const float kClientSpeed = 40.0f; // cm/s
    const float kJumpSpeed = 130.0f; // cm/s
    const float kStopSpeed = 90.0f; // -cm/s

    newDirection.y = 0.0f;
    if (newDirection.absSquared() > 0.1f)
        newDirection.setLength(kClientSpeed);
    newDirection.y += velocity.y;
    if (m_isOnGround) {
        newDirection += jump * kJumpSpeed;
    }
    if (commands.size() == 0) {
        m::vec3 slowDown = m_velocity * kStopSpeed * 0.01f;
        slowDown.y = 0.0f;
        newDirection += slowDown;
    }
    m_lastDirection = direction;
    m_velocity = newDirection;
}

void client::inputMouseMove(void) {
    static const float kSensitivity = 0.50f / 6.0f;
    static const bool kInvert = true;
    const float invert = kInvert ? -1.0f : 1.0f;

    int deltaX;
    int deltaY;
    getMouseDelta(&deltaX, &deltaY);

    m_mouseLat -= (float)deltaY * kSensitivity * invert;
    m_mouseLat = m::clamp(m_mouseLat, -89.0f, 89.0f);

    m_mouseLon -= (float)deltaX * kSensitivity * invert;

    m::quat qlat(m::vec3::xAxis, m_mouseLat * m::kDegToRad);
    m::quat qlon(m::vec3::yAxis, m_mouseLon * m::kDegToRad);

    setRotation(qlon * qlat);
}

void client::inputGetCommands(u::vector<clientCommands> &commands) {
    u::map<int, int> &keyState = getKeyState();
    commands.clear();
    if (keyState[SDLK_w])     commands.push_back(kCommandForward);
    if (keyState[SDLK_s])     commands.push_back(kCommandBackward);
    if (keyState[SDLK_a])     commands.push_back(kCommandLeft);
    if (keyState[SDLK_d])     commands.push_back(kCommandRight);
    if (keyState[SDLK_SPACE]) commands.push_back(kCommandJump);
}

void client::setRotation(const m::quat &rotation) {
    m_rotation = rotation;
}

void client::getDirection(m::vec3 *direction, m::vec3 *up, m::vec3 *side) const {
    return m_rotation.getOrient(direction, up, side);
}

const m::vec3 &client::getPosition(void) const {
    return m_origin;
}
<|endoftext|>


<commit_before>#include <netdb.h>
#include <unistd.h>
#include <sys/fcntl.h>

#include "client.h"
#include "duckchat.h"
#include "raw.h"

// Variables
struct sockaddr_in client_addr;
struct sockaddr_in server_addr;
int client_socket;
struct addrinfo *server_info;
char *channel;

// Prints an error message and exits the program.
void Error(const char *msg) {
  std::cerr << msg << std::endl;
  exit(1);
}

// Connects to the server at a the given port.
void Connect(char *domain, const char *port) {
  std::cout << "Connecting to " << domain << std::endl;

  struct addrinfo hints;
  struct addrinfo *server_info_tmp;
  int status;

  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_DGRAM;
  hints.ai_protocol = 0;

  if ((status = getaddrinfo(domain, port, &hints, &server_info_tmp)) != 0) {
    std::cerr << "client: unable to resolve address: " << gai_strerror(status) << std::endl;
    exit(1);
  }

  // getaddrinfo() returns a list of address structures into server_info_tmp.
  // Try each address until we successfully connect().
  // If socket() (or connect()) fails, close the socket and try the next address.

  for (server_info = server_info_tmp; server_info != NULL; server_info = server_info->ai_next) {
    if ((client_socket = socket(server_info->ai_family, server_info->ai_socktype, server_info->ai_protocol)) < 0) {
      continue;
    }
    if (connect(client_socket, server_info->ai_addr, server_info->ai_addrlen) != -1) {
      fcntl(client_socket, F_SETFL, O_NONBLOCK);
      break; // Success
    }
    close(client_socket);
  }

  if (server_info == NULL) {
    Error("client: all sockets failed to connect");
  }
}

// Sends a message to all users in on the active channel.
int RequestSay(const char *message) {
  struct request_say say;
  memset(&say, 0, sizeof(say));
  say.req_type = REQ_SAY;
  strncpy(say.req_text, message, SAY_MAX);
  strncpy(say.req_channel, channel, CHANNEL_MAX);

  if (sendto(client_socket, &say, sizeof(say), 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
    Error("client: failed to send message\n");
  }

  return 0;
}

// Sends login requests to the server.
int RequestLogin(char *username) {
  struct request_login login;
  memset(&login, 0, sizeof(login));
  login.req_type = REQ_LOGIN;
  strncpy(login.req_username, username, USERNAME_MAX);

  size_t message_size = sizeof(struct request_login);

  if (sendto(client_socket, &login, message_size, 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
    Error("client: failed to request login\n");
  }

  return 0;
}

// Sends logout requests to the server.
int RequestLogout() {
  struct request_logout logout;
  memset((char *) &logout, 0, sizeof(logout));
  logout.req_type = REQ_LOGOUT;

  size_t message_size = sizeof(struct request_logout);

  if (sendto(client_socket, &logout, message_size, 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
    Error("client: failed to request logout\n");
  }

  return 0;
}

// Sends join requests to the server.
int RequestJoin(char *channel) {
  struct request_join join;
  memset((char *) &join, 0, sizeof(join));
  join.req_type = REQ_JOIN;
  strncpy(join.req_channel, channel, CHANNEL_MAX);

  size_t message_size = sizeof(struct request_join);

  if (sendto(client_socket, &join, message_size, 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
    Error("client: failed to request join\n");
  }

  return 0;
}

// Splits strings around spaces.
std::vector<std::string> StringSplit(std::string input) {
  std::istringstream iss(input);
  std::vector<std::string> result{std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>{}};

  return result;
}

// Splits strings around spaces.
std::vector<std::string> SplitString(char *input, char delimiter) {
  std::vector<std::string> result;
  std::string word = "";

  size_t input_size = strlen(input);
  for (size_t i = 0; i < input_size; i++) {
    if (input[i] != delimiter) {
      word += input[i];
    } else {
      result.push_back(word);
      word = "";
    }
  }
  result.push_back(word);

  return result;
}

void StripChar(char *input, char c) {
  size_t size = strlen(input);
  for (size_t i = 0; i < size; i++) {
    if (input[i] == c) {
      input[i] = '\0';
    }
  }
}

// Processes the input string to decide what type of command it is.
bool ProcessInput(std::string input) {
  std::vector<std::string> inputs = StringSplit(input);
  bool result = true;

  if (inputs[0] == "/exit") {
    RequestLogout();
    cooked_mode();
    result = false;
  } else if (inputs[0] == "/list") {

  } else if (inputs[0] == "/join") {

  } else if (inputs[0] == "/leave") {

  } else if (inputs[0] == "/who") {

  } else if (inputs[0] == "/switch") {

  } else {
    std::cout << "\n*Unknown command" << std::endl;
  }

  return result;
}

void PrintPrompt() {
  std::cout << ">" << std::flush;
}

int main(int argc, char *argv[]) {
  char *domain;
  char *port_str;
  int port_num;
  char *username;
  char *input;
  char *output = (char *) "";
  char tmp_buffer[SAY_MAX];
  memset(&tmp_buffer, 0, SAY_MAX);

  char stdin_buffer[SAY_MAX + 1];
  char *stdin_buffer_position = stdin_buffer;

  fd_set read_set;
  int result;
  char receive_buffer[kBufferSize];
  memset(&receive_buffer, 0, kBufferSize);

  if (argc < 4) {
    Error("usage: client [server name] [port] [username]");
  }

  domain = argv[1];
  port_str = argv[2];
  port_num = atoi(argv[2]);
  username = argv[3];

  if (strlen(domain) > UNIX_PATH_MAX) {
    Error("client: server name must be less than 108 characters");
  }

  if (port_num < 0 || port_num > 65535) {
    Error("client: port number must be between 0 and 65535");
  }

  if (strlen(username) > USERNAME_MAX) {
    Error("client: username must be less than 32 characters");
  }

  Connect(domain, port_str);

  RequestLogin(username);

  channel = (char *) "Common";
  RequestJoin(channel);

  // TODO handle response from send

  if (raw_mode() != 0){
    Error("client: error using raw mode");
  }

  PrintPrompt();

  while (1) {
    FD_ZERO(&read_set);
    FD_SET(client_socket, &read_set);
    FD_SET(STDIN_FILENO, &read_set);

    if ((result = select(client_socket + 1, &read_set, NULL, NULL, NULL)) < 0) {
      Error("client: problem using select");
    }

    if (result > 0) {
      if (FD_ISSET(STDIN_FILENO, &read_set)) {
        char c = (char) getchar();
        if (c == '\n') {
          // Increments the stdin_buffer pointer's position and sets new position to the NULL char.
          *stdin_buffer_position++ = '\0';

          // Resets stdin_buffer_position to the original pointer position.
          stdin_buffer_position = stdin_buffer;

          printf("\n");
          fflush(stdout);

          // Prevents output from printing on the new prompt.
          output = (char *) "";

          input = stdin_buffer;
          if (input[0] == '/') {
            if (!ProcessInput(input)) {
              break;
            }
          } else {
            // Sends chat messages
            RequestSay(input);
          }
        } else if (stdin_buffer_position != stdin_buffer + SAY_MAX) {
          *stdin_buffer_position++ = c;
          printf("%c", c); // cout does not work
          fflush(stdout);

          // Creates output to use on the new prompt after receiving a server message.
          output = stdin_buffer_position;
          *output++ = '\0';
          output = stdin_buffer;
        }
      } else if (FD_ISSET(client_socket, &read_set)) {
        // Socket has data
        int read_size = read(client_socket, receive_buffer, kBufferSize);

        if (read_size != 0) {
          struct text message;
          memcpy(&message, receive_buffer, sizeof(struct text));
          text_t text_type = message.txt_type;

          switch (text_type) {
            case TXT_SAY:
              struct text_say say;
              memcpy(&say, receive_buffer, sizeof(struct text_say));
              std::cout << "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
              std::cout << "[" << say.txt_channel << "]" << "[" << say.txt_username << "]: " << say.txt_text << std::endl;
              PrintPrompt();
              std::cout << output << std::flush;
              break;
            default:
              break;
          }
        }

        memset(&receive_buffer, 0, SAY_MAX);
      } // end of if client_socket

    } // end of if result

  } // end of while

  return 0;
}<commit_msg>simply process input check<commit_after>#include <netdb.h>
#include <unistd.h>
#include <sys/fcntl.h>

#include "client.h"
#include "duckchat.h"
#include "raw.h"

// Variables
struct sockaddr_in client_addr;
struct sockaddr_in server_addr;
int client_socket;
struct addrinfo *server_info;
char *channel;

// Prints an error message and exits the program.
void Error(const char *msg) {
  std::cerr << msg << std::endl;
  exit(1);
}

// Connects to the server at a the given port.
void Connect(char *domain, const char *port) {
  std::cout << "Connecting to " << domain << std::endl;

  struct addrinfo hints;
  struct addrinfo *server_info_tmp;
  int status;

  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_DGRAM;
  hints.ai_protocol = 0;

  if ((status = getaddrinfo(domain, port, &hints, &server_info_tmp)) != 0) {
    std::cerr << "client: unable to resolve address: " << gai_strerror(status) << std::endl;
    exit(1);
  }

  // getaddrinfo() returns a list of address structures into server_info_tmp.
  // Try each address until we successfully connect().
  // If socket() (or connect()) fails, close the socket and try the next address.

  for (server_info = server_info_tmp; server_info != NULL; server_info = server_info->ai_next) {
    if ((client_socket = socket(server_info->ai_family, server_info->ai_socktype, server_info->ai_protocol)) < 0) {
      continue;
    }
    if (connect(client_socket, server_info->ai_addr, server_info->ai_addrlen) != -1) {
      fcntl(client_socket, F_SETFL, O_NONBLOCK);
      break; // Success
    }
    close(client_socket);
  }

  if (server_info == NULL) {
    Error("client: all sockets failed to connect");
  }
}

// Sends a message to all users in on the active channel.
int RequestSay(const char *message) {
  struct request_say say;
  memset(&say, 0, sizeof(say));
  say.req_type = REQ_SAY;
  strncpy(say.req_text, message, SAY_MAX);
  strncpy(say.req_channel, channel, CHANNEL_MAX);

  if (sendto(client_socket, &say, sizeof(say), 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
    Error("client: failed to send message\n");
  }

  return 0;
}

// Sends login requests to the server.
int RequestLogin(char *username) {
  struct request_login login;
  memset(&login, 0, sizeof(login));
  login.req_type = REQ_LOGIN;
  strncpy(login.req_username, username, USERNAME_MAX);

  size_t message_size = sizeof(struct request_login);

  if (sendto(client_socket, &login, message_size, 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
    Error("client: failed to request login\n");
  }

  return 0;
}

// Sends logout requests to the server.
int RequestLogout() {
  struct request_logout logout;
  memset((char *) &logout, 0, sizeof(logout));
  logout.req_type = REQ_LOGOUT;

  size_t message_size = sizeof(struct request_logout);

  if (sendto(client_socket, &logout, message_size, 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
    Error("client: failed to request logout\n");
  }

  return 0;
}

// Sends join requests to the server.
int RequestJoin(char *channel) {
  struct request_join join;
  memset((char *) &join, 0, sizeof(join));
  join.req_type = REQ_JOIN;
  strncpy(join.req_channel, channel, CHANNEL_MAX);

  size_t message_size = sizeof(struct request_join);

  if (sendto(client_socket, &join, message_size, 0, server_info->ai_addr, server_info->ai_addrlen) < 0) {
    Error("client: failed to request join\n");
  }

  return 0;
}

// Splits strings around spaces.
std::vector<std::string> StringSplit(std::string input) {
  std::istringstream iss(input);
  std::vector<std::string> result{std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>{}};

  return result;
}

// Splits strings around spaces.
std::vector<std::string> SplitString(char *input, char delimiter) {
  std::vector<std::string> result;
  std::string word = "";

  size_t input_size = strlen(input);
  for (size_t i = 0; i < input_size; i++) {
    if (input[i] != delimiter) {
      word += input[i];
    } else {
      result.push_back(word);
      word = "";
    }
  }
  result.push_back(word);

  return result;
}

void StripChar(char *input, char c) {
  size_t size = strlen(input);
  for (size_t i = 0; i < size; i++) {
    if (input[i] == c) {
      input[i] = '\0';
    }
  }
}

// Processes the input string to decide what type of command it is.
bool ProcessInput(std::string input) {
  std::vector<std::string> inputs = StringSplit(input);
  bool result = true;

  if (inputs[0] == "/exit") {
    RequestLogout();
    cooked_mode();
    result = false;
  } else if (inputs[0] == "/list") {

  } else if (inputs[0] == "/join") {

  } else if (inputs[0] == "/leave") {

  } else if (inputs[0] == "/who") {

  } else if (inputs[0] == "/switch") {

  } else {
    std::cout << "\n*Unknown command" << std::endl;
  }

  return result;
}

void PrintPrompt() {
  std::cout << ">" << std::flush;
}

int main(int argc, char *argv[]) {
  char *domain;
  char *port_str;
  int port_num;
  char *username;
  char *input;
  char *output = (char *) "";
  char tmp_buffer[SAY_MAX];
  memset(&tmp_buffer, 0, SAY_MAX);

  char stdin_buffer[SAY_MAX + 1];
  char *stdin_buffer_position = stdin_buffer;

  fd_set read_set;
  int result;
  char receive_buffer[kBufferSize];
  memset(&receive_buffer, 0, kBufferSize);

  if (argc < 4) {
    Error("usage: client [server name] [port] [username]");
  }

  domain = argv[1];
  port_str = argv[2];
  port_num = atoi(argv[2]);
  username = argv[3];

  if (strlen(domain) > UNIX_PATH_MAX) {
    Error("client: server name must be less than 108 characters");
  }

  if (port_num < 0 || port_num > 65535) {
    Error("client: port number must be between 0 and 65535");
  }

  if (strlen(username) > USERNAME_MAX) {
    Error("client: username must be less than 32 characters");
  }

  Connect(domain, port_str);

  RequestLogin(username);

  channel = (char *) "Common";
  RequestJoin(channel);

  if (raw_mode() != 0){
    Error("client: error using raw mode");
  }

  PrintPrompt();

  while (1) {
    FD_ZERO(&read_set);
    FD_SET(client_socket, &read_set);
    FD_SET(STDIN_FILENO, &read_set);

    if ((result = select(client_socket + 1, &read_set, NULL, NULL, NULL)) < 0) {
      Error("client: problem using select");
    }

    if (result > 0) {
      if (FD_ISSET(STDIN_FILENO, &read_set)) {
        char c = (char) getchar();
        if (c == '\n') {
          // Increments the stdin_buffer pointer's position and sets new position to the NULL char.
          *stdin_buffer_position++ = '\0';

          // Resets stdin_buffer_position to the original pointer position.
          stdin_buffer_position = stdin_buffer;

          printf("\n");
          fflush(stdout);

          // Prevents output from printing on the new prompt.
          output = (char *) "";

          input = stdin_buffer;
          if (input[0] == '/' && !ProcessInput(input)) {
            break;
          } else {
            // Sends chat messages
            RequestSay(input);
          }
        } else if (stdin_buffer_position != stdin_buffer + SAY_MAX) {
          *stdin_buffer_position++ = c;
          printf("%c", c); // cout does not work
          fflush(stdout);

          // Creates output to use on the new prompt after receiving a server message.
          output = stdin_buffer_position;
          *output++ = '\0';
          output = stdin_buffer;
        }
      } else if (FD_ISSET(client_socket, &read_set)) {
        // Socket has data
        int read_size = read(client_socket, receive_buffer, kBufferSize);

        if (read_size != 0) {
          struct text message;
          memcpy(&message, receive_buffer, sizeof(struct text));
          text_t text_type = message.txt_type;

          switch (text_type) {
            case TXT_SAY:
              struct text_say say;
              memcpy(&say, receive_buffer, sizeof(struct text_say));
              std::cout << "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
              std::cout << "[" << say.txt_channel << "]" << "[" << say.txt_username << "]: " << say.txt_text << std::endl;
              PrintPrompt();
              std::cout << output << std::flush;
              break;
            default:
              break;
          }
        }

        memset(&receive_buffer, 0, SAY_MAX);
      } // end of if client_socket

    } // end of if result

  } // end of while

  return 0;
}<|endoftext|>


<commit_before>/* gobby - A GTKmm driven libobby client
 * Copyright (C) 2005 0x539 dev group
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <gtkmm/stock.h>
#include "common.hpp"
#include "chat.hpp"

Gobby::Chat::Chat()
 : Gtk::VBox(), m_img_btn(Gtk::Stock::JUMP_TO, Gtk::ICON_SIZE_BUTTON)
{
	m_btn_chat.set_label(_("Send"));
	m_btn_chat.set_image(m_img_btn);

	m_btn_chat.set_size_request(100, -1);
	m_btn_chat.signal_clicked().connect(
		sigc::mem_fun(*this, &Chat::on_chat) );
	m_ent_chat.signal_activate().connect(
		sigc::mem_fun(*this, &Chat::on_chat) );

	m_wnd_chat.add(m_log_chat);
	m_wnd_chat.set_shadow_type(Gtk::SHADOW_IN);
	m_wnd_chat.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

	m_box_chat.pack_start(m_ent_chat, Gtk::PACK_EXPAND_WIDGET);
	m_box_chat.pack_start(m_btn_chat, Gtk::PACK_SHRINK);

	m_box_chat.set_spacing(5);

	pack_start(m_wnd_chat, Gtk::PACK_EXPAND_WIDGET);
	pack_start(m_box_chat, Gtk::PACK_SHRINK);

	set_spacing(5);
	set_sensitive(false);
}

Gobby::Chat::~Chat()
{
}

Gobby::Chat::signal_chat_type Gobby::Chat::chat_event() const
{
	return m_signal_chat;
}

void Gobby::Chat::obby_start()
{
	m_log_chat.clear();
	m_ent_chat.set_sensitive(true);
	m_btn_chat.set_sensitive(true);

	set_sensitive(true);
}

void Gobby::Chat::obby_end()
{
	m_ent_chat.clear_history();
	m_ent_chat.set_sensitive(false);
	m_btn_chat.set_sensitive(false);
}

void Gobby::Chat::obby_user_join(obby::user& user)
{
	m_log_chat.log(user.get_name() + " has joined", "blue");
}

void Gobby::Chat::obby_user_part(obby::user& user)
{
	m_log_chat.log(user.get_name() + " has left", "blue");
}

void Gobby::Chat::obby_document_insert(obby::document& document)
{
}

void Gobby::Chat::obby_document_remove(obby::document& document)
{
}

void Gobby::Chat::obby_message(obby::user& user, const Glib::ustring& message)
{
	// Make sure we are not deceived by rogue multi line messages
	Glib::ustring::size_type prev = 0, pos = 0;
	while( (pos = message.find('\n', pos)) != Glib::ustring::npos)
	{
		add_line(user, message.substr(prev, pos - prev) );
		prev = ++pos;
	}
}

void Gobby::Chat::add_line(obby::user& user, const Glib::ustring& message)
{
	m_log_chat.log("<" + user.get_name() + "> " + message, "black");
}

void Gobby::Chat::obby_server_message(const Glib::ustring& message)
{
	m_log_chat.log(message, "forest green");
}

void Gobby::Chat::on_chat()
{
	Glib::ustring message = m_ent_chat.get_text();
	if(message.empty() ) return;
	m_ent_chat.set_text("");

	// Send each line separately
	Glib::ustring::size_type prev = 0, pos = 0;
	while( (pos = message.find('\n', pos)) != Glib::ustring::npos)
	{
		m_signal_chat.emit(message.substr(prev, pos - prev) );
		prev = ++pos;
	}
	m_signal_chat.emit(message.substr(prev) );

	m_signal_chat.emit(message);
}

<commit_msg>[project @ Fixed my messup fixing the chat multiline handling]<commit_after>/* gobby - A GTKmm driven libobby client
 * Copyright (C) 2005 0x539 dev group
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <gtkmm/stock.h>
#include "common.hpp"
#include "chat.hpp"

Gobby::Chat::Chat()
 : Gtk::VBox(), m_img_btn(Gtk::Stock::JUMP_TO, Gtk::ICON_SIZE_BUTTON)
{
	m_btn_chat.set_label(_("Send"));
	m_btn_chat.set_image(m_img_btn);

	m_btn_chat.set_size_request(100, -1);
	m_btn_chat.signal_clicked().connect(
		sigc::mem_fun(*this, &Chat::on_chat) );
	m_ent_chat.signal_activate().connect(
		sigc::mem_fun(*this, &Chat::on_chat) );

	m_wnd_chat.add(m_log_chat);
	m_wnd_chat.set_shadow_type(Gtk::SHADOW_IN);
	m_wnd_chat.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

	m_box_chat.pack_start(m_ent_chat, Gtk::PACK_EXPAND_WIDGET);
	m_box_chat.pack_start(m_btn_chat, Gtk::PACK_SHRINK);

	m_box_chat.set_spacing(5);

	pack_start(m_wnd_chat, Gtk::PACK_EXPAND_WIDGET);
	pack_start(m_box_chat, Gtk::PACK_SHRINK);

	set_spacing(5);
	set_sensitive(false);
}

Gobby::Chat::~Chat()
{
}

Gobby::Chat::signal_chat_type Gobby::Chat::chat_event() const
{
	return m_signal_chat;
}

void Gobby::Chat::obby_start()
{
	m_log_chat.clear();
	m_ent_chat.set_sensitive(true);
	m_btn_chat.set_sensitive(true);

	set_sensitive(true);
}

void Gobby::Chat::obby_end()
{
	m_ent_chat.clear_history();
	m_ent_chat.set_sensitive(false);
	m_btn_chat.set_sensitive(false);
}

void Gobby::Chat::obby_user_join(obby::user& user)
{
	m_log_chat.log(user.get_name() + " has joined", "blue");
}

void Gobby::Chat::obby_user_part(obby::user& user)
{
	m_log_chat.log(user.get_name() + " has left", "blue");
}

void Gobby::Chat::obby_document_insert(obby::document& document)
{
}

void Gobby::Chat::obby_document_remove(obby::document& document)
{
}

void Gobby::Chat::obby_message(obby::user& user, const Glib::ustring& message)
{
	// Make sure we are not deceived by rogue multi line messages
	Glib::ustring::size_type prev = 0, pos = 0;
	while( (pos = message.find('\n', pos)) != Glib::ustring::npos)
	{
		add_line(user, message.substr(prev, pos - prev) );
		prev = ++pos;
	}
	add_line(user, message.substr(prev));
}

void Gobby::Chat::add_line(obby::user& user, const Glib::ustring& message)
{
	m_log_chat.log("<" + user.get_name() + "> " + message, "black");
}

void Gobby::Chat::obby_server_message(const Glib::ustring& message)
{
	m_log_chat.log(message, "forest green");
}

void Gobby::Chat::on_chat()
{
	Glib::ustring message = m_ent_chat.get_text();
	if(message.empty() ) return;
	m_ent_chat.set_text("");

	// Send each line separately
	Glib::ustring::size_type prev = 0, pos = 0;
	while( (pos = message.find('\n', pos)) != Glib::ustring::npos)
	{
		m_signal_chat.emit(message.substr(prev, pos - prev) );
		prev = ++pos;
	}
	m_signal_chat.emit(message.substr(prev) );
}

<|endoftext|>


<commit_before>/*!
 * \file debug.cc
 *
 * \brief Some debugging tools for BPEL2oWFN
 *
 * \author
 *          - responsible: Christian Gierds <gierds@informatik.hu-berlin.de>
 *          - last changes of: \$Author: gierds $
 *
 * \date
 *          - created: 2005/11/09
 *          - last changed: \$Date: 2005/11/30 14:45:54 $
 *
 * \note    This file is part of the tool BPEL2oWFN and was created during the
 *          project "Tools4BPEL" at the Humboldt-Universitt zu Berlin. See
 *          http://www.informatik.hu-berlin.de/top/forschung/projekte/tools4bpel
 *          for details.
 *
 * \version \$Revision: 1.8 $
 *          - 2005-11-09 (gierds) Initial release.
 *            Simple trace methods and new place for yyerror().
 *          - 2005-11-20 (nlohmann) Overworked and commented yyerror().
 *
 */

#include "debug.h"

/// debug level
int debug_level = 0;

/**
 * Provides output to stderr using different #trace_level
 * (in order to regulate amount of output)
 *
 * \param pTraceLevel	the #trace_level
 * \param message	the output
 *
 */
void trace(trace_level pTraceLevel, std::string message)
{
  if (pTraceLevel <= debug_level)
  {
    std::cerr << message << std::flush;
  }
}

/**
 * Works like #trace(trace_level,std::string) with trace_level = TRACE_ALWAYS
 *
 * \param message the output
 *
 */
void trace(std::string message )
{
  trace(TRACE_ALWAYS, message);
}

/*!
 * This function is invoked by the parser and the lexer during the syntax
 * analysis. When an error occurs, it prints an accordant message and shows the
 * lines of the input files where the error occured.
 *
 * \param msg a message (mostly "Parse error") and some more information e.g.
 *            the location of the syntax error.
 * \return 1, since an error occured
 */
int yyerror(const char* msg)
{
  /* defined by flex */
  extern int yylineno;      ///< line number of current token
  extern char *yytext;      ///< text of the current token

  trace("Error while parsing!\n\n");
  trace(msg);
  trace("\n");

  // display passed error message
  trace("Error in '" + filename + "' in line ");
  trace(intToString(yylineno));
  trace(":\n");
  trace("  token/text last read was '");
  trace(yytext);
  trace("'\n\n");

  if (filename != "<STDIN>")
  {
    trace("-------------------------------------------------------------------------------\n");

    // number of lines to print before and after errorneous line
    int environment = 4;

    unsigned int firstShowedLine = ((yylineno-environment)>0)?(yylineno-environment):1;

    std::ifstream inputFile(filename.c_str());
    std::string errorLine;
    for (unsigned int i=0; i<firstShowedLine; i++)
    {
      trace(".");
      getline(inputFile, errorLine);
    }
    // print the erroneous line (plus/minus three more)
    for (unsigned int i=firstShowedLine; i<=firstShowedLine+(2*environment); i++)
    {
      trace(intToString(i) + ": " + errorLine + "\n");
      getline(inputFile, errorLine);
      if (inputFile.eof())
	break;
    }
    inputFile.close();

    trace("-------------------------------------------------------------------------------\n");
  }

  error();
  return 1;
}
<commit_msg>+ minor changes<commit_after>/*!
 * \file debug.cc
 *
 * \brief Some debugging tools for BPEL2oWFN
 *
 * \author
 *          - responsible: Christian Gierds <gierds@informatik.hu-berlin.de>
 *          - last changes of: \$Author: gierds $
 *
 * \date
 *          - created: 2005/11/09
 *          - last changed: \$Date: 2005/11/30 14:47:07 $
 *
 * \note    This file is part of the tool BPEL2oWFN and was created during the
 *          project "Tools4BPEL" at the Humboldt-Universitt zu Berlin. See
 *          http://www.informatik.hu-berlin.de/top/forschung/projekte/tools4bpel
 *          for details.
 *
 * \version \$Revision: 1.9 $
 *          - 2005-11-09 (gierds) Initial release.
 *            Simple trace methods and new place for yyerror().
 *          - 2005-11-20 (nlohmann) Overworked and commented yyerror().
 *
 */

#include "debug.h"

/// debug level
int debug_level = 0;

/**
 * Provides output to stderr using different #trace_level
 * (in order to regulate amount of output)
 *
 * \param pTraceLevel	the #trace_level
 * \param message	the output
 *
 */
void trace(trace_level pTraceLevel, std::string message)
{
  if (pTraceLevel <= debug_level)
  {
    std::cerr << message << std::flush;
  }
}

/**
 * Works like #trace(trace_level,std::string) with trace_level = TRACE_ALWAYS
 *
 * \param message the output
 *
 */
void trace(std::string message )
{
  trace(TRACE_ALWAYS, message);
}

/*!
 * This function is invoked by the parser and the lexer during the syntax
 * analysis. When an error occurs, it prints an accordant message and shows the
 * lines of the input files where the error occured.
 *
 * \param msg a message (mostly "Parse error") and some more information e.g.
 *            the location of the syntax error.
 * \return 1, since an error occured
 */
int yyerror(const char* msg)
{
  /* defined by flex */
  extern int yylineno;      ///< line number of current token
  extern char *yytext;      ///< text of the current token

  trace("Error while parsing!\n\n");
  trace(msg);
  trace("\n");

  // display passed error message
  trace("Error in '" + filename + "' in line ");
  trace(intToString(yylineno));
  trace(":\n");
  trace("  token/text last read was '");
  trace(yytext);
  trace("'\n\n");

  if (filename != "<STDIN>")
  {
    trace("-------------------------------------------------------------------------------\n");

    // number of lines to print before and after errorneous line
    int environment = 4;

    unsigned int firstShowedLine = ((yylineno-environment)>0)?(yylineno-environment):1;

    std::ifstream inputFile(filename.c_str());
    std::string errorLine;
    for (unsigned int i=0; i<firstShowedLine; i++)
    {
      getline(inputFile, errorLine);
    }
    // print the erroneous line (plus/minus three more)
    for (unsigned int i=firstShowedLine; i<=firstShowedLine+(2*environment); i++)
    {
      trace(intToString(i) + ": " + errorLine + "\n");
      getline(inputFile, errorLine);
      if (inputFile.eof())
	break;
    }
    inputFile.close();

    trace("-------------------------------------------------------------------------------\n");
  }

  error();
  return 1;
}
<|endoftext|>


<commit_before>#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <iohub_client.h>
#include <mug.h>
#include <res_manager.h>

#ifndef USE_IOHUB
#include <io.h>
#endif

struct __attribute__((packed)) led_line_data {
  uint8_t row;
  uint8_t reserved[2];
  uint8_t content[MAX_COLS/2];
};

mug_error_t mug_disp_raw(handle_t handle, char* imgData)
{
  int row, col;
  char *p = imgData;
  mug_error_t err = MUG_ERROR_NONE;

  struct led_line_data data = {
    0, {0xff, 0xff}, {0}
  };

  for(row = 0; row < MAX_COMPRESSED_ROWS; row++) {

    // pack the data
    data.row = row;
    memcpy(&(data.content), p, MAX_COMPRESSED_COLS);

    // send to iohub
#ifdef USE_IOHUB
    err = iohub_send_command(handle, IOHUB_CMD_FB, (char*)&data, sizeof(data));
#else
    err = dev_send_command(handle, IOHUB_CMD_FB, (char*)&data, sizeof(data));
#endif

    if(err != ERROR_NONE) {
      MUG_ASSERT(0, "iohub_send_command error: %d\n", err);
      return err;
    }

    // go to the next row
    p += MAX_COMPRESSED_COLS;
  }

  return err;
}

mug_error_t mug_disp_raw_N(handle_t handle, char* imgData, int number, int interval)
{
  int semResource = resource_init(LOCK_DISPLAY_TOUCH);
  char *p = imgData;
  mug_error_t error = ERROR_NONE;
  int i;
  resource_wait(semResource);
  for(i = 0; i < number; i++) {
    error = mug_disp_raw(handle, p);

    if(error != ERROR_NONE) {
      printf("C program, disp page error!\n");
      fflush(NULL);
      resource_post(semResource);
      return error;
    }
    p += COMPRESSED_SIZE;
    usleep(interval * 1000);
  }
  resource_post(semResource);

  return error;
}

handle_t mug_init(device_t type)
{
#ifdef USE_IOHUB
  handle_t handle = iohub_open_session(type);
#else
  handle_t handle = dev_open(type);
#endif
  return handle;
}

void mug_close(handle_t handle)
{
#ifdef USE_IOHUB
  iohub_close_session(handle);
#else
  dev_close(handle);
#endif
}

handle_t mug_disp_init()
{
  return mug_init(DEVICE_LED);
}
<commit_msg>filter two continuous same image from one process<commit_after>#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <iohub_client.h>
#include <mug.h>
#include <res_manager.h>

#ifndef USE_IOHUB
#include <io.h>
#endif

struct __attribute__((packed)) led_line_data {
  uint8_t row;
  uint8_t reserved[2];
  uint8_t content[MAX_COLS/2];
};

mug_error_t mug_disp_raw(handle_t handle, char* imgData)
{
  int row, col;
  char *p = imgData;
  mug_error_t err = MUG_ERROR_NONE;

  struct led_line_data data = {
    0, {0xff, 0xff}, {0}
  };

  for(row = 0; row < MAX_COMPRESSED_ROWS; row++) {

    // pack the data
    data.row = row;
    memcpy(&(data.content), p, MAX_COMPRESSED_COLS);

    // send to iohub
#ifdef USE_IOHUB
    err = iohub_send_command(handle, IOHUB_CMD_FB, (char*)&data, sizeof(data));
#else
    err = dev_send_command(handle, IOHUB_CMD_FB, (char*)&data, sizeof(data));
#endif

    if(err != ERROR_NONE) {
      MUG_ASSERT(0, "iohub_send_command error: %d\n", err);
      return err;
    }

    // go to the next row
    p += MAX_COMPRESSED_COLS;
  }

  return err;
}

char lastImg[COMPRESSED_SIZE];
mug_error_t mug_disp_raw_N(handle_t handle, char* imgData, int number, int interval)
{
  int semResource = resource_init(LOCK_DISPLAY_TOUCH);
  char *p = imgData;
  mug_error_t error = ERROR_NONE;
  int i;
  resource_wait(semResource);
  for(i = 0; i < number; i++) {
    int isDiff = memcmp(lastImg, p, COMPRESSED_SIZE);
    if (isDiff == 0) {
      p += COMPRESSED_SIZE;
      usleep(interval * 1000);
      continue;
    } else {
      memcpy(lastImg, p, COMPRESSED_SIZE);
    }

    error = mug_disp_raw(handle, p);

    if(error != ERROR_NONE) {
      printf("C program, disp page error!\n");
      fflush(NULL);
      resource_post(semResource);
      return error;
    }
    p += COMPRESSED_SIZE;
    usleep(interval * 1000);
  }
  resource_post(semResource);

  return error;
}

handle_t mug_init(device_t type)
{
#ifdef USE_IOHUB
  handle_t handle = iohub_open_session(type);
#else
  handle_t handle = dev_open(type);
#endif
  return handle;
}

void mug_close(handle_t handle)
{
#ifdef USE_IOHUB
  iohub_close_session(handle);
#else
  dev_close(handle);
#endif
}

handle_t mug_disp_init()
{
  return mug_init(DEVICE_LED);
}
<|endoftext|>