//----------------------------------------------------------------// int MOAILuaObject::_tostring ( lua_State* L ) { MOAILuaState state ( L ); MOAILuaObject* data = ( MOAILuaObject* )state.GetPtrUserData ( 1 ); if ( data ) { STLString str; lua_getfield ( state, 1, "getClassName" ); if ( state.IsType ( -1, LUA_TFUNCTION )) { lua_pushvalue ( state, 1 ); state.DebugCall ( 1, 1 ); cc8* classname = state.GetValue < cc8* >( -1, "" ); str.write ( "%p <%s>", data, classname ); state.Push ( str ); return 1; } str.write ( "%p <%s>", data, data->TypeName ()); state.Push ( str ); return 1; } return 0; }
//----------------------------------------------------------------// STLString USMemStream::ToString ( u32 size ) { if ( size == 0 ) return 0; if (( this->mCursor + size ) > this->mLength ) { size = this->mLength - this->mCursor; } STLString str; char buffer [ DEFAULT_CHUNK_SIZE + 1 ]; u32 readSize = DEFAULT_CHUNK_SIZE; while ( size > 0 ) { if ( size < readSize ) { readSize = size; } this->ReadBytes ( buffer, readSize ); buffer [ readSize ] = 0; str.write ( "%s", buffer ); size -= readSize; } return str; }
//----------------------------------------------------------------// u32 MOAIHttpTaskInfo::_writeHeader ( char* data, u32 n, u32 l, void* s ) { MOAIHttpTaskInfo* self = ( MOAIHttpTaskInfo* )s; u32 size = n * l; STLString key = "content-length"; u32 keyLength = ( u32 )strlen ( key ); if ( strncmp ( data, key, keyLength ) == 0 ) { STLString header = data; u32 end = ( u32 )header.find_last_of ( '\n' ); STLString value = header.clip ( keyLength + 2, end - 1 ); u32 length = atoi ( value ); if ( length ) { self->mData.Init ( length ); self->mByteStream.SetBuffer ( self->mData, length ); self->mByteStream.SetLength ( length ); self->mStream = &self->mByteStream; } } return size; }
//----------------------------------------------------------------// u32 USLuaSerializer::WriteTableInitializer ( USStream& stream, USLuaState& state, int idx, cc8* prefix ) { u32 count = 0; u32 itr = state.PushTableItr ( idx ); while ( state.TableItrNext ( itr )) { switch ( lua_type ( state, -2 )) { case LUA_TSTRING: { stream.Print ( "\t%s [ \"%s\" ] = ", prefix, lua_tostring ( state, -2 )); break; } case LUA_TNUMBER: { stream.Print ( "\t%s [ %s ]\t= ", prefix, lua_tostring ( state, -2 )); break; } }; switch ( lua_type ( state, -1 )) { case LUA_TBOOLEAN: { int value = lua_toboolean ( state, -1 ); cc8* str = ( value ) ? "true": "false"; stream.Print ( "%s\n", str ); break; } case LUA_TTABLE: { uintptr tableID = ( uintptr )lua_topointer ( state, -1 ); if ( this->mTableMap.contains ( tableID )) { stream.Print ( "objects [ 0x%08X ]\n", tableID ); } break; } case LUA_TSTRING: { STLString str = _escapeString ( lua_tostring ( state, -1 )); stream.Print ( "\"%s\"\n", str.c_str ()); break; } case LUA_TNUMBER: { stream.Print ( "%s\n", lua_tostring ( state, -1 )); break; } case LUA_TUSERDATA: { USLuaObject* object = state.GetLuaObject < USLuaObject >( -1 ); u32 instanceID = this->GetID ( object ); stream.Print ( "objects [ 0x%08X ]\n", instanceID ); break; } case LUA_TLIGHTUSERDATA: { stream.Print ( "%p,\n", lua_touserdata ( state, -1 )); break; } }; ++count; } return count; }
//----------------------------------------------------------------// u32 MOAIHttpTaskCurl::_writeHeader ( char* data, u32 n, u32 l, void* s ) { MOAIHttpTaskCurl* self = ( MOAIHttpTaskCurl* )s; u32 size = n * l; char *endp = data + size; char *colon = data; while ( colon < endp && *colon != ':' ) { colon++; } if ( colon < endp ) { STLString name ( data, colon - data ); // Case insensitive char *vstart = colon; vstart++; while( vstart < endp && isspace ( *vstart )) { vstart++; } char *vend = endp - 1; while( vend > vstart && isspace ( *vend ) ) { vend--; } STLString value(vstart, ( vend - vstart ) + 1); // Emulate XMLHTTPRequest.getResponseHeader() behavior of appending with comma // separator if there are multiple header responses? if( self->mResponseHeaders.find ( name ) != self->mResponseHeaders.end ()) { self->mResponseHeaders [ name ] = self->mResponseHeaders [ name ] + "," + value; } else { self->mResponseHeaders [ name ] = value; } } // Shouldn't this be a case-insensitive check? STLString key = "content-length"; u32 keyLength = ( u32 )strlen ( key ); if ( strncmp ( data, key, keyLength ) == 0 ) { STLString header = data; u32 end = ( u32 )header.find_last_of ( '\n' ); STLString value = header.clip ( keyLength + 2, end - 1 ); u32 length = atoi ( value ); if ( length ) { self->mData.Init ( length ); self->mByteStream.SetBuffer ( self->mData, length ); self->mByteStream.SetLength ( length ); self->mStream = &self->mByteStream; } } return size; }
//----------------------------------------------------------------// void MOAILuaState::PrintStackTrace ( FILE* file, int level ) { STLString stackTrace = this->GetStackTrace ( level ); // TODO: Fix this on Android #ifndef MOAI_OS_ANDROID ZLLog::PrintFile ( file, stackTrace.str ()); #endif }
//----------------------------------------------------------------// int USLuaSerializer::_exportToString ( lua_State* L ) { LUA_SETUP ( USLuaSerializer, "U" ) STLString retStr = self->SerializeToString (); lua_pushstring ( L, retStr.str() ); return 1; }
//----------------------------------------------------------------// bool USFileSys::Copy ( cc8* path, cc8* newPath ) { zl_stat fileStat; if ( !USFileSys::GetFileStat ( path, fileStat )) return false; if ( !fileStat.mExists ) return false; if ( fileStat.mIsDir ) { bool result = true; STLString cwd = USFileSys::GetCurrentPath (); STLString toPath = USFileSys::GetAbsoluteDirPath ( newPath ); USFileSys::AffirmPath ( toPath ); USFileSys::SetCurrentPath ( path ); ZLDIR* itr = zl_dir_open (); if ( itr ) { while ( zl_dir_read_entry ( itr )) { cc8* entry = zl_dir_entry_name ( itr ); if ( strcmp ( entry, "." ) == 0 ) continue; if ( strcmp ( entry, ".." ) == 0 ) continue; STLString destEntry = toPath; destEntry.append ( entry ); if ( !USFileSys::Copy ( entry, destEntry )) { result = false; break; } } zl_dir_close ( itr ); } USFileSys::SetCurrentPath ( cwd ); return result; } else { USFileStream infile; if ( infile.OpenRead ( path )) { USFileStream outfile; if ( outfile.OpenWrite ( newPath )) { outfile.WriteStream ( infile ); return true; } } } return false; }
//----------------------------------------------------------------// void ZLAdapterInfo::SetNameFromMACAddress ( u8* address, u32 length ) { STLString result; for ( u32 i = 0; i < length; i++ ) { if ( i ) { result.write ( "-" ); } result.write ( "%.2X", ( u32 )address [ i ]); } this->mName = result; }
//----------------------------------------------------------------// bool USLuaState::PrintErrors ( int status ) { if ( status != 0 ) { cc8* error = lua_tostring ( this->mState, -1 ); if ( error ) { STLString msg = lua_tostring ( this->mState, -1 ); USLog::Print ( "-- %s\n", msg.c_str ()); } lua_pop ( this->mState, 1 ); // pop error message return true; } return false; }
//----------------------------------------------------------------// int MOAILuaObject::_tostring ( lua_State* L ) { MOAILuaState state ( L ); MOAILuaObject* data = ( MOAILuaObject* )state.GetPtrUserData ( 1 ); if ( data ) { STLString str; str.write ( "0x%p <%s>", data, data->TypeName ()); // TODO: 64-bit state.Push ( str ); return 1; } return 0; }
//----------------------------------------------------------------// void MOAIHttpTaskNaCl::Prepare ( GetURLHandler *handler ) { // until we get a header indicating otherwise, assume we won't // know the final length of the stream, so default to use the // USMemStream which will grow dynamically this->mStream = &this->mMemStream; char buffer [ MAX_HEADER_LENGTH ]; int written = 0; // prepare the custom headers (if any) HeaderMapIt headerMapIt = this->mHeaderMap.begin (); for ( ; headerMapIt != this->mHeaderMap.end (); ++headerMapIt ) { STLString key = headerMapIt->first; STLString value = headerMapIt->second; assert (( written + ( key.size () + value.size () + 3 )) < MAX_HEADER_LENGTH ); if ( value.size ()) { written += sprintf ( buffer + written, "%s: %s\n", key.c_str (), value.c_str ()); } else { written += sprintf ( buffer + written, "%s:\n", key.c_str ()); } } //append headers handler->SetHeaders ( buffer ); }
//----------------------------------------------------------------// bool MOAILuaState::PrintErrors ( FILE* file, int status ) { if ( status != 0 ) { cc8* error = lua_tostring ( this->mState, -1 ); if ( error ) { STLString msg = lua_tostring ( this->mState, -1 ); // TODO: Fix this on Android #ifndef MOAI_OS_ANDROID ZLLog::PrintFile ( file, "-- %s\n", msg.c_str ()); #endif } lua_pop ( this->mState, 1 ); // pop error message return true; } return false; }
//----------------------------------------------------------------// static STLString _escapeString ( cc8* str ) { u32 len = ( u32 )strlen ( str ); STLString outStr; outStr.reserve ( len * 2 ); for ( u32 i = 0; i < len; ++i ) { char c = str [ i ]; if ( c == '\\' ) { outStr.append ( "\\\\" ); } else { outStr.push_back ( c ); } } return outStr; }
//----------------------------------------------------------------// STLString ZLCgt::ReadUnicodeAsASCII ( ZLStream& stream ) { // TODO: change this to convert to UTF8! // Also: GOLD now has native UTF8 support. Look into it. STLString result = ""; static const u32 BUFFER_SIZE = 1024; char buffer [ BUFFER_SIZE ]; u16 utf = 1; while ( utf ) { for ( u32 i = 0; ( i < BUFFER_SIZE ) && utf; ++i ) { utf = stream.Read < u16 >( 0 ); buffer [ i ] = ( char )( utf & 0x00ff ); } result.append ( buffer ); } return result; }
//----------------------------------------------------------------// void MOAIHttpTaskCurl::Prepare () { // until we get a header indicating otherwise, assume we won't // know the final length of the stream, so default to use the // USMemStream which will grow dynamically if ( this->mUserStream ) { this->mStream = this->mUserStream->GetUSStream(); } else { this->mStream = &this->mMemStream; } char buffer [ MAX_HEADER_LENGTH ]; // prepare the custom headers (if any) HeaderMapIt headerMapIt = this->mHeaderMap.begin (); for ( ; headerMapIt != this->mHeaderMap.end (); ++headerMapIt ) { STLString key = headerMapIt->first; STLString value = headerMapIt->second; assert (( key.size () + value.size () + 3 ) < MAX_HEADER_LENGTH ); if ( value.size ()) { sprintf ( buffer, "%s: %s", key.c_str (), value.c_str ()); } else { sprintf ( buffer, "%s:", key.c_str ()); } this->mHeaderList = curl_slist_append ( this->mHeaderList, buffer ); } if ( this->mHeaderList ) { CURLcode result = curl_easy_setopt ( this->mEasyHandle, CURLOPT_HTTPHEADER, this->mHeaderList ); PrintError ( result ); } CURLcode result = curl_easy_setopt ( this->mEasyHandle, CURLOPT_CONNECTTIMEOUT, this->mDefaultTimeout ); // follow redirects based on settings in base class (default is to NOT follow redirects) result = curl_easy_setopt ( this->mEasyHandle, CURLOPT_FOLLOWLOCATION, this->mFollowRedirects ); // set the timeout for this task result = curl_easy_setopt ( this->mEasyHandle, CURLOPT_TIMEOUT, this->mTimeout ); PrintError ( result ); }
//----------------------------------------------------------------// void Load ( u32 transform = 0 ) { if ( this->mType != TYPE_UNKNOWN ) { return; } this->mTransform |= transform; if ( !this->mImage.IsOK ()) { if ( this->mFileData ) { this->mImage.Load ( this->mFileData, ( u32 )this->mFileDataSize, this->mTransform ); free ( this->mFileData ); this->mFileData = 0; } else if ( mFilename.size ()) { this->mImage.Load ( this->mFilename, this->mTransform ); } } if ( this->mImage.IsOK ()) { this->mType = TYPE_MOAI_IMAGE; } #ifdef MOAI_TEST_PVR else { // get file data, check if PVR USFileStream stream; stream.OpenRead ( this->mFilename ); if ( this->mFileData ) { free ( this->mFileData ); this->mFileData = 0; } this->mFileDataSize = stream.GetLength (); this->mFileData = malloc ( this->mFileDataSize ); stream.ReadBytes ( this->mFileData, this->mFileDataSize ); stream.Close (); if ( MOAIPvrHeader::GetHeader( this->mFileData, this->mFileDataSize )) { this->mType = TYPE_PVR; } } #endif if ( this->mType == TYPE_UNKNOWN ) { this->mType = TYPE_FAIL; this->Release (); } }
//----------------------------------------------------------------// void Load ( u32 transform = 0 ) { if ( this->mType != TYPE_UNKNOWN ) { return; } this->mTransform |= transform; if ( !this->mImage.IsOK ()) { if ( this->mFileData ) { this->mImage.Load ( this->mFileData, ( u32 )this->mFileDataSize, this->mTransform ); free ( this->mFileData ); this->mFileData = 0; } else if ( mFilename.size ()) { this->mImage.Load ( this->mFilename, this->mTransform ); } } if ( this->mImage.IsOK ()) { this->mType = TYPE_MOAI_IMAGE; } #ifdef MOAI_TEST_PVR else if ( USPvrHeader::GetHeader ( this->mFileData, this->mFileDataSize )) { this->mType = TYPE_PVR; } #endif if ( this->mType == TYPE_UNKNOWN ) { this->mType = TYPE_FAIL; if ( this->mFileData ) { free ( this->mFileData ); this->mFileData = 0; } } }
//----------------------------------------------------------------// size_t STLString::tokenize ( const STLString& str, STLArray < STLString >& tokens, const STLString& delimiters ) { return str.tokenize ( tokens, delimiters ); }
//----------------------------------------------------------------// void MOAIGfxDevice::DetectContext () { this->mHasContext = true; #ifdef __GLEW_H__ static bool initGlew = true; if ( initGlew ) { glewInit (); initGlew = false; } #endif const GLubyte* driverVersion = glGetString ( GL_VERSION ); STLString version = ( cc8* )driverVersion; version.to_lower (); STLString gles = "opengl es"; if ( version.find ( gles ) != version.npos ) { this->mIsOpenGLES = true; version = version.substr ( gles.length ()); size_t space = version.find ( ' ' ); if ( space != version.npos ) { version = version.substr ( space + 1 ); } } else { this->mIsOpenGLES = false; } version = version.substr ( 0, 3 ); this->mMajorVersion = version.at ( 0 ) - '0'; this->mMinorVersion = version.at ( 2 ) - '0'; this->mIsProgrammable = ( this->mMajorVersion >= 2 ); this->mIsFramebufferSupported = true; #if defined ( __GLEW_H__ ) // if framebuffer object is not in code, check to see if it's available as // an extension and remap to core function pointers if so if (( this->mIsOpenGLES == false ) && ( this->mMajorVersion < 3 )) { if ( glewIsSupported ( "GL_EXT_framebuffer_object" )) { REMAP_EXTENSION_PTR ( glBindFramebuffer, glBindFramebufferEXT ) REMAP_EXTENSION_PTR ( glCheckFramebufferStatus, glCheckFramebufferStatusEXT ) REMAP_EXTENSION_PTR ( glDeleteFramebuffers, glDeleteFramebuffersEXT ) REMAP_EXTENSION_PTR ( glDeleteRenderbuffers, glDeleteRenderbuffersEXT ) REMAP_EXTENSION_PTR ( glFramebufferRenderbuffer, glFramebufferRenderbufferEXT ) REMAP_EXTENSION_PTR ( glFramebufferTexture1D, glFramebufferTexture1DEXT ) REMAP_EXTENSION_PTR ( glFramebufferTexture2D, glFramebufferTexture2DEXT ) REMAP_EXTENSION_PTR ( glFramebufferTexture3D, glFramebufferTexture3DEXT ) REMAP_EXTENSION_PTR ( glGenFramebuffers, glGenFramebuffersEXT ) REMAP_EXTENSION_PTR ( glGenRenderbuffers, glGenRenderbuffersEXT ) REMAP_EXTENSION_PTR ( glGenerateMipmap, glGenerateMipmapEXT ) REMAP_EXTENSION_PTR ( glGetFramebufferAttachmentParameteriv, glGetFramebufferAttachmentParameterivEXT ) REMAP_EXTENSION_PTR ( glGetRenderbufferParameteriv, glGetRenderbufferParameterivEXT ) REMAP_EXTENSION_PTR ( glIsFramebuffer, glIsFramebufferEXT ) REMAP_EXTENSION_PTR ( glIsRenderbuffer, glIsRenderbufferEXT ) REMAP_EXTENSION_PTR ( glRenderbufferStorage, glRenderbufferStorageEXT ) } else { // looks like frame buffer isn't supported this->mIsFramebufferSupported = false; } } #endif int maxTextureUnits; glGetIntegerv ( GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits ); this->mTextureUnits.Init ( maxTextureUnits ); this->mTextureUnits.Fill ( 0 ); int maxTextureSize; glGetIntegerv ( GL_MAX_TEXTURE_SIZE, &maxTextureSize ); this->mMaxTextureSize = maxTextureSize; this->mDeleterStack.Reset (); this->ResetResources (); }
//----------------------------------------------------------------// u32 USLuaSerializer::WriteTable ( USStream& stream, USLuaState& state, int idx, u32 tab ) { STLString indent; for ( u32 i = 0; i < tab; ++i ) { indent.append ( "\t" ); } u32 count = 0; u32 itr = state.PushTableItr ( idx ); while ( state.TableItrNext ( itr )) { if ( count == 0 ) { stream.Print ( "\n" ); } switch ( lua_type ( state, -2 )) { case LUA_TSTRING: { stream.Print ( "%s[ \"%s\" ] = ", indent.c_str (), lua_tostring ( state, -2 )); break; } case LUA_TNUMBER: { stream.Print ( "%s[ %s ]\t= ", indent.c_str (), lua_tostring ( state, -2 )); break; } }; switch ( lua_type ( state, -1 )) { case LUA_TBOOLEAN: { int value = lua_toboolean ( state, -1 ); cc8* str = ( value ) ? "true": "false"; stream.Print ( "%s,\n", str ); break; } case LUA_TTABLE: { uintptr tableID = ( uintptr )lua_topointer ( state, -1 ); if ( this->mTableMap.contains ( tableID )) { stream.Print ( "objects [ 0x%08X ],\n", tableID ); } else { stream.Print ( "{" ); if ( this->WriteTable ( stream, state, -1, tab + 1 )) { stream.Print ( "%s},\n", indent.c_str ()); } else { stream.Print ( "},\n" ); } } break; } case LUA_TSTRING: { STLString str = _escapeString ( lua_tostring ( state, -1 )); stream.Print ( "\"%s\",\n", str.c_str ()); break; } case LUA_TNUMBER: { stream.Print ( "%s,\n", lua_tostring ( state, -1 )); break; } case LUA_TLIGHTUSERDATA: { stream.Print ( "%p,\n", lua_touserdata ( state, -1 )); break; } }; ++count; } return count; }
//----------------------------------------------------------------// STLString MOAILuaState::GetStackTrace ( int level ) { int firstpart = 1; /* still before eventual `...' */ lua_Debug ar; lua_State* L = this->mState; STLString out; out.append ( "stack traceback:" ); while ( lua_getstack ( L, level++, &ar )) { if ( level > LEVELS1 && firstpart ) { if ( !lua_getstack ( L, level + LEVELS2, &ar )) { level--; } else { // too many levels out.append ( "\n\t..." ); /* too many levels */ // find last levels */ while ( lua_getstack ( L, level + LEVELS2, &ar )) level++; } firstpart = 0; continue; } out.append ( "\n\t" ); lua_getinfo ( L, "Snl", &ar ); out.append ( ar.short_src ); if ( ar.currentline > 0 ) { out.write ( ":%d", ar.currentline ); } if ( *ar.namewhat != '\0' ) { out.write ( " in function '%s'", ar.name ); } else { if ( *ar.what == 'm' ) { out.write ( " in main chunk" ); } else if ( *ar.what == 'C' || *ar.what == 't' ) { out.write ( " ?" ); } else { out.write ( " in function <%s:%d>", ar.short_src, ar.linedefined ); } } } out.append ( "\n" ); return out; }
//----------------------------------------------------------------// STLString STLString::build_var ( cc8* format, va_list args ) { STLString result; result.write_var ( format, args ); return result; }
//----------------------------------------------------------------// void MOAILuaState::PrintStackTrace ( FILE* file, int level ) { STLString stackTrace = this->GetStackTrace ( level ); USLog::PrintFile ( file, stackTrace.str ()); }
//----------------------------------------------------------------// STLString USStream::ReadToken ( cc8* delimiters ) { STLString str; if ( this->IsAtEnd ()) return str; char stackBuffer [ LOCAL_BUFFER ]; USMemStream memStream; memStream.SetChunkSize ( LOCAL_BUFFER ); memStream.SetGuestBuffer ( stackBuffer, LOCAL_BUFFER ); char c = 0; size_t size = 0; do { c = this->Read < char >( 0 ); if ( delimiters && c ) { bool isDelimiter = false; for ( size_t i = 0; delimiters [ i ]; ++i ) { if ( delimiters [ i ] == c ) { isDelimiter = true; break; } } if ( isDelimiter ) { if ( size ) { c = 0; } else { continue; } } } memStream.Write < char >( c ); size++; } while ( c ); if ( size ) { str.reserve ( size + 1 ); memStream.Seek ( 0, SEEK_SET ); while ( size > 0 ) { char buffer [ LOCAL_BUFFER ]; size_t readSize = size; if ( LOCAL_BUFFER < readSize ) { readSize = LOCAL_BUFFER; } memStream.ReadBytes ( buffer, readSize ); str.append ( buffer, readSize ); size -= readSize; } } return str; }
//----------------------------------------------------------------// // This beast will walk through all tables and functions accessible in the // current lua state and print a reference line for each one found to help // track who is pointing to it. void MOAILuaRuntime::FindAndPrintLuaRefs ( int idx, cc8* prefix, FILE *f, const LeakPtrList& objects ) { lua_State* L = this->mMainState; // Convert to absolute index if ( idx < 0 ) { idx = lua_gettop(L) + idx + 1; } // Check if the item at the top of the stack has been traversed yet. lua_pushvalue ( L, -1 ); lua_gettable ( L, idx ); if( lua_type ( L, -1 ) != LUA_TNIL ) { // It has, let's bail. lua_pop ( L, 1 ); // Clean our 'true' return; } lua_pop(L, 1); // Remove the nil int tt = lua_type ( L, -1 ); if( tt == LUA_TTABLE ) { // printf("finding refs in: %s\n", prefix); // It hasn't been visited, so mark it in our traversal set lua_pushvalue ( L, -1 ); // Push table as key lua_pushboolean ( L, true ); lua_settable ( L, idx ); lua_pushnil ( L ); // first key while ( lua_next ( L, -2 ) != 0 ) { // use the 'key' (at index -2) and 'value' (at index -1) STLString key; if ( lua_type ( L, -2) == LUA_TSTRING ) { if ( MOAILuaRuntime::IsLuaIdentifier ( lua_tostring ( L, -2 ))) { key.write ( "%s.%s", prefix, lua_tostring ( L, -2 )); } else { // TODO: escape '\"' key.write ( "%s[\"%s\"]", prefix, lua_tostring ( L, -2 )); } } else { // stringify key lua_getglobal ( L, "tostring" ); lua_pushvalue ( L, -3 ); lua_call ( L, 1, 1 ); key.write ( "%s[%s]", prefix, lua_tostring ( L, -1 )); // Pop stringified key lua_pop ( L, 1 ); } this->FindAndPrintLuaRefs ( idx, key.c_str (), f, objects ); // removes 'value'; keeps 'key' for next iteration lua_pop ( L, 1 ); } // Check its metatable (if it has one) if ( lua_getmetatable ( L, -1 )) { STLString key; key.write ( "%s~mt", prefix ); this->FindAndPrintLuaRefs ( idx, key.c_str(), f, objects ); lua_pop ( L, 1 ); // Pop metatable } } else if ( tt == LUA_TFUNCTION ) { // printf("finding refs in: %s\n", prefix); // It hasn't been visited, so mark it in our tarversal set lua_pushvalue ( L, -1 ); // Push table as key lua_pushboolean ( L, true ); lua_settable ( L, idx ); const char *upname; for ( int i = 1; ( upname = lua_getupvalue ( L, -1, i )) != NULL; ++i ) { STLString key; key.write ( "%s(%s)", prefix, upname ); this->FindAndPrintLuaRefs ( idx, key.c_str(), f, objects ); // Pop the upvalue lua_pop ( L, 1 ); } } else if ( tt == LUA_TUSERDATA ) { // It hasn't been visited, so mark it in our traversal set lua_pushvalue ( L, -1 ); // Push table as key lua_pushboolean ( L, true ); lua_settable ( L, idx ); MOAILuaState state ( L ); void *ud = state.GetPtrUserData ( -1 ); for ( LeakPtrList::const_iterator i = objects.begin (); i != objects.end (); ++i ) { if( *i == ud ) { fprintf ( f, "\tLua Ref: %s = %s <%p>\n", prefix, ( *i )->TypeName (), ud ); // if ( strcmp((*i)->TypeName(), "MOAICoroutine") == 0 ) { // MOAICoroutine *t = (MOAICoroutine*)ud; // } } } // Check its metatable (if it has one) if ( lua_getmetatable ( L, -1 )) { STLString key; key.write ( "%s~mt", prefix ); this->FindAndPrintLuaRefs ( idx, key.c_str (), f, objects ); lua_pop ( L, 1 ); // Pop metatable } } }