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

/* interface header */
#include "PlayerInfo.h"

/* system implementation headers */
#include <errno.h>
#include <stdio.h>
#include <string>
#include <ctype.h>

/* implementation-specific common headers */
#include "TextUtils.h"

WordFilter PlayerInfo::serverSpoofingFilter;
TimeKeeper PlayerInfo::now = TimeKeeper::getCurrent();

bool	PlayerInfo::callSignFiltering = false;
WordFilter *PlayerInfo::filterData	= NULL;
bool	PlayerInfo::simpleFiltering   = true;

PlayerInfo::PlayerInfo(int _playerIndex) :
  playerIndex(_playerIndex), state(PlayerInLimbo), team(NoTeam), flag(-1),
  spamWarns(0), lastMsgTime(now), paused(false),
  pausedSince(TimeKeeper::getNullTime()), autopilot(false), tracker(0)
{
  notResponding = false;
  memset(motto, 0, MottoLen);
  memset(callSign, 0, CallSignLen);
  memset(token, 0, TokenLen);
  memset(clientVersion, 0, VersionLen);
  clientVersionMajor = -1;
  clientVersionMinor = -1;
  clientVersionRevision = -1;
  completelyAdded = false;
  nextSpawnTime = TimeKeeper::getSunGenesisTime();
  wantsToSpawn = false;
}

void PlayerInfo::setFilterParameters(bool	_callSignFiltering,
				     WordFilter &_filterData,
				     bool	_simpleFiltering)
{
  callSignFiltering = _callSignFiltering;
  filterData	= &_filterData;
  simpleFiltering   = _simpleFiltering;
}

void PlayerInfo::resetPlayer(bool ctf) {
  wasRabbit = false;

  lastupdate = now;
  lastmsg    = now;

  replayState = ReplayNone;

  playedEarly = false;

  restartOnBase = ctf;
}

void PlayerInfo::setRestartOnBase(bool on) {
  restartOnBase = on;
}

bool PlayerInfo::shouldRestartAtBase() {
  return restartOnBase;
}

void PlayerInfo::signingOn() {
  state = PlayerDead;
}

void PlayerInfo::setAlive() {
  state = PlayerAlive;
  paused = false;
  wantsToSpawn = false;
  flag = -1;
}

void PlayerInfo::setDead() {
  state = PlayerDead;
}

void *PlayerInfo::packUpdate(void *buf) {
  buf = nboPackUShort(buf, uint16_t(type));
  buf = nboPackUShort(buf, uint16_t(team));
  return buf;
}

void *PlayerInfo::packId(void *buf) {
  buf = nboPackString(buf, callSign, CallSignLen);
  buf = nboPackString(buf, motto, MottoLen);
  return buf;
}

bool PlayerInfo::unpackEnter(void *buf, uint16_t &rejectCode, char *rejectMsg)
{
  // data: type, team, name, motto
  uint16_t _type;
  int16_t _team;
  buf = nboUnpackUShort(buf, _type);
  buf = nboUnpackShort(buf, _team);
  type = PlayerType(_type);
  team = TeamColor(_team);
  buf = nboUnpackString(buf, callSign, CallSignLen);
  buf = nboUnpackString(buf, motto, MottoLen);
  buf = nboUnpackString(buf, token, TokenLen);
  buf = nboUnpackString(buf, clientVersion, VersionLen);

  return processEnter(rejectCode, rejectMsg);;
}

bool PlayerInfo::processEnter ( uint16_t &rejectCode, char *rejectMsg )
{
  // terminate the strings
  callSign[CallSignLen - 1] = '\0';
  motto[MottoLen - 1] = '\0';
  token[TokenLen - 1] = '\0';
  clientVersion[VersionLen - 1] = '\0';
  cleanMotto();

  logDebugMessage(2,"Player %s [%d] sent version string: %s\n",
    callSign, playerIndex, clientVersion);
  int major, minor, rev;
  if (sscanf(clientVersion, "%d.%d.%d", &major, &minor, &rev) == 3) {
    clientVersionMajor = major;
    clientVersionMinor = minor;
    clientVersionRevision = rev;
  }
  logDebugMessage(4,"Player %s version code parsed as:  %i.%i.%i\n", callSign,
    clientVersionMajor, clientVersionMinor, clientVersionRevision);

  // spoof filter holds "SERVER" for robust name comparisons
  if (serverSpoofingFilter.wordCount() == 0) {
    serverSpoofingFilter.addToFilter("SERVER", "");
  }

  if (!isCallSignReadable()) {
    logDebugMessage(2,"rejecting unreadable callsign: %s\n", callSign);
    rejectCode   = RejectBadCallsign;
    strcpy(rejectMsg, errorString.c_str());
    return false;
  }
  // no spoofing the server name
  if (serverSpoofingFilter.filter(callSign)) {
    rejectCode   = RejectRepeatCallsign;
    strcpy(rejectMsg, "The callsign specified is already in use.");
    return false;
  }
  if (!isMottoReadable())
    setMotto("");

  // make sure the callsign is not obscene/filtered
  if (callSignFiltering) {
    logDebugMessage(2,"checking callsign: %s\n",callSign);

    char cs[CallSignLen];
    memcpy(cs, callSign, sizeof(char) * CallSignLen);
    if (filterData->filter(cs, simpleFiltering)) {
      rejectCode = RejectBadCallsign;
      strcpy(rejectMsg,
	"The callsign was rejected. Try a different callsign.");
      return false;
    }
  }

  // make sure the motto is not obscene/filtered
  if (callSignFiltering) {
    logDebugMessage(2,"checking motto: %s\n", motto);
    char em[MottoLen];
    memcpy(em, motto, sizeof(char) * MottoLen);
    if (filterData->filter(em, simpleFiltering)) {
      rejectCode = RejectBadMotto;
      strcpy(rejectMsg, "The motto was rejected. Try a different motto.");
      return false;
    }
  }

  if (token[0] == 0) {
    strcpy(token, "NONE");
  }
  return true;
}

const char *PlayerInfo::getCallSign() const {
  return callSign;
}

void PlayerInfo::setCallSign(const char * c)
{
  if (c != NULL)
    strcpy(callSign,c);
}

bool PlayerInfo::isCallSignReadable() {
  // callsign readability filter, make sure there are more alphanum than non
  // keep a count of alpha-numerics

  int callsignlen = (int)strlen(callSign);
  // reject less than 2 characters
  if (callsignlen < 2) {
    errorString = "Callsigns must be at least 2 characters.";
    return false;
  }

  // reject trailing space
  if (isspace(callSign[strlen(callSign) - 1])) {
    errorString = "Trailing spaces are not allowed in callsigns.";
    return false;
  }

  // prevent spoofing global login indicators + and @ in the scoreboard
  // and reserve # for /kick or /ban #slot
  if (*callSign=='+' || *callSign=='@' || *callSign=='#' ) {
    errorString = "Callsigns are not allowed to start with +, @, or #.";
    return false;
  }

  // start with true to reject leading space
  bool lastWasSpace = true;
  int alnumCount = 0;
  const char *sp = callSign;
  do {
    // reject sequential spaces
    if (lastWasSpace && isspace(*sp)) {
      errorString = "Leading or consecutive spaces are not allowed in callsigns.";
      return false;
    }

    // reject ' and " and any nonprintable
    if ((*sp == '\'') || (*sp == '"') || ((unsigned)*sp > 0x7f) || !isprint(*sp)) {
      errorString = "Non-printable characters and quotes are not allowed in callsigns.";
      return false;
    }
    if (isspace(*sp)) {
      // only space is valid, not tab etc.
      if (*sp != ' ') {
	      errorString = "Invalid whitespace in callsign.";
	      return false;
      }
      lastWasSpace = true;
    } else {
      lastWasSpace = false;
      if (isalnum(*sp))
	      alnumCount++;
    }
  } while (*++sp);

  bool readable = ((float)alnumCount / (float)callsignlen) > 0.5f;
  if (!readable)
    errorString = "Callsign rejected. Please use mostly letters and numbers.";
  return readable;
}

const char *PlayerInfo::getMotto() const {
  return motto;
}

void PlayerInfo::cleanMotto() {
  // strip leading whitespace from motto
  char *sp = motto;
  char *tp = sp;
  while (isspace(*sp))
    sp++;

  // strip any non-printable characters and ' and " from motto
  do {
    if (isprint(*sp) && (*sp != '\'') && (*sp != '"')) {
      *tp++ = *sp;
    }
  } while (*++sp);
  *tp = *sp;

  // strip trailing whitespace from motto
  while (isspace(*--tp)) {
    *tp=0;
  }
}

bool PlayerInfo::isMottoReadable() {
  // motto/"team" readability filter, make sure there are more
  // alphanum than non
  int mottoAlnumCount = 0;
  char *sp = motto;
  do {
    if (isalnum(*sp)) {
      mottoAlnumCount++;
    }
  } while (*++sp);
  int mottolen = (int)strlen(motto);
  return (mottolen <= 4) || (((float)mottoAlnumCount / (float)mottolen) > 0.5);
}

void PlayerInfo::setMotto(const char* _motto) {
  strncpy(motto, _motto, MottoLen);
  motto[MottoLen - 1] = '\0';	// ensure null termination
}

const char *PlayerInfo::getToken() const {
  return token;
}

void PlayerInfo::setToken(const char * c)
{
  if (c != NULL)
    strcpy(token,c);
}

void PlayerInfo::clearToken() {
  token[0] = '\0';
}

void *PlayerInfo::packVirtualFlagCapture(void *buf) {
  buf = nboPackUShort(buf, uint16_t(int(team) - 1));
  buf = nboPackUShort(buf, uint16_t(1 + (int(team) % 4)));
  return buf;
}

bool PlayerInfo::isTeam(TeamColor _team) const {
  return team == _team;
}

bool PlayerInfo::isObserver() const {
  return team == ObserverTeam;
}

TeamColor PlayerInfo::getTeam() const {
  return team;
}

void PlayerInfo::setTeam(TeamColor _team) {
  team = _team;
}

void PlayerInfo::wasARabbit() {
  team = HunterTeam;
  wasRabbit = true;
}

void PlayerInfo::wasNotARabbit() {
  wasRabbit = false;
}

void PlayerInfo::resetFlag() {
  flag = -1;
  lastFlagDropTime = now;
}

void PlayerInfo::setFlag(int _flag) {
  flag = _flag;
}

bool PlayerInfo::isFlagTransitSafe() {
  return now - lastFlagDropTime >= 2.0f;
}

const char *PlayerInfo::getClientVersion() {
  return clientVersion;
}

void PlayerInfo::setClientVersion(const char * c)
{
  if (c != NULL)
    strcpy(clientVersion,c);
}

void PlayerInfo::getClientVersionNumbers(int& major, int& minor, int& rev)
{
  major = clientVersionMajor;
  minor = clientVersionMinor;
  rev = clientVersionRevision;
  return;
}

