<commit_before>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: dockWidget.C,v 1.13 2003/09/17 22:16:40 amoll Exp $

#include <BALL/VIEW/WIDGETS/dockWidget.h>
#include <BALL/VIEW/KERNEL/mainControl.h>
#include <BALL/VIEW/KERNEL/common.h>
#include <qmenubar.h>
#include <qlabel.h>

using std::endl;

namespace BALL
{
	namespace VIEW
	{

DockWidget::DockWidget(QWidget* parent, const char* name)
: QDockWindow(QDockWindow::InDock, parent),
	ModularWidget(name),
	guest_(0)
{
	layout_ = new QVBoxLayout(this);
  caption_label_ = new QLabel(this, "caption_label");
	caption_label_->resize(90, 12);
  caption_label_->setSizePolicy( QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed, 0, 0, false));
  caption_label_->setPaletteBackgroundColor( QColor( 255, 255, 127 ) );
  QFont caption_label_font(caption_label_->font());
  caption_label_font.setFamily( "Helvetica" );
  caption_label_font.setPointSize( 11 );
  caption_label_->setFont( caption_label_font );
  caption_label_->setFrameShape(QLabel::NoFrame);
  caption_label_->setAlignment(QLabel::AlignCenter);
	layout_->addWidget(caption_label_);
	Log.remove(std::cerr);
	boxLayout()->addItem(layout_);
	Log.insert(std::cerr);

	setOrientation(Qt::Vertical);

	if (name != 0)
	{
		setCaption(name);
		setName(name);
		caption_label_->setText(name);
	}
	else
	{
		setName("DockWidget");
	}

	registerWidget(this);
}

void DockWidget::setGuest(QWidget& guest)
{
	QPoint p;
	guest.reparent(this, p, true);
	guest.resize(120,100);
  guest.setSizePolicy( QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, 0, 0, false));
	layout_->addWidget(&guest);
	guest_ = &guest;
	setMinimumSize(20, 20);
	setCloseMode(QDockWindow::Always);
	setResizeEnabled(true);
}

void DockWidget::initializeWidget(MainControl& main_control)
	throw()
{
	window_menu_entry_id_ =
		main_control.insertMenuEntry(MainControl::WINDOWS, getIdentifier(), this, SLOT(switchShowWidget()));
	getMainControl()->menuBar()->setItemChecked(window_menu_entry_id_, true);
	connect(this, SIGNAL(visibilityChanged(bool)), this, SLOT(setWindowsMenuEntry(bool)));
}

void DockWidget::finalizeWidget(MainControl& main_control)
	throw()
{
	main_control.removeMenuEntry(MainControl::WINDOWS, getIdentifier(), this, SLOT(switchShowWidget()));
}

void DockWidget::writePreferences(INIFile& inifile)
	throw()
{
	ModularWidget::writePreferences(inifile);

	inifile.insertValue("WINDOWS", getIdentifier() + "::docked", String(area() != 0));
	if (!area()) return;

	Dock dock;
	Index index, offset;
	bool newline;
	getMainControl()->getLocation(this, dock, index, newline, offset);
	inifile.insertValue("WINDOWS", getIdentifier() + "::dockarea", String(dock));
	inifile.insertValue("WINDOWS", getIdentifier() + "::dockindex", String(index));
	inifile.insertValue("WINDOWS", getIdentifier() + "::dockoffset", String(offset));
	inifile.insertValue("WINDOWS", getIdentifier() + "::docknewline", String(newline));
}

void DockWidget::fetchPreferences(INIFile & inifile)
	throw()
{
	if (inifile.hasEntry("WINDOWS", getIdentifier() + "::docked"))
	{
		if (!inifile.getValue("WINDOWS", getIdentifier() + "::docked").toUnsignedInt())
		{
			undock();
			show();
		}
		else
		{
			if (inifile.hasEntry("WINDOWS", getIdentifier() + "::dockarea")  &&
					inifile.hasEntry("WINDOWS", getIdentifier() + "::dockindex") &&
					inifile.hasEntry("WINDOWS", getIdentifier() + "::dockoffset")    &&
					inifile.hasEntry("WINDOWS", getIdentifier() + "::docknewline"))
			{
				Dock dock = (Dock) inifile.getValue("WINDOWS", getIdentifier() + "::dockarea").toUnsignedInt();
				Index index = inifile.getValue("WINDOWS", getIdentifier() + "::dockindex").toUnsignedInt();
				Index offset = inifile.getValue("WINDOWS", getIdentifier() + "::dockoffset").toUnsignedInt();
				bool newline = inifile.getValue("WINDOWS", getIdentifier() + "::docknewline").toUnsignedInt();
				getMainControl()->moveDockWindow(this, dock, newline, index, offset);
			}
		}
	}

	ModularWidget::fetchPreferences(inifile);
	if (inifile.hasEntry("WINDOWS", getIdentifier() + "::height"))
	{
		Index width = inifile.getValue("WINDOWS", getIdentifier() + "::width").toUnsignedInt();
		Index height = inifile.getValue("WINDOWS", getIdentifier() + "::height").toUnsignedInt();

		if (guest_)
		{
			guest_->resize(width, height);
		}
	}

	if (inifile.hasEntry("WINDOWS", getIdentifier() + "::on"))
	{
		if (!inifile.getValue("WINDOWS", getIdentifier() + "::on").toUnsignedInt())
		{
			switchShowWidget();
		}
	}
	else
	{
		if (!default_visible_)
		{
			switchShowWidget();
		}
	}

	if (!BALL_VIEW_DOCKWINDOWS_SHOW_LABELS) caption_label_->hide();
}

void DockWidget::switchShowWidget()
	throw()
{
	if (window_menu_entry_id_ == -1) return;

	if (!getMainControl())
	{
		Log.error() << "Problem in " << __FILE__ << __LINE__ << std::endl;
		return;
	}

	QMenuBar* menu = getMainControl()->menuBar();
	if (menu->isItemChecked(window_menu_entry_id_))
	{
		hide();
		menu->setItemChecked(window_menu_entry_id_, false);
	}
	else
	{
		show();
		menu->setItemChecked(window_menu_entry_id_, true);
	}
}

void DockWidget::setWindowsMenuEntry(bool state)
{
	QMenuBar* menu = getMainControl()->menuBar();
	if (menu->isItemChecked(window_menu_entry_id_) != isVisible())
	{
		menu->setItemChecked(window_menu_entry_id_, state);
	}
}

void DockWidget::applyPreferences(Preferences & /* preferences */)
	throw()
{
	if (!BALL_VIEW_DOCKWINDOWS_SHOW_LABELS) caption_label_->hide();
	else caption_label_->show();
}

} } // namespaces
<commit_msg>changed handling of layout to prevent warning from qt<commit_after>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: dockWidget.C,v 1.14 2003/09/20 16:49:06 amoll Exp $

#include <BALL/VIEW/WIDGETS/dockWidget.h>
#include <BALL/VIEW/KERNEL/mainControl.h>
#include <BALL/VIEW/KERNEL/common.h>
#include <qmenubar.h>
#include <qlabel.h>

using std::endl;

namespace BALL
{
	namespace VIEW
	{

DockWidget::DockWidget(QWidget* parent, const char* name)
: QDockWindow(QDockWindow::InDock, parent),
	ModularWidget(name),
	guest_(0)
{
	layout_ = new QVBoxLayout();
  caption_label_ = new QLabel(this, "caption_label");
	caption_label_->resize(90, 12);
  caption_label_->setSizePolicy( QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed, 0, 0, false));
  caption_label_->setPaletteBackgroundColor( QColor( 255, 255, 127 ) );
  QFont caption_label_font(caption_label_->font());
  caption_label_font.setFamily( "Helvetica" );
  caption_label_font.setPointSize( 11 );
  caption_label_->setFont( caption_label_font );
  caption_label_->setFrameShape(QLabel::NoFrame);
  caption_label_->setAlignment(QLabel::AlignCenter);
	layout_->addWidget(caption_label_);
	Log.remove(std::cerr);
	boxLayout()->addLayout(layout_);
	Log.insert(std::cerr);

	setOrientation(Qt::Vertical);

	if (name != 0)
	{
		setCaption(name);
		setName(name);
		caption_label_->setText(name);
	}
	else
	{
		setName("DockWidget");
	}

	registerWidget(this);
}

void DockWidget::setGuest(QWidget& guest)
{
	QPoint p;
	guest.reparent(this, p, true);
	guest.resize(120,100);
  guest.setSizePolicy( QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, 0, 0, false));
	layout_->addWidget(&guest);
	guest_ = &guest;
	setMinimumSize(20, 20);
	setCloseMode(QDockWindow::Always);
	setResizeEnabled(true);
}

void DockWidget::initializeWidget(MainControl& main_control)
	throw()
{
	window_menu_entry_id_ =
		main_control.insertMenuEntry(MainControl::WINDOWS, getIdentifier(), this, SLOT(switchShowWidget()));
	getMainControl()->menuBar()->setItemChecked(window_menu_entry_id_, true);
	connect(this, SIGNAL(visibilityChanged(bool)), this, SLOT(setWindowsMenuEntry(bool)));
}

void DockWidget::finalizeWidget(MainControl& main_control)
	throw()
{
	main_control.removeMenuEntry(MainControl::WINDOWS, getIdentifier(), this, SLOT(switchShowWidget()));
}

void DockWidget::writePreferences(INIFile& inifile)
	throw()
{
	ModularWidget::writePreferences(inifile);

	inifile.insertValue("WINDOWS", getIdentifier() + "::docked", String(area() != 0));
	if (!area()) return;

	Dock dock;
	Index index, offset;
	bool newline;
	getMainControl()->getLocation(this, dock, index, newline, offset);
	inifile.insertValue("WINDOWS", getIdentifier() + "::dockarea", String(dock));
	inifile.insertValue("WINDOWS", getIdentifier() + "::dockindex", String(index));
	inifile.insertValue("WINDOWS", getIdentifier() + "::dockoffset", String(offset));
	inifile.insertValue("WINDOWS", getIdentifier() + "::docknewline", String(newline));
}

void DockWidget::fetchPreferences(INIFile & inifile)
	throw()
{
	if (inifile.hasEntry("WINDOWS", getIdentifier() + "::docked"))
	{
		if (!inifile.getValue("WINDOWS", getIdentifier() + "::docked").toUnsignedInt())
		{
			undock();
			show();
		}
		else
		{
			if (inifile.hasEntry("WINDOWS", getIdentifier() + "::dockarea")  &&
					inifile.hasEntry("WINDOWS", getIdentifier() + "::dockindex") &&
					inifile.hasEntry("WINDOWS", getIdentifier() + "::dockoffset")    &&
					inifile.hasEntry("WINDOWS", getIdentifier() + "::docknewline"))
			{
				Dock dock = (Dock) inifile.getValue("WINDOWS", getIdentifier() + "::dockarea").toUnsignedInt();
				Index index = inifile.getValue("WINDOWS", getIdentifier() + "::dockindex").toUnsignedInt();
				Index offset = inifile.getValue("WINDOWS", getIdentifier() + "::dockoffset").toUnsignedInt();
				bool newline = inifile.getValue("WINDOWS", getIdentifier() + "::docknewline").toUnsignedInt();
				getMainControl()->moveDockWindow(this, dock, newline, index, offset);
			}
		}
	}

	ModularWidget::fetchPreferences(inifile);
	if (inifile.hasEntry("WINDOWS", getIdentifier() + "::height"))
	{
		Index width = inifile.getValue("WINDOWS", getIdentifier() + "::width").toUnsignedInt();
		Index height = inifile.getValue("WINDOWS", getIdentifier() + "::height").toUnsignedInt();

		if (guest_)
		{
			guest_->resize(width, height);
		}
	}

	if (inifile.hasEntry("WINDOWS", getIdentifier() + "::on"))
	{
		if (!inifile.getValue("WINDOWS", getIdentifier() + "::on").toUnsignedInt())
		{
			switchShowWidget();
		}
	}
	else
	{
		if (!default_visible_)
		{
			switchShowWidget();
		}
	}

	if (!BALL_VIEW_DOCKWINDOWS_SHOW_LABELS) caption_label_->hide();
}

void DockWidget::switchShowWidget()
	throw()
{
	if (window_menu_entry_id_ == -1) return;

	if (!getMainControl())
	{
		Log.error() << "Problem in " << __FILE__ << __LINE__ << std::endl;
		return;
	}

	QMenuBar* menu = getMainControl()->menuBar();
	if (menu->isItemChecked(window_menu_entry_id_))
	{
		hide();
		menu->setItemChecked(window_menu_entry_id_, false);
	}
	else
	{
		show();
		menu->setItemChecked(window_menu_entry_id_, true);
	}
}

void DockWidget::setWindowsMenuEntry(bool state)
{
	QMenuBar* menu = getMainControl()->menuBar();
	if (menu->isItemChecked(window_menu_entry_id_) != isVisible())
	{
		menu->setItemChecked(window_menu_entry_id_, state);
	}
}

void DockWidget::applyPreferences(Preferences & /* preferences */)
	throw()
{
	if (!BALL_VIEW_DOCKWINDOWS_SHOW_LABELS) caption_label_->hide();
	else caption_label_->show();
}

} } // namespaces
<|endoftext|>


<commit_before>#include "ros/ros.h"
#include <string>

#include "uinput_device.h"

const char* DEVICE_NAME_PARAM = "device_name";

