<commit_before>#include "stdafx.h"
#include "Rule.h"

#include "Simulation.h"

namespace sim
{

Rule::Rule(json_spirit::Object &data)
{
	weight = 0.0;

	for (json_spirit::Pair &pair : data)
	{
		std::string &key = pair.name_;
		if (key == "scores") setupNeededScores(pair.value_.get_array());
		else if (key == "parameters") setupParameters(pair.value_.get_obj());
		else if (key == "weight") weight = pair.value_.get_real();
		else if (key == "function") setCalculationFunction(pair.value_.get_str());
		else if (key == "backref") isBackrefRule = pair.value_.get_bool();
		else
			std::cerr << "sim::Rule: invalid property \"" << key << "\"" << std::endl;
	}

	if (calculationFunction == &Rule::calc_dummy || calculationFunction == nullptr)
		std::cerr << "Rule without calculation function." << std::endl;

	if (calculationFunction == &Rule::calc_custom_binary)
	{
		if (ruleParameters.count("normalization_constant"))
		{
			customNormalizationConstant = ruleParameters["normalization_constant"];

			if (!std::isnormal(customNormalizationConstant))
			{
				std::cerr << "The normalization constant of the custom rating rule must be a non-zero number!" << std::endl;
				throw "The Simulation was stopped because of invalid rule parameters.";
			}
		}
		else
		{
			std::cerr << "Custom Rating rule needs a normalization constant!" << std::endl;
			throw "The simulation was stopped because of missing rule parameters.";
		}
	}

}

Rule::~Rule()
{

}

void Rule::setupNeededScores(json_spirit::Array &data)
{
	for (json_spirit::Value &val : data)
	{
		neededScores.push_back(val.get_str());
	}
}

void Rule::setupParameters(json_spirit::Object &data)
{
	for (json_spirit::Pair &pair : data)
	{
		std::string &key = pair.name_;
		ruleParameters[key] = pair.value_.get_real();
	}
}

double Rule::getRawResults(Team &left, Team &right, double *weight, double *currentWinExpectancy)
{
	assert((isBackrefRule && currentWinExpectancy != nullptr) || (!isBackrefRule && currentWinExpectancy == nullptr));
	*weight = 1.0;
	return (this->*calculationFunction)(left, right, weight, currentWinExpectancy);
}

void Rule::setCalculationFunction(std::string functionName)
{
	if (functionName == "elo_binary")
		calculationFunction = &Rule::calc_elo_binary;
	else if (functionName == "fifa_binary")
		calculationFunction = &Rule::calc_fifa_binary;
	else if (functionName == "value_binary")
		calculationFunction = &Rule::calc_value_binary;
	else if (functionName == "age_binary")
		calculationFunction = &Rule::calc_age_binary;
	else if (functionName == "homeadvantage_binary")
		calculationFunction = &Rule::calc_homeadvantage_binary;
	else if (functionName == "spi_binary")
		calculationFunction = &Rule::calc_spi_binary;
	else if (functionName == "luck_binary")
		calculationFunction = &Rule::calc_luck_binary;
	else if (functionName == "custom_binary")
		calculationFunction = &Rule::calc_custom_binary;
	else
	{
		std::cerr << "Unknown calculation function: \"" << functionName << "\"" << std::endl;
		calculationFunction = &Rule::calc_dummy;
	}
}

double Rule::calc_elo_binary(Team &left, Team &right, double *weight, double *currentWinExpectancy)
{
	return 1.0 / (1.0 + std::pow(10.0, (right.scores["ELO"] - left.scores["ELO"]) / 400.0));
}

double Rule::calc_fifa_binary(Team &left, Team &right, double *weight, double *currentWinExpectancy)
{
	const double &leftScore = left.scores["FIFA"];
	const double &rightScore = right.scores["FIFA"];
	const double logScore = std::log(leftScore / rightScore);
	const double result = 1.0 / (1.0 + std::exp(-logScore / 0.23725));
	//std::cerr << "left: " << leftScore << "\tright: " << rightScore << "\tlog: " << logScore << "\tresult: " << result << std::endl;
	return result;
}

double Rule::calc_value_binary(Team &left, Team &right, double *weight, double *currentWinExpectancy)
{
	const double &leftScore = left.scores["Value"];
	const double &rightScore = right.scores["Value"];
	const double logScore = std::log(leftScore / rightScore);
	const double result = 1.0 / (1.0 + std::exp(-logScore / 1.3026));
	return result;
}

double Rule::calc_age_binary(Team &left, Team &right, double *weight, double *currentWinExpectancy)
{
	const double &leftScore = left.scores["Age"];
	const double &rightScore = right.scores["Age"];
	const double ageDiff = leftScore - rightScore;
	const double result = 1.0 / (1.0 + std::exp(-(32.0 * ageDiff - ageDiff * ageDiff * ageDiff) / 131.0));
	return result;
}

double Rule::calc_spi_binary(Team &left, Team &right, double *weight, double *currentWinExpectancy)
{
	if (probabilityLookupMatrix.empty())
		generateExpectancyMatrix(&Rule::calculateSPIWinExpectancy);
	return probabilityLookupMatrix[left.index][right.index];
}

double Rule::calc_homeadvantage_binary(Team &left, Team &right, double *weight, double *currentWinExpectancy)
{
	const double &homeLeft = left.scores["HA"];
	const double &homeRight = right.scores["HA"];
	// this rule is only effective if at least one of the teams has a home-advantage assigned
	*weight = homeLeft / (homeLeft + homeRight);
	assert(((homeLeft + homeRight) == 0.0) || (*weight >= 0.0 && *weight <= 1.0));
	// if not, the weight will be 0 anyway..
	if (homeLeft == 0.0) return *currentWinExpectancy;

	return 2.0 /
		(1.0 + std::exp(-4.0 * (*currentWinExpectancy))) - 1.0;
}

double Rule::calc_custom_binary(Team &left, Team &right, double *weight, double *currentWinExpectancy)
{
	return 1.0 / (1.0 + std::exp((right.scores["Custom"] - left.scores["Custom"]) / customNormalizationConstant));
}

void Rule::generateExpectancyMatrix(double (*fun)(Team&, Team&))
{
	assert(probabilityLookupMatrix.empty());
	size_t teamCount = Simulation::singleton->teams.size();

	probabilityLookupMatrix.resize(teamCount);
	for (size_t i = 0; i < teamCount; ++i)
		probabilityLookupMatrix[i].resize(teamCount);

	for (Team &left : Simulation::singleton->teams)
	{
		for (Team &right : Simulation::singleton->teams)
		{
			double prob_left = fun(left, right);
			double prob_right = fun(right, left);
			probabilityLookupMatrix[left.index][right.index] = prob_left;
			probabilityLookupMatrix[right.index][left.index] = prob_right;
		}
	}

	std::cerr << "Matrix is go\nI1\tI2\tP\t" << std::endl;
	for (size_t i = 0; i < teamCount; ++i)
		std::cerr << Simulation::singleton->teams[i].id << "\t";
	std::cerr << std::endl;
	for (size_t i = 0; i < teamCount; ++i)
	{
		for (size_t c = 0; c < teamCount; ++c)
			std::cerr << probabilityLookupMatrix[i][c] << "\t";
		std::cerr << std::endl;
	}
}

double Rule::calculateSPIWinExpectancy(Team &left, Team &right)
{
	const double &off1 = left.scores["SPI Off"];
	const double &off2 = right.scores["SPI Off"];
	const double &def1 = left.scores["SPI Def"];
	const double &def2 = right.scores["SPI Def"];

	const double combined_off = (off1 + def2) / 2.0;
	const double combined_def = (def1 + off2) / 2.0;

	std::function<int(int)> factorial =
		[&](int n)
	{
		return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n;
	};
	auto poisson_probability =
		[&](double lambda, int times)
	{
		return std::exp(-lambda) * std::pow(lambda, (double)times) / (double)factorial(times);
	};

	double prob_off(0.0), prob_def(0.0);

	for (int i = 0; i < 20; ++i)
	{
		const double equal_prob_off = poisson_probability(combined_off, i);
		const double equal_prob_def = poisson_probability(combined_def, i);

		double less_prob_off(0.0), less_prob_def(0.0);
		for (int c = 0; c < i; ++c)
		{
			less_prob_off += poisson_probability(combined_off, c);
			less_prob_def += poisson_probability(combined_def, c);
		}

		prob_off += equal_prob_off * less_prob_def;
		prob_def += equal_prob_def * less_prob_off;
	}
	return (prob_off / (prob_off + prob_def));
}

} // namespace sim<commit_msg>simulation: made home-advantages of below 1 actually reduce the weight of the rule<commit_after>#include "stdafx.h"
#include "Rule.h"

#include "Simulation.h"

