<commit_before>#include "Runtime/MP1/World/CAtomicAlpha.hpp"

#include <array>

#include "Runtime/CStateManager.hpp"
#include "Runtime/Weapon/CPlayerGun.hpp"
#include "Runtime/World/CGameArea.hpp"
#include "Runtime/World/CPatternedInfo.hpp"
#include "Runtime/World/CPlayer.hpp"
#include "Runtime/World/CWorld.hpp"

namespace urde::MP1 {
constexpr std::array skBombLocators{
    "bomb1_LCTR"sv,
    "bomb2_LCTR"sv,
    "bomb3_LCTR"sv,
    "bomb4_LCTR"sv,
};

CAtomicAlpha::CAtomicAlpha(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
                           CModelData&& mData, const CActorParameters& actParms, const CPatternedInfo& pInfo,
                           CAssetId bombWeapon, const CDamageInfo& bombDamage, float bombDropDelay, float f2, float f3,
                           CAssetId cmdl, bool invisible, bool b2)
: CPatterned(ECharacter::AtomicAlpha, uid, name, EFlavorType::Zero, info, xf, std::move(mData), pInfo,
             EMovementType::Flyer, EColliderType::One, EBodyType::Flyer, actParms, EKnockBackVariant::Medium)
, x568_24_inRange(false)
, x568_25_invisible(invisible)
, x568_26_applyBeamAttraction(b2)
, x56c_bomdDropDelay(bombDropDelay)
, x570_bombReappearDelay(f2)
, x574_bombRappearTime(f3)
, x580_pathFind(nullptr, 3, pInfo.GetPathfindingIndex(), 1.f, 1.f)
, x668_bombProjectile(bombWeapon, bombDamage)
, x690_bombModel(CStaticRes(cmdl, GetModelData()->GetScale())) {
  x668_bombProjectile.Token().Lock();
  for (u32 i = 0; i < skBombCount; ++i) {
    x6dc_bombLocators.push_back(
        SBomb(skBombLocators[i], pas::ELocomotionType(u32(pas::ELocomotionType::Internal10) + i)));
  }
}

void CAtomicAlpha::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
  CPatterned::AcceptScriptMsg(msg, uid, mgr);
  if (msg == EScriptObjectMessage::InitializedInArea) {
    x580_pathFind.SetArea(mgr.GetWorld()->GetAreaAlways(GetAreaIdAlways())->GetPostConstructed()->x10bc_pathArea);
  } else if (msg == EScriptObjectMessage::Registered) {
    x450_bodyController->Activate(mgr);
  } else if (msg == EScriptObjectMessage::AddSplashInhabitant) {
    if (x400_25_alive)
      x401_30_pendingDeath = true;
  }
}

void CAtomicAlpha::Render(const CStateManager& mgr) const {
  if (mgr.GetPlayerState()->GetActiveVisor(mgr) != CPlayerState::EPlayerVisor::XRay && x568_25_invisible)
    return;

  CPatterned::Render(mgr);
  for (const SBomb& bomb : x6dc_bombLocators) {
    zeus::CTransform locatorXf =
        GetTransform() * GetScaledLocatorTransform(bomb.x0_locatorName) *
        zeus::CTransform::Scale(
            std::min(1.f, std::max(0.f, bomb.x14_scaleTime - x570_bombReappearDelay) / x570_bombReappearDelay));
    CModelFlags flags;
    flags.x2_flags = 1 | 2;
    flags.x4_color = zeus::skWhite;
    x690_bombModel.Render(mgr, locatorXf, x90_actorLights.get(), flags);
  }
}
void CAtomicAlpha::AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const {
  if (mgr.GetPlayerState()->GetActiveVisor(mgr) != CPlayerState::EPlayerVisor::XRay && x568_25_invisible)
    return;
  CPatterned::AddToRenderer(frustum, mgr);
}

void CAtomicAlpha::Think(float dt, CStateManager& mgr) {
  CPatterned::Think(dt, mgr);
  if (!GetActive())
    return;

  x578_bombTime += dt;

  for (SBomb& bomb : x6dc_bombLocators) {
    bomb.x14_scaleTime += dt;
  }
}

void CAtomicAlpha::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt) {
  if (type == EUserEventType::Projectile) {
    zeus::CVector3f origin = GetLctrTransform(node.GetLocatorName()).origin;
    zeus::CTransform xf = zeus::lookAt(origin, origin + zeus::skDown, zeus::skUp);
    LaunchProjectile(xf, mgr, 4, EProjectileAttrib::None, false, {}, 0xFFFF, false, zeus::CVector3f(1.f));
    x578_bombTime = 0.f;
    x57c_curBomb = (x57c_curBomb + 1) & (x6dc_bombLocators.size() - 1);
  } else
    CPatterned::DoUserAnimEvent(mgr, node, type, dt);
}

bool CAtomicAlpha::Leash(CStateManager& mgr, float) {
  if ((mgr.GetPlayer().GetTranslation() - GetTranslation()).magSquared() <=
      x3cc_playerLeashRadius * x3cc_playerLeashRadius)
    return false;

  return x3d4_curPlayerLeashTime > x3d0_playerLeashTime;
}

bool CAtomicAlpha::AggressionCheck(CStateManager& mgr, float) {
  const CPlayerGun* playerGun = mgr.GetPlayer().GetPlayerGun();
  float factor = 0.f;
  if (x568_26_applyBeamAttraction && playerGun->IsCharging())
    factor = playerGun->GetChargeBeamFactor();
  return factor > 0.1f;
}

void CAtomicAlpha::CollidedWith(TUniqueId uid, const CCollisionInfoList& list, CStateManager& mgr) {
  if (IsAlive()) {
    if (TCastToConstPtr<CPlayer> pl = mgr.GetObjectById(uid)) {
      if (x420_curDamageRemTime <= 0.f) {
        mgr.GetPlayerState()->GetStaticInterference().AddSource(GetUniqueId(), 0.5f, 0.25f);
        for (SBomb& bomb : x6dc_bombLocators) {
          bomb.x14_scaleTime = 0.f;
        }
      }
    }
  }
  CPatterned::CollidedWith(uid, list, mgr);
}

void CAtomicAlpha::Patrol(CStateManager& mgr, EStateMsg msg, float arg) {
  CPatterned::Patrol(mgr, msg, arg);
  if (msg == EStateMsg::Activate) {
    x578_bombTime = 0.f;
  } else if (msg == EStateMsg::Update) {
    if (x568_24_inRange) {
      if (x578_bombTime >= x56c_bomdDropDelay &&
          x6dc_bombLocators[0].x14_scaleTime > (x570_bombReappearDelay + x574_bombRappearTime)) {
        x450_bodyController->SetLocomotionType(x6dc_bombLocators[x57c_curBomb].x10_locomotionType);
      } else {
        x450_bodyController->SetLocomotionType(pas::ELocomotionType::Relaxed);
      }
      if (Leash(mgr, arg))
        x568_24_inRange = false;
    } else {
      x450_bodyController->SetLocomotionType(pas::ELocomotionType::Relaxed);
      if (InMaxRange(mgr, arg))
        x568_24_inRange = true;
    }
  } else if (msg == EStateMsg::Deactivate) {
    x568_24_inRange = false;
  }
}

void CAtomicAlpha::Attack(CStateManager& mgr, EStateMsg msg, float) {
  if (msg == EStateMsg::Activate) {
    x450_bodyController->SetLocomotionType(pas::ELocomotionType::Internal8);
  } else if (msg == EStateMsg::Update) {
    zeus::CVector3f seekVec = x664_steeringBehaviors.Seek(*this, mgr.GetPlayer().GetEyePosition());
    x450_bodyController->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(seekVec, {}, 1.f));
  } else if (msg == EStateMsg::Deactivate) {
    x450_bodyController->SetLocomotionType(pas::ELocomotionType::Relaxed);
  }
}
} // namespace urde::MP1
<commit_msg>CAtomicAlpha: Use emplace_back where applicable<commit_after>#include "Runtime/MP1/World/CAtomicAlpha.hpp"

#include <array>

#include "Runtime/CStateManager.hpp"
#include "Runtime/Weapon/CPlayerGun.hpp"
#include "Runtime/World/CGameArea.hpp"
#include "Runtime/World/CPatternedInfo.hpp"
#include "Runtime/World/CPlayer.hpp"
#include "Runtime/World/CWorld.hpp"

namespace urde::MP1 {
constexpr std::array skBombLocators{
    "bomb1_LCTR"sv,
    "bomb2_LCTR"sv,
    "bomb3_LCTR"sv,
    "bomb4_LCTR"sv,
};

CAtomicAlpha::CAtomicAlpha(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
                           CModelData&& mData, const CActorParameters& actParms, const CPatternedInfo& pInfo,
                           CAssetId bombWeapon, const CDamageInfo& bombDamage, float bombDropDelay, float f2, float f3,
                           CAssetId cmdl, bool invisible, bool b2)
: CPatterned(ECharacter::AtomicAlpha, uid, name, EFlavorType::Zero, info, xf, std::move(mData), pInfo,
             EMovementType::Flyer, EColliderType::One, EBodyType::Flyer, actParms, EKnockBackVariant::Medium)
, x568_24_inRange(false)
, x568_25_invisible(invisible)
, x568_26_applyBeamAttraction(b2)
, x56c_bomdDropDelay(bombDropDelay)
, x570_bombReappearDelay(f2)
, x574_bombRappearTime(f3)
, x580_pathFind(nullptr, 3, pInfo.GetPathfindingIndex(), 1.f, 1.f)
, x668_bombProjectile(bombWeapon, bombDamage)
, x690_bombModel(CStaticRes(cmdl, GetModelData()->GetScale())) {
  x668_bombProjectile.Token().Lock();
  for (u32 i = 0; i < skBombCount; ++i) {
    x6dc_bombLocators.emplace_back(skBombLocators[i], pas::ELocomotionType(u32(pas::ELocomotionType::Internal10) + i));
  }
}

void CAtomicAlpha::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
  CPatterned::AcceptScriptMsg(msg, uid, mgr);
  if (msg == EScriptObjectMessage::InitializedInArea) {
    x580_pathFind.SetArea(mgr.GetWorld()->GetAreaAlways(GetAreaIdAlways())->GetPostConstructed()->x10bc_pathArea);
  } else if (msg == EScriptObjectMessage::Registered) {
    x450_bodyController->Activate(mgr);
  } else if (msg == EScriptObjectMessage::AddSplashInhabitant) {
    if (x400_25_alive)
      x401_30_pendingDeath = true;
  }
}

void CAtomicAlpha::Render(const CStateManager& mgr) const {
  if (mgr.GetPlayerState()->GetActiveVisor(mgr) != CPlayerState::EPlayerVisor::XRay && x568_25_invisible)
    return;

  CPatterned::Render(mgr);
  for (const SBomb& bomb : x6dc_bombLocators) {
    zeus::CTransform locatorXf =
        GetTransform() * GetScaledLocatorTransform(bomb.x0_locatorName) *
        zeus::CTransform::Scale(
            std::min(1.f, std::max(0.f, bomb.x14_scaleTime - x570_bombReappearDelay) / x570_bombReappearDelay));
    CModelFlags flags;
    flags.x2_flags = 1 | 2;
    flags.x4_color = zeus::skWhite;
    x690_bombModel.Render(mgr, locatorXf, x90_actorLights.get(), flags);
  }
}
void CAtomicAlpha::AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const {
  if (mgr.GetPlayerState()->GetActiveVisor(mgr) != CPlayerState::EPlayerVisor::XRay && x568_25_invisible)
    return;
  CPatterned::AddToRenderer(frustum, mgr);
}

