Mercurial > minori
comparison dep/animone/src/player.cc @ 337:a7d4e5107531
dep/animone: REFACTOR ALL THE THINGS
1: animone now has its own syntax divergent from anisthesia,
making different platforms actually have their own sections
2: process names in animone are now called `comm' (this will
probably break things). this is what its called in bsd/linux
so I'm just going to use it everywhere
3: the X11 code now checks for the existence of a UTF-8 window title
and passes it if available
4: ANYTHING THATS NOT LINUX IS 100% UNTESTED AND CAN AND WILL BREAK!
I still actually need to test the bsd code. to be honest I'm probably
going to move all of the bsds into separate files because they're
all essentially different operating systems at this point
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Wed, 19 Jun 2024 12:51:15 -0400 |
parents | b1f625b0227c |
children |
comparison
equal
deleted
inserted
replaced
336:d260549151d6 | 337:a7d4e5107531 |
---|---|
3 | 3 |
4 #include <map> | 4 #include <map> |
5 #include <sstream> | 5 #include <sstream> |
6 #include <string> | 6 #include <string> |
7 #include <vector> | 7 #include <vector> |
8 #include <optional> | |
9 | |
10 #include <iostream> | |
8 | 11 |
9 namespace animone { | 12 namespace animone { |
10 | 13 |
11 namespace internal::parser { | 14 namespace internal::parser { |
12 | 15 |
13 enum class State { | 16 struct State { |
14 ExpectPlayerName, | 17 enum class Name { |
15 ExpectSection, | 18 ExpectPlayerName, |
16 ExpectWindow, | 19 ExpectSection, |
17 ExpectExecutable, | 20 ExpectWindowPlatform, |
18 ExpectStrategy, | 21 ExpectExecutablePlatform, |
19 ExpectType, | 22 ExpectWindow, |
20 ExpectWindowTitle, | 23 ExpectExecutable, |
24 ExpectStrategy, | |
25 ExpectType, | |
26 ExpectWindowTitle, | |
27 }; | |
28 | |
29 Name state = Name::ExpectPlayerName; | |
30 WindowPlatform window_platform = WindowPlatform::Unknown; | |
31 ExecutablePlatform executable_platform = ExecutablePlatform::Unknown; | |
21 }; | 32 }; |
22 | 33 |
23 size_t GetIndentation(const std::string& line) { | 34 size_t GetIndentation(const std::string& line) { |
24 return line.find_first_not_of('\t'); | 35 return line.find_first_not_of('\t'); |
25 } | 36 } |
26 | 37 |
27 bool HandleIndentation(const size_t current, const std::vector<Player>& players, State& state) { | 38 bool HandleIndentation(const size_t current, const std::vector<Player>& players, State& state) { |
28 // Each state has a definitive expected indentation | 39 // Each state has a definitive expected indentation |
29 const auto expected = [&state]() -> size_t { | 40 const auto expected = [](const State::Name& state) -> size_t { |
30 switch (state) { | 41 switch (state) { |
31 default: | 42 default: |
32 case State::ExpectPlayerName: return 0; | 43 case State::Name::ExpectPlayerName: return 0; |
33 case State::ExpectSection: return 1; | 44 case State::Name::ExpectSection: return 1; |
34 case State::ExpectWindow: | 45 case State::Name::ExpectWindowPlatform: |
35 case State::ExpectExecutable: | 46 case State::Name::ExpectExecutablePlatform: |
36 case State::ExpectStrategy: | 47 case State::Name::ExpectStrategy: |
37 case State::ExpectType: return 2; | 48 case State::Name::ExpectType: return 2; |
38 case State::ExpectWindowTitle: return 3; | 49 case State::Name::ExpectWindow: |
39 } | 50 case State::Name::ExpectExecutable: |
40 }(); | 51 case State::Name::ExpectWindowTitle: return 3; |
41 | 52 } |
42 if (current > expected) | 53 }(state.state); |
54 | |
55 if (current > expected) { | |
56 std::cerr << "animone: excessive indentation found" << std::endl; | |
43 return false; // Disallow excessive indentation | 57 return false; // Disallow excessive indentation |
58 } | |
44 | 59 |
45 if (current < expected) { | 60 if (current < expected) { |
46 auto fix_state = [&]() { state = !current ? State::ExpectPlayerName : State::ExpectSection; }; | 61 const std::optional<State::Name> st = [current, state]() -> std::optional<State::Name> { |
47 switch (state) { | 62 switch (current) { |
48 case State::ExpectWindow: | 63 case 0: return State::Name::ExpectPlayerName; |
64 default: | |
65 case 1: return State::Name::ExpectSection; | |
66 case 2: | |
67 switch (state.state) { | |
68 case State::Name::ExpectWindow: return State::Name::ExpectWindowPlatform; | |
69 case State::Name::ExpectExecutable: return State::Name::ExpectExecutablePlatform; | |
70 default: return std::nullopt; | |
71 } | |
72 } | |
73 }(); | |
74 if (!st.has_value()) | |
75 return false; | |
76 | |
77 switch (state.state) { | |
78 case State::Name::ExpectWindow: | |
49 if (players.back().windows.empty()) | 79 if (players.back().windows.empty()) |
50 return false; | 80 return false; |
51 fix_state(); | 81 state.state = st.value(); |
52 break; | 82 break; |
53 case State::ExpectExecutable: | 83 case State::Name::ExpectExecutable: |
54 if (players.back().executables.empty()) | 84 if (players.back().executables.empty()) |
55 return false; | 85 return false; |
56 fix_state(); | 86 state.state = st.value(); |
57 break; | 87 break; |
58 case State::ExpectStrategy: | 88 case State::Name::ExpectStrategy: |
59 if (players.back().strategies.empty()) | 89 if (players.back().strategies.empty()) |
60 return false; | 90 return false; |
61 fix_state(); | 91 state.state = st.value(); |
62 break; | 92 break; |
63 case State::ExpectType: fix_state(); break; | 93 case State::Name::ExpectType: |
64 case State::ExpectWindowTitle: return false; | 94 state.state = st.value(); |
95 break; | |
96 case State::Name::ExpectWindowTitle: | |
97 return false; | |
65 } | 98 } |
66 } | 99 } |
67 | 100 |
68 return true; | 101 return true; |
69 } | 102 } |
70 | 103 |
71 bool HandleState(std::string& line, std::vector<Player>& players, State& state) { | 104 bool HandleState(std::string& line, std::vector<Player>& players, State& state) { |
72 switch (state) { | 105 switch (state.state) { |
73 case State::ExpectPlayerName: | 106 case State::Name::ExpectPlayerName: |
74 players.push_back(Player()); | 107 players.push_back(Player()); |
75 players.back().name = line; | 108 players.back().name = line; |
76 state = State::ExpectSection; | 109 state.state = State::Name::ExpectSection; |
77 break; | 110 break; |
78 | 111 |
79 case State::ExpectSection: { | 112 case State::Name::ExpectSection: { |
80 static const std::map<std::string, State> sections = { | 113 static const std::map<std::string, State::Name> sections = { |
81 {"windows", State::ExpectWindow }, | 114 {"windows", State::Name::ExpectWindowPlatform}, |
82 {"executables", State::ExpectExecutable}, | 115 {"executables", State::Name::ExpectExecutablePlatform}, |
83 {"strategies", State::ExpectStrategy }, | 116 {"strategies", State::Name::ExpectStrategy }, |
84 {"type", State::ExpectType }, | 117 {"type", State::Name::ExpectType }, |
85 }; | 118 }; |
86 util::TrimRight(line, ":"); | 119 util::TrimRight(line, ":"); |
87 const auto it = sections.find(line); | 120 const auto it = sections.find(line); |
88 if (it == sections.end()) | 121 if (it == sections.end()) |
89 return false; | 122 return false; |
90 state = it->second; | 123 state.state = it->second; |
91 break; | 124 break; |
92 } | 125 } |
93 | 126 |
94 case State::ExpectWindow: players.back().windows.push_back(line); break; | 127 case State::Name::ExpectWindowPlatform: { |
95 | 128 static const std::map<std::string, WindowPlatform> platforms = { |
96 case State::ExpectExecutable: players.back().executables.push_back(line); break; | 129 {"quartz", WindowPlatform::Quartz}, |
97 | 130 {"win32", WindowPlatform::Win32}, |
98 case State::ExpectStrategy: { | 131 {"x11", WindowPlatform::X11}, |
132 }; | |
133 util::TrimRight(line, ":"); | |
134 const auto it = platforms.find(line); | |
135 if (it == platforms.end()) | |
136 return false; | |
137 state.state = State::Name::ExpectWindow; | |
138 state.window_platform = it->second; | |
139 break; | |
140 } | |
141 | |
142 case State::Name::ExpectExecutablePlatform: { | |
143 static const std::map<std::string, ExecutablePlatform> platforms = { | |
144 {"posix", ExecutablePlatform::Posix}, | |
145 {"win32", ExecutablePlatform::Win32}, | |
146 {"macosx", ExecutablePlatform::Xnu}, | |
147 }; | |
148 util::TrimRight(line, ":"); | |
149 const auto it = platforms.find(line); | |
150 if (it == platforms.end()) | |
151 return false; | |
152 state.state = State::Name::ExpectExecutable; | |
153 state.executable_platform = it->second; | |
154 break; | |
155 } | |
156 | |
157 case State::Name::ExpectWindow: players.back().windows[state.window_platform].push_back(line); break; | |
158 | |
159 case State::Name::ExpectExecutable: players.back().executables[state.executable_platform].push_back(line); break; | |
160 | |
161 case State::Name::ExpectStrategy: { | |
99 static const std::map<std::string, Strategy> strategies = { | 162 static const std::map<std::string, Strategy> strategies = { |
100 {"window_title", Strategy::WindowTitle }, | 163 {"window_title", Strategy::WindowTitle }, |
101 {"open_files", Strategy::OpenFiles }, | 164 {"open_files", Strategy::OpenFiles }, |
102 {"ui_automation", Strategy::UiAutomation}, | 165 {"ui_automation", Strategy::UiAutomation}, |
103 }; | 166 }; |
106 if (it == strategies.end()) | 169 if (it == strategies.end()) |
107 return false; | 170 return false; |
108 const auto strategy = it->second; | 171 const auto strategy = it->second; |
109 players.back().strategies.push_back(strategy); | 172 players.back().strategies.push_back(strategy); |
110 switch (strategy) { | 173 switch (strategy) { |
111 case Strategy::WindowTitle: state = State::ExpectWindowTitle; break; | 174 case Strategy::WindowTitle: state.state = State::Name::ExpectWindowTitle; break; |
112 } | 175 } |
113 break; | 176 break; |
114 } | 177 } |
115 | 178 |
116 case State::ExpectType: { | 179 case State::Name::ExpectType: { |
117 static const std::map<std::string, PlayerType> types = { | 180 static const std::map<std::string, PlayerType> types = { |
118 {"default", PlayerType::Default }, | 181 {"default", PlayerType::Default }, |
119 {"web_browser", PlayerType::WebBrowser}, | 182 {"web_browser", PlayerType::WebBrowser}, |
120 }; | 183 }; |
121 const auto it = types.find(line); | 184 const auto it = types.find(line); |
123 return false; | 186 return false; |
124 players.back().type = it->second; | 187 players.back().type = it->second; |
125 break; | 188 break; |
126 } | 189 } |
127 | 190 |
128 case State::ExpectWindowTitle: | 191 case State::Name::ExpectWindowTitle: |
129 players.back().window_title_format = line; | 192 players.back().window_title_format = line; |
130 state = State::ExpectStrategy; | 193 state.state = State::Name::ExpectStrategy; |
131 break; | 194 break; |
132 } | 195 } |
133 | 196 |
134 return true; | 197 return true; |
135 } | 198 } |
143 return false; | 206 return false; |
144 | 207 |
145 std::istringstream stream(data); | 208 std::istringstream stream(data); |
146 std::string line; | 209 std::string line; |
147 size_t indentation = 0; | 210 size_t indentation = 0; |
148 auto state = internal::parser::State::ExpectPlayerName; | 211 internal::parser::State state; |
149 | 212 |
150 while (std::getline(stream, line, '\n')) { | 213 int ln = 1; |
214 for (; std::getline(stream, line, '\n'); ln++) { | |
151 if (line.empty()) | 215 if (line.empty()) |
152 continue; // Ignore empty lines | 216 continue; // Ignore empty lines |
153 | 217 |
154 indentation = internal::parser::GetIndentation(line); | 218 indentation = internal::parser::GetIndentation(line); |
155 | 219 |
157 internal::util::TrimRight(line, "\n\r"); | 221 internal::util::TrimRight(line, "\n\r"); |
158 | 222 |
159 if (line.empty() || line.front() == '#') | 223 if (line.empty() || line.front() == '#') |
160 continue; // Ignore empty lines and comments | 224 continue; // Ignore empty lines and comments |
161 | 225 |
162 if (!internal::parser::HandleIndentation(indentation, players, state)) | 226 if (!internal::parser::HandleIndentation(indentation, players, state)) { |
227 std::cerr << "animone: indentation: failed on line " << ln << std::endl; | |
163 return false; | 228 return false; |
164 | 229 } |
165 if (!internal::parser::HandleState(line, players, state)) | 230 |
231 if (!internal::parser::HandleState(line, players, state)) { | |
232 std::cerr << "animone: state: failed on line " << ln << std::endl; | |
166 return false; | 233 return false; |
234 } | |
167 } | 235 } |
168 | 236 |
169 return !players.empty(); | 237 return !players.empty(); |
170 } | 238 } |
171 | 239 |