std::string PlayerInfo::getIdleStat() {
  std::string reply;
  if ((state > PlayerInLimbo) && (team != ObserverTeam)) {
    reply = TextUtils::format("%s\t: %4ds", callSign,
				int(now - lastupdate));
    if (paused) {
      reply += TextUtils::format("  paused %4ds", int(now - pausedSince));
    }
  }
  return reply;
}

bool PlayerInfo::canBeRabbit(bool relaxing) {
  if (paused || notResponding || (team == ObserverTeam))
    return false;
  return relaxing ? (state > PlayerInLimbo) : (state == PlayerAlive);
}

void PlayerInfo::setPaused(bool _paused) {
  paused = _paused;
  pausedSince = now;
}

void PlayerInfo::setAutoPilot(bool _autopilot) {
  autopilot = _autopilot;
}

bool PlayerInfo::isTooMuchIdling(float kickThresh) {
  bool idling = false;
  if ((state > PlayerInLimbo) && (team != ObserverTeam)) {
    const float idletime = (float)(now - lastupdate);
    if (idletime > kickThresh) {
      idling = true;
    }
  }
  return idling;
}

bool PlayerInfo::hasStartedToNotRespond() {
  const float notRespondingTime =
    BZDB.eval(StateDatabase::BZDB_NOTRESPONDINGTIME);
  bool startingToNotRespond = false;
  if (state > PlayerInLimbo) {
    bool oldnr = notResponding;
    notResponding = (now - lastupdate) > notRespondingTime;
    if (!oldnr && notResponding) {
      startingToNotRespond = true;
    }
  }
  return startingToNotRespond;
}

void PlayerInfo::hasSent() {
  lastmsg = now;
}

bool PlayerInfo::hasPlayedEarly() {
  bool returnValue = playedEarly;
  playedEarly      = false;
  return returnValue;
}

void PlayerInfo::setPlayedEarly(bool early) {
  playedEarly = early;
}

void PlayerInfo::updateIdleTime() {
  if (!paused && (state != PlayerDead)) {
    lastupdate = now;
  }
}

void	PlayerInfo::setReplayState(PlayerReplayState _state) {
  replayState = _state;
}

PlayerReplayState PlayerInfo::getReplayState()
{
  return replayState;
}

void PlayerInfo::setTrackerID(unsigned short int t)
{
  tracker = t;
}

unsigned short int PlayerInfo::trackerID()
{
  return tracker;
}

