<commit_before>/*	opendatacon
 *
 *	Copyright (c) 2014:
 *
 *		DCrip3fJguWgVCLrZFfA7sIGgvx1Ou3fHfCxnrz4svAi
 *		yxeOtDhDCXf1Z4ApgXvX5ahqQmzRfJ2DoX8S05SqHA==
 *
 *	Licensed under the Apache License, Version 2.0 (the "License");
 *	you may not use this file except in compliance with the License.
 *	You may obtain a copy of the License at
 *
 *		http://www.apache.org/licenses/LICENSE-2.0
 *
 *	Unless required by applicable law or agreed to in writing, software
 *	distributed under the License is distributed on an "AS IS" BASIS,
 *	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *	See the License for the specific language governing permissions and
 *	limitations under the License.
 */
/*
 * DataConnector.cpp
 *
 *  Created on: 15/07/2014
 *      Author: Neil Stephens <dearknarl@gmail.com>
 */

#include <future>
#include <iostream>
#include <asiodnp3/DNP3Manager.h>
#include <opendnp3/LogLevels.h>
#include "DataConnector.h"
#include "IndexOffsetTransform.h"
#include "ThresholdTransform.h"
#include "RandTransform.h"
#include "RateLimitTransform.h"
#include <opendatacon/Platform.h>

DataConnector::DataConnector(std::string aName, std::string aConfFilename, const Json::Value aConfOverrides):
	IOHandler(aName),
	ConfigParser(aConfFilename, aConfOverrides)
{
	ProcessFile();
}

void DataConnector::ProcessElements(const Json::Value& JSONRoot)
{
	if(!JSONRoot.isObject()) return;
	if(!JSONRoot["Connections"].isNull())
	{
		const Json::Value JConnections = JSONRoot["Connections"];

		for(Json::ArrayIndex n = 0; n < JConnections.size(); ++n)
		{
			try
			{
				if(JConnections[n]["Name"].isNull() || JConnections[n]["Port1"].isNull() || JConnections[n]["Port2"].isNull())
				{
					std::cout<<"Warning: invalid Connection config: need at least Name, From and To: \n'"<<JConnections[n].toStyledString()<<"\n' : ignoring"<<std::endl;
					continue;
				}
				auto ConName = JConnections[n]["Name"].asString();
				auto ConPort1 = JConnections[n]["Port1"].asString();
				auto ConPort2 = JConnections[n]["Port2"].asString();
				if ((GetIOHandlers().count(ConPort1) == 0) || (GetIOHandlers().count(ConPort2) == 0))
				{
					std::cout << "Warning: invalid port on connection '" << ConName << "' skipping..." << std::endl;
					continue;
				}
				Connections[ConName] = std::make_pair(GetIOHandlers()[ConPort1], GetIOHandlers()[ConPort2]);
				//Subscribe to recieve events for the connection
				GetIOHandlers()[ConPort1]->Subscribe(this, this->Name);
				GetIOHandlers()[ConPort2]->Subscribe(this, this->Name);
				//Add to the lookup table
				SenderConnectionsLookup.insert(std::make_pair(ConPort1, ConName));
				SenderConnectionsLookup.insert(std::make_pair(ConPort2, ConName));
			}
			catch (std::exception& e)
			{
				std::cout<<"Warning: Exception raised when creating Connection from config: \n'"<<JConnections[n].toStyledString()<<"\n' : ignoring"<<std::endl;
			}
		}
	}
	if(!JSONRoot["Transforms"].isNull())
	{
		const Json::Value Transforms = JSONRoot["Transforms"];

		for(Json::ArrayIndex n = 0; n < Transforms.size(); ++n)
		{
			try
			{
				if(Transforms[n]["Type"].isNull() || Transforms[n]["Sender"].isNull())
				{
					std::cout<<"Warning: invalid Transform config: need at least Type and Sender: \n'"<<Transforms[n].toStyledString()<<"\n' : ignoring"<<std::endl;
					continue;
				}

				auto normal_delete = [](Transform* pTx){delete pTx;};

				if(Transforms[n]["Type"].asString() == "IndexOffset")
				{
					ConnectionTransforms[Transforms[n]["Sender"].asString()].push_back(std::unique_ptr<Transform, void(*)(Transform*)>(new IndexOffsetTransform(Transforms[n]["Parameters"]), normal_delete));
					continue;
				}
				if(Transforms[n]["Type"].asString() == "Threshold")
				{
					ConnectionTransforms[Transforms[n]["Sender"].asString()].push_back(std::unique_ptr<Transform, void(*)(Transform*)>(new ThresholdTransform(Transforms[n]["Parameters"]), normal_delete));
					continue;
				}
				if(Transforms[n]["Type"].asString() == "Rand")
				{
					ConnectionTransforms[Transforms[n]["Sender"].asString()].push_back(std::unique_ptr<Transform, void(*)(Transform*)>(new RandTransform(Transforms[n]["Parameters"]), normal_delete));
					continue;
				}
				if(Transforms[n]["Type"].asString() == "RateLimit")
				{
					ConnectionTransforms[Transforms[n]["Sender"].asString()].push_back(std::unique_ptr<Transform, void(*)(Transform*)>(new RateLimitTransform(Transforms[n]["Parameters"]), normal_delete));
					continue;
				}

				//Looks for a specific library (for libs that implement more than one class)
				std::string libname;
				if(!Transforms[n]["Library"].isNull())
				{
					libname = GetLibFileName(Transforms[n]["Library"].asString());
				}
				//Otherwise use the naming convention lib<Type>Port.so to find the default lib that implements a type of port
				else
				{
					libname = GetLibFileName(Transforms[n]["Type"].asString());
				}

				//try to load the lib
				auto* txlib = LoadModule(libname.c_str());

				if(txlib == nullptr)
				{
					std::cout << "Warning: failed to load library '"<<libname<<"' skipping transform..."<<std::endl;
					continue;
				}

				//Our API says the library should export a creation function: Transform* new_<Type>Transform(Params)
				//it should return a pointer to a heap allocated instance of a descendant of Transform
				std::string new_funcname = "new_"+Transforms[n]["Type"].asString()+"Transform";
				auto new_tx_func = (Transform*(*)(const Json::Value))LoadSymbol(txlib, new_funcname.c_str());
				std::string delete_funcname = "delete_"+Transforms[n]["Type"].asString()+"Transform";
				auto delete_tx_func = (void(*)(Transform*))LoadSymbol(txlib, delete_funcname.c_str());

				if(new_tx_func == nullptr)
					std::cout << "Warning: failed to load symbol '"<<new_funcname<< "' from library '" << libname << "' - " << LastSystemError() << std::endl;
				if(delete_tx_func == nullptr)
					std::cout << "Warning: failed to load symbol '"<<delete_funcname<< "' from library '" << libname << "' - " << LastSystemError() << std::endl;
				if(new_tx_func == nullptr || delete_tx_func == nullptr)
				{
					std::cout<<"'Skipping transform '"<<Transforms[n]["Type"].asString()<<"'..."<<std::endl;
					continue;
				}

				//call the creation function and wrap the returned pointer
				ConnectionTransforms[Transforms[n]["Sender"].asString()].push_back(std::unique_ptr<Transform, void(*)(Transform*)>(new_tx_func(Transforms[n]["Params"].asString()),delete_tx_func));
			}
			catch (std::exception& e)
			{
				std::cout<<"Warning: Exception raised when creating Transform from config: \n'"<<Transforms[n].toStyledString()<<"\n' : ignoring"<<std::endl;
			}
		}
	}
}

