<commit_before>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>

using std::pair;
using std::make_pair;
using std::vector;
using std::string;
using std::cout;
using std::ifstream;
using std::istringstream;
using std::basic_istringstream;

/*
Dado un caracter, separa un string en substring que almacena en un vector dado,
cada vez que se encuentre con el caracter dado.
*/
void split(const string &s, char c, vector<string> &v){

	string::size_type i = 0;
	string::size_type j = s.find(c);

	while (j != string::npos){
		v.push_back(s.substr(i, j - i));
		i = ++j;
		j = s.find(c, j);

		if (j == string::npos){
			v.push_back(s.substr(i, s.length()));
		}
	}

}

/*
Estructura que contiene un cojunto de palabras para un grupo de palabras prohibidas
determinada.
*/

class ACMCase{
public:
	int numCases, numRestrictedWords;
	vector<vector<string>> words;		// Vector con los las oraciones a evaluar(vectores de string).
	vector<string> restrictedWords;		// Vector con las palbras a ignorar
	ACMCase(){
		this->numCases = 0;
		this->numRestrictedWords = 0;
	};
	~ACMCase(){};

	void solveWord(vector<string> statement){

		pair<int, int> sp;					// Par <numero de letras confirmadas de la abreviacion, numero de ultima palbra usada para completar abreviacion>
		vector<pair<int, int>> solutions;	// Vector con las posibles abreviaciones
		int numSolution = 0;				// Numero de abreviaciones confirmadas
		int as = statement[0].size();
		int checkSolUntil;

		solutions.clear();

		// Recorro las palabras de la oracion a abreviar
		for (unsigned int i = 1; i < statement.size(); i++){

			// Recorro cada caracter de la palabra
			for (unsigned int j = 0; j < statement[i].size(); j++){

				// Recorro las soluciones actuales
				checkSolUntil = solutions.size();

				for (unsigned int k = 0; k < checkSolUntil; k++){

					// Si hubo una palabra en la solucion de la cual no se extrajo al
					// menos una letra para la abreviacion se elimina del vector de soluciones
					if (i > (solutions[k].second + 1)){
						solutions.erase(solutions.begin() + k);
						checkSolUntil-=1;
						k = k - 1;
						continue;
					}

					// Si encuentro un caracter que completa la abreviacio, agrego una nueva solucion.
					//cout << solutions[k].first << " " << statement[0].size() << "\n";

					if ((solutions[k].first < statement[0].size()) &&
						((statement[i][j] == statement[0][solutions[k].first + 1]) || (toupper(statement[i][j]) == statement[0][solutions[k].first + 1]))){
						// Si es el ultimo caracter de la abreviacion y esta en la ultima palabra, incremento en 1 el numero de soluciones.

						if ((i == (statement.size() - 1)) && ((solutions[k].first + 2) == as)){
							numSolution++;
						}
						else {
							sp = make_pair(solutions[k].first + 1, i);
							solutions.push_back(sp);
						}
					}
				}

				// Si se consigue el comienza de la abreviacion en la primera palabra, se agrega la posible solucion.
				// cout << statement[i][j] << " " << statement[0][0] << "\n";
				if (((statement[i][j] == statement[0][0]) || (toupper(statement[i][j]) == statement[0][0])) && (i == 1)){
					sp = make_pair(0, 1);
					solutions.push_back(sp);
				}
			}
		}

		cout << statement[0];

		if (numSolution > 0){
			cout << " can be formed in " << numSolution << " ways\n";
		}
		else {
			cout << " is not valid abbreviation\n";
		}
	}

	void solveMyself(){
		unsigned int i;
		for (i = 0; i < words.size(); i++){
			solveWord(this->words[i]);
		}
	}
};

/*
Procedimiento que dado el nombre de un archivo, lo lee y devuelve un vector
con los casosa evaluar.
*/

vector<ACMCase> readFile(char *fileName){

	ifstream fileStream(fileName);			// stream del archivo
	string currentLine;						// ultima linea leida
	ACMCase *currentCase = NULL;			// Caso en construccion
	vector<ACMCase> out;					// Vector de casos a evaluar
	vector<string> validWords, auxVector;	// Vector con las palabras utiles en cada subcaso.
											// Vecotr Auxiliuar
	int proxyInt, numWords = 0;				// Enteros auxiliar
	bool endReading = false;				// Guardia para salir del ciclo

	while (getline(fileStream, currentLine)){

		switch (currentLine[0]){
		// Casos en que es cualquier numero mayor a cero.
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			// Se agrega el caso anterior de exitir
			if (currentCase){
				out.push_back(*currentCase);
			}

			// obtengo el numero de palabras a omitir
			proxyInt = atoi(currentLine.c_str());

			// Se crea un nuevo caso
			currentCase = new ACMCase;
			currentCase->numRestrictedWords = proxyInt;
			currentCase->numCases = 0;

			// Se lee las palabras a omitir
			for (int i = 0; i < proxyInt; i++){
				getline(fileStream, currentLine);
				currentCase->restrictedWords.push_back(currentLine);
			}
			break;
		case '0':
			// Se agrega el caso anterior de exitir
			if (currentCase){
				out.push_back(*currentCase);
			}

			// Indica el final de lo casos e indica a la guardia que salga del ciclo de lectura
			endReading = true;
			break;
		default:
			// Se lee un una abreviacion con su palabra y se asigna al caso actual.
			if (currentLine!="LAST CASE"){

				currentCase->numCases++;
				auxVector.clear();
				validWords.clear();
				split(currentLine,' ',auxVector);

				validWords.push_back(auxVector[0]);
				unsigned int i;
				unsigned int j;

				for (i = 1; i < auxVector.size(); i++){
					bool valid = true;
					for (j = 0; j < currentCase->restrictedWords.size(); j++){
						// Se verifica que las palabras sean validas
						if (auxVector[i].compare(currentCase->restrictedWords[j]) == 0){
							valid = false;
							break;
						}
					}
					// Se almacenn solo las palabras validas
					if (valid) { validWords.push_back(auxVector[i]); };
				}

				currentCase->words.push_back(validWords);
				break;
			}
		}

		// Salgo del ciclo en cuanto lea cero.
		if (endReading) { break; };

	}

	return out;
}

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

	char *fileName;
	int nodeNum = 0;
	vector<ACMCase> cases;

	if (argc >= 2) {
		fileName = argv[1];
	}
	else {
		fileName = "prueba1.in";
	}

	// Llamo a la lectura de archivo
	cases = readFile(fileName);

	/*
	unsigned int i = 0;
	unsigned int j = 0;
	unsigned int k = 0;

	for (i = 0; i < cases.size(); i++){
		for (j = 0; j < cases[i].restrictedWords.size(); j++){
			cout << cases[i].restrictedWords[j] << '\n';
		}
		for (j = 0; j < cases[i].words.size(); j++){
			for (k = 0; k < cases[i].words[j].size(); k++){
				cout << cases[i].words[j][k] << ' ';
			}
			cout << "\n";
		}
	}
	*/

	for (int x = 0; x < cases.size(); x++){
		cases[x].solveMyself();
	}
	/*while (1){

	};*/
}<commit_msg>Arreglado peo de compilacion<commit_after>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>

using std::pair;
using std::make_pair;
using std::vector;
using std::string;
using std::cout;
using std::ifstream;
using std::istringstream;
using std::basic_istringstream;

/*
Dado un caracter, separa un string en substring que almacena en un vector dado,
cada vez que se encuentre con el caracter dado.
*/
void split(const string &s, char c, vector<string> &v){

	string::size_type i = 0;
	string::size_type j = s.find(c);

	while (j != string::npos){
		v.push_back(s.substr(i, j - i));
		i = ++j;
		j = s.find(c, j);

		if (j == string::npos){
			v.push_back(s.substr(i, s.length()));
		}
	}

}

/*
Estructura que contiene un cojunto de palabras para un grupo de palabras prohibidas
determinada.
*/

class ACMCase{
public:
	int numCases, numRestrictedWords;
	vector< vector<string> > words;		// Vector con los las oraciones a evaluar(vectores de string).
	vector<string> restrictedWords;		// Vector con las palbras a ignorar
	ACMCase(){
		this->numCases = 0;
		this->numRestrictedWords = 0;
	};
	~ACMCase(){};

	void solveWord(vector<string> statement){

		pair<int, int> sp;					// Par <numero de letras confirmadas de la abreviacion, numero de ultima palbra usada para completar abreviacion>
		vector<pair<int, int> > solutions;	// Vector con las posibles abreviaciones
		int numSolution = 0;				// Numero de abreviaciones confirmadas
		int as = statement[0].size();
		int checkSolUntil;

		solutions.clear();

		// Recorro las palabras de la oracion a abreviar
		for (unsigned int i = 1; i < statement.size(); i++){

			// Recorro cada caracter de la palabra
			for (unsigned int j = 0; j < statement[i].size(); j++){

				// Recorro las soluciones actuales
				checkSolUntil = solutions.size();

				for (unsigned int k = 0; k < checkSolUntil; k++){

					// Si hubo una palabra en la solucion de la cual no se extrajo al
					// menos una letra para la abreviacion se elimina del vector de soluciones
					if (i > (solutions[k].second + 1)){
						solutions.erase(solutions.begin() + k);
						checkSolUntil-=1;
						k = k - 1;
						continue;
					}

					// Si encuentro un caracter que completa la abreviacio, agrego una nueva solucion.
					//cout << solutions[k].first << " " << statement[0].size() << "\n";

					if ((solutions[k].first < statement[0].size()) &&
						((statement[i][j] == statement[0][solutions[k].first + 1]) || (toupper(statement[i][j]) == statement[0][solutions[k].first + 1]))){
						// Si es el ultimo caracter de la abreviacion y esta en la ultima palabra, incremento en 1 el numero de soluciones.

						if ((i == (statement.size() - 1)) && ((solutions[k].first + 2) == as)){
							numSolution++;
						}
						else {
							sp = make_pair(solutions[k].first + 1, i);
							solutions.push_back(sp);
						}
					}
				}

				// Si se consigue el comienza de la abreviacion en la primera palabra, se agrega la posible solucion.
				// cout << statement[i][j] << " " << statement[0][0] << "\n";
				if (((statement[i][j] == statement[0][0]) || (toupper(statement[i][j]) == statement[0][0])) && (i == 1)){
					sp = make_pair(0, 1);
					solutions.push_back(sp);
				}
			}
		}

		cout << statement[0];

		if (numSolution > 0){
			cout << " can be formed in " << numSolution << " ways\n";
		}
		else {
			cout << " is not valid abbreviation\n";
		}
	}

	void solveMyself(){
		unsigned int i;
		for (i = 0; i < words.size(); i++){
			solveWord(this->words[i]);
		}
	}
};

/*
Procedimiento que dado el nombre de un archivo, lo lee y devuelve un vector
con los casosa evaluar.
*/

