1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
|
--RB LUA show all global variables; BILGUS
require "actions"
require "audio"
require "buttons"
require "color"
require "draw"
require "draw_floodfill"
require "draw_poly"
require "draw_text"
require "image"
require "image_save"
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"))
|