<commit_before>#include <cstring>
#include <fstream>
#include <list>

#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/msg.h>
#include <sys/stat.h>

#include "global.h"

#include "judge.h"
#include "scoreboard.h"
#include "rejudger.h"
#include "webserver.h"

using namespace std;

static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER;
Settings::Settings() {
  memset(this, 0, sizeof(::Settings));
  fstream f("settings.txt");
  if (!f.is_open()) return;
  string tmp;
  auto func = [&](time_t& buf) {
    int Y, M, D, h, m;
    f >> tmp >> Y >> M >> D >> h >> m;
    time(&buf);
    pthread_mutex_lock(&localtime_mutex);
    tm* tinfo = localtime(&buf);
    tm ti = *tinfo;
    pthread_mutex_unlock(&localtime_mutex);
    ti.tm_year = Y - 1900;
    ti.tm_mon  = M - 1;
    ti.tm_mday = D;
    ti.tm_hour = h;
    ti.tm_min  = m;
    ti.tm_sec  = 0;
    buf = mktime(&ti);
  };
  func(begin);
  func(end);
  func(freeze);
  func(noverdict);
  int problems;
  f >> tmp >> problems;
  this->problems = vector<int>(problems);
  for (int i = 0; i < problems; i++) {
    f >> tmp >> this->problems[i];
  }
}

rejudgemsg::rejudgemsg(int id, char verdict)
: mtype(1), id(id), verdict(verdict) {}

size_t rejudgemsg::size() const { return sizeof(rejudgemsg)-sizeof(long); }

static __suseconds_t dt(const timeval& start) {
  timeval end;
  gettimeofday(&end, nullptr);
  return
    (end.tv_sec*1000000 + end.tv_usec)-
    (start.tv_sec*1000000 + start.tv_usec)
  ;
}
int timeout(bool& tle, int s, const char* cmd) {
  tle = false;
  __suseconds_t us = s*1000000;

  timeval start;
  gettimeofday(&start, nullptr);

  pid_t proc = fork();
  if (!proc) {
    setpgid(0, 0); // create new process group rooted at proc
    int status = system(cmd);
    exit(WEXITSTATUS(status));
  }

  int status;
  while (waitpid(proc, &status, WNOHANG) != proc) {
    if (dt(start) > us) {
      tle = true;
      kill(-proc, SIGKILL); //the minus kills the whole group rooted at proc
      waitpid(proc, &status, 0);
      break;
    }
    usleep(10000);
  }
  return status;
}

void ignoresd(int sd) {
  char* buf = new char[1 << 10];
  while (read(sd, buf, 1 << 10) == (1 << 10));
  delete[] buf;
}

template <>
string to<string, in_addr_t>(const in_addr_t& x) {
  char* ptr = (char*)&x;
  string ret = to<string>(int(ptr[0])&0x0ff);
  for (int i = 1; i < 4; i++) ret += ("."+to<string>(int(ptr[i])&0x0ff));
  return ret;
}

struct Contest {
  pid_t pid;
  key_t key;
  Contest(pid_t pid, key_t key) : pid(pid), key(key) {
    FILE* fp = fopen("contest.bin", "wb");
    fwrite(this, sizeof(Contest), 1, fp);
    fclose(fp);
  }
  Contest() : pid(0), key(0) {
    FILE* fp = fopen("contest.bin", "rb");
    if (!fp) return;
    fread(this, sizeof(Contest), 1, fp);
    fclose(fp);
  }
};

static bool quit = false;
static list<pthread_t> threads;
static pthread_mutex_t attfile_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t nextidfile_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t questionfile_mutex = PTHREAD_MUTEX_INITIALIZER;
static int msqid;

static key_t msgqueue() {
  key_t key = 0x713e24a;
  while ((msqid = msgget(key, (IPC_CREAT|IPC_EXCL)|0777)) < 0) key++;
  return key;
}

static void term(int) {
  msgctl(msqid, IPC_RMID, nullptr);
  remove("contest.bin");
  pthread_mutex_lock(&attfile_mutex);
  pthread_mutex_lock(&nextidfile_mutex);
  pthread_mutex_lock(&questionfile_mutex);
  quit = true;
  pthread_mutex_unlock(&questionfile_mutex);
  pthread_mutex_unlock(&nextidfile_mutex);
  pthread_mutex_unlock(&attfile_mutex);
  for (pthread_t& thread : threads) pthread_join(thread, nullptr);
  exit(0);
}

namespace Global {

vector<string> arg;

void install(const string& dir) {
  mkdir(dir.c_str(), 0777);
  FILE* fp = fopen((dir+"/settings.txt").c_str(), "w");
  fprintf(fp,
    "Begin:        2015 09 01 19 00\n"
    "End:          2015 12 25 23 50\n"
    "Freeze:       2015 12 25 23 50\n"
    "No-verdict:   2015 12 25 23 50\n"
    "Problems: 1\n"
    "A-timelimit: 1\n"
  );
  fclose(fp);
  fp = fopen((dir+"/teams.txt").c_str(), "w");
  fprintf(fp, "\"Team 1\" team1 team1pass\n");
  fclose(fp);
  fp = fopen((dir+"/clarifications.txt").c_str(), "w");
  fprintf(fp, "global A \"Question available to all teams\" \"Answer\"\n");
  fprintf(fp, "team1 C \"Question privately answered to team1\" \"Answer\"\n");
  fclose(fp);
  mkdir((dir+"/problems").c_str(), 0777);
  fp = fopen((dir+"/problems/A.in").c_str(), "w");
  fclose(fp);
  fp = fopen((dir+"/problems/A.sol").c_str(), "w");
  fclose(fp);
  system("cp -rf /usr/local/share/pjudge/www %s/www", dir.c_str());
}

void start(int argc, char** argv) {
  if (Contest().pid) return;
  arg = vector<string>(argc);
  for (int i = 0; i < argc; i++) arg[i] = argv[i];
  daemon(1, 0);
  Contest(getpid(), msgqueue());
  signal(SIGTERM, term);
  signal(SIGPIPE, SIG_IGN);
  Judge::fire();
  Scoreboard::fire();
  Rejudger::fire(msqid);
  WebServer::fire();
  for (pthread_t& thread : threads) pthread_join(thread, nullptr);
}

void stop() {
  Contest c;
  if (c.pid) kill(c.pid, SIGTERM);
}

void rejudge(int id, char verdict) {
  Contest c;
  if (!c.pid) Rejudger::rejudge(id, verdict);
  else {
    rejudgemsg msg(id, verdict);
    msgsnd(msgget(c.key, 0), &msg, msg.size(), 0);
  }
}

bool alive() {
  return !quit;
}

void fire(void* (*thread)(void*)) {
  threads.emplace_back();
  pthread_create(&threads.back(), nullptr, thread, nullptr);
}

void lock_att_file() {
  pthread_mutex_lock(&attfile_mutex);
}

void unlock_att_file() {
  pthread_mutex_unlock(&attfile_mutex);
}

void lock_nextid_file() {
  pthread_mutex_lock(&nextidfile_mutex);
}

void unlock_nextid_file() {
  pthread_mutex_unlock(&nextidfile_mutex);
}

void lock_question_file() {
  pthread_mutex_lock(&questionfile_mutex);
}

void unlock_question_file() {
  pthread_mutex_unlock(&questionfile_mutex);
}

} // namespace Global
<commit_msg>Improving comments<commit_after>#include <cstring>
#include <fstream>
#include <list>

#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/msg.h>
#include <sys/stat.h>

#include "global.h"

#include "judge.h"
#include "scoreboard.h"
#include "rejudger.h"
#include "webserver.h"

using namespace std;

static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER;
Settings::Settings() {
  memset(this, 0, sizeof(::Settings));
  fstream f("settings.txt");
  if (!f.is_open()) return;
  string tmp;
  auto func = [&](time_t& buf) {
    int Y, M, D, h, m;
    f >> tmp >> Y >> M >> D >> h >> m;
    time(&buf);
    pthread_mutex_lock(&localtime_mutex);
    tm* tinfo = localtime(&buf);
    tm ti = *tinfo;
    pthread_mutex_unlock(&localtime_mutex);
    ti.tm_year = Y - 1900;
    ti.tm_mon  = M - 1;
    ti.tm_mday = D;
    ti.tm_hour = h;
    ti.tm_min  = m;
    ti.tm_sec  = 0;
    buf = mktime(&ti);
  };
  func(begin);
  func(end);
  func(freeze);
  func(noverdict);
  int timelimit;
  while (f >> tmp >> timelimit) problems.push_back(timelimit);
}

rejudgemsg::rejudgemsg(int id, char verdict)
: mtype(1), id(id), verdict(verdict) {}

size_t rejudgemsg::size() const { return sizeof(rejudgemsg)-sizeof(long); }

static __suseconds_t dt(const timeval& start) {
  timeval end;
  gettimeofday(&end, nullptr);
  return
    (end.tv_sec*1000000 + end.tv_usec)-
    (start.tv_sec*1000000 + start.tv_usec)
  ;
}
int timeout(bool& tle, int s, const char* cmd) {
  tle = false;
  __suseconds_t us = s*1000000;

  timeval start;
  gettimeofday(&start, nullptr);

  pid_t proc = fork();
  if (!proc) {
    setpgid(0, 0); // create new process group rooted at proc
    int status = system(cmd);
    exit(WEXITSTATUS(status));
  }

  int status;
  while (waitpid(proc, &status, WNOHANG) != proc) {
    if (dt(start) > us) {
      tle = true;
      kill(-proc, SIGKILL); //the minus kills the whole group rooted at proc
      waitpid(proc, &status, 0);
      break;
    }
    usleep(10000);
  }
  return status;
}

void ignoresd(int sd) {
  char* buf = new char[1 << 10];
  while (read(sd, buf, 1 << 10) == (1 << 10));
  delete[] buf;
}

template <>
string to<string, in_addr_t>(const in_addr_t& x) {
  char* ptr = (char*)&x;
  string ret = to<string>(int(ptr[0])&0x0ff);
  for (int i = 1; i < 4; i++) ret += ("."+to<string>(int(ptr[i])&0x0ff));
  return ret;
}

struct Contest {
  pid_t pid;
  key_t key;
  Contest(pid_t pid, key_t key) : pid(pid), key(key) {
    FILE* fp = fopen("contest.bin", "wb");
    fwrite(this, sizeof(Contest), 1, fp);
    fclose(fp);
  }
  Contest() : pid(0), key(0) {
    FILE* fp = fopen("contest.bin", "rb");
    if (!fp) return;
    fread(this, sizeof(Contest), 1, fp);
    fclose(fp);
  }
};

static bool quit = false;
static list<pthread_t> threads;
static pthread_mutex_t attfile_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t nextidfile_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t questionfile_mutex = PTHREAD_MUTEX_INITIALIZER;
static int msqid;

static key_t msgqueue() {
  key_t key = 0x713e24a;
  while ((msqid = msgget(key, (IPC_CREAT|IPC_EXCL)|0777)) < 0) key++;
  return key;
}

static void term(int) {
  msgctl(msqid, IPC_RMID, nullptr);
  remove("contest.bin");
  pthread_mutex_lock(&attfile_mutex);
  pthread_mutex_lock(&nextidfile_mutex);
  pthread_mutex_lock(&questionfile_mutex);
  quit = true;
  pthread_mutex_unlock(&questionfile_mutex);
  pthread_mutex_unlock(&nextidfile_mutex);
  pthread_mutex_unlock(&attfile_mutex);
  for (pthread_t& thread : threads) pthread_join(thread, nullptr);
  exit(0);
}

