<commit_before>#pragma once
//=====================================================================//
/*! @file
    @brief  イグナイター・クライアント・クラス
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017, 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <winsock2.h>

#include <string>
#include <queue>

#include "utils/format.hpp"
#include "utils/string_utils.hpp"

// デバッグ・エミュレーションを行う場合有効にする
// #define DEBUG_EMU

namespace net {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  Ignitor Client クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class ign_client_tcp {
	public:
		static const uint32_t WAVE_BUFF_SIZE = 2048;

		//=================================================================//
		/*!
			@brief  モジュール・ステータス構造体
		*/
		//=================================================================//
		struct mod_status {
			uint32_t	crm_id_;

			uint32_t	crcd_;
			uint32_t	crcd_id_;

			uint32_t	crrd_;
			uint32_t	crrd_id_;

			uint32_t	d2md_;
			uint32_t	d2md_id_;

			uint32_t	wdm_id_[4];

			uint32_t	treg_id_[2];

			mod_status() :
				crm_id_(0),
				crcd_(0), crcd_id_(0),
				crrd_(0), crrd_id_(0),
				d2md_(0), d2md_id_(0),
				wdm_id_{ 0 }, treg_id_{ 0 }
			{ }
		};

	private:
		bool		startup_;

		SOCKET		sock_;

		bool		connect_;

		std::string	line_;

		typedef std::queue<std::string> SQUEUE;
		SQUEUE		rmsg_;

		mod_status	mod_status_;

		uint32_t	wdm_ch_;
		uint32_t	wdm_pos_;
		uint16_t	wdm_buff_[WAVE_BUFF_SIZE * 4];

		uint32_t	treg_ch_;
		uint32_t	treg_pos_;
		uint16_t	treg_buff_[WAVE_BUFF_SIZE * 2];

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		ign_client_tcp() : startup_(false),
			sock_(0),
			connect_(false), mod_status_(),
			wdm_ch_(0), wdm_pos_(0), wdm_buff_{ 0 },
			treg_ch_(0), treg_pos_(0), treg_buff_{ 0 }
		{
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  デストラクター
		*/
		//-----------------------------------------------------------------//
		~ign_client_tcp()
		{
			if(startup_) {
				WSACleanup();
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  モジュール・ステータスの取得
			@return モジュール・ステータス
		*/
		//-----------------------------------------------------------------//
		const mod_status& get_mod_status() const { return mod_status_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  波形の取得
			@param[in]	ch	チャネル
			@return 波形
		*/
		//-----------------------------------------------------------------//
		const uint16_t* get_wdm(uint32_t ch) const {
			return &wdm_buff_[WAVE_BUFF_SIZE * (ch & 3)];
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  熱抵抗波形の取得
			@param[in]	ch	チャネル（前半:0、後半:1）
			@return 熱抵抗波形
		*/
		//-----------------------------------------------------------------//
		const uint16_t* get_treg(uint32_t ch) const {
			return &treg_buff_[WAVE_BUFF_SIZE * (ch & 1)];
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  接続状態の確認
			@return 接続なら「true」
		*/
		//-----------------------------------------------------------------//
		bool probe() const { return connect_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  開始
			@param[in]	ip	IP アドレス
			@param[in]	pn	ポート番号
		*/
		//-----------------------------------------------------------------//
		bool start(const std::string& ip, uint16_t pn)
		{
#ifdef DEBUG_EMU
			connect_ = true;
			return true;
#endif
			if(!startup_) {
				WSADATA wsaData;
				int res = WSAStartup(MAKEWORD(2,0), &wsaData);
				if(res != NO_ERROR) {
					std::cout << "WSAStartup function failed with error:" << std::endl;
					return false;
				}
			}

			// クライアントソケット作成
			sock_ = socket(AF_INET, SOCK_STREAM, 0);
			if(sock_ == INVALID_SOCKET) {
				std::cout << "socket failed" << std::endl;
				return false;
			}

			// struct sockaddr_in 作成
			struct sockaddr_in cl;
			cl.sin_family = PF_INET;
			cl.sin_port = htons(pn);
			// 接続先のアドレスを指定（指定しない事も可能）
			cl.sin_addr.s_addr = inet_addr(ip.c_str());

			// クライアントの接続を待つ
			int ret = connect(sock_, (struct sockaddr *)&cl, sizeof(cl));
			if(ret == SOCKET_ERROR) {
				closesocket(sock_);
				perror("TCP connect fail...");
				return false;
			}

			connect_ = true;
//			utils::format("TCP Client connect (%d)\n") % sock_;

			u_long val = 1;
			ioctlsocket(sock_, FIONBIO, &val);

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  サービス
		*/
		//-----------------------------------------------------------------//
		void service()
		{
#ifdef DEBUG_EMU

#else
			if(!connect_) return;

			char tmp[8192];
			int n = recv(sock_, tmp, sizeof(tmp) - 1, 0);
			if(n < 1) {
				if(WSAGetLastError() == WSAEWOULDBLOCK) {
					// まだ来ない。
				} else {
					std::cout << "recv error..." << std::endl;
				}
			} else {
				for(int i = 0; i < n; ++i) {
					auto ch = tmp[i];
					line_ += ch;
					if(ch == '\n') {
						rmsg_.push(line_);
						line_.clear();
					}
				}
			}

			// 読み込みデータ処理
			while(!rmsg_.empty()) {
				auto s = rmsg_.front();
				rmsg_.pop();

				if(s.find("CRCD") == 0) {
					auto t = s.substr(4, 8);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						mod_status_.crcd_ = v;
						++mod_status_.crcd_id_;
						++mod_status_.crm_id_;
					}
				} else if(s.find("CRRD") == 0) {
					auto t = s.substr(4, 8);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						mod_status_.crrd_ = v;
						++mod_status_.crrd_id_;
						++mod_status_.crm_id_;
					}
				} else if(s.find("D2MD") == 0) {
					auto t = s.substr(4, 5);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						mod_status_.d2md_ = v;
						++mod_status_.d2md_id_;
					}
				} else if(s.find("WDCH") == 0) {  // WDM チャネル
					auto t = s.substr(4);
					int v = 0;
					utils::input("%d", t.c_str()) % v;
					wdm_ch_ = v;
					wdm_pos_ = 0;
// std::cout << "WDM capture CH: " << wdm_ch_ << std::endl;
				} else if(s.find("WDMW") == 0) {  // WDM 波形
					auto t = s.substr(4);
					while(t.size() > 4) {
						auto d = t.substr(4);
						t[4] = 0;
						int v;
						utils::input("%x", t.c_str()) % v;
						auto pos = wdm_pos_ % WAVE_BUFF_SIZE;
						wdm_buff_[(wdm_ch_ & 3) * WAVE_BUFF_SIZE + pos] = v;
						++wdm_pos_;
						if(wdm_pos_ >= WAVE_BUFF_SIZE) {
							++mod_status_.wdm_id_[wdm_ch_ & 3];
						}
						t = d;
					}
				} else if(s.find("TRCH") == 0) {  // 熱抵抗チャネル (0, 1)
					auto t = s.substr(4);
					int v = 0;
					utils::input("%d", t.c_str()) % v;
					treg_ch_ = v;
					treg_pos_ = 0;
// std::cout << "TRCH: " << treg_ch_ << std::endl;
				} else if(s.find("TRMW") == 0) {  // 熱抵抗波形 (0, 1)
					auto t = s.substr(4);
					while(t.size() > 4) {
						auto d = t.substr(4);
						t[4] = 0;
						int v;
						utils::input("%x", t.c_str()) % v;
						auto pos = treg_pos_ % WAVE_BUFF_SIZE;
						treg_buff_[(treg_ch_ & 1) * WAVE_BUFF_SIZE + pos] = v;
						++treg_pos_;
						if(treg_pos_ >= WAVE_BUFF_SIZE) {
							++mod_status_.treg_id_[treg_ch_ & 3];
// std::cout << "TRMW: " << treg_ch_ << std::endl;
						}
						t = d;
					}
				}
			}
#endif
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  送信
			@param[in]	text	送信文字列
		*/
		//-----------------------------------------------------------------//
		void send_data(const std::string& text)
		{
#ifdef DEBUG_EMU
			if(text.find("CRR?1") != std::string::npos) {
				double a = 50.0;
				a *= 2.0;
				a /= 778.2;
				a *= 50.0;
				a *= static_cast<double>(0x7FFFF) / 1.570798233;
				mod_status_.crrd_ = 50 * 0x7ffff + static_cast<uint32_t>(a);
				++mod_status_.crrd_id_;
				++mod_status_.crm_id_;
			} else if(text.find("CRC?1") != std::string::npos) {
				double a = 0.33;
				a /= 1e6;
				a = 1.0 / (2.0 * 3.141592654 * 1000.0 * a);
				a *= 2.0;
				a /= 778.2 * 2.0;  // 778.2 mV P-P
				a *= 50.0;
				a *= static_cast<double>(0x7FFFF) / 1.570798233;
				mod_status_.crcd_ = 50 * 0x7ffff + static_cast<uint32_t>(a);
				++mod_status_.crcd_id_;
				++mod_status_.crm_id_;
			} else if(text.find("wdm 20") != std::string::npos) {
				++mod_status_.wdm_id_[2];
			}
			std::cout << text << std::endl;
			return;
#else
			if(send(sock_, text.c_str(), text.size(), 0) == SOCKET_ERROR) {
				shutdown(sock_, 2);
				closesocket(sock_);
				connect_ = false;
			}
#endif
		}
	};
}
<commit_msg>update: cleanup<commit_after>#pragma once
//=====================================================================//
/*! @file
    @brief  イグナイター・クライアント・クラス
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017, 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <winsock2.h>

#include <string>
#include <queue>

#include "utils/format.hpp"
#include "utils/string_utils.hpp"

// デバッグ・エミュレーションを行う場合有効にする
// #define DEBUG_EMU

namespace net {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  Ignitor Client クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class ign_client_tcp {
	public:
		static const uint32_t WAVE_BUFF_SIZE = 2048;

		//=================================================================//
		/*!
			@brief  モジュール・ステータス構造体
		*/
		//=================================================================//
		struct mod_status {
			uint32_t	crm_id_;

			uint32_t	crcd_;
			uint32_t	crcd_id_;

			uint32_t	crrd_;
			uint32_t	crrd_id_;

			uint32_t	d2md_;
			uint32_t	d2md_id_;

			uint32_t	wdm_id_[4];

			uint32_t	treg_id_[2];

			mod_status() :
				crm_id_(0),
				crcd_(0), crcd_id_(0),
				crrd_(0), crrd_id_(0),
				d2md_(0), d2md_id_(0),
				wdm_id_{ 0 }, treg_id_{ 0 }
			{ }
		};

	private:
		bool		startup_;

		SOCKET		sock_;

		bool		connect_;

		std::string	line_;

		typedef std::queue<std::string> SQUEUE;
		SQUEUE		rmsg_;

		mod_status	mod_status_;

		uint32_t	wdm_ch_;
		uint32_t	wdm_pos_;
		uint16_t	wdm_buff_[WAVE_BUFF_SIZE * 4];

		uint32_t	treg_ch_;
		uint32_t	treg_pos_;
		uint16_t	treg_buff_[WAVE_BUFF_SIZE * 2];

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		ign_client_tcp() : startup_(false),
			sock_(0),
			connect_(false), mod_status_(),
			wdm_ch_(0), wdm_pos_(0), wdm_buff_{ 0 },
			treg_ch_(0), treg_pos_(0), treg_buff_{ 0 }
		{
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  デストラクター
		*/
		//-----------------------------------------------------------------//
		~ign_client_tcp()
		{
			if(startup_) {
				WSACleanup();
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  モジュール・ステータスの取得
			@return モジュール・ステータス
		*/
		//-----------------------------------------------------------------//
		const mod_status& get_mod_status() const { return mod_status_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  波形の取得
			@param[in]	ch	チャネル
			@return 波形
		*/
		//-----------------------------------------------------------------//
		const uint16_t* get_wdm(uint32_t ch) const {
			return &wdm_buff_[WAVE_BUFF_SIZE * (ch & 3)];
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  熱抵抗波形の取得
			@param[in]	ch	チャネル（前半:0、後半:1）
			@return 熱抵抗波形
		*/
		//-----------------------------------------------------------------//
		const uint16_t* get_treg(uint32_t ch) const {
			return &treg_buff_[WAVE_BUFF_SIZE * (ch & 1)];
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  接続状態の確認
			@return 接続なら「true」
		*/
		//-----------------------------------------------------------------//
		bool probe() const { return connect_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  開始
			@param[in]	ip	IP アドレス
			@param[in]	pn	ポート番号
		*/
		//-----------------------------------------------------------------//
		bool start(const std::string& ip, uint16_t pn)
		{
#ifdef DEBUG_EMU
			connect_ = true;
			return true;
#endif
			if(!startup_) {
				WSADATA wsaData;
				int res = WSAStartup(MAKEWORD(2,0), &wsaData);
				if(res != NO_ERROR) {
					std::cout << "WSAStartup function failed with error:" << std::endl;
					return false;
				}
			}

			// クライアントソケット作成
			sock_ = socket(AF_INET, SOCK_STREAM, 0);
			if(sock_ == INVALID_SOCKET) {
				std::cout << "socket failed" << std::endl;
				return false;
			}

			// struct sockaddr_in 作成
			struct sockaddr_in cl;
			cl.sin_family = PF_INET;
			cl.sin_port = htons(pn);
			// 接続先のアドレスを指定（指定しない事も可能）
			cl.sin_addr.s_addr = inet_addr(ip.c_str());

			// クライアントの接続を待つ
			int ret = connect(sock_, (struct sockaddr *)&cl, sizeof(cl));
			if(ret == SOCKET_ERROR) {
				closesocket(sock_);
				perror("TCP connect fail...");
				return false;
			}

			connect_ = true;
//			utils::format("TCP Client connect (%d)\n") % sock_;

			u_long val = 1;
			ioctlsocket(sock_, FIONBIO, &val);

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  サービス
		*/
		//-----------------------------------------------------------------//
		void service()
		{
#ifdef DEBUG_EMU

#else
			if(!connect_) return;

			char tmp[8192];
			int n = recv(sock_, tmp, sizeof(tmp) - 1, 0);
			if(n < 1) {
				if(WSAGetLastError() == WSAEWOULDBLOCK) {
					// まだ来ない。
				} else {
					std::cout << "recv error..." << std::endl;
				}
			} else {
				for(int i = 0; i < n; ++i) {
					auto ch = tmp[i];
					line_ += ch;
					if(ch == '\n') {
						rmsg_.push(line_);
						line_.clear();
					}
				}
			}

			// 読み込みデータ処理
			while(!rmsg_.empty()) {
				auto s = rmsg_.front();
				rmsg_.pop();

				if(s.find("CRCD") == 0) {
					auto t = s.substr(4, 8);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						mod_status_.crcd_ = v;
						++mod_status_.crcd_id_;
						++mod_status_.crm_id_;
					}
				} else if(s.find("CRRD") == 0) {
					auto t = s.substr(4, 8);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						mod_status_.crrd_ = v;
						++mod_status_.crrd_id_;
						++mod_status_.crm_id_;
					}
				} else if(s.find("D2MD") == 0) {
					auto t = s.substr(4, 5);
					int v = 0;
					if((utils::input("%x", t.c_str()) % v).status()) {
						mod_status_.d2md_ = v;
						++mod_status_.d2md_id_;
					}
				} else if(s.find("WDCH") == 0) {  // WDM チャネル
					auto t = s.substr(4);
					int v = 0;
					utils::input("%d", t.c_str()) % v;
					wdm_ch_ = v;
					wdm_pos_ = 0;
// std::cout << "WDM capture CH: " << wdm_ch_ << std::endl;
				} else if(s.find("WDMW") == 0) {  // WDM 波形
					auto t = s.substr(4);
					while(t.size() > 4) {
						auto d = t.substr(4);
						t[4] = 0;
						int v;
						utils::input("%x", t.c_str()) % v;
						auto pos = wdm_pos_ % WAVE_BUFF_SIZE;
						wdm_buff_[(wdm_ch_ & 3) * WAVE_BUFF_SIZE + pos] = v;
						++wdm_pos_;
						if(wdm_pos_ >= WAVE_BUFF_SIZE) {
							++mod_status_.wdm_id_[wdm_ch_ & 3];
						}
						t = d;
					}
				} else if(s.find("TRCH") == 0) {  // 熱抵抗チャネル (0, 1)
					auto t = s.substr(4);
					int v = 0;
					utils::input("%d", t.c_str()) % v;
					treg_ch_ = v;
					treg_pos_ = 0;
// std::cout << "TRCH: " << treg_ch_ << std::endl;
				} else if(s.find("TRMW") == 0) {  // 熱抵抗波形 (0, 1)
					auto t = s.substr(4);
					while(t.size() > 4) {
						auto d = t.substr(4);
						t[4] = 0;
						int v;
						utils::input("%x", t.c_str()) % v;
						auto pos = treg_pos_ % WAVE_BUFF_SIZE;
						treg_buff_[(treg_ch_ & 1) * WAVE_BUFF_SIZE + pos] = v;
						++treg_pos_;
						if(treg_pos_ >= WAVE_BUFF_SIZE) {
							++mod_status_.treg_id_[treg_ch_ & 1];
// std::cout << "TRMW: " << treg_ch_ << std::endl;
						}
						t = d;
					}
				}
			}
#endif
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  送信
			@param[in]	text	送信文字列
		*/
		//-----------------------------------------------------------------//
		void send_data(const std::string& text)
		{
#ifdef DEBUG_EMU
			if(text.find("CRR?1") != std::string::npos) {
				double a = 50.0;
				a *= 2.0;
				a /= 778.2;
				a *= 50.0;
				a *= static_cast<double>(0x7FFFF) / 1.570798233;
				mod_status_.crrd_ = 50 * 0x7ffff + static_cast<uint32_t>(a);
				++mod_status_.crrd_id_;
				++mod_status_.crm_id_;
			} else if(text.find("CRC?1") != std::string::npos) {
				double a = 0.33;
				a /= 1e6;
				a = 1.0 / (2.0 * 3.141592654 * 1000.0 * a);
				a *= 2.0;
				a /= 778.2 * 2.0;  // 778.2 mV P-P
				a *= 50.0;
				a *= static_cast<double>(0x7FFFF) / 1.570798233;
				mod_status_.crcd_ = 50 * 0x7ffff + static_cast<uint32_t>(a);
				++mod_status_.crcd_id_;
				++mod_status_.crm_id_;
			} else if(text.find("wdm 20") != std::string::npos) {
				++mod_status_.wdm_id_[2];
			}
			std::cout << text << std::endl;
			return;
#else
			if(send(sock_, text.c_str(), text.size(), 0) == SOCKET_ERROR) {
				shutdown(sock_, 2);
				closesocket(sock_);
				connect_ = false;
			}
#endif
		}
	};
}
<|endoftext|>


<commit_before>/*
 * Menu creation and other helper functions.
 * By 2MB Solutions (https://2mb.solutions)
 * Provided under the MIT license. See license.txt for details.
 * Billy: https://stormdragon.tk
 * Michael: https://michaeltaboada.me
*/
#include <dynamic_menu.h>
#include <string>
#include <vector>
#include <misc.h>
#include <soundplayer.h>
using std::string;
using std::vector;

dynamic_menu* create_menu(vector<string> items, vector<string> sounditems, vector<int(*)(dynamic_menu*, int, void*)> vec = vector<int(*)(dynamic_menu*, int, void*)>(), vector<void*> vec2 = vector<void*>()) {
int soundnumber = sounditems.size();
int numberofitems = items.size();
dynamic_menu* menu = new dynamic_menu((numberofitems > soundnumber)?numberofitems:soundnumber);
for(int x = 1; x <= numberofitems; x++) {
if(items[x-1] != "") {
menu->add_item_text(items[x-1], x, ((vec.size() >= x)?vec[x-1]:NULL), ((vec2.size() >= x)?vec2[x-1]:NULL));
}
}
for(int y = 1; y <= soundnumber; y++) {
if(sounditems[y-1] != "") {
menu->add_item_sound(sounditems[y-1], y, ((vec.size() >= y)?vec[y-1]:NULL), ((vec2.size() >= y)?vec2[y-1]:NULL));
}
}
return menu;
}

vector<string>* get_dir_children(string dir, int dir_or_file) {
ALLEGRO_FS_ENTRY *f = al_create_fs_entry((((string)(al_path_cstr(al_get_standard_path(ALLEGRO_RESOURCES_PATH), '/')))+dir).c_str());
if(!f) {
return NULL;
}
if(al_open_directory(f)) {
vector<string>* vec = new vector<string>();
ALLEGRO_FS_ENTRY *fs = al_read_directory(f);
while(fs) {
const char* fn = al_get_fs_entry_name(fs);
string fsn = "";
int x;
for(x = strlen(fn)-1; x >= 0; x--) {
if(fn[x] == '/' || fn[x] == '\\') {
break;
}
}
for(int y = x+1; y < strlen(fn); y++) {
fsn += fn[y];
}
if(dir_or_file == 0) {
vec->push_back(fsn);
}
else if(dir_or_file == 1 && (al_get_fs_entry_mode(fs) & ALLEGRO_FILEMODE_ISFILE) == ALLEGRO_FILEMODE_ISFILE) {
vec->push_back(fsn);
}
else if(dir_or_file == 2 && (al_get_fs_entry_mode(fs) & ALLEGRO_FILEMODE_ISDIR) == ALLEGRO_FILEMODE_ISDIR){
vec->push_back(fsn);
}
if(fs) {
al_destroy_fs_entry(fs);
}
fs = al_read_directory(f);
}
al_close_directory(f);
al_destroy_fs_entry(f);
return vec;
}
else {
al_destroy_fs_entry(f);
return NULL;
}
}

string generic_menu(vector<string> extra_items, string music = "") {
sound menu_music;
if(music != "") {
menu_music.load(music);
menu_music.play();
}
	vector<string> real_items;
real_items.push_back("Play game");
real_items.push_back("View instructions");
real_items.push_back("Learn game sounds.");
for (int x = 0; x < extra_items.size(); x++) {
real_items.push_back(extra_items[x]);
}
real_items.push_back("view credits");
real_items.push_back("Exit game");
dynamic_menu* menu = create_menu(real_items, vector<string>());
int pos = -1;
do {
	pos = menu->run_extended("", "Use your arrow keys to navigate the menu, and enter to select.", 1, true);
if(pos == 1) {
if(music != "")
	fade(&menu_music);
	return "play";
}
else if(pos == extra_items.size()+4) {
credits();
}
else if(pos == 2) {
instructions();
}
else if(pos == 3) {
if(music != "")
	fade(&menu_music);
	learn_sounds();
if(music != "") {
	menu_music.set_gain(0);
menu_music.play();
}
}
else if (pos == extra_items.size()+5) {
if(music != "")
	fade(&menu_music);
	return "exit";
}
else {
if(music != "")
	fade(&menu_music);
	return extra_items[pos-3];
}
}
while (pos != -1 && pos != 0 & pos != extra_items.size()+5);
if(music != "")
menu_music.stop();
return "invalid";
}

<commit_msg>Make the menu music loop.<commit_after>/*
 * Menu creation and other helper functions.
 * By 2MB Solutions (https://2mb.solutions)
 * Provided under the MIT license. See license.txt for details.
 * Billy: https://stormdragon.tk
 * Michael: https://michaeltaboada.me
*/
#include <dynamic_menu.h>
#include <string>
#include <vector>
#include <misc.h>
#include <soundplayer.h>
using std::string;
using std::vector;

dynamic_menu* create_menu(vector<string> items, vector<string> sounditems, vector<int(*)(dynamic_menu*, int, void*)> vec = vector<int(*)(dynamic_menu*, int, void*)>(), vector<void*> vec2 = vector<void*>()) {
int soundnumber = sounditems.size();
int numberofitems = items.size();
dynamic_menu* menu = new dynamic_menu((numberofitems > soundnumber)?numberofitems:soundnumber);
for(int x = 1; x <= numberofitems; x++) {
if(items[x-1] != "") {
menu->add_item_text(items[x-1], x, ((vec.size() >= x)?vec[x-1]:NULL), ((vec2.size() >= x)?vec2[x-1]:NULL));
}
}
for(int y = 1; y <= soundnumber; y++) {
if(sounditems[y-1] != "") {
menu->add_item_sound(sounditems[y-1], y, ((vec.size() >= y)?vec[y-1]:NULL), ((vec2.size() >= y)?vec2[y-1]:NULL));
}
}
return menu;
}

vector<string>* get_dir_children(string dir, int dir_or_file) {
ALLEGRO_FS_ENTRY *f = al_create_fs_entry((((string)(al_path_cstr(al_get_standard_path(ALLEGRO_RESOURCES_PATH), '/')))+dir).c_str());
if(!f) {
return NULL;
}
if(al_open_directory(f)) {
vector<string>* vec = new vector<string>();
ALLEGRO_FS_ENTRY *fs = al_read_directory(f);
while(fs) {
const char* fn = al_get_fs_entry_name(fs);
string fsn = "";
int x;
for(x = strlen(fn)-1; x >= 0; x--) {
if(fn[x] == '/' || fn[x] == '\\') {
break;
}
}
for(int y = x+1; y < strlen(fn); y++) {
fsn += fn[y];
}
if(dir_or_file == 0) {
vec->push_back(fsn);
}
else if(dir_or_file == 1 && (al_get_fs_entry_mode(fs) & ALLEGRO_FILEMODE_ISFILE) == ALLEGRO_FILEMODE_ISFILE) {
vec->push_back(fsn);
}
else if(dir_or_file == 2 && (al_get_fs_entry_mode(fs) & ALLEGRO_FILEMODE_ISDIR) == ALLEGRO_FILEMODE_ISDIR){
vec->push_back(fsn);
}
if(fs) {
al_destroy_fs_entry(fs);
}
fs = al_read_directory(f);
}
al_close_directory(f);
al_destroy_fs_entry(f);
return vec;
}
else {
al_destroy_fs_entry(f);
return NULL;
}
}

string generic_menu(vector<string> extra_items, string music = "") {
sound menu_music;
if(music != "") {
menu_music.load(music);
menu_music.set_loop(true);
menu_music.play();
}
	vector<string> real_items;
real_items.push_back("Play game");
real_items.push_back("View instructions");
real_items.push_back("Learn game sounds.");
for (int x = 0; x < extra_items.size(); x++) {
real_items.push_back(extra_items[x]);
}
real_items.push_back("view credits");
real_items.push_back("Exit game");
dynamic_menu* menu = create_menu(real_items, vector<string>());
int pos = -1;
do {
	pos = menu->run_extended("", "Use your arrow keys to navigate the menu, and enter to select.", 1, true);
if(pos == 1) {
if(music != "")
	fade(&menu_music);
	return "play";
}
else if(pos == extra_items.size()+4) {
credits();
}
else if(pos == 2) {
instructions();
}
else if(pos == 3) {
if(music != "")
	fade(&menu_music);
	learn_sounds();
if(music != "") {
	menu_music.set_gain(0);
menu_music.play();
}
}
else if (pos == extra_items.size()+5) {
if(music != "")
	fade(&menu_music);
	return "exit";
}
else {
if(music != "")
	fade(&menu_music);
	return extra_items[pos-3];
}
}
while (pos != -1 && pos != 0 & pos != extra_items.size()+5);
if(music != "")
menu_music.stop();
return "invalid";
}

<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "google/cloud/functions/internal/framework.h"
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/beast.hpp>
#include <boost/filesystem.hpp>
#include <boost/process.hpp>
#include <gmock/gmock.h>
#include <chrono>
#include <string>

namespace google::cloud::functions_internal {
inline namespace FUNCTIONS_FRAMEWORK_CPP_NS {
namespace {

using ::testing::HasSubstr;
namespace bp = boost::process;
// Even with C++17, we have to use the Boost version because Boost.Process
// expects it.
namespace bfs = boost::filesystem;
namespace beast = boost::beast;
namespace http = beast::http;
using http_response = http::response<http::string_body>;

http_response HttpGet(std::string const& host, std::string const& port,
                      std::string const& target) {
  using tcp = boost::asio::ip::tcp;

  // Create a socket to make the HTTP request over
  boost::asio::io_context ioc;
  tcp::resolver resolver(ioc);
  beast::tcp_stream stream(ioc);
  auto const results = resolver.resolve(host, port);
  stream.connect(results);

  // Use Boost.Beast to make the HTTP request
  auto constexpr kHttpVersion = 10;  // 1.0 as Boost.Beast spells it
  http::request<http::string_body> req{http::verb::get, target, kHttpVersion};
  req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
  req.set(http::field::host, host);
  http::write(stream, req);
  beast::flat_buffer buffer;
  http_response res;
  http::read(stream, buffer, res);
  stream.socket().shutdown(tcp::socket::shutdown_both);

  return res;
}

int WaitForServerReady(std::string const& host, std::string const& port) {
  auto constexpr kInitialDelay = std::chrono::milliseconds(100);
  auto constexpr kAttempts = 5;
  auto delay = kInitialDelay;
  for (int i = 0; i != kAttempts; ++i) {
    std::this_thread::sleep_for(delay);
    try {
      (void)HttpGet(host, port, "/ok");
      return 0;
    } catch (std::exception const& ex) {
      std::cerr << "WaitForServerReady[" << i << "]: failed with " << ex.what()
                << std::endl;
    }
    delay *= 2;
  }
  return -1;
}

char const* argv0 = nullptr;

TEST(RunIntegrationTest, Basic) {
  auto constexpr kOkay = 200;
  auto constexpr kNotFound = 404;
  auto constexpr kInternalError = 500;

  auto const exe = bfs::path(argv0).parent_path() / "echo_server";
  auto server = bp::child(exe, "--port=8080");
  auto result = WaitForServerReady("localhost", "8080");
  ASSERT_EQ(result, 0);

  auto actual = HttpGet("localhost", "8080", "/say/hello");
  EXPECT_EQ(actual.result_int(), kOkay);
  EXPECT_THAT(actual.body(), HasSubstr(R"js("target": "/say/hello")js"));

  actual = HttpGet("localhost", "8080", "/error/" + std::to_string(kNotFound));
  EXPECT_THAT(actual.result_int(), kNotFound);

  actual = HttpGet("localhost", "8080", "/exception/");
  EXPECT_THAT(actual.result_int(), kInternalError);

  try {
    (void)HttpGet("localhost", "8080", "/quit/program/0");
  } catch (...) {
  }
  server.wait();
  EXPECT_EQ(server.exit_code(), 0);
}

}  // namespace
}  // namespace FUNCTIONS_FRAMEWORK_CPP_NS
}  // namespace google::cloud::functions_internal

int main(int argc, char* argv[]) {
  ::testing::InitGoogleMock(&argc, argv);
  google::cloud::functions_internal::argv0 = argv[0];
  return RUN_ALL_TESTS();
}
<commit_msg>test: verify exceptions are logged (#110)<commit_after>// Copyright 2020 Google LLC
//
// 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
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "google/cloud/functions/internal/framework.h"
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/beast.hpp>
#include <boost/filesystem.hpp>
#include <boost/process.hpp>
#include <gmock/gmock.h>
#include <chrono>
#include <string>

namespace google::cloud::functions_internal {
inline namespace FUNCTIONS_FRAMEWORK_CPP_NS {
namespace {

using ::testing::HasSubstr;
namespace bp = boost::process;
// Even with C++17, we have to use the Boost version because Boost.Process
// expects it.
namespace bfs = boost::filesystem;
namespace beast = boost::beast;
namespace http = beast::http;
using http_response = http::response<http::string_body>;

http_response HttpGet(std::string const& host, std::string const& port,
                      std::string const& target) {
  using tcp = boost::asio::ip::tcp;

  // Create a socket to make the HTTP request over
  boost::asio::io_context ioc;
  tcp::resolver resolver(ioc);
  beast::tcp_stream stream(ioc);
  auto const results = resolver.resolve(host, port);
  stream.connect(results);

  // Use Boost.Beast to make the HTTP request
  auto constexpr kHttpVersion = 10;  // 1.0 as Boost.Beast spells it
  http::request<http::string_body> req{http::verb::get, target, kHttpVersion};
  req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
  req.set(http::field::host, host);
  http::write(stream, req);
  beast::flat_buffer buffer;
  http_response res;
  http::read(stream, buffer, res);
  stream.socket().shutdown(tcp::socket::shutdown_both);

  return res;
}

int WaitForServerReady(std::string const& host, std::string const& port) {
  auto constexpr kInitialDelay = std::chrono::milliseconds(100);
  auto constexpr kAttempts = 5;
  auto delay = kInitialDelay;
  for (int i = 0; i != kAttempts; ++i) {
    std::this_thread::sleep_for(delay);
    try {
      (void)HttpGet(host, port, "/ok");
      return 0;
    } catch (std::exception const& ex) {
      std::cerr << "WaitForServerReady[" << i << "]: failed with " << ex.what()
                << std::endl;
    }
    delay *= 2;
  }
  return -1;
}

char const* argv0 = nullptr;

TEST(RunIntegrationTest, Basic) {
  auto constexpr kOkay = 200;
  auto constexpr kNotFound = 404;
  auto constexpr kInternalError = 500;

  auto const exe = bfs::path(argv0).parent_path() / "echo_server";
  auto server = bp::child(exe, "--port=8080");
  auto result = WaitForServerReady("localhost", "8080");
  ASSERT_EQ(result, 0);

  auto actual = HttpGet("localhost", "8080", "/say/hello");
  EXPECT_EQ(actual.result_int(), kOkay);
  EXPECT_THAT(actual.body(), HasSubstr(R"js("target": "/say/hello")js"));

  actual = HttpGet("localhost", "8080", "/error/" + std::to_string(kNotFound));
  EXPECT_THAT(actual.result_int(), kNotFound);

  actual = HttpGet("localhost", "8080", "/exception/");
  EXPECT_THAT(actual.result_int(), kInternalError);

  try {
    (void)HttpGet("localhost", "8080", "/quit/program/0");
  } catch (...) {
  }
  server.wait();
  EXPECT_EQ(server.exit_code(), 0);
}

TEST(RunIntegrationTest, ExceptionLogsToStderr) {
  auto constexpr kInternalError = 500;

  auto const exe = bfs::path(argv0).parent_path() / "echo_server";
  bp::ipstream child_stderr;
  auto server = bp::child(exe, "--port=8080", bp::std_err > child_stderr);
  auto result = WaitForServerReady("localhost", "8080");
  ASSERT_EQ(result, 0);

  auto actual = HttpGet("localhost", "8080", "/exception/test-string");
  EXPECT_THAT(actual.result_int(), kInternalError);

  std::string line;
  std::getline(child_stderr, line);
  EXPECT_THAT(line, HasSubstr("standard C++ exception"));
  EXPECT_THAT(line, HasSubstr("/exception/test-string"));

  try {
    (void)HttpGet("localhost", "8080", "/quit/program/0");
  } catch (...) {
  }
  server.wait();
  EXPECT_EQ(server.exit_code(), 0);
}

}  // namespace
}  // namespace FUNCTIONS_FRAMEWORK_CPP_NS
}  // namespace google::cloud::functions_internal

int main(int argc, char* argv[]) {
  ::testing::InitGoogleMock(&argc, argv);
  google::cloud::functions_internal::argv0 = argv[0];
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/omi/exp_omi_utils.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2018,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file exp_omi_utils.H
/// @brief OMI utility functions
///
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: Memory
#ifndef EXP_OMI_UTILS_H_
#define EXP_OMI_UTILS_H_

#include <fapi2.H>
#include <generic/memory/lib/utils/c_str.H>

namespace mss
{
namespace exp
{
namespace omi
{

///
/// @brief Constants used for the OMI register fields
///
// TODO:RTC196850 Update Explorer code to use actual register addresses/names
enum fields
{
    // Bit we set to put ourselves into enterprise mode
    ENTERPRISE_SET_BIT = 0,
    HALF_DIMM_MODE = 1,
    // How the HW is actually configured in enterprise mode
    ENTERPRISE_BIT_CONFIG = 2,
};

///
/// @brief Constants used for the OMI registers
///
// TODO:RTC196850 Update Explorer code to use actual register addresses/names
enum registers
{
    // Bit we set to put ourselves into enterprise mode
    MENTERP = 0x080108e4,
};

///////////////////////////////////////////////////////////////////////////////////
/// Bit Field Operations
///////////////////////////////////////////////////////////////////////////////////

///
/// @brief Gets the enterprise set bit
/// @param[in] i_data the register data
/// @return The register's ENTERPRISE_SET_BIT
///
inline bool get_enterprise_set_bit( const fapi2::buffer<uint64_t>& i_data )
{
    return i_data.getBit<fields::ENTERPRISE_SET_BIT>();
}

///
/// @brief Sets the enterprise set bit
/// @param[in,out] io_data the register data
/// @param[in] i_is_enterprise true IFF we're in enterprise mode
///
inline void set_enterprise_set_bit( fapi2::buffer<uint64_t>& io_data, const bool i_is_enterprise )
{
    io_data.writeBit<fields::ENTERPRISE_SET_BIT>(i_is_enterprise);
}

///
/// @brief Gets the half-DIMM mode
/// @param[in] i_data the register data
/// @return The register's HALF_DIMM_MODE
///
inline bool get_half_dimm_mode( const fapi2::buffer<uint64_t>& i_data )
{
    return i_data.getBit<fields::HALF_DIMM_MODE>();
}

///
/// @brief Sets the half-DIMM mode
/// @param[in,out] io_data the register data
/// @param[in] i_is_half_dimm_mode true IFF we're in half_dimm_mode mode
///
inline void set_half_dimm_mode( fapi2::buffer<uint64_t>& io_data, const bool i_is_half_dimm_mode )
{
    io_data.writeBit<fields::HALF_DIMM_MODE>(i_is_half_dimm_mode);
}

// Note: ENTERPRISE_BIT_CONFIG is a Read only bit, so no setting it
///
/// @brief Gets the enterprise config bit
/// @param[in] i_data the register data
/// @return The register's ENTERPRISE_BIT_CONFIG
/// @note This bit indicates whether the hardware is in enterprise mode
///
inline bool get_enterprise_config( const fapi2::buffer<uint64_t>& i_data )
{
    return i_data.getBit<fields::ENTERPRISE_BIT_CONFIG>();
}

///
/// @brief Checks if the enterprise config bit is in the correct mode
/// @param[in] i_target target on which we are operating - for logging
/// @param[in] i_is_enterprise true if the chip should be in enterprise mode
/// @param[in] i_data data from the enterprise mode register
/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff everything is OK
///
inline fapi2::ReturnCode check_enterprise_mode( const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target,
        const bool i_is_enterprise,
        fapi2::buffer<uint64_t>& i_data )
{
    const bool l_actual = mss::exp::omi::get_enterprise_config(i_data);
    FAPI_ASSERT(l_actual == i_is_enterprise,
                fapi2::MSS_EXP_ENTERPRISE_SETUP_ERROR()
                .set_EXPECTED(i_is_enterprise)
                .set_ACTUAL(l_actual)
                .set_REGISTER_DATA(i_data)
                .set_OCMB_TARGET(i_target),
                "%s failed to setup enterprise mode properly expected: %u actual: %u register data 0x%016lx",
                mss::c_str(i_target), i_is_enterprise, l_actual, i_data);

fapi_try_exit:
    return fapi2::current_err;
}

///////////////////////////////////////////////////////////////////////////////////
/// Register access operations
///////////////////////////////////////////////////////////////////////////////////
// The scom API should be able to distinguish between the need for i2c vs MMIO

///
/// @brief Reads the register using I2C
/// @param[in] i_target the OCMB target on which to operate
/// @param[out] o_data the register contents
/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK
///
inline fapi2::ReturnCode read_enterprise_config( const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target,
        fapi2::buffer<uint64_t>& o_data )
{
    return fapi2::getScom(i_target, registers::MENTERP, o_data);
}

///
/// @brief Writes the register using I2C
/// @param[in] i_target the OCMB target on which to operate
/// @param[in] i_data the register contents
/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK
///
inline fapi2::ReturnCode write_enterprise_config( const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target,
        const  fapi2::buffer<uint64_t>& i_data )
{
    return fapi2::putScom(i_target, registers::MENTERP, i_data);
}

} // ns mss

} // ns exp

} // ns omi

#endif
<commit_msg>Adds explorer OMI training code<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/omi/exp_omi_utils.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2018,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file exp_omi_utils.H
/// @brief OMI utility functions
///
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: Memory
#ifndef EXP_OMI_UTILS_H_
#define EXP_OMI_UTILS_H_

#include <fapi2.H>
#include <generic/memory/lib/utils/c_str.H>

namespace mss
{
namespace exp
{
namespace omi
{

///
/// @brief Constants used for the OMI register fields
///
// TODO:RTC196850 Update Explorer code to use actual register addresses/names
enum fields
{
    // Bit we set to put ourselves into enterprise mode
    ENTERPRISE_SET_BIT = 0,
    HALF_DIMM_MODE = 1,
    // How the HW is actually configured in enterprise mode
    ENTERPRISE_BIT_CONFIG = 2,
};

///
/// @brief Constants used for the OMI registers
///
// TODO:RTC196850 Update Explorer code to use actual register addresses/names
enum registers
{
    // Bit we set to put ourselves into enterprise mode
    MENTERP = 0x080108e4,
};

///////////////////////////////////////////////////////////////////////////////////
/// Bit Field Operations
///////////////////////////////////////////////////////////////////////////////////

///
/// @brief Gets the enterprise set bit
/// @param[in] i_data the register data
/// @return The register's ENTERPRISE_SET_BIT
///
inline bool get_enterprise_set_bit( const fapi2::buffer<uint64_t>& i_data )
{
    return i_data.getBit<fields::ENTERPRISE_SET_BIT>();
}

///
/// @brief Sets the enterprise set bit
/// @param[in,out] io_data the register data
/// @param[in] i_is_enterprise true IFF we're in enterprise mode
///
inline void set_enterprise_set_bit( fapi2::buffer<uint64_t>& io_data, const bool i_is_enterprise )
{
    io_data.writeBit<fields::ENTERPRISE_SET_BIT>(i_is_enterprise);
}

///
/// @brief Gets the half-DIMM mode
/// @param[in] i_data the register data
/// @return The register's HALF_DIMM_MODE
///
inline bool get_half_dimm_mode( const fapi2::buffer<uint64_t>& i_data )
{
    return i_data.getBit<fields::HALF_DIMM_MODE>();
}

///
/// @brief Sets the half-DIMM mode
/// @param[in,out] io_data the register data
/// @param[in] i_is_half_dimm_mode true IFF we're in half_dimm_mode mode
///
inline void set_half_dimm_mode( fapi2::buffer<uint64_t>& io_data, const bool i_is_half_dimm_mode )
{
    io_data.writeBit<fields::HALF_DIMM_MODE>(i_is_half_dimm_mode);
}

// Note: ENTERPRISE_BIT_CONFIG is a Read only bit, so no setting it
///
/// @brief Gets the enterprise config bit
/// @param[in] i_data the register data
/// @return The register's ENTERPRISE_BIT_CONFIG
/// @note This bit indicates whether the hardware is in enterprise mode
///
inline bool get_enterprise_config( const fapi2::buffer<uint64_t>& i_data )
{
    return i_data.getBit<fields::ENTERPRISE_BIT_CONFIG>();
}

///
/// @brief Checks if the enterprise config bit is in the correct mode
/// @param[in] i_target target on which we are operating - for logging
/// @param[in] i_is_enterprise true if the chip should be in enterprise mode
/// @param[in] i_data data from the enterprise mode register
/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff everything is OK
///
inline fapi2::ReturnCode check_enterprise_mode( const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target,
        const bool i_is_enterprise,
        fapi2::buffer<uint64_t>& i_data )
{
    const bool l_actual = mss::exp::omi::get_enterprise_config(i_data);
    FAPI_ASSERT(l_actual == i_is_enterprise,
                fapi2::MSS_EXP_ENTERPRISE_SETUP_ERROR()
                .set_EXPECTED(i_is_enterprise)
                .set_ACTUAL(l_actual)
                .set_REGISTER_DATA(i_data)
                .set_OCMB_TARGET(i_target),
                "%s failed to setup enterprise mode properly expected: %u actual: %u register data 0x%016lx",
                mss::c_str(i_target), i_is_enterprise, l_actual, i_data);

fapi_try_exit:
    return fapi2::current_err;
}

///////////////////////////////////////////////////////////////////////////////////
/// Register access operations
///////////////////////////////////////////////////////////////////////////////////
// The scom API should be able to distinguish between the need for i2c vs MMIO

///
/// @brief Reads the register using I2C
/// @param[in] i_target the OCMB target on which to operate
/// @param[out] o_data the register contents
/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK
///
inline fapi2::ReturnCode read_enterprise_config( const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target,
        fapi2::buffer<uint64_t>& o_data )
{
    return fapi2::getScom(i_target, registers::MENTERP, o_data);
}

///
/// @brief Writes the register using I2C
/// @param[in] i_target the OCMB target on which to operate
/// @param[in] i_data the register contents
/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK
///
inline fapi2::ReturnCode write_enterprise_config( const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target,
        const  fapi2::buffer<uint64_t>& i_data )
{
    return fapi2::putScom(i_target, registers::MENTERP, i_data);
}

namespace train
{

///
/// @brief Sets up the OMI training
/// @param[in] i_target target on which the code is operating
/// @param[in] i_manufacturing_mode manufacturing mode control
/// @param[in] i_loopback_testing loopback testing control
/// @param[in] i_transport_layer transport layer configuration
/// @param[in] i_dl_layer DL layer boot mode
/// @param[in] i_boot_mode true if step-by-step mode
/// @param[in] i_lane_mode lane mode configuration
/// @param[in] i_serdes serdes frequency
/// @param[out] o_data data for the FW_BOOT_CONFIG
/// @return fapi2::ReturnCode - FAPI2_RC_SUCCESS iff get is OK
///
fapi2::ReturnCode setup_fw_boot_config( const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target,
                                        const uint8_t i_manufacturing_mode,
                                        const uint8_t i_loopback_testing,
                                        const uint8_t i_transport_layer,
                                        const uint8_t i_dl_layer,
                                        const uint8_t i_boot_mode,
                                        const uint8_t i_lane_mode,
                                        const uint8_t i_serdes,
                                        std::vector<uint8_t>& o_data );

} // ns train

} // ns omi

} // ns exp

} // ns mss

#endif
<|endoftext|>


<commit_before>#ifndef BFC_AST_MOD_HPP
#define BFC_AST_MOD_HPP

#include "types.h"

#include "ast/base.hpp"
#include "ast/seq.hpp"
#include "ast/traits.hpp"
#include "ast/visitor.hpp"
#include "token.hpp"

#include <cstddef>

namespace bfc {
namespace ast {

/* NB: when adding visitable node types, make sure you add a forward
 * declaration in "ast/visitor.hpp" and a visit overload on the visitor
 * abstract class.
 */

class set :public base_crtp<set>, public arith {
public:
  set(source_loc loc, ptrdiff_t offset, bf_value value) noexcept :
    arith{std::move(loc), offset, value}
  {}
};

class add : public base_crtp<add>, public arith {
public:
  add(source_loc loc, ptrdiff_t offset, bf_value value) noexcept :
    arith{std::move(loc), offset, value}
  {}
};

class sub : public base_crtp<sub>, public arith {
public:
  sub(source_loc loc, ptrdiff_t offset, bf_value value) noexcept :
    arith{std::move(loc), offset, value}
  {}
};

class mul : public base_crtp<mul>, public arith {
public:
  mul(source_loc loc, ptrdiff_t offset, bf_value value) noexcept :
    arith{std::move(loc), offset, value}
  {}
};

class mov : public base_crtp<mov>, public ptr_op {
public:
  mov(source_loc loc, ptrdiff_t offset) noexcept :
    ptr_op{std::move(loc), offset}
  {}
};

class program : public has_loc, public seq {
public:
  program(source_loc loc, seq op_seq) noexcept :
    has_loc{std::move(loc)}, seq{std::move(op_seq)}
  {}
};

class loop : public has_loc, public seq {
public:
  loop(source_loc begin_pos, seq op_seq) noexcept :
    has_loc{begin_pos}, seq{std::move(op_seq)}
  {}
};

class read : public io {
public:
  read(source_loc loc, ptrdiff_t offset) noexcept :
    io{std::move(loc), offset}
  {}
};

class write : public io {
public:
  write(source_loc loc, ptrdiff_t offset) noexcept :
    io{std::move(loc), offset}
  {}
};

}
}

#endif /* !BFC_AST_HPP */
<commit_msg>Fix ambiguous inheritance chains (diamond problem is bad).<commit_after>#ifndef BFC_AST_MOD_HPP
#define BFC_AST_MOD_HPP

#include "types.h"

#include "ast/base.hpp"
#include "ast/seq.hpp"
#include "ast/traits.hpp"
#include "ast/visitor.hpp"
#include "token.hpp"

#include <cstddef>

namespace bfc {
namespace ast {

/* NB: when adding visitable node types, make sure you add a forward
 * declaration in "ast/visitor.hpp" and a visit overload on the visitor
 * abstract class.
 */

class set : public base_crtp<set>, public arith {
public:
  set(source_loc loc, ptrdiff_t offset, bf_value value) noexcept :
    arith{std::move(loc), offset, value}
  {}
};

class add : public base_crtp<add>, public arith {
public:
  add(source_loc loc, ptrdiff_t offset, bf_value value) noexcept :
    arith{std::move(loc), offset, value}
  {}
};

class sub : public base_crtp<sub>, public arith {
public:
  sub(source_loc loc, ptrdiff_t offset, bf_value value) noexcept :
    arith{std::move(loc), offset, value}
  {}
};

class mul : public base_crtp<mul>, public arith {
public:
  mul(source_loc loc, ptrdiff_t offset, bf_value value) noexcept :
    arith{std::move(loc), offset, value}
  {}
};

class mov : public base_crtp<mov>, public ptr_op {
public:
  mov(source_loc loc, ptrdiff_t offset) noexcept :
    ptr_op{std::move(loc), offset}
  {}
};

/* Cannot inherit from base_crtp because of the diamond problem. */
class program : public has_loc, public seq {
public:
  program(source_loc loc, seq op_seq) noexcept :
    has_loc{std::move(loc)}, seq{std::move(op_seq)}
  {}
  visitor::status accept(visitor &obj) override
  {
    return obj.visit(*this);
  }
  visitor::status accept(visitor &obj) const override
  {
    return obj.visit(*this);
  }
private:
  base *clone(void) const override
  {
    return new program{*this};
  }
};

/* Cannot inherit from base_crtp because of the diamond problem. */
class loop : public has_loc, public seq {
public:
  loop(source_loc begin_pos, seq op_seq) noexcept :
    has_loc{begin_pos}, seq{std::move(op_seq)}
  {}
  visitor::status accept(visitor &obj) override
  {
    return obj.visit(*this);
  }
  visitor::status accept(visitor &obj) const override
  {
    return obj.visit(*this);
  }
private:
  base *clone(void) const override
  {
    return new loop{*this};
  }
};

class read : public base_crtp<read>, public io {
public:
  read(source_loc loc, ptrdiff_t offset) noexcept :
    io{std::move(loc), offset}
  {}
};

class write : public base_crtp<write>, public io {
public:
  write(source_loc loc, ptrdiff_t offset) noexcept :
    io{std::move(loc), offset}
  {}
};

}
}

#endif /* !BFC_AST_HPP */
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/shared/exp_consts.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2018,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
<commit_msg>Added I2C fields, EXP_FW_STATUS API<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/ocmb/explorer/procedures/hwp/memory/lib/shared/exp_consts.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2018,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file explorer_check_for_ready.H
/// @brief explorer_check_for_ready HWP declaration
///
// *HWP HWP Owner: Andre A. Marin <aamarin@us.ibm.com>
// *HWP HWP Backup: Louis Stermole <stermole@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: CI

namespace mss
{
namespace exp
{
namespace i2c
{

///
/// @brief explorer ffdc codes
///
enum ffdc_codes
{
    EXP_I2C_GET_FIELD = 0x0000,
    EXP_I2C_SET_FIELD = 0x0001,
};

/// @brief List of explorer I2C commands
///
enum cmd_id : uint8_t
{
    FW_BOOT_CONFIG     = 0x01,
    FW_STATUS          = 0x02,
    FW_REG_ADDR_LATCH  = 0x03,
    FW_REG_READ        = 0x04,
    FW_REG_WRITE       = 0x05,
    FW_DOWNLOAD        = 0x06,
    FW_CONT_REG_READ   = 0x07,
    FW_CONT_REG_WRITE  = 0x08,
};

///
/// @brief common explorer sizes
///
enum sizes
{
    // 32-bit commands
    FW_BOOT_CONFIG_BYTE_LEN = 4,
    FW_STATUS_BYTE_LEN      = 4,

    // Largest R/W length for bytes of data
    MIN_DATA_BYTES_LEN = 1,
    MAX_DATA_BYTES_LEN = 32,
};

///
/// @brief General I2C status codes
/// @note Shared I2C status codes for EXP_FW_REG_READ, EXP_FW_REG_WRITE,
/// EXP_FW_CONT_REG_READ, and EXP_FW_CONT_REG_WRITE
///
enum status_codes
{
    SUCCESS              = 0x00,
    ADDRESS_OUT_OF_RANGE = 0x01,
    ADDRESS_PROHIBITED   = 0x02,
};

///
/// @brief status codes for FW_BOOT_CONFIG
///
enum fw_boot_cfg_status
{
    FW_BOOT_CFG_SUCCESS                 = status_codes::SUCCESS,

    // Loopback fail
    FW_BOOT_CFG_LB_FAIL                 = 0x01,
    // Transport layer fail
    FW_BOOT_CFG_UNSUPPORTED_TL          = 0x02,
    // DL (data link) layer fail
    FW_BOOT_CFG_UNSUPPORTED_DL          = 0x03,
    // SERDES (serializer/deserializer) FREQ fail
    FW_BOOT_CFG_UNSUPPORTED_SERDES_FREQ = 0x04,
};

///
/// @brief I2C boot stage options
/// @note certain cmds work in certain boot stages
///
enum boot_stages
{
    BOOT_ROM_STAGE  = 0x01,
    FW_UPGRADE_MODE = 0x02,
    RUNTIME_FW      = 0x03,
};

}// i2c
}// exp
}// mss
<|endoftext|>


<commit_before><commit_msg>bortli compression detection fixed<commit_after><|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/* cacheurl.cc - Plugin to modify the URL used as a cache key for certain
 * requests, without modifying the URL used for actually fetching data from
 * the origin server.
 */

#include <stdio.h>
#include <string.h>

#include "ink_config.h"

#ifdef HAVE_PCRE_PCRE_H
#include <pcre/pcre.h>
#else
#include <pcre.h>
#endif

#include "ts/ts.h"
#include "ts/remap.h"
#include "ink_defs.h"
#include <string>
#include <vector>

#define TOKENCOUNT 10
#define OVECOUNT 30
#define PLUGIN_NAME "cacheurl"

struct regex_info
{
  pcre *re;                     /* Compiled regular expression */
  int tokcount;                 /* Token count */
  char *pattern;                /* Pattern string */
  char *replacement;            /* Replacement string */
  int *tokens;                  /* Array of $x token values */
  int *tokenoffset;             /* Array of $x token offsets */
};

struct pr_list
{
  std::vector<regex_info*>pr;

  pr_list()
  {
  }

  ~pr_list()
  {
    for (std::vector < regex_info * >::iterator info = this->pr.begin(); info != this->pr.end(); ++info) {
      TSfree((*info)->tokens);
      TSfree((*info)->tokenoffset);
      pcre_free((*info)->re);
      TSfree(*info);
    }
  }
};

static int
regex_substitute(char **buf, char *str, regex_info * info)
{
  int matchcount;
  int ovector[OVECOUNT];        /* Locations of matches in regex */

  int replacelen;               /* length of replacement string */
  int i;
  int offset;
  int prev;

  /* Perform the regex matching */
  matchcount = pcre_exec(info->re, NULL, str, strlen(str), 0, 0, ovector, OVECOUNT);
  if (matchcount < 0) {
    switch (matchcount) {
    case PCRE_ERROR_NOMATCH:
      break;
    default:
      TSError("[%s] Matching error: %d\n", PLUGIN_NAME, matchcount);
      break;
    }
    return 0;
  }

  /* Verify the replacement has the right number of matching groups */
  for (i = 0; i < info->tokcount; i++) {
    if (info->tokens[i] >= matchcount) {
      TSError("[%s] Invalid reference int replacement: $%d\n", PLUGIN_NAME, info->tokens[i]);
      return 0;
    }
  }

  /* malloc the replacement string */
  replacelen = strlen(info->replacement);
  replacelen -= info->tokcount * 2;     /* Subtract $1, $2 etc... */
  for (i = 0; i < info->tokcount; i++) {
    replacelen += (ovector[info->tokens[i] * 2 + 1] - ovector[info->tokens[i] * 2]);
  }
  replacelen++;                 /* Null terminator */
  *buf = (char *) TSmalloc(replacelen);

  /* perform string replacement */
  offset = 0;                   /* Where we are adding new data in the string */
  prev = 0;
  for (i = 0; i < info->tokcount; i++) {
    memcpy(*buf + offset, info->replacement + prev, info->tokenoffset[i] - prev);
    offset += (info->tokenoffset[i] - prev);
    prev = info->tokenoffset[i] + 2;

    memcpy(*buf + offset, str + ovector[info->tokens[i] * 2],
           ovector[info->tokens[i] * 2 + 1] - ovector[info->tokens[i] * 2]);
    offset += (ovector[info->tokens[i] * 2 + 1] - ovector[info->tokens[i] * 2]);
  }
  memcpy(*buf + offset, info->replacement + prev, strlen(info->replacement) - prev);
  offset += strlen(info->replacement) - prev;
  (*buf)[offset] = 0;           /* Null termination */
  return 1;
}

static int
regex_compile(regex_info ** buf, char *pattern, char *replacement)
{
  const char *reerror;          /* Error string from pcre */
  int reerroffset;              /* Offset where any pcre error occured */

  int tokcount;
  int *tokens;
  int *tokenoffset;

  int status = 1;               /* Status (return value) of the function */
  regex_info *info = (regex_info *) TSmalloc(sizeof(regex_info));

  /* Precompile the regular expression */
  info->re = pcre_compile(pattern, 0, &reerror, &reerroffset, NULL);
  if (!info->re) {
    TSError("[%s] Compilation of regex '%s' failed at char %d: %s\n", PLUGIN_NAME, pattern, reerroffset, reerror);
    status = 0;
  }

  /* Precalculate the location of $X tokens in the replacement */
  tokcount = 0;
  if (status) {
    tokens = (int *) TSmalloc(sizeof(int) * TOKENCOUNT);
    tokenoffset = (int *) TSmalloc(sizeof(int) * TOKENCOUNT);
    for (unsigned i = 0; i < strlen(replacement); i++) {
      if (replacement[i] == '$') {
        if (tokcount >= TOKENCOUNT) {
          TSError("[%s] Error: too many tokens in replacement " "string: %s\n", PLUGIN_NAME, replacement);
          status = 0;
          break;
        } else if (replacement[i + 1] < '0' || replacement[i + 1] > '9') {
          TSError("[%s] Error: Invalid replacement token $%c in %s: should be $0 - $9\n",
                  PLUGIN_NAME, replacement[i + 1], replacement);
          status = 0;
          break;
        } else {
          /* Store the location of the replacement */
          /* Convert '0' to 0 */
          tokens[tokcount] = replacement[i + 1] - '0';
          tokenoffset[tokcount] = i;
          tokcount++;
          /* Skip the next char */
          i++;
        }
      }
    }
  }

  if (status) {
    /* Everything went OK */
    info->tokcount = tokcount;
    info->tokens = tokens;
    info->tokenoffset = tokenoffset;

    info->pattern = TSstrdup(pattern);
    info->replacement = TSstrdup(replacement);

    *buf = info;
  } else {
    /* Something went wrong, clean up */
    if (info->tokens)
      TSfree(info->tokens);
    if (info->tokenoffset)
      TSfree(info->tokenoffset);
    if (info->re)
      pcre_free(info->re);
    if (info)
      TSfree(info);
  }
  return status;
}

static pr_list *
load_config_file(const char *config_file)
{
  char buffer[1024];
  std::string path;
  TSFile fh;
  pr_list *prl = new pr_list();

  /* locations in a config file line, end of line, split start, split end */
  char *eol, *spstart, *spend;
  int lineno = 0;
  int retval;
  regex_info *info = 0;

  if (config_file == NULL) {
    /* Default config file of plugins/cacheurl.config */
    path = TSPluginDirGet();
    path += "/cacheurl.config";
  } else if (*config_file != '/') {
    // Relative paths are relative to the config directory
    path = TSConfigDirGet();
    path += "/";
    path += config_file;
  } else {
    // Absolute path ...
    path = config_file;
  }

  TSDebug(PLUGIN_NAME, "Opening config file: %s", path.c_str());
  fh = TSfopen(path.c_str(), "r");

  if (!fh) {
    TSError("[%s] Unable to open %s. No patterns will be loaded\n", PLUGIN_NAME, path.c_str());
    return prl;
  }

  while (TSfgets(fh, buffer, sizeof(buffer) - 1)) {
    lineno++;
    if (*buffer == '#') {
      /* # Comments, only at line beginning */
      continue;
    }
    eol = strstr(buffer, "\n");
    if (eol) {
      *eol = 0;                 /* Terminate string at newline */
    } else {
      /* Malformed line - skip */
      continue;
    }
    /* Split line into two parts based on whitespace */
    /* Find first whitespace */
    spstart = strstr(buffer, " ");
    if (!spstart) {
      spstart = strstr(buffer, "\t");
    }
    if (!spstart) {
      TSError("[%s] ERROR: Invalid format on line %d. Skipping\n", PLUGIN_NAME, lineno);
      continue;
    }
    /* Find part of the line after any whitespace */
    spend = spstart + 1;
    while (*spend == ' ' || *spend == '\t') {
      spend++;
    }
    if (*spend == 0) {
      /* We reached the end of the string without any non-whitepace */
      TSError("[%s] ERROR: Invalid format on line %d. Skipping\n", PLUGIN_NAME, lineno);
      continue;
    }

    *spstart = 0;
    /* We have the pattern/replacement, now do precompilation.
     * buffer is the first part of the line. spend is the second part just
     * after the whitespace */
    TSDebug(PLUGIN_NAME, "Adding pattern/replacement pair: '%s' -> '%s'", buffer, spend);
    retval = regex_compile(&info, buffer, spend);
    if (!retval) {
      TSError("[%s] Error precompiling regex/replacement. Skipping.\n", PLUGIN_NAME);
    }

    prl->pr.push_back(info);
  }
  TSfclose(fh);

  TSDebug(PLUGIN_NAME, "loaded %u regexes", (unsigned) prl->pr.size());
  return prl;
}

static int
rewrite_cacheurl(pr_list * prl, TSHttpTxn txnp)
{
  int ok = 1;
  char *newurl = 0;
  int retval;
  char *url;
  int url_length;

  url = TSHttpTxnEffectiveUrlStringGet(txnp, &url_length);
  if (!url) {
    TSError("[%s] couldn't retrieve request url\n", PLUGIN_NAME);
    ok = 0;
  }

  if (ok) {
    for (std::vector<regex_info*>::iterator info = prl->pr.begin(); info != prl->pr.end(); ++info) {
      retval = regex_substitute(&newurl, url, *info);
      if (retval) {
        /* Successful match/substitution */
        break;
      }
    }
    if (newurl) {
      TSDebug(PLUGIN_NAME, "Rewriting cache URL for %s to %s", url, newurl);
      if (TSCacheUrlSet(txnp, newurl, strlen(newurl))
          != TS_SUCCESS) {
        TSError("[%s] Unable to modify cache url from " "%s to %s\n", PLUGIN_NAME, url, newurl);
        ok = 0;
      }
    }
  }

  /* Clean up */
  if (url)
    TSfree(url);
  if (newurl)
    TSfree(newurl);

  return ok;
}

static int
handle_hook(TSCont contp, TSEvent event, void *edata)
{
  TSHttpTxn txnp = (TSHttpTxn) edata;
  pr_list *prl;
  int ok = 1;

  prl = (pr_list *) TSContDataGet(contp);

  switch (event) {
  case TS_EVENT_HTTP_READ_REQUEST_HDR:
    ok = rewrite_cacheurl(prl, txnp);
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    break;
  default:
    TSAssert(!"Unexpected event");
    ok = 0;
    break;
  }

  return ok;
}

/* Generic error message function for errors in plugin initialization */
static void
initialization_error(const char *msg)
{
  TSError("[%s] %s\n", PLUGIN_NAME, msg);
  TSError("[%s] Unable to initialize plugin (disabled).\n", PLUGIN_NAME);
}

TSReturnCode
TSRemapInit(TSRemapInterface * api_info, char *errbuf, int errbuf_size)
{
  if (!api_info) {
    strncpy(errbuf, "[tsremap_init] Invalid TSRemapInterface argument", errbuf_size - 1);
    return TS_ERROR;
  }

  if (api_info->size < sizeof(TSRemapInterface)) {
    strncpy(errbuf, "[tsremap_init] Incorrect size of TSRemapInterface structure", errbuf_size - 1);
    return TS_ERROR;
  }

  if (api_info->tsremap_version < TSREMAP_VERSION) {
    snprintf(errbuf, errbuf_size - 1, "[tsremap_init] Incorrect API version %ld.%ld",
             api_info->tsremap_version >> 16, (api_info->tsremap_version & 0xffff));
    return TS_ERROR;
  }

  TSDebug(PLUGIN_NAME, "remap plugin is successfully initialized");
  return TS_SUCCESS;
}

TSReturnCode
TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf ATS_UNUSED, int errbuf_size ATS_UNUSED)
{
  *ih = load_config_file(argc > 2 ? argv[2] : NULL);
  return TS_SUCCESS;
}

void
TSRemapDeleteInstance(void *ih)
{
  pr_list *prl = (pr_list *) ih;

  TSDebug(PLUGIN_NAME, "Deleting remap instance");

  delete prl;
}

TSRemapStatus
TSRemapDoRemap(void *ih, TSHttpTxn rh, TSRemapRequestInfo * rri ATS_UNUSED)
{
  int ok;

  ok = rewrite_cacheurl((pr_list *) ih, rh);
  if (ok) {
    return TSREMAP_NO_REMAP;
  } else {
    return TSREMAP_ERROR;
  }
}

void
TSPluginInit(int argc, const char *argv[])
{
  TSPluginRegistrationInfo info;
  TSCont contp;
  pr_list *prl;

  info.plugin_name = (char *) PLUGIN_NAME;
  info.vendor_name = (char *) "Apache Software Foundation";
  info.support_email = (char *) "dev@trafficserver.apache.org";

  if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
    initialization_error("Plugin registration failed.");
    return;
  }

  prl = load_config_file(argc > 1 ? argv[1] : NULL);

  contp = TSContCreate((TSEventFunc) handle_hook, NULL);
  /* Store the pattern replacement list in the continuation */
  TSContDataSet(contp, prl);
  TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, contp);
}
<commit_msg>TS-1475: Coverity 120023 120024 - fix resource leak<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/* cacheurl.cc - Plugin to modify the URL used as a cache key for certain
 * requests, without modifying the URL used for actually fetching data from
 * the origin server.
 */

#include <stdio.h>
#include <string.h>

#include "ink_config.h"

#ifdef HAVE_PCRE_PCRE_H
#include <pcre/pcre.h>
#else
#include <pcre.h>
#endif

#include "ts/ts.h"
#include "ts/remap.h"
#include "ink_defs.h"
#include <string>
#include <vector>

#define TOKENCOUNT 10
#define OVECOUNT 30
#define PLUGIN_NAME "cacheurl"

struct regex_info
{
  pcre *re;                     /* Compiled regular expression */
  int tokcount;                 /* Token count */
  char *pattern;                /* Pattern string */
  char *replacement;            /* Replacement string */
  int *tokens;                  /* Array of $x token values */
  int *tokenoffset;             /* Array of $x token offsets */
};

struct pr_list
{
  std::vector<regex_info*>pr;

  pr_list()
  {
  }

  ~pr_list()
  {
    for (std::vector < regex_info * >::iterator info = this->pr.begin(); info != this->pr.end(); ++info) {
      TSfree((*info)->tokens);
      TSfree((*info)->tokenoffset);
      pcre_free((*info)->re);
      TSfree(*info);
    }
  }
};

static int
regex_substitute(char **buf, char *str, regex_info * info)
{
  int matchcount;
  int ovector[OVECOUNT];        /* Locations of matches in regex */

  int replacelen;               /* length of replacement string */
  int i;
  int offset;
  int prev;

  /* Perform the regex matching */
  matchcount = pcre_exec(info->re, NULL, str, strlen(str), 0, 0, ovector, OVECOUNT);
  if (matchcount < 0) {
    switch (matchcount) {
    case PCRE_ERROR_NOMATCH:
      break;
    default:
      TSError("[%s] Matching error: %d\n", PLUGIN_NAME, matchcount);
      break;
    }
    return 0;
  }

  /* Verify the replacement has the right number of matching groups */
  for (i = 0; i < info->tokcount; i++) {
    if (info->tokens[i] >= matchcount) {
      TSError("[%s] Invalid reference int replacement: $%d\n", PLUGIN_NAME, info->tokens[i]);
      return 0;
    }
  }

  /* malloc the replacement string */
  replacelen = strlen(info->replacement);
  replacelen -= info->tokcount * 2;     /* Subtract $1, $2 etc... */
  for (i = 0; i < info->tokcount; i++) {
    replacelen += (ovector[info->tokens[i] * 2 + 1] - ovector[info->tokens[i] * 2]);
  }
  replacelen++;                 /* Null terminator */
  *buf = (char *) TSmalloc(replacelen);

  /* perform string replacement */
  offset = 0;                   /* Where we are adding new data in the string */
  prev = 0;
  for (i = 0; i < info->tokcount; i++) {
    memcpy(*buf + offset, info->replacement + prev, info->tokenoffset[i] - prev);
    offset += (info->tokenoffset[i] - prev);
    prev = info->tokenoffset[i] + 2;

    memcpy(*buf + offset, str + ovector[info->tokens[i] * 2],
           ovector[info->tokens[i] * 2 + 1] - ovector[info->tokens[i] * 2]);
    offset += (ovector[info->tokens[i] * 2 + 1] - ovector[info->tokens[i] * 2]);
  }
  memcpy(*buf + offset, info->replacement + prev, strlen(info->replacement) - prev);
  offset += strlen(info->replacement) - prev;
  (*buf)[offset] = 0;           /* Null termination */
  return 1;
}

static int
regex_compile(regex_info ** buf, char *pattern, char *replacement)
{
  const char *reerror;          /* Error string from pcre */
  int reerroffset;              /* Offset where any pcre error occured */

  int tokcount;
  int *tokens = NULL;
  int *tokenoffset = NULL;

  int status = 1;               /* Status (return value) of the function */
  regex_info *info = (regex_info *) TSmalloc(sizeof(regex_info));

  /* Precompile the regular expression */
  info->re = pcre_compile(pattern, 0, &reerror, &reerroffset, NULL);
  if (!info->re) {
    TSError("[%s] Compilation of regex '%s' failed at char %d: %s\n", PLUGIN_NAME, pattern, reerroffset, reerror);
    status = 0;
  }

  /* Precalculate the location of $X tokens in the replacement */
  tokcount = 0;
  if (status) {
    tokens = (int *) TSmalloc(sizeof(int) * TOKENCOUNT);
    tokenoffset = (int *) TSmalloc(sizeof(int) * TOKENCOUNT);
    for (unsigned i = 0; i < strlen(replacement); i++) {
      if (replacement[i] == '$') {
        if (tokcount >= TOKENCOUNT) {
          TSError("[%s] Error: too many tokens in replacement " "string: %s\n", PLUGIN_NAME, replacement);
          status = 0;
          break;
        } else if (replacement[i + 1] < '0' || replacement[i + 1] > '9') {
          TSError("[%s] Error: Invalid replacement token $%c in %s: should be $0 - $9\n",
                  PLUGIN_NAME, replacement[i + 1], replacement);
          status = 0;
          break;
        } else {
          /* Store the location of the replacement */
          /* Convert '0' to 0 */
          tokens[tokcount] = replacement[i + 1] - '0';
          tokenoffset[tokcount] = i;
          tokcount++;
          /* Skip the next char */
          i++;
        }
      }
    }
  }

  if (status) {
    /* Everything went OK */
    info->tokcount = tokcount;
    info->tokens = tokens;
    info->tokenoffset = tokenoffset;

    info->pattern = TSstrdup(pattern);
    info->replacement = TSstrdup(replacement);

    *buf = info;
  } else {
    /* Something went wrong, clean up */
    TSfree(tokens);
    TSfree(tokenoffset);
    if (info->re)
      pcre_free(info->re);
    TSfree(info);
  }
  return status;
}

static pr_list *
load_config_file(const char *config_file)
{
  char buffer[1024];
  std::string path;
  TSFile fh;
  pr_list *prl = new pr_list();

  /* locations in a config file line, end of line, split start, split end */
  char *eol, *spstart, *spend;
  int lineno = 0;
  int retval;
  regex_info *info = 0;

  if (config_file == NULL) {
    /* Default config file of plugins/cacheurl.config */
    path = TSPluginDirGet();
    path += "/cacheurl.config";
  } else if (*config_file != '/') {
    // Relative paths are relative to the config directory
    path = TSConfigDirGet();
    path += "/";
    path += config_file;
  } else {
    // Absolute path ...
    path = config_file;
  }

  TSDebug(PLUGIN_NAME, "Opening config file: %s", path.c_str());
  fh = TSfopen(path.c_str(), "r");

  if (!fh) {
    TSError("[%s] Unable to open %s. No patterns will be loaded\n", PLUGIN_NAME, path.c_str());
    return prl;
  }

  while (TSfgets(fh, buffer, sizeof(buffer) - 1)) {
    lineno++;
    if (*buffer == '#') {
      /* # Comments, only at line beginning */
      continue;
    }
    eol = strstr(buffer, "\n");
    if (eol) {
      *eol = 0;                 /* Terminate string at newline */
    } else {
      /* Malformed line - skip */
      continue;
    }
    /* Split line into two parts based on whitespace */
    /* Find first whitespace */
    spstart = strstr(buffer, " ");
    if (!spstart) {
      spstart = strstr(buffer, "\t");
    }
    if (!spstart) {
      TSError("[%s] ERROR: Invalid format on line %d. Skipping\n", PLUGIN_NAME, lineno);
      continue;
    }
    /* Find part of the line after any whitespace */
    spend = spstart + 1;
    while (*spend == ' ' || *spend == '\t') {
      spend++;
    }
    if (*spend == 0) {
      /* We reached the end of the string without any non-whitepace */
      TSError("[%s] ERROR: Invalid format on line %d. Skipping\n", PLUGIN_NAME, lineno);
      continue;
    }

    *spstart = 0;
    /* We have the pattern/replacement, now do precompilation.
     * buffer is the first part of the line. spend is the second part just
     * after the whitespace */
    TSDebug(PLUGIN_NAME, "Adding pattern/replacement pair: '%s' -> '%s'", buffer, spend);
    retval = regex_compile(&info, buffer, spend);
    if (!retval) {
      TSError("[%s] Error precompiling regex/replacement. Skipping.\n", PLUGIN_NAME);
    }

    prl->pr.push_back(info);
  }
  TSfclose(fh);

  TSDebug(PLUGIN_NAME, "loaded %u regexes", (unsigned) prl->pr.size());
  return prl;
}

static int
rewrite_cacheurl(pr_list * prl, TSHttpTxn txnp)
{
  int ok = 1;
  char *newurl = 0;
  int retval;
  char *url;
  int url_length;

  url = TSHttpTxnEffectiveUrlStringGet(txnp, &url_length);
  if (!url) {
    TSError("[%s] couldn't retrieve request url\n", PLUGIN_NAME);
    ok = 0;
  }

  if (ok) {
    for (std::vector<regex_info*>::iterator info = prl->pr.begin(); info != prl->pr.end(); ++info) {
      retval = regex_substitute(&newurl, url, *info);
      if (retval) {
        /* Successful match/substitution */
        break;
      }
    }
    if (newurl) {
      TSDebug(PLUGIN_NAME, "Rewriting cache URL for %s to %s", url, newurl);
      if (TSCacheUrlSet(txnp, newurl, strlen(newurl))
          != TS_SUCCESS) {
        TSError("[%s] Unable to modify cache url from " "%s to %s\n", PLUGIN_NAME, url, newurl);
        ok = 0;
      }
    }
  }

  /* Clean up */
  if (url)
    TSfree(url);
  if (newurl)
    TSfree(newurl);

  return ok;
}

static int
handle_hook(TSCont contp, TSEvent event, void *edata)
{
  TSHttpTxn txnp = (TSHttpTxn) edata;
  pr_list *prl;
  int ok = 1;

  prl = (pr_list *) TSContDataGet(contp);

  switch (event) {
  case TS_EVENT_HTTP_READ_REQUEST_HDR:
    ok = rewrite_cacheurl(prl, txnp);
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    break;
  default:
    TSAssert(!"Unexpected event");
    ok = 0;
    break;
  }

  return ok;
}

/* Generic error message function for errors in plugin initialization */
static void
initialization_error(const char *msg)
{
  TSError("[%s] %s\n", PLUGIN_NAME, msg);
  TSError("[%s] Unable to initialize plugin (disabled).\n", PLUGIN_NAME);
}

TSReturnCode
TSRemapInit(TSRemapInterface * api_info, char *errbuf, int errbuf_size)
{
  if (!api_info) {
    strncpy(errbuf, "[tsremap_init] Invalid TSRemapInterface argument", errbuf_size - 1);
    return TS_ERROR;
  }

  if (api_info->size < sizeof(TSRemapInterface)) {
    strncpy(errbuf, "[tsremap_init] Incorrect size of TSRemapInterface structure", errbuf_size - 1);
    return TS_ERROR;
  }

  if (api_info->tsremap_version < TSREMAP_VERSION) {
    snprintf(errbuf, errbuf_size - 1, "[tsremap_init] Incorrect API version %ld.%ld",
             api_info->tsremap_version >> 16, (api_info->tsremap_version & 0xffff));
    return TS_ERROR;
  }

  TSDebug(PLUGIN_NAME, "remap plugin is successfully initialized");
  return TS_SUCCESS;
}

TSReturnCode
TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf ATS_UNUSED, int errbuf_size ATS_UNUSED)
{
  *ih = load_config_file(argc > 2 ? argv[2] : NULL);
  return TS_SUCCESS;
}

void
TSRemapDeleteInstance(void *ih)
{
  pr_list *prl = (pr_list *) ih;

  TSDebug(PLUGIN_NAME, "Deleting remap instance");

  delete prl;
}

TSRemapStatus
TSRemapDoRemap(void *ih, TSHttpTxn rh, TSRemapRequestInfo * rri ATS_UNUSED)
{
  int ok;

  ok = rewrite_cacheurl((pr_list *) ih, rh);
  if (ok) {
    return TSREMAP_NO_REMAP;
  } else {
    return TSREMAP_ERROR;
  }
}

void
TSPluginInit(int argc, const char *argv[])
{
  TSPluginRegistrationInfo info;
  TSCont contp;
  pr_list *prl;

  info.plugin_name = (char *) PLUGIN_NAME;
  info.vendor_name = (char *) "Apache Software Foundation";
  info.support_email = (char *) "dev@trafficserver.apache.org";

  if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
    initialization_error("Plugin registration failed.");
    return;
  }

  prl = load_config_file(argc > 1 ? argv[1] : NULL);

  contp = TSContCreate((TSEventFunc) handle_hook, NULL);
  /* Store the pattern replacement list in the continuation */
  TSContDataSet(contp, prl);
  TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, contp);
}
<|endoftext|>