<commit_before>/**
 * @file loger.cpp
 *
 * @brief implementation main
 *
 * @author Matus Blaho
 * @version 1.0
 */

#include "loger.h"
#include "config.h"
#include "connectionHandler.h"
#include "adaServerSender.h"
#include "adaServerReceiver.h"
#include <termios.h>
#include <Poco/Exception.h>

using namespace Poco;

Config *c;

WorkerPool *wpool = NULL;
sem_t connectionSem;
std::atomic<unsigned long> connCount;
AdaServerReceiver *receiver;
AdaServerSender *sender;
std::thread *SenderThread;
Loger *SenderLog;
Loger *ReceiverLog;
bool sigint =false;
SSLContainer *sslCont;

static pthread_mutex_t *lockarray;

static void lock_callback(int mode, int type, char *file, int line)
{
	(void)file;
	(void)line;
	if (mode & CRYPTO_LOCK) {
		pthread_mutex_lock(&(lockarray[type]));
	}
	else {
		pthread_mutex_unlock(&(lockarray[type]));
	}
}

static unsigned long thread_id(void)
{
	unsigned long ret;

	ret=(unsigned long)pthread_self();
	return(ret);
}

static void init_locks(void)
{
	int i;

	lockarray=(pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() *
												sizeof(pthread_mutex_t));
	for (i=0; i<CRYPTO_num_locks(); i++) {
		pthread_mutex_init(&(lockarray[i]),NULL);
	}

	CRYPTO_set_id_callback((unsigned long (*)())thread_id);
	CRYPTO_set_locking_callback((void (*)(int, int, const char*, int))lock_callback);
}

static void kill_locks(void)
{
	int i;

	CRYPTO_set_locking_callback(NULL);
	for (i=0; i<CRYPTO_num_locks(); i++)
		pthread_mutex_destroy(&(lockarray[i]));

	OPENSSL_free(lockarray);
}

void sig_handler(int signo) //on signals to turn of clear
{
	if ((signo == SIGINT)||(signo == SIGTERM))
	{
		sigint = true;
		receiver->LogINT();
		sender->LogINT();
		delete (sslCont);
		delete (c);
		delete (wpool);
		delete (sender);
		delete (receiver);
		sem_destroy(&connectionSem);
		delete (SenderThread);
		delete (SenderLog);
		delete (ReceiverLog);
		kill_locks();
		ERR_remove_state(0);
		ERR_free_strings();
		EVP_cleanup();
		CRYPTO_cleanup_all_ex_data();
	}
	exit(EXIT_SUCCESS);
}

std::string buildConnString(std::string DBName, std::string User, std::string Password) //building connection string to database
{
	std::string result;
	result.clear();
	if(DBName.empty())
	{
		return ("");
	}
	if (User.empty())
	{
		return ("dbname=" + DBName);
	}
	if (Password.empty())
	{
		std::cout<<"Enter password for user :"<<User<<std::endl;
		struct termios tty;
		tcgetattr(STDIN_FILENO, &tty);
		tty.c_lflag &= ~ECHO;
		(void) tcsetattr(STDIN_FILENO, TCSANOW, &tty);
		std::cin>>Password;
		tcgetattr(STDIN_FILENO, &tty);
		tty.c_lflag |= ECHO;
		(void) tcsetattr(STDIN_FILENO, TCSANOW, &tty);
		std::cout<<"Password readed"<<std::endl;
		result = "dbname="+ DBName + " user=" + User + " password=" + Password;
		return (result);
	}
	result = "dbname="+ DBName + " user=" + User + " password=" + Password;
	return(result);
}

int main(int argc, char **argv)  //main body of application
{
	if (argc < 2) {
		std::cerr<<"Path to configuration file was not given."<<std::endl;
		exit(EXIT_FAILURE);
	}

	pid_t pid, sid;
	std::cout<<"Reading configuration"<<std::endl;
	c = new Config();

	try {
		c->setConfig(argv[1]);
	} catch(Exception &e) {
		std::cerr << e.displayText() << std::endl;
		std::cerr << "Failed to parse configuration" << std::endl;
		delete c;
		return EXIT_FAILURE;
	}
	std::string connStr = buildConnString(c->DBName(),c->User(),c->Password());
	/* Fork off the parent process */
	if (c->Mode()!=0)  //start as deamon
	{
		std::cout<<"Starting deamonization"<<std::endl;
		pid = fork();
		if (pid < 0)
		{
				std::cerr<<"Deamonzation failed! Running in teminal mode."<<std::endl;
		}
		else
		{
		/* If we got a good PID, then
		   we can exit the parent process. */
			if (pid > 0)
			{
				delete(c);
				exit(EXIT_SUCCESS);
			}

			/* Change the file mode mask */
			umask(0);

			/* Open any logs here */

			/* Create a new SID for the child process */
			sid = setsid();
			if (sid < 0) {
					/* Log the failure */
					exit(EXIT_FAILURE);
			}
			int proces_id=getpid();
			//std::cout<<"Creating stop script in current directory"<<std::endl;
			std::ofstream stopSCR;
			stopSCR.open("stop_ada_server.sh", std::ios::out|std::ios::trunc);
			stopSCR<<"kill -SIGINT "<<proces_id<<std::endl;
			stopSCR.close();
			/* Change the current working directory */
			if ((chdir("/")) < 0)
			{
					/* Log the failure */
					exit(EXIT_FAILURE);
			}
			//std::cout<<"Finishing deamonization"<<std::endl;
			/* Close out the standard file descriptors */
			close(STDIN_FILENO);
			close(STDOUT_FILENO);
			close(STDERR_FILENO);
		}
	}
	else
	{
		std::cout<<"Server started in terminal(debug) mode"<<std::endl;
		int proces_id=getpid();
		//std::cout<<"Creating stop script in current directory"<<std::endl;
		std::ofstream stopSCR;
		stopSCR.open("stop_ada_server.sh", std::ios::out|std::ios::trunc);
		stopSCR<<"kill -SIGINT "<<proces_id<<std::endl;
		stopSCR.close();
	}
	SSL_load_error_strings();
	SSL_library_init();
	OpenSSL_add_all_algorithms();
	SenderLog = new Loger();
	ReceiverLog = new Loger();
	SenderLog->SetLogger(c->SenderVerbosity(),c->SenderMaxFiles(),c->SenderMaxLines(),c->SenderFileNaming(),c->SenderPath(),"SENDER",c->SenderToSTD());
	ReceiverLog->SetLogger(c->ReceiverVerbosity(),c->ReceiverMaxFiles(),c->ReceiverMaxLines(),c->ReceiverFileNaming(),c->SenderPath(),"RECEIVER",c->ReceiverToSTD());
	if (signal(SIGINT, sig_handler) == SIG_ERR)
	{
		SenderLog->WriteMessage(ERR," [Main Process] Unable to catch SIGINT");
	}
	if (signal(SIGTERM, sig_handler) == SIG_ERR)
	{
		SenderLog->WriteMessage(ERR," [Main Process] Unable to catch SIGTERM");
	}
	if (signal(SIGHUP, SIG_IGN) == SIG_ERR)
	{
		SenderLog->WriteMessage(ERR," [Main Process] Unable to mask SIGHUP");
	}
	if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
	{
		SenderLog->WriteMessage(ERR," [Main Process] Unable to mask SIGPIPE");
	}
	sslCont = new SSLContainer(ReceiverLog);
	wpool = WorkerPool::CreatePool(ReceiverLog,SenderLog,connStr,c,sslCont);
	init_locks();
	if ((wpool==NULL)||(wpool->Limit()<=0))
	{
		SenderLog->WriteMessage(FATAL," [Main Process] 0 connections to DB unable to serve, terminating!");
		delete (c);
		delete wpool;
		delete SenderLog;
		delete ReceiverLog;
		exit(EXIT_FAILURE);
	}
	else
	{
		int semVal = wpool->Limit();
		SenderLog->WriteMessage(INFO,"[Main Process] Maximal connection count : " + std::to_string(semVal));
		ReceiverLog->WriteMessage(INFO,"[Main Process] Maximal connection count : " + std::to_string(semVal));
		sem_init(&connectionSem,0,semVal);
		wpool->SetSemaphore(&connectionSem);
		SenderLog->WriteMessage(TRACE,"[Main Process] Creating Sender");
		ReceiverLog->WriteMessage(TRACE,"[Main Process] Creating Sender");
		sender = new AdaServerSender(&connectionSem,wpool,SenderLog,c);
		SenderLog->WriteMessage(TRACE,"[Main Process] Creating Receiver");
		ReceiverLog->WriteMessage(TRACE,"[Main Process] Creating Receiver");
		receiver = new AdaServerReceiver(&connectionSem,wpool,ReceiverLog,c);
		SenderLog->WriteMessage(INFO,"[Main Process] Starting Sender");
		ReceiverLog->WriteMessage(INFO,"[Main Process] Starting Sender");
		SenderThread = new std::thread( [ ] { sender->Start(); });
		SenderThread->detach();
		ReceiverLog->WriteMessage(INFO,"[Main Process] Starting Receiver");
		SenderLog->WriteMessage(INFO,"[Main Process] Starting Receiver");
		receiver->Start();
	}
	if (!sigint)
	{
		delete (c);
		delete (wpool);
		delete (sender);
		delete (receiver);
		CRYPTO_cleanup_all_ex_data();
		kill_locks();
		ERR_remove_state(0);
		ERR_free_strings();
		EVP_cleanup();
		sem_destroy(&connectionSem);
		delete (SenderThread);
		delete (SenderLog);
		delete (ReceiverLog);
		exit(EXIT_FAILURE);
	}
	return (0);
}

<commit_msg>ada_server: extract function startDaemon<commit_after>/**
 * @file loger.cpp
 *
 * @brief implementation main
 *
 * @author Matus Blaho
 * @version 1.0
 */

#include "loger.h"
#include "config.h"
#include "connectionHandler.h"
#include "adaServerSender.h"
#include "adaServerReceiver.h"
#include <termios.h>
#include <Poco/Exception.h>

using namespace Poco;

Config *c;

WorkerPool *wpool = NULL;
sem_t connectionSem;
std::atomic<unsigned long> connCount;
AdaServerReceiver *receiver;
AdaServerSender *sender;
std::thread *SenderThread;
Loger *SenderLog;
Loger *ReceiverLog;
bool sigint =false;
SSLContainer *sslCont;

static pthread_mutex_t *lockarray;

static void lock_callback(int mode, int type, char *file, int line)
{
	(void)file;
	(void)line;
	if (mode & CRYPTO_LOCK) {
		pthread_mutex_lock(&(lockarray[type]));
	}
	else {
		pthread_mutex_unlock(&(lockarray[type]));
	}
}

static unsigned long thread_id(void)
{
	unsigned long ret;

	ret=(unsigned long)pthread_self();
	return(ret);
}

static void init_locks(void)
{
	int i;

	lockarray=(pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() *
												sizeof(pthread_mutex_t));
	for (i=0; i<CRYPTO_num_locks(); i++) {
		pthread_mutex_init(&(lockarray[i]),NULL);
	}

	CRYPTO_set_id_callback((unsigned long (*)())thread_id);
	CRYPTO_set_locking_callback((void (*)(int, int, const char*, int))lock_callback);
}

static void kill_locks(void)
{
	int i;

	CRYPTO_set_locking_callback(NULL);
	for (i=0; i<CRYPTO_num_locks(); i++)
		pthread_mutex_destroy(&(lockarray[i]));

	OPENSSL_free(lockarray);
}

void sig_handler(int signo) //on signals to turn of clear
{
	if ((signo == SIGINT)||(signo == SIGTERM))
	{
		sigint = true;
		receiver->LogINT();
		sender->LogINT();
		delete (sslCont);
		delete (c);
		delete (wpool);
		delete (sender);
		delete (receiver);
		sem_destroy(&connectionSem);
		delete (SenderThread);
		delete (SenderLog);
		delete (ReceiverLog);
		kill_locks();
		ERR_remove_state(0);
		ERR_free_strings();
		EVP_cleanup();
		CRYPTO_cleanup_all_ex_data();
	}
	exit(EXIT_SUCCESS);
}

std::string buildConnString(std::string DBName, std::string User, std::string Password) //building connection string to database
{
	std::string result;
	result.clear();
	if(DBName.empty())
	{
		return ("");
	}
	if (User.empty())
	{
		return ("dbname=" + DBName);
	}
	if (Password.empty())
	{
		std::cout<<"Enter password for user :"<<User<<std::endl;
		struct termios tty;
		tcgetattr(STDIN_FILENO, &tty);
		tty.c_lflag &= ~ECHO;
		(void) tcsetattr(STDIN_FILENO, TCSANOW, &tty);
		std::cin>>Password;
		tcgetattr(STDIN_FILENO, &tty);
		tty.c_lflag |= ECHO;
		(void) tcsetattr(STDIN_FILENO, TCSANOW, &tty);
		std::cout<<"Password readed"<<std::endl;
		result = "dbname="+ DBName + " user=" + User + " password=" + Password;
		return (result);
	}
	result = "dbname="+ DBName + " user=" + User + " password=" + Password;
	return(result);
}

