wxIScan
wxluascript.cpp
Go to the documentation of this file.
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 }