<commit_before>/**
 * Clever programming language
 * Copyright (c) Clever Team
 *
 * This file is distributed under the MIT license. See LICENSE for details.
 */

#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <map>
#include <string>
#ifndef __APPLE__
# include <ffi.h>
#else
# include <ffi/ffi.h>
#endif
#ifdef CLEVER_WIN32
# include <windows.h>
#else
# include <dlfcn.h>
#endif
#include "core/clever.h"
#include "modules/std/core/function.h"
#include "types/type.h"
#include "core/value.h"
#include "modules/std/ffi/ffi.h"
#include "modules/std/ffi/ffistruct.h"
#include "modules/std/ffi/ffitypes.h"

namespace clever { namespace modules { namespace std {

extern "C" {
typedef void (*ffi_call_func)();
}

#if defined(CLEVER_WIN32)
static const char* CLEVER_DYLIB_EXT = ".dll";
#elif defined(CLEVER_APPLE)
static const char* CLEVER_DYLIB_EXT = ".dylib";
#else
static const char* CLEVER_DYLIB_EXT = ".so";
#endif

static ffi_type* _find_ffi_type(FFIType type)
{
	switch (type) {
		case FFIINT:     return &ffi_type_sint32;
		case FFIDOUBLE:  return &ffi_type_double;
		case FFIBOOL:    return &ffi_type_schar;
		case FFIPOINTER: return &ffi_type_pointer;
		case FFIVOID:    return &ffi_type_void;
		case FFISTRUCT:  return &ffi_type_pointer;
		case FFISTRING:  return &ffi_type_pointer;
	}
	return NULL;
}

static bool _load_lib(FFIData* h, const CString* libname)
{
	if (h->m_lib_handler != NULL) {
		dlclose(h->m_lib_handler);
	}

	h->m_lib_name = *libname;
	h->m_lib_handler = dlopen((h->m_lib_name + CLEVER_DYLIB_EXT).c_str(), RTLD_LAZY);

	return h->m_lib_handler != NULL;
}

/* XXX(heuripedes): please use this function instead of directly calling dlsym
 *                  so we don't have to maintain a zilion versions of the same code.
 */
static inline ffi_call_func _ffi_dlsym(void* handler, const char* name)
{
#ifdef CLEVER_WIN32
#  error "Dynamic library symbol loading support is not yet available for windows. Please disable this module."
#endif

	/* XXX(heuripedes): iso c++ forbids casts between pointer-to-function and
	 *                  pointer-to-object as .code and .data pointers are not
	 *                  garanteed to be compatible in some platforms.
	 *                  THE CODE BELLOW IS A HACK TO SHUT THE COMPILER UP.
	 */
	union {
		void *p;
		ffi_call_func fp;
	} u;

	u.p = dlsym(handler, name);

	return u.fp;
}

static inline ffi_call_func _ffi_get_pf(void* lib_handler, const CString* func)
{
	ffi_call_func fpf = _ffi_dlsym(lib_handler, func->c_str());

	if (fpf == NULL) {
		return 0;
	}

	return fpf;
}

static void _ffi_call(Value* result, ffi_call_func pf, size_t n_args,
					  FFIType rt, const ::std::vector<Value*>& args, size_t offset,
					  ExtMemberType* ext_args_types = 0)
{
	ffi_cif cif;
	ffi_type* ffi_rt = _find_ffi_type(rt);
	ffi_type** ffi_args = (ffi_type**) malloc(n_args * sizeof(ffi_type*));
	void** ffi_values = (void**) malloc(n_args * sizeof(void*));

	for (size_t i = 0; i < n_args; ++i) {
		Value* v = args.at(i + offset);
		FFIType arg_type = FFIVOID;

		if (ext_args_types) {
			arg_type = ext_args_types->at(i + 1);
		}

		if (v->isInt()) {
			if (arg_type == FFIVOID or arg_type == FFIINT) {
				ffi_args[i] = _find_ffi_type(FFIINT);

				int* vi= (int*) malloc(sizeof(int));

				*vi = v->getInt();

				ffi_values[i] =  vi;
			} else {
				clever_error("Argument %N isn't a int!\n", i + 1);
			}
		} else if (v->isBool()) {
			if (arg_type == FFIVOID or arg_type == FFIBOOL) {
				ffi_args[i] = _find_ffi_type(FFIBOOL);

				char* b = (char*) malloc (sizeof(char));

				*b = v->getBool();

				ffi_values[i] = b;
			} else {
				clever_error("Argument %N isn't a bool!\n", i + 1);
			}
		} else if (v->isStr()) {
			if (arg_type == FFIVOID or arg_type == FFISTRING) {
				const char* st = v->getStr()->c_str();
				char** s = (char**) malloc(sizeof(char*));

				*s = (char*) malloc (sizeof(char) * (strlen(st) + 1));

				strcpy(*s, st);
				(*s)[strlen(st)] = '\0';

				ffi_args[i] = _find_ffi_type(FFISTRING);

				ffi_values[i] =  s;
			} else {
				clever_error("Argument %N isn't a string!\n", i + 1);
			}
		} else if (v->isDouble()) {
			if (arg_type == FFIVOID or arg_type == FFIDOUBLE) {
				ffi_args[i] = _find_ffi_type(FFIDOUBLE);;

				double* d = (double*) malloc(sizeof(double));

				*d = v->getDouble();

				ffi_values[i] = d;
			} else {
				clever_error("Argument %N isn't a double!\n", i + 1);
			}
		} else {
			if (arg_type == FFIVOID or arg_type == FFIPOINTER) {
				ffi_args[i] = _find_ffi_type(FFIPOINTER);

				FFIStructData* obj = static_cast<FFIStructData*>(v->getObj());

				ffi_values[i] = &(obj->data);
			} else {
				clever_error("Argument %N isn't a pointer!\n", i + 1);
			}
		}
	}

	if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, n_args, ffi_rt, ffi_args) != FFI_OK) {
		result->setBool(false);
		return;
	}

#ifndef CLEVER_WIN32
	if (rt == FFIINT) {
		int vi;

		ffi_call(&cif, pf, &vi, ffi_values);

		result->setInt(vi);
	} else if (rt == FFIDOUBLE) {
		double vd;

		ffi_call(&cif, pf, &vd, ffi_values);

		result->setDouble(vd);
	} else if (rt == FFIBOOL) {
		bool vb;

		ffi_call(&cif, pf, &vb, ffi_values);

		result->setBool(vb);
	} else if (rt == FFISTRING) {
		char* vs[1];

		ffi_call(&cif, pf, &vs, ffi_values);

		result->setStr(CSTRING(*vs));

		free(vs[0]);
	} else if (rt == FFIBOOL) {
		char vc;

		ffi_call(&cif, pf, &vc, ffi_values);

		result->setBool(vc);
	} else if (rt == FFIVOID) {
		ffi_call(&cif, pf, NULL, ffi_values);

		result->setBool(true);
	} else if (rt == FFIPOINTER) {
		//FFIObjectValue* x = static_cast<FFIObjectValue*> (retval->getDataValue());

		//if ( x == NULL ) x = new FFIObjectValue();

		//ffi_call(&cif, pf, &(x->pointer), ffi_values);

		//CLEVER_RETURN_DATA_VALUE(x);
	} else {
		result->setBool(true);
	}
#endif

	for (size_t i = 0; i < n_args; ++i) {
		Value* v = args.at(i + offset);

		if (v->isInt()) {
			free((int*)ffi_values[i]);
		} else if (v->isBool()) {
			free((char*)ffi_values[i]);
		} else if (v->isStr()) {
			char** v= (char**)ffi_values[i];
			free(v[0]);
			free(v);
		} else if (v->isDouble()) {
			free((double*)ffi_values[i]);
		} //else if (CLEVER_ARG_IS_INTERNAL(i)) {
		//}
	}

	free(ffi_args);
	free(ffi_values);
}

TypeObject* FFI::allocData(CLEVER_TYPE_CTOR_ARGS) const
{
	FFIData* data = new FFIData(this);
	const CString* name = args->at(0)->getStr();

	if (!_load_lib(data, name)) {
		clever_error("Failed to open %S!", name);
	}

	return data;
}

// FFILib constructor
CLEVER_METHOD(FFI::ctor)
{
	if (!clever_check_args("s")) {
		return;
	}

	result->setObj(this, allocData(&args));
}

FFIData::~FFIData()
{
	if (m_lib_handler) {
		dlclose(m_lib_handler);
	}
}

Value* FFIData::getMember(const CString* name) const
{
	const_cast<FFIData*>(this)->m_func_name = *name;
	Value* fvalue = TypeObject::getMember(name);

	if (fvalue == NULL) {
		return m_ffi->getCallHandler();
	}

	return fvalue;
}

CLEVER_METHOD(FFI::callThisFunction)
{
	FFIData* handler = CLEVER_GET_OBJECT(FFIData*, CLEVER_THIS());
	const CString func = handler->m_func_name;

	ExtStruct* ext_struct = FFITypes::getStruct(handler->m_lib_name);

	FFIType rt = FFIVOID;

	size_t n_args = args.size();
	size_t offset = 0;
	ExtMemberType* args_types = 0;

	if (ext_struct) {
		args_types = ext_struct->getArgs(func);
		n_args = args_types->size() - 1;
		rt = args_types->at(0);
	} else {
		n_args--;
		offset = 1;
		rt = static_cast<FFIType>(args.at(0)->getInt());
	}

	ffi_call_func pf;

	pf = _ffi_dlsym(handler->m_lib_handler, func.c_str());

	if (pf == NULL) {
		clever_throw("function `%S' don't exist!", &func);
		return;
	}

	_ffi_call(result, pf, n_args, rt, args, offset, args_types);
}

// FFILib.exec()
CLEVER_METHOD(FFI::exec)
{
	if (!clever_check_args("ss*")) {
		return;
	}

	const CString* lib = args.at(0)->getStr();
	const CString* func = args.at(1)->getStr();
	FFIType rt = static_cast<FFIType>(args.at(2)->getInt());
	size_t n_args = args.size() - 3;

#ifndef CLEVER_WIN32
	void* lib_handler = dlopen((*lib + CLEVER_DYLIB_EXT).c_str(), RTLD_LAZY);
	ffi_call_func pf = _ffi_get_pf(lib_handler,
								   func);
	if (pf == 0) {
		clever_throw("function `%S' don't exist!", func);
		return;
	}
#endif

	_ffi_call(result, pf, n_args, rt, args, 3);
	dlclose(lib_handler);
}

// FFILib.call()
CLEVER_METHOD(FFI::call)
{
	if (!clever_check_args("s*")) {
		return;
	}

	FFIData* handler = CLEVER_GET_OBJECT(FFIData*, CLEVER_THIS());

	const CString* func = args.at(0)->getStr();
	FFIType rt = static_cast<FFIType>(args.at(1)->getInt());
	size_t n_args = args.size() - 2;

#ifndef CLEVER_WIN32
	ffi_call_func pf = _ffi_get_pf(handler->m_lib_handler,
								   func);
	if (pf == 0) {
		clever_throw("function `%S' don't exist!", func);
		return;
	}
#endif

	_ffi_call(result, pf, n_args, rt, args, 2);
}

// FFILib.load()
CLEVER_METHOD(FFI::load)
{
	FFIData* data = CLEVER_GET_OBJECT(FFIData*, CLEVER_THIS());

	if (!clever_check_args("s")) {
		return;
	}

	result->setBool(_load_lib(data, args.at(0)->getStr()));
}

// FFILib.unload()
CLEVER_METHOD(FFI::unload)
{
	FFIData* data = CLEVER_GET_OBJECT(FFIData*, CLEVER_THIS());

	if (data->m_lib_handler != NULL) {
		dlclose(data->m_lib_handler);
		data->m_lib_handler = NULL;
	}
}

// FFI type initialization
CLEVER_TYPE_INIT(FFI::init)
{
	setConstructor((MethodPtr) &FFI::ctor);

	addMethod(new Function("callThisFunction", (MethodPtr)&FFI::callThisFunction));
	addMethod(new Function("call",   (MethodPtr)&FFI::call));
	addMethod(new Function("exec",   (MethodPtr)&FFI::exec))->setStatic();
	addMethod(new Function("load",   (MethodPtr)&FFI::load));
	addMethod(new Function("unload", (MethodPtr)&FFI::unload));

	m_call_handler = new Value;
	m_call_handler->setObj(CLEVER_FUNC_TYPE,
		new Function("callThisFunction", (MethodPtr)&FFI::callThisFunction));
}

// FFI module initialization
CLEVER_MODULE_INIT(FFIModule)
{
	addType(new FFI);
	addType(new FFIStruct);
	addType(new FFITypes);
}

}}} // clever::modules::std
<commit_msg>FFI function declaration added<commit_after>/**
 * Clever programming language
 * Copyright (c) Clever Team
 *
 * This file is distributed under the MIT license. See LICENSE for details.
 */

