TableDumper.lua
Aus Romwiki
Mit diesem lua-Script habe ich die Liste aller Widgets erstellt.
Ja, es fehlen noch Kommentare. Ist auch noch nicht fertig.
Elrac 08:02, 30. Jan 2009 (CET)
local mod = b9.StartModule("TableDumper")
local handle,gripe = io.open("TableStats.txt", "w")
if not handle then
b9.perr(gripe)
error(gripe)
end
local function addTo(list, item)
if not list then
return { item }
else
table.insert(list, item)
return list
end
end
local tables = { } -- key -> entry
-- Create an entry from a table. Record its noteworthy properties.
local function discover(name, tab, newRank)
local key = tostring(tab)
local entry = tables[key]
if not entry then
entry = { table=tab, rank=newRank }
tables[key] = entry
else
if newRank > entry.rank then entry.rank = newRank end
end
if name then
entry.names = addTo(entry.names, name)
end
local idx = tab.__index
if type(idx) == "table" and idx ~= tab then
entry.index = discover(nil, idx, entry.rank + 1)
entry.index.iChildren = addTo(entry.index.iChildren, tab)
end
local mt = getmetatable(tab)
if type(mt) == "table" and mt ~= tab then
entry.meta = discover(nil, mt, entry.rank + 1)
entry.meta.mChildren = addTo(entry.meta.mChildren, tab)
end
return entry
end
-- Loop over all variables to gather all tables
for name, tab in pairs(_G) do
if type(tab) == "table" then
discover(name, tab, 1)
end
end
local function tableSize(tab)
local size = 0
for k,v in pairs(tab) do size = size + 1 end
return size
end
local function max(n1,n2)
if n1 > n2 then return n1 else return n2 end
end
-- Gather all indices and metatables
local ancestors = { } -- key,...
local iCount, mCount, imCount = 0, 0, 0
for key, entry in pairs(tables) do
if entry.iChildren and entry.mChildren then
if not entry.name then
imCount = imCount + 1
entry.names = addTo(entry.names, "meta-index#" .. tostring(imCount))
end
entry.childCount = max(tableSize(entry.iChildren), tableSize(entry.mChildren))
table.insert(ancestors, key)
elseif entry.iChildren then
if not entry.name then
iCount = iCount + 1
entry.names = addTo(entry.names, "index#" .. tostring(iCount))
end
entry.childCount = tableSize(entry.iChildren)
table.insert(ancestors, key)
elseif entry.mChildren then
if not entry.name then
mCount = mCount + 1
entry.names = addTo(entry.names, "meta#" .. tostring(mCount))
end
entry.childCount = tableSize(entry.mChildren)
table.insert(ancestors, key)
end
end
-- Sort ancestors on
--- descending rank
--- ascending child count
local function compareEntries(key1,key2)
local e1 = tables[key1]
local e2 = tables[key2]
if e1.rank > e2.rank then return true end
if e1.rank < e2.rank then return false end
if e1.childCount < e2.childCount then return true end
return false
end
table.sort(ancestors, compareEntries)
-- Given a list of names, convert any group of names with common
-- alpha parts but varying numeric parts into a single name with the
-- maximum numeric value at that position in square brackets.
local function sanitizeNames(names)
-- Build an index from the given name:
-- if name is pure alpha, insert it into "plain". otherwise:
-- * construct a label from the name
-- * create a table entry from "label" and { min, max, ... } of the numeric values in the name.
-- * a min, max pair is stored for each numeric in the name, so the value will have 2*n entries
-- * for n numeric substrings in "name".
local function indexName(names, plain, name)
-- Split a name (e.g. "aa5bb66cc") into a table of alpha strings
-- (e.g. {"aa", "bb", "cc"}) and a table of numbers (e.g. {5, 66}).
-- "alpha" in this case includes the underscore ( "_" )
local function scanName(name)
local texts = { }
local numbers = { }
local pos = 1
while true do
local start, stop, part = string.find(name, "([a-zA-Z_#]+)", pos)
if not start then break end
table.insert(texts, part)
pos = stop + 1
local start, stop, part = string.find(name, "(%d+)", pos)
if not start then break end
table.insert(numbers, tonumber(part))
pos = stop + 1
end
if numbers[1] then
return texts, numbers
else
return texts
end
end
-- Make a label (e.g. "aa[]bb[]cc") from an array of alpha strings.
local function makeLabel(texts)
local first = true
local label
for _,str in pairs(texts) do
if first then
label = str
first = false
else
label = label .. "[]" .. str
end
end
return label
end
if string.find(name, "#") or not string.find(name, "%d+") then
table.insert(plain, name)
else
local texts, numbers = scanName(name)
local label = makeLabel(texts)
local entry = names[label]
if not entry then
entry = { }
for _,n in ipairs(numbers) do
table.insert(entry, n)
table.insert(entry, n)
end
names[label] = entry
else
local idx = 1
for _,n in ipairs(numbers) do
if entry[idx] == nil or n < entry[idx] then entry[idx] = n end
idx = idx + 1
if entry[idx] == nil or n > entry[idx] then entry[idx] = n end
idx = idx + 1
end
end
end
end
local pool = { }
local plain = { }
for _,name in ipairs(names) do
indexName(pool, plain, name)
end
for xname,stats in pairs(pool) do
local name = xname
local idx = 0
while true do
local p,q = string.find(name, "%[%]")
if not p then break end
idx = idx + 1
if stats[idx] == stats[idx+1] then
name = string.sub(name, 1, p-1) .. tostring(stats[idx]) .. string.sub(name, q+1)
else
name = string.sub(name, 1, p) .. tostring(stats[idx+1]) .. string.sub(name, q)
end
idx = idx + 1
end
table.insert(plain, name)
end
return plain
end
-- output each ancestor
local function tablesByName(children, childTables)
for _,tab in pairs(childTables) do
local key = tostring(tab)
local name = tables[key].names[1]
children[name] = tab
end
end
local function compareNames(name1, name2)
local p1 = string.find(name1, "#")
local p2 = string.find(name2, "#")
if not p1 and not p2 or p1 and p2 then return name1 < name2 end
return p1 ~= nil
end
for _,aKey in ipairs(ancestors) do
local entry = tables[aKey]
handle:write(string.format(
'=== <span id="%s">%s</span> ===\n\n',
entry.names[1], entry.names[1]))
local children = { } -- name -> tab
if entry.iChildren then
tablesByName(children, entry.iChildren)
end
if entry.mChildren then
tablesByName(children, entry.mChildren)
end
local names = { } -- name,...
for name,_ in pairs(children) do
table.insert(names, name)
end
local sanitized = sanitizeNames(names)
-- local sanitized = names
table.sort(sanitized, compareNames)
local nth = false
local pos = 0
for n,name in ipairs(sanitized) do
if pos > 80 then
handle:write("\n")
pos = 0
end
if nth then
if pos > 0 then handle:write(" ") end
handle:write("• ")
pos = pos + 1
else
nth = true
end
if string.find(name, "#") then
handle:write("[[#", name, "]]")
pos = pos + string.len(name) + 5
else
handle:write(name)
pos = pos + string.len(name)
end
end
handle:write("\n\n\n")
end
handle:close()
b9.ModuleLoaded(mod)
