From 58f3f55b58d34d4a4b70a6099a81296b862e6d9f Mon Sep 17 00:00:00 2001
From: Hans Hagen <pragma@wxs.nl>
Date: Fri, 28 Dec 2012 20:30:00 +0100
Subject: beta 2012.12.28 20:30

---
 tex/context/base/anch-pgr.lua                      | 115 +++----
 tex/context/base/anch-pos.lua                      |  56 ++--
 tex/context/base/attr-col.lua                      |  17 +-
 tex/context/base/back-pdf.mkiv                     |   2 +-
 tex/context/base/chem-str.lua                      |  87 ++---
 tex/context/base/cldf-ini.lua                      |  20 +-
 tex/context/base/context-version.pdf               | Bin 4114 -> 4131 bytes
 tex/context/base/context-version.png               | Bin 40509 -> 40605 bytes
 tex/context/base/core-uti.lua                      |   2 +-
 tex/context/base/data-tex.lua                      |   1 +
 tex/context/base/grph-inc.lua                      |  10 +-
 tex/context/base/l-io.lua                          |  58 ++--
 tex/context/base/lpdf-col.lua                      |  49 +--
 tex/context/base/lpdf-grp.lua                      |   2 +-
 tex/context/base/lpdf-ini.lua                      |  31 +-
 tex/context/base/lpdf-u3d.lua                      |   2 +-
 tex/context/base/luat-fio.lua                      |  61 ++--
 tex/context/base/luat-lib.mkiv                     |   4 +-
 tex/context/base/m-chart.mkvi                      |  16 +-
 tex/context/base/meta-pdf.lua                      |   5 +-
 tex/context/base/mlib-pps.lua                      | 107 ++++---
 tex/context/base/mlib-pps.mkiv                     |   2 +-
 tex/context/base/s-abr-01.tex                      |   1 +
 tex/context/base/s-abr-04.tex                      |   1 +
 tex/context/base/status-files.pdf                  | Bin 24417 -> 24676 bytes
 tex/context/base/status-lua.pdf                    | Bin 203077 -> 208248 bytes
 tex/context/base/strc-lst.lua                      |   4 +-
 tex/context/base/trac-log.lua                      |  73 +++--
 tex/context/base/typo-mar.lua                      |   6 +-
 tex/context/base/util-str.lua                      | 353 +++++++++++++++++++--
 tex/context/base/util-tab.lua                      |  52 +++
 tex/context/base/x-calcmath.lua                    |   4 +-
 tex/context/base/x-mathml.lua                      |   2 +-
 tex/generic/context/luatex/luatex-basics-gen.lua   |  44 ++-
 tex/generic/context/luatex/luatex-fonts-merged.lua | 104 +++---
 35 files changed, 876 insertions(+), 415 deletions(-)

(limited to 'tex')

diff --git a/tex/context/base/anch-pgr.lua b/tex/context/base/anch-pgr.lua
index aba61794b..7f53ef2e0 100644
--- a/tex/context/base/anch-pgr.lua
+++ b/tex/context/base/anch-pgr.lua
@@ -17,20 +17,19 @@ local splitter = lpeg.splitat(":")
 local lpegmatch = lpeg.match
 
 local jobpositions = job.positions
+local formatters   = string.formatters
 
 local report_graphics = logs.reporter("graphics")
 
-local function point(n)
-    return format("%.5fpt",n/65536)
-end
+local f_b_tag   = formatters["b:%s"]
+local f_e_tag   = formatters["e:%s"]
+local f_p_tag   = formatters["p:%s"]
 
-local function pair(x,y)
-    return format("(%.5fpt,%.5fpt)",x/65536,y/65536)
-end
+local f_tag_two = formatters["%s:%s"]
 
-local function path(t)
-    return concat(t,"--") .. "--cycle"
-end
+local f_point   = formatters["%p"]
+local f_pair    = formatters["(%p,%p)"]
+local f_path    = formatters["%--t--cycle"]
 
 local function regionarea(r)
     local rx, ry = r.x, r.y
@@ -38,10 +37,10 @@ local function regionarea(r)
     local rh = ry + r.h
     local rd = ry - r.d
     return {
-        pair(rx, rh - ry),
-        pair(rw, rh - ry),
-        pair(rw, rd - ry),
-        pair(rx, rd - ry),
+        f_pair(rx, rh - ry),
+        f_pair(rw, rh - ry),
+        f_pair(rw, rd - ry),
+        f_pair(rx, rd - ry),
     }
 end
 
@@ -245,10 +244,10 @@ local function singlepart(b,e,r,left,right,obeyhang)
     local area
     if by == ey then
         area = {
-            pair(bx,bh-ry),
-            pair(ex,eh-ry),
-            pair(ex,ed-ry),
-            pair(bx,bd-ry),
+            f_pair(bx,bh-ry),
+            f_pair(ex,eh-ry),
+            f_pair(ex,ed-ry),
+            f_pair(bx,bd-ry),
         }
     else
         area = { }
@@ -269,7 +268,7 @@ local function singlepart(b,e,r,left,right,obeyhang)
         finish(area)
         for i=1,#area do
             local a = area[i]
