Mercurial > minori
comparison dep/animone/src/player.cc @ 258:862d0d8619f6
*: HUUUGE changes
animia has been renamed to animone, so instead of thinking of a
health condition, you think of a beautiful flower :)
I've also edited some of the code for animone, but I have no idea
if it even works or not because I don't have a mac or windows
machine lying around. whoops!
... anyway, all of the changes divergent from Anisthesia are now
licensed under BSD. it's possible that I could even rewrite most
of the code to where I don't even have to keep the MIT license,
but that's thinking too far into the future
I've been slacking off on implementing the anime seasons page,
mostly out of laziness. I think I'd have to create another db file
specifically for the seasons
anyway, this code is being pushed *primarily* because the hard drive
it's on is failing! yay :)
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Mon, 01 Apr 2024 02:43:44 -0400 |
parents | |
children | b1f625b0227c |
comparison
equal
deleted
inserted
replaced
257:699a20c57dc8 | 258:862d0d8619f6 |
---|---|
1 #include "animone/player.h" | |
2 #include "animone/util.h" | |
3 | |
4 #include <map> | |
5 #include <sstream> | |
6 #include <string> | |
7 #include <vector> | |
8 | |
9 namespace animone { | |
10 | |
11 namespace internal::parser { | |
12 | |
13 enum class State { | |
14 ExpectPlayerName, | |
15 ExpectSection, | |
16 ExpectWindow, | |
17 ExpectExecutable, | |
18 ExpectStrategy, | |
19 ExpectType, | |
20 ExpectWindowTitle, | |
21 }; | |
22 | |
23 size_t GetIndentation(const std::string& line) { | |
24 return line.find_first_not_of('\t'); | |
25 } | |
26 | |
27 bool HandleIndentation(const size_t current, const std::vector<Player>& players, State& state) { | |
28 // Each state has a definitive expected indentation | |
29 const auto expected = [&state]() -> size_t { | |
30 switch (state) { | |
31 default: | |
32 case State::ExpectPlayerName: return 0; | |
33 case State::ExpectSection: return 1; | |
34 case State::ExpectWindow: | |
35 case State::ExpectExecutable: | |
36 case State::ExpectStrategy: | |
37 case State::ExpectType: return 2; | |
38 case State::ExpectWindowTitle: return 3; | |
39 } | |
40 }(); | |
41 | |
42 if (current > expected) | |
43 return false; // Disallow excessive indentation | |
44 | |
45 if (current < expected) { | |
46 auto fix_state = [&]() { state = !current ? State::ExpectPlayerName : State::ExpectSection; }; | |
47 switch (state) { | |
48 case State::ExpectWindow: | |
49 if (players.back().windows.empty()) | |
50 return false; | |
51 fix_state(); | |
52 break; | |
53 case State::ExpectExecutable: | |
54 if (players.back().executables.empty()) | |
55 return false; | |
56 fix_state(); | |
57 break; | |
58 case State::ExpectStrategy: | |
59 if (players.back().strategies.empty()) | |
60 return false; | |
61 fix_state(); | |
62 break; | |
63 case State::ExpectType: fix_state(); break; | |
64 case State::ExpectWindowTitle: return false; | |
65 } | |
66 } | |
67 | |
68 return true; | |
69 } | |
70 | |
71 bool HandleState(std::string& line, std::vector<Player>& players, State& state) { | |
72 switch (state) { | |
73 case State::ExpectPlayerName: | |
74 players.push_back(Player()); | |
75 players.back().name = line; | |
76 state = State::ExpectSection; | |
77 break; | |
78 | |
79 case State::ExpectSection: { | |
80 static const std::map<std::string, State> sections = { | |
81 {"windows", State::ExpectWindow }, | |
82 {"executables", State::ExpectExecutable}, | |
83 {"strategies", State::ExpectStrategy }, | |
84 {"type", State::ExpectType }, | |
85 }; | |
86 util::TrimRight(line, ":"); | |
87 const auto it = sections.find(line); | |
88 if (it == sections.end()) | |
89 return false; | |
90 state = it->second; | |
91 break; | |
92 } | |
93 | |
94 case State::ExpectWindow: players.back().windows.push_back(line); break; | |
95 | |
96 case State::ExpectExecutable: players.back().executables.push_back(line); break; | |
97 | |
98 case State::ExpectStrategy: { | |
99 static const std::map<std::string, Strategy> strategies = { | |
100 {"window_title", Strategy::WindowTitle }, | |
101 {"open_files", Strategy::OpenFiles }, | |
102 {"ui_automation", Strategy::UiAutomation}, | |
103 }; | |
104 util::TrimRight(line, ":"); | |
105 const auto it = strategies.find(line); | |
106 if (it == strategies.end()) | |
107 return false; | |
108 const auto strategy = it->second; | |
109 players.back().strategies.push_back(strategy); | |
110 switch (strategy) { | |
111 case Strategy::WindowTitle: state = State::ExpectWindowTitle; break; | |
112 } | |
113 break; | |
114 } | |
115 | |
116 case State::ExpectType: { | |
117 static const std::map<std::string, PlayerType> types = { | |
118 {"default", PlayerType::Default }, | |
119 {"web_browser", PlayerType::WebBrowser}, | |
120 }; | |
121 const auto it = types.find(line); | |
122 if (it == types.end()) | |
123 return false; | |
124 players.back().type = it->second; | |
125 break; | |
126 } | |
127 | |
128 case State::ExpectWindowTitle: | |
129 players.back().window_title_format = line; | |
130 state = State::ExpectStrategy; | |
131 break; | |
132 } | |
133 | |
134 return true; | |
135 } | |
136 | |
137 } // namespace internal::parser | |
138 | |
139 //////////////////////////////////////////////////////////////////////////////// | |
140 | |
141 bool ParsePlayersData(const std::string& data, std::vector<Player>& players) { | |
142 if (data.empty()) | |
143 return false; | |
144 | |
145 std::istringstream stream(data); | |
146 std::string line; | |
147 size_t indentation = 0; | |
148 auto state = internal::parser::State::ExpectPlayerName; | |
149 | |
150 while (std::getline(stream, line, '\n')) { | |
151 if (line.empty()) | |
152 continue; // Ignore empty lines | |
153 | |
154 indentation = internal::parser::GetIndentation(line); | |
155 | |
156 internal::util::TrimLeft(line, "\t"); | |
157 internal::util::TrimRight(line, "\n\r"); | |
158 | |
159 if (line.empty() || line.front() == '#') | |
160 continue; // Ignore empty lines and comments | |
161 | |
162 if (!internal::parser::HandleIndentation(indentation, players, state)) | |
163 return false; | |
164 | |
165 if (!internal::parser::HandleState(line, players, state)) | |
166 return false; | |
167 } | |
168 | |
169 return !players.empty(); | |
170 } | |
171 | |
172 bool ParsePlayersFile(const std::string& path, std::vector<Player>& players) { | |
173 std::string data; | |
174 | |
175 if (!internal::util::ReadFile(path, data)) | |
176 return false; | |
177 | |
178 return ParsePlayersData(data, players); | |
179 } | |
180 | |
181 } // namespace animone |