void CAtomicAlpha::Think(float dt, CStateManager& mgr) {
  CPatterned::Think(dt, mgr);
  if (!GetActive())
    return;

  x578_bombTime += dt;

  for (SBomb& bomb : x6dc_bombLocators) {
    bomb.x14_scaleTime += dt;
  }
}

void CAtomicAlpha::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt) {
  if (type == EUserEventType::Projectile) {
    zeus::CVector3f origin = GetLctrTransform(node.GetLocatorName()).origin;
    zeus::CTransform xf = zeus::lookAt(origin, origin + zeus::skDown, zeus::skUp);
    LaunchProjectile(xf, mgr, 4, EProjectileAttrib::None, false, {}, 0xFFFF, false, zeus::CVector3f(1.f));
    x578_bombTime = 0.f;
    x57c_curBomb = (x57c_curBomb + 1) & (x6dc_bombLocators.size() - 1);
  } else
    CPatterned::DoUserAnimEvent(mgr, node, type, dt);
}

bool CAtomicAlpha::Leash(CStateManager& mgr, float) {
  if ((mgr.GetPlayer().GetTranslation() - GetTranslation()).magSquared() <=
      x3cc_playerLeashRadius * x3cc_playerLeashRadius)
    return false;

  return x3d4_curPlayerLeashTime > x3d0_playerLeashTime;
}

bool CAtomicAlpha::AggressionCheck(CStateManager& mgr, float) {
  const CPlayerGun* playerGun = mgr.GetPlayer().GetPlayerGun();
  float factor = 0.f;
  if (x568_26_applyBeamAttraction && playerGun->IsCharging())
    factor = playerGun->GetChargeBeamFactor();
  return factor > 0.1f;
}

void CAtomicAlpha::CollidedWith(TUniqueId uid, const CCollisionInfoList& list, CStateManager& mgr) {
  if (IsAlive()) {
    if (TCastToConstPtr<CPlayer> pl = mgr.GetObjectById(uid)) {
      if (x420_curDamageRemTime <= 0.f) {
        mgr.GetPlayerState()->GetStaticInterference().AddSource(GetUniqueId(), 0.5f, 0.25f);
        for (SBomb& bomb : x6dc_bombLocators) {
          bomb.x14_scaleTime = 0.f;
        }
      }
    }
  }
  CPatterned::CollidedWith(uid, list, mgr);
}

void CAtomicAlpha::Patrol(CStateManager& mgr, EStateMsg msg, float arg) {
  CPatterned::Patrol(mgr, msg, arg);
  if (msg == EStateMsg::Activate) {
    x578_bombTime = 0.f;
  } else if (msg == EStateMsg::Update) {
    if (x568_24_inRange) {
      if (x578_bombTime >= x56c_bomdDropDelay &&
          x6dc_bombLocators[0].x14_scaleTime > (x570_bombReappearDelay + x574_bombRappearTime)) {
        x450_bodyController->SetLocomotionType(x6dc_bombLocators[x57c_curBomb].x10_locomotionType);
      } else {
        x450_bodyController->SetLocomotionType(pas::ELocomotionType::Relaxed);
      }
      if (Leash(mgr, arg))
        x568_24_inRange = false;
    } else {
      x450_bodyController->SetLocomotionType(pas::ELocomotionType::Relaxed);
      if (InMaxRange(mgr, arg))
        x568_24_inRange = true;
    }
  } else if (msg == EStateMsg::Deactivate) {
    x568_24_inRange = false;
  }
}

void CAtomicAlpha::Attack(CStateManager& mgr, EStateMsg msg, float) {
  if (msg == EStateMsg::Activate) {
    x450_bodyController->SetLocomotionType(pas::ELocomotionType::Internal8);
  } else if (msg == EStateMsg::Update) {
    zeus::CVector3f seekVec = x664_steeringBehaviors.Seek(*this, mgr.GetPlayer().GetEyePosition());
    x450_bodyController->GetCommandMgr().DeliverCmd(CBCLocomotionCmd(seekVec, {}, 1.f));
  } else if (msg == EStateMsg::Deactivate) {
    x450_bodyController->SetLocomotionType(pas::ELocomotionType::Relaxed);
  }
}
} // namespace urde::MP1
<|endoftext|>


<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 *  ---
 *
 *  The Verilog frontend.
 *
 *  This frontend is using the AST frontend library (see frontends/ast/).
 *  Thus this frontend does not generate RTLIL code directly but creates an
 *  AST directly from the Verilog parse tree and then passes this AST to
 *  the AST frontend library.
 *
 *  ---
 *
 *  Ad-hoc implementation of a Verilog preprocessor. The directives `define,
 *  `include, `ifdef, `ifndef, `else and `endif are handled here. All other
 *  directives are handled by the lexer (see lexer.l).
 *
 */

#include "verilog_frontend.h"
#include "kernel/log.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

YOSYS_NAMESPACE_BEGIN

static std::list<std::string> output_code;
static std::list<std::string> input_buffer;
static size_t input_buffer_charp;

static void return_char(char ch)
{
	if (input_buffer_charp == 0)
		input_buffer.push_front(std::string() + ch);
	else
		input_buffer.front()[--input_buffer_charp] = ch;
}

static void insert_input(std::string str)
{
	if (input_buffer_charp != 0) {
		input_buffer.front() = input_buffer.front().substr(input_buffer_charp);
		input_buffer_charp = 0;
	}
	input_buffer.push_front(str);
}

static char next_char()
{
	if (input_buffer.empty())
		return 0;

	log_assert(input_buffer_charp <= input_buffer.front().size());
	if (input_buffer_charp == input_buffer.front().size()) {
		input_buffer_charp = 0;
		input_buffer.pop_front();
		return next_char();
	}

	char ch = input_buffer.front()[input_buffer_charp++];
	return ch == '\r' ? next_char() : ch;
}

static std::string skip_spaces()
{
	std::string spaces;
	while (1) {
		char ch = next_char();
		if (ch == 0)
			break;
		if (ch != ' ' && ch != '\t') {
			return_char(ch);
			break;
		}
		spaces += ch;
	}
	return spaces;
}

static std::string next_token(bool pass_newline = false)
{
	std::string token;

	char ch = next_char();
	if (ch == 0)
		return token;

	token += ch;
	if (ch == '\n') {
		if (pass_newline) {
			output_code.push_back(token);
			return "";
		}
		return token;
	}

	if (ch == ' ' || ch == '\t')
	{
		while ((ch = next_char()) != 0) {
			if (ch != ' ' && ch != '\t') {
				return_char(ch);
				break;
			}
			token += ch;
		}
	}
	else if (ch == '"')
	{
		while ((ch = next_char()) != 0) {
			token += ch;
			if (ch == '"')
				break;
			if (ch == '\\') {
				if ((ch = next_char()) != 0)
					token += ch;
			}
		}
		if (token == "\"\"" && (ch = next_char()) != 0) {
			if (ch == '"')
				token += ch;
			else
				return_char(ch);
		}
	}
	else if (ch == '/')
	{
		if ((ch = next_char()) != 0) {
			if (ch == '/') {
				token += '*';
				char last_ch = 0;
				while ((ch = next_char()) != 0) {
					if (ch == '\n') {
						return_char(ch);
						break;
					}
					if (last_ch != '*' || ch != '/') {
						token += ch;
						last_ch = ch;
					}
				}
				token += " */";
			}
			else if (ch == '*') {
				token += '*';
				int newline_count = 0;
				char last_ch = 0;
				while ((ch = next_char()) != 0) {
					if (ch == '\n') {
						newline_count++;
						token += ' ';
					} else
						token += ch;
					if (last_ch == '*' && ch == '/')
						break;
					last_ch = ch;
				}
				while (newline_count-- > 0)
					return_char('\n');
			}
			else
				return_char(ch);
		}
	}
	else
	{
		const char *ok = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ$0123456789";
		if (ch == '`' || strchr(ok, ch) != NULL)
			while ((ch = next_char()) != 0) {
				if (strchr(ok, ch) == NULL) {
					return_char(ch);
					break;
				}
				token += ch;
			}
	}

	return token;
}

static void input_file(FILE *f, std::string filename)
{
	char buffer[513];
	int rc;

	insert_input("");
	auto it = input_buffer.begin();

	input_buffer.insert(it, "`file_push " + filename + "\n");
	while ((rc = fread(buffer, 1, sizeof(buffer)-1, f)) > 0) {
		buffer[rc] = 0;
		input_buffer.insert(it, buffer);
	}
	input_buffer.insert(it, "\n`file_pop\n");
}

