From f8583123d8e264910387d015f4d6576551fe0ee4 Mon Sep 17 00:00:00 2001
From: Hans Hagen <pragma@wxs.nl>
Date: Fri, 12 Mar 2010 19:49:00 +0100
Subject: beta 2010.03.12 19:49

---
 scripts/context/lua/luatools.lua            | 179 +++++++++++-----------
 scripts/context/lua/mtxrun.lua              | 201 +++++++++++++------------
 scripts/context/stubs/mswin/luatools.lua    | 179 +++++++++++-----------
 scripts/context/stubs/mswin/mtxrun.lua      | 201 +++++++++++++------------
 scripts/context/stubs/unix/luatools         | 179 +++++++++++-----------
 scripts/context/stubs/unix/mtxrun           | 201 +++++++++++++------------
 tex/context/base/anch-pgr.mkiv              |   2 +-
 tex/context/base/bibl-bib.lua               |   5 +-
 tex/context/base/buff-ini.lua               |   2 +-
 tex/context/base/buff-ini.mkiv              |   6 +-
 tex/context/base/buff-ver.mkiv              |   2 +-
 tex/context/base/cont-log.tex               |  35 ++++-
 tex/context/base/cont-new.tex               |   2 +-
 tex/context/base/context.tex                |   2 +-
 tex/context/base/core-mis.mkiv              |   2 +-
 tex/context/base/core-sys.mkiv              |   2 +-
 tex/context/base/data-res.lua               |  30 ++--
 tex/context/base/data-tex.lua               |   2 +-
 tex/context/base/enco-ini.mkiv              |   4 +-
 tex/context/base/font-ini.mkiv              |  32 ++--
 tex/context/base/l-aux.lua                  |  32 ++--
 tex/context/base/l-dir.lua                  |   6 +-
 tex/context/base/l-file.lua                 |   9 ++
 tex/context/base/l-lpeg.lua                 | 124 +++++++---------
 tex/context/base/l-os.lua                   |   8 +-
 tex/context/base/lxml-lpt.lua               |  10 +-
 tex/context/base/lxml-tab.lua               |  22 ++-
 tex/context/base/lxml-tex.lua               |  43 +++---
 tex/context/base/math-ali.mkiv              |   4 +-
 tex/context/base/math-arr.mkiv              |  12 +-
 tex/context/base/math-ini.mkiv              |   8 +-
 tex/context/base/node-rul.mkiv              |   4 +-
 tex/context/base/pack-rul.mkiv              |   8 +-
 tex/context/base/page-mar.mkiv              |   2 +-
 tex/context/base/page-str.mkiv              |  69 ++-------
 tex/context/base/prop-ini.mkiv              |  16 +-
 tex/context/base/spac-fnt.mkiv              |   3 +
 tex/context/base/spac-ver.lua               |   8 +
 tex/context/base/spac-ver.mkiv              | 222 +++++++++++++++++++++-------
 tex/context/base/strc-blk.lua               |   2 +-
 tex/context/base/strc-def.mkiv              |   1 +
 tex/context/base/strc-des.mkiv              |  30 ++--
 tex/context/base/strc-flt.mkiv              |  42 +++---
 tex/context/base/strc-lnt.mkiv              |   6 +-
 tex/context/base/strc-mar.mkiv              |   6 +-
 tex/context/base/strc-ref.mkiv              |   2 +-
 tex/context/base/strc-reg.mkiv              |   6 +-
 tex/context/base/strc-ren.mkiv              |  54 +++++--
 tex/context/base/strc-sec.mkiv              |  20 ++-
 tex/context/base/strc-syn.mkiv              |  12 +-
 tex/context/base/syst-aux.mkiv              |   5 +
 tex/context/base/tabl-tab.mkiv              |   4 +-
 tex/context/base/type-ini.mkiv              |   2 +-
 tex/context/base/x-asciimath.lua            |   2 +-
 tex/generic/context/luatex-fonts-merged.lua | 131 ++++++++--------
 55 files changed, 1188 insertions(+), 1015 deletions(-)

diff --git a/scripts/context/lua/luatools.lua b/scripts/context/lua/luatools.lua
index 1a579eb69..ea3b47840 100644
--- a/scripts/context/lua/luatools.lua
+++ b/scripts/context/lua/luatools.lua
@@ -336,57 +336,55 @@ if not modules then modules = { } end modules ['l-lpeg'] = {
     license   = "see context related readme files"
 }
 
-lpeg = require("lpeg")
+local lpeg = require("lpeg")
 
-lpeg.patterns = lpeg.patterns or { } -- so that we can share
+lpeg.patterns  = lpeg.patterns or { } -- so that we can share
+local patterns = lpeg.patterns
 
-local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
+local P, R, S, Ct, C, Cs, Cc, V = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.V
 local match = lpeg.match
 
---~ l-lpeg.lua :
-
---~ lpeg.digit         = lpeg.R('09')^1
---~ lpeg.sign          = lpeg.S('+-')^1
---~ lpeg.cardinal      = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
---~ lpeg.integer       = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
---~ lpeg.float         = lpeg.P(lpeg.sign^0 * lpeg.digit^0 * lpeg.P('.') * lpeg.digit^1)
---~ lpeg.number        = lpeg.float + lpeg.integer
---~ lpeg.oct           = lpeg.P("0") * lpeg.R('07')^1
---~ lpeg.hex           = lpeg.P("0x") * (lpeg.R('09') + lpeg.R('AF'))^1
---~ lpeg.uppercase     = lpeg.P("AZ")
---~ lpeg.lowercase     = lpeg.P("az")
-
---~ lpeg.eol           = lpeg.S('\r\n\f')^1 -- includes formfeed
---~ lpeg.space         = lpeg.S(' ')^1
---~ lpeg.nonspace      = lpeg.P(1-lpeg.space)^1
---~ lpeg.whitespace    = lpeg.S(' \r\n\f\t')^1
---~ lpeg.nonwhitespace = lpeg.P(1-lpeg.whitespace)^1
-
-local hash = { }
+local digit, sign      = R('09'), S('+-')
+local cr, lf, crlf     = P("\r"), P("\n"), P("\r\n")
+local utf8byte         = R("\128\191")
+
+patterns.utf8byte      = utf8byte
+patterns.utf8one       = R("\000\127")
+patterns.utf8two       = R("\194\223") * utf8byte
+patterns.utf8three     = R("\224\239") * utf8byte * utf8byte
+patterns.utf8four      = R("\240\244") * utf8byte * utf8byte * utf8byte
+
+patterns.digit         = digit
+patterns.sign          = sign
+patterns.cardinal      = sign^0 * digit^1
+patterns.integer       = sign^0 * digit^1
+patterns.float         = sign^0 * digit^0 * P('.') * digit^1
+patterns.number        = patterns.float + patterns.integer
+patterns.oct           = P("0") * R("07")^1
+patterns.hex           = P("0x") * R("09","AF")^1
+patterns.lowercase     = R("az")
+patterns.uppercase     = R("AZ")
+patterns.letter        = patterns.lowercase + patterns.uppercase
+patterns.space         = S(" ")
+patterns.eol           = S("\n\r")
+patterns.spacer        = S(" \t\f\v")  -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
+patterns.newline       = crlf + cr + lf
+patterns.nonspace      = 1 - patterns.space
+patterns.nonspacer     = 1 - patterns.spacer
+patterns.whitespace    = patterns.eol + patterns.spacer
+patterns.nonwhitespace = 1 - patterns.whitespace
+patterns.utf8          = patterns.utf8one + patterns.utf8two + patterns.utf8three + patterns.utf8four
+patterns.utfbom        = P('\000\000\254\255') + P('\255\254\000\000') + P('\255\254') + P('\254\255') + P('\239\187\191')
 
 function lpeg.anywhere(pattern) --slightly adapted from website
-    return P { P(pattern) + 1 * lpeg.V(1) }
-end
-
-function lpeg.startswith(pattern) --slightly adapted
-    return P(pattern)
+    return P { P(pattern) + 1 * V(1) } -- why so complex?
 end
 
 function lpeg.splitter(pattern, action)
     return (((1-P(pattern))^1)/action+1)^0
 end
 
--- variant:
-
---~ local parser = lpeg.Ct(lpeg.splitat(newline))
-
-local crlf     = P("\r\n")
-local cr       = P("\r")
-local lf       = P("\n")
-local space    = S(" \t\f\v")  -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
-local newline  = crlf + cr + lf
-local spacing  = space^0 * newline
-
+local spacing  = patterns.spacer^0 * patterns.newline -- sort of strip
 local empty    = spacing * Cc("")
 local nonempty = Cs((1-spacing)^1) * spacing^-1
 local content  = (empty + nonempty)^1
@@ -397,7 +395,7 @@ function string:splitlines()
     return match(capture,self)
 end
 
-lpeg.linebyline = content -- better make a sublibrary
+patterns.textline = content
 
 --~ local p = lpeg.splitat("->",false)  print(match(p,"oeps->what->more"))  -- oeps what more
 --~ local p = lpeg.splitat("->",true)   print(match(p,"oeps->what->more"))  -- oeps what->more
@@ -463,37 +461,31 @@ end
 
 --~ from roberto's site:
 --~
---~ -- decode a two-byte UTF-8 sequence
---~ local function f2 (s)
+--~ local function f1 = string.byte
+--~
+--~ local function f2(s)
 --~   local c1, c2 = string.byte(s, 1, 2)
 --~   return c1 * 64 + c2 - 12416
 --~ end
 --~
---~ -- decode a three-byte UTF-8 sequence
---~ local function f3 (s)
+--~ local function f3(s)
 --~   local c1, c2, c3 = string.byte(s, 1, 3)
 --~   return (c1 * 64 + c2) * 64 + c3 - 925824
 --~ end
 --~
---~ -- decode a four-byte UTF-8 sequence
---~ local function f4 (s)
+--~ local function f4(s)
 --~   local c1, c2, c3, c4 = string.byte(s, 1, 4)
 --~   return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168
 --~ end
 --~
 --~ local cont = lpeg.R("\128\191")   -- continuation byte
---~
---~ local utf8 = lpeg.R("\0\127") / string.byte
+--~ local utf8 = lpeg.R("\0\127") / f1
 --~            + lpeg.R("\194\223") * cont / f2
 --~            + lpeg.R("\224\239") * cont * cont / f3
 --~            + lpeg.R("\240\244") * cont * cont * cont / f4
 --~
 --~ local decode_pattern = lpeg.Ct(utf8^0) * -1
 
-local cont = R("\128\191")   -- continuation byte
-
-lpeg.patterns.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont
-
 
 end -- of closure
 
