1 /*
2 LUASTATE.CPP
3 Author: Stef.
4
5 */
6 //#include <io.h>
7 #include <limits.h>
8 #include <stdint.h>
9 #include <string.h>
10 #ifdef WIN32
11 #include <io.h>
12 #endif
13
14 #include "Log.h"
15 #include "base.h"
16 #include "Exception.h"
17 #include "LuaState.h"
18
19 // Lua.
20 extern "C" {
21 #include "lauxlib.h"
22 #include "lua.h"
23 #include "lualib.h"
24 };
25
26 #ifdef LINUX_GNU
27 #include <limits.h>
28 #define MAX_PATH PATH_MAX
29 #endif
30
31 #ifndef MAX_PATH
32 #define MAX_PATH 4096
33 #endif
34
35 namespace Base {
36 namespace Script {
37
38 /*
39 luaInstallation().
40
41 */
42 static const char *luaInstallation = " \
43 function SetInstallation( _luaPath ) \
44 print( 'SetInstallation: ' .. tostring(_luaPath) ) \
45 require 'string' \
46 LUA_PATH = _luaPath .. '/?.lua;' \
47 LUA_PATH = LUA_PATH .. _luaPath .. '/?/?.lua;' \
48 LUA_CPATH = _luaPath .. '/?.dll;' \
49 LUA_CPATH = LUA_CPATH .. _luaPath .. '/?/?.dll;' \
50 package.path = LUA_PATH \
51 package.cpath = LUA_CPATH \
52 end";
53
54 /*
55 addInstallation().
56
57 */
58 static const char *addInstallation = " \
59 function AddInstallation( _package ) \
60 print( 'AddInstallation: ' .. tostring(_package) ) \
61 require 'string' \
62 LUA_PATH = LUA_PATH .. _package .. '/?.lua;' \
63 LUA_PATH = LUA_PATH .. _package .. '/?/?.lua;' \
64 LUA_CPATH = LUA_CPATH .. _package .. '/?.dll;' \
65 LUA_CPATH = LUA_CPATH .. _package .. '/?/?.dll;' \
66 package.path = LUA_PATH \
67 package.cpath = LUA_CPATH \
68 end";
69
70 //
LuaAlert(::lua_State * _pState)71 static int LuaAlert( ::lua_State *_pState )
72 {
73 ASSERT( _pState != NULL );
74 const char *pMsg = lua_tostring( _pState, -1 );
75 //ThrowStr( pMsg );
76 g_Log->Error( "Lua Alert: %s", pMsg );
77 return( 0 );
78 }
79
80
81 /*
82 CLuaState().
83
84 */
CLuaState()85 CLuaState::CLuaState()
86 {
87 }
88
89 /*
90 ~CLuaState().
91
92 */
~CLuaState()93 CLuaState::~CLuaState()
94 {
95 if( m_pState )
96 lua_close( m_pState );
97 }
98
99 //
DumpStack()100 void CLuaState::DumpStack()
101 {
102 g_Log->Debug( "stack: %d\n", lua_gettop( m_pState ) );
103 }
104
105 /*
106 registerLib().
107 Pre-register library, so it's up to the script to require libraries.
108 */
registerLib(const char * _pName,lua_CFunction _func)109 void CLuaState::registerLib( const char *_pName, lua_CFunction _func )
110 {
111 lua_getglobal( m_pState, "package" );
112 lua_getfield( m_pState, -1, "preload" ); // 'package.preload'
113 lua_pushcfunction( m_pState, _func );
114 lua_setfield( m_pState, -2, _pName ); // 'package.preload[ _pName ] = f'
115 lua_pop( m_pState, 2 ); // Pop package & preload tables.
116 }
117
118 /*
119 AddPackagePath().
120
121 */
c_AddPackagePath(lua_State * _pState)122 static int c_AddPackagePath( lua_State *_pState )
123 {
124 const char *packagePath = luaL_checkstring( _pState, 1 );
125
126 bool bRelative = true;
127
128 if( lua_isboolean( _pState, 2 ) )
129 if( lua_toboolean( _pState, 2 ) == 0 )
130 bRelative = false;
131
132 char dirBuf[ MAX_PATH + 1];
133 #if defined(WIN32) && defined(_MSC_VER)
134 std::string dir;
135 if (GetCurrentDirectoryA(sizeof(dirBuf) - 1, dirBuf))
136 dir = dirBuf;
137 #else
138 std::string dir = getcwd( &dirBuf[0], MAX_PATH + 1 );
139 #endif
140
141 if( bRelative )
142 dir += packagePath;
143 else
144 dir = packagePath;
145
146 Call( _pState, "AddInstallation", "s", (const char *)dir.c_str() );
147
148 return( 0 );
149 }
150
151 /*
152 Init().
153
154 */
Init(const std::string & _basePath)155 void CLuaState::Init( const std::string &_basePath )
156 {
157 g_Log->Info( "Lua base bath: %s", _basePath.c_str() );
158
159 // Create state.
160 m_pState = luaL_newstate();
161
162 g_Log->Info( "stack: %d\n", lua_gettop( m_pState ) );
163
164 lua_gc( m_pState, LUA_GCSTOP, 0 );
165
166 lua_cpcall( m_pState, luaopen_base, NULL ); // Base library.
167 lua_cpcall( m_pState, luaopen_package, NULL ); // Package library. (we need this to be able to 'require' from lua)
168
169 #ifdef LUA_JIT
170 lua_cpcall( m_pState, luaopen_jit, NULL );
171 #endif
172
173 #if defined(AMD64) || defined(__LP64__)
174 Execute( "_PLATFORM = 'x64'" );
175 #else
176 Execute( "_PLATFORM = 'x86'" );
177 #endif
178
179 // The following will be pre-registered, and only loaded explicitly from the script.
180 registerLib( "io", luaopen_io );
181 registerLib( "os", luaopen_os );
182 registerLib( "table", luaopen_table );
183 registerLib( "string", luaopen_string );
184 registerLib( "math", luaopen_math );
185 registerLib( "debug", luaopen_debug );
186
187 lua_register( m_pState, "_ALERT", &LuaAlert );
188
189 //
190 lua_pushcfunction( m_pState, c_AddPackagePath );
191 lua_setglobal( m_pState, "c_AddPackagePath" );
192
193 //
194 std::string cmd = luaInstallation;
195 Execute( luaInstallation );
196
197 //
198 cmd = addInstallation;
199 Execute( addInstallation );
200
201 Call( m_pState, "SetInstallation", "s", (const char *)_basePath.c_str() );
202
203 // Start collector again.
204 lua_gc( m_pState, LUA_GCRESTART, 0 );
205 }
206
207 /*
208 */
traceback(lua_State * _pLuaState)209 static int traceback( lua_State *_pLuaState )
210 {
211 lua_getfield( _pLuaState, LUA_GLOBALSINDEX, "debug" );
212 if (!lua_istable( _pLuaState, -1 ) )
213 {
214 lua_pop( _pLuaState, 1 );
215 return 1;
216 }
217
218 lua_getfield( _pLuaState, -1, "traceback" );
219
220 if( !lua_isfunction( _pLuaState, -1 ) )
221 {
222 lua_pop( _pLuaState, 2 );
223 return 1;
224 }
225
226 lua_pushvalue( _pLuaState, 1 ); // Pass error message.
227 lua_pushinteger( _pLuaState, 2 ); // Skip this function and traceback.
228 lua_call( _pLuaState, 2, 1 ); // Call debug.traceback.
229
230 return 1;
231 }
232
233 /*
234 */
docall(lua_State * _pLuaState,int narg,int clear)235 static int docall( lua_State *_pLuaState, int narg, int clear )
236 {
237 int status;
238 int base = lua_gettop( _pLuaState ) - narg; // Function index.
239
240 lua_pushcfunction( _pLuaState, traceback ); // Push traceback function.
241 lua_insert( _pLuaState, base ); // Put it under chunk and args.
242
243 status = lua_pcall( _pLuaState, narg, (clear ? 0 : LUA_MULTRET ), base );
244
245 lua_remove( _pLuaState, base ); // Remove traceback function.
246
247 // Force a complete garbage collection in case of errors */
248 if( status != 0 )
249 lua_gc( _pLuaState, LUA_GCCOLLECT, 0 );
250
251 return( status );
252 }
253
254
255 /*
256 reportLua().
257
258 */
reportLua(lua_State * _pLuaState,const int32 _status)259 static bool reportLua( lua_State *_pLuaState, const int32 _status )
260 {
261 if( _status && !lua_isnil( _pLuaState, -1 ) )
262 {
263 const char *pMsg = lua_tostring( _pLuaState, -1 );
264
265 if( !pMsg )
266 pMsg = "(error object is not a string)";
267
268 g_Log->Error( "%s", pMsg );
269 //ThrowArgs( ("CLuaState(): %s", pMsg) );
270
271 lua_pop( _pLuaState, 1 );
272
273 return false;
274 }
275
276 return true;
277 }
278
279 /*
280 Execute().
281 Execute lua code.
282 */
Execute(const std::string & _command)283 bool CLuaState::Execute( const std::string &_command )
284 {
285 int status = luaL_loadstring( m_pState, _command.c_str() );
286 if( status == 0 )
287 status = docall( m_pState, 0, 1 );
288
289 return reportLua( m_pState, status );
290 }
291
292
293 //
294 /*static void LuaCall( lua_State *L, int narg, int clear )
295 {
296 int status;
297 lua_checkstack( L, LUA_MINSTACK );
298 int top = lua_gettop(L);
299 int base = top - narg; // function index
300 lua_pushliteral(L, "_TRACEBACK");
301 lua_rawget(L, LUA_GLOBALSINDEX); // get traceback function
302 lua_insert(L, base); // put it under chunk and args
303 //status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
304 status = lua_pcall(L, narg, clear, base );
305 lua_remove(L, base); // remove traceback function
306 //status = LuaError(L, status, top - (narg + 1));
307 reportLua( L, status );
308
309 lua_settop( L, top );
310 }*/
311
312 /*
313 Run().
314
315 */
Run(const std::string & _script)316 bool CLuaState::Run( const std::string &_script )
317 {
318 int status = luaL_loadfile( m_pState, _script.c_str() );
319 if( status == 0 )
320 status = lua_pcall( m_pState, 0, 0, 0 );
321
322 reportLua( m_pState, status );
323
324 if( status != 0 )
325 return false;
326
327 return( true );
328 }
329
330 /*
331 Pop().
332
333 */
Pop(const int32 _num)334 void CLuaState::Pop( const int32 _num )
335 {
336 if( _num != 0 )
337 lua_pop( m_pState, _num );
338 }
339
340 /*
341 Call().
342
343 */
Call(lua_State * _pState,const char * _pFunc,const char * _pSig,...)344 int32 Call( lua_State *_pState, const char *_pFunc, const char *_pSig, ... )
345 {
346 ASSERT( _pState != NULL );
347
348 uint32 stackSizeIn = static_cast<uint32>(lua_gettop( _pState ));
349 if( stackSizeIn != 0 )
350 {
351 g_Log->Error( "Lua stack not empty..." );
352 return 0;
353 }
354
355 int delta = 0;
356
357 va_list pArg;
358
359 //try
360 {
361 // Number of arguments and results.
362 int narg, nres;
363
364 // Get function.
365 lua_getglobal( _pState, _pFunc );
366
367 // Push arguments.
368 narg = 0;
369
370 char *pBinarySource = NULL;
371 int32 binaryLen = 0;
372
373 // Gimme args.
374 va_start( pArg, _pSig );
375
376 while( *_pSig )
377 {
378 // Push arguments.
379 switch( *_pSig++ )
380 {
381 case 'd': // Double argument.
382 lua_pushnumber( _pState, va_arg( pArg, fp8 ) );
383 break;
384
385 case 'i': // Int argument.
386 lua_pushinteger( _pState, va_arg( pArg, int32 ) );
387 break;
388
389 case 'b': // Bool argument.
390 lua_pushboolean( _pState, va_arg( pArg, int32 ) != 0 );
391 break;
392
393 case 'x': // Binary string argument. Next argument MUST be an integer. (which will be skipped)
394 pBinarySource = va_arg( pArg, char * );
395 binaryLen = va_arg( pArg, int32 );
396 lua_pushlstring( _pState, pBinarySource, static_cast<size_t>(binaryLen) );
397 _pSig++;
398 break;
399
400 case 's': // String argument.
401 lua_pushstring( _pState, va_arg( pArg, char * ) );
402 break;
403
404 case '>':
405 goto endwhileLabel;
406
407 default:
408 {
409 g_Log->Error( "Invalid option (%c)", *(_pSig - 1) );
410 return 0;
411 }
412 }
413
414 //printf( "stack: %d", lua_gettop( _pState ) );
415
416 narg++;
417 luaL_checkstack( _pState, 1, "Too many arguments" );
418
419 } endwhileLabel:
420
421 // Do the call.
422 nres = (int)strlen( _pSig ); // Number of expected results.
423
424 //LuaCall( _pState, narg, nres );
425 //int status = lua_pcall( _pState, narg, nres, 0 );
426 int status = docall( _pState, narg, 0 );
427
428 reportLua( _pState, status );
429
430 // Retrieve results.
431 nres = -nres; // Stack index of first result.
432
433 while( *_pSig ) // Get results.
434 {
435 switch( *_pSig++ )
436 {
437 case 'd': // Double result.
438 if( !lua_isnumber( _pState, nres ) )
439 g_Log->Error( "Wrong result type, expected double" );
440 else
441 *va_arg( pArg, fp8 *) = lua_tonumber( _pState, nres );
442
443 break;
444
445
446 case 'b': // Bool result.
447 if( !lua_isboolean( _pState, nres ) )
448 g_Log->Error( "Wrong result type, expected bool" );
449 else
450 *va_arg( pArg, bool *) = lua_toboolean( _pState, nres ) != 0;
451
452 break;
453
454 case 'i': // Int result.
455 if( !lua_isnumber( _pState, nres ) )
456 g_Log->Error( "Wrong result type, expected integer" );
457 else
458 *va_arg( pArg, int32 *) = (int32)lua_tonumber( _pState, nres );
459
460 break;
461
462 case 's': // String result.
463 if( !lua_isstring( _pState, nres ) )
464 g_Log->Error( "Wrong result type, expected string" );
465 else
466 *va_arg( pArg, const char **) = lua_tostring( _pState, nres );
467
468 break;
469
470 default:
471 {
472 g_Log->Error( "Invalid option (%c)", *(_pSig - 1) );
473 break;
474 }
475 }
476
477 nres++;
478 }
479
480 /*
481 HACK!
482 Pop delta from stack, keeping this function from raceing away!.
483 */
484 delta = lua_gettop( _pState ) - static_cast<int>(stackSizeIn);
485 }
486 /*catch( Base::CException &_e )
487 {
488 va_end( pArg );
489
490 // Make sure to clean up stack in case of errors.
491 delta = lua_gettop( _pState ) - stackSizeIn;
492 if( delta != 0 )
493 lua_pop( _pState, delta );
494
495 g_Log->Warning( "%s", _e.Text().c_str() );
496 //_e.ReportCatch();
497 return 0;
498 }*/
499
500 va_end( pArg );
501
502 return( delta );
503 }
504
505 };
506
507 };
508