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)
9 local function BufferDump(self
)
10 for i
=#self
-1, 1, -1 do
11 self
[i
] = self
[i
]..table.remove(self
)
16 local function BufferAppend(self
, buffer
)
18 BufferAdd(self
, buffer
[i
])
20 while table.remove(buffer
) do end
23 function CreateBuffer()
24 return {add
=BufferAdd
, dump
=BufferDump
, append
=BufferAppend
}
27 local function TableCompare(tbl_a
, tbl_b
)
28 local ak
, av
= next(tbl_a
)
29 local bk
, bv
= next(tbl_b
)
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
47 if av
< bv
then return -1 end
48 if av
> bv
then return 1 end
51 ak
, av
= next(tbl_a
, ak
)
52 bk
, bv
= next(tbl_b
, bk
)
55 if type(ak
) < type(bk
) then return -1 end
56 if type(ak
) > type(bk
) then return 1 end
63 local function FindSameTable(tbl
)
68 if not key
then break end
72 local list
= table_list
[sz
]
78 local mn
, mx
= 1, #list
+1
80 local m
= math
.floor((mn
+mx
)*0.5)
82 local cmp
= TableCompare(ltbl
, tbl
)
88 return ltbl
, table_dat
[ltbl
]
92 table.insert(list
, mn
, tbl
)
98 function ScanVariable(tbl
)
99 if type(tbl
) == "table" then
100 local tbl2
, dat
= FindSameTable(tbl
)
105 for i
, j
in pairs(tbl2
) do
106 tbl2
[i
] = ScanVariable(j
)
109 dat
.ref
= dat
.ref
+ 1
122 local function WriteDupVariables(prebuf
, var
, dup
)
124 local buf
= CreateBuffer()
126 dup
.ref
= 0 -- Do that we don't try to write DAT[???] = DAT[???] over and over again.
130 prebuf
:add("local DAT={}\n")
133 DumpRecurse(buf
, prebuf
, var
, 1)
137 last_id
= last_id
+ 1
140 prebuf
:add(tostring(dup
.id
))
147 local function isArray(obj
)
148 if type(obj
) == "table" then
150 for i
, j
in pairs(obj
) do c
= c
+ 1 end
156 local reserved_words
=
181 local function isSafeString(obj
)
182 return type(obj
) == "string" and not reserved_words
[obj
] and obj
:find("^[%a_][%w_]*$")
185 DumpRecurse
= function(buffer
, prebuf
, variable
, depth
)
186 if type(variable
) == "string" then
187 return buffer
:add(("%q"):format(variable
))
188 elseif type(variable
) == "number" then
189 return buffer
:add(tostring(variable
+0))
190 elseif type(variable
) == "nil" then
191 return buffer
:add("nil")
192 elseif type(variable
) == "boolean" then
193 return buffer
:add(variable
and "true" or "false")
194 elseif type(variable
) == "table" then
195 local dup
= table_dat
[variable
]
197 if dup
and dup
.ref
> 1 then
198 WriteDupVariables(prebuf
, variable
, dup
)
199 buffer
:add("DAT["..dup
.id
.."]")
205 if isArray(variable
) then
206 for i
, j
in ipairs(variable
) do
208 buffer
:add("\n"..(" "):rep(depth
))
211 DumpRecurse(buffer
, prebuf
, j
, depth
+1)
212 if i
~= #variable
then
217 buffer
:add("\n"..(" "):rep(depth
))
219 local sort_table
= {}
221 for key
in pairs(variable
) do
222 table.insert(sort_table
, key
)
225 table.sort(sort_table
, function (a
, b
)
226 if type(a
) < type(b
) then return true end
227 return type(a
) == type(b
) and (tostring(a
) or "") < (tostring(b
) or "")
230 for index
, i
in ipairs(sort_table
) do
231 local j
= variable
[i
]
233 if isSafeString(i
) then
237 DumpRecurse(buffer
, prebuf
, i
, depth
+1)
241 --buffer:add((type(j)=="table"and"\n"..(" "):rep(depth+1) or ""))
243 DumpRecurse(buffer
, prebuf
, j
, depth
+1)
245 if index
~=#sort_table
then
246 buffer
:add(",\n"..(" "):rep(depth
))
253 return buffer
:add("nil --[[ UNHANDLED TYPE: '"..type(variable
).."' ]]")
257 function DumpVariable(buffer
, prebuf
, variable
, name
)
260 DumpRecurse(buffer
, prebuf
, variable
, 1)
264 function DumpingComplete(buffer
, prebuf
)
266 buffer
:add("DAT=nil\n")
271 prebuf
:append(buffer
)
273 local result
= prebuf
:dump()
280 function ScanAndDumpVariable(variable
, name
, no_scan
)
281 local buffer
, prebuf
= CreateBuffer(), CreateBuffer()
284 DumpVariable(buffer
, prebuf
, no_scan
and variable
or ScanVariable(variable
), name
)
286 -- If no name is specified, dump each variable in sequence.
287 local sort_table
= {}
289 for key
, var
in pairs(variable
) do
290 table.insert(sort_table
, key
)
297 table.sort(sort_table
, function (a
, b
)
298 if type(a
) < type(b
) then return true end
299 return type(a
) == type(b
) and (tostring(a
) or "") < (tostring(b
) or "")
302 for index
, i
in ipairs(sort_table
) do
303 if isSafeString(i
) then
307 -- A variable that doesn't have a normal name. Why this would be is a mystery.
309 DumpRecurse(buffer
, prebuf
, i
, 0)
313 DumpRecurse(buffer
, prebuf
, variable
[i
], 1)
318 return DumpingComplete(buffer
, prebuf
)