<commit_before>/**
 * @file ica.cpp
 *
 * Implementation of ICA (Hyvarinen, 1999).
 */
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "ica.h"
#include "logger.h"
#include "math_utils.h"
#include "pca.h"
#include "timer.h"

typedef Matrix (*ica_nonl_func_t)(const Matrix& , const Matrix& );

/**
 * Construct an ICA layer.
 *
 * @param n1
 * @param n2
 * @param nonl
 * @param max_iter
 * @param eps
 */
ICALayer::ICALayer(int n1, int n2, ica_nonl_t nonl, int max_iter, precision_t eps)
{
	this->n1 = n1;
	this->n2 = n2;
	this->nonl = nonl;
	this->max_iter = max_iter;
	this->eps = eps;
}

/**
 * Compute the independent components of a matrix X, which
 * consists of observations in columns.
 *
 * @param X
 * @param y
 * @param c
 */
void ICALayer::compute(const Matrix& X, const std::vector<data_entry_t>& y, int c)
{
	timer_push("ICA");

	timer_push("subtract mean from input matrix");

	// compute mixedsig = X', subtract mean column
	Matrix mixedsig = X.transpose("mixedsig");
	Matrix mixedmean = mixedsig.mean_column("mixedmean");

	mixedsig.subtract_columns(mixedmean);

	timer_pop();

	timer_push("compute whitening matrix and whitened input matrix");

	// compute whitening matrix W_z = inv(sqrt(D)) * W_pca'
	PCALayer pca(this->n1);

	pca.compute(mixedsig, y, c);

	Matrix D = pca.D;
	D.elem_apply(sqrtf);
	D = D.inverse(D.name());

	Matrix W_z = D * TRAN(pca.W);

	// compute whitened input U = W_z * mixedsig
	Matrix U = W_z * mixedsig;

	timer_pop();

	timer_push("compute mixing matrix");

	// compute mixing matrix
	Matrix W_mix = this->fpica(U, W_z);

	timer_pop();

	timer_push("compute ICA projection matrix");

	// compute independent components
	// icasig = W_mix * (mixedsig + mixedmean * ones(1, mixedsig.cols()))
	Matrix icasig_temp1 = mixedmean * Matrix::ones("", 1, mixedsig.cols());
	icasig_temp1 += mixedsig;

	Matrix icasig = W_mix * icasig_temp1;

	// compute W_ica = icasig'
	this->W = icasig.transpose("W_ica");

	timer_pop();

	timer_pop();
}

/**
 * Project a matrix X into the feature space of an ICA layer.
 *
 * @param X
 */
Matrix ICALayer::project(const Matrix& X)
{
	return TRAN(this->W) * X;
}

/**
 * Save an ICA layer to a file.
 *
 * @param file
 */
void ICALayer::save(FILE *file)
{
	this->W.save(file);
}

/**
 * Load an ICA layer from a file.
 *
 * @param file
 */
void ICALayer::load(FILE *file)
{
	this->W.load(file);
}

/**
 * Print information about an ICA layer.
 */
void ICALayer::print()
{
	const char *nonl_name = "";

	if ( this->nonl == ICA_NONL_POW3 ) {
		nonl_name = "pow3";
	}
	else if ( this->nonl == ICA_NONL_TANH ) {
		nonl_name = "tanh";
	}
	else if ( this->nonl == ICA_NONL_GAUSS ) {
		nonl_name = "gauss";
	}

	log(LL_VERBOSE, "ICA\n");
	log(LL_VERBOSE, "  %-20s  %10d\n", "n1", this->n1);
	log(LL_VERBOSE, "  %-20s  %10d\n", "n2", this->n2);
	log(LL_VERBOSE, "  %-20s  %10s\n", "nonl", nonl_name);
	log(LL_VERBOSE, "  %-20s  %10d\n", "max_iter", this->max_iter);
	log(LL_VERBOSE, "  %-20s  %10f\n", "eps", this->eps);
}

/**
 * Compute the parameter update for fpica
 * with the pow3 nonlinearity:
 *
 * g(u) = u^3
 * g'(u) = 3 * u^2
 *
 * which gives:
 *
 * w+ = X * ((X' * w) .^ 3) / X.cols() - 3 * w
 *
 * @param w0
 * @param X
 */
Matrix fpica_pow3 (const Matrix& w0, const Matrix& X)
{
	Matrix w_temp1 = TRAN(X) * w0;
	w_temp1.elem_apply(pow3);

	Matrix w = X * w_temp1;
	w /= X.cols();
	w -= 3 * w0;

	return w;
}

/**
 * Compute the parameter update for fpica
 * with the tanh nonlinearity:
 *
 * g(u) = tanh(u)
 * g'(u) = sech(u)^2 = 1 - tanh(u)^2
 *
 * which gives:
 *
 * w+ = (X * g(X' * w) - sum(g'(X' * w)) * w) / X.cols()
 *
 * @param w0
 * @param X
 */
Matrix fpica_tanh (const Matrix& w0, const Matrix& X)
{
	Matrix w_temp1 = TRAN(X) * w0;
	Matrix w_temp2 = w_temp1;

	w_temp1.elem_apply(tanhf);
	w_temp2.elem_apply(sechf);
	w_temp2.elem_apply(pow2);

	Matrix w = X * w_temp1;
	w -= w_temp2.sum() * w0;
	w /= X.cols();

	return w;
}

/**
 * Gaussian nonlinearity function.
 *
 * @param x
 */
precision_t gauss (precision_t x)
{
	return x * expf(-(x * x) / 2.0f);
}

/**
 * Derivative of the Gaussian nonlinearity function.
 *
 * @param x
 */
precision_t dgauss (precision_t x)
{
	return (1 - x * x) * expf(-(x * x) / 2.0f);
}

/**
 * Compute the parameter update for fpica
 * with the Gaussian nonlinearity:
 *
 * g(u) = u * exp(-u^2 / 2)
 * g'(u) = (1 - u^2) * exp(-u^2 / 2)
 *
 * which gives:
 *
 * w+ = (X * g(X' * w) - sum(g'(X' * w)) * w) / X.cols()
 *
 * @param w0
 * @param X
 */
Matrix fpica_gauss (const Matrix& w0, const Matrix& X)
{
	Matrix w_temp1 = TRAN(X) * w0;
	Matrix w_temp2 = w_temp1;

	w_temp1.elem_apply(tanhf);
	w_temp2.elem_apply(sechf);
	w_temp2.elem_apply(pow2);

	Matrix w = X * w_temp1;
	w -= w_temp2.sum() * w0;
	w /= X.cols();

	return w;
}

/**
 * Compute the mixing matrix W_mix for an input matrix X using
 * the deflation approach. The input matrix should already
 * be whitened.
 *
 * @param X
 * @param W_z
 */
Matrix ICALayer::fpica(const Matrix& X, const Matrix& W_z)
{
	// if n2 is -1, use default value
	int n2 = (this->n2 == -1)
		? X.rows()
		: min(X.rows(), this->n2);

	// determine nonlinearity function
	ica_nonl_func_t fpica_update = nullptr;

	if ( this->nonl == ICA_NONL_POW3 ) {
		fpica_update = fpica_pow3;
	}
	else if ( this->nonl == ICA_NONL_TANH ) {
		fpica_update = fpica_tanh;
	}
	else if ( this->nonl == ICA_NONL_GAUSS ) {
		fpica_update = fpica_gauss;
	}

	Matrix B = Matrix::zeros("B", n2, n2);
	Matrix W_mix = Matrix::zeros("W_mix", n2, W_z.cols());

	int i;
	for ( i = 0; i < n2; i++ ) {
		log(LL_VERBOSE, "      round %d\n", i + 1);

		// initialize w as a Gaussian (0, 1) random vector
		Matrix w = Matrix::random("w", n2, 1);

		// compute w = w - B * B' * w, normalize w
		w -= B * TRAN(B) * w;
		w /= w.norm();

		// initialize w0
		Matrix w0 = Matrix::zeros("w0", w.rows(), w.cols());

		int j;
		for ( j = 0; j < this->max_iter; j++ ) {
			// compute w = w - B * B' * w, normalize w
			w -= B * TRAN(B) * w;
			w /= w.norm();

			// determine whether the direction of w and w0 are equal
			precision_t norm1 = (w - w0).norm();
			precision_t norm2 = (w + w0).norm();

			// terminate round if w converges
			if ( norm1 < this->eps || norm2 < this->eps ) {
				// save B(:, i) = w
				B.assign_column(i, w, 0);

				// save W_mix(i, :) = w' * W_z
				W_mix.assign_row(i, TRAN(w) * W_z, 0);

				// continue to the next round
				break;
			}

			// update w0
			w0.assign_column(0, w, 0);

			// compute w+ based on non-linearity
			w = fpica_update(w0, X);

			// compute w* = w+ / ||w+||
			w /= w.norm();
		}

		log(LL_VERBOSE, "      iterations: %d\n", j);
	}

	return W_mix;
}
<commit_msg>Fixed bug in fpica_gauss<commit_after>/**
 * @file ica.cpp
 *
 * Implementation of ICA (Hyvarinen, 1999).
 */
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "ica.h"
#include "logger.h"
#include "math_utils.h"
#include "pca.h"
#include "timer.h"

typedef Matrix (*ica_nonl_func_t)(const Matrix& , const Matrix& );

/**
 * Construct an ICA layer.
 *
 * @param n1
 * @param n2
 * @param nonl
 * @param max_iter
 * @param eps
 */
ICALayer::ICALayer(int n1, int n2, ica_nonl_t nonl, int max_iter, precision_t eps)
{
	this->n1 = n1;
	this->n2 = n2;
	this->nonl = nonl;
	this->max_iter = max_iter;
	this->eps = eps;
}

/**
 * Compute the independent components of a matrix X, which
 * consists of observations in columns.
 *
 * @param X
 * @param y
 * @param c
 */
void ICALayer::compute(const Matrix& X, const std::vector<data_entry_t>& y, int c)
{
	timer_push("ICA");

	timer_push("subtract mean from input matrix");

	// compute mixedsig = X', subtract mean column
	Matrix mixedsig = X.transpose("mixedsig");
	Matrix mixedmean = mixedsig.mean_column("mixedmean");

	mixedsig.subtract_columns(mixedmean);

	timer_pop();

	timer_push("compute whitening matrix and whitened input matrix");

	// compute whitening matrix W_z = inv(sqrt(D)) * W_pca'
	PCALayer pca(this->n1);

	pca.compute(mixedsig, y, c);

	Matrix D = pca.D;
	D.elem_apply(sqrtf);
	D = D.inverse(D.name());

	Matrix W_z = D * TRAN(pca.W);

	// compute whitened input U = W_z * mixedsig
	Matrix U = W_z * mixedsig;

	timer_pop();

	timer_push("compute mixing matrix");

	// compute mixing matrix
	Matrix W_mix = this->fpica(U, W_z);

	timer_pop();

	timer_push("compute ICA projection matrix");

	// compute independent components
	// icasig = W_mix * (mixedsig + mixedmean * ones(1, mixedsig.cols()))
	Matrix icasig_temp1 = mixedmean * Matrix::ones("", 1, mixedsig.cols());
	icasig_temp1 += mixedsig;

	Matrix icasig = W_mix * icasig_temp1;

	// compute W_ica = icasig'
	this->W = icasig.transpose("W_ica");

	timer_pop();

	timer_pop();
}

/**
 * Project a matrix X into the feature space of an ICA layer.
 *
 * @param X
 */
Matrix ICALayer::project(const Matrix& X)
{
	return TRAN(this->W) * X;
}

/**
 * Save an ICA layer to a file.
 *
 * @param file
 */
void ICALayer::save(FILE *file)
{
	this->W.save(file);
}

/**
 * Load an ICA layer from a file.
 *
 * @param file
 */
void ICALayer::load(FILE *file)
{
	this->W.load(file);
}

/**
 * Print information about an ICA layer.
 */
void ICALayer::print()
{
	const char *nonl_name = "";

	if ( this->nonl == ICA_NONL_POW3 ) {
		nonl_name = "pow3";
	}
	else if ( this->nonl == ICA_NONL_TANH ) {
		nonl_name = "tanh";
	}
	else if ( this->nonl == ICA_NONL_GAUSS ) {
		nonl_name = "gauss";
	}

	log(LL_VERBOSE, "ICA\n");
	log(LL_VERBOSE, "  %-20s  %10d\n", "n1", this->n1);
	log(LL_VERBOSE, "  %-20s  %10d\n", "n2", this->n2);
	log(LL_VERBOSE, "  %-20s  %10s\n", "nonl", nonl_name);
	log(LL_VERBOSE, "  %-20s  %10d\n", "max_iter", this->max_iter);
	log(LL_VERBOSE, "  %-20s  %10f\n", "eps", this->eps);
}

