SQInteger CSquirrel::PrintErrorFunction(SQVM * pVM) { if(sq_gettop(pVM) >= 1) { const SQChar * szError = NULL; sq_getstring(pVM, 2, &szError); ErrorInfo info; info.strError = szError; SQStackInfos si; SQInteger level = 1; // 1 is to skip this function that is level 0 const SQChar *name = 0; SQInteger seq = 0; while(SQ_SUCCEEDED(sq_stackinfos(pVM, level, &si))) { const SQChar * fn = _SC("unknown"); const SQChar * src = _SC("unknown"); if(si.funcname) fn = si.funcname; if(si.source) src = si.source; info.callstack.push_back(ErrorCallstackPair(fn, ErrorSourcePair(src, si.line))); level++; } for(level = 0; level < 10; level++) { seq = 0; while((name = sq_getlocal(pVM, level, seq))) { seq++; CSquirrelArgument arg; arg.pushFromStack(pVM, -1); info.locals.push_back(ErrorLocalPair(name, arg)); sq_pop(pVM, 1); } } CSquirrel * pScript = CScriptingManager::GetInstance()->Get(pVM); if(pScript) { CSquirrelArguments arguments; CSquirrelArguments tempArray; CSquirrelArguments callstackTable; CSquirrelArguments localsTable; arguments.push(info.strError); for(ErrorCallstackList::iterator iter = info.callstack.begin(); iter != info.callstack.end(); iter++) { String strFunction = iter->first; String strSource = iter->second.first; int iLine = iter->second.second; callstackTable.push(strFunction); tempArray.reset(); tempArray.push(strSource); tempArray.push(iLine); callstackTable.push(tempArray, true); } arguments.push(callstackTable, false); for(ErrorLocalsList::iterator iter = info.locals.begin(); iter != info.locals.end(); iter++) { String strName = iter->first; CSquirrelArgument arg = iter->second; localsTable.push(strName); localsTable.push(arg); } arguments.push(localsTable, false); if(CEvents::GetInstance()->Call("scriptError", &arguments, pScript).GetInteger() == 1) { CLogFile::Printf("<Error (%s)>", info.strError.Get()); CLogFile::Printf("<Callstack>"); for(ErrorCallstackList::iterator iter = info.callstack.begin(); iter != info.callstack.end(); iter++) { String strFunction = iter->first; String strSource = iter->second.first; int iLine = iter->second.second; CLogFile::Printf("<%s (%s, %d)>", strFunction.Get(), strSource.Get(), iLine); } CLogFile::Printf("</Callstack>"); CLogFile::Printf("<Locals>"); for(ErrorLocalsList::iterator iter = info.locals.begin(); iter != info.locals.end(); iter++) { String strName = iter->first; CSquirrelArgument arg = iter->second; CLogFile::Printf("<%s (%s)>", strName.Get(), arg.GetTypeString().Get()); } CLogFile::Printf("</Locals>"); CLogFile::Printf("</Error>"); } } } return 0; }
/** * Get the real-instance pointer. * @note This will only work just after a function-call from within Squirrel * to your C++ function. */ static bool GetRealInstance(HSQUIRRELVM vm, SQUserPointer *ptr) { return SQ_SUCCEEDED(sq_getinstanceup(vm, 1, ptr, 0)); }
static SQInteger array_pop(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_arraypop(v,1,SQTrue))?1:SQ_ERROR; }
ScriptBehavior::ScriptBehavior( HSQUIRRELVM vm,HSQOBJECT classObject,const std::map< tstring_symbol,ScriptParameterInterfacePtr >& scriptParameters ) : m_vm(vm) , m_start(false) { int top = sq_gettop(m_vm); sq_pushobject(m_vm, classObject); sq_pushroottable( m_vm ); m_initialize = false; m_haveAwake = false; m_haveStart = false; m_haveUpdate = false; if( SQ_SUCCEEDED( sq_call( m_vm,1,SQTrue,SQTrue) ) ) { if( SQ_SUCCEEDED( sq_getstackobj(m_vm, -1, &m_instance) ) ) { sq_addref( m_vm,&m_instance ); m_initialize = true; sq_pushstring( m_vm,_SC("Awake"),-1 ); if( SQ_SUCCEEDED( sq_get(m_vm,-2 ) ) ) { if( SQ_SUCCEEDED( sq_getstackobj(m_vm, -1, &m_awakeFunction) ) ) { sq_addref( m_vm,&m_awakeFunction ); m_haveAwake = true; } } sq_pop(m_vm,1); sq_pushstring( m_vm,_SC("Start"),-1 ); if( SQ_SUCCEEDED( sq_get(m_vm,-2 ) ) ) { if( SQ_SUCCEEDED( sq_getstackobj(m_vm, -1, &m_startFunction) ) ) { sq_addref( m_vm,&m_startFunction ); m_haveStart = true; } } sq_pop(m_vm,1); sq_pushstring( m_vm,_SC("Update"),-1 ); if( SQ_SUCCEEDED( sq_get(m_vm,-2 ) ) ) { if( SQ_SUCCEEDED( sq_getstackobj(m_vm, -1, &m_updateFunction) ) ) { sq_addref( m_vm,&m_updateFunction ); m_haveUpdate = true; } } sq_pop(m_vm,1); std::map< tstring_symbol,ScriptParameterInterfacePtr >::const_iterator it = scriptParameters.begin(); while( it!=scriptParameters.end() ) { it->second->SetParameter( m_vm ); it++; } } } sq_settop( m_vm,top ); }
static SQInteger class_instance(HSQUIRRELVM v) { if(SQ_SUCCEEDED(sq_createinstance(v,-1))) return 1; return SQ_ERROR; }
bool CSquirrelArgument::pushFromStack(SQVM * pVM, int idx) { reset(); SQObjectPtr obj = stack_get(pVM, idx); switch(obj._type) { case OT_NULL: // Nothing needed break; case OT_INTEGER: data.i = obj._unVal.nInteger; break; case OT_BOOL: data.b = (obj._unVal.nInteger != 0); break; case OT_FLOAT: data.f = obj._unVal.fFloat; break; case OT_STRING: data.str = new String(obj._unVal.pString->_val); break; case OT_TABLE: { CSquirrelArguments * pArguments = new CSquirrelArguments(); sq_push(pVM, idx); sq_pushnull(pVM); while(SQ_SUCCEEDED(sq_next(pVM, -2))) { if(!pArguments->pushFromStack(pVM, -2) || !pArguments->pushFromStack(pVM, -1)) { sq_pop(pVM, 4); delete pArguments; return false; } sq_pop(pVM, 2); } sq_pop(pVM, 2); data.pArray = pArguments; } break; case OT_ARRAY: { CSquirrelArguments * pArguments = new CSquirrelArguments(); sq_push(pVM, idx); sq_pushnull(pVM); while(SQ_SUCCEEDED(sq_next(pVM, -2))) { if(!pArguments->pushFromStack(pVM, -1)) { sq_pop(pVM, 4); delete pArguments; return false; } sq_pop(pVM, 2); } sq_pop(pVM, 2); data.pArray = pArguments; } break; case OT_CLOSURE: case OT_NATIVECLOSURE: data.sqObject = SQObject(obj); break; case OT_INSTANCE: data.pInstance = obj._unVal.pInstance; break; default: return false; break; } type = obj._type; return true; }
bool ScriptObject::_getSlot(const char* name) const { sq_pushobject(mSqvm, mObj); sq_pushstring(mSqvm, name, -1); return SQ_SUCCEEDED(sq_get(mSqvm, -2)); }
void ConsoleImpl::eval_command_line() { if (!command_line.empty() && (history.empty() || history.back() != command_line)) { history.push_back(command_line); history_position = history.size(); } console << ">" << command_line << std::endl; if (command_line == "quit" || command_line == "exit") { console.deactive(); } else if (command_line == "help") { console << "This is a script console, can enter stuff in here that will then be evaluated.\n" << "Type 'quit' to exit the console." << std::endl; } else if (command_line == "reset") { GameSession::current()->set_sector("levels/newformat2.wst"); } else if (command_line == "show") { HSQUIRRELVM v = script_manager->get_vm(); int size = sq_getsize(v, -1); console << size << " elements on the root table" << std::endl; sq_pushroottable(v); //push your table/array here sq_pushnull(v); //null iterator while(SQ_SUCCEEDED(sq_next(v,-2))) { //here -1 is the value and -2 is the key const SQChar *s; if (SQ_SUCCEEDED(sq_getstring(v,-2, &s))) { console << s << " -> " << squirrel2string(v, -1) << std::endl; } else { console << "Unknown key type for element" << std::endl; } sq_pop(v,2); //pops key and val before the nex iteration } sq_pop(v, 1); } else { execute(command_line); maybe_newline(); } command_line = ""; cursor_pos = 0; }
/** * スレッドのメイン処理 * @param diff 経過時間 * @return スレッド実行終了なら true */ bool Thread::_main(long diff) { // スレッドとして動作できてない場合は即終了 if (_status == THREAD_NONE) { return true; } if (_status == THREAD_LOADING_FILE) { // ファイル読み込み処理 const char *dataAddr; int dataSize; if (sqobjCheckFile(_fileHandler, &dataAddr, &dataSize)) { _init(); SQRESULT ret = sqstd_loadmemory(_thread, dataAddr, dataSize, _scriptName.getString(), SQTrue); sqobjCloseFile(_fileHandler); _fileHandler = NULL; if (SQ_SUCCEEDED(ret)) { _status = THREAD_RUN; } else { // exit相当 printError(); _exit(); return true; } } else { // 読み込み完了待ち return false; } } else if (_status == THREAD_LOADING_FUNC) { // スクリプト読み込み処理 _init(); _func.push(_thread); _func.clear(); _status = THREAD_RUN; } _currentTick += diff; // タイムアウト処理 if (_waitTimeout >= 0) { _waitTimeout -= diff; if (_waitTimeout < 0) { _clearWait(); } } // スレッド実行 if (!isWait() && _status == THREAD_RUN) { SQRESULT result; if (sq_getvmstate(_thread) == SQ_VMSTATE_SUSPENDED) { _waitResult.push(_thread); _waitResult.clear(); result = sq_wakeupvm(_thread, SQTrue, SQTrue, SQTrue, SQFalse); } else { sq_pushroottable(_thread); SQInteger n = _args.pushArray(_thread) + 1; _args.clear(); result = sq_call(_thread, n, SQTrue, SQTrue); } if (SQ_FAILED(result)) { // スレッドがエラー終了 printError(); _exit(); } else { // 終了コード取得。return/suspend の値が格納される _exitCode.getStack(_thread, -1); sq_pop(_thread, 1); if (sq_getvmstate(_thread) == SQ_VMSTATE_IDLE) { // スレッドが終了 _exit(); } } } return _status == THREAD_NONE; }
void Interactive(HSQUIRRELVM v) { #define MAXINPUT 1024 SQChar buffer[MAXINPUT]; SQInteger blocks =0; SQInteger string=0; SQInteger retval=0; SQInteger done=0; PrintVersionInfos(); sq_pushroottable(v); sq_pushstring(v,_SC("quit"),-1); sq_pushuserpointer(v,&done); sq_newclosure(v,quit,1); sq_setparamscheck(v,1,NULL); sq_createslot(v,-3); sq_pop(v,1); while (!done) { SQInteger i = 0; scprintf(_SC("\nsq>")); for(;;) { int c; if(done)return; c = getchar(); if (c == _SC('\n')) { if (i>0 && buffer[i-1] == _SC('\\')) { buffer[i-1] = _SC('\n'); } else if(blocks==0)break; buffer[i++] = _SC('\n'); } else if (c==_SC('}')) {blocks--; buffer[i++] = (SQChar)c;} else if(c==_SC('{') && !string){ blocks++; buffer[i++] = (SQChar)c; } else if(c==_SC('"') || c==_SC('\'')){ string=!string; buffer[i++] = (SQChar)c; } else if (i >= MAXINPUT-1) { scfprintf(stderr, _SC("sq : input line too long\n")); break; } else{ buffer[i++] = (SQChar)c; } } buffer[i] = _SC('\0'); if(buffer[0]==_SC('=')){ scsprintf(sq_getscratchpad(v,MAXINPUT),_SC("return (%s)"),&buffer[1]); memcpy(buffer,sq_getscratchpad(v,-1),(scstrlen(sq_getscratchpad(v,-1))+1)*sizeof(SQChar)); retval=1; } i=scstrlen(buffer); if(i>0){ SQInteger oldtop=sq_gettop(v); if(SQ_SUCCEEDED(sq_compilebuffer(v,buffer,i,_SC("interactive console"),SQTrue))){ sq_pushroottable(v); if(SQ_SUCCEEDED(sq_call(v,1,retval,SQTrue)) && retval){ scprintf(_SC("\n")); sq_pushroottable(v); sq_pushstring(v,_SC("print"),-1); sq_get(v,-2); sq_pushroottable(v); sq_push(v,-4); sq_call(v,2,SQFalse,SQTrue); retval=0; scprintf(_SC("\n")); } } sq_settop(v,oldtop); } } }
//<<FIXME>> this func is a mess int getargs(HSQUIRRELVM v,int argc, char* argv[]) { int i; int compiles_only = 0; static SQChar temp[500]; const SQChar *ret=NULL; char * output = NULL; int lineinfo=0; int endian=0; const char *precompile = NULL; if(argc>1) { int arg=1,exitloop=0; while(arg < argc && !exitloop) { if(argv[arg][0]=='-') { switch(argv[arg][1]) { case 'd': //DEBUG(debug infos) sq_enabledebuginfo(v,1); break; case 'c': compiles_only = 1; break; case 'o': if(arg < argc) { arg++; output = argv[arg]; } break; case 'e': if(arg < argc) { arg++; endian = atoi(argv[arg]); } break; case 'v': PrintVersionInfos(); return _DONE; case 'h': PrintVersionInfos(); PrintUsage(); return _DONE; case 'p': if (arg < argc) { arg++; precompile = argv[arg]; } break; default: PrintVersionInfos(); scprintf(_SC("unknown prameter '-%c'\n"),argv[arg][1]); PrintUsage(); return _ERROR; } }else break; arg++; } // precompile header if (precompile) { const SQChar *a; #ifdef SQUNICODE int alen=(int)strlen(precompile); a=sq_getscratchpad(v,(int)(alen*sizeof(SQChar))); mbstowcs(sq_getscratchpad(v,-1),precompile,alen); sq_getscratchpad(v,-1)[alen] = _SC('\0'); #else a=precompile; #endif if(SQ_FAILED(sqstd_dofile(v,a,SQFalse,SQTrue))) { const SQChar *err; sq_getlasterror(v); if(SQ_SUCCEEDED(sq_getstring(v,-1,&err))) { scprintf(_SC("Error [%s]\n"),err); return _ERROR; } } } // src file if(arg<argc) { const SQChar *filename=NULL; #ifdef SQUNICODE mbstowcs(temp,argv[arg],strlen(argv[arg])); filename=temp; #else filename=argv[arg]; #endif arg++; sq_pushroottable(v); sq_pushstring(v,_SC("ARGS"),-1); sq_newarray(v,0); for(i=arg;i<argc;i++) { const SQChar *a; #ifdef SQUNICODE int alen=(int)strlen(argv[i]); a=sq_getscratchpad(v,(int)(alen*sizeof(SQChar))); mbstowcs(sq_getscratchpad(v,-1),argv[i],alen); sq_getscratchpad(v,-1)[alen] = _SC('\0'); #else a=argv[i]; #endif sq_pushstring(v,a,-1); sq_arrayappend(v,-2); } sq_createslot(v,-3); sq_pop(v,1); if(compiles_only) { if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,SQTrue))){ SQChar *outfile = _SC("out.cnut"); if(output) { #ifdef SQUNICODE int len = (int)(strlen(output)+1); mbstowcs(sq_getscratchpad(v,len*sizeof(SQChar)),output,len); outfile = sq_getscratchpad(v,-1); #else outfile = output; #endif } if(SQ_SUCCEEDED(sqstd_writeclosuretofile(v,outfile,endian))) return _DONE; } } else { if(SQ_SUCCEEDED(sqstd_dofile(v,filename,SQFalse,SQTrue))) { return _DONE; } } //if this point is reached an error occured { const SQChar *err; sq_getlasterror(v); if(SQ_SUCCEEDED(sq_getstring(v,-1,&err))) { scprintf(_SC("Error [%s]\n"),err); return _ERROR; } } } } return _INTERACTIVE; }
int app_sqlang_run_ex(sip_msg_t *msg, char *func, char *p1, char *p2, char *p3, int emode) { int n; int ret; int top; sip_msg_t *bmsg; SQInteger rv; if(_sr_J_env.JJ==NULL) { LM_ERR("sqlang loading state not initialized (call: %s)\n", func); return -1; } /* check the script version loaded */ sqlang_kemi_reload_script(); top = sqlang_gettop(_sr_J_env.JJ); LM_DBG("sqlang top index is: %d\n", top); sq_pushroottable(_sr_J_env.JJ); /* pushes the global table */ sq_pushstring(_sr_J_env.JJ, _SC(func), -1); if(!SQ_SUCCEEDED(sq_get(_sr_J_env.JJ, -2))) { /* failed to gets the func field from the global table */ sq_settop(_sr_J_env.JJ, (top<=0)?1:top); /* restores the original stack size */ LM_ERR("sqlang failed to find symbol (call: %s)\n", func); return -1; } if(!sqlang_isfunction(_sr_J_env.JJ, -1)) { LM_ERR("no such function [%s] in sqlang scripts\n", func); LM_ERR("top stack type [%d]\n", sqlang_gettype(_sr_J_env.JJ, -1)); } /* push the 'this' (in this case is the global table) */ sq_pushroottable(_sr_J_env.JJ); n = 1; if(p1!=NULL) { sqlang_pushstring(_sr_J_env.JJ, p1); n++; if(p2!=NULL) { sqlang_pushstring(_sr_J_env.JJ, p2); n++; if(p3!=NULL) { sqlang_pushstring(_sr_J_env.JJ, p3); n++; } } } LM_DBG("executing sqlang function: [[%s]] (n: %d)\n", func, n); bmsg = _sr_J_env.msg; _sr_J_env.msg = msg; _sr_J_env.JJ_exit = 0; /* call the function */ rv = sq_call(_sr_J_env.JJ, n, SQFalse, SQTrue); if(SQ_SUCCEEDED(rv)) { ret = 1; } else { if(_sr_J_env.JJ_exit==0) { LM_ERR("failed to execute the func: %s (%d)\n", func, (int)rv); sqstd_printcallstack(_sr_J_env.JJ); ret = -1; } else { LM_DBG("script execution exit\n"); ret = 1; } } _sr_J_env.msg = bmsg; _sr_J_env.JJ_exit = 0; sq_settop(_sr_J_env.JJ, (top<=0)?1:top); /* restores the original stack size */ return ret; }
SQInteger AIInfo::AddSetting(HSQUIRRELVM vm) { AIConfigItem config; memset(&config, 0, sizeof(config)); config.max_value = 1; config.step_size = 1; uint items = 0; /* Read the table, and find all properties we care about */ sq_pushnull(vm); while (SQ_SUCCEEDED(sq_next(vm, -2))) { const SQChar *sqkey; if (SQ_FAILED(sq_getstring(vm, -2, &sqkey))) return SQ_ERROR; const char *key = SQ2OTTD(sqkey); if (strcmp(key, "name") == 0) { const SQChar *sqvalue; if (SQ_FAILED(sq_getstring(vm, -1, &sqvalue))) return SQ_ERROR; char *name = strdup(SQ2OTTD(sqvalue)); char *s; /* Don't allow '=' and ',' in configure setting names, as we need those * 2 chars to nicely store the settings as a string. */ while ((s = strchr(name, '=')) != NULL) *s = '_'; while ((s = strchr(name, ',')) != NULL) *s = '_'; config.name = name; items |= 0x001; } else if (strcmp(key, "description") == 0) { const SQChar *sqdescription; if (SQ_FAILED(sq_getstring(vm, -1, &sqdescription))) return SQ_ERROR; config.description = strdup(SQ2OTTD(sqdescription)); items |= 0x002; } else if (strcmp(key, "min_value") == 0) { SQInteger res; if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; config.min_value = res; items |= 0x004; } else if (strcmp(key, "max_value") == 0) { SQInteger res; if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; config.max_value = res; items |= 0x008; } else if (strcmp(key, "easy_value") == 0) { SQInteger res; if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; config.easy_value = res; items |= 0x010; } else if (strcmp(key, "medium_value") == 0) { SQInteger res; if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; config.medium_value = res; items |= 0x020; } else if (strcmp(key, "hard_value") == 0) { SQInteger res; if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; config.hard_value = res; items |= 0x040; } else if (strcmp(key, "random_deviation") == 0) { SQInteger res; if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; config.random_deviation = res; items |= 0x200; } else if (strcmp(key, "custom_value") == 0) { SQInteger res; if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; config.custom_value = res; items |= 0x080; } else if (strcmp(key, "step_size") == 0) { SQInteger res; if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; config.step_size = res; } else if (strcmp(key, "flags") == 0) { SQInteger res; if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR; config.flags = (AIConfigFlags)res; items |= 0x100; } else { char error[1024]; snprintf(error, sizeof(error), "unknown setting property '%s'", key); this->engine->ThrowError(error); return SQ_ERROR; } sq_pop(vm, 2); } sq_pop(vm, 1); /* Don't allow both random_deviation and AICONFIG_RANDOM to * be set for the same config item. */ if ((items & 0x200) != 0 && (config.flags & AICONFIG_RANDOM) != 0) { char error[1024]; snprintf(error, sizeof(error), "Setting both random_deviation and AICONFIG_RANDOM is not allowed"); this->engine->ThrowError(error); return SQ_ERROR; } /* Reset the bit for random_deviation as it's optional. */ items &= ~0x200; /* Make sure all properties are defined */ uint mask = (config.flags & AICONFIG_BOOLEAN) ? 0x1F3 : 0x1FF; if (items != mask) { char error[1024]; snprintf(error, sizeof(error), "please define all properties of a setting (min/max not allowed for booleans)"); this->engine->ThrowError(error); return SQ_ERROR; } this->config_list.push_back(config); return 0; }
std::string squirrel2string(HSQUIRRELVM v, SQInteger i) { std::ostringstream os; switch(sq_gettype(v, i)) { case OT_NULL: os << "<null>"; break; case OT_BOOL: { SQBool p; if (SQ_SUCCEEDED(sq_getbool(v, i, &p))) { if (p) os << "true"; else os << "false"; } break; } case OT_INTEGER: { SQInteger val; sq_getinteger(v, i, &val); os << val; break; } case OT_FLOAT: { SQFloat val; sq_getfloat(v, i, &val); os << val; break; } case OT_STRING: { const SQChar* val; sq_getstring(v, i, &val); os << "\"" << val << "\""; break; } case OT_TABLE: { bool first = true; os << "{"; sq_pushnull(v); //null iterator while(SQ_SUCCEEDED(sq_next(v,i-1))) { if (!first) { os << ", "; } first = false; //here -1 is the value and -2 is the key os << squirrel2string(v, -2) << " => " << squirrel2string(v, -1); sq_pop(v,2); //pops key and val before the nex iteration } sq_pop(v, 1); os << "}"; break; } case OT_ARRAY: { bool first = true; os << "["; sq_pushnull(v); //null iterator while(SQ_SUCCEEDED(sq_next(v,i-1))) { if (!first) { os << ", "; } first = false; //here -1 is the value and -2 is the key // we ignore the key, since that is just the index in an array os << squirrel2string(v, -1); sq_pop(v,2); //pops key and val before the nex iteration } sq_pop(v, 1); os << "]"; break; } case OT_USERDATA: os << "<userdata>"; break; case OT_CLOSURE: os << "<closure>"; break; case OT_NATIVECLOSURE: os << "<native closure>"; break; case OT_GENERATOR: os << "<generator>"; break; case OT_USERPOINTER: os << "userpointer"; break; case OT_THREAD: os << "<thread>"; break; case OT_CLASS: os << "<class>"; break; case OT_INSTANCE: os << "<instance>"; break; case OT_WEAKREF: os << "<weakref>"; break; default: os << "<unknown>"; break; } return os.str(); }
static SQInteger class_getbase(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_getbase(v,-1))?1:SQ_ERROR; }
static SQInteger squirrel_errorhandler(HSQUIRRELVM v) { /* Detect whether this error is just propagating through, or it originated * here. To do so, we store the last error we saw in the registry and compare * it to the current error. If they are the equal, we've already handled this * error. * * Without this check, we'll call the error handler for every transition * between the Squirrel and Wasm VMs. */ /* TODO(binji): It seems like there should be a better way to handle this */ SQInteger top = sq_gettop(v); WasmBool is_new_error = WASM_TRUE; /* get the last error we saw */ sq_pushregistrytable(v); sq_pushstring(v, WASM_LAST_ERROR_NAME, -1); if (SQ_SUCCEEDED(sq_get(v, -2))) { /* STACK: error registry_table last_error */ sq_push(v, -3); HSQOBJECT last_error; HSQOBJECT error; if (SQ_SUCCEEDED(sq_getstackobj(v, -1, &error)) && SQ_SUCCEEDED(sq_getstackobj(v, -2, &last_error))) { /* we don't want to use cmp here, because it will throw if the values are * unordered, and because it performs value equality */ if (squirrel_objects_are_equal_raw(last_error, error)) is_new_error = WASM_FALSE; } /* set the last_error in the registry to the new error. */ /* STACK: registry_table last_error error */ sq_remove(v, -2); sq_pushstring(v, WASM_LAST_ERROR_NAME, -1); sq_push(v, -2); /* STACK: registry_table error WASM_LAST_ERROR_NAME error */ SQRESULT r = sq_set(v, -4); WASM_USE(r); assert(r == SQ_OK); } sq_settop(v, top); if (is_new_error) { const char* error_msg = "unknown"; if (sq_gettop(v) >= 1) sq_getstring(v, -1, &error_msg); squirrel_error(v, "error: %s\n", error_msg); squirrel_error(v, "callstack:\n"); SQStackInfos stack_info; SQInteger depth; for (depth = 1; SQ_SUCCEEDED(sq_stackinfos(v, depth, &stack_info)); depth++) { const char* source = stack_info.source ? stack_info.source : "unknown"; const char* funcname = stack_info.funcname ? stack_info.funcname : "unknown"; SQInteger line = stack_info.line; squirrel_error(v, " #"_PRINT_INT_FMT ": %s:"_PRINT_INT_FMT ": %s()\n", depth, source, line, funcname); } } return 0; }
static SQInteger table_getdelegate(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_getdelegate(v,-1))?1:SQ_ERROR; }
/* static */ bool ScriptAdmin::MakeJSON(HSQUIRRELVM vm, SQInteger index, int max_depth, std::string &data) { if (max_depth == 0) { ScriptLog::Error("Send parameters can only be nested to 25 deep. No data sent."); // SQUIRREL_MAX_DEPTH = 25 return false; } switch (sq_gettype(vm, index)) { case OT_INTEGER: { SQInteger res; sq_getinteger(vm, index, &res); char buf[10]; snprintf(buf, sizeof(buf), "%d", (int32)res); data = buf; return true; } case OT_STRING: { const SQChar *res; sq_getstring(vm, index, &res); /* @bug if a string longer than 512 characters is given to SQ2OTTD, the * internal buffer overflows. */ const char *buf = SQ2OTTD(res); size_t len = strlen(buf) + 1; if (len >= 255) { ScriptLog::Error("Maximum string length is 254 chars. No data sent."); return false; } data = std::string("\"") + buf + "\""; return true; } case OT_ARRAY: { data = "[ "; bool first = true; sq_pushnull(vm); while (SQ_SUCCEEDED(sq_next(vm, index - 1))) { if (!first) data += ", "; if (first) first = false; std::string tmp; bool res = MakeJSON(vm, -1, max_depth - 1, tmp); sq_pop(vm, 2); if (!res) { sq_pop(vm, 1); return false; } data += tmp; } sq_pop(vm, 1); data += " ]"; return true; } case OT_TABLE: { data = "{ "; bool first = true; sq_pushnull(vm); while (SQ_SUCCEEDED(sq_next(vm, index - 1))) { if (!first) data += ", "; if (first) first = false; std::string key; std::string value; /* Store the key + value */ bool res = MakeJSON(vm, -2, max_depth - 1, key) && MakeJSON(vm, -1, max_depth - 1, value); sq_pop(vm, 2); if (!res) { sq_pop(vm, 1); return false; } data += key + ": " + value; } sq_pop(vm, 1); data += " }"; return true; } case OT_BOOL: { SQBool res; sq_getbool(vm, index, &res); if (res) { data = "true"; return true; } data = "false"; return true; } case OT_NULL: { data = "null"; return true; } default: ScriptLog::Error("You tried to send an unsupported type. No data sent."); return false; } }
int main(int argc, char *argv[]) { if(argc < 2){ scprintf(_SC("SQDBG error : no file specified")); return -1; } // RVF + int debuggerPort = 0; for (int i = 1; i < argc; i++) { const char* arg = argv[i]; if (!strncmp(arg, "-d", 2)) debuggerPort = std::atoi(arg + 2); } if (!debuggerPort) { scprintf(_SC("SQDBG error : Debugger port not specified. Use the -d<PORT> parameter")); return EXIT_FAILURE; } // RVF - HSQUIRRELVM v = sq_open(1024); sqstd_seterrorhandlers(v); //!! INITIALIZES THE DEBUGGER ON THE TCP PORT 1234 //!! ENABLES AUTOUPDATE HSQREMOTEDBG rdbg = sq_rdbg_init(v,debuggerPort,SQTrue); if(rdbg) { //!! ENABLES DEBUG INFO GENERATION(for the compiler) sq_enabledebuginfo(v,SQTrue); sq_setprintfunc(v,printfunc,errorfunc); //!! SUSPENDS THE APP UNTIL THE DEBUGGER CLIENT CONNECTS if(SQ_SUCCEEDED(sq_rdbg_waitforconnections(rdbg))) { scprintf(_SC("connected\n")); const SQChar *fname=NULL; #ifdef _UNICODE SQChar sTemp[256]; mbstowcs(sTemp,argv[argc-1],(int)strlen(argv[1])+1); fname=sTemp; #else fname=argv[argc-1]; #endif //!!REGISTERS STANDARDS LIBS sq_pushroottable(v); sqstd_register_bloblib(v); sqstd_register_iolib(v); sqstd_register_systemlib(v); sqstd_register_mathlib(v); sqstd_register_stringlib(v); //!!EXECUTE A SCTIPT if(SQ_FAILED(sqstd_dofile(v,fname,SQFalse,SQTrue))) { PrintError(v); _getch(); } } //!! CLEANUP sq_rdbg_shutdown(rdbg); } else { PrintError(v); } sq_close(v); return 0; }
void sqstd_printcallstack(HSQUIRRELVM v) { SQPRINTFUNCTION pf = sq_geterrorfunc(v); if(pf) { SQStackInfos si; SQInteger i; SQFloat f; const SQChar *s; SQInteger level=1; //1 is to skip this function that is level 0 const SQChar *name=0; SQInteger seq=0; pf(v,_SC("\nCALLSTACK\n")); while(SQ_SUCCEEDED(sq_stackinfos(v,level,&si))) { const SQChar *fn=_SC("unknown"); const SQChar *src=_SC("unknown"); if(si.funcname)fn=si.funcname; if(si.source)src=si.source; pf(v,_SC("*FUNCTION [%s()] %s line [%d]\n"),fn,src,si.line); level++; } level=0; pf(v,_SC("\nLOCALS\n")); for(level=0;level<10;level++){ seq=0; while((name = sq_getlocal(v,level,seq))) { seq++; switch(sq_gettype(v,-1)) { case OT_NULL: pf(v,_SC("[%s] NULL\n"),name); break; case OT_INTEGER: sq_getinteger(v,-1,&i); pf(v,_SC("[%s] %d\n"),name,i); break; case OT_FLOAT: sq_getfloat(v,-1,&f); pf(v,_SC("[%s] %.14g\n"),name,f); break; case OT_USERPOINTER: pf(v,_SC("[%s] USERPOINTER\n"),name); break; case OT_STRING: sq_getstring(v,-1,&s); pf(v,_SC("[%s] \"%s\"\n"),name,s); break; case OT_TABLE: pf(v,_SC("[%s] TABLE\n"),name); break; case OT_ARRAY: pf(v,_SC("[%s] ARRAY\n"),name); break; case OT_CLOSURE: pf(v,_SC("[%s] CLOSURE\n"),name); break; case OT_NATIVECLOSURE: pf(v,_SC("[%s] NATIVECLOSURE\n"),name); break; case OT_GENERATOR: pf(v,_SC("[%s] GENERATOR\n"),name); break; case OT_USERDATA: pf(v,_SC("[%s] USERDATA\n"),name); break; case OT_THREAD: pf(v,_SC("[%s] THREAD\n"),name); break; case OT_CLASS: pf(v,_SC("[%s] CLASS\n"),name); break; case OT_INSTANCE: pf(v,_SC("[%s] INSTANCE\n"),name); break; case OT_WEAKREF: pf(v,_SC("[%s] WEAKREF\n"),name); break; case OT_BOOL:{ sq_getinteger(v,-1,&i); pf(v,_SC("[%s] %s\n"),name,i?_SC("true"):_SC("false")); } break; default: assert(0); break; } sq_pop(v,1); } } } }
bool ScriptObject::getTypeTag(SQUserPointer* typeTag) const { return SQ_SUCCEEDED(sq_getobjtypetag((HSQOBJECT*)&mObj, typeTag)); }
/* * Load squirrel script from asset */ bool loadScriptFromAsset(const char* fname) { /* * read squirrel script from asset */ AAssetManager* mgr = engine->app->activity->assetManager; if (mgr == NULL) { engine->setLastError(ERR_SCRIPT_LOAD); LOGE("loadScriptFromAsset: failed to load AAssetManager"); return false; } AAsset* asset = AAssetManager_open(mgr, fname, AASSET_MODE_UNKNOWN); if (asset == NULL) { engine->setLastError(ERR_SCRIPT_OPEN); LOGW("loadScriptFromAsset: failed to open main script file"); LOGW(fname); return false; } unsigned short sqtag; bool isByteCode = false; if (AAsset_read(asset, &sqtag, 2) > 0) { if (sqtag == SQ_BYTECODE_STREAM_TAG) { isByteCode = true; } AAsset_seek(asset, 0, SEEK_SET); } else { AAsset_close(asset); return false; } if (isByteCode && SQ_SUCCEEDED(sq_readclosure(engine->sqvm, sq_lexer_bytecode, asset))) { sq_pushroottable(engine->sqvm); if (SQ_FAILED(sq_call(engine->sqvm, 1, SQFalse, SQTrue))) { engine->setLastError(ERR_SCRIPT_CALL_ROOT); LOGW("loadScriptFromAsset: failed to sq_call"); LOGW(fname); AAsset_close(asset); return false; } } else if(!isByteCode && SQ_SUCCEEDED(sq_compile(engine->sqvm, sq_lexer_asset, asset, fname, SQTrue))) { sq_pushroottable(engine->sqvm); if (SQ_FAILED(sq_call(engine->sqvm, 1, SQFalse, SQTrue))) { engine->setLastError(ERR_SCRIPT_CALL_ROOT); LOGW("loadScriptFromAsset: failed to sq_call"); LOGW(fname); AAsset_close(asset); return false; } } else { engine->setLastError(ERR_SCRIPT_COMPILE); LOGW("loadScriptFromAsset: failed to compile squirrel script"); LOGW(fname); AAsset_close(asset); return false; } AAsset_close(asset); return true; }
static SQInteger class_setattributes(HSQUIRRELVM v) { if(SQ_SUCCEEDED(sq_setattributes(v,-3))) return 1; return SQ_ERROR; }
TextureHandle TextureManager::loadTexture(const std::string& name) { // Check if texture has already been loaded. TextureHandle existing = getLoadedResource(name); if (existing.valid()) return existing; std::string texture_filename; Texture::FilterMode filter_mode = Texture::FilterMode::LINEAR; Texture::RepeatMode repeat_mode = Texture::RepeatMode::WRAP; int channels = 4; HSQUIRRELVM vm = ::hw::engine::script_engine->vm; sq_pushroottable(vm); loadVariablePath(vm, "Resources^TextureInfo^" + name); const SQChar* tex_filename_cstr; CSQ(getKey(vm, "filename")); sq_getstring(vm, -1, &tex_filename_cstr); sq_poptop(vm); texture_filename = tex_filename_cstr; if (SQ_SUCCEEDED(getKey(vm, "channels"))) { sq_getinteger(vm, -1, &channels); sq_poptop(vm); } if (SQ_SUCCEEDED(getKey(vm, "filter_mode"))) { SQInteger tmp; sq_getinteger(vm, -1, &tmp); sq_poptop(vm); filter_mode = Texture::FilterMode(tmp); } if (SQ_SUCCEEDED(getKey(vm, "repeat_mode"))) { SQInteger tmp; sq_getinteger(vm, -1, &tmp); sq_poptop(vm); repeat_mode = Texture::RepeatMode(tmp); } texture_filename = "data/" + texture_filename; if (texture_filename.empty()) { return TextureHandle(); } gl::Texture new_tex; glGenTextures(1, &new_tex.name); glBindTexture(GL_TEXTURE_2D, new_tex.name); setTextureParameters(filter_mode, repeat_mode); assert(channels >= 1 && channels <= 4); static const GLint internal_formats[4] = {GL_RED, GL_RG, GL_RGB, GL_RGBA}; GLint gl_format = internal_formats[channels-1]; int width, height, comp; unsigned char* data = stbi_load(texture_filename.c_str(), &width, &height, &comp, channels); if (data == nullptr) { return TextureHandle(); } glTexImage2D(GL_TEXTURE_2D, 0, gl_format, width, height, 0, gl_format, GL_UNSIGNED_BYTE, data); return constructResource(name, Texture(std::move(new_tex), name, width, height)); }
static SQInteger instance_getclass(HSQUIRRELVM v) { if(SQ_SUCCEEDED(sq_getclass(v,1))) return 1; return SQ_ERROR; }
void CScripts::Call(RakNet::BitStream * bitStream) { for(int i = 0; i < MAX_SCRIPTS; i++) { if(m_pScripts[i]) { int iArgCount = 0; int funcLen = 0; CHAR szFunc[256]; bitStream->Read(funcLen); bitStream->Read(iArgCount); bitStream->Read(szFunc, funcLen); szFunc[funcLen] = '\0'; // get the script vm pointer SQVM * pVM = m_pScripts[i]->GetVM(); // Get the stack top int iTop = sq_gettop(pVM); // Push the root table onto the stack sq_pushroottable(pVM); // Push the function name onto the stack sq_pushstring(pVM, szFunc, -1); if(SQ_SUCCEEDED(sq_get(pVM, -2))) { // Push the root table onto the stack sq_pushroottable(pVM); if(iArgCount > 0) { for(int j = 0; i < iArgCount; i++) { int type; bitStream->Read(type); if(type == OT_INTEGER) { int val; bitStream->Read(val); sq_pushinteger(pVM, val); } else if(type == OT_FLOAT) { float val; bitStream->Read(val); sq_pushfloat(pVM, val); } else if(type == OT_BOOL) { bool val; bitStream->Read(val); sq_pushbool(pVM, val); } else if(type == OT_STRING) { int len; bitStream->Read(len); CHAR szStr[256]; bitStream->Read(szStr, len); szStr[len] = '\0'; std::string str = szStr; sq_pushstring(pVM, str.c_str(), -1); } } } sq_call(pVM, iArgCount + 1, true, true); } // Restore the stack top sq_settop(pVM, iTop); bitStream->ResetReadPointer(); } } }
static SQInteger table_rawget(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_rawget(v,-2))?1:SQ_ERROR; }
static SQInteger class_getattributes(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_getattributes(v,-2))?1:SQ_ERROR; }
static SQInteger closure_call(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQTrue))?1:SQ_ERROR; }
void sqstd_printcallstack(HSQUIRRELVM v) { SQPRINTFUNCTION pf = sq_getprintfunc(v); if(pf) { SQStackInfos si; SQInteger i; SQBool b; SQFloat f; const SQChar *s; SQInteger level=1; //1 is to skip this function that is level 0 const SQChar *name=0; SQInteger seq=0; pf(v,_SC("\nCALLSTACK\n")); while(SQ_SUCCEEDED(sq_stackinfos(v,level,&si))) { const SQChar *fn=_SC("unknown"); const SQChar *src=_SC("unknown"); if(si.funcname)fn=si.funcname; if(si.source) { /* 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/. */ src = scstrstr(si.source, _SC("\\ai\\")); if (!src) src = scstrstr(si.source, _SC("/ai/")); if (src) { src += 4; } else { src = si.source; } } pf(v,_SC("*FUNCTION [%s()] %s line [%d]\n"),fn,src,si.line); level++; } level=0; pf(v,_SC("\nLOCALS\n")); for(level=0;level<10;level++){ seq=0; while((name = sq_getlocal(v,level,seq))) { seq++; switch(sq_gettype(v,-1)) { case OT_NULL: pf(v,_SC("[%s] NULL\n"),name); break; case OT_INTEGER: sq_getinteger(v,-1,&i); pf(v,_SC("[%s] %d\n"),name,i); break; case OT_FLOAT: sq_getfloat(v,-1,&f); pf(v,_SC("[%s] %.14g\n"),name,f); break; case OT_USERPOINTER: pf(v,_SC("[%s] USERPOINTER\n"),name); break; case OT_STRING: sq_getstring(v,-1,&s); pf(v,_SC("[%s] \"%s\"\n"),name,s); break; case OT_TABLE: pf(v,_SC("[%s] TABLE\n"),name); break; case OT_ARRAY: pf(v,_SC("[%s] ARRAY\n"),name); break; case OT_CLOSURE: pf(v,_SC("[%s] CLOSURE\n"),name); break; case OT_NATIVECLOSURE: pf(v,_SC("[%s] NATIVECLOSURE\n"),name); break; case OT_GENERATOR: pf(v,_SC("[%s] GENERATOR\n"),name); break; case OT_USERDATA: pf(v,_SC("[%s] USERDATA\n"),name); break; case OT_THREAD: pf(v,_SC("[%s] THREAD\n"),name); break; case OT_CLASS: pf(v,_SC("[%s] CLASS\n"),name); break; case OT_INSTANCE: pf(v,_SC("[%s] INSTANCE\n"),name); break; case OT_WEAKREF: pf(v,_SC("[%s] WEAKREF\n"),name); break; case OT_BOOL:{ sq_getbool(v,-1,&b); pf(v,_SC("[%s] %s\n"),name,b?_SC("true"):_SC("false")); } break; default: assert(0); break; } sq_pop(v,1); } } } }