std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::map<std::string, std::string> pre_defines_map, const std::list<std::string> include_dirs)
{
	std::set<std::string> defines_with_args;
	std::map<std::string, std::string> defines_map(pre_defines_map);
	int ifdef_fail_level = 0;
	bool in_elseif = false;

	output_code.clear();
	input_buffer.clear();
	input_buffer_charp = 0;

	input_file(f, filename);
	defines_map["__YOSYS__"] = "1";

	while (!input_buffer.empty())
	{
		std::string tok = next_token();
		// printf("token: >>%s<<\n", tok != "\n" ? tok.c_str() : "NEWLINE");

		if (tok == "`endif") {
			if (ifdef_fail_level > 0)
				ifdef_fail_level--;
			if (ifdef_fail_level == 0)
				in_elseif = false;
			continue;
		}

		if (tok == "`else") {
			if (ifdef_fail_level == 0)
				ifdef_fail_level = 1;
			else if (ifdef_fail_level == 1 && !in_elseif)
				ifdef_fail_level = 0;
			continue;
		}

		if (tok == "`elsif") {
			skip_spaces();
			std::string name = next_token(true);
			if (ifdef_fail_level == 0)
				ifdef_fail_level = 1, in_elseif = true;
			else if (ifdef_fail_level == 1 && defines_map.count(name) != 0)
				ifdef_fail_level = 0, in_elseif = true;
			continue;
		}

		if (tok == "`ifdef") {
			skip_spaces();
			std::string name = next_token(true);
			if (ifdef_fail_level > 0 || defines_map.count(name) == 0)
				ifdef_fail_level++;
			continue;
		}

		if (tok == "`ifndef") {
			skip_spaces();
			std::string name = next_token(true);
			if (ifdef_fail_level > 0 || defines_map.count(name) != 0)
				ifdef_fail_level++;
			continue;
		}

		if (ifdef_fail_level > 0) {
			if (tok == "\n")
				output_code.push_back(tok);
			continue;
		}

		if (tok == "`include") {
			skip_spaces();
			std::string fn = next_token(true);
			while (1) {
				size_t pos = fn.find('"');
				if (pos == std::string::npos)
					break;
				if (pos == 0)
					fn = fn.substr(1);
				else
					fn = fn.substr(0, pos) + fn.substr(pos+1);
			}
			FILE *fp = fopen(fn.c_str(), "r");
			if (fp == NULL && fn.size() > 0 && fn[0] != '/' && filename.find('/') != std::string::npos) {
				// if the include file was not found, it is not given with an absolute path, and the
				// currently read file is given with a path, then try again relative to its directory
				std::string fn2 = filename.substr(0, filename.rfind('/')+1) + fn;
				fp = fopen(fn2.c_str(), "r");
			}
			if (fp == NULL && fn.size() > 0 && fn[0] != '/') {
				// if the include file was not found and it is not given with an absolute path, then
				// search it in the include path
				for (auto incdir : include_dirs) {
					std::string fn2 = incdir + '/' + fn;
					fp = fopen(fn2.c_str(), "r");
					if (fp != NULL) break;
				}
			}
			if (fp != NULL) {
				input_file(fp, fn);
				fclose(fp);
			} else
				output_code.push_back("`file_notfound " + fn);
			continue;
		}

		if (tok == "`define") {
			std::string name, value;
			std::map<std::string, int> args;
			skip_spaces();
			name = next_token(true);
			bool here_doc_mode = false;
			int newline_count = 0;
			int state = 0;
			if (skip_spaces() != "")
				state = 3;
			while (!tok.empty()) {
				tok = next_token();
				if (tok == "\"\"\"") {
					here_doc_mode = !here_doc_mode;
					continue;
				}
				if (state == 0 && tok == "(") {
					state = 1;
					skip_spaces();
				} else
				if (state == 1) {
					if (tok == ")")
						state = 2;
					else if (tok != ",") {
						int arg_idx = args.size()+1;
						args[tok] = arg_idx;
					}
					skip_spaces();
				} else {
					if (state != 2)
						state = 3;
					if (tok == "\n" && !here_doc_mode) {
						return_char('\n');
						break;
					}
					if (tok == "\\") {
						char ch = next_char();
						if (ch == '\n') {
							value += " ";
							newline_count++;
						} else {
							value += std::string("\\");
							return_char(ch);
						}
					} else
					if (args.count(tok) > 0)
						value += stringf("`macro_%s_arg%d", name.c_str(), args.at(tok));
					else
						value += tok;
				}
			}
			while (newline_count-- > 0)
				return_char('\n');
			// printf("define: >>%s<< -> >>%s<<\n", name.c_str(), value.c_str());
			defines_map[name] = value;
			if (state == 2)
				defines_with_args.insert(name);
			else
				defines_with_args.erase(name);
			continue;
		}

		if (tok == "`undef") {
			std::string name;
			skip_spaces();
			name = next_token(true);
			// printf("undef: >>%s<<\n", name.c_str());
			defines_map.erase(name);
			defines_with_args.erase(name);
			continue;
		}

		if (tok == "`timescale") {
			skip_spaces();
			while (!tok.empty() && tok != "\n")
				tok = next_token(true);
			if (tok == "\n")
				return_char('\n');
			continue;
		}

		if (tok.size() > 1 && tok[0] == '`' && defines_map.count(tok.substr(1)) > 0) {
			std::string name = tok.substr(1);
			// printf("expand: >>%s<< -> >>%s<<\n", name.c_str(), defines_map[name].c_str());
			std::string skipped_spaces = skip_spaces();
			tok = next_token(false);
			if (tok == "(" && defines_with_args.count(name) > 0) {
				int level = 1;
				std::vector<std::string> args;
				args.push_back(std::string());
				while (1)
				{
					tok = next_token(true);
					if (tok == ")" || tok == "}" || tok == "]")
						level--;
					if (level == 0)
						break;
					if (level == 1 && tok == ",")
						args.push_back(std::string());
					else
						args.back() += tok;
					if (tok == "(" || tok == "{" || tok == "[")
						level++;
				}
				for (size_t i = 0; i < args.size(); i++)
					defines_map[stringf("macro_%s_arg%d", name.c_str(), i+1)] = args[i];
			} else {
				insert_input(tok);
				insert_input(skipped_spaces);
			}
			insert_input(defines_map[name]);
			continue;
		}

		output_code.push_back(tok);
	}

	std::string output;
	for (auto &str : output_code)
		output += str;

	output_code.clear();
	input_buffer.clear();
	input_buffer_charp = 0;

	return output;
}

YOSYS_NAMESPACE_END

<commit_msg>Fixed line numbers when using here-doc macros<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 *  ---
 *
 *  The Verilog frontend.
 *
 *  This frontend is using the AST frontend library (see frontends/ast/).
 *  Thus this frontend does not generate RTLIL code directly but creates an
 *  AST directly from the Verilog parse tree and then passes this AST to
 *  the AST frontend library.
 *
 *  ---
 *
 *  Ad-hoc implementation of a Verilog preprocessor. The directives `define,
 *  `include, `ifdef, `ifndef, `else and `endif are handled here. All other
 *  directives are handled by the lexer (see lexer.l).
 *
 */

#include "verilog_frontend.h"
#include "kernel/log.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

YOSYS_NAMESPACE_BEGIN

static std::list<std::string> output_code;
static std::list<std::string> input_buffer;
static size_t input_buffer_charp;

static void return_char(char ch)
{
	if (input_buffer_charp == 0)
		input_buffer.push_front(std::string() + ch);
	else
		input_buffer.front()[--input_buffer_charp] = ch;
}

static void insert_input(std::string str)
{
	if (input_buffer_charp != 0) {
		input_buffer.front() = input_buffer.front().substr(input_buffer_charp);
		input_buffer_charp = 0;
	}
	input_buffer.push_front(str);
}

static char next_char()
{
	if (input_buffer.empty())
		return 0;

	log_assert(input_buffer_charp <= input_buffer.front().size());
	if (input_buffer_charp == input_buffer.front().size()) {
		input_buffer_charp = 0;
		input_buffer.pop_front();
		return next_char();
	}

	char ch = input_buffer.front()[input_buffer_charp++];
	return ch == '\r' ? next_char() : ch;
}

static std::string skip_spaces()
{
	std::string spaces;
	while (1) {
		char ch = next_char();
		if (ch == 0)
			break;
		if (ch != ' ' && ch != '\t') {
			return_char(ch);
			break;
		}
		spaces += ch;
	}
	return spaces;
}

static std::string next_token(bool pass_newline = false)
{
	std::string token;

	char ch = next_char();
	if (ch == 0)
		return token;

	token += ch;
	if (ch == '\n') {
		if (pass_newline) {
			output_code.push_back(token);
			return "";
		}
		return token;
	}

	if (ch == ' ' || ch == '\t')
	{
		while ((ch = next_char()) != 0) {
			if (ch != ' ' && ch != '\t') {
				return_char(ch);
				break;
			}
			token += ch;
		}
	}
	else if (ch == '"')
	{
		while ((ch = next_char()) != 0) {
			token += ch;
			if (ch == '"')
				break;
			if (ch == '\\') {
				if ((ch = next_char()) != 0)
					token += ch;
			}
		}
		if (token == "\"\"" && (ch = next_char()) != 0) {
			if (ch == '"')
				token += ch;
			else
				return_char(ch);
		}
	}
	else if (ch == '/')
	{
		if ((ch = next_char()) != 0) {
			if (ch == '/') {
				token += '*';
				char last_ch = 0;
				while ((ch = next_char()) != 0) {
					if (ch == '\n') {
						return_char(ch);
						break;
					}
					if (last_ch != '*' || ch != '/') {
						token += ch;
						last_ch = ch;
					}
				}
				token += " */";
			}
			else if (ch == '*') {
				token += '*';
				int newline_count = 0;
				char last_ch = 0;
				while ((ch = next_char()) != 0) {
					if (ch == '\n') {
						newline_count++;
						token += ' ';
					} else
						token += ch;
					if (last_ch == '*' && ch == '/')
						break;
					last_ch = ch;
				}
				while (newline_count-- > 0)
					return_char('\n');
			}
			else
				return_char(ch);
		}
	}
	else
	{
		const char *ok = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ$0123456789";
		if (ch == '`' || strchr(ok, ch) != NULL)
			while ((ch = next_char()) != 0) {
				if (strchr(ok, ch) == NULL) {
					return_char(ch);
					break;
				}
				token += ch;
			}
	}

	return token;
}

static void input_file(FILE *f, std::string filename)
{
	char buffer[513];
	int rc;

	insert_input("");
	auto it = input_buffer.begin();

	input_buffer.insert(it, "`file_push " + filename + "\n");
	while ((rc = fread(buffer, 1, sizeof(buffer)-1, f)) > 0) {
		buffer[rc] = 0;
		input_buffer.insert(it, buffer);
	}
	input_buffer.insert(it, "\n`file_pop\n");
}

std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::map<std::string, std::string> pre_defines_map, const std::list<std::string> include_dirs)
{
	std::set<std::string> defines_with_args;
	std::map<std::string, std::string> defines_map(pre_defines_map);
	int ifdef_fail_level = 0;
	bool in_elseif = false;

	output_code.clear();
	input_buffer.clear();
	input_buffer_charp = 0;

	input_file(f, filename);
	defines_map["__YOSYS__"] = "1";

	while (!input_buffer.empty())
	{
		std::string tok = next_token();
		// printf("token: >>%s<<\n", tok != "\n" ? tok.c_str() : "NEWLINE");

		if (tok == "`endif") {
			if (ifdef_fail_level > 0)
				ifdef_fail_level--;
			if (ifdef_fail_level == 0)
				in_elseif = false;
			continue;
		}

		if (tok == "`else") {
			if (ifdef_fail_level == 0)
				ifdef_fail_level = 1;
			else if (ifdef_fail_level == 1 && !in_elseif)
				ifdef_fail_level = 0;
			continue;
		}

		if (tok == "`elsif") {
			skip_spaces();
			std::string name = next_token(true);
			if (ifdef_fail_level == 0)
				ifdef_fail_level = 1, in_elseif = true;
			else if (ifdef_fail_level == 1 && defines_map.count(name) != 0)
				ifdef_fail_level = 0, in_elseif = true;
			continue;
		}

		if (tok == "`ifdef") {
			skip_spaces();
			std::string name = next_token(true);
			if (ifdef_fail_level > 0 || defines_map.count(name) == 0)
				ifdef_fail_level++;
			continue;
		}

		if (tok == "`ifndef") {
			skip_spaces();
			std::string name = next_token(true);
			if (ifdef_fail_level > 0 || defines_map.count(name) != 0)
				ifdef_fail_level++;
			continue;
		}

		if (ifdef_fail_level > 0) {
			if (tok == "\n")
				output_code.push_back(tok);
			continue;
		}

		if (tok == "`include") {
			skip_spaces();
			std::string fn = next_token(true);
			while (1) {
				size_t pos = fn.find('"');
				if (pos == std::string::npos)
					break;
				if (pos == 0)
					fn = fn.substr(1);
				else
					fn = fn.substr(0, pos) + fn.substr(pos+1);
			}
			FILE *fp = fopen(fn.c_str(), "r");
			if (fp == NULL && fn.size() > 0 && fn[0] != '/' && filename.find('/') != std::string::npos) {
				// if the include file was not found, it is not given with an absolute path, and the
				// currently read file is given with a path, then try again relative to its directory
				std::string fn2 = filename.substr(0, filename.rfind('/')+1) + fn;
				fp = fopen(fn2.c_str(), "r");
			}
			if (fp == NULL && fn.size() > 0 && fn[0] != '/') {
				// if the include file was not found and it is not given with an absolute path, then
				// search it in the include path
				for (auto incdir : include_dirs) {
					std::string fn2 = incdir + '/' + fn;
					fp = fopen(fn2.c_str(), "r");
					if (fp != NULL) break;
				}
			}
			if (fp != NULL) {
				input_file(fp, fn);
				fclose(fp);
			} else
				output_code.push_back("`file_notfound " + fn);
			continue;
		}

		if (tok == "`define") {
			std::string name, value;
			std::map<std::string, int> args;
			skip_spaces();
			name = next_token(true);
			bool here_doc_mode = false;
			int newline_count = 0;
			int state = 0;
			if (skip_spaces() != "")
				state = 3;
			while (!tok.empty()) {
				tok = next_token();
				if (tok == "\"\"\"") {
					here_doc_mode = !here_doc_mode;
					continue;
				}
				if (state == 0 && tok == "(") {
					state = 1;
					skip_spaces();
				} else
				if (state == 1) {
					if (tok == ")")
						state = 2;
					else if (tok != ",") {
						int arg_idx = args.size()+1;
						args[tok] = arg_idx;
					}
					skip_spaces();
				} else {
					if (state != 2)
						state = 3;
					if (tok == "\n") {
						if (here_doc_mode) {
							value += " ";
							newline_count++;
						} else {
							return_char('\n');
							break;
						}
					} else
					if (tok == "\\") {
						char ch = next_char();
						if (ch == '\n') {
							value += " ";
							newline_count++;
						} else {
							value += std::string("\\");
							return_char(ch);
						}
					} else
					if (args.count(tok) > 0)
						value += stringf("`macro_%s_arg%d", name.c_str(), args.at(tok));
					else
						value += tok;
				}
			}
			while (newline_count-- > 0)
				return_char('\n');
			// printf("define: >>%s<< -> >>%s<<\n", name.c_str(), value.c_str());
			defines_map[name] = value;
			if (state == 2)
				defines_with_args.insert(name);
			else
				defines_with_args.erase(name);
			continue;
		}

		if (tok == "`undef") {
			std::string name;
			skip_spaces();
			name = next_token(true);
			// printf("undef: >>%s<<\n", name.c_str());
			defines_map.erase(name);
			defines_with_args.erase(name);
			continue;
		}

		if (tok == "`timescale") {
			skip_spaces();
			while (!tok.empty() && tok != "\n")
				tok = next_token(true);
			if (tok == "\n")
				return_char('\n');
			continue;
		}

		if (tok.size() > 1 && tok[0] == '`' && defines_map.count(tok.substr(1)) > 0) {
			std::string name = tok.substr(1);
			// printf("expand: >>%s<< -> >>%s<<\n", name.c_str(), defines_map[name].c_str());
			std::string skipped_spaces = skip_spaces();
			tok = next_token(false);
			if (tok == "(" && defines_with_args.count(name) > 0) {
				int level = 1;
				std::vector<std::string> args;
				args.push_back(std::string());
				while (1)
				{
					tok = next_token(true);
					if (tok == ")" || tok == "}" || tok == "]")
						level--;
					if (level == 0)
						break;
					if (level == 1 && tok == ",")
						args.push_back(std::string());
					else
						args.back() += tok;
					if (tok == "(" || tok == "{" || tok == "[")
						level++;
				}
				for (size_t i = 0; i < args.size(); i++)
					defines_map[stringf("macro_%s_arg%d", name.c_str(), i+1)] = args[i];
			} else {
				insert_input(tok);
				insert_input(skipped_spaces);
			}
			insert_input(defines_map[name]);
			continue;
		}

		output_code.push_back(tok);
	}

	std::string output;
	for (auto &str : output_code)
		output += str;

	output_code.clear();
	input_buffer.clear();
	input_buffer_charp = 0;

	return output;
}