void PlayerInfo::setCurrentTime(TimeKeeper tm)
{
  now = tm;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>Log unreadable mottos. Be very careful not to overflow the buffer in the new setCallSign(), setToken(), and setClientVersion() methods.<commit_after>/* bzflag
 * Copyright (c) 1993-2011 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "PlayerInfo.h"

/* system implementation headers */
#include <errno.h>
#include <stdio.h>
#include <string>
#include <ctype.h>

/* implementation-specific common headers */
#include "TextUtils.h"

WordFilter PlayerInfo::serverSpoofingFilter;
TimeKeeper PlayerInfo::now = TimeKeeper::getCurrent();

bool	PlayerInfo::callSignFiltering = false;
WordFilter *PlayerInfo::filterData	= NULL;
bool	PlayerInfo::simpleFiltering   = true;

PlayerInfo::PlayerInfo(int _playerIndex) :
  playerIndex(_playerIndex), state(PlayerInLimbo), team(NoTeam), flag(-1),
  spamWarns(0), lastMsgTime(now), paused(false),
  pausedSince(TimeKeeper::getNullTime()), autopilot(false), tracker(0)
{
  notResponding = false;
  memset(motto, 0, MottoLen);
  memset(callSign, 0, CallSignLen);
  memset(token, 0, TokenLen);
  memset(clientVersion, 0, VersionLen);
  clientVersionMajor = -1;
  clientVersionMinor = -1;
  clientVersionRevision = -1;
  completelyAdded = false;
  nextSpawnTime = TimeKeeper::getSunGenesisTime();
  wantsToSpawn = false;
}

void PlayerInfo::setFilterParameters(bool	_callSignFiltering,
				     WordFilter &_filterData,
				     bool	_simpleFiltering)
{
  callSignFiltering = _callSignFiltering;
  filterData	= &_filterData;
  simpleFiltering   = _simpleFiltering;
}

void PlayerInfo::resetPlayer(bool ctf) {
  wasRabbit = false;

  lastupdate = now;
  lastmsg    = now;

  replayState = ReplayNone;

  playedEarly = false;

  restartOnBase = ctf;
}

void PlayerInfo::setRestartOnBase(bool on) {
  restartOnBase = on;
}

bool PlayerInfo::shouldRestartAtBase() {
  return restartOnBase;
}

void PlayerInfo::signingOn() {
  state = PlayerDead;
}

void PlayerInfo::setAlive() {
  state = PlayerAlive;
  paused = false;
  wantsToSpawn = false;
  flag = -1;
}

void PlayerInfo::setDead() {
  state = PlayerDead;
}

void *PlayerInfo::packUpdate(void *buf) {
  buf = nboPackUShort(buf, uint16_t(type));
  buf = nboPackUShort(buf, uint16_t(team));
  return buf;
}

void *PlayerInfo::packId(void *buf) {
  buf = nboPackString(buf, callSign, CallSignLen);
  buf = nboPackString(buf, motto, MottoLen);
  return buf;
}

bool PlayerInfo::unpackEnter(void *buf, uint16_t &rejectCode, char *rejectMsg)
{
  // data: type, team, name, motto
  uint16_t _type;
  int16_t _team;
  buf = nboUnpackUShort(buf, _type);
  buf = nboUnpackShort(buf, _team);
  type = PlayerType(_type);
  team = TeamColor(_team);
  buf = nboUnpackString(buf, callSign, CallSignLen);
  buf = nboUnpackString(buf, motto, MottoLen);
  buf = nboUnpackString(buf, token, TokenLen);
  buf = nboUnpackString(buf, clientVersion, VersionLen);

  return processEnter(rejectCode, rejectMsg);;
}

bool PlayerInfo::processEnter ( uint16_t &rejectCode, char *rejectMsg )
{
  // terminate the strings
  callSign[CallSignLen - 1] = '\0';
  motto[MottoLen - 1] = '\0';
  token[TokenLen - 1] = '\0';
  clientVersion[VersionLen - 1] = '\0';
  cleanMotto();

  logDebugMessage(2,"Player %s [%d] sent version string: %s\n",
    callSign, playerIndex, clientVersion);
  int major, minor, rev;
  if (sscanf(clientVersion, "%d.%d.%d", &major, &minor, &rev) == 3) {
    clientVersionMajor = major;
    clientVersionMinor = minor;
    clientVersionRevision = rev;
  }
  logDebugMessage(4,"Player %s version code parsed as:  %i.%i.%i\n", callSign,
    clientVersionMajor, clientVersionMinor, clientVersionRevision);

  // spoof filter holds "SERVER" for robust name comparisons
  if (serverSpoofingFilter.wordCount() == 0) {
    serverSpoofingFilter.addToFilter("SERVER", "");
  }

  if (!isCallSignReadable()) {
    logDebugMessage(2,"rejecting unreadable callsign: %s\n", callSign);
    rejectCode   = RejectBadCallsign;
    strcpy(rejectMsg, errorString.c_str());
    return false;
  }
  // no spoofing the server name
  if (serverSpoofingFilter.filter(callSign)) {
    rejectCode   = RejectRepeatCallsign;
    strcpy(rejectMsg, "The callsign specified is already in use.");
    return false;
  }
  if (!isMottoReadable()) {
    logDebugMessage(2,"ignoring unreadable player motto: %s (%s)\n", callSign, motto);
    // The sendMessage() function is not available in this scope.
    // TODO: reorganize the code to send this courtesy notice to the player.
    // sendMessage(ServerPlayer, playerIndex, "Ignoring your unreadable motto.");
    setMotto("");
  }

  // make sure the callsign is not obscene/filtered
  if (callSignFiltering) {
    logDebugMessage(2,"checking callsign: %s\n",callSign);

    char cs[CallSignLen];
    memcpy(cs, callSign, sizeof(char) * CallSignLen);
    if (filterData->filter(cs, simpleFiltering)) {
      rejectCode = RejectBadCallsign;
      strcpy(rejectMsg,
	"The callsign was rejected. Try a different callsign.");
      return false;
    }
  }

  // make sure the motto is not obscene/filtered
  if (callSignFiltering) {
    logDebugMessage(2,"checking motto: %s\n", motto);
    char em[MottoLen];
    memcpy(em, motto, sizeof(char) * MottoLen);
    if (filterData->filter(em, simpleFiltering)) {
      rejectCode = RejectBadMotto;
      strcpy(rejectMsg, "The motto was rejected. Try a different motto.");
      return false;
    }
  }

  if (token[0] == 0) {
    strcpy(token, "NONE");
  }
  return true;
}

const char *PlayerInfo::getCallSign() const {
  return callSign;
}

void PlayerInfo::setCallSign(const char * c)
{
  if (c != NULL) {
    strncpy(callSign, c, CallSignLen);
    callSign[CallSignLen - 1] = '\0';	// ensure null termination
  }
}

bool PlayerInfo::isCallSignReadable() {
  // callsign readability filter, make sure there are more alphanum than non
  // keep a count of alpha-numerics

  int callsignlen = (int)strlen(callSign);
  // reject less than 2 characters
  if (callsignlen < 2) {
    errorString = "Callsigns must be at least 2 characters.";
    return false;
  }

  // reject trailing space
  if (isspace(callSign[strlen(callSign) - 1])) {
    errorString = "Trailing spaces are not allowed in callsigns.";
    return false;
  }

  // prevent spoofing global login indicators + and @ in the scoreboard
  // and reserve # for /kick or /ban #slot
  if (*callSign=='+' || *callSign=='@' || *callSign=='#' ) {
    errorString = "Callsigns are not allowed to start with +, @, or #.";
    return false;
  }

  // start with true to reject leading space
  bool lastWasSpace = true;
  int alnumCount = 0;
  const char *sp = callSign;
  do {
    // reject sequential spaces
    if (lastWasSpace && isspace(*sp)) {
      errorString = "Leading or consecutive spaces are not allowed in callsigns.";
      return false;
    }

    // reject ' and " and any nonprintable
    if ((*sp == '\'') || (*sp == '"') || ((unsigned)*sp > 0x7f) || !isprint(*sp)) {
      errorString = "Non-printable characters and quotes are not allowed in callsigns.";
      return false;
    }
    if (isspace(*sp)) {
      // only space is valid, not tab etc.
      if (*sp != ' ') {
	      errorString = "Invalid whitespace in callsign.";
	      return false;
      }
      lastWasSpace = true;
    } else {
      lastWasSpace = false;
      if (isalnum(*sp))
	      alnumCount++;
    }
  } while (*++sp);

  bool readable = ((float)alnumCount / (float)callsignlen) > 0.5f;
  if (!readable)
    errorString = "Callsign rejected. Please use mostly letters and numbers.";
  return readable;
}

const char *PlayerInfo::getMotto() const {
  return motto;
}

void PlayerInfo::cleanMotto() {
  // strip leading whitespace from motto
  char *sp = motto;
  char *tp = sp;
  while (isspace(*sp))
    sp++;

  // strip any non-printable characters and ' and " from motto
  do {
    if (isprint(*sp) && (*sp != '\'') && (*sp != '"')) {
      *tp++ = *sp;
    }
  } while (*++sp);
  *tp = *sp;

  // strip trailing whitespace from motto
  while (isspace(*--tp)) {
    *tp=0;
  }
}

bool PlayerInfo::isMottoReadable() {
  // motto/"team" readability filter, make sure there are more
  // alphanum than non
  int mottoAlnumCount = 0;
  char *sp = motto;
  do {
    if (isalnum(*sp)) {
      mottoAlnumCount++;
    }
  } while (*++sp);
  int mottolen = (int)strlen(motto);
  return (mottolen <= 4) || (((float)mottoAlnumCount / (float)mottolen) > 0.5);
}

void PlayerInfo::setMotto(const char* _motto) {
  strncpy(motto, _motto, MottoLen);
  motto[MottoLen - 1] = '\0';	// ensure null termination
}

const char *PlayerInfo::getToken() const {
  return token;
}

void PlayerInfo::setToken(const char * c)
{
  if (c != NULL) {
    strncpy(token, c, TokenLen);
    token[TokenLen - 1] = '\0';	// ensure null termination
  }
}

void PlayerInfo::clearToken() {
  token[0] = '\0';
}

void *PlayerInfo::packVirtualFlagCapture(void *buf) {
  buf = nboPackUShort(buf, uint16_t(int(team) - 1));
  buf = nboPackUShort(buf, uint16_t(1 + (int(team) % 4)));
  return buf;
}

bool PlayerInfo::isTeam(TeamColor _team) const {
  return team == _team;
}

bool PlayerInfo::isObserver() const {
  return team == ObserverTeam;
}

TeamColor PlayerInfo::getTeam() const {
  return team;
}

void PlayerInfo::setTeam(TeamColor _team) {
  team = _team;
}

void PlayerInfo::wasARabbit() {
  team = HunterTeam;
  wasRabbit = true;
}

void PlayerInfo::wasNotARabbit() {
  wasRabbit = false;
}

void PlayerInfo::resetFlag() {
  flag = -1;
  lastFlagDropTime = now;
}

void PlayerInfo::setFlag(int _flag) {
  flag = _flag;
}

bool PlayerInfo::isFlagTransitSafe() {
  return now - lastFlagDropTime >= 2.0f;
}

const char *PlayerInfo::getClientVersion() {
  return clientVersion;
}

void PlayerInfo::setClientVersion(const char * c)
{
  if (c != NULL) {
    strncpy(clientVersion, c, VersionLen);
    clientVersion[VersionLen - 1] = '\0';	// ensure null termination
  }
}

void PlayerInfo::getClientVersionNumbers(int& major, int& minor, int& rev)
{
  major = clientVersionMajor;
  minor = clientVersionMinor;
  rev = clientVersionRevision;
  return;
}

std::string PlayerInfo::getIdleStat() {
  std::string reply;
  if ((state > PlayerInLimbo) && (team != ObserverTeam)) {
    reply = TextUtils::format("%s\t: %4ds", callSign,
				int(now - lastupdate));
    if (paused) {
      reply += TextUtils::format("  paused %4ds", int(now - pausedSince));
    }
  }
  return reply;
}

bool PlayerInfo::canBeRabbit(bool relaxing) {
  if (paused || notResponding || (team == ObserverTeam))
    return false;
  return relaxing ? (state > PlayerInLimbo) : (state == PlayerAlive);
}

void PlayerInfo::setPaused(bool _paused) {
  paused = _paused;
  pausedSince = now;
}

void PlayerInfo::setAutoPilot(bool _autopilot) {
  autopilot = _autopilot;
}

bool PlayerInfo::isTooMuchIdling(float kickThresh) {
  bool idling = false;
  if ((state > PlayerInLimbo) && (team != ObserverTeam)) {
    const float idletime = (float)(now - lastupdate);
    if (idletime > kickThresh) {
      idling = true;
    }
  }
  return idling;
}

bool PlayerInfo::hasStartedToNotRespond() {
  const float notRespondingTime =
    BZDB.eval(StateDatabase::BZDB_NOTRESPONDINGTIME);
  bool startingToNotRespond = false;
  if (state > PlayerInLimbo) {
    bool oldnr = notResponding;
    notResponding = (now - lastupdate) > notRespondingTime;
    if (!oldnr && notResponding) {
      startingToNotRespond = true;
    }
  }
  return startingToNotRespond;
}

void PlayerInfo::hasSent() {
  lastmsg = now;
}

bool PlayerInfo::hasPlayedEarly() {
  bool returnValue = playedEarly;
  playedEarly      = false;
  return returnValue;
}

void PlayerInfo::setPlayedEarly(bool early) {
  playedEarly = early;
}

void PlayerInfo::updateIdleTime() {
  if (!paused && (state != PlayerDead)) {
    lastupdate = now;
  }
}

void	PlayerInfo::setReplayState(PlayerReplayState _state) {
  replayState = _state;
}

PlayerReplayState PlayerInfo::getReplayState()
{
  return replayState;
}

void PlayerInfo::setTrackerID(unsigned short int t)
{
  tracker = t;
}

unsigned short int PlayerInfo::trackerID()
{
  return tracker;
}

void PlayerInfo::setCurrentTime(TimeKeeper tm)
{
  now = tm;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/http_connection.hpp"
#include "libtorrent/escape_string.hpp"

#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <asio/ip/tcp.hpp>
#include <string>

using boost::bind;

namespace libtorrent
{

	enum { max_bottled_buffer = 1024 * 1024 };

void http_connection::get(std::string const& url, time_duration timeout
	, bool handle_redirect)
{
	m_redirect = handle_redirect;
	std::string protocol;
	std::string auth;
	std::string hostname;
	std::string path;
	int port;
	boost::tie(protocol, auth, hostname, port, path) = parse_url_components(url);
	std::stringstream headers;
	headers << "GET " << path << " HTTP/1.0\r\n"
		"Host:" << hostname <<
		"\r\nConnection: close\r\n";
	if (!auth.empty())
		headers << "Authorization: Basic " << base64encode(auth) << "\r\n";
	headers << "\r\n";
	sendbuffer = headers.str();
	start(hostname, boost::lexical_cast<std::string>(port), timeout);
}

void http_connection::start(std::string const& hostname, std::string const& port
	, time_duration timeout, bool handle_redirect)
{
	m_redirect = handle_redirect;
	m_timeout = timeout;
	m_timer.expires_from_now(m_timeout);
	m_timer.async_wait(bind(&http_connection::on_timeout
		, boost::weak_ptr<http_connection>(shared_from_this()), _1));
	m_called = false;
	if (m_sock.is_open() && m_hostname == hostname && m_port == port)
	{
		m_parser.reset();
		asio::async_write(m_sock, asio::buffer(sendbuffer)
			, bind(&http_connection::on_write, shared_from_this(), _1));
	}
	else
	{
		m_sock.close();
		tcp::resolver::query query(hostname, port);
		m_resolver.async_resolve(query, bind(&http_connection::on_resolve
			, shared_from_this(), _1, _2));
		m_hostname = hostname;
		m_port = port;
	}
}

void http_connection::on_connect_timeout()
{
	if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
	m_connection_ticket = -1;

	callback(asio::error::timed_out);
	close();
}

void http_connection::on_timeout(boost::weak_ptr<http_connection> p
	, asio::error_code const& e)
{
	boost::shared_ptr<http_connection> c = p.lock();
	if (!c) return;
	if (c->m_connection_ticket > -1) c->m_cc.done(c->m_connection_ticket);
	c->m_connection_ticket = -1;

	if (e == asio::error::operation_aborted) return;

	if (c->m_last_receive + c->m_timeout < time_now())
	{
		c->callback(asio::error::timed_out);
		c->close();
		return;
	}

	if (!c->m_sock.is_open()) return;

	c->m_timer.expires_at(c->m_last_receive + c->m_timeout);
	c->m_timer.async_wait(bind(&http_connection::on_timeout, p, _1));
}

void http_connection::close()
{
	m_timer.cancel();
	m_limiter_timer.cancel();
	m_sock.close();
	m_hostname.clear();
	m_port.clear();

	if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
	m_connection_ticket = -1;

	m_handler.clear();
}

void http_connection::on_resolve(asio::error_code const& e
		, tcp::resolver::iterator i)
{
	if (e)
	{
		callback(e);
		close();
		return;
	}
	TORRENT_ASSERT(i != tcp::resolver::iterator());
	m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, *i)
		, bind(&http_connection::on_connect_timeout, shared_from_this())
		, m_timeout);
}

void http_connection::connect(int ticket, tcp::endpoint target_address)
{
	m_connection_ticket = ticket;
	m_sock.async_connect(target_address, boost::bind(&http_connection::on_connect
		, shared_from_this(), _1/*, ++i*/));
}

void http_connection::on_connect(asio::error_code const& e
	/*, tcp::resolver::iterator i*/)
{
	if (!e)
	{
		m_last_receive = time_now();
		if (m_connect_handler) m_connect_handler(*this);
		asio::async_write(m_sock, asio::buffer(sendbuffer)
			, bind(&http_connection::on_write, shared_from_this(), _1));
	}
/*	else if (i != tcp::resolver::iterator())
	{
		// The connection failed. Try the next endpoint in the list.
		m_sock.close();
		m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, *i)
			, bind(&http_connection::on_connect_timeout, shared_from_this())
			, m_timeout);
	}
*/	else
	{
		callback(e);
		close();
	}
}

void http_connection::callback(asio::error_code const& e, char const* data, int size)
{
	if (!m_bottled || !m_called)
	{
		m_called = true;
		if (m_handler) m_handler(e, m_parser, data, size);
	}
}

void http_connection::on_write(asio::error_code const& e)
{
	if (e)
	{
		callback(e);
		close();
		return;
	}

	std::string().swap(sendbuffer);
	m_recvbuffer.resize(4096);

	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (m_rate_limit > 0 && amount_to_read > m_download_quota)
	{
		amount_to_read = m_download_quota;
		if (m_download_quota == 0)
		{
			if (!m_limiter_timer_active)
				on_assign_bandwidth(asio::error_code());
			return;
		}
	}
	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));
}

