<commit_before>#include "ability.hh"
#include "actor.hh"

bool Ability_OpenDoor::operator()(Actor* self, Tile* target, bool force) {
	if (target->ch == '+') {
		if (self->confirmAction || force) {
			Tile tile = TileBuilder("Open door");
			*target = tile;
			self->confirmAction = false;
			self->msgs.push_back("Door opened.");
		} else {
			self->confirmAction = true;
			self->msgs.push_back("Door is closed. Do you want to open it?");
		}
		return true;
	}
	return false;
}

bool Ability_CloseDoor::operator()(Actor* self, bool force) {
	Tile* target = self->getTilePtr();
	if (*target == TileBuilder("Open door")) {
		Tile tile = TileBuilder("Closed door");
		*target = tile;
		self->msgs.push_back("Door closed.");
		return true;
	}
	return false;
}

bool Ability_LookAt::operator()(Actor* self, Tile* target, bool force) {
	self->msgs.push_back(target->desc + ".");
	return true;
}

bool Ability_ConcealDivinity::operator()(Actor* self, bool force) {
	if (self->realType == self->type) {
		self->type = Actor::HUMAN;
		self->msgs.push_back("You took human form.");
	} else {
		self->type = self->realType;
		self->msgs.push_back("You took your real form.");
	}
	return true;
}

bool Ability_TouchOfGod::operator()(Actor* self, Actor* target, bool force) {
	if (self->realType != self->type) {
		self->msgs.push_back("You must be in your true form to use Touch of God.");
		return false;
	}
	if (!(target->realType & EVIL_ACTORS)) return false;
	// Reveal possessed
	if (target->type == Actor::HUMAN) {
		self->msgs.push_back("The human is possessed!");
		target->type = Actor::POSSESSED;
		return true;
	}
	// Do some damage!
	int dmg = randint(5,8) + (self->realType == Actor::ARCHANGEL) ? randint(5,8) : 0;
	bool died = target->hurt(dmg);
	self->msgs.push_back(died ?
		std::string("You vanquished the ") + target->getTypeName() + "." :
		std::string("You punish the ") + target->getTypeName() + " by " + num2str(dmg) + "."
		);
	if (died) self->addExp(target->realType == Actor::ARCHDEMON ? 2 : 1);
	return true;
}

bool Ability_Bless::operator()(Actor* self, Actor* target, bool force) {
	//if (self->realType != self->type) {
		//self->msgs.push_back("You must be in your true form to use Bless.");
		//return false;
	//}
	// Reveal possessed
	if (target->type == Actor::HUMAN && (target->realType & EVIL_ACTORS)) {
		self->msgs.push_back("The human is possessed!");
		target->type = Actor::POSSESSED;
		return true;
	}
	if (!(target->realType & Actor::HUMAN) || target->blessed > 0 || target->possessed) return false;
	// Bless
	int blessing = randint(2,3) + (self->realType == Actor::ARCHANGEL) ? randint(2,4) : 0;
	target->blessed += blessing;
	self->msgs.push_back(std::string("You blessed the ") + target->getTypeName() + ".");
	self->addExp(1);
	return true;
}

bool Ability_HealSelf::operator()(Actor* self, bool force) {
	if (self->getExp() >= 2 && self->getHealth() < self->getMaxHealth()) {
		self->addExp(-2); self->hurt(-1);
	}
	return true;
}

bool Ability_Possess::operator()(Actor* self, Actor* target, bool force) {
	if (target->type != Actor::HUMAN || self->possessing) return false;
	// Reveal cloaked angel
	if (target->realType & (Actor::ANGEL | Actor::ARCHANGEL)) {
		self->msgs.push_back("The human is an angel in disguise!");
		target->type = Actor::CLOAKEDANGEL;
		return true;
	}
	// Handle blessed humans
	if (target->blessed > 0) {
		self->hurt(target->blessed);
		self->msgs.push_back("You hurt yourself trying to possess a human blessed by an angel.");
		return true;
	}
	// Do possession
	self->msgs.push_back("You are now possessing the human.");
	self->possessing = target;
	target->possessed = self;
	self->type = Actor::HUMAN;
	self->addExp(1);
	// Move in-place
	self->getTilePtr()->actor = NULL;
	target->getTilePtr()->actor = self;
	self->x = target->x;
	self->y = target->y;
	return true;
}

bool Ability_DemonFire::operator()(Actor* self, Actor* target, bool force) {
	if (target->realType & EVIL_ACTORS) return false;
	// Handle no body
	if (!self->possessing) {
		self->msgs.push_back("You must be possessing a body to use demon fire.");
		return false;
	}
	// Reveal cloaked angel
	if (target->type == Actor::HUMAN && (target->realType & GOOD_ACTORS)) {
		self->msgs.push_back("The human is an angel in disguise!");
		target->type = Actor::CLOAKEDANGEL;
		return true;
	}
	// Reveal self when attacking angel
	if (self->type == Actor::HUMAN && self->possessing && target->realType & GOOD_ACTORS) {
		self->type = Actor::POSSESSED;
	}
	// Do fire
	int dmg = randint(4,6) + (self->realType == Actor::ARCHDEMON) ? randint(5,8) : 0;
	if (self->realType == Actor::IMP) dmg = randint(1,2);
	bool died = target->hurt(dmg);
	self->msgs.push_back(died ?
		std::string("You burnt the ") + target->getTypeName() + " to oblivion." :
		std::string("You burn the ") + target->getTypeName() + " by " + num2str(dmg) + "."
		);
	if (died) {
		int expadd = 1;
		if (target->realType == Actor::ANGEL) expadd++;
		if (target->realType == Actor::ARCHANGEL) expadd++;
		self->addExp(expadd);
	}
	return true;
}
<commit_msg>Added more messages.<commit_after>#include "ability.hh"
#include "actor.hh"

bool Ability_OpenDoor::operator()(Actor* self, Tile* target, bool force) {
	if (target->ch == '+') {
		if (self->confirmAction || force) {
			Tile tile = TileBuilder("Open door");
			*target = tile;
			self->confirmAction = false;
			self->msgs.push_back("Door opened.");
		} else {
			self->confirmAction = true;
			self->msgs.push_back("Door is closed. Do you want to open it?");
		}
		return true;
	}
	return false;
}

bool Ability_CloseDoor::operator()(Actor* self, bool force) {
	Tile* target = self->getTilePtr();
	if (*target == TileBuilder("Open door")) {
		Tile tile = TileBuilder("Closed door");
		*target = tile;
		self->msgs.push_back("Door closed.");
		return true;
	}
	return false;
}

bool Ability_LookAt::operator()(Actor* self, Tile* target, bool force) {
	self->msgs.push_back(target->desc + ".");
	return true;
}

bool Ability_ConcealDivinity::operator()(Actor* self, bool force) {
	if (self->realType == self->type) {
		self->type = Actor::HUMAN;
		self->msgs.push_back("You took human form.");
	} else {
		self->type = self->realType;
		self->msgs.push_back("You took your real form.");
	}
	return true;
}

bool Ability_TouchOfGod::operator()(Actor* self, Actor* target, bool force) {
	if (!(target->realType & EVIL_ACTORS)) return false;
	// Reveal possessed
	if (target->type == Actor::HUMAN) {
		self->msgs.push_back("The human is possessed!");
		target->msgs.push_back("You possessing the human is revealed!");
		target->type = Actor::POSSESSED;
		return true;
	}
	// Check form
	if (self->realType != self->type) {
		self->msgs.push_back("You must be in your true form to use Touch of God.");
		return false;
	}
	// Do some damage!
	int dmg = randint(5,8) + (self->realType == Actor::ARCHANGEL) ? randint(5,8) : 0;
	bool died = target->hurt(dmg);
	self->msgs.push_back(died ?
		std::string("You vanquished the ") + target->getTypeName() + "." :
		std::string("You punish the ") + target->getTypeName() + " (" + num2str(dmg) + ")."
		);
	target->msgs.push_back(died ?
		std::string("You fell to the attack of the ") + self->getTypeName() + "." :
		std::string("You were hurt by the ") + self->getTypeName() + " (" + num2str(dmg) + ")."
		);

	if (died) self->addExp(target->realType == Actor::ARCHDEMON ? 2 : 1);
	return true;
}

bool Ability_Bless::operator()(Actor* self, Actor* target, bool force) {
	//if (self->realType != self->type) {
		//self->msgs.push_back("You must be in your true form to use Bless.");
		//return false;
	//}
	// Reveal possessed
	if (target->type == Actor::HUMAN && (target->realType & EVIL_ACTORS)) {
		self->msgs.push_back("The human is possessed!");
		target->msgs.push_back("You possessing the human is revealed!");
		target->type = Actor::POSSESSED;
		return true;
	}
	if (!(target->realType & Actor::HUMAN) || target->blessed > 0 || target->possessed) return false;
	// Bless
	int blessing = randint(2,3) + (self->realType == Actor::ARCHANGEL) ? randint(2,4) : 0;
	target->blessed += blessing;
	self->msgs.push_back(std::string("You blessed the ") + target->getTypeName() + ".");
	self->addExp(1);
	return true;
}

bool Ability_HealSelf::operator()(Actor* self, bool force) {
	if (self->getExp() >= 2 && self->getHealth() < self->getMaxHealth()) {
		self->addExp(-2); self->hurt(-1);
		self->msgs.push_back("You feel a tiny bit better.");
	}
	return true;
}

bool Ability_Possess::operator()(Actor* self, Actor* target, bool force) {
	if (target->type != Actor::HUMAN || self->possessing) return false;
	// Reveal cloaked angel
	if (target->realType & (Actor::ANGEL | Actor::ARCHANGEL)) {
		self->msgs.push_back("The human is an angel in disguise!");
		target->type = Actor::CLOAKEDANGEL;
		return true;
	}
	// Handle blessed humans
	if (target->blessed > 0) {
		self->hurt(target->blessed);
		self->msgs.push_back("You hurt yourself trying to possess a human blessed by an angel.");
		return true;
	}
	// Do possession
	self->msgs.push_back("You are now possessing the human.");
	self->possessing = target;
	target->possessed = self;
	self->type = Actor::HUMAN;
	self->addExp(1);
	// Move in-place
	self->getTilePtr()->actor = NULL;
	target->getTilePtr()->actor = self;
	self->x = target->x;
	self->y = target->y;
	return true;
}