/**
 * Compute the parameter update for fpica
 * with the pow3 nonlinearity:
 *
 * g(u) = u^3
 * g'(u) = 3 * u^2
 *
 * which gives:
 *
 * w+ = X * ((X' * w) .^ 3) / X.cols() - 3 * w
 *
 * @param w0
 * @param X
 */
Matrix fpica_pow3 (const Matrix& w0, const Matrix& X)
{
	Matrix w_temp1 = TRAN(X) * w0;
	w_temp1.elem_apply(pow3);

	Matrix w = X * w_temp1;
	w /= X.cols();
	w -= 3 * w0;

	return w;
}

/**
 * Compute the parameter update for fpica
 * with the tanh nonlinearity:
 *
 * g(u) = tanh(u)
 * g'(u) = sech(u)^2 = 1 - tanh(u)^2
 *
 * which gives:
 *
 * w+ = (X * g(X' * w) - sum(g'(X' * w)) * w) / X.cols()
 *
 * @param w0
 * @param X
 */
Matrix fpica_tanh (const Matrix& w0, const Matrix& X)
{
	Matrix w_temp1 = TRAN(X) * w0;
	Matrix w_temp2 = w_temp1;

	w_temp1.elem_apply(tanhf);
	w_temp2.elem_apply(sechf);
	w_temp2.elem_apply(pow2);

	Matrix w = X * w_temp1;
	w -= w_temp2.sum() * w0;
	w /= X.cols();

	return w;
}

/**
 * Gaussian nonlinearity function.
 *
 * @param x
 */
precision_t gauss (precision_t x)
{
	return x * expf(-(x * x) / 2.0f);
}

/**
 * Derivative of the Gaussian nonlinearity function.
 *
 * @param x
 */
precision_t dgauss (precision_t x)
{
	return (1 - x * x) * expf(-(x * x) / 2.0f);
}

/**
 * Compute the parameter update for fpica
 * with the Gaussian nonlinearity:
 *
 * g(u) = u * exp(-u^2 / 2)
 * g'(u) = (1 - u^2) * exp(-u^2 / 2)
 *
 * which gives:
 *
 * w+ = (X * g(X' * w) - sum(g'(X' * w)) * w) / X.cols()
 *
 * @param w0
 * @param X
 */
Matrix fpica_gauss (const Matrix& w0, const Matrix& X)
{
	Matrix w_temp1 = TRAN(X) * w0;
	Matrix w_temp2 = w_temp1;

	w_temp1.elem_apply(gauss);
	w_temp2.elem_apply(dgauss);

	Matrix w = X * w_temp1;
	w -= w_temp2.sum() * w0;
	w /= X.cols();

	return w;
}

/**
 * Compute the mixing matrix W_mix for an input matrix X using
 * the deflation approach. The input matrix should already
 * be whitened.
 *
 * @param X
 * @param W_z
 */
Matrix ICALayer::fpica(const Matrix& X, const Matrix& W_z)
{
	// if n2 is -1, use default value
	int n2 = (this->n2 == -1)
		? X.rows()
		: min(X.rows(), this->n2);

	// determine nonlinearity function
	ica_nonl_func_t fpica_update = nullptr;

	if ( this->nonl == ICA_NONL_POW3 ) {
		fpica_update = fpica_pow3;
	}
	else if ( this->nonl == ICA_NONL_TANH ) {
		fpica_update = fpica_tanh;
	}
	else if ( this->nonl == ICA_NONL_GAUSS ) {
		fpica_update = fpica_gauss;
	}

	Matrix B = Matrix::zeros("B", n2, n2);
	Matrix W_mix = Matrix::zeros("W_mix", n2, W_z.cols());

	int i;
	for ( i = 0; i < n2; i++ ) {
		log(LL_VERBOSE, "      round %d\n", i + 1);

		// initialize w as a Gaussian (0, 1) random vector
		Matrix w = Matrix::random("w", n2, 1);

		// compute w = w - B * B' * w, normalize w
		w -= B * TRAN(B) * w;
		w /= w.norm();

		// initialize w0
		Matrix w0 = Matrix::zeros("w0", w.rows(), w.cols());

		int j;
		for ( j = 0; j < this->max_iter; j++ ) {
			// compute w = w - B * B' * w, normalize w
			w -= B * TRAN(B) * w;
			w /= w.norm();

			// determine whether the direction of w and w0 are equal
			precision_t norm1 = (w - w0).norm();
			precision_t norm2 = (w + w0).norm();

			// terminate round if w converges
			if ( norm1 < this->eps || norm2 < this->eps ) {
				// save B(:, i) = w
				B.assign_column(i, w, 0);

				// save W_mix(i, :) = w' * W_z
				W_mix.assign_row(i, TRAN(w) * W_z, 0);

				// continue to the next round
				break;
			}

			// update w0
			w0.assign_column(0, w, 0);

			// compute w+ based on non-linearity
			w = fpica_update(w0, X);

			// compute w* = w+ / ||w+||
			w /= w.norm();
		}

		log(LL_VERBOSE, "      iterations: %d\n", j);
	}

	return W_mix;
}
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2003 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include <algorithm>
#include <functional>
#include <iostream>
#include <map>
#include <string>
#include <vector>

#include "BZAdminUI.h"
#if (defined(HAVE_CURSES_H) || defined (HAVE_NCURSES_H))
#include "CursesUI.h"
#endif
#include "OptionParser.h"
#include "ServerLink.h"
#include "StdBothUI.h"
#include "StdInUI.h"
#include "StdOutUI.h"
#include "UIMap.h"

// causes persistent rebuilding to obtain build versioning
#include "version.h"

using namespace std;

// function prototypes
/** Checks for new packets from the server, ignores them or stores a
    text message in str. Tells ui about new or removed players. Returns
    false if no interesting packets have arrived. */
bool getServerString(ServerLink& sLink, string& str, BZAdminUI& ui);

/** Sends the message msg to the server. */
void sendMessage(ServerLink& sLink, const string& msg, PlayerId target);

/** Formats an incoming message. */
string formatMessage(const string& msg, PlayerId src,
		     PlayerId dst, TeamColor dstTeam, PlayerId me);

// some global variables
map<PlayerId, string> players;
TeamColor myTeam(ObserverTeam);
struct CLOptions {
  CLOptions() : ui("curses"), showHelp(false) { }
  string ui;
  bool showHelp;
} clOptions;

// Here we go.
int main(int argc, char** argv) {

  // no curses, use stdboth instead
  const UIMap::map_t& interfaces(UIMap::getInstance().getMap());
  if (interfaces.find("curses") == interfaces.end())
    clOptions.ui = "stdboth";

  // build a usage string with all interfaces
  UIMap::map_t::const_iterator uiIter;
  string uiUsage;
  for (uiIter = interfaces.begin(); uiIter != interfaces.end(); ++uiIter)
    uiUsage += uiIter->first + '|';
  uiUsage = string("[-ui ") + uiUsage.substr(0, uiUsage.size() - 1) + ']';

  // register and parse command line arguments
  OptionParser op;
  op.registerVariable("ui", clOptions.ui, uiUsage,
		      "choose a user interface");
  op.registerVariable("help", clOptions.showHelp, "[-help]",
		      "print this help message");
  if (!op.parse(argc, argv)) {
    cerr<<op.getError()<<endl;
    op.printUsage(cout, argv[0]);
    cout<<"CALLSIGN@HOST[:PORT] [COMMAND] [COMMAND] ..."<<endl;
    return 1;
  }
  if (clOptions.showHelp) {
    cout<<"bzadmin "<<getAppVersion()<<endl;
    op.printUsage(cout, argv[0]);
    cout<<"CALLSIGN@HOST[:PORT] [COMMAND] [COMMAND] ..."<<endl<<endl;
    op.printHelp(cout);
    return 0;
  }

  // check that the ui is valid
  uiIter = UIMap::getInstance().getMap().find(clOptions.ui);
  if (uiIter == UIMap::getInstance().getMap().end()) {
    cerr<<"There is no interface called \""<<clOptions.ui<<"\"."<<endl;
    return 1;
  }

  // check that we have callsign and host in the right format and extract them
  if (op.getParameters().size() == 0) {
    cerr<<"You have to specify callsign@host."<<endl;
    return 1;
  }
  const string& namehost = op.getParameters()[0];
  int atPos = namehost.find('@');
  if (atPos == -1) {
    cerr<<"You have to specify callsign@host."<<endl;
    return 1;
  }
  string name = namehost.substr(0, atPos);
  string host = namehost.substr(atPos + 1);
  int port = ServerPort;
  int cPos = host.find(':');
  if (cPos != -1) {
    port = atoi(host.substr(cPos + 1).c_str());
    host = host.substr(0, cPos);
  }

  // connect to the server
  Address a(host);
  ServerLink sLink(a, port);
  if (sLink.getState() != ServerLink::Okay) {
    cerr<<"Could not connect to "<<host<<':'<<port<<'.'<<endl;
    return 0;
  }
  sLink.sendEnter(TankPlayer, myTeam, name.c_str(), "");
  if (sLink.getState() != ServerLink::Okay) {
    cerr<<"Rejected."<<endl;
    return 0;
  }

  // if we got commands as arguments, send them and exit
  if (op.getParameters().size() > 1) {
    for (unsigned int i = 1; i < op.getParameters().size(); ++i)
      sendMessage(sLink, op.getParameters()[i], AllPlayers);
    return 0;
  }

  // choose UI
  BZAdminUI*  ui = uiIter->second(players, sLink.getId());

  // main loop
  string str;
  PlayerId me = sLink.getId();
  while (true) {
    while (getServerString(sLink, str, *ui))
      ui->outputMessage(str);
    if (ui->checkCommand(str)) {
      if (str == "/quit")
	break;
      sendMessage(sLink, str, ui->getTarget());
      // private messages to other players aren't sent back to us, print here
      if (players.count(ui->getTarget()))
	ui->outputMessage(formatMessage(str, me, ui->getTarget(), NoTeam, me));
    }
  }
  delete ui;

  return 0;
}

bool getServerString(ServerLink& sLink, string& str, BZAdminUI& ui) {
  uint16_t code, len;
  char inbuf[MaxPacketLen];
  int e;
  std::string dstName, srcName;
  str = "";

  /* read until we have a package that we want, or until there are no more
     packages for 100 ms */
  while ((e = sLink.read(code, len, inbuf, 100)) == 1) {
    void* vbuf = inbuf;
    PlayerId p;
    switch (code) {

    case MsgAddPlayer:

      vbuf = nboUnpackUByte(vbuf, p);

      uint16_t team, type, wins, losses, tks;
      char callsign[CallSignLen];
      char email[EmailLen];
      vbuf = nboUnpackUShort(vbuf, type);
      vbuf = nboUnpackUShort(vbuf, team);
      vbuf = nboUnpackUShort(vbuf, wins);
      vbuf = nboUnpackUShort(vbuf, losses);
      vbuf = nboUnpackUShort(vbuf, tks);
      vbuf = nboUnpackString(vbuf, callsign, CallSignLen);
      vbuf = nboUnpackString(vbuf, email, EmailLen);
      players[p] = callsign;
      if (p != sLink.getId())
	ui.addedPlayer(p);
      str = str + "*** '" + callsign + "' joined the game.";
      return true;

    case MsgRemovePlayer:
      vbuf = nboUnpackUByte(vbuf, p);
      str = str + "*** '" + players[p] + "' left the game.";
      ui.removingPlayer(p);
      players.erase(p);
      return true;

    case MsgMessage:

      // unpack the message header
      PlayerId src;
      PlayerId dst;
      PlayerId me = sLink.getId();
      vbuf = nboUnpackUByte(vbuf, src);
      vbuf = nboUnpackUByte(vbuf, dst);

      // is the message for me?
      TeamColor dstTeam = (dst >= 244 && dst <= 250 ?
			   TeamColor(250 - dst) : NoTeam);
      if (dst == AllPlayers || src == me || dst == me || dstTeam == myTeam) {
	str = formatMessage((char*)vbuf, src, dst, dstTeam, me);
	return true;
      }
    }

    if (e == -2) {
      cerr<<"Server communication error!"<<endl;
      exit(0);
    }
  }

  return false;
}

void sendMessage(ServerLink& sLink, const string& msg, PlayerId target) {
  char buffer[MessageLen];
  char buffer2[1 + MessageLen];
  void* buf = buffer2;

  buf = nboPackUByte(buf, target);
  memset(buffer, 0, MessageLen);
  strncpy(buffer, msg.c_str(), MessageLen);
  nboPackString(buffer2 + 1, buffer, MessageLen);
  sLink.send(MsgMessage, sizeof(buffer2), buffer2);
}

