From 965214d981e6129b782c67adcaf3a81aedcb0bac Mon Sep 17 00:00:00 2001
From: Marius <mariausol@gmail.com>
Date: Sun, 20 Oct 2013 01:20:14 +0300
Subject: stable 2013.05.28 00:36

---
 tex/generic/context/luatex/luatex-basics-gen.lua   |   28 +-
 tex/generic/context/luatex/luatex-basics-nod.lua   |   79 +-
 tex/generic/context/luatex/luatex-fonts-merged.lua | 2938 +++++---------------
 tex/generic/context/luatex/luatex-fonts-syn.lua    |    4 -
 tex/generic/context/luatex/luatex-fonts.lua        |    8 +-
 tex/generic/context/luatex/luatex-test.tex         |    4 -
 6 files changed, 765 insertions(+), 2296 deletions(-)

(limited to 'tex/generic')

diff --git a/tex/generic/context/luatex/luatex-basics-gen.lua b/tex/generic/context/luatex/luatex-basics-gen.lua
index 9cf5b9317..4a46fbb07 100644
--- a/tex/generic/context/luatex/luatex-basics-gen.lua
+++ b/tex/generic/context/luatex/luatex-basics-gen.lua
@@ -89,7 +89,6 @@ local remapper = {
     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!
-    afm    = "afm",
 }
 
 function resolvers.findfile(name,fileformat)
@@ -118,11 +117,6 @@ end
 
 resolvers.findbinfile = resolvers.findfile
 
-function resolvers.loadbinfile(filename,filetype)
-    local data = io.loaddata(filename)
-    return true, data, #data
-end
-
 function resolvers.resolve(s)
     return s
 end
@@ -155,29 +149,19 @@ do
 
     local cachepaths = kpse.expand_var('$TEXMFCACHE') or ""
 
-    -- quite like tex live or so (the weird $TEXMFCACHE test seems to be needed on miktex)
+    -- quite like tex live or so
 
-    if cachepaths == "" or cachepaths == "$TEXMFCACHE" then
+    if cachepaths == "" then
         cachepaths = kpse.expand_var('$TEXMFVAR') or ""
     end
 
-    -- this also happened to be used (the weird $TEXMFVAR test seems to be needed on miktex)
+    -- this also happened to be used
 
-    if cachepaths == "" or cachepaths == "$TEXMFVAR" then
+    if cachepaths == "" then
         cachepaths = kpse.expand_var('$VARTEXMF') or ""
     end
 
-    -- and this is a last resort (hm, we could use TEMP or TEMPDIR)
-
-    if cachepaths == "" then
-        local fallbacks = { "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" }
-        for i=1,#fallbacks do
-            cachepaths = os.getenv(fallbacks[i]) or ""
-            if cachepath ~= "" and lfs.isdir(cachepath) then
-                break
-            end
-        end
-    end
+    -- and this is a last resort
 
     if cachepaths == "" then
         cachepaths = "."
@@ -283,7 +267,7 @@ function caches.savedata(path,name,data)
     local luaname, lucname = makefullname(path,name)
     if luaname then
         texio.write(string.format("(save: %s)",luaname))
-        table.tofile(luaname,data,true)
+        table.tofile(luaname,data,true,{ reduce = true })
         if lucname and type(caches.compile) == "function" then
             os.remove(lucname) -- better be safe
             texio.write(string.format("(save: %s)",lucname))
diff --git a/tex/generic/context/luatex/luatex-basics-nod.lua b/tex/generic/context/luatex/luatex-basics-nod.lua
index 50a1e8627..5ab9df7f9 100644
--- a/tex/generic/context/luatex/luatex-basics-nod.lua
+++ b/tex/generic/context/luatex/luatex-basics-nod.lua
@@ -88,80 +88,17 @@ function nodes.delete(head,current)
     return nodes.remove(head,current,true)
 end
 
+nodes.before = node.insert_before
+nodes.after  = node.insert_after
+
 function nodes.pool.kern(k)
     local n = new_node("kern",1)
     n.kern = k
     return n
 end
 
--- experimental
-
-local getfield = node.getfield or function(n,tag)       return n[tag]  end
-local setfield = node.setfield or function(n,tag,value) n[tag] = value end
-
-nodes.getfield = getfield
-nodes.setfield = setfield
-
-nodes.getattr  = getfield
-nodes.setattr  = setfield
-
-if node.getid      then nodes.getid      = node.getid      else function nodes.getid     (n) return getfield(n,"id")      end end
-if node.getsubtype then nodes.getsubtype = node.getsubtype else function nodes.getsubtype(n) return getfield(n,"subtype") end end
-if node.getnext    then nodes.getnext    = node.getnext    else function nodes.getnext   (n) return getfield(n,"next")    end end
-if node.getprev    then nodes.getprev    = node.getprev    else function nodes.getprev   (n) return getfield(n,"prev")    end end
-if node.getchar    then nodes.getchar    = node.getchar    else function nodes.getchar   (n) return getfield(n,"char")    end end
-if node.getfont    then nodes.getfont    = node.getfont    else function nodes.getfont   (n) return getfield(n,"font")    end end
-if node.getlist    then nodes.getlist    = node.getlist    else function nodes.getlist   (n) return getfield(n,"list")    end end
-
-function nodes.tonut (n) return n end
-function nodes.tonode(n) return n end
-
--- being lazy ... just copy a bunch ... not all needed in generic but we assume
--- nodes to be kind of private anyway
-
-nodes.tostring             = node.tostring or tostring
-nodes.copy                 = node.copy
-nodes.copy_list            = node.copy_list
-nodes.delete               = node.delete
-nodes.dimensions           = node.dimensions
-nodes.end_of_math          = node.end_of_math
-nodes.flush_list           = node.flush_list
-nodes.flush_node           = node.flush_node
-nodes.free                 = node.free
-nodes.insert_after         = node.insert_after
-nodes.insert_before        = node.insert_before
-nodes.hpack                = node.hpack
-nodes.new                  = node.new
-nodes.tail                 = node.tail
-nodes.traverse             = node.traverse
-nodes.traverse_id          = node.traverse_id
-nodes.slide                = node.slide
-nodes.vpack                = node.vpack
-
-nodes.first_glyph          = node.first_glyph
-nodes.first_character      = node.first_character
-nodes.has_glyph            = node.has_glyph or node.first_glyph
-
-nodes.current_attr         = node.current_attr
-nodes.do_ligature_n        = node.do_ligature_n
-nodes.has_field            = node.has_field
-nodes.last_node            = node.last_node
-nodes.usedlist             = node.usedlist
-nodes.protrusion_skippable = node.protrusion_skippable
-nodes.write                = node.write
-
-nodes.has_attribute        = node.has_attribute
-nodes.set_attribute        = node.set_attribute
-nodes.unset_attribute      = node.unset_attribute
-
-nodes.protect_glyphs       = node.protect_glyphs
-nodes.unprotect_glyphs     = node.unprotect_glyphs
-nodes.kerning              = node.kerning
-nodes.ligaturing           = node.ligaturing
-nodes.mlist_to_hlist       = node.mlist_to_hlist
-
--- in generic code, at least for some time, we stay nodes, while in context
--- we can go nuts (e.g. experimental); this split permits us us keep code
--- used elsewhere stable but at the same time play around in context
-
-nodes.nuts = nodes
+function nodes.endofmath(n)
+    for n in traverse_id(math_code,n.next) do
+        return n
+    end
+end
diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua
index 8fe2ad9c1..cf5862ca9 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  : 10/15/13 13:52:35
+-- merge date  : 05/28/13 00:34:00
 
 do -- begin closure to overcome local limits and interference
 
@@ -95,7 +95,6 @@ if not modules then modules={} end modules ['l-lpeg']={
   license="see context related readme files"
 }
 lpeg=require("lpeg")
-if not lpeg.print then function lpeg.print(...) print(lpeg.pcode(...)) end end
 local type,next,tostring=type,next,tostring
 local byte,char,gmatch,format=string.byte,string.char,string.gmatch,string.format
 local floor=math.floor
@@ -111,46 +110,28 @@ patterns.anything=anything
 patterns.endofstring=endofstring
 patterns.beginofstring=alwaysmatched
 patterns.alwaysmatched=alwaysmatched
-local sign=S('+-')
-local zero=P('0')
-local digit=R('09')
-local octdigit=R("07")
-local lowercase=R("az")
-local uppercase=R("AZ")
-local underscore=P("_")
-local hexdigit=digit+lowercase+uppercase
+local digit,sign=R('09'),S('+-')
 local cr,lf,crlf=P("\r"),P("\n"),P("\r\n")
 local newline=crlf+S("\r\n") 
 local escaped=P("\\")*anything
 local squote=P("'")
 local dquote=P('"')
 local space=P(" ")
-local period=P(".")
-local comma=P(",")
-local utfbom_32_be=P('\000\000\254\255') 
-local utfbom_32_le=P('\255\254\000\000') 
-local utfbom_16_be=P('\254\255')     
-local utfbom_16_le=P('\255\254')     
-local utfbom_8=P('\239\187\191')   
+local utfbom_32_be=P('\000\000\254\255')
+local utfbom_32_le=P('\255\254\000\000')
+local utfbom_16_be=P('\255\254')
+local utfbom_16_le=P('\254\255')
+local utfbom_8=P('\239\187\191')
 local utfbom=utfbom_32_be+utfbom_32_le+utfbom_16_be+utfbom_16_le+utfbom_8
 local utftype=utfbom_32_be*Cc("utf-32-be")+utfbom_32_le*Cc("utf-32-le")+utfbom_16_be*Cc("utf-16-be")+utfbom_16_le*Cc("utf-16-le")+utfbom_8*Cc("utf-8")+alwaysmatched*Cc("utf-8") 
-local utfstricttype=utfbom_32_be*Cc("utf-32-be")+utfbom_32_le*Cc("utf-32-le")+utfbom_16_be*Cc("utf-16-be")+utfbom_16_le*Cc("utf-16-le")+utfbom_8*Cc("utf-8")
 local utfoffset=utfbom_32_be*Cc(4)+utfbom_32_le*Cc(4)+utfbom_16_be*Cc(2)+utfbom_16_le*Cc(2)+utfbom_8*Cc(3)+Cc(0)
 local utf8next=R("\128\191")
-patterns.utfbom_32_be=utfbom_32_be
-patterns.utfbom_32_le=utfbom_32_le
-patterns.utfbom_16_be=utfbom_16_be
-patterns.utfbom_16_le=utfbom_16_le
-patterns.utfbom_8=utfbom_8
-patterns.utf_16_be_nl=P("\000\r\000\n")+P("\000\r")+P("\000\n")
-patterns.utf_16_le_nl=P("\r\000\n\000")+P("\r\000")+P("\n\000")
 patterns.utf8one=R("\000\127")
 patterns.utf8two=R("\194\223")*utf8next
 patterns.utf8three=R("\224\239")*utf8next*utf8next
 patterns.utf8four=R("\240\244")*utf8next*utf8next*utf8next
 patterns.utfbom=utfbom
 patterns.utftype=utftype
-patterns.utfstricttype=utfstricttype
 patterns.utfoffset=utfoffset
 local utf8char=patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four
 local validutf8char=utf8char^0*endofstring*Cc(true)+Cc(false)
@@ -174,8 +155,23 @@ local stripper=spacer^0*C((spacer^0*nonspacer^1)^0)
 local collapser=Cs(spacer^0/""*nonspacer^0*((spacer^0/" "*nonspacer^1)^0))
 patterns.stripper=stripper
 patterns.collapser=collapser
-patterns.lowercase=lowercase
-patterns.uppercase=uppercase
+patterns.digit=digit
+patterns.sign=sign
+patterns.cardinal=sign^0*digit^1
+patterns.integer=sign^0*digit^1
+patterns.unsigned=digit^0*P('.')*digit^1
+patterns.float=sign^0*patterns.unsigned
+patterns.cunsigned=digit^0*P(',')*digit^1
+patterns.cfloat=sign^0*patterns.cunsigned
+patterns.number=patterns.float+patterns.integer
+patterns.cnumber=patterns.cfloat+patterns.integer
+patterns.oct=P("0")*R("07")^1
+patterns.octal=patterns.oct
+patterns.HEX=P("0x")*R("09","AF")^1
+patterns.hex=P("0x")*R("09","af")^1
+patterns.hexadecimal=P("0x")*R("09","AF","af")^1
+patterns.lowercase=R("az")
+patterns.uppercase=R("AZ")
 patterns.letter=patterns.lowercase+patterns.uppercase
 patterns.space=space
 patterns.tab=P("\t")
@@ -183,12 +179,12 @@ patterns.spaceortab=patterns.space+patterns.tab
 patterns.newline=newline
 patterns.emptyline=newline^1
 patterns.equal=P("=")
-patterns.comma=comma
-patterns.commaspacer=comma*spacer^0
-patterns.period=period
+patterns.comma=P(",")
+patterns.commaspacer=P(",")*spacer^0
+patterns.period=P(".")
 patterns.colon=P(":")
 patterns.semicolon=P(";")
-patterns.underscore=underscore
+patterns.underscore=P("_")
 patterns.escaped=escaped
 patterns.squote=squote
 patterns.dquote=dquote
@@ -201,29 +197,10 @@ patterns.unspacer=((patterns.spacer^1)/"")^0
 patterns.singlequoted=squote*patterns.nosquote*squote
 patterns.doublequoted=dquote*patterns.nodquote*dquote
 patterns.quoted=patterns.doublequoted+patterns.singlequoted
-patterns.digit=digit
-patterns.octdigit=octdigit
-patterns.hexdigit=hexdigit
-patterns.sign=sign
-patterns.cardinal=digit^1
-patterns.integer=sign^-1*digit^1
-patterns.unsigned=digit^0*period*digit^1
-patterns.float=sign^-1*patterns.unsigned
-patterns.cunsigned=digit^0*comma*digit^1
-patterns.cfloat=sign^-1*patterns.cunsigned
-patterns.number=patterns.float+patterns.integer
-patterns.cnumber=patterns.cfloat+patterns.integer
-patterns.oct=zero*octdigit^1
-patterns.octal=patterns.oct
-patterns.HEX=zero*P("X")*(digit+uppercase)^1
-patterns.hex=zero*P("x")*(digit+lowercase)^1
-patterns.hexadecimal=zero*S("xX")*hexdigit^1
-patterns.hexafloat=sign^-1*zero*S("xX")*(hexdigit^0*period*hexdigit^1+hexdigit^1*period*hexdigit^0+hexdigit^1)*(S("pP")*sign^-1*hexdigit^1)^-1
-patterns.decafloat=sign^-1*(digit^0*period*digit^1+digit^1*period*digit^0+digit^1)*S("eE")*sign^-1*digit^1
-patterns.propername=(uppercase+lowercase+underscore)*(uppercase+lowercase+underscore+digit)^0*endofstring
+patterns.propername=R("AZ","az","__")*R("09","AZ","az","__")^0*P(-1)
 patterns.somecontent=(anything-newline-space)^1 
 patterns.beginline=#(1-newline)
-patterns.longtostring=Cs(whitespace^0/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(P(-1)+Cc(" ")))^0))
+patterns.longtostring=Cs(whitespace^0/""*nonwhitespace^0*((whitespace^0/" "*(patterns.quoted+nonwhitespace)^1)^0))
 local function anywhere(pattern) 
   return P { P(pattern)+1*V(1) }
 end
@@ -395,7 +372,7 @@ function lpeg.replacer(one,two,makefunction,isutf)
     return pattern
   end
 end
-function lpeg.finder(lst,makefunction) 
+function lpeg.finder(lst,makefunction)
   local pattern
   if type(lst)=="table" then
     pattern=P(false)
@@ -424,8 +401,8 @@ local splitters_f,splitters_s={},{}
 function lpeg.firstofsplit(separator) 
   local splitter=splitters_f[separator]
   if not splitter then
-    local pattern=P(separator)
-    splitter=C((1-pattern)^0)
+    separator=P(separator)
+    splitter=C((1-separator)^0)
     splitters_f[separator]=splitter
   end
   return splitter
@@ -433,31 +410,12 @@ end
 function lpeg.secondofsplit(separator) 
   local splitter=splitters_s[separator]
   if not splitter then
-    local pattern=P(separator)
-    splitter=(1-pattern)^0*pattern*C(anything^0)
-    splitters_s[separator]=splitter
-  end
-  return splitter
-end
-local splitters_s,splitters_p={},{}
-function lpeg.beforesuffix(separator) 
-  local splitter=splitters_s[separator]
-  if not splitter then
-    local pattern=P(separator)
-    splitter=C((1-pattern)^0)*pattern*endofstring
+    separator=P(separator)
+    splitter=(1-separator)^0*separator*C(anything^0)
     splitters_s[separator]=splitter
   end
   return splitter
 end
-function lpeg.afterprefix(separator) 
-  local splitter=splitters_p[separator]
-  if not splitter then
-    local pattern=P(separator)
-    splitter=pattern*C(anything^0)
-    splitters_p[separator]=splitter
-  end
-  return splitter
-end
 function lpeg.balancer(left,right)
   left,right=P(left),P(right)
   return P { left*((1-left-right)+V(1))^0*right }
@@ -689,6 +647,9 @@ end
 function lpeg.times(pattern,n)
   return P(nextstep(n,2^16,{ "start",["1"]=pattern }))
 end
+local digit=R("09")
+local period=P(".")
+local zero=P("0")
 local trailingzeros=zero^0*-digit 
 local case_1=period*trailingzeros/""
 local case_2=period*(digit-trailingzeros)^1*(trailingzeros/"")
@@ -1076,7 +1037,6 @@ local noquotes,hexify,handle,reduce,compact,inline,functions
 local reserved=table.tohash { 
   'and','break','do','else','elseif','end','false','for','function','if',
   'in','local','nil','not','or','repeat','return','then','true','until','while',
-  'NaN','goto',
 }
 local function simple_table(t)
   if #t>0 then
@@ -1096,12 +1056,12 @@ local function simple_table(t)
           else
             tt[nt]=tostring(v) 
           end
+        elseif tv=="boolean" then
+          nt=nt+1
+          tt[nt]=tostring(v)
         elseif tv=="string" then
           nt=nt+1
           tt[nt]=format("%q",v)
-        elseif tv=="boolean" then
-          nt=nt+1
-          tt[nt]=v and "true" or "false"
         else
           tt=nil
           break
@@ -1134,7 +1094,7 @@ local function do_serialize(root,name,depth,level,indexed)
           handle(format("%s[%q]={",depth,name))
         end
       elseif tn=="boolean" then
-        handle(format("%s[%s]={",depth,name and "true" or "false"))
+        handle(format("%s[%s]={",depth,tostring(name)))
       else
         handle(format("%s{",depth))
       end
@@ -1158,21 +1118,21 @@ local function do_serialize(root,name,depth,level,indexed)
     for i=1,#sk do
       local k=sk[i]
       local v=root[k]
-      local tv,tk=type(v),type(k)
+      local t,tk=type(v),type(k)
       if compact and first and tk=="number" and k>=first and k<=last then
-        if tv=="number" then
+        if t=="number" then
           if hexify then
             handle(format("%s 0x%04X,",depth,v))
           else
             handle(format("%s %s,",depth,v)) 
           end
-        elseif tv=="string" then
+        elseif t=="string" then
           if reduce and tonumber(v) then
             handle(format("%s %s,",depth,v))
           else
             handle(format("%s %q,",depth,v))
           end
-        elseif tv=="table" then
+        elseif t=="table" then
           if not next(v) then
             handle(format("%s {},",depth))
           elseif inline then 
@@ -1185,11 +1145,11 @@ local function do_serialize(root,name,depth,level,indexed)
           else
             do_serialize(v,k,depth,level+1,true)
           end
-        elseif tv=="boolean" then
-          handle(format("%s %s,",depth,v and "true" or "false"))
-        elseif tv=="function" then
+        elseif t=="boolean" then
+          handle(format("%s %s,",depth,tostring(v)))
+        elseif t=="function" then
           if functions then
-            handle(format('%s load(%q),',depth,dump(v))) 
+            handle(format('%s load(%q),',depth,dump(v)))
           else
             handle(format('%s "function",',depth))
           end
@@ -1200,7 +1160,7 @@ local function do_serialize(root,name,depth,level,indexed)
         if false then
           handle(format("%s __p__=nil,",depth))
         end
-      elseif tv=="number" then
+      elseif t=="number" then
         if tk=="number" then
           if hexify then
             handle(format("%s [0x%04X]=0x%04X,",depth,k,v))
@@ -1209,9 +1169,9 @@ local function do_serialize(root,name,depth,level,indexed)
           end
         elseif tk=="boolean" then
           if hexify then
