Difference between revisions of "Script lua"
(Created page with "Script_lua is a basic example plugin. This wiki page is intended as a walkthrough of the code in order to help you better understand the SDK. ==Functionality== This plugin ...") |
|||
Line 1: | Line 1: | ||
Script_lua is a basic example plugin. This wiki page is intended as a walkthrough of the code in order to help you better understand the SDK. | Script_lua is a basic example plugin. This wiki page is intended as a walkthrough of the code in order to help you better understand the SDK. | ||
− | |||
− | |||
− | |||
This plugin serves as a Lua script interpreter. | This plugin serves as a Lua script interpreter. | ||
Line 9: | Line 6: | ||
===Declarations=== | ===Declarations=== | ||
+ | |||
+ | This is a struct that defines certain objects and constants that will be used by the plugin. | ||
typedef struct st_IntrInstance { | typedef struct st_IntrInstance { | ||
Line 23: | Line 22: | ||
} IntrInstance; | } IntrInstance; | ||
− | + | Declaration of functions that will be used by the plugin. | |
extern "C" int l_lxout(lua_State *L); | extern "C" int l_lxout(lua_State *L); | ||
Line 38: | Line 37: | ||
extern "C" int l_lxmonStep(lua_State *L); | extern "C" int l_lxmonStep(lua_State *L); | ||
− | + | Here we declare a variety of scripts and services that will be used below. "extern" indicates that the objects inside have already been defined elsewhere so the compiler won't complain. | |
extern "C" { | extern "C" { | ||
Line 49: | Line 48: | ||
} | } | ||
− | |||
− | |||
===Class Declarations=== | ===Class Declarations=== | ||
+ | |||
+ | This class is intended to take a lua script and interpret it, so we need it to be a modified text editor. To this end, we inherit from [[Scripts_(lx-scripts.hpp)#Text_Script_Interpreter|CLxImpl_TextScriptInterpreter]]. | ||
class CLuaInterpreter : public CLxImpl_TextScriptInterpreter | class CLuaInterpreter : public CLxImpl_TextScriptInterpreter | ||
Line 80: | Line 79: | ||
lua_State *L; | lua_State *L; | ||
}; | }; | ||
− | |||
− | |||
===[[Server_Tags|Server Tags]]=== | ===[[Server_Tags|Server Tags]]=== | ||
+ | |||
+ | LXtTagInfoDesc CLuaInterpreter::descInfo[] = { | ||
+ | { LXsSRV_USERNAME, "Lua Scripts" }, | ||
+ | { LXsLOD_DOSPATTERN, "*.lua" }, | ||
+ | { 0 } | ||
+ | }; | ||
The tags here indicate that CLuaInterpreter has the name Lua Scripts and takes files with the .lua extension. | The tags here indicate that CLuaInterpreter has the name Lua Scripts and takes files with the .lua extension. | ||
===[[Initialize_(index)|Initialize]]=== | ===[[Initialize_(index)|Initialize]]=== | ||
+ | |||
+ | This initialize function exports one server of the type TextScriptInterpreter that is dependent on the class CLuaInterpreter and has the name lua. | ||
void | void | ||
Line 94: | Line 99: | ||
LXx_ADD_SERVER (TextScriptInterpreter, CLuaInterpreter, "lua"); | LXx_ADD_SERVER (TextScriptInterpreter, CLuaInterpreter, "lua"); | ||
} | } | ||
− | |||
− | |||
===Implementations=== | ===Implementations=== | ||
+ | |||
+ | Add a string to a parent log, possibly returning a log entry for sub-entries | ||
static void | static void | ||
Line 112: | Line 117: | ||
} | } | ||
− | + | Adding a log entry to a parent, for clients with no need for the entry. | |
void | void | ||
Line 126: | Line 131: | ||
} | } | ||
− | + | Logging for clients with no need for the entry. | |
void | void | ||
Line 139: | Line 144: | ||
} | } | ||
− | + | lxout: Output a string to the log | |
int | int | ||
Line 154: | Line 159: | ||
} | } | ||
− | + | Internal function to perform queries and executions | |
#define LXEVALMODEf_QUERY 1 // Query only; fail if no query is marked | #define LXEVALMODEf_QUERY 1 // Query only; fail if no query is marked | ||
Line 366: | Line 371: | ||
} | } | ||
− | + | At some point in the future, lxq() needs to use the raw string conversion feature to ensure that the values that are queried are the same kinds of values that get passed to commands. | |
int | int | ||
Line 377: | Line 382: | ||
} | } | ||
− | + | lxqt(): Query a toggle command's toggle argument. Returns the query state on success (1 or 0), or 0 on failure. | |
int | int | ||
Line 425: | Line 430: | ||
} | } | ||
− | + | Return true if the last command executed/queried successfully. | |
int | int | ||
Line 434: | Line 439: | ||
} | } | ||
− | Return | + | Return the LxResult code of the last command executed or quieried. |
int | int | ||
Line 443: | Line 448: | ||
} | } | ||
− | + | When activated, lx() and lxq() data is output to the event log. If no args are passed in, this returns if tracing is active or not. | |
int | int | ||
Line 463: | Line 468: | ||
} | } | ||
− | + | Get the state of an option. | |
int | int | ||
Line 516: | Line 521: | ||
} | } | ||
− | + | Initialize the progress bar. Initialize the progress bar with n total steps. Returns 0 on error. | |
int | int | ||
Line 562: | Line 567: | ||
} | } | ||
− | + | Step the progress bar. Increment the progress bar by n steps, or 1 step if no steps are provided. This always returns true unless the user aborts, in which case it returns false. | |
int | int | ||
Line 597: | Line 602: | ||
} | } | ||
− | + | verifies that the file passed in is of the lua type. | |
LxResult | LxResult | ||
Line 611: | Line 616: | ||
} | } | ||
− | + | adds all of the functions just implemented in lxlua.cpp to CLuaInterpreter | |
void | void | ||
Line 684: | Line 689: | ||
} | } | ||
− | + | performs most of the work, is the function that actually interprets the file. | |
LxResult | LxResult | ||
Line 865: | Line 870: | ||
} | } | ||
− | + | This function cleans up. | |
void | void | ||
Line 892: | Line 897: | ||
} | } | ||
− | |||
− |
Revision as of 21:05, 10 September 2013
Script_lua is a basic example plugin. This wiki page is intended as a walkthrough of the code in order to help you better understand the SDK.
This plugin serves as a Lua script interpreter.
Contents
Code Walkthrough
Declarations
This is a struct that defines certain objects and constants that will be used by the plugin.
typedef struct st_IntrInstance { ILxScriptID script; // Script being executed. ILxMonitorID monitor; // Progress monitor used by lxmon??? functions. int askedForMonitor; // True if we asked for the monitor. LxResult rc; // Result code from the most recently executed/queried command. int tracing; // 1 if tracing is active, 0 if inactive. int execFlags; // Flags provided by the caller of Run() and used for command execution. CLxUser_LogEntry log; // For logging data int queryAnglesAsDegrees; // True if queried angles should be returned in degrees instead of radians. } IntrInstance;
Declaration of functions that will be used by the plugin.
extern "C" int l_lxout(lua_State *L); extern "C" int l_lx(lua_State *L); extern "C" int l_lxq(lua_State *L); extern "C" int l_lxqt(lua_State *L); extern "C" int l_lxeval(lua_State *L); extern "C" int l_lxok(lua_State *L); extern "C" int l_lxres(lua_State *L); extern "C" int l_lxtrace(lua_State *L); extern "C" int l_lxoption(lua_State *L); extern "C" int l_lxsetOption(lua_State *L); extern "C" int l_lxmonInit(lua_State *L); extern "C" int l_lxmonStep(lua_State *L);
Here we declare a variety of scripts and services that will be used below. "extern" indicates that the objects inside have already been defined elsewhere so the compiler won't complain.
extern "C" { ILxScriptSysServiceID scriptSrv; /* Script system service; common to all instances */ ILxStdDialogServiceID dlgSrv; /* Standard dialog service; common to all instances */ IntrInstance intrStack[ MAX_STACK ]; /* Interpreter stack; allows scripts to execute other scripts */ int intrTop = -1; /* The current script being executed as an index into interStack */ IntrInstance *intrCur = NULL; /* The same as &intrStack[ intrTop ], or NULL if intrTop is -1 */ }
Class Declarations
This class is intended to take a lua script and interpret it, so we need it to be a modified text editor. To this end, we inherit from CLxImpl_TextScriptInterpreter.
class CLuaInterpreter : public CLxImpl_TextScriptInterpreter { CLxUser_LogService logSvc; CLxUser_CommandService cmdSvc; CLxUser_ValueService valueSvc; public: virtual ~CLuaInterpreter () {} virtual LxResult tsi_ValidateFileType ( ILxUnknownID scriptObj, const char *firstLine) LXx_OVERRIDE; virtual LxResult tsi_Run ( ILxUnknownID scriptObj, int execFlags, const char *args, ILxUnknownID messObj) LXx_OVERRIDE; void Init (); void Kill (); static LXtTagInfoDesc descInfo[]; private: lua_State *L; };
Server Tags
LXtTagInfoDesc CLuaInterpreter::descInfo[] = { { LXsSRV_USERNAME, "Lua Scripts" }, { LXsLOD_DOSPATTERN, "*.lua" }, { 0 } };
The tags here indicate that CLuaInterpreter has the name Lua Scripts and takes files with the .lua extension.
Initialize
This initialize function exports one server of the type TextScriptInterpreter that is dependent on the class CLuaInterpreter and has the name lua.
void initialize () { LXx_ADD_SERVER (TextScriptInterpreter, CLuaInterpreter, "lua"); }
Implementations
Add a string to a parent log, possibly returning a log entry for sub-entries
static void AddLogStringEntry ( CLxLoc_LogEntry &parent, const char *s, LxResult code, int persist, CLxLoc_LogEntry &entry) { if (logSrv->NewEntry (code, s, entry)) { parent.AddEntry (entry); } }
Adding a log entry to a parent, for clients with no need for the entry.
void AddLogString ( CLxLoc_LogEntry &parent, const char *s, LxResult code, int persist) { CLxLoc_LogEntry entry; AddLogStringEntry (parent, s, code, persist, entry); }
Logging for clients with no need for the entry.
void LogString ( const char *s, LxResult code, int persist) { CLxLoc_LogEntry entry; LogStringEntry (s, code, persist, entry); }
lxout: Output a string to the log
int l_lxout(lua_State *L) { const char *c = lua_tostring(L, 1); if(c) LogString( c, LXe_INFO, 0 ); else LogString( "nil", LXe_INFO, 0 ); return 0; }
Internal function to perform queries and executions
#define LXEVALMODEf_QUERY 1 // Query only; fail if no query is marked #define LXEVALMODEf_EXECUTE 2 // Execute only; fail if a query is marked #define LXEVALMODEf_EITHER (LXEVALMODEf_QUERY | LXEVALMODEf_EXECUTE) // Query or execute, whatever works LxResult lxeval(lua_State *L, int mode) { CLxUser_Command command; CLxLoc_LogEntry entry; int i, x, type, queryArgIndex; int iVal; double fVal, fScalar = 1.0; char sVal[2048]; const char *typeName; LxResult rc; const LXtTextValueHint *hints = NULL; unsigned execFlags = intrCur->execFlags; const char *c = lua_tostring(L, 1); bool isOK; OutputTraceInfo( c, entry ); /* Spawn the command and get the query argument */ isOK = cmdSrv->NewCommandFromString (command, c, execFlags, queryArgIndex); if( !isOK ) { intrCur->rc = LXe_FAILED; if( intrCur->tracing ) AddLogString( entry, "\03(f:FONT_ITALIC)lxtrace, lxq/lx/lxeval failed: error spawning command/parsing arguments\03(f:FONT_DEFAULT)", LXe_FAILED, 0 ); return LXe_FAILED; } if( (mode == LXEVALMODEf_EXECUTE) || // Execute only flag; execute if there's a query or not ((queryArgIndex == -1) && (mode & LXEVALMODEf_EXECUTE)) ) { // No query arg; execute if the execute flag is set (in case of "either" mode) /* Execute */ if( !(mode & LXEVALMODEf_EXECUTE) ) { if( intrCur->tracing ) AddLogString( entry, "\03(f:FONT_ITALIC)lxtrace, lx failed: unprocessed query argument (i.e., \'?\') specified in command string\03(f:FONT_DEFAULT)", LXe_FAILED, 0 ); return LXe_FAILED; } intrCur->rc = cmdSrv->ExecuteSpecial( execFlags, command, queryArgIndex ); lua_pushnumber(L, LXx_OK( intrCur->rc ) ? 1 : 0 ); return LXe_OK; } /* See if we're allowed to query */ if( !(mode & LXEVALMODEf_QUERY) ) { if( intrCur->tracing ) AddLogString( entry, "\03(f:FONT_ITALIC)lxtrace, lxq/lxeval failed: no query (i.e., \'?\') marked in command string\03(f:FONT_DEFAULT)", LXe_FAILED, 0 ); return LXe_CMD_NO_QUERY_MARKED; } /* Create the value array and query the command */ CLxUser_ValueArray qval; CLxUser_Attributes attr; if (attr.set(command)) { /* Get the type */ type = attr.Type (queryArgIndex); if (type != -1) { /* Get the type name */ rc = attr.TypeName (queryArgIndex, &typeName); if (LXx_OK (rc)) { /* Create a value array */ ILxUnknownID oqval; rc = cmdSrv->CreateQueryObject( typeName, (void **)&oqval ); if (LXx_OK (rc)) { /* Query */ qval.set (oqval); if( qval.set (oqval) ) rc = command.Query (queryArgIndex, qval); } } } else { rc = LXe_FAILED; } } if( LXx_FAIL (rc) ) { if( intrCur->tracing ) AddLogString( entry, "\03(f:FONT_ITALIC)lxtrace, lxq/lxeval failed: error querying command\03(f:FONT_DEFAULT)", LXe_FAILED, 0 ); return rc; } /* Return the values in the value array to the script */ i = qval.Count(); if(0 == i) { /* Nothing is on the stack; return nil */ lua_pushnil( L ); return LXe_OK; } if( attr != NULL ) hints = attr.Hints( queryArgIndex ); lua_newtable(L); if( intrCur->queryAnglesAsDegrees ) { /* Special case: convert angles to degrees, if applicable */ if( strcmp( typeName, "angle" ) == 0 ) fScalar = 57.295780490442968321226628812406; // 180 / 3.1415926; } for(x = 0 ; x < i ; x++) { lua_pushnumber(L, x+1); // The key, which is just the index of the value if(type == LXi_TYPE_INTEGER) { bool asNumber = 1; qval.GetInt (x, &iVal); if( hints != NULL ) { LxResult encodeResult = valueSrv->TextHintEncode( iVal, hints, sVal, 2048 ); if( encodeResult != LXe_OK_NO_CHOICES ) { lua_pushlstring(L, sVal, strlen(sVal)); asNumber = 0; if( intrCur->tracing ) { char buf[ 64 ]; sprintf( buf, "\03(f:FONT_ITALIC)lxtrace, lxq, %d:\03(f:FONT_DEFAULT) %s", x+1, sVal ); AddLogString( entry, buf, LXe_INFO, 0 ); } } } if( asNumber ) { lua_pushnumber(L, iVal); if( intrCur->tracing ) { char buf[ 64 ]; sprintf( buf, "\03(f:FONT_ITALIC)lxtrace, lxq, %d:\03(f:FONT_DEFAULT) %d", x+1, iVal ); AddLogString( entry, buf, LXe_INFO, 0 ); } } } else if(type == LXi_TYPE_FLOAT) { qval.GetFloat (x, &fVal); fVal *= fScalar; lua_pushnumber(L, fVal); if( intrCur->tracing ) { char buf[ 64 ]; sprintf( buf, "\03(f:FONT_ITALIC)lxtrace, lxq, %d:\03(f:FONT_DEFAULT) %g", x+1, fVal ); AddLogString( entry, buf, LXe_INFO, 0 ); } } else if(type == LXi_TYPE_STRING) { qval.GetString (x, sVal, 2048); lua_pushlstring(L, sVal, strlen(sVal)); if( intrCur->tracing ) { char buf[ 2048 ]; sprintf( buf, "\03(f:FONT_ITALIC)lxtrace, lxq, %d:\03(f:FONT_DEFAULT) %s", x+1, sVal ); AddLogString( entry, buf, LXe_INFO, 0 ); } } else { /* Object; convert to a string and return */ char buffer[2048]; LXtObjectID value; if( LXx_FAIL( (qval.GetValue (x, (void **) &value) ))) { lua_pushnil( L ); continue; } /* * Check if we have a string converter. */ CLxUser_StringConversion stringer; stringer.set (value); if (!stringer.test ()) { lua_pushnil( L ); continue; } if( LXx_FAIL( stringer.Encode ( buffer, 2048 ) ) ) { lua_pushnil( L ); continue; } lua_pushlstring(L, buffer, strlen(buffer)); if( intrCur->tracing ) { char buf[ 2100 ]; sprintf( buf, "\03(f:FONT_ITALIC)lxtrace, lxq, %d:\03(f:FONT_DEFAULT) %s", x+1, buffer ); AddLogString( entry, buf, LXe_INFO, 0 ); } } lua_settable(L, -3); } return 1; }
At some point in the future, lxq() needs to use the raw string conversion feature to ensure that the values that are queried are the same kinds of values that get passed to commands.
int l_lxq(lua_State *L) { if( LXx_FAIL( lxeval( L, LXEVALMODEf_QUERY ) ) ) return 0; return 1; }
lxqt(): Query a toggle command's toggle argument. Returns the query state on success (1 or 0), or 0 on failure.
int l_lxqt(lua_State *L) { CLxUser_Command command; CLxLoc_LogEntry entry; int state; unsigned execFlags = intrCur->execFlags; const char *c = lua_tostring(L, 1); bool isOK; OutputTraceInfo( c, entry ); /* Spawn the command */ int queryArgIndex; isOK = cmdSrv->NewCommandFromString( command, c, execFlags, queryArgIndex ); if( !isOK ) { intrCur->rc = LXe_FAILED; if( intrCur->tracing ) AddLogString( entry, "\03(f:FONT_ITALIC)lxtrace, lxqt failed: error spawning command/parsing arguments\03(f:FONT_DEFAULT)", LXe_FAILED, 0 ); lua_pushnumber( L, 0 ); return 1; } /* Query the toggle argument */ intrCur->rc = cmdSrv->GetToggleArgState( command, &state, NULL ); if( intrCur->tracing ) { if( LXx_OK( intrCur->rc ) ) { if( state ) { AddLogString( entry, "\03(f:FONT_ITALIC)lxtrace, lxqt, toggled state is true (1)\03(f:FONT_DEFAULT)", LXe_INFO, 0 ); lua_pushnumber( L, 1 ); } else { AddLogString( entry, "\03(f:FONT_ITALIC)lxtrace, lxqt, toggled state is false (0)\03(f:FONT_DEFAULT)", LXe_INFO, 0 ); lua_pushnumber( L, 0 ); } } else { AddLogString( entry, "\03(f:FONT_ITALIC)lxtrace, lxqt failed: error querying the command\03(f:FONT_DEFAULT)", LXe_FAILED, 0 ); lua_pushnumber( L, 0 ); } } return 1; }
Return true if the last command executed/queried successfully.
int l_lxok(lua_State *L) { lua_pushboolean(L, LXx_OK( intrCur->rc ) ? 1 : 0); return 1; }
Return the LxResult code of the last command executed or quieried.
int l_lxres(lua_State *L) { lua_pushnumber(L, intrCur->rc); return 1; }
When activated, lx() and lxq() data is output to the event log. If no args are passed in, this returns if tracing is active or not.
int l_lxtrace(lua_State *L) { /* See if there's at least one argument */ const char *c = lua_tostring(L, 1); if( c != NULL ) { intrCur->tracing = atoi( c ); // For some reason, lua_toboolean() is always returning 1, so we'll just do this if( intrCur->tracing ) LogString( "\03(f:FONT_ITALIC)lxtrace: Enabled\03(f:FONT_DEFAULT)", LXe_INFO, 0 ); else LogString( "\03(f:FONT_ITALIC)lxtrace: Disabled\03(f:FONT_DEFAULT)", LXe_INFO, 0 ); } lua_pushnumber(L, intrCur->tracing); return 1; }
Get the state of an option.
int l_lxoption(lua_State *L) { const char *tag = lua_tostring(L, 1); if( strcmp( tag, "queryAnglesAs" ) == 0 ) { /* Query Angles As. Returns "degrees" or "radians" */ const char *state = intrCur->queryAnglesAsDegrees ? "degrees" : "radians"; lua_pushlstring(L, state, strlen(state)); return 1; } /* Unknown tag */ return 0; }
Get the state of an option.
int l_lxsetOption(lua_State *L) { const char *tag = lua_tostring(L, 1); const char *value = lua_tostring(L, 2); if( strcmp( tag, "queryAnglesAs" ) == 0 ) { /* Query Angles As. Returns "degrees" or "radians" */ if( strcmp( tag, "queryAnglesAs" ) == 0 ) { /* Query Angles As. Supports "degrees" or "radians" */ if( strcmp( value, "degrees" ) == 0 ) { intrCur->queryAnglesAsDegrees = 1; } else if( strcmp( value, "radians" ) == 0 ) { intrCur->queryAnglesAsDegrees = 0; } else { lua_pushboolean(L, 0); return 0; } lua_pushboolean(L, 1); } return 1; } /* Unknown tag */ lua_pushboolean(L, 0); return 0; }
Initialize the progress bar. Initialize the progress bar with n total steps. Returns 0 on error.
int l_lxmonInit(lua_State *L) { int count; LxResult rc; /* See if there's at least one argument */ if( lua_tostring(L, 1) == NULL ) { lua_pushboolean(L, 0); return 1; } /* Make sure there's at least one step */ count = (int)lua_tonumber(L, 1); if( count < 1 ) { lua_pushboolean(L, 0); return 1; } /* Get the monitor */ if( intrCur->monitor == NULL ) { if( intrCur->askedForMonitor ) { lua_pushboolean(L, 0); return 1; } if( LXx_FAIL( dlgSrv[0]->MonitorAllocate( dlgSrv, "Progress", (void **)&intrCur->monitor ) ) || (intrCur->monitor == NULL) ) { lua_pushboolean(L, 0); return 1; } intrCur->askedForMonitor = 1; } /* Initialize the monitor */ rc = intrCur->monitor[0]->Initialize( intrCur->monitor, count ); if( LXx_OK( rc ) ) lua_pushboolean(L, 1); else lua_pushboolean(L, 0); return 1; }
Step the progress bar. Increment the progress bar by n steps, or 1 step if no steps are provided. This always returns true unless the user aborts, in which case it returns false.
int l_lxmonStep(lua_State *L) { int steps; LxResult rc; if( intrCur->monitor == NULL ) { lua_pushboolean(L, 1); return 1; } /* See if there are any arguments */ if( lua_tostring(L, 1) == NULL ) steps = 1; else steps = (int)lua_tonumber(L, 1); /* Make sure there's at least one step */ if( steps < 1 ) { lua_pushboolean(L, 1); return 1; } /* Increment the monitor and check for a user abort */ rc = intrCur->monitor[0]->Increment( intrCur->monitor, steps ); if( LXx_OK( rc ) ) lua_pushboolean(L, 1); else lua_pushboolean(L, 0); return 1; }
verifies that the file passed in is of the lua type.
LxResult CLuaInterpreter::tsi_ValidateFileType ( ILxUnknownID scriptObj, const char *firstLine) { if (!strstr (firstLine, "lua")) return LXe_SCRIPT_UNKNOWN; return LXe_OK; }
adds all of the functions just implemented in lxlua.cpp to CLuaInterpreter
void CLuaInterpreter::Init() { logSrv = &logSvc; cmdSrv = &cmdSvc; valueSrv = &valueSvc; L = lua_open(); /* Add the new functions to lua */ lua_pushcfunction(L, l_lxout); lua_setglobal(L, "lxout"); lua_pushcfunction(L, l_lx); lua_setglobal(L, "lx"); lua_pushcfunction(L, l_lxq); lua_setglobal(L, "lxq"); lua_pushcfunction(L, l_lxqt); lua_setglobal(L, "lxqt"); lua_pushcfunction(L, l_lxeval); lua_setglobal(L, "lxeval"); lua_pushcfunction(L, l_lxok); lua_setglobal(L, "lxok"); lua_pushcfunction(L, l_lxres); lua_setglobal(L, "lxres"); lua_pushcfunction(L, l_lxtrace); lua_setglobal(L, "lxtrace"); lua_pushcfunction(L, l_lxoption); lua_setglobal(L, "lxoption"); lua_pushcfunction(L, l_lxsetOption); lua_setglobal(L, "lxsetOption"); lua_pushcfunction(L, l_lxmonInit); lua_setglobal(L, "lxmonInit"); lua_pushcfunction(L, l_lxmonStep); lua_setglobal(L, "lxmonStep"); /* Other lua init */ /* * Updated for Lua 5.1, per the Lua API Programming FAQ: * * http://lua-users.org/wiki/LuaFaq * * See "Why do I get a 'no calling environment' error?" */ luaL_openlibs(L); /* Init our level of the stack */ intrTop++; assert( intrTop < MAX_STACK ); intrCur = &intrStack[ intrTop ]; intrCur->script = NULL; intrCur->monitor = NULL; intrCur->askedForMonitor = 0; intrCur->rc = LXe_OK; intrCur->tracing = 0; intrCur->execFlags = LXfCMD_EXEC_DEFAULT; intrCur->queryAnglesAsDegrees = 1; }
performs most of the work, is the function that actually interprets the file.
LxResult CLuaInterpreter::tsi_Run ( ILxUnknownID scriptObj, int execFlags, const char *args, ILxUnknownID messObj ) { // Hybrid access: Let the localization handle the reference-counting, but // extract the interface for old-style direct usage. // CLxLoc_Script u_script (scriptObj); CLxLoc_Message u_mess (messObj); ILxScriptID script = u_script.m_loc; ILxMessageID mess = u_mess.m_loc; const char *name, *hash; unsigned int size = 0; const char *st; char *localBuf, nameBuf[ 512 ]; LxResult rc = LXe_OK; int error; int errMsg = -1; int numArgs = 0; Init(); script[0]->GetBuffer( script, &st, &size ); size -= 1; // Remove the \0 from the buffer length /* Variable initialization */ scriptSrv = (ILxScriptSysServiceID)lx::GetGlobal(LXu_SCRIPTSYSSERVICE); dlgSrv = (ILxStdDialogServiceID)lx::GetGlobal (LXu_STDDIALOGSERVICE); intrCur->script = script; intrCur->execFlags = execFlags; /* Load up the default libraries */ /* * Updated for Lua 5.1, per the Lua API Programming FAQ: * * http://lua-users.org/wiki/LuaFaq * * See "Why do I get a 'no calling environment' error?" */ luaL_openlibs(L); /* Log Setup */ if( LXx_FAIL( script[0]->UserName( script, &name ) ) ) script[0]->Hash( script, &name ); sprintf( nameBuf, "%s (lua script)", name ); logSvc.NewEntry( LXe_INFO, nameBuf, intrCur->log ); if( intrTop == 0 ) { /* Add the entry to the subsystem */ CLxLoc_Log logSubSys; logSvc.GetSubSystem( LXsLOG_SCRIPTSYS, logSubSys ); logSubSys.AddEntry( ILxUnknownID(intrCur->log) ); } else { /* Add the entry to the parent script's entry */ intrStack[ intrTop - 1 ].log.AddEntry (intrCur->log); } /* Load the script into the interpreter */ error = luaL_loadbuffer(L, st, strlen(st), "lua script"); if( error ) { errMsg = 1; } else { /* Create the argument table */ lua_newtable(L); // arg table /* Push the script name onto the table at index 0 */ script[0]->Hash( script, &hash ); lua_pushnumber(L, 0); lua_pushstring(L, hash); lua_settable(L, -3); /* Parse the arguments and add them to the table */ if (args) { int alen = static_cast<int>(strlen (args)) + 1; localBuf = new char [alen]; strcpy (localBuf, args); char *arg = localBuf; char *endQuote; int index = 0; while( (arg != NULL) && (arg[0] != '\0') ) { /* Skip white space */ for( /*NULL*/; isspace( arg[0] ) && (arg[0] != '\0'); arg++ ) { ; } if( arg[0] == '\0' ) break; /* Check for quoted arguments */ if( arg[0] == '\"' ) { arg++; endQuote = strchr( arg, '\"' ); if( endQuote == NULL ) { /* Unbalanced quotes; fail */ rc = LXe_FAILED; mess[0]->SetCode (mess, rc); mess[0]->SetMessage (mess, "lualintr", NULL, 3); mess[0]->SetArgumentString (mess, 1, args); error = 1; errMsg = 2; break; } endQuote[0] = '\0'; lua_pushnumber(L, ++index); lua_pushstring(L, arg); lua_settable(L, -3); numArgs++; arg = endQuote + 1; } else { /* Normal space delimiting */ endQuote = strchr( arg, ' ' ); if( endQuote ) endQuote[0] = '\0'; lua_pushnumber(L, ++index); lua_pushstring(L, arg); lua_settable(L, -3); numArgs++; if( endQuote == NULL ) arg = NULL; else arg = endQuote + 1; } } } /* Make the table into the global "arg" variable */ lua_setglobal(L, "arg"); if( !error ) { /* Execute */ error = lua_pcall(L, 0, 0, 0); if( error ) errMsg = 2; } } if( (errMsg == 1) || (errMsg == 2) ) { /* Error Handling */ const char *c = lua_tostring(L, -1); LogString( c, LXe_FAILED, 0 ); lua_pop(L, 1); rc = LXe_FAILED; // TODO: Figure out how to handle aborts differently from failures mess[0]->SetCode( mess, rc ); mess[0]->SetMessage( mess, "luaintr", NULL, errMsg ); mess[0]->SetArgumentString( mess, 1, c ); } /* Clean Up */ if (args) delete[] localBuf; Kill(); return rc; }
This function cleans up.
void CLuaInterpreter::Kill() { lua_close(L); /* Clean up our level of the stack */ intrCur->script = NULL; intrCur->rc = LXe_OK; intrCur->tracing = 0; intrCur->execFlags = LXfCMD_EXEC_DEFAULT; if( intrCur->askedForMonitor ) { dlgSrv[0]->MonitorRelease( dlgSrv ); intrCur->askedForMonitor = 0; intrCur->monitor = NULL; } assert( intrTop >= -1 ); /* Set the current pointer to the previous level */ intrTop--; intrCur = (intrTop == -1) ? NULL : &intrStack[ intrTop ]; }