<commit_before>/**
 * \file
 * \brief FifoQueuePriorityTestCase class implementation
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-12-14
 */

#include "FifoQueuePriorityTestCase.hpp"

#include "priorityTestPhases.hpp"
#include "SequenceAsserter.hpp"

#include "distortos/StaticThread.hpp"
#include "distortos/StaticFifoQueue.hpp"
#include "distortos/statistics.hpp"

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// size of stack for test thread, bytes
constexpr size_t testThreadStackSize {256};

/*---------------------------------------------------------------------------------------------------------------------+
| local types
+---------------------------------------------------------------------------------------------------------------------*/

/// pair of sequence points
using SequencePoints = std::pair<unsigned int, unsigned int>;

/// type of elements of \a TestFifoQueue
using TestType = unsigned int;

/// FifoQueue with \a TestType
using TestFifoQueue = FifoQueue<TestType>;

/// StaticFifoQueue with \a TestType, with storage for \a totalThreads elements
using TestStaticFifoQueue = StaticFifoQueue<TestType, totalThreads>;

/// type of test thread function
using TestThreadFunction = void(SequenceAsserter&, SequencePoints, TestFifoQueue&);

/// type of test thread
using TestThread = decltype(makeStaticThread<testThreadStackSize>({}, std::declval<TestThreadFunction>(),
		std::ref(std::declval<SequenceAsserter&>()), std::declval<SequencePoints>(),
		std::ref(std::declval<TestFifoQueue&>())));

/// function executed to prepare queue for test
using Prepare = void(TestFifoQueue&);

/// function executed on queue to trigger unblocking of test thread
using Trigger = bool(TestFifoQueue&, size_t);

/// function with final check of queue's contents after all test threads are terminated
using FinalCheck = bool(TestFifoQueue&);

/// tuple with functions for one stage, Prepare and FinalCheck may be nullptr
using Stage = std::tuple<const TestThreadFunction&, const Prepare* const, const Trigger* const,
		const FinalCheck* const>;

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Final check for "pop" stage.
 *
 * The queue should contain "second" sequence points of test threads in the same order as expected by SequenceAsserter.
 *
 * \param [in] fifoQueue is a reference to shared FIFO queue
 *
 * \return true if final check check succeeded, false otherwise
 */

bool popFinalCheck(TestFifoQueue& fifoQueue)
{
	for (size_t i = 0; i < totalThreads; ++i)
	{
		TestType testValue {};
		const auto ret = fifoQueue.tryPop(testValue);
		if (ret != 0 || testValue != i + totalThreads)
			return false;
	}

	return true;
}

/**
 * \brief Prepares queue for "pop" stage - just fills it completely with increasing values.
 *
 * \param [in] fifoQueue is a reference to shared FIFO queue
 */

void popPrepare(TestFifoQueue& fifoQueue)
{
	for (size_t i = 0; i < totalThreads; ++i)
		fifoQueue.tryPush(i);
}

/**
 * \brief FifoQueue::pop() test thread
 *
 * Marks the first sequence point in SequenceAsserter, waits for the last sequence point from FIFO queue and marks it in
 * SequenceAsserter.
 *
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] sequencePoints is a pair of sequence points for this instance (second one is ignored)
 * \param [in] fifoQueue is a reference to shared FIFO queue
 */

void popThread(SequenceAsserter& sequenceAsserter, const SequencePoints sequencePoints, TestFifoQueue& fifoQueue)
{
	sequenceAsserter.sequencePoint(sequencePoints.first);
	unsigned int lastSequencePoint {};
	fifoQueue.pop(lastSequencePoint);
	sequenceAsserter.sequencePoint(lastSequencePoint);
}

/**
 * \brief Trigger action with FifoQueue::pop().
 *
 * \param [in] fifoQueue is a reference to shared FIFO queue
 * \param [in] i is the iteration counter
 *
 * \return true if trigger check succeeded, false otherwise
 */

bool popTrigger(TestFifoQueue& fifoQueue, const size_t i)
{
	TestType testValue {};
	fifoQueue.pop(testValue);
	return testValue == i;
}

/**
 * \brief FifoQueue::push() test thread
 *
 * Marks the first sequence point in SequenceAsserter, waits for free space in FIFO queue and marks last sequence point
 * in SequenceAsserter.
 *
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] sequencePoints is a pair of sequence points for this instance
 * \param [in] fifoQueue is a reference to shared FIFO queue
 */

void pushThread(SequenceAsserter& sequenceAsserter, const SequencePoints sequencePoints, TestFifoQueue& fifoQueue)
{
	sequenceAsserter.sequencePoint(sequencePoints.first);
	fifoQueue.push(sequencePoints.second);
	sequenceAsserter.sequencePoint(sequencePoints.second);
}

/**
 * \brief Trigger action with FifoQueue::push().
 *
 * \param [in] fifoQueue is a reference to shared FIFO queue
 * \param [in] i is the iteration counter
 *
 * \return true if trigger check succeeded, false otherwise
 */

bool pushTrigger(TestFifoQueue& fifoQueue, const size_t i)
{
	fifoQueue.push(i + totalThreads);
	return true;
}

/**
 * \brief Builder of TestThread objects.
 *
 * \param [in] testThreadFunction is a reference to test thread function that will be used in TestThread
 * \param [in] firstSequencePoint is the first sequence point for this instance - equal to the order in which this
 * thread will be started
 * \param [in] threadParameters is a reference to ThreadParameters object
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] fifoQueue is a reference to shared FIFO queue
 *
 * \return constructed TestThread object
 */