-            handle(format("%s [%s]=0x%04X,",depth,k and "true" or "false",v))
+            handle(format("%s [%s]=0x%04X,",depth,tostring(k),v))
           else
-            handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) 
+            handle(format("%s [%s]=%s,",depth,tostring(k),v)) 
           end
         elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
           if hexify then
@@ -1226,7 +1186,7 @@ local function do_serialize(root,name,depth,level,indexed)
             handle(format("%s [%q]=%s,",depth,k,v)) 
           end
         end
-      elseif tv=="string" then
+      elseif t=="string" then
         if reduce and tonumber(v) then
           if tk=="number" then
             if hexify then
@@ -1235,7 +1195,7 @@ local function do_serialize(root,name,depth,level,indexed)
               handle(format("%s [%s]=%s,",depth,k,v))
             end
           elseif tk=="boolean" then
-            handle(format("%s [%s]=%s,",depth,k and "true" or "false",v))
+            handle(format("%s [%s]=%s,",depth,tostring(k),v))
           elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
             handle(format("%s %s=%s,",depth,k,v))
           else
@@ -1249,14 +1209,14 @@ local function do_serialize(root,name,depth,level,indexed)
               handle(format("%s [%s]=%q,",depth,k,v))
             end
           elseif tk=="boolean" then
-            handle(format("%s [%s]=%q,",depth,k and "true" or "false",v))
+            handle(format("%s [%s]=%q,",depth,tostring(k),v))
           elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
             handle(format("%s %s=%q,",depth,k,v))
           else
             handle(format("%s [%q]=%q,",depth,k,v))
           end
         end
-      elseif tv=="table" then
+      elseif t=="table" then
         if not next(v) then
           if tk=="number" then
             if hexify then
@@ -1265,7 +1225,7 @@ local function do_serialize(root,name,depth,level,indexed)
               handle(format("%s [%s]={},",depth,k))
             end
           elseif tk=="boolean" then
-            handle(format("%s [%s]={},",depth,k and "true" or "false"))
+            handle(format("%s [%s]={},",depth,tostring(k)))
           elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
             handle(format("%s %s={},",depth,k))
           else
@@ -1281,7 +1241,7 @@ local function do_serialize(root,name,depth,level,indexed)
                 handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
               end
             elseif tk=="boolean" then
-              handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", ")))
+              handle(format("%s [%s]={ %s },",depth,tostring(k),concat(st,", ")))
             elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
               handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
             else
@@ -1293,21 +1253,21 @@ local function do_serialize(root,name,depth,level,indexed)
         else
           do_serialize(v,k,depth,level+1)
         end
-      elseif tv=="boolean" then
+      elseif t=="boolean" then
         if tk=="number" then
           if hexify then
-            handle(format("%s [0x%04X]=%s,",depth,k,v and "true" or "false"))
+            handle(format("%s [0x%04X]=%s,",depth,k,tostring(v)))
           else
-            handle(format("%s [%s]=%s,",depth,k,v and "true" or "false"))
+            handle(format("%s [%s]=%s,",depth,k,tostring(v)))
           end
         elseif tk=="boolean" then
-          handle(format("%s [%s]=%s,",depth,tostring(k),v and "true" or "false"))
+          handle(format("%s [%s]=%s,",depth,tostring(k),tostring(v)))
         elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
-          handle(format("%s %s=%s,",depth,k,v and "true" or "false"))
+          handle(format("%s %s=%s,",depth,k,tostring(v)))
         else
-          handle(format("%s [%q]=%s,",depth,k,v and "true" or "false"))
+          handle(format("%s [%q]=%s,",depth,k,tostring(v)))
         end
-      elseif tv=="function" then
+      elseif t=="function" then
         if functions then
           local f=getinfo(v).what=="C" and dump(dummy) or dump(v)
           if tk=="number" then
@@ -1317,7 +1277,7 @@ local function do_serialize(root,name,depth,level,indexed)
               handle(format("%s [%s]=load(%q),",depth,k,f))
             end
           elseif tk=="boolean" then
-            handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f))
+            handle(format("%s [%s]=load(%q),",depth,tostring(k),f))
           elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
             handle(format("%s %s=load(%q),",depth,k,f))
           else
@@ -1332,7 +1292,7 @@ local function do_serialize(root,name,depth,level,indexed)
             handle(format("%s [%s]=%q,",depth,k,tostring(v)))
           end
         elseif tk=="boolean" then
-          handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v)))
+          handle(format("%s [%s]=%q,",depth,tostring(k),tostring(v)))
         elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
           handle(format("%s %s=%q,",depth,k,tostring(v)))
         else
@@ -1702,7 +1662,6 @@ local function readall(f)
     return f:read('*all')
   else
     local done=f:seek("set",0)
-    local step
     if size<1024*1024 then
       step=1024*1024
     elseif size>16*1024*1024 then
@@ -2226,24 +2185,17 @@ end
 function file.joinpath(tab,separator) 
   return tab and concat(tab,separator or io.pathseparator) 
 end
-local someslash=S("\\/")
 local stripper=Cs(P(fwslash)^0/""*reslasher)
-local isnetwork=someslash*someslash*(1-someslash)+(1-fwslash-colon)^1*colon
+local isnetwork=fwslash*fwslash*(1-fwslash)+(1-fwslash-colon)^1*colon
 local isroot=fwslash^1*-1
 local hasroot=fwslash^1
-local reslasher=lpeg.replacer(S("\\/"),"/")
 local deslasher=lpeg.replacer(S("\\/")^1,"/")
 function file.join(...)
   local lst={... }
   local one=lst[1]
   if lpegmatch(isnetwork,one) then
-    local one=lpegmatch(reslasher,one)
     local two=lpegmatch(deslasher,concat(lst,"/",2))
-    if lpegmatch(hasroot,two) then
-      return one..two
-    else
-      return one.."/"..two
-    end
+    return one.."/"..two
   elseif lpegmatch(isroot,one) then
     local two=lpegmatch(deslasher,concat(lst,"/",2))
     if lpegmatch(hasroot,two) then
@@ -2260,9 +2212,7 @@ end
 local drivespec=R("az","AZ")^1*colon
 local anchors=fwslash+drivespec
 local untouched=periods+(1-period)^1*P(-1)
-local mswindrive=Cs(drivespec*(bwslash/"/"+fwslash)^0)
-local mswinuncpath=(bwslash+fwslash)*(bwslash+fwslash)*Cc("//")
-local splitstarter=(mswindrive+mswinuncpath+Cc(false))*Ct(lpeg.splitat(S("/\\")^1))
+local splitstarter=(Cs(drivespec*(bwslash/"/"+fwslash)^0)+Cc(false))*Ct(lpeg.splitat(S("/\\")^1))
 local absolute=fwslash
 function file.collapsepath(str,anchor) 
   if not str then
@@ -2425,9 +2375,9 @@ function string.booleanstring(str)
 end
 function string.is_boolean(str,default)
   if type(str)=="string" then
-    if str=="true" or str=="yes" or str=="on" or str=="t" or str=="1" then
+    if str=="true" or str=="yes" or str=="on" or str=="t" then
       return true
-    elseif str=="false" or str=="no" or str=="off" or str=="f" or str=="0" then
+    elseif str=="false" or str=="no" or str=="off" or str=="f" then
       return false
     end
   end
@@ -2630,7 +2580,6 @@ local tracedchar = string.tracedchar
 local autosingle = string.autosingle
 local autodouble = string.autodouble
 local sequenced = table.sequenced
-local formattednumber = number.formatted
 ]]
 local template=[[
 %s
@@ -2645,7 +2594,7 @@ setmetatable(arguments,{ __index=function(t,k)
   end
 })
 local prefix_any=C((S("+- .")+R("09"))^0)
-local prefix_tab=P("{")*C((1-P("}"))^0)*P("}")+C((1-R("az","AZ","09","%%"))^0)
+local prefix_tab=C((1-R("az","AZ","09","%%"))^0)
 local format_s=function(f)
   n=n+1
   if f and f~="" then
@@ -2675,7 +2624,7 @@ local format_i=function(f)
   if f and f~="" then
     return format("format('%%%si',a%s)",f,n)
   else
-    return format("format('%%i',a%s)",n)
+    return format("a%s",n)
   end
 end
 local format_d=format_i
@@ -2827,39 +2776,6 @@ end
 local format_W=function(f) 
   return format("nspaces[%s]",tonumber(f) or 0)
 end
-local digit=patterns.digit
-local period=patterns.period
-local three=digit*digit*digit
-local splitter=Cs (
-  (((1-(three^1*period))^1+C(three))*(Carg(1)*three)^1+C((1-period)^1))*(P(1)/""*Carg(2))*C(2)
-)
-patterns.formattednumber=splitter
-function number.formatted(n,sep1,sep2)
-  local s=type(s)=="string" and n or format("%0.2f",n)
-  if sep1==true then
-    return lpegmatch(splitter,s,1,".",",")
-  elseif sep1=="." then
-    return lpegmatch(splitter,s,1,sep1,sep2 or ",")
-  elseif sep1=="," then
-    return lpegmatch(splitter,s,1,sep1,sep2 or ".")
-  else
-    return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".")
-  end
-end
-local format_m=function(f)
-  n=n+1
-  if not f or f=="" then
-    f=","
-  end
-  return format([[formattednumber(a%s,%q,".")]],n,f)
-end
-local format_M=function(f)
-  n=n+1
-  if not f or f=="" then
-    f="."
-  end
-  return format([[formattednumber(a%s,%q,",")]],n,f)
-end
 local format_rest=function(s)
   return format("%q",s) 
 end
@@ -2897,8 +2813,7 @@ local builder=Cs { "start",
 +V("w") 
 +V("W") 
 +V("a") 
-+V("A") 
-+V("m")+V("M")
++V("A")
 +V("*") 
       )+V("*")
     )*(P(-1)+Carg(1))
@@ -2929,16 +2844,14 @@ local builder=Cs { "start",
   ["b"]=(prefix_any*P("b"))/format_b,
   ["t"]=(prefix_tab*P("t"))/format_t,
   ["T"]=(prefix_tab*P("T"))/format_T,
-  ["l"]=(prefix_any*P("l"))/format_l,
-  ["L"]=(prefix_any*P("L"))/format_L,
+  ["l"]=(prefix_tab*P("l"))/format_l,
+  ["L"]=(prefix_tab*P("L"))/format_L,
   ["I"]=(prefix_any*P("I"))/format_I,
   ["w"]=(prefix_any*P("w"))/format_w,
   ["W"]=(prefix_any*P("W"))/format_W,
-  ["m"]=(prefix_tab*P("m"))/format_m,
-  ["M"]=(prefix_tab*P("M"))/format_M,
   ["a"]=(prefix_any*P("a"))/format_a,
   ["A"]=(prefix_any*P("A"))/format_A,
-  ["*"]=Cs(((1-P("%"))^1+P("%%")/"%%")^1)/format_rest,
+  ["*"]=Cs(((1-P("%"))^1+P("%%")/"%%%%")^1)/format_rest,
   ["!"]=Carg(2)*prefix_any*P("!")*C((1-P("!"))^1)*P("!")/format_extension,
 }
 local direct=Cs (
@@ -2984,13 +2897,10 @@ local function add(t,name,template,preamble)
   end
 end
 strings.formatters.add=add
-patterns.xmlescape=Cs((P("<")/"&lt;"+P(">")/"&gt;"+P("&")/"&amp;"+P('"')/"&quot;"+P(1))^0)
-patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+P(1))^0)
-patterns.luaescape=Cs(((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0) 
-patterns.luaquoted=Cs(Cc('"')*((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0*Cc('"'))
+lpeg.patterns.xmlescape=Cs((P("<")/"&lt;"+P(">")/"&gt;"+P("&")/"&amp;"+P('"')/"&quot;"+P(1))^0)
+lpeg.patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+P(1))^0)
 add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],[[local xmlescape = lpeg.patterns.xmlescape]])
 add(formatters,"tex",[[lpegmatch(texescape,%s)]],[[local texescape = lpeg.patterns.texescape]])
-add(formatters,"lua",[[lpegmatch(luaescape,%s)]],[[local luaescape = lpeg.patterns.luaescape]])
 
 end -- closure
 
@@ -3069,7 +2979,6 @@ local remapper={
   fea="font feature files",
   pfa="type1 fonts",
   pfb="type1 fonts",
-  afm="afm",
 }
 function resolvers.findfile(name,fileformat)
   name=string.gsub(name,"\\","/")
@@ -3088,10 +2997,6 @@ function resolvers.findfile(name,fileformat)
   return found
 end
 resolvers.findbinfile=resolvers.findfile
-function resolvers.loadbinfile(filename,filetype)
-  local data=io.loaddata(filename)
-  return true,data,#data
-end
 function resolvers.resolve(s)
   return s
 end
@@ -3107,20 +3012,11 @@ if not caches.namespace or caches.namespace=="" or caches.namespace=="context" t
 end
 do
   local cachepaths=kpse.expand_var('$TEXMFCACHE') or ""
-  if cachepaths=="" or cachepaths=="$TEXMFCACHE" then
+  if cachepaths=="" then
     cachepaths=kpse.expand_var('$TEXMFVAR') or ""
   end
-  if cachepaths=="" or cachepaths=="$TEXMFVAR" then
-    cachepaths=kpse.expand_var('$VARTEXMF') or ""
-  end
   if cachepaths=="" then