static void startDaemon(void)
{
	pid_t pid, sid;

	std::cout<<"Starting deamonization"<<std::endl;
	pid = fork();
	if (pid < 0) {
		std::cerr<<"Deamonzation failed! Running in teminal mode."<<std::endl;
	} else {
		/* If we got a good PID, then
		   we can exit the parent process. */
		if (pid > 0) {
			delete(c);
			exit(EXIT_SUCCESS);
		}

		/* Change the file mode mask */
		umask(0);

		/* Open any logs here */

		/* Create a new SID for the child process */
		sid = setsid();
		if (sid < 0) {
			/* Log the failure */
			exit(EXIT_FAILURE);
		}

		int proces_id = getpid();
		//std::cout<<"Creating stop script in current directory"<<std::endl;
		std::ofstream stopSCR;
		stopSCR.open("stop_ada_server.sh", std::ios::out|std::ios::trunc);
		stopSCR<<"kill -SIGINT "<<proces_id<<std::endl;
		stopSCR.close();

		/* Change the current working directory */
		if ((chdir("/")) < 0) {
			/* Log the failure */
			exit(EXIT_FAILURE);
		}
		//std::cout<<"Finishing deamonization"<<std::endl;
		/* Close out the standard file descriptors */
		close(STDIN_FILENO);
		close(STDOUT_FILENO);
		close(STDERR_FILENO);
	}
}

int main(int argc, char **argv)  //main body of application
{
	if (argc < 2) {
		std::cerr<<"Path to configuration file was not given."<<std::endl;
		exit(EXIT_FAILURE);
	}

	std::cout<<"Reading configuration"<<std::endl;
	c = new Config();

	try {
		c->setConfig(argv[1]);
	} catch(Exception &e) {
		std::cerr << e.displayText() << std::endl;
		std::cerr << "Failed to parse configuration" << std::endl;
		delete c;
		return EXIT_FAILURE;
	}
	std::string connStr = buildConnString(c->DBName(),c->User(),c->Password());
	/* Fork off the parent process */
	if (c->Mode()!=0)  //start as deamon
	{
		startDaemon();
	}
	else
	{
		std::cout<<"Server started in terminal(debug) mode"<<std::endl;
		int proces_id=getpid();
		//std::cout<<"Creating stop script in current directory"<<std::endl;
		std::ofstream stopSCR;
		stopSCR.open("stop_ada_server.sh", std::ios::out|std::ios::trunc);
		stopSCR<<"kill -SIGINT "<<proces_id<<std::endl;
		stopSCR.close();
	}
	SSL_load_error_strings();
	SSL_library_init();
	OpenSSL_add_all_algorithms();
	SenderLog = new Loger();
	ReceiverLog = new Loger();
	SenderLog->SetLogger(c->SenderVerbosity(),c->SenderMaxFiles(),c->SenderMaxLines(),c->SenderFileNaming(),c->SenderPath(),"SENDER",c->SenderToSTD());
	ReceiverLog->SetLogger(c->ReceiverVerbosity(),c->ReceiverMaxFiles(),c->ReceiverMaxLines(),c->ReceiverFileNaming(),c->SenderPath(),"RECEIVER",c->ReceiverToSTD());
	if (signal(SIGINT, sig_handler) == SIG_ERR)
	{
		SenderLog->WriteMessage(ERR," [Main Process] Unable to catch SIGINT");
	}
	if (signal(SIGTERM, sig_handler) == SIG_ERR)
	{
		SenderLog->WriteMessage(ERR," [Main Process] Unable to catch SIGTERM");
	}
	if (signal(SIGHUP, SIG_IGN) == SIG_ERR)
	{
		SenderLog->WriteMessage(ERR," [Main Process] Unable to mask SIGHUP");
	}
	if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
	{
		SenderLog->WriteMessage(ERR," [Main Process] Unable to mask SIGPIPE");
	}
	sslCont = new SSLContainer(ReceiverLog);
	wpool = WorkerPool::CreatePool(ReceiverLog,SenderLog,connStr,c,sslCont);
	init_locks();
	if ((wpool==NULL)||(wpool->Limit()<=0))
	{
		SenderLog->WriteMessage(FATAL," [Main Process] 0 connections to DB unable to serve, terminating!");
		delete (c);
		delete wpool;
		delete SenderLog;
		delete ReceiverLog;
		exit(EXIT_FAILURE);
	}
	else
	{
		int semVal = wpool->Limit();
		SenderLog->WriteMessage(INFO,"[Main Process] Maximal connection count : " + std::to_string(semVal));
		ReceiverLog->WriteMessage(INFO,"[Main Process] Maximal connection count : " + std::to_string(semVal));
		sem_init(&connectionSem,0,semVal);
		wpool->SetSemaphore(&connectionSem);
		SenderLog->WriteMessage(TRACE,"[Main Process] Creating Sender");
		ReceiverLog->WriteMessage(TRACE,"[Main Process] Creating Sender");
		sender = new AdaServerSender(&connectionSem,wpool,SenderLog,c);
		SenderLog->WriteMessage(TRACE,"[Main Process] Creating Receiver");
		ReceiverLog->WriteMessage(TRACE,"[Main Process] Creating Receiver");
		receiver = new AdaServerReceiver(&connectionSem,wpool,ReceiverLog,c);
		SenderLog->WriteMessage(INFO,"[Main Process] Starting Sender");
		ReceiverLog->WriteMessage(INFO,"[Main Process] Starting Sender");
		SenderThread = new std::thread( [ ] { sender->Start(); });
		SenderThread->detach();
		ReceiverLog->WriteMessage(INFO,"[Main Process] Starting Receiver");
		SenderLog->WriteMessage(INFO,"[Main Process] Starting Receiver");
		receiver->Start();
	}
	if (!sigint)
	{
		delete (c);
		delete (wpool);
		delete (sender);
		delete (receiver);
		CRYPTO_cleanup_all_ex_data();
		kill_locks();
		ERR_remove_state(0);
		ERR_free_strings();
		EVP_cleanup();
		sem_destroy(&connectionSem);
		delete (SenderThread);
		delete (SenderLog);
		delete (ReceiverLog);
		exit(EXIT_FAILURE);
	}
	return (0);
}

<|endoftext|>


<commit_before>#include <iostream>
#include <iterator>
#include <sstream>
#include <unordered_map>
#include <stdexcept>
#include <memory>
#include <random>
#include <cmath>

#include <GL/glew.h>
#include <GL/glut.h>

#include "scope.hh"
#include "parser.hh"
#include "value.hh"
#include "exception.hh"

#include "draw/input.h"
#include "draw/texture.h"
#include "draw/render_target.h"
#include "draw/draw2d.h"

namespace izna {

std::shared_ptr<scope> cur_scope = nullptr;

class break_stmt: public std::exception {};
class next_stmt : public std::exception {};

void pushScope()
{
	cur_scope = std::make_shared<scope>(cur_scope);
}

void popScope()
{
	cur_scope = cur_scope->m_prev;
}

value eval_tree(std::shared_ptr<node> node);

value ExecFunc(value func_val, std::vector<value> &&args)
{
	value result;
	if (func_val.isFunc())
	{
		auto &f = func_val.toFunc();

		auto previous_scope = cur_scope;
		cur_scope = f.scope;
		pushScope();
		{
			auto cur_param = f.params;
			auto cur_arg   = args.begin();
			while (cur_param != nullptr)
			{
				cur_scope->setValue(cur_param->m_string, *cur_arg);
				cur_param = cur_param->m_right;
				++cur_arg;
			}

			result = eval_tree(f.stmt);
		}
		popScope();
		cur_scope = previous_scope;
	} else if (func_val.isNativeFunc())
	{
		auto f = func_val.toNativeFunc();
		result = f(args);
	} else
	{
		throw type_error();
	}

	return result;
}

value eval_tree(std::shared_ptr<node> node)
{
	if (!node) {
		return value();
	}

	switch (node->m_op)
	{
	case OP_ADD:
		return eval_tree(node->m_left).Add(eval_tree(node->m_right));

	case OP_SUBTRACT:
		return eval_tree(node->m_left).Sub(eval_tree(node->m_right));

	case OP_MULTIPLY:
		return eval_tree(node->m_left).Mul(eval_tree(node->m_right));

	case OP_DIVIDE:
		return eval_tree(node->m_left).Div(eval_tree(node->m_right));

	case OP_MODULO:
		return eval_tree(node->m_left).Mod(eval_tree(node->m_right));

	case OP_LOGICAL_OR:
		return eval_tree(node->m_left).LOr(eval_tree(node->m_right));

	case OP_LOGICAL_AND:
		return eval_tree(node->m_left).LAnd(eval_tree(node->m_right));

	case OP_EQ:
		return eval_tree(node->m_left).Eq(eval_tree(node->m_right));

	case OP_NE:
		return eval_tree(node->m_left).Ne(eval_tree(node->m_right));

	case OP_LESS:
		return eval_tree(node->m_left).Less(eval_tree(node->m_right));

	case OP_LESS_EQ:
		return eval_tree(node->m_left).LessEq(eval_tree(node->m_right));

	case OP_GREATER:
		return eval_tree(node->m_left).Greater(eval_tree(node->m_right));

	case OP_GREATER_EQ:
		return eval_tree(node->m_left).GreaterEq(eval_tree(node->m_right));

	case OP_ASSIGN:
		return eval_tree(node->m_left).Assign(eval_tree(node->m_right));

	case OP_NEG:
		return eval_tree(node->m_left).Neg();

	case OP_IDENTIFIER:
		{
			auto v = cur_scope->getValue(node->m_string);
			if (!v)
			{
				cur_scope->setValue(node->m_string, value());
				v = cur_scope->getValue(node->m_string);
			}

			return value(v);
		}

	case OP_CONST:
		return *(node->m_value);

	case OP_CLOSURE:
		{
			auto &func = node->m_value->toFunc();
			func.scope = cur_scope;

			return *(node->m_value);
		}

	case OP_CONTINUE:
		eval_tree(node->m_left);
		return eval_tree(node->m_right);

	case OP_IF:
		{
			if (eval_tree(node->m_cond).toBoolean())
			{
				return eval_tree(node->m_left);
			} else
			{
				return eval_tree(node->m_right);
			}
		}

	case OP_NEXT:
		throw next_stmt();

	case OP_BREAK:
		throw break_stmt();

	case OP_WHILE:
		{
			value val = value();
			for(;;)
			{
				if (!eval_tree(node->m_cond).toBoolean())
				{
					break;
				}

				try {
					val = eval_tree(node->m_left);
				} catch (next_stmt)
				{
				} catch (break_stmt)
				{
					break;
				}
			}
			return val;
		}
	case OP_EXECFUNC:
		{
			pushScope();

			std::vector<value> args;
			auto cur_arg = node->m_right;
			while (cur_arg != nullptr)
			{
				args.push_back(eval_tree(cur_arg->m_left));
				cur_arg = cur_arg->m_right;
			}

			value result = ExecFunc(eval_tree(node->m_left), std::move(args));

			popScope();
			return result;
		}
	case OP_ARRAY:
		{
			std::vector<value> arr;

			auto cur_elem = node->m_left;
			while (cur_elem != nullptr)
			{
				arr.push_back(eval_tree(cur_elem->m_left));
				cur_elem = cur_elem->m_right;
			}

			return value(std::move(arr));
		}
	case OP_OBJECT:
		{
			std::unordered_map<std::string, value> obj;

			auto cur_elem = node->m_left;
			while (cur_elem != nullptr)
			{
				obj[cur_elem->m_left->m_string] = eval_tree(cur_elem->m_left->m_right);
				cur_elem = cur_elem->m_right;
			}

			return value(std::move(obj));
		}
	case OP_INDEX:
		{
			auto lv = eval_tree(node->m_left);
			if (lv.isArray())
			{
				auto &arr = lv.toArray();

				int rv_int;
				if (node->m_right)
				{
					rv_int = eval_tree(node->m_right).toInteger();
				} else
				{
					rv_int = arr.size();
				}

				if (arr.size() <= rv_int)
				{
					while (arr.capacity() <= rv_int)
					{
						if (arr.capacity() == 0)
						{
							arr.reserve(1);
						} else
						{
							arr.reserve(arr.capacity() * 2);
						}
					}
					arr.resize(rv_int + 1);
				}

				return value(&arr[rv_int]);
			}
			else if (lv.isObject())
			{
				auto &obj = lv.toUnorderedMap();
				return value(&obj[eval_tree(node->m_right).toString()]);
			}
		}
	}
	return value();
}

} //izna

