From 4ed30744220cf0763f968c837b0ff7dd367f19b2 Mon Sep 17 00:00:00 2001
From: Hans Hagen <pragma@wxs.nl>
Date: Fri, 25 Mar 2011 18:03:00 +0100
Subject: beta 2011.03.25 18:03

---
 scripts/context/lua/mtx-context.lua             | 532 ++++++++++++------------
 scripts/context/lua/mtx-fonts.lua               |   2 +-
 scripts/context/lua/mtx-interface.lua           |   2 +-
 scripts/context/lua/mtx-server-ctx-fonttest.lua |  14 +-
 scripts/context/lua/mtxrun.lua                  |  99 +++--
 scripts/context/stubs/mswin/mtxrun.lua          |  99 +++--
 scripts/context/stubs/unix/mtxrun               |  99 +++--
 7 files changed, 476 insertions(+), 371 deletions(-)

(limited to 'scripts')

diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua
index 39712af7e..36e3efb6b 100644
--- a/scripts/context/lua/mtx-context.lua
+++ b/scripts/context/lua/mtx-context.lua
@@ -117,334 +117,334 @@ function io.copydata(fromfile,tofile)
     io.savedata(tofile,io.loaddata(fromfile) or "")
 end
 
--- ctx
-
-ctxrunner = { }
-
-do
-
-    function ctxrunner.filtered(str,method)
-        str = tostring(str)
-        if     method == 'name'     then str = file.removesuffix(file.basename(str))
-        elseif method == 'path'     then str = file.dirname(str)
-        elseif method == 'suffix'   then str = file.extname(str)
-        elseif method == 'nosuffix' then str = file.removesuffix(str)
-        elseif method == 'nopath'   then str = file.basename(str)
-        elseif method == 'base'     then str = file.basename(str)
-    --  elseif method == 'full'     then
-    --  elseif method == 'complete' then
-    --  elseif method == 'expand'   then -- str = file.expandpath(str)
-        end
-        return str:gsub("\\","/")
+-- ctx (will become util-ctx)
+
+local ctxrunner = { }
+
+function ctxrunner.filtered(str,method)
+    str = tostring(str)
+    if     method == 'name'     then str = file.removesuffix(file.basename(str))
+    elseif method == 'path'     then str = file.dirname(str)
+    elseif method == 'suffix'   then str = file.extname(str)
+    elseif method == 'nosuffix' then str = file.removesuffix(str)
+    elseif method == 'nopath'   then str = file.basename(str)
+    elseif method == 'base'     then str = file.basename(str)
+--  elseif method == 'full'     then
+--  elseif method == 'complete' then
+--  elseif method == 'expand'   then -- str = file.expandpath(str)
     end
+    return str:gsub("\\","/")
+end
 
-    function ctxrunner.substitute(e,str)
-        local attributes = e.at
-        if str and attributes then
-            if attributes['method'] then
-                str = ctxrunner.filtered(str,attributes['method'])
-            end
-            if str == "" and attributes['default'] then
-                str = attributes['default']
-            end
+function ctxrunner.substitute(e,str)
+    local attributes = e.at
+    if str and attributes then
+        if attributes['method'] then
+            str = ctxrunner.filtered(str,attributes['method'])
+        end
+        if str == "" and attributes['default'] then
+            str = attributes['default']
         end
-        return str
     end
+    return str
+end
 
-    function ctxrunner.reflag(flags)
-        local t = { }
-        for _, flag in next, flags do
-            local key, value = match(flag,"^(.-)=(.+)$")
-            if key and value then
-                t[key] = value
-            else
-                t[flag] = true
-            end
+function ctxrunner.reflag(flags)
+    local t = { }
+    for _, flag in next, flags do
+        local key, value = match(flag,"^(.-)=(.+)$")
+        if key and value then
+            t[key] = value
+        else
+            t[flag] = true
         end
-        return t
     end
+    return t
+end
 
-    function ctxrunner.substitute(str)
-        return str
-    end
+function ctxrunner.substitute(str)
+    return str
+end
 
-    function ctxrunner.justtext(str)
-        str = xml.unescaped(tostring(str))
-        str = xml.cleansed(str)
-        str = str:gsub("\\+",'/')
-        str = str:gsub("%s+",' ')
-        return str
-    end
+function ctxrunner.justtext(str)
+    str = xml.unescaped(tostring(str))
+    str = xml.cleansed(str)
+    str = str:gsub("\\+",'/')
+    str = str:gsub("%s+",' ')
+    return str
+end
 
-    function ctxrunner.new()
-        return {
-            ctxname      = "",
-            jobname      = "",
-            xmldata      = nil,
-            suffix       = "prep",
-            locations    = { '..', '../..' },
-            variables    = { },
-            messages     = { },
-            environments = { },
-            modules      = { },
-            filters      = { },
-            flags        = { },
-            modes        = { },
-            prepfiles    = { },
-            paths        = { },
-        }
-    end
+function ctxrunner.new()
+    return {
+        ctxname      = "",
+        jobname      = "",
+        xmldata      = nil,
+        suffix       = "prep",
+        locations    = { '..', '../..' },
+        variables    = { },
+        messages     = { },
+        environments = { },
+        modules      = { },
+        filters      = { },
+        flags        = { },
+        modes        = { },
+        prepfiles    = { },
+        paths        = { },
+    }
+end
 
-    function ctxrunner.savelog(ctxdata,ctlname)
-        local function yn(b)
-            if b then return 'yes' else return 'no' end
-        end
-        if not ctlname or ctlname == "" or ctlname == ctxdata.jobname then
-            if ctxdata.jobname then
-                ctlname = file.replacesuffix(ctxdata.jobname,'ctl')
-            elseif ctxdata.ctxname then
-                ctlname = file.replacesuffix(ctxdata.ctxname,'ctl')
-            else
-                report("invalid ctl name: %s",ctlname or "?")
-                return
-            end
+function ctxrunner.savelog(ctxdata,ctlname)
+    local function yn(b)
+        if b then return 'yes' else return 'no' end
+    end
+    if not ctlname or ctlname == "" or ctlname == ctxdata.jobname then
+        if ctxdata.jobname then
+            ctlname = file.replacesuffix(ctxdata.jobname,'ctl')
+        elseif ctxdata.ctxname then
+            ctlname = file.replacesuffix(ctxdata.ctxname,'ctl')
+        else
+            report("invalid ctl name: %s",ctlname or "?")
+            return
         end