TestThread makeTestThread(const TestThreadFunction& testThreadFunction, const unsigned int firstSequencePoint,
		const ThreadParameters& threadParameters, SequenceAsserter& sequenceAsserter, TestFifoQueue& fifoQueue)
{
	return makeStaticThread<testThreadStackSize>(threadParameters.first, testThreadFunction, std::ref(sequenceAsserter),
			SequencePoints{firstSequencePoint, threadParameters.second + totalThreads}, std::ref(fifoQueue));
}

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// test stages
const std::array<Stage, 2> stages
{{
		Stage{popThread, nullptr, pushTrigger, nullptr},
		Stage{pushThread, popPrepare, popTrigger, popFinalCheck},
}};

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool FifoQueuePriorityTestCase::Implementation::run_() const
{
	const auto contextSwitchCount = statistics::getContextSwitchCount();
	std::remove_const<decltype(contextSwitchCount)>::type expectedContextSwitchCount {};

	for (const auto& stage : stages)
		for (const auto& phase : priorityTestPhases)
		{
			SequenceAsserter sequenceAsserter;
			TestStaticFifoQueue fifoQueue;

			const auto& threadFunction = std::get<0>(stage);
			std::array<TestThread, totalThreads> threads
			{{
					makeTestThread(threadFunction, 0, phase.first[phase.second[0]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 1, phase.first[phase.second[1]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 2, phase.first[phase.second[2]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 3, phase.first[phase.second[3]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 4, phase.first[phase.second[4]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 5, phase.first[phase.second[5]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 6, phase.first[phase.second[6]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 7, phase.first[phase.second[7]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 8, phase.first[phase.second[8]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 9, phase.first[phase.second[9]], sequenceAsserter, fifoQueue),
			}};

			// execute Prepare
			if (std::get<1>(stage) != nullptr)
				std::get<1>(stage)(fifoQueue);

			bool result {true};

			for (auto& thread : threads)
			{
				thread.start();
				// 2 context switches: "into" the thread and "back" to main thread when test thread blocks on FIFO queue
				expectedContextSwitchCount += 2;
				if (statistics::getContextSwitchCount() - contextSwitchCount != expectedContextSwitchCount)
					result = false;
			}

			if (sequenceAsserter.assertSequence(totalThreads) == false)
				result = false;

			for (size_t i = 0; i < threads.size(); ++i)
			{
				std::get<2>(stage)(fifoQueue, i);
				// 2 context switches: into" the unblocked thread and "back" to main thread when test thread terminates
				expectedContextSwitchCount += 2;
				if (statistics::getContextSwitchCount() - contextSwitchCount != expectedContextSwitchCount)
					result = false;
			}

			for (auto& thread : threads)
				thread.join();

			// execute FinalCheck
			if (std::get<3>(stage) != nullptr && std::get<3>(stage)(fifoQueue) == false)
				result = false;

			if (result == false || sequenceAsserter.assertSequence(totalThreads * 2) == false)
				return false;
		}

	if (statistics::getContextSwitchCount() - contextSwitchCount != 2 * 4 * totalThreads * priorityTestPhases.size())
		return false;

	return true;
}

}	// namespace test

}	// namespace distortos
<commit_msg>test: comment fix in FifoQueuePriorityTestCase<commit_after>/**
 * \file
 * \brief FifoQueuePriorityTestCase class implementation
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-01-02
 */

#include "FifoQueuePriorityTestCase.hpp"

#include "priorityTestPhases.hpp"
#include "SequenceAsserter.hpp"

#include "distortos/StaticThread.hpp"
#include "distortos/StaticFifoQueue.hpp"
#include "distortos/statistics.hpp"

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// size of stack for test thread, bytes
constexpr size_t testThreadStackSize {256};

/*---------------------------------------------------------------------------------------------------------------------+
| local types
+---------------------------------------------------------------------------------------------------------------------*/

/// pair of sequence points
using SequencePoints = std::pair<unsigned int, unsigned int>;

/// type of elements of \a TestFifoQueue
using TestType = unsigned int;

/// FifoQueue with \a TestType
using TestFifoQueue = FifoQueue<TestType>;

/// StaticFifoQueue with \a TestType, with storage for \a totalThreads elements
using TestStaticFifoQueue = StaticFifoQueue<TestType, totalThreads>;

/// type of test thread function
using TestThreadFunction = void(SequenceAsserter&, SequencePoints, TestFifoQueue&);

/// type of test thread
using TestThread = decltype(makeStaticThread<testThreadStackSize>({}, std::declval<TestThreadFunction>(),
		std::ref(std::declval<SequenceAsserter&>()), std::declval<SequencePoints>(),
		std::ref(std::declval<TestFifoQueue&>())));

/// function executed to prepare queue for test
using Prepare = void(TestFifoQueue&);

/// function executed on queue to trigger unblocking of test thread
using Trigger = bool(TestFifoQueue&, size_t);

/// function with final check of queue's contents after all test threads are terminated
using FinalCheck = bool(TestFifoQueue&);

/// tuple with functions for one stage, Prepare and FinalCheck may be nullptr
using Stage = std::tuple<const TestThreadFunction&, const Prepare* const, const Trigger* const,
		const FinalCheck* const>;

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Final check for "pop" stage.
 *
 * The queue should contain "second" sequence points of test threads in the same order as expected by SequenceAsserter.
 *
 * \param [in] fifoQueue is a reference to shared FIFO queue
 *
 * \return true if final check succeeded, false otherwise
 */

bool popFinalCheck(TestFifoQueue& fifoQueue)
{
	for (size_t i = 0; i < totalThreads; ++i)
	{
		TestType testValue {};
		const auto ret = fifoQueue.tryPop(testValue);
		if (ret != 0 || testValue != i + totalThreads)
			return false;
	}

	return true;
}

/**
 * \brief Prepares queue for "pop" stage - just fills it completely with increasing values.
 *
 * \param [in] fifoQueue is a reference to shared FIFO queue
 */

void popPrepare(TestFifoQueue& fifoQueue)
{
	for (size_t i = 0; i < totalThreads; ++i)
		fifoQueue.tryPush(i);
}

/**
 * \brief FifoQueue::pop() test thread
 *
 * Marks the first sequence point in SequenceAsserter, waits for the last sequence point from FIFO queue and marks it in
 * SequenceAsserter.
 *
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] sequencePoints is a pair of sequence points for this instance (second one is ignored)
 * \param [in] fifoQueue is a reference to shared FIFO queue
 */

void popThread(SequenceAsserter& sequenceAsserter, const SequencePoints sequencePoints, TestFifoQueue& fifoQueue)
{
	sequenceAsserter.sequencePoint(sequencePoints.first);
	unsigned int lastSequencePoint {};
	fifoQueue.pop(lastSequencePoint);
	sequenceAsserter.sequencePoint(lastSequencePoint);
}

/**
 * \brief Trigger action with FifoQueue::pop().
 *
 * \param [in] fifoQueue is a reference to shared FIFO queue
 * \param [in] i is the iteration counter
 *
 * \return true if trigger check succeeded, false otherwise
 */

bool popTrigger(TestFifoQueue& fifoQueue, const size_t i)
{
	TestType testValue {};
	fifoQueue.pop(testValue);
	return testValue == i;
}

/**
 * \brief FifoQueue::push() test thread
 *
 * Marks the first sequence point in SequenceAsserter, waits for free space in FIFO queue and marks last sequence point
 * in SequenceAsserter.
 *
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] sequencePoints is a pair of sequence points for this instance
 * \param [in] fifoQueue is a reference to shared FIFO queue
 */

void pushThread(SequenceAsserter& sequenceAsserter, const SequencePoints sequencePoints, TestFifoQueue& fifoQueue)
{
	sequenceAsserter.sequencePoint(sequencePoints.first);
	fifoQueue.push(sequencePoints.second);
	sequenceAsserter.sequencePoint(sequencePoints.second);
}

/**
 * \brief Trigger action with FifoQueue::push().
 *
 * \param [in] fifoQueue is a reference to shared FIFO queue
 * \param [in] i is the iteration counter
 *
 * \return true if trigger check succeeded, false otherwise
 */

bool pushTrigger(TestFifoQueue& fifoQueue, const size_t i)
{
	fifoQueue.push(i + totalThreads);
	return true;
}

/**
 * \brief Builder of TestThread objects.
 *
 * \param [in] testThreadFunction is a reference to test thread function that will be used in TestThread
 * \param [in] firstSequencePoint is the first sequence point for this instance - equal to the order in which this
 * thread will be started
 * \param [in] threadParameters is a reference to ThreadParameters object
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] fifoQueue is a reference to shared FIFO queue
 *
 * \return constructed TestThread object
 */

TestThread makeTestThread(const TestThreadFunction& testThreadFunction, const unsigned int firstSequencePoint,
		const ThreadParameters& threadParameters, SequenceAsserter& sequenceAsserter, TestFifoQueue& fifoQueue)
{
	return makeStaticThread<testThreadStackSize>(threadParameters.first, testThreadFunction, std::ref(sequenceAsserter),
			SequencePoints{firstSequencePoint, threadParameters.second + totalThreads}, std::ref(fifoQueue));
}

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// test stages
const std::array<Stage, 2> stages
{{
		Stage{popThread, nullptr, pushTrigger, nullptr},
		Stage{pushThread, popPrepare, popTrigger, popFinalCheck},
}};

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool FifoQueuePriorityTestCase::Implementation::run_() const
{
	const auto contextSwitchCount = statistics::getContextSwitchCount();
	std::remove_const<decltype(contextSwitchCount)>::type expectedContextSwitchCount {};

	for (const auto& stage : stages)
		for (const auto& phase : priorityTestPhases)
		{
			SequenceAsserter sequenceAsserter;
			TestStaticFifoQueue fifoQueue;

			const auto& threadFunction = std::get<0>(stage);
			std::array<TestThread, totalThreads> threads
			{{
					makeTestThread(threadFunction, 0, phase.first[phase.second[0]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 1, phase.first[phase.second[1]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 2, phase.first[phase.second[2]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 3, phase.first[phase.second[3]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 4, phase.first[phase.second[4]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 5, phase.first[phase.second[5]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 6, phase.first[phase.second[6]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 7, phase.first[phase.second[7]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 8, phase.first[phase.second[8]], sequenceAsserter, fifoQueue),
					makeTestThread(threadFunction, 9, phase.first[phase.second[9]], sequenceAsserter, fifoQueue),
			}};

			// execute Prepare
			if (std::get<1>(stage) != nullptr)
				std::get<1>(stage)(fifoQueue);

			bool result {true};

			for (auto& thread : threads)
			{
				thread.start();
				// 2 context switches: "into" the thread and "back" to main thread when test thread blocks on FIFO queue
				expectedContextSwitchCount += 2;
				if (statistics::getContextSwitchCount() - contextSwitchCount != expectedContextSwitchCount)
					result = false;
			}

			if (sequenceAsserter.assertSequence(totalThreads) == false)
				result = false;

			for (size_t i = 0; i < threads.size(); ++i)
			{
				std::get<2>(stage)(fifoQueue, i);
				// 2 context switches: into" the unblocked thread and "back" to main thread when test thread terminates
				expectedContextSwitchCount += 2;
				if (statistics::getContextSwitchCount() - contextSwitchCount != expectedContextSwitchCount)
					result = false;
			}

			for (auto& thread : threads)
				thread.join();

			// execute FinalCheck
			if (std::get<3>(stage) != nullptr && std::get<3>(stage)(fifoQueue) == false)
				result = false;

			if (result == false || sequenceAsserter.assertSequence(totalThreads * 2) == false)
				return false;
		}

	if (statistics::getContextSwitchCount() - contextSwitchCount != 2 * 4 * totalThreads * priorityTestPhases.size())
		return false;

	return true;
}

}	// namespace test

}	// namespace distortos
<|endoftext|>


<commit_before>
<commit_msg>Update Ngen.Content.Path.cpp<commit_after>

#include <Ngen.hpp>

namespace Ngen {
  namespace Content {
     _static tchar Path::PathSeperatorChar() {
       #if _tkn_Platform == _tknval_Platform_Windows
         return '/';
       #else
         return '/';
       #endif
     }
  }
}
class Path {
      public:

        static const string& SystemPathChar() const;
        static string GetLastNode(const string& node=const_string("/\|"));
    };
}
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Common.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */

#include "Common.h"

using namespace std;
using namespace dev;

namespace dev
{

char const* Version = "0.6.8c";

}

<commit_msg>Version bump.<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Common.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 */

#include "Common.h"

using namespace std;
using namespace dev;

namespace dev
{

char const* Version = "0.6.8d";

}

<|endoftext|>


<commit_before>
#include "Runtime.h"

#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Function.h>

#include <libevm/VM.h>

#include "Type.h"

namespace dev
{
namespace eth
{
namespace jit
{

llvm::StructType* RuntimeData::getType()
{
	static llvm::StructType* type = nullptr;
	if (!type)
	{
		llvm::Type* elems[] =
		{
			llvm::ArrayType::get(Type::Word, _size),
			Type::BytePtr,
			Type::BytePtr,
			Type::BytePtr
		};
		type = llvm::StructType::create(elems, "Runtime");
	}
	return type;
}

namespace
{
llvm::Twine getName(RuntimeData::Index _index)
{
	switch (_index)
	{
	default:						return "data";
	case RuntimeData::Gas:			return "gas";
	case RuntimeData::Address:		return "address";
	case RuntimeData::Caller:		return "caller";
	case RuntimeData::Origin:		return "origin";
	case RuntimeData::CallValue:	return "callvalue";
	case RuntimeData::CallDataSize:	return "calldatasize";
	case RuntimeData::GasPrice:		return "gasprice";
	case RuntimeData::PrevHash:		return "prevhash";
	case RuntimeData::CoinBase:		return "coinbase";
	case RuntimeData::TimeStamp:	return "timestamp";
	case RuntimeData::Number:		return "number";
	case RuntimeData::Difficulty:	return "difficulty";
	case RuntimeData::GasLimit:		return "gaslimit";
	case RuntimeData::CodeSize:		return "codesize";
	}
}
}

Runtime::Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf):
	m_ext(_ext)
{
	set(RuntimeData::Gas, _gas);
	set(RuntimeData::Address, fromAddress(_ext.myAddress));
	set(RuntimeData::Caller, fromAddress(_ext.caller));
	set(RuntimeData::Origin, fromAddress(_ext.origin));
	set(RuntimeData::CallValue, _ext.value);
	set(RuntimeData::CallDataSize, _ext.data.size());
	set(RuntimeData::GasPrice, _ext.gasPrice);
	set(RuntimeData::PrevHash, _ext.previousBlock.hash);
	set(RuntimeData::CoinBase, fromAddress(_ext.currentBlock.coinbaseAddress));
	set(RuntimeData::TimeStamp, _ext.currentBlock.timestamp);
	set(RuntimeData::Number, _ext.currentBlock.number);
	set(RuntimeData::Difficulty, _ext.currentBlock.difficulty);
	set(RuntimeData::GasLimit, _ext.currentBlock.gasLimit);
	set(RuntimeData::CodeSize, _ext.code.size());   // TODO: Use constant
	m_data.callData = _ext.data.data();
	m_data.code = _ext.code.data();
	m_data.jmpBuf = _jmpBuf;
}

void Runtime::set(RuntimeData::Index _index, u256 _value)
{
	m_data.elems[_index] = eth2llvm(_value);
}

u256 Runtime::getGas() const
{
	return llvm2eth(m_data.elems[RuntimeData::Gas]);
}

bytesConstRef Runtime::getReturnData() const
{
	// TODO: Handle large indexes
	auto offset = static_cast<size_t>(llvm2eth(m_data.elems[RuntimeData::ReturnDataOffset]));
	auto size = static_cast<size_t>(llvm2eth(m_data.elems[RuntimeData::ReturnDataSize]));

	assert(offset + size <= m_memory.size());
	// TODO: Handle invalid data access by returning empty ref
	return {m_memory.data() + offset, size};
}

RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder)
{
	m_dataPtr = new llvm::GlobalVariable(*getModule(), Type::RuntimePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::RuntimePtr), "rt");
	llvm::Type* args[] = {Type::BytePtr, m_builder.getInt32Ty()};
	m_longjmp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, args, false), llvm::Function::ExternalLinkage, "longjmp", getModule());

	// Export data
	auto mainFunc = getMainFunction();
	llvm::Value* dataPtr = &mainFunc->getArgumentList().back();
	m_builder.CreateStore(dataPtr, m_dataPtr);
}

llvm::Value* RuntimeManager::getRuntimePtr()
{
	if (auto mainFunc = getMainFunction())
		return mainFunc->arg_begin()->getNextNode();    // Runtime is the second parameter of main function
	return m_builder.CreateLoad(m_dataPtr, "rt");
}

llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index)
{
	llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(_index)};
	return m_builder.CreateInBoundsGEP(getRuntimePtr(), idxList, getName(_index) + "Ptr");
}

llvm::Value* RuntimeManager::get(RuntimeData::Index _index)
{
	return m_builder.CreateLoad(getPtr(_index), getName(_index));
}

void RuntimeManager::set(RuntimeData::Index _index, llvm::Value* _value)
{
	m_builder.CreateStore(_value, getPtr(_index));
}

void RuntimeManager::registerReturnData(llvm::Value* _offset, llvm::Value* _size)
{
	set(RuntimeData::ReturnDataOffset, _offset);
	set(RuntimeData::ReturnDataSize, _size);
}

void RuntimeManager::raiseException(ReturnCode _returnCode)
{
	m_builder.CreateCall2(m_longjmp, getJmpBuf(), Constant::get(_returnCode));
}

llvm::Value* RuntimeManager::get(Instruction _inst)
{
	switch (_inst)
	{
	default: assert(false); return nullptr;
	case Instruction::GAS:			return get(RuntimeData::Gas);
	case Instruction::ADDRESS:		return get(RuntimeData::Address);
	case Instruction::CALLER:		return get(RuntimeData::Caller);
	case Instruction::ORIGIN:		return get(RuntimeData::Origin);
	case Instruction::CALLVALUE:	return get(RuntimeData::CallValue);
	case Instruction::CALLDATASIZE:	return get(RuntimeData::CallDataSize);
	case Instruction::GASPRICE:		return get(RuntimeData::GasPrice);
	case Instruction::PREVHASH:		return get(RuntimeData::PrevHash);
	case Instruction::COINBASE:		return get(RuntimeData::CoinBase);
	case Instruction::TIMESTAMP:	return get(RuntimeData::TimeStamp);
	case Instruction::NUMBER:		return get(RuntimeData::Number);
	case Instruction::DIFFICULTY:	return get(RuntimeData::Difficulty);
	case Instruction::GASLIMIT:		return get(RuntimeData::GasLimit);
	case Instruction::CODESIZE:		return get(RuntimeData::CodeSize);
	}
}

llvm::Value* RuntimeManager::getCallData()
{
	auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 1, "calldataPtr");
	return getBuilder().CreateLoad(ptr, "calldata");
}

llvm::Value* RuntimeManager::getCode()
{
	auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "codePtr");
	return getBuilder().CreateLoad(ptr, "code");
}

llvm::Value* RuntimeManager::getJmpBuf()
{
	auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 3, "jmpbufPtr");
	return getBuilder().CreateLoad(ptr, "jmpbuf");
}

llvm::Value* RuntimeManager::getGas()
{
	return get(RuntimeData::Gas);
}

void RuntimeManager::setGas(llvm::Value* _gas)
{
	llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(RuntimeData::Gas)};
	auto ptr = m_builder.CreateInBoundsGEP(getRuntimePtr(), idxList, "gasPtr");
	m_builder.CreateStore(_gas, ptr);
}

}
}
}
<commit_msg>Use llvm.longjmp intrinsic for longjmp [Delivers #81792986]<commit_after>
#include "Runtime.h"

#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/IntrinsicInst.h>

#include <libevm/VM.h>

#include "Type.h"

namespace dev
{
namespace eth
{
namespace jit
{

llvm::StructType* RuntimeData::getType()
{
	static llvm::StructType* type = nullptr;
	if (!type)
	{
		llvm::Type* elems[] =
		{
			llvm::ArrayType::get(Type::Word, _size),
			Type::BytePtr,
			Type::BytePtr,
			Type::BytePtr
		};
		type = llvm::StructType::create(elems, "Runtime");
	}
	return type;
}

namespace
{
llvm::Twine getName(RuntimeData::Index _index)
{
	switch (_index)
	{
	default:						return "data";
	case RuntimeData::Gas:			return "gas";
	case RuntimeData::Address:		return "address";
	case RuntimeData::Caller:		return "caller";
	case RuntimeData::Origin:		return "origin";
	case RuntimeData::CallValue:	return "callvalue";
	case RuntimeData::CallDataSize:	return "calldatasize";
	case RuntimeData::GasPrice:		return "gasprice";
	case RuntimeData::PrevHash:		return "prevhash";
	case RuntimeData::CoinBase:		return "coinbase";
	case RuntimeData::TimeStamp:	return "timestamp";
	case RuntimeData::Number:		return "number";
	case RuntimeData::Difficulty:	return "difficulty";
	case RuntimeData::GasLimit:		return "gaslimit";
	case RuntimeData::CodeSize:		return "codesize";
	}
}
}

Runtime::Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf):
	m_ext(_ext)
{
	set(RuntimeData::Gas, _gas);
	set(RuntimeData::Address, fromAddress(_ext.myAddress));
	set(RuntimeData::Caller, fromAddress(_ext.caller));
	set(RuntimeData::Origin, fromAddress(_ext.origin));
	set(RuntimeData::CallValue, _ext.value);
	set(RuntimeData::CallDataSize, _ext.data.size());
	set(RuntimeData::GasPrice, _ext.gasPrice);
	set(RuntimeData::PrevHash, _ext.previousBlock.hash);
	set(RuntimeData::CoinBase, fromAddress(_ext.currentBlock.coinbaseAddress));
	set(RuntimeData::TimeStamp, _ext.currentBlock.timestamp);
	set(RuntimeData::Number, _ext.currentBlock.number);
	set(RuntimeData::Difficulty, _ext.currentBlock.difficulty);
	set(RuntimeData::GasLimit, _ext.currentBlock.gasLimit);
	set(RuntimeData::CodeSize, _ext.code.size());   // TODO: Use constant
	m_data.callData = _ext.data.data();
	m_data.code = _ext.code.data();
	m_data.jmpBuf = _jmpBuf;
}

void Runtime::set(RuntimeData::Index _index, u256 _value)
{
	m_data.elems[_index] = eth2llvm(_value);
}

u256 Runtime::getGas() const
{
	return llvm2eth(m_data.elems[RuntimeData::Gas]);
}

bytesConstRef Runtime::getReturnData() const
{
	// TODO: Handle large indexes
	auto offset = static_cast<size_t>(llvm2eth(m_data.elems[RuntimeData::ReturnDataOffset]));
	auto size = static_cast<size_t>(llvm2eth(m_data.elems[RuntimeData::ReturnDataSize]));

	assert(offset + size <= m_memory.size());
	// TODO: Handle invalid data access by returning empty ref
	return {m_memory.data() + offset, size};
}

RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder)
{
	m_dataPtr = new llvm::GlobalVariable(*getModule(), Type::RuntimePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::RuntimePtr), "rt");
	llvm::Type* args[] = {Type::BytePtr, m_builder.getInt32Ty()};
	m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp);

	// Export data
	auto mainFunc = getMainFunction();
	llvm::Value* dataPtr = &mainFunc->getArgumentList().back();
	m_builder.CreateStore(dataPtr, m_dataPtr);
}

llvm::Value* RuntimeManager::getRuntimePtr()
{
	if (auto mainFunc = getMainFunction())
		return mainFunc->arg_begin()->getNextNode();    // Runtime is the second parameter of main function
	return m_builder.CreateLoad(m_dataPtr, "rt");
}

llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index)
{
	llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(_index)};
	return m_builder.CreateInBoundsGEP(getRuntimePtr(), idxList, getName(_index) + "Ptr");
}