const int   WINDOW_WIDTH   = 800;
const int   WINDOW_HEIGHT  = 600;
const char *WINDOW_TITLE   = "iznagame";
const int   TIMER_INTERVAL = 16;

void Reshape(int w, int h);
void Timer(int);

bool InitResources();
void Draw();

std::vector<stg::Texture_ptr> g_textures;
izna::value g_drawfunc;

stg::input::Key GetKey(std::string str)
{
	if (str == "ESC")
	{
		return stg::input::Key::Esc();
	}
	else if(str == "UP")
	{
		return stg::input::Key::Up();
	}
	else if(str == "DOWN")
	{
		return stg::input::Key::Down();
	}
	else if(str == "LEFT")
	{
		return stg::input::Key::Left();
	}
	else if(str == "RIGHT")
	{
		return stg::input::Key::Right();
	}
	else
	{
		return stg::input::Key(str[0]);
	}
}

int main(int argc, char *argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
	glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);

	glutCreateWindow(WINDOW_TITLE);
	glutDisplayFunc(Draw);
	glutReshapeFunc(Reshape);
	glutTimerFunc(TIMER_INTERVAL, Timer, 0);

	if (glewInit() != GLEW_OK)
	{
		std::cerr << "ERROR: Failed to initialize GLEW" << std::endl;
		return 1;
	}

	if (!GLEW_EXT_framebuffer_object)
	{
		std::cerr << "ERROR: EXT_framebuffer_objet is not supported in this environment" << std::endl;
		return 1;
	}

	stg::input::Init();
	if (!InitResources())
	{
		return 1;
	}

	{
		std::string str((std::istreambuf_iterator<char>(std::cin)), (std::istreambuf_iterator<char>()));
		izna::parser_params params(str.c_str(), str.size());

		izna::parser parser(params);
		if (parser.parse() != 0 || !params.root)
		{
			std::cout << "Failed to parse the input file." << std::endl;
			return 1;
		}

		izna::pushScope();

		izna::cur_scope->setValue(
			"print",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					std::cout << args[0].toString();
					return izna::value();
				})
			);

		izna::cur_scope->setValue(
			"LoadPNG",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					g_textures.push_back(stg::LoadPNG(args[0].toString().c_str()));
					return izna::value(static_cast<int>(g_textures.size() - 1));
				})
			);

		izna::cur_scope->setValue(
			"MainLoop",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					g_drawfunc = args[0];
					return izna::value();
				})
			);

		izna::cur_scope->setValue(
			"Draw",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					stg::Drawer2D(
						g_textures[args[0].toInteger()],
						args[1].toInteger(),
						args[2].toInteger()).Apply();
					return izna::value();
				})
			);

		izna::cur_scope->setValue(
			"KeyIsPushed",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					return izna::value(GetKey(args[0].toString()).IsPushed());
				})
			);

		izna::cur_scope->setValue(
			"KeyIsHolded",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					return izna::value(GetKey(args[0].toString()).IsHolded());
				})
			);

		izna::cur_scope->setValue(
			"KeyIsReleased",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					return izna::value(GetKey(args[0].toString()).IsReleased());
				})
			);

		izna::cur_scope->setValue(
			"Draw",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					stg::Drawer2D(
						g_textures[args[0].toInteger()],
						args[1].toInteger(),
						args[2].toInteger()).Apply();
					return izna::value();
				})
			);

		izna::cur_scope->setValue(
			"sin",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					return izna::value(std::sin(args[0].toReal()));
				})
			);

		izna::cur_scope->setValue(
			"cos",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					return izna::value(std::cos(args[0].toReal()));
				})
			);

		izna::cur_scope->setValue(
			"tan",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					return izna::value(std::tan(args[0].toReal()));
				})
			);

		izna::cur_scope->setValue(
			"rand",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					static std::mt19937 mt;

					std::uniform_real_distribution<double> rand_range(0.0, 1.0);
					return izna::value(rand_range(mt));
				})
			);

		izna::cur_scope->setValue(
			"ArraySize",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					return izna::value(static_cast<int>(args[0].toArray().size()));
				})
			);

		izna::cur_scope->setValue(
			"ArrayPushBack",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					args[0].toArray().push_back(args[1]);
					return izna::value();
				})
			);

		izna::eval_tree(params.root);

		glutMainLoop();
		izna::popScope();
	}

	return 0;
}

void Reshape(int w, int h)
{
	if (w != WINDOW_WIDTH || h != WINDOW_HEIGHT)
	{
		glutReshapeWindow(WINDOW_WIDTH, WINDOW_HEIGHT);
	}
}

void Timer(int)
{
	glutPostRedisplay();
	glutTimerFunc(TIMER_INTERVAL, Timer, 0);
}

bool InitResources()
{
	return true;
}

void Draw()
{
	glClearColor(0, 0, 0, 0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	stg::Draw2D([](){
		ExecFunc(g_drawfunc, std::vector<izna::value>());
	});

	glFlush();
	glutSwapBuffers();

	stg::input::Update();
}
<commit_msg>for console applications<commit_after>#include <iostream>
#include <iterator>
#include <sstream>
#include <unordered_map>
#include <stdexcept>
#include <memory>
#include <random>
#include <cmath>

#include <GL/glew.h>
#include <GL/glut.h>

#include "scope.hh"
#include "parser.hh"
#include "value.hh"
#include "exception.hh"

#include "draw/input.h"
#include "draw/texture.h"
#include "draw/render_target.h"
#include "draw/draw2d.h"

namespace izna {

std::shared_ptr<scope> cur_scope = nullptr;

class break_stmt: public std::exception {};
class next_stmt : public std::exception {};

void pushScope()
{
	cur_scope = std::make_shared<scope>(cur_scope);
}

void popScope()
{
	cur_scope = cur_scope->m_prev;
}

value eval_tree(std::shared_ptr<node> node);

value ExecFunc(value func_val, std::vector<value> &&args)
{
	value result;
	if (func_val.isFunc())
	{
		auto &f = func_val.toFunc();

		auto previous_scope = cur_scope;
		cur_scope = f.scope;
		pushScope();
		{
			auto cur_param = f.params;
			auto cur_arg   = args.begin();
			while (cur_param != nullptr)
			{
				cur_scope->setValue(cur_param->m_string, *cur_arg);
				cur_param = cur_param->m_right;
				++cur_arg;
			}

			result = eval_tree(f.stmt);
		}
		popScope();
		cur_scope = previous_scope;
	} else if (func_val.isNativeFunc())
	{
		auto f = func_val.toNativeFunc();
		result = f(args);
	} else
	{
		throw type_error();
	}

	return result;
}

value eval_tree(std::shared_ptr<node> node)
{
	if (!node) {
		return value();
	}

	switch (node->m_op)
	{
	case OP_ADD:
		return eval_tree(node->m_left).Add(eval_tree(node->m_right));

	case OP_SUBTRACT:
		return eval_tree(node->m_left).Sub(eval_tree(node->m_right));

	case OP_MULTIPLY:
		return eval_tree(node->m_left).Mul(eval_tree(node->m_right));

	case OP_DIVIDE:
		return eval_tree(node->m_left).Div(eval_tree(node->m_right));

	case OP_MODULO:
		return eval_tree(node->m_left).Mod(eval_tree(node->m_right));

	case OP_LOGICAL_OR:
		return eval_tree(node->m_left).LOr(eval_tree(node->m_right));

	case OP_LOGICAL_AND:
		return eval_tree(node->m_left).LAnd(eval_tree(node->m_right));

	case OP_EQ:
		return eval_tree(node->m_left).Eq(eval_tree(node->m_right));

	case OP_NE:
		return eval_tree(node->m_left).Ne(eval_tree(node->m_right));

	case OP_LESS:
		return eval_tree(node->m_left).Less(eval_tree(node->m_right));

	case OP_LESS_EQ:
		return eval_tree(node->m_left).LessEq(eval_tree(node->m_right));

	case OP_GREATER:
		return eval_tree(node->m_left).Greater(eval_tree(node->m_right));

	case OP_GREATER_EQ:
		return eval_tree(node->m_left).GreaterEq(eval_tree(node->m_right));

	case OP_ASSIGN:
		return eval_tree(node->m_left).Assign(eval_tree(node->m_right));

	case OP_NEG:
		return eval_tree(node->m_left).Neg();

	case OP_IDENTIFIER:
		{
			auto v = cur_scope->getValue(node->m_string);
			if (!v)
			{
				cur_scope->setValue(node->m_string, value());
				v = cur_scope->getValue(node->m_string);
			}

			return value(v);
		}

	case OP_CONST:
		return *(node->m_value);

	case OP_CLOSURE:
		{
			auto &func = node->m_value->toFunc();
			func.scope = cur_scope;

			return *(node->m_value);
		}

	case OP_CONTINUE:
		eval_tree(node->m_left);
		return eval_tree(node->m_right);

	case OP_IF:
		{
			if (eval_tree(node->m_cond).toBoolean())
			{
				return eval_tree(node->m_left);
			} else
			{
				return eval_tree(node->m_right);
			}
		}

	case OP_NEXT:
		throw next_stmt();

	case OP_BREAK:
		throw break_stmt();

	case OP_WHILE:
		{
			value val = value();
			for(;;)
			{
				if (!eval_tree(node->m_cond).toBoolean())
				{
					break;
				}

				try {
					val = eval_tree(node->m_left);
				} catch (next_stmt)
				{
				} catch (break_stmt)
				{
					break;
				}
			}
			return val;
		}
	case OP_EXECFUNC:
		{
			pushScope();

			std::vector<value> args;
			auto cur_arg = node->m_right;
			while (cur_arg != nullptr)
			{
				args.push_back(eval_tree(cur_arg->m_left));
				cur_arg = cur_arg->m_right;
			}

			value result = ExecFunc(eval_tree(node->m_left), std::move(args));

			popScope();
			return result;
		}
	case OP_ARRAY:
		{
			std::vector<value> arr;

			auto cur_elem = node->m_left;
			while (cur_elem != nullptr)
			{
				arr.push_back(eval_tree(cur_elem->m_left));
				cur_elem = cur_elem->m_right;
			}

			return value(std::move(arr));
		}
	case OP_OBJECT:
		{
			std::unordered_map<std::string, value> obj;

			auto cur_elem = node->m_left;
			while (cur_elem != nullptr)
			{
				obj[cur_elem->m_left->m_string] = eval_tree(cur_elem->m_left->m_right);
				cur_elem = cur_elem->m_right;
			}

			return value(std::move(obj));
		}
	case OP_INDEX:
		{
			auto lv = eval_tree(node->m_left);
			if (lv.isArray())
			{
				auto &arr = lv.toArray();

				int rv_int;
				if (node->m_right)
				{
					rv_int = eval_tree(node->m_right).toInteger();
				} else
				{
					rv_int = arr.size();
				}

				if (arr.size() <= rv_int)
				{
					while (arr.capacity() <= rv_int)
					{
						if (arr.capacity() == 0)
						{
							arr.reserve(1);
						} else
						{
							arr.reserve(arr.capacity() * 2);
						}
					}
					arr.resize(rv_int + 1);
				}

				return value(&arr[rv_int]);
			}
			else if (lv.isObject())
			{
				auto &obj = lv.toUnorderedMap();
				return value(&obj[eval_tree(node->m_right).toString()]);
			}
		}
	}
	return value();
}

} //izna

const int   WINDOW_WIDTH   = 800;
const int   WINDOW_HEIGHT  = 600;
const char *WINDOW_TITLE   = "iznagame";
const int   TIMER_INTERVAL = 16;

void Reshape(int w, int h);
void Timer(int);

bool InitResources();
void Draw();

std::vector<stg::Texture_ptr> g_textures;
izna::value g_drawfunc;

stg::input::Key GetKey(std::string str)
{
	if (str == "ESC")
	{
		return stg::input::Key::Esc();
	}
	else if(str == "UP")
	{
		return stg::input::Key::Up();
	}
	else if(str == "DOWN")
	{
		return stg::input::Key::Down();
	}
	else if(str == "LEFT")
	{
		return stg::input::Key::Left();
	}
	else if(str == "RIGHT")
	{
		return stg::input::Key::Right();
	}
	else
	{
		return stg::input::Key(str[0]);
	}
}

int main(int argc, char *argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
	glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);

	glutCreateWindow(WINDOW_TITLE);
	glutDisplayFunc(Draw);
	glutReshapeFunc(Reshape);
	glutTimerFunc(TIMER_INTERVAL, Timer, 0);

	if (glewInit() != GLEW_OK)
	{
		std::cerr << "ERROR: Failed to initialize GLEW" << std::endl;
		return 1;
	}

	if (!GLEW_EXT_framebuffer_object)
	{
		std::cerr << "ERROR: EXT_framebuffer_objet is not supported in this environment" << std::endl;
		return 1;
	}

	stg::input::Init();
	if (!InitResources())
	{
		return 1;
	}

	{
		std::string str((std::istreambuf_iterator<char>(std::cin)), (std::istreambuf_iterator<char>()));
		izna::parser_params params(str.c_str(), str.size());

		izna::parser parser(params);
		if (parser.parse() != 0 || !params.root)
		{
			std::cout << "Failed to parse the input file." << std::endl;
			return 1;
		}

		izna::pushScope();

		izna::cur_scope->setValue(
			"print",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					std::cout << args[0].toString();
					return izna::value();
				})
			);

		izna::cur_scope->setValue(
			"LoadPNG",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					g_textures.push_back(stg::LoadPNG(args[0].toString().c_str()));
					return izna::value(static_cast<int>(g_textures.size() - 1));
				})
			);

		izna::cur_scope->setValue(
			"MainLoop",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					g_drawfunc = args[0];
					return izna::value();
				})
			);

		izna::cur_scope->setValue(
			"Draw",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					stg::Drawer2D(
						g_textures[args[0].toInteger()],
						args[1].toInteger(),
						args[2].toInteger()).Apply();
					return izna::value();
				})
			);

		izna::cur_scope->setValue(
			"KeyIsPushed",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					return izna::value(GetKey(args[0].toString()).IsPushed());
				})
			);

		izna::cur_scope->setValue(
			"KeyIsHolded",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					return izna::value(GetKey(args[0].toString()).IsHolded());
				})
			);

		izna::cur_scope->setValue(
			"KeyIsReleased",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					return izna::value(GetKey(args[0].toString()).IsReleased());
				})
			);

		izna::cur_scope->setValue(
			"Draw",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					stg::Drawer2D(
						g_textures[args[0].toInteger()],
						args[1].toInteger(),
						args[2].toInteger()).Apply();
					return izna::value();
				})
			);

		izna::cur_scope->setValue(
			"sin",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					return izna::value(std::sin(args[0].toReal()));
				})
			);

		izna::cur_scope->setValue(
			"cos",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					return izna::value(std::cos(args[0].toReal()));
				})
			);

		izna::cur_scope->setValue(
			"tan",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					return izna::value(std::tan(args[0].toReal()));
				})
			);

		izna::cur_scope->setValue(
			"rand",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					static std::mt19937 mt;

					std::uniform_real_distribution<double> rand_range(0.0, 1.0);
					return izna::value(rand_range(mt));
				})
			);

		izna::cur_scope->setValue(
			"ArraySize",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					return izna::value(static_cast<int>(args[0].toArray().size()));
				})
			);

		izna::cur_scope->setValue(
			"ArrayPushBack",
			izna::value([](std::vector<izna::value> args) -> izna::value {
					args[0].toArray().push_back(args[1]);
					return izna::value();
				})
			);

		izna::eval_tree(params.root);

		if (!g_drawfunc.isNil())
		{
			glutMainLoop();
		}
		izna::popScope();
	}

	return 0;
}