#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <map>
#include <string>
#ifndef __APPLE__
# include <ffi.h>
#else
# include <ffi/ffi.h>
#endif
#ifdef CLEVER_WIN32
# include <windows.h>
#else
# include <dlfcn.h>
#endif
#include "core/clever.h"
#include "modules/std/core/function.h"
#include "types/type.h"
#include "core/value.h"
#include "modules/std/ffi/ffi.h"
#include "modules/std/ffi/ffistruct.h"
#include "modules/std/ffi/ffitypes.h"

namespace clever { namespace modules { namespace std {

extern "C" {
typedef void (*ffi_call_func)();
}

#if defined(CLEVER_WIN32)
static const char* CLEVER_DYLIB_EXT = ".dll";
#elif defined(CLEVER_APPLE)
static const char* CLEVER_DYLIB_EXT = ".dylib";
#else
static const char* CLEVER_DYLIB_EXT = ".so";
#endif

static ffi_type* _find_ffi_type(FFIType type)
{
	switch (type) {
		case FFIINT:     return &ffi_type_sint32;
		case FFIDOUBLE:  return &ffi_type_double;
		case FFIBOOL:    return &ffi_type_schar;
		case FFIPOINTER: return &ffi_type_pointer;
		case FFIVOID:    return &ffi_type_void;
		case FFISTRUCT:  return &ffi_type_pointer;
		case FFISTRING:  return &ffi_type_pointer;
	}
	return NULL;
}

static bool _load_lib(FFIData* h, const CString* libname)
{
	if (h->m_lib_handler != NULL) {
		dlclose(h->m_lib_handler);
	}

	h->m_lib_name = *libname;
	h->m_lib_handler = dlopen((h->m_lib_name + CLEVER_DYLIB_EXT).c_str(), RTLD_LAZY);

	return h->m_lib_handler != NULL;
}

/* XXX(heuripedes): please use this function instead of directly calling dlsym
 *                  so we don't have to maintain a zilion versions of the same code.
 */
static inline ffi_call_func _ffi_dlsym(void* handler, const char* name)
{
#ifdef CLEVER_WIN32
#  error "Dynamic library symbol loading support is not yet available for windows. Please disable this module."
#endif

	/* XXX(heuripedes): iso c++ forbids casts between pointer-to-function and
	 *                  pointer-to-object as .code and .data pointers are not
	 *                  garanteed to be compatible in some platforms.
	 *                  THE CODE BELLOW IS A HACK TO SHUT THE COMPILER UP.
	 */
	union {
		void *p;
		ffi_call_func fp;
	} u;

	u.p = dlsym(handler, name);

	return u.fp;
}

static inline ffi_call_func _ffi_get_pf(void* lib_handler, const CString* func)
{
	ffi_call_func fpf = _ffi_dlsym(lib_handler, func->c_str());

	if (fpf == NULL) {
		return 0;
	}

	return fpf;
}

static void _ffi_call(Value* result, ffi_call_func pf, size_t n_args,
					  FFIType rt, const ::std::vector<Value*>& args, size_t offset,
					  ExtMemberType* ext_args_types = 0)
{
	ffi_cif cif;
	ffi_type* ffi_rt = _find_ffi_type(rt);
	ffi_type** ffi_args = (ffi_type**) malloc(n_args * sizeof(ffi_type*));
	void** ffi_values = (void**) malloc(n_args * sizeof(void*));

	for (size_t i = 0; i < n_args; ++i) {
		Value* v = args.at(i + offset);
		FFIType arg_type = FFIVOID;

		if (ext_args_types) {
			arg_type = ext_args_types->at(i + 1);
		}

		if (v->isInt()) {
			if (arg_type == FFIVOID or arg_type == FFIINT) {
				ffi_args[i] = _find_ffi_type(FFIINT);

				int* vi= (int*) malloc(sizeof(int));

				*vi = v->getInt();

				ffi_values[i] =  vi;
			} else {
				clever_error("Argument %N isn't a int!\n", i + 1);
				return;
			}
		} else if (v->isBool()) {
			if (arg_type == FFIVOID or arg_type == FFIBOOL) {
				ffi_args[i] = _find_ffi_type(FFIBOOL);

				char* b = (char*) malloc (sizeof(char));

				*b = v->getBool();

				ffi_values[i] = b;
			} else {
				clever_error("Argument %N isn't a bool!\n", i + 1);
				return;
			}
		} else if (v->isStr()) {
			if (arg_type == FFIVOID or arg_type == FFISTRING) {
				const char* st = v->getStr()->c_str();
				char** s = (char**) malloc(sizeof(char*));

				*s = (char*) malloc (sizeof(char) * (strlen(st) + 1));

				strcpy(*s, st);
				(*s)[strlen(st)] = '\0';

				ffi_args[i] = _find_ffi_type(FFISTRING);

				ffi_values[i] =  s;
			} else {
				clever_error("Argument %N isn't a string!\n", i + 1);
				return;
			}
		} else if (v->isDouble()) {
			if (arg_type == FFIVOID or arg_type == FFIDOUBLE) {
				ffi_args[i] = _find_ffi_type(FFIDOUBLE);;

				double* d = (double*) malloc(sizeof(double));

				*d = v->getDouble();

				ffi_values[i] = d;
			} else {
				clever_error("Argument %N isn't a double!\n", i + 1);
				return;
			}
		} else {
			if (arg_type == FFIVOID or arg_type == FFIPOINTER) {
				ffi_args[i] = _find_ffi_type(FFIPOINTER);

				FFIStructData* obj = static_cast<FFIStructData*>(v->getObj());

				ffi_values[i] = &(obj->data);
			} else {
				clever_error("Argument %N isn't a pointer!\n", i + 1);
				return;
			}
		}
	}

	if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, n_args, ffi_rt, ffi_args) != FFI_OK) {
		result->setBool(false);
		return;
	}

#ifndef CLEVER_WIN32
	if (rt == FFIINT) {
		int vi;

		ffi_call(&cif, pf, &vi, ffi_values);

		result->setInt(vi);
	} else if (rt == FFIDOUBLE) {
		double vd;

		ffi_call(&cif, pf, &vd, ffi_values);

		result->setDouble(vd);
	} else if (rt == FFIBOOL) {
		bool vb;

		ffi_call(&cif, pf, &vb, ffi_values);

		result->setBool(vb);
	} else if (rt == FFISTRING) {
		char* vs[1];

		ffi_call(&cif, pf, &vs, ffi_values);

		result->setStr(CSTRING(*vs));

		free(vs[0]);
	} else if (rt == FFIBOOL) {
		char vc;

		ffi_call(&cif, pf, &vc, ffi_values);

		result->setBool(vc);
	} else if (rt == FFIVOID) {
		ffi_call(&cif, pf, NULL, ffi_values);

		result->setBool(true);
	} else if (rt == FFIPOINTER) {
		//FFIObjectValue* x = static_cast<FFIObjectValue*> (retval->getDataValue());

		//if ( x == NULL ) x = new FFIObjectValue();

		//ffi_call(&cif, pf, &(x->pointer), ffi_values);

		//CLEVER_RETURN_DATA_VALUE(x);
	} else {
		result->setBool(true);
	}
#endif

	for (size_t i = 0; i < n_args; ++i) {
		Value* v = args.at(i + offset);

		if (v->isInt()) {
			free((int*)ffi_values[i]);
		} else if (v->isBool()) {
			free((char*)ffi_values[i]);
		} else if (v->isStr()) {
			char** v= (char**)ffi_values[i];
			free(v[0]);
			free(v);
		} else if (v->isDouble()) {
			free((double*)ffi_values[i]);
		} //else if (CLEVER_ARG_IS_INTERNAL(i)) {
		//}
	}

	free(ffi_args);
	free(ffi_values);
}

TypeObject* FFI::allocData(CLEVER_TYPE_CTOR_ARGS) const
{
	FFIData* data = new FFIData(this);
	const CString* name = args->at(0)->getStr();

	if (!_load_lib(data, name)) {
		clever_error("Failed to open %S!", name);
	}

	return data;
}

// FFILib constructor
CLEVER_METHOD(FFI::ctor)
{
	if (!clever_check_args("s")) {
		return;
	}

	result->setObj(this, allocData(&args));
}

FFIData::~FFIData()
{
	if (m_lib_handler) {
		dlclose(m_lib_handler);
	}
}

Value* FFIData::getMember(const CString* name) const
{
	const_cast<FFIData*>(this)->m_func_name = *name;
	Value* fvalue = TypeObject::getMember(name);

	if (fvalue == NULL) {
		return m_ffi->getCallHandler();
	}

	return fvalue;
}

CLEVER_METHOD(FFI::callThisFunction)
{
	FFIData* handler = CLEVER_GET_OBJECT(FFIData*, CLEVER_THIS());
	const CString func = handler->m_func_name;

	ExtStruct* ext_struct = FFITypes::getStruct(handler->m_lib_name);

	FFIType rt = FFIVOID;

	size_t n_args = args.size();
	size_t offset = 0;
	ExtMemberType* args_types = 0;

	if (ext_struct) {
		args_types = ext_struct->getArgs(func);
		n_args = args_types->size() - 1;
		rt = args_types->at(0);
	} else {
		n_args--;
		offset = 1;
		rt = static_cast<FFIType>(args.at(0)->getInt());
	}

	ffi_call_func pf;

	pf = _ffi_dlsym(handler->m_lib_handler, func.c_str());

	if (pf == NULL) {
		clever_throw("function `%S' don't exist!", &func);
		return;
	}

	_ffi_call(result, pf, n_args, rt, args, offset, args_types);
}

// FFILib.exec()
CLEVER_METHOD(FFI::exec)
{
	if (!clever_check_args("ss*")) {
		return;
	}

	const CString* lib = args.at(0)->getStr();
	const CString* func = args.at(1)->getStr();
	FFIType rt = static_cast<FFIType>(args.at(2)->getInt());
	size_t n_args = args.size() - 3;

#ifndef CLEVER_WIN32
	void* lib_handler = dlopen((*lib + CLEVER_DYLIB_EXT).c_str(), RTLD_LAZY);
	ffi_call_func pf = _ffi_get_pf(lib_handler,
								   func);
	if (pf == 0) {
		clever_throw("function `%S' don't exist!", func);
		return;
	}
#endif

	_ffi_call(result, pf, n_args, rt, args, 3);
	dlclose(lib_handler);
}

// FFILib.call()
CLEVER_METHOD(FFI::call)
{
	if (!clever_check_args("s*")) {
		return;
	}

	FFIData* handler = CLEVER_GET_OBJECT(FFIData*, CLEVER_THIS());

	const CString* func = args.at(0)->getStr();
	FFIType rt = static_cast<FFIType>(args.at(1)->getInt());
	size_t n_args = args.size() - 2;

#ifndef CLEVER_WIN32
	ffi_call_func pf = _ffi_get_pf(handler->m_lib_handler,
								   func);
	if (pf == 0) {
		clever_throw("function `%S' don't exist!", func);
		return;
	}
#endif

	_ffi_call(result, pf, n_args, rt, args, 2);
}

// FFILib.load()
CLEVER_METHOD(FFI::load)
{
	FFIData* data = CLEVER_GET_OBJECT(FFIData*, CLEVER_THIS());

	if (!clever_check_args("s")) {
		return;
	}

	result->setBool(_load_lib(data, args.at(0)->getStr()));
}

// FFILib.unload()
CLEVER_METHOD(FFI::unload)
{
	FFIData* data = CLEVER_GET_OBJECT(FFIData*, CLEVER_THIS());

	if (data->m_lib_handler != NULL) {
		dlclose(data->m_lib_handler);
		data->m_lib_handler = NULL;
	}
}

// FFI type initialization
CLEVER_TYPE_INIT(FFI::init)
{
	setConstructor((MethodPtr) &FFI::ctor);

	addMethod(new Function("callThisFunction", (MethodPtr)&FFI::callThisFunction));
	addMethod(new Function("call",   (MethodPtr)&FFI::call));
	addMethod(new Function("exec",   (MethodPtr)&FFI::exec))->setStatic();
	addMethod(new Function("load",   (MethodPtr)&FFI::load));
	addMethod(new Function("unload", (MethodPtr)&FFI::unload));

	m_call_handler = new Value;
	m_call_handler->setObj(CLEVER_FUNC_TYPE,
		new Function("callThisFunction", (MethodPtr)&FFI::callThisFunction));
}

// FFI module initialization
CLEVER_MODULE_INIT(FFIModule)
{
	addType(new FFI);
	addType(new FFIStruct);
	addType(new FFITypes);
}

}}} // clever::modules::std
<|endoftext|>