-        local prepfiles = ctxdata.prepfiles
-        if prepfiles and next(prepfiles) then
-            report("saving logdata in: %s",ctlname)
-            f = io.open(ctlname,'w')
-            if f then
-                f:write("<?xml version='1.0' standalone='yes'?>\n\n")
-                f:write(format("<ctx:preplist local='%s'>\n",yn(ctxdata.runlocal)))
-                local sorted = table.sortedkeys(prepfiles)
-                for i=1,#sorted do
-                    local name = sorted[i]
-                    f:write(format("\t<ctx:prepfile done='%s'>%s</ctx:prepfile>\n",yn(prepfiles[name]),name))
-                end
-                f:write("</ctx:preplist>\n")
-                f:close()
+    end
+    local prepfiles = ctxdata.prepfiles
+    if prepfiles and next(prepfiles) then
+        report("saving logdata in: %s",ctlname)
+        f = io.open(ctlname,'w')
+        if f then
+            f:write("<?xml version='1.0' standalone='yes'?>\n\n")
+            f:write(format("<ctx:preplist local='%s'>\n",yn(ctxdata.runlocal)))
+            local sorted = table.sortedkeys(prepfiles)
+            for i=1,#sorted do
+                local name = sorted[i]
+                f:write(format("\t<ctx:prepfile done='%s'>%s</ctx:prepfile>\n",yn(prepfiles[name]),name))
             end
-        else
-            report("nothing prepared, no ctl file saved")
-            os.remove(ctlname)
+            f:write("</ctx:preplist>\n")
+            f:close()
         end
+    else
+        report("nothing prepared, no ctl file saved")
+        os.remove(ctlname)
     end
+end
 
-    function ctxrunner.register_path(ctxdata,path)
-        -- test if exists
-        ctxdata.paths[ctxdata.paths+1] = path
-    end
+function ctxrunner.register_path(ctxdata,path)
+    -- test if exists
+    ctxdata.paths[ctxdata.paths+1] = path
+end
 
-    function ctxrunner.trace(ctxdata)
-        print(table.serialize(ctxdata.messages))
-        print(table.serialize(ctxdata.flags))
-        print(table.serialize(ctxdata.environments))
-        print(table.serialize(ctxdata.modules))
-        print(table.serialize(ctxdata.filters))
-        print(table.serialize(ctxdata.modes))
-        print(xml.tostring(ctxdata.xmldata))
-    end
+function ctxrunner.trace(ctxdata)
+    print(table.serialize(ctxdata.messages))
+    print(table.serialize(ctxdata.flags))
+    print(table.serialize(ctxdata.environments))
+    print(table.serialize(ctxdata.modules))
+    print(table.serialize(ctxdata.filters))
+    print(table.serialize(ctxdata.modes))
+    print(xml.tostring(ctxdata.xmldata))
+end
 
-    function ctxrunner.manipulate(ctxdata,ctxname,defaultname)
+function ctxrunner.manipulate(ctxdata,ctxname,defaultname)
 
-        if not ctxdata.jobname or ctxdata.jobname == "" then
-            return
-        end
+    if not ctxdata.jobname or ctxdata.jobname == "" then
+        return
+    end
 
-        ctxdata.ctxname = ctxname or file.removesuffix(ctxdata.jobname) or ""
+    ctxdata.ctxname = ctxname or file.removesuffix(ctxdata.jobname) or ""
 
-        if ctxdata.ctxname == "" then
-            return
-        end
+    if ctxdata.ctxname == "" then
+        return
+    end
 
-        ctxdata.jobname = file.addsuffix(ctxdata.jobname,'tex')
-        ctxdata.ctxname = file.addsuffix(ctxdata.ctxname,'ctx')
+    ctxdata.jobname = file.addsuffix(ctxdata.jobname,'tex')
+    ctxdata.ctxname = file.addsuffix(ctxdata.ctxname,'ctx')
 
-        report("jobname: %s",ctxdata.jobname)
-        report("ctxname: %s",ctxdata.ctxname)
+    report("jobname: %s",ctxdata.jobname)
+    report("ctxname: %s",ctxdata.ctxname)
 
-        -- mtxrun should resolve kpse: and file:
+    -- mtxrun should resolve kpse: and file:
 
-        local usedname = ctxdata.ctxname
-        local found    = lfs.isfile(usedname)
+    local usedname = ctxdata.ctxname
+    local found    = lfs.isfile(usedname)
 
-        if not found then
-            for _, path in next, ctxdata.locations do
-                local fullname = file.join(path,ctxdata.ctxname)
-                if lfs.isfile(fullname) then
-                    usedname, found = fullname, true
-                    break
-                end
+    -- no futher test if qualified path
+
+    if not found then
+        for _, path in next, ctxdata.locations do
+            local fullname = file.join(path,ctxdata.ctxname)
+            if lfs.isfile(fullname) then
+                usedname, found = fullname, true
+                break
             end
         end
+    end
 
+    if not found then
         usedname = resolvers.findfile(ctxdata.ctxname,"tex")
         found = usedname ~= ""
+    end
 
-        if not found and defaultname and defaultname ~= "" and lfs.isfile(defaultname) then
-            usedname, found = defaultname, true
-        end
+    if not found and defaultname and defaultname ~= "" and lfs.isfile(defaultname) then
+        usedname, found = defaultname, true
+    end
 
-        if not found then
-            return
-        end
+    if not found then
+        return
+    end
 
-        ctxdata.xmldata = xml.load(usedname)
+    ctxdata.xmldata = xml.load(usedname)
 
-        if not ctxdata.xmldata then
-            return
-        else
-            -- test for valid, can be text file
-        end
+    if not ctxdata.xmldata then
+        return
+    else
+        -- test for valid, can be text file
+    end
 
-        xml.include(ctxdata.xmldata,'ctx:include','name', table.append({'.', file.dirname(ctxdata.ctxname)},ctxdata.locations))
+    xml.include(ctxdata.xmldata,'ctx:include','name', table.append({'.', file.dirname(ctxdata.ctxname)},ctxdata.locations))
 
-        ctxdata.variables['job'] = ctxdata.jobname
+    ctxdata.variables['job'] = ctxdata.jobname
 
-        ctxdata.flags        = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:flags/ctx:flag",true)
-        ctxdata.environments = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:environment",true)
-        ctxdata.modules      = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:module",true)
-        ctxdata.filters      = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:filter",true)
-        ctxdata.modes        = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:mode",true)
-        ctxdata.messages     = xml.collect_texts(ctxdata.xmldata,"ctx:message",true)
+    ctxdata.flags        = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:flags/ctx:flag",true)
+    ctxdata.environments = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:environment",true)
+    ctxdata.modules      = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:module",true)
+    ctxdata.filters      = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:filter",true)
+    ctxdata.modes        = xml.collect_texts(ctxdata.xmldata,"/ctx:job/ctx:process/ctx:resources/ctx:mode",true)
+    ctxdata.messages     = xml.collect_texts(ctxdata.xmldata,"ctx:message",true)
 
-        ctxdata.flags = ctxrunner.reflag(ctxdata.flags)
+    ctxdata.flags = ctxrunner.reflag(ctxdata.flags)
 
-        local messages = ctxdata.messages
-        for i=1,#messages do
-            report("ctx comment: %s", xml.tostring(messages[i]))
-        end
+    local messages = ctxdata.messages
+    for i=1,#messages do
+        report("ctx comment: %s", xml.tostring(messages[i]))
+    end
 