void Reshape(int w, int h)
{
	if (w != WINDOW_WIDTH || h != WINDOW_HEIGHT)
	{
		glutReshapeWindow(WINDOW_WIDTH, WINDOW_HEIGHT);
	}
}

void Timer(int)
{
	glutPostRedisplay();
	glutTimerFunc(TIMER_INTERVAL, Timer, 0);
}

bool InitResources()
{
	return true;
}

void Draw()
{
	glClearColor(0, 0, 0, 0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	stg::Draw2D([](){
		ExecFunc(g_drawfunc, std::vector<izna::value>());
	});

	glFlush();
	glutSwapBuffers();

	stg::input::Update();
}
<|endoftext|>


<commit_before>/*
 * This file is part of the LibreOffice project.
 *
 * Based on LLVM/Clang.
 *
 * This file is distributed under the University of Illinois Open Source
 * License. See LICENSE.TXT for details.
 *
 */

#include "plugin.hxx"

#include <clang/Lex/Preprocessor.h>

namespace loplugin
{

/*
This is a compile check.

Feature macros from config_XXX.h headers are always #defined (to 1 or 0 in case of yes/no
settings). It is a mistake to use #ifdef/#ifndef/defined to check them.

Using 1/0 instead of defined/undefined avoids undetected problems when e.g. the necessary
#include of the config_XXX.h file is missing.
*/

class CheckConfigMacros
    : public PPCallbacks
    , public Plugin
    {
    public:
        explicit CheckConfigMacros( CompilerInstance& compiler );
        virtual void run() override;
#if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
        virtual void MacroDefined( const Token& macroToken, const MacroInfo* info ) override;
        virtual void MacroUndefined( const Token& macroToken, const MacroInfo* info ) override;
        virtual void Ifdef( SourceLocation location, const Token& macroToken ) override;
        virtual void Ifndef( SourceLocation location, const Token& macroToken ) override;
        virtual void Defined( const Token& macroToken ) override;
#else
        virtual void MacroDefined( const Token& macroToken, const MacroDirective* info ) override;
        virtual void MacroUndefined( const Token& macroToken, const MacroDirective* info ) override;
        virtual void Ifdef( SourceLocation location, const Token& macroToken, const MacroDirective* info ) override;
        virtual void Ifndef( SourceLocation location, const Token& macroToken, const MacroDirective* info ) override;
        virtual void Defined( const Token& macroToken, const MacroDirective* info ) override;
#endif
    private:
        void checkMacro( const Token& macroToken, SourceLocation location );
        std::set< string > configMacros;
    };

CheckConfigMacros::CheckConfigMacros( CompilerInstance& compiler )
    : Plugin( compiler )
    {
    compiler.getPreprocessor().addPPCallbacks( this );
    }

void CheckConfigMacros::run()
    {
    // nothing, only check preprocessor usage
    }

#if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
void CheckConfigMacros::MacroDefined( const Token& macroToken, const MacroInfo* info )
    {
    SourceLocation location = info->getDefinitionLoc();
#else
void CheckConfigMacros::MacroDefined( const Token& macroToken, const MacroDirective* info )
    {
    SourceLocation location = info->getLocation();
#endif
    const char* filename = compiler.getSourceManager().getPresumedLoc( location ).getFilename();
    if( filename != NULL
        && ( strncmp( filename, BUILDDIR "/config_host/", strlen( BUILDDIR "/config_host/" )) == 0
            || strncmp( filename, BUILDDIR "/config_build/", strlen( BUILDDIR "/config_build/" )) == 0 ))
        {
//        fprintf(stderr,"DEF: %s %s\n", macroToken.getIdentifierInfo()->getName().data(), filename );
        configMacros.insert( macroToken.getIdentifierInfo()->getName());
        }
    }

#if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
void CheckConfigMacros::MacroUndefined( const Token& macroToken, const MacroInfo* )
#else
void CheckConfigMacros::MacroUndefined( const Token& macroToken, const MacroDirective* )
#endif
    {
    configMacros.erase( macroToken.getIdentifierInfo()->getName());
    }

#if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
void CheckConfigMacros::Ifdef( SourceLocation location, const Token& macroToken )
#else
void CheckConfigMacros::Ifdef( SourceLocation location, const Token& macroToken, const MacroDirective* )
#endif
    {
    checkMacro( macroToken, location );
    }

#if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
void CheckConfigMacros::Ifndef( SourceLocation location, const Token& macroToken )
#else
void CheckConfigMacros::Ifndef( SourceLocation location, const Token& macroToken, const MacroDirective* )
#endif
    {
    checkMacro( macroToken, location );
    }

#if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
void CheckConfigMacros::Defined( const Token& macroToken )
#else
void CheckConfigMacros::Defined( const Token& macroToken, const MacroDirective* )
#endif
    {
    checkMacro( macroToken, macroToken.getLocation());
    }

void CheckConfigMacros::checkMacro( const Token& macroToken, SourceLocation location )
    {
    if( configMacros.find( macroToken.getIdentifierInfo()->getName()) != configMacros.end())
        {
        report( DiagnosticsEngine::Error, "checking whether a config macro %0 is defined",
            location ) << macroToken.getIdentifierInfo()->getName();
        report( DiagnosticsEngine::Note, "use #if instead of #ifdef/#ifndef/defined", location );
        }
    }

static Plugin::Registration< CheckConfigMacros > X( "bodynotinblock" );

} // namespace
<commit_msg>Adapt to PPCallbacks.h changes on Clang trunk towards 3.4<commit_after>/*
 * This file is part of the LibreOffice project.
 *
 * Based on LLVM/Clang.
 *
 * This file is distributed under the University of Illinois Open Source
 * License. See LICENSE.TXT for details.
 *
 */

#include "plugin.hxx"

#include <clang/Lex/Preprocessor.h>

namespace loplugin
{

/*
This is a compile check.

Feature macros from config_XXX.h headers are always #defined (to 1 or 0 in case of yes/no
settings). It is a mistake to use #ifdef/#ifndef/defined to check them.

Using 1/0 instead of defined/undefined avoids undetected problems when e.g. the necessary
#include of the config_XXX.h file is missing.
*/

class CheckConfigMacros
    : public PPCallbacks
    , public Plugin
    {
    public:
        explicit CheckConfigMacros( CompilerInstance& compiler );
        virtual void run() override;
#if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
        virtual void MacroDefined( const Token& macroToken, const MacroInfo* info ) override;
        virtual void MacroUndefined( const Token& macroToken, const MacroInfo* info ) override;
        virtual void Ifdef( SourceLocation location, const Token& macroToken ) override;
        virtual void Ifndef( SourceLocation location, const Token& macroToken ) override;
        virtual void Defined( const Token& macroToken ) override;
#else
        virtual void MacroDefined( const Token& macroToken, const MacroDirective* info ) override;
        virtual void MacroUndefined( const Token& macroToken, const MacroDirective* info ) override;
        virtual void Ifdef( SourceLocation location, const Token& macroToken, const MacroDirective* info ) override;
        virtual void Ifndef( SourceLocation location, const Token& macroToken, const MacroDirective* info ) override;
#if __clang_major__ == 3 && __clang_minor__ < 4
        virtual void Defined( const Token& macroToken, const MacroDirective* info ) override;
#else
        virtual void Defined( const Token& macroToken, const MacroDirective* info, SourceRange Range ) override;
#endif
#endif
    private:
        void checkMacro( const Token& macroToken, SourceLocation location );
        std::set< string > configMacros;
    };

CheckConfigMacros::CheckConfigMacros( CompilerInstance& compiler )
    : Plugin( compiler )
    {
    compiler.getPreprocessor().addPPCallbacks( this );
    }

void CheckConfigMacros::run()
    {
    // nothing, only check preprocessor usage
    }

#if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
void CheckConfigMacros::MacroDefined( const Token& macroToken, const MacroInfo* info )
    {
    SourceLocation location = info->getDefinitionLoc();
#else
void CheckConfigMacros::MacroDefined( const Token& macroToken, const MacroDirective* info )
    {
    SourceLocation location = info->getLocation();
#endif
    const char* filename = compiler.getSourceManager().getPresumedLoc( location ).getFilename();
    if( filename != NULL
        && ( strncmp( filename, BUILDDIR "/config_host/", strlen( BUILDDIR "/config_host/" )) == 0
            || strncmp( filename, BUILDDIR "/config_build/", strlen( BUILDDIR "/config_build/" )) == 0 ))
        {
//        fprintf(stderr,"DEF: %s %s\n", macroToken.getIdentifierInfo()->getName().data(), filename );
        configMacros.insert( macroToken.getIdentifierInfo()->getName());
        }
    }

#if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
void CheckConfigMacros::MacroUndefined( const Token& macroToken, const MacroInfo* )
#else
void CheckConfigMacros::MacroUndefined( const Token& macroToken, const MacroDirective* )
#endif
    {
    configMacros.erase( macroToken.getIdentifierInfo()->getName());
    }

#if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
void CheckConfigMacros::Ifdef( SourceLocation location, const Token& macroToken )
#else
void CheckConfigMacros::Ifdef( SourceLocation location, const Token& macroToken, const MacroDirective* )
#endif
    {
    checkMacro( macroToken, location );
    }

#if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
void CheckConfigMacros::Ifndef( SourceLocation location, const Token& macroToken )
#else
void CheckConfigMacros::Ifndef( SourceLocation location, const Token& macroToken, const MacroDirective* )
#endif
    {
    checkMacro( macroToken, location );
    }

#if __clang_major__ < 3 || __clang_major__ == 3 && __clang_minor__ < 3
void CheckConfigMacros::Defined( const Token& macroToken )
#elif __clang_major__ == 3 && __clang_minor__ < 4
void CheckConfigMacros::Defined( const Token& macroToken, const MacroDirective* )
#else
void CheckConfigMacros::Defined( const Token& macroToken, const MacroDirective* , SourceRange )
#endif
    {
    checkMacro( macroToken, macroToken.getLocation());
    }

void CheckConfigMacros::checkMacro( const Token& macroToken, SourceLocation location )
    {
    if( configMacros.find( macroToken.getIdentifierInfo()->getName()) != configMacros.end())
        {
        report( DiagnosticsEngine::Error, "checking whether a config macro %0 is defined",
            location ) << macroToken.getIdentifierInfo()->getName();
        report( DiagnosticsEngine::Note, "use #if instead of #ifdef/#ifndef/defined", location );
        }
    }

static Plugin::Registration< CheckConfigMacros > X( "bodynotinblock" );

} // namespace
<|endoftext|>


<commit_before><commit_msg>more overrides<commit_after><|endoftext|>


<commit_before>// Standard includes
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <cmath>
#include <string.h>
#include <inttypes.h>
#include <fstream>
#include <limits.h>

// Serial includes
#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#
#ifdef __linux
#include <sys/ioctl.h>
#endif

#include "serialwifly.h"

using std::string;
using namespace std;

// TODO: Investigate this parameter... what exactly does it do?
#define WD 1000

/**
 * Start serial connection over one some port
 *
 * *port should be of the format "/dev/ttyUSB0"
 */
int start_connection(char *port)
{
	int fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
	return fd;
}

/**
 * This puts you in command mode
 * Must wait 250 ms before
 */
int commandmode(int fd)
{
	// First, we must make sure we are in command mode
	// For now, let's assume we just booted up
	write(fd, "exit\r", 5);
	usleep(WD);
	write(fd, "exit\r", 5);
	usleep(WD);

	/* Give it the turn on command */
	/* Must wait 250 ms before and after giving $$$ command */
	/* To be safe, I wait 300 ms */
	write(fd, "$$$", 3);
	usleep(300000);

	return 0;
}

/**
 * Parses output from scan command.
 * Searches for SSID provided.
 * Returns the RSSI value of that SSID, as an int.
 */
int getrssi(char *buf, char *ssid)
{
	char *delim = (char *) "\n";
	char *token = strtok(buf, delim);
	int rssi_value = INT_MAX;

	while (token)
	{
		if (strstr(token, ssid) != NULL)
		{
			char *comma_delim = (char *)  ",";
			char *jam_token = strtok(token, comma_delim);
			jam_token =	strtok(0, comma_delim);
			jam_token =	strtok(0, comma_delim);
			rssi_value = atoi(jam_token);
			token = NULL;
		}
		else
		{
			token = strtok(0, delim);
		}
	}

	return rssi_value;
}

/**
 * Scans the channels and returns the rssi of the specified SSID
 */
int scanrssi(int fd, char *ssid)
{
	char buf[1000];
	write(fd, "scan 10\r", 8);
	usleep(1000000);
	read(fd, buf, sizeof(buf));

	return getrssi(buf, ssid);
}

/**
 * Scans numtimes times and prints rssi values to a line in a file
 */
int scanrssi_f(int fd, char *ssid, FILE *f, int numtimes)
{
	int rssi_value, i;
	for (i = 1; i <= (numtimes-1); i++)
	{
		rssi_value = scanrssi(fd, ssid);
		fprintf(f, "%i,", rssi_value);
		//printf("rssi_value = %i\n", rssi_value);
	}

	/* Don't include comma for last one */
	rssi_value = scanrssi(fd, ssid);
	fprintf(f, "%i\n", rssi_value);
	//printf("rssi_value = %i\n", rssi_value);

	return rssi;
}

/**
 * Scans numtimes times and prints rssi values to a line in a file
 */
int scanrssi_2(int fd1, int fd2, char *ssid, FILE *f1, FILE *f2, int numtimes)
{
	int rssi_1, rssi_2, i;
	for (i = 1; i <= (numtimes-1); i++)
	{
		rssi_1 = scanrssi(fd1, ssid);
		rssi_2 = scanrssi(fd2, ssid);
		fprintf(f1, "%i,", rssi_1);
		fprintf(f2, "%i,", rssi_2);
		printf("Wifly 1 RSSI = %i\n", rssi_1);
		printf("Wifly 2 RSSI = %i\n", rssi_2);
	}

	/* Don't include comma for last one */
	rssi_1 = scanrssi(fd1, ssid);
	rssi_2 = scanrssi(fd2, ssid);
	fprintf(f1, "%i\n", rssi_1);
	fprintf(f2, "%i\n", rssi_2);
	printf("Wifly 1 RSSI = %i\n", rssi_1);
	printf("Wifly 2 RSSI = %i\n", rssi_2);

	return 0;
}

<commit_msg>fix typo in rssi return value<commit_after>// Standard includes
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <cmath>
#include <string.h>
#include <inttypes.h>
#include <fstream>
#include <limits.h>

// Serial includes
#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#
#ifdef __linux
#include <sys/ioctl.h>
#endif

#include "serialwifly.h"

using std::string;
using namespace std;

// TODO: Investigate this parameter... what exactly does it do?
#define WD 1000

/**
 * Start serial connection over one some port
 *
 * *port should be of the format "/dev/ttyUSB0"
 */
int start_connection(char *port)
{
	int fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
	return fd;
}

/**
 * This puts you in command mode
 * Must wait 250 ms before
 */
int commandmode(int fd)
{
	// First, we must make sure we are in command mode
	// For now, let's assume we just booted up
	write(fd, "exit\r", 5);
	usleep(WD);
	write(fd, "exit\r", 5);
	usleep(WD);

	/* Give it the turn on command */
	/* Must wait 250 ms before and after giving $$$ command */
	/* To be safe, I wait 300 ms */
	write(fd, "$$$", 3);
	usleep(300000);

	return 0;
}

/**
 * Parses output from scan command.
 * Searches for SSID provided.
 * Returns the RSSI value of that SSID, as an int.
 */
int getrssi(char *buf, char *ssid)
{
	char *delim = (char *) "\n";
	char *token = strtok(buf, delim);
	int rssi_value = INT_MAX;

	while (token)
	{
		if (strstr(token, ssid) != NULL)
		{
			char *comma_delim = (char *)  ",";
			char *jam_token = strtok(token, comma_delim);
			jam_token =	strtok(0, comma_delim);
			jam_token =	strtok(0, comma_delim);
			rssi_value = atoi(jam_token);
			token = NULL;
		}
		else
		{
			token = strtok(0, delim);
		}
	}

	return rssi_value;
}

/**
 * Scans the channels and returns the rssi of the specified SSID
 */
int scanrssi(int fd, char *ssid)
{
	char buf[1000];
	write(fd, "scan 10\r", 8);
	usleep(1000000);
	read(fd, buf, sizeof(buf));

	return getrssi(buf, ssid);
}

/**
 * Scans numtimes times and prints rssi values to a line in a file
 */
int scanrssi_f(int fd, char *ssid, FILE *f, int numtimes)
{
	int rssi_value, i;
	for (i = 1; i <= (numtimes-1); i++)
	{
		rssi_value = scanrssi(fd, ssid);
		fprintf(f, "%i,", rssi_value);
		//printf("rssi_value = %i\n", rssi_value);
	}

	/* Don't include comma for last one */
	rssi_value = scanrssi(fd, ssid);
	fprintf(f, "%i\n", rssi_value);
	//printf("rssi_value = %i\n", rssi_value);

	return rssi_value;
}

/**
 * Scans numtimes times and prints rssi values to a line in a file
 */
int scanrssi_2(int fd1, int fd2, char *ssid, FILE *f1, FILE *f2, int numtimes)
{
	int rssi_1, rssi_2, i;
	for (i = 1; i <= (numtimes-1); i++)
	{
		rssi_1 = scanrssi(fd1, ssid);
		rssi_2 = scanrssi(fd2, ssid);
		fprintf(f1, "%i,", rssi_1);
		fprintf(f2, "%i,", rssi_2);
		printf("Wifly 1 RSSI = %i\n", rssi_1);
		printf("Wifly 2 RSSI = %i\n", rssi_2);
	}

	/* Don't include comma for last one */
	rssi_1 = scanrssi(fd1, ssid);
	rssi_2 = scanrssi(fd2, ssid);
	fprintf(f1, "%i\n", rssi_1);
	fprintf(f2, "%i\n", rssi_2);
	printf("Wifly 1 RSSI = %i\n", rssi_1);
	printf("Wifly 2 RSSI = %i\n", rssi_2);

	return 0;
}

<|endoftext|>


<commit_before>#include <typeinfo>
#include <array>
#include <algorithm>

#include "gtest.h"
#include "util/optional.hpp"

using namespace nest::mc::util;

TEST(optionalm,ctors) {
    optional<int> a,b(3),c=b,d=4;

    ASSERT_FALSE((bool)a);
    ASSERT_TRUE((bool)b);
    ASSERT_TRUE((bool)c);
    ASSERT_TRUE((bool)d);

    EXPECT_EQ(3,b.get());
    EXPECT_EQ(3,c.get());
    EXPECT_EQ(4,d.get());
}

TEST(optionalm,unset_throw) {
    optional<int> a;
    int check=10;

    try { a.get(); }
    catch(optional_unset_error &e) {
        ++check;
    }
    EXPECT_EQ(11,check);

    check=20;
    a=2;
    try { a.get(); }
    catch(optional_unset_error &e) {
        ++check;
    }
    EXPECT_EQ(20,check);

    check=30;
    a.reset();
    try { a.get(); }
    catch(optional_unset_error &e) {
        ++check;
    }
    EXPECT_EQ(31,check);
}

TEST(optionalm,deref) {
    struct foo {
        int a;
        explicit foo(int a_): a(a_) {}
        double value() { return 3.0*a; }
    };

    optional<foo> f=foo(2);
    EXPECT_EQ(6.0,f->value());
    EXPECT_EQ(2,(*f).a);
}

TEST(optionalm,ctor_conv) {
    optional<std::array<int,3>> x{{1,2,3}};
    EXPECT_EQ(3u,x->size());
}

TEST(optionalm,ctor_ref) {
    int v=10;
    optional<int &> a(v);

    EXPECT_EQ(10,a.get());
    v=20;
    EXPECT_EQ(20,a.get());

    optional<int &> b(a),c=b,d=v;
    EXPECT_EQ(&(a.get()),&(b.get()));
    EXPECT_EQ(&(a.get()),&(c.get()));
    EXPECT_EQ(&(a.get()),&(d.get()));
}

TEST(optionalm,assign_returns) {
    optional<int> a=3;

    auto b=(a=4);
    EXPECT_EQ(typeid(optional<int>),typeid(b));

    auto bp=&(a=4);
    EXPECT_EQ(&a,bp);
}

TEST(optionalm,assign_reference) {
    double a=3.0;
    optional<double &> ar;
    optional<double &> br;

    ar = a;
    EXPECT_TRUE(ar);
    *ar = 5.0;
    EXPECT_EQ(5.0, a);

    br = ar;
    EXPECT_TRUE(br);

    *br = 7.0;
    EXPECT_EQ(7.0, a);
}

struct nomove {
    int value;

    nomove(): value(0) {}
    nomove(int i): value(i) {}
    nomove(const nomove &n): value(n.value) {}
    nomove(nomove &&n) = delete;

    nomove &operator=(const nomove &n) { value=n.value; return *this; }

    bool operator==(const nomove &them) const { return them.value==value; }
    bool operator!=(const nomove &them) const { return !(*this==them); }
};

TEST(optionalm,ctor_nomove) {
    optional<nomove> a(nomove(3));
    EXPECT_EQ(nomove(3),a.get());

    optional<nomove> b;
    b=a;
    EXPECT_EQ(nomove(3),b.get());

    b=optional<nomove>(nomove(4));
    EXPECT_EQ(nomove(4),b.get());
}

struct nocopy {
    int value;

    nocopy(): value(0) {}
    nocopy(int i): value(i) {}
    nocopy(const nocopy &n) = delete;
    nocopy(nocopy &&n) {
        value=n.value;
        n.value=0;
    }

    nocopy &operator=(const nocopy &n) = delete;
    nocopy &operator=(nocopy &&n) {
        value=n.value;
        n.value=-1;
        return *this;
    }

    bool operator==(const nocopy &them) const { return them.value==value; }
    bool operator!=(const nocopy &them) const { return !(*this==them); }
};

TEST(optionalm,ctor_nocopy) {
    optional<nocopy> a(nocopy(5));
    EXPECT_EQ(nocopy(5),a.get());

    optional<nocopy> b(std::move(a));
    EXPECT_EQ(nocopy(5),b.get());
    EXPECT_EQ(0,a.get().value);

    b=optional<nocopy>(nocopy(6));
    EXPECT_EQ(nocopy(6),b.get());
}

static optional<double> odd_half(int n) {
    optional<double> h;
    if (n%2==1) h=n/2.0;
    return h;
}

TEST(optionalm,bind) {
    optional<int> a;
    auto b=a.bind(odd_half);

    EXPECT_EQ(typeid(optional<double>),typeid(b));

    a=10;
    b=a.bind(odd_half);
    EXPECT_FALSE((bool)b);

    a=11;
    b=a.bind(odd_half);
    EXPECT_TRUE((bool)b);
    EXPECT_EQ(5.5,b.get());

    b=a >> odd_half >> [](double x) { return (int)x; } >> odd_half;
    EXPECT_TRUE((bool)b);
    EXPECT_EQ(2.5,b.get());
}

TEST(optionalm,void) {
    optional<void> a,b(true),c(a),d=b,e(false);

    EXPECT_FALSE((bool)a);
    EXPECT_TRUE((bool)b);
    EXPECT_FALSE((bool)c);
    EXPECT_TRUE((bool)d);
    EXPECT_TRUE((bool)e);

    auto x=a >> []() { return 1; };
    EXPECT_FALSE((bool)x);

    x=b >> []() { return 1; };
    EXPECT_TRUE((bool)x);
    EXPECT_EQ(1,x.get());
}

TEST(optionalm,bind_to_void) {
    optional<int> a,b(3);

    int call_count=0;
    auto vf=[&call_count](int i) -> void { ++call_count; };

    auto x=a >> vf;
    EXPECT_EQ(typeid(optional<void>),typeid(x));
    EXPECT_FALSE((bool)x);
    EXPECT_EQ(0,call_count);

    call_count=0;
    x=b >> vf;
    EXPECT_TRUE((bool)x);
    EXPECT_EQ(1,call_count);
}

TEST(optionalm,bind_to_optional_void) {
    optional<int> a,b(3),c(4);

    int count=0;
    auto count_if_odd=[&count](int i) {
        return i%2?(++count,optional<void>(true)):optional<void>();
    };

    auto x=a >> count_if_odd;
    EXPECT_EQ(typeid(optional<void>),typeid(x));
    EXPECT_FALSE((bool)x);
    EXPECT_EQ(0,count);

    count=0;
    x=b >> count_if_odd;
    EXPECT_TRUE((bool)x);
    EXPECT_EQ(1,count);

    count=0;
    x=c >> count_if_odd;
    EXPECT_FALSE((bool)x);
    EXPECT_EQ(0,count);
}

TEST(optionalm,bind_with_ref) {
    optional<int> a=10;
    a >> [](int &v) {++v; };
    EXPECT_EQ(11,*a);
}

struct check_cref {
    int operator()(const int &) { return 10; }
    int operator()(int &) { return 11; }
};

TEST(optionalm,bind_constness) {
    check_cref checker;
    optional<int> a=1;
    int v=*(a >> checker);
    EXPECT_EQ(11,v);

    const optional<int> b=1;
    v=*(b >> checker);
    EXPECT_EQ(10,v);
}

TEST(optionalm,conversion) {
    optional<double> a(3),b=5;
    EXPECT_TRUE((bool)a);
    EXPECT_TRUE((bool)b);
    EXPECT_EQ(3.0,a.get());
    EXPECT_EQ(5.0,b.get());

    optional<int> x;
    optional<double> c(x);
    optional<double> d=optional<int>();
    EXPECT_FALSE((bool)c);
    EXPECT_FALSE((bool)d);

    auto doubler=[](double x) { return x*2; };
    auto y=optional<int>(3) >> doubler;
    EXPECT_TRUE((bool)y);
    EXPECT_EQ(6.0,y.get());
}

TEST(optionalm,or_operator) {
    optional<const char *> default_msg="default";
    auto x=(char *)0 | default_msg;
    EXPECT_TRUE((bool)x);
    EXPECT_STREQ("default",x.get());

    auto y="something" | default_msg;
    EXPECT_TRUE((bool)y);
    EXPECT_STREQ("something",y.get());

    optional<int> a(1),b,c(3);
    EXPECT_EQ(1,*(a|b|c));
    EXPECT_EQ(1,*(a|c|b));
    EXPECT_EQ(1,*(b|a|c));
    EXPECT_EQ(3,*(b|c|a));
    EXPECT_EQ(3,*(c|a|b));
    EXPECT_EQ(3,*(c|b|a));
}

TEST(optionalm,and_operator) {
    optional<int> a(1);
    optional<double> b(2.0);

    auto ab=a&b;
    auto ba=b&a;

    EXPECT_EQ(typeid(ab),typeid(b));
    EXPECT_EQ(typeid(ba),typeid(a));
    EXPECT_EQ(2.0,*ab);
    EXPECT_EQ(1,*ba);

    auto zb=false & b;
    EXPECT_EQ(typeid(zb),typeid(b));
    EXPECT_FALSE((bool)zb);

    auto b3=b & 3;
    EXPECT_EQ(typeid(b3),typeid(optional<int>));
    EXPECT_TRUE((bool)b3);
    EXPECT_EQ(3,*b3);
}

TEST(optionalm,provided) {
    std::array<int,3> qs={1,0,3};
    std::array<int,3> ps={14,14,14};
    std::array<int,3> rs;

    std::transform(ps.begin(),ps.end(),qs.begin(),rs.begin(),
        [](int p,int q) { return *( provided(q!=0) >> [=]() { return p/q; } | -1 ); });

    EXPECT_EQ(14,rs[0]);
    EXPECT_EQ(-1,rs[1]);
    EXPECT_EQ(4,rs[2]);
}
<commit_msg>Address coding style issue<commit_after>#include <typeinfo>
#include <array>
#include <algorithm>

#include "gtest.h"
#include "util/optional.hpp"

using namespace nest::mc::util;

TEST(optionalm,ctors) {
    optional<int> a,b(3),c=b,d=4;

    ASSERT_FALSE((bool)a);
    ASSERT_TRUE((bool)b);
    ASSERT_TRUE((bool)c);
    ASSERT_TRUE((bool)d);

    EXPECT_EQ(3,b.get());
    EXPECT_EQ(3,c.get());
    EXPECT_EQ(4,d.get());
}

TEST(optionalm,unset_throw) {
    optional<int> a;
    int check=10;

    try { a.get(); }
    catch(optional_unset_error &e) {
        ++check;
    }
    EXPECT_EQ(11,check);

    check=20;
    a=2;
    try { a.get(); }
    catch(optional_unset_error &e) {
        ++check;
    }
    EXPECT_EQ(20,check);

    check=30;
    a.reset();
    try { a.get(); }
    catch(optional_unset_error &e) {
        ++check;
    }
    EXPECT_EQ(31,check);
}

TEST(optionalm,deref) {
    struct foo {
        int a;
        explicit foo(int a_): a(a_) {}
        double value() { return 3.0*a; }
    };

    optional<foo> f=foo(2);
    EXPECT_EQ(6.0,f->value());
    EXPECT_EQ(2,(*f).a);
}

TEST(optionalm,ctor_conv) {
    optional<std::array<int,3>> x{{1,2,3}};
    EXPECT_EQ(3u,x->size());
}

TEST(optionalm,ctor_ref) {
    int v=10;
    optional<int &> a(v);

    EXPECT_EQ(10,a.get());
    v=20;
    EXPECT_EQ(20,a.get());

    optional<int &> b(a),c=b,d=v;
    EXPECT_EQ(&(a.get()),&(b.get()));
    EXPECT_EQ(&(a.get()),&(c.get()));
    EXPECT_EQ(&(a.get()),&(d.get()));
}

TEST(optionalm,assign_returns) {
    optional<int> a=3;

    auto b=(a=4);
    EXPECT_EQ(typeid(optional<int>),typeid(b));

    auto bp=&(a=4);
    EXPECT_EQ(&a,bp);
}

TEST(optionalm,assign_reference) {
    double a=3.0;
    optional<double&> ar;
    optional<double&> br;

    ar = a;
    EXPECT_TRUE(ar);
    *ar = 5.0;
    EXPECT_EQ(5.0, a);

    br = ar;
    EXPECT_TRUE(br);

    *br = 7.0;
    EXPECT_EQ(7.0, a);
}

struct nomove {
    int value;

    nomove(): value(0) {}
    nomove(int i): value(i) {}
    nomove(const nomove &n): value(n.value) {}
    nomove(nomove &&n) = delete;

    nomove &operator=(const nomove &n) { value=n.value; return *this; }

    bool operator==(const nomove &them) const { return them.value==value; }
    bool operator!=(const nomove &them) const { return !(*this==them); }
};

TEST(optionalm,ctor_nomove) {
    optional<nomove> a(nomove(3));
    EXPECT_EQ(nomove(3),a.get());

    optional<nomove> b;
    b=a;
    EXPECT_EQ(nomove(3),b.get());

    b=optional<nomove>(nomove(4));
    EXPECT_EQ(nomove(4),b.get());
}

struct nocopy {
    int value;

    nocopy(): value(0) {}
    nocopy(int i): value(i) {}
    nocopy(const nocopy &n) = delete;
    nocopy(nocopy &&n) {
        value=n.value;
        n.value=0;
    }

    nocopy &operator=(const nocopy &n) = delete;
    nocopy &operator=(nocopy &&n) {
        value=n.value;
        n.value=-1;
        return *this;
    }

    bool operator==(const nocopy &them) const { return them.value==value; }
    bool operator!=(const nocopy &them) const { return !(*this==them); }
};

TEST(optionalm,ctor_nocopy) {
    optional<nocopy> a(nocopy(5));
    EXPECT_EQ(nocopy(5),a.get());

    optional<nocopy> b(std::move(a));
    EXPECT_EQ(nocopy(5),b.get());
    EXPECT_EQ(0,a.get().value);

    b=optional<nocopy>(nocopy(6));
    EXPECT_EQ(nocopy(6),b.get());
}

static optional<double> odd_half(int n) {
    optional<double> h;
    if (n%2==1) h=n/2.0;
    return h;
}

TEST(optionalm,bind) {
    optional<int> a;
    auto b=a.bind(odd_half);

    EXPECT_EQ(typeid(optional<double>),typeid(b));

    a=10;
    b=a.bind(odd_half);
    EXPECT_FALSE((bool)b);

    a=11;
    b=a.bind(odd_half);
    EXPECT_TRUE((bool)b);
    EXPECT_EQ(5.5,b.get());

    b=a >> odd_half >> [](double x) { return (int)x; } >> odd_half;
    EXPECT_TRUE((bool)b);
    EXPECT_EQ(2.5,b.get());
}

TEST(optionalm,void) {
    optional<void> a,b(true),c(a),d=b,e(false);

    EXPECT_FALSE((bool)a);
    EXPECT_TRUE((bool)b);
    EXPECT_FALSE((bool)c);
    EXPECT_TRUE((bool)d);
    EXPECT_TRUE((bool)e);

    auto x=a >> []() { return 1; };
    EXPECT_FALSE((bool)x);

    x=b >> []() { return 1; };
    EXPECT_TRUE((bool)x);
    EXPECT_EQ(1,x.get());
}

TEST(optionalm,bind_to_void) {
    optional<int> a,b(3);

    int call_count=0;
    auto vf=[&call_count](int i) -> void { ++call_count; };

    auto x=a >> vf;
    EXPECT_EQ(typeid(optional<void>),typeid(x));
    EXPECT_FALSE((bool)x);
    EXPECT_EQ(0,call_count);

    call_count=0;
    x=b >> vf;
    EXPECT_TRUE((bool)x);
    EXPECT_EQ(1,call_count);
}

TEST(optionalm,bind_to_optional_void) {
    optional<int> a,b(3),c(4);

    int count=0;
    auto count_if_odd=[&count](int i) {
        return i%2?(++count,optional<void>(true)):optional<void>();
    };

    auto x=a >> count_if_odd;
    EXPECT_EQ(typeid(optional<void>),typeid(x));
    EXPECT_FALSE((bool)x);
    EXPECT_EQ(0,count);

    count=0;
    x=b >> count_if_odd;
    EXPECT_TRUE((bool)x);
    EXPECT_EQ(1,count);

    count=0;
    x=c >> count_if_odd;
    EXPECT_FALSE((bool)x);
    EXPECT_EQ(0,count);
}

TEST(optionalm,bind_with_ref) {
    optional<int> a=10;
    a >> [](int &v) {++v; };
    EXPECT_EQ(11,*a);
}

struct check_cref {
    int operator()(const int &) { return 10; }
    int operator()(int &) { return 11; }
};

TEST(optionalm,bind_constness) {
    check_cref checker;
    optional<int> a=1;
    int v=*(a >> checker);
    EXPECT_EQ(11,v);

    const optional<int> b=1;
    v=*(b >> checker);
    EXPECT_EQ(10,v);
}

TEST(optionalm,conversion) {
    optional<double> a(3),b=5;
    EXPECT_TRUE((bool)a);
    EXPECT_TRUE((bool)b);
    EXPECT_EQ(3.0,a.get());
    EXPECT_EQ(5.0,b.get());

    optional<int> x;
    optional<double> c(x);
    optional<double> d=optional<int>();
    EXPECT_FALSE((bool)c);
    EXPECT_FALSE((bool)d);

    auto doubler=[](double x) { return x*2; };
    auto y=optional<int>(3) >> doubler;
    EXPECT_TRUE((bool)y);
    EXPECT_EQ(6.0,y.get());
}

TEST(optionalm,or_operator) {
    optional<const char *> default_msg="default";
    auto x=(char *)0 | default_msg;
    EXPECT_TRUE((bool)x);
    EXPECT_STREQ("default",x.get());

    auto y="something" | default_msg;
    EXPECT_TRUE((bool)y);
    EXPECT_STREQ("something",y.get());

    optional<int> a(1),b,c(3);
    EXPECT_EQ(1,*(a|b|c));
    EXPECT_EQ(1,*(a|c|b));
    EXPECT_EQ(1,*(b|a|c));
    EXPECT_EQ(3,*(b|c|a));
    EXPECT_EQ(3,*(c|a|b));
    EXPECT_EQ(3,*(c|b|a));
}

TEST(optionalm,and_operator) {
    optional<int> a(1);
    optional<double> b(2.0);

    auto ab=a&b;
    auto ba=b&a;

    EXPECT_EQ(typeid(ab),typeid(b));
    EXPECT_EQ(typeid(ba),typeid(a));
    EXPECT_EQ(2.0,*ab);
    EXPECT_EQ(1,*ba);

    auto zb=false & b;
    EXPECT_EQ(typeid(zb),typeid(b));
    EXPECT_FALSE((bool)zb);

    auto b3=b & 3;
    EXPECT_EQ(typeid(b3),typeid(optional<int>));
    EXPECT_TRUE((bool)b3);
    EXPECT_EQ(3,*b3);
}

TEST(optionalm,provided) {
    std::array<int,3> qs={1,0,3};
    std::array<int,3> ps={14,14,14};
    std::array<int,3> rs;

    std::transform(ps.begin(),ps.end(),qs.begin(),rs.begin(),
        [](int p,int q) { return *( provided(q!=0) >> [=]() { return p/q; } | -1 ); });

    EXPECT_EQ(14,rs[0]);
    EXPECT_EQ(-1,rs[1]);
    EXPECT_EQ(4,rs[2]);
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <cmath>
#include <assert.h>
#include <gtest/gtest.h>
#include "../parallel_async.h"
#include "../task.h"

class ParallelTest : testing::Test { ; };

TEST(ParallelTest, test_parallel)
{
	auto result = asyncply::parallel(
		[]()
		{
			return 9.0;
		},
		[]()
		{
			return 7.0;
		},
		[]()
		{
			return 10.0;
		},
		[]()
		{
			return 6.0;
		});
	ASSERT_EQ(result, 32.0);
}

<commit_msg>Update test_parallel.cpp<commit_after>#include <iostream>
#include <vector>
#include <cmath>
#include <assert.h>
#include <gtest/gtest.h>
#include "../parallel_async.h"
#include "../task.h"

class ParallelTest : testing::Test { ; };

#if 0

TEST(ParallelTest, test_parallel)
{
	auto result = asyncply::parallel(
		[]()
		{
			return 9.0;
		},
		[]()
		{
			return 7.0;
		},
		[]()
		{
			return 10.0;
		},
		[]()
		{
			return 6.0;
		});
	ASSERT_EQ(result, 32.0);
}

#endif
<|endoftext|>


<commit_before>/* This file is part of Ingen.
 * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
 *
 * Ingen 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.
 *
 * Ingen 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 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.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "QueuedEventSource.h"
#include "QueuedEvent.h"
#include "PostProcessor.h"
#include "ThreadManager.h"
#include <sys/mman.h>
#include <iostream>
using std::cout; using std::cerr; using std::endl;

namespace Ingen {

QueuedEventSource::QueuedEventSource(size_t queued_size, size_t stamped_size)
: _front(0),
  _back(0),
  _prepared_back(0),
  _size(queued_size+1),
  _blocking_semaphore(0),
  _stamped_queue(stamped_size)
{
	_events = (QueuedEvent**)calloc(_size, sizeof(QueuedEvent*));

	mlock(_events, _size * sizeof(QueuedEvent*));

	Thread::set_context(THREAD_PRE_PROCESS);
	assert(context() == THREAD_PRE_PROCESS);

	set_name("QueuedEventSource");
	Thread::start();
}

QueuedEventSource::~QueuedEventSource()
{
	Thread::stop();

	free(_events);
}

/** Push an unprepared event onto the queue.
 */
void
QueuedEventSource::push_queued(QueuedEvent* const ev)
{
	assert(!ev->is_prepared());

	if (_events[_back] != NULL) {
		cerr << "[QueuedEventSource] Error: Queue is full!  Event is lost, please report!" << endl;
		delete ev;
	} else {
		_events[_back] = ev;
		_back = (_back + 1) % _size;
		whip();
	}
}

/** Process all events for a cycle.
 *
 * Executed events will be pushed to @a dest.
 */
void
QueuedEventSource::process(PostProcessor& dest, SampleCount nframes, FrameTime cycle_start, FrameTime cycle_end)
{
	assert(ThreadManager::current_thread_id() == THREAD_PROCESS);

	Event* ev = NULL;

	/* Limit the maximum number of queued events to process per cycle.  This
	 * makes the process callback (more) realtime-safe by preventing being
	 * choked by events coming in faster than they can be processed.
	 * FIXME: test this and figure out a good value */
	const unsigned int MAX_QUEUED_EVENTS = nframes / 100;

	unsigned int num_events_processed = 0;

	/* FIXME: Merge these next two loops into one */

	while ((ev = pop_earliest_queued_before(cycle_end))) {
		ev->execute(nframes, cycle_start, cycle_end);
		dest.push(ev);
		if (++num_events_processed > MAX_QUEUED_EVENTS)
			break;
	}

	while ((ev = pop_earliest_stamped_before(cycle_end))) {
		ev->execute(nframes, cycle_start, cycle_end);
		dest.push(ev);
		++num_events_processed;
	}

	if (num_events_processed > 0)
		dest.whip();
	//else
	//	cerr << "NO PROC: queued: " << unprepared_events() << ", stamped: " << !_stamped_queue.empty() << endl;
}

/** Pops the prepared event at the front of the prepare queue, if it exists.
 *
 * This method will only pop events that have been prepared, and are
 * stamped before the time passed.  In other words, it may return NULL
 * even if there are events pending in the queue.  The events returned are
 * actually QueuedEvents, but after this they are "normal" events and the
 * engine deals with them just like a realtime in-band event.  The engine will
 * not use the timestamps of the returned events in any way, since it is free
 * to execute these non-time-stamped events whenever it wants (at whatever rate
 * it wants).
 */
Event*
QueuedEventSource::pop_earliest_queued_before(const SampleCount time)
{
	assert(ThreadManager::current_thread_id() == THREAD_PROCESS);

	QueuedEvent* const front_event = _events[_front];

	// Pop
	if (front_event && front_event->is_prepared() && front_event->time() < time) {
		_events[_front] = NULL;
		_front = (_front + 1) % _size;
		return front_event;
	} else {
		return NULL;
	}
}

// Private //

/** Signal that the blocking event is finished.
 *
 * When this is called preparing will resume.  This MUST be called by
 * blocking events in their post_process() method.
 */
void
QueuedEventSource::unblock()
{
	_blocking_semaphore.post();
}

/** Pre-process a single event */
void
QueuedEventSource::_whipped()
{
	QueuedEvent* const ev = _events[_prepared_back];

	if (!ev)
		return;

	assert(!ev->is_prepared());
	ev->pre_process();
	assert(ev->is_prepared());

	_prepared_back = (_prepared_back+1) % _size;

	// If event was blocking, wait for event to being run through the
	// process thread before preparing the next event
	if (ev->is_blocking())
		_blocking_semaphore.wait();
}

} // namespace Ingen

<commit_msg>Added harsher assertion in hopes of catching bug earlier.<commit_after>/* This file is part of Ingen.
 * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
 *
 * Ingen 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.
 *
 * Ingen 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 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.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "QueuedEventSource.h"
#include "QueuedEvent.h"
#include "PostProcessor.h"
#include "ThreadManager.h"
#include <sys/mman.h>
#include <iostream>
using std::cout; using std::cerr; using std::endl;

namespace Ingen {

QueuedEventSource::QueuedEventSource(size_t queued_size, size_t stamped_size)
: _front(0),
  _back(0),
  _prepared_back(0),
  _size(queued_size+1),
  _blocking_semaphore(0),
  _stamped_queue(stamped_size)
{
	_events = (QueuedEvent**)calloc(_size, sizeof(QueuedEvent*));

	mlock(_events, _size * sizeof(QueuedEvent*));

	Thread::set_context(THREAD_PRE_PROCESS);
	assert(context() == THREAD_PRE_PROCESS);

	set_name("QueuedEventSource");
	Thread::start();
}

QueuedEventSource::~QueuedEventSource()
{
	Thread::stop();

	free(_events);
}

/** Push an unprepared event onto the queue.
 */
void
QueuedEventSource::push_queued(QueuedEvent* const ev)
{
	assert(!ev->is_prepared());

	if (_events[_back] != NULL) {
		cerr << "[QueuedEventSource] Error: Queue is full!  Event is lost, please report!" << endl;
		delete ev;
	} else {
		_events[_back] = ev;
		_back = (_back + 1) % _size;
		whip();
	}
}

/** Process all events for a cycle.
 *
 * Executed events will be pushed to @a dest.
 */
void
QueuedEventSource::process(PostProcessor& dest, SampleCount nframes, FrameTime cycle_start, FrameTime cycle_end)
{
	assert(ThreadManager::current_thread_id() == THREAD_PROCESS);

	Event* ev = NULL;

	/* Limit the maximum number of queued events to process per cycle.  This
	 * makes the process callback (more) realtime-safe by preventing being
	 * choked by events coming in faster than they can be processed.
	 * FIXME: test this and figure out a good value */
	const unsigned int MAX_QUEUED_EVENTS = nframes / 100;

	unsigned int num_events_processed = 0;

	/* FIXME: Merge these next two loops into one */

	while ((ev = pop_earliest_queued_before(cycle_end))) {
		ev->execute(nframes, cycle_start, cycle_end);
		dest.push(ev);
		if (++num_events_processed > MAX_QUEUED_EVENTS)
			break;
	}

	while ((ev = pop_earliest_stamped_before(cycle_end))) {
		ev->execute(nframes, cycle_start, cycle_end);
		dest.push(ev);
		++num_events_processed;
	}

	if (num_events_processed > 0)
		dest.whip();
	//else
	//	cerr << "NO PROC: queued: " << unprepared_events() << ", stamped: " << !_stamped_queue.empty() << endl;
}

/** Pops the prepared event at the front of the prepare queue, if it exists.
 *
 * This method will only pop events that have been prepared, and are
 * stamped before the time passed.  In other words, it may return NULL
 * even if there are events pending in the queue.  The events returned are
 * actually QueuedEvents, but after this they are "normal" events and the
 * engine deals with them just like a realtime in-band event.  The engine will
 * not use the timestamps of the returned events in any way, since it is free
 * to execute these non-time-stamped events whenever it wants (at whatever rate
 * it wants).
 */
Event*
QueuedEventSource::pop_earliest_queued_before(const SampleCount time)
{
	assert(ThreadManager::current_thread_id() == THREAD_PROCESS);

	QueuedEvent* const front_event = _events[_front];

	// Pop
	if (front_event && front_event->is_prepared() && front_event->time() < time) {
		_events[_front] = NULL;
		_front = (_front + 1) % _size;
		return front_event;
	} else {
		return NULL;
	}
}

// Private //

/** Signal that the blocking event is finished.
 *
 * When this is called preparing will resume.  This MUST be called by
 * blocking events in their post_process() method.
 */
void
QueuedEventSource::unblock()
{
	_blocking_semaphore.post();
}

/** Pre-process a single event */
void
QueuedEventSource::_whipped()
{
	QueuedEvent* const ev = _events[_prepared_back];
	assert(ev);

	assert(!ev->is_prepared());
	ev->pre_process();
	assert(ev->is_prepared());

	_prepared_back = (_prepared_back+1) % _size;

	// If event was blocking, wait for event to being run through the
	// process thread before preparing the next event
	if (ev->is_blocking())
		_blocking_semaphore.wait();
}

} // namespace Ingen

<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include "libtorrent/lsd.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/http_tracker_connection.hpp"
#include "libtorrent/xml_parse.hpp"
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp>
#include <boost/thread/mutex.hpp>
#include <cstdlib>

using boost::bind;
using namespace libtorrent;

address_v4 lsd::lsd_multicast_address;
udp::endpoint lsd::lsd_multicast_endpoint;

lsd::lsd(io_service& ios, address const& listen_interface
	, peer_callback_t const& cb)
	: m_callback(cb)
	, m_retry_count(0)
	, m_socket(ios)
	, m_broadcast_timer(ios)
	, m_disabled(false)
{
	// Bittorrent Local discovery multicast address and port
	lsd_multicast_address = address_v4::from_string("239.192.152.143");
	lsd_multicast_endpoint = udp::endpoint(lsd_multicast_address, 6771);

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log.open("lsd.log", std::ios::in | std::ios::out | std::ios::trunc);
#endif
	assert(lsd_multicast_address.is_multicast());
	rebind(listen_interface);
}

lsd::~lsd() {}

void lsd::rebind(address const& listen_interface)
{
	address_v4 local_ip;
	if (listen_interface.is_v4() && listen_interface != address_v4::from_string("0.0.0.0"))
	{
		local_ip = listen_interface.to_v4();
	}
	else
	{
		// make a best guess of the interface we're using and its IP
		udp::resolver r(m_socket.io_service());
		udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(), "0"));
		for (;i != udp::resolver_iterator(); ++i)
		{
			if (i->endpoint().address().is_v4()) break;
		}

		if (i == udp::resolver_iterator())
		{
	#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
			m_log << "local host name did not resolve to an IPv4 address. "
				"disabling local service discovery" << std::endl;
	#endif
			m_disabled = true;
			return;
		}

		local_ip = i->endpoint().address().to_v4();
	}

	try
	{
		// the local interface hasn't changed
		if (m_socket.is_open()
			&& m_socket.local_endpoint().address() == local_ip)
			return;

		m_socket.close();

		using namespace asio::ip::multicast;

		m_socket.open(udp::v4());
		m_socket.set_option(datagram_socket::reuse_address(true));
		m_socket.bind(udp::endpoint(local_ip, 6771));

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << "local ip: " << local_ip << std::endl;
#endif

		m_socket.set_option(join_group(lsd_multicast_address));
		m_socket.set_option(outbound_interface(address_v4()));
		m_socket.set_option(enable_loopback(false));
		m_socket.set_option(hops(255));
	}
	catch (std::exception& e)
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << "socket multicast error " << e.what()
			<< ". disabling local service discovery" << std::endl;
#endif
		m_disabled = true;
		return;
	}
	m_disabled = false;

	setup_receive();
}