YOSYS_NAMESPACE_END

<|endoftext|>


<commit_before>//
// This file is part of the Marble Desktop Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2011      Konstantin Oblaukhov <oblaukhov.konstantin@gmail.com>
//

#include "GeoGraphicsScene.h"
#include "GeoDataLatLonAltBox.h"
#include "GeoGraphicsItem.h"
#include "TileId.h"
#include "TileCoordsPyramid.h"
#include "MarbleDebug.h"
#include <QtCore/QMap>

namespace Marble
{

bool zValueLessThan( GeoGraphicsItem* i1, GeoGraphicsItem* i2 )
{
    return i1->zValue() < i2->zValue();
}

int GeoGraphicsScene::s_tileZoomLevel = 14;

class GeoGraphicsScenePrivate
{
public:
    TileId coordToTileId( const GeoDataCoordinates& coord, int popularity ) const
    {
        if ( popularity < 0 ) {
            return TileId();
        }
        int maxLat = 90000000;
        int maxLon = 180000000;
        int lat = coord.latitude( GeoDataCoordinates::Degree ) * 1000000;
        int lon = coord.longitude( GeoDataCoordinates::Degree ) * 1000000;
        int deltaLat, deltaLon;
        int x = 0;
        int y = 0;
        for( int i=0; i<popularity; ++i ) {
            deltaLat = maxLat >> i;
            if( lat < ( maxLat - deltaLat )) {
                y += 1<<(popularity-i-1);
                lat += deltaLat;
            }
            deltaLon = maxLon >> i;
            if( lon >= ( maxLon - deltaLon )) {
                x += 1<<(popularity-i-1);
            } else {
                lon += deltaLon;
            }
        }
        return TileId( "", popularity, x, y );
    }

    QMap<TileId, QList<GeoGraphicsItem*> > m_items;
};

GeoGraphicsScene::GeoGraphicsScene( QObject* parent ): QObject( parent ), d( new GeoGraphicsScenePrivate() )
{

}

GeoGraphicsScene::~GeoGraphicsScene()
{
    delete d;
}

QList< GeoGraphicsItem* > GeoGraphicsScene::items() const
{
    //TODO: insert items
    return QList< GeoGraphicsItem* >();
    //return d->m_items;
}

QList< GeoGraphicsItem* > GeoGraphicsScene::items( const Marble::GeoDataLatLonAltBox& box ) const
{
    QList< GeoGraphicsItem* > result;
    QRect rect;
    qreal north, south, east, west;
    box.boundaries( north, south, east, west );
    TileId key;

    key = d->coordToTileId( GeoDataCoordinates(west, north, 0), s_tileZoomLevel );
    rect.setLeft( key.x() );
    rect.setTop( key.y() );

    key = d->coordToTileId( GeoDataCoordinates(east, south, 0), s_tileZoomLevel );
    rect.setRight( key.x() );
    rect.setBottom( key.y() );

    TileCoordsPyramid pyramid( 0, s_tileZoomLevel );
    pyramid.setBottomLevelCoords( rect );

    for ( int level = pyramid.topLevel(); level <= pyramid.bottomLevel(); ++level ) {
        QRect const coords = pyramid.coords( level );
        int x1, y1, x2, y2;
        coords.getCoords( &x1, &y1, &x2, &y2 );
        for ( int x = x1; x <= x2; ++x ) {
            for ( int y = y1; y <= y2; ++y ) {
                TileId const tileId( "", level, x, y );
                result += d->m_items.value(tileId);
            }
        }
    }
    //TODO: Even quicksort isn't fast enouth...
    qSort( result.begin(), result.end(), zValueLessThan );
    return result;
}

void GeoGraphicsScene::removeItem( GeoGraphicsItem* item )
{
    //TODO: Remove one item
    //d->m_items.removeOne( item );
}

void GeoGraphicsScene::clear()
{
    d->m_items.clear();
}

void GeoGraphicsScene::addIdem( GeoGraphicsItem* item )
{
    // Select zoom level so that the object fit in single tile
    int zoomLevel;
    qreal north, south, east, west;
    item->latLonAltBox().boundaries( north, south, east, west );
    for(zoomLevel = s_tileZoomLevel; zoomLevel >= 0; zoomLevel--)
    {
        if( d->coordToTileId( GeoDataCoordinates(west, north, 0), zoomLevel ) ==
            d->coordToTileId( GeoDataCoordinates(east, south, 0), zoomLevel ) )
            break;
    }
    int tnorth, tsouth, teast, twest;
    TileId key;

    key = d->coordToTileId( GeoDataCoordinates(west, north, 0), zoomLevel );
    twest = key.x();
    tnorth = key.y();

    key = d->coordToTileId( GeoDataCoordinates(east, south, 0), zoomLevel );
    teast = key.x();
    tsouth = key.y();

    for( int i = twest; i <= teast; i++ )
    {
        for( int j = tsouth; j <= tnorth; j++ )
        {
            QList< GeoGraphicsItem* >& tileList = d->m_items[TileId( "", zoomLevel, i, j )];
            QList< GeoGraphicsItem* >::iterator position = qLowerBound( tileList.begin(), tileList.end(), item, zValueLessThan );
            tileList.insert( position, item );
        }
    }
}
};

#include "GeoGraphicsScene.moc"
<commit_msg>New way to build object list in GeoGraphicsScene::items.<commit_after>//
// This file is part of the Marble Desktop Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2011      Konstantin Oblaukhov <oblaukhov.konstantin@gmail.com>
//

#include "GeoGraphicsScene.h"
#include "GeoDataLatLonAltBox.h"
#include "GeoGraphicsItem.h"
#include "TileId.h"
#include "TileCoordsPyramid.h"
#include "MarbleDebug.h"
#include <QtCore/QMap>

namespace Marble
{

bool zValueLessThan( GeoGraphicsItem* i1, GeoGraphicsItem* i2 )
{
    return i1->zValue() < i2->zValue();
}

int GeoGraphicsScene::s_tileZoomLevel = 14;

class GeoGraphicsScenePrivate
{
public:
    TileId coordToTileId( const GeoDataCoordinates& coord, int popularity ) const
    {
        if ( popularity < 0 ) {
            return TileId();
        }
        int maxLat = 90000000;
        int maxLon = 180000000;
        int lat = coord.latitude( GeoDataCoordinates::Degree ) * 1000000;
        int lon = coord.longitude( GeoDataCoordinates::Degree ) * 1000000;
        int deltaLat, deltaLon;
        int x = 0;
        int y = 0;
        for( int i=0; i<popularity; ++i ) {
            deltaLat = maxLat >> i;
            if( lat < ( maxLat - deltaLat )) {
                y += 1<<(popularity-i-1);
                lat += deltaLat;
            }
            deltaLon = maxLon >> i;
            if( lon >= ( maxLon - deltaLon )) {
                x += 1<<(popularity-i-1);
            } else {
                lon += deltaLon;
            }
        }
        return TileId( "", popularity, x, y );
    }