@@ -1720,7 +1712,7 @@ if not modules then modules = { } end modules ['l-os'] = {
 
 -- maybe build io.flush in os.execute
 
-local find, format = string.find, string.format
+local find, format, gsub = string.find, string.format, string.gsub
 local random, ceil = math.random, math.ceil
 
 local execute, spawn, exec, ioflush = os.execute, os.spawn or os.execute, os.exec or os.execute, io.flush
@@ -1800,13 +1792,15 @@ end
 
 -- no need for function anymore as we have more clever code and helpers now
 
-os.resolvers = { }
+os.resolvers = os.resolvers or { }
+
+local resolvers = os.resolvers
 
 local osmt = getmetatable(os) or { __index = function(t,k) t[k] = "unset" return "unset" end }
 local osix = osmt.__index
 
 osmt.__index = function(t,k)
-    return (os.resolvers[k] or osix)(t,k)
+    return (resolvers[k] or osix)(t,k)
 end
 
 setmetatable(os,osmt)
@@ -2318,6 +2312,15 @@ end
 -- test { "/aa", "/aa/bb", "/aa/bb/cc", "/aa/bb/cc.dd", "/aa/bb/cc.dd.ee" }
 -- test { "aa", "aa/bb", "aa/bb/cc", "aa/bb/cc.dd", "aa/bb/cc.dd.ee" }
 
+--~ -- todo:
+--~
+--~ if os.type == "windows" then
+--~     local currentdir = lfs.currentdir
+--~     function lfs.currentdir()
+--~         return (gsub(currentdir(),"\\","/"))
+--~     end
+--~ end
+
 
 end -- of closure
 
@@ -2549,6 +2552,8 @@ if not modules then modules = { } end modules ['l-dir'] = {
     license   = "see context related readme files"
 }
 
+-- dir.expand_name will be merged with cleanpath and collapsepath
+
 local type = type
 local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
 local lpegmatch = lpeg.match
@@ -2717,7 +2722,7 @@ end
 
 local make_indeed = true -- false
 
-if string.find(os.getenv("PATH"),";") then
+if string.find(os.getenv("PATH"),";") then -- os.type == "windows"
 
     function dir.mkdirs(...)
         local str, pth = "", ""
@@ -2784,7 +2789,7 @@ if string.find(os.getenv("PATH"),";") then
 --~         print(dir.mkdirs("///a/b/c"))
 --~         print(dir.mkdirs("a/bbb//ccc/"))
 
-    function dir.expand_name(str)
+    function dir.expand_name(str) -- will be merged with cleanpath and collapsepath
         local first, nothing, last = match(str,"^(//)(//*)(.*)$")
         if first then
             first = lfs.currentdir() .. "/"
@@ -3386,6 +3391,15 @@ local concat, format, gmatch = table.concat, string.format, string.gmatch
 local tostring, type = tostring, type
 local lpegmatch = lpeg.match
 
+local P, R, V = lpeg.P, lpeg.R, lpeg.V
+
+local escape, left, right = P("\\"), P('{'), P('}')
+
+lpeg.patterns.balanced = P {
+    [1] = ((escape * (left+right)) + (1 - (left+right)) + V(2))^0,
+    [2] = left * V(1) * right
+}
+
 local space     = lpeg.P(' ')
 local equal     = lpeg.P("=")
 local comma     = lpeg.P(",")
@@ -3558,21 +3572,14 @@ end
 
 -- temporary here
 
-local digit    = lpeg.R("09")
-local period   = lpeg.P(".")
-local zero     = lpeg.P("0")
-
---~ local finish   = lpeg.P(-1)
---~ local nodigit  = (1-digit) + finish
---~ local case_1   = (period * zero^1 * #nodigit)/"" -- .000
---~ local case_2   = (period * (1-(zero^0/"") * #nodigit)^1 * (zero^0/"") * nodigit) -- .010 .10 .100100
-
+local digit         = lpeg.R("09")
+local period        = lpeg.P(".")
+local zero          = lpeg.P("0")
 local trailingzeros = zero^0 * -digit -- suggested by Roberto R
-local case_1 = period * trailingzeros / ""
-local case_2 = period * (digit - trailingzeros)^1 * (trailingzeros / "")
-
-local number   = digit^1 * (case_1 + case_2)
-local stripper = lpeg.Cs((number + 1)^0)
+local case_1        = period * trailingzeros / ""
+local case_2        = period * (digit - trailingzeros)^1 * (trailingzeros / "")
+local number        = digit^1 * (case_1 + case_2)
+local stripper      = lpeg.Cs((number + 1)^0)
 
 --~ local sample = "bla 11.00 bla 11 bla 0.1100 bla 1.00100 bla 0.00 bla 0.001 bla 1.1100 bla 0.100100100 bla 0.00100100100"
 --~ collectgarbage("collect")
@@ -5671,22 +5678,26 @@ local cache = { }
 local function split_kpse_path(str) -- beware, this can be either a path or a {specification}
     local found = cache[str]
     if not found then
-        str = gsub(str,"\\","/")
-        local split = (find(str,";") and checkedsplit(str,";")) or checkedsplit(str,io.pathseparator)
-        found = { }
-        for i=1,#split do
-            local s = split[i]
-            if not find(s,"^{*unset}*") then
-                found[#found+1] = s
+        if str == "" then
+            found = { }
+        else
+            str = gsub(str,"\\","/")
+            local split = (find(str,";") and checkedsplit(str,";")) or checkedsplit(str,io.pathseparator)
+            found = { }
+            for i=1,#split do
+                local s = split[i]
+                if not find(s,"^{*unset}*") then
+                    found[#found+1] = s
+                end
             end
-        end
-        if trace_expansions then
-            logs.report("fileio","splitting path specification '%s'",str)
-            for k,v in ipairs(found) do
-                logs.report("fileio","% 4i: %s",k,v)
+            if trace_expansions then
+                logs.report("fileio","splitting path specification '%s'",str)
+                for k,v in ipairs(found) do
+                    logs.report("fileio","% 4i: %s",k,v)
+                end
             end
+            cache[str] = found
         end
-        cache[str] = found
     end
     return found
 end
diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua
index ef7eda9b0..447d958b2 100644
--- a/scripts/context/lua/mtxrun.lua
+++ b/scripts/context/lua/mtxrun.lua
@@ -345,57 +345,55 @@ if not modules then modules = { } end modules ['l-lpeg'] = {
     license   = "see context related readme files"
 }
 
-lpeg = require("lpeg")
+local lpeg = require("lpeg")
 
-lpeg.patterns = lpeg.patterns or { } -- so that we can share
+lpeg.patterns  = lpeg.patterns or { } -- so that we can share
+local patterns = lpeg.patterns
 
-local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
+local P, R, S, Ct, C, Cs, Cc, V = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.V
 local match = lpeg.match
 
---~ l-lpeg.lua :
-
---~ lpeg.digit         = lpeg.R('09')^1
---~ lpeg.sign          = lpeg.S('+-')^1
---~ lpeg.cardinal      = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
---~ lpeg.integer       = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
---~ lpeg.float         = lpeg.P(lpeg.sign^0 * lpeg.digit^0 * lpeg.P('.') * lpeg.digit^1)
---~ lpeg.number        = lpeg.float + lpeg.integer
---~ lpeg.oct           = lpeg.P("0") * lpeg.R('07')^1
---~ lpeg.hex           = lpeg.P("0x") * (lpeg.R('09') + lpeg.R('AF'))^1
---~ lpeg.uppercase     = lpeg.P("AZ")
---~ lpeg.lowercase     = lpeg.P("az")
-
---~ lpeg.eol           = lpeg.S('\r\n\f')^1 -- includes formfeed
---~ lpeg.space         = lpeg.S(' ')^1
---~ lpeg.nonspace      = lpeg.P(1-lpeg.space)^1
---~ lpeg.whitespace    = lpeg.S(' \r\n\f\t')^1
---~ lpeg.nonwhitespace = lpeg.P(1-lpeg.whitespace)^1
-
-local hash = { }
+local digit, sign      = R('09'), S('+-')
+local cr, lf, crlf     = P("\r"), P("\n"), P("\r\n")
+local utf8byte         = R("\128\191")
+
+patterns.utf8byte      = utf8byte
+patterns.utf8one       = R("\000\127")
+patterns.utf8two       = R("\194\223") * utf8byte
+patterns.utf8three     = R("\224\239") * utf8byte * utf8byte
+patterns.utf8four      = R("\240\244") * utf8byte * utf8byte * utf8byte
+
+patterns.digit         = digit
+patterns.sign          = sign
+patterns.cardinal      = sign^0 * digit^1
+patterns.integer       = sign^0 * digit^1
+patterns.float         = sign^0 * digit^0 * P('.') * digit^1
+patterns.number        = patterns.float + patterns.integer
+patterns.oct           = P("0") * R("07")^1
+patterns.hex           = P("0x") * R("09","AF")^1
+patterns.lowercase     = R("az")
+patterns.uppercase     = R("AZ")
+patterns.letter        = patterns.lowercase + patterns.uppercase
+patterns.space         = S(" ")
+patterns.eol           = S("\n\r")
+patterns.spacer        = S(" \t\f\v")  -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
+patterns.newline       = crlf + cr + lf
+patterns.nonspace      = 1 - patterns.space
+patterns.nonspacer     = 1 - patterns.spacer
+patterns.whitespace    = patterns.eol + patterns.spacer
+patterns.nonwhitespace = 1 - patterns.whitespace
+patterns.utf8          = patterns.utf8one + patterns.utf8two + patterns.utf8three + patterns.utf8four
+patterns.utfbom        = P('\000\000\254\255') + P('\255\254\000\000') + P('\255\254') + P('\254\255') + P('\239\187\191')
 
 function lpeg.anywhere(pattern) --slightly adapted from website
-    return P { P(pattern) + 1 * lpeg.V(1) }
-end
-
-function lpeg.startswith(pattern) --slightly adapted
-    return P(pattern)
+    return P { P(pattern) + 1 * V(1) } -- why so complex?
 end
 
 function lpeg.splitter(pattern, action)
     return (((1-P(pattern))^1)/action+1)^0
 end
 
--- variant:
-
---~ local parser = lpeg.Ct(lpeg.splitat(newline))
-
-local crlf     = P("\r\n")
-local cr       = P("\r")
-local lf       = P("\n")
-local space    = S(" \t\f\v")  -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
-local newline  = crlf + cr + lf
-local spacing  = space^0 * newline
-
+local spacing  = patterns.spacer^0 * patterns.newline -- sort of strip
 local empty    = spacing * Cc("")
 local nonempty = Cs((1-spacing)^1) * spacing^-1
 local content  = (empty + nonempty)^1
@@ -406,7 +404,7 @@ function string:splitlines()
     return match(capture,self)
 end
 
-lpeg.linebyline = content -- better make a sublibrary
+patterns.textline = content
 
 --~ local p = lpeg.splitat("->",false)  print(match(p,"oeps->what->more"))  -- oeps what more
 --~ local p = lpeg.splitat("->",true)   print(match(p,"oeps->what->more"))  -- oeps what->more
@@ -472,37 +470,31 @@ end
 
 --~ from roberto's site:
 --~
---~ -- decode a two-byte UTF-8 sequence
---~ local function f2 (s)
+--~ local function f1 = string.byte
+--~
+--~ local function f2(s)
 --~   local c1, c2 = string.byte(s, 1, 2)
 --~   return c1 * 64 + c2 - 12416
 --~ end
 --~
---~ -- decode a three-byte UTF-8 sequence
---~ local function f3 (s)
+--~ local function f3(s)
 --~   local c1, c2, c3 = string.byte(s, 1, 3)
 --~   return (c1 * 64 + c2) * 64 + c3 - 925824
 --~ end
 --~
---~ -- decode a four-byte UTF-8 sequence
---~ local function f4 (s)
+--~ local function f4(s)
 --~   local c1, c2, c3, c4 = string.byte(s, 1, 4)
 --~   return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168
 --~ end
 --~
 --~ local cont = lpeg.R("\128\191")   -- continuation byte
---~
---~ local utf8 = lpeg.R("\0\127") / string.byte
+--~ local utf8 = lpeg.R("\0\127") / f1
 --~            + lpeg.R("\194\223") * cont / f2
 --~            + lpeg.R("\224\239") * cont * cont / f3
 --~            + lpeg.R("\240\244") * cont * cont * cont / f4
 --~
 --~ local decode_pattern = lpeg.Ct(utf8^0) * -1
 
-local cont = R("\128\191")   -- continuation byte
-
-lpeg.patterns.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont
-
 
 end -- of closure
 
@@ -1729,7 +1721,7 @@ if not modules then modules = { } end modules ['l-os'] = {
 
 -- maybe build io.flush in os.execute
 
-local find, format = string.find, string.format
+local find, format, gsub = string.find, string.format, string.gsub
 local random, ceil = math.random, math.ceil
 
 local execute, spawn, exec, ioflush = os.execute, os.spawn or os.execute, os.exec or os.execute, io.flush
@@ -1809,13 +1801,15 @@ end
 
 -- no need for function anymore as we have more clever code and helpers now
 
-os.resolvers = { }
+os.resolvers = os.resolvers or { }
+
+local resolvers = os.resolvers
 
 local osmt = getmetatable(os) or { __index = function(t,k) t[k] = "unset" return "unset" end }
 local osix = osmt.__index
 
 osmt.__index = function(t,k)
-    return (os.resolvers[k] or osix)(t,k)
+    return (resolvers[k] or osix)(t,k)
 end
 
 setmetatable(os,osmt)
@@ -2327,6 +2321,15 @@ end
 -- test { "/aa", "/aa/bb", "/aa/bb/cc", "/aa/bb/cc.dd", "/aa/bb/cc.dd.ee" }
 -- test { "aa", "aa/bb", "aa/bb/cc", "aa/bb/cc.dd", "aa/bb/cc.dd.ee" }
 
+--~ -- todo:
+--~
+--~ if os.type == "windows" then
+--~     local currentdir = lfs.currentdir
+--~     function lfs.currentdir()
+--~         return (gsub(currentdir(),"\\","/"))
+--~     end
+--~ end
+
 
 end -- of closure
 
@@ -2558,6 +2561,8 @@ if not modules then modules = { } end modules ['l-dir'] = {
     license   = "see context related readme files"
 }
 
+-- dir.expand_name will be merged with cleanpath and collapsepath
+
 local type = type
 local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
 local lpegmatch = lpeg.match
@@ -2726,7 +2731,7 @@ end
 
 local make_indeed = true -- false
 
-if string.find(os.getenv("PATH"),";") then
+if string.find(os.getenv("PATH"),";") then -- os.type == "windows"
 
     function dir.mkdirs(...)
         local str, pth = "", ""
@@ -2793,7 +2798,7 @@ if string.find(os.getenv("PATH"),";") then
 --~         print(dir.mkdirs("///a/b/c"))
 --~         print(dir.mkdirs("a/bbb//ccc/"))
 
-    function dir.expand_name(str)
+    function dir.expand_name(str) -- will be merged with cleanpath and collapsepath
         local first, nothing, last = match(str,"^(//)(//*)(.*)$")
         if first then
             first = lfs.currentdir() .. "/"
@@ -3196,6 +3201,15 @@ local concat, format, gmatch = table.concat, string.format, string.gmatch
 local tostring, type = tostring, type
 local lpegmatch = lpeg.match
 
+local P, R, V = lpeg.P, lpeg.R, lpeg.V
+
+local escape, left, right = P("\\"), P('{'), P('}')
+
+lpeg.patterns.balanced = P {
+    [1] = ((escape * (left+right)) + (1 - (left+right)) + V(2))^0,
+    [2] = left * V(1) * right
+}
+
 local space     = lpeg.P(' ')
 local equal     = lpeg.P("=")
 local comma     = lpeg.P(",")
@@ -3368,21 +3382,14 @@ end
 
 -- temporary here
 
-local digit    = lpeg.R("09")
-local period   = lpeg.P(".")
-local zero     = lpeg.P("0")
-
---~ local finish   = lpeg.P(-1)
---~ local nodigit  = (1-digit) + finish
---~ local case_1   = (period * zero^1 * #nodigit)/"" -- .000
---~ local case_2   = (period * (1-(zero^0/"") * #nodigit)^1 * (zero^0/"") * nodigit) -- .010 .10 .100100
-
+local digit         = lpeg.R("09")
+local period        = lpeg.P(".")
+local zero          = lpeg.P("0")
 local trailingzeros = zero^0 * -digit -- suggested by Roberto R
-local case_1 = period * trailingzeros / ""
-local case_2 = period * (digit - trailingzeros)^1 * (trailingzeros / "")
-
-local number   = digit^1 * (case_1 + case_2)
-local stripper = lpeg.Cs((number + 1)^0)
+local case_1        = period * trailingzeros / ""
+local case_2        = period * (digit - trailingzeros)^1 * (trailingzeros / "")
+local number        = digit^1 * (case_1 + case_2)
+local stripper      = lpeg.Cs((number + 1)^0)
 
 --~ local sample = "bla 11.00 bla 11 bla 0.1100 bla 1.00100 bla 0.00 bla 0.001 bla 1.1100 bla 0.100100100 bla 0.00100100100"
 --~ collectgarbage("collect")
@@ -3820,6 +3827,7 @@ local type, next, setmetatable, getmetatable, tonumber = type, next, setmetatabl
 local format, lower, find, match = string.format, string.lower, string.find, string.match
 local utfchar = unicode.utf8.char
 local lpegmatch = lpeg.match
+local P, S, R, C, V, C, Cs = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.C, lpeg.Cs
 
 --[[ldx--
 <p>First a hack to enable namespace resolving. A namespace is characterized by
@@ -3831,7 +3839,7 @@ much cleaner.</p>
 
 xml.xmlns = xml.xmlns or { }
 
-local check = lpeg.P(false)
+local check = P(false)
 local parse = check
 
 --[[ldx--
@@ -3844,8 +3852,8 @@ xml.registerns("mml","mathml")
 --ldx]]--
 
 function xml.registerns(namespace, pattern) -- pattern can be an lpeg
-    check = check + lpeg.C(lpeg.P(lower(pattern))) / namespace
-    parse = lpeg.P { lpeg.P(check) + 1 * lpeg.V(1) }
+    check = check + C(P(lower(pattern))) / namespace
+    parse = P { P(check) + 1 * V(1) }
 end
 
 --[[ldx--
@@ -4123,8 +4131,6 @@ local function fromdec(s)
     end
 end
 
-local P, S, R, C, V, Cs = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.Cs
-
 local rest = (1-P(";"))^0
 local many = P(1)^0
 
@@ -4226,10 +4232,7 @@ local valid            = R('az', 'AZ', '09') + S('_-.')
 local name_yes         = C(valid^1) * colon * C(valid^1)
 local name_nop         = C(P(true)) * C(valid^1)
 local name             = name_yes + name_nop
-
-local utfbom           = P('\000\000\254\255') + P('\255\254\000\000') +
-                         P('\255\254') + P('\254\255') + P('\239\187\191') -- no capture
-
+local utfbom           = lpeg.patterns.utfbom -- no capture
 local spacing          = C(space^0)
 
 ----- entitycontent    = (1-open-semicolon)^0
@@ -4314,10 +4317,10 @@ local doctype          = (spacing * begindoctype     * somedoctype     * enddoct
 
 --  nicer but slower:
 --
---  local instruction = (lpeg.Cc("@pi@") * spacing * begininstruction * someinstruction * endinstruction) / add_special
---  local comment     = (lpeg.Cc("@cm@") * spacing * begincomment     * somecomment     * endcomment    ) / add_special
---  local cdata       = (lpeg.Cc("@cd@") * spacing * begincdata       * somecdata       * endcdata      ) / add_special
---  local doctype     = (lpeg.Cc("@dt@") * spacing * begindoctype     * somedoctype     * enddoctype    ) / add_special
+--  local instruction = (Cc("@pi@") * spacing * begininstruction * someinstruction * endinstruction) / add_special
+--  local comment     = (Cc("@cm@") * spacing * begincomment     * somecomment     * endcomment    ) / add_special
+--  local cdata       = (Cc("@cd@") * spacing * begincdata       * somecdata       * endcdata      ) / add_special
+--  local doctype     = (Cc("@dt@") * spacing * begindoctype     * somedoctype     * enddoctype    ) / add_special
 
 local trailer = space^0 * (text_unparsed/set_message)^0
 
@@ -8765,22 +8768,26 @@ local cache = { }
 local function split_kpse_path(str) -- beware, this can be either a path or a {specification}
     local found = cache[str]
     if not found then
-        str = gsub(str,"\\","/")
-        local split = (find(str,";") and checkedsplit(str,";")) or checkedsplit(str,io.pathseparator)
-        found = { }
-        for i=1,#split do
-            local s = split[i]
-            if not find(s,"^{*unset}*") then
-                found[#found+1] = s
+        if str == "" then
+            found = { }
+        else
+            str = gsub(str,"\\","/")
+            local split = (find(str,";") and checkedsplit(str,";")) or checkedsplit(str,io.pathseparator)
+            found = { }
+            for i=1,#split do
+                local s = split[i]
+                if not find(s,"^{*unset}*") then
+                    found[#found+1] = s
+                end
             end
-        end
-        if trace_expansions then
-            logs.report("fileio","splitting path specification '%s'",str)
-            for k,v in ipairs(found) do
-                logs.report("fileio","% 4i: %s",k,v)
+            if trace_expansions then
+                logs.report("fileio","splitting path specification '%s'",str)
+                for k,v in ipairs(found) do
+                    logs.report("fileio","% 4i: %s",k,v)
+                end
             end
+            cache[str] = found
         end
-        cache[str] = found
     end
     return found
 end
diff --git a/scripts/context/stubs/mswin/luatools.lua b/scripts/context/stubs/mswin/luatools.lua
index 1a579eb69..ea3b47840 100644
--- a/scripts/context/stubs/mswin/luatools.lua
+++ b/scripts/context/stubs/mswin/luatools.lua
@@ -336,57 +336,55 @@ if not modules then modules = { } end modules ['l-lpeg'] = {
     license   = "see context related readme files"
 }
 
-lpeg = require("lpeg")
+local lpeg = require("lpeg")
 
-lpeg.patterns = lpeg.patterns or { } -- so that we can share
+lpeg.patterns  = lpeg.patterns or { } -- so that we can share
+local patterns = lpeg.patterns
 
-local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
+local P, R, S, Ct, C, Cs, Cc, V = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.V
 local match = lpeg.match
 
---~ l-lpeg.lua :
-
---~ lpeg.digit         = lpeg.R('09')^1
---~ lpeg.sign          = lpeg.S('+-')^1
---~ lpeg.cardinal      = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
---~ lpeg.integer       = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
---~ lpeg.float         = lpeg.P(lpeg.sign^0 * lpeg.digit^0 * lpeg.P('.') * lpeg.digit^1)
---~ lpeg.number        = lpeg.float + lpeg.integer
---~ lpeg.oct           = lpeg.P("0") * lpeg.R('07')^1
---~ lpeg.hex           = lpeg.P("0x") * (lpeg.R('09') + lpeg.R('AF'))^1
---~ lpeg.uppercase     = lpeg.P("AZ")
---~ lpeg.lowercase     = lpeg.P("az")
-
---~ lpeg.eol           = lpeg.S('\r\n\f')^1 -- includes formfeed
---~ lpeg.space         = lpeg.S(' ')^1
---~ lpeg.nonspace      = lpeg.P(1-lpeg.space)^1
---~ lpeg.whitespace    = lpeg.S(' \r\n\f\t')^1
---~ lpeg.nonwhitespace = lpeg.P(1-lpeg.whitespace)^1
-
-local hash = { }
+local digit, sign      = R('09'), S('+-')
+local cr, lf, crlf     = P("\r"), P("\n"), P("\r\n")
+local utf8byte         = R("\128\191")
+
+patterns.utf8byte      = utf8byte
+patterns.utf8one       = R("\000\127")
+patterns.utf8two       = R("\194\223") * utf8byte
+patterns.utf8three     = R("\224\239") * utf8byte * utf8byte
+patterns.utf8four      = R("\240\244") * utf8byte * utf8byte * utf8byte
+
+patterns.digit         = digit
+patterns.sign          = sign
+patterns.cardinal      = sign^0 * digit^1
+patterns.integer       = sign^0 * digit^1
+patterns.float         = sign^0 * digit^0 * P('.') * digit^1
+patterns.number        = patterns.float + patterns.integer
+patterns.oct           = P("0") * R("07")^1
+patterns.hex           = P("0x") * R("09","AF")^1
+patterns.lowercase     = R("az")
+patterns.uppercase     = R("AZ")
+patterns.letter        = patterns.lowercase + patterns.uppercase
+patterns.space         = S(" ")
+patterns.eol           = S("\n\r")
+patterns.spacer        = S(" \t\f\v")  -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
+patterns.newline       = crlf + cr + lf
+patterns.nonspace      = 1 - patterns.space
+patterns.nonspacer     = 1 - patterns.spacer
+patterns.whitespace    = patterns.eol + patterns.spacer
+patterns.nonwhitespace = 1 - patterns.whitespace
+patterns.utf8          = patterns.utf8one + patterns.utf8two + patterns.utf8three + patterns.utf8four
+patterns.utfbom        = P('\000\000\254\255') + P('\255\254\000\000') + P('\255\254') + P('\254\255') + P('\239\187\191')
 
 function lpeg.anywhere(pattern) --slightly adapted from website
-    return P { P(pattern) + 1 * lpeg.V(1) }
-end
-
-function lpeg.startswith(pattern) --slightly adapted
-    return P(pattern)
+    return P { P(pattern) + 1 * V(1) } -- why so complex?
 end
 
 function lpeg.splitter(pattern, action)
     return (((1-P(pattern))^1)/action+1)^0
 end
 
--- variant:
-
---~ local parser = lpeg.Ct(lpeg.splitat(newline))
-
-local crlf     = P("\r\n")
-local cr       = P("\r")
-local lf       = P("\n")
-local space    = S(" \t\f\v")  -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
-local newline  = crlf + cr + lf
-local spacing  = space^0 * newline
-
+local spacing  = patterns.spacer^0 * patterns.newline -- sort of strip
 local empty    = spacing * Cc("")
 local nonempty = Cs((1-spacing)^1) * spacing^-1
 local content  = (empty + nonempty)^1
@@ -397,7 +395,7 @@ function string:splitlines()
     return match(capture,self)
 end
 
-lpeg.linebyline = content -- better make a sublibrary
+patterns.textline = content
 
 --~ local p = lpeg.splitat("->",false)  print(match(p,"oeps->what->more"))  -- oeps what more
 --~ local p = lpeg.splitat("->",true)   print(match(p,"oeps->what->more"))  -- oeps what->more
@@ -463,37 +461,31 @@ end
 
 --~ from roberto's site:
 --~
---~ -- decode a two-byte UTF-8 sequence
---~ local function f2 (s)
+--~ local function f1 = string.byte
+--~
+--~ local function f2(s)
 --~   local c1, c2 = string.byte(s, 1, 2)
 --~   return c1 * 64 + c2 - 12416
 --~ end
 --~
---~ -- decode a three-byte UTF-8 sequence
---~ local function f3 (s)
+--~ local function f3(s)
 --~   local c1, c2, c3 = string.byte(s, 1, 3)
 --~   return (c1 * 64 + c2) * 64 + c3 - 925824
 --~ end
 --~
---~ -- decode a four-byte UTF-8 sequence
---~ local function f4 (s)
+--~ local function f4(s)
 --~   local c1, c2, c3, c4 = string.byte(s, 1, 4)
 --~   return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168
 --~ end
 --~
 --~ local cont = lpeg.R("\128\191")   -- continuation byte
---~
---~ local utf8 = lpeg.R("\0\127") / string.byte
+--~ local utf8 = lpeg.R("\0\127") / f1
 --~            + lpeg.R("\194\223") * cont / f2
 --~            + lpeg.R("\224\239") * cont * cont / f3
 --~            + lpeg.R("\240\244") * cont * cont * cont / f4
 --~
 --~ local decode_pattern = lpeg.Ct(utf8^0) * -1
 
-local cont = R("\128\191")   -- continuation byte
-
-lpeg.patterns.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont
-
 
 end -- of closure
 
@@ -1720,7 +1712,7 @@ if not modules then modules = { } end modules ['l-os'] = {
 
 -- maybe build io.flush in os.execute
 
-local find, format = string.find, string.format
+local find, format, gsub = string.find, string.format, string.gsub
 local random, ceil = math.random, math.ceil
 
 local execute, spawn, exec, ioflush = os.execute, os.spawn or os.execute, os.exec or os.execute, io.flush
@@ -1800,13 +1792,15 @@ end
 
 -- no need for function anymore as we have more clever code and helpers now
 
-os.resolvers = { }
+os.resolvers = os.resolvers or { }
+
+local resolvers = os.resolvers
 
 local osmt = getmetatable(os) or { __index = function(t,k) t[k] = "unset" return "unset" end }
 local osix = osmt.__index
 
 osmt.__index = function(t,k)
-    return (os.resolvers[k] or osix)(t,k)
+    return (resolvers[k] or osix)(t,k)
 end
 
 setmetatable(os,osmt)
@@ -2318,6 +2312,15 @@ end
 -- test { "/aa", "/aa/bb", "/aa/bb/cc", "/aa/bb/cc.dd", "/aa/bb/cc.dd.ee" }
 -- test { "aa", "aa/bb", "aa/bb/cc", "aa/bb/cc.dd", "aa/bb/cc.dd.ee" }
 
+--~ -- todo:
+--~
+--~ if os.type == "windows" then
+--~     local currentdir = lfs.currentdir
+--~     function lfs.currentdir()
+--~         return (gsub(currentdir(),"\\","/"))
+--~     end
+--~ end
+
 
 end -- of closure
 
@@ -2549,6 +2552,8 @@ if not modules then modules = { } end modules ['l-dir'] = {
     license   = "see context related readme files"
 }
 
+-- dir.expand_name will be merged with cleanpath and collapsepath
+
 local type = type
 local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
 local lpegmatch = lpeg.match
@@ -2717,7 +2722,7 @@ end
 
 local make_indeed = true -- false
 
-if string.find(os.getenv("PATH"),";") then
+if string.find(os.getenv("PATH"),";") then -- os.type == "windows"
 
     function dir.mkdirs(...)
         local str, pth = "", ""
@@ -2784,7 +2789,7 @@ if string.find(os.getenv("PATH"),";") then
 --~         print(dir.mkdirs("///a/b/c"))
 --~         print(dir.mkdirs("a/bbb//ccc/"))
 
-    function dir.expand_name(str)
+    function dir.expand_name(str) -- will be merged with cleanpath and collapsepath
         local first, nothing, last = match(str,"^(//)(//*)(.*)$")
         if first then
             first = lfs.currentdir() .. "/"
@@ -3386,6 +3391,15 @@ local concat, format, gmatch = table.concat, string.format, string.gmatch
 local tostring, type = tostring, type
 local lpegmatch = lpeg.match
 
+local P, R, V = lpeg.P, lpeg.R, lpeg.V
+
+local escape, left, right = P("\\"), P('{'), P('}')
+
+lpeg.patterns.balanced = P {
+    [1] = ((escape * (left+right)) + (1 - (left+right)) + V(2))^0,
+    [2] = left * V(1) * right
+}
+
 local space     = lpeg.P(' ')
 local equal     = lpeg.P("=")
 local comma     = lpeg.P(",")
@@ -3558,21 +3572,14 @@ end
 
 -- temporary here
 
-local digit    = lpeg.R("09")
-local period   = lpeg.P(".")
-local zero     = lpeg.P("0")
-
---~ local finish   = lpeg.P(-1)
---~ local nodigit  = (1-digit) + finish
---~ local case_1   = (period * zero^1 * #nodigit)/"" -- .000
---~ local case_2   = (period * (1-(zero^0/"") * #nodigit)^1 * (zero^0/"") * nodigit) -- .010 .10 .100100
-
+local digit         = lpeg.R("09")
+local period        = lpeg.P(".")
+local zero          = lpeg.P("0")
 local trailingzeros = zero^0 * -digit -- suggested by Roberto R
-local case_1 = period * trailingzeros / ""
-local case_2 = period * (digit - trailingzeros)^1 * (trailingzeros / "")
-
-local number   = digit^1 * (case_1 + case_2)
-local stripper = lpeg.Cs((number + 1)^0)
+local case_1        = period * trailingzeros / ""
+local case_2        = period * (digit - trailingzeros)^1 * (trailingzeros / "")
+local number        = digit^1 * (case_1 + case_2)
+local stripper      = lpeg.Cs((number + 1)^0)
 
 --~ local sample = "bla 11.00 bla 11 bla 0.1100 bla 1.00100 bla 0.00 bla 0.001 bla 1.1100 bla 0.100100100 bla 0.00100100100"
 --~ collectgarbage("collect")
@@ -5671,22 +5678,26 @@ local cache = { }
 local function split_kpse_path(str) -- beware, this can be either a path or a {specification}
     local found = cache[str]
     if not found then
-        str = gsub(str,"\\","/")
-        local split = (find(str,";") and checkedsplit(str,";")) or checkedsplit(str,io.pathseparator)
-        found = { }
-        for i=1,#split do
-            local s = split[i]
-            if not find(s,"^{*unset}*") then
-                found[#found+1] = s
+        if str == "" then
+            found = { }
+        else
+            str = gsub(str,"\\","/")
+            local split = (find(str,";") and checkedsplit(str,";")) or checkedsplit(str,io.pathseparator)
+            found = { }
+            for i=1,#split do
+                local s = split[i]
+                if not find(s,"^{*unset}*") then
+                    found[#found+1] = s
+                end
             end
-        end
-        if trace_expansions then
-            logs.report("fileio","splitting path specification '%s'",str)
-            for k,v in ipairs(found) do
-                logs.report("fileio","% 4i: %s",k,v)
+            if trace_expansions then
+                logs.report("fileio","splitting path specification '%s'",str)
+                for k,v in ipairs(found) do
+                    logs.report("fileio","% 4i: %s",k,v)
+                end
             end
+            cache[str] = found
         end
-        cache[str] = found
     end
     return found
 end
diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua
index ef7eda9b0..447d958b2 100644
--- a/scripts/context/stubs/mswin/mtxrun.lua
+++ b/scripts/context/stubs/mswin/mtxrun.lua
@@ -345,57 +345,55 @@ if not modules then modules = { } end modules ['l-lpeg'] = {
     license   = "see context related readme files"
 }
 
-lpeg = require("lpeg")
+local lpeg = require("lpeg")
 
-lpeg.patterns = lpeg.patterns or { } -- so that we can share
+lpeg.patterns  = lpeg.patterns or { } -- so that we can share
+local patterns = lpeg.patterns
 
-local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
+local P, R, S, Ct, C, Cs, Cc, V = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.V
 local match = lpeg.match
 
---~ l-lpeg.lua :
-
---~ lpeg.digit         = lpeg.R('09')^1
---~ lpeg.sign          = lpeg.S('+-')^1
---~ lpeg.cardinal      = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
---~ lpeg.integer       = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
---~ lpeg.float         = lpeg.P(lpeg.sign^0 * lpeg.digit^0 * lpeg.P('.') * lpeg.digit^1)
---~ lpeg.number        = lpeg.float + lpeg.integer
---~ lpeg.oct           = lpeg.P("0") * lpeg.R('07')^1
---~ lpeg.hex           = lpeg.P("0x") * (lpeg.R('09') + lpeg.R('AF'))^1
---~ lpeg.uppercase     = lpeg.P("AZ")
---~ lpeg.lowercase     = lpeg.P("az")
-
---~ lpeg.eol           = lpeg.S('\r\n\f')^1 -- includes formfeed
---~ lpeg.space         = lpeg.S(' ')^1
---~ lpeg.nonspace      = lpeg.P(1-lpeg.space)^1
---~ lpeg.whitespace    = lpeg.S(' \r\n\f\t')^1
---~ lpeg.nonwhitespace = lpeg.P(1-lpeg.whitespace)^1
-
-local hash = { }
+local digit, sign      = R('09'), S('+-')
+local cr, lf, crlf     = P("\r"), P("\n"), P("\r\n")
+local utf8byte         = R("\128\191")
+
+patterns.utf8byte      = utf8byte
+patterns.utf8one       = R("\000\127")
+patterns.utf8two       = R("\194\223") * utf8byte
+patterns.utf8three     = R("\224\239") * utf8byte * utf8byte
+patterns.utf8four      = R("\240\244") * utf8byte * utf8byte * utf8byte
+
+patterns.digit         = digit
+patterns.sign          = sign
+patterns.cardinal      = sign^0 * digit^1
+patterns.integer       = sign^0 * digit^1
+patterns.float         = sign^0 * digit^0 * P('.') * digit^1
+patterns.number        = patterns.float + patterns.integer
+patterns.oct           = P("0") * R("07")^1
+patterns.hex           = P("0x") * R("09","AF")^1
+patterns.lowercase     = R("az")
+patterns.uppercase     = R("AZ")
+patterns.letter        = patterns.lowercase + patterns.uppercase
+patterns.space         = S(" ")
+patterns.eol           = S("\n\r")
+patterns.spacer        = S(" \t\f\v")  -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
+patterns.newline       = crlf + cr + lf
+patterns.nonspace      = 1 - patterns.space
+patterns.nonspacer     = 1 - patterns.spacer
+patterns.whitespace    = patterns.eol + patterns.spacer
+patterns.nonwhitespace = 1 - patterns.whitespace
+patterns.utf8          = patterns.utf8one + patterns.utf8two + patterns.utf8three + patterns.utf8four
+patterns.utfbom        = P('\000\000\254\255') + P('\255\254\000\000') + P('\255\254') + P('\254\255') + P('\239\187\191')
 
 function lpeg.anywhere(pattern) --slightly adapted from website
-    return P { P(pattern) + 1 * lpeg.V(1) }
-end
-
-function lpeg.startswith(pattern) --slightly adapted
-    return P(pattern)
+    return P { P(pattern) + 1 * V(1) } -- why so complex?
 end
 
 function lpeg.splitter(pattern, action)
     return (((1-P(pattern))^1)/action+1)^0
 end
 
--- variant:
-
---~ local parser = lpeg.Ct(lpeg.splitat(newline))
-
-local crlf     = P("\r\n")
-local cr       = P("\r")
-local lf       = P("\n")
-local space    = S(" \t\f\v")  -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
-local newline  = crlf + cr + lf
-local spacing  = space^0 * newline
-
+local spacing  = patterns.spacer^0 * patterns.newline -- sort of strip
 local empty    = spacing * Cc("")
 local nonempty = Cs((1-spacing)^1) * spacing^-1
 local content  = (empty + nonempty)^1
@@ -406,7 +404,7 @@ function string:splitlines()
     return match(capture,self)
 end
 
-lpeg.linebyline = content -- better make a sublibrary
+patterns.textline = content
 
 --~ local p = lpeg.splitat("->",false)  print(match(p,"oeps->what->more"))  -- oeps what more
 --~ local p = lpeg.splitat("->",true)   print(match(p,"oeps->what->more"))  -- oeps what->more
@@ -472,37 +470,31 @@ end
 
 --~ from roberto's site:
 --~
---~ -- decode a two-byte UTF-8 sequence
---~ local function f2 (s)
+--~ local function f1 = string.byte
+--~
+--~ local function f2(s)
 --~   local c1, c2 = string.byte(s, 1, 2)
 --~   return c1 * 64 + c2 - 12416
 --~ end
 --~
---~ -- decode a three-byte UTF-8 sequence
---~ local function f3 (s)
+--~ local function f3(s)
 --~   local c1, c2, c3 = string.byte(s, 1, 3)
 --~   return (c1 * 64 + c2) * 64 + c3 - 925824
 --~ end
 --~
---~ -- decode a four-byte UTF-8 sequence
---~ local function f4 (s)
+--~ local function f4(s)
 --~   local c1, c2, c3, c4 = string.byte(s, 1, 4)
 --~   return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168
 --~ end
 --~
 --~ local cont = lpeg.R("\128\191")   -- continuation byte
---~
---~ local utf8 = lpeg.R("\0\127") / string.byte
+--~ local utf8 = lpeg.R("\0\127") / f1
 --~            + lpeg.R("\194\223") * cont / f2
 --~            + lpeg.R("\224\239") * cont * cont / f3
 --~            + lpeg.R("\240\244") * cont * cont * cont / f4
 --~
 --~ local decode_pattern = lpeg.Ct(utf8^0) * -1
 
-local cont = R("\128\191")   -- continuation byte
-
-lpeg.patterns.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont
-
 
 end -- of closure
 
@@ -1729,7 +1721,7 @@ if not modules then modules = { } end modules ['l-os'] = {
 
 -- maybe build io.flush in os.execute
 
-local find, format = string.find, string.format
+local find, format, gsub = string.find, string.format, string.gsub
 local random, ceil = math.random, math.ceil
 
 local execute, spawn, exec, ioflush = os.execute, os.spawn or os.execute, os.exec or os.execute, io.flush
@@ -1809,13 +1801,15 @@ end
 
 -- no need for function anymore as we have more clever code and helpers now
 
-os.resolvers = { }
+os.resolvers = os.resolvers or { }
+
+local resolvers = os.resolvers
 
 local osmt = getmetatable(os) or { __index = function(t,k) t[k] = "unset" return "unset" end }
 local osix = osmt.__index
 
 osmt.__index = function(t,k)
-    return (os.resolvers[k] or osix)(t,k)
+    return (resolvers[k] or osix)(t,k)
 end
 
 setmetatable(os,osmt)
@@ -2327,6 +2321,15 @@ end
 -- test { "/aa", "/aa/bb", "/aa/bb/cc", "/aa/bb/cc.dd", "/aa/bb/cc.dd.ee" }
 -- test { "aa", "aa/bb", "aa/bb/cc", "aa/bb/cc.dd", "aa/bb/cc.dd.ee" }
 
+--~ -- todo:
+--~
+--~ if os.type == "windows" then
+--~     local currentdir = lfs.currentdir
+--~     function lfs.currentdir()
+--~         return (gsub(currentdir(),"\\","/"))
+--~     end
+--~ end
+
 
 end -- of closure
 
@@ -2558,6 +2561,8 @@ if not modules then modules = { } end modules ['l-dir'] = {
     license   = "see context related readme files"
 }
 
+-- dir.expand_name will be merged with cleanpath and collapsepath
+
 local type = type
 local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
 local lpegmatch = lpeg.match
@@ -2726,7 +2731,7 @@ end
 
 local make_indeed = true -- false
 
-if string.find(os.getenv("PATH"),";") then
+if string.find(os.getenv("PATH"),";") then -- os.type == "windows"
 
     function dir.mkdirs(...)
         local str, pth = "", ""
@@ -2793,7 +2798,7 @@ if string.find(os.getenv("PATH"),";") then
 --~         print(dir.mkdirs("///a/b/c"))
 --~         print(dir.mkdirs("a/bbb//ccc/"))
 
-    function dir.expand_name(str)
+    function dir.expand_name(str) -- will be merged with cleanpath and collapsepath
         local first, nothing, last = match(str,"^(//)(//*)(.*)$")
         if first then
             first = lfs.currentdir() .. "/"
@@ -3196,6 +3201,15 @@ local concat, format, gmatch = table.concat, string.format, string.gmatch
 local tostring, type = tostring, type
 local lpegmatch = lpeg.match
 
+local P, R, V = lpeg.P, lpeg.R, lpeg.V
+
+local escape, left, right = P("\\"), P('{'), P('}')
+
+lpeg.patterns.balanced = P {
+    [1] = ((escape * (left+right)) + (1 - (left+right)) + V(2))^0,
+    [2] = left * V(1) * right
+}
+
 local space     = lpeg.P(' ')
 local equal     = lpeg.P("=")
 local comma     = lpeg.P(",")
@@ -3368,21 +3382,14 @@ end
 
 -- temporary here
 
-local digit    = lpeg.R("09")
-local period   = lpeg.P(".")
-local zero     = lpeg.P("0")
-
---~ local finish   = lpeg.P(-1)
---~ local nodigit  = (1-digit) + finish
---~ local case_1   = (period * zero^1 * #nodigit)/"" -- .000
---~ local case_2   = (period * (1-(zero^0/"") * #nodigit)^1 * (zero^0/"") * nodigit) -- .010 .10 .100100
-
+local digit         = lpeg.R("09")
+local period        = lpeg.P(".")
+local zero          = lpeg.P("0")
 local trailingzeros = zero^0 * -digit -- suggested by Roberto R
-local case_1 = period * trailingzeros / ""
-local case_2 = period * (digit - trailingzeros)^1 * (trailingzeros / "")
-
-local number   = digit^1 * (case_1 + case_2)
-local stripper = lpeg.Cs((number + 1)^0)
+local case_1        = period * trailingzeros / ""
+local case_2        = period * (digit - trailingzeros)^1 * (trailingzeros / "")
+local number        = digit^1 * (case_1 + case_2)
+local stripper      = lpeg.Cs((number + 1)^0)
 
 --~ local sample = "bla 11.00 bla 11 bla 0.1100 bla 1.00100 bla 0.00 bla 0.001 bla 1.1100 bla 0.100100100 bla 0.00100100100"
 --~ collectgarbage("collect")
@@ -3820,6 +3827,7 @@ local type, next, setmetatable, getmetatable, tonumber = type, next, setmetatabl
 local format, lower, find, match = string.format, string.lower, string.find, string.match
 local utfchar = unicode.utf8.char
 local lpegmatch = lpeg.match
+local P, S, R, C, V, C, Cs = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.C, lpeg.Cs
 
 --[[ldx--
 <p>First a hack to enable namespace resolving. A namespace is characterized by
@@ -3831,7 +3839,7 @@ much cleaner.</p>
 
 xml.xmlns = xml.xmlns or { }
 
-local check = lpeg.P(false)
+local check = P(false)
 local parse = check
 
 --[[ldx--
@@ -3844,8 +3852,8 @@ xml.registerns("mml","mathml")
 --ldx]]--
 
 function xml.registerns(namespace, pattern) -- pattern can be an lpeg
-    check = check + lpeg.C(lpeg.P(lower(pattern))) / namespace
-    parse = lpeg.P { lpeg.P(check) + 1 * lpeg.V(1) }
+    check = check + C(P(lower(pattern))) / namespace
+    parse = P { P(check) + 1 * V(1) }
 end
 
 --[[ldx--
@@ -4123,8 +4131,6 @@ local function fromdec(s)
     end
 end
 
-local P, S, R, C, V, Cs = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.Cs
-
 local rest = (1-P(";"))^0
 local many = P(1)^0
 
@@ -4226,10 +4232,7 @@ local valid            = R('az', 'AZ', '09') + S('_-.')
 local name_yes         = C(valid^1) * colon * C(valid^1)
 local name_nop         = C(P(true)) * C(valid^1)
 local name             = name_yes + name_nop
-
-local utfbom           = P('\000\000\254\255') + P('\255\254\000\000') +
-                         P('\255\254') + P('\254\255') + P('\239\187\191') -- no capture
-
+local utfbom           = lpeg.patterns.utfbom -- no capture
 local spacing          = C(space^0)
 
 ----- entitycontent    = (1-open-semicolon)^0
@@ -4314,10 +4317,10 @@ local doctype          = (spacing * begindoctype     * somedoctype     * enddoct
 
 --  nicer but slower:
 --
---  local instruction = (lpeg.Cc("@pi@") * spacing * begininstruction * someinstruction * endinstruction) / add_special
---  local comment     = (lpeg.Cc("@cm@") * spacing * begincomment     * somecomment     * endcomment    ) / add_special
---  local cdata       = (lpeg.Cc("@cd@") * spacing * begincdata       * somecdata       * endcdata      ) / add_special
---  local doctype     = (lpeg.Cc("@dt@") * spacing * begindoctype     * somedoctype     * enddoctype    ) / add_special
+--  local instruction = (Cc("@pi@") * spacing * begininstruction * someinstruction * endinstruction) / add_special
+--  local comment     = (Cc("@cm@") * spacing * begincomment     * somecomment     * endcomment    ) / add_special
+--  local cdata       = (Cc("@cd@") * spacing * begincdata       * somecdata       * endcdata      ) / add_special
+--  local doctype     = (Cc("@dt@") * spacing * begindoctype     * somedoctype     * enddoctype    ) / add_special
 
 local trailer = space^0 * (text_unparsed/set_message)^0
 
@@ -8765,22 +8768,26 @@ local cache = { }
 local function split_kpse_path(str) -- beware, this can be either a path or a {specification}
     local found = cache[str]
     if not found then
-        str = gsub(str,"\\","/")
-        local split = (find(str,";") and checkedsplit(str,";")) or checkedsplit(str,io.pathseparator)
-        found = { }
-        for i=1,#split do
-            local s = split[i]
-            if not find(s,"^{*unset}*") then
-                found[#found+1] = s
+        if str == "" then
+            found = { }
+        else
+            str = gsub(str,"\\","/")
+            local split = (find(str,";") and checkedsplit(str,";")) or checkedsplit(str,io.pathseparator)
+            found = { }
+            for i=1,#split do
+                local s = split[i]
+                if not find(s,"^{*unset}*") then
+                    found[#found+1] = s
+                end
             end
-        end
-        if trace_expansions then
-            logs.report("fileio","splitting path specification '%s'",str)
-            for k,v in ipairs(found) do
-                logs.report("fileio","% 4i: %s",k,v)
+            if trace_expansions then
+                logs.report("fileio","splitting path specification '%s'",str)
+                for k,v in ipairs(found) do
+                    logs.report("fileio","% 4i: %s",k,v)
+                end
             end
+            cache[str] = found
         end
-        cache[str] = found
     end
     return found
 end
diff --git a/scripts/context/stubs/unix/luatools b/scripts/context/stubs/unix/luatools
index 1a579eb69..ea3b47840 100755
--- a/scripts/context/stubs/unix/luatools
+++ b/scripts/context/stubs/unix/luatools
@@ -336,57 +336,55 @@ if not modules then modules = { } end modules ['l-lpeg'] = {
     license   = "see context related readme files"
 }
 
-lpeg = require("lpeg")
+local lpeg = require("lpeg")
 
-lpeg.patterns = lpeg.patterns or { } -- so that we can share
+lpeg.patterns  = lpeg.patterns or { } -- so that we can share
+local patterns = lpeg.patterns
 
-local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
+local P, R, S, Ct, C, Cs, Cc, V = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.V
 local match = lpeg.match
 
---~ l-lpeg.lua :
-
---~ lpeg.digit         = lpeg.R('09')^1
---~ lpeg.sign          = lpeg.S('+-')^1
---~ lpeg.cardinal      = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
---~ lpeg.integer       = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
---~ lpeg.float         = lpeg.P(lpeg.sign^0 * lpeg.digit^0 * lpeg.P('.') * lpeg.digit^1)
---~ lpeg.number        = lpeg.float + lpeg.integer
---~ lpeg.oct           = lpeg.P("0") * lpeg.R('07')^1
---~ lpeg.hex           = lpeg.P("0x") * (lpeg.R('09') + lpeg.R('AF'))^1
---~ lpeg.uppercase     = lpeg.P("AZ")
---~ lpeg.lowercase     = lpeg.P("az")
-
---~ lpeg.eol           = lpeg.S('\r\n\f')^1 -- includes formfeed
---~ lpeg.space         = lpeg.S(' ')^1
---~ lpeg.nonspace      = lpeg.P(1-lpeg.space)^1
---~ lpeg.whitespace    = lpeg.S(' \r\n\f\t')^1
---~ lpeg.nonwhitespace = lpeg.P(1-lpeg.whitespace)^1
-
-local hash = { }
+local digit, sign      = R('09'), S('+-')
+local cr, lf, crlf     = P("\r"), P("\n"), P("\r\n")
+local utf8byte         = R("\128\191")
+
+patterns.utf8byte      = utf8byte
+patterns.utf8one       = R("\000\127")
+patterns.utf8two       = R("\194\223") * utf8byte
+patterns.utf8three     = R("\224\239") * utf8byte * utf8byte
+patterns.utf8four      = R("\240\244") * utf8byte * utf8byte * utf8byte
+
+patterns.digit         = digit
+patterns.sign          = sign
+patterns.cardinal      = sign^0 * digit^1
+patterns.integer       = sign^0 * digit^1
+patterns.float         = sign^0 * digit^0 * P('.') * digit^1
+patterns.number        = patterns.float + patterns.integer
+patterns.oct           = P("0") * R("07")^1
+patterns.hex           = P("0x") * R("09","AF")^1
+patterns.lowercase     = R("az")
+patterns.uppercase     = R("AZ")
+patterns.letter        = patterns.lowercase + patterns.uppercase
+patterns.space         = S(" ")
+patterns.eol           = S("\n\r")
+patterns.spacer        = S(" \t\f\v")  -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
+patterns.newline       = crlf + cr + lf
+patterns.nonspace      = 1 - patterns.space
+patterns.nonspacer     = 1 - patterns.spacer
+patterns.whitespace    = patterns.eol + patterns.spacer
+patterns.nonwhitespace = 1 - patterns.whitespace
+patterns.utf8          = patterns.utf8one + patterns.utf8two + patterns.utf8three + patterns.utf8four
+patterns.utfbom        = P('\000\000\254\255') + P('\255\254\000\000') + P('\255\254') + P('\254\255') + P('\239\187\191')
 
 function lpeg.anywhere(pattern) --slightly adapted from website
-    return P { P(pattern) + 1 * lpeg.V(1) }
-end
-
-function lpeg.startswith(pattern) --slightly adapted
-    return P(pattern)
+    return P { P(pattern) + 1 * V(1) } -- why so complex?
 end
 
 function lpeg.splitter(pattern, action)
     return (((1-P(pattern))^1)/action+1)^0
 end
 
--- variant:
-
---~ local parser = lpeg.Ct(lpeg.splitat(newline))
-
-local crlf     = P("\r\n")
-local cr       = P("\r")
-local lf       = P("\n")
-local space    = S(" \t\f\v")  -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
-local newline  = crlf + cr + lf
-local spacing  = space^0 * newline
-
+local spacing  = patterns.spacer^0 * patterns.newline -- sort of strip
 local empty    = spacing * Cc("")
 local nonempty = Cs((1-spacing)^1) * spacing^-1
 local content  = (empty + nonempty)^1
@@ -397,7 +395,7 @@ function string:splitlines()
     return match(capture,self)
 end
 
-lpeg.linebyline = content -- better make a sublibrary
+patterns.textline = content
 
 --~ local p = lpeg.splitat("->",false)  print(match(p,"oeps->what->more"))  -- oeps what more
 --~ local p = lpeg.splitat("->",true)   print(match(p,"oeps->what->more"))  -- oeps what->more
@@ -463,37 +461,31 @@ end
 
 --~ from roberto's site:
 --~
---~ -- decode a two-byte UTF-8 sequence
---~ local function f2 (s)
+--~ local function f1 = string.byte
+--~
+--~ local function f2(s)
 --~   local c1, c2 = string.byte(s, 1, 2)
 --~   return c1 * 64 + c2 - 12416
 --~ end
 --~
---~ -- decode a three-byte UTF-8 sequence
---~ local function f3 (s)
+--~ local function f3(s)
 --~   local c1, c2, c3 = string.byte(s, 1, 3)
 --~   return (c1 * 64 + c2) * 64 + c3 - 925824
 --~ end
 --~
---~ -- decode a four-byte UTF-8 sequence
---~ local function f4 (s)
+--~ local function f4(s)
 --~   local c1, c2, c3, c4 = string.byte(s, 1, 4)
 --~   return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168
 --~ end
 --~
 --~ local cont = lpeg.R("\128\191")   -- continuation byte
---~
---~ local utf8 = lpeg.R("\0\127") / string.byte
+--~ local utf8 = lpeg.R("\0\127") / f1
 --~            + lpeg.R("\194\223") * cont / f2
 --~            + lpeg.R("\224\239") * cont * cont / f3
 --~            + lpeg.R("\240\244") * cont * cont * cont / f4
 --~
 --~ local decode_pattern = lpeg.Ct(utf8^0) * -1
 
-local cont = R("\128\191")   -- continuation byte
-
-lpeg.patterns.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont
-
 
 end -- of closure
 
@@ -1720,7 +1712,7 @@ if not modules then modules = { } end modules ['l-os'] = {
 
 -- maybe build io.flush in os.execute
 
-local find, format = string.find, string.format
+local find, format, gsub = string.find, string.format, string.gsub
 local random, ceil = math.random, math.ceil
 
 local execute, spawn, exec, ioflush = os.execute, os.spawn or os.execute, os.exec or os.execute, io.flush
@@ -1800,13 +1792,15 @@ end
 
 -- no need for function anymore as we have more clever code and helpers now
 
-os.resolvers = { }
+os.resolvers = os.resolvers or { }
+
+local resolvers = os.resolvers
 
 local osmt = getmetatable(os) or { __index = function(t,k) t[k] = "unset" return "unset" end }
 local osix = osmt.__index
 
 osmt.__index = function(t,k)
-    return (os.resolvers[k] or osix)(t,k)
+    return (resolvers[k] or osix)(t,k)
 end
 
 setmetatable(os,osmt)
@@ -2318,6 +2312,15 @@ end
 -- test { "/aa", "/aa/bb", "/aa/bb/cc", "/aa/bb/cc.dd", "/aa/bb/cc.dd.ee" }
 -- test { "aa", "aa/bb", "aa/bb/cc", "aa/bb/cc.dd", "aa/bb/cc.dd.ee" }
 
+--~ -- todo:
+--~
+--~ if os.type == "windows" then
+--~     local currentdir = lfs.currentdir
+--~     function lfs.currentdir()
+--~         return (gsub(currentdir(),"\\","/"))
+--~     end
+--~ end
+
 
 end -- of closure
 
@@ -2549,6 +2552,8 @@ if not modules then modules = { } end modules ['l-dir'] = {
     license   = "see context related readme files"
 }
 
+-- dir.expand_name will be merged with cleanpath and collapsepath
+
 local type = type
 local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
 local lpegmatch = lpeg.match
@@ -2717,7 +2722,7 @@ end
 
 local make_indeed = true -- false
 
-if string.find(os.getenv("PATH"),";") then
+if string.find(os.getenv("PATH"),";") then -- os.type == "windows"
 
     function dir.mkdirs(...)
         local str, pth = "", ""
@@ -2784,7 +2789,7 @@ if string.find(os.getenv("PATH"),";") then
 --~         print(dir.mkdirs("///a/b/c"))
 --~         print(dir.mkdirs("a/bbb//ccc/"))
 
-    function dir.expand_name(str)
+    function dir.expand_name(str) -- will be merged with cleanpath and collapsepath
         local first, nothing, last = match(str,"^(//)(//*)(.*)$")
         if first then
             first = lfs.currentdir() .. "/"
@@ -3386,6 +3391,15 @@ local concat, format, gmatch = table.concat, string.format, string.gmatch
 local tostring, type = tostring, type
 local lpegmatch = lpeg.match
 
+local P, R, V = lpeg.P, lpeg.R, lpeg.V
+
+local escape, left, right = P("\\"), P('{'), P('}')
+
+lpeg.patterns.balanced = P {
+    [1] = ((escape * (left+right)) + (1 - (left+right)) + V(2))^0,
+    [2] = left * V(1) * right
+}
+
 local space     = lpeg.P(' ')
 local equal     = lpeg.P("=")
 local comma     = lpeg.P(",")
@@ -3558,21 +3572,14 @@ end
 
 -- temporary here
 
-local digit    = lpeg.R("09")
-local period   = lpeg.P(".")
-local zero     = lpeg.P("0")
-
---~ local finish   = lpeg.P(-1)
---~ local nodigit  = (1-digit) + finish
---~ local case_1   = (period * zero^1 * #nodigit)/"" -- .000
---~ local case_2   = (period * (1-(zero^0/"") * #nodigit)^1 * (zero^0/"") * nodigit) -- .010 .10 .100100
-
+local digit         = lpeg.R("09")
+local period        = lpeg.P(".")
+local zero          = lpeg.P("0")
 local trailingzeros = zero^0 * -digit -- suggested by Roberto R
-local case_1 = period * trailingzeros / ""
-local case_2 = period * (digit - trailingzeros)^1 * (trailingzeros / "")
-
-local number   = digit^1 * (case_1 + case_2)
-local stripper = lpeg.Cs((number + 1)^0)
+local case_1        = period * trailingzeros / ""
+local case_2        = period * (digit - trailingzeros)^1 * (trailingzeros / "")
+local number        = digit^1 * (case_1 + case_2)
+local stripper      = lpeg.Cs((number + 1)^0)
 
 --~ local sample = "bla 11.00 bla 11 bla 0.1100 bla 1.00100 bla 0.00 bla 0.001 bla 1.1100 bla 0.100100100 bla 0.00100100100"
 --~ collectgarbage("collect")
@@ -5671,22 +5678,26 @@ local cache = { }
 local function split_kpse_path(str) -- beware, this can be either a path or a {specification}
     local found = cache[str]
     if not found then
-        str = gsub(str,"\\","/")
-        local split = (find(str,";") and checkedsplit(str,";")) or checkedsplit(str,io.pathseparator)
-        found = { }
-        for i=1,#split do
-            local s = split[i]
-            if not find(s,"^{*unset}*") then
-                found[#found+1] = s
+        if str == "" then
+            found = { }
+        else
+            str = gsub(str,"\\","/")
+            local split = (find(str,";") and checkedsplit(str,";")) or checkedsplit(str,io.pathseparator)
+            found = { }
+            for i=1,#split do
+                local s = split[i]
+                if not find(s,"^{*unset}*") then
+                    found[#found+1] = s
+                end
             end
-        end
-        if trace_expansions then
-            logs.report("fileio","splitting path specification '%s'",str)
-            for k,v in ipairs(found) do
-                logs.report("fileio","% 4i: %s",k,v)
+            if trace_expansions then
+                logs.report("fileio","splitting path specification '%s'",str)
+                for k,v in ipairs(found) do
+                    logs.report("fileio","% 4i: %s",k,v)
+                end
             end
+            cache[str] = found
         end
-        cache[str] = found
     end
     return found
 end
diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun
index ef7eda9b0..447d958b2 100755
--- a/scripts/context/stubs/unix/mtxrun
+++ b/scripts/context/stubs/unix/mtxrun
@@ -345,57 +345,55 @@ if not modules then modules = { } end modules ['l-lpeg'] = {
     license   = "see context related readme files"
 }
 
-lpeg = require("lpeg")
+local lpeg = require("lpeg")
 
-lpeg.patterns = lpeg.patterns or { } -- so that we can share
+lpeg.patterns  = lpeg.patterns or { } -- so that we can share
+local patterns = lpeg.patterns
 
-local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
+local P, R, S, Ct, C, Cs, Cc, V = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.V
 local match = lpeg.match
 
---~ l-lpeg.lua :
-
---~ lpeg.digit         = lpeg.R('09')^1
---~ lpeg.sign          = lpeg.S('+-')^1
---~ lpeg.cardinal      = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
---~ lpeg.integer       = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
---~ lpeg.float         = lpeg.P(lpeg.sign^0 * lpeg.digit^0 * lpeg.P('.') * lpeg.digit^1)
---~ lpeg.number        = lpeg.float + lpeg.integer
---~ lpeg.oct           = lpeg.P("0") * lpeg.R('07')^1
---~ lpeg.hex           = lpeg.P("0x") * (lpeg.R('09') + lpeg.R('AF'))^1
---~ lpeg.uppercase     = lpeg.P("AZ")
---~ lpeg.lowercase     = lpeg.P("az")
-
---~ lpeg.eol           = lpeg.S('\r\n\f')^1 -- includes formfeed
---~ lpeg.space         = lpeg.S(' ')^1
---~ lpeg.nonspace      = lpeg.P(1-lpeg.space)^1
---~ lpeg.whitespace    = lpeg.S(' \r\n\f\t')^1
---~ lpeg.nonwhitespace = lpeg.P(1-lpeg.whitespace)^1
-
-local hash = { }
+local digit, sign      = R('09'), S('+-')
+local cr, lf, crlf     = P("\r"), P("\n"), P("\r\n")
+local utf8byte         = R("\128\191")
+
+patterns.utf8byte      = utf8byte
+patterns.utf8one       = R("\000\127")
+patterns.utf8two       = R("\194\223") * utf8byte
+patterns.utf8three     = R("\224\239") * utf8byte * utf8byte
+patterns.utf8four      = R("\240\244") * utf8byte * utf8byte * utf8byte
+
+patterns.digit         = digit
+patterns.sign          = sign
+patterns.cardinal      = sign^0 * digit^1
+patterns.integer       = sign^0 * digit^1
+patterns.float         = sign^0 * digit^0 * P('.') * digit^1
+patterns.number        = patterns.float + patterns.integer
+patterns.oct           = P("0") * R("07")^1
+patterns.hex           = P("0x") * R("09","AF")^1
+patterns.lowercase     = R("az")
+patterns.uppercase     = R("AZ")
+patterns.letter        = patterns.lowercase + patterns.uppercase
+patterns.space         = S(" ")
+patterns.eol           = S("\n\r")
+patterns.spacer        = S(" \t\f\v")  -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
+patterns.newline       = crlf + cr + lf
+patterns.nonspace      = 1 - patterns.space
+patterns.nonspacer     = 1 - patterns.spacer
+patterns.whitespace    = patterns.eol + patterns.spacer
+patterns.nonwhitespace = 1 - patterns.whitespace
+patterns.utf8          = patterns.utf8one + patterns.utf8two + patterns.utf8three + patterns.utf8four
+patterns.utfbom        = P('\000\000\254\255') + P('\255\254\000\000') + P('\255\254') + P('\254\255') + P('\239\187\191')
 
 function lpeg.anywhere(pattern) --slightly adapted from website
-    return P { P(pattern) + 1 * lpeg.V(1) }
-end
-
-function lpeg.startswith(pattern) --slightly adapted
-    return P(pattern)
+    return P { P(pattern) + 1 * V(1) } -- why so complex?
 end
 
 function lpeg.splitter(pattern, action)
     return (((1-P(pattern))^1)/action+1)^0
 end
 
--- variant:
-
---~ local parser = lpeg.Ct(lpeg.splitat(newline))
-
-local crlf     = P("\r\n")
-local cr       = P("\r")
-local lf       = P("\n")
-local space    = S(" \t\f\v")  -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
-local newline  = crlf + cr + lf
-local spacing  = space^0 * newline
-
+local spacing  = patterns.spacer^0 * patterns.newline -- sort of strip
 local empty    = spacing * Cc("")
 local nonempty = Cs((1-spacing)^1) * spacing^-1
 local content  = (empty + nonempty)^1
@@ -406,7 +404,7 @@ function string:splitlines()
     return match(capture,self)
 end
 
-lpeg.linebyline = content -- better make a sublibrary
+patterns.textline = content
 
 --~ local p = lpeg.splitat("->",false)  print(match(p,"oeps->what->more"))  -- oeps what more
 --~ local p = lpeg.splitat("->",true)   print(match(p,"oeps->what->more"))  -- oeps what->more
@@ -472,37 +470,31 @@ end
 
 --~ from roberto's site:
 --~
---~ -- decode a two-byte UTF-8 sequence
---~ local function f2 (s)
+--~ local function f1 = string.byte
+--~
+--~ local function f2(s)
 --~   local c1, c2 = string.byte(s, 1, 2)
 --~   return c1 * 64 + c2 - 12416
 --~ end
 --~
---~ -- decode a three-byte UTF-8 sequence
---~ local function f3 (s)
+--~ local function f3(s)
 --~   local c1, c2, c3 = string.byte(s, 1, 3)
 --~   return (c1 * 64 + c2) * 64 + c3 - 925824
 --~ end
 --~
---~ -- decode a four-byte UTF-8 sequence
---~ local function f4 (s)
+--~ local function f4(s)
 --~   local c1, c2, c3, c4 = string.byte(s, 1, 4)
 --~   return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168
 --~ end
 --~
 --~ local cont = lpeg.R("\128\191")   -- continuation byte
---~
---~ local utf8 = lpeg.R("\0\127") / string.byte
+--~ local utf8 = lpeg.R("\0\127") / f1
 --~            + lpeg.R("\194\223") * cont / f2
 --~            + lpeg.R("\224\239") * cont * cont / f3
 --~            + lpeg.R("\240\244") * cont * cont * cont / f4
 --~
 --~ local decode_pattern = lpeg.Ct(utf8^0) * -1
 
-local cont = R("\128\191")   -- continuation byte
-
-lpeg.patterns.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont
-
 
 end -- of closure
 
@@ -1729,7 +1721,7 @@ if not modules then modules = { } end modules ['l-os'] = {
 
 -- maybe build io.flush in os.execute
 
-local find, format = string.find, string.format
+local find, format, gsub = string.find, string.format, string.gsub
 local random, ceil = math.random, math.ceil
 
 local execute, spawn, exec, ioflush = os.execute, os.spawn or os.execute, os.exec or os.execute, io.flush
@@ -1809,13 +1801,15 @@ end
 
 -- no need for function anymore as we have more clever code and helpers now
 
-os.resolvers = { }
+os.resolvers = os.resolvers or { }
+
+local resolvers = os.resolvers
 
 local osmt = getmetatable(os) or { __index = function(t,k) t[k] = "unset" return "unset" end }
 local osix = osmt.__index
 
 osmt.__index = function(t,k)
-    return (os.resolvers[k] or osix)(t,k)
+    return (resolvers[k] or osix)(t,k)
 end
 
 setmetatable(os,osmt)
@@ -2327,6 +2321,15 @@ end
 -- test { "/aa", "/aa/bb", "/aa/bb/cc", "/aa/bb/cc.dd", "/aa/bb/cc.dd.ee" }
 -- test { "aa", "aa/bb", "aa/bb/cc", "aa/bb/cc.dd", "aa/bb/cc.dd.ee" }
 
+--~ -- todo:
+--~
+--~ if os.type == "windows" then
+--~     local currentdir = lfs.currentdir
+--~     function lfs.currentdir()
+--~         return (gsub(currentdir(),"\\","/"))
+--~     end
+--~ end
+
 
 end -- of closure
 
@@ -2558,6 +2561,8 @@ if not modules then modules = { } end modules ['l-dir'] = {
     license   = "see context related readme files"
 }
 
+-- dir.expand_name will be merged with cleanpath and collapsepath
+
 local type = type
 local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
 local lpegmatch = lpeg.match
@@ -2726,7 +2731,7 @@ end
 
 local make_indeed = true -- false
 
-if string.find(os.getenv("PATH"),";") then
+if string.find(os.getenv("PATH"),";") then -- os.type == "windows"
 
     function dir.mkdirs(...)
         local str, pth = "", ""
@@ -2793,7 +2798,7 @@ if string.find(os.getenv("PATH"),";") then
 --~         print(dir.mkdirs("///a/b/c"))
 --~         print(dir.mkdirs("a/bbb//ccc/"))
 
-    function dir.expand_name(str)
+    function dir.expand_name(str) -- will be merged with cleanpath and collapsepath
         local first, nothing, last = match(str,"^(//)(//*)(.*)$")
         if first then
             first = lfs.currentdir() .. "/"
@@ -3196,6 +3201,15 @@ local concat, format, gmatch = table.concat, string.format, string.gmatch
 local tostring, type = tostring, type
 local lpegmatch = lpeg.match
 
+local P, R, V = lpeg.P, lpeg.R, lpeg.V
+
+local escape, left, right = P("\\"), P('{'), P('}')
+
+lpeg.patterns.balanced = P {
+    [1] = ((escape * (left+right)) + (1 - (left+right)) + V(2))^0,
+    [2] = left * V(1) * right
+}
+
 local space     = lpeg.P(' ')
 local equal     = lpeg.P("=")
 local comma     = lpeg.P(",")
@@ -3368,21 +3382,14 @@ end
 
 -- temporary here
 
-local digit    = lpeg.R("09")
-local period   = lpeg.P(".")
-local zero     = lpeg.P("0")
-
---~ local finish   = lpeg.P(-1)
---~ local nodigit  = (1-digit) + finish
---~ local case_1   = (period * zero^1 * #nodigit)/"" -- .000
---~ local case_2   = (period * (1-(zero^0/"") * #nodigit)^1 * (zero^0/"") * nodigit) -- .010 .10 .100100
-
+local digit         = lpeg.R("09")
+local period        = lpeg.P(".")
+local zero          = lpeg.P("0")
 local trailingzeros = zero^0 * -digit -- suggested by Roberto R
-local case_1 = period * trailingzeros / ""
-local case_2 = period * (digit - trailingzeros)^1 * (trailingzeros / "")
-
-local number   = digit^1 * (case_1 + case_2)
-local stripper = lpeg.Cs((number + 1)^0)
+local case_1        = period * trailingzeros / ""
+local case_2        = period * (digit - trailingzeros)^1 * (trailingzeros / "")
+local number        = digit^1 * (case_1 + case_2)
+local stripper      = lpeg.Cs((number + 1)^0)
 
 --~ local sample = "bla 11.00 bla 11 bla 0.1100 bla 1.00100 bla 0.00 bla 0.001 bla 1.1100 bla 0.100100100 bla 0.00100100100"
 --~ collectgarbage("collect")
@@ -3820,6 +3827,7 @@ local type, next, setmetatable, getmetatable, tonumber = type, next, setmetatabl
 local format, lower, find, match = string.format, string.lower, string.find, string.match
 local utfchar = unicode.utf8.char
 local lpegmatch = lpeg.match
+local P, S, R, C, V, C, Cs = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.C, lpeg.Cs
 
 --[[ldx--
 <p>First a hack to enable namespace resolving. A namespace is characterized by
@@ -3831,7 +3839,7 @@ much cleaner.</p>
 
 xml.xmlns = xml.xmlns or { }
 
-local check = lpeg.P(false)
+local check = P(false)
 local parse = check
 
 --[[ldx--
@@ -3844,8 +3852,8 @@ xml.registerns("mml","mathml")
 --ldx]]--
 
 function xml.registerns(namespace, pattern) -- pattern can be an lpeg
-    check = check + lpeg.C(lpeg.P(lower(pattern))) / namespace
-    parse = lpeg.P { lpeg.P(check) + 1 * lpeg.V(1) }
+    check = check + C(P(lower(pattern))) / namespace
+    parse = P { P(check) + 1 * V(1) }
 end
 
 --[[ldx--
@@ -4123,8 +4131,6 @@ local function fromdec(s)
     end
 end
 
-local P, S, R, C, V, Cs = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.Cs
-
 local rest = (1-P(";"))^0
 local many = P(1)^0
 
@@ -4226,10 +4232,7 @@ local valid            = R('az', 'AZ', '09') + S('_-.')
 local name_yes         = C(valid^1) * colon * C(valid^1)
 local name_nop         = C(P(true)) * C(valid^1)
 local name             = name_yes + name_nop
-
-local utfbom           = P('\000\000\254\255') + P('\255\254\000\000') +
-                         P('\255\254') + P('\254\255') + P('\239\187\191') -- no capture
-
+local utfbom           = lpeg.patterns.utfbom -- no capture
 local spacing          = C(space^0)
 
 ----- entitycontent    = (1-open-semicolon)^0
@@ -4314,10 +4317,10 @@ local doctype          = (spacing * begindoctype     * somedoctype     * enddoct
 
 --  nicer but slower:
 --
---  local instruction = (lpeg.Cc("@pi@") * spacing * begininstruction * someinstruction * endinstruction) / add_special
---  local comment     = (lpeg.Cc("@cm@") * spacing * begincomment     * somecomment     * endcomment    ) / add_special
---  local cdata       = (lpeg.Cc("@cd@") * spacing * begincdata       * somecdata       * endcdata      ) / add_special
---  local doctype     = (lpeg.Cc("@dt@") * spacing * begindoctype     * somedoctype     * enddoctype    ) / add_special
+--  local instruction = (Cc("@pi@") * spacing * begininstruction * someinstruction * endinstruction) / add_special
+--  local comment     = (Cc("@cm@") * spacing * begincomment     * somecomment     * endcomment    ) / add_special
+--  local cdata       = (Cc("@cd@") * spacing * begincdata       * somecdata       * endcdata      ) / add_special
+--  local doctype     = (Cc("@dt@") * spacing * begindoctype     * somedoctype     * enddoctype    ) / add_special
 
 local trailer = space^0 * (text_unparsed/set_message)^0
 
@@ -8765,22 +8768,26 @@ local cache = { }
 local function split_kpse_path(str) -- beware, this can be either a path or a {specification}
     local found = cache[str]
     if not found then
-        str = gsub(str,"\\","/")
-        local split = (find(str,";") and checkedsplit(str,";")) or checkedsplit(str,io.pathseparator)
-        found = { }
-        for i=1,#split do
-            local s = split[i]
-            if not find(s,"^{*unset}*") then
-                found[#found+1] = s
+        if str == "" then
+            found = { }
+        else
+            str = gsub(str,"\\","/")
+            local split = (find(str,";") and checkedsplit(str,";")) or checkedsplit(str,io.pathseparator)
+            found = { }
+            for i=1,#split do
+                local s = split[i]
+                if not find(s,"^{*unset}*") then
+                    found[#found+1] = s
+                end
             end
-        end
-        if trace_expansions then
-            logs.report("fileio","splitting path specification '%s'",str)
-            for k,v in ipairs(found) do
-                logs.report("fileio","% 4i: %s",k,v)
+            if trace_expansions then
+                logs.report("fileio","splitting path specification '%s'",str)
+                for k,v in ipairs(found) do
+                    logs.report("fileio","% 4i: %s",k,v)
+                end
             end
+            cache[str] = found
         end
-        cache[str] = found
     end
     return found
 end
diff --git a/tex/context/base/anch-pgr.mkiv b/tex/context/base/anch-pgr.mkiv
index 7a8fcd07f..19a44d687 100644
--- a/tex/context/base/anch-pgr.mkiv
+++ b/tex/context/base/anch-pgr.mkiv
@@ -950,7 +950,7 @@
         \c!leftoffset,\c!rightoffset,\c!topoffset,\c!bottomoffset]%
      \getparameters[\??td#1][#2]%
      \doifvalue{\??td#1\c!state}\v!start\checktextbackgrounds
-     \unexpanded\setvalue{#1}%
+     \setuvalue{#1}%
        {\groupedcommand{\starttextbackground[#1]}{\stoptextbackground}}%
      \setvalue{\e!start#1}{\starttextbackground[#1]}%
      \setvalue{\e!stop #1}{\stoptextbackground}%
diff --git a/tex/context/base/bibl-bib.lua b/tex/context/base/bibl-bib.lua
index b3199a506..8c76465c2 100644
--- a/tex/context/base/bibl-bib.lua
+++ b/tex/context/base/bibl-bib.lua
@@ -82,10 +82,7 @@ local function add(a,b) if b then return a..b else return a end end
 local keyword    = lpeg.C((lpeg.R("az","AZ","09") + lpeg.S("@_:-"))^1)  -- lpeg.C((1-space)^1)
 local s_quoted   = ((escape*single) + collapsed + (1-single))^0
 local d_quoted   = ((escape*double) + collapsed + (1-double))^0
-local balanced   = lpeg.P {
-    [1] = ((escape * (left+right)) + (1 - (left+right)) + lpeg.V(2))^0,
-    [2] = left * lpeg.V(1) * right
-}
+local balanced   = lpeg.patterns.balanced
 
 local s_value    = (single/"") * s_quoted * (single/"")
 local d_value    = (double/"") * d_quoted * (double/"")
diff --git a/tex/context/base/buff-ini.lua b/tex/context/base/buff-ini.lua
index 129182741..0e17e23b0 100644
--- a/tex/context/base/buff-ini.lua
+++ b/tex/context/base/buff-ini.lua
@@ -258,7 +258,7 @@ function buffers.run(name,list,encapsulate)
     end
 end
 
-local printer = (lpeg.linebyline/texprint)^0
+local printer = (lpeg.patterns.textline/texprint)^0
 
 function buffers.get(name)
     local b = buffers.data[name]
diff --git a/tex/context/base/buff-ini.mkiv b/tex/context/base/buff-ini.mkiv
index c6300a624..dea7b0a49 100644
--- a/tex/context/base/buff-ini.mkiv
+++ b/tex/context/base/buff-ini.mkiv
@@ -161,9 +161,9 @@
      \doglobal\increment\nofdefinedbuffers
      \letvalue{\??bu#1\c!number   }\nofdefinedbuffers
      \letvalue{\??bu#1\c!paragraph}\v!no
-     \setevalue{\e!start#1}{\noexpand\dostartbuffer[#1][def-\nofdefinedbuffers][\e!start#1][\e!stop#1]}%
-     \unexpanded\setevalue{\e!get  #1}{\noexpand\dogetbuffer  [#1][def-\nofdefinedbuffers]}%
-     \unexpanded\setevalue{\e!type #1}{\noexpand\dotypebuffer [#1][def-\nofdefinedbuffers]}%
+     \setuevalue{\e!start#1}{\noexpand\dostartbuffer[#1][def-\nofdefinedbuffers][\e!start#1][\e!stop#1]}% maybe also relax stop
+     \setuevalue{\e!get  #1}{\noexpand\dogetbuffer  [#1][def-\nofdefinedbuffers]}%
+     \setuevalue{\e!type #1}{\noexpand\dotypebuffer [#1][def-\nofdefinedbuffers]}%
      \getparameters[\??bu#1][#2]%
    \fi}
 
diff --git a/tex/context/base/buff-ver.mkiv b/tex/context/base/buff-ver.mkiv
index f1d733d76..928f26057 100644
--- a/tex/context/base/buff-ver.mkiv
+++ b/tex/context/base/buff-ver.mkiv
@@ -726,7 +726,7 @@
   {\dodoubleempty\dodefinetype}
 
 \def\dodefinetype[#1][#2]%
-  {\unexpanded\setvalue{#1}{\dotype{#1}}%
+  {\setuvalue{#1}{\dotype{#1}}%
    \getparameters[\??ty#1][#2]}
 
 %D \macros
diff --git a/tex/context/base/cont-log.tex b/tex/context/base/cont-log.tex
index 3eb68db7a..9bfec2999 100644
--- a/tex/context/base/cont-log.tex
+++ b/tex/context/base/cont-log.tex
@@ -322,7 +322,38 @@
 %    \TeX
 %    \endgroup}
 %
-% \let\LuaTeX \luaTeX
-% \let\LUATEX \luaTeX
+% a further iteration from the list, patched again
+
+% \ifx\fontalternative\c!it -\else
+% \ifx\fontalternative\c!sl -\else
+% \ifx\fontalternative\c!bi -\else
+% \ifx\fontalternative\c!bs -\fi\fi\fi\fi
+
+\def\LuaTeX
+  {\dontleavehmode
+   \begingroup
+     Lua%
+     % hope for kerning, try aT
+     \setbox0\hbox{aT}%
+     \setbox2\hbox{a\kern\zeropoint T}%
+     \ifdim\wd0=\wd2 % kerns can go two ways
+       % no aT kerning, try oT as a is not symmetrical
+       \setbox0\hbox{oT}%
+       \setbox2\hbox{o\kern\zeropoint T}%
+       \ifdim\wd0=\wd2 % kerns can go two ways
+         % no aT and oT kerning, try To
+         \setbox0\hbox{To}%
+         \setbox2\hbox{T\kern\zeropoint o}%
+         % maybe we need to compensate for the angle (sl/it/bs/bi)
+       \fi
+       \ifdim\wd0=\wd2\else
+         \kern\dimexpr\wd0-\wd2\relax
+       \fi
+     \fi
+     \TeX
+   \endgroup}
+
+\let\luaTeX \LuaTeX
+\let\LUATEX \LuaTeX
 
 \protect \endinput
diff --git a/tex/context/base/cont-new.tex b/tex/context/base/cont-new.tex
index a313c6c54..e080d3904 100644
--- a/tex/context/base/cont-new.tex
+++ b/tex/context/base/cont-new.tex
@@ -11,7 +11,7 @@
 %C therefore copyrighted by \PRAGMA. See mreadme.pdf for
 %C details.
 
-\newcontextversion{2010.03.10 23:47}
+\newcontextversion{2010.03.12 19:49}
 
 %D This file is loaded at runtime, thereby providing an
 %D excellent place for hacks, patches, extensions and new
diff --git a/tex/context/base/context.tex b/tex/context/base/context.tex
index b0742590a..c70f20b8e 100644
--- a/tex/context/base/context.tex
+++ b/tex/context/base/context.tex
@@ -20,7 +20,7 @@
 %D your styles an modules.
 
 \edef\contextformat {\jobname}
-\edef\contextversion{2010.03.10 23:47}
+\edef\contextversion{2010.03.12 19:49}
 
 %D For those who want to use this:
 
diff --git a/tex/context/base/core-mis.mkiv b/tex/context/base/core-mis.mkiv
index 63f279c92..00535e586 100644
--- a/tex/context/base/core-mis.mkiv
+++ b/tex/context/base/core-mis.mkiv
@@ -859,7 +859,7 @@
             \c!leftmargin,\c!rightmargin,\c!indentnext,
             \c!before,\c!after,\c!left,\c!right]}}%
    \doifsomething{#1}
-     {\unexpanded\setvalue{#1}{\delimitedtext[#1]}%
+     {\setuvalue{#1}{\delimitedtext[#1]}%
       \setvalue{\e!start#1}{\startdelimitedtext[#1]}%
       \setvalue{\e!stop #1}{\stopdelimitedtext}}}
 
diff --git a/tex/context/base/core-sys.mkiv b/tex/context/base/core-sys.mkiv
index c7747d4bb..932d387ec 100644
--- a/tex/context/base/core-sys.mkiv
+++ b/tex/context/base/core-sys.mkiv
@@ -203,7 +203,7 @@
       \c!commands=,
       \c!style=,
       #2]%
-   \unexpanded\setvalue{#1}%
+   \setuvalue{#1}%
      {\groupedcommand
         {\getvalue{\??be#1\c!commands}%
          \dostartattributes{\??be#1}\c!style\c!color}
diff --git a/tex/context/base/data-res.lua b/tex/context/base/data-res.lua
index 47c29fda9..7299475d3 100644
--- a/tex/context/base/data-res.lua
+++ b/tex/context/base/data-res.lua
@@ -891,22 +891,26 @@ local cache = { }
 local function split_kpse_path(str) -- beware, this can be either a path or a {specification}
     local found = cache[str]
     if not found then
-        str = gsub(str,"\\","/")
-        local split = (find(str,";") and checkedsplit(str,";")) or checkedsplit(str,io.pathseparator)
-        found = { }
-        for i=1,#split do
-            local s = split[i]
-            if not find(s,"^{*unset}*") then
-                found[#found+1] = s
+        if str == "" then
+            found = { }
+        else
+            str = gsub(str,"\\","/")
+            local split = (find(str,";") and checkedsplit(str,";")) or checkedsplit(str,io.pathseparator)
+            found = { }
+            for i=1,#split do
+                local s = split[i]
+                if not find(s,"^{*unset}*") then
+                    found[#found+1] = s
+                end
             end
-        end
-        if trace_expansions then
-            logs.report("fileio","splitting path specification '%s'",str)
-            for k,v in ipairs(found) do
-                logs.report("fileio","% 4i: %s",k,v)
+            if trace_expansions then
+                logs.report("fileio","splitting path specification '%s'",str)
+                for k,v in ipairs(found) do
+                    logs.report("fileio","% 4i: %s",k,v)
+                end
             end
+            cache[str] = found
         end
-        cache[str] = found
     end
     return found
 end
diff --git a/tex/context/base/data-tex.lua b/tex/context/base/data-tex.lua
index 8f31bb258..c9fa3625a 100644
--- a/tex/context/base/data-tex.lua
+++ b/tex/context/base/data-tex.lua
@@ -34,7 +34,7 @@ function finders.generic(tag,filename,filetype)
 end
 
 --~ local lpegmatch = lpeg.match
---~ local getlines = lpeg.Ct(lpeg.linebyline)
+--~ local getlines = lpeg.Ct(lpeg.patterns.textline)
 
 local input_translator, utf_translator, user_translator = nil, nil, nil
 
diff --git a/tex/context/base/enco-ini.mkiv b/tex/context/base/enco-ini.mkiv
index bab631ef9..495767389 100644
--- a/tex/context/base/enco-ini.mkiv
+++ b/tex/context/base/enco-ini.mkiv
@@ -71,10 +71,10 @@
 \def\definecharacter#1 #2 %
   {\doifnumberelse{\string#2}
      {\setevalue{\string#1}{\utfchar{#2}}} % or {\expandafter\chardef\csname#1\endcsname#2\relax}
-     {\unexpanded\setvalue {\string#1}{#2}}}
+     {\setuvalue {\string#1}{#2}}}
 
 \def\definecommand#1 #2 %
-  {\unexpanded\setvalue{\string#1}{#2}}
+  {\setuvalue{\string#1}{#2}}
 
 %D \macros
 %D   {everyuppercase, EveryUppercase,
diff --git a/tex/context/base/font-ini.mkiv b/tex/context/base/font-ini.mkiv
index 40142ea10..b000cac31 100644
--- a/tex/context/base/font-ini.mkiv
+++ b/tex/context/base/font-ini.mkiv
@@ -1109,9 +1109,9 @@
 
 \def\dodefinefont[#1][#2][#3]% [name][spec][1.6 | line=10pt | setup_id]
   {\ifthirdargument
-     \unexpanded\setvalue{#1}{\redodefinefont{#1}{#2}{#3}}%
+     \setuvalue{#1}{\redodefinefont{#1}{#2}{#3}}%
    \else
-     \unexpanded\setvalue{#1}{\dododefinefont{#1}{#2}}%
+     \setuvalue{#1}{\dododefinefont{#1}{#2}}%
    \fi}
 
 \def\redodefinefont#1#2#3%
@@ -1657,21 +1657,21 @@
 \def\checkmathbodyfont#1#2#3% style alt size / gdef % #3 can be empty
   {%\message{!m #1 #2 #3!}%
    % #1 #2 #3 = signal
-   %unexpanded\setgvalue     {#2}{\setcurrentfontalternative         {#2}}%         \mr \mb
-   \unexpanded\setgvalue     {#1}{\setcurrentfontstyle               {#1}}}%        \mm
+   %setugvalue     {#2}{\setcurrentfontalternative         {#2}}%         \mr \mb
+   \setugvalue     {#1}{\setcurrentfontstyle               {#1}}}%        \mm
 
 \def\checktextbodyfont#1#2#3% style alt size / gdef % #3 can be empty
   {%\message{!t #1 #2 #3!}%
-   \unexpanded\setgvalue   {#1#3}{\setcurrentfontstylesize           {#1}{#3}}%     \rma
-   \unexpanded\setgvalue   {#2#3}{\setcurrentfontalternativesize     {#2}{#3}}%     \sla
-   \unexpanded\setgvalue {#1#2#3}{\setcurrentfontstylealternativesize{#1}{#2}{#3}}% \rmsla
-   \unexpanded\setgvalue     {#1}{\setcurrentfontstyle               {#1}}%         \rm
-   \unexpanded\setgvalue     {#2}{\setcurrentfontalternative         {#2}}%         \sl
-   \unexpanded\setgvalue {#1\c!x}{\setcurrentfontxstylealternative   {#1}}%         \rmx
-   \unexpanded\setgvalue{#1\c!xx}{\setcurrentfontxxstylealternative  {#1}}%         \rmxx
-   \unexpanded\setgvalue {#2\c!x}{\setcurrentfontxalternative        {#2}}%         \slx
-   \unexpanded\setgvalue{#2\c!xx}{\setcurrentfontxxalternative       {#2}}%         \slxx
-   \unexpanded\setgvalue   {#1#2}{\setcurrentfontstylealternative    {#1}{#2}}}%    \rmsl
+   \setugvalue   {#1#3}{\setcurrentfontstylesize           {#1}{#3}}%     \rma
+   \setugvalue   {#2#3}{\setcurrentfontalternativesize     {#2}{#3}}%     \sla
+   \setugvalue {#1#2#3}{\setcurrentfontstylealternativesize{#1}{#2}{#3}}% \rmsla
+   \setugvalue     {#1}{\setcurrentfontstyle               {#1}}%         \rm
+   \setugvalue     {#2}{\setcurrentfontalternative         {#2}}%         \sl
+   \setugvalue {#1\c!x}{\setcurrentfontxstylealternative   {#1}}%         \rmx
+   \setugvalue{#1\c!xx}{\setcurrentfontxxstylealternative  {#1}}%         \rmxx
+   \setugvalue {#2\c!x}{\setcurrentfontxalternative        {#2}}%         \slx
+   \setugvalue{#2\c!xx}{\setcurrentfontxxalternative       {#2}}%         \slxx
+   \setugvalue   {#1#2}{\setcurrentfontstylealternative    {#1}{#2}}}%    \rmsl
 
 \def\dodefinedefaultbodyfont[#1][#2][#3]% sizes styles identifier
   {\def\dododefinedefaultbodyfont##1%
@@ -1750,7 +1750,7 @@
 %D instead of the more memory hungry:
 %D
 %D \starttyping
-%D \unexpanded\setvalue{name}{...}
+%D \setuvalue{name}{...}
 %D \stoptyping
 %D
 %D The first alternative saves about 500 hash entries (about
@@ -4007,7 +4007,7 @@
 
 \def\dodefinestylecollection[#1]%
   {\iffirstargument
-     \unexpanded\setvalue{#1}{\styleinstance[#1]}%
+     \setuvalue{#1}{\styleinstance[#1]}%
      \def\docommand##1%
        {\def\dodocommand####1{\letbeundefined{\??sx##1:####1:\commalistelement}}%
         \processcommacommand[\fontalternativelist,\s!default]\dodocommand}%
diff --git a/tex/context/base/l-aux.lua b/tex/context/base/l-aux.lua
index 4cee5f324..7950a03a7 100644
--- a/tex/context/base/l-aux.lua
+++ b/tex/context/base/l-aux.lua
@@ -14,13 +14,22 @@ local concat, format, gmatch = table.concat, string.format, string.gmatch
 local tostring, type = tostring, type
 local lpegmatch = lpeg.match
 
+local P, R, V = lpeg.P, lpeg.R, lpeg.V
+
+local escape, left, right = P("\\"), P('{'), P('}')
+
+lpeg.patterns.balanced = P {
+    [1] = ((escape * (left+right)) + (1 - (left+right)) + V(2))^0,
+    [2] = left * V(1) * right
+}
+
 local space     = lpeg.P(' ')
 local equal     = lpeg.P("=")
 local comma     = lpeg.P(",")
 local lbrace    = lpeg.P("{")
 local rbrace    = lpeg.P("}")
 local nobrace   = 1 - (lbrace+rbrace)
-local nested    = lpeg.P{ lbrace * (nobrace + lpeg.V(1))^0 * rbrace }
+local nested    = lpeg.P { lbrace * (nobrace + lpeg.V(1))^0 * rbrace }
 local spaces    = space^0
 
 local value     = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0)
@@ -186,21 +195,14 @@ end
 
 -- temporary here
 
-local digit    = lpeg.R("09")
-local period   = lpeg.P(".")
-local zero     = lpeg.P("0")
-
---~ local finish   = lpeg.P(-1)
---~ local nodigit  = (1-digit) + finish
---~ local case_1   = (period * zero^1 * #nodigit)/"" -- .000
---~ local case_2   = (period * (1-(zero^0/"") * #nodigit)^1 * (zero^0/"") * nodigit) -- .010 .10 .100100
-
+local digit         = lpeg.R("09")
+local period        = lpeg.P(".")
+local zero          = lpeg.P("0")
 local trailingzeros = zero^0 * -digit -- suggested by Roberto R
-local case_1 = period * trailingzeros / ""
-local case_2 = period * (digit - trailingzeros)^1 * (trailingzeros / "")
-
-local number   = digit^1 * (case_1 + case_2)
-local stripper = lpeg.Cs((number + 1)^0)
+local case_1        = period * trailingzeros / ""
+local case_2        = period * (digit - trailingzeros)^1 * (trailingzeros / "")
+local number        = digit^1 * (case_1 + case_2)
+local stripper      = lpeg.Cs((number + 1)^0)
 
 --~ local sample = "bla 11.00 bla 11 bla 0.1100 bla 1.00100 bla 0.00 bla 0.001 bla 1.1100 bla 0.100100100 bla 0.00100100100"
 --~ collectgarbage("collect")
diff --git a/tex/context/base/l-dir.lua b/tex/context/base/l-dir.lua
index 369895c43..0d08362b1 100644
--- a/tex/context/base/l-dir.lua
+++ b/tex/context/base/l-dir.lua
@@ -6,6 +6,8 @@ if not modules then modules = { } end modules ['l-dir'] = {
     license   = "see context related readme files"
 }
 
+-- dir.expand_name will be merged with cleanpath and collapsepath
+
 local type = type
 local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
 local lpegmatch = lpeg.match
@@ -174,7 +176,7 @@ end
 
 local make_indeed = true -- false
 
-if string.find(os.getenv("PATH"),";") then
+if string.find(os.getenv("PATH"),";") then -- os.type == "windows"
 
     function dir.mkdirs(...)
         local str, pth = "", ""
@@ -241,7 +243,7 @@ if string.find(os.getenv("PATH"),";") then
 --~         print(dir.mkdirs("///a/b/c"))
 --~         print(dir.mkdirs("a/bbb//ccc/"))
 
-    function dir.expand_name(str)
+    function dir.expand_name(str) -- will be merged with cleanpath and collapsepath
         local first, nothing, last = match(str,"^(//)(//*)(.*)$")
         if first then
             first = lfs.currentdir() .. "/"
diff --git a/tex/context/base/l-file.lua b/tex/context/base/l-file.lua
index 0b2c96d8f..be0e3d016 100644
--- a/tex/context/base/l-file.lua
+++ b/tex/context/base/l-file.lua
@@ -301,3 +301,12 @@ end
 -- test { "c:", "c:aa", "c:aa/bb", "c:aa/bb/cc", "c:aa/bb/cc.dd", "c:aa/bb/cc.dd.ee" }
 -- test { "/aa", "/aa/bb", "/aa/bb/cc", "/aa/bb/cc.dd", "/aa/bb/cc.dd.ee" }
 -- test { "aa", "aa/bb", "aa/bb/cc", "aa/bb/cc.dd", "aa/bb/cc.dd.ee" }
+
+--~ -- todo:
+--~
+--~ if os.type == "windows" then
+--~     local currentdir = lfs.currentdir
+--~     function lfs.currentdir()
+--~         return (gsub(currentdir(),"\\","/"))
+--~     end
+--~ end
diff --git a/tex/context/base/l-lpeg.lua b/tex/context/base/l-lpeg.lua
index 227b193da..2e366a904 100644
--- a/tex/context/base/l-lpeg.lua
+++ b/tex/context/base/l-lpeg.lua
@@ -6,57 +6,58 @@ if not modules then modules = { } end modules ['l-lpeg'] = {
     license   = "see context related readme files"
 }
 
-lpeg = require("lpeg")
+local lpeg = require("lpeg")
 
-lpeg.patterns = lpeg.patterns or { } -- so that we can share
+lpeg.patterns  = lpeg.patterns or { } -- so that we can share
+local patterns = lpeg.patterns
 
-local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
+local P, R, S, Ct, C, Cs, Cc, V = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.V
 local match = lpeg.match
 
---~ l-lpeg.lua :
-
---~ lpeg.digit         = lpeg.R('09')^1
---~ lpeg.sign          = lpeg.S('+-')^1
---~ lpeg.cardinal      = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
---~ lpeg.integer       = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
---~ lpeg.float         = lpeg.P(lpeg.sign^0 * lpeg.digit^0 * lpeg.P('.') * lpeg.digit^1)
---~ lpeg.number        = lpeg.float + lpeg.integer
---~ lpeg.oct           = lpeg.P("0") * lpeg.R('07')^1
---~ lpeg.hex           = lpeg.P("0x") * (lpeg.R('09') + lpeg.R('AF'))^1
---~ lpeg.uppercase     = lpeg.P("AZ")
---~ lpeg.lowercase     = lpeg.P("az")
-
---~ lpeg.eol           = lpeg.S('\r\n\f')^1 -- includes formfeed
---~ lpeg.space         = lpeg.S(' ')^1
---~ lpeg.nonspace      = lpeg.P(1-lpeg.space)^1
---~ lpeg.whitespace    = lpeg.S(' \r\n\f\t')^1
---~ lpeg.nonwhitespace = lpeg.P(1-lpeg.whitespace)^1
-
-local hash = { }
+local digit, sign      = R('09'), S('+-')
+local cr, lf, crlf     = P("\r"), P("\n"), P("\r\n")
+local utf8byte         = R("\128\191")
+
+patterns.utf8byte      = utf8byte
+patterns.utf8one       = R("\000\127")
+patterns.utf8two       = R("\194\223") * utf8byte
+patterns.utf8three     = R("\224\239") * utf8byte * utf8byte
+patterns.utf8four      = R("\240\244") * utf8byte * utf8byte * utf8byte
+
+patterns.digit         = digit
+patterns.sign          = sign
+patterns.cardinal      = sign^0 * digit^1
+patterns.integer       = sign^0 * digit^1
+patterns.float         = sign^0 * digit^0 * P('.') * digit^1
+patterns.number        = patterns.float + patterns.integer
+patterns.oct           = P("0") * R("07")^1
+patterns.octal         = patterns.oct
+patterns.HEX           = P("0x") * R("09","AF")^1
+patterns.hex           = P("0x") * R("09","af")^1
+patterns.hexadecimal   = P("0x") * R("09","AF","af")^1
+patterns.lowercase     = R("az")
+patterns.uppercase     = R("AZ")
+patterns.letter        = patterns.lowercase + patterns.uppercase
+patterns.space         = S(" ")
+patterns.eol           = S("\n\r")
+patterns.spacer        = S(" \t\f\v")  -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
+patterns.newline       = crlf + cr + lf
+patterns.nonspace      = 1 - patterns.space
+patterns.nonspacer     = 1 - patterns.spacer
+patterns.whitespace    = patterns.eol + patterns.spacer
+patterns.nonwhitespace = 1 - patterns.whitespace
+patterns.utf8          = patterns.utf8one + patterns.utf8two + patterns.utf8three + patterns.utf8four
+patterns.utfbom        = P('\000\000\254\255') + P('\255\254\000\000') + P('\255\254') + P('\254\255') + P('\239\187\191')
 
 function lpeg.anywhere(pattern) --slightly adapted from website
-    return P { P(pattern) + 1 * lpeg.V(1) }
-end
-
-function lpeg.startswith(pattern) --slightly adapted
-    return P(pattern)
+    return P { P(pattern) + 1 * V(1) } -- why so complex?
 end
 
 function lpeg.splitter(pattern, action)
     return (((1-P(pattern))^1)/action+1)^0
 end
 
--- variant:
-
---~ local parser = lpeg.Ct(lpeg.splitat(newline))
-
-local crlf     = P("\r\n")
-local cr       = P("\r")
-local lf       = P("\n")
-local space    = S(" \t\f\v")  -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
-local newline  = crlf + cr + lf
-local spacing  = space^0 * newline
-
+local spacing  = patterns.spacer^0 * patterns.newline -- sort of strip
 local empty    = spacing * Cc("")
 local nonempty = Cs((1-spacing)^1) * spacing^-1
 local content  = (empty + nonempty)^1
@@ -67,7 +68,7 @@ function string:splitlines()
     return match(capture,self)
 end
 
-lpeg.linebyline = content -- better make a sublibrary
+patterns.textline = content
 
 --~ local p = lpeg.splitat("->",false)  print(match(p,"oeps->what->more"))  -- oeps what more
 --~ local p = lpeg.splitat("->",true)   print(match(p,"oeps->what->more"))  -- oeps what->more
@@ -123,43 +124,20 @@ end
 --~     local p = pp
 --~     for l=1,#list do
 --~         if p then
---~             p = p + lpeg.P(list[l])
+--~             p = p + P(list[l])
 --~         else
---~             p = lpeg.P(list[l])
+--~             p = P(list[l])
 --~         end
 --~     end
 --~     return p
 --~ end
 
 --~ from roberto's site:
---~
---~ -- decode a two-byte UTF-8 sequence
---~ local function f2 (s)
---~   local c1, c2 = string.byte(s, 1, 2)
---~   return c1 * 64 + c2 - 12416
---~ end
---~
---~ -- decode a three-byte UTF-8 sequence
---~ local function f3 (s)
---~   local c1, c2, c3 = string.byte(s, 1, 3)
---~   return (c1 * 64 + c2) * 64 + c3 - 925824
---~ end
---~
---~ -- decode a four-byte UTF-8 sequence
---~ local function f4 (s)
---~   local c1, c2, c3, c4 = string.byte(s, 1, 4)
---~   return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168
---~ end
---~
---~ local cont = lpeg.R("\128\191")   -- continuation byte
---~
---~ local utf8 = lpeg.R("\0\127") / string.byte
---~            + lpeg.R("\194\223") * cont / f2
---~            + lpeg.R("\224\239") * cont * cont / f3
---~            + lpeg.R("\240\244") * cont * cont * cont / f4
---~
---~ local decode_pattern = lpeg.Ct(utf8^0) * -1
-
-local cont = R("\128\191")   -- continuation byte
-
-lpeg.patterns.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont
+
+local f1 = string.byte
+
+local function f2(s) local c1, c2         = f1(s,1,2) return   c1 * 64 + c2                       -    12416 end
+local function f3(s) local c1, c2, c3     = f1(s,1,3) return  (c1 * 64 + c2) * 64 + c3            -   925824 end
+local function f4(s) local c1, c2, c3, c4 = f1(s,1,4) return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168 end
+
+patterns.utf8byte = patterns.utf8one/f1 + patterns.utf8two/f2 + patterns.utf8three/f3 + patterns.utf8four/f4
diff --git a/tex/context/base/l-os.lua b/tex/context/base/l-os.lua
index 7dd288877..4f0c0c176 100644
--- a/tex/context/base/l-os.lua
+++ b/tex/context/base/l-os.lua
@@ -8,7 +8,7 @@ if not modules then modules = { } end modules ['l-os'] = {
 
 -- maybe build io.flush in os.execute
 
-local find, format = string.find, string.format
+local find, format, gsub = string.find, string.format, string.gsub
 local random, ceil = math.random, math.ceil
 
 local execute, spawn, exec, ioflush = os.execute, os.spawn or os.execute, os.exec or os.execute, io.flush
@@ -88,13 +88,15 @@ end
 
 -- no need for function anymore as we have more clever code and helpers now
 
-os.resolvers = { }
+os.resolvers = os.resolvers or { }
+
+local resolvers = os.resolvers
 
 local osmt = getmetatable(os) or { __index = function(t,k) t[k] = "unset" return "unset" end }
 local osix = osmt.__index
 
 osmt.__index = function(t,k)
-    return (os.resolvers[k] or osix)(t,k)
+    return (resolvers[k] or osix)(t,k)
 end
 
 setmetatable(os,osmt)
diff --git a/tex/context/base/lxml-lpt.lua b/tex/context/base/lxml-lpt.lua
index 04808c70f..883b174db 100644
--- a/tex/context/base/lxml-lpt.lua
+++ b/tex/context/base/lxml-lpt.lua
@@ -475,10 +475,10 @@ local lp_or      = P("|")  / " or "
 local lp_and     = P("&")  / " and "
 
 local lp_builtin = P (
-P("firstindex")      / "1" +
-P("lastindex")       / "(#ll.__p__.dt or 1)" +
-P("firstelement")    / "1" +
-P("lastelement")     / "(ll.__p__.en or 1)" +
+        P("firstindex")   / "1" +
+        P("lastindex")    / "(#ll.__p__.dt or 1)" +
+        P("firstelement") / "1" +
+        P("lastelement")  / "(ll.__p__.en or 1)" +
         P("first")        / "1" +
         P("last")         / "#list" +
         P("rootposition") / "order" +
@@ -488,7 +488,7 @@ P("lastelement")     / "(ll.__p__.en or 1)" +
         P("index")        / "(ll.ni or 1)" +
         P("match")        / "(ll.mi or 1)" +
         P("text")         / "(ll.dt[1] or '')" +
---~         P("name")         / "(ll.ns~='' and ll.ns..':'..ll.tg)" +
+    --  P("name")         / "(ll.ns~='' and ll.ns..':'..ll.tg)" +
         P("name")         / "((ll.ns~='' and ll.ns..':'..ll.tg) or ll.tg)" +
         P("tag")          / "ll.tg" +
         P("ns")           / "ll.ns"
diff --git a/tex/context/base/lxml-tab.lua b/tex/context/base/lxml-tab.lua
index b275ef03b..b13e2a4ac 100644
--- a/tex/context/base/lxml-tab.lua
+++ b/tex/context/base/lxml-tab.lua
@@ -33,6 +33,7 @@ local type, next, setmetatable, getmetatable, tonumber = type, next, setmetatabl
 local format, lower, find, match = string.format, string.lower, string.find, string.match
 local utfchar = unicode.utf8.char
 local lpegmatch = lpeg.match
+local P, S, R, C, V, C, Cs = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.C, lpeg.Cs
 
 --[[ldx--
 <p>First a hack to enable namespace resolving. A namespace is characterized by
@@ -44,7 +45,7 @@ much cleaner.</p>
 
 xml.xmlns = xml.xmlns or { }
 
-local check = lpeg.P(false)
+local check = P(false)
 local parse = check
 
 --[[ldx--
@@ -57,8 +58,8 @@ xml.registerns("mml","mathml")
 --ldx]]--
 
 function xml.registerns(namespace, pattern) -- pattern can be an lpeg
-    check = check + lpeg.C(lpeg.P(lower(pattern))) / namespace
-    parse = lpeg.P { lpeg.P(check) + 1 * lpeg.V(1) }
+    check = check + C(P(lower(pattern))) / namespace
+    parse = P { P(check) + 1 * V(1) }
 end
 
 --[[ldx--
@@ -336,8 +337,6 @@ local function fromdec(s)
     end
 end
 
-local P, S, R, C, V, Cs = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.Cs
-
 local rest = (1-P(";"))^0
 local many = P(1)^0
 
@@ -439,10 +438,7 @@ local valid            = R('az', 'AZ', '09') + S('_-.')
 local name_yes         = C(valid^1) * colon * C(valid^1)
 local name_nop         = C(P(true)) * C(valid^1)
 local name             = name_yes + name_nop
-
-local utfbom           = P('\000\000\254\255') + P('\255\254\000\000') +
-                         P('\255\254') + P('\254\255') + P('\239\187\191') -- no capture
-
+local utfbom           = lpeg.patterns.utfbom -- no capture
 local spacing          = C(space^0)
 
 ----- entitycontent    = (1-open-semicolon)^0
@@ -527,10 +523,10 @@ local doctype          = (spacing * begindoctype     * somedoctype     * enddoct
 
 --  nicer but slower:
 --
---  local instruction = (lpeg.Cc("@pi@") * spacing * begininstruction * someinstruction * endinstruction) / add_special
---  local comment     = (lpeg.Cc("@cm@") * spacing * begincomment     * somecomment     * endcomment    ) / add_special
---  local cdata       = (lpeg.Cc("@cd@") * spacing * begincdata       * somecdata       * endcdata      ) / add_special
---  local doctype     = (lpeg.Cc("@dt@") * spacing * begindoctype     * somedoctype     * enddoctype    ) / add_special
+--  local instruction = (Cc("@pi@") * spacing * begininstruction * someinstruction * endinstruction) / add_special
+--  local comment     = (Cc("@cm@") * spacing * begincomment     * somecomment     * endcomment    ) / add_special
+--  local cdata       = (Cc("@cd@") * spacing * begincdata       * somecdata       * endcdata      ) / add_special
+--  local doctype     = (Cc("@dt@") * spacing * begindoctype     * somedoctype     * enddoctype    ) / add_special
 
 local trailer = space^0 * (text_unparsed/set_message)^0
 
diff --git a/tex/context/base/lxml-tex.lua b/tex/context/base/lxml-tex.lua
index f27fd6d44..754c9eb7d 100644
--- a/tex/context/base/lxml-tex.lua
+++ b/tex/context/base/lxml-tex.lua
@@ -13,6 +13,7 @@ local concat, insert, remove, gsub, find = table.concat, table.insert, table.rem
 local format, sub, gsub, find, gmatch, match = string.format, string.sub, string.gsub, string.find, string.gmatch, string.match
 local type, next, tonumber, tostring = type, next, tonumber, tostring
 local lpegmatch = lpeg.match
+local P, S, C, Cc = lpeg.P, lpeg.S, lpeg.C, lpeg.Cc
 
 if not tex and not tex.sprint then
     tex = {
@@ -61,30 +62,27 @@ finalizers.tex = finalizers.tex or { }
 -- because we avoid tokenization of leading spaces and xml can be
 -- rather verbose (indented)
 
-local crlf      = lpeg.P("\r\n")
-local cr        = lpeg.P("\r")
-local lf        = lpeg.P("\n")
-local newline   = crlf + cr + lf
-local space     = lpeg.S(" \t\f\v")
-local ampersand = lpeg.P("&")
-local semicolon = lpeg.P(";")
+local newline   = lpeg.patterns.newline
+local space     = lpeg.patterns.spacer
+local ampersand = P("&")
+local semicolon = P(";")
 local spacing   = newline * space^0
-local content   = lpeg.C((1-spacing-ampersand)^1)
-local verbose   = lpeg.C((1-(space+newline))^1)
-local entity    = ampersand * lpeg.C((1-semicolon)^1) * semicolon
+local content   = C((1-spacing-ampersand)^1)
+local verbose   = C((1-(space+newline))^1)
+local entity    = ampersand * C((1-semicolon)^1) * semicolon
 
 local xmltextcapture = (
-    space^0 * newline^2  * lpeg.Cc("")            / texprint  + -- better ^-2 ?
-    space^0 * newline    * space^0 * lpeg.Cc(" ") / texsprint +
-    content                                       / function(str) return texsprint(notcatcodes,str) end + -- was just texsprint, current catcodes regime is notcatcodes
-    entity                                        / xml.resolved_entity
+    space^0 * newline^2  * Cc("")            / texprint  + -- better ^-2 ?
+    space^0 * newline    * space^0 * Cc(" ") / texsprint +
+    content                                  / function(str) return texsprint(notcatcodes,str) end + -- was just texsprint, current catcodes regime is notcatcodes
+    entity                                  / xml.resolved_entity
 )^0
 
 local ctxtextcapture = (
-    space^0 * newline^2  * lpeg.Cc("")            / texprint  + -- better ^-2 ?
-    space^0 * newline    * space^0 * lpeg.Cc(" ") / texsprint +
-    content                                       / function(str) return texsprint(ctxcatcodes,str) end + -- was just texsprint, current catcodes regime is notcatcodes
-    entity                                        / xml.resolved_entity
+    space^0 * newline^2  * Cc("")            / texprint  + -- better ^-2 ?
+    space^0 * newline    * space^0 * Cc(" ") / texsprint +
+    content                                  / function(str) return texsprint(ctxcatcodes,str) end + -- was just texsprint, current catcodes regime is notcatcodes
+    entity                                   / xml.resolved_entity
 )^0
 
 local forceraw, rawroot = false, nil
@@ -178,7 +176,6 @@ function lxml.store(id,root,filename)
     end
 end
 
---~ local splitter = lpeg.C((1-lpeg.P(":"))^1) * lpeg.P("::") * lpeg.C(lpeg.P(1)^1)
 local splitter = lpeg.splitat("::")
 
 lxml.idsplitter = splitter
@@ -482,12 +479,12 @@ end
 
 local pihandlers = { }  xml.pihandlers = pihandlers
 
-local kind   = lpeg.P("context-") * lpeg.C((1-lpeg.P("-"))^1) * lpeg.P("-directive")
-local space  = lpeg.S(" \n\r")
+local kind   = P("context-") * C((1-P("-"))^1) * P("-directive")
+local space  = S(" \n\r")
 local spaces = space^0
-local class  = lpeg.C((1-space)^0)
+local class  = C((1-space)^0)
 local key    = class
-local value  = lpeg.C(lpeg.P(1-(space * -1))^0)
+local value  = C(P(1-(space * -1))^0)
 
 local parser = kind * spaces * class * spaces * key * spaces * value
 
diff --git a/tex/context/base/math-ali.mkiv b/tex/context/base/math-ali.mkiv
index c9741e8cc..fcf5b4cc5 100644
--- a/tex/context/base/math-ali.mkiv
+++ b/tex/context/base/math-ali.mkiv
@@ -610,8 +610,8 @@
   {\dodoubleempty\dodefinemathmatrix}
 
 \def\dodefinemathmatrix[#1]% [#2]%
-  {\unexpanded\setvalue{\e!start#1}{\dodoubleempty\dostartmathmatrix[#1]}%
-   \unexpanded\setvalue{\e!stop #1}{\dostopmathmatrix}%
+  {\setuvalue{\e!start#1}{\dodoubleempty\dostartmathmatrix[#1]}%
+   \setuvalue{\e!stop #1}{\dostopmathmatrix}%
    \setupmathmatrix[#1]}% [#2]
 
 \definemathmatrix[matrix]
diff --git a/tex/context/base/math-arr.mkiv b/tex/context/base/math-arr.mkiv
index 0b2ee9b66..6019de4bc 100644
--- a/tex/context/base/math-arr.mkiv
+++ b/tex/context/base/math-arr.mkiv
@@ -217,13 +217,13 @@
 \def\redefinebotharrow#1#2#3% real dirty, this overload!
   {\doifdefined{#1}
      {\pushmacro\dohandlemtharrow
-      \def\dohandlemtharrow[##1][##2]{\unexpanded\setvalue{#1}{\dohandlemtharrow[#2][##2]}}%
+      \def\dohandlemtharrow[##1][##2]{\setuvalue{#1}{\dohandlemtharrow[#2][##2]}}%
       % == \def\dohandlemtharrow[##1][##2]{\dodefinebotharrow{#1}{#2}{##2}}%
       \getvalue{#1}%
       \popmacro\dohandlemtharrow}}
 
 \def\dodefinebotharrow#1#2#3%
-  {\unexpanded\setvalue{#1}{\dohandlemtharrow[#2][#3]}}
+  {\setuvalue{#1}{\dohandlemtharrow[#2][#3]}}
 
 \def\dohandlemtharrow
   {\dotripleempty\doxmtharrow}
@@ -363,9 +363,9 @@
 
 \def\dodefinemathoverarrow[#1][#2][#3]%
   {\ifthirdargument
-      \unexpanded\setvalue{#1}{\dohandlemathoverarrow[#2][#3]}%
+      \setuvalue{#1}{\dohandlemathoverarrow[#2][#3]}%
     \else
-      \unexpanded\setvalue{#1}{\dohandlemathoverarrow[\zeropoint][#2]}%
+      \setuvalue{#1}{\dohandlemathoverarrow[\zeropoint][#2]}%
     \fi}
 
 \def\dohandlemathoverarrow[#1][#2]%
@@ -390,9 +390,9 @@
 
 \def\dodefinemathunderarrow[#1][#2][#3]%
   {\ifthirdargument
-      \unexpanded\setvalue{#1}{\dohandlemathunderarrow[#2][#3]}%
+      \setuvalue{#1}{\dohandlemathunderarrow[#2][#3]}%
     \else
-      \unexpanded\setvalue{#1}{\dohandlemathunderarrow[0.3ex][#2]}%
+      \setuvalue{#1}{\dohandlemathunderarrow[0.3ex][#2]}%
     \fi}
 
 \def\dohandlemathunderarrow[#1][#2]%
diff --git a/tex/context/base/math-ini.mkiv b/tex/context/base/math-ini.mkiv
index 9ac43455d..d4be17ded 100644
--- a/tex/context/base/math-ini.mkiv
+++ b/tex/context/base/math-ini.mkiv
@@ -244,12 +244,12 @@
   {\ifthirdargument
      \processaction
        [#3]
-       [one=>\unexpanded\setvalue{#1}##1{\puremathcomm{#2}{#4{##1}}},
-        two=>\unexpanded\setvalue{#1}##1##2{\puremathcomm{#2}{#4{##1}{##2}}}]%
+       [one=>\setuvalue{#1}##1{\puremathcomm{#2}{#4{##1}}},
+        two=>\setuvalue{#1}##1##2{\puremathcomm{#2}{#4{##1}{##2}}}]%
    \else\ifsecondargument
-     \unexpanded\setvalue{#1}{\puremathcomm{#2}{#4}}%
+     \setuvalue{#1}{\puremathcomm{#2}{#4}}%
    \else
-     \unexpanded\setvalue{#1}{\puremathcomm{nothing}{#4}}%
+     \setuvalue{#1}{\puremathcomm{nothing}{#4}}%
    \fi\fi}
 
 %D Moved from font-ini.mkiv:
diff --git a/tex/context/base/node-rul.mkiv b/tex/context/base/node-rul.mkiv
index ca4018d14..a14f56955 100644
--- a/tex/context/base/node-rul.mkiv
+++ b/tex/context/base/node-rul.mkiv
@@ -87,7 +87,7 @@
    \fi
    \normalexpanded{\checkalldefinedbars{\noexpand\doredefinebar{#1}\the\checkalldefinedbars}}%
    \dodefinebarindeed{#1}%
-   \unexpanded\setvalue{#1}{\doruled{#1}}}
+   \setuvalue{#1}{\doruled{#1}}}
 
 \def\dodefinebarindeed#1%
   {\bgroup
@@ -233,7 +233,7 @@
    \fi
    \normalexpanded{\checkalldefinedshifts{\noexpand\doredefineshift{#1}\the\checkalldefinedshifts}}%
    \dodefineshiftindeed{#1}%
-   \unexpanded\setvalue{#1}{\doshifted{#1}}}
+   \setuvalue{#1}{\doshifted{#1}}}
 
 \def\dodefineshiftindeed#1%
   {\bgroup
diff --git a/tex/context/base/pack-rul.mkiv b/tex/context/base/pack-rul.mkiv
index 9dc7e5321..a77436b61 100644
--- a/tex/context/base/pack-rul.mkiv
+++ b/tex/context/base/pack-rul.mkiv
@@ -2655,9 +2655,9 @@
       \c!orientation=,
       \c!indenting=,
       #2]%
-   \unexpanded\setvalue{\e!start#1}{\dostartframedtext[#1]}%
-   \unexpanded\setvalue{\e!stop #1}{\dostopframedtext     }%
-   \unexpanded\setvalue        {#1}{\doframedtext     [#1]}}
+   \setuvalue{\e!start#1}{\dostartframedtext[#1]}%
+   \setuvalue{\e!stop #1}{\dostopframedtext     }%
+   \setuvalue        {#1}{\doframedtext     [#1]}}
 
 \def\defineframedtext
   {\dodoubleempty\dodefineframedtext}
@@ -2833,7 +2833,7 @@
 
 \def\dodefineframed[#1][#2]%
   {\iffirstargument
-     \unexpanded\setvalue{#1}{\dodoubleempty\doframed[#2]}%
+     \setuvalue{#1}{\dodoubleempty\doframed[#2]}%
    \fi}
 
 \def\doframed[#1][#2]%
diff --git a/tex/context/base/page-mar.mkiv b/tex/context/base/page-mar.mkiv
index b85a99aa6..83a08d00e 100644
--- a/tex/context/base/page-mar.mkiv
+++ b/tex/context/base/page-mar.mkiv
@@ -58,7 +58,7 @@
       \c!hoffset=\leftmargindistance,
       \c!command=,
       #2]%
-   \unexpanded\setvalue{#1}{\dohandlemarginline{#1}}}
+   \setuvalue{#1}{\dohandlemarginline{#1}}}
 
 \def\marginlineparameter  #1{\csname\??im\??im\currentmarginline#1\endcsname}
 \def\marginlineexecuter #1#2{\executeifdefined{\??im\??im\currentmarginline#1}{#2}}
diff --git a/tex/context/base/page-str.mkiv b/tex/context/base/page-str.mkiv
index e4fd39794..4fd5d58a5 100644
--- a/tex/context/base/page-str.mkiv
+++ b/tex/context/base/page-str.mkiv
@@ -25,9 +25,9 @@
 
 % not yet ok in mkiv ... marknotes .. will be completely redone
 
-\unprotect
+\endinput
 
-% taco, what is the best way to append a otr chunk (insert pagediscards?)
+\unprotect
 
 \let\currentoutputstream\s!default
 
@@ -107,21 +107,12 @@
         \kern\strutdepth}%
    \fi}
 
-% \def\presetoutputstream
-%   {\pdffirstlineheight\strutheight
-%    \pdflastlinedepth  \strutdepth
-%    \pdfeachlineheight \strutheight
-%    \pdfeachlinedepth  \strutdepth}
-
 \let\presetoutputstream\relax
 
 \def\outputstreamht  [#1]{\ht\outputstreamtag{#1}}
 \def\outputstreamdp  [#1]{\dp\outputstreamtag{#1}}
 \def\outputstreamwd  [#1]{\wd\outputstreamtag{#1}}
 
-%def\outputstreambox [#1]{\ifvoid\outputstreamtag{#1}\else\box \outputstreamtag{#1}\fi}
-%def\outputstreamcopy[#1]{\ifvoid\outputstreamtag{#1}\else\copy\outputstreamtag{#1}\fi}
-
 \def\dowithoutputstreambox#1[#2]{\ifvoid\outputstreamtag{#2}\else#1\outputstreamtag{#2}\fi}
 
 \def\outputstreamcopy   {\dowithoutputstreambox\copy   }
@@ -129,55 +120,13 @@
 \def\outputstreamunvcopy{\dowithoutputstreambox\unvcopy}
 \def\outputstreamunvbox {\dowithoutputstreambox\unvbox }
 
-%D Footnotes don't go along with streams, simply because there is no
-%D way to re-split inserts. A dirty way out is to use marks and store
-%D notes that way.
-
-% not mkiv ready yet
-
-\def\definemarknote
-  {\dodoubleempty\dodefinemarknote}
-
-\def\dodefinemarknote[#1][#2]%
-  {\definemarking[mn:#1]%
-   \setvalue{mn:#1:n}{0}%
-   \getparameters
-     [mn:#1]
-     [\c!before=,
-      \c!after=,
-      \c!inbetween=\endgraf,
-      \c!command=\firstofoneargument,
-      #2]}
-
-\def\setmarknote[#1]#2%
-  {\doglobal\incrementvalue{mn:#1:n}%
-   \setgvalue{mn:#1:t:\getvalue{mn:#1:n}}{#2}%
-   \expanded{\marking[mn:#1]{\getvalue{mn:#1:n}}}}
-
-\def\flushmarknotes[#1]% assumes split
-  {\begingroup
-%    \edef\firstmarknote{0\fetchmark[mn:#1][column:first]}%
-%    \edef\lastmarknote {0\fetchmark[mn:#1][column:last]}%
-%    \ifnum\firstmarknote<\lastmarknote\relax
-%      \getvalue{mn:#1\c!before}%
-%      \dostepwiserecurse\firstmarknote\lastmarknote\plusone
-%        {\ifnum\recurselevel>\firstmarknote\relax
-%           \ifnum\recurselevel<\lastmarknote\relax
-%             \getvalue{mn:#1\c!inbetween}%
-%           \fi
-%         \fi
-%         \getvalue{mn:#1\c!command}{\getvalue{mn:#1:t:\recurselevel}}}%
-%      \getvalue{mn:#1\c!after}%
-%    \fi
-   \endgroup}
-
-\def\erasemarknotes[#1]%
-  {\begingroup
-   \edef\firstmarknote{0\fetchmark[mn:#1][column:first]}%
-   \edef\lastmarknote {0\fetchmark[mn:#1][column:last]}%
-   \dostepwiserecurse\firstmarknote\lastmarknote\plusone
-     {\global\letvalue{mn:#1:t:\recurselevel}\empty}%
-   \endgroup}
+%D Obsolete in \MKIV:
+
+\def\definemarknote          {\dodoubleempty\dodefinemarknote}
+\def\dodefinemarknote[#1][#2]{}
+\def\setmarknote         [#1]{\gobbleoneargument}
+\def\flushmarknotes      [#1]{}
+\def\erasemarknotes      [#1]{}
 
 %D The next section implements synchronization of (currently
 %D two) output streams. In due time we will implement both a
diff --git a/tex/context/base/prop-ini.mkiv b/tex/context/base/prop-ini.mkiv
index c5df391a7..10b313506 100644
--- a/tex/context/base/prop-ini.mkiv
+++ b/tex/context/base/prop-ini.mkiv
@@ -98,15 +98,15 @@
    \letgvalue{\??py\s!check#1}\docheckproperty
    \doifelsevalue{\??py#1\c!method}\v!command
      {\doifelsevalue{\??py#1\c!global}\v!yes
-        {\unexpanded\setgvalue{\e!start#1}{\dostartproperty{#1}}%
-         \unexpanded\setgvalue{\e!stop #1}{\dostopproperty}}%
-        {\unexpanded\setgvalue{\e!start#1}{\dostartgproperty{#1}}%
-         \unexpanded\setgvalue{\e!stop #1}{\dostopgproperty}}}%
+        {\setugvalue{\e!start#1}{\dostartproperty{#1}}%
+         \setugvalue{\e!stop #1}{\dostopproperty}}%
+        {\setugvalue{\e!start#1}{\dostartgproperty{#1}}%
+         \setugvalue{\e!stop #1}{\dostopgproperty}}}%
      {\doifelsevalue{\??py#1\c!global}\v!yes
-        {\unexpanded\setgvalue{\e!start#2}[##1]{\dostartproperty{##1}}%
-         \unexpanded\setgvalue{\e!stop #2}{\dostopproperty}}%
-        {\unexpanded\setgvalue{\e!start#2}[##1]{\dostartgproperty{##1}}%
-         \unexpanded\setgvalue{\e!stop #2}{\dostopgproperty}}}}
+        {\setugvalue{\e!start#2}[##1]{\dostartproperty{##1}}%
+         \setugvalue{\e!stop #2}{\dostopproperty}}%
+        {\setugvalue{\e!start#2}[##1]{\dostartgproperty{##1}}%
+         \setugvalue{\e!stop #2}{\dostopgproperty}}}}
 
 \def\nododefineproperty[#1][#2][#3]%
   {}
diff --git a/tex/context/base/spac-fnt.mkiv b/tex/context/base/spac-fnt.mkiv
index d8fc46a5e..c268d7893 100644
--- a/tex/context/base/spac-fnt.mkiv
+++ b/tex/context/base/spac-fnt.mkiv
@@ -61,8 +61,11 @@
 
 %D Bonus macro, see core-sec.tex
 
+\newconditional\fontattributeisset
+
 \unexpanded\def\dosetfontattribute#1#2%
   {\ifcsname#1#2\endcsname
+     \settrue\fontattributeisset % reset is done elsewhere
      \@EA\doconvertfont\csname#1#2\@EA\endcsname
    \fi\empty}
 
diff --git a/tex/context/base/spac-ver.lua b/tex/context/base/spac-ver.lua
index 02fe1fe85..af9f5170f 100644
--- a/tex/context/base/spac-ver.lua
+++ b/tex/context/base/spac-ver.lua
@@ -1088,6 +1088,14 @@ function nodes.repackage_graphicvadjust(head,groupcode) -- we can make an action
     end
 end
 
+--~ function nodes.repackage_graphicvadjust(head,groupcode) -- we can make an actionchain for mvl only
+--~     if groupcode == "" then -- mvl only
+--~         return head, false
+--~     else
+--~         return head, false
+--~     end
+--~ end
+
 --~ tasks.appendaction("finalizers", "lists", "nodes.repackage_graphicvadjust")
 
 nodes.builders = nodes.builder or { }
diff --git a/tex/context/base/spac-ver.mkiv b/tex/context/base/spac-ver.mkiv
index 58aec3caf..1a4291e17 100644
--- a/tex/context/base/spac-ver.mkiv
+++ b/tex/context/base/spac-ver.mkiv
@@ -78,9 +78,42 @@
 
 \fi
 
+% \def\presetnormallineheight
+%   {\edef\normallineheight{\@@itline}%
+%   %done elsewhere : \spacing\!!plusone % new per 10/08/2004, else problems in otr / !! needed
+%    \iflocalinterlinespace \else
+%      \doifdefined\bodyfontinterlinespecs
+%        {\doifsomething\bodyfontinterlinespace
+%           {\edef\normallineheight{\bodyfontinterlinespace}}}%
+%    \fi}
+
+% \def\setupspecifiedinterlinespace[#1]%
+%   {\getparameters[\??it][#1]%
+%    \scratchdimen0\@@itheight\points
+%    \advance\scratchdimen 0\@@itdepth\points
+%    \ifdim\scratchdimen>\onepoint
+%      \showmessage\m!layouts{10}{\@@itheight,\@@itdepth}%
+%      \let\@@itheight\strutheightfactor
+%      \let\@@itdepth \strutdepthfactor
+%    \else
+%      \let\strutheightfactor\@@itheight
+%      \let\strutdepthfactor \@@itdepth
+%    \fi
+%    \let\minimumstrutheight \@@itminheight
+%    \let\minimumstrutdepth  \@@itmindepth
+%    \let\minimumlinedistance\@@itdistance
+%    \let\normallineheight   \@@itline % let ! ! ! ! ! ivm ex
+%    \doifelse\@@ittop\v!height % new, topskip does more bad than good
+%      {\let\topskipfactor   \@@itheight}
+%      {\let\topskipfactor   \@@ittop   }%
+%    \let\maxdepthfactor     \@@itbottom
+%    \let\baselinegluefactor \@@itstretch
+%    \setfontparameters % redundant, can be \setstrut, test first
+%    \updateraggedskips} % yes indeed
+
 \def\presetnormallineheight
-  {\edef\normallineheight{\@@itline}%
-%  done elsewhere : \spacing\!!plusone % new per 10/08/2004, else problems in otr / !! needed
+  {\edef\normallineheight{\interlinespaceparameter\c!line}%
+  %done elsewhere : \spacing\!!plusone % new per 10/08/2004, else problems in otr / !! needed
    \iflocalinterlinespace \else
      \doifdefined\bodyfontinterlinespecs
        {\doifsomething\bodyfontinterlinespace
@@ -88,43 +121,28 @@
    \fi}
 
 \def\setupspecifiedinterlinespace[#1]%
-  {\getparameters[\??it][#1]%
-   \scratchdimen0\@@itheight\points
-   \advance\scratchdimen 0\@@itdepth\points
-   \ifdim\scratchdimen>\onepoint
-     \showmessage\m!layouts{10}{\@@itheight,\@@itdepth}%
-     \let\@@itheight\strutheightfactor
-     \let\@@itdepth \strutdepthfactor
-   \else
-     \let\strutheightfactor\@@itheight
-     \let\strutdepthfactor \@@itdepth
+  {\getparameters[\??it\currentinterlinespace][#1]%
+   \dosetupspecifiedinterlinespaceindeed}
+
+\def\dosetupspecifiedinterlinespaceindeed
+  {\edef\strutheightfactor  {\interlinespaceparameter\c!height}%
+   \edef\strutdepthfactor   {\interlinespaceparameter\c!depth}%
+   \edef\minimumstrutheight {\interlinespaceparameter\c!minheight}%
+   \edef\minimumstrutdepth  {\interlinespaceparameter\c!mindepth}%
+   \edef\minimumlinedistance{\interlinespaceparameter\c!distance}%
+   \edef\normallineheight   {\interlinespaceparameter\c!line}%
+   \edef\topskipfactor      {\interlinespaceparameter\c!top}%
+   \edef\maxdepthfactor     {\interlinespaceparameter\c!bottom}%
+   \edef\baselinegluefactor {\interlinespaceparameter\c!stretch}%
+   % often topskip does more bad than good, so:
+   \ifx\topskipfactor\v!height
+     \let\topskipfactor\strutheightfactor
    \fi
-   \let\minimumstrutheight \@@itminheight
-   \let\minimumstrutdepth  \@@itmindepth
-   \let\minimumlinedistance\@@itdistance
-   \let\normallineheight   \@@itline % let ! ! ! ! ! ivm ex
-   \doifelse\@@ittop\v!height % new, topskip does more bad than good
-     {\let\topskipfactor   \@@itheight}
-     {\let\topskipfactor   \@@ittop   }%
-   \let\maxdepthfactor     \@@itbottom
-   \let\baselinegluefactor \@@itstretch
    \setfontparameters % redundant, can be \setstrut, test first
    \updateraggedskips} % yes indeed
 
 \let\currentrelativeinterlinespace\empty
 
-% \def\setuprelativeinterlinespace[#1]%
-%   {\processallactionsinset
-%      [#1]
-%      [      \v!on=>\oninterlineskip,
-%            \v!off=>\offinterlineskip,
-%          \v!reset=>\let\currentrelativeinterlinespace\empty
-%                    \let\setrelativeinterlinespace\relax
-%                    \setfontparameters,
-%           \v!auto=>\let\setrelativeinterlinespace\dosetrelativeinterlinespace,
-%        \s!unknown=>\assignvalue\commalistelement\currentrelativeinterlinespace{1.00}{1.25}{1.50}%
-%                    \spacing\currentrelativeinterlinespace]}
-
 \setvalue{\??it::\v!on   }{\oninterlineskip}
 \setvalue{\??it::\v!off  }{\offinterlineskip}
 \setvalue{\??it::\v!reset}{\let\currentrelativeinterlinespace\empty
@@ -132,9 +150,15 @@
                            \setfontparameters}
 \setvalue{\??it::\v!auto }{\let\setrelativeinterlinespace\dosetrelativeinterlinespace}
 
-\def\dosetspecifiedrelativeinterlinespace#1%
-  {\assignvalue{#1}\currentrelativeinterlinespace{1.00}{1.25}{1.50}%
-   \spacing\currentrelativeinterlinespace}
+% \def\dosetspecifiedrelativeinterlinespace#1%
+%   {\assignvalue{#1}\currentrelativeinterlinespace{1.00}{1.25}{1.50}%
+%    \spacing\currentrelativeinterlinespace}
+
+\def\dosetspecifiedrelativeinterlinespace#1% fragile?
+  {\doifdimensionelse{#1}
+     {\setupspecifiedinterlinespace[\c!line=#1]}
+     {\assignvalue{#1}\currentrelativeinterlinespace{1.00}{1.25}{1.50}%
+      \spacing\currentrelativeinterlinespace}}
 
 \def\setuprelativeinterlinespace[#1]%
   {\processcommalist[#1]\dosetuprelativeinterlinespace}
@@ -158,6 +182,43 @@
 \newtoks \everysetupglobalinterlinespace
 \newtoks \everysetuplocalinterlinespace
 
+% \def\complexsetupinterlinespace[#1]% \commalistelement ipv #1
+%   {\doifassignmentelse{#1}\setupspecifiedinterlinespace\setuprelativeinterlinespace[#1]%
+%    \the\iflocalinterlinespace\everysetuplocalinterlinespace\else\everysetupglobalinterlinespace\fi}
+
+\def\interlinespaceparameter          #1{\csname\dointerlinespaceparameter{\??it\currentinterlinespace}#1\endcsname}
+\def\dointerlinespaceparameter      #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\dointerlinespaceparentparameter\csname#1\s!parent\endcsname#2\fi}
+\def\dointerlinespaceparentparameter#1#2{\ifx#1\relax\s!empty\else\dointerlinespaceparameter#1#2\fi}
+
+\newconditional\interlinespaceisset
+
+\let\currentinterlinespace\empty
+
+\def\defineinterlinespace
+  {\dodoubleempty\dodefineinterlinespace}
+
+\def\dodefineinterlinespace[#1][#2]%
+  {\getparameters[\??it#1][\s!parent=\??it,#2]}
+
+\unexpanded\def\setupinterlinespace
+  {\dodoubleempty\dosetupinterlinespace}
+
+\def\dosetupinterlinespace[#1][#2]%
+  {\settrue\interlinespaceisset % reset has to be done when needed
+   \ifsecondargument
+     \getparameters[\??it#1][#2]%
+   \else\iffirstargument
+     \edef\currentinterlinespace{\ifcsname\??it#1\s!parent\endcsname#1\fi}%
+     \ifx\currentinterlinespace\empty
+       \complexsetupinterlinespace[#1]%
+     \else
+       \dosetupspecifiedinterlinespaceindeed
+     \fi
+   \else
+     \let\currentinterlinespace\empty
+     \simplesetupinterlinespace
+   \fi\fi}
+
 \def\complexsetupinterlinespace[#1]% \commalistelement ipv #1
   {\doifassignmentelse{#1}\setupspecifiedinterlinespace\setuprelativeinterlinespace[#1]%
    \the\iflocalinterlinespace\everysetuplocalinterlinespace\else\everysetupglobalinterlinespace\fi}
@@ -169,27 +230,80 @@
    \the\everysetuplocalinterlinespace
    \localinterlinespacefalse}
 
+% \def\dosetupcheckedinterlinespace#1% often a chain
+%   {\edef\askedinterlinespace{#1}%
+%    \ifx\askedinterlinespace\empty
+%      \simplesetupinterlinespace
+%    \else
+%      \normalexpanded{\noexpand\doifassignmentelse{\askedinterlinespace}%
+%        \noexpand\setupspecifiedinterlinespace
+%        \noexpand\setuprelativeinterlinespace[\askedinterlinespace]}%
+%      \iflocalinterlinespace
+%        \the\everysetuplocalinterlinespace
+%      \else
+%        \localinterlinespacetrue
+%        \the\everysetuplocalinterlinespace
+%        \localinterlinespacefalse
+%      \fi
+%    \fi}
+
+\def\dosetupcheckedinterlinespace#1% often a chain
+  {\edef\askedinterlinespace{#1}%
+   \ifx\askedinterlinespace\empty
+     \simplesetupinterlinespace
+   \else\ifcsname\??it\askedinterlinespace\s!parent\endcsname
+     \pushmacro\currentinterlinespace
+     \let\currentinterlinespace\askedinterlinespace
+     \dosetupspecifiedinterlinespaceindeed
+     \iflocalinterlinespace
+       \the\everysetuplocalinterlinespace
+     \else
+       \localinterlinespacetrue
+       \the\everysetuplocalinterlinespace
+       \localinterlinespacefalse
+     \fi
+     \popmacro\currentinterlinespace
+   \else
+     \normalexpanded{\noexpand\doifassignmentelse{\askedinterlinespace}%
+       \noexpand\setupspecifiedinterlinespace
+       \noexpand\setuprelativeinterlinespace[\askedinterlinespace]}%
+     \iflocalinterlinespace
+       \the\everysetuplocalinterlinespace
+     \else
+       \localinterlinespacetrue
+       \the\everysetuplocalinterlinespace
+       \localinterlinespacefalse
+     \fi
+   \fi\fi}
+
+% \unexpanded\def\setuplocalinterlinespace[#1]%
+%   {\localinterlinespacetrue
+%    \let\@@saveditheight   \@@itheight
+%    \let\@@saveditdepth    \@@itdepth
+%    \let\@@saveditline     \@@itline
+%    \let\@@saveditminheight\@@itminheight
+%    \let\@@saveditmindepth \@@itmindepth
+%    \let\@@saveditdistance \@@itdistance
+%    \let\@@savedittop      \@@ittop
+%    \let\@@saveditbottom   \@@itbottom
+%    \let\@@saveditstretch  \@@itstretch
+%    \setupinterlinespace[#1]%
+%    \let\@@itheight   \@@saveditheight
+%    \let\@@itdepth    \@@saveditdepth
+%    \let\@@itline     \@@saveditline
+%    \let\@@itminheight\@@saveditminheight
+%    \let\@@itmindepth \@@saveditmindepth
+%    \let\@@itdistance \@@saveditdistance
+%    \let\@@ittop      \@@savedittop
+%    \let\@@itbottom   \@@saveditbottom
+%    \let\@@itstretch  \@@saveditstretch
+%    \localinterlinespacefalse}
+
 \unexpanded\def\setuplocalinterlinespace[#1]%
   {\localinterlinespacetrue
-   \let\@@saveditheight   \@@itheight
-   \let\@@saveditdepth    \@@itdepth
-   \let\@@saveditline     \@@itline
-   \let\@@saveditminheight\@@itminheight
-   \let\@@saveditmindepth \@@itmindepth
-   \let\@@saveditdistance \@@itdistance
-   \let\@@savedittop      \@@ittop
-   \let\@@saveditbottom   \@@itbottom
-   \let\@@saveditstretch  \@@itstretch
+   \pushmacro\currentinterlinespace
    \setupinterlinespace[#1]%
-   \let\@@itheight   \@@saveditheight
-   \let\@@itdepth    \@@saveditdepth
-   \let\@@itline     \@@saveditline
-   \let\@@itminheight\@@saveditminheight
-   \let\@@itmindepth \@@saveditmindepth
-   \let\@@itdistance \@@saveditdistance
-   \let\@@ittop      \@@savedittop
-   \let\@@itbottom   \@@saveditbottom
-   \let\@@itstretch  \@@saveditstretch
+   \popmacro\currentinterlinespace
    \localinterlinespacefalse}
 
 \let\switchtointerlinespace\setuplocalinterlinespace
diff --git a/tex/context/base/strc-blk.lua b/tex/context/base/strc-blk.lua
index 301c76a0e..f9f20a8fb 100644
--- a/tex/context/base/strc-blk.lua
+++ b/tex/context/base/strc-blk.lua
@@ -30,7 +30,7 @@ end
 
 job.register('structure.blocks.collected', structure.blocks.tobesaved, initializer)
 
-local printer = (lpeg.linebyline/texprint)^0
+local printer = (lpeg.patterns.textline/texprint)^0 -- can be shared
 
 function blocks.print(name,data,hide)
     if hide then
diff --git a/tex/context/base/strc-def.mkiv b/tex/context/base/strc-def.mkiv
index f1a8aab87..ea5c9e66f 100644
--- a/tex/context/base/strc-def.mkiv
+++ b/tex/context/base/strc-def.mkiv
@@ -89,6 +89,7 @@
     %\c!sectionsegments=,
     \c!sectionseparatorset=\s!default,
     \c!sectionset=\v!all,
+    \c!interlinespace=,
     %\c!sectionstopper=,
     %\c!sectionstarter=,
     %\c!strut=,
diff --git a/tex/context/base/strc-des.mkiv b/tex/context/base/strc-des.mkiv
index df234b948..c457f812c 100644
--- a/tex/context/base/strc-des.mkiv
+++ b/tex/context/base/strc-des.mkiv
@@ -474,9 +474,9 @@
    \fi}
 
 \def\dodefinedescriptioncommands#1#2%
-  {\unexpanded\setevalue        {#1}{\noexpand\dodescriptioncommand{#1}}%
-   \unexpanded\setevalue{\e!start#1}{\noexpand\dodescriptionstart  {#1}}%
-   \unexpanded\setevalue{\e!stop #1}{\noexpand\dodescriptionstop   {#1}}}
+  {\setuevalue        {#1}{\noexpand\dodescriptioncommand{#1}}%
+   \setuevalue{\e!start#1}{\noexpand\dodescriptionstart  {#1}}%
+   \setuevalue{\e!stop #1}{\noexpand\dodescriptionstop   {#1}}}
 
 % handle descriptions
 
@@ -602,9 +602,9 @@
 
 \def\dodefineenumerationcommands#1#2#3#4% since we use \currentdescription, we need an edef
   {\setevalue{\??dd#3#1\s!parent}{#4}%
-   \unexpanded\setevalue        {#3#1}{\noexpand\doenumerationcommand{#1}{#2}{#3}}%
-   \unexpanded\setevalue{\e!start#3#1}{\noexpand\doenumerationstart  {#1}{#2}{#3}}%
-   \unexpanded\setevalue{\e!stop #3#1}{\noexpand\doenumerationstop   {#1}{#2}{#3}}}
+   \setuevalue        {#3#1}{\noexpand\doenumerationcommand{#1}{#2}{#3}}%
+   \setuevalue{\e!start#3#1}{\noexpand\doenumerationstart  {#1}{#2}{#3}}%
+   \setuevalue{\e!stop #3#1}{\noexpand\doenumerationstop   {#1}{#2}{#3}}}
 
 % handle enumeration
 
@@ -912,12 +912,12 @@
    \fi}
 
 \def\dodefinelabelcommands#1#2%
-  {\unexpanded\setevalue            {#1}{\noexpand\dolabelnumbercommand  {#1}}%
-   \unexpanded\setevalue{\c!reset    #1}{\noexpand\doresetlabelnumber    {#1}}%
-  %\unexpanded\setevalue{\c!set      #1}{\noexpand\dosetlabelnumber      {#1}}% [#2] or {#2}  ?
-   \unexpanded\setevalue{\e!next     #1}{\noexpand\donextlabelnumber     {#1}}%
-   \unexpanded\setevalue{\e!increment#1}{\noexpand\doincrementlabelnumber{#1}}%
-   \unexpanded\setevalue{\c!current  #1}{\noexpand\docurrentlabelnumber  {#1}}}
+  {\setuevalue            {#1}{\noexpand\dolabelnumbercommand  {#1}}%
+   \setuevalue{\c!reset    #1}{\noexpand\doresetlabelnumber    {#1}}%
+  %\setuevalue{\c!set      #1}{\noexpand\dosetlabelnumber      {#1}}% [#2] or {#2}  ?
+   \setuevalue{\e!next     #1}{\noexpand\donextlabelnumber     {#1}}%
+   \setuevalue{\e!increment#1}{\noexpand\doincrementlabelnumber{#1}}%
+   \setuevalue{\c!current  #1}{\noexpand\docurrentlabelnumber  {#1}}}
 
 % this is just for downward compatibility, we might drop it
 
@@ -982,9 +982,9 @@
       [\c!text,\c!separator,\c!width,\c!style,\c!color,
        \c!headstyle,\c!sample,\c!before,\c!after,\c!distance]%
    \getparameters[\??ds#1][#2]%
-   \unexpanded\setvalue            {#1}{\dododefineindenting{#1}{0}{1}}%
-   \unexpanded\setvalue      {\v!sub#1}{\dododefineindenting{#1}{1}{2}}%
-   \unexpanded\setvalue{\v!sub\v!sub#1}{\dododefineindenting{#1}{2}{3}}}
+   \setuvalue            {#1}{\dododefineindenting{#1}{0}{1}}%
+   \setuvalue      {\v!sub#1}{\dododefineindenting{#1}{1}{2}}%
+   \setuvalue{\v!sub\v!sub#1}{\dododefineindenting{#1}{2}{3}}}
 
 \def\dododefineindenting#1#2#3%
   {\par
diff --git a/tex/context/base/strc-flt.mkiv b/tex/context/base/strc-flt.mkiv
index 08b91823b..6af0a1434 100644
--- a/tex/context/base/strc-flt.mkiv
+++ b/tex/context/base/strc-flt.mkiv
@@ -20,7 +20,7 @@
 %D This module needs a cleanup and will be split in
 %D strc-flt.tex and page-flt.mkiv cq. page-flt.mkii.
 
-\ifx\addlocalbackgroundtobox\undefined \def\addlocalbackgroundtobox{\resetglobal\gobbleoneargument} \fi
+\ifdefined\addlocalbackgroundtobox\else \def\addlocalbackgroundtobox{\resetglobal\gobbleoneargument} \fi
 
 \def\placefloats{\doflushfloats}  % keep this one
 
@@ -268,16 +268,16 @@
    \dodefinefloatcommands[#1][#2]}
 
 \def\dodefinefloatcommands[#1][#2]%
-  {\setvalue        {\e!place\e!listof#2}{\dodoubleempty\doplacelist[#1]}%
-   \setvalue     {\e!complete\e!listof#2}{\dotripleempty\dodocompletelist[#1][#2]}%
-   \setvalue                 {\e!place#1}{\dotripleempty\docomplexplacefloat[#1]}%
-   \setvalue               {\e!reserve#1}{\doquadrupleempty\docomplexreserveblock[#1]}%
-   \setvalue          {\e!start#1\e!text}{\dotripleempty\docomplexstarttextblock[#1]}%
-   \setvalue           {\e!stop#1\e!text}{\dostoptextfloat}%
-   \setvalue{\e!start\e!reserve#1\e!text}{\doquadrupleempty\docomplexstartreservetextblock[#1]}%
-   \setvalue {\e!stop\e!reserve#1\e!text}{\dostoptextfloat}%
-   \setvalue              {\e!emptyone#1}{\doemptyfloatblock{#1}}%
-   \setvalue              {\e!emptytwo#1}{\doemptyfloatblock{#1}}}
+  {\setuvalue        {\e!place\e!listof#2}{\dodoubleempty\doplacelist[#1]}%
+   \setuvalue     {\e!complete\e!listof#2}{\dotripleempty\dodocompletelist[#1][#2]}%
+   \setuvalue                 {\e!place#1}{\dotripleempty\docomplexplacefloat[#1]}%
+   \setuvalue               {\e!reserve#1}{\doquadrupleempty\docomplexreserveblock[#1]}%
+   \setuvalue          {\e!start#1\e!text}{\dotripleempty\docomplexstarttextblock[#1]}%
+   \setuvalue           {\e!stop#1\e!text}{\dostoptextfloat}%
+   \setuvalue{\e!start\e!reserve#1\e!text}{\doquadrupleempty\docomplexstartreservetextblock[#1]}%
+   \setuvalue {\e!stop\e!reserve#1\e!text}{\dostoptextfloat}%
+   \setuvalue              {\e!emptyone#1}{\doemptyfloatblock{#1}}%
+   \setuvalue              {\e!emptytwo#1}{\doemptyfloatblock{#1}}}
 
 %D Fallback float body:
 
@@ -1103,8 +1103,8 @@
 
 \let\dorestorefloatstatus\relax
 
-\ifx\doflushfloats\undefined \let\doflushfloats\relax \fi
-\ifx\flushfloatbox\undefined \let\flushfloatbox\relax \fi
+\ifdefined\doflushfloats\else \let\doflushfloats\relax \fi
+\ifdefined\flushfloatbox\else \let\flushfloatbox\relax \fi
 
 % needed in the splitter:
 
@@ -1173,12 +1173,12 @@
    \flushfloatbox
    \blank[\floatsharedparameter\c!spaceafter]}
 
-\ifx\someherefloat\undefined \let\someherefloat\doplacefloatbox \fi
-\ifx\someslotfloat\undefined \let\someslotfloat\doplacefloatbox \fi
-\ifx\somefixdfloat\undefined \let\somefixdfloat\doplacefloatbox \fi
-\ifx\sometopsfloat\undefined \let\sometopsfloat\doplacefloatbox \fi
-\ifx\somebotsfloat\undefined \let\somebotsfloat\doplacefloatbox \fi
-\ifx\somesidefloat\undefined \let\somesidefloat\doplacefloatbox \fi
+\ifdefined\someherefloat\else \let\someherefloat\doplacefloatbox \fi
+\ifdefined\someslotfloat\else \let\someslotfloat\doplacefloatbox \fi
+\ifdefined\somefixdfloat\else \let\somefixdfloat\doplacefloatbox \fi
+\ifdefined\sometopsfloat\else \let\sometopsfloat\doplacefloatbox \fi
+\ifdefined\somebotsfloat\else \let\somebotsfloat\doplacefloatbox \fi
+\ifdefined\somesidefloat\else \let\somesidefloat\doplacefloatbox \fi
 
 % test case:
 %
@@ -1374,7 +1374,7 @@
 
 % minwidth=fit,width=max : no overshoot, as wide as graphic
 
-\ifx\moveboxontogrid\undefined \let\movecaptionontogrid\gobblethreearguments \fi
+\ifdefined\moveboxontogrid\else \let\movecaptionontogrid\gobblethreearguments \fi
 
 \def\locatefloatbox
   {\chardef\alignstrutmode\zerocount
@@ -2052,7 +2052,7 @@
         \@EA\aftersplitstring \floatcolumn\at*\to\floatrow
         \@EA\beforesplitstring\floatcolumn\at*\to\floatcolumn
         % todo: nog algemeen otr
-        \ifx\OTRSETsetpreferedcolumnslot\undefined\else
+        \ifdefined\OTRSETsetpreferedcolumnslot
           \OTRSETsetpreferedcolumnslot\floatcolumn\floatrow
         \fi}
        {\let\floatcolumn\empty
diff --git a/tex/context/base/strc-lnt.mkiv b/tex/context/base/strc-lnt.mkiv
index d80d38900..707559ac3 100644
--- a/tex/context/base/strc-lnt.mkiv
+++ b/tex/context/base/strc-lnt.mkiv
@@ -59,9 +59,9 @@
 
 \def\dodefinelinenote[#1][#2]%
   {\definenote[ln:#1][#2]%
-   \unexpanded\setvalue        {#1}{\dolinenote     {#1}}%
-   \unexpanded\setvalue{\e!start#1}{\dostartlinenote{#1}}%
-   \unexpanded\setvalue{\e!stop #1}{\dostoplinenote {#1}}}
+   \setuvalue        {#1}{\dolinenote     {#1}}%
+   \setuvalue{\e!start#1}{\dostartlinenote{#1}}%
+   \setuvalue{\e!stop #1}{\dostoplinenote {#1}}}
 
 \def\setuplinenote[#1]% convenient
   {\setupnote[ln:#1]}
diff --git a/tex/context/base/strc-mar.mkiv b/tex/context/base/strc-mar.mkiv
index 8dbbb232c..65f360749 100644
--- a/tex/context/base/strc-mar.mkiv
+++ b/tex/context/base/strc-mar.mkiv
@@ -138,8 +138,10 @@
 
 \def\checkedcurrentmarks{\markcurrentcs} % #1 shared current mark
 
-\let\currentsplittopmarknumber\currenttopmarknumber
-\let\normalsplittopmarks      \normaltopmarks
+\let\currentsplitfirstmarknumber\currentfirstmarknumber
+\let\currentsplittopmarknumber  \currenttopmarknumber
+\let\currentsplitbotmarknumber  \currentbotmarknumber
+\let\normalsplittopmarks        \normaltopmarks
 
 \def\uncheckedautotopmark        {\normaltopmarks       \markautocs} % #1
 \def\uncheckedautofirstmark      {\normalfirstmarks     \markautocs} % #1
diff --git a/tex/context/base/strc-ref.mkiv b/tex/context/base/strc-ref.mkiv
index 7e578459b..ed77edc85 100644
--- a/tex/context/base/strc-ref.mkiv
+++ b/tex/context/base/strc-ref.mkiv
@@ -917,7 +917,7 @@
         \c!label=, % can be {left}{right}
         \c!command=\in,
         #2]%
-     \unexpanded\setvalue{#1}%
+     \setuvalue{#1}%
        {\dontleavehmode\doexecutereferenceformat{#1}}%
    \fi}
 
diff --git a/tex/context/base/strc-reg.mkiv b/tex/context/base/strc-reg.mkiv
index 4fa29285a..b9498c0d2 100644
--- a/tex/context/base/strc-reg.mkiv
+++ b/tex/context/base/strc-reg.mkiv
@@ -132,9 +132,9 @@
   {\setupregister[#1][\s!parent=\??id]%
    \ctxlua{jobregisters.define('#1')}%
    \presetheadtext[#1=\Word{#1}]%
-   \unexpanded\setvalue{#1}{\dodoubleempty\doregister[#1]}%
-   \unexpanded\setvalue{\e!see#1}{\dodoubleempty\doseeregister[#1]}%
-%  \unexpanded\setvalue{\e!coupled#1}{\dolinkedregister{#1}}%
+   \setuvalue{#1}{\dodoubleempty\doregister[#1]}%
+   \setuvalue{\e!see#1}{\dodoubleempty\doseeregister[#1]}%
+%  \setuvalue{\e!coupled#1}{\dolinkedregister{#1}}%
    \setvalue{\e!place#1}{\placeregister[#1]}%
    \setvalue{\e!complete#1}{\completeregister[#1]}%
    \setvalue{\e!setup#1\e!endsetup}[##1]{\getparameters[\??id#1][##1]}}
diff --git a/tex/context/base/strc-ren.mkiv b/tex/context/base/strc-ren.mkiv
index 2115d6287..5cdf3703f 100644
--- a/tex/context/base/strc-ren.mkiv
+++ b/tex/context/base/strc-ren.mkiv
@@ -31,22 +31,51 @@
   {\the\everyheadstart
    \doif{\structureheadparameter\c!margintext}\v!yes\placemargincontent}
 
-\def\doplaceheadtextcomponent#1#2%
-  {\begingroup
-     \dosetstructureheadattributes\c!style\c!color
-     % nasty, we need to adapt twice
-     \ifconditional\structureheadisdisplay % \ifdisplaysectionhead
-       \setupinterlinespace
+\def\setupheadcomponentfont#1#2%
+  {\ifconditional\structureheadisdisplay
+     \edef\askedstructureheadinterlinespace{\structureheadparameter\c!interlinespace}%
+     \ifx\askedstructureheadinterlinespace\empty
+       % here the interline space is only set when style sets no space
+       \setfalse\fontattributeisset
+       \setfalse\interlinespaceisset
+       \dosetstructureheadattributes\c!style\c!color
+       \ifconditional\fontattributeisset \ifconditional\interlinespaceisset \else
+         \setupinterlinespace
+       \fi \fi
+       \setfalse\fontattributeisset \dosetstructureheadattributes#1#2%
+       \ifconditional\fontattributeisset \ifconditional\interlinespaceisset \else
+         \setupinterlinespace
+       \fi \fi
      \else
+       % here the set interline space overloads any other set space in the style
+       \setfalse\fontattributeisset
+       \dosetstructureheadattributes\c!style\c!color
+       \ifconditional\fontattributeisset
+         \dosetupcheckedinterlinespace\askedstructureheadinterlinespace
+       \fi
+       \setfalse\fontattributeisset
+       \dosetstructureheadattributes#1#2%
+       \ifconditional\fontattributeisset
+         \dosetupcheckedinterlinespace\askedstructureheadinterlinespace
+       \fi
+     \fi
+   \else
+     \setfalse\fontattributeisset
+     \dosetstructureheadattributes\c!style\c!color
+     \ifconditional\fontattributeisset
        \setupspacing
      \fi
-     \dosetstructureheadattributes\c!textstyle\c!textcolor
-     \dontconvertfont
-     \ifconditional\structureheadisdisplay % \ifdisplaysectionhead
-       \setupinterlinespace
-     \else
+     \setfalse\fontattributeisset
+     \dosetstructureheadattributes#1#2%
+     \ifconditional\fontattributeisset
        \setupspacing
      \fi
+   \fi
+   \dontconvertfont}
+
+\def\doplaceheadtextcomponent#1#2%
+  {\begingroup
+     \setupheadcomponentfont\c!textstyle\c!textcolor
      % \ifcase\headtimingmode#1\fi % can introduce cr
      \structureheadparameter\c!commandbefore
      \placeheadmargintexts
@@ -74,8 +103,7 @@
 
 \def\doplaceheadnumbercomponent#1#2%
   {\begingroup
-     \dosetstructureheadattributes\c!style\c!color
-     \dosetstructureheadattributes\c!numberstyle\c!numbercolor
+     \setupheadcomponentfont\c!numberstyle\c!numbercolor
      % \getvalue{\??ko\currentstructurehead\c!commandbefore}% strange, why here? moved 21/11/2005
      \placeheadmargintexts
      \ifconditional\structureheadisdisplay % \ifdisplaysectionhead
diff --git a/tex/context/base/strc-sec.mkiv b/tex/context/base/strc-sec.mkiv
index f583ef849..2074fabdf 100644
--- a/tex/context/base/strc-sec.mkiv
+++ b/tex/context/base/strc-sec.mkiv
@@ -399,14 +399,21 @@
 \unexpanded\def\placeheadtext  {\dosingleempty\doplaceheadtext  } % use with care
 \unexpanded\def\placeheadnumber{\dosingleempty\doplaceheadnumber} % use with care
 
+\ifdefined\setupheadcomponentfont \else
+
+    \def\setupheadcomponentfont#1#2%
+      {\dosetstructureheadattributes\c!style\c!color
+       \dosetstructureheadattributes#1#2%
+       \dontconvertfont
+       \setupinterlinespace}
+
+\fi
+
 \def\doplaceheadtext[#1]%
   {\dontleavehmode
    \begingroup
    \edef\currentstructurehead{#1}%
-   \dosetstructureheadattributes\c!style\c!color
-   \dosetstructureheadattributes\c!textstyle\c!textcolor
-   \dontconvertfont
-   \setupinterlinespace
+   \setupheadcomponentfont\c!textstyle\c!textcolor
    \relax
    \getspecificstructuretitle{\thenamedstructureheadlevel{#1}}%
    \endgraf
@@ -416,10 +423,7 @@
   {\dontleavehmode
    \begingroup
    \edef\currentstructurehead{#1}%
-   \dosetstructureheadattributes\c!style\c!color
-   \dosetstructureheadattributes\c!numberstyle\c!numbercolor
-   \dontconvertfont
-   \setupinterlinespace
+   \setupheadcomponentfont\c!numberstyle\c!numbercolor
    \relax
    \getfullstructurenumber{\thenamedstructureheadlevel{#1}}%
    \endgraf
diff --git a/tex/context/base/strc-syn.mkiv b/tex/context/base/strc-syn.mkiv
index 17ae7934a..9da6aad40 100644
--- a/tex/context/base/strc-syn.mkiv
+++ b/tex/context/base/strc-syn.mkiv
@@ -107,12 +107,12 @@
      \ifthirdargument
        \unexpanded\def#3##1{\doinsertsynonymmeaning{#1}{##1}}% \meaning
      \fi
-     \unexpanded\setvalue{#1}{\definesynonym[\v!no][#1]}% \name
+     \setuvalue{#1}{\definesynonym[\v!no][#1]}% \name
    \else
      \ifthirdargument
        \unexpanded\def#3##1{\doinsertsynonymmeaning{#1}{##1}}% \meaning
      \fi
-     \unexpanded\setvalue{#1}{\definesynonym[\v!yes][#1]}% \name
+     \setuvalue{#1}{\definesynonym[\v!yes][#1]}% \name
    \fi
    \getparameters[\??sm#1][\s!parent=\??sm,\s!multi={#2}]%
    \presetheadtext[#2=\Word{#2}]% changes the \if...argument
@@ -150,7 +150,7 @@
             used    = false,
         }
      })}%
-     \doif{#1}\v!yes{\unexpanded\setxvalue\currentsynonymtag{\noexpand\doinsertsynonym{\currentsynonym}{\currentsynonymtag}}}%
+     \doif{#1}\v!yes{\setuxvalue\currentsynonymtag{\noexpand\doinsertsynonym{\currentsynonym}{\currentsynonymtag}}}%
    \fi
    \endgroup}
 
@@ -275,9 +275,9 @@
        {\ifx#3\relax \else
           \unexpanded\def#3##1{\doinsertsort{#1}{##1}}%
         \fi}%
-     \unexpanded\setvalue{#1}{\definesort[\v!no][#1]}%
+     \setuvalue{#1}{\definesort[\v!no][#1]}%
    \else
-     \unexpanded\setvalue{#1}{\definesort[\v!yes][#1]}%
+     \setuvalue{#1}{\definesort[\v!yes][#1]}%
    \fi
    \getparameters[\??so#1][\s!parent=\??so,\s!multi={#2}]%
    \presetheadtext[#2=\Word{#2}]% after \ifthirdargument -)
@@ -313,7 +313,7 @@
         %   used    = false,
         }
      })}%
-     \doif{#1}\v!yes{\unexpanded\setxvalue\currentsortingtag{\noexpand\doinsertsort{\currentsorting}{\currentsortingtag}}}%
+     \doif{#1}\v!yes{\setuxvalue\currentsortingtag{\noexpand\doinsertsort{\currentsorting}{\currentsortingtag}}}%
    \fi
    \endgroup}
 
diff --git a/tex/context/base/syst-aux.mkiv b/tex/context/base/syst-aux.mkiv
index 815d5add0..95d260750 100644
--- a/tex/context/base/syst-aux.mkiv
+++ b/tex/context/base/syst-aux.mkiv
@@ -428,6 +428,11 @@
 \def\undefinevalue#1{\expandafter\let\csname#1\endcsname\undefined}
 \def\ignorevalue#1#2{\expandafter\let\csname#1\endcsname\empty}
 
+\def\setuvalue    #1{\normalprotected\expandafter \def\csname#1\endcsname}
+\def\setuevalue   #1{\normalprotected\expandafter\edef\csname#1\endcsname}
+\def\setugvalue   #1{\normalprotected\expandafter\gdef\csname#1\endcsname}
+\def\setuxvalue   #1{\normalprotected\expandafter\xdef\csname#1\endcsname}
+
 %D \macros
 %D   {globallet,glet}
 %D
diff --git a/tex/context/base/tabl-tab.mkiv b/tex/context/base/tabl-tab.mkiv
index 1b83d4dd8..5015473e0 100644
--- a/tex/context/base/tabl-tab.mkiv
+++ b/tex/context/base/tabl-tab.mkiv
@@ -2423,10 +2423,10 @@
    \expanded{\NormalTLTU{\the\scratchdimen}}%
    % spacing, was depth=4 height=8 (counters, sigh, now macros)
    \doifelse\@@tiheight\v!strut
-     {\let\StrutHeightFactor\@@itheight}
+     {\let\StrutHeightFactor\strutheightfactor}
      {\let\StrutHeightFactor\@@tiheight}%
    \doifelse\@@tidepth\v!strut
-     {\let\StrutDepthFactor\@@itdepth}
+     {\let\StrutDepthFactor\strutdepthfactor}
      {\let\StrutDepthFactor\@@tidepth}%
    \scratchdimen\StrutHeightFactor\points \multiply\scratchdimen 10%
    \edef\StrutHeightFactor{\withoutpt\the\scratchdimen}%
diff --git a/tex/context/base/type-ini.mkiv b/tex/context/base/type-ini.mkiv
index 6a17eccc7..dca6e3a4d 100644
--- a/tex/context/base/type-ini.mkiv
+++ b/tex/context/base/type-ini.mkiv
@@ -554,7 +554,7 @@
         \setgvalue{\??tf#1\s!default}{#2}%
       \fi
       \ifcsname#1\endcsname \else
-        \unexpanded\setgvalue{#1}{\switchtotypeface[#1][#2]}%
+        \setugvalue{#1}{\switchtotypeface[#1][#2]}%
       \fi}}
 
 \def\setuptypeface% [class] [settings]
diff --git a/tex/context/base/x-asciimath.lua b/tex/context/base/x-asciimath.lua
index 84a89ad44..c2b15e313 100644
--- a/tex/context/base/x-asciimath.lua
+++ b/tex/context/base/x-asciimath.lua
@@ -18,7 +18,7 @@ local lpegmatch = lpeg.match
 
 local S, P, R, C, V, Cc, Ct, Cs = lpeg.S, lpeg.P, lpeg.R, lpeg.C, lpeg.V, lpeg.Cc, lpeg.Ct, lpeg.Cs
 
-local letter     = lpeg.utf8
+local letter     = lpeg.patterns.utf8
 local space      = S(" \n\r\t")
 local spaces     = space^0/""
 local integer    = P("-")^-1 * R("09")^1
diff --git a/tex/generic/context/luatex-fonts-merged.lua b/tex/generic/context/luatex-fonts-merged.lua
index 21396c76c..800d3d525 100644
--- a/tex/generic/context/luatex-fonts-merged.lua
+++ b/tex/generic/context/luatex-fonts-merged.lua
@@ -1,6 +1,6 @@
 -- merged file : c:/data/develop/context/texmf/tex/generic/context/luatex-fonts-merged.lua
 -- parent file : c:/data/develop/context/texmf/tex/generic/context/luatex-fonts.lua
--- merge date  : 03/10/10 23:51:28
+-- merge date  : 03/12/10 19:55:31
 
 do -- begin closure to overcome local limits and interference
 
@@ -302,57 +302,58 @@ if not modules then modules = { } end modules ['l-lpeg'] = {
     license   = "see context related readme files"
 }
 
-lpeg = require("lpeg")
+local lpeg = require("lpeg")
 
-lpeg.patterns = lpeg.patterns or { } -- so that we can share
+lpeg.patterns  = lpeg.patterns or { } -- so that we can share
+local patterns = lpeg.patterns
 
-local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
+local P, R, S, Ct, C, Cs, Cc, V = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.V
 local match = lpeg.match
 
---~ l-lpeg.lua :
-
---~ lpeg.digit         = lpeg.R('09')^1
---~ lpeg.sign          = lpeg.S('+-')^1
---~ lpeg.cardinal      = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
---~ lpeg.integer       = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
---~ lpeg.float         = lpeg.P(lpeg.sign^0 * lpeg.digit^0 * lpeg.P('.') * lpeg.digit^1)
---~ lpeg.number        = lpeg.float + lpeg.integer
---~ lpeg.oct           = lpeg.P("0") * lpeg.R('07')^1
---~ lpeg.hex           = lpeg.P("0x") * (lpeg.R('09') + lpeg.R('AF'))^1
---~ lpeg.uppercase     = lpeg.P("AZ")
---~ lpeg.lowercase     = lpeg.P("az")
-
---~ lpeg.eol           = lpeg.S('\r\n\f')^1 -- includes formfeed
---~ lpeg.space         = lpeg.S(' ')^1
---~ lpeg.nonspace      = lpeg.P(1-lpeg.space)^1
---~ lpeg.whitespace    = lpeg.S(' \r\n\f\t')^1
---~ lpeg.nonwhitespace = lpeg.P(1-lpeg.whitespace)^1
-
-local hash = { }
+local digit, sign      = R('09'), S('+-')
+local cr, lf, crlf     = P("\r"), P("\n"), P("\r\n")
+local utf8byte         = R("\128\191")
+
+patterns.utf8byte      = utf8byte
+patterns.utf8one       = R("\000\127")
+patterns.utf8two       = R("\194\223") * utf8byte
+patterns.utf8three     = R("\224\239") * utf8byte * utf8byte
+patterns.utf8four      = R("\240\244") * utf8byte * utf8byte * utf8byte
+
+patterns.digit         = digit
+patterns.sign          = sign
+patterns.cardinal      = sign^0 * digit^1
+patterns.integer       = sign^0 * digit^1
+patterns.float         = sign^0 * digit^0 * P('.') * digit^1
+patterns.number        = patterns.float + patterns.integer
+patterns.oct           = P("0") * R("07")^1
+patterns.octal         = patterns.oct
+patterns.HEX           = P("0x") * R("09","AF")^1
+patterns.hex           = P("0x") * R("09","af")^1
+patterns.hexadecimal   = P("0x") * R("09","AF","af")^1
+patterns.lowercase     = R("az")
+patterns.uppercase     = R("AZ")
+patterns.letter        = patterns.lowercase + patterns.uppercase
+patterns.space         = S(" ")
+patterns.eol           = S("\n\r")
+patterns.spacer        = S(" \t\f\v")  -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
+patterns.newline       = crlf + cr + lf
+patterns.nonspace      = 1 - patterns.space
+patterns.nonspacer     = 1 - patterns.spacer
+patterns.whitespace    = patterns.eol + patterns.spacer
+patterns.nonwhitespace = 1 - patterns.whitespace
+patterns.utf8          = patterns.utf8one + patterns.utf8two + patterns.utf8three + patterns.utf8four
+patterns.utfbom        = P('\000\000\254\255') + P('\255\254\000\000') + P('\255\254') + P('\254\255') + P('\239\187\191')
 
 function lpeg.anywhere(pattern) --slightly adapted from website
-    return P { P(pattern) + 1 * lpeg.V(1) }
-end
-
-function lpeg.startswith(pattern) --slightly adapted
-    return P(pattern)
+    return P { P(pattern) + 1 * V(1) } -- why so complex?
 end
 
 function lpeg.splitter(pattern, action)
     return (((1-P(pattern))^1)/action+1)^0
 end
 
--- variant:
-
---~ local parser = lpeg.Ct(lpeg.splitat(newline))
-
-local crlf     = P("\r\n")
-local cr       = P("\r")
-local lf       = P("\n")
-local space    = S(" \t\f\v")  -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
-local newline  = crlf + cr + lf
-local spacing  = space^0 * newline
-
+local spacing  = patterns.spacer^0 * patterns.newline -- sort of strip
 local empty    = spacing * Cc("")
 local nonempty = Cs((1-spacing)^1) * spacing^-1
 local content  = (empty + nonempty)^1
@@ -363,7 +364,7 @@ function string:splitlines()
     return match(capture,self)
 end
 
-lpeg.linebyline = content -- better make a sublibrary
+patterns.textline = content
 
 --~ local p = lpeg.splitat("->",false)  print(match(p,"oeps->what->more"))  -- oeps what more
 --~ local p = lpeg.splitat("->",true)   print(match(p,"oeps->what->more"))  -- oeps what->more
@@ -419,46 +420,23 @@ end
 --~     local p = pp
 --~     for l=1,#list do
 --~         if p then
---~             p = p + lpeg.P(list[l])
+--~             p = p + P(list[l])
 --~         else
---~             p = lpeg.P(list[l])
+--~             p = P(list[l])
 --~         end
 --~     end
 --~     return p
 --~ end
 
 --~ from roberto's site:
---~
---~ -- decode a two-byte UTF-8 sequence
---~ local function f2 (s)
---~   local c1, c2 = string.byte(s, 1, 2)
---~   return c1 * 64 + c2 - 12416
---~ end
---~
---~ -- decode a three-byte UTF-8 sequence
---~ local function f3 (s)
---~   local c1, c2, c3 = string.byte(s, 1, 3)
---~   return (c1 * 64 + c2) * 64 + c3 - 925824
---~ end
---~
---~ -- decode a four-byte UTF-8 sequence
---~ local function f4 (s)
---~   local c1, c2, c3, c4 = string.byte(s, 1, 4)
---~   return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168
---~ end
---~
---~ local cont = lpeg.R("\128\191")   -- continuation byte
---~
---~ local utf8 = lpeg.R("\0\127") / string.byte
---~            + lpeg.R("\194\223") * cont / f2
---~            + lpeg.R("\224\239") * cont * cont / f3
---~            + lpeg.R("\240\244") * cont * cont * cont / f4
---~
---~ local decode_pattern = lpeg.Ct(utf8^0) * -1
 
-local cont = R("\128\191")   -- continuation byte
+local f1 = string.byte
 
-lpeg.patterns.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont
+local function f2(s) local c1, c2         = f1(s,1,2) return   c1 * 64 + c2                       -    12416 end
+local function f3(s) local c1, c2, c3     = f1(s,1,3) return  (c1 * 64 + c2) * 64 + c3            -   925824 end
+local function f4(s) local c1, c2, c3, c4 = f1(s,1,4) return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168 end
+
+patterns.utf8byte = patterns.utf8one/f1 + patterns.utf8two/f2 + patterns.utf8three/f3 + patterns.utf8four/f4
 
 end -- closure
 
@@ -1738,6 +1716,15 @@ end
 -- test { "/aa", "/aa/bb", "/aa/bb/cc", "/aa/bb/cc.dd", "/aa/bb/cc.dd.ee" }
 -- test { "aa", "aa/bb", "aa/bb/cc", "aa/bb/cc.dd", "aa/bb/cc.dd.ee" }
 
+--~ -- todo:
+--~
+--~ if os.type == "windows" then
+--~     local currentdir = lfs.currentdir
+--~     function lfs.currentdir()
+--~         return (gsub(currentdir(),"\\","/"))
+--~     end
+--~ end
+
 end -- closure
 
 do -- begin closure to overcome local limits and interference
-- 
cgit v1.2.3