-    local fallbacks={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" }
-    for i=1,#fallbacks do
-      cachepaths=os.getenv(fallbacks[i]) or ""
-      if cachepath~="" and lfs.isdir(cachepath) then
-        break
-      end
-    end
+    cachepaths=kpse.expand_var('$VARTEXMF') or ""
   end
   if cachepaths=="" then
     cachepaths="."
@@ -3215,7 +3111,7 @@ function caches.savedata(path,name,data)
   local luaname,lucname=makefullname(path,name)
   if luaname then
     texio.write(string.format("(save: %s)",luaname))
-    table.tofile(luaname,data,true)
+    table.tofile(luaname,data,true,{ reduce=true })
     if lucname and type(caches.compile)=="function" then
       os.remove(lucname) 
       texio.write(string.format("(save: %s)",lucname))
@@ -3427,63 +3323,18 @@ end
 function nodes.delete(head,current)
   return nodes.remove(head,current,true)
 end
+nodes.before=node.insert_before
+nodes.after=node.insert_after
 function nodes.pool.kern(k)
   local n=new_node("kern",1)
   n.kern=k
   return n
 end
-local getfield=node.getfield or function(n,tag)    return n[tag] end
-local setfield=node.setfield or function(n,tag,value) n[tag]=value end
-nodes.getfield=getfield
-nodes.setfield=setfield
-nodes.getattr=getfield
-nodes.setattr=setfield
-if node.getid   then nodes.getid=node.getid   else function nodes.getid   (n) return getfield(n,"id")   end end
-if node.getsubtype then nodes.getsubtype=node.getsubtype else function nodes.getsubtype(n) return getfield(n,"subtype") end end
-if node.getnext  then nodes.getnext=node.getnext  else function nodes.getnext  (n) return getfield(n,"next")  end end
-if node.getprev  then nodes.getprev=node.getprev  else function nodes.getprev  (n) return getfield(n,"prev")  end end
-if node.getchar  then nodes.getchar=node.getchar  else function nodes.getchar  (n) return getfield(n,"char")  end end
-if node.getfont  then nodes.getfont=node.getfont  else function nodes.getfont  (n) return getfield(n,"font")  end end
-if node.getlist  then nodes.getlist=node.getlist  else function nodes.getlist  (n) return getfield(n,"list")  end end
-function nodes.tonut (n) return n end
-function nodes.tonode(n) return n end
-nodes.tostring=node.tostring or tostring
-nodes.copy=node.copy
-nodes.copy_list=node.copy_list
-nodes.delete=node.delete
-nodes.dimensions=node.dimensions
-nodes.end_of_math=node.end_of_math
-nodes.flush_list=node.flush_list
-nodes.flush_node=node.flush_node
-nodes.free=node.free
-nodes.insert_after=node.insert_after
-nodes.insert_before=node.insert_before
-nodes.hpack=node.hpack
-nodes.new=node.new
-nodes.tail=node.tail
-nodes.traverse=node.traverse
-nodes.traverse_id=node.traverse_id
-nodes.slide=node.slide
-nodes.vpack=node.vpack
-nodes.first_glyph=node.first_glyph
-nodes.first_character=node.first_character
-nodes.has_glyph=node.has_glyph or node.first_glyph
-nodes.current_attr=node.current_attr
-nodes.do_ligature_n=node.do_ligature_n
-nodes.has_field=node.has_field
-nodes.last_node=node.last_node
-nodes.usedlist=node.usedlist
-nodes.protrusion_skippable=node.protrusion_skippable
-nodes.write=node.write
-nodes.has_attribute=node.has_attribute
-nodes.set_attribute=node.set_attribute
-nodes.unset_attribute=node.unset_attribute
-nodes.protect_glyphs=node.protect_glyphs
-nodes.unprotect_glyphs=node.unprotect_glyphs
-nodes.kerning=node.kerning
-nodes.ligaturing=node.ligaturing
-nodes.mlist_to_hlist=node.mlist_to_hlist
-nodes.nuts=nodes
+function nodes.endofmath(n)
+  for n in traverse_id(math_code,n.next) do
+    return n
+  end
+end
 
 end -- closure
 
@@ -3727,7 +3578,6 @@ function constructors.scale(tfmdata,specification)
   if tonumber(specification) then
     specification={ size=specification }
   end
-  target.specification=specification
   local scaledpoints=specification.size
   local relativeid=specification.relativeid
   local properties=tfmdata.properties   or {}
@@ -3779,7 +3629,7 @@ function constructors.scale(tfmdata,specification)
   targetproperties.script=properties.script  or "dflt" 
   targetproperties.mode=properties.mode   or "base"
   local askedscaledpoints=scaledpoints
-  local scaledpoints,delta=constructors.calculatescale(tfmdata,scaledpoints,nil,specification)
+  local scaledpoints,delta=constructors.calculatescale(tfmdata,scaledpoints)
   local hdelta=delta
   local vdelta=delta
   target.designsize=parameters.designsize 
@@ -3853,7 +3703,7 @@ function constructors.scale(tfmdata,specification)
   end
   target.type=isvirtual and "virtual" or "real"
   target.postprocessors=tfmdata.postprocessors
-  local targetslant=(parameters.slant     or parameters[1] or 0)*factors.pt 
+  local targetslant=(parameters.slant     or parameters[1] or 0)
   local targetspace=(parameters.space     or parameters[2] or 0)*hdelta
   local targetspace_stretch=(parameters.space_stretch or parameters[3] or 0)*hdelta
   local targetspace_shrink=(parameters.space_shrink or parameters[4] or 0)*hdelta
@@ -4171,7 +4021,7 @@ function constructors.finalize(tfmdata)
     parameters.slantfactor=tfmdata.slant or 0
   end
   if not parameters.designsize then
-    parameters.designsize=tfmdata.designsize or (factors.pt*10)
+    parameters.designsize=tfmdata.designsize or 655360
   end
   if not parameters.units then
     parameters.units=tfmdata.units_per_em or 1000
@@ -4295,11 +4145,11 @@ function constructors.hashinstance(specification,force)
     size=math.round(constructors.scaled(size,designsizes[hash]))
     specification.size=size
   end
-  if fallbacks then
-    return hash..' @ '..tostring(size)..' @ '..fallbacks
-  else
-    return hash..' @ '..tostring(size)
-  end
+    if fallbacks then
+      return hash..' @ '..tostring(size)..' @ '..fallbacks
+    else
+      return hash..' @ '..tostring(size)
+    end
 end
 function constructors.setname(tfmdata,specification) 
   if constructors.namemode=="specification" then
@@ -4533,8 +4383,7 @@ function constructors.collectprocessors(what,tfmdata,features,trace,report)
     local whathandler=handlers[what]
     local whatfeatures=whathandler.features
     local whatprocessors=whatfeatures.processors
-    local mode=properties.mode
-    local processors=whatprocessors[mode]
+    local processors=whatprocessors[properties.mode]
     if processors then
       for i=1,#processors do
         local step=processors[i]
@@ -4551,7 +4400,7 @@ function constructors.collectprocessors(what,tfmdata,features,trace,report)
         end
       end
     elseif trace then
-      report("no feature processors for mode %a for font %a",mode,properties.fullname)
+      report("no feature processors for mode %a for font %a",mode,tfmdata.properties.fullname)
     end
   end
   return processes
@@ -4562,8 +4411,7 @@ function constructors.applymanipulators(what,tfmdata,features,trace,report)
     local whathandler=handlers[what]
     local whatfeatures=whathandler.features
     local whatmanipulators=whatfeatures.manipulators
-    local mode=properties.mode
-    local manipulators=whatmanipulators[mode]
+    local manipulators=whatmanipulators[properties.mode]
     if manipulators then
       for i=1,#manipulators do
         local step=manipulators[i]
@@ -4572,7 +4420,7 @@ function constructors.applymanipulators(what,tfmdata,features,trace,report)
         if value then
           local action=step.action
           if trace then
-            report("applying feature manipulator %a for mode %a for font %a",feature,mode,properties.fullname)
+            report("applying feature manipulator %a for mode %a for font %a",feature,mode,tfmdata.properties.fullname)
           end
           if action then
             action(tfmdata,feature,value)
@@ -4932,38 +4780,33 @@ function mappings.addtounicode(data,filename)
       if not unicode or unicode=="" then
         local split=lpegmatch(namesplitter,name)
         local nsplit=split and #split or 0
-        local t,n={},0
-        unicode=true
-        for l=1,nsplit do
-          local base=split[l]
-          local u=unicodes[base] or unicodevector[base]
-          if not u then
-            break
-          elseif type(u)=="table" then
-            if u[1]>=private then
-              unicode=false
+        if nsplit>=2 then
+          local t,n={},0
+          for l=1,nsplit do
+            local base=split[l]
+            local u=unicodes[base] or unicodevector[base]
+            if not u then
               break
+            elseif type(u)=="table" then
+              n=n+1
+              t[n]=u[1]
+            else
+              n=n+1
+              t[n]=u
             end
-            n=n+1
-            t[n]=u[1]
+          end
+          if n==0 then
+          elseif n==1 then
+            originals[index]=t[1]
+            tounicode[index]=tounicode16(t[1],name)
           else
-            if u>=private then
-              unicode=false
-              break
-            end
-            n=n+1
-            t[n]=u
+            originals[index]=t
+            tounicode[index]=tounicode16sequence(t)
           end
-        end
-        if n==0 then
-        elseif n==1 then
-          originals[index]=t[1]
-          tounicode[index]=tounicode16(t[1],name)
+          nl=nl+1
+          unicode=true
         else
-          originals[index]=t
-          tounicode[index]=tounicode16sequence(t)
         end
-        nl=nl+1
       end
       if not unicode or unicode=="" then
         local foundcodes,multiple=lpegmatch(uparser,name)
@@ -5050,1133 +4893,35 @@ function fonts.names.resolve(name,sub)
         end
       end
     end
-    loaded=true
-  end
-  if type(data)=="table" and data.version==fonts.names.version then
-    local condensed=string.gsub(string.lower(name),"[^%a%d]","")
-    local found=data.mappings and data.mappings[condensed]
-    if found then
-      local fontname,filename,subfont=found[1],found[2],found[3]
-      if subfont then
-        return filename,fontname
-      else
-        return filename,false
-      end
-    elseif fonts.names.reportmissingname then
-      fonts.names.reportmissingname()
-      return name,false 
-    end
-  elseif fonts.names.reportmissingbase then
-    fonts.names.reportmissingbase()
-  end
-end
-fonts.names.resolvespec=fonts.names.resolve 
-function fonts.names.getfilename(askedname,suffix) 
-  return ""
-end
-function fonts.names.ignoredfile(filename) 
-  return true 
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['font-tfm']={
-  version=1.001,
-  comment="companion to font-ini.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local next=next
-local match=string.match
-local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end)
-local trace_features=false trackers.register("tfm.features",function(v) trace_features=v end)
-local report_defining=logs.reporter("fonts","defining")
-local report_tfm=logs.reporter("fonts","tfm loading")
-local findbinfile=resolvers.findbinfile
-local fonts=fonts
-local handlers=fonts.handlers
-local readers=fonts.readers
-local constructors=fonts.constructors
-local encodings=fonts.encodings
-local tfm=constructors.newhandler("tfm")
-local tfmfeatures=constructors.newfeatures("tfm")
-local registertfmfeature=tfmfeatures.register
-constructors.resolvevirtualtoo=false 
-fonts.formats.tfm="type1"
-function tfm.setfeatures(tfmdata,features)
-  local okay=constructors.initializefeatures("tfm",tfmdata,features,trace_features,report_tfm)
-  if okay then
-    return constructors.collectprocessors("tfm",tfmdata,features,trace_features,report_tfm)
-  else
-    return {} 
-  end
-end
-local function read_from_tfm(specification)
-  local filename=specification.filename
-  local size=specification.size
-  if trace_defining then
-    report_defining("loading tfm file %a at size %s",filename,size)
-  end
-  local tfmdata=font.read_tfm(filename,size) 
-  if tfmdata then
-    local features=specification.features and specification.features.normal or {}
-    local resources=tfmdata.resources or {}
-    local properties=tfmdata.properties or {}
-    local parameters=tfmdata.parameters or {}
-    local shared=tfmdata.shared   or {}
-    properties.name=tfmdata.name
-    properties.fontname=tfmdata.fontname
-    properties.psname=tfmdata.psname
-    properties.filename=specification.filename
-    parameters.size=size
-    shared.rawdata={}
-    shared.features=features
-    shared.processes=next(features) and tfm.setfeatures(tfmdata,features) or nil
-    tfmdata.properties=properties
-    tfmdata.resources=resources
-    tfmdata.parameters=parameters
-    tfmdata.shared=shared
-    parameters.slant=parameters.slant     or parameters[1] or 0
-    parameters.space=parameters.space     or parameters[2] or 0
-    parameters.space_stretch=parameters.space_stretch or parameters[3] or 0
-    parameters.space_shrink=parameters.space_shrink  or parameters[4] or 0
-    parameters.x_height=parameters.x_height    or parameters[5] or 0
-    parameters.quad=parameters.quad      or parameters[6] or 0
-    parameters.extra_space=parameters.extra_space  or parameters[7] or 0
-    constructors.enhanceparameters(parameters)
-    if constructors.resolvevirtualtoo then
-      fonts.loggers.register(tfmdata,file.suffix(filename),specification) 
-      local vfname=findbinfile(specification.name,'ovf')
-      if vfname and vfname~="" then
-        local vfdata=font.read_vf(vfname,size) 
-        if vfdata then
-          local chars=tfmdata.characters
-          for k,v in next,vfdata.characters do
-            chars[k].commands=v.commands
-          end
-          properties.virtualized=true
-          tfmdata.fonts=vfdata.fonts
-        end
-      end
-    end
-    local allfeatures=tfmdata.shared.features or specification.features.normal
-    constructors.applymanipulators("tfm",tfmdata,allfeatures.normal,trace_features,report_tfm)
-    if not features.encoding then
-      local encoding,filename=match(properties.filename,"^(.-)%-(.*)$") 
-      if filename and encoding and encodings.known and encodings.known[encoding] then
-        features.encoding=encoding
-      end
-    end
-    return tfmdata
-  end
-end
-local function check_tfm(specification,fullname) 
-  local foundname=findbinfile(fullname,'tfm') or ""
-  if foundname=="" then
-    foundname=findbinfile(fullname,'ofm') or "" 
-  end
-  if foundname=="" then
-    foundname=fonts.names.getfilename(fullname,"tfm") or ""
-  end
-  if foundname~="" then
-    specification.filename=foundname
-    specification.format="ofm"
-    return read_from_tfm(specification)
-  elseif trace_defining then
-    report_defining("loading tfm with name %a fails",specification.name)
-  end
-end
-readers.check_tfm=check_tfm
-function readers.tfm(specification)
-  local fullname=specification.filename or ""
-  if fullname=="" then
-    local forced=specification.forced or ""
-    if forced~="" then
-      fullname=specification.name.."."..forced
-    else
-      fullname=specification.name
-    end
-  end
-  return check_tfm(specification,fullname)
-end
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
-if not modules then modules={} end modules ['font-afm']={
-  version=1.001,
-  comment="companion to font-ini.mkiv",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files"
-}
-local fonts,logs,trackers,containers,resolvers=fonts,logs,trackers,containers,resolvers
-local next,type,tonumber=next,type,tonumber
-local format,match,gmatch,lower,gsub,strip=string.format,string.match,string.gmatch,string.lower,string.gsub,string.strip
-local abs=math.abs
-local P,S,C,R,lpegmatch,patterns=lpeg.P,lpeg.S,lpeg.C,lpeg.R,lpeg.match,lpeg.patterns
-local derivetable=table.derive
-local trace_features=false trackers.register("afm.features",function(v) trace_features=v end)
-local trace_indexing=false trackers.register("afm.indexing",function(v) trace_indexing=v end)
-local trace_loading=false trackers.register("afm.loading",function(v) trace_loading=v end)
-local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end)
-local report_afm=logs.reporter("fonts","afm loading")
-local findbinfile=resolvers.findbinfile
-local definers=fonts.definers
-local readers=fonts.readers
-local constructors=fonts.constructors
-local afm=constructors.newhandler("afm")
-local pfb=constructors.newhandler("pfb")
-local afmfeatures=constructors.newfeatures("afm")
-local registerafmfeature=afmfeatures.register
-afm.version=1.410 
-afm.cache=containers.define("fonts","afm",afm.version,true)
-afm.autoprefixed=true 
-afm.helpdata={} 
-afm.syncspace=true 
-afm.addligatures=true 
-afm.addtexligatures=true 
-afm.addkerns=true 
-local applyruntimefixes=fonts.treatments and fonts.treatments.applyfixes
-local function setmode(tfmdata,value)
-  if value then
-    tfmdata.properties.mode=lower(value)
-  end
-end
-registerafmfeature {
-  name="mode",
-  description="mode",
-  initializers={
-    base=setmode,
-    node=setmode,
-  }
-}
-local comment=P("Comment")
-local spacing=patterns.spacer 
-local lineend=patterns.newline 
-local words=C((1-lineend)^1)
-local number=C((R("09")+S("."))^1)/tonumber*spacing^0
-local data=lpeg.Carg(1)
-local pattern=(
-  comment*spacing*(
-      data*(
-        ("CODINGSCHEME"*spacing*words                   )/function(fd,a)                   end+("DESIGNSIZE"*spacing*number*words               )/function(fd,a)   fd[ 1]=a    end+("CHECKSUM"*spacing*number*words               )/function(fd,a)   fd[ 2]=a    end+("SPACE"*spacing*number*"plus"*number*"minus"*number)/function(fd,a,b,c) fd[ 3],fd[ 4],fd[ 5]=a,b,c end+("QUAD"*spacing*number                   )/function(fd,a)   fd[ 6]=a    end+("EXTRASPACE"*spacing*number                   )/function(fd,a)   fd[ 7]=a    end+("NUM"*spacing*number*number*number          )/function(fd,a,b,c) fd[ 8],fd[ 9],fd[10]=a,b,c end+("DENOM"*spacing*number*number              )/function(fd,a,b ) fd[11],fd[12]=a,b  end+("SUP"*spacing*number*number*number          )/function(fd,a,b,c) fd[13],fd[14],fd[15]=a,b,c end+("SUB"*spacing*number*number              )/function(fd,a,b)  fd[16],fd[17]=a,b  end+("SUPDROP"*spacing*number                   )/function(fd,a)   fd[18]=a    end+("SUBDROP"*spacing*number                   )/function(fd,a)   fd[19]=a    end+("DELIM"*spacing*number*number              )/function(fd,a,b)  fd[20],fd[21]=a,b  end+("AXISHEIGHT"*spacing*number                   )/function(fd,a)   fd[22]=a    end
-      )+(1-lineend)^0
-    )+(1-comment)^1
-)^0
-local function scan_comment(str)
-  local fd={}
-  lpegmatch(pattern,str,1,fd)
-  return fd
-end
-local keys={}
-function keys.FontName  (data,line) data.metadata.fontname=strip  (line) 
-                   data.metadata.fullname=strip  (line) end
-function keys.ItalicAngle (data,line) data.metadata.italicangle=tonumber (line) end
-function keys.IsFixedPitch(data,line) data.metadata.isfixedpitch=toboolean(line,true) end
-function keys.CharWidth  (data,line) data.metadata.charwidth=tonumber (line) end
-function keys.XHeight   (data,line) data.metadata.xheight=tonumber (line) end
-function keys.Descender  (data,line) data.metadata.descender=tonumber (line) end
-function keys.Ascender  (data,line) data.metadata.ascender=tonumber (line) end
-function keys.Comment   (data,line)
-  line=lower(line)
-  local designsize=match(line,"designsize[^%d]*(%d+)")
-  if designsize then data.metadata.designsize=tonumber(designsize) end
-end
-local function get_charmetrics(data,charmetrics,vector)
-  local characters=data.characters
-  local chr,ind={},0
-  for k,v in gmatch(charmetrics,"([%a]+) +(.-) *;") do
-    if k=='C' then
-      v=tonumber(v)
-      if v<0 then
-        ind=ind+1 
-      else
-        ind=v
-      end
-      chr={
-        index=ind
-      }
-    elseif k=='WX' then
-      chr.width=tonumber(v)
-    elseif k=='N' then
-      characters[v]=chr
-    elseif k=='B' then
-      local llx,lly,urx,ury=match(v,"^ *(.-) +(.-) +(.-) +(.-)$")
-      chr.boundingbox={ tonumber(llx),tonumber(lly),tonumber(urx),tonumber(ury) }
-    elseif k=='L' then
-      local plus,becomes=match(v,"^(.-) +(.-)$")
-      local ligatures=chr.ligatures
-      if ligatures then
-        ligatures[plus]=becomes
-      else
-        chr.ligatures={ [plus]=becomes }
-      end
-    end
-  end
-end
-local function get_kernpairs(data,kernpairs)
-  local characters=data.characters
-  for one,two,value in gmatch(kernpairs,"KPX +(.-) +(.-) +(.-)\n") do
-    local chr=characters[one]
-    if chr then
-      local kerns=chr.kerns
-      if kerns then
-        kerns[two]=tonumber(value)
-      else
-        chr.kerns={ [two]=tonumber(value) }
-      end
-    end
-  end
-end
-local function get_variables(data,fontmetrics)
-  for key,rest in gmatch(fontmetrics,"(%a+) *(.-)[\n\r]") do
-    local keyhandler=keys[key]
-    if keyhandler then
-      keyhandler(data,rest)
-    end
-  end
-end
-local function get_indexes(data,pfbname)
-  data.resources.filename=resolvers.unresolve(pfbname) 
-  local pfbblob=fontloader.open(pfbname)
-  if pfbblob then
-    local characters=data.characters
-    local pfbdata=fontloader.to_table(pfbblob)
-    if pfbdata then
-      local glyphs=pfbdata.glyphs
-      if glyphs then
-        if trace_loading then
-          report_afm("getting index data from %a",pfbname)
-        end
-        for index,glyph in next,glyphs do
-          local name=glyph.name
-          if name then
-            local char=characters[name]
-            if char then
-              if trace_indexing then
-                report_afm("glyph %a has index %a",name,index)
-              end
-              char.index=index
-            end
-          end
-        end
-      elseif trace_loading then
-        report_afm("no glyph data in pfb file %a",pfbname)
-      end
-    elseif trace_loading then
-      report_afm("no data in pfb file %a",pfbname)
-    end
-    fontloader.close(pfbblob)
-  elseif trace_loading then
-    report_afm("invalid pfb file %a",pfbname)
-  end
-end
-local function readafm(filename)
-  local ok,afmblob,size=resolvers.loadbinfile(filename) 
-  if ok and afmblob then
-    local data={
-      resources={
-        filename=resolvers.unresolve(filename),
-        version=afm.version,
-        creator="context mkiv",
-      },
-      properties={
-        hasitalics=false,
-      },
-      goodies={},
-      metadata={
-        filename=file.removesuffix(file.basename(filename))
-      },
-      characters={
-      },
-      descriptions={
-      },
-    }
-    afmblob=gsub(afmblob,"StartCharMetrics(.-)EndCharMetrics",function(charmetrics)
-      if trace_loading then
-        report_afm("loading char metrics")
-      end
-      get_charmetrics(data,charmetrics,vector)
-      return ""
-    end)
-    afmblob=gsub(afmblob,"StartKernPairs(.-)EndKernPairs",function(kernpairs)
-      if trace_loading then
-        report_afm("loading kern pairs")
-      end
-      get_kernpairs(data,kernpairs)
-      return ""
-    end)
-    afmblob=gsub(afmblob,"StartFontMetrics%s+([%d%.]+)(.-)EndFontMetrics",function(version,fontmetrics)
-      if trace_loading then
-        report_afm("loading variables")
-      end
-      data.afmversion=version
-      get_variables(data,fontmetrics)
-      data.fontdimens=scan_comment(fontmetrics) 
-      return ""
-    end)
-    return data
-  else
-    if trace_loading then
-      report_afm("no valid afm file %a",filename)
-    end
-    return nil
-  end
-end
-local addkerns,addligatures,addtexligatures,unify,normalize 
-function afm.load(filename)
-  filename=resolvers.findfile(filename,'afm') or ""
-  if filename~="" and not fonts.names.ignoredfile(filename) then
-    local name=file.removesuffix(file.basename(filename))
-    local data=containers.read(afm.cache,name)
-    local attr=lfs.attributes(filename)
-    local size,time=attr.size or 0,attr.modification or 0
-    local pfbfile=file.replacesuffix(name,"pfb")
-    local pfbname=resolvers.findfile(pfbfile,"pfb") or ""
-    if pfbname=="" then
-      pfbname=resolvers.findfile(file.basename(pfbfile),"pfb") or ""
-    end
-    local pfbsize,pfbtime=0,0
-    if pfbname~="" then
-      local attr=lfs.attributes(pfbname)
-      pfbsize=attr.size or 0
-      pfbtime=attr.modification or 0
-    end
-    if not data or data.size~=size or data.time~=time or data.pfbsize~=pfbsize or data.pfbtime~=pfbtime then
-      report_afm("reading %a",filename)
-      data=readafm(filename)
-      if data then
-        if pfbname~="" then
-          get_indexes(data,pfbname)
-        elseif trace_loading then
-          report_afm("no pfb file for %a",filename)
-        end
-        report_afm("unifying %a",filename)
-        unify(data,filename)
-        if afm.addligatures then
-          report_afm("add ligatures")
-          addligatures(data)
-        end
-        if afm.addtexligatures then
-          report_afm("add tex ligatures")
-          addtexligatures(data)
-        end
-        if afm.addkerns then
-          report_afm("add extra kerns")
-          addkerns(data)
-        end
-        normalize(data)
-        report_afm("add tounicode data")
-        fonts.mappings.addtounicode(data,filename)
-        data.size=size
-        data.time=time
-        data.pfbsize=pfbsize
-        data.pfbtime=pfbtime
-        report_afm("saving %a in cache",name)
-        data=containers.write(afm.cache,name,data)
-        data=containers.read(afm.cache,name)
-      end
-      if applyruntimefixes and data then
-        applyruntimefixes(filename,data)
-      end
-    end
-    return data
-  else
-    return nil
-  end
-end
-local uparser=fonts.mappings.makenameparser()
-unify=function(data,filename)
-  local unicodevector=fonts.encodings.agl.unicodes 
-  local unicodes,names={},{}
-  local private=constructors.privateoffset
-  local descriptions=data.descriptions
-  for name,blob in next,data.characters do
-    local code=unicodevector[name] 
-    if not code then
-      code=lpegmatch(uparser,name)
-      if not code then
-        code=private
-        private=private+1
-        report_afm("assigning private slot %U for unknown glyph name %a",code,name)
-      end
-    end
-    local index=blob.index
-    unicodes[name]=code
-    names[name]=index
-    blob.name=name
-    descriptions[code]={
-      boundingbox=blob.boundingbox,
-      width=blob.width,
-      kerns=blob.kerns,
-      index=index,
-      name=name,
-    }
-  end
-  for unicode,description in next,descriptions do
-    local kerns=description.kerns
-    if kerns then
-      local krn={}
-      for name,kern in next,kerns do
-        local unicode=unicodes[name]
-        if unicode then
-          krn[unicode]=kern
-        else
-          print(unicode,name)
-        end
-      end
-      description.kerns=krn
-    end
-  end
-  data.characters=nil
-  local resources=data.resources
-  local filename=resources.filename or file.removesuffix(file.basename(filename))
-  resources.filename=resolvers.unresolve(filename) 
-  resources.unicodes=unicodes 
-  resources.marks={} 
-  resources.names=names 
-  resources.private=private
-end
-normalize=function(data)
-end
-local addthem=function(rawdata,ligatures)
-  if ligatures then
-    local descriptions=rawdata.descriptions
-    local resources=rawdata.resources
-    local unicodes=resources.unicodes
-    local names=resources.names
-    for ligname,ligdata in next,ligatures do
-      local one=descriptions[unicodes[ligname]]
-      if one then
-        for _,pair in next,ligdata do
-          local two,three=unicodes[pair[1]],unicodes[pair[2]]
-          if two and three then
-            local ol=one.ligatures
-            if ol then
-              if not ol[two] then
-                ol[two]=three
-              end
-            else
-              one.ligatures={ [two]=three }
-            end
-          end
-        end
-      end
-    end
-  end
-end
-addligatures=function(rawdata) addthem(rawdata,afm.helpdata.ligatures  ) end
-addtexligatures=function(rawdata) addthem(rawdata,afm.helpdata.texligatures) end
-addkerns=function(rawdata) 
-  local descriptions=rawdata.descriptions
-  local resources=rawdata.resources
-  local unicodes=resources.unicodes
-  local function do_it_left(what)
-    if what then
-      for unicode,description in next,descriptions do
-        local kerns=description.kerns
-        if kerns then
-          local extrakerns
-          for complex,simple in next,what do
-            complex=unicodes[complex]
-            simple=unicodes[simple]
-            if complex and simple then
-              local ks=kerns[simple]
-              if ks and not kerns[complex] then
-                if extrakerns then
-                  extrakerns[complex]=ks
-                else
-                  extrakerns={ [complex]=ks }
-                end
-              end
-            end
-          end
-          if extrakerns then
-            description.extrakerns=extrakerns
-          end
-        end
-      end
-    end
-  end
-  local function do_it_copy(what)
-    if what then
-      for complex,simple in next,what do
-        complex=unicodes[complex]
-        simple=unicodes[simple]
-        if complex and simple then
-          local complexdescription=descriptions[complex]
-          if complexdescription then 
-            local simpledescription=descriptions[complex]
-            if simpledescription then
-              local extrakerns
-              local kerns=simpledescription.kerns
-              if kerns then
-                for unicode,kern in next,kerns do
-                  if extrakerns then
-                    extrakerns[unicode]=kern
-                  else
-                    extrakerns={ [unicode]=kern }
-                  end
-                end
-              end
-              local extrakerns=simpledescription.extrakerns
-              if extrakerns then
-                for unicode,kern in next,extrakerns do
-                  if extrakerns then
-                    extrakerns[unicode]=kern
-                  else
-                    extrakerns={ [unicode]=kern }
-                  end
-                end
-              end
-              if extrakerns then
-                complexdescription.extrakerns=extrakerns
-              end
-            end
-          end
-        end
-      end
-    end
-  end
-  do_it_left(afm.helpdata.leftkerned)
-  do_it_left(afm.helpdata.bothkerned)
-  do_it_copy(afm.helpdata.bothkerned)
-  do_it_copy(afm.helpdata.rightkerned)
-end
-local function adddimensions(data) 
-  if data then
-    for unicode,description in next,data.descriptions do
-      local bb=description.boundingbox
-      if bb then
-        local ht,dp=bb[4],-bb[2]
-        if ht==0 or ht<0 then
-        else
-          description.height=ht
-        end
-        if dp==0 or dp<0 then
-        else
-          description.depth=dp
-        end
-      end
-    end
-  end
-end
-local function copytotfm(data)
-  if data and data.descriptions then
-    local metadata=data.metadata
-    local resources=data.resources
-    local properties=derivetable(data.properties)
-    local descriptions=derivetable(data.descriptions)
-    local goodies=derivetable(data.goodies)
-    local characters={}
-    local parameters={}
-    local unicodes=resources.unicodes
-    for unicode,description in next,data.descriptions do 
-      characters[unicode]={}
-    end
-    local filename=constructors.checkedfilename(resources)
-    local fontname=metadata.fontname or metadata.fullname
-    local fullname=metadata.fullname or metadata.fontname
-    local endash=unicodes['space']
-    local emdash=unicodes['emdash']
-    local spacer="space"
-    local spaceunits=500
-    local monospaced=metadata.isfixedpitch
-    local charwidth=metadata.charwidth
-    local italicangle=metadata.italicangle
-    local charxheight=metadata.xheight and metadata.xheight>0 and metadata.xheight
-    properties.monospaced=monospaced
-    parameters.italicangle=italicangle
-    parameters.charwidth=charwidth
-    parameters.charxheight=charxheight
-    if properties.monospaced then
-      if descriptions[endash] then
-        spaceunits,spacer=descriptions[endash].width,"space"
-      end
-      if not spaceunits and descriptions[emdash] then
-        spaceunits,spacer=descriptions[emdash].width,"emdash"
-      end
-      if not spaceunits and charwidth then
-        spaceunits,spacer=charwidth,"charwidth"
-      end
-    else
-      if descriptions[endash] then
-        spaceunits,spacer=descriptions[endash].width,"space"
-      end
-      if not spaceunits and charwidth then
-        spaceunits,spacer=charwidth,"charwidth"
-      end
-    end
-    spaceunits=tonumber(spaceunits)
-    if spaceunits<200 then
-    end
-    parameters.slant=0
-    parameters.space=spaceunits
-    parameters.space_stretch=500
-    parameters.space_shrink=333
-    parameters.x_height=400
-    parameters.quad=1000
-    if italicangle and italicangle~=0 then
-      parameters.italicangle=italicangle
-      parameters.italicfactor=math.cos(math.rad(90+italicangle))
-      parameters.slant=- math.tan(italicangle*math.pi/180)
-    end
-    if monospaced then
-      parameters.space_stretch=0
-      parameters.space_shrink=0
-    elseif afm.syncspace then
-      parameters.space_stretch=spaceunits/2
-      parameters.space_shrink=spaceunits/3
-    end
-    parameters.extra_space=parameters.space_shrink
-    if charxheight then
-      parameters.x_height=charxheight
-    else
-      local x=unicodes['x']
-      if x then
-        local x=descriptions[x]
-        if x then
-          parameters.x_height=x.height
-        end
-      end
-    end
-    local fd=data.fontdimens
-    if fd and fd[8] and fd[9] and fd[10] then 
-      for k,v in next,fd do
-        parameters[k]=v
-      end
-    end
-    parameters.designsize=(metadata.designsize or 10)*65536
-    parameters.ascender=abs(metadata.ascender or 0)
-    parameters.descender=abs(metadata.descender or 0)
-    parameters.units=1000
-    properties.spacer=spacer
-    properties.encodingbytes=2
-    properties.format=fonts.formats[filename] or "type1"
-    properties.filename=filename
-    properties.fontname=fontname
-    properties.fullname=fullname
-    properties.psname=fullname
-    properties.name=filename or fullname or fontname
-    if next(characters) then
-      return {
-        characters=characters,
-        descriptions=descriptions,
-        parameters=parameters,
-        resources=resources,
-        properties=properties,
-        goodies=goodies,
-      }
-    end
-  end
-  return nil
-end
-function afm.setfeatures(tfmdata,features)
-  local okay=constructors.initializefeatures("afm",tfmdata,features,trace_features,report_afm)
-  if okay then
-    return constructors.collectprocessors("afm",tfmdata,features,trace_features,report_afm)
-  else
-    return {} 
-  end
-end
-local function checkfeatures(specification)
-end
-local function afmtotfm(specification)
-  local afmname=specification.filename or specification.name
-  if specification.forced=="afm" or specification.format=="afm" then 
-    if trace_loading then
-      report_afm("forcing afm format for %a",afmname)
-    end
-  else
-    local tfmname=findbinfile(afmname,"ofm") or ""
-    if tfmname~="" then
-      if trace_loading then
-        report_afm("fallback from afm to tfm for %a",afmname)
-      end
-      return 
-    end
-  end
-  if afmname~="" then
-    local features=constructors.checkedfeatures("afm",specification.features.normal)
-    specification.features.normal=features
-    constructors.hashinstance(specification,true)
-    specification=definers.resolve(specification) 
-    local cache_id=specification.hash
-    local tfmdata=containers.read(constructors.cache,cache_id) 
-    if not tfmdata then
-      local rawdata=afm.load(afmname)
-      if rawdata and next(rawdata) then
-        adddimensions(rawdata)
-        tfmdata=copytotfm(rawdata)
-        if tfmdata and next(tfmdata) then
-          local shared=tfmdata.shared
-          if not shared then
-            shared={}
-            tfmdata.shared=shared
-          end
-          shared.rawdata=rawdata
-          shared.features=features
-          shared.processes=afm.setfeatures(tfmdata,features)
-        end
-      elseif trace_loading then
-        report_afm("no (valid) afm file found with name %a",afmname)
-      end
-      tfmdata=containers.write(constructors.cache,cache_id,tfmdata)
-    end
-    return tfmdata
-  end
-end
-local function read_from_afm(specification)
-  local tfmdata=afmtotfm(specification)
-  if tfmdata then
-    tfmdata.properties.name=specification.name
-    tfmdata=constructors.scale(tfmdata,specification)
-    local allfeatures=tfmdata.shared.features or specification.features.normal
-    constructors.applymanipulators("afm",tfmdata,allfeatures,trace_features,report_afm)
-    fonts.loggers.register(tfmdata,'afm',specification)
-  end
-  return tfmdata
-end
-local function prepareligatures(tfmdata,ligatures,value)
-  if value then
-    local descriptions=tfmdata.descriptions
-    for unicode,character in next,tfmdata.characters do
-      local description=descriptions[unicode]
-      local dligatures=description.ligatures
-      if dligatures then
-        local cligatures=character.ligatures
-        if not cligatures then
-          cligatures={}
-          character.ligatures=cligatures
-        end
-        for unicode,ligature in next,dligatures do
-          cligatures[unicode]={
-            char=ligature,
-            type=0
-          }
-        end
-      end
-    end
-  end
-end
-local function preparekerns(tfmdata,kerns,value)
-  if value then
-    local rawdata=tfmdata.shared.rawdata
-    local resources=rawdata.resources
-    local unicodes=resources.unicodes
-    local descriptions=tfmdata.descriptions
-    for u,chr in next,tfmdata.characters do
-      local d=descriptions[u]
-      local newkerns=d[kerns]
-      if newkerns then
-        local kerns=chr.kerns
-        if not kerns then
-          kerns={}
-          chr.kerns=kerns
-        end
-        for k,v in next,newkerns do
-          local uk=unicodes[k]
-          if uk then
-            kerns[uk]=v
-          end
-        end
-      end
-    end
-  end
-end
-local list={
-  [0x0027]=0x2019,
-}
-local function texreplacements(tfmdata,value)
-  local descriptions=tfmdata.descriptions
-  local characters=tfmdata.characters
-  for k,v in next,list do
-    characters [k]=characters [v] 
-    descriptions[k]=descriptions[v] 
-  end
-end
-local function ligatures  (tfmdata,value) prepareligatures(tfmdata,'ligatures',value) end
-local function texligatures(tfmdata,value) prepareligatures(tfmdata,'texligatures',value) end
-local function kerns    (tfmdata,value) preparekerns  (tfmdata,'kerns',value) end
-local function extrakerns (tfmdata,value) preparekerns  (tfmdata,'extrakerns',value) end
-registerafmfeature {
-  name="liga",
-  description="traditional ligatures",
-  initializers={
-    base=ligatures,
-    node=ligatures,
-  }
-}
-registerafmfeature {
-  name="kern",
-  description="intercharacter kerning",
-  initializers={
-    base=kerns,
-    node=kerns,
-  }
-}
-registerafmfeature {
-  name="extrakerns",
-  description="additional intercharacter kerning",
-  initializers={
-    base=extrakerns,
-    node=extrakerns,
-  }
-}
-registerafmfeature {
-  name='tlig',
-  description='tex ligatures',
-  initializers={
-    base=texligatures,
-    node=texligatures,
-  }
-}
-registerafmfeature {
-  name='trep',
-  description='tex replacements',
-  initializers={
-    base=texreplacements,
-    node=texreplacements,
-  }
-}
-local check_tfm=readers.check_tfm
-fonts.formats.afm="type1"
-fonts.formats.pfb="type1"
-local function check_afm(specification,fullname)
-  local foundname=findbinfile(fullname,'afm') or "" 
-  if foundname=="" then
-    foundname=fonts.names.getfilename(fullname,"afm") or ""
-  end
-  if foundname=="" and afm.autoprefixed then
-    local encoding,shortname=match(fullname,"^(.-)%-(.*)$") 
-    if encoding and shortname and fonts.encodings.known[encoding] then
-      shortname=findbinfile(shortname,'afm') or "" 
-      if shortname~="" then
-        foundname=shortname
-        if trace_defining then
-          report_afm("stripping encoding prefix from filename %a",afmname)
-        end
-      end
-    end
-  end
-  if foundname~="" then
-    specification.filename=foundname
-    specification.format="afm"
-    return read_from_afm(specification)
+    loaded=true
   end