namespace Global {

vector<string> arg;

void install(const string& dir) {
  mkdir(dir.c_str(), 0777);
  FILE* fp = fopen((dir+"/settings.txt").c_str(), "w");
  fprintf(fp,
    "Begin:  2015 09 01 19 00\n"
    "End:    2015 12 25 23 50\n"
    "Freeze: 2015 12 25 23 50\n"
    "Blind:  2015 12 25 23 50\n"
    "A(time-limit-in-seconds): 4\n"
    "B(these-comments-are-useless-and-can-be-removed): 3\n"
    "C: 5\n"
  );
  fclose(fp);
  fp = fopen((dir+"/teams.txt").c_str(), "w");
  fprintf(fp, "\"Team 1\" team1 team1pass\n");
  fclose(fp);
  fp = fopen((dir+"/clarifications.txt").c_str(), "w");
  fprintf(fp, "global A \"Question available to all teams\" \"Answer\"\n");
  fprintf(fp, "team1 C \"Question privately answered to team1\" \"Answer\"\n");
  fclose(fp);
  mkdir((dir+"/problems").c_str(), 0777);
  fp = fopen((dir+"/problems/A.in").c_str(), "w");
  fclose(fp);
  fp = fopen((dir+"/problems/A.sol").c_str(), "w");
  fclose(fp);
  fp = fopen((dir+"/problems/B.in").c_str(), "w");
  fclose(fp);
  fp = fopen((dir+"/problems/B.sol").c_str(), "w");
  fclose(fp);
  fp = fopen((dir+"/problems/C.in").c_str(), "w");
  fclose(fp);
  fp = fopen((dir+"/problems/C.sol").c_str(), "w");
  fclose(fp);
  system("cp -rf /usr/local/share/pjudge/www %s/www", dir.c_str());
}

void start(int argc, char** argv) {
  if (Contest().pid) return;
  arg = vector<string>(argc);
  for (int i = 0; i < argc; i++) arg[i] = argv[i];
  daemon(1, 0);
  Contest(getpid(), msgqueue());
  signal(SIGTERM, term);
  signal(SIGPIPE, SIG_IGN);
  Judge::fire();
  Scoreboard::fire();
  Rejudger::fire(msqid);
  WebServer::fire();
  for (pthread_t& thread : threads) pthread_join(thread, nullptr);
}

void stop() {
  Contest c;
  if (c.pid) kill(c.pid, SIGTERM);
}

void rejudge(int id, char verdict) {
  Contest c;
  if (!c.pid) Rejudger::rejudge(id, verdict);
  else {
    rejudgemsg msg(id, verdict);
    msgsnd(msgget(c.key, 0), &msg, msg.size(), 0);
  }
}

bool alive() {
  return !quit;
}

void fire(void* (*thread)(void*)) {
  threads.emplace_back();
  pthread_create(&threads.back(), nullptr, thread, nullptr);
}

void lock_att_file() {
  pthread_mutex_lock(&attfile_mutex);
}

void unlock_att_file() {
  pthread_mutex_unlock(&attfile_mutex);
}

void lock_nextid_file() {
  pthread_mutex_lock(&nextidfile_mutex);
}

void unlock_nextid_file() {
  pthread_mutex_unlock(&nextidfile_mutex);
}

void lock_question_file() {
  pthread_mutex_lock(&questionfile_mutex);
}

void unlock_question_file() {
  pthread_mutex_unlock(&questionfile_mutex);
}

} // namespace Global
<|endoftext|>


<commit_before>#include <cassert>
#include <vector>
#include <sstream>
#include <boost/foreach.hpp>
#include <fnv_solution.hpp>
#include <stp/c_interface.h>

FNVSolution::FNVSolution(const FNVParam& param, const FNVAlgo& algo, VC& vc,
                         const std::vector<Expr>& octetExprs)
{
  std::ostringstream prefixStream;
  prefixStream << "FNV" << param.getWidth() << "_" << algo.getName();
  prefix = prefixStream.str();

  BOOST_FOREACH(const Expr& octetExpr, octetExprs)
  {
    assert(getVWidth(octetExpr) == 8);

    const Expr octetValue = vc_getCounterExample(vc, octetExpr);
    assert(getType(octetValue) == BITVECTOR_TYPE);
    assert(getExprKind(octetValue) == BVCONST);

    const unsigned value = getBVUnsigned(octetValue);
    assert(value < 256);

    octets.push_back(static_cast<unsigned char>(value));
  }
}

bool FNVSolution::operator<(const FNVSolution& s) const
{
  if (prefix < s.prefix)
    return true;

  if (prefix == s.prefix)
    return octets < s.octets;

  return false;
}

bool FNVSolution::operator==(const FNVSolution& s) const
{
  return prefix == s.prefix && octets == s.octets;
}

void FNVSolution::write(std::ostream& out) const
{
  out << prefix << "(";
  for(unsigned i=0; i<octets.size(); ++i)
  {
    const char octet = octets[i];
    static const char* digits = "0123456789abcdef";
    const char first = digits[octet >> 4];
    const char second = digits[octet & ((1<<4)-1)];
    out << first << second << (i+1 < octets.size() ? " " : "");
  }

  out << ")";
}

std::ostream& operator<<(std::ostream& o, const FNVSolution& solution)
{
  solution.write(o);
  return o;
}
<commit_msg>Fix signed/unsigned char conversion issue.<commit_after>#include <cassert>
#include <vector>
#include <sstream>
#include <boost/foreach.hpp>
#include <fnv_solution.hpp>
#include <stp/c_interface.h>

FNVSolution::FNVSolution(const FNVParam& param, const FNVAlgo& algo, VC& vc,
                         const std::vector<Expr>& octetExprs)
{
  std::ostringstream prefixStream;
  prefixStream << "FNV" << param.getWidth() << "_" << algo.getName();
  prefix = prefixStream.str();

  BOOST_FOREACH(const Expr& octetExpr, octetExprs)
  {
    assert(getVWidth(octetExpr) == 8);

    const Expr octetValue = vc_getCounterExample(vc, octetExpr);
    assert(getType(octetValue) == BITVECTOR_TYPE);
    assert(getExprKind(octetValue) == BVCONST);

    const unsigned value = getBVUnsigned(octetValue);
    assert(value < 256);

    octets.push_back(static_cast<unsigned char>(value));
  }
}

bool FNVSolution::operator<(const FNVSolution& s) const
{
  if (prefix < s.prefix)
    return true;

  if (prefix == s.prefix)
    return octets < s.octets;

  return false;
}

bool FNVSolution::operator==(const FNVSolution& s) const
{
  return prefix == s.prefix && octets == s.octets;
}

void FNVSolution::write(std::ostream& out) const
{
  out << prefix << "(";
  for(unsigned i=0; i<octets.size(); ++i)
  {
    const int octet = octets[i];
    static const char* digits = "0123456789abcdef";
    const char first = digits[octet >> 4];
    const char second = digits[octet & ((1<<4)-1)];
    out << first << second << (i+1 < octets.size() ? " " : "");
  }

  out << ")";
}

std::ostream& operator<<(std::ostream& o, const FNVSolution& solution)
{
  solution.write(o);
  return o;
}
<|endoftext|>


<commit_before><commit_msg>[TCling] Also add temporary debug output to InspectMembers.<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (c) 2007-2010 Digital Bazaar, Inc. All rights reserved.
 */
#include "monarch/sql/mysql/MySqlConnection.h"

#include "monarch/sql/mysql/MySqlStatement.h"

#include <mysql/errmsg.h>

using namespace std;
using namespace monarch::sql;
using namespace monarch::sql::mysql;
using namespace monarch::net;
using namespace monarch::rt;

MySqlConnection::MySqlConnection()
{
   // no handle yet
   mHandle = NULL;
}

MySqlConnection::~MySqlConnection()
{
   // ensure connection is closed
   MySqlConnection::close();
}

inline ::MYSQL* MySqlConnection::getHandle()
{
   return mHandle;
}

bool MySqlConnection::connect(Url* url)
{
   bool rval = false;

   if(strcmp(url->getScheme().c_str(), "mysql") != 0)
   {
      ExceptionRef e = new Exception(
         "Could not connect to mysql database. "
         "Url scheme doesn't start with 'mysql'",
         "monarch.sql.BadUrlScheme");
      e->getDetails()["url"] = url->toString().c_str();
      Exception::set(e);
   }
   else
   {
      // initialize handle
      mHandle = mysql_init(NULL);

      // default character set to UTF-8
      mysql_options(mHandle, MYSQL_SET_CHARSET_NAME, "utf8");

      // setup client flag
      int clientFlag = CLIENT_FOUND_ROWS | CLIENT_COMPRESS;

      // determine default database (if any)
      const char* db = (url->getPath().length() <= 1 ?
         NULL : url->getPath().c_str() + 1);

      // FIXME: we want to add read/write/create params to the URL
      // so connections can be read-only/write/etc (use query in URL)
      if(mysql_real_connect(
         mHandle,
         url->getHost().c_str(),
         url->getUser().c_str(), url->getPassword().c_str(),
         db,
         url->getPort(), NULL, clientFlag) == NULL)
      {
         // create exception, close connection
         ExceptionRef e = createException();
         Exception::set(e);
         MySqlConnection::close();
      }
      else
      {
         // connected
         rval = true;
      }
   }

   return rval;
}

void MySqlConnection::close()
{
   AbstractConnection::close();

   if(mHandle != NULL)
   {
      mysql_close(mHandle);
      mHandle = NULL;
   }
}

bool MySqlConnection::begin()
{
   bool rval;

   if(!(rval = (mysql_query(mHandle, "START TRANSACTION") == 0)))
   {
      ExceptionRef e = new Exception("Could not begin transaction.");
      ExceptionRef cause = createException();
      e->setCause(cause);
      Exception::set(e);
   }

   return rval;
}

bool MySqlConnection::commit()
{
   bool rval;

   if(!(rval = (mysql_query(mHandle, "COMMIT") == 0)))
   {
      ExceptionRef e = new Exception("Could not commit transaction.");
      ExceptionRef cause = createException();
      e->setCause(cause);
      Exception::set(e);
   }

   return rval;
}

bool MySqlConnection::rollback()
{
   bool rval;

   if(!(rval = (mysql_query(mHandle, "ROLLBACK") == 0)))
   {
      ExceptionRef e = new Exception("Could not rollback transaction.");
      ExceptionRef cause = createException();
      e->setCause(cause);
      Exception::set(e);
   }

   return rval;
}

bool MySqlConnection::isConnected()
{
   bool rval = false;

   if(mHandle != NULL)
   {
      rval = (mysql_ping(mHandle) == 0);
   }

   return rval;
}

bool MySqlConnection::setCharacterSet(const char* cset)
{
   // FIXME: handle exceptions
   mysql_options(mHandle, MYSQL_SET_CHARSET_NAME, cset);
   return true;
}

bool MySqlConnection::query(const char* sql)
{
   bool rval;

   if(!(rval = (mysql_query(mHandle, sql) == 0)))
   {
      ExceptionRef e = new Exception("Could not execute query.");
      ExceptionRef cause = createException();
      e->setCause(cause);
      Exception::set(e);
   }

   return rval;
}

Exception* MySqlConnection::createException()
{
   Exception* e = new Exception(
      mysql_error(mHandle),
      "monarch.sql.mysql.MySql",
      mysql_errno(mHandle));
   e->getDetails()["sqlState"] = mysql_sqlstate(mHandle);
   return e;
}

Statement* MySqlConnection::createStatement(const char* sql)
{
   // create statement
   MySqlStatement* rval = new MySqlStatement(sql);
   if(!rval->initialize(this))
   {
      // delete statement if it could not be initialized
      delete rval;
      rval = NULL;
   }

   return rval;
}
<commit_msg>Added logging to mysql connection failures.<commit_after>/*
 * Copyright (c) 2007-2010 Digital Bazaar, Inc. All rights reserved.
 */
#include "monarch/sql/mysql/MySqlConnection.h"

#include "monarch/data/json/JsonWriter.h"
#include "monarch/logging/Logging.h"
#include "monarch/sql/mysql/MySqlStatement.h"

#include <mysql/errmsg.h>

using namespace std;
using namespace monarch::sql;
using namespace monarch::sql::mysql;
using namespace monarch::net;
using namespace monarch::rt;

MySqlConnection::MySqlConnection()
{
   // no handle yet
   mHandle = NULL;
}

MySqlConnection::~MySqlConnection()
{
   // ensure connection is closed
   MySqlConnection::close();
}

inline ::MYSQL* MySqlConnection::getHandle()
{
   return mHandle;
}

bool MySqlConnection::connect(Url* url)
{
   bool rval = false;

   if(strcmp(url->getScheme().c_str(), "mysql") != 0)
   {
      ExceptionRef e = new Exception(
         "Could not connect to mysql database. "
         "Url scheme doesn't start with 'mysql'",
         "monarch.sql.BadUrlScheme");
      e->getDetails()["url"] = url->toString().c_str();
      Exception::set(e);
   }
   else
   {
      // initialize handle
      mHandle = mysql_init(NULL);

      // default character set to UTF-8
      mysql_options(mHandle, MYSQL_SET_CHARSET_NAME, "utf8");

      // setup client flag
      int clientFlag = CLIENT_FOUND_ROWS | CLIENT_COMPRESS;

      // determine default database (if any)
      const char* db = (url->getPath().length() <= 1 ?
         NULL : url->getPath().c_str() + 1);

      // FIXME: we want to add read/write/create params to the URL
      // so connections can be read-only/write/etc (use query in URL)
      if(mysql_real_connect(
         mHandle,
         url->getHost().c_str(),
         url->getUser().c_str(), url->getPassword().c_str(),
         db,
         url->getPort(), NULL, clientFlag) == NULL)
      {
         // create exception, close connection
         ExceptionRef e = createException();
         Exception::set(e);
         MySqlConnection::close();
         MO_CAT_DEBUG(MO_SQL_CAT,
            "Could not connect to database host '%s:%d': %s",
            url->getHost().c_str(), url->getPort(),
            monarch::data::json::JsonWriter::writeToString(
               Exception::convertToDynamicObject(e)).c_str());
      }
      else
      {
         // connected
         rval = true;
      }
   }

   return rval;
}