string formatMessage(const string& msg, PlayerId src,
		     PlayerId dst, TeamColor dstTeam, PlayerId me) {
  string formatted = "    ";

  // get sender and receiver
  const string srcName = (src == ServerPlayer ? "SERVER" :
			  (players.count(src) ? players[src] : "(UNKNOWN)"));
  const string dstName = (players.count(dst) ? players[dst] : "(UNKNOWN)");

  // direct message to or from me
  if (dst == me || players.count(dst)) {
    if (!(src == me && dst == me)) {
      formatted += "[";
      if (src == me) {
	formatted += "->";
	formatted += dstName;
      }
      else {
	formatted += srcName;
	formatted += "->";
      }
      formatted += "] ";
    }
    formatted += msg;
  }

  // public or team message
  else {
    if (dstTeam != NoTeam)
      formatted += "[Team] ";
    formatted += srcName;
    formatted += ": ";
    formatted += msg;
  }

  return formatted;
}
<commit_msg>bzadmin responds to CLIENTQUERY<commit_after>/* bzflag
 * Copyright (c) 1993 - 2003 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include <algorithm>
#include <functional>
#include <iostream>
#include <map>
#include <string>
#include <vector>

#include "BZAdminUI.h"
#if (defined(HAVE_CURSES_H) || defined (HAVE_NCURSES_H))
#include "CursesUI.h"
#endif
#include "OptionParser.h"
#include "ServerLink.h"
#include "StdBothUI.h"
#include "StdInUI.h"
#include "StdOutUI.h"
#include "UIMap.h"

// causes persistent rebuilding to obtain build versioning
#include "version.h"

using namespace std;

// function prototypes
/** Checks for new packets from the server, ignores them or stores a
    text message in str. Tells ui about new or removed players. Returns
    false if no interesting packets have arrived. */
bool getServerString(ServerLink& sLink, string& str, BZAdminUI& ui);

/** Sends the message msg to the server. */
void sendMessage(ServerLink& sLink, const string& msg, PlayerId target);

/** Formats an incoming message. */
string formatMessage(const string& msg, PlayerId src,
		     PlayerId dst, TeamColor dstTeam, PlayerId me);

// some global variables
map<PlayerId, string> players;
TeamColor myTeam(ObserverTeam);
struct CLOptions {
  CLOptions() : ui("curses"), showHelp(false) { }
  string ui;
  bool showHelp;
} clOptions;

// Here we go.
int main(int argc, char** argv) {

  // no curses, use stdboth instead
  const UIMap::map_t& interfaces(UIMap::getInstance().getMap());
  if (interfaces.find("curses") == interfaces.end())
    clOptions.ui = "stdboth";

  // build a usage string with all interfaces
  UIMap::map_t::const_iterator uiIter;
  string uiUsage;
  for (uiIter = interfaces.begin(); uiIter != interfaces.end(); ++uiIter)
    uiUsage += uiIter->first + '|';
  uiUsage = string("[-ui ") + uiUsage.substr(0, uiUsage.size() - 1) + ']';

  // register and parse command line arguments
  OptionParser op;
  op.registerVariable("ui", clOptions.ui, uiUsage,
		      "choose a user interface");
  op.registerVariable("help", clOptions.showHelp, "[-help]",
		      "print this help message");
  if (!op.parse(argc, argv)) {
    cerr<<op.getError()<<endl;
    op.printUsage(cout, argv[0]);
    cout<<"CALLSIGN@HOST[:PORT] [COMMAND] [COMMAND] ..."<<endl;
    return 1;
  }
  if (clOptions.showHelp) {
    cout<<"bzadmin "<<getAppVersion()<<endl;
    op.printUsage(cout, argv[0]);
    cout<<"CALLSIGN@HOST[:PORT] [COMMAND] [COMMAND] ..."<<endl<<endl;
    op.printHelp(cout);
    return 0;
  }

  // check that the ui is valid
  uiIter = UIMap::getInstance().getMap().find(clOptions.ui);
  if (uiIter == UIMap::getInstance().getMap().end()) {
    cerr<<"There is no interface called \""<<clOptions.ui<<"\"."<<endl;
    return 1;
  }

  // check that we have callsign and host in the right format and extract them
  if (op.getParameters().size() == 0) {
    cerr<<"You have to specify callsign@host."<<endl;
    return 1;
  }
  const string& namehost = op.getParameters()[0];
  int atPos = namehost.find('@');
  if (atPos == -1) {
    cerr<<"You have to specify callsign@host."<<endl;
    return 1;
  }
  string name = namehost.substr(0, atPos);
  string host = namehost.substr(atPos + 1);
  int port = ServerPort;
  int cPos = host.find(':');
  if (cPos != -1) {
    port = atoi(host.substr(cPos + 1).c_str());
    host = host.substr(0, cPos);
  }

  // connect to the server
  Address a(host);
  ServerLink sLink(a, port);
  if (sLink.getState() != ServerLink::Okay) {
    cerr<<"Could not connect to "<<host<<':'<<port<<'.'<<endl;
    return 0;
  }
  sLink.sendEnter(TankPlayer, myTeam, name.c_str(), "");
  if (sLink.getState() != ServerLink::Okay) {
    cerr<<"Rejected."<<endl;
    return 0;
  }

  // if we got commands as arguments, send them and exit
  if (op.getParameters().size() > 1) {
    for (unsigned int i = 1; i < op.getParameters().size(); ++i)
      sendMessage(sLink, op.getParameters()[i], AllPlayers);
    return 0;
  }

  // choose UI
  BZAdminUI*  ui = uiIter->second(players, sLink.getId());

  // main loop
  string str;
  PlayerId me = sLink.getId();
  while (true) {
    while (getServerString(sLink, str, *ui))
      ui->outputMessage(str);
    if (ui->checkCommand(str)) {
      if (str == "/quit")
	break;
      sendMessage(sLink, str, ui->getTarget());
      // private messages to other players aren't sent back to us, print here
      if (players.count(ui->getTarget()))
	ui->outputMessage(formatMessage(str, me, ui->getTarget(), NoTeam, me));
    }
  }
  delete ui;

  return 0;
}

bool getServerString(ServerLink& sLink, string& str, BZAdminUI& ui) {
  uint16_t code, len;
  char inbuf[MaxPacketLen];
  int e;
  std::string dstName, srcName;
  str = "";

  /* read until we have a package that we want, or until there are no more
     packages for 100 ms */
  while ((e = sLink.read(code, len, inbuf, 100)) == 1) {
    void* vbuf = inbuf;
    PlayerId p;
    switch (code) {

    case MsgAddPlayer:

      vbuf = nboUnpackUByte(vbuf, p);

      uint16_t team, type, wins, losses, tks;
      char callsign[CallSignLen];
      char email[EmailLen];
      vbuf = nboUnpackUShort(vbuf, type);
      vbuf = nboUnpackUShort(vbuf, team);
      vbuf = nboUnpackUShort(vbuf, wins);
      vbuf = nboUnpackUShort(vbuf, losses);
      vbuf = nboUnpackUShort(vbuf, tks);
      vbuf = nboUnpackString(vbuf, callsign, CallSignLen);
      vbuf = nboUnpackString(vbuf, email, EmailLen);
      players[p] = callsign;
      if (p != sLink.getId())
	ui.addedPlayer(p);
      str = str + "*** '" + callsign + "' joined the game.";
      return true;

    case MsgRemovePlayer:
      vbuf = nboUnpackUByte(vbuf, p);
      str = str + "*** '" + players[p] + "' left the game.";
      ui.removingPlayer(p);
      players.erase(p);
      return true;

    case MsgMessage:

      // unpack the message header
      PlayerId src;
      PlayerId dst;
      PlayerId me = sLink.getId();
      vbuf = nboUnpackUByte(vbuf, src);
      vbuf = nboUnpackUByte(vbuf, dst);

      // is the message for me?
      TeamColor dstTeam = (dst >= 244 && dst <= 250 ?
			   TeamColor(250 - dst) : NoTeam);
      if (dst == AllPlayers || src == me || dst == me || dstTeam == myTeam) {
	str = (char*)vbuf;
	if (str == "CLIENTQUERY") {
	  sendMessage(sLink, string("bzadmin ") + getAppVersion(), src);
	  ui.outputMessage("    [Sent versioninfo per request]");
	}
	else {
	  str = formatMessage((char*)vbuf, src, dst, dstTeam, me);
	  return true;
	}
      }
    }

    if (e == -2) {
      cerr<<"Server communication error!"<<endl;
      exit(0);
    }
  }

  return false;
}

void sendMessage(ServerLink& sLink, const string& msg, PlayerId target) {
  char buffer[MessageLen];
  char buffer2[1 + MessageLen];
  void* buf = buffer2;

  buf = nboPackUByte(buf, target);
  memset(buffer, 0, MessageLen);
  strncpy(buffer, msg.c_str(), MessageLen);
  nboPackString(buffer2 + 1, buffer, MessageLen);
  sLink.send(MsgMessage, sizeof(buffer2), buffer2);
}

string formatMessage(const string& msg, PlayerId src,
		     PlayerId dst, TeamColor dstTeam, PlayerId me) {
  string formatted = "    ";

  // get sender and receiver
  const string srcName = (src == ServerPlayer ? "SERVER" :
			  (players.count(src) ? players[src] : "(UNKNOWN)"));
  const string dstName = (players.count(dst) ? players[dst] : "(UNKNOWN)");

  // direct message to or from me
  if (dst == me || players.count(dst)) {
    if (!(src == me && dst == me)) {
      formatted += "[";
      if (src == me) {
	formatted += "->";
	formatted += dstName;
      }
      else {
	formatted += srcName;
	formatted += "->";
      }
      formatted += "] ";
    }
    formatted += msg;
  }

  // public or team message
  else {
    if (dstTeam != NoTeam)
      formatted += "[Team] ";
    formatted += srcName;
    formatted += ": ";
    formatted += msg;
  }

  return formatted;
}
<|endoftext|>


<commit_before>/*
  @copyright Russell Standish 2017
  @author Russell Standish
  This file is part of EcoLab

  Open source licensed under the MIT license. See LICENSE for details.
*/

#if defined(CAIRO) && defined(TK)
#include "cairoSurfaceImage.h"
#include "tcl++.h"

#ifdef _WIN32
#undef Realloc
#include <windows.h>
#endif

#include "ecolab_epilogue.h"
#define USE_WIN32_SURFACE defined(CAIRO_HAS_WIN32_SURFACE) && !defined(__CYGWIN__)

#ifdef CAIRO_HAS_XLIB_SURFACE
#include <cairo/cairo-xlib.h>
#endif
#if USE_WIN32_SURFACE
#include <cairo/cairo-win32.h>
// undocumented internal function for extracting the HDC from a Drawable
extern "C" HDC TkWinGetDrawableDC(Display*, Drawable, void*);
extern "C" HDC TkWinReleaseDrawableDC(Drawable, HDC, void*);
#endif

#if defined(MAC_OSX_TK)
#include <Carbon/Carbon.h>
#include <cairo/cairo-quartz.h>
#include "getContext.h"
#endif

using namespace ecolab;
using namespace std;

namespace
{
    struct TkWinSurface: public ecolab::cairo::Surface
    {
      CairoSurface& csurf;
      Tk_ImageMaster imageMaster;
      TkWinSurface(CairoSurface& csurf, Tk_ImageMaster imageMaster, cairo_surface_t* surf):
        cairo::Surface(surf), csurf(csurf),  imageMaster(imageMaster) {}
      void requestRedraw() {
        Tk_ImageChanged(imageMaster,-1000000,-1000000,2000000,2000000,2000000,2000000);
      }
      void blit() {cairo_surface_flush(surface());}
    };

    struct CD
    {
      Tk_Window tkWin;
      Tk_ImageMaster master;
      CairoSurface& csurf;
      CD(Tk_Window tkWin, Tk_ImageMaster master, CairoSurface& csurf):
        tkWin(tkWin), master(master), csurf(csurf) {}
    };

    // Define a new image type that renders a minsky::Canvas
    int createCI(Tcl_Interp* interp, const char* name, int objc, Tcl_Obj *const objv[],
                 const Tk_ImageType* typePtr, Tk_ImageMaster master, ClientData *masterData)
    {
      try
        {
          TCL_args args(objc,objv);
          string canvas=args; // arguments should be something like -surface minsky.canvas
          if (TCL_obj_hash::mapped_type mb=TCL_obj_properties()[canvas])
            if (CairoSurface* csurf=mb->memberPtrCasted<CairoSurface>())
              {
                *masterData=new CD(0,master,*csurf);
                Tk_ImageChanged(master,-1000000,-1000000,2000000,2000000,2000000,2000000);
                return TCL_OK;
              }
          Tcl_AppendResult(interp,"Not a CairoSurface",NULL);
          return TCL_ERROR;
        }
      catch (const std::exception& e)
        {
          Tcl_AppendResult(interp,e.what(),NULL);
          return TCL_ERROR;
        }
    }