-end
-function readers.afm(specification,method)
-  local fullname,tfmdata=specification.filename or "",nil
-  if fullname=="" then
-    local forced=specification.forced or ""
-    if forced~="" then
-      tfmdata=check_afm(specification,specification.name.."."..forced)
-    end
-    if not tfmdata then
-      method=method or definers.method or "afm or tfm"
-      if method=="tfm" then
-        tfmdata=check_tfm(specification,specification.name)
-      elseif method=="afm" then
-        tfmdata=check_afm(specification,specification.name)
-      elseif method=="tfm or afm" then
-        tfmdata=check_tfm(specification,specification.name) or check_afm(specification,specification.name)
-      else 
-        tfmdata=check_afm(specification,specification.name) or check_tfm(specification,specification.name)
+  if type(data)=="table" and data.version==fonts.names.version then
+    local condensed=string.gsub(string.lower(name),"[^%a%d]","")
+    local found=data.mappings and data.mappings[condensed]
+    if found then
+      local fontname,filename,subfont=found[1],found[2],found[3]
+      if subfont then
+        return filename,fontname
+      else
+        return filename,false
       end
+    elseif fonts.names.reportmissingname then
+      fonts.names.reportmissingname()
+      return name,false 
     end
-  else
-    tfmdata=check_afm(specification,fullname)
+  elseif fonts.names.reportmissingbase then
+    fonts.names.reportmissingbase()
   end
-  return tfmdata
 end
-function readers.pfb(specification,method) 
-  local original=specification.specification
-  if trace_defining then
-    report_afm("using afm reader for %a",original)
-  end
-  specification.specification=gsub(original,"%.pfb",".afm")
-  specification.forced="afm"
-  return readers.afm(specification,method)
+fonts.names.resolvespec=fonts.names.resolve 
+function fonts.names.getfilename(askedname,suffix) 
+  return ""
 end
 
 end -- closure
 
 do -- begin closure to overcome local limits and interference
 