llvm::Value* RuntimeManager::get(RuntimeData::Index _index)
{
	return m_builder.CreateLoad(getPtr(_index), getName(_index));
}

void RuntimeManager::set(RuntimeData::Index _index, llvm::Value* _value)
{
	m_builder.CreateStore(_value, getPtr(_index));
}

void RuntimeManager::registerReturnData(llvm::Value* _offset, llvm::Value* _size)
{
	set(RuntimeData::ReturnDataOffset, _offset);
	set(RuntimeData::ReturnDataSize, _size);
}

void RuntimeManager::raiseException(ReturnCode _returnCode)
{
	m_builder.CreateCall2(m_longjmp, getJmpBuf(), Constant::get(_returnCode));
}

llvm::Value* RuntimeManager::get(Instruction _inst)
{
	switch (_inst)
	{
	default: assert(false); return nullptr;
	case Instruction::GAS:			return get(RuntimeData::Gas);
	case Instruction::ADDRESS:		return get(RuntimeData::Address);
	case Instruction::CALLER:		return get(RuntimeData::Caller);
	case Instruction::ORIGIN:		return get(RuntimeData::Origin);
	case Instruction::CALLVALUE:	return get(RuntimeData::CallValue);
	case Instruction::CALLDATASIZE:	return get(RuntimeData::CallDataSize);
	case Instruction::GASPRICE:		return get(RuntimeData::GasPrice);
	case Instruction::PREVHASH:		return get(RuntimeData::PrevHash);
	case Instruction::COINBASE:		return get(RuntimeData::CoinBase);
	case Instruction::TIMESTAMP:	return get(RuntimeData::TimeStamp);
	case Instruction::NUMBER:		return get(RuntimeData::Number);
	case Instruction::DIFFICULTY:	return get(RuntimeData::Difficulty);
	case Instruction::GASLIMIT:		return get(RuntimeData::GasLimit);
	case Instruction::CODESIZE:		return get(RuntimeData::CodeSize);
	}
}

llvm::Value* RuntimeManager::getCallData()
{
	auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 1, "calldataPtr");
	return getBuilder().CreateLoad(ptr, "calldata");
}

llvm::Value* RuntimeManager::getCode()
{
	auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "codePtr");
	return getBuilder().CreateLoad(ptr, "code");
}

llvm::Value* RuntimeManager::getJmpBuf()
{
	auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 3, "jmpbufPtr");
	return getBuilder().CreateLoad(ptr, "jmpbuf");
}

llvm::Value* RuntimeManager::getGas()
{
	return get(RuntimeData::Gas);
}

void RuntimeManager::setGas(llvm::Value* _gas)
{
	llvm::Value* idxList[] = {m_builder.getInt32(0), m_builder.getInt32(0), m_builder.getInt32(RuntimeData::Gas)};
	auto ptr = m_builder.CreateInBoundsGEP(getRuntimePtr(), idxList, "gasPtr");
	m_builder.CreateStore(_gas, ptr);
}

}
}
}
<|endoftext|>


