mirror of https://github.com/mgba-emu/mgba.git
Feature: Modernize argument parsing API
This commit is contained in:
parent
770b121b10
commit
4556d4b121
|
@ -31,12 +31,20 @@ struct mArguments {
|
||||||
bool showVersion;
|
bool showVersion;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mOption {
|
||||||
|
const char* name;
|
||||||
|
bool arg;
|
||||||
|
char shortEquiv;
|
||||||
|
};
|
||||||
|
|
||||||
struct mCoreConfig;
|
struct mCoreConfig;
|
||||||
struct mSubParser {
|
struct mSubParser {
|
||||||
const char* usage;
|
const char* usage;
|
||||||
bool (*parse)(struct mSubParser* parser, int option, const char* arg);
|
bool (*parse)(struct mSubParser* parser, int option, const char* arg);
|
||||||
|
bool (*parseLong)(struct mSubParser* parser, const char* option, const char* arg);
|
||||||
void (*apply)(struct mSubParser* parser, struct mCoreConfig* config);
|
void (*apply)(struct mSubParser* parser, struct mCoreConfig* config);
|
||||||
const char* extraOptions;
|
const char* extraOptions;
|
||||||
|
const struct mOption* longOptions;
|
||||||
void* opts;
|
void* opts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,15 +53,14 @@ struct mGraphicsOpts {
|
||||||
bool fullscreen;
|
bool fullscreen;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool parseArguments(struct mArguments* args, int argc, char* const* argv,
|
void usage(const char* arg0, const char* prologue, const char* epilogue, const struct mSubParser* subparsers, int nSubparsers);
|
||||||
struct mSubParser* subparser);
|
|
||||||
void applyArguments(const struct mArguments* args, struct mSubParser* subparser, struct mCoreConfig* config);
|
|
||||||
void freeArguments(struct mArguments* args);
|
|
||||||
|
|
||||||
void usage(const char* arg0, const char* extraOptions);
|
|
||||||
void version(const char* arg0);
|
void version(const char* arg0);
|
||||||
|
|
||||||
void initParserForGraphics(struct mSubParser* parser, struct mGraphicsOpts* opts);
|
bool mArgumentsParse(struct mArguments* args, int argc, char* const* argv, struct mSubParser* subparsers, int nSubparsers);
|
||||||
|
void mArgumentsApply(const struct mArguments* args, struct mSubParser* subparsers, int nSubparsers, struct mCoreConfig* config);
|
||||||
|
void mArgumentsDeinit(struct mArguments* args);
|
||||||
|
|
||||||
|
void mSubParserGraphicsInit(struct mSubParser* parser, struct mGraphicsOpts* opts);
|
||||||
|
|
||||||
CXX_GUARD_END
|
CXX_GUARD_END
|
||||||
|
|
||||||
|
|
|
@ -16,16 +16,12 @@
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define GRAPHICS_OPTIONS "123456f"
|
#define GRAPHICS_OPTIONS "12345678f"
|
||||||
#define GRAPHICS_USAGE \
|
#define GRAPHICS_USAGE \
|
||||||
"\nGraphics options:\n" \
|
"Graphics options:\n" \
|
||||||
" -1 1x viewport\n" \
|
" -1, -2, -3, -4, -5, -6, -7, -8 Scale viewport by 1-8 times\n" \
|
||||||
" -2 2x viewport\n" \
|
" -f, --fullscreen Start full-screen\n" \
|
||||||
" -3 3x viewport\n" \
|
" --scale X Scale viewport by X times"
|
||||||
" -4 4x viewport\n" \
|
|
||||||
" -5 5x viewport\n" \
|
|
||||||
" -6 6x viewport\n" \
|
|
||||||
" -f Start full-screen"
|
|
||||||
|
|
||||||
static const struct option _options[] = {
|
static const struct option _options[] = {
|
||||||
{ "bios", required_argument, 0, 'b' },
|
{ "bios", required_argument, 0, 'b' },
|
||||||
|
@ -45,7 +41,14 @@ static const struct option _options[] = {
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct mOption _graphicsLongOpts[] = {
|
||||||
|
{ "fullscreen", false, 'f' },
|
||||||
|
{ "scale", true, '\0' },
|
||||||
|
{ 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
static bool _parseGraphicsArg(struct mSubParser* parser, int option, const char* arg);
|
static bool _parseGraphicsArg(struct mSubParser* parser, int option, const char* arg);
|
||||||
|
static bool _parseLongGraphicsArg(struct mSubParser* parser, const char* option, const char* arg);
|
||||||
static void _applyGraphicsArgs(struct mSubParser* parser, struct mCoreConfig* config);
|
static void _applyGraphicsArgs(struct mSubParser* parser, struct mCoreConfig* config);
|
||||||
|
|
||||||
static void _tableInsert(struct Table* table, const char* pair) {
|
static void _tableInsert(struct Table* table, const char* pair) {
|
||||||
|
@ -65,9 +68,9 @@ static void _tableApply(const char* key, void* value, void* user) {
|
||||||
mCoreConfigSetOverrideValue(config, key, value);
|
mCoreConfigSetOverrideValue(config, key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct mSubParser* subparser) {
|
bool mArgumentsParse(struct mArguments* args, int argc, char* const* argv, struct mSubParser* subparsers, int nSubparsers) {
|
||||||
int ch;
|
int ch;
|
||||||
char options[64] =
|
char options[128] =
|
||||||
"b:c:C:hl:p:s:t:"
|
"b:c:C:hl:p:s:t:"
|
||||||
#ifdef USE_EDITLINE
|
#ifdef USE_EDITLINE
|
||||||
"d"
|
"d"
|
||||||
|
@ -76,23 +79,51 @@ bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct
|
||||||
"g"
|
"g"
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
|
struct option longOptions[128] = {0};
|
||||||
|
memcpy(longOptions, _options, sizeof(_options));
|
||||||
|
|
||||||
memset(args, 0, sizeof(*args));
|
memset(args, 0, sizeof(*args));
|
||||||
args->frameskip = -1;
|
args->frameskip = -1;
|
||||||
args->logLevel = INT_MIN;
|
args->logLevel = INT_MIN;
|
||||||
HashTableInit(&args->configOverrides, 0, free);
|
HashTableInit(&args->configOverrides, 0, free);
|
||||||
if (subparser && subparser->extraOptions) {
|
int lastLongOpt;
|
||||||
// TODO: modularize options to subparsers
|
|
||||||
strncat(options, subparser->extraOptions, sizeof(options) - strlen(options) - 1);
|
int i, j;
|
||||||
|
for (i = 0; _options[i].name; ++i); // Seek to end
|
||||||
|
lastLongOpt = i;
|
||||||
|
|
||||||
|
for (i = 0; i < nSubparsers; ++i) {
|
||||||
|
if (subparsers[i].extraOptions) {
|
||||||
|
strncat(options, subparsers[i].extraOptions, sizeof(options) - strlen(options) - 1);
|
||||||
|
}
|
||||||
|
if (subparsers[i].longOptions) {
|
||||||
|
for (j = 0; subparsers[i].longOptions[j].name; ++j) {
|
||||||
|
longOptions[lastLongOpt].name = subparsers[i].longOptions[j].name;
|
||||||
|
longOptions[lastLongOpt].has_arg = subparsers[i].longOptions[j].arg ? required_argument : no_argument;
|
||||||
|
longOptions[lastLongOpt].flag = NULL;
|
||||||
|
longOptions[lastLongOpt].val = subparsers[i].longOptions[j].shortEquiv;
|
||||||
|
++lastLongOpt;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
bool ok = false;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
while ((ch = getopt_long(argc, argv, options, _options, &index)) != -1) {
|
while ((ch = getopt_long(argc, argv, options, longOptions, &index)) != -1) {
|
||||||
const struct option* opt = &_options[index];
|
const struct option* opt = &longOptions[index];
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case '\0':
|
case '\0':
|
||||||
if (strcmp(opt->name, "version") == 0) {
|
if (strcmp(opt->name, "version") == 0) {
|
||||||
args->showVersion = true;
|
args->showVersion = true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
for (i = 0; i < nSubparsers; ++i) {
|
||||||
|
if (subparsers[i].parseLong) {
|
||||||
|
ok = subparsers[i].parseLong(&subparsers[i], opt->name, optarg) || ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ok) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'b':
|
case 'b':
|
||||||
|
@ -136,11 +167,14 @@ bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct
|
||||||
args->savestate = strdup(optarg);
|
args->savestate = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (subparser) {
|
for (i = 0; i < nSubparsers; ++i) {
|
||||||
if (!subparser->parse(subparser, ch, optarg)) {
|
if (subparsers[i].parse) {
|
||||||
return false;
|
ok = subparsers[i].parse(&subparsers[i], ch, optarg) || ok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!ok) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,7 +190,7 @@ bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void applyArguments(const struct mArguments* args, struct mSubParser* subparser, struct mCoreConfig* config) {
|
void mArgumentsApply(const struct mArguments* args, struct mSubParser* subparsers, int nSubparsers, struct mCoreConfig* config) {
|
||||||
if (args->frameskip >= 0) {
|
if (args->frameskip >= 0) {
|
||||||
mCoreConfigSetOverrideIntValue(config, "frameskip", args->frameskip);
|
mCoreConfigSetOverrideIntValue(config, "frameskip", args->frameskip);
|
||||||
}
|
}
|
||||||
|
@ -168,12 +202,15 @@ void applyArguments(const struct mArguments* args, struct mSubParser* subparser,
|
||||||
mCoreConfigSetOverrideIntValue(config, "useBios", true);
|
mCoreConfigSetOverrideIntValue(config, "useBios", true);
|
||||||
}
|
}
|
||||||
HashTableEnumerate(&args->configOverrides, _tableApply, config);
|
HashTableEnumerate(&args->configOverrides, _tableApply, config);
|
||||||
if (subparser) {
|
int i;
|
||||||
subparser->apply(subparser, config);
|
for (i = 0; i < nSubparsers; ++i) {
|
||||||
|
if (subparsers[i].apply) {
|
||||||
|
subparsers[i].apply(&subparsers[i], config);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeArguments(struct mArguments* args) {
|
void mArgumentsDeinit(struct mArguments* args) {
|
||||||
free(args->fname);
|
free(args->fname);
|
||||||
args->fname = 0;
|
args->fname = 0;
|
||||||
|
|
||||||
|
@ -192,12 +229,14 @@ void freeArguments(struct mArguments* args) {
|
||||||
HashTableDeinit(&args->configOverrides);
|
HashTableDeinit(&args->configOverrides);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initParserForGraphics(struct mSubParser* parser, struct mGraphicsOpts* opts) {
|
void mSubParserGraphicsInit(struct mSubParser* parser, struct mGraphicsOpts* opts) {
|
||||||
parser->usage = GRAPHICS_USAGE;
|
parser->usage = GRAPHICS_USAGE;
|
||||||
parser->opts = opts;
|
parser->opts = opts;
|
||||||
parser->parse = _parseGraphicsArg;
|
parser->parse = _parseGraphicsArg;
|
||||||
|
parser->parseLong = _parseLongGraphicsArg;
|
||||||
parser->apply = _applyGraphicsArgs;
|
parser->apply = _applyGraphicsArgs;
|
||||||
parser->extraOptions = GRAPHICS_OPTIONS;
|
parser->extraOptions = GRAPHICS_OPTIONS;
|
||||||
|
parser->longOptions = _graphicsLongOpts;
|
||||||
opts->multiplier = 0;
|
opts->multiplier = 0;
|
||||||
opts->fullscreen = false;
|
opts->fullscreen = false;
|
||||||
}
|
}
|
||||||
|
@ -215,6 +254,8 @@ bool _parseGraphicsArg(struct mSubParser* parser, int option, const char* arg) {
|
||||||
case '4':
|
case '4':
|
||||||
case '5':
|
case '5':
|
||||||
case '6':
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
if (graphicsOpts->multiplier) {
|
if (graphicsOpts->multiplier) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -225,6 +266,18 @@ bool _parseGraphicsArg(struct mSubParser* parser, int option, const char* arg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _parseLongGraphicsArg(struct mSubParser* parser, const char* option, const char* arg) {
|
||||||
|
struct mGraphicsOpts* graphicsOpts = parser->opts;
|
||||||
|
if (strcmp(option, "scale") == 0) {
|
||||||
|
if (graphicsOpts->multiplier) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
graphicsOpts->multiplier = atoi(arg);
|
||||||
|
return graphicsOpts->multiplier != 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void _applyGraphicsArgs(struct mSubParser* parser, struct mCoreConfig* config) {
|
void _applyGraphicsArgs(struct mSubParser* parser, struct mCoreConfig* config) {
|
||||||
struct mGraphicsOpts* graphicsOpts = parser->opts;
|
struct mGraphicsOpts* graphicsOpts = parser->opts;
|
||||||
if (graphicsOpts->fullscreen) {
|
if (graphicsOpts->fullscreen) {
|
||||||
|
@ -232,25 +285,36 @@ void _applyGraphicsArgs(struct mSubParser* parser, struct mCoreConfig* config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void usage(const char* arg0, const char* extraOptions) {
|
void usage(const char* arg0, const char* prologue, const char* epilogue, const struct mSubParser* subparsers, int nSubparsers) {
|
||||||
printf("usage: %s [option ...] file\n", arg0);
|
printf("usage: %s [option ...] file\n", arg0);
|
||||||
puts("\nGeneric options:");
|
if (prologue) {
|
||||||
puts(" -b, --bios FILE GBA BIOS file to use");
|
puts(prologue);
|
||||||
puts(" -c, --cheats FILE Apply cheat codes from a file");
|
}
|
||||||
puts(" -C, --config OPTION=VALUE Override config value");
|
puts("\nGeneric options:\n"
|
||||||
|
" -b, --bios FILE GBA BIOS file to use\n"
|
||||||
|
" -c, --cheats FILE Apply cheat codes from a file\n"
|
||||||
|
" -C, --config OPTION=VALUE Override config value\n"
|
||||||
#ifdef USE_EDITLINE
|
#ifdef USE_EDITLINE
|
||||||
puts(" -d, --debug Use command-line debugger");
|
" -d, --debug Use command-line debugger\n"
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_GDB_STUB
|
#ifdef USE_GDB_STUB
|
||||||
puts(" -g, --gdb Start GDB session (default port 2345)");
|
" -g, --gdb Start GDB session (default port 2345)\n"
|
||||||
#endif
|
#endif
|
||||||
puts(" -l, --log-level N Log level mask");
|
" -l, --log-level N Log level mask\n"
|
||||||
puts(" -t, --savestate FILE Load savestate when starting");
|
" -t, --savestate FILE Load savestate when starting\n"
|
||||||
puts(" -p, --patch FILE Apply a specified patch file when running");
|
" -p, --patch FILE Apply a specified patch file when running\n"
|
||||||
puts(" -s, --frameskip N Skip every N frames");
|
" -s, --frameskip N Skip every N frames\n"
|
||||||
puts(" --version Print version and exit");
|
" --version Print version and exit"
|
||||||
if (extraOptions) {
|
);
|
||||||
puts(extraOptions);
|
int i;
|
||||||
|
for (i = 0; i < nSubparsers; ++i) {
|
||||||
|
if (subparsers[i].usage) {
|
||||||
|
puts("");
|
||||||
|
puts(subparsers[i].usage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (epilogue) {
|
||||||
|
puts(epilogue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,14 +16,14 @@ int main(int argc, char** argv) {
|
||||||
// Arguments from the command line are parsed by the parseArguments function.
|
// Arguments from the command line are parsed by the parseArguments function.
|
||||||
// The NULL here shows that we don't give it any arguments beyond the default ones.
|
// The NULL here shows that we don't give it any arguments beyond the default ones.
|
||||||
struct mArguments args = {};
|
struct mArguments args = {};
|
||||||
bool parsed = parseArguments(&args, argc, argv, NULL);
|
bool parsed = mArgumentsParse(&args, argc, argv, NULL, 0);
|
||||||
// Parsing can succeed without finding a filename, but we need one.
|
// Parsing can succeed without finding a filename, but we need one.
|
||||||
if (!args.fname) {
|
if (!args.fname) {
|
||||||
parsed = false;
|
parsed = false;
|
||||||
}
|
}
|
||||||
if (!parsed || args.showHelp) {
|
if (!parsed || args.showHelp) {
|
||||||
// If parsing failed, or the user passed --help, show usage.
|
// If parsing failed, or the user passed --help, show usage.
|
||||||
usage(argv[0], NULL);
|
usage(argv[0], NULL, NULL, NULL, 0);
|
||||||
didFail = !parsed;
|
didFail = !parsed;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ int main(int argc, char** argv) {
|
||||||
SocketSubsystemDeinit();
|
SocketSubsystemDeinit();
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
freeArguments(&args);
|
mArgumentsDeinit(&args);
|
||||||
|
|
||||||
return didFail;
|
return didFail;
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ bool _mExampleRun(const struct mArguments* args, Socket client) {
|
||||||
// loaded into the config system, as well as manually overriding the
|
// loaded into the config system, as well as manually overriding the
|
||||||
// "idleOptimization" setting to ensure cores that can detect idle loops
|
// "idleOptimization" setting to ensure cores that can detect idle loops
|
||||||
// will attempt the detection.
|
// will attempt the detection.
|
||||||
applyArguments(args, NULL, &core->config);
|
mArgumentsApply(args, NULL, 0, &core->config);
|
||||||
mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "detect");
|
mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "detect");
|
||||||
|
|
||||||
// Tell the core to apply the configuration in the associated config object.
|
// Tell the core to apply the configuration in the associated config object.
|
||||||
|
|
|
@ -130,13 +130,22 @@ ConfigController::ConfigController(QObject* parent)
|
||||||
ConfigController::~ConfigController() {
|
ConfigController::~ConfigController() {
|
||||||
mCoreConfigDeinit(&m_config);
|
mCoreConfigDeinit(&m_config);
|
||||||
mCoreConfigFreeOpts(&m_opts);
|
mCoreConfigFreeOpts(&m_opts);
|
||||||
|
|
||||||
|
if (m_parsed) {
|
||||||
|
mArgumentsDeinit(&m_args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConfigController::parseArguments(mArguments* args, int argc, char* argv[], mSubParser* subparser) {
|
bool ConfigController::parseArguments(int argc, char* argv[]) {
|
||||||
if (::parseArguments(args, argc, argv, subparser)) {
|
if (m_parsed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mSubParserGraphicsInit(&m_subparsers[0], &m_graphicsOpts);
|
||||||
|
if (mArgumentsParse(&m_args, argc, argv, m_subparsers.data(), m_subparsers.size())) {
|
||||||
mCoreConfigFreeOpts(&m_opts);
|
mCoreConfigFreeOpts(&m_opts);
|
||||||
applyArguments(args, subparser, &m_config);
|
mArgumentsApply(&m_args, m_subparsers.data(), m_subparsers.size(), &m_config);
|
||||||
mCoreConfigMap(&m_config, &m_opts);
|
mCoreConfigMap(&m_config, &m_opts);
|
||||||
|
m_parsed = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -299,6 +308,10 @@ void ConfigController::makePortable() {
|
||||||
m_settings = std::move(settings2);
|
m_settings = std::move(settings2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigController::usage(const char* arg0) const {
|
||||||
|
::usage(arg0, nullptr, nullptr, m_subparsers.data(), m_subparsers.size());
|
||||||
|
}
|
||||||
|
|
||||||
bool ConfigController::isPortable() {
|
bool ConfigController::isPortable() {
|
||||||
return mCoreConfigIsPortable();
|
return mCoreConfigIsPortable();
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ public:
|
||||||
~ConfigController();
|
~ConfigController();
|
||||||
|
|
||||||
const mCoreOptions* options() const { return &m_opts; }
|
const mCoreOptions* options() const { return &m_opts; }
|
||||||
bool parseArguments(mArguments* args, int argc, char* argv[], mSubParser* subparser = nullptr);
|
bool parseArguments(int argc, char* argv[]);
|
||||||
|
|
||||||
ConfigOption* addOption(const char* key);
|
ConfigOption* addOption(const char* key);
|
||||||
void updateOption(const char* key);
|
void updateOption(const char* key);
|
||||||
|
@ -91,6 +92,10 @@ public:
|
||||||
const mCoreConfig* config() const { return &m_config; }
|
const mCoreConfig* config() const { return &m_config; }
|
||||||
mCoreConfig* config() { return &m_config; }
|
mCoreConfig* config() { return &m_config; }
|
||||||
|
|
||||||
|
const mArguments* args() const { return &m_args; }
|
||||||
|
const mGraphicsOpts* graphicsOpts() const { return &m_graphicsOpts; }
|
||||||
|
void usage(const char* arg0) const;
|
||||||
|
|
||||||
static const QString& configDir();
|
static const QString& configDir();
|
||||||
static bool isPortable();
|
static bool isPortable();
|
||||||
|
|
||||||
|
@ -110,6 +115,10 @@ private:
|
||||||
|
|
||||||
mCoreConfig m_config;
|
mCoreConfig m_config;
|
||||||
mCoreOptions m_opts{};
|
mCoreOptions m_opts{};
|
||||||
|
mArguments m_args{};
|
||||||
|
mGraphicsOpts m_graphicsOpts{};
|
||||||
|
std::array<mSubParser, 1> m_subparsers;
|
||||||
|
bool m_parsed = false;
|
||||||
|
|
||||||
QHash<QString, ConfigOption*> m_optionSet;
|
QHash<QString, ConfigOption*> m_optionSet;
|
||||||
std::unique_ptr<QSettings> m_settings;
|
std::unique_ptr<QSettings> m_settings;
|
||||||
|
|
|
@ -179,8 +179,8 @@ Window::~Window() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::argumentsPassed(mArguments* args) {
|
void Window::argumentsPassed() {
|
||||||
loadConfig();
|
const mArguments* args = m_config->args();
|
||||||
|
|
||||||
if (args->patch) {
|
if (args->patch) {
|
||||||
m_pendingPatch = args->patch;
|
m_pendingPatch = args->patch;
|
||||||
|
@ -203,9 +203,24 @@ void Window::argumentsPassed(mArguments* args) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (m_config->graphicsOpts()->multiplier) {
|
||||||
|
m_savedScale = m_config->graphicsOpts()->multiplier;
|
||||||
|
|
||||||
|
#if defined(M_CORE_GBA)
|
||||||
|
QSize size(GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
|
||||||
|
#elif defined(M_CORE_GB)
|
||||||
|
QSize size(GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS);
|
||||||
|
#endif
|
||||||
|
resizeFrame(size * m_savedScale);
|
||||||
|
}
|
||||||
|
|
||||||
if (args->fname) {
|
if (args->fname) {
|
||||||
setController(m_manager->loadGame(args->fname), args->fname);
|
setController(m_manager->loadGame(args->fname), args->fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_config->graphicsOpts()->fullscreen) {
|
||||||
|
enterFullScreen();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::resizeFrame(const QSize& size) {
|
void Window::resizeFrame(const QSize& size) {
|
||||||
|
|
|
@ -24,8 +24,6 @@
|
||||||
#include "LogController.h"
|
#include "LogController.h"
|
||||||
#include "SettingsView.h"
|
#include "SettingsView.h"
|
||||||
|
|
||||||
struct mArguments;
|
|
||||||
|
|
||||||
namespace QGBA {
|
namespace QGBA {
|
||||||
|
|
||||||
class AudioProcessor;
|
class AudioProcessor;
|
||||||
|
@ -59,7 +57,7 @@ public:
|
||||||
void setConfig(ConfigController*);
|
void setConfig(ConfigController*);
|
||||||
ConfigController* config() { return m_config; }
|
ConfigController* config() { return m_config; }
|
||||||
|
|
||||||
void argumentsPassed(mArguments*);
|
void argumentsPassed();
|
||||||
|
|
||||||
void resizeFrame(const QSize& size);
|
void resizeFrame(const QSize& size);
|
||||||
|
|
||||||
|
|
|
@ -68,22 +68,18 @@ int main(int argc, char* argv[]) {
|
||||||
QLocale::setDefault(locale);
|
QLocale::setDefault(locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
mArguments args;
|
if (configController.parseArguments(argc, argv)) {
|
||||||
mGraphicsOpts graphicsOpts;
|
if (configController.args()->showHelp) {
|
||||||
mSubParser subparser;
|
configController.usage(argv[0]);
|
||||||
initParserForGraphics(&subparser, &graphicsOpts);
|
|
||||||
bool loaded = configController.parseArguments(&args, argc, argv, &subparser);
|
|
||||||
if (loaded) {
|
|
||||||
if (args.showHelp) {
|
|
||||||
usage(argv[0], subparser.usage);
|
|
||||||
freeArguments(&args);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (args.showVersion) {
|
if (configController.args()->showVersion) {
|
||||||
version(argv[0]);
|
version(argv[0]);
|
||||||
freeArguments(&args);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
configController.usage(argv[0]);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QApplication::setApplicationName(projectName);
|
QApplication::setApplicationName(projectName);
|
||||||
|
@ -117,19 +113,8 @@ int main(int argc, char* argv[]) {
|
||||||
application.installTranslator(&langTranslator);
|
application.installTranslator(&langTranslator);
|
||||||
|
|
||||||
Window* w = application.newWindow();
|
Window* w = application.newWindow();
|
||||||
if (loaded) {
|
w->loadConfig();
|
||||||
w->argumentsPassed(&args);
|
w->argumentsPassed();
|
||||||
} else {
|
|
||||||
w->loadConfig();
|
|
||||||
}
|
|
||||||
freeArguments(&args);
|
|
||||||
|
|
||||||
if (graphicsOpts.multiplier) {
|
|
||||||
w->resizeFrame(QSize(GBA_VIDEO_HORIZONTAL_PIXELS * graphicsOpts.multiplier, GBA_VIDEO_VERTICAL_PIXELS * graphicsOpts.multiplier));
|
|
||||||
}
|
|
||||||
if (graphicsOpts.fullscreen) {
|
|
||||||
w->enterFullScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
w->show();
|
w->show();
|
||||||
|
|
||||||
|
|
|
@ -80,37 +80,37 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
struct mSubParser subparser;
|
struct mSubParser subparser;
|
||||||
|
|
||||||
initParserForGraphics(&subparser, &graphicsOpts);
|
mSubParserGraphicsInit(&subparser, &graphicsOpts);
|
||||||
bool parsed = parseArguments(&args, argc, argv, &subparser);
|
bool parsed = mArgumentsParse(&args, argc, argv, &subparser, 1);
|
||||||
if (!args.fname && !args.showVersion) {
|
if (!args.fname && !args.showVersion) {
|
||||||
parsed = false;
|
parsed = false;
|
||||||
}
|
}
|
||||||
if (!parsed || args.showHelp) {
|
if (!parsed || args.showHelp) {
|
||||||
usage(argv[0], subparser.usage);
|
usage(argv[0], NULL, NULL, &subparser, 1);
|
||||||
freeArguments(&args);
|
mArgumentsDeinit(&args);
|
||||||
return !parsed;
|
return !parsed;
|
||||||
}
|
}
|
||||||
if (args.showVersion) {
|
if (args.showVersion) {
|
||||||
version(argv[0]);
|
version(argv[0]);
|
||||||
freeArguments(&args);
|
mArgumentsDeinit(&args);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||||
printf("Could not initialize video: %s\n", SDL_GetError());
|
printf("Could not initialize video: %s\n", SDL_GetError());
|
||||||
freeArguments(&args);
|
mArgumentsDeinit(&args);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.core = mCoreFind(args.fname);
|
renderer.core = mCoreFind(args.fname);
|
||||||
if (!renderer.core) {
|
if (!renderer.core) {
|
||||||
printf("Could not run game. Are you sure the file exists and is a compatible game?\n");
|
printf("Could not run game. Are you sure the file exists and is a compatible game?\n");
|
||||||
freeArguments(&args);
|
mArgumentsDeinit(&args);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!renderer.core->init(renderer.core)) {
|
if (!renderer.core->init(renderer.core)) {
|
||||||
freeArguments(&args);
|
mArgumentsDeinit(&args);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
mInputMapInit(&renderer.core->inputMap, &GBAInputInfo);
|
mInputMapInit(&renderer.core->inputMap, &GBAInputInfo);
|
||||||
mCoreInitConfig(renderer.core, PORT);
|
mCoreInitConfig(renderer.core, PORT);
|
||||||
applyArguments(&args, &subparser, &renderer.core->config);
|
mArgumentsApply(&args, &subparser, 1, &renderer.core->config);
|
||||||
|
|
||||||
mCoreConfigLoadDefaults(&renderer.core->config, &opts);
|
mCoreConfigLoadDefaults(&renderer.core->config, &opts);
|
||||||
mCoreLoadConfig(renderer.core);
|
mCoreLoadConfig(renderer.core);
|
||||||
|
@ -168,7 +168,7 @@ int main(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!renderer.init(&renderer)) {
|
if (!renderer.init(&renderer)) {
|
||||||
freeArguments(&args);
|
mArgumentsDeinit(&args);
|
||||||
mCoreConfigDeinit(&renderer.core->config);
|
mCoreConfigDeinit(&renderer.core->config);
|
||||||
renderer.core->deinit(renderer.core);
|
renderer.core->deinit(renderer.core);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -199,7 +199,7 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
mSDLDeinit(&renderer);
|
mSDLDeinit(&renderer);
|
||||||
|
|
||||||
freeArguments(&args);
|
mArgumentsDeinit(&args);
|
||||||
mCoreConfigFreeOpts(&opts);
|
mCoreConfigFreeOpts(&opts);
|
||||||
mCoreConfigDeinit(&renderer.core->config);
|
mCoreConfigDeinit(&renderer.core->config);
|
||||||
renderer.core->deinit(renderer.core);
|
renderer.core->deinit(renderer.core);
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#define FUZZ_OPTIONS "F:NO:S:V:"
|
#define FUZZ_OPTIONS "F:NO:S:V:"
|
||||||
#define FUZZ_USAGE \
|
#define FUZZ_USAGE \
|
||||||
"\nAdditional options:\n" \
|
"Additional options:\n" \
|
||||||
" -F FRAMES Run for the specified number of FRAMES before exiting\n" \
|
" -F FRAMES Run for the specified number of FRAMES before exiting\n" \
|
||||||
" -N Disable video rendering entirely\n" \
|
" -N Disable video rendering entirely\n" \
|
||||||
" -O OFFSET Offset to apply savestate overlay\n" \
|
" -O OFFSET Offset to apply savestate overlay\n" \
|
||||||
|
@ -53,12 +53,12 @@ int main(int argc, char** argv) {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mArguments args;
|
struct mArguments args;
|
||||||
bool parsed = parseArguments(&args, argc, argv, &subparser);
|
bool parsed = mArgumentsParse(&args, argc, argv, &subparser, 1);
|
||||||
if (!args.fname) {
|
if (!args.fname) {
|
||||||
parsed = false;
|
parsed = false;
|
||||||
}
|
}
|
||||||
if (!parsed || args.showHelp) {
|
if (!parsed || args.showHelp) {
|
||||||
usage(argv[0], FUZZ_USAGE);
|
usage(argv[0], NULL, NULL, &subparser, 1);
|
||||||
return !parsed;
|
return !parsed;
|
||||||
}
|
}
|
||||||
if (args.showVersion) {
|
if (args.showVersion) {
|
||||||
|
@ -71,7 +71,7 @@ int main(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
core->init(core);
|
core->init(core);
|
||||||
mCoreInitConfig(core, "fuzz");
|
mCoreInitConfig(core, "fuzz");
|
||||||
applyArguments(&args, NULL, &core->config);
|
mArgumentsApply(&args, NULL, 0, &core->config);
|
||||||
|
|
||||||
mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "remove");
|
mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "remove");
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ int main(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
loadError:
|
loadError:
|
||||||
freeArguments(&args);
|
mArgumentsDeinit(&args);
|
||||||
if (outputBuffer) {
|
if (outputBuffer) {
|
||||||
free(outputBuffer);
|
free(outputBuffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ size_t romBufferSize;
|
||||||
|
|
||||||
#define PERF_OPTIONS "DF:L:NPS:T"
|
#define PERF_OPTIONS "DF:L:NPS:T"
|
||||||
#define PERF_USAGE \
|
#define PERF_USAGE \
|
||||||
"\nBenchmark options:\n" \
|
"Benchmark options:\n" \
|
||||||
" -F FRAMES Run for the specified number of FRAMES before exiting\n" \
|
" -F FRAMES Run for the specified number of FRAMES before exiting\n" \
|
||||||
" -N Disable video rendering entirely\n" \
|
" -N Disable video rendering entirely\n" \
|
||||||
" -T Use threaded video rendering\n" \
|
" -T Use threaded video rendering\n" \
|
||||||
|
@ -131,12 +131,12 @@ int main(int argc, char** argv) {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mArguments args = {};
|
struct mArguments args = {};
|
||||||
bool parsed = parseArguments(&args, argc, argv, &subparser);
|
bool parsed = mArgumentsParse(&args, argc, argv, &subparser, 1);
|
||||||
if (!args.fname && !perfOpts.server) {
|
if (!args.fname && !perfOpts.server) {
|
||||||
parsed = false;
|
parsed = false;
|
||||||
}
|
}
|
||||||
if (!parsed || args.showHelp) {
|
if (!parsed || args.showHelp) {
|
||||||
usage(argv[0], PERF_USAGE);
|
usage(argv[0], NULL, NULL, &subparser, 1);
|
||||||
didFail = !parsed;
|
didFail = !parsed;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ int main(int argc, char** argv) {
|
||||||
_savestate->close(_savestate);
|
_savestate->close(_savestate);
|
||||||
}
|
}
|
||||||
cleanup:
|
cleanup:
|
||||||
freeArguments(&args);
|
mArgumentsDeinit(&args);
|
||||||
|
|
||||||
#ifdef __3DS__
|
#ifdef __3DS__
|
||||||
gfxExit();
|
gfxExit();
|
||||||
|
@ -217,7 +217,7 @@ bool _mPerfRunCore(const char* fname, const struct mArguments* args, const struc
|
||||||
mCoreConfigMap(&core->config, &opts);
|
mCoreConfigMap(&core->config, &opts);
|
||||||
opts.audioSync = false;
|
opts.audioSync = false;
|
||||||
opts.videoSync = false;
|
opts.videoSync = false;
|
||||||
applyArguments(args, NULL, &core->config);
|
mArgumentsApply(args, NULL, 0, &core->config);
|
||||||
mCoreConfigLoadDefaults(&core->config, &opts);
|
mCoreConfigLoadDefaults(&core->config, &opts);
|
||||||
mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "detect");
|
mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "detect");
|
||||||
mCoreLoadConfig(core);
|
mCoreLoadConfig(core);
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
#define ROM_TEST_OPTIONS "S:R:"
|
#define ROM_TEST_OPTIONS "S:R:"
|
||||||
#define ROM_TEST_USAGE \
|
#define ROM_TEST_USAGE \
|
||||||
"\nAdditional options:\n" \
|
"Additional options:\n" \
|
||||||
" -S SWI Run until specified SWI call before exiting\n" \
|
" -S SWI Run until specified SWI call before exiting\n" \
|
||||||
" -R REGISTER General purpose register to return as exit code\n" \
|
" -R REGISTER General purpose register to return as exit code\n" \
|
||||||
|
|
||||||
|
@ -81,12 +81,12 @@ int main(int argc, char * argv[]) {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mArguments args;
|
struct mArguments args;
|
||||||
bool parsed = parseArguments(&args, argc, argv, &subparser);
|
bool parsed = mArgumentsParse(&args, argc, argv, &subparser, 1);
|
||||||
if (!args.fname) {
|
if (!args.fname) {
|
||||||
parsed = false;
|
parsed = false;
|
||||||
}
|
}
|
||||||
if (!parsed || args.showHelp) {
|
if (!parsed || args.showHelp) {
|
||||||
usage(argv[0], ROM_TEST_USAGE);
|
usage(argv[0], NULL, NULL, &subparser, 1);
|
||||||
return !parsed;
|
return !parsed;
|
||||||
}
|
}
|
||||||
if (args.showVersion) {
|
if (args.showVersion) {
|
||||||
|
@ -99,7 +99,7 @@ int main(int argc, char * argv[]) {
|
||||||
}
|
}
|
||||||
core->init(core);
|
core->init(core);
|
||||||
mCoreInitConfig(core, "romTest");
|
mCoreInitConfig(core, "romTest");
|
||||||
applyArguments(&args, NULL, &core->config);
|
mArgumentsApply(&args, NULL, 0, &core->config);
|
||||||
|
|
||||||
mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "remove");
|
mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "remove");
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ int main(int argc, char * argv[]) {
|
||||||
cleanExit = true;
|
cleanExit = true;
|
||||||
|
|
||||||
loadError:
|
loadError:
|
||||||
freeArguments(&args);
|
mArgumentsDeinit(&args);
|
||||||
mCoreConfigDeinit(&core->config);
|
mCoreConfigDeinit(&core->config);
|
||||||
core->deinit(core);
|
core->deinit(core);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue