From edab57887d57909a42ac8abeb75ad0a865e86b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Sat, 31 Dec 2022 10:48:44 +0100 Subject: [PATCH] Redo command line parsing --- src/PowderToySDL.cpp | 222 +++++++++++++++++-------------------------- 1 file changed, 87 insertions(+), 135 deletions(-) diff --git a/src/PowderToySDL.cpp b/src/PowderToySDL.cpp index 78f269678..b416fb6e2 100644 --- a/src/PowderToySDL.cpp +++ b/src/PowderToySDL.cpp @@ -2,6 +2,7 @@ #include "common/tpt-minmax.h" #include +#include #include #include #ifdef WIN @@ -296,109 +297,6 @@ unsigned int GetTicks() return SDL_GetTicks(); } -std::map readArguments(int argc, char * argv[]) -{ - std::map arguments; - - //Defaults - arguments["scale"] = ""; - arguments["proxy"] = ""; - arguments["cafile"] = ""; - arguments["capath"] = ""; - arguments["nohud"] = "false"; //the nohud, sound, and scripts commands currently do nothing. - arguments["sound"] = "false"; - arguments["kiosk"] = "false"; - arguments["redirect"] = "false"; - arguments["nobluescreen"] = "false"; - arguments["scripts"] = "false"; - arguments["open"] = ""; - arguments["ddir"] = ""; - arguments["ptsave"] = ""; - - for (int i=1; i= 7) - { - arguments["open"] = format::URLDecode(argv[i] + 7); // skip "file://" - } - else if (!strncmp(argv[i], "open", 5) && i+1= 8) - { - arguments["ptsave"] = argv[i]; - break; - } - else if (!strncmp(argv[i], "ptsave", 7) && i+1 arguments = readArguments(argc, argv); + using Argument = std::optional; + std::map arguments; - if (arguments["ddir"].length()) + for (auto i = 1; i < argc; ++i) + { + auto str = ByteString(argv[i]); + if (str.BeginsWith("file://")) + { + arguments.insert({ "open", format::URLDecode(str.substr(7 /* length of the "file://" prefix */)) }); + } + else if (str.BeginsWith("ptsave:")) + { + arguments.insert({ "ptsave", str }); + } + else if (auto split = str.SplitBy(':')) + { + arguments.insert({ split.Before(), split.After() }); + } + else if (auto split = str.SplitBy('=')) + { + arguments.insert({ split.Before(), split.After() }); + } + else if (str == "open" || str == "ptsave" || str == "ddir") + { + if (i + 1 < argc) + { + arguments.insert({ str, argv[i + 1] }); + i += 1; + } + else + { + std::cerr << "no value provided for command line parameter " << str << std::endl; + } + } + else + { + arguments.insert({ str, "" }); // so .has_value() is true + } + } + + auto ddirArg = arguments["ddir"]; + if (ddirArg.has_value()) { #ifdef WIN - int failure = _chdir(arguments["ddir"].c_str()); + int failure = _chdir(ddirArg.value().c_str()); #else - int failure = chdir(arguments["ddir"].c_str()); + int failure = chdir(ddirArg.value().c_str()); #endif if (!failure) Platform::sharedCwd = Platform::GetCwd(); @@ -787,14 +724,27 @@ int main(int argc, char * argv[]) momentumScroll = Client::Ref().GetPrefBool("MomentumScroll", true); showAvatars = Client::Ref().GetPrefBool("ShowAvatars", true); + auto true_string = [](ByteString str) { + str = str.ToLower(); + return str == "true" || + str == "t" || + str == "on" || + str == "yes" || + str == "y" || + str == ""; // standalone "redirect" or "disable-bluescreen" or similar arguments + }; + auto true_arg = [&true_string](Argument arg) { + return arg.has_value() && true_string(arg.value()); + }; - if(arguments["kiosk"] == "true") + auto kioskArg = arguments["kiosk"]; + if (kioskArg.has_value()) { - fullscreen = true; + fullscreen = true_string(kioskArg.value()); Client::Ref().SetPref("Fullscreen", fullscreen); } - if(arguments["redirect"] == "true") + if (true_arg(arguments["redirect"])) { FILE *new_stdout = freopen("stdout.log", "w", stdout); FILE *new_stderr = freopen("stderr.log", "w", stderr); @@ -804,26 +754,33 @@ int main(int argc, char * argv[]) } } - if(arguments["scale"].length()) + auto scaleArg = arguments["scale"]; + if (scaleArg.has_value()) { - scale = arguments["scale"].ToNumber(); - Client::Ref().SetPref("Scale", scale); + try + { + scale = scaleArg.value().ToNumber(); + Client::Ref().SetPref("Scale", scale); + } + catch (const std::runtime_error &e) + { + std::cerr << "failed to set scale: " << e.what() << std::endl; + } } - auto clientConfig = [](ByteString cmdlineValue, ByteString configName, ByteString defaultValue) { + auto clientConfig = [](Argument arg, ByteString name, ByteString defaultValue) { ByteString value; - if (cmdlineValue.length()) + if (arg.has_value()) { - value = cmdlineValue; - if (value == "false") + if (value == "") { value = defaultValue; } - Client::Ref().SetPref(configName, value); + Client::Ref().SetPref(name, value); } else { - value = Client::Ref().GetPrefByteString(configName, defaultValue); + value = Client::Ref().GetPrefByteString(name, defaultValue); } return value; }; @@ -831,9 +788,7 @@ int main(int argc, char * argv[]) ByteString cafileString = clientConfig(arguments["cafile"], "CAFile", ""); ByteString capathString = clientConfig(arguments["capath"], "CAPath", ""); - bool disableNetwork = false; - if (arguments.find("disable-network") != arguments.end()) - disableNetwork = true; + bool disableNetwork = true_arg(arguments["disable-network"]); Client::Ref().Initialise(proxyString, cafileString, capathString, disableNetwork); @@ -871,11 +826,7 @@ int main(int argc, char * argv[]) engine->SetFastQuit(Client::Ref().GetPrefBool("FastQuit", true)); #if !defined(DEBUG) - bool enableBluescreen = true; - if(arguments["nobluescreen"] == "true") - { - enableBluescreen = false; - } + bool enableBluescreen = !true_arg(arguments["disable-bluescreen"]); if (enableBluescreen) { //Get ready to catch any dodgy errors @@ -899,23 +850,24 @@ int main(int argc, char * argv[]) gameController = new GameController(); engine->ShowWindow(gameController->GetView()); - if(arguments["open"].length()) + auto openArg = arguments["open"]; + if (openArg.has_value()) { #ifdef DEBUG - std::cout << "Loading " << arguments["open"] << std::endl; + std::cout << "Loading " << openArg.value() << std::endl; #endif - if (Platform::FileExists(arguments["open"])) + if (Platform::FileExists(openArg.value())) { try { std::vector gameSaveData; - if (!Platform::ReadFile(gameSaveData, arguments["open"])) + if (!Platform::ReadFile(gameSaveData, openArg.value())) { new ErrorMessage("Error", "Could not read file"); } else { - SaveFile * newFile = new SaveFile(arguments["open"]); + SaveFile * newFile = new SaveFile(openArg.value()); GameSave * newSave = new GameSave(std::move(gameSaveData)); newFile->SetGameSave(newSave); gameController->LoadSaveFile(newFile); @@ -934,18 +886,18 @@ int main(int argc, char * argv[]) } } - if (arguments["ptsave"].length()) + auto ptsaveArg = arguments["ptsave"]; + if (ptsaveArg.has_value()) { engine->g->fillrect((engine->GetWidth()/2)-101, (engine->GetHeight()/2)-26, 202, 52, 0, 0, 0, 210); engine->g->drawrect((engine->GetWidth()/2)-100, (engine->GetHeight()/2)-25, 200, 50, 255, 255, 255, 180); engine->g->drawtext((engine->GetWidth()/2)-(Graphics::textwidth("Loading save...")/2), (engine->GetHeight()/2)-5, "Loading save...", style::Colour::InformationTitle.Red, style::Colour::InformationTitle.Green, style::Colour::InformationTitle.Blue, 255); blit(engine->g->vid); - ByteString ptsaveArg = arguments["ptsave"]; try { ByteString saveIdPart; - if (ByteString::Split split = arguments["ptsave"].SplitBy(':')) + if (ByteString::Split split = ptsaveArg.value().SplitBy(':')) { if (split.Before() != "ptsave") throw std::runtime_error("Not a ptsave link");