Initial work on console interface (nw)

Use Ctrl-Z to close console on any OS. To start use -console parameter
This commit is contained in:
Miodrag Milanovic 2016-10-09 14:38:41 +02:00
parent d0ee476b0a
commit 3c4c4e08ed
5 changed files with 210 additions and 107 deletions

View File

@ -2281,11 +2281,11 @@ int InputBuffer::incrementalHistorySearch(PromptBase& pi, int startChar) {
break; break;
// job control is its own thing // job control is its own thing
#ifndef _WIN32 //#ifndef _WIN32
case ctrlChar('Z'): // ctrl-Z, job control case ctrlChar('Z'): // ctrl-Z, job control
disableRawMode(); // Returning to Linux (whatever) shell, leave raw disableRawMode(); // Returning to Linux (whatever) shell, leave raw
// mode // mode
raise(SIGSTOP); // Break out in mid-line // raise(SIGSTOP); // Break out in mid-line
enableRawMode(); // Back from Linux shell, re-enter raw mode enableRawMode(); // Back from Linux shell, re-enter raw mode
{ {
bufferSize = historyLineLength + 1; bufferSize = historyLineLength + 1;
@ -2295,9 +2295,9 @@ int InputBuffer::incrementalHistorySearch(PromptBase& pi, int startChar) {
dynamicRefresh(dp, tempUnicode.get(), historyLineLength, dynamicRefresh(dp, tempUnicode.get(), historyLineLength,
historyLinePosition); historyLinePosition);
} }
continue; fprintf(stdout, "\n");
break; std::exit(0);
#endif //#endif
// these characters update the search string, and hence the selected input // these characters update the search string, and hence the selected input
// line // line
@ -2929,16 +2929,18 @@ int InputBuffer::getInputLine(PromptBase& pi) {
beep(); beep();
break; break;
#ifndef _WIN32 //#ifndef _WIN32
case ctrlChar('Z'): // ctrl-Z, job control case ctrlChar('Z'): // ctrl-Z, job control
disableRawMode(); // Returning to Linux (whatever) shell, leave raw disableRawMode(); // Returning to Linux (whatever) shell, leave raw
// mode // mode
raise(SIGSTOP); // Break out in mid-line //raise(SIGSTOP); // Break out in mid-line
enableRawMode(); // Back from Linux shell, re-enter raw mode enableRawMode(); // Back from Linux shell, re-enter raw mode
if (!pi.write()) break; // Redraw prompt //if (!pi.write()) break; // Redraw prompt
refreshLine(pi); // Refresh the line //refreshLine(pi); // Refresh the line
break; fprintf(stdout,"\n");
#endif std::exit(0);
//break;
//#endif
// DEL, delete the character under the cursor // DEL, delete the character under the cursor
case 127: case 127:

View File

@ -195,6 +195,7 @@ end
if (STANDALONE~=true) then if (STANDALONE~=true) then
links { links {
"frontend", "frontend",
"linenoise-ng",
} }
end end
if (MACHINES["NETLIST"]~=null) then if (MACHINES["NETLIST"]~=null) then

View File

@ -9,6 +9,7 @@
***************************************************************************/ ***************************************************************************/
#include "emu.h" #include "emu.h"
#include "luaengine.h"
#include "mame.h" #include "mame.h"
#include "chd.h" #include "chd.h"
#include "emuopts.h" #include "emuopts.h"
@ -31,6 +32,10 @@
#include "language.h" #include "language.h"
#include "pluginopts.h" #include "pluginopts.h"
#include "linenoise-ng/include/linenoise.h"
#include <atomic>
#include <thread>
#include <new> #include <new>
#include <ctype.h> #include <ctype.h>
@ -482,29 +487,8 @@ cli_frontend::~cli_frontend()
mame_options::remove_device_options(m_options); mame_options::remove_device_options(m_options);
} }
//------------------------------------------------- void cli_frontend::start_execution(mame_machine_manager *manager,int argc, char **argv,std::string &option_errors)
// 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.software_name()) != 0) if (*(m_options.software_name()) != 0)
{ {
const game_driver *system = mame_options::system(m_options); const game_driver *system = mame_options::system(m_options);
@ -555,9 +539,8 @@ int cli_frontend::execute(int argc, char **argv)
throw emu_fatalerror(EMU_ERR_FATALERROR, "Software '%s' is incompatible with system '%s'\n", m_options.software_name(), m_options.system_name()); 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 // parse the command line, adding any system-specific options
if (!mame_options::parse_command_line(m_options,argc, argv, option_errors)) 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 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) if (*(m_options.command()) == 0 && mame_options::system(m_options) == nullptr && *(m_options.system_name()) != 0)
@ -584,7 +567,7 @@ int cli_frontend::execute(int argc, char **argv)
if (m_options.read_config()) if (m_options.read_config())
{ {
m_options.revert(OPTION_PRIORITY_INI); m_options.revert(OPTION_PRIORITY_INI);
mame_options::parse_standard_inis(m_options,option_errors); mame_options::parse_standard_inis(m_options, option_errors);
} }
if (!option_errors.empty()) if (!option_errors.empty())
osd_printf_error("Error in command line:\n%s\n", strtrimspace(option_errors).c_str()); osd_printf_error("Error in command line:\n%s\n", strtrimspace(option_errors).c_str());
@ -597,8 +580,126 @@ int cli_frontend::execute(int argc, char **argv)
// otherwise just run the game // otherwise just run the game
m_result = manager->execute(); m_result = manager->execute();
} }
}
/*
static const char* examples[] = {
"db", "hello", "hallo", "hans", "hansekogge", "seamann", "quetzalcoatl", "quit", "power", NULL
};
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())
{
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);
}
}*/
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> ";
free(result);
wait.store(true);
}
}
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 // handle exceptions of various types
catch (emu_fatalerror &fatal) catch (emu_fatalerror &fatal)
{ {

View File

@ -61,6 +61,8 @@ private:
void display_help(const char *exename); void display_help(const char *exename);
void display_suggestions(const char *gamename); void display_suggestions(const char *gamename);
void output_single_softlist(FILE *out, software_list_device &swlist); 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 // internal state
emu_options & m_options; emu_options & m_options;

View File

@ -179,9 +179,6 @@ int mame_machine_manager::execute()
bool exit_pending = false; bool exit_pending = false;
int error = EMU_ERR_NONE; int error = EMU_ERR_NONE;
if (m_options.console()) {
m_lua->start_console();
}
while (error == EMU_ERR_NONE && !exit_pending) while (error == EMU_ERR_NONE && !exit_pending)
{ {
m_new_driver_pending = nullptr; m_new_driver_pending = nullptr;