void lsd::announce(sha1_hash const& ih, int listen_port)
{
	if (m_disabled) return;

	std::stringstream btsearch;
	btsearch << "BT-SEARCH * HTTP/1.1\r\n"
		"Host: 239.192.152.143:6771\r\n"
		"Port: " << listen_port << "\r\n"
		"Infohash: " << ih << "\r\n"
		"\r\n\r\n";
	std::string const& msg = btsearch.str();

	m_retry_count = 0;
	asio::error_code ec;
	m_socket.send_to(asio::buffer(msg.c_str(), msg.size() - 1)
		, lsd_multicast_endpoint, ec);
	if (ec)
	{
		m_disabled = true;
		return;
	}

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " ==> announce: ih: " << ih << " port: " << listen_port << std::endl;
#endif

	m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count));
	m_broadcast_timer.async_wait(bind(&lsd::resend_announce, this, _1, msg));
}

void lsd::resend_announce(asio::error_code const& e, std::string msg) try
{
	if (e) return;

	m_socket.send_to(asio::buffer(msg, msg.size() - 1)
		, lsd_multicast_endpoint);

	++m_retry_count;
	if (m_retry_count >= 5)
		return;

	m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count));
	m_broadcast_timer.async_wait(bind(&lsd::resend_announce, this, _1, msg));
}
catch (std::exception&)
{}