-        for r, d, k in xml.elements(ctxdata.xmldata,"ctx:value[@name='job']") do
-            d[k] = ctxdata.variables['job'] or ""
-        end
+    for r, d, k in xml.elements(ctxdata.xmldata,"ctx:value[@name='job']") do
+        d[k] = ctxdata.variables['job'] or ""
+    end
 
-        local commands = { }
-        for e in xml.collected(ctxdata.xmldata,"/ctx:job/ctx:preprocess/ctx:processors/ctx:processor") do
-            commands[e.at and e.at['name'] or "unknown"] = e
-        end
+    local commands = { }
+    for e in xml.collected(ctxdata.xmldata,"/ctx:job/ctx:preprocess/ctx:processors/ctx:processor") do
+        commands[e.at and e.at['name'] or "unknown"] = e
+    end
 
-        local suffix   = xml.filter(ctxdata.xmldata,"/ctx:job/ctx:preprocess/attribute('suffix')") or ctxdata.suffix
-        local runlocal = xml.filter(ctxdata.xmldata,"/ctx:job/ctx:preprocess/ctx:processors/attribute('local')")
+    local suffix   = xml.filter(ctxdata.xmldata,"/ctx:job/ctx:preprocess/attribute('suffix')") or ctxdata.suffix
+    local runlocal = xml.filter(ctxdata.xmldata,"/ctx:job/ctx:preprocess/ctx:processors/attribute('local')")
 
-        runlocal = toboolean(runlocal)
+    runlocal = toboolean(runlocal)
 
-        for files in xml.collected(ctxdata.xmldata,"/ctx:job/ctx:preprocess/ctx:files") do
-            for pattern in xml.collected(files,"ctx:file") do
+    for files in xml.collected(ctxdata.xmldata,"/ctx:job/ctx:preprocess/ctx:files") do
+        for pattern in xml.collected(files,"ctx:file") do
 
-                preprocessor = pattern.at['processor'] or ""
+            preprocessor = pattern.at['processor'] or ""
 
-                if preprocessor ~= "" then
+            if preprocessor ~= "" then
 
-                    ctxdata.variables['old'] = ctxdata.jobname
-                    for r, d, k in xml.elements(ctxdata.xmldata,"ctx:value") do
-                        local ek = d[k]
-                        local ekat = ek.at['name']
-                        if ekat == 'old' then
-                            d[k] = ctxrunner.substitute(ctxdata.variables[ekat] or "")
-                        end
+                ctxdata.variables['old'] = ctxdata.jobname
+                for r, d, k in xml.elements(ctxdata.xmldata,"ctx:value") do
+                    local ek = d[k]
+                    local ekat = ek.at['name']
+                    if ekat == 'old' then
+                        d[k] = ctxrunner.substitute(ctxdata.variables[ekat] or "")
                     end
+                end
 
-                    pattern = ctxrunner.justtext(xml.tostring(pattern))
+                pattern = ctxrunner.justtext(xml.tostring(pattern))
 
-                    local oldfiles = dir.glob(pattern)
+                local oldfiles = dir.glob(pattern)
 
-                    local pluspath = false
-                    if #oldfiles == 0 then
-                        -- message: no files match pattern
-                        local paths = ctxdata.paths
-                        for i=1,#paths do
-                            local p = paths[i]
-                            local oldfiles = dir.glob(path.join(p,pattern))
-                            if #oldfiles > 0 then
-                                pluspath = true
-                                break
-                            end
+                local pluspath = false
+                if #oldfiles == 0 then
+                    -- message: no files match pattern
+                    local paths = ctxdata.paths
+                    for i=1,#paths do
+                        local p = paths[i]
+                        local oldfiles = dir.glob(path.join(p,pattern))
+                        if #oldfiles > 0 then
+                            pluspath = true
+                            break
                         end
                     end
-                    if #oldfiles == 0 then
-                        -- message: no old files
-                    else
-                        for i=1,#oldfiles do
-                            local oldfile = oldfiles[i]
-                            local newfile = oldfile .. "." .. suffix -- addsuffix will add one only
-                            if ctxdata.runlocal then
-                                newfile = file.basename(newfile)
-                            end
-                            if oldfile ~= newfile and file.needsupdate(oldfile,newfile) then
-                            --  message: oldfile needs preprocessing
-                            --  os.remove(newfile)
-                                local splitted = preprocessor:split(',')
-                                for i=1,#splitted do
-                                    local pp = splitted[i]
-                                    local command = commands[pp]
-                                    if command then
-                                        command = xml.copy(command)
-                                        local suf = (command.at and command.at['suffix']) or ctxdata.suffix
-                                        if suf then
-                                            newfile = oldfile .. "." .. suf
-                                        end
-                                        if ctxdata.runlocal then
-                                            newfile = file.basename(newfile)
-                                        end
-                                        for r, d, k in xml.elements(command,"ctx:old") do
-                                            d[k] = ctxrunner.substitute(oldfile)
-                                        end
-                                        for r, d, k in xml.elements(command,"ctx:new") do
-                                            d[k] = ctxrunner.substitute(newfile)
-                                        end
-                                        ctxdata.variables['old'] = oldfile
-                                        ctxdata.variables['new'] = newfile
-                                        for r, d, k in xml.elements(command,"ctx:value") do
-                                            local ek = d[k]
-                                            local ekat = ek.at and ek.at['name']
-                                            if ekat then
-                                                d[k] = ctxrunner.substitute(ctxdata.variables[ekat] or "")
-                                            end
-                                        end
-                                        -- potential optimization: when mtxrun run internal
-                                        command = xml.content(command)
-                                        command = ctxrunner.justtext(command)
-                                        report("command: %s",command)
-                                        local result = os.spawn(command) or 0
-                                        -- somehow we get the wrong return value
-                                        if result > 0 then
-                                            report("error, return code: %s",result)
-                                        end
-                                        if ctxdata.runlocal then
-                                            oldfile = file.basename(oldfile)
+                end
+                if #oldfiles == 0 then
+                    -- message: no old files
+                else
+                    for i=1,#oldfiles do
+                        local oldfile = oldfiles[i]
+                        local newfile = oldfile .. "." .. suffix -- addsuffix will add one only
+                        if ctxdata.runlocal then
+                            newfile = file.basename(newfile)
+                        end
+                        if oldfile ~= newfile and file.needsupdate(oldfile,newfile) then
+                        --  message: oldfile needs preprocessing
+                        --  os.remove(newfile)
+                            local splitted = preprocessor:split(',')
+                            for i=1,#splitted do
+                                local pp = splitted[i]
+                                local command = commands[pp]
+                                if command then
+                                    command = xml.copy(command)
+                                    local suf = (command.at and command.at['suffix']) or ctxdata.suffix
+                                    if suf then
+                                        newfile = oldfile .. "." .. suf
+                                    end
+                                    if ctxdata.runlocal then
+                                        newfile = file.basename(newfile)
+                                    end
+                                    for r, d, k in xml.elements(command,"ctx:old") do
+                                        d[k] = ctxrunner.substitute(oldfile)
+                                    end
+                                    for r, d, k in xml.elements(command,"ctx:new") do
+                                        d[k] = ctxrunner.substitute(newfile)
+                                    end
+                                    ctxdata.variables['old'] = oldfile
+                                    ctxdata.variables['new'] = newfile
+                                    for r, d, k in xml.elements(command,"ctx:value") do
+                                        local ek = d[k]
+                                        local ekat = ek.at and ek.at['name']
+                                        if ekat then
+                                            d[k] = ctxrunner.substitute(ctxdata.variables[ekat] or "")
                                         end
                                     end