namespace sim
{

Rule::Rule(json_spirit::Object &data)
{
	weight = 0.0;

	for (json_spirit::Pair &pair : data)
	{
		std::string &key = pair.name_;
		if (key == "scores") setupNeededScores(pair.value_.get_array());
		else if (key == "parameters") setupParameters(pair.value_.get_obj());
		else if (key == "weight") weight = pair.value_.get_real();
		else if (key == "function") setCalculationFunction(pair.value_.get_str());
		else if (key == "backref") isBackrefRule = pair.value_.get_bool();
		else
			std::cerr << "sim::Rule: invalid property \"" << key << "\"" << std::endl;
	}

	if (calculationFunction == &Rule::calc_dummy || calculationFunction == nullptr)
		std::cerr << "Rule without calculation function." << std::endl;

	if (calculationFunction == &Rule::calc_custom_binary)
	{
		if (ruleParameters.count("normalization_constant"))
		{
			customNormalizationConstant = ruleParameters["normalization_constant"];

			if (!std::isnormal(customNormalizationConstant))
			{
				std::cerr << "The normalization constant of the custom rating rule must be a non-zero number!" << std::endl;
				throw "The Simulation was stopped because of invalid rule parameters.";
			}
		}
		else
		{
			std::cerr << "Custom Rating rule needs a normalization constant!" << std::endl;
			throw "The simulation was stopped because of missing rule parameters.";
		}
	}

}

Rule::~Rule()
{

}

void Rule::setupNeededScores(json_spirit::Array &data)
{
	for (json_spirit::Value &val : data)
	{
		neededScores.push_back(val.get_str());
	}
}

void Rule::setupParameters(json_spirit::Object &data)
{
	for (json_spirit::Pair &pair : data)
	{
		std::string &key = pair.name_;
		ruleParameters[key] = pair.value_.get_real();
	}
}

double Rule::getRawResults(Team &left, Team &right, double *weight, double *currentWinExpectancy)
{
	assert((isBackrefRule && currentWinExpectancy != nullptr) || (!isBackrefRule && currentWinExpectancy == nullptr));
	*weight = 1.0;
	return (this->*calculationFunction)(left, right, weight, currentWinExpectancy);
}

void Rule::setCalculationFunction(std::string functionName)
{
	if (functionName == "elo_binary")
		calculationFunction = &Rule::calc_elo_binary;
	else if (functionName == "fifa_binary")
		calculationFunction = &Rule::calc_fifa_binary;
	else if (functionName == "value_binary")
		calculationFunction = &Rule::calc_value_binary;
	else if (functionName == "age_binary")
		calculationFunction = &Rule::calc_age_binary;
	else if (functionName == "homeadvantage_binary")
		calculationFunction = &Rule::calc_homeadvantage_binary;
	else if (functionName == "spi_binary")
		calculationFunction = &Rule::calc_spi_binary;
	else if (functionName == "luck_binary")
		calculationFunction = &Rule::calc_luck_binary;
	else if (functionName == "custom_binary")
		calculationFunction = &Rule::calc_custom_binary;
	else
	{
		std::cerr << "Unknown calculation function: \"" << functionName << "\"" << std::endl;
		calculationFunction = &Rule::calc_dummy;
	}
}

double Rule::calc_elo_binary(Team &left, Team &right, double *weight, double *currentWinExpectancy)
{
	return 1.0 / (1.0 + std::pow(10.0, (right.scores["ELO"] - left.scores["ELO"]) / 400.0));
}

double Rule::calc_fifa_binary(Team &left, Team &right, double *weight, double *currentWinExpectancy)
{
	const double &leftScore = left.scores["FIFA"];
	const double &rightScore = right.scores["FIFA"];
	const double logScore = std::log(leftScore / rightScore);
	const double result = 1.0 / (1.0 + std::exp(-logScore / 0.23725));
	//std::cerr << "left: " << leftScore << "\tright: " << rightScore << "\tlog: " << logScore << "\tresult: " << result << std::endl;
	return result;
}

double Rule::calc_value_binary(Team &left, Team &right, double *weight, double *currentWinExpectancy)
{
	const double &leftScore = left.scores["Value"];
	const double &rightScore = right.scores["Value"];
	const double logScore = std::log(leftScore / rightScore);
	const double result = 1.0 / (1.0 + std::exp(-logScore / 1.3026));
	return result;
}

double Rule::calc_age_binary(Team &left, Team &right, double *weight, double *currentWinExpectancy)
{
	const double &leftScore = left.scores["Age"];
	const double &rightScore = right.scores["Age"];
	const double ageDiff = leftScore - rightScore;
	const double result = 1.0 / (1.0 + std::exp(-(32.0 * ageDiff - ageDiff * ageDiff * ageDiff) / 131.0));
	return result;
}

double Rule::calc_spi_binary(Team &left, Team &right, double *weight, double *currentWinExpectancy)
{
	if (probabilityLookupMatrix.empty())
		generateExpectancyMatrix(&Rule::calculateSPIWinExpectancy);
	return probabilityLookupMatrix[left.index][right.index];
}

double Rule::calc_homeadvantage_binary(Team &left, Team &right, double *weight, double *currentWinExpectancy)
{
	const double &homeLeft = left.scores["HA"];
	const double &homeRight = right.scores["HA"];
	// this rule is only effective if at least one of the teams has a home-advantage assigned
	*weight = homeLeft / std::max(1.0, homeLeft + homeRight);
	assert(((homeLeft + homeRight) == 0.0) || (*weight >= 0.0 && *weight <= 1.0));
	// if not, the weight will be 0 anyway..
	if (homeLeft == 0.0) return *currentWinExpectancy;

	return 2.0 /
		(1.0 + std::exp(-4.0 * (*currentWinExpectancy))) - 1.0;
}

double Rule::calc_custom_binary(Team &left, Team &right, double *weight, double *currentWinExpectancy)
{
	return 1.0 / (1.0 + std::exp((right.scores["Custom"] - left.scores["Custom"]) / customNormalizationConstant));
}

void Rule::generateExpectancyMatrix(double (*fun)(Team&, Team&))
{
	assert(probabilityLookupMatrix.empty());
	size_t teamCount = Simulation::singleton->teams.size();

	probabilityLookupMatrix.resize(teamCount);
	for (size_t i = 0; i < teamCount; ++i)
		probabilityLookupMatrix[i].resize(teamCount);

	for (Team &left : Simulation::singleton->teams)
	{
		for (Team &right : Simulation::singleton->teams)
		{
			double prob_left = fun(left, right);
			double prob_right = fun(right, left);
			probabilityLookupMatrix[left.index][right.index] = prob_left;
			probabilityLookupMatrix[right.index][left.index] = prob_right;
		}
	}

	std::cerr << "Matrix is go\nI1\tI2\tP\t" << std::endl;
	for (size_t i = 0; i < teamCount; ++i)
		std::cerr << Simulation::singleton->teams[i].id << "\t";
	std::cerr << std::endl;
	for (size_t i = 0; i < teamCount; ++i)
	{
		for (size_t c = 0; c < teamCount; ++c)
			std::cerr << probabilityLookupMatrix[i][c] << "\t";
		std::cerr << std::endl;
	}
}

double Rule::calculateSPIWinExpectancy(Team &left, Team &right)
{
	const double &off1 = left.scores["SPI Off"];
	const double &off2 = right.scores["SPI Off"];
	const double &def1 = left.scores["SPI Def"];
	const double &def2 = right.scores["SPI Def"];

	const double combined_off = (off1 + def2) / 2.0;
	const double combined_def = (def1 + off2) / 2.0;

	std::function<int(int)> factorial =
		[&](int n)
	{
		return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n;
	};
	auto poisson_probability =
		[&](double lambda, int times)
	{
		return std::exp(-lambda) * std::pow(lambda, (double)times) / (double)factorial(times);
	};

	double prob_off(0.0), prob_def(0.0);

	for (int i = 0; i < 20; ++i)
	{
		const double equal_prob_off = poisson_probability(combined_off, i);
		const double equal_prob_def = poisson_probability(combined_def, i);

		double less_prob_off(0.0), less_prob_def(0.0);
		for (int c = 0; c < i; ++c)
		{
			less_prob_off += poisson_probability(combined_off, c);
			less_prob_def += poisson_probability(combined_def, c);
		}

		prob_off += equal_prob_off * less_prob_def;
		prob_def += equal_prob_def * less_prob_off;
	}
	return (prob_off / (prob_off + prob_def));
}

} // namespace sim<|endoftext|>


<commit_before>#include "bwbot.h"

int main() {
	BWBOT bwbot;
	bwbot.init('t');
	bwbot.testinit();
	bwbot.run();
	bwbot.testprint();
	return 0;
}

void BWBOT::run() {
	int i=0;
	while(!buildOrder.atEnd()&&i<1000) {
		update();
		i++;
	}
}

void BWBOT::update() {
	ActiveUnit currentUnit = buildHandler.update();
	Frame currentFrame = resourceHandler.update(currentUnit);
	if(currentUnit.action == ActionName::Next_Frame)
		if(tryToBuild(buildOrder.getUnit()))
				buildOrder.nextUnit();
	if(currentUnit.timer != -1 && currentUnit.action != ActionName::Next_Frame) {
		currentFrame.miners = buildHandler.getMineralMinerCount();
		currentFrame.gasminers = buildHandler.getGasMinerCount();
		output.push_back(currentFrame);
	}
}

void BWBOT::testinit() {
	buildOrder.push_back(UnitName::Terran_SCV);
	buildOrder.push_back(UnitName::Terran_SCV);
	buildOrder.push_back(UnitName::Terran_SCV);
	//buildOrder.push_back(UnitName::Terran_SCV);
	//buildOrder.push_back(UnitName::Terran_SCV);
	//buildOrder.push_back(UnitName::Terran_Supply_Depot);
	//buildOrder.push_back(UnitName::Terran_SCV);
	//buildOrder.push_back(UnitName::Terran_SCV);
}

void BWBOT::testprint() {
	for(int i=0; i<(int)output.size(); i++) {
		Frame f = output[i];
		printf("%6d %3d %3d ", f.frame, f.minerals, f.gas);
		printf("%3d/%3d ", f.supply, f.supplymax);
		printf("%2d %2d ", f.miners, f.gasminers);
		string uname = "NULL";
		if(f.unit != UnitName::UNIT_NULL)
			uname = unitData.getUnitFromId(f.unit).name;
		printf("%2d %s\n", f.action, uname.c_str());
	}
}

void BWBOT::init(char race) {
	clear();
	if(race=='t') {
		for(int i=0; i<4; i++)
			buildHandler.spawn(UnitName::Terran_SCV);
		buildHandler.spawn(UnitName::Terran_Command_Center);
	}
	if(race=='p') {
		for(int i=0; i<4; i++)
			buildHandler.spawn(UnitName::Protoss_Probe);
		buildHandler.spawn(UnitName::Protoss_Nexus);
	}
	if(race=='z') {
		for(int i=0; i<4; i++)
			buildHandler.spawn(UnitName::Zerg_Drone);
		buildHandler.spawn(UnitName::Zerg_Hatchery);
		buildHandler.spawn(UnitName::Zerg_Overlord);
	}
}

bool BWBOT::tryToBuild(UnitName unitname) {
	if(resourceHandler.canBuild(unitname)) {
		if(buildHandler.canBuild(unitname)) {
			buildHandler.build(unitname);
			return true;
		}
	}
	return false;
}

void BWBOT::clear() {
	buildHandler.clear();
	buildOrder.clear();
	resourceHandler.clear();
	output.clear();
}
<commit_msg>more working... larva still has issues, need to figure out how to pass times as well (maybe just fully update frame every time)<commit_after>#include "bwbot.h"

int main() {
	BWBOT bwbot;
	bwbot.init('t');
	bwbot.testinit();
	bwbot.run();
	bwbot.testprint();
	return 0;
}

void BWBOT::run() {
	int i=0;
	while(!buildOrder.atEnd()&&i<10000) {
		update();
		i++;
	}
}

void BWBOT::update() {
	ActiveUnit currentUnit = buildHandler.update();
	Frame currentFrame = resourceHandler.update(currentUnit);
	if(currentUnit.action == ActionName::Next_Frame)
		if(tryToBuild(buildOrder.getUnit()))
				buildOrder.nextUnit();
	if(currentUnit.action != ActionName::Next_Frame) {
		currentFrame.miners = buildHandler.getMineralMinerCount();
		currentFrame.gasminers = buildHandler.getGasMinerCount();
		output.push_back(currentFrame);
	}
}

void BWBOT::testinit() {
	buildOrder.push_back(UnitName::Terran_SCV);
	buildOrder.push_back(UnitName::Terran_SCV);
	buildOrder.push_back(UnitName::Terran_SCV);
	buildOrder.push_back(UnitName::Terran_SCV);
	buildOrder.push_back(UnitName::Terran_SCV);
	buildOrder.push_back(UnitName::Terran_Supply_Depot);
	buildOrder.push_back(UnitName::Terran_SCV);
	buildOrder.push_back(UnitName::Terran_SCV);
	buildOrder.push_back(UnitName::Terran_Barracks);
	buildOrder.push_back(UnitName::Terran_SCV);
	buildOrder.push_back(UnitName::Terran_Refinery);
	buildOrder.push_back(UnitName::Terran_Command_Center);
}

void BWBOT::testprint() {
	for(int i=0; i<(int)output.size(); i++) {
		Frame f = output[i];
		printf("%6d %3d %3d ", f.frame, f.minerals, f.gas);
		printf("%3d/%3d ", f.supply, f.supplymax);
		printf("%2d %2d ", f.miners, f.gasminers);
		string uname = "NULL";
		if(f.unit != UnitName::UNIT_NULL)
			uname = unitData.getUnitFromId(f.unit).name;
		printf("%2d %s\n", f.action, uname.c_str());
	}
}

void BWBOT::init(char race) {
	clear();
	if(race=='t') {
		for(int i=0; i<4; i++)
			buildHandler.spawn(UnitName::Terran_SCV);
		buildHandler.spawn(UnitName::Terran_Command_Center);
	}
	if(race=='p') {
		for(int i=0; i<4; i++)
			buildHandler.spawn(UnitName::Protoss_Probe);
		buildHandler.spawn(UnitName::Protoss_Nexus);
	}
	if(race=='z') {
		for(int i=0; i<4; i++)
			buildHandler.spawn(UnitName::Zerg_Drone);
		buildHandler.spawn(UnitName::Zerg_Hatchery);
		buildHandler.spawn(UnitName::Zerg_Overlord);
	}
}

bool BWBOT::tryToBuild(UnitName unitname) {
	if(resourceHandler.canBuild(unitname)) {
		if(buildHandler.canBuild(unitname)) {
			buildHandler.build(unitname);
			ActiveUnit abcarg(unitname, ActionName::Start_Build, 150);
			output.push_back(resourceHandler.update(abcarg));
			return true;
		}
	}
	return false;
}

void BWBOT::clear() {
	buildHandler.clear();
	buildOrder.clear();
	resourceHandler.clear();
	output.clear();
}
<|endoftext|>


<commit_before>#include "Session.hh"

#include "../net/HttpConnection.hh"
#include "../net/HttpRequest.hh"
#include <tr064/trace.hh>

#include "../Tr064Exception.hh"

#include <pugixml/pugixml.hpp>

#include <sstream>
#include <iostream>

using namespace tr064::soap;

//------------------------------------------------------------------------------

pugi::xml_node
Session::execute_action(
      const Service::Ptr& service,
      const ServiceAction::Ptr& action)
{

  LOG_TRACE("Going to execute Service: " + service->name() +
            " with action: " + action->name());

  HttpConnection http_conn(_host, _port);

  pugi::xml_document doc;
  // iterate as long as it is not authenticated
  do
  {
    // reset xml docuemnt.
    doc.reset();

    auto body_str = get_body(service, action);
    std::stringstream ss;
    //ss << headers
       //<< body;

    std::stringbuf headers_buf;
    std::ostream headers(&headers_buf);
    auto header_str = get_headers(service, action, body_str.size()+4);
    headers << header_str;

    std::stringbuf body_buf;
    std::ostream body(&body_buf);
    body << body_str;

    LOG_DEBUG("Current request: " << std::endl << header_str << body_str);

    HttpRequest req(headers, body);
    auto response = http_conn.sync(&req);
    //return "";

    std::ostringstream r_oss;
    r_oss << (response->body());
    std::string r_s = r_oss.str();

    doc.load(r_s.c_str());

    // used for debug
    std::stringstream d_ss; doc.save(d_ss); LOG_DEBUG(d_ss.str());

    const auto& envelope_node = doc.child("s:Envelope");
    if ( envelope_node.empty() )
    {
      throw tr064::Tr064Exception(
          "Received response does not contain an envelope_node, "
          "unable to proceed, received: \n" + r_s);
    }

    _auth.handle_auth_response(envelope_node);

    delete response;

  } while ( !_auth.is_authenticated() );

  // the xml doc should be filled at this point
  auto body_node = doc.child("s:Envelope").child("s:Body");
  if ( body_node.empty() )
  {
    std::cerr << "Received body node is empty." << std::endl;
  }
  return body_node;
}

