Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / gui / lua_helper.cpp
blobed4106144bf15bb26837a077f19952c0c5ad79ba
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2013-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "stdpch.h"
23 #include "nel/gui/lua_helper.h"
24 #include "nel/misc/file.h"
26 #ifdef LUA_NEVRAX_VERSION
27 #include "lua_ide_dll_nevrax/include/lua_ide_dll/ide_interface.h" // external debugger
28 #endif
31 #include "nel/gui/lua_loadlib.h"
33 // to get rid of you_must_not_use_assert___use_nl_assert___read_debug_h_file messages
34 #include <cassert>
35 #ifdef assert
36 #undef assert
37 #endif
39 #ifdef NL_DEBUG
40 #define assert(x) nlassert(x)
41 #else
42 #define assert(x)
43 #endif
45 // Always use unique_ptr with ValyriaTear/luabind on Ubuntu 20,
46 // since the setting is not stored in build_information.hpp
47 #ifndef LUABIND_USE_CXX11
48 #define LUABIND_USE_CXX11
49 #endif
51 #include <luabind/luabind.hpp>
52 #include <nel/misc/algo.h>
53 #include <nel/misc/path.h>
55 #ifdef NL_OS_WINDOWS
56 #include <Windows.h>
57 #endif
59 using namespace std;
60 using namespace NLMISC;
62 #ifdef DEBUG_NEW
63 #define new DEBUG_NEW
64 #endif
66 namespace NLGUI
69 namespace LuaHelperStuff
71 void formatLuaStackContext( std::string &stackContext )
73 stackContext = std::string( "@{FC8A}" ).append( stackContext ).append( "@{FC8F} " );
76 std::string formatLuaErrorSysInfo( const std::string &error )
78 return std::string( "@{FC8F}" ).append( error );
81 std::string formatLuaErrorNlWarn( const std::string &error )
83 // Remove color tags (see formatLuaErrorSC())
84 std::string ret = error;
85 strFindReplace( ret, "@{FC8A}", "" );
86 strFindReplace( ret, "@{FC8F}", "" );
87 return ret;
91 // ***************************************************************************
92 const char *CLuaState::_NELSmallScriptTableName= "NELSmallScriptTable";
93 uint CLuaStackChecker::_ExceptionContextCounter = 0;
95 // ***************************************************************************
96 void CLuaStackChecker::incrementExceptionContextCounter()
98 //H_AUTO(Lua_CLuaStackChecker_incrementExceptionContextCounter)
99 ++ _ExceptionContextCounter;
102 // ***************************************************************************
103 void CLuaStackChecker::decrementExceptionContextCounter()
105 //H_AUTO(Lua_CLuaStackChecker_decrementExceptionContextCounter)
106 nlassert(_ExceptionContextCounter > 0);
107 -- _ExceptionContextCounter;
111 #ifdef LUA_NEVRAX_VERSION
112 ILuaIDEInterface *LuaDebuggerIDE = NULL;
113 static bool LuaDebuggerVisible = false;
114 #endif
116 #ifdef NL_OS_WINDOWS
117 HMODULE LuaDebuggerModule = 0;
118 #endif
120 void luaDebuggerMainLoop()
122 #ifdef LUA_NEVRAX_VERSION
123 if (!LuaDebuggerIDE) return;
124 if (!LuaDebuggerVisible)
126 LuaDebuggerIDE->showDebugger(true);
127 LuaDebuggerIDE->expandProjectTree();
128 LuaDebuggerIDE->sortFiles();
129 LuaDebuggerVisible = true;
131 LuaDebuggerIDE->doMainLoop();
132 #endif
137 static std::allocator<uint8> l_stlAlloc;
140 static void l_free_func(void *block, int oldSize)
142 l_stlAlloc.deallocate((uint8 *) block, oldSize);
145 static void *l_realloc_func(void *b, int os, int s)
147 if (os == s) return b;
148 void *newB = l_stlAlloc.allocate(s);
149 memcpy(newB, b, std::min(os, s));
150 l_free_func(b, os);
151 return newB;
156 const int MinGCThreshold = 128; // min value at which garbage collector will be triggered (in kilobytes)
157 // ***************************************************************************
158 CLuaState::CLuaState( bool debugger )
160 _State = NULL;
162 #ifdef LUA_NEVRAX_VERSION
163 _GCThreshold = MinGCThreshold;
164 #endif
166 #ifdef NL_OS_WINDOWS
167 if( debugger )
169 #ifndef LUA_NEVRAX_VERSION
170 static bool warningShown = false;
171 if (!warningShown)
173 nldebug( "Lua debugger was asked, but the static lua library against which the client was linked is too old. Please update to lua-5.0.2_nevrax. Debugging won't be available!" );
174 //MessageBox (NULL, "Lua debugger was asked, but the static lua library against which the client was linked is too old. Please update to lua-5.0.2_nevrax. Debugging won't be available!", "Lua support", MB_OK);
175 warningShown = true;
177 #else
178 nlassert(LuaDebuggerIDE == NULL); // for now, only one debugger supported...
179 #ifdef NL_DEBUG
180 LuaDebuggerModule = ::LoadLibrary("lua_ide2_dll_d.dll");
181 #else
182 LuaDebuggerModule = ::LoadLibrary("lua_ide2_dll_r.dll");
183 #endif
184 if (LuaDebuggerModule)
186 TGetLuaIDEInterfaceVersion getVersion = (TGetLuaIDEInterfaceVersion) GetProcAddress(LuaDebuggerModule, "GetLuaIDEInterfaceVersion");
187 nlassert(getVersion);
188 int dllInterfaceVersion = getVersion();
189 if (dllInterfaceVersion > LUA_IDE_INTERFACE_VERSION)
191 MessageBox (NULL, "Lua debugger interface is newer than the application. Debugging will be disabled. Please update your client", "Lua support", MB_OK);
193 else if (dllInterfaceVersion < LUA_IDE_INTERFACE_VERSION)
195 MessageBox (NULL, "Lua debugger interface is too old. Lua debugging will be disabled. Please ask for a more recent dll.", "Lua support", MB_OK);
197 else
199 TGetLuaIDEInterface getter = (TGetLuaIDEInterface) GetProcAddress(LuaDebuggerModule, "GetLuaIDEInterface");
200 nlassert(getter);
201 LuaDebuggerIDE = getter();
202 LuaDebuggerIDE->prepareDebug("save\\___external_debug.lpr", l_realloc_func, l_free_func, Driver->getDisplay());
203 _State = LuaDebuggerIDE->getLuaState();
206 #endif
208 #endif
210 if (!_State)
212 #ifdef LUA_NEVRAX_VERSION
213 _State = lua_open(l_realloc_func, l_free_func);
214 #elif defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501
215 _State = luaL_newstate();
216 #else
217 _State = lua_open();
218 #endif
219 nlassert(_State);
222 // *** Load base libs
224 CLuaStackChecker lsc(this);
225 #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501
226 luaL_openlibs(_State);
227 #else
228 luaopen_base (_State);
229 luaopen_table (_State);
230 luaopen_io (_State);
231 luaopen_string (_State);
232 luaopen_math (_State);
233 luaopen_debug (_State);
234 #endif
236 #ifdef _WIN32
237 // Lua socket library for MobDebug, optional
238 if (NLMISC::CFile::fileExists("socket\\core.dll"))
240 // Load socket\core.dll dynamically
241 m_LuaSocket = LoadLibraryW(L"socket\\core.dll");
242 if (!m_LuaSocket)
244 nlwarning("Lua socket library found, but failed to load");
246 else
248 void *luaopen_socket_core = (void *)GetProcAddress(m_LuaSocket, "luaopen_socket_core");
249 if (!luaopen_socket_core)
251 nlwarning("Lua socket library loaded, but `luaopen_socket_core` not found");
252 FreeLibrary(m_LuaSocket);
253 m_LuaSocket = NULL;
255 else
257 // preload['socket.core'] = luaopen_socket_core
258 #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501
259 lua_getglobal(_State, "package");
260 lua_getfield(_State, -1, "preload");
261 lua_pushcfunction(_State, (lua_CFunction)luaopen_socket_core);
262 lua_setfield(_State, -2, "socket.core");
263 lua_pop(_State, 2);
264 nlinfo("Lua socket library preloaded");
265 #endif
269 else
271 m_LuaSocket = NULL;
273 #endif
275 // open are buggy????
276 clear();
279 // *** Register basics
280 CLuaStackChecker lsc(this);
282 // do: LUA_REGISTRYINDEX.(lightuserdata*)this.classes= {}
283 pushLightUserData((void *) this);
284 newTable();
285 push("classes");
286 newTable(); // registry class
287 setTable(-3);
288 setTable(LUA_REGISTRYINDEX);
290 // add pointer from lua state to this CLuaState object
291 // do: LUA_REGISTRYINDEX.(lightuserdata*)_State= this
292 pushLightUserData((void *) _State); // NB : as creator of the state, we make the assumption that
293 // no one will be using this pointer in the registry (cf. ref manual about registry)
294 pushLightUserData((void *) this);
295 setTable(LUA_REGISTRYINDEX);
297 // Create the Table that contains Function cache for small script execution
298 push(_NELSmallScriptTableName); // 1:TableName
299 newTable(); // 1:TableName 2:table
300 setTable(LUA_REGISTRYINDEX); // ...
301 _SmallScriptPool= 0;
303 // *** luabind init
304 luabind::open(_State);
308 // ***************************************************************************
309 CLuaStackRestorer::CLuaStackRestorer(CLuaState *state, int finalSize) : _FinalSize(finalSize), _State(state)
313 // ***************************************************************************
314 CLuaStackRestorer::~CLuaStackRestorer()
316 nlassert(_State);
317 _State->setTop(_FinalSize);
320 #ifdef NL_OS_WINDOWS
321 static int NoOpReportHook( int /* reportType */, char * /* message */, int * /* returnValue */ )
323 return TRUE;
325 #endif
328 // ***************************************************************************
329 CLuaState::~CLuaState()
331 nlassert(_State);
333 #ifdef LUA_NEVRAX_VERSION
334 if (!LuaDebuggerIDE)
335 #else
336 if (1)
337 #endif
339 lua_close(_State);
341 else
343 #ifdef LUA_NEVRAX_VERSION
344 LuaDebuggerIDE->stopDebug(); // this will also close the lua state
345 LuaDebuggerIDE = NULL;
346 LuaDebuggerVisible = false;
347 #ifdef NL_OS_WINDOWS
348 nlassert(LuaDebuggerModule)
349 _CrtSetReportHook(NoOpReportHook); // prevent dump of memory leaks at this point
350 //::FreeLibrary(LuaDebuggerModule); // don't free the library now (seems that it destroy, the main window, causing
351 // a crash when the app window is destroyed for real...
352 // -> FreeLibrary will be called when the application is closed
353 LuaDebuggerModule = 0;
354 #endif
355 #endif
358 // Clear Small Script Cache
359 _SmallScriptPool= 0;
360 _SmallScriptCache.clear();
362 #ifdef _WIN32
363 if (m_LuaSocket)
365 FreeLibrary(m_LuaSocket);
366 m_LuaSocket = NULL;
368 #endif
371 // ***************************************************************************
372 CLuaState *CLuaState::fromStatePointer(lua_State *state)
374 //H_AUTO(Lua_CLuaState_fromStatePointer)
375 nlassert(state);
376 int initialStackSize = lua_gettop(state);
377 lua_checkstack(state, initialStackSize + 2);
378 lua_pushlightuserdata(state, (void *) state);
379 lua_gettable(state, LUA_REGISTRYINDEX);
380 if (!lua_islightuserdata(state, -1))
382 lua_pop(state, 1);
383 return NULL;
385 CLuaState *ls = (CLuaState *) lua_touserdata(state, -1);
386 lua_pop(state, 1);
387 nlassert(initialStackSize == lua_gettop(state));
388 return ls;
391 // ***************************************************************************
392 struct CLuaReader
394 const std::string *Str;
395 bool Done;
401 void CLuaState::loadScript(const std::string &code, const std::string &dbgSrc)
403 //H_AUTO(Lua_CLuaState_loadScript)
404 if (code.empty()) return;
405 struct CHelper
407 static const char *luaChunkReaderFromString(lua_State * /* L */, void *ud, size_t *sz)
409 CLuaReader *rd = (CLuaReader *) ud;
410 if (!rd->Done)
412 rd->Done = true;
413 *sz = rd->Str->size();
414 return rd->Str->c_str();
416 else
418 *sz = 0;
419 return NULL;
423 CLuaReader rd;
424 rd.Str = &code;
425 rd.Done = false;
427 int result = lua_load(_State, CHelper::luaChunkReaderFromString, (void *) &rd, dbgSrc.c_str()
428 #if LUA_VERSION_NUM >= 502
429 , NULL
430 #endif
432 if (result !=0)
434 // pop the error code
435 string err= toString();
436 pop();
437 // throw error
438 throw ELuaParseError(err);
442 // ***************************************************************************
443 void CLuaState::executeScriptInternal(const std::string &code, const std::string &dbgSrc, int numRet)
445 //H_AUTO(Lua_CLuaState_executeScriptInternal)
446 CLuaStackChecker lsc(this, numRet);
448 // load the script
449 loadScript(code, dbgSrc);
451 // execute
452 if (pcall(0, numRet) != 0)
454 // pop the error code
455 string err= toString();
456 pop();
457 // throw error
458 throw ELuaExecuteError(err);
462 // ***************************************************************************
463 void CLuaState::executeScript(const std::string &code, int numRet)
465 //H_AUTO(Lua_CLuaState_executeScript)
466 // run the script, with dbgSrc==script
467 executeScriptInternal(code, code, numRet);
470 // ***************************************************************************
471 bool CLuaState::executeScriptNoThrow(const std::string &code, int numRet)
473 //H_AUTO(Lua_CLuaState_executeScriptNoThrow)
476 executeScript(code, numRet);
478 catch (const ELuaError &e)
480 nlwarning(e.what());
481 return false;
483 return true;
486 // ***************************************************************************
487 bool CLuaState::executeFile(const std::string &pathName)
489 //H_AUTO(Lua_CLuaState_executeFile)
491 CIFile inputFile;
492 if(!inputFile.open(pathName))
493 return false;
495 #ifdef LUA_NEVRAX_VERSION
496 if (LuaDebuggerIDE)
498 std::string path = NLMISC::CPath::getCurrentPath() + "/" + pathName.c_str();
499 path = CPath::standardizeDosPath(path);
500 LuaDebuggerIDE->addFile(path.c_str());
502 #endif
504 // load the script text
505 string script;
507 while(!inputFile.eof())
509 char tmpBuff[5000];
510 inputFile.getline(tmpBuff, 5000);
511 script+= tmpBuff;
512 script+= "\n";
515 script.resize(CFile::getFileSize(pathName));
516 inputFile.serialBuffer((uint8 *) &script[0], (uint)script.size());
519 // execute the script text, with dbgSrc==filename (use @ for lua internal purpose)
520 #ifdef _WIN32
521 // Paths need to be correct for debugging to work
522 std::string pathNameStandardized = pathName;
523 if (pathNameStandardized.size() > 1)
525 if (pathNameStandardized[1] == ':' && pathNameStandardized[0] >= 'a' && pathNameStandardized[0] <= 'z')
526 pathNameStandardized[0] -= 'a' - 'A';
527 for (ptrdiff_t i = 0; i < (ptrdiff_t)pathNameStandardized.size(); ++i)
529 if (pathNameStandardized[i] == '/')
530 pathNameStandardized[i] = '\\';
533 #else
534 const std::string &pathNameStandardized = pathName;
535 #endif
536 executeScriptInternal(script, string("@") + pathNameStandardized);
538 return true;
541 // ***************************************************************************
542 void CLuaState::executeSmallScript(const std::string &script)
544 //H_AUTO(Lua_CLuaState_executeSmallScript)
545 if (script.empty()) return;
546 // *** if the small script has not already been called before, parse it now
547 TSmallScriptCache::iterator it= _SmallScriptCache.find(script);
548 if(it==_SmallScriptCache.end())
550 CLuaStackChecker lsc(this);
552 // add it to a function
553 loadScript(script, script);
555 // Assign the method to the NEL table: NELSmallScriptTable[_SmallScriptPool]= function
556 push(_NELSmallScriptTableName); // 1:function 2:NelTableName
557 getTable(LUA_REGISTRYINDEX); // 1:function 2:NelTable
558 insert(-2); // 1:NelTable 2:function
559 rawSetI(-2, _SmallScriptPool); // 1:NelTable
560 pop();
562 // bkup in cache map
563 it= _SmallScriptCache.insert(make_pair(script, _SmallScriptPool)).first;
565 // next allocated
566 _SmallScriptPool++;
569 // *** Execute the function associated to the script
570 CLuaStackChecker lsc(this);
571 push(_NELSmallScriptTableName); // 1:NelTableName
572 getTable(LUA_REGISTRYINDEX); // 1:NelTable
573 // get the function at the given index in the "NELSmallScriptTable" table
574 rawGetI(-1, it->second); // 1:NelTable 2:function
576 // execute
577 if (pcall(0, 0) != 0)
579 // Stack: 1: NelTable 2:errorcode
580 // pop the error code, and clear stack
581 string err= toString();
582 pop(); // 1:NelTable
583 pop(); // ....
584 // throw error
585 throw ELuaExecuteError(err);
587 else
589 // Stack: 1:NelTable
590 pop(); // ....
595 // ***************************************************************************
596 void CLuaState::registerFunc(const char *name, lua_CFunction function)
598 //H_AUTO(Lua_CLuaState_registerFunc)
599 lua_register(_State, name, function);
602 // ***************************************************************************
603 void CLuaState::pushCClosure(lua_CFunction function, int n)
605 //H_AUTO(Lua_CLuaState_pushCClosure)
606 nlassert(function);
607 nlassert(getTop() >= n);
608 lua_pushcclosure(_State, function, n);
611 // ***************************************************************************
612 void CLuaState::push(TLuaWrappedFunction function)
614 //H_AUTO(Lua_CLuaState_push)
615 struct CForwarder
617 static int callFunc(lua_State *ls)
619 nlassert(ls);
620 TLuaWrappedFunction func = (TLuaWrappedFunction) lua_touserdata(ls, lua_upvalueindex(1));
621 CLuaState *state = (CLuaState *) lua_touserdata(ls, lua_upvalueindex(2));
622 nlassert(func);
623 nlassert(state);
624 // get real function pointer from the values in the closure
625 int numResults = 0;
626 int initialStackSize = state->getTop();
629 // call the actual function
630 numResults = func(*state);
632 catch(const std::exception &e)
634 // restore stack to its initial size
635 state->setTop(initialStackSize);
636 lua_pushstring(ls, e.what());
637 // TODO : see if this is safe to call lua error there" ... (it does a long jump)
638 lua_error(ls);
640 return numResults;
643 pushLightUserData((void *) function);
644 pushLightUserData((void *) this);
645 pushCClosure(CForwarder::callFunc, 2);
648 // ***************************************************************************
649 // Wrapped function
650 void CLuaState::registerFunc(const char *name, TLuaWrappedFunction function)
652 //H_AUTO(Lua_CLuaState_registerFunc)
653 nlassert(function);
654 CLuaStackChecker lsc(this);
655 #if LUA_VERSION_NUM >= 502
656 pushGlobalTable();
657 #endif
658 push(name);
659 push(function);
660 #if LUA_VERSION_NUM >= 502
661 setTable(-3); // -3 is the pushGlobalTable
662 pop(1); // pop the pushGlobalTable value (setTable popped the 2 pushes)
663 #else
664 setTable(LUA_GLOBALSINDEX);
665 #endif
669 // ***************************************************************************
670 bool CLuaState::getTableBooleanValue(const char *name, bool defaultValue)
672 //H_AUTO(Lua_CLuaState_getTableBooleanValue)
673 nlassert(name);
674 push(name);
675 getTable(-2);
676 if (isNil())
678 pop();
679 return defaultValue;
681 bool result = toBoolean(-1);
682 pop();
683 return result;
686 // ***************************************************************************
687 double CLuaState::getTableNumberValue(const char *name, double defaultValue)
689 //H_AUTO(Lua_CLuaState_getTableNumberValue)
690 nlassert(name);
691 push(name);
692 getTable(-2);
693 if (isNil())
695 pop();
696 return defaultValue;
698 double result = toNumber(-1);
699 pop();
700 return result;
703 // ***************************************************************************
704 sint64 CLuaState::getTableIntegerValue(const char *name, sint64 defaultValue)
706 //H_AUTO(Lua_CLuaState_getTableIntegerValue)
707 nlassert(name);
708 push(name);
709 getTable(-2);
710 if (isNil())
712 pop();
713 return defaultValue;
715 sint64 result = toInteger(-1);
716 pop();
717 return result;
720 // ***************************************************************************
721 const char *CLuaState::getTableStringValue(const char *name, const char *defaultValue)
723 //H_AUTO(Lua_CLuaState_getTableStringValue)
724 nlassert(name);
725 push(name);
726 getTable(-2);
727 if (isNil())
729 pop();
730 return defaultValue;
732 const char *result = toString(-1);
733 pop();
734 return result;
737 // ***************************************************************************
738 void CLuaState::getStackContext(string &ret, uint stackLevel)
740 //H_AUTO(Lua_CLuaState_getStackContext)
741 nlassert(_State);
742 ret.clear();
743 lua_Debug dbg;
744 if(lua_getstack (_State, stackLevel, &dbg))
746 if(lua_getinfo(_State, "lS", &dbg))
748 ret= NLMISC::toString("%s:%d:", dbg.short_src, dbg.currentline);
753 // ***************************************************************************
754 int CLuaState::pcallByNameGlobal(const char *functionName, int nargs, int nresults, int errfunc /*= 0*/)
756 int initialStackSize = getTop();
757 nlassert(functionName);
758 #if LUA_VERSION_NUM >= 502
759 pushGlobalTable();
760 #else
761 nlassert(isTable(LUA_GLOBALSINDEX));
762 pushValue(LUA_GLOBALSINDEX);
763 #endif
764 return pcallByNameInternal(functionName, nargs, nresults, errfunc, initialStackSize);
767 int CLuaState::pcallByName(const char *functionName, int nargs, int nresults, int funcTableIndex, int errfunc /*= 0*/)
769 int initialStackSize = getTop();
770 nlassert(functionName);
771 nlassert(isTable(funcTableIndex));
772 pushValue(funcTableIndex);
773 return pcallByNameInternal(functionName, nargs, nresults, errfunc, initialStackSize);
776 int CLuaState::pcallByNameInternal(const char *functionName, int nargs, int nresults, int errfunc /*= 0*/, int initialStackSize)
778 //H_AUTO(Lua_CLuaState_pcallByName)
779 push(functionName);
780 getTable(-2);
781 remove(-2); // get rid of the table
782 nlassert(getTop() >= nargs); // not enough arguments on the stack
783 // insert function before its arguments
784 insert(- 1 - nargs);
785 int result = pcall(nargs, nresults, errfunc);
786 int currSize = getTop();
787 if (result == 0)
789 nlassert(currSize == initialStackSize - nargs + nresults);
791 else
793 // errors, the stack contains a single string
794 if (errfunc == 0)
796 nlassert(currSize == initialStackSize - nargs + 1);
798 // else if there's an error handler, can't know the size of stack
800 return result;
803 // ***************************************************************************
804 void CLuaState::dumpStack()
806 //H_AUTO(Lua_CLuaState_dumpStack)
807 nlinfo("LUA STACK CONTENT (size = %d)", getTop());
808 nlinfo("=================");
809 CLuaStackChecker lsc(this);
810 for(int k = 1; k <= getTop(); ++k)
812 pushValue(k);
813 std::string value = toString(-1) ? toString(-1) : "?";
814 nlinfo("Stack entry %d : type = %s, value = %s", k, getTypename(type(-1)), value.c_str());
815 pop();
819 // ***************************************************************************
820 void CLuaState::getStackAsString(std::string &dest)
822 //H_AUTO(Lua_CLuaState_getStackAsString)
823 dest = NLMISC::toString("Stack size = %d\n", getTop());
824 CLuaStackChecker lsc(this);
825 for(int k = 1; k <= getTop(); ++k)
827 pushValue(k);
828 std::string value = toString(-1) ? toString(-1) : "?";
829 dest += NLMISC::toString("Stack entry %d : type = %s, value = %s\n", k, getTypename(type(-1)), value.c_str());
830 pop();
834 //================================================================================
835 CLuaStackChecker::~CLuaStackChecker()
837 nlassert(_State);
838 if (!_ExceptionContextCounter)
840 int currSize = _State->getTop();
841 if (currSize != _FinalWantedSize)
843 static volatile bool assertWanted = true;
844 if (assertWanted)
846 nlwarning("Lua stack size error : expected size is %d, current size is %d", _FinalWantedSize, currSize);
847 _State->dumpStack();
848 nlassert(0);
852 else
854 // this object dtor was called because an exception was thrown, so let the exception
855 // propagate (the stack must be broken, but because of the exception, not because of code error)
856 _State->setTop(_FinalWantedSize);
860 // ***************************************************************************
861 void ELuaWrappedFunctionException::init(CLuaState *ls, const std::string &reason)
863 //H_AUTO(Lua_ELuaWrappedFunctionException_init)
864 // Print first Lua Stack Context
865 if(ls)
867 ls->getStackContext(_Reason, 1); // 1 because 0 is the current C function => return 1 for script called
868 // enclose with cool colors
869 LuaHelperStuff::formatLuaStackContext(_Reason);
872 // Append the reason
873 _Reason+= reason;
876 // ***************************************************************************
877 ELuaWrappedFunctionException::ELuaWrappedFunctionException(CLuaState *luaState)
879 //H_AUTO(Lua_ELuaWrappedFunctionException_ELuaWrappedFunctionException)
880 init(luaState, "");
883 // ***************************************************************************
884 ELuaWrappedFunctionException::ELuaWrappedFunctionException(CLuaState *luaState, const std::string &reason)
886 //H_AUTO(Lua_ELuaWrappedFunctionException_ELuaWrappedFunctionException)
887 init(luaState, reason);
890 // ***************************************************************************
891 ELuaWrappedFunctionException::ELuaWrappedFunctionException(CLuaState *luaState, const char *format, ...)
893 //H_AUTO(Lua_ELuaWrappedFunctionException_ELuaWrappedFunctionException)
894 std::string reason;
895 NLMISC_CONVERT_VARGS (reason, format, NLMISC::MaxCStringSize);
896 init(luaState, reason);
899 //================================================================================
900 void CLuaState::newTable()
902 //H_AUTO(Lua_CLuaState_newTable)
903 nlverify( lua_checkstack(_State, 1) );
904 lua_newtable(_State);
907 //================================================================================
908 int CLuaState::getGCCount()
910 //H_AUTO(Lua_CLuaState_getGCCount)
911 #if LUA_VERSION_NUM >= 502
912 // deprecated
913 return 0;
914 #else
915 return lua_getgccount(_State);
916 #endif
919 //================================================================================
920 int CLuaState::getGCThreshold()
922 //H_AUTO(Lua_CLuaState_getGCThreshold)
923 #ifdef LUA_NEVRAX_VERSION
924 return _GCThreshold;
925 #else
926 # if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501
927 return lua_gc(_State, LUA_GCCOUNT, 0);
928 # else
929 return lua_getgcthreshold(_State);
930 # endif
931 #endif
934 //================================================================================
935 void CLuaState::setGCThreshold(int kb)
937 //H_AUTO(Lua_CLuaState_setGCThreshold)
938 #ifdef LUA_NEVRAX_VERSION
939 _GCThreshold = kb;
940 handleGC();
941 #else
942 # if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501
943 lua_gc(_State, LUA_GCCOLLECT, kb);
944 # else
945 lua_setgcthreshold(_State, kb);
946 # endif
947 #endif
950 //================================================================================
951 void CLuaState::handleGC()
953 //H_AUTO(Lua_CLuaState_handleGC)
954 #ifdef LUA_NEVRAX_VERSION
955 // must handle gc manually with the refcounted version
956 int gcCount = getGCCount();
957 if (gcCount >= _GCThreshold)
959 nlwarning("Triggering GC : memory in use = %d kb, current threshold = %d kb", gcCount, _GCThreshold);
960 lua_setgcthreshold(_State, 0);
961 gcCount = getGCCount();
962 _GCThreshold = std::max(MinGCThreshold, gcCount * 2);
963 nlwarning("After GC : memory in use = %d kb, threshold = %d kb", gcCount, _GCThreshold);
965 #endif