    ClientData getCI(Tk_Window win, ClientData masterData)
    {
      CD* r=new CD(*(CD*)masterData);
      r->tkWin=win;
      return r;
    }

    void displayCI(ClientData cd, Display* display, Drawable win,
                  int imageX, int imageY, int width, int height,
                  int drawableX, int drawableY)
    {
      CD& c=*(CD*)cd;
#if USE_WIN32_SURFACE
      // TkWinGetDrawableDC is an internal (ie undocumented) routine
      // for getting the DC. We need to declare something to take
      // the state parameter - two long longs should be ample here
      long long state[2];
      HDC hdc=TkWinGetDrawableDC(display, win, state);
      //HDC hdc=GetDC(Tk_GetHWND(win));
      SaveDC(hdc);
      c.csurf.surface.reset
        (new TkWinSurface
         (c.csurf, c.master,
          cairo_win32_surface_create(hdc)));
#elif defined(MAC_OSX_TK)
      NSContext nctx(win);
      c.csurf.surface.reset
        (new TkWinSurface
         (c.csurf, c.master,
          cairo_quartz_surface_create_for_cg_context(nctx.context, Tk_Width(c.tkWin), Tk_Height(c.tkWin))));
      // x offset required because MacOSX draws a thick white border around this
      cairo_surface_set_device_offset(c.csurf.surface->surface(),30,Tk_Height(c.tkWin));
      cairo_surface_set_device_scale(c.csurf.surface->surface(),1,-1);
#else
      int depth;
      Visual *visual = Tk_GetVisual(interp(), c.tkWin, "default", &depth, NULL);
      c.csurf.surface.reset
        (new TkWinSurface
         (c.csurf, c.master,
          cairo_xlib_surface_create(display, win, visual, Tk_Width(c.tkWin), Tk_Height(c.tkWin))));

#endif
      width=min(width,Tk_Width(c.tkWin));
      height=min(height,Tk_Height(c.tkWin));
      c.csurf.redraw(imageX,imageY,width,height);
      cairo_surface_flush(c.csurf.surface->surface());
      // release surface prior to any context going out of scope
      c.csurf.surface->surface(NULL);
#if USE_WIN32_SURFACE
      RestoreDC(hdc,-1);
      TkWinReleaseDrawableDC(win, hdc, state);
#endif
    }

  void freeCI(ClientData cd,Display*) {delete (CD*)cd;}
  void deleteCI(ClientData cd) {delete (CD*)cd;}

  Tk_ImageType canvasImage = {
    "cairoSurface",
    createCI,
    getCI,
    displayCI,
    freeCI,
    deleteCI
  };

}

void CairoSurface::registerImage()
{
  // ensure Tk_Init is called.
  if (!Tk_MainWindow(interp())) Tk_Init(interp());
  Tk_CreateImageType(&canvasImage);
}
#endif
<commit_msg>handle support for older (v8.5) Tk_ImageCreateProc<commit_after>/*
  @copyright Russell Standish 2017
  @author Russell Standish
  This file is part of EcoLab

  Open source licensed under the MIT license. See LICENSE for details.
*/

#if defined(CAIRO) && defined(TK)
#include "cairoSurfaceImage.h"
#include "tcl++.h"

#ifdef _WIN32
#undef Realloc
#include <windows.h>
#endif

#include "ecolab_epilogue.h"
#define USE_WIN32_SURFACE defined(CAIRO_HAS_WIN32_SURFACE) && !defined(__CYGWIN__)

#ifdef CAIRO_HAS_XLIB_SURFACE
#include <cairo/cairo-xlib.h>
#endif
#if USE_WIN32_SURFACE
#include <cairo/cairo-win32.h>
// undocumented internal function for extracting the HDC from a Drawable
extern "C" HDC TkWinGetDrawableDC(Display*, Drawable, void*);
extern "C" HDC TkWinReleaseDrawableDC(Drawable, HDC, void*);
#endif

#if defined(MAC_OSX_TK)
#include <Carbon/Carbon.h>
#include <cairo/cairo-quartz.h>
#include "getContext.h"
#endif

using namespace ecolab;
using namespace std;

namespace
{
    struct TkWinSurface: public ecolab::cairo::Surface
    {
      CairoSurface& csurf;
      Tk_ImageMaster imageMaster;
      TkWinSurface(CairoSurface& csurf, Tk_ImageMaster imageMaster, cairo_surface_t* surf):
        cairo::Surface(surf), csurf(csurf),  imageMaster(imageMaster) {}
      void requestRedraw() {
        Tk_ImageChanged(imageMaster,-1000000,-1000000,2000000,2000000,2000000,2000000);
      }
      void blit() {cairo_surface_flush(surface());}
    };

    struct CD
    {
      Tk_Window tkWin;
      Tk_ImageMaster master;
      CairoSurface& csurf;
      CD(Tk_Window tkWin, Tk_ImageMaster master, CairoSurface& csurf):
        tkWin(tkWin), master(master), csurf(csurf) {}
    };

    // Define a new image type that renders a minsky::Canvas
#ifdef USE_OLD_IMAGE
    int createCI(Tcl_Interp* interp, char* name, int objc, char * objv[],
                 Tk_ImageType* typePtr, Tk_ImageMaster master, ClientData *masterData)
#else
    int createCI(Tcl_Interp* interp, const char* name, int objc, Tcl_Obj *const objv[],
                 const Tk_ImageType* typePtr, Tk_ImageMaster master, ClientData *masterData)
#endif
    {
      try
        {
          TCL_args args(objc,objv);
          string canvas=args; // arguments should be something like -surface minsky.canvas
          if (TCL_obj_hash::mapped_type mb=TCL_obj_properties()[canvas])
            if (CairoSurface* csurf=mb->memberPtrCasted<CairoSurface>())
              {
                *masterData=new CD(0,master,*csurf);
                Tk_ImageChanged(master,-1000000,-1000000,2000000,2000000,2000000,2000000);
                return TCL_OK;
              }
          Tcl_AppendResult(interp,"Not a CairoSurface",NULL);
          return TCL_ERROR;
        }
      catch (const std::exception& e)
        {
          Tcl_AppendResult(interp,e.what(),NULL);
          return TCL_ERROR;
        }
    }

    ClientData getCI(Tk_Window win, ClientData masterData)
    {
      CD* r=new CD(*(CD*)masterData);
      r->tkWin=win;
      return r;
    }

    void displayCI(ClientData cd, Display* display, Drawable win,
                  int imageX, int imageY, int width, int height,
                  int drawableX, int drawableY)
    {
      CD& c=*(CD*)cd;
#if USE_WIN32_SURFACE
      // TkWinGetDrawableDC is an internal (ie undocumented) routine
      // for getting the DC. We need to declare something to take
      // the state parameter - two long longs should be ample here
      long long state[2];
      HDC hdc=TkWinGetDrawableDC(display, win, state);
      //HDC hdc=GetDC(Tk_GetHWND(win));
      SaveDC(hdc);
      c.csurf.surface.reset
        (new TkWinSurface
         (c.csurf, c.master,
          cairo_win32_surface_create(hdc)));
#elif defined(MAC_OSX_TK)
      NSContext nctx(win);
      c.csurf.surface.reset
        (new TkWinSurface
         (c.csurf, c.master,
          cairo_quartz_surface_create_for_cg_context(nctx.context, Tk_Width(c.tkWin), Tk_Height(c.tkWin))));
      // x offset required because MacOSX draws a thick white border around this
      cairo_surface_set_device_offset(c.csurf.surface->surface(),30,Tk_Height(c.tkWin));
      cairo_surface_set_device_scale(c.csurf.surface->surface(),1,-1);
#else
      int depth;
      Visual *visual = Tk_GetVisual(interp(), c.tkWin, "default", &depth, NULL);
      c.csurf.surface.reset
        (new TkWinSurface
         (c.csurf, c.master,
          cairo_xlib_surface_create(display, win, visual, Tk_Width(c.tkWin), Tk_Height(c.tkWin))));

#endif
      width=min(width,Tk_Width(c.tkWin));
      height=min(height,Tk_Height(c.tkWin));
      c.csurf.redraw(imageX,imageY,width,height);
      cairo_surface_flush(c.csurf.surface->surface());
      // release surface prior to any context going out of scope
      c.csurf.surface->surface(NULL);
#if USE_WIN32_SURFACE
      RestoreDC(hdc,-1);
      TkWinReleaseDrawableDC(win, hdc, state);
#endif
    }

  void freeCI(ClientData cd,Display*) {delete (CD*)cd;}
  void deleteCI(ClientData cd) {delete (CD*)cd;}

  Tk_ImageType canvasImage = {
    "cairoSurface",
    createCI,
    getCI,
    displayCI,
    freeCI,
    deleteCI
  };

}

void CairoSurface::registerImage()
{
  // ensure Tk_Init is called.
  if (!Tk_MainWindow(interp())) Tk_Init(interp());
  Tk_CreateImageType(&canvasImage);
}
#endif
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "irc.h"
#include "net.h"
#include "strlcpy.h"
#include "base58.h"

using namespace std;
using namespace boost;

int nGotIRCAddresses = 0;

void ThreadIRCSeed2(void* parg);

#pragma pack(push, 1)
struct ircaddr
{
    struct in_addr ip;
    short port;
};
#pragma pack(pop)

string EncodeAddress(const CService& addr)
{
    struct ircaddr tmp;
    if (addr.GetInAddr(&tmp.ip))
    {
        tmp.port = htons(addr.GetPort());

        vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
        return string("u") + EncodeBase58Check(vch);
    }
    return "";
}

bool DecodeAddress(string str, CService& addr)
{
    vector<unsigned char> vch;
    if (!DecodeBase58Check(str.substr(1), vch))
        return false;

    struct ircaddr tmp;
    if (vch.size() != sizeof(tmp))
        return false;
    memcpy(&tmp, &vch[0], sizeof(tmp));

    addr = CService(tmp.ip, ntohs(tmp.port));
    return true;
}

static bool Send(SOCKET hSocket, const char* pszSend)
{
    if (strstr(pszSend, "PONG") != pszSend)
        printf("IRC SENDING: %s\n", pszSend);
    const char* psz = pszSend;
    const char* pszEnd = psz + strlen(psz);
    while (psz < pszEnd)
    {
        int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL);
        if (ret < 0)
            return false;
        psz += ret;
    }
    return true;
}

bool RecvLineIRC(SOCKET hSocket, string& strLine)
{
    while (true)
    {
        bool fRet = RecvLine(hSocket, strLine);
        if (fRet)
        {
            if (fShutdown)
                return false;
            vector<string> vWords;
            ParseString(strLine, ' ', vWords);
            if (vWords.size() >= 1 && vWords[0] == "PING")
            {
                strLine[1] = 'O';
                strLine += '\r';
                Send(hSocket, strLine.c_str());
                continue;
            }
        }
        return fRet;
    }
}

int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL, const char* psz4=NULL)
{
    while (true)
    {
        string strLine;
        strLine.reserve(10000);
        if (!RecvLineIRC(hSocket, strLine))
            return 0;
        printf("IRC %s\n", strLine.c_str());
        if (psz1 && strLine.find(psz1) != string::npos)
            return 1;
        if (psz2 && strLine.find(psz2) != string::npos)
            return 2;
        if (psz3 && strLine.find(psz3) != string::npos)
            return 3;
        if (psz4 && strLine.find(psz4) != string::npos)
            return 4;
    }
}

bool Wait(int nSeconds)
{
    if (fShutdown)
        return false;
    printf("IRC waiting %d seconds to reconnect\n", nSeconds);
    for (int i = 0; i < nSeconds; i++)
    {
        if (fShutdown)
            return false;
        MilliSleep(1000);
    }
    return true;
}

bool RecvCodeLine(SOCKET hSocket, const char* psz1, string& strRet)
{
    strRet.clear();
    while (true)
    {
        string strLine;
        if (!RecvLineIRC(hSocket, strLine))
            return false;

        vector<string> vWords;
        ParseString(strLine, ' ', vWords);
        if (vWords.size() < 2)
            continue;

        if (vWords[1] == psz1)
        {
            printf("IRC %s\n", strLine.c_str());
            strRet = strLine;
            return true;
        }
    }
}

bool GetIPFromIRC(SOCKET hSocket, string strMyName, CNetAddr& ipRet)
{
    Send(hSocket, strprintf("USERHOST %s\r", strMyName.c_str()).c_str());

    string strLine;
    if (!RecvCodeLine(hSocket, "302", strLine))
        return false;

    vector<string> vWords;
    ParseString(strLine, ' ', vWords);
    if (vWords.size() < 4)
        return false;

    string str = vWords[3];
    if (str.rfind("@") == string::npos)
        return false;
    string strHost = str.substr(str.rfind("@")+1);

    // Hybrid IRC used by lfnet always returns IP when you userhost yourself,
    // but in case another IRC is ever used this should work.
    printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
    CNetAddr addr(strHost, true);
    if (!addr.IsValid())
        return false;
    ipRet = addr;

    return true;
}

void ThreadIRCSeed(void* parg)
{
    // Make this thread recognisable as the IRC seeding thread
    RenameThread("selen-ircseed");

    try
    {
        ThreadIRCSeed2(parg);
    }
    catch (std::exception& e) {
        PrintExceptionContinue(&e, "ThreadIRCSeed()");
    } catch (...) {
        PrintExceptionContinue(NULL, "ThreadIRCSeed()");
    }
    printf("ThreadIRCSeed exited\n");
}

void ThreadIRCSeed2(void* parg)
{
    // Don't connect to IRC if we won't use IPv4 connections.
    if (IsLimited(NET_IPV4))
        return;

    // ... or if we won't make outbound connections and won't accept inbound ones.
    if (mapArgs.count("-connect") && fNoListen)
        return;

    // ... or if IRC is not enabled.
    if (!GetBoolArg("-irc", false))
        return;

    printf("ThreadIRCSeed started\n");
    int nErrorWait = 10;
    int nRetryWait = 10;
    int nNameRetry = 0;

    while (!fShutdown)
    {
        CService addrConnect("38.229.70.22", 6667); // irc.freenode.org

        CService addrIRC("chat.freenode.net", 6667, true);
        if (addrIRC.IsValid())
            addrConnect = addrIRC;

        SOCKET hSocket;
        if (!ConnectSocket(addrConnect, hSocket))
        {
            printf("IRC connect failed\n");
            nErrorWait = nErrorWait * 11 / 10;
            if (Wait(nErrorWait += 60))
                continue;
            else
                return;
        }

        if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname", "ignoring hostname"))
        {
            closesocket(hSocket);
            hSocket = INVALID_SOCKET;
            nErrorWait = nErrorWait * 11 / 10;
            if (Wait(nErrorWait += 60))
                continue;
            else
                return;
        }

        CNetAddr addrIPv4("1.2.3.4"); // arbitrary IPv4 address to make GetLocal prefer IPv4 addresses
        CService addrLocal;
        string strMyName;
        // Don't use our IP as our nick if we're not listening
        // or if it keeps failing because the nick is already in use.
        if (!fNoListen && GetLocal(addrLocal, &addrIPv4) && nNameRetry<3)
            strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
        if (strMyName == "")
            strMyName = strprintf("x%"PRIu64"", GetRand(1000000000));

        Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
        Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());

        int nRet = RecvUntil(hSocket, " 004 ", " 433 ");
        if (nRet != 1)
        {
            closesocket(hSocket);
            hSocket = INVALID_SOCKET;
            if (nRet == 2)
            {
                printf("IRC name already in use\n");
                nNameRetry++;
                Wait(10);
                continue;
            }
            nErrorWait = nErrorWait * 11 / 10;
            if (Wait(nErrorWait += 60))
                continue;
            else
                return;
        }
        nNameRetry = 0;
        MilliSleep(500);

        // Get our external IP from the IRC server and re-nick before joining the channel
        CNetAddr addrFromIRC;
        if (GetIPFromIRC(hSocket, strMyName, addrFromIRC))
        {
            printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToString().c_str());
            // Don't use our IP as our nick if we're not listening
            if (!fNoListen && addrFromIRC.IsRoutable())
            {
                // IRC lets you to re-nick
                AddLocal(addrFromIRC, LOCAL_IRC);
                strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
                Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
            }
        }

        if (fTestNet) {
            Send(hSocket, "JOIN #selenTEST\r");
            Send(hSocket, "WHO #selenTEST\r");
        } else {
            // randomly join #selen00-#selen05
            //int channel_number = GetRandInt(5);
            int channel_number = 0;
            // Channel number is always 0 for initial release
            //int channel_number = 0;
            Send(hSocket, strprintf("JOIN #selen%02d\r", channel_number).c_str());
            Send(hSocket, strprintf("WHO #selen%02d\r", channel_number).c_str());
        }

        int64_t nStart = GetTime();
        string strLine;
        strLine.reserve(10000);
        while (!fShutdown && RecvLineIRC(hSocket, strLine))
        {
            if (strLine.empty() || strLine.size() > 900 || strLine[0] != ':')
                continue;

            vector<string> vWords;
            ParseString(strLine, ' ', vWords);
            if (vWords.size() < 2)
                continue;

            char pszName[10000];
            pszName[0] = '\0';

            if (vWords[1] == "352" && vWords.size() >= 8)
            {
                // index 7 is limited to 16 characters
                // could get full length name at index 10, but would be different from join messages
                strlcpy(pszName, vWords[7].c_str(), sizeof(pszName));
                printf("IRC got who\n");
            }

            if (vWords[1] == "JOIN" && vWords[0].size() > 1)
            {
                // :username!username@50000007.F000000B.90000002.IP JOIN :#channelname
                strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName));
                if (strchr(pszName, '!'))
                    *strchr(pszName, '!') = '\0';
                printf("IRC got join\n");
            }

            if (pszName[0] == 'u')
            {
                CAddress addr;
                if (DecodeAddress(pszName, addr))
                {
                    addr.nTime = GetAdjustedTime();
                    if (addrman.Add(addr, addrConnect, 51 * 60))
                        printf("IRC got new address: %s\n", addr.ToString().c_str());
                    nGotIRCAddresses++;
                }
                else
                {
                    printf("IRC decode failed\n");
                }
            }
        }
        closesocket(hSocket);
        hSocket = INVALID_SOCKET;

        if (GetTime() - nStart > 20 * 60)
        {
            nErrorWait /= 3;
            nRetryWait /= 3;
        }

        nRetryWait = nRetryWait * 11 / 10;
        if (!Wait(nRetryWait += 60))
            return;
    }
}

#ifdef TEST
int main(int argc, char *argv[])
{
    WSADATA wsadata;
    if (WSAStartup(MAKEWORD(2,2), &wsadata) != NO_ERROR)
    {
        printf("Error at WSAStartup()\n");
        return false;
    }

    ThreadIRCSeed(NULL);

    WSACleanup();
    return 0;
}
#endif
<commit_msg>Stable<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "irc.h"
#include "net.h"
#include "strlcpy.h"
#include "base58.h"

using namespace std;
using namespace boost;

int nGotIRCAddresses = 0;

void ThreadIRCSeed2(void* parg);

#pragma pack(push, 1)
struct ircaddr
{
    struct in_addr ip;
    short port;
};
#pragma pack(pop)

string EncodeAddress(const CService& addr)
{
    struct ircaddr tmp;
    if (addr.GetInAddr(&tmp.ip))
    {
        tmp.port = htons(addr.GetPort());

        vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
        return string("u") + EncodeBase58Check(vch);
    }
    return "";
}

bool DecodeAddress(string str, CService& addr)
{
    vector<unsigned char> vch;
    if (!DecodeBase58Check(str.substr(1), vch))
        return false;

    struct ircaddr tmp;
    if (vch.size() != sizeof(tmp))
        return false;
    memcpy(&tmp, &vch[0], sizeof(tmp));

    addr = CService(tmp.ip, ntohs(tmp.port));
    return true;
}

static bool Send(SOCKET hSocket, const char* pszSend)
{
    if (strstr(pszSend, "PONG") != pszSend)
        printf("IRC SENDING: %s\n", pszSend);
    const char* psz = pszSend;
    const char* pszEnd = psz + strlen(psz);
    while (psz < pszEnd)
    {
        int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL);
        if (ret < 0)
            return false;
        psz += ret;
    }
    return true;
}

bool RecvLineIRC(SOCKET hSocket, string& strLine)
{
    while (true)
    {
        bool fRet = RecvLine(hSocket, strLine);
        if (fRet)
        {
            if (fShutdown)
                return false;
            vector<string> vWords;
            ParseString(strLine, ' ', vWords);
            if (vWords.size() >= 1 && vWords[0] == "PING")
            {
                strLine[1] = 'O';
                strLine += '\r';
                Send(hSocket, strLine.c_str());
                continue;
            }
        }
        return fRet;
    }
}

int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL, const char* psz4=NULL)
{
    while (true)
    {
        string strLine;
        strLine.reserve(10000);
        if (!RecvLineIRC(hSocket, strLine))
            return 0;
        printf("IRC %s\n", strLine.c_str());
        if (psz1 && strLine.find(psz1) != string::npos)
            return 1;
        if (psz2 && strLine.find(psz2) != string::npos)
            return 2;
        if (psz3 && strLine.find(psz3) != string::npos)
            return 3;
        if (psz4 && strLine.find(psz4) != string::npos)
            return 4;
    }
}

bool Wait(int nSeconds)
{
    if (fShutdown)
        return false;
    printf("IRC waiting %d seconds to reconnect\n", nSeconds);
    for (int i = 0; i < nSeconds; i++)
    {
        if (fShutdown)
            return false;
        MilliSleep(1000);
    }
    return true;
}

bool RecvCodeLine(SOCKET hSocket, const char* psz1, string& strRet)
{
    strRet.clear();
    while (true)
    {
        string strLine;
        if (!RecvLineIRC(hSocket, strLine))
            return false;

        vector<string> vWords;
        ParseString(strLine, ' ', vWords);
        if (vWords.size() < 2)
            continue;

        if (vWords[1] == psz1)
        {
            printf("IRC %s\n", strLine.c_str());
            strRet = strLine;
            return true;
        }
    }
}

bool GetIPFromIRC(SOCKET hSocket, string strMyName, CNetAddr& ipRet)
{
    Send(hSocket, strprintf("USERHOST %s\r", strMyName.c_str()).c_str());

    string strLine;
    if (!RecvCodeLine(hSocket, "302", strLine))
        return false;

    vector<string> vWords;
    ParseString(strLine, ' ', vWords);
    if (vWords.size() < 4)
        return false;

    string str = vWords[3];
    if (str.rfind("@") == string::npos)
        return false;
    string strHost = str.substr(str.rfind("@")+1);

    // Hybrid IRC used by lfnet always returns IP when you userhost yourself,
    // but in case another IRC is ever used this should work.
    printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
    CNetAddr addr(strHost, true);
    if (!addr.IsValid())
        return false;
    ipRet = addr;

    return true;
}

void ThreadIRCSeed(void* parg)
{
    // Make this thread recognisable as the IRC seeding thread
    RenameThread("selen-ircseed");

    try
    {
        ThreadIRCSeed2(parg);
    }
    catch (std::exception& e) {
        PrintExceptionContinue(&e, "ThreadIRCSeed()");
    } catch (...) {
        PrintExceptionContinue(NULL, "ThreadIRCSeed()");
    }
    printf("ThreadIRCSeed exited\n");
}