-if not modules then modules={} end modules ['font-afk']={
-  version=1.001,
-  comment="companion to font-afm.lua",
-  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
-  copyright="PRAGMA ADE / ConTeXt Development Team",
-  license="see context related readme files",
-  dataonly=true,
-}
-local allocate=utilities.storage.allocate
-fonts.handlers.afm.helpdata={
-  ligatures=allocate { 
-    ['f']={ 
-      { 'f','ff' },
-      { 'i','fi' },
-      { 'l','fl' },
-    },
-    ['ff']={
-      { 'i','ffi' }
-    },
-    ['fi']={
-      { 'i','fii' }
-    },
-    ['fl']={
-      { 'i','fli' }
-    },
-    ['s']={
-      { 't','st' }
-    },
-    ['i']={
-      { 'j','ij' }
-    },
-  },
-  texligatures=allocate {
-    ['quoteleft']={
-      { 'quoteleft','quotedblleft' }
-    },
-    ['quoteright']={
-      { 'quoteright','quotedblright' }
-    },
-    ['hyphen']={
-      { 'hyphen','endash' }
-    },
-    ['endash']={
-      { 'hyphen','emdash' }
-    }
-  },
-  leftkerned=allocate {
-    AEligature="A",aeligature="a",
-    OEligature="O",oeligature="o",
-    IJligature="I",ijligature="i",
-    AE="A",ae="a",
-    OE="O",oe="o",
-    IJ="I",ij="i",
-    Ssharp="S",ssharp="s",
-  },
-  rightkerned=allocate {
-    AEligature="E",aeligature="e",
-    OEligature="E",oeligature="e",
-    IJligature="J",ijligature="j",
-    AE="E",ae="e",
-    OE="E",oe="e",
-    IJ="J",ij="j",
-    Ssharp="S",ssharp="s",
-  },
-  bothkerned=allocate {
-    Acircumflex="A",acircumflex="a",
-    Ccircumflex="C",ccircumflex="c",
-    Ecircumflex="E",ecircumflex="e",
-    Gcircumflex="G",gcircumflex="g",
-    Hcircumflex="H",hcircumflex="h",
-    Icircumflex="I",icircumflex="i",
-    Jcircumflex="J",jcircumflex="j",
-    Ocircumflex="O",ocircumflex="o",
-    Scircumflex="S",scircumflex="s",
-    Ucircumflex="U",ucircumflex="u",
-    Wcircumflex="W",wcircumflex="w",
-    Ycircumflex="Y",ycircumflex="y",
-    Agrave="A",agrave="a",
-    Egrave="E",egrave="e",
-    Igrave="I",igrave="i",
-    Ograve="O",ograve="o",
-    Ugrave="U",ugrave="u",
-    Ygrave="Y",ygrave="y",
-    Atilde="A",atilde="a",
-    Itilde="I",itilde="i",
-    Otilde="O",otilde="o",
-    Utilde="U",utilde="u",
-    Ntilde="N",ntilde="n",
-    Adiaeresis="A",adiaeresis="a",Adieresis="A",adieresis="a",
-    Ediaeresis="E",ediaeresis="e",Edieresis="E",edieresis="e",
-    Idiaeresis="I",idiaeresis="i",Idieresis="I",idieresis="i",
-    Odiaeresis="O",odiaeresis="o",Odieresis="O",odieresis="o",
-    Udiaeresis="U",udiaeresis="u",Udieresis="U",udieresis="u",
-    Ydiaeresis="Y",ydiaeresis="y",Ydieresis="Y",ydieresis="y",
-    Aacute="A",aacute="a",
-    Cacute="C",cacute="c",
-    Eacute="E",eacute="e",
-    Iacute="I",iacute="i",
-    Lacute="L",lacute="l",
-    Nacute="N",nacute="n",
-    Oacute="O",oacute="o",
-    Racute="R",racute="r",
-    Sacute="S",sacute="s",
-    Uacute="U",uacute="u",
-    Yacute="Y",yacute="y",
-    Zacute="Z",zacute="z",
-    Dstroke="D",dstroke="d",
-    Hstroke="H",hstroke="h",
-    Tstroke="T",tstroke="t",
-    Cdotaccent="C",cdotaccent="c",
-    Edotaccent="E",edotaccent="e",
-    Gdotaccent="G",gdotaccent="g",
-    Idotaccent="I",idotaccent="i",
-    Zdotaccent="Z",zdotaccent="z",
-    Amacron="A",amacron="a",
-    Emacron="E",emacron="e",
-    Imacron="I",imacron="i",
-    Omacron="O",omacron="o",
-    Umacron="U",umacron="u",
-    Ccedilla="C",ccedilla="c",
-    Kcedilla="K",kcedilla="k",
-    Lcedilla="L",lcedilla="l",
-    Ncedilla="N",ncedilla="n",
-    Rcedilla="R",rcedilla="r",
-    Scedilla="S",scedilla="s",
-    Tcedilla="T",tcedilla="t",
-    Ohungarumlaut="O",ohungarumlaut="o",
-    Uhungarumlaut="U",uhungarumlaut="u",
-    Aogonek="A",aogonek="a",
-    Eogonek="E",eogonek="e",
-    Iogonek="I",iogonek="i",
-    Uogonek="U",uogonek="u",
-    Aring="A",aring="a",
-    Uring="U",uring="u",
-    Abreve="A",abreve="a",
-    Ebreve="E",ebreve="e",
-    Gbreve="G",gbreve="g",
-    Ibreve="I",ibreve="i",
-    Obreve="O",obreve="o",
-    Ubreve="U",ubreve="u",
-    Ccaron="C",ccaron="c",
-    Dcaron="D",dcaron="d",
-    Ecaron="E",ecaron="e",
-    Lcaron="L",lcaron="l",
-    Ncaron="N",ncaron="n",
-    Rcaron="R",rcaron="r",
-    Scaron="S",scaron="s",
-    Tcaron="T",tcaron="t",
-    Zcaron="Z",zcaron="z",
-    dotlessI="I",dotlessi="i",
-    dotlessJ="J",dotlessj="j",
-    AEligature="AE",aeligature="ae",AE="AE",ae="ae",
-    OEligature="OE",oeligature="oe",OE="OE",oe="oe",
-    IJligature="IJ",ijligature="ij",IJ="IJ",ij="ij",
-    Lstroke="L",lstroke="l",Lslash="L",lslash="l",
-    Ostroke="O",ostroke="o",Oslash="O",oslash="o",
-    Ssharp="SS",ssharp="ss",
-    Aumlaut="A",aumlaut="a",
-    Eumlaut="E",eumlaut="e",
-    Iumlaut="I",iumlaut="i",
-    Oumlaut="O",oumlaut="o",
-    Uumlaut="U",uumlaut="u",
-  }
-}
-
-end -- closure
-
-do -- begin closure to overcome local limits and interference
-
 if not modules then modules={} end modules ['luatex-fonts-tfm']={
   version=1.001,
   comment="companion to luatex-*.tex",
@@ -6334,7 +5079,7 @@ local report_otf=logs.reporter("fonts","otf loading")
 local fonts=fonts
 local otf=fonts.handlers.otf
 otf.glists={ "gsub","gpos" }
-otf.version=2.745 
+otf.version=2.743 
 otf.cache=containers.define("fonts","otf",otf.version,true)
 local fontdata=fonts.hashes.identifiers
 local chardata=characters and characters.data 
@@ -6354,28 +5099,17 @@ local packdata=true
 local syncspace=true
 local forcenotdef=false
 local includesubfonts=false
-local overloadkerns=false 
-local applyruntimefixes=fonts.treatments and fonts.treatments.applyfixes
 local wildcard="*"
 local default="dflt"
 local fontloaderfields=fontloader.fields
 local mainfields=nil
 local glyphfields=nil 
-local formats=fonts.formats
-formats.otf="opentype"
-formats.ttf="truetype"
-formats.ttc="truetype"
-formats.dfont="truetype"
 registerdirective("fonts.otf.loader.cleanup",function(v) cleanup=tonumber(v) or (v and 1) or 0 end)
 registerdirective("fonts.otf.loader.force",function(v) forceload=v end)
 registerdirective("fonts.otf.loader.usemetatables",function(v) usemetatables=v end)
 registerdirective("fonts.otf.loader.pack",function(v) packdata=v end)
 registerdirective("fonts.otf.loader.syncspace",function(v) syncspace=v end)
 registerdirective("fonts.otf.loader.forcenotdef",function(v) forcenotdef=v end)
-registerdirective("fonts.otf.loader.overloadkerns",function(v) overloadkerns=v end)
-local function otf_format(filename)
-  return formats[lower(file.suffix(filename))]
-end
 local function load_featurefile(raw,featurefile)
   if featurefile and featurefile~="" then
     if trace_loading then
@@ -6562,7 +5296,7 @@ end
 function enhancers.register(what,action) 
   actions[what]=action
 end
-function otf.load(filename,sub,featurefile) 
+function otf.load(filename,format,sub,featurefile)
   local base=file.basename(file.removesuffix(filename))
   local name=file.removesuffix(base)
   local attr=lfs.attributes(filename)
@@ -6660,7 +5394,7 @@ function otf.load(filename,sub,featurefile)
       data={
         size=size,
         time=time,
-        format=otf_format(filename),
+        format=format,
         featuredata=featurefiles,
         resources={
           filename=resolvers.unresolve(filename),
@@ -6726,9 +5460,6 @@ function otf.load(filename,sub,featurefile)
       report_otf("loading from cache using hash %a",hash)
     end
     enhance("unpack",data,filename,nil,false)
-    if applyruntimefixes then
-      applyruntimefixes(filename,data)
-    end
     enhance("add dimensions",data,filename,nil,false)
     if trace_sequences then
       showfeatureorder(data,filename)
@@ -7659,93 +6390,74 @@ actions["merge kern classes"]=function(data,filename,raw)
     local resources=data.resources
     local unicodes=resources.unicodes
     local splitter=data.helpers.tounicodetable
-    local ignored=0
-    local blocked=0
     for gp=1,#gposlist do
       local gpos=gposlist[gp]
       local subtables=gpos.subtables
       if subtables then
-        local first_done={} 
-        local split={} 
         for s=1,#subtables do
           local subtable=subtables[s]
           local kernclass=subtable.kernclass 
-          local lookup=subtable.lookup or subtable.name
           if kernclass then 
-            if #kernclass>0 then
-              kernclass=kernclass[1]
-              lookup=type(kernclass.lookup)=="string" and kernclass.lookup or lookup
-              report_otf("fixing kernclass table of lookup %a",lookup)
-            end
-            local firsts=kernclass.firsts
-            local seconds=kernclass.seconds
-            local offsets=kernclass.offsets
-            for n,s in next,firsts do
-              split[s]=split[s] or lpegmatch(splitter,s)
-            end
-            local maxseconds=0
-            for n,s in next,seconds do
-              if n>maxseconds then
-                maxseconds=n
+            local split={} 
+            for k=1,#kernclass do
+              local kcl=kernclass[k]
+              local firsts=kcl.firsts
+              local seconds=kcl.seconds
+              local offsets=kcl.offsets
+              local lookups=kcl.lookup 
+              if type(lookups)~="table" then
+                lookups={ lookups }
               end
-              split[s]=split[s] or lpegmatch(splitter,s)
-            end
-            for fk=1,#firsts do 
-              local fv=firsts[fk]
-              local splt=split[fv]
-              if splt then
-                local extrakerns={}
-                local baseoffset=(fk-1)*maxseconds
-                for sk=2,maxseconds do 
-                  local sv=seconds[sk]
-                  local splt=split[sv]
-                  if splt then 
-                    local offset=offsets[baseoffset+sk]
-                    if offset then
-                      for i=1,#splt do
-                        extrakerns[splt[i]]=offset
-                      end
-                    end
-                  end
+              for n,s in next,firsts do
+                split[s]=split[s] or lpegmatch(splitter,s)
+              end
+              local maxseconds=0
+              for n,s in next,seconds do
+                if n>maxseconds then
+                  maxseconds=n
                 end
-                for i=1,#splt do
-                  local first_unicode=splt[i]
-                  if first_done[first_unicode] then
-                    report_otf("lookup %a: ignoring further kerns of %C",lookup,first_unicode)
-                    blocked=blocked+1
-                  else
-                    first_done[first_unicode]=true
-                    local description=descriptions[first_unicode]
-                    if description then
-                      local kerns=description.kerns
-                      if not kerns then
-                        kerns={} 
-                        description.kerns=kerns
-                      end
-                      local lookupkerns=kerns[lookup]
-                      if not lookupkerns then
-                        lookupkerns={}
-                        kerns[lookup]=lookupkerns
+                split[s]=split[s] or lpegmatch(splitter,s)
+              end
+              for l=1,#lookups do
+                local lookup=lookups[l]
+                for fk=1,#firsts do 
+                  local fv=firsts[fk]
+                  local splt=split[fv]
+                  if splt then
+                    local extrakerns={}
+                    local baseoffset=(fk-1)*maxseconds
+                    for sk=2,maxseconds do 
+                      local sv=seconds[sk]
+                      local splt=split[sv]
+                      if splt then 
+                        local offset=offsets[baseoffset+sk]
+                        if offset then
+                          for i=1,#splt do
+                            extrakerns[splt[i]]=offset
+                          end
+                        end
                       end
-                      if overloadkerns then
-                        for second_unicode,kern in next,extrakerns do
-                          lookupkerns[second_unicode]=kern
+                    end
+                    for i=1,#splt do
+                      local first_unicode=splt[i]
+                      local description=descriptions[first_unicode]
+                      if description then
+                        local kerns=description.kerns
+                        if not kerns then
+                          kerns={} 
+                          description.kerns=kerns
+                        end
+                        local lookupkerns=kerns[lookup]
+                        if not lookupkerns then
+                          lookupkerns={}
+                          kerns[lookup]=lookupkerns
                         end
-                      else
                         for second_unicode,kern in next,extrakerns do
-                          local k=lookupkerns[second_unicode]
-                          if not k then
-                            lookupkerns[second_unicode]=kern
-                          elseif k~=kern then
-                            if trace_loading then
-                              report_otf("lookup %a: ignoring overload of kern between %C and %C, rejecting %a, keeping %a",lookup,first_unicode,second_unicode,k,kern)
-                            end
-                            ignored=ignored+1
-                          end
+                          lookupkerns[second_unicode]=kern
                         end
+                      elseif trace_loading then
+                        report_otf("no glyph data for %U",first_unicode)
                       end
-                    elseif trace_loading then
-                      report_otf("no glyph data for %U",first_unicode)
                     end
                   end
                 end
@@ -7756,12 +6468,6 @@ actions["merge kern classes"]=function(data,filename,raw)
         end
       end
     end
-    if ignored>0 then
-      report_otf("%s kern overloads ignored",ignored)
-    end
-    if blocked>0 then
-      report_otf("%s succesive kerns blocked",blocked)
-    end
   end
 end
 actions["check glyphs"]=function(data,filename,raw)
@@ -7975,19 +6681,10 @@ local function copytotfm(data,cache_id)
         end
       end
     end
-    local filename=constructors.checkedfilename(resources)
-    local fontname=metadata.fontname
-    local fullname=metadata.fullname or fontname
-    local units=metadata.units_per_em or 1000
-    if units==0 then 
-      units=1000 
-      metadata.units_per_em=1000
-      report_otf("changing %a units to %a",0,units)
-    end
     local monospaced=metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose.proportion=="Monospaced")
     local charwidth=pfminfo.avgwidth 
-    local charxheight=pfminfo.os2_xheight and pfminfo.os2_xheight>0 and pfminfo.os2_xheight
     local italicangle=metadata.italicangle
+    local charxheight=pfminfo.os2_xheight and pfminfo.os2_xheight>0 and pfminfo.os2_xheight
     properties.monospaced=monospaced
     parameters.italicangle=italicangle
     parameters.charwidth=charwidth
@@ -8016,6 +6713,14 @@ local function copytotfm(data,cache_id)
       end
     end
     spaceunits=tonumber(spaceunits) or 500
+    local filename=constructors.checkedfilename(resources)
+    local fontname=metadata.fontname
+    local fullname=metadata.fullname or fontname
+    local units=metadata.units_per_em or 1000
+    if units==0 then 
+      units=1000
+      metadata.units_per_em=1000
+    end
     parameters.slant=0
     parameters.space=spaceunits     
     parameters.space_stretch=units/2  
@@ -8024,10 +6729,10 @@ local function copytotfm(data,cache_id)
     parameters.quad=units   
     if spaceunits<2*units/5 then
     end
-    if italicangle and italicangle~=0 then
+    if italicangle then
       parameters.italicangle=italicangle
       parameters.italicfactor=math.cos(math.rad(90+italicangle))
-      parameters.slant=- math.tan(italicangle*math.pi/180)
+      parameters.slant=- math.round(math.tan(italicangle*math.pi/180))
     end
     if monospaced then
       parameters.space_stretch=0
@@ -8054,7 +6759,7 @@ local function copytotfm(data,cache_id)
     parameters.units=units
     properties.space=spacer
     properties.encodingbytes=2
-    properties.format=data.format or otf_format(filename) or formats.otf
+    properties.format=data.format or fonts.formats[filename] or "opentype"
     properties.noglyphnames=true
     properties.filename=filename
     properties.fontname=fontname
@@ -8079,8 +6784,9 @@ local function otftotfm(specification)
     local name=specification.name
     local sub=specification.sub
     local filename=specification.filename
+    local format=specification.format
     local features=specification.features.normal
-    local rawdata=otf.load(filename,sub,features and features.featurefile)
+    local rawdata=otf.load(filename,format,sub,features and features.featurefile)
     if rawdata and next(rawdata) then
       rawdata.lookuphash={}
       tfmdata=copytotfm(rawdata,cache_id)
@@ -8162,33 +6868,41 @@ function otf.collectlookups(rawdata,kind,script,language)
   end
   return nil,nil
 end
-local function check_otf(forced,specification,suffix)
+local function check_otf(forced,specification,suffix,what)
   local name=specification.name
   if forced then
-    name=specification.forcedname 
+    name=file.addsuffix(name,suffix,true)
   end
   local fullname=findbinfile(name,suffix) or ""
   if fullname=="" then
     fullname=fonts.names.getfilename(name,suffix) or ""
   end
-  if fullname~="" and not fonts.names.ignoredfile(fullname) then
+  if fullname~="" then
     specification.filename=fullname
+    specification.format=what
     return read_from_otf(specification)
   end
 end
-local function opentypereader(specification,suffix)
+local function opentypereader(specification,suffix,what)
   local forced=specification.forced or ""
-  if formats[forced] then
-    return check_otf(true,specification,forced)
+  if forced=="otf" then
+    return check_otf(true,specification,forced,"opentype")
+  elseif forced=="ttf" or forced=="ttc" or forced=="dfont" then
+    return check_otf(true,specification,forced,"truetype")
   else
-    return check_otf(false,specification,suffix)
+    return check_otf(false,specification,suffix,what)
   end
 end
-readers.opentype=opentypereader 
-function readers.otf (specification) return opentypereader(specification,"otf") end
-function readers.ttf (specification) return opentypereader(specification,"ttf") end
-function readers.ttc (specification) return opentypereader(specification,"ttf") end
-function readers.dfont(specification) return opentypereader(specification,"ttf") end
+readers.opentype=opentypereader
+local formats=fonts.formats
+formats.otf="opentype"
+formats.ttf="truetype"
+formats.ttc="truetype"
+formats.dfont="truetype"
+function readers.otf (specification) return opentypereader(specification,"otf",formats.otf ) end
+function readers.ttf (specification) return opentypereader(specification,"ttf",formats.ttf ) end
+function readers.ttc (specification) return opentypereader(specification,"ttf",formats.ttc ) end
+function readers.dfont(specification) return opentypereader(specification,"ttf",formats.dfont) end
 function otf.scriptandlanguage(tfmdata,attr)
   local properties=tfmdata.properties
   return properties.script or "dflt",properties.language or "dflt"
@@ -8780,24 +7494,11 @@ local injections=nodes.injections
 local nodecodes=nodes.nodecodes
 local glyph_code=nodecodes.glyph
 local kern_code=nodecodes.kern
-local nuts=nodes.nuts
-local nodepool=nuts.pool
+local nodepool=nodes.pool
 local newkern=nodepool.kern
-local tonode=nuts.tonode
-local tonut=nuts.tonut
-local getfield=nuts.getfield
-local getnext=nuts.getnext
-local getprev=nuts.getprev
-local getid=nuts.getid
-local getattr=nuts.getattr
-local getfont=nuts.getfont
-local getsubtype=nuts.getsubtype
-local getchar=nuts.getchar
-local setfield=nuts.setfield
-local setattr=nuts.setattr
-local traverse_id=nuts.traverse_id
-local insert_node_before=nuts.insert_before
-local insert_node_after=nuts.insert_after
+local traverse_id=node.traverse_id
+local insert_node_before=node.insert_before
+local insert_node_after=node.insert_after
 local a_kernpair=attributes.private('kernpair')
 local a_ligacomp=attributes.private('ligacomp')
 local a_markbase=attributes.private('markbase')
@@ -8816,21 +7517,21 @@ function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmne
   local dx,dy=factor*(exit[1]-entry[1]),factor*(exit[2]-entry[2])
   local ws,wn=tfmstart.width,tfmnext.width
   local bound=#cursives+1
-  setattr(start,a_cursbase,bound)
-  setattr(nxt,a_curscurs,bound)
+  start[a_cursbase]=bound
+  nxt[a_curscurs]=bound
   cursives[bound]={ rlmode,dx,dy,ws,wn }
   return dx,dy,bound
 end
 function injections.setpair(current,factor,rlmode,r2lflag,spec,tfmchr)
   local x,y,w,h=factor*spec[1],factor*spec[2],factor*spec[3],factor*spec[4]
   if x~=0 or w~=0 or y~=0 or h~=0 then
-    local bound=getattr(current,a_kernpair)
+    local bound=current[a_kernpair]
     if bound then
       local kb=kerns[bound]
       kb[2],kb[3],kb[4],kb[5]=(kb[2] or 0)+x,(kb[3] or 0)+y,(kb[4] or 0)+w,(kb[5] or 0)+h
     else
       bound=#kerns+1
-      setattr(current,a_kernpair,bound)
+      current[a_kernpair]=bound
       kerns[bound]={ rlmode,x,y,w,h,r2lflag,tfmchr.width }
     end
     return x,y,w,h,bound
@@ -8841,35 +7542,35 @@ function injections.setkern(current,factor,rlmode,x,tfmchr)
   local dx=factor*x
   if dx~=0 then
     local bound=#kerns+1
-    setattr(current,a_kernpair,bound)
+    current[a_kernpair]=bound
     kerns[bound]={ rlmode,dx }
     return dx,bound
   else
     return 0,0
   end
 end
-function injections.setmark(start,base,factor,rlmode,ba,ma,index,baseismark) 
+function injections.setmark(start,base,factor,rlmode,ba,ma,index) 
   local dx,dy=factor*(ba[1]-ma[1]),factor*(ba[2]-ma[2])   
-  local bound=getattr(base,a_markbase)          
+  local bound=base[a_markbase]          
   local index=1
   if bound then
     local mb=marks[bound]
     if mb then
       index=#mb+1
       mb[index]={ dx,dy,rlmode }
-      setattr(start,a_markmark,bound)
-      setattr(start,a_markdone,index)
+      start[a_markmark]=bound
+      start[a_markdone]=index
       return dx,dy,bound
     else
-      report_injections("possible problem, %U is base mark without data (id %a)",getchar(base),bound)
+      report_injections("possible problem, %U is base mark without data (id %a)",base.char,bound)
     end
   end
   index=index or 1
   bound=#marks+1
-  setattr(base,a_markbase,bound)
-  setattr(start,a_markmark,bound)
-  setattr(start,a_markdone,index)
-  marks[bound]={ [index]={ dx,dy,rlmode,baseismark } }
+  base[a_markbase]=bound
+  start[a_markmark]=bound
+  start[a_markdone]=index
+  marks[bound]={ [index]={ dx,dy,rlmode } }
   return dx,dy,bound
 end
 local function dir(n)
@@ -8878,15 +7579,15 @@ end
 local function trace(head)
   report_injections("begin run")
   for n in traverse_id(glyph_code,head) do
-    if getsubtype(n)<256 then
-      local kp=getattr(n,a_kernpair)
-      local mb=getattr(n,a_markbase)
-      local mm=getattr(n,a_markmark)
-      local md=getattr(n,a_markdone)
-      local cb=getattr(n,a_cursbase)
-      local cc=getattr(n,a_curscurs)
-      local char=getchar(n)
-      report_injections("font %s, char %U, glyph %c",getfont(n),char,char)
+    if n.subtype<256 then
+      local kp=n[a_kernpair]
+      local mb=n[a_markbase]
+      local mm=n[a_markmark]
+      local md=n[a_markdone]
+      local cb=n[a_cursbase]
+      local cc=n[a_curscurs]
+      local char=n.char
+      report_injections("font %s, char %U, glyph %c",n.font,char,char)
       if kp then
         local k=kerns[kp]
         if k[3] then
@@ -8927,23 +7628,21 @@ local function show_result(head)
   local current=head
   local skipping=false
   while current do
-    local id=getid(current)
+    local id=current.id
     if id==glyph_code then
-      report_injections("char: %C, width %p, xoffset %p, yoffset %p",
-        getchar(current),getfield(current,"width"),getfield(current,"xoffset"),getfield(current,"yoffset"))
+      report_injections("char: %C, width %p, xoffset %p, yoffset %p",current.char,current.width,current.xoffset,current.yoffset)
       skipping=false
     elseif id==kern_code then
-      report_injections("kern: %p",getfield(current,"kern"))
+      report_injections("kern: %p",current.kern)
       skipping=false
     elseif not skipping then
       report_injections()
       skipping=true
     end
-    current=getnext(current)
+    current=current.next
   end
 end
 function injections.handler(head,where,keep)
-  head=tonut(head)
   local has_marks,has_cursives,has_kerns=next(marks),next(cursives),next(kerns)
   if has_marks or has_cursives then
     if trace_injections then
@@ -8953,18 +7652,17 @@ function injections.handler(head,where,keep)
     if has_kerns then 
       local nf,tm=nil,nil
       for n in traverse_id(glyph_code,head) do 
-        if getsubtype(n)<256 then
+        if n.subtype<256 then
           nofvalid=nofvalid+1
           valid[nofvalid]=n
-          local f=getfont(n)
-          if f~=nf then
-            nf=f
-            tm=fontdata[nf].resources.marks 
+          if n.font~=nf then
+            nf=n.font
+            tm=fontdata[nf].resources.marks
           end
           if tm then
-            mk[n]=tm[getchar(n)]
+            mk[n]=tm[n.char]
           end
-          local k=getattr(n,a_kernpair)
+          local k=n[a_kernpair]
           if k then
             local kk=kerns[k]
             if kk then
@@ -8984,16 +7682,15 @@ function injections.handler(head,where,keep)
     else
       local nf,tm=nil,nil
       for n in traverse_id(glyph_code,head) do
-        if getsubtype(n)<256 then
+        if n.subtype<256 then
           nofvalid=nofvalid+1
           valid[nofvalid]=n
-          local f=getfont(n)
-          if f~=nf then
-            nf=f
-            tm=fontdata[nf].resources.marks 
+          if n.font~=nf then
+            nf=n.font
+            tm=fontdata[nf].resources.marks
           end
           if tm then
-            mk[n]=tm[getchar(n)]
+            mk[n]=tm[n.char]
           end
         end
       end
@@ -9002,7 +7699,7 @@ function injections.handler(head,where,keep)
       local cx={}
       if has_kerns and next(ky) then
         for n,k in next,ky do
-          setfield(n,"yoffset",k)
+          n.yoffset=k
         end
       end
       if has_cursives then
@@ -9011,9 +7708,9 @@ function injections.handler(head,where,keep)
         for i=1,nofvalid do 
           local n=valid[i]
           if not mk[n] then
-            local n_cursbase=getattr(n,a_cursbase)
+            local n_cursbase=n[a_cursbase]
             if p_cursbase then
-              local n_curscurs=getattr(n,a_curscurs)
+              local n_curscurs=n[a_curscurs]
               if p_cursbase==n_curscurs then
                 local c=cursives[n_curscurs]
                 if c then
@@ -9036,20 +7733,20 @@ function injections.handler(head,where,keep)
                 end
               end
             elseif maxt>0 then
-              local ny=getfield(n,"yoffset")
+              local ny=n.yoffset
               for i=maxt,1,-1 do
                 ny=ny+d[i]
                 local ti=t[i]
-                setfield(ti,"yoffset",getfield(ti,"yoffset")+ny)
+                ti.yoffset=ti.yoffset+ny
               end
               maxt=0
             end
             if not n_cursbase and maxt>0 then
-              local ny=getfield(n,"yoffset")
+              local ny=n.yoffset
               for i=maxt,1,-1 do
                 ny=ny+d[i]
                 local ti=t[i]
-                setfield(ti,"yoffset",ny)
+                ti.yoffset=ny
               end
               maxt=0
             end
@@ -9057,11 +7754,11 @@ function injections.handler(head,where,keep)
           end
         end
         if maxt>0 then
-          local ny=getfield(n,"yoffset")
+          local ny=n.yoffset
           for i=maxt,1,-1 do
             ny=ny+d[i]
             local ti=t[i]
-            setfield(ti,"yoffset",ny)
+            ti.yoffset=ny
           end
           maxt=0
         end
@@ -9072,66 +7769,52 @@ function injections.handler(head,where,keep)
       if has_marks then
         for i=1,nofvalid do
           local p=valid[i]
-          local p_markbase=getattr(p,a_markbase)
+          local p_markbase=p[a_markbase]
           if p_markbase then
             local mrks=marks[p_markbase]
             local nofmarks=#mrks
-            for n in traverse_id(glyph_code,getnext(p)) do
-              local n_markmark=getattr(n,a_markmark)
+            for n in traverse_id(glyph_code,p.next) do
+              local n_markmark=n[a_markmark]
               if p_markbase==n_markmark then
-                local index=getattr(n,a_markdone) or 1
+                local index=n[a_markdone] or 1
                 local d=mrks[index]
                 if d then
                   local rlmode=d[3]
                   local k=wx[p]
-                  local px=getfield(p,"xoffset")
-                  local ox=0
                   if k then
                     local x=k[2]
                     local w=k[4]
                     if w then
                       if rlmode and rlmode>=0 then
-                        ox=px-getfield(p,"width")+d[1]-(w-x)
+                        n.xoffset=p.xoffset-p.width+d[1]-(w-x)
                       else
-                        ox=px-d[1]-x
+                        n.xoffset=p.xoffset-d[1]-x
                       end
                     else
                       if rlmode and rlmode>=0 then
-                        ox=px-getfield(p,"width")+d[1]
+                        n.xoffset=p.xoffset-p.width+d[1]
                       else
-                        ox=px-d[1]-x
+                        n.xoffset=p.xoffset-d[1]-x
                       end
                     end
                   else
-                    local wp=getfield(p,"width")
-                    local wn=getfield(n,"width") 
                     if rlmode and rlmode>=0 then
-                      ox=px-wp+d[1]
+                      n.xoffset=p.xoffset-p.width+d[1]
                     else
-                      ox=px-d[1]
-                    end
-                    if wn~=0 then
-                      insert_node_before(head,n,newkern(-wn/2))
-                      insert_node_after(head,n,newkern(-wn/2))
+                      n.xoffset=p.xoffset-d[1]
                     end
                   end
-                  setfield(n,"xoffset",ox)
-                  local py=getfield(p,"yoffset")
-                  local oy=0
                   if mk[p] then
-                    oy=py+d[2]
+                    n.yoffset=p.yoffset+d[2]
                   else
-                    oy=getfield(n,"yoffset")+py+d[2]
+                    n.yoffset=n.yoffset+p.yoffset+d[2]
                   end
-                  setfield(n,"yoffset",oy)
                   if nofmarks==1 then
                     break
                   else
                     nofmarks=nofmarks-1
                   end
                 end
-              elseif not n_markmark then
-                break 
               else
               end
             end
@@ -9183,7 +7866,6 @@ function injections.handler(head,where,keep)
       if not keep then
         kerns={}
       end
-head=tonode(head)
       return head,true
     elseif not keep then
       kerns,cursives,marks={},{},{}
@@ -9193,14 +7875,14 @@ head=tonode(head)
       trace(head)
     end
     for n in traverse_id(glyph_code,head) do
-      if getsubtype(n)<256 then
-        local k=getattr(n,a_kernpair)
+      if n.subtype<256 then
+        local k=n[a_kernpair]
         if k then
           local kk=kerns[k]
           if kk then
             local rl,x,y,w=kk[1],kk[2] or 0,kk[3],kk[4]
             if y and y~=0 then
-              setfield(n,"yoffset",y) 
+              n.yoffset=y 
             end
             if w then
               local wx=w-x
@@ -9231,10 +7913,10 @@ head=tonode(head)
     if not keep then
       kerns={}
     end
-    return tonode(head),true
+    return head,true
   else
   end
-  return tonode(head),false
+  return head,false
 end
 
 end -- closure
@@ -9262,7 +7944,6 @@ analyzers.useunicodemarks=false
 local a_state=attributes.private('state')
 local nodecodes=nodes.nodecodes
 local glyph_code=nodecodes.glyph
-local disc_code=nodecodes.disc
 local math_code=nodecodes.math
 local traverse_id=node.traverse_id
 local traverse_node_list=node.traverse
@@ -9295,11 +7976,6 @@ local features={
   medi=s_medi,
   fina=s_fina,
   isol=s_isol,
-  rphf=s_rphf,
-  half=s_half,
-  pref=s_pref,
-  blwf=s_blwf,
-  pstf=s_pstf,
 }
 analyzers.states=states
 analyzers.features=features
@@ -9334,7 +8010,7 @@ function analyzers.setstate(head,font)
         first,last,n=nil,nil,0
       end
     elseif id==disc_code then
-      current[a_state]=s_medi
+      current[a_state]=s_midi
       last=current
     else 
       if first and first==last then
@@ -9386,7 +8062,7 @@ local function analyzeprocessor(head,font,attr)
 end
 registerotffeature {
   name="analyze",
-  description="analysis of character classes",
+  description="analysis of (for instance) character classes",
   default=true,
   initializers={
     node=analyzeinitializer,
@@ -9649,25 +8325,12 @@ registertracker("otf.positions","otf.marks,otf.kerns,otf.cursive")
 registertracker("otf.actions","otf.replacements,otf.positions")
 registertracker("otf.injections","nodes.injections")
 registertracker("*otf.sample","otf.steps,otf.actions,otf.analyzing")
-local nuts=nodes.nuts
-local tonode=nuts.tonode
-local tonut=nuts.tonut
-local getfield=nuts.getfield
-local getnext=nuts.getnext
-local getprev=nuts.getprev
-local getid=nuts.getid
-local getattr=nuts.getattr
-local getfont=nuts.getfont
-local getsubtype=nuts.getsubtype
-local getchar=nuts.getchar
-local setfield=nuts.setfield
-local setattr=nuts.setattr
-local insert_node_after=nuts.insert_after
-local delete_node=nuts.delete
-local copy_node=nuts.copy
-local find_node_tail=nuts.tail
-local flush_node_list=nuts.flush_list
-local end_of_math=nuts.end_of_math
+local insert_node_after=node.insert_after
+local delete_node=nodes.delete
+local copy_node=node.copy
+local find_node_tail=node.tail or node.slide
+local flush_node_list=node.flush_list
+local end_of_math=node.end_of_math
 local setmetatableindex=table.setmetatableindex
 local zwnj=0x200C
 local zwj=0x200D
@@ -9676,7 +8339,6 @@ local default="dflt"
 local nodecodes=nodes.nodecodes
 local whatcodes=nodes.whatcodes
 local glyphcodes=nodes.glyphcodes
-local disccodes=nodes.disccodes
 local glyph_code=nodecodes.glyph
 local glue_code=nodecodes.glue
 local disc_code=nodecodes.disc
@@ -9684,7 +8346,6 @@ local whatsit_code=nodecodes.whatsit
 local math_code=nodecodes.math
 local dir_code=whatcodes.dir
 local localpar_code=whatcodes.localpar
-local discretionary_code=disccodes.discretionary
 local ligature_code=glyphcodes.ligature
 local privateattribute=attributes.private
 local a_state=privateattribute('state')
@@ -9778,83 +8439,83 @@ local function pref(kind,lookupname)
   return formatters["feature %a, lookup %a"](kind,lookupname)
 end
 local function copy_glyph(g) 
-  local components=getfield(g,"components")
+  local components=g.components
   if components then
-    setfield(g,"components",nil)
+    g.components=nil
     local n=copy_node(g)
-    setfield(g,"components",components)
+    g.components=components
     return n
   else
     return copy_node(g)
   end
 end
 local function markstoligature(kind,lookupname,head,start,stop,char)
-  if start==stop and getchar(start)==char then
+  if start==stop and start.char==char then
     return head,start
   else
-    local prev=getprev(start)
-    local next=getnext(stop)
-    setfield(start,"prev",nil)
-    setfield(stop,"next",nil)
+    local prev=start.prev
+    local next=stop.next
+    start.prev=nil
+    stop.next=nil
     local base=copy_glyph(start)
     if head==start then
       head=base
     end
-    setfield(base,"char",char)
-    setfield(base,"subtype",ligature_code)
-    setfield(base,"components",start)
+    base.char=char
+    base.subtype=ligature_code
+    base.components=start
     if prev then
-      setfield(prev,"next",base)
+      prev.next=base
     end
     if next then
-      setfield(next,"prev",base)
+      next.prev=base
     end
-    setfield(base,"next",next)
-    setfield(base,"prev",prev)
+    base.next=next
+    base.prev=prev
     return head,base
   end
 end
 local function getcomponentindex(start)
-  if getid(start)~=glyph_code then
+  if start.id~=glyph_code then
     return 0
-  elseif getsubtype(start)==ligature_code then
+  elseif start.subtype==ligature_code then
     local i=0
-    local components=getfield(start,"components")
+    local components=start.components
     while components do
       i=i+getcomponentindex(components)
-      components=getnext(components)
+      components=components.next
     end
     return i
-  elseif not marks[getchar(start)] then
+  elseif not marks[start.char] then
     return 1
   else
     return 0
   end
 end
 local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound) 
-  if start==stop and getchar(start)==char then
-    setfield(start,"char",char)
+  if start==stop and start.char==char then
+    start.char=char
     return head,start
   end
-  local prev=getprev(start)
-  local next=getnext(stop)
-  setfield(start,"prev",nil)
-  setfield(stop,"next",nil)
+  local prev=start.prev
+  local next=stop.next
+  start.prev=nil
+  stop.next=nil
   local base=copy_glyph(start)
   if start==head then
     head=base
   end
-  setfield(base,"char",char)
-  setfield(base,"subtype",ligature_code)
-  setfield(base,"components",start) 
+  base.char=char
+  base.subtype=ligature_code
+  base.components=start 
   if prev then
-    setfield(prev,"next",base)
+    prev.next=base
   end
   if next then
-    setfield(next,"prev",base)
+    next.prev=base
   end
-  setfield(base,"next",next)
-  setfield(base,"prev",prev)
+  base.next=next
+  base.prev=prev
   if not discfound then
     local deletemarks=markflag~="mark"
     local components=start
@@ -9863,42 +8524,42 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun
     local head=base
     local current=base
     while start do
-      local char=getchar(start)
+      local char=start.char
       if not marks[char] then
         baseindex=baseindex+componentindex
         componentindex=getcomponentindex(start)
       elseif not deletemarks then 
-        setattr(start,a_ligacomp,baseindex+(getattr(start,a_ligacomp) or componentindex))
+        start[a_ligacomp]=baseindex+(start[a_ligacomp] or componentindex)
         if trace_marks then
-          logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),getattr(start,a_ligacomp))
+          logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),start[a_ligacomp])
         end
         head,current=insert_node_after(head,current,copy_node(start)) 
       elseif trace_marks then
         logwarning("%s: delete mark %s",pref(kind,lookupname),gref(char))
       end
