local function esc(x) local res = "" for i=1, #x do local c = x:sub(i,i) if c == "\\" then res = res .. "\\\\" elseif c == "\01" then res = res .. "\\a" elseif c == "\02" then res = res .. "\\b" elseif c == "|" then res = res .. "\\p" else res = res .. c end end return res end local function unesc(x) local res = "" local i = 1 while i <= #x do local c = x:sub(i,i) if c == "\\" then local c2 = x:sub(i+1,i+1) if c2 == "\\" then res = res .. "\\" end if c2 == "a" then res = res .. "\01" end if c2 == "b" then res = res .. "\02" end if c2 == "p" then res = res .. "|" end i = i + 1 else res = res .. c end i = i + 1 end return res end local function genmsg(msg) return "\01|"..msg.timestamp.."|"..esc(msg.sender).."|"..esc(msg.content).."|"..(msg.parent or "").."|" end local function parsemsg(readable) if readable:read(1) ~= "\01" or readable:read(1) ~= "|" then return false end local section = 0 local timestamp = "" local sender = "" local content = "" local parent = "" while true do local c = readable:read(1) if c == nil then return false end if c == "|" then section = section + 1 if section == 4 then return {timestamp=timestamp, sender=unesc(sender), content=unesc(content), parent=parent=="" and nil or tonumber(parent)} end elseif section == 0 then timestamp = timestamp .. c elseif section == 1 then sender = sender .. c elseif section == 2 then content = content .. c else parent = parent .. c end end end local function appendmsg(filename,msg) local f = io.open(filename,"ab") local res = f:seek("cur",0) f:write(genmsg(msg)) f:close() return res end local function getmsg(filename,id) local f = io.open(filename,"rb") f:seek("set",id) local msg = parsemsg(f) msg.id = id f:close() return msg end local function last_n(filename,n,id) local res = {} local f = io.open(filename,"rb") local i = id or 0 while true do i = i - 1 local pos = f:seek(id and "set" or "end",i) local c = f:read(1) if not c then local res2 = {} for i=#res,1,-1 do table.insert(res2,res[i]) end return res2 end if c == "\01" then table.insert(res, getmsg(filename,pos)) end if #res >= n or pos == 0 then local res2 = {} for i=#res,1,-1 do table.insert(res2,res[i]) end return res2 end end end return {last_n = last_n, getmsg = getmsg, appendmsg = appendmsg}