//------------------------------------------------------------------------------

std::string
Session::get_headers(
    const Service::Ptr& service,
    const ServiceAction::Ptr& action,
    const size_t body_length)
{
  std::stringstream ss;

  ss << "POST "  << service->control_url() << " HTTP/1.1\r\n"
     << "HOST: " << _host << "\r\n"
     << "CONTENT-LENGTH: " << body_length << "\r\n"
     << "CONTENT-TYPE: text/xml; charset=\"utf-8\"" << "\r\n"
     << "SOAPACTION: \"" << service->type() << "#"  << action->name() << "\"" << "\r\n"
     << "CONNECTION: close\r\n"
     << "USER-AGENT: AVM UPnP/1.0 Client 1.0 - tr064 lib" << "\r\n\r\n";

  return ss.str();
}

//------------------------------------------------------------------------------

std::string
Session::get_body(
      const Service::Ptr& service,
      const ServiceAction::Ptr& action)
{
  std::stringstream ss;

  ss << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl
     << "<s:Envelope s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">" << std::endl;

  if (!_no_auth)
  {
     ss << "  <s:Header>" << std::endl
        << _auth.get_auth_header_for_request()
        << "  </s:Header>" << std::endl;
  }
  ss << "  <s:Body>" << std::endl
     << "    <u:"  << action->name() << " xmlns:u=\"" << service->type() << "\">" << std::endl;

  for ( const auto& in_arg : action->args() )
  {
    // skip out args
    if ( in_arg->direction() == ServiceActionArg::OUT ) continue;
    // skip empty in args
    if ( in_arg->value().empty() ) continue;

    ss << "       <" << in_arg->name() << ">"
       << in_arg->value()
       << "       </" << in_arg->name() << ">" << std::endl;
  }

  ss << "    </u:" << action->name() << ">" << std::endl
     << "  </s:Body>" << std::endl
     << "</s:Envelope>" << std::endl;

  return ss.str();
}
<commit_msg>Handle no_auth on HttpRepsonses<commit_after>#include "Session.hh"

#include "../net/HttpConnection.hh"
#include "../net/HttpRequest.hh"
#include <tr064/trace.hh>

#include "../Tr064Exception.hh"

#include <pugixml/pugixml.hpp>

#include <sstream>
#include <iostream>

using namespace tr064::soap;

//------------------------------------------------------------------------------

pugi::xml_node
Session::execute_action(
      const Service::Ptr& service,
      const ServiceAction::Ptr& action)
{

  LOG_TRACE("Going to execute Service: " + service->name() +
            " with action: " + action->name());

  HttpConnection http_conn(_host, _port);

  pugi::xml_document doc;
  // iterate as long as it is not authenticated
  do
  {
    // reset xml docuemnt.
    doc.reset();

    auto body_str = get_body(service, action);
    std::stringstream ss;
    //ss << headers
       //<< body;

    std::stringbuf headers_buf;
    std::ostream headers(&headers_buf);
    auto header_str = get_headers(service, action, body_str.size()+4);
    headers << header_str;

    std::stringbuf body_buf;
    std::ostream body(&body_buf);
    body << body_str;

    LOG_DEBUG("Current request: " << std::endl << header_str << body_str);

    HttpRequest req(headers, body);
    auto response = http_conn.sync(&req);
    //return "";

    std::ostringstream r_oss;
    r_oss << (response->body());
    std::string r_s = r_oss.str();

    doc.load(r_s.c_str());

    // used for debug
    std::stringstream d_ss; doc.save(d_ss); LOG_DEBUG(d_ss.str());

    const auto& envelope_node = doc.child("s:Envelope");
    if ( envelope_node.empty() )
    {
      throw tr064::Tr064Exception(
          "Received response does not contain an envelope_node, "
          "unable to proceed, received: \n" + r_s);
    }

    if ( !_no_auth )
      _auth.handle_auth_response(envelope_node);

    delete response;

  } while ( !_auth.is_authenticated() && !_no_auth );

  // the xml doc should be filled at this point
  auto body_node = doc.child("s:Envelope").child("s:Body");
  if ( body_node.empty() )
  {
    std::cerr << "Received body node is empty." << std::endl;
  }
  return body_node;
}

//------------------------------------------------------------------------------

std::string
Session::get_headers(
    const Service::Ptr& service,
    const ServiceAction::Ptr& action,
    const size_t body_length)
{
  std::stringstream ss;

  ss << "POST "  << service->control_url() << " HTTP/1.1\r\n"
     << "HOST: " << _host << "\r\n"
     << "CONTENT-LENGTH: " << body_length << "\r\n"
     << "CONTENT-TYPE: text/xml; charset=\"utf-8\"" << "\r\n"
     << "SOAPACTION: \"" << service->type() << "#"  << action->name() << "\"" << "\r\n"
     << "CONNECTION: close\r\n"
     << "USER-AGENT: AVM UPnP/1.0 Client 1.0 - tr064 lib" << "\r\n\r\n";

  return ss.str();
}

//------------------------------------------------------------------------------

std::string
Session::get_body(
      const Service::Ptr& service,
      const ServiceAction::Ptr& action)
{
  std::stringstream ss;

  ss << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl
     << "<s:Envelope s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">" << std::endl;

  if (!_no_auth)
  {
     ss << "  <s:Header>" << std::endl
        << _auth.get_auth_header_for_request()
        << "  </s:Header>" << std::endl;
  }
  ss << "  <s:Body>" << std::endl
     << "    <u:"  << action->name() << " xmlns:u=\"" << service->type() << "\">" << std::endl;

  for ( const auto& in_arg : action->args() )
  {
    // skip out args
    if ( in_arg->direction() == ServiceActionArg::OUT ) continue;
    // skip empty in args
    if ( in_arg->value().empty() ) continue;

    ss << "       <" << in_arg->name() << ">"
       << in_arg->value()
       << "       </" << in_arg->name() << ">" << std::endl;
  }

  ss << "    </u:" << action->name() << ">" << std::endl
     << "  </s:Body>" << std::endl
     << "</s:Envelope>" << std::endl;

  return ss.str();
}
<|endoftext|>


<commit_before>#ifndef _INCLUDED_DS_TEXTDS_HPP
#define _INCLUDED_DS_TEXTDS_HPP

#include <sdsl/int_vector.hpp>

#include <tudocomp/ds/ITextDSProvider.hpp>

#include <tudocomp/ds/SuffixArray.hpp>
#include <tudocomp/ds/InverseSuffixArray.hpp>
#include <tudocomp/ds/PhiArray.hpp>
#include <tudocomp/ds/LCPArray.hpp>

#include <tudocomp/io.h>

namespace tudocomp {

using io::InputView;

/// Manages text related data structures.
class TextDS : public ITextDSProvider {

private:
    size_t m_size;
    const uint8_t* m_text;

    std::shared_ptr<SuffixArray>        m_sa;
    std::shared_ptr<InverseSuffixArray> m_isa;
    std::shared_ptr<PhiArray>           m_phi;
    std::shared_ptr<LCPArray>           m_lcp;

public:
    inline TextDS(const InputView& input)
        : m_size(input.size()), m_text((const uint8_t*)input.data())

    {
    }

    /// Requires the Suffix Array to be constructed if not already present.
    virtual inline const SuffixArray& require_sa() override {
        if(!m_sa) {
            m_sa = std::shared_ptr<SuffixArray>(new SuffixArray());
            m_sa->construct(*this);
        }

        return *m_sa;
    }

    /// Requires the Phi Array to be constructed if not already present.
    virtual inline const PhiArray& require_phi() override {
        if(!m_phi) {
            m_phi = std::shared_ptr<PhiArray>(new PhiArray());
            m_phi->construct(*this);
        }

        return *m_phi;
    }

    /// Requires the Inverse Suffix Array to be constructed if not already present.
    virtual inline const InverseSuffixArray& require_isa() override {
        if(!m_isa) {
            m_isa = std::shared_ptr<InverseSuffixArray>(new InverseSuffixArray());
            m_isa->construct(*this);
        }

        return *m_isa;
    }

    /// Requires the LCP Array to be constructed if not already present.
    virtual inline const LCPArray& require_lcp() override {
        if(!m_lcp) {
            m_lcp = std::shared_ptr<LCPArray>(new LCPArray());
            m_lcp->construct(*this);
        }

        return *m_lcp;
    }

    virtual inline uint8_t operator[](size_t i) const override {
        return m_text[i];
    }

    virtual inline const uint8_t* text() const override {
        return m_text;
    }

    virtual inline size_t size() const override {
        return m_size;
    }
};

}

#endif

<commit_msg>Allow release of unneeded data structures<commit_after>#ifndef _INCLUDED_DS_TEXTDS_HPP
#define _INCLUDED_DS_TEXTDS_HPP

#include <sdsl/int_vector.hpp>

#include <tudocomp/ds/ITextDSProvider.hpp>

#include <tudocomp/ds/SuffixArray.hpp>
#include <tudocomp/ds/InverseSuffixArray.hpp>
#include <tudocomp/ds/PhiArray.hpp>
#include <tudocomp/ds/LCPArray.hpp>

#include <tudocomp/io.h>

namespace tudocomp {

using io::InputView;

/// Manages text related data structures.
class TextDS : public ITextDSProvider {

public:
    static const uint64_t SA = 0x01;
    static const uint64_t ISA = 0x02;
    static const uint64_t Phi = 0x04;
    static const uint64_t LCP = 0x08;

private:
    size_t m_size;
    const uint8_t* m_text;

    std::shared_ptr<SuffixArray>        m_sa;
    std::shared_ptr<InverseSuffixArray> m_isa;
    std::shared_ptr<PhiArray>           m_phi;
    std::shared_ptr<LCPArray>           m_lcp;

public:
    inline TextDS(const InputView& input)
        : m_size(input.size()), m_text((const uint8_t*)input.data())
    {
    }

    /// Constructs the required data structures as denoted by the given flags
    /// and releases all unwanted ones in a second step.
    inline void require(uint64_t flags) {
        //Step 1: construct
        if(flags & SA) require_sa();
        if(flags & ISA) require_isa();
        if(flags & Phi) require_phi();
        if(flags & LCP) require_lcp();

        //Step 2: release unwanted (may have been constructed beforehand)
        if(!(flags & SA)) release_sa();
        if(!(flags & ISA)) release_isa();
        if(!(flags & Phi)) release_phi();
        if(!(flags & LCP)) release_lcp();
    }

    /// Requires the Suffix Array to be constructed if not already present.
    virtual inline const SuffixArray& require_sa() override {
        if(!m_sa) {
            m_sa = std::shared_ptr<SuffixArray>(new SuffixArray());
            m_sa->construct(*this);
        }

        return *m_sa;
    }

    /// Requires the Phi Array to be constructed if not already present.
    virtual inline const PhiArray& require_phi() override {
        if(!m_phi) {
            m_phi = std::shared_ptr<PhiArray>(new PhiArray());
            m_phi->construct(*this);
        }

        return *m_phi;
    }

    /// Requires the Inverse Suffix Array to be constructed if not already present.
    virtual inline const InverseSuffixArray& require_isa() override {
        if(!m_isa) {
            m_isa = std::shared_ptr<InverseSuffixArray>(new InverseSuffixArray());
            m_isa->construct(*this);
        }

        return *m_isa;
    }

    /// Requires the LCP Array to be constructed if not already present.
    virtual inline const LCPArray& require_lcp() override {
        if(!m_lcp) {
            m_lcp = std::shared_ptr<LCPArray>(new LCPArray());
            m_lcp->construct(*this);
        }

        return *m_lcp;
    }

    /// Releases the suffix array if present.
    inline void release_sa() {
        m_sa.reset();
    }

    /// Releases the inverse suffix array array if present.
    inline void release_isa() {
        m_isa.reset();
    }

