Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

options parser: add simple options parser, base on artistic style parser #970

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ set(SOURCE_FILES
util/Meta.hxx
util/Exception.{hxx,cxx}
util/OSystem.{hxx,cxx}
util/AppOptions.{hxx,cxx}
services/Randomizer.{hxx,cxx}
services/GameClock.{hxx,cxx}
services/GameClock.inl.hxx
Expand Down
29 changes: 9 additions & 20 deletions src/main.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "MainMenu.hxx"
#include "Exception.hxx"
#include "LOG.hxx"
#include "AppOptions.hxx"
#include "engine/WindowManager.hxx"

#include <SDL.h>
Expand Down Expand Up @@ -51,32 +52,15 @@ int protected_main(int argc, char **argv)

LOG(LOG_INFO) << VERSION;

// add commandline parameter to skipMenu
auto has_args = [argv, argc](const std::string &param)
{
for (int i = 1; i < argc; ++i)
if (param == argv[i])
return i;

LOG(LOG_DEBUG) << "Unknown game option " << param;
return 0;
};

bool skipMenu = has_args("--skipMenu");
uint32_t videoOpt = has_args("--video");
const char *videoDriver = nullptr;
if (videoOpt)
{
videoDriver = argv[videoOpt + 1];
}
bool skipMenu = AppOptions::parseOption("skipMenu", "");
std::string videoDriver = AppOptions::parseOption("video", "", "");

LOG(LOG_DEBUG) << "Launching Cytopia";

Cytopia::Game game;

LOG(LOG_DEBUG) << "Initializing Cytopia";

if (!initialize(videoDriver))
if (!initialize(videoDriver.c_str()))
return EXIT_FAILURE;
else
LOG(LOG_DEBUG) << "DONE Cytopia";
Expand All @@ -101,6 +85,11 @@ int protected_main(int argc, char **argv)

int main(int argc, char **argv)
{
AppOptions::setArgvOptions(argc, argv);
std::string errorInfo;
if (!AppOptions::parseOptions(errorInfo))
LOG(LOG_DEBUG) << "Options error: " << errorInfo;

systemSetupCrashHandler();

try
Expand Down
120 changes: 120 additions & 0 deletions src/util/AppOptions.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#include "AppOptions.hxx"

#include <cstring>

// build a vector of argv options
// the program path argv[0] is excluded
static std::vector<std::string > argvOptions;

void AppOptions::setArgvOptions(int argc, char **argv)
{
argvOptions.clear();
for (int i = 1; i < argc; i++)
argvOptions.emplace_back(std::string(argv[i]));
}

bool AppOptions::parseOptions(const std::string &errorInfo)
{
std::string arg, subArg, subArg2;

for (auto &arg : argvOptions)
{
if (arg.compare(0, 2, "--") == 0)
{
parseOption(arg.substr(2), errorInfo);
}
else if (arg[0] == '-')
{
size_t i;
for (i = 1; i < arg.length(); ++i)
{
if (i > 1 && isalpha((unsigned char)arg[i]) && arg[i - 1] != 'x')
{
// parse the previous option in subArg
parseOption(subArg, errorInfo);
subArg = "";
}

if (arg[i] == '-')
{
parseOption(subArg2, errorInfo);
subArg2 = "";
i++;
}

// append the current option to subArg
subArg.append(1, arg[i]);
subArg2.append(1, arg[i]);
}

subArg = "";
}
else
{
parseOption(arg, errorInfo);
subArg = "";
}
}

if (errorInfo.length() > 0)
return false;

return true;
}

bool AppOptions::isOption(const std::string &arg, const char *op)
{
return arg.compare(op) == 0;
}

bool AppOptions::isOption(const std::string &arg, const char *a, const char *b)
{
return (isOption(arg, a) || isOption(arg, b));
}

bool AppOptions::isParamOption(const std::string &arg, const char *option)
{
bool retVal = arg.compare(0, strlen(option), option) == 0;
// if comparing for short option, 2nd char of arg must be numeric
if (retVal && strlen(option) == 1 && arg.length() > 1)
if (!isdigit((unsigned char)arg[1]))
retVal = false;
return retVal;
}

bool AppOptions::isParamOption(const std::string &arg, const char *option1, const char *option2)
{
return isParamOption(arg, option1) || isParamOption(arg, option2);
}

std::string AppOptions::getParam(const std::string &arg, const char *op)
{
std::string param = arg.substr(strlen(op));
if (param.size() > 1 && param.front() == '=')
param.erase(0, 1);
return param;
}

std::string AppOptions::getParam(const std::string &arg, const char *op1, const char *op2)
{
return isParamOption(arg, op1) ? getParam(arg, op1) : getParam(arg, op2);
}

std::vector<std::string > &AppOptions::getArgvOptions()
{
return argvOptions;
}

void AppOptions::parseOption(const std::string &arg, const std::string &errorInfo)
{
// sample how to check options
if (isParamOption(arg, "s", "map-size="))
{
std::string mapSizeStr = getParam(arg, "s", "map-size=");
int mapSize = 0;
if (mapSizeStr.length() > 0)
mapSize = atoi(mapSizeStr.c_str());

return;
}
}
76 changes: 76 additions & 0 deletions src/util/AppOptions.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#ifndef APPOPTIONS_HXX_
#define APPOPTIONS_HXX_

#include <vector>
#include <string>

struct AppOptions {
template<class Func>
static bool parseOption(const char *a, const char *b, const Func &func)
{
bool hasb = (b && *b);
for (auto &arg : getArgvOptions())
{
if (arg.compare(0, 2, "--") == 0)
{
std::string rarg = arg.substr(2);
if (hasb && isParamOption(rarg, a, b)) {
std::string param = getParam(rarg, a, b);
return func(param);
}
else if (isParamOption(rarg, a))
{
std::string param = getParam(rarg, a);
return func(param);
}
}
else if (arg.front() == '-')
{
std::string rarg = arg.substr(1);
if (hasb && isParamOption(rarg, a, b)) {
std::string param = getParam(rarg, a, b);
return func(param);
}
else if (isParamOption(rarg, a))
{
std::string param = getParam(rarg, a);
return func(param);
}
}
else
{
if (hasb && isOption(arg, a, b)) {
return func("");
}
else if (isOption(arg, a)) {
return func("");
}
}
}
return false;
}

static bool parseOption(const char *a, const char *b) { return parseOption(a, b, [] (auto &) { return true; }); }
static std::string parseOption(const char *a, const char *b, const char *def) {
std::string param;
bool found = parseOption(a, b, [&param] (auto &p) { param = p; return true; });
return found ? param : def;
}

static void setArgvOptions(int argc, char **argv);
static bool parseOptions(const std::string &errorInfo);

private:
static void parseOption(const std::string &arg, const std::string &errorInfo);
static bool isOption(const std::string &arg, const char *op);
static bool isOption(const std::string &arg, const char *a, const char *b);
static bool isParamOption(const std::string &arg, const char *option);
static bool isParamOption(const std::string &arg, const char *option1, const char *option2);
static std::string getParam(const std::string &arg, const char *op);
static std::string getParam(const std::string &arg, const char *op1, const char *op2);
static std::vector<std::string> &getArgvOptions();

AppOptions(const AppOptions &) = delete;
AppOptions &operator=(AppOptions &) = delete;
};
#endif // APPOPTIONS_HXX_