Mercurial > minori
comparison dep/animia/src/player.cc @ 138:28842a8d0c6b
dep/animia: huge refactor (again...)
but this time, it actually compiles! and it WORKS! (on win32... not sure about
other platforms...)
configuring players is still not supported: at some point I'll prune something
up...
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Sun, 12 Nov 2023 04:53:19 -0500 |
parents | 69db40272acd |
children | d8a61e7e2a36 |
comparison
equal
deleted
inserted
replaced
137:69db40272acd | 138:28842a8d0c6b |
---|---|
1 #include <map> | |
2 #include <sstream> | |
3 #include <string> | |
4 #include <vector> | |
5 | |
6 #include "animia/player.h" | |
7 #include "animia/util.h" | |
8 | |
9 namespace animia { | |
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, | |
28 const std::vector<Player>& players, | |
29 State& state) { | |
30 // Each state has a definitive expected indentation | |
31 const auto expected = [&state]() -> size_t { | |
32 switch (state) { | |
33 default: | |
34 case State::ExpectPlayerName: | |
35 return 0; | |
36 case State::ExpectSection: | |
37 return 1; | |
38 case State::ExpectWindow: | |
39 case State::ExpectExecutable: | |
40 case State::ExpectStrategy: | |
41 case State::ExpectType: | |
42 return 2; | |
43 case State::ExpectWindowTitle: | |
44 return 3; | |
45 } | |
46 }(); | |
47 | |
48 if (current > expected) | |
49 return false; // Disallow excessive indentation | |
50 | |
51 if (current < expected) { | |
52 auto fix_state = [&]() { | |
53 state = !current ? State::ExpectPlayerName : State::ExpectSection; | |
54 }; | |
55 switch (state) { | |
56 case State::ExpectWindow: | |
57 if (players.back().windows.empty()) | |
58 return false; | |
59 fix_state(); | |
60 break; | |
61 case State::ExpectExecutable: | |
62 if (players.back().executables.empty()) | |
63 return false; | |
64 fix_state(); | |
65 break; | |
66 case State::ExpectStrategy: | |
67 if (players.back().strategies.empty()) | |
68 return false; | |
69 fix_state(); | |
70 break; | |
71 case State::ExpectType: | |
72 fix_state(); | |
73 break; | |
74 case State::ExpectWindowTitle: | |
75 return false; | |
76 } | |
77 } | |
78 | |
79 return true; | |
80 } | |
81 | |
82 bool HandleState(std::string& line, std::vector<Player>& players, State& state) { | |
83 switch (state) { | |
84 case State::ExpectPlayerName: | |
85 players.push_back(Player()); | |
86 players.back().name = line; | |
87 state = State::ExpectSection; | |
88 break; | |
89 | |
90 case State::ExpectSection: { | |
91 static const std::map<std::string, State> sections = { | |
92 {"windows", State::ExpectWindow}, | |
93 {"executables", State::ExpectExecutable}, | |
94 {"strategies", State::ExpectStrategy}, | |
95 {"type", State::ExpectType}, | |
96 }; | |
97 util::TrimRight(line, ":"); | |
98 const auto it = sections.find(line); | |
99 if (it == sections.end()) | |
100 return false; | |
101 state = it->second; | |
102 break; | |
103 } | |
104 | |
105 case State::ExpectWindow: | |
106 players.back().windows.push_back(line); | |
107 break; | |
108 | |
109 case State::ExpectExecutable: | |
110 players.back().executables.push_back(line); | |
111 break; | |
112 | |
113 case State::ExpectStrategy: { | |
114 static const std::map<std::string, Strategy> strategies = { | |
115 {"window_title", Strategy::WindowTitle}, | |
116 {"open_files", Strategy::OpenFiles}, | |
117 {"ui_automation", Strategy::UiAutomation}, | |
118 }; | |
119 util::TrimRight(line, ":"); | |
120 const auto it = strategies.find(line); | |
121 if (it == strategies.end()) | |
122 return false; | |
123 const auto strategy = it->second; | |
124 players.back().strategies.push_back(strategy); | |
125 switch (strategy) { | |
126 case Strategy::WindowTitle: | |
127 state = State::ExpectWindowTitle; | |
128 break; | |
129 } | |
130 break; | |
131 } | |
132 | |
133 case State::ExpectType: { | |
134 static const std::map<std::string, PlayerType> types = { | |
135 {"default", PlayerType::Default}, | |
136 {"web_browser", PlayerType::WebBrowser}, | |
137 }; | |
138 const auto it = types.find(line); | |
139 if (it == types.end()) | |
140 return false; | |
141 players.back().type = it->second; | |
142 break; | |
143 } | |
144 | |
145 case State::ExpectWindowTitle: | |
146 players.back().window_title_format = line; | |
147 state = State::ExpectStrategy; | |
148 break; | |
149 } | |
150 | |
151 return true; | |
152 } | |
153 | |
154 } // namespace internal::parser | |
155 | |
156 //////////////////////////////////////////////////////////////////////////////// | |
157 | |
158 bool ParsePlayersData(const std::string& data, std::vector<Player>& players) { | |
159 if (data.empty()) | |
160 return false; | |
161 | |
162 std::istringstream stream(data); | |
163 std::string line; | |
164 size_t indentation = 0; | |
165 auto state = internal::parser::State::ExpectPlayerName; | |
166 | |
167 while (std::getline(stream, line, '\n')) { | |
168 if (line.empty()) | |
169 continue; // Ignore empty lines | |
170 | |
171 indentation = internal::parser::GetIndentation(line); | |
172 | |
173 internal::util::TrimLeft(line, "\t"); | |
174 internal::util::TrimRight(line, "\n\r"); | |
175 | |
176 if (line.empty() || line.front() == '#') | |
177 continue; // Ignore empty lines and comments | |
178 | |
179 if (!internal::parser::HandleIndentation(indentation, players, state)) | |
180 return false; | |
181 | |
182 if (!internal::parser::HandleState(line, players, state)) | |
183 return false; | |
184 } | |
185 | |
186 return !players.empty(); | |
187 } | |
188 | |
189 bool ParsePlayersFile(const std::string& path, std::vector<Player>& players) { | |
190 std::string data; | |
191 | |
192 if (!internal::util::ReadFile(path, data)) | |
193 return false; | |
194 | |
195 return ParsePlayersData(data, players); | |
196 } | |
197 | |
198 } // namespace anisthesia |