    /// Releases the Phi array if present.
    inline void release_phi() {
        m_phi.reset();
    }

    /// Releases the LCP array if present.
    inline void release_lcp() {
        m_lcp.reset();
    }

    /// Accesses the input text at position i.
    virtual inline uint8_t operator[](size_t i) const override {
        return m_text[i];
    }

    /// Provides access to the input text.
    virtual inline const uint8_t* text() const override {
        return m_text;
    }

    /// Returns the size of the input text.
    virtual inline size_t size() const override {
        return m_size;
    }
};

}

#endif

<|endoftext|>


<commit_before>/*
 * Copyright 2007-2020 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "cache.hxx"
#include "event/Loop.hxx"
#include "util/djbhash.h"

#include <assert.h>
#include <string.h>

inline size_t
CacheItem::KeyHasher(const char *key) noexcept
{
	assert(key != nullptr);

	return djb_hash_string(key);
}

bool
CacheItem::KeyValueEqual(const char *a, const CacheItem &b) noexcept
{
	assert(a != nullptr);

	return strcmp(a, b.key) == 0;
}

void
CacheItem::Release() noexcept
{
	if (lock == 0)
		Destroy();
	else
		/* this item is locked - postpone the Destroy() call */
		removed = true;
}

Cache::Cache(EventLoop &event_loop,
	     unsigned hashtable_capacity, size_t _max_size) noexcept
	:max_size(_max_size),
	 buckets(new ItemSet::bucket_type[hashtable_capacity]),
	 items(ItemSet::bucket_traits(buckets.get(), hashtable_capacity)),
	 cleanup_timer(event_loop, std::chrono::minutes(1),
		       BIND_THIS_METHOD(ExpireCallback)) {}

Cache::~Cache() noexcept
{
	items.clear_and_dispose([this](CacheItem *item){
		assert(item->lock == 0);
		assert(size >= item->size);
		size -= item->size;

#ifndef NDEBUG
		sorted_items.erase(sorted_items.iterator_to(*item));
#endif

		item->Destroy();
	});

	assert(size == 0);
	assert(sorted_items.empty());
}

std::chrono::steady_clock::time_point
Cache::SteadyNow() const noexcept
{
	return GetEventLoop().SteadyNow();
}

std::chrono::system_clock::time_point
Cache::SystemNow() const noexcept
{
	return GetEventLoop().SystemNow();
}

void
Cache::ItemRemoved(CacheItem *item) noexcept
{
	assert(item != nullptr);
	assert(item->size > 0);
	assert(item->lock > 0 || !item->removed);
	assert(size >= item->size);

	sorted_items.erase(sorted_items.iterator_to(*item));

	size -= item->size;

	item->Release();

	if (size == 0)
		cleanup_timer.Disable();
}

void
Cache::Flush() noexcept
{
	items.clear_and_dispose(Cache::ItemRemover(*this));
}

void
Cache::RefreshItem(CacheItem &item,
		   std::chrono::steady_clock::time_point now) noexcept
{
	item.last_accessed = now;

	/* move to the front of the linked list */
	sorted_items.erase(sorted_items.iterator_to(item));
	sorted_items.push_back(item);
}

void
Cache::RemoveItem(CacheItem &item) noexcept
{
	assert(!item.removed);

	items.erase_and_dispose(items.iterator_to(item),
				ItemRemover(*this));
}

CacheItem *
Cache::Get(const char *key) noexcept
{
	auto i = items.find(key, CacheItem::KeyHasher, CacheItem::KeyValueEqual);
	if (i == items.end())
		return nullptr;

	CacheItem *item = &*i;

	const auto now = SteadyNow();

	if (!item->Validate(now)) {
		RemoveItem(*item);
		return nullptr;
	}

	RefreshItem(*item, now);
	return item;
}

CacheItem *
Cache::GetMatch(const char *key,
		bool (*match)(const CacheItem *, void *),
		void *ctx) noexcept
{
	const auto now = SteadyNow();

	const auto r = items.equal_range(key, CacheItem::KeyHasher,
					 CacheItem::KeyValueEqual);
	for (auto i = r.first, end = r.second; i != end;) {
		CacheItem *item = &*i++;

		if (!item->Validate(now)) {
			/* expired cache item: delete it, and re-start the
			   search */

			RemoveItem(*item);
		} else if (match(item, ctx)) {
			/* this one matches: return it to the caller */
			RefreshItem(*item, now);
			return item;
		}
	};

	return nullptr;
}

void
Cache::DestroyOldestItem() noexcept
{
	if (sorted_items.empty())
		return;

	CacheItem &item = sorted_items.front();
	RemoveItem(item);
}

bool
Cache::NeedRoom(size_t _size) noexcept
{
	if (_size > max_size)
		return false;

	while (true) {
		if (size + _size <= max_size)
			return true;

		DestroyOldestItem();
	}
}

bool
Cache::Add(const char *key, CacheItem &item) noexcept
{
	/* XXX size constraints */
	if (!NeedRoom(item.size)) {
		item.Destroy();
		return false;
	}

	item.key = key;
	items.insert(item);
	sorted_items.push_back(item);

	size += item.size;
	item.last_accessed = SteadyNow();

	cleanup_timer.Enable();
	return true;
}

bool
Cache::Put(const char *key, CacheItem &item) noexcept
{
	/* XXX size constraints */

	assert(item.size > 0);
	assert(item.lock == 0);
	assert(!item.removed);

	if (!NeedRoom(item.size)) {
		item.Destroy();
		return false;
	}

	item.key = key;

	auto i = items.find(key, CacheItem::KeyHasher,
			    CacheItem::KeyValueEqual);
	if (i != items.end())
		RemoveItem(*i);

	size += item.size;
	item.last_accessed = SteadyNow();

	items.insert(item);
	sorted_items.push_back(item);

	cleanup_timer.Enable();
	return true;
}

bool
Cache::PutMatch(const char *key, CacheItem &item,
		bool (*match)(const CacheItem *, void *), void *ctx) noexcept
{
	auto *old = GetMatch(key, match, ctx);

	assert(item.size > 0);
	assert(item.lock == 0);
	assert(!item.removed);

	if (old != nullptr)
		RemoveItem(*old);

	return Add(key, item);
}

void
Cache::Remove(const char *key) noexcept
{
	items.erase_and_dispose(key, CacheItem::KeyHasher,
				CacheItem::KeyValueEqual,
				[this](CacheItem *item){
					ItemRemoved(item);
				});
}

void
Cache::RemoveMatch(const char *key,
		   bool (*match)(const CacheItem *, void *),
		   void *ctx) noexcept
{
	const auto r = items.equal_range(key, CacheItem::KeyHasher,
					 CacheItem::KeyValueEqual);
	for (auto i = r.first, end = r.second; i != end;) {
		CacheItem &item = *i++;

		if (match(&item, ctx))
			RemoveItem(item);
	}
}

void
Cache::Remove(CacheItem &item) noexcept
{
	if (item.removed) {
		/* item has already been removed by somebody else */
		assert(item.lock > 0);
		return;
	}

	RemoveItem(item);
}

unsigned
Cache::RemoveAllMatch(bool (*match)(const CacheItem *, void *),
		      void *ctx) noexcept
{
	unsigned removed = 0;

	for (auto i = sorted_items.begin(), end = sorted_items.end();
	     i != end;) {
		CacheItem &item = *i++;

		if (!match(&item, ctx))
			continue;

		items.erase(items.iterator_to(item));
		ItemRemoved(&item);
		++removed;
	}

	return removed;
}

static std::chrono::steady_clock::time_point
ToSteady(std::chrono::steady_clock::time_point steady_now,
	 std::chrono::system_clock::time_point system_now,
	 std::chrono::system_clock::time_point t) noexcept
{
	return t > system_now
		? steady_now + (t - system_now)
		: std::chrono::steady_clock::time_point();
}

CacheItem::CacheItem(std::chrono::steady_clock::time_point now,
		     std::chrono::system_clock::time_point system_now,
		     std::chrono::system_clock::time_point _expires,
		     size_t _size) noexcept
	:CacheItem(ToSteady(now, system_now, _expires), _size)
{
}

CacheItem::CacheItem(std::chrono::steady_clock::time_point now,
		     std::chrono::seconds max_age, size_t _size) noexcept
	:CacheItem(now + max_age, _size)
{
}

void
CacheItem::Unlock() noexcept
{
	assert(lock > 0);

	if (--lock == 0 && removed)
		/* postponed destroy */
		Destroy();
}

/** clean up expired cache items every 60 seconds */
bool
Cache::ExpireCallback() noexcept
{
	const auto now = SteadyNow();

	for (auto i = sorted_items.begin(), end = sorted_items.end(); i != end;) {
		CacheItem &item = *i++;

		if (item.expires > now)
			/* not yet expired */
			continue;

		RemoveItem(item);
	}

	return size > 0;
}

void
Cache::EventAdd() noexcept
{
	if (size > 0)
		cleanup_timer.Enable();
}

void
Cache::EventDel() noexcept
{
	cleanup_timer.Disable();
}
<commit_msg>cache: add `constexpr`<commit_after>/*
 * Copyright 2007-2020 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "cache.hxx"
#include "event/Loop.hxx"
#include "util/djbhash.h"

#include <assert.h>
#include <string.h>

inline size_t
CacheItem::KeyHasher(const char *key) noexcept
{
	assert(key != nullptr);

	return djb_hash_string(key);
}

bool
CacheItem::KeyValueEqual(const char *a, const CacheItem &b) noexcept
{
	assert(a != nullptr);

	return strcmp(a, b.key) == 0;
}

void
CacheItem::Release() noexcept
{
	if (lock == 0)
		Destroy();
	else
		/* this item is locked - postpone the Destroy() call */
		removed = true;
}

Cache::Cache(EventLoop &event_loop,
	     unsigned hashtable_capacity, size_t _max_size) noexcept
	:max_size(_max_size),
	 buckets(new ItemSet::bucket_type[hashtable_capacity]),
	 items(ItemSet::bucket_traits(buckets.get(), hashtable_capacity)),
	 cleanup_timer(event_loop, std::chrono::minutes(1),
		       BIND_THIS_METHOD(ExpireCallback)) {}

Cache::~Cache() noexcept
{
	items.clear_and_dispose([this](CacheItem *item){
		assert(item->lock == 0);
		assert(size >= item->size);
		size -= item->size;

#ifndef NDEBUG
		sorted_items.erase(sorted_items.iterator_to(*item));
#endif

		item->Destroy();
	});

	assert(size == 0);
	assert(sorted_items.empty());
}

std::chrono::steady_clock::time_point
Cache::SteadyNow() const noexcept
{
	return GetEventLoop().SteadyNow();
}

std::chrono::system_clock::time_point
Cache::SystemNow() const noexcept
{
	return GetEventLoop().SystemNow();
}

void
Cache::ItemRemoved(CacheItem *item) noexcept
{
	assert(item != nullptr);
	assert(item->size > 0);
	assert(item->lock > 0 || !item->removed);
	assert(size >= item->size);

	sorted_items.erase(sorted_items.iterator_to(*item));

	size -= item->size;

	item->Release();

	if (size == 0)
		cleanup_timer.Disable();
}

void
Cache::Flush() noexcept
{
	items.clear_and_dispose(Cache::ItemRemover(*this));
}

void
Cache::RefreshItem(CacheItem &item,
		   std::chrono::steady_clock::time_point now) noexcept
{
	item.last_accessed = now;

	/* move to the front of the linked list */
	sorted_items.erase(sorted_items.iterator_to(item));
	sorted_items.push_back(item);
}

void
Cache::RemoveItem(CacheItem &item) noexcept
{
	assert(!item.removed);

	items.erase_and_dispose(items.iterator_to(item),
				ItemRemover(*this));
}

CacheItem *
Cache::Get(const char *key) noexcept
{
	auto i = items.find(key, CacheItem::KeyHasher, CacheItem::KeyValueEqual);
	if (i == items.end())
		return nullptr;

	CacheItem *item = &*i;

	const auto now = SteadyNow();

	if (!item->Validate(now)) {
		RemoveItem(*item);
		return nullptr;
	}

	RefreshItem(*item, now);
	return item;
}

