From 19bfaa0684b1fbf8ee26b5e846260f6c754314d0 Mon Sep 17 00:00:00 2001 From: twanvl Date: Mon, 4 Aug 2008 18:45:46 +0000 Subject: [PATCH] Beginnings of a simple command line interface git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@1051 0fc631ac-6414-0410-93d0-97cfa31319b6 --- src/cli/cli_main.cpp | 71 +++++++++++++++++++++++ src/cli/cli_main.hpp | 29 ++++++++++ src/cli/text_io_handler.cpp | 103 ++++++++++++++++++++++++++++++++++ src/cli/text_io_handler.hpp | 47 ++++++++++++++++ src/cli/win32_cli_wrapper.cpp | 18 ++++-- src/main.cpp | 69 +++++++++++++++-------- src/mse.vcproj | 12 ++++ 7 files changed, 319 insertions(+), 30 deletions(-) create mode 100644 src/cli/cli_main.cpp create mode 100644 src/cli/cli_main.hpp create mode 100644 src/cli/text_io_handler.cpp create mode 100644 src/cli/text_io_handler.hpp diff --git a/src/cli/cli_main.cpp b/src/cli/cli_main.cpp new file mode 100644 index 00000000..595ee6f5 --- /dev/null +++ b/src/cli/cli_main.cpp @@ -0,0 +1,71 @@ +//+----------------------------------------------------------------------------+ +//| Description: Magic Set Editor - Program to make Magic (tm) cards | +//| Copyright: (C) 2001 - 2008 Twan van Laarhoven and "coppro" | +//| License: GNU General Public License 2 or later (see file COPYING) | +//+----------------------------------------------------------------------------+ + +// ----------------------------------------------------------------------------- : Includes + +#include +#include +#include +#include + +// ----------------------------------------------------------------------------- : Command line interface + +CLISetInterface::CLISetInterface() + : quiet(false) +{ + if (!cli.haveConsole()) { + throw Error(_("Can not run command line interface without a console;\nstart MSE with \"mse.com --cli\"")); + } + run(); +} + +void CLISetInterface::run() { + // show welcome logo + if (!quiet) showWelcome(); + // loop + running = true; + while (running) { + // show prompt + if (!quiet) { + cli << GRAY << _("> ") << NORMAL; + cli.flush(); + } + // read line from stdin + String command = cli.getLine(); + handleCommand(command); + } +} + +void CLISetInterface::showWelcome() { + cli << _(" ___ \n") + _(" __ __ _ ___ _ ___ _ _ _ |__ \\ \n") + _(" | \\/ |__ _ __ _(_)__ / __|___| |_ | __|__| (_) |_ ___ _ _ ) |\n") + _(" | |\\/| / _` / _` | / _| \\__ | -_) _| | _|/ _` | | _/ _ \\ '_| / / \n") + _(" |_| |_\\__,_\\__, |_\\__| |___|___|\\__| |___\\__,_|_|\\__\\___/_| / /_ \n") + _(" |___/ |____|\n\n"); + cli.flush(); +} + +void CLISetInterface::handleCommand(const String& command) { + if (command.empty()) { + // empty, ignore + } else if (command == _(":q") || command == _(":quit")) { + if (!quiet) { + cli << _("Goodbye\n"); cli.flush(); + } + running = false; + } else if (command == _(":?") || command == _(":help")) { + // TODO show help + } else if (command == _("exit") || command == _("quit")) { + cli << _("Use :quit to quit\n"); cli.flush(); + } else if (command.GetChar(0) == _(':')) { + cli << _("Unknown command, type :help for help.\n"); cli.flush(); + } else { + // execute command + // TODO + cli << _("You said:\n") << command << ENDL; cli.flush(); + } +} diff --git a/src/cli/cli_main.hpp b/src/cli/cli_main.hpp new file mode 100644 index 00000000..e7108299 --- /dev/null +++ b/src/cli/cli_main.hpp @@ -0,0 +1,29 @@ +//+----------------------------------------------------------------------------+ +//| Description: Magic Set Editor - Program to make Magic (tm) cards | +//| Copyright: (C) 2001 - 2008 Twan van Laarhoven and "coppro" | +//| License: GNU General Public License 2 or later (see file COPYING) | +//+----------------------------------------------------------------------------+ + +#ifndef HEADER_CLI_MAIN +#define HEADER_CLI_MAIN + +// ----------------------------------------------------------------------------- : Includes + +#include + +// ----------------------------------------------------------------------------- : Command line interface + +class CLISetInterface { + public: + CLISetInterface(); + private: + bool quiet; + bool running; + + void run(); + void showWelcome(); + void handleCommand(const String& command); +}; + +// ----------------------------------------------------------------------------- : EOF +#endif diff --git a/src/cli/text_io_handler.cpp b/src/cli/text_io_handler.cpp new file mode 100644 index 00000000..306b48c3 --- /dev/null +++ b/src/cli/text_io_handler.cpp @@ -0,0 +1,103 @@ +//+----------------------------------------------------------------------------+ +//| Description: Magic Set Editor - Program to make Magic (tm) cards | +//| Copyright: (C) 2001 - 2008 Twan van Laarhoven and "coppro" | +//| License: GNU General Public License 2 or later (see file COPYING) | +//+----------------------------------------------------------------------------+ + +// ----------------------------------------------------------------------------- : Includes + +#include +#include + +// ----------------------------------------------------------------------------- : Text I/O handler + +const Char* BRIGHT = _("\x1B[1m"); +const Char* NORMAL = _("\x1B[0m"); +const Char* PARAM = _("\x1B[33m"); +const Char* FILE_EXT = _("\x1B[0;1m"); +const Char* GRAY = _("\x1B[1;30m"); +const Char* RED = _("\x1B[1;31m"); +const Char* ENDL = _("\n"); + +TextIOHandler cli; + + +void TextIOHandler::init() { + #ifdef __WXMSW__ + have_console = false; + escapes = false; + // Detect whether to use console output + // GetStdHandle sometimes returns an invalid handle instead of INVALID_HANDLE_VALUE + // check with GetHandleInformation + HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD flags; + bool ok = GetHandleInformation(h,&flags); + if (ok) have_console = true; + // Detect the --color flag, indicating we should allow escapes + if (have_console) { + for (int i = 1 ; i < wxTheApp->argc ; ++i) { + if (String(wxTheApp->argv[i]) == _("--color")) { + escapes = true; + break; + } + } + } + #else + // always use console on *nix (?) + have_console = true; + escapes = true; + #endif +} + +bool TextIOHandler::haveConsole() const { + return have_console; +} + + +void TextIOHandler::flush() { + if (have_console) { + fflush(stdout); + } else if (!buffer.empty()) { + // Show message box + wxMessageBox(buffer, _("Magic Set Editor"), wxOK | wxICON_INFORMATION); + buffer.clear(); + } +} + +TextIOHandler& TextIOHandler::operator << (const Char* str) { + if (escapes || str[0] != 27) { + if (have_console) { + IF_UNICODE(wprintf,printf)(str); + } else { + buffer += str; + } + } + return *this; +} + +TextIOHandler& TextIOHandler::operator << (const String& str) { + if (escapes || str.empty() || str.GetChar(0) != 27) { + if (have_console) { + IF_UNICODE(wprintf,printf)(str.c_str()); + } else { + buffer += str; + } + } + return *this; +} + +String TextIOHandler::getLine() { + String result; + Char buffer[2048]; + while (true) { + if (!IF_UNICODE(fgetws,fgets)(buffer, 2048, stdin)) { + return result; // error + } + result += buffer; + if (result.GetChar(result.size()-1) == _('\n')) { + // drop newline, done + result.resize(result.size() - 1); + return result; + } + } +} diff --git a/src/cli/text_io_handler.hpp b/src/cli/text_io_handler.hpp new file mode 100644 index 00000000..cbd50f95 --- /dev/null +++ b/src/cli/text_io_handler.hpp @@ -0,0 +1,47 @@ +//+----------------------------------------------------------------------------+ +//| Description: Magic Set Editor - Program to make Magic (tm) cards | +//| Copyright: (C) 2001 - 2008 Twan van Laarhoven and "coppro" | +//| License: GNU General Public License 2 or later (see file COPYING) | +//+----------------------------------------------------------------------------+ + +#ifndef HEADER_CLI_TEXT_IO_HANDLER +#define HEADER_CLI_TEXT_IO_HANDLER + +// ----------------------------------------------------------------------------- : Includes + +#include + +// ----------------------------------------------------------------------------- : Text I/O handler + +// color codes +extern const Char *BRIGHT, *NORMAL, *PARAM, *FILE_EXT, *GRAY, *RED, *ENDL; + +/// Command line input / output handler +class TextIOHandler { + public: + void init(); + + /// Do we have a console to read/write from/to? + bool haveConsole() const; + + /// Output text to the console + TextIOHandler& operator << (const Char*); + TextIOHandler& operator << (const String&); + + /// Read a line from stdin + String getLine(); + + /// Flush output + void flush(); + + private: + bool have_console; + bool escapes; + String buffer; ///< Buffer when not writing to console +}; + +/// The global TextIOHandler object +extern TextIOHandler cli; + +// ----------------------------------------------------------------------------- : EOF +#endif diff --git a/src/cli/win32_cli_wrapper.cpp b/src/cli/win32_cli_wrapper.cpp index 20ba6f78..97b10c1c 100644 --- a/src/cli/win32_cli_wrapper.cpp +++ b/src/cli/win32_cli_wrapper.cpp @@ -41,6 +41,7 @@ struct Transfer { DWORD WINAPI TransferThread(Transfer*); BOOL WINAPI HandleCtrlEvent(DWORD type); +void InitEscapeTranslation(HANDLE console); void PerformEscapeCode(HANDLE console, char command, int argc, int argv[]); /// The child process @@ -59,7 +60,7 @@ int main(int argc, char** argv) { // determine whether we need to wrap console i/o bool need_redirection = false; for (int i = 1 ; i < argc ; ++i) { - for (int j = 1 ; j < sizeof(redirect_flags)/sizeof(redirect_flags[0]) ; ++j) { + for (int j = 0 ; j < sizeof(redirect_flags)/sizeof(redirect_flags[0]) ; ++j) { if (strcmp(argv[i],redirect_flags[j]) == 0) { need_redirection = true; goto break_2; @@ -116,6 +117,7 @@ int main(int argc, char** argv) { in_real = GetStdHandle(STD_INPUT_HANDLE); out_real = GetStdHandle(STD_OUTPUT_HANDLE); err_real = GetStdHandle(STD_ERROR_HANDLE); + InitEscapeTranslation(out_real); // start threads Transfer tranfer_in = {in_real, in_mine, false}; @@ -149,9 +151,6 @@ int main(int argc, char** argv) { return exit_code; } -// ----------------------------------------------------------------------------- : Running - - // ----------------------------------------------------------------------------- : Terminating /// Handle Ctrl+C @@ -189,10 +188,10 @@ void CopyFileBufferWithEscape(HANDLE output, char* buffer, DWORD size, bool hand } DWORD pos = 0; while (pos < size) { - // find next escape code, "\27[" + // find next escape code, "\x1B[" DWORD next_pos = pos; while (next_pos < size && - (buffer[next_pos] != '\27' || + (buffer[next_pos] != '\x1B' || (next_pos + 1 >= size || buffer[next_pos+1] != '['))) ++next_pos; // copy part before next escape CopyFileBuffer(output, buffer+pos, next_pos-pos); @@ -236,6 +235,13 @@ DWORD WINAPI TransferThread(Transfer* transfer) { WORD original_attributes; +/// Initialization for escape translation +void InitEscapeTranslation(HANDLE console) { + CONSOLE_SCREEN_BUFFER_INFO screen_buffer; + GetConsoleScreenBufferInfo(console, &screen_buffer); + original_attributes = screen_buffer.wAttributes; +} + /// Perform an escape code void PerformEscapeCode(HANDLE console, char command, int argc, int argv[]) { switch (command) { diff --git a/src/main.cpp b/src/main.cpp index c663c8c1..620ad9dd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -102,6 +104,7 @@ int MSE::OnRun() { wxFileSystem::AddHandler(new wxInternetFSHandler); // needed for update checker init_script_variables(); init_file_formats(); + cli.init(); package_manager.init(); settings.read(); the_locale = Locale::byName(settings.locale); @@ -155,33 +158,51 @@ int MSE::OnRun() { return EXIT_SUCCESS; } else if (arg == _("--help") || arg == _("-?")) { // command line help - write_stdout( String(_("Magic Set Editor\n\n")) - + _("Usage: ") + argv[0] + _(" [OPTIONS]\n\n") - + _(" no options\n") - + _(" \tStart the MSE user interface showing the welcome window.\n\n") - + _(" -? or --help\n") - + _(" \tShows this help screen.\n\n") - + _(" -v or --version\n") - + _(" \tShow version information.\n\n") - + _(" FILE.mse-set, FILE.set, FILE.mse\n") - + _(" \tLoad the set file in the MSE user interface.\n\n") - + _(" FILE.mse-symbol\n") - + _(" \tLoad the symbol into the MSE symbol editor.\n\n") - + _(" FILE.mse-installer [--local]\n") - + _(" \tInstall the packages from the installer.\n") - + _(" \tIf the --local flag is passed, install packages for this user only.\n\n") - + _(" --symbol-editor\n") - + _(" \tShow the symbol editor instead of the welcome window.\n\n") - + _(" --create-installer [OUTFILE.mse-installer] [PACKAGE [PACKAGE ...]]\n") - + _(" \tCreate an instaler, containing the listed packages.\n") - + _(" \tIf no filename is specified, the name of the first package is used.\n\n") - + _(" --export FILE [IMAGE]\n") - + _(" \tExport the cards in a set to image files,\n") - + _(" \tIMAGE is the same format as for 'export all card images'.\n") ); + cli << _("Magic Set Editor\n\n"); + cli << _("Usage: ") << BRIGHT << argv[0] << NORMAL << _(" [") << PARAM << _("OPTIONS") << NORMAL << _("]"); + cli << _("\n\n no options"); + cli << _("\n \tStart the MSE user interface showing the welcome window."); + cli << _("\n\n ") << BRIGHT << _("-?") << NORMAL << _(", ") + << BRIGHT << _("--help") << NORMAL; + cli << _("\n \tShows this help screen."); + cli << _("\n\n ") << BRIGHT << _("-v") << NORMAL << _(", ") + << BRIGHT << _("--version") << NORMAL; + cli << _("\n \tShow version information."); + cli << _("\n\n ") << PARAM << _("FILE") << FILE_EXT << _(".mse-set") << NORMAL << _(", ") + << PARAM << _("FILE") << FILE_EXT << _(".set") << NORMAL << _(", ") + << PARAM << _("FILE") << FILE_EXT << _(".mse") << NORMAL; + cli << _("\n \tLoad the set file in the MSE user interface."); + cli << _("\n\n ") << PARAM << _("FILE") << FILE_EXT << _(".mse-symbol") << NORMAL; + cli << _("\n \tLoad the symbol into the MSE symbol editor."); + cli << _("\n\n ") << BRIGHT << _("FILE") << FILE_EXT << _(".mse-installer") + << NORMAL << _(" [") << BRIGHT << _("--local") << NORMAL << _("]"); + cli << _("\n \tInstall the packages from the installer."); + cli << _("\n \tIf the ") << BRIGHT << _("--local") << NORMAL << _(" flag is passed, install packages for this user only."); + cli << _("\n\n ") << BRIGHT << _("--symbol-editor") << NORMAL; + cli << _("\n \tShow the symbol editor instead of the welcome window."); + cli << _("\n\n ") << BRIGHT << _("--create-installer") << NORMAL << _(" [") + << PARAM << _("OUTFILE") << FILE_EXT << _(".mse-installer") << NORMAL << _("] [") + << PARAM << _("PACKAGE") << NORMAL << _(" [") << PARAM << _("PACKAGE") << NORMAL << _(" ...]]"); + cli << _("\n \tCreate an instaler, containing the listed packages."); + cli << _("\n \tIf no output filename is specified, the name of the first package is used."); + cli << _("\n\n ") << BRIGHT << _("--export") << NORMAL << PARAM << _(" FILE") << NORMAL << _(" [") << PARAM << _("IMAGE") << NORMAL << _("]"); + cli << _("\n \tExport the cards in a set to image files,"); + cli << _("\n \tIMAGE is the same format as for 'export all card images'."); + cli << _("\n\n ") << BRIGHT << _("--cli") << NORMAL << _(" [") + << PARAM << _("FILE") << NORMAL << _("]"); + cli << _("\n \tStart the command line interface for performing commands on the set file."); + cli << ENDL; + cli.flush(); return EXIT_SUCCESS; } else if (arg == _("--version") || arg == _("-v")) { // dump version - write_stdout( _("Magic Set Editor\nVersion ") + app_version.toString() + version_suffix ); + cli << _("Magic Set Editor\n"); + cli << _("Version ") << app_version.toString() << version_suffix << ENDL; + cli.flush(); + return EXIT_SUCCESS; + } else if (arg == _("--cli")) { + // command line interface + CLISetInterface cli_interface; return EXIT_SUCCESS; } else if (arg == _("--export")) { if (argc <= 2) { diff --git a/src/mse.vcproj b/src/mse.vcproj index 12a9cea2..36928cad 100644 --- a/src/mse.vcproj +++ b/src/mse.vcproj @@ -3819,6 +3819,18 @@ + + + + + + + +