+                                    -- potential optimization: when mtxrun run internal
+                                    command = xml.content(command)
+                                    command = ctxrunner.justtext(command)
+                                    report("command: %s",command)
+                                    local result = os.spawn(command) or 0
+                                    -- somehow we get the wrong return value
+                                    if result > 0 then
+                                        report("error, return code: %s",result)
+                                    end
+                                    if ctxdata.runlocal then
+                                        oldfile = file.basename(oldfile)
+                                    end
                                 end
-                                if lfs.isfile(newfile) then
-                                    file.syncmtimes(oldfile,newfile)
-                                    ctxdata.prepfiles[oldfile] = true
-                                else
-                                    report("error, check target location of new file: %s", newfile)
-                                    ctxdata.prepfiles[oldfile] = false
-                                end
+                            end
+                            if lfs.isfile(newfile) then
+                                file.syncmtimes(oldfile,newfile)
+                                ctxdata.prepfiles[oldfile] = true
                             else
-                                report("old file needs no preprocessing")
-                                ctxdata.prepfiles[oldfile] = lfs.isfile(newfile)
+                                report("error, check target location of new file: %s", newfile)
+                                ctxdata.prepfiles[oldfile] = false
                             end
+                        else
+                            report("old file needs no preprocessing")
+                            ctxdata.prepfiles[oldfile] = lfs.isfile(newfile)
                         end
                     end
                 end
             end
         end
+    end
 
-        ctxrunner.savelog(ctxdata)
+    ctxrunner.savelog(ctxdata)
 
-    end
+end
 
-    function ctxrunner.preppedfile(ctxdata,filename)
-        if ctxdata.prepfiles[file.basename(filename)] then
-            return filename .. ".prep"
-        else
-            return filename
-        end
+function ctxrunner.preppedfile(ctxdata,filename)
+    if ctxdata.prepfiles[file.basename(filename)] then
+        return filename .. ".prep"
+    else
+        return filename
     end
-
 end
 
 -- rest