CacheItem *
Cache::GetMatch(const char *key,
		bool (*match)(const CacheItem *, void *),
		void *ctx) noexcept
{
	const auto now = SteadyNow();

	const auto r = items.equal_range(key, CacheItem::KeyHasher,
					 CacheItem::KeyValueEqual);
	for (auto i = r.first, end = r.second; i != end;) {
		CacheItem *item = &*i++;

		if (!item->Validate(now)) {
			/* expired cache item: delete it, and re-start the
			   search */

			RemoveItem(*item);
		} else if (match(item, ctx)) {
			/* this one matches: return it to the caller */
			RefreshItem(*item, now);
			return item;
		}
	};

	return nullptr;
}

void
Cache::DestroyOldestItem() noexcept
{
	if (sorted_items.empty())
		return;

	CacheItem &item = sorted_items.front();
	RemoveItem(item);
}

bool
Cache::NeedRoom(size_t _size) noexcept
{
	if (_size > max_size)
		return false;

	while (true) {
		if (size + _size <= max_size)
			return true;

		DestroyOldestItem();
	}
}

bool
Cache::Add(const char *key, CacheItem &item) noexcept
{
	/* XXX size constraints */
	if (!NeedRoom(item.size)) {
		item.Destroy();
		return false;
	}

	item.key = key;
	items.insert(item);
	sorted_items.push_back(item);

	size += item.size;
	item.last_accessed = SteadyNow();

	cleanup_timer.Enable();
	return true;
}

bool
Cache::Put(const char *key, CacheItem &item) noexcept
{
	/* XXX size constraints */

	assert(item.size > 0);
	assert(item.lock == 0);
	assert(!item.removed);

	if (!NeedRoom(item.size)) {
		item.Destroy();
		return false;
	}

	item.key = key;

	auto i = items.find(key, CacheItem::KeyHasher,
			    CacheItem::KeyValueEqual);
	if (i != items.end())
		RemoveItem(*i);

	size += item.size;
	item.last_accessed = SteadyNow();

	items.insert(item);
	sorted_items.push_back(item);

	cleanup_timer.Enable();
	return true;
}

bool
Cache::PutMatch(const char *key, CacheItem &item,
		bool (*match)(const CacheItem *, void *), void *ctx) noexcept
{
	auto *old = GetMatch(key, match, ctx);

	assert(item.size > 0);
	assert(item.lock == 0);
	assert(!item.removed);

	if (old != nullptr)
		RemoveItem(*old);

	return Add(key, item);
}

void
Cache::Remove(const char *key) noexcept
{
	items.erase_and_dispose(key, CacheItem::KeyHasher,
				CacheItem::KeyValueEqual,
				[this](CacheItem *item){
					ItemRemoved(item);
				});
}

void
Cache::RemoveMatch(const char *key,
		   bool (*match)(const CacheItem *, void *),
		   void *ctx) noexcept
{
	const auto r = items.equal_range(key, CacheItem::KeyHasher,
					 CacheItem::KeyValueEqual);
	for (auto i = r.first, end = r.second; i != end;) {
		CacheItem &item = *i++;

		if (match(&item, ctx))
			RemoveItem(item);
	}
}

void
Cache::Remove(CacheItem &item) noexcept
{
	if (item.removed) {
		/* item has already been removed by somebody else */
		assert(item.lock > 0);
		return;
	}

	RemoveItem(item);
}

unsigned
Cache::RemoveAllMatch(bool (*match)(const CacheItem *, void *),
		      void *ctx) noexcept
{
	unsigned removed = 0;

	for (auto i = sorted_items.begin(), end = sorted_items.end();
	     i != end;) {
		CacheItem &item = *i++;

		if (!match(&item, ctx))
			continue;

		items.erase(items.iterator_to(item));
		ItemRemoved(&item);
		++removed;
	}

	return removed;
}

static constexpr std::chrono::steady_clock::time_point
ToSteady(std::chrono::steady_clock::time_point steady_now,
	 std::chrono::system_clock::time_point system_now,
	 std::chrono::system_clock::time_point t) noexcept
{
	return t > system_now
		? steady_now + (t - system_now)
		: std::chrono::steady_clock::time_point();
}

CacheItem::CacheItem(std::chrono::steady_clock::time_point now,
		     std::chrono::system_clock::time_point system_now,
		     std::chrono::system_clock::time_point _expires,
		     size_t _size) noexcept
	:CacheItem(ToSteady(now, system_now, _expires), _size)
{
}

CacheItem::CacheItem(std::chrono::steady_clock::time_point now,
		     std::chrono::seconds max_age, size_t _size) noexcept
	:CacheItem(now + max_age, _size)
{
}

void
CacheItem::Unlock() noexcept
{
	assert(lock > 0);

	if (--lock == 0 && removed)
		/* postponed destroy */
		Destroy();
}

/** clean up expired cache items every 60 seconds */
bool
Cache::ExpireCallback() noexcept
{
	const auto now = SteadyNow();

	for (auto i = sorted_items.begin(), end = sorted_items.end(); i != end;) {
		CacheItem &item = *i++;

		if (item.expires > now)
			/* not yet expired */
			continue;

		RemoveItem(item);
	}

	return size > 0;
}

void
Cache::EventAdd() noexcept
{
	if (size > 0)
		cleanup_timer.Enable();
}

void
Cache::EventDel() noexcept
{
	cleanup_timer.Disable();
}
<|endoftext|>


<commit_before>/*  This file is part of the KDE project.

Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).

This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 or 3 of the License.

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

You should have received a copy of the GNU Lesser General Public License
along with this library.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "utils.h"
#include <e32std.h>

QT_BEGIN_NAMESPACE

using namespace Phonon;
using namespace Phonon::MMF;

_LIT(PanicCategory, "Phonon::MMF");

void MMF::Utils::panic(PanicCode code)
{
    User::Panic(PanicCategory, code);
}

static const TInt KMimePrefixLength = 6; // either "audio/" or "video/"
_LIT(KMimePrefixAudio, "audio/");
_LIT(KMimePrefixVideo, "video/");

MMF::MediaType MMF::Utils::mimeTypeToMediaType(const TDesC& mimeType)
{
    MediaType result = MediaTypeUnknown;

    if (mimeType.Left(KMimePrefixLength).Compare(KMimePrefixAudio) == 0) {
        result = MediaTypeAudio;
    } else if (mimeType.Left(KMimePrefixLength).Compare(KMimePrefixVideo) == 0) {
        result = MediaTypeVideo;
    }

    return result;
}

#ifdef _DEBUG

#include <hal.h>
#include <hal_data.h>
#include <gdi.h>
#include <eikenv.h>

struct TScreenInfo
{
    int width;
    int height;
    int bpp;
    const char* address;
    int initialOffset;
    int lineOffset;
    TDisplayMode displayMode;
};

void getScreenInfoL(TScreenInfo& info)
{
    info.displayMode = CEikonEnv::Static()->ScreenDevice()->DisplayMode();

    // Then we must set these as the input parameter
    info.width = info.displayMode;
    info.height = info.displayMode;
    info.initialOffset = info.displayMode;
    info.lineOffset = info.displayMode;
    info.bpp = info.displayMode;

    User::LeaveIfError( HAL::Get(HALData::EDisplayXPixels, info.width) );
    User::LeaveIfError( HAL::Get(HALData::EDisplayYPixels, info.width) );

    int address;
    User::LeaveIfError( HAL::Get(HALData::EDisplayMemoryAddress, address) );
    info.address = reinterpret_cast<const char*>(address);

    User::LeaveIfError( HAL::Get(HALData::EDisplayOffsetToFirstPixel, info.initialOffset) );

    User::LeaveIfError( HAL::Get(HALData::EDisplayOffsetBetweenLines, info.lineOffset) );

    User::LeaveIfError( HAL::Get(HALData::EDisplayBitsPerPixel, info.bpp) );
}

QColor MMF::Utils::getScreenPixel(const QPoint& pos)
{
    TScreenInfo info;
    TRAPD(err, getScreenInfoL(info));
    QColor pixel;
    if(err == KErrNone and pos.x() < info.width and pos.y() < info.height)
    {
        const int bytesPerPixel = info.bpp / 8;
        Q_ASSERT(bytesPerPixel >= 3);

        const int stride = (info.width * bytesPerPixel) + info.lineOffset;

        const char* ptr =
                info.address
            +    info.initialOffset
            +    pos.y() * stride
            +    pos.x() * bytesPerPixel;

        // BGRA
        pixel.setBlue(*ptr++);
        pixel.setGreen(*ptr++);
        pixel.setRed(*ptr++);

        if(bytesPerPixel == 4)
            pixel.setAlpha(*ptr++);
    }
    return pixel;
}

// Debugging: for debugging video visibility
void MMF::Utils::dumpScreenPixelSample()
{
    for(int i=0; i<20; ++i) {
        const QPoint pos(i*10, i*10);
        const QColor pixel = Utils::getScreenPixel(pos);
        RDebug::Printf(
            "Phonon::MMF::Utils::dumpScreenPixelSample %d %d = %d %d %d %d",
            pos.x(), pos.y(), pixel.red(), pixel.green(), pixel.blue(), pixel.alpha()
        );
    }
}

#endif // _DEBUG

QT_END_NAMESPACE

<commit_msg>Make local function static.<commit_after>/*  This file is part of the KDE project.

Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).

This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 or 3 of the License.

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

You should have received a copy of the GNU Lesser General Public License
along with this library.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "utils.h"
#include <e32std.h>

QT_BEGIN_NAMESPACE

using namespace Phonon;
using namespace Phonon::MMF;

_LIT(PanicCategory, "Phonon::MMF");

void MMF::Utils::panic(PanicCode code)
{
    User::Panic(PanicCategory, code);
}

static const TInt KMimePrefixLength = 6; // either "audio/" or "video/"
_LIT(KMimePrefixAudio, "audio/");
_LIT(KMimePrefixVideo, "video/");

MMF::MediaType MMF::Utils::mimeTypeToMediaType(const TDesC& mimeType)
{
    MediaType result = MediaTypeUnknown;

    if (mimeType.Left(KMimePrefixLength).Compare(KMimePrefixAudio) == 0) {
        result = MediaTypeAudio;
    } else if (mimeType.Left(KMimePrefixLength).Compare(KMimePrefixVideo) == 0) {
        result = MediaTypeVideo;
    }

    return result;
}

#ifdef _DEBUG

#include <hal.h>
#include <hal_data.h>
#include <gdi.h>
#include <eikenv.h>

struct TScreenInfo
{
    int width;
    int height;
    int bpp;
    const char* address;
    int initialOffset;
    int lineOffset;
    TDisplayMode displayMode;
};

static void getScreenInfoL(TScreenInfo& info)
{
    info.displayMode = CEikonEnv::Static()->ScreenDevice()->DisplayMode();

    // Then we must set these as the input parameter
    info.width = info.displayMode;
    info.height = info.displayMode;
    info.initialOffset = info.displayMode;
    info.lineOffset = info.displayMode;
    info.bpp = info.displayMode;

    User::LeaveIfError( HAL::Get(HALData::EDisplayXPixels, info.width) );
    User::LeaveIfError( HAL::Get(HALData::EDisplayYPixels, info.width) );

    int address;
    User::LeaveIfError( HAL::Get(HALData::EDisplayMemoryAddress, address) );
    info.address = reinterpret_cast<const char*>(address);

    User::LeaveIfError( HAL::Get(HALData::EDisplayOffsetToFirstPixel, info.initialOffset) );

    User::LeaveIfError( HAL::Get(HALData::EDisplayOffsetBetweenLines, info.lineOffset) );

    User::LeaveIfError( HAL::Get(HALData::EDisplayBitsPerPixel, info.bpp) );
}

QColor MMF::Utils::getScreenPixel(const QPoint& pos)
{
    TScreenInfo info;
    TRAPD(err, getScreenInfoL(info));
    QColor pixel;
    if(err == KErrNone and pos.x() < info.width and pos.y() < info.height)
    {
        const int bytesPerPixel = info.bpp / 8;
        Q_ASSERT(bytesPerPixel >= 3);

        const int stride = (info.width * bytesPerPixel) + info.lineOffset;

        const char* ptr =
                info.address
            +    info.initialOffset
            +    pos.y() * stride
            +    pos.x() * bytesPerPixel;

        // BGRA
        pixel.setBlue(*ptr++);
        pixel.setGreen(*ptr++);
        pixel.setRed(*ptr++);

        if(bytesPerPixel == 4)
            pixel.setAlpha(*ptr++);
    }
    return pixel;
}

// Debugging: for debugging video visibility
void MMF::Utils::dumpScreenPixelSample()
{
    for(int i=0; i<20; ++i) {
        const QPoint pos(i*10, i*10);
        const QColor pixel = Utils::getScreenPixel(pos);
        RDebug::Printf(
            "Phonon::MMF::Utils::dumpScreenPixelSample %d %d = %d %d %d %d",
            pos.x(), pos.y(), pixel.red(), pixel.green(), pixel.blue(), pixel.alpha()
        );
    }
}

#endif // _DEBUG

QT_END_NAMESPACE

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2004-2011  See the AUTHORS file for details.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation.
 */