vector<ACMCase> readFile(const char *fileName){

	ifstream fileStream(fileName);			// stream del archivo
	string currentLine;						// ultima linea leida
	ACMCase *currentCase = NULL;			// Caso en construccion
	vector<ACMCase> out;					// Vector de casos a evaluar
	vector<string> validWords, auxVector;	// Vector con las palabras utiles en cada subcaso.
											// Vecotr Auxiliuar
	int proxyInt, numWords = 0;				// Enteros auxiliar
	bool endReading = false;				// Guardia para salir del ciclo

	while (getline(fileStream, currentLine)){

		switch (currentLine[0]){
		// Casos en que es cualquier numero mayor a cero.
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			// Se agrega el caso anterior de exitir
			if (currentCase){
				out.push_back(*currentCase);
			}

			// obtengo el numero de palabras a omitir
			proxyInt = atoi(currentLine.c_str());

			// Se crea un nuevo caso
			currentCase = new ACMCase;
			currentCase->numRestrictedWords = proxyInt;
			currentCase->numCases = 0;

			// Se lee las palabras a omitir
			for (int i = 0; i < proxyInt; i++){
				getline(fileStream, currentLine);
				currentCase->restrictedWords.push_back(currentLine);
			}
			break;
		case '0':
			// Se agrega el caso anterior de exitir
			if (currentCase){
				out.push_back(*currentCase);
			}

			// Indica el final de lo casos e indica a la guardia que salga del ciclo de lectura
			endReading = true;
			break;
		default:
			// Se lee un una abreviacion con su palabra y se asigna al caso actual.
			if (currentLine!="LAST CASE"){

				currentCase->numCases++;
				auxVector.clear();
				validWords.clear();
				split(currentLine,' ',auxVector);

				validWords.push_back(auxVector[0]);
				unsigned int i;
				unsigned int j;

				for (i = 1; i < auxVector.size(); i++){
					bool valid = true;
					for (j = 0; j < currentCase->restrictedWords.size(); j++){
						// Se verifica que las palabras sean validas
						if (auxVector[i].compare(currentCase->restrictedWords[j]) == 0){
							valid = false;
							break;
						}
					}
					// Se almacenn solo las palabras validas
					if (valid) { validWords.push_back(auxVector[i]); };
				}

				currentCase->words.push_back(validWords);
				break;
			}
		}

		// Salgo del ciclo en cuanto lea cero.
		if (endReading) { break; };

	}

	return out;
}

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

	const char *fileName;
	int nodeNum = 0;
	vector<ACMCase> cases;

	if (argc >= 2) {
		fileName = argv[1];
	}
	else {
		fileName = "prueba1.in";
	}

	// Llamo a la lectura de archivo
	cases = readFile(fileName);

	/*
	unsigned int i = 0;
	unsigned int j = 0;
	unsigned int k = 0;

	for (i = 0; i < cases.size(); i++){
		for (j = 0; j < cases[i].restrictedWords.size(); j++){
			cout << cases[i].restrictedWords[j] << '\n';
		}
		for (j = 0; j < cases[i].words.size(); j++){
			for (k = 0; k < cases[i].words[j].size(); k++){
				cout << cases[i].words[j][k] << ' ';
			}
			cout << "\n";
		}
	}
	*/

	for (int x = 0; x < cases.size(); x++){
		cases[x].solveMyself();
	}
	/*while (1){

	};*/
}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX24T グループ MTU3 制御
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "RX24T/icu_mgr.hpp"
#include "RX24T/port_map.hpp"
#include "RX24T/power_cfg.hpp"
#include "RX24T/mtu3.hpp"
#include "common/intr_utils.hpp"
#include "common/vect.h"

#include "common/format.hpp"

