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