void http_connection::on_read(asio::error_code const& e
	, std::size_t bytes_transferred)
{
	if (m_rate_limit)
	{
		m_download_quota -= bytes_transferred;
		TORRENT_ASSERT(m_download_quota >= 0);
	}

	if (e == asio::error::eof)
	{
		char const* data = 0;
		std::size_t size = 0;
		if (m_bottled && m_parser.header_finished())
		{
			data = m_parser.get_body().begin;
			size = m_parser.get_body().left();
		}
		callback(e, data, size);
		close();
		return;
	}

	if (e)
	{
		callback(e);
		close();
		return;
	}

	m_read_pos += bytes_transferred;
	TORRENT_ASSERT(m_read_pos <= int(m_recvbuffer.size()));

	// having a nonempty path means we should handle redirects
	if (m_redirect && m_parser.header_finished())
	{
		int code = m_parser.status_code();
		if (code >= 300 && code < 400)
		{
			// attempt a redirect
			std::string const& url = m_parser.header("location");
			if (url.empty())
			{
				// missing location header
				callback(e);
				return;
			}

			m_limiter_timer_active = false;
			close();

			get(url, m_timeout);
			return;
		}

		m_redirect = false;
	}

	if (m_bottled || !m_parser.header_finished())
	{
		libtorrent::buffer::const_interval rcv_buf(&m_recvbuffer[0]
			, &m_recvbuffer[0] + m_read_pos);
		bool error = false;
		m_parser.incoming(rcv_buf, error);
		if (error)
		{
			// HTTP parse error
			asio::error_code ec = asio::error::fault;
			callback(ec, 0, 0);
			return;
		}
		if (!m_bottled && m_parser.header_finished())
		{
			if (m_read_pos > m_parser.body_start())
				callback(e, &m_recvbuffer[0] + m_parser.body_start()
					, m_read_pos - m_parser.body_start());
			m_read_pos = 0;
			m_last_receive = time_now();
		}
		else if (m_bottled && m_parser.finished())
		{
			m_timer.cancel();
			callback(e, m_parser.get_body().begin, m_parser.get_body().left());
		}
	}
	else
	{
		TORRENT_ASSERT(!m_bottled);
		callback(e, &m_recvbuffer[0], m_read_pos);
		m_read_pos = 0;
		m_last_receive = time_now();
	}

	if (int(m_recvbuffer.size()) == m_read_pos)
		m_recvbuffer.resize((std::min)(m_read_pos + 2048, int(max_bottled_buffer)));
	if (m_read_pos == max_bottled_buffer)
	{
		callback(asio::error::eof);
		close();
		return;
	}
	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (m_rate_limit > 0 && amount_to_read > m_download_quota)
	{
		amount_to_read = m_download_quota;
		if (m_download_quota == 0)
		{
			if (!m_limiter_timer_active)
				on_assign_bandwidth(asio::error_code());
			return;
		}
	}
	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));
}

void http_connection::on_assign_bandwidth(asio::error_code const& e)
{
	if ((e == asio::error::operation_aborted
		&& m_limiter_timer_active)
		|| !m_sock.is_open())
	{
		callback(asio::error::eof);
		return;
	}
	m_limiter_timer_active = false;
	if (e) return;

	if (m_download_quota > 0) return;

	m_download_quota = m_rate_limit / 4;

	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (amount_to_read > m_download_quota)
		amount_to_read = m_download_quota;

	if (!m_sock.is_open()) return;

	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));

	m_limiter_timer_active = true;
	m_limiter_timer.expires_from_now(milliseconds(250));
	m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth
		, shared_from_this(), _1));
}

void http_connection::rate_limit(int limit)
{
	if (!m_sock.is_open()) return;

	if (!m_limiter_timer_active)
	{
		m_limiter_timer_active = true;
		m_limiter_timer.expires_from_now(milliseconds(250));
		m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth
			, shared_from_this(), _1));
	}
	m_rate_limit = limit;
}

}

<commit_msg>made http_connection build without exception support<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/http_connection.hpp"
#include "libtorrent/escape_string.hpp"

#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <asio/ip/tcp.hpp>
#include <string>

using boost::bind;

namespace libtorrent
{

	enum { max_bottled_buffer = 1024 * 1024 };

void http_connection::get(std::string const& url, time_duration timeout
	, bool handle_redirect)
{
	m_redirect = handle_redirect;
	std::string protocol;
	std::string auth;
	std::string hostname;
	std::string path;
	int port;
	boost::tie(protocol, auth, hostname, port, path) = parse_url_components(url);
	std::stringstream headers;
	headers << "GET " << path << " HTTP/1.0\r\n"
		"Host:" << hostname <<
		"\r\nConnection: close\r\n";
	if (!auth.empty())
		headers << "Authorization: Basic " << base64encode(auth) << "\r\n";
	headers << "\r\n";
	sendbuffer = headers.str();
	start(hostname, boost::lexical_cast<std::string>(port), timeout);
}

void http_connection::start(std::string const& hostname, std::string const& port
	, time_duration timeout, bool handle_redirect)
{
	m_redirect = handle_redirect;
	m_timeout = timeout;
	asio::error_code ec;
	m_timer.expires_from_now(m_timeout, ec);
	m_timer.async_wait(bind(&http_connection::on_timeout
		, boost::weak_ptr<http_connection>(shared_from_this()), _1));
	m_called = false;
	if (m_sock.is_open() && m_hostname == hostname && m_port == port)
	{
		m_parser.reset();
		asio::async_write(m_sock, asio::buffer(sendbuffer)
			, bind(&http_connection::on_write, shared_from_this(), _1));
	}
	else
	{
		asio::error_code ec;
		m_sock.close(ec);
		tcp::resolver::query query(hostname, port);
		m_resolver.async_resolve(query, bind(&http_connection::on_resolve
			, shared_from_this(), _1, _2));
		m_hostname = hostname;
		m_port = port;
	}
}

void http_connection::on_connect_timeout()
{
	if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
	m_connection_ticket = -1;

	callback(asio::error::timed_out);
	close();
}

void http_connection::on_timeout(boost::weak_ptr<http_connection> p
	, asio::error_code const& e)
{
	boost::shared_ptr<http_connection> c = p.lock();
	if (!c) return;
	if (c->m_connection_ticket > -1) c->m_cc.done(c->m_connection_ticket);
	c->m_connection_ticket = -1;

	if (e == asio::error::operation_aborted) return;

	if (c->m_last_receive + c->m_timeout < time_now())
	{
		c->callback(asio::error::timed_out);
		c->close();
		return;
	}

	if (!c->m_sock.is_open()) return;
	asio::error_code ec;
	c->m_timer.expires_at(c->m_last_receive + c->m_timeout, ec);
	c->m_timer.async_wait(bind(&http_connection::on_timeout, p, _1));
}

void http_connection::close()
{
	asio::error_code ec;
	m_timer.cancel(ec);
	m_limiter_timer.cancel(ec);
	m_sock.close(ec);
	m_hostname.clear();
	m_port.clear();

	if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
	m_connection_ticket = -1;

	m_handler.clear();
}

void http_connection::on_resolve(asio::error_code const& e
		, tcp::resolver::iterator i)
{
	if (e)
	{
		callback(e);
		close();
		return;
	}
	TORRENT_ASSERT(i != tcp::resolver::iterator());
	m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, *i)
		, bind(&http_connection::on_connect_timeout, shared_from_this())
		, m_timeout);
}

void http_connection::connect(int ticket, tcp::endpoint target_address)
{
	m_connection_ticket = ticket;
	m_sock.async_connect(target_address, boost::bind(&http_connection::on_connect
		, shared_from_this(), _1/*, ++i*/));
}

void http_connection::on_connect(asio::error_code const& e
	/*, tcp::resolver::iterator i*/)
{
	if (!e)
	{
		m_last_receive = time_now();
		if (m_connect_handler) m_connect_handler(*this);
		asio::async_write(m_sock, asio::buffer(sendbuffer)
			, bind(&http_connection::on_write, shared_from_this(), _1));
	}
/*	else if (i != tcp::resolver::iterator())
	{
		// The connection failed. Try the next endpoint in the list.
		m_sock.close();
		m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, *i)
			, bind(&http_connection::on_connect_timeout, shared_from_this())
			, m_timeout);
	}
*/	else
	{
		callback(e);
		close();
	}
}

void http_connection::callback(asio::error_code const& e, char const* data, int size)
{
	if (!m_bottled || !m_called)
	{
		m_called = true;
		m_timer.cancel();
		if (m_handler) m_handler(e, m_parser, data, size);
	}
}

void http_connection::on_write(asio::error_code const& e)
{
	if (e)
	{
		callback(e);
		close();
		return;
	}

	std::string().swap(sendbuffer);
	m_recvbuffer.resize(4096);

	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (m_rate_limit > 0 && amount_to_read > m_download_quota)
	{
		amount_to_read = m_download_quota;
		if (m_download_quota == 0)
		{
			if (!m_limiter_timer_active)
				on_assign_bandwidth(asio::error_code());
			return;
		}
	}
	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));
}

void http_connection::on_read(asio::error_code const& e
	, std::size_t bytes_transferred)
{
	if (m_rate_limit)
	{
		m_download_quota -= bytes_transferred;
		TORRENT_ASSERT(m_download_quota >= 0);
	}

	if (e == asio::error::eof)
	{
		char const* data = 0;
		std::size_t size = 0;
		if (m_bottled && m_parser.header_finished())
		{
			data = m_parser.get_body().begin;
			size = m_parser.get_body().left();
		}
		callback(e, data, size);
		close();
		return;
	}

	if (e)
	{
		callback(e);
		close();
		return;
	}

	m_read_pos += bytes_transferred;
	TORRENT_ASSERT(m_read_pos <= int(m_recvbuffer.size()));

	// having a nonempty path means we should handle redirects
	if (m_redirect && m_parser.header_finished())
	{
		int code = m_parser.status_code();
		if (code >= 300 && code < 400)
		{
			// attempt a redirect
			std::string const& url = m_parser.header("location");
			if (url.empty())
			{
				// missing location header
				callback(e);
				return;
			}

			m_limiter_timer_active = false;
			close();

			get(url, m_timeout);
			return;
		}

		m_redirect = false;
	}

	if (m_bottled || !m_parser.header_finished())
	{
		libtorrent::buffer::const_interval rcv_buf(&m_recvbuffer[0]
			, &m_recvbuffer[0] + m_read_pos);
		bool error = false;
		m_parser.incoming(rcv_buf, error);
		if (error)
		{
			// HTTP parse error
			asio::error_code ec = asio::error::fault;
			callback(ec, 0, 0);
			return;
		}
		if (!m_bottled && m_parser.header_finished())
		{
			if (m_read_pos > m_parser.body_start())
				callback(e, &m_recvbuffer[0] + m_parser.body_start()
					, m_read_pos - m_parser.body_start());
			m_read_pos = 0;
			m_last_receive = time_now();
		}
		else if (m_bottled && m_parser.finished())
		{
			asio::error_code ec;
			m_timer.cancel(ec);
			callback(e, m_parser.get_body().begin, m_parser.get_body().left());
		}
	}
	else
	{
		TORRENT_ASSERT(!m_bottled);
		callback(e, &m_recvbuffer[0], m_read_pos);
		m_read_pos = 0;
		m_last_receive = time_now();
	}

	if (int(m_recvbuffer.size()) == m_read_pos)
		m_recvbuffer.resize((std::min)(m_read_pos + 2048, int(max_bottled_buffer)));
	if (m_read_pos == max_bottled_buffer)
	{
		callback(asio::error::eof);
		close();
		return;
	}
	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (m_rate_limit > 0 && amount_to_read > m_download_quota)
	{
		amount_to_read = m_download_quota;
		if (m_download_quota == 0)
		{
			if (!m_limiter_timer_active)
				on_assign_bandwidth(asio::error_code());
			return;
		}
	}
	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));
}