-      start=getnext(start)
+      start=start.next
     end
-    local start=getnext(current)
-    while start and getid(start)==glyph_code do
-      local char=getchar(start)
+    local start=current.next
+    while start and start.id==glyph_code do
+      local char=start.char
       if marks[char] then
-        setattr(start,a_ligacomp,baseindex+(getattr(start,a_ligacomp) or componentindex))
+        start[a_ligacomp]=baseindex+(start[a_ligacomp] or componentindex)
         if trace_marks then
-          logwarning("%s: set mark %s, gets index %s",pref(kind,lookupname),gref(char),getattr(start,a_ligacomp))
+          logwarning("%s: set mark %s, gets index %s",pref(kind,lookupname),gref(char),start[a_ligacomp])
         end
       else
         break
       end
-      start=getnext(start)
+      start=start.next
     end
   end
   return head,base
 end
 function handlers.gsub_single(head,start,kind,lookupname,replacement)
   if trace_singles then
-    logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(getchar(start)),gref(replacement))
+    logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(start.char),gref(replacement))
   end
-  setfield(start,"char",replacement)
+  start.char=replacement
   return head,start,true
 end
 local function get_alternative_glyph(start,alternatives,value,trace_alternatives)
@@ -9924,7 +8585,7 @@ local function get_alternative_glyph(start,alternatives,value,trace_alternatives
         return false,trace_alternatives and formatters["invalid value %a, %s"](value,"out of range")
       end
     elseif value==0 then
-      return getchar(start),trace_alternatives and formatters["invalid value %a, %s"](value,"no change")
+      return start.char,trace_alternatives and formatters["invalid value %a, %s"](value,"no change")
     elseif value<1 then
       return alternatives[1],trace_alternatives and formatters["invalid value %a, taking %a"](value,1)
     else
@@ -9932,28 +8593,28 @@ local function get_alternative_glyph(start,alternatives,value,trace_alternatives
     end
   end
 end
-local function multiple_glyphs(head,start,multiple,ignoremarks)
+local function multiple_glyphs(head,start,multiple) 
   local nofmultiples=#multiple
   if nofmultiples>0 then
-    setfield(start,"char",multiple[1])
+    start.char=multiple[1]
     if nofmultiples>1 then
-      local sn=getnext(start)
-      for k=2,nofmultiples do
+      local sn=start.next
+      for k=2,nofmultiples do 
         local n=copy_node(start) 
-        setfield(n,"char",multiple[k])
-        setfield(n,"next",sn)
-        setfield(n,"prev",start)
+        n.char=multiple[k]
+        n.next=sn
+        n.prev=start
         if sn then
-          setfield(sn,"prev",n)
+          sn.prev=n
         end
-        setfield(start,"next",n)
+        start.next=n
         start=n
       end
     end
     return head,start,true
   else
     if trace_multiples then
-      logprocess("no multiple for %s",gref(getchar(start)))
+      logprocess("no multiple for %s",gref(start.char))
     end
     return head,start,false
   end
@@ -9963,34 +8624,34 @@ function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence
   local choice,comment=get_alternative_glyph(start,alternative,value,trace_alternatives)
   if choice then
     if trace_alternatives then
-      logprocess("%s: replacing %s by alternative %a to %s, %s",pref(kind,lookupname),gref(getchar(start)),choice,gref(choice),comment)
+      logprocess("%s: replacing %s by alternative %a to %s, %s",pref(kind,lookupname),gref(start.char),choice,gref(choice),comment)
     end
-    setfield(start,"char",choice)
+    start.char=choice
   else
     if trace_alternatives then
-      logwarning("%s: no variant %a for %s, %s",pref(kind,lookupname),value,gref(getchar(start)),comment)
+      logwarning("%s: no variant %a for %s, %s",pref(kind,lookupname),value,gref(start.char),comment)
     end
   end
   return head,start,true
 end
-function handlers.gsub_multiple(head,start,kind,lookupname,multiple,sequence)
+function handlers.gsub_multiple(head,start,kind,lookupname,multiple)
   if trace_multiples then
-    logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(getchar(start)),gref(multiple))
+    logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(start.char),gref(multiple))
   end
-  return multiple_glyphs(head,start,multiple,sequence.flags[1])
+  return multiple_glyphs(head,start,multiple)
 end
 function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
-  local s,stop,discfound=getnext(start),nil,false
-  local startchar=getchar(start)
+  local s,stop,discfound=start.next,nil,false
+  local startchar=start.char
   if marks[startchar] then
     while s do
-      local id=getid(s)
-      if id==glyph_code and getfont(s)==currentfont and getsubtype(s)<256 then
-        local lg=ligature[getchar(s)]
+      local id=s.id
+      if id==glyph_code and s.font==currentfont and s.subtype<256 then
+        local lg=ligature[s.char]
         if lg then
           stop=s
           ligature=lg
-          s=getnext(s)
+          s=s.next
         else
           break
         end
@@ -10002,9 +8663,9 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
       local lig=ligature.ligature
       if lig then
         if trace_ligatures then
-          local stopchar=getchar(stop)
+          local stopchar=stop.char
           head,start=markstoligature(kind,lookupname,head,start,stop,lig)
-          logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(getchar(start)))
+          logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
         else
           head,start=markstoligature(kind,lookupname,head,start,stop,lig)
         end
@@ -10015,18 +8676,18 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
   else
     local skipmark=sequence.flags[1]
     while s do
-      local id=getid(s)
-      if id==glyph_code and getsubtype(s)<256 then
-        if getfont(s)==currentfont then
-          local char=getchar(s)
+      local id=s.id
+      if id==glyph_code and s.subtype<256 then
+        if s.font==currentfont then
+          local char=s.char
           if skipmark and marks[char] then
-            s=getnext(s)
+            s=s.next
           else
             local lg=ligature[char]
             if lg then
               stop=s
               ligature=lg
-              s=getnext(s)
+              s=s.next
             else
               break
             end
@@ -10036,7 +8697,7 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
         end
       elseif id==disc_code then
         discfound=true
-        s=getnext(s)
+        s=s.next
       else
         break
       end
@@ -10045,9 +8706,9 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
       local lig=ligature.ligature
       if lig then
         if trace_ligatures then
-          local stopchar=getchar(stop)
+          local stopchar=stop.char
           head,start=toligature(kind,lookupname,head,start,stop,lig,skipmark,discfound)
-          logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(getchar(start)))
+          logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
         else
           head,start=toligature(kind,lookupname,head,start,stop,lig,skipmark,discfound)
         end
@@ -10059,16 +8720,16 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
   return head,start,false
 end
 function handlers.gpos_mark2base(head,start,kind,lookupname,markanchors,sequence)
-  local markchar=getchar(start)
+  local markchar=start.char
   if marks[markchar] then
-    local base=getprev(start) 
-    if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
-      local basechar=getchar(base)
+    local base=start.prev 
+    if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+      local basechar=base.char
       if marks[basechar] then
         while true do
-          base=getprev(base)
-          if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
-            basechar=getchar(base)
+          base=base.prev
+          if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+            basechar=base.char
             if not marks[basechar] then
               break
             end
