diff 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
line wrap: on
line diff
--- a/dep/animone/src/player.cc	Wed Jun 19 06:32:25 2024 -0400
+++ b/dep/animone/src/player.cc	Wed Jun 19 12:51:15 2024 -0400
@@ -5,19 +5,30 @@
 #include <sstream>
 #include <string>
 #include <vector>
+#include <optional>
+
+#include <iostream>
 
 namespace animone {
 
 namespace internal::parser {
 
-enum class State {
-	ExpectPlayerName,
-	ExpectSection,
-	ExpectWindow,
-	ExpectExecutable,
-	ExpectStrategy,
-	ExpectType,
-	ExpectWindowTitle,
+struct State {
+	enum class Name {
+		ExpectPlayerName,
+		ExpectSection,
+		ExpectWindowPlatform,
+		ExpectExecutablePlatform,
+		ExpectWindow,
+		ExpectExecutable,
+		ExpectStrategy,
+		ExpectType,
+		ExpectWindowTitle,
+	};
+
+	Name state = Name::ExpectPlayerName;
+	WindowPlatform window_platform = WindowPlatform::Unknown;
+	ExecutablePlatform executable_platform = ExecutablePlatform::Unknown;
 };
 
 size_t GetIndentation(const std::string& line) {
@@ -26,42 +37,64 @@
 
 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 {
+	const auto expected = [](const State::Name& 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;
+			case State::Name::ExpectPlayerName: return 0;
+			case State::Name::ExpectSection: return 1;
+			case State::Name::ExpectWindowPlatform:
+			case State::Name::ExpectExecutablePlatform:
+			case State::Name::ExpectStrategy:
+			case State::Name::ExpectType: return 2;
+			case State::Name::ExpectWindow:
+			case State::Name::ExpectExecutable:
+			case State::Name::ExpectWindowTitle: return 3;
 		}
-	}();
+	}(state.state);
 
-	if (current > expected)
+	if (current > expected) {
+		std::cerr << "animone: excessive indentation found" << std::endl;
 		return false; // Disallow excessive indentation
+	}
 
 	if (current < expected) {
-		auto fix_state = [&]() { state = !current ? State::ExpectPlayerName : State::ExpectSection; };
-		switch (state) {
-			case State::ExpectWindow:
+		const std::optional<State::Name> st = [current, state]() -> std::optional<State::Name> {
+			switch (current) {
+				case 0: return State::Name::ExpectPlayerName;
+				default:
+				case 1: return State::Name::ExpectSection;
+				case 2:
+					switch (state.state) {
+						case State::Name::ExpectWindow: return State::Name::ExpectWindowPlatform;
+						case State::Name::ExpectExecutable: return State::Name::ExpectExecutablePlatform;
+						default: return std::nullopt;
+					}
+			}
+		}();
+		if (!st.has_value())
+			return false;
+
+		switch (state.state) {
+			case State::Name::ExpectWindow:
 				if (players.back().windows.empty())
 					return false;
-				fix_state();
+				state.state = st.value();
 				break;
-			case State::ExpectExecutable:
+			case State::Name::ExpectExecutable:
 				if (players.back().executables.empty())
 					return false;
-				fix_state();
+				state.state = st.value();
 				break;
-			case State::ExpectStrategy:
+			case State::Name::ExpectStrategy:
 				if (players.back().strategies.empty())
 					return false;
-				fix_state();
+				state.state = st.value();
 				break;
-			case State::ExpectType: fix_state(); break;
-			case State::ExpectWindowTitle: return false;
+			case State::Name::ExpectType:
+				state.state = st.value();
+				break;
+			case State::Name::ExpectWindowTitle:
+				return false;
 		}
 	}
 
@@ -69,33 +102,63 @@
 }
 
 bool HandleState(std::string& line, std::vector<Player>& players, State& state) {
-	switch (state) {
-		case State::ExpectPlayerName:
+	switch (state.state) {
+		case State::Name::ExpectPlayerName:
 			players.push_back(Player());
 			players.back().name = line;
-			state = State::ExpectSection;
+			state.state = State::Name::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      },
+		case State::Name::ExpectSection: {
+			static const std::map<std::string, State::Name> sections = {
+			    {"windows",     State::Name::ExpectWindowPlatform},
+			    {"executables", State::Name::ExpectExecutablePlatform},
+			    {"strategies",  State::Name::ExpectStrategy  },
+			    {"type",        State::Name::ExpectType      },
 			};
 			util::TrimRight(line, ":");
 			const auto it = sections.find(line);
 			if (it == sections.end())
 				return false;
-			state = it->second;
+			state.state = it->second;
+			break;
+		}
+
+		case State::Name::ExpectWindowPlatform: {
+			static const std::map<std::string, WindowPlatform> platforms = {
+				{"quartz", WindowPlatform::Quartz},
+				{"win32",  WindowPlatform::Win32},
+				{"x11",    WindowPlatform::X11},
+			};
+			util::TrimRight(line, ":");
+			const auto it = platforms.find(line);
+			if (it == platforms.end())
+				return false;
+			state.state = State::Name::ExpectWindow;
+			state.window_platform = it->second;
 			break;
 		}
 
-		case State::ExpectWindow: players.back().windows.push_back(line); break;
+		case State::Name::ExpectExecutablePlatform: {
+			static const std::map<std::string, ExecutablePlatform> platforms = {
+				{"posix",   ExecutablePlatform::Posix},
+				{"win32",   ExecutablePlatform::Win32},
+				{"macosx",  ExecutablePlatform::Xnu},
+			};
+			util::TrimRight(line, ":");
+			const auto it = platforms.find(line);
+			if (it == platforms.end())
+				return false;
+			state.state = State::Name::ExpectExecutable;
+			state.executable_platform = it->second;
+			break;
+		}
 
-		case State::ExpectExecutable: players.back().executables.push_back(line); break;
+		case State::Name::ExpectWindow: players.back().windows[state.window_platform].push_back(line); break;
 
-		case State::ExpectStrategy: {
+		case State::Name::ExpectExecutable: players.back().executables[state.executable_platform].push_back(line); break;
+
+		case State::Name::ExpectStrategy: {
 			static const std::map<std::string, Strategy> strategies = {
 			    {"window_title",  Strategy::WindowTitle },
 			    {"open_files",    Strategy::OpenFiles   },
@@ -108,12 +171,12 @@
 			const auto strategy = it->second;
 			players.back().strategies.push_back(strategy);
 			switch (strategy) {
-				case Strategy::WindowTitle: state = State::ExpectWindowTitle; break;
+				case Strategy::WindowTitle: state.state = State::Name::ExpectWindowTitle; break;
 			}
 			break;
 		}
 
-		case State::ExpectType: {
+		case State::Name::ExpectType: {
 			static const std::map<std::string, PlayerType> types = {
 			    {"default",     PlayerType::Default   },
 			    {"web_browser", PlayerType::WebBrowser},
@@ -125,9 +188,9 @@
 			break;
 		}
 
-		case State::ExpectWindowTitle:
+		case State::Name::ExpectWindowTitle:
 			players.back().window_title_format = line;
-			state = State::ExpectStrategy;
+			state.state = State::Name::ExpectStrategy;
 			break;
 	}
 
@@ -145,9 +208,10 @@
 	std::istringstream stream(data);
 	std::string line;
 	size_t indentation = 0;
-	auto state = internal::parser::State::ExpectPlayerName;
+	internal::parser::State state;
 
-	while (std::getline(stream, line, '\n')) {
+	int ln = 1;
+	for (; std::getline(stream, line, '\n'); ln++) {
 		if (line.empty())
 			continue; // Ignore empty lines
 
@@ -159,11 +223,15 @@
 		if (line.empty() || line.front() == '#')
 			continue; // Ignore empty lines and comments
 
-		if (!internal::parser::HandleIndentation(indentation, players, state))
+		if (!internal::parser::HandleIndentation(indentation, players, state)) {
+			std::cerr << "animone: indentation: failed on line " << ln << std::endl;
 			return false;
+		}
 
-		if (!internal::parser::HandleState(line, players, state))
+		if (!internal::parser::HandleState(line, players, state)) {
+			std::cerr << "animone: state: failed on line " << ln << std::endl;
 			return false;
+		}
 	}
 
 	return !players.empty();