diff options
Diffstat (limited to 'xml.lua')
-rw-r--r-- | xml.lua | 73 |
1 files changed, 73 insertions, 0 deletions
@@ -0,0 +1,73 @@ +local function parseargs(s) + local arg = {} + string.gsub(s, "([%-%w]+)=([\"'])(.-)%2", function (w, _, a) + arg[w] = a + end) + return arg +end + +local psingle + +local function pmulti(s, i, parent) + ::again:: + local nexti, child = psingle(s, i) + if child.close and child.label == parent.label then + return nexti, parent + else + table.insert(parent, child) + i = nexti + goto again + end +end + +psingle = function(s, i) + i = i or 1 + local ts,j,c,label,xarg,empty = s:find("<(%/?)([%w:]+)(.-)(%/?)>", i) + if not ts then + local rest = s:sub(i) + if rest:find("<",i) then + error('ill formed (eof?)') + elseif #rest == 0 then + error('empty string') + else + return i+#rest, rest + end + end + local nexti = j+1 + + local pretext = s:sub(i, ts-1) + if not pretext:find("^%s*$") then -- not entirely whitespace + return ts, pretext + end + + if empty == "/" then + return nexti, {label=label, xarg=parseargs(xarg), empty=true} + elseif c == "" then -- start tag + return multi(s, nexti, {label=label, xarg=parseargs(xarg)}) + else -- end tag + return nexti, {label=label, close=true} + end +end + +local wrap +do + local _, cqa = pcall(require, 'cqueues.auxlib') + wrap = cqa and cqa.wrap or coroutine.wrap +end +local function stanzae(getmore) + return wrap(function() + local buf = '' + while true do + local ok, ni, el = pcall(psingle, buf) + if ok then + coroutine.yield(el) + buf = buf:sub(ni) + else + buf = buf..getmore() + end + end + end) +end + + +return { psingle = psingle, stanzae = stanzae, wrap=wrap } |