void MySqlConnection::close()
{
   AbstractConnection::close();

   if(mHandle != NULL)
   {
      mysql_close(mHandle);
      mHandle = NULL;
   }
}

bool MySqlConnection::begin()
{
   bool rval;

   if(!(rval = (mysql_query(mHandle, "START TRANSACTION") == 0)))
   {
      ExceptionRef e = new Exception("Could not begin transaction.");
      ExceptionRef cause = createException();
      e->setCause(cause);
      Exception::set(e);
   }

   return rval;
}

bool MySqlConnection::commit()
{
   bool rval;

   if(!(rval = (mysql_query(mHandle, "COMMIT") == 0)))
   {
      ExceptionRef e = new Exception("Could not commit transaction.");
      ExceptionRef cause = createException();
      e->setCause(cause);
      Exception::set(e);
   }

   return rval;
}

bool MySqlConnection::rollback()
{
   bool rval;

   if(!(rval = (mysql_query(mHandle, "ROLLBACK") == 0)))
   {
      ExceptionRef e = new Exception("Could not rollback transaction.");
      ExceptionRef cause = createException();
      e->setCause(cause);
      Exception::set(e);
   }

   return rval;
}

bool MySqlConnection::isConnected()
{
   bool rval = false;

   if(mHandle != NULL)
   {
      rval = (mysql_ping(mHandle) == 0);
   }

   return rval;
}

bool MySqlConnection::setCharacterSet(const char* cset)
{
   // FIXME: handle exceptions
   mysql_options(mHandle, MYSQL_SET_CHARSET_NAME, cset);
   return true;
}

bool MySqlConnection::query(const char* sql)
{
   bool rval;

   if(!(rval = (mysql_query(mHandle, sql) == 0)))
   {
      ExceptionRef e = new Exception("Could not execute query.");
      ExceptionRef cause = createException();
      e->setCause(cause);
      Exception::set(e);
   }

   return rval;
}

Exception* MySqlConnection::createException()
{
   Exception* e = new Exception(
      mysql_error(mHandle),
      "monarch.sql.mysql.MySql",
      mysql_errno(mHandle));
   e->getDetails()["sqlState"] = mysql_sqlstate(mHandle);
   return e;
}

Statement* MySqlConnection::createStatement(const char* sql)
{
   // create statement
   MySqlStatement* rval = new MySqlStatement(sql);
   if(!rval->initialize(this))
   {
      // delete statement if it could not be initialized
      delete rval;
      rval = NULL;
   }

   return rval;
}
<|endoftext|>


<commit_before>#include <opencv2/opencv.hpp>
// #include "opencv2/highgui/highgui.hpp"
// #include "opencv2/imgproc/imgproc.hpp"
//#include "opencv2/gpu/gpu.hpp"
#include "opencv2/core/cuda.hpp"
#include "opencv2/cudaobjdetect.hpp"

using namespace cv;
using namespace std;

int findObject(vector<Rect> found, Mat img,string filename);

int main (int argc, const char * argv[]){

    Mat img;
    //init the descriptors
    cv::Ptr<cv::cuda::HOG> gpu_hog = cv::cuda::HOG::create();
    HOGDescriptor cpu_hog;

    //set the svm to default people detector
    gpu_hog->setSVMDetector(gpu_hog->getDefaultPeopleDetector());
    cpu_hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());

    while (true){

        img = imread("../walkingPeople.jpeg",CV_LOAD_IMAGE_GRAYSCALE);

        if (!img.data){
            cerr<<"Couldn't open image"<<endl;
            return -1;
        }

        // //resizing the video since it's so massive
        // resize(img, img, Size(640, 360), 0, 0, INTER_CUBIC);

        vector<Rect> found_cpu, found_filtered_cpu;
        vector<Rect> found_gpu, found_filtered_gpu;

        //comput for the gpu
        cuda::GpuMat gpu_img;
        gpu_img.upload(img);
        gpu_hog->detectMultiScale(gpu_img, found_gpu);

        //comput for the cpu
        cpu_hog.detectMultiScale(img, found_cpu, 0, Size(8,8), Size(32,32), 1.05, 2);
        findObject(found_cpu,img,"tracking_cpu.jpeg");
        findObject(found_gpu,img,"tracking_gpu.jpeg");

    }
    return 0;
}

int findObject(vector<Rect> found, Mat img,string filename){
    size_t j = 0, i = 0;
    vector<Rect> found_filtered;

    for (i=0; i<found.size(); i++){
        Rect r = found[i];
        for (j=0; j<found.size(); j++){
            if (j!=i && (r & found[j]) == r){
                break;
            }
        }
        if (j== found.size()){
            found_filtered.push_back(r);
        }
    }

        for (i=0; i<found_filtered.size(); i++){
            Rect r = found_filtered[i];
            r.x += cvRound(r.width*0.1);
            r.width = cvRound(r.width*0.8);
            r.y += cvRound(r.height*0.07);
            r.height = cvRound(r.height*0.8);
            rectangle(img, r.tl(), r.br(), Scalar(0,255,0), 3);
        }

        imwrite(filename,img);
}
<commit_msg>added timing for the functions<commit_after>#include <opencv2/opencv.hpp>
// #include "opencv2/highgui/highgui.hpp"
// #include "opencv2/imgproc/imgproc.hpp"
//#include "opencv2/gpu/gpu.hpp"
#include "opencv2/core/cuda.hpp"
#include "opencv2/cudaobjdetect.hpp"
#include "../include/timing.hpp"

using namespace cv;
using namespace std;

int findObject(vector<Rect> found, Mat img,string filename);

int main (int argc, const char * argv[]){

    Mat img, temp;
    //init the descriptors
    cv::Ptr<cv::cuda::HOG> gpu_hog = cv::cuda::HOG::create();
    HOGDescriptor cpu_hog;

    //set the svm to default people detector
    gpu_hog->setSVMDetector(gpu_hog->getDefaultPeopleDetector());
    cpu_hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());

    temp = imread("../walkingPeople.jpeg");

    cvtColor( temp,img,  CV_RGB2GRAY);

    if (!img.data){
        cerr<<"Couldn't open image"<<endl;
        return -1;
    }

    // //resizing the video since it's so massive
    // resize(img, img, Size(640, 360), 0, 0, INTER_CUBIC);

    vector<Rect> found_cpu, found_filtered_cpu;
    vector<Rect> found_gpu, found_filtered_gpu;
    Timing gpu_time;
    Timing cpu_time;

    gpu_time.start();
    //comput for the gpu
    cuda::GpuMat gpu_img;
    gpu_img.upload(img);
    gpu_hog->detectMultiScale(gpu_img, found_gpu);
    findObject(found_gpu,img,"tracking_gpu.jpeg");

    gpu_time.end();

    cpu_time.start();
    //comput for the cpu
    cpu_hog.detectMultiScale(img, found_cpu, 0, Size(8,8), Size(32,32), 1.05, 2);
    findObject(found_cpu,img,"tracking_cpu.jpeg");
    cpu_time.end();

    cout<<"cpu time: "<<cpu_time.get_elapse()<<" gpu time: "<<gpu_time.get_elapse()<<endl;
    cout<<"Percent speed up is: "<<cpu_time.get_elapse()/gpu_time.get_elapse()<<endl;

    return 0;
}

int findObject(vector<Rect> found, Mat img,string filename){
    size_t j = 0, i = 0;
    vector<Rect> found_filtered;

    for (i=0; i<found.size(); i++){
        Rect r = found[i];
        for (j=0; j<found.size(); j++){
            if (j!=i && (r & found[j]) == r){
                break;
            }
        }
        if (j== found.size()){
            found_filtered.push_back(r);
        }
    }

        for (i=0; i<found_filtered.size(); i++){
            Rect r = found_filtered[i];
            r.x += cvRound(r.width*0.1);
            r.width = cvRound(r.width*0.8);
            r.y += cvRound(r.height*0.07);
            r.height = cvRound(r.height*0.8);
            rectangle(img, r.tl(), r.br(), Scalar(0,255,0), 3);
        }

        imwrite(filename,img);
}
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <Eigen/LU>

template<typename MatrixType> void inverse(const MatrixType& m)
{
  /* this test covers the following files:
     Inverse.h
  */
  int rows = m.rows();
  int cols = m.cols();

  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;

  MatrixType m1(rows, cols),
             m2(rows, cols),
             mzero = MatrixType::Zero(rows, cols),
             identity = MatrixType::Identity(rows, rows);
  createRandomPIMatrixOfRank(rows,rows,rows,m1);
  m2 = m1.inverse();
  VERIFY_IS_APPROX(m1, m2.inverse() );

  VERIFY_IS_APPROX((Scalar(2)*m2).inverse(), m2.inverse()*Scalar(0.5));

  VERIFY_IS_APPROX(identity, m1.inverse() * m1 );
  VERIFY_IS_APPROX(identity, m1 * m1.inverse() );

  VERIFY_IS_APPROX(m1, m1.inverse().inverse() );

  // since for the general case we implement separately row-major and col-major, test that
  VERIFY_IS_APPROX(m1.transpose().inverse(), m1.inverse().transpose());

#if !defined(EIGEN_TEST_PART_5) && !defined(EIGEN_TEST_PART_6)
  //computeInverseAndDetWithCheck tests
  //First: an invertible matrix
  bool invertible;
  RealScalar det;

  m2.setZero();
  m1.computeInverseAndDetWithCheck(m2, det, invertible);
  VERIFY(invertible);
  VERIFY_IS_APPROX(identity, m1*m2);
  VERIFY_IS_APPROX(det, m1.determinant());

  m2.setZero();
  m1.computeInverseWithCheck(m2, invertible);
  VERIFY(invertible);
  VERIFY_IS_APPROX(identity, m1*m2);

  //Second: a rank one matrix (not invertible, except for 1x1 matrices)
  VectorType v3 = VectorType::Random(rows);
  MatrixType m3 = v3*v3.transpose(), m4(rows,cols);
  m3.computeInverseAndDetWithCheck(m4, det, invertible);
  VERIFY( rows==1 ? invertible : !invertible );
  VERIFY_IS_MUCH_SMALLER_THAN(m3.determinant(), RealScalar(1));
  m3.computeInverseWithCheck(m4, invertible);
  VERIFY( rows==1 ? invertible : !invertible );
#endif

  // check in-place inversion
  if(MatrixType::RowsAtCompileTime>=2 && MatrixType::RowsAtCompileTime<=4)
  {
    // in-place is forbidden
    VERIFY_RAISES_ASSERT(m1 = m1.inverse());
  }
  else
  {
    m2 = m1.inverse();
    m1 = m1.inverse();
    VERIFY_IS_APPROX(m1,m2);
  }
}

void test_inverse()
{
  int s;
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( inverse(Matrix<double,1,1>()) );
    CALL_SUBTEST_2( inverse(Matrix2d()) );
    CALL_SUBTEST_3( inverse(Matrix3f()) );
    CALL_SUBTEST_4( inverse(Matrix4f()) );
    s = ei_random<int>(50,320);
    CALL_SUBTEST_5( inverse(MatrixXf(s,s)) );
    s = ei_random<int>(25,100);
    CALL_SUBTEST_6( inverse(MatrixXcd(s,s)) );
    CALL_SUBTEST_7( inverse(Matrix4d()) );
  }
}
<commit_msg>For 1x1 matrices we really need to check the abs diff of the determinants.<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <Eigen/LU>