<commit_before>// Two dimensional grid class

#include <vector>
#include <cassert>
#include <iostream>

template<class T>
class Grid2D
{
    public:
        // This is the default constructor. Call it without any
        // arguments and it will return a 0x0 matrix (initialized
        // with 0)
        // Example
        //      Grid2D<double> g;
        Grid2D()
            : rows(0)
            , cols(0)
            , data(std::vector<T>(0))
            , blocking(0)
            {}

        // This is the normal constructor. Gets you a rowsxcols matrix
        // with optinal default value value
        // Example
        //      Grid2D<double> square(3, 3, 5.0);
        Grid2D(const size_t rows, const size_t cols, T value=0, const size_t blocking = 0)
            : rows(rows)
            , cols(cols)
            , data(std::vector<T>(rows*cols, value))
            , blocking(0)
            {}

        const size_t getRows() const { return rows; }
        const size_t getCols() const { return cols; }

        const size_t getBlockingFactor() const { return blocking; }
        void setBlockingFactor(const size_t factor) {
            // assert rows and cols beeing multiple of the blocking factor
            assert(rows % factor == 0);
            assert(cols % factor == 0);
            assert(factor > 1 && factor <= std::min(rows, cols));

            blocking = factor;
        }

        void getBlock(const size_t I, const size_t J, Grid2D<T>& block) {
            // assert a useful blocking factor
            assert(blocking > 1);
            assert(blocking <= std::min(rows, cols));
            assert(rows % blocking == 0 && cols % blocking == 0);

            // assert i/j within bounds
            assert(I < rows/blocking && J < cols/blocking);

            // assert block beeing of size blocking x blocking
            assert(block.getCols() == blocking && block.getRows() == blocking);

            size_t k = 0;
            for(size_t i = 0; i < blocking; ++i) {
                for(size_t j = 0; j < blocking; ++j) {
                    block.data[k++] = data[(I*blocking+i)*cols + J*blocking+j];
                }
            }
            assert(k == blocking * blocking);
        }

        void setBlock(const size_t I, const size_t J, const Grid2D<T>& block) {
            // assert a useful blocking factor
            assert(blocking > 1);
            assert(blocking <= std::min(rows, cols));
            assert(rows % blocking == 0 && cols % blocking == 0);

            // assert i/j within bounds
            assert(I < rows/blocking && J < cols/blocking);

            // assert block beeing of size blocking x blocking
            assert(block.getCols() == blocking && block.getRows() == blocking);

            size_t k = 0;
            for(size_t i = 0; i < blocking; ++i) {
                for(size_t j = 0; j < blocking; ++j) {
                    data[(I*blocking+i)*cols + J*blocking+j] = block.data[k++];
                }
            }
        }

        // This is the copy constructor.
        // Example
        //      Grid2D<int> g(3, 3, 0);
        //      Grid2D<int> copy(g);
        Grid2D(const Grid2D<T>& g)
            : rows(g.rows)
            , cols(g.cols)
            , data(g.data)
            , blocking(g.blocking)
            {}

        // This is the assignment operator
        // Example
        //      Grid2D<double> g(3, 4, 5.0);
        //      Grid2D<int>    g2;
        //      g2 = g;
        Grid2D& operator=(Grid2D<T> g) {
            using std::swap;
            swap(*this, g);
            return *this;
        }

        // This is for writing to location (i,j)
        T& operator()(const size_t i, const size_t j) {
            assert(i < rows);
            assert(j < cols);
            return data[i*cols + j];
        }

        // This is for reading from location (i,j)
        const T& operator()(const size_t i, const size_t j) const {
            assert(i < rows);
            assert(j < cols);
            return data[i*cols + j];
        }

        template<class U>
        friend void swap(Grid2D<U>& left, Grid2D<U>& right);

    private:
        size_t rows;
        size_t cols;
        std::vector<T> data;
        size_t blocking;
};

template<class T>
std::ostream& operator<<(std::ostream& out, const Grid2D<T>& g)
{
    if(g.getBlockingFactor() > 1) {
        out << "Blocking factor: " << g.getBlockingFactor() << "\n";
    }

    for(size_t i = 0; i < g.getRows(); ++i) {
        if(g.getBlockingFactor() > 1 && i > 0 && i % g.getBlockingFactor() == 0) {
            for(size_t k = 0; k < g.getCols() + g.getCols() / g.getBlockingFactor() - 1; ++k) {
                out << "-\t";
            }
            out << "\n";
        }

        for(size_t j = 0; j < g.getCols(); ++j) {
            if(g.getBlockingFactor() > 1 && j > 0 && j % g.getBlockingFactor() == 0) {
                out << "|\t";
            }
            out << g(i, j) << "\t";
        }
        out << "\n";
    }
    return out;
}

template<class T>
void swap(Grid2D<T>& left, Grid2D<T>& right) {
    std::swap(left.rows, right.rows);
    std::swap(left.cols, right.cols);
    std::swap(left.data, right.data);
    std::swap(left.blocking, right.blocking);
}
<commit_msg>rename blockingFactor to blockSize, what it actually is<commit_after>// Two dimensional grid class

#include <vector>
#include <cassert>
#include <iostream>
#include <limits>

template<class T>
class Grid2D
{
    public:
        // This is the default constructor. Call it without any
        // arguments and it will return a 0x0 matrix (initialized
        // with 0)
        // Example
        //      Grid2D<double> g;
        Grid2D()
            : rows(0)
            , cols(0)
            , data(std::vector<T>(0))
            , blockSize(0)
            {}

        // This is the normal constructor. Gets you a rowsxcols matrix
        // with optinal default value value
        // Example
        //      Grid2D<double> square(3, 3, 5.0);
        Grid2D(const size_t rows, const size_t cols, T value=0, const size_t blockSize = 0)
            : rows(rows)
            , cols(cols)
            , data(std::vector<T>(rows*cols, value))
            , blockSize(0)
            {}

        const size_t getRows() const { return rows; }
        const size_t getCols() const { return cols; }

        const size_t getBlockSize() const { return blockSize; }
        void setBlockSize(const size_t size) {
            // assert rows and cols beeing multiple of the block size
            assert(rows % size == 0);
            assert(cols % size == 0);
            assert(size > 1 && size <= std::min(rows, cols));

            blockSize = size;
        }

        void getBlock(const size_t I, const size_t J, Grid2D<T>& block) {
            // assert a useful block size
            assert(blockSize > 1);
            assert(blockSize <= std::min(rows, cols));
            assert(rows % blockSize == 0 && cols % blockSize == 0);

            // assert i/j within bounds
            assert(I < rows/blockSize && J < cols/blockSize);

            // assert block beeing of size blockSize x blockSize
            assert(block.getCols() == blockSize && block.getRows() == blockSize);

            size_t k = 0;
            for(size_t i = 0; i < blockSize; ++i) {
                for(size_t j = 0; j < blockSize; ++j) {
                    block.data[k++] = data[(I*blockSize+i)*cols + J*blockSize+j];
                }
            }
            assert(k == blockSize * blockSize);
        }

        void setBlock(const size_t I, const size_t J, const Grid2D<T>& block) {
            // assert a useful blockSize factor
            assert(blockSize > 1);
            assert(blockSize <= std::min(rows, cols));
            assert(rows % blockSize == 0 && cols % blockSize == 0);

            // assert i/j within bounds
            assert(I < rows/blockSize && J < cols/blockSize);

            // assert block beeing of size blockSize x blockSize
            assert(block.getCols() == blockSize && block.getRows() == blockSize);

            size_t k = 0;
            for(size_t i = 0; i < blockSize; ++i) {
                for(size_t j = 0; j < blockSize; ++j) {
                    data[(I*blockSize+i)*cols + J*blockSize+j] = block.data[k++];
                }
            }
        }

        // This is the copy constructor.
        // Example
        //      Grid2D<int> g(3, 3, 0);
        //      Grid2D<int> copy(g);
        Grid2D(const Grid2D<T>& g)
            : rows(g.rows)
            , cols(g.cols)
            , data(g.data)
            , blockSize(g.blockSize)
            {}

        // This is the assignment operator
        // Example
        //      Grid2D<double> g(3, 4, 5.0);
        //      Grid2D<int>    g2;
        //      g2 = g;
        Grid2D& operator=(Grid2D<T> g) {
            using std::swap;
            swap(*this, g);
            return *this;
        }

        // This is for writing to location (i,j)
        T& operator()(const size_t i, const size_t j) {
            assert(i < rows);
            assert(j < cols);
            return data[i*cols + j];
        }

        // This is for reading from location (i,j)
        const T& operator()(const size_t i, const size_t j) const {
            assert(i < rows);
            assert(j < cols);
            return data[i*cols + j];
        }

        template<class U>
        friend void swap(Grid2D<U>& left, Grid2D<U>& right);

    private:
        size_t rows;
        size_t cols;
        std::vector<T> data;
        size_t blockSize;
};

template<class T>
std::ostream& operator<<(std::ostream& out, const Grid2D<T>& g)
{
    if(g.getBlockSize() > 1) {
        out << "Block size: " << g.getBlockSize() << "\n";
    }

    for(size_t i = 0; i < g.getRows(); ++i) {
        if(g.getBlockSize() > 1 && i > 0 && i % g.getBlockSize() == 0) {
            for(size_t k = 0; k < g.getCols() + g.getCols() / g.getBlockSize() - 1; ++k) {
                out << "-\t";
            }
            out << "\n";
        }

        for(size_t j = 0; j < g.getCols(); ++j) {
            if(g.getBlockSize() > 1 && j > 0 && j % g.getBlockSize() == 0) {
                out << "|\t";
            }
            out << ((g(i, j) == std::numeric_limits<T>::max()) ? 12345 : g(i,j)) << "\t";
        }
        out << "\n";
    }
    return out;
}

template<class T>
void swap(Grid2D<T>& left, Grid2D<T>& right) {
    std::swap(left.rows, right.rows);
    std::swap(left.cols, right.cols);
    std::swap(left.data, right.data);
    std::swap(left.blockSize, right.blockSize);
}
<|endoftext|>


<commit_before>// Virvo - Virtual Reality Volume Rendering
// Copyright (C) 1999-2003 University of Stuttgart, 2004-2005 Brown University
// Contact: Jurgen P. Schulze, jschulze@ucsd.edu
//
// This file is part of Virvo.
//
// Virvo is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library (see license.txt); if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

#ifdef HAVE_CONFIG_H
#include "vvconfig.h"
#endif

#ifdef VV_DEBUG_MEMORY
#include <crtdbg.h>
#define new new(_NORMAL_BLOCK,__FILE__, __LINE__)
#endif

#include "vvresourcemanager.h"
#include "vvserver.h"

#include <virvo/vvdebugmsg.h>
#include <virvo/vvibrserver.h>
#include <virvo/vvimageserver.h>
#include <virvo/vvremoteserver.h>
#include <virvo/vvrendererfactory.h>
#include <virvo/vvsocketio.h>
#include <virvo/vvtcpserver.h>
#include <virvo/vvtcpsocket.h>
#include <virvo/vvtoolshed.h>
#include <virvo/vvvirvo.h>
#include <virvo/vvvoldesc.h>

#include <iostream>
#include <limits>
#include <pthread.h>

const int vvServer::DEFAULTSIZE  = 512;
const int vvServer::DEFAULT_PORT = 31050;

using std::cerr;
using std::endl;

vvServer::vvServer()
{
  _port       = vvServer::DEFAULT_PORT;
  _sm         = SERVER;
  _useBonjour = false;
}

vvServer::~vvServer()
{
}

int vvServer::run(int argc, char** argv)
{
  vvDebugMsg::msg(3, "vvServer::run()");

  cerr << "Virvo server " << virvo::getVersionMajor() << "." << virvo::getReleaseCounter() << endl;
  cerr << "(c) " << virvo::getYearOfRelease() << " Juergen Schulze (schulze@cs.brown.edu)" << endl;
  cerr << "Brown University" << endl << endl;

  if(!parseCommandLine(argc, argv))
    return 1;

  if(serverLoop())
    return 0;
  else
    return 1;
}

void vvServer::displayHelpInfo()
{
  vvDebugMsg::msg(3, "vvServer::displayHelpInfo()");

  cerr << "Syntax:" << endl;
  cerr << endl;
  cerr << "  vserver [options]" << endl;
  cerr << endl;
  cerr << "Available options:" << endl;
  cerr << endl;
  cerr << "-port" << endl;
  cerr << " Don't use the default port (" << DEFAULT_PORT << "), but the specified one" << endl;
  cerr << endl;
  cerr << "-mode" << endl;
  cerr << " Start vvServer with one of the following modes:" << endl;
  cerr << " s     single server (default)" << endl;
  cerr << " rm    resource manager" << endl;
  cerr << " rm+s  server and resource manager simultanously" << endl;
  cerr << endl;
#ifdef HAVE_BONJOUR
  cerr << "-bonjour" << endl;
  cerr << " use bonjour to broadcast this service. options:" << endl;
  cerr << " on" << endl;
  cerr << " off (default)" << endl;
  cerr << endl;
#endif
  cerr << "-debug" << endl;
  cerr << " Set debug level" << endl;
  cerr << endl;
}

bool vvServer::parseCommandLine(int argc, char** argv)
{
  vvDebugMsg::msg(1, "vvServer::parseCommandLine()");

  for (int arg=1; arg<argc; ++arg)
  {
    if (vvToolshed::strCompare(argv[arg], "-help")==0 ||
        vvToolshed::strCompare(argv[arg], "-h")==0    ||
        vvToolshed::strCompare(argv[arg], "-?")==0    ||
        vvToolshed::strCompare(argv[arg], "/?")==0)
    {
      displayHelpInfo();
      return false;
    }
    else if (vvToolshed::strCompare(argv[arg], "-port")==0)
    {
      if ((++arg)>=argc)
      {
        cerr << "No port specified" << endl;
        return false;
      }
      else
      {
        int inport = atoi(argv[arg]);
        if(inport > std::numeric_limits<ushort>::max() || inport <= std::numeric_limits<ushort>::min())
        {
          cerr << "Specified port is out of range. Falling back to default: " << vvServer::DEFAULT_PORT << endl;
          _port = vvServer::DEFAULT_PORT;
        }
        else
          _port = inport;
      }
    }
    else if (vvToolshed::strCompare(argv[arg], "-mode")==0)
    {
      if ((++arg)>=argc)
      {
        cerr << "Mode type missing." << endl;
        return false;
      }
      if     (vvToolshed::strCompare(argv[arg], "s")==0)
      {
        _sm = SERVER;
      }
      else if(vvToolshed::strCompare(argv[arg], "rm")==0)
      {
        _sm = RM;
      }
      else if(vvToolshed::strCompare(argv[arg], "rm+s")==0)
      {
        _sm = RM_WITH_SERVER;
      }
      else
      {
        cerr << "Unknown mode type." << endl;
        return false;
      }
    }
#ifdef HAVE_BONJOUR
    else if (vvToolshed::strCompare(argv[arg], "-bonjour")==0)
    {
      if ((++arg)>=argc)
      {
        cerr << "Bonjour setting missing." << endl;
        return false;
      }
      if     (vvToolshed::strCompare(argv[arg], "on")==0)
      {
        _useBonjour = true;
      }
      else if(vvToolshed::strCompare(argv[arg], "off")==0)
      {
        _useBonjour = false;
      }
      else
      {
        cerr << "Unknown bonjour setting." << endl;
        return false;
      }
    }
#endif
    else if (vvToolshed::strCompare(argv[arg], "-debug")==0)
    {
      if ((++arg)>=argc)
      {
        cerr << "Debug level missing." << endl;
        return false;
      }
      int level = atoi(argv[arg]);
      if (level>=0 && level<=3)
        vvDebugMsg::setDebugLevel(level);
      else
      {
        cerr << "Invalid debug level." << endl;
        return false;
      }
    }
    else
    {
      cerr << "Unknown option/parameter: \"" << argv[arg] << "\", use -help for instructions" << endl;
      return false;
    }
  }
  return true;
}

bool vvServer::serverLoop()
{
  vvTcpServer tcpServ = vvTcpServer(_port);

  if(!tcpServ.initStatus())
  {
    cerr << "Failed to initialize server-socket on port " << _port << "." << endl;
    return false;
  }
  else
  {
#ifdef HAVE_BONJOUR
    if(_useBonjour) registerToBonjour();
#endif
  }

  vvResourceManager *rm = NULL;

  if(RM == _sm)
  {
    rm = new vvResourceManager();
  }
  else if(RM_WITH_SERVER == _sm)
  {
    rm = new vvResourceManager(this);
  }

  while (1)
  {
    cerr << "Listening on port " << _port << endl;

    vvTcpSocket *sock = NULL;

    while((sock = tcpServ.nextConnection()) == NULL)
    {
      vvDebugMsg::msg(3, "vvServer::serverLoop() Listening socket blocked, retry...");
    }

    if(sock == NULL)
    {
      cerr << "vvServer::serverLoop() Failed to initialize server-socket on port " << _port << endl;
      break;
    }
    else
    {
      cerr << "Incoming connection..." << endl;

      if(RM == _sm || RM_WITH_SERVER == _sm)
      {
        rm->addJob(sock);
      }
      else
      {
        handleClient(sock);
      }
    }
  }

#ifdef HAVE_BONJOUR
  if(_useBonjour) unregisterFromBonjour();
#endif

  delete rm;

  return true;
}

#ifdef HAVE_BONJOUR
DNSServiceErrorType vvServer::registerToBonjour()
{
  vvDebugMsg::msg(3, "vvServer::registerToBonjour()");
  vvBonjourEntry entry = vvBonjourEntry("Virvo Server", "_vserver._tcp", "");
  return _registrar.registerService(entry, _port);
}

void vvServer::unregisterFromBonjour()
{
  vvDebugMsg::msg(3, "vvServer::unregisterFromBonjour()");
  _registrar.unregisterService();
}
#endif

void vvServer::handleClient(vvTcpSocket *sock)
{
  vvServerThreadArgs *args = new vvServerThreadArgs;
  args->_sock = sock;
  args->_exitFunc = NULL;

  pthread_t pthread;
  pthread_create(&pthread,  NULL, handleClientThread, args);
  pthread_detach(pthread);
}

void * vvServer::handleClientThread(void *param)
{
  vvServerThreadArgs *args = reinterpret_cast<vvServerThreadArgs*>(param);

  if(args->_exitFunc == NULL)
  {
    args->_exitFunc = &vvServer::exitCallback;
  }

  pthread_cleanup_push(args->_exitFunc, NULL);

  vvTcpSocket *sock = args->_sock;

  vvSocketIO *sockio = new vvSocketIO(sock);

  vvRemoteServer* server = NULL;

  sockio->putBool(true);  // let client know we are ready

  int getType;
  sockio->getInt32(getType);
  vvRenderer::RendererType rType = (vvRenderer::RendererType)getType;
  switch(rType)
  {
    case vvRenderer::REMOTE_IMAGE:
      server = new vvImageServer(sockio);
      break;
    case vvRenderer::REMOTE_IBR:
      server = new vvIbrServer(sockio);
      break;
    default:
      cerr << "Unknown remote rendering type " << rType << std::endl;
      break;
  }
  if(!server)
  {
    pthread_exit(NULL);
  #ifdef _WIN32
    return NULL;
  #endif
  }

  vvVolDesc *vd = NULL;
  if(server->initRenderContext(DEFAULTSIZE, DEFAULTSIZE) != vvRemoteServer::VV_OK)
  {
    cerr << "Couldn't initialize render context" << std::endl;
    goto cleanup;
  }
  vvGLTools::enableGLErrorBacktrace();
  if(server->initData(vd) != vvRemoteServer::VV_OK)
  {
    cerr << "Could not initialize volume data" << endl;
    cerr << "Continuing with next client..." << endl;
    goto cleanup;
  }

  if(vd != NULL)
  {
    if(server->getLoadVolumeFromFile())
    {
      vd->printInfoLine();
    }

    // Set default color scheme if no TF present:
    if(vd->tf.isEmpty())
    {
      vd->tf.setDefaultAlpha(0, 0.0, 1.0);
      vd->tf.setDefaultColors((vd->chan==1) ? 0 : 2, 0.0, 1.0);
    }

    vvRenderState rs;
    vvRenderer *renderer = vvRendererFactory::create(vd,
        rs,
        rType==vvRenderer::REMOTE_IBR ? "rayrend" : "default",
        "");

    if(rType == vvRenderer::REMOTE_IBR)
      renderer->setParameter(vvRenderer::VV_USE_IBR, 1.f);

    while(1)
    {
      if(!server->processEvents(renderer))
      {
        delete renderer;
        renderer = NULL;
        break;
      }
    }
  }

cleanup:
  server->destroyRenderContext();

  // Frames vector with bricks is deleted along with the renderer.
  // Don't free them here.
  // see setRenderer().

  delete server;
  server = NULL;

  delete sockio;
  sockio = NULL;

  sock->disconnectFromHost();
  delete sock;
  sock = NULL;

  delete vd;
  vd = NULL;

  pthread_exit(NULL);
  pthread_cleanup_pop(0);
#ifdef _WIN32
  return NULL;
#endif
}

/*vvServer *s = NULL;

void sigproc(int )
{
  // NOTE some versions of UNIX will reset signal to default
  // after each call. So for portability set signal each time
  signal(SIGINT, sigproc);

  cerr << "you have pressed ctrl-c" << endl;

  delete s;
  s = NULL;
}*/

//-------------------------------------------------------------------
/// Main entry point.
int main(int argc, char** argv)
{
//  signal(SIGINT, sigproc);
#ifdef VV_DEBUG_MEMORY
  int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);// Get current flag
  flag |= _CRTDBG_LEAK_CHECK_DF;                 // Turn on leak-checking bit
  flag |=  _CRTDBG_CHECK_ALWAYS_DF;
  _CrtSetDbgFlag(flag);                          // Set flag to the new value
#endif

#ifdef VV_DEBUG_MEMORY
  _CrtMemState s1, s2, s3;
  _CrtCheckMemory();
  _CrtMemCheckpoint( &s1 );
#endif

  // do stuff to test memory difference for

#ifdef VV_DEBUG_MEMORY
  _CrtMemCheckpoint( &s2 );
  if ( _CrtMemDifference( &s3, &s1, &s2 ) ) _CrtMemDumpStatistics( &s3 );
  _CrtCheckMemory();
#endif

  // do stuff to verify memory status after

#ifdef VV_DEBUG_MEMORY
  _CrtCheckMemory();
#endif

  //vvDebugMsg::setDebugLevel(vvDebugMsg::NO_MESSAGES);
  vvServer vserver;
  int error = vserver.run(argc, argv);