bool Ability_DemonFire::operator()(Actor* self, Actor* target, bool force) {
	if (target->realType & EVIL_ACTORS) return false;
	// Handle no body
	if (!self->possessing) {
		self->msgs.push_back("You must be possessing a body to use demon fire.");
		return false;
	}
	// Reveal cloaked angel
	if (target->type == Actor::HUMAN && (target->realType & GOOD_ACTORS)) {
		self->msgs.push_back("The human is an angel in disguise!");
		target->type = Actor::CLOAKEDANGEL;
		return true;
	}
	// Reveal self when attacking angel
	if (self->type == Actor::HUMAN && self->possessing && target->realType & GOOD_ACTORS) {
		self->type = Actor::POSSESSED;
	}
	// Do fire
	int dmg = randint(4,6) + (self->realType == Actor::ARCHDEMON) ? randint(5,8) : 0;
	if (self->realType == Actor::IMP) dmg = randint(1,2);
	bool died = target->hurt(dmg);
	self->msgs.push_back(died ?
		std::string("You burnt the ") + target->getTypeName() + " to oblivion." :
		std::string("You burn the ") + target->getTypeName() + " (" + num2str(dmg) + ")."
		);
	target->msgs.push_back(died ?
		std::string("You fell to the attack of the ") + self->getTypeName() + "." :
		std::string("You were hurt by the ") + self->getTypeName() + " (" + num2str(dmg) + ")."
		);
	if (died) {
		int expadd = 1;
		if (target->realType == Actor::ANGEL) expadd++;
		if (target->realType == Actor::ARCHANGEL) expadd++;
		self->addExp(expadd);
	}
	return true;
}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	Arithmetic テンプレート @n
			※テキストの数式を展開して、計算結果を得る。@n
			演算式解析
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2015, 2020 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/R8C/blob/master/LICENSE
*/
//=====================================================================//
#include <cstdint>
#include "common/bitset.hpp"

namespace utils {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief	Arithmetic クラス
		@param[in]	VTYPE	基本型
		@param[in]	SYMBOL	シンボルクラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <typename VTYPE>
	struct basic_arith {

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief	エラー・タイプ
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class error : uint8_t {
			fatal,				///< エラー
			number_fatal,		///< 数字の変換に関するエラー
			zero_divide,		///< ０除算エラー
			binary_fatal,		///< ２進データの変換に関するエラー
			octal_fatal,		///< ８進データの変換に関するエラー
			hexdecimal_fatal,	///< １６進データの変換に関するエラー
			num_fatal,			///< 数値の変換に関するエラー
			symbol_fatal,		///< シンボルデータの変換に関するエラー
		};

		typedef bitset<uint16_t, error> error_t;

	private:

		const char*		tx_;
		char			ch_;

		error_t		error_;

		VTYPE		value_;

		void skip_space_() {
			while(ch_ == ' ' || ch_ == '\t') {
				ch_ = *tx_++;
			}
		}

		VTYPE number_() {
			bool inv = false;
///			bool neg = false;
			bool point = false;
			uint32_t v = 0;
			uint32_t fp = 0;
			uint32_t fs = 1;

			skip_space_();

			// 符号、反転の判定
			if(ch_ == '-') {
				inv = true;
				ch_ = *tx_++;
			} else if(ch_ == '+') {
				ch_ = *tx_++;
//			} else if(ch_ == '!' || ch_ == '~') {
//				neg = true;
//				ch_ = *tx_++;
			}

			skip_space_();

			if(ch_ == '(') {
				v = factor_();
			} else {
				skip_space_();

//				if(ch_ >= 'A' && ch_ <= 'Z') symbol = true;
//				else if(ch_ >= 'a' && ch_ <= 'z') symbol = true;
//				else if(ch_ == '_' || ch_ == '?') symbol = true;

				while(ch_ != 0) {
					if(ch_ == '+') break;
					else if(ch_ == '-') break;
					else if(ch_ == '*') break;
					else if(ch_ == '/') break;
//					else if(ch_ == '&') break;
//					else if(ch_ == '^') break;
//					else if(ch_ == '|') break;
//					else if(ch_ == '%') break;
					else if(ch_ == ')') break;
//					else if(ch_ == '<') break;
//					else if(ch_ == '>') break;
//					else if(ch_ == '!') break;
//					else if(ch_ == '~') break;
					else if(ch_ == '.') {
						if(point) {
							error_.set(error::fatal);
							break;
						} else {
							point = true;
						}
					} else if(ch_ >= '0' && ch_ <= '9') {
						if(point) {
							fp *= 10;
							fp += ch_ - '0';
							fs *= 10;
						} else {
							v *= 10;
							v += ch_ - '0';
						}
					}
					ch_ = *tx_++;
				}

#if 0
				if(symbol) {
					symbol_map_cit cit = symbol_.find(sym);
					if(cit != symbol_.end()) {
						v = (*cit).second;
					} else {
						error_.set(error::symbol_fatal);
					}
				}
#endif
			}

			if(inv) { v = -v; }
///			if(neg) { v = ~v; }
			if(point) {
				return static_cast<VTYPE>(v) + static_cast<VTYPE>(fp) / static_cast<VTYPE>(fs);
			} else {
				return static_cast<VTYPE>(v);
			}
		}

		VTYPE factor_() {
			VTYPE v = 0;
			if(ch_ == '(') {
				ch_ = *tx_++;
				v = expression_();
				if(ch_ == ')') {
					ch_ = *tx_++;
				} else {
					error_.set(error::fatal);
				}
			} else {
				v = number_();
			}
			return v;
		}

		VTYPE term_() {
			VTYPE v = factor_();
			VTYPE tmp;
			while(error_() == 0) {
				switch(ch_) {
				case ' ':
				case '\t':
					ch_ = *tx_++;
					break;
				case '*':
					ch_ = *tx_++;
					v *= factor_();
					break;
#if 0
				case '%':
					ch_ = *tx_++;
					tmp = factor_();
					if(tmp == 0) {
						error_.set(error::zero_divide);
						break;
					}
					v %= tmp;
					break;
#endif
				case '/':
					ch_ = *tx_++;
					if(ch_ == '/') {
						ch_ = *tx_++;
						tmp = factor_();
						if(tmp == 0) {
							error_.set(error::zero_divide);
							break;
						}
///						v %= tmp;
					} else {
						tmp = factor_();
						if(tmp == 0) {
							error_.set(error::zero_divide);
							break;
						}
						v /= tmp;
					}
					break;
#if 0
				case '<':
					ch_ = *tx_++;
					if(ch_ == '<') {
						ch_ = *tx_++;
						v <<= factor_();
					} else {
						error_.set(error::fatal);
					}
					break;
				case '>':
					ch_ = *tx_++;
					if(ch_ == '>') {
						ch_ = *tx_++;
						v <<= factor_();
					} else {
						error_.set(error::fatal);
					}
					break;
#endif
				default:
					return v;
					break;
				}
			}
			return v;
		}