void http_connection::on_assign_bandwidth(asio::error_code const& e)
{
	if ((e == asio::error::operation_aborted
		&& m_limiter_timer_active)
		|| !m_sock.is_open())
	{
		callback(asio::error::eof);
		return;
	}
	m_limiter_timer_active = false;
	if (e) return;

	if (m_download_quota > 0) return;

	m_download_quota = m_rate_limit / 4;

	int amount_to_read = m_recvbuffer.size() - m_read_pos;
	if (amount_to_read > m_download_quota)
		amount_to_read = m_download_quota;

	if (!m_sock.is_open()) return;

	m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos
		, amount_to_read)
		, bind(&http_connection::on_read
		, shared_from_this(), _1, _2));

	asio::error_code ec;
	m_limiter_timer_active = true;
	m_limiter_timer.expires_from_now(milliseconds(250), ec);
	m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth
		, shared_from_this(), _1));
}

void http_connection::rate_limit(int limit)
{
	if (!m_sock.is_open()) return;

	if (!m_limiter_timer_active)
	{
		asio::error_code ec;
		m_limiter_timer_active = true;
		m_limiter_timer.expires_from_now(milliseconds(250), ec);
		m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth
			, shared_from_this(), _1));
	}
	m_rate_limit = limit;
}

}

<|endoftext|>


<commit_before> //
 // This file is part of Easylogging++ samples
 // Simple custom log builder
 //
 // Revision 1.0
 // @author mkhan3189
 //

#include "easylogging++.h"

_INITIALIZE_EASYLOGGINGPP

/// @brief Not a very fast log builder but good enough for sample
class MyLogBuilder : public el::api::LogBuilder {
public:
    std::string build(const el::LogMessage* logMessage, bool appendNewLine) const {
        std::stringstream str;
        str << logMessage->message();
        if (appendNewLine) str << "\n";
        return str.str().c_str();
    }
};

int main(void) {
    el::Loggers::getLogger("default")->setLogBuilder(el::api::LogBuilderPtr(new MyLogBuilder()));
    LOG(INFO) << "My first ultimate log message";

    return 0;
}
<commit_msg>more log builder sample<commit_after> //
 // This file is part of Easylogging++ samples
 // Simple custom log builder
 //
 // Revision 1.0
 // @author mkhan3189
 //

#include "easylogging++.h"

_INITIALIZE_EASYLOGGINGPP

/// @brief Not a very fast log builder but good enough for sample
class MyLogBuilder : public el::api::LogBuilder {
public:
    std::string build(const el::LogMessage* logMessage, bool appendNewLine) const {
        std::stringstream str;
        str << logMessage->message();
        if (appendNewLine) str << "\n";
        return str.str().c_str();
    }
};

int main(void) {
    el::api::LogBuilderPtr myLogBuilder = el::api::LogBuilderPtr(new MyLogBuilder());
    el::Loggers::getLogger("default")->setLogBuilder(myLogBuilder);
    LOG(INFO) << "message from default logger";

    el::Loggers::getLogger("new_logger");
    CLOG(INFO, "new_logger") << "message from new_logger logger";

    el::Helpers::setDefaultLogBuilder(myLogBuilder);
    el::Loggers::getLogger("new_logger2");
    CLOG(INFO, "new_logger2") << "message from new_logger2 logger";

    return 0;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <cctype>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
}
#endif

namespace
{

	using namespace libtorrent;

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		for (int j = 0; j < 2; ++j)
		{
			if (!std::isprint(*i)) return boost::optional<fingerprint>();
			ret.id[j] = *i;
			++i;
		}

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.major_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.minor_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.revision_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.tag_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (!std::isprint(*i)) return boost::optional<fingerprint>();
		ret.id[0] = *i;
		ret.id[1] = 0;
		++i;

		if (std::equal(id.begin()+4, id.begin()+8, "----"))
		{
			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.major_version = *i - '0';
			++i;

			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.minor_version = *i - '0';
			++i;

			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.revision_version = *i - '0';
		}
		else if (id[8] == 0)
		{
			if (*i > 127) return boost::optional<fingerprint>();
			ret.major_version = *i;
			++i;

			if (*i > 127) return boost::optional<fingerprint>();
			ret.minor_version = *i;
			++i;

			if (*i > 127) return boost::optional<fingerprint>();
			ret.revision_version = *i;
		}
		else
			return boost::optional<fingerprint>();

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (!std::isprint(*i)) return boost::optional<fingerprint>();
		ret.id[0] = *i;
		ret.id[1] = 0;
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.major_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.minor_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.revision_version = *i - '0';
		++i;

