diff options
-rw-r--r-- | 3rdparty/linenoise-ng/src/linenoise.cpp | 24 | ||||
-rw-r--r-- | scripts/src/main.lua | 1 | ||||
-rw-r--r-- | src/frontend/mame/clifront.cpp | 275 | ||||
-rw-r--r-- | src/frontend/mame/clifront.h | 2 | ||||
-rw-r--r-- | src/frontend/mame/mame.cpp | 5 |
5 files changed, 205 insertions, 102 deletions
diff --git a/3rdparty/linenoise-ng/src/linenoise.cpp b/3rdparty/linenoise-ng/src/linenoise.cpp index 10ab72790bd..751c535d084 100644 --- a/3rdparty/linenoise-ng/src/linenoise.cpp +++ b/3rdparty/linenoise-ng/src/linenoise.cpp @@ -2281,11 +2281,11 @@ int InputBuffer::incrementalHistorySearch(PromptBase& pi, int startChar) { break; // job control is its own thing -#ifndef _WIN32 +//#ifndef _WIN32 case ctrlChar('Z'): // ctrl-Z, job control disableRawMode(); // Returning to Linux (whatever) shell, leave raw // mode - raise(SIGSTOP); // Break out in mid-line + // raise(SIGSTOP); // Break out in mid-line enableRawMode(); // Back from Linux shell, re-enter raw mode { bufferSize = historyLineLength + 1; @@ -2295,9 +2295,9 @@ int InputBuffer::incrementalHistorySearch(PromptBase& pi, int startChar) { dynamicRefresh(dp, tempUnicode.get(), historyLineLength, historyLinePosition); } - continue; - break; -#endif + fprintf(stdout, "\n"); + std::exit(0); +//#endif // these characters update the search string, and hence the selected input // line @@ -2929,16 +2929,18 @@ int InputBuffer::getInputLine(PromptBase& pi) { beep(); break; -#ifndef _WIN32 +//#ifndef _WIN32 case ctrlChar('Z'): // ctrl-Z, job control disableRawMode(); // Returning to Linux (whatever) shell, leave raw // mode - raise(SIGSTOP); // Break out in mid-line + //raise(SIGSTOP); // Break out in mid-line enableRawMode(); // Back from Linux shell, re-enter raw mode - if (!pi.write()) break; // Redraw prompt - refreshLine(pi); // Refresh the line - break; -#endif + //if (!pi.write()) break; // Redraw prompt + //refreshLine(pi); // Refresh the line + fprintf(stdout,"\n"); + std::exit(0); + //break; +//#endif // DEL, delete the character under the cursor case 127: diff --git a/scripts/src/main.lua b/scripts/src/main.lua index 08f047d99db..eb7cac4c8d5 100644 --- a/scripts/src/main.lua +++ b/scripts/src/main.lua @@ -195,6 +195,7 @@ end if (STANDALONE~=true) then links { "frontend", + "linenoise-ng", } end if (MACHINES["NETLIST"]~=null) then diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp index a274326fac2..c3fbb049ffa 100644 --- a/src/frontend/mame/clifront.cpp +++ b/src/frontend/mame/clifront.cpp @@ -9,6 +9,7 @@ ***************************************************************************/ #include "emu.h" +#include "luaengine.h" #include "mame.h" #include "chd.h" #include "emuopts.h" @@ -31,6 +32,10 @@ #include "language.h" #include "pluginopts.h" +#include "linenoise-ng/include/linenoise.h" +#include <atomic> +#include <thread> + #include <new> #include <ctype.h> @@ -482,123 +487,219 @@ cli_frontend::~cli_frontend() mame_options::remove_device_options(m_options); } -//------------------------------------------------- -// execute - execute a game via the standard -// command line interface -//------------------------------------------------- - -int cli_frontend::execute(int argc, char **argv) +void cli_frontend::start_execution(mame_machine_manager *manager,int argc, char **argv,std::string &option_errors) { - // wrap the core execution in a try/catch to field all fatal errors - m_result = EMU_ERR_NONE; - mame_machine_manager *manager = mame_machine_manager::instance(m_options, m_osd); - - try + if (*(m_options.software_name()) != 0) { - // first parse options to be able to get software from it - std::string option_errors; - mame_options::parse_command_line(m_options,argc, argv, option_errors); - - mame_options::parse_standard_inis(m_options,option_errors); - - load_translation(m_options); + const game_driver *system = mame_options::system(m_options); + if (system == nullptr && *(m_options.system_name()) != 0) + throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "Unknown system '%s'", m_options.system_name()); - manager->start_luaengine(); + machine_config config(*system, m_options); + software_list_device_iterator iter(config.root_device()); + if (iter.count() == 0) + throw emu_fatalerror(EMU_ERR_FATALERROR, "Error: unknown option: %s\n", m_options.software_name()); - if (*(m_options.software_name()) != 0) + bool found = false; + bool compatible = false; + for (software_list_device &swlistdev : iter) { - const game_driver *system = mame_options::system(m_options); - if (system == nullptr && *(m_options.system_name()) != 0) - throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "Unknown system '%s'", m_options.system_name()); - - machine_config config(*system, m_options); - software_list_device_iterator iter(config.root_device()); - if (iter.count() == 0) - throw emu_fatalerror(EMU_ERR_FATALERROR, "Error: unknown option: %s\n", m_options.software_name()); - - bool found = false; - bool compatible = false; - for (software_list_device &swlistdev : iter) + const software_info *swinfo = swlistdev.find(m_options.software_name()); + if (swinfo != nullptr) { - const software_info *swinfo = swlistdev.find(m_options.software_name()); - if (swinfo != nullptr) + // loop through all parts + for (const software_part &swpart : swinfo->parts()) { - // loop through all parts - for (const software_part &swpart : swinfo->parts()) + // only load compatible software this way + if (swlistdev.is_compatible(swpart) == SOFTWARE_IS_COMPATIBLE) { - // only load compatible software this way - if (swlistdev.is_compatible(swpart) == SOFTWARE_IS_COMPATIBLE) + device_image_interface *image = software_list_device::find_mountable_image(config, swpart); + if (image != nullptr) { - device_image_interface *image = software_list_device::find_mountable_image(config, swpart); - if (image != nullptr) - { - std::string val = string_format("%s:%s:%s", swlistdev.list_name(), m_options.software_name(), swpart.name()); + std::string val = string_format("%s:%s:%s", swlistdev.list_name(), m_options.software_name(), swpart.name()); - // call this in order to set slot devices according to mounting - mame_options::parse_slot_devices(m_options, argc, argv, option_errors, image->instance_name(), val.c_str(), &swpart); - } - compatible = true; + // call this in order to set slot devices according to mounting + mame_options::parse_slot_devices(m_options, argc, argv, option_errors, image->instance_name(), val.c_str(), &swpart); } + compatible = true; } - found = true; } - - if (compatible) - break; - } - if (!compatible) - { - software_list_device::display_matches(config, nullptr, m_options.software_name()); - if (!found) - throw emu_fatalerror(EMU_ERR_FATALERROR, nullptr); - else - throw emu_fatalerror(EMU_ERR_FATALERROR, "Software '%s' is incompatible with system '%s'\n", m_options.software_name(), m_options.system_name()); + found = true; } - } - // parse the command line, adding any system-specific options - if (!mame_options::parse_command_line(m_options,argc, argv, option_errors)) + if (compatible) + break; + } + if (!compatible) { - // if we failed, check for no command and a system name first; in that case error on the name - if (*(m_options.command()) == 0 && mame_options::system(m_options) == nullptr && *(m_options.system_name()) != 0) - throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "Unknown system '%s'", m_options.system_name()); + software_list_device::display_matches(config, nullptr, m_options.software_name()); + if (!found) + throw emu_fatalerror(EMU_ERR_FATALERROR, nullptr); + else + throw emu_fatalerror(EMU_ERR_FATALERROR, "Software '%s' is incompatible with system '%s'\n", m_options.software_name(), m_options.system_name()); + } + } + // parse the command line, adding any system-specific options + if (!mame_options::parse_command_line(m_options, argc, argv, option_errors)) + { + // if we failed, check for no command and a system name first; in that case error on the name + if (*(m_options.command()) == 0 && mame_options::system(m_options) == nullptr && *(m_options.system_name()) != 0) + throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "Unknown system '%s'", m_options.system_name()); - // otherwise, error on the options - throw emu_fatalerror(EMU_ERR_INVALID_CONFIG, "%s", strtrimspace(option_errors).c_str()); + // otherwise, error on the options + throw emu_fatalerror(EMU_ERR_INVALID_CONFIG, "%s", strtrimspace(option_errors).c_str()); + } + if (!option_errors.empty()) + osd_printf_error("Error in command line:\n%s\n", strtrimspace(option_errors).c_str()); + + // determine the base name of the EXE + std::string exename = core_filename_extract_base(argv[0], true); + + // if we have a command, execute that + if (*(m_options.command()) != 0) + execute_commands(exename.c_str()); + + // otherwise, check for a valid system + else + { + // We need to preprocess the config files once to determine the web server's configuration + // and file locations + if (m_options.read_config()) + { + m_options.revert(OPTION_PRIORITY_INI); + mame_options::parse_standard_inis(m_options, option_errors); } if (!option_errors.empty()) osd_printf_error("Error in command line:\n%s\n", strtrimspace(option_errors).c_str()); - // determine the base name of the EXE - std::string exename = core_filename_extract_base(argv[0], true); + // if we can't find it, give an appropriate error + const game_driver *system = mame_options::system(m_options); + if (system == nullptr && *(m_options.system_name()) != 0) + throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "Unknown system '%s'", m_options.system_name()); - // if we have a command, execute that - if (*(m_options.command()) != 0) - execute_commands(exename.c_str()); + // otherwise just run the game + m_result = manager->execute(); + } +} +/* +static const char* examples[] = { + "db", "hello", "hallo", "hans", "hansekogge", "seamann", "quetzalcoatl", "quit", "power", NULL +}; - // otherwise, check for a valid system - else +void completionHook(char const* prefix, linenoiseCompletions* lc) { + size_t i; + + for (i = 0; examples[i] != NULL; ++i) { + if (strncmp(prefix, examples[i], strlen(prefix)) == 0) { + linenoiseAddCompletion(lc, examples[i]); + } + } +} +*/ + +void read_console(std::atomic<bool>& run, std::atomic<bool>& wait, std::string &cmdLine) +{ + char const* prompt = "\x1b[1;36m[MAME]\x1b[0m> "; + + while (run.load()) + { + while (wait.load()) { - // We need to preprocess the config files once to determine the web server's configuration - // and file locations - if (m_options.read_config()) - { - m_options.revert(OPTION_PRIORITY_INI); - mame_options::parse_standard_inis(m_options,option_errors); + using namespace std::chrono_literals; + std::this_thread::sleep_for(100ms); + } + char* result = linenoise(prompt); + if (result == NULL) + { + continue; + } +/* else if (!strncmp(result, "/history", 8)) { + // Display the current history. + for (int index = 0; ; ++index) { + char* hist = linenoiseHistoryLine(index); + if (hist == NULL) break; + printf("%4d: %s\n", index, hist); + free(hist); } - if (!option_errors.empty()) - osd_printf_error("Error in command line:\n%s\n", strtrimspace(option_errors).c_str()); + }*/ + else if (*result == '\0') { + free(result); + continue; + } + cmdLine = std::string(result); + linenoiseHistoryAdd(result); + //prompt = "\x1b[1;36m[MAME]\x1b[0m \x1b[1;32m[test]\x1b[0m> "; - // if we can't find it, give an appropriate error - const game_driver *system = mame_options::system(m_options); - if (system == nullptr && *(m_options.system_name()) != 0) - throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "Unknown system '%s'", m_options.system_name()); + free(result); + wait.store(true); + } +} - // otherwise just run the game - m_result = manager->execute(); +void cli_frontend::start_console() +{ + linenoiseInstallWindowChangeHandler(); + std::string cmdLine = ""; + const char* file = "./history"; + + linenoiseHistoryLoad(file); + //linenoiseSetCompletionCallback(completionHook); + printf(" _/ _/ _/_/ _/ _/ _/_/_/_/\n"); + printf(" _/_/ _/_/ _/ _/ _/_/ _/_/ _/ \n"); + printf(" _/ _/ _/ _/_/_/_/ _/ _/ _/ _/_/_/ \n"); + printf(" _/ _/ _/ _/ _/ _/ _/ \n"); + printf("_/ _/ _/ _/ _/ _/ _/_/_/_/ \n"); + printf("\n"); + printf("%s v%s\n%s\n\n", emulator_info::get_appname(), build_version, emulator_info::get_copyright_info()); + + std::atomic<bool> run(true), wait(false); + std::thread cinThread(read_console, std::ref(run), std::ref(wait), std::ref(cmdLine)); + + while (run.load()) + { + if (wait.load()) + { + //printf("command %s\n", cmdLine.c_str()); + cmdLine.clear(); + wait.store(false); } } + run.store(false); + cinThread.join(); + + linenoiseHistorySave(file); + linenoiseHistoryFree(); +} +//------------------------------------------------- +// execute - execute a game via the standard +// command line interface +//------------------------------------------------- + +int cli_frontend::execute(int argc, char **argv) +{ + // wrap the core execution in a try/catch to field all fatal errors + m_result = EMU_ERR_NONE; + mame_machine_manager *manager = mame_machine_manager::instance(m_options, m_osd); + + try + { + // first parse options to be able to get software from it + std::string option_errors; + mame_options::parse_command_line(m_options,argc, argv, option_errors); + + mame_options::parse_standard_inis(m_options,option_errors); + + load_translation(m_options); + + manager->start_luaengine(); + + if (m_options.console()) { + //manager->lua()->start_console(); + start_console(); + } else { + start_execution(manager, argc, argv, option_errors); + } + } // handle exceptions of various types catch (emu_fatalerror &fatal) { diff --git a/src/frontend/mame/clifront.h b/src/frontend/mame/clifront.h index 4c4641ff72e..aeceeace397 100644 --- a/src/frontend/mame/clifront.h +++ b/src/frontend/mame/clifront.h @@ -61,6 +61,8 @@ private: void display_help(const char *exename); void display_suggestions(const char *gamename); void output_single_softlist(FILE *out, software_list_device &swlist); + void start_execution(mame_machine_manager *manager, int argc, char **argv, std::string &option_errors); + void start_console(); // internal state emu_options & m_options; diff --git a/src/frontend/mame/mame.cpp b/src/frontend/mame/mame.cpp index 0a4fc03b3bd..55c8219a425 100644 --- a/src/frontend/mame/mame.cpp +++ b/src/frontend/mame/mame.cpp @@ -178,10 +178,7 @@ int mame_machine_manager::execute() // loop across multiple hard resets bool exit_pending = false; int error = EMU_ERR_NONE; - - if (m_options.console()) { - m_lua->start_console(); - } + while (error == EMU_ERR_NONE && !exit_pending) { m_new_driver_pending = nullptr; |