template<typename MatrixType> void inverse(const MatrixType& m)
{
  /* this test covers the following files:
     Inverse.h
  */
  int rows = m.rows();
  int cols = m.cols();

  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;

  MatrixType m1(rows, cols),
             m2(rows, cols),
             mzero = MatrixType::Zero(rows, cols),
             identity = MatrixType::Identity(rows, rows);
  createRandomPIMatrixOfRank(rows,rows,rows,m1);
  m2 = m1.inverse();
  VERIFY_IS_APPROX(m1, m2.inverse() );

  VERIFY_IS_APPROX((Scalar(2)*m2).inverse(), m2.inverse()*Scalar(0.5));

  VERIFY_IS_APPROX(identity, m1.inverse() * m1 );
  VERIFY_IS_APPROX(identity, m1 * m1.inverse() );

  VERIFY_IS_APPROX(m1, m1.inverse().inverse() );

  // since for the general case we implement separately row-major and col-major, test that
  VERIFY_IS_APPROX(m1.transpose().inverse(), m1.inverse().transpose());

#if !defined(EIGEN_TEST_PART_5) && !defined(EIGEN_TEST_PART_6)
  //computeInverseAndDetWithCheck tests
  //First: an invertible matrix
  bool invertible;
  RealScalar det;

  m2.setZero();
  m1.computeInverseAndDetWithCheck(m2, det, invertible);
  VERIFY(invertible);
  VERIFY_IS_APPROX(identity, m1*m2);
  VERIFY_IS_APPROX(det, m1.determinant());

  m2.setZero();
  m1.computeInverseWithCheck(m2, invertible);
  VERIFY(invertible);
  VERIFY_IS_APPROX(identity, m1*m2);

  //Second: a rank one matrix (not invertible, except for 1x1 matrices)
  VectorType v3 = VectorType::Random(rows);
  MatrixType m3 = v3*v3.transpose(), m4(rows,cols);
  m3.computeInverseAndDetWithCheck(m4, det, invertible);
  VERIFY( rows==1 ? invertible : !invertible );
  VERIFY_IS_MUCH_SMALLER_THAN(ei_abs(det-m3.determinant()), RealScalar(1));
  m3.computeInverseWithCheck(m4, invertible);
  VERIFY( rows==1 ? invertible : !invertible );
#endif

  // check in-place inversion
  if(MatrixType::RowsAtCompileTime>=2 && MatrixType::RowsAtCompileTime<=4)
  {
    // in-place is forbidden
    VERIFY_RAISES_ASSERT(m1 = m1.inverse());
  }
  else
  {
    m2 = m1.inverse();
    m1 = m1.inverse();
    VERIFY_IS_APPROX(m1,m2);
  }
}

void test_inverse()
{
  int s;
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( inverse(Matrix<double,1,1>()) );
    CALL_SUBTEST_2( inverse(Matrix2d()) );
    CALL_SUBTEST_3( inverse(Matrix3f()) );
    CALL_SUBTEST_4( inverse(Matrix4f()) );
    s = ei_random<int>(50,320);
    CALL_SUBTEST_5( inverse(MatrixXf(s,s)) );
    s = ei_random<int>(25,100);
    CALL_SUBTEST_6( inverse(MatrixXcd(s,s)) );
    CALL_SUBTEST_7( inverse(Matrix4d()) );
  }
}
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

template<typename MatrixType>
bool equalsIdentity(const MatrixType& A)
{
  typedef typename MatrixType::Scalar Scalar;
  Scalar zero = static_cast<Scalar>(0);

  bool offDiagOK = true;
  for (int i = 0; i < A.rows(); ++i) {
    for (int j = i+1; j < A.cols(); ++j) {
      offDiagOK = offDiagOK && (A(i,j) == zero);
    }
  }
  for (int i = 0; i < A.rows(); ++i) {
    for (int j = 0; j < std::min(i, A.cols()); ++j) {
      offDiagOK = offDiagOK && (A(i,j) == zero);
    }
  }

  bool diagOK = (A.diagonal().array() == 1).all();
  return offDiagOK && diagOK;
}

template<typename VectorType>
void testVectorType(const VectorType& base)
{
  typedef typename internal::traits<VectorType>::Index Index;
  typedef typename internal::traits<VectorType>::Scalar Scalar;
  Scalar low = internal::random<Scalar>(-500,500);
  Scalar high = internal::random<Scalar>(-500,500);
  if (low>high) std::swap(low,high);
  const Index size = base.size();
  const Scalar step = (high-low)/(size-1);

  // check whether the result yields what we expect it to do
  VectorType m(base);
  m.setLinSpaced(size,low,high);

  VectorType n(size);
  for (int i=0; i<size; ++i)
    n(i) = low+i*step;

  VERIFY_IS_APPROX(m,n);

  // random access version
  m = VectorType::LinSpaced(size,low,high);
  VERIFY_IS_APPROX(m,n);

  // Assignment of a RowVectorXd to a MatrixXd (regression test for bug #79).
  VERIFY( (MatrixXd(RowVectorXd::LinSpaced(3, 0, 1)) - RowVector3d(0, 0.5, 1)).norm() < std::numeric_limits<Scalar>::epsilon() );

  // These guys sometimes fail! This is not good. Any ideas how to fix them!?
//   VERIFY( m(m.size()-1) == high );
//   VERIFY( m(0) == low );

  // sequential access version
  m = VectorType::LinSpaced(Sequential,size,low,high);
  VERIFY_IS_APPROX(m,n);

  // These guys sometimes fail! This is not good. Any ideas how to fix them!?
  //VERIFY( m(m.size()-1) == high );
  //VERIFY( m(0) == low );

  // check whether everything works with row and col major vectors
  Matrix<Scalar,Dynamic,1> row_vector(size);
  Matrix<Scalar,1,Dynamic> col_vector(size);
  row_vector.setLinSpaced(size,low,high);
  col_vector.setLinSpaced(size,low,high);
  VERIFY( row_vector.isApprox(col_vector.transpose(), NumTraits<Scalar>::epsilon()));

  Matrix<Scalar,Dynamic,1> size_changer(size+50);
  size_changer.setLinSpaced(size,low,high);
  VERIFY( size_changer.size() == size );
}

template<typename MatrixType>
void testMatrixType(const MatrixType& m)
{
  typedef typename MatrixType::Index Index;
  const Index rows = m.rows();
  const Index cols = m.cols();

  MatrixType A;
  A.setIdentity(rows, cols);
  VERIFY(equalsIdentity(A));
  VERIFY(equalsIdentity(MatrixType::Identity(rows, cols)));
}

void test_nullary()
{
  CALL_SUBTEST_1( testMatrixType(Matrix2d()) );
  CALL_SUBTEST_2( testMatrixType(MatrixXcf(internal::random<int>(1,300),internal::random<int>(1,300))) );
  CALL_SUBTEST_3( testMatrixType(MatrixXf(internal::random<int>(1,300),internal::random<int>(1,300))) );

  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_4( testVectorType(VectorXd(internal::random<int>(1,300))) );
    CALL_SUBTEST_5( testVectorType(VectorXd(internal::random<int>(1,300))) );
    CALL_SUBTEST_6( testVectorType(Vector3d()) );
    CALL_SUBTEST_7( testVectorType(VectorXf(internal::random<int>(1,300))) );
    CALL_SUBTEST_8( testVectorType(VectorXf(internal::random<int>(1,300))) );
    CALL_SUBTEST_9( testVectorType(Vector3f()) );
  }
}
<commit_msg>Change int to Index in equalsIdentity(). This fixes compilation errors in nullary test on 64-bits machines.<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

template<typename MatrixType>
bool equalsIdentity(const MatrixType& A)
{
  typedef typename MatrixType::Index Index;
  typedef typename MatrixType::Scalar Scalar;
  Scalar zero = static_cast<Scalar>(0);

  bool offDiagOK = true;
  for (Index i = 0; i < A.rows(); ++i) {
    for (Index j = i+1; j < A.cols(); ++j) {
      offDiagOK = offDiagOK && (A(i,j) == zero);
    }
  }
  for (Index i = 0; i < A.rows(); ++i) {
    for (Index j = 0; j < std::min(i, A.cols()); ++j) {
      offDiagOK = offDiagOK && (A(i,j) == zero);
    }
  }

  bool diagOK = (A.diagonal().array() == 1).all();
  return offDiagOK && diagOK;
}

template<typename VectorType>
void testVectorType(const VectorType& base)
{
  typedef typename internal::traits<VectorType>::Index Index;
  typedef typename internal::traits<VectorType>::Scalar Scalar;
  Scalar low = internal::random<Scalar>(-500,500);
  Scalar high = internal::random<Scalar>(-500,500);
  if (low>high) std::swap(low,high);
  const Index size = base.size();
  const Scalar step = (high-low)/(size-1);

  // check whether the result yields what we expect it to do
  VectorType m(base);
  m.setLinSpaced(size,low,high);

  VectorType n(size);
  for (int i=0; i<size; ++i)
    n(i) = low+i*step;

  VERIFY_IS_APPROX(m,n);

  // random access version
  m = VectorType::LinSpaced(size,low,high);
  VERIFY_IS_APPROX(m,n);

  // Assignment of a RowVectorXd to a MatrixXd (regression test for bug #79).
  VERIFY( (MatrixXd(RowVectorXd::LinSpaced(3, 0, 1)) - RowVector3d(0, 0.5, 1)).norm() < std::numeric_limits<Scalar>::epsilon() );

  // These guys sometimes fail! This is not good. Any ideas how to fix them!?
//   VERIFY( m(m.size()-1) == high );
//   VERIFY( m(0) == low );

  // sequential access version
  m = VectorType::LinSpaced(Sequential,size,low,high);
  VERIFY_IS_APPROX(m,n);

  // These guys sometimes fail! This is not good. Any ideas how to fix them!?
  //VERIFY( m(m.size()-1) == high );
  //VERIFY( m(0) == low );

  // check whether everything works with row and col major vectors
  Matrix<Scalar,Dynamic,1> row_vector(size);
  Matrix<Scalar,1,Dynamic> col_vector(size);
  row_vector.setLinSpaced(size,low,high);
  col_vector.setLinSpaced(size,low,high);
  VERIFY( row_vector.isApprox(col_vector.transpose(), NumTraits<Scalar>::epsilon()));

  Matrix<Scalar,Dynamic,1> size_changer(size+50);
  size_changer.setLinSpaced(size,low,high);
  VERIFY( size_changer.size() == size );
}

template<typename MatrixType>
void testMatrixType(const MatrixType& m)
{
  typedef typename MatrixType::Index Index;
  const Index rows = m.rows();
  const Index cols = m.cols();

  MatrixType A;
  A.setIdentity(rows, cols);
  VERIFY(equalsIdentity(A));
  VERIFY(equalsIdentity(MatrixType::Identity(rows, cols)));
}

void test_nullary()
{
  CALL_SUBTEST_1( testMatrixType(Matrix2d()) );
  CALL_SUBTEST_2( testMatrixType(MatrixXcf(internal::random<int>(1,300),internal::random<int>(1,300))) );
  CALL_SUBTEST_3( testMatrixType(MatrixXf(internal::random<int>(1,300),internal::random<int>(1,300))) );

  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_4( testVectorType(VectorXd(internal::random<int>(1,300))) );
    CALL_SUBTEST_5( testVectorType(VectorXd(internal::random<int>(1,300))) );
    CALL_SUBTEST_6( testVectorType(Vector3d()) );
    CALL_SUBTEST_7( testVectorType(VectorXf(internal::random<int>(1,300))) );
    CALL_SUBTEST_8( testVectorType(VectorXf(internal::random<int>(1,300))) );
    CALL_SUBTEST_9( testVectorType(Vector3f()) );
  }
}
<|endoftext|>


<commit_before><commit_msg>Cyber: checked return value of WriteHeader method.<commit_after><|endoftext|>


<commit_before>#include "catch.hpp"

#include <initializer_list>

#include "cxxopts.hpp"

class Argv {
  public:

  Argv(std::initializer_list<const char*> args)
  : m_argv(new char*[args.size()])
  , m_argc(args.size())
  {
    int i = 0;
    auto iter = args.begin();
    while (iter != args.end()) {
      auto len = strlen(*iter) + 1;
      auto ptr = std::unique_ptr<char[]>(new char[len]);

      strcpy(ptr.get(), *iter);
      m_args.push_back(std::move(ptr));
      m_argv.get()[i] = m_args.back().get();

      ++iter;
      ++i;
    }
  }

  char** argv() const {
    return m_argv.get();
  }

  int argc() const {
    return m_argc;
  }

  private:

  std::vector<std::unique_ptr<char[]>> m_args;
  std::unique_ptr<char*[]> m_argv;
  int m_argc;
};