		if (!std::equal(i, i+1, "--")) return boost::optional<fingerprint>();

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

} // namespace unnamed

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unkown";

		// look for azureus style id
		f = parse_az_style(p);
		if (f)
		{
			std::stringstream identity;

			// azureus
			if (std::equal(f->id, f->id+2, "AZ"))
				identity << "Azureus ";

			// BittorrentX
			else if (std::equal(f->id, f->id+2, "BX"))
				identity << "BittorrentX ";

			// libtorrent
			else if (std::equal(f->id, f->id+2, "LT"))
				identity << "libtorrent ";

			// Moonlight Torrent
			else if (std::equal(f->id, f->id+2, "MT"))
				identity << "Moonlight Torrent ";

			// Torrent Storm
			else if (std::equal(f->id, f->id+2, "TS"))
				identity << "TorrentStorm ";

			// SwarmScope
			else if (std::equal(f->id, f->id+2, "SS"))
				identity << "SwarmScope ";

			// XanTorrent
			else if (std::equal(f->id, f->id+2, "XT"))
				identity << "XanTorrent ";

			// unknown client
			else
				identity << std::string(f->id, f->id+2) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version
				<< "." << (int)f->tag_version;

			return identity.str();
		}

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f)
		{
			std::stringstream identity;

			// Shadow
			if (std::equal(f->id, f->id+1, "S"))
				identity << "Shadow ";

			// ABC
			if (std::equal(f->id, f->id+1, "A"))
				identity << "ABC ";

			// UPnP
			else if (std::equal(f->id, f->id+1, "U"))
				identity << "UPnP ";

			// BitTornado
			else if (std::equal(f->id, f->id+1, "T"))
				identity << "BitTornado ";

			// unknown client
			else
				identity << std::string(f->id, f->id+1) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version;

			return identity.str();
		}

		f = parse_mainline_style(p);
		if (f)
		{
			std::stringstream identity;

			// Mainline
			if (std::equal(f->id, f->id+1, "M"))
				identity << "Mainline ";

			// unknown client
			else
				identity << std::string(f->id, f->id+1) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version;

			return identity.str();
		}

		// ----------------------
		// non standard encodings
		// ----------------------

		if (std::equal(PID, PID + 12, "-G3g3rmz    "))
		{
			return "G3 Torrent";
		}

		if (std::equal(PID, PID + 4, "exbc"))
		{
			std::stringstream s;
			s << "BitComet " << (int)PID[4] << "." << (int)PID[5]/10 << (int)PID[5]%10;
			return s.str();
		}

		if (std::equal(PID + 5, PID + 5 + 8, "Azureus"))
		{
			return "Azureus 2.0.3.2";
		}

		if (std::equal(PID, PID + 11, "DansClient"))
		{
			return "XanTorrent";
		}

		if (std::equal(PID, PID + 7, "Plus---"))
		{
			return "Bittorrent Plus";
		}

		if (std::equal(PID, PID + 16, "Deadman Walking-"))
		{
			return "Deadman";
		}

		if (std::equal(PID, PID + 7, "btuga"))
		{
			return "BTugaXP";
		}

		if (std::equal(PID, PID + 7, "btfans"))
		{
			return "SimpleBT";
		}

		if (std::equal(PID, PID + 7, "turbobt"))
		{
			std::stringstream s;
			s << "TurboBT " << PID[8] << "." << PID[10] << "." << PID[12];
			return s.str();
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
		{
			return "Experimental 3.2.1b2";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
		{
			return "Experimental 3.1";
		}

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
		{
			return "Generic";
		}

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<commit_msg>*** empty log message ***<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <cctype>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
}
#endif

namespace
{

	using namespace libtorrent;

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		for (int j = 0; j < 2; ++j)
		{
			if (!std::isprint(*i)) return boost::optional<fingerprint>();
			ret.id[j] = *i;
			++i;
		}

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.major_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.minor_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.revision_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.tag_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (!std::isprint(*i)) return boost::optional<fingerprint>();
		ret.id[0] = *i;
		ret.id[1] = 0;
		++i;

		if (std::equal(id.begin()+4, id.begin()+8, "----"))
		{
			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.major_version = *i - '0';
			++i;

			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.minor_version = *i - '0';
			++i;

			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.revision_version = *i - '0';
		}
		else if (id[8] == 0)
		{
			if (*i > 127) return boost::optional<fingerprint>();
			ret.major_version = *i;
			++i;

			if (*i > 127) return boost::optional<fingerprint>();
			ret.minor_version = *i;
			++i;

			if (*i > 127) return boost::optional<fingerprint>();
			ret.revision_version = *i;
		}
		else
			return boost::optional<fingerprint>();

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (!std::isprint(*i)) return boost::optional<fingerprint>();
		ret.id[0] = *i;
		ret.id[1] = 0;
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.major_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.minor_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.revision_version = *i - '0';
		++i;

		if (!std::equal(i, i+1, "--")) return boost::optional<fingerprint>();

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

} // namespace unnamed

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unkown";

		// look for azureus style id
		f = parse_az_style(p);
		if (f)
		{
			std::stringstream identity;

			// azureus
			if (std::equal(f->id, f->id+2, "AZ"))
				identity << "Azureus ";

			// BittorrentX
			else if (std::equal(f->id, f->id+2, "BX"))
				identity << "BittorrentX ";

			// libtorrent
			else if (std::equal(f->id, f->id+2, "LT"))
				identity << "libtorrent ";

			// Moonlight Torrent
			else if (std::equal(f->id, f->id+2, "MT"))
				identity << "Moonlight Torrent ";

			// Torrent Storm
			else if (std::equal(f->id, f->id+2, "TS"))
				identity << "TorrentStorm ";

			// SwarmScope
			else if (std::equal(f->id, f->id+2, "SS"))
				identity << "SwarmScope ";

			// XanTorrent
			else if (std::equal(f->id, f->id+2, "XT"))
				identity << "XanTorrent ";

			// unknown client
			else
				identity << std::string(f->id, f->id+2) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version
				<< "." << (int)f->tag_version;

			return identity.str();
		}

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f)
		{
			std::stringstream identity;

			// Shadow
			if (std::equal(f->id, f->id+1, "S"))
				identity << "Shadow ";

			// ABC
			else if (std::equal(f->id, f->id+1, "A"))
				identity << "ABC ";

			// UPnP
			else if (std::equal(f->id, f->id+1, "U"))
				identity << "UPnP ";

			// BitTornado
			else if (std::equal(f->id, f->id+1, "T"))
				identity << "BitTornado ";

			// unknown client
			else
				identity << std::string(f->id, f->id+1) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version;

			return identity.str();
		}

		f = parse_mainline_style(p);
		if (f)
		{
			std::stringstream identity;

			// Mainline
			if (std::equal(f->id, f->id+1, "M"))
				identity << "Mainline ";

			// unknown client
			else
				identity << std::string(f->id, f->id+1) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version;

			return identity.str();
		}

		// ----------------------
		// non standard encodings
		// ----------------------

		if (std::equal(PID, PID + 12, "-G3g3rmz    "))
		{
			return "G3 Torrent";
		}

		if (std::equal(PID, PID + 4, "exbc"))
		{
			std::stringstream s;
			s << "BitComet " << (int)PID[4] << "." << (int)PID[5]/10 << (int)PID[5]%10;
			return s.str();
		}

		if (std::equal(PID + 5, PID + 5 + 8, "Azureus"))
		{
			return "Azureus 2.0.3.2";
		}

		if (std::equal(PID, PID + 11, "DansClient"))
		{
			return "XanTorrent";
		}

		if (std::equal(PID, PID + 7, "Plus---"))
		{
			return "Bittorrent Plus";
		}

		if (std::equal(PID, PID + 16, "Deadman Walking-"))
		{
			return "Deadman";
		}

		if (std::equal(PID, PID + 7, "btuga"))
		{
			return "BTugaXP";
		}

		if (std::equal(PID, PID + 7, "btfans"))
		{
			return "SimpleBT";
		}

		if (std::equal(PID, PID + 7, "turbobt"))
		{
			std::stringstream s;
			s << "TurboBT " << PID[8] << "." << PID[10] << "." << PID[12];
			return s.str();
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
		{
			return "Experimental 3.2.1b2";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
		{
			return "Experimental 3.1";
		}

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
		{
			return "Generic";
		}

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2017.  All rights reserved
 */
#ifndef _Stroika_Foundation_Time_Realtime_inl_
#define _Stroika_Foundation_Time_Realtime_inl_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
namespace Stroika {
    namespace Foundation {
        namespace Time {

            namespace Private_ {
                template <class Clock>
                DurationSecondsType GetClockTickountOffset_ ();

                template <>
                DurationSecondsType GetClockTickountOffset_<std::chrono::steady_clock> ();
            }

            /*
             ********************************************************************************
             ***************************** time_point2DurationSeconds ***********************
             ********************************************************************************
             */
            template <class Clock, class Duration>
            inline DurationSecondsType time_point2DurationSeconds (const time_point<Clock, Duration>& tp)
            {
                // nb: AtLeast() needed because first time through, steady_clock::now () for param called before one inside GetClockTickountOffset_
                // Cannot use  Math::AtLeast<DurationSecondsType> <> () because according to IEEE floating point -0 == 0 (but still prints as neg zero)
                // So do more carefully creafted if-test instead
                using std::chrono::duration;
                DurationSecondsType tmp = duration<DurationSecondsType>{tp.time_since_epoch ()}.count () - Private_::GetClockTickountOffset_<Clock> ();
                if (tmp <= 0) {
                    tmp = 0;
                }
                return tmp;
            }

            /*
             ********************************************************************************
             ***************************** DurationSeconds2time_point ***********************
             ********************************************************************************
             */
            template <class Clock, class Duration>
            inline time_point<Clock, Duration> DurationSeconds2time_point (DurationSecondsType t)
            {
                Require (t >= 0);
                using std::chrono::duration;
                return time_point<Clock, Duration> (std::chrono::duration_cast<Duration> (duration<DurationSecondsType>{t + Private_::GetClockTickountOffset_<Clock> ()}));
            }

            /*
             ********************************************************************************
             ******************************* Time::GetTickCount *****************************
             ********************************************************************************
             */
            inline DurationSecondsType GetTickCount () noexcept
            {
                try {
                    return time_point2DurationSeconds (std::chrono::steady_clock::now ());
                }
                catch (...) {
                    // Cannot DbgTrace here because DbgTrace () calls this...
                    return 0;
                }
            }
        }
    }
}
#endif /*_Stroika_Foundation_Time_Realtime_inl_*/
<commit_msg>minor fix to recent checkins<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2017.  All rights reserved
 */
#ifndef _Stroika_Foundation_Time_Realtime_inl_
#define _Stroika_Foundation_Time_Realtime_inl_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */

#include "../Debug/Assertions.h"

namespace Stroika {
    namespace Foundation {
        namespace Time {

            namespace Private_ {
                template <class Clock>
                DurationSecondsType GetClockTickountOffset_ ();

                template <>
                DurationSecondsType GetClockTickountOffset_<std::chrono::steady_clock> ();
            }

            /*
             ********************************************************************************
             ***************************** time_point2DurationSeconds ***********************
             ********************************************************************************
             */
            template <class Clock, class Duration>
            inline DurationSecondsType time_point2DurationSeconds (const time_point<Clock, Duration>& tp)
            {
                // nb: AtLeast() needed because first time through, steady_clock::now () for param called before one inside GetClockTickountOffset_
                // Cannot use  Math::AtLeast<DurationSecondsType> <> () because according to IEEE floating point -0 == 0 (but still prints as neg zero)
                // So do more carefully creafted if-test instead
                using std::chrono::duration;
                DurationSecondsType tmp = duration<DurationSecondsType>{tp.time_since_epoch ()}.count () - Private_::GetClockTickountOffset_<Clock> ();
                if (tmp <= 0) {
                    tmp = 0;
                }
                return tmp;
            }

            /*
             ********************************************************************************
             ***************************** DurationSeconds2time_point ***********************
             ********************************************************************************
             */
            template <class Clock, class Duration>
            inline time_point<Clock, Duration> DurationSeconds2time_point (DurationSecondsType t)
            {
                Require (t >= 0);
                using std::chrono::duration;
                return time_point<Clock, Duration> (std::chrono::duration_cast<Duration> (duration<DurationSecondsType>{t + Private_::GetClockTickountOffset_<Clock> ()}));
            }

            /*
             ********************************************************************************
             ******************************* Time::GetTickCount *****************************
             ********************************************************************************
             */
            inline DurationSecondsType GetTickCount () noexcept
            {
                try {
                    return time_point2DurationSeconds (std::chrono::steady_clock::now ());
                }
                catch (...) {
                    // Cannot DbgTrace here because DbgTrace () calls this...
                    return 0;
                }
            }
        }
    }
}
#endif /*_Stroika_Foundation_Time_Realtime_inl_*/
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "breakwindow.h"

#include "debuggeractions.h"
#include "debuggermanager.h"
#include "ui_breakcondition.h"
#include "ui_breakbyfunction.h"

#include <utils/qtcassert.h>

#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QFileInfoList>

#include <QtGui/QAction>
#include <QtGui/QHeaderView>
#include <QtGui/QKeyEvent>
#include <QtGui/QMenu>
#include <QtGui/QResizeEvent>
#include <QtGui/QItemSelectionModel>
#include <QtGui/QToolButton>
#include <QtGui/QTreeView>

using Debugger::Internal::BreakWindow;

///////////////////////////////////////////////////////////////////////
//
// BreakByFunctionDialog
//
///////////////////////////////////////////////////////////////////////

class BreakByFunctionDialog : public QDialog, Ui::BreakByFunctionDialog
{
public:
    explicit BreakByFunctionDialog(QWidget *parent)
      : QDialog(parent)
    {
        setupUi(this);
        connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
        connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
    }
    QString functionName() const { return functionLineEdit->text(); }
};

///////////////////////////////////////////////////////////////////////
//
// BreakWindow
//
///////////////////////////////////////////////////////////////////////

BreakWindow::BreakWindow(QWidget *parent)
  : QTreeView(parent), m_alwaysResizeColumnsToContents(false)
{
    QAction *act = theDebuggerAction(UseAlternatingRowColors);
    setWindowTitle(tr("Breakpoints"));
    setWindowIcon(QIcon(":/debugger/images/debugger_breakpoints.png"));
    setAlternatingRowColors(act->isChecked());
    setRootIsDecorated(false);
    setIconSize(QSize(10, 10));
    setSelectionMode(QAbstractItemView::ExtendedSelection);

    connect(this, SIGNAL(activated(QModelIndex)),
        this, SLOT(rowActivated(QModelIndex)));
    connect(act, SIGNAL(toggled(bool)),
        this, SLOT(setAlternatingRowColorsHelper(bool)));
    connect(theDebuggerAction(UseAddressInBreakpointsView), SIGNAL(toggled(bool)),
        this, SLOT(showAddressColumn(bool)));
}

void BreakWindow::showAddressColumn(bool on)
{
    setColumnHidden(6, !on);
}

static QModelIndexList normalizeIndexes(const QModelIndexList &list)
{
    QModelIndexList res;
    foreach (const QModelIndex &idx, list)
        if (idx.column() == 0)
            res.append(idx);
    return res;
}

void BreakWindow::keyPressEvent(QKeyEvent *ev)
{
    if (ev->key() == Qt::Key_Delete) {
        QItemSelectionModel *sm = selectionModel();
        QTC_ASSERT(sm, return);
        QModelIndexList si = sm->selectedIndexes();
        if (si.isEmpty())
            si.append(currentIndex().sibling(currentIndex().row(), 0));
        deleteBreakpoints(normalizeIndexes(si));
    }
    QTreeView::keyPressEvent(ev);
}

void BreakWindow::resizeEvent(QResizeEvent *ev)
{
    QTreeView::resizeEvent(ev);
}

void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
{
    QMenu menu;
    const QAbstractItemModel *itemModel = model();
    QItemSelectionModel *sm = selectionModel();
    QTC_ASSERT(sm, return);
    QModelIndexList si = sm->selectedIndexes();
    QModelIndex indexUnderMouse = indexAt(ev->pos());
    if (si.isEmpty() && indexUnderMouse.isValid())
        si.append(indexUnderMouse.sibling(indexUnderMouse.row(), 0));
    si = normalizeIndexes(si);

    const int rowCount = itemModel->rowCount();

    QAction *deleteAction = new QAction(tr("Delete breakpoint"), &menu);
    deleteAction->setEnabled(si.size() > 0);

    QAction *deleteAllAction = new QAction(tr("Delete all breakpoints"), &menu);
    deleteAllAction->setEnabled(si.size() > 0);

    // Delete by file: Find indexes of breakpoints of the same file
    QAction *deleteByFileAction = 0;
    QList<int> breakPointsOfFile;
    if (indexUnderMouse.isValid()) {
        const QString file = itemModel->data(indexUnderMouse.sibling(indexUnderMouse.row(), 2)).toString();
        if (!file.isEmpty()) {
            for (int i = 0; i < rowCount; i++)
                if (itemModel->data(itemModel->index(i, 2)).toString() == file)
                    breakPointsOfFile.push_back(i);
            if (breakPointsOfFile.size() > 1) {
                deleteByFileAction = new QAction(tr("Delete breakpoints of \"%1\"").arg(file), &menu);
                deleteByFileAction->setEnabled(true);
            }
        }
    }
    if (!deleteByFileAction) {
        deleteByFileAction = new QAction(tr("Delete breakpoints of file"), &menu);
        deleteByFileAction->setEnabled(false);
    }

    QAction *adjustColumnAction = new QAction(tr("Adjust column widths to contents"), &menu);

    QAction *alwaysAdjustAction = new QAction(tr("Always adjust column widths to contents"), &menu);
    alwaysAdjustAction->setCheckable(true);
    alwaysAdjustAction->setChecked(m_alwaysResizeColumnsToContents);

    QAction *editConditionAction = new QAction(tr("Edit condition..."), &menu);
    editConditionAction->setEnabled(si.size() > 0);

    QAction *synchronizeAction = new QAction(tr("Synchronize breakpoints"), &menu);
    synchronizeAction->setEnabled(Debugger::DebuggerManager::instance()->debuggerActionsEnabled());

    QModelIndex idx0 = (si.size() ? si.front() : QModelIndex());
    QModelIndex idx2 = idx0.sibling(idx0.row(), 2);
    bool enabled = si.isEmpty() || itemModel->data(idx0, Qt::UserRole).toBool();
    const QString str5 = enabled ? tr("Disable breakpoint") : tr("Enable breakpoint");
    QAction *toggleEnabledAction = new QAction(str5, &menu);
    toggleEnabledAction->setEnabled(si.size() > 0);

    const bool fullpath = si.isEmpty() || itemModel->data(idx2, Qt::UserRole).toBool();
    const QString str6 = fullpath ? tr("Use short path") : tr("Use full path");
    QAction *pathAction = new QAction(str6, &menu);
    pathAction->setEnabled(si.size() > 0);

    QAction *breakAtFunctionAction = new QAction(tr("Set Breakpoint at Function..."), this);
    QAction *breakAtMainAction = new QAction(tr("Set Breakpoint at Function \"main\""), this);

    menu.addAction(deleteAction);
    menu.addAction(editConditionAction);
    menu.addAction(toggleEnabledAction);
    menu.addAction(pathAction);
    menu.addSeparator();
    menu.addAction(deleteAllAction);
    menu.addAction(deleteByFileAction);
    menu.addSeparator();
    menu.addAction(synchronizeAction);
    menu.addSeparator();
    menu.addAction(breakAtFunctionAction);
    menu.addAction(breakAtMainAction);
    menu.addSeparator();
    menu.addAction(theDebuggerAction(UseToolTipsInBreakpointsView));
    menu.addAction(theDebuggerAction(UseAddressInBreakpointsView));
    menu.addAction(adjustColumnAction);
    menu.addAction(alwaysAdjustAction);
    menu.addSeparator();
    menu.addAction(theDebuggerAction(SettingsDialog));

    QAction *act = menu.exec(ev->globalPos());

    if (act == deleteAction) {
        deleteBreakpoints(si);
    } else if (act == deleteAllAction) {
        QList<int> allRows;
        for (int i = 0; i < rowCount; i++)
            allRows.push_back(i);
        deleteBreakpoints(allRows);
    }  else if (act == deleteByFileAction)
        deleteBreakpoints(breakPointsOfFile);
    else if (act == adjustColumnAction)
        resizeColumnsToContents();
    else if (act == alwaysAdjustAction)
        setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
    else if (act == editConditionAction)
        editConditions(si);
    else if (act == synchronizeAction)
        emit breakpointSynchronizationRequested();
    else if (act == toggleEnabledAction)
        setBreakpointsEnabled(si, !enabled);
    else if (act == pathAction)
        setBreakpointsFullPath(si, !enabled);
    else if (act == breakAtFunctionAction) {
        BreakByFunctionDialog dlg(this);
        if (dlg.exec())
            emit breakByFunctionRequested(dlg.functionName());
    } else if (act == breakAtMainAction)
        emit breakByFunctionMainRequested();
}

void BreakWindow::setBreakpointsEnabled(const QModelIndexList &list, bool enabled)
{
    foreach (const QModelIndex &idx, list)
        model()->setData(idx, enabled);
    emit breakpointSynchronizationRequested();
}

void BreakWindow::setBreakpointsFullPath(const QModelIndexList &list, bool fullpath)
{
    foreach (const QModelIndex &idx, list) {
        QModelIndex idx2 = idx.sibling(idx.row(), 2);
        model()->setData(idx2, fullpath);
    }
    emit breakpointSynchronizationRequested();
}

void BreakWindow::deleteBreakpoints(const QModelIndexList &indexes)
{
    QTC_ASSERT(!indexes.isEmpty(), return);
    QList<int> list;
    foreach (const QModelIndex &idx, indexes)
        list.append(idx.row());
    deleteBreakpoints(list);
}

void BreakWindow::deleteBreakpoints(QList<int> list)
{
    if (list.empty())
        return;
    const int firstRow = list.front();
    qSort(list.begin(), list.end());
    for (int i = list.size(); --i >= 0; )
        emit breakpointDeleted(list.at(i));

    const int row = qMax(firstRow, model()->rowCount() - list.size() - 1);
    if (row >= 0)
        setCurrentIndex(model()->index(row, 0));
}

void BreakWindow::editConditions(const QModelIndexList &list)
{
    QDialog dlg(this);
    Ui::BreakCondition ui;
    ui.setupUi(&dlg);

    QTC_ASSERT(!list.isEmpty(), return);
    QModelIndex idx = list.front();
    int row = idx.row();
    dlg.setWindowTitle(tr("Conditions on Breakpoint %1").arg(row));
    ui.lineEditCondition->setText(model()->data(idx.sibling(row, 4)).toString());
    ui.spinBoxIgnoreCount->setValue(model()->data(idx.sibling(row, 5)).toInt());

    if (dlg.exec() == QDialog::Rejected)
        return;

    foreach (const QModelIndex &idx, list) {
        model()->setData(idx.sibling(idx.row(), 4), ui.lineEditCondition->text());
        model()->setData(idx.sibling(idx.row(), 5), ui.spinBoxIgnoreCount->value());
    }
}

void BreakWindow::resizeColumnsToContents()
{
    for (int i = model()->columnCount(); --i >= 0; )
        resizeColumnToContents(i);
}

void BreakWindow::setAlwaysResizeColumnsToContents(bool on)
{
    m_alwaysResizeColumnsToContents = on;
    QHeaderView::ResizeMode mode = on
        ? QHeaderView::ResizeToContents : QHeaderView::Interactive;
    for (int i = model()->columnCount(); --i >= 0; )
        header()->setResizeMode(i, mode);
}

void BreakWindow::rowActivated(const QModelIndex &idx)
{
    emit breakpointActivated(idx.row());
}

<commit_msg>debugger: better positioning of current entry when deleting breakpoints<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "breakwindow.h"

#include "debuggeractions.h"
#include "debuggermanager.h"
#include "ui_breakcondition.h"
#include "ui_breakbyfunction.h"

#include <utils/qtcassert.h>

#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QFileInfoList>

#include <QtGui/QAction>
#include <QtGui/QHeaderView>
#include <QtGui/QKeyEvent>
#include <QtGui/QMenu>
#include <QtGui/QResizeEvent>
#include <QtGui/QItemSelectionModel>
#include <QtGui/QToolButton>
#include <QtGui/QTreeView>

using Debugger::Internal::BreakWindow;

///////////////////////////////////////////////////////////////////////
//
// BreakByFunctionDialog
//
///////////////////////////////////////////////////////////////////////

class BreakByFunctionDialog : public QDialog, Ui::BreakByFunctionDialog
{
public:
    explicit BreakByFunctionDialog(QWidget *parent)
      : QDialog(parent)
    {
        setupUi(this);
        connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
        connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
    }
    QString functionName() const { return functionLineEdit->text(); }
};

///////////////////////////////////////////////////////////////////////
//
// BreakWindow
//
///////////////////////////////////////////////////////////////////////

BreakWindow::BreakWindow(QWidget *parent)
  : QTreeView(parent), m_alwaysResizeColumnsToContents(false)
{
    QAction *act = theDebuggerAction(UseAlternatingRowColors);
    setWindowTitle(tr("Breakpoints"));
    setWindowIcon(QIcon(":/debugger/images/debugger_breakpoints.png"));
    setAlternatingRowColors(act->isChecked());
    setRootIsDecorated(false);
    setIconSize(QSize(10, 10));
    setSelectionMode(QAbstractItemView::ExtendedSelection);

    connect(this, SIGNAL(activated(QModelIndex)),
        this, SLOT(rowActivated(QModelIndex)));
    connect(act, SIGNAL(toggled(bool)),
        this, SLOT(setAlternatingRowColorsHelper(bool)));
    connect(theDebuggerAction(UseAddressInBreakpointsView), SIGNAL(toggled(bool)),
        this, SLOT(showAddressColumn(bool)));
}

void BreakWindow::showAddressColumn(bool on)
{
    setColumnHidden(6, !on);
}

static QModelIndexList normalizeIndexes(const QModelIndexList &list)
{
    QModelIndexList res;
    foreach (const QModelIndex &idx, list)
        if (idx.column() == 0)
            res.append(idx);
    return res;
}

void BreakWindow::keyPressEvent(QKeyEvent *ev)
{
    if (ev->key() == Qt::Key_Delete) {
        QItemSelectionModel *sm = selectionModel();
        QTC_ASSERT(sm, return);
        QModelIndexList si = sm->selectedIndexes();
        if (si.isEmpty())
            si.append(currentIndex().sibling(currentIndex().row(), 0));
        deleteBreakpoints(normalizeIndexes(si));
    }
    QTreeView::keyPressEvent(ev);
}

void BreakWindow::resizeEvent(QResizeEvent *ev)
{
    QTreeView::resizeEvent(ev);
}

void BreakWindow::contextMenuEvent(QContextMenuEvent *ev)
{
    QMenu menu;
    const QAbstractItemModel *itemModel = model();
    QItemSelectionModel *sm = selectionModel();
    QTC_ASSERT(sm, return);
    QModelIndexList si = sm->selectedIndexes();
    QModelIndex indexUnderMouse = indexAt(ev->pos());
    if (si.isEmpty() && indexUnderMouse.isValid())
        si.append(indexUnderMouse.sibling(indexUnderMouse.row(), 0));
    si = normalizeIndexes(si);

    const int rowCount = itemModel->rowCount();

    QAction *deleteAction = new QAction(tr("Delete breakpoint"), &menu);
    deleteAction->setEnabled(si.size() > 0);

    QAction *deleteAllAction = new QAction(tr("Delete all breakpoints"), &menu);
    deleteAllAction->setEnabled(si.size() > 0);

    // Delete by file: Find indexes of breakpoints of the same file
    QAction *deleteByFileAction = 0;
    QList<int> breakPointsOfFile;
    if (indexUnderMouse.isValid()) {
        const QString file = itemModel->data(indexUnderMouse.sibling(indexUnderMouse.row(), 2)).toString();
        if (!file.isEmpty()) {
            for (int i = 0; i < rowCount; i++)
                if (itemModel->data(itemModel->index(i, 2)).toString() == file)
                    breakPointsOfFile.push_back(i);
            if (breakPointsOfFile.size() > 1) {
                deleteByFileAction = new QAction(tr("Delete breakpoints of \"%1\"").arg(file), &menu);
                deleteByFileAction->setEnabled(true);
            }
        }
    }
    if (!deleteByFileAction) {
        deleteByFileAction = new QAction(tr("Delete breakpoints of file"), &menu);
        deleteByFileAction->setEnabled(false);
    }

    QAction *adjustColumnAction = new QAction(tr("Adjust column widths to contents"), &menu);

    QAction *alwaysAdjustAction = new QAction(tr("Always adjust column widths to contents"), &menu);
    alwaysAdjustAction->setCheckable(true);
    alwaysAdjustAction->setChecked(m_alwaysResizeColumnsToContents);

    QAction *editConditionAction = new QAction(tr("Edit condition..."), &menu);
    editConditionAction->setEnabled(si.size() > 0);

    QAction *synchronizeAction = new QAction(tr("Synchronize breakpoints"), &menu);
    synchronizeAction->setEnabled(Debugger::DebuggerManager::instance()->debuggerActionsEnabled());

    QModelIndex idx0 = (si.size() ? si.front() : QModelIndex());
    QModelIndex idx2 = idx0.sibling(idx0.row(), 2);
    bool enabled = si.isEmpty() || itemModel->data(idx0, Qt::UserRole).toBool();
    const QString str5 = enabled ? tr("Disable breakpoint") : tr("Enable breakpoint");
    QAction *toggleEnabledAction = new QAction(str5, &menu);
    toggleEnabledAction->setEnabled(si.size() > 0);

    const bool fullpath = si.isEmpty() || itemModel->data(idx2, Qt::UserRole).toBool();
    const QString str6 = fullpath ? tr("Use short path") : tr("Use full path");
    QAction *pathAction = new QAction(str6, &menu);
    pathAction->setEnabled(si.size() > 0);

    QAction *breakAtFunctionAction = new QAction(tr("Set Breakpoint at Function..."), this);
    QAction *breakAtMainAction = new QAction(tr("Set Breakpoint at Function \"main\""), this);

    menu.addAction(deleteAction);
    menu.addAction(editConditionAction);
    menu.addAction(toggleEnabledAction);
    menu.addAction(pathAction);
    menu.addSeparator();
    menu.addAction(deleteAllAction);
    menu.addAction(deleteByFileAction);
    menu.addSeparator();
    menu.addAction(synchronizeAction);
    menu.addSeparator();
    menu.addAction(breakAtFunctionAction);
    menu.addAction(breakAtMainAction);
    menu.addSeparator();
    menu.addAction(theDebuggerAction(UseToolTipsInBreakpointsView));
    menu.addAction(theDebuggerAction(UseAddressInBreakpointsView));
    menu.addAction(adjustColumnAction);
    menu.addAction(alwaysAdjustAction);
    menu.addSeparator();
    menu.addAction(theDebuggerAction(SettingsDialog));

    QAction *act = menu.exec(ev->globalPos());

    if (act == deleteAction) {
        deleteBreakpoints(si);
    } else if (act == deleteAllAction) {
        QList<int> allRows;
        for (int i = 0; i < rowCount; i++)
            allRows.push_back(i);
        deleteBreakpoints(allRows);
    }  else if (act == deleteByFileAction)
        deleteBreakpoints(breakPointsOfFile);
    else if (act == adjustColumnAction)
        resizeColumnsToContents();
    else if (act == alwaysAdjustAction)
        setAlwaysResizeColumnsToContents(!m_alwaysResizeColumnsToContents);
    else if (act == editConditionAction)
        editConditions(si);
    else if (act == synchronizeAction)
        emit breakpointSynchronizationRequested();
    else if (act == toggleEnabledAction)
        setBreakpointsEnabled(si, !enabled);
    else if (act == pathAction)
        setBreakpointsFullPath(si, !enabled);
    else if (act == breakAtFunctionAction) {
        BreakByFunctionDialog dlg(this);
        if (dlg.exec())
            emit breakByFunctionRequested(dlg.functionName());
    } else if (act == breakAtMainAction)
        emit breakByFunctionMainRequested();
}

void BreakWindow::setBreakpointsEnabled(const QModelIndexList &list, bool enabled)
{
    foreach (const QModelIndex &idx, list)
        model()->setData(idx, enabled);
    emit breakpointSynchronizationRequested();
}

void BreakWindow::setBreakpointsFullPath(const QModelIndexList &list, bool fullpath)
{
    foreach (const QModelIndex &idx, list) {
        QModelIndex idx2 = idx.sibling(idx.row(), 2);
        model()->setData(idx2, fullpath);
    }
    emit breakpointSynchronizationRequested();
}

void BreakWindow::deleteBreakpoints(const QModelIndexList &indexes)
{
    QTC_ASSERT(!indexes.isEmpty(), return);
    QList<int> list;
    foreach (const QModelIndex &idx, indexes)
        list.append(idx.row());
    deleteBreakpoints(list);
}

void BreakWindow::deleteBreakpoints(QList<int> list)
{
    if (list.empty())
        return;
    const int firstRow = list.front();
    qSort(list.begin(), list.end());
    for (int i = list.size(); --i >= 0; )
        emit breakpointDeleted(list.at(i));

    const int row = qMin(firstRow, model()->rowCount() - 1);
    if (row >= 0)
        setCurrentIndex(model()->index(row, 0));
}

void BreakWindow::editConditions(const QModelIndexList &list)
{
    QDialog dlg(this);
    Ui::BreakCondition ui;
    ui.setupUi(&dlg);

    QTC_ASSERT(!list.isEmpty(), return);
    QModelIndex idx = list.front();
    int row = idx.row();
    dlg.setWindowTitle(tr("Conditions on Breakpoint %1").arg(row));
    ui.lineEditCondition->setText(model()->data(idx.sibling(row, 4)).toString());
    ui.spinBoxIgnoreCount->setValue(model()->data(idx.sibling(row, 5)).toInt());

    if (dlg.exec() == QDialog::Rejected)
        return;

    foreach (const QModelIndex &idx, list) {
        model()->setData(idx.sibling(idx.row(), 4), ui.lineEditCondition->text());
        model()->setData(idx.sibling(idx.row(), 5), ui.spinBoxIgnoreCount->value());
    }
}

void BreakWindow::resizeColumnsToContents()
{
    for (int i = model()->columnCount(); --i >= 0; )
        resizeColumnToContents(i);
}

void BreakWindow::setAlwaysResizeColumnsToContents(bool on)
{
    m_alwaysResizeColumnsToContents = on;
    QHeaderView::ResizeMode mode = on
        ? QHeaderView::ResizeToContents : QHeaderView::Interactive;
    for (int i = model()->columnCount(); --i >= 0; )
        header()->setResizeMode(i, mode);
}

void BreakWindow::rowActivated(const QModelIndex &idx)
{
    emit breakpointActivated(idx.row());
}

<|endoftext|>


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

#ifndef INCLUDE_DISTORTOS_ARCHITECTURE_INTERRUPTMASKINGUNMASKINGLOCK_HPP_
#define INCLUDE_DISTORTOS_ARCHITECTURE_INTERRUPTMASKINGUNMASKINGLOCK_HPP_

#include "distortos/architecture/restoreInterruptMasking.hpp"

namespace distortos
{

namespace architecture
{

/**
 * \brief InterruptMaskingUnmaskingLock class is a RAII wrapper for interrupt mask manipulation.
 *
 * \param Function is a reference to function which modifies interrupt mask and returns InterruptMask;
 * enableInterruptMasking() or disableInterruptMasking() should be used
 */

template<InterruptMask (& Function)()>
class InterruptMaskingUnmaskingLock
{
public:

	/**
	 * \brief InterruptMaskingUnmaskingLock's constructor
	 *
	 * Enables/disables interrupt masking, saving current interrupt mask for use in destructor.
	 */

	InterruptMaskingUnmaskingLock() :
			interruptMask_{Function()}
	{}

	/**
	 * \brief InterruptMaskingUnmaskingLock's destructor
	 *
	 * Restores previous interrupt masking state by restoring interrupt mask saved in constructor.
	 */

	~InterruptMaskingUnmaskingLock()
	{
		restoreInterruptMasking(interruptMask_);
	}

	InterruptMaskingUnmaskingLock(const InterruptMaskingUnmaskingLock&) = delete;
	InterruptMaskingUnmaskingLock(InterruptMaskingUnmaskingLock&&) = delete;
	InterruptMaskingUnmaskingLock& operator=(const InterruptMaskingUnmaskingLock&) = delete;
	InterruptMaskingUnmaskingLock& operator=(InterruptMaskingUnmaskingLock&&) = delete;

private:

	/// interrupt mask
	const InterruptMask interruptMask_;
};

}	// namespace architecture

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_ARCHITECTURE_INTERRUPTMASKINGUNMASKINGLOCK_HPP_
<commit_msg>InterruptMaskingUnmaskingLock: minor style improvements<commit_after>/**
 * \file
 * \brief InterruptMaskingUnmaskingLock class header
 *
 * \author Copyright (C) 2014-2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-10-18
 */

#ifndef INCLUDE_DISTORTOS_ARCHITECTURE_INTERRUPTMASKINGUNMASKINGLOCK_HPP_
#define INCLUDE_DISTORTOS_ARCHITECTURE_INTERRUPTMASKINGUNMASKINGLOCK_HPP_

#include "distortos/architecture/restoreInterruptMasking.hpp"

namespace distortos
{

namespace architecture
{

/**
 * \brief InterruptMaskingUnmaskingLock class is a RAII wrapper for interrupt mask manipulation.
 *
 * \param Function is a reference to function which modifies interrupt mask and returns InterruptMask;
 * enableInterruptMasking() or disableInterruptMasking() should be used
 */

template<InterruptMask (& Function)()>
class InterruptMaskingUnmaskingLock
{
public:

	/**
	 * \brief InterruptMaskingUnmaskingLock's constructor
	 *
	 * Enables/disables interrupt masking, saving current interrupt mask for use in destructor.
	 */

	InterruptMaskingUnmaskingLock() :
			interruptMask_{Function()}
	{

	}

	/**
	 * \brief InterruptMaskingUnmaskingLock's destructor
	 *
	 * Restores previous interrupt masking state by restoring interrupt mask saved in constructor.
	 */

	~InterruptMaskingUnmaskingLock()
	{
		restoreInterruptMasking(interruptMask_);
	}

	InterruptMaskingUnmaskingLock(const InterruptMaskingUnmaskingLock&) = delete;
	InterruptMaskingUnmaskingLock(InterruptMaskingUnmaskingLock&&) = delete;
	InterruptMaskingUnmaskingLock& operator=(const InterruptMaskingUnmaskingLock&) = delete;
	InterruptMaskingUnmaskingLock& operator=(InterruptMaskingUnmaskingLock&&) = delete;

private:

	/// interrupt mask
	const InterruptMask interruptMask_;
};

}	// namespace architecture

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_ARCHITECTURE_INTERRUPTMASKINGUNMASKINGLOCK_HPP_
<|endoftext|>