Displays help using the same code used to display the change log.
[QuestHelper.git] / Development / dump.lua
blob90668350442aaf672aede4bbb038cf273d800f43
1 local function BufferAdd(self, text)
2 table.insert(self, tostring(text))
3 for i=#self-1, 1, -1 do
4 if string.len(self[i]) > string.len(self[i+1]) then break end
5 self[i] = self[i]..table.remove(self,i+1)
6 end
7 end
9 local function BufferDump(self)
10 for i=#self-1, 1, -1 do
11 self[i] = self[i]..table.remove(self)
12 end
13 return self[1] or ""
14 end
16 local function BufferAppend(self, buffer)
17 for i=1,#buffer do
18 BufferAdd(self, buffer[i])
19 end
20 while table.remove(buffer) do end
21 end
23 function CreateBuffer()
24 return {add=BufferAdd, dump=BufferDump, append=BufferAppend}
25 end
27 local function TableCompare(tbl_a, tbl_b)
28 local ak, av = next(tbl_a)
29 local bk, bv = next(tbl_b)
31 while ak and bk do
32 if type(ak) < type(bk) then return -1 end
33 if type(ak) > type(bk) then return 1 end
34 if ak < bk then return -1 end
35 if ak > bk then return 1 end
37 if type(av) < type(bv) then return -1 end
38 if type(av) > type(bv) then return 1 end
39 if type(av) == "table" then
40 local cmp = TableCompare(av, bv)
41 if cmp ~= 0 then return cmp end
42 elseif type(av) == "boolean" then
43 if av == bv then return 0
44 elseif av then return 1
45 else return -1 end
46 else
47 if av < bv then return -1 end
48 if av > bv then return 1 end
49 end
51 ak, av = next(tbl_a, ak)
52 bk, bv = next(tbl_b, bk)
53 end
55 if type(ak) < type(bk) then return -1 end
56 if type(ak) > type(bk) then return 1 end
57 return 0
58 end
60 local table_list = {}
61 local table_dat = {}
63 local function FindSameTable(tbl)
64 local sz = 0
65 local key = nil
66 while true do
67 key = next(tbl, key)
68 if not key then break end
69 sz = sz + 1
70 end
72 local list = table_list[sz]
73 if not list then
74 list = {}
75 table_list[sz] = list
76 end
78 local mn, mx = 1, #list+1
79 while mn ~= mx do
80 local m = math.floor((mn+mx)*0.5)
81 local ltbl = list[m]
82 local cmp = TableCompare(ltbl, tbl)
83 if cmp == -1 then
84 mx = m
85 elseif cmp == 1 then
86 mn = m+1
87 else
88 return ltbl, table_dat[ltbl]
89 end
90 end
92 table.insert(list, mn, tbl)
93 local dat = {}
94 table_dat[tbl] = dat
95 return tbl, dat
96 end
98 function ScanVariable(tbl)
99 if type(tbl) == "table" then
100 local tbl2, dat = FindSameTable(tbl)
102 if not dat.ref then
103 dat.ref = 1
105 for i, j in pairs(tbl2) do
106 tbl2[i] = ScanVariable(j)
108 else
109 dat.ref = dat.ref + 1
112 return tbl2, dat
115 return tbl, nil
118 local DumpRecurse
120 local last_id = 0
122 local function WriteDupVariables(prebuf, var, dup)
123 if not dup.id then
124 local buf = CreateBuffer()
125 local ref = dup.ref
126 dup.ref = 0 -- Do that we don't try to write DAT[???] = DAT[???] over and over again.
128 if last_id == 0 then
129 last_id = 1
130 prebuf:add("local DAT={}\n")
133 DumpRecurse(buf, prebuf, var, 1)
134 dup.ref = ref
136 dup.id = last_id
137 last_id = last_id + 1
139 prebuf:add("DAT[")
140 prebuf:add(tostring(dup.id))
141 prebuf:add("]=")
142 prebuf:append(buf)
143 prebuf:add("\n")
147 local function isArray(obj)
148 if type(obj) == "table" then
149 local c = 0
150 for i, j in pairs(obj) do c = c + 1 end
151 return c == #obj
153 return false
156 local function isSafeString(obj)
157 return type(obj) == "string" and string.len(obj) > 0 and string.find(obj, "^[%a_][%a%d_]*$")
160 DumpRecurse = function(buffer, prebuf, variable, depth)
161 if type(variable) == "string" then
162 return buffer:add(("%q"):format(variable))
163 elseif type(variable) == "number" then
164 return buffer:add(tostring(variable+0))
165 elseif type(variable) == "nil" then
166 return buffer:add("nil")
167 elseif type(variable) == "boolean" then
168 return buffer:add(variable and "true" or "false")
169 elseif type(variable) == "table" then
170 local dup = table_dat[variable]
172 if dup and dup.ref > 1 then
173 WriteDupVariables(prebuf, variable, dup)
174 buffer:add("DAT["..dup.id.."]")
175 return
178 buffer:add("{")
180 if isArray(variable) then
181 for i, j in ipairs(variable) do
182 if isArray(j) then
183 buffer:add("\n"..(" "):rep(depth))
186 DumpRecurse(buffer, prebuf, j, depth+1)
187 if i ~= #variable then
188 buffer:add(", ")
191 else
192 buffer:add("\n"..(" "):rep(depth))
194 local sort_table = {}
196 for key in pairs(variable) do
197 table.insert(sort_table, key)
200 table.sort(sort_table, function (a, b)
201 if type(a) < type(b) then return true end
202 return type(a) == type(b) and (tostring(a) or "") < (tostring(b) or "")
203 end)
205 for index, i in ipairs(sort_table) do
206 local j = variable[i]
208 if isSafeString(i) then
209 buffer:add(i.."=")
210 else
211 buffer:add("[")
212 DumpRecurse(buffer, prebuf, i, depth+1)
213 buffer:add("]=")
216 --buffer:add((type(j)=="table"and"\n"..(" "):rep(depth+1) or ""))
218 DumpRecurse(buffer, prebuf, j, depth+1)
220 if index~=#sort_table then
221 buffer:add(",\n"..(" "):rep(depth))
226 buffer:add("}")
227 else
228 return buffer:add("nil --[[ UNHANDLED TYPE: '"..type(variable).."' ]]")
232 function DumpVariable(buffer, prebuf, variable, name)
233 buffer:add(name)
234 buffer:add("=")
235 DumpRecurse(buffer, prebuf, variable, 1)
236 buffer:add("\n")
239 function DumpingComplete(buffer, prebuf)
240 if last_id ~= 0 then
241 buffer:add("DAT=nil\n")
242 last_id = 0
243 prebuf:add("\n")
246 prebuf:append(buffer)
248 local result = prebuf:dump()
250 table_list = {}
251 table_dat = {}
252 return result
255 function ScanAndDumpVariable(variable, name, no_scan)
256 local buffer, prebuf = CreateBuffer(), CreateBuffer()
258 if name then
259 DumpVariable(buffer, prebuf, no_scan and variable or ScanVariable(variable), name)
260 else
261 -- If no name is specified, dump each variable in sequence.
262 local sort_table = {}
264 for key, var in pairs(variable) do
265 table.insert(sort_table, key)
267 if not no_scan then
268 ScanVariable(var)
272 table.sort(sort_table, function (a, b)
273 if type(a) < type(b) then return true end
274 return type(a) == type(b) and (tostring(a) or "") < (tostring(b) or "")
275 end)
277 for index, i in ipairs(sort_table) do
278 if isSafeString(i) then
279 buffer:add(i)
280 buffer:add("=")
281 else
282 -- A variable that doesn't have a normal name. Why this would be is a mystery.
283 buffer:add("_G[")
284 DumpRecurse(buffer, prebuf, i, 0)
285 buffer:add("]=")
288 DumpRecurse(buffer, prebuf, variable[i], 1)
289 buffer:add("\n")
293 return DumpingComplete(buffer, prebuf)