@@ -10117,16 +8778,16 @@ function handlers.gpos_mark2base(head,start,kind,lookupname,markanchors,sequence
   return head,start,false
 end
 function handlers.gpos_mark2ligature(head,start,kind,lookupname,markanchors,sequence)
-  local markchar=getchar(start)
+  local markchar=start.char
   if marks[markchar] then
-    local base=getprev(start) 
-    if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
-      local basechar=getchar(base)
+    local base=start.prev 
+    if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+      local basechar=base.char
       if marks[basechar] then
         while true do
-          base=getprev(base)
-          if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
-            basechar=getchar(base)
+          base=base.prev
+          if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+            basechar=base.char
             if not marks[basechar] then
               break
             end
@@ -10138,7 +8799,7 @@ function handlers.gpos_mark2ligature(head,start,kind,lookupname,markanchors,sequ
           end
         end
       end
-      local index=getattr(start,a_ligacomp)
+      local index=start[a_ligacomp]
       local baseanchors=descriptions[basechar]
       if baseanchors then
         baseanchors=baseanchors.anchors
@@ -10183,22 +8844,22 @@ function handlers.gpos_mark2ligature(head,start,kind,lookupname,markanchors,sequ
   return head,start,false
 end
 function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence)
-  local markchar=getchar(start)
+  local markchar=start.char
   if marks[markchar] then
-    local base=getprev(start) 
-    local slc=getattr(start,a_ligacomp)
+    local base=start.prev 
+    local slc=start[a_ligacomp]
     if slc then 
       while base do
-        local blc=getattr(base,a_ligacomp)
+        local blc=base[a_ligacomp]
         if blc and blc~=slc then
-          base=getprev(base)
+          base=base.prev
         else
           break
         end
       end
     end
-    if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then 
-      local basechar=getchar(base)
+    if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then 
+      local basechar=base.char
       local baseanchors=descriptions[basechar]
       if baseanchors then
         baseanchors=baseanchors.anchors
@@ -10210,7 +8871,7 @@ function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence
               if al[anchor] then
                 local ma=markanchors[anchor]
                 if ma then
-                  local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,true)
+                  local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma)
                   if trace_marks then
                     logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
                       pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -10236,20 +8897,20 @@ function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence
   return head,start,false
 end
 function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence) 
-  local alreadydone=cursonce and getattr(start,a_cursbase)
+  local alreadydone=cursonce and start[a_cursbase]
   if not alreadydone then
     local done=false
-    local startchar=getchar(start)
+    local startchar=start.char
     if marks[startchar] then
       if trace_cursive then
         logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar))
       end
     else
-      local nxt=getnext(start)
-      while not done and nxt and getid(nxt)==glyph_code and getfont(nxt)==currentfont and getsubtype(nxt)<256 do
-        local nextchar=getchar(nxt)
+      local nxt=start.next
+      while not done and nxt and nxt.id==glyph_code and nxt.font==currentfont and nxt.subtype<256 do
+        local nextchar=nxt.char
         if marks[nextchar] then
-          nxt=getnext(nxt)
+          nxt=nxt.next
         else
           local entryanchors=descriptions[nextchar]
           if entryanchors then
@@ -10283,13 +8944,13 @@ function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence)
     return head,start,done
   else
     if trace_cursive and trace_details then
-      logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(getchar(start)),alreadydone)
+      logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
     end
     return head,start,false
   end
 end
 function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence)
-  local startchar=getchar(start)
+  local startchar=start.char
   local dx,dy,w,h=setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar])
   if trace_kerns then
     logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h)
@@ -10297,33 +8958,34 @@ function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence)
   return head,start,false
 end
 function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)
-  local snext=getnext(start)
+  local snext=start.next
   if not snext then
     return head,start,false
   else
     local prev,done=start,false
     local factor=tfmdata.parameters.factor
     local lookuptype=lookuptypes[lookupname]
-    while snext and getid(snext)==glyph_code and getfont(snext)==currentfont and getsubtype(snext)<256 do
-      local nextchar=getchar(snext)
+    while snext and snext.id==glyph_code and snext.font==currentfont and snext.subtype<256 do
+      local nextchar=snext.char
       local krn=kerns[nextchar]
       if not krn and marks[nextchar] then
         prev=snext
-        snext=getnext(snext)
+        snext=snext.next
       else
+        local krn=kerns[nextchar]
         if not krn then
         elseif type(krn)=="table" then
           if lookuptype=="pair" then 
             local a,b=krn[2],krn[3]
             if a and #a>0 then
-              local startchar=getchar(start)
+              local startchar=start.char
               local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
               if trace_kerns then
                 logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
               end
             end
             if b and #b>0 then
-              local startchar=getchar(start)
+              local startchar=start.char
               local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
               if trace_kerns then
                 logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
@@ -10336,7 +8998,7 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence)
         elseif krn~=0 then
           local k=setkern(snext,factor,rlmode,krn)
           if trace_kerns then
-            logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar))
+            logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar))
           end
           done=true
         end
@@ -10371,18 +9033,46 @@ function chainmores.chainsub(head,start,stop,kind,chainname,currentcontext,looku
   return head,start,false
 end
 function chainprocs.reversesub(head,start,stop,kind,chainname,currentcontext,lookuphash,replacements)
-  local char=getchar(start)
+  local char=start.char
   local replacement=replacements[char]
   if replacement then
     if trace_singles then
       logprocess("%s: single reverse replacement of %s by %s",cref(kind,chainname),gref(char),gref(replacement))
     end
-    setfield(start,"char",replacement)
+    start.char=replacement
     return head,start,true
   else
     return head,start,false
   end
 end
+local function delete_till_stop(start,stop,ignoremarks) 
+  local n=1
+  if start==stop then
+  elseif ignoremarks then
+    repeat 
+      local next=start.next
+      if not marks[next.char] then
+        local components=next.components
+        if components then 
+          flush_node_list(components)
+        end
+        delete_node(start,next)
+      end
+      n=n+1
+    until next==stop
+  else 
+    repeat
+      local next=start.next
+      local components=next.components
+      if components then 
+        flush_node_list(components)
+      end
+      delete_node(start,next)
+      n=n+1
+    until next==stop
+  end
+  return n
+end
 function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
   local current=start
   local subtables=currentlookup.subtables
@@ -10390,8 +9080,8 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo
     logwarning("todo: check if we need to loop over the replacements: %s",concat(subtables," "))
   end
   while current do
-    if getid(current)==glyph_code then
-      local currentchar=getchar(current)
+    if current.id==glyph_code then
+      local currentchar=current.char
       local lookupname=subtables[1] 
       local replacement=lookuphash[lookupname]
       if not replacement then
@@ -10408,21 +9098,22 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo
           if trace_singles then
             logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement))
           end
-          setfield(current,"char",replacement)
+          current.char=replacement
         end
       end
       return head,start,true
     elseif current==stop then
       break
     else
-      current=getnext(current)
+      current=current.next
     end
   end
   return head,start,false
 end
 chainmores.gsub_single=chainprocs.gsub_single
 function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
-  local startchar=getchar(start)
+  delete_till_stop(start,stop) 
+  local startchar=start.char
   local subtables=currentlookup.subtables
   local lookupname=subtables[1]
   local replacements=lookuphash[lookupname]
@@ -10440,7 +9131,7 @@ function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,
       if trace_multiples then
         logprocess("%s: replacing %s by multiple characters %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar),gref(replacements))
       end
-      return multiple_glyphs(head,start,replacements,currentlookup.flags[1])
+      return multiple_glyphs(head,start,replacements)
     end
   end
   return head,start,false
@@ -10451,8 +9142,8 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext
   local subtables=currentlookup.subtables
   local value=featurevalue==true and tfmdata.shared.features[kind] or featurevalue
   while current do
-    if getid(current)==glyph_code then 
-      local currentchar=getchar(current)
+    if current.id==glyph_code then 
+      local currentchar=current.char
       local lookupname=subtables[1]
       local alternatives=lookuphash[lookupname]
       if not alternatives then
@@ -10467,7 +9158,7 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext
             if trace_alternatives then
               logprocess("%s: replacing %s by alternative %a to %s, %s",cref(kind,chainname,chainlookupname,lookupname),gref(char),choice,gref(choice),comment)
             end
-            setfield(start,"char",choice)
+            start.char=choice
           else
             if trace_alternatives then
               logwarning("%s: no variant %a for %s, %s",cref(kind,chainname,chainlookupname,lookupname),value,gref(char),comment)
@@ -10481,14 +9172,14 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext
     elseif current==stop then
       break
     else
-      current=getnext(current)
+      current=current.next
     end
   end
   return head,start,false
 end
 chainmores.gsub_alternate=chainprocs.gsub_alternate
 function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex)
-  local startchar=getchar(start)
+  local startchar=start.char
   local subtables=currentlookup.subtables
   local lookupname=subtables[1]
   local ligatures=lookuphash[lookupname]
@@ -10503,20 +9194,20 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
         logwarning("%s: no ligatures starting with %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
       end
     else
-      local s=getnext(start)
+      local s=start.next
       local discfound=false
       local last=stop
       local nofreplacements=0
       local skipmark=currentlookup.flags[1]
       while s do
-        local id=getid(s)
+        local id=s.id
         if id==disc_code then
-          s=getnext(s)
+          s=s.next
           discfound=true
         else
-          local schar=getchar(s)
+          local schar=s.char
           if skipmark and marks[schar] then 
-            s=getnext(s)
+            s=s.next
           else
             local lg=ligatures[schar]
             if lg then
@@ -10524,7 +9215,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
               if s==stop then
                 break
               else
-                s=getnext(s)
+                s=s.next
               end
             else
               break
@@ -10541,7 +9232,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
           if start==stop then
             logprocess("%s: replacing character %s by ligature %s case 3",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(l2))
           else
-            logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(getchar(stop)),gref(l2))
+            logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char),gref(l2))
           end
         end
         head,start=toligature(kind,lookupname,head,start,stop,l2,currentlookup.flags[1],discfound)
@@ -10550,7 +9241,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
         if start==stop then
           logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
         else
-          logwarning("%s: replacing character %s upto %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(getchar(stop)))
+          logwarning("%s: replacing character %s upto %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char))
         end
       end
     end
@@ -10559,7 +9250,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
 end
 chainmores.gsub_ligature=chainprocs.gsub_ligature
 function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
-  local markchar=getchar(start)
+  local markchar=start.char
   if marks[markchar] then
     local subtables=currentlookup.subtables
     local lookupname=subtables[1]
@@ -10568,14 +9259,14 @@ function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext
       markanchors=markanchors[markchar]
     end
     if markanchors then
-      local base=getprev(start) 
-      if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
-        local basechar=getchar(base)
+      local base=start.prev 
+      if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+        local basechar=base.char
         if marks[basechar] then
           while true do
-            base=getprev(base)
-            if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
-              basechar=getchar(base)
+            base=base.prev
+            if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+              basechar=base.char
               if not marks[basechar] then
                 break
               end
@@ -10622,7 +9313,7 @@ function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext
   return head,start,false
 end
 function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
-  local markchar=getchar(start)
+  local markchar=start.char
   if marks[markchar] then
     local subtables=currentlookup.subtables
     local lookupname=subtables[1]
@@ -10631,14 +9322,14 @@ function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcon
       markanchors=markanchors[markchar]
     end
     if markanchors then
-      local base=getprev(start) 
-      if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
-        local basechar=getchar(base)
+      local base=start.prev 
+      if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+        local basechar=base.char
         if marks[basechar] then
           while true do
-            base=getprev(base)
-            if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then
-              basechar=getchar(base)
+            base=base.prev
+            if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then
+              basechar=base.char
               if not marks[basechar] then
                 break
               end
@@ -10650,7 +9341,7 @@ function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcon
             end
           end
         end
-        local index=getattr(start,a_ligacomp)
+        local index=start[a_ligacomp]
         local baseanchors=descriptions[basechar].anchors
         if baseanchors then
           local baseanchors=baseanchors['baselig']
@@ -10689,7 +9380,7 @@ function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcon
   return head,start,false
 end
 function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
-  local markchar=getchar(start)
+  local markchar=start.char
   if marks[markchar] then
       local subtables=currentlookup.subtables
       local lookupname=subtables[1]
@@ -10698,20 +9389,20 @@ function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext
         markanchors=markanchors[markchar]
       end
       if markanchors then
-        local base=getprev(start) 
-        local slc=getattr(start,a_ligacomp)
+        local base=start.prev 
+        local slc=start[a_ligacomp]
         if slc then 
           while base do
-            local blc=getattr(base,a_ligacomp)
+            local blc=base[a_ligacomp]
             if blc and blc~=slc then
-              base=getprev(base)
+              base=base.prev
             else
               break
             end
           end
         end
-        if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then 
-          local basechar=getchar(base)
+        if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then 
+          local basechar=base.char
           local baseanchors=descriptions[basechar].anchors
           if baseanchors then
             baseanchors=baseanchors['basemark']
@@ -10721,7 +9412,7 @@ function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext
                 if al[anchor] then
                   local ma=markanchors[anchor]
                   if ma then
-                    local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,true)
+                    local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma)
                     if trace_marks then
                       logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)",
                         cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
@@ -10747,9 +9438,9 @@ function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext
   return head,start,false
 end
 function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname)
-  local alreadydone=cursonce and getattr(start,a_cursbase)
+  local alreadydone=cursonce and start[a_cursbase]
   if not alreadydone then
-    local startchar=getchar(start)
+    local startchar=start.char
     local subtables=currentlookup.subtables
     local lookupname=subtables[1]
     local exitanchors=lookuphash[lookupname]
@@ -10763,11 +9454,11 @@ function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,l
           logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar))
         end
       else
-        local nxt=getnext(start)
-        while not done and nxt and getid(nxt)==glyph_code and getfont(nxt)==currentfont and getsubtype(nxt)<256 do
-          local nextchar=getchar(nxt)
+        local nxt=start.next
+        while not done and nxt and nxt.id==glyph_code and nxt.font==currentfont and nxt.subtype<256 do
+          local nextchar=nxt.char
           if marks[nextchar] then
-            nxt=getnext(nxt)
+            nxt=nxt.next
           else
             local entryanchors=descriptions[nextchar]
             if entryanchors then
@@ -10801,7 +9492,7 @@ function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,l
       return head,start,done
     else
       if trace_cursive and trace_details then
-        logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(getchar(start)),alreadydone)
+        logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
       end
       return head,start,false
     end
@@ -10809,7 +9500,7 @@ function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,l
   return head,start,false
 end
 function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
-  local startchar=getchar(start)
+  local startchar=start.char
   local subtables=currentlookup.subtables
   local lookupname=subtables[1]
   local kerns=lookuphash[lookupname]
@@ -10824,11 +9515,10 @@ function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lo
   end
   return head,start,false
 end
-chainmores.gpos_single=chainprocs.gpos_single
 function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence)
-  local snext=getnext(start)
+  local snext=start.next
   if snext then
-    local startchar=getchar(start)
+    local startchar=start.char
     local subtables=currentlookup.subtables
     local lookupname=subtables[1]
     local kerns=lookuphash[lookupname]
@@ -10838,26 +9528,26 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look
         local lookuptype=lookuptypes[lookupname]
         local prev,done=start,false
         local factor=tfmdata.parameters.factor
-        while snext and getid(snext)==glyph_code and getfont(snext)==currentfont and getsubtype(snext)<256 do
-          local nextchar=getchar(snext)
+        while snext and snext.id==glyph_code and snext.font==currentfont and snext.subtype<256 do
+          local nextchar=snext.char
           local krn=kerns[nextchar]
           if not krn and marks[nextchar] then
             prev=snext
-            snext=getnext(snext)
+            snext=snext.next
           else
             if not krn then
             elseif type(krn)=="table" then
               if lookuptype=="pair" then
                 local a,b=krn[2],krn[3]
                 if a and #a>0 then
-                  local startchar=getchar(start)
+                  local startchar=start.char
                   local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar])
                   if trace_kerns then
                     logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
                   end
                 end
                 if b and #b>0 then
-                  local startchar=getchar(start)
+                  local startchar=start.char
                   local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar])
                   if trace_kerns then
                     logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
@@ -10869,7 +9559,7 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look
                 if a and a~=0 then
                   local k=setkern(snext,factor,rlmode,a)
                   if trace_kerns then
-                    logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar))
+                    logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar))
                   end
                 end
                 if b and b~=0 then
@@ -10880,7 +9570,7 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look
             elseif krn~=0 then
               local k=setkern(snext,factor,rlmode,krn)
               if trace_kerns then
-                logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar))
+                logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar))
               end
               done=true
             end
@@ -10893,7 +9583,6 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look
   end
   return head,start,false
 end
-chainmores.gpos_pair=chainprocs.gpos_pair
 local function show_skip(kind,chainname,char,ck,class)
   if ck[9] then
     logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a, %a => %a",cref(kind,chainname),gref(char),class,ck[1],ck[2],ck[9],ck[10])
@@ -10918,7 +9607,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
     local seq=ck[3]
     local s=#seq
     if s==1 then
-      match=getid(current)==glyph_code and getfont(current)==currentfont and getsubtype(current)<256 and seq[1][getchar(current)]
+      match=current.id==glyph_code and current.font==currentfont and current.subtype<256 and seq[1][current.char]
     else
       local f,l=ck[4],ck[5]
       if f==1 and f==l then
@@ -10926,13 +9615,13 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
         if f==l then
         else
           local n=f+1
-          last=getnext(last)
+          last=last.next
           while n<=l do
             if last then
-              local id=getid(last)
+              local id=last.id
               if id==glyph_code then
-                if getfont(last)==currentfont and getsubtype(last)<256 then
-                  local char=getchar(last)
+                if last.font==currentfont and last.subtype<256 then
+                  local char=last.char
                   local ccd=descriptions[char]
                   if ccd then
                     local class=ccd.class
@@ -10941,10 +9630,10 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
                       if trace_skips then
                         show_skip(kind,chainname,char,ck,class)
                       end
-                      last=getnext(last)
+                      last=last.next
                     elseif seq[n][char] then
                       if n<l then
-                        last=getnext(last)
+                        last=last.next
                       end
                       n=n+1
                     else
@@ -10960,7 +9649,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
                   break
                 end
               elseif id==disc_code then
-                last=getnext(last)
+                last=last.next
               else
                 match=false
                 break
@@ -10973,15 +9662,15 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
         end
       end
       if match and f>1 then
-        local prev=getprev(start)
+        local prev=start.prev
         if prev then
           local n=f-1
           while n>=1 do
             if prev then
-              local id=getid(prev)
+              local id=prev.id
               if id==glyph_code then
-                if getfont(prev)==currentfont and getsubtype(prev)<256 then 
-                  local char=getchar(prev)
+                if prev.font==currentfont and prev.subtype<256 then 
+                  local char=prev.char
                   local ccd=descriptions[char]
                   if ccd then
                     local class=ccd.class
@@ -11011,7 +9700,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
                 match=false
                 break
               end
-              prev=getprev(prev)
+              prev=prev.prev
             elseif seq[n][32] then 
               n=n -1
             else
@@ -11031,15 +9720,15 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
         end
       end
       if match and s>l then
-        local current=last and getnext(last)
+        local current=last and last.next
         if current then
           local n=l+1
           while n<=s do
             if current then
-              local id=getid(current)
+              local id=current.id
               if id==glyph_code then
-                if getfont(current)==currentfont and getsubtype(current)<256 then 
-                  local char=getchar(current)
+                if current.font==currentfont and current.subtype<256 then 
+                  local char=current.char
                   local ccd=descriptions[char]
                   if ccd then
                     local class=ccd.class
@@ -11069,7 +9758,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
                 match=false
                 break
               end
-              current=getnext(current)
+              current=current.next
             elseif seq[n][32] then
               n=n+1
             else
@@ -11092,7 +9781,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
     if match then
       if trace_contexts then
         local rule,lookuptype,f,l=ck[1],ck[2],ck[4],ck[5]
-        local char=getchar(start)
+        local char=start.char
         if ck[9] then
           logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a, %a => %a",
             cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype,ck[9],ck[10])
@@ -11110,11 +9799,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
           if chainlookup then
             local cp=chainprocs[chainlookup.type]
             if cp then
-              local ok
-              head,start,ok=cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence)
-              if ok then
-                done=true
-              end
+              head,start,done=cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence)
             else
               logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
             end
@@ -11126,12 +9811,12 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
           repeat
             if skipped then
               while true do
-                local char=getchar(start)
+                local char=start.char
                 local ccd=descriptions[char]
                 if ccd then
                   local class=ccd.class
                   if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then
-                    start=getnext(start)
+                    start=start.next
                   else
                     break
                   end
@@ -11141,27 +9826,22 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
               end
             end
             local chainlookupname=chainlookups[i]
-            local chainlookup=lookuptable[chainlookupname]
-            if not chainlookup then
-              i=i+1
-            else
-              local cp=chainmores[chainlookup.type]
-              if not cp then
-                logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
-                i=i+1
+            local chainlookup=lookuptable[chainlookupname] 
+            local cp=chainlookup and chainmores[chainlookup.type]
+            if cp then
+              local ok,n
+              head,start,ok,n=cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence)
+              if ok then
+                done=true
+                i=i+(n or 1)
               else
