| --RB LUA show all global variables; BILGUS |
| require "actions" |
| require "audio" |
| require "buttons" |
| require "color" |
| require "draw" |
| require "image" |
| require "lcd" |
| require "math_ex" |
| require "pcm" |
| require "playlist" |
| require "print" |
| --require "settings" --uses a lot of memory |
| require "sound" |
| collectgarbage("collect") |
| |
| local sDumpFile = "/rb-lua_functions.txt" |
| local filehandle |
| |
| local function a2m_m2a(addr_member) |
| --turns members into addresses; addresses back into members |
| return addr_member |
| end |
| |
| local function dtTag(sType) |
| --convert named type; 'number'.. to short type '[n]...' |
| --if '?' supplied print out datatype key; number = [n]... |
| local retType = "?" |
| local typ = { |
| ["nil"] = "nil", |
| ["boolean"] = "b", |
| ["number"] = "n", |
| ["string"] = "s", |
| ["userdata"] = "u", |
| ["function"] = "f", |
| ["thread"] = "thr", |
| ["table"] = "t" |
| } |
| if sType == "?" then retType = "Datatypes: " end |
| for k,v in pairs(typ) do |
| if sType == k then |
| retType = v break |
| elseif (sType == "?") then |
| retType = retType .. " [" ..v.. "] = " .. k |
| end |
| end |
| return " [" ..retType.. "] " |
| end |
| |
| local function tableByName(tName) |
| --find the longest match possible to an actual table |
| --Name comes in as (table) tName.var so we can pass back out the name found PITA |
| --returns the table found (key and value) |
| local ld = {} |
| local sMatch = "" |
| local kMatch = nil |
| local vMatch = nil |
| |
| ----FUNCTIONS for tableByName ----------------------------------------------------- |
| local function search4Str(n, k, v) |
| local sKey = tostring(k) |
| if string.find (n, sKey,1,true) then |
| if sKey:len() > sMatch:len() then sMatch = sKey kMatch = k vMatch = v end |
| --find the longest match we can |
| end |
| end |
| ----END FUNCTIONS for tableByName ------------------------------------------------- |
| |
| if tName.val ~= nil and tName.val ~= "" then |
| for k, v in pairs(_G) do |
| --_G check both since some tables are only in _G or package.loaded |
| search4Str(tName.val, k, v) |
| end |
| for k, v in pairs(package.loaded) do --package.loaded |
| search4Str(tName.val, k, v) |
| end |
| if not string.find (sMatch, "_G",1,true) then sMatch = "_G." .. sMatch end |
| -- put the root _G in if not exist |
| if kMatch and vMatch then ld[kMatch] = vMatch tName.val = sMatch return ld end |
| end |
| tName.val = "_G" |
| return package.loaded --Not Found return default |
| end |
| |
| local function dump_Tables(tBase, sFunc, tSeen, tRet) |
| --Based on: http://www.lua.org/cgi-bin/demo?globals |
| --Recurse through tBase tables copying all found Tables |
| local sSep="" |
| local ld={} |
| local tNameBuf = {} |
| local sName |
| if sFunc ~= "" then sSep = "." end |
| |
| for k, v in pairs(tBase) do |
| k = tostring(k) |
| tNameBuf[1] = sFunc |
| tNameBuf[2] = sSep |
| tNameBuf[3] = k |
| |
| |
| if k ~= "loaded" and type(v) == "table" and not tSeen[v] then |
| tSeen[v]=sFunc |
| sName = table.concat(tNameBuf) |
| tRet[sName] = a2m_m2a(v) --place all keys into ld[i]=value |
| dump_Tables(v, sName, tSeen, tRet) |
| elseif type(v) == "table" and not tSeen[v] then |
| tSeen[v]=sFunc |
| tRet[table.concat(tNameBuf)] = a2m_m2a(v) -- dump 'loaded' table |
| for k1, v1 in pairs(v) do |
| if not _G[k1] and type(v1) == "table" and not tSeen[v1] then |
| -- dump tables that are loaded but not global |
| tSeen[v1]=sFunc |
| tNameBuf[3] = k1 |
| sName = table.concat(tNameBuf) |
| tRet[sName] = a2m_m2a(v1) --place all keys into ld[i]=value |
| dump_Tables(v1, sName, tSeen, tRet) |
| end |
| end |
| end |
| end |
| end |
| |
| local function dump_Functions(tBase) |
| --Based on: http://www.lua.org/cgi-bin/demo?globals |
| --We already recursed through tBase copying all found tables |
| --we look up the table by name and then (ab)use a2m_m2a() to load the address |
| --after finding the table by address in tBase we will |
| --put the table address of tFuncs in its place |
| local tFuncBuf = {} |
| for k,v in pairs(tBase) do |
| local tTable = a2m_m2a(v) |
| local tFuncs = {} |
| |
| for key, val in pairs(tTable) do |
| if key ~= "loaded" then |
| tFuncBuf[1] = dtTag(type(val)) |
| tFuncBuf[2] = tostring(key) |
| tFuncs[table.concat(tFuncBuf)]= val |
| --put the name and value in our tFuncs table |
| end |
| end |
| tBase[k] = a2m_m2a(tFuncs) -- copy the address back to tBase |
| end |
| |
| end |
| |
| local function get_common_branches(t, tRet) |
| --load t 'names(values)' into keys |
| --strip off long paths then iterate value if it exists |
| --local tRet={} |
| local sBranch = "" |
| local tName = {} |
| for k in pairs(t) do |
| tName["val"]=k |
| tableByName(tName) |
| sBranch = tName.val |
| if tRet[sBranch] == nil then |
| tRet[sBranch] = 1 --first instance of this branch |
| else |
| tRet[sBranch] = tRet[sBranch] + 1 |
| end |
| end |
| end |
| |
| local function pairsByPairs (t, tkSorted) |
| --tkSorted should be an already sorted (i)table with t[keys] in the values |
| --https://www.lua.org/pil/19.3.html |
| --!!Note: table sort default function does not like numbers as [KEY]!! |
| --see *sortbyKeys*cmp_alphanum* |
| |
| local i = 0 -- iterator variable |
| local iter = function () -- iterator function |
| i = i + 1 |
| if tkSorted[i] == nil then return nil |
| else return tkSorted[i], t[tkSorted[i]] |
| end |
| end |
| return iter |
| end |
| |
| local function sortbyKeys(t, tkSorted) |
| --loads keys of (t) into values of tkSorted |
| --and then sorts them |
| --tkSorted has integer keys (see ipairs) |
| ----FUNCTIONS for sortByKeys ------------- |
| local cmp_alphanum = function (op1, op2) |
| local type1= type(op1) |
| local type2 = type(op2) |
| if type1 ~= type2 then |
| return type1 < type2 |
| else |
| return op1 < op2 |
| end |
| end |
| ----END FUNCTIONS for sortByKeys --------- |
| for n in pairs(t) do table.insert(tkSorted, n) end |
| table.sort(tkSorted, cmp_alphanum)--table.sort(tkSorted) |
| end |
| |
| local function funcprint(tBuf, strName, value) |
| local sType = type(value) |
| local sVal = "" |
| local sHex = "" |
| tBuf[#tBuf + 1] = "\t" |
| tBuf[#tBuf + 1] = strName |
| if nil ~= string.find (";string;number;userdata;boolean;", sType, 1, true) then |
| --If any of the above types print the contents of variable |
| sVal = tostring(value) |
| |
| if type(value) == "number" then |
| sHex = " = 0x" .. string.format("%x", value) |
| else |
| sHex = "" |
| sVal = string.gsub(sVal, "\n", "\\n") --replace newline with \n |
| end |
| tBuf[#tBuf + 1] = " : " |
| tBuf[#tBuf + 1] = sVal |
| tBuf[#tBuf + 1] = sHex |
| end |
| tBuf[#tBuf + 1] = "\r\n" |
| end |
| |
| local function errorHandler( err ) |
| filehandle:write(" ERROR:" .. err .. "\n") |
| end |
| |
| |
| ------------MAIN---------------------------------------------------------------- |
| local _NIL = nil |
| local tSeen= {} |
| local tcBase = {} |
| local tkSortCbase = {} |
| local tMods= {} |
| local tkSortMods = {} |
| local tWriteBuf = {} |
| local n = 0 -- count of how many items were found |
| |
| filehandle = io.open(sDumpFile, "w+") --overwrite |
| tWriteBuf[#tWriteBuf + 1] = "*Loaded Modules* \n" |
| |
| xpcall( function() |
| dump_Tables(tableByName({["val"] = "_G"}),"", tSeen, tMods) |
| --you can put a table name here if you just wanted to display |
| --only its items, ex. "os" or "rb" or "io" |
| --However, it has to be accessible directly from _G |
| --so "rb.actions" wouldn't return anything since its technically |
| --enumerated through _G.rb |
| end , errorHandler ) |
| tSeen = nil |
| |
| xpcall( function()dump_Functions(tMods)end , errorHandler ) |
| |
| get_common_branches(tMods, tcBase) |
| |
| sortbyKeys(tcBase, tkSortCbase) |
| sortbyKeys(tMods, tkSortMods) |
| |
| for k, v in pairsByPairs(tcBase, tkSortCbase ) do |
| n = n + 1 |
| if n ~= 1 then |
| tWriteBuf[#tWriteBuf + 1] = ", " |
| end |
| tWriteBuf[#tWriteBuf + 1] = tostring(k) |
| if n >= 3 then -- split loaded modules to multiple lines |
| n = 0 |
| tWriteBuf[#tWriteBuf + 1] = "\r\n" |
| end |
| if #tWriteBuf > 25 then |
| filehandle:write(table.concat(tWriteBuf)) |
| for i=1, #tWriteBuf do tWriteBuf[i] = _NIL end -- reuse table |
| end |
| end |
| |
| tcBase= nil tkSortCbase= nil |
| tWriteBuf[#tWriteBuf + 1] = "\r\n" |
| tWriteBuf[#tWriteBuf + 1] = dtTag("?") |
| tWriteBuf[#tWriteBuf + 1] = "\r\n\r\n" |
| tWriteBuf[#tWriteBuf + 1] = "Functions: \r\n" |
| |
| n = 0 |
| for key, val in pairsByPairs(tMods, tkSortMods) do |
| local tkSorted = {} |
| local tFuncs = a2m_m2a(val) |
| sortbyKeys(tFuncs, tkSorted) |
| tWriteBuf[#tWriteBuf + 1] = "\r\n" |
| tWriteBuf[#tWriteBuf + 1] = tostring(key) |
| tWriteBuf[#tWriteBuf + 1] = "\r\n" |
| for k, v in pairsByPairs(tFuncs, tkSorted) do |
| n = n + 1 |
| funcprint(tWriteBuf, k,v) |
| if #tWriteBuf > 25 then |
| filehandle:write(table.concat(tWriteBuf)) |
| for i=1, #tWriteBuf do tWriteBuf[i] = _NIL end -- reuse table |
| end |
| end |
| end |
| tWriteBuf[#tWriteBuf + 1] = "\r\n\r\n" |
| tWriteBuf[#tWriteBuf + 1] = n |
| tWriteBuf[#tWriteBuf + 1] = " Items Found \r\n" |
| filehandle:write(table.concat(tWriteBuf)) |
| for i=1, #tWriteBuf do tWriteBuf[i] = _NIL end -- empty table |
| filehandle:close() |
| rb.splash(rb.HZ * 5, n .. " Items dumped to : " .. sDumpFile) |
| --rb.splash(500, collectgarbage("count")) |