/* see copyright notice in squirrel.h */ #include "../../../stdafx.h" #include #include #include "../../fmt/format.h" #include "../../../safeguards.h" void sqstd_printcallstack(HSQUIRRELVM v) { SQPRINTFUNCTION pf = sq_getprintfunc(v); if(pf) { SQStackInfos si; SQInteger i; SQBool b; SQFloat f; SQInteger level=1; //1 is to skip this function that is level 0 SQInteger seq=0; pf(v,"\n"); pf(v,"CALLSTACK WITH LOCALS\n"); while(SQ_SUCCEEDED(sq_stackinfos(v,level,&si))) { std::string_view fn="unknown"; std::string_view src="unknown"; if(!si.funcname.empty())fn=si.funcname; if(!si.source.empty()) { /* We don't want to bother users with absolute paths to all AI files. * Since the path only reaches NoAI code in a formatted string we have * to strip it here. Let's hope nobody installs openttd in a subdirectory * of a directory named /ai/. */ auto p = si.source.find("\\ai\\"); if (p == std::string_view::npos) p = si.source.find("/ai/"); src = (p == std::string_view::npos) ? si.source : si.source.substr(p + 4); } pf(v,fmt::format("*FUNCTION [{}()] {} line [{}]\n",fn,src,si.line)); seq=0; std::optional opt; while ((opt = sq_getlocal(v,level,seq)).has_value()) { std::string_view name = *opt; seq++; switch(sq_gettype(v,-1)) { case OT_NULL: pf(v,fmt::format(" [{}] NULL\n",name)); break; case OT_INTEGER: sq_getinteger(v,-1,&i); pf(v,fmt::format(" [{}] {}\n",name,i)); break; case OT_FLOAT: sq_getfloat(v,-1,&f); pf(v,fmt::format(" [{}] {:14g}\n",name,f)); break; case OT_USERPOINTER: pf(v,fmt::format(" [{}] USERPOINTER\n",name)); break; case OT_STRING: { std::string_view view; sq_getstring(v,-1,view); pf(v,fmt::format(" [{}] \"{}\"\n",name,view)); break; } case OT_TABLE: pf(v,fmt::format(" [{}] TABLE\n",name)); break; case OT_ARRAY: pf(v,fmt::format(" [{}] ARRAY\n",name)); break; case OT_CLOSURE: pf(v,fmt::format(" [{}] CLOSURE\n",name)); break; case OT_NATIVECLOSURE: pf(v,fmt::format(" [{}] NATIVECLOSURE\n",name)); break; case OT_GENERATOR: pf(v,fmt::format(" [{}] GENERATOR\n",name)); break; case OT_USERDATA: pf(v,fmt::format(" [{}] USERDATA\n",name)); break; case OT_THREAD: pf(v,fmt::format(" [{}] THREAD\n",name)); break; case OT_CLASS: pf(v,fmt::format(" [{}] CLASS\n",name)); break; case OT_INSTANCE: pf(v,fmt::format(" [{}] INSTANCE\n",name)); break; case OT_WEAKREF: pf(v,fmt::format(" [{}] WEAKREF\n",name)); break; case OT_BOOL:{ sq_getbool(v,-1,&b); pf(v,fmt::format(" [{}] {}\n",name,b?"true":"false")); } break; default: assert(0); break; } sq_pop(v,1); } level++; } } } static SQInteger _sqstd_aux_printerror(HSQUIRRELVM v) { SQPRINTFUNCTION pf = sq_getprintfunc(v); if(pf) { std::string_view error; if(sq_gettop(v)>=1) { pf(v,"\n"); if(SQ_SUCCEEDED(sq_getstring(v,2,error))) { pf(v,fmt::format("AN ERROR HAS OCCURRED [{}]\n",error)); } else{ pf(v,"AN ERROR HAS OCCURRED [unknown]\n"); } sqstd_printcallstack(v); } } return 0; } void _sqstd_compiler_error(HSQUIRRELVM v,std::string_view sErr,std::string_view sSource,SQInteger line,SQInteger column) { SQPRINTFUNCTION pf = sq_getprintfunc(v); if(pf) { pf(v,fmt::format("{} line = ({}) column = ({}) : error {}\n",sSource,line,column,sErr)); } } void sqstd_seterrorhandlers(HSQUIRRELVM v) { sq_setcompilererrorhandler(v,_sqstd_compiler_error); sq_newclosure(v,_sqstd_aux_printerror,0); sq_seterrorhandler(v); }