File texmf-luatools.dif of Package texlive

--- texmf-dist/scripts/context/lua/luatools.lua
+++ texmf-dist/scripts/context/lua/luatools.lua	2008-10-30 14:05:11.270545206 +0100
@@ -3,19 +3,21 @@
 -- one can make a stub:
 --
 -- #!/bin/sh
--- env LUATEXDIR=/....../texmf/scripts/context/lua luatex --luaonly=luatools.lua "$@"
+-- env LUATEXDIR=/....../texmf/scripts/context/lua texlua luatools.lua "$@"
+
 -- filename : luatools.lua
 -- comment  : companion to context.tex
 -- author   : Hans Hagen, PRAGMA-ADE, Hasselt NL
 -- copyright: PRAGMA ADE / ConTeXt Development Team
 -- license  : see context related readme files
+
 -- Although this script is part of the ConTeXt distribution it is
 -- relatively indepent of ConTeXt.  The same is true for some of
 -- the luat files. We may may make them even less dependent in
 -- the future. As long as Luatex is under development the
 -- interfaces and names of functions may change.
 
-banner = "version 1.2.0 - 2006+ - PRAGMA ADE / CONTEXT"
+banner = "version 1.2.2 - 2006+ - PRAGMA ADE / CONTEXT"
 texlua = true
 
 -- For the sake of independence we optionally can merge the library
@@ -111,7 +113,7 @@ end
 function string:splitchr(chr)
     if #self > 0 then
         local t = { }
-        for s in string.gmatch(self..chr,"(.-)"..chr) do
+        for s in (self..chr):gmatch("(.-)"..chr) do
             t[#t+1] = s
         end
         return t
@@ -120,22 +122,6 @@ function string:splitchr(chr)
     end
 end
 
---~ function string.piecewise(str, pat, fnc) -- variant of split
---~     local fpat = "(.-)"..pat
---~     local last_end = 1
---~     local s, e, cap = string.find(str, fpat, 1)
---~     while s ~= nil do
---~         if s~=1 or cap~="" then
---~             fnc(cap)
---~         end
---~         last_end = e+1
---~         s, e, cap = string.find(str, fpat, last_end)
---~     end
---~     if last_end <= #str then
---~         fnc((string.sub(str,last_end)))
---~     end
---~ end
-
 function string.piecewise(str, pat, fnc) -- variant of split
     for k in string.splitter(str,pat) do fnc(k) end
 end
@@ -177,7 +163,7 @@ end
 
 --~ end end
 
-string.chr_to_esc = {
+local chr_to_esc = {
     ["%"] = "%%",
     ["."] = "%.",
     ["+"] = "%+", ["-"] = "%-", ["*"] = "%*",
@@ -187,16 +173,18 @@ string.chr_to_esc = {
     ["{"] = "%{", ["}"] = "%}"
 }
 
+string.chr_to_esc = chr_to_esc
+
 function string:esc() -- variant 2
-    return (self:gsub("(.)",string.chr_to_esc))
+    return (self:gsub("(.)",chr_to_esc))
 end
 
-function string.unquote(str)
-    return (str:gsub("^([\"\'])(.*)%1$","%2"))
+function string:unquote()
+    return (self:gsub("^([\"\'])(.*)%1$","%2"))
 end
 
-function string.quote(str)
-    return '"' .. str:unquote() .. '"'
+function string:quote()
+    return '"' .. self:unquote() .. '"'
 end
 
 function string:count(pattern) -- variant 3
@@ -446,6 +434,30 @@ function string:splitlines()
     return capture:match(self)
 end
 
+--~ local p = lpeg.splitat("->",false)  print(p:match("oeps->what->more"))  -- oeps what more
+--~ local p = lpeg.splitat("->",true)   print(p:match("oeps->what->more"))  -- oeps what->more
+--~ local p = lpeg.splitat("->",false)  print(p:match("oeps"))              -- oeps
+--~ local p = lpeg.splitat("->",true)   print(p:match("oeps"))              -- oeps
+
+local splitters_s, splitters_m = { }, { }
+
+function lpeg.splitat(separator,single)
+    local splitter = (single and splitters_s[separator]) or splitters_m[separator]
+    if not splitter then
+        separator = lpeg.P(separator)
+        if single then
+            local other, any = lpeg.C((1 - separator)^0), lpeg.P(1)
+            splitter = other * (separator * lpeg.C(any^0) + "")
+            splitters_s[separator] = splitter
+        else
+            local other = lpeg.C((1 - separator)^0)
+            splitter = other * (separator * other)^0
+            splitters_m[separator] = splitter
+        end
+    end
+    return splitter
+end
+
 
 -- filename : l-table.lua
 -- comment  : split off from luat-lib
@@ -457,11 +469,15 @@ if not versions then versions = { } end 
 
 table.join = table.concat
 
+local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove
+local format = string.format
+local getmetatable, setmetatable = getmetatable, setmetatable
+local pairs, ipairs, type, next, tostring = pairs, ipairs, type, next, tostring
+
 function table.strip(tab)
     local lst = { }
-    for k, v in ipairs(tab) do
-     -- s = string.gsub(v, "^%s*(.-)%s*$", "%1")
-        s = v:gsub("^%s*(.-)%s*$", "%1")
+    for i=1,#tab do
+        local s = tab[i]:gsub("^%s*(.-)%s*$","%1")
         if s == "" then
             -- skip this one
         else
@@ -471,16 +487,7 @@ function table.strip(tab)
     return lst
 end
 
---~ function table.sortedkeys(tab)
---~     local srt = { }
---~     for key,_ in pairs(tab) do
---~         srt[#srt+1] = key
---~     end
---~     table.sort(srt)
---~     return srt
---~ end
-
-function table.sortedkeys(tab)
+local function sortedkeys(tab)
     local srt, kind = { }, 0 -- 0=unknown 1=string, 2=number 3=mixed
     for key,_ in pairs(tab) do
         srt[#srt+1] = key
@@ -500,22 +507,34 @@ function table.sortedkeys(tab)
         end
     end
     if kind == 0 or kind == 3 then
-        table.sort(srt,function(a,b) return (tostring(a) < tostring(b)) end)
+        sort(srt,function(a,b) return (tostring(a) < tostring(b)) end)
     else
-        table.sort(srt)
+        sort(srt)
+    end
+    return srt
+end
+
+local function sortedhashkeys(tab) -- fast one
+    local srt = { }
+    for key,_ in pairs(tab) do
+        srt[#srt+1] = key
     end
+    sort(srt)
     return srt
 end
 
+table.sortedkeys     = sortedkeys
+table.sortedhashkeys = sortedhashkeys
+
 function table.append(t, list)
     for _,v in pairs(list) do
-        table.insert(t,v)
+        insert(t,v)
     end
 end
 
 function table.prepend(t, list)
     for k,v in pairs(list) do
-        table.insert(t,k,v)
+        insert(t,k,v)
     end
 end
 
@@ -562,70 +581,57 @@ function table.imerged(...)
     return tmp
 end
 
-if not table.fastcopy then do
-
-    local type, pairs, getmetatable, setmetatable = type, pairs, getmetatable, setmetatable
-
-    local function fastcopy(old) -- fast one
-        if old then
-            local new = { }
-            for k,v in pairs(old) do
-                if type(v) == "table" then
-                    new[k] = fastcopy(v) -- was just table.copy
-                else
-                    new[k] = v
-                end
-            end
-            local mt = getmetatable(old)
-            if mt then
-                setmetatable(new,mt)
+local function fastcopy(old) -- fast one
+    if old then
+        local new = { }
+        for k,v in pairs(old) do
+            if type(v) == "table" then
+                new[k] = fastcopy(v) -- was just table.copy
+            else
+                new[k] = v
             end
-            return new
-        else
-            return { }
         end
+        local mt = getmetatable(old)
+        if mt then
+            setmetatable(new,mt)
+        end
+        return new
+    else
+        return { }
     end
+end
 
-    table.fastcopy = fastcopy
-
-end end
-
-if not table.copy then do
-
-    local type, pairs, getmetatable, setmetatable = type, pairs, getmetatable, setmetatable
-
-    local function copy(t, tables) -- taken from lua wiki, slightly adapted
-        tables = tables or { }
-        local tcopy = {}
-        if not tables[t] then
-            tables[t] = tcopy
-        end
-        for i,v in pairs(t) do -- brrr, what happens with sparse indexed
-            if type(i) == "table" then
-                if tables[i] then
-                    i = tables[i]
-                else
-                    i = copy(i, tables)
-                end
-            end
-            if type(v) ~= "table" then
-                tcopy[i] = v
-            elseif tables[v] then
-                tcopy[i] = tables[v]
+local function copy(t, tables) -- taken from lua wiki, slightly adapted
+    tables = tables or { }
+    local tcopy = {}
+    if not tables[t] then
+        tables[t] = tcopy
+    end
+    for i,v in pairs(t) do -- brrr, what happens with sparse indexed
+        if type(i) == "table" then
+            if tables[i] then
+                i = tables[i]
             else
-                tcopy[i] = copy(v, tables)
+                i = copy(i, tables)
             end
         end
-        local mt = getmetatable(t)
-        if mt then
-            setmetatable(tcopy,mt)
+        if type(v) ~= "table" then
+            tcopy[i] = v
+        elseif tables[v] then
+            tcopy[i] = tables[v]
+        else
+            tcopy[i] = copy(v, tables)
         end
-        return tcopy
     end
+    local mt = getmetatable(t)
+    if mt then
+        setmetatable(tcopy,mt)
+    end
+    return tcopy
+end
 
-    table.copy = copy
-
-end end
+table.fastcopy = fastcopy
+table.copy     = copy
 
 -- rougly: copy-loop : unpack : sub == 0.9 : 0.4 : 0.45 (so in critical apps, use unpack)
 
@@ -654,334 +660,363 @@ function table.starts_at(t)
     return ipairs(t,1)(t,0)
 end
 
-do
+function table.tohash(t,value)
+    local h = { }
+    if value == nil then value = true end
+    for _, v in pairs(t) do -- no ipairs here
+        h[v] = value
+    end
+    return h
+end
+
+function table.fromhash(t)
+    local h = { }
+    for k, v in pairs(t) do -- no ipairs here
+        if v then h[#h+1] = k end
+    end
+    return h
+end
 
-    -- one of my first exercises in lua ...
+--~ print(table.serialize(t), "\n")
+--~ print(table.serialize(t,"name"), "\n")
+--~ print(table.serialize(t,false), "\n")
+--~ print(table.serialize(t,true), "\n")
+--~ print(table.serialize(t,"name",true), "\n")
+--~ print(table.serialize(t,"name",true,true), "\n")
 
-    -- 34.055.092 32.403.326 arabtype.tma
-    --  1.620.614  1.513.863 lmroman10-italic.tma
-    --  1.325.585  1.233.044 lmroman10-regular.tma
-    --  1.248.157  1.158.903 lmsans10-regular.tma
-    --    194.646    153.120 lmtypewriter10-regular.tma
-    --  1.771.678  1.658.461 palatinosanscom-bold.tma
-    --  1.695.251  1.584.491 palatinosanscom-regular.tma
-    -- 13.736.534 13.409.446 zapfinoextraltpro.tma
-
-    -- 13.679.038 11.774.106 arabtype.tmc
-    --    886.248    754.944 lmroman10-italic.tmc
-    --    729.828    466.864 lmroman10-regular.tmc
-    --    688.482    441.962 lmsans10-regular.tmc
-    --    128.685     95.853 lmtypewriter10-regular.tmc
-    --    715.929    582.985 palatinosanscom-bold.tmc
-    --    669.942    540.126 palatinosanscom-regular.tmc
-    --  1.560.588  1.317.000 zapfinoextraltpro.tmc
-
-    table.serialize_functions = true
-    table.serialize_compact   = true
-    table.serialize_inline    = true
+table.serialize_functions = true
+table.serialize_compact   = true
+table.serialize_inline    = true
+
+local noquotes, hexify, handle, reduce, compact, inline, functions
+
+local reserved = table.tohash { -- intercept a language flaw, no reserved words as key
+    'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if',
+    'in', 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while',
+}
 
-    local function key(k)
-        if type(k) == "number" then -- or k:find("^%d+$") then
-            return "["..k.."]"
-        elseif noquotes and k:find("^%a[%a%d%_]*$") then
-            return k
+local function key(k)
+    if type(k) == "number" then -- or k:find("^%d+$") then
+        if hexify then
+            return ("[0x%04X]"):format(k)
         else
-            return '["'..k..'"]'
+            return "["..k.."]"
         end
+    elseif noquotes and not reserved[k] and k:find("^%a[%a%d%_]*$") then
+        return k
+    else
+        return '["'..k..'"]'
     end
+end
 
-    local function simple_table(t)
-        if #t > 0 then
-            local n = 0
-            for _,v in pairs(t) do
-                n = n + 1
-            end
-            if n == #t then
-                local tt = { }
-                for i=1,#t do
-                    local v = t[i]
-                    local tv = type(v)
-                    if tv == "number" or tv == "boolean" then
-                        tt[#tt+1] = tostring(v)
-                    elseif tv == "string" then
-                        tt[#tt+1] = ("%q"):format(v)
+local function simple_table(t)
+    if #t > 0 then
+        local n = 0
+        for _,v in pairs(t) do
+            n = n + 1
+        end
+        if n == #t then
+            local tt = { }
+            for i=1,#t do
+                local v = t[i]
+                local tv = type(v)
+                if tv == "number" then
+                    if hexify then
+                        tt[#tt+1] = ("0x%04X"):format(v)
                     else
-                        tt = nil
-                        break
+                        tt[#tt+1] = tostring(v)
                     end
+                elseif tv == "boolean" then
+                    tt[#tt+1] = tostring(v)
+                elseif tv == "string" then
+                    tt[#tt+1] = ("%q"):format(v)
+                else
+                    tt = nil
+                    break
                 end
-                return tt
             end
+            return tt
         end
-        return nil
     end
+    return nil
+end
 
-    local function serialize(root,name,handle,depth,level,reduce,noquotes,indexed)
-        handle = handle or print
-        reduce = reduce or false
-        if depth then
-            depth = depth .. " "
-            if indexed then
-                handle(("%s{"):format(depth))
-            else
-                handle(("%s%s={"):format(depth,key(name)))
-            end
-        else
-            depth = ""
-            local tname = type(name)
-            if tname == "string" then
-                if name == "return" then
-                    handle("return {")
-                else
-                    handle(name .. "={")
-                end
-            elseif tname == "number" then
-                handle("[" .. name .. "]={")
-            elseif tname == "boolean" then
-                if name then
-                    handle("return {")
-                else
-                    handle("{")
-                end
-            else
-                handle("t={")
-            end
-        end
-        if root and next(root) then
-            local compact = table.serialize_compact
-            local inline  = compact and table.serialize_inline
-            local first, last = nil, 0 -- #root cannot be trusted here
-            if compact then
-              for k,v in ipairs(root) do -- NOT: for k=1,#root do (why)
-                    if not first then first = k end
-                    last = last + 1
-                end
-            end
-            for _,k in pairs(table.sortedkeys(root)) do
-                local v = root[k]
-                local t = type(v)
-                if compact and first and type(k) == "number" and k >= first and k <= last then
-                    if t == "number" then
-                        handle(("%s %s,"):format(depth,v))
-                    elseif t == "string" then
-                        if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then
-                            handle(("%s %s,"):format(depth,v))
-                        else
-                            handle(("%s %q,"):format(depth,v))
-                        end
-                    elseif t == "table" then
-                        if not next(v) then
-                            handle(("%s {},"):format(depth))
-                        elseif inline then
-                            local st = simple_table(v)
-                            if st then
-                                handle(("%s { %s },"):format(depth,table.concat(st,", ")))
-                            else
-                                serialize(v,k,handle,depth,level+1,reduce,noquotes,true)
-                            end
-                        else
-                            serialize(v,k,handle,depth,level+1,reduce,noquotes,true)
-                        end
-                    elseif t == "boolean" then
-                        handle(("%s %s,"):format(depth,tostring(v)))
-                    elseif t == "function" then
-                        if table.serialize_functions then
-                            handle(('%s loadstring(%q),'):format(depth,string.dump(v)))
-                        else
-                            handle(('%s "function",'):format(depth))
-                        end
+local function do_serialize(root,name,depth,level,indexed)
+    if level > 0 then
+        depth = depth .. " "
+        if indexed then
+            handle(("%s{"):format(depth))
+        elseif name then
+            handle(("%s%s={"):format(depth,key(name)))
+        else
+            handle(("%s{"):format(depth))
+        end
+    end
+    if root and next(root) then
+        local first, last = nil, 0 -- #root cannot be trusted here
+        if compact then
+          for k,v in ipairs(root) do -- NOT: for k=1,#root do (we need to quit at nil)
+                if not first then first = k end
+                last = last + 1
+            end
+        end
+    --~ for _,k in pairs(sortedkeys(root)) do -- 1% faster:
+        local sk = sortedkeys(root)
+        for i=1,#sk do
+            local k = sk[i]
+            local v = root[k]
+            local t = type(v)
+            if compact and first and type(k) == "number" and k >= first and k <= last then
+                if t == "number" then
+                    if hexify then
+                        handle(("%s 0x%04X,"):format(depth,v))
                     else
-                        handle(("%s %q,"):format(depth,tostring(v)))
-                    end
-                elseif k == "__p__" then -- parent
-                    if false then
-                        handle(("%s __p__=nil,"):format(depth))
+                        handle(("%s %s,"):format(depth,v))
                     end
-                elseif t == "number" then
-                    handle(("%s %s=%s,"):format(depth,key(k),v))
                 elseif t == "string" then
                     if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then
-                        handle(("%s %s=%s,"):format(depth,key(k),v))
+                        handle(("%s %s,"):format(depth,v))
                     else
-                        handle(("%s %s=%q,"):format(depth,key(k),v))
+                        handle(("%s %q,"):format(depth,v))
                     end
                 elseif t == "table" then
                     if not next(v) then
-                        handle(("%s %s={},"):format(depth,key(k)))
+                        handle(("%s {},"):format(depth))
                     elseif inline then
                         local st = simple_table(v)
                         if st then
-                            handle(("%s %s={ %s },"):format(depth,key(k),table.concat(st,", ")))
+                            handle(("%s { %s },"):format(depth,concat(st,", ")))
                         else
-                            serialize(v,k,handle,depth,level+1,reduce,noquotes)
+                            do_serialize(v,k,depth,level+1,true)
                         end
                     else
-                        serialize(v,k,handle,depth,level+1,reduce,noquotes)
+                        do_serialize(v,k,depth,level+1,true)
                     end
                 elseif t == "boolean" then
-                    handle(("%s %s=%s,"):format(depth,key(k),tostring(v)))
+                    handle(("%s %s,"):format(depth,tostring(v)))
                 elseif t == "function" then
-                    if table.serialize_functions then
-                        handle(('%s %s=loadstring(%q),'):format(depth,key(k),string.dump(v)))
+                    if functions then
+                        handle(('%s loadstring(%q),'):format(depth,v:dump()))
                     else
-                        handle(('%s %s="function",'):format(depth,key(k)))
+                        handle(('%s "function",'):format(depth))
                     end
                 else
-                    handle(("%s %s=%q,"):format(depth,key(k),tostring(v)))
-                --  handle(('%s %s=loadstring(%q),'):format(depth,key(k),string.dump(function() return v end)))
+                    handle(("%s %q,"):format(depth,tostring(v)))
+                end
+            elseif k == "__p__" then -- parent
+                if false then
+                    handle(("%s __p__=nil,"):format(depth))
+                end
+            elseif t == "number" then
+                if hexify then
+                    handle(("%s %s=0x%04X,"):format(depth,key(k),v))
+                else
+                    handle(("%s %s=%s,"):format(depth,key(k),v))
+                end
+            elseif t == "string" then
+                if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+                    handle(("%s %s=%s,"):format(depth,key(k),v))
+                else
+                    handle(("%s %s=%q,"):format(depth,key(k),v))
+                end
+            elseif t == "table" then
+                if not next(v) then
+                    handle(("%s %s={},"):format(depth,key(k)))
+                elseif inline then
+                    local st = simple_table(v)
+                    if st then
+                        handle(("%s %s={ %s },"):format(depth,key(k),concat(st,", ")))
+                    else
+                        do_serialize(v,k,depth,level+1)
+                    end
+                else
+                    do_serialize(v,k,depth,level+1)
+                end
+            elseif t == "boolean" then
+                handle(("%s %s=%s,"):format(depth,key(k),tostring(v)))
+            elseif t == "function" then
+                if functions then
+                    handle(('%s %s=loadstring(%q),'):format(depth,key(k),v:dump()))
+                else
+                    handle(('%s %s="function",'):format(depth,key(k)))
                 end
-            end
-            if level > 0 then
-                handle(("%s},"):format(depth))
             else
-                handle(("%s}"):format(depth))
+                handle(("%s %s=%q,"):format(depth,key(k),tostring(v)))
+            --  handle(('%s %s=loadstring(%q),'):format(depth,key(k),string.dump(function() return v end)))
             end
-        else
-            handle(("%s}"):format(depth))
         end
     end
+   if level > 0 then
+        handle(("%s},"):format(depth))
+    end
+end
 
-    --~ name:
-    --~
-    --~ true     : return     { }
-    --~ false    :            { }
-    --~ nil      : t        = { }
-    --~ string   : string   = { }
-    --~ 'return' : return     { }
-    --~ number   : [number] = { }
-
-    function table.serialize(root,name,reduce,noquotes)
-        local t = { }
-        local function flush(s)
-            t[#t+1] = s
+local function serialize(root,name,_handle,_reduce,_noquotes,_hexify)
+    noquotes = _noquotes
+    hexify = _hexify
+    handle = _handle or print
+    reduce = _reduce or false
+    compact = table.serialize_compact
+    inline  = compact and table.serialize_inline
+    functions = table.serialize_functions
+    local tname = type(name)
+    if tname == "string" then
+        if name == "return" then
+            handle("return {")
+        else
+            handle(name .. "={")
+        end
+    elseif tname == "number" then
+        if hexify then
+            handle(("[0x%04X]={"):format(name))
+        else
+            handle("[" .. name .. "]={")
+        end
+    elseif tname == "boolean" then
+        if name then
+            handle("return {")
+        else
+            handle("{")
         end
-        serialize(root, name, flush, nil, 0, reduce, noquotes)
-        return table.concat(t,"\n")
+    else
+        handle("t={")
+    end
+    if root and next(root) then
+        do_serialize(root,name,"",0,indexed)
     end
+    handle("}")
+end
+
+--~ name:
+--~
+--~ true     : return     { }
+--~ false    :            { }
+--~ nil      : t        = { }
+--~ string   : string   = { }
+--~ 'return' : return     { }
+--~ number   : [number] = { }
 
-    function table.tohandle(handle,root,name,reduce,noquotes)
-        serialize(root, name, handle, nil, 0, reduce, noquotes)
+function table.serialize(root,name,reduce,noquotes,hexify)
+    local t = { }
+    local function flush(s)
+        t[#t+1] = s
     end
+    serialize(root,name,flush,reduce,noquotes,hexify)
+    return concat(t,"\n")
+end
 
-    -- sometimes tables are real use (zapfino extra pro is some 85M) in which
-    -- case a stepwise serialization is nice; actually, we could consider:
-    --
-    -- for line in table.serializer(root,name,reduce,noquotes) do
-    --    ...(line)
-    -- end
-    --
-    -- so this is on the todo list
+function table.tohandle(handle,root,name,reduce,noquotes,hexify)
+    serialize(root,name,handle,reduce,noquotes,hexify)
+end
 
-    table.tofile_maxtab = 2*1024
+-- sometimes tables are real use (zapfino extra pro is some 85M) in which
+-- case a stepwise serialization is nice; actually, we could consider:
+--
+-- for line in table.serializer(root,name,reduce,noquotes) do
+--    ...(line)
+-- end
+--
+-- so this is on the todo list
 
-    function table.tofile(filename,root,name,reduce,noquotes)
-        local f = io.open(filename,'w')
-        if f then
-            local concat = table.concat
-            local maxtab = table.tofile_maxtab
-            if maxtab > 1 then
-                local t = { }
-                local function flush(s)
-                    t[#t+1] = s
-                    if #t > maxtab then
-                        f:write(concat(t,"\n"),"\n") -- hm, write(sometable) should be nice
-                        t = { }
-                    end
-                end
-                serialize(root, name, flush, nil, 0, reduce, noquotes)
-                f:write(concat(t,"\n"),"\n")
-            else
-                local function flush(s)
-                    f:write(s,"\n")
+table.tofile_maxtab = 2*1024
+
+function table.tofile(filename,root,name,reduce,noquotes,hexify)
+    local f = io.open(filename,'w')
+    if f then
+        local maxtab = table.tofile_maxtab
+        if maxtab > 1 then
+            local t = { }
+            local function flush(s)
+                t[#t+1] = s
+                if #t > maxtab then
+                    f:write(concat(t,"\n"),"\n") -- hm, write(sometable) should be nice
+                    t = { }
                 end
-                serialize(root, name, flush, nil, 0, reduce, noquotes)
             end
-            f:close()
+            serialize(root,name,flush,reduce,noquotes,hexify)
+            f:write(concat(t,"\n"),"\n")
+        else
+            local function flush(s)
+                f:write(s,"\n")
+            end
+            serialize(root,name,flush,reduce,noquotes,hexify)
         end
+        f:close()
     end
-
 end
 
---~ t = {
---~     b = "123",
---~     a = "x",
---~     c = 1.23,
---~     d = "1.23",
---~     e = true,
---~     f = {
---~         d = "1.23",
---~         a = "x",
---~         b = "123",
---~         c = 1.23,
---~         e = true,
---~         f = {
---~             e = true,
---~             f = {
---~                 e = true
---~             },
---~         },
---~     },
---~     g = function() end
---~ }
-
---~ print(table.serialize(t), "\n")
---~ print(table.serialize(t,"name"), "\n")
---~ print(table.serialize(t,false), "\n")
---~ print(table.serialize(t,true), "\n")
---~ print(table.serialize(t,"name",true), "\n")
---~ print(table.serialize(t,"name",true,true), "\n")
-
-do
-
-    local function flatten(t,f,complete)
-        for i=1,#t do
-            local v = t[i]
-            if type(v) == "table" then
-                if complete or type(v[1]) == "table" then
-                    flatten(v,f,complete)
-                else
-                    f[#f+1] = v
-                end
+local function flatten(t,f,complete)
+    for i=1,#t do
+        local v = t[i]
+        if type(v) == "table" then
+            if complete or type(v[1]) == "table" then
+                flatten(v,f,complete)
             else
                 f[#f+1] = v
             end
+        else
+            f[#f+1] = v
         end
     end
+end
 
-    function table.flatten(t)
-        local f = { }
-        flatten(t,f,true)
-        return f
-    end
+function table.flatten(t)
+    local f = { }
+    flatten(t,f,true)
+    return f
+end
 
-    function table.unnest(t) -- bad name
-        local f = { }
-        flatten(t,f,false)
-        return f
-    end
+function table.unnest(t) -- bad name
+    local f = { }
+    flatten(t,f,false)
+    return f
+end
+
+table.flatten_one_level = table.unnest
 
-    table.flatten_one_level = table.unnest
+-- the next three may disappear
 
+function table.remove_value(t,value) -- todo: n
+    if value then
+        for i=1,#t do
+            if t[i] == value then
+                remove(t,i)
+                -- remove all, so no: return
+            end
+        end
+    end
 end
 
 function table.insert_before_value(t,value,str)
-    for i=1,#t do
-        if t[i] == value then
-            table.insert(t,i,str)
-            return
+    if str then
+        if value then
+            for i=1,#t do
+                if t[i] == value then
+                    insert(t,i,str)
+                    return
+                end
+            end
         end
+        insert(t,1,str)
+    elseif value then
+        insert(t,1,value)
     end
-    table.insert(t,1,str)
 end
 
 function table.insert_after_value(t,value,str)
-    for i=1,#t do
-        if t[i] == value then
-            table.insert(t,i+1,str)
-            return
+    if str then
+        if value then
+            for i=1,#t do
+                if t[i] == value then
+                    insert(t,i+1,str)
+                    return
+                end
+            end
         end
+        t[#t+1] = str
+    elseif value then
+        t[#t+1] = value
     end
-    t[#t+1] = str
 end
 
 function table.are_equal(a,b,n,m)
@@ -1012,27 +1047,11 @@ function table.compact(t)
     end
 end
 
-function table.tohash(t)
-    local h = { }
-    for _, v in pairs(t) do -- no ipairs here
-        h[v] = true
-    end
-    return h
-end
-
-function table.fromhash(t)
-    local h = { }
-    for k, v in pairs(t) do -- no ipairs here
-        if v then h[#h+1] = k end
-    end
-    return h
-end
-
 function table.contains(t, v)
     if t then
         for i=1, #t do
             if t[i] == v then
-                return true
+                return i
             end
         end
     end
@@ -1069,11 +1088,10 @@ function table.clone(t,p) -- t is option
     return t
 end
 
-
 function table.hexed(t,seperator)
     local tt = { }
-    for i=1,#t do tt[i] = string.format("0x%04X",t[i]) end
-    return table.concat(tt,seperator or " ")
+    for i=1,#t do tt[i] = ("0x%04X"):format(t[i]) end
+    return concat(tt,seperator or " ")
 end
 
 function table.reverse_hash(h)
@@ -1113,6 +1131,7 @@ function io.loaddata(filename)
     local f = io.open(filename,'rb')
     if f then
         local data = f:read('*all')
+    --  garbagecollector.check(data)
         f:close()
         return data
     else
@@ -1121,7 +1140,7 @@ function io.loaddata(filename)
 end
 
 function io.savedata(filename,data,joiner)
-    local f = io.open(filename, "wb")
+    local f = io.open(filename,"wb")
     if f then
         if type(data) == "table" then
             f:write(table.join(data,joiner or ""))
@@ -1131,6 +1150,9 @@ function io.savedata(filename,data,joine
             f:write(data)
         end
         f:close()
+        return true
+    else
+        return false
     end
 end
 
@@ -1465,6 +1487,9 @@ end
 -- copyright: PRAGMA ADE / ConTeXt Development Team
 -- license  : see context related readme files
 
+
+--~ print(table.serialize(os.uname()))
+
 if not versions then versions = { } end versions['l-os'] = 1.001
 
 function os.resultof(command)
@@ -1560,10 +1585,14 @@ if not versions then versions = { } end 
 
 if not file then file = { } end
 
+local concat = table.concat
+
 function file.removesuffix(filename)
-    return filename:gsub("%.[%a%d]+$", "")
+    return (filename:gsub("%.[%a%d]+$",""))
 end
 
+file.stripsuffix = file.removesuffix
+
 function file.addsuffix(filename, suffix)
     if not filename:find("%.[%a%d]+$") then
         return filename .. "." .. suffix
@@ -1573,11 +1602,7 @@ function file.addsuffix(filename, suffix
 end
 
 function file.replacesuffix(filename, suffix)
-    if not filename:find("%.[%a%d]+$") then
-        return filename .. "." .. suffix
-    else
-        return (filename:gsub("%.[%a%d]+$","."..suffix))
-    end
+    return (filename:gsub("%.[%a%d]+$","")) .. "." .. suffix
 end
 
 function file.dirname(name)
@@ -1598,18 +1623,6 @@ end
 
 file.suffix = file.extname
 
-function file.stripsuffix(name)
-    return (name:gsub("%.[%a%d]+$",""))
-end
-
---~ function file.join(...)
---~     local t = { ... }
---~     for i=1,#t do
---~         t[i] = (t[i]:gsub("\\","/")):gsub("/+$","")
---~     end
---~     return table.concat(t,"/")
---~ end
-
 --~ print(file.join("x/","/y"))
 --~ print(file.join("http://","/y"))
 --~ print(file.join("http://a","/y"))
@@ -1617,7 +1630,7 @@ end
 --~ print(file.join("//nas-1","/y"))
 
 function file.join(...)
-    local pth = table.concat({...},"/")
+    local pth = concat({...},"/")
     pth = pth:gsub("\\","/")
     local a, b = pth:match("^(.*://)(.*)$")
     if a and b then
@@ -1650,6 +1663,16 @@ function file.is_readable(name)
     end
 end
 
+function file.iswritable(name)
+    local a = lfs.attributes(name)
+    return a and a.permissions:sub(2,2) == "w"
+end
+
+function file.isreadable(name)
+    local a = lfs.attributes(name)
+    return a and a.permissions:sub(1,1) == "r"
+end
+
 --~ function file.split_path(str)
 --~     if str:find(';') then
 --~         return str:splitchr(";")
@@ -1674,37 +1697,29 @@ function file.split_path(str)
 end
 
 function file.join_path(tab)
-    return table.concat(tab,io.pathseparator) -- can have trailing //
+    return concat(tab,io.pathseparator) -- can have trailing //
 end
 
---~ print('test'           .. " == " .. file.collapse_path("test"))
---~ print("test/test"      .. " == " .. file.collapse_path("test/test"))
---~ print("test/test/test" .. " == " .. file.collapse_path("test/test/test"))
---~ print("test/test"      .. " == " .. file.collapse_path("test/../test/test"))
---~ print("test"           .. " == " .. file.collapse_path("test/../test"))
---~ print("../test"        .. " == " .. file.collapse_path("../test"))
---~ print("../test/"       .. " == " .. file.collapse_path("../test/"))
---~ print("a/a"            .. " == " .. file.collapse_path("a/b/c/../../a"))
-
---~ function file.collapse_path(str)
---~     local ok, n = false, 0
---~     while not ok do
---~         ok = true
---~         str, n = str:gsub("[^%./]+/%.%./", function(s)
---~             ok = false
---~             return ""
---~         end)
---~     end
---~     return (str:gsub("/%./","/"))
---~ end
-
 function file.collapse_path(str)
-    local n = 1
-    while n > 0 do
-        str, n = str:gsub("([^/%.]+/%.%./)","")
-    end
-    return (str:gsub("/%./","/"))
-end
+    str = str:gsub("/%./","/")
+    local n, m = 1, 1
+    while n > 0 or m > 0 do
+        str, n = str:gsub("[^/%.]+/%.%.$","")
+        str, m = str:gsub("[^/%.]+/%.%./","")
+    end
+    str = str:gsub("([^/])/$","%1")
+    str = str:gsub("^%./","")
+    str = str:gsub("/%.$","")
+    if str == "" then str = "." end
+    return str
+end
+
+--~ print(file.collapse_path("a/./b/.."))
+--~ print(file.collapse_path("a/aa/../b/bb"))
+--~ print(file.collapse_path("a/../.."))
+--~ print(file.collapse_path("a/.././././b/.."))
+--~ print(file.collapse_path("a/./././b/.."))
+--~ print(file.collapse_path("a/b/c/../.."))
 
 function file.robustname(str)
     return (str:gsub("[^%a%d%/%-%.\\]+","-"))
@@ -1717,19 +1732,111 @@ function file.copy(oldname,newname)
     file.savedata(newname,io.loaddata(oldname))
 end
 
+-- lpeg variants, slightly faster, not always
 
--- filename : l-url.lua
--- author   : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license  : see context related readme files
+--~ local period    = lpeg.P(".")
+--~ local slashes   = lpeg.S("\\/")
+--~ local noperiod  = 1-period
+--~ local noslashes = 1-slashes
+--~ local name      = noperiod^1
 
-if not versions then versions = { } end versions['l-url'] = 1.001
-if not url      then url      = { } end
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.C(noperiod^1) * -1
 
--- from the spec (on the web):
---
---     foo://example.com:8042/over/there?name=ferret#nose
---     \_/   \______________/\_________/ \_________/ \__/
+--~ function file.extname(name)
+--~     return pattern:match(name) or ""
+--~ end
+
+--~ local pattern = lpeg.Cs(((period * noperiod^1 * -1)/"" + 1)^1)
+
+--~ function file.removesuffix(name)
+--~     return pattern:match(name)
+--~ end
+
+--~ file.stripsuffix = file.removesuffix
+
+--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.C(noslashes^1) * -1
+
+--~ function file.basename(name)
+--~     return pattern:match(name) or name
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.Cp() * noslashes^1 * -1
+
+--~ function file.dirname(name)
+--~     local p = pattern:match(name)
+--~     if p then
+--~         return name:sub(1,p-2)
+--~     else
+--~         return ""
+--~     end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+
+--~ function file.addsuffix(name, suffix)
+--~     local p = pattern:match(name)
+--~     if p then
+--~         return name
+--~     else
+--~         return name .. "." .. suffix
+--~     end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+
+--~ function file.replacesuffix(name,suffix)
+--~     local p = pattern:match(name)
+--~     if p then
+--~         return name:sub(1,p-2) .. "." .. suffix
+--~     else
+--~         return name .. "." .. suffix
+--~     end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * lpeg.Cp() * ((noperiod^1 * period)^1 * lpeg.Cp() + lpeg.P(true)) * noperiod^1 * -1
+
+--~ function file.nameonly(name)
+--~     local a, b = pattern:match(name)
+--~     if b then
+--~         return name:sub(a,b-2)
+--~     elseif a then
+--~         return name:sub(a)
+--~     else
+--~         return name
+--~     end
+--~ end
+
+--~ local test = file.extname
+--~ local test = file.stripsuffix
+--~ local test = file.basename
+--~ local test = file.dirname
+--~ local test = file.addsuffix
+--~ local test = file.replacesuffix
+--~ local test = file.nameonly
+
+--~ print(1,test("./a/b/c/abd.def.xxx","!!!"))
+--~ print(2,test("./../b/c/abd.def.xxx","!!!"))
+--~ print(3,test("a/b/c/abd.def.xxx","!!!"))
+--~ print(4,test("a/b/c/def.xxx","!!!"))
+--~ print(5,test("a/b/c/def","!!!"))
+--~ print(6,test("def","!!!"))
+--~ print(7,test("def.xxx","!!!"))
+
+--~ local tim = os.clock() for i=1,250000 do local ext = test("abd.def.xxx","!!!") end print(os.clock()-tim)
+
+
+-- filename : l-url.lua
+-- author   : Hans Hagen, PRAGMA-ADE, Hasselt NL
+-- copyright: PRAGMA ADE / ConTeXt Development Team
+-- license  : see context related readme files
+
+if not versions then versions = { } end versions['l-url'] = 1.001
+if not url      then url      = { } end
+
+-- from the spec (on the web):
+--
+--     foo://example.com:8042/over/there?name=ferret#nose
+--     \_/   \______________/\_________/ \_________/ \__/
 --      |           |            |            |        |
 --   scheme     authority       path        query   fragment
 --      |   _____________________|__
@@ -1837,51 +1944,6 @@ dir = { }
 
 if lfs then do
 
---~     local attributes = lfs.attributes
---~     local walkdir    = lfs.dir
---~
---~     local function glob_pattern(path,patt,recurse,action)
---~         local ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe
---~         if ok and type(scanner) == "function" then
---~             if not path:find("/$") then path = path .. '/' end
---~             for name in scanner do
---~                 local full = path .. name
---~                 local mode = attributes(full,'mode')
---~                 if mode == 'file' then
---~                     if name:find(patt) then
---~                         action(full)
---~                     end
---~                 elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
---~                     glob_pattern(full,patt,recurse,action)
---~                 end
---~             end
---~         end
---~     end
---~
---~     dir.glob_pattern = glob_pattern
---~
---~     local function glob(pattern, action)
---~         local t = { }
---~         local action = action or function(name) t[#t+1] = name end
---~         local path, patt = pattern:match("^(.*)/*%*%*/*(.-)$")
---~         local recurse = path and patt
---~         if not recurse then
---~             path, patt = pattern:match("^(.*)/(.-)$")
---~             if not (path and patt) then
---~                 path, patt = '.', pattern
---~             end
---~         end
---~         patt = patt:gsub("([%.%-%+])", "%%%1")
---~         patt = patt:gsub("%*", ".*")
---~         patt = patt:gsub("%?", ".")
---~         patt = "^" .. patt .. "$"
---~      -- print('path: ' .. path .. ' | pattern: ' .. patt .. ' | recurse: ' .. tostring(recurse))
---~         glob_pattern(path,patt,recurse,action)
---~         return t
---~     end
---~
---~     dir.glob = glob
-
     local attributes = lfs.attributes
     local walkdir    = lfs.dir
 
@@ -1910,30 +1972,6 @@ if lfs then do
 
     dir.glob_pattern = glob_pattern
 
-    --~ local function glob(pattern, action)
-    --~     local t = { }
-    --~     local path, rest, patt, recurse
-    --~     local action = action or function(name) t[#t+1] = name end
-    --~     local pattern = pattern:gsub("^%*%*","./**")
-    --~     local pattern = pattern:gsub("/%*/","/**/")
-    --~     path, rest = pattern:match("^(/)(.-)$")
-    --~     if path then
-    --~         path = path
-    --~     else
-    --~         path, rest = pattern:match("^([^/]*)/(.-)$")
-    --~     end
-    --~     if rest then
-    --~         patt = rest:gsub("([%.%-%+])", "%%%1")
-    --~     end
-    --~     patt = patt:gsub("%*", "[^/]*")
-    --~     patt = patt:gsub("%?", "[^/]")
-    --~     patt = patt:gsub("%[%^/%]%*%[%^/%]%*", ".*")
-    --~     if path == "" then path = "." end
-    --~     recurse = patt:find("%.%*/") ~= nil
-    --~     glob_pattern(path,patt,recurse,action)
-    --~     return t
-    --~ end
-
     local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
 
     local pattern = Ct {
@@ -1959,13 +1997,17 @@ if lfs then do
                 glob(s,t)
             end
             return t
+        elseif lfs.isfile(str) then
+            local t = t or { }
+            t[#t+1] = str
+            return t
         else
             local split = pattern:match(str)
             if split then
                 local t = t or { }
                 local action = action or function(name) t[#t+1] = name end
                 local root, path, base = split[1], split[2], split[3]
-                local recurse = base:find("**")
+                local recurse = base:find("%*%*")
                 local start = root .. path
                 local result = filter:match(start .. base)
                 glob_pattern(start,result,recurse,action)
@@ -1993,16 +2035,21 @@ if lfs then do
         for name in walkdir(path) do
             if name:find("^%.") then
                 --- skip
-            elseif attributes(name,'mode') == "directory" then
-                if recurse then
-                    globfiles(path .. "/" .. name,recurse,func,files)
-                end
-            elseif func then
-                if func(name) then
-                    files[#files+1] = path .. "/" .. name
-                end
             else
-                files[#files+1] = path .. "/" .. name
+                local mode = attributes(name,'mode')
+                if mode == "directory" then
+                    if recurse then
+                        globfiles(path .. "/" .. name,recurse,func,files)
+                    end
+                elseif mode == "file" then
+                    if func then
+                        if func(name) then
+                            files[#files+1] = path .. "/" .. name
+                        end
+                    else
+                        files[#files+1] = path .. "/" .. name
+                    end
+                end
             end
         end
         return files
@@ -2210,7 +2257,7 @@ function toboolean(str,tolerant)
     if tolerant then
         local tstr = type(str)
         if tstr == "string" then
-            return str == "true" or str == "yes" or str == "on" or str == "1"
+            return str == "true" or str == "yes" or str == "on" or str == "1" or str == "t"
         elseif tstr == "number" then
             return tonumber(str) ~= 0
         elseif tstr == "nil" then
@@ -2229,9 +2276,9 @@ end
 
 function string.is_boolean(str)
     if type(str) == "string" then
-        if str == "true" or str == "yes" or str == "on" then
+        if str == "true" or str == "yes" or str == "on" or str == "t" then
             return true
-        elseif str == "false" or str == "no" or str == "off" then
+        elseif str == "false" or str == "no" or str == "off" or str == "f" then
             return false
         end
     end
@@ -2256,6 +2303,9 @@ end
 if not versions then versions = { } end versions['l-unicode'] = 1.001
 if not unicode  then unicode  = { } end
 
+local concat, utfchar, utfgsub = table.concat, unicode.utf8.char, unicode.utf8.gsub
+local char, byte = string.char, string.byte
+
 if not garbagecollector then
     garbagecollector = {
         push = function() collectgarbage("stop")    end,
@@ -2301,70 +2351,69 @@ function unicode.utftype(f) -- \000 fail
     end
 end
 
-function unicode.utf16_to_utf8(str, endian)
-    garbagecollector.push()
-    local result = { }
-    local tc, uc = table.concat, unicode.utf8.char
-    local tmp, n, m, p = { }, 0, 0, 0
+function unicode.utf16_to_utf8(str, endian) -- maybe a gsub is faster or an lpeg
+--~     garbagecollector.push()
+    local result, tmp, n, m, p = { }, { }, 0, 0, 0
     -- lf | cr | crlf / (cr:13, lf:10)
     local function doit()
         if n == 10 then
             if p ~= 13 then
-                result[#result+1] = tc(tmp,"")
+                result[#result+1] = concat(tmp,"")
                 tmp = { }
                 p = 0
             end
         elseif n == 13 then
-            result[#result+1] = tc(tmp,"")
+            result[#result+1] = concat(tmp,"")
             tmp = { }
             p = n
         else
-            tmp[#tmp+1] = uc(n)
+            tmp[#tmp+1] = utfchar(n)
             p = 0
         end
     end
     for l,r in str:bytepairs() do
-        if endian then
-            n = l*256 + r
-        else
-            n = r*256 + l
-        end
-        if m > 0 then
-            n = (m-0xD800)*0x400 + (n-0xDC00) + 0x10000
-            m = 0
-            doit()
-        elseif n >= 0xD800 and n <= 0xDBFF then
-            m = n
-        else
-            doit()
+        if r then
+            if endian then
+                n = l*256 + r
+            else
+                n = r*256 + l
+            end
+            if m > 0 then
+                n = (m-0xD800)*0x400 + (n-0xDC00) + 0x10000
+                m = 0
+                doit()
+            elseif n >= 0xD800 and n <= 0xDBFF then
+                m = n
+            else
+                doit()
+            end
         end
     end
     if #tmp > 0 then
-        result[#result+1] = tc(tmp,"")
+        result[#result+1] = concat(tmp,"")
     end
-    garbagecollector.pop()
+--~     garbagecollector.pop()
     return result
 end
 
 function unicode.utf32_to_utf8(str, endian)
-    garbagecollector.push()
+--~     garbagecollector.push()
     local result = { }
-    local tc, uc = table.concat, unicode.utf8.char
     local tmp, n, m, p = { }, 0, -1, 0
     -- lf | cr | crlf / (cr:13, lf:10)
     local function doit()
         if n == 10 then
             if p ~= 13 then
-                result[#result+1] = tc(tmp,"")
+                result[#result+1] = concat(tmp,"")
                 tmp = { }
                 p = 0
             end
         elseif n == 13 then
-            result[#result+1] = tc(tmp,"")
+            result[#result+1] = concat(tmp,"")
             tmp = { }
             p = n
         else
-            tmp[#tmp+1] = uc(n)
+            tmp[#tmp+1] = utfchar(n)
             p = 0
         end
     end
@@ -2390,12 +2439,67 @@ function unicode.utf32_to_utf8(str, endi
         end
     end
     if #tmp > 0 then
-        result[#result+1] = tc(tmp,"")
+        result[#result+1] = concat(tmp,"")
     end
-    garbagecollector.pop()
+--~     garbagecollector.pop()
     return result
 end
 
+function unicode.utf8_to_utf16(str,littleendian)
+    if littleendian then
+        return char(255,254) .. utfgsub(str,".",function(c)
+            local b = byte(c)
+            if b < 0x10000 then
+                return char(b%256,b/256)
+            else
+                b = b - 0x10000
+                local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
+                return char(b1%256,b1/256,b2%256,b2/256)
+            end
+        end)
+    else
+        return char(254,255) .. utfgsub(str,".",function(c)
+            local b = byte(c)
+            if b < 0x10000 then
+                return char(b/256,b%256)
+            else
+                b = b - 0x10000
+                local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
+                return char(b1/256,b1%256,b2/256,b2%256)
+            end
+        end)
+    end
+end
+
+
+-- filename : l-math.lua
+-- comment  : split off from luat-lib
+-- author   : Hans Hagen, PRAGMA-ADE, Hasselt NL
+-- copyright: PRAGMA ADE / ConTeXt Development Team
+-- license  : see context related readme files
+
+if not versions then versions = { } end versions['l-math'] = 1.001
+
+local floor = math.floor
+
+if not math.round then
+    function math.round(x)
+        return floor(x + 0.5)
+    end
+end
+
+if not math.div then
+    function math.div(n,m)
+        return floor(n/m)
+    end
+end
+
+if not math.mod then
+    function math.mod(n,m)
+        return n % m
+    end
+end
+
 
 -- filename : l-utils.lua
 -- comment  : split off from luat-lib
@@ -2429,11 +2533,20 @@ function utils.report(...)
     print(...)
 end
 
+utils.merger.strip_comment = true
+
 function utils.merger._self_load_(name)
     local f, data = io.open(name), ""
     if f then
+        utils.report("reading merge from %s",name)
         data = f:read("*all")
         f:close()
+    else
+        utils.report("unknown file to merge %s",name)
+    end
+    if data and utils.merger.strip_comment then
+        -- saves some 20K
+        data = data:gsub("%-%-~[^\n\r]*[\r\n]", "")
     end
     return data or ""
 end
@@ -2442,6 +2555,7 @@ function utils.merger._self_save_(name, 
     if data ~= "" then
         local f = io.open(name,'w')
         if f then
+            utils.report("saving merge from %s",name)
             f:write(data)
             f:close()
         end
@@ -2467,13 +2581,13 @@ function utils.merger._self_libs_(libs,l
             local name = string.gsub(pth .. "/" .. lib,"\\","/")
             f = io.open(name)
             if f then
-            --  utils.report("merging library",name)
+                utils.report("merging library %s",name)
                 result[#result+1] = f:read("*all")
                 f:close()
                 list = { pth } -- speed up the search
                 break
             else
-            --  utils.report("no library",name)
+                utils.report("no library %s",name)
             end
         end
     end
@@ -2512,108 +2626,62 @@ function utils.merger.selfclean(name)
     )
 end
 
-utils.lua.compile_strip = true
-
-function utils.lua.compile(luafile, lucfile)
+function utils.lua.compile(luafile, lucfile, cleanup, strip) -- defaults: cleanup=false strip=true
  -- utils.report("compiling",luafile,"into",lucfile)
     os.remove(lucfile)
     local command = "-o " .. string.quote(lucfile) .. " " .. string.quote(luafile)
-    if utils.lua.compile_strip then
+    if strip ~= false then
         command = "-s " .. command
     end
-    if os.spawn("texluac " .. command) == 0 then
-        return true
-    elseif os.spawn("luac " .. command) == 0 then
-        return true
-    else
-        return false
+    local done = (os.spawn("texluac " .. command) == 0) or (os.spawn("luac " .. command) == 0)
+    if done and cleanup == true and lfs.isfile(lucfile) and lfs.isfile(luafile) then
+     -- utils.report("removing",luafile)
+        os.remove(luafile)
     end
+    return done
 end
 
 
 
--- filename : luat-lib.lua
--- comment  : companion to luat-lib.tex
--- author   : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license  : see context related readme files
-
-if not versions then versions = { } end versions['luat-lib'] = 1.001
-
--- mostcode moved to the l-*.lua and other luat-*.lua files
+if not modules then modules = { } end modules ['luat-lib'] = {
+    version   = 1.001,
+    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+    copyright = "PRAGMA ADE / ConTeXt Development Team",
+    license   = "see context related readme files",
+    comment   = "companion to luat-lib.tex",
+}
 
--- os / io
+-- most code already moved to the l-*.lua and other luat-*.lua files
 
 os.setlocale(nil,nil) -- useless feature and even dangerous in luatex
 
--- os.platform
-
--- mswin|bccwin|mingw|cygwin  windows
--- darwin|rhapsody|nextstep   macosx
--- netbsd|unix                unix
--- linux                      linux
-
-if not io.fileseparator then
-    if string.find(os.getenv("PATH"),";") then
-        io.fileseparator, io.pathseparator, os.platform = "\\", ";", os.type or "windows"
-    else
-        io.fileseparator, io.pathseparator, os.platform = "/" , ":", os.type or "unix"
-    end
-end
-
-os.platform = os.platform or os.type or (io.pathseparator == ";" and "windows") or "unix"
-
--- arg normalization
---
--- for k,v in pairs(arg) do print(k,v) end
-
--- environment
-
-if not environment then environment = { } end
-
-environment.ownbin = environment.ownbin or arg[-2] or arg[-1] or arg[0] or "luatex"
-
-local ownpath = nil -- we could use a metatable here
-
-function environment.ownpath()
-    if not ownpath then
-        for p in string.gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
-            local b = file.join(p,environment.ownbin)
-            if lfs.isfile(b..".exe") or lfs.isfile(b) then
-                ownpath = p
-                break
-            end
-        end
-        if not ownpath then ownpath = '.' end
-    end
-    return ownpath
+function os.setlocale()
+    -- no way you can mess with it
 end
 
 if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then
     arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil
 end
 
-environment.arguments            = { }
-environment.files                = { }
-environment.sorted_argument_keys = nil
-
-environment.platform = os.platform
+environment             = environment or { }
+environment.arguments   = { }
+environment.files       = { }
+environment.sortedflags = nil
 
 function environment.initialize_arguments(arg)
-    environment.arguments = { }
-    environment.files     = { }
-    environment.sorted_argument_keys = nil
+    local arguments, files = { }, { }
+    environment.arguments, environment.files, environment.sortedflags = arguments, files, nil
     for index, argument in pairs(arg) do
         if index > 0 then
             local flag, value = argument:match("^%-+(.+)=(.-)$")
             if flag then
-                environment.arguments[flag] = string.unquote(value or "")
+                arguments[flag] = string.unquote(value or "")
             else
                 flag = argument:match("^%-+(.+)")
                 if flag then
-                    environment.arguments[flag] = true
+                    arguments[flag] = true
                 else
-                    environment.files[#environment.files+1] = argument
+                    files[#files+1] = argument
                 end
             end
         end
@@ -2634,19 +2702,21 @@ function environment.setargument(name,va
     environment.arguments[name] = value
 end
 
-function environment.argument(name)
-    if environment.arguments[name] then
-        return environment.arguments[name]
-    else
-        if not environment.sorted_argument_keys then
-            environment.sorted_argument_keys = { }
-            for _,v in pairs(table.sortedkeys(environment.arguments)) do
-                table.insert(environment.sorted_argument_keys, "^" .. v)
+function environment.argument(name) -- todo: default (plus typecheck on default)
+    local arguments, sortedflags = environment.arguments, environment.sortedflags
+    if arguments[name] then
+        return arguments[name]
+    else
+        if not sortedflags then
+            sortedflags = { }
+            for _,v in pairs(table.sortedkeys(arguments)) do
+                sortedflags[#sortedflags+1] = "^" .. v
             end
+            environment.sortedflags = sortedflags
         end
-        for _,v in pairs(environment.sorted_argument_keys) do
+        for _,v in ipairs(sortedflags) do
             if name:find(v) then
-                return environment.arguments[v:sub(2,#v)]
+                return arguments[v:sub(2,#v)]
             end
         end
     end
@@ -2667,48 +2737,106 @@ function environment.split_arguments(sep
     return before, after
 end
 
-function environment.reconstruct_commandline(arg)
+--~ function environment.reconstruct_commandline(arg)
+--~     if not arg then arg = environment.original_arguments end
+--~     local result = { }
+--~     for _,a in ipairs(arg) do -- ipairs 1 .. #n
+--~         local kk, vv = a:match("^(%-+.-)=(.+)$")
+--~         if kk and vv then
+--~             if vv:find(" ") then
+--~                 vv = vv:unquote()
+--~                 vv = vv:gsub('"','\\"')
+--~                 result[#result+1] = kk .. "=" .. vv:quote()
+--~             else
+--~                 a = a:unquote()
+--~                 a = a:gsub('"','\\"')
+--~                 result[#result+1] = a
+--~             end
+--~         elseif a:find(" ") then
+--~             a = a:unquote()
+--~             a = a:gsub('"','\\"')
+--~             result[#result+1] = a:quote()
+--~         else
+--~             result[#result+1] = a
+--~         end
+--~     end
+--~     return table.join(result," ")
+--~ end
+
+function environment.reconstruct_commandline(arg,noquote)
     if not arg then arg = environment.original_arguments end
-    local result = { }
-    for _,a in ipairs(arg) do -- ipairs 1 .. #n
-        local kk, vv = a:match("^(%-+.-)=(.+)$")
-        if kk and vv then
-            if vv:find(" ") then
-                result[#result+1] = kk .. "=" .. string.quote(vv)
+    if noquote and #arg == 1 then
+        local a = arg[1]
+        a = input.resolve(a)
+        a = a:unquote()
+        return a
+    elseif #arg == 1 then
+        local result = { }
+        for _,a in ipairs(arg) do -- ipairs 1 .. #n
+            a = input.resolve(a)
+            a = a:unquote()
+            a = a:gsub('"','\\"') -- tricky
+            if a:find(" ") then
+                result[#result+1] = a:quote()
             else
                 result[#result+1] = a
             end
-        elseif a:find(" ") then
-            result[#result+1] = string.quote(a)
-        else
-            result[#result+1] = a
         end
+        return table.join(result," ")
     end
-    return table.join(result," ")
 end
 
 if arg then
-    environment.initialize_arguments(arg)
-    environment.original_arguments = arg
+
+    -- new, reconstruct quoted snippets (maybe better just remnove the " then and add them later)
+    local newarg, instring = { }, false
+
+    for index, argument in ipairs(arg) do
+        if argument:find("^\"") then
+            newarg[#newarg+1] = argument:gsub("^\"","")
+            if not argument:find("\"$") then
+                instring = true
+            end
+        elseif argument:find("\"$") then
+            newarg[#newarg] = newarg[#newarg] .. " " .. argument:gsub("\"$","")
+            instring = false
+        elseif instring then
+            newarg[#newarg] = newarg[#newarg] .. " " .. argument
+        else
+            newarg[#newarg+1] = argument
+        end
+    end
+    for i=1,-5,-1 do
+        newarg[i] = arg[i]
+    end
+
+    environment.initialize_arguments(newarg)
+    environment.original_arguments = newarg
+    environment.raw_arguments = arg
+
     arg = { } -- prevent duplicate handling
+
 end
 
 
--- filename : luat-inp.lua
--- comment  : companion to luat-lib.tex
--- author   : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license  : see context related readme files
-
--- This lib is multi-purpose and can be loaded again later on so that
--- additional functionality becomes available. We will split this
--- module in components when we're done with prototyping.
+if not modules then modules = { } end modules ['luat-inp'] = {
+    version   = 1.001,
+    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+    copyright = "PRAGMA ADE / ConTeXt Development Team",
+    license   = "see context related readme files",
+    comment   = "companion to luat-lib.tex",
+}
 
 -- TODO: os.getenv -> os.env[]
 -- TODO: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller)
 -- TODO: check escaping in find etc, too much, too slow
 
--- This is the first code I wrote for LuaTeX, so it needs some cleanup.
+-- This lib is multi-purpose and can be loaded again later on so that
+-- additional functionality becomes available. We will split this
+-- module in components once we're done with prototyping. This is the
+-- first code I wrote for LuaTeX, so it needs some cleanup. Before changing
+-- something in this module one can best check with Taco or Hans first; there
+-- is some nasty trickery going on that relates to traditional kpse support.
 
 -- To be considered: hash key lowercase, first entry in table filename
 -- (any case), rest paths (so no need for optimization). Or maybe a
@@ -2718,12 +2846,6 @@ end
 
 -- Beware, loading and saving is overloaded in luat-tmp!
 
-if not versions    then versions    = { } end versions['luat-inp'] = 1.001
-if not environment then environment = { } end
-if not file        then file        = { } end
-
-if environment.aleph_mode == nil then environment.aleph_mode = true end -- temp hack
-
 if not input            then input            = { } end
 if not input.suffixes   then input.suffixes   = { } end
 if not input.formats    then input.formats    = { } end
@@ -2736,7 +2858,7 @@ if not input.hashers    then input.hashe
 if not input.generators then input.generators = { } end  -- generate databases
 if not input.filters    then input.filters    = { } end  -- conversion filters
 
-local format = string.format
+local format, concat, sortedkeys = string.format, table.concat, table.sortedkeys
 
 input.locators.notfound   = { nil }
 input.hashers.notfound    = { nil }
@@ -2749,8 +2871,16 @@ input.debug        = false
 input.cnfname      = 'texmf.cnf'
 input.luaname      = 'texmfcnf.lua'
 input.lsrname      = 'ls-R'
-input.luasuffix    = '.tma'
-input.lucsuffix    = '.tmc'
+input.homedir      = os.env[os.platform == "windows" and 'USERPROFILE'] or os.env['HOME'] or '~'
+
+--~ input.luasuffix    = 'tma'
+--~ input.lucsuffix    = 'tmc'
+
+-- for the moment we have .local but this will disappear
+input.cnfdefault   = '{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
+
+-- chances are low that the cnf file is in the bin path
+input.cnfdefault   = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
 
 -- we use a cleaned up list / format=any is a wildcard, as is *name
 
@@ -2786,7 +2916,8 @@ input.suffixes['lua'] = { 'lua', 'luc', 
 -- FONTFEATURES  = .;$TEXMF/fonts/fea//
 -- FONTCIDMAPS   = .;$TEXMF/fonts/cid//
 
-function input.checkconfigdata(instance) -- not yet ok, no time for debugging now
+function input.checkconfigdata() -- not yet ok, no time for debugging now
+    local instance = input.instance
     local function fix(varname,default)
         local proname = varname .. "." .. instance.progname or "crap"
         local p = instance.environment[proname]
@@ -2795,7 +2926,15 @@ function input.checkconfigdata(instance)
             instance.variables[varname] = default -- or environment?
         end
     end
-    fix("LUAINPUTS"   , ".;$TEXINPUTS;$TEXMFSCRIPTS")
+    local name = os.name
+    if name == "windows" then
+        fix("OSFONTDIR", "c:/windows/fonts//")
+    elseif name == "macosx" then
+        fix("OSFONTDIR", "$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//")
+    else
+        -- bad luck
+    end
+    fix("LUAINPUTS"   , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm
     fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
     fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
 end
@@ -2822,14 +2961,20 @@ input.formats     ['sfd']               
 input.suffixes    ['sfd']                      = { 'sfd' }
 input.alternatives['subfont definition files'] = 'sfd'
 
-function input.reset()
+-- In practice we will work within one tds tree, but i want to keep
+-- the option open to build tools that look at multiple trees, which is
+-- why we keep the tree specific data in a table. We used to pass the
+-- instance but for practical pusposes we now avoid this and use a
+-- instance variable.
+
+function input.newinstance()
 
     local instance = { }
 
     instance.rootpath        = ''
     instance.treepath        = ''
-    instance.progname        = environment.progname or 'context'
-    instance.engine          = environment.engine   or 'luatex'
+    instance.progname        = 'context'
+    instance.engine          = 'luatex'
     instance.format          = ''
     instance.environment     = { }
     instance.variables       = { }
@@ -2853,12 +2998,12 @@ function input.reset()
     instance.cachepath       = nil
     instance.loaderror       = false
     instance.smallcache      = false
+    instance.sortdata        = false
     instance.savelists       = true
     instance.cleanuppaths    = true
     instance.allresults      = false
     instance.pattern         = nil    -- lists
     instance.kpseonly        = false  -- lists
-    instance.cachefile       = 'tmftools'
     instance.loadtime        = 0
     instance.starttime       = 0
     instance.stoptime        = 0
@@ -2869,23 +3014,13 @@ function input.reset()
     instance.fakepaths       = { }
     instance.lsrmode         = false
 
-    if os.env then
-        -- store once, freeze and faster
-        for k,v in pairs(os.env) do
-            instance.environment[k] = input.bare_variable(v)
-        end
-    else
-        -- we will access os.env frequently
-        for k,v in pairs({'HOME','TEXMF','TEXMFCNF'}) do
-            local e = os.getenv(v)
-            if e then
-            --  input.report("setting",v,"to",input.bare_variable(e))
-                instance.environment[v] = input.bare_variable(e)
-            end
-        end
+    -- store once, freeze and faster (once reset we can best use instance.environment)
+
+    for k,v in pairs(os.env) do
+        instance.environment[k] = input.bare_variable(v)
     end
 
-    -- cross referencing
+    -- cross referencing, delayed because we can add suffixes
 
     for k, v in pairs(input.suffixes) do
         for _, vv in pairs(v) do
@@ -2899,68 +3034,42 @@ function input.reset()
 
 end
 
-function input.reset_hashes(instance)
-    instance.lists = { }
-    instance.found = { }
-end
+input.instance = input.instance or nil
 
-function input.bare_variable(str) -- assumes str is a string
- -- return string.gsub(string.gsub(string.gsub(str,"%s+$",""),'^"(.+)"$',"%1"),"^'(.+)'$","%1")
-    return (str:gsub("\s*([\"\']?)(.+)%1\s*", "%2"))
+function input.reset()
+    input.instance = input.newinstance()
+    return input.instance
 end
 
-if texio then
-    input.log = texio.write_nl
-else
-    input.log = print
+function input.reset_hashes()
+    input.instance.lists = { }
+    input.instance.found = { }
 end
 
-function input.simple_logger(kind, name)
-    if name and name ~= "" then
-        if input.banner then
-            input.log(input.banner..kind..": "..name)
-        else
-            input.log("<<"..kind..": "..name..">>")
-        end
-    else
-        if input.banner then
-            input.log(input.banner..kind..": no name")
-        else
-            input.log("<<"..kind..": no name>>")
-        end
-    end
-end
-
-function input.dummy_logger()
+function input.bare_variable(str) -- assumes str is a string
+ -- return string.gsub(string.gsub(string.gsub(str,"%s+$",""),'^"(.+)"$',"%1"),"^'(.+)'$","%1")
+    return (str:gsub("\s*([\"\']?)(.+)%1\s*", "%2"))
 end
 
 function input.settrace(n)
     input.trace = tonumber(n or 0)
     if input.trace > 0 then
-        input.logger = input.simple_logger
         input.verbose = true
-    else
-        input.logger = function() end
     end
 end
 
-function input.report(...) -- inefficient
+input.log  = (texio and texio.write_nl) or print
+
+function input.report(...)
     if input.verbose then
-        if input.banner then
-            input.log(input.banner .. table.concat({...},' '))
-        elseif input.logmode() == 'xml' then
-            input.log("<t>"..table.concat({...},' ').."</t>")
-        else
-            input.log("<<"..table.concat({...},' ')..">>")
-        end
+        input.log("<<"..format(...)..">>")
     end
 end
 
-function input.reportlines(str)
-    if type(str) == "string" then
-        str = str:split("\n")
+function input.report(...)
+    if input.trace > 0 then -- extra test
+        input.log("<<"..format(...)..">>")
     end
-    for _,v in pairs(str) do input.report(v) end
 end
 
 input.settrace(tonumber(os.getenv("MTX.INPUT.TRACE") or os.getenv("MTX_INPUT_TRACE") or input.trace or 0))
@@ -2989,7 +3098,7 @@ do
                 instance.stoptime = stoptime
                 instance.loadtime = instance.loadtime + loadtime
                 if report then
-                    input.report('load time', format("%0.3f",loadtime))
+                    input.report("load time %0.3f",loadtime)
                 end
                 return loadtime
             end
@@ -3005,18 +3114,18 @@ end
 
 function input.report_loadtime(instance)
     if instance then
-        input.report('total load time', input.elapsedtime(instance))
+        input.report('total load time %s', input.elapsedtime(instance))
     end
 end
 
 input.loadtime = input.elapsedtime
 
-function input.env(instance,key)
-    return instance.environment[key] or input.osenv(instance,key)
+function input.env(key)
+    return input.instance.environment[key] or input.osenv(key)
 end
 
-function input.osenv(instance,key)
-    local ie = instance.environment
+function input.osenv(key)
+    local ie = input.instance.environment
     local value = ie[key]
     if value == nil then
      -- local e = os.getenv(key)
@@ -3034,81 +3143,106 @@ end
 -- we follow a rather traditional approach:
 --
 -- (1) texmf.cnf given in TEXMFCNF
--- (2) texmf.cnf searched in TEXMF/web2c
+-- (2) texmf.cnf searched in default variable
 --
--- for the moment we don't expect a configuration file in a zip
+-- also we now follow the stupid route: if not set then just assume *one*
+-- cnf file under texmf (i.e. distribution)
 
-function input.identify_cnf(instance)
-    -- we no longer support treepath and rootpath (was handy for testing);
-    -- also we now follow the stupid route: if not set then just assume *one*
-    -- cnf file under texmf (i.e. distribution)
-    if #instance.cnffiles == 0 then
-        if input.env(instance,'TEXMFCNF') == "" then
-            local ownpath = environment.ownpath() or "."
-            if ownpath then
-                -- beware, this is tricky on my own system because at that location I do have
-                -- the raw tree that ends up in the zip; i.e. I cannot test this kind of mess
-                local function locate(filename,list)
-                    local ownroot = input.normalize_name(file.join(ownpath,"../.."))
-                    if not lfs.isdir(file.join(ownroot,"texmf")) then
-                        ownroot = input.normalize_name(file.join(ownpath,".."))
-                        if not lfs.isdir(file.join(ownroot,"texmf")) then
-                            input.verbose = true
-                            input.report("error", "unable to identify cnf file")
-                            return
+input.ownpath     = input.ownpath or nil
+input.ownbin      = input.ownbin  or arg[-2] or arg[-1] or arg[0] or "luatex"
+input.autoselfdir = true -- false may be handy for debugging
+
+function input.getownpath()
+    if not input.ownpath then
+        if input.autoselfdir and os.selfdir then
+            input.ownpath = os.selfdir
+        else
+            local binary = input.ownbin
+            if os.platform == "windows" then
+                binary = file.replacesuffix(binary,"exe")
+            end
+            for p in string.gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
+                local b = file.join(p,binary)
+                if lfs.isfile(b) then
+                    -- we assume that after changing to the path the currentdir function
+                    -- resolves to the real location and use this side effect here; this
+                    -- trick is needed because on the mac installations use symlinks in the
+                    -- path instead of real locations
+                    local olddir = lfs.currentdir()
+                    if lfs.chdir(p) then
+                        local pp = lfs.currentdir()
+                        if input.verbose and p ~= pp then
+                            input.report("following symlink %s to %s",p,pp)
                         end
-                    end
-                    local texmfcnf = file.join(ownroot,"texmf-local/web2c",filename) -- for minimals and myself
-                    if not lfs.isfile(texmfcnf) then
-                        texmfcnf = file.join(ownroot,"texmf/web2c",filename)
-                        if not lfs.isfile(texmfcnf) then
-                            input.verbose = true
-                            input.report("error", "unable to locate",filename)
-                            return
+                        input.ownpath = pp
+                        lfs.chdir(olddir)
+                    else
+                        if input.verbose then
+                            input.report("unable to check path %s",p)
                         end
+                        input.ownpath =  p
                     end
-                    table.insert(list,texmfcnf)
-                    local ie = instance.environment
-                    if not ie['SELFAUTOPARENT'] then ie['SELFAUTOPARENT'] = ownroot end
-                    if not ie['TEXMFCNF']       then ie['TEXMFCNF']       = file.dirname(texmfcnf) end
-                end
-                locate(input.luaname,instance.luafiles)
-                locate(input.cnfname,instance.cnffiles)
-                if #instance.luafiles == 0 and instance.cnffiles == 0 then
-                    input.verbose = true
-                    input.report("error", "unable to locate",filename)
-                    os.exit()
+                    break
                 end
-                -- here we also assume then TEXMF is set in the distribution, if this trickery is
-                -- used in the minimals, then users who don't use setuptex are on their own with
-                -- regards to extra trees
-            else
-                input.verbose = true
-                input.report("error", "unable to identify own path")
-                os.exit()
             end
-        else
-            local t = input.split_path(input.env(instance,'TEXMFCNF'))
-            t = input.aux.expanded_path(instance,t)
-            input.aux.expand_vars(instance,t)
-            local function locate(filename,list)
-                for _,v in ipairs(t) do
-                    local texmfcnf = input.normalize_name(file.join(v,filename))
-                    if lfs.isfile(texmfcnf) then
-                        table.insert(list,texmfcnf)
-                    end
+        end
+        if not input.ownpath then input.ownpath = '.' end
+    end
+    return input.ownpath
+end
+
+function input.identify_own()
+    local instance = input.instance
+    local ownpath = input.getownpath() or lfs.currentdir()
+    local ie = instance.environment
+    if ownpath then
+        if input.env('SELFAUTOLOC')    == "" then os.env['SELFAUTOLOC']    = file.collapse_path(ownpath) end
+        if input.env('SELFAUTODIR')    == "" then os.env['SELFAUTODIR']    = file.collapse_path(ownpath .. "/..") end
+        if input.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end
+    else
+        input.verbose = true
+        input.report("error: unable to locate ownpath")
+        os.exit()
+    end
+    if input.env('TEXMFCNF') == "" then os.env['TEXMFCNF'] = input.cnfdefault end
+    if input.env('TEXOS')    == "" then os.env['TEXOS']    = input.env('SELFAUTODIR') end
+    if input.env('TEXROOT')  == "" then os.env['TEXROOT']  = input.env('SELFAUTOPARENT') end
+    if input.verbose then
+        for _,v in ipairs({"SELFAUTOLOC","SELFAUTODIR","SELFAUTOPARENT","TEXMFCNF"}) do
+            input.report("variable %s set to %s",v,input.env(v) or "unknown")
+        end
+    end
+    function input.identify_own() end
+end
+
+function input.identify_cnf()
+    local instance = input.instance
+    if #instance.cnffiles == 0 then
+        -- fallback
+        input.identify_own()
+        -- the real search
+        input.expand_variables()
+        local t = input.split_path(input.env('TEXMFCNF'))
+        t = input.aux.expanded_path(t)
+        input.aux.expand_vars(t) -- redundant
+        local function locate(filename,list)
+            for _,v in ipairs(t) do
+                local texmfcnf = input.normalize_name(file.join(v,filename))
+                if lfs.isfile(texmfcnf) then
+                    table.insert(list,texmfcnf)
                 end
             end
-            locate(input.luaname,instance.luafiles)
-            locate(input.cnfname,instance.cnffiles)
         end
+        locate(input.luaname,instance.luafiles)
+        locate(input.cnfname,instance.cnffiles)
     end
 end
 
-function input.load_cnf(instance)
+function input.load_cnf()
+    local instance = input.instance
     local function loadoldconfigdata()
         for _, fname in ipairs(instance.cnffiles) do
-            input.aux.load_cnf(instance,fname)
+            input.aux.load_cnf(fname)
         end
     end
     -- instance.cnffiles contain complete names now !
@@ -3123,27 +3257,27 @@ function input.load_cnf(instance)
             instance.rootpath = file.dirname(instance.rootpath)
         end
         instance.rootpath = input.normalize_name(instance.rootpath)
-        instance.environment['SELFAUTOPARENT'] = instance.rootpath -- just to be sure
         if instance.lsrmode then
             loadoldconfigdata()
         elseif instance.diskcache and not instance.renewcache then
-            input.loadoldconfig(instance,instance.cnffiles)
+            input.loadoldconfig(instance.cnffiles)
             if instance.loaderror then
                 loadoldconfigdata()
-                input.saveoldconfig(instance)
+                input.saveoldconfig()
             end
         else
             loadoldconfigdata()
             if instance.renewcache then
-                input.saveoldconfig(instance)
+                input.saveoldconfig()
             end
         end
-        input.aux.collapse_cnf_data(instance)
+        input.aux.collapse_cnf_data()
     end
-    input.checkconfigdata(instance)
+    input.checkconfigdata()
 end
 
-function input.load_lua(instance)
+function input.load_lua()
+    local instance = input.instance
     if #instance.luafiles == 0 then
         -- yet harmless
     else
@@ -3155,14 +3289,14 @@ function input.load_lua(instance)
             instance.rootpath = file.dirname(instance.rootpath)
         end
         instance.rootpath = input.normalize_name(instance.rootpath)
-        instance.environment['SELFAUTOPARENT'] = instance.rootpath -- just to be sure
-        input.loadnewconfig(instance)
-        input.aux.collapse_cnf_data(instance)
+        input.loadnewconfig()
+        input.aux.collapse_cnf_data()
     end
-    input.checkconfigdata(instance)
+    input.checkconfigdata()
 end
 
-function input.aux.collapse_cnf_data(instance) -- potential optmization: pass start index (setup and configuration are shared)
+function input.aux.collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared)
+    local instance = input.instance
     for _,c in ipairs(instance.order) do
         for k,v in pairs(c) do
             if not instance.variables[k] then
@@ -3177,21 +3311,22 @@ function input.aux.collapse_cnf_data(ins
     end
 end
 
-function input.aux.load_cnf(instance,fname)
+function input.aux.load_cnf(fname)
+    local instance = input.instance
     fname = input.clean_path(fname)
-    local lname = fname:gsub("%.%a+$",input.luasuffix)
+    local lname = file.replacesuffix(fname,'lua')
     local f = io.open(lname)
     if f then -- this will go
         f:close()
         local dname = file.dirname(fname)
         if not instance.configuration[dname] then
-            input.aux.load_configuration(instance,dname,lname)
+            input.aux.load_configuration(dname,lname)
             instance.order[#instance.order+1] = instance.configuration[dname]
         end
     else
         f = io.open(fname)
         if f then
-            input.report("loading", fname)
+            input.report("loading %s", fname)
             local line, data, n, k, v
             local dname = file.dirname(fname)
             if not instance.configuration[dname] then
@@ -3223,227 +3358,226 @@ function input.aux.load_cnf(instance,fna
             end
             f:close()
         else
-            input.report("skipping", fname)
+            input.report("skipping %s", fname)
         end
     end
 end
 
 -- database loading
 
-function input.load_hash(instance)
-    input.locatelists(instance)
+function input.load_hash()
+    local instance = input.instance
+    input.locatelists()
     if instance.lsrmode then
-        input.loadlists(instance)
+        input.loadlists()
     elseif instance.diskcache and not instance.renewcache then
-        input.loadfiles(instance)
+        input.loadfiles()
         if instance.loaderror then
-            input.loadlists(instance)
-            input.savefiles(instance)
+            input.loadlists()
+            input.savefiles()
         end
     else
-        input.loadlists(instance)
+        input.loadlists()
         if instance.renewcache then
-            input.savefiles(instance)
+            input.savefiles()
         end
     end
 end
 
-function input.aux.append_hash(instance,type,tag,name)
-    input.logger("= hash append",tag)
-    table.insert(instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } )
+function input.aux.append_hash(type,tag,name)
+    if input.trace > 0 then
+        input.logger("= hash append: %s",tag)
+    end
+    table.insert(input.instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } )
 end
 
-function input.aux.prepend_hash(instance,type,tag,name)
-    input.logger("= hash prepend",tag)
-    table.insert(instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } )
+function input.aux.prepend_hash(type,tag,name)
+    if input.trace > 0 then
+        input.logger("= hash prepend: %s",tag)
+    end
+    table.insert(input.instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } )
 end
 
-function input.aux.extend_texmf_var(instance,specification) -- crap
-    if instance.environment['TEXMF'] then
-        input.report("extending environment variable TEXMF with", specification)
-        instance.environment['TEXMF'] = instance.environment['TEXMF']:gsub("^%{", function()
-            return "{" .. specification .. ","
-        end)
-    elseif instance.variables['TEXMF'] then
-        input.report("extending configuration variable TEXMF with", specification)
-        instance.variables['TEXMF'] = instance.variables['TEXMF']:gsub("^%{", function()
-            return "{" .. specification .. ","
-        end)
+function input.aux.extend_texmf_var(specification) -- crap, we could better prepend the hash
+    local instance = input.instance
+--  local t = input.expanded_path_list('TEXMF') -- full expansion
+    local t = input.split_path(input.env('TEXMF'))
+    table.insert(t,1,specification)
+    local newspec = table.join(t,";")
+    if instance.environment["TEXMF"] then
+        instance.environment["TEXMF"] = newspec
+    elseif instance.variables["TEXMF"] then
+        instance.variables["TEXMF"] = newspec
     else
-        input.report("setting configuration variable TEXMF to", specification)
-        instance.variables['TEXMF'] = "{" .. specification .. "}"
+        -- weird
     end
-    if instance.variables['TEXMF']:find("%,") and not instance.variables['TEXMF']:find("^%{") then
-        input.report("adding {} to complex TEXMF variable, best do that yourself")
-        instance.variables['TEXMF'] = "{" .. instance.variables['TEXMF'] .. "}"
-    end
-    input.expand_variables(instance)
-    input.reset_hashes(instance)
+    input.expand_variables()
+    input.reset_hashes()
 end
 
 -- locators
 
-function input.locatelists(instance)
-    for _, path in pairs(input.simplified_list(input.expansion(instance,'TEXMF'))) do
-        path = file.collapse_path(path)
-        input.report("locating list of",path)
-        input.locatedatabase(instance,input.normalize_name(path))
+function input.locatelists()
+    local instance = input.instance
+    for _, path in pairs(input.clean_path_list('TEXMF')) do
+        input.report("locating list of %s",path)
+        input.locatedatabase(input.normalize_name(path))
     end
 end
 
-function input.locatedatabase(instance,specification)
-    return input.methodhandler('locators', instance, specification)
+function input.locatedatabase(specification)
+    return input.methodhandler('locators', specification)
 end
 
-function input.locators.tex(instance,specification)
+function input.locators.tex(specification)
     if specification and specification ~= '' and lfs.isdir(specification) then
-        input.logger('! tex locator', specification..' found')
-        input.aux.append_hash(instance,'file',specification,filename)
-    else
-        input.logger('? tex locator', specification..' not found')
+        if input.trace > 0 then
+            input.logger('! tex locator found: %s',specification)
+        end
+        input.aux.append_hash('file',specification,filename)
+    elseif input.trace > 0 then
+        input.logger('? tex locator not found: %s',specification)
     end
 end
 
 -- hashers
 
-function input.hashdatabase(instance,tag,name)
-    return input.methodhandler('hashers',instance,tag,name)
+function input.hashdatabase(tag,name)
+    return input.methodhandler('hashers',tag,name)
 end
 
-function input.loadfiles(instance)
+function input.loadfiles()
+    local instance = input.instance
     instance.loaderror = false
     instance.files = { }
     if not instance.renewcache then
         for _, hash in ipairs(instance.hashes) do
-            input.hashdatabase(instance,hash.tag,hash.name)
+            input.hashdatabase(hash.tag,hash.name)
             if instance.loaderror then break end
         end
     end
 end
 
-function input.hashers.tex(instance,tag,name)
-    input.aux.load_files(instance,tag)
+function input.hashers.tex(tag,name)
+    input.aux.load_files(tag)
 end
 
 -- generators:
 
-function input.loadlists(instance)
-    for _, hash in ipairs(instance.hashes) do
-        input.generatedatabase(instance,hash.tag)
+function input.loadlists()
+    for _, hash in ipairs(input.instance.hashes) do
+        input.generatedatabase(hash.tag)
     end
 end
 
-function input.generatedatabase(instance,specification)
-    return input.methodhandler('generators', instance, specification)
-end
-
-do
-
-    local weird = lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
-
-    function input.generators.tex(instance,specification)
-        local tag = specification
-        if not instance.lsrmode and lfs and lfs.dir then
-            input.report("scanning path",specification)
-            instance.files[tag] = { }
-            local files = instance.files[tag]
-            local n, m, r = 0, 0, 0
-            local spec = specification .. '/'
-            local attributes = lfs.attributes
-            local directory = lfs.dir
-            local small = instance.smallcache
-            local function action(path)
-                local mode, full
-                if path then
-                    full = spec .. path .. '/'
+function input.generatedatabase(specification)
+    return input.methodhandler('generators', specification)
+end
+
+local weird = lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
+
+function input.generators.tex(specification)
+    local instance = input.instance
+    local tag = specification
+    if not instance.lsrmode and lfs.dir then
+        input.report("scanning path %s",specification)
+        instance.files[tag] = { }
+        local files = instance.files[tag]
+        local n, m, r = 0, 0, 0
+        local spec = specification .. '/'
+        local attributes = lfs.attributes
+        local directory = lfs.dir
+        local small = instance.smallcache
+        local function action(path)
+            local mode, full
+            if path then
+                full = spec .. path .. '/'
+            else
+                full = spec
+            end
+            for name in directory(full) do
+                if name:find("^%.") then
+                  -- skip
+            --  elseif name:find("[%~%`%!%#%$%%%^%&%*%(%)%=%{%}%[%]%:%;\"\'%|%<%>%,%?\n\r\t]") then -- too much escaped
+                elseif weird:match(name) then
+                  -- texio.write_nl("skipping " .. name)
+                  -- skip
                 else
-                    full = spec
-                end
-                for name in directory(full) do
-                    if name:find("^%.") then
-                      -- skip
-                --  elseif name:find("[%~%`%!%#%$%%%^%&%*%(%)%=%{%}%[%]%:%;\"\'%|%<%>%,%?\n\r\t]") then -- too much escaped
-                    elseif weird:match(name) then
-                      -- texio.write_nl("skipping " .. name)
-                      -- skip
-                    else
-                        mode = attributes(full..name,'mode')
-                        if mode == "directory" then
-                            m = m + 1
-                            if path then
-                                action(path..'/'..name)
-                            else
-                                action(name)
-                            end
-                        elseif path and mode == 'file' then
-                            n = n + 1
-                            local f = files[name]
-                            if f then
-                                if not small then
-                                    if type(f) == 'string' then
-                                        files[name] = { f, path }
-                                    else
-                                      f[#f+1] = path
-                                    end
-                                end
-                            else
-                                files[name] = path
-                                local lower = name:lower()
-                                if name ~= lower then
-                                    files["remap:"..lower] = name
-                                    r = r + 1
-                                end
-                            end
+                    mode = attributes(full..name,'mode')
+                    if mode == 'directory' then
+                        m = m + 1
+                        if path then
+                            action(path..'/'..name)
+                        else
+                            action(name)
                         end
-                    end
-                end
-            end
-            action()
-            input.report(format("%s files found on %s directories with %s uppercase remappings",n,m,r))
-        else
-            local fullname = file.join(specification,input.lsrname)
-            local path     = '.'
-            local f        = io.open(fullname)
-            if f then
-                instance.files[tag] = { }
-                local files = instance.files[tag]
-                local small = instance.smallcache
-                input.report("loading lsr file",fullname)
-            --  for line in f:lines() do -- much slower then the next one
-                for line in (f:read("*a")):gmatch("(.-)\n") do
-                    if line:find("^[%a%d]") then
-                        local fl = files[line]
-                        if fl then
+                    elseif path and mode == 'file' then
+                        n = n + 1
+                        local f = files[name]
+                        if f then
                             if not small then
-                                if type(fl) == 'string' then
-                                    files[line] = { fl, path } -- table
+                                if type(f) == 'string' then
+                                    files[name] = { f, path }
                                 else
-                                    fl[#fl+1] = path
+                                  f[#f+1] = path
                                 end
                             end
                         else
-                            files[line] = path -- string
-                            local lower = line:lower()
-                            if line ~= lower then
-                                files["remap:"..lower] = line
+                            files[name] = path
+                            local lower = name:lower()
+                            if name ~= lower then
+                                files["remap:"..lower] = name
+                                r = r + 1
+                            end
+                        end
+                    end
+                end
+            end
+        end
+        action()
+        input.report("%s files found on %s directories with %s uppercase remappings",n,m,r)
+    else
+        local fullname = file.join(specification,input.lsrname)
+        local path     = '.'
+        local f        = io.open(fullname)
+        if f then
+            instance.files[tag] = { }
+            local files = instance.files[tag]
+            local small = instance.smallcache
+            input.report("loading lsr file %s",fullname)
+        --  for line in f:lines() do -- much slower then the next one
+            for line in (f:read("*a")):gmatch("(.-)\n") do
+                if line:find("^[%a%d]") then
+                    local fl = files[line]
+                    if fl then
+                        if not small then
+                            if type(fl) == 'string' then
+                                files[line] = { fl, path } -- table
+                            else
+                                fl[#fl+1] = path
                             end
                         end
                     else
-                        path = line:match("%.%/(.-)%:$") or path -- match could be nil due to empty line
+                        files[line] = path -- string
+                        local lower = line:lower()
+                        if line ~= lower then
+                            files["remap:"..lower] = line
+                        end
                     end
+                else
+                    path = line:match("%.%/(.-)%:$") or path -- match could be nil due to empty line
                 end
-                f:close()
             end
+            f:close()
         end
     end
-
 end
 
 -- savers, todo
 
-function input.savefiles(instance)
-    input.aux.save_data(instance, 'files', function(k,v)
-        return instance.validfile(k,v) -- path, name
+function input.savefiles()
+    input.aux.save_data('files', function(k,v)
+        return input.instance.validfile(k,v) -- path, name
     end)
 end
 
@@ -3451,8 +3585,8 @@ end
 -- we join them and split them after the expansion has taken place. This
 -- is more convenient.
 
-function input.splitconfig(instance)
-    for i,c in ipairs(instance) do
+function input.splitconfig()
+    for i,c in ipairs(input.instance) do
         for k,v in pairs(c) do
             if type(v) == 'string' then
                 local t = file.split_path(v)
@@ -3463,8 +3597,9 @@ function input.splitconfig(instance)
         end
     end
 end
-function input.joinconfig(instance)
-    for i,c in ipairs(instance.order) do
+
+function input.joinconfig()
+    for i,c in ipairs(input.instance.order) do
         for k,v in pairs(c) do
             if type(v) == 'table' then
                 c[k] = file.join_path(v)
@@ -3487,8 +3622,9 @@ function input.join_path(str)
     end
 end
 
-function input.splitexpansions(instance)
-    for k,v in pairs(instance.expansions) do
+function input.splitexpansions()
+    local ie = input.instance.expansions
+    for k,v in pairs(ie) do
         local t, h = { }, { }
         for _,vv in pairs(file.split_path(v)) do
             if vv ~= "" and not h[vv] then
@@ -3497,19 +3633,19 @@ function input.splitexpansions(instance)
             end
         end
         if #t > 1 then
-            instance.expansions[k] = t
+            ie[k] = t
         else
-            instance.expansions[k] = t[1]
+            ie[k] = t[1]
         end
     end
 end
 
 -- end of split/join code
 
-function input.saveoldconfig(instance)
-    input.splitconfig(instance)
-    input.aux.save_data(instance, 'configuration', nil)
-    input.joinconfig(instance)
+function input.saveoldconfig()
+    input.splitconfig()
+    input.aux.save_data('configuration', nil)
+    input.joinconfig()
 end
 
 input.configbanner = [[
@@ -3526,8 +3662,6 @@ function input.serialize(files)
     -- luatools and mtxtools are called frequently. Okay,
     -- we pay a small price for properly tabbed tables.
     local t = { }
-    local concat = table.concat
-    local sorted = table.sortedkeys
     local function dump(k,v,m)
         if type(v) == 'string' then
             return m .. "['" .. k .. "']='" .. v .. "',"
@@ -3538,12 +3672,12 @@ function input.serialize(files)
         end
     end
     t[#t+1] = "return {"
-    if instance.sortdata then
-        for _, k in pairs(sorted(files)) do
+    if input.instance.sortdata then
+        for _, k in pairs(sortedkeys(files)) do
             local fk  = files[k]
             if type(fk) == 'table' then
                 t[#t+1] = "\t['" .. k .. "']={"
-                for _, kk in pairs(sorted(fk)) do
+                for _, kk in pairs(sortedkeys(fk)) do
                     t[#t+1] = dump(kk,fk[kk],"\t\t")
                 end
                 t[#t+1] = "\t},"
@@ -3570,11 +3704,11 @@ end
 
 if not texmf then texmf = {} end -- no longer needed, at least not here
 
-function input.aux.save_data(instance, dataname, check, makename) -- untested without cache overload
-    for cachename, files in pairs(instance[dataname]) do
+function input.aux.save_data(dataname, check, makename) -- untested without cache overload
+    for cachename, files in pairs(input.instance[dataname]) do
         local name = (makename or file.join)(cachename,dataname)
-        local luaname, lucname = name .. input.luasuffix, name .. input.lucsuffix
-        input.report("preparing " .. dataname .. " for", luaname)
+        local luaname, lucname = name .. ".lua", name .. ".luc"
+        input.report("preparing %s for %s",dataname,cachename)
         for k, v in pairs(files) do
             if not check or check(v,k) then -- path, name
                 if type(v) == "table" and #v == 1 then
@@ -3592,38 +3726,38 @@ function input.aux.save_data(instance, d
             time    = os.date("%H:%M:%S"),
             content = files,
         }
-        local f = io.open(luaname,'w')
-        if f then
-            input.report("saving " .. dataname .. " in", luaname)
-            f:write(input.serialize(data))
-            f:close()
-            input.report("compiling " .. dataname .. " to", lucname)
-            if not utils.lua.compile(luaname,lucname) then
-                input.report("compiling failed for " .. dataname .. ", deleting file " .. lucname)
+        local ok = io.savedata(luaname,input.serialize(data))
+        if ok then
+            input.report("%s saved in %s",dataname,luaname)
+            if utils.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip
+                input.report("%s compiled to %s",dataname,lucname)
+            else
+                input.report("compiling failed for %s, deleting file %s",dataname,lucname)
                 os.remove(lucname)
             end
         else
-            input.report("unable to save " .. dataname .. " in " .. name..input.luasuffix)
+            input.report("unable to save %s in %s (access error)",dataname,luaname)
         end
     end
 end
 
-function input.aux.load_data(instance,pathname,dataname,filename,makename) -- untested without cache overload
+function input.aux.load_data(pathname,dataname,filename,makename) -- untested without cache overload
+    local instance = input.instance
     filename = ((not filename or (filename == "")) and dataname) or filename
     filename = (makename and makename(dataname,filename)) or file.join(pathname,filename)
-    local blob = loadfile(filename .. input.lucsuffix) or loadfile(filename .. input.luasuffix)
+    local blob = loadfile(filename .. ".luc") or loadfile(filename .. ".lua")
     if blob then
         local data = blob()
         if data and data.content and data.type == dataname and data.version == input.cacheversion then
-            input.report("loading",dataname,"for",pathname,"from",filename)
+            input.report("loading %s for %s from %s",dataname,pathname,filename)
             instance[dataname][pathname] = data.content
         else
-            input.report("skipping",dataname,"for",pathname,"from",filename)
+            input.report("skipping %s for %s from %s",dataname,pathname,filename)
             instance[dataname][pathname] = { }
             instance.loaderror = true
         end
     else
-        input.report("skipping",dataname,"for",pathname,"from",filename)
+        input.report("skipping %s for %s from %s",dataname,pathname,filename)
     end
 end
 
@@ -3636,13 +3770,14 @@ end
 --     TEXMFBOGUS = 'effe checken of dit werkt',
 -- }
 
-function input.aux.load_texmfcnf(instance,dataname,pathname)
+function input.aux.load_texmfcnf(dataname,pathname)
+    local instance = input.instance
     local filename = file.join(pathname,input.luaname)
     local blob = loadfile(filename)
     if blob then
         local data = blob()
         if data then
-            input.report("loading","configuration file",filename)
+            input.report("loading configuration file %s",filename)
             if true then
                 -- flatten to variable.progname
                 local t = { }
@@ -3662,172 +3797,168 @@ function input.aux.load_texmfcnf(instanc
                 instance[dataname][pathname] = data
             end
         else
-            input.report("skipping","configuration file",filename)
+            input.report("skipping configuration file %s",filename)
             instance[dataname][pathname] = { }
             instance.loaderror = true
         end
     else
-        input.report("skipping","configuration file",filename)
+        input.report("skipping configuration file %s",filename)
     end
 end
 
-function input.aux.load_configuration(instance,dname,lname)
-    input.aux.load_data(instance,dname,'configuration',lname and file.basename(lname))
+function input.aux.load_configuration(dname,lname)
+    input.aux.load_data(dname,'configuration',lname and file.basename(lname))
 end
-function input.aux.load_files(instance,tag)
-    input.aux.load_data(instance,tag,'files')
+function input.aux.load_files(tag)
+    input.aux.load_data(tag,'files')
 end
 
-function input.resetconfig(instance)
+function input.resetconfig()
+    input.identify_own()
+    local instance = input.instance
     instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false
 end
 
-function input.loadnewconfig(instance)
+function input.loadnewconfig()
+    local instance = input.instance
     for _, cnf in ipairs(instance.luafiles) do
         local dname = file.dirname(cnf)
-        input.aux.load_texmfcnf(instance,'setup',dname)
+        input.aux.load_texmfcnf('setup',dname)
         instance.order[#instance.order+1] = instance.setup[dname]
         if instance.loaderror then break end
     end
 end
 
-function input.loadoldconfig(instance)
+function input.loadoldconfig()
+    local instance = input.instance
     if not instance.renewcache then
         for _, cnf in ipairs(instance.cnffiles) do
             local dname = file.dirname(cnf)
-            input.aux.load_configuration(instance,dname)
+            input.aux.load_configuration(dname)
             instance.order[#instance.order+1] = instance.configuration[dname]
             if instance.loaderror then break end
         end
     end
-    input.joinconfig(instance)
+    input.joinconfig()
 end
 
-function input.expand_variables(instance)
-    instance.expansions = { }
---~ instance.environment['SELFAUTOPARENT'] = instance.environment['SELFAUTOPARENT'] or instance.rootpath
-    if instance.engine   ~= "" then instance.environment['engine']   = instance.engine   end
-    if instance.progname ~= "" then instance.environment['progname'] = instance.progname end
-    for k,v in pairs(instance.environment) do
+function input.expand_variables()
+    local instance = input.instance
+    local expansions, environment, variables = { }, instance.environment, instance.variables
+    local env = input.env
+    instance.expansions = expansions
+    if instance.engine   ~= "" then environment['engine']   = instance.engine   end
+    if instance.progname ~= "" then environment['progname'] = instance.progname end
+    for k,v in pairs(environment) do
         local a, b = k:match("^(%a+)%_(.*)%s*$")
         if a and b then
-            instance.expansions[a..'.'..b] = v
+            expansions[a..'.'..b] = v
         else
-            instance.expansions[k] = v
+            expansions[k] = v
         end
     end
-    for k,v in pairs(instance.environment) do -- move environment to expansions
-        if not instance.expansions[k] then instance.expansions[k] = v end
+    for k,v in pairs(environment) do -- move environment to expansions
+        if not expansions[k] then expansions[k] = v end
     end
-    for k,v in pairs(instance.variables) do -- move variables to expansions
-        if not instance.expansions[k] then instance.expansions[k] = v end
+    for k,v in pairs(variables) do -- move variables to expansions
+        if not expansions[k] then expansions[k] = v end
     end
     while true do
         local busy = false
-        for k,v in pairs(instance.expansions) do
+        for k,v in pairs(expansions) do
             local s, n = v:gsub("%$([%a%d%_%-]+)", function(a)
                 busy = true
-                return instance.expansions[a] or input.env(instance,a)
+                return expansions[a] or env(a)
             end)
             local s, m = s:gsub("%$%{([%a%d%_%-]+)%}", function(a)
                 busy = true
-                return instance.expansions[a] or input.env(instance,a)
+                return expansions[a] or env(a)
             end)
             if n > 0 or m > 0 then
-                instance.expansions[k]= s
+                expansions[k]= s
             end
         end
         if not busy then break end
     end
-    local homedir = 
-       instance.environment[(os.type == "windows" and 'USERPROFILE') or 'HOME'] or '~'
-    for k,v in pairs(instance.expansions) do
-        v = v:gsub("^~", homedir) 
-        instance.expansions[k] = v:gsub("\\", '/')
+    for k,v in pairs(expansions) do
+        expansions[k] = v:gsub("\\", '/')
     end
 end
 
-function input.aux.expand_vars(instance,lst) -- simple vars
+function input.aux.expand_vars(lst) -- simple vars
+    local instance = input.instance
+    local variables, env = instance.variables, input.env
     for k,v in pairs(lst) do
         lst[k] = v:gsub("%$([%a%d%_%-]+)", function(a)
-            return instance.variables[a] or input.env(instance,a)
+            return variables[a] or env(a)
         end)
     end
 end
 
-function input.aux.expanded_var(instance,var) -- simple vars
+function input.aux.expanded_var(var) -- simple vars
+    local instance = input.instance
     return var:gsub("%$([%a%d%_%-]+)", function(a)
-        return instance.variables[a] or input.env(instance,a)
+        return instance.variables[a] or input.env(a)
     end)
 end
 
-function input.aux.entry(instance,entries,name)
+function input.aux.entry(entries,name)
     if name and (name ~= "") then
+        local instance = input.instance
         name = name:gsub('%$','')
         local result = entries[name..'.'..instance.progname] or entries[name]
         if result then
             return result
         else
-            result = input.env(instance,name)
+            result = input.env(name)
             if result then
                 instance.variables[name] = result
-                input.expand_variables(instance)
+                input.expand_variables()
                 return instance.expansions[name] or ""
             end
         end
     end
     return ""
 end
-function input.variable(instance,name)
-    return input.aux.entry(instance,instance.variables,name)
+function input.variable(name)
+    return input.aux.entry(input.instance.variables,name)
 end
-function input.expansion(instance,name)
-    return input.aux.entry(instance,instance.expansions,name)
+function input.expansion(name)
+    return input.aux.entry(input.instance.expansions,name)
 end
 
-function input.aux.is_entry(instance,entries,name)
+function input.aux.is_entry(entries,name)
     if name and name ~= "" then
         name = name:gsub('%$','')
-        return (entries[name..'.'..instance.progname] or entries[name]) ~= nil
+        return (entries[name..'.'..input.instance.progname] or entries[name]) ~= nil
     else
         return false
     end
 end
 
-function input.is_variable(instance,name)
-    return input.aux.is_entry(instance,instance.variables,name)
-end
-function input.is_expansion(instance,name)
-    return input.aux.is_entry(instance,instance.expansions,name)
+function input.is_variable(name)
+    return input.aux.is_entry(input.instance.variables,name)
 end
 
-function input.simplified_list(str)
-    if type(str) == 'table' then
-        return str -- troubles ; ipv , in texmf
-    elseif str == '' then
-        return { }
-    else
-        local t = { }
-        for _,v in ipairs(string.splitchr(str:gsub("^\{(.+)\}$","%1"),",")) do
-            t[#t+1] = (v:gsub("^[%!]*(.+)[%/\\]*$","%1"))
-        end
-        return t
-    end
+function input.is_expansion(name)
+    return input.aux.is_entry(input.instance.expansions,name)
 end
 
-function input.unexpanded_path_list(instance,str)
-    local pth = input.variable(instance,str)
+function input.unexpanded_path_list(str)
+    local pth = input.variable(str)
     local lst = input.split_path(pth)
-    return input.aux.expanded_path(instance,lst)
+    return input.aux.expanded_path(lst)
 end
-function input.unexpanded_path(instance,str)
-    return file.join_path(input.unexpanded_path_list(instance,str))
+
+function input.unexpanded_path(str)
+    return file.join_path(input.unexpanded_path_list(str))
 end
 
 do
     local done = { }
 
-    function input.reset_extra_path(instance)
+    function input.reset_extra_path()
+        local instance = input.instance
         local ep = instance.extra_paths
         if not ep then
             ep, done = { }, { }
@@ -3837,7 +3968,8 @@ do
         end
     end
 
-    function input.register_extra_path(instance,paths,subpaths)
+    function input.register_extra_path(paths,subpaths)
+        local instance = input.instance
         local ep = instance.extra_paths or { }
         local n = #ep
         if paths and paths ~= "" then
@@ -3882,7 +4014,8 @@ do
 
 end
 
-function input.expanded_path_list(instance,str)
+function input.expanded_path_list(str)
+    local instance = input.instance
     local function made_list(list)
         local ep = instance.extra_paths
         if not ep or #ep == 0 then
@@ -3923,39 +4056,41 @@ function input.expanded_path_list(instan
         -- engine+progname hash
         str = str:gsub("%$","")
         if not instance.lists[str] then -- cached
-            local lst = made_list(input.split_path(input.expansion(instance,str)))
-            instance.lists[str] = input.aux.expanded_path(instance,lst)
+            local lst = made_list(input.split_path(input.expansion(str)))
+            instance.lists[str] = input.aux.expanded_path(lst)
         end
         return instance.lists[str]
     else
-        local lst = input.split_path(input.expansion(instance,str))
-        return made_list(input.aux.expanded_path(instance,lst))
+        local lst = input.split_path(input.expansion(str))
+        return made_list(input.aux.expanded_path(lst))
     end
 end
 
-function input.expand_path(instance,str)
-    return file.join_path(input.expanded_path_list(instance,str))
+
+function input.clean_path_list(str)
+    local t = input.expanded_path_list(str)
+    if t then
+        for i=1,#t do
+            t[i] = file.collapse_path(input.clean_path(t[i]))
+        end
+    end
+    return t
 end
 
---~ function input.first_writable_path(instance,name)
---~     for _,v in pairs(input.expanded_path_list(instance,name)) do
---~         if file.is_writable(file.join(v,'luatex-cache.tmp')) then
---~             return v
---~         end
---~     end
---~     return "."
---~ end
+function input.expand_path(str)
+    return file.join_path(input.expanded_path_list(str))
+end
 
-function input.expanded_path_list_from_var(instance,str) -- brrr
+function input.expanded_path_list_from_var(str) -- brrr
     local tmp = input.var_of_format_or_suffix(str:gsub("%$",""))
     if tmp ~= "" then
-        return input.expanded_path_list(instance,str)
+        return input.expanded_path_list(str)
     else
-        return input.expanded_path_list(instance,tmp)
+        return input.expanded_path_list(tmp)
     end
 end
-function input.expand_path_from_var(instance,str)
-    return file.join_path(input.expanded_path_list_from_var(instance,str))
+function input.expand_path_from_var(str)
+    return file.join_path(input.expanded_path_list_from_var(str))
 end
 
 function input.format_of_var(str)
@@ -3985,9 +4120,9 @@ function input.var_of_format_or_suffix(s
     return ''
 end
 
-function input.expand_braces(instance,str) -- output variable and brace expansion of STRING
-    local ori = input.variable(instance,str)
-    local pth = input.aux.expanded_path(instance,input.split_path(ori))
+function input.expand_braces(str) -- output variable and brace expansion of STRING
+    local ori = input.variable(str)
+    local pth = input.aux.expanded_path(input.split_path(ori))
     return file.join_path(pth)
 end
 
@@ -4002,6 +4137,7 @@ end
 -- {a,b,c/{p,q,r}/d/{x,y,z}//}
 -- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}}
 -- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}}
+-- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}
 
 -- this one is better and faster, but it took me a while to realize
 -- that this kind of replacement is cleaner than messy parsing and
@@ -4010,19 +4146,19 @@ end
 -- work that well; the parsing is ok, but dealing with the resulting
 -- table is a pain because we need to work inside-out recursively
 
--- get rid of piecewise here, just a gmatch is ok
-
 function input.aux.splitpathexpr(str, t, validate)
     -- no need for optimization, only called a few times, we can use lpeg for the sub
     t = t or { }
-    local concat = table.concat
+    str = str:gsub(",}",",@}")
+    str = str:gsub("{,","{@,")
+ -- str = "@" .. str .. "@"
     while true do
         local done = false
         while true do
             local ok = false
-            str = str:gsub("([^{},]+){([^{}]-)}", function(a,b)
+            str = str:gsub("([^{},]+){([^{}]+)}", function(a,b)
                 local t = { }
-                b:piecewise(",", function(s) t[#t+1] = a .. s end)
+                for s in b:gmatch("[^,]+") do t[#t+1] = a .. s end
                 ok, done = true, true
                 return "{" .. concat(t,",") .. "}"
             end)
@@ -4030,9 +4166,9 @@ function input.aux.splitpathexpr(str, t,
         end
         while true do
             local ok = false
-            str = str:gsub("{([^{}]-)}([^{},]+)", function(a,b)
+            str = str:gsub("{([^{}]+)}([^{},]+)", function(a,b)
                 local t = { }
-                a:piecewise(",", function(s) t[#t+1] = s .. b end)
+                for s in a:gmatch("[^,]+") do t[#t+1] = s .. b end
                 ok, done = true, true
                 return "{" .. concat(t,",") .. "}"
             end)
@@ -4040,50 +4176,41 @@ function input.aux.splitpathexpr(str, t,
         end
         while true do
             local ok = false
-            str = str:gsub("([,{]){([^{}]+)}([,}])", function(a,b,c)
+            str = str:gsub("{([^{}]+)}{([^{}]+)}", function(a,b)
+                local t = { }
+                for sa in a:gmatch("[^,]+") do
+                    for sb in b:gmatch("[^,]+") do
+                        t[#t+1] = sa .. sb
+                    end
+                end
                 ok, done = true, true
-                return a .. b .. c
+                return "{" .. concat(t,",") .. "}"
             end)
             if not ok then break end
         end
-        if not done then break end
-    end
-    while true do
-        local ok = false
-        str = str:gsub("{([^{}]-)}{([^{}]-)}", function(a,b)
-            local t = { }
-            a:piecewise(",", function(sa)
-                b:piecewise(",", function(sb)
-                    t[#t+1] = sa .. sb
-                end)
-            end)
-            ok = true
-            return "{" .. concat(t,",") .. "}"
-        end)
-        if not ok then break end
-    end
-    while true do
-        local ok = false
-        str = str:gsub("{([^{}]-)}", function(a)
-            ok = true
-            return a
+        str = str:gsub("({[^{}]*){([^{}]+)}([^{}]*})", function(a,b,c)
+            done = true
+            return a .. b.. c
         end)
-        if not ok then break end
+        if not done then break end
     end
+    str = str:gsub("[{}]", "")
+    str = str:gsub("@","")
     if validate then
-        str:piecewise(",", function(s)
+        for s in str:gmatch("[^,]+") do
             s = validate(s)
             if s then t[#t+1] = s end
-        end)
+        end
     else
-        str:piecewise(",", function(s)
+        for s in str:gmatch("[^,]+") do
             t[#t+1] = s
-        end)
+        end
     end
     return t
 end
 
-function input.aux.expanded_path(instance,pathlist) -- maybe not a list, just a path
+function input.aux.expanded_path(pathlist) -- maybe not a list, just a path
+    local instance = input.instance
     -- a previous version fed back into pathlist
     local newlist, ok = { }, false
     for _,v in ipairs(pathlist) do
@@ -4115,17 +4242,16 @@ input.is_readable = { }
 function input.aux.is_readable(readable, name)
     if input.trace > 2 then
         if readable then
-            input.logger("+ readable", name)
+            input.logger("+ readable: %s",name)
         else
-            input.logger("- readable", name)
+            input.logger("- readable: %s", name)
         end
     end
     return readable
 end
 
 function input.is_readable.file(name)
- -- return input.aux.is_readable(file.is_readable(name), name)
-    return input.aux.is_readable(input.aux.is_file(name), name)
+    return input.aux.is_readable(lfs.isfile(name), name)
 end
 
 input.is_readable.tex = input.is_readable.file
@@ -4133,12 +4259,13 @@ input.is_readable.tex = input.is_readabl
 -- name
 -- name/name
 
-function input.aux.collect_files(instance,names)
+function input.aux.collect_files(names)
+    local instance = input.instance
     local filelist = { }
     for _, fname in pairs(names) do
         if fname then
             if input.trace > 2 then
-                input.logger("? blobpath asked",fname)
+                input.logger("? blobpath asked: %s",fname)
             end
             local bname = file.basename(fname)
             local dname = file.dirname(fname)
@@ -4152,7 +4279,7 @@ function input.aux.collect_files(instanc
                 local files = blobpath and instance.files[blobpath]
                 if files then
                     if input.trace > 2 then
-                        input.logger('? blobpath do',blobpath .. " (" .. bname ..")")
+                        input.logger('? blobpath do: %s (%s)',blobpath,bname)
                     end
                     local blobfile = files[bname]
                     if not blobfile then
@@ -4185,7 +4312,7 @@ function input.aux.collect_files(instanc
                         end
                     end
                 elseif input.trace > 1 then
-                    input.logger('! blobpath no',blobpath .. " (" .. bname ..")" )
+                    input.logger('! blobpath no: %s (%s)',blobpath,bname)
                 end
             end
         end
@@ -4240,15 +4367,17 @@ do
 
 end
 
-function input.aux.register_in_trees(instance,name)
+function input.aux.register_in_trees(name)
     if not name:find("^%.") then
+        local instance = input.instance
         instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one
     end
 end
 
 -- split the next one up, better for jit
 
-function input.aux.find_file(instance,filename) -- todo : plugin (scanners, checkers etc)
+function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc)
+    local instance = input.instance
     local result = { }
     local stamp  = nil
     filename = input.normalize_name(filename)  -- elsewhere
@@ -4257,16 +4386,22 @@ function input.aux.find_file(instance,fi
     if instance.remember then
         stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format
         if instance.found[stamp] then
-            input.logger('! remembered', filename)
+            if input.trace > 0 then
+                input.logger('! remembered: %s',filename)
+            end
             return instance.found[stamp]
         end
     end
     if filename:find('%*') then
-        input.logger('! wildcard', filename)
-        result = input.find_wildcard_files(instance,filename)
+        if input.trace > 0 then
+            input.logger('! wildcard: %s', filename)
+        end
+        result = input.find_wildcard_files(filename)
     elseif input.aux.qualified_path(filename) then
         if input.is_readable.file(filename) then
-            input.logger('! qualified', filename)
+            if input.trace > 0 then
+                input.logger('! qualified: %s', filename)
+            end
             result = { filename }
         else
             local forcedname, ok = "", false
@@ -4274,22 +4409,26 @@ function input.aux.find_file(instance,fi
                 if instance.format == "" then
                     forcedname = filename .. ".tex"
                     if input.is_readable.file(forcedname) then
-                        input.logger('! no suffix, forcing standard filetype tex')
+                        if input.trace > 0 then
+                            input.logger('! no suffix, forcing standard filetype: tex')
+                        end
                         result, ok = { forcedname }, true
                     end
                 else
                     for _, s in pairs(input.suffixes_of_format(instance.format)) do
                         forcedname = filename .. "." .. s
                         if input.is_readable.file(forcedname) then
-                            input.logger('! no suffix, forcing format filetype', s)
+                            if input.trace > 0 then
+                                input.logger('! no suffix, forcing format filetype: %s', s)
+                            end
                             result, ok = { forcedname }, true
                             break
                         end
                     end
                 end
             end
-            if not ok then
-                input.logger('? qualified', filename)
+            if not ok and input.trace > 0 then
+                input.logger('? qualified: %s', filename)
             end
         end
     else
@@ -4307,10 +4446,14 @@ function input.aux.find_file(instance,fi
                 local forcedname = filename .. '.tex'
                 wantedfiles[#wantedfiles+1] = forcedname
                 filetype = input.format_of_suffix(forcedname)
-                input.logger('! forcing filetype',filetype)
+                    if input.trace > 0 then
+                        input.logger('! forcing filetype: %s',filetype)
+                    end
             else
                 filetype = input.format_of_suffix(filename)
-                input.logger('! using suffix based filetype',filetype)
+                if input.trace > 0 then
+                    input.logger('! using suffix based filetype: %s',filetype)
+                end
             end
         else
             if ext == "" then
@@ -4319,16 +4462,18 @@ function input.aux.find_file(instance,fi
                 end
             end
             filetype = instance.format
-            input.logger('! using given filetype',filetype)
+            if input.trace > 0 then
+                input.logger('! using given filetype: %s',filetype)
+            end
         end
         local typespec = input.variable_of_format(filetype)
-        local pathlist = input.expanded_path_list(instance,typespec)
+        local pathlist = input.expanded_path_list(typespec)
         if not pathlist or #pathlist == 0 then
             -- no pathlist, access check only / todo == wildcard
             if input.trace > 2 then
-                input.logger('? filename',filename)
-                input.logger('? filetype',filetype or '?')
-                input.logger('? wanted files',table.concat(wantedfiles," | "))
+                input.logger('? filename: %s',filename)
+                input.logger('? filetype: %s',filetype or '?')
+                input.logger('? wanted files: %s',concat(wantedfiles," | "))
             end
             for _, fname in pairs(wantedfiles) do
                 if fname and input.is_readable.file(fname) then
@@ -4338,7 +4483,7 @@ function input.aux.find_file(instance,fi
                 end
             end
             -- this is actually 'other text files' or 'any' or 'whatever'
-            local filelist = input.aux.collect_files(instance,wantedfiles)
+            local filelist = input.aux.collect_files(wantedfiles)
             local fl = filelist and filelist[1]
             if fl then
                 filename = fl[3]
@@ -4347,12 +4492,12 @@ function input.aux.find_file(instance,fi
             end
         else
             -- list search
-            local filelist = input.aux.collect_files(instance,wantedfiles)
+            local filelist = input.aux.collect_files(wantedfiles)
             local doscan, recurse
             if input.trace > 2 then
-                input.logger('? filename',filename)
-            --                if pathlist then input.logger('? path list',table.concat(pathlist," | ")) end
-            --                if filelist then input.logger('? file list',table.concat(filelist," | ")) end
+                input.logger('? filename: %s',filename)
+            --                if pathlist then input.logger('? path list: %s',concat(pathlist," | ")) end
+            --                if filelist then input.logger('? file list: %s',concat(filelist," | ")) end
             end
             -- a bit messy ... esp the doscan setting here
             for _, path in pairs(pathlist) do
@@ -4373,11 +4518,11 @@ function input.aux.find_file(instance,fi
                         if f:find(expr) then
                             -- input.debug('T',' '..f)
                             if input.trace > 2 then
-                                input.logger('= found in hash',f)
+                                input.logger('= found in hash: %s',f)
                             end
                             --- todo, test for readable
                             result[#result+1] = fl[3]
-                            input.aux.register_in_trees(instance,f) -- for tracing used files
+                            input.aux.register_in_trees(f) -- for tracing used files
                             done = true
                             if not instance.allresults then break end
                         else
@@ -4391,12 +4536,12 @@ function input.aux.find_file(instance,fi
                         local pname = pathname:gsub("%.%*$",'')
                         if not pname:find("%*") then
                             local ppname = pname:gsub("/+$","")
-                            if input.aux.can_be_dir(instance,ppname) then
+                            if input.aux.can_be_dir(ppname) then
                                 for _, w in pairs(wantedfiles) do
                                     local fname = file.join(ppname,w)
                                     if input.is_readable.file(fname) then
                                         if input.trace > 2 then
-                                            input.logger('= found by scanning',fname)
+                                            input.logger('= found by scanning: %s',fname)
                                         end
                                         result[#result+1] = fname
                                         done = true
@@ -4425,40 +4570,29 @@ function input.aux.find_file(instance,fi
     return result
 end
 
-input.aux._find_file_ = input.aux.find_file
+input.aux._find_file_ = input.aux.find_file -- frozen variant
 
-function input.aux.find_file(instance,filename) -- maybe make a lowres cache too
-    local result = input.aux._find_file_(instance,filename)
+function input.aux.find_file(filename) -- maybe make a lowres cache too
+    local result = input.aux._find_file_(filename)
     if #result == 0 then
         local lowered = filename:lower()
         if filename ~= lowered then
-            return input.aux._find_file_(instance,lowered)
+            return input.aux._find_file_(lowered)
         end
     end
     return result
 end
 
-if lfs and lfs.isfile then
-    input.aux.is_file = lfs.isfile      -- to be done: use this
-else
-    input.aux.is_file = file.is_readable
-end
-
-if lfs and lfs.isdir then
-    function input.aux.can_be_dir(instance,name)
-        if not instance.fakepaths[name] then
-            if lfs.isdir(name) then
-                instance.fakepaths[name] = 1 -- directory
-            else
-                instance.fakepaths[name] = 2 -- no directory
-            end
+function input.aux.can_be_dir(name)
+    local instance = input.instance
+    if not instance.fakepaths[name] then
+        if lfs.isdir(name) then
+            instance.fakepaths[name] = 1 -- directory
+        else
+            instance.fakepaths[name] = 2 -- no directory
         end
-        return (instance.fakepaths[name] == 1)
-    end
-else
-    function input.aux.can_be_dir()
-        return true
     end
+    return (instance.fakepaths[name] == 1)
 end
 
 if not input.concatinators  then input.concatinators = { } end
@@ -4466,7 +4600,8 @@ if not input.concatinators  then input.c
 input.concatinators.tex  = file.join
 input.concatinators.file = input.concatinators.tex
 
-function input.find_files(instance,filename,filetype,mustexist)
+function input.find_files(filename,filetype,mustexist)
+    local instance = input.instance
     if type(mustexist) == boolean then
         -- all set
     elseif type(filetype) == 'boolean' then
@@ -4475,16 +4610,17 @@ function input.find_files(instance,filen
         filetype, mustexist = nil, false
     end
     instance.format = filetype or ''
-    local t = input.aux.find_file(instance,filename,true)
+    local t = input.aux.find_file(filename,true)
     instance.format = ''
     return t
 end
 
-function input.find_file(instance,filename,filetype,mustexist)
-    return (input.find_files(instance,filename,filetype,mustexist)[1] or "")
+function input.find_file(filename,filetype,mustexist)
+    return (input.find_files(filename,filetype,mustexist)[1] or "")
 end
 
-function input.find_given_files(instance,filename)
+function input.find_given_files(filename)
+    local instance = input.instance
     local bname, result = file.basename(filename), { }
     for k, hash in ipairs(instance.hashes) do
         local files = instance.files[hash.tag]
@@ -4512,11 +4648,12 @@ function input.find_given_files(instance
     return result
 end
 
-function input.find_given_file(instance,filename)
-    return (input.find_given_files(instance,filename)[1] or "")
+function input.find_given_file(filename)
+    return (input.find_given_files(filename)[1] or "")
 end
 
-function input.find_wildcard_files(instance,filename) -- todo: remap:
+function input.find_wildcard_files(filename) -- todo: remap:
+    local instance = input.instance
     local result = { }
     local bname, dname = file.basename(filename), file.dirname(filename)
     local path = dname:gsub("^*/","")
@@ -4569,16 +4706,19 @@ function input.find_wildcard_files(insta
             if done and not allresults then break end
         end
     end
+    -- we can consider also searching the paths not in the database, but then
+    -- we end up with a messy search (all // in all path specs)
     return result
 end
 
-function input.find_wildcard_file(instance,filename)
-    return (input.find_wildcard_files(instance,filename)[1] or "")
+function input.find_wildcard_file(filename)
+    return (input.find_wildcard_files(filename)[1] or "")
 end
 
 -- main user functions
 
-function input.save_used_files_in_trees(instance, filename,jobname)
+function input.save_used_files_in_trees(filename,jobname)
+    local instance = input.instance
     if not filename then filename = 'luatex.jlg' end
     local f = io.open(filename,'w')
     if f then
@@ -4588,7 +4728,7 @@ function input.save_used_files_in_trees(
             f:write("\t<rl:name>" .. jobname .. "</rl:name>\n")
         end
         f:write("\t<rl:files>\n")
-        for _,v in pairs(table.sortedkeys(instance.foundintrees)) do
+        for _,v in pairs(sorted(instance.foundintrees)) do -- ipairs
             f:write("\t\t<rl:file n='" .. instance.foundintrees[v] .. "'>" .. v .. "</rl:file>\n")
         end
         f:write("\t</rl:files>\n")
@@ -4597,24 +4737,24 @@ function input.save_used_files_in_trees(
     end
 end
 
-function input.automount(instance)
+function input.automount()
     -- implemented later
 end
 
-function input.load(instance)
-    input.starttiming(instance)
-    input.resetconfig(instance)
-    input.identify_cnf(instance)
-    input.load_lua(instance)
-    input.expand_variables(instance)
-    input.load_cnf(instance)
-    input.expand_variables(instance)
-    input.load_hash(instance)
-    input.automount(instance)
-    input.stoptiming(instance)
+function input.load()
+    input.starttiming(input.instance)
+    input.resetconfig()
+    input.identify_cnf()
+    input.load_lua()
+    input.expand_variables()
+    input.load_cnf()
+    input.expand_variables()
+    input.load_hash()
+    input.automount()
+    input.stoptiming(input.instance)
 end
 
-function input.for_files(instance, command, files, filetype, mustexist)
+function input.for_files(command, files, filetype, mustexist)
     if files and #files > 0 then
         local function report(str)
             if input.verbose then
@@ -4627,7 +4767,7 @@ function input.for_files(instance, comma
             report('')
         end
         for _, file in pairs(files) do
-            local result = command(instance,file,filetype,mustexist)
+            local result = command(file,filetype,mustexist)
             if type(result) == 'string' then
                 report(result)
             else
@@ -4641,14 +4781,11 @@ end
 
 -- strtab
 
-function input.var_value(instance,str)     -- output the value of variable $STRING.
-    return input.variable(instance,str)
-end
-function input.expand_var(instance,str)    -- output variable expansion of STRING.
-    return input.expansion(instance,str)
-end
-function input.show_path(instance,str)     -- output search path for file type NAME
-    return file.join_path(input.expanded_path_list(instance,input.format_of_var(str)))
+input.var_value  = input.variable   -- output the value of variable $STRING.
+input.expand_var = input.expansion  -- output variable expansion of STRING.
+
+function input.show_path(str)     -- output search path for file type NAME
+    return file.join_path(input.expanded_path_list(input.format_of_var(str)))
 end
 
 -- input.find_file(filename)
@@ -4697,56 +4834,58 @@ function table.sequenced(t,sep) -- temp 
     for k, v in pairs(t) do
         s[#s+1] = k .. "=" .. v
     end
-    return table.concat(s, sep or " | ")
+    return concat(s, sep or " | ")
 end
 
-function input.methodhandler(what, instance, filename, filetype) -- ...
+function input.methodhandler(what, filename, filetype) -- ...
     local specification = (type(filename) == "string" and input.splitmethod(filename)) or filename -- no or { }, let it bomb
     local scheme = specification.scheme
     if input[what][scheme] then
-        input.logger('= handler',specification.original .." -> " .. what .. " -> " .. table.sequenced(specification))
-        return input[what][scheme](instance,filename,filetype) -- todo: specification
+        if input.trace > 0 then
+            input.logger('= handler: %s -> %s -> %s',specification.original,what,table.sequenced(specification))
+        end
+        return input[what][scheme](filename,filetype) -- todo: specification
     else
-        return input[what].tex(instance,filename,filetype) -- todo: specification
+        return input[what].tex(filename,filetype) -- todo: specification
     end
 end
 
 -- also inside next test?
 
-function input.findtexfile(instance, filename, filetype)
-    return input.methodhandler('finders',instance, input.normalize_name(filename), filetype)
+function input.findtexfile(filename, filetype)
+    return input.methodhandler('finders',input.normalize_name(filename), filetype)
 end
-function input.opentexfile(instance,filename)
-    return input.methodhandler('openers',instance, input.normalize_name(filename))
+function input.opentexfile(filename)
+    return input.methodhandler('openers',input.normalize_name(filename))
 end
 
-function input.findbinfile(instance, filename, filetype)
-    return input.methodhandler('finders',instance, input.normalize_name(filename), filetype)
+function input.findbinfile(filename, filetype)
+    return input.methodhandler('finders',input.normalize_name(filename), filetype)
 end
-function input.openbinfile(instance,filename)
-    return input.methodhandler('loaders',instance, input.normalize_name(filename))
+function input.openbinfile(filename)
+    return input.methodhandler('loaders',input.normalize_name(filename))
 end
 
-function input.loadbinfile(instance, filename, filetype)
-    local fname = input.findbinfile(instance, input.normalize_name(filename), filetype)
+function input.loadbinfile(filename, filetype)
+    local fname = input.findbinfile(input.normalize_name(filename), filetype)
     if fname and fname ~= "" then
-        return input.openbinfile(instance,fname)
+        return input.openbinfile(fname)
     else
         return unpack(input.loaders.notfound)
     end
 end
 
-function input.texdatablob(instance, filename, filetype)
-    local ok, data, size = input.loadbinfile(instance, filename, filetype)
+function input.texdatablob(filename, filetype)
+    local ok, data, size = input.loadbinfile(filename, filetype)
     return data or ""
 end
 
 input.loadtexfile = input.texdatablob
 
-function input.openfile(filename) -- brrr texmf.instance here  / todo ! ! ! ! !
-    local fullname = input.findtexfile(texmf.instance, filename)
+function input.openfile(filename)
+    local fullname = input.findtexfile(filename)
     if fullname and (fullname ~= "") then
-        return input.opentexfile(texmf.instance, fullname)
+        return input.opentexfile(fullname)
     else
         return nil
     end
@@ -4792,16 +4931,18 @@ end
 -- beware: i need to check where we still need a / on windows:
 
 function input.clean_path(str)
---~     return (((str:gsub("\\","/")):gsub("^!+","")):gsub("//+","//"))
     if str then
-        return ((str:gsub("\\","/")):gsub("^!+",""))
+        str = str:gsub("\\","/")
+        str = str:gsub("^!+","")
+        str = str:gsub("^~",input.homedir)
+        return str
     else
         return nil
     end
 end
 
 function input.do_with_path(name,func)
-    for _, v in pairs(input.expanded_path_list(instance,name)) do
+    for _, v in pairs(input.expanded_path_list(name)) do
         func("^"..input.clean_path(v))
     end
 end
@@ -4810,7 +4951,8 @@ function input.do_with_var(name,func)
     func(input.aux.expanded_var(name))
 end
 
-function input.with_files(instance,pattern,handle)
+function input.with_files(pattern,handle)
+    local instance = input.instance
     for _, hash in ipairs(instance.hashes) do
         local blobpath = hash.tag
         local blobtype = hash.type
@@ -4837,37 +4979,22 @@ function input.with_files(instance,patte
     end
 end
 
---~ function input.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
---~     newname = file.addsuffix(newname,"lua")
---~     local newscript = input.clean_path(input.find_file(instance, newname))
---~     local oldscript = input.clean_path(oldname)
---~     input.report("old script", oldscript)
---~     input.report("new script", newscript)
---~     if oldscript ~= newscript and (oldscript:find(file.removesuffix(newname).."$") or oldscript:find(newname.."$")) then
---~         local newdata = io.loaddata(newscript)
---~         if newdata then
---~             input.report("old script content replaced by new content")
---~             io.savedata(oldscript,newdata)
---~         end
---~     end
---~ end
-
-function input.update_script(instance,oldname,newname) -- oldname -> own.name, not per se a suffix
+function input.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
     local scriptpath = "scripts/context/lua"
     newname = file.addsuffix(newname,"lua")
     local oldscript = input.clean_path(oldname)
-    input.report("to be replaced old script", oldscript)
-    local newscripts = input.find_files(instance, newname) or { }
+    input.report("to be replaced old script %s", oldscript)
+    local newscripts = input.find_files(newname) or { }
     if #newscripts == 0 then
         input.report("unable to locate new script")
     else
         for _, newscript in ipairs(newscripts) do
             newscript = input.clean_path(newscript)
-            input.report("checking new script", newscript)
+            input.report("checking new script %s", newscript)
             if oldscript == newscript then
                 input.report("old and new script are the same")
             elseif not newscript:find(scriptpath) then
-                input.report("new script should come from",scriptpath)
+                input.report("new script should come from %s",scriptpath)
             elseif not (oldscript:find(file.removesuffix(newname).."$") or oldscript:find(newname.."$")) then
                 input.report("invalid new script name")
             else
@@ -4895,10 +5022,10 @@ do
 
     local resolvers = { }
 
-    resolvers.environment = function(instance,str)
+    resolvers.environment = function(str)
         return input.clean_path(os.getenv(str) or os.getenv(str:upper()) or os.getenv(str:lower()) or "")
     end
-    resolvers.relative = function(instance,str,n)
+    resolvers.relative = function(str,n)
         if io.exists(str) then
             -- nothing
         elseif io.exists("./" .. str) then
@@ -4916,16 +5043,16 @@ do
         end
         return input.clean_path(str)
     end
-    resolvers.locate = function(instance,str)
-        local fullname = input.find_given_file(instance,str) or ""
+    resolvers.locate = function(str)
+        local fullname = input.find_given_file(str) or ""
         return input.clean_path((fullname ~= "" and fullname) or str)
     end
-    resolvers.filename = function(instance,str)
-        local fullname = input.find_given_file(instance,str) or ""
+    resolvers.filename = function(str)
+        local fullname = input.find_given_file(str) or ""
         return input.clean_path(file.basename((fullname ~= "" and fullname) or str))
     end
-    resolvers.pathname = function(instance,str)
-        local fullname = input.find_given_file(instance,str) or ""
+    resolvers.pathname = function(str)
+        local fullname = input.find_given_file(str) or ""
         return input.clean_path(file.dirname((fullname ~= "" and fullname) or str))
     end
 
@@ -4937,15 +5064,15 @@ do
     resolvers.file = resolvers.filename
     resolvers.path = resolvers.pathname
 
-    local function resolve(instance,str)
+    local function resolve(str)
         if type(str) == "table" then
             for k, v in pairs(str) do
-                str[k] = resolve(instance,v) or v
+                str[k] = resolve(v) or v
             end
         elseif str and str ~= "" then
-            str = str:gsub("([a-z]+):([^ ]+)", function(method,target)
+            str = str:gsub("([a-z]+):([^ \"\']*)", function(method,target)
                 if resolvers[method] then
-                    return resolvers[method](instance,target)
+                    return resolvers[method](target)
                 else
                     return method .. ":" .. target
                 end
@@ -4954,10 +5081,185 @@ do
         return str
     end
 
+    if os.uname then
+        for k, v in pairs(os.uname()) do
+            if not resolvers[k] then
+                resolvers[k] = function() return v end
+            end
+        end
+    end
+
     input.resolve = resolve
 
 end
 
+function input.boolean_variable(str,default)
+    local b = input.expansion(str)
+    if b == "" then
+        return default
+    else
+        b = toboolean(b)
+        return (b == nil and default) or b
+    end
+end
+
+
+if not modules then modules = { } end modules ['luat-log'] = {
+    version   = 1.001,
+    comment   = "companion to luat-lib.tex",
+    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+    copyright = "PRAGMA ADE / ConTeXt Development Team",
+    license   = "see context related readme files"
+}
+
+--[[ldx--
+<p>This is a prelude to a more extensive logging module. For the sake
+of parsing log files, in addition to the standard logging we will
+provide an <l n='xml'/> structured file. Actually, any logging that
+is hooked into callbacks will be \XML\ by default.</p>
+--ldx]]--
+
+-- input.logger -> special tracing, driven by log level (only input)
+-- input.report -> goes to terminal, depends on verbose, has banner
+-- logs.report  -> module specific tracing and reporting, no banner but class
+
+
+input = input or { }
+logs  = logs  or { }
+
+--[[ldx--
+<p>This looks pretty ugly but we need to speed things up a bit.</p>
+--ldx]]--
+
+logs.levels = {
+    ['error']   = 1,
+    ['warning'] = 2,
+    ['info']    = 3,
+    ['debug']   = 4
+}
+
+logs.functions = {
+    'report', 'start', 'stop', 'push', 'pop', 'line', 'direct'
+}
+
+logs.callbacks  = {
+    'start_page_number',
+    'stop_page_number',
+    'report_output_pages',
+    'report_output_log'
+}
+
+logs.tracers = {
+}
+
+logs.xml = logs.xml or { }
+logs.tex = logs.tex or { }
+
+logs.level = 0
+
+local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format
+
+if texlua then
+    write_nl = print
+    write    = io.write
+end
+
+function logs.xml.report(category,fmt,...) -- new
+    write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...)))
+end
+function logs.xml.line(fmt,...) -- new
+    write_nl(format("<r>%s</r>",format(fmt,...)))
+end
+
+function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end
+function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end
+function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end
+function logs.xml.pop  () if logs.level > 0 then tw(" -->" ) end end
+
+function logs.tex.report(category,fmt,...) -- new
+ -- write_nl(format("%s | %s",category,format(fmt,...))) -- arg to format can be tex comment so .. .
+    write_nl(category .. " | " .. format(fmt,...))
+end
+function logs.tex.line(fmt,...) -- new
+    write_nl(format(fmt,...))
+end
+
+function logs.set_level(level)
+    logs.level = logs.levels[level] or level
+end
+
+function logs.set_method(method)
+    for _, v in pairs(logs.functions) do
+        logs[v] = logs[method][v] or function() end
+    end
+    if callback and input[method] then
+        for _, cb in pairs(logs.callbacks) do
+            callback.register(cb, input[method][cb])
+        end
+    end
+end
+
+function logs.xml.start_page_number()
+    write_nl(format("<p real='%s' page='%s' sub='%s'", tex.count[0], tex.count[1], tex.count[2]))
+end
+
+function logs.xml.stop_page_number()
+    write("/>")
+    write_nl("")
+end
+
+function logs.xml.report_output_pages(p,b)
+    write_nl(format("<v k='pages' v='%s'/>", p))
+    write_nl(format("<v k='bytes' v='%s'/>", b))
+    write_nl("")
+end
+
+function logs.xml.report_output_log()
+end
+
+function input.logger(...) -- assumes test for input.trace > n
+    if input.trace > 0 then
+        logs.report(...)
+    end
+end
+
+function input.report(fmt,...)
+    if input.verbose then
+        logs.report(input.banner or "report",format(fmt,...))
+    end
+end
+
+function input.reportlines(str) -- todo: <lines></lines>
+    for line in str:gmatch("(.-)[\n\r]") do
+        logs.report(input.banner or "report",line)
+    end
+end
+
+input.moreinfo = [[
+more information about ConTeXt and the tools that come with it can be found at:
+
+maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
+webpage  : http://www.pragma-ade.nl / http://tex.aanhet.net
+wiki     : http://contextgarden.net
+]]
+
+function input.help(banner,message)
+    if not input.verbose then
+        input.verbose = true
+    --  input.report(banner,"\n")
+    end
+    input.report(banner,"\n")
+    input.report("")
+    input.reportlines(message)
+    if input.moreinfo and input.moreinfo ~= "" then
+        input.report("")
+        input.reportlines(input.moreinfo)
+    end
+end
+
+logs.set_level('error')
+logs.set_method('tex')
+
 
 if not modules then modules = { } end modules ['luat-tmp'] = {
     version   = 1.001,
@@ -4983,63 +5285,82 @@ being written at the same time is small.
 luatools with a recache feature.</p>
 --ldx]]--
 
+local format = string.format
+
 caches = caches or { }
 dir    = dir    or { }
 texmf  = texmf  or { }
 
-caches.path   = caches.path or nil
-caches.base   = caches.base or "luatex-cache"
-caches.more   = caches.more or "context"
-caches.direct = false -- true is faster but may need huge amounts of memory
-caches.trace  = false
-caches.tree   = false
-caches.paths  = caches.paths or nil
-caches.force  = false
-
-input.usecache = not toboolean(os.getenv("TEXMFSHARECACHE") or "false",true) -- true
-
-function caches.temp(instance)
-    local function checkpath(cachepath)
-        if not cachepath or cachepath == "" then
-            return nil
-        elseif lfs.attributes(cachepath,"mode") == "directory" then -- lfs.isdir(cachepath) then
-            return cachepath
-        elseif caches.force or io.ask(string.format("Should I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then
-            dir.mkdirs(cachepath)
-            return (lfs.attributes(cachepath,"mode") == "directory") and cachepath
-        else
-            return nil
+caches.path     = caches.path or nil
+caches.base     = caches.base or "luatex-cache"
+caches.more     = caches.more or "context"
+caches.direct   = false -- true is faster but may need huge amounts of memory
+caches.trace    = false
+caches.tree     = false
+caches.paths    = caches.paths or nil
+caches.force    = false
+caches.defaults = { "TEXMFCACHE", "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" }
+
+function caches.temp()
+    local cachepath = nil
+    local function check(list,isenv)
+        if not cachepath then
+            for _, v in ipairs(list) do
+                cachepath = (isenv and (os.env[v] or "")) or v or ""
+                if cachepath == "" then
+                    -- next
+                else
+                    cachepath = input.clean_path(cachepath)
+                     if lfs.isdir(cachepath) and file.iswritable(cachepath) then -- lfs.attributes(cachepath,"mode") == "directory"
+                        break
+                    elseif caches.force or io.ask(format("\nShould I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then
+                        dir.mkdirs(cachepath)
+                        if lfs.isdir(cachepath) and file.iswritable(cachepath) then
+                            break
+                        end
+                    end
+                end
+                cachepath = nil
+            end
         end
     end
-    local cachepath = input.expanded_path_list(instance,"TEXMFCACHE")
-    cachepath = cachepath and #cachepath > 0 and checkpath(cachepath[1])
-    if not cachepath then
-        cachepath = os.getenv("TEXMFCACHE") or os.getenv("HOME") or os.getenv("HOMEPATH") or os.getenv("TMP") or os.getenv("TEMP") or os.getenv("TMPDIR") or nil
-        cachepath = checkpath(cachepath)
-    end
+    check(input.clean_path_list("TEXMFCACHE") or { })
+    check(caches.defaults,true)
     if not cachepath then
-        print("\nfatal error: there is no valid cache path defined\n")
+        print("\nfatal error: there is no valid (writable) cache path defined\n")
         os.exit()
-    elseif lfs.attributes(cachepath,"mode") ~= "directory" then
-        print(string.format("\nfatal error: cache path %s is not a directory\n",cachepath))
+    elseif not lfs.isdir(cachepath) then -- lfs.attributes(cachepath,"mode") ~= "directory"
+        print(format("\nfatal error: cache path %s is not a directory\n",cachepath))
         os.exit()
     end
-    function caches.temp(instance)
+    cachepath = input.normalize_name(cachepath)
+    function caches.temp()
         return cachepath
     end
     return cachepath
 end
 
-function caches.configpath(instance)
-    return table.concat(instance.cnffiles,";")
+function caches.configpath()
+    return table.concat(input.instance.cnffiles,";")
 end
 
 function caches.hashed(tree)
     return md5.hex((tree:lower()):gsub("[\\\/]+","/"))
 end
 
-function caches.treehash(instance)
-    local tree = caches.configpath(instance)
+--~ tracing:
+
+--~ function caches.hashed(tree)
+--~     tree = (tree:lower()):gsub("[\\\/]+","/")
+--~     local hash = md5.hex(tree)
+--~     if input.verbose then -- temp message
+--~         input.report("hashing %s => %s",tree,hash)
+--~     end
+--~     return hash
+--~ end
+
+function caches.treehash()
+    local tree = caches.configpath()
     if not tree or tree == "" then
         return false
     else
@@ -5047,14 +5368,14 @@ function caches.treehash(instance)
     end
 end
 
-function caches.setpath(instance,...)
+function caches.setpath(...)
     if not caches.path then
         if not caches.path then
-            caches.path = caches.temp(instance)
+            caches.path = caches.temp()
         end
         caches.path = input.clean_path(caches.path) -- to be sure
         if lfs then
-            caches.tree = caches.tree or caches.treehash(instance)
+            caches.tree = caches.tree or caches.treehash()
             if caches.tree then
                 caches.path = dir.mkdirs(caches.path,caches.base,caches.more,caches.tree)
             else
@@ -5074,9 +5395,9 @@ function caches.setpath(instance,...)
     return caches.path
 end
 
-function caches.definepath(instance,category,subcategory)
+function caches.definepath(category,subcategory)
     return function()
-        return caches.setpath(instance,category,subcategory)
+        return caches.setpath(category,subcategory)
     end
 end
 
@@ -5099,26 +5420,28 @@ function caches.is_writable(filepath,fil
     return file.is_writable(tmaname)
 end
 
-function caches.savedata(filepath,filename,data,raw) -- raw needed for file cache
+function caches.savedata(filepath,filename,data,raw)
     local tmaname, tmcname = caches.setluanames(filepath,filename)
     local reduce, simplify = true, true
     if raw then
         reduce, simplify = false, false
     end
     if caches.direct then
-        file.savedata(tmaname, table.serialize(data,'return',true,true))
+        file.savedata(tmaname, table.serialize(data,'return',true,true,false)) -- no hex
     else
-        table.tofile (tmaname,                 data,'return',true,true) -- maybe not the last true
+        table.tofile(tmaname, data,'return',true,true,false) -- maybe not the last true
     end
-    utils.lua.compile(tmaname, tmcname)
+    local cleanup = input.boolean_variable("PURGECACHE", false)
+    local strip = input.boolean_variable("LUACSTRIP", true)
+    utils.lua.compile(tmaname, tmcname, cleanup, strip)
 end
 
 -- here we use the cache for format loading (texconfig.[formatname|jobname])
 
 --~ if tex and texconfig and texconfig.formatname and texconfig.formatname == "" then
-if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and texmf.instance then
+if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and input and input.instance then
     if not texconfig.luaname then texconfig.luaname = "cont-en.lua" end -- or luc
-    texconfig.formatname = caches.setpath(texmf.instance,"formats") .. "/" .. texconfig.luaname:gsub("%.lu.$",".fmt")
+    texconfig.formatname = caches.setpath("formats") .. "/" .. texconfig.luaname:gsub("%.lu.$",".fmt")
 end
 
 --[[ldx--
@@ -5141,7 +5464,7 @@ do -- local report
 
     local function report(container,tag,name)
         if caches.trace or containers.trace or container.trace then
-            logs.report(string.format("%s cache",container.subcategory),string.format("%s: %s",tag,name or 'invalid'))
+            logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid')
         end
     end
 
@@ -5166,7 +5489,7 @@ do -- local report
                         enabled = enabled,
                         version = version or 1.000,
                         trace = false,
-                        path = caches.setpath(texmf.instance,category,subcategory),
+                        path = caches.setpath(category,subcategory),
                     }
                     c[subcategory] = s
                 end
@@ -5231,13 +5554,16 @@ end
 -- reimplement the saver.
 
 local save_data = input.aux.save_data
+local load_data = input.aux.load_data
 
-input.cachepath = nil
+input.cachepath = nil  -- public, for tracing
+input.usecache  = true -- public, for tracing
 
-function input.aux.save_data(instance, dataname, check)
-    input.cachepath = input.cachepath or caches.definepath(instance,"trees")
-    save_data(instance, dataname, check, function(cachename,dataname)
+function input.aux.save_data(dataname, check)
+    save_data(dataname, check, function(cachename,dataname)
+        input.usecache = not toboolean(input.expansion("CACHEINTDS") or "false",true)
         if input.usecache then
+            input.cachepath = input.cachepath or caches.definepath("trees")
             return file.join(input.cachepath(),caches.hashed(cachename))
         else
             return file.join(cachename,dataname)
@@ -5245,12 +5571,11 @@ function input.aux.save_data(instance, d
     end)
 end
 
-local load_data = input.aux.load_data
-
-function input.aux.load_data(instance,pathname,dataname,filename)
-    input.cachepath = input.cachepath or caches.definepath(instance,"trees")
-    load_data(instance,pathname,dataname,filename,function(dataname,filename)
+function input.aux.load_data(pathname,dataname,filename)
+    load_data(pathname,dataname,filename,function(dataname,filename)
+        input.usecache = not toboolean(input.expansion("CACHEINTDS") or "false",true)
         if input.usecache then
+            input.cachepath = input.cachepath or caches.definepath("trees")
             return file.join(input.cachepath(),caches.hashed(pathname))
         else
             if not filename or (filename == "") then
@@ -5265,13 +5590,13 @@ end
 
 input.automounted = input.automounted or { }
 
-function input.automount(instance,usecache)
-    local mountpaths = input.simplified_list(input.expansion(instance,'TEXMFMOUNT'))
+function input.automount(usecache)
+    local mountpaths = input.clean_path_list(input.expansion('TEXMFMOUNT'))
     if table.is_empty(mountpaths) and usecache then
-        mountpaths = { caches.setpath(instance,"mount") }
+        mountpaths = { caches.setpath("mount") }
     end
     if not table.is_empty(mountpaths) then
-        input.starttiming(instance)
+        input.starttiming(input.instance)
         for k, root in pairs(mountpaths) do
             local f = io.open(root.."/url.tmi")
             if f then
@@ -5280,16 +5605,16 @@ function input.automount(instance,usecac
                         if line:find("^[%%#%-]") then -- or %W
                             -- skip
                         elseif line:find("^zip://") then
-                            input.report("mounting",line)
+                            input.report("mounting %s",line)
                             table.insert(input.automounted,line)
-                            input.usezipfile(instance,line)
+                            input.usezipfile(line)
                         end
                     end
                 end
                 f:close()
             end
         end
-        input.stoptiming(instance)
+        input.stoptiming(input.instance)
     end
 end
 
@@ -5300,7 +5625,7 @@ input.storage.data       = { }
 input.storage.min        = 0 -- 500
 input.storage.max        = input.storage.min - 1
 input.storage.trace      = false -- true
-input.storage.done       = 0
+input.storage.done       = input.storage.done or 0
 input.storage.evaluators = { }
 -- (evaluate,message,names)
 
@@ -5338,17 +5663,17 @@ function input.storage.dump()
             else
                 name = str
             end
-            initialize = string.format("%s %s = %s or {} ", initialize, name, name)
+            initialize = format("%s %s = %s or {} ", initialize, name, name)
         end
         if evaluate then
             finalize = "input.storage.evaluate(" .. name .. ")"
         end
         input.storage.max = input.storage.max + 1
         if input.storage.trace then
-            logs.report('storage',string.format('saving %s in slot %s',message,input.storage.max))
+            logs.report('storage','saving %s in slot %s',message,input.storage.max)
             code =
                 initialize ..
-                string.format("logs.report('storage','restoring %s from slot %s') ",message,input.storage.max) ..
+                format("logs.report('storage','restoring %s from slot %s') ",message,input.storage.max) ..
                 table.serialize(original,name) ..
                 finalize
         else
@@ -5358,6 +5683,8 @@ function input.storage.dump()
     end
 end
 
+-- we also need to count at generation time (nicer for message)
+
 if lua.bytecode then -- from 0 upwards
     local i = input.storage.min
     while lua.bytecode[i] do
@@ -5377,6 +5704,8 @@ end
 
 if not versions then versions = { } end versions['luat-zip'] = 1.001
 
+local format = string.format
+
 if zip and input then
     zip.supported = true
 else
@@ -5408,7 +5737,7 @@ else
     zip.archives        = { }
     zip.registeredfiles = { }
 
-    function zip.openarchive(instance,name)
+    function zip.openarchive(name)
         if not name or name == "" then
             return nil
         else
@@ -5416,7 +5745,7 @@ else
             if arch then
                 return arch
             else
-               local full = input.find_file(instance,name) or ""
+               local full = input.find_file(name) or ""
                local arch = (full ~= "" and zip.open(full)) or false
                zip.archives[name] = arch
                return arch
@@ -5424,7 +5753,7 @@ else
         end
     end
 
-    function zip.closearchive(instance,name)
+    function zip.closearchive(name)
         if not name or name == "" and zip.archives[name] then
             zip.close(zip.archives[name])
             zip.archives[name] = nil
@@ -5435,20 +5764,22 @@ else
     -- zip:///texmf.zip?tree=/tex/texmf-local
     -- zip:///texmf-mine.zip?tree=/tex/texmf-projects
 
-    function input.locators.zip(instance,specification) -- where is this used? startup zips (untested)
+    function input.locators.zip(specification) -- where is this used? startup zips (untested)
         specification = input.splitmethod(specification)
         local zipfile = specification.path
-        local zfile = zip.openarchive(instance,name) -- tricky, could be in to be initialized tree
-        if zfile then
-            input.logger('! zip locator', specification.original ..' found')
-        else
-            input.logger('? zip locator', specification.original ..' not found')
+        local zfile = zip.openarchive(name) -- tricky, could be in to be initialized tree
+        if input.trace > 0 then
+            if zfile then
+                input.logger('! zip locator, found: %s',specification.original)
+            else
+                input.logger('? zip locator, not found: %s',specification.original)
+            end
         end
     end
 
-    function input.hashers.zip(instance,tag,name)
-        input.report("loading zip file",name,"as",tag)
-        input.usezipfile(instance,tag .."?tree=" .. name)
+    function input.hashers.zip(tag,name)
+        input.report("loading zip file %s as %s",name,tag)
+        input.usezipfile(tag .."?tree=" .. name)
     end
 
     function input.concatinators.zip(tag,path,name)
@@ -5463,101 +5794,124 @@ else
         return true
     end
 
-    function input.finders.zip(instance,specification,filetype)
+    function input.finders.zip(specification,filetype)
         specification = input.splitmethod(specification)
         if specification.path then
             local q = url.query(specification.query)
             if q.name then
-                local zfile = zip.openarchive(instance,specification.path)
+                local zfile = zip.openarchive(specification.path)
                 if zfile then
-                    input.logger('! zip finder',specification.path)
+                    if input.trace > 0 then
+                        input.logger('! zip finder, path: %s',specification.path)
+                    end
                     local dfile = zfile:open(q.name)
                     if dfile then
                         dfile = zfile:close()
-                        input.logger('+ zip finder',q.name)
+                        if input.trace > 0 then
+                            input.logger('+ zip finder, name: %s',q.name)
+                        end
                         return specification.original
                     end
-                else
-                    input.logger('? zip finder',specification.path)
+                elseif input.trace > 0 then
+                    input.logger('? zip finder, path %s',specification.path)
                 end
             end
         end
-        input.logger('- zip finder',filename)
+        if input.trace > 0 then
+            input.logger('- zip finder, name: %s',filename)
+        end
         return unpack(input.finders.notfound)
     end
 
-    function input.openers.zip(instance,specification)
+    function input.openers.zip(specification)
         local zipspecification = input.splitmethod(specification)
         if zipspecification.path then
             local q = url.query(zipspecification.query)
             if q.name then
-                local zfile = zip.openarchive(instance,zipspecification.path)
+                local zfile = zip.openarchive(zipspecification.path)
                 if zfile then
-                    input.logger('+ zip starter',zipspecification.path)
+                    if input.trace > 0 then
+                        input.logger('+ zip starter, path: %s',zipspecification.path)
+                    end
                     local dfile = zfile:open(q.name)
                     if dfile then
                         input.show_open(specification)
                         return input.openers.text_opener(specification,dfile,'zip')
                     end
-                else
-                    input.logger('- zip starter',zipspecification.path)
+                elseif input.trace > 0 then
+                    input.logger('- zip starter, path %s',zipspecification.path)
                 end
             end
         end
-        input.logger('- zip opener',filename)
+        if input.trace > 0 then
+            input.logger('- zip opener, name: %s',filename)
+        end
         return unpack(input.openers.notfound)
     end
 
-    function input.loaders.zip(instance,specification)
+    function input.loaders.zip(specification)
         specification = input.splitmethod(specification)
         if specification.path then
             local q = url.query(specification.query)
             if q.name then
-                local zfile = zip.openarchive(instance,specification.path)
+                local zfile = zip.openarchive(specification.path)
                 if zfile then
-                    input.logger('+ zip starter',specification.path)
+                    if input.trace > 0 then
+                        input.logger('+ zip starter, path: %s',specification.path)
+                    end
                     local dfile = zfile:open(q.name)
                     if dfile then
                         input.show_load(filename)
-                        input.logger('+ zip loader',filename)
+                        if input.trace > 0 then
+                            input.logger('+ zip loader, name: %s',filename)
+                        end
                         local s = dfile:read("*all")
                         dfile:close()
                         return true, s, #s
                     end
-                else
-                    input.logger('- zip starter',specification.path)
+                elseif input.trace > 0 then
+                    input.logger('- zip starter, path: %s',specification.path)
                 end
             end
         end
-        input.logger('- zip loader',filename)
+        if input.trace > 0 then
+            input.logger('- zip loader, name: %s',filename)
+        end
         return unpack(input.openers.notfound)
     end
 
     -- zip:///somefile.zip
     -- zip:///somefile.zip?tree=texmf-local -> mount
 
-    function input.usezipfile(instance,zipname)
+    function input.usezipfile(zipname)
         zipname = validzip(zipname)
-        input.logger('! zip use','file '..zipname)
+        if input.trace > 0 then
+            input.logger('! zip use, file: %s',zipname)
+        end
         local specification = input.splitmethod(zipname)
         local zipfile = specification.path
         if zipfile and not zip.registeredfiles[zipname] then
             local tree = url.query(specification.query).tree or ""
-            input.logger('! zip register','file '..zipname)
-            local z = zip.openarchive(instance,zipfile)
+            if input.trace > 0 then
+                input.logger('! zip register, file: %s',zipname)
+            end
+            local z = zip.openarchive(zipfile)
             if z then
-                input.logger("= zipfile","registering "..zipname)
+                local instance = input.instance
+                if input.trace > 0 then
+                    input.logger("= zipfile, registering: %s",zipname)
+                end
                 input.starttiming(instance)
-                input.aux.prepend_hash(instance,'zip',zipname,zipfile)
-                input.aux.extend_texmf_var(instance,zipname) -- resets hashes too
+                input.aux.prepend_hash('zip',zipname,zipfile)
+                input.aux.extend_texmf_var(zipname) -- resets hashes too
                 zip.registeredfiles[zipname] = z
                 instance.files[zipname] = input.aux.register_zip_file(z,tree or "")
                 input.stoptiming(instance)
-            else
-                input.logger("? zipfile","unknown "..zipname)
+            elseif input.trace > 0 then
+                input.logger("? zipfile, unknown: %s",zipname)
             end
-        else
-            input.logger('! zip register','no file '..zipname)
+        elseif input.trace > 0 then
+            input.logger('! zip register, no file: %s',zipname)
         end
     end
 
@@ -5568,7 +5922,9 @@ else
         else
             filter = "^"..tree.."/(.+)/(.-)$"
         end
-        input.logger('= zip filter',filter)
+        if input.trace > 0 then
+            input.logger('= zip filter: %s',filter)
+        end
         local register, n = input.aux.register_file, 0
         for i in z:files() do
             local path, name = i.filename:match(filter)
@@ -5584,7 +5940,7 @@ else
                 n = n + 1
             end
         end
-        input.report('= zip entries',n)
+        input.logger('= zip entries: %s',n)
         return files
     end
 
@@ -5601,6 +5957,8 @@ if not versions then versions = { } end 
 
 -- special functions that deal with io
 
+local format = string.format
+
 if texconfig and not texlua then
 
     input.level = input.level or 0
@@ -5623,13 +5981,17 @@ if texconfig and not texlua then
         function input.show_load () end
     end
 
-    function input.finders.generic(instance,tag,filename,filetype)
-        local foundname = input.find_file(instance,filename,filetype)
+    function input.finders.generic(tag,filename,filetype)
+        local foundname = input.find_file(filename,filetype)
         if foundname and foundname ~= "" then
-            input.logger('+ ' .. tag .. ' finder',filename,'filetype')
+            if input.trace > 0 then
+                input.logger('+ finder: %s, file: %s', tag,filename)
+            end
             return foundname
         else
-            input.logger('- ' .. tag .. ' finder',filename,'filetype')
+            if input.trace > 0 then
+                input.logger('- finder: %s, file: %s', tag,filename)
+            end
             return unpack(input.finders.notfound)
         end
     end
@@ -5642,7 +6004,9 @@ if texconfig and not texlua then
         local u = unicode.utftype(file_handle)
         local t = { }
         if u > 0  then
-            input.logger('+ ' .. tag .. ' opener (' .. unicode.utfname[u] .. ')',filename)
+            if input.trace > 0 then
+                input.logger('+ opener: %s (%s), file: %s',tag,unicode.utfname[u],filename)
+            end
             local l
             if u > 2 then
                 l = unicode.utf32_to_utf8(file_handle:read("*a"),u==4)
@@ -5657,8 +6021,11 @@ if texconfig and not texlua then
                 handle = nil,
                 noflines = #l,
                 close = function()
-                    input.logger('= ' .. tag .. ' closer (' .. unicode.utfname[u] .. ')',filename)
+                    if input.trace > 0 then
+                        input.logger('= closer: %s (%s), file: %s',tag,unicode.utfname[u],filename)
+                    end
                     input.show_close(filename)
+                    t = nil
                 end,
 --~                 getline = function(n)
 --~                     local line = t.lines[n]
@@ -5693,7 +6060,9 @@ if texconfig and not texlua then
                 end
             }
         else
-            input.logger('+ ' .. tag .. ' opener',filename)
+            if input.trace > 0 then
+                input.logger('+ opener: %s, file: %s',tag,filename)
+            end
             -- todo: file;name -> freeze / eerste regel scannen -> freeze
             local filters = input.filters
             t = {
@@ -5713,9 +6082,12 @@ if texconfig and not texlua then
                     return line
                 end,
                 close = function()
-                    input.logger('= ' .. tag .. ' closer',filename)
+                    if input.trace > 0 then
+                        input.logger('= closer: %s, file: %s',tag,filename)
+                    end
                     input.show_close(filename)
                     file_handle:close()
+                    t = nil
                 end,
                 handle = function()
                     return file_handle
@@ -5729,7 +6101,7 @@ if texconfig and not texlua then
         return t
     end
 
-    function input.openers.generic(instance,tag,filename)
+    function input.openers.generic(tag,filename)
         if filename and filename ~= "" then
             local f = io.open(filename,"r")
             if f then
@@ -5737,35 +6109,42 @@ if texconfig and not texlua then
                 return input.openers.text_opener(filename,f,tag)
             end
         end
-        input.logger('- ' .. tag .. ' opener',filename)
+        if input.trace > 0 then
+            input.logger('- opener: %s, file: %s',tag,filename)
+        end
         return unpack(input.openers.notfound)
     end
 
-    function input.loaders.generic(instance,tag,filename)
+    function input.loaders.generic(tag,filename)
         if filename and filename ~= "" then
             local f = io.open(filename,"rb")
             if f then
                 input.show_load(filename)
-                input.logger('+ ' .. tag .. ' loader',filename)
+                if input.trace > 0 then
+                    input.logger('+ loader: %s, file: %s',tag,filename)
+                end
                 local s = f:read("*a")
+                garbagecollector.check(s)
                 f:close()
                 if s then
                     return true, s, #s
                 end
             end
         end
-        input.logger('- ' .. tag .. ' loader',filename)
+        if input.trace > 0 then
+            input.logger('- loader: %s, file: %s',tag,filename)
+        end
         return unpack(input.loaders.notfound)
     end
 
-    function input.finders.tex(instance,filename,filetype)
-        return input.finders.generic(instance,'tex',filename,filetype)
+    function input.finders.tex(filename,filetype)
+        return input.finders.generic('tex',filename,filetype)
     end
-    function input.openers.tex(instance,filename)
-        return input.openers.generic(instance,'tex',filename)
+    function input.openers.tex(filename)
+        return input.openers.generic('tex',filename)
     end
-    function input.loaders.tex(instance,filename)
-        return input.loaders.generic(instance,'tex',filename)
+    function input.loaders.tex(filename)
+        return input.loaders.generic('tex',filename)
     end
 
 end
@@ -5779,15 +6158,12 @@ if texconfig and not texlua then do
 
     ctx = ctx or { }
 
-    local ss = { }
-
-    function ctx.writestatus(a,b)
-        local s = ss[a]
-        if not ss[a] then
-            s = a:rpadd(15) .. ": "
-            ss[a] = s
+    function ctx.writestatus(a,b,c,...)
+        if c then
+            texio.write_nl(("%-15s: %s\n"):format(a,b:format(c,...)))
+        else
+            texio.write_nl(("%-15s: %s\n"):format(a,b)) -- b can have %'s
         end
-        texio.write_nl(s .. b .. "\n")
     end
 
     -- this will become: ctx.install_statistics(fnc() return ..,.. end) etc
@@ -5799,63 +6175,75 @@ if texconfig and not texlua then do
         if #tag > n then n = #tag end
     end
 
+    function ctx.memused()
+    --  collectgarbage("collect")
+        return string.format("%s MB (ctx: %s MB)",math.round(collectgarbage("count")), math.round(status.luastate_bytes/1000))
+    end
+
     function ctx.show_statistics() -- todo: move calls
+        local loadtime, register_statistics = input.loadtime, ctx.register_statistics
         if caches then
-            ctx.register_statistics("used config path", "%s", function() return caches.configpath(texmf.instance) end)
-            ctx.register_statistics("used cache path", "%s", function() return caches.path end)
+            register_statistics("used config path", "%s", function() return caches.configpath() end)
+            register_statistics("used cache path", "%s", function() return caches.temp() or "?" end)
         end
         if status.luabytecodes > 0 and input.storage and input.storage.done then
-            ctx.register_statistics("modules/dumps/instances", "%s/%s/%s", function() return status.luabytecodes-500, input.storage.done, status.luastates end)
+            register_statistics("modules/dumps/instances", "%s/%s/%s", function() return status.luabytecodes-500, input.storage.done, status.luastates end)
         end
-        if texmf.instance then
-            ctx.register_statistics("input load time", "%s seconds", function() return input.loadtime(texmf.instance) end)
+        if input.instance then
+            register_statistics("input load time", "%s seconds", function() return loadtime(input.instance) end)
         end
         if fonts then
-            ctx.register_statistics("fonts load time","%s seconds", function() return input.loadtime(fonts) end)
+            register_statistics("fonts load time","%s seconds", function() return loadtime(fonts) end)
         end
         if xml then
-            ctx.register_statistics("xml load time", "%s seconds, backreferences: %i, outer filtering time: %s", function() return input.loadtime(xml), #lxml.self, input.loadtime(lxml) end)
+            register_statistics("xml load time", "%s seconds, lpath calls: %s, cached calls: %s", function()
+                local stats = xml.statistics()
+                return loadtime(xml), stats.lpathcalls, stats.lpathcached
+            end)
+            register_statistics("lxml load time", "%s seconds preparation, backreferences: %i", function()
+                return loadtime(lxml), #lxml.self
+            end)
         end
         if mptopdf then
-            ctx.register_statistics("mps conversion time", "%s seconds", function() return input.loadtime(mptopdf) end)
+            register_statistics("mps conversion time", "%s seconds", function() return loadtime(mptopdf) end)
         end
         if nodes then
-            ctx.register_statistics("node processing time", "%s seconds (including kernel)", function() return input.loadtime(nodes) end)
+            register_statistics("node processing time", "%s seconds including kernel", function() return loadtime(nodes) end)
         end
         if kernel then
-            ctx.register_statistics("kernel processing time", "%s seconds", function() return input.loadtime(kernel) end)
+            register_statistics("kernel processing time", "%s seconds", function() return loadtime(kernel) end)
         end
         if attributes then
-            ctx.register_statistics("attribute processing time", "%s seconds", function() return input.loadtime(attributes) end)
+            register_statistics("attribute processing time", "%s seconds", function() return loadtime(attributes) end)
         end
         if languages then
-            ctx.register_statistics("language load time", "%s seconds, n=%s", function() return input.loadtime(languages), languages.hyphenation.n() end)
+            register_statistics("language load time", "%s seconds, n=%s", function() return loadtime(languages), languages.hyphenation.n() end)
         end
         if figures then
-            ctx.register_statistics("graphics processing time", "%s seconds, n=%s (including tex)", function() return input.loadtime(figures), figures.n or "?" end)
+            register_statistics("graphics processing time", "%s seconds including tex, n=%s", function() return loadtime(figures), figures.n or "?" end)
         end
         if metapost then
-            ctx.register_statistics("metapost processing time", "%s seconds, loading: %s seconds, execution: %s seconds, n: %s", function() return input.loadtime(metapost), input.loadtime(mplib), input.loadtime(metapost.exectime), metapost.n end)
+            register_statistics("metapost processing time", "%s seconds, loading: %s seconds, execution: %s seconds, n: %s", function() return loadtime(metapost), loadtime(mplib), loadtime(metapost.exectime), metapost.n end)
         end
-        if status.luastate_bytes then
-            ctx.register_statistics("current memory usage", "%s bytes", function() return status.luastate_bytes end)
+        if status.luastate_bytes and ctx.memused then
+            register_statistics("current memory usage", "%s", ctx.memused)
         end
         if nodes then
-            ctx.register_statistics("cleaned up reserved nodes", "%s nodes, %s lists of %s", function() return nodes.cleanup_reserved(tex.count[24]) end) -- \topofboxstack
+            register_statistics("cleaned up reserved nodes", "%s nodes, %s lists of %s", function() return nodes.cleanup_reserved(tex.count[24]) end) -- \topofboxstack
         end
         if status.node_mem_usage then
-            ctx.register_statistics("node memory usage", "%s", function() return status.node_mem_usage end)
+            register_statistics("node memory usage", "%s", function() return status.node_mem_usage end)
         end
         if languages then
-            ctx.register_statistics("loaded patterns", "%s", function() return languages.logger.report() end)
+            register_statistics("loaded patterns", "%s", function() return languages.logger.report() end)
         end
         if fonts then
-            ctx.register_statistics("loaded fonts", "%s", function() return fonts.logger.report() end)
+            register_statistics("loaded fonts", "%s", function() return fonts.logger.report() end)
         end
         if xml then -- so we are in mkiv, we need a different check
-            ctx.register_statistics("runtime", "%s seconds, %i processed pages, %i shipped pages, %.3f pages/second", function()
-                input.stoptiming(texmf)
-                local runtime = input.loadtime(texmf)
+            register_statistics("runtime", "%s seconds, %i processed pages, %i shipped pages, %.3f pages/second", function()
+                input.stoptiming(input.instance)
+                local runtime = loadtime(input.instance)
                 local shipped = tex.count['nofshipouts']
                 local pages = tex.count['realpageno'] - 1
                 local persecond = shipped / runtime
@@ -5864,8 +6252,8 @@ if texconfig and not texlua then do
         end
         for _, t in ipairs(statusinfo) do
             local tag, pattern, fnc = t[1], t[2], t[3]
-            ctx.writestatus("mkiv lua stats", string.format("%s - %s", tag:rpadd(n," "), pattern:format(fnc())))
-        end
+            ctx.writestatus("mkiv lua stats", "%s - %s", tag:rpadd(n," "), pattern:format(fnc()))
+        end-- input.expanded_path_list("osfontdir")
     end
 
 end end
@@ -5878,65 +6266,65 @@ if texconfig and not texlua then
 
     -- if still present, we overload kpse (put it off-line so to say)
 
-    if not texmf then texmf = { } end
+    input.starttiming(input.instance)
 
-    input.starttiming(texmf)
+    if not input.instance then
 
-    if not texmf.instance then
+        if not input.instance then -- prevent a second loading
 
-        if not texmf.instance then -- prevent a second loading
+            input.instance            = input.reset()
+            input.instance.progname   = 'context'
+            input.instance.engine     = 'luatex'
+            input.instance.validfile  = input.validctxfile
 
-            texmf.instance            = input.reset()
-            texmf.instance.progname   = environment.progname or 'context'
-            texmf.instance.engine     = environment.engine   or 'luatex'
-            texmf.instance.validfile  = input.validctxfile
-
-            input.load(texmf.instance)
+            input.load()
 
         end
 
         if callback then
-            callback.register('find_read_file'      , function(id,name) return input.findtexfile(texmf.instance,name) end)
-            callback.register('open_read_file'      , function(   name) return input.opentexfile(texmf.instance,name) end)
+            callback.register('find_read_file'      , function(id,name) return input.findtexfile(name) end)
+            callback.register('open_read_file'      , function(   name) return input.opentexfile(name) end)
         end
 
         if callback then
-            callback.register('find_data_file'      , function(name) return input.findbinfile(texmf.instance,name,"tex") end)
-            callback.register('find_enc_file'       , function(name) return input.findbinfile(texmf.instance,name,"enc") end)
-            callback.register('find_font_file'      , function(name) return input.findbinfile(texmf.instance,name,"tfm") end)
-            callback.register('find_format_file'    , function(name) return input.findbinfile(texmf.instance,name,"fmt") end)
-            callback.register('find_image_file'     , function(name) return input.findbinfile(texmf.instance,name,"tex") end)
-            callback.register('find_map_file'       , function(name) return input.findbinfile(texmf.instance,name,"map") end)
-            callback.register('find_ocp_file'       , function(name) return input.findbinfile(texmf.instance,name,"ocp") end)
-            callback.register('find_opentype_file'  , function(name) return input.findbinfile(texmf.instance,name,"otf") end)
-            callback.register('find_output_file'    , function(name) return name                                         end)
-            callback.register('find_pk_file'        , function(name) return input.findbinfile(texmf.instance,name,"pk")  end)
-            callback.register('find_sfd_file'       , function(name) return input.findbinfile(texmf.instance,name,"sfd") end)
-            callback.register('find_truetype_file'  , function(name) return input.findbinfile(texmf.instance,name,"ttf") end)
-            callback.register('find_type1_file'     , function(name) return input.findbinfile(texmf.instance,name,"pfb") end)
-            callback.register('find_vf_file'        , function(name) return input.findbinfile(texmf.instance,name,"vf")  end)
-
-            callback.register('read_data_file'      , function(file) return input.loadbinfile(texmf.instance,file,"tex") end)
-            callback.register('read_enc_file'       , function(file) return input.loadbinfile(texmf.instance,file,"enc") end)
-            callback.register('read_font_file'      , function(file) return input.loadbinfile(texmf.instance,file,"tfm") end)
+            callback.register('find_data_file'      , function(name) return input.findbinfile(name,"tex") end)
+            callback.register('find_enc_file'       , function(name) return input.findbinfile(name,"enc") end)
+            callback.register('find_font_file'      , function(name) return input.findbinfile(name,"tfm") end)
+            callback.register('find_format_file'    , function(name) return input.findbinfile(name,"fmt") end)
+            callback.register('find_image_file'     , function(name) return input.findbinfile(name,"tex") end)
+            callback.register('find_map_file'       , function(name) return input.findbinfile(name,"map") end)
+            callback.register('find_ocp_file'       , function(name) return input.findbinfile(name,"ocp") end)
+            callback.register('find_opentype_file'  , function(name) return input.findbinfile(name,"otf") end)
+            callback.register('find_output_file'    , function(name) return name                          end)
+            callback.register('find_pk_file'        , function(name) return input.findbinfile(name,"pk")  end)
+            callback.register('find_sfd_file'       , function(name) return input.findbinfile(name,"sfd") end)
+            callback.register('find_truetype_file'  , function(name) return input.findbinfile(name,"ttf") end)
+            callback.register('find_type1_file'     , function(name) return input.findbinfile(name,"pfb") end)
+            callback.register('find_vf_file'        , function(name) return input.findbinfile(name,"vf")  end)
+
+            callback.register('read_data_file'      , function(file) return input.loadbinfile(file,"tex") end)
+            callback.register('read_enc_file'       , function(file) return input.loadbinfile(file,"enc") end)
+            callback.register('read_font_file'      , function(file) return input.loadbinfile(file,"tfm") end)
          -- format
          -- image
-            callback.register('read_map_file'       , function(file) return input.loadbinfile(texmf.instance,file,"map") end)
-            callback.register('read_ocp_file'       , function(file) return input.loadbinfile(texmf.instance,file,"ocp") end)
-            callback.register('read_opentype_file'  , function(file) return input.loadbinfile(texmf.instance,file,"otf") end)
+            callback.register('read_map_file'       , function(file) return input.loadbinfile(file,"map") end)
+            callback.register('read_ocp_file'       , function(file) return input.loadbinfile(file,"ocp") end)
+            callback.register('read_opentype_file'  , function(file) return input.loadbinfile(file,"otf") end)
          -- output
-            callback.register('read_pk_file'        , function(file) return input.loadbinfile(texmf.instance,file,"pk")  end)
-            callback.register('read_sfd_file'       , function(file) return input.loadbinfile(texmf.instance,file,"sfd") end)
-            callback.register('read_truetype_file'  , function(file) return input.loadbinfile(texmf.instance,file,"ttf") end)
-            callback.register('read_type1_file'     , function(file) return input.loadbinfile(texmf.instance,file,"pfb") end)
-            callback.register('read_vf_file'        , function(file) return input.loadbinfile(texmf.instance,file,"vf" ) end)
+            callback.register('read_pk_file'        , function(file) return input.loadbinfile(file,"pk")  end)
+            callback.register('read_sfd_file'       , function(file) return input.loadbinfile(file,"sfd") end)
+            callback.register('read_truetype_file'  , function(file) return input.loadbinfile(file,"ttf") end)
+            callback.register('read_type1_file'     , function(file) return input.loadbinfile(file,"pfb") end)
+            callback.register('read_vf_file'        , function(file) return input.loadbinfile(file,"vf" ) end)
         end
 
-        if callback and environment.aleph_mode then
-            callback.register('find_font_file'      , function(name) return input.findbinfile(texmf.instance,name,"ofm") end)
-            callback.register('read_font_file'      , function(file) return input.loadbinfile(texmf.instance,file,"ofm") end)
-            callback.register('find_vf_file'        , function(name) return input.findbinfile(texmf.instance,name,"ovf") end)
-            callback.register('read_vf_file'        , function(file) return input.loadbinfile(texmf.instance,file,"ovf") end)
+        if input.aleph_mode == nil then environment.aleph_mode = true end -- some day we will drop omega font support
+
+        if callback and input.aleph_mode then
+            callback.register('find_font_file'      , function(name) return input.findbinfile(name,"ofm") end)
+            callback.register('read_font_file'      , function(file) return input.loadbinfile(file,"ofm") end)
+            callback.register('find_vf_file'        , function(name) return input.findbinfile(name,"ovf") end)
+            callback.register('read_vf_file'        , function(file) return input.loadbinfile(file,"ovf") end)
         end
 
         if callback then
@@ -6024,16 +6412,16 @@ if texconfig and not texlua then
     if kpse then
 
         function kpse.find_file(filename,filetype,mustexist)
-            return input.find_file(texmf.instance,filename,filetype,mustexist)
+            return input.find_file(filename,filetype,mustexist)
         end
         function kpse.expand_path(variable)
-            return input.expand_path(texmf.instance,variable)
+            return input.expand_path(variable)
         end
         function kpse.expand_var(variable)
-            return input.expand_var(texmf.instance,variable)
+            return input.expand_var(variable)
         end
         function kpse.expand_braces(variable)
-            return input.expand_braces(texmf.instance,variable)
+            return input.expand_braces(variable)
         end
 
     end
@@ -6060,7 +6448,7 @@ if texconfig and not texlua then
     function luatex.variables()
         local t, x = { }, nil
         for _,v in pairs(luatex.variablenames) do
-            x = input.var_value(texmf.instance,v)
+            x = input.var_value(v)
             if x and x:find("^%d+$") then
                 t[v] = tonumber(x)
             end
@@ -6084,28 +6472,34 @@ if texconfig and not texlua then
 
 end
 
--- some tex basics
+-- some tex basics, maybe this will move to ctx
 
-if not cs then cs = { } end
+if tex then
 
-function cs.def(k,v)
-    tex.sprint(tex.texcatcodes, "\\def\\" .. k .. "{" .. v .. "}")
-end
+    local texsprint, texwrite = tex.sprint, tex.write
 
-function cs.chardef(k,v)
-    tex.sprint(tex.texcatcodes, "\\chardef\\" .. k .. "=" .. v .. "\\relax")
-end
+    if not cs then cs = { } end
 
-function cs.boolcase(b)
-    if b then tex.write(1) else tex.write(0) end
-end
+    function cs.def(k,v)
+        texsprint(tex.texcatcodes, "\\def\\" .. k .. "{" .. v .. "}")
+    end
 
-function cs.testcase(b)
-    if b then
-        tex.sprint(tex.texcatcodes, "\\firstoftwoarguments")
-    else
-        tex.sprint(tex.texcatcodes, "\\secondoftwoarguments")
+    function cs.chardef(k,v)
+        texsprint(tex.texcatcodes, "\\chardef\\" .. k .. "=" .. v .. "\\relax")
+    end
+
+    function cs.boolcase(b)
+        if b then texwrite(1) else texwrite(0) end
+    end
+
+    function cs.testcase(b)
+        if b then
+            texsprint(tex.texcatcodes, "\\firstoftwoarguments")
+        else
+            texsprint(tex.texcatcodes, "\\secondoftwoarguments")
+        end
     end
+
 end
 
 
@@ -6235,9 +6629,11 @@ own.libs = { -- todo: check which ones a
     'l-dir.lua',
     'l-boolean.lua',
     'l-unicode.lua',
+    'l-math.lua',
     'l-utils.lua',
     'luat-lib.lua',
     'luat-inp.lua',
+    'luat-log.lua',
     'luat-tmp.lua',
     'luat-zip.lua',
     'luat-tex.lua',
@@ -6291,19 +6687,21 @@ if not input then
     os.exit()
 end
 
-instance            = input.reset()
+input.instance      = input.reset()
 input.verbose       = environment.arguments["verbose"]  or false
-input.banner        = 'LuaTools | '
+input.banner        = 'LuaTools'
 utils.report        = input.report
 
 input.defaultlibs   = { -- not all are needed
     'l-string.lua', 'l-lpeg.lua', 'l-table.lua', 'l-boolean.lua', 'l-number.lua', 'l-set.lua', 'l-unicode.lua',
-    'l-md5.lua', 'l-os.lua', 'l-io.lua', 'l-file.lua', 'l-url.lua', 'l-dir.lua', 'l-utils.lua', 'l-tex.lua',
-    'luat-env.lua', 'luat-lib.lua', 'luat-inp.lua', 'luat-tmp.lua', 'luat-zip.lua', 'luat-tex.lua'
+    'l-md5.lua', 'l-os.lua', 'l-io.lua', 'l-file.lua', 'l-url.lua', 'l-dir.lua', 'l-utils.lua', 'l-dimen.lua',
+    'luat-lib.lua', 'luat-inp.lua', 'luat-env.lua', 'luat-tmp.lua', 'luat-zip.lua', 'luat-tex.lua'
 }
 
 -- todo: use environment.argument() instead of environment.arguments[]
 
+local instance = input.instance
+
 instance.engine     =     environment.arguments["engine"]   or 'luatex'
 instance.progname   =     environment.arguments["progname"] or 'context'
 instance.luaname    =     environment.arguments["luafile"]  or "" -- environment.ownname or ""
@@ -6328,19 +6726,19 @@ if environment.arguments["minimize"] the
     end
 end
 
-function input.my_prepare_a(instance)
-    input.resetconfig(instance)
-    input.identify_cnf(instance)
-    input.load_lua(instance)
-    input.expand_variables(instance)
-    input.load_cnf(instance)
-    input.expand_variables(instance)
+function input.my_prepare_a()
+    input.resetconfig()
+    input.identify_cnf()
+    input.load_lua()
+    input.expand_variables()
+    input.load_cnf()
+    input.expand_variables()
 end
 
-function input.my_prepare_b(instance)
-    input.my_prepare_a(instance)
-    input.load_hash(instance)
-    input.automount(instance)
+function input.my_prepare_b()
+    input.my_prepare_a()
+    input.load_hash()
+    input.automount()
 end
 
 -- barename
@@ -6382,10 +6780,11 @@ messages.help = [[
 --lsr             use lsr and cnf directly
 ]]
 
-function input.my_make_format(instance,texname)
+function input.my_make_format(texname)
+    local instance = input.instance
     if texname and texname ~= "" then
         if input.usecache then
-            local path = file.join(caches.setpath(instance,"formats")) -- maybe platform
+            local path = file.join(caches.setpath("formats")) -- maybe platform
             if path and lfs then
                 lfs.chdir(path)
             end
@@ -6394,22 +6793,22 @@ function input.my_make_format(instance,t
         if barename == texname then
             texname = texname .. ".tex"
         end
-        local fullname = input.find_files(instance,texname)[1] or ""
+        local fullname = input.find_files(texname)[1] or ""
         if fullname == "" then
-            input.report("no tex file with name",texname)
+            input.report("no tex file with name: %s",texname)
         else
             local luaname, lucname, luapath, lualibs = "", "", "", { }
             -- the following is optional, since context.lua can also
             -- handle this collect and compile business
             if environment.arguments["compile"] then
                 if luaname == "" then luaname = barename end
-                input.report("creating initialization file " .. luaname)
+                input.report("creating initialization file: %s",luaname)
                 luapath = file.dirname(luaname)
                 if luapath == "" then
                     luapath = file.dirname(texname)
                 end
                 if luapath == "" then
-                    luapath = file.dirname(input.find_files(instance,texname)[1] or "")
+                    luapath = file.dirname(input.find_files(texname)[1] or "")
                 end
                 lualibs = string.split(instance.lualibs,",")
                 luaname = file.basename(barename .. ".lua")
@@ -6419,27 +6818,28 @@ function input.my_make_format(instance,t
                 if lualibs[1] then
                     local firstlib = file.join(luapath,lualibs[1])
                     if not lfs.isfile(firstlib) then
-                        local foundname = input.find_files(instance,lualibs[1])[1]
+                        local foundname = input.find_files(lualibs[1])[1]
                         if foundname then
-                            input.report("located library path : " .. luapath)
+                            input.report("located library path: %s",luapath)
                             luapath = file.dirname(foundname)
                         end
                     end
                 end
-                input.report("using library path : " .. luapath)
-                input.report("using lua libraries: " .. table.join(lualibs," "))
+                input.report("using library path: %s",luapath)
+                input.report("using lua libraries: %s",table.join(lualibs," "))
                 utils.merger.selfcreate(lualibs,luapath,luaname)
-                if utils.lua.compile(luaname, lucname) and io.exists(lucname) then
+                local strip = input.boolean_variable("LUACSTRIP", true)
+                if utils.lua.compile(luaname,lucname,false,strip) and io.exists(lucname) then
                     luaname = lucname
-                    input.report("using compiled initialization file " .. lucname)
+                    input.report("using compiled initialization file: %s",lucname)
                 else
-                    input.report("using uncompiled initialization file " .. luaname)
+                    input.report("using uncompiled initialization file: %s",luaname)
                 end
             else
                 for _, v in pairs({instance.luaname, instance.progname, barename}) do
                     v = string.gsub(v..".lua","%.lua%.lua$",".lua")
                     if v and (v ~= "") then
-                        luaname = input.find_files(instance,v)[1] or ""
+                        luaname = input.find_files(v)[1] or ""
                         if luaname ~= "" then
                             break
                         end
@@ -6448,22 +6848,30 @@ function input.my_make_format(instance,t
             end
             if luaname == "" then
                 input.reportlines(messages.no_ini_file)
-                input.report("texname  : " .. texname)
-                input.report("luaname  : " .. instance.luaname)
-                input.report("progname : " .. instance.progname)
-                input.report("barename : " .. barename)
-            else
-                input.report("using lua initialization file " .. luaname)
+                input.report("texname : %s",texname)
+                input.report("luaname : %s",instance.luaname)
+                input.report("progname: %s",instance.progname)
+                input.report("barename: %s",barename)
+            else
+                input.report("using lua initialization file: %s",luaname)
+                local mp = dir.glob(file.stripsuffix(file.basename(luaname)).."-*.mem")
+                if mp and #mp > 0 then
+                    for _, name in ipairs(mp) do
+                        input.report("removing related mplib format %s", file.basename(name))
+                        os.remove(name)
+                    end
+                end
                 local flags = { "--ini" }
                 if environment.arguments["mkii"] then
                     flags[#flags+1] = "--progname=" .. instance.progname
                 else
                     flags[#flags+1] = "--lua=" .. string.quote(luaname)
                 end
-                local bs = (environment.platform == "unix" and "\\\\") or "\\" -- todo: make a function
+                local bs = (os.platform == "unix" and "\\\\") or "\\" -- todo: make a function
                 local command = "luatex ".. table.concat(flags," ")  .. " " .. string.quote(fullname) .. " " .. bs .. "dump"
-                input.report("running command: " .. command .. "\n")
+                input.report("running command: %s\n",command)
                 os.spawn(command)
+                -- todo: do a dummy run that generates the related metafun and mfplain formats
             end
         end
     else
@@ -6471,22 +6879,22 @@ function input.my_make_format(instance,t
     end
 end
 
-function input.my_run_format(instance,name,data,more)
+function input.my_run_format(name,data,more)
  -- hm, rather old code here; we can now use the file.whatever functions
     if name and (name ~= "") then
         local barename = name:gsub("%.%a+$","")
         local fmtname = ""
         if input.usecache then
-            local path = file.join(caches.setpath(instance,"formats")) -- maybe platform
+            local path = file.join(caches.setpath("formats")) -- maybe platform
             fmtname = file.join(path,barename..".fmt") or ""
         end
         if fmtname == "" then
-            fmtname = input.find_files(instance,barename..".fmt")[1] or ""
+            fmtname = input.find_files(barename..".fmt")[1] or ""
         end
         fmtname = input.clean_path(fmtname)
         barename = fmtname:gsub("%.%a+$","")
         if fmtname == "" then
-            input.report("no format with name",name)
+            input.report("no format with name: %s",name)
         else
             local luaname = barename .. ".luc"
             local f = io.open(luaname)
@@ -6497,11 +6905,11 @@ function input.my_run_format(instance,na
             if f then
                 f:close()
                 local command = "luatex --fmt=" .. string.quote(barename) .. " --lua=" .. string.quote(luaname) .. " " .. string.quote(data) .. " " .. string.quote(more)
-                input.report("running command: " .. command)
+                input.report("running command: %s",command)
                 os.spawn(command)
             else
-                input.report("using format name",fmtname)
-                input.report("no luc/lua with name",barename)
+                input.report("using format name: %s",fmtname)
+                input.report("no luc/lua with name: %s",barename)
             end
         end
     end
@@ -6519,8 +6927,9 @@ local function tabstr(str)
     end
 end
 
-local function list(instance,list)
-    local pat = string.upper(instance.pattern or "","")
+local function list(list)
+    local instance = input.instance
+    local pat = string.upper(pattern or "","")
     for _,key in pairs(table.sortedkeys(list)) do
         if instance.pattern == "" or string.find(key:upper(),pat) then
             if instance.kpseonly then
@@ -6534,10 +6943,11 @@ local function list(instance,list)
     end
 end
 
-function input.listers.variables (instance) list(instance,instance.variables ) end
-function input.listers.expansions(instance) list(instance,instance.expansions) end
+function input.listers.variables () list(input.instance.variables ) end
+function input.listers.expansions() list(input.instance.expansions) end
 
-function input.listers.configurations(instance)
+function input.listers.configurations()
+    local instance = input.instance
     for _,key in pairs(table.sortedkeys(instance.kpsevars)) do
         if not instance.pattern or (instance.pattern=="") or key:find(instance.pattern) then
             print(key.."\n")
@@ -6552,61 +6962,58 @@ function input.listers.configurations(in
     end
 end
 
-input.report(banner,"\n")
+input.report("%s\n",banner)
 
 local ok = true
 
 if environment.arguments["find-file"] then
-    input.my_prepare_b(instance)
+    input.my_prepare_b()
     instance.format  = environment.arguments["format"] or instance.format
     if instance.pattern then
         instance.allresults = true
-        input.for_files(instance, input.find_files, { instance.pattern }, instance.my_format)
+        input.for_files(input.find_files, { instance.pattern }, instance.my_format)
     else
-        input.for_files(instance, input.find_files, environment.files, instance.my_format)
+        input.for_files(input.find_files, environment.files, instance.my_format)
     end
 elseif environment.arguments["find-path"] then
-    input.my_prepare_b(instance)
-    local path = input.find_file(instance, environment.files[1], instance.my_format)
+    input.my_prepare_b()
+    local path = input.find_file(environment.files[1], instance.my_format)
     if input.verbose then
         input.report(file.dirname(path))
     else
         print(file.dirname(path))
     end
---~ elseif environment.arguments["first-writable-path"] then
---~     input.my_prepare_b(instance)
---~     input.report(input.first_writable_path(instance,environment.files[1] or "."))
 elseif environment.arguments["run"] then
-    input.my_prepare_a(instance) -- ! no need for loading databases
+    input.my_prepare_a() -- ! no need for loading databases
     input.verbose = true
-    input.my_run_format(instance,environment.files[1] or "",environment.files[2] or "",environment.files[3] or "")
+    input.my_run_format(environment.files[1] or "",environment.files[2] or "",environment.files[3] or "")
 elseif environment.arguments["fmt"] then
-    input.my_prepare_a(instance) -- ! no need for loading databases
+    input.my_prepare_a() -- ! no need for loading databases
     input.verbose = true
-    input.my_run_format(instance,environment.arguments["fmt"], environment.files[1] or "",environment.files[2] or "")
+    input.my_run_format(environment.arguments["fmt"], environment.files[1] or "",environment.files[2] or "")
 elseif environment.arguments["expand-braces"] then
-    input.my_prepare_a(instance)
-    input.for_files(instance, input.expand_braces, environment.files)
+    input.my_prepare_a()
+    input.for_files(input.expand_braces, environment.files)
 elseif environment.arguments["expand-path"] then
-    input.my_prepare_a(instance)
-    input.for_files(instance, input.expand_path, environment.files)
+    input.my_prepare_a()
+    input.for_files(input.expand_path, environment.files)
 elseif environment.arguments["expand-var"] or environment.arguments["expand-variable"] then
-    input.my_prepare_a(instance)
-    input.for_files(instance, input.expand_var, environment.files)
+    input.my_prepare_a()
+    input.for_files(input.expand_var, environment.files)
 elseif environment.arguments["show-path"] or environment.arguments["path-value"] then
-    input.my_prepare_a(instance)
-    input.for_files(instance, input.show_path, environment.files)
+    input.my_prepare_a()
+    input.for_files(input.show_path, environment.files)
 elseif environment.arguments["var-value"] or environment.arguments["show-value"] then
-    input.my_prepare_a(instance)
-    input.for_files(instance, input.var_value, environment.files)
+    input.my_prepare_a()
+    input.for_files(input.var_value, environment.files)
 elseif environment.arguments["format-path"] then
-    input.my_prepare_b(instance)
-    input.report(caches.setpath(instance,"format"))
+    input.my_prepare_b()
+    input.report(caches.setpath("format"))
 elseif instance.pattern then -- brrr
-    input.my_prepare_b(instance)
+    input.my_prepare_b()
     instance.format = environment.arguments["format"] or instance.format
     instance.allresults = true
-    input.for_files(instance, input.find_files, { instance.pattern }, instance.my_format)
+    input.for_files(input.find_files, { instance.pattern }, instance.my_format)
 elseif environment.arguments["generate"] then
     instance.renewcache = true
     input.verbose = true
@@ -6614,46 +7021,36 @@ elseif environment.arguments["generate"]
 elseif environment.arguments["make"] or environment.arguments["ini"] or environment.arguments["compile"] then
     input.my_prepare_b(instance)
     input.verbose = true
-    input.my_make_format(instance,environment.files[1] or "")
+    input.my_make_format(environment.files[1] or "")
 elseif environment.arguments["selfmerge"] then
     utils.merger.selfmerge(own.name,own.libs,own.list)
 elseif environment.arguments["selfclean"] then
     utils.merger.selfclean(own.name)
 elseif environment.arguments["selfupdate"] then
-    input.my_prepare_b(instance)
+    input.my_prepare_b()
     input.verbose = true
-    input.update_script(instance,own.name,"luatools")
+    input.update_script(own.name,"luatools")
 elseif environment.arguments["variables"] or environment.arguments["show-variables"] then
-    input.my_prepare_a(instance)
-    input.listers.variables(instance)
+    input.my_prepare_a()
+    input.listers.variables()
 elseif environment.arguments["expansions"] or environment.arguments["show-expansions"] then
-    input.my_prepare_a(instance)
-    input.listers.expansions(instance)
+    input.my_prepare_a()
+    input.listers.expansions()
 elseif environment.arguments["configurations"] or environment.arguments["show-configurations"] then
-    input.my_prepare_a(instance)
-    input.listers.configurations(instance)
+    input.my_prepare_a()
+    input.listers.configurations()
 elseif environment.arguments["help"] or (environment.files[1]=='help') or (#environment.files==0) then
-    if not input.verbose then
-        input.verbose = true
-        input.report(banner,"\n")
-    end
-    input.reportlines(messages.help)
+    input.help(banner,messages.help)
 else
-    input.my_prepare_b(instance)
-    input.for_files(instance, input.find_files, environment.files, instance.my_format)
+    input.my_prepare_b()
+    input.for_files(input.find_files, environment.files, instance.my_format)
 end
 
 if input.verbose then
     input.report("")
-    input.report(string.format("runtime: %0.3f seconds",os.runtime()))
+    input.report("runtime: %0.3f seconds",os.runtime())
 end
 
---~ if ok then
---~     input.report("exit code: 0") os.exit(0)
---~ else
---~     input.report("exit code: 1") os.exit(1)
---~ end
-
-if environment.platform == "unix" then
+if os.platform == "unix" then
     io.write("\n")
 end
--- texmf-dist/scripts/context/lua/mtxrun.lua
+++ texmf-dist/scripts/context/lua/mtxrun.lua	2008-10-30 14:05:20.903589570 +0100
@@ -37,7 +37,7 @@ if not modules then modules = { } end mo
 -- remember for subruns: _CTX_K_S_#{original}_
 -- remember for subruns: TEXMFSTART.#{original} [tex.rb texmfstart.rb]
 
-banner = "version 1.0.2 - 2007+ - PRAGMA ADE / CONTEXT"
+banner = "version 1.1.2 - 2007+ - PRAGMA ADE / CONTEXT" -- not local
 texlua = true
 
 -- begin library merge
@@ -125,7 +125,7 @@ end
 function string:splitchr(chr)
     if #self > 0 then
         local t = { }
-        for s in string.gmatch(self..chr,"(.-)"..chr) do
+        for s in (self..chr):gmatch("(.-)"..chr) do
             t[#t+1] = s
         end
         return t
@@ -134,22 +134,6 @@ function string:splitchr(chr)
     end
 end
 
---~ function string.piecewise(str, pat, fnc) -- variant of split
---~     local fpat = "(.-)"..pat
---~     local last_end = 1
---~     local s, e, cap = string.find(str, fpat, 1)
---~     while s ~= nil do
---~         if s~=1 or cap~="" then
---~             fnc(cap)
---~         end
---~         last_end = e+1
---~         s, e, cap = string.find(str, fpat, last_end)
---~     end
---~     if last_end <= #str then
---~         fnc((string.sub(str,last_end)))
---~     end
---~ end
-
 function string.piecewise(str, pat, fnc) -- variant of split
     for k in string.splitter(str,pat) do fnc(k) end
 end
@@ -191,7 +175,7 @@ end
 
 --~ end end
 
-string.chr_to_esc = {
+local chr_to_esc = {
     ["%"] = "%%",
     ["."] = "%.",
     ["+"] = "%+", ["-"] = "%-", ["*"] = "%*",
@@ -201,16 +185,18 @@ string.chr_to_esc = {
     ["{"] = "%{", ["}"] = "%}"
 }
 
+string.chr_to_esc = chr_to_esc
+
 function string:esc() -- variant 2
-    return (self:gsub("(.)",string.chr_to_esc))
+    return (self:gsub("(.)",chr_to_esc))
 end
 
-function string.unquote(str)
-    return (str:gsub("^([\"\'])(.*)%1$","%2"))
+function string:unquote()
+    return (self:gsub("^([\"\'])(.*)%1$","%2"))
 end
 
-function string.quote(str)
-    return '"' .. str:unquote() .. '"'
+function string:quote()
+    return '"' .. self:unquote() .. '"'
 end
 
 function string:count(pattern) -- variant 3
@@ -460,6 +446,30 @@ function string:splitlines()
     return capture:match(self)
 end
 
+--~ local p = lpeg.splitat("->",false)  print(p:match("oeps->what->more"))  -- oeps what more
+--~ local p = lpeg.splitat("->",true)   print(p:match("oeps->what->more"))  -- oeps what->more
+--~ local p = lpeg.splitat("->",false)  print(p:match("oeps"))              -- oeps
+--~ local p = lpeg.splitat("->",true)   print(p:match("oeps"))              -- oeps
+
+local splitters_s, splitters_m = { }, { }
+
+function lpeg.splitat(separator,single)
+    local splitter = (single and splitters_s[separator]) or splitters_m[separator]
+    if not splitter then
+        separator = lpeg.P(separator)
+        if single then
+            local other, any = lpeg.C((1 - separator)^0), lpeg.P(1)
+            splitter = other * (separator * lpeg.C(any^0) + "")
+            splitters_s[separator] = splitter
+        else
+            local other = lpeg.C((1 - separator)^0)
+            splitter = other * (separator * other)^0
+            splitters_m[separator] = splitter
+        end
+    end
+    return splitter
+end
+
 
 -- filename : l-table.lua
 -- comment  : split off from luat-lib
@@ -471,11 +481,15 @@ if not versions then versions = { } end 
 
 table.join = table.concat
 
+local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove
+local format = string.format
+local getmetatable, setmetatable = getmetatable, setmetatable
+local pairs, ipairs, type, next, tostring = pairs, ipairs, type, next, tostring
+
 function table.strip(tab)
     local lst = { }
-    for k, v in ipairs(tab) do
-     -- s = string.gsub(v, "^%s*(.-)%s*$", "%1")
-        s = v:gsub("^%s*(.-)%s*$", "%1")
+    for i=1,#tab do
+        local s = tab[i]:gsub("^%s*(.-)%s*$","%1")
         if s == "" then
             -- skip this one
         else
@@ -485,16 +499,7 @@ function table.strip(tab)
     return lst
 end
 
---~ function table.sortedkeys(tab)
---~     local srt = { }
---~     for key,_ in pairs(tab) do
---~         srt[#srt+1] = key
---~     end
---~     table.sort(srt)
---~     return srt
---~ end
-
-function table.sortedkeys(tab)
+local function sortedkeys(tab)
     local srt, kind = { }, 0 -- 0=unknown 1=string, 2=number 3=mixed
     for key,_ in pairs(tab) do
         srt[#srt+1] = key
@@ -514,22 +519,34 @@ function table.sortedkeys(tab)
         end
     end
     if kind == 0 or kind == 3 then
-        table.sort(srt,function(a,b) return (tostring(a) < tostring(b)) end)
+        sort(srt,function(a,b) return (tostring(a) < tostring(b)) end)
     else
-        table.sort(srt)
+        sort(srt)
     end
     return srt
 end
 
+local function sortedhashkeys(tab) -- fast one
+    local srt = { }
+    for key,_ in pairs(tab) do
+        srt[#srt+1] = key
+    end
+    sort(srt)
+    return srt
+end
+
+table.sortedkeys     = sortedkeys
+table.sortedhashkeys = sortedhashkeys
+
 function table.append(t, list)
     for _,v in pairs(list) do
-        table.insert(t,v)
+        insert(t,v)
     end
 end
 
 function table.prepend(t, list)
     for k,v in pairs(list) do
-        table.insert(t,k,v)
+        insert(t,k,v)
     end
 end
 
@@ -576,70 +593,57 @@ function table.imerged(...)
     return tmp
 end
 
-if not table.fastcopy then do
-
-    local type, pairs, getmetatable, setmetatable = type, pairs, getmetatable, setmetatable
-
-    local function fastcopy(old) -- fast one
-        if old then
-            local new = { }
-            for k,v in pairs(old) do
-                if type(v) == "table" then
-                    new[k] = fastcopy(v) -- was just table.copy
-                else
-                    new[k] = v
-                end
-            end
-            local mt = getmetatable(old)
-            if mt then
-                setmetatable(new,mt)
+local function fastcopy(old) -- fast one
+    if old then
+        local new = { }
+        for k,v in pairs(old) do
+            if type(v) == "table" then
+                new[k] = fastcopy(v) -- was just table.copy
+            else
+                new[k] = v
             end
-            return new
-        else
-            return { }
         end
+        local mt = getmetatable(old)
+        if mt then
+            setmetatable(new,mt)
+        end
+        return new
+    else
+        return { }
     end
+end
 
-    table.fastcopy = fastcopy
-
-end end
-
-if not table.copy then do
-
-    local type, pairs, getmetatable, setmetatable = type, pairs, getmetatable, setmetatable
-
-    local function copy(t, tables) -- taken from lua wiki, slightly adapted
-        tables = tables or { }
-        local tcopy = {}
-        if not tables[t] then
-            tables[t] = tcopy
-        end
-        for i,v in pairs(t) do -- brrr, what happens with sparse indexed
-            if type(i) == "table" then
-                if tables[i] then
-                    i = tables[i]
-                else
-                    i = copy(i, tables)
-                end
-            end
-            if type(v) ~= "table" then
-                tcopy[i] = v
-            elseif tables[v] then
-                tcopy[i] = tables[v]
+local function copy(t, tables) -- taken from lua wiki, slightly adapted
+    tables = tables or { }
+    local tcopy = {}
+    if not tables[t] then
+        tables[t] = tcopy
+    end
+    for i,v in pairs(t) do -- brrr, what happens with sparse indexed
+        if type(i) == "table" then
+            if tables[i] then
+                i = tables[i]
             else
-                tcopy[i] = copy(v, tables)
+                i = copy(i, tables)
             end
         end
-        local mt = getmetatable(t)
-        if mt then
-            setmetatable(tcopy,mt)
+        if type(v) ~= "table" then
+            tcopy[i] = v
+        elseif tables[v] then
+            tcopy[i] = tables[v]
+        else
+            tcopy[i] = copy(v, tables)
         end
-        return tcopy
     end
+    local mt = getmetatable(t)
+    if mt then
+        setmetatable(tcopy,mt)
+    end
+    return tcopy
+end
 
-    table.copy = copy
-
-end end
+table.fastcopy = fastcopy
+table.copy     = copy
 
 -- rougly: copy-loop : unpack : sub == 0.9 : 0.4 : 0.45 (so in critical apps, use unpack)
 
@@ -668,334 +672,363 @@ function table.starts_at(t)
     return ipairs(t,1)(t,0)
 end
 
-do
+function table.tohash(t,value)
+    local h = { }
+    if value == nil then value = true end
+    for _, v in pairs(t) do -- no ipairs here
+        h[v] = value
+    end
+    return h
+end
+
+function table.fromhash(t)
+    local h = { }
+    for k, v in pairs(t) do -- no ipairs here
+        if v then h[#h+1] = k end
+    end
+    return h
+end
 
-    -- one of my first exercises in lua ...
+--~ print(table.serialize(t), "\n")
+--~ print(table.serialize(t,"name"), "\n")
+--~ print(table.serialize(t,false), "\n")
+--~ print(table.serialize(t,true), "\n")
+--~ print(table.serialize(t,"name",true), "\n")
+--~ print(table.serialize(t,"name",true,true), "\n")
 
-    -- 34.055.092 32.403.326 arabtype.tma
-    --  1.620.614  1.513.863 lmroman10-italic.tma
-    --  1.325.585  1.233.044 lmroman10-regular.tma
-    --  1.248.157  1.158.903 lmsans10-regular.tma
-    --    194.646    153.120 lmtypewriter10-regular.tma
-    --  1.771.678  1.658.461 palatinosanscom-bold.tma
-    --  1.695.251  1.584.491 palatinosanscom-regular.tma
-    -- 13.736.534 13.409.446 zapfinoextraltpro.tma
-
-    -- 13.679.038 11.774.106 arabtype.tmc
-    --    886.248    754.944 lmroman10-italic.tmc
-    --    729.828    466.864 lmroman10-regular.tmc
-    --    688.482    441.962 lmsans10-regular.tmc
-    --    128.685     95.853 lmtypewriter10-regular.tmc
-    --    715.929    582.985 palatinosanscom-bold.tmc
-    --    669.942    540.126 palatinosanscom-regular.tmc
-    --  1.560.588  1.317.000 zapfinoextraltpro.tmc
-
-    table.serialize_functions = true
-    table.serialize_compact   = true
-    table.serialize_inline    = true
+table.serialize_functions = true
+table.serialize_compact   = true
+table.serialize_inline    = true
+
+local noquotes, hexify, handle, reduce, compact, inline, functions
+
+local reserved = table.tohash { -- intercept a language flaw, no reserved words as key
+    'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if',
+    'in', 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while',
+}
 
-    local function key(k)
-        if type(k) == "number" then -- or k:find("^%d+$") then
-            return "["..k.."]"
-        elseif noquotes and k:find("^%a[%a%d%_]*$") then
-            return k
+local function key(k)
+    if type(k) == "number" then -- or k:find("^%d+$") then
+        if hexify then
+            return ("[0x%04X]"):format(k)
         else
-            return '["'..k..'"]'
+            return "["..k.."]"
         end
+    elseif noquotes and not reserved[k] and k:find("^%a[%a%d%_]*$") then
+        return k
+    else
+        return '["'..k..'"]'
     end
+end
 
-    local function simple_table(t)
-        if #t > 0 then
-            local n = 0
-            for _,v in pairs(t) do
-                n = n + 1
-            end
-            if n == #t then
-                local tt = { }
-                for i=1,#t do
-                    local v = t[i]
-                    local tv = type(v)
-                    if tv == "number" or tv == "boolean" then
-                        tt[#tt+1] = tostring(v)
-                    elseif tv == "string" then
-                        tt[#tt+1] = ("%q"):format(v)
+local function simple_table(t)
+    if #t > 0 then
+        local n = 0
+        for _,v in pairs(t) do
+            n = n + 1
+        end
+        if n == #t then
+            local tt = { }
+            for i=1,#t do
+                local v = t[i]
+                local tv = type(v)
+                if tv == "number" then
+                    if hexify then
+                        tt[#tt+1] = ("0x%04X"):format(v)
                     else
-                        tt = nil
-                        break
+                        tt[#tt+1] = tostring(v)
                     end
+                elseif tv == "boolean" then
+                    tt[#tt+1] = tostring(v)
+                elseif tv == "string" then
+                    tt[#tt+1] = ("%q"):format(v)
+                else
+                    tt = nil
+                    break
                 end
-                return tt
             end
+            return tt
         end
-        return nil
     end
+    return nil
+end
 
-    local function serialize(root,name,handle,depth,level,reduce,noquotes,indexed)
-        handle = handle or print
-        reduce = reduce or false
-        if depth then
-            depth = depth .. " "
-            if indexed then
-                handle(("%s{"):format(depth))
-            else
-                handle(("%s%s={"):format(depth,key(name)))
-            end
-        else
-            depth = ""
-            local tname = type(name)
-            if tname == "string" then
-                if name == "return" then
-                    handle("return {")
-                else
-                    handle(name .. "={")
-                end
-            elseif tname == "number" then
-                handle("[" .. name .. "]={")
-            elseif tname == "boolean" then
-                if name then
-                    handle("return {")
-                else
-                    handle("{")
-                end
-            else
-                handle("t={")
-            end
-        end
-        if root and next(root) then
-            local compact = table.serialize_compact
-            local inline  = compact and table.serialize_inline
-            local first, last = nil, 0 -- #root cannot be trusted here
-            if compact then
-              for k,v in ipairs(root) do -- NOT: for k=1,#root do (why)
-                    if not first then first = k end
-                    last = last + 1
-                end
-            end
-            for _,k in pairs(table.sortedkeys(root)) do
-                local v = root[k]
-                local t = type(v)
-                if compact and first and type(k) == "number" and k >= first and k <= last then
-                    if t == "number" then
-                        handle(("%s %s,"):format(depth,v))
-                    elseif t == "string" then
-                        if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then
-                            handle(("%s %s,"):format(depth,v))
-                        else
-                            handle(("%s %q,"):format(depth,v))
-                        end
-                    elseif t == "table" then
-                        if not next(v) then
-                            handle(("%s {},"):format(depth))
-                        elseif inline then
-                            local st = simple_table(v)
-                            if st then
-                                handle(("%s { %s },"):format(depth,table.concat(st,", ")))
-                            else
-                                serialize(v,k,handle,depth,level+1,reduce,noquotes,true)
-                            end
-                        else
-                            serialize(v,k,handle,depth,level+1,reduce,noquotes,true)
-                        end
-                    elseif t == "boolean" then
-                        handle(("%s %s,"):format(depth,tostring(v)))
-                    elseif t == "function" then
-                        if table.serialize_functions then
-                            handle(('%s loadstring(%q),'):format(depth,string.dump(v)))
-                        else
-                            handle(('%s "function",'):format(depth))
-                        end
+local function do_serialize(root,name,depth,level,indexed)
+    if level > 0 then
+        depth = depth .. " "
+        if indexed then
+            handle(("%s{"):format(depth))
+        elseif name then
+            handle(("%s%s={"):format(depth,key(name)))
+        else
+            handle(("%s{"):format(depth))
+        end
+    end
+    if root and next(root) then
+        local first, last = nil, 0 -- #root cannot be trusted here
+        if compact then
+          for k,v in ipairs(root) do -- NOT: for k=1,#root do (we need to quit at nil)
+                if not first then first = k end
+                last = last + 1
+            end
+        end
+    --~ for _,k in pairs(sortedkeys(root)) do -- 1% faster:
+        local sk = sortedkeys(root)
+        for i=1,#sk do
+            local k = sk[i]
+            local v = root[k]
+            local t = type(v)
+            if compact and first and type(k) == "number" and k >= first and k <= last then
+                if t == "number" then
+                    if hexify then
+                        handle(("%s 0x%04X,"):format(depth,v))
                     else
-                        handle(("%s %q,"):format(depth,tostring(v)))
-                    end
-                elseif k == "__p__" then -- parent
-                    if false then
-                        handle(("%s __p__=nil,"):format(depth))
+                        handle(("%s %s,"):format(depth,v))
                     end
-                elseif t == "number" then
-                    handle(("%s %s=%s,"):format(depth,key(k),v))
                 elseif t == "string" then
                     if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then
-                        handle(("%s %s=%s,"):format(depth,key(k),v))
+                        handle(("%s %s,"):format(depth,v))
                     else
-                        handle(("%s %s=%q,"):format(depth,key(k),v))
+                        handle(("%s %q,"):format(depth,v))
                     end
                 elseif t == "table" then
                     if not next(v) then
-                        handle(("%s %s={},"):format(depth,key(k)))
+                        handle(("%s {},"):format(depth))
                     elseif inline then
                         local st = simple_table(v)
                         if st then
-                            handle(("%s %s={ %s },"):format(depth,key(k),table.concat(st,", ")))
+                            handle(("%s { %s },"):format(depth,concat(st,", ")))
                         else
-                            serialize(v,k,handle,depth,level+1,reduce,noquotes)
+                            do_serialize(v,k,depth,level+1,true)
                         end
                     else
-                        serialize(v,k,handle,depth,level+1,reduce,noquotes)
+                        do_serialize(v,k,depth,level+1,true)
                     end
                 elseif t == "boolean" then
-                    handle(("%s %s=%s,"):format(depth,key(k),tostring(v)))
+                    handle(("%s %s,"):format(depth,tostring(v)))
                 elseif t == "function" then
-                    if table.serialize_functions then
-                        handle(('%s %s=loadstring(%q),'):format(depth,key(k),string.dump(v)))
+                    if functions then
+                        handle(('%s loadstring(%q),'):format(depth,v:dump()))
                     else
-                        handle(('%s %s="function",'):format(depth,key(k)))
+                        handle(('%s "function",'):format(depth))
                     end
                 else
-                    handle(("%s %s=%q,"):format(depth,key(k),tostring(v)))
-                --  handle(('%s %s=loadstring(%q),'):format(depth,key(k),string.dump(function() return v end)))
+                    handle(("%s %q,"):format(depth,tostring(v)))
+                end
+            elseif k == "__p__" then -- parent
+                if false then
+                    handle(("%s __p__=nil,"):format(depth))
+                end
+            elseif t == "number" then
+                if hexify then
+                    handle(("%s %s=0x%04X,"):format(depth,key(k),v))
+                else
+                    handle(("%s %s=%s,"):format(depth,key(k),v))
+                end
+            elseif t == "string" then
+                if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+                    handle(("%s %s=%s,"):format(depth,key(k),v))
+                else
+                    handle(("%s %s=%q,"):format(depth,key(k),v))
+                end
+            elseif t == "table" then
+                if not next(v) then
+                    handle(("%s %s={},"):format(depth,key(k)))
+                elseif inline then
+                    local st = simple_table(v)
+                    if st then
+                        handle(("%s %s={ %s },"):format(depth,key(k),concat(st,", ")))
+                    else
+                        do_serialize(v,k,depth,level+1)
+                    end
+                else
+                    do_serialize(v,k,depth,level+1)
+                end
+            elseif t == "boolean" then
+                handle(("%s %s=%s,"):format(depth,key(k),tostring(v)))
+            elseif t == "function" then
+                if functions then
+                    handle(('%s %s=loadstring(%q),'):format(depth,key(k),v:dump()))
+                else
+                    handle(('%s %s="function",'):format(depth,key(k)))
                 end
-            end
-            if level > 0 then
-                handle(("%s},"):format(depth))
             else
-                handle(("%s}"):format(depth))
+                handle(("%s %s=%q,"):format(depth,key(k),tostring(v)))
+            --  handle(('%s %s=loadstring(%q),'):format(depth,key(k),string.dump(function() return v end)))
             end
-        else
-            handle(("%s}"):format(depth))
         end
     end
+   if level > 0 then
+        handle(("%s},"):format(depth))
+    end
+end
 
-    --~ name:
-    --~
-    --~ true     : return     { }
-    --~ false    :            { }
-    --~ nil      : t        = { }
-    --~ string   : string   = { }
-    --~ 'return' : return     { }
-    --~ number   : [number] = { }
-
-    function table.serialize(root,name,reduce,noquotes)
-        local t = { }
-        local function flush(s)
-            t[#t+1] = s
+local function serialize(root,name,_handle,_reduce,_noquotes,_hexify)
+    noquotes = _noquotes
+    hexify = _hexify
+    handle = _handle or print
+    reduce = _reduce or false
+    compact = table.serialize_compact
+    inline  = compact and table.serialize_inline
+    functions = table.serialize_functions
+    local tname = type(name)
+    if tname == "string" then
+        if name == "return" then
+            handle("return {")
+        else
+            handle(name .. "={")
+        end
+    elseif tname == "number" then
+        if hexify then
+            handle(("[0x%04X]={"):format(name))
+        else
+            handle("[" .. name .. "]={")
         end
-        serialize(root, name, flush, nil, 0, reduce, noquotes)
-        return table.concat(t,"\n")
+    elseif tname == "boolean" then
+        if name then
+            handle("return {")
+        else
+            handle("{")
+        end
+    else
+        handle("t={")
     end
+    if root and next(root) then
+        do_serialize(root,name,"",0,indexed)
+    end
+    handle("}")
+end
+
+--~ name:
+--~
+--~ true     : return     { }
+--~ false    :            { }
+--~ nil      : t        = { }
+--~ string   : string   = { }
+--~ 'return' : return     { }
+--~ number   : [number] = { }
 
-    function table.tohandle(handle,root,name,reduce,noquotes)
-        serialize(root, name, handle, nil, 0, reduce, noquotes)
+function table.serialize(root,name,reduce,noquotes,hexify)
+    local t = { }
+    local function flush(s)
+        t[#t+1] = s
     end
+    serialize(root,name,flush,reduce,noquotes,hexify)
+    return concat(t,"\n")
+end
 
-    -- sometimes tables are real use (zapfino extra pro is some 85M) in which
-    -- case a stepwise serialization is nice; actually, we could consider:
-    --
-    -- for line in table.serializer(root,name,reduce,noquotes) do
-    --    ...(line)
-    -- end
-    --
-    -- so this is on the todo list
+function table.tohandle(handle,root,name,reduce,noquotes,hexify)
+    serialize(root,name,handle,reduce,noquotes,hexify)
+end
 
-    table.tofile_maxtab = 2*1024
+-- sometimes tables are real use (zapfino extra pro is some 85M) in which
+-- case a stepwise serialization is nice; actually, we could consider:
+--
+-- for line in table.serializer(root,name,reduce,noquotes) do
+--    ...(line)
+-- end
+--
+-- so this is on the todo list
 
-    function table.tofile(filename,root,name,reduce,noquotes)
-        local f = io.open(filename,'w')
-        if f then
-            local concat = table.concat
-            local maxtab = table.tofile_maxtab
-            if maxtab > 1 then
-                local t = { }
-                local function flush(s)
-                    t[#t+1] = s
-                    if #t > maxtab then
-                        f:write(concat(t,"\n"),"\n") -- hm, write(sometable) should be nice
-                        t = { }
-                    end
-                end
-                serialize(root, name, flush, nil, 0, reduce, noquotes)
-                f:write(concat(t,"\n"),"\n")
-            else
-                local function flush(s)
-                    f:write(s,"\n")
+table.tofile_maxtab = 2*1024
+
+function table.tofile(filename,root,name,reduce,noquotes,hexify)
+    local f = io.open(filename,'w')
+    if f then
+        local maxtab = table.tofile_maxtab
+        if maxtab > 1 then
+            local t = { }
+            local function flush(s)
+                t[#t+1] = s
+                if #t > maxtab then
+                    f:write(concat(t,"\n"),"\n") -- hm, write(sometable) should be nice
+                    t = { }
                 end
-                serialize(root, name, flush, nil, 0, reduce, noquotes)
             end
-            f:close()
+            serialize(root,name,flush,reduce,noquotes,hexify)
+            f:write(concat(t,"\n"),"\n")
+        else
+            local function flush(s)
+                f:write(s,"\n")
+            end
+            serialize(root,name,flush,reduce,noquotes,hexify)
         end
+        f:close()
     end
-
 end
 
---~ t = {
---~     b = "123",
---~     a = "x",
---~     c = 1.23,
---~     d = "1.23",
---~     e = true,
---~     f = {
---~         d = "1.23",
---~         a = "x",
---~         b = "123",
---~         c = 1.23,
---~         e = true,
---~         f = {
---~             e = true,
---~             f = {
---~                 e = true
---~             },
---~         },
---~     },
---~     g = function() end
---~ }
-
---~ print(table.serialize(t), "\n")
---~ print(table.serialize(t,"name"), "\n")
---~ print(table.serialize(t,false), "\n")
---~ print(table.serialize(t,true), "\n")
---~ print(table.serialize(t,"name",true), "\n")
---~ print(table.serialize(t,"name",true,true), "\n")
-
-do
-
-    local function flatten(t,f,complete)
-        for i=1,#t do
-            local v = t[i]
-            if type(v) == "table" then
-                if complete or type(v[1]) == "table" then
-                    flatten(v,f,complete)
-                else
-                    f[#f+1] = v
-                end
+local function flatten(t,f,complete)
+    for i=1,#t do
+        local v = t[i]
+        if type(v) == "table" then
+            if complete or type(v[1]) == "table" then
+                flatten(v,f,complete)
             else
                 f[#f+1] = v
             end
+        else
+            f[#f+1] = v
         end
     end
+end
 
-    function table.flatten(t)
-        local f = { }
-        flatten(t,f,true)
-        return f
-    end
+function table.flatten(t)
+    local f = { }
+    flatten(t,f,true)
+    return f
+end
 
-    function table.unnest(t) -- bad name
-        local f = { }
-        flatten(t,f,false)
-        return f
-    end
+function table.unnest(t) -- bad name
+    local f = { }
+    flatten(t,f,false)
+    return f
+end
 
-    table.flatten_one_level = table.unnest
+table.flatten_one_level = table.unnest
 
+-- the next three may disappear
+
+function table.remove_value(t,value) -- todo: n
+    if value then
+        for i=1,#t do
+            if t[i] == value then
+                remove(t,i)
+                -- remove all, so no: return
+            end
+        end
+    end
 end
 
 function table.insert_before_value(t,value,str)
-    for i=1,#t do
-        if t[i] == value then
-            table.insert(t,i,str)
-            return
+    if str then
+        if value then
+            for i=1,#t do
+                if t[i] == value then
+                    insert(t,i,str)
+                    return
+                end
+            end
         end
+        insert(t,1,str)
+    elseif value then
+        insert(t,1,value)
     end
-    table.insert(t,1,str)
 end
 
 function table.insert_after_value(t,value,str)
-    for i=1,#t do
-        if t[i] == value then
-            table.insert(t,i+1,str)
-            return
+    if str then
+        if value then
+            for i=1,#t do
+                if t[i] == value then
+                    insert(t,i+1,str)
+                    return
+                end
+            end
         end
+        t[#t+1] = str
+    elseif value then
+        t[#t+1] = value
     end
-    t[#t+1] = str
 end
 
 function table.are_equal(a,b,n,m)
@@ -1026,27 +1059,11 @@ function table.compact(t)
     end
 end
 
-function table.tohash(t)
-    local h = { }
-    for _, v in pairs(t) do -- no ipairs here
-        h[v] = true
-    end
-    return h
-end
-
-function table.fromhash(t)
-    local h = { }
-    for k, v in pairs(t) do -- no ipairs here
-        if v then h[#h+1] = k end
-    end
-    return h
-end
-
 function table.contains(t, v)
     if t then
         for i=1, #t do
             if t[i] == v then
-                return true
+                return i
             end
         end
     end
@@ -1083,11 +1100,10 @@ function table.clone(t,p) -- t is option
     return t
 end
 
-
 function table.hexed(t,seperator)
     local tt = { }
-    for i=1,#t do tt[i] = string.format("0x%04X",t[i]) end
-    return table.concat(tt,seperator or " ")
+    for i=1,#t do tt[i] = ("0x%04X"):format(t[i]) end
+    return concat(tt,seperator or " ")
 end
 
 function table.reverse_hash(h)
@@ -1127,6 +1143,7 @@ function io.loaddata(filename)
     local f = io.open(filename,'rb')
     if f then
         local data = f:read('*all')
+    --  garbagecollector.check(data)
         f:close()
         return data
     else
@@ -1135,7 +1152,7 @@ function io.loaddata(filename)
 end
 
 function io.savedata(filename,data,joiner)
-    local f = io.open(filename, "wb")
+    local f = io.open(filename,"wb")
     if f then
         if type(data) == "table" then
             f:write(table.join(data,joiner or ""))
@@ -1145,6 +1162,9 @@ function io.savedata(filename,data,joine
             f:write(data)
         end
         f:close()
+        return true
+    else
+        return false
     end
 end
 
@@ -1499,6 +1519,9 @@ end
 -- copyright: PRAGMA ADE / ConTeXt Development Team
 -- license  : see context related readme files
 
+
+--~ print(table.serialize(os.uname()))
+
 if not versions then versions = { } end versions['l-os'] = 1.001
 
 function os.resultof(command)
@@ -1574,10 +1597,14 @@ if not versions then versions = { } end 
 
 if not file then file = { } end
 
+local concat = table.concat
+
 function file.removesuffix(filename)
-    return filename:gsub("%.[%a%d]+$", "")
+    return (filename:gsub("%.[%a%d]+$",""))
 end
 
+file.stripsuffix = file.removesuffix
+
 function file.addsuffix(filename, suffix)
     if not filename:find("%.[%a%d]+$") then
         return filename .. "." .. suffix
@@ -1587,11 +1614,7 @@ function file.addsuffix(filename, suffix
 end
 
 function file.replacesuffix(filename, suffix)
-    if not filename:find("%.[%a%d]+$") then
-        return filename .. "." .. suffix
-    else
-        return (filename:gsub("%.[%a%d]+$","."..suffix))
-    end
+    return (filename:gsub("%.[%a%d]+$","")) .. "." .. suffix
 end
 
 function file.dirname(name)
@@ -1612,18 +1635,6 @@ end
 
 file.suffix = file.extname
 
-function file.stripsuffix(name)
-    return (name:gsub("%.[%a%d]+$",""))
-end
-
---~ function file.join(...)
---~     local t = { ... }
---~     for i=1,#t do
---~         t[i] = (t[i]:gsub("\\","/")):gsub("/+$","")
---~     end
---~     return table.concat(t,"/")
---~ end
-
 --~ print(file.join("x/","/y"))
 --~ print(file.join("http://","/y"))
 --~ print(file.join("http://a","/y"))
@@ -1631,7 +1642,7 @@ end
 --~ print(file.join("//nas-1","/y"))
 
 function file.join(...)
-    local pth = table.concat({...},"/")
+    local pth = concat({...},"/")
     pth = pth:gsub("\\","/")
     local a, b = pth:match("^(.*://)(.*)$")
     if a and b then
@@ -1664,6 +1675,16 @@ function file.is_readable(name)
     end
 end
 
+function file.iswritable(name)
+    local a = lfs.attributes(name)
+    return a and a.permissions:sub(2,2) == "w"
+end
+
+function file.isreadable(name)
+    local a = lfs.attributes(name)
+    return a and a.permissions:sub(1,1) == "r"
+end
+
 --~ function file.split_path(str)
 --~     if str:find(';') then
 --~         return str:splitchr(";")
@@ -1688,37 +1709,29 @@ function file.split_path(str)
 end
 
 function file.join_path(tab)
-    return table.concat(tab,io.pathseparator) -- can have trailing //
+    return concat(tab,io.pathseparator) -- can have trailing //
 end
 
---~ print('test'           .. " == " .. file.collapse_path("test"))
---~ print("test/test"      .. " == " .. file.collapse_path("test/test"))
---~ print("test/test/test" .. " == " .. file.collapse_path("test/test/test"))
---~ print("test/test"      .. " == " .. file.collapse_path("test/../test/test"))
---~ print("test"           .. " == " .. file.collapse_path("test/../test"))
---~ print("../test"        .. " == " .. file.collapse_path("../test"))
---~ print("../test/"       .. " == " .. file.collapse_path("../test/"))
---~ print("a/a"            .. " == " .. file.collapse_path("a/b/c/../../a"))
-
---~ function file.collapse_path(str)
---~     local ok, n = false, 0
---~     while not ok do
---~         ok = true
---~         str, n = str:gsub("[^%./]+/%.%./", function(s)
---~             ok = false
---~             return ""
---~         end)
---~     end
---~     return (str:gsub("/%./","/"))
---~ end
-
 function file.collapse_path(str)
-    local n = 1
-    while n > 0 do
-        str, n = str:gsub("([^/%.]+/%.%./)","")
-    end
-    return (str:gsub("/%./","/"))
-end
+    str = str:gsub("/%./","/")
+    local n, m = 1, 1
+    while n > 0 or m > 0 do
+        str, n = str:gsub("[^/%.]+/%.%.$","")
+        str, m = str:gsub("[^/%.]+/%.%./","")
+    end
+    str = str:gsub("([^/])/$","%1")
+    str = str:gsub("^%./","")
+    str = str:gsub("/%.$","")
+    if str == "" then str = "." end
+    return str
+end
+
+--~ print(file.collapse_path("a/./b/.."))
+--~ print(file.collapse_path("a/aa/../b/bb"))
+--~ print(file.collapse_path("a/../.."))
+--~ print(file.collapse_path("a/.././././b/.."))
+--~ print(file.collapse_path("a/./././b/.."))
+--~ print(file.collapse_path("a/b/c/../.."))
 
 function file.robustname(str)
     return (str:gsub("[^%a%d%/%-%.\\]+","-"))
@@ -1731,6 +1744,98 @@ function file.copy(oldname,newname)
     file.savedata(newname,io.loaddata(oldname))
 end
 
+-- lpeg variants, slightly faster, not always
+
+--~ local period    = lpeg.P(".")
+--~ local slashes   = lpeg.S("\\/")
+--~ local noperiod  = 1-period
+--~ local noslashes = 1-slashes
+--~ local name      = noperiod^1
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.C(noperiod^1) * -1
+
+--~ function file.extname(name)
+--~     return pattern:match(name) or ""
+--~ end
+
+--~ local pattern = lpeg.Cs(((period * noperiod^1 * -1)/"" + 1)^1)
+
+--~ function file.removesuffix(name)
+--~     return pattern:match(name)
+--~ end
+
+--~ file.stripsuffix = file.removesuffix
+
+--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.C(noslashes^1) * -1
+
+--~ function file.basename(name)
+--~     return pattern:match(name) or name
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.Cp() * noslashes^1 * -1
+
+--~ function file.dirname(name)
+--~     local p = pattern:match(name)
+--~     if p then
+--~         return name:sub(1,p-2)
+--~     else
+--~         return ""
+--~     end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+
+--~ function file.addsuffix(name, suffix)
+--~     local p = pattern:match(name)
+--~     if p then
+--~         return name
+--~     else
+--~         return name .. "." .. suffix
+--~     end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+
+--~ function file.replacesuffix(name,suffix)
+--~     local p = pattern:match(name)
+--~     if p then
+--~         return name:sub(1,p-2) .. "." .. suffix
+--~     else
+--~         return name .. "." .. suffix
+--~     end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * lpeg.Cp() * ((noperiod^1 * period)^1 * lpeg.Cp() + lpeg.P(true)) * noperiod^1 * -1
+
+--~ function file.nameonly(name)
+--~     local a, b = pattern:match(name)
+--~     if b then
+--~         return name:sub(a,b-2)
+--~     elseif a then
+--~         return name:sub(a)
+--~     else
+--~         return name
+--~     end
+--~ end
+
+--~ local test = file.extname
+--~ local test = file.stripsuffix
+--~ local test = file.basename
+--~ local test = file.dirname
+--~ local test = file.addsuffix
+--~ local test = file.replacesuffix
+--~ local test = file.nameonly
+
+--~ print(1,test("./a/b/c/abd.def.xxx","!!!"))
+--~ print(2,test("./../b/c/abd.def.xxx","!!!"))
+--~ print(3,test("a/b/c/abd.def.xxx","!!!"))
+--~ print(4,test("a/b/c/def.xxx","!!!"))
+--~ print(5,test("a/b/c/def","!!!"))
+--~ print(6,test("def","!!!"))
+--~ print(7,test("def.xxx","!!!"))
+
+--~ local tim = os.clock() for i=1,250000 do local ext = test("abd.def.xxx","!!!") end print(os.clock()-tim)
+
 
 -- filename : l-dir.lua
 -- comment  : split off from luat-lib
@@ -1746,51 +1851,6 @@ dir = { }
 
 if lfs then do
 
---~     local attributes = lfs.attributes
---~     local walkdir    = lfs.dir
---~
---~     local function glob_pattern(path,patt,recurse,action)
---~         local ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe
---~         if ok and type(scanner) == "function" then
---~             if not path:find("/$") then path = path .. '/' end
---~             for name in scanner do
---~                 local full = path .. name
---~                 local mode = attributes(full,'mode')
---~                 if mode == 'file' then
---~                     if name:find(patt) then
---~                         action(full)
---~                     end
---~                 elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
---~                     glob_pattern(full,patt,recurse,action)
---~                 end
---~             end
---~         end
---~     end
---~
---~     dir.glob_pattern = glob_pattern
---~
---~     local function glob(pattern, action)
---~         local t = { }
---~         local action = action or function(name) t[#t+1] = name end
---~         local path, patt = pattern:match("^(.*)/*%*%*/*(.-)$")
---~         local recurse = path and patt
---~         if not recurse then
---~             path, patt = pattern:match("^(.*)/(.-)$")
---~             if not (path and patt) then
---~                 path, patt = '.', pattern
---~             end
---~         end
---~         patt = patt:gsub("([%.%-%+])", "%%%1")
---~         patt = patt:gsub("%*", ".*")
---~         patt = patt:gsub("%?", ".")
---~         patt = "^" .. patt .. "$"
---~      -- print('path: ' .. path .. ' | pattern: ' .. patt .. ' | recurse: ' .. tostring(recurse))
---~         glob_pattern(path,patt,recurse,action)
---~         return t
---~     end
---~
---~     dir.glob = glob
-
     local attributes = lfs.attributes
     local walkdir    = lfs.dir
 
@@ -1819,30 +1879,6 @@ if lfs then do
 
     dir.glob_pattern = glob_pattern
 
-    --~ local function glob(pattern, action)
-    --~     local t = { }
-    --~     local path, rest, patt, recurse
-    --~     local action = action or function(name) t[#t+1] = name end
-    --~     local pattern = pattern:gsub("^%*%*","./**")
-    --~     local pattern = pattern:gsub("/%*/","/**/")
-    --~     path, rest = pattern:match("^(/)(.-)$")
-    --~     if path then
-    --~         path = path
-    --~     else
-    --~         path, rest = pattern:match("^([^/]*)/(.-)$")
-    --~     end
-    --~     if rest then
-    --~         patt = rest:gsub("([%.%-%+])", "%%%1")
-    --~     end
-    --~     patt = patt:gsub("%*", "[^/]*")
-    --~     patt = patt:gsub("%?", "[^/]")
-    --~     patt = patt:gsub("%[%^/%]%*%[%^/%]%*", ".*")
-    --~     if path == "" then path = "." end
-    --~     recurse = patt:find("%.%*/") ~= nil
-    --~     glob_pattern(path,patt,recurse,action)
-    --~     return t
-    --~ end
-
     local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
 
     local pattern = Ct {
@@ -1868,13 +1904,17 @@ if lfs then do
                 glob(s,t)
             end
             return t
+        elseif lfs.isfile(str) then
+            local t = t or { }
+            t[#t+1] = str
+            return t
         else
             local split = pattern:match(str)
             if split then
                 local t = t or { }
                 local action = action or function(name) t[#t+1] = name end
                 local root, path, base = split[1], split[2], split[3]
-                local recurse = base:find("**")
+                local recurse = base:find("%*%*")
                 local start = root .. path
                 local result = filter:match(start .. base)
                 glob_pattern(start,result,recurse,action)
@@ -1902,16 +1942,21 @@ if lfs then do
         for name in walkdir(path) do
             if name:find("^%.") then
                 --- skip
-            elseif attributes(name,'mode') == "directory" then
-                if recurse then
-                    globfiles(path .. "/" .. name,recurse,func,files)
-                end
-            elseif func then
-                if func(name) then
-                    files[#files+1] = path .. "/" .. name
-                end
             else
-                files[#files+1] = path .. "/" .. name
+                local mode = attributes(name,'mode')
+                if mode == "directory" then
+                    if recurse then
+                        globfiles(path .. "/" .. name,recurse,func,files)
+                    end
+                elseif mode == "file" then
+                    if func then
+                        if func(name) then
+                            files[#files+1] = path .. "/" .. name
+                        end
+                    else
+                        files[#files+1] = path .. "/" .. name
+                    end
+                end
             end
         end
         return files
@@ -2119,7 +2164,7 @@ function toboolean(str,tolerant)
     if tolerant then
         local tstr = type(str)
         if tstr == "string" then
-            return str == "true" or str == "yes" or str == "on" or str == "1"
+            return str == "true" or str == "yes" or str == "on" or str == "1" or str == "t"
         elseif tstr == "number" then
             return tonumber(str) ~= 0
         elseif tstr == "nil" then
@@ -2138,9 +2183,9 @@ end
 
 function string.is_boolean(str)
     if type(str) == "string" then
-        if str == "true" or str == "yes" or str == "on" then
+        if str == "true" or str == "yes" or str == "on" or str == "t" then
             return true
-        elseif str == "false" or str == "no" or str == "off" then
+        elseif str == "false" or str == "no" or str == "off" or str == "f" then
             return false
         end
     end
@@ -2156,6 +2201,35 @@ function boolean.falsetrue()
 end
 
 
+-- filename : l-math.lua
+-- comment  : split off from luat-lib
+-- author   : Hans Hagen, PRAGMA-ADE, Hasselt NL
+-- copyright: PRAGMA ADE / ConTeXt Development Team
+-- license  : see context related readme files
+
+if not versions then versions = { } end versions['l-math'] = 1.001
+
+local floor = math.floor
+
+if not math.round then
+    function math.round(x)
+        return floor(x + 0.5)
+    end
+end
+
+if not math.div then
+    function math.div(n,m)
+        return floor(n/m)
+    end
+end
+
+if not math.mod then
+    function math.mod(n,m)
+        return n % m
+    end
+end
+
+
 if not modules then modules = { } end modules ['l-xml'] = {
     version   = 1.001,
     comment   = "this module is the basis for the lxml-* ones",
@@ -2199,11 +2273,11 @@ xml.trace_lpath = false
 xml.trace_print = false
 xml.trace_remap = false
 
-local format, concat = string.format, table.concat
+local format, concat, remove, insert, type, next = string.format, table.concat, table.remove, table.insert, type, next
 
 --~ local pairs, next, type = pairs, next, type
 
--- todo: some things per xml file, liek namespace remapping
+-- todo: some things per xml file, like namespace remapping
 
 --[[ldx--
 <p>First a hack to enable namespace resolving. A namespace is characterized by
@@ -2312,7 +2386,7 @@ do
 
     -- not just one big nested table capture (lpeg overflow)
 
-    local remove, nsremap, resolvens = table.remove, xml.xmlns, xml.resolvens
+    local nsremap, resolvens = xml.xmlns, xml.resolvens
 
     local stack, top, dt, at, xmlns, errorstr, entities = {}, {}, {}, {}, {}, nil, {}
 
@@ -2364,7 +2438,7 @@ do
         end
         dt = top.dt
         dt[#dt+1] = toclose
-        if at.xmlns then
+        if toclose.at.xmlns then
             remove(xmlns)
         end
     end
@@ -2378,10 +2452,10 @@ do
         local t = { ns=namespace or "", rn=resolved, tg=tag, at=at, dt={}, __p__ = top }
         dt[#dt+1] = t
         setmetatable(t, mt)
-        at = { }
         if at.xmlns then
             remove(xmlns)
         end
+        at = { }
     end
     local function add_text(text)
         if cleanup and #text > 0 then
@@ -2638,22 +2712,19 @@ do
         elseif not nocommands then
             local ec = e.command
             if ec ~= nil then -- we can have all kind of types
-
-if e.special then -- todo test for true/false
-    local etg, edt = e.tg, e.dt
-    local spc = specialconverter and specialconverter[etg]
-    if spc then
---~ print("SPECIAL",etg,table.serialize(specialconverter), spc)
-        local result = spc(edt[1])
-        if result then
-            handle(result)
-            return
-        else
-            -- no need to handle any further
-        end
-    end
-end
-
+                if e.special then
+                    local etg, edt = e.tg, e.dt
+                    local spc = specialconverter and specialconverter[etg]
+                    if spc then
+                        local result = spc(edt[1])
+                        if result then
+                            handle(result)
+                            return
+                        else
+                            -- no need to handle any further
+                        end
+                    end
+                end
                 local xc = xml.command
                 if xc then
                     xc(e,ec)
@@ -2704,17 +2775,7 @@ end
                     end
                 end
                 if ern and xml.trace_remap and ern ~= ens then
---~                     if ats then
---~                         ats[#ats+1] = format("xmlns:remapped='%s'",ern)
---~                     else
---~                         ats = { format("xmlns:remapped='%s'",ern) }
---~                     end
---~ if ats then
---~     ats[#ats+1] = format("remappedns='%s'",ens or '-')
---~ else
---~     ats = { format("remappedns='%s'",ens or '-') }
---~ end
-ens = ern
+                    ens = ern
                 end
                 if ens ~= "" then
                     if edt and #edt > 0 then
@@ -2758,7 +2819,16 @@ ens = ern
                             handle("<" .. etg .. ">")
                         end
                         for i=1,#edt do
-                            serialize(edt[i],handle,textconverter,attributeconverter,specialconverter,nocommands)
+                            local ei = edt[i]
+                            if type(ei) == "string" then
+                                if textconverter then
+                                    handle(textconverter(ei))
+                                else
+                                    handle(ei)
+                                end
+                            else
+                                serialize(ei,handle,textconverter,attributeconverter,specialconverter,nocommands)
+                            end
                         end
                     --  handle(format("</%s>",etg))
                         handle("</" .. etg .. ">")
@@ -2781,7 +2851,16 @@ ens = ern
             end
         else
             for i=1,#e do
-                serialize(e[i],handle,textconverter,attributeconverter,specialconverter,nocommands)
+                local ei = e[i]
+                if type(ei) == "string" then
+                    if textconverter then
+                        handle(textconverter(ei))
+                    else
+                        handle(ei)
+                    end
+                else
+                    serialize(ei,handle,textconverter,attributeconverter,specialconverter,nocommands)
+                end
             end
         end
     end
@@ -2798,8 +2877,8 @@ ens = ern
                 end
             end
             if not found then
-                table.insert(dt, 1, { special=true, ns="", tg="@pi@", dt = { "xml version='1.0' standalone='yes'"} } )
-                table.insert(dt, 2, "\n" )
+                insert(dt, 1, { special=true, ns="", tg="@pi@", dt = { "xml version='1.0' standalone='yes'"} } )
+                insert(dt, 2, "\n" )
             end
         end
     end
@@ -2811,14 +2890,14 @@ ens = ern
 
     function xml.tostring(root) -- 25% overhead due to collecting
         if root then
-        if type(root) == 'string' then
-            return root
-        elseif next(root) then -- next is faster than type (and >0 test)
-            local result = { }
-            serialize(root,function(s) result[#result+1] = s end)
-            return concat(result,"")
+            if type(root) == 'string' then
+                return root
+            elseif next(root) then -- next is faster than type (and >0 test)
+                local result = { }
+                serialize(root,function(s) result[#result+1] = s end)
+                return concat(result,"")
+            end
         end
-    end
         return ""
     end
 
@@ -2883,6 +2962,18 @@ function xml.content(root) -- bugged
     return (root and root.dt and xml.tostring(root.dt)) or ""
 end
 
+function xml.isempty(root, pattern)
+    if pattern == "" or pattern == "*" then
+        pattern = nil
+    end
+    if pattern then
+        -- todo
+        return false
+    else
+        return not root or not root.dt or #root.dt == 0 or root.dt == ""
+    end
+end
+
 --[[ldx--
 <p>The next helper erases an element but keeps the table as it is,
 and since empty strings are not serialized (effectively) it does
@@ -2925,11 +3016,16 @@ of <l n='xpath'/> and since we're not co
 will explain more about its usage in other documents.</p>
 --ldx]]--
 
+local lpathcalls  = 0 -- statisctics
+local lpathcached = 0 -- statisctics
+
 do
 
-    xml.functions = xml.functions or { }
+    xml.functions   = xml.functions   or { }
+    xml.expressions = xml.expressions or { }
 
-    local functions = xml.functions
+    local functions   = xml.functions
+    local expressions = xml.expressions
 
     local actions = {
         [10] = "stay",
@@ -2953,34 +3049,32 @@ do
         [40] = "processing instruction",
     }
 
-    --~     local function make_expression(str) --could also be an lpeg
-    --~         str = str:gsub("@([a-zA-Z%-_]+)", "(a['%1'] or '')")
-    --~         str = str:gsub("position%(%)", "i")
-    --~         str = str:gsub("text%(%)", "t")
-    --~         str = str:gsub("!=", "~=")
-    --~         str = str:gsub("([^=!~<>])=([^=!~<>])", "%1==%2")
-    --~         str = str:gsub("([a-zA-Z%-_]+)%(", "functions.%1(")
-    --~         return str, loadstring(format("return function(functions,i,a,t) return %s end", str))()
-    --~     end
-
     -- a rather dumb lpeg
 
     local P, S, R, C, V, Cc = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.Cc
 
-    local lp_position  = P("position()") / "id"
+    -- instead of using functions we just parse a few names which saves a call
+    -- later on
+
+    local lp_position  = P("position()") / "ps"
+    local lp_index     = P("index()")    / "id"
     local lp_text      = P("text()")     / "tx"
-    local lp_name      = P("name()")     / "((rt.ns~='' and rt.ns..':'..rt.tg) or '')"
-    local lp_tag       = P("tag()")      / "(rt.tg or '')"
-    local lp_ns        = P("ns()")       / "(rt.ns or '')"
+    local lp_name      = P("name()")     / "(ns~='' and ns..':'..tg)" -- "((rt.ns~='' and rt.ns..':'..rt.tg) or '')"
+    local lp_tag       = P("tag()")      / "tg" -- (rt.tg or '')
+    local lp_ns        = P("ns()")       / "ns" -- (rt.ns or '')
     local lp_noequal   = P("!=")         / "~=" + P("<=") + P(">=") + P("==")
     local lp_doequal   = P("=")          / "=="
     local lp_attribute = P("@")          / "" * Cc("(at['") * R("az","AZ","--","__")^1 * Cc("'] or '')")
 
-    local lp_function  = C(R("az","AZ","--","__")^1) * P("(") / function(t)
-        if functions[t] then
-            return "functions." .. t .. "("
+    local lp_lua_function  = C(R("az","AZ","--","__")^1 * (P(".") * R("az","AZ","--","__")^1)^1) * P("(") / function(t) -- todo: better . handling
+        return t .. "("
+    end
+
+    local lp_function  = C(R("az","AZ","--","__")^1) * P("(") / function(t) -- todo: better . handling
+        if expressions[t] then
+            return "expressions." .. t .. "("
         else
-            return "functions.error("
+            return "expressions.error("
         end
     end
 
@@ -2988,34 +3082,45 @@ do
     local rparent  = lpeg.P(")")
     local noparent = 1 - (lparent+rparent)
     local nested   = lpeg.P{lparent * (noparent + lpeg.V(1))^0 * rparent}
-    local value    = lpeg.P(lparent * lpeg.C((noparent + nested)^0) * rparent)
+    local value    = lpeg.P(lparent * lpeg.C((noparent + nested)^0) * rparent) -- lpeg.P{"("*C(((1-S("()"))+V(1))^0)*")"}
 
---~ local value = P { "(" * C(((1 - S("()")) + V(1))^0) * ")" }
+    -- if we use a dedicated namespace then we don't need to pass rt and k
 
     local lp_special = (C(P("name")+P("text")+P("tag"))) * value / function(t,s)
-        if functions[t] then
+        if expressions[t] then
             if s then
-                return "functions." .. t .. "(rt,k," .. s ..")"
+                return "expressions." .. t .. "(r,k," .. s ..")"
             else
-                return "functions." .. t .. "(rt,k)"
+                return "expressions." .. t .. "(r,k)"
             end
         else
-            return "functions.error(" .. t .. ")"
+            return "expressions.error(" .. t .. ")"
         end
     end
 
     local converter = lpeg.Cs ( (
         lp_position +
+        lp_index +
         lp_text + lp_name + -- fast one
         lp_special +
         lp_noequal + lp_doequal +
         lp_attribute +
+        lp_lua_function +
         lp_function +
     1 )^1 )
 
+    -- expressions,root,rootdt,k,e,edt,ns,tg,idx,hsh[tg] or 1
+
+    local template = [[
+        return function(expressions,r,d,k,e,dt,ns,tg,id,ps)
+            local at, tx = e.at or { }, dt[1] or ""
+            return %s
+        end
+    ]]
+
     local function make_expression(str)
         str = converter:match(str)
-        return str, loadstring(format("return function(functions,id,at,tx,rt,k) return %s end", str))()
+        return str, loadstring(format(template,str))()
     end
 
     local map = { }
@@ -3125,7 +3230,7 @@ do
 
     local selector = (
         instruction +
-        many + any +
+--~         many + any + -- brrr, not here !
         parent + stay +
         dont_position + position +
         dont_match_one_of_and_eq + dont_match_one_of_and_ne +
@@ -3137,6 +3242,7 @@ do
         has_attribute + has_value +
         dont_match_one_of + match_one_of +
         dont_match + match +
+        many + any +
         crap + empty
     )
 
@@ -3173,7 +3279,7 @@ do
                     return { map[2] }
                 end
                 if m ~= 11 and m ~= 12 and m ~= 13 and m ~= 14 and m ~= 15 and m ~= 16 then
-                    table.insert(map, 1, { 16 })
+                    insert(map, 1, { 16 })
                 end
             --  print((table.serialize(map)):gsub("[ \n]+"," "))
                 return map
@@ -3184,11 +3290,13 @@ do
     local cache = { }
 
     function xml.lpath(pattern,trace)
+        lpathcalls = lpathcalls + 1
         if type(pattern) == "string" then
             local result = cache[pattern]
-            if not result then
+            if result == nil then -- can be false which is valid -)
                 result = compose(pattern)
                 cache[pattern] = result
+                lpathcached = lpathcached + 1
             end
             if trace or xml.trace_lpath then
                 xml.lshow(result)
@@ -3199,6 +3307,10 @@ do
         end
     end
 
+    function lpath_cached_patterns()
+        return cache
+    end
+
     local fallbackreport = (texio and texio.write) or io.write
 
     function xml.lshow(pattern,report)
@@ -3266,22 +3378,25 @@ functions.</p>
 
 do
 
-    local functions = xml.functions
+    local functions   = xml.functions
+    local expressions = xml.expressions
 
-    functions.contains = string.find
-    functions.find     = string.find
-    functions.upper    = string.upper
-    functions.lower    = string.lower
-    functions.number   = tonumber
-    functions.boolean  = toboolean
+    expressions.contains = string.find
+    expressions.find     = string.find
+    expressions.upper    = string.upper
+    expressions.lower    = string.lower
+    expressions.number   = tonumber
+    expressions.boolean  = toboolean
 
-    functions.oneof = function(s,...) -- slow
+    expressions.oneof = function(s,...) -- slow
         local t = {...} for i=1,#t do if s == t[i] then return true end end return false
     end
-    functions.error = function(str)
-        xml.error_handler("unknown function in lpath expression",str)
+
+    expressions.error = function(str)
+        xml.error_handler("unknown function in lpath expression",str or "?")
         return false
     end
+
     functions.text = function(root,k,n) -- unchecked, maybe one deeper
         local t = type(t)
         if t == "string" then
@@ -3291,35 +3406,21 @@ do
             return (rdt and rdt[k]) or root[k] or ""
         end
     end
-    functions.name = function(root,k,n)
-        -- way too fuzzy
-        local found
-        if not k or not n then
-            local ns, tg = root.rn or root.ns or "", root.tg
-            if not tg then
-                for i=1,#root do
-                    local e = root[i]
-                    if type(e) == "table" then
-                        found = e
-                        break
-                    end
-                end
-            elseif ns ~= "" then
-                return ns .. ":" .. tg
-            else
-                return tg
-            end
+
+    functions.name = function(d,k,n) -- ns + tg
+        local found = false
+        n = n or 0
+        if not k then
+            -- not found
         elseif n == 0 then
-            local e = root[k]
-            if type(e) ~= "table" then
-                found = e
-            end
+            local dk = d[k]
+            found = dk and (type(dk) == "table") and dk
         elseif n < 0 then
             for i=k-1,1,-1 do
-                local e = root[i]
-                if type(e) == "table" then
+                local di = d[i]
+                if type(di) == "table" then
                     if n == -1 then
-                        found = e
+                        found = di
                         break
                     else
                         n = n + 1
@@ -3327,12 +3428,11 @@ do
                 end
             end
         else
---~ print(k,n,#root)
-            for i=k+1,#root,1 do
-                local e = root[i]
-                if type(e) == "table" then
+            for i=k+1,#d,1 do
+                local di = d[i]
+                if type(di) == "table" then
                     if n == 1 then
-                        found = e
+                        found = di
                         break
                     else
                         n = n - 1
@@ -3347,11 +3447,51 @@ do
             else
                 return tg
             end
-        else
-            return ""
+        else
+            return ""
+        end
+    end
+
+    functions.tag = function(d,k,n) -- only tg
+        local found = false
+        n = n or 0
+        if not k then
+            -- not found
+        elseif n == 0 then
+            local dk = d[k]
+            found = dk and (type(dk) == "table") and dk
+        elseif n < 0 then
+            for i=k-1,1,-1 do
+                local di = d[i]
+                if type(di) == "table" then
+                    if n == -1 then
+                        found = di
+                        break
+                    else
+                        n = n + 1
+                    end
+                end
+            end
+        else
+            for i=k+1,#d,1 do
+                local di = d[i]
+                if type(di) == "table" then
+                    if n == 1 then
+                        found = di
+                        break
+                    else
+                        n = n - 1
+                    end
+                end
+            end
         end
+        return (found and found.tg) or ""
     end
 
+    expressions.text = functions.text
+    expressions.name = functions.name
+    expressions.tag  = functions.tag
+
     local function traverse(root,pattern,handle,reverse,index,parent,wildcard) -- multiple only for tags, not for namespaces
         if not root then -- error
             return false
@@ -3424,10 +3564,13 @@ do
                         start, stop, step = stop, start, -1
                     end
                     local idx = 0
+                    local hsh = { } -- this will slooow down the lot
                     for k=start,stop,step do -- we used to have functions for all but a case is faster
                         local e = rootdt[k]
                         local ns, tg = e.rn or e.ns, e.tg
                         if tg then
+                         -- we can optimize this for simple searches, but it probably does not pay off
+                            hsh[tg] = (hsh[tg] or 0) + 1
                             idx = idx + 1
                             if command == 30 then
                                 local ns_a, tg_a = action[3], action[4]
@@ -3550,7 +3693,7 @@ do
                                     end
                                     if not action[2] then matched = not matched end
                                     if matched then
-                                        matched = action[6](functions,idx,e.at or { },edt[1],rootdt,k)
+                                        matched = action[6](expressions,root,rootdt,k,e,edt,ns,tg,idx,hsh[tg] or 1)
                                     end
                                 end
                                 if matched then -- combine tg test and at test
@@ -4025,10 +4168,10 @@ do
                         local r, d, k, element = m[1], m[2], m[3], m[4]
                         if not before then k = k + 1 end
                         if element.tg then
-                            table.insert(d,k,element) -- untested
+                            insert(d,k,element) -- untested
                         elseif element.dt then
                             for _,v in ipairs(element.dt) do -- i added
-                                table.insert(d,k,v)
+                                insert(d,k,v)
                                 k = k + 1
                             end
                         end
@@ -4116,15 +4259,27 @@ do
         xml.each_element(xmldata, pattern, include)
     end
 
-    function xml.strip_whitespace(root, pattern)
+    function xml.strip_whitespace(root, pattern, nolines) -- strips all leading and trailing space !
         traverse(root, lpath(pattern), function(r,d,k)
             local dkdt = d[k].dt
             if dkdt then -- can be optimized
                 local t = { }
                 for i=1,#dkdt do
                     local str = dkdt[i]
-                    if type(str) == "string" and str:find("^[ \n\r\t]*$") then
-                        -- stripped
+                    if type(str) == "string" then
+
+                        if str == "" then
+                            -- stripped
+                        else
+                            if nolines then
+                                str = str:gsub("[ \n\r\t]+"," ")
+                            end
+                            if str == "" then
+                                -- stripped
+                            else
+                                t[#t+1] = str
+                            end
+                        end
                     else
                         t[#t+1] = str
                     end
@@ -4326,9 +4481,9 @@ original entity is returned.</p>
 
 do if unicode and unicode.utf8 then
 
-    xml.entities = xml.entities or { } -- xml.entities.handler == function
+    xml.entities = xml.entities or { } -- xml.entity_handler == function
 
-    function xml.entities.handler(e)
+    function xml.entity_handler(e)
         return format("[%s]",e)
     end
 
@@ -4338,8 +4493,6 @@ do if unicode and unicode.utf8 then
         return char(tonumber(s,16))
     end
 
-    local entities = xml.entities -- global entities
-
     function utfize(root)
         local d = root.dt
         for k=1,#d do
@@ -4361,11 +4514,11 @@ do if unicode and unicode.utf8 then
         if e:find("#x") then
             return char(tonumber(e:sub(3),16))
         else
-            local ee = entities[e]
+            local ee = xml.entities[e] -- we cannot shortcut this one (is reloaded)
             if ee then
                 return ee
             else
-                local h = xml.entities.handler
+                local h = xml.entity_handler
                 return (h and h(e)) or "&" .. e .. ";"
             end
         end
@@ -4427,6 +4580,13 @@ do if unicode and unicode.utf8 then
 
 end end
 
+function xml.statistics()
+    return {
+        lpathcalls = lpathcalls,
+        lpathcached = lpathcached,
+    }
+end
+
 --  xml.set_text_cleanup(xml.show_text_entities)
 --  xml.set_text_cleanup(xml.resolve_text_entities)
 
@@ -4505,11 +4665,20 @@ function utils.report(...)
     print(...)
 end
 
+utils.merger.strip_comment = true
+
 function utils.merger._self_load_(name)
     local f, data = io.open(name), ""
     if f then
+        utils.report("reading merge from %s",name)
         data = f:read("*all")
         f:close()
+    else
+        utils.report("unknown file to merge %s",name)
+    end
+    if data and utils.merger.strip_comment then
+        -- saves some 20K
+        data = data:gsub("%-%-~[^\n\r]*[\r\n]", "")
     end
     return data or ""
 end
@@ -4518,6 +4687,7 @@ function utils.merger._self_save_(name, 
     if data ~= "" then
         local f = io.open(name,'w')
         if f then
+            utils.report("saving merge from %s",name)
             f:write(data)
             f:close()
         end
@@ -4543,13 +4713,13 @@ function utils.merger._self_libs_(libs,l
             local name = string.gsub(pth .. "/" .. lib,"\\","/")
             f = io.open(name)
             if f then
-            --  utils.report("merging library",name)
+                utils.report("merging library %s",name)
                 result[#result+1] = f:read("*all")
                 f:close()
                 list = { pth } -- speed up the search
                 break
             else
-            --  utils.report("no library",name)
+                utils.report("no library %s",name)
             end
         end
     end
@@ -4588,108 +4758,62 @@ function utils.merger.selfclean(name)
     )
 end
 
-utils.lua.compile_strip = true
-
-function utils.lua.compile(luafile, lucfile)
+function utils.lua.compile(luafile, lucfile, cleanup, strip) -- defaults: cleanup=false strip=true
  -- utils.report("compiling",luafile,"into",lucfile)
     os.remove(lucfile)
     local command = "-o " .. string.quote(lucfile) .. " " .. string.quote(luafile)
-    if utils.lua.compile_strip then
+    if strip ~= false then
         command = "-s " .. command
     end
-    if os.spawn("texluac " .. command) == 0 then
-        return true
-    elseif os.spawn("luac " .. command) == 0 then
-        return true
-    else
-        return false
+    local done = (os.spawn("texluac " .. command) == 0) or (os.spawn("luac " .. command) == 0)
+    if done and cleanup == true and lfs.isfile(lucfile) and lfs.isfile(luafile) then
+     -- utils.report("removing",luafile)
+        os.remove(luafile)
     end
+    return done
 end
 
 
 
--- filename : luat-lib.lua
--- comment  : companion to luat-lib.tex
--- author   : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license  : see context related readme files
-
-if not versions then versions = { } end versions['luat-lib'] = 1.001
-
--- mostcode moved to the l-*.lua and other luat-*.lua files
+if not modules then modules = { } end modules ['luat-lib'] = {
+    version   = 1.001,
+    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+    copyright = "PRAGMA ADE / ConTeXt Development Team",
+    license   = "see context related readme files",
+    comment   = "companion to luat-lib.tex",
+}
 
--- os / io
+-- most code already moved to the l-*.lua and other luat-*.lua files
 
 os.setlocale(nil,nil) -- useless feature and even dangerous in luatex
 
--- os.platform
-
--- mswin|bccwin|mingw|cygwin  windows
--- darwin|rhapsody|nextstep   macosx
--- netbsd|unix                unix
--- linux                      linux
-
-if not io.fileseparator then
-    if string.find(os.getenv("PATH"),";") then
-        io.fileseparator, io.pathseparator, os.platform = "\\", ";", os.type or "windows"
-    else
-        io.fileseparator, io.pathseparator, os.platform = "/" , ":", os.type or "unix"
-    end
-end
-
-os.platform = os.platform or os.type or (io.pathseparator == ";" and "windows") or "unix"
-
--- arg normalization
---
--- for k,v in pairs(arg) do print(k,v) end
-
--- environment
-
-if not environment then environment = { } end
-
-environment.ownbin = environment.ownbin or arg[-2] or arg[-1] or arg[0] or "luatex"
-
-local ownpath = nil -- we could use a metatable here
-
-function environment.ownpath()
-    if not ownpath then
-        for p in string.gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
-            local b = file.join(p,environment.ownbin)
-            if lfs.isfile(b..".exe") or lfs.isfile(b) then
-                ownpath = p
-                break
-            end
-        end
-        if not ownpath then ownpath = '.' end
-    end
-    return ownpath
+function os.setlocale()
+    -- no way you can mess with it
 end
 
 if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then
     arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil
 end
 
-environment.arguments            = { }
-environment.files                = { }
-environment.sorted_argument_keys = nil
-
-environment.platform = os.platform
+environment             = environment or { }
+environment.arguments   = { }
+environment.files       = { }
+environment.sortedflags = nil
 
 function environment.initialize_arguments(arg)
-    environment.arguments = { }
-    environment.files     = { }
-    environment.sorted_argument_keys = nil
+    local arguments, files = { }, { }
+    environment.arguments, environment.files, environment.sortedflags = arguments, files, nil
     for index, argument in pairs(arg) do
         if index > 0 then
             local flag, value = argument:match("^%-+(.+)=(.-)$")
             if flag then
-                environment.arguments[flag] = string.unquote(value or "")
+                arguments[flag] = string.unquote(value or "")
             else
                 flag = argument:match("^%-+(.+)")
                 if flag then
-                    environment.arguments[flag] = true
+                    arguments[flag] = true
                 else
-                    environment.files[#environment.files+1] = argument
+                    files[#files+1] = argument
                 end
             end
         end
@@ -4710,19 +4834,21 @@ function environment.setargument(name,va
     environment.arguments[name] = value
 end
 
-function environment.argument(name)
-    if environment.arguments[name] then
-        return environment.arguments[name]
-    else
-        if not environment.sorted_argument_keys then
-            environment.sorted_argument_keys = { }
-            for _,v in pairs(table.sortedkeys(environment.arguments)) do
-                table.insert(environment.sorted_argument_keys, "^" .. v)
+function environment.argument(name) -- todo: default (plus typecheck on default)
+    local arguments, sortedflags = environment.arguments, environment.sortedflags
+    if arguments[name] then
+        return arguments[name]
+    else
+        if not sortedflags then
+            sortedflags = { }
+            for _,v in pairs(table.sortedkeys(arguments)) do
+                sortedflags[#sortedflags+1] = "^" .. v
             end
+            environment.sortedflags = sortedflags
         end
-        for _,v in pairs(environment.sorted_argument_keys) do
+        for _,v in ipairs(sortedflags) do
             if name:find(v) then
-                return environment.arguments[v:sub(2,#v)]
+                return arguments[v:sub(2,#v)]
             end
         end
     end
@@ -4743,48 +4869,106 @@ function environment.split_arguments(sep
     return before, after
 end
 
-function environment.reconstruct_commandline(arg)
+--~ function environment.reconstruct_commandline(arg)
+--~     if not arg then arg = environment.original_arguments end
+--~     local result = { }
+--~     for _,a in ipairs(arg) do -- ipairs 1 .. #n
+--~         local kk, vv = a:match("^(%-+.-)=(.+)$")
+--~         if kk and vv then
+--~             if vv:find(" ") then
+--~                 vv = vv:unquote()
+--~                 vv = vv:gsub('"','\\"')
+--~                 result[#result+1] = kk .. "=" .. vv:quote()
+--~             else
+--~                 a = a:unquote()
+--~                 a = a:gsub('"','\\"')
+--~                 result[#result+1] = a
+--~             end
+--~         elseif a:find(" ") then
+--~             a = a:unquote()
+--~             a = a:gsub('"','\\"')
+--~             result[#result+1] = a:quote()
+--~         else
+--~             result[#result+1] = a
+--~         end
+--~     end
+--~     return table.join(result," ")
+--~ end
+
+function environment.reconstruct_commandline(arg,noquote)
     if not arg then arg = environment.original_arguments end
-    local result = { }
-    for _,a in ipairs(arg) do -- ipairs 1 .. #n
-        local kk, vv = a:match("^(%-+.-)=(.+)$")
-        if kk and vv then
-            if vv:find(" ") then
-                result[#result+1] = kk .. "=" .. string.quote(vv)
+    if noquote and #arg == 1 then
+        local a = arg[1]
+        a = input.resolve(a)
+        a = a:unquote()
+        return a
+    elseif #arg == 1 then
+        local result = { }
+        for _,a in ipairs(arg) do -- ipairs 1 .. #n
+            a = input.resolve(a)
+            a = a:unquote()
+            a = a:gsub('"','\\"') -- tricky
+            if a:find(" ") then
+                result[#result+1] = a:quote()
             else
                 result[#result+1] = a
             end
-        elseif a:find(" ") then
-            result[#result+1] = string.quote(a)
-        else
-            result[#result+1] = a
         end
+        return table.join(result," ")
     end
-    return table.join(result," ")
 end
 
 if arg then
-    environment.initialize_arguments(arg)
-    environment.original_arguments = arg
+
+    -- new, reconstruct quoted snippets (maybe better just remnove the " then and add them later)
+    local newarg, instring = { }, false
+
+    for index, argument in ipairs(arg) do
+        if argument:find("^\"") then
+            newarg[#newarg+1] = argument:gsub("^\"","")
+            if not argument:find("\"$") then
+                instring = true
+            end
+        elseif argument:find("\"$") then
+            newarg[#newarg] = newarg[#newarg] .. " " .. argument:gsub("\"$","")
+            instring = false
+        elseif instring then
+            newarg[#newarg] = newarg[#newarg] .. " " .. argument
+        else
+            newarg[#newarg+1] = argument
+        end
+    end
+    for i=1,-5,-1 do
+        newarg[i] = arg[i]
+    end
+
+    environment.initialize_arguments(newarg)
+    environment.original_arguments = newarg
+    environment.raw_arguments = arg
+
     arg = { } -- prevent duplicate handling
-end
 
+end
 
--- filename : luat-inp.lua
--- comment  : companion to luat-lib.tex
--- author   : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license  : see context related readme files
 
--- This lib is multi-purpose and can be loaded again later on so that
--- additional functionality becomes available. We will split this
--- module in components when we're done with prototyping.
+if not modules then modules = { } end modules ['luat-inp'] = {
+    version   = 1.001,
+    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+    copyright = "PRAGMA ADE / ConTeXt Development Team",
+    license   = "see context related readme files",
+    comment   = "companion to luat-lib.tex",
+}
 
 -- TODO: os.getenv -> os.env[]
 -- TODO: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller)
 -- TODO: check escaping in find etc, too much, too slow
 
--- This is the first code I wrote for LuaTeX, so it needs some cleanup.
+-- This lib is multi-purpose and can be loaded again later on so that
+-- additional functionality becomes available. We will split this
+-- module in components once we're done with prototyping. This is the
+-- first code I wrote for LuaTeX, so it needs some cleanup. Before changing
+-- something in this module one can best check with Taco or Hans first; there
+-- is some nasty trickery going on that relates to traditional kpse support.
 
 -- To be considered: hash key lowercase, first entry in table filename
 -- (any case), rest paths (so no need for optimization). Or maybe a
@@ -4794,12 +4978,6 @@ end
 
 -- Beware, loading and saving is overloaded in luat-tmp!
 
-if not versions    then versions    = { } end versions['luat-inp'] = 1.001
-if not environment then environment = { } end
-if not file        then file        = { } end
-
-if environment.aleph_mode == nil then environment.aleph_mode = true end -- temp hack
-
 if not input            then input            = { } end
 if not input.suffixes   then input.suffixes   = { } end
 if not input.formats    then input.formats    = { } end
@@ -4812,7 +4990,7 @@ if not input.hashers    then input.hashe
 if not input.generators then input.generators = { } end  -- generate databases
 if not input.filters    then input.filters    = { } end  -- conversion filters
 
-local format = string.format
+local format, concat, sortedkeys = string.format, table.concat, table.sortedkeys
 
 input.locators.notfound   = { nil }
 input.hashers.notfound    = { nil }
@@ -4825,8 +5003,16 @@ input.debug        = false
 input.cnfname      = 'texmf.cnf'
 input.luaname      = 'texmfcnf.lua'
 input.lsrname      = 'ls-R'
-input.luasuffix    = '.tma'
-input.lucsuffix    = '.tmc'
+input.homedir      = os.env[os.platform == "windows" and 'USERPROFILE'] or os.env['HOME'] or '~'
+
+--~ input.luasuffix    = 'tma'
+--~ input.lucsuffix    = 'tmc'
+
+-- for the moment we have .local but this will disappear
+input.cnfdefault   = '{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
+
+-- chances are low that the cnf file is in the bin path
+input.cnfdefault   = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
 
 -- we use a cleaned up list / format=any is a wildcard, as is *name
 
@@ -4862,7 +5048,8 @@ input.suffixes['lua'] = { 'lua', 'luc', 
 -- FONTFEATURES  = .;$TEXMF/fonts/fea//
 -- FONTCIDMAPS   = .;$TEXMF/fonts/cid//
 
-function input.checkconfigdata(instance) -- not yet ok, no time for debugging now
+function input.checkconfigdata() -- not yet ok, no time for debugging now
+    local instance = input.instance
     local function fix(varname,default)
         local proname = varname .. "." .. instance.progname or "crap"
         local p = instance.environment[proname]
@@ -4871,7 +5058,15 @@ function input.checkconfigdata(instance)
             instance.variables[varname] = default -- or environment?
         end
     end
-    fix("LUAINPUTS"   , ".;$TEXINPUTS;$TEXMFSCRIPTS")
+    local name = os.name
+    if name == "windows" then
+        fix("OSFONTDIR", "c:/windows/fonts//")
+    elseif name == "macosx" then
+        fix("OSFONTDIR", "$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//")
+    else
+        -- bad luck
+    end
+    fix("LUAINPUTS"   , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm
     fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
     fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
 end
@@ -4898,14 +5093,20 @@ input.formats     ['sfd']               
 input.suffixes    ['sfd']                      = { 'sfd' }
 input.alternatives['subfont definition files'] = 'sfd'
 
-function input.reset()
+-- In practice we will work within one tds tree, but i want to keep
+-- the option open to build tools that look at multiple trees, which is
+-- why we keep the tree specific data in a table. We used to pass the
+-- instance but for practical pusposes we now avoid this and use a
+-- instance variable.
+
+function input.newinstance()
 
     local instance = { }
 
     instance.rootpath        = ''
     instance.treepath        = ''
-    instance.progname        = environment.progname or 'context'
-    instance.engine          = environment.engine   or 'luatex'
+    instance.progname        = 'context'
+    instance.engine          = 'luatex'
     instance.format          = ''
     instance.environment     = { }
     instance.variables       = { }
@@ -4929,12 +5130,12 @@ function input.reset()
     instance.cachepath       = nil
     instance.loaderror       = false
     instance.smallcache      = false
+    instance.sortdata        = false
     instance.savelists       = true
     instance.cleanuppaths    = true
     instance.allresults      = false
     instance.pattern         = nil    -- lists
     instance.kpseonly        = false  -- lists
-    instance.cachefile       = 'tmftools'
     instance.loadtime        = 0
     instance.starttime       = 0
     instance.stoptime        = 0
@@ -4945,23 +5146,13 @@ function input.reset()
     instance.fakepaths       = { }
     instance.lsrmode         = false
 
-    if os.env then
-        -- store once, freeze and faster
-        for k,v in pairs(os.env) do
-            instance.environment[k] = input.bare_variable(v)
-        end
-    else
-        -- we will access os.env frequently
-        for k,v in pairs({'HOME','TEXMF','TEXMFCNF'}) do
-            local e = os.getenv(v)
-            if e then
-            --  input.report("setting",v,"to",input.bare_variable(e))
-                instance.environment[v] = input.bare_variable(e)
-            end
-        end
+    -- store once, freeze and faster (once reset we can best use instance.environment)
+
+    for k,v in pairs(os.env) do
+        instance.environment[k] = input.bare_variable(v)
     end
 
-    -- cross referencing
+    -- cross referencing, delayed because we can add suffixes
 
     for k, v in pairs(input.suffixes) do
         for _, vv in pairs(v) do
@@ -4975,68 +5166,42 @@ function input.reset()
 
 end
 
-function input.reset_hashes(instance)
-    instance.lists = { }
-    instance.found = { }
-end
-
-function input.bare_variable(str) -- assumes str is a string
- -- return string.gsub(string.gsub(string.gsub(str,"%s+$",""),'^"(.+)"$',"%1"),"^'(.+)'$","%1")
-    return (str:gsub("\s*([\"\']?)(.+)%1\s*", "%2"))
-end
+input.instance = input.instance or nil
 
-if texio then
-    input.log = texio.write_nl
-else
-    input.log = print
+function input.reset()
+    input.instance = input.newinstance()
+    return input.instance
 end
 
-function input.simple_logger(kind, name)
-    if name and name ~= "" then
-        if input.banner then
-            input.log(input.banner..kind..": "..name)
-        else
-            input.log("<<"..kind..": "..name..">>")
-        end
-    else
-        if input.banner then
-            input.log(input.banner..kind..": no name")
-        else
-            input.log("<<"..kind..": no name>>")
-        end
-    end
+function input.reset_hashes()
+    input.instance.lists = { }
+    input.instance.found = { }
 end
 
-function input.dummy_logger()
+function input.bare_variable(str) -- assumes str is a string
+ -- return string.gsub(string.gsub(string.gsub(str,"%s+$",""),'^"(.+)"$',"%1"),"^'(.+)'$","%1")
+    return (str:gsub("\s*([\"\']?)(.+)%1\s*", "%2"))
 end
 
 function input.settrace(n)
     input.trace = tonumber(n or 0)
     if input.trace > 0 then
-        input.logger = input.simple_logger
         input.verbose = true
-    else
-        input.logger = function() end
     end
 end
 
-function input.report(...) -- inefficient
+input.log  = (texio and texio.write_nl) or print
+
+function input.report(...)
     if input.verbose then
-        if input.banner then
-            input.log(input.banner .. table.concat({...},' '))
-        elseif input.logmode() == 'xml' then
-            input.log("<t>"..table.concat({...},' ').."</t>")
-        else
-            input.log("<<"..table.concat({...},' ')..">>")
-        end
+        input.log("<<"..format(...)..">>")
     end
 end
 
-function input.reportlines(str)
-    if type(str) == "string" then
-        str = str:split("\n")
+function input.report(...)
+    if input.trace > 0 then -- extra test
+        input.log("<<"..format(...)..">>")
     end
-    for _,v in pairs(str) do input.report(v) end
 end
 
 input.settrace(tonumber(os.getenv("MTX.INPUT.TRACE") or os.getenv("MTX_INPUT_TRACE") or input.trace or 0))
@@ -5065,7 +5230,7 @@ do
                 instance.stoptime = stoptime
                 instance.loadtime = instance.loadtime + loadtime
                 if report then
-                    input.report('load time', format("%0.3f",loadtime))
+                    input.report("load time %0.3f",loadtime)
                 end
                 return loadtime
             end
@@ -5081,18 +5246,18 @@ end
 
 function input.report_loadtime(instance)
     if instance then
-        input.report('total load time', input.elapsedtime(instance))
+        input.report('total load time %s', input.elapsedtime(instance))
     end
 end
 
 input.loadtime = input.elapsedtime
 
-function input.env(instance,key)
-    return instance.environment[key] or input.osenv(instance,key)
+function input.env(key)
+    return input.instance.environment[key] or input.osenv(key)
 end
 
-function input.osenv(instance,key)
-    local ie = instance.environment
+function input.osenv(key)
+    local ie = input.instance.environment
     local value = ie[key]
     if value == nil then
      -- local e = os.getenv(key)
@@ -5110,81 +5275,106 @@ end
 -- we follow a rather traditional approach:
 --
 -- (1) texmf.cnf given in TEXMFCNF
--- (2) texmf.cnf searched in TEXMF/web2c
+-- (2) texmf.cnf searched in default variable
 --
--- for the moment we don't expect a configuration file in a zip
+-- also we now follow the stupid route: if not set then just assume *one*
+-- cnf file under texmf (i.e. distribution)
 
-function input.identify_cnf(instance)
-    -- we no longer support treepath and rootpath (was handy for testing);
-    -- also we now follow the stupid route: if not set then just assume *one*
-    -- cnf file under texmf (i.e. distribution)
-    if #instance.cnffiles == 0 then
-        if input.env(instance,'TEXMFCNF') == "" then
-            local ownpath = environment.ownpath() or "."
-            if ownpath then
-                -- beware, this is tricky on my own system because at that location I do have
-                -- the raw tree that ends up in the zip; i.e. I cannot test this kind of mess
-                local function locate(filename,list)
-                    local ownroot = input.normalize_name(file.join(ownpath,"../.."))
-                    if not lfs.isdir(file.join(ownroot,"texmf")) then
-                        ownroot = input.normalize_name(file.join(ownpath,".."))
-                        if not lfs.isdir(file.join(ownroot,"texmf")) then
-                            input.verbose = true
-                            input.report("error", "unable to identify cnf file")
-                            return
+input.ownpath     = input.ownpath or nil
+input.ownbin      = input.ownbin  or arg[-2] or arg[-1] or arg[0] or "luatex"
+input.autoselfdir = true -- false may be handy for debugging
+
+function input.getownpath()
+    if not input.ownpath then
+        if input.autoselfdir and os.selfdir then
+            input.ownpath = os.selfdir
+        else
+            local binary = input.ownbin
+            if os.platform == "windows" then
+                binary = file.replacesuffix(binary,"exe")
+            end
+            for p in string.gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
+                local b = file.join(p,binary)
+                if lfs.isfile(b) then
+                    -- we assume that after changing to the path the currentdir function
+                    -- resolves to the real location and use this side effect here; this
+                    -- trick is needed because on the mac installations use symlinks in the
+                    -- path instead of real locations
+                    local olddir = lfs.currentdir()
+                    if lfs.chdir(p) then
+                        local pp = lfs.currentdir()
+                        if input.verbose and p ~= pp then
+                            input.report("following symlink %s to %s",p,pp)
                         end
-                    end
-                    local texmfcnf = file.join(ownroot,"texmf-local/web2c",filename) -- for minimals and myself
-                    if not lfs.isfile(texmfcnf) then
-                        texmfcnf = file.join(ownroot,"texmf/web2c",filename)
-                        if not lfs.isfile(texmfcnf) then
-                            input.verbose = true
-                            input.report("error", "unable to locate",filename)
-                            return
+                        input.ownpath = pp
+                        lfs.chdir(olddir)
+                    else
+                        if input.verbose then
+                            input.report("unable to check path %s",p)
                         end
+                        input.ownpath =  p
                     end
-                    table.insert(list,texmfcnf)
-                    local ie = instance.environment
-                    if not ie['SELFAUTOPARENT'] then ie['SELFAUTOPARENT'] = ownroot end
-                    if not ie['TEXMFCNF']       then ie['TEXMFCNF']       = file.dirname(texmfcnf) end
-                end
-                locate(input.luaname,instance.luafiles)
-                locate(input.cnfname,instance.cnffiles)
-                if #instance.luafiles == 0 and instance.cnffiles == 0 then
-                    input.verbose = true
-                    input.report("error", "unable to locate",filename)
-                    os.exit()
+                    break
                 end
-                -- here we also assume then TEXMF is set in the distribution, if this trickery is
-                -- used in the minimals, then users who don't use setuptex are on their own with
-                -- regards to extra trees
-            else
-                input.verbose = true
-                input.report("error", "unable to identify own path")
-                os.exit()
             end
-        else
-            local t = input.split_path(input.env(instance,'TEXMFCNF'))
-            t = input.aux.expanded_path(instance,t)
-            input.aux.expand_vars(instance,t)
-            local function locate(filename,list)
-                for _,v in ipairs(t) do
-                    local texmfcnf = input.normalize_name(file.join(v,filename))
-                    if lfs.isfile(texmfcnf) then
-                        table.insert(list,texmfcnf)
-                    end
+        end
+        if not input.ownpath then input.ownpath = '.' end
+    end
+    return input.ownpath
+end
+
+function input.identify_own()
+    local instance = input.instance
+    local ownpath = input.getownpath() or lfs.currentdir()
+    local ie = instance.environment
+    if ownpath then
+        if input.env('SELFAUTOLOC')    == "" then os.env['SELFAUTOLOC']    = file.collapse_path(ownpath) end
+        if input.env('SELFAUTODIR')    == "" then os.env['SELFAUTODIR']    = file.collapse_path(ownpath .. "/..") end
+        if input.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end
+    else
+        input.verbose = true
+        input.report("error: unable to locate ownpath")
+        os.exit()
+    end
+    if input.env('TEXMFCNF') == "" then os.env['TEXMFCNF'] = input.cnfdefault end
+    if input.env('TEXOS')    == "" then os.env['TEXOS']    = input.env('SELFAUTODIR') end
+    if input.env('TEXROOT')  == "" then os.env['TEXROOT']  = input.env('SELFAUTOPARENT') end
+    if input.verbose then
+        for _,v in ipairs({"SELFAUTOLOC","SELFAUTODIR","SELFAUTOPARENT","TEXMFCNF"}) do
+            input.report("variable %s set to %s",v,input.env(v) or "unknown")
+        end
+    end
+    function input.identify_own() end
+end
+
+function input.identify_cnf()
+    local instance = input.instance
+    if #instance.cnffiles == 0 then
+        -- fallback
+        input.identify_own()
+        -- the real search
+        input.expand_variables()
+        local t = input.split_path(input.env('TEXMFCNF'))
+        t = input.aux.expanded_path(t)
+        input.aux.expand_vars(t) -- redundant
+        local function locate(filename,list)
+            for _,v in ipairs(t) do
+                local texmfcnf = input.normalize_name(file.join(v,filename))
+                if lfs.isfile(texmfcnf) then
+                    table.insert(list,texmfcnf)
                 end
             end
-            locate(input.luaname,instance.luafiles)
-            locate(input.cnfname,instance.cnffiles)
         end
+        locate(input.luaname,instance.luafiles)
+        locate(input.cnfname,instance.cnffiles)
     end
 end
 
-function input.load_cnf(instance)
+function input.load_cnf()
+    local instance = input.instance
     local function loadoldconfigdata()
         for _, fname in ipairs(instance.cnffiles) do
-            input.aux.load_cnf(instance,fname)
+            input.aux.load_cnf(fname)
         end
     end
     -- instance.cnffiles contain complete names now !
@@ -5199,27 +5389,27 @@ function input.load_cnf(instance)
             instance.rootpath = file.dirname(instance.rootpath)
         end
         instance.rootpath = input.normalize_name(instance.rootpath)
-        instance.environment['SELFAUTOPARENT'] = instance.rootpath -- just to be sure
         if instance.lsrmode then
             loadoldconfigdata()
         elseif instance.diskcache and not instance.renewcache then
-            input.loadoldconfig(instance,instance.cnffiles)
+            input.loadoldconfig(instance.cnffiles)
             if instance.loaderror then
                 loadoldconfigdata()
-                input.saveoldconfig(instance)
+                input.saveoldconfig()
             end
         else
             loadoldconfigdata()
             if instance.renewcache then
-                input.saveoldconfig(instance)
+                input.saveoldconfig()
             end
         end
-        input.aux.collapse_cnf_data(instance)
+        input.aux.collapse_cnf_data()
     end
-    input.checkconfigdata(instance)
+    input.checkconfigdata()
 end
 
-function input.load_lua(instance)
+function input.load_lua()
+    local instance = input.instance
     if #instance.luafiles == 0 then
         -- yet harmless
     else
@@ -5231,14 +5421,14 @@ function input.load_lua(instance)
             instance.rootpath = file.dirname(instance.rootpath)
         end
         instance.rootpath = input.normalize_name(instance.rootpath)
-        instance.environment['SELFAUTOPARENT'] = instance.rootpath -- just to be sure
-        input.loadnewconfig(instance)
-        input.aux.collapse_cnf_data(instance)
+        input.loadnewconfig()
+        input.aux.collapse_cnf_data()
     end
-    input.checkconfigdata(instance)
+    input.checkconfigdata()
 end
 
-function input.aux.collapse_cnf_data(instance) -- potential optmization: pass start index (setup and configuration are shared)
+function input.aux.collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared)
+    local instance = input.instance
     for _,c in ipairs(instance.order) do
         for k,v in pairs(c) do
             if not instance.variables[k] then
@@ -5253,21 +5443,22 @@ function input.aux.collapse_cnf_data(ins
     end
 end
 
-function input.aux.load_cnf(instance,fname)
+function input.aux.load_cnf(fname)
+    local instance = input.instance
     fname = input.clean_path(fname)
-    local lname = fname:gsub("%.%a+$",input.luasuffix)
+    local lname = file.replacesuffix(fname,'lua')
     local f = io.open(lname)
     if f then -- this will go
         f:close()
         local dname = file.dirname(fname)
         if not instance.configuration[dname] then
-            input.aux.load_configuration(instance,dname,lname)
+            input.aux.load_configuration(dname,lname)
             instance.order[#instance.order+1] = instance.configuration[dname]
         end
     else
         f = io.open(fname)
         if f then
-            input.report("loading", fname)
+            input.report("loading %s", fname)
             local line, data, n, k, v
             local dname = file.dirname(fname)
             if not instance.configuration[dname] then
@@ -5299,227 +5490,226 @@ function input.aux.load_cnf(instance,fna
             end
             f:close()
         else
-            input.report("skipping", fname)
+            input.report("skipping %s", fname)
         end
     end
 end
 
 -- database loading
 
-function input.load_hash(instance)
-    input.locatelists(instance)
+function input.load_hash()
+    local instance = input.instance
+    input.locatelists()
     if instance.lsrmode then
-        input.loadlists(instance)
+        input.loadlists()
     elseif instance.diskcache and not instance.renewcache then
-        input.loadfiles(instance)
+        input.loadfiles()
         if instance.loaderror then
-            input.loadlists(instance)
-            input.savefiles(instance)
+            input.loadlists()
+            input.savefiles()
         end
     else
-        input.loadlists(instance)
+        input.loadlists()
         if instance.renewcache then
-            input.savefiles(instance)
+            input.savefiles()
         end
     end
 end
 
-function input.aux.append_hash(instance,type,tag,name)
-    input.logger("= hash append",tag)
-    table.insert(instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } )
+function input.aux.append_hash(type,tag,name)
+    if input.trace > 0 then
+        input.logger("= hash append: %s",tag)
+    end
+    table.insert(input.instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } )
 end
 
-function input.aux.prepend_hash(instance,type,tag,name)
-    input.logger("= hash prepend",tag)
-    table.insert(instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } )
+function input.aux.prepend_hash(type,tag,name)
+    if input.trace > 0 then
+        input.logger("= hash prepend: %s",tag)
+    end
+    table.insert(input.instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } )
 end
 
-function input.aux.extend_texmf_var(instance,specification) -- crap
-    if instance.environment['TEXMF'] then
-        input.report("extending environment variable TEXMF with", specification)
-        instance.environment['TEXMF'] = instance.environment['TEXMF']:gsub("^%{", function()
-            return "{" .. specification .. ","
-        end)
-    elseif instance.variables['TEXMF'] then
-        input.report("extending configuration variable TEXMF with", specification)
-        instance.variables['TEXMF'] = instance.variables['TEXMF']:gsub("^%{", function()
-            return "{" .. specification .. ","
-        end)
+function input.aux.extend_texmf_var(specification) -- crap, we could better prepend the hash
+    local instance = input.instance
+--  local t = input.expanded_path_list('TEXMF') -- full expansion
+    local t = input.split_path(input.env('TEXMF'))
+    table.insert(t,1,specification)
+    local newspec = table.join(t,";")
+    if instance.environment["TEXMF"] then
+        instance.environment["TEXMF"] = newspec
+    elseif instance.variables["TEXMF"] then
+        instance.variables["TEXMF"] = newspec
     else
-        input.report("setting configuration variable TEXMF to", specification)
-        instance.variables['TEXMF'] = "{" .. specification .. "}"
+        -- weird
     end
-    if instance.variables['TEXMF']:find("%,") and not instance.variables['TEXMF']:find("^%{") then
-        input.report("adding {} to complex TEXMF variable, best do that yourself")
-        instance.variables['TEXMF'] = "{" .. instance.variables['TEXMF'] .. "}"
-    end
-    input.expand_variables(instance)
-    input.reset_hashes(instance)
+    input.expand_variables()
+    input.reset_hashes()
 end
 
 -- locators
 
-function input.locatelists(instance)
-    for _, path in pairs(input.simplified_list(input.expansion(instance,'TEXMF'))) do
-        path = file.collapse_path(path)
-        input.report("locating list of",path)
-        input.locatedatabase(instance,input.normalize_name(path))
+function input.locatelists()
+    local instance = input.instance
+    for _, path in pairs(input.clean_path_list('TEXMF')) do
+        input.report("locating list of %s",path)
+        input.locatedatabase(input.normalize_name(path))
     end
 end
 
-function input.locatedatabase(instance,specification)
-    return input.methodhandler('locators', instance, specification)
+function input.locatedatabase(specification)
+    return input.methodhandler('locators', specification)
 end
 
-function input.locators.tex(instance,specification)
+function input.locators.tex(specification)
     if specification and specification ~= '' and lfs.isdir(specification) then
-        input.logger('! tex locator', specification..' found')
-        input.aux.append_hash(instance,'file',specification,filename)
-    else
-        input.logger('? tex locator', specification..' not found')
+        if input.trace > 0 then
+            input.logger('! tex locator found: %s',specification)
+        end
+        input.aux.append_hash('file',specification,filename)
+    elseif input.trace > 0 then
+        input.logger('? tex locator not found: %s',specification)
     end
 end
 
 -- hashers
 
-function input.hashdatabase(instance,tag,name)
-    return input.methodhandler('hashers',instance,tag,name)
+function input.hashdatabase(tag,name)
+    return input.methodhandler('hashers',tag,name)
 end
 
-function input.loadfiles(instance)
+function input.loadfiles()
+    local instance = input.instance
     instance.loaderror = false
     instance.files = { }
     if not instance.renewcache then
         for _, hash in ipairs(instance.hashes) do
-            input.hashdatabase(instance,hash.tag,hash.name)
+            input.hashdatabase(hash.tag,hash.name)
             if instance.loaderror then break end
         end
     end
 end
 
-function input.hashers.tex(instance,tag,name)
-    input.aux.load_files(instance,tag)
+function input.hashers.tex(tag,name)
+    input.aux.load_files(tag)
 end
 
 -- generators:
 
-function input.loadlists(instance)
-    for _, hash in ipairs(instance.hashes) do
-        input.generatedatabase(instance,hash.tag)
+function input.loadlists()
+    for _, hash in ipairs(input.instance.hashes) do
+        input.generatedatabase(hash.tag)
     end
 end
 
-function input.generatedatabase(instance,specification)
-    return input.methodhandler('generators', instance, specification)
-end
-
-do
-
-    local weird = lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
-
-    function input.generators.tex(instance,specification)
-        local tag = specification
-        if not instance.lsrmode and lfs and lfs.dir then
-            input.report("scanning path",specification)
-            instance.files[tag] = { }
-            local files = instance.files[tag]
-            local n, m, r = 0, 0, 0
-            local spec = specification .. '/'
-            local attributes = lfs.attributes
-            local directory = lfs.dir
-            local small = instance.smallcache
-            local function action(path)
-                local mode, full
-                if path then
-                    full = spec .. path .. '/'
+function input.generatedatabase(specification)
+    return input.methodhandler('generators', specification)
+end
+
+local weird = lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
+
+function input.generators.tex(specification)
+    local instance = input.instance
+    local tag = specification
+    if not instance.lsrmode and lfs.dir then
+        input.report("scanning path %s",specification)
+        instance.files[tag] = { }
+        local files = instance.files[tag]
+        local n, m, r = 0, 0, 0
+        local spec = specification .. '/'
+        local attributes = lfs.attributes
+        local directory = lfs.dir
+        local small = instance.smallcache
+        local function action(path)
+            local mode, full
+            if path then
+                full = spec .. path .. '/'
+            else
+                full = spec
+            end
+            for name in directory(full) do
+                if name:find("^%.") then
+                  -- skip
+            --  elseif name:find("[%~%`%!%#%$%%%^%&%*%(%)%=%{%}%[%]%:%;\"\'%|%<%>%,%?\n\r\t]") then -- too much escaped
+                elseif weird:match(name) then
+                  -- texio.write_nl("skipping " .. name)
+                  -- skip
                 else
-                    full = spec
-                end
-                for name in directory(full) do
-                    if name:find("^%.") then
-                      -- skip
-                --  elseif name:find("[%~%`%!%#%$%%%^%&%*%(%)%=%{%}%[%]%:%;\"\'%|%<%>%,%?\n\r\t]") then -- too much escaped
-                    elseif weird:match(name) then
-                      -- texio.write_nl("skipping " .. name)
-                      -- skip
-                    else
-                        mode = attributes(full..name,'mode')
-                        if mode == "directory" then
-                            m = m + 1
-                            if path then
-                                action(path..'/'..name)
-                            else
-                                action(name)
-                            end
-                        elseif path and mode == 'file' then
-                            n = n + 1
-                            local f = files[name]
-                            if f then
-                                if not small then
-                                    if type(f) == 'string' then
-                                        files[name] = { f, path }
-                                    else
-                                      f[#f+1] = path
-                                    end
-                                end
-                            else
-                                files[name] = path
-                                local lower = name:lower()
-                                if name ~= lower then
-                                    files["remap:"..lower] = name
-                                    r = r + 1
-                                end
-                            end
+                    mode = attributes(full..name,'mode')
+                    if mode == 'directory' then
+                        m = m + 1
+                        if path then
+                            action(path..'/'..name)
+                        else
+                            action(name)
                         end
-                    end
-                end
-            end
-            action()
-            input.report(format("%s files found on %s directories with %s uppercase remappings",n,m,r))
-        else
-            local fullname = file.join(specification,input.lsrname)
-            local path     = '.'
-            local f        = io.open(fullname)
-            if f then
-                instance.files[tag] = { }
-                local files = instance.files[tag]
-                local small = instance.smallcache
-                input.report("loading lsr file",fullname)
-            --  for line in f:lines() do -- much slower then the next one
-                for line in (f:read("*a")):gmatch("(.-)\n") do
-                    if line:find("^[%a%d]") then
-                        local fl = files[line]
-                        if fl then
+                    elseif path and mode == 'file' then
+                        n = n + 1
+                        local f = files[name]
+                        if f then
                             if not small then
-                                if type(fl) == 'string' then
-                                    files[line] = { fl, path } -- table
+                                if type(f) == 'string' then
+                                    files[name] = { f, path }
                                 else
-                                    fl[#fl+1] = path
+                                  f[#f+1] = path
                                 end
                             end
                         else
-                            files[line] = path -- string
-                            local lower = line:lower()
-                            if line ~= lower then
-                                files["remap:"..lower] = line
+                            files[name] = path
+                            local lower = name:lower()
+                            if name ~= lower then
+                                files["remap:"..lower] = name
+                                r = r + 1
+                            end
+                        end
+                    end
+                end
+            end
+        end
+        action()
+        input.report("%s files found on %s directories with %s uppercase remappings",n,m,r)
+    else
+        local fullname = file.join(specification,input.lsrname)
+        local path     = '.'
+        local f        = io.open(fullname)
+        if f then
+            instance.files[tag] = { }
+            local files = instance.files[tag]
+            local small = instance.smallcache
+            input.report("loading lsr file %s",fullname)
+        --  for line in f:lines() do -- much slower then the next one
+            for line in (f:read("*a")):gmatch("(.-)\n") do
+                if line:find("^[%a%d]") then
+                    local fl = files[line]
+                    if fl then
+                        if not small then
+                            if type(fl) == 'string' then
+                                files[line] = { fl, path } -- table
+                            else
+                                fl[#fl+1] = path
                             end
                         end
                     else
-                        path = line:match("%.%/(.-)%:$") or path -- match could be nil due to empty line
+                        files[line] = path -- string
+                        local lower = line:lower()
+                        if line ~= lower then
+                            files["remap:"..lower] = line
+                        end
                     end
+                else
+                    path = line:match("%.%/(.-)%:$") or path -- match could be nil due to empty line
                 end
-                f:close()
             end
+            f:close()
         end
     end
-
 end
 
 -- savers, todo
 
-function input.savefiles(instance)
-    input.aux.save_data(instance, 'files', function(k,v)
-        return instance.validfile(k,v) -- path, name
+function input.savefiles()
+    input.aux.save_data('files', function(k,v)
+        return input.instance.validfile(k,v) -- path, name
     end)
 end
 
@@ -5527,8 +5717,8 @@ end
 -- we join them and split them after the expansion has taken place. This
 -- is more convenient.
 
-function input.splitconfig(instance)
-    for i,c in ipairs(instance) do
+function input.splitconfig()
+    for i,c in ipairs(input.instance) do
         for k,v in pairs(c) do
             if type(v) == 'string' then
                 local t = file.split_path(v)
@@ -5539,8 +5729,9 @@ function input.splitconfig(instance)
         end
     end
 end
-function input.joinconfig(instance)
-    for i,c in ipairs(instance.order) do
+
+function input.joinconfig()
+    for i,c in ipairs(input.instance.order) do
         for k,v in pairs(c) do
             if type(v) == 'table' then
                 c[k] = file.join_path(v)
@@ -5563,8 +5754,9 @@ function input.join_path(str)
     end
 end
 
-function input.splitexpansions(instance)
-    for k,v in pairs(instance.expansions) do
+function input.splitexpansions()
+    local ie = input.instance.expansions
+    for k,v in pairs(ie) do
         local t, h = { }, { }
         for _,vv in pairs(file.split_path(v)) do
             if vv ~= "" and not h[vv] then
@@ -5573,19 +5765,19 @@ function input.splitexpansions(instance)
             end
         end
         if #t > 1 then
-            instance.expansions[k] = t
+            ie[k] = t
         else
-            instance.expansions[k] = t[1]
+            ie[k] = t[1]
         end
     end
 end
 
 -- end of split/join code
 
-function input.saveoldconfig(instance)
-    input.splitconfig(instance)
-    input.aux.save_data(instance, 'configuration', nil)
-    input.joinconfig(instance)
+function input.saveoldconfig()
+    input.splitconfig()
+    input.aux.save_data('configuration', nil)
+    input.joinconfig()
 end
 
 input.configbanner = [[
@@ -5602,8 +5794,6 @@ function input.serialize(files)
     -- luatools and mtxtools are called frequently. Okay,
     -- we pay a small price for properly tabbed tables.
     local t = { }
-    local concat = table.concat
-    local sorted = table.sortedkeys
     local function dump(k,v,m)
         if type(v) == 'string' then
             return m .. "['" .. k .. "']='" .. v .. "',"
@@ -5614,12 +5804,12 @@ function input.serialize(files)
         end
     end
     t[#t+1] = "return {"
-    if instance.sortdata then
-        for _, k in pairs(sorted(files)) do
+    if input.instance.sortdata then
+        for _, k in pairs(sortedkeys(files)) do
             local fk  = files[k]
             if type(fk) == 'table' then
                 t[#t+1] = "\t['" .. k .. "']={"
-                for _, kk in pairs(sorted(fk)) do
+                for _, kk in pairs(sortedkeys(fk)) do
                     t[#t+1] = dump(kk,fk[kk],"\t\t")
                 end
                 t[#t+1] = "\t},"
@@ -5646,11 +5836,11 @@ end
 
 if not texmf then texmf = {} end -- no longer needed, at least not here
 
-function input.aux.save_data(instance, dataname, check, makename) -- untested without cache overload
-    for cachename, files in pairs(instance[dataname]) do
+function input.aux.save_data(dataname, check, makename) -- untested without cache overload
+    for cachename, files in pairs(input.instance[dataname]) do
         local name = (makename or file.join)(cachename,dataname)
-        local luaname, lucname = name .. input.luasuffix, name .. input.lucsuffix
-        input.report("preparing " .. dataname .. " for", luaname)
+        local luaname, lucname = name .. ".lua", name .. ".luc"
+        input.report("preparing %s for %s",dataname,cachename)
         for k, v in pairs(files) do
             if not check or check(v,k) then -- path, name
                 if type(v) == "table" and #v == 1 then
@@ -5668,38 +5858,38 @@ function input.aux.save_data(instance, d
             time    = os.date("%H:%M:%S"),
             content = files,
         }
-        local f = io.open(luaname,'w')
-        if f then
-            input.report("saving " .. dataname .. " in", luaname)
-            f:write(input.serialize(data))
-            f:close()
-            input.report("compiling " .. dataname .. " to", lucname)
-            if not utils.lua.compile(luaname,lucname) then
-                input.report("compiling failed for " .. dataname .. ", deleting file " .. lucname)
+        local ok = io.savedata(luaname,input.serialize(data))
+        if ok then
+            input.report("%s saved in %s",dataname,luaname)
+            if utils.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip
+                input.report("%s compiled to %s",dataname,lucname)
+            else
+                input.report("compiling failed for %s, deleting file %s",dataname,lucname)
                 os.remove(lucname)
             end
         else
-            input.report("unable to save " .. dataname .. " in " .. name..input.luasuffix)
+            input.report("unable to save %s in %s (access error)",dataname,luaname)
         end
     end
 end
 
-function input.aux.load_data(instance,pathname,dataname,filename,makename) -- untested without cache overload
+function input.aux.load_data(pathname,dataname,filename,makename) -- untested without cache overload
+    local instance = input.instance
     filename = ((not filename or (filename == "")) and dataname) or filename
     filename = (makename and makename(dataname,filename)) or file.join(pathname,filename)
-    local blob = loadfile(filename .. input.lucsuffix) or loadfile(filename .. input.luasuffix)
+    local blob = loadfile(filename .. ".luc") or loadfile(filename .. ".lua")
     if blob then
         local data = blob()
         if data and data.content and data.type == dataname and data.version == input.cacheversion then
-            input.report("loading",dataname,"for",pathname,"from",filename)
+            input.report("loading %s for %s from %s",dataname,pathname,filename)
             instance[dataname][pathname] = data.content
         else
-            input.report("skipping",dataname,"for",pathname,"from",filename)
+            input.report("skipping %s for %s from %s",dataname,pathname,filename)
             instance[dataname][pathname] = { }
             instance.loaderror = true
         end
     else
-        input.report("skipping",dataname,"for",pathname,"from",filename)
+        input.report("skipping %s for %s from %s",dataname,pathname,filename)
     end
 end
 
@@ -5712,13 +5902,14 @@ end
 --     TEXMFBOGUS = 'effe checken of dit werkt',
 -- }
 
-function input.aux.load_texmfcnf(instance,dataname,pathname)
+function input.aux.load_texmfcnf(dataname,pathname)
+    local instance = input.instance
     local filename = file.join(pathname,input.luaname)
     local blob = loadfile(filename)
     if blob then
         local data = blob()
         if data then
-            input.report("loading","configuration file",filename)
+            input.report("loading configuration file %s",filename)
             if true then
                 -- flatten to variable.progname
                 local t = { }
@@ -5738,172 +5929,168 @@ function input.aux.load_texmfcnf(instanc
                 instance[dataname][pathname] = data
             end
         else
-            input.report("skipping","configuration file",filename)
+            input.report("skipping configuration file %s",filename)
             instance[dataname][pathname] = { }
             instance.loaderror = true
         end
     else
-        input.report("skipping","configuration file",filename)
+        input.report("skipping configuration file %s",filename)
     end
 end
 
-function input.aux.load_configuration(instance,dname,lname)
-    input.aux.load_data(instance,dname,'configuration',lname and file.basename(lname))
+function input.aux.load_configuration(dname,lname)
+    input.aux.load_data(dname,'configuration',lname and file.basename(lname))
 end
-function input.aux.load_files(instance,tag)
-    input.aux.load_data(instance,tag,'files')
+function input.aux.load_files(tag)
+    input.aux.load_data(tag,'files')
 end
 
-function input.resetconfig(instance)
+function input.resetconfig()
+    input.identify_own()
+    local instance = input.instance
     instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false
 end
 
-function input.loadnewconfig(instance)
+function input.loadnewconfig()
+    local instance = input.instance
     for _, cnf in ipairs(instance.luafiles) do
         local dname = file.dirname(cnf)
-        input.aux.load_texmfcnf(instance,'setup',dname)
+        input.aux.load_texmfcnf('setup',dname)
         instance.order[#instance.order+1] = instance.setup[dname]
         if instance.loaderror then break end
     end
 end
 
-function input.loadoldconfig(instance)
+function input.loadoldconfig()
+    local instance = input.instance
     if not instance.renewcache then
         for _, cnf in ipairs(instance.cnffiles) do
             local dname = file.dirname(cnf)
-            input.aux.load_configuration(instance,dname)
+            input.aux.load_configuration(dname)
             instance.order[#instance.order+1] = instance.configuration[dname]
             if instance.loaderror then break end
         end
     end
-    input.joinconfig(instance)
+    input.joinconfig()
 end
 
-function input.expand_variables(instance)
-    instance.expansions = { }
---~ instance.environment['SELFAUTOPARENT'] = instance.environment['SELFAUTOPARENT'] or instance.rootpath
-    if instance.engine   ~= "" then instance.environment['engine']   = instance.engine   end
-    if instance.progname ~= "" then instance.environment['progname'] = instance.progname end
-    for k,v in pairs(instance.environment) do
+function input.expand_variables()
+    local instance = input.instance
+    local expansions, environment, variables = { }, instance.environment, instance.variables
+    local env = input.env
+    instance.expansions = expansions
+    if instance.engine   ~= "" then environment['engine']   = instance.engine   end
+    if instance.progname ~= "" then environment['progname'] = instance.progname end
+    for k,v in pairs(environment) do
         local a, b = k:match("^(%a+)%_(.*)%s*$")
         if a and b then
-            instance.expansions[a..'.'..b] = v
+            expansions[a..'.'..b] = v
         else
-            instance.expansions[k] = v
+            expansions[k] = v
         end
     end
-    for k,v in pairs(instance.environment) do -- move environment to expansions
-        if not instance.expansions[k] then instance.expansions[k] = v end
+    for k,v in pairs(environment) do -- move environment to expansions
+        if not expansions[k] then expansions[k] = v end
     end
-    for k,v in pairs(instance.variables) do -- move variables to expansions
-        if not instance.expansions[k] then instance.expansions[k] = v end
+    for k,v in pairs(variables) do -- move variables to expansions
+        if not expansions[k] then expansions[k] = v end
     end
     while true do
         local busy = false
-        for k,v in pairs(instance.expansions) do
+        for k,v in pairs(expansions) do
             local s, n = v:gsub("%$([%a%d%_%-]+)", function(a)
                 busy = true
-                return instance.expansions[a] or input.env(instance,a)
+                return expansions[a] or env(a)
             end)
             local s, m = s:gsub("%$%{([%a%d%_%-]+)%}", function(a)
                 busy = true
-                return instance.expansions[a] or input.env(instance,a)
+                return expansions[a] or env(a)
             end)
             if n > 0 or m > 0 then
-                instance.expansions[k]= s
+                expansions[k]= s
             end
         end
         if not busy then break end
     end
-    local homedir = 
-       instance.environment[(os.type == "windows" and 'USERPROFILE') or 'HOME'] or '~'
-    for k,v in pairs(instance.expansions) do
-        v = v:gsub("^~", homedir) 
-        instance.expansions[k] = v:gsub("\\", '/')
+    for k,v in pairs(expansions) do
+        expansions[k] = v:gsub("\\", '/')
     end
 end
 
-function input.aux.expand_vars(instance,lst) -- simple vars
+function input.aux.expand_vars(lst) -- simple vars
+    local instance = input.instance
+    local variables, env = instance.variables, input.env
     for k,v in pairs(lst) do
         lst[k] = v:gsub("%$([%a%d%_%-]+)", function(a)
-            return instance.variables[a] or input.env(instance,a)
+            return variables[a] or env(a)
         end)
     end
 end
 
-function input.aux.expanded_var(instance,var) -- simple vars
+function input.aux.expanded_var(var) -- simple vars
+    local instance = input.instance
     return var:gsub("%$([%a%d%_%-]+)", function(a)
-        return instance.variables[a] or input.env(instance,a)
+        return instance.variables[a] or input.env(a)
     end)
 end
 
-function input.aux.entry(instance,entries,name)
+function input.aux.entry(entries,name)
     if name and (name ~= "") then
+        local instance = input.instance
         name = name:gsub('%$','')
         local result = entries[name..'.'..instance.progname] or entries[name]
         if result then
             return result
         else
-            result = input.env(instance,name)
+            result = input.env(name)
             if result then
                 instance.variables[name] = result
-                input.expand_variables(instance)
+                input.expand_variables()
                 return instance.expansions[name] or ""
             end
         end
     end
     return ""
 end
-function input.variable(instance,name)
-    return input.aux.entry(instance,instance.variables,name)
+function input.variable(name)
+    return input.aux.entry(input.instance.variables,name)
 end
-function input.expansion(instance,name)
-    return input.aux.entry(instance,instance.expansions,name)
+function input.expansion(name)
+    return input.aux.entry(input.instance.expansions,name)
 end
 
-function input.aux.is_entry(instance,entries,name)
+function input.aux.is_entry(entries,name)
     if name and name ~= "" then
         name = name:gsub('%$','')
-        return (entries[name..'.'..instance.progname] or entries[name]) ~= nil
+        return (entries[name..'.'..input.instance.progname] or entries[name]) ~= nil
     else
         return false
     end
 end
 
-function input.is_variable(instance,name)
-    return input.aux.is_entry(instance,instance.variables,name)
-end
-function input.is_expansion(instance,name)
-    return input.aux.is_entry(instance,instance.expansions,name)
+function input.is_variable(name)
+    return input.aux.is_entry(input.instance.variables,name)
 end
 
-function input.simplified_list(str)
-    if type(str) == 'table' then
-        return str -- troubles ; ipv , in texmf
-    elseif str == '' then
-        return { }
-    else
-        local t = { }
-        for _,v in ipairs(string.splitchr(str:gsub("^\{(.+)\}$","%1"),",")) do
-            t[#t+1] = (v:gsub("^[%!]*(.+)[%/\\]*$","%1"))
-        end
-        return t
-    end
+function input.is_expansion(name)
+    return input.aux.is_entry(input.instance.expansions,name)
 end
 
-function input.unexpanded_path_list(instance,str)
-    local pth = input.variable(instance,str)
+function input.unexpanded_path_list(str)
+    local pth = input.variable(str)
     local lst = input.split_path(pth)
-    return input.aux.expanded_path(instance,lst)
+    return input.aux.expanded_path(lst)
 end
-function input.unexpanded_path(instance,str)
-    return file.join_path(input.unexpanded_path_list(instance,str))
+
+function input.unexpanded_path(str)
+    return file.join_path(input.unexpanded_path_list(str))
 end
 
 do
     local done = { }
 
-    function input.reset_extra_path(instance)
+    function input.reset_extra_path()
+        local instance = input.instance
         local ep = instance.extra_paths
         if not ep then
             ep, done = { }, { }
@@ -5913,7 +6100,8 @@ do
         end
     end
 
-    function input.register_extra_path(instance,paths,subpaths)
+    function input.register_extra_path(paths,subpaths)
+        local instance = input.instance
         local ep = instance.extra_paths or { }
         local n = #ep
         if paths and paths ~= "" then
@@ -5958,7 +6146,8 @@ do
 
 end
 
-function input.expanded_path_list(instance,str)
+function input.expanded_path_list(str)
+    local instance = input.instance
     local function made_list(list)
         local ep = instance.extra_paths
         if not ep or #ep == 0 then
@@ -5999,39 +6188,41 @@ function input.expanded_path_list(instan
         -- engine+progname hash
         str = str:gsub("%$","")
         if not instance.lists[str] then -- cached
-            local lst = made_list(input.split_path(input.expansion(instance,str)))
-            instance.lists[str] = input.aux.expanded_path(instance,lst)
+            local lst = made_list(input.split_path(input.expansion(str)))
+            instance.lists[str] = input.aux.expanded_path(lst)
         end
         return instance.lists[str]
     else
-        local lst = input.split_path(input.expansion(instance,str))
-        return made_list(input.aux.expanded_path(instance,lst))
+        local lst = input.split_path(input.expansion(str))
+        return made_list(input.aux.expanded_path(lst))
     end
 end
 
-function input.expand_path(instance,str)
-    return file.join_path(input.expanded_path_list(instance,str))
+
+function input.clean_path_list(str)
+    local t = input.expanded_path_list(str)
+    if t then
+        for i=1,#t do
+            t[i] = file.collapse_path(input.clean_path(t[i]))
+        end
+    end
+    return t
 end
 
---~ function input.first_writable_path(instance,name)
---~     for _,v in pairs(input.expanded_path_list(instance,name)) do
---~         if file.is_writable(file.join(v,'luatex-cache.tmp')) then
---~             return v
---~         end
---~     end
---~     return "."
---~ end
+function input.expand_path(str)
+    return file.join_path(input.expanded_path_list(str))
+end
 
-function input.expanded_path_list_from_var(instance,str) -- brrr
+function input.expanded_path_list_from_var(str) -- brrr
     local tmp = input.var_of_format_or_suffix(str:gsub("%$",""))
     if tmp ~= "" then
-        return input.expanded_path_list(instance,str)
+        return input.expanded_path_list(str)
     else
-        return input.expanded_path_list(instance,tmp)
+        return input.expanded_path_list(tmp)
     end
 end
-function input.expand_path_from_var(instance,str)
-    return file.join_path(input.expanded_path_list_from_var(instance,str))
+function input.expand_path_from_var(str)
+    return file.join_path(input.expanded_path_list_from_var(str))
 end
 
 function input.format_of_var(str)
@@ -6061,9 +6252,9 @@ function input.var_of_format_or_suffix(s
     return ''
 end
 
-function input.expand_braces(instance,str) -- output variable and brace expansion of STRING
-    local ori = input.variable(instance,str)
-    local pth = input.aux.expanded_path(instance,input.split_path(ori))
+function input.expand_braces(str) -- output variable and brace expansion of STRING
+    local ori = input.variable(str)
+    local pth = input.aux.expanded_path(input.split_path(ori))
     return file.join_path(pth)
 end
 
@@ -6078,6 +6269,7 @@ end
 -- {a,b,c/{p,q,r}/d/{x,y,z}//}
 -- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}}
 -- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}}
+-- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}
 
 -- this one is better and faster, but it took me a while to realize
 -- that this kind of replacement is cleaner than messy parsing and
@@ -6086,19 +6278,19 @@ end
 -- work that well; the parsing is ok, but dealing with the resulting
 -- table is a pain because we need to work inside-out recursively
 
--- get rid of piecewise here, just a gmatch is ok
-
 function input.aux.splitpathexpr(str, t, validate)
     -- no need for optimization, only called a few times, we can use lpeg for the sub
     t = t or { }
-    local concat = table.concat
+    str = str:gsub(",}",",@}")
+    str = str:gsub("{,","{@,")
+ -- str = "@" .. str .. "@"
     while true do
         local done = false
         while true do
             local ok = false
-            str = str:gsub("([^{},]+){([^{}]-)}", function(a,b)
+            str = str:gsub("([^{},]+){([^{}]+)}", function(a,b)
                 local t = { }
-                b:piecewise(",", function(s) t[#t+1] = a .. s end)
+                for s in b:gmatch("[^,]+") do t[#t+1] = a .. s end
                 ok, done = true, true
                 return "{" .. concat(t,",") .. "}"
             end)
@@ -6106,9 +6298,9 @@ function input.aux.splitpathexpr(str, t,
         end
         while true do
             local ok = false
-            str = str:gsub("{([^{}]-)}([^{},]+)", function(a,b)
+            str = str:gsub("{([^{}]+)}([^{},]+)", function(a,b)
                 local t = { }
-                a:piecewise(",", function(s) t[#t+1] = s .. b end)
+                for s in a:gmatch("[^,]+") do t[#t+1] = s .. b end
                 ok, done = true, true
                 return "{" .. concat(t,",") .. "}"
             end)
@@ -6116,50 +6308,41 @@ function input.aux.splitpathexpr(str, t,
         end
         while true do
             local ok = false
-            str = str:gsub("([,{]){([^{}]+)}([,}])", function(a,b,c)
+            str = str:gsub("{([^{}]+)}{([^{}]+)}", function(a,b)
+                local t = { }
+                for sa in a:gmatch("[^,]+") do
+                    for sb in b:gmatch("[^,]+") do
+                        t[#t+1] = sa .. sb
+                    end
+                end
                 ok, done = true, true
-                return a .. b .. c
+                return "{" .. concat(t,",") .. "}"
             end)
             if not ok then break end
         end
-        if not done then break end
-    end
-    while true do
-        local ok = false
-        str = str:gsub("{([^{}]-)}{([^{}]-)}", function(a,b)
-            local t = { }
-            a:piecewise(",", function(sa)
-                b:piecewise(",", function(sb)
-                    t[#t+1] = sa .. sb
-                end)
-            end)
-            ok = true
-            return "{" .. concat(t,",") .. "}"
-        end)
-        if not ok then break end
-    end
-    while true do
-        local ok = false
-        str = str:gsub("{([^{}]-)}", function(a)
-            ok = true
-            return a
+        str = str:gsub("({[^{}]*){([^{}]+)}([^{}]*})", function(a,b,c)
+            done = true
+            return a .. b.. c
         end)
-        if not ok then break end
+        if not done then break end
     end
+    str = str:gsub("[{}]", "")
+    str = str:gsub("@","")
     if validate then
-        str:piecewise(",", function(s)
+        for s in str:gmatch("[^,]+") do
             s = validate(s)
             if s then t[#t+1] = s end
-        end)
+        end
     else
-        str:piecewise(",", function(s)
+        for s in str:gmatch("[^,]+") do
             t[#t+1] = s
-        end)
+        end
     end
     return t
 end
 
-function input.aux.expanded_path(instance,pathlist) -- maybe not a list, just a path
+function input.aux.expanded_path(pathlist) -- maybe not a list, just a path
+    local instance = input.instance
     -- a previous version fed back into pathlist
     local newlist, ok = { }, false
     for _,v in ipairs(pathlist) do
@@ -6191,17 +6374,16 @@ input.is_readable = { }
 function input.aux.is_readable(readable, name)
     if input.trace > 2 then
         if readable then
-            input.logger("+ readable", name)
+            input.logger("+ readable: %s",name)
         else
-            input.logger("- readable", name)
+            input.logger("- readable: %s", name)
         end
     end
     return readable
 end
 
 function input.is_readable.file(name)
- -- return input.aux.is_readable(file.is_readable(name), name)
-    return input.aux.is_readable(input.aux.is_file(name), name)
+    return input.aux.is_readable(lfs.isfile(name), name)
 end
 
 input.is_readable.tex = input.is_readable.file
@@ -6209,12 +6391,13 @@ input.is_readable.tex = input.is_readabl
 -- name
 -- name/name
 
-function input.aux.collect_files(instance,names)
+function input.aux.collect_files(names)
+    local instance = input.instance
     local filelist = { }
     for _, fname in pairs(names) do
         if fname then
             if input.trace > 2 then
-                input.logger("? blobpath asked",fname)
+                input.logger("? blobpath asked: %s",fname)
             end
             local bname = file.basename(fname)
             local dname = file.dirname(fname)
@@ -6228,7 +6411,7 @@ function input.aux.collect_files(instanc
                 local files = blobpath and instance.files[blobpath]
                 if files then
                     if input.trace > 2 then
-                        input.logger('? blobpath do',blobpath .. " (" .. bname ..")")
+                        input.logger('? blobpath do: %s (%s)',blobpath,bname)
                     end
                     local blobfile = files[bname]
                     if not blobfile then
@@ -6261,7 +6444,7 @@ function input.aux.collect_files(instanc
                         end
                     end
                 elseif input.trace > 1 then
-                    input.logger('! blobpath no',blobpath .. " (" .. bname ..")" )
+                    input.logger('! blobpath no: %s (%s)',blobpath,bname)
                 end
             end
         end
@@ -6316,15 +6499,17 @@ do
 
 end
 
-function input.aux.register_in_trees(instance,name)
+function input.aux.register_in_trees(name)
     if not name:find("^%.") then
+        local instance = input.instance
         instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one
     end
 end
 
 -- split the next one up, better for jit
 
-function input.aux.find_file(instance,filename) -- todo : plugin (scanners, checkers etc)
+function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc)
+    local instance = input.instance
     local result = { }
     local stamp  = nil
     filename = input.normalize_name(filename)  -- elsewhere
@@ -6333,16 +6518,22 @@ function input.aux.find_file(instance,fi
     if instance.remember then
         stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format
         if instance.found[stamp] then
-            input.logger('! remembered', filename)
+            if input.trace > 0 then
+                input.logger('! remembered: %s',filename)
+            end
             return instance.found[stamp]
         end
     end
     if filename:find('%*') then
-        input.logger('! wildcard', filename)
-        result = input.find_wildcard_files(instance,filename)
+        if input.trace > 0 then
+            input.logger('! wildcard: %s', filename)
+        end
+        result = input.find_wildcard_files(filename)
     elseif input.aux.qualified_path(filename) then
         if input.is_readable.file(filename) then
-            input.logger('! qualified', filename)
+            if input.trace > 0 then
+                input.logger('! qualified: %s', filename)
+            end
             result = { filename }
         else
             local forcedname, ok = "", false
@@ -6350,22 +6541,26 @@ function input.aux.find_file(instance,fi
                 if instance.format == "" then
                     forcedname = filename .. ".tex"
                     if input.is_readable.file(forcedname) then
-                        input.logger('! no suffix, forcing standard filetype tex')
+                        if input.trace > 0 then
+                            input.logger('! no suffix, forcing standard filetype: tex')
+                        end
                         result, ok = { forcedname }, true
                     end
                 else
                     for _, s in pairs(input.suffixes_of_format(instance.format)) do
                         forcedname = filename .. "." .. s
                         if input.is_readable.file(forcedname) then
-                            input.logger('! no suffix, forcing format filetype', s)
+                            if input.trace > 0 then
+                                input.logger('! no suffix, forcing format filetype: %s', s)
+                            end
                             result, ok = { forcedname }, true
                             break
                         end
                     end
                 end
             end
-            if not ok then
-                input.logger('? qualified', filename)
+            if not ok and input.trace > 0 then
+                input.logger('? qualified: %s', filename)
             end
         end
     else
@@ -6383,10 +6578,14 @@ function input.aux.find_file(instance,fi
                 local forcedname = filename .. '.tex'
                 wantedfiles[#wantedfiles+1] = forcedname
                 filetype = input.format_of_suffix(forcedname)
-                input.logger('! forcing filetype',filetype)
+                    if input.trace > 0 then
+                        input.logger('! forcing filetype: %s',filetype)
+                    end
             else
                 filetype = input.format_of_suffix(filename)
-                input.logger('! using suffix based filetype',filetype)
+                if input.trace > 0 then
+                    input.logger('! using suffix based filetype: %s',filetype)
+                end
             end
         else
             if ext == "" then
@@ -6395,16 +6594,18 @@ function input.aux.find_file(instance,fi
                 end
             end
             filetype = instance.format
-            input.logger('! using given filetype',filetype)
+            if input.trace > 0 then
+                input.logger('! using given filetype: %s',filetype)
+            end
         end
         local typespec = input.variable_of_format(filetype)
-        local pathlist = input.expanded_path_list(instance,typespec)
+        local pathlist = input.expanded_path_list(typespec)
         if not pathlist or #pathlist == 0 then
             -- no pathlist, access check only / todo == wildcard
             if input.trace > 2 then
-                input.logger('? filename',filename)
-                input.logger('? filetype',filetype or '?')
-                input.logger('? wanted files',table.concat(wantedfiles," | "))
+                input.logger('? filename: %s',filename)
+                input.logger('? filetype: %s',filetype or '?')
+                input.logger('? wanted files: %s',concat(wantedfiles," | "))
             end
             for _, fname in pairs(wantedfiles) do
                 if fname and input.is_readable.file(fname) then
@@ -6414,7 +6615,7 @@ function input.aux.find_file(instance,fi
                 end
             end
             -- this is actually 'other text files' or 'any' or 'whatever'
-            local filelist = input.aux.collect_files(instance,wantedfiles)
+            local filelist = input.aux.collect_files(wantedfiles)
             local fl = filelist and filelist[1]
             if fl then
                 filename = fl[3]
@@ -6423,12 +6624,12 @@ function input.aux.find_file(instance,fi
             end
         else
             -- list search
-            local filelist = input.aux.collect_files(instance,wantedfiles)
+            local filelist = input.aux.collect_files(wantedfiles)
             local doscan, recurse
             if input.trace > 2 then
-                input.logger('? filename',filename)
-            --                if pathlist then input.logger('? path list',table.concat(pathlist," | ")) end
-            --                if filelist then input.logger('? file list',table.concat(filelist," | ")) end
+                input.logger('? filename: %s',filename)
+            --                if pathlist then input.logger('? path list: %s',concat(pathlist," | ")) end
+            --                if filelist then input.logger('? file list: %s',concat(filelist," | ")) end
             end
             -- a bit messy ... esp the doscan setting here
             for _, path in pairs(pathlist) do
@@ -6449,11 +6650,11 @@ function input.aux.find_file(instance,fi
                         if f:find(expr) then
                             -- input.debug('T',' '..f)
                             if input.trace > 2 then
-                                input.logger('= found in hash',f)
+                                input.logger('= found in hash: %s',f)
                             end
                             --- todo, test for readable
                             result[#result+1] = fl[3]
-                            input.aux.register_in_trees(instance,f) -- for tracing used files
+                            input.aux.register_in_trees(f) -- for tracing used files
                             done = true
                             if not instance.allresults then break end
                         else
@@ -6467,12 +6668,12 @@ function input.aux.find_file(instance,fi
                         local pname = pathname:gsub("%.%*$",'')
                         if not pname:find("%*") then
                             local ppname = pname:gsub("/+$","")
-                            if input.aux.can_be_dir(instance,ppname) then
+                            if input.aux.can_be_dir(ppname) then
                                 for _, w in pairs(wantedfiles) do
                                     local fname = file.join(ppname,w)
                                     if input.is_readable.file(fname) then
                                         if input.trace > 2 then
-                                            input.logger('= found by scanning',fname)
+                                            input.logger('= found by scanning: %s',fname)
                                         end
                                         result[#result+1] = fname
                                         done = true
@@ -6501,40 +6702,29 @@ function input.aux.find_file(instance,fi
     return result
 end
 
-input.aux._find_file_ = input.aux.find_file
+input.aux._find_file_ = input.aux.find_file -- frozen variant
 
-function input.aux.find_file(instance,filename) -- maybe make a lowres cache too
-    local result = input.aux._find_file_(instance,filename)
+function input.aux.find_file(filename) -- maybe make a lowres cache too
+    local result = input.aux._find_file_(filename)
     if #result == 0 then
         local lowered = filename:lower()
         if filename ~= lowered then
-            return input.aux._find_file_(instance,lowered)
+            return input.aux._find_file_(lowered)
         end
     end
     return result
 end
 
-if lfs and lfs.isfile then
-    input.aux.is_file = lfs.isfile      -- to be done: use this
-else
-    input.aux.is_file = file.is_readable
-end
-
-if lfs and lfs.isdir then
-    function input.aux.can_be_dir(instance,name)
-        if not instance.fakepaths[name] then
-            if lfs.isdir(name) then
-                instance.fakepaths[name] = 1 -- directory
-            else
-                instance.fakepaths[name] = 2 -- no directory
-            end
+function input.aux.can_be_dir(name)
+    local instance = input.instance
+    if not instance.fakepaths[name] then
+        if lfs.isdir(name) then
+            instance.fakepaths[name] = 1 -- directory
+        else
+            instance.fakepaths[name] = 2 -- no directory
         end
-        return (instance.fakepaths[name] == 1)
-    end
-else
-    function input.aux.can_be_dir()
-        return true
     end
+    return (instance.fakepaths[name] == 1)
 end
 
 if not input.concatinators  then input.concatinators = { } end
@@ -6542,7 +6732,8 @@ if not input.concatinators  then input.c
 input.concatinators.tex  = file.join
 input.concatinators.file = input.concatinators.tex
 
-function input.find_files(instance,filename,filetype,mustexist)
+function input.find_files(filename,filetype,mustexist)
+    local instance = input.instance
     if type(mustexist) == boolean then
         -- all set
     elseif type(filetype) == 'boolean' then
@@ -6551,16 +6742,17 @@ function input.find_files(instance,filen
         filetype, mustexist = nil, false
     end
     instance.format = filetype or ''
-    local t = input.aux.find_file(instance,filename,true)
+    local t = input.aux.find_file(filename,true)
     instance.format = ''
     return t
 end
 
-function input.find_file(instance,filename,filetype,mustexist)
-    return (input.find_files(instance,filename,filetype,mustexist)[1] or "")
+function input.find_file(filename,filetype,mustexist)
+    return (input.find_files(filename,filetype,mustexist)[1] or "")
 end
 
-function input.find_given_files(instance,filename)
+function input.find_given_files(filename)
+    local instance = input.instance
     local bname, result = file.basename(filename), { }
     for k, hash in ipairs(instance.hashes) do
         local files = instance.files[hash.tag]
@@ -6588,11 +6780,12 @@ function input.find_given_files(instance
     return result
 end
 
-function input.find_given_file(instance,filename)
-    return (input.find_given_files(instance,filename)[1] or "")
+function input.find_given_file(filename)
+    return (input.find_given_files(filename)[1] or "")
 end
 
-function input.find_wildcard_files(instance,filename) -- todo: remap:
+function input.find_wildcard_files(filename) -- todo: remap:
+    local instance = input.instance
     local result = { }
     local bname, dname = file.basename(filename), file.dirname(filename)
     local path = dname:gsub("^*/","")
@@ -6645,16 +6838,19 @@ function input.find_wildcard_files(insta
             if done and not allresults then break end
         end
     end
+    -- we can consider also searching the paths not in the database, but then
+    -- we end up with a messy search (all // in all path specs)
     return result
 end
 
-function input.find_wildcard_file(instance,filename)
-    return (input.find_wildcard_files(instance,filename)[1] or "")
+function input.find_wildcard_file(filename)
+    return (input.find_wildcard_files(filename)[1] or "")
 end
 
 -- main user functions
 
-function input.save_used_files_in_trees(instance, filename,jobname)
+function input.save_used_files_in_trees(filename,jobname)
+    local instance = input.instance
     if not filename then filename = 'luatex.jlg' end
     local f = io.open(filename,'w')
     if f then
@@ -6664,7 +6860,7 @@ function input.save_used_files_in_trees(
             f:write("\t<rl:name>" .. jobname .. "</rl:name>\n")
         end
         f:write("\t<rl:files>\n")
-        for _,v in pairs(table.sortedkeys(instance.foundintrees)) do
+        for _,v in pairs(sorted(instance.foundintrees)) do -- ipairs
             f:write("\t\t<rl:file n='" .. instance.foundintrees[v] .. "'>" .. v .. "</rl:file>\n")
         end
         f:write("\t</rl:files>\n")
@@ -6673,24 +6869,24 @@ function input.save_used_files_in_trees(
     end
 end
 
-function input.automount(instance)
+function input.automount()
     -- implemented later
 end
 
-function input.load(instance)
-    input.starttiming(instance)
-    input.resetconfig(instance)
-    input.identify_cnf(instance)
-    input.load_lua(instance)
-    input.expand_variables(instance)
-    input.load_cnf(instance)
-    input.expand_variables(instance)
-    input.load_hash(instance)
-    input.automount(instance)
-    input.stoptiming(instance)
+function input.load()
+    input.starttiming(input.instance)
+    input.resetconfig()
+    input.identify_cnf()
+    input.load_lua()
+    input.expand_variables()
+    input.load_cnf()
+    input.expand_variables()
+    input.load_hash()
+    input.automount()
+    input.stoptiming(input.instance)
 end
 
-function input.for_files(instance, command, files, filetype, mustexist)
+function input.for_files(command, files, filetype, mustexist)
     if files and #files > 0 then
         local function report(str)
             if input.verbose then
@@ -6703,7 +6899,7 @@ function input.for_files(instance, comma
             report('')
         end
         for _, file in pairs(files) do
-            local result = command(instance,file,filetype,mustexist)
+            local result = command(file,filetype,mustexist)
             if type(result) == 'string' then
                 report(result)
             else
@@ -6717,14 +6913,11 @@ end
 
 -- strtab
 
-function input.var_value(instance,str)     -- output the value of variable $STRING.
-    return input.variable(instance,str)
-end
-function input.expand_var(instance,str)    -- output variable expansion of STRING.
-    return input.expansion(instance,str)
-end
-function input.show_path(instance,str)     -- output search path for file type NAME
-    return file.join_path(input.expanded_path_list(instance,input.format_of_var(str)))
+input.var_value  = input.variable   -- output the value of variable $STRING.
+input.expand_var = input.expansion  -- output variable expansion of STRING.
+
+function input.show_path(str)     -- output search path for file type NAME
+    return file.join_path(input.expanded_path_list(input.format_of_var(str)))
 end
 
 -- input.find_file(filename)
@@ -6773,56 +6966,58 @@ function table.sequenced(t,sep) -- temp 
     for k, v in pairs(t) do
         s[#s+1] = k .. "=" .. v
     end
-    return table.concat(s, sep or " | ")
+    return concat(s, sep or " | ")
 end
 
-function input.methodhandler(what, instance, filename, filetype) -- ...
+function input.methodhandler(what, filename, filetype) -- ...
     local specification = (type(filename) == "string" and input.splitmethod(filename)) or filename -- no or { }, let it bomb
     local scheme = specification.scheme
     if input[what][scheme] then
-        input.logger('= handler',specification.original .." -> " .. what .. " -> " .. table.sequenced(specification))
-        return input[what][scheme](instance,filename,filetype) -- todo: specification
+        if input.trace > 0 then
+            input.logger('= handler: %s -> %s -> %s',specification.original,what,table.sequenced(specification))
+        end
+        return input[what][scheme](filename,filetype) -- todo: specification
     else
-        return input[what].tex(instance,filename,filetype) -- todo: specification
+        return input[what].tex(filename,filetype) -- todo: specification
     end
 end
 
 -- also inside next test?
 
-function input.findtexfile(instance, filename, filetype)
-    return input.methodhandler('finders',instance, input.normalize_name(filename), filetype)
+function input.findtexfile(filename, filetype)
+    return input.methodhandler('finders',input.normalize_name(filename), filetype)
 end
-function input.opentexfile(instance,filename)
-    return input.methodhandler('openers',instance, input.normalize_name(filename))
+function input.opentexfile(filename)
+    return input.methodhandler('openers',input.normalize_name(filename))
 end
 
-function input.findbinfile(instance, filename, filetype)
-    return input.methodhandler('finders',instance, input.normalize_name(filename), filetype)
+function input.findbinfile(filename, filetype)
+    return input.methodhandler('finders',input.normalize_name(filename), filetype)
 end
-function input.openbinfile(instance,filename)
-    return input.methodhandler('loaders',instance, input.normalize_name(filename))
+function input.openbinfile(filename)
+    return input.methodhandler('loaders',input.normalize_name(filename))
 end
 
-function input.loadbinfile(instance, filename, filetype)
-    local fname = input.findbinfile(instance, input.normalize_name(filename), filetype)
+function input.loadbinfile(filename, filetype)
+    local fname = input.findbinfile(input.normalize_name(filename), filetype)
     if fname and fname ~= "" then
-        return input.openbinfile(instance,fname)
+        return input.openbinfile(fname)
     else
         return unpack(input.loaders.notfound)
     end
 end
 
-function input.texdatablob(instance, filename, filetype)
-    local ok, data, size = input.loadbinfile(instance, filename, filetype)
+function input.texdatablob(filename, filetype)
+    local ok, data, size = input.loadbinfile(filename, filetype)
     return data or ""
 end
 
 input.loadtexfile = input.texdatablob
 
-function input.openfile(filename) -- brrr texmf.instance here  / todo ! ! ! ! !
-    local fullname = input.findtexfile(texmf.instance, filename)
+function input.openfile(filename)
+    local fullname = input.findtexfile(filename)
     if fullname and (fullname ~= "") then
-        return input.opentexfile(texmf.instance, fullname)
+        return input.opentexfile(fullname)
     else
         return nil
     end
@@ -6868,16 +7063,18 @@ end
 -- beware: i need to check where we still need a / on windows:
 
 function input.clean_path(str)
---~     return (((str:gsub("\\","/")):gsub("^!+","")):gsub("//+","//"))
     if str then
-        return ((str:gsub("\\","/")):gsub("^!+",""))
+        str = str:gsub("\\","/")
+        str = str:gsub("^!+","")
+        str = str:gsub("^~",input.homedir)
+        return str
     else
         return nil
     end
 end
 
 function input.do_with_path(name,func)
-    for _, v in pairs(input.expanded_path_list(instance,name)) do
+    for _, v in pairs(input.expanded_path_list(name)) do
         func("^"..input.clean_path(v))
     end
 end
@@ -6886,7 +7083,8 @@ function input.do_with_var(name,func)
     func(input.aux.expanded_var(name))
 end
 
-function input.with_files(instance,pattern,handle)
+function input.with_files(pattern,handle)
+    local instance = input.instance
     for _, hash in ipairs(instance.hashes) do
         local blobpath = hash.tag
         local blobtype = hash.type
@@ -6913,37 +7111,22 @@ function input.with_files(instance,patte
     end
 end
 
---~ function input.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
---~     newname = file.addsuffix(newname,"lua")
---~     local newscript = input.clean_path(input.find_file(instance, newname))
---~     local oldscript = input.clean_path(oldname)
---~     input.report("old script", oldscript)
---~     input.report("new script", newscript)
---~     if oldscript ~= newscript and (oldscript:find(file.removesuffix(newname).."$") or oldscript:find(newname.."$")) then
---~         local newdata = io.loaddata(newscript)
---~         if newdata then
---~             input.report("old script content replaced by new content")
---~             io.savedata(oldscript,newdata)
---~         end
---~     end
---~ end
-
-function input.update_script(instance,oldname,newname) -- oldname -> own.name, not per se a suffix
+function input.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
     local scriptpath = "scripts/context/lua"
     newname = file.addsuffix(newname,"lua")
     local oldscript = input.clean_path(oldname)
-    input.report("to be replaced old script", oldscript)
-    local newscripts = input.find_files(instance, newname) or { }
+    input.report("to be replaced old script %s", oldscript)
+    local newscripts = input.find_files(newname) or { }
     if #newscripts == 0 then
         input.report("unable to locate new script")
     else
         for _, newscript in ipairs(newscripts) do
             newscript = input.clean_path(newscript)
-            input.report("checking new script", newscript)
+            input.report("checking new script %s", newscript)
             if oldscript == newscript then
                 input.report("old and new script are the same")
             elseif not newscript:find(scriptpath) then
-                input.report("new script should come from",scriptpath)
+                input.report("new script should come from %s",scriptpath)
             elseif not (oldscript:find(file.removesuffix(newname).."$") or oldscript:find(newname.."$")) then
                 input.report("invalid new script name")
             else
@@ -6971,10 +7154,10 @@ do
 
     local resolvers = { }
 
-    resolvers.environment = function(instance,str)
+    resolvers.environment = function(str)
         return input.clean_path(os.getenv(str) or os.getenv(str:upper()) or os.getenv(str:lower()) or "")
     end
-    resolvers.relative = function(instance,str,n)
+    resolvers.relative = function(str,n)
         if io.exists(str) then
             -- nothing
         elseif io.exists("./" .. str) then
@@ -6992,16 +7175,16 @@ do
         end
         return input.clean_path(str)
     end
-    resolvers.locate = function(instance,str)
-        local fullname = input.find_given_file(instance,str) or ""
+    resolvers.locate = function(str)
+        local fullname = input.find_given_file(str) or ""
         return input.clean_path((fullname ~= "" and fullname) or str)
     end
-    resolvers.filename = function(instance,str)
-        local fullname = input.find_given_file(instance,str) or ""
+    resolvers.filename = function(str)
+        local fullname = input.find_given_file(str) or ""
         return input.clean_path(file.basename((fullname ~= "" and fullname) or str))
     end
-    resolvers.pathname = function(instance,str)
-        local fullname = input.find_given_file(instance,str) or ""
+    resolvers.pathname = function(str)
+        local fullname = input.find_given_file(str) or ""
         return input.clean_path(file.dirname((fullname ~= "" and fullname) or str))
     end
 
@@ -7013,15 +7196,15 @@ do
     resolvers.file = resolvers.filename
     resolvers.path = resolvers.pathname
 
-    local function resolve(instance,str)
+    local function resolve(str)
         if type(str) == "table" then
             for k, v in pairs(str) do
-                str[k] = resolve(instance,v) or v
+                str[k] = resolve(v) or v
             end
         elseif str and str ~= "" then
-            str = str:gsub("([a-z]+):([^ ]+)", function(method,target)
+            str = str:gsub("([a-z]+):([^ \"\']*)", function(method,target)
                 if resolvers[method] then
-                    return resolvers[method](instance,target)
+                    return resolvers[method](target)
                 else
                     return method .. ":" .. target
                 end
@@ -7030,10 +7213,185 @@ do
         return str
     end
 
+    if os.uname then
+        for k, v in pairs(os.uname()) do
+            if not resolvers[k] then
+                resolvers[k] = function() return v end
+            end
+        end
+    end
+
     input.resolve = resolve
 
 end
 
+function input.boolean_variable(str,default)
+    local b = input.expansion(str)
+    if b == "" then
+        return default
+    else
+        b = toboolean(b)
+        return (b == nil and default) or b
+    end
+end
+
+
+if not modules then modules = { } end modules ['luat-log'] = {
+    version   = 1.001,
+    comment   = "companion to luat-lib.tex",
+    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+    copyright = "PRAGMA ADE / ConTeXt Development Team",
+    license   = "see context related readme files"
+}
+
+--[[ldx--
+<p>This is a prelude to a more extensive logging module. For the sake
+of parsing log files, in addition to the standard logging we will
+provide an <l n='xml'/> structured file. Actually, any logging that
+is hooked into callbacks will be \XML\ by default.</p>
+--ldx]]--
+
+-- input.logger -> special tracing, driven by log level (only input)
+-- input.report -> goes to terminal, depends on verbose, has banner
+-- logs.report  -> module specific tracing and reporting, no banner but class
+
+
+input = input or { }
+logs  = logs  or { }
+
+--[[ldx--
+<p>This looks pretty ugly but we need to speed things up a bit.</p>
+--ldx]]--
+
+logs.levels = {
+    ['error']   = 1,
+    ['warning'] = 2,
+    ['info']    = 3,
+    ['debug']   = 4
+}
+
+logs.functions = {
+    'report', 'start', 'stop', 'push', 'pop', 'line', 'direct'
+}
+
+logs.callbacks  = {
+    'start_page_number',
+    'stop_page_number',
+    'report_output_pages',
+    'report_output_log'
+}
+
+logs.tracers = {
+}
+
+logs.xml = logs.xml or { }
+logs.tex = logs.tex or { }
+
+logs.level = 0
+
+local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format
+
+if texlua then
+    write_nl = print
+    write    = io.write
+end
+
+function logs.xml.report(category,fmt,...) -- new
+    write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...)))
+end
+function logs.xml.line(fmt,...) -- new
+    write_nl(format("<r>%s</r>",format(fmt,...)))
+end
+
+function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end
+function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end
+function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end
+function logs.xml.pop  () if logs.level > 0 then tw(" -->" ) end end
+
+function logs.tex.report(category,fmt,...) -- new
+ -- write_nl(format("%s | %s",category,format(fmt,...))) -- arg to format can be tex comment so .. .
+    write_nl(category .. " | " .. format(fmt,...))
+end
+function logs.tex.line(fmt,...) -- new
+    write_nl(format(fmt,...))
+end
+
+function logs.set_level(level)
+    logs.level = logs.levels[level] or level
+end
+
+function logs.set_method(method)
+    for _, v in pairs(logs.functions) do
+        logs[v] = logs[method][v] or function() end
+    end
+    if callback and input[method] then
+        for _, cb in pairs(logs.callbacks) do
+            callback.register(cb, input[method][cb])
+        end
+    end
+end
+
+function logs.xml.start_page_number()
+    write_nl(format("<p real='%s' page='%s' sub='%s'", tex.count[0], tex.count[1], tex.count[2]))
+end
+
+function logs.xml.stop_page_number()
+    write("/>")
+    write_nl("")
+end
+
+function logs.xml.report_output_pages(p,b)
+    write_nl(format("<v k='pages' v='%s'/>", p))
+    write_nl(format("<v k='bytes' v='%s'/>", b))
+    write_nl("")
+end
+
+function logs.xml.report_output_log()
+end
+
+function input.logger(...) -- assumes test for input.trace > n
+    if input.trace > 0 then
+        logs.report(...)
+    end
+end
+
+function input.report(fmt,...)
+    if input.verbose then
+        logs.report(input.banner or "report",format(fmt,...))
+    end
+end
+
+function input.reportlines(str) -- todo: <lines></lines>
+    for line in str:gmatch("(.-)[\n\r]") do
+        logs.report(input.banner or "report",line)
+    end
+end
+
+input.moreinfo = [[
+more information about ConTeXt and the tools that come with it can be found at:
+
+maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
+webpage  : http://www.pragma-ade.nl / http://tex.aanhet.net
+wiki     : http://contextgarden.net
+]]
+
+function input.help(banner,message)
+    if not input.verbose then
+        input.verbose = true
+    --  input.report(banner,"\n")
+    end
+    input.report(banner,"\n")
+    input.report("")
+    input.reportlines(message)
+    if input.moreinfo and input.moreinfo ~= "" then
+        input.report("")
+        input.reportlines(input.moreinfo)
+    end
+end
+
+logs.set_level('error')
+logs.set_method('tex')
+
 
 if not modules then modules = { } end modules ['luat-tmp'] = {
     version   = 1.001,
@@ -7059,63 +7417,82 @@ being written at the same time is small.
 luatools with a recache feature.</p>
 --ldx]]--
 
+local format = string.format
+
 caches = caches or { }
 dir    = dir    or { }
 texmf  = texmf  or { }
 
-caches.path   = caches.path or nil
-caches.base   = caches.base or "luatex-cache"
-caches.more   = caches.more or "context"
-caches.direct = false -- true is faster but may need huge amounts of memory
-caches.trace  = false
-caches.tree   = false
-caches.paths  = caches.paths or nil
-caches.force  = false
-
-input.usecache = not toboolean(os.getenv("TEXMFSHARECACHE") or "false",true) -- true
-
-function caches.temp(instance)
-    local function checkpath(cachepath)
-        if not cachepath or cachepath == "" then
-            return nil
-        elseif lfs.attributes(cachepath,"mode") == "directory" then -- lfs.isdir(cachepath) then
-            return cachepath
-        elseif caches.force or io.ask(string.format("Should I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then
-            dir.mkdirs(cachepath)
-            return (lfs.attributes(cachepath,"mode") == "directory") and cachepath
-        else
-            return nil
+caches.path     = caches.path or nil
+caches.base     = caches.base or "luatex-cache"
+caches.more     = caches.more or "context"
+caches.direct   = false -- true is faster but may need huge amounts of memory
+caches.trace    = false
+caches.tree     = false
+caches.paths    = caches.paths or nil
+caches.force    = false
+caches.defaults = { "TEXMFCACHE", "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" }
+
+function caches.temp()
+    local cachepath = nil
+    local function check(list,isenv)
+        if not cachepath then
+            for _, v in ipairs(list) do
+                cachepath = (isenv and (os.env[v] or "")) or v or ""
+                if cachepath == "" then
+                    -- next
+                else
+                    cachepath = input.clean_path(cachepath)
+                     if lfs.isdir(cachepath) and file.iswritable(cachepath) then -- lfs.attributes(cachepath,"mode") == "directory"
+                        break
+                    elseif caches.force or io.ask(format("\nShould I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then
+                        dir.mkdirs(cachepath)
+                        if lfs.isdir(cachepath) and file.iswritable(cachepath) then
+                            break
+                        end
+                    end
+                end
+                cachepath = nil
+            end
         end
     end
-    local cachepath = input.expanded_path_list(instance,"TEXMFCACHE")
-    cachepath = cachepath and #cachepath > 0 and checkpath(cachepath[1])
-    if not cachepath then
-        cachepath = os.getenv("TEXMFCACHE") or os.getenv("HOME") or os.getenv("HOMEPATH") or os.getenv("TMP") or os.getenv("TEMP") or os.getenv("TMPDIR") or nil
-        cachepath = checkpath(cachepath)
-    end
+    check(input.clean_path_list("TEXMFCACHE") or { })
+    check(caches.defaults,true)
     if not cachepath then
-        print("\nfatal error: there is no valid cache path defined\n")
+        print("\nfatal error: there is no valid (writable) cache path defined\n")
         os.exit()
-    elseif lfs.attributes(cachepath,"mode") ~= "directory" then
-        print(string.format("\nfatal error: cache path %s is not a directory\n",cachepath))
+    elseif not lfs.isdir(cachepath) then -- lfs.attributes(cachepath,"mode") ~= "directory"
+        print(format("\nfatal error: cache path %s is not a directory\n",cachepath))
         os.exit()
     end
-    function caches.temp(instance)
+    cachepath = input.normalize_name(cachepath)
+    function caches.temp()
         return cachepath
     end
     return cachepath
 end
 
-function caches.configpath(instance)
-    return table.concat(instance.cnffiles,";")
+function caches.configpath()
+    return table.concat(input.instance.cnffiles,";")
 end
 
 function caches.hashed(tree)
     return md5.hex((tree:lower()):gsub("[\\\/]+","/"))
 end
 
-function caches.treehash(instance)
-    local tree = caches.configpath(instance)
+--~ tracing:
+
+--~ function caches.hashed(tree)
+--~     tree = (tree:lower()):gsub("[\\\/]+","/")
+--~     local hash = md5.hex(tree)
+--~     if input.verbose then -- temp message
+--~         input.report("hashing %s => %s",tree,hash)
+--~     end
+--~     return hash
+--~ end
+
+function caches.treehash()
+    local tree = caches.configpath()
     if not tree or tree == "" then
         return false
     else
@@ -7123,14 +7500,14 @@ function caches.treehash(instance)
     end
 end
 
-function caches.setpath(instance,...)
+function caches.setpath(...)
     if not caches.path then
         if not caches.path then
-            caches.path = caches.temp(instance)
+            caches.path = caches.temp()
         end
         caches.path = input.clean_path(caches.path) -- to be sure
         if lfs then
-            caches.tree = caches.tree or caches.treehash(instance)
+            caches.tree = caches.tree or caches.treehash()
             if caches.tree then
                 caches.path = dir.mkdirs(caches.path,caches.base,caches.more,caches.tree)
             else
@@ -7150,9 +7527,9 @@ function caches.setpath(instance,...)
     return caches.path
 end
 
-function caches.definepath(instance,category,subcategory)
+function caches.definepath(category,subcategory)
     return function()
-        return caches.setpath(instance,category,subcategory)
+        return caches.setpath(category,subcategory)
     end
 end
 
@@ -7175,26 +7552,28 @@ function caches.is_writable(filepath,fil
     return file.is_writable(tmaname)
 end
 
-function caches.savedata(filepath,filename,data,raw) -- raw needed for file cache
+function caches.savedata(filepath,filename,data,raw)
     local tmaname, tmcname = caches.setluanames(filepath,filename)
     local reduce, simplify = true, true
     if raw then
         reduce, simplify = false, false
     end
     if caches.direct then
-        file.savedata(tmaname, table.serialize(data,'return',true,true))
+        file.savedata(tmaname, table.serialize(data,'return',true,true,false)) -- no hex
     else
-        table.tofile (tmaname,                 data,'return',true,true) -- maybe not the last true
+        table.tofile(tmaname, data,'return',true,true,false) -- maybe not the last true
     end
-    utils.lua.compile(tmaname, tmcname)
+    local cleanup = input.boolean_variable("PURGECACHE", false)
+    local strip = input.boolean_variable("LUACSTRIP", true)
+    utils.lua.compile(tmaname, tmcname, cleanup, strip)
 end
 
 -- here we use the cache for format loading (texconfig.[formatname|jobname])
 
 --~ if tex and texconfig and texconfig.formatname and texconfig.formatname == "" then
-if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and texmf.instance then
+if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and input and input.instance then
     if not texconfig.luaname then texconfig.luaname = "cont-en.lua" end -- or luc
-    texconfig.formatname = caches.setpath(texmf.instance,"formats") .. "/" .. texconfig.luaname:gsub("%.lu.$",".fmt")
+    texconfig.formatname = caches.setpath("formats") .. "/" .. texconfig.luaname:gsub("%.lu.$",".fmt")
 end
 
 --[[ldx--
@@ -7217,7 +7596,7 @@ do -- local report
 
     local function report(container,tag,name)
         if caches.trace or containers.trace or container.trace then
-            logs.report(string.format("%s cache",container.subcategory),string.format("%s: %s",tag,name or 'invalid'))
+            logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid')
         end
     end
 
@@ -7242,7 +7621,7 @@ do -- local report
                         enabled = enabled,
                         version = version or 1.000,
                         trace = false,
-                        path = caches.setpath(texmf.instance,category,subcategory),
+                        path = caches.setpath(category,subcategory),
                     }
                     c[subcategory] = s
                 end
@@ -7307,13 +7686,16 @@ end
 -- reimplement the saver.
 
 local save_data = input.aux.save_data
+local load_data = input.aux.load_data
 
-input.cachepath = nil
+input.cachepath = nil  -- public, for tracing
+input.usecache  = true -- public, for tracing
 
-function input.aux.save_data(instance, dataname, check)
-    input.cachepath = input.cachepath or caches.definepath(instance,"trees")
-    save_data(instance, dataname, check, function(cachename,dataname)
+function input.aux.save_data(dataname, check)
+    save_data(dataname, check, function(cachename,dataname)
+        input.usecache = not toboolean(input.expansion("CACHEINTDS") or "false",true)
         if input.usecache then
+            input.cachepath = input.cachepath or caches.definepath("trees")
             return file.join(input.cachepath(),caches.hashed(cachename))
         else
             return file.join(cachename,dataname)
@@ -7321,12 +7703,11 @@ function input.aux.save_data(instance, d
     end)
 end
 
-local load_data = input.aux.load_data
-
-function input.aux.load_data(instance,pathname,dataname,filename)
-    input.cachepath = input.cachepath or caches.definepath(instance,"trees")
-    load_data(instance,pathname,dataname,filename,function(dataname,filename)
+function input.aux.load_data(pathname,dataname,filename)
+    load_data(pathname,dataname,filename,function(dataname,filename)
+        input.usecache = not toboolean(input.expansion("CACHEINTDS") or "false",true)
         if input.usecache then
+            input.cachepath = input.cachepath or caches.definepath("trees")
             return file.join(input.cachepath(),caches.hashed(pathname))
         else
             if not filename or (filename == "") then
@@ -7341,13 +7722,13 @@ end
 
 input.automounted = input.automounted or { }
 
-function input.automount(instance,usecache)
-    local mountpaths = input.simplified_list(input.expansion(instance,'TEXMFMOUNT'))
+function input.automount(usecache)
+    local mountpaths = input.clean_path_list(input.expansion('TEXMFMOUNT'))
     if table.is_empty(mountpaths) and usecache then
-        mountpaths = { caches.setpath(instance,"mount") }
+        mountpaths = { caches.setpath("mount") }
     end
     if not table.is_empty(mountpaths) then
-        input.starttiming(instance)
+        input.starttiming(input.instance)
         for k, root in pairs(mountpaths) do
             local f = io.open(root.."/url.tmi")
             if f then
@@ -7356,16 +7737,16 @@ function input.automount(instance,usecac
                         if line:find("^[%%#%-]") then -- or %W
                             -- skip
                         elseif line:find("^zip://") then
-                            input.report("mounting",line)
+                            input.report("mounting %s",line)
                             table.insert(input.automounted,line)
-                            input.usezipfile(instance,line)
+                            input.usezipfile(line)
                         end
                     end
                 end
                 f:close()
             end
         end
-        input.stoptiming(instance)
+        input.stoptiming(input.instance)
     end
 end
 
@@ -7376,7 +7757,7 @@ input.storage.data       = { }
 input.storage.min        = 0 -- 500
 input.storage.max        = input.storage.min - 1
 input.storage.trace      = false -- true
-input.storage.done       = 0
+input.storage.done       = input.storage.done or 0
 input.storage.evaluators = { }
 -- (evaluate,message,names)
 
@@ -7414,17 +7795,17 @@ function input.storage.dump()
             else
                 name = str
             end
-            initialize = string.format("%s %s = %s or {} ", initialize, name, name)
+            initialize = format("%s %s = %s or {} ", initialize, name, name)
         end
         if evaluate then
             finalize = "input.storage.evaluate(" .. name .. ")"
         end
         input.storage.max = input.storage.max + 1
         if input.storage.trace then
-            logs.report('storage',string.format('saving %s in slot %s',message,input.storage.max))
+            logs.report('storage','saving %s in slot %s',message,input.storage.max)
             code =
                 initialize ..
-                string.format("logs.report('storage','restoring %s from slot %s') ",message,input.storage.max) ..
+                format("logs.report('storage','restoring %s from slot %s') ",message,input.storage.max) ..
                 table.serialize(original,name) ..
                 finalize
         else
@@ -7434,6 +7815,8 @@ function input.storage.dump()
     end
 end
 
+-- we also need to count at generation time (nicer for message)
+
 if lua.bytecode then -- from 0 upwards
     local i = input.storage.min
     while lua.bytecode[i] do
@@ -7460,6 +7843,11 @@ provide an <l n='xml'/> structured file.
 is hooked into callbacks will be \XML\ by default.</p>
 --ldx]]--
 
+-- input.logger -> special tracing, driven by log level (only input)
+-- input.report -> goes to terminal, depends on verbose, has banner
+-- logs.report  -> module specific tracing and reporting, no banner but class
+
+
 input = input or { }
 logs  = logs  or { }
 
@@ -7475,8 +7863,7 @@ logs.levels = {
 }
 
 logs.functions = {
-    'error', 'warning', 'info', 'debug', 'report',
-    'start', 'stop', 'push', 'pop'
+    'report', 'start', 'stop', 'push', 'pop', 'line', 'direct'
 }
 
 logs.callbacks  = {
@@ -7486,89 +7873,112 @@ logs.callbacks  = {
     'report_output_log'
 }
 
+logs.tracers = {
+}
+
 logs.xml = logs.xml or { }
 logs.tex = logs.tex or { }
 
 logs.level = 0
 
-do
-    local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format
+local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format
 
-    if texlua then
-        write_nl = print
-        write    = io.write
-    end
+if texlua then
+    write_nl = print
+    write    = io.write
+end
 
-    function logs.xml.debug(category,str)
-        if logs.level > 3 then write_nl(format("<d category='%s'>%s</d>",category,str)) end
-    end
-    function logs.xml.info(category,str)
-        if logs.level > 2 then write_nl(format("<i category='%s'>%s</i>",category,str)) end
-    end
-    function logs.xml.warning(category,str)
-        if logs.level > 1 then write_nl(format("<w category='%s'>%s</w>",category,str)) end
-    end
-    function logs.xml.error(category,str)
-        if logs.level > 0 then write_nl(format("<e category='%s'>%s</e>",category,str)) end
-    end
-    function logs.xml.report(category,str)
-        write_nl(format("<r category='%s'>%s</r>",category,str))
-    end
+function logs.xml.report(category,fmt,...) -- new
+    write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...)))
+end
+function logs.xml.line(fmt,...) -- new
+    write_nl(format("<r>%s</r>",format(fmt,...)))
+end
 
-    function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end
-    function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end
-    function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end
-    function logs.xml.pop  () if logs.level > 0 then tw(" -->" ) end end
+function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end
+function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end
+function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end
+function logs.xml.pop  () if logs.level > 0 then tw(" -->" ) end end
 
-    function logs.tex.debug(category,str)
-        if logs.level > 3 then write_nl(format("debug >> %s: %s"  ,category,str)) end
-    end
-    function logs.tex.info(category,str)
-        if logs.level > 2 then write_nl(format("info >> %s: %s"   ,category,str)) end
-    end
-    function logs.tex.warning(category,str)
-        if logs.level > 1 then write_nl(format("warning >> %s: %s",category,str)) end
-    end
-    function logs.tex.error(category,str)
-        if logs.level > 0 then write_nl(format("error >> %s: %s"  ,category,str)) end
-    end
-    function logs.tex.report(category,str)
-        write_nl(format("report >> %s: %s"  ,category,str))
-    end
+function logs.tex.report(category,fmt,...) -- new
+ -- write_nl(format("%s | %s",category,format(fmt,...))) -- arg to format can be tex comment so .. .
+    write_nl(category .. " | " .. format(fmt,...))
+end
+function logs.tex.line(fmt,...) -- new
+    write_nl(format(fmt,...))
+end
 
-    function logs.set_level(level)
-        logs.level = logs.levels[level] or level
-    end
+function logs.set_level(level)
+    logs.level = logs.levels[level] or level
+end
 
-    function logs.set_method(method)
-        for _, v in pairs(logs.functions) do
-            logs[v] = logs[method][v] or function() end
-        end
-        if callback and input[method] then
-            for _, cb in pairs(logs.callbacks) do
-                callback.register(cb, input[method][cb])
-            end
+function logs.set_method(method)
+    for _, v in pairs(logs.functions) do
+        logs[v] = logs[method][v] or function() end
+    end
+    if callback and input[method] then
+        for _, cb in pairs(logs.callbacks) do
+            callback.register(cb, input[method][cb])
         end
     end
+end
 
-    function logs.xml.start_page_number()
-        write_nl(format("<p real='%s' page='%s' sub='%s'", tex.count[0], tex.count[1], tex.count[2]))
-    end
+function logs.xml.start_page_number()
+    write_nl(format("<p real='%s' page='%s' sub='%s'", tex.count[0], tex.count[1], tex.count[2]))
+end
+
+function logs.xml.stop_page_number()
+    write("/>")
+    write_nl("")
+end
+
+function logs.xml.report_output_pages(p,b)
+    write_nl(format("<v k='pages' v='%s'/>", p))
+    write_nl(format("<v k='bytes' v='%s'/>", b))
+    write_nl("")
+end
+
+function logs.xml.report_output_log()
+end
 
-    function logs.xml.stop_page_number()
-        write("/>")
-        write_nl("")
+function input.logger(...) -- assumes test for input.trace > n
+    if input.trace > 0 then
+        logs.report(...)
     end
+end
 
-    function logs.xml.report_output_pages(p,b)
-        write_nl(format("<v k='pages' v='%s'/>", p))
-        write_nl(format("<v k='bytes' v='%s'/>", b))
-        write_nl("")
+function input.report(fmt,...)
+    if input.verbose then
+        logs.report(input.banner or "report",format(fmt,...))
     end
+end
 
-    function logs.xml.report_output_log()
+function input.reportlines(str) -- todo: <lines></lines>
+    for line in str:gmatch("(.-)[\n\r]") do
+        logs.report(input.banner or "report",line)
     end
+end
 
+input.moreinfo = [[
+more information about ConTeXt and the tools that come with it can be found at:
+
+maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
+webpage  : http://www.pragma-ade.nl / http://tex.aanhet.net
+wiki     : http://contextgarden.net
+]]
+
+function input.help(banner,message)
+    if not input.verbose then
+        input.verbose = true
+    --  input.report(banner,"\n")
+    end
+    input.report(banner,"\n")
+    input.report("")
+    input.reportlines(message)
+    if input.moreinfo and input.moreinfo ~= "" then
+        input.report("")
+        input.reportlines(input.moreinfo)
+    end
 end
 
 logs.set_level('error')
@@ -7761,7 +8171,7 @@ end
 
 -- end library merge
 
-own = { }
+own = { } -- not local
 
 own.libs = { -- todo: check which ones are really needed
     'l-string.lua',
@@ -7775,12 +8185,14 @@ own.libs = { -- todo: check which ones a
     'l-file.lua',
     'l-dir.lua',
     'l-boolean.lua',
+    'l-math.lua',
     'l-xml.lua',
 --  'l-unicode.lua',
     'l-utils.lua',
 --  'l-tex.lua',
     'luat-lib.lua',
     'luat-inp.lua',
+    'luat-log.lua',
 --  'luat-zip.lua',
 --  'luat-tex.lua',
 --  'luat-kps.lua',
@@ -7810,7 +8222,7 @@ table.insert(own.list,own.path.."/../../
 table.insert(own.list,own.path.."/mtx")
 table.insert(own.list,own.path.."/../sources")
 
-function locate_libs()
+local function locate_libs()
     for _, lib in pairs(own.libs) do
         for _, pth in pairs(own.list) do
             local filename = string.gsub(pth .. "/" .. lib,"\\","/")
@@ -7837,37 +8249,14 @@ if not input then
     os.exit()
 end
 
-instance            = input.reset()
-input.verbose       = environment.argument("verbose") or false
-input.banner        = 'MtxRun | '
+input.instance      = input.reset()
+input.banner        = 'MtxRun'
 utils.report        = input.report
 
-instance.engine   = environment.argument("engine")   or 'luatex'
-instance.progname = environment.argument("progname") or 'context'
-instance.lsrmode  = environment.argument("lsr")      or false
+local instance = input.instance
 
--- use os.env or environment when available
 
---~ function input.check_environment(tree)
---~     input.report('')
---~     os.setenv('TMP', os.getenv('TMP') or os.getenv('TEMP') or os.getenv('TMPDIR') or os.getenv('HOME'))
---~     if os.platform == 'linux' then
---~         os.setenv('TEXOS', os.getenv('TEXOS') or 'texmf-linux')
---~     elseif os.platform == 'windows' then
---~         os.setenv('TEXOS', os.getenv('TEXOS') or 'texmf-windows')
---~     elseif os.platform == 'macosx'  then
---~         os.setenv('TEXOS', os.getenv('TEXOS') or 'texmf-macosx')
---~     end
---~     os.setenv('TEXOS',   string.gsub(string.gsub(os.getenv('TEXOS'),"^[\\\/]*", ''),"[\\\/]*$", ''))
---~     os.setenv('TEXPATH', string.gsub(tree,"\/+$",''))
---~     os.setenv('TEXMFOS', os.getenv('TEXPATH') .. "/" .. os.getenv('TEXOS'))
---~     input.report('')
---~     input.report("preset : TEXPATH => " .. os.getenv('TEXPATH'))
---~     input.report("preset : TEXOS   => " .. os.getenv('TEXOS'))
---~     input.report("preset : TEXMFOS => " .. os.getenv('TEXMFOS'))
---~     input.report("preset : TMP     => " .. os.getenv('TMP'))
---~     input.report('')
---~ end
+-- use os.env or environment when available
 
 function input.check_environment(tree)
     input.report('')
@@ -7876,10 +8265,10 @@ function input.check_environment(tree)
     os.setenv('TEXPATH', (tree or "tex"):gsub("\/+$",''))
     os.setenv('TEXMFOS', os.getenv('TEXPATH') .. "/" .. os.getenv('TEXOS'))
     input.report('')
-    input.report("preset : TEXPATH => " .. os.getenv('TEXPATH'))
-    input.report("preset : TEXOS   => " .. os.getenv('TEXOS'))
-    input.report("preset : TEXMFOS => " .. os.getenv('TEXMFOS'))
-    input.report("preset : TMP     => " .. os.getenv('TMP'))
+    input.report("preset : TEXPATH => %s", os.getenv('TEXPATH'))
+    input.report("preset : TEXOS   => %s", os.getenv('TEXOS'))
+    input.report("preset : TEXMFOS => %s", os.getenv('TEXMFOS'))
+    input.report("preset : TMP     => %s", os.getenv('TMP'))
     input.report('')
 end
 
@@ -7968,9 +8357,9 @@ function file.needs_updating(oldname,new
     end
 end
 
-function file.mdchecksum(name)
+function file.checksum(name)
     if md5 then
-        local data = io.loadall(name)
+        local data = io.loaddata(name)
         if data then
             return md5.HEXsum(data)
         end
@@ -7979,24 +8368,18 @@ function file.mdchecksum(name)
 end
 
 function file.loadchecksum(name)
-    if md then
-        local data = io.loadall(name .. ".md5")
-        if data then
-            return string.gsub(md5.HEXsum(data),"%s$","")
-        end
+    if md5 then
+        local data = io.loaddata(name .. ".md5")
+        return data and data:gsub("%s","")
     end
     return nil
 end
 
 function file.savechecksum(name, checksum)
-    if not checksum then checksum = file.mdchecksum(name) end
+    if not checksum then checksum = file.checksum(name) end
     if checksum then
-        local f = io.open(name .. ".md5","w")
-        if f then
-            f:write(checksum)
-            f:close()
-            return checksum
-        end
+        io.savedata(name .. ".md5",checksum)
+        return checksum
     end
     return nil
 end
@@ -8014,6 +8397,8 @@ function os.currentplatform(name, defaul
             local architecture = os.arch()
             if architecture:find("x86_64") then
                 return "linux-64"
+            elseif architecture:find("ppc") then
+                return "linux-ppc"
             else
                 return "linux"
             end
@@ -8055,7 +8440,7 @@ input.runners.registered = {
     mptopdf      = { 'mptopdf.pl',      true  },
     pstopdf      = { 'pstopdf.rb',      true  },
 
-    examplex     = { 'examplex.rb',     false },
+--  examplex     = { 'examplex.rb',     false },
     concheck     = { 'concheck.rb',     false },
 
     runtools     = { 'runtools.rb',     true  },
@@ -8076,8 +8461,8 @@ input.runners.registered = {
 if not messages then messages = { } end
 
 messages.help = [[
---script              run an mtx script
---execute             run a script or program
+--script              run an mtx script (--noquotes)
+--execute             run a script or program (--noquotes)
 --resolve             resolve prefixed arguments
 --ctxlua              run internally (using preloaded libs)
 --locate              locate given filename
@@ -8100,46 +8485,46 @@ messages.help = [[
 --progname=str        format or backend
 
 --edit                launch editor with found file
---launch (--all)      launch files (assume os support)
+--launch (--all)      launch files like manuals, assumes os support
 
 --intern              run script using built in libraries
 ]]
 
-function input.runners.my_prepare_a(instance)
-    input.resetconfig(instance)
-    input.identify_cnf(instance)
-    input.load_lua(instance)
-    input.expand_variables(instance)
-    input.load_cnf(instance)
-    input.expand_variables(instance)
-end
-
-function input.runners.my_prepare_b(instance)
-    input.runners.my_prepare_a(instance)
-    input.load_hash(instance)
-    input.automount(instance)
+function input.runners.my_prepare_a()
+    input.resetconfig()
+    input.identify_cnf()
+    input.load_lua()
+    input.expand_variables()
+    input.load_cnf()
+    input.expand_variables()
+end
+
+function input.runners.my_prepare_b()
+    input.runners.my_prepare_a()
+    input.load_hash()
+    input.automount()
 end
 
-function input.runners.prepare(instance)
+function input.runners.prepare()
     local checkname = environment.argument("ifchanged")
     if checkname and checkname ~= "" then
         local oldchecksum = file.loadchecksum(checkname)
         local newchecksum = file.checksum(checkname)
         if oldchecksum == newchecksum then
-            report("file '" .. checkname .. "' is unchanged")
+            input.report("file '%s' is unchanged",checkname)
             return "skip"
         else
-            report("file '" .. checkname .. "' is changed, processing started")
+            input.report("file '%s' is changed, processing started",checkname)
         end
         file.savechecksum(checkname)
     end
     local oldname, newname = string.split(environment.argument("iftouched") or "", ",")
     if oldname and newname and oldname ~= "" and newname ~= "" then
         if not file.needs_updating(oldname,newname) then
-            report("file '" .. oldname .. "' and '" .. newname .. "'have same age")
+            input.report("file '%s' and '%s' have same age",oldname,newname)
             return "skip"
         else
-            report("file '" .. newname .. "' is older than '" .. oldname .. "'")
+            input.report("file '%s' is older than '%s'",oldname,newname)
         end
     end
     local tree = environment.argument('tree') or ""
@@ -8158,15 +8543,17 @@ function input.runners.prepare(instance)
     end
     local runpath = environment.argument("path")
     if runpath and not dir.chdir(runpath) then
-        input.report("unable to change to path '" .. runpath .. "'")
+        input.report("unable to change to path '%s'",runpath)
         return "error"
     end
     return "run"
 end
 
-function input.runners.execute_script(instance,fullname,internal)
+function input.runners.execute_script(fullname,internal)
+    local instance = input.instance
+    local noquote = environment.argument("noquotes")
     if fullname and fullname ~= "" then
-        local state = input.runners.prepare(instance)
+        local state = input.runners.prepare()
         if state == 'error' then
             return false
         elseif state == 'skip' then
@@ -8190,16 +8577,16 @@ function input.runners.execute_script(in
                 if suffix == "" then
                     -- loop over known suffixes
                     for _,s in pairs(input.runners.suffixes) do
-                        result = input.find_file(instance, name .. "." .. s, 'texmfscripts')
+                        result = input.find_file(name .. "." .. s, 'texmfscripts')
                         if result ~= "" then
                             break
                         end
                     end
                 elseif input.runners.applications[suffix] then
-                    result = input.find_file(instance, name, 'texmfscripts')
+                    result = input.find_file(name, 'texmfscripts')
                 else
                     -- maybe look on path
-                    result = input.find_file(instance, name, 'other text files')
+                    result = input.find_file(name, 'other text files')
                 end
             end
             if result and result ~= "" then
@@ -8213,9 +8600,9 @@ function input.runners.execute_script(in
                         result = binary .. " " .. result
                     end
                     local before, after = environment.split_arguments(fullname)
-                    local command = result .. " " .. environment.reconstruct_commandline(after)
+                    local command = result .. " " .. environment.reconstruct_commandline(after,noquote)
                     input.report("")
-                    input.report("executing: " .. command)
+                    input.report("executing: %s",command)
                     input.report("\n \n")
                     io.flush()
                     local code = os.exec(command) -- maybe spawn
@@ -8227,9 +8614,10 @@ function input.runners.execute_script(in
     return false
 end
 
-function input.runners.execute_program(instance,fullname)
+function input.runners.execute_program(fullname)
+    local noquote = environment.argument("noquotes")
     if fullname and fullname ~= "" then
-        local state = input.runners.prepare(instance)
+        local state = input.runners.prepare()
         if state == 'error' then
             return false
         elseif state == 'skip' then
@@ -8238,9 +8626,9 @@ function input.runners.execute_program(i
             local before, after = environment.split_arguments(fullname)
             environment.initialize_arguments(after)
             fullname = fullname:gsub("^bin:","")
-            local command = fullname .. " " .. environment.reconstruct_commandline(after)
+            local command = fullname .. " " .. (environment.reconstruct_commandline(after or "",noquote) or "")
             input.report("")
-            input.report("executing: " .. command)
+            input.report("executing: %s",command)
             input.report("\n \n")
             io.flush()
             local code = os.exec(command) -- (fullname,unpack(after)) does not work / maybe spawn
@@ -8250,12 +8638,12 @@ function input.runners.execute_program(i
     return false
 end
 
-function input.runners.handle_stubs(instance,create)
+function input.runners.handle_stubs(create)
     local stubpath = environment.argument('stubpath') or '.' -- 'auto' no longer supported
     local windows  = environment.argument('windows') or environment.argument('mswin') or false
     local unix     = environment.argument('unix') or environment.argument('linux') or false
     if not windows and not unix then
-        if environment.platform == "unix" then
+        if os.platform == "unix" then
             unix = true
         else
             windows = true
@@ -8270,41 +8658,41 @@ function input.runners.handle_stubs(inst
                 local command = "luatex --luaonly mtxrun.lua " .. name
                 if windows then
                     io.savedata(base..".bat", {"@echo off", command.." %*"}, "\013\010")
-                        input.report("windows stub for '" .. base .. "' created")
+                        input.report("windows stub for '%s' created",base)
                 end
                 if unix then
                     io.savedata(base, {"#!/bin/sh", command..' "$@"'}, "\010")
-                    input.report("unix stub for '" .. base .. "' created")
+                    input.report("unix stub for '%s' created",base)
                 end
             else
                 if windows and (os.remove(base..'.bat') or os.remove(base..'.cmd')) then
-                    input.report("windows stub for '" .. base .. "' removed")
+                    input.report("windows stub for '%s' removed", base)
                 end
                 if unix and (os.remove(base) or os.remove(base..'.sh')) then
-                    input.report("unix stub for '" .. base .. "' removed")
+                    input.report("unix stub for '%s' removed",base)
                 end
             end
         end
     end
 end
 
-function input.runners.resolve_string(instance,filename)
+function input.runners.resolve_string(filename)
     if filename and filename ~= "" then
-        input.runners.report_location(instance,input.resolve(instance,filename))
+        input.runners.report_location(input.resolve(filename))
     end
 end
 
-function input.runners.locate_file(instance,filename)
+function input.runners.locate_file(filename)
     if filename and filename ~= "" then
-        input.runners.report_location(instance,input.find_given_file(instance,filename))
+        input.runners.report_location(input.find_given_file(filename))
     end
 end
 
-function input.runners.locate_platform(instance)
-    input.runners.report_location(instance,os.currentplatform())
+function input.runners.locate_platform()
+    input.runners.report_location(os.currentplatform())
 end
 
-function input.runners.report_location(instance,result)
+function input.runners.report_location(result)
     if input.verbose then
         input.report("")
         if result and result ~= "" then
@@ -8317,11 +8705,17 @@ function input.runners.report_location(i
     end
 end
 
-function input.runners.edit_script(instance,filename)
-    local editor = os.getenv("MTXRUN_EDITOR") or os.getenv("TEXMFSTART_EDITOR") or os.getenv("EDITOR") or 'scite'
-    local rest = input.resolve(instance,filename)
+function input.runners.edit_script(filename) -- we assume that vim is present on most systems
+    local editor = os.getenv("MTXRUN_EDITOR") or os.getenv("TEXMFSTART_EDITOR") or os.getenv("EDITOR") or 'vim'
+    local rest = input.resolve(filename)
     if rest ~= "" then
-        os.launch(editor .. " " .. rest)
+        local command = editor .. " " .. rest
+        if input.verbose then
+            input.report("")
+            input.report("starting editor: %s",command)
+            input.report("\n \n")
+        end
+        os.launch(command)
     end
 end
 
@@ -8364,7 +8758,8 @@ function input.launch(str)
     os.launch(str)
 end
 
-function input.runners.launch_file(instance,filename)
+function input.runners.launch_file(filename)
+    local instance = input.instance
     instance.allresults = true
     input.verbose = true
     local pattern = environment.arguments["pattern"]
@@ -8374,25 +8769,30 @@ function input.runners.launch_file(insta
     if not pattern or pattern == "" then
         input.report("provide name or --pattern=")
     else
-        local t = input.find_files(instance,pattern)
-    --  local t = input.aux.find_file(instance,"*/" .. pattern,true)
+        local t = input.find_files(pattern)
+        if not t or #t == 0 then
+            t = input.aux.find_file("*/" .. pattern,true)
+        end
+        if not t or #t == 0 then
+            t = input.aux.find_file("*/" .. pattern .. "*",true)
+        end
         if t and #t > 0 then
             if environment.arguments["all"] then
                 for _, v in pairs(t) do
-                    input.report("launching", v)
+                    input.report("launching %s", v)
                     input.launch(v)
                 end
             else
-                input.report("launching", t[1])
+                input.report("launching %s", t[1])
                 input.launch(t[1])
             end
         else
-            input.report("no match for", pattern)
+            input.report("no match for %s", pattern)
         end
     end
 end
 
-function input.runners.execute_ctx_script(instance,filename,arguments)
+function input.runners.find_mtx_script(filename)
     local function found(name)
         local path = file.dirname(name)
         if path and path ~= "" then
@@ -8402,30 +8802,48 @@ function input.runners.execute_ctx_scrip
             return io.exists(fullname) and fullname
         end
     end
-    local suffix = ""
-    if not filename:find("%.lua$") then suffix = ".lua" end
-    local fullname = filename
-    -- just <filename>
-    fullname = filename .. suffix
-    fullname = input.find_file(instance,fullname)
-    -- mtx-<filename>
-    if not fullname or fullname == "" then
-        fullname = "mtx-" .. filename .. suffix
-        fullname = found(fullname) or input.find_file(instance,fullname)
-    end
-    -- mtx-<filename>s
-    if not fullname or fullname == "" then
-        fullname = "mtx-" .. filename .. "s" .. suffix
-        fullname = found(fullname) or input.find_file(instance,fullname)
-    end
-    -- mtx-<filename minus trailing s>
-    if not fullname or fullname == "" then
-        fullname = "mtx-" .. filename:gsub("s$","") .. suffix
-        fullname = found(fullname) or input.find_file(instance,fullname)
+    filename = file.addsuffix(filename,"lua")
+    local basename = file.stripsuffix(file.basename(filename))
+    local suffix = file.extname(filename)
+    -- qualified path, raw name
+    local fullname = input.aux.qualified_path(filename) and io.exists(filename) and filename
+    if fullname and fullname ~= "" then
+        return fullname
+    end
+    -- current path, raw name
+    fullname = "./" .. filename
+    fullname = io.exists(fullname) and fullname
+    if fullname and fullname ~= "" then
+        return fullname
+    end
+    -- context namespace, mtx-<filename>
+    fullname = "mtx-" .. filename
+    fullname = found(fullname) or input.find_file(fullname)
+    if fullname and fullname ~= "" then
+        return fullname
+    end
+    -- context namespace, mtx-<filename>s
+    fullname = "mtx-" .. basename .. "s" .. "." .. suffix
+    fullname = found(fullname) or input.find_file(fullname)
+    if fullname and fullname ~= "" then
+        return fullname
+    end
+    -- context namespace, mtx-<filename minus trailing s>
+    fullname = "mtx-" .. basename:gsub("s$","") .. "." .. suffix
+    fullname = found(fullname) or input.find_file(fullname)
+    if fullname and fullname ~= "" then
+        return fullname
     end
+    -- context namespace, just <filename>
+    fullname = input.find_file(fullname)
+    return fullname
+end
+
+function input.runners.execute_ctx_script(filename,arguments)
+    local fullname = input.runners.find_mtx_script(filename)
     -- that should do it
     if fullname and fullname ~= "" then
-        local state = input.runners.prepare(instance)
+        local state = input.runners.prepare()
         if state == 'error' then
             return false
         elseif state == 'skip' then
@@ -8442,7 +8860,7 @@ function input.runners.execute_ctx_scrip
             end
             filename = environment.files[1]
             if input.verbose then
-                input.report("using script: " .. fullname)
+                input.report("using script: %s\n",fullname)
             end
             dofile(fullname)
             local savename = environment.arguments['save']
@@ -8455,20 +8873,19 @@ function input.runners.execute_ctx_scrip
         end
     else
         input.verbose = true
-        input.report("unknown script: " .. filename)
+        filename = file.addsuffix(filename,"lua")
+        if filename == "" then
+            input.report("unknown script, no name given")
+        elseif input.aux.qualified_path(filename) then
+            input.report("unknown script '%s'",filename)
+        else
+            input.report("unknown script '%s' or 'mtx-%s'",filename,filename)
+        end
         return false
     end
 end
 
-input.report(banner,"\n")
-
-function input.help(banner,message)
-    if not input.verbose then
-        input.verbose = true
-        input.report(banner,"\n")
-    end
-    input.reportlines(message)
-end
+input.report("%s\n",banner)
 
 -- this is a bit dirty ... first we store the first filename and next we
 -- split the arguments so that we only see the ones meant for this script
@@ -8478,12 +8895,14 @@ local filename = environment.files[1] or
 local ok      = true
 
 local before, after = environment.split_arguments(filename)
+environment.initialize_arguments(before)
 
-input.runners.my_prepare_b(instance)
-before = input.resolve(instance,before) -- experimental here
-after = input.resolve(instance,after) -- experimental here
+instance.engine   = environment.argument("engine")   or 'luatex'
+instance.progname = environment.argument("progname") or 'context'
+instance.lsrmode  = environment.argument("lsr")      or false
+input.verbose     = environment.argument("verbose")  or false
 
-environment.initialize_arguments(before)
+input.runners.my_prepare_b()
 
 if environment.argument("selfmerge") then
     -- embed used libraries
@@ -8493,60 +8912,52 @@ elseif environment.argument("selfclean")
     utils.merger.selfclean(own.name)
 elseif environment.argument("selfupdate") then
     input.verbose = true
-    input.update_script(instance,own.name,"mtxrun")
+    input.update_script(own.name,"mtxrun")
 elseif environment.argument("ctxlua") or environment.argument("internal") then
     -- run a script by loading it (using libs)
-    ok = input.runners.execute_script(instance,filename,true)
+    ok = input.runners.execute_script(filename,true)
 elseif environment.argument("script") then
     -- run a script by loading it (using libs), pass args
-    ok = input.runners.execute_ctx_script(instance,filename,after)
+    ok = input.runners.execute_ctx_script(filename,after)
 elseif environment.argument("execute") then
     -- execute script
-    ok = input.runners.execute_script(instance,filename)
+    ok = input.runners.execute_script(filename)
 elseif environment.argument("direct") then
     -- equals bin:
-    ok = input.runners.execute_program(instance,filename)
+    ok = input.runners.execute_program(filename)
 elseif environment.argument("edit") then
     -- edit file
-    input.runners.edit_script(instance,filename)
+    input.runners.edit_script(filename)
 elseif environment.argument("launch") then
-    input.runners.launch_file(instance,filename)
+    input.runners.launch_file(filename)
 elseif environment.argument("make") then
     -- make stubs
-    input.runners.handle_stubs(instance,true)
+    input.runners.handle_stubs(true)
 elseif environment.argument("remove") then
     -- remove stub
-    input.runners.handle_stubs(instance,false)
+    input.runners.handle_stubs(false)
 elseif environment.argument("resolve") then
     -- resolve string
-    input.runners.resolve_string(instance,filename)
+    input.runners.resolve_string(filename)
 elseif environment.argument("locate") then
     -- locate file
-    input.runners.locate_file(instance,filename)
+    input.runners.locate_file(filename)
 elseif environment.argument("platform")then
     -- locate platform
-    input.runners.locate_platform(instance)
+    input.runners.locate_platform()
 elseif environment.argument("help") or filename=='help' or filename == "" then
     input.help(banner,messages.help)
     -- execute script
-    if filename:find("^bin:") then
-        ok = input.runners.execute_program(instance,filename)
-    else
-        ok = input.runners.execute_script(instance,filename)
-    end
+elseif filename:find("^bin:") then
+    ok = input.runners.execute_program(filename)
+else
+    ok = input.runners.execute_script(filename)
 end
 
---~ if input.verbose then
---~     input.report("")
---~     input.report(string.format("runtime: %0.3f seconds",os.runtime()))
---~ end
-
---~ if ok then
---~     input.report("exit code: 0") os.exit(0)
---~ else
---~     input.report("exit code: 1") os.exit(1)
---~ end
-
-if environment.platform == "unix" then
+if os.platform == "unix" then
     io.write("\n")
 end
+
+if ok == false then ok = 1 elseif ok == true then ok = 0 end
+
+os.exit(ok)
--- texmf-dist/tex/context/base/luat-inp.lua
+++ texmf-dist/tex/context/base/luat-inp.lua	2008-10-30 14:05:43.990092457 +0100
@@ -1,18 +1,21 @@
--- filename : luat-inp.lua
--- comment  : companion to luat-lib.tex
--- author   : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license  : see context related readme files
-
--- This lib is multi-purpose and can be loaded again later on so that
--- additional functionality becomes available. We will split this
--- module in components when we're done with prototyping.
+if not modules then modules = { } end modules ['luat-inp'] = {
+    version   = 1.001,
+    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+    copyright = "PRAGMA ADE / ConTeXt Development Team",
+    license   = "see context related readme files",
+    comment   = "companion to luat-lib.tex",
+}
 
 -- TODO: os.getenv -> os.env[]
 -- TODO: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller)
 -- TODO: check escaping in find etc, too much, too slow
 
--- This is the first code I wrote for LuaTeX, so it needs some cleanup.
+-- This lib is multi-purpose and can be loaded again later on so that
+-- additional functionality becomes available. We will split this
+-- module in components once we're done with prototyping. This is the
+-- first code I wrote for LuaTeX, so it needs some cleanup. Before changing
+-- something in this module one can best check with Taco or Hans first; there
+-- is some nasty trickery going on that relates to traditional kpse support.
 
 -- To be considered: hash key lowercase, first entry in table filename
 -- (any case), rest paths (so no need for optimization). Or maybe a
@@ -22,12 +25,6 @@
 
 -- Beware, loading and saving is overloaded in luat-tmp!
 
-if not versions    then versions    = { } end versions['luat-inp'] = 1.001
-if not environment then environment = { } end
-if not file        then file        = { } end
-
-if environment.aleph_mode == nil then environment.aleph_mode = true end -- temp hack
-
 if not input            then input            = { } end
 if not input.suffixes   then input.suffixes   = { } end
 if not input.formats    then input.formats    = { } end
@@ -40,7 +37,7 @@ if not input.hashers    then input.hashe
 if not input.generators then input.generators = { } end  -- generate databases
 if not input.filters    then input.filters    = { } end  -- conversion filters
 
-local format = string.format
+local format, concat, sortedkeys = string.format, table.concat, table.sortedkeys
 
 input.locators.notfound   = { nil }
 input.hashers.notfound    = { nil }
@@ -53,8 +50,16 @@ input.debug        = false
 input.cnfname      = 'texmf.cnf'
 input.luaname      = 'texmfcnf.lua'
 input.lsrname      = 'ls-R'
-input.luasuffix    = '.tma'
-input.lucsuffix    = '.tmc'
+input.homedir      = os.env[os.platform == "windows" and 'USERPROFILE'] or os.env['HOME'] or '~'
+
+--~ input.luasuffix    = 'tma'
+--~ input.lucsuffix    = 'tmc'
+
+-- for the moment we have .local but this will disappear
+input.cnfdefault   = '{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
+
+-- chances are low that the cnf file is in the bin path
+input.cnfdefault   = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
 
 -- we use a cleaned up list / format=any is a wildcard, as is *name
 
@@ -90,7 +95,8 @@ input.suffixes['lua'] = { 'lua', 'luc', 
 -- FONTFEATURES  = .;$TEXMF/fonts/fea//
 -- FONTCIDMAPS   = .;$TEXMF/fonts/cid//
 
-function input.checkconfigdata(instance) -- not yet ok, no time for debugging now
+function input.checkconfigdata() -- not yet ok, no time for debugging now
+    local instance = input.instance
     local function fix(varname,default)
         local proname = varname .. "." .. instance.progname or "crap"
         local p = instance.environment[proname]
@@ -99,7 +105,15 @@ function input.checkconfigdata(instance)
             instance.variables[varname] = default -- or environment?
         end
     end
-    fix("LUAINPUTS"   , ".;$TEXINPUTS;$TEXMFSCRIPTS")
+    local name = os.name
+    if name == "windows" then
+        fix("OSFONTDIR", "c:/windows/fonts//")
+    elseif name == "macosx" then
+        fix("OSFONTDIR", "$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//")
+    else
+        -- bad luck
+    end
+    fix("LUAINPUTS"   , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm
     fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
     fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
 end
@@ -126,14 +140,20 @@ input.formats     ['sfd']               
 input.suffixes    ['sfd']                      = { 'sfd' }
 input.alternatives['subfont definition files'] = 'sfd'
 
-function input.reset()
+-- In practice we will work within one tds tree, but i want to keep
+-- the option open to build tools that look at multiple trees, which is
+-- why we keep the tree specific data in a table. We used to pass the
+-- instance but for practical pusposes we now avoid this and use a
+-- instance variable.
+
+function input.newinstance()
 
     local instance = { }
 
     instance.rootpath        = ''
     instance.treepath        = ''
-    instance.progname        = environment.progname or 'context'
-    instance.engine          = environment.engine   or 'luatex'
+    instance.progname        = 'context'
+    instance.engine          = 'luatex'
     instance.format          = ''
     instance.environment     = { }
     instance.variables       = { }
@@ -157,6 +177,7 @@ function input.reset()
     instance.cachepath       = nil
     instance.loaderror       = false
     instance.smallcache      = false
+    instance.sortdata        = false
     instance.savelists       = true
     instance.cleanuppaths    = true
     instance.allresults      = false
@@ -172,23 +193,13 @@ function input.reset()
     instance.fakepaths       = { }
     instance.lsrmode         = false
 
-    if os.env then
-        -- store once, freeze and faster
-        for k,v in pairs(os.env) do
-            instance.environment[k] = input.bare_variable(v)
-        end
-    else
-        -- we will access os.env frequently
-        for k,v in pairs({'HOME','TEXMF','TEXMFCNF'}) do
-            local e = os.getenv(v)
-            if e then
-            --  input.report("setting",v,"to",input.bare_variable(e))
-                instance.environment[v] = input.bare_variable(e)
-            end
-        end
+    -- store once, freeze and faster (once reset we can best use instance.environment)
+
+    for k,v in pairs(os.env) do
+        instance.environment[k] = input.bare_variable(v)
     end
 
-    -- cross referencing
+    -- cross referencing, delayed because we can add suffixes
 
     for k, v in pairs(input.suffixes) do
         for _, vv in pairs(v) do
@@ -202,68 +213,42 @@ function input.reset()
 
 end
 
-function input.reset_hashes(instance)
-    instance.lists = { }
-    instance.found = { }
-end
-
-function input.bare_variable(str) -- assumes str is a string
- -- return string.gsub(string.gsub(string.gsub(str,"%s+$",""),'^"(.+)"$',"%1"),"^'(.+)'$","%1")
-    return (str:gsub("\s*([\"\']?)(.+)%1\s*", "%2"))
-end
+input.instance = input.instance or nil
 
-if texio then
-    input.log = texio.write_nl
-else
-    input.log = print
+function input.reset()
+    input.instance = input.newinstance()
+    return input.instance
 end
 
-function input.simple_logger(kind, name)
-    if name and name ~= "" then
-        if input.banner then
-            input.log(input.banner..kind..": "..name)
-        else
-            input.log("<<"..kind..": "..name..">>")
-        end
-    else
-        if input.banner then
-            input.log(input.banner..kind..": no name")
-        else
-            input.log("<<"..kind..": no name>>")
-        end
-    end
+function input.reset_hashes()
+    input.instance.lists = { }
+    input.instance.found = { }
 end
 
-function input.dummy_logger()
+function input.bare_variable(str) -- assumes str is a string
+ -- return string.gsub(string.gsub(string.gsub(str,"%s+$",""),'^"(.+)"$',"%1"),"^'(.+)'$","%1")
+    return (str:gsub("\s*([\"\']?)(.+)%1\s*", "%2"))
 end
 
 function input.settrace(n)
     input.trace = tonumber(n or 0)
     if input.trace > 0 then
-        input.logger = input.simple_logger
         input.verbose = true
-    else
-        input.logger = function() end
     end
 end
 
-function input.report(...) -- inefficient
+input.log  = (texio and texio.write_nl) or print
+
+function input.report(...)
     if input.verbose then
-        if input.banner then
-            input.log(input.banner .. table.concat({...},' '))
-        elseif input.logmode() == 'xml' then
-            input.log("<t>"..table.concat({...},' ').."</t>")
-        else
-            input.log("<<"..table.concat({...},' ')..">>")
-        end
+        input.log("<<"..format(...)..">>")
     end
 end
 
-function input.reportlines(str)
-    if type(str) == "string" then
-        str = str:split("\n")
+function input.report(...)
+    if input.trace > 0 then -- extra test
+        input.log("<<"..format(...)..">>")
     end
-    for _,v in pairs(str) do input.report(v) end
 end
 
 input.settrace(tonumber(os.getenv("MTX.INPUT.TRACE") or os.getenv("MTX_INPUT_TRACE") or input.trace or 0))
@@ -274,27 +259,44 @@ input.settrace(tonumber(os.getenv("MTX.I
 do
     local clock = os.gettimeofday or os.clock
 
+    function input.hastimer(instance)
+        return instance and instance.starttime
+    end
+
     function input.starttiming(instance)
         if instance then
-            instance.starttime = clock()
-            if not instance.loadtime then
-                instance.loadtime = 0
+            local it = instance.timing
+            if not it then
+                it = 0
+            end
+            if it == 0 then
+                instance.starttime = clock()
+                if not instance.loadtime then
+                    instance.loadtime = 0
+                end
             end
+            instance.timing = it + 1
         end
     end
 
     function input.stoptiming(instance, report)
         if instance then
-            local starttime = instance.starttime
-            if starttime then
-                local stoptime = clock()
-                local loadtime = stoptime - starttime
-                instance.stoptime = stoptime
-                instance.loadtime = instance.loadtime + loadtime
-                if report then
-                    input.report('load time', format("%0.3f",loadtime))
+            local it = instance.timing
+            if it > 1 then
+                instance.timing = it - 1
+            else
+                local starttime = instance.starttime
+                if starttime then
+                    local stoptime = clock()
+                    local loadtime = stoptime - starttime
+                    instance.stoptime = stoptime
+                    instance.loadtime = instance.loadtime + loadtime
+                    if report then
+                        input.report("load time %0.3f",loadtime)
+                    end
+                    instance.timing = 0
+                    return loadtime
                 end
-                return loadtime
             end
         end
         return 0
@@ -308,18 +310,18 @@ end
 
 function input.report_loadtime(instance)
     if instance then
-        input.report('total load time', input.elapsedtime(instance))
+        input.report('total load time %s', input.elapsedtime(instance))
     end
 end
 
 input.loadtime = input.elapsedtime
 
-function input.env(instance,key)
-    return instance.environment[key] or input.osenv(instance,key)
+function input.env(key)
+    return input.instance.environment[key] or input.osenv(key)
 end
 
-function input.osenv(instance,key)
-    local ie = instance.environment
+function input.osenv(key)
+    local ie = input.instance.environment
     local value = ie[key]
     if value == nil then
      -- local e = os.getenv(key)
@@ -337,81 +339,106 @@ end
 -- we follow a rather traditional approach:
 --
 -- (1) texmf.cnf given in TEXMFCNF
--- (2) texmf.cnf searched in TEXMF/web2c
+-- (2) texmf.cnf searched in default variable
 --
--- for the moment we don't expect a configuration file in a zip
+-- also we now follow the stupid route: if not set then just assume *one*
+-- cnf file under texmf (i.e. distribution)
 
-function input.identify_cnf(instance)
-    -- we no longer support treepath and rootpath (was handy for testing);
-    -- also we now follow the stupid route: if not set then just assume *one*
-    -- cnf file under texmf (i.e. distribution)
-    if #instance.cnffiles == 0 then
-        if input.env(instance,'TEXMFCNF') == "" then
-            local ownpath = environment.ownpath() or "."
-            if ownpath then
-                -- beware, this is tricky on my own system because at that location I do have
-                -- the raw tree that ends up in the zip; i.e. I cannot test this kind of mess
-                local function locate(filename,list)
-                    local ownroot = input.normalize_name(file.join(ownpath,"../.."))
-                    if not lfs.isdir(file.join(ownroot,"texmf")) then
-                        ownroot = input.normalize_name(file.join(ownpath,".."))
-                        if not lfs.isdir(file.join(ownroot,"texmf")) then
-                            input.verbose = true
-                            input.report("error", "unable to identify cnf file")
-                            return
+input.ownpath     = input.ownpath or nil
+input.ownbin      = input.ownbin  or arg[-2] or arg[-1] or arg[0] or "luatex"
+input.autoselfdir = true -- false may be handy for debugging
+
+function input.getownpath()
+    if not input.ownpath then
+        if input.autoselfdir and os.selfdir then
+            input.ownpath = os.selfdir
+        else
+            local binary = input.ownbin
+            if os.platform == "windows" then
+                binary = file.replacesuffix(binary,"exe")
+            end
+            for p in string.gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
+                local b = file.join(p,binary)
+                if lfs.isfile(b) then
+                    -- we assume that after changing to the path the currentdir function
+                    -- resolves to the real location and use this side effect here; this
+                    -- trick is needed because on the mac installations use symlinks in the
+                    -- path instead of real locations
+                    local olddir = lfs.currentdir()
+                    if lfs.chdir(p) then
+                        local pp = lfs.currentdir()
+                        if input.verbose and p ~= pp then
+                            input.report("following symlink %s to %s",p,pp)
                         end
-                    end
-                    local texmfcnf = file.join(ownroot,"texmf-local/web2c",filename) -- for minimals and myself
-                    if not lfs.isfile(texmfcnf) then
-                        texmfcnf = file.join(ownroot,"texmf/web2c",filename)
-                        if not lfs.isfile(texmfcnf) then
-                            input.verbose = true
-                            input.report("error", "unable to locate",filename)
-                            return
+                        input.ownpath = pp
+                        lfs.chdir(olddir)
+                    else
+                        if input.verbose then
+                            input.report("unable to check path %s",p)
                         end
+                        input.ownpath =  p
                     end
-                    table.insert(list,texmfcnf)
-                    local ie = instance.environment
-                    if not ie['SELFAUTOPARENT'] then ie['SELFAUTOPARENT'] = ownroot end
-                    if not ie['TEXMFCNF']       then ie['TEXMFCNF']       = file.dirname(texmfcnf) end
-                end
-                locate(input.luaname,instance.luafiles)
-                locate(input.cnfname,instance.cnffiles)
-                if #instance.luafiles == 0 and instance.cnffiles == 0 then
-                    input.verbose = true
-                    input.report("error", "unable to locate",filename)
-                    os.exit()
-                end
-                -- here we also assume then TEXMF is set in the distribution, if this trickery is
-                -- used in the minimals, then users who don't use setuptex are on their own with
-                -- regards to extra trees
-            else
-                input.verbose = true
-                input.report("error", "unable to identify own path")
-                os.exit()
+                    break
+                end
             end
-        else
-            local t = input.split_path(input.env(instance,'TEXMFCNF'))
-            t = input.aux.expanded_path(instance,t)
-            input.aux.expand_vars(instance,t)
-            local function locate(filename,list)
-                for _,v in ipairs(t) do
-                    local texmfcnf = input.normalize_name(file.join(v,filename))
-                    if lfs.isfile(texmfcnf) then
-                        table.insert(list,texmfcnf)
-                    end
+        end
+        if not input.ownpath then input.ownpath = '.' end
+    end
+    return input.ownpath
+end
+
+function input.identify_own()
+    local instance = input.instance
+    local ownpath = input.getownpath() or lfs.currentdir()
+    local ie = instance.environment
+    if ownpath then
+        if input.env('SELFAUTOLOC')    == "" then os.env['SELFAUTOLOC']    = file.collapse_path(ownpath) end
+        if input.env('SELFAUTODIR')    == "" then os.env['SELFAUTODIR']    = file.collapse_path(ownpath .. "/..") end
+        if input.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end
+    else
+        input.verbose = true
+        input.report("error: unable to locate ownpath")
+        os.exit()
+    end
+    if input.env('TEXMFCNF') == "" then os.env['TEXMFCNF'] = input.cnfdefault end
+    if input.env('TEXOS')    == "" then os.env['TEXOS']    = input.env('SELFAUTODIR') end
+    if input.env('TEXROOT')  == "" then os.env['TEXROOT']  = input.env('SELFAUTOPARENT') end
+    if input.verbose then
+        for _,v in ipairs({"SELFAUTOLOC","SELFAUTODIR","SELFAUTOPARENT","TEXMFCNF"}) do
+            input.report("variable %s set to %s",v,input.env(v) or "unknown")
+        end
+    end
+    function input.identify_own() end
+end
+
+function input.identify_cnf()
+    local instance = input.instance
+    if #instance.cnffiles == 0 then
+        -- fallback
+        input.identify_own()
+        -- the real search
+        input.expand_variables()
+        local t = input.split_path(input.env('TEXMFCNF'))
+        t = input.aux.expanded_path(t)
+        input.aux.expand_vars(t) -- redundant
+        local function locate(filename,list)
+            for _,v in ipairs(t) do
+                local texmfcnf = input.normalize_name(file.join(v,filename))
+                if lfs.isfile(texmfcnf) then
+                    table.insert(list,texmfcnf)
                 end
             end
-            locate(input.luaname,instance.luafiles)
-            locate(input.cnfname,instance.cnffiles)
         end
+        locate(input.luaname,instance.luafiles)
+        locate(input.cnfname,instance.cnffiles)
     end
 end
 
-function input.load_cnf(instance)
+function input.load_cnf()
+    local instance = input.instance
     local function loadoldconfigdata()
         for _, fname in ipairs(instance.cnffiles) do
-            input.aux.load_cnf(instance,fname)
+            input.aux.load_cnf(fname)
         end
     end
     -- instance.cnffiles contain complete names now !
@@ -426,27 +453,27 @@ function input.load_cnf(instance)
             instance.rootpath = file.dirname(instance.rootpath)
         end
         instance.rootpath = input.normalize_name(instance.rootpath)
-        instance.environment['SELFAUTOPARENT'] = instance.rootpath -- just to be sure
         if instance.lsrmode then
             loadoldconfigdata()
         elseif instance.diskcache and not instance.renewcache then
-            input.loadoldconfig(instance,instance.cnffiles)
+            input.loadoldconfig(instance.cnffiles)
             if instance.loaderror then
                 loadoldconfigdata()
-                input.saveoldconfig(instance)
+                input.saveoldconfig()
             end
         else
             loadoldconfigdata()
             if instance.renewcache then
-                input.saveoldconfig(instance)
+                input.saveoldconfig()
             end
         end
-        input.aux.collapse_cnf_data(instance)
+        input.aux.collapse_cnf_data()
     end
-    input.checkconfigdata(instance)
+    input.checkconfigdata()
 end
 
-function input.load_lua(instance)
+function input.load_lua()
+    local instance = input.instance
     if #instance.luafiles == 0 then
         -- yet harmless
     else
@@ -458,14 +485,14 @@ function input.load_lua(instance)
             instance.rootpath = file.dirname(instance.rootpath)
         end
         instance.rootpath = input.normalize_name(instance.rootpath)
-        instance.environment['SELFAUTOPARENT'] = instance.rootpath -- just to be sure
-        input.loadnewconfig(instance)
-        input.aux.collapse_cnf_data(instance)
+        input.loadnewconfig()
+        input.aux.collapse_cnf_data()
     end
-    input.checkconfigdata(instance)
+    input.checkconfigdata()
 end
 
-function input.aux.collapse_cnf_data(instance) -- potential optmization: pass start index (setup and configuration are shared)
+function input.aux.collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared)
+    local instance = input.instance
     for _,c in ipairs(instance.order) do
         for k,v in pairs(c) do
             if not instance.variables[k] then
@@ -480,21 +507,22 @@ function input.aux.collapse_cnf_data(ins
     end
 end
 
-function input.aux.load_cnf(instance,fname)
+function input.aux.load_cnf(fname)
+    local instance = input.instance
     fname = input.clean_path(fname)
-    local lname = fname:gsub("%.%a+$",input.luasuffix)
+    local lname = file.replacesuffix(fname,'lua')
     local f = io.open(lname)
     if f then -- this will go
         f:close()
         local dname = file.dirname(fname)
         if not instance.configuration[dname] then
-            input.aux.load_configuration(instance,dname,lname)
+            input.aux.load_configuration(dname,lname)
             instance.order[#instance.order+1] = instance.configuration[dname]
         end
     else
         f = io.open(fname)
         if f then
-            input.report("loading", fname)
+            input.report("loading %s", fname)
             local line, data, n, k, v
             local dname = file.dirname(fname)
             if not instance.configuration[dname] then
@@ -526,227 +554,226 @@ function input.aux.load_cnf(instance,fna
             end
             f:close()
         else
-            input.report("skipping", fname)
+            input.report("skipping %s", fname)
         end
     end
 end
 
 -- database loading
 
-function input.load_hash(instance)
-    input.locatelists(instance)
+function input.load_hash()
+    local instance = input.instance
+    input.locatelists()
     if instance.lsrmode then
-        input.loadlists(instance)
+        input.loadlists()
     elseif instance.diskcache and not instance.renewcache then
-        input.loadfiles(instance)
+        input.loadfiles()
         if instance.loaderror then
-            input.loadlists(instance)
-            input.savefiles(instance)
+            input.loadlists()
+            input.savefiles()
         end
     else
-        input.loadlists(instance)
+        input.loadlists()
         if instance.renewcache then
-            input.savefiles(instance)
+            input.savefiles()
         end
     end
 end
 
-function input.aux.append_hash(instance,type,tag,name)
-    input.logger("= hash append",tag)
-    table.insert(instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } )
+function input.aux.append_hash(type,tag,name)
+    if input.trace > 0 then
+        input.logger("= hash append: %s",tag)
+    end
+    table.insert(input.instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } )
 end
 
-function input.aux.prepend_hash(instance,type,tag,name)
-    input.logger("= hash prepend",tag)
-    table.insert(instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } )
+function input.aux.prepend_hash(type,tag,name)
+    if input.trace > 0 then
+        input.logger("= hash prepend: %s",tag)
+    end
+    table.insert(input.instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } )
 end
 
-function input.aux.extend_texmf_var(instance,specification) -- crap
-    if instance.environment['TEXMF'] then
-        input.report("extending environment variable TEXMF with", specification)
-        instance.environment['TEXMF'] = instance.environment['TEXMF']:gsub("^%{", function()
-            return "{" .. specification .. ","
-        end)
-    elseif instance.variables['TEXMF'] then
-        input.report("extending configuration variable TEXMF with", specification)
-        instance.variables['TEXMF'] = instance.variables['TEXMF']:gsub("^%{", function()
-            return "{" .. specification .. ","
-        end)
+function input.aux.extend_texmf_var(specification) -- crap, we could better prepend the hash
+    local instance = input.instance
+--  local t = input.expanded_path_list('TEXMF') -- full expansion
+    local t = input.split_path(input.env('TEXMF'))
+    table.insert(t,1,specification)
+    local newspec = table.join(t,";")
+    if instance.environment["TEXMF"] then
+        instance.environment["TEXMF"] = newspec
+    elseif instance.variables["TEXMF"] then
+        instance.variables["TEXMF"] = newspec
     else
-        input.report("setting configuration variable TEXMF to", specification)
-        instance.variables['TEXMF'] = "{" .. specification .. "}"
-    end
-    if instance.variables['TEXMF']:find("%,") and not instance.variables['TEXMF']:find("^%{") then
-        input.report("adding {} to complex TEXMF variable, best do that yourself")
-        instance.variables['TEXMF'] = "{" .. instance.variables['TEXMF'] .. "}"
+        -- weird
     end
-    input.expand_variables(instance)
-    input.reset_hashes(instance)
+    input.expand_variables()
+    input.reset_hashes()
 end
 
 -- locators
 
-function input.locatelists(instance)
-    for _, path in pairs(input.simplified_list(input.expansion(instance,'TEXMF'))) do
-        path = file.collapse_path(path)
-        input.report("locating list of",path)
-        input.locatedatabase(instance,input.normalize_name(path))
+function input.locatelists()
+    local instance = input.instance
+    for _, path in pairs(input.clean_path_list('TEXMF')) do
+        input.report("locating list of %s",path)
+        input.locatedatabase(input.normalize_name(path))
     end
 end
 
-function input.locatedatabase(instance,specification)
-    return input.methodhandler('locators', instance, specification)
+function input.locatedatabase(specification)
+    return input.methodhandler('locators', specification)
 end
 
-function input.locators.tex(instance,specification)
+function input.locators.tex(specification)
     if specification and specification ~= '' and lfs.isdir(specification) then
-        input.logger('! tex locator', specification..' found')
-        input.aux.append_hash(instance,'file',specification,filename)
-    else
-        input.logger('? tex locator', specification..' not found')
+        if input.trace > 0 then
+            input.logger('! tex locator found: %s',specification)
+        end
+        input.aux.append_hash('file',specification,filename)
+    elseif input.trace > 0 then
+        input.logger('? tex locator not found: %s',specification)
     end
 end
 
 -- hashers
 
-function input.hashdatabase(instance,tag,name)
-    return input.methodhandler('hashers',instance,tag,name)
+function input.hashdatabase(tag,name)
+    return input.methodhandler('hashers',tag,name)
 end
 
-function input.loadfiles(instance)
+function input.loadfiles()
+    local instance = input.instance
     instance.loaderror = false
     instance.files = { }
     if not instance.renewcache then
         for _, hash in ipairs(instance.hashes) do
-            input.hashdatabase(instance,hash.tag,hash.name)
+            input.hashdatabase(hash.tag,hash.name)
             if instance.loaderror then break end
         end
     end
 end
 
-function input.hashers.tex(instance,tag,name)
-    input.aux.load_files(instance,tag)
+function input.hashers.tex(tag,name)
+    input.aux.load_files(tag)
 end
 
 -- generators:
 
-function input.loadlists(instance)
-    for _, hash in ipairs(instance.hashes) do
-        input.generatedatabase(instance,hash.tag)
+function input.loadlists()
+    for _, hash in ipairs(input.instance.hashes) do
+        input.generatedatabase(hash.tag)
     end
 end
 
-function input.generatedatabase(instance,specification)
-    return input.methodhandler('generators', instance, specification)
-end
-
-do
-
-    local weird = lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
-
-    function input.generators.tex(instance,specification)
-        local tag = specification
-        if not instance.lsrmode and lfs and lfs.dir then
-            input.report("scanning path",specification)
-            instance.files[tag] = { }
-            local files = instance.files[tag]
-            local n, m, r = 0, 0, 0
-            local spec = specification .. '/'
-            local attributes = lfs.attributes
-            local directory = lfs.dir
-            local small = instance.smallcache
-            local function action(path)
-                local mode, full
-                if path then
-                    full = spec .. path .. '/'
+function input.generatedatabase(specification)
+    return input.methodhandler('generators', specification)
+end
+
+local weird = lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
+
+function input.generators.tex(specification)
+    local instance = input.instance
+    local tag = specification
+    if not instance.lsrmode and lfs.dir then
+        input.report("scanning path %s",specification)
+        instance.files[tag] = { }
+        local files = instance.files[tag]
+        local n, m, r = 0, 0, 0
+        local spec = specification .. '/'
+        local attributes = lfs.attributes
+        local directory = lfs.dir
+        local small = instance.smallcache
+        local function action(path)
+            local mode, full
+            if path then
+                full = spec .. path .. '/'
+            else
+                full = spec
+            end
+            for name in directory(full) do
+                if name:find("^%.") then
+                  -- skip
+            --  elseif name:find("[%~%`%!%#%$%%%^%&%*%(%)%=%{%}%[%]%:%;\"\'%|%<%>%,%?\n\r\t]") then -- too much escaped
+                elseif weird:match(name) then
+                  -- texio.write_nl("skipping " .. name)
+                  -- skip
                 else
-                    full = spec
-                end
-                for name in directory(full) do
-                    if name:find("^%.") then
-                      -- skip
-                --  elseif name:find("[%~%`%!%#%$%%%^%&%*%(%)%=%{%}%[%]%:%;\"\'%|%<%>%,%?\n\r\t]") then -- too much escaped
-                    elseif weird:match(name) then
-                      -- texio.write_nl("skipping " .. name)
-                      -- skip
-                    else
-                        mode = attributes(full..name,'mode')
-                        if mode == "directory" then
-                            m = m + 1
-                            if path then
-                                action(path..'/'..name)
-                            else
-                                action(name)
-                            end
-                        elseif path and mode == 'file' then
-                            n = n + 1
-                            local f = files[name]
-                            if f then
-                                if not small then
-                                    if type(f) == 'string' then
-                                        files[name] = { f, path }
-                                    else
-                                      f[#f+1] = path
-                                    end
-                                end
-                            else
-                                files[name] = path
-                                local lower = name:lower()
-                                if name ~= lower then
-                                    files["remap:"..lower] = name
-                                    r = r + 1
-                                end
-                            end
+                    mode = attributes(full..name,'mode')
+                    if mode == 'directory' then
+                        m = m + 1
+                        if path then
+                            action(path..'/'..name)
+                        else
+                            action(name)
                         end
-                    end
-                end
-            end
-            action()
-            input.report(format("%s files found on %s directories with %s uppercase remappings",n,m,r))
-        else
-            local fullname = file.join(specification,input.lsrname)
-            local path     = '.'
-            local f        = io.open(fullname)
-            if f then
-                instance.files[tag] = { }
-                local files = instance.files[tag]
-                local small = instance.smallcache
-                input.report("loading lsr file",fullname)
-            --  for line in f:lines() do -- much slower then the next one
-                for line in (f:read("*a")):gmatch("(.-)\n") do
-                    if line:find("^[%a%d]") then
-                        local fl = files[line]
-                        if fl then
+                    elseif path and mode == 'file' then
+                        n = n + 1
+                        local f = files[name]
+                        if f then
                             if not small then
-                                if type(fl) == 'string' then
-                                    files[line] = { fl, path } -- table
+                                if type(f) == 'string' then
+                                    files[name] = { f, path }
                                 else
-                                    fl[#fl+1] = path
+                                  f[#f+1] = path
                                 end
                             end
                         else
-                            files[line] = path -- string
-                            local lower = line:lower()
-                            if line ~= lower then
-                                files["remap:"..lower] = line
+                            files[name] = path
+                            local lower = name:lower()
+                            if name ~= lower then
+                                files["remap:"..lower] = name
+                                r = r + 1
+                            end
+                        end
+                    end
+                end
+            end
+        end
+        action()
+        input.report("%s files found on %s directories with %s uppercase remappings",n,m,r)
+    else
+        local fullname = file.join(specification,input.lsrname)
+        local path     = '.'
+        local f        = io.open(fullname)
+        if f then
+            instance.files[tag] = { }
+            local files = instance.files[tag]
+            local small = instance.smallcache
+            input.report("loading lsr file %s",fullname)
+        --  for line in f:lines() do -- much slower then the next one
+            for line in (f:read("*a")):gmatch("(.-)\n") do
+                if line:find("^[%a%d]") then
+                    local fl = files[line]
+                    if fl then
+                        if not small then
+                            if type(fl) == 'string' then
+                                files[line] = { fl, path } -- table
+                            else
+                                fl[#fl+1] = path
                             end
                         end
                     else
-                        path = line:match("%.%/(.-)%:$") or path -- match could be nil due to empty line
+                        files[line] = path -- string
+                        local lower = line:lower()
+                        if line ~= lower then
+                            files["remap:"..lower] = line
+                        end
                     end
+                else
+                    path = line:match("%.%/(.-)%:$") or path -- match could be nil due to empty line
                 end
-                f:close()
             end
+            f:close()
         end
     end
-
 end
 
 -- savers, todo
 
-function input.savefiles(instance)
-    input.aux.save_data(instance, 'files', function(k,v)
-        return instance.validfile(k,v) -- path, name
+function input.savefiles()
+    input.aux.save_data('files', function(k,v)
+        return input.instance.validfile(k,v) -- path, name
     end)
 end
 
@@ -754,8 +781,8 @@ end
 -- we join them and split them after the expansion has taken place. This
 -- is more convenient.
 
-function input.splitconfig(instance)
-    for i,c in ipairs(instance) do
+function input.splitconfig()
+    for i,c in ipairs(input.instance) do
         for k,v in pairs(c) do
             if type(v) == 'string' then
                 local t = file.split_path(v)
@@ -766,8 +793,9 @@ function input.splitconfig(instance)
         end
     end
 end
-function input.joinconfig(instance)
-    for i,c in ipairs(instance.order) do
+
+function input.joinconfig()
+    for i,c in ipairs(input.instance.order) do
         for k,v in pairs(c) do
             if type(v) == 'table' then
                 c[k] = file.join_path(v)
@@ -790,8 +818,9 @@ function input.join_path(str)
     end
 end
 
-function input.splitexpansions(instance)
-    for k,v in pairs(instance.expansions) do
+function input.splitexpansions()
+    local ie = input.instance.expansions
+    for k,v in pairs(ie) do
         local t, h = { }, { }
         for _,vv in pairs(file.split_path(v)) do
             if vv ~= "" and not h[vv] then
@@ -800,19 +829,19 @@ function input.splitexpansions(instance)
             end
         end
         if #t > 1 then
-            instance.expansions[k] = t
+            ie[k] = t
         else
-            instance.expansions[k] = t[1]
+            ie[k] = t[1]
         end
     end
 end
 
 -- end of split/join code
 
-function input.saveoldconfig(instance)
-    input.splitconfig(instance)
-    input.aux.save_data(instance, 'configuration', nil)
-    input.joinconfig(instance)
+function input.saveoldconfig()
+    input.splitconfig()
+    input.aux.save_data('configuration', nil)
+    input.joinconfig()
 end
 
 input.configbanner = [[
@@ -829,8 +858,6 @@ function input.serialize(files)
     -- luatools and mtxtools are called frequently. Okay,
     -- we pay a small price for properly tabbed tables.
     local t = { }
-    local concat = table.concat
-    local sorted = table.sortedkeys
     local function dump(k,v,m)
         if type(v) == 'string' then
             return m .. "['" .. k .. "']='" .. v .. "',"
@@ -841,12 +868,12 @@ function input.serialize(files)
         end
     end
     t[#t+1] = "return {"
-    if instance.sortdata then
-        for _, k in pairs(sorted(files)) do
+    if input.instance.sortdata then
+        for _, k in pairs(sortedkeys(files)) do
             local fk  = files[k]
             if type(fk) == 'table' then
                 t[#t+1] = "\t['" .. k .. "']={"
-                for _, kk in pairs(sorted(fk)) do
+                for _, kk in pairs(sortedkeys(fk)) do
                     t[#t+1] = dump(kk,fk[kk],"\t\t")
                 end
                 t[#t+1] = "\t},"
@@ -873,11 +900,11 @@ end
 
 if not texmf then texmf = {} end -- no longer needed, at least not here
 
-function input.aux.save_data(instance, dataname, check, makename) -- untested without cache overload
-    for cachename, files in pairs(instance[dataname]) do
+function input.aux.save_data(dataname, check, makename) -- untested without cache overload
+    for cachename, files in pairs(input.instance[dataname]) do
         local name = (makename or file.join)(cachename,dataname)
-        local luaname, lucname = name .. input.luasuffix, name .. input.lucsuffix
-        input.report("preparing " .. dataname .. " for", luaname)
+        local luaname, lucname = name .. ".lua", name .. ".luc"
+        input.report("preparing %s for %s",dataname,cachename)
         for k, v in pairs(files) do
             if not check or check(v,k) then -- path, name
                 if type(v) == "table" and #v == 1 then
@@ -895,38 +922,38 @@ function input.aux.save_data(instance, d
             time    = os.date("%H:%M:%S"),
             content = files,
         }
-        local f = io.open(luaname,'w')
-        if f then
-            input.report("saving " .. dataname .. " in", luaname)
-            f:write(input.serialize(data))
-            f:close()
-            input.report("compiling " .. dataname .. " to", lucname)
-            if not utils.lua.compile(luaname,lucname) then
-                input.report("compiling failed for " .. dataname .. ", deleting file " .. lucname)
+        local ok = io.savedata(luaname,input.serialize(data))
+        if ok then
+            input.report("%s saved in %s",dataname,luaname)
+            if utils.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip
+                input.report("%s compiled to %s",dataname,lucname)
+            else
+                input.report("compiling failed for %s, deleting file %s",dataname,lucname)
                 os.remove(lucname)
             end
         else
-            input.report("unable to save " .. dataname .. " in " .. name..input.luasuffix)
+            input.report("unable to save %s in %s (access error)",dataname,luaname)
         end
     end
 end
 
-function input.aux.load_data(instance,pathname,dataname,filename,makename) -- untested without cache overload
+function input.aux.load_data(pathname,dataname,filename,makename) -- untested without cache overload
+    local instance = input.instance
     filename = ((not filename or (filename == "")) and dataname) or filename
     filename = (makename and makename(dataname,filename)) or file.join(pathname,filename)
-    local blob = loadfile(filename .. input.lucsuffix) or loadfile(filename .. input.luasuffix)
+    local blob = loadfile(filename .. ".luc") or loadfile(filename .. ".lua")
     if blob then
         local data = blob()
         if data and data.content and data.type == dataname and data.version == input.cacheversion then
-            input.report("loading",dataname,"for",pathname,"from",filename)
+            input.report("loading %s for %s from %s",dataname,pathname,filename)
             instance[dataname][pathname] = data.content
         else
-            input.report("skipping",dataname,"for",pathname,"from",filename)
+            input.report("skipping %s for %s from %s",dataname,pathname,filename)
             instance[dataname][pathname] = { }
             instance.loaderror = true
         end
     else
-        input.report("skipping",dataname,"for",pathname,"from",filename)
+        input.report("skipping %s for %s from %s",dataname,pathname,filename)
     end
 end
 
@@ -939,13 +966,14 @@ end
 --     TEXMFBOGUS = 'effe checken of dit werkt',
 -- }
 
-function input.aux.load_texmfcnf(instance,dataname,pathname)
+function input.aux.load_texmfcnf(dataname,pathname)
+    local instance = input.instance
     local filename = file.join(pathname,input.luaname)
     local blob = loadfile(filename)
     if blob then
         local data = blob()
         if data then
-            input.report("loading","configuration file",filename)
+            input.report("loading configuration file %s",filename)
             if true then
                 -- flatten to variable.progname
                 local t = { }
@@ -965,172 +993,168 @@ function input.aux.load_texmfcnf(instanc
                 instance[dataname][pathname] = data
             end
         else
-            input.report("skipping","configuration file",filename)
+            input.report("skipping configuration file %s",filename)
             instance[dataname][pathname] = { }
             instance.loaderror = true
         end
     else
-        input.report("skipping","configuration file",filename)
+        input.report("skipping configuration file %s",filename)
     end
 end
 
-function input.aux.load_configuration(instance,dname,lname)
-    input.aux.load_data(instance,dname,'configuration',lname and file.basename(lname))
+function input.aux.load_configuration(dname,lname)
+    input.aux.load_data(dname,'configuration',lname and file.basename(lname))
 end
-function input.aux.load_files(instance,tag)
-    input.aux.load_data(instance,tag,'files')
+function input.aux.load_files(tag)
+    input.aux.load_data(tag,'files')
 end
 
-function input.resetconfig(instance)
+function input.resetconfig()
+    input.identify_own()
+    local instance = input.instance
     instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false
 end
 
-function input.loadnewconfig(instance)
+function input.loadnewconfig()
+    local instance = input.instance
     for _, cnf in ipairs(instance.luafiles) do
         local dname = file.dirname(cnf)
-        input.aux.load_texmfcnf(instance,'setup',dname)
+        input.aux.load_texmfcnf('setup',dname)
         instance.order[#instance.order+1] = instance.setup[dname]
         if instance.loaderror then break end
     end
 end
 
-function input.loadoldconfig(instance)
+function input.loadoldconfig()
+    local instance = input.instance
     if not instance.renewcache then
         for _, cnf in ipairs(instance.cnffiles) do
             local dname = file.dirname(cnf)
-            input.aux.load_configuration(instance,dname)
+            input.aux.load_configuration(dname)
             instance.order[#instance.order+1] = instance.configuration[dname]
             if instance.loaderror then break end
         end
     end
-    input.joinconfig(instance)
+    input.joinconfig()
 end
 
-function input.expand_variables(instance)
-    instance.expansions = { }
---~ instance.environment['SELFAUTOPARENT'] = instance.environment['SELFAUTOPARENT'] or instance.rootpath
-    if instance.engine   ~= "" then instance.environment['engine']   = instance.engine   end
-    if instance.progname ~= "" then instance.environment['progname'] = instance.progname end
-    for k,v in pairs(instance.environment) do
+function input.expand_variables()
+    local instance = input.instance
+    local expansions, environment, variables = { }, instance.environment, instance.variables
+    local env = input.env
+    instance.expansions = expansions
+    if instance.engine   ~= "" then environment['engine']   = instance.engine   end
+    if instance.progname ~= "" then environment['progname'] = instance.progname end
+    for k,v in pairs(environment) do
         local a, b = k:match("^(%a+)%_(.*)%s*$")
         if a and b then
-            instance.expansions[a..'.'..b] = v
+            expansions[a..'.'..b] = v
         else
-            instance.expansions[k] = v
+            expansions[k] = v
         end
     end
-    for k,v in pairs(instance.environment) do -- move environment to expansions
-        if not instance.expansions[k] then instance.expansions[k] = v end
+    for k,v in pairs(environment) do -- move environment to expansions
+        if not expansions[k] then expansions[k] = v end
     end
-    for k,v in pairs(instance.variables) do -- move variables to expansions
-        if not instance.expansions[k] then instance.expansions[k] = v end
+    for k,v in pairs(variables) do -- move variables to expansions
+        if not expansions[k] then expansions[k] = v end
     end
     while true do
         local busy = false
-        for k,v in pairs(instance.expansions) do
+        for k,v in pairs(expansions) do
             local s, n = v:gsub("%$([%a%d%_%-]+)", function(a)
                 busy = true
-                return instance.expansions[a] or input.env(instance,a)
+                return expansions[a] or env(a)
             end)
             local s, m = s:gsub("%$%{([%a%d%_%-]+)%}", function(a)
                 busy = true
-                return instance.expansions[a] or input.env(instance,a)
+                return expansions[a] or env(a)
             end)
             if n > 0 or m > 0 then
-                instance.expansions[k]= s
+                expansions[k]= s
             end
         end
         if not busy then break end
     end
-    local homedir = 
-       instance.environment[(os.type == "windows" and 'USERPROFILE') or 'HOME'] or '~'
-    for k,v in pairs(instance.expansions) do
-        v = v:gsub("^~", homedir) 
-        instance.expansions[k] = v:gsub("\\", '/')
+    for k,v in pairs(expansions) do
+        expansions[k] = v:gsub("\\", '/')
     end
 end
 
-function input.aux.expand_vars(instance,lst) -- simple vars
+function input.aux.expand_vars(lst) -- simple vars
+    local instance = input.instance
+    local variables, env = instance.variables, input.env
     for k,v in pairs(lst) do
         lst[k] = v:gsub("%$([%a%d%_%-]+)", function(a)
-            return instance.variables[a] or input.env(instance,a)
+            return variables[a] or env(a)
         end)
     end
 end
 
-function input.aux.expanded_var(instance,var) -- simple vars
+function input.aux.expanded_var(var) -- simple vars
+    local instance = input.instance
     return var:gsub("%$([%a%d%_%-]+)", function(a)
-        return instance.variables[a] or input.env(instance,a)
+        return instance.variables[a] or input.env(a)
     end)
 end
 
-function input.aux.entry(instance,entries,name)
+function input.aux.entry(entries,name)
     if name and (name ~= "") then
+        local instance = input.instance
         name = name:gsub('%$','')
         local result = entries[name..'.'..instance.progname] or entries[name]
         if result then
             return result
         else
-            result = input.env(instance,name)
+            result = input.env(name)
             if result then
                 instance.variables[name] = result
-                input.expand_variables(instance)
+                input.expand_variables()
                 return instance.expansions[name] or ""
             end
         end
     end
     return ""
 end
-function input.variable(instance,name)
-    return input.aux.entry(instance,instance.variables,name)
+function input.variable(name)
+    return input.aux.entry(input.instance.variables,name)
 end
-function input.expansion(instance,name)
-    return input.aux.entry(instance,instance.expansions,name)
+function input.expansion(name)
+    return input.aux.entry(input.instance.expansions,name)
 end
 
-function input.aux.is_entry(instance,entries,name)
+function input.aux.is_entry(entries,name)
     if name and name ~= "" then
         name = name:gsub('%$','')
-        return (entries[name..'.'..instance.progname] or entries[name]) ~= nil
+        return (entries[name..'.'..input.instance.progname] or entries[name]) ~= nil
     else
         return false
     end
 end
 
-function input.is_variable(instance,name)
-    return input.aux.is_entry(instance,instance.variables,name)
-end
-function input.is_expansion(instance,name)
-    return input.aux.is_entry(instance,instance.expansions,name)
+function input.is_variable(name)
+    return input.aux.is_entry(input.instance.variables,name)
 end
 
-function input.simplified_list(str)
-    if type(str) == 'table' then
-        return str -- troubles ; ipv , in texmf
-    elseif str == '' then
-        return { }
-    else
-        local t = { }
-        for _,v in ipairs(string.splitchr(str:gsub("^\{(.+)\}$","%1"),",")) do
-            t[#t+1] = (v:gsub("^[%!]*(.+)[%/\\]*$","%1"))
-        end
-        return t
-    end
+function input.is_expansion(name)
+    return input.aux.is_entry(input.instance.expansions,name)
 end
 
-function input.unexpanded_path_list(instance,str)
-    local pth = input.variable(instance,str)
+function input.unexpanded_path_list(str)
+    local pth = input.variable(str)
     local lst = input.split_path(pth)
-    return input.aux.expanded_path(instance,lst)
+    return input.aux.expanded_path(lst)
 end
-function input.unexpanded_path(instance,str)
-    return file.join_path(input.unexpanded_path_list(instance,str))
+
+function input.unexpanded_path(str)
+    return file.join_path(input.unexpanded_path_list(str))
 end
 
 do
     local done = { }
 
-    function input.reset_extra_path(instance)
+    function input.reset_extra_path()
+        local instance = input.instance
         local ep = instance.extra_paths
         if not ep then
             ep, done = { }, { }
@@ -1140,7 +1164,8 @@ do
         end
     end
 
-    function input.register_extra_path(instance,paths,subpaths)
+    function input.register_extra_path(paths,subpaths)
+        local instance = input.instance
         local ep = instance.extra_paths or { }
         local n = #ep
         if paths and paths ~= "" then
@@ -1185,7 +1210,8 @@ do
 
 end
 
-function input.expanded_path_list(instance,str)
+function input.expanded_path_list(str)
+    local instance = input.instance
     local function made_list(list)
         local ep = instance.extra_paths
         if not ep or #ep == 0 then
@@ -1226,39 +1252,41 @@ function input.expanded_path_list(instan
         -- engine+progname hash
         str = str:gsub("%$","")
         if not instance.lists[str] then -- cached
-            local lst = made_list(input.split_path(input.expansion(instance,str)))
-            instance.lists[str] = input.aux.expanded_path(instance,lst)
+            local lst = made_list(input.split_path(input.expansion(str)))
+            instance.lists[str] = input.aux.expanded_path(lst)
         end
         return instance.lists[str]
     else
-        local lst = input.split_path(input.expansion(instance,str))
-        return made_list(input.aux.expanded_path(instance,lst))
+        local lst = input.split_path(input.expansion(str))
+        return made_list(input.aux.expanded_path(lst))
     end
 end
 
-function input.expand_path(instance,str)
-    return file.join_path(input.expanded_path_list(instance,str))
+
+function input.clean_path_list(str)
+    local t = input.expanded_path_list(str)
+    if t then
+        for i=1,#t do
+            t[i] = file.collapse_path(input.clean_path(t[i]))
+        end
+    end
+    return t
 end
 
---~ function input.first_writable_path(instance,name)
---~     for _,v in pairs(input.expanded_path_list(instance,name)) do
---~         if file.is_writable(file.join(v,'luatex-cache.tmp')) then
---~             return v
---~         end
---~     end
---~     return "."
---~ end
+function input.expand_path(str)
+    return file.join_path(input.expanded_path_list(str))
+end
 
-function input.expanded_path_list_from_var(instance,str) -- brrr
+function input.expanded_path_list_from_var(str) -- brrr
     local tmp = input.var_of_format_or_suffix(str:gsub("%$",""))
     if tmp ~= "" then
-        return input.expanded_path_list(instance,str)
+        return input.expanded_path_list(str)
     else
-        return input.expanded_path_list(instance,tmp)
+        return input.expanded_path_list(tmp)
     end
 end
-function input.expand_path_from_var(instance,str)
-    return file.join_path(input.expanded_path_list_from_var(instance,str))
+function input.expand_path_from_var(str)
+    return file.join_path(input.expanded_path_list_from_var(str))
 end
 
 function input.format_of_var(str)
@@ -1288,9 +1316,9 @@ function input.var_of_format_or_suffix(s
     return ''
 end
 
-function input.expand_braces(instance,str) -- output variable and brace expansion of STRING
-    local ori = input.variable(instance,str)
-    local pth = input.aux.expanded_path(instance,input.split_path(ori))
+function input.expand_braces(str) -- output variable and brace expansion of STRING
+    local ori = input.variable(str)
+    local pth = input.aux.expanded_path(input.split_path(ori))
     return file.join_path(pth)
 end
 
@@ -1305,6 +1333,7 @@ end
 -- {a,b,c/{p,q,r}/d/{x,y,z}//}
 -- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}}
 -- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}}
+-- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}
 
 -- this one is better and faster, but it took me a while to realize
 -- that this kind of replacement is cleaner than messy parsing and
@@ -1313,19 +1342,19 @@ end
 -- work that well; the parsing is ok, but dealing with the resulting
 -- table is a pain because we need to work inside-out recursively
 
--- get rid of piecewise here, just a gmatch is ok
-
 function input.aux.splitpathexpr(str, t, validate)
     -- no need for optimization, only called a few times, we can use lpeg for the sub
     t = t or { }
-    local concat = table.concat
+    str = str:gsub(",}",",@}")
+    str = str:gsub("{,","{@,")
+ -- str = "@" .. str .. "@"
     while true do
         local done = false
         while true do
             local ok = false
-            str = str:gsub("([^{},]+){([^{}]-)}", function(a,b)
+            str = str:gsub("([^{},]+){([^{}]+)}", function(a,b)
                 local t = { }
-                b:piecewise(",", function(s) t[#t+1] = a .. s end)
+                for s in b:gmatch("[^,]+") do t[#t+1] = a .. s end
                 ok, done = true, true
                 return "{" .. concat(t,",") .. "}"
             end)
@@ -1333,9 +1362,9 @@ function input.aux.splitpathexpr(str, t,
         end
         while true do
             local ok = false
-            str = str:gsub("{([^{}]-)}([^{},]+)", function(a,b)
+            str = str:gsub("{([^{}]+)}([^{},]+)", function(a,b)
                 local t = { }
-                a:piecewise(",", function(s) t[#t+1] = s .. b end)
+                for s in a:gmatch("[^,]+") do t[#t+1] = s .. b end
                 ok, done = true, true
                 return "{" .. concat(t,",") .. "}"
             end)
@@ -1343,50 +1372,41 @@ function input.aux.splitpathexpr(str, t,
         end
         while true do
             local ok = false
-            str = str:gsub("([,{]){([^{}]+)}([,}])", function(a,b,c)
+            str = str:gsub("{([^{}]+)}{([^{}]+)}", function(a,b)
+                local t = { }
+                for sa in a:gmatch("[^,]+") do
+                    for sb in b:gmatch("[^,]+") do
+                        t[#t+1] = sa .. sb
+                    end
+                end
                 ok, done = true, true
-                return a .. b .. c
+                return "{" .. concat(t,",") .. "}"
             end)
             if not ok then break end
         end
-        if not done then break end
-    end
-    while true do
-        local ok = false
-        str = str:gsub("{([^{}]-)}{([^{}]-)}", function(a,b)
-            local t = { }
-            a:piecewise(",", function(sa)
-                b:piecewise(",", function(sb)
-                    t[#t+1] = sa .. sb
-                end)
-            end)
-            ok = true
-            return "{" .. concat(t,",") .. "}"
-        end)
-        if not ok then break end
-    end
-    while true do
-        local ok = false
-        str = str:gsub("{([^{}]-)}", function(a)
-            ok = true
-            return a
+        str = str:gsub("({[^{}]*){([^{}]+)}([^{}]*})", function(a,b,c)
+            done = true
+            return a .. b.. c
         end)
-        if not ok then break end
+        if not done then break end
     end
+    str = str:gsub("[{}]", "")
+    str = str:gsub("@","")
     if validate then
-        str:piecewise(",", function(s)
+        for s in str:gmatch("[^,]+") do
             s = validate(s)
             if s then t[#t+1] = s end
-        end)
+        end
     else
-        str:piecewise(",", function(s)
+        for s in str:gmatch("[^,]+") do
             t[#t+1] = s
-        end)
+        end
     end
     return t
 end
 
-function input.aux.expanded_path(instance,pathlist) -- maybe not a list, just a path
+function input.aux.expanded_path(pathlist) -- maybe not a list, just a path
+    local instance = input.instance
     -- a previous version fed back into pathlist
     local newlist, ok = { }, false
     for _,v in ipairs(pathlist) do
@@ -1418,17 +1438,16 @@ input.is_readable = { }
 function input.aux.is_readable(readable, name)
     if input.trace > 2 then
         if readable then
-            input.logger("+ readable", name)
+            input.logger("+ readable: %s",name)
         else
-            input.logger("- readable", name)
+            input.logger("- readable: %s", name)
         end
     end
     return readable
 end
 
 function input.is_readable.file(name)
- -- return input.aux.is_readable(file.is_readable(name), name)
-    return input.aux.is_readable(input.aux.is_file(name), name)
+    return input.aux.is_readable(lfs.isfile(name), name)
 end
 
 input.is_readable.tex = input.is_readable.file
@@ -1436,12 +1455,13 @@ input.is_readable.tex = input.is_readabl
 -- name
 -- name/name
 
-function input.aux.collect_files(instance,names)
+function input.aux.collect_files(names)
+    local instance = input.instance
     local filelist = { }
     for _, fname in pairs(names) do
         if fname then
             if input.trace > 2 then
-                input.logger("? blobpath asked",fname)
+                input.logger("? blobpath asked: %s",fname)
             end
             local bname = file.basename(fname)
             local dname = file.dirname(fname)
@@ -1455,7 +1475,7 @@ function input.aux.collect_files(instanc
                 local files = blobpath and instance.files[blobpath]
                 if files then
                     if input.trace > 2 then
-                        input.logger('? blobpath do',blobpath .. " (" .. bname ..")")
+                        input.logger('? blobpath do: %s (%s)',blobpath,bname)
                     end
                     local blobfile = files[bname]
                     if not blobfile then
@@ -1488,7 +1508,7 @@ function input.aux.collect_files(instanc
                         end
                     end
                 elseif input.trace > 1 then
-                    input.logger('! blobpath no',blobpath .. " (" .. bname ..")" )
+                    input.logger('! blobpath no: %s (%s)',blobpath,bname)
                 end
             end
         end
@@ -1543,15 +1563,17 @@ do
 
 end
 
-function input.aux.register_in_trees(instance,name)
+function input.aux.register_in_trees(name)
     if not name:find("^%.") then
+        local instance = input.instance
         instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one
     end
 end
 
 -- split the next one up, better for jit
 
-function input.aux.find_file(instance,filename) -- todo : plugin (scanners, checkers etc)
+function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc)
+    local instance = input.instance
     local result = { }
     local stamp  = nil
     filename = input.normalize_name(filename)  -- elsewhere
@@ -1560,16 +1582,22 @@ function input.aux.find_file(instance,fi
     if instance.remember then
         stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format
         if instance.found[stamp] then
-            input.logger('! remembered', filename)
+            if input.trace > 0 then
+                input.logger('! remembered: %s',filename)
+            end
             return instance.found[stamp]
         end
     end
     if filename:find('%*') then
-        input.logger('! wildcard', filename)
-        result = input.find_wildcard_files(instance,filename)
+        if input.trace > 0 then
+            input.logger('! wildcard: %s', filename)
+        end
+        result = input.find_wildcard_files(filename)
     elseif input.aux.qualified_path(filename) then
         if input.is_readable.file(filename) then
-            input.logger('! qualified', filename)
+            if input.trace > 0 then
+                input.logger('! qualified: %s', filename)
+            end
             result = { filename }
         else
             local forcedname, ok = "", false
@@ -1577,22 +1605,26 @@ function input.aux.find_file(instance,fi
                 if instance.format == "" then
                     forcedname = filename .. ".tex"
                     if input.is_readable.file(forcedname) then
-                        input.logger('! no suffix, forcing standard filetype tex')
+                        if input.trace > 0 then
+                            input.logger('! no suffix, forcing standard filetype: tex')
+                        end
                         result, ok = { forcedname }, true
                     end
                 else
                     for _, s in pairs(input.suffixes_of_format(instance.format)) do
                         forcedname = filename .. "." .. s
                         if input.is_readable.file(forcedname) then
-                            input.logger('! no suffix, forcing format filetype', s)
+                            if input.trace > 0 then
+                                input.logger('! no suffix, forcing format filetype: %s', s)
+                            end
                             result, ok = { forcedname }, true
                             break
                         end
                     end
                 end
             end
-            if not ok then
-                input.logger('? qualified', filename)
+            if not ok and input.trace > 0 then
+                input.logger('? qualified: %s', filename)
             end
         end
     else
@@ -1610,10 +1642,14 @@ function input.aux.find_file(instance,fi
                 local forcedname = filename .. '.tex'
                 wantedfiles[#wantedfiles+1] = forcedname
                 filetype = input.format_of_suffix(forcedname)
-                input.logger('! forcing filetype',filetype)
+                    if input.trace > 0 then
+                        input.logger('! forcing filetype: %s',filetype)
+                    end
             else
                 filetype = input.format_of_suffix(filename)
-                input.logger('! using suffix based filetype',filetype)
+                if input.trace > 0 then
+                    input.logger('! using suffix based filetype: %s',filetype)
+                end
             end
         else
             if ext == "" then
@@ -1622,16 +1658,18 @@ function input.aux.find_file(instance,fi
                 end
             end
             filetype = instance.format
-            input.logger('! using given filetype',filetype)
+            if input.trace > 0 then
+                input.logger('! using given filetype: %s',filetype)
+            end
         end
         local typespec = input.variable_of_format(filetype)
-        local pathlist = input.expanded_path_list(instance,typespec)
+        local pathlist = input.expanded_path_list(typespec)
         if not pathlist or #pathlist == 0 then
             -- no pathlist, access check only / todo == wildcard
             if input.trace > 2 then
-                input.logger('? filename',filename)
-                input.logger('? filetype',filetype or '?')
-                input.logger('? wanted files',table.concat(wantedfiles," | "))
+                input.logger('? filename: %s',filename)
+                input.logger('? filetype: %s',filetype or '?')
+                input.logger('? wanted files: %s',concat(wantedfiles," | "))
             end
             for _, fname in pairs(wantedfiles) do
                 if fname and input.is_readable.file(fname) then
@@ -1641,7 +1679,7 @@ function input.aux.find_file(instance,fi
                 end
             end
             -- this is actually 'other text files' or 'any' or 'whatever'
-            local filelist = input.aux.collect_files(instance,wantedfiles)
+            local filelist = input.aux.collect_files(wantedfiles)
             local fl = filelist and filelist[1]
             if fl then
                 filename = fl[3]
@@ -1650,12 +1688,12 @@ function input.aux.find_file(instance,fi
             end
         else
             -- list search
-            local filelist = input.aux.collect_files(instance,wantedfiles)
+            local filelist = input.aux.collect_files(wantedfiles)
             local doscan, recurse
             if input.trace > 2 then
-                input.logger('? filename',filename)
-            --                if pathlist then input.logger('? path list',table.concat(pathlist," | ")) end
-            --                if filelist then input.logger('? file list',table.concat(filelist," | ")) end
+                input.logger('? filename: %s',filename)
+            --                if pathlist then input.logger('? path list: %s',concat(pathlist," | ")) end
+            --                if filelist then input.logger('? file list: %s',concat(filelist," | ")) end
             end
             -- a bit messy ... esp the doscan setting here
             for _, path in pairs(pathlist) do
@@ -1676,11 +1714,11 @@ function input.aux.find_file(instance,fi
                         if f:find(expr) then
                             -- input.debug('T',' '..f)
                             if input.trace > 2 then
-                                input.logger('= found in hash',f)
+                                input.logger('= found in hash: %s',f)
                             end
                             --- todo, test for readable
                             result[#result+1] = fl[3]
-                            input.aux.register_in_trees(instance,f) -- for tracing used files
+                            input.aux.register_in_trees(f) -- for tracing used files
                             done = true
                             if not instance.allresults then break end
                         else
@@ -1694,12 +1732,12 @@ function input.aux.find_file(instance,fi
                         local pname = pathname:gsub("%.%*$",'')
                         if not pname:find("%*") then
                             local ppname = pname:gsub("/+$","")
-                            if input.aux.can_be_dir(instance,ppname) then
+                            if input.aux.can_be_dir(ppname) then
                                 for _, w in pairs(wantedfiles) do
                                     local fname = file.join(ppname,w)
                                     if input.is_readable.file(fname) then
                                         if input.trace > 2 then
-                                            input.logger('= found by scanning',fname)
+                                            input.logger('= found by scanning: %s',fname)
                                         end
                                         result[#result+1] = fname
                                         done = true
@@ -1728,40 +1766,29 @@ function input.aux.find_file(instance,fi
     return result
 end
 
-input.aux._find_file_ = input.aux.find_file
+input.aux._find_file_ = input.aux.find_file -- frozen variant
 
-function input.aux.find_file(instance,filename) -- maybe make a lowres cache too
-    local result = input.aux._find_file_(instance,filename)
+function input.aux.find_file(filename) -- maybe make a lowres cache too
+    local result = input.aux._find_file_(filename)
     if #result == 0 then
         local lowered = filename:lower()
         if filename ~= lowered then
-            return input.aux._find_file_(instance,lowered)
+            return input.aux._find_file_(lowered)
         end
     end
     return result
 end
 
-if lfs and lfs.isfile then
-    input.aux.is_file = lfs.isfile      -- to be done: use this
-else
-    input.aux.is_file = file.is_readable
-end
-
-if lfs and lfs.isdir then
-    function input.aux.can_be_dir(instance,name)
-        if not instance.fakepaths[name] then
-            if lfs.isdir(name) then
-                instance.fakepaths[name] = 1 -- directory
-            else
-                instance.fakepaths[name] = 2 -- no directory
-            end
+function input.aux.can_be_dir(name)
+    local instance = input.instance
+    if not instance.fakepaths[name] then
+        if lfs.isdir(name) then
+            instance.fakepaths[name] = 1 -- directory
+        else
+            instance.fakepaths[name] = 2 -- no directory
         end
-        return (instance.fakepaths[name] == 1)
-    end
-else
-    function input.aux.can_be_dir()
-        return true
     end
+    return (instance.fakepaths[name] == 1)
 end
 
 if not input.concatinators  then input.concatinators = { } end
@@ -1769,7 +1796,8 @@ if not input.concatinators  then input.c
 input.concatinators.tex  = file.join
 input.concatinators.file = input.concatinators.tex
 
-function input.find_files(instance,filename,filetype,mustexist)
+function input.find_files(filename,filetype,mustexist)
+    local instance = input.instance
     if type(mustexist) == boolean then
         -- all set
     elseif type(filetype) == 'boolean' then
@@ -1778,16 +1806,17 @@ function input.find_files(instance,filen
         filetype, mustexist = nil, false
     end
     instance.format = filetype or ''
-    local t = input.aux.find_file(instance,filename,true)
+    local t = input.aux.find_file(filename,true)
     instance.format = ''
     return t
 end
 
-function input.find_file(instance,filename,filetype,mustexist)
-    return (input.find_files(instance,filename,filetype,mustexist)[1] or "")
+function input.find_file(filename,filetype,mustexist)
+    return (input.find_files(filename,filetype,mustexist)[1] or "")
 end
 
-function input.find_given_files(instance,filename)
+function input.find_given_files(filename)
+    local instance = input.instance
     local bname, result = file.basename(filename), { }
     for k, hash in ipairs(instance.hashes) do
         local files = instance.files[hash.tag]
@@ -1815,11 +1844,12 @@ function input.find_given_files(instance
     return result
 end
 
-function input.find_given_file(instance,filename)
-    return (input.find_given_files(instance,filename)[1] or "")
+function input.find_given_file(filename)
+    return (input.find_given_files(filename)[1] or "")
 end
 
-function input.find_wildcard_files(instance,filename) -- todo: remap:
+function input.find_wildcard_files(filename) -- todo: remap:
+    local instance = input.instance
     local result = { }
     local bname, dname = file.basename(filename), file.dirname(filename)
     local path = dname:gsub("^*/","")
@@ -1872,16 +1902,19 @@ function input.find_wildcard_files(insta
             if done and not allresults then break end
         end
     end
+    -- we can consider also searching the paths not in the database, but then
+    -- we end up with a messy search (all // in all path specs)
     return result
 end
 
-function input.find_wildcard_file(instance,filename)
-    return (input.find_wildcard_files(instance,filename)[1] or "")
+function input.find_wildcard_file(filename)
+    return (input.find_wildcard_files(filename)[1] or "")
 end
 
 -- main user functions
 
-function input.save_used_files_in_trees(instance, filename,jobname)
+function input.save_used_files_in_trees(filename,jobname)
+    local instance = input.instance
     if not filename then filename = 'luatex.jlg' end
     local f = io.open(filename,'w')
     if f then
@@ -1891,7 +1924,7 @@ function input.save_used_files_in_trees(
             f:write("\t<rl:name>" .. jobname .. "</rl:name>\n")
         end
         f:write("\t<rl:files>\n")
-        for _,v in pairs(table.sortedkeys(instance.foundintrees)) do
+        for _,v in pairs(sorted(instance.foundintrees)) do -- ipairs
             f:write("\t\t<rl:file n='" .. instance.foundintrees[v] .. "'>" .. v .. "</rl:file>\n")
         end
         f:write("\t</rl:files>\n")
@@ -1900,24 +1933,24 @@ function input.save_used_files_in_trees(
     end
 end
 
-function input.automount(instance)
+function input.automount()
     -- implemented later
 end
 
-function input.load(instance)
-    input.starttiming(instance)
-    input.resetconfig(instance)
-    input.identify_cnf(instance)
-    input.load_lua(instance)
-    input.expand_variables(instance)
-    input.load_cnf(instance)
-    input.expand_variables(instance)
-    input.load_hash(instance)
-    input.automount(instance)
-    input.stoptiming(instance)
+function input.load()
+    input.starttiming(input.instance)
+    input.resetconfig()
+    input.identify_cnf()
+    input.load_lua()
+    input.expand_variables()
+    input.load_cnf()
+    input.expand_variables()
+    input.load_hash()
+    input.automount()
+    input.stoptiming(input.instance)
 end
 
-function input.for_files(instance, command, files, filetype, mustexist)
+function input.for_files(command, files, filetype, mustexist)
     if files and #files > 0 then
         local function report(str)
             if input.verbose then
@@ -1930,7 +1963,7 @@ function input.for_files(instance, comma
             report('')
         end
         for _, file in pairs(files) do
-            local result = command(instance,file,filetype,mustexist)
+            local result = command(file,filetype,mustexist)
             if type(result) == 'string' then
                 report(result)
             else
@@ -1944,14 +1977,11 @@ end
 
 -- strtab
 
-function input.var_value(instance,str)     -- output the value of variable $STRING.
-    return input.variable(instance,str)
-end
-function input.expand_var(instance,str)    -- output variable expansion of STRING.
-    return input.expansion(instance,str)
-end
-function input.show_path(instance,str)     -- output search path for file type NAME
-    return file.join_path(input.expanded_path_list(instance,input.format_of_var(str)))
+input.var_value  = input.variable   -- output the value of variable $STRING.
+input.expand_var = input.expansion  -- output variable expansion of STRING.
+
+function input.show_path(str)     -- output search path for file type NAME
+    return file.join_path(input.expanded_path_list(input.format_of_var(str)))
 end
 
 -- input.find_file(filename)
@@ -2000,56 +2030,58 @@ function table.sequenced(t,sep) -- temp 
     for k, v in pairs(t) do
         s[#s+1] = k .. "=" .. v
     end
-    return table.concat(s, sep or " | ")
+    return concat(s, sep or " | ")
 end
 
-function input.methodhandler(what, instance, filename, filetype) -- ...
+function input.methodhandler(what, filename, filetype) -- ...
     local specification = (type(filename) == "string" and input.splitmethod(filename)) or filename -- no or { }, let it bomb
     local scheme = specification.scheme
     if input[what][scheme] then
-        input.logger('= handler',specification.original .." -> " .. what .. " -> " .. table.sequenced(specification))
-        return input[what][scheme](instance,filename,filetype) -- todo: specification
+        if input.trace > 0 then
+            input.logger('= handler: %s -> %s -> %s',specification.original,what,table.sequenced(specification))
+        end
+        return input[what][scheme](filename,filetype) -- todo: specification
     else
-        return input[what].tex(instance,filename,filetype) -- todo: specification
+        return input[what].tex(filename,filetype) -- todo: specification
     end
 end
 
 -- also inside next test?
 
-function input.findtexfile(instance, filename, filetype)
-    return input.methodhandler('finders',instance, input.normalize_name(filename), filetype)
+function input.findtexfile(filename, filetype)
+    return input.methodhandler('finders',input.normalize_name(filename), filetype)
 end
-function input.opentexfile(instance,filename)
-    return input.methodhandler('openers',instance, input.normalize_name(filename))
+function input.opentexfile(filename)
+    return input.methodhandler('openers',input.normalize_name(filename))
 end
 
-function input.findbinfile(instance, filename, filetype)
-    return input.methodhandler('finders',instance, input.normalize_name(filename), filetype)
+function input.findbinfile(filename, filetype)
+    return input.methodhandler('finders',input.normalize_name(filename), filetype)
 end
-function input.openbinfile(instance,filename)
-    return input.methodhandler('loaders',instance, input.normalize_name(filename))
+function input.openbinfile(filename)
+    return input.methodhandler('loaders',input.normalize_name(filename))
 end
 
-function input.loadbinfile(instance, filename, filetype)
-    local fname = input.findbinfile(instance, input.normalize_name(filename), filetype)
+function input.loadbinfile(filename, filetype)
+    local fname = input.findbinfile(input.normalize_name(filename), filetype)
     if fname and fname ~= "" then
-        return input.openbinfile(instance,fname)
+        return input.openbinfile(fname)
     else
         return unpack(input.loaders.notfound)
     end
 end
 
-function input.texdatablob(instance, filename, filetype)
-    local ok, data, size = input.loadbinfile(instance, filename, filetype)
+function input.texdatablob(filename, filetype)
+    local ok, data, size = input.loadbinfile(filename, filetype)
     return data or ""
 end
 
 input.loadtexfile = input.texdatablob
 
-function input.openfile(filename) -- brrr texmf.instance here  / todo ! ! ! ! !
-    local fullname = input.findtexfile(texmf.instance, filename)
+function input.openfile(filename)
+    local fullname = input.findtexfile(filename)
     if fullname and (fullname ~= "") then
-        return input.opentexfile(texmf.instance, fullname)
+        return input.opentexfile(fullname)
     else
         return nil
     end
@@ -2095,16 +2127,18 @@ end
 -- beware: i need to check where we still need a / on windows:
 
 function input.clean_path(str)
---~     return (((str:gsub("\\","/")):gsub("^!+","")):gsub("//+","//"))
     if str then
-        return ((str:gsub("\\","/")):gsub("^!+",""))
+        str = str:gsub("\\","/")
+        str = str:gsub("^!+","")
+        str = str:gsub("^~",input.homedir)
+        return str
     else
         return nil
     end
 end
 
 function input.do_with_path(name,func)
-    for _, v in pairs(input.expanded_path_list(instance,name)) do
+    for _, v in pairs(input.expanded_path_list(name)) do
         func("^"..input.clean_path(v))
     end
 end
@@ -2113,7 +2147,8 @@ function input.do_with_var(name,func)
     func(input.aux.expanded_var(name))
 end
 
-function input.with_files(instance,pattern,handle)
+function input.with_files(pattern,handle)
+    local instance = input.instance
     for _, hash in ipairs(instance.hashes) do
         local blobpath = hash.tag
         local blobtype = hash.type
@@ -2140,37 +2175,22 @@ function input.with_files(instance,patte
     end
 end
 
---~ function input.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
---~     newname = file.addsuffix(newname,"lua")
---~     local newscript = input.clean_path(input.find_file(instance, newname))
---~     local oldscript = input.clean_path(oldname)
---~     input.report("old script", oldscript)
---~     input.report("new script", newscript)
---~     if oldscript ~= newscript and (oldscript:find(file.removesuffix(newname).."$") or oldscript:find(newname.."$")) then
---~         local newdata = io.loaddata(newscript)
---~         if newdata then
---~             input.report("old script content replaced by new content")
---~             io.savedata(oldscript,newdata)
---~         end
---~     end
---~ end
-
-function input.update_script(instance,oldname,newname) -- oldname -> own.name, not per se a suffix
+function input.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
     local scriptpath = "scripts/context/lua"
     newname = file.addsuffix(newname,"lua")
     local oldscript = input.clean_path(oldname)
-    input.report("to be replaced old script", oldscript)
-    local newscripts = input.find_files(instance, newname) or { }
+    input.report("to be replaced old script %s", oldscript)
+    local newscripts = input.find_files(newname) or { }
     if #newscripts == 0 then
         input.report("unable to locate new script")
     else
         for _, newscript in ipairs(newscripts) do
             newscript = input.clean_path(newscript)
-            input.report("checking new script", newscript)
+            input.report("checking new script %s", newscript)
             if oldscript == newscript then
                 input.report("old and new script are the same")
             elseif not newscript:find(scriptpath) then
-                input.report("new script should come from",scriptpath)
+                input.report("new script should come from %s",scriptpath)
             elseif not (oldscript:find(file.removesuffix(newname).."$") or oldscript:find(newname.."$")) then
                 input.report("invalid new script name")
             else
@@ -2198,10 +2218,10 @@ do
 
     local resolvers = { }
 
-    resolvers.environment = function(instance,str)
+    resolvers.environment = function(str)
         return input.clean_path(os.getenv(str) or os.getenv(str:upper()) or os.getenv(str:lower()) or "")
     end
-    resolvers.relative = function(instance,str,n)
+    resolvers.relative = function(str,n)
         if io.exists(str) then
             -- nothing
         elseif io.exists("./" .. str) then
@@ -2219,16 +2239,16 @@ do
         end
         return input.clean_path(str)
     end
-    resolvers.locate = function(instance,str)
-        local fullname = input.find_given_file(instance,str) or ""
+    resolvers.locate = function(str)
+        local fullname = input.find_given_file(str) or ""
         return input.clean_path((fullname ~= "" and fullname) or str)
     end
-    resolvers.filename = function(instance,str)
-        local fullname = input.find_given_file(instance,str) or ""
+    resolvers.filename = function(str)
+        local fullname = input.find_given_file(str) or ""
         return input.clean_path(file.basename((fullname ~= "" and fullname) or str))
     end
-    resolvers.pathname = function(instance,str)
-        local fullname = input.find_given_file(instance,str) or ""
+    resolvers.pathname = function(str)
+        local fullname = input.find_given_file(str) or ""
         return input.clean_path(file.dirname((fullname ~= "" and fullname) or str))
     end
 
@@ -2240,15 +2260,15 @@ do
     resolvers.file = resolvers.filename
     resolvers.path = resolvers.pathname
 
-    local function resolve(instance,str)
+    local function resolve(str)
         if type(str) == "table" then
             for k, v in pairs(str) do
-                str[k] = resolve(instance,v) or v
+                str[k] = resolve(v) or v
             end
         elseif str and str ~= "" then
-            str = str:gsub("([a-z]+):([^ ]+)", function(method,target)
+            str = str:gsub("([a-z]+):([^ \"\']*)", function(method,target)
                 if resolvers[method] then
-                    return resolvers[method](instance,target)
+                    return resolvers[method](target)
                 else
                     return method .. ":" .. target
                 end
@@ -2257,6 +2277,24 @@ do
         return str
     end
 
+    if os.uname then
+        for k, v in pairs(os.uname()) do
+            if not resolvers[k] then
+                resolvers[k] = function() return v end
+            end
+        end
+    end
+
     input.resolve = resolve
 
 end
+
+function input.boolean_variable(str,default)
+    local b = input.expansion(str)
+    if b == "" then
+        return default
+    else
+        b = toboolean(b)
+        return (b == nil and default) or b
+    end
+end
openSUSE Build Service is sponsored by