Mercurial > minori
view dep/animone/src/player.cc @ 306:f4538a4c91ba
cleanup: remove extraneous executable flags
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Sun, 19 May 2024 17:48:52 -0400 |
parents | b1f625b0227c |
children | a7d4e5107531 |
line wrap: on
line source
#include "animone/player.h" #include "animone/util.h" #include <map> #include <sstream> #include <string> #include <vector> namespace animone { namespace internal::parser { enum class State { ExpectPlayerName, ExpectSection, ExpectWindow, ExpectExecutable, ExpectStrategy, ExpectType, ExpectWindowTitle, }; size_t GetIndentation(const std::string& line) { return line.find_first_not_of('\t'); } bool HandleIndentation(const size_t current, const std::vector<Player>& players, State& state) { // Each state has a definitive expected indentation const auto expected = [&state]() -> size_t { switch (state) { default: case State::ExpectPlayerName: return 0; case State::ExpectSection: return 1; case State::ExpectWindow: case State::ExpectExecutable: case State::ExpectStrategy: case State::ExpectType: return 2; case State::ExpectWindowTitle: return 3; } }(); if (current > expected) return false; // Disallow excessive indentation if (current < expected) { auto fix_state = [&]() { state = !current ? State::ExpectPlayerName : State::ExpectSection; }; switch (state) { case State::ExpectWindow: if (players.back().windows.empty()) return false; fix_state(); break; case State::ExpectExecutable: if (players.back().executables.empty()) return false; fix_state(); break; case State::ExpectStrategy: if (players.back().strategies.empty()) return false; fix_state(); break; case State::ExpectType: fix_state(); break; case State::ExpectWindowTitle: return false; } } return true; } bool HandleState(std::string& line, std::vector<Player>& players, State& state) { switch (state) { case State::ExpectPlayerName: players.push_back(Player()); players.back().name = line; state = State::ExpectSection; break; case State::ExpectSection: { static const std::map<std::string, State> sections = { {"windows", State::ExpectWindow }, {"executables", State::ExpectExecutable}, {"strategies", State::ExpectStrategy }, {"type", State::ExpectType }, }; util::TrimRight(line, ":"); const auto it = sections.find(line); if (it == sections.end()) return false; state = it->second; break; } case State::ExpectWindow: players.back().windows.push_back(line); break; case State::ExpectExecutable: players.back().executables.push_back(line); break; case State::ExpectStrategy: { static const std::map<std::string, Strategy> strategies = { {"window_title", Strategy::WindowTitle }, {"open_files", Strategy::OpenFiles }, {"ui_automation", Strategy::UiAutomation}, }; util::TrimRight(line, ":"); const auto it = strategies.find(line); if (it == strategies.end()) return false; const auto strategy = it->second; players.back().strategies.push_back(strategy); switch (strategy) { case Strategy::WindowTitle: state = State::ExpectWindowTitle; break; } break; } case State::ExpectType: { static const std::map<std::string, PlayerType> types = { {"default", PlayerType::Default }, {"web_browser", PlayerType::WebBrowser}, }; const auto it = types.find(line); if (it == types.end()) return false; players.back().type = it->second; break; } case State::ExpectWindowTitle: players.back().window_title_format = line; state = State::ExpectStrategy; break; } return true; } } // namespace internal::parser //////////////////////////////////////////////////////////////////////////////// bool ParsePlayersData(const std::string& data, std::vector<Player>& players) { if (data.empty()) return false; std::istringstream stream(data); std::string line; size_t indentation = 0; auto state = internal::parser::State::ExpectPlayerName; while (std::getline(stream, line, '\n')) { if (line.empty()) continue; // Ignore empty lines indentation = internal::parser::GetIndentation(line); internal::util::TrimLeft(line, "\t"); internal::util::TrimRight(line, "\n\r"); if (line.empty() || line.front() == '#') continue; // Ignore empty lines and comments if (!internal::parser::HandleIndentation(indentation, players, state)) return false; if (!internal::parser::HandleState(line, players, state)) return false; } return !players.empty(); } bool ParsePlayersFile(const std::string& path, std::vector<Player>& players) { std::string data; if (!internal::util::ReadFile(path, data)) return false; return ParsePlayersData(data, players); } } // namespace animone