void lsd::on_announce(asio::error_code const& e
	, std::size_t bytes_transferred)
{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << time_now_string()
			<< " <== on_announce" << std::endl;
#endif
	using namespace libtorrent::detail;
	if (e) return;

	char* p = m_receive_buffer;
	char* end = m_receive_buffer + bytes_transferred;
	char* line = std::find(p, end, '\n');
	for (char* i = p; i < line; ++i) *i = std::tolower(*i);
	if (line == end || std::strcmp("bt-search", p))
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << time_now_string()
			<< " <== Got incorrect method in announce" << std::string(p, line) << std::endl;
#endif
		setup_receive();
		return;
	}
	p = line + 1;
	int port = 0;
	sha1_hash ih(0);
	while (p != end)
	{
		line = std::find(p, end, '\n');
		if (line == end) break;
		*line = 0;
		for (char* i = p; i < line; ++i) *i = std::tolower(*i);
		if (!strcmp(p, "port:"))
		{
			port = atoi(p + 5);
		}
		else if (!strcmp(p, "infohash:"))
		{
			ih = boost::lexical_cast<sha1_hash>(p + 9);
		}
		p = line + 1;
	}

	if (!ih.is_all_zeros() && port != 0)
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << time_now_string()
			<< " <== Got incoming local announce " << m_remote.address()
			<< ":" << port << " ih: " << ih << std::endl;