#include "User.h"
#include <algorithm>

class CPerform : public CModule {
	void Add(const CString& sCommand) {
		CString sPerf = sCommand.Token(1, true);

		if (sPerf.empty()) {
			PutModule("Usage: add <command>");
			return;
		}

		m_vPerform.push_back(ParsePerform(sPerf));
		PutModule("Added!");
		Save();
	}

	void Del(const CString& sCommand) {
		u_int iNum = sCommand.Token(1, true).ToUInt();

		if (iNum > m_vPerform.size() || iNum <= 0) {
			PutModule("Illegal # Requested");
			return;
		} else {
			m_vPerform.erase(m_vPerform.begin() + iNum - 1);
			PutModule("Command Erased.");
		}
		Save();
	}

	void List(const CString& sCommand) {
		CTable Table;
		unsigned int index = 1;
		CString sExpanded;

		Table.AddColumn("Id");
		Table.AddColumn("Perform");
		Table.AddColumn("Expanded");

		for (VCString::const_iterator it = m_vPerform.begin(); it != m_vPerform.end(); it++, index++) {
			Table.AddRow();
			Table.SetCell("Id", CString(index));
			Table.SetCell("Perform", *it);

			sExpanded = GetUser()->ExpandString(*it);
			if (sExpanded != *it) {
				Table.SetCell("Expanded", sExpanded);
			}
		}

		if (PutModule(Table) == 0) {
			PutModule("No commands in your perform list.");
		}
	}

	void Execute(const CString& sCommand) {
		OnIRCConnected();
		PutModule("perform commands sent");
	}

	void Swap(const CString& sCommand) {
		u_int iNumA = sCommand.Token(1).ToUInt();
		u_int iNumB = sCommand.Token(2).ToUInt();

		if (iNumA > m_vPerform.size() || iNumA <= 0 || iNumB > m_vPerform.size() || iNumB <= 0) {
			PutModule("Illegal # Requested");
		} else {
			std::iter_swap(m_vPerform.begin() + (iNumA - 1), m_vPerform.begin() + (iNumB - 1));
			PutModule("Commands Swapped.");
			Save();
		}
	}

public:
	MODCONSTRUCTOR(CPerform) {
		AddHelpCommand();
		AddCommand("Add",     static_cast<CModCommand::ModCmdFunc>(&CPerform::Add),
			"<command>");
		AddCommand("Del",     static_cast<CModCommand::ModCmdFunc>(&CPerform::Del),
			"<nr>");
		AddCommand("List",    static_cast<CModCommand::ModCmdFunc>(&CPerform::List));
		AddCommand("Execute", static_cast<CModCommand::ModCmdFunc>(&CPerform::Execute));
		AddCommand("Swap",    static_cast<CModCommand::ModCmdFunc>(&CPerform::Swap),
			"<nr> <nr>");
	}

	virtual ~CPerform() {}

	CString ParsePerform(const CString& sArg) const {
		CString sPerf = sArg;

		if (sPerf.Left(1) == "/")
			sPerf.LeftChomp();

		if (sPerf.Token(0).Equals("MSG")) {
			sPerf = "PRIVMSG " + sPerf.Token(1, true);
		}

		if ((sPerf.Token(0).Equals("PRIVMSG") ||
				sPerf.Token(0).Equals("NOTICE")) &&
				sPerf.Token(2).Left(1) != ":") {
			sPerf = sPerf.Token(0) + " " + sPerf.Token(1)
				+ " :" + sPerf.Token(2, true);
		}

		return sPerf;
	}

	virtual bool OnLoad(const CString& sArgs, CString& sMessage) {
		GetNV("Perform").Split("\n", m_vPerform, false);

		return true;
	}

	virtual void OnIRCConnected() {
		for (VCString::const_iterator it = m_vPerform.begin(); it != m_vPerform.end(); ++it) {
			PutIRC(GetUser()->ExpandString(*it));
		}
	}

	virtual CString GetWebMenuTitle() { return "Perform"; }

	virtual bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) {
		if (sPageName != "index") {
			// only accept requests to /mods/perform/
			return false;
		}

		if (WebSock.IsPost()) {
			VCString vsPerf;
			WebSock.GetRawParam("perform", true).Split("\n", vsPerf, false);
			m_vPerform.clear();

			for (VCString::const_iterator it = vsPerf.begin(); it != vsPerf.end(); ++it)
				m_vPerform.push_back(ParsePerform(*it));

			Save();
		}

		for (VCString::const_iterator it = m_vPerform.begin(); it != m_vPerform.end(); ++it) {
			CTemplate& Row = Tmpl.AddRow("PerformLoop");
			Row["Perform"] = *it;
		}

		return true;
	}

private:
	void Save() {
		CString sBuffer = "";

		for (VCString::const_iterator it = m_vPerform.begin(); it != m_vPerform.end(); ++it) {
			sBuffer += *it + "\n";
		}
		SetNV("Perform", sBuffer);
	}

	VCString m_vPerform;
};

template<> void TModInfo<CPerform>(CModInfo& Info) {
	Info.SetWikiPage("perform");
}

MODULEDEFS(CPerform, "Keeps a list of commands to be executed when ZNC connects to IRC.")
<commit_msg>Perform is now a network module, but could also be loaded as a user module if the user desires<commit_after>/*
 * Copyright (C) 2004-2011  See the AUTHORS file for details.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation.
 */

#include "User.h"
#include <algorithm>

class CPerform : public CModule {
	void Add(const CString& sCommand) {
		CString sPerf = sCommand.Token(1, true);

		if (sPerf.empty()) {
			PutModule("Usage: add <command>");
			return;
		}

		m_vPerform.push_back(ParsePerform(sPerf));
		PutModule("Added!");
		Save();
	}

	void Del(const CString& sCommand) {
		u_int iNum = sCommand.Token(1, true).ToUInt();

		if (iNum > m_vPerform.size() || iNum <= 0) {
			PutModule("Illegal # Requested");
			return;
		} else {
			m_vPerform.erase(m_vPerform.begin() + iNum - 1);
			PutModule("Command Erased.");
		}
		Save();
	}

	void List(const CString& sCommand) {
		CTable Table;
		unsigned int index = 1;
		CString sExpanded;

		Table.AddColumn("Id");
		Table.AddColumn("Perform");
		Table.AddColumn("Expanded");

		for (VCString::const_iterator it = m_vPerform.begin(); it != m_vPerform.end(); it++, index++) {
			Table.AddRow();
			Table.SetCell("Id", CString(index));
			Table.SetCell("Perform", *it);

			sExpanded = GetUser()->ExpandString(*it);
			if (sExpanded != *it) {
				Table.SetCell("Expanded", sExpanded);
			}
		}

		if (PutModule(Table) == 0) {
			PutModule("No commands in your perform list.");
		}
	}

	void Execute(const CString& sCommand) {
		OnIRCConnected();
		PutModule("perform commands sent");
	}

	void Swap(const CString& sCommand) {
		u_int iNumA = sCommand.Token(1).ToUInt();
		u_int iNumB = sCommand.Token(2).ToUInt();

		if (iNumA > m_vPerform.size() || iNumA <= 0 || iNumB > m_vPerform.size() || iNumB <= 0) {
			PutModule("Illegal # Requested");
		} else {
			std::iter_swap(m_vPerform.begin() + (iNumA - 1), m_vPerform.begin() + (iNumB - 1));
			PutModule("Commands Swapped.");
			Save();
		}
	}

public:
	MODCONSTRUCTOR(CPerform) {
		AddHelpCommand();
		AddCommand("Add",     static_cast<CModCommand::ModCmdFunc>(&CPerform::Add),
			"<command>");
		AddCommand("Del",     static_cast<CModCommand::ModCmdFunc>(&CPerform::Del),
			"<nr>");
		AddCommand("List",    static_cast<CModCommand::ModCmdFunc>(&CPerform::List));
		AddCommand("Execute", static_cast<CModCommand::ModCmdFunc>(&CPerform::Execute));
		AddCommand("Swap",    static_cast<CModCommand::ModCmdFunc>(&CPerform::Swap),
			"<nr> <nr>");
	}

	virtual ~CPerform() {}

	CString ParsePerform(const CString& sArg) const {
		CString sPerf = sArg;

		if (sPerf.Left(1) == "/")
			sPerf.LeftChomp();

		if (sPerf.Token(0).Equals("MSG")) {
			sPerf = "PRIVMSG " + sPerf.Token(1, true);
		}

		if ((sPerf.Token(0).Equals("PRIVMSG") ||
				sPerf.Token(0).Equals("NOTICE")) &&
				sPerf.Token(2).Left(1) != ":") {
			sPerf = sPerf.Token(0) + " " + sPerf.Token(1)
				+ " :" + sPerf.Token(2, true);
		}

		return sPerf;
	}

	virtual bool OnLoad(const CString& sArgs, CString& sMessage) {
		GetNV("Perform").Split("\n", m_vPerform, false);

		return true;
	}

	virtual void OnIRCConnected() {
		for (VCString::const_iterator it = m_vPerform.begin(); it != m_vPerform.end(); ++it) {
			PutIRC(GetUser()->ExpandString(*it));
		}
	}

	virtual CString GetWebMenuTitle() { return "Perform"; }

	virtual bool OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) {
		if (sPageName != "index") {
			// only accept requests to /mods/perform/
			return false;
		}

		if (WebSock.IsPost()) {
			VCString vsPerf;
			WebSock.GetRawParam("perform", true).Split("\n", vsPerf, false);
			m_vPerform.clear();

			for (VCString::const_iterator it = vsPerf.begin(); it != vsPerf.end(); ++it)
				m_vPerform.push_back(ParsePerform(*it));

			Save();
		}

		for (VCString::const_iterator it = m_vPerform.begin(); it != m_vPerform.end(); ++it) {
			CTemplate& Row = Tmpl.AddRow("PerformLoop");
			Row["Perform"] = *it;
		}

		return true;
	}

private:
	void Save() {
		CString sBuffer = "";

		for (VCString::const_iterator it = m_vPerform.begin(); it != m_vPerform.end(); ++it) {
			sBuffer += *it + "\n";
		}
		SetNV("Perform", sBuffer);
	}

	VCString m_vPerform;
};

template<> void TModInfo<CPerform>(CModInfo& Info) {
	Info.AddType(CModInfo::UserModule);
	Info.SetWikiPage("perform");
}

NETWORKMODULEDEFS(CPerform, "Keeps a list of commands to be executed when ZNC connects to IRC.")
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QApplication>
#include <QDebug>

#include "qsysteminfo.h"

using namespace QtMobility;

#define X(expr) qDebug() << #expr << "->" << (expr);

struct symbol_t
{
  const char *key;
  int val;
};

int lookup(const symbol_t *stab, const char *key, int def)
{
  for(;stab->key;++stab) {
    if(!strcmp(stab->key,key)) return stab->val;
  }
  return def;
}

const char *rlookup(const symbol_t *stab, int val, const char *def)
{
  for(;stab->key; ++stab) {
    if(stab->val == val) return stab->key;
  }
  return def;
}

#define SYM(x) { #x, x }

static const symbol_t Version_lut[] =
{
  SYM(QSystemInfo::Os),
  SYM(QSystemInfo::QtCore),
  SYM(QSystemInfo::Firmware),
  SYM(QSystemInfo::QtMobility),
  {0,0}
};

static const symbol_t Feature_lut[] =
{
  SYM(QSystemInfo::BluetoothFeature),
  SYM(QSystemInfo::CameraFeature),
  SYM(QSystemInfo::FmradioFeature),
  SYM(QSystemInfo::IrFeature),
  SYM(QSystemInfo::LedFeature),
  SYM(QSystemInfo::MemcardFeature),
  SYM(QSystemInfo::UsbFeature),
  SYM(QSystemInfo::VibFeature),
  SYM(QSystemInfo::WlanFeature),
  SYM(QSystemInfo::SimFeature),
  SYM(QSystemInfo::LocationFeature),
  SYM(QSystemInfo::VideoOutFeature),
  SYM(QSystemInfo::HapticsFeature),
 SYM(QSystemInfo::FmTransmitterFeature),
  {0,0}
};

