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 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
.."]")
180 if isArray(variable
) then
181 for i
, j
in ipairs(variable
) do
183 buffer
:add("\n"..(" "):rep(depth
))
186 DumpRecurse(buffer
, prebuf
, j
, depth
+1)
187 if i
~= #variable
then
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 "")
205 for index
, i
in ipairs(sort_table
) do
206 local j
= variable
[i
]
208 if isSafeString(i
) then
212 DumpRecurse(buffer
, prebuf
, i
, depth
+1)
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
))
228 return buffer
:add("nil --[[ UNHANDLED TYPE: '"..type(variable
).."' ]]")
232 function DumpVariable(buffer
, prebuf
, variable
, name
)
235 DumpRecurse(buffer
, prebuf
, variable
, 1)
239 function DumpingComplete(buffer
, prebuf
)
241 buffer
:add("DAT=nil\n")
246 prebuf
:append(buffer
)
248 local result
= prebuf
:dump()
255 function ScanAndDumpVariable(variable
, name
, no_scan
)
256 local buffer
, prebuf
= CreateBuffer(), CreateBuffer()
259 DumpVariable(buffer
, prebuf
, no_scan
and variable
or ScanVariable(variable
), name
)
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
)
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 "")
277 for index
, i
in ipairs(sort_table
) do
278 if isSafeString(i
) then
282 -- A variable that doesn't have a normal name. Why this would be is a mystery.
284 DumpRecurse(buffer
, prebuf
, i
, 0)
288 DumpRecurse(buffer
, prebuf
, variable
[i
], 1)
293 return DumpingComplete(buffer
, prebuf
)