[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: persistent data & serialization
- From: cmuz@...
- Date: Mon, 13 Nov 2000 13:33:18 +0100 (MET)
Hello,
I've seen the thread about serialization earlier in this list,
but didn't find the code mentioned there.
To deal with persistent data in LUA similar to the Win95 INI-Files, I put
together a serialization scheme for basic lua types (Lua version 3.2).
'function' and 'userdata' is not supported.
There is one function 'serialize(t,q)' which returns a _one_ line
representation of the value of variable t. Parameter q is optional to
change the default quote character (') of string serialization.
Note that the name of the serialized variable is not included in
the serial representation but only the value.
The other function is 'unserialize(s)' which tries to undo what
serialize did. It's also possible to unserialize unquoted strings, but
this can have side effects. Look at attached source for details.
To see an example of how it works, run
$lua serial.lua >out
from the command line and look at the generated output in file 'out'.
It's not heavily tested but works fine for me.
May be it is useful for someone else.
Comments, improvements and bug reports are welcome.
CM
--
Sent through GMX FreeMail - http://www.gmx.net
-----------------------------------------------------------------------------
-- Simple serialization of basic lua types
-- 11/12/2000 Christof Muz
-- This is public domain. Absolutely no guarantees.
-----------------------------------------------------------------------------
-----------------------------------
-- Make a _flat_ copy of table t --
-----------------------------------
function duptable(t)
if type(t) == 'table' then
local nt = {}
local i,v = next(t,nil)
while i do
nt[i]=v
i,v = next(t,i)
end
return nt
end
return t
end
---------------------------------------------
-- Escape all special characters of string --
---------------------------------------------
function escapestring(s)
s = gsub(s,"([%c\\'\"%z]?)", -- convert special characters
function(l)
if l and l ~= '' then
if strbyte(l) == strbyte('\n') then return "\\n" end
if strbyte(l) == strbyte('\t') then return "\\t" end
if strbyte(l) == strbyte('\r') then return "\\r" end
if strbyte(l) == strbyte('\f') then return "\\f" end
if strbyte(l) == strbyte('\\') then return "\\\\" end
if strbyte(l) == strbyte('"') then return '\\"' end
if strbyte(l) == strbyte("'") then return "\\'" end
return "\\" .. tonumber(strbyte(l))
end
end
)
return s
end
----------------------------------------------------
-- Serialize a luatype (recursively for 'tables') --
-----------------------------------------------------------------------------
-- The serialization of a luatype is a _one_ line string (e.g. no \n,...)
-- ot : the luatype , works fine with 'table', 'string', 'number' and nil
-- for userdata and functions the type string is returned.
-- q (optional) : quote-character for string serialization (default is "'")
-----------------------------------------------------------------------------
function serialize(ot,q)
if ot == nil or
type(ot) == 'number' then
return tostring(ot)
end
if not q then -- string quotation character
q = "'"
end
if type(ot) == 'string' then
ot = escapestring(ot)
return q .. ot .. q
end
if type(ot) == 'table' then -- tables
local s ='{' -- serial representation to build
local t = duptable(ot) -- work on a copy of the table
local i,n = 1,getn(t) -- iteration start for 'array' elements
local sep = '' -- the item seperator for output
local defd = '_$visited$_' -- this element is already serialized
while i<=n do -- first all array items
if t[i] then s = s .. sep .. serialize(t[i]) end
t[i]=defd
sep = ','
i=i+1
end
sep=';'
i,v = next(t,nil) -- iterate again for all other items
while i do
if v and v ~= defd then
s = s .. sep .. tostring(i) .. '=' .. serialize(v)
sep=','
end
i,v = next(t,i)
end
s = s .. '}'
return s
end
return q .. type(ot) .. q
end
------------------------
-- Undo serialization --
-----------------------------------------------------------------------------
-- only type 'string' is considered a valid serialization
-- other types are simply returned !
-- serialized strings should be quoted (e.g "'a string'"), which
-- is the default behaviour of serialize.
-- If not quoted the default 'tonumber' conversion may lead to
-- unexpected results. ( e.g. string(1stclass) -> number(1) )
-- Leading whitespace is _NOT_ stripped, which might be a problem with
-- 'table' unserialization, as tables are identified by a '{'-character
-- at the first position. (e.g. string({n=0}) -> table {n=0}
-- but string( {n=0}) represents a string
-- ^ space-character
-----------------------------------------------------------------------------
function unserialize(s)
if type(s) ~= 'string' then return s end
if tonumber(s) then return tonumber(s) end -- seems to be a simple number
-- but watch out: '1a-class'
if s == tostring(nil) then return nil end -- nil
if strbyte(s) ~= strbyte('{') and -- not a tabledef string
strbyte(s) ~= strbyte("'") and -- and
strbyte(s) ~= strbyte('"') then -- not a quoted string
local t = escapestring(s)
s = "'" .. t .. "'" -- quote the string
end
local gname = '__unserialized__var'
local t
-- parse string with lua core
dostring(gname.."="..s) -- convert it
t = getglobal(gname)
setglobal(gname,nil)
return t
end
-----------------------------------------------------------------------------
-- Tests of serialization/unserialization
-----------------------------------------------------------------------------
function xforeach(t,f,l) -- recursively for tables
local i,v = next(t,nil)
if not l then l=0 end
while i do
if type(v) == 'table' then
f(l,i,v)
xforeach(v,f,l+1)
else
f(l,i,v)
end
i,v = next(t,i)
end
end
function tp(l,n,v) -- print table hierarchy (l=level)
local s=''
while l > 0 do s=s..'\t' l=l-1 end
print(format("%s[%s]=(%s)%s",s,n,type(v),tostring(v)))
end
-----------------------------------------------------------------------------
--- define test data
-----------------------------------------------------------------------------
tab = {1,2,3,4,
{5.1,5.2;n=2,t='subtable'},
{6.1,6.2;n=2,t='subtable'};
n=6,
example='table serialization'}
strtab = { " 'first' ",' "second" ', " \"third\" ",' \'fourth\' '}
bindat = [[Hello World
from Lua
This is a longer 'string' with
embedded ctrl-characters\t
]]
thetest = {tab,strtab,bindat;n=3}
-----------------------------------------------------------------------------
-- The test
-----------------------------------------------------------------------------
--- print test data
print('test data:')
xforeach(thetest,tp)
--- serialize and print serialization
thetestser = serialize(thetest)
print('\nserial representation of test data:')
print(thetestser,"\n")
--- unserialize and print generated data
print('unserialized test data:')
xforeach(unserialize(thetestser),tp)