		VTYPE expression_() {
			VTYPE v = term_();
			while(error_() == 0) {
				switch(ch_) {
				case ' ':
				case '\t':
					ch_ = *tx_++;
					break;
				case '+':
					ch_ = *tx_++;
					v += term_();
					break;
				case '-':
					ch_ = *tx_++;
					v -= term_();
					break;
#if 0
				case '&':
					ch_ = *tx_++;
					v &= term_();
					break;
				case '^':
					ch_ = *tx_++;
					v ^= term_();
					break;
				case '|':
					ch_ = *tx_++;
					v |= term_();
					break;
#endif
				default:
					return v;
					break;
				}
			}
			return v;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
		*/
		//-----------------------------------------------------------------//
		basic_arith() : tx_(nullptr), ch_(0), error_(), value_(0) { }

		//-----------------------------------------------------------------//
		/*!
			@brief	解析を開始
			@param[in]	text	解析テキスト
			@return	文法にエラーがあった場合、「false」
		*/
		//-----------------------------------------------------------------//
		bool analize(const char* text) {
			if(text == nullptr) {
				error_.set(error::fatal);
				return false;
			}
			tx_ = text;

			error_.clear();

			ch_ = *tx_++;
			if(ch_ != 0) {
				value_ = expression_();
			} else {
				error_.set(error::fatal);
			}

			if(error_() != 0) {
				return false;
			} else if(ch_ != 0) {
				error_.set(error::fatal);
				return false;
			}
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	エラーを受け取る
			@return エラー
		*/
		//-----------------------------------------------------------------//
		const error_t& get_error() const { return error_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	結果を取得
			@return	結果
		*/
		//-----------------------------------------------------------------//
		VTYPE get() const { return value_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	() で結果を取得
			@return	結果
		*/
		//-----------------------------------------------------------------//
		VTYPE operator() () const { return value_; }
	};
}
<commit_msg>Fix: minus value<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	Arithmetic テンプレート @n
			※テキストの数式を展開して、計算結果を得る。@n
			演算式解析
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2015, 2020 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/R8C/blob/master/LICENSE
*/
//=====================================================================//
#include <cstdint>
#include "common/bitset.hpp"

namespace utils {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief	Arithmetic クラス
		@param[in]	VTYPE	基本型
		@param[in]	SYMBOL	シンボルクラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <typename VTYPE>
	struct basic_arith {

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief	エラー・タイプ
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class error : uint8_t {
			fatal,				///< エラー
			number_fatal,		///< 数字の変換に関するエラー
			zero_divide,		///< ０除算エラー
			binary_fatal,		///< ２進データの変換に関するエラー
			octal_fatal,		///< ８進データの変換に関するエラー
			hexdecimal_fatal,	///< １６進データの変換に関するエラー
			num_fatal,			///< 数値の変換に関するエラー
			symbol_fatal,		///< シンボルデータの変換に関するエラー
		};

		typedef bitset<uint16_t, error> error_t;

	private:

		const char*		tx_;
		char			ch_;

		error_t		error_;

		VTYPE		value_;

		void skip_space_() {
			while(ch_ == ' ' || ch_ == '\t') {
				ch_ = *tx_++;
			}
		}

		VTYPE number_() {
			bool inv = false;
///			bool neg = false;
			bool point = false;
			int32_t v = 0;
			uint32_t fp = 0;
			uint32_t fs = 1;

			skip_space_();

			// 符号、反転の判定
			if(ch_ == '-') {
				inv = true;
				ch_ = *tx_++;
			} else if(ch_ == '+') {
				ch_ = *tx_++;
//			} else if(ch_ == '!' || ch_ == '~') {
//				neg = true;
//				ch_ = *tx_++;
			}

			skip_space_();

			if(ch_ == '(') {
				v = factor_();
			} else {
				skip_space_();

//				if(ch_ >= 'A' && ch_ <= 'Z') symbol = true;
//				else if(ch_ >= 'a' && ch_ <= 'z') symbol = true;
//				else if(ch_ == '_' || ch_ == '?') symbol = true;

				while(ch_ != 0) {
					if(ch_ == '+') break;
					else if(ch_ == '-') break;
					else if(ch_ == '*') break;
					else if(ch_ == '/') break;
//					else if(ch_ == '&') break;
//					else if(ch_ == '^') break;
//					else if(ch_ == '|') break;
//					else if(ch_ == '%') break;
					else if(ch_ == ')') break;
//					else if(ch_ == '<') break;
//					else if(ch_ == '>') break;
//					else if(ch_ == '!') break;
//					else if(ch_ == '~') break;
					else if(ch_ == '.') {
						if(point) {
							error_.set(error::fatal);
							break;
						} else {
							point = true;
						}
					} else if(ch_ >= '0' && ch_ <= '9') {
						if(point) {
							fp *= 10;
							fp += ch_ - '0';
							fs *= 10;
						} else {
							v *= 10;
							v += ch_ - '0';
						}
					}
					ch_ = *tx_++;
				}

#if 0
				if(symbol) {
					symbol_map_cit cit = symbol_.find(sym);
					if(cit != symbol_.end()) {
						v = (*cit).second;
					} else {
						error_.set(error::symbol_fatal);
					}
				}
#endif
			}

			if(inv) { v = -v; }
///			if(neg) { v = ~v; }
			if(point) {
				return static_cast<VTYPE>(v) + static_cast<VTYPE>(fp) / static_cast<VTYPE>(fs);
			} else {
				return static_cast<VTYPE>(v);
			}
		}

		VTYPE factor_() {
			VTYPE v = 0;
			if(ch_ == '(') {
				ch_ = *tx_++;
				v = expression_();
				if(ch_ == ')') {
					ch_ = *tx_++;
				} else {
					error_.set(error::fatal);
				}
			} else {
				v = number_();
			}
			return v;
		}

		VTYPE term_() {
			VTYPE v = factor_();
			VTYPE tmp;
			while(error_() == 0) {
				switch(ch_) {
				case ' ':
				case '\t':
					ch_ = *tx_++;
					break;
				case '*':
					ch_ = *tx_++;
					v *= factor_();
					break;
#if 0
				case '%':
					ch_ = *tx_++;
					tmp = factor_();
					if(tmp == 0) {
						error_.set(error::zero_divide);
						break;
					}
					v %= tmp;
					break;
#endif
				case '/':
					ch_ = *tx_++;
					if(ch_ == '/') {
						ch_ = *tx_++;
						tmp = factor_();
						if(tmp == 0) {
							error_.set(error::zero_divide);
							break;
						}
///						v %= tmp;
					} else {
						tmp = factor_();
						if(tmp == 0) {
							error_.set(error::zero_divide);
							break;
						}
						v /= tmp;
					}
					break;
#if 0
				case '<':
					ch_ = *tx_++;
					if(ch_ == '<') {
						ch_ = *tx_++;
						v <<= factor_();
					} else {
						error_.set(error::fatal);
					}
					break;
				case '>':
					ch_ = *tx_++;
					if(ch_ == '>') {
						ch_ = *tx_++;
						v <<= factor_();
					} else {
						error_.set(error::fatal);
					}
					break;
#endif
				default:
					return v;
					break;
				}
			}
			return v;
		}

		VTYPE expression_() {
			VTYPE v = term_();
			while(error_() == 0) {
				switch(ch_) {
				case ' ':
				case '\t':
					ch_ = *tx_++;
					break;
				case '+':
					ch_ = *tx_++;
					v += term_();
					break;
				case '-':
					ch_ = *tx_++;
					v -= term_();
					break;
#if 0
				case '&':
					ch_ = *tx_++;
					v &= term_();
					break;
				case '^':
					ch_ = *tx_++;
					v ^= term_();
					break;
				case '|':
					ch_ = *tx_++;
					v |= term_();
					break;
#endif
				default:
					return v;
					break;
				}
			}
			return v;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
		*/
		//-----------------------------------------------------------------//
		basic_arith() : tx_(nullptr), ch_(0), error_(), value_(0) { }

		//-----------------------------------------------------------------//
		/*!
			@brief	解析を開始
			@param[in]	text	解析テキスト
			@return	文法にエラーがあった場合、「false」
		*/
		//-----------------------------------------------------------------//
		bool analize(const char* text) {
			if(text == nullptr) {
				error_.set(error::fatal);
				return false;
			}
			tx_ = text;

			error_.clear();

			ch_ = *tx_++;
			if(ch_ != 0) {
				value_ = expression_();
			} else {
				error_.set(error::fatal);
			}

			if(error_() != 0) {
				return false;
			} else if(ch_ != 0) {
				error_.set(error::fatal);
				return false;
			}
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	エラーを受け取る
			@return エラー
		*/
		//-----------------------------------------------------------------//
		const error_t& get_error() const { return error_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	結果を取得
			@return	結果
		*/
		//-----------------------------------------------------------------//
		VTYPE get() const { return value_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	() で結果を取得
			@return	結果
		*/
		//-----------------------------------------------------------------//
		VTYPE operator() () const { return value_; }
	};
}
<|endoftext|>


<commit_before><commit_msg>consistent constness for getFunctionSymbol() overloads<commit_after><|endoftext|>


<commit_before>//
//  GvmClusterMain.cpp
//  GvmCpp
//
//  Created by Mo DeJong on 8/14/15.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//

#include <iostream>

#include <unordered_map>

#import "Gvm.hpp"

using namespace std;
using namespace Gvm;

// Load points from a file

template<typename V, typename P>
vector<V> loadPointsFromBGR(string filename)
{
  vector<V> allPoints;

  FILE *fp = fopen(filename.c_str(), "rb");

  fseek(fp, 0, SEEK_END);

  int numBytes = (int) ftell(fp);

  if (numBytes == 0) {
    cerr << "empty input YUV file contains zero BGRA pixels" << endl;
    exit(1);
  }

  if ((numBytes % sizeof(uint32_t)) != 0) {
    cerr << "input YUV must be a file with a whole number of BGRA pixels" << endl;
    exit(1);
  }

  fseek(fp, 0, SEEK_SET);

  // In DEBUG mode, use unordered_map to check for duplicate pixels in the input

#if defined(DEBUG)
  unordered_map<uint32_t, uint32_t> uniquePixelMap;
#endif // DEBUG

  for (; numBytes > 0 ; numBytes -= 4) {
    uint32_t pixel;

    int numRead = (int)fread(&pixel, sizeof(pixel), 1, fp);
    if (numRead != 1) {
      cerr << "could not read whole pixel from YUV input at offset " << ftell(fp) << endl;
      exit(1);
    }

    uint32_t B = pixel & 0xFF;
    uint32_t G = (pixel >> 8) & 0xFF;
    uint32_t R = (pixel >> 16) & 0xFF;

#if defined(DEBUG)
    uint32_t pixelNoAlpha = (R << 16) | (G << 8) | B;

    if (uniquePixelMap.count(pixelNoAlpha) > 0) {
      cerr << "input contains duplicate BGR pixel" << endl;
      exit(1);
    }
#endif // DEBUG

    P x = B;
    P y = G;
    P z = R;

    V coordsVec;

    coordsVec[0] = x;
    coordsVec[1] = y;
    coordsVec[2] = z;

    allPoints.push_back(coordsVec);
  }

  fclose(fp);

  return allPoints;
}

int main(int argc, char **argv) {

  string filename = "/Users/modejong/Development/ImageCompression/GVMCluster/Lenna_int_order.yuv";

  // Using float instead of double cuts memory usage down just a bit, like 10%

  typedef double FP;
//  typedef float FP;

  // ClusterVector and ClusterVspace define the low level fixed size
  // vector of values that represents the point values.

  typedef GvmStdVector<FP,3> ClusterVector;
  typedef GvmVectorSpace<ClusterVector,FP,3> ClusterVectorSpace;

  // A "key" is a vector of points in one specific cluster.

  typedef vector<ClusterVector> ClusterKey;

  vector<ClusterVector> allPoints = loadPointsFromBGR<ClusterVector,FP>(filename);

  cout << "read " << allPoints.size() << " pixels from " << filename << endl;

  ClusterVectorSpace vspace;

  const int numClusters = 2048;
  //const int numClusters = 1024;
  //const int numClusters = 512; // 30 megs of ram, 8 sec CPU
  //const int numClusters = 256; // 16 megs of ram, 3 sec of CPU
  //const int numClusters = 128; // 16 megs of ram, 1 sec of CPU

  GvmClusters<ClusterVectorSpace, ClusterVector, ClusterKey, FP> clusters(vspace, numClusters);

  GvmListKeyer<ClusterVectorSpace, ClusterVector, ClusterKey, FP> listKeyer;

  // Install key combiner for list of points, caller must manage ptr lifetime

  clusters.setKeyer(&listKeyer);

  // Insert each point into clusters. Each point is
  // associated with a list of points called a "key".
  // This key object lifetime must be managed by the caller
  // for performance reasons.

  vector<ClusterKey> allKeys;
  allKeys.reserve(allPoints.size());

  for ( ClusterVector & pt : allPoints ) {
    // Key is a list of (list of points)
    if (false) {
    assert(pt.getDimensions() == 3);
    cout << "clustering point (B G R) (" << pt[0] << " " << pt[1] << " " << pt[2] << ")" << endl;
    }

    allKeys.push_back(ClusterKey ());
    ClusterKey *key = &allKeys[allKeys.size() - 1];
    key->push_back(pt);

    clusters.add(1, pt, key);
  }

  cout << "generated " << clusters.clusters.size() << " clusters" << endl;

  // Emit clustered results as YUV data padded out to 256 with zeros

  // vector<GvmResult>

  int clusteri = 0;

  vector<GvmResult<ClusterVectorSpace, ClusterVector, ClusterKey, FP>> results = clusters.results();

  for ( auto & result : results ) {
    cout << "cluster[" << clusteri << "]: " << result.toString() << endl;
    clusteri++;
  }

  // Write clustered pixels as YUV output

  int totalPixelsWritten = 0;

  string outYuvFilename = "out.yuv";

  FILE *outFP = fopen(outYuvFilename.c_str(), "wb");

  for (int i = 0; i < results.size(); i++) {
    int clusterID = i; // keep to byte range

    ClusterKey *allKeys = results[i].getKey();

    cout << "cluster " << clusterID << " contains " << allKeys->size() << " pixels" << endl;

    int pixelsWritten = 0;

    for ( ClusterVector &pt : *allKeys ) {
      FP x = pt[0];
      FP y = pt[1];
      FP z = pt[2];

      if (x < 0 || x > 255) {
        assert(0);
      }
      if (y < 0 || y > 255) {
        assert(0);
      }
      if (z < 0 || z > 255) {
        assert(0);
      }

      uint32_t B = int(x);
      uint32_t G = int(y);
      uint32_t R = int(z);

      uint32_t pixel = (R << 16) | (G << 8) | B;

      int numWritten = (int)fwrite(&pixel, sizeof(uint32_t), 1, outFP);
      assert(numWritten == 1);
      pixelsWritten++;
    }

    totalPixelsWritten += pixelsWritten;

    if (true) {
      // Pad each cluster out to 256

      int numPointsInCluster = pixelsWritten;

      int over = numPointsInCluster % 256;
      int under = 0;

      if (over == 0) {
        // Cluster of exactly 256 pixels, emit 256 zeros to indicate this case.
        under = 256;
      } else {
        under = 256 - over;
      }

      for (int j = 0; j < under; j++) {
        uint32_t pixel = 0;
        int numWritten = (int)fwrite(&pixel, sizeof(uint32_t), 1, outFP);
        assert(numWritten == 1);
        totalPixelsWritten++;
      }
    }
  }

  fclose(outFP);

  cout << "wrote " << totalPixelsWritten << " total pixels to " << outYuvFilename << endl;

  int totalRowsOf256 = totalPixelsWritten/256;
  if ((totalPixelsWritten % 256) != 0) {
    assert(0);
  }

  cout << "wrote 256 x " << totalRowsOf256 << endl;

  cout << "as " << results.size() << " number of clusters" << endl;

  return 0;
}
<commit_msg>emit BGRA pixels with alpha turned on<commit_after>//
//  GvmClusterMain.cpp
//  GvmCpp
//
//  Created by Mo DeJong on 8/14/15.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//

#include <iostream>

#include <unordered_map>

#import "Gvm.hpp"

using namespace std;
using namespace Gvm;

// Load points from a file

template<typename V, typename P>
vector<V> loadPointsFromBGR(string filename)
{
  vector<V> allPoints;

  FILE *fp = fopen(filename.c_str(), "rb");

  fseek(fp, 0, SEEK_END);

  int numBytes = (int) ftell(fp);

  if (numBytes == 0) {
    cerr << "empty input YUV file contains zero BGRA pixels" << endl;
    exit(1);
  }

  if ((numBytes % sizeof(uint32_t)) != 0) {
    cerr << "input YUV must be a file with a whole number of BGRA pixels" << endl;
    exit(1);
  }

  fseek(fp, 0, SEEK_SET);

  // In DEBUG mode, use unordered_map to check for duplicate pixels in the input

#if defined(DEBUG)
  unordered_map<uint32_t, uint32_t> uniquePixelMap;
#endif // DEBUG

  for (; numBytes > 0 ; numBytes -= 4) {
    uint32_t pixel;

    int numRead = (int)fread(&pixel, sizeof(pixel), 1, fp);
    if (numRead != 1) {
      cerr << "could not read whole pixel from YUV input at offset " << ftell(fp) << endl;
      exit(1);
    }

    uint32_t B = pixel & 0xFF;
    uint32_t G = (pixel >> 8) & 0xFF;
    uint32_t R = (pixel >> 16) & 0xFF;

#if defined(DEBUG)
    uint32_t pixelNoAlpha = (R << 16) | (G << 8) | B;

    if (uniquePixelMap.count(pixelNoAlpha) > 0) {
      cerr << "input contains duplicate BGR pixel" << endl;
      exit(1);
    }
#endif // DEBUG

    P x = B;
    P y = G;
    P z = R;

    V coordsVec;

    coordsVec[0] = x;
    coordsVec[1] = y;
    coordsVec[2] = z;

    allPoints.push_back(coordsVec);
  }

  fclose(fp);

  return allPoints;
}

int main(int argc, char **argv) {

  string filename = "/Users/modejong/Development/ImageCompression/GVMCluster/Lenna_int_order.yuv";

  // Using float instead of double cuts memory usage down just a bit, like 10%

  typedef double FP;
//  typedef float FP;

  // ClusterVector and ClusterVspace define the low level fixed size
  // vector of values that represents the point values.

  typedef GvmStdVector<FP,3> ClusterVector;
  typedef GvmVectorSpace<ClusterVector,FP,3> ClusterVectorSpace;

  // A "key" is a vector of points in one specific cluster.

  typedef vector<ClusterVector> ClusterKey;

  vector<ClusterVector> allPoints = loadPointsFromBGR<ClusterVector,FP>(filename);

  cout << "read " << allPoints.size() << " pixels from " << filename << endl;

  ClusterVectorSpace vspace;

  const int numClusters = 2048;
  //const int numClusters = 1024;
  //const int numClusters = 512; // 30 megs of ram, 8 sec CPU
  //const int numClusters = 256; // 16 megs of ram, 3 sec of CPU
  //const int numClusters = 128; // 16 megs of ram, 1 sec of CPU

  GvmClusters<ClusterVectorSpace, ClusterVector, ClusterKey, FP> clusters(vspace, numClusters);

  GvmListKeyer<ClusterVectorSpace, ClusterVector, ClusterKey, FP> listKeyer;

  // Install key combiner for list of points, caller must manage ptr lifetime

  clusters.setKeyer(&listKeyer);

  // Insert each point into clusters. Each point is
  // associated with a list of points called a "key".
  // This key object lifetime must be managed by the caller
  // for performance reasons.

  vector<ClusterKey> allKeys;
  allKeys.reserve(allPoints.size());

  for ( ClusterVector & pt : allPoints ) {
    // Key is a list of (list of points)
    if (false) {
    assert(pt.getDimensions() == 3);
    cout << "clustering point (B G R) (" << pt[0] << " " << pt[1] << " " << pt[2] << ")" << endl;
    }

    allKeys.push_back(ClusterKey ());
    ClusterKey *key = &allKeys[allKeys.size() - 1];
    key->push_back(pt);

    clusters.add(1, pt, key);
  }

  cout << "generated " << clusters.clusters.size() << " clusters" << endl;

  // Emit clustered results as YUV data padded out to 256 with zeros

  // vector<GvmResult>

  int clusteri = 0;

  vector<GvmResult<ClusterVectorSpace, ClusterVector, ClusterKey, FP>> results = clusters.results();

  for ( auto & result : results ) {
    cout << "cluster[" << clusteri << "]: " << result.toString() << endl;
    clusteri++;
  }

  // Write clustered pixels as YUV output

  int totalPixelsWritten = 0;

  string outYuvFilename = "out.yuv";

  FILE *outFP = fopen(outYuvFilename.c_str(), "wb");

  for (int i = 0; i < results.size(); i++) {
    int clusterID = i; // keep to byte range

    ClusterKey *allKeys = results[i].getKey();

    cout << "cluster " << clusterID << " contains " << allKeys->size() << " pixels" << endl;

    int pixelsWritten = 0;

    for ( ClusterVector &pt : *allKeys ) {
      FP x = pt[0];
      FP y = pt[1];
      FP z = pt[2];

      if (x < 0 || x > 255) {
        assert(0);
      }
      if (y < 0 || y > 255) {
        assert(0);
      }
      if (z < 0 || z > 255) {
        assert(0);
      }

      uint32_t B = int(x);
      uint32_t G = int(y);
      uint32_t R = int(z);

      uint32_t pixel = (0xFF << 24) | (R << 16) | (G << 8) | B;

      int numWritten = (int)fwrite(&pixel, sizeof(uint32_t), 1, outFP);
      assert(numWritten == 1);
      pixelsWritten++;
    }

    totalPixelsWritten += pixelsWritten;

    if (true) {
      // Pad each cluster out to 256

      int numPointsInCluster = pixelsWritten;

      int over = numPointsInCluster % 256;
      int under = 0;

      if (over == 0) {
        // Cluster of exactly 256 pixels, emit 256 zeros to indicate this case.
        under = 256;
      } else {
        under = 256 - over;
      }

      for (int j = 0; j < under; j++) {
        uint32_t pixel = 0;
        int numWritten = (int)fwrite(&pixel, sizeof(uint32_t), 1, outFP);
        assert(numWritten == 1);
        totalPixelsWritten++;
      }
    }
  }

  fclose(outFP);

  cout << "wrote " << totalPixelsWritten << " total pixels to " << outYuvFilename << endl;

  int totalRowsOf256 = totalPixelsWritten/256;
  if ((totalPixelsWritten % 256) != 0) {
    assert(0);
  }

  cout << "wrote 256 x " << totalRowsOf256 << endl;

  cout << "as " << results.size() << " number of clusters" << endl;

  // In the combination phase, pixels split into clusters are combined based on calculation
  // of distances from one cluster center to the next.

  return 0;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2013, 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 "test.hpp"
#include "setup_transfer.hpp"
#include "dht_server.hpp"
#include "peer_server.hpp"
#include "udp_tracker.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/alert_types.hpp"

#include <fstream>

using namespace libtorrent;

char const* proxy_name[] = {
	"none",
	"socks4",
	"socks5",
	"socks5_pw",
	"http",
	"http_pw",
	"i2p_proxy"
};

std::vector<std::string> rejected_trackers;

bool alert_predicate(libtorrent::alert* a)
{
	anonymous_mode_alert* am = alert_cast<anonymous_mode_alert>(a);
	if (am == NULL) return false;

	if (am->kind == anonymous_mode_alert::tracker_not_anonymous)
		rejected_trackers.push_back(am->str);

	return false;
}

enum flags_t
{
	anonymous_mode = 1,
	expect_http_connection = 2,
	expect_udp_connection = 4,
	expect_http_reject = 8,
	expect_udp_reject = 16,
	expect_dht_msg = 32,
	expect_peer_connection = 64,
};

session_proxy test_proxy(proxy_settings::proxy_type proxy_type, int flags)
{
#ifdef TORRENT_DISABLE_DHT
	// if DHT is disabled, we won't get any requests to it
	flags &= ~expect_dht_msg;
#endif
	fprintf(stderr, "\n=== TEST == proxy: %s anonymous-mode: %s\n\n", proxy_name[proxy_type], (flags & anonymous_mode) ? "yes" : "no");
	int http_port = start_web_server();
	int udp_port = start_udp_tracker();
	int dht_port = start_dht();
	int peer_port = start_peer();

	int prev_udp_announces = num_udp_announces();

	int const alert_mask = alert::all_categories
		& ~alert::progress_notification
		& ~alert::stats_notification;

	session* s = new libtorrent::session(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48875, 49800), "0.0.0.0", 0, alert_mask);

	session_settings sett;
	sett.stop_tracker_timeout = 2;
	sett.tracker_completion_timeout = 2;
	sett.tracker_receive_timeout = 2;
	sett.half_open_limit = 1;
	sett.announce_to_all_trackers = true;
	sett.announce_to_all_tiers = true;
	sett.anonymous_mode = flags & anonymous_mode;
	sett.force_proxy = flags & anonymous_mode;

	// if we don't do this, the peer connection test
	// will be delayed by several seconds, by first
	// trying uTP
	sett.enable_outgoing_utp = false;
	s->set_settings(sett);

	// in non-anonymous mode we circumvent/ignore the proxy if it fails
	// wheras in anonymous mode, we just fail
	proxy_settings ps;
	ps.hostname = "non-existing.com";
	ps.port = 4444;
	ps.type = proxy_type;
	s->set_proxy(ps);

	s->start_dht();

	error_code ec;
	create_directory("tmp1_privacy", ec);
	std::ofstream file(combine_path("tmp1_privacy", "temporary").c_str());
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false);
	file.close();

	char http_tracker_url[200];
	snprintf(http_tracker_url, sizeof(http_tracker_url), "http://127.0.0.1:%d/announce", http_port);
	t->add_tracker(http_tracker_url, 0);

	char udp_tracker_url[200];
	snprintf(udp_tracker_url, sizeof(udp_tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
	t->add_tracker(udp_tracker_url, 1);

	add_torrent_params addp;
	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;
	addp.ti = t;
	addp.save_path = "tmp1_privacy";
	addp.dht_nodes.push_back(std::pair<std::string, int>("127.0.0.1", dht_port));
	torrent_handle h = s->add_torrent(addp);

	printf("connect_peer: 127.0.0.1:%d\n", peer_port);
	h.connect_peer(tcp::endpoint(address_v4::from_string("127.0.0.1"), peer_port));

	rejected_trackers.clear();

#ifdef TORRENT_USE_VALGRIND
	const int timeout = 100;
#else
	const int timeout = 20;
#endif

	for (int i = 0; i < timeout; ++i)
	{
		print_alerts(*s, "s", false, false, false, &alert_predicate);
		test_sleep(100);

		if (num_udp_announces() >= prev_udp_announces + 1
			&& num_peer_hits() > 0)
			break;
	}

	// we should have announced to the tracker by now
	TEST_EQUAL(num_udp_announces(), prev_udp_announces + bool(flags & expect_udp_connection));
	if (flags & expect_dht_msg)
	{
		TEST_CHECK(num_dht_hits() > 0);
	}
	else
	{
		TEST_EQUAL(num_dht_hits(), 0);
	}

	if (flags & expect_peer_connection)
	{
		TEST_CHECK(num_peer_hits() > 0);
	}
	else
	{
		TEST_EQUAL(num_peer_hits(), 0);
	}

	if (flags & expect_udp_reject)
		TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), udp_tracker_url) != rejected_trackers.end());

	if (flags & expect_http_reject)
		TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), http_tracker_url) != rejected_trackers.end());

	fprintf(stderr, "%s: ~session\n", time_now_string());
	session_proxy pr = s->abort();
	delete s;

	stop_peer();
	stop_dht();
	stop_udp_tracker();
	stop_web_server();
	return pr;
}

int test_main()
{
	session_proxy pr[20];
	// not using anonymous mode
	// UDP fails open if we can't connect to the proxy
	// or if the proxy doesn't support UDP
	pr[0] = test_proxy(proxy_settings::none, expect_udp_connection | expect_http_connection | expect_dht_msg | expect_peer_connection);
	pr[1] = test_proxy(proxy_settings::socks4, expect_udp_connection | expect_dht_msg);
	pr[2] = test_proxy(proxy_settings::socks5, expect_udp_connection | expect_dht_msg);
	pr[3] = test_proxy(proxy_settings::socks5_pw, expect_udp_connection | expect_dht_msg);
	pr[4] = test_proxy(proxy_settings::http, expect_udp_connection | expect_dht_msg);
	pr[5] = test_proxy(proxy_settings::http_pw, expect_udp_connection | expect_dht_msg);
	pr[6] = test_proxy(proxy_settings::i2p_proxy, expect_udp_connection | expect_dht_msg);

	// using anonymous mode

	// anonymous mode doesn't require a proxy when one isn't configured. It could be
	// used with a VPN for instance. This will all changed in 1.0, where anonymous
	// mode is separated from force_proxy
	pr[7] = test_proxy(proxy_settings::none, anonymous_mode | expect_peer_connection);
	pr[8] = test_proxy(proxy_settings::socks4, anonymous_mode | expect_udp_reject);
	pr[9] = test_proxy(proxy_settings::socks5, anonymous_mode);
	pr[10] = test_proxy(proxy_settings::socks5_pw, anonymous_mode);
	pr[11] = test_proxy(proxy_settings::http, anonymous_mode | expect_udp_reject);
	pr[12] = test_proxy(proxy_settings::http_pw, anonymous_mode | expect_udp_reject);
	pr[13] = test_proxy(proxy_settings::i2p_proxy, anonymous_mode);
	return 0;
}

<commit_msg>improve reliability of test_privacy<commit_after>/*

Copyright (c) 2013, 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 "test.hpp"
#include "setup_transfer.hpp"
#include "dht_server.hpp"
#include "peer_server.hpp"
#include "udp_tracker.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/alert_types.hpp"

#include <fstream>

using namespace libtorrent;

char const* proxy_name[] = {
	"none",
	"socks4",
	"socks5",
	"socks5_pw",
	"http",
	"http_pw",
	"i2p_proxy"
};

std::vector<std::string> rejected_trackers;

bool alert_predicate(libtorrent::alert* a)
{
	anonymous_mode_alert* am = alert_cast<anonymous_mode_alert>(a);
	if (am == NULL) return false;

	if (am->kind == anonymous_mode_alert::tracker_not_anonymous)
		rejected_trackers.push_back(am->str);

	return false;
}

enum flags_t
{
	anonymous_mode = 1,
	expect_http_connection = 2,
	expect_udp_connection = 4,
	expect_http_reject = 8,
	expect_udp_reject = 16,
	expect_dht_msg = 32,
	expect_peer_connection = 64,
};

session_proxy test_proxy(proxy_settings::proxy_type proxy_type, int flags)
{
#ifdef TORRENT_DISABLE_DHT
	// if DHT is disabled, we won't get any requests to it
	flags &= ~expect_dht_msg;
#endif
	fprintf(stderr, "\n=== TEST == proxy: %s anonymous-mode: %s\n\n", proxy_name[proxy_type], (flags & anonymous_mode) ? "yes" : "no");
	int http_port = start_web_server();
	int udp_port = start_udp_tracker();
	int dht_port = start_dht();
	int peer_port = start_peer();

	int prev_udp_announces = num_udp_announces();

	int const alert_mask = alert::all_categories
		& ~alert::progress_notification
		& ~alert::stats_notification;

	session* s = new libtorrent::session(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48875, 49800), "0.0.0.0", 0, alert_mask);

	session_settings sett;
	sett.stop_tracker_timeout = 2;
	sett.tracker_completion_timeout = 2;
	sett.tracker_receive_timeout = 2;
	sett.half_open_limit = 1;
	sett.announce_to_all_trackers = true;
	sett.announce_to_all_tiers = true;
	sett.anonymous_mode = flags & anonymous_mode;
	sett.force_proxy = flags & anonymous_mode;

	// if we don't do this, the peer connection test
	// will be delayed by several seconds, by first
	// trying uTP
	sett.enable_outgoing_utp = false;
	s->set_settings(sett);

	// in non-anonymous mode we circumvent/ignore the proxy if it fails
	// wheras in anonymous mode, we just fail
	proxy_settings ps;
	ps.hostname = "non-existing.com";
	ps.port = 4444;
	ps.type = proxy_type;
	s->set_proxy(ps);

	s->start_dht();

	error_code ec;
	remove_all("tmp1_privacy", ec);
	create_directory("tmp1_privacy", ec);
	std::ofstream file(combine_path("tmp1_privacy", "temporary").c_str());
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false);
	file.close();

	char http_tracker_url[200];
	snprintf(http_tracker_url, sizeof(http_tracker_url), "http://127.0.0.1:%d/announce", http_port);
	t->add_tracker(http_tracker_url, 0);

	char udp_tracker_url[200];
	snprintf(udp_tracker_url, sizeof(udp_tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
	t->add_tracker(udp_tracker_url, 1);

	add_torrent_params addp;
	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;

	// we don't want to waste time checking the torrent, just go straight into
	// seeding it, announcing to trackers and connecting to peers
	addp.flags |= add_torrent_params::flag_seed_mode;

	addp.ti = t;
	addp.save_path = "tmp1_privacy";
	addp.dht_nodes.push_back(std::pair<std::string, int>("127.0.0.1", dht_port));
	torrent_handle h = s->add_torrent(addp);

	printf("connect_peer: 127.0.0.1:%d\n", peer_port);
	h.connect_peer(tcp::endpoint(address_v4::from_string("127.0.0.1"), peer_port));

	rejected_trackers.clear();

#ifdef TORRENT_USE_VALGRIND
	const int timeout = 100;
#else
	const int timeout = 20;
#endif

	for (int i = 0; i < timeout; ++i)
	{
		print_alerts(*s, "s", false, false, false, &alert_predicate);
		test_sleep(100);

		if (num_udp_announces() >= prev_udp_announces + 1
			&& num_peer_hits() > 0)
			break;
	}

	// we should have announced to the tracker by now
	TEST_EQUAL(num_udp_announces(), prev_udp_announces + bool(flags & expect_udp_connection));
	if (flags & expect_dht_msg)
	{
		TEST_CHECK(num_dht_hits() > 0);
	}
	else
	{
		TEST_EQUAL(num_dht_hits(), 0);
	}

	if (flags & expect_peer_connection)
	{
		TEST_CHECK(num_peer_hits() > 0);
	}
	else
	{
		TEST_EQUAL(num_peer_hits(), 0);
	}

	if (flags & expect_udp_reject)
		TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), udp_tracker_url) != rejected_trackers.end());

	if (flags & expect_http_reject)
		TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), http_tracker_url) != rejected_trackers.end());

	fprintf(stderr, "%s: ~session\n", time_now_string());
	session_proxy pr = s->abort();
	delete s;

	stop_peer();
	stop_dht();
	stop_udp_tracker();
	stop_web_server();
	return pr;
}

int test_main()
{
	session_proxy pr[20];
	// not using anonymous mode
	// UDP fails open if we can't connect to the proxy
	// or if the proxy doesn't support UDP
	pr[0] = test_proxy(proxy_settings::none, expect_udp_connection | expect_http_connection | expect_dht_msg | expect_peer_connection);
	pr[1] = test_proxy(proxy_settings::socks4, expect_udp_connection | expect_dht_msg);
	pr[2] = test_proxy(proxy_settings::socks5, expect_udp_connection | expect_dht_msg);
	pr[3] = test_proxy(proxy_settings::socks5_pw, expect_udp_connection | expect_dht_msg);
	pr[4] = test_proxy(proxy_settings::http, expect_udp_connection | expect_dht_msg);
	pr[5] = test_proxy(proxy_settings::http_pw, expect_udp_connection | expect_dht_msg);
	pr[6] = test_proxy(proxy_settings::i2p_proxy, expect_udp_connection | expect_dht_msg);

	// using anonymous mode

	// anonymous mode doesn't require a proxy when one isn't configured. It could be
	// used with a VPN for instance. This will all changed in 1.0, where anonymous
	// mode is separated from force_proxy
	pr[7] = test_proxy(proxy_settings::none, anonymous_mode | expect_peer_connection);
	pr[8] = test_proxy(proxy_settings::socks4, anonymous_mode | expect_udp_reject);
	pr[9] = test_proxy(proxy_settings::socks5, anonymous_mode);
	pr[10] = test_proxy(proxy_settings::socks5_pw, anonymous_mode);
	pr[11] = test_proxy(proxy_settings::http, anonymous_mode | expect_udp_reject);
	pr[12] = test_proxy(proxy_settings::http_pw, anonymous_mode | expect_udp_reject);
	pr[13] = test_proxy(proxy_settings::i2p_proxy, anonymous_mode);
	return 0;
}

<|endoftext|>


<commit_before>/*
 * REnvironmentPosix.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/r_util/REnvironment.hpp>

#include <algorithm>

#include <boost/tokenizer.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/replace.hpp>

#include <core/Error.hpp>
#include <core/FilePath.hpp>
#include <core/ConfigUtils.hpp>
#include <core/system/System.hpp>

namespace core {
namespace r_util {

namespace {

// MacOS X Specific
#ifdef __APPLE__

#define kLibRFileName            "libR.dylib"
#define kLibraryPathEnvVariable  "DYLD_LIBRARY_PATH"

// no extra paths on the mac
std::string extraLibraryPaths(const FilePath& ldPathsScript,
                              const std::string& rHome)
{
   return std::string();
}

// Linux specific
#else

#define kLibRFileName            "libR.so"
#define kLibraryPathEnvVariable  "LD_LIBRARY_PATH"

// extra paths from R (for rjava) on linux
std::string extraLibraryPaths(const FilePath& ldPathsScript,
                              const std::string& rHome)
{
   // verify that script exists
   if (!ldPathsScript.exists())
   {
      LOG_WARNING_MESSAGE("r-ldpaths script not found at " +
                          ldPathsScript.absolutePath());
      return std::string();
   }

   // run script to capture paths
   std::string libraryPaths;
   std::string command = ldPathsScript.absolutePath() + " " + rHome;
   Error error = system::captureCommand(command, &libraryPaths);
   if (error)
      LOG_ERROR(error);
   boost::algorithm::trim(libraryPaths);
   return libraryPaths;
}

#endif

bool validateRScriptPath(const std::string& rScriptPath,
                         std::string* pErrMsg)
{
   // get realpath
   FilePath rBinaryPath;
   Error error = core::system::realPath(rScriptPath, &rBinaryPath);
   if (error)
   {
      LOG_ERROR(error);
      *pErrMsg = "Unable to determine real path of R script " +
                 rScriptPath + " (" + error.summary() + ")";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }

   // check for real path doesn't exist
   else if (!rBinaryPath.exists())
   {
      *pErrMsg = "Real path of R script does not exist (" +
                  rBinaryPath.absolutePath() + ")";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }

   // error if it is a directry
   else if (rBinaryPath.isDirectory())
   {
      *pErrMsg = "R script path (" + rBinaryPath.absolutePath() +
                 ") is a directory rather than a file";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }

   // looks good!
   else
   {
      return true;
   }
}

bool validateSystemDefaultRScript(std::string* pErrMsg)
{
   // ask system which R to use
   std::string whichOutput;
   Error error = core::system::captureCommand("which R", &whichOutput);
   if (error)
   {
      LOG_ERROR(error);
      *pErrMsg = "Error calling which R to determine system default "
                 "R binary " + error.summary();
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }
   boost::algorithm::trim(whichOutput);

   // if we got no output then log and return false
   if (whichOutput.empty())
   {
      *pErrMsg = "Unable to find an installation of R on the system "
                 "(which R didn't return valid output)";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }
   else
   {
      return validateRScriptPath(whichOutput, pErrMsg);
   }
}

bool validateREnvironment(const EnvironmentVars& vars,
                          const FilePath& rLibPath,
                          std::string* pErrMsg)
{
   // first extract paths
   FilePath rHomePath, rSharePath, rIncludePath, rDocPath, rLibRPath;
   for (EnvironmentVars::const_iterator it = vars.begin();
        it != vars.end();
        ++it)
   {
      if (it->first == "R_HOME")
         rHomePath = FilePath(it->second);
      else if (it->first == "R_SHARE_DIR")
         rSharePath = FilePath(it->second);
      else if (it->first == "R_INCLUDE_DIR")
         rIncludePath = FilePath(it->second);
      else if (it->first == "R_DOC_DIR")
         rDocPath = FilePath(it->second);
   }

   // resolve libR path
   rLibRPath = rLibPath.complete(kLibRFileName);

   // validate required paths (if these don't exist then rsession won't
   // be able start up)
   if (!rHomePath.exists())
   {
      *pErrMsg = "R Home path (" + rHomePath.absolutePath() + ") not found";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }
   else if (!rLibPath.exists())
   {
      *pErrMsg = "R lib path (" + rLibPath.absolutePath() + ") not found";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }
   else if (!rLibRPath.exists())
   {
      *pErrMsg = "R shared library (" + rLibRPath.absolutePath() + ") "
                 "not found. If this is a custom build of R, was it "
                 "built with the --enable-R-shlib option?";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }
   else if (!rDocPath.exists())
   {
      *pErrMsg = "R doc dir (" + rDocPath.absolutePath() + ") not found.";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }

   // log warnings for other missing paths (rsession can still start but
   // won't be able to find these env variables)

   if (!rSharePath.exists())
   {
      LOG_WARNING_MESSAGE("R share path (" + rSharePath.absolutePath() +
                          ") not found");
   }

   if (!rIncludePath.exists())
   {
      LOG_WARNING_MESSAGE("R include path (" + rIncludePath.absolutePath() +
                          ") not found");
   }

   return true;
}

bool detectRLocations(const std::string& rScriptPath,
                      FilePath* pHomePath,
                      FilePath* pLibPath,
                      config_utils::Variables* pScriptVars,
                      std::string* pErrMsg)
{
   // eliminate a potentially conflicting R_HOME before calling R
   // (the normal semantics of invoking the R script are that it overwrites
   // R_HOME and prints a warning -- this warning is co-mingled with the
   // output of R and messes up our parsing)
   core::system::setenv("R_HOME", "");

   // call R to determine the locations
   std::string output;
   std::string command = rScriptPath +
     " --slave --vanilla -e \"cat(paste("
            "R.home('home'),"
            "R.home('share'),"
            "R.home('include'),"
            "R.home('doc'), sep=':'))\"";
   Error error = core::system::captureCommand(command, &output);
   if (error)
   {
      LOG_ERROR(error);
      *pErrMsg = "Error calling R script (" + rScriptPath +
                 "), " + error.summary();
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }

   if (output.empty())
   {
      *pErrMsg = "R did not return any output when queried for "
                 "directory location information";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }

   // extract the locations
   config_utils::Variables& scriptVars = *pScriptVars;
   using namespace boost;
   char_separator<char> sep(":");
   tokenizer<char_separator<char> > tokens(output, sep);
   tokenizer<char_separator<char> >::iterator tokenIter = tokens.begin();
   if (tokenIter != tokens.end())
      scriptVars["R_HOME"] = *tokenIter++;
   if (tokenIter != tokens.end())
      scriptVars["R_SHARE_DIR"] = *tokenIter++;
   if (tokenIter != tokens.end())
      scriptVars["R_INCLUDE_DIR"] = *tokenIter++;
   if (tokenIter != tokens.end())
      scriptVars["R_DOC_DIR"] = *tokenIter++;

   if (scriptVars.size() < 4)
   {
      *pErrMsg = "R did not return valid directory location information; "
                 "R output was: " + output;
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }

   // get home and lib path
   config_utils::Variables::const_iterator it = pScriptVars->find("R_HOME");
   if (it != pScriptVars->end())
   {
      // get R home
      *pHomePath = FilePath(it->second);

      // get R lib path
      FilePath libPath = FilePath(*pHomePath).complete("lib");

      // verify we can find libR
      if (libPath.complete(kLibRFileName).exists())
      {
         *pLibPath = libPath;
      }

      // sometimes on the mac an architecture specific subdirectory is used
      else if (libPath.complete("x86_64/" kLibRFileName).exists())
      {
         *pLibPath = libPath.complete("x86_64");
      }

      // couldn't find libR
      else
      {
         *pErrMsg = "Unable to find " kLibRFileName " in expected locations "
                    "within R Home directory " + pHomePath->absolutePath();
         LOG_ERROR_MESSAGE(*pErrMsg);
         return false;
      }
   }
   else
   {
      *pErrMsg = "Unable to find R_HOME via " + rScriptPath +
                 "; R output was: " + output;
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }

   return true;
}

} // anonymous namespace

bool detectREnvironment(const FilePath& ldPathsScript,
                        EnvironmentVars* pVars,
                        std::string* pErrMsg)
{
   return detectREnvironment(FilePath(),
                             ldPathsScript,
                             std::string(),
                             pVars,
                             pErrMsg);
}

bool detectREnvironment(const FilePath& whichRScript,
                        const FilePath& ldPathsScript,
                        const std::string& ldLibraryPath,
                        EnvironmentVars* pVars,
                        std::string* pErrMsg)
{
   // if there is a which R script override then validate it
   std::string rScriptPath;
   if (!whichRScript.empty())
   {
      // validate
      if (!validateRScriptPath(whichRScript.absolutePath(), pErrMsg))
         return false;

      // set it
      rScriptPath = whichRScript.absolutePath();
   }
   // otherwise use the system default (after validating it as well)
   else
   {
      if (!validateSystemDefaultRScript(pErrMsg))
         return false;

      // set it
      rScriptPath = "R";
   }

   // detect R locations
   FilePath rHomePath, rLibPath;
   config_utils::Variables scriptVars;
   if (!detectRLocations(rScriptPath,
                         &rHomePath,
                         &rLibPath,
                         &scriptVars,
                         pErrMsg))
   {
      return false;
   }

   // set R home path
   pVars->push_back(std::make_pair("R_HOME", rHomePath.absolutePath()));

   // set other environment values
   pVars->push_back(std::make_pair("R_SHARE_DIR", scriptVars["R_SHARE_DIR"]));
   pVars->push_back(std::make_pair("R_INCLUDE_DIR", scriptVars["R_INCLUDE_DIR"]));
   pVars->push_back(std::make_pair("R_DOC_DIR", scriptVars["R_DOC_DIR"]));

   // determine library path (existing + r lib dir + r extra lib dirs)
   std::string libraryPath = core::system::getenv(kLibraryPathEnvVariable);
   if (!libraryPath.empty())
      libraryPath.append(":");
   libraryPath.append(ldLibraryPath);
   if (!libraryPath.empty())
      libraryPath.append(":");
   libraryPath.append(rLibPath.absolutePath());
   std::string extraPaths = extraLibraryPaths(ldPathsScript,
                                              rHomePath.absolutePath());
   if (!extraPaths.empty())
      libraryPath.append(":" + extraPaths);
   pVars->push_back(std::make_pair(kLibraryPathEnvVariable, libraryPath));

   return validateREnvironment(*pVars, rLibPath, pErrMsg);
}

void setREnvironmentVars(const EnvironmentVars& vars)
{
   for (EnvironmentVars::const_iterator it = vars.begin();
        it != vars.end();
        ++it)
   {
      core::system::setenv(it->first, it->second);
   }
}

} // namespace r_util
} // namespace core

<commit_msg>invert shell quoting for R directory probing<commit_after>/*
 * REnvironmentPosix.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/r_util/REnvironment.hpp>

#include <algorithm>

#include <boost/tokenizer.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/replace.hpp>

#include <core/Error.hpp>
#include <core/FilePath.hpp>
#include <core/ConfigUtils.hpp>
#include <core/system/System.hpp>

namespace core {
namespace r_util {

namespace {

// MacOS X Specific
#ifdef __APPLE__

#define kLibRFileName            "libR.dylib"
#define kLibraryPathEnvVariable  "DYLD_LIBRARY_PATH"

// no extra paths on the mac
std::string extraLibraryPaths(const FilePath& ldPathsScript,
                              const std::string& rHome)
{
   return std::string();
}

// Linux specific
#else

#define kLibRFileName            "libR.so"
#define kLibraryPathEnvVariable  "LD_LIBRARY_PATH"

// extra paths from R (for rjava) on linux
std::string extraLibraryPaths(const FilePath& ldPathsScript,
                              const std::string& rHome)
{
   // verify that script exists
   if (!ldPathsScript.exists())
   {
      LOG_WARNING_MESSAGE("r-ldpaths script not found at " +
                          ldPathsScript.absolutePath());
      return std::string();
   }

   // run script to capture paths
   std::string libraryPaths;
   std::string command = ldPathsScript.absolutePath() + " " + rHome;
   Error error = system::captureCommand(command, &libraryPaths);
   if (error)
      LOG_ERROR(error);
   boost::algorithm::trim(libraryPaths);
   return libraryPaths;
}

#endif

bool validateRScriptPath(const std::string& rScriptPath,
                         std::string* pErrMsg)
{
   // get realpath
   FilePath rBinaryPath;
   Error error = core::system::realPath(rScriptPath, &rBinaryPath);
   if (error)
   {
      LOG_ERROR(error);
      *pErrMsg = "Unable to determine real path of R script " +
                 rScriptPath + " (" + error.summary() + ")";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }

   // check for real path doesn't exist
   else if (!rBinaryPath.exists())
   {
      *pErrMsg = "Real path of R script does not exist (" +
                  rBinaryPath.absolutePath() + ")";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }

   // error if it is a directry
   else if (rBinaryPath.isDirectory())
   {
      *pErrMsg = "R script path (" + rBinaryPath.absolutePath() +
                 ") is a directory rather than a file";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }

   // looks good!
   else
   {
      return true;
   }
}

bool validateSystemDefaultRScript(std::string* pErrMsg)
{
   // ask system which R to use
   std::string whichOutput;
   Error error = core::system::captureCommand("which R", &whichOutput);
   if (error)
   {
      LOG_ERROR(error);
      *pErrMsg = "Error calling which R to determine system default "
                 "R binary " + error.summary();
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }
   boost::algorithm::trim(whichOutput);

   // if we got no output then log and return false
   if (whichOutput.empty())
   {
      *pErrMsg = "Unable to find an installation of R on the system "
                 "(which R didn't return valid output)";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }
   else
   {
      return validateRScriptPath(whichOutput, pErrMsg);
   }
}

bool validateREnvironment(const EnvironmentVars& vars,
                          const FilePath& rLibPath,
                          std::string* pErrMsg)
{
   // first extract paths
   FilePath rHomePath, rSharePath, rIncludePath, rDocPath, rLibRPath;
   for (EnvironmentVars::const_iterator it = vars.begin();
        it != vars.end();
        ++it)
   {
      if (it->first == "R_HOME")
         rHomePath = FilePath(it->second);
      else if (it->first == "R_SHARE_DIR")
         rSharePath = FilePath(it->second);
      else if (it->first == "R_INCLUDE_DIR")
         rIncludePath = FilePath(it->second);
      else if (it->first == "R_DOC_DIR")
         rDocPath = FilePath(it->second);
   }

   // resolve libR path
   rLibRPath = rLibPath.complete(kLibRFileName);

   // validate required paths (if these don't exist then rsession won't
   // be able start up)
   if (!rHomePath.exists())
   {
      *pErrMsg = "R Home path (" + rHomePath.absolutePath() + ") not found";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }
   else if (!rLibPath.exists())
   {
      *pErrMsg = "R lib path (" + rLibPath.absolutePath() + ") not found";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }
   else if (!rLibRPath.exists())
   {
      *pErrMsg = "R shared library (" + rLibRPath.absolutePath() + ") "
                 "not found. If this is a custom build of R, was it "
                 "built with the --enable-R-shlib option?";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }
   else if (!rDocPath.exists())
   {
      *pErrMsg = "R doc dir (" + rDocPath.absolutePath() + ") not found.";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }

   // log warnings for other missing paths (rsession can still start but
   // won't be able to find these env variables)

   if (!rSharePath.exists())
   {
      LOG_WARNING_MESSAGE("R share path (" + rSharePath.absolutePath() +
                          ") not found");
   }

   if (!rIncludePath.exists())
   {
      LOG_WARNING_MESSAGE("R include path (" + rIncludePath.absolutePath() +
                          ") not found");
   }

   return true;
}

bool detectRLocations(const std::string& rScriptPath,
                      FilePath* pHomePath,
                      FilePath* pLibPath,
                      config_utils::Variables* pScriptVars,
                      std::string* pErrMsg)
{
   // eliminate a potentially conflicting R_HOME before calling R
   // (the normal semantics of invoking the R script are that it overwrites
   // R_HOME and prints a warning -- this warning is co-mingled with the
   // output of R and messes up our parsing)
   core::system::setenv("R_HOME", "");

   // call R to determine the locations
   std::string output;
   std::string command = rScriptPath +
     " --slave --vanilla -e 'cat(paste("
            "R.home(\"home\"),"
            "R.home(\"share\"),"
            "R.home(\"include\"),"
            "R.home(\"doc\"), sep=\":\"))'";
   Error error = core::system::captureCommand(command, &output);
   if (error)
   {
      LOG_ERROR(error);
      *pErrMsg = "Error calling R script (" + rScriptPath +
                 "), " + error.summary();
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }
   boost::algorithm::trim(output);

   if (output.empty())
   {
      *pErrMsg = "R did not return any output when queried for "
                 "directory location information";
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }

   // extract the locations
   config_utils::Variables& scriptVars = *pScriptVars;
   using namespace boost;
   char_separator<char> sep(":");
   tokenizer<char_separator<char> > tokens(output, sep);
   tokenizer<char_separator<char> >::iterator tokenIter = tokens.begin();
   if (tokenIter != tokens.end())
      scriptVars["R_HOME"] = *tokenIter++;
   if (tokenIter != tokens.end())
      scriptVars["R_SHARE_DIR"] = *tokenIter++;
   if (tokenIter != tokens.end())
      scriptVars["R_INCLUDE_DIR"] = *tokenIter++;
   if (tokenIter != tokens.end())
      scriptVars["R_DOC_DIR"] = *tokenIter++;

   if (scriptVars.size() < 4)
   {
      *pErrMsg = "R did not return valid directory location information; "
                 "R output was: " + output;
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }

   // get home and lib path
   config_utils::Variables::const_iterator it = pScriptVars->find("R_HOME");
   if (it != pScriptVars->end())
   {
      // get R home
      *pHomePath = FilePath(it->second);

      // get R lib path
      FilePath libPath = FilePath(*pHomePath).complete("lib");

      // verify we can find libR
      if (libPath.complete(kLibRFileName).exists())
      {
         *pLibPath = libPath;
      }

      // sometimes on the mac an architecture specific subdirectory is used
      else if (libPath.complete("x86_64/" kLibRFileName).exists())
      {
         *pLibPath = libPath.complete("x86_64");
      }

      // couldn't find libR
      else
      {
         *pErrMsg = "Unable to find " kLibRFileName " in expected locations "
                    "within R Home directory " + pHomePath->absolutePath();
         LOG_ERROR_MESSAGE(*pErrMsg);
         return false;
      }
   }
   else
   {
      *pErrMsg = "Unable to find R_HOME via " + rScriptPath +
                 "; R output was: " + output;
      LOG_ERROR_MESSAGE(*pErrMsg);
      return false;
   }

   return true;
}

} // anonymous namespace

bool detectREnvironment(const FilePath& ldPathsScript,
                        EnvironmentVars* pVars,
                        std::string* pErrMsg)
{
   return detectREnvironment(FilePath(),
                             ldPathsScript,
                             std::string(),
                             pVars,
                             pErrMsg);
}

bool detectREnvironment(const FilePath& whichRScript,
                        const FilePath& ldPathsScript,
                        const std::string& ldLibraryPath,
                        EnvironmentVars* pVars,
                        std::string* pErrMsg)
{
   // if there is a which R script override then validate it
   std::string rScriptPath;
   if (!whichRScript.empty())
   {
      // validate
      if (!validateRScriptPath(whichRScript.absolutePath(), pErrMsg))
         return false;

      // set it
      rScriptPath = whichRScript.absolutePath();
   }
   // otherwise use the system default (after validating it as well)
   else
   {
      if (!validateSystemDefaultRScript(pErrMsg))
         return false;

      // set it
      rScriptPath = "R";
   }

   // detect R locations
   FilePath rHomePath, rLibPath;
   config_utils::Variables scriptVars;
   if (!detectRLocations(rScriptPath,
                         &rHomePath,
                         &rLibPath,
                         &scriptVars,
                         pErrMsg))
   {
      return false;
   }

   // set R home path
   pVars->push_back(std::make_pair("R_HOME", rHomePath.absolutePath()));

   // set other environment values
   pVars->push_back(std::make_pair("R_SHARE_DIR", scriptVars["R_SHARE_DIR"]));
   pVars->push_back(std::make_pair("R_INCLUDE_DIR", scriptVars["R_INCLUDE_DIR"]));
   pVars->push_back(std::make_pair("R_DOC_DIR", scriptVars["R_DOC_DIR"]));

   // determine library path (existing + r lib dir + r extra lib dirs)
   std::string libraryPath = core::system::getenv(kLibraryPathEnvVariable);
   if (!libraryPath.empty())
      libraryPath.append(":");
   libraryPath.append(ldLibraryPath);
   if (!libraryPath.empty())
      libraryPath.append(":");
   libraryPath.append(rLibPath.absolutePath());
   std::string extraPaths = extraLibraryPaths(ldPathsScript,
                                              rHomePath.absolutePath());
   if (!extraPaths.empty())
      libraryPath.append(":" + extraPaths);
   pVars->push_back(std::make_pair(kLibraryPathEnvVariable, libraryPath));

   return validateREnvironment(*pVars, rLibPath, pErrMsg);
}

void setREnvironmentVars(const EnvironmentVars& vars)
{
   for (EnvironmentVars::const_iterator it = vars.begin();
        it != vars.end();
        ++it)
   {
      core::system::setenv(it->first, it->second);
   }
}

} // namespace r_util
} // namespace core

<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stdio.h>

#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "net/test/test_server.h"

static void PrintUsage() {
  printf("run_testserver --doc-root=relpath [--http|--https|--ftp|--sync]\n");
  printf("(NOTE: relpath should be relative to the 'src' directory)\n");
}

int main(int argc, const char* argv[]) {
  base::AtExitManager at_exit_manager;
  MessageLoopForIO message_loop;

  // Process command line
  CommandLine::Init(argc, argv);
  CommandLine* command_line = CommandLine::ForCurrentProcess();

  if (command_line->GetSwitchCount() == 0 ||
      command_line->HasSwitch("help")) {
    PrintUsage();
    return -1;
  }

  net::TestServer::Type server_type(net::TestServer::TYPE_HTTP);
  if (command_line->HasSwitch("https")) {
    server_type = net::TestServer::TYPE_HTTPS;
  } else if (command_line->HasSwitch("ftp")) {
    server_type = net::TestServer::TYPE_FTP;
  } else if (command_line->HasSwitch("sync")) {
    server_type = net::TestServer::TYPE_SYNC;
  }

  FilePath doc_root = command_line->GetSwitchValuePath("doc-root");
  if ((server_type != net::TestServer::TYPE_SYNC) && doc_root.empty()) {
    printf("Error: --doc-root must be specified\n");
    PrintUsage();
    return -1;
  }

  net::TestServer test_server(server_type, doc_root);
  if (!test_server.Start()) {
    printf("Error: failed to start test server. Exiting.\n");
    return -1;
  }

  printf("testserver running at %s (type ctrl+c to exit)\n",
         test_server.host_port_pair().ToString().c_str());

  message_loop.Run();
  return 0;
}
<commit_msg>added InitLogging call to run_testserver.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stdio.h>

#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "net/test/test_server.h"

static void PrintUsage() {
  printf("run_testserver --doc-root=relpath [--http|--https|--ftp|--sync]\n");
  printf("(NOTE: relpath should be relative to the 'src' directory)\n");
}

int main(int argc, const char* argv[]) {
  base::AtExitManager at_exit_manager;
  MessageLoopForIO message_loop;

  // Process command line
  CommandLine::Init(argc, argv);
  CommandLine* command_line = CommandLine::ForCurrentProcess();

  if (!logging::InitLogging(FILE_PATH_LITERAL("testserver.log"),
                            logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG,
                            logging::LOCK_LOG_FILE,
                            logging::APPEND_TO_OLD_LOG_FILE)) {
    printf("Error: could not initialize logging. Exiting.\n");
    return -1;
  }

  if (command_line->GetSwitchCount() == 0 ||
      command_line->HasSwitch("help")) {
    PrintUsage();
    return -1;
  }

  net::TestServer::Type server_type(net::TestServer::TYPE_HTTP);
  if (command_line->HasSwitch("https")) {
    server_type = net::TestServer::TYPE_HTTPS;
  } else if (command_line->HasSwitch("ftp")) {
    server_type = net::TestServer::TYPE_FTP;
  } else if (command_line->HasSwitch("sync")) {
    server_type = net::TestServer::TYPE_SYNC;
  }

  FilePath doc_root = command_line->GetSwitchValuePath("doc-root");
  if ((server_type != net::TestServer::TYPE_SYNC) && doc_root.empty()) {
    printf("Error: --doc-root must be specified\n");
    PrintUsage();
    return -1;
  }

  net::TestServer test_server(server_type, doc_root);
  if (!test_server.Start()) {
    printf("Error: failed to start test server. Exiting.\n");
    return -1;
  }

  printf("testserver running at %s (type ctrl+c to exit)\n",
         test_server.host_port_pair().ToString().c_str());

  message_loop.Run();
  return 0;
}
<|endoftext|>