-            area[i] = pair(a[1],a[2])
+            area[i] = f_pair(a[1],a[2])
         end
     end
     return {
@@ -307,7 +306,7 @@ local function firstpart(b,r,left,right,obeyhang)
     finish(area)
     for i=1,#area do
         local a = area[i]
-        area[i] = pair(a[1],a[2])
+        area[i] = f_pair(a[1],a[2])
     end
     return {
         location = "first",
@@ -338,7 +337,7 @@ local function middlepart(r,left,right,obeyhang)
     finish(area)
     for i=1,#area do
         local a = area[i]
-        area[i] = pair(a[1],a[2])
+        area[i] = f_pair(a[1],a[2])
     end
     return {
         location = "middle",
@@ -375,7 +374,7 @@ local function lastpart(e,r,left,right,obeyhang)
     finish(area)
     for i=1,#area do
         local a = area[i]
-        area[i] = pair(a[1],a[2])
+        area[i] = f_pair(a[1],a[2])
     end
     return {
         location = "last",
@@ -391,8 +390,8 @@ graphics.backgrounds = backgrounds
 
 local function calculatemultipar(tag,obeyhang)
     local collected = jobpositions.collected
-    local b = collected[format("b:%s",tag)]
-    local e = collected[format("e:%s",tag)]
+    local b = collected[f_b_tag(tag)]
+    local e = collected[f_e_tag(tag)]
     if not b or not e then
         report_graphics("invalid tag '%s'",tag)
         return { }
@@ -434,7 +433,7 @@ local function calculatemultipar(tag,obeyhang)
     --
     local bn = b.n
     if bn then
-        local bp = collected[format("p:%s",bn)]
+        local bp = collected[f_p_tag(bn)]
         if bp then
             left  = left  + bp.ls
             right = right + bp.rs
@@ -452,7 +451,7 @@ local function calculatemultipar(tag,obeyhang)
             [b.p] = { firstpart(b,collected[br],left,right,obeyhang) },
         }
         for i=bindex+1,eindex-1 do
-            br = format("%s:%s",btag,i)
+            br = f_tag_two(btag,i)
             local r = collected[br]
             if not r then
                report_graphics("invalid middle for '%s'",br)
@@ -525,32 +524,37 @@ local multilocs = {
 
 -- if unknown context_abck : input mp-abck.mpiv ; fi ;
 
-local template_a = [[
+local f_template_a = [[
 path multiregs[], multipars[], multibox ;
 string multikind[] ;
 numeric multilocs[], nofmultipars ;
 nofmultipars := %s ;
-multibox := unitsquare xyscaled %s ;
+multibox := unitsquare xyscaled (%p,%p) ;
 numeric par_strut_height, par_strut_depth, par_line_height ;
-par_strut_height := %s ;
-par_strut_depth := %s ;
-par_line_height := %s ;
+par_strut_height := %p ;
+par_strut_depth := %p ;
+par_line_height := %p ;
 ]]
 
-local template_b = [[
+local f_template_b = [[
 multilocs[%s] := %s ;
 multikind[%s] := "%s" ;
-multipars[%s] := (%s) shifted - %s ;
+multipars[%s] := (%--t--cycle) shifted - (%p,%p) ;
 ]]
 
-local template_c = [[
-multiregs[%s] := (%s) shifted - %s ;
+local f_template_c = [[
+multiregs[%s] := (%--t--cycle) shifted - %s ;
 ]]
 
-local template_d = [[
+local f_template_d = [[
 setbounds currentpicture to multibox ;
 ]]
 
+f_template_a = formatters[f_template_a]
+f_template_b = formatters[f_template_b]
+f_template_c = formatters[f_template_c]
+f_template_d = formatters[f_template_d]
+
 function backgrounds.fetchmultipar(n,anchor,page,obeyhang)
     local data = pbg[n]
     if not data then
@@ -573,32 +577,31 @@ function backgrounds.fetchmultipar(n,anchor,page,obeyhang)
                     local x, y, w, h, d = a.x, a.y, a.w, a.h, a.d
                     local bpos = data.bpos
                     local bh, bd = bpos.h, bpos.d
-                    local result = { format(template_a,nofmultipars,pair(w,h+d),point(bh),point(bd),point(bh+bd)) }
+                    local result = { f_template_a(nofmultipars,w,h+d,bh,bd,bh+bd) }
                     for i=1,nofmultipars do
                         local region = pagedata[i]
-                        result[#result+1] = format(template_b,
+                        result[#result+1] = f_template_b(
                             i, multilocs[region.location],
                             i, region.location,
-                            i, path(region.area), pair(x,y-region.region.y))
+                            i, region.area, x, y-region.region.y)
                         if trace then
-                            result[#result+1] = format(template_c,
-                                i, path(regionarea(region.region)), offset)
+                            result[#result+1] = f_template_c(i, regionarea(region.region), offset)
                         end
                     end
                     data[page] = nil
-                    result[#result+1] = template_d
+                    result[#result+1] = f_template_d()
                     result = concat(result,"\n")
                     return result
                 end
             end
         end
     end
-    return format(template_a,0,"origin",0,0,0)
+    return f_template_a(0,"origin",0,0,0)
 end
 
-backgrounds.point = point
-backgrounds.pair  = pair
-backgrounds.path  = path
+backgrounds.point = f_point
+backgrounds.pair  = f_pair
+backgrounds.path  = f_path
 
 function commands.fetchmultipar(n,anchor,page)
     context(backgrounds.fetchmultipar(n,anchor,page))
@@ -608,20 +611,23 @@ function commands.fetchmultishape(n,anchor,page)
     context(backgrounds.fetchmultipar(n,anchor,page,true))
 end
 
-local template_a = [[
+local f_template_a = [[
 path posboxes[], posregions[] ;
 numeric pospages[] ;
 numeric nofposboxes ;
 nofposboxes := %s ;
-%s ;
+%t ;
 ]]
 
-local template_b = [[
+local f_template_b = [[
 pospages[%s] := %s ;
-posboxes[%s] := %s--%s--%s--%s--cycle ;
-posregions[%s] := %s--%s--%s--%s--cycle ;
+posboxes[%s] := (%p,%p)--(%p,%p)--(%p,%p)--(%p,%p)--cycle ;
+posregions[%s] := (%p,%p)--(%p,%p)--(%p,%p)--(%p,%p)--cycle ;
 ]]
 
+f_template_a = formatters[f_template_a]
+f_template_b = formatters[f_template_b]
+
 function commands.fetchposboxes(tags,anchor,page) -- no caching (yet) / todo: anchor, page
     local collected = jobpositions.collected
     if type(tags) == "string" then
@@ -643,10 +649,10 @@ function commands.fetchposboxes(tags,anchor,page) -- no caching (yet) / todo: an
                     local ch = cy + c.h
                     local cd = cy - c.d
                     nofboxes = nofboxes + 1
-                    list[nofboxes] = format(template_b,
+                    list[nofboxes] = f_template_b(
                         nofboxes,c.p,
-                        nofboxes,pair(cx,ch),pair(cw,ch),pair(cw,cd),pair(cx,cd),
-                        nofboxes,pair(0,rh),pair(rw,rh),pair(rw,rd),pair(0,rd)
+                        nofboxes,cx,ch,cw,ch,cw,cd,cx,cd,
+                        nofboxes,0,rh,rw,rh,rw,rd,0,rd
                     )
                 end
             end
@@ -654,8 +660,7 @@ function commands.fetchposboxes(tags,anchor,page) -- no caching (yet) / todo: an
             print("\n missing",tag)
         end
     end
- -- print(format(template_a,nofboxes,concat(list)))
-    context(template_a,nofboxes,concat(list))
+    context(f_template_a(nofboxes,list))
 end
 
 local doifelse = commands.doifelse
diff --git a/tex/context/base/anch-pos.lua b/tex/context/base/anch-pos.lua
index eda0ba37a..2697cecf4 100644
--- a/tex/context/base/anch-pos.lua
+++ b/tex/context/base/anch-pos.lua
@@ -41,6 +41,7 @@ local v_column          = variables.column
 
 local pt                = number.dimenfactors.pt
 local pts               = number.pts
+local formatters        = string.formatters
 
 local collected         = allocate()
 local tobesaved         = allocate()
@@ -73,6 +74,23 @@ local default = { -- not r and paragraphs etc
     }
 }
 
+local f_b_tag     = formatters["b:%s"]
+local f_e_tag     = formatters["e:%s"]
+local f_p_tag     = formatters["p:%s"]
+local f_w_tag     = formatters["w:%s"]
+
+local f_b_column  = formatters["_plib_.b_col(%q)"]
+local f_e_column  = formatters["_plib_.e_col()"]
+
+local f_enhance   = formatters["_plib_.enhance(%q)"]
+local f_region    = formatters["region:%s"]
+
+local f_b_region  = formatters["_plib_.b_region(%q)"]
+local f_e_region  = formatters["_plib_.e_region(%s)"]
+
+local f_tag_three = formatters["%s:%s:%s"]
+local f_tag_two   = formatters["%s:%s"]
+
 local function sorter(a,b)
     return a.y > b.y
 end
@@ -277,13 +295,13 @@ function commands.bcolumn(tag,register)
     insert(columns,tag)
     column = tag
     if register then
-        context(new_latelua(format("_plib_.b_col(%q)",tag)))
+        context(new_latelua(f_b_column(tag)))
     end
 end
 
 function commands.ecolumn(register)
     if register then
-        context(new_latelua("_plib_.e_col()"))
+        context(new_latelua(f_e_column()))
     end
     remove(columns)
     column = columns[#columns]
@@ -313,7 +331,7 @@ end
 function jobpositions.markregionbox(n,tag,correct)
     if not tag or tag == "" then
         nofregions = nofregions + 1
-        tag = format("region:%s",nofregions)
+        tag = f_region(nofregions)
     end
     local box = texbox[n]
     local w = box.width
@@ -327,8 +345,8 @@ function jobpositions.markregionbox(n,tag,correct)
         h = h ~= 0 and h or nil,
         d = d ~= 0 and d or nil,
     }
-    local push = new_latelua(format("_plib_.b_region(%q)",tag))
-    local pop  = new_latelua(format("_plib_.e_region(%s)",tostring(correct)))
+    local push = new_latelua(f_b_region(tag))
+    local pop  = new_latelua(f_e_region(tostring(correct))) -- todo: check if tostring is needed with formatter
     -- maybe we should construct a hbox first (needs experimenting) so that we can avoid some at the tex end
     local head = box.list
     if head then
@@ -350,7 +368,7 @@ end
 
 function commands.pos(name,t)
     tobesaved[name] = t
-    context(new_latelua(format("_plib_.enhance(%q)",name)))
+    context(new_latelua(f_enhance(name)))
 end
 
 local nofparagraphs = 0
@@ -393,9 +411,9 @@ function commands.parpos() -- todo: relate to localpar (so this is an intermedia
     if parshape and #parshape > 0 then
         t.ps = parshape
     end
-    local tag = format("p:%s",nofparagraphs)
+    local tag = f_p_tag(nofparagraphs)
     tobesaved[tag] = t
-    context(new_latelua(format("_plib_.enhance(%q)",tag)))
+    context(new_latelua(f_enhance(tag)))
 end
 
 function commands.posxy(name) -- can node.write be used here?
@@ -407,7 +425,7 @@ function commands.posxy(name) -- can node.write be used here?
         y = true,
         n = nofparagraphs > 0 and nofparagraphs or nil,
     }
-    context(new_latelua(format("_plib_.enhance(%q)",name)))
+    context(new_latelua(f_enhance(name)))
 end
 
 function commands.poswhd(name,w,h,d)
@@ -422,7 +440,7 @@ function commands.poswhd(name,w,h,d)
         d = d,
         n = nofparagraphs > 0 and nofparagraphs or nil,
     }
-    context(new_latelua(format("_plib_.enhance(%q)",name)))
+    context(new_latelua(f_enhance(name)))
 end
 
 function commands.posplus(name,w,h,d,extra)
@@ -438,7 +456,7 @@ function commands.posplus(name,w,h,d,extra)
         n = nofparagraphs > 0 and nofparagraphs or nil,
         e = extra,
     }
-    context(new_latelua(format("_plib_.enhance(%q)",name)))
+    context(new_latelua(f_enhance(name)))
 end
 
 function commands.posstrut(name,w,h,d)
@@ -453,12 +471,12 @@ function commands.posstrut(name,w,h,d)
         d = strutbox.depth,
         n = nofparagraphs > 0 and nofparagraphs or nil,
     }
-    context(new_latelua(format("_plib_.enhance(%q)",name)))
+    context(new_latelua(f_enhance(name)))
 end
 
 function jobpositions.getreserved(tag,n)
     if tag == v_column then
-        local fulltag = format("%s:%s:%s",tag,texcount.realpageno,n or 1)
+        local fulltag = f_tag_three(tag,texcount.realpageno,n or 1)
         local data = collected[fulltag]
         if data then
             return data, fulltag
@@ -466,7 +484,7 @@ function jobpositions.getreserved(tag,n)
         tag = v_text
     end
     if tag == v_text then
-        local fulltag = format("%s:%s",tag,texcount.realpageno)
+        local fulltag = f_tag_two(tag,texcount.realpageno)
         return collected[fulltag] or false, fulltag
     end
     return collected[tag] or false, tag
@@ -887,7 +905,7 @@ end
 local function MPpardata(n)
     local t = collected[n]
     if not t then
-        local tag = format("p:%s",n)
+        local tag = f_p_tag(n)
         t = collected[tag]
     end
     if t then
@@ -907,10 +925,10 @@ end
 commands.MPpardata = MPpardata
 
 function commands.MPposset(id) -- special helper, used in backgrounds
-    local b = format("b:%s",id)
-    local e = format("e:%s",id)
-    local w = format("w:%s",id)
-    local p = format("p:%s",jobpositions.n(b))
+    local b = f_b_tag(id)
+    local e = f_e_tag(id)
+    local w = f_w_tag(id)
+    local p = f_p_tag(jobpositions.n(b))
     MPpos(b) context(",") MPpos(e) context(",") MPpos(w) context(",") MPpos(p) context(",") MPpardata(p)
 end
 
diff --git a/tex/context/base/attr-col.lua b/tex/context/base/attr-col.lua
index 18182ba85..d4139daf7 100644
--- a/tex/context/base/attr-col.lua
+++ b/tex/context/base/attr-col.lua
@@ -41,6 +41,7 @@ local registrations   = backends.registrations
 local unsetvalue      = attributes.unsetvalue
 
 local registerstorage = storage.register
+local formatters      = string.formatters
 
 -- We can distinguish between rules and glyphs but it's not worth the trouble. A
 -- first implementation did that and while it saves a bit for glyphs and rules, it
@@ -100,11 +101,11 @@ local list        = attributes.list
 registerstorage("attributes/colors/values",     values,     "attributes.colors.values")
 registerstorage("attributes/colors/registered", registered, "attributes.colors.registered")
 
-local templates = {
-    rgb  = "r:%s:%s:%s",
-    cmyk = "c:%s:%s:%s:%s",
-    gray = "s:%s",
-    spot = "p:%s:%s:%s:%s"
+local f_colors = {
+    rgb  = formatters["r:%s:%s:%s"],
+    cmyk = formatters["c:%s:%s:%s:%s"],
+    gray = formatters["s:%s"],
+    spot = formatters["p:%s:%s:%s:%s"],
 }
 
 local models = {
@@ -322,7 +323,7 @@ function colors.setmodel(name,weightgray)
 end
 
 function colors.register(name, colorspace, ...) -- passing 9 vars is faster (but not called that often)
-    local stamp = format(templates[colorspace],...)
+    local stamp = f_colors[colorspace](...)
     local color = registered[stamp]
     if not color then
         color = #values + 1
@@ -379,7 +380,7 @@ transparencies.supported  = true
 local registered          = transparencies.registered -- we could use a 2 dimensional table instead
 local data                = transparencies.data
 local values              = transparencies.values
-local template            = "%s:%s"
+local f_transparency      = formatters["%s:%s"]
 
 registerstorage("attributes/transparencies/registered", registered, "attributes.transparencies.registered")
 registerstorage("attributes/transparencies/values",     values,     "attributes.transparencies.values")
@@ -399,7 +400,7 @@ function transparencies.register(name,a,t,force) -- name is irrelevant here (can
     -- but then we'd end up with transparencies resources even if we
     -- would not use transparencies (but define them only). This is
     -- somewhat messy.
-    local stamp = format(template,a,t)
+    local stamp = f_transparency(a,t)
     local n = registered[stamp]
     if not n then
         n = #values + 1
diff --git a/tex/context/base/back-pdf.mkiv b/tex/context/base/back-pdf.mkiv
index 7e910f07f..e0966ef52 100644
--- a/tex/context/base/back-pdf.mkiv
+++ b/tex/context/base/back-pdf.mkiv
@@ -141,7 +141,7 @@
 %
 % function lpdf.rotationcm(a)
 %     local s, c = sind(a), cosd(a)
-%     return format("%s %s %s %s 0 0 cm",c,s,-s,c)
+%     return format("%f %f %f %f 0 0 cm",c,s,-s,c)
 % end
 %
 % \def\dostartmirroring{\pdfliteral{-1 0 0 1 0 0 cm}}
diff --git a/tex/context/base/chem-str.lua b/tex/context/base/chem-str.lua
index 3ab2e53b6..1967948de 100644
--- a/tex/context/base/chem-str.lua
+++ b/tex/context/base/chem-str.lua
@@ -40,8 +40,9 @@ local settings_to_array_with_repeat = utilities.parsers.settings_to_array_with_r
 local lpegmatch = lpeg.match
 local P, R, S, C, Cs, Ct, Cc, Cmt = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Ct, lpeg.Cc, lpeg.Cmt
 
-local variables = interfaces and interfaces.variables
-local context   = context
+local variables  = interfaces and interfaces.variables
+local context    = context
+local formatters = string.formatters
 
 local v_default = variables.default
 local v_small   = variables.small
@@ -311,18 +312,18 @@ local pattern   =
 -- print(lpegmatch(pattern,"RZ1..3=x"))    -- 1 RZ 1     3     false x
 -- print(lpegmatch(pattern,"RZ13=x"))      -- 1 RZ false false table x
 
-local t_initialize      = 'if unknown context_chem : input mp-chem.mpiv ; fi ;'
-local t_start_structure = 'chem_start_structure(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s);'
-local t_stop_structure  = 'chem_stop_structure;'
-local t_start_component = 'chem_start_component;'
-local t_stop_component  = 'chem_stop_component;'
-local t_line            = 'chem_%s%s(%s,%s,%s,%s,%s);'
-local t_set             = 'chem_set(%s);'
-local t_number          = 'chem_%s%s(%s,%s,"\\chemicaltext{%s}");'
-local t_text            = t_number
-local t_empty_normal    = 'chem_%s(%s,%s,"");'
-local t_empty_center    = 'chem_c%s(%s,%s,"");'
-local t_transform       = 'chem_%s(%s,%s,%s);'
+local f_initialize      = formatters['if unknown context_chem : input mp-chem.mpiv ; fi ;']
+local f_start_structure = formatters['chem_start_structure(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s);']
+local f_stop_structure  = formatters['chem_stop_structure;']
+local f_start_component = formatters['chem_start_component;']
+local f_stop_component  = formatters['chem_stop_component;']
+local f_line            = formatters['chem_%s%s(%s,%s,%s,%s,%s);']
+local f_set             = formatters['chem_set(%s);']
+local f_number          = formatters['chem_%s%s(%s,%s,"\\chemicaltext{%s}");']
+local f_text            = f_number
+local f_empty_normal    = formatters['chem_%s(%s,%s,"");']
+local f_empty_center    = formatters['chem_c%s(%s,%s,"");']
+local f_transform       = formatters['chem_%s(%s,%s,%s);']
 
 local prepareMPvariable = commands and commands.prepareMPvariable
 
@@ -398,9 +399,9 @@ local function process(level,spec,text,n,rulethickness,rulecolor,offset,default_
                 m = m + 1 ; metacode[m] = syntax.pb.direct
                 if keys[special] == "text" and index then
                     if keys["c"..special] == "text" then -- can be option: auto ...
-                        m = m + 1 ; metacode[m] = format(t_empty_center,special,variant,index)
+                        m = m + 1 ; metacode[m] = f_empty_center(special,variant,index)
                     else
-                        m = m + 1 ; metacode[m] = format(t_empty_normal,special,variant,index)
+                        m = m + 1 ; metacode[m] = f_empty_normal(special,variant,index)
                     end
                 end
             elseif operation == "pe" then
@@ -408,7 +409,7 @@ local function process(level,spec,text,n,rulethickness,rulecolor,offset,default_
                 local ss = syntax[variant]
                 keys, max = ss.keys, ss.max
                 m = m + 1 ; metacode[m] = syntax[operation].direct
-                m = m + 1 ; metacode[m] = format(t_set,variant)
+                m = m + 1 ; metacode[m] = f_set(variant)
                 current_variant = variant
             elseif operation == "save" then
                 insert(sstack,variant)
@@ -418,7 +419,7 @@ local function process(level,spec,text,n,rulethickness,rulecolor,offset,default_
                 local ss = syntax[variant]
                 keys, max = ss.keys, ss.max
                 m = m + 1 ; metacode[m] = syntax[operation].direct
-                m = m + 1 ; metacode[m] = format(t_set,variant)
+                m = m + 1 ; metacode[m] = f_set(variant)
                 current_variant = variant
             elseif operation then
                 local ss = syntax[operation]
@@ -481,7 +482,7 @@ local function process(level,spec,text,n,rulethickness,rulecolor,offset,default_
                         end
                     elseif ss.keys then
                         variant, keys, max = s, ss.keys, ss.max
-                        m = m + 1 ; metacode[m] = format(t_set,variant)
+                        m = m + 1 ; metacode[m] = f_set(variant)
                         current_variant = variant
                     end
                 elseif what == "line" then
@@ -494,35 +495,35 @@ local function process(level,spec,text,n,rulethickness,rulecolor,offset,default_
                         local sf, st = set[1]
                         for i=1,ns do
                             if i > 1 and set[i] ~= set[i-1]+1 then
-                                m = m + 1 ; metacode[m] = format(t_line,operation,s,variant,sf,st,rulethickness,rulecolor)
+                                m = m + 1 ; metacode[m] = f_line(operation,s,variant,sf,st,rulethickness,rulecolor)
                                 sf = set[i]
                             end
                             st = set[i]
                         end
-                        m = m + 1 ; metacode[m] = format(t_line,operation,s,variant,sf,st,rulethickness,rulecolor)
+                        m = m + 1 ; metacode[m] = f_line(operation,s,variant,sf,st,rulethickness,rulecolor)
                     elseif upto then
-                        m = m + 1 ; metacode[m] = format(t_line,operation,s,variant,index,upto,rulethickness,rulecolor)
+                        m = m + 1 ; metacode[m] = f_line(operation,s,variant,index,upto,rulethickness,rulecolor)
                     elseif index then
-                        m = m + 1 ; metacode[m] = format(t_line,operation,s,variant,index,index,rulethickness,rulecolor)
+                        m = m + 1 ; metacode[m] = f_line(operation,s,variant,index,index,rulethickness,rulecolor)
                     else
-                        m = m + 1 ; metacode[m] = format(t_line,operation,s,variant,1,max,rulethickness,rulecolor)
+                        m = m + 1 ; metacode[m] = f_line(operation,s,variant,1,max,rulethickness,rulecolor)
                     end
                 elseif what == "number" then
                     if set then
                         for i=1,ns do
                             local si = set[i]
-                            m = m + 1 ; metacode[m] = format(t_number,operation,align,variant,si,si)
+                            m = m + 1 ; metacode[m] = f_number(operation,align,variant,si,si)
                         end
                     elseif upto then
                         for i=index,upto do
                             local si = set[i]
-                            m = m + 1 ; metacode[m] = format(t_number,operation,align,variant,si,si)
+                            m = m + 1 ; metacode[m] = f_number(operation,align,variant,si,si)
                         end
                     elseif index then
-                        m = m + 1 ; metacode[m] = format(t_number,operation,align,variant,index,index)
+                        m = m + 1 ; metacode[m] = f_number(operation,align,variant,index,index)
                     else
                         for i=1,max do
-                            m = m + 1 ; metacode[m] = format(t_number,operation,align,variant,i,i)
+                            m = m + 1 ; metacode[m] = f_number(operation,align,variant,i,i)
                         end
                     end
                 elseif what == "text" then
@@ -533,7 +534,7 @@ local function process(level,spec,text,n,rulethickness,rulecolor,offset,default_
                             if not t then txt, t = fetch(txt) end
                             if t then
                                 t = molecule(processor_tostring(t))
-                                m = m + 1 ; metacode[m] = format(t_text,operation,align,variant,si,t)
+                                m = m + 1 ; metacode[m] = f_text(operation,align,variant,si,t)
                             end
                         end
                     elseif upto then
@@ -542,7 +543,7 @@ local function process(level,spec,text,n,rulethickness,rulecolor,offset,default_
                             if not t then txt, t = fetch(txt) end
                             if t then
                                 t = molecule(processor_tostring(t))
-                                m = m + 1 ; metacode[m] = format(t_text,operation,align,variant,i,t)
+                                m = m + 1 ; metacode[m] = f_text(operation,align,variant,i,t)
                             end
                         end
                     elseif index == 0 then
@@ -550,14 +551,14 @@ local function process(level,spec,text,n,rulethickness,rulecolor,offset,default_
                         if not t then txt, t = fetch(txt) end
                         if t then
                             t = molecule(processor_tostring(t))
-                            m = m + 1 ; metacode[m] = format(t_text,operation,align,variant,index,t)
+                            m = m + 1 ; metacode[m] = f_text(operation,align,variant,index,t)
                         end
                     elseif index then
                         local t = text
                         if not t then txt, t = fetch(txt) end
                         if t then
                             t = molecule(processor_tostring(t))
-                            m = m + 1 ; metacode[m] = format(t_text,operation,align,variant,index,t)
+                            m = m + 1 ; metacode[m] = f_text(operation,align,variant,index,t)
                         end
                     else
                         for i=1,max do
@@ -565,7 +566,7 @@ local function process(level,spec,text,n,rulethickness,rulecolor,offset,default_
                             if not t then txt, t = fetch(txt) end
                             if t then
                                 t = molecule(processor_tostring(t))
-                                m = m + 1 ; metacode[m] = format(t_text,operation,align,variant,i,t)
+                                m = m + 1 ; metacode[m] = f_text(operation,align,variant,i,t)
                             end
                         end
                     end
@@ -576,17 +577,17 @@ local function process(level,spec,text,n,rulethickness,rulecolor,offset,default_
                     if set then
                         for i=1,ns do
                             local si = set[i]
-                            m = m + 1 ; metacode[m] = format(t_transform,operation,variant,si,factor)
+                            m = m + 1 ; metacode[m] = f_transform(operation,variant,si,factor)
                         end
                     elseif upto then
                         for i=index,upto do
-                            m = m + 1 ; metacode[m] = format(t_transform,operation,variant,i,factor)
+                            m = m + 1 ; metacode[m] = f_transform(operation,variant,i,factor)
                         end
                     else
-                        m = m + 1 ; metacode[m] = format(t_transform,operation,variant,index or 1,factor)
+                        m = m + 1 ; metacode[m] = f_transform(operation,variant,index or 1,factor)
                     end
                 elseif what == "fixed" then
-                    m = m + 1 ; metacode[m] = format(t_transform,operation,variant,rulethickness,rulecolor)
+                    m = m + 1 ; metacode[m] = f_transform(operation,variant,rulethickness,rulecolor)
                 elseif trace_structure then
                     report_chemistry("%s > warning: undefined operation %s ignored here",
                         level, operation or "")
@@ -685,7 +686,7 @@ function chemistry.start(settings)
     end
     rotation = tonumber(rotation) or 0
     --
-    metacode[#metacode+1] = format(t_start_structure,
+    metacode[#metacode+1] = f_start_structure(
         chemistry.structures,
         l, r, t, b, scale, rotation,
         tostring(width), tostring(height), tostring(emwidth), tostring(offset),
@@ -696,19 +697,19 @@ function chemistry.start(settings)
 end
 
 function chemistry.stop()
-    metacode[#metacode+1] = t_stop_structure
+    metacode[#metacode+1] = f_stop_structure()
     local mpcode = concat(metacode,"\n")
     if trace_metapost then
         report_chemistry("metapost code:\n%s", mpcode)
     end
     if metapost.instance(chemistry.instance) then
-        t_initialize = ""
+        f_initialize = nil
     end
     metapost.graphic {
         instance    = chemistry.instance,
         format      = chemistry.format,
         data        = mpcode,
-        definitions = t_initialize,
+        definitions = f_initialize and f_initialize(),
     }
     t_initialize = ""
     metacode = nil
@@ -719,9 +720,9 @@ function chemistry.component(spec,text,settings)
     local spec = settings_to_array_with_repeat(spec,true) -- no lower?
     local text = settings_to_array_with_repeat(text,true)
 -- inspect(spec)
-    metacode[#metacode+1] = t_start_component
+    metacode[#metacode+1] = f_start_component()
     process(1,spec,text,1,rulethickness,rulecolor) -- offset?
-    metacode[#metacode+1] = t_stop_component
+    metacode[#metacode+1] = f_stop_component()
 end
 
 statistics.register("chemical formulas", function()
diff --git a/tex/context/base/cldf-ini.lua b/tex/context/base/cldf-ini.lua
index b045282b1..c943dcb51 100644
--- a/tex/context/base/cldf-ini.lua
+++ b/tex/context/base/cldf-ini.lua
@@ -609,7 +609,7 @@ function context.fprint(catcodes,fmt,first,...)
         end
     else
         if fmt then
-            flush(format(catodes,fmt,first,...))
+            flush(format(catcodes,fmt,first,...))
         else
             flush(catcodes)
         end
@@ -624,6 +624,24 @@ function tex.fprint(fmt,first,...) -- goodie
     end
 end
 
+local formatters = string.formatters
+
+function context.formatted(catcodes,fmt,first,...)
+    if type(catcodes) == "number" then
+        if first then
+            flush(catcodes,formatters[fmt](first,...))
+        else
+            flush(catcodes,fmt)
+        end
+    else
+        if fmt then
+            flush(formatters[catcodes](fmt,first,...))
+        else
+            flush(catcodes)
+        end
+    end
+end
+
 -- logging
 
 local trace_stack   = { }
diff --git a/tex/context/base/context-version.pdf b/tex/context/base/context-version.pdf
index 988b0384d..9e36f1a86 100644
Binary files a/tex/context/base/context-version.pdf and b/tex/context/base/context-version.pdf differ
diff --git a/tex/context/base/context-version.png b/tex/context/base/context-version.png
index b588b612d..db588f664 100644
Binary files a/tex/context/base/context-version.png and b/tex/context/base/context-version.png differ
diff --git a/tex/context/base/core-uti.lua b/tex/context/base/core-uti.lua
index 5f00d6fff..b1b830c31 100644
--- a/tex/context/base/core-uti.lua
+++ b/tex/context/base/core-uti.lua
@@ -35,7 +35,7 @@ local report_passes = logs.reporter("job","passes")
 job                 = job or { }
 local job           = job
 
-job.version         = "1.20"
+job.version         = "1.21"
 
 -- some day we will implement loading of other jobs and then we need
 -- job.jobs
diff --git a/tex/context/base/data-tex.lua b/tex/context/base/data-tex.lua
index f19b53407..6ba742cce 100644
--- a/tex/context/base/data-tex.lua
+++ b/tex/context/base/data-tex.lua
@@ -67,6 +67,7 @@ function helpers.textopener(tag,filename,filehandle,coding)
         lines = filehandle
     else
         lines = filehandle:read("*a") -- io.readall(filehandle) ... but never that large files anyway
+     -- lines = io.readall(filehandle)
         filehandle:close()
     end
     if type(lines) == "string" then
diff --git a/tex/context/base/grph-inc.lua b/tex/context/base/grph-inc.lua
index ee59de508..d58221fe7 100644
--- a/tex/context/base/grph-inc.lua
+++ b/tex/context/base/grph-inc.lua
@@ -43,6 +43,7 @@ local contains = table.contains
 local concat, insert, remove = table.concat, table.insert, table.remove
 local todimen = string.todimen
 local collapsepath = file.collapsepath
+local formatters = string.formatters
 
 local P, lpegmatch = lpeg.P, lpeg.match
 
@@ -65,6 +66,9 @@ local report_inclusion  = logs.reporter("graphics","inclusion")
 
 local context, img = context, img
 
+local f_hash_part = formatters["%s->%s->%s"]
+local f_hash_full = formatters["%s->%s->%s->%s->%s->%s->%s"]
+
 local maxdimen = 2^30-1
 
 function img.check(figure)
@@ -635,7 +639,7 @@ local function register(askedname,specification)
         end
     end
     specification.foundname = specification.foundname or specification.fullname
-    local askedhash = format("%s->%s->%s",askedname,specification.conversion or "default",specification.resolution or "default")
+    local askedhash = f_hash_part(askedname,specification.conversion or "default",specification.resolution or "default")
     figures_found[askedhash] = specification
     return specification
 end
@@ -646,7 +650,7 @@ local function locate(request) -- name, format, cache
     -- not resolvers.cleanpath(request.name) as it fails on a!b.pdf and b~c.pdf
     -- todo: more restricted cleanpath
     local askedname = request.name
-    local askedhash = format("%s->%s->%s",askedname,request.conversion or "default",request.resolution or "default")
+    local askedhash = f_hash_part(askedname,request.conversion or "default",request.resolution or "default")
     local foundname = figures_found[askedhash]
     if foundname then
         return foundname
@@ -980,7 +984,7 @@ function checkers.generic(data)
     if not resolution or resolution == "" then
         resolution = "unknown"
     end
-    local hash = format("%s->%s->%s->%s->%s->%s->%s",name,page,size,color,conversion,resolution,mask)
+    local hash = f_hash_full(name,page,size,color,conversion,resolution,mask)
     local figure = figures_loaded[hash]
     if figure == nil then
         figure = img.new {
diff --git a/tex/context/base/l-io.lua b/tex/context/base/l-io.lua
index e7bc23642..e48b448c5 100644
--- a/tex/context/base/l-io.lua
+++ b/tex/context/base/l-io.lua
@@ -59,7 +59,7 @@ io.readall = readall
 function io.loaddata(filename,textmode) -- return nil if empty
     local f = io.open(filename,(textmode and 'r') or 'rb')
     if f then
-     -- local data = f:read('*all')
+--       local data = f:read('*all')
         local data = readall(f)
         f:close()
         if #data > 0 then
@@ -88,29 +88,29 @@ end
 
 function io.loadlines(filename,n) -- return nil if empty
     local f = io.open(filename,'r')
-    if f then
-        if n then
-            local lines = { }
-            for i=1,n do
-                local line = f:read("*lines")
-                if line then
-                    lines[#lines+1] = line
-                else
-                    break
-                end
-            end
-            f:close()
-            lines = concat(lines,"\n")
-            if #lines > 0 then
-                return lines
-            end
-        else
-            local line = f:read("*line") or ""
-            assert(f:close())
-            if #line > 0 then
-                return line
+    if not f then
+        -- no file
+    elseif n then
+        local lines = { }
+        for i=1,n do
+            local line = f:read("*lines")
+            if line then
+                lines[#lines+1] = line
+            else
+                break
             end
         end
+        f:close()
+        lines = concat(lines,"\n")
+        if #lines > 0 then
+            return lines
+        end
+    else
+        local line = f:read("*line") or ""
+        f:close()
+        if #line > 0 then
+            return line
+        end
     end
 end
 
@@ -130,7 +130,7 @@ function io.exists(filename)
     if f == nil then
         return false
     else
-        assert(f:close())
+        f:close()
         return true
     end
 end
@@ -141,7 +141,7 @@ function io.size(filename)
         return 0
     else
         local s = f:seek("end")
-        assert(f:close())
+        f:close()
         return s
     end
 end
@@ -149,9 +149,13 @@ end
 function io.noflines(f)
     if type(f) == "string" then
         local f = io.open(filename)
-        local n = f and io.noflines(f) or 0
-        assert(f:close())
-        return n
+        if f then
+            local n = f and io.noflines(f) or 0
+            f:close()
+            return n
+        else
+            return 0
+        end
     else
         local n = 0
         for _ in f:lines() do
diff --git a/tex/context/base/lpdf-col.lua b/tex/context/base/lpdf-col.lua
index db9d3268b..4936b37c9 100644
--- a/tex/context/base/lpdf-col.lua
+++ b/tex/context/base/lpdf-col.lua
@@ -14,6 +14,7 @@ local round = math.round
 local backends, lpdf, nodes = backends, lpdf, nodes
 
 local allocate             = utilities.storage.allocate
+local formatters           = string.formatters
 
 local nodeinjections       = backends.pdf.nodeinjections
 local codeinjections       = backends.pdf.codeinjections
@@ -42,6 +43,11 @@ local forcedmodel          = colors.forcedmodel
 
 local c_transparency = pdfconstant("Transparency")
 
+local f_gray = formatters["%.3f g %.3f G"]
+local f_rgb  = formatters["%.3f %.3f %.3f rg %.3f %.3f %.3f RG"]
+local f_cmyk = formatters["%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K"]
+local f_cm   = formatters["q %f %f %f %f %f %f cm"]
+
 local report_color = logs.reporter("colors","backend")
 
 -- page groups (might move to lpdf-ini.lua)
@@ -99,15 +105,15 @@ commands.synchronizecolormodel                = synchronizecolormodel
 -- color injection
 
 function nodeinjections.rgbcolor(r,g,b)
-    return register(pdfliteral(format("%s %s %s rg %s %s %s RG",r,g,b,r,g,b)))
+    return register(pdfliteral(f_rgb(r,g,b,r,g,b)))
 end
 
 function nodeinjections.cmykcolor(c,m,y,k)
-    return register(pdfliteral(format("%s %s %s %s k %s %s %s %s K",c,m,y,k,c,m,y,k)))
+    return register(pdfliteral(f_cmyk(c,m,y,k,c,m,y,k)))
 end
 
 function nodeinjections.graycolor(s) -- caching 0/1 does not pay off
-    return register(pdfliteral(format("%s g %s G",s,s)))
+    return register(pdfliteral(f_gray(s,s)))
 end
 
 function nodeinjections.spotcolor(n,f,d,p)
@@ -154,9 +160,9 @@ local pdf_rbg_range  = pdfarray { 0, 1, 0, 1, 0, 1 }
 local pdf_cmyk_range = pdfarray { 0, 1, 0, 1, 0, 1, 0, 1 }
 local pdf_gray_range = pdfarray { 0, 1 }
 
-local rgb_function  = "dup %s mul exch dup %s mul exch %s mul"
-local cmyk_function = "dup %s mul exch dup %s mul exch dup %s mul exch %s mul"
-local gray_function = "%s mul"
+local f_rgb_function  = formatters["dup %s mul exch dup %s mul exch %s mul"]
+local f_cmyk_function = formatters["dup %s mul exch dup %s mul exch dup %s mul exch %s mul"]
+local f_gray_function = formatters["%s mul"]
 
 local documentcolorspaces = pdfdictionary()
 
@@ -345,47 +351,47 @@ end
 
 function registrations.rgbspotcolor(name,noffractions,names,p,r,g,b)
     if noffractions == 1 then
-        registersomespotcolor(name,noffractions,names,p,pdf_device_rgb,pdf_rbg_range,format(rgb_function,r,g,b))
+        registersomespotcolor(name,noffractions,names,p,pdf_device_rgb,pdf_rbg_range,f_rgb_function(r,g,b))
     else
         registersomespotcolor(name,noffractions,names,p,pdf_device_rgb,pdf_rbg_range,format("%s %s %s",r,g,b))
     end
     delayindexcolor(name,names,function()
-        return registersomeindexcolor(name,noffractions,names,p,pdf_device_rgb,pdf_rgb_range,format(rgb_function,r,g,b))
+        return registersomeindexcolor(name,noffractions,names,p,pdf_device_rgb,pdf_rgb_range,f_rgb_function(r,g,b))
     end)
 end
 
 function registrations.cmykspotcolor(name,noffractions,names,p,c,m,y,k)
     if noffractions == 1 then
-        registersomespotcolor(name,noffractions,names,p,pdf_device_cmyk,pdf_cmyk_range,format(cmyk_function,c,m,y,k))
+        registersomespotcolor(name,noffractions,names,p,pdf_device_cmyk,pdf_cmyk_range,f_cmyk_function(c,m,y,k))
     else
         registersomespotcolor(name,noffractions,names,p,pdf_device_cmyk,pdf_cmyk_range,format("%s %s %s %s",c,m,y,k))
     end
     delayindexcolor(name,names,function()
-        return registersomeindexcolor(name,noffractions,names,p,pdf_device_cmyk,pdf_cmyk_range,format(cmyk_function,c,m,y,k))
+        return registersomeindexcolor(name,noffractions,names,p,pdf_device_cmyk,pdf_cmyk_range,f_cmyk_function(c,m,y,k))
     end)
 end
 
 function registrations.grayspotcolor(name,noffractions,names,p,s)
     if noffractions == 1 then
-        registersomespotcolor(name,noffractions,names,p,pdf_device_gray,pdf_gray_range,format(gray_function,s))
+        registersomespotcolor(name,noffractions,names,p,pdf_device_gray,pdf_gray_range,f_gray_function(s))
     else
         registersomespotcolor(name,noffractions,names,p,pdf_device_gray,pdf_gray_range,s)
     end
     delayindexcolor(name,names,function()
-        return registersomeindexcolor(name,noffractions,names,p,pdf_device_gray,pdf_gray_range,format(gray_function,s))
+        return registersomeindexcolor(name,noffractions,names,p,pdf_device_gray,pdf_gray_range,f_gray_function(s))
     end)
 end
 
 function registrations.rgbindexcolor(name,noffractions,names,p,r,g,b)
-    registersomeindexcolor(name,noffractions,names,p,pdf_device_rgb,pdf_rgb_range,format(rgb_function,r,g,b))
+    registersomeindexcolor(name,noffractions,names,p,pdf_device_rgb,pdf_rgb_range,f_rgb_function(r,g,b))
 end
 
 function registrations.cmykindexcolor(name,noffractions,names,p,c,m,y,k)
-    registersomeindexcolor(name,noffractions,names,p,pdf_device_cmyk,pdf_cmyk_range,format(cmyk_function,c,m,y,k))
+    registersomeindexcolor(name,noffractions,names,p,pdf_device_cmyk,pdf_cmyk_range,f_cmyk_function(c,m,y,k))
 end
 
 function registrations.grayindexcolor(name,noffractions,names,p,s)
-    registersomeindexcolor(name,noffractions,names,p,pdf_device_gray,pdf_gray_range,gray_function)
+    registersomeindexcolor(name,noffractions,names,p,pdf_device_gray,pdf_gray_range,f_gray_function(s))
 end
 
 function codeinjections.setfigurecolorspace(data,figure)
@@ -461,11 +467,10 @@ end
 
 statistics.register("page group warning", function()
     if done and not transparencygroups[currentgroupcolormodel] then
-        return format("transparencies are used but no pagecolormodel is set")
+        return "transparencies are used but no pagecolormodel is set"
     end
 end)
 
-
 -- Literals needed to inject code in the mp stream, we cannot use attributes there
 -- since literals may have qQ's, much may go away once we have mplib code in place.
 --
@@ -482,13 +487,13 @@ local function lpdfcolor(model,ca,default) -- todo: use gray when no color
             model = forcedmodel(model)
             if model == 2 then
                 local s = cv[2]
-                return format("%s g %s G",s,s)
+                return f_gray(s,s)
             elseif model == 3 then
                 local r, g, b = cv[3], cv[4], cv[5]
-                return format("%s %s %s rg %s %s %s RG",r,g,b,r,g,b)
+                return f_rgb(r,g,b,r,g,b)
             elseif model == 4 then
                 local c, m, y, k = cv[6],cv[7],cv[8],cv[9]
-                return format("%s %s %s %s k %s %s %s %s K",c,m,y,k,c,m,y,k)
+                return f_cmyk(c,m,y,k,c,m,y,k)
             else
                 local n,f,d,p = cv[10],cv[11],cv[12],cv[13]
                 if type(p) == "string" then
@@ -497,7 +502,7 @@ local function lpdfcolor(model,ca,default) -- todo: use gray when no color
                 return format("/%s cs /%s CS %s SCN %s scn",n,n,p,p)
             end
         else
-            return format("%s g %s G",default or 0,default or 0)
+            return f_gray(default or 0,default or 0)
         end
     else
         return ""
@@ -716,7 +721,7 @@ backends.pdf.tables.vfspecials = allocate { -- todo: distinguish between glyph a
             palegray   = { "special", 'pdf: .75 g' },
     },
 
-    startslant = function(a) return { "special", format("pdf: q 1 0 %s 1 0 0 cm",a) } end,
+    startslant = function(a) return { "special", format("pdf: q 1 0 %f 1 0 0 cm",a) } end,
     stopslant  = { "special", "pdf: Q" },
 
 }
diff --git a/tex/context/base/lpdf-grp.lua b/tex/context/base/lpdf-grp.lua
index aba5771fd..fed5e6a46 100644
--- a/tex/context/base/lpdf-grp.lua
+++ b/tex/context/base/lpdf-grp.lua
@@ -236,7 +236,7 @@ function img.package(image) -- see lpdf-u3d **
     local height = boundingbox[4]
     local xform = img.scan {
         attr   = resources(),
-        stream = format("%s 0 0 %s 0 0 cm /%s Do",width,height,imagetag),
+        stream = format("%f 0 0 %f 0 0 cm /%s Do",width,height,imagetag),
         bbox   = { 0, 0, width/factor, height/factor },
     }
     img.immediatewrite(xform)
diff --git a/tex/context/base/lpdf-ini.lua b/tex/context/base/lpdf-ini.lua
index c1b742949..bdecf63c2 100644
--- a/tex/context/base/lpdf-ini.lua
+++ b/tex/context/base/lpdf-ini.lua
@@ -11,6 +11,7 @@ local char, byte, format, gsub, concat, match, sub, gmatch = string.char, string
 local utfchar, utfvalues = utf.char, utf.values
 local sind, cosd = math.sind, math.cosd
 local lpegmatch, P, C, R, S, Cc, Cs = lpeg.match, lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.Cc, lpeg.Cs
+local formatters = string.formatters
 
 local pdfreserveobject   = pdf.reserveobj
 local pdfimmediateobject = pdf.immediateobj
@@ -38,7 +39,7 @@ backends.pdf = backends.pdf or {
 lpdf       = lpdf or { }
 local lpdf = lpdf
 
-local function tosixteen(str) -- an lpeg might be faster
+local function tosixteen(str) -- an lpeg might be faster (no table)
     if not str or str == "" then
         return "<feff>" -- not () as we want an indication that it's unicode
     else
@@ -104,6 +105,12 @@ local function merge_t(a,b)
     return setmetatable(t,getmetatable(a))
 end
 
+local f_key_value      = formatters["/%s %s"]
+local f_key_dictionary = formatters["/%s << % t >>"]
+local f_dictionary     = formatters["<< % t >>"]
+local f_key_array      = formatters["/%s [ % t ]"]
+local f_array          = formatters["[ % t ]"]
+
 local tostring_a, tostring_d
 
 tostring_d = function(t,contentonly,key)
@@ -119,28 +126,28 @@ tostring_d = function(t,contentonly,key)
             rn = rn + 1
             local tv = type(v)
             if tv == "string" then
-                r[rn] = format("/%s %s",k,toeight(v))
+                r[rn] = f_key_value(k,toeight(v))
             elseif tv == "unicode" then
-                r[rn] = format("/%s %s",k,tosixteen(v))
+                r[rn] = f_key_value(k,tosixteen(v))
             elseif tv == "table" then
                 local mv = getmetatable(v)
                 if mv and mv.__lpdftype then
-                    r[rn] = format("/%s %s",k,tostring(v))
+                    r[rn] = f_key_value(k,tostring(v))
                 elseif v[1] then
-                    r[rn] = format("/%s %s",k,tostring_a(v))
+                    r[rn] = f_key_value(k,tostring_a(v))
                 else
-                    r[rn] = format("/%s %s",k,tostring_d(v))
+                    r[rn] = f_key_value(k,tostring_d(v))
                 end
             else
-                r[rn] = format("/%s %s",k,tostring(v))
+                r[rn] = f_key_value(k,tostring(v))
             end
         end
         if contentonly then
-            return concat(r, " ")
+            return concat(r," ")
         elseif key then
-            return format("/%s << %s >>", key, concat(r, " "))
+            return f_key_dictionary(key,r)
         else
-            return format("<< %s >>", concat(r, " "))
+            return f_dictionary(r)
         end
     end
 end
@@ -179,9 +186,9 @@ tostring_a = function(t,contentonly,key)
         if contentonly then
             return concat(r, " ")
         elseif key then
-            return format("/%s [ %s ]", key, concat(r, " "))
+            return f_key_array(key,r)
         else
-            return format("[ %s ]", concat(r, " "))
+            return f_array(r)
         end
     end
 end
diff --git a/tex/context/base/lpdf-u3d.lua b/tex/context/base/lpdf-u3d.lua
index f5f66a487..33269486c 100644
--- a/tex/context/base/lpdf-u3d.lua
+++ b/tex/context/base/lpdf-u3d.lua
@@ -462,7 +462,7 @@ local function insert3d(spec) -- width, height, factor, display, controls, label
                             },
                 ProcSet    = pdfarray { pdfconstant("PDF"), pdfconstant("ImageC") },
             }
-            local pwd = pdfflushstreamobject(format("q /GS gs %s 0 0 %s 0 0 cm /IM Do Q",factor*width,factor*height),pw)
+            local pwd = pdfflushstreamobject(format("q /GS gs %f 0 0 %f 0 0 cm /IM Do Q",factor*width,factor*height),pw)
             annot.AP = pdfdictionary {
                 N = pdfreference(pwd)
             }
diff --git a/tex/context/base/luat-fio.lua b/tex/context/base/luat-fio.lua
index 0af9cb6fc..d194928dd 100644
--- a/tex/context/base/luat-fio.lua
+++ b/tex/context/base/luat-fio.lua
@@ -43,47 +43,46 @@ if not resolvers.instance then
         register('find_read_file'      , function(id,name) return findtexfile(name) end, true)
         register('open_read_file'      , function(   name) return opentexfile(name) end, true)
 
-        register('find_data_file'      , function(name) return findbinfile(name,"tex") end, true)
-        register('find_enc_file'       , function(name) return findbinfile(name,"enc") end, true)
-        register('find_font_file'      , function(name) return findbinfile(name,"tfm") end, true)
-        register('find_format_file'    , function(name) return findbinfile(name,"fmt") end, true)
-        register('find_image_file'     , function(name) return findbinfile(name,"tex") end, true)
-        register('find_map_file'       , function(name) return findbinfile(name,"map") end, true)
-        register('find_opentype_file'  , function(name) return findbinfile(name,"otf") end, true)
-        register('find_output_file'    , function(name) return name                    end, true)
-        register('find_pk_file'        , function(name) return findbinfile(name,"pk")  end, true)
-        register('find_sfd_file'       , function(name) return findbinfile(name,"sfd") end, true)
-        register('find_truetype_file'  , function(name) return findbinfile(name,"ttf") end, true)
-        register('find_type1_file'     , function(name) return findbinfile(name,"pfb") end, true)
-        register('find_vf_file'        , function(name) return findbinfile(name,"vf")  end, true)
-
-        register('read_data_file'      , function(file) return loadbinfile(file,"tex") end, true)
-        register('read_enc_file'       , function(file) return loadbinfile(file,"enc") end, true)
-        register('read_font_file'      , function(file) return loadbinfile(file,"tfm") end, true)
+        register('find_data_file'      , function(name) return findbinfile(name,"tex")    end, true)
+        register('find_enc_file'       , function(name) return findbinfile(name,"enc")    end, true)
+        register('find_font_file'      , function(name) return findbinfile(name,"tfm")    end, true)
+        register('find_format_file'    , function(name) return findbinfile(name,"fmt")    end, true)
+        register('find_image_file'     , function(name) return findbinfile(name,"tex")    end, true)
+        register('find_map_file'       , function(name) return findbinfile(name,"map")    end, true)
+        register('find_opentype_file'  , function(name) return findbinfile(name,"otf")    end, true)
+        register('find_output_file'    , function(name) return name                       end, true)
+        register('find_pk_file'        , function(name) return findbinfile(name,"pk")     end, true)
+        register('find_sfd_file'       , function(name) return findbinfile(name,"sfd")    end, true)
+        register('find_truetype_file'  , function(name) return findbinfile(name,"ttf")    end, true)
+        register('find_type1_file'     , function(name) return findbinfile(name,"pfb")    end, true)
+        register('find_vf_file'        , function(name) return findbinfile(name,"vf")     end, true)
+        register('find_cidmap_file'    , function(name) return findbinfile(name,"cidmap") end, true)
+
+        register('read_data_file'      , function(file) return loadbinfile(file,"tex")    end, true)
+        register('read_enc_file'       , function(file) return loadbinfile(file,"enc")    end, true)
+        register('read_font_file'      , function(file) return loadbinfile(file,"tfm")    end, true)
      -- format
      -- image
-        register('read_map_file'       , function(file) return loadbinfile(file,"map") end, true)
+        register('read_map_file'       , function(file) return loadbinfile(file,"map")    end, true)
      -- output
-        register('read_pk_file'        , function(file) return loadbinfile(file,"pk")  end, true) -- 600dpi/manfnt.720pk
-        register('read_sfd_file'       , function(file) return loadbinfile(file,"sfd") end, true)
-        register('read_vf_file'        , function(file) return loadbinfile(file,"vf" ) end, true)
+        register('read_pk_file'        , function(file) return loadbinfile(file,"pk")     end, true) -- 600dpi/manfnt.720pk
+        register('read_sfd_file'       , function(file) return loadbinfile(file,"sfd")    end, true)
+        register('read_vf_file'        , function(file) return loadbinfile(file,"vf" )    end, true)
 
-        register('find_font_file'      , function(name) return findbinfile(name,"ofm") end, true)
-        register('find_vf_file'        , function(name) return findbinfile(name,"ovf") end, true)
+        register('find_font_file'      , function(name) return findbinfile(name,"ofm")    end, true)
+        register('find_vf_file'        , function(name) return findbinfile(name,"ovf")    end, true)
 
-        register('read_font_file'      , function(file) return loadbinfile(file,"ofm") end, true)
-        register('read_vf_file'        , function(file) return loadbinfile(file,"ovf") end, true)
+        register('read_font_file'      , function(file) return loadbinfile(file,"ofm")    end, true)
+        register('read_vf_file'        , function(file) return loadbinfile(file,"ovf")    end, true)
 
-     -- register('read_opentype_file'  , function(file) return loadbinfile(file,"otf") end, true)
-     -- register('read_truetype_file'  , function(file) return loadbinfile(file,"ttf") end, true)
-     -- register('read_type1_file'     , function(file) return loadbinfile(file,"pfb") end, true)
+     -- register('read_opentype_file'  , function(file) return loadbinfile(file,"otf")    end, true)
+     -- register('read_truetype_file'  , function(file) return loadbinfile(file,"ttf")    end, true)
+     -- register('read_type1_file'     , function(file) return loadbinfile(file,"pfb")    end, true)
+     -- register('read_cidmap_file'    , function(file) return loadbinfile(file,"cidmap") end, true)
 
         register('find_write_file'     , function(id,name) return name end, true)
         register('find_format_file'    , function(name)    return name end, true)
 
-        register('find_cidmap_file'    , function(name) return findbinfile(name,"cidmap") end, true)
-     -- register('read_cidmap_file'    , function(file) return loadbinfile(file,"cidmap") end, true)
-
     end
 
 end
diff --git a/tex/context/base/luat-lib.mkiv b/tex/context/base/luat-lib.mkiv
index 6ca0ac05a..283ed8998 100644
--- a/tex/context/base/luat-lib.mkiv
+++ b/tex/context/base/luat-lib.mkiv
@@ -13,10 +13,10 @@
 
 \writestatus{loading}{ConTeXt Lua Macros / Libraries}
 
-\registerctxluafile{util-str}{1.001}
 \registerctxluafile{util-tab}{1.001}
-\registerctxluafile{util-pck}{1.001}
 \registerctxluafile{util-sto}{1.001} % could also be done in trac-deb.mkiv
+\registerctxluafile{util-str}{1.001} % uses util-sto
+\registerctxluafile{util-pck}{1.001}
 \registerctxluafile{util-seq}{1.001}
 %registerctxluafile{util-mrg}{1.001} % not needed in context itself, only mtxrun
 \registerctxluafile{util-lua}{1.001}
diff --git a/tex/context/base/m-chart.mkvi b/tex/context/base/m-chart.mkvi
index cb6a1e8c8..2b1a7447c 100644
--- a/tex/context/base/m-chart.mkvi
+++ b/tex/context/base/m-chart.mkvi
@@ -30,20 +30,6 @@
 % todo: figure out a nice way to define the lot: share current and
 % support current as name (nb: we need to set parent then)
 
-% \def\??flch{@@flch} % chart
-% \def\??flln{@@flln} % line
-% \def\??flsh{@@flsh} % shape
-% \def\??flfc{@@flfc} % focus
-% \def\??flst{@@flst} % sets
-% \def\??flsp{@@flsp} % split
-
-% \installsimplecommandhandler \??flch {FLOWchart} \??flch
-% \installsimplecommandhandler \??flln {FLOWline}  \??flln
-% \installsimplecommandhandler \??flsh {FLOWshape} \??flsh
-% \installsimplecommandhandler \??flfc {FLOWfocus} \??flfc
-% \installsimplecommandhandler \??flst {FLOWsets}  \??flst
-% \installsimplecommandhandler \??flsp {FLOWsplit} \??flsp
-
 \installcorenamespace {flowchart} % \def\??flch{@@flch} % chart
 \installcorenamespace {flowline}  % \def\??flln{@@flln} % line
 \installcorenamespace {flowshape} % \def\??flsh{@@flsh} % shape
@@ -97,7 +83,7 @@
    \c!radius=.375\bodyfontsize,
    \c!color=FLOWlinecolor,
    \c!rulethickness=.15\bodyfontsize,
-   \c!offset=\v!none]
+   \c!offset=\zeropoint]
 
 \setupFLOWshapes
   [\c!default=action,
diff --git a/tex/context/base/meta-pdf.lua b/tex/context/base/meta-pdf.lua
index 307779b16..7046f5311 100644
--- a/tex/context/base/meta-pdf.lua
+++ b/tex/context/base/meta-pdf.lua
@@ -13,7 +13,8 @@ if not modules then modules = { } end modules ['meta-pdf'] = {
 -- We can make it even more efficient if needed, but as we don't use this
 -- code often in \MKIV\ it makes no sense.
 
-local concat, format, gsub, find, byte, gmatch, match = table.concat, string.format, string.gsub, string.find, string.byte, string.gmatch, string.match
+local concat, unpack = table.concat, table.unpack
+local format, gsub, find, byte, gmatch, match = string.format, string.gsub, string.find, string.byte, string.gmatch, string.match
 local lpegmatch = lpeg.match
 local round = math.round
 
@@ -79,7 +80,7 @@ end
 
 local function flushconcat()
     if m_stack_concat then
-        mpscode(concat(m_stack_concat," ") .. " cm")
+        mpscode("%f %f %f %f %f %f cm",unpack(m_stack_concat)) -- no %s due to 1e-035 issues
         m_stack_concat = nil
     end
 end
diff --git a/tex/context/base/mlib-pps.lua b/tex/context/base/mlib-pps.lua
index 21b6657de..4756690be 100644
--- a/tex/context/base/mlib-pps.lua
+++ b/tex/context/base/mlib-pps.lua
@@ -15,6 +15,8 @@ local insert, concat = table.insert, table.concat
 local Cs, Cf, C, Cg, Ct, P, S, V, Carg = lpeg.Cs, lpeg.Cf, lpeg.C, lpeg.Cg, lpeg.Ct, lpeg.P, lpeg.S, lpeg.V, lpeg.Carg
 local lpegmatch = lpeg.match
 
+local formatters = string.formatters
+
 local mplib, metapost, lpdf, context = mplib, metapost, lpdf, context
 
 local texbox               = tex.box
@@ -80,14 +82,21 @@ function metapost.setoutercolor(mode,colormodel,colorattribute,transparencyattri
     innertransparency = outertransparency -- not yet used
 end
 
-local function checked_color_pair(color)
+local f_gray  = formatters["%.3f g %.3f G"]
+local f_rgb   = formatters["%.3f %.3f %.3f rg %.3f %.3f %.3f RG"]
+local f_cmyk  = formatters["%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K"]
+local f_cm    = formatters["q %f %f %f %f %f %f cm"]
+local f_shade = formatters["MpSh%s"]
+
+local function checked_color_pair(color,...)
     if not color then
         return innercolor, outercolor
-    elseif outercolormode == 3 then
-        innercolor = color
+    end
+    if outercolormode == 3 then
+        innercolor = color(...)
         return innercolor, innercolor
     else
-        return color, outercolor
+        return color(...), outercolor
     end
 end
 
@@ -142,7 +151,7 @@ local commasplitter = lpeg.tsplitat(",")
 
 local function checkandconvertspot(n_a,f_a,c_a,v_a,n_b,f_b,c_b,v_b)
     -- must be the same but we don't check
-    local name = format("MpSh%s",nofshades)
+    local name = f_shade(nofshades)
     local ca = lpegmatch(commasplitter,v_a)
     local cb = lpegmatch(commasplitter,v_b)
     if #ca == 0 or #cb == 0 then
@@ -156,7 +165,7 @@ local function checkandconvertspot(n_a,f_a,c_a,v_a,n_b,f_b,c_b,v_b)
 end
 
 local function checkandconvert(ca,cb)
-    local name = format("MpSh%s",nofshades)
+    local name = f_shade(nofshades)
     if not ca or not cb or type(ca) == "string" then
         return { 0 }, { 1 }, "DeviceGray", name
     else
@@ -257,32 +266,32 @@ function models.all(cr)
     elseif metapost.reducetogray then
         if n == 1 then
             local s = cr[1]
-            return checked_color_pair(format("%.3f g %.3f G",s,s))
+            return checked_color_pair(f_gray,s,s)
         elseif n == 3 then
             local r, g, b = cr[1], cr[2], cr[3]
             if r == g and g == b then
-                return checked_color_pair(format("%.3f g %.3f G",r,r))
+                return checked_color_pair(f_gray,r,r)
             else
-                return checked_color_pair(format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b))
+                return checked_color_pair(f_rgb,r,g,b,r,g,b)
             end
         else
             local c, m, y, k = cr[1], cr[2], cr[3], cr[4]
             if c == m and m == y and y == 0 then
                 k = 1 - k
-                return checked_color_pair(format("%.3f g %.3f G",k,k))
+                return checked_color_pair(f_gray,k,k)
             else
-                return checked_color_pair(format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k))
+                return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
             end
         end
     elseif n == 1 then
         local s = cr[1]
-        return checked_color_pair(format("%.3f g %.3f G",s,s))
+        return checked_color_pair(f_gray,s,s)
     elseif n == 3 then
         local r, g, b = cr[1], cr[2], cr[3]
-        return checked_color_pair(format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b))
+        return checked_color_pair(f_rgb,r,g,b,r,g,b)
     else
         local c, m, y, k = cr[1], cr[2], cr[3], cr[4]
-        return checked_color_pair(format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k))
+        return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
     end
 end
 
@@ -293,27 +302,27 @@ function models.rgb(cr)
     elseif metapost.reducetogray then
         if n == 1 then
             local s = cr[1]
-            checked_color_pair(format("%.3f g %.3f G",s,s))
+            checked_color_pair(f_gray,s,s)
         elseif n == 3 then
             local r, g, b = cr[1], cr[2], cr[3]
             if r == g and g == b then
-                return checked_color_pair(format("%.3f g %.3f G",r,r))
+                return checked_color_pair(f_gray,r,r)
             else
-                return checked_color_pair(format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b))
+                return checked_color_pair(f_rgb,r,g,b,r,g,b)
             end
         else
             local c, m, y, k = cr[1], cr[2], cr[3], cr[4]
             if c == m and m == y and y == 0 then
                 k = 1 - k
-                return checked_color_pair(format("%.3f g %.3f G",k,k))
+                return checked_color_pair(f_gray,k,k)
             else
                 local r, g, b = cmyktorgb(c,m,y,k)
-                return checked_color_pair(format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b))
+                return checked_color_pair(f_rgb,r,g,b,r,g,b)
             end
         end
     elseif n == 1 then
         local s = cr[1]
-        return checked_color_pair(format("%.3f g %.3f G",s,s))
+        return checked_color_pair(f_gray,s,s)
     else
         local r, g, b
         if n == 3 then
@@ -321,7 +330,7 @@ function models.rgb(cr)
         else
             r, g, b = cr[1], cr[2], cr[3]
         end
-        return checked_color_pair(format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b))
+        return checked_color_pair(f_rgb,r,g,b,r,g,b)
     end
 end
 
@@ -332,27 +341,27 @@ function models.cmyk(cr)
     elseif metapost.reducetogray then
         if n == 1 then
             local s = cr[1]
-            return checked_color_pair(format("%.3f g %.3f G",s,s))
+            return checked_color_pair(f_gray,s,s)
         elseif n == 3 then
             local r, g, b = cr[1], cr[2], cr[3]
             if r == g and g == b then
-                return checked_color_pair(format("%.3f g %.3f G",r,r))
+                return checked_color_pair(f_gray,r,r)
             else
                 local c, m, y, k = rgbtocmyk(r,g,b)
-                return checked_color_pair(format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k))
+                return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
             end
         else
             local c, m, y, k = cr[1], cr[2], cr[3], cr[4]
             if c == m and m == y and y == 0 then
-                k = 1 - k
-                return checked_color_pair(format("%.3f g %.3f G",k,k))
+                k = k - 1
+                return checked_color_pair(f_gray,k,k)
             else
-                return checked_color_pair(format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k))
+                return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
             end
         end
     elseif n == 1 then
         local s = cr[1]
-        return checked_color_pair(format("%.3f g %.3f G",s,s))
+        return checked_color_pair(f_gray,s,s)
     else
         local c, m, y, k
         if n == 3 then
@@ -360,7 +369,7 @@ function models.cmyk(cr)
         else
             c, m, y, k = cr[1], cr[2], cr[3], cr[4]
         end
-        return checked_color_pair(format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k))
+        return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
     end
 end
 
@@ -375,7 +384,7 @@ function models.gray(cr)
     else
         s = cr[1]
     end
-    return checked_color_pair(format("%.3f g %.3f G",s,s))
+    return checked_color_pair(f_gray,s,s)
 end
 
 setmetatableindex(models, function(t,k)
@@ -461,12 +470,13 @@ local function sxsy(wd,ht,dp) -- helper for text
     return (wd ~= 0 and factor/wd) or 0, (hd ~= 0 and factor/hd) or 0
 end
 
-local no_trial_run       = "mfun_trial_run := false ;"
-local do_trial_run       = "mfun_trial_run := true ;"
-local text_data_template = "mfun_tt_w[%i] := %f ; mfun_tt_h[%i] := %f ; mfun_tt_d[%i] := %f ;"
-local do_begin_fig       = "; beginfig(1) ; "
-local do_end_fig         = "; endfig ;"
-local do_safeguard       = ";"
+local no_trial_run = "mfun_trial_run := false ;"
+local do_trial_run = "mfun_trial_run := true ;"
+local do_begin_fig = "; beginfig(1) ; "
+local do_end_fig   = "; endfig ;"
+local do_safeguard = ";"
+
+local f_text_data  = formatters["mfun_tt_w[%i] := %f ; mfun_tt_h[%i] := %f ; mfun_tt_d[%i] := %f ;"]
 
 function metapost.textextsdata()
     local t, nt, n = { }, 0, 0
@@ -477,7 +487,7 @@ function metapost.textextsdata()
                 report_textexts("passed data %s: (%0.4f,%0.4f,%0.4f)",n,wd,ht,dp)
             end
             nt = nt + 1
-            t[nt] = format(text_data_template,n,wd,n,ht,n,dp)
+            t[nt] = f_text_data(n,wd,n,ht,n,dp)
         else
             break
         end
@@ -827,14 +837,21 @@ local function tx_process(object,prescript,before,after)
             if trace_textexts then
                 report_textexts("processing %s (second pass)",tx_number)
             end
-        --  before[#before+1] = format("q %f %f %f %f %f %f cm",cm(object))
+        --  before[#before+1] = f_cm(cm(object))
             local sx,rx,ry,sy,tx,ty = cm(object)
             before[#before+1] = function()
                 -- flush always happens, we can have a special flush function injected before
                 local box = textexts[tx_number]
                 if box then
                 --  context.MPLIBgettextscaled(tx_number,sxsy(box.width,box.height,box.depth))
-                    context.MPLIBgettextscaledcm(tx_number,sx,rx,ry,sy,tx,ty,sxsy(box.width,box.height,box.depth))
+                    context.MPLIBgettextscaledcm(tx_number,
+                        format("%f",sx), -- bah ... %s no longer checks
+                        format("%f",rx), -- bah ... %s no longer checks
+                        format("%f",ry), -- bah ... %s no longer checks
+                        format("%f",sy), -- bah ... %s no longer checks
+                        format("%f",tx), -- bah ... %s no longer checks
+                        format("%f",ty), -- bah ... %s no longer checks
+                        sxsy(box.width,box.height,box.depth))
                 else
                     report_textexts("unknown %s",tx_number)
                 end
@@ -952,7 +969,7 @@ end
 local function bm_process(object,prescript,before,after)
     local bm_xresolution = prescript.bm_xresolution
     if bm_xresolution then
-        before[#before+1] = format("q %f %f %f %f %f %f cm",cm(object))
+        before[#before+1] = f_cm(cm(object))
         before[#before+1] = function()
             figures.bitmapimage {
                 xresolution = tonumber(bm_xresolution),
@@ -992,7 +1009,7 @@ end
 local function fg_process(object,prescript,before,after)
     local fg_name = prescript.fg_name
     if fg_name then
-        before[#before+1] = format("q %f %f %f %f %f %f cm",cm(object)) -- beware: does not use the cm stack
+        before[#before+1] = f_cm(cm(object)) -- beware: does not use the cm stack
         before[#before+1] = function()
             context.MPLIBfigure(fg_name,prescript.fg_mask or "")
         end
@@ -1062,16 +1079,16 @@ local function tr_process(object,prescript,before,after)
                 local f = cs[1]
                 if colorspace == 2 then
                     local s = f*v[2]
-                    c_b, c_a = checked_color_pair(format("%.3f g %.3f G",s,s))
+                    c_b, c_a = checked_color_pair(f_gray,s,s)
                 elseif colorspace == 3 then
                     local r, g, b = f*v[3], f*v[4], f*v[5]
-                    c_b, c_a = checked_color_pair(format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b))
+                    c_b, c_a = checked_color_pair(f_rgb,r,g,b,r,g,b)
                 elseif colorspace == 4 or colorspace == 1 then
                     local c, m, y, k = f*v[6], f*v[7], f*v[8], f*v[9]
-                    c_b, c_a = checked_color_pair(format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k))
+                    c_b, c_a = checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
                 else
                     local s = f*v[2]
-                    c_b, c_a = checked_color_pair(format("%.3f g %.3f G",s,s))
+                    c_b, c_a = checked_color_pair(f_gray,s,s)
                 end
             end
             --
diff --git a/tex/context/base/mlib-pps.mkiv b/tex/context/base/mlib-pps.mkiv
index 704c9e635..3ecabc1c3 100644
--- a/tex/context/base/mlib-pps.mkiv
+++ b/tex/context/base/mlib-pps.mkiv
@@ -60,7 +60,7 @@
 \def\MPLIBgettextscaledcm#1#2#3#4#5#6#7#8#9% 2-7: sx,rx,ry,sy,tx,ty
   {\ctxlua{metapost.gettext(\number\MPtextbox,#1)}%
    \setbox\MPbox\hbox\bgroup
-     \dotransformnextbox{#2}{#3}{#4}{#5}{#6}{#7}% does push pop
+     \dotransformnextbox{#2}{#3}{#4}{#5}{#6}{#7}% does push pop ... will be changed to proper lua call (avoid small numbers)
        \vbox to \zeropoint\bgroup
           \vss
           \hbox to \zeropoint \bgroup
diff --git a/tex/context/base/s-abr-01.tex b/tex/context/base/s-abr-01.tex
index 019a7b2fb..68cdea6f0 100644
--- a/tex/context/base/s-abr-01.tex
+++ b/tex/context/base/s-abr-01.tex
@@ -136,6 +136,7 @@
 \logo [JAVASCRIPT]    {Java\-Script}
 \logo [JPEG]          {jpeg}
 \logo [JPG]           {jpg}
+\logo [JBIG]          {jbig}
 \logo [KPATHSEA]      {kpathsea}
 \logo [KPSE]          {kpse}
 \logo [KPSEWHICH]     {kpsewhich}
diff --git a/tex/context/base/s-abr-04.tex b/tex/context/base/s-abr-04.tex
index bcc2c8265..0725bcdcf 100644
--- a/tex/context/base/s-abr-04.tex
+++ b/tex/context/base/s-abr-04.tex
@@ -123,6 +123,7 @@
 \logo [JAVASCRIPT] {Java\-Script}
 \logo [JPEG]       {jpeg}
 \logo [JPG]        {jpg}
+\logo [JBIG]       {jbig}
 \logo [KPATHSEA]   {kpathsea}
 \logo [KPSE]       {kpse}
 \logo [KPSEWHICH]  {kpsewhich}
diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf
index 43c9014a6..95940634b 100644
Binary files a/tex/context/base/status-files.pdf and b/tex/context/base/status-files.pdf differ
diff --git a/tex/context/base/status-lua.pdf b/tex/context/base/status-lua.pdf
index 588c718a3..3563789f6 100644
Binary files a/tex/context/base/status-lua.pdf and b/tex/context/base/status-lua.pdf differ
diff --git a/tex/context/base/strc-lst.lua b/tex/context/base/strc-lst.lua
index 13ea04489..115b58063 100644
--- a/tex/context/base/strc-lst.lua
+++ b/tex/context/base/strc-lst.lua
@@ -249,7 +249,7 @@ local function filtercollected(names, criterium, number, collected, forced, nest
     if block == "" then
         block = false
     end
---~ print(">>",block,criterium)
+-- print(">>",block,criterium)
     --
     forced = forced or { } -- todo: also on other branched, for the moment only needed for bookmarks
     if type(names) == "string" then
@@ -274,7 +274,7 @@ local function filtercollected(names, criterium, number, collected, forced, nest
         for i=1,#collected do
             local v = collected[i]
             local r = v.references
-            if r then
+            if r and (not block or not r.block or block == r.block) then
                 local metadata = v.metadata
                 if metadata then
                     local name = metadata.name or false
diff --git a/tex/context/base/trac-log.lua b/tex/context/base/trac-log.lua
index 6c8213099..40d2860be 100644
--- a/tex/context/base/trac-log.lua
+++ b/tex/context/base/trac-log.lua
@@ -19,6 +19,7 @@ local texcount = tex and tex.count
 local next, type, select = next, type, select
 
 local setmetatableindex = table.setmetatableindex
+local formatters        = string.formatters
 
 --[[ldx--
 <p>This is a prelude to a more extensive logging module. We no longer
@@ -65,61 +66,76 @@ if tex and (tex.jobname or tex.formatname) then
         write_nl(target,"\n")
     end
 
+    local f_one = formatters["%-15s > %s\n"]
+    local f_two = formatters["%-15s >\n"]
+
     report = function(a,b,c,...)
         if c then
-            write_nl(target,format("%-15s > %s\n",translations[a],format(formats[b],c,...)))
+            write_nl(target,f_one(translations[a],format(formats[b],c,...)))
         elseif b then
-            write_nl(target,format("%-15s > %s\n",translations[a],formats[b]))
+            write_nl(target,f_one(translations[a],formats[b]))
         elseif a then
-            write_nl(target,format("%-15s >\n",   translations[a]))
+            write_nl(target,f_two(translations[a]))
         else
             write_nl(target,"\n")
         end
     end
 
+    local f_one = formatters["%-15s > %s"]
+    local f_two = formatters["%-15s >"]
+
     direct = function(a,b,c,...)
         if c then
-            return format("%-15s > %s",translations[a],format(formats[b],c,...))
+            return f_one(translations[a],format(formats[b],c,...))
         elseif b then
-            return format("%-15s > %s",translations[a],formats[b])
+            return f_one(translations[a],formats[b])
         elseif a then
-            return format("%-15s >",   translations[a])
+            return f_two(translations[a])
         else
             return ""
         end
     end
 
+    local f_one = formatters["%-15s > %s > %s\n"]
+    local f_two = formatters["%-15s > %s >\n"]
+
     subreport = function(a,s,b,c,...)
         if c then
-            write_nl(target,format("%-15s > %s > %s\n",translations[a],translations[s],format(formats[b],c,...)))
+            write_nl(target,f_one(translations[a],translations[s],format(formats[b],c,...)))
         elseif b then
-            write_nl(target,format("%-15s > %s > %s\n",translations[a],translations[s],formats[b]))
+            write_nl(target,f_one(translations[a],translations[s],formats[b]))
         elseif a then
-            write_nl(target,format("%-15s > %s >\n",   translations[a],translations[s]))
+            write_nl(target,f_two(translations[a],translations[s]))
         else
             write_nl(target,"\n")
         end
     end
 
+    local f_one = formatters["%-15s > %s > %s"]
+    local f_two = formatters["%-15s > %s >"]
+
     subdirect = function(a,s,b,c,...)
         if c then
-            return format("%-15s > %s > %s",translations[a],translations[s],format(formats[b],c,...))
+            return f_one(translations[a],translations[s],format(formats[b],c,...))
         elseif b then
-            return format("%-15s > %s > %s",translations[a],translations[s],formats[b])
+            return f_one(translations[a],translations[s],formats[b])
         elseif a then
-            return format("%-15s > %s >",   translations[a],translations[s])
+            return f_two(translations[a],translations[s])
         else
             return ""
         end
     end
 
+    local f_one = formatters["%-15s : %s\n"]
+    local f_two = formatters["%-15s :\n"]
+
     status = function(a,b,c,...)
         if c then
-            write_nl(target,format("%-15s : %s\n",translations[a],format(formats[b],c,...)))
+            write_nl(target,f_one(translations[a],format(formats[b],c,...)))
         elseif b then
-            write_nl(target,format("%-15s : %s\n",translations[a],formats[b]))
+            write_nl(target,f_one(translations[a],formats[b]))
         elseif a then
-            write_nl(target,format("%-15s :\n",   translations[a]))
+            write_nl(target,f_two(translations[a]))
         else
             write_nl(target,"\n")
         end
@@ -174,37 +190,46 @@ else
         write_nl("\n")
     end
 
+    local f_one = formatters["%-15s | %s"]
+    local f_two = formatters["%-15s |"]
+
     report = function(a,b,c,...)
         if c then
-            write_nl(format("%-15s | %s",a,format(b,c,...)))
+            write_nl(f_one(a,format(b,c,...)))
         elseif b then
-            write_nl(format("%-15s | %s",a,b))
+            write_nl(f_one(a,b))
         elseif a then
-            write_nl(format("%-15s |",   a))
+            write_nl(f_two(a))
         else
             write_nl("")
         end
     end
 
+    local f_one = formatters["%-15s | %s | %s"]
+    local f_two = formatters["%-15s | %s |"]
+
     subreport = function(a,sub,b,c,...)
         if c then
-            write_nl(format("%-15s | %s | %s",a,sub,format(b,c,...)))
+            write_nl(f_one(a,sub,format(b,c,...)))
         elseif b then
-            write_nl(format("%-15s | %s | %s",a,sub,b))
+            write_nl(f_one(a,sub,b))
         elseif a then
-            write_nl(format("%-15s | %s |",   a,sub))
+            write_nl(f_two(a,sub))
         else
             write_nl("")
         end
     end
 
+    local f_one = formatters["%-15s : %s\n"]
+    local f_two = formatters["%-15s :\n"]
+
     status = function(a,b,c,...) -- not to be used in lua anyway
         if c then
-            write_nl(format("%-15s : %s\n",a,format(b,c,...)))
+            write_nl(f_one(a,format(b,c,...)))
         elseif b then
-            write_nl(format("%-15s : %s\n",a,b)) -- b can have %'s
+            write_nl(f_one(a,b)) -- b can have %'s
         elseif a then
-            write_nl(format("%-15s :\n",   a))
+            write_nl(f_two(a))
         else
             write_nl("\n")
         end
diff --git a/tex/context/base/typo-mar.lua b/tex/context/base/typo-mar.lua
index 9252ef874..db8508a4a 100644
--- a/tex/context/base/typo-mar.lua
+++ b/tex/context/base/typo-mar.lua
@@ -36,11 +36,11 @@ if not modules then modules = { } end modules ['typo-mar'] = {
 --     if not w then
 --         -- error
 --     elseif how == "horizontal" or how == "h" then
---         pdfprint("page",format(" q 1 0 0 1 %s 0 cm ", (w[1] - pdf.h) * factor))
+--         pdfprint("page",format(" q 1 0 0 1 %f 0 cm ", (w[1] - pdf.h) * factor))
 --     elseif how == "vertical" or how == "v" then
---         pdfprint("page",format(" q 1 0 0 1 0 %s cm ", (w[2] - pdf.v) * factor))
+--         pdfprint("page",format(" q 1 0 0 1 0 %f cm ", (w[2] - pdf.v) * factor))
 --     else
---         pdfprint("page",format(" q 1 0 0 1 %s %s cm ", (w[1] - pdf.h) * factor, (w[2] - pdf.v) * factor))
+--         pdfprint("page",format(" q 1 0 0 1 %f %f cm ", (w[1] - pdf.h) * factor, (w[2] - pdf.v) * factor))
 --     end
 -- end
 --
diff --git a/tex/context/base/util-str.lua b/tex/context/base/util-str.lua
index 377dd163f..bade3493a 100644
--- a/tex/context/base/util-str.lua
+++ b/tex/context/base/util-str.lua
@@ -10,9 +10,27 @@ utilities         = utilities or {}
 utilities.strings = utilities.strings or { }
 local strings     = utilities.strings
 
-local gsub, rep = string.gsub, string.rep
-local Cs, C, Cp, P, Carg = lpeg.Cs, lpeg.C, lpeg.Cp, lpeg.P, lpeg.Carg
+local load = load
+local format, gsub, rep, sub = string.format, string.gsub, string.rep, string.sub
+local concat = table.concat
+local P, V, C, S, R, Ct, Cs, Cp, Carg = lpeg.P, lpeg.V, lpeg.C, lpeg.S, lpeg.R, lpeg.Ct, lpeg.Cs, lpeg.Cp, lpeg.Carg
 local patterns, lpegmatch = lpeg.patterns, lpeg.match
+local utfchar, utfbyte = utf.char, utf.byte
+local setmetatableindex = table.setmetatableindex
+--
+
+local stripper = patterns.stripzeros
+
+local function points(n)
+    return (not n or n == 0) and "0pt" or lpegmatch(stripper,format("%.5fpt",n/65536))
+end
+
+local function basepoints(n)
+    return (not n or n == 0) and "0bp" or lpegmatch(stripper,format("%.5fbp", n*(7200/7227)/65536))
+end
+
+number.points     = points
+number.basepoints = basepoints
 
 -- str = " \n \ntest  \n test\ntest "
 -- print("["..string.gsub(string.collapsecrlf(str),"\n","+").."]")
@@ -47,17 +65,15 @@ function strings.newrepeater(str,offset)
         return t
     end
     t = { }
-    setmetatable(t, {
-        __index = function(t,k)
-            if not k then
-                return ""
-            end
-            local n = k + offset
-            local s = n > 0 and rep(str,n) or ""
-            t[k] = s
-            return s
+    setmetatableindex(t, function(t,k)
+        if not k then
+            return ""
         end
-    } )
+        local n = k + offset
+        local s = n > 0 and rep(str,n) or ""
+        t[k] = s
+        return s
+    end)
     s[offset] = t
     return t
 end
@@ -94,20 +110,20 @@ function strings.tabtospace(str,tab)
     return lpegmatch(pattern,str,1,tab or 7)
 end
 
---~ local t = {
---~     "1234567123456712345671234567",
---~     "\tb\tc",
---~     "a\tb\tc",
---~     "aa\tbb\tcc",
---~     "aaa\tbbb\tccc",
---~     "aaaa\tbbbb\tcccc",
---~     "aaaaa\tbbbbb\tccccc",
---~     "aaaaaa\tbbbbbb\tcccccc\n       aaaaaa\tbbbbbb\tcccccc",
---~     "one\n	two\nxxx	three\nxx	four\nx	five\nsix",
---~ }
---~ for k=1,#t do
---~     print(strings.tabtospace(t[k]))
---~ end
+-- local t = {
+--     "1234567123456712345671234567",
+--     "\tb\tc",
+--     "a\tb\tc",
+--     "aa\tbb\tcc",
+--     "aaa\tbbb\tccc",
+--     "aaaa\tbbbb\tcccc",
+--     "aaaaa\tbbbbb\tccccc",
+--     "aaaaaa\tbbbbbb\tcccccc\n       aaaaaa\tbbbbbb\tcccccc",
+--     "one\n	two\nxxx	three\nxx	four\nx	five\nsix",
+-- }
+-- for k=1,#t do
+--     print(strings.tabtospace(t[k]))
+-- end
 
 function strings.striplong(str) -- strips all leading spaces
     str = gsub(str,"^%s*","")
@@ -115,13 +131,288 @@ function strings.striplong(str) -- strips all leading spaces
     return str
 end
 
---~ local template = string.striplong([[
---~   aaaa
---~   bb
---~   cccccc
---~ ]])
+-- local template = string.striplong([[
+--   aaaa
+--   bb
+--   cccccc
+-- ]])
 
 function strings.nice(str)
     str = gsub(str,"[:%-+_]+"," ") -- maybe more
     return str
 end
+
+-- Work in progress. Interesting is that compared to the built-in this
+-- is faster in luatex than in luajittex where we have a comparable speed.
+
+local n = 0
+
+-- we are somewhat sloppy in parsing prefixes as it's not that critical
+--
+-- this does not work out ok:
+--
+-- function fnc(...) -- 1,2,3
+--     print(...,...,...) -- 1,1,1,2,3
+-- end
+
+local prefix_any = C((S("+- .") + R("09"))^0)
+local prefix_tab = C((1-R("az","AZ","09","%%"))^0)
+
+-- we've split all cases as then we can optimize them (let's omit the fuzzy u)
+
+local format_s = function(f)
+    n = n + 1
+    if f and f ~= "" then
+        return format("format('%%%ss',(select(%s,...)))",f,n)
+    else
+        return format("(select(%s,...))",n)
+    end
+end
+
+local format_q = function()
+    n = n + 1
+    return format("format('%%q',(select(%s,...)))",n) -- maybe an own lpeg
+end
+
+local format_i = function(f)
+    n = n + 1
+    if f and f ~= "" then
+        return format("format('%%%si',(select(%s,...)))",f,n)
+    else
+        return format("(select(%s,...))",n)
+    end
+end
+
+local format_d = format_i
+
+local format_f = function(f)
+    n = n + 1
+    return format("format('%%%sf',(select(%s,...)))",f,n)
+end
+
+local format_g = function(f)
+    n = n + 1
+    return format("format('%%%sg',(select(%s,...)))",f,n)
+end
+
+local format_G = function(f)
+    n = n + 1
+    return format("format('%%%sG',(select(%s,...)))",f,n)
+end
+
+local format_e = function(f)
+    n = n + 1
+    return format("format('%%%se',(select(%s,...)))",f,n)
+end
+
+local format_E = function(f)
+    n = n + 1
+    return format("format('%%%sE',(select(%s,...)))",f,n)
+end
+
+local format_x = function(f)
+    n = n + 1
+    return format("format('%%%sx',(select(%s,...)))",f,n)
+end
+
+local format_X = function(f)
+    n = n + 1
+    return format("format('%%%sX',(select(%s,...)))",f,n)
+end
+
+local format_o = function(f)
+    n = n + 1
+    return format("format('%%%so',(select(%s,...)))",f,n)
+end
+
+local format_c = function()
+    n = n + 1
+    return format("utfchar((select(%s,...)))",n)
+end
+
+local format_r = function(f)
+    n = n + 1
+    return format("format('%%%s.0f',(select(%s,...)))",f,n)
+end
+
+local format_v = function(f)
+    n = n + 1
+    if f == "-" then
+        f = sub(f,2)
+        return format("format('%%%sx',utfbyte((select(%s,...))))",f == "" and "05" or f,n)
+    else
+        return format("format('0x%%%sx',utfbyte((select(%s,...))))",f == "" and "05" or f,n)
+    end
+end
+
+local format_V = function(f)
+    n = n + 1
+    if f == "-" then
+        f = sub(f,2)
+        return format("format('%%%sX',utfbyte((select(%s,...))))",f == "" and "05" or f,n)
+    else
+        return format("format('0x%%%sX',utfbyte((select(%s,...))))",f == "" and "05" or f,n)
+    end
+end
+
+local format_u = function(f)
+    n = n + 1
+    if f == "-" then
+        f = sub(f,2)
+        return format("format('%%%sx',utfbyte((select(%s,...))))",f == "" and "05" or f,n)
+    else
+        return format("format('u+%%%sx',utfbyte((select(%s,...))))",f == "" and "05" or f,n)
+    end
+end
+
+local format_U = function(f)
+    n = n + 1
+    if f == "-" then
+        f = sub(f,2)
+        return format("format('%%%sX',utfbyte((select(%s,...))))",f == "" and "05" or f,n)
+    else
+        return format("format('U+%%%sX',utfbyte((select(%s,...))))",f == "" and "05" or f,n)
+    end
+end
+
+local format_p = function()
+    n = n + 1
+    return format("points((select(%s,...)))",n)
+end
+
+local format_b = function()
+    n = n + 1
+    return format("basepoints((select(%s,...)))",n)
+end
+
+local format_t = function(f)
+    n = n + 1
+    if f and f ~= "" then
+        return format("concat((select(%s,...)),%q)",n,f)
+    else
+        return format("concat((select(%s,...)))",n)
+    end
+end
+
+local format_l = function()
+    n = n + 1
+    return format("(select(%s,...) and 'true' or 'false')",n)
+end
+
+local format_a = function(s)
+    return format("%q",s)
+end
+
+local builder = Ct { "start",
+    start = (P("%") * (
+        V("s") + V("q")
+      + V("i") + V("d")
+      + V("f") + V("g") + V("G") + V("e") + V("E")
+      + V("x") + V("X") + V("o")
+      --
+      + V("c")
+      --
+      + V("r")
+      + V("v") + V("V") + V("u") + V("U")
+      + V("p") + V("b")
+      + V("t")
+      + V("l")
+    )
+      + V("a")
+    )^0,
+    --
+    ["s"] = (prefix_any * P("s")) / format_s, -- %s => regular %s (string)
+    ["q"] = (prefix_any * P("q")) / format_q, -- %q => regular %q (quoted string)
+    ["i"] = (prefix_any * P("i")) / format_i, -- %i => regular %i (integer)
+    ["d"] = (prefix_any * P("d")) / format_d, -- %d => regular %d (integer)
+    ["f"] = (prefix_any * P("f")) / format_f, -- %f => regular %f (float)
+    ["g"] = (prefix_any * P("g")) / format_g, -- %g => regular %g (float)
+    ["G"] = (prefix_any * P("G")) / format_G, -- %G => regular %G (float)
+    ["e"] = (prefix_any * P("e")) / format_e, -- %e => regular %e (float)
+    ["E"] = (prefix_any * P("E")) / format_E, -- %E => regular %E (float)
+    ["x"] = (prefix_any * P("x")) / format_x, -- %x => regular %x (hexadecimal)
+    ["X"] = (prefix_any * P("X")) / format_X, -- %X => regular %X (HEXADECIMAL)
+    ["o"] = (prefix_any * P("o")) / format_o, -- %o => regular %o (octal)
+    --
+    ["c"] = (prefix_any * P("c")) / format_c, -- %c => utf character (extension to regular)
+    --
+    ["r"] = (prefix_any * P("r")) / format_r, -- %r => round
+    ["v"] = (prefix_any * P("v")) / format_v, -- %v => 0x0a1b2 (when - no 0x)
+    ["V"] = (prefix_any * P("V")) / format_V, -- %V => 0x0A1B2 (when - no 0x)
+    ["u"] = (prefix_any * P("u")) / format_u, -- %u => u+0a1b2 (when - no u+)
+    ["U"] = (prefix_any * P("U")) / format_U, -- %U => U+0A1B2 (when - no U+)
+    ["p"] = (prefix_any * P("p")) / format_p, -- %p => 12.345pt / maybe: P (and more units)
+    ["b"] = (prefix_any * P("b")) / format_b, -- %b => 12.342bp / maybe: B (and more units)
+    ["t"] = (prefix_tab * P("t")) / format_t, -- %t => concat
+    ["l"] = (prefix_tab * P("l")) / format_l, -- %l => boolean
+    --
+    ["a"] = Cs(((1-P("%"))^1 + P("%%")/"%%")^1) / format_a, -- %a => text (including %%)
+}
+
+-- we can be clever and only alias what is needed
+
+local template = [[
+local format = string.format
+local concat = table.concat
+local points = number.points
+local basepoints = number.basepoints
+local utfchar = utf.char
+local utfbyte = utf.byte
+return function(...)
+    return %s
+end
+]]
+
+local function make(t,str)
+    n = 0
+    local p = lpegmatch(builder,str)
+-- inspect(p)
+    local c = format(template,concat(p,".."))
+-- inspect(c)
+    formatter = load(c)()
+    t[str] = formatter
+    return formatter
+end
+
+local formatters  = string.formatters or { }
+string.formatters = formatters
+
+setmetatableindex(formatters,make)
+
+function string.makeformatter(str)
+    return formatters[str]
+end
+
+function string.formatter(str,...)
+    return formatters[str](...)
+end
+
+-- local p1 = "%s test %f done %p and %c and %V or %+t or %%"
+-- local p2 = "%s test %f done %s and %s and 0x%05X or %s or %%"
+--
+-- local t = { 1,2,3,4 }
+-- local r = ""
+--
+-- local format, formatter, formatters  = string.format, string.formatter, string.formatters
+-- local utfchar, utfbyte, concat, points = utf.char, utf.byte, table.concat, number.points
+--
+-- local c = os.clock()
+-- local f = formatters[p1]
+-- for i=1,500000 do
+--  -- r = formatters[p1]("hans",123.45,123.45,123,"a",t)
+--     r = formatter(p1,"hans",123.45,123.45,123,"a",t)
+--  -- r = f("hans",123.45,123.45,123,"a",t)
+-- end
+-- print(os.clock()-c,r)
+--
+-- local c = os.clock()
+-- for i=1,500000 do
+--     r = format(p2,"hans",123.45,points(123.45),utfchar(123),utfbyte("a"),concat(t,"+"))
+-- end
+-- print(os.clock()-c,r)
+
+-- local f = format
+-- function string.format(fmt,...)
+--     print(fmt,...)
+--     return f(fmt,...)
+-- end
diff --git a/tex/context/base/util-tab.lua b/tex/context/base/util-tab.lua
index e3d6a9f7d..47e533fa4 100644
--- a/tex/context/base/util-tab.lua
+++ b/tex/context/base/util-tab.lua
@@ -236,6 +236,58 @@ local function fastserialize(t,r,outer) -- no mixes
     return r
 end
 
+-- local f_hashed_string  = formatters["[%q]=%q,"]
+-- local f_hashed_number  = formatters["[%q]=%s,"]
+-- local f_hashed_table   = formatters["[%q]="]
+-- local f_hashed_true    = formatters["[%q]=true,"]
+-- local f_hashed_false   = formatters["[%q]=false,"]
+--
+-- local f_indexed_string = formatters["%q,"]
+-- local f_indexed_number = formatters["%s,"]
+-- ----- f_indexed_true   = formatters["true,"]
+-- ----- f_indexed_false  = formatters["false,"]
+--
+-- local function fastserialize(t,r,outer) -- no mixes
+--     r[#r+1] = "{"
+--     local n = #t
+--     if n > 0 then
+--         for i=1,n do
+--             local v = t[i]
+--             local tv = type(v)
+--             if tv == "string" then
+--                 r[#r+1] = f_indexed_string(v)
+--             elseif tv == "number" then
+--                 r[#r+1] = f_indexed_number(v)
+--             elseif tv == "table" then
+--                 fastserialize(v,r)
+--             elseif tv == "boolean" then
+--              -- r[#r+1] = v and f_indexed_true(k) or f_indexed_false(k)
+--                 r[#r+1] = v and "true," or "false,"
+--             end
+--         end
+--     else
+--         for k, v in next, t do
+--             local tv = type(v)
+--             if tv == "string" then
+--                 r[#r+1] = f_hashed_string(k,v)
+--             elseif tv == "number" then
+--                 r[#r+1] = f_hashed_number(k,v)
+--             elseif tv == "table" then
+--                 r[#r+1] = f_hashed_table(k)
+--                 fastserialize(v,r)
+--             elseif tv == "boolean" then
+--                 r[#r+1] = v and f_hashed_true(k) or f_hashed_false(k)
+--             end
+--         end
+--     end
+--     if outer then
+--         r[#r+1] = "}"
+--     else
+--         r[#r+1] = "},"
+--     end
+--     return r
+-- end
+
 function table.fastserialize(t,prefix) -- so prefix should contain the =
     return concat(fastserialize(t,{ prefix or "return" },true))
 end
diff --git a/tex/context/base/x-calcmath.lua b/tex/context/base/x-calcmath.lua
index 707abe82a..e8656c78e 100644
--- a/tex/context/base/x-calcmath.lua
+++ b/tex/context/base/x-calcmath.lua
@@ -156,8 +156,8 @@ local function totex(str,mode)
     end
     -- parenthesis (optional)
     if mode == 2 then
-      str = gsub(str,"%(", "\\left\(")
-      str = gsub(str,"%)", "\\right\)")
+      str = gsub(str,"%(", "\\left(")
+      str = gsub(str,"%)", "\\right)")
     end
     -- csnames
     str = gsub(str,"(\\[A-Z]+)", lower)
diff --git a/tex/context/base/x-mathml.lua b/tex/context/base/x-mathml.lua
index f35251d37..9565057d0 100644
--- a/tex/context/base/x-mathml.lua
+++ b/tex/context/base/x-mathml.lua
@@ -13,7 +13,7 @@ local format, lower, find, gsub = string.format, string.lower, string.find, stri
 local strip = string.strip
 local xmlsprint, xmlcprint, xmltext, xmlcontent = xml.sprint, xml.cprint, xml.text, xml.content
 local getid = lxml.getid
-local utfchar. utfcharacters, utfvalues = utf.char, utf.characters, utf.values
+local utfchar, utfcharacters, utfvalues = utf.char, utf.characters, utf.values
 local lpegmatch = lpeg.match
 
 local mathml      = { }
diff --git a/tex/generic/context/luatex/luatex-basics-gen.lua b/tex/generic/context/luatex/luatex-basics-gen.lua
index 2f03efba8..e7e98154a 100644
--- a/tex/generic/context/luatex/luatex-basics-gen.lua
+++ b/tex/generic/context/luatex/luatex-basics-gen.lua
@@ -74,32 +74,42 @@ texconfig.kpse_init = true
 resolvers = resolvers or { } -- no fancy file helpers used
 
 local remapper = {
-    otf   = "opentype fonts",
-    ttf   = "truetype fonts",
-    ttc   = "truetype fonts",
-    dfont = "truetype fonts", -- "truetype dictionary",
-    cid   = "cid maps",
-    fea   = "font feature files",
-    pfa   = "type1 fonts", -- this is for Khaled, in ConTeXt we don't use this!
-    pfb   = "type1 fonts", -- this is for Khaled, in ConTeXt we don't use this!
+    otf    = "opentype fonts",
+    ttf    = "truetype fonts",
+    ttc    = "truetype fonts",
+    dfont  = "truetype fonts", -- "truetype dictionary",
+    cid    = "cid maps",
+    cidmap = "cid maps",
+    fea    = "font feature files",
+    pfa    = "type1 fonts", -- this is for Khaled, in ConTeXt we don't use this!
+    pfb    = "type1 fonts", -- this is for Khaled, in ConTeXt we don't use this!
 }
 
 function resolvers.findfile(name,fileformat)
-    name = string.gsub(name,"\\","\/")
-    fileformat = fileformat and string.lower(fileformat)
-    local found = kpse.find_file(name,(fileformat and fileformat ~= "" and (remapper[fileformat] or fileformat)) or file.suffix(name,"tex"))
+    name = string.gsub(name,"\\","/")
+    if not fileformat or fileformat == "" then
+        fileformat = file.suffix(name)
+        if fileformat == "" then
+            fileformat = "tex"
+        end
+    end
+    fileformat = string.lower(fileformat)
+    fileformat = remapper[fileformat] or fileformat
+    local found = kpse.find_file(name,fileformat)
     if not found or found == "" then
         found = kpse.find_file(name,"other text files")
     end
     return found
 end
 
-function resolvers.findbinfile(name,fileformat)
-    if not fileformat or fileformat == "" then
-        fileformat = file.suffix(name) -- string.match(name,"%.([^%.]-)$")
-    end
-    return resolvers.findfile(name,(fileformat and remapper[fileformat]) or fileformat)
-end
+-- function resolvers.findbinfile(name,fileformat)
+--     if not fileformat or fileformat == "" then
+--         fileformat = file.suffix(name)
+--     end
+--     return resolvers.findfile(name,(fileformat and remapper[fileformat]) or fileformat)
+-- end
+
+resolvers.findbinfile = resolvers.findfile
 
 function resolvers.resolve(s)
     return s
diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua
index f302df378..66560b702 100644
--- a/tex/generic/context/luatex/luatex-fonts-merged.lua
+++ b/tex/generic/context/luatex/luatex-fonts-merged.lua
@@ -1,6 +1,6 @@
 -- merged file : luatex-fonts-merged.lua
 -- parent file : luatex-fonts.lua
--- merge date  : 12/25/12 15:14:15
+-- merge date  : 12/28/12 20:30:09
 
 do -- begin closure to overcome local limits and interference
 
@@ -2701,7 +2701,7 @@ io.readall = readall
 function io.loaddata(filename,textmode) -- return nil if empty
     local f = io.open(filename,(textmode and 'r') or 'rb')
     if f then
-     -- local data = f:read('*all')
+--       local data = f:read('*all')
         local data = readall(f)
         f:close()
         if #data > 0 then
@@ -2730,29 +2730,29 @@ end
 
 function io.loadlines(filename,n) -- return nil if empty
     local f = io.open(filename,'r')
-    if f then
-        if n then
-            local lines = { }
-            for i=1,n do
-                local line = f:read("*lines")
-                if line then
-                    lines[#lines+1] = line
-                else
-                    break
-                end
-            end
-            f:close()
-            lines = concat(lines,"\n")
-            if #lines > 0 then
-                return lines
-            end
-        else
-            local line = f:read("*line") or ""
-            assert(f:close())
-            if #line > 0 then
-                return line
+    if not f then
+        -- no file
+    elseif n then
+        local lines = { }
+        for i=1,n do
+            local line = f:read("*lines")
+            if line then
+                lines[#lines+1] = line
+            else
+                break
             end
         end
+        f:close()
+        lines = concat(lines,"\n")
+        if #lines > 0 then
+            return lines
+        end
+    else
+        local line = f:read("*line") or ""
+        f:close()
+        if #line > 0 then
+            return line
+        end
     end
 end
 
@@ -2772,7 +2772,7 @@ function io.exists(filename)
     if f == nil then
         return false
     else
-        assert(f:close())
+        f:close()
         return true
     end
 end
@@ -2783,7 +2783,7 @@ function io.size(filename)
         return 0
     else
         local s = f:seek("end")
-        assert(f:close())
+        f:close()
         return s
     end
 end
@@ -2791,9 +2791,13 @@ end
 function io.noflines(f)
     if type(f) == "string" then
         local f = io.open(filename)
-        local n = f and io.noflines(f) or 0
-        assert(f:close())
-        return n
+        if f then
+            local n = f and io.noflines(f) or 0
+            f:close()
+            return n
+        else
+            return 0
+        end
     else
         local n = 0
         for _ in f:lines() do
@@ -3077,32 +3081,42 @@ texconfig.kpse_init = true
 resolvers = resolvers or { } -- no fancy file helpers used
 
 local remapper = {
-    otf   = "opentype fonts",
-    ttf   = "truetype fonts",
-    ttc   = "truetype fonts",
-    dfont = "truetype fonts", -- "truetype dictionary",
-    cid   = "cid maps",
-    fea   = "font feature files",
-    pfa   = "type1 fonts", -- this is for Khaled, in ConTeXt we don't use this!
-    pfb   = "type1 fonts", -- this is for Khaled, in ConTeXt we don't use this!
+    otf    = "opentype fonts",
+    ttf    = "truetype fonts",
+    ttc    = "truetype fonts",
+    dfont  = "truetype fonts", -- "truetype dictionary",
+    cid    = "cid maps",
+    cidmap = "cid maps",
+    fea    = "font feature files",
+    pfa    = "type1 fonts", -- this is for Khaled, in ConTeXt we don't use this!
+    pfb    = "type1 fonts", -- this is for Khaled, in ConTeXt we don't use this!
 }
 
 function resolvers.findfile(name,fileformat)
-    name = string.gsub(name,"\\","\/")
-    fileformat = fileformat and string.lower(fileformat)
-    local found = kpse.find_file(name,(fileformat and fileformat ~= "" and (remapper[fileformat] or fileformat)) or file.suffix(name,"tex"))
+    name = string.gsub(name,"\\","/")
+    if not fileformat or fileformat == "" then
+        fileformat = file.suffix(name)
+        if fileformat == "" then
+            fileformat = "tex"
+        end
+    end
+    fileformat = string.lower(fileformat)
+    fileformat = remapper[fileformat] or fileformat
+    local found = kpse.find_file(name,fileformat)
     if not found or found == "" then
         found = kpse.find_file(name,"other text files")
     end
     return found
 end
 
-function resolvers.findbinfile(name,fileformat)
-    if not fileformat or fileformat == "" then
-        fileformat = file.suffix(name) -- string.match(name,"%.([^%.]-)$")
-    end
-    return resolvers.findfile(name,(fileformat and remapper[fileformat]) or fileformat)
-end
+-- function resolvers.findbinfile(name,fileformat)
+--     if not fileformat or fileformat == "" then
+--         fileformat = file.suffix(name)
+--     end
+--     return resolvers.findfile(name,(fileformat and remapper[fileformat]) or fileformat)
+-- end
+
+resolvers.findbinfile = resolvers.findfile
 
 function resolvers.resolve(s)
     return s
-- 
cgit v1.2.3