TEST_CASE("Basic options", "[options]")
{

  cxxopts::Options options("tester", " - test basic options");

  options.add_options()
    ("long", "a long option")
    ("s,short", "a short option")
    ("value", "an option with a value", cxxopts::value<std::string>())
    ("a,av", "a short option with a value", cxxopts::value<std::string>())
    ("6,six", "a short number option")
    ("p, space", "an option with space between short and long")
    ;

  Argv argv({
    "tester",
    "--long",
    "-s",
    "--value",
    "value",
    "-a",
    "b",
    "-6",
    "-p",
    "--space",
  });

  char** actual_argv = argv.argv();
  auto argc = argv.argc();

  auto result = options.parse(argc, actual_argv);

  CHECK(result.count("long") == 1);
  CHECK(result.count("s") == 1);
  CHECK(result.count("value") == 1);
  CHECK(result.count("a") == 1);
  CHECK(result["value"].as<std::string>() == "value");
  CHECK(result["a"].as<std::string>() == "b");
  CHECK(result.count("6") == 1);
  CHECK(result.count("p") == 2);
  CHECK(result.count("space") == 2);

  auto& arguments = result.arguments();
  REQUIRE(arguments.size() == 7);
  CHECK(arguments[0].key() == "long");
  CHECK(arguments[0].value() == "true");
  CHECK(arguments[0].as<bool>() == true);

  CHECK(arguments[1].key() == "short");
  CHECK(arguments[2].key() == "value");
  CHECK(arguments[3].key() == "av");
}

TEST_CASE("Short options", "[options]")
{
  cxxopts::Options options("test_short", " - test short options");

  options.add_options()
    ("a", "a short option", cxxopts::value<std::string>());

  Argv argv({"test_short", "-a", "value"});

  auto actual_argv = argv.argv();
  auto argc = argv.argc();

  auto result = options.parse(argc, actual_argv);

  CHECK(result.count("a") == 1);
  CHECK(result["a"].as<std::string>() == "value");

  REQUIRE_THROWS_AS(options.add_options()("", "nothing option"),
    cxxopts::invalid_option_format_error);
}

TEST_CASE("No positional", "[positional]")
{
  cxxopts::Options options("test_no_positional",
    " - test no positional options");

  Argv av({"tester", "a", "b", "def"});

  char** argv = av.argv();
  auto argc = av.argc();
  auto result = options.parse(argc, argv);

  REQUIRE(argc == 4);
  CHECK(strcmp(argv[1], "a") == 0);
}

TEST_CASE("All positional", "[positional]")
{
  std::vector<std::string> positional;

  cxxopts::Options options("test_all_positional", " - test all positional");
  options.add_options()
    ("positional", "Positional parameters",
      cxxopts::value<std::vector<std::string>>(positional))
  ;

  Argv av({"tester", "a", "b", "c"});

  auto argc = av.argc();
  auto argv = av.argv();

  options.parse_positional("positional");

  auto result = options.parse(argc, argv);

  REQUIRE(argc == 1);
  REQUIRE(positional.size() == 3);

  CHECK(positional[0] == "a");
  CHECK(positional[1] == "b");
  CHECK(positional[2] == "c");
}

TEST_CASE("Some positional explicit", "[positional]")
{
  cxxopts::Options options("positional_explicit", " - test positional");

  options.add_options()
    ("input", "Input file", cxxopts::value<std::string>())
    ("output", "Output file", cxxopts::value<std::string>())
    ("positional", "Positional parameters",
      cxxopts::value<std::vector<std::string>>())
  ;

  options.parse_positional({"input", "output", "positional"});

  Argv av({"tester", "--output", "a", "b", "c", "d"});

  char** argv = av.argv();
  auto argc = av.argc();

  auto result = options.parse(argc, argv);

  CHECK(argc == 1);
  CHECK(result.count("output"));
  CHECK(result["input"].as<std::string>() == "b");
  CHECK(result["output"].as<std::string>() == "a");

  auto& positional = result["positional"].as<std::vector<std::string>>();

  REQUIRE(positional.size() == 2);
  CHECK(positional[0] == "c");
  CHECK(positional[1] == "d");
}

TEST_CASE("No positional with extras", "[positional]")
{
  cxxopts::Options options("posargmaster", "shows incorrect handling");
  options.add_options()
      ("dummy", "oh no", cxxopts::value<std::string>())
      ;

  Argv av({"extras", "--", "a", "b", "c", "d"});

  char** argv = av.argv();
  auto argc = av.argc();

  auto old_argv = argv;
  auto old_argc = argc;

  options.parse(argc, argv);

  REQUIRE(argc == old_argc - 1);
  CHECK(argv[0] == std::string("extras"));
  CHECK(argv[1] == std::string("a"));
}

TEST_CASE("Empty with implicit value", "[implicit]")
{
  cxxopts::Options options("empty_implicit", "doesn't handle empty");
  options.add_options()
    ("implicit", "Has implicit", cxxopts::value<std::string>()
      ->implicit_value("foo"));

  Argv av({"implicit", "--implicit", ""});

  char** argv = av.argv();
  auto argc = av.argc();

  auto result = options.parse(argc, argv);

  REQUIRE(result.count("implicit") == 1);
  REQUIRE(result["implicit"].as<std::string>() == "");
}

TEST_CASE("Default values", "[default]")
{
  cxxopts::Options options("defaults", "has defaults");
  options.add_options()
    ("default", "Has implicit", cxxopts::value<int>()
      ->default_value("42"));

  SECTION("Sets defaults") {
    Argv av({"implicit"});

    char** argv = av.argv();
    auto argc = av.argc();

    auto result = options.parse(argc, argv);
    CHECK(result.count("default") == 1);
    CHECK(result["default"].as<int>() == 42);
  }

  SECTION("When values provided") {
    Argv av({"implicit", "--default", "5"});

    char** argv = av.argv();
    auto argc = av.argc();

    auto result = options.parse(argc, argv);
    CHECK(result.count("default") == 1);
    CHECK(result["default"].as<int>() == 5);
  }
}

TEST_CASE("Parse into a reference", "[reference]")
{
  int value = 0;

  cxxopts::Options options("into_reference", "parses into a reference");
  options.add_options()
    ("ref", "A reference", cxxopts::value(value));

  Argv av({"into_reference", "--ref", "42"});

  auto argv = av.argv();
  auto argc = av.argc();

  auto result = options.parse(argc, argv);
  CHECK(result.count("ref") == 1);
  CHECK(value == 42);
}

TEST_CASE("Integers", "[options]")
{
  cxxopts::Options options("parses_integers", "parses integers correctly");
  options.add_options()
    ("positional", "Integers", cxxopts::value<std::vector<int>>());

  Argv av({"ints", "--", "5", "6", "-6", "0", "0xab", "0xAf", "0x0"});

  char** argv = av.argv();
  auto argc = av.argc();

  options.parse_positional("positional");
  auto result = options.parse(argc, argv);

  REQUIRE(result.count("positional") == 7);

  auto& positional = result["positional"].as<std::vector<int>>();
  REQUIRE(positional.size() == 7);
  CHECK(positional[0] == 5);
  CHECK(positional[1] == 6);
  CHECK(positional[2] == -6);
  CHECK(positional[3] == 0);
  CHECK(positional[4] == 0xab);
  CHECK(positional[5] == 0xaf);
  CHECK(positional[6] == 0x0);
}

TEST_CASE("Unsigned integers", "[options]")
{
  cxxopts::Options options("parses_unsigned", "detects unsigned errors");
  options.add_options()
    ("positional", "Integers", cxxopts::value<std::vector<unsigned int>>());

  Argv av({"ints", "--", "-2"});

  char** argv = av.argv();
  auto argc = av.argc();

  options.parse_positional("positional");
  CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type);
}

TEST_CASE("Integer bounds", "[integer]")
{
  cxxopts::Options options("integer_boundaries", "check min/max integer");
  options.add_options()
    ("positional", "Integers", cxxopts::value<std::vector<int8_t>>());

  SECTION("No overflow")
  {
    Argv av({"ints", "--", "127", "-128", "0x7f", "-0x80", "0x7e"});

    auto argv = av.argv();
    auto argc = av.argc();

    options.parse_positional("positional");
    auto result = options.parse(argc, argv);

    REQUIRE(result.count("positional") == 5);

    auto& positional = result["positional"].as<std::vector<int8_t>>();
    CHECK(positional[0] == 127);
    CHECK(positional[1] == -128);
    CHECK(positional[2] == 0x7f);
    CHECK(positional[3] == -0x80);
    CHECK(positional[4] == 0x7e);
  }
}

TEST_CASE("Overflow on boundary", "[integer]")
{
  using namespace cxxopts::values;

  int8_t si;
  uint8_t ui;

  CHECK_THROWS_AS((integer_parser("128", si)), cxxopts::argument_incorrect_type);
  CHECK_THROWS_AS((integer_parser("-129", si)), cxxopts::argument_incorrect_type);
  CHECK_THROWS_AS((integer_parser("256", ui)), cxxopts::argument_incorrect_type);
  CHECK_THROWS_AS((integer_parser("-0x81", si)), cxxopts::argument_incorrect_type);
  CHECK_THROWS_AS((integer_parser("0x80", si)), cxxopts::argument_incorrect_type);
  CHECK_THROWS_AS((integer_parser("0x100", ui)), cxxopts::argument_incorrect_type);
}

TEST_CASE("Integer overflow", "[options]")
{
  cxxopts::Options options("reject_overflow", "rejects overflowing integers");
  options.add_options()
    ("positional", "Integers", cxxopts::value<std::vector<int8_t>>());

  Argv av({"ints", "--", "128"});

  auto argv = av.argv();
  auto argc = av.argc();

  options.parse_positional("positional");
  CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type);
}

TEST_CASE("Floats", "[options]")
{
  cxxopts::Options options("parses_floats", "parses floats correctly");
  options.add_options()
    ("double", "Double precision", cxxopts::value<double>())
    ("positional", "Floats", cxxopts::value<std::vector<float>>());

  Argv av({"floats", "--double", "0.5", "--", "4", "-4", "1.5e6", "-1.5e6"});

  char** argv = av.argv();
  auto argc = av.argc();

  options.parse_positional("positional");
  auto result = options.parse(argc, argv);

  REQUIRE(result.count("double") == 1);
  REQUIRE(result.count("positional") == 4);

  CHECK(result["double"].as<double>() == 0.5);

  auto& positional = result["positional"].as<std::vector<float>>();
  CHECK(positional[0] == 4);
  CHECK(positional[1] == -4);
  CHECK(positional[2] == 1.5e6);
  CHECK(positional[3] == -1.5e6);
}

TEST_CASE("Invalid integers", "[integer]") {
    cxxopts::Options options("invalid_integers", "rejects invalid integers");
    options.add_options()
    ("positional", "Integers", cxxopts::value<std::vector<int>>());

    Argv av({"ints", "--", "Ae"});

    char **argv = av.argv();
    auto argc = av.argc();

    options.parse_positional("positional");
    CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type);
}

TEST_CASE("Booleans", "[boolean]") {
  cxxopts::Options options("parses_floats", "parses floats correctly");
  options.add_options()
    ("bool", "A Boolean", cxxopts::value<bool>())
    ("debug", "Debugging", cxxopts::value<bool>())
    ("timing", "Timing", cxxopts::value<bool>())
    ;

  Argv av({"booleans", "--bool=false", "--debug", "true", "--timing"});

  char** argv = av.argv();
  auto argc = av.argc();

  auto result = options.parse(argc, argv);

  REQUIRE(result.count("bool") == 1);
  REQUIRE(result.count("debug") == 1);
  REQUIRE(result.count("timing") == 1);

  CHECK(result["bool"].as<bool>() == false);
  CHECK(result["debug"].as<bool>() == true);
  CHECK(result["timing"].as<bool>() == true);
}
<commit_msg>add a test for broken boolean options<commit_after>#include "catch.hpp"

#include <initializer_list>

#include "cxxopts.hpp"

class Argv {
  public:

  Argv(std::initializer_list<const char*> args)
  : m_argv(new char*[args.size()])
  , m_argc(args.size())
  {
    int i = 0;
    auto iter = args.begin();
    while (iter != args.end()) {
      auto len = strlen(*iter) + 1;
      auto ptr = std::unique_ptr<char[]>(new char[len]);

      strcpy(ptr.get(), *iter);
      m_args.push_back(std::move(ptr));
      m_argv.get()[i] = m_args.back().get();

      ++iter;
      ++i;
    }
  }

  char** argv() const {
    return m_argv.get();
  }

  int argc() const {
    return m_argc;
  }

  private:

  std::vector<std::unique_ptr<char[]>> m_args;
  std::unique_ptr<char*[]> m_argv;
  int m_argc;
};