    QMap<TileId, QList<GeoGraphicsItem*> > m_items;
};

GeoGraphicsScene::GeoGraphicsScene( QObject* parent ): QObject( parent ), d( new GeoGraphicsScenePrivate() )
{

}

GeoGraphicsScene::~GeoGraphicsScene()
{
    delete d;
}

QList< GeoGraphicsItem* > GeoGraphicsScene::items() const
{
    //TODO: insert items
    return QList< GeoGraphicsItem* >();
    //return d->m_items;
}

QList< GeoGraphicsItem* > GeoGraphicsScene::items( const Marble::GeoDataLatLonAltBox& box ) const
{
    QList< GeoGraphicsItem* > result;
    QRect rect;
    qreal north, south, east, west;
    box.boundaries( north, south, east, west );
    TileId key;

    key = d->coordToTileId( GeoDataCoordinates(west, north, 0), s_tileZoomLevel );
    rect.setLeft( key.x() );
    rect.setTop( key.y() );

    key = d->coordToTileId( GeoDataCoordinates(east, south, 0), s_tileZoomLevel );
    rect.setRight( key.x() );
    rect.setBottom( key.y() );

    TileCoordsPyramid pyramid( 0, s_tileZoomLevel );
    pyramid.setBottomLevelCoords( rect );

    for ( int level = pyramid.topLevel(); level <= pyramid.bottomLevel(); ++level ) {
        QRect const coords = pyramid.coords( level );
        int x1, y1, x2, y2;
        coords.getCoords( &x1, &y1, &x2, &y2 );
        for ( int x = x1; x <= x2; ++x ) {
            for ( int y = y1; y <= y2; ++y ) {
                TileId const tileId( "", level, x, y );
                const QList< GeoGraphicsItem* > &objects = d->m_items.value(tileId);
                QList< GeoGraphicsItem* >::iterator before = result.begin();
                QList< GeoGraphicsItem* >::const_iterator currentItem = objects.constBegin();
                while( currentItem != objects.end() )
                {
                    while( ( currentItem != objects.end() )
                      && ( ( before == result.end() ) || ( (*currentItem)->zValue() < (*before)->zValue() ) ) )
                    {
                        before = result.insert( before, *currentItem );
                        currentItem++;
                    }
                    if ( before != result.end() )
                        before++;
                }
            }
        }
    }
    return result;
}

void GeoGraphicsScene::removeItem( GeoGraphicsItem* item )
{
    //TODO: Remove one item
    //d->m_items.removeOne( item );
}

void GeoGraphicsScene::clear()
{
    d->m_items.clear();
}

void GeoGraphicsScene::addIdem( GeoGraphicsItem* item )
{
    // Select zoom level so that the object fit in single tile
    int zoomLevel;
    qreal north, south, east, west;
    item->latLonAltBox().boundaries( north, south, east, west );
    for(zoomLevel = s_tileZoomLevel; zoomLevel >= 0; zoomLevel--)
    {
        if( d->coordToTileId( GeoDataCoordinates(west, north, 0), zoomLevel ) ==
            d->coordToTileId( GeoDataCoordinates(east, south, 0), zoomLevel ) )
            break;
    }
    int tnorth, tsouth, teast, twest;
    TileId key;

    key = d->coordToTileId( GeoDataCoordinates(west, north, 0), zoomLevel );
    twest = key.x();
    tnorth = key.y();

    key = d->coordToTileId( GeoDataCoordinates(east, south, 0), zoomLevel );
    teast = key.x();
    tsouth = key.y();

    for( int i = twest; i <= teast; i++ )
    {
        for( int j = tsouth; j <= tnorth; j++ )
        {
            QList< GeoGraphicsItem* >& tileList = d->m_items[TileId( "", zoomLevel, i, j )];
            QList< GeoGraphicsItem* >::iterator position = qLowerBound( tileList.begin(), tileList.end(), item, zValueLessThan );
            tileList.insert( position, item );
        }
    }
}
};

#include "GeoGraphicsScene.moc"
<|endoftext|>


<commit_before>#include <cstdio>
#include <cwctype>
#include <algorithm>
#include "../vendor/hunspell/src/hunspell/hunspell.hxx"
#include "../vendor/hunspell/src/hunspell/csutil.hxx"
#include "spellchecker_hunspell.h"

namespace spellchecker {

HunspellSpellchecker::HunspellSpellchecker() : hunspell(NULL) { }
HunspellSpellchecker::~HunspellSpellchecker() {
  if (hunspell) {
    delete hunspell;
  }
}

bool HunspellSpellchecker::SetDictionary(const std::string& language, const std::string& dirname) {
  if (hunspell) {
    delete hunspell;
    hunspell = NULL;
  }

  // NB: Hunspell uses underscore to separate language and locale, and Win8 uses
  // dash - if they use the wrong one, just silently replace it for them
  std::string lang = language;
  std::replace(lang.begin(), lang.end(), '-', '_');

  std::string affixpath = dirname + "/" + lang + ".aff";
  std::string dpath = dirname + "/" + lang + ".dic";

  // TODO: This code is almost certainly jacked on Win32 for non-ASCII paths
  FILE* handle = fopen(dpath.c_str(), "r");
  if (!handle) {
    return false;
  }
  fclose(handle);

  hunspell = new Hunspell(affixpath.c_str(), dpath.c_str());
  return true;
}

std::vector<std::string> HunspellSpellchecker::GetAvailableDictionaries(const std::string& path) {
  return std::vector<std::string>();
}

bool HunspellSpellchecker::IsMisspelled(const std::string& word) {
  if (!hunspell) {
    return false;
  }
  return hunspell->spell(word.c_str()) == 0;
}

std::vector<MisspelledRange> HunspellSpellchecker::CheckSpelling(const uint16_t *utf16_text, size_t utf16_length) {
  std::vector<MisspelledRange> result;
  return result;
}

void HunspellSpellchecker::Add(const std::string& word) {
  if (hunspell) {
    hunspell->add(word.c_str());
  }
}

std::vector<std::string> HunspellSpellchecker::GetCorrectionsForMisspelling(const std::string& word) {
  std::vector<std::string> corrections;

  if (hunspell) {
    char** slist;
    int size = hunspell->suggest(&slist, word.c_str());

    corrections.reserve(size);
    for (int i = 0; i < size; ++i) {
      corrections.push_back(slist[i]);
    }

    hunspell->free_list(&slist, size);
  }
  return corrections;
}

}  // namespace spellchecker
<commit_msg>Add real hunspell impl for bulk spell-checking function<commit_after>#include <cstdio>
#include <cwctype>
#include <algorithm>
#include "../vendor/hunspell/src/hunspell/hunspell.hxx"
#include "../vendor/hunspell/src/hunspell/csutil.hxx"
#include "spellchecker_hunspell.h"

namespace spellchecker {

HunspellSpellchecker::HunspellSpellchecker() : hunspell(NULL) { }
HunspellSpellchecker::~HunspellSpellchecker() {
  if (hunspell) {
    delete hunspell;
  }
}

bool HunspellSpellchecker::SetDictionary(const std::string& language, const std::string& dirname) {
  if (hunspell) {
    delete hunspell;
    hunspell = NULL;
  }

  // NB: Hunspell uses underscore to separate language and locale, and Win8 uses
  // dash - if they use the wrong one, just silently replace it for them
  std::string lang = language;
  std::replace(lang.begin(), lang.end(), '-', '_');

  std::string affixpath = dirname + "/" + lang + ".aff";
  std::string dpath = dirname + "/" + lang + ".dic";

  // TODO: This code is almost certainly jacked on Win32 for non-ASCII paths
  FILE* handle = fopen(dpath.c_str(), "r");
  if (!handle) {
    return false;
  }
  fclose(handle);

  hunspell = new Hunspell(affixpath.c_str(), dpath.c_str());
  return true;
}

std::vector<std::string> HunspellSpellchecker::GetAvailableDictionaries(const std::string& path) {
  return std::vector<std::string>();
}

bool HunspellSpellchecker::IsMisspelled(const std::string& word) {
  if (!hunspell) {
    return false;
  }
  return hunspell->spell(word.c_str()) == 0;
}

std::vector<MisspelledRange> HunspellSpellchecker::CheckSpelling(const uint16_t *utf16_text, size_t utf16_length) {
  std::vector<MisspelledRange> result;

  if (!hunspell) {
    return result;
  }

  std::vector<char> utf8_buffer(256);
  char *utf8_word = utf8_buffer.data();

  bool within_word = false;
  size_t word_start = 0;
  for (size_t i = 0; i <= utf16_length; i++) {
    bool is_alpha = i < utf16_length && std::iswalpha(utf16_text[i]);

    if (within_word) {
      if (!is_alpha) {
        within_word = false;
        const w_char *utf16_word = reinterpret_cast<const w_char *>(utf16_text + word_start);
        u16_u8(utf8_word, utf8_buffer.size(), utf16_word, i - word_start);

        if (hunspell->spell(utf8_word) == 0) {
          MisspelledRange range;
          range.start = word_start;
          range.end = i;
          result.push_back(range);
        }
      }
    } else if (is_alpha) {
      word_start = i;
      within_word = true;
    }
  }

  return result;
}

void HunspellSpellchecker::Add(const std::string& word) {
  if (hunspell) {
    hunspell->add(word.c_str());
  }
}

std::vector<std::string> HunspellSpellchecker::GetCorrectionsForMisspelling(const std::string& word) {
  std::vector<std::string> corrections;

  if (hunspell) {
    char** slist;
    int size = hunspell->suggest(&slist, word.c_str());

    corrections.reserve(size);
    for (int i = 0; i < size; ++i) {
      corrections.push_back(slist[i]);
    }

    hunspell->free_list(&slist, size);
  }
  return corrections;
}

}  // namespace spellchecker
<|endoftext|>