<commit_before>#include <silicium/html/tree.hpp>
#include <silicium/sink/iterator_sink.hpp>
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE(html_tree)
{
	using namespace Si::html;
	auto document =
		tag("html",
			tag("head",
				tag("title",
					text("Title")
				)
			)
			+
			tag("body",
				text("Hello, ") + raw("world") + dynamic<min_length<0>>([](Si::Sink<char, Si::success>::interface &destination)
				{
					Si::html::unpaired_element(destination, "br");
				})+
				tag("input", detail::make_element<min_length<0>>([](Si::Sink<char, Si::success>::interface &destination)
					{
						Si::html::add_attribute(destination, "key", "value");
					}),
					empty
				)
			)
		);
	BOOST_CHECK_EQUAL(86u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("<title>Title</title>Hello, world
<input key=\"value\"/>", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_attributes_of_unpaired_tag)
{
	using namespace Si::html;
	auto document =
		tag("input", detail::make_element<min_length<0>>([](Si::Sink<char, Si::success>::interface &destination)
			{
				Si::html::add_attribute(destination, "key", "value");
			}),
			empty
		);
	BOOST_CHECK_EQUAL(8u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("<input key=\"value\"/>", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_attributes)
{
	using namespace Si::html;
	auto document =
		tag("input", detail::make_element<min_length<0>>([](Si::Sink<char, Si::success>::interface &destination)
			{
				Si::html::add_attribute(destination, "key", "value");
			}),
			text("content")
		);
	BOOST_CHECK_EQUAL(22u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("<input key=\"value\">content</input>", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_one_attribute)
{
	using namespace Si::html;
	auto document =
		tag("i",
			attribute("key", "value"),
			empty
		);
	BOOST_CHECK_EQUAL(16u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_two_attributes)
{
	using namespace Si::html;
	auto document =
		tag("i",
			attribute("key", "value") + attribute("key2", "value2"),
			empty
		);
	BOOST_CHECK_EQUAL(30u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_trait)
{
	Si::html::Element<>::box const erased = Si::html::Element<>::make_box(Si::html::tag("test", Si::html::text("Hello")));
	std::string generated;
	auto sink = Si::Sink<char, Si::success>::erase(Si::make_container_sink(generated));
	erased.generate(sink);
	BOOST_CHECK_EQUAL("<test>Hello</test>", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_produces_same_output_as_generator)
{
	bool const build_triggered = true;

	std::vector<char> old_style_generated;
	auto html = Si::html::make_generator(Si::make_container_sink(old_style_generated));
	html("html", [&]
	{
		html("head", [&]
		{
			html("title", [&]
			{
				html.write("Silicium build tester");
			});
		});
		html("body", [&]
		{
			if (build_triggered)
			{
				html.write("build was triggered");
			}
			html("form",
				[&]
			{
				html.attribute("action", "/");
				html.attribute("method", "POST");
			},
				[&]
			{
				html("input",
					[&]
				{
					html.attribute("type", "submit");
					html.attribute("value", "Trigger build");
				},
					Si::html::empty);
			});
		});

	});

	using namespace Si::html;
	auto document = tag("html",
		tag("head",
			tag("title",
				text("Silicium build tester")
			)
		) +
		tag("body",
			dynamic<min_length<0>>([build_triggered](Si::Sink<char, Si::success>::interface &destination)
			{
				if (!build_triggered)
				{
					return;
				}
				text("build was triggered").generate(destination);
			}) +
			tag("form",
				attribute("action", "/") +
				attribute("method", "POST"),
				tag("input",
					attribute("type", "submit") +
					attribute("value", "Trigger build"),
					empty
				)
			)
		)
	);
	std::vector<char> new_style_generated = Si::html::generate<std::vector<char>>(document);

	BOOST_CHECK(old_style_generated == new_style_generated);
}
<commit_msg>more HTML tree tests<commit_after>#include <silicium/html/tree.hpp>
#include <silicium/sink/iterator_sink.hpp>
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE(html_tree)
{
	using namespace Si::html;
	auto document =
		tag("html",
			tag("head",
				tag("title",
					text("Title")
				)
			)
			+
			tag("body",
				text("Hello, ") + raw("world") + dynamic<min_length<0>>([](Si::Sink<char, Si::success>::interface &destination)
				{
					Si::html::unpaired_element(destination, "br");
				})+
				tag("input", detail::make_element<min_length<0>>([](Si::Sink<char, Si::success>::interface &destination)
					{
						Si::html::add_attribute(destination, "key", "value");
					}),
					empty
				)
			)
		);
	BOOST_CHECK_EQUAL(86u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("<title>Title</title>Hello, world
<input key=\"value\"/>", generated);
}

#if !SILICIUM_VC2013
BOOST_AUTO_TEST_CASE(html_tree_tag_without_attributes_argument)
{
	using namespace Si::html;
	auto document = tag("a", empty);
	BOOST_CHECK_EQUAL(4u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("", generated);
}
#endif

BOOST_AUTO_TEST_CASE(html_tree_unpaired_tag)
{
	using namespace Si::html;
	auto no_attributes = detail::make_element<exact_length<0>>([](Si::Sink<char, Si::success>::interface &)
	{
	});
	auto document = tag("a", no_attributes, empty);
	BOOST_CHECK_EQUAL(4u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_paired_empty_tag)
{
	using namespace Si::html;
	auto document = tag("a", dynamic<exact_length<0>>([](Si::Sink<char, Si::success>::interface &) {}));
	BOOST_CHECK_EQUAL(7u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_tag_sequence_of_tags_0)
{
	using namespace Si::html;
	auto document = sequence();
	BOOST_CHECK_EQUAL(0u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_tag_sequence_of_tags_1)
{
	using namespace Si::html;
	auto no_attributes = detail::make_element<exact_length<0>>([](Si::Sink<char, Si::success>::interface &)
	{
	});
	auto document = sequence(tag("a", no_attributes, empty));
	BOOST_CHECK_EQUAL(4u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_tag_sequence_of_tags_2)
{
	using namespace Si::html;
	auto no_attributes = detail::make_element<exact_length<0>>([](Si::Sink<char, Si::success>::interface &)
	{
	});
	auto document = sequence(tag("a", no_attributes, empty), tag("b", no_attributes, empty));
	BOOST_CHECK_EQUAL(8u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_tag_sequence_of_tags_3)
{
	using namespace Si::html;
	auto no_attributes = detail::make_element<exact_length<0>>([](Si::Sink<char, Si::success>::interface &)
	{
	});
	auto document = sequence(tag("a", no_attributes, empty), tag("b", no_attributes, empty), tag("c", no_attributes, empty));
	BOOST_CHECK_EQUAL(12u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("<c/>", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_tag_sum_of_tags_2)
{
	using namespace Si::html;
	auto no_attributes = detail::make_element<exact_length<0>>([](Si::Sink<char, Si::success>::interface &)
	{
	});
	auto document = tag("a", no_attributes, empty) + tag("b", no_attributes, empty);
	BOOST_CHECK_EQUAL(8u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_tag_sum_of_tags_3)
{
	using namespace Si::html;
	auto no_attributes = detail::make_element<exact_length<0>>([](Si::Sink<char, Si::success>::interface &)
	{
	});
	auto document = tag("a", no_attributes, empty) + tag("b", no_attributes, empty) + tag("c", no_attributes, empty);
	BOOST_CHECK_EQUAL(12u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("<c/>", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_attributes_of_unpaired_tag)
{
	using namespace Si::html;
	auto document =
		tag("input", detail::make_element<min_length<0>>([](Si::Sink<char, Si::success>::interface &destination)
			{
				Si::html::add_attribute(destination, "key", "value");
			}),
			empty
		);
	BOOST_CHECK_EQUAL(8u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("<input key=\"value\"/>", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_attributes)
{
	using namespace Si::html;
	auto document =
		tag("input", detail::make_element<min_length<0>>([](Si::Sink<char, Si::success>::interface &destination)
			{
				Si::html::add_attribute(destination, "key", "value");
			}),
			text("content")
		);
	BOOST_CHECK_EQUAL(22u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("<input key=\"value\">content</input>", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_one_attribute)
{
	using namespace Si::html;
	auto document =
		tag("i",
			attribute("key", "value"),
			empty
		);
	BOOST_CHECK_EQUAL(16u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_two_attributes)
{
	using namespace Si::html;
	auto document =
		tag("i",
			attribute("key", "value") + attribute("key2", "value2"),
			empty
		);
	BOOST_CHECK_EQUAL(30u, decltype(document)::length_type::value);
	std::string generated = generate<std::string>(document);
	BOOST_CHECK_EQUAL("", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_trait)
{
	Si::html::Element<>::box const erased = Si::html::Element<>::make_box(Si::html::tag("test", Si::html::text("Hello")));
	std::string generated;
	auto sink = Si::Sink<char, Si::success>::erase(Si::make_container_sink(generated));
	erased.generate(sink);
	BOOST_CHECK_EQUAL("<test>Hello</test>", generated);
}

BOOST_AUTO_TEST_CASE(html_tree_produces_same_output_as_generator)
{
	bool const build_triggered = true;

	std::vector<char> old_style_generated;
	auto html = Si::html::make_generator(Si::make_container_sink(old_style_generated));
	html("html", [&]
	{
		html("head", [&]
		{
			html("title", [&]
			{
				html.write("Silicium build tester");
			});
		});
		html("body", [&]
		{
			if (build_triggered)
			{
				html.write("build was triggered");
			}
			html("form",
				[&]
			{
				html.attribute("action", "/");
				html.attribute("method", "POST");
			},
				[&]
			{
				html("input",
					[&]
				{
					html.attribute("type", "submit");
					html.attribute("value", "Trigger build");
				},
					Si::html::empty);
			});
		});

	});

	using namespace Si::html;
	auto document = tag("html",
		tag("head",
			tag("title",
				text("Silicium build tester")
			)
		) +
		tag("body",
			dynamic<min_length<0>>([build_triggered](Si::Sink<char, Si::success>::interface &destination)
			{
				if (!build_triggered)
				{
					return;
				}
				text("build was triggered").generate(destination);
			}) +
			tag("form",
				attribute("action", "/") +
				attribute("method", "POST"),
				tag("input",
					attribute("type", "submit") +
					attribute("value", "Trigger build"),
					empty
				)
			)
		)
	);
	std::vector<char> new_style_generated = Si::html::generate<std::vector<char>>(document);

	BOOST_CHECK(old_style_generated == new_style_generated);
}
<|endoftext|>


<commit_before>/*
 Copyright (c) 2018 ANON authors, see AUTHORS file.

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
*/

#include "request_dispatcher.h"
#include "percent_codec.h"

// path "specs" look like this:
//
//  some_host.com/some_partial_path/{thing_one}/some_more_partial_path/{thing_two}/maybe_even_more?queryName1&queryName2

request_helper request_mapping_helper(const std::string &path_spec)
{
  std::string path, query, headers;
  pcrecpp::RE split_at_q("([^?]*)(.*)");
  if (!split_at_q.FullMatch(path_spec, &path, &query))
    anon_throw(std::runtime_error, "request_mapping failed, invalid path: " << path_spec);
  if (query.size() > 0)
  {
    if (!split_at_q.FullMatch(query.substr(1), &query, &headers))
      anon_throw(std::runtime_error, "request_mapping failed, invalid path: " << path);
    if (headers.size() > 0)
      headers = headers.substr(1);
  }

  // firgure out how many {foo} statments are in the path
  pcrecpp::StringPiece input(path);
  int count = 0;
  pcrecpp::RE re1("({[^}]*})");
  while (re1.FindAndConsume(&input))
    ++count;

  // construct a regular expression for what we will be parsing
  // out of incomming uri's
  std::string newre_str = path;
  pcrecpp::RE("{[^}]*}").GlobalReplace("([^/]*)", &newre_str);

  request_helper h(newre_str, count);

  pcrecpp::RE split_at_and("([^&]+)");
  if (query.size() > 0)
  {
    pcrecpp::StringPiece input(query);
    std::string val;
    while (split_at_and.FindAndConsume(&input, &val))
      h.query_string_items.push_back(val);
  }

  if (headers.size() > 0)
  {
    pcrecpp::StringPiece input(headers);
    std::string val;
    while (split_at_and.FindAndConsume(&input, &val))
    {
      h.header_items.push_back(val);
    }
  }

  pcrecpp::RE split_at_var("([^?{]*)(.*)");
  if (!split_at_var.FullMatch(path_spec, &h.non_var))
    anon_throw(std::runtime_error, "request_mapping failed, invalid path");

  return h;
}

std::pair<bool, std::vector<std::string>> extract_params(const request_helper &h, const http_request &request, const std::string &path, const std::string &query, bool is_options)
{
  auto ret = std::make_pair(false, std::vector<std::string>());

  std::vector<std::string> p(8);
  bool match = false;
  switch (h.num_path_substitutions)
  {
  case 0:
    match = h.path_re.FullMatch(path);
    break;
  case 1:
    match = h.path_re.FullMatch(path, &p[0]);
    break;
  case 2:
    match = h.path_re.FullMatch(path, &p[0], &p[1]);
    break;
  case 3:
    match = h.path_re.FullMatch(path, &p[0], &p[1], &p[2]);
    break;
  case 4:
    match = h.path_re.FullMatch(path, &p[0], &p[1], &p[2], &p[3]);
    break;
  case 5:
    match = h.path_re.FullMatch(path, &p[0], &p[1], &p[2], &p[3], &p[4]);
    break;
  case 6:
    match = h.path_re.FullMatch(path, &p[0], &p[1], &p[2], &p[3], &p[4], &p[5]);
    break;
  case 7:
    match = h.path_re.FullMatch(path, &p[0], &p[1], &p[2], &p[3], &p[4], &p[5], &p[6]);
    break;
  case 8:
    match = h.path_re.FullMatch(path, &p[0], &p[1], &p[2], &p[3], &p[4], &p[5], &p[6], &p[7]);
    break;
  default:
    break;
  }
  if (!match)
    return ret;
  for (auto &v : p)
  {
    if (v.size() == 0)
      break;
    ret.second.push_back(v);
  }
  if (ret.second.size() != h.num_path_substitutions)
    return ret;

  if (h.query_string_items.size() > 0)
  {
    auto quer = percent_decode(query);
    for (auto &it : h.query_string_items)
    {
      size_t pos = 0;
      auto skip_len = it.size() + 1; // for the "="
      while (true)
      {
        pos = quer.find(it + "=", pos);
        if (pos == std::string::npos)
          break;
        if (pos == 0 || (quer[pos - 1] == '&'))
          break;
        pos = quer.find("&", pos + skip_len);
      }
      if (pos == std::string::npos)
        ret.second.push_back("");
      else
      {
        auto v = quer.substr(pos + skip_len);
        ret.second.push_back(v.substr(0, v.find("&", 0)));
      }
    }
  }

  if (!is_options && h.header_items.size() > 0)
  {
    for (auto &it : h.header_items)
    {
      auto headers = request.headers;
      if (!headers.contains_header(it.c_str()))
        throw_request_error(HTTP_STATUS_BAD_REQUEST, "missing, required header: " << it);
      ret.second.push_back(headers.get_header(it.c_str()).str());
    }
  }

  ret.first = true;
  return ret;
}

void respond_options(http_server::pipe_t &pipe, const http_request &request)
{
  http_response response;
  response.add_header("access-control-allow-origin", "*");
  std::ostringstream oss;
  oss << "OPTIONS, " << request.method_str();
  response.add_header("access-control-allow-methods", oss.str());
  response.add_header("access-control-allow-headers", "*");
  response.set_status_code("204 No Content");
  pipe.respond(response);
}

void request_dispatcher::dispatch(http_server::pipe_t &pipe, const http_request &request, bool is_tls)
{
  request_wrap(pipe, [this, &pipe, &request, is_tls] {
    std::string method = request.method_str();
    bool is_options = (_cors_enabled != 0) && (_options == method);
    auto path = request.get_url_field(UF_PATH);
    if (is_options) {
      if (path == "*" || path == "") {
        std::ostringstream oss;
        oss << "OPTIONS";
        if (_cors_enabled & k_enable_cors_get)
          oss << ", GET";
        if (_cors_enabled & k_enable_cors_head)
          oss << ", HEAD";
        if (_cors_enabled & k_enable_cors_post)
          oss << ", POST";
        if (_cors_enabled & k_enable_cors_put)
          oss << ", PUT";
        if (_cors_enabled & k_enable_cors_delete)
          oss << ", DELETE";
        http_response response;
        response.add_header("allow", oss.str());
        response.set_status_code("204 No Content");
        pipe.respond(response);
        return;
      }
      if (!request.headers.contains_header("access-control-request-method"))
        throw_request_error(HTTP_STATUS_BAD_REQUEST, "OPTIONS request missing required access-control-request-method header");
      method = request.headers.get_header("access-control-request-method").str();
      bool chk = false;
      if (method == "GET")
        chk = _cors_enabled & k_enable_cors_get;
      else if (method == "HEAD")
        chk = _cors_enabled & k_enable_cors_head;
      else if (method == "POST")
        chk = _cors_enabled & k_enable_cors_post;
      else if (method == "PUT")
        chk = _cors_enabled & k_enable_cors_put;
      else if (method == "DELETE")
        chk = _cors_enabled & k_enable_cors_put;
      if (!chk)
        throw_request_error(HTTP_STATUS_METHOD_NOT_ALLOWED, "method: " << method);
    }
    auto m = _map.find(method);
    if (m == _map.end())
      throw_request_error(HTTP_STATUS_METHOD_NOT_ALLOWED, "method: " << method);
    auto query = request.get_url_field(UF_QUERY);
    auto e = m->second.upper_bound(path);
    if (e == m->second.begin())
      throw_request_error(HTTP_STATUS_NOT_FOUND, "resource: \"" << path << "\" not found (1)");
    --e;
    for (auto &f : e->second)
    {
      if (f(pipe, request, is_tls, path, query, is_options))
        return;
    }
    throw_request_error(HTTP_STATUS_NOT_FOUND, "resource: \"" << path << "\" not found (2)");
  });
}<commit_msg>debugging<commit_after>/*
 Copyright (c) 2018 ANON authors, see AUTHORS file.

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
*/

#include "request_dispatcher.h"
#include "percent_codec.h"

// path "specs" look like this:
//
//  some_host.com/some_partial_path/{thing_one}/some_more_partial_path/{thing_two}/maybe_even_more?queryName1&queryName2

request_helper request_mapping_helper(const std::string &path_spec)
{
  std::string path, query, headers;
  pcrecpp::RE split_at_q("([^?]*)(.*)");
  if (!split_at_q.FullMatch(path_spec, &path, &query))
    anon_throw(std::runtime_error, "request_mapping failed, invalid path: " << path_spec);
  if (query.size() > 0)
  {
    if (!split_at_q.FullMatch(query.substr(1), &query, &headers))
      anon_throw(std::runtime_error, "request_mapping failed, invalid path: " << path);
    if (headers.size() > 0)
      headers = headers.substr(1);
  }

  // firgure out how many {foo} statments are in the path
  pcrecpp::StringPiece input(path);
  int count = 0;
  pcrecpp::RE re1("({[^}]*})");
  while (re1.FindAndConsume(&input))
    ++count;

  // construct a regular expression for what we will be parsing
  // out of incomming uri's
  std::string newre_str = path;
  pcrecpp::RE("{[^}]*}").GlobalReplace("([^/]*)", &newre_str);

  request_helper h(newre_str, count);

  pcrecpp::RE split_at_and("([^&]+)");
  if (query.size() > 0)
  {
    pcrecpp::StringPiece input(query);
    std::string val;
    while (split_at_and.FindAndConsume(&input, &val))
      h.query_string_items.push_back(val);
  }

  if (headers.size() > 0)
  {
    pcrecpp::StringPiece input(headers);
    std::string val;
    while (split_at_and.FindAndConsume(&input, &val))
    {
      h.header_items.push_back(val);
    }
  }

  pcrecpp::RE split_at_var("([^?{]*)(.*)");
  if (!split_at_var.FullMatch(path_spec, &h.non_var))
    anon_throw(std::runtime_error, "request_mapping failed, invalid path");

  return h;
}

std::pair<bool, std::vector<std::string>> extract_params(const request_helper &h, const http_request &request, const std::string &path, const std::string &query, bool is_options)
{
  auto ret = std::make_pair(false, std::vector<std::string>());

  std::vector<std::string> p(8);
  bool match = false;
  switch (h.num_path_substitutions)
  {
  case 0:
    match = h.path_re.FullMatch(path);
    break;
  case 1:
    match = h.path_re.FullMatch(path, &p[0]);
    break;
  case 2:
    match = h.path_re.FullMatch(path, &p[0], &p[1]);
    break;
  case 3:
    match = h.path_re.FullMatch(path, &p[0], &p[1], &p[2]);
    break;
  case 4:
    match = h.path_re.FullMatch(path, &p[0], &p[1], &p[2], &p[3]);
    break;
  case 5:
    match = h.path_re.FullMatch(path, &p[0], &p[1], &p[2], &p[3], &p[4]);
    break;
  case 6:
    match = h.path_re.FullMatch(path, &p[0], &p[1], &p[2], &p[3], &p[4], &p[5]);
    break;
  case 7:
    match = h.path_re.FullMatch(path, &p[0], &p[1], &p[2], &p[3], &p[4], &p[5], &p[6]);
    break;
  case 8:
    match = h.path_re.FullMatch(path, &p[0], &p[1], &p[2], &p[3], &p[4], &p[5], &p[6], &p[7]);
    break;
  default:
    break;
  }
  if (!match)
    return ret;
  for (auto &v : p)
  {
    if (v.size() == 0)
      break;
    ret.second.push_back(v);
  }
  if (ret.second.size() != h.num_path_substitutions)
    return ret;

  if (h.query_string_items.size() > 0)
  {
    auto quer = percent_decode(query);
    for (auto &it : h.query_string_items)
    {
      size_t pos = 0;
      auto skip_len = it.size() + 1; // for the "="
      while (true)
      {
        pos = quer.find(it + "=", pos);
        if (pos == std::string::npos)
          break;
        if (pos == 0 || (quer[pos - 1] == '&'))
          break;
        pos = quer.find("&", pos + skip_len);
      }
      if (pos == std::string::npos)
        ret.second.push_back("");
      else
      {
        auto v = quer.substr(pos + skip_len);
        ret.second.push_back(v.substr(0, v.find("&", 0)));
      }
    }
  }

  if (!is_options && h.header_items.size() > 0)
  {
    for (auto &it : h.header_items)
    {
      auto headers = request.headers;
      if (!headers.contains_header(it.c_str()))
        throw_request_error(HTTP_STATUS_BAD_REQUEST, "missing, required header: " << it);
      ret.second.push_back(headers.get_header(it.c_str()).str());
    }
  }

  ret.first = true;
  return ret;
}

void respond_options(http_server::pipe_t &pipe, const http_request &request)
{
  http_response response;
  response.add_header("access-control-allow-origin", "*");
  std::ostringstream oss;
  oss << "OPTIONS, " << request.headers.get_header("access-control-request-method").str();
  response.add_header("access-control-allow-methods", oss.str());
  response.add_header("access-control-allow-headers", "*");
  response.set_status_code("204 No Content");
  pipe.respond(response);
}

void request_dispatcher::dispatch(http_server::pipe_t &pipe, const http_request &request, bool is_tls)
{
  request_wrap(pipe, [this, &pipe, &request, is_tls] {
    std::string method = request.method_str();
    bool is_options = (_cors_enabled != 0) && (_options == method);
    auto path = request.get_url_field(UF_PATH);
    if (is_options) {
      if (path == "*" || path == "") {
        std::ostringstream oss;
        oss << "OPTIONS";
        if (_cors_enabled & k_enable_cors_get)
          oss << ", GET";
        if (_cors_enabled & k_enable_cors_head)
          oss << ", HEAD";
        if (_cors_enabled & k_enable_cors_post)
          oss << ", POST";
        if (_cors_enabled & k_enable_cors_put)
          oss << ", PUT";
        if (_cors_enabled & k_enable_cors_delete)
          oss << ", DELETE";
        http_response response;
        response.add_header("allow", oss.str());
        response.set_status_code("204 No Content");
        pipe.respond(response);
        return;
      }
      if (!request.headers.contains_header("access-control-request-method"))
        throw_request_error(HTTP_STATUS_BAD_REQUEST, "OPTIONS request missing required access-control-request-method header");
      method = request.headers.get_header("access-control-request-method").str();
      bool chk = false;
      if (method == "GET")
        chk = _cors_enabled & k_enable_cors_get;
      else if (method == "HEAD")
        chk = _cors_enabled & k_enable_cors_head;
      else if (method == "POST")
        chk = _cors_enabled & k_enable_cors_post;
      else if (method == "PUT")
        chk = _cors_enabled & k_enable_cors_put;
      else if (method == "DELETE")
        chk = _cors_enabled & k_enable_cors_put;
      if (!chk)
        throw_request_error(HTTP_STATUS_METHOD_NOT_ALLOWED, "method: " << method);
    }
    auto m = _map.find(method);
    if (m == _map.end())
      throw_request_error(HTTP_STATUS_METHOD_NOT_ALLOWED, "method: " << method);
    auto query = request.get_url_field(UF_QUERY);
    auto e = m->second.upper_bound(path);
    if (e == m->second.begin())
      throw_request_error(HTTP_STATUS_NOT_FOUND, "resource: \"" << path << "\" not found (1)");
    --e;
    for (auto &f : e->second)
    {
      if (f(pipe, request, is_tls, path, query, is_options))
        return;
    }
    throw_request_error(HTTP_STATUS_NOT_FOUND, "resource: \"" << path << "\" not found (2)");
  });
}<|endoftext|>


<commit_before>/*
    This file is part of libkcal.

    Copyright (c) 2001,2004 Cornelius Schumacher <schumacher@kde.org>
    Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <qdir.h>
#include <qfile.h>
#include <qtextstream.h>

#include <klocale.h>
#include <kdebug.h>
#include <kstandarddirs.h>

#include "event.h"
#include "todo.h"
#include "freebusy.h"
#include "icalformat.h"
#include "calendar.h"
#include "freebusycache.h"

#include "scheduler.h"

using namespace KCal;

ScheduleMessage::ScheduleMessage(IncidenceBase *incidence,int method,ScheduleMessage::Status status)
{
  mIncidence = incidence;
  mMethod = method;
  mStatus = status;
}

QString ScheduleMessage::statusName(ScheduleMessage::Status status)
{
  switch (status) {
    case PublishUpdate:
      return i18n("Updated Publish");
    case PublishNew:
      return i18n("Publish");
    case Obsolete:
      return i18n("Obsolete");
    case RequestNew:
      return i18n("New Request");
    case RequestUpdate:
      return i18n("Updated Request");
    default:
      return i18n("Unknown Status: %1").arg(QString::number(status));
  }
}

struct Scheduler::Private
{
  Private() : mFreeBusyCache( 0 ) {}

  FreeBusyCache *mFreeBusyCache;
};

Scheduler::Scheduler(Calendar *calendar)
{
  mCalendar = calendar;
  mFormat = new ICalFormat();
  mFormat->setTimeZone( calendar->timeZoneId(), !calendar->isLocalTime() );

  d = new Private;
}

Scheduler::~Scheduler()
{
  delete d;

  delete mFormat;
}

void Scheduler::setFreeBusyCache( FreeBusyCache *c )
{
  d->mFreeBusyCache = c;
}

FreeBusyCache *Scheduler::freeBusyCache() const
{
  return d->mFreeBusyCache;
}

bool Scheduler::acceptTransaction(IncidenceBase *incidence,Method method,ScheduleMessage::Status status)
{
  kdDebug(5800) << "Scheduler::acceptTransaction, method="
                << methodName( method ) << endl;

  switch (method) {
    case Publish:
      return acceptPublish(incidence, status, method);
    case Request:
      return acceptRequest(incidence, status);
    case Add:
      return acceptAdd(incidence, status);
    case Cancel:
      return acceptCancel(incidence, status);
    case Declinecounter:
      return acceptDeclineCounter(incidence, status);
    case Reply:
      return acceptReply(incidence, status, method);
    case Refresh:
      return acceptRefresh(incidence, status);
    case Counter:
      return acceptCounter(incidence, status);
    default:
      break;
  }
  deleteTransaction(incidence);
  return false;
}

QString Scheduler::methodName(Method method)
{
  switch (method) {
    case Publish:
      return QString::fromLatin1("Publish");
    case Request:
      return QString::fromLatin1("Request");
    case Refresh:
      return QString::fromLatin1("Refresh");
    case Cancel:
      return QString::fromLatin1("Cancel");
    case Add:
      return QString::fromLatin1("Add");
    case Reply:
      return QString::fromLatin1("Reply");
    case Counter:
      return QString::fromLatin1("Counter");
    case Declinecounter:
      return QString::fromLatin1("Decline Counter");
    default:
      return QString::fromLatin1("Unknown");
  }
}

QString Scheduler::translatedMethodName(Method method)
{
  switch (method) {
    case Publish:
      return i18n("Publish");
    case Request:
      return i18n("Request");
    case Refresh:
      return i18n("Refresh");
    case Cancel:
      return i18n("Cancel");
    case Add:
      return i18n("Add");
    case Reply:
      return i18n("Reply");
    case Counter:
      return i18n("counter proposal","Counter");
    case Declinecounter:
      return i18n("decline counter proposal","Decline Counter");
    default:
      return i18n("Unknown");
  }
}

bool Scheduler::deleteTransaction(IncidenceBase *)
{
  return true;
}

bool Scheduler::acceptPublish( IncidenceBase *newIncBase,
                               ScheduleMessage::Status status, Method method )
{
  if( newIncBase->type() == "FreeBusy" ) {
    return acceptFreeBusy( newIncBase, method );
  }

  bool res = false;
  kdDebug(5800) << "Scheduler::acceptPublish, status="
            << ScheduleMessage::statusName( status ) << endl;
  Incidence *newInc = static_cast<Incidence *>( newIncBase );
  Incidence *calInc = mCalendar->incidence( newIncBase->uid() );
  switch ( status ) {
    case ScheduleMessage::Unknown:
    case ScheduleMessage::PublishNew:
    case ScheduleMessage::PublishUpdate:
      res = true;
      if ( calInc ) {
        if ( (newInc->revision() > calInc->revision()) ||
             (newInc->revision() == calInc->revision() &&
               newInc->lastModified() > calInc->lastModified() ) ) {
          mCalendar->deleteIncidence( calInc );
        } else
          res = false;
      }
      if ( res )
        mCalendar->addIncidence( newInc );
      break;
    case ScheduleMessage::Obsolete:
      res = true;
      break;
    default:
      break;
  }
  deleteTransaction( newIncBase );
  return res;
}

bool Scheduler::acceptRequest(IncidenceBase *newIncBase, ScheduleMessage::Status /* status */)
{
  if (newIncBase->type()=="FreeBusy") {
    // reply to this request is handled in korganizer's incomingdialog
    return true;
  }
  Incidence *newInc = dynamic_cast<Incidence *>( newIncBase );
  if ( newInc ) {
    bool res = true;
    Incidence *exInc = mCalendar->incidenceFromSchedulingID( newIncBase->uid() );
    if ( exInc ) {
      res = false;
      if ( (newInc->revision() > exInc->revision()) ||
           (newInc->revision() == exInc->revision() &&
             newInc->lastModified()>exInc->lastModified()) ) {
        mCalendar->deleteIncidence( exInc );
        res = true;
      }
    }
    if ( res ) {
      // Move the uid to be the schedulingID and make a unique UID
      newInc->setSchedulingID( newInc->uid() );
      newInc->setUid( CalFormat::createUniqueId() );

      mCalendar->addIncidence(newInc);
    }
    deleteTransaction( newIncBase );
    return res;
  }
  return false;
}

bool Scheduler::acceptAdd(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptCancel(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  bool ret = false;
  Incidence *inc = mCalendar->incidence( incidence->uid() );
  if ( inc ) {
    mCalendar->deleteIncidence( inc );
    ret = true;
  }
  deleteTransaction(incidence);
  return ret;
}

bool Scheduler::acceptDeclineCounter(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  deleteTransaction(incidence);
  return false;
}

//bool Scheduler::acceptFreeBusy(Incidence *incidence,ScheduleMessage::Status status)
//{
//  deleteTransaction(incidence);
//  return false;
//}

bool Scheduler::acceptReply(IncidenceBase *incidence,ScheduleMessage::Status /* status */, Method method)
{
  if(incidence->type()=="FreeBusy") {
    return acceptFreeBusy(incidence, method);
  }
  bool ret = false;
  Event *ev = mCalendar->event(incidence->uid());
  Todo *to = mCalendar->todo(incidence->uid());
  if (ev || to) {
    //get matching attendee in calendar
    kdDebug(5800) << "Scheduler::acceptTransaction match found!" << endl;
    Attendee::List attendeesIn = incidence->attendees();
    Attendee::List attendeesEv;
    if (ev) attendeesEv = ev->attendees();
    if (to) attendeesEv = to->attendees();
    Attendee::List::ConstIterator inIt;
    Attendee::List::ConstIterator evIt;
    for ( inIt = attendeesIn.begin(); inIt != attendeesIn.end(); ++inIt ) {
      Attendee *attIn = *inIt;
      for ( evIt = attendeesEv.begin(); evIt != attendeesEv.end(); ++evIt ) {
        Attendee *attEv = *evIt;
        if (attIn->email().lower()==attEv->email().lower()) {
          //update attendee-info
          kdDebug(5800) << "Scheduler::acceptTransaction update attendee" << endl;
          attEv->setStatus(attIn->status());
          ret = true;
        }
      }
    }
    if ( ret ) {
      // We set at least one of the attendees, so the incidence changed
      // Note: This should not result in a sequence number bump
      if ( ev )
        ev->updated();
      else if ( to )
        to->updated();
    }
  } else
    kdError(5800) << "No incidence for scheduling\n";
  if (ret) deleteTransaction(incidence);
  return ret;
}

bool Scheduler::acceptRefresh(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  // handled in korganizer's IncomingDialog
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptCounter(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptFreeBusy(IncidenceBase *incidence, Method method)
{
  if ( !d->mFreeBusyCache ) {
    kdError() << "KCal::Scheduler: no FreeBusyCache." << endl;
    return false;
  }

  FreeBusy *freebusy = static_cast<FreeBusy *>(incidence);

  kdDebug(5800) << "acceptFreeBusy:: freeBusyDirName: " << freeBusyDir() << endl;

  Person from;
  if(method == Scheduler::Publish) {
    from = freebusy->organizer();
  }
  if((method == Scheduler::Reply) && (freebusy->attendeeCount() == 1)) {
    Attendee *attendee = freebusy->attendees().first();
    from = attendee->email();
  }

  if ( !d->mFreeBusyCache->saveFreeBusy( freebusy, from ) ) return false;

  deleteTransaction(incidence);
  return true;
}
<commit_msg>Handle incoming updates of completion status in vtodos.<commit_after>/*
    This file is part of libkcal.

    Copyright (c) 2001,2004 Cornelius Schumacher <schumacher@kde.org>
    Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <qdir.h>
#include <qfile.h>
#include <qtextstream.h>

#include <klocale.h>
#include <kdebug.h>
#include <kstandarddirs.h>

#include "event.h"
#include "todo.h"
#include "freebusy.h"
#include "icalformat.h"
#include "calendar.h"
#include "freebusycache.h"

#include "scheduler.h"

using namespace KCal;

ScheduleMessage::ScheduleMessage(IncidenceBase *incidence,int method,ScheduleMessage::Status status)
{
  mIncidence = incidence;
  mMethod = method;
  mStatus = status;
}

QString ScheduleMessage::statusName(ScheduleMessage::Status status)
{
  switch (status) {
    case PublishUpdate:
      return i18n("Updated Publish");
    case PublishNew:
      return i18n("Publish");
    case Obsolete:
      return i18n("Obsolete");
    case RequestNew:
      return i18n("New Request");
    case RequestUpdate:
      return i18n("Updated Request");
    default:
      return i18n("Unknown Status: %1").arg(QString::number(status));
  }
}

struct Scheduler::Private
{
  Private() : mFreeBusyCache( 0 ) {}

  FreeBusyCache *mFreeBusyCache;
};

Scheduler::Scheduler(Calendar *calendar)
{
  mCalendar = calendar;
  mFormat = new ICalFormat();
  mFormat->setTimeZone( calendar->timeZoneId(), !calendar->isLocalTime() );

  d = new Private;
}

Scheduler::~Scheduler()
{
  delete d;

  delete mFormat;
}

void Scheduler::setFreeBusyCache( FreeBusyCache *c )
{
  d->mFreeBusyCache = c;
}

FreeBusyCache *Scheduler::freeBusyCache() const
{
  return d->mFreeBusyCache;
}

bool Scheduler::acceptTransaction(IncidenceBase *incidence,Method method,ScheduleMessage::Status status)
{
  kdDebug(5800) << "Scheduler::acceptTransaction, method="
                << methodName( method ) << endl;

  switch (method) {
    case Publish:
      return acceptPublish(incidence, status, method);
    case Request:
      return acceptRequest(incidence, status);
    case Add:
      return acceptAdd(incidence, status);
    case Cancel:
      return acceptCancel(incidence, status);
    case Declinecounter:
      return acceptDeclineCounter(incidence, status);
    case Reply:
      return acceptReply(incidence, status, method);
    case Refresh:
      return acceptRefresh(incidence, status);
    case Counter:
      return acceptCounter(incidence, status);
    default:
      break;
  }
  deleteTransaction(incidence);
  return false;
}

QString Scheduler::methodName(Method method)
{
  switch (method) {
    case Publish:
      return QString::fromLatin1("Publish");
    case Request:
      return QString::fromLatin1("Request");
    case Refresh:
      return QString::fromLatin1("Refresh");
    case Cancel:
      return QString::fromLatin1("Cancel");
    case Add:
      return QString::fromLatin1("Add");
    case Reply:
      return QString::fromLatin1("Reply");
    case Counter:
      return QString::fromLatin1("Counter");
    case Declinecounter:
      return QString::fromLatin1("Decline Counter");
    default:
      return QString::fromLatin1("Unknown");
  }
}

QString Scheduler::translatedMethodName(Method method)
{
  switch (method) {
    case Publish:
      return i18n("Publish");
    case Request:
      return i18n("Request");
    case Refresh:
      return i18n("Refresh");
    case Cancel:
      return i18n("Cancel");
    case Add:
      return i18n("Add");
    case Reply:
      return i18n("Reply");
    case Counter:
      return i18n("counter proposal","Counter");
    case Declinecounter:
      return i18n("decline counter proposal","Decline Counter");
    default:
      return i18n("Unknown");
  }
}

bool Scheduler::deleteTransaction(IncidenceBase *)
{
  return true;
}

bool Scheduler::acceptPublish( IncidenceBase *newIncBase,
                               ScheduleMessage::Status status, Method method )
{
  if( newIncBase->type() == "FreeBusy" ) {
    return acceptFreeBusy( newIncBase, method );
  }

  bool res = false;
  kdDebug(5800) << "Scheduler::acceptPublish, status="
            << ScheduleMessage::statusName( status ) << endl;
  Incidence *newInc = static_cast<Incidence *>( newIncBase );
  Incidence *calInc = mCalendar->incidence( newIncBase->uid() );
  switch ( status ) {
    case ScheduleMessage::Unknown:
    case ScheduleMessage::PublishNew:
    case ScheduleMessage::PublishUpdate:
      res = true;
      if ( calInc ) {
        if ( (newInc->revision() > calInc->revision()) ||
             (newInc->revision() == calInc->revision() &&
               newInc->lastModified() > calInc->lastModified() ) ) {
          mCalendar->deleteIncidence( calInc );
        } else
          res = false;
      }
      if ( res )
        mCalendar->addIncidence( newInc );
      break;
    case ScheduleMessage::Obsolete:
      res = true;
      break;
    default:
      break;
  }
  deleteTransaction( newIncBase );
  return res;
}

bool Scheduler::acceptRequest(IncidenceBase *newIncBase, ScheduleMessage::Status /* status */)
{
  if (newIncBase->type()=="FreeBusy") {
    // reply to this request is handled in korganizer's incomingdialog
    return true;
  }
  Incidence *newInc = dynamic_cast<Incidence *>( newIncBase );
  if ( newInc ) {
    bool res = true;
    Incidence *exInc = mCalendar->incidenceFromSchedulingID( newIncBase->uid() );
    if ( exInc ) {
      res = false;
      if ( (newInc->revision() > exInc->revision()) ||
           (newInc->revision() == exInc->revision() &&
             newInc->lastModified()>exInc->lastModified()) ) {
        mCalendar->deleteIncidence( exInc );
        res = true;
      }
    }
    if ( res ) {
      // Move the uid to be the schedulingID and make a unique UID
      newInc->setSchedulingID( newInc->uid() );
      newInc->setUid( CalFormat::createUniqueId() );

      mCalendar->addIncidence(newInc);
    }
    deleteTransaction( newIncBase );
    return res;
  }
  return false;
}

bool Scheduler::acceptAdd(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptCancel(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  bool ret = false;
  Incidence *inc = mCalendar->incidence( incidence->uid() );
  if ( inc ) {
    mCalendar->deleteIncidence( inc );
    ret = true;
  }
  deleteTransaction(incidence);
  return ret;
}

bool Scheduler::acceptDeclineCounter(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  deleteTransaction(incidence);
  return false;
}

//bool Scheduler::acceptFreeBusy(Incidence *incidence,ScheduleMessage::Status status)
//{
//  deleteTransaction(incidence);
//  return false;
//}

bool Scheduler::acceptReply(IncidenceBase *incidence,ScheduleMessage::Status /* status */, Method method)
{
  if(incidence->type()=="FreeBusy") {
    return acceptFreeBusy(incidence, method);
  }
  bool ret = false;
  Event *ev = mCalendar->event(incidence->uid());
  Todo *to = mCalendar->todo(incidence->uid());
  if (ev || to) {
    //get matching attendee in calendar
    kdDebug(5800) << "Scheduler::acceptTransaction match found!" << endl;
    Attendee::List attendeesIn = incidence->attendees();
    Attendee::List attendeesEv;
    if (ev) attendeesEv = ev->attendees();
    if (to) attendeesEv = to->attendees();
    Attendee::List::ConstIterator inIt;
    Attendee::List::ConstIterator evIt;
    for ( inIt = attendeesIn.begin(); inIt != attendeesIn.end(); ++inIt ) {
      Attendee *attIn = *inIt;
      for ( evIt = attendeesEv.begin(); evIt != attendeesEv.end(); ++evIt ) {
        Attendee *attEv = *evIt;
        if (attIn->email().lower()==attEv->email().lower()) {
          //update attendee-info
          kdDebug(5800) << "Scheduler::acceptTransaction update attendee" << endl;
          attEv->setStatus(attIn->status());
          ret = true;
        }
      }
    }
    if ( ret ) {
      // We set at least one of the attendees, so the incidence changed
      // Note: This should not result in a sequence number bump
      if ( ev )
        ev->updated();
      else if ( to )
        to->updated();
    }
    if ( to ) {
      // for VTODO a REPLY can be used to update the completion status of
      // a task. see RFC2446 3.4.3
      Todo *update = dynamic_cast<Todo*> ( incidence );
      Q_ASSERT( update );
      if ( update && ( to->percentComplete() != update->percentComplete() ) ) {
        to->setPercentComplete( update->percentComplete() );
        to->updated();
      }
    }
  } else
    kdError(5800) << "No incidence for scheduling\n";
  if (ret) deleteTransaction(incidence);
  return ret;
}

bool Scheduler::acceptRefresh(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  // handled in korganizer's IncomingDialog
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptCounter(IncidenceBase *incidence,ScheduleMessage::Status /* status */)
{
  deleteTransaction(incidence);
  return false;
}

bool Scheduler::acceptFreeBusy(IncidenceBase *incidence, Method method)
{
  if ( !d->mFreeBusyCache ) {
    kdError() << "KCal::Scheduler: no FreeBusyCache." << endl;
    return false;
  }

  FreeBusy *freebusy = static_cast<FreeBusy *>(incidence);

  kdDebug(5800) << "acceptFreeBusy:: freeBusyDirName: " << freeBusyDir() << endl;

  Person from;
  if(method == Scheduler::Publish) {
    from = freebusy->organizer();
  }
  if((method == Scheduler::Reply) && (freebusy->attendeeCount() == 1)) {
    Attendee *attendee = freebusy->attendees().first();
    from = attendee->email();
  }

  if ( !d->mFreeBusyCache->saveFreeBusy( freebusy, from ) ) return false;

  deleteTransaction(incidence);
  return true;
}
<|endoftext|>


<commit_before>#pragma ident "$Id$"

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk 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
//  any later version.
//
//  The GPSTk 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 GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

//============================================================================
//
//This software developed by Applied Research Laboratories at the University of
//Texas at Austin, under contract to an agency or agencies within the U.S.
//Department of Defense. The U.S. Government retains all rights to use,
//duplicate, distribute, disclose, or release this software.
//
//Pursuant to DoD Directive 523024
//
// DISTRIBUTION STATEMENT A: This software has been approved for public
//                           release, distribution is unlimited.
//
//=============================================================================

#include "SP3EphemerisStore.hpp"
#include "BCEphemerisStore.hpp"

#include "RinexNavStream.hpp"
#include "RinexNavData.hpp"

#include "FICStream.hpp"
#include "FICData.hpp"

#include "EphReader.hpp"
#include "FFIdentifier.hpp"

using namespace std;
using namespace gpstk;

// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
void EphReader::read(const std::string& fn)
{
   FFIdentifier ffid(fn);

   switch (ffid)
   {
      case FFIdentifier::tRinexNav: read_rinex_nav_data(fn); break;
      case FFIdentifier::tFIC:      read_fic_data(fn);       break;
      case FFIdentifier::tSP3:      read_sp3_data(fn);       break;
      default:
         if (verboseLevel)
            cout << "# Could not determine the format of " << fn << endl;
   }

   filesRead.push_back(fn);
   if (verboseLevel>1)
      cout << "# Ephemers initial time: " << eph->getInitialTime()
           << ", final time: " << eph->getFinalTime() << endl;
} // end of read()

// ---------------------------------------------------------------------
// Read in ephemeris data in rinex format
// ---------------------------------------------------------------------
void EphReader::read_rinex_nav_data(const string& fn)
{
   BCEphemerisStore* bce;
   if (eph == NULL)
   {
      bce = new(BCEphemerisStore);
      eph = dynamic_cast<EphemerisStore*>(bce);
   }
   else
   {
      if (typeid(*eph) != typeid(BCEphemerisStore))
         throw(FFStreamError("Don't mix nav data types..."));
      bce = dynamic_cast<BCEphemerisStore*>(eph);
   }
   if (verboseLevel>2)
      cout << "# Reading " << fn << " as RINEX nav."<< endl;

   RinexNavStream rns(fn.c_str(), ios::in);
   rns.exceptions(ifstream::failbit);
   RinexNavData rnd;
   while (rns >> rnd)
      bce->addEphemeris(rnd);

   if (verboseLevel>1)
      cout << "# Read " << fn << " as RINEX nav. " << endl;
} // end of read_rinex_nav_data()

void EphReader::read_fic_data(const string& fn)
{
   BCEphemerisStore* bce;

   if (eph == NULL)
   {
      bce = new(BCEphemerisStore);
      eph = dynamic_cast<EphemerisStore*>(bce);
   }
   else
   {
      if (typeid(*eph) != typeid(BCEphemerisStore))
         throw(FFStreamError("Don't mix nav data types..."));
      bce = dynamic_cast<BCEphemerisStore*>(eph);
   }
   if (verboseLevel>2)
      cout << "# Reading " << fn << " as FIC nav."<< endl;

   FICStream fs(fn.c_str(), ios::in);
   FICHeader header;
   fs >> header;

   FICData data;
   while(fs >> data)
      if (data.blockNum==9) // Only look at the eng ephemeris
         bce->addEphemeris(data);

   if (verboseLevel>1)
      cout << "# Read " << fn << " as FIC nav."<< endl;
} // end of read_fic_data()

void EphReader::read_sp3_data(const string& fn)
{
   SP3EphemerisStore* pe;

   if (eph == NULL)
   {
      pe = new(SP3EphemerisStore);
      eph = dynamic_cast<EphemerisStore*>(pe);
   }
   else
   {
      if (typeid(*eph) != typeid(SP3EphemerisStore))
         throw(FFStreamError("Don't mix nav data types..."));
      pe = dynamic_cast<SP3EphemerisStore*>(eph);
   }
   if (verboseLevel>2)
      cout << "# Reading " << fn << " as SP3 ephemeris."<< endl;

   SP3Stream pefile(fn.c_str(),ios::in);
   pefile.exceptions(ifstream::failbit);

   SP3Header header;
   pefile >> header;

   SP3Data data;
   while(pefile >> data)
      pe->addEphemeris(data);

   if (verboseLevel>1)
      cout << "# Read " << fn << " as SP3 ephemeris."<< endl;
} // end of read_sp3_data()
<commit_msg>"Ephemeris" not "Ephemers" in output.<commit_after>#pragma ident "$Id$"

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk 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
//  any later version.
//
//  The GPSTk 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 GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Copyright 2004, The University of Texas at Austin
//
//============================================================================

//============================================================================
//
//This software developed by Applied Research Laboratories at the University of
//Texas at Austin, under contract to an agency or agencies within the U.S.
//Department of Defense. The U.S. Government retains all rights to use,
//duplicate, distribute, disclose, or release this software.
//
//Pursuant to DoD Directive 523024
//
// DISTRIBUTION STATEMENT A: This software has been approved for public
//                           release, distribution is unlimited.
//
//=============================================================================

#include "SP3EphemerisStore.hpp"
#include "BCEphemerisStore.hpp"

#include "RinexNavStream.hpp"
#include "RinexNavData.hpp"

#include "FICStream.hpp"
#include "FICData.hpp"

#include "EphReader.hpp"
#include "FFIdentifier.hpp"

using namespace std;
using namespace gpstk;

// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
void EphReader::read(const std::string& fn)
{
   FFIdentifier ffid(fn);

   switch (ffid)
   {
      case FFIdentifier::tRinexNav: read_rinex_nav_data(fn); break;
      case FFIdentifier::tFIC:      read_fic_data(fn);       break;
      case FFIdentifier::tSP3:      read_sp3_data(fn);       break;
      default:
         if (verboseLevel)
            cout << "# Could not determine the format of " << fn << endl;
   }

   filesRead.push_back(fn);
   if (verboseLevel>1)
      cout << "# Ephemeris initial time: " << eph->getInitialTime()
           << ", final time: " << eph->getFinalTime() << endl;
} // end of read()

// ---------------------------------------------------------------------
// Read in ephemeris data in rinex format
// ---------------------------------------------------------------------
void EphReader::read_rinex_nav_data(const string& fn)
{
   BCEphemerisStore* bce;
   if (eph == NULL)
   {
      bce = new(BCEphemerisStore);
      eph = dynamic_cast<EphemerisStore*>(bce);
   }
   else
   {
      if (typeid(*eph) != typeid(BCEphemerisStore))
         throw(FFStreamError("Don't mix nav data types..."));
      bce = dynamic_cast<BCEphemerisStore*>(eph);
   }
   if (verboseLevel>2)
      cout << "# Reading " << fn << " as RINEX nav."<< endl;

   RinexNavStream rns(fn.c_str(), ios::in);
   rns.exceptions(ifstream::failbit);
   RinexNavData rnd;
   while (rns >> rnd)
      bce->addEphemeris(rnd);

   if (verboseLevel>1)
      cout << "# Read " << fn << " as RINEX nav. " << endl;
} // end of read_rinex_nav_data()

void EphReader::read_fic_data(const string& fn)
{
   BCEphemerisStore* bce;

   if (eph == NULL)
   {
      bce = new(BCEphemerisStore);
      eph = dynamic_cast<EphemerisStore*>(bce);
   }
   else
   {
      if (typeid(*eph) != typeid(BCEphemerisStore))
         throw(FFStreamError("Don't mix nav data types..."));
      bce = dynamic_cast<BCEphemerisStore*>(eph);
   }
   if (verboseLevel>2)
      cout << "# Reading " << fn << " as FIC nav."<< endl;

   FICStream fs(fn.c_str(), ios::in);
   FICHeader header;
   fs >> header;

   FICData data;
   while(fs >> data)
      if (data.blockNum==9) // Only look at the eng ephemeris
         bce->addEphemeris(data);

   if (verboseLevel>1)
      cout << "# Read " << fn << " as FIC nav."<< endl;
} // end of read_fic_data()

void EphReader::read_sp3_data(const string& fn)
{
   SP3EphemerisStore* pe;

   if (eph == NULL)
   {
      pe = new(SP3EphemerisStore);
      eph = dynamic_cast<EphemerisStore*>(pe);
   }
   else
   {
      if (typeid(*eph) != typeid(SP3EphemerisStore))
         throw(FFStreamError("Don't mix nav data types..."));
      pe = dynamic_cast<SP3EphemerisStore*>(eph);
   }
   if (verboseLevel>2)
      cout << "# Reading " << fn << " as SP3 ephemeris."<< endl;

   SP3Stream pefile(fn.c_str(),ios::in);
   pefile.exceptions(ifstream::failbit);

   SP3Header header;
   pefile >> header;

   SP3Data data;
   while(pefile >> data)
      pe->addEphemeris(data);

   if (verboseLevel>1)
      cout << "# Read " << fn << " as SP3 ephemeris."<< endl;
} // end of read_sp3_data()
<|endoftext|>