![]() |
wxIScan
|
00001 /*************************************************************** 00002 * Name: wxluascript.h 00003 * Purpose: Defines a lua scripting object 00004 * Author: Daniel Nell (daniel.nell@nellresearch.de) 00005 * Created: 2009-11-11 00006 * Copyright: Daniel Nell (www.nellresearch.de) 00007 * License: wxWindows license 00008 **************************************************************/ 00009 00010 // Include precompiled headers. 00011 #include "wx_pch.h" 00012 00013 // wxWidgets headers 00014 // ... 00015 00016 // Private header files. 00017 #include "wxluascript.h" 00018 00019 00020 ///////////////////////////////////////////////////////////////////////////// 00021 // Class wxLuaScript (scripting support) 00022 // 00023 // ... 00024 // 00025 00026 #if __WXLUASCRIPT_DYNAMIC__ 00027 // Define dynamic library. 00028 wxDynamicLibrary wxLuaScript::m_oWxLuaScriptDynamicLibrary; 00029 00030 // Define and initialize dynamic lua functions with NULL; 00031 wxLuaScript::t_luaL_newstate *wxLuaScript::luaL_newstate= NULL; 00032 wxLuaScript::t_luaL_openlibs *wxLuaScript::luaL_openlibs= NULL; 00033 wxLuaScript::t_lua_atpanic *wxLuaScript::lua_atpanic= NULL; 00034 wxLuaScript::t_lua_error *wxLuaScript::lua_error= NULL; 00035 wxLuaScript::t_lua_gettop *wxLuaScript::lua_gettop= NULL; 00036 wxLuaScript::t_luaL_loadstring *wxLuaScript::luaL_loadstring= NULL; 00037 wxLuaScript::t_lua_pushstring *wxLuaScript::lua_pushstring= NULL; 00038 wxLuaScript::t_lua_pushinteger *wxLuaScript::lua_pushinteger= NULL; 00039 wxLuaScript::t_lua_pushboolean *wxLuaScript::lua_pushboolean= NULL; 00040 wxLuaScript::t_lua_tointeger *wxLuaScript::lua_tointeger= NULL; 00041 wxLuaScript::t_lua_tolstring *wxLuaScript::lua_tolstring= NULL; 00042 wxLuaScript::t_lua_tonumber *wxLuaScript::lua_tonumber= NULL; 00043 wxLuaScript::t_lua_toboolean *wxLuaScript::lua_toboolean= NULL; 00044 wxLuaScript::t_lua_isnumber *wxLuaScript::lua_isnumber= NULL; 00045 wxLuaScript::t_lua_type *wxLuaScript::lua_type= NULL; 00046 wxLuaScript::t_lua_isstring *wxLuaScript::lua_isstring= NULL; 00047 wxLuaScript::t_lua_pushcclosure *wxLuaScript::lua_pushcclosure= NULL; 00048 wxLuaScript::t_lua_call *wxLuaScript::lua_call= NULL; 00049 wxLuaScript::t_lua_pcall *wxLuaScript::lua_pcall= NULL; 00050 wxLuaScript::t_lua_cpcall *wxLuaScript::lua_cpcall= NULL; 00051 wxLuaScript::t_lua_settable *wxLuaScript::lua_settable= NULL; 00052 wxLuaScript::t_lua_setfield *wxLuaScript::lua_setfield= NULL; 00053 wxLuaScript::t_lua_getfield *wxLuaScript::lua_getfield= NULL; 00054 wxLuaScript::t_lua_settop *wxLuaScript::lua_settop= NULL; 00055 wxLuaScript::t_lua_insert *wxLuaScript::lua_insert= NULL; 00056 wxLuaScript::t_lua_pushvalue *wxLuaScript::lua_pushvalue= NULL; 00057 wxLuaScript::t_lua_close *wxLuaScript::lua_close= NULL; 00058 wxLuaScript::t_lua_createtable *wxLuaScript::lua_createtable= NULL; 00059 wxLuaScript::t_lua_pushlightuserdata *wxLuaScript::lua_pushlightuserdata= NULL; 00060 wxLuaScript::t_lua_topointer *wxLuaScript::lua_topointer= NULL; 00061 wxLuaScript::t_lua_gettable *wxLuaScript::lua_gettable= NULL; 00062 wxLuaScript::t_lua_pushnumber *wxLuaScript::lua_pushnumber= NULL; 00063 #endif // __WXLUASCRIPT_DYNAMIC__ 00064 00065 // Standard constructor. 00066 // 00067 wxLuaScript::wxLuaScript( const wxString& strScript, wxEvtHandler *poParent, 00068 const wxString& strDomain, bool *pbParentState ) 00069 #if __WXLUASCRIPT_DYNAMIC__ 00070 : m_bOk( true ) 00071 #endif // __WXLUASCRIPT_DYNAMIC__ 00072 { 00073 // Initialize members. 00074 m_strScript= strScript; 00075 m_poParent= poParent; 00076 m_strDomain= strDomain; 00077 m_pbParentState= pbParentState; 00078 if( m_pbParentState ) 00079 { 00080 (*m_pbParentState)= true; 00081 } 00082 00083 #if __WXLUASCRIPT_DYNAMIC__ 00084 if( !m_oWxLuaScriptDynamicLibrary.IsLoaded() ) 00085 { 00086 if( m_oWxLuaScriptDynamicLibrary.Load( wxDynamicLibrary::CanonicalizeName( wxT( WXLUASCRIPT_LIBLUA ) ), 00087 wxDL_DEFAULT | wxDL_GLOBAL ) ) 00088 { 00089 luaL_newstate= (t_luaL_newstate *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "luaL_newstate" ) ); 00090 luaL_openlibs= (t_luaL_openlibs *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "luaL_openlibs" ) ); 00091 lua_atpanic= (t_lua_atpanic *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_atpanic" ) ); 00092 lua_error= (t_lua_error *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_error" ) ); 00093 lua_gettop= (t_lua_gettop *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_gettop" ) ); 00094 luaL_loadstring= (t_luaL_loadstring *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "luaL_loadstring" ) ); 00095 lua_pushstring= (t_lua_pushstring *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_pushstring" ) ); 00096 lua_pushinteger= (t_lua_pushinteger *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_pushinteger" ) ); 00097 lua_pushboolean= (t_lua_pushboolean *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_pushboolean" ) ); 00098 lua_tointeger= (t_lua_tointeger *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_tointeger" ) ); 00099 lua_tolstring= (t_lua_tolstring *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_tolstring" ) ); 00100 lua_tonumber= (t_lua_tonumber *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_tonumber" ) ); 00101 lua_toboolean= (t_lua_toboolean *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_toboolean" ) ); 00102 lua_isnumber= (t_lua_isnumber *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_isnumber" ) ); 00103 lua_type= (t_lua_type *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_type" ) ); 00104 lua_isstring= (t_lua_isstring *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_isstring" ) ); 00105 lua_pushcclosure= (t_lua_pushcclosure *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_pushcclosure" ) ); 00106 lua_call= (t_lua_call *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_call" ) ); 00107 lua_pcall= (t_lua_pcall *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_pcall" ) ); 00108 lua_cpcall= (t_lua_cpcall *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_cpcall" ) ); 00109 lua_settable= (t_lua_settable *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_settable" ) ); 00110 lua_setfield= (t_lua_setfield *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_setfield" ) ); 00111 lua_getfield= (t_lua_getfield *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_getfield" ) ); 00112 lua_settop= (t_lua_settop *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_settop" ) ); 00113 lua_insert= (t_lua_insert *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_insert" ) ); 00114 lua_pushvalue= (t_lua_pushvalue *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_pushvalue" ) ); 00115 lua_close= (t_lua_close *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_close" ) ); 00116 lua_createtable= (t_lua_createtable *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_createtable" ) ); 00117 lua_pushlightuserdata= (t_lua_pushlightuserdata *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_pushlightuserdata" ) ); 00118 lua_topointer= (t_lua_topointer *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_topointer" ) ); 00119 lua_gettable= (t_lua_gettable *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_gettable" ) ); 00120 lua_pushnumber= (t_lua_pushnumber *)m_oWxLuaScriptDynamicLibrary.GetSymbol( wxT( "lua_pushnumber" ) ); 00121 } 00122 else 00123 { 00124 // Remember the state; 00125 m_bOk= false; 00126 00127 #if __DEBUG__ 00128 // Log waring message in DEBUG mode. 00129 wxLogWarning( wxString( wxT( "wxLuaScript::wxLuaScript -- " ) ) 00130 + _( "Cannot load Lua library." ) ); 00131 #endif // __DEBUG__ 00132 return; 00133 } 00134 } 00135 #endif // __WXLUASCRIPT_DYNAMIC__ 00136 00137 // Initialize Lua. 00138 L= luaL_newstate(); 00139 00140 // Load Lua base libraries. 00141 luaL_openlibs( L ); 00142 00143 // Register an error handler (since there may be fatal Lua errors). 00144 lua_atpanic( L, LuaAtPanic ); 00145 00146 // Register the this pointer (to the current wxLuaScript object) 00147 // as a global value called "this". 00148 lua_pushinteger( L, (long)this ); 00149 lua_setglobal( L, "this" ); 00150 00151 // Register "SendMenuEvent" as Lua function. 00152 RegisterFunction( wxT( "SendMenuEvent" ), SendMenuEvent ); 00153 00154 // Register "LogMessage" as Lua function. 00155 RegisterFunction( wxT( "LogMessage" ), LogMessage ); 00156 } 00157 00158 // Virtual destructor. 00159 // 00160 wxLuaScript::~wxLuaScript() 00161 { 00162 // Cleanup Lua. 00163 #if __WXLUASCRIPT_DYNAMIC__ 00164 if( IsOk() ) 00165 { 00166 lua_close( L ); 00167 } 00168 #else 00169 lua_close( L ); 00170 #endif // __WXLUASCRIPT_DYNAMIC__ 00171 } 00172 00173 // Register a new (LuaC-)function to Lua. (Lower level function.) 00174 // 00175 void wxLuaScript::RegisterFunction( lua_State* L, const char *pszTableName, 00176 const char * pszFuncName, lua_CFunction pLuaCFunction) 00177 { 00178 lua_getfield( L, LUA_GLOBALSINDEX, pszTableName ); // push table onto stack 00179 if( !lua_istable( L, -1 ) ) // not a table, create it 00180 { 00181 lua_createtable( L, 0, 1 ); // create new table 00182 lua_setfield( L, LUA_GLOBALSINDEX, pszTableName) ; // add it to global context 00183 00184 // reset table on stack: 00185 lua_pop( L, 1 ); // pop table (nil value) from stack 00186 lua_getfield( L, LUA_GLOBALSINDEX, pszTableName ); // push table onto stack 00187 } 00188 00189 lua_pushstring( L, pszFuncName ); // push key onto stack 00190 lua_pushcfunction( L, pLuaCFunction ); // push value onto stack 00191 lua_settable( L, -3 ); // add key-value pair to table 00192 00193 lua_pop( L, 1 ); // pop table from stack 00194 } 00195 00196 // Register new accessors for variables to Lua. 00197 // 00198 void wxLuaScript::RegisterVariable( const wxString& strLuaVarName, const int *pnValue ) 00199 { 00200 lua_gettable( L, LUA_GLOBALSINDEX ); 00201 lua_pushlightuserdata( L, (void *)pnValue ); 00202 lua_pushcclosure( L, wxLuaScript::LuaIntVarAccessor, 1 ); 00203 lua_setfield( L, LUA_GLOBALSINDEX, strLuaVarName.char_str() ); 00204 } 00205 00206 int wxLuaScript::LuaIntVarAccessor( lua_State *L ) 00207 { 00208 int *p = (int *)lua_topointer( L, lua_upvalueindex( 1 ) ); 00209 00210 if( lua_gettop( L ) == 0 ) 00211 { // stack empty, so get 00212 lua_pushinteger( L, *p ); 00213 return 1; 00214 } 00215 else 00216 { // arg provided, so set 00217 *p = lua_tointeger( L, 1 ); 00218 return 0; 00219 } 00220 } 00221 00222 void wxLuaScript::RegisterVariable( const wxString& strLuaVarName, const bool *pnValue ) 00223 { 00224 lua_gettable( L, LUA_GLOBALSINDEX ); 00225 lua_pushlightuserdata( L, (void *)pnValue ); 00226 lua_pushcclosure( L, wxLuaScript::LuaBoolVarAccessor, 1 ); 00227 lua_setfield( L, LUA_GLOBALSINDEX, strLuaVarName.char_str() ); 00228 } 00229 00230 int wxLuaScript::LuaBoolVarAccessor( lua_State *L ) 00231 { 00232 bool *p = (bool *)lua_topointer( L, lua_upvalueindex( 1 ) ); 00233 00234 if( lua_gettop( L ) == 0 ) 00235 { // stack empty, so get 00236 lua_pushboolean( L, *p ); 00237 return 1; 00238 } 00239 else 00240 { // arg provided, so set 00241 *p = lua_toboolean( L, 1 ); 00242 return 0; 00243 } 00244 } 00245 00246 void wxLuaScript::RegisterVariable( const wxString& strLuaVarName, const double *pnValue ) 00247 { 00248 lua_gettable( L, LUA_GLOBALSINDEX ); 00249 lua_pushlightuserdata( L, (void *)pnValue ); 00250 lua_pushcclosure( L, wxLuaScript::LuaDoubleVarAccessor, 1 ); 00251 lua_setfield( L, LUA_GLOBALSINDEX, strLuaVarName.char_str() ); 00252 } 00253 00254 int wxLuaScript::LuaDoubleVarAccessor( lua_State *L ) 00255 { 00256 double *p = (double *)lua_topointer( L, lua_upvalueindex( 1 ) ); 00257 00258 if( lua_gettop( L ) == 0 ) 00259 { // stack empty, so get 00260 lua_pushnumber( L, *p ); 00261 return 1; 00262 } 00263 else 00264 { // arg provided, so set 00265 *p = (double)lua_tonumber( L, 1 ); 00266 return 0; 00267 } 00268 } 00269 00270 void wxLuaScript::RegisterVariable( const wxString& strLuaVarName, const wxString *pstrValue ) 00271 { 00272 lua_gettable( L, LUA_GLOBALSINDEX ); 00273 lua_pushlightuserdata( L, (void *)pstrValue ); 00274 lua_pushcclosure( L, wxLuaScript::LuaStringVarAccessor, 1 ); 00275 lua_setfield( L, LUA_GLOBALSINDEX, strLuaVarName.char_str() ); 00276 } 00277 00278 int wxLuaScript::LuaStringVarAccessor( lua_State *L ) 00279 { 00280 wxString *p = (wxString *)lua_topointer( L, lua_upvalueindex( 1 ) ); 00281 00282 if( lua_gettop( L ) == 0 ) 00283 { // stack empty, so get 00284 lua_pushstring( L, p->char_str( wxConvISO8859_1 ) ); 00285 return 1; 00286 } 00287 else 00288 { // arg provided, so set 00289 (*p)= wxString( lua_tostring( L, 1 ), wxConvISO8859_1 ); 00290 return 0; 00291 } 00292 } 00293 00294 // Get the this-pointer from Lua. 00295 // 00296 wxLuaScript *wxLuaScript::GetThis( lua_State* L ) 00297 { 00298 // Get the this-pointer from Lua. 00299 lua_getglobal( L, "this" ); 00300 return (wxLuaScript *)lua_tointeger( L, -1 ); 00301 } 00302 00303 // Run the Lua script in memory in protected mode. 00304 // 00305 // Note: This function is already called by Lua. 00306 // Therefore we can get error context, too. 00307 // 00308 int wxLuaScript::Run( lua_State* L ) 00309 { 00310 // Get the this-pointer to the current wxLuaScript object. 00311 wxLuaScript *poThis= GetThis( L ); 00312 00313 if( luaL_loadstring( L, poThis->m_strScript.char_str() ) ) 00314 { 00315 // Log an error message. 00316 wxLogError( wxString( wxT( "int wxLuaScript::Run( lua_State* L ) -- " ) ) 00317 + _( "Cannot initialize Lua script." ) ); 00318 00319 // Return the number of (Lua) results. 00320 return 0; 00321 } 00322 00323 // Insert TraceBack function. 00324 int base= lua_gettop(L); /* function index */ 00325 lua_pushcfunction( L, wxLuaScript::TraceBack ); /* push traceback function */ 00326 lua_insert( L, base ); /* put it under chunk and args */ 00327 00328 // Run the script (from memory) and output an error 00329 // message if there was an error running the script. 00330 if( lua_pcall( L, 0, 0, base ) 00331 && !lua_isnil( L, -1 ) ) 00332 { 00333 // Get the error message and log it. 00334 wxLogError( wxString( (const char *)lua_tostring( L, -1 ), wxConvISO8859_1 ) ); 00335 } 00336 00337 // Return the number of (Lua) results. 00338 return 0; 00339 } 00340 00341 // Create a stack trace on the Lua stack. 00342 // 00343 int wxLuaScript::TraceBack( lua_State* L ) 00344 { 00345 if( !lua_isstring(L, 1) ) /* 'message' not a string? */ 00346 { 00347 return 1; /* keep it intact */ 00348 } 00349 lua_getfield(L, LUA_GLOBALSINDEX, "debug"); 00350 if( !lua_istable( L, -1 ) ) 00351 { 00352 lua_pop( L, 1 ); 00353 return 1; 00354 } 00355 lua_getfield( L, -1, "traceback" ); 00356 if( !lua_isfunction( L, -1 ) ) 00357 { 00358 lua_pop( L, 2 ); 00359 return 1; 00360 } 00361 lua_pushvalue( L, 1 ); /* pass error message */ 00362 lua_pushinteger( L, 2 ); /* skip this function and traceback */ 00363 lua_call( L, 2, 1 ); /* call debug.traceback */ 00364 return 1; 00365 } 00366 00367 // Error handler for (maybe fatal) Lua errors. 00368 // 00369 int wxLuaScript::LuaAtPanic( lua_State* L ) 00370 { 00371 // Get the error message and log it. 00372 wxLogError( wxString( (const char *)lua_tostring( L, 1 ), wxConvISO8859_1 ) ); 00373 00374 // Return the number of (Lua) results. 00375 return 0; 00376 } 00377 00378 // Log a message on the standard wxWidgets log target. 00379 // 00380 // Note: You can change the standard log target and the 00381 // messages you log are logged to the new target, too. 00382 // 00383 int wxLuaScript::LogMessage( lua_State* L ) 00384 { 00385 // Check the number of argument(s) and the type(s). 00386 if( ( lua_gettop( L ) != 1 ) || !lua_isstring( L, 1 ) ) 00387 { 00388 // Signal error. 00389 lua_pushstring( L, "Incorrect argument or incorrect number of arguments." ); 00390 lua_error( L ); 00391 } 00392 00393 // Get the message and log it. 00394 wxLogMessage( wxString( (const char *)lua_tostring( L, 1 ), wxConvISO8859_1 ) ); 00395 00396 // Return the number of (Lua) results. 00397 return 0; 00398 } 00399 00400 // Send a menu event to the parent event handler. 00401 // 00402 int wxLuaScript::SendMenuEvent( lua_State* L ) 00403 { 00404 // Check the number of (Lua) argument(s) and the type(s). 00405 if( ( lua_gettop( L ) != 1 ) || !lua_isnumber( L, 1 ) ) 00406 { 00407 // Signal error. 00408 lua_pushstring( L, "Incorrect argument or incorrect number of arguments." ); 00409 lua_error( L ); 00410 } 00411 00412 // Get the this pointer to the current wxLuaScript object. 00413 wxLuaScript *poThis= GetThis( L ); 00414 00415 // Get the pointer to the event handler. 00416 wxEvtHandler *poParent= poThis->m_poParent; 00417 00418 // Post the message (if possible). 00419 if( poParent ) 00420 { 00421 // Process the corresponding wxWidgets menu event. 00422 // 00423 // NOTE: We get the adress of the this-pointer from Lua 00424 // (for this is a static function, and we need it 00425 // to call the correct event handler). 00426 wxCommandEvent oEvent( wxEVT_COMMAND_MENU_SELECTED, lua_tonumber( L, 1 ) ); 00427 00428 if( poParent->ProcessEvent( oEvent ) ) 00429 { 00430 // Push the return value ( the parent state ); 00431 if( poThis->m_pbParentState ) 00432 { 00433 lua_pushboolean( L, *poThis->m_pbParentState ); 00434 (*poThis->m_pbParentState)= true; 00435 } 00436 else 00437 { 00438 lua_pushboolean( L, true ); 00439 } 00440 } 00441 else 00442 { 00443 // Push an error value for the event could not be handled 00444 // or a proper event handler could not be found. 00445 #if __DEBUG__ 00446 wxLogWarning( wxT( "wxLuaScript::SendMenuEvent -- Could not handle the event." ) ); 00447 #endif 00448 lua_pushboolean( L, false ); 00449 } 00450 } 00451 else 00452 { 00453 // Push an error value for there is no parent to post the 00454 // message. 00455 lua_pushboolean( L, false ); 00456 } 00457 00458 // Return the number of (Lua) results. 00459 return 1; 00460 }