<commit_before>/*
 * GameKeeper Framework
 *
 * Copyright (C) 2013 Karol Herbst <gamekeeper@karolherbst.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "pch.h"

#include <algorithm>
#include <chrono>
#include <iostream>
#include <iterator>
#include <sstream>
#include <vector>

#include <std_compat/thread>

#include <gamekeeper/core/curlfiledownloader.h>
#include <gamekeeper/core/logger.h>
#include <gamekeeper/core/loggerFactory.h>
#include <gamekeeper/core/loggerStream.h>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>

#include <curl/curl.h>

namespace algo = boost::algorithm;
namespace fs = boost::filesystem;

GAMEKEEPER_NAMESPACE_START(core)

class PRIVATE_API CurlFileDownloadInfo
{
public:
	PRIVATE_API CurlFileDownloadInfo(const FileDownloader::DownloadCallback * _func, uint64_t _maxBufferSize, const fs::path & _path)
	:	maxBufferSize(_maxBufferSize),
		func(_func),
		path(_path){}

	PRIVATE_API uint64_t bytesDownloaded();
	PRIVATE_API bool addData(void * const buffer, uint64_t bytes);
	PRIVATE_API void callback();

private:
	const uint64_t maxBufferSize;
	const FileDownloader::DownloadCallback * func;
	const fs::path path;
	std::vector<gkbyte_t> dataBuffer;
	uint64_t _bytesDownloaded = 0;
};

uint64_t
CurlFileDownloadInfo::bytesDownloaded()
{
	return this->_bytesDownloaded;
}

bool
CurlFileDownloadInfo::addData(void * const buffer, uint64_t bytes)
{
	gkbyte_t * newData = static_cast<gkbyte_t *>(buffer);
	// check amount of downloaded bytes to know if we use a file or buffer stream
	if(this->bytesDownloaded() <= (this->maxBufferSize * 1024))
	{
		// the buffer might be too small for the new data, so check it before
		if((this->dataBuffer.size() + bytes) > (this->maxBufferSize * 1024))
		{
			// first create directories
			if(!fs::exists(this->path.parent_path()))
			{
				fs::create_directories(this->path.parent_path());
			}
			fs::basic_ofstream<gkbyte_t> ofs(this->path, std::ios_base::trunc | std::ios_base::binary);
			ofs.write(this->dataBuffer.data(), this->dataBuffer.size());
			ofs.write(newData, bytes);
			ofs.close();
			// clear internal buffer
			this->dataBuffer.clear();
		}
		else
		{
			this->dataBuffer.insert(this->dataBuffer.end(), newData, &newData[bytes]);
		}
	}
	else
	{
		fs::basic_ofstream<gkbyte_t> ofs(this->path, std::ios_base::app | std::ios_base::binary);
		ofs.write(newData, bytes);
	}
	this->_bytesDownloaded += bytes;
	return true;
}

void
CurlFileDownloadInfo::callback()
{
	if(bytesDownloaded() <= (this->maxBufferSize * 1024))
	{
		namespace bio = boost::iostreams;
		bio::stream<bio::basic_array_source<gkbyte_t>> stream(this->dataBuffer.data(), this->dataBuffer.size());
		stream.peek();
		(*this->func)(stream);
	}
	else
	{
		fs::basic_ifstream<gkbyte_t> ifs(this->path);
		(*this->func)(ifs);
		ifs.close();
		fs::remove(this->path);
	}
}

class PRIVATE_API CURLPrivateData
{
public:
	PRIVATE_API CURLPrivateData(const char * const url, const std::string & userAgent,
	                            std::shared_ptr<PropertyResolver>);
	PRIVATE_API ~CURLPrivateData();

	CURL * handle;
	std::string postData;
	CurlFileDownloadInfo * downloadInfo = nullptr;
	uint16_t resolveFailed = 0;
	uint16_t connectFailed = 0;
};

CURLPrivateData::CURLPrivateData(const char * const url, const std::string & userAgent,
                                 std::shared_ptr<PropertyResolver> pr)
:	handle(curl_easy_init())
{
	curl_easy_setopt(this->handle, CURLOPT_URL, url);
	curl_easy_setopt(this->handle, CURLOPT_NOSIGNAL, 1);
	curl_easy_setopt(this->handle, CURLOPT_USERAGENT, userAgent.c_str());
	curl_easy_setopt(this->handle, CURLOPT_CONNECTTIMEOUT_MS, pr->get<uint16_t>("network.connection.timeout"));
}

CURLPrivateData::~CURLPrivateData()
{
	if(this->downloadInfo != nullptr)
	{
		delete downloadInfo;
	}
	curl_easy_cleanup(this->handle);
}

static uint64_t
curlFileDownloadCallback(void * const buffer, size_t size, size_t nrMem,
                         CURLPrivateData * data)
{
	uint64_t sizeInBytes = size * nrMem;
	CurlFileDownloadInfo * info = data->downloadInfo;
	if(!info->addData(buffer, sizeInBytes))
	{
		return -1;
	}
	return sizeInBytes;
}

static uint64_t
emptyCurlFileDownloadCallback(void * const, size_t size, size_t nrMem, void *)
{
	return size * nrMem;
}

static std::string
buildUserAgentString(const boost::any & configValue)
{
	if(configValue.empty())
	{
		return std::string("GameKeeper/0.1 libcurl/") + curl_version_info(CURLVERSION_NOW)->version;
	}
	return boost::any_cast<std::string>(configValue);
}

const std::unordered_set<std::string>
CurlFileDownloader::supportedProtocols = {"http", "https", "ftp", "ftps", "sftp"};

CurlFileDownloader::CurlFileDownloader(std::shared_ptr<LoggerFactory> loggerFactory,
                                       std::shared_ptr<PropertyResolver> _propertyResolver,
                                       std::shared_ptr<OSPaths> _ospaths)
:	propertyResolver(_propertyResolver),
	ospaths(_ospaths),
	logger(loggerFactory->getComponentLogger("IO.curl")),
	userAgent(buildUserAgentString(_propertyResolver->get("network.user_agent")))
{
	logger << LogLevel::Debug << "init curl with user-agent: " << this->userAgent << endl;
	curl_global_init(CURL_GLOBAL_SSL);
}

CurlFileDownloader::~CurlFileDownloader()
{
	curl_global_cleanup();
}

void
CurlFileDownloader::handleFileDownload(CURLPrivateData & curl, FileDownloader::DownloadCallback * func, const char * const url)
{
	boost::filesystem::path downloadPath = this->resolveDownloadPath(url);
	this->logger << LogLevel::Debug << "try to download file from: " << url << " at: " << downloadPath.string() << endl;
	curl.downloadInfo =
		new CurlFileDownloadInfo(func, this->propertyResolver->get<uint32_t>("network.download.max_buffer_size"),
		                         downloadPath);
	curl_easy_setopt(curl.handle, CURLOPT_WRITEFUNCTION, &curlFileDownloadCallback);
	curl_easy_setopt(curl.handle, CURLOPT_WRITEDATA, &curl);
	this->performCurl(curl);
	curl.downloadInfo->callback();
}

static void
addCookiesToCurl(const HttpFileDownloader::CookieBuket& cookies, CURLPrivateData & curl)
{
	if(!cookies.empty())
	{
		std::ostringstream cookieLineBuilder;
		for (const HttpFileDownloader::Cookie cookie : cookies)
		{
			cookieLineBuilder << cookie.first << '=' << cookie.second << ";";
		}
		std::string cookieLine = cookieLineBuilder.str();
		curl_easy_setopt(curl.handle, CURLOPT_COOKIE, cookieLine.c_str());
	}
}

static HttpFileDownloader::CookieBuket
getCookies(CURLPrivateData & curl)
{
	struct curl_slist * list;
	HttpFileDownloader::CookieBuket result;
	curl_easy_getinfo(curl.handle, CURLINFO_COOKIELIST, &list);

	while(list != nullptr)
	{
		std::vector<std::string> strings;
		boost::split(strings, list->data, boost::is_any_of("\t"));
		result[strings[5]] = strings[6];
		list = list->next;
	}

	curl_slist_free_all(list);
	return result;
}

static void
addFormToCurl(const HttpFileDownloader::Form& form, CURLPrivateData & curl)
{
	if(!form.empty())
	{
		std::ostringstream cookieLineBuilder;
		for (const HttpFileDownloader::FormField formField : form)
		{
			cookieLineBuilder << formField.first << '=' << formField.second << '&';
		}
		curl.postData = cookieLineBuilder.str();
		curl_easy_setopt(curl.handle, CURLOPT_POSTFIELDS, curl.postData.c_str());
	}
}

bool
CurlFileDownloader::supportsProtocol(const char * const protocolName)
{
	return supportedProtocols.find(protocolName) != supportedProtocols.end();
}

void
CurlFileDownloader::downloadFile(const char * const url, DownloadCallback callback)
{
	CURLPrivateData curl(url, this->userAgent, this->propertyResolver);
	this->handleFileDownload(curl, &callback, url);
}

void
CurlFileDownloader::downloadFileWithCookies(const char * const url, DownloadCallback callback,
                                            const CookieBuket& cookies)
{
	CURLPrivateData curl(url, this->userAgent, this->propertyResolver);
	addCookiesToCurl(cookies, curl);
	this->handleFileDownload(curl, &callback, url);
}

CurlFileDownloader::CookieBuket
CurlFileDownloader::doPostRequestForCookies(const char * const url, const Form& form)
{
	this->logger << LogLevel::Debug << "try to fetch cookies at: " << url << endl;
	CURLPrivateData curl(url, this->userAgent, this->propertyResolver);
	curl_easy_setopt(curl.handle, CURLOPT_WRITEFUNCTION, &emptyCurlFileDownloadCallback);
	curl_easy_setopt(curl.handle, CURLOPT_COOKIEJAR, nullptr);

	addFormToCurl(form, curl);

	this->performCurl(curl);

	CurlFileDownloader::CookieBuket result = getCookies(curl);

	return result;
}

void
CurlFileDownloader::performCurl(CURLPrivateData & curl, uint32_t timeout)
{
	if(timeout > 0)
	{
		std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
	}

	CURLcode code = curl_easy_perform(curl.handle);
	switch (code)
	{
		case CURLE_OK: // 0
			// everything okay
			this->logger << LogLevel::Trace << "CURL returned without errors" << endl;
			break;
		case CURLE_COULDNT_RESOLVE_HOST: // 6
			curl.resolveFailed++;
			if(curl.resolveFailed < this->propertyResolver->get<uint16_t>("network.resolve.retries"))
			{
				this->logger << LogLevel::Warn << "CURL couldn't resolve host, retrying" << endl;
				this->performCurl(curl, this->propertyResolver->get<uint16_t>("network.time_between_retries"));
			}
			else
			{
				this->logger << LogLevel::Error << "CURL couldn't resolve host after " << curl.resolveFailed << " retries" << endl;
			}
			break;
		case CURLE_COULDNT_CONNECT: // 7
			curl.connectFailed++;
			if(curl.connectFailed < this->propertyResolver->get<uint16_t>("network.connection.retries"))
			{
				this->logger << LogLevel::Warn << "CURL couldn't connect to host, retrying" << endl;
				this->performCurl(curl, this->propertyResolver->get<uint16_t>("network.time_between_retries"));
			}
			else
			{
				this->logger << LogLevel::Error << "CURL couldn't connect to host after " << curl.connectFailed << " retries" << endl;
			}
			break;
		default:
			// unhandled error
			this->logger << LogLevel::Fatal << "CURL error \"" << curl_easy_strerror(code) << "\" (" << code <<
				") unhandled, please report a bug" << endl;
			break;
	}
}

boost::filesystem::path
CurlFileDownloader::resolveDownloadPath(const char * const url)
{
	std::string uri = url;
	// frist cut the protocoll
	size_t pos = uri.find("://");
	uri.erase(0, pos + 3);
	// now replace some unsupported characters
	algo::replace_all(uri, ":", "_");
	return this->ospaths->getCacheFile(std::string("downloads/" + uri));
}

GAMEKEEPER_NAMESPACE_END(core)
<commit_msg>core/curl: also add ssl and libz information in the generated user-agent string<commit_after>/*
 * GameKeeper Framework
 *
 * Copyright (C) 2013 Karol Herbst <gamekeeper@karolherbst.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "pch.h"

#include <algorithm>
#include <chrono>
#include <iostream>
#include <iterator>
#include <sstream>
#include <vector>

#include <std_compat/thread>

#include <gamekeeper/core/curlfiledownloader.h>
#include <gamekeeper/core/logger.h>
#include <gamekeeper/core/loggerFactory.h>
#include <gamekeeper/core/loggerStream.h>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>

#include <curl/curl.h>

namespace algo = boost::algorithm;
namespace fs = boost::filesystem;

GAMEKEEPER_NAMESPACE_START(core)

class PRIVATE_API CurlFileDownloadInfo
{
public:
	PRIVATE_API CurlFileDownloadInfo(const FileDownloader::DownloadCallback * _func, uint64_t _maxBufferSize, const fs::path & _path)
	:	maxBufferSize(_maxBufferSize),
		func(_func),
		path(_path){}

	PRIVATE_API uint64_t bytesDownloaded();
	PRIVATE_API bool addData(void * const buffer, uint64_t bytes);
	PRIVATE_API void callback();

private:
	const uint64_t maxBufferSize;
	const FileDownloader::DownloadCallback * func;
	const fs::path path;
	std::vector<gkbyte_t> dataBuffer;
	uint64_t _bytesDownloaded = 0;
};

uint64_t
CurlFileDownloadInfo::bytesDownloaded()
{
	return this->_bytesDownloaded;
}

bool
CurlFileDownloadInfo::addData(void * const buffer, uint64_t bytes)
{
	gkbyte_t * newData = static_cast<gkbyte_t *>(buffer);
	// check amount of downloaded bytes to know if we use a file or buffer stream
	if(this->bytesDownloaded() <= (this->maxBufferSize * 1024))
	{
		// the buffer might be too small for the new data, so check it before
		if((this->dataBuffer.size() + bytes) > (this->maxBufferSize * 1024))
		{
			// first create directories
			if(!fs::exists(this->path.parent_path()))
			{
				fs::create_directories(this->path.parent_path());
			}
			fs::basic_ofstream<gkbyte_t> ofs(this->path, std::ios_base::trunc | std::ios_base::binary);
			ofs.write(this->dataBuffer.data(), this->dataBuffer.size());
			ofs.write(newData, bytes);
			ofs.close();
			// clear internal buffer
			this->dataBuffer.clear();
		}
		else
		{
			this->dataBuffer.insert(this->dataBuffer.end(), newData, &newData[bytes]);
		}
	}
	else
	{
		fs::basic_ofstream<gkbyte_t> ofs(this->path, std::ios_base::app | std::ios_base::binary);
		ofs.write(newData, bytes);
	}
	this->_bytesDownloaded += bytes;
	return true;
}

void
CurlFileDownloadInfo::callback()
{
	if(bytesDownloaded() <= (this->maxBufferSize * 1024))
	{
		namespace bio = boost::iostreams;
		bio::stream<bio::basic_array_source<gkbyte_t>> stream(this->dataBuffer.data(), this->dataBuffer.size());
		stream.peek();
		(*this->func)(stream);
	}
	else
	{
		fs::basic_ifstream<gkbyte_t> ifs(this->path);
		(*this->func)(ifs);
		ifs.close();
		fs::remove(this->path);
	}
}

class PRIVATE_API CURLPrivateData
{
public:
	PRIVATE_API CURLPrivateData(const char * const url, const std::string & userAgent,
	                            std::shared_ptr<PropertyResolver>);
	PRIVATE_API ~CURLPrivateData();

	CURL * handle;
	std::string postData;
	CurlFileDownloadInfo * downloadInfo = nullptr;
	uint16_t resolveFailed = 0;
	uint16_t connectFailed = 0;
};

CURLPrivateData::CURLPrivateData(const char * const url, const std::string & userAgent,
                                 std::shared_ptr<PropertyResolver> pr)
:	handle(curl_easy_init())
{
	curl_easy_setopt(this->handle, CURLOPT_URL, url);
	curl_easy_setopt(this->handle, CURLOPT_NOSIGNAL, 1);
	curl_easy_setopt(this->handle, CURLOPT_USERAGENT, userAgent.c_str());
	curl_easy_setopt(this->handle, CURLOPT_CONNECTTIMEOUT_MS, pr->get<uint16_t>("network.connection.timeout"));
}

CURLPrivateData::~CURLPrivateData()
{
	if(this->downloadInfo != nullptr)
	{
		delete downloadInfo;
	}
	curl_easy_cleanup(this->handle);
}

static uint64_t
curlFileDownloadCallback(void * const buffer, size_t size, size_t nrMem,
                         CURLPrivateData * data)
{
	uint64_t sizeInBytes = size * nrMem;
	CurlFileDownloadInfo * info = data->downloadInfo;
	if(!info->addData(buffer, sizeInBytes))
	{
		return -1;
	}
	return sizeInBytes;
}

static uint64_t
emptyCurlFileDownloadCallback(void * const, size_t size, size_t nrMem, void *)
{
	return size * nrMem;
}

static std::string
buildUserAgentString(const boost::any & configValue)
{
	if(configValue.empty())
	{
		curl_version_info_data * data = curl_version_info(CURLVERSION_NOW);
		return std::string("GameKeeper/0.1 libcurl/") + data->version + ' ' + data->ssl_version +
			" zlib/" + data->libz_version;
	}
	return boost::any_cast<std::string>(configValue);
}

const std::unordered_set<std::string>
CurlFileDownloader::supportedProtocols = {"http", "https", "ftp", "ftps", "sftp"};

CurlFileDownloader::CurlFileDownloader(std::shared_ptr<LoggerFactory> loggerFactory,
                                       std::shared_ptr<PropertyResolver> _propertyResolver,
                                       std::shared_ptr<OSPaths> _ospaths)
:	propertyResolver(_propertyResolver),
	ospaths(_ospaths),
	logger(loggerFactory->getComponentLogger("IO.curl")),
	userAgent(buildUserAgentString(_propertyResolver->get("network.user_agent")))
{
	logger << LogLevel::Debug << "init curl with user-agent: " << this->userAgent << endl;
	curl_global_init(CURL_GLOBAL_SSL);
}

CurlFileDownloader::~CurlFileDownloader()
{
	curl_global_cleanup();
}

void
CurlFileDownloader::handleFileDownload(CURLPrivateData & curl, FileDownloader::DownloadCallback * func, const char * const url)
{
	boost::filesystem::path downloadPath = this->resolveDownloadPath(url);
	this->logger << LogLevel::Debug << "try to download file from: " << url << " at: " << downloadPath.string() << endl;
	curl.downloadInfo =
		new CurlFileDownloadInfo(func, this->propertyResolver->get<uint32_t>("network.download.max_buffer_size"),
		                         downloadPath);
	curl_easy_setopt(curl.handle, CURLOPT_WRITEFUNCTION, &curlFileDownloadCallback);
	curl_easy_setopt(curl.handle, CURLOPT_WRITEDATA, &curl);
	this->performCurl(curl);
	curl.downloadInfo->callback();
}

static void
addCookiesToCurl(const HttpFileDownloader::CookieBuket& cookies, CURLPrivateData & curl)
{
	if(!cookies.empty())
	{
		std::ostringstream cookieLineBuilder;
		for (const HttpFileDownloader::Cookie cookie : cookies)
		{
			cookieLineBuilder << cookie.first << '=' << cookie.second << ";";
		}
		std::string cookieLine = cookieLineBuilder.str();
		curl_easy_setopt(curl.handle, CURLOPT_COOKIE, cookieLine.c_str());
	}
}

static HttpFileDownloader::CookieBuket
getCookies(CURLPrivateData & curl)
{
	struct curl_slist * list;
	HttpFileDownloader::CookieBuket result;
	curl_easy_getinfo(curl.handle, CURLINFO_COOKIELIST, &list);

	while(list != nullptr)
	{
		std::vector<std::string> strings;
		boost::split(strings, list->data, boost::is_any_of("\t"));
		result[strings[5]] = strings[6];
		list = list->next;
	}

	curl_slist_free_all(list);
	return result;
}

static void
addFormToCurl(const HttpFileDownloader::Form& form, CURLPrivateData & curl)
{
	if(!form.empty())
	{
		std::ostringstream cookieLineBuilder;
		for (const HttpFileDownloader::FormField formField : form)
		{
			cookieLineBuilder << formField.first << '=' << formField.second << '&';
		}
		curl.postData = cookieLineBuilder.str();
		curl_easy_setopt(curl.handle, CURLOPT_POSTFIELDS, curl.postData.c_str());
	}
}

bool
CurlFileDownloader::supportsProtocol(const char * const protocolName)
{
	return supportedProtocols.find(protocolName) != supportedProtocols.end();
}

void
CurlFileDownloader::downloadFile(const char * const url, DownloadCallback callback)
{
	CURLPrivateData curl(url, this->userAgent, this->propertyResolver);
	this->handleFileDownload(curl, &callback, url);
}

void
CurlFileDownloader::downloadFileWithCookies(const char * const url, DownloadCallback callback,
                                            const CookieBuket& cookies)
{
	CURLPrivateData curl(url, this->userAgent, this->propertyResolver);
	addCookiesToCurl(cookies, curl);
	this->handleFileDownload(curl, &callback, url);
}

CurlFileDownloader::CookieBuket
CurlFileDownloader::doPostRequestForCookies(const char * const url, const Form& form)
{
	this->logger << LogLevel::Debug << "try to fetch cookies at: " << url << endl;
	CURLPrivateData curl(url, this->userAgent, this->propertyResolver);
	curl_easy_setopt(curl.handle, CURLOPT_WRITEFUNCTION, &emptyCurlFileDownloadCallback);
	curl_easy_setopt(curl.handle, CURLOPT_COOKIEJAR, nullptr);

	addFormToCurl(form, curl);

	this->performCurl(curl);

	CurlFileDownloader::CookieBuket result = getCookies(curl);

	return result;
}

void
CurlFileDownloader::performCurl(CURLPrivateData & curl, uint32_t timeout)
{
	if(timeout > 0)
	{
		std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
	}

	CURLcode code = curl_easy_perform(curl.handle);
	switch (code)
	{
		case CURLE_OK: // 0
			// everything okay
			this->logger << LogLevel::Trace << "CURL returned without errors" << endl;
			break;
		case CURLE_COULDNT_RESOLVE_HOST: // 6
			curl.resolveFailed++;
			if(curl.resolveFailed < this->propertyResolver->get<uint16_t>("network.resolve.retries"))
			{
				this->logger << LogLevel::Warn << "CURL couldn't resolve host, retrying" << endl;
				this->performCurl(curl, this->propertyResolver->get<uint16_t>("network.time_between_retries"));
			}
			else
			{
				this->logger << LogLevel::Error << "CURL couldn't resolve host after " << curl.resolveFailed << " retries" << endl;
			}
			break;
		case CURLE_COULDNT_CONNECT: // 7
			curl.connectFailed++;
			if(curl.connectFailed < this->propertyResolver->get<uint16_t>("network.connection.retries"))
			{
				this->logger << LogLevel::Warn << "CURL couldn't connect to host, retrying" << endl;
				this->performCurl(curl, this->propertyResolver->get<uint16_t>("network.time_between_retries"));
			}
			else
			{
				this->logger << LogLevel::Error << "CURL couldn't connect to host after " << curl.connectFailed << " retries" << endl;
			}
			break;
		default:
			// unhandled error
			this->logger << LogLevel::Fatal << "CURL error \"" << curl_easy_strerror(code) << "\" (" << code <<
				") unhandled, please report a bug" << endl;
			break;
	}
}

boost::filesystem::path
CurlFileDownloader::resolveDownloadPath(const char * const url)
{
	std::string uri = url;
	// frist cut the protocoll
	size_t pos = uri.find("://");
	uri.erase(0, pos + 3);
	// now replace some unsupported characters
	algo::replace_all(uri, ":", "_");
	return this->ospaths->getCacheFile(std::string("downloads/" + uri));
}

GAMEKEEPER_NAMESPACE_END(core)
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2016 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE 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 <inviwo/core/util/sharedlibrary.h>
#include <inviwo/core/util/filesystem.h>
#include <inviwo/core/util/stringconversion.h> // splitString
#include <codecvt>
#include <locale>

#if WIN32
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <dlfcn.h>
#endif

namespace inviwo {

SharedLibrary::SharedLibrary(std::string filePath)
    : filePath_(filePath)
{

#if WIN32

    // Search for dlls in directories specified by the path environment variable
    // Need to be done since we are using a non-standard call to LoadLibrary
    static auto addDirectoriesInPath = []() { // Lambda executed once
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        const char* environmentPath = std::getenv("PATH");
        if (environmentPath &&
            GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "AddDllDirectory")) {
            auto elems = splitString(std::string(environmentPath), ';');
            for (auto path : elems) {
                std::wstring dd;

                //std::string narrow = converter.to_bytes(wide_utf16_source_string);
                std::wstring wide = converter.from_bytes(path);
                AddDllDirectory(converter.from_bytes(path).c_str());
            }
            return true;
        }
        else {
            return false;
        }
    }();

    // Load library and search for dependencies in
    // 1. The directory that contains the DLL (LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR).
    // 2. Paths explicitly added with the AddDllDirectory function (LOAD_LIBRARY_SEARCH_USER_DIRS)
    // or the SetDllDirectory function. If more than one path has been added, the order in which the
    // paths are searched is unspecified.
    // 3. The System directory (LOAD_LIBRARY_SEARCH_SYSTEM32)
    //
    // Note 1: The directory containing the application executable is not searched filePath is in
    // that directory. This enables us to use a temporary directory when loading dlls and thereby
    // allow the original ones to be overwritten while the application is running.
    // Note 2: LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR and LOAD_LIBRARY_SEARCH_USER_DIRS requires KB2533623
    // to be installed.
    // Note 3: Not supported on Windows XP and Server 2003
    if (GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "AddDllDirectory")) {
        handle_ = LoadLibraryExA(filePath.c_str(), nullptr, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS);
    } else {
        // LOAD_LIBRARY_SEARCH_* flags are not supported
        // Fall back to LoadLibrary
        handle_ = LoadLibraryA(filePath.c_str());
    }

    if (!handle_) {
        auto error = GetLastError();
        std::ostringstream errorStream;
        LPVOID errorText;

        auto outputSize = FormatMessage(
            // use system message tables to retrieve error text
            FORMAT_MESSAGE_FROM_SYSTEM
            // allocate buffer on local heap for error text
            | FORMAT_MESSAGE_ALLOCATE_BUFFER
            // Important! will fail otherwise, since we're not
            // (and CANNOT) pass insertion parameters
            | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            error,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPTSTR)&errorText,
            0, NULL);
        if (errorText != nullptr) {
            std::string errorString(static_cast<const char *>(errorText), outputSize + 1);
            errorStream << errorString;
            //errorStream << static_cast<const char *>(errorText);
            // release memory allocated by FormatMessage()
            LocalFree(errorText);
        }

        throw Exception("Failed to load library: " + filePath + "\n Error: " + errorStream.str());
    }
#else
    handle_ = dlopen(filePath.c_str(), RTLD_NOW | RTLD_GLOBAL);
    if (!handle_) {
        throw Exception("Failed to load library: " + filePath);
    }
#endif

}
SharedLibrary::~SharedLibrary() {
#if WIN32
    FreeLibrary(handle_);
#else
    dlclose(handle_);
#endif
}

void* SharedLibrary::findSymbol(std::string name) {
#if WIN32
    return GetProcAddress(handle_, "createModule");
#else
    return dlsym(handle_, name.c_str());
#endif
}

} // namespace

<commit_msg>Core: inviwo/inviwo-dev#1364 Added minor comments in SharedLibrary and removed RTLD_NOW since, as far as I know, we do not need it.<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2016 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE 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 <inviwo/core/util/sharedlibrary.h>
#include <inviwo/core/util/filesystem.h>
#include <inviwo/core/util/stringconversion.h> // splitString
#include <codecvt>
#include <locale>

#if WIN32
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <dlfcn.h>
#endif

namespace inviwo {

SharedLibrary::SharedLibrary(std::string filePath)
    : filePath_(filePath)
{

#if WIN32

    // Search for dlls in directories specified by the path environment variable
    // Need to be done since we are using a non-standard call to LoadLibrary
    static auto addDirectoriesInPath = []() { // Lambda executed once
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        const char* environmentPath = std::getenv("PATH");
        if (environmentPath &&
            GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "AddDllDirectory")) {
            auto elems = splitString(std::string(environmentPath), ';');
            for (auto path : elems) {
                std::wstring dd;

                //std::string narrow = converter.to_bytes(wide_utf16_source_string);
                std::wstring wide = converter.from_bytes(path);
                AddDllDirectory(converter.from_bytes(path).c_str());
            }
            return true;
        }
        else {
            return false;
        }
    }();

    // Load library and search for dependencies in
    // 1. The directory that contains the DLL (LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR).
    // 2. Paths explicitly added with the AddDllDirectory function (LOAD_LIBRARY_SEARCH_USER_DIRS)
    // or the SetDllDirectory function. If more than one path has been added, the order in which the
    // paths are searched is unspecified.
    // 3. The System directory (LOAD_LIBRARY_SEARCH_SYSTEM32)
    //
    // Note 1: The directory containing the application executable is not searched filePath is in
    // that directory. This enables us to use a temporary directory when loading dlls and thereby
    // allow the original ones to be overwritten while the application is running.
    // Note 2: LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR and LOAD_LIBRARY_SEARCH_USER_DIRS requires KB2533623
    // to be installed.
    // Note 3: Not supported on Windows XP and Server 2003
    if (GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "AddDllDirectory")) {
        handle_ = LoadLibraryExA(filePath.c_str(), nullptr, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS);
    } else {
        // LOAD_LIBRARY_SEARCH_* flags are not supported
        // Fall back to LoadLibrary
        handle_ = LoadLibraryA(filePath.c_str());
    }

    if (!handle_) {
        auto error = GetLastError();
        std::ostringstream errorStream;
        LPVOID errorText;

        auto outputSize = FormatMessage(
            // use system message tables to retrieve error text
            FORMAT_MESSAGE_FROM_SYSTEM
            // allocate buffer on local heap for error text
            | FORMAT_MESSAGE_ALLOCATE_BUFFER
            // Important! will fail otherwise, since we're not
            // (and CANNOT) pass insertion parameters
            | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            error,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPTSTR)&errorText,
            0, NULL);
        if (errorText != nullptr) {
            std::string errorString(static_cast<const char *>(errorText), outputSize + 1);
            errorStream << errorString;
            //errorStream << static_cast<const char *>(errorText);
            // release memory allocated by FormatMessage()
            LocalFree(errorText);
        }

        throw Exception("Failed to load library: " + filePath + "\n Error: " + errorStream.str());
    }
#else
    // RTLD_GLOBAL gives all other loaded libraries access to library
    // RTLD_LOCAL is preferred but would require each module to
    // explicitly load its dependent libraries as well.
    handle_ = dlopen(filePath.c_str(), RTLD_GLOBAL);
    if (!handle_) {
        throw Exception("Failed to load library: " + filePath);
    }
#endif

}
SharedLibrary::~SharedLibrary() {
#if WIN32
    FreeLibrary(handle_);
#else
    dlclose(handle_);
#endif
}

void* SharedLibrary::findSymbol(std::string name) {
#if WIN32
    return GetProcAddress(handle_, "createModule");
#else
    return dlsym(handle_, name.c_str());
#endif
}

} // namespace

<|endoftext|>


<commit_before>/*
 * Copyright (C) 1994-2017 Altair Engineering, Inc.
 * For more information, contact Altair at www.altair.com.
 *
 * This file is part of the PBS Professional ("PBS Pro") software.
 *
 * Open Source License Information:
 *
 * PBS Pro is free software. You can redistribute it and/or modify it under the
 * terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * PBS Pro is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Commercial License Information:
 *
 * The PBS Pro software is licensed under the terms of the GNU Affero General
 * Public License agreement ("AGPL"), except where a separate commercial license
 * agreement for PBS Pro version 14 or later has been executed in writing with Altair.
 *
 * Altair’s dual-license business model allows companies, individuals, and
 * organizations to create proprietary derivative works of PBS Pro and distribute
 * them - whether embedded or bundled with other software - under a commercial
 * license agreement.
 *
 * Use of Altair’s trademarks, including but not limited to "PBS™",
 * "PBS Professional®", and "PBS Pro™" and Altair’s logos is subject to Altair's
 * trademark licensing policies.
 *
 */

