diff options
| author | isanae <14251494+isanae@users.noreply.github.com> | 2020-07-18 02:24:44 -0400 |
|---|---|---|
| committer | isanae <14251494+isanae@users.noreply.github.com> | 2020-11-03 11:39:01 -0500 |
| commit | 5e528fb4cf16ae208944d15d568c9140e3d741e4 (patch) | |
| tree | 8fd4927aeffb19406e2356d39c2bec0751c7f53d /src | |
| parent | b103f297752b170ee4ade6e0e9085c6d31c020ca (diff) | |
new CommandLine class
implemented crashdump as a command, fixed dump_running_process.bat to use it
attach to console if present instead of always create one
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/commandline.cpp | 205 | ||||
| -rw-r--r-- | src/commandline.h | 62 | ||||
| -rw-r--r-- | src/env.cpp | 42 | ||||
| -rw-r--r-- | src/env.h | 4 | ||||
| -rw-r--r-- | src/main.cpp | 31 | ||||
| -rw-r--r-- | src/pch.h | 1 |
7 files changed, 317 insertions, 29 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e95179b8..73254574 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,6 +11,7 @@ endif() add_filter(NAME src/application GROUPS iuserinterface + commandline main moapplication moshortcut diff --git a/src/commandline.cpp b/src/commandline.cpp new file mode 100644 index 00000000..f0bdadf9 --- /dev/null +++ b/src/commandline.cpp @@ -0,0 +1,205 @@ +#include "commandline.h" +#include "env.h" + +namespace cl +{ + +CommandLine::CommandLine() +{ + createOptions(); + m_commands.push_back(std::make_unique<CrashDumpCommand>()); +} + +int CommandLine::run(int argc, char** argv) +{ + try + { + po::variables_map vm; + + auto parsed = po::command_line_parser(argc, argv) + .options(m_allOptions) + .positional(m_positional) + .allow_unregistered() + .run(); + + po::store(parsed, vm); + + if (vm.count("command")) { + const auto cmd = vm["command"].as<std::string>(); + + for (auto&& c : m_commands) { + if (c->name() == cmd) { + auto co = c->options(); + co.add_options() + ("help", "shows this message"); + + auto opts = po::collect_unrecognized( + parsed.options, po::include_positional); + + // remove the command name itself + opts.erase(opts.begin()); + + parsed = po::command_line_parser(opts) + .options(co) + .run(); + + po::store(parsed, vm); + + if (vm.count("help")) { + env::Console console; + std::cout << usage(c.get()) << "\n"; + return 0; + } + + return c->run(vm); + } + } + } + + if (vm.count("help")) { + env::Console console; + std::cout << usage() << "\n"; + return 0; + } + + return -1; + } + catch(po::error& e) + { + env::Console console; + std::cerr << e.what() << "\n"; + std::cerr << usage() << "\n"; + return 1; + } +} + +void CommandLine::createOptions() +{ + m_visibleOptions.add_options() + ("help", "shows this message"); + + po::options_description options; + options.add_options() + ("command", po::value<std::string>(), "command to execute"); + + m_positional + .add("command", 1) + .add("subargs", -1); + + m_allOptions.add(m_visibleOptions); + m_allOptions.add(options); +} + +std::string CommandLine::usage(const Command* c) const +{ + std::ostringstream oss; + + oss + << "\n" + << "Usage:\n"; + + if (c) { + oss + << " ModOrganizer.exe [options] " << c->name() << " [command-options]\n" + << "\n" + << "Command options:\n" + << c->options() << "\n"; + } else { + oss + << " ModOrganizer.exe [options] [[command] [command-options]]\n" + << "\n" + << "Commands:\n"; + + for (auto&& c : m_commands) { + oss << " " << c->name() << " " << c->description() << "\n"; + } + + oss << "\n"; + } + + oss + << "Global options:\n" + << m_visibleOptions << "\n"; + + return oss.str(); +} + + +std::string Command::name() const +{ + return meta().name; +} + +std::string Command::description() const +{ + return meta().description; +} + +po::options_description Command::options() const +{ + return doOptions(); +} + +po::options_description Command::doOptions() const +{ + // no-op + return {}; +} + +std::string Command::usage() const +{ + std::ostringstream oss; + + oss + << "\n" + << "Usage:\n" + << " ModOrganizer.exe [options] [[command] [command-options]]\n" + << "\n" + << "Options:\n" + << options() << "\n"; + + return oss.str(); +} + +int Command::run(po::variables_map& vm) +{ + return doRun(vm); +} + + + +po::options_description CrashDumpCommand::doOptions() const +{ + po::options_description d; + + d.add_options() + ("type", po::value<std::string>()->default_value("mini"), "mini|data|full"); + + return d; +} + +Command::Meta CrashDumpCommand::meta() const +{ + return {"crashdump", "writes a crashdump for a running process of MO"}; +} + +int CrashDumpCommand::doRun(po::variables_map& vm) +{ + env::Console console; + + const auto typeString = vm["type"].as<std::string>(); + const auto type = env::coreDumpTypeFromString(typeString); + + // dump + const auto b = env::coredumpOther(type); + if (!b) { + std::wcerr << L"\n>>>> a minidump file was not written\n\n"; + } + + std::wcerr << L"Press enter to continue..."; + std::wcin.get(); + + return (b ? 0 : 1); +} + +} // namespace diff --git a/src/commandline.h b/src/commandline.h new file mode 100644 index 00000000..d5ad5a32 --- /dev/null +++ b/src/commandline.h @@ -0,0 +1,62 @@ +#pragma once + +#include <vector> +#include <memory> + +namespace cl +{ + +namespace po = boost::program_options; + + +class Command +{ +public: + virtual ~Command() = default; + + std::string name() const; + std::string description() const; + + po::options_description options() const; + std::string usage() const; + + int run(po::variables_map& vm); + +protected: + struct Meta + { + std::string name, description; + }; + + virtual po::options_description doOptions() const; + virtual Meta meta() const = 0; + virtual int doRun(po::variables_map& vm) = 0; +}; + + +class CrashDumpCommand : public Command +{ +protected: + po::options_description doOptions() const; + Meta meta() const override; + int doRun(po::variables_map& vm) override; +}; + + +class CommandLine +{ +public: + CommandLine(); + + int run(int argc, char** argv); + std::string usage(const Command* c=nullptr) const; + +private: + po::options_description m_visibleOptions, m_allOptions; + po::positional_options_description m_positional; + std::vector<std::unique_ptr<Command>> m_commands; + + void createOptions(); +}; + +} // namespace diff --git a/src/env.cpp b/src/env.cpp index 2862aa95..bf75c9fa 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -16,9 +16,15 @@ using namespace MOBase; Console::Console() : m_hasConsole(false), m_in(nullptr), m_out(nullptr), m_err(nullptr) { - // open a console - if (!AllocConsole()) { - // failed, ignore + // try to attach to parent + if (!AttachConsole(ATTACH_PARENT_PROCESS)) { + if (GetLastError() != ERROR_ACCESS_DENIED) { + // parent has no console, create one + if (!AllocConsole()) { + // failed, ignore + return; + } + } } m_hasConsole = true; @@ -1032,6 +1038,36 @@ HandlePtr dumpFile() return {}; } + +CoreDumpTypes coreDumpTypeFromString(const std::string& s) +{ + if (s == "data") + return env::CoreDumpTypes::Data; + else if (s == "full") + return env::CoreDumpTypes::Full; + else + return env::CoreDumpTypes::Mini; +} + +std::string toString(CoreDumpTypes type) +{ + switch (type) + { + case CoreDumpTypes::Mini: + return "mini"; + + case CoreDumpTypes::Data: + return "data"; + + case CoreDumpTypes::Full: + return "full"; + + default: + return "?"; + } +} + + bool createMiniDump(HANDLE process, CoreDumpTypes type) { const DWORD pid = GetProcessId(process); @@ -307,6 +307,10 @@ enum class CoreDumpTypes Full }; + +CoreDumpTypes coreDumpTypeFromString(const std::string& s); +std::string toString(CoreDumpTypes type); + // creates a minidump file for this process // bool coredump(CoreDumpTypes type); diff --git a/src/main.cpp b/src/main.cpp index 7130d15c..8a006907 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,6 +49,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "env.h" #include "envmodule.h" #include "shared/util.h" +#include "commandline.h" #include <eh.h> #include "shared/windows_error.h" @@ -811,22 +812,6 @@ int runApplication( return 1; } -int doCoreDump(env::CoreDumpTypes type) -{ - env::Console c; - - // dump - const auto b = env::coredumpOther(type); - if (!b) { - std::wcerr << L"\n>>>> a minidump file was not written\n\n"; - } - - std::wcerr << L"Press enter to continue..."; - std::wcin.get(); - - return (b ? 0 : 1); -} - log::Levels convertQtLevel(QtMsgType t) { switch (t) @@ -895,17 +880,11 @@ void initLogging() int main(int argc, char *argv[]) { TimeThis tt("main to runApplication()"); + cl::CommandLine cl; - // handle --crashdump first - for (int i=1; i<argc; ++i) { - if (std::strcmp(argv[i], "--crashdump") == 0) { - return doCoreDump(env::CoreDumpTypes::Mini); - } else if (std::strcmp(argv[i], "--crashdump-data") == 0) { - return doCoreDump(env::CoreDumpTypes::Data); - } else if (std::strcmp(argv[i], "--crashdump-full") == 0) { - return doCoreDump(env::CoreDumpTypes::Full); - } - } + const auto r = cl.run(argc, argv); + if (r >= 0) + return r; initLogging(); @@ -64,6 +64,7 @@ #include <boost/thread.hpp> #include <boost/uuid/uuid_generators.hpp> #include <boost/uuid/uuid_io.hpp> +#include <boost/program_options.hpp> // openssl #include <tlhelp32.h> |
