From c2cc95b83041173bfd436d4b2473bbf28597a669 Mon Sep 17 00:00:00 2001 From: Ingo Ruhnke Date: Mon, 11 Aug 2014 23:34:45 +0200 Subject: [PATCH] Moved argument parsing into CommandLineArguments --- src/supertux/command_line_arguments.cpp | 300 ++++++++++++++++++++++++++++++++ src/supertux/command_line_arguments.hpp | 88 ++++++++++ src/supertux/main.cpp | 249 ++++---------------------- src/supertux/main.hpp | 9 +- 4 files changed, 431 insertions(+), 215 deletions(-) create mode 100644 src/supertux/command_line_arguments.cpp create mode 100644 src/supertux/command_line_arguments.hpp diff --git a/src/supertux/command_line_arguments.cpp b/src/supertux/command_line_arguments.cpp new file mode 100644 index 000000000..50d16ca95 --- /dev/null +++ b/src/supertux/command_line_arguments.cpp @@ -0,0 +1,300 @@ +// SuperTux +// Copyright (C) 2014 Ingo Ruhnke +// +// This program 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 "supertux/command_line_arguments.hpp" + +#include +#include +#include + +#include "supertux/gameconfig.hpp" +#include "supertux/main.hpp" +#include "util/gettext.hpp" +#include "util/log.hpp" +#include "version.h" + +CommandLineArguments::CommandLineArguments() : + m_action(NO_ACTION), + fullscreen_size(), + fullscreen_refresh_rate(), + window_size(), + aspect_size(), + use_fullscreen(), + video(), + show_fps(), + sound_enabled(), + music_enabled(), + console_enabled(), + start_level(), + enable_script_debugger(), + start_demo(), + record_demo() +{ +} + +CommandLineArguments::~CommandLineArguments() +{ +} + +void +CommandLineArguments::print_datadir() +{ + // Print the datadir searchpath to stdout, one path per + // line. Then exit. Intended for use by the supertux-editor. + char **sp; + size_t sp_index; + sp = PHYSFS_getSearchPath(); + if (sp) + for (sp_index = 0; sp[sp_index]; sp_index++) + std::cout << sp[sp_index] << std::endl; + PHYSFS_freeList(sp); +} + +void +CommandLineArguments::print_help(const char* argv0) +{ + std::string default_user_data_dir = + std::string(PHYSFS_getUserDir()) + WRITEDIR_NAME; + + std::cerr << boost::format(_( + "\n" + "Usage: %s [OPTIONS] [LEVELFILE]\n\n" + "CommandLineArguments:\n" + " -f, --fullscreen Run in fullscreen mode\n" + " -w, --window Run in window mode\n" + " -g, --geometry WIDTHxHEIGHT Run SuperTux in given resolution\n" + " -a, --aspect WIDTH:HEIGHT Run SuperTux with given aspect ratio\n" + " -d, --default Reset video settings to default values\n" + " --renderer RENDERER Use sdl, opengl, or auto to render\n" + " --disable-sound Disable sound effects\n" + " --disable-music Disable music\n" + " -h, --help Show this help message and quit\n" + " -v, --version Show SuperTux version and quit\n" + " --console Enable ingame scripting console\n" + " --noconsole Disable ingame scripting console\n" + " --show-fps Display framerate in levels\n" + " --no-show-fps Do not display framerate in levels\n" + " --record-demo FILE LEVEL Record a demo to FILE\n" + " --play-demo FILE LEVEL Play a recorded demo\n" + " -s, --debug-scripts Enable script debugger.\n" + " --print-datadir Print supertux's primary data directory.\n" + "\n" + "Environment variables:\n" + " SUPERTUX2_USER_DIR Directory for user data (savegames, etc.);\n" + " default %s\n" + "\n" + )) + % argv0 % default_user_data_dir + << std::flush; +} + +void +CommandLineArguments::print_version() +{ + std::cout << PACKAGE_NAME << " " << PACKAGE_VERSION << std::endl; +} + +void +CommandLineArguments::parse_args(int argc, char** argv) +{ + for(int i = 1; i < argc; ++i) + { + std::string arg = argv[i]; + + if (arg == "--version" || arg == "-v") + { + m_action = PRINT_VERSION; + + } + else if (arg == "--help" || arg == "-h") + { + m_action = PRINT_HELP; + } + else if (arg == "--print-datadir") + { + m_action = PRINT_DATADIR; + } + else if (arg == "--fullscreen" || arg == "-f") + { + use_fullscreen = true; + } + else if (arg == "--default" || arg == "-d") + { + use_fullscreen = false; + + window_size = Size(800, 600); + fullscreen_size = Size(800, 600); + fullscreen_refresh_rate = 0; + aspect_size = Size(0, 0); // auto detect + } + else if (arg == "--window" || arg == "-w") + { + use_fullscreen = false; + } + else if (arg == "--geometry" || arg == "-g") + { + i += 1; + if (i >= argc) + { + throw std::runtime_error("Need to specify a size (WIDTHxHEIGHT) for geometry argument"); + } + else + { + int width, height; + if (sscanf(argv[i], "%dx%d", &width, &height) != 2) + { + throw std::runtime_error("Invalid geometry spec, should be WIDTHxHEIGHT"); + } + else + { + window_size = Size(width, height); + fullscreen_size = Size(width, height); + fullscreen_refresh_rate = 0; + } + } + } + else if (arg == "--aspect" || arg == "-a") + { + i += 1; + if (i >= argc) + { + throw std::runtime_error("Need to specify a ratio (WIDTH:HEIGHT) for aspect ratio"); + } + else + { + int aspect_width = 0; + int aspect_height = 0; + if (strcmp(argv[i], "auto") == 0) + { + aspect_width = 0; + aspect_height = 0; + } + else if (sscanf(argv[i], "%d:%d", &aspect_width, &aspect_height) != 2) + { + throw std::runtime_error("Invalid aspect spec, should be WIDTH:HEIGHT or auto"); + } + else + { + float aspect_ratio = static_cast(aspect_width) / static_cast(aspect_height); + + // use aspect ratio to calculate logical resolution + if (aspect_ratio > 1) { + aspect_size = Size(static_cast(600 * aspect_ratio + 0.5), + 600); + } else { + aspect_size = Size(600, + static_cast(600 * 1/aspect_ratio + 0.5)); + } + } + } + } + else if (arg == "--renderer") + { + i += 1; + if (i >= argc) + { + throw std::runtime_error("Need to specify a renderer for renderer argument"); + } + else + { + video = VideoSystem::get_video_system(argv[i]); + } + } + else if (arg == "--show-fps") + { + show_fps = true; + } + else if (arg == "--no-show-fps") + { + show_fps = false; + } + else if (arg == "--console") + { + console_enabled = true; + } + else if (arg == "--noconsole") + { + console_enabled = false; + } + else if (arg == "--disable-sound" || arg == "--disable-sfx") + { + sound_enabled = false; + } + else if (arg == "--disable-music") + { + music_enabled = false; + } + else if (arg == "--play-demo") + { + if (i+1 >= argc) + { + throw std::runtime_error("Need to specify a demo filename"); + } + else + { + start_demo = argv[++i]; + } + } + else if (arg == "--record-demo") + { + if (i+1 >= argc) + { + throw std::runtime_error("Need to specify a demo filename"); + } + else + { + record_demo = argv[++i]; + } + } + else if (arg == "--debug-scripts" || arg == "-s") + { + enable_script_debugger = true; + } + else if (arg[0] != '-') + { + start_level = arg; + } + else + { + throw std::runtime_error((boost::format("Unknown option '%1%''. Use --help to see a list of options") % arg).str()); + } + } +} + +void +CommandLineArguments::merge_into(Config& config) +{ +#define merge_option(x) if (x) { config.x = *x; } + + merge_option(fullscreen_size); + merge_option(fullscreen_refresh_rate); + merge_option(window_size); + merge_option(aspect_size); + merge_option(use_fullscreen); + merge_option(video); + merge_option(show_fps); + merge_option(sound_enabled); + merge_option(music_enabled); + merge_option(console_enabled); + merge_option(start_level); + merge_option(enable_script_debugger); + merge_option(start_demo); + merge_option(record_demo); + +#undef merge_option +} + +/* EOF */ diff --git a/src/supertux/command_line_arguments.hpp b/src/supertux/command_line_arguments.hpp new file mode 100644 index 000000000..903278613 --- /dev/null +++ b/src/supertux/command_line_arguments.hpp @@ -0,0 +1,88 @@ +// SuperTux +// Copyright (C) 2014 Ingo Ruhnke +// +// This program 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 HEADER_SUPERTUX_SUPERTUX_OPTIONS_HPP +#define HEADER_SUPERTUX_SUPERTUX_OPTIONS_HPP + +#include + +#include "math/size.hpp" +#include "video/video_systems.hpp" + +class Config; + +/** Command line argument parsing */ +class CommandLineArguments +{ +public: + enum Action + { + NO_ACTION, + PRINT_VERSION, + PRINT_HELP, + PRINT_DATADIR + }; + +private: + Action m_action; + +public: + boost::optional fullscreen_size; + boost::optional fullscreen_refresh_rate; + boost::optional window_size; + boost::optional aspect_size; + + // boost::optional magnification; + + boost::optional use_fullscreen; + boost::optional video; + // boost::optional try_vsync; + boost::optional show_fps; + boost::optional sound_enabled; + boost::optional music_enabled; + boost::optional console_enabled; + + // boost::optional random_seed; + + boost::optional start_level; + boost::optional enable_script_debugger; + boost::optional start_demo; + boost::optional record_demo; + + // boost::optional locale; + +public: + CommandLineArguments(); + ~CommandLineArguments(); + + Action get_action() const { return m_action; } + + void parse_args(int argc, char** argv); + + void print_help(const char* argv0); + void print_version(); + void print_datadir(); + + void merge_into(Config& config); + +private: + CommandLineArguments(const CommandLineArguments&) = delete; + CommandLineArguments& operator=(const CommandLineArguments&) = delete; +}; + +#endif + +/* EOF */ diff --git a/src/supertux/main.cpp b/src/supertux/main.cpp index eee10dc8f..c231938f3 100644 --- a/src/supertux/main.cpp +++ b/src/supertux/main.cpp @@ -41,6 +41,7 @@ extern "C" { #include "supertux/game_manager.hpp" #include "supertux/gameconfig.hpp" #include "supertux/globals.hpp" +#include "supertux/command_line_arguments.hpp" #include "supertux/player_status.hpp" #include "supertux/resources.hpp" #include "supertux/screen_fade.hpp" @@ -55,12 +56,6 @@ extern "C" { namespace { DrawingContext *context_pointer; } -#ifdef _WIN32 -# define WRITEDIR_NAME PACKAGE_NAME -#else -# define WRITEDIR_NAME "." PACKAGE_NAME -#endif - void Main::init_config() { @@ -192,205 +187,6 @@ Main::init_physfs(const char* argv0) } void -Main::print_usage(const char* argv0) -{ - std::string default_user_data_dir = - std::string(PHYSFS_getUserDir()) + WRITEDIR_NAME; - - std::cerr << boost::format(_( - "\n" - "Usage: %s [OPTIONS] [LEVELFILE]\n\n" - "Options:\n" - " -f, --fullscreen Run in fullscreen mode\n" - " -w, --window Run in window mode\n" - " -g, --geometry WIDTHxHEIGHT Run SuperTux in given resolution\n" - " -a, --aspect WIDTH:HEIGHT Run SuperTux with given aspect ratio\n" - " -d, --default Reset video settings to default values\n" - " --renderer RENDERER Use sdl, opengl, or auto to render\n" - " --disable-sfx Disable sound effects\n" - " --disable-music Disable music\n" - " -h, --help Show this help message and quit\n" - " -v, --version Show SuperTux version and quit\n" - " --console Enable ingame scripting console\n" - " --noconsole Disable ingame scripting console\n" - " --show-fps Display framerate in levels\n" - " --no-show-fps Do not display framerate in levels\n" - " --record-demo FILE LEVEL Record a demo to FILE\n" - " --play-demo FILE LEVEL Play a recorded demo\n" - " -s, --debug-scripts Enable script debugger.\n" - " --print-datadir Print supertux's primary data directory.\n" - "\n" - "Environment variables:\n" - " SUPERTUX2_USER_DIR Directory for user data (savegames, etc.);\n" - " default %s\n" - "\n" - )) - % argv0 % default_user_data_dir - << std::flush; -} - -/** - * Options that should be evaluated prior to any initializations at all go here - */ -bool -Main::pre_parse_commandline(int argc, char** argv) -{ - for(int i = 1; i < argc; ++i) { - std::string arg = argv[i]; - - if(arg == "--version" || arg == "-v") { - std::cout << PACKAGE_NAME << " " << PACKAGE_VERSION << std::endl; - return true; - } - if(arg == "--help" || arg == "-h") { - print_usage(argv[0]); - return true; - } - if(arg == "--print-datadir") { - /* - * Print the datadir searchpath to stdout, one path per - * line. Then exit. Intended for use by the supertux-editor. - */ - char **sp; - size_t sp_index; - sp = PHYSFS_getSearchPath(); - if (sp) - for (sp_index = 0; sp[sp_index]; sp_index++) - std::cout << sp[sp_index] << std::endl; - PHYSFS_freeList(sp); - return true; - } - } - - return false; -} - -/** - * Options that should be evaluated after config is read go here - */ -bool -Main::parse_commandline(int argc, char** argv) -{ - for(int i = 1; i < argc; ++i) { - std::string arg = argv[i]; - - if(arg == "--fullscreen" || arg == "-f") { - g_config->use_fullscreen = true; - } else if(arg == "--default" || arg == "-d") { - g_config->use_fullscreen = false; - - g_config->window_size = Size(800, 600); - g_config->fullscreen_size = Size(800, 600); - g_config->fullscreen_refresh_rate = 0; - g_config->aspect_size = Size(0, 0); // auto detect - - } else if(arg == "--window" || arg == "-w") { - g_config->use_fullscreen = false; - } else if(arg == "--geometry" || arg == "-g") { - i += 1; - if(i >= argc) - { - print_usage(argv[0]); - throw std::runtime_error("Need to specify a size (WIDTHxHEIGHT) for geometry argument"); - } - else - { - int width, height; - if (sscanf(argv[i], "%dx%d", &width, &height) != 2) - { - print_usage(argv[0]); - throw std::runtime_error("Invalid geometry spec, should be WIDTHxHEIGHT"); - } - else - { - g_config->window_size = Size(width, height); - g_config->fullscreen_size = Size(width, height); - g_config->fullscreen_refresh_rate = 0; - } - } - } else if(arg == "--aspect" || arg == "-a") { - i += 1; - if(i >= argc) - { - print_usage(argv[0]); - throw std::runtime_error("Need to specify a ratio (WIDTH:HEIGHT) for aspect ratio"); - } - else - { - int aspect_width = 0; - int aspect_height = 0; - if (strcmp(argv[i], "auto") == 0) - { - aspect_width = 0; - aspect_height = 0; - } - else if (sscanf(argv[i], "%d:%d", &aspect_width, &aspect_height) != 2) - { - print_usage(argv[0]); - throw std::runtime_error("Invalid aspect spec, should be WIDTH:HEIGHT or auto"); - } - else - { - float aspect_ratio = static_cast(aspect_width) / static_cast(aspect_height); - - // use aspect ratio to calculate logical resolution - if (aspect_ratio > 1) { - g_config->aspect_size = Size(static_cast(600 * aspect_ratio + 0.5), - 600); - } else { - g_config->aspect_size = Size(600, - static_cast(600 * 1/aspect_ratio + 0.5)); - } - } - } - } else if(arg == "--renderer") { - i += 1; - if(i >= argc) - { - print_usage(argv[0]); - throw std::runtime_error("Need to specify a renderer for renderer argument"); - } - else - { - g_config->video = VideoSystem::get_video_system(argv[i]); - } - } else if(arg == "--show-fps") { - g_config->show_fps = true; - } else if(arg == "--no-show-fps") { - g_config->show_fps = false; - } else if(arg == "--console") { - g_config->console_enabled = true; - } else if(arg == "--noconsole") { - g_config->console_enabled = false; - } else if(arg == "--disable-sfx") { - g_config->sound_enabled = false; - } else if(arg == "--disable-music") { - g_config->music_enabled = false; - } else if(arg == "--play-demo") { - if(i+1 >= argc) { - print_usage(argv[0]); - throw std::runtime_error("Need to specify a demo filename"); - } - g_config->start_demo = argv[++i]; - } else if(arg == "--record-demo") { - if(i+1 >= argc) { - print_usage(argv[0]); - throw std::runtime_error("Need to specify a demo filename"); - } - g_config->record_demo = argv[++i]; - } else if(arg == "--debug-scripts" || arg == "-s") { - g_config->enable_script_debugger = true; - } else if(arg[0] != '-') { - g_config->start_level = arg; - } else { - log_warning << "Unknown option '" << arg << "'. Use --help to see a list of options" << std::endl; - } - } - - return false; -} - -void Main::init_sdl() { if(SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) { @@ -475,13 +271,42 @@ Main::run(int argc, char** argv) { int result = 0; - try { - /* Do this before pre_parse_commandline, because --help now shows the - * default user data dir. */ + try + { + CommandLineArguments args; + + // Do this before pre_parse_commandline, because --help now shows the + // default user data dir. init_physfs(argv[0]); + + try + { + args.parse_args(argc, argv); + } + catch(const std::exception& err) + { + std::cout << "Error: " << err.what() << std::endl; + return EXIT_FAILURE; + } + + switch (args.get_action()) + { + case CommandLineArguments::PRINT_VERSION: + args.print_version(); + return 0; - if(pre_parse_commandline(argc, argv)) - return 0; + case CommandLineArguments::PRINT_HELP: + args.print_help(argv[0]); + return 0; + + case CommandLineArguments::PRINT_DATADIR: + args.print_datadir(); + return 0; + + default: + // continue and start the game as usual + break; + } init_sdl(); Console::instance = new Console(); @@ -492,9 +317,9 @@ Main::run(int argc, char** argv) timelog("config"); init_config(); + args.merge_into(*g_config); + timelog("commandline"); - if(parse_commandline(argc, argv)) - return 0; timelog("video"); std::unique_ptr renderer(VideoSystem::new_renderer()); diff --git a/src/supertux/main.hpp b/src/supertux/main.hpp index d36f8ab3b..e76dfcc3c 100644 --- a/src/supertux/main.hpp +++ b/src/supertux/main.hpp @@ -17,11 +17,15 @@ #ifndef HEADER_SUPERTUX_SUPERTUX_MAIN_HPP #define HEADER_SUPERTUX_SUPERTUX_MAIN_HPP +#ifdef _WIN32 +# define WRITEDIR_NAME PACKAGE_NAME +#else +# define WRITEDIR_NAME "." PACKAGE_NAME +#endif + class Main { private: - bool parse_commandline(int argc, char** argv); - bool pre_parse_commandline(int argc, char** argv); void init_audio(); void init_config(); void init_physfs(const char* argv0); @@ -29,7 +33,6 @@ private: void init_sdl(); void init_tinygettext(); void init_video(); - void print_usage(const char* argv0); void quit_audio(); public: -- 2.11.0