#ifdef VV_DEBUG_MEMORY
  _CrtDumpMemoryLeaks();                         // display memory leaks, if any
#endif

  return error;
}

//===================================================================
// End of File
//===================================================================
// vim: sw=2:expandtab:softtabstop=2:ts=2:cino=\:0g0t0
<commit_msg>vserver fix: do not allow modes that don't work<commit_after>// Virvo - Virtual Reality Volume Rendering
// Copyright (C) 1999-2003 University of Stuttgart, 2004-2005 Brown University
// Contact: Jurgen P. Schulze, jschulze@ucsd.edu
//
// This file is part of Virvo.
//
// Virvo is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library (see license.txt); if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

#ifdef HAVE_CONFIG_H
#include "vvconfig.h"
#endif

#ifdef VV_DEBUG_MEMORY
#include <crtdbg.h>
#define new new(_NORMAL_BLOCK,__FILE__, __LINE__)
#endif

#include "vvresourcemanager.h"
#include "vvserver.h"

#include <virvo/vvdebugmsg.h>
#include <virvo/vvibrserver.h>
#include <virvo/vvimageserver.h>
#include <virvo/vvremoteserver.h>
#include <virvo/vvrendererfactory.h>
#include <virvo/vvsocketio.h>
#include <virvo/vvtcpserver.h>
#include <virvo/vvtcpsocket.h>
#include <virvo/vvtoolshed.h>
#include <virvo/vvvirvo.h>
#include <virvo/vvvoldesc.h>

#include <iostream>
#include <limits>
#include <pthread.h>

const int vvServer::DEFAULTSIZE  = 512;
const int vvServer::DEFAULT_PORT = 31050;

using std::cerr;
using std::endl;

vvServer::vvServer()
{
  _port       = vvServer::DEFAULT_PORT;
  _sm         = SERVER;
  _useBonjour = false;
}

vvServer::~vvServer()
{
}

int vvServer::run(int argc, char** argv)
{
  vvDebugMsg::msg(3, "vvServer::run()");

  cerr << "Virvo server " << virvo::getVersionMajor() << "." << virvo::getReleaseCounter() << endl;
  cerr << "(c) " << virvo::getYearOfRelease() << " Juergen Schulze (schulze@cs.brown.edu)" << endl;
  cerr << "Brown University" << endl << endl;

  if(!parseCommandLine(argc, argv))
    return 1;

  if(serverLoop())
    return 0;
  else
    return 1;
}

void vvServer::displayHelpInfo()
{
  vvDebugMsg::msg(3, "vvServer::displayHelpInfo()");

  cerr << "Syntax:" << endl;
  cerr << endl;
  cerr << "  vserver [options]" << endl;
  cerr << endl;
  cerr << "Available options:" << endl;
  cerr << endl;
  cerr << "-port" << endl;
  cerr << " Don't use the default port (" << DEFAULT_PORT << "), but the specified one" << endl;
  cerr << endl;
#ifdef HAVE_BONJOUR
  cerr << "-mode" << endl;
  cerr << " Start vvServer with one of the following modes:" << endl;
  cerr << " s     single server (default)" << endl;
  cerr << " rm    resource manager" << endl;
  cerr << " rm+s  server and resource manager simultanously" << endl;
  cerr << endl;
  cerr << "-bonjour" << endl;
  cerr << " use bonjour to broadcast this service. options:" << endl;
  cerr << " on" << endl;
  cerr << " off (default)" << endl;
  cerr << endl;
#endif
  cerr << "-debug" << endl;
  cerr << " Set debug level" << endl;
  cerr << endl;
}

bool vvServer::parseCommandLine(int argc, char** argv)
{
  vvDebugMsg::msg(1, "vvServer::parseCommandLine()");

  for (int arg=1; arg<argc; ++arg)
  {
    if (vvToolshed::strCompare(argv[arg], "-help")==0 ||
        vvToolshed::strCompare(argv[arg], "-h")==0    ||
        vvToolshed::strCompare(argv[arg], "-?")==0    ||
        vvToolshed::strCompare(argv[arg], "/?")==0)
    {
      displayHelpInfo();
      return false;
    }
    else if (vvToolshed::strCompare(argv[arg], "-port")==0)
    {
      if ((++arg)>=argc)
      {
        cerr << "No port specified" << endl;
        return false;
      }
      else
      {
        int inport = atoi(argv[arg]);
        if(inport > std::numeric_limits<ushort>::max() || inport <= std::numeric_limits<ushort>::min())
        {
          cerr << "Specified port is out of range. Falling back to default: " << vvServer::DEFAULT_PORT << endl;
          _port = vvServer::DEFAULT_PORT;
        }
        else
          _port = inport;
      }
    }
#ifdef HAVE_BONJOUR
    else if (vvToolshed::strCompare(argv[arg], "-mode")==0)
    {
      if ((++arg)>=argc)
      {
        cerr << "Mode type missing." << endl;
        return false;
      }
      if     (vvToolshed::strCompare(argv[arg], "s")==0)
      {
        _sm = SERVER;
      }
      else if(vvToolshed::strCompare(argv[arg], "rm")==0)
      {
        _sm = RM;
      }
      else if(vvToolshed::strCompare(argv[arg], "rm+s")==0)
      {
        _sm = RM_WITH_SERVER;
      }
      else
      {
        cerr << "Unknown mode type." << endl;
        return false;
      }
    }
    else if (vvToolshed::strCompare(argv[arg], "-bonjour")==0)
    {
      if ((++arg)>=argc)
      {
        cerr << "Bonjour setting missing." << endl;
        return false;
      }
      if     (vvToolshed::strCompare(argv[arg], "on")==0)
      {
        _useBonjour = true;
      }
      else if(vvToolshed::strCompare(argv[arg], "off")==0)
      {
        _useBonjour = false;
      }
      else
      {
        cerr << "Unknown bonjour setting." << endl;
        return false;
      }
    }
#endif
    else if (vvToolshed::strCompare(argv[arg], "-debug")==0)
    {
      if ((++arg)>=argc)
      {
        cerr << "Debug level missing." << endl;
        return false;
      }
      int level = atoi(argv[arg]);
      if (level>=0 && level<=3)
        vvDebugMsg::setDebugLevel(level);
      else
      {
        cerr << "Invalid debug level." << endl;
        return false;
      }
    }
    else
    {
      cerr << "Unknown option/parameter: \"" << argv[arg] << "\", use -help for instructions" << endl;
      return false;
    }
  }
  return true;
}

bool vvServer::serverLoop()
{
  vvTcpServer tcpServ = vvTcpServer(_port);

  if(!tcpServ.initStatus())
  {
    cerr << "Failed to initialize server-socket on port " << _port << "." << endl;
    return false;
  }
  else
  {
#ifdef HAVE_BONJOUR
    if(_useBonjour) registerToBonjour();
#endif
  }

  vvResourceManager *rm = NULL;

  if(RM == _sm)
  {
    rm = new vvResourceManager();
  }
  else if(RM_WITH_SERVER == _sm)
  {
    rm = new vvResourceManager(this);
  }

  while (1)
  {
    cerr << "Listening on port " << _port << endl;

    vvTcpSocket *sock = NULL;

    while((sock = tcpServ.nextConnection()) == NULL)
    {
      vvDebugMsg::msg(3, "vvServer::serverLoop() Listening socket blocked, retry...");
    }

    if(sock == NULL)
    {
      cerr << "vvServer::serverLoop() Failed to initialize server-socket on port " << _port << endl;
      break;
    }
    else
    {
      cerr << "Incoming connection..." << endl;

      if(RM == _sm || RM_WITH_SERVER == _sm)
      {
        rm->addJob(sock);
      }
      else
      {
        handleClient(sock);
      }
    }
  }

#ifdef HAVE_BONJOUR
  if(_useBonjour) unregisterFromBonjour();
#endif

  delete rm;

  return true;
}

#ifdef HAVE_BONJOUR
DNSServiceErrorType vvServer::registerToBonjour()
{
  vvDebugMsg::msg(3, "vvServer::registerToBonjour()");
  vvBonjourEntry entry = vvBonjourEntry("Virvo Server", "_vserver._tcp", "");
  return _registrar.registerService(entry, _port);
}

void vvServer::unregisterFromBonjour()
{
  vvDebugMsg::msg(3, "vvServer::unregisterFromBonjour()");
  _registrar.unregisterService();
}
#endif

void vvServer::handleClient(vvTcpSocket *sock)
{
  vvServerThreadArgs *args = new vvServerThreadArgs;
  args->_sock = sock;
  args->_exitFunc = NULL;

  pthread_t pthread;
  pthread_create(&pthread,  NULL, handleClientThread, args);
  pthread_detach(pthread);
}

void * vvServer::handleClientThread(void *param)
{
  vvServerThreadArgs *args = reinterpret_cast<vvServerThreadArgs*>(param);

  if(args->_exitFunc == NULL)
  {
    args->_exitFunc = &vvServer::exitCallback;
  }

  pthread_cleanup_push(args->_exitFunc, NULL);

  vvTcpSocket *sock = args->_sock;

  vvSocketIO *sockio = new vvSocketIO(sock);

  vvRemoteServer* server = NULL;

  sockio->putBool(true);  // let client know we are ready

  int getType;
  sockio->getInt32(getType);
  vvRenderer::RendererType rType = (vvRenderer::RendererType)getType;
  switch(rType)
  {
    case vvRenderer::REMOTE_IMAGE:
      server = new vvImageServer(sockio);
      break;
    case vvRenderer::REMOTE_IBR:
      server = new vvIbrServer(sockio);
      break;
    default:
      cerr << "Unknown remote rendering type " << rType << std::endl;
      break;
  }
  if(!server)
  {
    pthread_exit(NULL);
  #ifdef _WIN32
    return NULL;
  #endif
  }

  vvVolDesc *vd = NULL;
  if(server->initRenderContext(DEFAULTSIZE, DEFAULTSIZE) != vvRemoteServer::VV_OK)
  {
    cerr << "Couldn't initialize render context" << std::endl;
    goto cleanup;
  }
  vvGLTools::enableGLErrorBacktrace();
  if(server->initData(vd) != vvRemoteServer::VV_OK)
  {
    cerr << "Could not initialize volume data" << endl;
    cerr << "Continuing with next client..." << endl;
    goto cleanup;
  }

  if(vd != NULL)
  {
    if(server->getLoadVolumeFromFile())
    {
      vd->printInfoLine();
    }

    // Set default color scheme if no TF present:
    if(vd->tf.isEmpty())
    {
      vd->tf.setDefaultAlpha(0, 0.0, 1.0);
      vd->tf.setDefaultColors((vd->chan==1) ? 0 : 2, 0.0, 1.0);
    }

    vvRenderState rs;
    vvRenderer *renderer = vvRendererFactory::create(vd,
        rs,
        rType==vvRenderer::REMOTE_IBR ? "rayrend" : "default",
        "");

    if(rType == vvRenderer::REMOTE_IBR)
      renderer->setParameter(vvRenderer::VV_USE_IBR, 1.f);

    while(1)
    {
      if(!server->processEvents(renderer))
      {
        delete renderer;
        renderer = NULL;
        break;
      }
    }
  }

cleanup:
  server->destroyRenderContext();

  // Frames vector with bricks is deleted along with the renderer.
  // Don't free them here.
  // see setRenderer().

  delete server;
  server = NULL;

  delete sockio;
  sockio = NULL;

  sock->disconnectFromHost();
  delete sock;
  sock = NULL;

  delete vd;
  vd = NULL;

  pthread_exit(NULL);
  pthread_cleanup_pop(0);
#ifdef _WIN32
  return NULL;
#endif
}

/*vvServer *s = NULL;

void sigproc(int )
{
  // NOTE some versions of UNIX will reset signal to default
  // after each call. So for portability set signal each time
  signal(SIGINT, sigproc);

  cerr << "you have pressed ctrl-c" << endl;

  delete s;
  s = NULL;
}*/

