diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index 55b21a6892..f20bb86790 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -572,7 +572,6 @@ D41B72431C21015A0080A7B9 /* Sources */ = { isa = PBXGroup; children = ( - D4B8C2A51C41EADF00B006AC /* argparse */, D4EC46D81C26342F0024B507 /* audio */, D4EC46E51C26342F0024B507 /* core */, D4EC46F31C26342F0024B507 /* drawing */, @@ -673,16 +672,6 @@ path = OpenRCT2; sourceTree = ""; }; - D4B8C2A51C41EADF00B006AC /* argparse */ = { - isa = PBXGroup; - children = ( - D4B8C2A61C41EADF00B006AC /* argparse.c */, - D4B8C2A71C41EADF00B006AC /* argparse.h */, - ); - name = argparse; - path = src/argparse; - sourceTree = ""; - }; D4C1EDD01C266A0B00F71B63 /* data */ = { isa = PBXGroup; children = ( @@ -1443,7 +1432,6 @@ D4EC483C1C26342F0024B507 /* finances.c in Sources */, D4EC47F01C26342F0024B507 /* supports.c in Sources */, D4EC47FC1C26342F0024B507 /* title_sequences.c in Sources */, - D4B8C2A81C41EADF00B006AC /* argparse.c in Sources */, D4EC48421C26342F0024B507 /* land.c in Sources */, D4EC48791C26342F0024B507 /* map_animation.c in Sources */, D4EC480D1C26342F0024B507 /* marketing.c in Sources */, diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 50deb39584..4a8b885800 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -19,12 +19,10 @@ - - @@ -192,11 +190,9 @@ - - diff --git a/openrct2.vcxproj.filters b/openrct2.vcxproj.filters index 199085fcb3..fcebcbbe58 100644 --- a/openrct2.vcxproj.filters +++ b/openrct2.vcxproj.filters @@ -56,8 +56,8 @@ {28a808eb-9017-44cc-939b-f828fd1e2e7d} - - {b1a4d0cf-f4a1-4a38-934c-369d4c129a85} + + {4bf369d2-3df8-40c9-a878-f484b0a0afd3} @@ -333,9 +333,6 @@ Source\Drawing - - Source - Source @@ -561,15 +558,24 @@ Source\Core - - Source\argparse + + Source\CommandLine + + + Source\CommandLine + + + Source\CommandLine + + + Source\CommandLine + + + Source\Core + + + Source\Core - - - - - - @@ -725,9 +731,6 @@ Source\Management - - Source - Source @@ -863,11 +866,14 @@ Source\Core - - Source\argparse + + Source\CommandLine + + + Source\Core + + + Source\Core - - - \ No newline at end of file diff --git a/openrct2.vcxproj.user b/openrct2.vcxproj.user index ccf34d4657..4beb5eab50 100644 --- a/openrct2.vcxproj.user +++ b/openrct2.vcxproj.user @@ -1,13 +1,14 @@  - true + false $(TargetDir)\openrct2.exe WindowsLocalDebugger $(TargetDir) - host "C:\Users\Ted\Documents\OpenRCT2\save\Forest Frontiers MP.sv6" + + $(TargetDir) diff --git a/src/argparse/argparse.c b/src/argparse/argparse.c deleted file mode 100644 index e2e14d068f..0000000000 --- a/src/argparse/argparse.c +++ /dev/null @@ -1,324 +0,0 @@ -#include "argparse.h" - -#define OPT_UNSET 1 - -static const char * -prefix_skip(const char *str, const char *prefix) -{ - size_t len = strlen(prefix); - return strncmp(str, prefix, len) ? NULL : str + len; -} - -int -prefix_cmp(const char *str, const char *prefix) -{ - for (;; str++, prefix++) - if (!*prefix) - return 0; - else if (*str != *prefix) - return (unsigned char)*prefix - (unsigned char)*str; -} - -static void -argparse_error(struct argparse *this, const struct argparse_option *opt, - const char *reason) -{ - if (!strncmp(this->argv[0], "--", 2)) { - fprintf(stderr, "error: option `%s` %s\n", opt->long_name, reason); - exit(1); - } else { - fprintf(stderr, "error: option `%c` %s\n", opt->short_name, reason); - exit(1); - } -} - -static int -argparse_getvalue(struct argparse *this, const struct argparse_option *opt, - int flags) -{ - const char *s = NULL; - if (!opt->value) - goto skipped; - switch (opt->type) { - case ARGPARSE_OPT_BOOLEAN: - if (flags & OPT_UNSET) { - *(int *)opt->value = *(int *)opt->value - 1; - } else { - *(int *)opt->value = *(int *)opt->value + 1; - } - if (*(int *)opt->value < 0) { - *(int *)opt->value = 0; - } - break; - case ARGPARSE_OPT_BIT: - if (flags & OPT_UNSET) { - *(int *)opt->value &= ~opt->data; - } else { - *(int *)opt->value |= opt->data; - } - break; - case ARGPARSE_OPT_STRING: - if (this->optvalue) { - *(const char **)opt->value = this->optvalue; - this->optvalue = NULL; - } else if (this->argc > 1) { - this->argc--; - *(const char **)opt->value = *++this->argv; - } else { - argparse_error(this, opt, "requires a value"); - } - break; - case ARGPARSE_OPT_INTEGER: - if (this->optvalue) { - *(int *)opt->value = strtol(this->optvalue, (char **)&s, 0); - this->optvalue = NULL; - } else if (this->argc > 1) { - this->argc--; - *(int *)opt->value = strtol(*++this->argv, (char **)&s, 0); - } else { - argparse_error(this, opt, "requires a value"); - } - if (s[0] != '\0') - argparse_error(this, opt, "expects a numerical value"); - break; - default: - assert(0); - } - -skipped: - if (opt->callback) { - return opt->callback(this, opt); - } - - return 0; -} - -static void -argparse_options_check(const struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - switch (options->type) { - case ARGPARSE_OPT_END: - case ARGPARSE_OPT_BOOLEAN: - case ARGPARSE_OPT_BIT: - case ARGPARSE_OPT_INTEGER: - case ARGPARSE_OPT_STRING: - case ARGPARSE_OPT_GROUP: - continue; - default: - fprintf(stderr, "wrong option type: %d", options->type); - break; - } - } -} - -static int -argparse_short_opt(struct argparse *this, const struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - if (options->short_name == *this->optvalue) { - this->optvalue = this->optvalue[1] ? this->optvalue + 1 : NULL; - return argparse_getvalue(this, options, 0); - } - } - return -2; -} - -static int -argparse_long_opt(struct argparse *this, const struct argparse_option *options) -{ - for (; options->type != ARGPARSE_OPT_END; options++) { - const char *rest; - int opt_flags = 0; - if (!options->long_name) - continue; - - rest = prefix_skip(this->argv[0] + 2, options->long_name); - if (!rest) { - // Negation allowed? - if (options->flags & OPT_NONEG) { - continue; - } - // Only boolean/bit allow negation. - if (options->type != ARGPARSE_OPT_BOOLEAN && options->type != ARGPARSE_OPT_BIT) { - continue; - } - - if (!prefix_cmp(this->argv[0] + 2, "no-")) { - rest = prefix_skip(this->argv[0] + 2 + 3, options->long_name); - if (!rest) - continue; - opt_flags |= OPT_UNSET; - } else { - continue; - } - } - if (*rest) { - if (*rest != '=') - continue; - this->optvalue = rest + 1; - } - return argparse_getvalue(this, options, opt_flags); - } - return -2; -} - -int -argparse_init(struct argparse *this, struct argparse_option *options, - const char *const *usage, int flags) -{ - memset(this, 0, sizeof(*this)); - this->options = options; - this->usage = usage; - this->flags = flags; - return 0; -} - -int -argparse_parse(struct argparse *this, int argc, const char **argv) -{ - this->argc = argc - 1; - this->argv = argv + 1; - this->out = argv; - - argparse_options_check(this->options); - - for (; this->argc; this->argc--, this->argv++) { - const char *arg = this->argv[0]; - if (arg[0] != '-' || !arg[1]) { - if (this->flags & ARGPARSE_STOP_AT_NON_OPTION) { - goto end; - } - // if it's not option or is a single char '-', copy verbatimly - this->out[this->cpidx++] = this->argv[0]; - continue; - } - // short option - if (arg[1] != '-') { - this->optvalue = arg + 1; - switch (argparse_short_opt(this, this->options)) { - case -1: - break; - case -2: - goto unknown; - } - while (this->optvalue) { - switch (argparse_short_opt(this, this->options)) { - case -1: - break; - case -2: - goto unknown; - } - } - continue; - } - // if '--' presents - if (!arg[2]) { - this->argc--; - this->argv++; - break; - } - // long option - switch (argparse_long_opt(this, this->options)) { - case -1: - break; - case -2: - goto unknown; - } - continue; - -unknown: - fprintf(stderr, "error: unknown option `%s`\n", this->argv[0]); - argparse_usage(this); - exit(1); - } - -end: - memmove((void*)(this->out + this->cpidx), - this->argv, - this->argc * sizeof(*this->out)); - this->out[this->cpidx + this->argc] = NULL; - - return this->cpidx + this->argc; -} - -void -argparse_usage(struct argparse *this) -{ - fprintf(stdout, "Usage: %s\n", *this->usage++); - while (*this->usage && **this->usage) - fprintf(stdout, " or: %s\n", *this->usage++); - fputc('\n', stdout); - - const struct argparse_option *options; - - // figure out best width - size_t usage_opts_width = 0; - size_t len; - options = this->options; - for (; options->type != ARGPARSE_OPT_END; options++) { - len = 0; - if ((options)->short_name) { - len += 2; - } - if ((options)->short_name && (options)->long_name) { - len += 2; // separator ", " - } - if ((options)->long_name) { - len += strlen((options)->long_name) + 2; - } - if (options->type == ARGPARSE_OPT_INTEGER) { - len += strlen("="); - } else if (options->type == ARGPARSE_OPT_STRING) { - len += strlen("="); - } - len = ((len + 3) / 4) * 4; - if (usage_opts_width < len) { - usage_opts_width = len; - } - } - usage_opts_width += 4; // 4 spaces prefix - - options = this->options; - for (; options->type != ARGPARSE_OPT_END; options++) { - size_t pos = 0; - int pad = 0; - if (options->type == ARGPARSE_OPT_GROUP) { - fputc('\n', stdout); - pos += fprintf(stdout, "%s", options->help); - fputc('\n', stdout); - continue; - } - pos = fprintf(stdout, " "); - if (options->short_name) { - pos += fprintf(stdout, "-%c", options->short_name); - } - if (options->long_name && options->short_name) { - pos += fprintf(stdout, ", "); - } - if (options->long_name) { - pos += fprintf(stdout, "--%s", options->long_name); - } - if (options->type == ARGPARSE_OPT_INTEGER) { - pos += fprintf(stdout, "="); - } else if (options->type == ARGPARSE_OPT_STRING) { - pos += fprintf(stdout, "="); - } - if (pos <= usage_opts_width) { - pad = usage_opts_width - pos; - } else { - fputc('\n', stdout); - pad = usage_opts_width; - } - fprintf(stdout, "%*s%s\n", pad + 2, "", options->help); - } -} - -int -argparse_help_cb(struct argparse *this, const struct argparse_option *option) -{ - (void)option; - argparse_usage(this); - exit(0); - return 0; -} diff --git a/src/argparse/argparse.h b/src/argparse/argparse.h deleted file mode 100644 index 350ee58df4..0000000000 --- a/src/argparse/argparse.h +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef ARGPARSE_H -#define ARGPARSE_H -/** - * Command-line arguments parsing library. - * - * This module is inspired by parse-options.c (git) and python's argparse - * module. - * - * Arguments parsing is common task in cli program, but traditional `getopt` - * libraries are not easy to use. This library provides high-level arguments - * parsing solutions. - * - * The program defines what arguments it requires, and `argparse` will figure - * out how to parse those out of `argc` and `argv`, it also automatically - * generates help and usage messages and issues errors when users give the - * program invalid arguments. - * - * Reserved namespaces: - * argparse - * OPT - * Author: Yecheng Fu - */ - -#include -#include -#include -#include -#include -#include - -struct argparse; -struct argparse_option; - -typedef int argparse_callback(struct argparse *this, - const struct argparse_option *option); - -enum argparse_flag { - ARGPARSE_STOP_AT_NON_OPTION = 1, -}; - -enum argparse_option_type { - /* special */ - ARGPARSE_OPT_END, - ARGPARSE_OPT_GROUP, - /* options with no arguments */ - ARGPARSE_OPT_BOOLEAN, - ARGPARSE_OPT_BIT, - /* options with arguments (optional or required) */ - ARGPARSE_OPT_INTEGER, - ARGPARSE_OPT_STRING, -}; - -enum argparse_option_flags { - OPT_NONEG = 1, /* Negation disabled. */ -}; - -/* - * Argparse option struct. - * - * `type`: - * holds the type of the option, you must have an ARGPARSE_OPT_END last in your - * array. - * - * `short_name`: - * the character to use as a short option name, '\0' if none. - * - * `long_name`: - * the long option name, without the leading dash, NULL if none. - * - * `value`: - * stores pointer to the value to be filled. - * - * `help`: - * the short help message associated to what the option does. - * Must never be NULL (except for ARGPARSE_OPT_END). - * - * `callback`: - * function is called when corresponding argument is parsed. - * - * `data`: - * associated data. Callbacks can use it like they want. - * - * `flags`: - * option flags. - * - */ -struct argparse_option { - enum argparse_option_type type; - const char short_name; - const char *long_name; - void *value; - const char *help; - argparse_callback *callback; - intptr_t data; - int flags; -}; - -/* - * argpparse - */ -struct argparse { - // user supplied - const struct argparse_option *options; - const char *const *usage; - int flags; - // internal context - int argc; - const char **argv; - const char **out; - int cpidx; - const char *optvalue; // current option value -}; - -// builtin callbacks -int argparse_help_cb(struct argparse *this, - const struct argparse_option *option); - -// builtin option macros -#define OPT_END() { ARGPARSE_OPT_END } -#define OPT_BOOLEAN(...) { ARGPARSE_OPT_BOOLEAN, __VA_ARGS__ } -#define OPT_BIT(...) { ARGPARSE_OPT_BIT, __VA_ARGS__ } -#define OPT_INTEGER(...) { ARGPARSE_OPT_INTEGER, __VA_ARGS__ } -#define OPT_STRING(...) { ARGPARSE_OPT_STRING, __VA_ARGS__ } -#define OPT_GROUP(h) { ARGPARSE_OPT_GROUP, 0, NULL, NULL, h, NULL } -#define OPT_HELP() OPT_BOOLEAN('h', "help", NULL, "show this help message and exit", argparse_help_cb) - -int argparse_init(struct argparse *this, struct argparse_option *options, - const char *const *usage, int flags); -int argparse_parse(struct argparse *this, int argc, const char **argv); -void argparse_usage(struct argparse *this); - -#endif diff --git a/src/cmdline.c b/src/cmdline.c deleted file mode 100644 index 194a95b475..0000000000 --- a/src/cmdline.c +++ /dev/null @@ -1,275 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014 Ted John - * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * - * This file is part of OpenRCT2. - * - * OpenRCT2 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ - -#include -#include "argparse/argparse.h" -#include "addresses.h" -#include "cmdline.h" -#include "interface/screenshot.h" -#include "network/network.h" -#include "openrct2.h" -#include "platform/platform.h" -#include "util/util.h" - -#ifdef ENABLE_TESTS - #include "../test/tests.h" -#else - static int cmdline_for_test_error(const char **argv, int argc) - { - printf("OpenRCT2 has not been built with the test suite.\n"); - return -1; - } -#endif - -typedef struct tm tm_t; -typedef struct argparse_option argparse_option_t; -typedef struct argparse argparse_t; - -typedef int (*cmdline_action)(const char **argv, int argc); - -int gExitCode = 0; -int sprite_mode; - -static void print_launch_information(); -static void print_version(); -static int cmdline_call_action(const char **argv, int argc); - -static const char *const usage[] = { - "openrct2 [options] []", - "openrct2 [options]", - "openrct2 intro [options]", - "openrct2 edit [path] [options]", - NULL -}; - -/** - * A shared entry point to OpenRCT2. The command lines must be parsed before any further action is done. Invalid command lines - * will then terminate before any initialisation has even been done. - * @returns 1 if the game should run, otherwise 0. - */ -int cmdline_run_old(const char **argv, int argc) -{ - // - int version = 0, headless = 0, verbose = 0, width = 0, height = 0, port = 0; - char *server = NULL; - char *userDataPath = NULL; - char *openrctDataPath = NULL; - - argparse_option_t options[] = { - OPT_HELP(), - OPT_BOOLEAN('v', "version", &version, "show version information and exit"), - OPT_BOOLEAN(0, "headless", &headless, "run OpenRCT2 headless"), - OPT_BOOLEAN(0, "verbose", &verbose, "log verbose messages"), - OPT_INTEGER('m', "mode", &sprite_mode, "the type of sprite conversion. 0 = default, 1 = simple closest pixel match, 2 = dithering"), - OPT_STRING(0, "server", &server, "server to connect to"), - OPT_INTEGER(0, "port", &port, "Port to use. If used with --server, it will connect to specified server at this port, otherwise it will start the server"), - OPT_STRING(0, "user-data-path", &userDataPath, "path to the user data directory (containing config.ini)"), - OPT_STRING(0, "openrct-data-path", &openrctDataPath, "path to the OpenRCT2 data directory (containing languages)"), - OPT_END() - }; - - argparse_t argparse; - argparse_init(&argparse, options, usage, 0); - size_t argvsize = sizeof(char**) * argc; - /** - * argparse_parse ends up inadvertently mutating the argv variable, setting - * a null pointer in the array. Because of this, AppKit in OS X 10.10 will - * dereference it, causing a segmentation fault. - */ - char** mutableArgv = malloc(argvsize); - -#ifdef __APPLE__ - /** - * Fixes problems with the default settings in the Xcode debugger - * with it adding the option "-NSDocumentRevisionsDebugMode" - */ - int k=0; - for (int i=0; i < argc; ++i) - if (strcmp(argv[k], "-NSDocumentRevisionsDebugMode") != 0 && strncmp(argv[k], "-psn_", 5) != 0) - mutableArgv[k++] = (char *) argv[i]; - argc = k; -#else - memcpy(mutableArgv,argv,argvsize); -#endif - - argc = argparse_parse(&argparse, argc, (const char **)mutableArgv); - - if (version) { - print_version(); - free(mutableArgv); - return 0; - } - - if (headless) - gOpenRCT2Headless = true; - - if (verbose) - _log_levels[DIAGNOSTIC_LEVEL_VERBOSE] = 1; - - if (userDataPath != NULL) { - safe_strncpy(gCustomUserDataPath, userDataPath, sizeof(gCustomUserDataPath)); - } - - if (openrctDataPath != NULL) { - safe_strncpy(gCustomOpenrctDataPath, openrctDataPath, sizeof(gCustomOpenrctDataPath)); - } - -#ifndef DISABLE_NETWORK - if (port != 0) { - gNetworkStart = NETWORK_MODE_SERVER; - gNetworkStartPort = port; - } - - if (server != NULL) { - gNetworkStart = NETWORK_MODE_CLIENT; - safe_strncpy(gNetworkStartHost, server, sizeof(gNetworkStartHost)); - } -#endif // DISABLE_NETWORK - - if (argc != 0) { - // see comment next to cmdline_call_action for expected return codes - gExitCode = cmdline_call_action((const char**)mutableArgv, argc); - free(mutableArgv); - if (gExitCode < 0) { - // action failed, don't change exit code - // and don't start the game - return 0; - } else if (gExitCode > 0) { - // action successful, but don't start the game - // change exit code to success - gExitCode = 0; - return 0; - } - // start the game, so far exit code means success. - } else { - free(mutableArgv); - } - - // Headless mode requires a park to open - if (gOpenRCT2Headless) { - if (str_is_null_or_empty(gOpenRCT2StartupActionPath)) { - printf("You must specify a park to open in headless mode.\n"); - gExitCode = -1; - return 0; - } - } - - if (verbose) { - print_launch_information(); - } - return 1; -} - -static void print_launch_information() -{ - char buffer[256]; - time_t timer; - tm_t* tmInfo; - - // Print name and version information - openrct2_write_full_version_info(buffer, sizeof(buffer)); - printf("%s\n", buffer); - printf("%s (%s)\n", OPENRCT2_PLATFORM, OPENRCT2_ARCHITECTURE); - printf("@ %s\n\n", OPENRCT2_TIMESTAMP); - - // Print current time - time(&timer); - tmInfo = localtime(&timer); - strftime(buffer, sizeof(buffer), "%Y/%m/%d %H:%M:%S", tmInfo); - printf("VERBOSE: time is %s\n", buffer); - - // TODO Print other potential information (e.g. user, hardware) -} - -static void print_version() -{ - char buffer[256]; - openrct2_write_full_version_info(buffer, sizeof(buffer)); - printf("%s\n", buffer); - printf("%s (%s)\n", OPENRCT2_PLATFORM, OPENRCT2_ARCHITECTURE); -} - -static int cmdline_for_intro(const char **argv, int argc) -{ - gOpenRCT2StartupAction = STARTUP_ACTION_INTRO; - return 0; -} - -static int cmdline_for_edit(const char **argv, int argc) -{ - gOpenRCT2StartupAction = STARTUP_ACTION_EDIT; - if (argc >= 1) - safe_strncpy(gOpenRCT2StartupActionPath, argv[0], 512); - - return 0; -} - -static int cmdline_for_none(const char **argv, int argc) -{ - assert(argc >= 1); - - if (platform_file_exists(argv[0])) { - gOpenRCT2StartupAction = STARTUP_ACTION_OPEN; - safe_strncpy(gOpenRCT2StartupActionPath, argv[0], 512); - return 0; - } else { - fprintf(stderr, "error: %s does not exist\n", argv[0]); - return -1; - } -} - -// see comment next to cmdline_call_action for expected return codes -struct { const char *firstArg; cmdline_action action; } cmdline_table[] = { - { "intro", cmdline_for_intro }, - { "edit", cmdline_for_edit }, - { "sprite", cmdline_for_sprite }, - { "screenshot", cmdline_for_screenshot }, - -#ifdef ENABLE_TESTS - { "test", cmdline_for_test }, -#else - { "test", cmdline_for_test_error }, -#endif -}; - -/** - * This function delegates starting the game to different handlers, if found. - * - * Three cases of return values are supported: - * - result < 0 means failure, will exit with error code - * This case is useful when user provided wrong arguments or the requested - * action failed - * - result > 0 means success, won't start game, will exit program with success code - * This case is useful when you want to do some batch action and signalize - * success to the user. - * - result == 0 means success, will launch the game. - * This is default when ran with no arguments. - */ -static int cmdline_call_action(const char **argv, int argc) -{ - for (int i = 0; i < countof(cmdline_table); i++) { - if (_stricmp(cmdline_table[i].firstArg, argv[0]) != 0) - continue; - - return cmdline_table[i].action(argv + 1, argc - 1); - } - - return cmdline_for_none(argv, argc); -} diff --git a/src/cmdline.h b/src/cmdline.h deleted file mode 100644 index dd11f23549..0000000000 --- a/src/cmdline.h +++ /dev/null @@ -1,34 +0,0 @@ -/***************************************************************************** - * Copyright (c) 2014 Ted John - * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * - * This file is part of OpenRCT2. - * - * OpenRCT2 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *****************************************************************************/ - -#ifndef _CMDLINE_H_ -#define _CMDLINE_H_ - -#include "common.h" - -/** The exit code for OpenRCT2 when it exits. */ -extern int gExitCode; - -extern int sprite_mode; - -int cmdline_run(const char **argv, int argc); -int cmdline_for_sprite(const char **argv, int argc); - -#endif diff --git a/src/cmdline/CommandLine.cpp b/src/cmdline/CommandLine.cpp index 0a368f20d7..b2d0f6a28b 100644 --- a/src/cmdline/CommandLine.cpp +++ b/src/cmdline/CommandLine.cpp @@ -105,6 +105,8 @@ namespace CommandLine static bool ParseLongOption(const CommandLineOptionDefinition * options, CommandLineArgEnumerator * argEnumerator, const char * argument); static bool ParseOptionValue(const CommandLineOptionDefinition * option, const char * valueString); + static bool HandleSpecialArgument(const char * argument); + void PrintHelp(bool allCommands) { PrintHelpFor(RootCommands); @@ -313,6 +315,7 @@ namespace CommandLine } } + argEnumerator->Backtrack(); return fallback; } @@ -323,6 +326,11 @@ namespace CommandLine const char * argument; while (argEnumerator->TryPopString(&argument)) { + if (HandleSpecialArgument(argument)) + { + continue; + } + if (argument[0] == '-') { if (argument[1] == '-') @@ -500,6 +508,22 @@ namespace CommandLine } } + static bool HandleSpecialArgument(const char * argument) + { +#if defined(__APPLE__) && defined(__MACH__) + if (String::Equals(argument, "-NSDocumentRevisionsDebugMode")) + { + return true; + } + if (String::StartsWith("-psn_")) + { + return true; + } +#endif + return false; + } + + const CommandLineOptionDefinition * FindOption(const CommandLineOptionDefinition * options, char shortName) { for (const CommandLineOptionDefinition * option = options; option->Type != 255; option++) @@ -543,7 +567,7 @@ extern "C" return EXITCODE_FAIL; } } - if (command == CommandLine::RootCommands || command->Func == nullptr) + if (command == CommandLine::RootCommands && command->Func == nullptr) { return CommandLine::HandleCommandDefault(); } diff --git a/src/cmdline/CommandLine.hpp b/src/cmdline/CommandLine.hpp index c6f16f082b..3dc1f7a156 100644 --- a/src/cmdline/CommandLine.hpp +++ b/src/cmdline/CommandLine.hpp @@ -16,8 +16,9 @@ private: uint16 _index; public: - uint16 GetCount() const { return _count; } - uint16 GetIndex() const { return _index; } + const char * const * GetArguments() const { return _arguments; } + uint16 GetCount() const { return _count; } + uint16 GetIndex() const { return _index; } CommandLineArgEnumerator(const char * const * arguments, int count); diff --git a/src/cmdline/ScreenshotCommands.cpp b/src/cmdline/ScreenshotCommands.cpp index 2dc6a12c42..9b49e7e946 100644 --- a/src/cmdline/ScreenshotCommands.cpp +++ b/src/cmdline/ScreenshotCommands.cpp @@ -1,9 +1,27 @@ +extern "C" +{ + #include "../interface/screenshot.h" +} + #include "CommandLine.hpp" +static exitcode_t HandleScreenshot(CommandLineArgEnumerator *argEnumerator); + const CommandLineCommand CommandLine::ScreenshotCommands[] { // Main commands - DefineCommand("", " [ ]", nullptr, nullptr), - DefineCommand("", " giant ", nullptr, nullptr), + DefineCommand("", " [ ]", nullptr, HandleScreenshot), + DefineCommand("", " giant ", nullptr, HandleScreenshot), CommandTableEnd }; + +static exitcode_t HandleScreenshot(CommandLineArgEnumerator *argEnumerator) +{ + const char * * argv = (const char * *)argEnumerator->GetArguments() + argEnumerator->GetIndex() - 1; + int argc = argEnumerator->GetCount() - argEnumerator->GetIndex() + 1; + int result = cmdline_for_screenshot(argv, argc); + if (result < 0) { + return EXITCODE_FAIL; + } + return EXITCODE_OK; +} diff --git a/src/cmdline/SpriteCommands.cpp b/src/cmdline/SpriteCommands.cpp index c7f62dd410..03d68ae7e9 100644 --- a/src/cmdline/SpriteCommands.cpp +++ b/src/cmdline/SpriteCommands.cpp @@ -1,25 +1,48 @@ +#include "../core/Memory.hpp" +#include "../core/String.hpp" #include "CommandLine.hpp" +#define SZ_DEFAULT "default" +#define SZ_CLOSEST "closest" +#define SZ_DITHERING "dithering" + +extern "C" +{ + int gSpriteMode = 0; + + int cmdline_for_sprite(const char **argv, int argc); +} + static const char * _mode; static const CommandLineOptionDefinition SpriteOptions[] { - { CMDLINE_TYPE_STRING, &_mode, 'm', "mode", "the type of sprite conversion " }, + { CMDLINE_TYPE_STRING, &_mode, 'm', "mode", "the type of sprite conversion <" SZ_DEFAULT "|" SZ_CLOSEST "|" SZ_DITHERING ">" }, OptionTableEnd }; -static exitcode_t Handle(CommandLineArgEnumerator *argEnumerator); +static exitcode_t HandleSprite(CommandLineArgEnumerator *argEnumerator); const CommandLineCommand CommandLine::SpriteCommands[] { // Main commands - DefineCommand("details", " [idx]", SpriteOptions, Handle), - DefineCommand("export", " ", SpriteOptions, Handle), - DefineCommand("build", " [silent]", SpriteOptions, Handle), + DefineCommand("details", " [idx]", SpriteOptions, HandleSprite), + DefineCommand("export", " ", SpriteOptions, HandleSprite), + DefineCommand("build", " [silent]", SpriteOptions, HandleSprite), CommandTableEnd }; -static exitcode_t Handle(CommandLineArgEnumerator *argEnumerator) +static exitcode_t HandleSprite(CommandLineArgEnumerator *argEnumerator) { + if (String::Equals(_mode, SZ_CLOSEST, true)) gSpriteMode = 1; + else if (String::Equals(_mode, SZ_DITHERING, true)) gSpriteMode = 2; + Memory::Free(_mode); + + const char * * argv = (const char * *)argEnumerator->GetArguments() + argEnumerator->GetIndex() - 1; + int argc = argEnumerator->GetCount() - argEnumerator->GetIndex() + 1; + int result = cmdline_for_sprite(argv, argc); + if (result < 0) { + return EXITCODE_FAIL; + } return EXITCODE_OK; } diff --git a/src/cmdline_sprite.c b/src/cmdline_sprite.c index c7fc2eec5c..73f5a4ff09 100644 --- a/src/cmdline_sprite.c +++ b/src/cmdline_sprite.c @@ -18,7 +18,6 @@ * along with this program. If not, see . *****************************************************************************/ -#include "cmdline.h" #include "drawing/drawing.h" #include "image_io.h" #include "openrct2.h" @@ -29,6 +28,8 @@ #define MODE_CLOSEST 1 #define MODE_DITHERING 2 +extern int gSpriteMode; + typedef struct { uint32 num_entries; uint32 total_size; @@ -554,7 +555,7 @@ int cmdline_for_sprite(const char **argv, int argc) rct_g1_element spriteElement; uint8 *buffer; int bufferLength; - if (!sprite_file_import(imagePath, &spriteElement, &buffer, &bufferLength, sprite_mode)) + if (!sprite_file_import(imagePath, &spriteElement, &buffer, &bufferLength, gSpriteMode)) return -1; if (!sprite_file_open(spriteFilePath)) { @@ -613,7 +614,7 @@ int cmdline_for_sprite(const char **argv, int argc) rct_g1_element spriteElement; uint8 *buffer; int bufferLength; - if (!sprite_file_import(imagePath, &spriteElement, &buffer, &bufferLength, sprite_mode)) { + if (!sprite_file_import(imagePath, &spriteElement, &buffer, &bufferLength, gSpriteMode)) { fprintf(stderr, "Could not import image file: %s\nCanceling\n", imagePath); return -1; } diff --git a/src/core/String.cpp b/src/core/String.cpp index 3c63bc3f9f..03e50482e1 100644 --- a/src/core/String.cpp +++ b/src/core/String.cpp @@ -25,6 +25,32 @@ namespace String } } + bool StartsWith(const utf8 * str, const utf8 * match, bool ignoreCase) + { + if (ignoreCase) + { + while (*str != '\0' && *match != '\0') + { + if (tolower(*str++) != tolower(*match++)) + { + return false; + } + } + return true; + } + else + { + while (*str != '\0' && *match != '\0') + { + if (*str++ != *match++) + { + return false; + } + } + return true; + } + } + size_t LengthOf(const utf8 * str) { return utf8_length(str); diff --git a/src/core/String.hpp b/src/core/String.hpp index ded9ec6f57..98313ec1ce 100644 --- a/src/core/String.hpp +++ b/src/core/String.hpp @@ -8,6 +8,7 @@ extern "C" namespace String { bool Equals(const utf8 * a, const utf8 * b, bool ignoreCase = false); + bool StartsWith(const utf8 * str, const utf8 * match, bool ignoreCase = false); size_t LengthOf(const utf8 * str); size_t SizeOf(const utf8 * str); utf8 * Set(utf8 * buffer, size_t bufferSize, const utf8 * src); diff --git a/src/openrct2.c b/src/openrct2.c index 5bc9bc39fc..7ffb262aa2 100644 --- a/src/openrct2.c +++ b/src/openrct2.c @@ -21,7 +21,6 @@ #include "addresses.h" #include "audio/audio.h" #include "audio/mixer.h" -#include "cmdline.h" #include "config.h" #include "editor.h" #include "game.h" @@ -49,6 +48,8 @@ #include #endif // defined(__unix__) +int gExitCode; + int gOpenRCT2StartupAction = STARTUP_ACTION_TITLE; utf8 gOpenRCT2StartupActionPath[512] = { 0 }; utf8 gExePath[MAX_PATH]; diff --git a/src/openrct2.h b/src/openrct2.h index 7683857f1c..e044e848f9 100644 --- a/src/openrct2.h +++ b/src/openrct2.h @@ -31,6 +31,9 @@ enum { STARTUP_ACTION_EDIT }; +/** The exit code for OpenRCT2 when it exits. */ +extern int gExitCode; + extern int gOpenRCT2StartupAction; extern utf8 gOpenRCT2StartupActionPath[512]; extern utf8 gExePath[MAX_PATH]; @@ -52,4 +55,6 @@ void openrct2_dispose(); void openrct2_finish(); void openrct2_reset_object_tween_locations(); +int cmdline_run(const char **argv, int argc); + #endif diff --git a/src/platform/windows.c b/src/platform/windows.c index eb8e83f3f4..be7967a40c 100644 --- a/src/platform/windows.c +++ b/src/platform/windows.c @@ -26,7 +26,6 @@ #include #include #include "../addresses.h" -#include "../cmdline.h" #include "../openrct2.h" #include "../localisation/language.h" #include "../localisation/currency.h"