void ThreadIRCSeed2(void* parg)
{
    // Don't connect to IRC if we won't use IPv4 connections.
    if (IsLimited(NET_IPV4))
        return;

    // ... or if we won't make outbound connections and won't accept inbound ones.
    if (mapArgs.count("-connect") && fNoListen)
        return;

    // ... or if IRC is not enabled.
    if (!GetBoolArg("-irc", false))
        return;

    printf("ThreadIRCSeed started\n");
    int nErrorWait = 10;
    int nRetryWait = 10;
    int nNameRetry = 0;

    while (!fShutdown)
    {
        CService addrConnect("88.99.47.154", 6667); // irc.freenode.org

        CService addrIRC("seed.for-biz.com", 6667, true);
        if (addrIRC.IsValid())
            addrConnect = addrIRC;

        SOCKET hSocket;
        if (!ConnectSocket(addrConnect, hSocket))
        {
            printf("IRC connect failed\n");
            nErrorWait = nErrorWait * 11 / 10;
            if (Wait(nErrorWait += 60))
                continue;
            else
                return;
        }

        if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname", "ignoring hostname"))
        {
            closesocket(hSocket);
            hSocket = INVALID_SOCKET;
            nErrorWait = nErrorWait * 11 / 10;
            if (Wait(nErrorWait += 60))
                continue;
            else
                return;
        }

        CNetAddr addrIPv4("1.2.3.4"); // arbitrary IPv4 address to make GetLocal prefer IPv4 addresses
        CService addrLocal;
        string strMyName;
        // Don't use our IP as our nick if we're not listening
        // or if it keeps failing because the nick is already in use.
        if (!fNoListen && GetLocal(addrLocal, &addrIPv4) && nNameRetry<3)
            strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
        if (strMyName == "")
            strMyName = strprintf("x%"PRIu64"", GetRand(1000000000));

        Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
        Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());

        int nRet = RecvUntil(hSocket, " 004 ", " 433 ");
        if (nRet != 1)
        {
            closesocket(hSocket);
            hSocket = INVALID_SOCKET;
            if (nRet == 2)
            {
                printf("IRC name already in use\n");
                nNameRetry++;
                Wait(10);
                continue;
            }
            nErrorWait = nErrorWait * 11 / 10;
            if (Wait(nErrorWait += 60))
                continue;
            else
                return;
        }
        nNameRetry = 0;
        MilliSleep(500);

        // Get our external IP from the IRC server and re-nick before joining the channel
        CNetAddr addrFromIRC;
        if (GetIPFromIRC(hSocket, strMyName, addrFromIRC))
        {
            printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToString().c_str());
            // Don't use our IP as our nick if we're not listening
            if (!fNoListen && addrFromIRC.IsRoutable())
            {
                // IRC lets you to re-nick
                AddLocal(addrFromIRC, LOCAL_IRC);
                strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
                Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
            }
        }

        if (fTestNet) {
            Send(hSocket, "JOIN #selenTEST\r");
            Send(hSocket, "WHO #selenTEST\r");
        } else {
            // randomly join #selen00-#selen05
            //int channel_number = GetRandInt(5);
            int channel_number = 0;
            // Channel number is always 0 for initial release
            //int channel_number = 0;
            Send(hSocket, strprintf("JOIN #selen%02d\r", channel_number).c_str());
            Send(hSocket, strprintf("WHO #selen%02d\r", channel_number).c_str());
        }

        int64_t nStart = GetTime();
        string strLine;
        strLine.reserve(10000);
        while (!fShutdown && RecvLineIRC(hSocket, strLine))
        {
            if (strLine.empty() || strLine.size() > 900 || strLine[0] != ':')
                continue;

            vector<string> vWords;
            ParseString(strLine, ' ', vWords);
            if (vWords.size() < 2)
                continue;

            char pszName[10000];
            pszName[0] = '\0';

            if (vWords[1] == "352" && vWords.size() >= 8)
            {
                // index 7 is limited to 16 characters
                // could get full length name at index 10, but would be different from join messages
                strlcpy(pszName, vWords[7].c_str(), sizeof(pszName));
                printf("IRC got who\n");
            }

            if (vWords[1] == "JOIN" && vWords[0].size() > 1)
            {
                // :username!username@50000007.F000000B.90000002.IP JOIN :#channelname
                strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName));
                if (strchr(pszName, '!'))
                    *strchr(pszName, '!') = '\0';
                printf("IRC got join\n");
            }

            if (pszName[0] == 'u')
            {
                CAddress addr;
                if (DecodeAddress(pszName, addr))
                {
                    addr.nTime = GetAdjustedTime();
                    if (addrman.Add(addr, addrConnect, 51 * 60))
                        printf("IRC got new address: %s\n", addr.ToString().c_str());
                    nGotIRCAddresses++;
                }
                else
                {
                    printf("IRC decode failed\n");
                }
            }
        }
        closesocket(hSocket);
        hSocket = INVALID_SOCKET;

        if (GetTime() - nStart > 20 * 60)
        {
            nErrorWait /= 3;
            nRetryWait /= 3;
        }

        nRetryWait = nRetryWait * 11 / 10;
        if (!Wait(nRetryWait += 60))
            return;
    }
}

#ifdef TEST
int main(int argc, char *argv[])
{
    WSADATA wsadata;
    if (WSAStartup(MAKEWORD(2,2), &wsadata) != NO_ERROR)
    {
        printf("Error at WSAStartup()\n");
        return false;
    }

    ThreadIRCSeed(NULL);

    WSACleanup();
    return 0;
}
#endif
<|endoftext|>


<commit_before>#ifndef _PWRE_HPP
#define _PWRE_HPP

#include <string>
#include <vector>
#include <functional>
#include <atomic>
#include <thread>
#include <chrono>

namespace Pwre {
	// Blocking current GUI work, wait GUI environment quit, but doesn't stop other GUI works.
	// GUI thread use only.
	void WaitQuit();

	// Blocking current GUI work, wait flag is true, but doesn't stop other GUI works.
	// GUI thread use only.
	void Wait(const std::atomic<bool> &flag);

	// Wake up sleeping GUI thread (if is).
	// All threads can use, but GUI thread can't wake up self.
	void WakeUp();

	// Add a task to GUI thread, and return a function for delete this task.
	// Argument "count" is 0 for unlimited, "interval" in milliseconds.
	// All threads can use.
	std::function<void()> AddTask(
		const std::function<void()> &,
		size_t count = 0,
		size_t interval = 0
	);

	struct Point {
		int x, y;
	};

	struct Size {
		int width, height;
	};

	struct Bounds {
		int left, top, right, bottom;
	};

	struct ActionArea {
		Bounds outer;
		Bounds border;
		Bounds control;
	};

	template <typename Ret, typename... Args>
	class EventHandler {
		public:
			std::function<void()> Add(const std::function<Ret(Args...)> &handler) {
				_funcs.push_back(handler);
				auto it = --_funcs.end();
				return [this, it](){
					this->_funcs.erase(it);
				};
			}
		protected:
			std::vector<std::function<Ret(Args...)>> _funcs;
	};

	template <typename... Args>
	class EventAcceptor : public EventHandler<bool, Args...> {
		public:
			bool Accept(Args... a) {
				for (auto rit = this->_funcs.rbegin(); rit != this->_funcs.rend(); rit++) {
					if (!(*rit)(a...)) {
						return false;
					}
				}
				return true;
			}
	};

	template <typename... Args>
	class EventReceiver : public EventHandler<void, Args...> {
		public:
			void Receive(Args... a) {
				for (auto rit = this->_funcs.rbegin(); rit != this->_funcs.rend(); rit++) {
					(*rit)(a...);
				}
			}
	};

	class Window {
		public:
			#define PWRE_HINT_ALPHA 0x00000001 // Support for Windows Vista+ (suggest less), X11 (only GL), macOS.
			#define PWRE_HINT_BLUR 0x00000010 // Support for Windows Vista/7 (only Aero Glass), Windows 10 (unpublished API, not perfect, suggest less), macOS.
			#define PWRE_HINT_WMBACKGROUND 0x00000002 // Support for Windows Vista+ (Aero Glass will automatically blur, but when less only shadow), macOS.

			Window(uint64_t hints = 0);
			~Window();

			void Close();
			void Destroy();

			uintptr_t NativeObj();

			std::string Title();
			void Retitle(const std::string &);

			#define PWRE_MOVE_AUTO -10101

			void Pos(int &x, int &y);
			void Move(int x = PWRE_MOVE_AUTO, int y = PWRE_MOVE_AUTO);

			void Size(int &width, int &height);
			void Resize(int width, int height);

			#define PWRE_STATE_VISIBLE 0x00000001
			#define PWRE_STATE_MINIMIZE 0x00000010
			#define PWRE_STATE_MAXIMIZE 0x00000100
			#define PWRE_STATE_FULLSCREEN 0x00001000

			void AddStates(uint32_t);
			void RmStates(uint32_t);
			bool HasStates(uint32_t);

			void Less(bool);
			bool CustomActionArea(const ActionArea &);

			EventAcceptor<> OnClose;
			EventReceiver<> OnDestroy;
			EventReceiver<int/*width*/, int/*height*/> OnSize;
			EventReceiver<int/*x*/, int/*y*/> OnMove;
			EventReceiver<> OnPaint;
			EventReceiver<int/*x*/, int/*y*/> OnMouseMove;
			EventReceiver<int/*x*/, int/*y*/> OnMouseDown;
			EventReceiver<int/*x*/, int/*y*/> OnMouseUp;
			EventReceiver<int/*keyCode*/> OnKeyDown;
			EventReceiver<int/*keyCode*/> OnKeyUp;

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

			struct _BlackBox;
			_BlackBox *_m;
	};

	namespace GL {
		class Window : public Pwre::Window {
			public:
				#define PWRE_HINT_GL_V3 0x3000000000

				Window(uint64_t hints = 0);
				~Window();

				uintptr_t NativeGLCtx();
				void MakeCurrent();
				void SwapBuffers();

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

				struct _BlackBox;
				_BlackBox *_glm;
		};

		inline uintptr_t NativeGLCtx(Pwre::Window *wnd) {
			return static_cast<Pwre::GL::Window *>(wnd)->NativeGLCtx();
		}

		inline void MakeCurrent(Pwre::Window *wnd) {
			static_cast<Pwre::GL::Window *>(wnd)->MakeCurrent();
		}

		inline void SwapBuffers(Pwre::Window *wnd) {
			static_cast<Pwre::GL::Window *>(wnd)->SwapBuffers();
		}
	} /* GL */
} /* Pwre */

#endif // !_PWRE_HPP
<commit_msg>Added WaitNewThrd()<commit_after>#ifndef _PWRE_HPP
#define _PWRE_HPP

#include <string>
#include <vector>
#include <functional>
#include <atomic>
#include <thread>
#include <chrono>

namespace Pwre {
	// Block current GUI work, until GUI environment quit, but doesn't stop other GUI works.
	// GUI thread use only.
	void WaitQuit();

	// Block current GUI work, until flag is true, but doesn't stop other GUI works.
	// GUI thread use only.
	void Wait(const std::atomic<bool> &flag);

	// Wake up sleeping GUI thread (if is).
	// All threads can use, but GUI thread can't wake up self.
	void WakeUp();

	// Add a task to GUI thread, and return a function for delete this task.
	// Argument "count" is 0 for unlimited, "interval" in milliseconds.
	// All threads can use.
	std::function<void()> AddTask(
		const std::function<void()> &,
		size_t count = 0,
		size_t interval = 0
	);

	// Block current GUI work, until new thread finishes its execution, but doesn't stop other GUI works.
	// GUI thread use only.
	template <typename R>
	R WaitNewThrd(const std::function<R()> &func) {
		std::atomic<bool> done(false);
		R reuslt;
		std::thread thrd([func, &done, &reuslt]() {
			reuslt = func();
			done = true;
		});
		Wait(done);
		return reuslt;
	}

	struct Point {
		int x, y;
	};

	struct Size {
		int width, height;
	};

	struct Bounds {
		int left, top, right, bottom;
	};

	struct ActionArea {
		Bounds outer;
		Bounds border;
		Bounds control;
	};

	template <typename Ret, typename... Args>
	class EventHandler {
		public:
			std::function<void()> Add(const std::function<Ret(Args...)> &handler) {
				_funcs.push_back(handler);
				auto it = --_funcs.end();
				return [this, it](){
					this->_funcs.erase(it);
				};
			}
		protected:
			std::vector<std::function<Ret(Args...)>> _funcs;
	};

	template <typename... Args>
	class EventAcceptor : public EventHandler<bool, Args...> {
		public:
			bool Accept(Args... a) {
				for (auto rit = this->_funcs.rbegin(); rit != this->_funcs.rend(); rit++) {
					if (!(*rit)(a...)) {
						return false;
					}
				}
				return true;
			}
	};

	template <typename... Args>
	class EventReceiver : public EventHandler<void, Args...> {
		public:
			void Receive(Args... a) {
				for (auto rit = this->_funcs.rbegin(); rit != this->_funcs.rend(); rit++) {
					(*rit)(a...);
				}
			}
	};

	class Window {
		public:
			#define PWRE_HINT_ALPHA 0x00000001 // Support for Windows Vista+ (suggest less), X11 (only GL), macOS.
			#define PWRE_HINT_BLUR 0x00000010 // Support for Windows Vista/7 (only Aero Glass), Windows 10 (unpublished API, not perfect, suggest less), macOS.
			#define PWRE_HINT_WMBACKGROUND 0x00000002 // Support for Windows Vista+ (Aero Glass will automatically blur, but when less only shadow), macOS.

			Window(uint64_t hints = 0);
			~Window();

			void Close();
			void Destroy();

			uintptr_t NativeObj();

			std::string Title();
			void Retitle(const std::string &);

			#define PWRE_MOVE_AUTO -10101

			void Pos(int &x, int &y);
			void Move(int x = PWRE_MOVE_AUTO, int y = PWRE_MOVE_AUTO);

			void Size(int &width, int &height);
			void Resize(int width, int height);

			#define PWRE_STATE_VISIBLE 0x00000001
			#define PWRE_STATE_MINIMIZE 0x00000010
			#define PWRE_STATE_MAXIMIZE 0x00000100
			#define PWRE_STATE_FULLSCREEN 0x00001000

			void AddStates(uint32_t);
			void RmStates(uint32_t);
			bool HasStates(uint32_t);

			void Less(bool);
			bool CustomActionArea(const ActionArea &);