#endif
		// we got an announce, pass it on through the callback
		try { m_callback(tcp::endpoint(m_remote.address(), port), ih); }
		catch (std::exception&) {}
	}
	setup_receive();
}

void lsd::setup_receive() try
{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " *** setup_receive" << std::endl;
#endif
	assert(m_socket.is_open());
	m_socket.async_receive_from(asio::buffer(m_receive_buffer
		, sizeof(m_receive_buffer)), m_remote, bind(&lsd::on_announce, this, _1, _2));
}
catch (std::exception&)
{}

void lsd::close()
{
	m_socket.close();
}

<commit_msg>fixed typo in last check in<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include "libtorrent/lsd.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/http_tracker_connection.hpp"
#include "libtorrent/xml_parse.hpp"
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp>
#include <boost/thread/mutex.hpp>
#include <cstdlib>

using boost::bind;
using namespace libtorrent;

address_v4 lsd::lsd_multicast_address;
udp::endpoint lsd::lsd_multicast_endpoint;

lsd::lsd(io_service& ios, address const& listen_interface
	, peer_callback_t const& cb)
	: m_callback(cb)
	, m_retry_count(0)
	, m_socket(ios)
	, m_broadcast_timer(ios)
	, m_disabled(false)
{
	// Bittorrent Local discovery multicast address and port
	lsd_multicast_address = address_v4::from_string("239.192.152.143");
	lsd_multicast_endpoint = udp::endpoint(lsd_multicast_address, 6771);

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log.open("lsd.log", std::ios::in | std::ios::out | std::ios::trunc);
#endif
	assert(lsd_multicast_address.is_multicast());
	rebind(listen_interface);
}