#include <cppunit/extensions/AutoRegisterSuite.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestAssert.h>
#include <ConnectionPool.h>
#include <testdrmaa.h>
#include <pbs_ifl.h>

using namespace std;

CPPUNIT_TEST_SUITE_REGISTRATION(TestDrmaa);

void TestDrmaa::TestConnectionPool() {
        int connfd[22], i = 0, prevfd = 0, x = 0;
        ConnPool* tmp= ConnPool::getInstance();
        connfd[i] = tmp->getConnectionFromPool(pbs_default());
	prevfd = connfd[i];
        //printf("\nIndex [%d] Fd [%d]", i, connfd[i]);
        i++;
        tmp->returnConnectionToPool(connfd[0]);
        connfd[i] = tmp->getConnectionFromPool(pbs_default());
        //printf("\nIndex [%d] Fd [%d]", i, connfd[i]);
	CPPUNIT_ASSERT_EQUAL(prevfd, connfd[i]);
        i++;
        connfd[i] = tmp->getConnectionFromPool(pbs_default());
        //printf("\nIndex [%d] Fd [%d]", i, connfd[i]);
        i++;
        connfd[i] = tmp->getConnectionFromPool(pbs_default());
        //printf("\nIndex [%d] Fd [%d]", i, connfd[i]);
        i++;
        connfd[i] = tmp->getConnectionFromPool(pbs_default());
        //printf("\nIndex [%d] Fd [%d]", i, connfd[i]);
	prevfd = connfd[i];
        connfd[i] = tmp->reestablishConnection(connfd[i]);
        //printf("\nIndex [%d] Fd [%d]", i, connfd[i]);
	CPPUNIT_ASSERT(prevfd == connfd[i]);
	i++;
	for(x = i; x < 22; x++) {
        	connfd[x] = tmp->getConnectionFromPool(pbs_default());
        	//printf("\nIndex [%d] Fd [%d]", x, connfd[x]);
	}
	CPPUNIT_ASSERT(connfd[21] == -1);
}
<commit_msg>Outsider commit (#1)<commit_after>/*
 * Copyright (C) 1994-2017 Altair Engineering, Inc.
 * For more information, contact Altair at www.altair.com.
 *
 * This file is part of the PBS Professional ("PBS Pro") software.
 *
 * Open Source License Information:
 *
 * PBS Pro is free software. You can redistribute it and/or modify it under the
 * terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * PBS Pro is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Commercial License Information:
 *
 * The PBS Pro software is licensed under the terms of the GNU Affero General
 * Public License agreement ("AGPL"), except where a separate commercial license
 * agreement for PBS Pro version 14 or later has been executed in writing with Altair.
 *
 * Altair’s dual-license business model allows companies, individuals, and
 * organizations to create proprietary derivative works of PBS Pro and distribute
 * them - whether embedded or bundled with other software - under a commercial
 * license agreement.
 *
 * Use of Altair’s trademarks, including but not limited to "PBS™",
 * "PBS Professional®", and "PBS Pro™" and Altair’s logos is subject to Altair's
 * trademark licensing policies.
 *
 */

#include <cppunit/extensions/AutoRegisterSuite.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestAssert.h>
#include <ConnectionPool.h>
#include <testdrmaa.h>
#include <pbs_ifl.h>

using namespace std;

CPPUNIT_TEST_SUITE_REGISTRATION(TestDrmaa);

void TestDrmaa::TestConnectionPool() {
        int connfd[22], i = 0, prevfd = 0, x = 0;
        ConnPool* tmp= ConnPool::getInstance();
        connfd[i] = tmp->getConnectionFromPool(pbs_default());
	prevfd = connfd[i];
        //printf("\nIndex [%d] Fd [%d]", i, connfd[i]);
        i++;
        tmp->returnConnectionToPool(connfd[0]);
        connfd[i] = tmp->getConnectionFromPool(pbs_default());
        //printf("\nIndex [%d] Fd [%d]", i, connfd[i]);
	CPPUNIT_ASSERT_EQUAL(prevfd, connfd[i]);
        i++;
        connfd[i] = tmp->getConnectionFromPool(pbs_default());
        //printf("\nIndex [%d] Fd [%d]", i, connfd[i]);
        i++;
        connfd[i] = tmp->getConnectionFromPool(pbs_default());
        //printf("\nIndex [%d] Fd [%d]", i, connfd[i]);
        i++;
        connfd[i] = tmp->getConnectionFromPool(pbs_default());
        //printf("\nIndex [%d] Fd [%d]", i, connfd[i]);
	prevfd = connfd[i];
        connfd[i] = tmp->reestablishConnection(connfd[i]);
        //printf("\nIndex [%d] Fd [%d]", i, connfd[i]);
	CPPUNIT_ASSERT(prevfd != connfd[i]);
	i++;
	for(x = i; x < 22; x++) {
        	connfd[x] = tmp->getConnectionFromPool(pbs_default());
        	//printf("\nIndex [%d] Fd [%d]", x, connfd[x]);
	}
	CPPUNIT_ASSERT(connfd[21] == -1);
}
<|endoftext|>