//-------------------------------------------------------------------
/// Main entry point.
int main(int argc, char** argv)
{
//  signal(SIGINT, sigproc);
#ifdef VV_DEBUG_MEMORY
  int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);// Get current flag
  flag |= _CRTDBG_LEAK_CHECK_DF;                 // Turn on leak-checking bit
  flag |=  _CRTDBG_CHECK_ALWAYS_DF;
  _CrtSetDbgFlag(flag);                          // Set flag to the new value
#endif

#ifdef VV_DEBUG_MEMORY
  _CrtMemState s1, s2, s3;
  _CrtCheckMemory();
  _CrtMemCheckpoint( &s1 );
#endif

  // do stuff to test memory difference for

#ifdef VV_DEBUG_MEMORY
  _CrtMemCheckpoint( &s2 );
  if ( _CrtMemDifference( &s3, &s1, &s2 ) ) _CrtMemDumpStatistics( &s3 );
  _CrtCheckMemory();
#endif

  // do stuff to verify memory status after

#ifdef VV_DEBUG_MEMORY
  _CrtCheckMemory();
#endif

  //vvDebugMsg::setDebugLevel(vvDebugMsg::NO_MESSAGES);
  vvServer vserver;
  int error = vserver.run(argc, argv);

#ifdef VV_DEBUG_MEMORY
  _CrtDumpMemoryLeaks();                         // display memory leaks, if any
#endif

  return error;
}

//===================================================================
// End of File
//===================================================================
// vim: sw=2:expandtab:softtabstop=2:ts=2:cino=\:0g0t0
<|endoftext|>


<commit_before>#include <telebotxx/BotApi.hpp>
#include <telebotxx/Exception.hpp>

#include <sstream>

#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/istreamwrapper.h>

#include <curlpp/cURLpp.hpp>
#include <curlpp/Easy.hpp>
#include <curlpp/Options.hpp>

#include <boost/log/trivial.hpp>

namespace telebotxx
{
	const rapidjson::Value& parseResponse(const rapidjson::Document& doc)
	{
		using namespace rapidjson;
		if (!doc.IsObject())
			throw ParseError("Object expected");

		// Get status
		if (!doc.HasMember("ok") || !doc["ok"].IsBool())
			throw ParseError("Field 'ok' not found or has invalid type");
		bool ok = doc["ok"].GetBool();

		if (ok)
		{
			if (!doc.HasMember("result") || !doc["result"].IsObject())
				throw ParseError("Field 'result' not found or has invalid type");
			return doc["result"];
		} else
		{
			if (!doc.HasMember("error_code") || !doc["error_code"].IsInt())
				throw ParseError("Field 'error_code' not found or has invalid type");
			int code = doc["error_code"].GetInt();

			if (!doc.HasMember("description") || !doc["description"].IsString())
				throw ParseError("Field 'description' not found or has invalid type");
			std::string description(doc["description"].GetString());

			throw ApiError(code, description);
		}
	}

	User parseUser(const rapidjson::Value& obj)
	{
		if (!obj.HasMember("id") || !obj["id"].IsInt())
			throw ParseError("Field 'id' not found or has invalid type");
		int id = obj["id"].GetInt();

		if (!obj.HasMember("first_name") || !obj["first_name"].IsString())
			throw ParseError("Field 'first_name' not found or has invalid type");
		std::string firstName(obj["first_name"].GetString());

		std::string lastName;
		if (obj.HasMember("last_name"))
		{
			if (obj["last_name"].IsString())
				lastName = obj["last_name"].GetString();
			else
				throw ParseError("Field 'last_name' has invalid type");
		}

		std::string username;
		if (obj.HasMember("username"))
		{
			if (obj["username"].IsString())
				username = obj["username"].GetString();
			else
				throw ParseError("Field 'username' has invalid type");
		}

		return User(id, firstName, lastName, username);
	}
}

using namespace telebotxx;

class BotApi::Impl
{
public:
	Impl(const std::string& token)
		: token_(token)
	{
		telegramMainUrl_ = "https://api.telegram.org/bot" + token_;
		botUser_ = getMe();
	}

	inline User getMe()
	{
		curlpp::Easy request;
		std::stringstream ss;

		request.setOpt(new curlpp::Options::Url(telegramMainUrl_ + "/getMe"));
		request.setOpt(new curlpp::Options::Verbose(false));
		request.setOpt(new curlpp::options::WriteStream(&ss));
		request.perform();

		BOOST_LOG_TRIVIAL(debug) << ss.str();

		using namespace rapidjson;
		IStreamWrapper isw(ss);
		Document doc;
		doc.ParseStream(isw);

		return parseUser(parseResponse(doc));
	}

	inline void sendMessage(const std::string& chat, const std::string& text)
	{
		// Construct JSON body and istream
		using namespace rapidjson;
		StringBuffer s;
		Writer<StringBuffer> writer(s);

		writer.StartObject();
		writer.String("chat_id");
		writer.String(chat.c_str());
		writer.String("text");
		writer.String(text.c_str());
		writer.EndObject();

		std::istringstream requestStream(s.GetString());
		BOOST_LOG_TRIVIAL(debug) << requestStream.str();
		auto size = requestStream.str().size();

		std::stringstream responseStream;

		// Construct HTTP request
		curlpp::Easy request;
		std::list<std::string> headers;

		// Content-Type
		headers.push_back("Content-Type: application/json");

		// Content-Length
		{
			std::ostringstream ss;
			ss << "Content-Length: " << size;
			headers.push_back(ss.str());
		}

		// Set options
		request.setOpt(new curlpp::Options::Url(telegramMainUrl_ + "/sendMessage"));
		request.setOpt(new curlpp::Options::Verbose(false));
		request.setOpt(new curlpp::Options::ReadStream(&requestStream));
		request.setOpt(new curlpp::options::WriteStream(&responseStream));
		request.setOpt(new curlpp::Options::InfileSize(size));
		request.setOpt(new curlpp::options::HttpHeader(headers));
		request.setOpt(new curlpp::Options::Post(true));

		// Perform request
		request.perform();

		BOOST_LOG_TRIVIAL(debug) << responseStream.str();

		using namespace rapidjson;
		IStreamWrapper isw(responseStream);
		Document doc;
		doc.ParseStream(isw);

		/// \todo Parse message
		parseResponse(doc);
	}

	inline void sendPhoto(const std::string& chat, const std::string& filename, const std::string& caption)
	{
		// Construct HTTP request
		curlpp::Easy request;
		std::stringstream responseStream;

		{
			// Forms takes ownership of pointers!
			curlpp::Forms formParts;
			formParts.push_back(new curlpp::FormParts::Content("chat_id", chat));
			formParts.push_back(new curlpp::FormParts::File("photo", filename));
			formParts.push_back(new curlpp::FormParts::Content("caption", caption));
			request.setOpt(new curlpp::options::HttpPost(formParts));
		}

		// Set options
		request.setOpt(new curlpp::Options::Url(telegramMainUrl_ + "/sendPhoto"));
		request.setOpt(new curlpp::Options::Verbose(false));
		request.setOpt(new curlpp::options::WriteStream(&responseStream));

		// Perform request
		request.perform();

		BOOST_LOG_TRIVIAL(debug) << responseStream.str();

		using namespace rapidjson;
		IStreamWrapper isw(responseStream);
		Document doc;
		doc.ParseStream(isw);

		/// \todo Parse message
		parseResponse(doc);
	}

private:

	std::string token_;
	std::string telegramMainUrl_;
	User botUser_;
};

BotApi::BotApi(const std::string& token)
	: impl_(std::make_unique<Impl>(token))
{
}

BotApi::~BotApi() = default;

User BotApi::getMe()
{
	return impl_->getMe();
}

void BotApi::sendMessage(const std::string& chat, const std::string& text)
{
	return impl_->sendMessage(chat, text);
}

void BotApi::sendPhoto(const std::string& chat, const std::string& filename, const std::string& caption)
{
	return impl_->sendPhoto(chat, filename, caption);
}
<commit_msg>Disabled default 'Expect: 100-Continue' header in POST requests.<commit_after>#include <telebotxx/BotApi.hpp>
#include <telebotxx/Exception.hpp>

#include <sstream>

#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/istreamwrapper.h>

#include <curlpp/cURLpp.hpp>
#include <curlpp/Easy.hpp>
#include <curlpp/Options.hpp>

#include <boost/log/trivial.hpp>

namespace telebotxx
{
	const rapidjson::Value& parseResponse(const rapidjson::Document& doc)
	{
		using namespace rapidjson;
		if (!doc.IsObject())
			throw ParseError("Object expected");

		// Get status
		if (!doc.HasMember("ok") || !doc["ok"].IsBool())
			throw ParseError("Field 'ok' not found or has invalid type");
		bool ok = doc["ok"].GetBool();

		if (ok)
		{
			if (!doc.HasMember("result") || !doc["result"].IsObject())
				throw ParseError("Field 'result' not found or has invalid type");
			return doc["result"];
		} else
		{
			if (!doc.HasMember("error_code") || !doc["error_code"].IsInt())
				throw ParseError("Field 'error_code' not found or has invalid type");
			int code = doc["error_code"].GetInt();

			if (!doc.HasMember("description") || !doc["description"].IsString())
				throw ParseError("Field 'description' not found or has invalid type");
			std::string description(doc["description"].GetString());

			throw ApiError(code, description);
		}
	}

	User parseUser(const rapidjson::Value& obj)
	{
		if (!obj.HasMember("id") || !obj["id"].IsInt())
			throw ParseError("Field 'id' not found or has invalid type");
		int id = obj["id"].GetInt();

		if (!obj.HasMember("first_name") || !obj["first_name"].IsString())
			throw ParseError("Field 'first_name' not found or has invalid type");
		std::string firstName(obj["first_name"].GetString());

		std::string lastName;
		if (obj.HasMember("last_name"))
		{
			if (obj["last_name"].IsString())
				lastName = obj["last_name"].GetString();
			else
				throw ParseError("Field 'last_name' has invalid type");
		}

		std::string username;
		if (obj.HasMember("username"))
		{
			if (obj["username"].IsString())
				username = obj["username"].GetString();
			else
				throw ParseError("Field 'username' has invalid type");
		}

		return User(id, firstName, lastName, username);
	}
}

using namespace telebotxx;

class BotApi::Impl
{
public:
	Impl(const std::string& token)
		: token_(token)
	{
		telegramMainUrl_ = "https://api.telegram.org/bot" + token_;
		botUser_ = getMe();
	}

	inline User getMe()
	{
		curlpp::Easy request;
		std::stringstream ss;

		request.setOpt(new curlpp::Options::Url(telegramMainUrl_ + "/getMe"));
		request.setOpt(new curlpp::Options::Verbose(false));
		request.setOpt(new curlpp::options::WriteStream(&ss));
		request.perform();

		BOOST_LOG_TRIVIAL(debug) << ss.str();

		using namespace rapidjson;
		IStreamWrapper isw(ss);
		Document doc;
		doc.ParseStream(isw);

		return parseUser(parseResponse(doc));
	}

	inline void sendMessage(const std::string& chat, const std::string& text)
	{
		// Construct JSON body and istream
		using namespace rapidjson;
		StringBuffer s;
		Writer<StringBuffer> writer(s);

		writer.StartObject();
		writer.String("chat_id");
		writer.String(chat.c_str());
		writer.String("text");
		writer.String(text.c_str());
		writer.EndObject();

		std::istringstream requestStream(s.GetString());
		BOOST_LOG_TRIVIAL(debug) << requestStream.str();
		auto size = requestStream.str().size();

		std::stringstream responseStream;

		// Construct HTTP request
		curlpp::Easy request;
		std::list<std::string> headers;

		// Content-Type
		headers.push_back("Content-Type: application/json");

		// Content-Length
		{
			std::ostringstream ss;
			ss << "Content-Length: " << size;
			headers.push_back(ss.str());
		}

		headers.push_back("Expect:");

		// Set options
		request.setOpt(new curlpp::Options::Url(telegramMainUrl_ + "/sendMessage"));
		request.setOpt(new curlpp::Options::Verbose(true));
		request.setOpt(new curlpp::Options::ReadStream(&requestStream));
		request.setOpt(new curlpp::Options::WriteStream(&responseStream));
		request.setOpt(new curlpp::Options::InfileSize(size));
		request.setOpt(new curlpp::Options::HttpHeader(headers));
		request.setOpt(new curlpp::Options::Post(true));

		// Perform request
		request.perform();

		BOOST_LOG_TRIVIAL(debug) << responseStream.str();

		using namespace rapidjson;
		IStreamWrapper isw(responseStream);
		Document doc;
		doc.ParseStream(isw);

		/// \todo Parse message
		parseResponse(doc);
	}

