mirror of
https://github.com/vxcontrol/lualibs-genx.git
synced 2026-07-01 17:54:37 -04:00
146 lines
3.3 KiB
Lua
146 lines
3.3 KiB
Lua
--genx xml generator binding.
|
|
local ffi = require'ffi'
|
|
local C = ffi.load'genx'
|
|
local M = {C = C}
|
|
require'genx_h'
|
|
|
|
local function checkh(w, statusP, h)
|
|
if h ~= nil then return h end
|
|
local s = C.genxGetErrorMessage(w, statusP[0])
|
|
error(s ~= nil and ffi.string(s) or 'unknown error')
|
|
end
|
|
|
|
local function checknz(w, status)
|
|
if status == 0 then return end
|
|
local s = C.genxGetErrorMessage(w, status)
|
|
error(s ~= nil and ffi.string(s) or 'unknown error')
|
|
end
|
|
|
|
local function nzcaller(f)
|
|
return function(w, ...)
|
|
return checknz(w, f(w, ...))
|
|
end
|
|
end
|
|
|
|
function M.version()
|
|
return ffi.string(C.genxGetVersion())
|
|
end
|
|
|
|
function M.new(alloc, dealloc, userdata)
|
|
local w = C.genxNew(alloc, dealloc, userdata)
|
|
assert(w ~= nil, 'out of memory')
|
|
ffi.gc(w, C.genxDispose)
|
|
return w
|
|
end
|
|
|
|
local senders = {} --{[genxWriter] = genxSender}
|
|
|
|
function free_sender(w)
|
|
local sender = senders[w]
|
|
if not sender then return end
|
|
sender.send:free()
|
|
sender.sendBounded:free()
|
|
sender.flush:free()
|
|
senders[w] = nil
|
|
end
|
|
|
|
local function free(w)
|
|
C.genxDispose(ffi.gc(w, nil))
|
|
free_sender(w)
|
|
end
|
|
|
|
ffi.metatype('genxWriter_rec', {__index = {
|
|
|
|
free = free,
|
|
|
|
start_doc = function(w, f, ...)
|
|
free_sender(w)
|
|
if type(f) == 'function' then
|
|
--f is called as either: f(s), f(s, sz), or f() to signal EOF.
|
|
local sender = ffi.new'genxSender'
|
|
sender.send = ffi.new('send_callback', function(_, s) f(s); return 0 end)
|
|
sender.sendBounded = ffi.new('sendBounded_callback', function(_, p1, p2) f(p1, p2-p1); return 0 end)
|
|
sender.flush = ffi.new('flush_callback', function() f(); return 0 end)
|
|
senders[w] = sender
|
|
checknz(w, C.genxStartDocSender(w, sender))
|
|
else
|
|
checknz(w, C.genxStartDocFile(w, f))
|
|
end
|
|
end,
|
|
|
|
end_doc = nzcaller(C.genxEndDocument),
|
|
|
|
ns = function(w, uri, prefix, statusP)
|
|
statusP = statusP or ffi.new'genxStatus[1]'
|
|
return checkh(w, statusP, C.genxDeclareNamespace(w, uri, prefix, statusP))
|
|
end,
|
|
|
|
element = function(w, name, ns, statusP)
|
|
statusP = statusP or ffi.new'genxStatus[1]'
|
|
return checkh(w, statusP, C.genxDeclareElement(w, ns, name, statusP))
|
|
end,
|
|
|
|
attr = function(w, name, ns, statusP)
|
|
statusP = statusP or ffi.new'genxStatus[1]'
|
|
return checkh(w, statusP, C.genxDeclareAttribute(w, ns, name, statusP))
|
|
end,
|
|
|
|
comment = nzcaller(C.genxComment),
|
|
|
|
pi = nzcaller(C.genxPI),
|
|
|
|
start_element = function(w, e, ns, prefix)
|
|
if type(ns) == 'string' then
|
|
ns = w:ns(ns, prefix)
|
|
end
|
|
if type(e) == 'string' then
|
|
e = w:element(e, ns)
|
|
end
|
|
checknz(w, C.genxStartElement(e))
|
|
end,
|
|
|
|
add_attr = function(w, a, val, ns, prefix)
|
|
if type(ns) == 'string' then
|
|
ns = w:ns(ns, prefix)
|
|
end
|
|
if type(a) == 'string' then
|
|
a = w:attr(a, ns)
|
|
end
|
|
checknz(w, C.genxAddAttribute(a, val))
|
|
end,
|
|
|
|
add_ns = function(w, ns, prefix)
|
|
if type(ns) == 'string' then
|
|
ns = w:ns(ns, prefix)
|
|
end
|
|
checknz(w, C.genxAddNamespace(ns, prefix))
|
|
end,
|
|
|
|
unset_default_namespace = nzcaller(C.genxUnsetDefaultNamespace),
|
|
|
|
end_element = nzcaller(C.genxEndElement),
|
|
|
|
text = function(w, s, sz)
|
|
checknz(w, C.genxAddCountedText(w, s, sz or #s))
|
|
end,
|
|
|
|
char = nzcaller(C.genxAddCharacter),
|
|
|
|
check_text = C.genxCheckText,
|
|
|
|
scrub_text = function(s_in)
|
|
s_out = ffi.new('constUtf8[?]', #s_in + 1)
|
|
if C.genxScrubText(s_in, s_out) ~= 0 then
|
|
return ffi.string(s_out)
|
|
else
|
|
return s_in
|
|
end
|
|
end,
|
|
|
|
}, __gc = free})
|
|
|
|
if not ... then require'genx_demo' end
|
|
|
|
return M
|
|
|