/// F_PCLKA は変換パラメーター計算で必要で、設定が無いとエラーにします。
#ifndef F_PCLKA
#  error "mtu_io.hpp requires F_PCLKA to be defined"
#endif

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  MTU 制御クラス
		@param[in]	MTU	MTU ユニット
		@param[in]	MTASK	メイン割り込みタスク
		@param[in]	OTASK	オーバーフロー割り込みタスク
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class MTUX, class MTASK = utils::null_task, class OTASK = utils::null_task>
	class mtu_io {
	public:

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  エッジ・タイプ
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class edge_type : uint8_t {
			positive,	///< 立ち上がり
			negative,	///< 立下り
			dual,		///< 両エッジ
		};

	private:

		struct task_t {
			volatile uint16_t	cap_tick_;
			volatile uint16_t	ovf_tick_;
			volatile uint32_t	tgr_adr_;
			volatile uint32_t	cap_count_;
			volatile uint16_t	ovf_limit_;
			volatile uint16_t	ovf_count_;

			task_t() : cap_tick_(0), ovf_tick_(0),
				tgr_adr_(MTUX::TGRA.address()), cap_count_(0),
				ovf_limit_(1221), ovf_count_(0) { }

			void clear() {
				cap_tick_ = 0;
				ovf_tick_ = 0;
				cap_count_ = 0;
				ovf_count_ = 0;
			}

			void load_cap() {
				cap_count_ = rd16_(tgr_adr_);
				cap_count_ |= static_cast<uint32_t>(ovf_tick_) << 16;
			}
		};

		static task_t	task_t_;
		static MTASK	mtask_;
		static OTASK	otask_;

		uint32_t	clk_limit_;

		static INTERRUPT_FUNC void cap_task_()
		{
			++task_t_.cap_tick_;
			task_t_.load_cap();
			mtask_();
			task_t_.ovf_tick_ = 0;
		}

		static INTERRUPT_FUNC void ovf_task_()
		{
			++task_t_.ovf_tick_;
			if(task_t_.ovf_tick_ >= task_t_.ovf_limit_) {
				task_t_.ovf_tick_ = 0;
				MTUX::TCNT = 0;
				++task_t_.ovf_count_;
			}
			otask_();
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		mtu_io() : clk_limit_(F_PCLKA) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  リミット・クロックの設定
			@param[in]	clk	リミット・クロック
		*/
		//-----------------------------------------------------------------//
		void set_limit_clock(uint32_t clk) { clk_limit_ = clk; }

		//-----------------------------------------------------------------//
		/*!
			@brief  インプットキャプチャ開始 @n
					※カウントクロックは「set_limit_clock」により @n
					変更が可能。
			@param[in]	ch		入力チャネル
			@param[in]	et		エッジ・タイプ
			@param[in]	level	割り込みレベル
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool start_capture(typename MTUX::channel ch, edge_type et, uint8_t level = 0)
		{
			if(MTUX::get_peripheral() == peripheral::MTU5) {  // MTU5 はインプットキャプチャとして利用不可
				return false;
			}

			uint8_t idx = static_cast<uint8_t>(ch);
			if(idx >= 4) return false;

			power_cfg::turn(MTUX::get_peripheral());
			MTUX::enable_port(ch);

			uint8_t etd = 0;
			switch(et) {
			case edge_type::positive: etd = 0b1000; break;
			case edge_type::negative: etd = 0b1001; break;
			case edge_type::dual:     etd = 0b1011; break;
			default: break;
			}
			MTUX::TIOR.set(ch, etd);

			uint8_t dv = 0;
			static const uint8_t cclr[4] = { 0b001, 0b010, 0b101, 0b110 };
			// CKEG: 立ち上がりエッジでカウントアップ
			MTUX::TCR  = MTUX::TCR.TPSC.b(dv)
					   | MTUX::TCR.CKEG.b(0b00)
					   | MTUX::TCR.CCLR.b(cclr[idx]);  // ※インプットキャプチャ入力で TCNT はクリア
			MTUX::TCR2  = 0x00;
			MTUX::TMDR1 = 0x00;  // 通常動作

			if(level > 0) {
				set_interrupt_task(ovf_task_, static_cast<uint32_t>(MTUX::get_vec(MTUX::interrupt::OVF)));
				icu_mgr::set_level(MTUX::get_vec(MTUX::interrupt::OVF), level);
				ICU::VECTOR cvec = MTUX::get_vec(static_cast<typename MTUX::interrupt>(ch));
				set_interrupt_task(cap_task_, static_cast<uint32_t>(cvec));
				icu_mgr::set_level(MTUX::get_vec(static_cast<typename MTUX::interrupt>(ch)), level);
				MTUX::TIER = (1 << static_cast<uint8_t>(ch)) | MTUX::TIER.TCIEV.b();
			}

			task_t_.clear();

			// 各チャネルに相当するジャネラルレジスタ
			task_t_.tgr_adr_ = MTUX::TGRA.address() + static_cast<uint32_t>(ch) * 2;
			wr16_(task_t_.tgr_adr_, 0x0000);

			MTUX::TCNT = 0;

			MTUX::enable();

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  インプット・キャプチャ、リミットの設定
			@param[in]	limit	インプット・キャプチャ、リミット
		*/
		//-----------------------------------------------------------------//
		void set_capture_limit(uint16_t limit)
		{
			task_t_.limit_ovf_ = limit;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  インプット・キャプチャのオーバーフローカウント取得
			@return インプット・キャプチャのオーバーフローカウント
		*/
		//-----------------------------------------------------------------//
		uint16_t get_capture_ovf() const
		{
			return task_t_.ovf_count_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  インプット・キャプチャカウント取得
			@return インプット・キャプチャカウント
		*/
		//-----------------------------------------------------------------//
		uint16_t get_capture_tick() const
		{
			return task_t_.cap_tick_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  インプット・キャプチャ値を取得
			@return インプット・キャプチャ値
		*/
		//-----------------------------------------------------------------//
		uint32_t get_capture() const
		{
			return task_t_.cap_count_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  MTASK クラスの参照
			@return MTASK クラス
		*/
		//-----------------------------------------------------------------//
		static MTASK& at_main_task() { return mtask_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  OTASK クラスの参照
			@return OTASK クラス
		*/
		//-----------------------------------------------------------------//
		static OTASK& at_ovfl_task() { return otask_; }
	};

	template <class MTUX, class MTASK, class OTASK>
		typename mtu_io<MTUX, MTASK, OTASK>::task_t mtu_io<MTUX, MTASK, OTASK>::task_t_;
	template <class MTUX, class MTASK, class OTASK> MTASK mtu_io<MTUX, MTASK, OTASK>::mtask_;
	template <class MTUX, class MTASK, class OTASK> OTASK mtu_io<MTUX, MTASK, OTASK>::otask_;
}
<commit_msg>cleanup<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX24T グループ MTU3 制御
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "RX24T/icu_mgr.hpp"
#include "RX24T/port_map.hpp"
#include "RX24T/power_cfg.hpp"
#include "RX24T/mtu3.hpp"
#include "common/intr_utils.hpp"
#include "common/vect.h"

#include "common/format.hpp"

/// F_PCLKA は変換パラメーター計算で必要で、設定が無いとエラーにします。
#ifndef F_PCLKA
#  error "mtu_io.hpp requires F_PCLKA to be defined"
#endif

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  MTU 制御クラス
		@param[in]	MTU	MTU ユニット
		@param[in]	MTASK	メイン割り込みタスク
		@param[in]	OTASK	オーバーフロー割り込みタスク
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class MTUX, class MTASK = utils::null_task, class OTASK = utils::null_task>
	class mtu_io {
	public:

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  エッジ・タイプ
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class edge_type : uint8_t {
			positive,	///< 立ち上がり
			negative,	///< 立下り
			dual,		///< 両エッジ
		};

	private:

		struct task_t {
			volatile uint32_t	tgr_adr_;
			volatile uint32_t	cap_count_;
			volatile uint16_t	cap_tick_;
			volatile uint16_t	ovf_tick_;
			volatile uint16_t	ovf_limit_;
			volatile uint16_t	ovf_count_;

			task_t() : tgr_adr_(MTUX::TGRA.address()), cap_count_(0),
				cap_tick_(0), ovf_tick_(0),
				ovf_limit_(1221), ovf_count_(0) { }

			void clear() {
				cap_tick_ = 0;
				ovf_tick_ = 0;
				cap_count_ = 0;
				ovf_count_ = 0;
			}

			void load_cap() {
				cap_count_ = (static_cast<uint32_t>(ovf_tick_) << 16) | rd16_(tgr_adr_);
			}
		};

		static task_t	task_t_;
		static MTASK	mtask_;
		static OTASK	otask_;

		uint32_t	clk_base_;

		static INTERRUPT_FUNC void cap_task_()
		{
			++task_t_.cap_tick_;
			task_t_.load_cap();
			mtask_();
			task_t_.ovf_tick_ = 0;
		}

		static INTERRUPT_FUNC void ovf_task_()
		{
			++task_t_.ovf_tick_;
			if(task_t_.ovf_tick_ >= task_t_.ovf_limit_) {
				task_t_.ovf_tick_ = 0;
				MTUX::TCNT = 0;
				++task_t_.ovf_count_;
			}
			otask_();
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		mtu_io() noexcept : clk_base_(F_PCLKA) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  ベース・クロックの設定
			@param[in]	clk	ベース・クロック
		*/
		//-----------------------------------------------------------------//
		void set_base_clock(uint32_t clk) noexcept { clk_base_ = clk; }

		//-----------------------------------------------------------------//
		/*!
			@brief  ベース・クロックの取得
			@return ベース・クロック
		*/
		//-----------------------------------------------------------------//
		uint32_t get_base_clock() const noexcept { return clk_base_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  インプットキャプチャ開始 @n
					※カウントクロックは「set_limit_clock」により @n
					変更が可能。
			@param[in]	ch		入力チャネル
			@param[in]	et		エッジ・タイプ
			@param[in]	level	割り込みレベル（割り込みを使わない場合エラー）
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool start_capture(typename MTUX::channel ch, edge_type et, uint8_t level) noexcept
		{
			if(level == 0) return false;

			if(MTUX::get_peripheral() == peripheral::MTU5) {  // MTU5 はインプットキャプチャとして利用不可
				return false;
			}

			uint8_t idx = static_cast<uint8_t>(ch);
			if(idx >= 4) return false;

			power_cfg::turn(MTUX::get_peripheral());
			MTUX::enable_port(ch);

			uint8_t etd = 0;
			switch(et) {
			case edge_type::positive: etd = 0b1000; break;
			case edge_type::negative: etd = 0b1001; break;
			case edge_type::dual:     etd = 0b1011; break;
			default: break;
			}
			MTUX::TIOR.set(ch, etd);

			uint8_t dv = 0;
			static const uint8_t cclr[4] = { 0b001, 0b010, 0b101, 0b110 };
			// CKEG: 立ち上がりエッジでカウントアップ
			MTUX::TCR  = MTUX::TCR.TPSC.b(dv)
					   | MTUX::TCR.CKEG.b(0b00)
					   | MTUX::TCR.CCLR.b(cclr[idx]);  // ※インプットキャプチャ入力で TCNT はクリア
			MTUX::TCR2  = 0x00;
			MTUX::TMDR1 = 0x00;  // 通常動作

			if(level > 0) {
				set_interrupt_task(ovf_task_, static_cast<uint32_t>(MTUX::get_vec(MTUX::interrupt::OVF)));
				icu_mgr::set_level(MTUX::get_vec(MTUX::interrupt::OVF), level);
				ICU::VECTOR cvec = MTUX::get_vec(static_cast<typename MTUX::interrupt>(ch));
				set_interrupt_task(cap_task_, static_cast<uint32_t>(cvec));
				icu_mgr::set_level(MTUX::get_vec(static_cast<typename MTUX::interrupt>(ch)), level);
				MTUX::TIER = (1 << static_cast<uint8_t>(ch)) | MTUX::TIER.TCIEV.b();
			}

			task_t_.clear();

			// 各チャネルに相当するジャネラルレジスタ
			task_t_.tgr_adr_ = MTUX::TGRA.address() + static_cast<uint32_t>(ch) * 2;
			wr16_(task_t_.tgr_adr_, 0x0000);

			MTUX::TCNT = 0;

			MTUX::enable();

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  インプット・キャプチャ、リミットの設定
			@param[in]	limit	インプット・キャプチャ、リミット
		*/
		//-----------------------------------------------------------------//
		void set_capture_limit(uint16_t limit) noexcept
		{
			task_t_.limit_ovf_ = limit;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  インプット・キャプチャのオーバーフローカウント取得
			@return インプット・キャプチャのオーバーフローカウント
		*/
		//-----------------------------------------------------------------//
		uint16_t get_capture_ovf() const noexcept
		{
			return task_t_.ovf_count_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  インプット・キャプチャカウント取得
			@return インプット・キャプチャカウント
		*/
		//-----------------------------------------------------------------//
		uint16_t get_capture_tick() const noexcept
		{
			return task_t_.cap_tick_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  インプット・キャプチャ値を取得
			@return インプット・キャプチャ値
		*/
		//-----------------------------------------------------------------//
		uint32_t get_capture() const noexcept
		{
			return task_t_.cap_count_;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  MTASK クラスの参照
			@return MTASK クラス
		*/
		//-----------------------------------------------------------------//
		static MTASK& at_main_task() noexcept { return mtask_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  OTASK クラスの参照
			@return OTASK クラス
		*/
		//-----------------------------------------------------------------//
		static OTASK& at_ovfl_task() noexcept { return otask_; }
	};

	template <class MTUX, class MTASK, class OTASK>
		typename mtu_io<MTUX, MTASK, OTASK>::task_t mtu_io<MTUX, MTASK, OTASK>::task_t_;
	template <class MTUX, class MTASK, class OTASK> MTASK mtu_io<MTUX, MTASK, OTASK>::mtask_;
	template <class MTUX, class MTASK, class OTASK> OTASK mtu_io<MTUX, MTASK, OTASK>::otask_;
}
<|endoftext|>


<commit_before>#include "SecureSocket.hpp"
#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sstream>
#include <iostream>

#include "Timer.hpp"

using namespace Kite;

//#define debugprintf(...) fprintf(stderr, __VA_ARGS__)
#define debugprintf(...)

//TODO: not thread safe
static std::map<SSL  *, SecureSocket *> rebind_map;

class Kite::SecureSocketPrivate : public Kite::Evented {
public:
    SSL_CTX *ssl_ctx;
    BIO     *bio;
    SSL     *ssl; //do note delete, is a ref from bio
    SecureSocket::SocketState state;
    std::string errorMessage;

    bool useTls;
    bool  hasTimeout;
    Timer connectionTimout;

    SecureSocket *p;
    void d_connect();

    SecureSocketPrivate(std::weak_ptr<Kite::EventLoop> ev)
        : Kite::Evented(ev)
        , connectionTimout(ev)
    {
        KITE_TIMER_DEBUG_NAME(&connectionTimout, "Kite::SecureSocketPrivate::connectionTimout");
    }
    virtual void onActivated (int)
    {
        if (state == Kite::SecureSocket::Connecting) {
            d_connect();
        } else if (state == Kite::SecureSocket::Connected) {
            p->onActivated(0);
        }
    }
    friend class Kite::SecureSocket;
};

void apps_ssl_info_callback(const SSL *s, int where, int ret)
{
    const char *str;
    int w;
    w=where& ~SSL_ST_MASK;
    if (w & SSL_ST_CONNECT) str="SSL_connect";
    else if (w & SSL_ST_ACCEPT) str="SSL_accept";
    else str="undefined";
    if (where & SSL_CB_LOOP)
    {
        debugprintf("%s:%s\n",str,SSL_state_string_long(s));
    }
    else if (where & SSL_CB_ALERT)
    {
        str=(where & SSL_CB_READ)?"read":"write";
        debugprintf("SSL3 alert %s:%s:%s\n",
                str,
                SSL_alert_type_string_long(ret),
                SSL_alert_desc_string_long(ret));
    }
    else if (where & SSL_CB_EXIT)
    {
        if (ret == 0)
            debugprintf("%s:failed in %s\n",
                    str,SSL_state_string_long(s));
        else if (ret < 0)
        {
            debugprintf("%s:error in %s\n",
                    str,SSL_state_string_long(s));
        }
    }
}

SecureSocket::SecureSocket(std::weak_ptr<Kite::EventLoop> ev)
    : p(new SecureSocketPrivate(ev))
{
    static bool sslIsInit = false;
    if (!sslIsInit) {
        SSL_load_error_strings();
        SSL_library_init();
        ERR_load_BIO_strings();
        OpenSSL_add_all_algorithms();
    }
    p->p = this;
    p->ssl_ctx = 0;
    p->bio     = 0;
    p->ssl     = 0;
    p->state   = Disconnected;

    // init ssl context
    p->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
    if (p->ssl_ctx == NULL)
    {
        ERR_print_errors_fp(stderr);
        return;
    }

    SSL_CTX_set_info_callback(p->ssl_ctx, apps_ssl_info_callback);

}

SecureSocket::~SecureSocket()
{
    disconnect();

    if (p->bio)
        BIO_free_all(p->bio);

    if (p->ssl_ctx)
        SSL_CTX_free(p->ssl_ctx);

    delete p;
}

bool SecureSocket::setCaDir (const std::string &path)
{
    int r = SSL_CTX_load_verify_locations(p->ssl_ctx, NULL, path.c_str());
    if (r == 0) {
        return false;
    }
    return true;
}

bool SecureSocket::setCaFile(const std::string &path)
{
    int r = SSL_CTX_load_verify_locations(p->ssl_ctx, path.c_str(), NULL);
    if (r == 0) {
        return false;
    }
    return true;
}
bool SecureSocket::setClientCertificateFile(const std::string &path)
{
    int r = SSL_CTX_use_certificate_file(p->ssl_ctx, path.c_str(), SSL_FILETYPE_PEM);
    if (r == 0) {
        return false;
    }
    return true;
}

bool SecureSocket::setClientKeyFile(const std::string &path)
{
    int r = SSL_CTX_use_PrivateKey_file(p->ssl_ctx, path.c_str(), SSL_FILETYPE_PEM);
    if (r == 0) {
        return false;
    }
    return true;
}

void SecureSocket::disconnect()
{
    int fd = 0;
    BIO_get_fd(p->bio, &fd);
    if (fd != 0)
        p->evRemove(fd);

    if (p->ssl) {
        auto e = rebind_map.find(p->ssl);
        if (e != rebind_map.end())
            rebind_map.erase(e);
    }

    if (p->bio)
        BIO_ssl_shutdown(p->bio);

    if (p->state == Connected || p->state == Connecting)
        p->state = Disconnected;
    onDisconnected(p->state);
}

void SecureSocket::connect(const std::string &hostname, int port, uint64_t timeout, bool tls)
{
    p->useTls = tls;
    if (timeout > 0) {
        p->hasTimeout = true;
        p->connectionTimout.reset(timeout);
    }
    p->state   = Connecting;
    int r = 0;

    if (p->useTls) {
        p->bio = BIO_new_ssl_connect(p->ssl_ctx);
    } else {
        std::vector<char> host_c(hostname.begin(), hostname.end());
        host_c.push_back('\0');
        p->bio = BIO_new_connect(&host_c[0]);
    }
    if (!p->bio) {
        p->errorMessage = "BIO_new_ssl_connect returned NULL";
        p->state        = SecureSetupError;
        disconnect();
        return;
    }

    BIO_set_nbio(p->bio, 1);

    if (p->useTls) {
        BIO_get_ssl(p->bio, &p->ssl);
        if (!(p->ssl)) {
            p->errorMessage = "BIO_get_ssl returned NULL";
            p->state        = SecureSetupError;
            disconnect();
            return;
        }

        rebind_map.insert(std::make_pair(p->ssl, this));
        auto cb = [](SSL *ssl, X509 **x509, EVP_PKEY **pkey) {
            SecureSocket *that = rebind_map[ssl];
            that->p->errorMessage = "Client Certificate Requested\n";
            that->p->state = SecureClientCertificateRequired;
            that->disconnect();
            return 0;
        };
        SSL_CTX_set_client_cert_cb(p->ssl_ctx, cb);

        SSL_set_mode(p->ssl, SSL_MODE_AUTO_RETRY);
    }
    BIO_set_conn_hostname(p->bio, hostname.c_str());
    BIO_set_conn_int_port(p->bio, &port);

    p->d_connect();
}
void SecureSocketPrivate::d_connect()
{
    if (hasTimeout) {
        if (connectionTimout.expires() < 1) {
            errorMessage = "Connection timed out";
            state        = SecureSocket::TransportErrror;
            p->disconnect();
            return;
        }
    }
    int r  = BIO_do_connect(bio);
    if (r < 1) {
        if (BIO_should_retry(bio)) {
            // rety imidiately.
            // this seems how to do it properly, but i cant get it working:
            // https://github.com/jmckaskill/bio_poll/blob/master/poll.c
            // probably because BIO_get_fd is garbage before connect?
            Timer::later(ev(), [this](){
                    d_connect();
                    return false;
                    }, 100, "BIO_should_retry");
            return;
        }
        if (state != SecureSocket::SecureClientCertificateRequired) {
            const char *em = ERR_reason_error_string(ERR_get_error());
            debugprintf( "BIO_new_ssl_connect failed: %u (0x%x)\n", r, r);
            debugprintf( "Error: %s\n", em);
            debugprintf( "%s\n", ERR_error_string(ERR_get_error(), NULL));
            if (useTls) {
                debugprintf("p_ssl state: %s\n",SSL_state_string_long(ssl));
            }
            ERR_print_errors_fp(stderr);
            errorMessage = std::string(em ? strdup(em) : "??");
            state        = SecureSocket::TransportErrror;
        }
        p->disconnect();
        return;
    }

    if (useTls) {
        auto result = SSL_get_verify_result(ssl);
        if (result != X509_V_OK) {
            std::stringstream str;
            str << "Secure Peer Verification Errror " << result;
            errorMessage = str.str();
            state        = SecureSocket::SecurePeerNotVerified;
            p->disconnect();
            return;
        }
    }

    int fd = 0;
    BIO_get_fd(bio, &fd);
    if (fd == 0) {
        errorMessage = "BIO_get_fd returned 0";
        state        = SecureSocket::SecureSetupError;
        p->disconnect();
        return;
    }
    evAdd(fd);

    state        = SecureSocket::Connected;
    p->onConnected();
}

int SecureSocket::write(const char *data, int len)
{
    if (p->state != Connected)
        return 0;

    int r;
    do {
        r = BIO_write(p->bio, data, len);
    } while (r < 0 && BIO_should_retry(p->bio));
    return len;
}

int SecureSocket::read (char *data, int len)
{
    if (p->state != Connected)
        return 0;
    int e = BIO_read(p->bio, data, len);
    if (e > -1)
        return e;
    if (BIO_should_retry(p->bio))
        return -1;
    return -2;
}

const std::string &SecureSocket::errorMessage() const
{
    return p->errorMessage;
}

void SecureSocket::flush()
{
    BIO_flush(p->bio);
}

const std::shared_ptr<EventLoop> SecureSocket::ev() const
{
    return p->ev();
}
<commit_msg>Schedule activations for unread data in sockets<commit_after>#include "SecureSocket.hpp"
#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sstream>
#include <iostream>

#include "Timer.hpp"

using namespace Kite;

//#define debugprintf(...) fprintf(stderr, __VA_ARGS__)
#define debugprintf(...)

//TODO: not thread safe
static std::map<SSL  *, SecureSocket *> rebind_map;

class Kite::SecureSocketPrivate : public Kite::Evented {
public:
    SSL_CTX *ssl_ctx;
    BIO     *bio;
    SSL     *ssl; //do note delete, is a ref from bio
    SecureSocket::SocketState state;
    std::string errorMessage;

    bool useTls;
    bool  hasTimeout;
    Timer connectionTimout;

    SecureSocket *p;
    void d_connect();

    SecureSocketPrivate(std::weak_ptr<Kite::EventLoop> ev)
        : Kite::Evented(ev)
        , connectionTimout(ev)
    {
        KITE_TIMER_DEBUG_NAME(&connectionTimout, "Kite::SecureSocketPrivate::connectionTimout");
    }
    virtual void onActivated (int)
    {
        if (state == Kite::SecureSocket::Connecting) {
            d_connect();
        } else if (state == Kite::SecureSocket::Connected) {
            p->onActivated(0);
            if (BIO_pending(bio)) {
                Timer::later(ev(), [this](){
                    onActivated(0);
                    return false;
                }, 1, "BIO_pending after read");
            }
        }
    }
    friend class Kite::SecureSocket;
};

void apps_ssl_info_callback(const SSL *s, int where, int ret)
{
    const char *str;
    int w;
    w=where& ~SSL_ST_MASK;
    if (w & SSL_ST_CONNECT) str="SSL_connect";
    else if (w & SSL_ST_ACCEPT) str="SSL_accept";
    else str="undefined";
    if (where & SSL_CB_LOOP)
    {
        debugprintf("%s:%s\n",str,SSL_state_string_long(s));
    }
    else if (where & SSL_CB_ALERT)
    {
        str=(where & SSL_CB_READ)?"read":"write";
        debugprintf("SSL3 alert %s:%s:%s\n",
                str,
                SSL_alert_type_string_long(ret),
                SSL_alert_desc_string_long(ret));
    }
    else if (where & SSL_CB_EXIT)
    {
        if (ret == 0)
            debugprintf("%s:failed in %s\n",
                    str,SSL_state_string_long(s));
        else if (ret < 0)
        {
            debugprintf("%s:error in %s\n",
                    str,SSL_state_string_long(s));
        }
    }
}

SecureSocket::SecureSocket(std::weak_ptr<Kite::EventLoop> ev)
    : p(new SecureSocketPrivate(ev))
{
    static bool sslIsInit = false;
    if (!sslIsInit) {
        SSL_load_error_strings();
        SSL_library_init();
        ERR_load_BIO_strings();
        OpenSSL_add_all_algorithms();
    }
    p->p = this;
    p->ssl_ctx = 0;
    p->bio     = 0;
    p->ssl     = 0;
    p->state   = Disconnected;

    // init ssl context
    p->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
    if (p->ssl_ctx == NULL)
    {
        ERR_print_errors_fp(stderr);
        return;
    }

    SSL_CTX_set_info_callback(p->ssl_ctx, apps_ssl_info_callback);

}

SecureSocket::~SecureSocket()
{
    disconnect();

    if (p->bio)
        BIO_free_all(p->bio);

    if (p->ssl_ctx)
        SSL_CTX_free(p->ssl_ctx);

    delete p;
}

bool SecureSocket::setCaDir (const std::string &path)
{
    int r = SSL_CTX_load_verify_locations(p->ssl_ctx, NULL, path.c_str());
    if (r == 0) {
        return false;
    }
    return true;
}

bool SecureSocket::setCaFile(const std::string &path)
{
    int r = SSL_CTX_load_verify_locations(p->ssl_ctx, path.c_str(), NULL);
    if (r == 0) {
        return false;
    }
    return true;
}
bool SecureSocket::setClientCertificateFile(const std::string &path)
{
    int r = SSL_CTX_use_certificate_file(p->ssl_ctx, path.c_str(), SSL_FILETYPE_PEM);
    if (r == 0) {
        return false;
    }
    return true;
}

bool SecureSocket::setClientKeyFile(const std::string &path)
{
    int r = SSL_CTX_use_PrivateKey_file(p->ssl_ctx, path.c_str(), SSL_FILETYPE_PEM);
    if (r == 0) {
        return false;
    }
    return true;
}

void SecureSocket::disconnect()
{
    int fd = 0;
    BIO_get_fd(p->bio, &fd);
    if (fd != 0)
        p->evRemove(fd);

    if (p->ssl) {
        auto e = rebind_map.find(p->ssl);
        if (e != rebind_map.end())
            rebind_map.erase(e);
    }

    if (p->bio)
        BIO_ssl_shutdown(p->bio);

    if (p->state == Connected || p->state == Connecting)
        p->state = Disconnected;
    onDisconnected(p->state);
}

void SecureSocket::connect(const std::string &hostname, int port, uint64_t timeout, bool tls)
{
    p->useTls = tls;
    if (timeout > 0) {
        p->hasTimeout = true;
        p->connectionTimout.reset(timeout);
    }
    p->state   = Connecting;
    int r = 0;

    if (p->useTls) {
        p->bio = BIO_new_ssl_connect(p->ssl_ctx);
    } else {
        std::vector<char> host_c(hostname.begin(), hostname.end());
        host_c.push_back('\0');
        p->bio = BIO_new_connect(&host_c[0]);
    }
    if (!p->bio) {
        p->errorMessage = "BIO_new_ssl_connect returned NULL";
        p->state        = SecureSetupError;
        disconnect();
        return;
    }

    BIO_set_nbio(p->bio, 1);

    if (p->useTls) {
        BIO_get_ssl(p->bio, &p->ssl);
        if (!(p->ssl)) {
            p->errorMessage = "BIO_get_ssl returned NULL";
            p->state        = SecureSetupError;
            disconnect();
            return;
        }

        rebind_map.insert(std::make_pair(p->ssl, this));
        auto cb = [](SSL *ssl, X509 **x509, EVP_PKEY **pkey) {
            SecureSocket *that = rebind_map[ssl];
            that->p->errorMessage = "Client Certificate Requested\n";
            that->p->state = SecureClientCertificateRequired;
            that->disconnect();
            return 0;
        };
        SSL_CTX_set_client_cert_cb(p->ssl_ctx, cb);

        SSL_set_mode(p->ssl, SSL_MODE_AUTO_RETRY);
    }
    BIO_set_conn_hostname(p->bio, hostname.c_str());
    BIO_set_conn_int_port(p->bio, &port);

    p->d_connect();
}
void SecureSocketPrivate::d_connect()
{
    if (hasTimeout) {
        if (connectionTimout.expires() < 1) {
            errorMessage = "Connection timed out";
            state        = SecureSocket::TransportErrror;
            p->disconnect();
            return;
        }
    }
    int r  = BIO_do_connect(bio);
    if (r < 1) {
        if (BIO_should_retry(bio)) {
            // rety imidiately.
            // this seems how to do it properly, but i cant get it working:
            // https://github.com/jmckaskill/bio_poll/blob/master/poll.c
            // probably because BIO_get_fd is garbage before connect?
            Timer::later(ev(), [this](){
                    d_connect();
                    return false;
                    }, 100, "BIO_should_retry");
            return;
        }
        if (state != SecureSocket::SecureClientCertificateRequired) {
            const char *em = ERR_reason_error_string(ERR_get_error());
            debugprintf( "BIO_new_ssl_connect failed: %u (0x%x)\n", r, r);
            debugprintf( "Error: %s\n", em);
            debugprintf( "%s\n", ERR_error_string(ERR_get_error(), NULL));
            if (useTls) {
                debugprintf("p_ssl state: %s\n",SSL_state_string_long(ssl));
            }
            ERR_print_errors_fp(stderr);
            errorMessage = std::string(em ? strdup(em) : "??");
            state        = SecureSocket::TransportErrror;
        }
        p->disconnect();
        return;
    }

    if (useTls) {
        auto result = SSL_get_verify_result(ssl);
        if (result != X509_V_OK) {
            std::stringstream str;
            str << "Secure Peer Verification Errror " << result;
            errorMessage = str.str();
            state        = SecureSocket::SecurePeerNotVerified;
            p->disconnect();
            return;
        }
    }

    int fd = 0;
    BIO_get_fd(bio, &fd);
    if (fd == 0) {
        errorMessage = "BIO_get_fd returned 0";
        state        = SecureSocket::SecureSetupError;
        p->disconnect();
        return;
    }
    evAdd(fd);

    state        = SecureSocket::Connected;
    p->onConnected();
}

int SecureSocket::write(const char *data, int len)
{
    if (p->state != Connected)
        return 0;

    int r;
    do {
        r = BIO_write(p->bio, data, len);
    } while (r < 0 && BIO_should_retry(p->bio));
    return len;
}

int SecureSocket::read (char *data, int len)
{
    if (p->state != Connected)
        return 0;
    int e = BIO_read(p->bio, data, len);
    if (e > -1)
        return e;
    if (BIO_should_retry(p->bio))
        return -1;
    return -2;
}

const std::string &SecureSocket::errorMessage() const
{
    return p->errorMessage;
}

void SecureSocket::flush()
{
    BIO_flush(p->bio);
}

const std::shared_ptr<EventLoop> SecureSocket::ev() const
{
    return p->ev();
}
<|endoftext|>


<commit_before>/* Cycript - Optimizing JavaScript Compiler/Runtime
 * Copyright (C) 2009-2013  Jay Freeman (saurik)
*/

/* GNU General Public License, Version 3 {{{ */
/*
 * Cycript is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * Cycript 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Cycript.  If not, see <http://www.gnu.org/licenses/>.
**/
/* }}} */

#define _PTHREAD_ATTR_T
#include <pthread_internals.h>

#include <mach-o/dyld.h>
#include <mach-o/dyld_images.h>
#include <mach-o/loader.h>

extern "C" {
#include <mach-o/nlist.h>
}

#include "Standard.hpp"
#include "Baton.hpp"

static void $bzero(void *data, size_t size) {
    char *bytes(reinterpret_cast<char *>(data));
    for (size_t i(0); i != size; ++i)
        bytes[i] = 0;
}

static int $strcmp(const char *lhs, const char *rhs) {
    while (*lhs == *rhs) {
        if (*lhs == '\0')
            return 0;
        ++lhs, ++rhs;
    } return *lhs < *rhs ? -1 : 1;
}

#ifdef __LP64__
typedef struct mach_header_64 mach_header_xx;
typedef struct nlist_64 nlist_xx;
typedef struct segment_command_64 segment_command_xx;

static const uint32_t LC_SEGMENT_XX = LC_SEGMENT_64;
static const uint32_t MH_MAGIC_XX = MH_MAGIC_64;
#else
typedef struct mach_header mach_header_xx;
typedef struct nlist nlist_xx;
typedef struct segment_command segment_command_xx;

static const uint32_t LC_SEGMENT_XX = LC_SEGMENT;
static const uint32_t MH_MAGIC_XX = MH_MAGIC;
#endif

#define forlc(command, mach, lc, type) \
    if (const struct load_command *load_commands = reinterpret_cast<const struct load_command *>(mach + 1)) \
        if (const struct load_command *lcp = load_commands) \
            for (uint32_t i(0); i != mach->ncmds; ++i, lcp = reinterpret_cast<const struct load_command *>(reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize)) \
                if ( \
                    lcp->cmdsize % sizeof(long) != 0 || lcp->cmdsize <= 0 || \
                    reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize > reinterpret_cast<const uint8_t *>(load_commands) + mach->sizeofcmds \
                ) \
                    return NULL; \
                else if (lcp->cmd != lc) \
                    continue; \
                else if (lcp->cmdsize < sizeof(type)) \
                    return NULL; \
                else if (const type *command = reinterpret_cast<const type *>(lcp))

static void *Symbol(struct dyld_all_image_infos *infos, const char *library, const char *name) {
    const dyld_image_info *info(NULL);
    for (uint32_t i(0); i != infos->infoArrayCount; ++i)
        if ($strcmp(infos->infoArray[i].imageFilePath, library) == 0)
            info = &infos->infoArray[i];
    if (info == NULL)
        return NULL;

    const mach_header_xx *mach(reinterpret_cast<const mach_header_xx *>(info->imageLoadAddress));
    if (mach->magic != MH_MAGIC_XX)
        return NULL;

    const struct symtab_command *stp(NULL);
    forlc (command, mach, LC_SYMTAB, struct symtab_command)
        stp = command;
    if (stp == NULL)
        return NULL;

    size_t slide(_not(size_t));
    const nlist_xx *symbols(NULL);
    const char *strings(NULL);

    forlc (segment, mach, LC_SEGMENT_XX, segment_command_xx) {
        if (segment->fileoff == 0)
            slide = reinterpret_cast<size_t>(mach) - segment->vmaddr;
        if (stp->symoff >= segment->fileoff && stp->symoff < segment->fileoff + segment->filesize)
            symbols = reinterpret_cast<const nlist_xx *>(stp->symoff - segment->fileoff + segment->vmaddr + slide);
        if (stp->stroff >= segment->fileoff && stp->stroff < segment->fileoff + segment->filesize)
            strings = reinterpret_cast<const char *>(stp->stroff - segment->fileoff + segment->vmaddr + slide);
    }

    if (slide == _not(size_t) || symbols == NULL || strings == NULL)
        return NULL;

    for (size_t i(0); i != stp->nsyms; ++i) {
        const nlist_xx *symbol(&symbols[i]);
        if (symbol->n_un.n_strx == 0 || (symbol->n_type & N_STAB) != 0)
            continue;

        const char *nambuf(strings + symbol->n_un.n_strx);
        if ($strcmp(name, nambuf) != 0)
            continue;

        uintptr_t value(symbol->n_value);
        if (value == 0)
            continue;

        value += slide;
        return reinterpret_cast<void *>(value);
    }

    return NULL;
}

struct Dynamic {
    char *(*dlerror)();
    void *(*dlsym)(void *, const char *);
};

template <typename Type_>
static _finline void dlset(Dynamic *dynamic, Type_ &function, const char *name, void *handle = RTLD_DEFAULT) {
    function = reinterpret_cast<Type_>(dynamic->dlsym(handle, name));
    if (function == NULL)
        dynamic->dlerror();
}

template <typename Type_>
static _finline void cyset(Baton *baton, Type_ &function, const char *name, const char *library) {
    struct dyld_all_image_infos *infos(reinterpret_cast<struct dyld_all_image_infos *>(baton->dyld));
    function = reinterpret_cast<Type_>(Symbol(infos, library, name));
}

// XXX: where you find this needs to be relative to CoreFoundation (or something)
// XXX: this needs to check if the framework is under PrivateFrameworks instead
#define Framework(framework) \
    "/System/Library/Frameworks/" #framework ".framework/" #framework

void *Routine(void *arg) {
    Baton *baton(reinterpret_cast<Baton *>(arg));

    Dynamic dynamic;
    cyset(baton, dynamic.dlerror, "_dlerror", "/usr/lib/system/libdyld.dylib");
    cyset(baton, dynamic.dlsym, "_dlsym", "/usr/lib/system/libdyld.dylib");

    int (*pthread_detach)(pthread_t);
    dlset(&dynamic, pthread_detach, "pthread_detach");

    pthread_t (*pthread_self)();
    dlset(&dynamic, pthread_self, "pthread_self");

    pthread_detach(pthread_self());

    void *(*dlopen)(const char *, int);
    dlset(&dynamic, dlopen, "dlopen");

    if (dynamic.dlsym(RTLD_DEFAULT, "JSEvaluateScript") == NULL)
        dlopen(Framework(JavaScriptCore), RTLD_GLOBAL | RTLD_LAZY);

    void *(*objc_getClass)(const char *);
    dlset(&dynamic, objc_getClass, "objc_getClass");

    if (objc_getClass("WebUndefined") == NULL)
        dlopen(Framework(WebKit), RTLD_GLOBAL | RTLD_LAZY);

    void *handle(dlopen(baton->library, RTLD_LAZY | RTLD_LOCAL));
    if (handle == NULL) {
        dynamic.dlerror();
        return NULL;
    }

    void (*CYHandleServer)(pid_t);
    dlset(&dynamic, CYHandleServer, "CYHandleServer", handle);
    if (CYHandleServer == NULL) {
        dynamic.dlerror();
        return NULL;
    }

    CYHandleServer(baton->pid);
    return NULL;
}

extern "C" void Start(Baton *baton) {
    struct _pthread self;
    $bzero(&self, sizeof(self));

    void (*$__pthread_set_self)(pthread_t);
    cyset(baton, $__pthread_set_self, "___pthread_set_self", "/usr/lib/system/libsystem_c.dylib");

    self.tsd[0] = &self;
    $__pthread_set_self(&self);

    int (*$pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *);
    cyset(baton, $pthread_create, "_pthread_create", "/usr/lib/system/libsystem_c.dylib");

    pthread_t thread;
    $pthread_create(&thread, NULL, &Routine, baton);

    mach_port_t (*$mach_thread_self)();
    cyset(baton, $mach_thread_self, "_mach_thread_self", "/usr/lib/system/libsystem_kernel.dylib");

    kern_return_t (*$thread_terminate)(thread_act_t);
    cyset(baton, $thread_terminate, "_thread_terminate", "/usr/lib/system/libsystem_kernel.dylib");

    $thread_terminate($mach_thread_self());
}
<commit_msg>Remove obsolete attempts to support the Simulator.<commit_after>/* Cycript - Optimizing JavaScript Compiler/Runtime
 * Copyright (C) 2009-2013  Jay Freeman (saurik)
*/

/* GNU General Public License, Version 3 {{{ */
/*
 * Cycript is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * Cycript 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Cycript.  If not, see <http://www.gnu.org/licenses/>.
**/
/* }}} */

#define _PTHREAD_ATTR_T
#include <pthread_internals.h>

#include <mach-o/dyld.h>
#include <mach-o/dyld_images.h>
#include <mach-o/loader.h>

extern "C" {
#include <mach-o/nlist.h>
}

#include "Standard.hpp"
#include "Baton.hpp"

static void $bzero(void *data, size_t size) {
    char *bytes(reinterpret_cast<char *>(data));
    for (size_t i(0); i != size; ++i)
        bytes[i] = 0;
}

static int $strcmp(const char *lhs, const char *rhs) {
    while (*lhs == *rhs) {
        if (*lhs == '\0')
            return 0;
        ++lhs, ++rhs;
    } return *lhs < *rhs ? -1 : 1;
}

#ifdef __LP64__
typedef struct mach_header_64 mach_header_xx;
typedef struct nlist_64 nlist_xx;
typedef struct segment_command_64 segment_command_xx;

static const uint32_t LC_SEGMENT_XX = LC_SEGMENT_64;
static const uint32_t MH_MAGIC_XX = MH_MAGIC_64;
#else
typedef struct mach_header mach_header_xx;
typedef struct nlist nlist_xx;
typedef struct segment_command segment_command_xx;

static const uint32_t LC_SEGMENT_XX = LC_SEGMENT;
static const uint32_t MH_MAGIC_XX = MH_MAGIC;
#endif

#define forlc(command, mach, lc, type) \
    if (const struct load_command *load_commands = reinterpret_cast<const struct load_command *>(mach + 1)) \
        if (const struct load_command *lcp = load_commands) \
            for (uint32_t i(0); i != mach->ncmds; ++i, lcp = reinterpret_cast<const struct load_command *>(reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize)) \
                if ( \
                    lcp->cmdsize % sizeof(long) != 0 || lcp->cmdsize <= 0 || \
                    reinterpret_cast<const uint8_t *>(lcp) + lcp->cmdsize > reinterpret_cast<const uint8_t *>(load_commands) + mach->sizeofcmds \
                ) \
                    return NULL; \
                else if (lcp->cmd != lc) \
                    continue; \
                else if (lcp->cmdsize < sizeof(type)) \
                    return NULL; \
                else if (const type *command = reinterpret_cast<const type *>(lcp))

static void *Symbol(struct dyld_all_image_infos *infos, const char *library, const char *name) {
    const dyld_image_info *info(NULL);
    for (uint32_t i(0); i != infos->infoArrayCount; ++i)
        if ($strcmp(infos->infoArray[i].imageFilePath, library) == 0)
            info = &infos->infoArray[i];
    if (info == NULL)
        return NULL;

    const mach_header_xx *mach(reinterpret_cast<const mach_header_xx *>(info->imageLoadAddress));
    if (mach->magic != MH_MAGIC_XX)
        return NULL;

    const struct symtab_command *stp(NULL);
    forlc (command, mach, LC_SYMTAB, struct symtab_command)
        stp = command;
    if (stp == NULL)
        return NULL;

    size_t slide(_not(size_t));
    const nlist_xx *symbols(NULL);
    const char *strings(NULL);

    forlc (segment, mach, LC_SEGMENT_XX, segment_command_xx) {
        if (segment->fileoff == 0)
            slide = reinterpret_cast<size_t>(mach) - segment->vmaddr;
        if (stp->symoff >= segment->fileoff && stp->symoff < segment->fileoff + segment->filesize)
            symbols = reinterpret_cast<const nlist_xx *>(stp->symoff - segment->fileoff + segment->vmaddr + slide);
        if (stp->stroff >= segment->fileoff && stp->stroff < segment->fileoff + segment->filesize)
            strings = reinterpret_cast<const char *>(stp->stroff - segment->fileoff + segment->vmaddr + slide);
    }

    if (slide == _not(size_t) || symbols == NULL || strings == NULL)
        return NULL;

    for (size_t i(0); i != stp->nsyms; ++i) {
        const nlist_xx *symbol(&symbols[i]);
        if (symbol->n_un.n_strx == 0 || (symbol->n_type & N_STAB) != 0)
            continue;

        const char *nambuf(strings + symbol->n_un.n_strx);
        if ($strcmp(name, nambuf) != 0)
            continue;

        uintptr_t value(symbol->n_value);
        if (value == 0)
            continue;

        value += slide;
        return reinterpret_cast<void *>(value);
    }

    return NULL;
}

struct Dynamic {
    char *(*dlerror)();
    void *(*dlsym)(void *, const char *);
};

template <typename Type_>
static _finline void dlset(Dynamic *dynamic, Type_ &function, const char *name, void *handle = RTLD_DEFAULT) {
    function = reinterpret_cast<Type_>(dynamic->dlsym(handle, name));
    if (function == NULL)
        dynamic->dlerror();
}

template <typename Type_>
static _finline void cyset(Baton *baton, Type_ &function, const char *name, const char *library) {
    struct dyld_all_image_infos *infos(reinterpret_cast<struct dyld_all_image_infos *>(baton->dyld));
    function = reinterpret_cast<Type_>(Symbol(infos, library, name));
}

void *Routine(void *arg) {
    Baton *baton(reinterpret_cast<Baton *>(arg));

    Dynamic dynamic;
    cyset(baton, dynamic.dlerror, "_dlerror", "/usr/lib/system/libdyld.dylib");
    cyset(baton, dynamic.dlsym, "_dlsym", "/usr/lib/system/libdyld.dylib");

    int (*pthread_detach)(pthread_t);
    dlset(&dynamic, pthread_detach, "pthread_detach");

    pthread_t (*pthread_self)();
    dlset(&dynamic, pthread_self, "pthread_self");

    pthread_detach(pthread_self());

    void *(*dlopen)(const char *, int);
    dlset(&dynamic, dlopen, "dlopen");

    void *handle(dlopen(baton->library, RTLD_LAZY | RTLD_LOCAL));
    if (handle == NULL) {
        dynamic.dlerror();
        return NULL;
    }

    void (*CYHandleServer)(pid_t);
    dlset(&dynamic, CYHandleServer, "CYHandleServer", handle);
    if (CYHandleServer == NULL) {
        dynamic.dlerror();
        return NULL;
    }

    CYHandleServer(baton->pid);
    return NULL;
}

extern "C" void Start(Baton *baton) {
    struct _pthread self;
    $bzero(&self, sizeof(self));

    void (*$__pthread_set_self)(pthread_t);
    cyset(baton, $__pthread_set_self, "___pthread_set_self", "/usr/lib/system/libsystem_c.dylib");

    self.tsd[0] = &self;
    $__pthread_set_self(&self);

    int (*$pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *);
    cyset(baton, $pthread_create, "_pthread_create", "/usr/lib/system/libsystem_c.dylib");

    pthread_t thread;
    $pthread_create(&thread, NULL, &Routine, baton);

    mach_port_t (*$mach_thread_self)();
    cyset(baton, $mach_thread_self, "_mach_thread_self", "/usr/lib/system/libsystem_kernel.dylib");

    kern_return_t (*$thread_terminate)(thread_act_t);
    cyset(baton, $thread_terminate, "_thread_terminate", "/usr/lib/system/libsystem_kernel.dylib");

    $thread_terminate($mach_thread_self());
}
<|endoftext|>


<commit_before>#include <PCU.h>
#include "phBC.h"
#include <apf.h>
#include <apfMesh.h>
#include <fstream>
#include <sstream>
#include <gmi.h>

namespace ph {

BC::BC()
{
  values = 0;
}

BC::~BC()
{
  delete [] values;
}

bool BC::operator<(const BC& other) const
{
  if (dim != other.dim)
    return dim < other.dim;
  return tag < other.tag;
}

static struct { const char* name; int size; } const knownSizes[4] =
{{"initial velocity", 3}
,{"comp1", 4}
,{"comp3", 4}
,{"traction vector", 3}
};

static int getSize(std::string const& name)
{
  for (int i = 0; i < 4; ++i)
    if (name == knownSizes[i].name)
      return knownSizes[i].size;
  return 1;
}

static void readBC(std::string const& line, BCs& bcs)
{
  std::stringstream ss(line);
  std::string name;
  std::getline(ss, name, ':');
  if (!bcs.fields.count(name)) {
    FieldBCs fbcs;
    fbcs.size = getSize(name);
    bcs.fields[name] = fbcs;
  }
  FieldBCs& fbcs = bcs.fields[name];
  BC bc;
  ss >> bc.tag >> bc.dim;
  bc.values = new double[fbcs.size];
  for (int i = 0; i < fbcs.size; ++i)
    ss >> bc.values[i];
  fbcs.bcs.insert(bc);
  bc.values = 0; //ownership of pointer transferred, prevent delete from here
}

void readBCs(const char* filename, BCs& bcs)
{
  double t0 = MPI_Wtime();
  std::ifstream file(filename);
  std::string line;
  while (std::getline(file, line, '\n')) {
    if (line[0] == '#')
      continue;
    readBC(line, bcs);
  }
  double t1 = MPI_Wtime();
  if (!PCU_Comm_Self())
    printf("\"%s\" loaded in %f seconds\n", filename, t1 - t0);
}

struct KnownBC
{
  const char* name;
  int offset;
  int bit;
  void (*apply)(double* values, int* bits,
    struct KnownBC const& bc, double* inval);
};

static bool applyBit2(int* bits, int bit)
{
  if (bit == -1)
    return true;
  int mask = (1<<bit);
  if (*bits & mask)
    return false;
  *bits |= mask;
  return true;
}

static void applyBit(double*, int* bits,
    KnownBC const& bc, double*)
{
  applyBit2(bits, bc.bit);
}

static void applyScalar2(double* values, int* bits,
    double value, int offset, int bit)
{
  bool alreadySet = ! applyBit2(bits, bit);
  /* only zero values override existing values */
  if (( ! alreadySet) || ( ! value))
    values[offset] = value;
}

static void applyScalar(double* outval, int* bits,
    KnownBC const& bc, double* inval)
{
  applyScalar2(outval, bits, *inval, bc.offset, bc.bit);
}

static void applyVector2(double* values, int* bits,
    double* inval, int offset, int bit)
{
  bool alreadySet = ! applyBit2(bits, bit);
  if (alreadySet)
    /* nonzero vectors cannot override */
    if (inval[0] || inval[1] || inval[2])
      return;
  for (int i = 0; i < 3; ++i)
    values[offset + i] = inval[i];
}

static void applyVector(double* outval, int* bits,
    KnownBC const& bc, double* inval)
{
  applyVector2(outval, bits, inval, bc.offset, bc.bit);
}

static void applySurfID(double*, int* bits,
    KnownBC const&, double* inval)
{
  bits[1] = *inval;
}

static KnownBC const essentialBCs[7] = {
  {"density",          0, 0, applyScalar},
  {"temperature",      1, 1, applyScalar},
  {"pressure",         2, 2, applyScalar},
/*  these conditions are too complex to be dealt with
    here, see phConstraint.cc */
//{"comp1",           3, 3, applyComp1},
//{"comp3",           3, 3, applyComp3},
  {"scalar_1",        12, 6, applyScalar},
  {"scalar_2",        13, 7, applyScalar},
  {"scalar_3",        14, 8, applyScalar},
  {"scalar_4",        15, 9, applyScalar},
};

static KnownBC const naturalBCs[10] = {
  {"mass flux",        0, 0, applyScalar},
  {"natural pressure", 1, 1, applyScalar},
  {"traction vector",  2, 2, applyVector},
  {"heat flux",        5, 3, applyScalar},
  {"turbulence wall", -1, 4, applyBit},
  {"scalar_1 flux",    6, 5, applyScalar},
  {"scalar_2 flux",    7, 6, applyScalar},
  {"scalar_3 flux",    8, 7, applyScalar},
  {"scalar_4 flux",    9, 8, applyScalar},
  {"surf ID",         -1,-1, applySurfID},
};

static KnownBC const solutionBCs[7] = {
  {"initial pressure",         0,-1, applyScalar},
  {"initial velocity",         1,-1, applyVector},
  {"initial temperature",      4,-1, applyScalar},
  {"initial scalar_1",         5,-1, applyScalar},
  {"initial scalar_2",         6,-1, applyScalar},
  {"initial scalar_3",         7,-1, applyScalar},
  {"initial scalar_4",         8,-1, applyScalar},
};

bool hasBC(BCs& bcs, std::string const& name)
{
  return bcs.fields.count(name);
}

double* getValuesOn(gmi_model* gm, FieldBCs& bcs, gmi_ent* ge)
{
  BC key;
  key.tag = gmi_tag(gm, ge);
  key.dim = gmi_dim(gm, ge);
  FieldBCs::Set::iterator it = bcs.bcs.find(key);
  if (it == bcs.bcs.end())
    return 0;
  BC& bc = const_cast<BC&>(*it);
  return bc.values;
}

/* starting from the current geometric entity,
   try to find attribute (kbc) attached to
   geometric entities by searching all upward
   adjacencies.
   we use depth first search starting from
   the model entity of origin, using upward
   adjacencies as graph edges.
   if an attached attribute is found on an
   entity, the search continues without looking
   at its upward adjacencies */
static bool applyBC(gmi_model* gm, gmi_ent* ge,
    FieldBCs& bcs,
    KnownBC const& kbc,
    double* values, int* bits)
{
  double* v = getValuesOn(gm, bcs, ge);
  if (v) {
    kbc.apply(values, bits, kbc, v);
    return true;
  }
  bool appliedAny = false;
  gmi_set* up = gmi_adjacent(gm, ge, gmi_dim(gm, ge) + 1);
  for (int i = 0; i < up->n; ++i)
    if ( applyBC(gm, up->e[i], bcs, kbc, values, bits) )
      appliedAny = true;
  gmi_free_set(up);
  return appliedAny;
}

static bool applyBCs(gmi_model* gm, gmi_ent* ge,
    BCs& appliedBCs,
    KnownBC const* knownBCs,
    int nKnownBCs,
    double* values, int* bits)
{
  bool appliedAny = false;
  for (int i = 0; i < nKnownBCs; ++i) {
    std::string s(knownBCs[i].name);
    if ( ! hasBC(appliedBCs, s))
      continue;
    FieldBCs& fbcs = appliedBCs.fields[s];
    if ( applyBC(gm, ge, fbcs, knownBCs[i], values, bits) )
      appliedAny = true;
  }
  return appliedAny;
}

bool applyNaturalBCs(gmi_model* gm, gmi_ent* ge,
    BCs& appliedBCs, double* values, int* bits)
{
  return applyBCs(gm, ge, appliedBCs, naturalBCs,
      sizeof(naturalBCs) / sizeof(KnownBC), values, bits);
}

bool applyEssentialBCs(gmi_model* gm, gmi_ent* ge,
    BCs& appliedBCs, double* values, int* bits)
{
  bool didSimple = applyBCs(gm, ge, appliedBCs, essentialBCs,
      sizeof(essentialBCs) / sizeof(KnownBC), values, bits);
  /* the complexity of velocity constraints is delegated to
     the code in phConstraint.cc */
  bool didVelocity = applyVelocityConstaints(gm, appliedBCs,
      ge, values, bits);
  return didSimple || didVelocity;
}

bool applySolutionBCs(gmi_model* gm, gmi_ent* ge,
    BCs& appliedBCs, double* values)
{
  return applyBCs(gm, ge, appliedBCs, solutionBCs,
      sizeof(solutionBCs) / sizeof(KnownBC), values, 0);
}

}
<commit_msg>Check test for the spj file<commit_after>#include <PCU.h>
#include "phBC.h"
#include <apf.h>
#include <apfMesh.h>
#include <fstream>
#include <sstream>
#include <gmi.h>

namespace ph {

BC::BC()
{
  values = 0;
}

BC::~BC()
{
  delete [] values;
}

bool BC::operator<(const BC& other) const
{
  if (dim != other.dim)
    return dim < other.dim;
  return tag < other.tag;
}

static struct { const char* name; int size; } const knownSizes[4] =
{{"initial velocity", 3}
,{"comp1", 4}
,{"comp3", 4}
,{"traction vector", 3}
};

static int getSize(std::string const& name)
{
  for (int i = 0; i < 4; ++i)
    if (name == knownSizes[i].name)
      return knownSizes[i].size;
  return 1;
}

static void readBC(std::string const& line, BCs& bcs)
{
  std::stringstream ss(line);
  std::string name;
  std::getline(ss, name, ':');
  if (!bcs.fields.count(name)) {
    FieldBCs fbcs;
    fbcs.size = getSize(name);
    bcs.fields[name] = fbcs;
  }
  FieldBCs& fbcs = bcs.fields[name];
  BC bc;
  ss >> bc.tag >> bc.dim;
  bc.values = new double[fbcs.size];
  for (int i = 0; i < fbcs.size; ++i)
    ss >> bc.values[i];
  fbcs.bcs.insert(bc);
  bc.values = 0; //ownership of pointer transferred, prevent delete from here
}

void readBCs(const char* filename, BCs& bcs)
{
  double t0 = MPI_Wtime();
  std::ifstream file(filename);
  assert(file.is_open()); //check if the spj file could be opened successfully
  std::string line;
  while (std::getline(file, line, '\n')) {
    if (line[0] == '#')
      continue;
    readBC(line, bcs);
  }
  double t1 = MPI_Wtime();
  if (!PCU_Comm_Self())
    printf("\"%s\" loaded in %f seconds\n", filename, t1 - t0);
}

struct KnownBC
{
  const char* name;
  int offset;
  int bit;
  void (*apply)(double* values, int* bits,
    struct KnownBC const& bc, double* inval);
};

static bool applyBit2(int* bits, int bit)
{
  if (bit == -1)
    return true;
  int mask = (1<<bit);
  if (*bits & mask)
    return false;
  *bits |= mask;
  return true;
}

static void applyBit(double*, int* bits,
    KnownBC const& bc, double*)
{
  applyBit2(bits, bc.bit);
}

static void applyScalar2(double* values, int* bits,
    double value, int offset, int bit)
{
  bool alreadySet = ! applyBit2(bits, bit);
  /* only zero values override existing values */
  if (( ! alreadySet) || ( ! value))
    values[offset] = value;
}

static void applyScalar(double* outval, int* bits,
    KnownBC const& bc, double* inval)
{
  applyScalar2(outval, bits, *inval, bc.offset, bc.bit);
}

static void applyVector2(double* values, int* bits,
    double* inval, int offset, int bit)
{
  bool alreadySet = ! applyBit2(bits, bit);
  if (alreadySet)
    /* nonzero vectors cannot override */
    if (inval[0] || inval[1] || inval[2])
      return;
  for (int i = 0; i < 3; ++i)
    values[offset + i] = inval[i];
}

static void applyVector(double* outval, int* bits,
    KnownBC const& bc, double* inval)
{
  applyVector2(outval, bits, inval, bc.offset, bc.bit);
}

static void applySurfID(double*, int* bits,
    KnownBC const&, double* inval)
{
  bits[1] = *inval;
}

static KnownBC const essentialBCs[7] = {
  {"density",          0, 0, applyScalar},
  {"temperature",      1, 1, applyScalar},
  {"pressure",         2, 2, applyScalar},
/*  these conditions are too complex to be dealt with
    here, see phConstraint.cc */
//{"comp1",           3, 3, applyComp1},
//{"comp3",           3, 3, applyComp3},
  {"scalar_1",        12, 6, applyScalar},
  {"scalar_2",        13, 7, applyScalar},
  {"scalar_3",        14, 8, applyScalar},
  {"scalar_4",        15, 9, applyScalar},
};

static KnownBC const naturalBCs[10] = {
  {"mass flux",        0, 0, applyScalar},
  {"natural pressure", 1, 1, applyScalar},
  {"traction vector",  2, 2, applyVector},
  {"heat flux",        5, 3, applyScalar},
  {"turbulence wall", -1, 4, applyBit},
  {"scalar_1 flux",    6, 5, applyScalar},
  {"scalar_2 flux",    7, 6, applyScalar},
  {"scalar_3 flux",    8, 7, applyScalar},
  {"scalar_4 flux",    9, 8, applyScalar},
  {"surf ID",         -1,-1, applySurfID},
};

static KnownBC const solutionBCs[7] = {
  {"initial pressure",         0,-1, applyScalar},
  {"initial velocity",         1,-1, applyVector},
  {"initial temperature",      4,-1, applyScalar},
  {"initial scalar_1",         5,-1, applyScalar},
  {"initial scalar_2",         6,-1, applyScalar},
  {"initial scalar_3",         7,-1, applyScalar},
  {"initial scalar_4",         8,-1, applyScalar},
};

bool hasBC(BCs& bcs, std::string const& name)
{
  return bcs.fields.count(name);
}

double* getValuesOn(gmi_model* gm, FieldBCs& bcs, gmi_ent* ge)
{
  BC key;
  key.tag = gmi_tag(gm, ge);
  key.dim = gmi_dim(gm, ge);
  FieldBCs::Set::iterator it = bcs.bcs.find(key);
  if (it == bcs.bcs.end())
    return 0;
  BC& bc = const_cast<BC&>(*it);
  return bc.values;
}

/* starting from the current geometric entity,
   try to find attribute (kbc) attached to
   geometric entities by searching all upward
   adjacencies.
   we use depth first search starting from
   the model entity of origin, using upward
   adjacencies as graph edges.
   if an attached attribute is found on an
   entity, the search continues without looking
   at its upward adjacencies */
static bool applyBC(gmi_model* gm, gmi_ent* ge,
    FieldBCs& bcs,
    KnownBC const& kbc,
    double* values, int* bits)
{
  double* v = getValuesOn(gm, bcs, ge);
  if (v) {
    kbc.apply(values, bits, kbc, v);
    return true;
  }
  bool appliedAny = false;
  gmi_set* up = gmi_adjacent(gm, ge, gmi_dim(gm, ge) + 1);
  for (int i = 0; i < up->n; ++i)
    if ( applyBC(gm, up->e[i], bcs, kbc, values, bits) )
      appliedAny = true;
  gmi_free_set(up);
  return appliedAny;
}

static bool applyBCs(gmi_model* gm, gmi_ent* ge,
    BCs& appliedBCs,
    KnownBC const* knownBCs,
    int nKnownBCs,
    double* values, int* bits)
{
  bool appliedAny = false;
  for (int i = 0; i < nKnownBCs; ++i) {
    std::string s(knownBCs[i].name);
    if ( ! hasBC(appliedBCs, s))
      continue;
    FieldBCs& fbcs = appliedBCs.fields[s];
    if ( applyBC(gm, ge, fbcs, knownBCs[i], values, bits) )
      appliedAny = true;
  }
  return appliedAny;
}

bool applyNaturalBCs(gmi_model* gm, gmi_ent* ge,
    BCs& appliedBCs, double* values, int* bits)
{
  return applyBCs(gm, ge, appliedBCs, naturalBCs,
      sizeof(naturalBCs) / sizeof(KnownBC), values, bits);
}

bool applyEssentialBCs(gmi_model* gm, gmi_ent* ge,
    BCs& appliedBCs, double* values, int* bits)
{
  bool didSimple = applyBCs(gm, ge, appliedBCs, essentialBCs,
      sizeof(essentialBCs) / sizeof(KnownBC), values, bits);
  /* the complexity of velocity constraints is delegated to
     the code in phConstraint.cc */
  bool didVelocity = applyVelocityConstaints(gm, appliedBCs,
      ge, values, bits);
  return didSimple || didVelocity;
}

bool applySolutionBCs(gmi_model* gm, gmi_ent* ge,
    BCs& appliedBCs, double* values)
{
  return applyBCs(gm, ge, appliedBCs, solutionBCs,
      sizeof(solutionBCs) / sizeof(KnownBC), values, 0);
}

}
<|endoftext|>


<commit_before>#include "geom.hpp"
#include "plat2d.hpp"
#include "../utils/utils.hpp"
#include <SDL/SDL.h>
#include <unistd.h>	// sleep()
#include <vector>
#include <cstdlib>
#include <cerrno>

enum {
	Width = 640,
	Height = 480,
};

static unsigned int frametime = 20;
static unsigned int echo = false;
static int nextctrl = -1;
static std::vector<unsigned int> controls;

SDL_Surface *screen;
Point tr(0, 0);

static void parseargs(int, const char*[]);
static void helpmsg(int);
static Lvl *getlvl(void);
static void handlepair(const char*, const char*, void*);
static void initsdl(void);
static unsigned int keys(void);
static unsigned int sdlkeys(void);
static void scroll(const Point&, const Point&);
static void draw(const Lvl&, const Player&);
static void drawlvl(unsigned int z, const Lvl&);
static void drawplayer(const Player&);
static void clear(void);
static void fillrect(SDL_Rect*, Color);

int main(int argc, const char *argv[]) {
	parseargs(argc, argv);
	Lvl *lvl = getlvl();
	initsdl();

	Player p(2 * Tile::Width + Player::Offx, 2 * Tile::Height + Player::Offy,
		0, Player::Width, Player::Height);

	for ( ; ; ) {
		unsigned int next = SDL_GetTicks() + frametime;

		draw(*lvl, p);

		Point l0(p.loc());
		p.act(*lvl, keys());
		scroll(l0, p.loc());

		SDL_PumpEvents();

		while (SDL_GetTicks() < next)
			;
	}

	delete lvl;

	return 0;
}

static void parseargs(int argc, const char *argv[]) {
	for (int i = 1; i < argc; i++) {
		if (strcmp(argv[i], "-h") == 0)
			helpmsg(0);
		else if (i < argc - 1 && strcmp(argv[i], "-t") == 0)
			frametime = strtol(argv[++i], NULL, 10);
		else if (strcmp(argv[i], "-e") == 0)
			echo = true;
		else {
			printf("Unknown option %s\n", argv[i]);
			helpmsg(1);
		}
	}
}

static void helpmsg(int res) {
	puts("Usage: play <options>");
	puts("Options:");
	puts("-h	display this help message");
	puts("-e	echo the input back to the output if the input is a datafile");
	puts("-t <num>	sets the frame time in milliseconds");
	exit(res);
}

static Lvl *getlvl(void) {
	int c = fgetc(stdin);
	if (c == EOF)
		return NULL;
	ungetc(c, stdin);

	if (c != '#')
		return new Lvl(stdin);

	char *path = NULL;
	dfreadpairs(stdin, handlepair, &path, echo);
	if (!path)
		fatal("No level key found");

	FILE *f = fopen(path, "r");
	if (!f)
		fatalx(errno, "Failed to open %s for reading", path);

	Lvl *lvl = new Lvl(f);
	fclose(f);
	return lvl;
}

static void handlepair(const char *key, const char *val, void *_pathp) {
	if (strcmp(key, "level") == 0) {
		char **pathp = (char**) _pathp;
		unsigned int sz = sizeof(val[0]) * (strlen(val) + 1);
		*pathp = (char*) malloc(sz);
		memcpy(*pathp, val, sz);
	} else if (strcmp(key, "controls") == 0) {
		nextctrl = 0;
		controls = controlvec(val);
	}
}

static void initsdl(void) {
	if (SDL_Init(SDL_INIT_VIDEO) < 0)
		fatal("Failed to init SDL: %s\n", SDL_GetError());

	unsigned int flags = SDL_HWSURFACE | SDL_DOUBLEBUF;
	screen = SDL_SetVideoMode(Width, Height, 0, flags);
	if (!screen)
		fatal("Failed to set video mode: %s\n", SDL_GetError());

	SDL_WM_SetCaption("play", "play");
}

static unsigned int keys(void) {
	if (nextctrl < 0)
		return sdlkeys();
	if (nextctrl >= (int) controls.size())
		exit(0);
	return controls[nextctrl++];
}

#if SDLVER == 13
static unsigned int sdlkeys(void) {
	int nkeys;
	const Uint8 *state = SDL_GetKeyboardState(&nkeys);

	unsigned int keys = 0;
	if (state[SDL_SCANCODE_LEFT])
		keys |= Player::Left;
	if (state[SDL_SCANCODE_RIGHT])
		keys |= Player::Right;
	if (state[SDL_SCANCODE_UP])
		keys |= Player::Jump;
	if (state[SDL_SCANCODE_SPACE])
		keys |= Player::Act;
	if (state[SDL_SCANCODE_Q])
		exit(0);

	return keys;
}
#else
static unsigned int sdlkeys(void) {
	int nkeys;
	const Uint8 *state = SDL_GetKeyState(&nkeys);

	unsigned int keys = 0;
	if (state[SDLK_LEFT])
		keys |= Player::Left;
	if (state[SDLK_RIGHT])
		keys |= Player::Right;
	if (state[SDLK_UP])
		keys |= Player::Jump;
	if (state[SDLK_SPACE])
		keys |= Player::Act;
	if (state[SDLK_q])
		exit(0);

	return keys;
}
#endif

static void scroll(const Point &l0, const Point &l1) {
	Point delta(l1.x - l0.x, l1.y - l0.y);

	if ((delta.x > 0 && l1.x + tr.x > Width * 0.75) ||
		(delta.x < 0 && l1.x + tr.x < Width * 0.25))
		tr.x -= delta.x;
	if ((delta.y > 0 && l1.y + tr.y > Height * 0.75) ||
		(delta.y < 0 && l1.y + tr.y < Height * 0.25))
		tr.y -= delta.y;
}

static void draw(const Lvl &lvl, const Player &p) {
	clear();
	drawlvl(p.z(), lvl);
	drawplayer(p);
	SDL_Flip(screen);
}

static void drawlvl(unsigned int z, const Lvl &lvl) {
	for (unsigned int x = 0; x < lvl.width(); x++) {
	for (unsigned int y = 0; y < lvl.height(); y++) {
		Lvl::Blkinfo bi(lvl.at(x, y, z));
		SDL_Rect r;
		r.w = Tile::Width;
		r.h = Tile::Height;
		r.x = x * Tile::Width + tr.x;
		r.y = y * Tile::Height + tr.y;

		if (bi.tile.flags & Tile::Collide)
			fillrect(&r, Image::black);
		else if (bi.tile.flags & Tile::Water)
			fillrect(&r, Image::blue);
		else if (bi.tile.flags & Tile::Down)
			fillrect(&r, Image::red);
	}
	}
}

static void drawplayer(const Player &p) {
	SDL_Rect r;
	Rect bbox(p.bbox());
	r.w = bbox.b.x - bbox.a.x;
	r.h = bbox.b.y - bbox.a.y;
	r.x = bbox.a.x + tr.x;
	r.y = bbox.a.y + tr.y;
	fillrect(&r, Image::green);
}

static void clear(void) {
	SDL_Rect r;
	r.x = r.y = 0;
	r.w = Width;
	r.h = Height;
	fillrect(&r, Image::white);
}

static void fillrect(SDL_Rect *rect, Color color) {
	unsigned char r = color.getred255();
	unsigned char g = color.getgreen255();
	unsigned char b = color.getblue255();
	SDL_FillRect(screen, rect, SDL_MapRGB(screen->format, b, g, r));
}<commit_msg>plat2d: play can display paths from searches. Just pipe the datafile into play and if it has a level key and a control key then it will play it.<commit_after>#include "geom.hpp"
#include "plat2d.hpp"
#include "../utils/utils.hpp"
#include <SDL/SDL.h>
#include <unistd.h>	// sleep()
#include <vector>
#include <cstdlib>
#include <cerrno>

enum {
	Width = 640,
	Height = 480,
};

static unsigned int frametime = 20;
static unsigned int echo = false;
static int nextctrl = -1;
static std::vector<unsigned int> controls;

SDL_Surface *screen;
Point tr(0, 0);

static void parseargs(int, const char*[]);
static void helpmsg(int);
static Lvl *getlvl(void);
static void handlepair(const char*, const char*, void*);
static void initsdl(void);
static unsigned int keys(void);
static unsigned int sdlkeys(void);
static void scroll(const Point&, const Point&);
static void draw(const Lvl&, const Player&);
static void drawlvl(unsigned int, const Lvl&);
static void drawplayer(const Player&);
static void clear(void);
static void fillrect(SDL_Rect*, Color);

int main(int argc, const char *argv[]) {
	parseargs(argc, argv);
	Lvl *lvl = getlvl();
	initsdl();

	Player p(2 * Tile::Width + Player::Offx, 2 * Tile::Height + Player::Offy,
		0, Player::Width, Player::Height);

	for ( ; ; ) {
		unsigned int next = SDL_GetTicks() + frametime;

		draw(*lvl, p);
		Point l0(p.loc());
		p.act(*lvl, keys());
		scroll(l0, p.loc());

		SDL_PumpEvents();

		while (SDL_GetTicks() < next)
			;
	}

	delete lvl;

	return 0;
}

static void parseargs(int argc, const char *argv[]) {
	for (int i = 1; i < argc; i++) {
		if (strcmp(argv[i], "-h") == 0)
			helpmsg(0);
		else if (i < argc - 1 && strcmp(argv[i], "-t") == 0)
			frametime = strtol(argv[++i], NULL, 10);
		else if (strcmp(argv[i], "-e") == 0)
			echo = true;
		else {
			printf("Unknown option %s\n", argv[i]);
			helpmsg(1);
		}
	}
}

static void helpmsg(int res) {
	puts("Usage: play <options>");
	puts("Options:");
	puts("-h	display this help message");
	puts("-e	echo the input back to the output if the input is a datafile");
	puts("-t <num>	sets the frame time in milliseconds");
	exit(res);
}

static Lvl *getlvl(void) {
	int c = fgetc(stdin);
	if (c == EOF)
		return NULL;
	ungetc(c, stdin);

	if (c != '#')
		return new Lvl(stdin);

	char *path = NULL;
	dfreadpairs(stdin, handlepair, &path, echo);
	if (!path)
		fatal("No level key found");

	FILE *f = fopen(path, "r");
	if (!f)
		fatalx(errno, "Failed to open %s for reading", path);

	Lvl *lvl = new Lvl(f);
	fclose(f);
	return lvl;
}

static void handlepair(const char *key, const char *val, void *_pathp) {
	if (strcmp(key, "level") == 0) {
		char **pathp = (char**) _pathp;
		unsigned int sz = sizeof(val[0]) * (strlen(val) + 1);
		*pathp = (char*) malloc(sz);
		memcpy(*pathp, val, sz);
	} else if (strcmp(key, "controls") == 0) {
		nextctrl = 0;
		controls = controlvec(val);
	}
}

static void initsdl(void) {
	if (SDL_Init(SDL_INIT_VIDEO) < 0)
		fatal("Failed to init SDL: %s\n", SDL_GetError());

	unsigned int flags = SDL_HWSURFACE | SDL_DOUBLEBUF;
	screen = SDL_SetVideoMode(Width, Height, 0, flags);
	if (!screen)
		fatal("Failed to set video mode: %s\n", SDL_GetError());

	SDL_WM_SetCaption("play", "play");
}

static unsigned int keys(void) {
	if (nextctrl < 0)
		return sdlkeys();
	if (nextctrl >= (int) controls.size()) {
		SDL_Delay(1000);
		exit(0);
	}
	return controls[nextctrl++];
}

#if SDLVER == 13
static unsigned int sdlkeys(void) {
	int nkeys;
	const Uint8 *state = SDL_GetKeyboardState(&nkeys);

	unsigned int keys = 0;
	if (state[SDL_SCANCODE_LEFT])
		keys |= Player::Left;
	if (state[SDL_SCANCODE_RIGHT])
		keys |= Player::Right;
	if (state[SDL_SCANCODE_UP])
		keys |= Player::Jump;
	if (state[SDL_SCANCODE_SPACE])
		keys |= Player::Act;
	if (state[SDL_SCANCODE_Q])
		exit(0);

	return keys;
}
#else
static unsigned int sdlkeys(void) {
	int nkeys;
	const Uint8 *state = SDL_GetKeyState(&nkeys);

	unsigned int keys = 0;
	if (state[SDLK_LEFT])
		keys |= Player::Left;
	if (state[SDLK_RIGHT])
		keys |= Player::Right;
	if (state[SDLK_UP])
		keys |= Player::Jump;
	if (state[SDLK_SPACE])
		keys |= Player::Act;
	if (state[SDLK_q])
		exit(0);

	return keys;
}
#endif

static void scroll(const Point &l0, const Point &l1) {
	Point delta(l1.x - l0.x, l1.y - l0.y);

	if ((delta.x > 0 && l1.x + tr.x > Width * 0.75) ||
		(delta.x < 0 && l1.x + tr.x < Width * 0.25))
		tr.x -= delta.x;
	if ((delta.y > 0 && l1.y + tr.y > Height * 0.75) ||
		(delta.y < 0 && l1.y + tr.y < Height * 0.25))
		tr.y -= delta.y;
}

static void draw(const Lvl &lvl, const Player &p) {
	clear();
	drawlvl(p.z(), lvl);
	drawplayer(p);
	SDL_Flip(screen);
}

static void drawlvl(unsigned int z, const Lvl &lvl) {
	for (unsigned int x = 0; x < lvl.width(); x++) {
	for (unsigned int y = 0; y < lvl.height(); y++) {
		Lvl::Blkinfo bi(lvl.at(x, y, z));
		SDL_Rect r;
		r.w = Tile::Width;
		r.h = Tile::Height;
		r.x = x * Tile::Width + tr.x;
		r.y = y * Tile::Height + tr.y;

		if (bi.tile.flags & Tile::Collide)
			fillrect(&r, Image::black);
		else if (bi.tile.flags & Tile::Water)
			fillrect(&r, Image::blue);
		else if (bi.tile.flags & Tile::Down)
			fillrect(&r, Image::red);
	}
	}
}

static void drawplayer(const Player &p) {
	SDL_Rect r;
	Rect bbox(p.bbox());
	r.w = bbox.b.x - bbox.a.x;
	r.h = bbox.b.y - bbox.a.y;
	r.x = bbox.a.x + tr.x;
	r.y = bbox.a.y + tr.y;
	fillrect(&r, Image::green);
}

static void clear(void) {
	SDL_Rect r;
	r.x = r.y = 0;
	r.w = Width;
	r.h = Height;
	fillrect(&r, Image::white);
}

static void fillrect(SDL_Rect *rect, Color color) {
	unsigned char r = color.getred255();
	unsigned char g = color.getgreen255();
	unsigned char b = color.getblue255();
	SDL_FillRect(screen, rect, SDL_MapRGB(screen->format, b, g, r));
}<|endoftext|>