summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--plugins/console/init.lua84
-rw-r--r--plugins/console/plugin.json10
-rw-r--r--scripts/src/mame/frontend.lua2
-rw-r--r--src/frontend/mame/clifront.cpp7
-rw-r--r--src/frontend/mame/console.cpp138
-rw-r--r--src/frontend/mame/console.h41
-rw-r--r--src/frontend/mame/luaengine.cpp67
-rw-r--r--src/frontend/mame/luaengine.h12
-rw-r--r--src/frontend/mame/mame.cpp1
9 files changed, 172 insertions, 190 deletions
diff --git a/plugins/console/init.lua b/plugins/console/init.lua
new file mode 100644
index 00000000000..fea0f930d42
--- /dev/null
+++ b/plugins/console/init.lua
@@ -0,0 +1,84 @@
+-- license:BSD-3-Clause
+-- copyright-holders:Carl
+local exports = {}
+exports.name = "console"
+exports.version = "0.0.1"
+exports.description = "Console plugin"
+exports.license = "The BSD 3-Clause License"
+exports.author = { name = "Carl" }
+
+local console = exports
+
+function console.startplugin()
+ local conth = emu.thread()
+ local started = false
+ local ln = require("linenoise")
+ print(" _/ _/ _/_/ _/ _/ _/_/_/_/");
+ print(" _/_/ _/_/ _/ _/ _/_/ _/_/ _/ ");
+ print(" _/ _/ _/ _/_/_/_/ _/ _/ _/ _/_/_/ ");
+ print(" _/ _/ _/ _/ _/ _/ _/ ");
+ print("_/ _/ _/ _/ _/ _/ _/_/_/_/ \n");
+ print(emu.app_name() .. " " .. emu.app_version(), "\nCopyright (C) Nicola Salmoria and the MAME team\n");
+ print(_VERSION, "\nCopyright (C) Lua.org, PUC-Rio\n");
+ -- linenoise isn't thread safe but that means history can handled here
+ -- that also means that bad things will happen if anything outside lua tries to use it
+ -- especially the completion callback
+ ln.historysetmaxlen(10)
+ local scr = "local ln = require('linenoise')\n"
+ scr = scr .. "ln.setcompletion(function(c, str) status = str\n"
+ scr = scr .. " yield()\n" -- coroutines can't yield in the middle of a callback so this is a real thread
+ scr = scr .. " status:gsub('[^,]*', function(s) if s ~= '' then ln.addcompletion(c, s) end end)\n"
+ scr = scr .. "end)\n"
+ scr = scr .. "return ln.linenoise('\x1b[1;36m[MAME]\x1b[0m> ')"
+
+ function get_completions(str)
+ local function is_pair_iterable(t)
+ local mt = getmetatable(t)
+ return type(t) == 'table' or (mt and mt.__pairs)
+ end
+ local comps = ","
+ local table, last = str:match("([(]?[%w.:()]-)[:.]?([%w]*)$")
+ if last == "" then
+ return comps
+ end
+ local err
+ err, tablef = pcall(load("return " .. table))
+ if (not err) or (not tablef) then
+ return comps
+ end
+ if is_pair_iterable(tablef) then
+ for k, v in pairs(tablef) do
+ if k:match("^" .. last) then
+ comps = comps .. "," .. table
+ end
+ end
+ end
+ return comps
+ end
+
+ emu.register_periodic(function()
+ if conth.yield then
+ conth:continue(get_completions(conth.result))
+ return
+ elseif conth.busy then
+ return
+ elseif started then
+ local cmd = conth.result
+ ln.historyadd(cmd)
+ local func, err = load(cmd)
+ if not func then
+ print("error: ", err)
+ else
+ local status
+ status, err = pcall(func)
+ if not status then
+ print("error: ", err)
+ end
+ end
+ end
+ conth:start(scr)
+ started = true
+ end)
+end
+
+return exports
diff --git a/plugins/console/plugin.json b/plugins/console/plugin.json
new file mode 100644
index 00000000000..182bb887785
--- /dev/null
+++ b/plugins/console/plugin.json
@@ -0,0 +1,10 @@
+{
+ "plugin": {
+ "name": "console",
+ "description": "Console plugin",
+ "version": "0.0.1",
+ "author": "Carl",
+ "type": "plugin",
+ "start": "false"
+ }
+}
diff --git a/scripts/src/mame/frontend.lua b/scripts/src/mame/frontend.lua
index bb89b1b3350..be764f32a0e 100644
--- a/scripts/src/mame/frontend.lua
+++ b/scripts/src/mame/frontend.lua
@@ -66,8 +66,6 @@ files {
MAME_DIR .. "src/frontend/mame/cheat.h",
MAME_DIR .. "src/frontend/mame/clifront.cpp",
MAME_DIR .. "src/frontend/mame/clifront.h",
- MAME_DIR .. "src/frontend/mame/console.cpp",
- MAME_DIR .. "src/frontend/mame/console.h",
MAME_DIR .. "src/frontend/mame/info.cpp",
MAME_DIR .. "src/frontend/mame/info.h",
MAME_DIR .. "src/frontend/mame/language.cpp",
diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp
index 96281849884..40775af09c9 100644
--- a/src/frontend/mame/clifront.cpp
+++ b/src/frontend/mame/clifront.cpp
@@ -29,7 +29,6 @@
#include "ui/moptions.h"
#include "language.h"
#include "pluginopts.h"
-#include "console.h"
#include <new>
#include <ctype.h>
@@ -312,13 +311,7 @@ int cli_frontend::execute(int argc, char **argv)
manager->start_luaengine();
- if (m_options.console()) {
- //manager->lua()->start_console();
- console_frontend console(m_options, m_osd);
- 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/console.cpp b/src/frontend/mame/console.cpp
deleted file mode 100644
index 2bc834f5ad5..00000000000
--- a/src/frontend/mame/console.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Miodrag Milanovic
-/***************************************************************************
-
- console.c
-
- Console interface frontend for MAME.
-
-***************************************************************************/
-
-#include "emu.h"
-#include "luaengine.h"
-#include "console.h"
-#include "linenoise-ng/include/linenoise.h"
-#include "mame.h"
-
-#include <atomic>
-#include <thread>
-
-static console_frontend *gConsole = nullptr;
-//-------------------------------------------------
-// console_frontend - constructor
-//-------------------------------------------------
-
-console_frontend::console_frontend(emu_options &options, osd_interface &osd)
- : //m_options(options),
- //m_osd(osd),
- m_run(true),
- m_wait(false),
- m_prompt("\x1b[1;36m[MAME]\x1b[0m> ")
-{
- mame_machine_manager::instance()->lua()->sol()["quit"] = [this]() { cmd_quit(); };
- m_commands.push_back("quit()");
- mame_machine_manager::instance()->lua()->sol()["exit"] = [this]() { cmd_quit(); };
- m_commands.push_back("exit()");
- gConsole = this;
-}
-
-
-//-------------------------------------------------
-// ~console_frontend - destructor
-//-------------------------------------------------
-
-console_frontend::~console_frontend()
-{
-}
-
-void console_frontend::completion(char const* prefix, linenoiseCompletions* lc)
-{
- for (auto cmd : m_commands)
- {
- if (strncmp(prefix, cmd.c_str(), strlen(prefix)) == 0)
- {
- linenoiseAddCompletion(lc, cmd.c_str());
- }
- }
-}
-
-void console_frontend::cmd_quit()
-{
- printf("Exiting application\n");
- m_run.store(false);
- m_wait.store(false);
-}
-
-void console_frontend::read_console(std::string &cmdLine)
-{
- while (m_run.load())
- {
- while (m_wait.load())
- {
- using namespace std::chrono_literals;
- std::this_thread::sleep_for(100ms);
- }
- if (!m_run.load()) break;
- char* result = linenoise(m_prompt.c_str());
- if (result == NULL)
- {
- continue;
- }
- else if (*result == '\0') {
- free(result);
- continue;
- }
- cmdLine = std::string(result);
- linenoiseHistoryAdd(result);
- //m_prompt = "\x1b[1;36m[MAME]\x1b[0m \x1b[1;32m[test]\x1b[0m> ";
-
- free(result);
- m_wait.store(true);
- }
-}
-
-static void completionHook(char const* prefix, linenoiseCompletions* lc)
-{
- gConsole->completion(prefix, lc);
-}
-
-void console_frontend::start_console()
-{
- linenoiseInstallWindowChangeHandler();
- std::string cmdLine = "";
- const char* file = "./history";
-
- linenoiseHistoryLoad(file);
- linenoiseSetCompletionCallback(completionHook);
-
- // Display app info
- 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::thread cinThread(&console_frontend::read_console, this, std::ref(cmdLine));
-
- while (m_run.load())
- {
- if (m_wait.load())
- {
- mame_machine_manager::instance()->lua()->load_string(cmdLine.c_str());
- cmdLine.clear();
- m_wait.store(false);
- } else {
- using namespace std::chrono_literals;
- std::this_thread::sleep_for(100ms);
- }
- }
-
- m_run.store(false);
- cinThread.join();
-
- linenoiseHistorySave(file);
- linenoiseHistoryFree();
-}
diff --git a/src/frontend/mame/console.h b/src/frontend/mame/console.h
deleted file mode 100644
index 94405c7dc60..00000000000
--- a/src/frontend/mame/console.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Miodrag Milanovic
-/***************************************************************************
-
- console.c
-
- Console interface frontend for MAME.
-
-***************************************************************************/
-#ifndef MAME_FRONTEND_CONSOLE_H
-#define MAME_FRONTEND_CONSOLE_H
-
-#pragma once
-
-#include "emu.h"
-
-struct linenoiseCompletions;
-
-class console_frontend
-{
-public:
- // construction/destruction
- console_frontend(emu_options &options, osd_interface &osd);
- ~console_frontend();
-
- void start_console();
- void completion(char const* prefix, linenoiseCompletions* lc);
-
-private:
- void read_console(std::string &cmdLine);
-
- void cmd_quit();
- // internal state
- std::atomic<bool> m_run;
- std::atomic<bool> m_wait;
- std::string m_prompt;
-
- std::vector<std::string> m_commands;
-};
-
-#endif /* MAME_FRONTEND_CONSOLE_H */
diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp
index 616375fc2e9..e5fb9930db4 100644
--- a/src/frontend/mame/luaengine.cpp
+++ b/src/frontend/mame/luaengine.cpp
@@ -8,6 +8,7 @@
***************************************************************************/
+#include <thread>
#include <lua.hpp>
#include "emu.h"
#include "mame.h"
@@ -668,6 +669,11 @@ void lua_engine::on_frame_done()
execute_function("LUA_ON_FRAME_DONE");
}
+void lua_engine::on_periodic()
+{
+ execute_function("LUA_ON_PERIODIC");
+}
+
void lua_engine::attach_notifiers()
{
machine().add_notifier(MACHINE_NOTIFY_RESET, machine_notify_delegate(&lua_engine::on_machine_prestart, this), true);
@@ -702,6 +708,7 @@ void lua_engine::initialize()
* emu.register_resume(callback) - callback at resume
* emu.register_frame(callback) - callback at end of frame
* emu.register_frame_done(callback) - callback after frame is drawn to screen (for overlays)
+ * emu.register_periodic(callback) - periodic callback while program is running
* emu.register_menu(event_callback, populate_callback, name) - callbacks for plugin menu
* emu.print_verbose(str) -- output to stderr at verbose level
* emu.print_error(str) -- output to stderr at error level
@@ -735,6 +742,7 @@ void lua_engine::initialize()
emu["register_resume"] = [this](sol::function func){ register_function(func, "LUA_ON_RESUME"); };
emu["register_frame"] = [this](sol::function func){ register_function(func, "LUA_ON_FRAME"); };
emu["register_frame_done"] = [this](sol::function func){ register_function(func, "LUA_ON_FRAME_DONE"); };
+ emu["register_periodic"] = [this](sol::function func){ register_function(func, "LUA_ON_PERIODIC"); };
emu["register_menu"] = [this](sol::function cb, sol::function pop, const std::string &name) {
std::string cbfield = "menu_cb_" + name;
std::string popfield = "menu_pop_" + name;
@@ -767,6 +775,7 @@ void lua_engine::initialize()
}
return item;
};
+ emu["thread"] = []() { context *ctx = new context; ctx->busy = false; ctx->yield = false; return ctx; };
emu.new_usertype<emu_file>("file", sol::call_constructor, sol::constructors<sol::types<const char *, uint32_t>>(),
"read", [](emu_file &file, sol::buffer *buff) { buff->set_len(file.read(buff->get_ptr(), buff->get_len())); return buff; },
@@ -777,6 +786,64 @@ void lua_engine::initialize()
"filename", &emu_file::filename,
"fullpath", &emu_file::fullpath);
+/*
+ * thread.start(scr) - run scr (string not function) in a seperate thread in a new empty (other then modules) lua context
+ * thread.continue(val) - resume thread and pass val to it
+ * thread.result() - get thread result as string
+ * thread.busy - check if thread is running
+ * thread.yield - check if thread is yielded
+*/
+
+ sol().new_usertype<context>("thread",
+ sol::meta_function::garbage_collect, sol::destructor([](context *ctx) { delete ctx; }),
+ "start", [this](context &ctx, const char *scr) {
+ std::string script(scr);
+ if(ctx.busy)
+ return false;
+ std::thread th([&ctx, script]() {
+ sol::state thstate;
+ thstate.open_libraries();
+ thstate["package"]["preload"]["zlib"] = &luaopen_zlib;
+ thstate["package"]["preload"]["lfs"] = &luaopen_lfs;
+ thstate["package"]["preload"]["linenoise"] = &luaopen_linenoise;
+ sol::load_result res = thstate.load(script);
+ if(res.valid())
+ {
+ sol::protected_function func = res.get<sol::protected_function>();
+ thstate["yield"] = [&ctx, &thstate]() {
+ std::mutex m;
+ std::unique_lock<std::mutex> lock(m);
+ ctx.result = thstate["status"];
+ ctx.yield = true;
+ ctx.sync.wait(lock);
+ ctx.yield = false;
+ thstate["status"] = ctx.result;
+ };
+ auto ret = func();
+ if(ret.valid())
+ ctx.result = ret.get<const char *>();
+ }
+ ctx.busy = false;
+ });
+ ctx.busy = true;
+ ctx.yield = false;
+ th.detach();
+ return true;
+ },
+ "continue", [this](context &ctx, const char *val) {
+ if(!ctx.yield)
+ return;
+ ctx.result = val;
+ ctx.sync.notify_all();
+ },
+ "result", sol::property([this](context &ctx) -> std::string {
+ if(ctx.busy && !ctx.yield)
+ return "";
+ return ctx.result;
+ }),
+ "busy", sol::readonly(&context::busy),
+ "yield", sol::readonly(&context::yield));
+
sol().new_usertype<save_item>("item",
sol::meta_function::garbage_collect, sol::destructor([](save_item *item) { delete item; }),
"size", sol::readonly(&save_item::size),
diff --git a/src/frontend/mame/luaengine.h b/src/frontend/mame/luaengine.h
index 570008d808b..1da55b416f8 100644
--- a/src/frontend/mame/luaengine.h
+++ b/src/frontend/mame/luaengine.h
@@ -18,12 +18,11 @@
#define __LUA_ENGINE_H__
#include <map>
+#include <condition_variable>
#define SOL_SAFE_USERTYPE
//#define SOL_CHECK_ARGUMENTS
#include "sol2/sol.hpp"
-class cheat_manager;
-
struct lua_State;
class lua_engine
@@ -46,6 +45,7 @@ public:
std::vector<std::string> &get_menu() { return m_menu; }
void attach_notifiers();
void on_frame_done();
+ void on_periodic();
template<typename T, typename U>
bool call_plugin(const std::string &name, const T in, U &out)
@@ -153,6 +153,14 @@ private:
void close();
void run(sol::load_result res);
+
+ struct context
+ {
+ std::string result;
+ std::condition_variable sync;
+ bool busy;
+ bool yield;
+ };
};
#endif /* __LUA_ENGINE_H__ */
diff --git a/src/frontend/mame/mame.cpp b/src/frontend/mame/mame.cpp
index fa5cc2999e6..5bb5486b7f7 100644
--- a/src/frontend/mame/mame.cpp
+++ b/src/frontend/mame/mame.cpp
@@ -326,6 +326,7 @@ void emulator_info::draw_user_interface(running_machine& machine)
void emulator_info::periodic_check()
{
+ return mame_machine_manager::instance()->lua()->on_periodic();
}
bool emulator_info::frame_hook()