			EventAcceptor<> OnClose;
			EventReceiver<> OnDestroy;
			EventReceiver<int/*width*/, int/*height*/> OnSize;
			EventReceiver<int/*x*/, int/*y*/> OnMove;
			EventReceiver<> OnPaint;
			EventReceiver<int/*x*/, int/*y*/> OnMouseMove;
			EventReceiver<int/*x*/, int/*y*/> OnMouseDown;
			EventReceiver<int/*x*/, int/*y*/> OnMouseUp;
			EventReceiver<int/*keyCode*/> OnKeyDown;
			EventReceiver<int/*keyCode*/> OnKeyUp;

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

			struct _BlackBox;
			_BlackBox *_m;
	};

	namespace GL {
		class Window : public Pwre::Window {
			public:
				#define PWRE_HINT_GL_V3 0x3000000000

				Window(uint64_t hints = 0);
				~Window();

				uintptr_t NativeGLCtx();
				void MakeCurrent();
				void SwapBuffers();

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

				struct _BlackBox;
				_BlackBox *_glm;
		};

		inline uintptr_t NativeGLCtx(Pwre::Window *wnd) {
			return static_cast<Pwre::GL::Window *>(wnd)->NativeGLCtx();
		}

		inline void MakeCurrent(Pwre::Window *wnd) {
			static_cast<Pwre::GL::Window *>(wnd)->MakeCurrent();
		}

		inline void SwapBuffers(Pwre::Window *wnd) {
			static_cast<Pwre::GL::Window *>(wnd)->SwapBuffers();
		}
	} /* GL */
} /* Pwre */

#endif // !_PWRE_HPP
<|endoftext|>


<commit_before>#ifndef face_hh_INCLUDED
#define face_hh_INCLUDED

#include "color.hh"

namespace Kakoune
{

enum class Attribute : int
{
    Normal    = 0,
    Underline = 1 << 1,
    Reverse   = 1 << 2,
    Blink     = 1 << 3,
    Bold      = 1 << 4,
    Dim       = 1 << 5
};

inline constexpr Attribute operator|(Attribute lhs, Attribute rhs)
{
    return (Attribute)((int) lhs | (int) rhs);
}

inline Attribute& operator|=(Attribute& lhs, Attribute rhs)
{
    return (Attribute&)((int&) lhs |= (int) rhs);
}

inline constexpr bool operator&(Attribute lhs, Attribute rhs)
{
    return ((int) lhs & (int) rhs) != 0;
}

inline Attribute& operator&=(Attribute& lhs, Attribute rhs)
{
    return (Attribute&)((int&) lhs &= (int) rhs);
}

struct Face
{
    Color fg;
    Color bg;
    Attribute attributes;

    Face(Color fg = Colors::Default, Color bg = Colors::Default,
         Attribute attributes = Attribute::Normal)
      : fg{fg}, bg{bg}, attributes{attributes} {}
};

inline bool operator==(const Face& lhs, const Face& rhs)
{
    return lhs.fg == rhs.fg and
           lhs.bg == rhs.bg and
           lhs.attributes == rhs.attributes;
}

inline bool operator!=(const Face& lhs, const Face& rhs)
{
    return not (lhs == rhs);
}

}

#endif // face_hh_INCLUDED

<commit_msg>Use general flags utility for Face Attribute<commit_after>#ifndef face_hh_INCLUDED
#define face_hh_INCLUDED

#include "color.hh"
#include "flags.hh"

namespace Kakoune
{

enum class Attribute : int
{
    Normal    = 0,
    Underline = 1 << 1,
    Reverse   = 1 << 2,
    Blink     = 1 << 3,
    Bold      = 1 << 4,
    Dim       = 1 << 5
};

template<> struct WithBitOps<Attribute> : std::true_type {};

struct Face
{
    Color fg;
    Color bg;
    Attribute attributes;

    Face(Color fg = Colors::Default, Color bg = Colors::Default,
         Attribute attributes = Attribute::Normal)
      : fg{fg}, bg{bg}, attributes{attributes} {}
};

inline bool operator==(const Face& lhs, const Face& rhs)
{
    return lhs.fg == rhs.fg and
           lhs.bg == rhs.bg and
           lhs.attributes == rhs.attributes;
}

inline bool operator!=(const Face& lhs, const Face& rhs)
{
    return not (lhs == rhs);
}

}

#endif // face_hh_INCLUDED

<|endoftext|>


<commit_before>#include "file.hh"

#include "buffer.hh"
#include "buffer_manager.hh"
#include "assert.hh"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstring>

namespace Kakoune
{

Buffer* create_buffer_from_file(const std::string& filename)
{
    int fd = open(filename.c_str(), O_RDONLY);
    if (fd == -1)
    {
        if (errno == ENOENT)
            throw file_not_found(filename);

        throw file_access_error(filename, strerror(errno));
    }

    std::string content;
    char buf[256];
    while (true)
    {
        ssize_t size = read(fd, buf, 256);
        if (size == -1 or size == 0)
            break;

        content += std::string(buf, size);
    }
    close(fd);

    if (Buffer* buffer = BufferManager::instance().get_buffer(filename))
        BufferManager::instance().delete_buffer(buffer);

    return new Buffer(filename, content);
}

void write_buffer_to_file(const Buffer& buffer, const std::string& filename)
{
    int fd = open(filename.c_str(), O_CREAT | O_WRONLY, 0644);
    if (fd == -1)
        throw file_access_error(filename, strerror(errno));

    const BufferString& content = buffer.content();
    ssize_t count = content.length() * sizeof(BufferChar);
    const char* ptr = content.c_str();

    while (count)
    {
        ssize_t written = write(fd, ptr, count);
        ptr += written;
        count -= written;

        if (written == -1)
            throw file_access_error(filename, strerror(errno));
    }
    close(fd);
}

}
<commit_msg>File: fix write_buffer_to_file<commit_after>#include "file.hh"

#include "buffer.hh"
#include "buffer_manager.hh"
#include "assert.hh"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstring>

namespace Kakoune
{

Buffer* create_buffer_from_file(const std::string& filename)
{
    int fd = open(filename.c_str(), O_RDONLY);
    if (fd == -1)
    {
        if (errno == ENOENT)
            throw file_not_found(filename);

        throw file_access_error(filename, strerror(errno));
    }

    std::string content;
    char buf[256];
    while (true)
    {
        ssize_t size = read(fd, buf, 256);
        if (size == -1 or size == 0)
            break;

        content += std::string(buf, size);
    }
    close(fd);

    if (Buffer* buffer = BufferManager::instance().get_buffer(filename))
        BufferManager::instance().delete_buffer(buffer);

    return new Buffer(filename, content);
}

void write_buffer_to_file(const Buffer& buffer, const std::string& filename)
{
    int fd = open(filename.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
    if (fd == -1)
        throw file_access_error(filename, strerror(errno));

    const BufferString& content = buffer.content();
    ssize_t count = content.length() * sizeof(BufferChar);
    const char* ptr = content.c_str();

    while (count)
    {
        ssize_t written = write(fd, ptr, count);
        ptr += written;
        count -= written;

        if (written == -1)
            throw file_access_error(filename, strerror(errno));
    }
    close(fd);
}

}
<|endoftext|>


<commit_before>//===-- XBeeSyncServer.cpp - XBee Syncing for GameModel ------------ c++ --===//
//
//                               UWH Timer
//
//           This file is distributed under the BSD 3-Clause License.
//                      See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "uwhd/sync/ModelSync.h"

#include "uwhd/model/GameModel.h"

#include <cassert>
#include <cstdint>
#include <cstring>
#include <errno.h>
#include <fcntl.h>
#include <iomanip>
#include <iostream>
#include <memory>
#include <queue>
#include <semaphore.h>
#include <sstream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <termios.h>
#include <thread>
#include <time.h>
#include <unistd.h>

// Serial comm stuff copied from: http://stackoverflow.com/a/6947758
int set_interface_attribs(int fd, int speed, int parity) {
  struct termios tty;
  memset (&tty, 0, sizeof tty);
  if (tcgetattr (fd, &tty) != 0)
  {
    printf("error %d from tcgetattr", errno);
    return -1;
  }

  cfsetospeed (&tty, speed);
  cfsetispeed (&tty, speed);

  tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;     // 8-bit chars
  // disable IGNBRK for mismatched speed tests; otherwise receive break
  // as \000 chars
  tty.c_iflag &= ~IGNBRK;         // disable break processing
  tty.c_lflag = 0;                // no signaling chars, no echo,
  // no canonical processing
  tty.c_oflag = 0;                // no remapping, no delays
  tty.c_cc[VMIN]  = 0;            // read doesn't block
  tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

  tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl

  tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
  // enable reading
  tty.c_cflag &= ~(PARENB | PARODD);      // shut off parity
  tty.c_cflag |= parity;
  tty.c_cflag &= ~CSTOPB;
  tty.c_cflag &= ~CRTSCTS;

  if (tcsetattr (fd, TCSANOW, &tty) != 0)
  {
    printf("error %d from tcsetattr", errno);
    return -1;
  }
  return 0;
}

void set_blocking(int fd, int should_block) {
  struct termios tty;
  memset(&tty, 0, sizeof tty);
  if (tcgetattr(fd, &tty) != 0)
  {
    printf("error %d from tggetattr", errno);
    return;
  }

  tty.c_cc[VMIN]  = should_block ? 1 : 0;
  tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

  if (tcsetattr(fd, TCSANOW, &tty) != 0)
    printf("error %d setting term attributes", errno);
}

namespace {

class XBeeSyncServer : public ModelSyncServer, GameModelManager {
public:
  XBeeSyncServer();
  ~XBeeSyncServer();

  virtual void Init() override;

  virtual void setMgr(GameModelManager *NewM) {
    assert(!M);
    M = NewM;
    M->registerListener(this);
  }

  virtual GameModelManager &getMgr() override { return *M; }

  virtual void modelChanged(GameModel Model) override;
private:
  int fd;
  GameModelManager *M;

  static const char *XBeeSerialConsole;
  static const int XBeeBaudRate;
};

class XBeeSyncClient : public ModelSync {
public:
  XBeeSyncClient();
  ~XBeeSyncClient();

  virtual void Init() override;

  virtual void setMgr(GameModelManager *NewM) {
    assert(!M);
    M = NewM;
    //M->registerListener(this);
  }

  virtual GameModelManager &getMgr() override { return *M; }

  void receivedModel(GameModel Model);

protected:

private:
  int fd;
  GameModelManager *M;