TEST_CASE("Basic options", "[options]")
{

  cxxopts::Options options("tester", " - test basic options");

  options.add_options()
    ("long", "a long option")
    ("s,short", "a short option")
    ("value", "an option with a value", cxxopts::value<std::string>())
    ("a,av", "a short option with a value", cxxopts::value<std::string>())
    ("6,six", "a short number option")
    ("p, space", "an option with space between short and long")
    ;

  Argv argv({
    "tester",
    "--long",
    "-s",
    "--value",
    "value",
    "-a",
    "b",
    "-6",
    "-p",
    "--space",
  });

  char** actual_argv = argv.argv();
  auto argc = argv.argc();

  auto result = options.parse(argc, actual_argv);

  CHECK(result.count("long") == 1);
  CHECK(result.count("s") == 1);
  CHECK(result.count("value") == 1);
  CHECK(result.count("a") == 1);
  CHECK(result["value"].as<std::string>() == "value");
  CHECK(result["a"].as<std::string>() == "b");
  CHECK(result.count("6") == 1);
  CHECK(result.count("p") == 2);
  CHECK(result.count("space") == 2);

  auto& arguments = result.arguments();
  REQUIRE(arguments.size() == 7);
  CHECK(arguments[0].key() == "long");
  CHECK(arguments[0].value() == "true");
  CHECK(arguments[0].as<bool>() == true);

  CHECK(arguments[1].key() == "short");
  CHECK(arguments[2].key() == "value");
  CHECK(arguments[3].key() == "av");
}

TEST_CASE("Short options", "[options]")
{
  cxxopts::Options options("test_short", " - test short options");

  options.add_options()
    ("a", "a short option", cxxopts::value<std::string>());

  Argv argv({"test_short", "-a", "value"});

  auto actual_argv = argv.argv();
  auto argc = argv.argc();

  auto result = options.parse(argc, actual_argv);

  CHECK(result.count("a") == 1);
  CHECK(result["a"].as<std::string>() == "value");

  REQUIRE_THROWS_AS(options.add_options()("", "nothing option"),
    cxxopts::invalid_option_format_error);
}

TEST_CASE("No positional", "[positional]")
{
  cxxopts::Options options("test_no_positional",
    " - test no positional options");

  Argv av({"tester", "a", "b", "def"});

  char** argv = av.argv();
  auto argc = av.argc();
  auto result = options.parse(argc, argv);

  REQUIRE(argc == 4);
  CHECK(strcmp(argv[1], "a") == 0);
}

TEST_CASE("All positional", "[positional]")
{
  std::vector<std::string> positional;

  cxxopts::Options options("test_all_positional", " - test all positional");
  options.add_options()
    ("positional", "Positional parameters",
      cxxopts::value<std::vector<std::string>>(positional))
  ;

  Argv av({"tester", "a", "b", "c"});

  auto argc = av.argc();
  auto argv = av.argv();

  options.parse_positional("positional");

  auto result = options.parse(argc, argv);

  REQUIRE(argc == 1);
  REQUIRE(positional.size() == 3);

  CHECK(positional[0] == "a");
  CHECK(positional[1] == "b");
  CHECK(positional[2] == "c");
}

TEST_CASE("Some positional explicit", "[positional]")
{
  cxxopts::Options options("positional_explicit", " - test positional");

  options.add_options()
    ("input", "Input file", cxxopts::value<std::string>())
    ("output", "Output file", cxxopts::value<std::string>())
    ("positional", "Positional parameters",
      cxxopts::value<std::vector<std::string>>())
  ;

  options.parse_positional({"input", "output", "positional"});

  Argv av({"tester", "--output", "a", "b", "c", "d"});

  char** argv = av.argv();
  auto argc = av.argc();

  auto result = options.parse(argc, argv);

  CHECK(argc == 1);
  CHECK(result.count("output"));
  CHECK(result["input"].as<std::string>() == "b");
  CHECK(result["output"].as<std::string>() == "a");

  auto& positional = result["positional"].as<std::vector<std::string>>();

  REQUIRE(positional.size() == 2);
  CHECK(positional[0] == "c");
  CHECK(positional[1] == "d");
}

TEST_CASE("No positional with extras", "[positional]")
{
  cxxopts::Options options("posargmaster", "shows incorrect handling");
  options.add_options()
      ("dummy", "oh no", cxxopts::value<std::string>())
      ;

  Argv av({"extras", "--", "a", "b", "c", "d"});

  char** argv = av.argv();
  auto argc = av.argc();

  auto old_argv = argv;
  auto old_argc = argc;

  options.parse(argc, argv);

  REQUIRE(argc == old_argc - 1);
  CHECK(argv[0] == std::string("extras"));
  CHECK(argv[1] == std::string("a"));
}

TEST_CASE("Empty with implicit value", "[implicit]")
{
  cxxopts::Options options("empty_implicit", "doesn't handle empty");
  options.add_options()
    ("implicit", "Has implicit", cxxopts::value<std::string>()
      ->implicit_value("foo"));

  Argv av({"implicit", "--implicit", ""});

  char** argv = av.argv();
  auto argc = av.argc();

  auto result = options.parse(argc, argv);

  REQUIRE(result.count("implicit") == 1);
  REQUIRE(result["implicit"].as<std::string>() == "");
}

TEST_CASE("Default values", "[default]")
{
  cxxopts::Options options("defaults", "has defaults");
  options.add_options()
    ("default", "Has implicit", cxxopts::value<int>()
      ->default_value("42"));

  SECTION("Sets defaults") {
    Argv av({"implicit"});

    char** argv = av.argv();
    auto argc = av.argc();

    auto result = options.parse(argc, argv);
    CHECK(result.count("default") == 1);
    CHECK(result["default"].as<int>() == 42);
  }

  SECTION("When values provided") {
    Argv av({"implicit", "--default", "5"});

    char** argv = av.argv();
    auto argc = av.argc();

    auto result = options.parse(argc, argv);
    CHECK(result.count("default") == 1);
    CHECK(result["default"].as<int>() == 5);
  }
}

TEST_CASE("Parse into a reference", "[reference]")
{
  int value = 0;

  cxxopts::Options options("into_reference", "parses into a reference");
  options.add_options()
    ("ref", "A reference", cxxopts::value(value));

  Argv av({"into_reference", "--ref", "42"});

  auto argv = av.argv();
  auto argc = av.argc();

  auto result = options.parse(argc, argv);
  CHECK(result.count("ref") == 1);
  CHECK(value == 42);
}

TEST_CASE("Integers", "[options]")
{
  cxxopts::Options options("parses_integers", "parses integers correctly");
  options.add_options()
    ("positional", "Integers", cxxopts::value<std::vector<int>>());

  Argv av({"ints", "--", "5", "6", "-6", "0", "0xab", "0xAf", "0x0"});

  char** argv = av.argv();
  auto argc = av.argc();

  options.parse_positional("positional");
  auto result = options.parse(argc, argv);

  REQUIRE(result.count("positional") == 7);

  auto& positional = result["positional"].as<std::vector<int>>();
  REQUIRE(positional.size() == 7);
  CHECK(positional[0] == 5);
  CHECK(positional[1] == 6);
  CHECK(positional[2] == -6);
  CHECK(positional[3] == 0);
  CHECK(positional[4] == 0xab);
  CHECK(positional[5] == 0xaf);
  CHECK(positional[6] == 0x0);
}

TEST_CASE("Unsigned integers", "[options]")
{
  cxxopts::Options options("parses_unsigned", "detects unsigned errors");
  options.add_options()
    ("positional", "Integers", cxxopts::value<std::vector<unsigned int>>());

  Argv av({"ints", "--", "-2"});

  char** argv = av.argv();
  auto argc = av.argc();

  options.parse_positional("positional");
  CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type);
}

TEST_CASE("Integer bounds", "[integer]")
{
  cxxopts::Options options("integer_boundaries", "check min/max integer");
  options.add_options()
    ("positional", "Integers", cxxopts::value<std::vector<int8_t>>());

  SECTION("No overflow")
  {
    Argv av({"ints", "--", "127", "-128", "0x7f", "-0x80", "0x7e"});

    auto argv = av.argv();
    auto argc = av.argc();

    options.parse_positional("positional");
    auto result = options.parse(argc, argv);

    REQUIRE(result.count("positional") == 5);

    auto& positional = result["positional"].as<std::vector<int8_t>>();
    CHECK(positional[0] == 127);
    CHECK(positional[1] == -128);
    CHECK(positional[2] == 0x7f);
    CHECK(positional[3] == -0x80);
    CHECK(positional[4] == 0x7e);
  }
}

TEST_CASE("Overflow on boundary", "[integer]")
{
  using namespace cxxopts::values;

  int8_t si;
  uint8_t ui;

  CHECK_THROWS_AS((integer_parser("128", si)), cxxopts::argument_incorrect_type);
  CHECK_THROWS_AS((integer_parser("-129", si)), cxxopts::argument_incorrect_type);
  CHECK_THROWS_AS((integer_parser("256", ui)), cxxopts::argument_incorrect_type);
  CHECK_THROWS_AS((integer_parser("-0x81", si)), cxxopts::argument_incorrect_type);
  CHECK_THROWS_AS((integer_parser("0x80", si)), cxxopts::argument_incorrect_type);
  CHECK_THROWS_AS((integer_parser("0x100", ui)), cxxopts::argument_incorrect_type);
}

TEST_CASE("Integer overflow", "[options]")
{
  cxxopts::Options options("reject_overflow", "rejects overflowing integers");
  options.add_options()
    ("positional", "Integers", cxxopts::value<std::vector<int8_t>>());

  Argv av({"ints", "--", "128"});

  auto argv = av.argv();
  auto argc = av.argc();

  options.parse_positional("positional");
  CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type);
}

TEST_CASE("Floats", "[options]")
{
  cxxopts::Options options("parses_floats", "parses floats correctly");
  options.add_options()
    ("double", "Double precision", cxxopts::value<double>())
    ("positional", "Floats", cxxopts::value<std::vector<float>>());

  Argv av({"floats", "--double", "0.5", "--", "4", "-4", "1.5e6", "-1.5e6"});

  char** argv = av.argv();
  auto argc = av.argc();

  options.parse_positional("positional");
  auto result = options.parse(argc, argv);

  REQUIRE(result.count("double") == 1);
  REQUIRE(result.count("positional") == 4);

  CHECK(result["double"].as<double>() == 0.5);

  auto& positional = result["positional"].as<std::vector<float>>();
  CHECK(positional[0] == 4);
  CHECK(positional[1] == -4);
  CHECK(positional[2] == 1.5e6);
  CHECK(positional[3] == -1.5e6);
}

TEST_CASE("Invalid integers", "[integer]") {
    cxxopts::Options options("invalid_integers", "rejects invalid integers");
    options.add_options()
    ("positional", "Integers", cxxopts::value<std::vector<int>>());

    Argv av({"ints", "--", "Ae"});

    char **argv = av.argv();
    auto argc = av.argc();

    options.parse_positional("positional");
    CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type);
}

TEST_CASE("Booleans", "[boolean]") {
  cxxopts::Options options("parses_floats", "parses floats correctly");
  options.add_options()
    ("bool", "A Boolean", cxxopts::value<bool>())
    ("debug", "Debugging", cxxopts::value<bool>())
    ("timing", "Timing", cxxopts::value<bool>())
    ("others", "Other arguments", cxxopts::value<std::vector<std::string>>())
    ;

  options.parse_positional("others");

  Argv av({"booleans", "--bool=false", "--debug", "true", "--timing", "extra"});

  char** argv = av.argv();
  auto argc = av.argc();

  auto result = options.parse(argc, argv);

  REQUIRE(result.count("bool") == 1);
  REQUIRE(result.count("debug") == 1);
  REQUIRE(result.count("timing") == 1);

  CHECK(result["bool"].as<bool>() == false);
  CHECK(result["debug"].as<bool>() == true);
  CHECK(result["timing"].as<bool>() == true);

  REQUIRE(result.count("others") == 1);
}
<|endoftext|>


<commit_before>#include "sys_local.h"

#define RAPTURE_DEFAULT_PORT		1750
#define RAPTURE_DEFAULT_BACKLOG		32
#define RAPTURE_DEFAULT_MAXCLIENTS	8

#define RAPTURE_NETPROTOCOL			0

namespace Network {
	using namespace ClientPacket;

	enum Netmode_e {
		Netmode_Red,		// No connections allowed on the server, and any current connections are terminated
		Netmode_Yellow,		// No new connections allowed, current connections aren't terminated
		Netmode_Green,		// Anything goes
	};

	enum Netstate_e {
		Netstate_NoConnect,		// Not connected to any network, not listening
		Netstate_Listen,		// Listening
		Netstate_NeedAuth,		// Connected to a server, need authorization packet
		Netstate_Authorized,	// Connected to a server and authorized
	};