static const symbol_t NetworkStatus_lut[] =
{
  SYM(QSystemNetworkInfo::UndefinedStatus),
  SYM(QSystemNetworkInfo::NoNetworkAvailable),
  SYM(QSystemNetworkInfo::EmergencyOnly),
  SYM(QSystemNetworkInfo::Searching),
  SYM(QSystemNetworkInfo::Busy),
  SYM(QSystemNetworkInfo::Connected),
  SYM(QSystemNetworkInfo::HomeNetwork),
  SYM(QSystemNetworkInfo::Denied),
  SYM(QSystemNetworkInfo::Roaming),
  {0,0}
};

static const symbol_t NetworkMode_lut[] =
{
  SYM(QSystemNetworkInfo::UnknownMode),
  SYM(QSystemNetworkInfo::GsmMode),
  SYM(QSystemNetworkInfo::CdmaMode),
  SYM(QSystemNetworkInfo::WcdmaMode),
  SYM(QSystemNetworkInfo::WlanMode),
  SYM(QSystemNetworkInfo::EthernetMode),
  SYM(QSystemNetworkInfo::BluetoothMode),
  SYM(QSystemNetworkInfo::WimaxMode),
  SYM(QSystemNetworkInfo::GprsMode),
  SYM(QSystemNetworkInfo::EdgeMode),
  SYM(QSystemNetworkInfo::HspaMode),
  SYM(QSystemNetworkInfo::LteMode),
  {0,0}
};

/* ------------------------------------------------------------------------- *
 * test_systeminfo
 * ------------------------------------------------------------------------- */

static void test_systeminfo(void)
{
  QSystemInfo info;

  X(info.currentLanguage());
  X(info.availableLanguages());
  X(info.currentCountryCode());

  X(info.version(QSystemInfo::Os));
  X(info.version(QSystemInfo::QtCore));
  X(info.version(QSystemInfo::Firmware));
  X(info.version(QSystemInfo::QtMobility));

  X(info.hasFeatureSupported(QSystemInfo::BluetoothFeature));
  X(info.hasFeatureSupported(QSystemInfo::CameraFeature));
  X(info.hasFeatureSupported(QSystemInfo::FmradioFeature));
  X(info.hasFeatureSupported(QSystemInfo::IrFeature));
  X(info.hasFeatureSupported(QSystemInfo::LedFeature));
  X(info.hasFeatureSupported(QSystemInfo::MemcardFeature));
  X(info.hasFeatureSupported(QSystemInfo::UsbFeature));
  X(info.hasFeatureSupported(QSystemInfo::VibFeature));
  X(info.hasFeatureSupported(QSystemInfo::WlanFeature));
  X(info.hasFeatureSupported(QSystemInfo::SimFeature));
  X(info.hasFeatureSupported(QSystemInfo::LocationFeature));
  X(info.hasFeatureSupported(QSystemInfo::VideoOutFeature));
  X(info.hasFeatureSupported(QSystemInfo::HapticsFeature));
  X(info.hasFeatureSupported(QSystemInfo::FmTransmitterFeature));
}

/* ------------------------------------------------------------------------- *
 * test_systemdeviceinfo
 * ------------------------------------------------------------------------- */

static void test_systemdeviceinfo(void)
{
  QSystemDeviceInfo deviceinfo;

  X(deviceinfo.batteryLevel());
  X(deviceinfo.batteryStatus());
  X(deviceinfo.currentBluetoothPowerState());
  X(deviceinfo.currentPowerState());
  X(deviceinfo.currentProfile());
  X(deviceinfo.imei());
  X(deviceinfo.imsi());
  X(deviceinfo.inputMethodType());
  X(deviceinfo.isDeviceLocked());
  X(deviceinfo.isKeyboardFlipOpen());
  X(deviceinfo.isWirelessKeyboardConnected());
  X(deviceinfo.keyboardType());
  X(deviceinfo.manufacturer());
  X(deviceinfo.model());
  X(deviceinfo.productName());
  X(deviceinfo.simStatus());
  X(deviceinfo.typeOfLock());
}

/* ------------------------------------------------------------------------- *
 * test_systemdisplayinfo
 * ------------------------------------------------------------------------- */

static void test_systemdisplayinfo(void)
{
  QSystemDisplayInfo displayinfo;

  for( int display = 0; display < 4; ++display )
  {
    qDebug() << "";
    qDebug() << "Display:" << display;
    int depth = displayinfo.colorDepth(display);
    qDebug() << "  displayinfo.colorDepth() ->" << depth;
    int value = displayinfo.displayBrightness(display);
    qDebug() << "  displayinfo.displayBrightness() ->" << value;
    QSystemDisplayInfo::DisplayOrientation orientation = displayinfo.getOrientation(display);
    qDebug() << "  displayinfo.getOrientation() ->" << orientation;
    float contrast = displayinfo.contrast(display);
    qDebug() << "  displayinfo.getContrast() ->" << contrast;
    int dpiWidth = displayinfo.getDPIWidth(display);
    qDebug() << "  displayinfo.getDPIWidth() ->" << dpiWidth;
    int dpiHeight = displayinfo.getDPIHeight(display);
    qDebug() << "  displayinfo.getDPIHeight() ->" << dpiHeight;
    int physicalHeight = displayinfo.physicalHeight(display);
    qDebug() << "  displayinfo.physicalHeight() ->" << physicalHeight;
    int physicalWidth = displayinfo.physicalWidth(display);
    qDebug() << "  displayinfo.physicalWidth() ->" << physicalWidth;
  }
}

/* ------------------------------------------------------------------------- *
 * test_systemstorageinfo
 * ------------------------------------------------------------------------- */

static const char *human_size(qlonglong n)
{
  if(n == 0) return "0B";

  static char buf[256];
  char *pos = buf;
  char *end = buf + sizeof buf;

  int b = n & 1023; n >>= 10;
  int k = n & 1023; n >>= 10;
  int m = n & 1023; n >>= 10;
  int g = n & 1023; n >>= 10;

  *pos = 0;
  if(g) snprintf(pos, end-pos, "%s%dGB", *buf?" ":"", g), pos = strchr(pos,0);
  if(m) snprintf(pos, end-pos, "%s%dMB", *buf?" ":"", m), pos = strchr(pos,0);
  if(k) snprintf(pos, end-pos, "%s%dkB", *buf?" ":"", k), pos = strchr(pos,0);
  if(b) snprintf(pos, end-pos, "%s%dB",  *buf?" ":"", b), pos = strchr(pos,0);

  return buf;
}

static void test_systemstorageinfo(void)
{
  QSystemStorageInfo storageinfo;

  QStringList lst = storageinfo.logicalDrives();

  qDebug() << "storageinfo.logicalDrives ->" << lst;

  for(int i = 0; i < lst.size(); ++i) {
    const QString &drv = lst.at(i);

    qDebug() << "Logical drive:" << drv;

    qlonglong avail = storageinfo.availableDiskSpace(drv);
    qDebug() << "  storageinfo.availableDiskSpace() ->" << human_size(avail);

    qlonglong total = storageinfo.totalDiskSpace(drv);
    qDebug() << "  storageinfo.totalDiskSpace() ->" << human_size(total);

    QSystemStorageInfo::DriveType dtype = storageinfo.typeForDrive(drv);
    qDebug() << "  storageinfo.typeForDrive() ->" << dtype;

    QString duri = storageinfo.uriForDrive(drv);
    qDebug() << "  storageinfo.uriForDrive() ->" << duri;

    QSystemStorageInfo::StorageState dstate = storageinfo.getStorageState(drv);
    qDebug() << "  storageinfo.getStorageState() ->" << dstate;
  }
}

/* ------------------------------------------------------------------------- *
 * test_systemnetworkinfo
 * ------------------------------------------------------------------------- */

static void test_systemnetworkinfo(void)
{
  QSystemNetworkInfo networkinfo;

  X(networkinfo.cellId());
  X(networkinfo.currentMobileCountryCode());
  X(networkinfo.currentMobileNetworkCode());
  X(networkinfo.homeMobileCountryCode());
  X(networkinfo.homeMobileNetworkCode());
  X(networkinfo.locationAreaCode());

  for(const symbol_t *sym = NetworkMode_lut; sym->key; ++sym) {
    QtMobility::QSystemNetworkInfo::NetworkMode mode =
    (QtMobility::QSystemNetworkInfo::NetworkMode) sym->val;

    qDebug() << "";
    qDebug() << "NetworkMode:" << sym->key;

    QNetworkInterface iface = networkinfo.interfaceForMode(mode);
    qDebug() << "  networkinfo.interfaceForMode() ->" << iface;

    QString macaddr = networkinfo.macAddress(mode);
    qDebug() << "  networkinfo.macAddress() ->" << macaddr;

    QSystemNetworkInfo::NetworkStatus status = networkinfo.networkStatus(mode);
    qDebug() << "  networkinfo.networkStatus() ->" << status;

    QString network = networkinfo.networkName(mode);
    qDebug() << "  networkinfo.networkName() ->" << network;

    int sigstr = networkinfo.networkSignalStrength(mode);
    qDebug() << "  networkinfo.networkSignalStrength() ->" << sigstr;
  }
}

static void test_systemscreensaver(void)
{
  QSystemScreenSaver screensaver;

  X(screensaver.screenSaverInhibited());
  X(screensaver.setScreenSaverInhibit());
}

struct dummy_t
{
  const char *name;
  void (*func)(void);
} lut[] = {
#define ADD(x) {#x, test_##x }
  ADD(systeminfo),
  ADD(systemdeviceinfo),
  ADD(systemstorageinfo),
  ADD(systemnetworkinfo),
  ADD(systemscreensaver),
  ADD(systemdisplayinfo),
#undef ADD
  {0,0}
};

static bool endswith(const char *str, const char *pat)
{
  int slen = strlen(str);
  int plen = strlen(pat);
  return (slen >= plen) && !strcmp(str+slen-plen, pat);
}

int lookup_test(const char *name)
{
  for(int i = 0; lut[i].name; ++i) {
    if(!strcmp(lut[i].name, name)) return i;
  }
  for(int i = 0; lut[i].name; ++i) {
    if(endswith(lut[i].name, name)) return i;
  }
  for(int i = 0; lut[i].name; ++i) {
    if(strstr(lut[i].name, name)) return i;
  }
  return -1;
}

int main(int ac, char **av)
{
  if(!getenv("DISPLAY")) {
    qDebug() << "$DISPLAY not set, assuming :0";
    setenv("DISPLAY", ":0", 1);
  }
  if(!getenv("DBUS_SESSION_BUS_ADDRESS")) {
    qDebug() << "session bus not configured";
  }

  QApplication app(ac, av, true);

  if(ac < 2) {
    qDebug() << "available tests:";
    for(int k = 0; lut[k].name; ++k) {
      qDebug() << *av << lut[k].name;
    }
    exit(0);
  }

  for(int i = 1; i < ac; ++i) {
    const char *name = av[i];

    int k = lookup_test(name);

    if(k != -1) {
      qDebug() << "";
      qDebug() << "----(" << lut[k].name << ")----";
      qDebug() << "";
      lut[k].func();
    } else if( !strcmp(name, "all")) {
      for(int k = 0; lut[k].name; ++k) {
        qDebug() << "";
        qDebug() << "----(" << lut[k].name << ")----";
        qDebug() << "";
        lut[k].func();
      }
    } else {
      break;
    }
  }
}

// EOF
<commit_msg>fix build on windows<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QApplication>
#include <QDebug>

#include "qsysteminfo.h"

using namespace QtMobility;

#define X(expr) qDebug() << #expr << "->" << (expr);

struct symbol_t
{
  const char *key;
  int val;
};

int lookup(const symbol_t *stab, const char *key, int def)
{
  for(;stab->key;++stab) {
    if(!strcmp(stab->key,key)) return stab->val;
  }
  return def;
}

const char *rlookup(const symbol_t *stab, int val, const char *def)
{
  for(;stab->key; ++stab) {
    if(stab->val == val) return stab->key;
  }
  return def;
}

#define SYM(x) { #x, x }

static const symbol_t Version_lut[] =
{
  SYM(QSystemInfo::Os),
  SYM(QSystemInfo::QtCore),
  SYM(QSystemInfo::Firmware),
  SYM(QSystemInfo::QtMobility),
  {0,0}
};