-                local ok,n
-                head,start,ok,n=cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence)
-                if ok then
-                  done=true
-                  i=i+(n or 1)
-                else
-                  i=i+1
-                end
+                i=i+1
               end
+            else
+              i=i+1
             end
             if start then
-              start=getnext(start)
+              start=start.next
             else
             end
           until i>nofchainlookups
@@ -11288,7 +9968,6 @@ local function featuresprocessor(head,font,attr)
   if not lookuphash then
     return head,false
   end
-  head=tonut(head)
   if trace_steps then
     checkstep(head)
   end
@@ -11306,344 +9985,228 @@ local function featuresprocessor(head,font,attr)
   local done=false
   local datasets=otf.dataset(tfmdata,font,attr)
   local dirstack={}
-  for s=1,#datasets do
-    local dataset=datasets[s]
-    featurevalue=dataset[1] 
-    local sequence=dataset[5] 
-    local rlparmode=0
-    local topstack=0
-    local success=false
-    local attribute=dataset[2]
-    local chain=dataset[3] 
-    local typ=sequence.type
-    local subtables=sequence.subtables
-    if chain<0 then
-      local handler=handlers[typ]
-      local start=find_node_tail(head) 
-      while start do
-        local id=getid(start)
-        if id==glyph_code then
-          if getfont(start)==font and getsubtype(start)<256 then
-            local a=getattr(start,0)
-            if a then
-              a=a==attr
-            else
-              a=true
-            end
-            if a then
-              for i=1,#subtables do
-                local lookupname=subtables[i]
-                local lookupcache=lookuphash[lookupname]
-                if lookupcache then
-                  local lookupmatch=lookupcache[getchar(start)]
-                  if lookupmatch then
-                    head,start,success=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
-                    if success then
-                      break
-                    end
-                  end
-                else
-                  report_missing_cache(typ,lookupname)
-                end
-              end
-              if start then start=getprev(start) end
-            else
-              start=getprev(start)
-            end
-          else
-            start=getprev(start)
-          end
-        else
-          start=getprev(start)
-        end
-      end
-    else
-      local handler=handlers[typ]
-      local ns=#subtables
-      local start=head 
-      rlmode=0 
-      if ns==1 then 
-        local lookupname=subtables[1]
-        local lookupcache=lookuphash[lookupname]
-        if not lookupcache then 
-          report_missing_cache(typ,lookupname)
-        else
-          local function subrun(start)
-            local head=start
-            local done=false
-            while start do
-              local id=getid(start)
-              if id==glyph_code and getfont(start)==font and getsubtype(start)<256 then
-                local a=getattr(start,0)
-                if a then
-                  a=(a==attr) and (not attribute or getattr(start,a_state)==attribute)
-                else
-                  a=not attribute or getattr(start,a_state)==attribute
-                end
-                if a then
-                  local lookupmatch=lookupcache[getchar(start)]
-                  if lookupmatch then
-                    local ok
-                    head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
-                    if ok then
-                      done=true
-                    end
-                  end
-                  if start then start=getnext(start) end
-                else
-                  start=getnext(start)
-                end
-              else
-                start=getnext(start)
-              end
-            end
-            if done then
-              success=true
-              return head
-            end
-          end
+for s=1,#datasets do
+  local dataset=datasets[s]
+  featurevalue=dataset[1] 
+        local sequence=dataset[5] 
+        local rlparmode=0
+        local topstack=0
+        local success=false
+        local attribute=dataset[2]
+        local chain=dataset[3] 
+        local typ=sequence.type
+        local subtables=sequence.subtables
+        if chain<0 then
+          local handler=handlers[typ]
+          local start=find_node_tail(head) 
           while start do
-            local id=getid(start)
+            local id=start.id
             if id==glyph_code then
-              if getfont(start)==font and getsubtype(start)<256 then
-                local a=getattr(start,0)
+              if start.font==font and start.subtype<256 then
+                local a=start[0]
                 if a then
-                  a=(a==attr) and (not attribute or getattr(start,a_state)==attribute)
+                  a=a==attr
                 else
-                  a=not attribute or getattr(start,a_state)==attribute
+                  a=true
                 end
                 if a then
-                  local lookupmatch=lookupcache[getchar(start)]
-                  if lookupmatch then
-                    local ok
-                    head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
-                    if ok then
-                      success=true
+                  for i=1,#subtables do
+                    local lookupname=subtables[i]
+                    local lookupcache=lookuphash[lookupname]
+                    if lookupcache then
+                      local lookupmatch=lookupcache[start.char]
+                      if lookupmatch then
+                        head,start,success=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
+                        if success then
+                          break
+                        end
+                      end
+                    else
+                      report_missing_cache(typ,lookupname)
                     end
                   end
-                  if start then start=getnext(start) end
+                  if start then start=start.prev end
                 else
-                  start=getnext(start)
+                  start=start.prev
                 end
               else
-                start=getnext(start)
-              end
-            elseif id==disc_code then
-              if getsubtype(start)==discretionary_code then
-                local pre=getfield(start,"pre")
-                if pre then
-                  local new=subrun(pre)
-                  if new then setfield(start,"pre",new) end
-                end
-                local post=getfield(start,"post")
-                if post then
-                  local new=subrun(post)
-                  if new then setfield(start,"post",new) end
-                end
-                local replace=getfield(start,"replace")
-                if replace then
-                  local new=subrun(replace)
-                  if new then setfield(start,"replace",new) end
-                end
-              end
-              start=getnext(start)
-            elseif id==whatsit_code then 
-              local subtype=getsubtype(start)
-              if subtype==dir_code then
-                local dir=getfield(start,"dir")
-                if   dir=="+TRT" or dir=="+TLT" then
-                  topstack=topstack+1
-                  dirstack[topstack]=dir
-                elseif dir=="-TRT" or dir=="-TLT" then
-                  topstack=topstack-1
-                end
-                local newdir=dirstack[topstack]
-                if newdir=="+TRT" then
-                  rlmode=-1
-                elseif newdir=="+TLT" then
-                  rlmode=1
-                else
-                  rlmode=rlparmode
-                end
-                if trace_directions then
-                  report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir)
-                end
-              elseif subtype==localpar_code then
-                local dir=getfield(start,"dir")
-                if dir=="TRT" then
-                  rlparmode=-1
-                elseif dir=="TLT" then
-                  rlparmode=1
-                else
-                  rlparmode=0
-                end
-                rlmode=rlparmode
-                if trace_directions then
-                  report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode)
-                end
+                start=start.prev
               end
-              start=getnext(start)
-            elseif id==math_code then
-              start=getnext(end_of_math(start))
             else
-              start=getnext(start)
+              start=start.prev
             end
           end
-        end
-      else
-        local function subrun(start)
-          local head=start
-          local done=false
-          while start do
-            local id=getid(start)
-            if id==glyph_code and getfont(start)==font and getsubtype(start)<256 then
-              local a=getattr(start,0)
-              if a then
-                a=(a==attr) and (not attribute or getattr(start,a_state)==attribute)
-              else
-                a=not attribute or getattr(start,a_state)==attribute
-              end
-              if a then
-                for i=1,ns do
-                  local lookupname=subtables[i]
-                  local lookupcache=lookuphash[lookupname]
-                  if lookupcache then
-                    local lookupmatch=lookupcache[getchar(start)]
-                    if lookupmatch then
-                      local ok
-                      head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
-                      if ok then
-                        done=true
-                        break
-                      elseif not start then
-                        break
+        else
+          local handler=handlers[typ]
+          local ns=#subtables
+          local start=head 
+          rlmode=0 
+          if ns==1 then 
+            local lookupname=subtables[1]
+            local lookupcache=lookuphash[lookupname]
+            if not lookupcache then 
+              report_missing_cache(typ,lookupname)
+            else
+              while start do
+                local id=start.id
+                if id==glyph_code then
+                  if start.font==font and start.subtype<256 then
+                    local a=start[0]
+                    if a then
+                      a=(a==attr) and (not attribute or start[a_state]==attribute)
+                    else
+                      a=not attribute or start[a_state]==attribute
+                    end
+                    if a then
+                      local lookupmatch=lookupcache[start.char]
+                      if lookupmatch then
+                        local ok
+                        head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1)
+                        if ok then
+                          success=true
+                        end
                       end
+                      if start then start=start.next end
+                    else
+                      start=start.next
                     end
+                  elseif id==math_code then
+                    start=end_of_math(start).next
                   else
-                    report_missing_cache(typ,lookupname)
+                    start=start.next
+                  end
+                elseif id==whatsit_code then 
+                  local subtype=start.subtype
+                  if subtype==dir_code then
+                    local dir=start.dir
+                    if   dir=="+TRT" or dir=="+TLT" then
+                      topstack=topstack+1
+                      dirstack[topstack]=dir
+                    elseif dir=="-TRT" or dir=="-TLT" then
+                      topstack=topstack-1
+                    end
+                    local newdir=dirstack[topstack]
+                    if newdir=="+TRT" then
+                      rlmode=-1
+                    elseif newdir=="+TLT" then
+                      rlmode=1
+                    else
+                      rlmode=rlparmode
+                    end
+                    if trace_directions then
+                      report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir)
+                    end
+                  elseif subtype==localpar_code then
+                    local dir=start.dir
+                    if dir=="TRT" then
+                      rlparmode=-1
+                    elseif dir=="TLT" then
+                      rlparmode=1
+                    else
+                      rlparmode=0
+                    end
+                    rlmode=rlparmode
+                    if trace_directions then
+                      report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode)
+                    end
                   end
+                  start=start.next
+                elseif id==math_code then
+                  start=end_of_math(start).next
+                else
+                  start=start.next
                 end
-                if start then start=getnext(start) end
-              else
-                start=getnext(start)
               end
-            else
-              start=getnext(start)
             end
-          end
-          if done then
-            success=true
-            return head
-          end
-        end
-        while start do
-          local id=getid(start)
-          if id==glyph_code then
-            if getfont(start)==font and getsubtype(start)<256 then
-              local a=getattr(start,0)
-              if a then
-                a=(a==attr) and (not attribute or getattr(start,a_state)==attribute)
-              else
-                a=not attribute or getattr(start,a_state)==attribute
-              end
-              if a then
-                for i=1,ns do
-                  local lookupname=subtables[i]
-                  local lookupcache=lookuphash[lookupname]
-                  if lookupcache then
-                    local lookupmatch=lookupcache[getchar(start)]
-                    if lookupmatch then
-                      local ok
-                      head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
-                      if ok then
-                        success=true
-                        break
-                      elseif not start then
-                        break
+          else
+            while start do
+              local id=start.id
+              if id==glyph_code then
+                if start.font==font and start.subtype<256 then
+                  local a=start[0]
+                  if a then
+                    a=(a==attr) and (not attribute or start[a_state]==attribute)
+                  else
+                    a=not attribute or start[a_state]==attribute
+                  end
+                  if a then
+                    for i=1,ns do
+                      local lookupname=subtables[i]
+                      local lookupcache=lookuphash[lookupname]
+                      if lookupcache then
+                        local lookupmatch=lookupcache[start.char]
+                        if lookupmatch then
+                          local ok
+                          head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i)
+                          if ok then
+                            success=true
+                            break
+                          elseif not start then
+                            break
+                          end
+                        end
+                      else
+                        report_missing_cache(typ,lookupname)
                       end
                     end
+                    if start then start=start.next end
+                  else
+                    start=start.next
+                  end
+                else
+                  start=start.next
+                end
+              elseif id==whatsit_code then
+                local subtype=start.subtype
+                if subtype==dir_code then
+                  local dir=start.dir
+                  if   dir=="+TRT" or dir=="+TLT" then
+                    topstack=topstack+1
+                    dirstack[topstack]=dir
+                  elseif dir=="-TRT" or dir=="-TLT" then
+                    topstack=topstack-1
+                  end
+                  local newdir=dirstack[topstack]
+                  if newdir=="+TRT" then
+                    rlmode=-1
+                  elseif newdir=="+TLT" then
+                    rlmode=1
                   else
-                    report_missing_cache(typ,lookupname)
+                    rlmode=rlparmode
+                  end
+                  if trace_directions then
+                    report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir)
+                  end
+                elseif subtype==localpar_code then
+                  local dir=start.dir
+                  if dir=="TRT" then
+                    rlparmode=-1
+                  elseif dir=="TLT" then
+                    rlparmode=1
+                  else
+                    rlparmode=0
+                  end
+                  rlmode=rlparmode
+                  if trace_directions then
+                    report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode)
                   end
                 end
-                if start then start=getnext(start) end
-              else
-                start=getnext(start)
-              end
-            else
-              start=getnext(start)
-            end
-          elseif id==disc_code then
-            if getsubtype(start)==discretionary_code then
-              local pre=getfield(start,"pre")
-              if pre then
-                local new=subrun(pre)
-                if new then setfield(start,"pre",new) end
-              end
-              local post=getfield(start,"post")
-              if post then
-                local new=subrun(post)
-                if new then setfield(start,"post",new) end
-              end
-              local replace=getfield(start,"replace")
-              if replace then
-                local new=subrun(replace)
-                if new then setfield(start,"replace",new) end
-              end
-            end
-            start=getnext(start)
-          elseif id==whatsit_code then
-            local subtype=getsubtype(start)
-            if subtype==dir_code then
-              local dir=getfield(start,"dir")
-              if   dir=="+TRT" or dir=="+TLT" then
-                topstack=topstack+1
-                dirstack[topstack]=dir
-              elseif dir=="-TRT" or dir=="-TLT" then
-                topstack=topstack-1
-              end
-              local newdir=dirstack[topstack]
-              if newdir=="+TRT" then
-                rlmode=-1
-              elseif newdir=="+TLT" then
-                rlmode=1
-              else
-                rlmode=rlparmode
-              end
-              if trace_directions then
-                report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir)
-              end
-            elseif subtype==localpar_code then
-              local dir=getfield(start,"dir")
-              if dir=="TRT" then
-                rlparmode=-1
-              elseif dir=="TLT" then
-                rlparmode=1
+                start=start.next
+              elseif id==math_code then
+                start=end_of_math(start).next
               else
-                rlparmode=0
-              end
-              rlmode=rlparmode
-              if trace_directions then
-                report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode)
+                start=start.next
               end
             end
-            start=getnext(start)
-          elseif id==math_code then
-            start=getnext(end_of_math(start))
-          else
-            start=getnext(start)
           end
         end
-      end
-    end
-    if success then
-      done=true
-    end
-    if trace_steps then 
-      registerstep(head)
-    end
+        if success then
+          done=true
+        end
+        if trace_steps then 
+          registerstep(head)
+        end
   end
-  head=tonode(head)
   return head,done
 end
 local function generic(lookupdata,lookupname,unicode,lookuphash)
@@ -12752,7 +11315,6 @@ if not modules then modules={} end modules ['font-def']={
 local format,gmatch,match,find,lower,gsub=string.format,string.gmatch,string.match,string.find,string.lower,string.gsub
 local tostring,next=tostring,next
 local lpegmatch=lpeg.match
-local suffixonly,removesuffix=file.suffix,file.removesuffix
 local allocate=utilities.storage.allocate
 local trace_defining=false trackers .register("fonts.defining",function(v) trace_defining=v end)
 local directive_embedall=false directives.register("fonts.embedall",function(v) directive_embedall=v end)
@@ -12800,7 +11362,7 @@ addlookup("file")
 addlookup("name")
 addlookup("spec")
 local function getspecification(str)
-  return lpegmatch(splitter,str or "") 
+  return lpegmatch(splitter,str)
 end
 definers.getspecification=getspecification
 function definers.registersplit(symbol,action,verbosename)
@@ -12842,11 +11404,10 @@ definers.resolvers=definers.resolvers or {}
 local resolvers=definers.resolvers
 function resolvers.file(specification)
   local name=resolvefile(specification.name) 
-  local suffix=lower(suffixonly(name))
+  local suffix=file.suffix(name)
   if fonts.formats[suffix] then
     specification.forced=suffix
-    specification.forcedname=name
-    specification.name=removesuffix(name)
+    specification.name=file.removesuffix(name)
   else
     specification.name=name 
   end
@@ -12858,11 +11419,10 @@ function resolvers.name(specification)
     if resolved then
       specification.resolved=resolved
       specification.sub=sub
-      local suffix=lower(suffixonly(resolved))
+      local suffix=file.suffix(resolved)
       if fonts.formats[suffix] then
         specification.forced=suffix
-        specification.forcedname=resolved
-        specification.name=removesuffix(resolved)
+        specification.name=file.removesuffix(resolved)
       else
         specification.name=resolved
       end
@@ -12878,9 +11438,8 @@ function resolvers.spec(specification)
     if resolved then
       specification.resolved=resolved
       specification.sub=sub
-      specification.forced=lower(suffixonly(resolved))
-      specification.forcedname=resolved
-      specification.name=removesuffix(resolved)
+      specification.forced=file.suffix(resolved)
+      specification.name=file.removesuffix(resolved)
     end
   else
     resolvers.name(specification)
@@ -12895,7 +11454,8 @@ function definers.resolve(specification)
   end
   if specification.forced=="" then
     specification.forced=nil
-    specification.forcedname=nil
+  else
+    specification.forced=specification.forced
   end
   specification.hash=lower(specification.name..' @ '..constructors.hashfeatures(specification))
   if specification.sub and specification.sub~="" then
@@ -12940,7 +11500,7 @@ function definers.loadfont(specification)
   if not tfmdata then
     local forced=specification.forced or ""
     if forced~="" then
-      local reader=readers[lower(forced)] 
+      local reader=readers[lower(forced)]
       tfmdata=reader and reader(specification)
       if not tfmdata then
         report_defining("forced type %a of %a not found",forced,specification.name)
diff --git a/tex/generic/context/luatex/luatex-fonts-syn.lua b/tex/generic/context/luatex/luatex-fonts-syn.lua
index 60dd2c063..ea6e3cab5 100644
--- a/tex/generic/context/luatex/luatex-fonts-syn.lua
+++ b/tex/generic/context/luatex/luatex-fonts-syn.lua
@@ -100,7 +100,3 @@ fonts.names.resolvespec = fonts.names.resolve -- only supported in mkiv
 function fonts.names.getfilename(askedname,suffix)  -- only supported in mkiv
     return ""
 end
-
-function fonts.names.ignoredfile(filename) -- only supported in mkiv
-    return true -- will be overloaded
-end
diff --git a/tex/generic/context/luatex/luatex-fonts.lua b/tex/generic/context/luatex/luatex-fonts.lua
index 7995be33e..89592fcac 100644
--- a/tex/generic/context/luatex/luatex-fonts.lua
+++ b/tex/generic/context/luatex/luatex-fonts.lua
@@ -192,7 +192,7 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then
         -- with context. The mtx-fonts script can be used to genate this file (using the --names option).
 
         -- In 2013/14 I will merge/move some generic files into luatex-fonts-* files (copies) so that
-        -- intermediate updates of context don't interfere. We can then also use the general merger and
+        -- intermediate updates of context not interfere. We can then also use the general merger and
         -- consider stripping debug code.
 
         loadmodule('font-ini.lua')
@@ -201,11 +201,6 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then
         loadmodule('font-cid.lua')
         loadmodule('font-map.lua')         -- for loading lum file (will be stripped)
         loadmodule('luatex-fonts-syn.lua') -- deals with font names (synonyms)
-        -- begin of test
-        loadmodule('font-tfm.lua')         -- optional
-        loadmodule('font-afm.lua')         -- optional
-        loadmodule('font-afk.lua')         -- optional
-        -- end of test
         loadmodule('luatex-fonts-tfm.lua')
         loadmodule('font-oti.lua')
         loadmodule('font-otf.lua')
@@ -214,6 +209,7 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then
         loadmodule('font-ota.lua')
         loadmodule('font-otn.lua')
         loadmodule('font-otp.lua')         -- optional
+        ----------('luatex-fonts-chr.lua')
         loadmodule('luatex-fonts-lua.lua')
         loadmodule('font-def.lua')
         loadmodule('luatex-fonts-def.lua')
diff --git a/tex/generic/context/luatex/luatex-test.tex b/tex/generic/context/luatex/luatex-test.tex
index fbf8ce3cf..fcc837e70 100644
--- a/tex/generic/context/luatex/luatex-test.tex
+++ b/tex/generic/context/luatex/luatex-test.tex
@@ -80,8 +80,4 @@ $$\left( { {1} \over { {1} \over {x} } } \right) $$
 
 $$\sqrt {2} { { {1} \over { {1} \over {x} } } } $$
 
-\font\cows=file:koeieletters.afm at 50pt
-
-\cows Hello World!
-
 \end
-- 
cgit v1.2.3