	inline void sendPhoto(const std::string& chat, const std::string& filename, const std::string& caption)
	{
		// Construct HTTP request
		curlpp::Easy request;
		std::stringstream responseStream;

		std::list<std::string> headers;
		headers.push_back("Expect:");
		request.setOpt(new curlpp::Options::HttpHeader(headers));

		{
			// Forms takes ownership of pointers!
			curlpp::Forms formParts;
			formParts.push_back(new curlpp::FormParts::Content("chat_id", chat));
			formParts.push_back(new curlpp::FormParts::File("photo", filename));
			formParts.push_back(new curlpp::FormParts::Content("caption", caption));
			request.setOpt(new curlpp::options::HttpPost(formParts));
		}

		// Set options
		request.setOpt(new curlpp::Options::Url(telegramMainUrl_ + "/sendPhoto"));
		request.setOpt(new curlpp::Options::Verbose(true));
		request.setOpt(new curlpp::options::WriteStream(&responseStream));

		// Perform request
		request.perform();

		BOOST_LOG_TRIVIAL(debug) << responseStream.str();

		using namespace rapidjson;
		IStreamWrapper isw(responseStream);
		Document doc;
		doc.ParseStream(isw);

		/// \todo Parse message
		parseResponse(doc);
	}

private:

	std::string token_;
	std::string telegramMainUrl_;
	User botUser_;
};

BotApi::BotApi(const std::string& token)
	: impl_(std::make_unique<Impl>(token))
{
}

BotApi::~BotApi() = default;

User BotApi::getMe()
{
	return impl_->getMe();
}

void BotApi::sendMessage(const std::string& chat, const std::string& text)
{
	return impl_->sendMessage(chat, text);
}

void BotApi::sendPhoto(const std::string& chat, const std::string& filename, const std::string& caption)
{
	return impl_->sendPhoto(chat, filename, caption);
}
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

// Add the muon tracks to the generic AOD track branch during the
// filtering of the ESD - R. Arnaldi 5/5/08

#include <TChain.h>
#include <TFile.h>
#include <TParticle.h>

#include "AliAnalysisTaskESDMuonFilter.h"
#include "AliAnalysisManager.h"
#include "AliESDEvent.h"
#include "AliAODEvent.h"
#include "AliESDInputHandler.h"
#include "AliAODHandler.h"
#include "AliAnalysisFilter.h"
#include "AliESDtrack.h"
#include "AliESDMuonTrack.h"
#include "AliESDVertex.h"
#include "AliMultiplicity.h"
#include "AliLog.h"
#include "AliStack.h"
#include "AliMCEvent.h"
#include "AliMCEventHandler.h"
#include "AliAODMCParticle.h"
#include "AliAODDimuon.h"

ClassImp(AliAnalysisTaskESDMuonFilter)

////////////////////////////////////////////////////////////////////////

AliAnalysisTaskESDMuonFilter::AliAnalysisTaskESDMuonFilter():
  AliAnalysisTaskSE(),
  fTrackFilter(0x0),
  fEnableMuonAOD(kFALSE)
{
  // Default constructor
}

AliAnalysisTaskESDMuonFilter::AliAnalysisTaskESDMuonFilter(const char* name):
  AliAnalysisTaskSE(name),
  fTrackFilter(0x0),
  fEnableMuonAOD(kFALSE)
{
  // Constructor
}

void AliAnalysisTaskESDMuonFilter::UserCreateOutputObjects()
{
  // Create the output container
  if (fTrackFilter) OutputTree()->GetUserInfo()->Add(fTrackFilter);
}

void AliAnalysisTaskESDMuonFilter::Init()
{
  // Initialization
  if (fDebug > 1) AliInfo("Init() \n");
  // From Andrei
  AliAODHandler *aodH = (AliAODHandler*)((AliAnalysisManager::GetAnalysisManager())->GetOutputEventHandler());
  if (!aodH) Fatal("UserCreateOutputObjects", "No AOD handler. Aborting.");
  if(fEnableMuonAOD)aodH->AddFilteredAOD("AliAOD.Muons.root", "MuonEvents");
  if(fEnableDimuonAOD)aodH->AddFilteredAOD("AliAOD.Dimuons.root", "DimuonEvents");
}

void AliAnalysisTaskESDMuonFilter::UserExec(Option_t */*option*/)
{
  // Execute analysis for current event
  Long64_t ientry = Entry();
  if(fDebug)printf("Muon Filter: Analysing event # %5d\n", (Int_t) ientry);

  ConvertESDtoAOD();
}

void AliAnalysisTaskESDMuonFilter::ConvertESDtoAOD()
{
  // ESD Muon Filter analysis task executed for each event
  AliESDEvent* esd = dynamic_cast<AliESDEvent*>(InputEvent());

  // Fetch Stack for debuggging if available
  AliStack *pStack = 0;
  AliMCEventHandler *mcH = 0;
  if(MCEvent()){
    pStack = MCEvent()->Stack();
    mcH = (AliMCEventHandler*) ((AliAnalysisManager::GetAnalysisManager())->GetMCtruthEventHandler());
  }

  // Define arrays for muons
  Double_t pos[3];
  Double_t p[3];
  Double_t pid[10];

  // has to be changed once the muon pid is provided by the ESD
  for (Int_t i = 0; i < 10; pid[i++] = 0.) {}
  pid[AliAODTrack::kMuon]=1.;

  AliAODHeader* header = AODEvent()->GetHeader();
  AliAODTrack *aodTrack = 0x0;
  AliESDMuonTrack *esdMuTrack = 0x0;

  // Access to the AOD container of tracks
  TClonesArray &tracks = *(AODEvent()->GetTracks());
  Int_t jTracks = header->GetRefMultiplicity();

  // Read primary vertex from AOD event
  AliAODVertex *primary = AODEvent()->GetPrimaryVertex();
  if(fDebug)primary->Print();

  // Loop on muon tracks to fill the AOD track branch
  Int_t nMuTracks = esd->GetNumberOfMuonTracks();

  // Update number of positive and negative tracks from AOD event (M.G.)
  Int_t nPosTracks = header->GetRefMultiplicityPos();
  Int_t nNegTracks = header->GetRefMultiplicityNeg();

  // Access to the AOD container of dimuons
  TClonesArray &dimuons = *(AODEvent()->GetDimuons());
  AliAODDimuon *aodDimuon = 0x0;

  Bool_t MuonsExist = kFALSE;
  Bool_t DimuonsExist = kFALSE;
  Int_t firstMuonTrack=0;
  Int_t nMuons=0;
  Int_t jDimuons=0;
  Int_t nMuonTrack[10];

  for(int imuon=0;imuon<10;imuon++) nMuonTrack[imuon]=0;

  for (Int_t nMuTrack = 0; nMuTrack < nMuTracks; ++nMuTrack) {
    esdMuTrack = esd->GetMuonTrack(nMuTrack);

    if (!esdMuTrack->ContainTrackerData()) continue;

    UInt_t selectInfo = 0;
    // Track selection
    if (fTrackFilter) {
     	selectInfo = fTrackFilter->IsSelected(esdMuTrack);
     	if (!selectInfo) {
     	  continue;
     	}
    }

    p[0] = esdMuTrack->Px();
    p[1] = esdMuTrack->Py();
    p[2] = esdMuTrack->Pz();

    pos[0] = esdMuTrack->GetNonBendingCoor();
    pos[1] = esdMuTrack->GetBendingCoor();
    pos[2] = esdMuTrack->GetZ();

    if(mcH)mcH->SelectParticle(esdMuTrack->GetLabel());

    aodTrack = new(tracks[jTracks++]) AliAODTrack(esdMuTrack->GetUniqueID(), // ID
						  esdMuTrack->GetLabel(), // label
						  p, // momentum
						  kTRUE, // cartesian coordinate system
						  pos, // position
						  kFALSE, // isDCA
						  0x0, // covariance matrix
						  esdMuTrack->Charge(), // charge
						  0, // ITSClusterMap
						  pid, // pid
						  primary, // primary vertex
						  kFALSE, // used for vertex fit?
						  kFALSE, // used for primary vertex fit?
						  AliAODTrack::kPrimary,// track type
						  selectInfo);

    aodTrack->SetXYAtDCA(esdMuTrack->GetNonBendingCoorAtDCA(), esdMuTrack->GetBendingCoorAtDCA());
    aodTrack->SetPxPyPzAtDCA(esdMuTrack->PxAtDCA(), esdMuTrack->PyAtDCA(), esdMuTrack->PzAtDCA());
    aodTrack->ConvertAliPIDtoAODPID();
    aodTrack->SetChi2perNDF(esdMuTrack->GetChi2() / (2.*esdMuTrack->GetNHit() - 5.));
    aodTrack->SetChi2MatchTrigger(esdMuTrack->GetChi2MatchTrigger());
    aodTrack->SetHitsPatternInTrigCh(esdMuTrack->GetHitsPatternInTrigCh());
    aodTrack->SetMuonClusterMap(esdMuTrack->GetMuonClusterMap());
    aodTrack->SetMatchTrigger(esdMuTrack->GetMatchTrigger());
    aodTrack->Connected(esdMuTrack->IsConnected());
    primary->AddDaughter(aodTrack);

    if (esdMuTrack->Charge() > 0) nPosTracks++;
    else nNegTracks++;

    nMuonTrack[nMuons]= jTracks-1.;
    nMuons++;
  }

    if(nMuons>=2) DimuonsExist = kTRUE;
    if(DimuonsExist) {
      for(int i=0;i<nMuons;i++){
        Int_t index0 = nMuonTrack[i];
	for(int j=i+1;j<nMuons;j++){
          Int_t index1 = nMuonTrack[j];
          aodDimuon = new(dimuons[jDimuons++]) AliAODDimuon(tracks.At(index0),tracks.At(index1));
          if (fDebug > 1){
            AliAODTrack *track0 = (AliAODTrack*)tracks.At(index0);
            AliAODTrack *track1 = (AliAODTrack*)tracks.At(index1);
            AliAODDimuon *dimuon0 = (AliAODDimuon*)dimuons.At(jDimuons-1);
            printf("Dimuon: mass = %f, px=%f, py=%f, pz=%f\n",dimuon0->M(),dimuon0->Px(),dimuon0->Py(),dimuon0->Pz());
            AliAODTrack  *mu0 = (AliAODTrack*) dimuon0->GetMu(0);
            AliAODTrack  *mu1 = (AliAODTrack*) dimuon0->GetMu(1);
            printf("Muon0 px=%f py=%f pz=%f\n",mu0->Px(),mu0->Py(),mu0->Pz());
            printf("Muon1 px=%f py=%f pz=%f\n",mu1->Px(),mu1->Py(),mu1->Pz());
	  }
        }
      }
    }

  header->SetRefMultiplicity(jTracks);
  header->SetRefMultiplicityPos(nPosTracks);
  header->SetRefMultiplicityNeg(nNegTracks);

  // From Andrei
  if(fEnableMuonAOD && MuonsExist){
    AliAODExtension *extMuons = dynamic_cast<AliAODHandler*>
    ((AliAnalysisManager::GetAnalysisManager())->GetOutputEventHandler())->GetFilteredAOD("AliAOD.Muons.root");
    extMuons->SelectEvent();
  }

  if(fEnableDimuonAOD && DimuonsExist){
    AliAODExtension *extDimuons = dynamic_cast<AliAODHandler*>
   ((AliAnalysisManager::GetAnalysisManager())->GetOutputEventHandler())->GetFilteredAOD("AliAOD.Dimuons.root");
    extDimuons->SelectEvent();
  }

}

void AliAnalysisTaskESDMuonFilter::Terminate(Option_t */*option*/)
{
  // Terminate analysis
  //
  if (fDebug > 1) printf("AnalysisESDfilter: Terminate() \n");
}