static const symbol_t Feature_lut[] =
{
  SYM(QSystemInfo::BluetoothFeature),
  SYM(QSystemInfo::CameraFeature),
  SYM(QSystemInfo::FmradioFeature),
  SYM(QSystemInfo::IrFeature),
  SYM(QSystemInfo::LedFeature),
  SYM(QSystemInfo::MemcardFeature),
  SYM(QSystemInfo::UsbFeature),
  SYM(QSystemInfo::VibFeature),
  SYM(QSystemInfo::WlanFeature),
  SYM(QSystemInfo::SimFeature),
  SYM(QSystemInfo::LocationFeature),
  SYM(QSystemInfo::VideoOutFeature),
  SYM(QSystemInfo::HapticsFeature),
 SYM(QSystemInfo::FmTransmitterFeature),
  {0,0}
};

static const symbol_t NetworkStatus_lut[] =
{
  SYM(QSystemNetworkInfo::UndefinedStatus),
  SYM(QSystemNetworkInfo::NoNetworkAvailable),
  SYM(QSystemNetworkInfo::EmergencyOnly),
  SYM(QSystemNetworkInfo::Searching),
  SYM(QSystemNetworkInfo::Busy),
  SYM(QSystemNetworkInfo::Connected),
  SYM(QSystemNetworkInfo::HomeNetwork),
  SYM(QSystemNetworkInfo::Denied),
  SYM(QSystemNetworkInfo::Roaming),
  {0,0}
};

static const symbol_t NetworkMode_lut[] =
{
  SYM(QSystemNetworkInfo::UnknownMode),
  SYM(QSystemNetworkInfo::GsmMode),
  SYM(QSystemNetworkInfo::CdmaMode),
  SYM(QSystemNetworkInfo::WcdmaMode),
  SYM(QSystemNetworkInfo::WlanMode),
  SYM(QSystemNetworkInfo::EthernetMode),
  SYM(QSystemNetworkInfo::BluetoothMode),
  SYM(QSystemNetworkInfo::WimaxMode),
  SYM(QSystemNetworkInfo::GprsMode),
  SYM(QSystemNetworkInfo::EdgeMode),
  SYM(QSystemNetworkInfo::HspaMode),
  SYM(QSystemNetworkInfo::LteMode),
  {0,0}
};

/* ------------------------------------------------------------------------- *
 * test_systeminfo
 * ------------------------------------------------------------------------- */

static void test_systeminfo(void)
{
  QSystemInfo info;

  X(info.currentLanguage());
  X(info.availableLanguages());
  X(info.currentCountryCode());

  X(info.version(QSystemInfo::Os));
  X(info.version(QSystemInfo::QtCore));
  X(info.version(QSystemInfo::Firmware));
  X(info.version(QSystemInfo::QtMobility));

  X(info.hasFeatureSupported(QSystemInfo::BluetoothFeature));
  X(info.hasFeatureSupported(QSystemInfo::CameraFeature));
  X(info.hasFeatureSupported(QSystemInfo::FmradioFeature));
  X(info.hasFeatureSupported(QSystemInfo::IrFeature));
  X(info.hasFeatureSupported(QSystemInfo::LedFeature));
  X(info.hasFeatureSupported(QSystemInfo::MemcardFeature));
  X(info.hasFeatureSupported(QSystemInfo::UsbFeature));
  X(info.hasFeatureSupported(QSystemInfo::VibFeature));
  X(info.hasFeatureSupported(QSystemInfo::WlanFeature));
  X(info.hasFeatureSupported(QSystemInfo::SimFeature));
  X(info.hasFeatureSupported(QSystemInfo::LocationFeature));
  X(info.hasFeatureSupported(QSystemInfo::VideoOutFeature));
  X(info.hasFeatureSupported(QSystemInfo::HapticsFeature));
  X(info.hasFeatureSupported(QSystemInfo::FmTransmitterFeature));
}

/* ------------------------------------------------------------------------- *
 * test_systemdeviceinfo
 * ------------------------------------------------------------------------- */

static void test_systemdeviceinfo(void)
{
  QSystemDeviceInfo deviceinfo;

  X(deviceinfo.batteryLevel());
  X(deviceinfo.batteryStatus());
  X(deviceinfo.currentBluetoothPowerState());
  X(deviceinfo.currentPowerState());
  X(deviceinfo.currentProfile());
  X(deviceinfo.imei());
  X(deviceinfo.imsi());
  X(deviceinfo.inputMethodType());
  X(deviceinfo.isDeviceLocked());
  X(deviceinfo.isKeyboardFlipOpen());
  X(deviceinfo.isWirelessKeyboardConnected());
  X(deviceinfo.keyboardType());
  X(deviceinfo.manufacturer());
  X(deviceinfo.model());
  X(deviceinfo.productName());
  X(deviceinfo.simStatus());
  X(deviceinfo.typeOfLock());
}

/* ------------------------------------------------------------------------- *
 * test_systemdisplayinfo
 * ------------------------------------------------------------------------- */

static void test_systemdisplayinfo(void)
{
  QSystemDisplayInfo displayinfo;

  for( int display = 0; display < 4; ++display )
  {
    qDebug() << "";
    qDebug() << "Display:" << display;
    int depth = displayinfo.colorDepth(display);
    qDebug() << "  displayinfo.colorDepth() ->" << depth;
    int value = displayinfo.displayBrightness(display);
    qDebug() << "  displayinfo.displayBrightness() ->" << value;
    QSystemDisplayInfo::DisplayOrientation orientation = displayinfo.getOrientation(display);
    qDebug() << "  displayinfo.getOrientation() ->" << orientation;
    float contrast = displayinfo.contrast(display);
    qDebug() << "  displayinfo.getContrast() ->" << contrast;
    int dpiWidth = displayinfo.getDPIWidth(display);
    qDebug() << "  displayinfo.getDPIWidth() ->" << dpiWidth;
    int dpiHeight = displayinfo.getDPIHeight(display);
    qDebug() << "  displayinfo.getDPIHeight() ->" << dpiHeight;
    int physicalHeight = displayinfo.physicalHeight(display);
    qDebug() << "  displayinfo.physicalHeight() ->" << physicalHeight;
    int physicalWidth = displayinfo.physicalWidth(display);
    qDebug() << "  displayinfo.physicalWidth() ->" << physicalWidth;
  }
}

/* ------------------------------------------------------------------------- *
 * test_systemstorageinfo
 * ------------------------------------------------------------------------- */

static const char *human_size(qlonglong n)
{
  if(n == 0) return "0B";

  static char buf[256];
  char *pos = buf;
  char *end = buf + sizeof buf;

  int b = n & 1023; n >>= 10;
  int k = n & 1023; n >>= 10;
  int m = n & 1023; n >>= 10;
  int g = n & 1023; n >>= 10;

  *pos = 0;
#if defined(Q_WS_WIN)
  if(g) _snprintf_s(pos, sizeof(pos), end-pos,"%s%dGB", *buf?" ":"", g), pos = strchr(pos,0);
  if(m) _snprintf_s(pos, sizeof(pos), end-pos,"%s%dMB", *buf?" ":"", m), pos = strchr(pos,0);
  if(k) _snprintf_s(pos, sizeof(pos), end-pos,"%s%dkB", *buf?" ":"", k), pos = strchr(pos,0);
  if(b) _snprintf_s(pos, sizeof(pos), end-pos,"%s%dB",  *buf?" ":"", b), pos = strchr(pos,0);
#else
  if(g) snprintf(pos, end-pos, "%s%dGB", *buf?" ":"", g), pos = strchr(pos,0);
  if(m) snprintf(pos, end-pos, "%s%dMB", *buf?" ":"", m), pos = strchr(pos,0);
  if(k) snprintf(pos, end-pos, "%s%dkB", *buf?" ":"", k), pos = strchr(pos,0);
  if(b) snprintf(pos, end-pos, "%s%dB",  *buf?" ":"", b), pos = strchr(pos,0);
#endif
  return buf;
}

static void test_systemstorageinfo(void)
{
  QSystemStorageInfo storageinfo;

  QStringList lst = storageinfo.logicalDrives();

  qDebug() << "storageinfo.logicalDrives ->" << lst;

  for(int i = 0; i < lst.size(); ++i) {
    const QString &drv = lst.at(i);

    qDebug() << "Logical drive:" << drv;

    qlonglong avail = storageinfo.availableDiskSpace(drv);
    qDebug() << "  storageinfo.availableDiskSpace() ->" << human_size(avail);

    qlonglong total = storageinfo.totalDiskSpace(drv);
    qDebug() << "  storageinfo.totalDiskSpace() ->" << human_size(total);

    QSystemStorageInfo::DriveType dtype = storageinfo.typeForDrive(drv);
    qDebug() << "  storageinfo.typeForDrive() ->" << dtype;

    QString duri = storageinfo.uriForDrive(drv);
    qDebug() << "  storageinfo.uriForDrive() ->" << duri;

    QSystemStorageInfo::StorageState dstate = storageinfo.getStorageState(drv);
    qDebug() << "  storageinfo.getStorageState() ->" << dstate;
  }
}

/* ------------------------------------------------------------------------- *
 * test_systemnetworkinfo
 * ------------------------------------------------------------------------- */

static void test_systemnetworkinfo(void)
{
  QSystemNetworkInfo networkinfo;

  X(networkinfo.cellId());
  X(networkinfo.currentMobileCountryCode());
  X(networkinfo.currentMobileNetworkCode());
  X(networkinfo.homeMobileCountryCode());
  X(networkinfo.homeMobileNetworkCode());
  X(networkinfo.locationAreaCode());

  for(const symbol_t *sym = NetworkMode_lut; sym->key; ++sym) {
    QtMobility::QSystemNetworkInfo::NetworkMode mode =
    (QtMobility::QSystemNetworkInfo::NetworkMode) sym->val;

    qDebug() << "";
    qDebug() << "NetworkMode:" << sym->key;

    QNetworkInterface iface = networkinfo.interfaceForMode(mode);
    qDebug() << "  networkinfo.interfaceForMode() ->" << iface;

    QString macaddr = networkinfo.macAddress(mode);
    qDebug() << "  networkinfo.macAddress() ->" << macaddr;

    QSystemNetworkInfo::NetworkStatus status = networkinfo.networkStatus(mode);
    qDebug() << "  networkinfo.networkStatus() ->" << status;

    QString network = networkinfo.networkName(mode);
    qDebug() << "  networkinfo.networkName() ->" << network;

    int sigstr = networkinfo.networkSignalStrength(mode);
    qDebug() << "  networkinfo.networkSignalStrength() ->" << sigstr;
  }
}

static void test_systemscreensaver(void)
{
  QSystemScreenSaver screensaver;

  X(screensaver.screenSaverInhibited());
  X(screensaver.setScreenSaverInhibit());
}

struct dummy_t
{
  const char *name;
  void (*func)(void);
} lut[] = {
#define ADD(x) {#x, test_##x }
  ADD(systeminfo),
  ADD(systemdeviceinfo),
  ADD(systemstorageinfo),
  ADD(systemnetworkinfo),
  ADD(systemscreensaver),
  ADD(systemdisplayinfo),
#undef ADD
  {0,0}
};

static bool endswith(const char *str, const char *pat)
{
  int slen = strlen(str);
  int plen = strlen(pat);
  return (slen >= plen) && !strcmp(str+slen-plen, pat);
}

int lookup_test(const char *name)
{
  for(int i = 0; lut[i].name; ++i) {
    if(!strcmp(lut[i].name, name)) return i;
  }
  for(int i = 0; lut[i].name; ++i) {
    if(endswith(lut[i].name, name)) return i;
  }
  for(int i = 0; lut[i].name; ++i) {
    if(strstr(lut[i].name, name)) return i;
  }
  return -1;
}

int main(int ac, char **av)
{
#if !defined(Q_WS_WIN)
    if(!getenv("DISPLAY")) {
    qDebug() << "$DISPLAY not set, assuming :0";
    setenv("DISPLAY", ":0", 1);
  }
  if(!getenv("DBUS_SESSION_BUS_ADDRESS")) {
    qDebug() << "session bus not configured";
  }
#endif
  QApplication app(ac, av, true);

  if(ac < 2) {
    qDebug() << "available tests:";
    for(int k = 0; lut[k].name; ++k) {
      qDebug() << *av << lut[k].name;
    }
    exit(0);
  }

  for(int i = 1; i < ac; ++i) {
    const char *name = av[i];

    int k = lookup_test(name);

    if(k != -1) {
      qDebug() << "";
      qDebug() << "----(" << lut[k].name << ")----";
      qDebug() << "";
      lut[k].func();
    } else if( !strcmp(name, "all")) {
      for(int k = 0; lut[k].name; ++k) {
        qDebug() << "";
        qDebug() << "----(" << lut[k].name << ")----";
        qDebug() << "";
        lut[k].func();
      }
    } else {
      break;
    }
  }
}

// EOF
<|endoftext|>