int main(int argc, char** argv) {

  /* initialize ros */

  ros::init(argc, argv, "evdev_teleport_receiver");

  ros::NodeHandle n("~");

  /* open the device */

  std::string device_name;
  UinputDevice *uinput_device = new UinputDevice();

  if (n.getParam(DEVICE_NAME_PARAM, device_name)) {
    ROS_DEBUG("Creating device: %s", device_name.c_str());
    n.deleteParam(DEVICE_NAME_PARAM);
  } else {
    ROS_ERROR("Private parameter 'device_name' must be set");
    ros::shutdown();
    exit(EXIT_FAILURE);
  }

  if (!uinput_device->CreateDevice(device_name)) {
    ROS_ERROR("failed to create uinput device");
    ros::shutdown();
    exit(EXIT_FAILURE);
  }

  /* begin relaying from the topic to the device */

  ros::Subscriber evdev_sub =
    n.subscribe("/evdev_teleport/event", 1, &UinputDevice::HandleMessage, uinput_device);

  ros::spin();
}
<commit_msg>Don't delete device_name from evdev receiver<commit_after>#include "ros/ros.h"
#include <string>

#include "uinput_device.h"

const char* DEVICE_NAME_PARAM = "device_name";

int main(int argc, char** argv) {

  /* initialize ros */

  ros::init(argc, argv, "evdev_teleport_receiver");

  ros::NodeHandle n("~");

  /* open the device */

  std::string device_name;
  UinputDevice *uinput_device = new UinputDevice();

  if (n.getParam(DEVICE_NAME_PARAM, device_name)) {
    ROS_DEBUG("Creating device: %s", device_name.c_str());
  } else {
    ROS_ERROR("Private parameter 'device_name' must be set");
    ros::shutdown();
    exit(EXIT_FAILURE);
  }

  if (!uinput_device->CreateDevice(device_name)) {
    ROS_ERROR("failed to create uinput device");
    ros::shutdown();
    exit(EXIT_FAILURE);
  }

  /* begin relaying from the topic to the device */

  ros::Subscriber evdev_sub =
    n.subscribe("/evdev_teleport/event", 1, &UinputDevice::HandleMessage, uinput_device);

  ros::spin();
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2013.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "report.hpp"
#include "expenses.hpp"
#include "earnings.hpp"
#include "budget_exception.hpp"
#include "accounts.hpp"

using namespace budget;

namespace {

void render(std::vector<std::vector<std::string>>& graph){
    std::reverse(graph.begin(), graph.end());

    for(auto& line : graph){
        for(auto& col : line){
            std::cout << col;
        }
        std::cout << std::endl;
    }
}

void monthly_report(boost::gregorian::greg_year year){
    auto today = boost::gregorian::day_clock::local_day();

    budget::money max_expenses;
    budget::money max_earnings;
    budget::money max_balance;
    budget::money min_expenses;
    budget::money min_earnings;
    budget::money min_balance;

    auto sm = start_month(year);

    std::vector<int> expenses(13);
    std::vector<int> earnings(13);
    std::vector<int> balances(13);

    for(unsigned short i = sm + 1; i < today.month() + 1; ++i){
        boost::gregorian::greg_month month = i;

        auto accounts = all_accounts(year, month);

        budget::money total_expenses;
        budget::money total_earnings;
        budget::money total_balance;

        for(auto& account : accounts){
            auto expenses = accumulate_amount_if(all_expenses(),
                [year,month,account](budget::expense& e){return e.account == account.id && e.date.year() == year && e.date.month() == month;});
            auto earnings = accumulate_amount_if(all_earnings(),
                [year,month,account](budget::earning& e){return e.account == account.id && e.date.year() == year && e.date.month() == month;});

            total_expenses += expenses;
            total_earnings += earnings;

            auto balance = account.amount;
            balance -= expenses;
            balance += earnings;

            total_balance += balance;
        }

        expenses[month] = total_expenses.dollars();
        earnings[month] = total_earnings.dollars();
        balances[month] = total_balance.dollars();

        max_expenses = std::max(max_expenses, total_expenses);
        max_earnings = std::max(max_earnings, total_earnings);
        max_balance = std::max(max_balance, total_balance);
        min_expenses = std::min(min_expenses, total_expenses);
        min_earnings = std::min(min_earnings, total_earnings);
        min_balance = std::min(min_balance, total_balance);
    }

    auto height = terminal_height() - 9;
    auto width = terminal_width() - 6;

    //TODO compute the scale based on the data
    unsigned int scale = 1000;

    int min = 0;
    if(min_expenses.negative() || min_earnings.negative() || min_balance.negative()){
        min = std::min(min_expenses, std::min(min_earnings, min_balance)).dollars();

        std::cout << "real_min" << min << std::endl;

        min = -1 * ((std::abs(min) / scale) + 1) * scale;

        std::cout << "real_min" << min << std::endl;
    }

    unsigned int max = std::max(max_earnings, std::max(max_expenses, max_balance)).dollars();
    max = ((max / scale) + 1) * scale;

    unsigned int levels = max / scale + std::abs(min) / scale;

    unsigned int step_height = height / levels;
    unsigned int precision = scale / step_height;

    auto graph_height = 9 + step_height * levels;
    auto graph_width = 6 + (12 - sm) * 8 + (12 - sm - 1) * 2;

    std::cout << graph_height << std::endl;
    std::cout << graph_width << std::endl;

    std::vector<std::vector<std::string>> graph(graph_height, std::vector<std::string>(graph_width, " "));

    std::cout << graph.size() << std::endl;
    std::cout << graph.at(0).size() << std::endl;

    unsigned int min_index = 3;
    unsigned int zero_index = min_index + 1 + (std::abs(min) / scale) * step_height;

    for(unsigned short i = sm + 1; i < today.month() + 1; ++i){
        boost::gregorian::greg_month month = i;

        auto col_start = 7 + 10 * (i - sm - 1);

        for(int j = 0; j < expenses[month] / precision; ++j){
           graph[zero_index + j][col_start] = "\033[1;41m \033[0m";
           graph[zero_index + j][col_start + 1] = "\033[1;41m \033[0m";
        }

        col_start += 3;

        for(int j = 0; j < earnings[month] / precision; ++j){
           graph[zero_index + j][col_start] = "\033[1;42m \033[0m";
           graph[zero_index + j][col_start + 1] = "\033[1;42m \033[0m";
        }

        col_start += 3;

        std::cout << "balance" << std::endl;

        if(balances[month] >= 0){
            for(int j = 0; j < balances[month] / precision; ++j){
                graph[zero_index + j][col_start] = "\033[1;44m \033[0m";
                graph[zero_index + j][col_start + 1] = "\033[1;44m \033[0m";
            }
        } else {
            for(int j = 0; j < std::abs(balances[month]) / precision; ++j){
                graph[zero_index - 1 - j][col_start] = "\033[1;44m \033[0m";
                graph[zero_index - 1 - j][col_start + 1] = "\033[1;44m \033[0m";
            }
        }

        std::cout << "balance end" << std::endl;
    }

    render(graph);
}

} //end of anonymous namespace

void budget::report_module::load(){
    load_accounts();
    load_expenses();
    load_earnings();
}

void budget::report_module::handle(const std::vector<std::string>& args){
    auto today = boost::gregorian::day_clock::local_day();

    if(args.size() == 1){
        monthly_report(today.year());
    } else {
        auto& subcommand = args[1];

        if(subcommand == "monthly"){
            monthly_report(today.year());
        } else {
            throw budget_exception("Invalid subcommand \"" + subcommand + "\"");
        }
    }
}
<commit_msg>Add month legends and graph title<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2013.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "report.hpp"
#include "expenses.hpp"
#include "earnings.hpp"
#include "budget_exception.hpp"
#include "accounts.hpp"

using namespace budget;

namespace {

typedef std::vector<std::vector<std::string>> graph_type;

void render(graph_type& graph){
    std::reverse(graph.begin(), graph.end());

    for(auto& line : graph){
        for(auto& col : line){
            std::cout << col;
        }
        std::cout << std::endl;
    }
}

void write(graph_type& graph, int row, int col, const std::string& value){
    for(int i = 0; i < value.size(); ++i){
        graph[row][col + i] = value[i];
    }
}

void monthly_report(boost::gregorian::greg_year year){
    auto today = boost::gregorian::day_clock::local_day();

    budget::money max_expenses;
    budget::money max_earnings;
    budget::money max_balance;
    budget::money min_expenses;
    budget::money min_earnings;
    budget::money min_balance;

    auto sm = start_month(year);

    std::vector<int> expenses(13);
    std::vector<int> earnings(13);
    std::vector<int> balances(13);

    for(unsigned short i = sm + 1; i < today.month() + 1; ++i){
        boost::gregorian::greg_month month = i;

        auto accounts = all_accounts(year, month);

        budget::money total_expenses;
        budget::money total_earnings;
        budget::money total_balance;

        for(auto& account : accounts){
            auto expenses = accumulate_amount_if(all_expenses(),
                [year,month,account](budget::expense& e){return e.account == account.id && e.date.year() == year && e.date.month() == month;});
            auto earnings = accumulate_amount_if(all_earnings(),
                [year,month,account](budget::earning& e){return e.account == account.id && e.date.year() == year && e.date.month() == month;});

            total_expenses += expenses;
            total_earnings += earnings;

            auto balance = account.amount;
            balance -= expenses;
            balance += earnings;

            total_balance += balance;
        }

        expenses[month] = total_expenses.dollars();
        earnings[month] = total_earnings.dollars();
        balances[month] = total_balance.dollars();

        max_expenses = std::max(max_expenses, total_expenses);
        max_earnings = std::max(max_earnings, total_earnings);
        max_balance = std::max(max_balance, total_balance);
        min_expenses = std::min(min_expenses, total_expenses);
        min_earnings = std::min(min_earnings, total_earnings);
        min_balance = std::min(min_balance, total_balance);
    }

    auto height = terminal_height() - 9;
    auto width = terminal_width() - 6;

    //TODO compute the scale based on the data
    unsigned int scale = 1000;

    int min = 0;
    if(min_expenses.negative() || min_earnings.negative() || min_balance.negative()){
        min = std::min(min_expenses, std::min(min_earnings, min_balance)).dollars();
        min = -1 * ((std::abs(min) / scale) + 1) * scale;
    }

    unsigned int max = std::max(max_earnings, std::max(max_expenses, max_balance)).dollars();
    max = ((max / scale) + 1) * scale;

    unsigned int levels = max / scale + std::abs(min) / scale;

    unsigned int step_height = height / levels;
    unsigned int precision = scale / step_height;

    auto graph_height = 9 + step_height * levels;
    auto graph_width = 6 + (12 - sm) * 8 + (12 - sm - 1) * 2;

    graph_type graph(graph_height, std::vector<std::string>(graph_width, " "));

    write(graph, graph_height - 2, 8, "Monthly report of " + to_string(year));

    unsigned int min_index = 3;
    unsigned int zero_index = min_index + 1 + (std::abs(min) / scale) * step_height;

    for(unsigned short i = sm + 1; i < today.month() + 1; ++i){
        boost::gregorian::greg_month month = i;

        auto col_start = 7 + 10 * (i - sm - 1);

        //Display month legend
        auto month_str = month.as_short_string();
        write(graph, 1, col_start + 2, month_str);

        for(int j = 0; j < expenses[month] / precision; ++j){
           graph[zero_index + j][col_start] = "\033[1;41m \033[0m";
           graph[zero_index + j][col_start + 1] = "\033[1;41m \033[0m";
        }

        col_start += 3;

        for(int j = 0; j < earnings[month] / precision; ++j){
           graph[zero_index + j][col_start] = "\033[1;42m \033[0m";
           graph[zero_index + j][col_start + 1] = "\033[1;42m \033[0m";
        }

        col_start += 3;

        if(balances[month] >= 0){
            for(int j = 0; j < balances[month] / precision; ++j){
                graph[zero_index + j][col_start] = "\033[1;44m \033[0m";
                graph[zero_index + j][col_start + 1] = "\033[1;44m \033[0m";
            }
        } else {
            for(int j = 0; j < std::abs(balances[month]) / precision; ++j){
                graph[zero_index - 1 - j][col_start] = "\033[1;44m \033[0m";
                graph[zero_index - 1 - j][col_start + 1] = "\033[1;44m \033[0m";
            }
        }
    }

    render(graph);
}

} //end of anonymous namespace

void budget::report_module::load(){
    load_accounts();
    load_expenses();
    load_earnings();
}

void budget::report_module::handle(const std::vector<std::string>& args){
    auto today = boost::gregorian::day_clock::local_day();

    if(args.size() == 1){
        monthly_report(today.year());
    } else {
        auto& subcommand = args[1];

        if(subcommand == "monthly"){
            monthly_report(today.year());
        } else {
            throw budget_exception("Invalid subcommand \"" + subcommand + "\"");
        }
    }
}
<|endoftext|>


<commit_before>#include <beluga/tls/tls_client.hpp>
#include <beluga/tls/tls_reader.hpp>

beluga::http_client::request_event::request_event(bool _continue):
    continue_event(_continue)
{
}

beluga::http_client::http_client(boost::asio::ip::tcp::socket& socket):
    tcp_client(socket)
{
    initialize();
}

beluga::http_client::http_client(boost::asio::io_service& io_service):
    tcp_client(io_service)
{
    initialize();
}

void beluga::http_client::initialize()
{
    std::shared_ptr<dynamic_buffer> buffer = std::make_shared<dynamic_buffer>();

    this->on_receive.connect
	([this, buffer] (tcp_client::receive_event& event)
	 {
	     if(on_client_hello.empty())
		 return;

	     buffer->insert(buffer->end(), event.get_buffer().begin(), event.get_buffer().end());

	     tls_reader<dynamic_buffer::const_iterator> reader(*buffer);

	     if(reader.read_request(request))
	     {
		 request_event request_event(true, request);
		 on_request(request_event);

		 event.set_continue(request_event.get_continue());
	     }
	 });
}
<commit_msg>added tls_client test code<commit_after>#include <beluga/tls/tls_client.hpp>
#include <beluga/tls/tls_reader.hpp>

beluga::tls_client::record_event::record_event(bool _continue, const tls_record record):
    continue_event(_continue),
    record(record)
{
}

void beluga::tls_client::record_event::set_record(const tls_record& record)
{
    this->record = record;
}
beluga::tls_record& beluga::tls_client::record_event::get_record()
{
    return record;
}
const beluga::tls_record& beluga::tls_client::record_event::get_record() const
{
    return record;
}

beluga::tls_client::handshake_event::handshake_event(bool _continue, const tls_handshake& handshake):
    continue_event(_continue),
    handshake(handshake)
{
}

void beluga::tls_client::handshake_event::set_handshake(const tls_handshake& handshake)
{
    this->handshake = handshake;
}
beluga::tls_handshake& beluga::tls_client::handshake_event::get_handshake()
{
    return handshake;
}
const beluga::tls_handshake& beluga::tls_client::handshake_event::get_handshake() const
{
    return handshake;
}

beluga::tls_client::client_hello_event::client_hello_event(bool _continue, const tls_client_hello& client_hello):
    continue_event(_continue),
    client_hello(client_hello)
{
}

void beluga::tls_client::client_hello_event::set_client_hello(const tls_client_hello& client_hello)
{
    this->client_hello = client_hello;
}
beluga::tls_client_hello& beluga::tls_client::client_hello_event::get_client_hello()
{
    return client_hello;
}
const beluga::tls_client_hello& beluga::tls_client::client_hello_event::get_client_hello() const
{
    return client_hello;
}

beluga::tls_client::tls_client(boost::asio::ip::tcp::socket& socket):
    tcp_client(socket)
{
    initialize();
}
beluga::tls_client::tls_client(boost::asio::io_service& io_service):
    tcp_client(io_service)
{
    initialize();
}

void beluga::tls_client::initialize()
{
    std::shared_ptr<dynamic_buffer> buffer = std::make_shared<dynamic_buffer>();

    this->on_receive.connect
	([this, buffer] (tcp_client::receive_event& event)
	 {
	     buffer->insert(buffer->end(), event.get_buffer().begin(), event.get_buffer().end());

	     tls_reader<dynamic_buffer::const_iterator> reader(*buffer);
	     tls_record record;

	     if(reader.read_record(record))
	     {
		 record_event record_event(true, record);
		 on_record(record_event);

		 if(record_event.get_continue())
		 {
		     switch(record.get_type())
		     {
		     case tls_record::HANDSHAKE:
			 tls_handshake handshake;

			 if(reader.read_handshake(handshake))
			 {
			     handshake_event handshake_event(true, handshake);
			     on_handshake(handshake_event);

			     event.set_continue(handshake_event.get_continue());
			 }

			 break;
		     }
		 }
		 else
		     event.set_continue(false);
	     }
	 });
}
<|endoftext|>


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

#include "open_spiel/games/2048.h"

#include <algorithm>
#include <array>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "open_spiel/abseil-cpp/absl/strings/str_cat.h"
#include "open_spiel/spiel_utils.h"
#include "open_spiel/utils/tensor_view.h"

namespace open_spiel {
namespace twenty_forty_eight {
namespace {

constexpr int kMoveUp = 0;
constexpr int kMoveRight = 1;
constexpr int kMoveDown = 2;
constexpr int kMoveLeft = 3;
inline const std::vector<Action> kPlayerActions() {
  return {kMoveUp, kMoveRight, kMoveDown, kMoveLeft};
}

// Facts about the game.
const GameType kGameType{/*short_name=*/"2048",
                         /*long_name=*/"2048",
                         GameType::Dynamics::kSequential,
                         GameType::ChanceMode::kExplicitStochastic,
                         GameType::Information::kPerfectInformation,
                         GameType::Utility::kGeneralSum,
                         GameType::RewardModel::kTerminal,
                         /*max_num_players=*/1,
                         /*min_num_players=*/1,
                         /*provides_information_state_string=*/false,
                         /*provides_information_state_tensor=*/false,
                         /*provides_observation_string=*/true,
                         /*provides_observation_tensor=*/true,
                         {{"max_game_length", GameParameter(kMaxGameLength)},
                          {"max_score", GameParameter(kMaxScore)}}};

std::shared_ptr<const Game> Factory(const GameParameters& params) {
  return std::shared_ptr<const Game>(new TwentyFortyEightGame(params));
}

REGISTER_SPIEL_GAME(kGameType, Factory);
}  // namespace

TwentyFortyEightState::TwentyFortyEightState(std::shared_ptr<const Game> game)
    : State(game),
      board_(std::vector<Tile>(kRows * kColumns, Tile(0, false)))
      {}

void TwentyFortyEightState::SetCustomBoard(const std::vector<int>& board_seq) {
  current_player_ = 0;
  for (int r = 0; r < kRows; r++) {
    for (int c = 0; c < kColumns; c++) {
      SetBoard(r, c, Tile(board_seq[r * kRows + c], false));
    }
  }
}

ChanceAction TwentyFortyEightState
    ::SpielActionToChanceAction(Action action) const {
  std::vector<int> values = UnrankActionMixedBase(
      action, {kRows, kColumns, kChanceTiles.size()});
  return ChanceAction(values[0], values[1], values[2]);
}

Action TwentyFortyEightState
    ::ChanceActionToSpielAction(ChanceAction move) const {
  std::vector<int> action_bases = {kRows, kColumns,
      kChanceTiles.size()};
  return RankActionMixedBase(
      action_bases, {move.row, move.column, move.is_four});
}

std::vector<std::vector<int>> TwentyFortyEightState
    ::BuildTraversals(int direction) const {
  std::vector<int> x, y;
  for (int pos = 0; pos < kRows; pos++) {
    x.push_back(pos);
  }
  for (int pos = 0; pos < kColumns; pos++) {
    y.push_back(pos);
  }
  switch (direction) {
    case kMoveRight:
      reverse(x.begin(), x.end());
      reverse(y.begin(), y.end());
      break;
    case kMoveLeft:
    case kMoveDown:
      reverse(x.begin(), x.end());
      break;
  }
  return {x, y};
};

bool TwentyFortyEightState::WithinBounds(int r, int c) const {
  return r >= 0 && r < kRows && c >= 0 && c < kColumns;
};

bool TwentyFortyEightState::CellAvailable(int r, int c) const {
  return BoardAt(r, c).value == 0;
}

Coordinate GetVector(int direction) {
  switch (direction) {
      case kMoveUp:
        return Coordinate(-1, 0);
      case kMoveRight:
        return Coordinate(0, 1);
      case kMoveDown:
        return Coordinate(1, 0);
      case kMoveLeft:
        return Coordinate(0, -1);
    }
}

std::vector<Coordinate> TwentyFortyEightState
    ::FindFarthestPosition(int r, int c, int direction) const {
  // Progress towards the vector direction until an obstacle is found
  Coordinate prev = Coordinate(r, c);
  do {
    prev = Coordinate(r, c);
    Coordinate direction_diff = GetVector(direction);
    r += direction_diff.row;
    c += direction_diff.column;
  } while (WithinBounds(r, c) && CellAvailable(r, c));
  return std::vector<Coordinate> {prev,
      Coordinate(r, c)};
};

// Check for available matches between tiles (more expensive check)
bool TwentyFortyEightState::TileMatchesAvailable() const {
  for (int r = 0; r < kRows; r++) {
    for (int c = 0; c < kColumns; c++) {
      int tile = BoardAt(r, c).value;
      if (tile > 0) {
        for (int direction = 0; direction < 4; direction++) {
          Coordinate vector = GetVector(direction);
          int other = GetCellContent(r + vector.row, c + vector.column);
          if (other > 0 && other == tile) {
            return true; // These two tiles can be merged
          }
        }
      }
    }
  }
  return false;
};

void TwentyFortyEightState::PrepareTiles() {
  for (int r = 0; r < kRows; r++) {
    for (int c = 0; c < kColumns; c++) {
      Tile tile = BoardAt(r, c);
      if (tile.is_merged) {
        SetBoard(r, c, Tile(tile.value, false));
      }
    }
  }
};

int TwentyFortyEightState::GetCellContent(int r, int c) const {
  if (!WithinBounds(r, c))
    return 0;
  return BoardAt(r, c).value;
}

void TwentyFortyEightState::DoApplyAction(Action action) {
  if (IsChanceNode()) {
    // The original 2048 game starts with two random tiles
    if (!extra_chance_turn_) {
      current_player_ = 0;
    }
    extra_chance_turn_ = false;

    if (action == kNoCellAvailableAction) {
      return;
    }
    ChanceAction chance_action = SpielActionToChanceAction(action);
    SetBoard(chance_action.row, chance_action.column,
        Tile(chance_action.is_four ? kChanceTiles[1] : kChanceTiles[0], false));
    return;
  }
  action_score_ = 0;
  std::vector<std::vector<int>> traversals = BuildTraversals(action);
  PrepareTiles();
  for (int r : traversals[0]) {
    for (int c : traversals[1]) {
      int tile = GetCellContent(r, c);
      if (tile > 0) {
        bool moved = false;
        std::vector<Coordinate> positions = FindFarthestPosition(r, c, action);
        Coordinate farthest_pos = positions[0];
        Coordinate next_pos = positions[1];
        int next_cell = GetCellContent(next_pos.row, next_pos.column);
        if (next_cell > 0 && next_cell == tile
            && !BoardAt(next_pos.row, next_pos.column).is_merged) {
          int merged = tile * 2;
          action_score_ += merged;
          SetBoard(next_pos.row, next_pos.column, Tile(merged, true));
          moved = true;
        } else if (farthest_pos.row != r || farthest_pos.column != c){
          SetBoard(farthest_pos.row, farthest_pos.column, Tile(tile, false));
          moved = true;
        }
        if (moved) {
          SetBoard(r, c, Tile(0, false));
          current_player_ = kChancePlayerId;
        }
      }
    }
  }
  total_score_ += action_score_;
}

std::string TwentyFortyEightState::ActionToString(Player player,
                                          Action action_id) const {
  if (IsChanceNode()) {
    if (action_id == kNoCellAvailableAction) {
      return "No Cell Available";
    }
    ChanceAction chance_action = SpielActionToChanceAction(action_id);
    return absl::StrCat(std::to_string(chance_action.is_four ? 4 : 2),
        " added to row ", std::to_string(chance_action.row + 1),
        ", column ", std::to_string(chance_action.column + 1));
  }
  switch (action_id) {
    case kMoveUp:
      return "Up";
    case kMoveRight:
      return "Right";
    case kMoveDown:
      return "Down";
    case kMoveLeft:
      return "Left";
    default:
      return "Invalid action";
  }
}

int TwentyFortyEightState::AvailableCellCount() const {
  int count = 0;
  for (int r = 0; r < kRows; r++) {
    for (int c = 0; c < kColumns; c++) {
      if (BoardAt(r, c).value == 0) {
        count++;
      }
    }
  }
  return count;
}

ActionsAndProbs TwentyFortyEightState::ChanceOutcomes() const {
  int count = AvailableCellCount();
  if (count == 0) {
    return {{kNoCellAvailableAction, 1.0}};
  }
  ActionsAndProbs action_and_probs;
  action_and_probs.reserve(count * 2);
  for (int r = 0; r < kRows; r++) {
    for (int c = 0; c < kColumns; c++) {
      if (BoardAt(r, c).value == 0) {
        // 2 appearing randomly on the board should be 9 times as likely as a 4
        action_and_probs.emplace_back(ChanceActionToSpielAction(
            ChanceAction(r, c, false)), .9 / count);
        action_and_probs.emplace_back(ChanceActionToSpielAction(
            ChanceAction(r, c, true)), .1 / count);
      }
    }
  }
  return action_and_probs;
}

std::vector<Action> TwentyFortyEightState::LegalActions() const {
  if (IsTerminal()) {
    return {};
  }
  if (IsChanceNode()) {
    return LegalChanceOutcomes();
  }
  return kPlayerActions();
}

bool TwentyFortyEightState::InBounds(int row, int column) const {
  return (row >= 0 && row < kRows && column >= 0
      && column < kColumns);
}

std::string TwentyFortyEightState::ToString() const {
  std::string str;
  for (int r = 0; r < kRows; ++r) {
    for (int c = 0; c < kColumns; ++c) {
      std::string tile = std::to_string(BoardAt(r, c).value);
      absl::StrAppend(&str, std::string(5 - tile.length(), ' '));
      absl::StrAppend(&str, tile);
    }
    absl::StrAppend(&str, "\n");
  }
  return str;
}

bool TwentyFortyEightState::IsTerminal() const {
  return Reached2048()
      || (AvailableCellCount() == 0 && !TileMatchesAvailable());
}

bool TwentyFortyEightState::Reached2048() const {
  for (int r = 0; r < kRows; r++) {
    for (int c = 0; c < kColumns; c++) {
      if (BoardAt(r, c).value == 2048) {
        return true;
      }
    }
  }
  return false;
}

std::vector<double> TwentyFortyEightState::Rewards() const {
  return {action_score_};
}

std::vector<double> TwentyFortyEightState::Returns() const {
  return {total_score_};
}

std::string TwentyFortyEightState::InformationStateString(Player player) const {
  SPIEL_CHECK_GE(player, 0);
  SPIEL_CHECK_LT(player, num_players_);
  return HistoryString();
}

std::string TwentyFortyEightState::ObservationString(Player player) const {
  SPIEL_CHECK_GE(player, 0);
  SPIEL_CHECK_LT(player, num_players_);
  return ToString();
}

void TwentyFortyEightState::ObservationTensor(Player player,
                                      absl::Span<float> values) const {
  SPIEL_CHECK_GE(player, 0);
  SPIEL_CHECK_LT(player, num_players_);
  TensorView<2> view(values, {kRows, kColumns}, true);
  for (int row = 0; row < kRows; row++) {
    for (int column = 0; column < kColumns; column++) {
      view[{row, column}] = BoardAt(row, column).value;
    }
  }
}

void TwentyFortyEightState::UndoAction(Player player, Action action) {
  history_.pop_back();
}

TwentyFortyEightGame::TwentyFortyEightGame(const GameParameters& params)
    : Game(kGameType, params),
      max_game_length_(ParameterValue<int>("max_game_length")),
      max_score_(ParameterValue<int>("max_score")) {}

int TwentyFortyEightGame::NumDistinctActions() const {
  return kPlayerActions().size();
}

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

#include "open_spiel/games/2048.h"

#include <algorithm>
#include <array>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "open_spiel/abseil-cpp/absl/strings/str_cat.h"
#include "open_spiel/spiel_utils.h"
#include "open_spiel/utils/tensor_view.h"

namespace open_spiel {
namespace twenty_forty_eight {
namespace {

constexpr int kMoveUp = 0;
constexpr int kMoveRight = 1;
constexpr int kMoveDown = 2;
constexpr int kMoveLeft = 3;
inline const std::vector<Action> kPlayerActions() {
  return {kMoveUp, kMoveRight, kMoveDown, kMoveLeft};
}

// Facts about the game.
const GameType kGameType{/*short_name=*/"2048",
                         /*long_name=*/"2048",
                         GameType::Dynamics::kSequential,
                         GameType::ChanceMode::kExplicitStochastic,
                         GameType::Information::kPerfectInformation,
                         GameType::Utility::kGeneralSum,
                         GameType::RewardModel::kTerminal,
                         /*max_num_players=*/1,
                         /*min_num_players=*/1,
                         /*provides_information_state_string=*/false,
                         /*provides_information_state_tensor=*/false,
                         /*provides_observation_string=*/true,
                         /*provides_observation_tensor=*/true,
                         {{"max_game_length", GameParameter(kMaxGameLength)},
                          {"max_score", GameParameter(kMaxScore)}}};

std::shared_ptr<const Game> Factory(const GameParameters& params) {
  return std::shared_ptr<const Game>(new TwentyFortyEightGame(params));
}

REGISTER_SPIEL_GAME(kGameType, Factory);
}  // namespace

TwentyFortyEightState::TwentyFortyEightState(std::shared_ptr<const Game> game)
    : State(game),
      board_(std::vector<Tile>(kRows * kColumns, Tile(0, false)))
      {}

void TwentyFortyEightState::SetCustomBoard(const std::vector<int>& board_seq) {
  current_player_ = 0;
  for (int r = 0; r < kRows; r++) {
    for (int c = 0; c < kColumns; c++) {
      SetBoard(r, c, Tile(board_seq[r * kRows + c], false));
    }
  }
}

ChanceAction TwentyFortyEightState
    ::SpielActionToChanceAction(Action action) const {
  std::vector<int> values = UnrankActionMixedBase(
      action, {kRows, kColumns, kChanceTiles.size()});
  return ChanceAction(values[0], values[1], values[2]);
}

Action TwentyFortyEightState
    ::ChanceActionToSpielAction(ChanceAction move) const {
  std::vector<int> action_bases = {kRows, kColumns,
      kChanceTiles.size()};
  return RankActionMixedBase(
      action_bases, {move.row, move.column, move.is_four});
}

std::vector<std::vector<int>> TwentyFortyEightState
    ::BuildTraversals(int direction) const {
  std::vector<int> x, y;
  for (int pos = 0; pos < kRows; pos++) {
    x.push_back(pos);
  }
  for (int pos = 0; pos < kColumns; pos++) {
    y.push_back(pos);
  }
  switch (direction) {
    case kMoveRight:
      reverse(x.begin(), x.end());
      reverse(y.begin(), y.end());
      break;
    case kMoveLeft:
    case kMoveDown:
      reverse(x.begin(), x.end());
      break;
  }
  return {x, y};
};

bool TwentyFortyEightState::WithinBounds(int r, int c) const {
  return r >= 0 && r < kRows && c >= 0 && c < kColumns;
};

bool TwentyFortyEightState::CellAvailable(int r, int c) const {
  return BoardAt(r, c).value == 0;
}

Coordinate GetVector(int direction) {
  switch (direction) {
      case kMoveUp:
        return Coordinate(-1, 0);
      case kMoveRight:
        return Coordinate(0, 1);
      case kMoveDown:
        return Coordinate(1, 0);
      case kMoveLeft:
        return Coordinate(0, -1);
    }
}

std::vector<Coordinate> TwentyFortyEightState
    ::FindFarthestPosition(int r, int c, int direction) const {
  // Progress towards the vector direction until an obstacle is found
  Coordinate prev = Coordinate(r, c);
  do {
    prev = Coordinate(r, c);
    Coordinate direction_diff = GetVector(direction);
    r += direction_diff.row;
    c += direction_diff.column;
  } while (WithinBounds(r, c) && CellAvailable(r, c));
  return std::vector<Coordinate> {prev, Coordinate(r, c)};
};

// Check for available matches between tiles (more expensive check)
bool TwentyFortyEightState::TileMatchesAvailable() const {
  for (int r = 0; r < kRows; r++) {
    for (int c = 0; c < kColumns; c++) {
      int tile = BoardAt(r, c).value;
      if (tile > 0) {
        for (int direction = 0; direction < 4; direction++) {
          Coordinate vector = GetVector(direction);
          int other = GetCellContent(r + vector.row, c + vector.column);
          if (other > 0 && other == tile) {
            return true; // These two tiles can be merged
          }
        }
      }
    }
  }
  return false;
};

void TwentyFortyEightState::PrepareTiles() {
  for (int r = 0; r < kRows; r++) {
    for (int c = 0; c < kColumns; c++) {
      Tile tile = BoardAt(r, c);
      if (tile.is_merged) {
        SetBoard(r, c, Tile(tile.value, false));
      }
    }
  }
};

int TwentyFortyEightState::GetCellContent(int r, int c) const {
  if (!WithinBounds(r, c))
    return 0;
  return BoardAt(r, c).value;
}

void TwentyFortyEightState::DoApplyAction(Action action) {
  if (IsChanceNode()) {
    // The original 2048 game starts with two random tiles
    if (!extra_chance_turn_) {
      current_player_ = 0;
    }
    extra_chance_turn_ = false;

    if (action == kNoCellAvailableAction) {
      return;
    }
    ChanceAction chance_action = SpielActionToChanceAction(action);
    SetBoard(chance_action.row, chance_action.column,
        Tile(chance_action.is_four ? kChanceTiles[1] : kChanceTiles[0], false));
    return;
  }
  action_score_ = 0;
  std::vector<std::vector<int>> traversals = BuildTraversals(action);
  PrepareTiles();
  for (int r : traversals[0]) {
    for (int c : traversals[1]) {
      int tile = GetCellContent(r, c);
      if (tile > 0) {
        bool moved = false;
        std::vector<Coordinate> positions = FindFarthestPosition(r, c, action);
        Coordinate farthest_pos = positions[0];
        Coordinate next_pos = positions[1];
        int next_cell = GetCellContent(next_pos.row, next_pos.column);
        if (next_cell > 0 && next_cell == tile
            && !BoardAt(next_pos.row, next_pos.column).is_merged) {
          int merged = tile * 2;
          action_score_ += merged;
          SetBoard(next_pos.row, next_pos.column, Tile(merged, true));
          moved = true;
        } else if (farthest_pos.row != r || farthest_pos.column != c){
          SetBoard(farthest_pos.row, farthest_pos.column, Tile(tile, false));
          moved = true;
        }
        if (moved) {
          SetBoard(r, c, Tile(0, false));
          current_player_ = kChancePlayerId;
        }
      }
    }
  }
  total_score_ += action_score_;
}

std::string TwentyFortyEightState::ActionToString(Player player,
                                          Action action_id) const {
  if (IsChanceNode()) {
    if (action_id == kNoCellAvailableAction) {
      return "No Cell Available";
    }
    ChanceAction chance_action = SpielActionToChanceAction(action_id);
    return absl::StrCat(std::to_string(chance_action.is_four ? 4 : 2),
        " added to row ", std::to_string(chance_action.row + 1),
        ", column ", std::to_string(chance_action.column + 1));
  }
  switch (action_id) {
    case kMoveUp:
      return "Up";
    case kMoveRight:
      return "Right";
    case kMoveDown:
      return "Down";
    case kMoveLeft:
      return "Left";
    default:
      return "Invalid action";
  }
}

int TwentyFortyEightState::AvailableCellCount() const {
  int count = 0;
  for (int r = 0; r < kRows; r++) {
    for (int c = 0; c < kColumns; c++) {
      if (BoardAt(r, c).value == 0) {
        count++;
      }
    }
  }
  return count;
}

ActionsAndProbs TwentyFortyEightState::ChanceOutcomes() const {
  int count = AvailableCellCount();
  if (count == 0) {
    return {{kNoCellAvailableAction, 1.0}};
  }
  ActionsAndProbs action_and_probs;
  action_and_probs.reserve(count * 2);
  for (int r = 0; r < kRows; r++) {
    for (int c = 0; c < kColumns; c++) {
      if (BoardAt(r, c).value == 0) {
        // 2 appearing randomly on the board should be 9 times as likely as a 4
        action_and_probs.emplace_back(ChanceActionToSpielAction(
            ChanceAction(r, c, false)), .9 / count);
        action_and_probs.emplace_back(ChanceActionToSpielAction(
            ChanceAction(r, c, true)), .1 / count);
      }
    }
  }
  return action_and_probs;
}

std::vector<Action> TwentyFortyEightState::LegalActions() const {
  if (IsTerminal()) {
    return {};
  }
  if (IsChanceNode()) {
    return LegalChanceOutcomes();
  }
  return kPlayerActions();
}

bool TwentyFortyEightState::InBounds(int row, int column) const {
  return (row >= 0 && row < kRows && column >= 0
      && column < kColumns);
}

std::string TwentyFortyEightState::ToString() const {
  std::string str;
  for (int r = 0; r < kRows; ++r) {
    for (int c = 0; c < kColumns; ++c) {
      std::string tile = std::to_string(BoardAt(r, c).value);
      absl::StrAppend(&str, std::string(5 - tile.length(), ' '));
      absl::StrAppend(&str, tile);
    }
    absl::StrAppend(&str, "\n");
  }
  return str;
}

bool TwentyFortyEightState::IsTerminal() const {
  return Reached2048()
      || (AvailableCellCount() == 0 && !TileMatchesAvailable());
}

bool TwentyFortyEightState::Reached2048() const {
  for (int r = 0; r < kRows; r++) {
    for (int c = 0; c < kColumns; c++) {
      if (BoardAt(r, c).value == 2048) {
        return true;
      }
    }
  }
  return false;
}

std::vector<double> TwentyFortyEightState::Rewards() const {
  return {action_score_};
}

std::vector<double> TwentyFortyEightState::Returns() const {
  return {total_score_};
}

std::string TwentyFortyEightState::InformationStateString(Player player) const {
  SPIEL_CHECK_GE(player, 0);
  SPIEL_CHECK_LT(player, num_players_);
  return HistoryString();
}

std::string TwentyFortyEightState::ObservationString(Player player) const {
  SPIEL_CHECK_GE(player, 0);
  SPIEL_CHECK_LT(player, num_players_);
  return ToString();
}

void TwentyFortyEightState::ObservationTensor(Player player,
                                      absl::Span<float> values) const {
  SPIEL_CHECK_GE(player, 0);
  SPIEL_CHECK_LT(player, num_players_);
  TensorView<2> view(values, {kRows, kColumns}, true);
  for (int row = 0; row < kRows; row++) {
    for (int column = 0; column < kColumns; column++) {
      view[{row, column}] = BoardAt(row, column).value;
    }
  }
}

void TwentyFortyEightState::UndoAction(Player player, Action action) {
  history_.pop_back();
}

TwentyFortyEightGame::TwentyFortyEightGame(const GameParameters& params)
    : Game(kGameType, params),
      max_game_length_(ParameterValue<int>("max_game_length")),
      max_score_(ParameterValue<int>("max_score")) {}

int TwentyFortyEightGame::NumDistinctActions() const {
  return kPlayerActions().size();
}

}  // namespace twenty_forty_eight
}  // namespace open_spiel
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <boost/program_options.hpp>
#include <iomanip>

std::string filename = "/tmp/pending-rollback.rewind";

namespace po = boost::program_options;

void run(char change_command[], char rollback_command[], int timeout);
void keep();
void print_usage(char *argv[], po::options_description desc);
void create_file(char change_command[]);
bool file_exists();
void delete_file();

int main(int argc, char *argv[]) {
    int timeout = 30;

    po::options_description desc("Allowed options");
    desc.add_options()("timeout,t", po::value<int>(&timeout)->default_value(timeout),
            "Timeout before rollback command is executed");
    po::variables_map vm;
    try {
        po::store(po::command_line_parser(argc, argv).options(desc).run(), vm);
    } catch (po::unknown_option e) {
        std::cout << "Unknown option" << std::endl;
        print_usage(argv, desc);
        return 0;
    } catch (po::invalid_option_value e) {
        std::cout << "Invalid value for option" << std::endl;
        print_usage(argv, desc);
        return 0;
    }
    po::notify(vm);

    if (argc < 2) {
        std::cout << "You must supply an action to be performed" << std::endl;
        print_usage(argv, desc);
        return 0;
    }

    std::string mode(argv[1]);

    if (mode == "run") {
        char *change_command = argv[2];
        char *rollback_command = argv[3];
        if (argc < 4 || strlen(change_command) == 0 || strlen(rollback_command) == 0) {
            std::cout << "Must provide both a change command and a rollback command" << std::endl;
            print_usage(argv, desc);
            return 1;
        }

        if (timeout < 1) {
            std::cout << "Timeout must be at least 1" << std::endl;
            print_usage(argv, desc);
            return 1;
        }

        run(change_command, rollback_command, timeout);
    } else if(mode == "keep") {
        keep();
    } else {
        print_usage(argv, desc);
    }

    return 0;
}

void print_usage(char *argv[], po::options_description desc) {
    std::cout << "Usage:" << std::endl;
    std::cout << "  Run a new command:\t" << argv[0] << " run <change command> <rollback command> [options]" << std::endl;
    std::cout << "  Stop rollback:\t" << argv[0] << " keep" << std::endl;
    std::cout << desc << std::endl;
}

void run(char change_command[], char rollback_command[], int timeout) {
    create_file(change_command);
    system(change_command);
    daemon(1, 0);
    sleep(timeout);

    if (file_exists()) {
        system(rollback_command);
        delete_file();
    }
}

void keep() {
    delete_file();
    std::cout << "Rollback aborted, changes will be kept!" << std::endl;
}

void create_file(char change_command[]) {
    // Check if the file from an old run exists, if so ask the user to confirm
    // deletion
    std::ifstream inf(filename);
    if (inf.good()) {
        std::string timestamp;
        std::string command;
        std::getline(inf, timestamp);
        std::getline(inf, command);

        std::cout << "Detected a pending rollback for command \"" << command;
        std::cout << "\" started at " << timestamp << std::endl;

        std::cout << "This may be an error, you may cancel the rollback and ";
        std::cout << "proceed with this run however if the previous run is ";
        std::cout << "still active then it will not be rolled back." << std::endl;

        std::cout << "Cancel previous rollback and start this run? (y/N): " << std::flush;
        char response = std::cin.get();
        if (response != 'y' && response != 'Y') {
            std::cout << "Aborting run!" << std::endl;
            return;
        }
    }

    auto t = std::time(nullptr);
    auto tm = *std::localtime(&t);
    std::ofstream outf(filename);
    outf << std::put_time(&tm, "%Y-%m-%d %H-%M-%S") << std::endl;
    outf << change_command << std::endl;
}

void delete_file() {
    std::remove(filename.c_str());
}

bool file_exists() {
    std::ifstream f(filename);
    return f.good();
}
<commit_msg>Tweaked comments<commit_after>#include <iostream>
#include <fstream>
#include <boost/program_options.hpp>
#include <iomanip>

std::string filename = "/tmp/pending-rollback.rewind";

namespace po = boost::program_options;

void run(char change_command[], char rollback_command[], int timeout);
void keep();
void print_usage(char *argv[], po::options_description desc);
void create_file(char change_command[]);
bool file_exists();
void delete_file();

int main(int argc, char *argv[]) {
    int timeout = 30;

    po::options_description desc("Allowed options");
    desc.add_options()("timeout,t", po::value<int>(&timeout)->default_value(timeout),
            "Timeout before rollback command is executed");
    po::variables_map vm;
    try {
        po::store(po::command_line_parser(argc, argv).options(desc).run(), vm);
    } catch (po::unknown_option e) {
        std::cout << "Unknown option" << std::endl;
        print_usage(argv, desc);
        return 0;
    } catch (po::invalid_option_value e) {
        std::cout << "Invalid value for option" << std::endl;
        print_usage(argv, desc);
        return 0;
    }
    po::notify(vm);

    if (argc < 2) {
        std::cout << "You must supply an action to be performed" << std::endl;
        print_usage(argv, desc);
        return 0;
    }

    std::string mode(argv[1]);

    if (mode == "run") {
        char *change_command = argv[2];
        char *rollback_command = argv[3];
        if (argc < 4 || strlen(change_command) == 0 || strlen(rollback_command) == 0) {
            std::cout << "Must provide both a change command and a rollback command" << std::endl;
            print_usage(argv, desc);
            return 1;
        }

        if (timeout < 1) {
            std::cout << "Timeout must be at least 1" << std::endl;
            print_usage(argv, desc);
            return 1;
        }

        run(change_command, rollback_command, timeout);
    } else if(mode == "keep") {
        keep();
    } else {
        print_usage(argv, desc);
    }

    return 0;
}

void print_usage(char *argv[], po::options_description desc) {
    std::cout << "Usage:" << std::endl;
    std::cout << "  Run a new command:\t" << argv[0] << " run <change command> <rollback command> [options]" << std::endl;
    std::cout << "  Stop rollback:\t" << argv[0] << " keep" << std::endl;
    std::cout << desc << std::endl;
}

void run(char change_command[], char rollback_command[], int timeout) {
    create_file(change_command);
    system(change_command);
    daemon(1, 0); // Do not change CWD, redirect output to /dev/null
    sleep(timeout);

    if (file_exists()) {
        system(rollback_command);
        delete_file();
    }
}

void keep() {
    delete_file();
    std::cout << "Rollback aborted, changes will be kept!" << std::endl;
}

void create_file(char change_command[]) {
    std::ifstream inf(filename);
    if (inf.good()) {
        std::string timestamp;
        std::string command;
        std::getline(inf, timestamp);
        std::getline(inf, command);

        std::cout << "Detected a pending rollback for command \"" << command;
        std::cout << "\" started at " << timestamp << std::endl;

        std::cout << "This may be an error, you may cancel the rollback and ";
        std::cout << "proceed with this run however if the previous run is ";
        std::cout << "still active then it will not be rolled back." << std::endl;

        std::cout << "Cancel previous rollback and start this run? (y/N): " << std::flush;
        char response = std::cin.get();
        if (response != 'y' && response != 'Y') {
            std::cout << "Aborting run!" << std::endl;
            return;
        }
    }

    auto t = std::time(nullptr);
    auto tm = *std::localtime(&t);
    std::ofstream outf(filename);
    outf << std::put_time(&tm, "%Y-%m-%d %H-%M-%S") << std::endl;
    outf << change_command << std::endl;
}

void delete_file() {
    std::remove(filename.c_str());
}

bool file_exists() {
    std::ifstream f(filename);
    return f.good();
}
<|endoftext|>


<commit_before>#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <cstdio>
#include <cassert>
#include "ring.hpp"
#include <stdint.h>
#include <QFile>

#define DEFAULTBUFFERSIZE 1024
#define DEFAULTMUTATIONINTERVAL 16

int main(int argc, char* argv[])
{
	char inputFile[256+1];
	char outputFile[256+1];
	char key[MAPSIZE+1];
	char salt[IVSIZE];
	char mutationInterval[4+1];
	char buffer[6+1];
	char keyFile[256+1];
	bool inputSet = false;
	bool outputSet = false;
	bool keySet = false;
	bool encode = false;
	bool decode = false;
	bool mutationIntervalSet = false;
	bool bufferSet = false;
	bool keyFileSet = false;
	bool verbose = false;
	bool removeSet = false;
	for (int i=0; i<argc; i++)//collect arguments from cmdline
	{
		if (strcmp(argv[i], "-in") == 0 || strcmp(argv[i], "-i") == 0)
		{
			i++;
			if (i < argc)
			{
				if (strlen(argv[i]) <= 256)
				{
					strcpy(inputFile, argv[i]);
					inputSet = true;
				}
			}
			continue;
		}
		if (strcmp(argv[i], "-out") == 0 || strcmp(argv[i], "-o") == 0)
		{
			i++;
			if (i < argc)
			{
				if (strlen(argv[i]) <= 256)
				{
					strcpy(outputFile, argv[i]);
					outputSet = true;
				}
			}
			continue;
		}
		if (strcmp(argv[i], "-password") == 0 || strcmp(argv[i], "-p") == 0)
		{
			i++;
			if (i < argc)
			{
				if (strlen(argv[i]) <= 256)
				{
					strcpy(key, argv[i]);
					keySet = true;
				}
			}
			continue;
		}
		if (strcmp(argv[i], "-key") == 0 || strcmp(argv[i], "-k") == 0)
		{
			i++;
			if (i < argc)
			{
				if (strlen(argv[i]) <= 256)
				{
					strcpy(keyFile, argv[i]);
					keyFileSet = true;
				}
			}
			continue;
		}
		if (strcmp(argv[i], "-encode") == 0 || strcmp(argv[i], "-e") == 0)
		{
			encode = true;
			continue;
		}
		if (strcmp(argv[i], "-decode") == 0 || strcmp(argv[i], "-d") == 0)
		{
			decode = true;
			continue;
		}
		if (strcmp(argv[i], "-verbose") == 0 || strcmp(argv[i], "-v") == 0)
		{
			verbose = true;
			continue;
		}
		if (strcmp(argv[i], "-remove") == 0 || strcmp(argv[i], "-r") == 0)
		{
			removeSet = true;
			continue;
		}
		if (strcmp(argv[i], "-mutation") == 0 || strcmp(argv[i], "-m") == 0)
		{
			i++;
			if (i < argc)
			{
				if (strlen(argv[i]) <= 4)
				{
					strcpy(mutationInterval, argv[i]);
					mutationIntervalSet = true;
				}
			}
			continue;
		}
		if (strcmp(argv[i], "-buffer") == 0 || strcmp(argv[i], "-b") == 0)
		{
			i++;
			if (i < argc)
			{
				if (strlen(argv[i]) <= 6)
				{
					strcpy(buffer, argv[i]);
					bufferSet = true;
				}
			}
			continue;
		}
		if (strcmp(argv[i], "-help") == 0 || strcmp(argv[i], "-h") == 0)
		{
			printf("%s [-e|-d] [-i <inputfile>] [-o <outputfile>] [-p <password> | -k <keyfile>] [-m <mutationInterval>] [-b <buffersize>] [-v] [-r] [-h]\n", argv[0]);
			printf("\n");
			printf("Encodes or decodes a single file.\n");
			printf("\n");
			printf("-e\n");
			printf("-encode\n");
			printf("\tdefault\n");
			printf("\toptional\n");
			printf("\tSpecifies the mode as \"encode\".\n");
			printf("\n");
			printf("-d\n");
			printf("-decode\n");
			printf("\toptional\n");
			printf("\tSpecifies the mode as \"decode\".\n");
			printf("\n");
			printf("-i <inputfile>\n");
			printf("-in <inputfile>\n");
			printf("\tmust\n");
			printf("\tSpecifies the inputfile.\n");
			printf("\n");
			printf("-o <outputfile>\n");
			printf("-out <outputfile>\n");
			printf("\tmust\n");
			printf("\tSpecifies the outputfile.\n");
			printf("\n");
			printf("-p <password>\n");
			printf("-password <password>\n");
			printf("\tmust\n");
			printf("\tSpecifies the password.\n");
			printf("\n");
			printf("-k <keyfile>\n");
			printf("-key <keyfile>\n");
			printf("\toptional (alternative for -p)\n");
			printf("\tSpecifies a keyfile.\n");
			printf("\n");
			printf("-m <mutationInterval>\n");
			printf("-mutation <mutationInterval>\n");
			printf("\tdefault: %u\n", DEFAULTMUTATIONINTERVAL);
			printf("\toptional\n");
			printf("\tSpecifies the mutationInterval.\n");
			printf("\n");
			printf("-b <buffersize>\n");
			printf("-buffer <buffersize>\n");
			printf("\tdefault: %u\n", DEFAULTBUFFERSIZE);
			printf("\toptional\n");
			printf("\tSpecifies the buffersize.\n");
			printf("\n");
			printf("-v\n");
			printf("-verbose\n");
			printf("\toptional\n");
			printf("\tMakes the program verbose.\n");
			printf("\n");
			printf("-r\n");
			printf("-remove\n");
			printf("\toptional\n");
			printf("\tRemoves the inputfile after reading.\n");
			printf("\n");
			printf("-h\n");
			printf("-help\n");
			printf("\toptional\n");
			printf("\tPrints this helpmessage and quits the program.\n");
			return 0;
		}
	}

	//evaluate arguments
	if (!inputSet)
	{
		printf("You need to specify an inputfile!\n");
		return -EINVAL;
	}
	if (keySet && keyFileSet)
	{
		printf("You shall not specify a password and a keyfile!\n");
		return -EINVAL;
	}
	if (!keySet && !keyFileSet)
	{
		printf("You need to specify a password or a keyfile!\n");
		return -EINVAL;
	}
	if (encode && decode)
	{
		printf("You may only specify one mode!\n");
		return -EINVAL;
	}
	if (keyFileSet)
	{
		QFile in(keyFile);
		if (!in.open(QIODevice::ReadOnly))
		{
			printf("ERROR: can not open keyfile\n");
			errno = EIO;
			return -errno;
		}
		unsigned int fileSize = in.size();
		if (fileSize > MAPSIZE)
		{
			printf("ERROR: keyfile is to large to contain a single key -> invalid\n");
			in.close();
			errno = EMSGSIZE;
			return -EMSGSIZE;
		}
		if (in.read((char*)(&key), fileSize) != fileSize)
		{
			in.close();
			errno = EIO;
			return -EIO;
		}
		key[fileSize] = '\0';
		in.close();
		printf("Password read from keyfile.\n");
	}
	if (!encode && !decode)
	{
		encode = true;
		printf("No mode specified... using \"encodemode\".\n");
	}
	if (!outputSet)
	{
		strcpy(outputFile, inputFile);
		if (encode)
		{
			strcat(outputFile, ".enc");
		}
		else
		{
			strcat(outputFile, ".dec");
		}
		printf("No outputfile specified... using \"%s\".\n", outputFile);
	}
	if (!mutationIntervalSet && encode)
	{
		sprintf(mutationInterval, "%u", DEFAULTMUTATIONINTERVAL);
		printf("No mutationInterval specified... using \"%s\".\n", mutationInterval);
	}
	if (!bufferSet)
	{
		sprintf(buffer, "%u", DEFAULTBUFFERSIZE);
		printf("No buffersize specified... using \"%s\".\n", buffer);
	}

	//setup
	if (encode)
	{
		QFile in("/dev/urandom");
		if (!in.open(QIODevice::ReadOnly))
		{
			printf("ERROR: can not open \"/dev/urandom\"\n");
			errno = EIO;
			return errno;
		}
		if (in.read((char*)(&salt), IVSIZE) != IVSIZE)
		{
			in.close();
			errno = EIO;
			return -EIO;
		}
		in.close();
		printf("Salt generated\n");
	}
	unsigned int bufferInt = atoi(buffer);
	unsigned int mutationIntervalInt;
	QFile in(inputFile);
	if (!in.open(QIODevice::ReadOnly))
	{
		printf("ERROR: can not open inputfile\n");
		errno = EIO;
		return -errno;
	}
	QFile out(outputFile);
	if (!in.open(QIODevice::WriteOnly))
	{
		printf("ERROR: can not open outputfile\n");
		in.close();
		errno = EIO;
		return errno;
	}
	unsigned int fileSize = in.size();
	if (encode)
	{
		mutationIntervalInt = atoi(mutationInterval);
		uint32_t mutationInterval32 = mutationIntervalInt;
		if (fwrite(&mutationInterval32, 1, sizeof(mutationInterval32), out) != sizeof(mutationInterval32))
		{
			fclose(in);
			fclose(out);
			errno = EIO;
			return -EIO;
		}
		if (fwrite(&salt, 1, IVSIZE, out) != IVSIZE)
		{
			fclose(in);
			fclose(out);
			errno = EIO;
			return -EIO;
		}
		printf("Salt saved\n");
	}
	else
	{
		uint32_t mutationInterval32;
		if (fread(&mutationInterval32, 1, sizeof(mutationInterval32), in) != sizeof(mutationInterval32))
		{
			in.close();
			out.close();
			errno = EIO;
			return -EIO;
		}
		mutationIntervalInt = mutationInterval32;
		fileSize -= sizeof(mutationInterval32);
		printf("Mutationinterval loaded\n");
		if (fread(&salt, 1, IVSIZE, in) != IVSIZE)
		{
			in.close();
			out.close();
			errno = EIO;
			return -EIO;
		}
		fileSize -= IVSIZE;
		printf("Salt loaded\n");
	}
	Ring ring((const unsigned char*)key, strlen(key), (const unsigned char*)salt, IVSIZE, mutationIntervalInt);
	unsigned int readBytes = 0;
	char buf[bufferInt];
	char verboseMessage[1+8+1+6+1];

	//encode/decode
	while (readBytes < fileSize)
	{
		if (verbose)//print
		{
			float progress = (100.0*readBytes)/fileSize;
			if (encode)
			{
				sprintf(verboseMessage, "\rencoding %.1f%%", progress);
			}
			else
			{
				sprintf(verboseMessage, "\rdecoding %.1f%%", progress);
			}
			printf("%s", verboseMessage);
		}
		//read
		unsigned int bytesToRead = bufferInt;
		if (readBytes+bytesToRead > fileSize)
		{
			bytesToRead = fileSize - readBytes;
		}
		unsigned int readRet = fread(&buf, 1, bytesToRead, in);
		readBytes += readRet;
#ifndef NDEBUG
		assert(readRet == bytesToRead);
#endif
		if (encode)
		{
			ring.encode((unsigned char*)buf, readRet);
		}
		else
		{
			ring.decode((unsigned char*)buf, readRet);
		}
		//write
		unsigned int writtenBytes = 0;
		while (writtenBytes < readRet)
		{
			unsigned int writeRet = fwrite((&buf)+writtenBytes, 1, readRet, out);
			writtenBytes += writeRet;
		}
	}

	//finishing
	if (verbose)
	{
		if (encode)
		{
			sprintf(verboseMessage, "\rencoding %.1f%%", 100.0);
		}
		else
		{
			sprintf(verboseMessage, "\rdecoding %.1f%%", 100.0);
		}
		printf("%s\n", verboseMessage);
	}
	in.close();
	out.close();
	if (removeSet)
	{
		if (remove(inputFile))
		{
			perror("WARNING: could not delete inputfile");
		}
		else
		{
			printf("Inputfile deleted\n");
		}
	}
	printf("done\n");
	return 0;
}
<commit_msg>ported to qt, untested<commit_after>#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <cstdio>
#include <cassert>
#include "ring.hpp"
#include <stdint.h>
#include <QFile>

#define DEFAULTBUFFERSIZE 1024
#define DEFAULTMUTATIONINTERVAL 16

int main(int argc, char* argv[])
{
	char inputFile[256+1];
	char outputFile[256+1];
	char key[MAPSIZE+1];
	char salt[IVSIZE];
	char mutationInterval[4+1];
	char buffer[6+1];
	char keyFile[256+1];
	bool inputSet = false;
	bool outputSet = false;
	bool keySet = false;
	bool encode = false;
	bool decode = false;
	bool mutationIntervalSet = false;
	bool bufferSet = false;
	bool keyFileSet = false;
	bool verbose = false;
	bool removeSet = false;
	for (int i=0; i<argc; i++)//collect arguments from cmdline
	{
		if (strcmp(argv[i], "-in") == 0 || strcmp(argv[i], "-i") == 0)
		{
			i++;
			if (i < argc)
			{
				if (strlen(argv[i]) <= 256)
				{
					strcpy(inputFile, argv[i]);
					inputSet = true;
				}
			}
			continue;
		}
		if (strcmp(argv[i], "-out") == 0 || strcmp(argv[i], "-o") == 0)
		{
			i++;
			if (i < argc)
			{
				if (strlen(argv[i]) <= 256)
				{
					strcpy(outputFile, argv[i]);
					outputSet = true;
				}
			}
			continue;
		}
		if (strcmp(argv[i], "-password") == 0 || strcmp(argv[i], "-p") == 0)
		{
			i++;
			if (i < argc)
			{
				if (strlen(argv[i]) <= 256)
				{
					strcpy(key, argv[i]);
					keySet = true;
				}
			}
			continue;
		}
		if (strcmp(argv[i], "-key") == 0 || strcmp(argv[i], "-k") == 0)
		{
			i++;
			if (i < argc)
			{
				if (strlen(argv[i]) <= 256)
				{
					strcpy(keyFile, argv[i]);
					keyFileSet = true;
				}
			}
			continue;
		}
		if (strcmp(argv[i], "-encode") == 0 || strcmp(argv[i], "-e") == 0)
		{
			encode = true;
			continue;
		}
		if (strcmp(argv[i], "-decode") == 0 || strcmp(argv[i], "-d") == 0)
		{
			decode = true;
			continue;
		}
		if (strcmp(argv[i], "-verbose") == 0 || strcmp(argv[i], "-v") == 0)
		{
			verbose = true;
			continue;
		}
		if (strcmp(argv[i], "-remove") == 0 || strcmp(argv[i], "-r") == 0)
		{
			removeSet = true;
			continue;
		}
		if (strcmp(argv[i], "-mutation") == 0 || strcmp(argv[i], "-m") == 0)
		{
			i++;
			if (i < argc)
			{
				if (strlen(argv[i]) <= 4)
				{
					strcpy(mutationInterval, argv[i]);
					mutationIntervalSet = true;
				}
			}
			continue;
		}
		if (strcmp(argv[i], "-buffer") == 0 || strcmp(argv[i], "-b") == 0)
		{
			i++;
			if (i < argc)
			{
				if (strlen(argv[i]) <= 6)
				{
					strcpy(buffer, argv[i]);
					bufferSet = true;
				}
			}
			continue;
		}
		if (strcmp(argv[i], "-help") == 0 || strcmp(argv[i], "-h") == 0)
		{
			printf("%s [-e|-d] [-i <inputfile>] [-o <outputfile>] [-p <password> | -k <keyfile>] [-m <mutationInterval>] [-b <buffersize>] [-v] [-r] [-h]\n", argv[0]);
			printf("\n");
			printf("Encodes or decodes a single file.\n");
			printf("\n");
			printf("-e\n");
			printf("-encode\n");
			printf("\tdefault\n");
			printf("\toptional\n");
			printf("\tSpecifies the mode as \"encode\".\n");
			printf("\n");
			printf("-d\n");
			printf("-decode\n");
			printf("\toptional\n");
			printf("\tSpecifies the mode as \"decode\".\n");
			printf("\n");
			printf("-i <inputfile>\n");
			printf("-in <inputfile>\n");
			printf("\tmust\n");
			printf("\tSpecifies the inputfile.\n");
			printf("\n");
			printf("-o <outputfile>\n");
			printf("-out <outputfile>\n");
			printf("\tmust\n");
			printf("\tSpecifies the outputfile.\n");
			printf("\n");
			printf("-p <password>\n");
			printf("-password <password>\n");
			printf("\tmust\n");
			printf("\tSpecifies the password.\n");
			printf("\n");
			printf("-k <keyfile>\n");
			printf("-key <keyfile>\n");
			printf("\toptional (alternative for -p)\n");
			printf("\tSpecifies a keyfile.\n");
			printf("\n");
			printf("-m <mutationInterval>\n");
			printf("-mutation <mutationInterval>\n");
			printf("\tdefault: %u\n", DEFAULTMUTATIONINTERVAL);
			printf("\toptional\n");
			printf("\tSpecifies the mutationInterval.\n");
			printf("\n");
			printf("-b <buffersize>\n");
			printf("-buffer <buffersize>\n");
			printf("\tdefault: %u\n", DEFAULTBUFFERSIZE);
			printf("\toptional\n");
			printf("\tSpecifies the buffersize.\n");
			printf("\n");
			printf("-v\n");
			printf("-verbose\n");
			printf("\toptional\n");
			printf("\tMakes the program verbose.\n");
			printf("\n");
			printf("-r\n");
			printf("-remove\n");
			printf("\toptional\n");
			printf("\tRemoves the inputfile after reading.\n");
			printf("\n");
			printf("-h\n");
			printf("-help\n");
			printf("\toptional\n");
			printf("\tPrints this helpmessage and quits the program.\n");
			return 0;
		}
	}

	//evaluate arguments
	if (!inputSet)
	{
		printf("You need to specify an inputfile!\n");
		return -EINVAL;
	}
	if (keySet && keyFileSet)
	{
		printf("You shall not specify a password and a keyfile!\n");
		return -EINVAL;
	}
	if (!keySet && !keyFileSet)
	{
		printf("You need to specify a password or a keyfile!\n");
		return -EINVAL;
	}
	if (encode && decode)
	{
		printf("You may only specify one mode!\n");
		return -EINVAL;
	}
	if (keyFileSet)
	{
		QFile in(keyFile);
		if (!in.open(QIODevice::ReadOnly))
		{
			printf("ERROR: can not open keyfile\n");
			errno = EIO;
			return -errno;
		}
		unsigned int fileSize = in.size();
		if (fileSize > MAPSIZE)
		{
			printf("ERROR: keyfile is to large to contain a single key -> invalid\n");
			in.close();
			errno = EMSGSIZE;
			return -EMSGSIZE;
		}
		if (in.read((char*)(&key), fileSize) != fileSize)
		{
			in.close();
			errno = EIO;
			return -EIO;
		}
		key[fileSize] = '\0';
		in.close();
		printf("Password read from keyfile.\n");
	}
	if (!encode && !decode)
	{
		encode = true;
		printf("No mode specified... using \"encodemode\".\n");
	}
	if (!outputSet)
	{
		strcpy(outputFile, inputFile);
		if (encode)
		{
			strcat(outputFile, ".enc");
		}
		else
		{
			strcat(outputFile, ".dec");
		}
		printf("No outputfile specified... using \"%s\".\n", outputFile);
	}
	if (!mutationIntervalSet && encode)
	{
		sprintf(mutationInterval, "%u", DEFAULTMUTATIONINTERVAL);
		printf("No mutationInterval specified... using \"%s\".\n", mutationInterval);
	}
	if (!bufferSet)
	{
		sprintf(buffer, "%u", DEFAULTBUFFERSIZE);
		printf("No buffersize specified... using \"%s\".\n", buffer);
	}

	//setup
	if (encode)
	{
		QFile in("/dev/urandom");
		if (!in.open(QIODevice::ReadOnly))
		{
			printf("ERROR: can not open \"/dev/urandom\"\n");
			errno = EIO;
			return errno;
		}
		if (in.read((char*)(&salt), IVSIZE) != IVSIZE)
		{
			in.close();
			errno = EIO;
			return -EIO;
		}
		in.close();
		printf("Salt generated\n");
	}
	unsigned int bufferInt = atoi(buffer);
	unsigned int mutationIntervalInt;
	QFile in(inputFile);
	if (!in.open(QIODevice::ReadOnly))
	{
		printf("ERROR: can not open inputfile\n");
		errno = EIO;
		return -errno;
	}
	QFile out(outputFile);
	if (!in.open(QIODevice::WriteOnly))
	{
		printf("ERROR: can not open outputfile\n");
		in.close();
		errno = EIO;
		return errno;
	}
	unsigned int fileSize = in.size();
	if (encode)
	{
		mutationIntervalInt = atoi(mutationInterval);
		uint32_t mutationInterval32 = mutationIntervalInt;
		if (out.write((const char*)(&mutationInterval32), sizeof(mutationInterval32)) != sizeof(mutationInterval32))
		{
			in.close();
			out.close();
			errno = EIO;
			return -EIO;
		}
		if (out.write((const char*)(&salt), IVSIZE) != IVSIZE)
		{
			in.close();
			out.close();
			errno = EIO;
			return -EIO;
		}
		printf("Salt saved\n");
	}
	else
	{
		uint32_t mutationInterval32;
		if (in.read((char*)(&mutationInterval32), sizeof(mutationInterval32)) != sizeof(mutationInterval32))
		{
			in.close();
			out.close();
			errno = EIO;
			return -EIO;
		}
		mutationIntervalInt = mutationInterval32;
		fileSize -= sizeof(mutationInterval32);
		printf("Mutationinterval loaded\n");
		if (in.read((char*)(&salt), IVSIZE) != IVSIZE)
		{
			in.close();
			out.close();
			errno = EIO;
			return -EIO;
		}
		fileSize -= IVSIZE;
		printf("Salt loaded\n");
	}
	Ring ring((const unsigned char*)key, strlen(key), (const unsigned char*)salt, IVSIZE, mutationIntervalInt);
	unsigned int readBytes = 0;
	char buf[bufferInt];
	char verboseMessage[1+8+1+6+1];

	//encode/decode
	while (readBytes < fileSize)
	{
		if (verbose)//print
		{
			float progress = (100.0*readBytes)/fileSize;
			if (encode)
			{
				sprintf(verboseMessage, "\rencoding %.1f%%", progress);
			}
			else
			{
				sprintf(verboseMessage, "\rdecoding %.1f%%", progress);
			}
			printf("%s", verboseMessage);
		}
		//read
		unsigned int bytesToRead = bufferInt;
		if (readBytes+bytesToRead > fileSize)
		{
			bytesToRead = fileSize - readBytes;
		}
		unsigned int readRet = in.read((char*)(&buf), bytesToRead);
		readBytes += readRet;
#ifndef NDEBUG
		assert(readRet == bytesToRead);
#endif
		if (encode)
		{
			ring.encode((unsigned char*)buf, readRet);
		}
		else
		{
			ring.decode((unsigned char*)buf, readRet);
		}
		//write
		unsigned int writtenBytes = 0;
		while (writtenBytes < readRet)
		{
			unsigned int writeRet = out.write((const char*)((&buf)+writtenBytes), readRet);
			writtenBytes += writeRet;
		}
	}

	//finishing
	if (verbose)
	{
		if (encode)
		{
			sprintf(verboseMessage, "\rencoding %.1f%%", 100.0);
		}
		else
		{
			sprintf(verboseMessage, "\rdecoding %.1f%%", 100.0);
		}
		printf("%s\n", verboseMessage);
	}
	in.close();
	out.close();
	if (removeSet)
	{
		if (remove(inputFile))
		{
			perror("WARNING: could not delete inputfile");
		}
		else
		{
			printf("Inputfile deleted\n");
		}
	}
	printf("done\n");
	return 0;
}
<|endoftext|>


<commit_before>//
// Licensed to Green Energy Corp (www.greenenergycorp.com) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  Green Enery Corp licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
//

#include <opendnp3/APL/AsyncTaskBase.h>
#include <opendnp3/APL/AsyncTaskContinuous.h>
#include <opendnp3/APL/AsyncTaskGroup.h>
#include <opendnp3/APL/AsyncTaskInterfaces.h>
#include <opendnp3/APL/AsyncTaskNonPeriodic.h>
#include <opendnp3/APL/AsyncTaskPeriodic.h>
#include <opendnp3/APL/CopyableBuffer.h>
#include <opendnp3/APL/DataInterfaces.h>
#include <opendnp3/APL/ITimerSource.h>
#include <opendnp3/APL/Logger.h>
#include <opendnp3/DNP3/Master.h>
#include <opendnp3/DNP3/MasterStates.h>
#include <opendnp3/DNP3/ObjectReadIterator.h>
#include <opendnp3/DNP3/ResponseLoader.h>
#include <opendnp3/DNP3/VtoEventBufferAdapter.h>

#include <boost/bind.hpp>
#include <boost/foreach.hpp>

using namespace boost;

namespace apl
{
namespace dnp
{

Master::Master(Logger* apLogger, MasterConfig aCfg, IAppLayer* apAppLayer, IDataObserver* apPublisher, AsyncTaskGroup* apTaskGroup, ITimerSource* apTimerSrc, ITimeSource* apTimeSrc) :
	Loggable(apLogger),
	mAllowTimeSync(aCfg.AllowTimeSync),
	mVtoReader(apLogger),
	mVtoWriter(apLogger->GetSubLogger("VtoWriter"), aCfg.VtoWriterQueueSize),
	mRequest(aCfg.FragSize),
	mpAppLayer(apAppLayer),
	mpPublisher(apPublisher),
	mpTaskGroup(apTaskGroup),
	mpTimerSrc(apTimerSrc),
	mpTimeSrc(apTimeSrc),
	mpState(AMS_Closed::Inst()),
	mpTask(NULL),
	mpScheduledTask(NULL),
	mpObserver(aCfg.mpObserver),
	mState(SS_UNKNOWN),
	mSchedule(apTaskGroup, this, aCfg),
	mClassPoll(apLogger, apPublisher, &mVtoReader),
	mClearRestart(apLogger),
	mConfigureUnsol(apLogger),
	mTimeSync(apLogger, apTimeSrc),
	mExecuteBO(apLogger),
	mExecuteSP(apLogger),
	mVtoTransmitTask(apLogger, aCfg.FragSize, aCfg.UseNonStandardVtoFunction)
{
	/*
	 * Establish a link between the mCommandQueue and the
	 * mSchedule.mpCommandTask.  When new data is written to mCommandQueue,
	 * wake up mpCommandTask to process the data.
	 */
	mCommandQueue.SetNotifier(
	    mNotifierSource.Get(
	        boost::bind(
	            &AsyncTaskBase::Enable,
	            mSchedule.mpCommandTask
	        ),
	        mpTimerSrc
	    )
	);

	/*
	 * Establish a link between the mVtoWriter and the
	 * mSchedule.mpVtoTransmitTask.  When new data is written to
	 * mVtoWriter, wake up the mSchedule.mpVtoTransmitTask.
	 */
	mVtoWriter.AddObserver(
	    mNotifierSource.Get(
	        boost::bind(
	            &AsyncTaskBase::Enable,
	            mSchedule.mpVtoTransmitTask
	        ),
	        mpTimerSrc
	    )
	);

	/*
	 * Set the initial state of the communication link.
	 */
	this->UpdateState(SS_COMMS_DOWN);
}

void Master::UpdateState(StackStates aState)
{
	if(mState != aState) {
		LOG_BLOCK(LEV_INFO, "StackState: " << ConvertStackStateToString(aState));
		mState = aState;
		if(mpObserver != NULL) mpObserver->OnStateChange(aState);
		if(mState == SS_COMMS_UP) {
			mSchedule.mpVtoTransmitTask->Enable();
		}
	}
}

void Master::ProcessIIN(const IINField& arIIN)
{
	this->UpdateState(SS_COMMS_UP);

	bool check_state = false;

	//The clear IIN task only happens in response to detecting an IIN bit.
	if(arIIN.GetNeedTime() && mAllowTimeSync) {
		LOG_BLOCK(LEV_INFO, "Need time detected");
		mSchedule.mpTimeTask->SilentEnable();
		check_state = true;
	}

	if(mLastIIN.GetDeviceTrouble()) LOG_BLOCK(LEV_WARNING, "IIN Device trouble detected");

	if(mLastIIN.GetEventBufferOverflow()) LOG_BLOCK(LEV_WARNING, "Event buffer overflow detected");

	// If this is detected, we need to reset the startup tasks
	if(mLastIIN.GetDeviceRestart()) {
		LOG_BLOCK(LEV_WARNING, "Device restart detected");
		mSchedule.ResetStartupTasks();
		mSchedule.mpClearRestartTask->SilentEnable();
		check_state = true;
	}

	if(check_state) mpTaskGroup->CheckState();
}

void Master::ProcessCommand(ITask* apTask)
{
	CommandData info;

	if(mpState == AMS_Closed::Inst()) { //we're closed
		if(!mCommandQueue.RespondToCommand(CS_HARDWARE_ERROR)) apTask->Disable();
	}
	else {

		switch(mCommandQueue.Next()) {
		case(apl::CT_BINARY_OUTPUT): {
				apl::BinaryOutput cmd;
				mCommandQueue.Read(cmd, info);
				mExecuteBO.Set(cmd, info, true);
				mpState->StartTask(this, apTask, &mExecuteBO);
			}
			break;
		case(apl::CT_SETPOINT): {
				apl::Setpoint cmd;
				mCommandQueue.Read(cmd, info);
				mExecuteSP.Set(cmd, info, true);
				mpState->StartTask(this, apTask, &mExecuteSP);
			}
			break;
		default:
			apTask->Disable(); //no commands to be read
			break;
		}
	}
}

void Master::StartTask(MasterTaskBase* apMasterTask, bool aInit)
{
	if(aInit) apMasterTask->Init();
	apMasterTask->ConfigureRequest(mRequest);
	mpAppLayer->SendRequest(mRequest);
}

/* Tasks */

void Master::SyncTime(ITask* apTask)
{
	if(mLastIIN.GetNeedTime() && mAllowTimeSync) {
		mpState->StartTask(this, apTask, &mTimeSync);
	}
	else apTask->Disable();
}

void Master::WriteIIN(ITask* apTask)
{
	if(mLastIIN.GetDeviceRestart()) {
		mpState->StartTask(this, apTask, &mClearRestart);
	}
	else apTask->Disable();
}

void Master::IntegrityPoll(ITask* apTask)
{
	mClassPoll.Set(PC_CLASS_0);
	mpState->StartTask(this, apTask, &mClassPoll);
}

void Master::EventPoll(ITask* apTask, int aClassMask)
{
	mClassPoll.Set(aClassMask);
	mpState->StartTask(this, apTask, &mClassPoll);
}

void Master::ChangeUnsol(ITask* apTask, bool aEnable, int aClassMask)
{
	mConfigureUnsol.Set(aEnable, aClassMask);
	mpState->StartTask(this, apTask, &mConfigureUnsol);
}

void Master::TransmitVtoData(ITask* apTask)
{
	if(mpState == AMS_Closed::Inst()) apTask->Disable();
	else {
		size_t max = mVtoTransmitTask.mBuffer.NumAvailable();
		VtoEventBufferAdapter adapter(&mVtoTransmitTask.mBuffer);
		mVtoWriter.Flush(&adapter, max);

		LOG_BLOCK(LEV_DEBUG, "TransmitVtoData: " << std::boolalpha << mVtoTransmitTask.mBuffer.IsFull() << " size: " << mVtoTransmitTask.mBuffer.Size());

		/* Any data to transmit? */
		if (mVtoTransmitTask.mBuffer.Size() > 0) {
			/* Start the mVtoTransmitTask */
			mpState->StartTask(this, apTask, &mVtoTransmitTask);
		}
		else {
			/* Stop the mVtoTransmitTask */
			apTask->Disable();
		}
	}
}

/* Implement IAppUser */

void Master::OnLowerLayerUp()
{
	mpState->OnLowerLayerUp(this);
	mSchedule.EnableOnlineTasks();
}

void Master::OnLowerLayerDown()
{
    mpState->OnLowerLayerDown(this);
    this->UpdateState(SS_COMMS_DOWN);
    mSchedule.DisableOnlineTasks();
}

void Master::OnSolSendSuccess()
{
	mpState->OnSendSuccess(this);
}

void Master::OnSolFailure()
{
	this->UpdateState(SS_COMMS_DOWN);
	mpState->OnFailure(this);
}

void Master::OnUnsolSendSuccess()
{
	throw InvalidStateException(LOCATION, "Master can't send unsol");
}

void Master::OnUnsolFailure()
{
	throw InvalidStateException(LOCATION, "Master can't send unsol");
}

void Master::OnPartialResponse(const APDU& arAPDU)
{
	mLastIIN = arAPDU.GetIIN();
	this->ProcessIIN(mLastIIN);
	mpState->OnPartialResponse(this, arAPDU);
}

void Master::OnFinalResponse(const APDU& arAPDU)
{
	mLastIIN = arAPDU.GetIIN();
	this->ProcessIIN(arAPDU.GetIIN());
	mpState->OnFinalResponse(this, arAPDU);
}

void Master::OnUnsolResponse(const APDU& arAPDU)
{
	mLastIIN = arAPDU.GetIIN();
	this->ProcessIIN(mLastIIN);
	mpState->OnUnsolResponse(this, arAPDU);
}

void Master::ScheduleOnDemandIntegrityPoll(void)
{
    mSchedule.AddOnDemandIntegrityPoll(this);
    return;
}

/* Private functions */

void Master::ProcessDataResponse(const APDU& arResponse)
{
	try {
		ResponseLoader loader(this->mpLogger, this->mpPublisher, this->GetVtoReader());

		for(HeaderReadIterator hdr = arResponse.BeginRead(); !hdr.IsEnd(); ++hdr)
			loader.Process(hdr);
	}
	catch(Exception ex) {
		EXCEPTION_BLOCK(LEV_WARNING, ex)
	}
}

}
} //end ns

/* vim: set ts=4 sw=4: */
<commit_msg>SGW-258-no-command-completion<commit_after>//
// Licensed to Green Energy Corp (www.greenenergycorp.com) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  Green Enery Corp licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
//

#include <opendnp3/APL/AsyncTaskBase.h>
#include <opendnp3/APL/AsyncTaskContinuous.h>
#include <opendnp3/APL/AsyncTaskGroup.h>
#include <opendnp3/APL/AsyncTaskInterfaces.h>
#include <opendnp3/APL/AsyncTaskNonPeriodic.h>
#include <opendnp3/APL/AsyncTaskPeriodic.h>
#include <opendnp3/APL/CopyableBuffer.h>
#include <opendnp3/APL/DataInterfaces.h>
#include <opendnp3/APL/ITimerSource.h>
#include <opendnp3/APL/Logger.h>
#include <opendnp3/DNP3/Master.h>
#include <opendnp3/DNP3/MasterStates.h>
#include <opendnp3/DNP3/ObjectReadIterator.h>
#include <opendnp3/DNP3/ResponseLoader.h>
#include <opendnp3/DNP3/VtoEventBufferAdapter.h>

#include <boost/bind.hpp>
#include <boost/foreach.hpp>

using namespace boost;

namespace apl
{
namespace dnp
{

Master::Master(Logger* apLogger, MasterConfig aCfg, IAppLayer* apAppLayer, IDataObserver* apPublisher, AsyncTaskGroup* apTaskGroup, ITimerSource* apTimerSrc, ITimeSource* apTimeSrc) :
	Loggable(apLogger),
	mAllowTimeSync(aCfg.AllowTimeSync),
	mVtoReader(apLogger),
	mVtoWriter(apLogger->GetSubLogger("VtoWriter"), aCfg.VtoWriterQueueSize),
	mRequest(aCfg.FragSize),
	mpAppLayer(apAppLayer),
	mpPublisher(apPublisher),
	mpTaskGroup(apTaskGroup),
	mpTimerSrc(apTimerSrc),
	mpTimeSrc(apTimeSrc),
	mpState(AMS_Closed::Inst()),
	mpTask(NULL),
	mpScheduledTask(NULL),
	mpObserver(aCfg.mpObserver),
	mState(SS_UNKNOWN),
	mSchedule(apTaskGroup, this, aCfg),
	mClassPoll(apLogger, apPublisher, &mVtoReader),
	mClearRestart(apLogger),
	mConfigureUnsol(apLogger),
	mTimeSync(apLogger, apTimeSrc),
	mExecuteBO(apLogger),
	mExecuteSP(apLogger),
	mVtoTransmitTask(apLogger, aCfg.FragSize, aCfg.UseNonStandardVtoFunction)
{
	/*
	 * Establish a link between the mCommandQueue and the
	 * mSchedule.mpCommandTask.  When new data is written to mCommandQueue,
	 * wake up mpCommandTask to process the data.
	 */
	mCommandQueue.SetNotifier(
	    mNotifierSource.Get(
	        boost::bind(
	            &AsyncTaskBase::Enable,
	            mSchedule.mpCommandTask
	        ),
	        mpTimerSrc
	    )
	);

	/*
	 * Establish a link between the mVtoWriter and the
	 * mSchedule.mpVtoTransmitTask.  When new data is written to
	 * mVtoWriter, wake up the mSchedule.mpVtoTransmitTask.
	 */
	mVtoWriter.AddObserver(
	    mNotifierSource.Get(
	        boost::bind(
	            &AsyncTaskBase::Enable,
	            mSchedule.mpVtoTransmitTask
	        ),
	        mpTimerSrc
	    )
	);

	/*
	 * Set the initial state of the communication link.
	 */
	this->UpdateState(SS_COMMS_DOWN);
}

void Master::UpdateState(StackStates aState)
{
	if(mState != aState) {
		LOG_BLOCK(LEV_INFO, "StackState: " << ConvertStackStateToString(aState));
		mState = aState;
		if(mpObserver != NULL) mpObserver->OnStateChange(aState);
		if(mState == SS_COMMS_UP) {
			mSchedule.mpVtoTransmitTask->Enable();
		}
	}
}

void Master::ProcessIIN(const IINField& arIIN)
{
	this->UpdateState(SS_COMMS_UP);

	bool check_state = false;

	//The clear IIN task only happens in response to detecting an IIN bit.
	if(arIIN.GetNeedTime() && mAllowTimeSync) {
		LOG_BLOCK(LEV_INFO, "Need time detected");
		mSchedule.mpTimeTask->SilentEnable();
		check_state = true;
	}

	if(mLastIIN.GetDeviceTrouble()) LOG_BLOCK(LEV_WARNING, "IIN Device trouble detected");

	if(mLastIIN.GetEventBufferOverflow()) LOG_BLOCK(LEV_WARNING, "Event buffer overflow detected");

	// If this is detected, we need to reset the startup tasks
	if(mLastIIN.GetDeviceRestart()) {
		LOG_BLOCK(LEV_WARNING, "Device restart detected");
		mSchedule.ResetStartupTasks();
		mSchedule.mpClearRestartTask->SilentEnable();
		check_state = true;
	}

	if(check_state) mpTaskGroup->CheckState();
}

void Master::ProcessCommand(ITask* apTask)
{
	CommandData info;

	if(mpState == AMS_Closed::Inst()) { //we're closed
		if(!mCommandQueue.RespondToCommand(CS_HARDWARE_ERROR)) {
			apTask->Disable();
		}
		else {
			// We need to set task completion when the stack is closed
			apTask->OnComplete(true);
		}
	}
	else {

		switch(mCommandQueue.Next()) {
		case(apl::CT_BINARY_OUTPUT): {
				apl::BinaryOutput cmd;
				mCommandQueue.Read(cmd, info);
				mExecuteBO.Set(cmd, info, true);
				mpState->StartTask(this, apTask, &mExecuteBO);
			}
			break;
		case(apl::CT_SETPOINT): {
				apl::Setpoint cmd;
				mCommandQueue.Read(cmd, info);
				mExecuteSP.Set(cmd, info, true);
				mpState->StartTask(this, apTask, &mExecuteSP);
			}
			break;
		default:
			apTask->Disable(); //no commands to be read
			break;
		}
	}
}

void Master::StartTask(MasterTaskBase* apMasterTask, bool aInit)
{
	if(aInit) apMasterTask->Init();
	apMasterTask->ConfigureRequest(mRequest);
	mpAppLayer->SendRequest(mRequest);
}

/* Tasks */

void Master::SyncTime(ITask* apTask)
{
	if(mLastIIN.GetNeedTime() && mAllowTimeSync) {
		mpState->StartTask(this, apTask, &mTimeSync);
	}
	else apTask->Disable();
}

void Master::WriteIIN(ITask* apTask)
{
	if(mLastIIN.GetDeviceRestart()) {
		mpState->StartTask(this, apTask, &mClearRestart);
	}
	else apTask->Disable();
}

void Master::IntegrityPoll(ITask* apTask)
{
	mClassPoll.Set(PC_CLASS_0);
	mpState->StartTask(this, apTask, &mClassPoll);
}

void Master::EventPoll(ITask* apTask, int aClassMask)
{
	mClassPoll.Set(aClassMask);
	mpState->StartTask(this, apTask, &mClassPoll);
}

void Master::ChangeUnsol(ITask* apTask, bool aEnable, int aClassMask)
{
	mConfigureUnsol.Set(aEnable, aClassMask);
	mpState->StartTask(this, apTask, &mConfigureUnsol);
}

void Master::TransmitVtoData(ITask* apTask)
{
	if(mpState == AMS_Closed::Inst()) apTask->Disable();
	else {
		size_t max = mVtoTransmitTask.mBuffer.NumAvailable();
		VtoEventBufferAdapter adapter(&mVtoTransmitTask.mBuffer);
		mVtoWriter.Flush(&adapter, max);

		LOG_BLOCK(LEV_DEBUG, "TransmitVtoData: " << std::boolalpha << mVtoTransmitTask.mBuffer.IsFull() << " size: " << mVtoTransmitTask.mBuffer.Size());

		/* Any data to transmit? */
		if (mVtoTransmitTask.mBuffer.Size() > 0) {
			/* Start the mVtoTransmitTask */
			mpState->StartTask(this, apTask, &mVtoTransmitTask);
		}
		else {
			/* Stop the mVtoTransmitTask */
			apTask->Disable();
		}
	}
}

/* Implement IAppUser */

void Master::OnLowerLayerUp()
{
	mpState->OnLowerLayerUp(this);
	mSchedule.EnableOnlineTasks();
}

void Master::OnLowerLayerDown()
{
    mpState->OnLowerLayerDown(this);
    this->UpdateState(SS_COMMS_DOWN);
    mSchedule.DisableOnlineTasks();
}

void Master::OnSolSendSuccess()
{
	mpState->OnSendSuccess(this);
}

void Master::OnSolFailure()
{
	this->UpdateState(SS_COMMS_DOWN);
	mpState->OnFailure(this);
}

void Master::OnUnsolSendSuccess()
{
	throw InvalidStateException(LOCATION, "Master can't send unsol");
}

void Master::OnUnsolFailure()
{
	throw InvalidStateException(LOCATION, "Master can't send unsol");
}

void Master::OnPartialResponse(const APDU& arAPDU)
{
	mLastIIN = arAPDU.GetIIN();
	this->ProcessIIN(mLastIIN);
	mpState->OnPartialResponse(this, arAPDU);
}

void Master::OnFinalResponse(const APDU& arAPDU)
{
	mLastIIN = arAPDU.GetIIN();
	this->ProcessIIN(arAPDU.GetIIN());
	mpState->OnFinalResponse(this, arAPDU);
}

void Master::OnUnsolResponse(const APDU& arAPDU)
{
	mLastIIN = arAPDU.GetIIN();
	this->ProcessIIN(mLastIIN);
	mpState->OnUnsolResponse(this, arAPDU);
}

void Master::ScheduleOnDemandIntegrityPoll(void)
{
    mSchedule.AddOnDemandIntegrityPoll(this);
    return;
}

/* Private functions */

void Master::ProcessDataResponse(const APDU& arResponse)
{
	try {
		ResponseLoader loader(this->mpLogger, this->mpPublisher, this->GetVtoReader());

		for(HeaderReadIterator hdr = arResponse.BeginRead(); !hdr.IsEnd(); ++hdr)
			loader.Process(hdr);
	}
	catch(Exception ex) {
		EXCEPTION_BLOCK(LEV_WARNING, ex)
	}
}

}
} //end ns

/* vim: set ts=4 sw=4: */
<|endoftext|>


<commit_before>#include <string>

std::string pre_rules()
{
	std::string pre;
	pre+="iptables -F\n";
	pre+="iptables -X\n";
	pre+="\n";
	pre+="iptables -P INPUT DROP\n";
	pre+="iptables -P FORWARD DROP\n";
	pre+="iptables -P OUTPUT DROP\n";
	pre+="\n";
	pre+="iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n";
	return pre;
}

std::string gen_rule(const std::string& proto,
	const std::string& l_ip,const std::string& l_mask,const std::string& l_port,
	const std::string& dir,
	const std::string& f_ip,const std::string& f_mask,const std::string& f_port,
	const std::string& action,
	const bool V6)
{

	if(dir=="<>")
	{
		std::string rules;
		rules+=gen_rule(proto,l_ip,l_mask,l_port,"<",f_ip,f_mask,f_port,action,V6);
		rules+="\n";
		rules+=gen_rule(proto,l_ip,l_mask,l_port,">",f_ip,f_mask,f_port,action,V6);
		return rules;
	}

	std::string rule;
	if(V6)
		rule+="ip6tables";
	else
		rule+="iptables";
	rule+=" --append ";
	std::string l_letter="s";
	std::string f_letter="d";
	if(dir=="<")
	{
		rule+="INPUT ";
		std::swap(l_letter,f_letter);
	}
	else
		rule+="OUTPUT";
	rule+=" -p "+proto;
	rule+=" -" +l_letter+" "    +l_ip+"/"+l_mask;

	if(l_port!="0")
		rule+=" --"+l_letter+"port "+l_port;
	rule+=" -" +f_letter+" "    +f_ip+"/"+f_mask;
	if(f_port!="0")
		rule+=" --"+f_letter+"port "+f_port;
	rule+=" --jump ";
	if(action=="deny")
		rule+="DROP";
	else
		rule+="ACCEPT";
	return rule;
}

//iptables --append INPUT  -p tcp -d any --dport 20 -s any --sport any --jump ACCEPT<commit_msg>Removed comment from iptables (which works now...last commit message somehow got overwritten with "mend"...).<commit_after>#include <string>

std::string pre_rules()
{
	std::string pre;
	pre+="iptables -F\n";
	pre+="iptables -X\n";
	pre+="\n";
	pre+="iptables -P INPUT DROP\n";
	pre+="iptables -P FORWARD DROP\n";
	pre+="iptables -P OUTPUT DROP\n";
	pre+="\n";
	pre+="iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n";
	return pre;
}

std::string gen_rule(const std::string& proto,
	const std::string& l_ip,const std::string& l_mask,const std::string& l_port,
	const std::string& dir,
	const std::string& f_ip,const std::string& f_mask,const std::string& f_port,
	const std::string& action,
	const bool V6)
{

	if(dir=="<>")
	{
		std::string rules;
		rules+=gen_rule(proto,l_ip,l_mask,l_port,"<",f_ip,f_mask,f_port,action,V6);
		rules+="\n";
		rules+=gen_rule(proto,l_ip,l_mask,l_port,">",f_ip,f_mask,f_port,action,V6);
		return rules;
	}

	std::string rule;
	if(V6)
		rule+="ip6tables";
	else
		rule+="iptables";
	rule+=" --append ";
	std::string l_letter="s";
	std::string f_letter="d";
	if(dir=="<")
	{
		rule+="INPUT ";
		std::swap(l_letter,f_letter);
	}
	else
		rule+="OUTPUT";
	rule+=" -p "+proto;
	rule+=" -" +l_letter+" "    +l_ip+"/"+l_mask;

	if(l_port!="0")
		rule+=" --"+l_letter+"port "+l_port;
	rule+=" -" +f_letter+" "    +f_ip+"/"+f_mask;
	if(f_port!="0")
		rule+=" --"+f_letter+"port "+f_port;
	rule+=" --jump ";
	if(action=="deny")
		rule+="DROP";
	else
		rule+="ACCEPT";
	return rule;
}<|endoftext|>