	static Cvar*				net_port = nullptr;
	static Cvar*				net_serverbacklog = nullptr;
	static Cvar*				net_maxclients = nullptr;
	static Cvar*				net_netmode = nullptr;

	static Socket*				localSocket = nullptr;
	static map<int, Socket*>	mOtherConnectedClients;
	static Socket*				remoteSocket = nullptr;
	static vector<Packet>		vPacketsAwaitingSend;	// Goes in both directions
	static Netstate_e			currentNetState = Netstate_NoConnect;
	static vector<Socket*>		vTemporaryConnections;

	static int			numConnectedClients = 1;
	static int			myClientNum = 0;				// Client 0 is always the host
	static int			lastFreeClientNum = 1;

	RaptureGame*		sys = nullptr;

	void Netmode_Callback(int newValue) {
		if (newValue == Netmode_Red) {
			mOtherConnectedClients.clear();
			numConnectedClients = 1;
		}
	}

	// Initialize the network
	void Init() {
		Zone::NewTag("network");
		net_port = Cvar::Get<int>("net_port", "Port used for networking (TCP)", (1 << CVAR_ARCHIVE), RAPTURE_DEFAULT_PORT);
		net_serverbacklog
			= Cvar::Get<int>("net_serverbacklog", "Maximum number of waiting connections for the server", (1 << CVAR_ARCHIVE), RAPTURE_DEFAULT_BACKLOG);
		net_maxclients = Cvar::Get<int>("net_maxclients", "Maximum number of clients allowed on server", (1 << CVAR_ROM) | (1 << CVAR_ARCHIVE), RAPTURE_DEFAULT_MAXCLIENTS);
		net_netmode = Cvar::Get<int>("net_netmode", "Current netmode", 0, Netmode_Red);

		net_netmode->AddCallback(Netmode_Callback);
		Sys_InitSockets();

		// Create a local socket so we can serve as the host later
		localSocket = new Socket(AF_INET6, SOCK_STREAM);
	}

	// Shut down the network, delete the local socket, disconnect any clients, etc.
	void Shutdown() {
		delete localSocket;

		Sys_ExitSockets();
	}

	// Dispatches a single packet that's been sent to us from the server
	void DispatchSingleServerPacket(Packet& packet) {
		switch (packet.packetHead.type) {
			case PACKET_CLIENTACCEPT:
				{
					// We have been accepted into the server
					ClientAcceptPacket* cPacket = (ClientAcceptPacket*)(packet.packetData);
					myClientNum = cPacket->clientNum;
					currentNetState = Netstate_Authorized;
				}
				return;
			case PACKET_CLIENTDENIED:
				{
					// We have been denied from the server
					ClientDeniedPacket* cPacket = (ClientDeniedPacket*)(packet.packetData);
					R_Message(PRIORITY_MESSAGE, "Denied entry from server: %s\n", cPacket->why);
					currentNetState = Netstate_NoConnect;
				}
				return;
			case PACKET_PING:
				{
					R_Message(PRIORITY_DEBUG, "Server PONG");
				}
				return;
		}

		if (sys && sys->trap) {
			sys->trap->interpretPacketFromServer(&packet);
		}
	}

	// Dispatches a single packet that's been sent to us from the client
	void DispatchSingleClientPacket(Packet& packet) {
		switch (packet.packetHead.type) {
			case PACKET_PING:
				R_Message(PRIORITY_DEBUG, "Server PING from %i\n", packet.packetHead.clientNum);
				SendServerPacketTo(PACKET_PING, packet.packetHead.clientNum, nullptr, 0);
				return;
		}

		if (sys && sys->trap) {
			sys->trap->interpretPacketFromClient(&packet);
		}
	}

	// Check for new incoming temporary connections
	void CheckTemporaryConnections() {
		Socket* newConnection = localSocket->CheckPendingConnections();
		if (newConnection != nullptr) {
			vTemporaryConnections.push_back(newConnection);
		}

		vector<Socket*> readReady, writeReady;	// WriteReady is not actually used in this case
		Socket::Select(vTemporaryConnections, readReady, writeReady);
		for (auto& socket : readReady) {
			Packet incPacket;
			socket->ReadPacket(incPacket);

			Packet outPacket;
			if (incPacket.packetHead.type == PACKET_CLIENTATTEMPT) {
				if (sys && sys->trap && sys->trap->acceptclient((ClientAttemptPacket*)incPacket.packetData)) {
					// Send an acceptance packet with the new client number. Also remove this socket from temporary read packets
					outPacket.packetHead.clientNum = lastFreeClientNum++;
					outPacket.packetHead.direction = Packet::PD_ServerClient;
					outPacket.packetHead.sendTime = 0; // FIXME
					outPacket.packetHead.type = PACKET_CLIENTACCEPT;
					outPacket.packetHead.packetSize = 0; // FIXME

					mOtherConnectedClients[outPacket.packetHead.clientNum] = socket;
				}
				else {
					outPacket.packetHead.clientNum = -1;
					outPacket.packetHead.direction = Packet::PD_ServerClient;
					outPacket.packetHead.sendTime = 0; // FIXME
					outPacket.packetHead.type = PACKET_CLIENTDENIED;
					outPacket.packetHead.packetSize = 0; // FIXME
				}
				socket->SendPacket(outPacket);
			}
		}
	}

	// Run all of the server stuff
	void ServerFrame() {
		// Try listening for any temporary connections
		CheckTemporaryConnections();

		// Create list of sockets
		vector<Socket*> vSockets = { localSocket };
		for (auto it = mOtherConnectedClients.begin(); it != mOtherConnectedClients.end(); ++it) {
			vSockets.push_back(it->second);
		}

		// Poll sockets
		vector<Socket*> vSocketsRead, vSocketsWrite;
		Socket::Select(vSockets, vSocketsRead, vSocketsWrite);

		// Deal with sockets that need reading
		for (auto& socket : vSocketsRead) {
			vector<Packet> vPackets;
			socket->ReadAllPackets(vPackets);
			for (auto& packet : vPackets) {
				DispatchSingleClientPacket(packet);
			}
		}

		// Deal with sockets that need writing
		for (auto& packet : vPacketsAwaitingSend) {
			int8_t clientNum = packet.packetHead.clientNum;
			if (clientNum != -1) {
				auto found = mOtherConnectedClients.find(clientNum);
				if (found == mOtherConnectedClients.end()) {
					R_Message(PRIORITY_WARNING,
						"Tried to send packet %i with bad client %i\n",
						packet.packetHead.type,
						packet.packetHead.clientNum);
					continue;
				}
				found->second->SendPacket(packet);
			}
			else {
				for (auto it = mOtherConnectedClients.begin(); it != mOtherConnectedClients.end(); ++it) {
					it->second->SendPacket(packet);
				}
				DispatchSingleServerPacket(packet);	// Don't forget to send to ourselves!
			}
		}
		vPacketsAwaitingSend.clear();

		if (sys && sys->trap) {
			sys->trap->runserverframe();
		}
	}

	// Run all of the client stuff
	void ClientFrame() {
		bool bRead, bWrite;
		Socket::SelectSingle(remoteSocket, bRead, bWrite);

		if (bRead) {
			vector<Packet> vPackets;
			localSocket->ReadAllPackets(vPackets);
			for (auto& packet : vPackets) {
				DispatchSingleServerPacket(packet);
			}
		}
		if (bWrite) {
			for (auto& packet : vPacketsAwaitingSend) {
				localSocket->SendPacket(packet);
			}
			vPacketsAwaitingSend.clear();
		}
		if (sys && sys->trap) {
			sys->trap->runclientframe();
		}
	}

	// Start running the client
	void StartRunningClient(const char* szSaveGame, RaptureGame* pGameModule) {
		sys = pGameModule;
		if (sys->trap != nullptr) {
			sys->trap->startclientfromsave(szSaveGame);
		}
	}

	// Start running the server
	void StartRunningServer(const char* szSaveGame, RaptureGame* pGameModule) {
		sys = pGameModule;
		if (sys->trap != nullptr) {
			sys->trap->startserverfromsave(szSaveGame);
		}
	}

	// Start a local server
	bool StartLocalServer(const char* szSaveGame, RaptureGame* pGameModule) {
		if (!localSocket->StartListening(net_port->Integer(), net_serverbacklog->Integer())) {
			return false;
		}
		StartRunningServer(szSaveGame, pGameModule);
		StartRunningClient(szSaveGame, pGameModule);
		return true;
	}

	// Join a remote server
	bool JoinServer(const char* szSaveGame, const char* hostname, RaptureGame* pGameModule) {
		if (!ConnectToRemote(hostname, net_port->Integer())) {
			return false;
		}
		StartRunningClient(szSaveGame, pGameModule);
		return true;
	}

	// Send a server packet to a single client
	void SendServerPacketTo(packetType_e packetType, int clientNum, void* packetData, size_t packetDataSize) {
		Packet packet = { { packetType, clientNum, Packet::PD_ServerClient, 0, packetDataSize }, packetData };
		if (clientNum == myClientNum) {
			DispatchSingleServerPacket(packet);
		}
		else {
			auto it = mOtherConnectedClients.find(clientNum);
			if (it == mOtherConnectedClients.end()) {
				R_Message(PRIORITY_WARNING, "Tried to send a packet (%i) to invalid client %i\n", packetType, clientNum);
				return;
			}
			else {
				it->second->SendPacket(packet);
			}
		}
	}

	// Send packet from server -> client
	void SendServerPacket(packetType_e packetType, int clientNum, void* packetData, size_t packetDataSize) {
		if (clientNum != -1) {
			SendServerPacketTo(packetType, clientNum, packetData, packetDataSize);
		}
		else for (auto it = mOtherConnectedClients.begin(); it != mOtherConnectedClients.end(); ++it) {
			SendServerPacketTo(packetType, it->first, packetData, packetDataSize);
		}
	}

	// Send packet from client -> server
	void SendClientPacket(packetType_e packetType, void* packetData, size_t packetDataSize) {
		// FIXME: use the correct timestamp
		Packet packet = { { packetType, myClientNum, Packet::PD_ClientServer, 0, packetDataSize }, packetData };
		if (remoteSocket == nullptr) {
			// Not connected to a remote server, send it to ourselves instead
			DispatchSingleClientPacket(packet);
		}
		else {
			remoteSocket->SendPacket(packet);
		}
	}

	// Determine if the local server is full.
	bool LocalServerFull() {
		return numConnectedClients >= net_maxclients->Integer();
	}

	void Connect(const char* hostname) {
		int port = net_port->Integer();
		R_Message(PRIORITY_MESSAGE, "Connecting to %s:%i\n", hostname, port);
		if (ConnectToRemote(hostname, port)) {
			R_Message(PRIORITY_MESSAGE, "Connection established.\n", hostname, port);
		}
		else {
			R_Message(PRIORITY_MESSAGE, "Could not connect to %s:%i\n", hostname, port);
			DisconnectFromRemote();
		}
	}

	// Try and connect to a server
	bool ConnectToRemote(const char* hostname, int port) {
		DisconnectFromRemote();
		remoteSocket = new Socket(AF_INET6, SOCK_STREAM);

		bool connected = remoteSocket->Connect(hostname, port);
		if (!connected) {
			delete remoteSocket;
			remoteSocket = nullptr;
		}
		currentNetState = Netstate_NeedAuth;
		return connected;
	}

	// Disconnect from current remote server
	void DisconnectFromRemote() {
		if (currentNetState == Netstate_NoConnect) {
			// Not connected in the first place
			return;
		}
		if (sys && sys->trap) {
			sys->trap->saveandexit();
		}
		if (remoteSocket != nullptr) {
			delete remoteSocket;
			remoteSocket = nullptr;
		}
		currentNetState = Netstate_NoConnect;
		R_Message(PRIORITY_NOTE, "--- Disconnected ---\n");
	}
}<commit_msg>Cleaned up DispatchSingleClient/ServerPacket.<commit_after>#include "sys_local.h"

#define RAPTURE_DEFAULT_PORT		1750
#define RAPTURE_DEFAULT_BACKLOG		32
#define RAPTURE_DEFAULT_MAXCLIENTS	8

#define RAPTURE_NETPROTOCOL			0

namespace Network {
	using namespace ClientPacket;

	enum Netmode_e {
		Netmode_Red,		// No connections allowed on the server, and any current connections are terminated
		Netmode_Yellow,		// No new connections allowed, current connections aren't terminated
		Netmode_Green,		// Anything goes
	};

