11#include " Std.h"
22#include < QLibraryInfo>
3+ #include < QFileSystemWatcher>
4+
35#include < pluginsdk/bridgemain.h>
46
57chaiscript::ChaiScript chai (chaiscript::Std_Lib::library());
68
9+
710#define plugin_name " CHAISCRIPTPLUGIN"
811#define plugin_version 1
912
@@ -14,6 +17,8 @@ int hMenuDisasm;
1417int hMenuDump;
1518int hMenuStack;
1619
20+ QFileSystemWatcher* fileWatcher = 0 ;
21+
1722std::string to_hex (int d, size_t digits = 2 ) {
1823 std::stringstream ss;
1924 ss << std::hex <<
@@ -23,24 +28,54 @@ std::string to_hex(int d, size_t digits = 2) {
2328 return ss.str ();
2429}
2530
26- bool chaiEval (int argc, char * argv[]) {
27- if (argc < 2 ) {
28- _plugin_logprintf (" Please specify a chai command\n " );
29- return true ;
30- }
31+ static std::set<std::string> commands;
32+ static std::set<std::string> workspace_set;
33+ static std::vector<std::string> workspace;
3134
35+ duint chaiEvalDirect (const char * cmd) {
3236 try {
33- auto bv = chai.eval (argv[1 ]);
34- if (bv.get_type_info ().is_arithmetic ()) {
35- return chai.boxed_cast <int >(bv);
37+ auto bv = chai.eval (cmd);
38+ if (bv.get_type_info ().is_arithmetic ()) {
39+ return chai.boxed_cast <duint>(bv);
40+ }
41+ if (bv.get_type_info ().name () == " bool" ) {
42+ return chai.boxed_cast <bool >(bv);
3643 }
37- return true ;
44+ _plugin_logprintf (" >>> bv type is: %s \n " , bv.get_type_info ().name ().c_str () );
45+ return 0 ;
3846 }
3947 catch ( const std::exception &e ) {
4048 _plugin_logprintf (" >>> Exception thrown: %s \n " , e.what ( ) );
4149 }
4250
43- return true ;
51+ return 0 ;
52+ }
53+
54+ bool chaiEvalCommand (int argc, char * argv[]) {
55+ if (argc == 0 )
56+ return false ;
57+ std::string cmdName = argv[0 ];
58+ auto pos = cmdName.find_first_of (" \t " );
59+ if (pos != std::string::npos)
60+ cmdName = cmdName.substr (0 , pos);
61+
62+ std::stringstream cmd;
63+ cmd << cmdName << " (" ;
64+ for (int i = 1 ;i < argc;i++) {
65+ if (i > 1 )
66+ cmd << " , " ;
67+ cmd << argv[i];
68+ }
69+ cmd << " )" ;
70+ return chaiEvalDirect (cmd.str ().c_str ());
71+ }
72+
73+
74+ bool chaiEval (int argc, char * argv[]) {
75+ if (argc < 2 )
76+ return false ;
77+
78+ return chaiEvalDirect (argv[1 ]);
4479}
4580
4681bool chaiShowEnv (int argc, char * argv[]) {
@@ -62,15 +97,41 @@ bool chaiShowEnv(int argc, char* argv[]) {
6297 _plugin_logprintf (" %s, " , func.first .c_str () );
6398 }
6499 }
100+
101+ _plugin_logprintf (" \n Workspace: \n " );
102+ for (const auto &script : workspace) {
103+ if (std::regex_search (script, reg)) {
104+ _plugin_logprintf (" \t %s\n " , script.c_str () );
105+ }
106+ }
107+
108+ _plugin_logprintf (" \n Commands: \n " );
109+ for (const auto &command : commands) {
110+ if (std::regex_search (command, reg)) {
111+ _plugin_logprintf (" \t %s\n " , command.c_str () );
112+ }
113+ }
65114 _plugin_logprintf (" \n\n " );
66115
67116 return true ;
68117}
69118
70- static void _chaiLoad (const std::string& fileName) {
119+ static void _chaiLoad (const std::string& fileName, bool reload = false ) {
71120 try {
72121 chai.eval_file (fileName);
73- _plugin_logprintf (" >>> [" plugin_name " ] Loaded %s \n " , fileName.c_str () );
122+ if (workspace_set.find (fileName) == workspace_set.end ()) {
123+ workspace.push_back (fileName);
124+ workspace_set.insert (fileName);
125+ if (fileWatcher) {
126+ QString qtFileName (fileName.c_str ());
127+ fileWatcher->addPath (qtFileName);
128+ }
129+ }
130+ if (reload) {
131+ _plugin_logprintf (" >>> [" plugin_name " ] Reloaded %s on modifcation\n " , fileName.c_str () );
132+ } else {
133+ _plugin_logprintf (" >>> [" plugin_name " ] Loaded %s \n " , fileName.c_str () );
134+ }
74135 }
75136 catch ( const std::exception &e ) {
76137 _plugin_logprintf (" >>> Exception thrown: %s \n " , e.what ( ) );
@@ -86,6 +147,52 @@ static void _chaiLoad() {
86147 _chaiLoad (fileName);
87148 }
88149}
150+ bool chaiClearWorkspace (int argc, char * argv[]) {
151+ for (auto script : workspace) {
152+ QString path (script.c_str ());
153+ if (fileWatcher)
154+ fileWatcher->removePath (path);
155+ }
156+ commands.clear ();
157+ workspace.clear ();
158+ workspace_set.clear ();
159+ return true ;
160+ }
161+
162+ duint chaiExpr (int argc, const duint* argv, void * usrdata) {
163+ std::string& cmdName = *(std::string*)usrdata;
164+ std::stringstream cmd;
165+ cmd << cmdName << " (" ;
166+ for (int i = 0 ;i < argc;i++) {
167+ if (i != 0 )
168+ cmd << " , " ;
169+ cmd << argv[i];
170+ }
171+ cmd << " )" ;
172+ return chaiEvalDirect (cmd.str ().c_str ());
173+ }
174+
175+ bool chaiRegisterCommand (const char * cmd) {
176+ commands.insert (cmd);
177+
178+ const auto funcs = chai.get_state ().engine_state .m_boxed_functions ;
179+ try {
180+ const chaiscript::Boxed_Value& c = chai.eval (std::string (cmd) + " .get_arity()" );
181+ int arity = chaiscript::boxed_cast<int >(c);
182+ _plugin_registerexprfunctionuserdata (pluginHandle, cmd, arity, chaiExpr, new std::string (cmd));
183+ }
184+ catch ( const std::exception &e ) {
185+ _plugin_logprintf (" >>> Exception thrown: %s \n " , e.what ( ) );
186+ }
187+ return _plugin_registercommand (pluginHandle, cmd, chaiEvalCommand, false );
188+ }
189+
190+ bool chaiRegisterCommand (int argc, char * argv[]) {
191+ if (argc < 2 ) {
192+ return false ;
193+ }
194+ return chaiRegisterCommand (argv[1 ]);
195+ }
89196
90197bool chaiLoad (int argc, char * argv[]) {
91198 std::string fileName = " " ;
@@ -129,29 +236,85 @@ static void registerChaiFunctions() {
129236#define DBG_FUNCTION (x ) chai.add(chaiscript::fun(FunctionWrapper(&x, 0 )), Sanitize(#x));
130237#include " dbgops.h"
131238
239+ chai.add (chaiscript::type_conversion<int , duint>());
240+ chai.add (chaiscript::type_conversion<unsigned int , duint>());
132241}
133242
134- extern " C" DLL_EXPORT bool plugstop () {
135- return true ;
243+ static void saveCache (CBTYPE cbType, void * callbackInfo) {
244+ PLUG_CB_LOADSAVEDB * loadSaveInfo = (PLUG_CB_LOADSAVEDB *)callbackInfo;
245+
246+ json_t * chaiScriptRoot = json_object ();
247+
248+ if (!workspace.empty ()) {
249+ json_t * loadedScripts = json_array ();
250+ for (auto script : workspace) {
251+ json_array_append_new (loadedScripts, json_string (script.c_str ()));
252+ }
253+ json_object_set (chaiScriptRoot, " workspace" , loadedScripts);
254+ }
255+
256+ if (!commands.empty ()) {
257+ json_t * definedCommands = json_array ();
258+ for (auto command : commands) {
259+ json_array_append_new (definedCommands, json_string (command.c_str ()));
260+ }
261+ json_object_set (chaiScriptRoot, " commands" , definedCommands);
262+ }
263+
264+ json_object_set (loadSaveInfo->root , " chaiScript" , chaiScriptRoot);
136265}
137266
267+ static void loadCache (CBTYPE cbType, void * callbackInfo) {
268+ PLUG_CB_LOADSAVEDB * loadSaveInfo = (PLUG_CB_LOADSAVEDB *)callbackInfo;
269+
270+ json_t * chaiScriptRoot = json_object_get (loadSaveInfo->root , " chaiScript" );
271+ if (chaiScriptRoot == 0 )
272+ return ;
273+
274+ json_t * loadedScripts = json_object_get (chaiScriptRoot, " workspace" );
275+
276+ for (size_t i = 0 ;i < json_array_size (loadedScripts);i++) {
277+ _chaiLoad ( json_string_value ( json_array_get (loadedScripts, i) ) );
278+ }
279+
280+ json_t * definedCommands = json_object_get (chaiScriptRoot, " commands" );
281+
282+ for (size_t i = 0 ;i < json_array_size (definedCommands);i++) {
283+ chaiRegisterCommand (json_string_value (json_array_get (definedCommands, i)));
284+ }
285+ }
286+
287+
138288extern " C" DLL_EXPORT bool pluginit (PLUG_INITSTRUCT * initStruct) {
139289 initStruct->pluginVersion = plugin_version;
140290 initStruct->sdkVersion = PLUG_SDKVERSION ;
141- strcpy (initStruct->pluginName , plugin_name);
291+ strncpy_s (initStruct->pluginName , sizeof (initStruct-> pluginName ), plugin_name, sizeof (initStruct-> pluginName ) );
142292 pluginHandle = initStruct->pluginHandle ;
143293
144294 _plugin_logprintf (" [ChaiScript] Qt version %s\n " , QLibraryInfo::build ());
145295
146296 if (!_plugin_registercommand (pluginHandle, " chaiEval" , chaiEval, false ))
147- _plugin_logputs (" error registering the \" exec \" command!" );
297+ _plugin_logputs (" error registering the \" chaiEval \" command!" );
148298
149299 if (!_plugin_registercommand (pluginHandle, " chaiLoad" , chaiLoad, false ))
150- _plugin_logputs (" error registering the \" exec \" command!" );
300+ _plugin_logputs (" error registering the \" chaiLoad \" command!" );
151301
152302 if (!_plugin_registercommand (pluginHandle, " chaiShowEnv" , chaiShowEnv, false ))
153- _plugin_logputs (" error registering the \" exec\" command!" );
303+ _plugin_logputs (" error registering the \" chaiShowEnv\" command!" );
304+
305+ if (!_plugin_registercommand (pluginHandle, " chaiClearWorkspace" , chaiClearWorkspace, false ))
306+ _plugin_logputs (" error registering the \" chaiClearWorkspace\" command!" );
307+
308+ if (!_plugin_registercommand (pluginHandle, " chaiRegisterCommand" , chaiRegisterCommand, false ))
309+ _plugin_logputs (" error registering the \" chaiRegisterCommand\" command!" );
310+
311+ fileWatcher = new QFileSystemWatcher ();
312+ QObject::connect (fileWatcher, &QFileSystemWatcher::fileChanged, [] (const QString& path) {
313+ _chaiLoad (path.toStdString (), true );
314+ });
154315
316+ _plugin_registercallback (pluginHandle, CBTYPE ::CB_SAVEDB , saveCache);
317+ _plugin_registercallback (pluginHandle, CBTYPE ::CB_LOADDB , loadCache);
155318 return true ;
156319}
157320
@@ -165,6 +328,12 @@ extern "C" DLL_EXPORT void plugsetup(PLUG_SETUPSTRUCT* setupStruct) {
165328 registerChaiFunctions ();
166329}
167330
331+ extern " C" DLL_EXPORT bool plugstop () {
332+ delete fileWatcher;
333+ fileWatcher = 0 ;
334+ return true ;
335+ }
336+
168337extern " C" DLL_EXPORT BOOL APIENTRY DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
169338 return TRUE ;
170339}
0 commit comments