  static const char *XBeeSerialConsole;
  static const int   XBeeBaudRate;
};

} // anonymous namespace

const char *XBeeSyncServer::XBeeSerialConsole = "/dev/ttyAMA0";
const int   XBeeSyncServer::XBeeBaudRate      = 9600;
const char *XBeeSyncClient::XBeeSerialConsole = "/dev/ttyAMA0";
const int   XBeeSyncClient::XBeeBaudRate      = 9600;

XBeeSyncServer::XBeeSyncServer()
  : fd(0), M(nullptr) {
}

XBeeSyncServer::~XBeeSyncServer() {
}

void XBeeSyncServer::Init() {
  char *portname = "/dev/ttyAMA0";
  fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
  if (fd < 0) {
    printf("error %d opening %s: %s", errno, portname, strerror (errno));
    return;
  }
  set_interface_attribs(fd, B9600, 0);  // set speed to 9600 bps, 8n1 (no parity)
  set_blocking(fd, 0);                  // set no blocking
}

void XBeeSyncServer::modelChanged(GameModel Model) {
  std::string Message = Model.serialize();
  write(fd, Message.c_str(), Message.size());
}

XBeeSyncClient::XBeeSyncClient()
  : fd(0), M(nullptr) {
}

XBeeSyncClient::~XBeeSyncClient() {
}

void XBeeSyncClient::Init() {
  char *portname = "/dev/ttyAMA0";
  fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
  if (fd < 0) {
    printf("error %d opening %s: %s", errno, portname, strerror (errno));
    return;
  }
  set_interface_attribs(fd, B9600, 0);  // set speed to 9600 bps, 8n1 (no parity)
  set_blocking(fd, 1);                  // set no blocking

  std::thread([this]() {
    std::queue<char> Queue;
    std::stringstream Msg;
    do {
      char buf[128];
      memset(buf, 0, sizeof(buf));
      int n = read(fd, buf, sizeof(buf));

      //printf("read: [%s]\n", buf);

      for (int i = 0; i < n; ++i)
        Queue.push(buf[i]);

      while (!Queue.empty()) {
        char C = Queue.front();
        Msg << C;
        Queue.pop();

        if (C == 'E') {
          GameModel Model;
          if (GameModel::deSerialize(Msg.str(), Model)) {
            printf("failed to deserialize [%s]\n", Msg.str().c_str());
          } else {
            //printf("updating model:\n");
            receivedModel(Model);
          }

          Msg.str("");
          Msg.clear();
        }
      }

      usleep(100);
    } while (true);
  }).detach();
}

void XBeeSyncClient::receivedModel(GameModel Model) {
  Model.setPrevStartTime();
  M->setModel(Model);
}

ModelSyncServer *CreateXBeeSyncServer() {
  return new XBeeSyncServer();
}

ModelSync *CreateXBeeSyncClient() {
  return new XBeeSyncClient();
}

<commit_msg>[sync] Send model updates from the sever<commit_after>//===-- XBeeSyncServer.cpp - XBee Syncing for GameModel ------------ c++ --===//
//
//                               UWH Timer
//
//           This file is distributed under the BSD 3-Clause License.
//                      See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "uwhd/sync/ModelSync.h"

#include "uwhd/model/GameModel.h"

#include <cassert>
#include <cstdint>
#include <cstring>
#include <errno.h>
#include <fcntl.h>
#include <iomanip>
#include <iostream>
#include <memory>
#include <queue>
#include <semaphore.h>
#include <sstream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <termios.h>
#include <thread>
#include <time.h>
#include <unistd.h>

// Serial comm stuff copied from: http://stackoverflow.com/a/6947758
int set_interface_attribs(int fd, int speed, int parity) {
  struct termios tty;
  memset (&tty, 0, sizeof tty);
  if (tcgetattr (fd, &tty) != 0)
  {
    printf("error %d from tcgetattr", errno);
    return -1;
  }

  cfsetospeed (&tty, speed);
  cfsetispeed (&tty, speed);

  tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;     // 8-bit chars
  // disable IGNBRK for mismatched speed tests; otherwise receive break
  // as \000 chars
  tty.c_iflag &= ~IGNBRK;         // disable break processing
  tty.c_lflag = 0;                // no signaling chars, no echo,
  // no canonical processing
  tty.c_oflag = 0;                // no remapping, no delays
  tty.c_cc[VMIN]  = 0;            // read doesn't block
  tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

  tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl

  tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
  // enable reading
  tty.c_cflag &= ~(PARENB | PARODD);      // shut off parity
  tty.c_cflag |= parity;
  tty.c_cflag &= ~CSTOPB;
  tty.c_cflag &= ~CRTSCTS;

  if (tcsetattr (fd, TCSANOW, &tty) != 0)
  {
    printf("error %d from tcsetattr", errno);
    return -1;
  }
  return 0;
}

void set_blocking(int fd, int should_block) {
  struct termios tty;
  memset(&tty, 0, sizeof tty);
  if (tcgetattr(fd, &tty) != 0)
  {
    printf("error %d from tggetattr", errno);
    return;
  }

  tty.c_cc[VMIN]  = should_block ? 1 : 0;
  tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

  if (tcsetattr(fd, TCSANOW, &tty) != 0)
    printf("error %d setting term attributes", errno);
}

namespace {

class XBeeSyncServer : public ModelSyncServer, GameModelManager {
public:
  XBeeSyncServer();
  ~XBeeSyncServer();

  virtual void Init() override;

  virtual void setMgr(GameModelManager *NewM) {
    assert(!M);
    M = NewM;
    M->registerListener(this);
  }

  virtual GameModelManager &getMgr() override { return *M; }

  virtual void modelChanged(GameModel Model) override;

  virtual void heartbeat() override;
private:
  int fd;
  GameModelManager *M;

  static const char *XBeeSerialConsole;
  static const int XBeeBaudRate;
};

class XBeeSyncClient : public ModelSync {
public:
  XBeeSyncClient();
  ~XBeeSyncClient();

  virtual void Init() override;

  virtual void setMgr(GameModelManager *NewM) {
    assert(!M);
    M = NewM;
    //M->registerListener(this);
  }

  virtual GameModelManager &getMgr() override { return *M; }

  void receivedModel(GameModel Model);

protected:

private:
  int fd;
  GameModelManager *M;

  static const char *XBeeSerialConsole;
  static const int   XBeeBaudRate;
};

} // anonymous namespace

const char *XBeeSyncServer::XBeeSerialConsole = "/dev/ttyAMA0";
const int   XBeeSyncServer::XBeeBaudRate      = 9600;
const char *XBeeSyncClient::XBeeSerialConsole = "/dev/ttyAMA0";
const int   XBeeSyncClient::XBeeBaudRate      = 9600;

XBeeSyncServer::XBeeSyncServer()
  : fd(0), M(nullptr) {
}

XBeeSyncServer::~XBeeSyncServer() {
}

void XBeeSyncServer::Init() {
  char *portname = "/dev/ttyAMA0";
  fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
  if (fd < 0) {
    printf("error %d opening %s: %s", errno, portname, strerror (errno));
    return;
  }
  set_interface_attribs(fd, B9600, 0);  // set speed to 9600 bps, 8n1 (no parity)
  set_blocking(fd, 0);                  // set no blocking
}

void XBeeSyncServer::modelChanged(GameModel Model) {
  std::string Message = Model.serialize();
  write(fd, Message.c_str(), Message.size());
}

void XBeeSyncServer::heartbeat() {
  modelChanged(M->getModel());
}

XBeeSyncClient::XBeeSyncClient()
  : fd(0), M(nullptr) {
}

XBeeSyncClient::~XBeeSyncClient() {
}

void XBeeSyncClient::Init() {
  char *portname = "/dev/ttyAMA0";
  fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
  if (fd < 0) {
    printf("error %d opening %s: %s", errno, portname, strerror (errno));
    return;
  }
  set_interface_attribs(fd, B9600, 0);  // set speed to 9600 bps, 8n1 (no parity)
  set_blocking(fd, 1);                  // set no blocking

  std::thread([this]() {
    std::queue<char> Queue;
    std::stringstream Msg;
    do {
      char buf[128];
      memset(buf, 0, sizeof(buf));
      int n = read(fd, buf, sizeof(buf));

      //printf("read: [%s]\n", buf);

      for (int i = 0; i < n; ++i)
        Queue.push(buf[i]);

      while (!Queue.empty()) {
        char C = Queue.front();
        Msg << C;
        Queue.pop();

        if (C == 'E') {
          GameModel Model;
          if (GameModel::deSerialize(Msg.str(), Model)) {
            printf("failed to deserialize [%s]\n", Msg.str().c_str());
          } else {
            //printf("updating model:\n");
            receivedModel(Model);
          }

          Msg.str("");
          Msg.clear();
        }
      }

      usleep(100);
    } while (true);
  }).detach();
}

void XBeeSyncClient::receivedModel(GameModel Model) {
  Model.setPrevStartTime();
  M->setModel(Model);
}

ModelSyncServer *CreateXBeeSyncServer() {
  return new XBeeSyncServer();
}

ModelSync *CreateXBeeSyncClient() {
  return new XBeeSyncClient();
}

<|endoftext|>


<commit_before>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2018 The Cats Project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#ifndef CATS_CORECAT_SYSTEM_PROCESS_HPP
#define CATS_CORECAT_SYSTEM_PROCESS_HPP

#include "OS.hpp"
#include "../Data/Array.hpp"
#include "../Text/String.hpp"
#include "../Util/Exception.hpp"

#if defined(CORECAT_OS_WINDOWS)
#   include "../Win32/Windows.hpp"
#elif defined(CORECAT_OS_LINUX) || defined(CORECAT_OS_MACOS)
#   include <spawn.h>
#else
#   error Unknown OS
#endif

namespace Cats {
namespace Corecat {
inline namespace System {

class Process {

#if defined(CORECAT_OS_WINDOWS)
private:

    static WString getFullPath(const WString& file) {

        HMODULE module = ::LoadLibraryW(file.getData());
        if(!module) return {};
        WString path;
        path.setLength(MAX_PATH);
        while(true) {

            DWORD pathLength = ::GetModuleFileNameW(module, path.getData(), path.getLength() + 1);
            if(::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {

                path.setLength(path.getLength() * 2);
                continue;

            }
            if(!pathLength) {

                ::FreeLibrary(module);
                return {};

            }
            path.setLength(pathLength);
            break;

        }
        ::FreeLibrary(module);
        return path;

    }

    static WString findFullPath(const WString& file) {

        WString path;
        path = getFullPath(file + L'.');
        if(!path.isEmpty()) return path;
        path = getFullPath(file + L".exe.");
        if(!path.isEmpty()) return path;
        throw SystemException("File not found");

    }
#endif

public:

    Process(const char* file, ArrayView<const char* const> argv) {
#if defined(CORECAT_OS_WINDOWS)
        WString argument;
        for(auto&& arg : argv) {

            if(!argument.isEmpty()) argument += L' ';
            argument += L'"';
            for(auto&& c : WString(arg)) {

                if(c == L'"') argument += L"\\\"";
                else if(c == L'\\') argument += L"\\\\";
                else argument += c;

            }
            argument += L'"';

        }
        STARTUPINFOW si = {};
        si.cb = sizeof(si);
        PROCESS_INFORMATION pi = {};
        auto path = findFullPath(WString(file));
        if(!::CreateProcessW(path.getData(), argument.getData(), nullptr, nullptr, false, 0, nullptr, nullptr, &si, &pi))
            throw SystemException("::CreateProcessW failed");
        ::CloseHandle(pi.hProcess);
        ::CloseHandle(pi.hThread);
#else
        pid_t pid;
        Array<const char*> argument(argv.getSize() + 1);
        std::copy(argv.begin(), argv.end(), argument.begin());
        argument[argv.getSize()] = nullptr;
        if(::posix_spawnp(&pid, file, nullptr, nullptr, argument, nullptr))
            throw SystemException("::posix_spawn failed");
#endif
    }
    Process(const Process& src) = delete;
    ~Process() {}

    Process& operator =(const Process& src) = delete;

};

}
}
}

#endif
<commit_msg>Update Process<commit_after>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2018 The Cats Project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#ifndef CATS_CORECAT_SYSTEM_PROCESS_HPP
#define CATS_CORECAT_SYSTEM_PROCESS_HPP

#include "OS.hpp"
#include "../Data/Array.hpp"
#include "../Text/String.hpp"
#include "../Util/Exception.hpp"

#if defined(CORECAT_OS_WINDOWS)
#   include "../Win32/Windows.hpp"
#elif defined(CORECAT_OS_LINUX) || defined(CORECAT_OS_MACOS)
#   include <spawn.h>
#else
#   error Unknown OS
#endif

namespace Cats {
namespace Corecat {
inline namespace System {

class Process {

#if defined(CORECAT_OS_WINDOWS)
private:

    static WString getFullPath(const WString& file) {

        HMODULE module = ::LoadLibraryW(file.getData());
        if(!module) return {};
        WString path;
        path.setLength(MAX_PATH);
        while(true) {

            DWORD pathLength = ::GetModuleFileNameW(module, path.getData(), path.getLength() + 1);
            if(::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {

                path.setLength(path.getLength() * 2);
                continue;

            }
            if(!pathLength) {

                ::FreeLibrary(module);
                return {};

            }
            path.setLength(pathLength);
            break;

        }
        ::FreeLibrary(module);
        return path;

    }

    static WString findFullPath(const WString& file) {

        WString path;
        path = getFullPath(file + L'.');
        if(!path.isEmpty()) return path;
        path = getFullPath(file + L".exe.");
        if(!path.isEmpty()) return path;
        throw SystemException("File not found");

    }
#endif

public:

    Process(const char* file, ArrayView<const char* const> argv) {
#if defined(CORECAT_OS_WINDOWS)
        WString argument;
        for(auto&& arg : argv) {

            if(!argument.isEmpty()) argument += L' ';
            argument += L'"';
            for(auto&& c : WString(arg)) {

                if(c == L'"') argument += L"\\\"";
                else if(c == L'\\') argument += L"\\\\";
                else argument += c;

            }
            argument += L'"';

        }
        STARTUPINFOW si = {};
        si.cb = sizeof(si);
        PROCESS_INFORMATION pi = {};
        auto path = findFullPath(WString(file));
        if(!::CreateProcessW(path.getData(), argument.getData(), nullptr, nullptr, false, 0, nullptr, nullptr, &si, &pi))
            throw SystemException("::CreateProcessW failed");
        ::CloseHandle(pi.hProcess);
        ::CloseHandle(pi.hThread);
#else
        pid_t pid;
        Array<const char*> argument(argv.getSize() + 1);
        std::copy(argv.begin(), argv.end(), argument.begin());
        argument[argv.getSize()] = nullptr;
        if(::posix_spawnp(&pid, file, nullptr, nullptr, const_cast<char* const*>(argument.getData()), nullptr))
            throw SystemException("::posix_spawn failed");
#endif
    }
    Process(const Process& src) = delete;
    ~Process() {}

    Process& operator =(const Process& src) = delete;

};

}
}
}

#endif
<|endoftext|>