#include "screencast/app/cli.h" #include #include #include namespace sc { namespace { void print_usage() { std::fputs( "usage: screencast --send [--target monitor|window] [--peer HOST[:PORT]] [--bitrate MAX_KBPS] [--crf 0-51]\n" " screencast --receive [--port PORT] [--signaling-port PORT] [--fullscreen] [--swdecode]\n" " screencast --discover [--timeout SECONDS]\n" " screencast waybar [--toggle] # for waybar widgets\n" "\n" "--send without --peer discovers a receiver on the LAN and requires\n" "that exactly one is found.\n", stderr); } bool parse_int(std::string_view text, int& value) { const auto [pointer, error] = std::from_chars(text.data(), text.data() + text.size(), value); return error == std::errc{} && pointer == text.data() + text.size(); } bool next_argument(int argc, const char* const argv[], int& index, std::string_view& value) { if (index + 1 >= argc) { print_usage(); return false; } value = argv[++index]; return true; } } // namespace std::optional parse_cli(int argc, const char* const argv[]) { enum class Mode { None, Send, Receive, Discover, Waybar, }; Mode mode = Mode::None; SendCommand send; ReceiveCommand receive; DiscoverCommand discover; WaybarCommand waybar; for (int index = 1; index < argc; ++index) { const std::string_view argument = argv[index]; if (argument == "--send") { if (mode != Mode::None) { print_usage(); return std::nullopt; } mode = Mode::Send; } else if (argument == "--receive") { if (mode != Mode::None) { print_usage(); return std::nullopt; } mode = Mode::Receive; } else if (argument == "--discover") { if (mode != Mode::None) { print_usage(); return std::nullopt; } mode = Mode::Discover; } else if (argument == "waybar") { if (mode != Mode::None) { print_usage(); return std::nullopt; } mode = Mode::Waybar; } else if (argument == "--toggle") { waybar.toggle = true; } else if (argument == "--target") { std::string_view value; if (!next_argument(argc, argv, index, value)) { return std::nullopt; } if (value != "monitor" && value != "window") { print_usage(); return std::nullopt; } send.target = value; } else if (argument == "--peer") { std::string_view value; if (!next_argument(argc, argv, index, value)) { return std::nullopt; } if (mode == Mode::Receive) { receive.peer_address = value; } else { send.peer_address = value; } } else if (argument == "--bitrate") { std::string_view value; if (!next_argument(argc, argv, index, value) || !parse_int(value, send.bitrate_kbps) || send.bitrate_kbps <= 0) { print_usage(); return std::nullopt; } } else if (argument == "--crf") { std::string_view value; if (!next_argument(argc, argv, index, value) || !parse_int(value, send.crf) || send.crf < 0 || send.crf > 51) { print_usage(); return std::nullopt; } } else if (argument == "--port") { std::string_view value; int port = 0; if (!next_argument(argc, argv, index, value) || !parse_int(value, port) || port <= 0 || port > 65535) { print_usage(); return std::nullopt; } receive.local_rtp_port = port; } else if (argument == "--signaling-port") { std::string_view value; int port = 0; if (!next_argument(argc, argv, index, value) || !parse_int(value, port) || port <= 0 || port > 65535) { print_usage(); return std::nullopt; } receive.signaling_port = port; } else if (argument == "--fullscreen") { receive.fullscreen = true; } else if (argument == "--swdecode") { receive.software_decode = true; } else if (argument == "--timeout") { std::string_view value; if (!next_argument(argc, argv, index, value) || !parse_int(value, discover.timeout_seconds) || discover.timeout_seconds <= 0) { print_usage(); return std::nullopt; } } else { print_usage(); return std::nullopt; } } if (mode == Mode::Send) { return Command{std::move(send)}; } if (mode == Mode::Receive) { return Command{std::move(receive)}; } if (mode == Mode::Discover) { return Command{std::move(discover)}; } if (mode == Mode::Waybar) { return Command{std::move(waybar)}; } print_usage(); return std::nullopt; } } // namespace sc