	enum Netstate_e {
		Netstate_NoConnect,		// Not connected to any network, not listening
		Netstate_Listen,		// Listening
		Netstate_NeedAuth,		// Connected to a server, need authorization packet
		Netstate_Authorized,	// Connected to a server and authorized
	};

	static Cvar*				net_port = nullptr;
	static Cvar*				net_serverbacklog = nullptr;
	static Cvar*				net_maxclients = nullptr;
	static Cvar*				net_netmode = nullptr;
	static Cvar*				net_timeout = nullptr;

	static Socket*				localSocket = nullptr;
	static map<int, Socket*>	mOtherConnectedClients;
	static Socket*				remoteSocket = nullptr;
	static vector<Packet>		vPacketsAwaitingSend;	// Goes in both directions
	static Netstate_e			currentNetState = Netstate_NoConnect;
	static vector<Socket*>		vTemporaryConnections;

	static int			numConnectedClients = 1;
	static int			myClientNum = 0;				// Client 0 is always the host
	static int			lastFreeClientNum = 1;

	RaptureGame*		sys = nullptr;

	void Netmode_Callback(int newValue) {
		if (newValue == Netmode_Red) {
			mOtherConnectedClients.clear();
			numConnectedClients = 1;
		}
	}

	// Initialize the network
	void Init() {
		Zone::NewTag("network");
		net_port = Cvar::Get<int>("net_port", "Port used for networking (TCP)", (1 << CVAR_ARCHIVE), RAPTURE_DEFAULT_PORT);
		net_serverbacklog
			= Cvar::Get<int>("net_serverbacklog", "Maximum number of waiting connections for the server", (1 << CVAR_ARCHIVE), RAPTURE_DEFAULT_BACKLOG);
		net_maxclients = Cvar::Get<int>("net_maxclients", "Maximum number of clients allowed on server", (1 << CVAR_ROM) | (1 << CVAR_ARCHIVE), RAPTURE_DEFAULT_MAXCLIENTS);
		net_netmode = Cvar::Get<int>("net_netmode", "Current netmode", 0, Netmode_Red);
		net_timeout = Cvar::Get<int>("net_timeout", "Timeout duration, in milliseconds", 0, 30000);

		net_netmode->AddCallback(Netmode_Callback);
		Sys_InitSockets();

		// Create a local socket so we can serve as the host later
		localSocket = new Socket(AF_INET6, SOCK_STREAM);
	}

	// Shut down the network, delete the local socket, disconnect any clients, etc.
	void Shutdown() {
		delete localSocket;

		Sys_ExitSockets();
	}

	// Dispatches a single packet that's been sent to us from the server
	void DispatchSingleServerPacket(Packet& packet) {
		switch (packet.packetHead.type) {
			case PACKET_CLIENTACCEPT:
				{
					// We have been accepted into the server
					ClientAcceptPacket* cPacket = (ClientAcceptPacket*)(packet.packetData);
					R_Message(PRIORITY_MESSAGE, "Authorization successful");
					myClientNum = cPacket->clientNum;
					currentNetState = Netstate_Authorized;
				}
				break;
			case PACKET_CLIENTDENIED:
				{
					// We have been denied from the server
					ClientDeniedPacket* cPacket = (ClientDeniedPacket*)(packet.packetData);
					R_Message(PRIORITY_MESSAGE, "Denied entry from server: %s\n", cPacket->why);
					currentNetState = Netstate_NoConnect;
				}
				break;
			case PACKET_PING:
				{
					R_Message(PRIORITY_DEBUG, "Server PONG");
				}
				break;
			default:
				if (!sys || !sys->trap || !sys->trap->interpretPacketFromServer(&packet)) {
					R_Message(PRIORITY_WARNING, "Unknown packet type %i\n", packet.packetHead.type);
				}
				break;
		}
	}

	// Dispatches a single packet that's been sent to us from the client
	void DispatchSingleClientPacket(Packet& packet) {
		switch (packet.packetHead.type) {
			case PACKET_PING:
				R_Message(PRIORITY_DEBUG, "Server PING from %i\n", packet.packetHead.clientNum);
				SendServerPacketTo(PACKET_PING, packet.packetHead.clientNum, nullptr, 0);
				break;
			default:
				if (!sys || !sys->trap || !sys->trap->interpretPacketFromClient(&packet)) {
					R_Message(PRIORITY_WARNING, "Unknown packet type %i\n", packet.packetHead.type);
				}
				break;
		}
	}

	// Check for new incoming temporary connections
	void CheckTemporaryConnections() {
		Socket* newConnection = localSocket->CheckPendingConnections();
		if (newConnection != nullptr) {
			vTemporaryConnections.push_back(newConnection);
		}

		vector<Socket*> readReady, writeReady;	// WriteReady is not actually used in this case
		Socket::Select(vTemporaryConnections, readReady, writeReady);
		for (auto& socket : readReady) {
			Packet incPacket;
			socket->ReadPacket(incPacket);

			Packet outPacket;
			if (incPacket.packetHead.type == PACKET_CLIENTATTEMPT) {
				if (sys && sys->trap && sys->trap->acceptclient((ClientAttemptPacket*)incPacket.packetData)) {
					// Send an acceptance packet with the new client number. Also remove this socket from temporary read packets
					outPacket.packetHead.clientNum = lastFreeClientNum++;
					outPacket.packetHead.direction = Packet::PD_ServerClient;
					outPacket.packetHead.sendTime = 0; // FIXME
					outPacket.packetHead.type = PACKET_CLIENTACCEPT;
					outPacket.packetHead.packetSize = 0; // FIXME

					mOtherConnectedClients[outPacket.packetHead.clientNum] = socket;
				}
				else {
					outPacket.packetHead.clientNum = -1;
					outPacket.packetHead.direction = Packet::PD_ServerClient;
					outPacket.packetHead.sendTime = 0; // FIXME
					outPacket.packetHead.type = PACKET_CLIENTDENIED;
					outPacket.packetHead.packetSize = 0; // FIXME
				}
				socket->SendPacket(outPacket);
			}
		}
	}

	// Run all of the server stuff
	void ServerFrame() {
		// Try listening for any temporary connections
		CheckTemporaryConnections();

		// Create list of sockets
		vector<Socket*> vSockets = { localSocket };
		for (auto it = mOtherConnectedClients.begin(); it != mOtherConnectedClients.end(); ++it) {
			vSockets.push_back(it->second);
		}

		// Poll sockets
		vector<Socket*> vSocketsRead, vSocketsWrite;
		Socket::Select(vSockets, vSocketsRead, vSocketsWrite);

		// Deal with sockets that need reading
		for (auto& socket : vSocketsRead) {
			vector<Packet> vPackets;
			socket->ReadAllPackets(vPackets);
			for (auto& packet : vPackets) {
				DispatchSingleClientPacket(packet);
			}
		}

		// Deal with sockets that need writing
		for (auto& packet : vPacketsAwaitingSend) {
			int8_t clientNum = packet.packetHead.clientNum;
			if (clientNum != -1) {
				auto found = mOtherConnectedClients.find(clientNum);
				if (found == mOtherConnectedClients.end()) {
					R_Message(PRIORITY_WARNING,
						"Tried to send packet %i with bad client %i\n",
						packet.packetHead.type,
						packet.packetHead.clientNum);
					continue;
				}
				found->second->SendPacket(packet);
			}
			else {
				for (auto it = mOtherConnectedClients.begin(); it != mOtherConnectedClients.end(); ++it) {
					it->second->SendPacket(packet);
				}
				DispatchSingleServerPacket(packet);	// Don't forget to send to ourselves!
			}
		}
		vPacketsAwaitingSend.clear();

		if (sys && sys->trap) {
			sys->trap->runserverframe();
		}
	}

	// Run all of the client stuff
	void ClientFrame() {
		bool bRead, bWrite;
		Socket::SelectSingle(remoteSocket, bRead, bWrite);

		if (bRead) {
			vector<Packet> vPackets;
			localSocket->ReadAllPackets(vPackets);
			for (auto& packet : vPackets) {
				DispatchSingleServerPacket(packet);
			}
		}
		if (bWrite) {
			for (auto& packet : vPacketsAwaitingSend) {
				localSocket->SendPacket(packet);
			}
			vPacketsAwaitingSend.clear();
		}
		if (sys && sys->trap) {
			sys->trap->runclientframe();
		}
	}

	// Start running the client
	void StartRunningClient(const char* szSaveGame, RaptureGame* pGameModule) {
		sys = pGameModule;
		if (sys->trap != nullptr) {
			sys->trap->startclientfromsave(szSaveGame);
		}
	}

	// Start running the server
	void StartRunningServer(const char* szSaveGame, RaptureGame* pGameModule) {
		sys = pGameModule;
		if (sys->trap != nullptr) {
			sys->trap->startserverfromsave(szSaveGame);
		}
	}

	// Start a local server
	bool StartLocalServer(const char* szSaveGame, RaptureGame* pGameModule) {
		if (!localSocket->StartListening(net_port->Integer(), net_serverbacklog->Integer())) {
			return false;
		}
		StartRunningServer(szSaveGame, pGameModule);
		StartRunningClient(szSaveGame, pGameModule);
		return true;
	}

	// Join a remote server
	bool JoinServer(const char* szSaveGame, const char* hostname, RaptureGame* pGameModule) {
		if (!ConnectToRemote(hostname, net_port->Integer())) {
			return false;
		}
		StartRunningClient(szSaveGame, pGameModule);
		return true;
	}

	// Send a server packet to a single client
	void SendServerPacketTo(packetType_e packetType, int clientNum, void* packetData, size_t packetDataSize) {
		Packet packet = { { packetType, clientNum, Packet::PD_ServerClient, 0, packetDataSize }, packetData };
		if (clientNum == myClientNum) {
			DispatchSingleServerPacket(packet);
		}
		else {
			auto it = mOtherConnectedClients.find(clientNum);
			if (it == mOtherConnectedClients.end()) {
				R_Message(PRIORITY_WARNING, "Tried to send a packet (%i) to invalid client %i\n", packetType, clientNum);
				return;
			}
			else {
				it->second->SendPacket(packet);
			}
		}
	}

	// Send packet from server -> client
	void SendServerPacket(packetType_e packetType, int clientNum, void* packetData, size_t packetDataSize) {
		if (clientNum != -1) {
			SendServerPacketTo(packetType, clientNum, packetData, packetDataSize);
		}
		else for (auto it = mOtherConnectedClients.begin(); it != mOtherConnectedClients.end(); ++it) {
			SendServerPacketTo(packetType, it->first, packetData, packetDataSize);
		}
	}

	// Send packet from client -> server
	void SendClientPacket(packetType_e packetType, void* packetData, size_t packetDataSize) {
		// FIXME: use the correct timestamp
		Packet packet = { { packetType, myClientNum, Packet::PD_ClientServer, 0, packetDataSize }, packetData };
		if (remoteSocket == nullptr) {
			// Not connected to a remote server, send it to ourselves instead
			DispatchSingleClientPacket(packet);
		}
		else {
			remoteSocket->SendPacket(packet);
		}
	}

	// Determine if the local server is full.
	bool LocalServerFull() {
		return numConnectedClients >= net_maxclients->Integer();
	}

	void Connect(const char* hostname) {
		int port = net_port->Integer();
		R_Message(PRIORITY_MESSAGE, "Connecting to %s:%i\n", hostname, port);
		if (ConnectToRemote(hostname, port)) {
			R_Message(PRIORITY_MESSAGE, "Connection established.\n", hostname, port);
		}
		else {
			R_Message(PRIORITY_MESSAGE, "Could not connect to %s:%i\n", hostname, port);
			DisconnectFromRemote();
		}
	}

	// Try and connect to a server
	bool ConnectToRemote(const char* hostname, int port) {
		DisconnectFromRemote();
		remoteSocket = new Socket(AF_INET6, SOCK_STREAM);

		bool connected = remoteSocket->Connect(hostname, port);
		if (!connected) {
			delete remoteSocket;
			remoteSocket = nullptr;
		}
		currentNetState = Netstate_NeedAuth;
		return connected;
	}

	// Disconnect from current remote server
	void DisconnectFromRemote() {
		if (currentNetState == Netstate_NoConnect) {
			// Not connected in the first place
			return;
		}
		if (sys && sys->trap) {
			sys->trap->saveandexit();
		}
		if (remoteSocket != nullptr) {
			delete remoteSocket;
			remoteSocket = nullptr;
		}
		currentNetState = Netstate_NoConnect;
		R_Message(PRIORITY_NOTE, "--- Disconnected ---\n");
	}
}<|endoftext|>