lsd::~lsd() {}

void lsd::rebind(address const& listen_interface)
{
	address_v4 local_ip;
	if (listen_interface.is_v4() && listen_interface != address_v4::from_string("0.0.0.0"))
	{
		local_ip = listen_interface.to_v4();
	}
	else
	{
		// make a best guess of the interface we're using and its IP
		udp::resolver r(m_socket.io_service());
		udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(), "0"));
		for (;i != udp::resolver_iterator(); ++i)
		{
			if (i->endpoint().address().is_v4()) break;
		}

		if (i == udp::resolver_iterator())
		{
	#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
			m_log << "local host name did not resolve to an IPv4 address. "
				"disabling local service discovery" << std::endl;
	#endif
			m_disabled = true;
			return;
		}

		local_ip = i->endpoint().address().to_v4();
	}

	try
	{
		// the local interface hasn't changed
		if (m_socket.is_open()
			&& m_socket.local_endpoint().address() == local_ip)
			return;

		m_socket.close();

		using namespace asio::ip::multicast;

		m_socket.open(udp::v4());
		m_socket.set_option(datagram_socket::reuse_address(true));
		m_socket.bind(udp::endpoint(local_ip, 6771));

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << "local ip: " << local_ip << std::endl;
#endif

		m_socket.set_option(join_group(lsd_multicast_address));
		m_socket.set_option(outbound_interface(address_v4()));
		m_socket.set_option(enable_loopback(false));
		m_socket.set_option(hops(255));
	}
	catch (std::exception& e)
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << "socket multicast error " << e.what()
			<< ". disabling local service discovery" << std::endl;
#endif
		m_disabled = true;
		return;
	}
	m_disabled = false;

	setup_receive();
}

void lsd::announce(sha1_hash const& ih, int listen_port)
{
	if (m_disabled) return;

	std::stringstream btsearch;
	btsearch << "BT-SEARCH * HTTP/1.1\r\n"
		"Host: 239.192.152.143:6771\r\n"
		"Port: " << listen_port << "\r\n"
		"Infohash: " << ih << "\r\n"
		"\r\n\r\n";
	std::string const& msg = btsearch.str();

	m_retry_count = 0;
	asio::error_code ec;
	m_socket.send_to(asio::buffer(msg.c_str(), msg.size() - 1)
		, lsd_multicast_endpoint, 0, ec);
	if (ec)
	{
		m_disabled = true;
		return;
	}

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " ==> announce: ih: " << ih << " port: " << listen_port << std::endl;
#endif

	m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count));
	m_broadcast_timer.async_wait(bind(&lsd::resend_announce, this, _1, msg));
}

void lsd::resend_announce(asio::error_code const& e, std::string msg) try
{
	if (e) return;

	m_socket.send_to(asio::buffer(msg, msg.size() - 1)
		, lsd_multicast_endpoint);

	++m_retry_count;
	if (m_retry_count >= 5)
		return;

	m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count));
	m_broadcast_timer.async_wait(bind(&lsd::resend_announce, this, _1, msg));
}
catch (std::exception&)
{}

void lsd::on_announce(asio::error_code const& e
	, std::size_t bytes_transferred)
{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << time_now_string()
			<< " <== on_announce" << std::endl;
#endif
	using namespace libtorrent::detail;
	if (e) return;

	char* p = m_receive_buffer;
	char* end = m_receive_buffer + bytes_transferred;
	char* line = std::find(p, end, '\n');
	for (char* i = p; i < line; ++i) *i = std::tolower(*i);
	if (line == end || std::strcmp("bt-search", p))
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << time_now_string()
			<< " <== Got incorrect method in announce" << std::string(p, line) << std::endl;
#endif
		setup_receive();
		return;
	}
	p = line + 1;
	int port = 0;
	sha1_hash ih(0);
	while (p != end)
	{
		line = std::find(p, end, '\n');
		if (line == end) break;
		*line = 0;
		for (char* i = p; i < line; ++i) *i = std::tolower(*i);
		if (!strcmp(p, "port:"))
		{
			port = atoi(p + 5);
		}
		else if (!strcmp(p, "infohash:"))
		{
			ih = boost::lexical_cast<sha1_hash>(p + 9);
		}
		p = line + 1;
	}

	if (!ih.is_all_zeros() && port != 0)
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << time_now_string()
			<< " <== Got incoming local announce " << m_remote.address()
			<< ":" << port << " ih: " << ih << std::endl;
#endif
		// we got an announce, pass it on through the callback
		try { m_callback(tcp::endpoint(m_remote.address(), port), ih); }
		catch (std::exception&) {}
	}
	setup_receive();
}

void lsd::setup_receive() try
{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " *** setup_receive" << std::endl;
#endif
	assert(m_socket.is_open());
	m_socket.async_receive_from(asio::buffer(m_receive_buffer
		, sizeof(m_receive_buffer)), m_remote, bind(&lsd::on_announce, this, _1, _2));
}
catch (std::exception&)
{}

void lsd::close()
{
	m_socket.close();
}

<|endoftext|>