@@ -575,7 +575,6 @@ function scripts.context.multipass.makeoptionfile(jobname,ctxdata,kindofrun,curr
         setalways("%% styles and modules")
         --
         setalways("\\startsetups *runtime:modules")
-        setvalues("filter"       , "\\useXMLfilter[%s]", true)
         setvalues("usemodule"    , "\\usemodule[%s]", true)
         setvalues("environment"  , "\\environment %s ", true)
         if ctxdata then
@@ -875,9 +874,9 @@ function scripts.context.run(ctxdata,filename)
 --~                             end
 --~                         end
 
-local directives  = environment.directives
-local trackers    = environment.trackers
-local experiments = environment.experiments
+                        local directives  = environment.directives
+                        local trackers    = environment.trackers
+                        local experiments = environment.experiments
 
                         --
                         if type(directives) == "string" then
@@ -1214,7 +1213,7 @@ local persistent_runfiles = {
 }
 
 local special_runfiles = {
-    "-mpgraph*", "-mprun*"
+    "-mpgraph*", "-mprun*", "-temp-*"
 }
 
 local function purge_file(dfile,cfile)
@@ -1324,6 +1323,7 @@ function scripts.context.touch()
     if environment.argument("expert") then
         touchfiles("mkii")
         touchfiles("mkiv")
+        touchfiles("mkvi")
     end
 end
 
@@ -1355,7 +1355,7 @@ function scripts.context.modules(pattern)
         if not done[base] then
             done[base] = true
             local suffix = file.suffix(base)
-            if suffix == "tex" or suffix == "mkiv" then
+            if suffix == "tex" or suffix == "mkiv" or suffix == "mkvi" then
                 local prefix = match(base,"^([xmst])%-")
                 if prefix then
                     v = resolvers.findfile(base) -- so that files on my dev path are seen
diff --git a/scripts/context/lua/mtx-fonts.lua b/scripts/context/lua/mtx-fonts.lua
index 0c315bc91..795fbe891 100644
--- a/scripts/context/lua/mtx-fonts.lua
+++ b/scripts/context/lua/mtx-fonts.lua
@@ -173,7 +173,7 @@ local function showfeatures(tag,specification)
     report("subfont : %s",subfont(specification.subfont))
     report("fweight : %s",fontweight(specification.fontweight))
     -- maybe more
-    local features = fonts.get_features(specification.filename,specification.format)
+    local features = fonts.helpers.getfeatures(specification.filename,specification.format)
     if features then
         for what, v in table.sortedhash(features) do
             local data = features[what]
diff --git a/scripts/context/lua/mtx-interface.lua b/scripts/context/lua/mtx-interface.lua
index 91ae16ce3..954cb4498 100644
--- a/scripts/context/lua/mtx-interface.lua
+++ b/scripts/context/lua/mtx-interface.lua
@@ -333,7 +333,7 @@ end
 
 function scripts.interface.preprocess()
     require("luat-mac.lua")
-    local newsuffix = environment.argument("suffix") or "tex"
+    local newsuffix = environment.argument("suffix") or "log"
     local force = environment.argument("force")
     for i=1,#environment.files do
         local oldname = environment.files[i]
diff --git a/scripts/context/lua/mtx-server-ctx-fonttest.lua b/scripts/context/lua/mtx-server-ctx-fonttest.lua
index d2d41fa39..b30cf0175 100644
--- a/scripts/context/lua/mtx-server-ctx-fonttest.lua
+++ b/scripts/context/lua/mtx-server-ctx-fonttest.lua
@@ -155,12 +155,12 @@ local function showfeatures(f)
         report("processing font '%s'",f)
         local features = cache[f]
         if features == nil then
-            features = fonts.get_features(resolvers.findfile(f))
+            features = fonts.helpers.getfeatures(resolvers.findfile(f))
             if not features then
                 report("building cache for '%s'",f)
                 io.savedata(file.join(temppath,file.addsuffix(tempname,"tex")),format(process_templates.cache,f,f))
                 os.execute(format("mtxrun --path=%s --script context --once --batchmode %s",temppath,tempname))
-                features = fonts.get_features(f)
+                features = fonts.helpers.getfeatures(f)
             end
             cache[f] = features or false
             report("caching info of '%s'",f)
@@ -305,7 +305,7 @@ local function edit_font(currentfont,detail,tempname)
             local sorted = table.sortedkeys(htmldata.scripts)
             for k=1,#sorted do
                 local v = sorted[k]
-                local s = fonts.otf.tables.scripts[v] or v
+                local s = fonts.handlers.otf.tables.scripts[v] or v
                 if detail and v == detail.script then
                     scripts[#scripts+1] = format("<input title='%s' id='s-%s' type='radio' name='script' value='%s' onclick='check_script()' checked='checked'/>&nbsp;<span id='t-s-%s'>%s</span>",s,v,v,v,v)
                 else
@@ -315,7 +315,7 @@ local function edit_font(currentfont,detail,tempname)
             local sorted = table.sortedkeys(htmldata.languages)
             for k=1,#sorted do
                 local v = sorted[k]
-                local l = fonts.otf.tables.languages[v] or v
+                local l = fonts.handlers.otf.tables.languages[v] or v
                 if detail and v == detail.language then
                     languages[#languages+1] = format("<input title='%s' id='l-%s' type='radio' name='language' value='%s' onclick='check_language()' checked='checked'/>&nbsp;<span id='t-l-%s'>%s</span>",l,v,v,v,v)
                 else
@@ -325,7 +325,7 @@ local function edit_font(currentfont,detail,tempname)
             local sorted = table.sortedkeys(htmldata.features)
             for k=1,#sorted do
                 local v = sorted[k]
-                local f = fonts.otf.tables.features[v] or v
+                local f = fonts.handlers.otf.tables.features[v] or v
                 if detail and detail["f-"..v] then
                     features[#features+1] = format("<input title='%s' id='f-%s' type='checkbox' name='f-%s' onclick='check_feature()' checked='checked'/>&nbsp;<span id='t-f-%s'>%s</span>",f,v,v,v,v)
                 else
@@ -408,7 +408,7 @@ end
 
 local function show_font(currentfont,detail)
     local specification = get_specification(currentfont)
-    local features = fonts.get_features(specification.filename)
+    local features = fonts.helpers.getfeatures(specification.filename)
     local result = { }
     result[#result+1] = format("<h1>names</h1>",what)
     result[#result+1] = "<table>"
@@ -446,7 +446,7 @@ local function show_font(currentfont,detail)
                         else
                             done = true
                         end
-                        local title = fonts.otf.tables.features[f] or ""
+                        local title = fonts.handlers.otf.tables.features[f] or ""
                         result[#result+1] = format("<tr><td width='50%%'>%s&nbsp;&nbsp;</td><td><tt>%s&nbsp;&nbsp;</tt></td><td><tt>%s&nbsp;&nbsp;</tt></td><td><tt>%s&nbsp;&nbsp;</tt></td></tr>",title,f,s,concat(table.sortedkeys(ss)," "))
                     end
                 end
diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua
index 0d9e071fe..38412f1e1 100644
--- a/scripts/context/lua/mtxrun.lua
+++ b/scripts/context/lua/mtxrun.lua
@@ -658,6 +658,7 @@ function lpeg.is_lpeg(p)
 end
 
 
+
 end -- of closure
 
 do -- create closure to overcome 200 locals limit
@@ -757,24 +758,24 @@ local function compare(a,b)
 end
 
 local function sortedkeys(tab)
-    local srt, kind, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
+    local srt, category, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
     for key,_ in next, tab do
         s = s + 1
         srt[s] = key
-        if kind == 3 then
+        if category == 3 then
             -- no further check
         else
             local tkey = type(key)
             if tkey == "string" then
-                kind = (kind == 2 and 3) or 1
+                category = (category == 2 and 3) or 1
             elseif tkey == "number" then
-                kind = (kind == 1 and 3) or 2
+                category = (category == 1 and 3) or 2
             else
-                kind = 3
+                category = 3
             end
         end
     end
-    if kind == 0 or kind == 3 then
+    if category == 0 or category == 3 then
         sort(srt,compare)
     else
         sort(srt)
@@ -940,6 +941,13 @@ end
 table.fastcopy = fastcopy
 table.copy     = copy
 
+function table.derive(parent)
+    local child = { }
+    if parent then
+        setmetatable(child,{ __index = parent })
+    end
+    return child
+end
 
 function table.tohash(t,value)
     local h = { }
@@ -3640,7 +3648,7 @@ local tables     = utilities.tables
 
 local format, gmatch = string.format, string.gmatch
 local concat, insert, remove = table.concat, table.insert, table.remove
-local setmetatable = setmetatable
+local setmetatable, tonumber, tostring = setmetatable, tonumber, tostring
 
 function tables.definetable(target) -- defines undefined tables
     local composed, t, n = nil, { }, 0
@@ -3711,6 +3719,28 @@ function table.setemptymetatable(t)
     setmetatable(t,_empty_table_)
 end
 
+-- experimental
+
+local function toxml(t,d,result)
+    for k, v in table.sortedpairs(t) do
+        if type(v) == "table" then
+            result[#result+1] = format("%s<%s>",d,k)
+            toxml(v,d.." ",result)
+            result[#result+1] = format("%s</%s>",d,k)
+        elseif tonumber(k) then
+            result[#result+1] = format("%s<entry n='%s'>%s</entry>",d,k,v,k)
+        else
+            result[#result+1] = format("%s<%s>%s</%s>",d,k,tostring(v),k)
+        end
+    end
+end
+
+function table.toxml(t,name)
+    local result = { "<?xml version='1.0' standalone='yes' ?>" }
+    toxml( { [name or "root"] = t }, "", result)
+    return concat(result,"\n")
+end
+
 
 end -- of closure
 
@@ -3823,13 +3853,13 @@ local gsub, format = string.gsub, string.format
 local concat = table.concat
 local type, next = type, next
 
-utilities        = utilities or {}
-utilities.merger = utilities.merger or { } -- maybe mergers
-utilities.report = logs and logs.reporter("system") or print
+utilities             = utilities or {}
+utilities.merger      = utilities.merger or { } -- maybe mergers
+utilities.report      = logs and logs.reporter("system") or print
 
-local merger     = utilities.merger
+local merger          = utilities.merger
 
-merger.strip_comment = true
+merger.strip_comment  = true
 
 local m_begin_merge   = "begin library merge"
 local m_end_merge     = "end library merge"
@@ -4171,7 +4201,8 @@ end
 
 function parsers.settings_to_set(str,t) -- tohash? -- todo: lpeg -- duplicate anyway
     t = t or { }
-    for s in gmatch(str,"%s*([^, ]+)") do -- space added
+--  for s in gmatch(str,"%s*([^, ]+)") do -- space added
+    for s in gmatch(str,"[^, ]+") do -- space added
         t[s] = true
     end
     return t
@@ -4214,6 +4245,10 @@ function parsers.getparameters(self,class,parentclass,settings)
     parsers.settings_to_hash(settings,sc)
 end
 
+function parsers.listitem(str)
+    return gmatch(str,"[^, ]+")
+end
+
 
 end -- of closure
 
@@ -11108,8 +11143,8 @@ local function load_configuration_files()
                     local variables = data.variables or { }
                     local warning = false
                     for k, v in next, data do
-                        local kind = type(v)
-                        if kind == "table" then
+                        local variant = type(v)
+                        if variant == "table" then
                             initializesetter(filename,k,v)
                         elseif variables[k] == nil then
                             if trace_locating and not warning then
@@ -11381,7 +11416,7 @@ function resolvers.registerextrapath(paths,subpaths)
             end
         end
     elseif subpaths and subpaths ~= "" then
-        for i=1,n do
+        for i=1,oldn do
             -- we gmatch each step again, not that fast, but used seldom
             for s in gmatch(subpaths,"[^,]+") do
                 local ps = ep[i] .. "/" .. s
@@ -11550,29 +11585,29 @@ local function collect_files(names)
                     local blobroot = files.__path__ or blobpath
                     if type(blobfile) == 'string' then
                         if not dname or find(blobfile,dname) then
-                            local kind   = hash.type
-                         -- local search = filejoin(blobpath,blobfile,bname)
-                            local search = filejoin(blobroot,blobfile,bname)
-                            local result = methodhandler('concatinators',hash.type,blobroot,blobfile,bname)
+                            local variant = hash.type
+                         -- local search  = filejoin(blobpath,blobfile,bname)
+                            local search  = filejoin(blobroot,blobfile,bname)
+                            local result  = methodhandler('concatinators',hash.type,blobroot,blobfile,bname)
                             if trace_detail then
-                                report_resolving("match: kind '%s', search '%s', result '%s'",kind,search,result)
+                                report_resolving("match: variant '%s', search '%s', result '%s'",variant,search,result)
                             end
                             noffiles = noffiles + 1
-                            filelist[noffiles] = { kind, search, result }
+                            filelist[noffiles] = { variant, search, result }
                         end
                     else
                         for kk=1,#blobfile do
                             local vv = blobfile[kk]
                             if not dname or find(vv,dname) then
-                                local kind   = hash.type
-                             -- local search = filejoin(blobpath,vv,bname)
-                                local search = filejoin(blobroot,vv,bname)
-                                local result = methodhandler('concatinators',hash.type,blobroot,vv,bname)
+                                local variant = hash.type
+                             -- local search  = filejoin(blobpath,vv,bname)
+                                local search  = filejoin(blobroot,vv,bname)
+                                local result  = methodhandler('concatinators',hash.type,blobroot,vv,bname)
                                 if trace_detail then
-                                    report_resolving("match: kind '%s', search '%s', result '%s'",kind,search,result)
+                                    report_resolving("match: variant '%s', search '%s', result '%s'",variant,search,result)
                                 end
                                 noffiles = noffiles + 1
-                                filelist[noffiles] = { kind, search, result }
+                                filelist[noffiles] = { variant, search, result }
                             end
                         end
                     end
@@ -11950,14 +11985,14 @@ function resolvers.findgivenfile(filename)
     return findgivenfiles(filename,false)[1] or ""
 end
 
-local function doit(path,blist,bname,tag,kind,result,allresults)
+local function doit(path,blist,bname,tag,variant,result,allresults)
     local done = false
-    if blist and kind then
+    if blist and variant then
         local resolve = resolvers.resolve -- added
         if type(blist) == 'string' then
             -- make function and share code
             if find(lower(blist),path) then
-                local full = methodhandler('concatinators',kind,tag,blist,bname) or ""
+                local full = methodhandler('concatinators',variant,tag,blist,bname) or ""
                 result[#result+1] = resolve(full)
                 done = true
             end
@@ -11965,7 +12000,7 @@ local function doit(path,blist,bname,tag,kind,result,allresults)
             for kk=1,#blist do
                 local vv = blist[kk]
                 if find(lower(vv),path) then
-                    local full = methodhandler('concatinators',kind,tag,vv,bname) or ""
+                    local full = methodhandler('concatinators',variant,tag,vv,bname) or ""
                     result[#result+1] = resolve(full)
                     done = true
                     if not allresults then break end
diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua
index 0d9e071fe..38412f1e1 100644
--- a/scripts/context/stubs/mswin/mtxrun.lua
+++ b/scripts/context/stubs/mswin/mtxrun.lua
@@ -658,6 +658,7 @@ function lpeg.is_lpeg(p)
 end
 
 
+
 end -- of closure
 
 do -- create closure to overcome 200 locals limit
@@ -757,24 +758,24 @@ local function compare(a,b)
 end
 
 local function sortedkeys(tab)
-    local srt, kind, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
+    local srt, category, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
     for key,_ in next, tab do
         s = s + 1
         srt[s] = key
-        if kind == 3 then
+        if category == 3 then
             -- no further check
         else
             local tkey = type(key)
             if tkey == "string" then
-                kind = (kind == 2 and 3) or 1
+                category = (category == 2 and 3) or 1
             elseif tkey == "number" then
-                kind = (kind == 1 and 3) or 2
+                category = (category == 1 and 3) or 2
             else
-                kind = 3
+                category = 3
             end
         end
     end
-    if kind == 0 or kind == 3 then
+    if category == 0 or category == 3 then
         sort(srt,compare)
     else
         sort(srt)
@@ -940,6 +941,13 @@ end
 table.fastcopy = fastcopy
 table.copy     = copy
 
+function table.derive(parent)
+    local child = { }
+    if parent then
+        setmetatable(child,{ __index = parent })
+    end
+    return child
+end
 
 function table.tohash(t,value)
     local h = { }
@@ -3640,7 +3648,7 @@ local tables     = utilities.tables
 
 local format, gmatch = string.format, string.gmatch
 local concat, insert, remove = table.concat, table.insert, table.remove
-local setmetatable = setmetatable
+local setmetatable, tonumber, tostring = setmetatable, tonumber, tostring
 
 function tables.definetable(target) -- defines undefined tables
     local composed, t, n = nil, { }, 0
@@ -3711,6 +3719,28 @@ function table.setemptymetatable(t)
     setmetatable(t,_empty_table_)
 end
 
+-- experimental
+
+local function toxml(t,d,result)
+    for k, v in table.sortedpairs(t) do
+        if type(v) == "table" then
+            result[#result+1] = format("%s<%s>",d,k)
+            toxml(v,d.." ",result)
+            result[#result+1] = format("%s</%s>",d,k)
+        elseif tonumber(k) then
+            result[#result+1] = format("%s<entry n='%s'>%s</entry>",d,k,v,k)
+        else
+            result[#result+1] = format("%s<%s>%s</%s>",d,k,tostring(v),k)
+        end
+    end
+end
+
+function table.toxml(t,name)
+    local result = { "<?xml version='1.0' standalone='yes' ?>" }
+    toxml( { [name or "root"] = t }, "", result)
+    return concat(result,"\n")
+end
+
 
 end -- of closure
 
@@ -3823,13 +3853,13 @@ local gsub, format = string.gsub, string.format
 local concat = table.concat
 local type, next = type, next
 
-utilities        = utilities or {}
-utilities.merger = utilities.merger or { } -- maybe mergers
-utilities.report = logs and logs.reporter("system") or print
+utilities             = utilities or {}
+utilities.merger      = utilities.merger or { } -- maybe mergers
+utilities.report      = logs and logs.reporter("system") or print
 
-local merger     = utilities.merger
+local merger          = utilities.merger
 
-merger.strip_comment = true
+merger.strip_comment  = true
 
 local m_begin_merge   = "begin library merge"
 local m_end_merge     = "end library merge"
@@ -4171,7 +4201,8 @@ end
 
 function parsers.settings_to_set(str,t) -- tohash? -- todo: lpeg -- duplicate anyway
     t = t or { }
-    for s in gmatch(str,"%s*([^, ]+)") do -- space added
+--  for s in gmatch(str,"%s*([^, ]+)") do -- space added
+    for s in gmatch(str,"[^, ]+") do -- space added
         t[s] = true
     end
     return t
@@ -4214,6 +4245,10 @@ function parsers.getparameters(self,class,parentclass,settings)
     parsers.settings_to_hash(settings,sc)
 end
 
+function parsers.listitem(str)
+    return gmatch(str,"[^, ]+")
+end
+
 
 end -- of closure
 
@@ -11108,8 +11143,8 @@ local function load_configuration_files()
                     local variables = data.variables or { }
                     local warning = false
                     for k, v in next, data do
-                        local kind = type(v)
-                        if kind == "table" then
+                        local variant = type(v)
+                        if variant == "table" then
                             initializesetter(filename,k,v)
                         elseif variables[k] == nil then
                             if trace_locating and not warning then
@@ -11381,7 +11416,7 @@ function resolvers.registerextrapath(paths,subpaths)
             end
         end
     elseif subpaths and subpaths ~= "" then
-        for i=1,n do
+        for i=1,oldn do
             -- we gmatch each step again, not that fast, but used seldom
             for s in gmatch(subpaths,"[^,]+") do
                 local ps = ep[i] .. "/" .. s
@@ -11550,29 +11585,29 @@ local function collect_files(names)
                     local blobroot = files.__path__ or blobpath
                     if type(blobfile) == 'string' then
                         if not dname or find(blobfile,dname) then
-                            local kind   = hash.type
-                         -- local search = filejoin(blobpath,blobfile,bname)
-                            local search = filejoin(blobroot,blobfile,bname)
-                            local result = methodhandler('concatinators',hash.type,blobroot,blobfile,bname)
+                            local variant = hash.type
+                         -- local search  = filejoin(blobpath,blobfile,bname)
+                            local search  = filejoin(blobroot,blobfile,bname)
+                            local result  = methodhandler('concatinators',hash.type,blobroot,blobfile,bname)
                             if trace_detail then
-                                report_resolving("match: kind '%s', search '%s', result '%s'",kind,search,result)
+                                report_resolving("match: variant '%s', search '%s', result '%s'",variant,search,result)
                             end
                             noffiles = noffiles + 1
-                            filelist[noffiles] = { kind, search, result }
+                            filelist[noffiles] = { variant, search, result }
                         end
                     else
                         for kk=1,#blobfile do
                             local vv = blobfile[kk]
                             if not dname or find(vv,dname) then
-                                local kind   = hash.type
-                             -- local search = filejoin(blobpath,vv,bname)
-                                local search = filejoin(blobroot,vv,bname)
-                                local result = methodhandler('concatinators',hash.type,blobroot,vv,bname)
+                                local variant = hash.type
+                             -- local search  = filejoin(blobpath,vv,bname)
+                                local search  = filejoin(blobroot,vv,bname)
+                                local result  = methodhandler('concatinators',hash.type,blobroot,vv,bname)
                                 if trace_detail then
-                                    report_resolving("match: kind '%s', search '%s', result '%s'",kind,search,result)
+                                    report_resolving("match: variant '%s', search '%s', result '%s'",variant,search,result)
                                 end
                                 noffiles = noffiles + 1
-                                filelist[noffiles] = { kind, search, result }
+                                filelist[noffiles] = { variant, search, result }
                             end
                         end
                     end
@@ -11950,14 +11985,14 @@ function resolvers.findgivenfile(filename)
     return findgivenfiles(filename,false)[1] or ""
 end
 
-local function doit(path,blist,bname,tag,kind,result,allresults)
+local function doit(path,blist,bname,tag,variant,result,allresults)
     local done = false
-    if blist and kind then
+    if blist and variant then
         local resolve = resolvers.resolve -- added
         if type(blist) == 'string' then
             -- make function and share code
             if find(lower(blist),path) then
-                local full = methodhandler('concatinators',kind,tag,blist,bname) or ""
+                local full = methodhandler('concatinators',variant,tag,blist,bname) or ""
                 result[#result+1] = resolve(full)
                 done = true
             end
@@ -11965,7 +12000,7 @@ local function doit(path,blist,bname,tag,kind,result,allresults)
             for kk=1,#blist do
                 local vv = blist[kk]
                 if find(lower(vv),path) then
-                    local full = methodhandler('concatinators',kind,tag,vv,bname) or ""
+                    local full = methodhandler('concatinators',variant,tag,vv,bname) or ""
                     result[#result+1] = resolve(full)
                     done = true
                     if not allresults then break end
diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun
index 0d9e071fe..38412f1e1 100755
--- a/scripts/context/stubs/unix/mtxrun
+++ b/scripts/context/stubs/unix/mtxrun
@@ -658,6 +658,7 @@ function lpeg.is_lpeg(p)
 end
 
 
+
 end -- of closure
 
 do -- create closure to overcome 200 locals limit
@@ -757,24 +758,24 @@ local function compare(a,b)
 end
 
 local function sortedkeys(tab)
-    local srt, kind, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
+    local srt, category, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed
     for key,_ in next, tab do
         s = s + 1
         srt[s] = key
-        if kind == 3 then
+        if category == 3 then
             -- no further check
         else
             local tkey = type(key)
             if tkey == "string" then
-                kind = (kind == 2 and 3) or 1
+                category = (category == 2 and 3) or 1
             elseif tkey == "number" then
-                kind = (kind == 1 and 3) or 2
+                category = (category == 1 and 3) or 2
             else
-                kind = 3
+                category = 3
             end
         end
     end
-    if kind == 0 or kind == 3 then
+    if category == 0 or category == 3 then
         sort(srt,compare)
     else
         sort(srt)
@@ -940,6 +941,13 @@ end
 table.fastcopy = fastcopy
 table.copy     = copy
 
+function table.derive(parent)
+    local child = { }
+    if parent then
+        setmetatable(child,{ __index = parent })
+    end
+    return child
+end
 
 function table.tohash(t,value)
     local h = { }
@@ -3640,7 +3648,7 @@ local tables     = utilities.tables
 
 local format, gmatch = string.format, string.gmatch
 local concat, insert, remove = table.concat, table.insert, table.remove
-local setmetatable = setmetatable
+local setmetatable, tonumber, tostring = setmetatable, tonumber, tostring
 
 function tables.definetable(target) -- defines undefined tables
     local composed, t, n = nil, { }, 0
@@ -3711,6 +3719,28 @@ function table.setemptymetatable(t)
     setmetatable(t,_empty_table_)
 end
 
+-- experimental
+
+local function toxml(t,d,result)
+    for k, v in table.sortedpairs(t) do
+        if type(v) == "table" then
+            result[#result+1] = format("%s<%s>",d,k)
+            toxml(v,d.." ",result)
+            result[#result+1] = format("%s</%s>",d,k)
+        elseif tonumber(k) then
+            result[#result+1] = format("%s<entry n='%s'>%s</entry>",d,k,v,k)
+        else
+            result[#result+1] = format("%s<%s>%s</%s>",d,k,tostring(v),k)
+        end
+    end
+end
+
+function table.toxml(t,name)
+    local result = { "<?xml version='1.0' standalone='yes' ?>" }
+    toxml( { [name or "root"] = t }, "", result)
+    return concat(result,"\n")
+end
+
 
 end -- of closure
 
@@ -3823,13 +3853,13 @@ local gsub, format = string.gsub, string.format
 local concat = table.concat
 local type, next = type, next
 
-utilities        = utilities or {}
-utilities.merger = utilities.merger or { } -- maybe mergers
-utilities.report = logs and logs.reporter("system") or print
+utilities             = utilities or {}
+utilities.merger      = utilities.merger or { } -- maybe mergers
+utilities.report      = logs and logs.reporter("system") or print
 
-local merger     = utilities.merger
+local merger          = utilities.merger
 
-merger.strip_comment = true
+merger.strip_comment  = true
 
 local m_begin_merge   = "begin library merge"
 local m_end_merge     = "end library merge"
@@ -4171,7 +4201,8 @@ end
 
 function parsers.settings_to_set(str,t) -- tohash? -- todo: lpeg -- duplicate anyway
     t = t or { }
-    for s in gmatch(str,"%s*([^, ]+)") do -- space added
+--  for s in gmatch(str,"%s*([^, ]+)") do -- space added
+    for s in gmatch(str,"[^, ]+") do -- space added
         t[s] = true
     end
     return t
@@ -4214,6 +4245,10 @@ function parsers.getparameters(self,class,parentclass,settings)
     parsers.settings_to_hash(settings,sc)
 end
 
+function parsers.listitem(str)
+    return gmatch(str,"[^, ]+")
+end
+
 
 end -- of closure
 
@@ -11108,8 +11143,8 @@ local function load_configuration_files()
                     local variables = data.variables or { }
                     local warning = false
                     for k, v in next, data do
-                        local kind = type(v)
-                        if kind == "table" then
+                        local variant = type(v)
+                        if variant == "table" then
                             initializesetter(filename,k,v)
                         elseif variables[k] == nil then
                             if trace_locating and not warning then
@@ -11381,7 +11416,7 @@ function resolvers.registerextrapath(paths,subpaths)
             end
         end
     elseif subpaths and subpaths ~= "" then
-        for i=1,n do
+        for i=1,oldn do
             -- we gmatch each step again, not that fast, but used seldom
             for s in gmatch(subpaths,"[^,]+") do
                 local ps = ep[i] .. "/" .. s
@@ -11550,29 +11585,29 @@ local function collect_files(names)
                     local blobroot = files.__path__ or blobpath
                     if type(blobfile) == 'string' then
                         if not dname or find(blobfile,dname) then
-                            local kind   = hash.type
-                         -- local search = filejoin(blobpath,blobfile,bname)
-                            local search = filejoin(blobroot,blobfile,bname)
-                            local result = methodhandler('concatinators',hash.type,blobroot,blobfile,bname)
+                            local variant = hash.type
+                         -- local search  = filejoin(blobpath,blobfile,bname)
+                            local search  = filejoin(blobroot,blobfile,bname)
+                            local result  = methodhandler('concatinators',hash.type,blobroot,blobfile,bname)
                             if trace_detail then
-                                report_resolving("match: kind '%s', search '%s', result '%s'",kind,search,result)
+                                report_resolving("match: variant '%s', search '%s', result '%s'",variant,search,result)
                             end
                             noffiles = noffiles + 1
-                            filelist[noffiles] = { kind, search, result }
+                            filelist[noffiles] = { variant, search, result }
                         end
                     else
                         for kk=1,#blobfile do
                             local vv = blobfile[kk]
                             if not dname or find(vv,dname) then
-                                local kind   = hash.type
-                             -- local search = filejoin(blobpath,vv,bname)
-                                local search = filejoin(blobroot,vv,bname)
-                                local result = methodhandler('concatinators',hash.type,blobroot,vv,bname)
+                                local variant = hash.type
+                             -- local search  = filejoin(blobpath,vv,bname)
+                                local search  = filejoin(blobroot,vv,bname)
+                                local result  = methodhandler('concatinators',hash.type,blobroot,vv,bname)
                                 if trace_detail then
-                                    report_resolving("match: kind '%s', search '%s', result '%s'",kind,search,result)
+                                    report_resolving("match: variant '%s', search '%s', result '%s'",variant,search,result)
                                 end
                                 noffiles = noffiles + 1
-                                filelist[noffiles] = { kind, search, result }
+                                filelist[noffiles] = { variant, search, result }
                             end
                         end
                     end
@@ -11950,14 +11985,14 @@ function resolvers.findgivenfile(filename)
     return findgivenfiles(filename,false)[1] or ""
 end
 
-local function doit(path,blist,bname,tag,kind,result,allresults)
+local function doit(path,blist,bname,tag,variant,result,allresults)
     local done = false
-    if blist and kind then
+    if blist and variant then
         local resolve = resolvers.resolve -- added
         if type(blist) == 'string' then
             -- make function and share code
             if find(lower(blist),path) then
-                local full = methodhandler('concatinators',kind,tag,blist,bname) or ""
+                local full = methodhandler('concatinators',variant,tag,blist,bname) or ""
                 result[#result+1] = resolve(full)
                 done = true
             end
@@ -11965,7 +12000,7 @@ local function doit(path,blist,bname,tag,kind,result,allresults)
             for kk=1,#blist do
                 local vv = blist[kk]
                 if find(lower(vv),path) then
-                    local full = methodhandler('concatinators',kind,tag,vv,bname) or ""
+                    local full = methodhandler('concatinators',variant,tag,vv,bname) or ""
                     result[#result+1] = resolve(full)
                     done = true
                     if not allresults then break end
-- 
cgit v1.2.3