void  AliAnalysisTaskESDMuonFilter::PrintMCInfo(AliStack *pStack,Int_t label){
  if(!pStack)return;
  label = TMath::Abs(label);
  TParticle *part = pStack->Particle(label);
  Printf("########################");
  Printf("%s:%d %d UniqueID %d PDG %d P %3.3f",(char*)__FILE__,__LINE__,label,part->GetUniqueID(),part->GetPdgCode(),part->P());
  part->Print();
  TParticle* mother = part;
  Int_t imo = part->GetFirstMother();
  Int_t nprim = pStack->GetNprimary();
  //  while((imo >= nprim) && (mother->GetUniqueID() == 4)) {
  while((imo >= nprim)) {
    mother =  pStack->Particle(imo);
    Printf("Mother %s:%d Label %d UniqueID %d PDG %d P %3.3f",(char*)__FILE__,__LINE__,imo,mother->GetUniqueID(),mother->GetPdgCode(),mother->P());
    mother->Print();
    imo =  mother->GetFirstMother();
  }
  Printf("########################");
}
<commit_msg>Fixing compilation warnings (Roberta)<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

// Add the muon tracks to the generic AOD track branch during the
// filtering of the ESD - R. Arnaldi 5/5/08

#include <TChain.h>
#include <TFile.h>
#include <TParticle.h>

#include "AliAnalysisTaskESDMuonFilter.h"
#include "AliAnalysisManager.h"
#include "AliESDEvent.h"
#include "AliAODEvent.h"
#include "AliESDInputHandler.h"
#include "AliAODHandler.h"
#include "AliAnalysisFilter.h"
#include "AliESDtrack.h"
#include "AliESDMuonTrack.h"
#include "AliESDVertex.h"
#include "AliMultiplicity.h"
#include "AliLog.h"
#include "AliStack.h"
#include "AliMCEvent.h"
#include "AliMCEventHandler.h"
#include "AliAODMCParticle.h"
#include "AliAODDimuon.h"

ClassImp(AliAnalysisTaskESDMuonFilter)

////////////////////////////////////////////////////////////////////////

AliAnalysisTaskESDMuonFilter::AliAnalysisTaskESDMuonFilter():
  AliAnalysisTaskSE(),
  fTrackFilter(0x0),
  fEnableMuonAOD(kFALSE),
  fEnableDimuonAOD(kFALSE)
{
  // Default constructor
}

AliAnalysisTaskESDMuonFilter::AliAnalysisTaskESDMuonFilter(const char* name):
  AliAnalysisTaskSE(name),
  fTrackFilter(0x0),
  fEnableMuonAOD(kFALSE),
  fEnableDimuonAOD(kFALSE)
{
  // Constructor
}

void AliAnalysisTaskESDMuonFilter::UserCreateOutputObjects()
{
  // Create the output container
  if (fTrackFilter) OutputTree()->GetUserInfo()->Add(fTrackFilter);
}

void AliAnalysisTaskESDMuonFilter::Init()
{
  // Initialization
  if (fDebug > 1) AliInfo("Init() \n");
  // From Andrei
  AliAODHandler *aodH = (AliAODHandler*)((AliAnalysisManager::GetAnalysisManager())->GetOutputEventHandler());
  if (!aodH) Fatal("UserCreateOutputObjects", "No AOD handler. Aborting.");
  if(fEnableMuonAOD)aodH->AddFilteredAOD("AliAOD.Muons.root", "MuonEvents");
  if(fEnableDimuonAOD)aodH->AddFilteredAOD("AliAOD.Dimuons.root", "DimuonEvents");
}

void AliAnalysisTaskESDMuonFilter::UserExec(Option_t */*option*/)
{
  // Execute analysis for current event
  Long64_t ientry = Entry();
  if(fDebug)printf("Muon Filter: Analysing event # %5d\n", (Int_t) ientry);

  ConvertESDtoAOD();
}

void AliAnalysisTaskESDMuonFilter::ConvertESDtoAOD()
{
  // ESD Muon Filter analysis task executed for each event
  AliESDEvent* esd = dynamic_cast<AliESDEvent*>(InputEvent());

  // Fetch Stack for debuggging if available
  AliStack *pStack = 0;
  AliMCEventHandler *mcH = 0;
  if(MCEvent()){
    pStack = MCEvent()->Stack();
    mcH = (AliMCEventHandler*) ((AliAnalysisManager::GetAnalysisManager())->GetMCtruthEventHandler());
  }

  // Define arrays for muons
  Double_t pos[3];
  Double_t p[3];
  Double_t pid[10];

  // has to be changed once the muon pid is provided by the ESD
  for (Int_t i = 0; i < 10; pid[i++] = 0.) {}
  pid[AliAODTrack::kMuon]=1.;

  AliAODHeader* header = AODEvent()->GetHeader();
  AliAODTrack *aodTrack = 0x0;
  AliESDMuonTrack *esdMuTrack = 0x0;

  // Access to the AOD container of tracks
  TClonesArray &tracks = *(AODEvent()->GetTracks());
  Int_t jTracks = header->GetRefMultiplicity();

  // Read primary vertex from AOD event
  AliAODVertex *primary = AODEvent()->GetPrimaryVertex();
  if(fDebug)primary->Print();

  // Loop on muon tracks to fill the AOD track branch
  Int_t nMuTracks = esd->GetNumberOfMuonTracks();

  // Update number of positive and negative tracks from AOD event (M.G.)
  Int_t nPosTracks = header->GetRefMultiplicityPos();
  Int_t nNegTracks = header->GetRefMultiplicityNeg();

  // Access to the AOD container of dimuons
  TClonesArray &dimuons = *(AODEvent()->GetDimuons());
  AliAODDimuon *aodDimuon = 0x0;

  Bool_t MuonsExist = kFALSE;
  Bool_t DimuonsExist = kFALSE;
  Int_t nMuons=0;
  Int_t jDimuons=0;
  Int_t nMuonTrack[10];

  for(int imuon=0;imuon<10;imuon++) nMuonTrack[imuon]=0;

  for (Int_t nMuTrack = 0; nMuTrack < nMuTracks; ++nMuTrack) {
    esdMuTrack = esd->GetMuonTrack(nMuTrack);

    if (!esdMuTrack->ContainTrackerData()) continue;

    UInt_t selectInfo = 0;
    // Track selection
    if (fTrackFilter) {
     	selectInfo = fTrackFilter->IsSelected(esdMuTrack);
     	if (!selectInfo) {
     	  continue;
     	}
    }

    p[0] = esdMuTrack->Px();
    p[1] = esdMuTrack->Py();
    p[2] = esdMuTrack->Pz();

    pos[0] = esdMuTrack->GetNonBendingCoor();
    pos[1] = esdMuTrack->GetBendingCoor();
    pos[2] = esdMuTrack->GetZ();

    if(mcH)mcH->SelectParticle(esdMuTrack->GetLabel());

    aodTrack = new(tracks[jTracks++]) AliAODTrack(esdMuTrack->GetUniqueID(), // ID
						  esdMuTrack->GetLabel(), // label
						  p, // momentum
						  kTRUE, // cartesian coordinate system
						  pos, // position
						  kFALSE, // isDCA
						  0x0, // covariance matrix
						  esdMuTrack->Charge(), // charge
						  0, // ITSClusterMap
						  pid, // pid
						  primary, // primary vertex
						  kFALSE, // used for vertex fit?
						  kFALSE, // used for primary vertex fit?
						  AliAODTrack::kPrimary,// track type
						  selectInfo);

    aodTrack->SetXYAtDCA(esdMuTrack->GetNonBendingCoorAtDCA(), esdMuTrack->GetBendingCoorAtDCA());
    aodTrack->SetPxPyPzAtDCA(esdMuTrack->PxAtDCA(), esdMuTrack->PyAtDCA(), esdMuTrack->PzAtDCA());
    aodTrack->ConvertAliPIDtoAODPID();
    aodTrack->SetChi2perNDF(esdMuTrack->GetChi2() / (2.*esdMuTrack->GetNHit() - 5.));
    aodTrack->SetChi2MatchTrigger(esdMuTrack->GetChi2MatchTrigger());
    aodTrack->SetHitsPatternInTrigCh(esdMuTrack->GetHitsPatternInTrigCh());
    aodTrack->SetMuonClusterMap(esdMuTrack->GetMuonClusterMap());
    aodTrack->SetMatchTrigger(esdMuTrack->GetMatchTrigger());
    aodTrack->Connected(esdMuTrack->IsConnected());
    primary->AddDaughter(aodTrack);

    if (esdMuTrack->Charge() > 0) nPosTracks++;
    else nNegTracks++;

    nMuonTrack[nMuons]= jTracks-1.;
    nMuons++;
  }

    if(nMuons>=2) DimuonsExist = kTRUE;
    if(DimuonsExist) {
      for(int i=0;i<nMuons;i++){
        Int_t index0 = nMuonTrack[i];
	for(int j=i+1;j<nMuons;j++){
          Int_t index1 = nMuonTrack[j];
          aodDimuon = new(dimuons[jDimuons++]) AliAODDimuon(tracks.At(index0),tracks.At(index1));
          if (fDebug > 1){
            AliAODDimuon *dimuon0 = (AliAODDimuon*)dimuons.At(jDimuons-1);
            printf("Dimuon: mass = %f, px=%f, py=%f, pz=%f\n",dimuon0->M(),dimuon0->Px(),dimuon0->Py(),dimuon0->Pz());
            AliAODTrack  *mu0 = (AliAODTrack*) dimuon0->GetMu(0);
            AliAODTrack  *mu1 = (AliAODTrack*) dimuon0->GetMu(1);
            printf("Muon0 px=%f py=%f pz=%f\n",mu0->Px(),mu0->Py(),mu0->Pz());
            printf("Muon1 px=%f py=%f pz=%f\n",mu1->Px(),mu1->Py(),mu1->Pz());
	  }
        }
      }
    }

  header->SetRefMultiplicity(jTracks);
  header->SetRefMultiplicityPos(nPosTracks);
  header->SetRefMultiplicityNeg(nNegTracks);

  // From Andrei
  if(fEnableMuonAOD && MuonsExist){
    AliAODExtension *extMuons = dynamic_cast<AliAODHandler*>
    ((AliAnalysisManager::GetAnalysisManager())->GetOutputEventHandler())->GetFilteredAOD("AliAOD.Muons.root");
    extMuons->SelectEvent();
  }

  if(fEnableDimuonAOD && DimuonsExist){
    AliAODExtension *extDimuons = dynamic_cast<AliAODHandler*>
   ((AliAnalysisManager::GetAnalysisManager())->GetOutputEventHandler())->GetFilteredAOD("AliAOD.Dimuons.root");
    extDimuons->SelectEvent();
  }

}

void AliAnalysisTaskESDMuonFilter::Terminate(Option_t */*option*/)
{
  // Terminate analysis
  //
  if (fDebug > 1) printf("AnalysisESDfilter: Terminate() \n");
}

void  AliAnalysisTaskESDMuonFilter::PrintMCInfo(AliStack *pStack,Int_t label){
  if(!pStack)return;
  label = TMath::Abs(label);
  TParticle *part = pStack->Particle(label);
  Printf("########################");
  Printf("%s:%d %d UniqueID %d PDG %d P %3.3f",(char*)__FILE__,__LINE__,label,part->GetUniqueID(),part->GetPdgCode(),part->P());
  part->Print();
  TParticle* mother = part;
  Int_t imo = part->GetFirstMother();
  Int_t nprim = pStack->GetNprimary();
  //  while((imo >= nprim) && (mother->GetUniqueID() == 4)) {
  while((imo >= nprim)) {
    mother =  pStack->Particle(imo);
    Printf("Mother %s:%d Label %d UniqueID %d PDG %d P %3.3f",(char*)__FILE__,__LINE__,imo,mother->GetUniqueID(),mother->GetPdgCode(),mother->P());
    mother->Print();
    imo =  mother->GetFirstMother();
  }
  Printf("########################");
}
<|endoftext|>