std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::Binary& meas, uint16_t index, const std::string& SenderName){ return EventT(meas, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::DoubleBitBinary& meas, uint16_t index, const std::string& SenderName){ return EventT(meas, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::Analog& meas, uint16_t index, const std::string& SenderName){ return EventT(meas, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::Counter& meas, uint16_t index, const std::string& SenderName){ return EventT(meas, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::FrozenCounter& meas, uint16_t index, const std::string& SenderName){ return EventT(meas, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::BinaryOutputStatus& meas, uint16_t index, const std::string& SenderName){ return EventT(meas, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::AnalogOutputStatus& meas, uint16_t index, const std::string& SenderName){ return EventT(meas, index, SenderName); }

std::future<opendnp3::CommandStatus> DataConnector::Event(const ::BinaryQuality qual, uint16_t index, const std::string& SenderName){ return EventT(qual, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const ::DoubleBitBinaryQuality qual, uint16_t index, const std::string& SenderName){ return EventT(qual, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const ::AnalogQuality qual, uint16_t index, const std::string& SenderName){ return EventT(qual, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const ::CounterQuality qual, uint16_t index, const std::string& SenderName){ return EventT(qual, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const ::FrozenCounterQuality qual, uint16_t index, const std::string& SenderName){ return EventT(qual, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const ::BinaryOutputStatusQuality qual, uint16_t index, const std::string& SenderName){ return EventT(qual, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const ::AnalogOutputStatusQuality qual, uint16_t index, const std::string& SenderName){ return EventT(qual, index, SenderName); }

std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::ControlRelayOutputBlock& arCommand, uint16_t index, const std::string& SenderName){ return EventT(arCommand, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::AnalogOutputInt16& arCommand, uint16_t index, const std::string& SenderName){ return EventT(arCommand, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::AnalogOutputInt32& arCommand, uint16_t index, const std::string& SenderName){ return EventT(arCommand, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::AnalogOutputFloat32& arCommand, uint16_t index, const std::string& SenderName){ return EventT(arCommand, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::AnalogOutputDouble64& arCommand, uint16_t index, const std::string& SenderName){ return EventT(arCommand, index, SenderName); }

std::future<opendnp3::CommandStatus> DataConnector::Event(ConnectState state, uint16_t index, const std::string& SenderName)
{
	if(MuxConnectionEvents(state, SenderName))
		return EventT(state, index, SenderName);
	else
		return IOHandler::CommandFutureUndefined();
}

template<typename T>
inline std::future<opendnp3::CommandStatus> DataConnector::EventT(const T& event_obj, uint16_t index, const std::string& SenderName)
{
	if(!enabled)
	{
		return IOHandler::CommandFutureUndefined();
	}

	auto bounds = SenderConnectionsLookup.equal_range(SenderName);
	//Do we have a connection for this sender?
	if(bounds.first != bounds.second) //yes
	{
		auto new_event_obj(event_obj);
		if(ConnectionTransforms.count(SenderName))
		{
			for(auto& Transform : ConnectionTransforms[SenderName])
			{
				if(!Transform->Event(new_event_obj, index))
					return IOHandler::CommandFutureUndefined();
			}
		}

		std::vector<std::future<opendnp3::CommandStatus> > returns;
		for(auto aMatch_it = bounds.first; aMatch_it != bounds.second; aMatch_it++)
		{
			//guess which one is the sendee
			IOHandler* pSendee = Connections[aMatch_it->second].second;

			//check if we were right and correct if need be
			if(pSendee->Name == SenderName)
				pSendee = Connections[aMatch_it->second].first;

			returns.push_back(pSendee->Event(new_event_obj, index, this->Name));
		}
		for(auto& ret : returns)
		{
			if(ret.get() != opendnp3::CommandStatus::SUCCESS)
				return IOHandler::CommandFutureUndefined();
		}
		return std::move(returns.back());
	}
	//no connection for sender if we get here
	std::string msg = "Connector '"+this->Name+"' discarding event from '"+SenderName+"' (No connection defined)";
	auto log_entry = openpal::LogEntry("DataConnector", openpal::logflags::WARN,"", msg.c_str(), -1);
	pLoggers->Log(log_entry);

	return IOHandler::CommandFutureUndefined();
}

void DataConnector::BuildOrRebuild(asiodnp3::DNP3Manager& DNP3Mgr, openpal::LogFilters& LOG_LEVEL)
{}
void DataConnector::Enable()
{
	enabled = true;
}
void DataConnector::Disable()
{
	enabled = false;
}

<commit_msg>Added check to prohibit duplicate Connection names<commit_after>/*	opendatacon
 *
 *	Copyright (c) 2014:
 *
 *		DCrip3fJguWgVCLrZFfA7sIGgvx1Ou3fHfCxnrz4svAi
 *		yxeOtDhDCXf1Z4ApgXvX5ahqQmzRfJ2DoX8S05SqHA==
 *
 *	Licensed under the Apache License, Version 2.0 (the "License");
 *	you may not use this file except in compliance with the License.
 *	You may obtain a copy of the License at
 *
 *		http://www.apache.org/licenses/LICENSE-2.0
 *
 *	Unless required by applicable law or agreed to in writing, software
 *	distributed under the License is distributed on an "AS IS" BASIS,
 *	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *	See the License for the specific language governing permissions and
 *	limitations under the License.
 */
/*
 * DataConnector.cpp
 *
 *  Created on: 15/07/2014
 *      Author: Neil Stephens <dearknarl@gmail.com>
 */

#include <future>
#include <iostream>
#include <asiodnp3/DNP3Manager.h>
#include <opendnp3/LogLevels.h>
#include "DataConnector.h"
#include "IndexOffsetTransform.h"
#include "ThresholdTransform.h"
#include "RandTransform.h"
#include "RateLimitTransform.h"
#include <opendatacon/Platform.h>

DataConnector::DataConnector(std::string aName, std::string aConfFilename, const Json::Value aConfOverrides):
	IOHandler(aName),
	ConfigParser(aConfFilename, aConfOverrides)
{
	ProcessFile();
}

void DataConnector::ProcessElements(const Json::Value& JSONRoot)
{
	if(!JSONRoot.isObject()) return;
	if(!JSONRoot["Connections"].isNull())
	{
		const Json::Value JConnections = JSONRoot["Connections"];

		for(Json::ArrayIndex n = 0; n < JConnections.size(); ++n)
		{
			try
			{
				if(JConnections[n]["Name"].isNull() || JConnections[n]["Port1"].isNull() || JConnections[n]["Port2"].isNull())
				{
					std::cout<<"Warning: invalid Connection config: need at least Name, From and To: \n'"<<JConnections[n].toStyledString()<<"\n' : ignoring"<<std::endl;
					continue;
				}
				auto ConName = JConnections[n]["Name"].asString();
				if(Connections.count(ConName))
				{
					std::cout<<"Warning: invalid Connection config: Duplicate Name: \n'"<<JConnections[n].toStyledString()<<"\n' : ignoring"<<std::endl;
					continue;
				}
				auto ConPort1 = JConnections[n]["Port1"].asString();
				auto ConPort2 = JConnections[n]["Port2"].asString();
				if ((GetIOHandlers().count(ConPort1) == 0) || (GetIOHandlers().count(ConPort2) == 0))
				{
					std::cout << "Warning: invalid port on connection '" << ConName << "' skipping..." << std::endl;
					continue;
				}
				Connections[ConName] = std::make_pair(GetIOHandlers()[ConPort1], GetIOHandlers()[ConPort2]);
				//Subscribe to recieve events for the connection
				GetIOHandlers()[ConPort1]->Subscribe(this, this->Name);
				GetIOHandlers()[ConPort2]->Subscribe(this, this->Name);
				//Add to the lookup table
				SenderConnectionsLookup.insert(std::make_pair(ConPort1, ConName));
				SenderConnectionsLookup.insert(std::make_pair(ConPort2, ConName));
			}
			catch (std::exception& e)
			{
				std::cout<<"Warning: Exception raised when creating Connection from config: \n'"<<JConnections[n].toStyledString()<<"\n' : ignoring"<<std::endl;
			}
		}
	}
	if(!JSONRoot["Transforms"].isNull())
	{
		const Json::Value Transforms = JSONRoot["Transforms"];

		for(Json::ArrayIndex n = 0; n < Transforms.size(); ++n)
		{
			try
			{
				if(Transforms[n]["Type"].isNull() || Transforms[n]["Sender"].isNull())
				{
					std::cout<<"Warning: invalid Transform config: need at least Type and Sender: \n'"<<Transforms[n].toStyledString()<<"\n' : ignoring"<<std::endl;
					continue;
				}

				auto normal_delete = [](Transform* pTx){delete pTx;};

				if(Transforms[n]["Type"].asString() == "IndexOffset")
				{
					ConnectionTransforms[Transforms[n]["Sender"].asString()].push_back(std::unique_ptr<Transform, void(*)(Transform*)>(new IndexOffsetTransform(Transforms[n]["Parameters"]), normal_delete));
					continue;
				}
				if(Transforms[n]["Type"].asString() == "Threshold")
				{
					ConnectionTransforms[Transforms[n]["Sender"].asString()].push_back(std::unique_ptr<Transform, void(*)(Transform*)>(new ThresholdTransform(Transforms[n]["Parameters"]), normal_delete));
					continue;
				}
				if(Transforms[n]["Type"].asString() == "Rand")
				{
					ConnectionTransforms[Transforms[n]["Sender"].asString()].push_back(std::unique_ptr<Transform, void(*)(Transform*)>(new RandTransform(Transforms[n]["Parameters"]), normal_delete));
					continue;
				}
				if(Transforms[n]["Type"].asString() == "RateLimit")
				{
					ConnectionTransforms[Transforms[n]["Sender"].asString()].push_back(std::unique_ptr<Transform, void(*)(Transform*)>(new RateLimitTransform(Transforms[n]["Parameters"]), normal_delete));
					continue;
				}

				//Looks for a specific library (for libs that implement more than one class)
				std::string libname;
				if(!Transforms[n]["Library"].isNull())
				{
					libname = GetLibFileName(Transforms[n]["Library"].asString());
				}
				//Otherwise use the naming convention lib<Type>Port.so to find the default lib that implements a type of port
				else
				{
					libname = GetLibFileName(Transforms[n]["Type"].asString());
				}

				//try to load the lib
				auto* txlib = LoadModule(libname.c_str());

				if(txlib == nullptr)
				{
					std::cout << "Warning: failed to load library '"<<libname<<"' skipping transform..."<<std::endl;
					continue;
				}

				//Our API says the library should export a creation function: Transform* new_<Type>Transform(Params)
				//it should return a pointer to a heap allocated instance of a descendant of Transform
				std::string new_funcname = "new_"+Transforms[n]["Type"].asString()+"Transform";
				auto new_tx_func = (Transform*(*)(const Json::Value))LoadSymbol(txlib, new_funcname.c_str());
				std::string delete_funcname = "delete_"+Transforms[n]["Type"].asString()+"Transform";
				auto delete_tx_func = (void(*)(Transform*))LoadSymbol(txlib, delete_funcname.c_str());

				if(new_tx_func == nullptr)
					std::cout << "Warning: failed to load symbol '"<<new_funcname<< "' from library '" << libname << "' - " << LastSystemError() << std::endl;
				if(delete_tx_func == nullptr)
					std::cout << "Warning: failed to load symbol '"<<delete_funcname<< "' from library '" << libname << "' - " << LastSystemError() << std::endl;
				if(new_tx_func == nullptr || delete_tx_func == nullptr)
				{
					std::cout<<"'Skipping transform '"<<Transforms[n]["Type"].asString()<<"'..."<<std::endl;
					continue;
				}

				//call the creation function and wrap the returned pointer
				ConnectionTransforms[Transforms[n]["Sender"].asString()].push_back(std::unique_ptr<Transform, void(*)(Transform*)>(new_tx_func(Transforms[n]["Params"].asString()),delete_tx_func));
			}
			catch (std::exception& e)
			{
				std::cout<<"Warning: Exception raised when creating Transform from config: \n'"<<Transforms[n].toStyledString()<<"\n' : ignoring"<<std::endl;
			}
		}
	}
}

std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::Binary& meas, uint16_t index, const std::string& SenderName){ return EventT(meas, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::DoubleBitBinary& meas, uint16_t index, const std::string& SenderName){ return EventT(meas, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::Analog& meas, uint16_t index, const std::string& SenderName){ return EventT(meas, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::Counter& meas, uint16_t index, const std::string& SenderName){ return EventT(meas, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::FrozenCounter& meas, uint16_t index, const std::string& SenderName){ return EventT(meas, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::BinaryOutputStatus& meas, uint16_t index, const std::string& SenderName){ return EventT(meas, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::AnalogOutputStatus& meas, uint16_t index, const std::string& SenderName){ return EventT(meas, index, SenderName); }

std::future<opendnp3::CommandStatus> DataConnector::Event(const ::BinaryQuality qual, uint16_t index, const std::string& SenderName){ return EventT(qual, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const ::DoubleBitBinaryQuality qual, uint16_t index, const std::string& SenderName){ return EventT(qual, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const ::AnalogQuality qual, uint16_t index, const std::string& SenderName){ return EventT(qual, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const ::CounterQuality qual, uint16_t index, const std::string& SenderName){ return EventT(qual, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const ::FrozenCounterQuality qual, uint16_t index, const std::string& SenderName){ return EventT(qual, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const ::BinaryOutputStatusQuality qual, uint16_t index, const std::string& SenderName){ return EventT(qual, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const ::AnalogOutputStatusQuality qual, uint16_t index, const std::string& SenderName){ return EventT(qual, index, SenderName); }

std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::ControlRelayOutputBlock& arCommand, uint16_t index, const std::string& SenderName){ return EventT(arCommand, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::AnalogOutputInt16& arCommand, uint16_t index, const std::string& SenderName){ return EventT(arCommand, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::AnalogOutputInt32& arCommand, uint16_t index, const std::string& SenderName){ return EventT(arCommand, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::AnalogOutputFloat32& arCommand, uint16_t index, const std::string& SenderName){ return EventT(arCommand, index, SenderName); }
std::future<opendnp3::CommandStatus> DataConnector::Event(const opendnp3::AnalogOutputDouble64& arCommand, uint16_t index, const std::string& SenderName){ return EventT(arCommand, index, SenderName); }

std::future<opendnp3::CommandStatus> DataConnector::Event(ConnectState state, uint16_t index, const std::string& SenderName)
{
	if(MuxConnectionEvents(state, SenderName))
		return EventT(state, index, SenderName);
	else
		return IOHandler::CommandFutureUndefined();
}

template<typename T>
inline std::future<opendnp3::CommandStatus> DataConnector::EventT(const T& event_obj, uint16_t index, const std::string& SenderName)
{
	if(!enabled)
	{
		return IOHandler::CommandFutureUndefined();
	}

	auto bounds = SenderConnectionsLookup.equal_range(SenderName);
	//Do we have a connection for this sender?
	if(bounds.first != bounds.second) //yes
	{
		auto new_event_obj(event_obj);
		if(ConnectionTransforms.count(SenderName))
		{
			for(auto& Transform : ConnectionTransforms[SenderName])
			{
				if(!Transform->Event(new_event_obj, index))
					return IOHandler::CommandFutureUndefined();
			}
		}

		std::vector<std::future<opendnp3::CommandStatus> > returns;
		for(auto aMatch_it = bounds.first; aMatch_it != bounds.second; aMatch_it++)
		{
			//guess which one is the sendee
			IOHandler* pSendee = Connections[aMatch_it->second].second;

			//check if we were right and correct if need be
			if(pSendee->Name == SenderName)
				pSendee = Connections[aMatch_it->second].first;

			returns.push_back(pSendee->Event(new_event_obj, index, this->Name));
		}
		for(auto& ret : returns)
		{
			if(ret.get() != opendnp3::CommandStatus::SUCCESS)
				return IOHandler::CommandFutureUndefined();
		}
		return std::move(returns.back());
	}
	//no connection for sender if we get here
	std::string msg = "Connector '"+this->Name+"' discarding event from '"+SenderName+"' (No connection defined)";
	auto log_entry = openpal::LogEntry("DataConnector", openpal::logflags::WARN,"", msg.c_str(), -1);
	pLoggers->Log(log_entry);

	return IOHandler::CommandFutureUndefined();
}

void DataConnector::BuildOrRebuild(asiodnp3::DNP3Manager& DNP3Mgr, openpal::LogFilters& LOG_LEVEL)
{}
void DataConnector::Enable()
{
	enabled = true;
}
void DataConnector::Disable()
{
	enabled = false;
}

<|endoftext|>


<commit_before><commit_msg>update supernode ip and remove depecrated dnsseed<commit_after><|endoftext|>


<commit_before>#include "include/moduler.hpp"
#include <loader/include/loader.hpp>
#include <logger/include/logger.hpp>
#include <sstream>

namespace moduler
{
	static Moduler *modulerInstance{ nullptr };

	class ModulerPrivate
	{
	public:
		loader::Loader *loaderInstance{ nullptr };

		ModulerPrivate()
			: loaderInstance{ loader::createLoader() } {}

		~ModulerPrivate() { loader::destroyLoader(); }
	};

	Moduler::Moduler()
	{
		m_private = new ModulerPrivate;
	}

	Moduler::~Moduler()
	{
		delete m_private;
	}

	typedef moduler::IModule * (*createModuleFunc)();
	typedef void (*deleteModuleFunc)(moduler::IModule *74);

	IModule *Moduler::loadModule(const char * fileName)
	{
		LOG_DEBUG_STR("Going to open " << fileName);
		auto *moduleData(m_private->loaderInstance->loadModule(fileName));
		if (moduleData) {
			LOG_DEBUG("Object file loaded");
			auto creatorFunc = static_cast<createModuleFunc>(m_private->loaderInstance->loadMethod(fileName, "createModule"));
			IModule *loadedModule = creatorFunc();
			return loadedModule;
		}
		return nullptr;
	}

	Moduler *createModuler ()
	{
		if (!modulerInstance) {
			LOG_DEBUG("Creating moduler...");
			modulerInstance = new Moduler;
			LOG_DEBUG("Moduler created");
		}
		else {
			LOG_DEBUG("Moduler already reated");
		}

		return modulerInstance;
	}

	void destroyModuler()
	{
		if (modulerInstance)
		{
			LOG_DEBUG("Destroying moduler...");
			delete modulerInstance;
			modulerInstance = nullptr;
			LOG_DEBUG("Moduler destroyed");
		}
	}
}
<commit_msg>Loading also deleter method<commit_after>#include "include/moduler.hpp"
#include <loader/include/loader.hpp>
#include <logger/include/logger.hpp>
#include <sstream>

namespace moduler
{
	static Moduler *modulerInstance{ nullptr };

	class ModulerPrivate
	{
	public:
		loader::Loader *loaderInstance{ nullptr };

		ModulerPrivate()
			: loaderInstance{ loader::createLoader() } {}

		~ModulerPrivate() { loader::destroyLoader(); }
	};

	Moduler::Moduler()
	{
		m_private = new ModulerPrivate;
	}

	Moduler::~Moduler()
	{
		delete m_private;
	}

	typedef moduler::IModule * (*createModuleFunc)();
	typedef void (*deleteModuleFunc)(moduler::IModule *);

	IModule *Moduler::loadModule(const char * fileName)
	{
		LOG_DEBUG_STR("Going to open " << fileName);
		auto *moduleData(m_private->loaderInstance->loadModule(fileName));
		if (moduleData) {
			LOG_DEBUG("Object file loaded");
			auto creatorFunc = static_cast<createModuleFunc>(m_private->loaderInstance->loadMethod(fileName, "createModule"));
			auto deleterFunc = static_cast<deleteModuleFunc>(m_private->loaderInstance->loadMethod(fileName, "deleteModule"));
			if (creatorFunc && deleterFunc) {
				IModule *loadedModule = creatorFunc();
				return loadedModule;
			}
			else {
				LOG_WARNING("Cannot read method createModule()");
			}
		}
		return nullptr;
	}

	Moduler *createModuler ()
	{
		if (!modulerInstance) {
			LOG_DEBUG("Creating moduler...");
			modulerInstance = new Moduler;
			LOG_DEBUG("Moduler created");
		}
		else {
			LOG_DEBUG("Moduler already reated");
		}

		return modulerInstance;
	}

	void destroyModuler()
	{
		if (modulerInstance)
		{
			LOG_DEBUG("Destroying moduler...");
			delete modulerInstance;
			modulerInstance = nullptr;
			LOG_DEBUG("Moduler destroyed");
		}
	}
}
<|endoftext|>


<commit_before>// Copyright Daniel Wallin 2006. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <libtorrent/session.hpp>
#include <boost/python.hpp>

using namespace boost::python;
using namespace libtorrent;

struct entry_to_python
{
    static object convert(entry::list_type const& l)
    {
        list result;

        for (entry::list_type::const_iterator i(l.begin()), e(l.end()); i != e; ++i)
        {
            result.append(*i);
        }

        return result;
    }

    static object convert(entry::dictionary_type const& d)
    {
        dict result;

        for (entry::dictionary_type::const_iterator i(d.begin()), e(d.end()); i != e; ++i)
            result[i->first] = i->second;

        return result;
    }

    static object convert0(entry const& e)
    {
        switch (e.type())
        {
        case entry::int_t:
            return object(e.integer());
        case entry::string_t:
            return object(e.string());
        case entry::list_t:
            return convert(e.list());
        case entry::dictionary_t:
            return convert(e.dict());
        default:
            return object();
        }
    }

    static PyObject* convert(entry const& e)
    {
        return incref(convert0(e).ptr());
    }
};

struct entry_from_python
{
    entry_from_python()
    {
        converter::registry::push_back(
            &convertible, &construct, type_id<entry>()
        );
    }

    static void* convertible(PyObject* e)
    {
        return e;
    }

    static entry construct0(object e)
    {
        if (extract<dict>(e).check())
        {
            dict d = extract<dict>(e);
            list items(d.items());
            std::size_t length = extract<std::size_t>(items.attr("__len__")());
            entry result(entry::dictionary_t);

            for (std::size_t i = 0; i < length; ++i)
            {
                result.dict().insert(
                    std::make_pair(
                        extract<char const*>(items[i][0])()
                      , construct0(items[i][1])
                    )
                );
            }

            return result;
        }
        else if (extract<list>(e).check())
        {
            list l = extract<list>(e);

            std::size_t length = extract<std::size_t>(l.attr("__len__")());
            entry result(entry::list_t);

            for (std::size_t i = 0; i < length; ++i)
            {
                result.list().push_back(construct0(l[i]));
            }

            return result;
        }
        else if (extract<str>(e).check())
        {
            return entry(extract<std::string>(e)());
        }
        else if (extract<entry::integer_type>(e).check())
        {
            return entry(extract<entry::integer_type>(e)());
        }

        return entry();
    }

    static void construct(PyObject* e, converter::rvalue_from_python_stage1_data* data)
    {
        void* storage = ((converter::rvalue_from_python_storage<entry>*)data)->storage.bytes;
        new (storage) entry(construct0(object(borrowed(e))));
        data->convertible = storage;
    }
};

void bind_entry()
{
    to_python_converter<entry, entry_to_python>();
    entry_from_python();
}

<commit_msg>Register to_python converter for shared_ptr<entry><commit_after>// Copyright Daniel Wallin 2006. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <libtorrent/session.hpp>
#include <boost/python.hpp>

using namespace boost::python;
using namespace libtorrent;

struct entry_to_python
{
    static object convert(entry::list_type const& l)
    {
        list result;

        for (entry::list_type::const_iterator i(l.begin()), e(l.end()); i != e; ++i)
        {
            result.append(*i);
        }

        return result;
    }

    static object convert(entry::dictionary_type const& d)
    {
        dict result;

        for (entry::dictionary_type::const_iterator i(d.begin()), e(d.end()); i != e; ++i)
            result[i->first] = i->second;

        return result;
    }

    static object convert0(entry const& e)
    {
        switch (e.type())
        {
        case entry::int_t:
            return object(e.integer());
        case entry::string_t:
            return object(e.string());
        case entry::list_t:
            return convert(e.list());
        case entry::dictionary_t:
            return convert(e.dict());
        default:
            return object();
        }
    }

    static PyObject* convert(boost::shared_ptr<entry> const& e)
    {
        if (!e)
            return incref(Py_None);
        return convert(*e);
    }

    static PyObject* convert(entry const& e)
    {
        return incref(convert0(e).ptr());
    }
};

struct entry_from_python
{
    entry_from_python()
    {
        converter::registry::push_back(
            &convertible, &construct, type_id<entry>()
        );
    }

    static void* convertible(PyObject* e)
    {
        return e;
    }

    static entry construct0(object e)
    {
        if (extract<dict>(e).check())
        {
            dict d = extract<dict>(e);
            list items(d.items());
            std::size_t length = extract<std::size_t>(items.attr("__len__")());
            entry result(entry::dictionary_t);

            for (std::size_t i = 0; i < length; ++i)
            {
                result.dict().insert(
                    std::make_pair(
                        extract<char const*>(items[i][0])()
                      , construct0(items[i][1])
                    )
                );
            }

            return result;
        }
        else if (extract<list>(e).check())
        {
            list l = extract<list>(e);

            std::size_t length = extract<std::size_t>(l.attr("__len__")());
            entry result(entry::list_t);

            for (std::size_t i = 0; i < length; ++i)
            {
                result.list().push_back(construct0(l[i]));
            }

            return result;
        }
        else if (extract<str>(e).check())
        {
            return entry(extract<std::string>(e)());
        }
        else if (extract<entry::integer_type>(e).check())
        {
            return entry(extract<entry::integer_type>(e)());
        }

        return entry();
    }

    static void construct(PyObject* e, converter::rvalue_from_python_stage1_data* data)
    {
        void* storage = ((converter::rvalue_from_python_storage<entry>*)data)->storage.bytes;
        new (storage) entry(construct0(object(borrowed(e))));
        data->convertible = storage;
    }
};

void bind_entry()
{
    to_python_converter<boost::shared_ptr<libtorrent::entry>, entry_to_python>();
    to_python_converter<entry, entry_to_python>();
    entry_from_python();
}

<|endoftext|>


<commit_before>#include <stdio.h>
#include <string>
#include "core/general.h"
#include "core/debug.h"
#include "core/native/native.h"
#include "core/interface/engine.h"
#include "includes/switches.h"
#include "io.h"

using namespace ink;
using namespace std;

extern InkMod_ModuleID ink_native_file_mod_id;

Ink_TypeTag getFilePointerType(Ink_InterpreteEngine *engine)
{
	return engine->getEngineComAs<Ink_TypeTag>(ink_native_file_mod_id)[0];
}

inline Ink_NumericValue getNumVal(Ink_Object *num)
{
	if (num->type == INK_NUMERIC) {
		return as<Ink_Numeric>(num)->value;
	}
	return 0;
}

Ink_Object *InkNative_File_Exist(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	if (!checkArgument(engine, argc, argv, 1, INK_STRING)) {
		return NULL_OBJ;
	}

	return new Ink_Numeric(engine, !access(getStringVal(engine, context, argv[0])->getValue().c_str(), 0));
}

Ink_Object *InkNative_File_Remove(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	if (!checkArgument(engine, argc, argv, 1, INK_STRING)) {
		return NULL_OBJ;
	}

	return new Ink_Numeric(engine, !remove(getStringVal(engine, context, argv[0])->getValue().c_str()));
}

Ink_Object *InkNative_File_Constructor(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	Ink_Object *ret;
	FILE *fp = NULL;
	const char *tmp;

	if (checkArgument(false, argc, argv, 2, INK_STRING, INK_STRING)) {
		fp = fopen(tmp = getStringVal(engine, context, argv[0])->getValue().c_str(),
				   getStringVal(engine, context, argv[1])->getValue().c_str());
		if (!fp) {
			InkWarn_Failed_Open_File(engine, tmp);
		}
	} else if (checkArgument(false, argc, argv, 1, INK_STRING)) {
		fp = fopen(tmp = getStringVal(engine, context, argv[0])->getValue().c_str(), "r");
		if (!fp) {
			InkWarn_Failed_Open_File(engine, tmp);
		}
	} else if (checkArgument(false, argc, argv, 1, FILE_POINTER_TYPE)) {
		fp = as<Ink_FilePointer>(argv[0])->fp;
	}

	context->getLocal()->context->setSlot("this", ret = new Ink_FilePointer(engine, fp));

	return ret;
}

Ink_Object *InkNative_File_Close(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	Ink_Object *base = context->searchSlot(engine, "base");
	FILE *tmp;

	ASSUME_BASE_TYPE(engine, FILE_POINTER_TYPE);

	tmp = as<Ink_FilePointer>(base)->fp;
	if (tmp) {
		as<Ink_FilePointer>(base)->fp = NULL;
		fclose(tmp);
	} else {
		InkWarn_IO_Uninitialized_File_Pointer(engine);
	}

	return NULL_OBJ;
}

Ink_Object *InkNative_File_PutString(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	Ink_Object *base = context->searchSlot(engine, "base");
	FILE *tmp;

	ASSUME_BASE_TYPE(engine, FILE_POINTER_TYPE);
	if (!checkArgument(engine, argc, argv, 1, INK_STRING)) {
		return NULL_OBJ;
	}

	tmp = as<Ink_FilePointer>(base)->fp;
	if (tmp) fputs(getStringVal(engine, context, argv[0])->getValue().c_str(), tmp);
	else {
		InkWarn_IO_Uninitialized_File_Pointer(engine);
	}

	return NULL_OBJ;
}

Ink_Object *InkNative_File_PutC(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	Ink_Object *base = context->searchSlot(engine, "base");
	FILE *tmp;
	char ch;

	ASSUME_BASE_TYPE(engine, FILE_POINTER_TYPE);
	if (checkArgument(false, argc, argv, 1, INK_STRING)) {
		ch = getStringVal(engine, context, argv[0])->getValue().c_str()[0];
	} else if (checkArgument(engine, argc, argv, 1, INK_NUMERIC)) {
		ch = getNumVal(argv[0]);
	} else {
		return NULL_OBJ;
	}

	tmp = as<Ink_FilePointer>(base)->fp;
	if (tmp) fputc(ch, tmp);
	else {
		InkWarn_IO_Uninitialized_File_Pointer(engine);
	}

	return NULL_OBJ;
}

Ink_Object *InkNative_File_GetString(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	Ink_Object *base = context->searchSlot(engine, "base");
	FILE *tmp;
	char buffer[FILE_GETS_BUFFER_SIZE] = { '\0' };

	ASSUME_BASE_TYPE(engine, FILE_POINTER_TYPE);

	tmp = as<Ink_FilePointer>(base)->fp;
	if (tmp) {
		return new Ink_String(engine, string(fgets(buffer, FILE_GETS_BUFFER_SIZE, tmp)));
	}

	InkWarn_IO_Uninitialized_File_Pointer(engine);

	return NULL_OBJ;
}

Ink_Object *InkNative_File_GetC(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	Ink_Object *base = context->searchSlot(engine, "base");
	FILE *tmp;

	ASSUME_BASE_TYPE(engine, FILE_POINTER_TYPE);

	tmp = as<Ink_FilePointer>(base)->fp;
	if (tmp) {
		return new Ink_Numeric(engine, fgetc(tmp));
	}

	InkWarn_IO_Uninitialized_File_Pointer(engine);

	return NULL_OBJ;
}

#if defined(INK_PLATFORM_LINUX)

Ink_Object *InkNative_File_GetCh(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	char ch;
	ttyMode mode_back = getttyMode(); // back up tty mode

	closettyBuffer();
	// close buffering
	ch = fgetc(stdin);

	// restore tty mode
	setttyMode(mode_back);

	return new Ink_Numeric(engine, ch);
}

#endif

Ink_Object *InkNative_File_ReadAll(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	Ink_Object *base = context->searchSlot(engine, "base");
	FILE *tmp;
	size_t len;
	char *buffer;
	Ink_Object *ret;

	ASSUME_BASE_TYPE(engine, FILE_POINTER_TYPE);

	tmp = as<Ink_FilePointer>(base)->fp;

	if (tmp) {
		fseek(tmp, 0L, SEEK_END);
		len = ftell(tmp);
		buffer = (char *)malloc(len + 1);

		fseek(tmp, 0L, SEEK_SET);
		fread(buffer, len, 1, tmp);
		buffer[len] = '\0';

		ret = new Ink_String(engine, string(buffer));
		free(buffer);

		return ret;
	}

	InkWarn_IO_Uninitialized_File_Pointer(engine);

	return NULL_OBJ;
}

Ink_Object *InkNative_File_Flush(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	Ink_Object *base = context->searchSlot(engine, "base");
	FILE *tmp;

	ASSUME_BASE_TYPE(engine, FILE_POINTER_TYPE);

	tmp = as<Ink_FilePointer>(base)->fp;
	if (tmp)
		fflush(tmp);
	else
		InkWarn_IO_Uninitialized_File_Pointer(engine);

	return NULL_OBJ;
}

void Ink_FilePointer::Ink_FilePointerMethodInit(Ink_InterpreteEngine *engine)
{
	setSlot("close", new Ink_FunctionObject(engine, InkNative_File_Close));
	setSlot("puts", new Ink_FunctionObject(engine, InkNative_File_PutString));
	setSlot("putc", new Ink_FunctionObject(engine, InkNative_File_PutC));
	setSlot("gets", new Ink_FunctionObject(engine, InkNative_File_GetString));
	setSlot("getc", new Ink_FunctionObject(engine, InkNative_File_GetC));
	setSlot("read", new Ink_FunctionObject(engine, InkNative_File_ReadAll));
	setSlot("flush", new Ink_FunctionObject(engine, InkNative_File_Flush));

	return;
}

void InkMod_File_bondTo(Ink_InterpreteEngine *engine, Ink_Object *bondee)
{
	bondee->setSlot("File", new Ink_FunctionObject(engine, InkNative_File_Constructor));
	bondee->setSlot("file_exist", new Ink_FunctionObject(engine, InkNative_File_Exist));
	bondee->setSlot("file_remove", new Ink_FunctionObject(engine, InkNative_File_Remove));
#if defined(INK_PLATFORM_LINUX)
	bondee->setSlot("getch", new Ink_FunctionObject(engine, InkNative_File_GetCh)); // no buffering getc
#endif

	return;
}

Ink_Object *InkMod_File_Loader(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	if (!checkArgument(engine, argc, 2)) {
		return NULL_OBJ;
	}

	Ink_Object *apply_to = argv[1];

	InkMod_File_bondTo(engine, apply_to);

	return NULL_OBJ;
}<commit_msg>040216#03: add reopen method<commit_after>#include <stdio.h>
#include <string>
#include "core/general.h"
#include "core/debug.h"
#include "core/native/native.h"
#include "core/interface/engine.h"
#include "includes/switches.h"
#include "io.h"

using namespace ink;
using namespace std;

extern InkMod_ModuleID ink_native_file_mod_id;

Ink_TypeTag getFilePointerType(Ink_InterpreteEngine *engine)
{
	return engine->getEngineComAs<Ink_TypeTag>(ink_native_file_mod_id)[0];
}

inline Ink_NumericValue getNumVal(Ink_Object *num)
{
	if (num->type == INK_NUMERIC) {
		return as<Ink_Numeric>(num)->value;
	}
	return 0;
}

Ink_Object *InkNative_File_Exist(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	if (!checkArgument(engine, argc, argv, 1, INK_STRING)) {
		return NULL_OBJ;
	}

	return new Ink_Numeric(engine, !access(getStringVal(engine, context, argv[0])->getValue().c_str(), 0));
}

Ink_Object *InkNative_File_Remove(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	if (!checkArgument(engine, argc, argv, 1, INK_STRING)) {
		return NULL_OBJ;
	}

	return new Ink_Numeric(engine, !remove(getStringVal(engine, context, argv[0])->getValue().c_str()));
}

Ink_Object *InkNative_File_Constructor(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	Ink_Object *ret;
	FILE *fp = NULL;
	const char *tmp;

	if (checkArgument(false, argc, argv, 2, INK_STRING, INK_STRING)) {
		fp = fopen(tmp = getStringVal(engine, context, argv[0])->getValue().c_str(),
				   getStringVal(engine, context, argv[1])->getValue().c_str());
		if (!fp) {
			InkWarn_Failed_Open_File(engine, tmp);
		}
	} else if (checkArgument(false, argc, argv, 1, INK_STRING)) {
		fp = fopen(tmp = getStringVal(engine, context, argv[0])->getValue().c_str(), "r");
		if (!fp) {
			InkWarn_Failed_Open_File(engine, tmp);
		}
	} else if (checkArgument(false, argc, argv, 1, FILE_POINTER_TYPE)) {
		fp = as<Ink_FilePointer>(argv[0])->fp;
	}

	context->getLocal()->context->setSlot("this", ret = new Ink_FilePointer(engine, fp));

	return ret;
}

Ink_Object *InkNative_File_Close(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	Ink_Object *base = context->searchSlot(engine, "base");
	FILE *tmp;

	ASSUME_BASE_TYPE(engine, FILE_POINTER_TYPE);

	tmp = as<Ink_FilePointer>(base)->fp;
	if (tmp) {
		as<Ink_FilePointer>(base)->fp = NULL;
		fclose(tmp);
	} else {
		InkWarn_IO_Uninitialized_File_Pointer(engine);
	}

	return NULL_OBJ;
}

Ink_Object *InkNative_File_PutString(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	Ink_Object *base = context->searchSlot(engine, "base");
	FILE *tmp;

	ASSUME_BASE_TYPE(engine, FILE_POINTER_TYPE);
	if (!checkArgument(engine, argc, argv, 1, INK_STRING)) {
		return NULL_OBJ;
	}

	tmp = as<Ink_FilePointer>(base)->fp;
	if (tmp) fputs(getStringVal(engine, context, argv[0])->getValue().c_str(), tmp);
	else {
		InkWarn_IO_Uninitialized_File_Pointer(engine);
	}

	return NULL_OBJ;
}

Ink_Object *InkNative_File_PutC(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	Ink_Object *base = context->searchSlot(engine, "base");
	FILE *tmp;
	char ch;

	ASSUME_BASE_TYPE(engine, FILE_POINTER_TYPE);
	if (checkArgument(false, argc, argv, 1, INK_STRING)) {
		ch = getStringVal(engine, context, argv[0])->getValue().c_str()[0];
	} else if (checkArgument(engine, argc, argv, 1, INK_NUMERIC)) {
		ch = getNumVal(argv[0]);
	} else {
		return NULL_OBJ;
	}

	tmp = as<Ink_FilePointer>(base)->fp;
	if (tmp) fputc(ch, tmp);
	else {
		InkWarn_IO_Uninitialized_File_Pointer(engine);
	}

	return NULL_OBJ;
}

Ink_Object *InkNative_File_GetString(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	Ink_Object *base = context->searchSlot(engine, "base");
	FILE *tmp;
	char buffer[FILE_GETS_BUFFER_SIZE] = { '\0' };

	ASSUME_BASE_TYPE(engine, FILE_POINTER_TYPE);

	tmp = as<Ink_FilePointer>(base)->fp;
	if (tmp) {
		return new Ink_String(engine, string(fgets(buffer, FILE_GETS_BUFFER_SIZE, tmp)));
	}

	InkWarn_IO_Uninitialized_File_Pointer(engine);

	return NULL_OBJ;
}

Ink_Object *InkNative_File_GetC(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	Ink_Object *base = context->searchSlot(engine, "base");
	FILE *tmp;

	ASSUME_BASE_TYPE(engine, FILE_POINTER_TYPE);

	tmp = as<Ink_FilePointer>(base)->fp;
	if (tmp) {
		return new Ink_Numeric(engine, fgetc(tmp));
	}

	InkWarn_IO_Uninitialized_File_Pointer(engine);

	return NULL_OBJ;
}

#if defined(INK_PLATFORM_LINUX)

Ink_Object *InkNative_File_GetCh(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	char ch;
	ttyMode mode_back = getttyMode(); // back up tty mode

	closettyBuffer();
	// close buffering
	ch = fgetc(stdin);

	// restore tty mode
	setttyMode(mode_back);

	return new Ink_Numeric(engine, ch);
}

#endif

Ink_Object *InkNative_File_ReadAll(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	Ink_Object *base = context->searchSlot(engine, "base");
	FILE *tmp;
	size_t len;
	char *buffer;
	Ink_Object *ret;

	ASSUME_BASE_TYPE(engine, FILE_POINTER_TYPE);

	tmp = as<Ink_FilePointer>(base)->fp;

	if (tmp) {
		fseek(tmp, 0L, SEEK_END);
		len = ftell(tmp);
		buffer = (char *)malloc(len + 1);

		fseek(tmp, 0L, SEEK_SET);
		fread(buffer, len, 1, tmp);
		buffer[len] = '\0';

		ret = new Ink_String(engine, string(buffer));
		free(buffer);

		return ret;
	}

	InkWarn_IO_Uninitialized_File_Pointer(engine);

	return NULL_OBJ;
}

Ink_Object *InkNative_File_Flush(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	Ink_Object *base = context->searchSlot(engine, "base");
	FILE *tmp;

	ASSUME_BASE_TYPE(engine, FILE_POINTER_TYPE);

	tmp = as<Ink_FilePointer>(base)->fp;
	if (tmp)
		fflush(tmp);
	else
		InkWarn_IO_Uninitialized_File_Pointer(engine);

	return NULL_OBJ;
}

Ink_Object *InkNative_File_Reopen(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	Ink_Object *base = context->searchSlot(engine, "base");
	FILE *tmp = NULL;

	if (!checkArgument(engine, argc, argv, 2, INK_STRING)) {
		return NULL_OBJ;
	}

	ASSUME_BASE_TYPE(engine, FILE_POINTER_TYPE);

	tmp = as<Ink_FilePointer>(base)->fp;
	if (tmp) {
		tmp = freopen(as<Ink_String>(argv[0])->getValue().c_str(),
					  as<Ink_String>(argv[1])->getValue().c_str(), tmp);
	} else
		InkWarn_IO_Uninitialized_File_Pointer(engine);

	return new Ink_Numeric(engine, tmp != NULL);
}

void Ink_FilePointer::Ink_FilePointerMethodInit(Ink_InterpreteEngine *engine)
{
	setSlot("close", new Ink_FunctionObject(engine, InkNative_File_Close));
	setSlot("puts", new Ink_FunctionObject(engine, InkNative_File_PutString));
	setSlot("putc", new Ink_FunctionObject(engine, InkNative_File_PutC));
	setSlot("gets", new Ink_FunctionObject(engine, InkNative_File_GetString));
	setSlot("getc", new Ink_FunctionObject(engine, InkNative_File_GetC));
	setSlot("read", new Ink_FunctionObject(engine, InkNative_File_ReadAll));
	setSlot("flush", new Ink_FunctionObject(engine, InkNative_File_Flush));
	setSlot("reopen", new Ink_FunctionObject(engine, InkNative_File_Reopen));

	return;
}

void InkMod_File_bondTo(Ink_InterpreteEngine *engine, Ink_Object *bondee)
{
	bondee->setSlot("File", new Ink_FunctionObject(engine, InkNative_File_Constructor));
	bondee->setSlot("file_exist", new Ink_FunctionObject(engine, InkNative_File_Exist));
	bondee->setSlot("file_remove", new Ink_FunctionObject(engine, InkNative_File_Remove));
#if defined(INK_PLATFORM_LINUX)
	bondee->setSlot("getch", new Ink_FunctionObject(engine, InkNative_File_GetCh)); // no buffering getc
#endif

	return;
}

Ink_Object *InkMod_File_Loader(Ink_InterpreteEngine *engine, Ink_ContextChain *context, Ink_ArgcType argc, Ink_Object **argv, Ink_Object *this_p)
{
	if (!checkArgument(engine, argc, 2)) {
		return NULL_OBJ;
	}

	Ink_Object *apply_to = argv[1];

	InkMod_File_bondTo(engine, apply_to);

	return NULL_OBJ;
}<|endoftext|>


<commit_before>//This is a dual-purpose class for gene pools - it serves as a "base"
//GA, and also as a gene pool for individuals in hierarchical GAs
//Since these functions are, by and large, very similar, they can be
//combined together into one class

#include "HierarchicalGenePool.h"
#include <sstream>
#include <iostream>

using namespace std;

//If we don't know the optimum
HierarchicalGenePool::HierarchicalGenePool(int newPopulationSize, Individual * templateIndividual, int myMaxGenerations, int numIterations, SelectionStrategy * newStrategy) : GenePool() {
	init(newPopulationSize, templateIndividual, myMaxGenerations, numIterations, newStrategy);
}

//Unknown optimum, overridden seed
HierarchicalGenePool::HierarchicalGenePool(int newPopulationSize, Individual * templateIndividual, int myMaxGenerations, int numIterations, int newSeed, SelectionStrategy * newStrategy) : GenePool(newSeed) {
	init(newPopulationSize, templateIndividual, myMaxGenerations, numIterations, newStrategy);
}

//If we do know the optimum
HierarchicalGenePool::HierarchicalGenePool(int newPopulationSize, Individual * templateIndividual, int myMaxGenerations, int numIterations, SelectionStrategy * newStrategy, int optimalGenome[]) : GenePool() {
	init(newPopulationSize, templateIndividual, myMaxGenerations, numIterations, newStrategy);

        knownOptimum = true;

	optimumGenome = optimalGenome;

	Individual * optimumIndividual = templateIndividual->makeSpecifiedCopy(optimalGenome);

	optimumFitness = optimumIndividual->checkFitness();

	delete(optimumIndividual);
}

//Known optimum, known seed
HierarchicalGenePool::HierarchicalGenePool(int newPopulationSize, Individual * templateIndividual, int myMaxGenerations, int numIterations, int newSeed, SelectionStrategy * newStrategy, int optimalGenome[]) : GenePool(newSeed) {
	init(newPopulationSize, templateIndividual, myMaxGenerations, numIterations, newStrategy);

	knownOptimum = true;

        optimumGenome = optimalGenome;

        Individual * optimumIndividual = templateIndividual->makeSpecifiedCopy(optimalGenome);

        optimumFitness = optimumIndividual->checkFitness();

	delete(optimumIndividual);
}

HierarchicalGenePool::~HierarchicalGenePool() {
	for (int i = 0; i < populationSize; i++) {
		delete(myPopulation[i]);
	}

	free(myPopulation);
	free(populationFitnesses);

	if (optimumGenome != NULL) {
		free(optimumGenome);
	}
}

void HierarchicalGenePool::init(int newPopulationSize, Individual * templateIndividual, int myMaxGenerations, int numIterations, SelectionStrategy * newStrategy) {
	myPopulation = (Individual**)malloc(sizeof(Individual*)*newPopulationSize);

	populationFitnesses = (int*)malloc(sizeof(int)*newPopulationSize);

	populationSize = newPopulationSize;
        currentGeneration = 0;
	readOnce = false;

	optimumGenome = NULL;

	maxGenerations = myMaxGenerations;
	numIterationsPerGeneration = numIterations;
	myStrategy = newStrategy;

        for (int i = 0; i < populationSize; i++) {
                myPopulation[i] = templateIndividual->makeRandomCopy();
        }

        optimumFound = false;
        knownOptimum = false;

        evaluateFitnesses();
}

//Evaluates the fitnesses of the population of this particular GenePool
//Basically a convenience thing
void HierarchicalGenePool::evaluateFitnesses() {
	for (int i = 0; i < populationSize; i++) {
		populationFitnesses[i] = myPopulation[i]->checkFitness();
	}
}

//Evaluates the fitnesses of a given population of individuals
//Doesn't care what their genetic makeup is - uses their fitness functions
int * HierarchicalGenePool::evaluateFitnesses(Individual ** populationToEval, int populationToEvalSize) {
	int * populationToEvalFitnesses = (int*)malloc(sizeof(int)*populationToEvalSize);

	for (int i = 0; i < populationToEvalSize; i++) {
		populationToEvalFitnesses[i] = populationToEval[i]->checkFitness();
	}

	return populationToEvalFitnesses;
}

//When we need a specific individual
void * HierarchicalGenePool::getIndex(int index) {
	void * returnValue;

	returnValue = (void*)myPopulation[index];

	return returnValue;
}

void * HierarchicalGenePool::getFittest() {
	return getIndex(0);
}

//Run one generation
void HierarchicalGenePool::nextGeneration() {
	Individual ** newPopulation;

	if (currentGeneration < maxGenerations && optimumFound == false) {
		//Run the hierarchical component first - we're evolving
		//from the bottom up
		myPopulation[0]->runHierarchicalGenerations();

		//Re-evaluate the fitnesses to take the lower GenePools
		//running their generations into account
		evaluateFitnesses();

		newPopulation = myStrategy->breedMutateSelect(myPopulation, populationFitnesses, populationSize);

                currentGeneration += 1;

		if (knownOptimum == true) {
                       	for (int i = 0; i < populationSize && optimumFound == false; i++) {
                               	//TODO: make this more approximate
                               	if (populationFitnesses[i] == optimumFitness) {
                                       	optimumFound = true;
                               	}
                       	}
		}

		//The new generation replaces the old
		for (int i = 0; i < populationSize; i++) {
			myPopulation[i] = newPopulation[i]->deepCopy();
			delete(newPopulation[i]);
		}

		free(newPopulation);
	}
}

//For HGAs - if we want to run multiple generations of a lower-level gene pool
//for every one of a higher-level one, this is how
//Basically a loop wrapped around nextGeneration()
void HierarchicalGenePool::runGenerations() {
	int target = currentGeneration + numIterationsPerGeneration;

	for (int i = currentGeneration; i < target && i < maxGenerations && optimumFound == false; i++) {
		nextGeneration();
	}
}

void HierarchicalGenePool::sortPopulation() {
	//TODO: Make more efficient
	Individual * tempIndividual;
	int temp;

	for (int i = 0; i < populationSize; i++) {
		for (int k = 0; k < populationSize; k++) {
			if (populationFitnesses[i] > populationFitnesses[k]) {
				tempIndividual = myPopulation[i];
				temp = populationFitnesses[i];

				myPopulation[i] = myPopulation[k];
				populationFitnesses[i] = populationFitnesses[k];

				myPopulation[k] = tempIndividual;
				populationFitnesses[k] = temp;
			}
		}
	}
}

int HierarchicalGenePool::getHighestFitness() {
	return populationFitnesses[0];
}

string HierarchicalGenePool::toString() {
	string returnString = "";
	stringstream ss;
	string populationString;

	ss << "Population size: " << populationSize << "\n";

	for (int i = 0; i < populationSize; i++) {
		if (readOnce == false) {
			populationString = myPopulation[i]->toString();
		} else {
			populationString = myPopulation[i]->toGenomeString();
		}

		ss << "Member " << i << ": " << populationString << "Fitness: " << populationFitnesses[i] << "\n";
	}

	if (readOnce == false) {
        	ss << "Seed: " << seed << "\n";
	        ss << "Selection Strategy Info:\n" << myStrategy->toString();
	}

	readOnce = true;

	returnString = ss.str();

	return returnString;
}
<commit_msg>[HierarchicalGenePool]: Fixed typo in toString()<commit_after>//This is a dual-purpose class for gene pools - it serves as a "base"
//GA, and also as a gene pool for individuals in hierarchical GAs
//Since these functions are, by and large, very similar, they can be
//combined together into one class

#include "HierarchicalGenePool.h"
#include <sstream>
#include <iostream>

using namespace std;

//If we don't know the optimum
HierarchicalGenePool::HierarchicalGenePool(int newPopulationSize, Individual * templateIndividual, int myMaxGenerations, int numIterations, SelectionStrategy * newStrategy) : GenePool() {
	init(newPopulationSize, templateIndividual, myMaxGenerations, numIterations, newStrategy);
}

//Unknown optimum, overridden seed
HierarchicalGenePool::HierarchicalGenePool(int newPopulationSize, Individual * templateIndividual, int myMaxGenerations, int numIterations, int newSeed, SelectionStrategy * newStrategy) : GenePool(newSeed) {
	init(newPopulationSize, templateIndividual, myMaxGenerations, numIterations, newStrategy);
}

//If we do know the optimum
HierarchicalGenePool::HierarchicalGenePool(int newPopulationSize, Individual * templateIndividual, int myMaxGenerations, int numIterations, SelectionStrategy * newStrategy, int optimalGenome[]) : GenePool() {
	init(newPopulationSize, templateIndividual, myMaxGenerations, numIterations, newStrategy);

        knownOptimum = true;

	optimumGenome = optimalGenome;

	Individual * optimumIndividual = templateIndividual->makeSpecifiedCopy(optimalGenome);

	optimumFitness = optimumIndividual->checkFitness();

	delete(optimumIndividual);
}

//Known optimum, known seed
HierarchicalGenePool::HierarchicalGenePool(int newPopulationSize, Individual * templateIndividual, int myMaxGenerations, int numIterations, int newSeed, SelectionStrategy * newStrategy, int optimalGenome[]) : GenePool(newSeed) {
	init(newPopulationSize, templateIndividual, myMaxGenerations, numIterations, newStrategy);

	knownOptimum = true;

        optimumGenome = optimalGenome;

        Individual * optimumIndividual = templateIndividual->makeSpecifiedCopy(optimalGenome);

        optimumFitness = optimumIndividual->checkFitness();

	delete(optimumIndividual);
}

HierarchicalGenePool::~HierarchicalGenePool() {
	for (int i = 0; i < populationSize; i++) {
		delete(myPopulation[i]);
	}

	free(myPopulation);
	free(populationFitnesses);

	if (optimumGenome != NULL) {
		free(optimumGenome);
	}
}

void HierarchicalGenePool::init(int newPopulationSize, Individual * templateIndividual, int myMaxGenerations, int numIterations, SelectionStrategy * newStrategy) {
	myPopulation = (Individual**)malloc(sizeof(Individual*)*newPopulationSize);

	populationFitnesses = (int*)malloc(sizeof(int)*newPopulationSize);

	populationSize = newPopulationSize;
        currentGeneration = 0;
	readOnce = false;

	optimumGenome = NULL;

	maxGenerations = myMaxGenerations;
	numIterationsPerGeneration = numIterations;
	myStrategy = newStrategy;

        for (int i = 0; i < populationSize; i++) {
                myPopulation[i] = templateIndividual->makeRandomCopy();
        }

        optimumFound = false;
        knownOptimum = false;

        evaluateFitnesses();
}

//Evaluates the fitnesses of the population of this particular GenePool
//Basically a convenience thing
void HierarchicalGenePool::evaluateFitnesses() {
	for (int i = 0; i < populationSize; i++) {
		populationFitnesses[i] = myPopulation[i]->checkFitness();
	}
}

//Evaluates the fitnesses of a given population of individuals
//Doesn't care what their genetic makeup is - uses their fitness functions
int * HierarchicalGenePool::evaluateFitnesses(Individual ** populationToEval, int populationToEvalSize) {
	int * populationToEvalFitnesses = (int*)malloc(sizeof(int)*populationToEvalSize);

	for (int i = 0; i < populationToEvalSize; i++) {
		populationToEvalFitnesses[i] = populationToEval[i]->checkFitness();
	}

	return populationToEvalFitnesses;
}

//When we need a specific individual
void * HierarchicalGenePool::getIndex(int index) {
	void * returnValue;

	returnValue = (void*)myPopulation[index];

	return returnValue;
}

void * HierarchicalGenePool::getFittest() {
	return getIndex(0);
}

//Run one generation
void HierarchicalGenePool::nextGeneration() {
	Individual ** newPopulation;

	if (currentGeneration < maxGenerations && optimumFound == false) {
		//Run the hierarchical component first - we're evolving
		//from the bottom up
		myPopulation[0]->runHierarchicalGenerations();

		//Re-evaluate the fitnesses to take the lower GenePools
		//running their generations into account
		evaluateFitnesses();

		newPopulation = myStrategy->breedMutateSelect(myPopulation, populationFitnesses, populationSize);

                currentGeneration += 1;

		if (knownOptimum == true) {
                       	for (int i = 0; i < populationSize && optimumFound == false; i++) {
                               	//TODO: make this more approximate
                               	if (populationFitnesses[i] == optimumFitness) {
                                       	optimumFound = true;
                               	}
                       	}
		}

		//The new generation replaces the old
		for (int i = 0; i < populationSize; i++) {
			myPopulation[i] = newPopulation[i]->deepCopy();
			delete(newPopulation[i]);
		}

		free(newPopulation);
	}
}

//For HGAs - if we want to run multiple generations of a lower-level gene pool
//for every one of a higher-level one, this is how
//Basically a loop wrapped around nextGeneration()
void HierarchicalGenePool::runGenerations() {
	int target = currentGeneration + numIterationsPerGeneration;

	for (int i = currentGeneration; i < target && i < maxGenerations && optimumFound == false; i++) {
		nextGeneration();
	}
}

void HierarchicalGenePool::sortPopulation() {
	//TODO: Make more efficient
	Individual * tempIndividual;
	int temp;

	for (int i = 0; i < populationSize; i++) {
		for (int k = 0; k < populationSize; k++) {
			if (populationFitnesses[i] > populationFitnesses[k]) {
				tempIndividual = myPopulation[i];
				temp = populationFitnesses[i];

				myPopulation[i] = myPopulation[k];
				populationFitnesses[i] = populationFitnesses[k];

				myPopulation[k] = tempIndividual;
				populationFitnesses[k] = temp;
			}
		}
	}
}

int HierarchicalGenePool::getHighestFitness() {
	return populationFitnesses[0];
}

string HierarchicalGenePool::toString() {
	string returnString = "";
	stringstream ss;
	string populationString;

	ss << "Population size: " << populationSize << "\n";

	for (int i = 0; i < populationSize; i++) {
		if (readOnce == false) {
			populationString = myPopulation[i]->toString();
		} else {
			populationString = myPopulation[i]->toGenomeString();
		}

		ss << "Member " << i << ": " << populationString << " Fitness: " << populationFitnesses[i] << "\n";
	}

	if (readOnce == false) {
        	ss << "Seed: " << seed << "\n";
	        ss << "Selection Strategy Info:\n" << myStrategy->toString();
	}

	readOnce = true;

	returnString = ss.str();

	return returnString;
}
<|endoftext|>


<commit_before>/**
 * @file
 * @brief Implementation of configuration
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "Configuration.hpp"

#include <cassert>
#include <ostream>
#include <stdexcept>
#include <string>

#include "core/utils/file.h"
#include "exceptions.h"

using namespace allpix;

Configuration::Configuration(std::string name, std::string path) : name_(std::move(name)), path_(std::move(path)) {}

bool Configuration::has(const std::string& key) const {
    return config_.find(key) != config_.cend();
}

std::string Configuration::getName() const {
    return name_;
}
void Configuration::setName(const std::string& name) {
    name_ = name;
}
std::string Configuration::getFilePath() const {
    return path_;
}

std::string Configuration::getText(const std::string& key) const {
    try {
        // NOTE: returning literally including ""
        return config_.at(key);
    } catch(std::out_of_range& e) {
        throw MissingKeyError(key, getName());
    }
}
std::string Configuration::getText(const std::string& key, const std::string& def) const {
    if(!has(key)) {
        return def;
    }
    return getText(key);
}

/**
 * @throws InvalidValueError If the path did not exists while the check_exists parameter is given
 *
 * For a relative path the absolute path of the configuration file is preprended. Absolute paths are not changed.
 */
// TODO [doc] Document canonicalizing behaviour
std::string Configuration::getPath(const std::string& key, bool check_exists) const {
    try {
        return path_to_absolute(get<std::string>(key), check_exists);
    } catch(std::invalid_argument& e) {
        throw InvalidValueError(*this, key, e.what());
    }
}
/**
 * @throws InvalidValueError If the path did not exists while the check_exists parameter is given
 *
 * For all relative paths the absolute path of the configuration file is preprended. Absolute paths are not changed.
 */
// TODO [doc] Document canonicalizing behaviour
std::vector<std::string> Configuration::getPathArray(const std::string& key, bool check_exists) const {
    std::vector<std::string> path_array = getArray<std::string>(key);

    // Convert all paths to absolute
    try {
        for(auto& path : path_array) {
            path = path_to_absolute(path, check_exists);
        }
        return path_array;
    } catch(std::invalid_argument& e) {
        throw InvalidValueError(*this, key, e.what());
    }
}
/**
 * @throws std::invalid_argument If the path does not exists
 */
std::string Configuration::path_to_absolute(std::string path, bool canonicalize_path) const {
    // If not a absolute path, make it an absolute path
    if(path[0] != '/') {
        // Get base directory of config file
        std::string directory = path_.substr(0, path_.find_last_of('/'));

        // Set new path
        path = directory + "/" + path;

        // Normalize path only if we have to check if it exists
        // NOTE: This throws an error if the path does not exist
        if(canonicalize_path) {
            path = allpix::get_absolute_path(path);
        }
    }
    return path;
}

void Configuration::setText(const std::string& key, const std::string& val) {
    config_[key] = val;
}

/**
 *  The alias is only used if new key does not exist but old key does
 */
void Configuration::setAlias(const std::string& new_key, const std::string& old_key) {
    if(!has(old_key) || has(new_key)) {
        return;
    }
    try {
        config_[new_key] = config_.at(old_key);
    } catch(std::out_of_range& e) {
        throw MissingKeyError(old_key, getName());
    }
}

unsigned int Configuration::countSettings() const {
    return static_cast<unsigned int>(config_.size());
}

/**
 * All keys that are already defined earlier in this configuration are not changed.
 */
void Configuration::merge(const Configuration& other) {
    for(auto config_pair : other.config_) {
        // Only merge values that do not yet exist
        if(!has(config_pair.first)) {
            setText(config_pair.first, config_pair.second);
        }
    }
}

std::vector<std::pair<std::string, std::string>> Configuration::getAll() {
    std::vector<std::pair<std::string, std::string>> result;

    // Loop over all configuration keys
    for(auto& key_value : config_) {
        // Skip internal keys starting with an underscore
        if(!key_value.first.empty() && key_value.first[0] == '_') {
            continue;
        }

        result.emplace_back(key_value);
    }

    return result;
}

/**
 * String is recursively parsed for all pair of [ and ] brackets. All parts between single or double quotation marks are
 * skipped.
 */
std::unique_ptr<Configuration::parse_node> Configuration::parse_string(std::string str, int depth) {
    using parse_node = Configuration::parse_node;

    auto node = std::make_unique<parse_node>();
    str = allpix::trim(str);
    if(str.empty()) {
        throw std::invalid_argument("element is empty");
    }

    // Initialize variables for non-zero levels
    size_t beg = 1, lst = 1;
    int in_dpt = 0;
    bool in_dpt_chg = false;

    // Implicitly add pair of brackets on zero level
    if(depth == 0) {
        beg = lst = 0;
        in_dpt = 1;
    }

    for(size_t i = 0; i < str.size(); ++i) {
        // Skip over quotation marks
        if(str[i] == '\'' || str[i] == '\"') {
            i = str.find(str[i], i + 1);
            if(i == std::string::npos) {
                throw std::invalid_argument("quotes are not balanced");
            }
            continue;
        }

        // Handle brackets
        if(str[i] == '[') {
            ++in_dpt;
            if(!in_dpt_chg && i != 0) {
                throw std::invalid_argument("invalid start bracket");
            }
            in_dpt_chg = true;
        } else if(str[i] == ']') {
            if(in_dpt == 0) {
                throw std::invalid_argument("brackets are not matched");
            }
            --in_dpt;
            in_dpt_chg = true;
        }

        // Make subitems at the zero level
        if(in_dpt == 1 && (str[i] == ',' || (isspace(str[i]) && (!isspace(str[i - 1]) && str[i - 1] != ',')))) {
            node->children.push_back(parse_string(str.substr(lst, i - lst), depth + 1));
            lst = i + 1;
        }
    }

    if((depth > 0 && in_dpt != 0) || (depth == 0 && in_dpt != 1)) {
        throw std::invalid_argument("brackets are not balanced");
    }

    // Determine if array or value
    if(in_dpt_chg || depth == 0) {
        // Handle last array item
        size_t end = str.size();
        if(depth != 0) {
            if(str.back() != ']') {
                throw std::invalid_argument("invalid end bracket");
            }
            end = str.size() - 1;
        }
        node->children.push_back(parse_string(str.substr(lst, end - lst), depth + 1));
        node->value = str.substr(beg, end - beg);
    } else {
        // Not an array, handle as value instead
        node->value = str;
    }

    // Handle zero level where brackets where explicitly added
    if(depth == 0 && node->children.size() == 1 && !node->children.front()->children.empty()) {
        node = std::move(node->children.front());
    }

    return node;
}
<commit_msg>use front instead of index zero for strings<commit_after>/**
 * @file
 * @brief Implementation of configuration
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "Configuration.hpp"

#include <cassert>
#include <ostream>
#include <stdexcept>
#include <string>

#include "core/utils/file.h"
#include "exceptions.h"

using namespace allpix;

Configuration::Configuration(std::string name, std::string path) : name_(std::move(name)), path_(std::move(path)) {}

bool Configuration::has(const std::string& key) const {
    return config_.find(key) != config_.cend();
}

std::string Configuration::getName() const {
    return name_;
}
void Configuration::setName(const std::string& name) {
    name_ = name;
}
std::string Configuration::getFilePath() const {
    return path_;
}

std::string Configuration::getText(const std::string& key) const {
    try {
        // NOTE: returning literally including ""
        return config_.at(key);
    } catch(std::out_of_range& e) {
        throw MissingKeyError(key, getName());
    }
}
std::string Configuration::getText(const std::string& key, const std::string& def) const {
    if(!has(key)) {
        return def;
    }
    return getText(key);
}

/**
 * @throws InvalidValueError If the path did not exists while the check_exists parameter is given
 *
 * For a relative path the absolute path of the configuration file is preprended. Absolute paths are not changed.
 */
// TODO [doc] Document canonicalizing behaviour
std::string Configuration::getPath(const std::string& key, bool check_exists) const {
    try {
        return path_to_absolute(get<std::string>(key), check_exists);
    } catch(std::invalid_argument& e) {
        throw InvalidValueError(*this, key, e.what());
    }
}
/**
 * @throws InvalidValueError If the path did not exists while the check_exists parameter is given
 *
 * For all relative paths the absolute path of the configuration file is preprended. Absolute paths are not changed.
 */
// TODO [doc] Document canonicalizing behaviour
std::vector<std::string> Configuration::getPathArray(const std::string& key, bool check_exists) const {
    std::vector<std::string> path_array = getArray<std::string>(key);

    // Convert all paths to absolute
    try {
        for(auto& path : path_array) {
            path = path_to_absolute(path, check_exists);
        }
        return path_array;
    } catch(std::invalid_argument& e) {
        throw InvalidValueError(*this, key, e.what());
    }
}
/**
 * @throws std::invalid_argument If the path does not exists
 */
std::string Configuration::path_to_absolute(std::string path, bool canonicalize_path) const {
    // If not a absolute path, make it an absolute path
    if(path.front() != '/') {
        // Get base directory of config file
        std::string directory = path_.substr(0, path_.find_last_of('/'));

        // Set new path
        path = directory + "/" + path;

        // Normalize path only if we have to check if it exists
        // NOTE: This throws an error if the path does not exist
        if(canonicalize_path) {
            path = allpix::get_absolute_path(path);
        }
    }
    return path;
}

void Configuration::setText(const std::string& key, const std::string& val) {
    config_[key] = val;
}

/**
 *  The alias is only used if new key does not exist but old key does
 */
void Configuration::setAlias(const std::string& new_key, const std::string& old_key) {
    if(!has(old_key) || has(new_key)) {
        return;
    }
    try {
        config_[new_key] = config_.at(old_key);
    } catch(std::out_of_range& e) {
        throw MissingKeyError(old_key, getName());
    }
}

unsigned int Configuration::countSettings() const {
    return static_cast<unsigned int>(config_.size());
}

/**
 * All keys that are already defined earlier in this configuration are not changed.
 */
void Configuration::merge(const Configuration& other) {
    for(auto config_pair : other.config_) {
        // Only merge values that do not yet exist
        if(!has(config_pair.first)) {
            setText(config_pair.first, config_pair.second);
        }
    }
}

std::vector<std::pair<std::string, std::string>> Configuration::getAll() {
    std::vector<std::pair<std::string, std::string>> result;

    // Loop over all configuration keys
    for(auto& key_value : config_) {
        // Skip internal keys starting with an underscore
        if(!key_value.first.empty() && key_value.first.front() == '_') {
            continue;
        }

        result.emplace_back(key_value);
    }

    return result;
}

/**
 * String is recursively parsed for all pair of [ and ] brackets. All parts between single or double quotation marks are
 * skipped.
 */
std::unique_ptr<Configuration::parse_node> Configuration::parse_string(std::string str, int depth) {
    using parse_node = Configuration::parse_node;

    auto node = std::make_unique<parse_node>();
    str = allpix::trim(str);
    if(str.empty()) {
        throw std::invalid_argument("element is empty");
    }

    // Initialize variables for non-zero levels
    size_t beg = 1, lst = 1;
    int in_dpt = 0;
    bool in_dpt_chg = false;

    // Implicitly add pair of brackets on zero level
    if(depth == 0) {
        beg = lst = 0;
        in_dpt = 1;
    }

    for(size_t i = 0; i < str.size(); ++i) {
        // Skip over quotation marks
        if(str[i] == '\'' || str[i] == '\"') {
            i = str.find(str[i], i + 1);
            if(i == std::string::npos) {
                throw std::invalid_argument("quotes are not balanced");
            }
            continue;
        }

        // Handle brackets
        if(str[i] == '[') {
            ++in_dpt;
            if(!in_dpt_chg && i != 0) {
                throw std::invalid_argument("invalid start bracket");
            }
            in_dpt_chg = true;
        } else if(str[i] == ']') {
            if(in_dpt == 0) {
                throw std::invalid_argument("brackets are not matched");
            }
            --in_dpt;
            in_dpt_chg = true;
        }

        // Make subitems at the zero level
        if(in_dpt == 1 && (str[i] == ',' || (isspace(str[i]) && (!isspace(str[i - 1]) && str[i - 1] != ',')))) {
            node->children.push_back(parse_string(str.substr(lst, i - lst), depth + 1));
            lst = i + 1;
        }
    }

    if((depth > 0 && in_dpt != 0) || (depth == 0 && in_dpt != 1)) {
        throw std::invalid_argument("brackets are not balanced");
    }

    // Determine if array or value
    if(in_dpt_chg || depth == 0) {
        // Handle last array item
        size_t end = str.size();
        if(depth != 0) {
            if(str.back() != ']') {
                throw std::invalid_argument("invalid end bracket");
            }
            end = str.size() - 1;
        }
        node->children.push_back(parse_string(str.substr(lst, end - lst), depth + 1));
        node->value = str.substr(beg, end - beg);
    } else {
        // Not an array, handle as value instead
        node->value = str;
    }

    // Handle zero level where brackets where explicitly added
    if(depth == 0 && node->children.size() == 1 && !node->children.front()->children.empty()) {
        node = std::move(node->children.front());
    }

    return node;
}
<|endoftext|>


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

/* Windows implementation for gpr threads. */

#include <grpc/support/port_platform.h>

#ifdef GPR_WINDOWS

#include "src/core/lib/gprpp/thd.h"

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/thd_id.h>
#include <string.h>

#include "src/core/lib/gprpp/memory.h"

#if defined(_MSC_VER)
#define thread_local __declspec(thread)
#define WIN_LAMBDA
#elif defined(__GNUC__)
#define thread_local __thread
#define WIN_LAMBDA WINAPI
#else
#error "Unknown compiler - please file a bug report"
#endif

namespace {
class ThreadInternalsWindows;
struct thd_info {
  ThreadInternalsWindows* thread;
  void (*body)(void* arg); /* body of a thread */
  void* arg;               /* argument to a thread */
  HANDLE join_event;       /* the join event */
  bool joinable;           /* whether it is joinable */
};

thread_local struct thd_info* g_thd_info;

}  // namespace

namespace grpc_core {
namespace {

class ThreadInternalsWindows : public internal::ThreadInternalsInterface {
 public:
  ThreadInternalsWindows(void (*thd_body)(void* arg), void* arg, bool* success,
                         const Thread::Options& options)
      : started_(false) {
    gpr_mu_init(&mu_);
    gpr_cv_init(&ready_);

    HANDLE handle;
    info_ = (struct thd_info*)gpr_malloc(sizeof(*info_));
    info_->thread = this;
    info_->body = thd_body;
    info_->arg = arg;
    info_->join_event = nullptr;
    info_->joinable = options.joinable();
    if (info_->joinable) {
      info_->join_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
      if (info_->join_event == nullptr) {
        gpr_free(info_);
        *success = false;
        return;
      }
    }
    handle = CreateThread(nullptr, 64 * 1024,
                          [](void* v) WIN_LAMBDA -> DWORD {
                            g_thd_info = static_cast<thd_info*>(v);
                            gpr_mu_lock(&g_thd_info->thread->mu_);
                            while (!g_thd_info->thread->started_) {
                              gpr_cv_wait(&g_thd_info->thread->ready_,
                                          &g_thd_info->thread->mu_,
                                          gpr_inf_future(GPR_CLOCK_MONOTONIC));
                            }
                            gpr_mu_unlock(&g_thd_info->thread->mu_);
                            if (!g_thd_info->joinable) {
                              Delete(g_thd_info->thread);
                              g_thd_info->thread = nullptr;
                            }
                            g_thd_info->body(g_thd_info->arg);
                            if (g_thd_info->joinable) {
                              BOOL ret = SetEvent(g_thd_info->join_event);
                              GPR_ASSERT(ret);
                            } else {
                              gpr_free(g_thd_info);
                            }
                            return 0;
                          },
                          info_, 0, nullptr);
    if (handle == nullptr) {
      destroy_thread();
      *success = false;
    } else {
      CloseHandle(handle);
      *success = true;
    }
  }

  ~ThreadInternalsWindows() override {
    gpr_mu_destroy(&mu_);
    gpr_cv_destroy(&ready_);
  }

  void Start() override {
    gpr_mu_lock(&mu_);
    started_ = true;
    gpr_cv_signal(&ready_);
    gpr_mu_unlock(&mu_);
  }

  void Join() override {
    DWORD ret = WaitForSingleObject(info_->join_event, INFINITE);
    GPR_ASSERT(ret == WAIT_OBJECT_0);
    destroy_thread();
  }

 private:
  void destroy_thread() {
    if (info_ != nullptr && info_->joinable) {
      CloseHandle(info_->join_event);
    }
    gpr_free(info_);
  }

  gpr_mu mu_;
  gpr_cv ready_;
  bool started_;
  thd_info* info_;
};

}  // namespace

Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
               bool* success, const Options& options)
    : options_(options) {
  bool outcome = false;
  impl_ = New<ThreadInternalsWindows>(thd_body, arg, &outcome, options);
  if (outcome) {
    state_ = ALIVE;
  } else {
    state_ = FAILED;
    Delete(impl_);
    impl_ = nullptr;
  }

  if (success != nullptr) {
    *success = outcome;
  }
}

}  // namespace grpc_core

gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; }

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

/* Windows implementation for gpr threads. */

#include <grpc/support/port_platform.h>

#ifdef GPR_WINDOWS

#include "src/core/lib/gprpp/thd.h"

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/thd_id.h>
#include <string.h>

#include "src/core/lib/gprpp/memory.h"

#if defined(_MSC_VER)
#define thread_local __declspec(thread)
#define WIN_LAMBDA
#elif defined(__GNUC__)
#define thread_local __thread
#define WIN_LAMBDA WINAPI
#else
#error "Unknown compiler - please file a bug report"
#endif

namespace {
class ThreadInternalsWindows;
struct thd_info {
  ThreadInternalsWindows* thread;
  void (*body)(void* arg); /* body of a thread */
  void* arg;               /* argument to a thread */
  HANDLE join_event;       /* the join event */
  bool joinable;           /* whether it is joinable */
};

thread_local struct thd_info* g_thd_info;

class ThreadInternalsWindows
    : public grpc_core::internal::ThreadInternalsInterface {
 public:
  ThreadInternalsWindows(void (*thd_body)(void* arg), void* arg, bool* success,
                         const grpc_core::Thread::Options& options)
      : started_(false) {
    gpr_mu_init(&mu_);
    gpr_cv_init(&ready_);

    HANDLE handle;
    info_ = (struct thd_info*)gpr_malloc(sizeof(*info_));
    info_->thread = this;
    info_->body = thd_body;
    info_->arg = arg;
    info_->join_event = nullptr;
    info_->joinable = options.joinable();
    if (info_->joinable) {
      info_->join_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
      if (info_->join_event == nullptr) {
        gpr_free(info_);
        *success = false;
        return;
      }
    }
    handle = CreateThread(nullptr, 64 * 1024,
                          [](void* v) WIN_LAMBDA -> DWORD {
                            g_thd_info = static_cast<thd_info*>(v);
                            gpr_mu_lock(&g_thd_info->thread->mu_);
                            while (!g_thd_info->thread->started_) {
                              gpr_cv_wait(&g_thd_info->thread->ready_,
                                          &g_thd_info->thread->mu_,
                                          gpr_inf_future(GPR_CLOCK_MONOTONIC));
                            }
                            gpr_mu_unlock(&g_thd_info->thread->mu_);
                            if (!g_thd_info->joinable) {
                              grpc_core::Delete(g_thd_info->thread);
                              g_thd_info->thread = nullptr;
                            }
                            g_thd_info->body(g_thd_info->arg);
                            if (g_thd_info->joinable) {
                              BOOL ret = SetEvent(g_thd_info->join_event);
                              GPR_ASSERT(ret);
                            } else {
                              gpr_free(g_thd_info);
                            }
                            return 0;
                          },
                          info_, 0, nullptr);
    if (handle == nullptr) {
      destroy_thread();
      *success = false;
    } else {
      CloseHandle(handle);
      *success = true;
    }
  }

  ~ThreadInternalsWindows() override {
    gpr_mu_destroy(&mu_);
    gpr_cv_destroy(&ready_);
  }

  void Start() override {
    gpr_mu_lock(&mu_);
    started_ = true;
    gpr_cv_signal(&ready_);
    gpr_mu_unlock(&mu_);
  }

  void Join() override {
    DWORD ret = WaitForSingleObject(info_->join_event, INFINITE);
    GPR_ASSERT(ret == WAIT_OBJECT_0);
    destroy_thread();
  }

 private:
  void destroy_thread() {
    if (info_ != nullptr && info_->joinable) {
      CloseHandle(info_->join_event);
    }
    gpr_free(info_);
  }

  gpr_mu mu_;
  gpr_cv ready_;
  bool started_;
  thd_info* info_;
};

}  // namespace

namespace grpc_core {

Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
               bool* success, const Options& options)
    : options_(options) {
  bool outcome = false;
  impl_ = New<ThreadInternalsWindows>(thd_body, arg, &outcome, options);
  if (outcome) {
    state_ = ALIVE;
  } else {
    state_ = FAILED;
    Delete(impl_);
    impl_ = nullptr;
  }

  if (success != nullptr) {
    *success = outcome;
  }
}

}  // namespace grpc_core

gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; }

#endif /* GPR_WINDOWS */
<|endoftext|>