diff options
| author | Hans Hagen <pragma@wxs.nl> | 2009-11-18 21:51:00 +0100 | 
|---|---|---|
| committer | Hans Hagen <pragma@wxs.nl> | 2009-11-18 21:51:00 +0100 | 
| commit | b309379ef546b7fa819f493fa3cb1dc559d4c3b8 (patch) | |
| tree | f7244cebdc52206c3a35767ed9eb834dc901313b | |
| parent | 9cf4a9e0a6642da57b94730bf7104335735a7ace (diff) | |
| download | context-b309379ef546b7fa819f493fa3cb1dc559d4c3b8.tar.gz | |
beta 2009.11.18 21:51
48 files changed, 3511 insertions, 1175 deletions
| diff --git a/scripts/context/lua/luatools.lua b/scripts/context/lua/luatools.lua index 2bc943210..abd80b8b4 100644 --- a/scripts/context/lua/luatools.lua +++ b/scripts/context/lua/luatools.lua @@ -308,7 +308,7 @@ if not modules then modules = { } end modules ['l-lpeg'] = {      license   = "see context related readme files"  } -local P, S, Ct, C, Cs, Cc = lpeg.P, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc +local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc  --~ l-lpeg.lua : @@ -415,6 +415,41 @@ end  --~     return p  --~ end +--~ from roberto's site: +--~ +--~ -- decode a two-byte UTF-8 sequence +--~ local function f2 (s) +--~   local c1, c2 = string.byte(s, 1, 2) +--~   return c1 * 64 + c2 - 12416 +--~ end +--~ +--~ -- decode a three-byte UTF-8 sequence +--~ local function f3 (s) +--~   local c1, c2, c3 = string.byte(s, 1, 3) +--~   return (c1 * 64 + c2) * 64 + c3 - 925824 +--~ end +--~ +--~ -- decode a four-byte UTF-8 sequence +--~ local function f4 (s) +--~   local c1, c2, c3, c4 = string.byte(s, 1, 4) +--~   return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168 +--~ end +--~ +--~ local cont = lpeg.R("\128\191")   -- continuation byte +--~ +--~ local utf8 = lpeg.R("\0\127") / string.byte +--~            + lpeg.R("\194\223") * cont / f2 +--~            + lpeg.R("\224\239") * cont * cont / f3 +--~            + lpeg.R("\240\244") * cont * cont * cont / f4 +--~ +--~ local decode_pattern = lpeg.Ct(utf8^0) * -1 + + +local cont = R("\128\191")   -- continuation byte + +lpeg.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont + +  end -- of closure @@ -431,9 +466,9 @@ if not modules then modules = { } end modules ['l-table'] = {  table.join = table.concat  local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove -local format, find, gsub, lower, dump = string.format, string.find, string.gsub, string.lower, string.dump +local format, find, gsub, lower, dump, match = string.format, string.find, string.gsub, string.lower, string.dump, string.match  local getmetatable, setmetatable = getmetatable, setmetatable -local type, next, tostring, ipairs = type, next, tostring, ipairs +local type, next, tostring, tonumber, ipairs, pairs = type, next, tostring, tonumber, ipairs, pairs  function table.strip(tab)      local lst = { } @@ -721,6 +756,8 @@ end  --  -- local propername = lpeg.P(lpeg.R("AZ","az","__") * lpeg.R("09","AZ","az", "__")^0 * lpeg.P(-1) ) +-- problem: there no good number_to_string converter with the best resolution +  local function do_serialize(root,name,depth,level,indexed)      if level > 0 then          depth = depth .. " " @@ -743,6 +780,7 @@ local function do_serialize(root,name,depth,level,indexed)              handle(format("%s{",depth))          end      end +    -- we could check for k (index) being number (cardinal)      if root and next(root) then          local first, last = nil, 0 -- #root cannot be trusted here          if compact then @@ -765,10 +803,10 @@ local function do_serialize(root,name,depth,level,indexed)                      if hexify then                          handle(format("%s 0x%04X,",depth,v))                      else -                        handle(format("%s %s,",depth,v)) +                        handle(format("%s %s,",depth,v)) -- %.99g                      end                  elseif t == "string" then -                    if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then +                    if reduce and tonumber(v) then                          handle(format("%s %s,",depth,v))                      else                          handle(format("%s %q,",depth,v)) @@ -805,29 +843,29 @@ local function do_serialize(root,name,depth,level,indexed)              --~ if hexify then              --~     handle(format("%s %s=0x%04X,",depth,key(k),v))              --~ else -            --~     handle(format("%s %s=%s,",depth,key(k),v)) +            --~     handle(format("%s %s=%s,",depth,key(k),v)) -- %.99g              --~ end                  if type(k) == "number" then -- or find(k,"^%d+$") then                      if hexify then                          handle(format("%s [0x%04X]=0x%04X,",depth,k,v))                      else -                        handle(format("%s [%s]=%s,",depth,k,v)) +                        handle(format("%s [%s]=%s,",depth,k,v)) -- %.99g                      end                  elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then                      if hexify then                          handle(format("%s %s=0x%04X,",depth,k,v))                      else -                        handle(format("%s %s=%s,",depth,k,v)) +                        handle(format("%s %s=%s,",depth,k,v)) -- %.99g                      end                  else                      if hexify then                          handle(format("%s [%q]=0x%04X,",depth,k,v))                      else -                        handle(format("%s [%q]=%s,",depth,k,v)) +                        handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g                      end                  end              elseif t == "string" then -                if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then +                if reduce and tonumber(v) then                  --~ handle(format("%s %s=%s,",depth,key(k),v))                      if type(k) == "number" then -- or find(k,"^%d+$") then                          if hexify then @@ -1036,7 +1074,7 @@ function table.tofile(filename,root,name,reduce,noquotes,hexify)      end  end -local function flatten(t,f,complete) +local function flatten(t,f,complete) -- is this used? meybe a variant with next, ...      for i=1,#t do          local v = t[i]          if type(v) == "table" then @@ -1065,6 +1103,24 @@ end  table.flatten_one_level = table.unnest +-- a better one: + +local function flattened(t,f) +    if not f then +        f = { } +    end +    for k, v in next, t do +        if type(v) == "table" then +            flattened(v,f) +        else +            f[k] = v +        end +    end +    return f +end + +table.flattened = flattened +  -- the next three may disappear  function table.remove_value(t,value) -- todo: n @@ -1200,7 +1256,7 @@ function table.clone(t,p) -- t is optional or nil or table      elseif not t then          t = { }      end -    setmetatable(t, { __index = function(_,key) return p[key] end }) +    setmetatable(t, { __index = function(_,key) return p[key] end }) -- why not __index = p ?      return t  end @@ -1615,7 +1671,8 @@ if not modules then modules = { } end modules ['l-os'] = {      license   = "see context related readme files"  } -local find = string.find +local find, format = string.find, string.format +local random, ceil = math.random, math.ceil  function os.resultof(command)      return io.popen(command,"r"):read("*all") @@ -1712,6 +1769,8 @@ function os.currentplatform(name,default)              elseif name == "macosx" then                  if find(architecture,"i386") then                      platform = "osx-intel" +                elseif find(architecture,"x86_64") then +                    platform = "osx-64"                  else                      platform = "osx-ppc"                  end @@ -1738,6 +1797,29 @@ function os.currentplatform(name,default)      return platform  end +-- beware, we set the randomseed +-- + +-- from wikipedia: Version 4 UUIDs use a scheme relying only on random numbers. This algorithm sets the +-- version number as well as two reserved bits. All other bits are set using a random or pseudorandom +-- data source. Version 4 UUIDs have the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx with hexadecimal +-- digits x and hexadecimal digits 8, 9, A, or B for y. e.g. f47ac10b-58cc-4372-a567-0e02b2c3d479. +-- +-- as we don't call this function too often there is not so much risk on repetition + + +local t = { 8, 9, "a", "b" } + +function os.uuid() +    return format("%04x%04x-4%03x-%s%03x-%04x-%04x%04x%04x", +        random(0xFFFF),random(0xFFFF), +        random(0x0FFF), +        t[ceil(random(4))] or 8,random(0x0FFF), +        random(0xFFFF), +        random(0xFFFF),random(0xFFFF),random(0xFFFF) +    ) +end +  end -- of closure @@ -1778,8 +1860,12 @@ function file.dirname(name,default)      return match(name,"^(.+)[/\\].-$") or (default or "")  end +--~ function file.basename(name) +--~     return match(name,"^.+[/\\](.-)$") or name +--~ end +  function file.basename(name) -    return match(name,"^.+[/\\](.-)$") or name +    return match(name,"^.*[/\\](.-)$") or name  end  function file.nameonly(name) @@ -1857,6 +1943,7 @@ function file.collapse_path(str)      return str  end +--~ print(file.collapse_path("/a"))  --~ print(file.collapse_path("a/./b/.."))  --~ print(file.collapse_path("a/aa/../b/bb"))  --~ print(file.collapse_path("a/../..")) @@ -3028,9 +3115,9 @@ function aux.make_settings_to_hash_pattern(set,how)      end  end -function aux.settings_to_hash(str) +function aux.settings_to_hash(str,existing)      if str and str ~= "" then -        hash = { } +        hash = existing or { }          if moretolerant then              pattern_b_s:match(str)          else @@ -3042,9 +3129,9 @@ function aux.settings_to_hash(str)      end  end -function aux.settings_to_hash_tolerant(str) +function aux.settings_to_hash_tolerant(str,existing)      if str and str ~= "" then -        hash = { } +        hash = existing or { }          pattern_b_s:match(str)          return hash      else @@ -3052,9 +3139,9 @@ function aux.settings_to_hash_tolerant(str)      end  end -function aux.settings_to_hash_strict(str) +function aux.settings_to_hash_strict(str,existing)      if str and str ~= "" then -        hash = { } +        hash = existing or { }          pattern_c_s:match(str)          return next(hash) and hash      else @@ -3142,7 +3229,7 @@ function aux.getparameters(self,class,parentclass,settings)          sc = table.clone(self[parent])          self[class] = sc      end -    aux.add_settings_to_array(sc, settings) +    aux.settings_to_hash(settings,sc)  end  -- temporary here @@ -3230,12 +3317,15 @@ if not modules then modules = { } end modules ['trac-tra'] = {  -- bound to a variable, like node.new, node.copy etc (contrary to for instance  -- node.has_attribute which is bound to a has_attribute local variable in mkiv) +local getinfo = debug.getinfo +local type, next = type, next +local concat = table.concat +local format, find, lower, gmatch, gsub = string.format, string.find, string.lower, string.gmatch, string.gsub +  debugger = debugger or { }  local counters = { }  local names = { } -local getinfo = debug.getinfo -local format, find, lower, gmatch, gsub = string.format, string.find, string.lower, string.gmatch, string.gsub  -- one @@ -3363,11 +3453,11 @@ end  --~ print("")  --~ debugger.showstats(print,3) -trackers = trackers or { } +setters      = setters      or { } +setters.data = setters.data or { } -local data, done = { }, { } - -local function set(what,value) +local function set(t,what,value) +    local data, done = t.data, t.done      if type(what) == "string" then          what = aux.settings_to_array(what) -- inefficient but ok      end @@ -3386,28 +3476,30 @@ local function set(what,value)      end  end -local function reset() -    for d, f in next, data do +local function reset(t) +    for d, f in next, t.data do          for i=1,#f do              f[i](false)          end      end  end -local function enable(what) -    set(what,true) +local function enable(t,what) +    set(t,what,true)  end -local function disable(what) +local function disable(t,what) +    local data = t.data      if not what or what == "" then -        done = { } -        reset() +        t.done = { } +        reset(t)      else -        set(what,false) +        set(t,what,false)      end  end -function trackers.register(what,...) +function setters.register(t,what,...) +    local data = t.data      what = lower(what)      local w = data[what]      if not w then @@ -3419,32 +3511,32 @@ function trackers.register(what,...)          if typ == "function" then              w[#w+1] = fnc          elseif typ == "string" then -            w[#w+1] = function(value) set(fnc,value,nesting) end +            w[#w+1] = function(value) set(t,fnc,value,nesting) end          end      end  end -function trackers.enable(what) -    local e = trackers.enable -    trackers.enable, done = enable, { } -    enable(string.simpleesc(what)) -    trackers.enable, done = e, { } +function setters.enable(t,what) +    local e = t.enable +    t.enable, t.done = enable, { } +    enable(t,string.simpleesc(what)) +    t.enable, t.done = e, { }  end -function trackers.disable(what) -    local e = trackers.disable -    trackers.disable, done = disable, { } -    disable(string.simpleesc(what)) -    trackers.disable, done = e, { } +function setters.disable(t,what) +    local e = t.disable +    t.disable, t.done = disable, { } +    disable(t,string.simpleesc(what)) +    t.disable, t.done = e, { }  end -function trackers.reset() -    done = { } -    reset() +function setters.reset(t) +    t.done = { } +    reset(t)  end -function trackers.list() -- pattern -    local list = table.sortedkeys(data) +function setters.list(t) -- pattern +    local list = table.sortedkeys(t.data)      local user, system = { }, { }      for l=1,#list do          local what = list[l] @@ -3457,6 +3549,139 @@ function trackers.list() -- pattern      return user, system  end +function setters.show(t) +    commands.writestatus("","") +    for k,v in ipairs(setters.list(t)) do +        commands.writestatus(t.name,v) +    end +    commands.writestatus("","") +end + +-- we could have used a bit of oo and the trackers:enable syntax but +-- there is already a lot of code around using the singluar tracker + +function setters.new(name) +    local t +    t = { +        data     = { }, +        name     = name, +        enable   = function(...) setters.enable  (t,...) end, +        disable  = function(...) setters.disable (t,...) end, +        register = function(...) setters.register(t,...) end, +        list     = function(...) setters.list    (t,...) end, +        show     = function(...) setters.show    (t,...) end, +    } +    setters.data[name] = t +    return t +end + +trackers   = setters.new("trackers") +directives = setters.new("directives") + +-- nice trick: we overload two of the directives related functions with variants that +-- do tracing (itself using a tracker) .. proof of concept + +local trace_directives = false local trace_directives = false  trackers.register("system.directives", function(v) trace_directives = v end) + +local e = directives.enable +local d = directives.disable + +function directives.enable(...) +    commands.writestatus("directives","enabling: %s",concat({...}," ")) +    e(...) +end + +function directives.disable(...) +    commands.writestatus("directives","disabling: %s",concat({...}," ")) +    d(...) +end + +--~ -- old code: +-- +--~ trackers = trackers or { } +--~ local data, done = { }, { } +--~ local function set(what,value) +--~     if type(what) == "string" then +--~         what = aux.settings_to_array(what) -- inefficient but ok +--~     end +--~     for i=1,#what do +--~         local w = what[i] +--~         for d, f in next, data do +--~             if done[d] then +--~                 -- prevent recursion due to wildcards +--~             elseif find(d,w) then +--~                 done[d] = true +--~                 for i=1,#f do +--~                     f[i](value) +--~                 end +--~             end +--~         end +--~     end +--~ end +--~ local function reset() +--~     for d, f in next, data do +--~         for i=1,#f do +--~             f[i](false) +--~         end +--~     end +--~ end +--~ local function enable(what) +--~     set(what,true) +--~ end +--~ local function disable(what) +--~     if not what or what == "" then +--~         done = { } +--~         reset() +--~     else +--~         set(what,false) +--~     end +--~ end +--~ function trackers.register(what,...) +--~     what = lower(what) +--~     local w = data[what] +--~     if not w then +--~         w = { } +--~         data[what] = w +--~     end +--~     for _, fnc in next, { ... } do +--~         local typ = type(fnc) +--~         if typ == "function" then +--~             w[#w+1] = fnc +--~         elseif typ == "string" then +--~             w[#w+1] = function(value) set(fnc,value,nesting) end +--~         end +--~     end +--~ end +--~ function trackers.enable(what) +--~     local e = trackers.enable +--~     trackers.enable, done = enable, { } +--~     enable(string.simpleesc(what)) +--~     trackers.enable, done = e, { } +--~ end +--~ function trackers.disable(what) +--~     local e = trackers.disable +--~     trackers.disable, done = disable, { } +--~     disable(string.simpleesc(what)) +--~     trackers.disable, done = e, { } +--~ end +--~ function trackers.reset() +--~     done = { } +--~     reset() +--~ end +--~ function trackers.list() -- pattern +--~     local list = table.sortedkeys(data) +--~     local user, system = { }, { } +--~     for l=1,#list do +--~         local what = list[l] +--~         if find(what,"^%*") then +--~             system[#system+1] = what +--~         else +--~             user[#user+1] = what +--~         end +--~     end +--~     return user, system +--~ end +  end -- of closure @@ -3908,6 +4133,7 @@ function statistics.timed(action,report)  end +  end -- of closure  do -- create closure to overcome 200 locals limit @@ -4241,6 +4467,8 @@ local format, gsub, find, lower, upper, match, gmatch = string.format, string.gs  local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys  local next, type = next, type +local collapse_path = file.collapse_path +  local trace_locating, trace_detail, trace_verbose  = false, false, false  trackers.register("resolvers.verbose",  function(v) trace_verbose  = v end) @@ -4629,7 +4857,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat      end      if ok then          local function validate(s) -            s = file.collapse_path(s) +            s = collapse_path(s)              return s ~= "" and not find(s,dummy_path_expr) and s          end          for k=1,#pathlist do @@ -4638,7 +4866,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat      else          for k=1,#pathlist do              for p in gmatch(pathlist[k],"([^,]+)") do -                p = file.collapse_path(p) +                p = collapse_path(p)                  if p ~= "" then newlist[#newlist+1] = p end              end          end @@ -4703,9 +4931,9 @@ local function identify_own()      local ownpath = resolvers.getownpath() or lfs.currentdir()      local ie = instance.environment      if ownpath then -        if resolvers.env('SELFAUTOLOC')    == "" then os.env['SELFAUTOLOC']    = file.collapse_path(ownpath) end -        if resolvers.env('SELFAUTODIR')    == "" then os.env['SELFAUTODIR']    = file.collapse_path(ownpath .. "/..") end -        if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end +        if resolvers.env('SELFAUTOLOC')    == "" then os.env['SELFAUTOLOC']    = collapse_path(ownpath) end +        if resolvers.env('SELFAUTODIR')    == "" then os.env['SELFAUTODIR']    = collapse_path(ownpath .. "/..") end +        if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = collapse_path(ownpath .. "/../..") end      else          logs.report("fileio","error: unable to locate ownpath")          os.exit() @@ -4734,7 +4962,7 @@ function resolvers.identify_cnf()          local function locate(filename,list)              for i=1,#t do                  local ti = t[i] -                local texmfcnf = file.collapse_path(file.join(ti,filename)) +                local texmfcnf = collapse_path(file.join(ti,filename))                  if lfs.isfile(texmfcnf) then                      list[#list+1] = texmfcnf                  end @@ -4746,11 +4974,11 @@ function resolvers.identify_cnf()  end  local function load_cnf_file(fname) +    -- why don't we just read the file from the cache +    -- we need to switch to the lua file      fname = resolvers.clean_path(fname)      local lname = file.replacesuffix(fname,'lua') -    local f = io.open(lname) -    if f then -- this will go -        f:close() +    if lfs.isfile(lname) then          local dname = file.dirname(fname)          if not instance.configuration[dname] then              resolvers.load_data(dname,'configuration',lname and file.basename(lname)) @@ -4815,13 +5043,17 @@ local function collapse_cnf_data() -- potential optimization: pass start index (      end  end -function resolvers.load_cnf() -    local function loadoldconfigdata() -        for _, fname in ipairs(instance.cnffiles) do -            load_cnf_file(fname) -        end +local function loadoldconfigdata() +    for _, fname in ipairs(instance.cnffiles) do +        load_cnf_file(fname)      end +end + +function resolvers.load_cnf()      -- instance.cnffiles contain complete names now ! +    -- we still use a funny mix of cnf and new but soon +    -- we will switch to lua exclusively as we only use +    -- the file to collect the tree roots      if #instance.cnffiles == 0 then          if trace_verbose then              logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)") @@ -4829,12 +5061,12 @@ function resolvers.load_cnf()      else          instance.rootpath = instance.cnffiles[1]          for k,fname in ipairs(instance.cnffiles) do -            instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/')) +            instance.cnffiles[k] = collapse_path(gsub(fname,"\\",'/'))          end          for i=1,3 do              instance.rootpath = file.dirname(instance.rootpath)          end -        instance.rootpath = file.collapse_path(instance.rootpath) +        instance.rootpath = collapse_path(instance.rootpath)          if instance.diskcache and not instance.renewcache then              resolvers.loadoldconfig(instance.cnffiles)              if instance.loaderror then @@ -4858,12 +5090,12 @@ function resolvers.load_lua()      else          instance.rootpath = instance.luafiles[1]          for k,fname in ipairs(instance.luafiles) do -            instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/')) +            instance.luafiles[k] = collapse_path(gsub(fname,"\\",'/'))          end          for i=1,3 do              instance.rootpath = file.dirname(instance.rootpath)          end -        instance.rootpath = file.collapse_path(instance.rootpath) +        instance.rootpath = collapse_path(instance.rootpath)          resolvers.loadnewconfig()          collapse_cnf_data()      end @@ -4925,7 +5157,7 @@ function resolvers.locatelists()          if trace_verbose then              logs.report("fileio","locating list of %s",path)          end -        resolvers.locatedatabase(file.collapse_path(path)) +        resolvers.locatedatabase(collapse_path(path))      end  end @@ -5184,6 +5416,7 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl              date    = os.date("%Y-%m-%d"),              time    = os.date("%H:%M:%S"),              content = files, +            uuid    = os.uuid(),          }          local ok = io.savedata(luaname,resolvers.serialize(data))          if ok then @@ -5206,6 +5439,12 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl      end  end +local data_state = { } + +function resolvers.data_state() +    return data_state or { } +end +  function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload      filename = ((not filename or (filename == "")) and dataname) or filename      filename = (makename and makename(dataname,filename)) or file.join(pathname,filename) @@ -5213,6 +5452,7 @@ function resolvers.load_data(pathname,dataname,filename,makename) -- untested wi      if blob then          local data = blob()          if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then +            data_state[#data_state+1] = data.uuid              if trace_verbose then                  logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename)              end @@ -5467,7 +5707,7 @@ function resolvers.clean_path_list(str)      local t = resolvers.expanded_path_list(str)      if t then          for i=1,#t do -            t[i] = file.collapse_path(resolvers.clean_path(t[i])) +            t[i] = collapse_path(resolvers.clean_path(t[i]))          end      end      return t @@ -5664,8 +5904,8 @@ end  local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc)      local result = collected or { }      local stamp  = nil -    filename = file.collapse_path(filename)  -- elsewhere -    filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere +    filename = collapse_path(filename)  -- elsewhere +    filename = collapse_path(gsub(filename,"\\","/")) -- elsewhere      -- speed up / beware: format problem      if instance.remember then          stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -5896,7 +6136,7 @@ local function collect_instance_files(filename,collected) -- todo : plugin (scan          end      end      for k=1,#result do -        result[k] = file.collapse_path(result[k]) +        result[k] = collapse_path(result[k])      end      if instance.remember then          instance.found[stamp] = result @@ -6048,9 +6288,9 @@ function resolvers.load(option)      statistics.starttiming(instance)      resolvers.resetconfig()      resolvers.identify_cnf() -    resolvers.load_lua() +    resolvers.load_lua() -- will become the new method      resolvers.expand_variables() -    resolvers.load_cnf() +    resolvers.load_cnf() -- will be skipped when we have a lua file      resolvers.expand_variables()      if option ~= "nofiles" then          resolvers.load_hash() @@ -6397,6 +6637,7 @@ function caches.savedata(filepath,filename,data,raw)      if raw then          reduce, simplify = false, false      end +    data.cache_uuid = os.uuid()      if caches.direct then          file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex      else diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua index 344ff42c5..22abf74b1 100644 --- a/scripts/context/lua/mtx-context.lua +++ b/scripts/context/lua/mtx-context.lua @@ -992,24 +992,29 @@ local loaded = false  function scripts.context.metapost()      local filename = environment.files[1] or "" ---~     local tempname = "mtx-context-metapost.tex" ---~     local tempdata = string.format(template,"metafun",filename) ---~     io.savedata(tempname,tempdata) ---~     environment.files[1] = tempname ---~     environment.setargument("result",file.removesuffix(filename)) ---~     environment.setargument("once",true) ---~     scripts.context.run()      if not loaded then          dofile(resolvers.find_file("mlib-run.lua"))          loaded = true          commands = commands or { }          commands.writestatus = logs.report      end -    local formatname = environment.arguments("format") or "metafun" +    local formatname = environment.argument("format") or "metafun"      if formatname == "" or type(format) == "boolean" then          formatname = "metafun"      end -    if environment.arguments("svg") then +    if environment.argument("pdf") then +        local basename = file.removesuffix(filename) +        local resultname = environment.argument("result") or basename +        local jobname = "mtx-context-metapost" +        local tempname = file.addsuffix(jobname,"tex") +        io.savedata(tempname,string.format(template,"metafun",filename)) +        environment.files[1] = tempname +        environment.setargument("result",resultname) +        environment.setargument("once",true) +        scripts.context.run() +        scripts.context.purge_job(jobname,true) +        scripts.context.purge_job(resultname,true) +    elseif environment.argument("svg") then          metapost.directrun(formatname,filename,"svg")      else          metapost.directrun(formatname,filename,"mps") diff --git a/scripts/context/lua/mtx-fonts.lua b/scripts/context/lua/mtx-fonts.lua index 0cd9a3270..67c48d0a8 100644 --- a/scripts/context/lua/mtx-fonts.lua +++ b/scripts/context/lua/mtx-fonts.lua @@ -20,23 +20,46 @@ function scripts.fonts.reload(verbose)  end  function scripts.fonts.names(name) +    local simpleversion = 1.001 +    local simplelist = { "ttf", "otf", "ttc", "dfont" }      name = name or "luatex-fonts-names.lua" +    fonts.names.filters.list = simplelist +    fonts.names.version = simpleversion -- this number is the same as in font-dum.lua +    logs.report("fontnames","generating font database for 'luatex-fonts' version %s",fonts.names.version)      fonts.names.identify(true)      local data = fonts.names.data      if data then -        data.fallback_mapping = nil +        local simplemappings = { } +        local simplified = { +            mappings = simplemappings, +            version = simpleversion, +        } +        local specifications = data.specifications +        for _, format in ipairs(simplelist) do +            for tag, index in pairs(data.mappings[format]) do +                local s = specifications[index] +                simplemappings[tag] = { s.rawname, s.filename, s.subfont } +            end +        end          logs.report("fontnames","saving names in '%s'",name) -        io.savedata(name,table.serialize(data,true)) +        io.savedata(name,table.serialize(simplified,true)) +        local data = io.loaddata(resolvers.find_file("font-dum.lua","tex")) +        local dummy = string.match(data,"fonts%.names%.version%s*=%s*([%d%.]+)") +        if tonumber(dummy) ~= simpleversion then +            logs.report("fontnames","warning: version number %s in 'font-dum' does not match database version number %s",dummy or "?",simpleversion) +        end      elseif lfs.isfile(name) then          os.remove(name)      end  end -local function showfeatures(v,n,f,s,t) -    logs.simple("fontname: %s",v) -    logs.simple("fullname: %s",n) -    logs.simple("filename: %s",f) -    local features = fonts.get_features(f,t) +local function showfeatures(tag,specification) +    logs.simple("mapping : %s",tag) +    logs.simple("fontname: %s",specification.fontname) +    logs.simple("fullname: %s",specification.fullname) +    logs.simple("filename: %s",specification.filename) +    -- maybe more +    local features = fonts.get_features(specification.filename,specification.format)      if features then          for what, v in table.sortedpairs(features) do              local data = features[what] @@ -61,6 +84,10 @@ local function showfeatures(v,n,f,s,t)                  end              end          end +    else +        logs.simple() +        logs.simple("no features") +        logs.simple()      end      logs.reportline()  end @@ -74,7 +101,7 @@ local function make_pattern(pattern) -- will become helper in string      if pattern == "" then          pattern = ".*"      else -        pattern = "^" .. pattern .. "$" +--~         pattern = "^" .. pattern .. "$"      end      return pattern  end @@ -87,53 +114,120 @@ local function reloadbase(reload)      end  end -function scripts.fonts.list_by_pattern(pattern,reload,all,info) -    reloadbase(reload) -    local t = fonts.names.list(make_pattern(pattern)) +local function subfont(sf) +    if sf then +        return string.format("index: % 2s", sf) +    else +        return "" +    end +end +local function fontweight(fw) +    if fw then +        return string.format("conflict: %s", fw) +    else +        return "" +    end +end + +local function list_specifications(t)      if t then          local s, w = table.sortedkeys(t), { 0, 0, 0 }          for k,v in ipairs(s) do              local entry = t[v] -            local n = #v        if n > w[1] then w[1] = n end -            local n = #entry[2] if n > w[2] then w[2] = n end -            local n = #entry[3] if n > w[3] then w[3] = n end +            s[k] = { +                entry.familyname  or "<nofamily>", +                entry.weight      or "<noweight>", +                entry.style       or "<nostyle>", +                entry.width       or "<nowidth>", +                entry.fontname, +                entry.filename, +                subfont(entry.subfont), +                fontweight(entry.fontweight), +            }          end -        local template = "%-" .. w[1] .. "s  %-" .. w[2] .. "s  %-" .. w[3] .. "s %s" +        table.formatcolumns(s)          for k,v in ipairs(s) do -            local entry = t[v] -            local tag, fontname, filename, sub = v, entry[2], entry[3], entry[4] -            if sub then sub = "(sub)" else sub = "" end -            if info then -                showfeatures(tag,fontname,filename,sub,t) -            else -                print(string.format(template,tag,fontname,filename,sub)) +            texio.write_nl(v) +        end +    end +end + +local function list_matches(t) +    if t then +        local s, w = table.sortedkeys(t), { 0, 0, 0 } +        if info then +            for k,v in ipairs(s) do +                showfeatures(v,t[v]) +            end +        else +            for k,v in ipairs(s) do +                local entry = t[v] +                s[k] = { +                    v, +                    entry.fontname, +                    entry.filename, +                    subfont(entry.subfont) +                } +            end +            table.formatcolumns(s) +            for k,v in ipairs(s) do +                texio.write_nl(v)              end          end      end  end -function scripts.fonts.list_by_specification(specification,reload,all,info) +function scripts.fonts.list() + +    local all     = environment.argument("all") +    local info    = environment.argument("info") +    local reload  = environment.argument("reload") +    local pattern = environment.argument("pattern") +    local filter  = environment.argument("filter") +    local given   = environment.files[1] +      reloadbase(reload) -    local t = fonts.names.collectspec(specification) -    if t then -        local w, tags = { 0, 0, 0 }, { } -        for k,entry in ipairs(t) do -            local s = entry[5] .. "-" .. (entry[6] or "noweight") .. "-" .. (entry[7] or "nostyle") .. "-" .. (entry[8] or "nowidth") -            local n = #s        if n > w[1] then w[1] = n end -            local n = #entry[2] if n > w[2] then w[2] = n end -            local n = #entry[3] if n > w[3] then w[3] = n end -            tags[k] = s + +    if environment.argument("name") then +        if pattern then +            --~ mtxrun --script font --list --name --pattern=*somename* +            list_matches(fonts.names.list(make_pattern(pattern),reload,all)) +        elseif filter then +            logs.report("fontnames","not supported: --list --name --filter",name) +        elseif given then +            --~ mtxrun --script font --list --name somename +            list_matches(fonts.names.list(given,reload,all)) +        else +            logs.report("fontnames","not supported: --list --name <no specification>",name)          end -        local template = "%-" .. w[1] .."s  %-" .. w[2] .. "s  %-" .. w[3] .. "s  %s" -        for k,entry in ipairs(t) do -            local tag, fontname, filename, sub, name, weight, style = tags[k], entry[2], entry[3], entry[4], entry[5], entry[6], entry[7] -            if sub then sub = "(sub)" else sub = "" end -            print(string.format(template,tag,fontname,filename,sub)) +    elseif environment.argument("spec") then +        if pattern then +            --~ mtxrun --script font --list --spec --pattern=*somename* +            logs.report("fontnames","not supported: --list --spec --pattern",name) +        elseif filter then +            --~ mtxrun --script font --list --spec --filter="fontname=somename" +            list_specifications(fonts.names.getlookups(filter),nil,reload) +        elseif given then +            --~ mtxrun --script font --list --spec somename +            list_specifications(fonts.names.collectspec(given,reload,all)) +        else +            logs.report("fontnames","not supported: --list --spec <no specification>",name)          end +    elseif pattern then +        --~ mtxrun --script font --list --pattern=*somename* +        list_matches(fonts.names.list(make_pattern(pattern),reload,all)) +    elseif given then +        --~ mtxrun --script font --list somename +        list_matches(fonts.names.list(given,reload,all)) +    else +        logs.report("fontnames","not supported: --list <no specification>",name)      end +  end -function scripts.fonts.save(name,sub) +function scripts.fonts.save() +    local name = environment.files[1] or "" +    local sub  = environment.files[2] or ""      local function save(savename,fontblob)          if fontblob then              savename = savename:lower() .. ".lua" @@ -171,37 +265,49 @@ function scripts.fonts.save(name,sub)      end  end -logs.extendbanner("Font Tools 0.20",true) +logs.extendbanner("Font Tools 0.21",true)  messages.help = [[  --reload              generate new font database ---list [--info]       list installed fonts (show info)  --save                save open type font in raw table  --names               generate 'luatex-fonts-names.lua' (not for context!) +--list                list installed fonts (show info) + +--name                filter by name +--spec                filter by spec  --pattern=str         filter files using pattern +--filter=list         key-value pairs  --all                 provide alternatives +--info                give more details +--track=list          enable trackers + +examples: + +mtxrun --script font --list somename (== --pattern=*somename*) + +mtxrun --script font --list --name somename +mtxrun --script font --list --name --pattern=*somename* + +mtxrun --script font --list --spec somename +mtxrun --script font --list --spec somename-bold-italic +mtxrun --script font --list --spec --pattern=*somename* +mtxrun --script font --list --spec --filter="fontname=somename" +mtxrun --script font --list --spec --filter="familyname=somename,weight=bold,style=italic,width=condensed"  ]] +local track = environment.argument("track") + +if track then trackers.enable(track) end +  if environment.argument("reload") then      scripts.fonts.reload(true)  elseif environment.argument("names") then      scripts.fonts.names() -elseif environment.argument("list") then -    local all     = environment.argument("all") -    local info    = environment.argument("info") -    local reload  = environment.argument("reload") -    if environment.argument("pattern") then -        scripts.fonts.list_by_pattern(environment.argument("pattern"),reload,all,info) -    elseif environment.files[1] then -        scripts.fonts.list_by_specification(environment.files[1],reload,all,info) -    else -        scripts.fonts.list_by_pattern("",reload,all,info) -- wildcard -    end  elseif environment.argument("save") then -    local name = environment.files[1] or "" -    local sub  = environment.files[2] or "" -    scripts.fonts.save(name,sub) +    scripts.fonts.save() +elseif environment.argument("list") then +    scripts.fonts.list()  else      logs.help(messages.help)  end diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index 130ad493c..0d3f08025 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -789,6 +789,7 @@ local function do_serialize(root,name,depth,level,indexed)              handle(format("%s{",depth))          end      end +    -- we could check for k (index) being number (cardinal)      if root and next(root) then          local first, last = nil, 0 -- #root cannot be trusted here          if compact then @@ -811,7 +812,7 @@ local function do_serialize(root,name,depth,level,indexed)                      if hexify then                          handle(format("%s 0x%04X,",depth,v))                      else -                        handle(format("%s %.99g,",depth,v)) +                        handle(format("%s %s,",depth,v)) -- %.99g                      end                  elseif t == "string" then                      if reduce and tonumber(v) then @@ -851,25 +852,25 @@ local function do_serialize(root,name,depth,level,indexed)              --~ if hexify then              --~     handle(format("%s %s=0x%04X,",depth,key(k),v))              --~ else -            --~     handle(format("%s %s=%.99g,",depth,key(k),v)) +            --~     handle(format("%s %s=%s,",depth,key(k),v)) -- %.99g              --~ end                  if type(k) == "number" then -- or find(k,"^%d+$") then                      if hexify then                          handle(format("%s [0x%04X]=0x%04X,",depth,k,v))                      else -                        handle(format("%s [%s]=%.99g,",depth,k,v)) +                        handle(format("%s [%s]=%s,",depth,k,v)) -- %.99g                      end                  elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then                      if hexify then                          handle(format("%s %s=0x%04X,",depth,k,v))                      else -                        handle(format("%s %s=%.99g,",depth,k,v)) +                        handle(format("%s %s=%s,",depth,k,v)) -- %.99g                      end                  else                      if hexify then                          handle(format("%s [%q]=0x%04X,",depth,k,v))                      else -                        handle(format("%s [%q]=%.99g,",depth,k,v)) +                        handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g                      end                  end              elseif t == "string" then @@ -1868,8 +1869,12 @@ function file.dirname(name,default)      return match(name,"^(.+)[/\\].-$") or (default or "")  end +--~ function file.basename(name) +--~     return match(name,"^.+[/\\](.-)$") or name +--~ end +  function file.basename(name) -    return match(name,"^.+[/\\](.-)$") or name +    return match(name,"^.*[/\\](.-)$") or name  end  function file.nameonly(name) @@ -4872,7 +4877,7 @@ local noparent = 1 - (lparent+rparent)  local nested   = lpeg.P{lparent * (noparent + lpeg.V(1))^0 * rparent}  local value    = lpeg.P(lparent * lpeg.C((noparent + nested)^0) * rparent) -- lpeg.P{"("*C(((1-S("()"))+V(1))^0)*")"} -local lp_child   = Cc("expr.child(e,'") * R("az","AZ","--","__")^1 * Cc("')") +local lp_child   = Cc("expr.child(ll,'") * R("az","AZ","--","__")^1 * Cc("')")  local lp_string  = Cc("'") * R("az","AZ","--","__")^1 * Cc("'")  local lp_content = (P("'") * (1-P("'"))^0 * P("'") + P('"') * (1-P('"'))^0 * P('"')) @@ -4882,9 +4887,9 @@ local lp_special = (C(P("name")+P("text")+P("tag")+P("count")+P("child"))) * val      if expressions[t] then          s = s and s ~= "" and cleaner:match(s)          if s and s ~= "" then -            return "expr." .. t .. "(e," .. s ..")" +            return "expr." .. t .. "(ll," .. s ..")"          else -            return "expr." .. t .. "(e)" +            return "expr." .. t .. "(ll)"          end      else          return "expr.error(" .. t .. ")" @@ -5434,38 +5439,42 @@ expressions.name = function(e,n) -- ns + tg  end  expressions.tag = function(e,n) -- only tg -    local found = false -    n = tonumber(n) or 0 -    if n == 0 then -        found = (type(e) == "table") and e -- seems to fail -    elseif n < 0 then -        local d, k = e.__p__.dt, e.ni -        for i=k-1,1,-1 do -            local di = d[i] -            if type(di) == "table" then -                if n == -1 then -                    found = di -                    break -                else -                    n = n + 1 +    if not e then +        return "" +    else +        local found = false +        n = tonumber(n) or 0 +        if n == 0 then +            found = (type(e) == "table") and e -- seems to fail +        elseif n < 0 then +            local d, k = e.__p__.dt, e.ni +            for i=k-1,1,-1 do +                local di = d[i] +                if type(di) == "table" then +                    if n == -1 then +                        found = di +                        break +                    else +                        n = n + 1 +                    end                  end              end -        end -    else -        local d, k = e.__p__.dt, e.ni -        for i=k+1,#d,1 do -            local di = d[i] -            if type(di) == "table" then -                if n == 1 then -                    found = di -                    break -                else -                    n = n - 1 +        else +            local d, k = e.__p__.dt, e.ni +            for i=k+1,#d,1 do +                local di = d[i] +                if type(di) == "table" then +                    if n == 1 then +                        found = di +                        break +                    else +                        n = n - 1 +                    end                  end              end          end +        return (found and found.tg) or ""      end -    return (found and found.tg) or ""  end  --[[ldx-- @@ -5992,7 +6001,7 @@ local function include(xmldata,pattern,attribute,recursive,loaddata)  --~                 local settings = xmldata.settings  --~                 settings.parent_root = xmldata -- to be tested  --~                 local xi = xmlconvert(data,settings) -                local xi = xml.inheritedconvert(element,xmldata) +                local xi = xml.inheritedconvert(data,xmldata)                  if not xi then                      epdt[ek.ni] = "" -- xml.empty(d,k)                  else @@ -7046,7 +7055,6 @@ end  local name, banner = 'report', 'context'  local function report(category,fmt,...) ---~ print(fmt,...)      if fmt then          write_nl(format("%s | %s: %s",name,category,format(fmt,...)))      elseif category then @@ -7187,6 +7195,8 @@ local format, gsub, find, lower, upper, match, gmatch = string.format, string.gs  local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys  local next, type = next, type +local collapse_path = file.collapse_path +  local trace_locating, trace_detail, trace_verbose  = false, false, false  trackers.register("resolvers.verbose",  function(v) trace_verbose  = v end) @@ -7575,7 +7585,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat      end      if ok then          local function validate(s) -            s = file.collapse_path(s) +            s = collapse_path(s)              return s ~= "" and not find(s,dummy_path_expr) and s          end          for k=1,#pathlist do @@ -7584,7 +7594,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat      else          for k=1,#pathlist do              for p in gmatch(pathlist[k],"([^,]+)") do -                p = file.collapse_path(p) +                p = collapse_path(p)                  if p ~= "" then newlist[#newlist+1] = p end              end          end @@ -7649,9 +7659,9 @@ local function identify_own()      local ownpath = resolvers.getownpath() or lfs.currentdir()      local ie = instance.environment      if ownpath then -        if resolvers.env('SELFAUTOLOC')    == "" then os.env['SELFAUTOLOC']    = file.collapse_path(ownpath) end -        if resolvers.env('SELFAUTODIR')    == "" then os.env['SELFAUTODIR']    = file.collapse_path(ownpath .. "/..") end -        if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end +        if resolvers.env('SELFAUTOLOC')    == "" then os.env['SELFAUTOLOC']    = collapse_path(ownpath) end +        if resolvers.env('SELFAUTODIR')    == "" then os.env['SELFAUTODIR']    = collapse_path(ownpath .. "/..") end +        if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = collapse_path(ownpath .. "/../..") end      else          logs.report("fileio","error: unable to locate ownpath")          os.exit() @@ -7680,7 +7690,7 @@ function resolvers.identify_cnf()          local function locate(filename,list)              for i=1,#t do                  local ti = t[i] -                local texmfcnf = file.collapse_path(file.join(ti,filename)) +                local texmfcnf = collapse_path(file.join(ti,filename))                  if lfs.isfile(texmfcnf) then                      list[#list+1] = texmfcnf                  end @@ -7692,11 +7702,11 @@ function resolvers.identify_cnf()  end  local function load_cnf_file(fname) +    -- why don't we just read the file from the cache +    -- we need to switch to the lua file      fname = resolvers.clean_path(fname)      local lname = file.replacesuffix(fname,'lua') -    local f = io.open(lname) -    if f then -- this will go -        f:close() +    if lfs.isfile(lname) then          local dname = file.dirname(fname)          if not instance.configuration[dname] then              resolvers.load_data(dname,'configuration',lname and file.basename(lname)) @@ -7761,13 +7771,17 @@ local function collapse_cnf_data() -- potential optimization: pass start index (      end  end -function resolvers.load_cnf() -    local function loadoldconfigdata() -        for _, fname in ipairs(instance.cnffiles) do -            load_cnf_file(fname) -        end +local function loadoldconfigdata() +    for _, fname in ipairs(instance.cnffiles) do +        load_cnf_file(fname)      end +end + +function resolvers.load_cnf()      -- instance.cnffiles contain complete names now ! +    -- we still use a funny mix of cnf and new but soon +    -- we will switch to lua exclusively as we only use +    -- the file to collect the tree roots      if #instance.cnffiles == 0 then          if trace_verbose then              logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)") @@ -7775,12 +7789,12 @@ function resolvers.load_cnf()      else          instance.rootpath = instance.cnffiles[1]          for k,fname in ipairs(instance.cnffiles) do -            instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/')) +            instance.cnffiles[k] = collapse_path(gsub(fname,"\\",'/'))          end          for i=1,3 do              instance.rootpath = file.dirname(instance.rootpath)          end -        instance.rootpath = file.collapse_path(instance.rootpath) +        instance.rootpath = collapse_path(instance.rootpath)          if instance.diskcache and not instance.renewcache then              resolvers.loadoldconfig(instance.cnffiles)              if instance.loaderror then @@ -7804,12 +7818,12 @@ function resolvers.load_lua()      else          instance.rootpath = instance.luafiles[1]          for k,fname in ipairs(instance.luafiles) do -            instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/')) +            instance.luafiles[k] = collapse_path(gsub(fname,"\\",'/'))          end          for i=1,3 do              instance.rootpath = file.dirname(instance.rootpath)          end -        instance.rootpath = file.collapse_path(instance.rootpath) +        instance.rootpath = collapse_path(instance.rootpath)          resolvers.loadnewconfig()          collapse_cnf_data()      end @@ -7871,7 +7885,7 @@ function resolvers.locatelists()          if trace_verbose then              logs.report("fileio","locating list of %s",path)          end -        resolvers.locatedatabase(file.collapse_path(path)) +        resolvers.locatedatabase(collapse_path(path))      end  end @@ -8130,6 +8144,7 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl              date    = os.date("%Y-%m-%d"),              time    = os.date("%H:%M:%S"),              content = files, +            uuid    = os.uuid(),          }          local ok = io.savedata(luaname,resolvers.serialize(data))          if ok then @@ -8152,6 +8167,12 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl      end  end +local data_state = { } + +function resolvers.data_state() +    return data_state or { } +end +  function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload      filename = ((not filename or (filename == "")) and dataname) or filename      filename = (makename and makename(dataname,filename)) or file.join(pathname,filename) @@ -8159,6 +8180,7 @@ function resolvers.load_data(pathname,dataname,filename,makename) -- untested wi      if blob then          local data = blob()          if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then +            data_state[#data_state+1] = data.uuid              if trace_verbose then                  logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename)              end @@ -8413,7 +8435,7 @@ function resolvers.clean_path_list(str)      local t = resolvers.expanded_path_list(str)      if t then          for i=1,#t do -            t[i] = file.collapse_path(resolvers.clean_path(t[i])) +            t[i] = collapse_path(resolvers.clean_path(t[i]))          end      end      return t @@ -8610,8 +8632,8 @@ end  local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc)      local result = collected or { }      local stamp  = nil -    filename = file.collapse_path(filename)  -- elsewhere -    filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere +    filename = collapse_path(filename)  -- elsewhere +    filename = collapse_path(gsub(filename,"\\","/")) -- elsewhere      -- speed up / beware: format problem      if instance.remember then          stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -8842,7 +8864,7 @@ local function collect_instance_files(filename,collected) -- todo : plugin (scan          end      end      for k=1,#result do -        result[k] = file.collapse_path(result[k]) +        result[k] = collapse_path(result[k])      end      if instance.remember then          instance.found[stamp] = result @@ -8994,9 +9016,9 @@ function resolvers.load(option)      statistics.starttiming(instance)      resolvers.resetconfig()      resolvers.identify_cnf() -    resolvers.load_lua() +    resolvers.load_lua() -- will become the new method      resolvers.expand_variables() -    resolvers.load_cnf() +    resolvers.load_cnf() -- will be skipped when we have a lua file      resolvers.expand_variables()      if option ~= "nofiles" then          resolvers.load_hash() @@ -9343,6 +9365,7 @@ function caches.savedata(filepath,filename,data,raw)      if raw then          reduce, simplify = false, false      end +    data.cache_uuid = os.uuid()      if caches.direct then          file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex      else diff --git a/scripts/context/stubs/mswin/luatools.lua b/scripts/context/stubs/mswin/luatools.lua index 2bc943210..abd80b8b4 100644 --- a/scripts/context/stubs/mswin/luatools.lua +++ b/scripts/context/stubs/mswin/luatools.lua @@ -308,7 +308,7 @@ if not modules then modules = { } end modules ['l-lpeg'] = {      license   = "see context related readme files"  } -local P, S, Ct, C, Cs, Cc = lpeg.P, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc +local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc  --~ l-lpeg.lua : @@ -415,6 +415,41 @@ end  --~     return p  --~ end +--~ from roberto's site: +--~ +--~ -- decode a two-byte UTF-8 sequence +--~ local function f2 (s) +--~   local c1, c2 = string.byte(s, 1, 2) +--~   return c1 * 64 + c2 - 12416 +--~ end +--~ +--~ -- decode a three-byte UTF-8 sequence +--~ local function f3 (s) +--~   local c1, c2, c3 = string.byte(s, 1, 3) +--~   return (c1 * 64 + c2) * 64 + c3 - 925824 +--~ end +--~ +--~ -- decode a four-byte UTF-8 sequence +--~ local function f4 (s) +--~   local c1, c2, c3, c4 = string.byte(s, 1, 4) +--~   return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168 +--~ end +--~ +--~ local cont = lpeg.R("\128\191")   -- continuation byte +--~ +--~ local utf8 = lpeg.R("\0\127") / string.byte +--~            + lpeg.R("\194\223") * cont / f2 +--~            + lpeg.R("\224\239") * cont * cont / f3 +--~            + lpeg.R("\240\244") * cont * cont * cont / f4 +--~ +--~ local decode_pattern = lpeg.Ct(utf8^0) * -1 + + +local cont = R("\128\191")   -- continuation byte + +lpeg.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont + +  end -- of closure @@ -431,9 +466,9 @@ if not modules then modules = { } end modules ['l-table'] = {  table.join = table.concat  local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove -local format, find, gsub, lower, dump = string.format, string.find, string.gsub, string.lower, string.dump +local format, find, gsub, lower, dump, match = string.format, string.find, string.gsub, string.lower, string.dump, string.match  local getmetatable, setmetatable = getmetatable, setmetatable -local type, next, tostring, ipairs = type, next, tostring, ipairs +local type, next, tostring, tonumber, ipairs, pairs = type, next, tostring, tonumber, ipairs, pairs  function table.strip(tab)      local lst = { } @@ -721,6 +756,8 @@ end  --  -- local propername = lpeg.P(lpeg.R("AZ","az","__") * lpeg.R("09","AZ","az", "__")^0 * lpeg.P(-1) ) +-- problem: there no good number_to_string converter with the best resolution +  local function do_serialize(root,name,depth,level,indexed)      if level > 0 then          depth = depth .. " " @@ -743,6 +780,7 @@ local function do_serialize(root,name,depth,level,indexed)              handle(format("%s{",depth))          end      end +    -- we could check for k (index) being number (cardinal)      if root and next(root) then          local first, last = nil, 0 -- #root cannot be trusted here          if compact then @@ -765,10 +803,10 @@ local function do_serialize(root,name,depth,level,indexed)                      if hexify then                          handle(format("%s 0x%04X,",depth,v))                      else -                        handle(format("%s %s,",depth,v)) +                        handle(format("%s %s,",depth,v)) -- %.99g                      end                  elseif t == "string" then -                    if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then +                    if reduce and tonumber(v) then                          handle(format("%s %s,",depth,v))                      else                          handle(format("%s %q,",depth,v)) @@ -805,29 +843,29 @@ local function do_serialize(root,name,depth,level,indexed)              --~ if hexify then              --~     handle(format("%s %s=0x%04X,",depth,key(k),v))              --~ else -            --~     handle(format("%s %s=%s,",depth,key(k),v)) +            --~     handle(format("%s %s=%s,",depth,key(k),v)) -- %.99g              --~ end                  if type(k) == "number" then -- or find(k,"^%d+$") then                      if hexify then                          handle(format("%s [0x%04X]=0x%04X,",depth,k,v))                      else -                        handle(format("%s [%s]=%s,",depth,k,v)) +                        handle(format("%s [%s]=%s,",depth,k,v)) -- %.99g                      end                  elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then                      if hexify then                          handle(format("%s %s=0x%04X,",depth,k,v))                      else -                        handle(format("%s %s=%s,",depth,k,v)) +                        handle(format("%s %s=%s,",depth,k,v)) -- %.99g                      end                  else                      if hexify then                          handle(format("%s [%q]=0x%04X,",depth,k,v))                      else -                        handle(format("%s [%q]=%s,",depth,k,v)) +                        handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g                      end                  end              elseif t == "string" then -                if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then +                if reduce and tonumber(v) then                  --~ handle(format("%s %s=%s,",depth,key(k),v))                      if type(k) == "number" then -- or find(k,"^%d+$") then                          if hexify then @@ -1036,7 +1074,7 @@ function table.tofile(filename,root,name,reduce,noquotes,hexify)      end  end -local function flatten(t,f,complete) +local function flatten(t,f,complete) -- is this used? meybe a variant with next, ...      for i=1,#t do          local v = t[i]          if type(v) == "table" then @@ -1065,6 +1103,24 @@ end  table.flatten_one_level = table.unnest +-- a better one: + +local function flattened(t,f) +    if not f then +        f = { } +    end +    for k, v in next, t do +        if type(v) == "table" then +            flattened(v,f) +        else +            f[k] = v +        end +    end +    return f +end + +table.flattened = flattened +  -- the next three may disappear  function table.remove_value(t,value) -- todo: n @@ -1200,7 +1256,7 @@ function table.clone(t,p) -- t is optional or nil or table      elseif not t then          t = { }      end -    setmetatable(t, { __index = function(_,key) return p[key] end }) +    setmetatable(t, { __index = function(_,key) return p[key] end }) -- why not __index = p ?      return t  end @@ -1615,7 +1671,8 @@ if not modules then modules = { } end modules ['l-os'] = {      license   = "see context related readme files"  } -local find = string.find +local find, format = string.find, string.format +local random, ceil = math.random, math.ceil  function os.resultof(command)      return io.popen(command,"r"):read("*all") @@ -1712,6 +1769,8 @@ function os.currentplatform(name,default)              elseif name == "macosx" then                  if find(architecture,"i386") then                      platform = "osx-intel" +                elseif find(architecture,"x86_64") then +                    platform = "osx-64"                  else                      platform = "osx-ppc"                  end @@ -1738,6 +1797,29 @@ function os.currentplatform(name,default)      return platform  end +-- beware, we set the randomseed +-- + +-- from wikipedia: Version 4 UUIDs use a scheme relying only on random numbers. This algorithm sets the +-- version number as well as two reserved bits. All other bits are set using a random or pseudorandom +-- data source. Version 4 UUIDs have the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx with hexadecimal +-- digits x and hexadecimal digits 8, 9, A, or B for y. e.g. f47ac10b-58cc-4372-a567-0e02b2c3d479. +-- +-- as we don't call this function too often there is not so much risk on repetition + + +local t = { 8, 9, "a", "b" } + +function os.uuid() +    return format("%04x%04x-4%03x-%s%03x-%04x-%04x%04x%04x", +        random(0xFFFF),random(0xFFFF), +        random(0x0FFF), +        t[ceil(random(4))] or 8,random(0x0FFF), +        random(0xFFFF), +        random(0xFFFF),random(0xFFFF),random(0xFFFF) +    ) +end +  end -- of closure @@ -1778,8 +1860,12 @@ function file.dirname(name,default)      return match(name,"^(.+)[/\\].-$") or (default or "")  end +--~ function file.basename(name) +--~     return match(name,"^.+[/\\](.-)$") or name +--~ end +  function file.basename(name) -    return match(name,"^.+[/\\](.-)$") or name +    return match(name,"^.*[/\\](.-)$") or name  end  function file.nameonly(name) @@ -1857,6 +1943,7 @@ function file.collapse_path(str)      return str  end +--~ print(file.collapse_path("/a"))  --~ print(file.collapse_path("a/./b/.."))  --~ print(file.collapse_path("a/aa/../b/bb"))  --~ print(file.collapse_path("a/../..")) @@ -3028,9 +3115,9 @@ function aux.make_settings_to_hash_pattern(set,how)      end  end -function aux.settings_to_hash(str) +function aux.settings_to_hash(str,existing)      if str and str ~= "" then -        hash = { } +        hash = existing or { }          if moretolerant then              pattern_b_s:match(str)          else @@ -3042,9 +3129,9 @@ function aux.settings_to_hash(str)      end  end -function aux.settings_to_hash_tolerant(str) +function aux.settings_to_hash_tolerant(str,existing)      if str and str ~= "" then -        hash = { } +        hash = existing or { }          pattern_b_s:match(str)          return hash      else @@ -3052,9 +3139,9 @@ function aux.settings_to_hash_tolerant(str)      end  end -function aux.settings_to_hash_strict(str) +function aux.settings_to_hash_strict(str,existing)      if str and str ~= "" then -        hash = { } +        hash = existing or { }          pattern_c_s:match(str)          return next(hash) and hash      else @@ -3142,7 +3229,7 @@ function aux.getparameters(self,class,parentclass,settings)          sc = table.clone(self[parent])          self[class] = sc      end -    aux.add_settings_to_array(sc, settings) +    aux.settings_to_hash(settings,sc)  end  -- temporary here @@ -3230,12 +3317,15 @@ if not modules then modules = { } end modules ['trac-tra'] = {  -- bound to a variable, like node.new, node.copy etc (contrary to for instance  -- node.has_attribute which is bound to a has_attribute local variable in mkiv) +local getinfo = debug.getinfo +local type, next = type, next +local concat = table.concat +local format, find, lower, gmatch, gsub = string.format, string.find, string.lower, string.gmatch, string.gsub +  debugger = debugger or { }  local counters = { }  local names = { } -local getinfo = debug.getinfo -local format, find, lower, gmatch, gsub = string.format, string.find, string.lower, string.gmatch, string.gsub  -- one @@ -3363,11 +3453,11 @@ end  --~ print("")  --~ debugger.showstats(print,3) -trackers = trackers or { } +setters      = setters      or { } +setters.data = setters.data or { } -local data, done = { }, { } - -local function set(what,value) +local function set(t,what,value) +    local data, done = t.data, t.done      if type(what) == "string" then          what = aux.settings_to_array(what) -- inefficient but ok      end @@ -3386,28 +3476,30 @@ local function set(what,value)      end  end -local function reset() -    for d, f in next, data do +local function reset(t) +    for d, f in next, t.data do          for i=1,#f do              f[i](false)          end      end  end -local function enable(what) -    set(what,true) +local function enable(t,what) +    set(t,what,true)  end -local function disable(what) +local function disable(t,what) +    local data = t.data      if not what or what == "" then -        done = { } -        reset() +        t.done = { } +        reset(t)      else -        set(what,false) +        set(t,what,false)      end  end -function trackers.register(what,...) +function setters.register(t,what,...) +    local data = t.data      what = lower(what)      local w = data[what]      if not w then @@ -3419,32 +3511,32 @@ function trackers.register(what,...)          if typ == "function" then              w[#w+1] = fnc          elseif typ == "string" then -            w[#w+1] = function(value) set(fnc,value,nesting) end +            w[#w+1] = function(value) set(t,fnc,value,nesting) end          end      end  end -function trackers.enable(what) -    local e = trackers.enable -    trackers.enable, done = enable, { } -    enable(string.simpleesc(what)) -    trackers.enable, done = e, { } +function setters.enable(t,what) +    local e = t.enable +    t.enable, t.done = enable, { } +    enable(t,string.simpleesc(what)) +    t.enable, t.done = e, { }  end -function trackers.disable(what) -    local e = trackers.disable -    trackers.disable, done = disable, { } -    disable(string.simpleesc(what)) -    trackers.disable, done = e, { } +function setters.disable(t,what) +    local e = t.disable +    t.disable, t.done = disable, { } +    disable(t,string.simpleesc(what)) +    t.disable, t.done = e, { }  end -function trackers.reset() -    done = { } -    reset() +function setters.reset(t) +    t.done = { } +    reset(t)  end -function trackers.list() -- pattern -    local list = table.sortedkeys(data) +function setters.list(t) -- pattern +    local list = table.sortedkeys(t.data)      local user, system = { }, { }      for l=1,#list do          local what = list[l] @@ -3457,6 +3549,139 @@ function trackers.list() -- pattern      return user, system  end +function setters.show(t) +    commands.writestatus("","") +    for k,v in ipairs(setters.list(t)) do +        commands.writestatus(t.name,v) +    end +    commands.writestatus("","") +end + +-- we could have used a bit of oo and the trackers:enable syntax but +-- there is already a lot of code around using the singluar tracker + +function setters.new(name) +    local t +    t = { +        data     = { }, +        name     = name, +        enable   = function(...) setters.enable  (t,...) end, +        disable  = function(...) setters.disable (t,...) end, +        register = function(...) setters.register(t,...) end, +        list     = function(...) setters.list    (t,...) end, +        show     = function(...) setters.show    (t,...) end, +    } +    setters.data[name] = t +    return t +end + +trackers   = setters.new("trackers") +directives = setters.new("directives") + +-- nice trick: we overload two of the directives related functions with variants that +-- do tracing (itself using a tracker) .. proof of concept + +local trace_directives = false local trace_directives = false  trackers.register("system.directives", function(v) trace_directives = v end) + +local e = directives.enable +local d = directives.disable + +function directives.enable(...) +    commands.writestatus("directives","enabling: %s",concat({...}," ")) +    e(...) +end + +function directives.disable(...) +    commands.writestatus("directives","disabling: %s",concat({...}," ")) +    d(...) +end + +--~ -- old code: +-- +--~ trackers = trackers or { } +--~ local data, done = { }, { } +--~ local function set(what,value) +--~     if type(what) == "string" then +--~         what = aux.settings_to_array(what) -- inefficient but ok +--~     end +--~     for i=1,#what do +--~         local w = what[i] +--~         for d, f in next, data do +--~             if done[d] then +--~                 -- prevent recursion due to wildcards +--~             elseif find(d,w) then +--~                 done[d] = true +--~                 for i=1,#f do +--~                     f[i](value) +--~                 end +--~             end +--~         end +--~     end +--~ end +--~ local function reset() +--~     for d, f in next, data do +--~         for i=1,#f do +--~             f[i](false) +--~         end +--~     end +--~ end +--~ local function enable(what) +--~     set(what,true) +--~ end +--~ local function disable(what) +--~     if not what or what == "" then +--~         done = { } +--~         reset() +--~     else +--~         set(what,false) +--~     end +--~ end +--~ function trackers.register(what,...) +--~     what = lower(what) +--~     local w = data[what] +--~     if not w then +--~         w = { } +--~         data[what] = w +--~     end +--~     for _, fnc in next, { ... } do +--~         local typ = type(fnc) +--~         if typ == "function" then +--~             w[#w+1] = fnc +--~         elseif typ == "string" then +--~             w[#w+1] = function(value) set(fnc,value,nesting) end +--~         end +--~     end +--~ end +--~ function trackers.enable(what) +--~     local e = trackers.enable +--~     trackers.enable, done = enable, { } +--~     enable(string.simpleesc(what)) +--~     trackers.enable, done = e, { } +--~ end +--~ function trackers.disable(what) +--~     local e = trackers.disable +--~     trackers.disable, done = disable, { } +--~     disable(string.simpleesc(what)) +--~     trackers.disable, done = e, { } +--~ end +--~ function trackers.reset() +--~     done = { } +--~     reset() +--~ end +--~ function trackers.list() -- pattern +--~     local list = table.sortedkeys(data) +--~     local user, system = { }, { } +--~     for l=1,#list do +--~         local what = list[l] +--~         if find(what,"^%*") then +--~             system[#system+1] = what +--~         else +--~             user[#user+1] = what +--~         end +--~     end +--~     return user, system +--~ end +  end -- of closure @@ -3908,6 +4133,7 @@ function statistics.timed(action,report)  end +  end -- of closure  do -- create closure to overcome 200 locals limit @@ -4241,6 +4467,8 @@ local format, gsub, find, lower, upper, match, gmatch = string.format, string.gs  local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys  local next, type = next, type +local collapse_path = file.collapse_path +  local trace_locating, trace_detail, trace_verbose  = false, false, false  trackers.register("resolvers.verbose",  function(v) trace_verbose  = v end) @@ -4629,7 +4857,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat      end      if ok then          local function validate(s) -            s = file.collapse_path(s) +            s = collapse_path(s)              return s ~= "" and not find(s,dummy_path_expr) and s          end          for k=1,#pathlist do @@ -4638,7 +4866,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat      else          for k=1,#pathlist do              for p in gmatch(pathlist[k],"([^,]+)") do -                p = file.collapse_path(p) +                p = collapse_path(p)                  if p ~= "" then newlist[#newlist+1] = p end              end          end @@ -4703,9 +4931,9 @@ local function identify_own()      local ownpath = resolvers.getownpath() or lfs.currentdir()      local ie = instance.environment      if ownpath then -        if resolvers.env('SELFAUTOLOC')    == "" then os.env['SELFAUTOLOC']    = file.collapse_path(ownpath) end -        if resolvers.env('SELFAUTODIR')    == "" then os.env['SELFAUTODIR']    = file.collapse_path(ownpath .. "/..") end -        if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end +        if resolvers.env('SELFAUTOLOC')    == "" then os.env['SELFAUTOLOC']    = collapse_path(ownpath) end +        if resolvers.env('SELFAUTODIR')    == "" then os.env['SELFAUTODIR']    = collapse_path(ownpath .. "/..") end +        if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = collapse_path(ownpath .. "/../..") end      else          logs.report("fileio","error: unable to locate ownpath")          os.exit() @@ -4734,7 +4962,7 @@ function resolvers.identify_cnf()          local function locate(filename,list)              for i=1,#t do                  local ti = t[i] -                local texmfcnf = file.collapse_path(file.join(ti,filename)) +                local texmfcnf = collapse_path(file.join(ti,filename))                  if lfs.isfile(texmfcnf) then                      list[#list+1] = texmfcnf                  end @@ -4746,11 +4974,11 @@ function resolvers.identify_cnf()  end  local function load_cnf_file(fname) +    -- why don't we just read the file from the cache +    -- we need to switch to the lua file      fname = resolvers.clean_path(fname)      local lname = file.replacesuffix(fname,'lua') -    local f = io.open(lname) -    if f then -- this will go -        f:close() +    if lfs.isfile(lname) then          local dname = file.dirname(fname)          if not instance.configuration[dname] then              resolvers.load_data(dname,'configuration',lname and file.basename(lname)) @@ -4815,13 +5043,17 @@ local function collapse_cnf_data() -- potential optimization: pass start index (      end  end -function resolvers.load_cnf() -    local function loadoldconfigdata() -        for _, fname in ipairs(instance.cnffiles) do -            load_cnf_file(fname) -        end +local function loadoldconfigdata() +    for _, fname in ipairs(instance.cnffiles) do +        load_cnf_file(fname)      end +end + +function resolvers.load_cnf()      -- instance.cnffiles contain complete names now ! +    -- we still use a funny mix of cnf and new but soon +    -- we will switch to lua exclusively as we only use +    -- the file to collect the tree roots      if #instance.cnffiles == 0 then          if trace_verbose then              logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)") @@ -4829,12 +5061,12 @@ function resolvers.load_cnf()      else          instance.rootpath = instance.cnffiles[1]          for k,fname in ipairs(instance.cnffiles) do -            instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/')) +            instance.cnffiles[k] = collapse_path(gsub(fname,"\\",'/'))          end          for i=1,3 do              instance.rootpath = file.dirname(instance.rootpath)          end -        instance.rootpath = file.collapse_path(instance.rootpath) +        instance.rootpath = collapse_path(instance.rootpath)          if instance.diskcache and not instance.renewcache then              resolvers.loadoldconfig(instance.cnffiles)              if instance.loaderror then @@ -4858,12 +5090,12 @@ function resolvers.load_lua()      else          instance.rootpath = instance.luafiles[1]          for k,fname in ipairs(instance.luafiles) do -            instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/')) +            instance.luafiles[k] = collapse_path(gsub(fname,"\\",'/'))          end          for i=1,3 do              instance.rootpath = file.dirname(instance.rootpath)          end -        instance.rootpath = file.collapse_path(instance.rootpath) +        instance.rootpath = collapse_path(instance.rootpath)          resolvers.loadnewconfig()          collapse_cnf_data()      end @@ -4925,7 +5157,7 @@ function resolvers.locatelists()          if trace_verbose then              logs.report("fileio","locating list of %s",path)          end -        resolvers.locatedatabase(file.collapse_path(path)) +        resolvers.locatedatabase(collapse_path(path))      end  end @@ -5184,6 +5416,7 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl              date    = os.date("%Y-%m-%d"),              time    = os.date("%H:%M:%S"),              content = files, +            uuid    = os.uuid(),          }          local ok = io.savedata(luaname,resolvers.serialize(data))          if ok then @@ -5206,6 +5439,12 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl      end  end +local data_state = { } + +function resolvers.data_state() +    return data_state or { } +end +  function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload      filename = ((not filename or (filename == "")) and dataname) or filename      filename = (makename and makename(dataname,filename)) or file.join(pathname,filename) @@ -5213,6 +5452,7 @@ function resolvers.load_data(pathname,dataname,filename,makename) -- untested wi      if blob then          local data = blob()          if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then +            data_state[#data_state+1] = data.uuid              if trace_verbose then                  logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename)              end @@ -5467,7 +5707,7 @@ function resolvers.clean_path_list(str)      local t = resolvers.expanded_path_list(str)      if t then          for i=1,#t do -            t[i] = file.collapse_path(resolvers.clean_path(t[i])) +            t[i] = collapse_path(resolvers.clean_path(t[i]))          end      end      return t @@ -5664,8 +5904,8 @@ end  local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc)      local result = collected or { }      local stamp  = nil -    filename = file.collapse_path(filename)  -- elsewhere -    filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere +    filename = collapse_path(filename)  -- elsewhere +    filename = collapse_path(gsub(filename,"\\","/")) -- elsewhere      -- speed up / beware: format problem      if instance.remember then          stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -5896,7 +6136,7 @@ local function collect_instance_files(filename,collected) -- todo : plugin (scan          end      end      for k=1,#result do -        result[k] = file.collapse_path(result[k]) +        result[k] = collapse_path(result[k])      end      if instance.remember then          instance.found[stamp] = result @@ -6048,9 +6288,9 @@ function resolvers.load(option)      statistics.starttiming(instance)      resolvers.resetconfig()      resolvers.identify_cnf() -    resolvers.load_lua() +    resolvers.load_lua() -- will become the new method      resolvers.expand_variables() -    resolvers.load_cnf() +    resolvers.load_cnf() -- will be skipped when we have a lua file      resolvers.expand_variables()      if option ~= "nofiles" then          resolvers.load_hash() @@ -6397,6 +6637,7 @@ function caches.savedata(filepath,filename,data,raw)      if raw then          reduce, simplify = false, false      end +    data.cache_uuid = os.uuid()      if caches.direct then          file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex      else diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua index 130ad493c..0d3f08025 100644 --- a/scripts/context/stubs/mswin/mtxrun.lua +++ b/scripts/context/stubs/mswin/mtxrun.lua @@ -789,6 +789,7 @@ local function do_serialize(root,name,depth,level,indexed)              handle(format("%s{",depth))          end      end +    -- we could check for k (index) being number (cardinal)      if root and next(root) then          local first, last = nil, 0 -- #root cannot be trusted here          if compact then @@ -811,7 +812,7 @@ local function do_serialize(root,name,depth,level,indexed)                      if hexify then                          handle(format("%s 0x%04X,",depth,v))                      else -                        handle(format("%s %.99g,",depth,v)) +                        handle(format("%s %s,",depth,v)) -- %.99g                      end                  elseif t == "string" then                      if reduce and tonumber(v) then @@ -851,25 +852,25 @@ local function do_serialize(root,name,depth,level,indexed)              --~ if hexify then              --~     handle(format("%s %s=0x%04X,",depth,key(k),v))              --~ else -            --~     handle(format("%s %s=%.99g,",depth,key(k),v)) +            --~     handle(format("%s %s=%s,",depth,key(k),v)) -- %.99g              --~ end                  if type(k) == "number" then -- or find(k,"^%d+$") then                      if hexify then                          handle(format("%s [0x%04X]=0x%04X,",depth,k,v))                      else -                        handle(format("%s [%s]=%.99g,",depth,k,v)) +                        handle(format("%s [%s]=%s,",depth,k,v)) -- %.99g                      end                  elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then                      if hexify then                          handle(format("%s %s=0x%04X,",depth,k,v))                      else -                        handle(format("%s %s=%.99g,",depth,k,v)) +                        handle(format("%s %s=%s,",depth,k,v)) -- %.99g                      end                  else                      if hexify then                          handle(format("%s [%q]=0x%04X,",depth,k,v))                      else -                        handle(format("%s [%q]=%.99g,",depth,k,v)) +                        handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g                      end                  end              elseif t == "string" then @@ -1868,8 +1869,12 @@ function file.dirname(name,default)      return match(name,"^(.+)[/\\].-$") or (default or "")  end +--~ function file.basename(name) +--~     return match(name,"^.+[/\\](.-)$") or name +--~ end +  function file.basename(name) -    return match(name,"^.+[/\\](.-)$") or name +    return match(name,"^.*[/\\](.-)$") or name  end  function file.nameonly(name) @@ -4872,7 +4877,7 @@ local noparent = 1 - (lparent+rparent)  local nested   = lpeg.P{lparent * (noparent + lpeg.V(1))^0 * rparent}  local value    = lpeg.P(lparent * lpeg.C((noparent + nested)^0) * rparent) -- lpeg.P{"("*C(((1-S("()"))+V(1))^0)*")"} -local lp_child   = Cc("expr.child(e,'") * R("az","AZ","--","__")^1 * Cc("')") +local lp_child   = Cc("expr.child(ll,'") * R("az","AZ","--","__")^1 * Cc("')")  local lp_string  = Cc("'") * R("az","AZ","--","__")^1 * Cc("'")  local lp_content = (P("'") * (1-P("'"))^0 * P("'") + P('"') * (1-P('"'))^0 * P('"')) @@ -4882,9 +4887,9 @@ local lp_special = (C(P("name")+P("text")+P("tag")+P("count")+P("child"))) * val      if expressions[t] then          s = s and s ~= "" and cleaner:match(s)          if s and s ~= "" then -            return "expr." .. t .. "(e," .. s ..")" +            return "expr." .. t .. "(ll," .. s ..")"          else -            return "expr." .. t .. "(e)" +            return "expr." .. t .. "(ll)"          end      else          return "expr.error(" .. t .. ")" @@ -5434,38 +5439,42 @@ expressions.name = function(e,n) -- ns + tg  end  expressions.tag = function(e,n) -- only tg -    local found = false -    n = tonumber(n) or 0 -    if n == 0 then -        found = (type(e) == "table") and e -- seems to fail -    elseif n < 0 then -        local d, k = e.__p__.dt, e.ni -        for i=k-1,1,-1 do -            local di = d[i] -            if type(di) == "table" then -                if n == -1 then -                    found = di -                    break -                else -                    n = n + 1 +    if not e then +        return "" +    else +        local found = false +        n = tonumber(n) or 0 +        if n == 0 then +            found = (type(e) == "table") and e -- seems to fail +        elseif n < 0 then +            local d, k = e.__p__.dt, e.ni +            for i=k-1,1,-1 do +                local di = d[i] +                if type(di) == "table" then +                    if n == -1 then +                        found = di +                        break +                    else +                        n = n + 1 +                    end                  end              end -        end -    else -        local d, k = e.__p__.dt, e.ni -        for i=k+1,#d,1 do -            local di = d[i] -            if type(di) == "table" then -                if n == 1 then -                    found = di -                    break -                else -                    n = n - 1 +        else +            local d, k = e.__p__.dt, e.ni +            for i=k+1,#d,1 do +                local di = d[i] +                if type(di) == "table" then +                    if n == 1 then +                        found = di +                        break +                    else +                        n = n - 1 +                    end                  end              end          end +        return (found and found.tg) or ""      end -    return (found and found.tg) or ""  end  --[[ldx-- @@ -5992,7 +6001,7 @@ local function include(xmldata,pattern,attribute,recursive,loaddata)  --~                 local settings = xmldata.settings  --~                 settings.parent_root = xmldata -- to be tested  --~                 local xi = xmlconvert(data,settings) -                local xi = xml.inheritedconvert(element,xmldata) +                local xi = xml.inheritedconvert(data,xmldata)                  if not xi then                      epdt[ek.ni] = "" -- xml.empty(d,k)                  else @@ -7046,7 +7055,6 @@ end  local name, banner = 'report', 'context'  local function report(category,fmt,...) ---~ print(fmt,...)      if fmt then          write_nl(format("%s | %s: %s",name,category,format(fmt,...)))      elseif category then @@ -7187,6 +7195,8 @@ local format, gsub, find, lower, upper, match, gmatch = string.format, string.gs  local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys  local next, type = next, type +local collapse_path = file.collapse_path +  local trace_locating, trace_detail, trace_verbose  = false, false, false  trackers.register("resolvers.verbose",  function(v) trace_verbose  = v end) @@ -7575,7 +7585,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat      end      if ok then          local function validate(s) -            s = file.collapse_path(s) +            s = collapse_path(s)              return s ~= "" and not find(s,dummy_path_expr) and s          end          for k=1,#pathlist do @@ -7584,7 +7594,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat      else          for k=1,#pathlist do              for p in gmatch(pathlist[k],"([^,]+)") do -                p = file.collapse_path(p) +                p = collapse_path(p)                  if p ~= "" then newlist[#newlist+1] = p end              end          end @@ -7649,9 +7659,9 @@ local function identify_own()      local ownpath = resolvers.getownpath() or lfs.currentdir()      local ie = instance.environment      if ownpath then -        if resolvers.env('SELFAUTOLOC')    == "" then os.env['SELFAUTOLOC']    = file.collapse_path(ownpath) end -        if resolvers.env('SELFAUTODIR')    == "" then os.env['SELFAUTODIR']    = file.collapse_path(ownpath .. "/..") end -        if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end +        if resolvers.env('SELFAUTOLOC')    == "" then os.env['SELFAUTOLOC']    = collapse_path(ownpath) end +        if resolvers.env('SELFAUTODIR')    == "" then os.env['SELFAUTODIR']    = collapse_path(ownpath .. "/..") end +        if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = collapse_path(ownpath .. "/../..") end      else          logs.report("fileio","error: unable to locate ownpath")          os.exit() @@ -7680,7 +7690,7 @@ function resolvers.identify_cnf()          local function locate(filename,list)              for i=1,#t do                  local ti = t[i] -                local texmfcnf = file.collapse_path(file.join(ti,filename)) +                local texmfcnf = collapse_path(file.join(ti,filename))                  if lfs.isfile(texmfcnf) then                      list[#list+1] = texmfcnf                  end @@ -7692,11 +7702,11 @@ function resolvers.identify_cnf()  end  local function load_cnf_file(fname) +    -- why don't we just read the file from the cache +    -- we need to switch to the lua file      fname = resolvers.clean_path(fname)      local lname = file.replacesuffix(fname,'lua') -    local f = io.open(lname) -    if f then -- this will go -        f:close() +    if lfs.isfile(lname) then          local dname = file.dirname(fname)          if not instance.configuration[dname] then              resolvers.load_data(dname,'configuration',lname and file.basename(lname)) @@ -7761,13 +7771,17 @@ local function collapse_cnf_data() -- potential optimization: pass start index (      end  end -function resolvers.load_cnf() -    local function loadoldconfigdata() -        for _, fname in ipairs(instance.cnffiles) do -            load_cnf_file(fname) -        end +local function loadoldconfigdata() +    for _, fname in ipairs(instance.cnffiles) do +        load_cnf_file(fname)      end +end + +function resolvers.load_cnf()      -- instance.cnffiles contain complete names now ! +    -- we still use a funny mix of cnf and new but soon +    -- we will switch to lua exclusively as we only use +    -- the file to collect the tree roots      if #instance.cnffiles == 0 then          if trace_verbose then              logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)") @@ -7775,12 +7789,12 @@ function resolvers.load_cnf()      else          instance.rootpath = instance.cnffiles[1]          for k,fname in ipairs(instance.cnffiles) do -            instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/')) +            instance.cnffiles[k] = collapse_path(gsub(fname,"\\",'/'))          end          for i=1,3 do              instance.rootpath = file.dirname(instance.rootpath)          end -        instance.rootpath = file.collapse_path(instance.rootpath) +        instance.rootpath = collapse_path(instance.rootpath)          if instance.diskcache and not instance.renewcache then              resolvers.loadoldconfig(instance.cnffiles)              if instance.loaderror then @@ -7804,12 +7818,12 @@ function resolvers.load_lua()      else          instance.rootpath = instance.luafiles[1]          for k,fname in ipairs(instance.luafiles) do -            instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/')) +            instance.luafiles[k] = collapse_path(gsub(fname,"\\",'/'))          end          for i=1,3 do              instance.rootpath = file.dirname(instance.rootpath)          end -        instance.rootpath = file.collapse_path(instance.rootpath) +        instance.rootpath = collapse_path(instance.rootpath)          resolvers.loadnewconfig()          collapse_cnf_data()      end @@ -7871,7 +7885,7 @@ function resolvers.locatelists()          if trace_verbose then              logs.report("fileio","locating list of %s",path)          end -        resolvers.locatedatabase(file.collapse_path(path)) +        resolvers.locatedatabase(collapse_path(path))      end  end @@ -8130,6 +8144,7 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl              date    = os.date("%Y-%m-%d"),              time    = os.date("%H:%M:%S"),              content = files, +            uuid    = os.uuid(),          }          local ok = io.savedata(luaname,resolvers.serialize(data))          if ok then @@ -8152,6 +8167,12 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl      end  end +local data_state = { } + +function resolvers.data_state() +    return data_state or { } +end +  function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload      filename = ((not filename or (filename == "")) and dataname) or filename      filename = (makename and makename(dataname,filename)) or file.join(pathname,filename) @@ -8159,6 +8180,7 @@ function resolvers.load_data(pathname,dataname,filename,makename) -- untested wi      if blob then          local data = blob()          if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then +            data_state[#data_state+1] = data.uuid              if trace_verbose then                  logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename)              end @@ -8413,7 +8435,7 @@ function resolvers.clean_path_list(str)      local t = resolvers.expanded_path_list(str)      if t then          for i=1,#t do -            t[i] = file.collapse_path(resolvers.clean_path(t[i])) +            t[i] = collapse_path(resolvers.clean_path(t[i]))          end      end      return t @@ -8610,8 +8632,8 @@ end  local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc)      local result = collected or { }      local stamp  = nil -    filename = file.collapse_path(filename)  -- elsewhere -    filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere +    filename = collapse_path(filename)  -- elsewhere +    filename = collapse_path(gsub(filename,"\\","/")) -- elsewhere      -- speed up / beware: format problem      if instance.remember then          stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -8842,7 +8864,7 @@ local function collect_instance_files(filename,collected) -- todo : plugin (scan          end      end      for k=1,#result do -        result[k] = file.collapse_path(result[k]) +        result[k] = collapse_path(result[k])      end      if instance.remember then          instance.found[stamp] = result @@ -8994,9 +9016,9 @@ function resolvers.load(option)      statistics.starttiming(instance)      resolvers.resetconfig()      resolvers.identify_cnf() -    resolvers.load_lua() +    resolvers.load_lua() -- will become the new method      resolvers.expand_variables() -    resolvers.load_cnf() +    resolvers.load_cnf() -- will be skipped when we have a lua file      resolvers.expand_variables()      if option ~= "nofiles" then          resolvers.load_hash() @@ -9343,6 +9365,7 @@ function caches.savedata(filepath,filename,data,raw)      if raw then          reduce, simplify = false, false      end +    data.cache_uuid = os.uuid()      if caches.direct then          file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex      else diff --git a/scripts/context/stubs/unix/luatools b/scripts/context/stubs/unix/luatools index 2bc943210..abd80b8b4 100755 --- a/scripts/context/stubs/unix/luatools +++ b/scripts/context/stubs/unix/luatools @@ -308,7 +308,7 @@ if not modules then modules = { } end modules ['l-lpeg'] = {      license   = "see context related readme files"  } -local P, S, Ct, C, Cs, Cc = lpeg.P, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc +local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc  --~ l-lpeg.lua : @@ -415,6 +415,41 @@ end  --~     return p  --~ end +--~ from roberto's site: +--~ +--~ -- decode a two-byte UTF-8 sequence +--~ local function f2 (s) +--~   local c1, c2 = string.byte(s, 1, 2) +--~   return c1 * 64 + c2 - 12416 +--~ end +--~ +--~ -- decode a three-byte UTF-8 sequence +--~ local function f3 (s) +--~   local c1, c2, c3 = string.byte(s, 1, 3) +--~   return (c1 * 64 + c2) * 64 + c3 - 925824 +--~ end +--~ +--~ -- decode a four-byte UTF-8 sequence +--~ local function f4 (s) +--~   local c1, c2, c3, c4 = string.byte(s, 1, 4) +--~   return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168 +--~ end +--~ +--~ local cont = lpeg.R("\128\191")   -- continuation byte +--~ +--~ local utf8 = lpeg.R("\0\127") / string.byte +--~            + lpeg.R("\194\223") * cont / f2 +--~            + lpeg.R("\224\239") * cont * cont / f3 +--~            + lpeg.R("\240\244") * cont * cont * cont / f4 +--~ +--~ local decode_pattern = lpeg.Ct(utf8^0) * -1 + + +local cont = R("\128\191")   -- continuation byte + +lpeg.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont + +  end -- of closure @@ -431,9 +466,9 @@ if not modules then modules = { } end modules ['l-table'] = {  table.join = table.concat  local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove -local format, find, gsub, lower, dump = string.format, string.find, string.gsub, string.lower, string.dump +local format, find, gsub, lower, dump, match = string.format, string.find, string.gsub, string.lower, string.dump, string.match  local getmetatable, setmetatable = getmetatable, setmetatable -local type, next, tostring, ipairs = type, next, tostring, ipairs +local type, next, tostring, tonumber, ipairs, pairs = type, next, tostring, tonumber, ipairs, pairs  function table.strip(tab)      local lst = { } @@ -721,6 +756,8 @@ end  --  -- local propername = lpeg.P(lpeg.R("AZ","az","__") * lpeg.R("09","AZ","az", "__")^0 * lpeg.P(-1) ) +-- problem: there no good number_to_string converter with the best resolution +  local function do_serialize(root,name,depth,level,indexed)      if level > 0 then          depth = depth .. " " @@ -743,6 +780,7 @@ local function do_serialize(root,name,depth,level,indexed)              handle(format("%s{",depth))          end      end +    -- we could check for k (index) being number (cardinal)      if root and next(root) then          local first, last = nil, 0 -- #root cannot be trusted here          if compact then @@ -765,10 +803,10 @@ local function do_serialize(root,name,depth,level,indexed)                      if hexify then                          handle(format("%s 0x%04X,",depth,v))                      else -                        handle(format("%s %s,",depth,v)) +                        handle(format("%s %s,",depth,v)) -- %.99g                      end                  elseif t == "string" then -                    if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then +                    if reduce and tonumber(v) then                          handle(format("%s %s,",depth,v))                      else                          handle(format("%s %q,",depth,v)) @@ -805,29 +843,29 @@ local function do_serialize(root,name,depth,level,indexed)              --~ if hexify then              --~     handle(format("%s %s=0x%04X,",depth,key(k),v))              --~ else -            --~     handle(format("%s %s=%s,",depth,key(k),v)) +            --~     handle(format("%s %s=%s,",depth,key(k),v)) -- %.99g              --~ end                  if type(k) == "number" then -- or find(k,"^%d+$") then                      if hexify then                          handle(format("%s [0x%04X]=0x%04X,",depth,k,v))                      else -                        handle(format("%s [%s]=%s,",depth,k,v)) +                        handle(format("%s [%s]=%s,",depth,k,v)) -- %.99g                      end                  elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then                      if hexify then                          handle(format("%s %s=0x%04X,",depth,k,v))                      else -                        handle(format("%s %s=%s,",depth,k,v)) +                        handle(format("%s %s=%s,",depth,k,v)) -- %.99g                      end                  else                      if hexify then                          handle(format("%s [%q]=0x%04X,",depth,k,v))                      else -                        handle(format("%s [%q]=%s,",depth,k,v)) +                        handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g                      end                  end              elseif t == "string" then -                if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then +                if reduce and tonumber(v) then                  --~ handle(format("%s %s=%s,",depth,key(k),v))                      if type(k) == "number" then -- or find(k,"^%d+$") then                          if hexify then @@ -1036,7 +1074,7 @@ function table.tofile(filename,root,name,reduce,noquotes,hexify)      end  end -local function flatten(t,f,complete) +local function flatten(t,f,complete) -- is this used? meybe a variant with next, ...      for i=1,#t do          local v = t[i]          if type(v) == "table" then @@ -1065,6 +1103,24 @@ end  table.flatten_one_level = table.unnest +-- a better one: + +local function flattened(t,f) +    if not f then +        f = { } +    end +    for k, v in next, t do +        if type(v) == "table" then +            flattened(v,f) +        else +            f[k] = v +        end +    end +    return f +end + +table.flattened = flattened +  -- the next three may disappear  function table.remove_value(t,value) -- todo: n @@ -1200,7 +1256,7 @@ function table.clone(t,p) -- t is optional or nil or table      elseif not t then          t = { }      end -    setmetatable(t, { __index = function(_,key) return p[key] end }) +    setmetatable(t, { __index = function(_,key) return p[key] end }) -- why not __index = p ?      return t  end @@ -1615,7 +1671,8 @@ if not modules then modules = { } end modules ['l-os'] = {      license   = "see context related readme files"  } -local find = string.find +local find, format = string.find, string.format +local random, ceil = math.random, math.ceil  function os.resultof(command)      return io.popen(command,"r"):read("*all") @@ -1712,6 +1769,8 @@ function os.currentplatform(name,default)              elseif name == "macosx" then                  if find(architecture,"i386") then                      platform = "osx-intel" +                elseif find(architecture,"x86_64") then +                    platform = "osx-64"                  else                      platform = "osx-ppc"                  end @@ -1738,6 +1797,29 @@ function os.currentplatform(name,default)      return platform  end +-- beware, we set the randomseed +-- + +-- from wikipedia: Version 4 UUIDs use a scheme relying only on random numbers. This algorithm sets the +-- version number as well as two reserved bits. All other bits are set using a random or pseudorandom +-- data source. Version 4 UUIDs have the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx with hexadecimal +-- digits x and hexadecimal digits 8, 9, A, or B for y. e.g. f47ac10b-58cc-4372-a567-0e02b2c3d479. +-- +-- as we don't call this function too often there is not so much risk on repetition + + +local t = { 8, 9, "a", "b" } + +function os.uuid() +    return format("%04x%04x-4%03x-%s%03x-%04x-%04x%04x%04x", +        random(0xFFFF),random(0xFFFF), +        random(0x0FFF), +        t[ceil(random(4))] or 8,random(0x0FFF), +        random(0xFFFF), +        random(0xFFFF),random(0xFFFF),random(0xFFFF) +    ) +end +  end -- of closure @@ -1778,8 +1860,12 @@ function file.dirname(name,default)      return match(name,"^(.+)[/\\].-$") or (default or "")  end +--~ function file.basename(name) +--~     return match(name,"^.+[/\\](.-)$") or name +--~ end +  function file.basename(name) -    return match(name,"^.+[/\\](.-)$") or name +    return match(name,"^.*[/\\](.-)$") or name  end  function file.nameonly(name) @@ -1857,6 +1943,7 @@ function file.collapse_path(str)      return str  end +--~ print(file.collapse_path("/a"))  --~ print(file.collapse_path("a/./b/.."))  --~ print(file.collapse_path("a/aa/../b/bb"))  --~ print(file.collapse_path("a/../..")) @@ -3028,9 +3115,9 @@ function aux.make_settings_to_hash_pattern(set,how)      end  end -function aux.settings_to_hash(str) +function aux.settings_to_hash(str,existing)      if str and str ~= "" then -        hash = { } +        hash = existing or { }          if moretolerant then              pattern_b_s:match(str)          else @@ -3042,9 +3129,9 @@ function aux.settings_to_hash(str)      end  end -function aux.settings_to_hash_tolerant(str) +function aux.settings_to_hash_tolerant(str,existing)      if str and str ~= "" then -        hash = { } +        hash = existing or { }          pattern_b_s:match(str)          return hash      else @@ -3052,9 +3139,9 @@ function aux.settings_to_hash_tolerant(str)      end  end -function aux.settings_to_hash_strict(str) +function aux.settings_to_hash_strict(str,existing)      if str and str ~= "" then -        hash = { } +        hash = existing or { }          pattern_c_s:match(str)          return next(hash) and hash      else @@ -3142,7 +3229,7 @@ function aux.getparameters(self,class,parentclass,settings)          sc = table.clone(self[parent])          self[class] = sc      end -    aux.add_settings_to_array(sc, settings) +    aux.settings_to_hash(settings,sc)  end  -- temporary here @@ -3230,12 +3317,15 @@ if not modules then modules = { } end modules ['trac-tra'] = {  -- bound to a variable, like node.new, node.copy etc (contrary to for instance  -- node.has_attribute which is bound to a has_attribute local variable in mkiv) +local getinfo = debug.getinfo +local type, next = type, next +local concat = table.concat +local format, find, lower, gmatch, gsub = string.format, string.find, string.lower, string.gmatch, string.gsub +  debugger = debugger or { }  local counters = { }  local names = { } -local getinfo = debug.getinfo -local format, find, lower, gmatch, gsub = string.format, string.find, string.lower, string.gmatch, string.gsub  -- one @@ -3363,11 +3453,11 @@ end  --~ print("")  --~ debugger.showstats(print,3) -trackers = trackers or { } +setters      = setters      or { } +setters.data = setters.data or { } -local data, done = { }, { } - -local function set(what,value) +local function set(t,what,value) +    local data, done = t.data, t.done      if type(what) == "string" then          what = aux.settings_to_array(what) -- inefficient but ok      end @@ -3386,28 +3476,30 @@ local function set(what,value)      end  end -local function reset() -    for d, f in next, data do +local function reset(t) +    for d, f in next, t.data do          for i=1,#f do              f[i](false)          end      end  end -local function enable(what) -    set(what,true) +local function enable(t,what) +    set(t,what,true)  end -local function disable(what) +local function disable(t,what) +    local data = t.data      if not what or what == "" then -        done = { } -        reset() +        t.done = { } +        reset(t)      else -        set(what,false) +        set(t,what,false)      end  end -function trackers.register(what,...) +function setters.register(t,what,...) +    local data = t.data      what = lower(what)      local w = data[what]      if not w then @@ -3419,32 +3511,32 @@ function trackers.register(what,...)          if typ == "function" then              w[#w+1] = fnc          elseif typ == "string" then -            w[#w+1] = function(value) set(fnc,value,nesting) end +            w[#w+1] = function(value) set(t,fnc,value,nesting) end          end      end  end -function trackers.enable(what) -    local e = trackers.enable -    trackers.enable, done = enable, { } -    enable(string.simpleesc(what)) -    trackers.enable, done = e, { } +function setters.enable(t,what) +    local e = t.enable +    t.enable, t.done = enable, { } +    enable(t,string.simpleesc(what)) +    t.enable, t.done = e, { }  end -function trackers.disable(what) -    local e = trackers.disable -    trackers.disable, done = disable, { } -    disable(string.simpleesc(what)) -    trackers.disable, done = e, { } +function setters.disable(t,what) +    local e = t.disable +    t.disable, t.done = disable, { } +    disable(t,string.simpleesc(what)) +    t.disable, t.done = e, { }  end -function trackers.reset() -    done = { } -    reset() +function setters.reset(t) +    t.done = { } +    reset(t)  end -function trackers.list() -- pattern -    local list = table.sortedkeys(data) +function setters.list(t) -- pattern +    local list = table.sortedkeys(t.data)      local user, system = { }, { }      for l=1,#list do          local what = list[l] @@ -3457,6 +3549,139 @@ function trackers.list() -- pattern      return user, system  end +function setters.show(t) +    commands.writestatus("","") +    for k,v in ipairs(setters.list(t)) do +        commands.writestatus(t.name,v) +    end +    commands.writestatus("","") +end + +-- we could have used a bit of oo and the trackers:enable syntax but +-- there is already a lot of code around using the singluar tracker + +function setters.new(name) +    local t +    t = { +        data     = { }, +        name     = name, +        enable   = function(...) setters.enable  (t,...) end, +        disable  = function(...) setters.disable (t,...) end, +        register = function(...) setters.register(t,...) end, +        list     = function(...) setters.list    (t,...) end, +        show     = function(...) setters.show    (t,...) end, +    } +    setters.data[name] = t +    return t +end + +trackers   = setters.new("trackers") +directives = setters.new("directives") + +-- nice trick: we overload two of the directives related functions with variants that +-- do tracing (itself using a tracker) .. proof of concept + +local trace_directives = false local trace_directives = false  trackers.register("system.directives", function(v) trace_directives = v end) + +local e = directives.enable +local d = directives.disable + +function directives.enable(...) +    commands.writestatus("directives","enabling: %s",concat({...}," ")) +    e(...) +end + +function directives.disable(...) +    commands.writestatus("directives","disabling: %s",concat({...}," ")) +    d(...) +end + +--~ -- old code: +-- +--~ trackers = trackers or { } +--~ local data, done = { }, { } +--~ local function set(what,value) +--~     if type(what) == "string" then +--~         what = aux.settings_to_array(what) -- inefficient but ok +--~     end +--~     for i=1,#what do +--~         local w = what[i] +--~         for d, f in next, data do +--~             if done[d] then +--~                 -- prevent recursion due to wildcards +--~             elseif find(d,w) then +--~                 done[d] = true +--~                 for i=1,#f do +--~                     f[i](value) +--~                 end +--~             end +--~         end +--~     end +--~ end +--~ local function reset() +--~     for d, f in next, data do +--~         for i=1,#f do +--~             f[i](false) +--~         end +--~     end +--~ end +--~ local function enable(what) +--~     set(what,true) +--~ end +--~ local function disable(what) +--~     if not what or what == "" then +--~         done = { } +--~         reset() +--~     else +--~         set(what,false) +--~     end +--~ end +--~ function trackers.register(what,...) +--~     what = lower(what) +--~     local w = data[what] +--~     if not w then +--~         w = { } +--~         data[what] = w +--~     end +--~     for _, fnc in next, { ... } do +--~         local typ = type(fnc) +--~         if typ == "function" then +--~             w[#w+1] = fnc +--~         elseif typ == "string" then +--~             w[#w+1] = function(value) set(fnc,value,nesting) end +--~         end +--~     end +--~ end +--~ function trackers.enable(what) +--~     local e = trackers.enable +--~     trackers.enable, done = enable, { } +--~     enable(string.simpleesc(what)) +--~     trackers.enable, done = e, { } +--~ end +--~ function trackers.disable(what) +--~     local e = trackers.disable +--~     trackers.disable, done = disable, { } +--~     disable(string.simpleesc(what)) +--~     trackers.disable, done = e, { } +--~ end +--~ function trackers.reset() +--~     done = { } +--~     reset() +--~ end +--~ function trackers.list() -- pattern +--~     local list = table.sortedkeys(data) +--~     local user, system = { }, { } +--~     for l=1,#list do +--~         local what = list[l] +--~         if find(what,"^%*") then +--~             system[#system+1] = what +--~         else +--~             user[#user+1] = what +--~         end +--~     end +--~     return user, system +--~ end +  end -- of closure @@ -3908,6 +4133,7 @@ function statistics.timed(action,report)  end +  end -- of closure  do -- create closure to overcome 200 locals limit @@ -4241,6 +4467,8 @@ local format, gsub, find, lower, upper, match, gmatch = string.format, string.gs  local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys  local next, type = next, type +local collapse_path = file.collapse_path +  local trace_locating, trace_detail, trace_verbose  = false, false, false  trackers.register("resolvers.verbose",  function(v) trace_verbose  = v end) @@ -4629,7 +4857,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat      end      if ok then          local function validate(s) -            s = file.collapse_path(s) +            s = collapse_path(s)              return s ~= "" and not find(s,dummy_path_expr) and s          end          for k=1,#pathlist do @@ -4638,7 +4866,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat      else          for k=1,#pathlist do              for p in gmatch(pathlist[k],"([^,]+)") do -                p = file.collapse_path(p) +                p = collapse_path(p)                  if p ~= "" then newlist[#newlist+1] = p end              end          end @@ -4703,9 +4931,9 @@ local function identify_own()      local ownpath = resolvers.getownpath() or lfs.currentdir()      local ie = instance.environment      if ownpath then -        if resolvers.env('SELFAUTOLOC')    == "" then os.env['SELFAUTOLOC']    = file.collapse_path(ownpath) end -        if resolvers.env('SELFAUTODIR')    == "" then os.env['SELFAUTODIR']    = file.collapse_path(ownpath .. "/..") end -        if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end +        if resolvers.env('SELFAUTOLOC')    == "" then os.env['SELFAUTOLOC']    = collapse_path(ownpath) end +        if resolvers.env('SELFAUTODIR')    == "" then os.env['SELFAUTODIR']    = collapse_path(ownpath .. "/..") end +        if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = collapse_path(ownpath .. "/../..") end      else          logs.report("fileio","error: unable to locate ownpath")          os.exit() @@ -4734,7 +4962,7 @@ function resolvers.identify_cnf()          local function locate(filename,list)              for i=1,#t do                  local ti = t[i] -                local texmfcnf = file.collapse_path(file.join(ti,filename)) +                local texmfcnf = collapse_path(file.join(ti,filename))                  if lfs.isfile(texmfcnf) then                      list[#list+1] = texmfcnf                  end @@ -4746,11 +4974,11 @@ function resolvers.identify_cnf()  end  local function load_cnf_file(fname) +    -- why don't we just read the file from the cache +    -- we need to switch to the lua file      fname = resolvers.clean_path(fname)      local lname = file.replacesuffix(fname,'lua') -    local f = io.open(lname) -    if f then -- this will go -        f:close() +    if lfs.isfile(lname) then          local dname = file.dirname(fname)          if not instance.configuration[dname] then              resolvers.load_data(dname,'configuration',lname and file.basename(lname)) @@ -4815,13 +5043,17 @@ local function collapse_cnf_data() -- potential optimization: pass start index (      end  end -function resolvers.load_cnf() -    local function loadoldconfigdata() -        for _, fname in ipairs(instance.cnffiles) do -            load_cnf_file(fname) -        end +local function loadoldconfigdata() +    for _, fname in ipairs(instance.cnffiles) do +        load_cnf_file(fname)      end +end + +function resolvers.load_cnf()      -- instance.cnffiles contain complete names now ! +    -- we still use a funny mix of cnf and new but soon +    -- we will switch to lua exclusively as we only use +    -- the file to collect the tree roots      if #instance.cnffiles == 0 then          if trace_verbose then              logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)") @@ -4829,12 +5061,12 @@ function resolvers.load_cnf()      else          instance.rootpath = instance.cnffiles[1]          for k,fname in ipairs(instance.cnffiles) do -            instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/')) +            instance.cnffiles[k] = collapse_path(gsub(fname,"\\",'/'))          end          for i=1,3 do              instance.rootpath = file.dirname(instance.rootpath)          end -        instance.rootpath = file.collapse_path(instance.rootpath) +        instance.rootpath = collapse_path(instance.rootpath)          if instance.diskcache and not instance.renewcache then              resolvers.loadoldconfig(instance.cnffiles)              if instance.loaderror then @@ -4858,12 +5090,12 @@ function resolvers.load_lua()      else          instance.rootpath = instance.luafiles[1]          for k,fname in ipairs(instance.luafiles) do -            instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/')) +            instance.luafiles[k] = collapse_path(gsub(fname,"\\",'/'))          end          for i=1,3 do              instance.rootpath = file.dirname(instance.rootpath)          end -        instance.rootpath = file.collapse_path(instance.rootpath) +        instance.rootpath = collapse_path(instance.rootpath)          resolvers.loadnewconfig()          collapse_cnf_data()      end @@ -4925,7 +5157,7 @@ function resolvers.locatelists()          if trace_verbose then              logs.report("fileio","locating list of %s",path)          end -        resolvers.locatedatabase(file.collapse_path(path)) +        resolvers.locatedatabase(collapse_path(path))      end  end @@ -5184,6 +5416,7 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl              date    = os.date("%Y-%m-%d"),              time    = os.date("%H:%M:%S"),              content = files, +            uuid    = os.uuid(),          }          local ok = io.savedata(luaname,resolvers.serialize(data))          if ok then @@ -5206,6 +5439,12 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl      end  end +local data_state = { } + +function resolvers.data_state() +    return data_state or { } +end +  function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload      filename = ((not filename or (filename == "")) and dataname) or filename      filename = (makename and makename(dataname,filename)) or file.join(pathname,filename) @@ -5213,6 +5452,7 @@ function resolvers.load_data(pathname,dataname,filename,makename) -- untested wi      if blob then          local data = blob()          if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then +            data_state[#data_state+1] = data.uuid              if trace_verbose then                  logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename)              end @@ -5467,7 +5707,7 @@ function resolvers.clean_path_list(str)      local t = resolvers.expanded_path_list(str)      if t then          for i=1,#t do -            t[i] = file.collapse_path(resolvers.clean_path(t[i])) +            t[i] = collapse_path(resolvers.clean_path(t[i]))          end      end      return t @@ -5664,8 +5904,8 @@ end  local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc)      local result = collected or { }      local stamp  = nil -    filename = file.collapse_path(filename)  -- elsewhere -    filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere +    filename = collapse_path(filename)  -- elsewhere +    filename = collapse_path(gsub(filename,"\\","/")) -- elsewhere      -- speed up / beware: format problem      if instance.remember then          stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -5896,7 +6136,7 @@ local function collect_instance_files(filename,collected) -- todo : plugin (scan          end      end      for k=1,#result do -        result[k] = file.collapse_path(result[k]) +        result[k] = collapse_path(result[k])      end      if instance.remember then          instance.found[stamp] = result @@ -6048,9 +6288,9 @@ function resolvers.load(option)      statistics.starttiming(instance)      resolvers.resetconfig()      resolvers.identify_cnf() -    resolvers.load_lua() +    resolvers.load_lua() -- will become the new method      resolvers.expand_variables() -    resolvers.load_cnf() +    resolvers.load_cnf() -- will be skipped when we have a lua file      resolvers.expand_variables()      if option ~= "nofiles" then          resolvers.load_hash() @@ -6397,6 +6637,7 @@ function caches.savedata(filepath,filename,data,raw)      if raw then          reduce, simplify = false, false      end +    data.cache_uuid = os.uuid()      if caches.direct then          file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex      else diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun index 130ad493c..0d3f08025 100755 --- a/scripts/context/stubs/unix/mtxrun +++ b/scripts/context/stubs/unix/mtxrun @@ -789,6 +789,7 @@ local function do_serialize(root,name,depth,level,indexed)              handle(format("%s{",depth))          end      end +    -- we could check for k (index) being number (cardinal)      if root and next(root) then          local first, last = nil, 0 -- #root cannot be trusted here          if compact then @@ -811,7 +812,7 @@ local function do_serialize(root,name,depth,level,indexed)                      if hexify then                          handle(format("%s 0x%04X,",depth,v))                      else -                        handle(format("%s %.99g,",depth,v)) +                        handle(format("%s %s,",depth,v)) -- %.99g                      end                  elseif t == "string" then                      if reduce and tonumber(v) then @@ -851,25 +852,25 @@ local function do_serialize(root,name,depth,level,indexed)              --~ if hexify then              --~     handle(format("%s %s=0x%04X,",depth,key(k),v))              --~ else -            --~     handle(format("%s %s=%.99g,",depth,key(k),v)) +            --~     handle(format("%s %s=%s,",depth,key(k),v)) -- %.99g              --~ end                  if type(k) == "number" then -- or find(k,"^%d+$") then                      if hexify then                          handle(format("%s [0x%04X]=0x%04X,",depth,k,v))                      else -                        handle(format("%s [%s]=%.99g,",depth,k,v)) +                        handle(format("%s [%s]=%s,",depth,k,v)) -- %.99g                      end                  elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then                      if hexify then                          handle(format("%s %s=0x%04X,",depth,k,v))                      else -                        handle(format("%s %s=%.99g,",depth,k,v)) +                        handle(format("%s %s=%s,",depth,k,v)) -- %.99g                      end                  else                      if hexify then                          handle(format("%s [%q]=0x%04X,",depth,k,v))                      else -                        handle(format("%s [%q]=%.99g,",depth,k,v)) +                        handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g                      end                  end              elseif t == "string" then @@ -1868,8 +1869,12 @@ function file.dirname(name,default)      return match(name,"^(.+)[/\\].-$") or (default or "")  end +--~ function file.basename(name) +--~     return match(name,"^.+[/\\](.-)$") or name +--~ end +  function file.basename(name) -    return match(name,"^.+[/\\](.-)$") or name +    return match(name,"^.*[/\\](.-)$") or name  end  function file.nameonly(name) @@ -4872,7 +4877,7 @@ local noparent = 1 - (lparent+rparent)  local nested   = lpeg.P{lparent * (noparent + lpeg.V(1))^0 * rparent}  local value    = lpeg.P(lparent * lpeg.C((noparent + nested)^0) * rparent) -- lpeg.P{"("*C(((1-S("()"))+V(1))^0)*")"} -local lp_child   = Cc("expr.child(e,'") * R("az","AZ","--","__")^1 * Cc("')") +local lp_child   = Cc("expr.child(ll,'") * R("az","AZ","--","__")^1 * Cc("')")  local lp_string  = Cc("'") * R("az","AZ","--","__")^1 * Cc("'")  local lp_content = (P("'") * (1-P("'"))^0 * P("'") + P('"') * (1-P('"'))^0 * P('"')) @@ -4882,9 +4887,9 @@ local lp_special = (C(P("name")+P("text")+P("tag")+P("count")+P("child"))) * val      if expressions[t] then          s = s and s ~= "" and cleaner:match(s)          if s and s ~= "" then -            return "expr." .. t .. "(e," .. s ..")" +            return "expr." .. t .. "(ll," .. s ..")"          else -            return "expr." .. t .. "(e)" +            return "expr." .. t .. "(ll)"          end      else          return "expr.error(" .. t .. ")" @@ -5434,38 +5439,42 @@ expressions.name = function(e,n) -- ns + tg  end  expressions.tag = function(e,n) -- only tg -    local found = false -    n = tonumber(n) or 0 -    if n == 0 then -        found = (type(e) == "table") and e -- seems to fail -    elseif n < 0 then -        local d, k = e.__p__.dt, e.ni -        for i=k-1,1,-1 do -            local di = d[i] -            if type(di) == "table" then -                if n == -1 then -                    found = di -                    break -                else -                    n = n + 1 +    if not e then +        return "" +    else +        local found = false +        n = tonumber(n) or 0 +        if n == 0 then +            found = (type(e) == "table") and e -- seems to fail +        elseif n < 0 then +            local d, k = e.__p__.dt, e.ni +            for i=k-1,1,-1 do +                local di = d[i] +                if type(di) == "table" then +                    if n == -1 then +                        found = di +                        break +                    else +                        n = n + 1 +                    end                  end              end -        end -    else -        local d, k = e.__p__.dt, e.ni -        for i=k+1,#d,1 do -            local di = d[i] -            if type(di) == "table" then -                if n == 1 then -                    found = di -                    break -                else -                    n = n - 1 +        else +            local d, k = e.__p__.dt, e.ni +            for i=k+1,#d,1 do +                local di = d[i] +                if type(di) == "table" then +                    if n == 1 then +                        found = di +                        break +                    else +                        n = n - 1 +                    end                  end              end          end +        return (found and found.tg) or ""      end -    return (found and found.tg) or ""  end  --[[ldx-- @@ -5992,7 +6001,7 @@ local function include(xmldata,pattern,attribute,recursive,loaddata)  --~                 local settings = xmldata.settings  --~                 settings.parent_root = xmldata -- to be tested  --~                 local xi = xmlconvert(data,settings) -                local xi = xml.inheritedconvert(element,xmldata) +                local xi = xml.inheritedconvert(data,xmldata)                  if not xi then                      epdt[ek.ni] = "" -- xml.empty(d,k)                  else @@ -7046,7 +7055,6 @@ end  local name, banner = 'report', 'context'  local function report(category,fmt,...) ---~ print(fmt,...)      if fmt then          write_nl(format("%s | %s: %s",name,category,format(fmt,...)))      elseif category then @@ -7187,6 +7195,8 @@ local format, gsub, find, lower, upper, match, gmatch = string.format, string.gs  local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys  local next, type = next, type +local collapse_path = file.collapse_path +  local trace_locating, trace_detail, trace_verbose  = false, false, false  trackers.register("resolvers.verbose",  function(v) trace_verbose  = v end) @@ -7575,7 +7585,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat      end      if ok then          local function validate(s) -            s = file.collapse_path(s) +            s = collapse_path(s)              return s ~= "" and not find(s,dummy_path_expr) and s          end          for k=1,#pathlist do @@ -7584,7 +7594,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat      else          for k=1,#pathlist do              for p in gmatch(pathlist[k],"([^,]+)") do -                p = file.collapse_path(p) +                p = collapse_path(p)                  if p ~= "" then newlist[#newlist+1] = p end              end          end @@ -7649,9 +7659,9 @@ local function identify_own()      local ownpath = resolvers.getownpath() or lfs.currentdir()      local ie = instance.environment      if ownpath then -        if resolvers.env('SELFAUTOLOC')    == "" then os.env['SELFAUTOLOC']    = file.collapse_path(ownpath) end -        if resolvers.env('SELFAUTODIR')    == "" then os.env['SELFAUTODIR']    = file.collapse_path(ownpath .. "/..") end -        if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end +        if resolvers.env('SELFAUTOLOC')    == "" then os.env['SELFAUTOLOC']    = collapse_path(ownpath) end +        if resolvers.env('SELFAUTODIR')    == "" then os.env['SELFAUTODIR']    = collapse_path(ownpath .. "/..") end +        if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = collapse_path(ownpath .. "/../..") end      else          logs.report("fileio","error: unable to locate ownpath")          os.exit() @@ -7680,7 +7690,7 @@ function resolvers.identify_cnf()          local function locate(filename,list)              for i=1,#t do                  local ti = t[i] -                local texmfcnf = file.collapse_path(file.join(ti,filename)) +                local texmfcnf = collapse_path(file.join(ti,filename))                  if lfs.isfile(texmfcnf) then                      list[#list+1] = texmfcnf                  end @@ -7692,11 +7702,11 @@ function resolvers.identify_cnf()  end  local function load_cnf_file(fname) +    -- why don't we just read the file from the cache +    -- we need to switch to the lua file      fname = resolvers.clean_path(fname)      local lname = file.replacesuffix(fname,'lua') -    local f = io.open(lname) -    if f then -- this will go -        f:close() +    if lfs.isfile(lname) then          local dname = file.dirname(fname)          if not instance.configuration[dname] then              resolvers.load_data(dname,'configuration',lname and file.basename(lname)) @@ -7761,13 +7771,17 @@ local function collapse_cnf_data() -- potential optimization: pass start index (      end  end -function resolvers.load_cnf() -    local function loadoldconfigdata() -        for _, fname in ipairs(instance.cnffiles) do -            load_cnf_file(fname) -        end +local function loadoldconfigdata() +    for _, fname in ipairs(instance.cnffiles) do +        load_cnf_file(fname)      end +end + +function resolvers.load_cnf()      -- instance.cnffiles contain complete names now ! +    -- we still use a funny mix of cnf and new but soon +    -- we will switch to lua exclusively as we only use +    -- the file to collect the tree roots      if #instance.cnffiles == 0 then          if trace_verbose then              logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)") @@ -7775,12 +7789,12 @@ function resolvers.load_cnf()      else          instance.rootpath = instance.cnffiles[1]          for k,fname in ipairs(instance.cnffiles) do -            instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/')) +            instance.cnffiles[k] = collapse_path(gsub(fname,"\\",'/'))          end          for i=1,3 do              instance.rootpath = file.dirname(instance.rootpath)          end -        instance.rootpath = file.collapse_path(instance.rootpath) +        instance.rootpath = collapse_path(instance.rootpath)          if instance.diskcache and not instance.renewcache then              resolvers.loadoldconfig(instance.cnffiles)              if instance.loaderror then @@ -7804,12 +7818,12 @@ function resolvers.load_lua()      else          instance.rootpath = instance.luafiles[1]          for k,fname in ipairs(instance.luafiles) do -            instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/')) +            instance.luafiles[k] = collapse_path(gsub(fname,"\\",'/'))          end          for i=1,3 do              instance.rootpath = file.dirname(instance.rootpath)          end -        instance.rootpath = file.collapse_path(instance.rootpath) +        instance.rootpath = collapse_path(instance.rootpath)          resolvers.loadnewconfig()          collapse_cnf_data()      end @@ -7871,7 +7885,7 @@ function resolvers.locatelists()          if trace_verbose then              logs.report("fileio","locating list of %s",path)          end -        resolvers.locatedatabase(file.collapse_path(path)) +        resolvers.locatedatabase(collapse_path(path))      end  end @@ -8130,6 +8144,7 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl              date    = os.date("%Y-%m-%d"),              time    = os.date("%H:%M:%S"),              content = files, +            uuid    = os.uuid(),          }          local ok = io.savedata(luaname,resolvers.serialize(data))          if ok then @@ -8152,6 +8167,12 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl      end  end +local data_state = { } + +function resolvers.data_state() +    return data_state or { } +end +  function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload      filename = ((not filename or (filename == "")) and dataname) or filename      filename = (makename and makename(dataname,filename)) or file.join(pathname,filename) @@ -8159,6 +8180,7 @@ function resolvers.load_data(pathname,dataname,filename,makename) -- untested wi      if blob then          local data = blob()          if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then +            data_state[#data_state+1] = data.uuid              if trace_verbose then                  logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename)              end @@ -8413,7 +8435,7 @@ function resolvers.clean_path_list(str)      local t = resolvers.expanded_path_list(str)      if t then          for i=1,#t do -            t[i] = file.collapse_path(resolvers.clean_path(t[i])) +            t[i] = collapse_path(resolvers.clean_path(t[i]))          end      end      return t @@ -8610,8 +8632,8 @@ end  local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc)      local result = collected or { }      local stamp  = nil -    filename = file.collapse_path(filename)  -- elsewhere -    filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere +    filename = collapse_path(filename)  -- elsewhere +    filename = collapse_path(gsub(filename,"\\","/")) -- elsewhere      -- speed up / beware: format problem      if instance.remember then          stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -8842,7 +8864,7 @@ local function collect_instance_files(filename,collected) -- todo : plugin (scan          end      end      for k=1,#result do -        result[k] = file.collapse_path(result[k]) +        result[k] = collapse_path(result[k])      end      if instance.remember then          instance.found[stamp] = result @@ -8994,9 +9016,9 @@ function resolvers.load(option)      statistics.starttiming(instance)      resolvers.resetconfig()      resolvers.identify_cnf() -    resolvers.load_lua() +    resolvers.load_lua() -- will become the new method      resolvers.expand_variables() -    resolvers.load_cnf() +    resolvers.load_cnf() -- will be skipped when we have a lua file      resolvers.expand_variables()      if option ~= "nofiles" then          resolvers.load_hash() @@ -9343,6 +9365,7 @@ function caches.savedata(filepath,filename,data,raw)      if raw then          reduce, simplify = false, false      end +    data.cache_uuid = os.uuid()      if caches.direct then          file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex      else diff --git a/tex/context/base/colo-hex.mkii b/tex/context/base/colo-hex.mkii index 7cef6e8a2..db67f1841 100644 --- a/tex/context/base/colo-hex.mkii +++ b/tex/context/base/colo-hex.mkii @@ -11,8 +11,8 @@  %C therefore copyrighted by \PRAGMA. See mreadme.pdf for  %C details. -\ifx\dodododefinecolor\undefined \else -  \endinput +\ifdefined \hexcolorprefix +  \expandafter \endinput  \fi  \writestatus{loading}{ConTeXt Color Macros / Hexadecimal} diff --git a/tex/context/base/colo-ini.mkiv b/tex/context/base/colo-ini.mkiv index 5f3cdf372..cde9f5820 100644 --- a/tex/context/base/colo-ini.mkiv +++ b/tex/context/base/colo-ini.mkiv @@ -143,7 +143,7 @@  \unexpanded\def\color              [#1]{\groupedcommand{\doactivatecolor{#1}}{}}  \unexpanded\def\startcolor         [#1]{\begingroup\doactivatecolor{#1}}  \unexpanded\def\stopcolor              {\endgroup} -\unexpanded\def\graycolor          [#1]{\groupedcommand{\setcolormodel{gray}\getvalue{#1}}{}} +\unexpanded\def\graycolor          [#1]{\groupedcommand{\dosetcolormodel{gray}\getvalue{#1}}{}}  \unexpanded\def\colored            [#1]{\groupedcommand{\definecolor[@colored@][#1]\doactivatecolor{@colored@}}{}}  \unexpanded\def\fastcolored      [#1]#2{\begingroup\dodefinefastcolor[@colored@][#1]\doactivatecolor{@colored@}#2\endgroup}             \def\predefinecolor     [#1]{\flushatshipout{\hbox{\color[#1]{}}}} @@ -693,7 +693,10 @@  \def\setcolormodel#1%    {\showcolormessage\m!colors1{#1}% -   \currentcolormodel\ctxlua{tex.print(colors.setmodel('#1',\ifweightGRAY true\else false\fi))}% +   \dosetcolormodel{#1}} + +\def\dosetcolormodel#1% no message +  {\currentcolormodel\ctxlua{tex.print(colors.setmodel('#1',\ifweightGRAY true\else false\fi))}%     \dosetattribute{colormodel}{\the\currentcolormodel}}  \setcolormodel{all} diff --git a/tex/context/base/colo-x11.tex b/tex/context/base/colo-x11.tex new file mode 100644 index 000000000..45d3aac62 --- /dev/null +++ b/tex/context/base/colo-x11.tex @@ -0,0 +1,677 @@ +%D \module +%D   [       file=colo-x11, +%D        version=2009.11.13, +%D          title=\CONTEXT\ Color Macros, +%D       subtitle=X11, +%D         author=Alan Braslau] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +%D Standard X11 rgb colors (from \type {/usr/share/X11/rgb.txt}): + +\doifnotmode{mkiv} { +    \input colo-hex.mkii +} + +\definecolor [snow]                 [h=fffafa] +\definecolor [ghostwhite]           [h=f8f8ff] +\definecolor [whitesmoke]           [s=0.96] +\definecolor [gainsboro]            [s=0.86] +\definecolor [floralwhite]          [h=fffaf0] +\definecolor [oldlace]              [h=fdf5e6] +\definecolor [linen]                [h=faf0e6] +\definecolor [antiquewhite]         [h=faebd7] +\definecolor [papayawhip]           [h=ffefd5] +\definecolor [blanchedalmond]       [h=ffebcd] +\definecolor [bisque]               [h=ffe4c4] +\definecolor [peachpuff]            [h=ffdab9] +\definecolor [navajowhite]          [h=ffdead] +\definecolor [moccasin]             [h=ffe4b5] +\definecolor [cornsilk]             [h=fff8dc] +\definecolor [ivory]                [h=fffff0] +\definecolor [lemonchiffon]         [h=fffacd] +\definecolor [seashell]             [h=fff5ee] +\definecolor [honeydew]             [h=f0fff0] +\definecolor [mintcream]            [h=f5fffa] +\definecolor [azure]                [h=f0ffff] +\definecolor [aliceblue]            [h=f0f8ff] +\definecolor [lavender]             [h=e6e6fa] +\definecolor [lavenderblush]        [h=fff0f5] +\definecolor [mistyrose]            [h=ffe4e1] +\definecolor [white]                [s=1] +\definecolor [black]                [s=0] +\definecolor [darkslategray]        [h=2f4f4f] +\definecolor [darkslategrey]        [darkslategray] +\definecolor [dimgray]              [s=0.41] +\definecolor [dimgrey]              [dimgray] +\definecolor [slategray]            [h=708090] +\definecolor [slategrey]            [slategray] +\definecolor [lightslategray]       [h=778899] +\definecolor [lightslategrey]       [lightslategray] +\definecolor [gray]                 [s=0.75] +\definecolor [grey]                 [gray] +\definecolor [lightgrey]            [s=0.83] +\definecolor [lightgray]            [lightgrey] +\definecolor [midnightblue]         [h=191970] +\definecolor [navy]                 [h=000080] +\definecolor [navyblue]             [navy] +\definecolor [cornflowerblue]       [h=6495ed] +\definecolor [darkslateblue]        [h=483d8b] +\definecolor [slateblue]            [h=6a5acd] +\definecolor [mediumslateblue]      [h=7b68ee] +\definecolor [lightslateblue]       [h=8470ff] +\definecolor [mediumblue]           [h=0000cd] +\definecolor [royalblue]            [h=4169e1] +\definecolor [blue]                 [h=0000ff] +\definecolor [dodgerblue]           [h=1e90ff] +\definecolor [deepskyblue]          [h=00bfff] +\definecolor [skyblue]              [h=87ceeb] +\definecolor [lightskyblue]         [h=87cefa] +\definecolor [steelblue]            [h=4682b4] +\definecolor [lightsteelblue]       [h=b0c4de] +\definecolor [lightblue]            [h=add8e6] +\definecolor [powderblue]           [h=b0e0e6] +\definecolor [paleturquoise]        [h=afeeee] +\definecolor [darkturquoise]        [h=00ced1] +\definecolor [mediumturquoise]      [h=48d1cc] +\definecolor [turquoise]            [h=40e0d0] +\definecolor [cyan]                 [h=00ffff] +\definecolor [lightcyan]            [h=e0ffff] +\definecolor [cadetblue]            [h=5f9ea0] +\definecolor [mediumaquamarine]     [h=66cdaa] +\definecolor [aquamarine]           [h=7fffd4] +\definecolor [darkgreen]            [h=006400] +\definecolor [darkolivegreen]       [h=556b2f] +\definecolor [darkseagreen]         [h=8fbc8f] +\definecolor [seagreen]             [h=2e8b57] +\definecolor [mediumseagreen]       [h=3cb371] +\definecolor [lightseagreen]        [h=20b2aa] +\definecolor [palegreen]            [h=98fb98] +\definecolor [springgreen]          [h=00ff7f] +\definecolor [lawngreen]            [h=7cfc00] +\definecolor [green]                [h=00ff00] +\definecolor [chartreuse]           [h=7fff00] +\definecolor [mediumspringgreen]    [h=00fa9a] +\definecolor [greenyellow]          [h=adff2f] +\definecolor [limegreen]            [h=32cd32] +\definecolor [yellowgreen]          [h=9acd32] +\definecolor [forestgreen]          [h=228b22] +\definecolor [olivedrab]            [h=6b8e23] +\definecolor [darkkhaki]            [h=bdb76b] +\definecolor [khaki]                [h=f0e68c] +\definecolor [palegoldenrod]        [h=eee8aa] +\definecolor [lightgoldenrodyellow] [h=fafad2] +\definecolor [lightyellow]          [h=ffffe0] +\definecolor [yellow]               [h=ffff00] +\definecolor [gold]                 [h=ffd700] +\definecolor [lightgoldenrod]       [h=eedd82] +\definecolor [goldenrod]            [h=daa520] +\definecolor [darkgoldenrod]        [h=b8860b] +\definecolor [rosybrown]            [h=bc8f8f] +\definecolor [indianred]            [h=cd5c5c] +\definecolor [saddlebrown]          [h=8b4513] +\definecolor [sienna]               [h=a0522d] +\definecolor [peru]                 [h=cd853f] +\definecolor [burlywood]            [h=deb887] +\definecolor [beige]                [h=f5f5dc] +\definecolor [wheat]                [h=f5deb3] +\definecolor [sandybrown]           [h=f4a460] +\definecolor [tan]                  [h=d2b48c] +\definecolor [chocolate]            [h=d2691e] +\definecolor [firebrick]            [h=b22222] +\definecolor [brown]                [h=a52a2a] +\definecolor [darksalmon]           [h=e9967a] +\definecolor [salmon]               [h=fa8072] +\definecolor [lightsalmon]          [h=ffa07a] +\definecolor [orange]               [h=ffa500] +\definecolor [darkorange]           [h=ff8c00] +\definecolor [coral]                [h=ff7f50] +\definecolor [lightcoral]           [h=f08080] +\definecolor [tomato]               [h=ff6347] +\definecolor [orangered]            [h=ff4500] +\definecolor [red]                  [h=ff0000] +\definecolor [hotpink]              [h=ff69b4] +\definecolor [deeppink]             [h=ff1493] +\definecolor [pink]                 [h=ffc0cb] +\definecolor [lightpink]            [h=ffb6c1] +\definecolor [palevioletred]        [h=db7093] +\definecolor [maroon]               [h=b03060] +\definecolor [mediumvioletred]      [h=c71585] +\definecolor [violetred]            [h=d02090] +\definecolor [magenta]              [h=ff00ff] +\definecolor [violet]               [h=ee82ee] +\definecolor [plum]                 [h=dda0dd] +\definecolor [orchid]               [h=da70d6] +\definecolor [mediumorchid]         [h=ba55d3] +\definecolor [darkorchid]           [h=9932cc] +\definecolor [darkviolet]           [h=9400d3] +\definecolor [blueviolet]           [h=8a2be2] +\definecolor [purple]               [h=a020f0] +\definecolor [mediumpurple]         [h=9370db] +\definecolor [thistle]              [h=d8bfd8] +\definecolor [snow1]                [h=fffafa] +\definecolor [snow2]                [h=eee9e9] +\definecolor [snow3]                [h=cdc9c9] +\definecolor [snow4]                [h=8b8989] +\definecolor [seashell1]            [h=fff5ee] +\definecolor [seashell2]            [h=eee5de] +\definecolor [seashell3]            [h=cdc5bf] +\definecolor [seashell4]            [h=8b8682] +\definecolor [antiquewhite1]        [h=ffefdb] +\definecolor [antiquewhite2]        [h=eedfcc] +\definecolor [antiquewhite3]        [h=cdc0b0] +\definecolor [antiquewhite4]        [h=8b8378] +\definecolor [bisque1]              [h=ffe4c4] +\definecolor [bisque2]              [h=eed5b7] +\definecolor [bisque3]              [h=cdb79e] +\definecolor [bisque4]              [h=8b7d6b] +\definecolor [peachpuff1]           [h=ffdab9] +\definecolor [peachpuff2]           [h=eecbad] +\definecolor [peachpuff3]           [h=cdaf95] +\definecolor [peachpuff4]           [h=8b7765] +\definecolor [navajowhite1]         [h=ffdead] +\definecolor [navajowhite2]         [h=eecfa1] +\definecolor [navajowhite3]         [h=cdb38b] +\definecolor [navajowhite4]         [h=8b795e] +\definecolor [lemonchiffon1]        [h=fffacd] +\definecolor [lemonchiffon2]        [h=eee9bf] +\definecolor [lemonchiffon3]        [h=cdc9a5] +\definecolor [lemonchiffon4]        [h=8b8970] +\definecolor [cornsilk1]            [h=fff8dc] +\definecolor [cornsilk2]            [h=eee8cd] +\definecolor [cornsilk3]            [h=cdc8b1] +\definecolor [cornsilk4]            [h=8b8878] +\definecolor [ivory1]               [h=fffff0] +\definecolor [ivory2]               [h=eeeee0] +\definecolor [ivory3]               [h=cdcdc1] +\definecolor [ivory4]               [h=8b8b83] +\definecolor [honeydew1]            [h=f0fff0] +\definecolor [honeydew2]            [h=e0eee0] +\definecolor [honeydew3]            [h=c1cdc1] +\definecolor [honeydew4]            [h=838b83] +\definecolor [lavenderblush1]       [h=fff0f5] +\definecolor [lavenderblush2]       [h=eee0e5] +\definecolor [lavenderblush3]       [h=cdc1c5] +\definecolor [lavenderblush4]       [h=8b8386] +\definecolor [mistyrose1]           [h=ffe4e1] +\definecolor [mistyrose2]           [h=eed5d2] +\definecolor [mistyrose3]           [h=cdb7b5] +\definecolor [mistyrose4]           [h=8b7d7b] +\definecolor [azure1]               [h=f0ffff] +\definecolor [azure2]               [h=e0eeee] +\definecolor [azure3]               [h=c1cdcd] +\definecolor [azure4]               [h=838b8b] +\definecolor [slateblue1]           [h=836fff] +\definecolor [slateblue2]           [h=7a67ee] +\definecolor [slateblue3]           [h=6959cd] +\definecolor [slateblue4]           [h=473c8b] +\definecolor [royalblue1]           [h=4876ff] +\definecolor [royalblue2]           [h=436eee] +\definecolor [royalblue3]           [h=3a5fcd] +\definecolor [royalblue4]           [h=27408b] +\definecolor [blue1]                [h=0000ff] +\definecolor [blue2]                [h=0000ee] +\definecolor [blue3]                [h=0000cd] +\definecolor [blue4]                [h=00008b] +\definecolor [dodgerblue1]          [h=1e90ff] +\definecolor [dodgerblue2]          [h=1c86ee] +\definecolor [dodgerblue3]          [h=1874cd] +\definecolor [dodgerblue4]          [h=104e8b] +\definecolor [steelblue1]           [h=63b8ff] +\definecolor [steelblue2]           [h=5cacee] +\definecolor [steelblue3]           [h=4f94cd] +\definecolor [steelblue4]           [h=36648b] +\definecolor [deepskyblue1]         [h=00bfff] +\definecolor [deepskyblue2]         [h=00b2ee] +\definecolor [deepskyblue3]         [h=009acd] +\definecolor [deepskyblue4]         [h=00688b] +\definecolor [skyblue1]             [h=87ceff] +\definecolor [skyblue2]             [h=7ec0ee] +\definecolor [skyblue3]             [h=6ca6cd] +\definecolor [skyblue4]             [h=4a708b] +\definecolor [lightskyblue1]        [h=b0e2ff] +\definecolor [lightskyblue2]        [h=a4d3ee] +\definecolor [lightskyblue3]        [h=8db6cd] +\definecolor [lightskyblue4]        [h=607b8b] +\definecolor [slategray1]           [h=c6e2ff] +\definecolor [slategray2]           [h=b9d3ee] +\definecolor [slategray3]           [h=9fb6cd] +\definecolor [slategray4]           [h=6c7b8b] +\definecolor [lightsteelblue1]      [h=cae1ff] +\definecolor [lightsteelblue2]      [h=bcd2ee] +\definecolor [lightsteelblue3]      [h=a2b5cd] +\definecolor [lightsteelblue4]      [h=6e7b8b] +\definecolor [lightblue1]           [h=bfefff] +\definecolor [lightblue2]           [h=b2dfee] +\definecolor [lightblue3]           [h=9ac0cd] +\definecolor [lightblue4]           [h=68838b] +\definecolor [lightcyan1]           [h=e0ffff] +\definecolor [lightcyan2]           [h=d1eeee] +\definecolor [lightcyan3]           [h=b4cdcd] +\definecolor [lightcyan4]           [h=7a8b8b] +\definecolor [paleturquoise1]       [h=bbffff] +\definecolor [paleturquoise2]       [h=aeeeee] +\definecolor [paleturquoise3]       [h=96cdcd] +\definecolor [paleturquoise4]       [h=668b8b] +\definecolor [cadetblue1]           [h=98f5ff] +\definecolor [cadetblue2]           [h=8ee5ee] +\definecolor [cadetblue3]           [h=7ac5cd] +\definecolor [cadetblue4]           [h=53868b] +\definecolor [turquoise1]           [h=00f5ff] +\definecolor [turquoise2]           [h=00e5ee] +\definecolor [turquoise3]           [h=00c5cd] +\definecolor [turquoise4]           [h=00868b] +\definecolor [cyan1]                [h=00ffff] +\definecolor [cyan2]                [h=00eeee] +\definecolor [cyan3]                [h=00cdcd] +\definecolor [cyan4]                [h=008b8b] +\definecolor [darkslategray1]       [h=97ffff] +\definecolor [darkslategray2]       [h=8deeee] +\definecolor [darkslategray3]       [h=79cdcd] +\definecolor [darkslategray4]       [h=528b8b] +\definecolor [aquamarine1]          [h=7fffd4] +\definecolor [aquamarine2]          [h=76eec6] +\definecolor [aquamarine3]          [h=66cdaa] +\definecolor [aquamarine4]          [h=458b74] +\definecolor [darkseagreen1]        [h=c1ffc1] +\definecolor [darkseagreen2]        [h=b4eeb4] +\definecolor [darkseagreen3]        [h=9bcd9b] +\definecolor [darkseagreen4]        [h=698b69] +\definecolor [seagreen1]            [h=54ff9f] +\definecolor [seagreen2]            [h=4eee94] +\definecolor [seagreen3]            [h=43cd80] +\definecolor [seagreen4]            [h=2e8b57] +\definecolor [palegreen1]           [h=9aff9a] +\definecolor [palegreen2]           [h=90ee90] +\definecolor [palegreen3]           [h=7ccd7c] +\definecolor [palegreen4]           [h=548b54] +\definecolor [springgreen1]         [h=00ff7f] +\definecolor [springgreen2]         [h=00ee76] +\definecolor [springgreen3]         [h=00cd66] +\definecolor [springgreen4]         [h=008b45] +\definecolor [green1]               [h=00ff00] +\definecolor [green2]               [h=00ee00] +\definecolor [green3]               [h=00cd00] +\definecolor [green4]               [h=008b00] +\definecolor [chartreuse1]          [h=7fff00] +\definecolor [chartreuse2]          [h=76ee00] +\definecolor [chartreuse3]          [h=66cd00] +\definecolor [chartreuse4]          [h=458b00] +\definecolor [olivedrab1]           [h=c0ff3e] +\definecolor [olivedrab2]           [h=b3ee3a] +\definecolor [olivedrab3]           [h=9acd32] +\definecolor [olivedrab4]           [h=698b22] +\definecolor [darkolivegreen1]      [h=caff70] +\definecolor [darkolivegreen2]      [h=bcee68] +\definecolor [darkolivegreen3]      [h=a2cd5a] +\definecolor [darkolivegreen4]      [h=6e8b3d] +\definecolor [khaki1]               [h=fff68f] +\definecolor [khaki2]               [h=eee685] +\definecolor [khaki3]               [h=cdc673] +\definecolor [khaki4]               [h=8b864e] +\definecolor [lightgoldenrod1]      [h=ffec8b] +\definecolor [lightgoldenrod2]      [h=eedc82] +\definecolor [lightgoldenrod3]      [h=cdbe70] +\definecolor [lightgoldenrod4]      [h=8b814c] +\definecolor [lightyellow1]         [h=ffffe0] +\definecolor [lightyellow2]         [h=eeeed1] +\definecolor [lightyellow3]         [h=cdcdb4] +\definecolor [lightyellow4]         [h=8b8b7a] +\definecolor [yellow1]              [h=ffff00] +\definecolor [yellow2]              [h=eeee00] +\definecolor [yellow3]              [h=cdcd00] +\definecolor [yellow4]              [h=8b8b00] +\definecolor [gold1]                [h=ffd700] +\definecolor [gold2]                [h=eec900] +\definecolor [gold3]                [h=cdad00] +\definecolor [gold4]                [h=8b7500] +\definecolor [goldenrod1]           [h=ffc125] +\definecolor [goldenrod2]           [h=eeb422] +\definecolor [goldenrod3]           [h=cd9b1d] +\definecolor [goldenrod4]           [h=8b6914] +\definecolor [darkgoldenrod1]       [h=ffb90f] +\definecolor [darkgoldenrod2]       [h=eead0e] +\definecolor [darkgoldenrod3]       [h=cd950c] +\definecolor [darkgoldenrod4]       [h=8b6508] +\definecolor [rosybrown1]           [h=ffc1c1] +\definecolor [rosybrown2]           [h=eeb4b4] +\definecolor [rosybrown3]           [h=cd9b9b] +\definecolor [rosybrown4]           [h=8b6969] +\definecolor [indianred1]           [h=ff6a6a] +\definecolor [indianred2]           [h=ee6363] +\definecolor [indianred3]           [h=cd5555] +\definecolor [indianred4]           [h=8b3a3a] +\definecolor [sienna1]              [h=ff8247] +\definecolor [sienna2]              [h=ee7942] +\definecolor [sienna3]              [h=cd6839] +\definecolor [sienna4]              [h=8b4726] +\definecolor [burlywood1]           [h=ffd39b] +\definecolor [burlywood2]           [h=eec591] +\definecolor [burlywood3]           [h=cdaa7d] +\definecolor [burlywood4]           [h=8b7355] +\definecolor [wheat1]               [h=ffe7ba] +\definecolor [wheat2]               [h=eed8ae] +\definecolor [wheat3]               [h=cdba96] +\definecolor [wheat4]               [h=8b7e66] +\definecolor [tan1]                 [h=ffa54f] +\definecolor [tan2]                 [h=ee9a49] +\definecolor [tan3]                 [h=cd853f] +\definecolor [tan4]                 [h=8b5a2b] +\definecolor [chocolate1]           [h=ff7f24] +\definecolor [chocolate2]           [h=ee7621] +\definecolor [chocolate3]           [h=cd661d] +\definecolor [chocolate4]           [h=8b4513] +\definecolor [firebrick1]           [h=ff3030] +\definecolor [firebrick2]           [h=ee2c2c] +\definecolor [firebrick3]           [h=cd2626] +\definecolor [firebrick4]           [h=8b1a1a] +\definecolor [brown1]               [h=ff4040] +\definecolor [brown2]               [h=ee3b3b] +\definecolor [brown3]               [h=cd3333] +\definecolor [brown4]               [h=8b2323] +\definecolor [salmon1]              [h=ff8c69] +\definecolor [salmon2]              [h=ee8262] +\definecolor [salmon3]              [h=cd7054] +\definecolor [salmon4]              [h=8b4c39] +\definecolor [lightsalmon1]         [h=ffa07a] +\definecolor [lightsalmon2]         [h=ee9572] +\definecolor [lightsalmon3]         [h=cd8162] +\definecolor [lightsalmon4]         [h=8b5742] +\definecolor [orange1]              [h=ffa500] +\definecolor [orange2]              [h=ee9a00] +\definecolor [orange3]              [h=cd8500] +\definecolor [orange4]              [h=8b5a00] +\definecolor [darkorange1]          [h=ff7f00] +\definecolor [darkorange2]          [h=ee7600] +\definecolor [darkorange3]          [h=cd6600] +\definecolor [darkorange4]          [h=8b4500] +\definecolor [coral1]               [h=ff7256] +\definecolor [coral2]               [h=ee6a50] +\definecolor [coral3]               [h=cd5b45] +\definecolor [coral4]               [h=8b3e2f] +\definecolor [tomato1]              [h=ff6347] +\definecolor [tomato2]              [h=ee5c42] +\definecolor [tomato3]              [h=cd4f39] +\definecolor [tomato4]              [h=8b3626] +\definecolor [orangered1]           [h=ff4500] +\definecolor [orangered2]           [h=ee4000] +\definecolor [orangered3]           [h=cd3700] +\definecolor [orangered4]           [h=8b2500] +\definecolor [red1]                 [h=ff0000] +\definecolor [red2]                 [h=ee0000] +\definecolor [red3]                 [h=cd0000] +\definecolor [red4]                 [h=8b0000] +\definecolor [debianred]            [h=d70751] +\definecolor [deeppink1]            [h=ff1493] +\definecolor [deeppink2]            [h=ee1289] +\definecolor [deeppink3]            [h=cd1076] +\definecolor [deeppink4]            [h=8b0a50] +\definecolor [hotpink1]             [h=ff6eb4] +\definecolor [hotpink2]             [h=ee6aa7] +\definecolor [hotpink3]             [h=cd6090] +\definecolor [hotpink4]             [h=8b3a62] +\definecolor [pink1]                [h=ffb5c5] +\definecolor [pink2]                [h=eea9b8] +\definecolor [pink3]                [h=cd919e] +\definecolor [pink4]                [h=8b636c] +\definecolor [lightpink1]           [h=ffaeb9] +\definecolor [lightpink2]           [h=eea2ad] +\definecolor [lightpink3]           [h=cd8c95] +\definecolor [lightpink4]           [h=8b5f65] +\definecolor [palevioletred1]       [h=ff82ab] +\definecolor [palevioletred2]       [h=ee799f] +\definecolor [palevioletred3]       [h=cd6889] +\definecolor [palevioletred4]       [h=8b475d] +\definecolor [maroon1]              [h=ff34b3] +\definecolor [maroon2]              [h=ee30a7] +\definecolor [maroon3]              [h=cd2990] +\definecolor [maroon4]              [h=8b1c62] +\definecolor [violetred1]           [h=ff3e96] +\definecolor [violetred2]           [h=ee3a8c] +\definecolor [violetred3]           [h=cd3278] +\definecolor [violetred4]           [h=8b2252] +\definecolor [magenta1]             [h=ff00ff] +\definecolor [magenta2]             [h=ee00ee] +\definecolor [magenta3]             [h=cd00cd] +\definecolor [magenta4]             [h=8b008b] +\definecolor [orchid1]              [h=ff83fa] +\definecolor [orchid2]              [h=ee7ae9] +\definecolor [orchid3]              [h=cd69c9] +\definecolor [orchid4]              [h=8b4789] +\definecolor [plum1]                [h=ffbbff] +\definecolor [plum2]                [h=eeaeee] +\definecolor [plum3]                [h=cd96cd] +\definecolor [plum4]                [h=8b668b] +\definecolor [mediumorchid1]        [h=e066ff] +\definecolor [mediumorchid2]        [h=d15fee] +\definecolor [mediumorchid3]        [h=b452cd] +\definecolor [mediumorchid4]        [h=7a378b] +\definecolor [darkorchid1]          [h=bf3eff] +\definecolor [darkorchid2]          [h=b23aee] +\definecolor [darkorchid3]          [h=9a32cd] +\definecolor [darkorchid4]          [h=68228b] +\definecolor [purple1]              [h=9b30ff] +\definecolor [purple2]              [h=912cee] +\definecolor [purple3]              [h=7d26cd] +\definecolor [purple4]              [h=551a8b] +\definecolor [mediumpurple1]        [h=ab82ff] +\definecolor [mediumpurple2]        [h=9f79ee] +\definecolor [mediumpurple3]        [h=8968cd] +\definecolor [mediumpurple4]        [h=5d478b] +\definecolor [thistle1]             [h=ffe1ff] +\definecolor [thistle2]             [h=eed2ee] +\definecolor [thistle3]             [h=cdb5cd] +\definecolor [thistle4]             [h=8b7b8b] +\definecolor [gray0]                [s=0.00] +\definecolor [grey0]                [gray0] +\definecolor [gray1]                [s=0.01] +\definecolor [grey1]                [gray1] +\definecolor [gray2]                [s=0.02] +\definecolor [grey2]                [gray2] +\definecolor [gray3]                [s=0.03] +\definecolor [grey3]                [gray3] +\definecolor [gray4]                [s=0.04] +\definecolor [grey4]                [gray4] +\definecolor [gray5]                [s=0.05] +\definecolor [grey5]                [gray5] +\definecolor [gray6]                [s=0.06] +\definecolor [grey6]                [gray6] +\definecolor [gray7]                [s=0.07] +\definecolor [grey7]                [gray7] +\definecolor [gray8]                [s=0.08] +\definecolor [grey8]                [gray8] +\definecolor [gray9]                [s=0.09] +\definecolor [grey9]                [gray9] +\definecolor [gray10]               [s=0.10] +\definecolor [grey10]               [gray10] +\definecolor [gray11]               [s=0.11] +\definecolor [grey11]               [gray11] +\definecolor [gray12]               [s=0.12] +\definecolor [grey12]               [gray12] +\definecolor [gray13]               [s=0.13] +\definecolor [grey13]               [gray13] +\definecolor [gray14]               [s=0.14] +\definecolor [grey14]               [gray14] +\definecolor [gray15]               [s=0.15] +\definecolor [grey15]               [gray15] +\definecolor [gray16]               [s=0.16] +\definecolor [grey16]               [gray16] +\definecolor [gray17]               [s=0.17] +\definecolor [grey17]               [gray17] +\definecolor [gray18]               [s=0.18] +\definecolor [grey18]               [gray18] +\definecolor [gray19]               [s=0.19] +\definecolor [grey19]               [gray19] +\definecolor [gray20]               [s=0.20] +\definecolor [grey20]               [gray20] +\definecolor [gray21]               [s=0.21] +\definecolor [grey21]               [gray21] +\definecolor [gray22]               [s=0.22] +\definecolor [grey22]               [gray22] +\definecolor [gray23]               [s=0.23] +\definecolor [grey23]               [gray23] +\definecolor [gray24]               [s=0.24] +\definecolor [grey24]               [gray24] +\definecolor [gray25]               [s=0.25] +\definecolor [grey25]               [gray25] +\definecolor [gray26]               [s=0.26] +\definecolor [grey26]               [gray26] +\definecolor [gray27]               [s=0.27] +\definecolor [grey27]               [gray27] +\definecolor [gray28]               [s=0.28] +\definecolor [grey28]               [gray28] +\definecolor [gray29]               [s=0.29] +\definecolor [grey29]               [gray29] +\definecolor [gray30]               [s=0.30] +\definecolor [grey30]               [gray30] +\definecolor [gray31]               [s=0.31] +\definecolor [grey31]               [gray31] +\definecolor [gray32]               [s=0.32] +\definecolor [grey32]               [gray32] +\definecolor [gray33]               [s=0.33] +\definecolor [grey33]               [gray33] +\definecolor [gray34]               [s=0.34] +\definecolor [grey34]               [gray34] +\definecolor [gray35]               [s=0.35] +\definecolor [grey35]               [gray35] +\definecolor [gray36]               [s=0.36] +\definecolor [grey36]               [gray36] +\definecolor [gray37]               [s=0.37] +\definecolor [grey37]               [gray37] +\definecolor [gray38]               [s=0.38] +\definecolor [grey38]               [gray38] +\definecolor [gray39]               [s=0.39] +\definecolor [grey39]               [gray39] +\definecolor [gray40]               [s=0.40] +\definecolor [grey40]               [gray40] +\definecolor [gray41]               [s=0.41] +\definecolor [grey41]               [gray41] +\definecolor [gray42]               [s=0.42] +\definecolor [grey42]               [gray42] +\definecolor [gray43]               [s=0.43] +\definecolor [grey43]               [gray43] +\definecolor [gray44]               [s=0.44] +\definecolor [grey44]               [gray44] +\definecolor [gray45]               [s=0.45] +\definecolor [grey45]               [gray45] +\definecolor [gray46]               [s=0.46] +\definecolor [grey46]               [gray46] +\definecolor [gray47]               [s=0.47] +\definecolor [grey47]               [gray47] +\definecolor [gray48]               [s=0.48] +\definecolor [grey48]               [gray48] +\definecolor [gray49]               [s=0.49] +\definecolor [grey49]               [gray49] +\definecolor [gray50]               [s=0.50] +\definecolor [grey50]               [gray50] +\definecolor [gray51]               [s=0.51] +\definecolor [grey51]               [gray51] +\definecolor [gray52]               [s=0.52] +\definecolor [grey52]               [gray52] +\definecolor [gray53]               [s=0.53] +\definecolor [grey53]               [gray53] +\definecolor [gray54]               [s=0.54] +\definecolor [grey54]               [gray54] +\definecolor [gray55]               [s=0.55] +\definecolor [grey55]               [gray55] +\definecolor [gray56]               [s=0.56] +\definecolor [grey56]               [gray56] +\definecolor [gray57]               [s=0.57] +\definecolor [grey57]               [gray57] +\definecolor [gray58]               [s=0.58] +\definecolor [grey58]               [gray58] +\definecolor [gray59]               [s=0.59] +\definecolor [grey59]               [gray59] +\definecolor [gray60]               [s=0.60] +\definecolor [grey60]               [gray60] +\definecolor [gray61]               [s=0.61] +\definecolor [grey61]               [gray61] +\definecolor [gray62]               [s=0.62] +\definecolor [grey62]               [gray62] +\definecolor [gray63]               [s=0.63] +\definecolor [grey63]               [gray63] +\definecolor [gray64]               [s=0.64] +\definecolor [grey64]               [gray64] +\definecolor [gray65]               [s=0.65] +\definecolor [grey65]               [gray65] +\definecolor [gray66]               [s=0.66] +\definecolor [grey66]               [gray66] +\definecolor [gray67]               [s=0.67] +\definecolor [grey67]               [gray67] +\definecolor [gray68]               [s=0.68] +\definecolor [grey68]               [gray68] +\definecolor [gray69]               [s=0.69] +\definecolor [grey69]               [gray69] +\definecolor [gray70]               [s=0.70] +\definecolor [grey70]               [gray70] +\definecolor [gray71]               [s=0.71] +\definecolor [grey71]               [gray71] +\definecolor [gray72]               [s=0.72] +\definecolor [grey72]               [gray72] +\definecolor [gray73]               [s=0.73] +\definecolor [grey73]               [gray73] +\definecolor [gray74]               [s=0.74] +\definecolor [grey74]               [gray74] +\definecolor [gray75]               [s=0.75] +\definecolor [grey75]               [gray75] +\definecolor [gray76]               [s=0.76] +\definecolor [grey76]               [gray76] +\definecolor [gray77]               [s=0.77] +\definecolor [grey77]               [gray77] +\definecolor [gray78]               [s=0.78] +\definecolor [grey78]               [gray78] +\definecolor [gray79]               [s=0.79] +\definecolor [grey79]               [gray79] +\definecolor [gray80]               [s=0.80] +\definecolor [grey80]               [gray80] +\definecolor [gray81]               [s=0.81] +\definecolor [grey81]               [gray81] +\definecolor [gray82]               [s=0.82] +\definecolor [grey82]               [gray82] +\definecolor [gray83]               [s=0.83] +\definecolor [grey83]               [gray83] +\definecolor [gray84]               [s=0.84] +\definecolor [grey84]               [gray84] +\definecolor [gray85]               [s=0.85] +\definecolor [grey85]               [gray85] +\definecolor [gray86]               [s=0.86] +\definecolor [grey86]               [gray86] +\definecolor [gray87]               [s=0.87] +\definecolor [grey87]               [gray87] +\definecolor [gray88]               [s=0.88] +\definecolor [grey88]               [gray88] +\definecolor [gray89]               [s=0.89] +\definecolor [grey89]               [gray89] +\definecolor [gray90]               [s=0.90] +\definecolor [grey90]               [gray90] +\definecolor [gray91]               [s=0.91] +\definecolor [grey91]               [gray91] +\definecolor [gray92]               [s=0.92] +\definecolor [grey92]               [gray92] +\definecolor [gray93]               [s=0.93] +\definecolor [grey93]               [gray93] +\definecolor [gray94]               [s=0.94] +\definecolor [grey94]               [gray94] +\definecolor [gray95]               [s=0.95] +\definecolor [grey95]               [gray95] +\definecolor [gray96]               [s=0.96] +\definecolor [grey96]               [gray96] +\definecolor [gray97]               [s=0.97] +\definecolor [grey97]               [gray97] +\definecolor [gray98]               [s=0.98] +\definecolor [grey98]               [gray98] +\definecolor [gray99]               [s=0.99] +\definecolor [grey99]               [gray99] +\definecolor [gray100]              [s=1.00] +\definecolor [grey100]              [gray100] +\definecolor [darkgrey]             [s=0.66] +\definecolor [darkgray]             [darkgrey] +\definecolor [darkblue]             [h=00008b] +\definecolor [darkcyan]             [h=008b8b] +\definecolor [darkmagenta]          [h=8b008b] +\definecolor [darkred]              [h=8b0000] +\definecolor [lightgreen]           [h=90ee90] + +\endinput diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv index 35b716ed4..93a1c17c2 100644 --- a/tex/context/base/cont-new.mkiv +++ b/tex/context/base/cont-new.mkiv @@ -25,6 +25,8 @@  %  % \setbreakpoints[compound] +\ctxlua{logs.report=function(s,...) commands.writestatus("!"..s,...) end} +  \unprotect  % % % % % % needs testing but saves runtime diff --git a/tex/context/base/cont-new.tex b/tex/context/base/cont-new.tex index 1eecb06fe..b6b633877 100644 --- a/tex/context/base/cont-new.tex +++ b/tex/context/base/cont-new.tex @@ -11,7 +11,7 @@  %C therefore copyrighted by \PRAGMA. See mreadme.pdf for  %C details. -\newcontextversion{2009.11.13 12:45} +\newcontextversion{2009.11.18 21:51}  %D This file is loaded at runtime, thereby providing an  %D excellent place for hacks, patches, extensions and new diff --git a/tex/context/base/context.tex b/tex/context/base/context.tex index 95b945f26..76233c43d 100644 --- a/tex/context/base/context.tex +++ b/tex/context/base/context.tex @@ -20,7 +20,7 @@  %D your styles an modules.  \edef\contextformat {\jobname} -\edef\contextversion{2009.11.13 12:45} +\edef\contextversion{2009.11.18 21:51}  %D For those who want to use this: diff --git a/tex/context/base/core-def.mkiv b/tex/context/base/core-def.mkiv index d3d24acd7..bc1b6b2bf 100644 --- a/tex/context/base/core-def.mkiv +++ b/tex/context/base/core-def.mkiv @@ -61,6 +61,8 @@  \appendtoks  \the\everybackendshipout              \to \everyshipout  \prependtoks \the\everylastbackendshipout          \to \everylastshipout +\prependtoks \lefttoright                          \to \everybeforeoutput +  % temporary here:  \ifdefined\in    \let\normalmathin   \in    \unexpanded\def\in   {\mathortext\normalmathin   \dospecialin   } \else \let\in   \dospecialin    \fi diff --git a/tex/context/base/data-res.lua b/tex/context/base/data-res.lua index 7181f5a17..9964af421 100644 --- a/tex/context/base/data-res.lua +++ b/tex/context/base/data-res.lua @@ -544,11 +544,11 @@ function resolvers.identify_cnf()  end  local function load_cnf_file(fname) +    -- why don't we just read the file from the cache +    -- we need to switch to the lua file      fname = resolvers.clean_path(fname)      local lname = file.replacesuffix(fname,'lua') -    local f = io.open(lname) -    if f then -- this will go -        f:close() +    if lfs.isfile(lname) then          local dname = file.dirname(fname)          if not instance.configuration[dname] then              resolvers.load_data(dname,'configuration',lname and file.basename(lname)) @@ -613,13 +613,17 @@ local function collapse_cnf_data() -- potential optimization: pass start index (      end  end -function resolvers.load_cnf() -    local function loadoldconfigdata() -        for _, fname in ipairs(instance.cnffiles) do -            load_cnf_file(fname) -        end +local function loadoldconfigdata() +    for _, fname in ipairs(instance.cnffiles) do +        load_cnf_file(fname)      end +end + +function resolvers.load_cnf()      -- instance.cnffiles contain complete names now ! +    -- we still use a funny mix of cnf and new but soon +    -- we will switch to lua exclusively as we only use +    -- the file to collect the tree roots      if #instance.cnffiles == 0 then          if trace_verbose then              logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)") @@ -982,6 +986,7 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl              date    = os.date("%Y-%m-%d"),              time    = os.date("%H:%M:%S"),              content = files, +            uuid    = os.uuid(),          }          local ok = io.savedata(luaname,resolvers.serialize(data))          if ok then @@ -1004,6 +1009,12 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl      end  end +local data_state = { } + +function resolvers.data_state() +    return data_state or { } +end +  function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload      filename = ((not filename or (filename == "")) and dataname) or filename      filename = (makename and makename(dataname,filename)) or file.join(pathname,filename) @@ -1011,6 +1022,7 @@ function resolvers.load_data(pathname,dataname,filename,makename) -- untested wi      if blob then          local data = blob()          if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then +            data_state[#data_state+1] = data.uuid              if trace_verbose then                  logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename)              end @@ -1846,9 +1858,9 @@ function resolvers.load(option)      statistics.starttiming(instance)      resolvers.resetconfig()      resolvers.identify_cnf() -    resolvers.load_lua() +    resolvers.load_lua() -- will become the new method      resolvers.expand_variables() -    resolvers.load_cnf() +    resolvers.load_cnf() -- will be skipped when we have a lua file      resolvers.expand_variables()      if option ~= "nofiles" then          resolvers.load_hash() diff --git a/tex/context/base/data-tmp.lua b/tex/context/base/data-tmp.lua index 802af6e4e..ba338b5a4 100644 --- a/tex/context/base/data-tmp.lua +++ b/tex/context/base/data-tmp.lua @@ -157,6 +157,7 @@ function caches.savedata(filepath,filename,data,raw)      if raw then          reduce, simplify = false, false      end +    data.cache_uuid = os.uuid()      if caches.direct then          file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex      else diff --git a/tex/context/base/font-afm.lua b/tex/context/base/font-afm.lua index 72b36600c..2ba73be26 100644 --- a/tex/context/base/font-afm.lua +++ b/tex/context/base/font-afm.lua @@ -720,7 +720,8 @@ function tfm.read_from_afm(specification)          if filename then              tfmtable.encodingbytes = 2              tfmtable.filename = resolvers.findbinfile(filename,"") or filename -            tfmtable.fullname = afmdata.metadata.fontname or afmdata.metadata.fullname +            tfmtable.fontname = afmdata.metadata.fontname or afmdata.metadata.fullname +            tfmtable.fullname = afmdata.metadata.fullname or afmdata.metadata.fontname              tfmtable.format   = 'type1'              tfmtable.name     = afmdata.luatex.filename or tfmtable.fullname          end diff --git a/tex/context/base/font-ctx.lua b/tex/context/base/font-ctx.lua index c18fbe0ff..3845ae5b9 100644 --- a/tex/context/base/font-ctx.lua +++ b/tex/context/base/font-ctx.lua @@ -405,9 +405,9 @@ local dimenfactors = number.dimenfactors  function fonts.dimenfactor(unit,tfmdata)      if unit == "ex" then -        return tfmdata.parameters.x_height +        return (tfmdata and tfmdata.parameters.x_height) or 655360      elseif unit == "em" then -        return tfmdata.parameters.em_height +        return (tfmdata and tfmdata.parameters.em_height) or 655360      else          return dimenfactors[unit] or unit      end diff --git a/tex/context/base/font-dum.lua b/tex/context/base/font-dum.lua index c585c18b5..d6fee5598 100644 --- a/tex/context/base/font-dum.lua +++ b/tex/context/base/font-dum.lua @@ -39,10 +39,15 @@ function fonts.logger.save()  end  -- names +-- +-- Watch out, the version number is the same as the one used in +-- the mtx-fonts.lua function scripts.fonts.names as we use a +-- simplified font database in the plain solution and by using +-- a different number we're less dependent on context.  fonts.names = fonts.names or { } -fonts.names.version    = 1.014 +fonts.names.version    = 1.001 -- not the same as in context  fonts.names.basename   = "luatex-fonts-names.lua"  fonts.names.new_to_old = { }  fonts.names.old_to_new = { } @@ -57,16 +62,6 @@ function fonts.names.resolve(name,sub)                  local foundname = resolvers.find_file(basename,format) or ""                  if foundname ~= "" then                      data = dofile(foundname) -                    if data then -                        local d = {  } -                        for k, v in pairs(data.mapping) do -                            local t = v[1] -                            if t == "ttf" or t == "otf" or t == "ttc" or t == "dfont" then -                                d[k] = v -                            end -                        end -                        data.mapping = d -                    end                      break                  end              end @@ -77,9 +72,12 @@ function fonts.names.resolve(name,sub)          local condensed = string.gsub(string.lower(name),"[^%a%d]","")          local found = data.mapping and data.mapping[condensed]          if found then -            local filename, is_sub = found[3], found[4] -            if is_sub then is_sub = found[2] end -            return filename, is_sub +            local fontname, filename, subfont = found[1], found[2], found[3] +            if subfont then +                return filename, fontname +            else +                return filename, false +            end          else              return name, false -- fallback to filename          end diff --git a/tex/context/base/font-ini.mkiv b/tex/context/base/font-ini.mkiv index 3ce821a39..e36485319 100644 --- a/tex/context/base/font-ini.mkiv +++ b/tex/context/base/font-ini.mkiv @@ -4010,6 +4010,28 @@  \def\showchardata#1{\ctxlua{fonts.show_char_data("#1")}}  \def\showfontdata  {\ctxlua{fonts.show_font_parameters()}} +%D some low level helpers +%D +%D \starttyping +%D \def\TestLookup#1% +%D   {pattern: #1, found: \dolookupnoffound +%D    \blank +%D    \dolookupfontbyspec{#1} +%D    \dorecurse {\dolookupnoffound} {% +%D      \recurselevel:~\dolookupgetkeyofindex{fontname}{\recurselevel}\quad +%D    }% +%D    \blank} +%D +%D \TestLookup{familyname=helveticaneue} +%D \TestLookup{familyname=helveticaneue,weight=bold} +%D \TestLookup{familyname=helveticaneue,weight=bold,style=italic} +%D \stoptyping + +\def\dolookupfontbyspec     #1{\ctxlua{fonts.names.lookup("#1")}} +\def\dolookupnoffound         {\ctxlua{tex.write(fonts.names.noflookups())}} +\def\dolookupgetkeyofindex#1#2{\ctxlua{tex.write(fonts.names.getlookupkey("#1",#2))}} +\def\dolookupgetkey         #1{\ctxlua{tex.write(fonts.names.getlookupkey("#1"))}} +  \protect \endinput  % \startluacode diff --git a/tex/context/base/font-mis.lua b/tex/context/base/font-mis.lua index dc60cf2a2..40160e49d 100644 --- a/tex/context/base/font-mis.lua +++ b/tex/context/base/font-mis.lua @@ -35,7 +35,7 @@ end  function fonts.get_features(name,t,script,language)      local t = lower(t or (name and file.extname(name)) or "") -    if t == "otf" or t == "ttf" or t == "ttc" then +    if t == "otf" or t == "ttf" or t == "ttc" or t == "dfont" then          local filename = resolvers.find_file(name,t) or ""          if filename ~= "" then              local data = fonts.otf.loadcached(filename) diff --git a/tex/context/base/font-otf.lua b/tex/context/base/font-otf.lua index b5f7cb431..7929dfb02 100644 --- a/tex/context/base/font-otf.lua +++ b/tex/context/base/font-otf.lua @@ -1497,8 +1497,9 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th          tfm.units              = metadata.units_per_em or 1000          -- we need a runtime lookup because of running from cdrom or zip, brrr          tfm.filename           = resolvers.findbinfile(luatex.filename,"") or luatex.filename -        tfm.fullname           = metadata.fontname or metadata.fullname -        tfm.psname             = tfm.fullname +        tfm.fullname           = metadata.fullname +        tfm.fontname           = metadata.fontname +        tfm.psname             = tfm.fontname or tfm.fullname          tfm.encodingbytes      = 2          tfm.cidinfo            = data.cidinfo          tfm.cidinfo.registry   = tfm.cidinfo.registry or "" @@ -1622,7 +1623,8 @@ function tfm.read_from_open_type(specification)          if filename then              tfmtable.encodingbytes = 2              tfmtable.filename = resolvers.findbinfile(filename,"") or filename -            tfmtable.fullname = tfmtable.fullname or otfdata.metadata.fontname or otfdata.metadata.fullname +            tfmtable.fontname = tfmtable.fontname or otfdata.metadata.fontname +            tfmtable.fullname = tfmtable.fullname or otfdata.metadata.fullname or tfmtable.fontname              local order = otfdata and otfdata.metadata.order2              if order == 0 then                  tfmtable.format = 'opentype' @@ -1631,7 +1633,7 @@ function tfm.read_from_open_type(specification)              else                  tfmtable.format = specification.format              end -            tfmtable.name = tfmtable.filename or tfmtable.fullname +            tfmtable.name = tfmtable.filename or tfmtable.fullname or tfmtable.fontname          end          fonts.logger.save(tfmtable,file.extname(specification.filename),specification)      end diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua index 77d67d4b5..fb04b367e 100644 --- a/tex/context/base/font-otn.lua +++ b/tex/context/base/font-otn.lua @@ -117,7 +117,7 @@ results in different tables.</p>  -- remark: the 'not implemented yet' variants will be done when we have fonts that use them  -- remark: we need to check what to do with discretionaries -local concat = table.concat +local concat, insert, remove = table.concat, table.insert, table.remove  local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip  local type, next, tonumber, tostring = type, next, tonumber, tostring @@ -139,6 +139,7 @@ local trace_details      = false  trackers.register("otf.details",      function  local trace_applied      = false  trackers.register("otf.applied",      function(v) trace_applied      = v end)  local trace_steps        = false  trackers.register("otf.steps",        function(v) trace_steps        = v end)  local trace_skips        = false  trackers.register("otf.skips",        function(v) trace_skips        = v end) +local trace_directions   = false  trackers.register("otf.directions",   function(v) trace_directions   = v end)  trackers.register("otf.verbose_chain", function(v) otf.setcontextchain(v and "verbose") end)  trackers.register("otf.normal_chain",  function(v) otf.setcontextchain(v and "normal")  end) @@ -743,7 +744,7 @@ function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) -- to                                          if exit then                                              local dx, dy, bound = set_cursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])                                              if trace_cursive then -                                                logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound) +                                                logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)                                              end                                              done = true                                              break @@ -1395,7 +1396,7 @@ function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache,                                              if exit then                                                  local dx, dy, bound = set_cursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])                                                  if trace_cursive then -                                                    logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound) +                                                    logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)                                                  end                                                  done = true                                                  break @@ -1832,6 +1833,9 @@ local resolved = { } -- we only resolve a font,script,language pair once  -- todo: pass all these 'locals' in a table +-- maybe some day i'll make an alternative that works on 'sub direction runs' which might be +-- more efficient for arabic but it has quite some consequences +  function fonts.methods.node.otf.features(head,font,attr)      if trace_steps then          checkstep(head) @@ -1875,6 +1879,7 @@ function fonts.methods.node.otf.features(head,font,attr)      local ra  = rl      [attr]     if ra == nil then ra  = { } rl      [attr]     = ra  end -- attr can be false      -- sequences always > 1 so no need for optimization      for s=1,#sequences do +    local pardir, txtdir = 0, { }          local success = false          local sequence = sequences[s]          local r = ra[s] -- cache @@ -1974,7 +1979,7 @@ function fonts.methods.node.otf.features(head,font,attr)                  local ns = #subtables                  local thecache = featuredata[typ] or { }                  start = head -- local ? -                rlmode = 0 +                rlmode = 0 -- to be checked ?                  if ns == 1 then                      local lookupname = subtables[1]                      local lookupcache = thecache[lookupname] @@ -2016,24 +2021,57 @@ function fonts.methods.node.otf.features(head,font,attr)                              --         start = start.next                              --     end                              elseif id == whatsit then +--~                             if subtype == 7 then +--~                                 local dir = start.dir +--~                                 if dir == "+TRT" then +--~                                     rlmode = -1 +--~                                 elseif dir == "+TLT" then +--~                                     rlmode = 1 +--~                                 else +--~                                     rlmode = 0 +--~                                 end +--~                             elseif subtype == 6 then +--~                                 local dir = start.dir +--~                                 if dir == "TRT" then +--~                                     rlmode = -1 +--~                                 elseif dir == "TLT" then +--~                                     rlmode = 1 +--~                                 else +--~                                     rlmode = 0 +--~                                 end +--~                             end                                  local subtype = start.subtype                                  if subtype == 7 then                                      local dir = start.dir -                                    if dir == "+TRT" then +                                    if     dir == "+TRT" or dir == "+TLT" then +                                        insert(txtdir,dir) +                                    elseif dir == "-TRT" or dir == "-TLT" then +                                        remove(txtdir) +                                    end +                                    local d = txtdir[#txtdir] +                                    if d == "+TRT" then                                          rlmode = -1 -                                    elseif dir == "+TLT" then +                                    elseif d == "+TLT" then                                          rlmode = 1                                      else -                                        rlmode = 0 +                                        rlmode = pardir +                                    end +                                    if trace_directions then +                                        logs.report("fonts","directions after textdir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode)                                      end                                  elseif subtype == 6 then                                      local dir = start.dir                                      if dir == "TRT" then -                                        rlmode = -1 +                                        pardir = -1                                      elseif dir == "TLT" then -                                        rlmode = 1 +                                        pardir = 1                                      else -                                        rlmode = 0 +                                        pardir = 0 +                                    end +                                    rlmode = pardir +                                --~ txtdir = { } +                                    if trace_directions then +                                        logs.report("fonts","directions after pardir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode)                                      end                                  end                                  start = start.next @@ -2041,7 +2079,6 @@ function fonts.methods.node.otf.features(head,font,attr)                                  start = start.next                              end                          end -                      end                  else                      while start do @@ -2088,25 +2125,59 @@ function fonts.methods.node.otf.features(head,font,attr)                          --     end                          elseif id == whatsit then                              local subtype = start.subtype -                            if subtype == 7 then -                                local dir = start.dir -                                if dir == "+TRT" then -                                    rlmode = -1 -                                elseif dir == "+TLT" then -                                    rlmode = 1 -                                else -                                    rlmode = 0 +--~                             if subtype == 7 then +--~                                 local dir = start.dir +--~                                 if dir == "+TRT" then +--~                                     rlmode = -1 +--~                                 elseif dir == "+TLT" then +--~                                     rlmode = 1 +--~                                 else +--~                                     rlmode = 0 +--~                                 end +--~                             elseif subtype == 6 then +--~                                 local dir = start.dir +--~                                 if dir == "TRT" then +--~                                     rlmode = -1 +--~                                 elseif dir == "TLT" then +--~                                     rlmode = 1 +--~                                 else +--~                                     rlmode = 0 +--~                                 end +--~                             end +                                local subtype = start.subtype +                                if subtype == 7 then +                                    local dir = start.dir +                                    if     dir == "+TRT" or dir == "+TLT" then +                                        insert(txtdir,dir) +                                    elseif dir == "-TRT" or dir == "-TLT" then +                                        remove(txtdir) +                                    end +                                    local d = txtdir[#txtdir] +                                    if d == "+TRT" then +                                        rlmode = -1 +                                    elseif d == "+TLT" then +                                        rlmode = 1 +                                    else +                                        rlmode = pardir +                                    end +                                    if trace_directions then +                                        logs.report("fonts","directions after textdir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode) +                                    end +                                elseif subtype == 6 then +                                    local dir = start.dir +                                    if dir == "TRT" then +                                        pardir = -1 +                                    elseif dir == "TLT" then +                                        pardir = 1 +                                    else +                                        pardir = 0 +                                    end +                                    rlmode = pardir +                                --~ txtdir = { } +                                if trace_directions then +                                    logs.report("fonts","directions after pardir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode)                                  end -                            elseif subtype == 6 then -                                local dir = start.dir -                                if dir == "TRT" then -                                    rlmode = -1 -                                elseif dir == "TLT" then -                                    rlmode = 1 -                                else -                                    rlmode = 0                                  end -                            end                              start = start.next                          else                              start = start.next diff --git a/tex/context/base/font-pat.lua b/tex/context/base/font-pat.lua index f2b86a48a..96b5fe870 100644 --- a/tex/context/base/font-pat.lua +++ b/tex/context/base/font-pat.lua @@ -95,17 +95,18 @@ end  patches["palatino.*arabic"] = patch -local function patch(data,filename) +local function patch_domh(data,filename,threshold)      local m = data.math      if m then          local d = m.DisplayOperatorMinHeight or 0 -        if d < 2800 then +        if d < threshold then              if trace_loading then -                logs.report("load otf","patching DisplayOperatorMinHeight(%s -> 2800)",d) +                logs.report("load otf","patching DisplayOperatorMinHeight(%s -> %s)",d,threshold)              end -            m.DisplayOperatorMinHeight = 2800 +            m.DisplayOperatorMinHeight = threshold          end      end  end -patches["cambria"] = patch +patches["cambria"] = function(data,filename) patch_domh(data,filename,2800) end +patches["asana"]   = function(data,filename) patch_domh(data,filename,1350) end diff --git a/tex/context/base/font-syn.lua b/tex/context/base/font-syn.lua index f184fe2e5..0b74cc73c 100644 --- a/tex/context/base/font-syn.lua +++ b/tex/context/base/font-syn.lua @@ -6,8 +6,11 @@ if not modules then modules = { } end modules ['font-syn'] = {      license   = "see context related readme files"  } -local next = next +-- todo: subs in lookups requests + +local next, tonumber = next, tonumber  local gsub, lower, match, find, lower, upper = string.gsub, string.lower, string.match, string.find, string.lower, string.upper +local find, gmatch = string.find, string.gmatch  local concat, sort, format = table.concat, table.sort, string.format  local trace_names = false  trackers.register("fonts.names", function(v) trace_names = v end) @@ -30,7 +33,7 @@ fonts.names.data       = fonts.names.data    or { }  local names   = fonts.names  local filters = fonts.names.filters -names.version    = 1.014 -- when adapting this, also changed font-dum.lua +names.version    = 1.100  names.basename   = "names"  names.saved      = false  names.loaded     = false @@ -40,6 +43,91 @@ names.autoreload = toboolean(os.env['MTX.FONTS.AUTOLOAD'] or os.env['MTX_FONTS_A  names.cache      = containers.define("fonts","data",names.version,true)  --[[ldx-- +<p>A few helpers.</p> +--ldx]]-- + +local P, C, Cc, Cs, Carg = lpeg.P, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Carg + +local weights = Cs ( -- not extra +    P("demibold") +  + P("semibold") +  + P("mediumbold") +  + P("ultrabold") +  + P("extrabold") +  + P("ultralight") +  + P("bold") +  + P("demi") +  + P("semi") +  + P("light") +  + P("medium") +  + P("heavy") +  + P("ultra") +  + P("black") +  + P("bol") +  + P("regular")  / "normal" +) + +local styles = Cs ( +    P("reverseoblique") / "reverseitalic" +  + P("regular")        / "normal" +  + P("italic") +  + P("oblique")        / "italic" +  + P("slanted") +  + P("roman")          / "normal" +  + P("ital")           / "italic" +  + P("ita")            / "italic" +) + +local widths = Cs( +    P("condensed") +  + P("thin") +  + P("expanded") +  + P("cond")     / "condensed" +  + P("normal") +  + P("book")     / "normal" +) + +local any = P(1) + +local analysed_table + +local analyser = Cs ( +    ( +        weights / function(s) analysed_table[1] = s return "" end +      + styles  / function(s) analysed_table[2] = s return "" end +      + widths  / function(s) analysed_table[3] = s return "" end +      + any +    )^0 +) + +local splitter = lpeg.splitat("-") + +function names.splitspec(askedname) +    local name, weight, style, width = splitter:match(askedname) +    weight = weight and weights:match(weight) or weight +    style  = style  and styles :match(style)  or style +    width  = width  and widths :match(width)  or width +    if trace_names then +        logs.report("fonts","requested name '%s' split in name '%s', weight '%s', style '%s' and width '%s'",askedname,name or '',weight or '',style or '',width or '') +    end +    if not weight or not weight or not width then +        weight, style, width = weight or "normal", style or "normal", width or "normal" +        if trace_names then +            logs.report("fonts","request '%s' normalized to '%s-%s-%s-%s'",askedname,name,weight,style,width) +        end +    end +    return name or askedname, weight, style, width +end + +local function analysespec(somename) +    if somename then +        analysed_table = { } +        local name = analyser:match(somename) +        return name, analysed_table[1], analysed_table[2],analysed_table[3] +    end +end + +--[[ldx--  <p>It would make sense to implement the filters in the related modules,  but to keep the overview, we define them here.</p>  --ldx]]-- @@ -104,16 +192,6 @@ filters.list = {      "otf", "ttf", "ttc", "dfont", "afm",  } -filters.fixes = { -- can be lpeg -    { "bolita$", "bolditalic", }, -    { "ital$", "italic", }, -    { "cond$", "condensed", }, -    { "book$", "", }, -    { "reg$", "regular", }, -    { "ita$", "italic", }, -    { "bol$", "bold", }, -} -  names.xml_configuration_file    = "fonts.conf" -- a bit weird format, bonus feature  names.environment_path_variable = "OSFONTDIR"  -- the official way, in minimals etc @@ -149,7 +227,7 @@ function names.getpaths(trace)                  end              end              if name ~= "" and lfs.isfile(name) then -                if trace then +                if trace_names then                      logs.report("fontnames","loading fontconfig file: %s",name)                  end                  local xmldata = xml.load(name) @@ -162,17 +240,17 @@ function names.getpaths(trace)                          end                      end                      if lfs.isfile(incname) then -                        if trace then +                        if trace_names then                              logs.report("fontnames","merging included fontconfig file: %s",incname)                          end                          return io.loaddata(incname) -                    elseif trace then +                    elseif trace_names then                          logs.report("fontnames","ignoring included fontconfig file: %s",incname)                      end                  end)                  -- end of untested mess                  local fontdirs = xml.collect_texts(xmldata,"dir",true) -                if trace then +                if trace_names then                      logs.report("fontnames","%s dirs found in fontconfig",#fontdirs)                  end                  collect(fontdirs) @@ -185,77 +263,299 @@ function names.getpaths(trace)      return result  end -function names.cleanname(name) +local function cleanname(name)      return (gsub(lower(name),"[^%a%d]",""))  end -function names.identify(verbose) -- lsr is for kpse -    names.data = { -        version = names.version, -        mapping = { }, -    --  sorted = { }, -        fallback_mapping = { }, -    --  fallback_sorted = { }, +names.cleanname = cleanname + +local function check_names(result) +    local names = result.names +    if names then +        for i=1,#names do +            local name = names[i] +            if name.lang == "English (US)" then +                return name.names +            end +        end +    end +end + +local function walk_tree(pathlist,suffix,identify) +    if pathlist then +        for _, path in ipairs(pathlist) do +            path = resolvers.clean_path(path .. "/") +            path = gsub(path,"/+","/") +            local pattern = path .. "**." .. suffix -- ** forces recurse +            logs.report("fontnames", "globbing path %s",pattern) +            local t = dir.glob(pattern) +            for _, completename in pairs(t) do -- ipairs +                identify(completename,file.basename(completename),suffix,completename) +            end +        end +    end +end + +local function check_name(data,result,filename,suffix,subfont) +    -- shortcuts +    local specifications = data.specifications +    local families       = data.families +    -- prepare +    local names = check_names(result) +    -- fetch +    local familyname  = (names and names.preffamilyname) or result.familyname +    local fullname    = (names and names.fullname) or result.fullname +    local fontname    = result.fontname +    local subfamily   = (names and names.subfamily) +    local modifiers   = (names and names.prefmodifiers) +    local weight      = (names and names.weight) or result.weight +    local italicangle = tonumber(result.italicangle) +    local subfont     = subfont or nil +    local rawname     = fullname or fontname or familyname +    -- normalize +    familyname  = familyname and cleanname(familyname) +    fullname    = fullname   and cleanname(fullname) +    fontname    = fontname   and cleanname(fontname) +    subfamily   = subfamily  and cleanname(subfamily) +    modifiers   = modifiers  and cleanname(modifiers) +    weight      = weight     and cleanname(weight) +    italicangle = (italicangle == 0) and nil +    -- analyse +    local a_name, a_weight, a_style, a_width = analysespec(fullname or fontname or familyname) +    -- check +    local width = a_width +    local style = modifiers and gsub(modifiers,"[^%a]","") +    if not style and italicangle then +        style = "italic" +    end +    if not weight or weight == "" then +        weight = a_weight +    end +    if not style or style == ""  then +        style = a_style +    end +    if not familyname then +        familyname = a_name +    end +    fontname   = fontname   or fullname or familyname or basename +    fullname   = fullname   or fontname +    familyname = familyname or fontname +    -- register +    local index = #specifications + 1 +    specifications[index] = { +        filename    = filename, +        format      = lower(suffix), +        subfont     = subfont, +        rawname     = rawname, +        familyname  = familyname, +        fullname    = fullname, +        fontname    = fontname, +        subfamily   = subfamily, +        modifiers   = modifiers, +        weight      = weight, +        style       = style, +        width       = width,      } -    local done, mapping, fallback_mapping, nofread, nofok = { }, names.data.mapping, names.data.fallback_mapping, 0, 0 -    local cleanname = names.cleanname -    local function check(result, filename, suffix, is_sub) -- unlocal this one -        local fontname = result.fullname -        if fontname then -            local n = cleanname(result.fullname) -            if not mapping[n] then -                mapping[n], nofok = { lower(suffix), fontname, filename, is_sub }, nofok + 1 -            end -        end -        if result.fontname then -            fontname = result.fontname or fontname -            local n = cleanname(result.fontname) -            if not mapping[n] then -                mapping[n], nofok = { lower(suffix), fontname, filename, is_sub }, nofok + 1 -            end -        end -        if result.familyname and result.weight and result.italicangle == 0 then -            local madename = result.familyname .. " " .. result.weight -            fontname = madename or fontname -            local n = cleanname(fontname) -            if not mapping[n] and not fallback_mapping[n] then -                fallback_mapping[n], nofok = { lower(suffix), fontname, filename, is_sub }, nofok + 1 -            end -        end -        if result.names then -            for k, v in ipairs(result.names) do -                local lang, names = v.lang, v.names -                if lang == "English (US)" then -                    local family, subfamily, fullnamet = names.family, names.subfamily, names.fullname -                    local preffamilyname, prefmodifiers, weight = names.preffamilyname, names.prefmodifiers, names.weight -                    if preffamilyname then -                        if subfamily then -                            local n = cleanname(preffamilyname .. " " .. subfamily) -                            if not mapping[n] and not fallback_mapping[n] then -                                fallback_mapping[n], nofok = { lower(suffix), fontname, filename, is_sub }, nofok + 1 -                            end -                        end -                        -- okay? -                        local n = cleanname(preffamilyname) -                        if not mapping[n] and not fallback_mapping[n] then -                            fallback_mapping[n], nofok = { lower(suffix), fontname, filename, is_sub }, nofok + 1 +    local family = families[familyname] +    if not family then +        families[familyname] = { index } +    else +        family[#family+1] = index +    end +end + +local function cleanupkeywords() +    local data = names.data +    local specifications = names.data.specifications +    if specifications then +        local weights, styles, widths, variants = { }, { }, { }, { } +        for i=1,#specifications do +            local s = specifications[i] +            -- fix (sofar styles are taken from the name, and widths from the specification) +            local b_variant, b_weight, b_style, b_width = analysespec(s.weight) +            local c_variant, c_weight, c_style, c_width = analysespec(s.style) +            local d_variant, d_weight, d_style, d_width = analysespec(s.width) +            local e_variant, e_weight, e_style, e_width = analysespec(s.fullname or "") +            local weight  = b_weight  or c_weight  or d_weight  or e_weight  or "normal" +            local style   = b_style   or c_style   or d_style   or e_style   or "normal" +            local width   = b_width   or c_width   or d_width   or e_width   or "normal" +            local variant = b_variant or c_variant or d_variant or e_variant or "normal" +            if weight  then weights [weight ] = (weights [weight ] or 0) + 1 end +            if style   then styles  [style  ] = (styles  [style  ] or 0) + 1 end +            if width   then widths  [width  ] = (widths  [width  ] or 0) + 1 end +            if variant then variants[variant] = (variants[variant] or 0) + 1 end +            if weight ~= s.weight then +                s.fontweight = s.weight +            end +            s.weight, s.style, s.width, s.variant = weight, style, width, variant +        end +        local stats = data.statistics +        stats.used_weights, stats.used_styles, stats.used_widths, stats.used_variants = weights, styles, widths, variants +    end +end + +local function collectstatistics() +    local data = names.data +    local specifications = data.specifications +    if specifications then +        local weights, styles, widths = { }, { }, { } +        for i=1,#specifications do +            local s = specifications[i] +            local weight, style, width = s.weight, s.style, s.width +            if weight then weights[weight] = (weights[weight] or 0) + 1 end +            if style  then styles [style ] = (styles [style ] or 0) + 1 end +            if width  then widths [width ] = (widths [width ] or 0) + 1 end +        end +        local stats = data.statistics +        stats.weights, stats.styles, stats.widths, stats.fonts = weights, styles, widths, #specifications +    end +end + +local function collecthashes() +    local data = names.data +    local mappings       = data.mappings +    local fallbacks      = data.fallbacks +    local specifications = data.specifications +    local nofmappings, noffallbacks = 0, 0 +    if specifications then +        for index=1,#specifications do +            local s = specifications[index] +            local format, fullname, fontname, familyname, weight, subfamily = s.format, s.fullname, s.fontname, s.familyname, s.weight, s.subfamily +            local mf, ff = mappings[format], fallbacks[format] +            if fullname and not mf[fullname] then +                mf[fullname], nofmappings = index, nofmappings + 1 +            end +            if fontname and not mf[fontname] then +                mf[fontname], nofmappings = index, nofmappings + 1 +            end +            if familyname and weight then +                local madename = familyname .. weight +                if not mf[madename] and not ff[madename] then +                    ff[madename], noffallbacks = index, noffallbacks + 1 +                end +            end +            if familyname and subfamily then +                local extraname = familyname .. subfamily +                if not mf[extraname] and not ff[extraname] then +                    ff[extraname], noffallbacks = index, noffallbacks + 1 +                end +            end +            if familyname and subfamily then +                if not mf[familyname] and not ff[familyname] then +                    ff[familyname], noffallbacks = index, noffallbacks + 1 +                end +            end +        end +    end +    return nofmappings, noffallbacks +end + +local function checkduplicate(mapping) -- fails on "Romantik" but that's a border case anyway +    local data = names.data +    local mapping = data[mapping] +    local specifications, loaded = data.specifications, { } +    if specifications and mapping then +        for _, m in next, mapping do +            for k, v in next, m do +                local s = specifications[v] +                local hash = format("%s-%s-%s-%s",s.familyname,s.weight or "*",s.style or "*",s.width or "*") +                local h = loaded[hash] +                if h then +                    local ok = true +                    local fn = s.filename +                    for i=1,#h do +                        local hn = s.filename +                        if h[i] == fn then +                            ok = false +                            break                          end                      end +                    if ok then +                        h[#h+1] = fn +                    end +                else +                    loaded[hash] = { s.filename }                  end              end          end      end -    local trace = verbose or trace_names -    local skip_paths = filters.paths -    local skip_names = filters.names +    for k, v in table.sortedpairs(loaded) do +        if #v > 1 then +            logs.report("fontnames", "double lookup: %s => %s",k,concat(v," | ")) +        end +    end +end + +local function checkduplicates() +    checkduplicate("mappings") +    checkduplicate("fallbacks") +end + +local sorter = function(a,b) +    return #a < #b and a < b +end + +local function sorthashes() +    local data, list = names.data, filters.list +    local mappings, fallbacks, sorted_mappings, sorted_fallbacks = data.mappings, data.fallbacks, { }, { } +    data.sorted_mappings, data.sorted_fallbacks = sorted_mappings, sorted_fallbacks +    for i=1,#list do +        local l = list[i] +        sorted_mappings[l], sorted_fallbacks[l] = table.keys(mappings[l]), table.keys(fallbacks[l]) +        sort(sorted_mappings[l],sorter) +        sort(sorted_fallbacks[l],sorter) +    end +    data.sorted_families = table.keys(data.families) +    sort(data.sorted_families,sorter) +end + +local function unpackreferences() +    local data = names.data +    local specifications = data.specifications +    if specifications then +        for k, v in next, data.families do +            for i=1,#v do +                v[i] = specifications[v[i]] +            end +        end +    end +    local mappings = data.mappings +    if mappings then +        for _, m in next, mappings do +            for k, v in next, m do +                m[k] = specifications[v] +            end +        end +    end +    local fallbacks = data.fallbacks +    if fallbacks then +        for _, f in next, fallbacks do +            for k, v in next, f do +                f[k] = specifications[v] +            end +        end +    end +end + +local function analysefiles() +    local data = names.data +    local done, totalnofread, totalnofskipped = { }, 0, 0 +    local skip_paths, skip_names = filters.paths, filters.names      local function identify(completename,name,suffix,storedname) -        if not done[name] and io.exists(completename) then +        local basename = file.basename(completename) +        local basepath = file.dirname(completename) +        if done[name] then +            -- already done (avoid otf afm clash) +        elseif not io.exists(completename) then +            -- weird error +        elseif not file.is_qualified_path(completename) and resolvers.find_file(completename,suffix) == "" then +            -- not locateble by backend anyway +        else              nofread = nofread + 1              if #skip_paths > 0 then -                local path = file.dirname(completename)                  for i=1,#skip_paths do -                    if find(path,skip_paths[i]) then -                        if trace then +                    if find(basepath,skip_paths[i]) then +                        if trace_names then                              logs.report("fontnames","rejecting path of %s font %s",suffix,completename)                              logs.push()                          end @@ -264,11 +564,10 @@ function names.identify(verbose) -- lsr is for kpse                  end              end              if #skip_names > 0 then -                local base = file.basename(completename)                  for i=1,#skip_paths do -                    if find(base,skip_names[i]) then +                    if find(basename,skip_names[i]) then                          done[name] = true -                        if trace then +                        if trace_names then                              logs.report("fontnames","rejecting name of %s font %s",suffix,completename)                              logs.push()                          end @@ -281,15 +580,21 @@ function names.identify(verbose) -- lsr is for kpse                  logs.push()              end              local result, message = filters[lower(suffix)](completename) -            if trace then +            if trace_names then                  logs.pop()              end              if result then                  if not result[1] then -                    check(result,storedname,suffix,false) -- was name +                    local ok = check_name(data,result,storedname,suffix) +                    if not ok then +                        nofskipped = nofskipped + 1 +                    end                  else                      for r=1,#result do -                        check(result[r],storedname,suffix,true) -- was name +                        local ok = check_name(data,result[r],storedname,suffix,r-1) -- subfonts start at zero +                        if not ok then +                            nofskipped = nofskipped + 1 +                        end                      end                  end                  if message and message ~= "" then @@ -301,33 +606,19 @@ function names.identify(verbose) -- lsr is for kpse              done[name] = true          end      end -    local totalread, totalok = 0, 0      local function traverse(what, method)          for n, suffix in ipairs(filters.list) do -            nofread, nofok  = 0, 0              local t = os.gettimeofday() -- use elapser +            nofread, nofskipped = 0, 0              suffix = lower(suffix)              logs.report("fontnames", "identifying %s font files with suffix %s",what,suffix)              method(suffix)              suffix = upper(suffix)              logs.report("fontnames", "identifying %s font files with suffix %s",what,suffix)              method(suffix) -            logs.report("fontnames", "%s %s files identified, %s hash entries added, runtime %0.3f seconds",nofread,what,nofok,os.gettimeofday()-t) -            totalread, totalok = totalread + nofread, totalok + nofok -        end -    end -    local function walk_tree(pathlist,suffix) -        if pathlist then -            for _, path in ipairs(pathlist) do -                path = resolvers.clean_path(path .. "/") -                path = gsub(path,"/+","/") -                local pattern = path .. "**." .. suffix -- ** forces recurse -                logs.report("fontnames", "globbing path %s",pattern) -                local t = dir.glob(pattern) -                for _, completename in pairs(t) do -- ipairs -                    identify(completename,file.basename(completename),suffix,completename) -                end -            end +            totalnofread, totalnofskipped = totalnofread + nofread, totalnofskipped + nofskipped +            local elapsed = os.gettimeofday() - t +            logs.report("fontnames", "%s %s files identified, %s hash entries added, runtime %0.3f seconds",nofread,what,nofread-nofskipped,elapsed)          end      end      traverse("tree", function(suffix) -- TEXTREE only @@ -343,43 +634,42 @@ function names.identify(verbose) -- lsr is for kpse          -- using the vars is to clumsy so we just stick to a full scan instead          traverse("lsr", function(suffix) -- all trees              local pathlist = resolvers.split_path(resolvers.show_path("ls-R") or "") -            walk_tree(pathlist,suffix) +            walk_tree(pathlist,suffix,identify)          end)      else          traverse("system", function(suffix) -- OSFONTDIR cum suis -            walk_tree(names.getpaths(trace),suffix) +            walk_tree(names.getpaths(trace),suffix,identify)          end)      end -    local t = { } -    for _, f in ipairs(filters.fixes) do -        local expression, replacement = f[1], f[2] -        for k,v in next, mapping do -            local fix, pos = gsub(k,expression,replacement) -            if pos > 0 and not mapping[fix] then -                t[fix] = v -            end -        end -    end -    local n = 0 -    for k,v in next, t do -        mapping[k] = v -        n = n + 1 -    end -    local rejected = 0 -    for k, v in next, mapping do -        local kind, filename = v[1], v[3] -        if not file.is_qualified_path(filename) and resolvers.find_file(filename,kind) == "" then -            mapping[k] = nil -            rejected = rejected + 1 -        end -    end -    if n > 0 then -        logs.report("fontnames", "%s files read, %s normal and %s extra entries added, %s rejected, %s valid",totalread,totalok,n,rejected,totalok+n-rejected) +    data.statistics.readfiles, data.statistics.skippedfiles = totalnofread, totalnofskipped +end + +local function resetdata() +    local mappings, fallbacks = { }, { } +    for _, k in next, filters.list do +        mappings[k], fallbacks[k] = { }, { }      end -    names.analyse(mapping) -    names.analyse(fallback_mapping) -    names.checkduplicates(mapping) -    names.checkduplicates(fallback_mapping) +    names.data = { +        version = names.version, +        mappings = mappings, +        fallbacks = fallbacks, +        specifications = { }, +        families = { }, +        statistics = { }, +        data_state = resolvers.data_state(), +    } +end + +function names.identify() +    resetdata() +    analysefiles() +    collectstatistics() +    cleanupkeywords() +    collecthashes() +    checkduplicates() + -- sorthashes() -- will be resorted when saved + + --~     logs.report("fontnames", "%s files read, %s normal and %s extra entries added, %s rejected, %s valid",totalread,totalok,added,rejected,totalok+added-rejected)  end  function names.is_permitted(name) @@ -392,120 +682,6 @@ function names.read_data(name)      return containers.read(names.cache(),name)  end -local sorter = function(a,b) return #a < #b and a < b end - -function names.sorted(t) -    local s = table.keys(t or { }) or { } -    sort(s,sorted) -    return s -end - ---~ local P, C, Cc = lpeg.P, lpeg.C, lpeg.Cc ---~ ---~ local weight   = C(P("demibold") + P("semibold") + P("mediumbold") + P("ultrabold") + P("bold") + P("demi") + P("semi") + P("light") + P("medium") + P("heavy") + P("ultra") + P("black")) ---~ local style    = C(P("regular") + P("italic") + P("oblique") + P("slanted") + P("roman") + P("ital")) ---~ local width    = C(P("condensed") + P("normal") + P("expanded") + P("cond")) ---~ local special  = P("roman") ---~ local reserved = style + weight + width ---~ local any      = (1-reserved) ---~ local name     = C((special + any)^1) ---~ local crap     = any^0 ---~ local dummy    = Cc(false) ---~ local normal   = Cc("normal") ---~ local analyser = name * (weight + normal) * crap * (style + normal) * crap * (width + normal) * crap ---~ ---~ function names.analyse(mapping) ---~     for k, v in next, mapping do ---~         -- fails on "Romantik" but that's a border case anyway ---~         local name, weight, style, width = analyser:match(k) ---~         v[5], v[6], v[7], v[8] = name or k, weight or "normal", style or "normal", width or "normal" ---~     end ---~ end - -local P, C, Cc, Cs, Carg = lpeg.P, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Carg - -local weight = C(P("demibold") + P("semibold") + P("mediumbold") + P("ultrabold") + P("bold") + P("demi") + P("semi") + P("light") + P("medium") + P("heavy") + P("ultra") + P("black")) -local style  = C(P("regular") + P("italic") + P("oblique") + P("slanted") + P("roman") + P("ital")) -local width  = C(P("condensed") + P("normal") + P("expanded") + P("cond")) -local strip  = P("book") + P("roman") -local any    = P(1) - -local t - -local analyser = Cs ( -    ( -        strip  / "" + -        weight / function(s) t[6] = s return "" end + -        style  / function(s) t[7] = s return "" end + -        width  / function(s) t[8] = s return "" end + -        any -    )^0 -) - -local stripper = Cs ( -    ( -        strip  / "" + -        any -    )^0 -) - -function names.analyse(mapping) -- fails on "Romantik" but that's a border case anyway -    for k, v in next, mapping do -        t = v -        t[5] = analyser:match(k) -- somehow Carg fails -        v[5], v[6], v[7], v[8] = t[5] or k, t[6] or "normal", t[7] or "normal", t[8] or "normal" -    end -end - -local splitter = lpeg.splitat("-") - -function names.splitspec(askedname) -    local name, weight, style, width = splitter:match(stripper:match(askedname) or askedname) -    if trace_names then -        logs.report("fonts","requested name '%s' split in name '%s', weight '%s', style '%s' and width '%s'",askedname,name or '',weight or '',style or '',width or '') -    end -    if not weight or not weight or not width then -        weight, style, width = weight or "normal", style or "normal", width or "normal" -        if trace_names then -            logs.report("fonts","request '%s' normalized to '%s-%s-%s-%s'",askedname,name,weight,style,width) -        end -    end -    return name or askedname, weight, style, width -end - -function names.checkduplicates(mapping) -- fails on "Romantik" but that's a border case anyway -    local loaded = { } -    for k, v in next, mapping do -        local hash = format("%s-%s-%s-%s",v[5],v[6],v[7],v[8]) -        local h = loaded[hash] -        if h then -            local ok = true -            local fn = v[3] -            for i=1,#h do -                local hn = mapping[h[i]][3] -                if hn == fn then -                    ok = false -                    break -                end -            end -            if ok then -                h[#h+1] = k -            end -        else -            loaded[hash] = { h } -        end -    end -    for k, v in table.sortedpairs(loaded) do -        if #v > 1 then -            for i=1,#v do -                local vi = v[i] -                v[i] = format("%s = %s",vi,mapping[vi][3]) -            end -            logs.report("fonts", "double lookup: %s => %s",k,concat(v," | ")) -        end -    end -end -  function names.load(reload,verbose)      if not names.loaded then          if reload then @@ -516,51 +692,85 @@ function names.load(reload,verbose)                  logs.report("font table", "unable to access database cache")              end              names.saved = true -        else -            names.data = names.read_data(names.basename) -            if not names.saved then -                if table.is_empty(names.data) or table.is_empty(names.data.mapping) then -                    names.load(true) -                end -                names.saved = true +        end +        local data = names.read_data(names.basename) +        names.data = data +        if not names.saved then +            if not next(data) or not next(data.specifications) then +               names.load(true)              end +            names.saved = true          end -        local data = names.data -    --  names.analyse(data.mapping) -    --  names.analyse(data.fallback_mapping) -        if data then -            data.sorted = names.sorted(data.mapping) -            data.fallback_sorted = names.sorted(data.fallback_mapping) -        else +        if not data then              logs.report("font table", "accessing the data table failed") +        else +            unpackreferences() +            sorthashes()          end          names.loaded = true      end  end -function names.list(pattern,reload) +local function list_them(mapping,sorted,pattern,t,all) +    if mapping[pattern] then +        t[pattern] = mapping[pattern] +    else +        for k=1,#sorted do +            local v = sorted[k] +            if find(v,pattern) then +                t[v] = mapping[v] +                if not all then +                    return +                end +            end +        end +    end +end + +function names.list(pattern,reload,all) -- here?      names.load(reload)      if names.loaded then          local t = { } -        local function list_them(mapping,sorted) -            if mapping[pattern] then -                t[pattern] = mapping[pattern] -            else -                for k,v in ipairs(sorted) do -                    if find(v,pattern) then -                        t[v] = mapping[v] -                    end +        local data = names.data +        if data then +            local list = filters.list +            local mappings, sorted_mappings = data.mappings, data.sorted_mappings +            local fallbacks, sorted_fallbacks = data.fallbacks, data.sorted_fallbacks +            for i=1,#list do +                local format = list[i] +                list_them(mappings[format],sorted_mappings[format],pattern,t,all) +                if next(t) and not all then +                    return t +                end +                list_them(fallbacks[format],sorted_fallbacks[format],pattern,t,all) +                if next(t) and not all then +                    return t                  end              end          end +        return t +    end +end + +local reloaded = false + +local function is_reloaded() +    if not reloaded then          local data = names.data -        if data then -            list_them(data.mapping,data.sorted) -            list_them(data.fallback_mapping,data.fallback_sorted) +        if names.autoreload then +            local c_status = table.serialize(resolvers.data_state()) +            local f_status = table.serialize(data.data_state) +            if c_status == f_status then +                logs.report("fonts","font database matches configuration and file hashes") +                return +            else +                logs.report("fonts","font database does not match configuration and file hashes") +            end          end -        return t -    else -        return nil +        names.loaded = false +        reloaded = true +        io.flush() +        names.load(true)      end  end @@ -570,231 +780,326 @@ here is for testing purposes only (it deals with names prefixed by an  encoding name).</p>  --ldx]]-- -local function found_indeed(mapping,sorted,name) -    local mn = mapping[name] -    if mn then -        return mn[2], mn[3], mn[4] +-- if names.be_clever then -- this will become obsolete +--     local encoding, tag = match(name,"^(.-)[%-%:](.+)$") +--     local mt = mapping[tag] +--     if tag and fonts.enc.is_known(encoding) and mt then +--         return mt[1], encoding .. "-" .. mt[3], mt[4] +--     end +-- end + +-- simple search + +local function found(mapping,sorted,name,sub) +    local found = mapping[name] +    -- obsolete: old encoding test +    if not found then +        for k,v in next, mapping do +            if find(k,name) then +                found = v +                break +            end +        end +        if not found then +            local condensed = gsub(name,"[^%a%d]","") +            found = mapping[condensed] +            if not found then +                for k=1,#sorted do +                    local v = sorted[k] +                    if find(v,condensed) then +                        found = mapping[v] +                        break +                    end +                end +            end +        end +    end +    return found +end + +local function foundname(name,sub) +    local data = names.data +    local mappings, sorted_mappings = data.mappings, data.sorted_mappings +    local fallbacks, sorted_fallbacks = data.fallbacks, data.sorted_fallbacks +    local list = filters.list +    for i=1,#list do +        local l = list[i] +        local okay = found(mappings[l],sorted_mappings[l],name,sub) or found(fallbacks[l],sorted_fallbacks[l],name,sub) +        if okay then +            return okay +        end +    end +end + +function names.resolve(askedname,sub) +    if askedname and askedname ~= "" and names.enabled then +        askedname = cleanname(askedname) +        names.load() +        local found = foundname(askedname,sub) +        if not found and is_reloaded() then +            found = foundname(askedname,sub) +        end +        if found then +            return found.filename, found.subfont and found.rawname +        end +    end +end + +-- specified search + +local function s_collect_weight_style_width(found,done,all,weight,style,width,family) +    if family then +        for i=1,#family do +            local f = family[i] +            if f and weight == f.weight and style == f.style and width == f.width then +                found[#found+1], done[f] = f, true +                if not all then return end +            end +        end      end -    if names.be_clever then -- this will become obsolete -        local encoding, tag = match(name,"^(.-)[%-%:](.+)$") -        local mt = mapping[tag] -        if tag and fonts.enc.is_known(encoding) and mt then -            return mt[1], encoding .. "-" .. mt[3], mt[4] +end +local function m_collect_weight_style_width(found,done,all,weight,style,width,families,sorted,strictname) +    for i=1,#sorted do +        local k = sorted[i] +        local family = families[k] +        for i=1,#family do +            local f = family[i] +            if not done[f] and weight == f.weight and style == f.style and width == f.width and find(f.fontname,strictname) then +                found[#found+1], done[f] = f, true +                if not all then return end +            end +        end +    end +end + +local function s_collect_weight_style(found,done,all,weight,style,family) +    if family then +        for i=1,#family do local f = family[i] +            if f and weight == f.weight and style == f.style then +                found[#found+1], done[f] = f, true +                if not all then return end +            end          end      end -    -- name, type, file -    for k,v in next, mapping do -        if find(k,name) then -            return v[2], v[3], v[4] +end +local function m_collect_weight_style(found,done,all,weight,style,families,sorted,strictname) +    for i=1,#sorted do +        local k = sorted[i] +        local family = families[k] +        for i=1,#family do +            local f = family[i] +            if not done[f] and weight == f.weight and style == f.style and find(f.fontname,strictname) then +                found[#found+1], done[f] = f, true +                if not all then return end +            end          end      end -    local condensed = gsub(name,"[^%a%d]","") -    local mc = mapping[condensed] -    if mc then -        return mc[2], mc[3], mc[4] +end + +local function s_collect_style_width(found,done,all,style,width,family) +    if family then +        for i=1,#family do local f = family[i] +            if f and style == f.style and width == f.width then +                found[#found+1], done[f] = f, true +                if not all then return end +            end +        end      end -    for k=1,#sorted do -        local v = sorted[k] -        if find(v,condensed) then -            v = mapping[v] -            return v[2], v[3], v[4] +end +local function m_collect_style_width(found,done,all,style,width,families,sorted,strictname) +    for i=1,#sorted do +        local k = sorted[i] +        local family = families[k] +        for i=1,#family do +            local f = family[i] +            if not done[f] and style == f.style and width == f.width and find(f.fontname,strictname) then +                found[#found+1], done[f] = f, true +                if not all then return end +            end          end      end -    return nil, nil, nil  end -local function found(name) -    if name and name ~= "" and names.data then -        name = names.cleanname(name) -        local data = names.data -        local fontname, filename, is_sub = found_indeed(data.mapping, data.sorted, name) -        if not fontname or not filename then -            fontname, filename, is_sub = found_indeed(data.fallback_mapping, data.fallback_sorted, name) +local function s_collect_weight(found,done,all,weight,family) +    if family then +        for i=1,#family do local f = family[i] +            if f and weight == f.weight then +                found[#found+1], done[f] = f, true +                if not all then return end +            end +        end +    end +end +local function m_collect_weight(found,done,all,weight,families,sorted,strictname) +    for i=1,#sorted do +        local k = sorted[i] +        local family = families[k] +        for i=1,#family do +            local f = family[i] +            if not done[f] and weight == f.weight and find(f.fontname,strictname) then +                found[#found+1], done[f] = f, true +                if not all then return end +            end          end -        return fontname, filename, is_sub -    else -        return nil, nil, nil      end  end -local function collect(stage,mapping,sorted,found,done,name,weight,style,width,all) -    if not mapping or not sorted then -        return +local function s_collect_style(found,done,all,style,family) +    if family then +        for i=1,#family do local f = family[i] +            if f and style == f.style then +                found[#found+1], done[f] = f, true +                if not all then return end +            end +        end +    end +end +local function m_collect_style(found,done,all,style,families,sorted,strictname) +    for i=1,#sorted do +        local k = sorted[i] +        local family = families[k] +        for i=1,#family do +            local f = family[i] +            if not done[f] and style == f.style and find(f.fontname,strictname) then +                found[#found+1], done[f] = f, true +                if not all then return end +            end +        end      end -strictname = "^".. name -    local f = mapping[name] -    if weight ~= "" then -        if style ~= "" then -            if width ~= "" then +end + +local function s_collect_width(found,done,all,width,family) +    if family then +        for i=1,#family do local f = family[i] +            if f and width == f.width then +                found[#found+1], done[f] = f, true +                if not all then return end +            end +        end +    end +end +local function m_collect_width(found,done,all,width,families,sorted,strictname) +    for i=1,#sorted do +        local k = sorted[i] +        local family = families[k] +        for i=1,#family do +            local f = family[i] +            if not done[f] and width == f.width and find(f.fontname,strictname) then +                found[#found+1], done[f] = f, true +                if not all then return end +            end +        end +    end +end + +local function s_collect(found,done,all,family) +    if family then +        for i=1,#family do local f = family[i] +            if f then +                found[#found+1], done[f] = f, true +                if not all then return end +            end +        end +    end +end +local function m_collect(found,done,all,families,sorted,strictname) +    for i=1,#sorted do +        local k = sorted[i] +        local family = families[k] +        for i=1,#family do +            local f = family[i] +            if not done[f] and find(f.fontname,strictname) then +                found[#found+1], done[f] = f, true +                if not all then return end +            end +        end +    end +end + +local function collect(stage,found,done,name,weight,style,width,all) +    local data = names.data +    local families, sorted = data.families, data.sorted_families +    strictname = "^".. name -- to be checked +    local family = families[name] +    if trace_names then +        logs.report("fonts","resolving name '%s', weight '%s', style '%s', width '%s'",name or "?",tostring(weight),tostring(style),tostring(width)) +    end +    if weight and weight ~= "" then +        if style and style ~= "" then +            if width and width ~= "" then                  if trace_names then                      logs.report("fonts","resolving stage %s, name '%s', weight '%s', style '%s', width '%s'",stage,name,weight,style,width)                  end -                if f and width ~= f[8] and style == f[7] and weight == f[6] then -                    found[#found+1], done[name] = f, true -                    if not all then return end -                end -                for i=1,#sorted do -                    local k = sorted[i] -                    if not done[k] then -                        local v = mapping[k] -                        if v[6] == weight and v[7] == style and v[8] == width and find(v[5],strictname) then -                            found[#found+1], done[k] = v, true -                            if not all then return end -                        end -                    end -                end +                s_collect_weight_style_width(found,done,all,weight,style,width,family) +                m_collect_weight_style_width(found,done,all,weight,style,width,families,sorted,strictname)              else                  if trace_names then                      logs.report("fonts","resolving stage %s, name '%s', weight '%s', style '%s'",stage,name,weight,style)                  end -                if f and style == f[7] and weight == f[6] then -                    found[#found+1], done[name] = f, true -                    if not all then return end -                end -                for i=1,#sorted do -                    local k = sorted[i] -                    if not done[k] then -                        local v = mapping[k] -                        if v[6] == weight and v[7] == style and find(v[5],strictname) then -                            found[#found+1], done[k] = v, true -                            if not all then return end -                        end -                    end -                end +                s_collect_weight_style(found,done,all,weight,style,family) +                m_collect_weight_style(found,done,all,weight,style,families,sorted,strictname)              end          else              if trace_names then                  logs.report("fonts","resolving stage %s, name '%s', weight '%s'",stage,name,weight)              end -            if f and weight == f[6] then -                found[#found+1], done[name] = f, true -                if not all then return end -            end -            for i=1,#sorted do -                local k = sorted[i] -                if not done[k] then -                    local v = mapping[k] -                    if v[6] == weight and find(v[5],strictname) then -                        found[#found+1], done[k] = v, true -                        if not all then return end -                    end -                end -            end +            s_collect_weight(found,done,all,weight,family) +            m_collect_weight(found,done,all,weight,families,sorted,strictname)          end -    elseif style ~= "" then -        if width ~= "" then +    elseif style and style ~= "" then +        if width and width ~= "" then              if trace_names then                  logs.report("fonts","resolving stage %s, name '%s', style '%s', width '%s'",stage,name,style,width)              end -            if f and style == f[7] and width == f[8] then -                found[#found+1], done[name] = f, true -                if not all then return end -            end -            for i=1,#sorted do -                local k = sorted[i] -                if not done[k] then -                    local v = mapping[k] -                    if v[7] == style and v[8] == width and find(v[5],strictname) then -                        found[#found+1], done[k] = v, true -                        if not all then return end -                    end -                end -            end +            s_collect_style_width(found,done,all,style,width,family) +            m_collect_style_width(found,done,all,style,width,families,sorted,strictname)          else              if trace_names then                  logs.report("fonts","resolving stage %s, name '%s', style '%s'",stage,name,style)              end -            if f and style == f[7] then -                found[#found+1], done[name] = f, true -                if not all then return end -            end -            for i=1,#sorted do -                local k = sorted[i] -                if not done[k] then -                    local v = mapping[k] -                    if v[7] == style and find(v[5],strictname) then -                        found[#found+1], done[k] = v, true -                        if not all then return end -                    end -                end -            end +            s_collect_style(found,done,all,style,family) +            m_collect_style(found,done,all,style,families,sorted,strictname)          end -    elseif width ~= "" then +    elseif width and width ~= "" then          if trace_names then              logs.report("fonts","resolving stage %s, name '%s', width '%s'",stage,name,width)          end -        if f and width == f[8] then -            found[#found+1], done[name] = f, true -            if not all then return end -        end -        for i=1,#sorted do -            local k = sorted[i] -            if not done[k] then -                local v = mapping[k] -                if v[8] == width and find(v[5],strictname) then -                    found[#found+1], done[k] = v, true -                    if not all then return end -                end -            end -        end +        s_collect_width(found,done,all,width,family) +        m_collect_width(found,done,all,width,families,sorted,strictname)      else          if trace_names then              logs.report("fonts","resolving stage %s, name '%s'",stage,name)          end -        if f then -            found[#found+1], done[name] = f, true -            if not all then return end -        end -        for i=1,#sorted do -            local k = sorted[i] -            if not done[k] then -                local v = mapping[k] -                if find(v[5],strictname) then -                    found[#found+1], done[k] = v, true -                    if not all then return end -                end -            end -        end +        s_collect(found,done,all,family) +        m_collect(found,done,all,families,sorted,strictname)      end  end  function heuristic(name,weight,style,width,all) -- todo: fallbacks      local found, done = { }, { } -    local data = names.data -    local mapping, sorted, fbmapping, fbsorted = data.mapping, data.sorted, data.fallback_mapping, data.fallback_sorted      weight, style = weight or "", style or "" -    name = names.cleanname(name) -    collect(1,mapping,sorted,found,done,name,weight,style,width,all) -    if #found == 0 then -        collect(2,fbmapping,fbsorted,found,done,name,weight,style,width,all) -    end +    name = cleanname(name) +    collect(1,found,done,name,weight,style,width,all) +    -- still needed ?      if #found == 0 and width ~= "" then -        width = "normal" -        collect(3,mapping,sorted,found,done,name,weight,style,width,all) -        if #found == 0 then -            collect(4,fbmapping,fbsorted,found,done,name,weight,style,width,all) -        end +        width = "" +        collect(2,found,done,name,weight,style,width,all)      end      if #found == 0 and weight ~= "" then -- not style -        weight = "normal" -        collect(5,mapping,sorted,found,done,name,weight,style,width,all) -        if #found == 0 then -            collect(6,fbmapping,fbsorted,found,done,name,weight,style,width,all) -        end +        weight = "" +        collect(3,found,done,name,weight,style,width,all)      end      if #found == 0 and style ~= "" then -- not weight -        style = "normal" -        collect(7,mapping,sorted,found,done,name,weight,style,width,all) -        if #found == 0 then -            collect(8,fbmapping,fbsorted,found,done,name,weight,style,width,all) -        end +        style = "" +        collect(4,found,done,name,weight,style,width,all)      end +    --      local nf = #found      if trace_names then          if nf then              local t = { }              for i=1,nf do -                t[#t+1] = format("'%s'",found[i][2]) +                t[#t+1] = format("'%s'",found[i].fontname)              end              logs.report("fonts","name '%s' resolved to %s instances: %s",name,nf,concat(t," "))          else @@ -803,63 +1108,48 @@ function heuristic(name,weight,style,width,all) -- todo: fallbacks      end      if all then          return nf > 0 and found -    elseif nf > 0 then -        local f = found[1] -        return f[2], f[3], f[4]      else -        return nil, nil, nil +        return found[1]      end  end -local reloaded = false - -function names.specification(askedname,weight,style,width) +function names.specification(askedname,weight,style,width,reload,all)      if askedname and askedname ~= "" and names.enabled then          askedname = lower(askedname) -- or cleanname -        names.load() -        local name, filename, is_sub = heuristic(askedname,weight,style,width) -        if not filename and not reloaded and names.autoreload then -            names.loaded = false -            reloaded = true -            io.flush() -            names.load(true) -            name, filename, is_sub = heuristic(askedname,weight,style,width) +        names.load(reload) +        local found = heuristic(askedname,weight,style,width,all) +        if not found and is_reloaded() then +            found = heuristic(askedname,weight,style,width,all)              if not filename then -                name, filename, is_sub = found(askedname) -- old method +                found = foundname(askedname) -- old method              end          end -        return name, filename, is_sub +        return found      end  end -function names.collect(askedname,weight,style,width) +function names.collect(askedname,weight,style,width,reload,all)      if askedname and askedname ~= "" and names.enabled then          askedname = lower(askedname) -- or cleanname -        names.load() +        names.load(reload)          local list = heuristic(askedname,weight,style,width,true) -        if not list or #list == 0 and not reloaded and names.autoreload then -            names.loaded = false -            reloaded = true -            io.flush() -            names.load(true) +        if not list or #list == 0 and is_reloaded() then              list = heuristic(askedname,weight,style,width,true)          end          return list      end  end -function names.resolve(askedname, sub) -    local name, filename, is_sub = names.specification(askedname) -    return filename, (is_sub and name) or sub -end - -function names.collectspec(askedname) -    return names.collect(names.splitspec(askedname)) +function names.collectspec(askedname,reload,all) +    local name, weight, style, width = names.splitspec(askedname) +    return names.collect(name,weight,style,width,reload,all)  end  function names.resolvespec(askedname,sub) -    local name, filename, is_sub = names.specification(names.splitspec(askedname)) -    return filename, (is_sub and name) or sub +    local found = names.specification(names.splitspec(askedname)) +    if found then +        return found.filename, found.subfont and found.rawname +    end  end  --[[ldx-- @@ -924,3 +1214,89 @@ function names.exists(name)      names.autoreload = fna      return found  end + +-- for i=1,fonts.names.lookup(pattern) do +--     texio.write_nl(fonts.names.getkey("filename",i)) +-- end + +local lastlookups, lastpattern = { }, "" + +function names.lookup(pattern,name,reload) -- todo: find +    if lastpattern ~= pattern then +        names.load(reload) +        local specifications = names.data.specifications +        local families = names.data.families +        local lookups = specifications +        if name then +            lookups = families[name] +        elseif not find(pattern,"=") then +            lookups = families[pattern] +        end +        if trace_names then +            logs.report("fonts","starting with %s lookups for '%s'",#lookups,pattern) +        end +        if lookups then +            for key, value in gmatch(pattern,"([^=,]+)=([^=,]+)") do +                local t = { } +                for i=1,#lookups do +                    local s = lookups[i] +                    if s[key] == value then +                        t[#t+1] = lookups[i] +                    end +                end +                if trace_names then +                    logs.report("fonts","%s matches for key '%s' with value '%s'",#t,key,value) +                end +                lookups = t +            end +        end +        lastpattern = pattern +        lastlookups = lookups or { } +    end +    return #lastlookups +end + +function names.getlookupkey(key,n) +    local l = lastlookups[n or 1] +    return (l and l[key]) or "" +end + +function names.noflookups() +    return #lastlookups +end + +function names.getlookups(pattern,name,reload) +    if pattern then +        names.lookup(pattern,name,reload) +    end +    return lastlookups +end + +function table.formatcolumns(result) +    if result and #result > 0 then +        local widths = { } +        local first = result[1] +        local n = #first +        for i=1,n do +            widths[i] = 0 +        end +        for i=1,#result do +            local r = result[i] +            for j=1,n do +                local w = #r[j] +                if w > widths[j] then +                    widths[j] = w +                end +            end +        end +        for i=1,n do +            widths[i] = "%-" .. widths[i] .. "s" +        end +        local template = concat(widths,"   ") +        for i=1,#result do +            local str = format(template,unpack(result[i])) +            result[i] = string.strip(str) +        end +    end +    return result +end diff --git a/tex/context/base/font-tfm.lua b/tex/context/base/font-tfm.lua index 576829369..2794a947a 100644 --- a/tex/context/base/font-tfm.lua +++ b/tex/context/base/font-tfm.lua @@ -533,15 +533,15 @@ local private = fonts.private      end      -- needed for \high cum suis      local tpx = tp.x_height -if hasmath then -    if not tp[13] then tp[13] = .86*tpx end  -- mathsupdisplay -    if not tp[14] then tp[14] = .86*tpx end  -- mathsupnormal -    if not tp[15] then tp[15] = .86*tpx end  -- mathsupcramped -    if not tp[16] then tp[16] = .48*tpx end  -- mathsubnormal -    if not tp[17] then tp[17] = .48*tpx end  -- mathsubcombined -    if not tp[22] then tp[22] =   0     end  -- mathaxisheight -    if t.MathConstants then t.MathConstants.AccentBaseHeight = nil end -- safeguard -end +    if hasmath then +        if not tp[13] then tp[13] = .86*tpx end  -- mathsupdisplay +        if not tp[14] then tp[14] = .86*tpx end  -- mathsupnormal +        if not tp[15] then tp[15] = .86*tpx end  -- mathsupcramped +        if not tp[16] then tp[16] = .48*tpx end  -- mathsubnormal +        if not tp[17] then tp[17] = .48*tpx end  -- mathsubcombined +        if not tp[22] then tp[22] =   0     end  -- mathaxisheight +        if t.MathConstants then t.MathConstants.AccentBaseHeight = nil end -- safeguard +    end      t.tounicode = 1      t.cidinfo = tfmtable.cidinfo      -- we have t.name=metricfile and t.fullname=RealName and t.filename=diskfilename @@ -549,20 +549,21 @@ end      -- can have multiple subfonts      if hasmath then          if trace_defining then -            logs.report("define font","math enabled for: %s %s %s",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename") +            logs.report("define font","math enabled for: name '%s', fullname: '%s', filename: '%s'",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename")          end      else          if trace_defining then -            logs.report("define font","math disabled for: %s %s %s",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename") +            logs.report("define font","math disabled for: name '%s', fullname: '%s', filename: '%s'",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename")          end          t.nomath, t.MathConstants = true, nil      end -    -- fullname is used in the subsetting      if not t.psname then -        t.psname = t.fullname -- else bad luck +     -- name used in pdf file as well as for selecting subfont in ttc/dfont +        t.psname = t.fontname or (t.fullname and fonts.names.cleanname(t.fullname))      end      if trace_defining then -        logs.report("define font","used for subsetting: %s ",t.fullname or "nofullname") +        logs.report("define font","used for accesing subfont: '%s'",t.psname or "nopsname") +        logs.report("define font","used for subsetting: '%s'",t.fontname or "nofontname")      end      return t, delta  end diff --git a/tex/context/base/grph-inc.lua b/tex/context/base/grph-inc.lua index 0fc40b38b..44447a7ad 100644 --- a/tex/context/base/grph-inc.lua +++ b/tex/context/base/grph-inc.lua @@ -667,7 +667,12 @@ function figures.includers.generic(data)      end      if figure then          local n = figures.boxnumber -        tex.box[n] = img.node(figure) -- img.write(figure) +        tex.box[n] = node.hpack(img.node(figure)) +     -- tex.box[n] = img.node(figure) -- img.write(figure) -- assigning img.node directly no longer valid +--~ local inode = img.node(figure) +--~ print(table.serialize(nodes.totable(inode))) +--~ tex.box[n] = inode +--~ print(table.serialize(nodes.totable(tex.box[n])))          tex.wd[n], tex.ht[n], tex.dp[n] = figure.width, figure.height, 0 -- new, hm, tricky, we need to do that in tex (yet)          ds.objectnumber = figure.objnum          texsprint(ctxcatcodes,"\\relocateexternalfigure") diff --git a/tex/context/base/lang-ini.lua b/tex/context/base/lang-ini.lua index b7b908144..c251ab1a6 100644 --- a/tex/context/base/lang-ini.lua +++ b/tex/context/base/lang-ini.lua @@ -280,7 +280,7 @@ end  languages.words           = languages.words      or {}  languages.words.data      = languages.words.data or {} -languages.words.enable    = false +languages.words.enables   = false  languages.words.threshold = 4  languages.words.colors    = { @@ -426,7 +426,7 @@ do      local color = attributes.private('color')      function languages.words.check(head) -        if lw.enable and head.next then +        if lw.enabled and head.next then              local colors = lw.colors              local alc    = attributes.list[color]              return lw.methods[lw.method](head, color, alc[colors.known], alc[colors.unknown]) @@ -435,6 +435,15 @@ do          end      end +    function languages.words.enable() +        tasks.enableaction("processors","languages.words.check") +        languages.words.enabled = true +    end + +    function languages.words.disable() +        languages.words.enabled = false +    end +  end  -- for the moment we hook it into the attribute handler diff --git a/tex/context/base/lang-ini.mkiv b/tex/context/base/lang-ini.mkiv index f88281a60..86870d635 100644 --- a/tex/context/base/lang-ini.mkiv +++ b/tex/context/base/lang-ini.mkiv @@ -567,8 +567,8 @@  \def\setupspellchecking[#1]% todo colors    {\getparameters[\??wl][#1]%     \doifelse\@@wlstate\v!start -     {\ctxlua{languages.words.enable=true }} -     {\ctxlua{languages.words.enable=false}}} +     {\ctxlua{languages.words.enable()}} +     {\ctxlua{languages.words.disable()}}}  \setupspellchecking    [\c!state=\v!stop] diff --git a/tex/context/base/m-pstric.tex b/tex/context/base/m-pstric.tex index ac018fe07..f4be08dbd 100644 --- a/tex/context/base/m-pstric.tex +++ b/tex/context/base/m-pstric.tex @@ -13,6 +13,9 @@  %M \usemodule[pstric] +\letvalue{@unused}\plussixteen +\letvalue{alloc@}\gobblefivearguments +  \chardef\oldbarcode\the\catcode`\|  \catcode`\|=12  \def\loadpstrickscolors#1% diff --git a/tex/context/base/math-vfu.lua b/tex/context/base/math-vfu.lua index 0300bb07f..1a8979160 100644 --- a/tex/context/base/math-vfu.lua +++ b/tex/context/base/math-vfu.lua @@ -371,7 +371,7 @@ function fonts.vf.math.define(specification,set)                                  if trace_virtual then                                      logs.report("math virtual", "unicode point U+%05X has no index %04X in vector %s for font %s",unicode,index,vectorname,fontname)                                  elseif not already_reported then -                                    logs.report("math virtual", "the mapping is incomplete for '%s' at %s",name,size) +                                    logs.report("math virtual", "the mapping is incomplete for '%s' at %s",name,number.topoints(size))                                      already_reported = true                                  end                                  rv[unicode] = true @@ -747,6 +747,23 @@ fonts.enc.math["tex-mi"] = {      [0x0003E] = 0x3E, -- >      [0x022C6] = 0x3F, -- star      [0x02202] = 0x40, -- partial +-- +    [0x0266D] = 0x5B, -- flat +    [0x0266E] = 0x5C, -- natural +    [0x0266F] = 0x5D, -- sharp +    [0x02323] = 0x5E, -- smile +    [0x02322] = 0x5F, -- frown +    [0x02113] = 0x60, -- ell +--  +    [0x1D6A4] = 0x7B, -- imath (TODO: also 0131) +    [0x1D6A5] = 0x7C, -- jmath (TODO: also 0237) +    [0x02118] = 0x7D, -- wp +    [0x020D7] = 0x7E, -- vec (TODO: not sure) +--              0x7F, -- (no idea what that could be) +} + + +fonts.enc.math["tex-it"] = {  --  [0x00041] = 0x41, -- A      [0x1D6E2] = 0x41, -- Alpha  --  [0x00042] = 0x42, -- B @@ -786,12 +803,6 @@ fonts.enc.math["tex-mi"] = {  --  [0x00059] = 0x59, -- Y  --  [0x0005A] = 0x5A, -- Z      [0x1D6E7] = 0x5A, -- Zeta -    [0x0266D] = 0x5B, -- flat -    [0x0266E] = 0x5C, -- natural -    [0x0266F] = 0x5D, -- sharp -    [0x02323] = 0x5E, -- smile -    [0x02322] = 0x5F, -- frown -    [0x02113] = 0x60, -- ell  --  [0x00061] = 0x61, -- a  --  [0x00062] = 0x62, -- b  --  [0x00063] = 0x63, -- c @@ -800,7 +811,7 @@ fonts.enc.math["tex-mi"] = {  --  [0x00066] = 0x66, -- f  --  [0x00067] = 0x67, -- g  --  [0x00068] = 0x68, -- h -    [0x0210E] = 0x68, -- plant constant +    [0x0210E] = 0x68, -- plank constant  --  [0x00069] = 0x69, -- i  --  [0x0006A] = 0x6A, -- j  --  [0x0006B] = 0x6B, -- k @@ -820,11 +831,6 @@ fonts.enc.math["tex-mi"] = {  --  [0x00078] = 0x78, -- x  --  [0x00079] = 0x79, -- y  --  [0x0007A] = 0x7A, -- z -    [0x1D6A4] = 0x7B, -- imath (TODO: also 0131) -    [0x1D6A5] = 0x7C, -- jmath (TODO: also 0237) -    [0x02118] = 0x7D, -- wp -    [0x020D7] = 0x7E, -- vec (TODO: not sure) ---              0x7F, -- (no idea what that could be)  }  fonts.enc.math["tex-ss"]           = { } @@ -1314,7 +1320,7 @@ fonts.enc.math["tex-fraktur"] = {  -- now that all other vectors are defined ... -fonts.vf.math.set_letters(fonts.enc.math, "tex-mi", 0x1D434, 0x1D44E) +fonts.vf.math.set_letters(fonts.enc.math, "tex-it", 0x1D434, 0x1D44E)  fonts.vf.math.set_letters(fonts.enc.math, "tex-ss", 0x1D5A0, 0x1D5BA)  fonts.vf.math.set_letters(fonts.enc.math, "tex-tt", 0x1D670, 0x1D68A)  fonts.vf.math.set_letters(fonts.enc.math, "tex-bf", 0x1D400, 0x1D41A) @@ -1342,6 +1348,7 @@ mathematics.make_font ( "lmroman5-math", {      { name = "lmroman5-regular.otf", features = "virtualmath", main = true },      { name = "rm-lmr5.tfm", vector = "tex-mr-missing" } ,      { name = "lmmi5.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "lmmi5.tfm", vector = "tex-it", skewchar=0x7F },      { name = "lmsy5.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "lmex10.tfm", vector = "tex-ex", extension = true } ,      { name = "msam5.tfm", vector = "tex-ma" }, @@ -1363,6 +1370,7 @@ mathematics.make_font ( "lmroman6-math", {      { name = "lmroman6-regular.otf", features = "virtualmath", main = true },      { name = "rm-lmr6.tfm", vector = "tex-mr-missing" } ,      { name = "lmmi6.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "lmmi6.tfm", vector = "tex-it", skewchar=0x7F },      { name = "lmsy6.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "lmex10.tfm", vector = "tex-ex", extension = true } ,      { name = "msam5.tfm", vector = "tex-ma" }, @@ -1387,6 +1395,7 @@ mathematics.make_font ( "lmroman7-math", {      { name = "lmroman7-regular.otf", features = "virtualmath", main = true },      { name = "rm-lmr7.tfm", vector = "tex-mr-missing" } ,      { name = "lmmi7.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "lmmi7.tfm", vector = "tex-it", skewchar=0x7F },      { name = "lmsy7.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "lmex10.tfm", vector = "tex-ex", extension = true } ,      { name = "msam7.tfm", vector = "tex-ma" }, @@ -1409,6 +1418,7 @@ mathematics.make_font ( "lmroman8-math", {      { name = "lmroman8-regular.otf", features = "virtualmath", main = true },      { name = "rm-lmr8.tfm", vector = "tex-mr-missing" } ,      { name = "lmmi8.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "lmmi8.tfm", vector = "tex-it", skewchar=0x7F },      { name = "lmsy8.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "lmex10.tfm", vector = "tex-ex", extension = true } ,      { name = "msam7.tfm", vector = "tex-ma" }, @@ -1431,6 +1441,7 @@ mathematics.make_font ( "lmroman9-math", {      { name = "lmroman9-regular.otf", features = "virtualmath", main = true },      { name = "rm-lmr9.tfm", vector = "tex-mr-missing" } ,      { name = "lmmi9.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "lmmi9.tfm", vector = "tex-it", skewchar=0x7F },      { name = "lmsy9.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "lmex10.tfm", vector = "tex-ex", extension = true } ,      { name = "msam10.tfm", vector = "tex-ma" }, @@ -1456,6 +1467,7 @@ mathematics.make_font ( "lmroman10-math", {      { name = "lmroman10-regular.otf", features = "virtualmath", main = true },      { name = "rm-lmr10.tfm", vector = "tex-mr-missing" } ,      { name = "lmmi10.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "lmmi10.tfm", vector = "tex-it", skewchar=0x7F },      { name = "lmsy10.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "lmex10.tfm", vector = "tex-ex", extension = true } ,      { name = "msam10.tfm", vector = "tex-ma" }, @@ -1473,6 +1485,7 @@ mathematics.make_font ( "lmroman10-boldmath", {      { name = "lmroman10-bold.otf", features = "virtualmath", main = true },      { name = "rm-lmr10.tfm", vector = "tex-mr-missing" } ,      { name = "lmmib10.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "lmmib10.tfm", vector = "tex-it", skewchar=0x7F },      { name = "lmbsy10.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "lmex10.tfm", vector = "tex-ex", extension = true } ,  -- copied from roman: @@ -1495,6 +1508,7 @@ mathematics.make_font ( "lmroman12-math", {      { name = "lmroman12-regular.otf", features = "virtualmath", main = true },      { name = "rm-lmr12.tfm", vector = "tex-mr-missing" } ,      { name = "lmmi12.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "lmmi12.tfm", vector = "tex-it", skewchar=0x7F },      { name = "lmsy10.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "lmex10.tfm", vector = "tex-ex", extension = true } ,      { name = "msam10.tfm", vector = "tex-ma" }, @@ -1514,6 +1528,7 @@ mathematics.make_font ( "lmroman17-math", {      { name = "lmroman17-regular.otf", features = "virtualmath", main = true },      { name = "rm-lmr12.tfm", vector = "tex-mr-missing" } ,      { name = "lmmi12.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "lmmi12.tfm", vector = "tex-it", skewchar=0x7F },      { name = "lmsy10.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "lmex10.tfm", vector = "tex-ex", extension = true } ,      { name = "msam10.tfm", vector = "tex-ma" }, @@ -1533,6 +1548,7 @@ mathematics.make_font ( "px-math", {      { name = "texgyrepagella-regular.otf", features = "virtualmath", main = true },      { name = "rpxr.tfm", vector = "tex-mr" } ,      { name = "rpxmi.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "pxmi1.tfm", vector = "tex-it", skewchar=0x7F },      { name = "pxsy.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "pxex.tfm", vector = "tex-ex", extension = true } ,      { name = "pxsya.tfm", vector = "tex-ma" }, @@ -1542,6 +1558,7 @@ mathematics.make_font ( "px-math", {  mathematics.make_font ( "tx-math", {      { name = "texgyretermes-regular.otf", features = "virtualmath", main = true },      { name = "rtxr.tfm", vector = "tex-mr" } , +    { name = "rtxptmri.tfm", vector = "tex-it", skewchar=0x7F },      { name = "rtxmi.tfm", vector = "tex-mi", skewchar=0x7F },      { name = "txsy.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "txex.tfm", vector = "tex-ex", extension = true } , @@ -1552,6 +1569,7 @@ mathematics.make_font ( "tx-math", {  mathematics.make_font ( "antykwa-math", {      { name = "file:AntykwaTorunska-Regular", features = "virtualmath", main = true },      { name = "mi-anttri.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "mi-anttri.tfm", vector = "tex-it", skewchar=0x7F },      { name = "sy-anttrz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "ex-anttr.tfm", vector = "tex-ex", extension = true } ,      { name = "msam10.tfm", vector = "tex-ma" }, @@ -1561,6 +1579,7 @@ mathematics.make_font ( "antykwa-math", {  mathematics.make_font ( "antykwa-light-math", {      { name = "file:AntykwaTorunskaLight-Regular", features = "virtualmath", main = true },      { name = "mi-anttli.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "mi-anttli.tfm", vector = "tex-it", skewchar=0x7F },      { name = "sy-anttlz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "ex-anttl.tfm", vector = "tex-ex", extension = true } ,      { name = "msam10.tfm", vector = "tex-ma" }, @@ -1570,6 +1589,7 @@ mathematics.make_font ( "antykwa-light-math", {  mathematics.make_font ( "antykwa-cond-math", {      { name = "file:AntykwaTorunskaCond-Regular", features = "virtualmath", main = true },      { name = "mi-anttcri.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "mi-anttcri.tfm", vector = "tex-it", skewchar=0x7F },      { name = "sy-anttcrz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "ex-anttcr.tfm", vector = "tex-ex", extension = true } ,      { name = "msam10.tfm", vector = "tex-ma" }, @@ -1579,6 +1599,7 @@ mathematics.make_font ( "antykwa-cond-math", {  mathematics.make_font ( "antykwa-lightcond-math", {      { name = "file:AntykwaTorunskaCondLight-Regular", features = "virtualmath", main = true },      { name = "mi-anttcli.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "mi-anttcli.tfm", vector = "tex-it", skewchar=0x7F },      { name = "sy-anttclz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "ex-anttcl.tfm", vector = "tex-ex", extension = true } ,      { name = "msam10.tfm", vector = "tex-ma" }, @@ -1588,6 +1609,7 @@ mathematics.make_font ( "antykwa-lightcond-math", {  mathematics.make_font ( "iwona-math", {      { name = "file:Iwona-Regular", features = "virtualmath", main = true },      { name = "mi-iwonari.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "mi-iwonari.tfm", vector = "tex-it", skewchar=0x7F },      { name = "sy-iwonarz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "ex-iwonar.tfm", vector = "tex-ex", extension = true } ,      { name = "msam10.tfm", vector = "tex-ma" }, @@ -1597,6 +1619,7 @@ mathematics.make_font ( "iwona-math", {  mathematics.make_font ( "iwona-light-math", {      { name = "file:IwonaLight-Regular", features = "virtualmath", main = true },      { name = "mi-iwonali.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "mi-iwonali.tfm", vector = "tex-it", skewchar=0x7F },      { name = "sy-iwonalz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "ex-iwonal.tfm", vector = "tex-ex", extension = true } ,      { name = "msam10.tfm", vector = "tex-ma" }, @@ -1606,6 +1629,7 @@ mathematics.make_font ( "iwona-light-math", {  mathematics.make_font ( "iwona-medium-math", {      { name = "file:IwonaMedium-Regular", features = "virtualmath", main = true },      { name = "mi-iwonami.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "mi-iwonami.tfm", vector = "tex-it", skewchar=0x7F },      { name = "sy-iwonamz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "ex-iwonam.tfm", vector = "tex-ex", extension = true } ,      { name = "msam10.tfm", vector = "tex-ma" }, @@ -1615,6 +1639,7 @@ mathematics.make_font ( "iwona-medium-math", {  mathematics.make_font ( "iwona-heavy-math", {      { name = "file:IwonaHeavy-Regular", features = "virtualmath", main = true },      { name = "mi-iwonahi.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "mi-iwonahi.tfm", vector = "tex-it", skewchar=0x7F },      { name = "sy-iwonahz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,      { name = "ex-iwonah.tfm", vector = "tex-ex", extension = true } ,      { name = "msam10.tfm", vector = "tex-ma" }, @@ -1626,6 +1651,7 @@ mathematics.make_font ( "iwona-heavy-math", {  mathematics.make_font ( "mathtimes-math", {      { name = "file:texgyretermes-regular.otf", features = "virtualmath", main = true },      { name = "mtmiz.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "mtmiz.tfm", vector = "tex-it", skewchar=0x7F },      { name = "mtsyn.tfm", vector = "tex-sy", skewchar=0x30, parameters = true },      { name = "mtex.tfm", vector = "tex-ex", extension = true },      { name = "msam10.tfm", vector = "tex-ma" }, @@ -1635,6 +1661,7 @@ mathematics.make_font ( "mathtimes-math", {  mathematics.make_font ( "lucida-math", {      { name = "lbr.afm", features = "virtualmath", main = true },      { name = "hlcrim.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "hlcrim.tfm", vector = "tex-it", skewchar=0x7F },      { name = "hlcry.tfm", vector = "tex-sy", skewchar=0x30, parameters = true },      { name = "hlcrv.tfm", vector = "tex-ex", extension = true },      { name = "hlcra.tfm", vector = "tex-ma" }, @@ -1645,6 +1672,7 @@ mathematics.make_font ( "charter-math", {      { name = "file:bchr8a", features = "virtualmath", main = true },   -- { name = "md-chr7m.tfm", vector = "tex-mr" },      { name = "md-chri7m.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "md-chri7m.tfm", vector = "tex-it", skewchar=0x7F },      { name = "md-chr7y.tfm", vector = "tex-sy", skewchar=0x30, parameters = true },      { name = "md-chr7v.tfm", vector = "tex-ex", extension = true },      { name = "msam10.tfm", vector = "tex-ma" }, @@ -1655,6 +1683,7 @@ mathematics.make_font ( "garamond-math", {      { name = "file:ugmr8y", features = "virtualmath", main = true },   -- { name = "md-gmr7m.tfm", vector = "tex-mr" },      { name = "md-gmri7m.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "md-gmri7m.tfm", vector = "tex-it", skewchar=0x7F },      { name = "md-gmr7y.tfm", vector = "tex-sy", skewchar=0x30, parameters = true },      { name = "md-gmr7v.tfm", vector = "tex-ex", extension = true },      { name = "msam10.tfm", vector = "tex-ma" }, @@ -1665,6 +1694,7 @@ mathematics.make_font ( "utopia-math", {      { name = "file:putr8y", features = "virtualmath", main = true },   -- { name = "md-utr7m.tfm", vector = "tex-mr" },      { name = "md-utri7m.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "md-utri7m.tfm", vector = "tex-it", skewchar=0x7F },      { name = "md-utr7y.tfm", vector = "tex-sy", skewchar=0x30, parameters = true },      { name = "md-utr7v.tfm", vector = "tex-ex", extension = true },      { name = "msam10.tfm", vector = "tex-ma" }, @@ -1675,6 +1705,7 @@ mathematics.make_font ( "hvmath-math", {      { name = "file:texgyreheros-regular.otf", features = "virtualmath", main = true },      { name = "hvrm108r.tfm", vector="tex-mr" },      { name = "hvmi10.tfm", vector = "tex-mi", skewchar=0x7F }, +    { name = "hvmi10.tfm", vector = "tex-it", skewchar=0x7F },      { name = "hvsy10.tfm", vector = "tex-sy", skewchar=0x30, parameters = true },      { name = "hvex10.tfm", vector = "tex-ex", extension = true },      { name = "hvam10.tfm", vector = "tex-ma" }, diff --git a/tex/context/base/mlib-pps.lua b/tex/context/base/mlib-pps.lua index 253243500..f0ee1ec29 100644 --- a/tex/context/base/mlib-pps.lua +++ b/tex/context/base/mlib-pps.lua @@ -424,7 +424,7 @@ metapost.last_box        = metapost.last_box or 1100  metapost.textext_current = metapost.first_box  metapost.multipass       = false -function metapost.free_boxes() +function metapost.free_boxes() -- todo: mp direct list ipv box      local tb = tex.box      for i = metapost.first_box,metapost.last_box do          local b = tb[i] diff --git a/tex/context/base/node-ref.lua b/tex/context/base/node-ref.lua index 02f6ca82d..008e44b6b 100644 --- a/tex/context/base/node-ref.lua +++ b/tex/context/base/node-ref.lua @@ -67,6 +67,8 @@ local function dimensions(parent,start,stop)      end  end +-- is pardir important at all? +  local function inject_range(head,first,last,reference,make,stack,parent,pardir,txtdir)      local width, height, depth = dimensions(parent,first,last)      if pardir == "TRT" or txtdir == "+TRT" then diff --git a/tex/context/base/node-res.lua b/tex/context/base/node-res.lua index f147981ed..49a1297eb 100644 --- a/tex/context/base/node-res.lua +++ b/tex/context/base/node-res.lua @@ -60,8 +60,10 @@ local glyph      = nodes.register(new_node("glyph",0))  local textdir    = nodes.register(new_node("whatsit",7))  local rule       = nodes.register(new_node("rule"))  local latelua    = nodes.register(new_node("whatsit",35)) ---~ local user       = nodes.register(new_node("user_defined")) -local user       = nodes.register(new_node(44)) +local user_n     = nodes.register(new_node("whatsit",44)) user_n.type = 100 +local user_l     = nodes.register(new_node("whatsit",44)) user_l.type = 110 +local user_s     = nodes.register(new_node("whatsit",44)) user_s.type = 115 +local user_t     = nodes.register(new_node("whatsit",44)) user_t.type = 116  function nodes.glyph(fnt,chr)      local n = copy_node(glyph) @@ -111,27 +113,41 @@ function nodes.latelua(code)      return n  end +local cache = { } +  function nodes.usernumber(num) -    local n = copy_node(user) -    n.type = 100 -    if num then n.value = num end -    return n -end -function nodes.userstring(str) -    local n = copy_node(user) -    n.type = 115 -    if str then n.value = str end -    return n +    local n = cache[num] +    if n then +        return copy_node(n) +    else +        local n = copy_node(user_n) +        if num then n.value = num end +        return n +    end  end +  function nodes.userlist(list) -    local n = copy_node(user) -    n.type = 110 +    local n = copy_node(user_l)      if list then n.value = list end      return n  end + +local cache = { } -- we could use the same cache + +function nodes.userstring(str) +    local n = cache[str] +    if n then +        return copy_node(n) +    else +        local n = copy_node(user_s) +        n.type = 115 +        if str then n.value = str end +        return n +    end +end +  function nodes.usertokens(tokens) -    local n = copy_node(user) -    n.type = 116 +    local n = copy_node(user_t)      if tokens then n.value = tokens end      return n  end diff --git a/tex/context/base/node-rul.lua b/tex/context/base/node-rul.lua index 60c6e77f3..3f1d572b7 100644 --- a/tex/context/base/node-rul.lua +++ b/tex/context/base/node-rul.lua @@ -11,7 +11,6 @@ if not modules then modules = { } end modules ['node-rul'] = {  local trace_ruled = false  trackers.register("nodes.ruled", function(v) trace_ruled = v end)  local floor = math.floor -local topoints = number.topoints  local n_tostring, n_tosequence = nodes.ids_tostring, nodes.tosequence  local a_ruled        = attributes.private('ruled') @@ -19,12 +18,14 @@ local a_color        = attributes.private('color')  local a_transparency = attributes.private('transparency')  local a_colorspace   = attributes.private('colormodel') -local glyph = node.id("glyph") -local disc  = node.id("disc") -local glue  = node.id("glue") -local kern  = node.id("kern") -local hlist = node.id("hlist") -local vlist = node.id("vlist") +local glyph   = node.id("glyph") +local disc    = node.id("disc") +local glue    = node.id("glue") +local kern    = node.id("kern") +local hlist   = node.id("hlist") +local vlist   = node.id("vlist") +local rule    = node.id("rule") +local whatsit = node.id("whatsit")  local new_rule = nodes.rule  local new_kern = nodes.kern @@ -44,6 +45,11 @@ local variables = interfaces.variables  --  -- glyph rule unset whatsit glue margin_kern kern math disc +local checkdir = true + +-- we assume {glyphruns} and no funny extra kerning, ok, maybe we need +-- a dummy character as start and end; anyway we only collect glyphs +  local function process_words(attribute,data,flush,head,parent)      local n = head      if n then @@ -55,7 +61,7 @@ local function process_words(attribute,data,flush,head,parent)                  local aa = has_attribute(n,attribute)                  if aa then                      if aa == a then -                        if not f then +                        if not f then -- ?                              f = n                          end                          l = n @@ -77,6 +83,8 @@ local function process_words(attribute,data,flush,head,parent)                  end              elseif f and id == disc then                  l = n +            elseif f and id == rule then +                l = n              elseif f and id == kern and n.subtype == 0 then                  l = n              elseif id == hlist or id == vlist then @@ -88,6 +96,10 @@ local function process_words(attribute,data,flush,head,parent)                  if list then                      n.list = process_words(attribute,data,flush,list,n)                  end +            elseif checkdir and id == whatsit and n.subtype == 7 then -- only changes in dir, we assume proper boundaries +                if f and a then +                    l = n +                end              elseif f and not continue then                  head, done = flush(head,f,l,d,level,parent), true                  f, l, a = nil, nil, nil @@ -160,7 +172,7 @@ local function flush_ruled(head,f,l,d,level,parent) -- not that fast but accepta              insert_after(head,r,k)          end          if trace_ruled then -            logs.report("ruled", "level: %s, width: %s, nodes: %s, text: %s",level,topoints(w),n_tostring(f,l),n_tosequence(f,l,true)) +            logs.report("ruled", "level: %s, width: %s, nodes: %s, text: %s",level,w,n_tostring(f,l),n_tosequence(f,l,true))          end      end      return head @@ -179,6 +191,8 @@ end  -- tasks.appendaction ("shipouts", "normalizers", "nodes.rules.process")  -- tasks.disableaction("shipouts",                "nodes.rules.process") -- only kick in when used +local trace_shifted = false  trackers.register("nodes.shifted", function(v) trace_shifted = v end) +  local a_shifted = attributes.private('shifted')  nodes.shifts      = nodes.shifts      or { } @@ -209,6 +223,9 @@ local function flush_shifted(head,first,last,data,level,parent) -- not that fast      end      local raise = data.dy * dimenfactor(data.unit,fontdata[first.font])      list.shift, list.height, list.depth = raise, height, depth +    if trace_shifted then +        logs.report("shifted", "width: %s, nodes: %s, text: %s",width,n_tostring(first,last),n_tosequence(first,last,true)) +    end      return head  end diff --git a/tex/context/base/node-rul.mkiv b/tex/context/base/node-rul.mkiv index 40d0014dc..ba2f0aed3 100644 --- a/tex/context/base/node-rul.mkiv +++ b/tex/context/base/node-rul.mkiv @@ -11,6 +11,8 @@  %C therefore copyrighted by \PRAGMA. See mreadme.pdf for  %C details. +% todo: ex and and em traveling with attribute +  \writestatus{loading}{ConTeXt Core Macros / Bars}  %D The name of this file might change. @@ -255,13 +257,39 @@     \glet\dodoshifted\dodoshiftedindeed     \dodoshifted} +% \def\dodoshiftedindeed#1% +%   {\def\currentshift{#1}% +%    \advance\csname\??ra:#1:c\endcsname\plusone +%    \scratchcounter\csname\??ra:#1:c\endcsname +%    \dosetattribute{shifted}{\numexpr1000*\scratchcounter +%      +\csname\??ra#1\ifcsname\??ra#1:\number\scratchcounter\s!parent\endcsname:\number\scratchcounter\fi:a\endcsname}% +%    \setupalign[\shiftparameter\c!align]% +%    \dosetshiftattributes\c!style\c!color} + +\def\dostartisolation{\char0 } +\def\dostopisolation {\char0 } +\def\doisolator      {\char0 } + +\def\doisolatedgroupedalign#1#2% +  {\groupedcommand +     {\begingroup\dostartisolation\begingroup#1} +     {#2\endgroup\dostopisolation\endgroup}} + +\def\dosetupisolatedalign#1% +  {\doisolator +   \setupalign[#1]\relax} +  \def\dodoshiftedindeed#1%    {\def\currentshift{#1}%     \advance\csname\??ra:#1:c\endcsname\plusone     \scratchcounter\csname\??ra:#1:c\endcsname     \dosetattribute{shifted}{\numexpr1000*\scratchcounter       +\csname\??ra#1\ifcsname\??ra#1:\number\scratchcounter\s!parent\endcsname:\number\scratchcounter\fi:a\endcsname}% -   \dosetshiftattributes\c!style\c!color} +   \dosetshiftattributes\c!style\c!color +   \dosetupisolatedalign{\shiftparameter\c!align}} + +\def\doshifted#1% +  {\doisolatedgroupedalign{\dodoshifted{#1}}{}}  \unexpanded\def\startshift[#1]%    {\begingroup @@ -287,6 +315,7 @@     \c!continue=\v!no,     \c!dy=0,     \c!unit=ex, +   \c!align=,     \c!style=,     \c!color=] diff --git a/tex/context/base/node-tra.lua b/tex/context/base/node-tra.lua index 004aa34fa..f243c9cd0 100644 --- a/tex/context/base/node-tra.lua +++ b/tex/context/base/node-tra.lua @@ -310,7 +310,7 @@ function nodes.show_list(head, message)      if message then          texio.write_nl(message)      end -    for n in traverse(head) do +    for n in traverse_nodes(head) do          texio.write_nl(tostring(n))      end  end diff --git a/tex/context/base/pack-rul.mkiv b/tex/context/base/pack-rul.mkiv index 8bae7e754..bd3a127e3 100644 --- a/tex/context/base/pack-rul.mkiv +++ b/tex/context/base/pack-rul.mkiv @@ -2286,7 +2286,7 @@     \egroup}  \def\complexvl[#1]% -  {\dovlwdhtdp\linewidth{#1}{#1}} +  {\dovlwdhtdp{1}{#1}{#1}}  \def\complexhl[#1]%    {\hbox diff --git a/tex/context/base/spec-fdf.mkii b/tex/context/base/spec-fdf.mkii index 6f5a83bcb..509ea0596 100644 --- a/tex/context/base/spec-fdf.mkii +++ b/tex/context/base/spec-fdf.mkii @@ -191,6 +191,26 @@  \def\appendtoPDFdocumentextgstates#1%    {\xdef\docuPDFextgstates{\docuPDFextgstates\space#1}} +%D Patterns (for tikz) + +\let\docuPDFpatterns\empty + +\def\checkPDFpatterns +  {\ifx\docuPDFpatterns\empty \else +     \ifnum\realpageno=\lastpage\relax +       \doPDFdictionaryobject{FDF}{docupatterns}{\docuPDFpatterns}% +     \fi +     \doPDFgetobjectreference{FDF}{docupatterns}\PDFobjectreference +     \doPDFpageresource{/Pattern \PDFobjectreference}% +   \fi} + +\appendtoksonce +    \checkPDFpatterns +\to \everyshipout + +\def\appendtoPDFdocumentpatterns#1% +  {\xdef\docuPDFpatterns{\docuPDFpatterns\space#1}} +  %D Another special mechanism (needed for color separation):  \let\docuPDFcolorspaces\empty diff --git a/tex/context/base/strc-not.mkiv b/tex/context/base/strc-not.mkiv index 0d45ee59e..0246767b9 100644 --- a/tex/context/base/strc-not.mkiv +++ b/tex/context/base/strc-not.mkiv @@ -251,7 +251,6 @@  %     \dochecknote  % \to \everysetupnote -  \def\setupnote    {\dodoubleempty\dosetupnote} diff --git a/tex/context/base/tabl-tbl.mkiv b/tex/context/base/tabl-tbl.mkiv index bfff978ab..6942327fe 100644 --- a/tex/context/base/tabl-tbl.mkiv +++ b/tex/context/base/tabl-tbl.mkiv @@ -410,8 +410,8 @@  \def\gettabulatepreskip#1%    {\doifnumberelse{#1} -     {\edef\pretabskip{\the\dimenexpr#1\tabulateunit}\let\next\empty} -     {\edef\pretabskip{\the\dimenexpr.5\tabulateunit}\def\next{#1}}% +     {\edef\pretabskip{\the\dimexpr#1\tabulateunit}\let\next\empty} +     {\edef\pretabskip{\the\dimexpr.5\tabulateunit}\def\next{#1}}%     \@EA\settabulatepreamble\next}  \def\gettabulateposskip#1% @@ -423,8 +423,8 @@  \def\gettabulatepreposskip#1%    {\doifnumberelse{#1} -     {\edef\pretabskip{\the\dimenexpr#1\tabulateunit}\let\next\empty} -     {\edef\pretabskip{\the\dimenexpr.5\tabulateunit}\def\next{#1}}% +     {\edef\pretabskip{\the\dimexpr#1\tabulateunit}\let\next\empty} +     {\edef\pretabskip{\the\dimexpr.5\tabulateunit}\def\next{#1}}%     \let\postabskip\pretabskip     \let\gettabulateexit\settabulatepreamble     \@EA\settabulatepreamble\next} diff --git a/tex/context/base/task-ini.lua b/tex/context/base/task-ini.lua index dba099451..01bcaec0f 100644 --- a/tex/context/base/task-ini.lua +++ b/tex/context/base/task-ini.lua @@ -20,7 +20,8 @@ tasks.appendaction("processors", "characters",  "chars.handle_breakpoints")  tasks.appendaction("processors", "characters",  "scripts.preprocess")  tasks.appendaction("processors", "words",       "kernel.hyphenation") -tasks.appendaction("processors", "words",       "languages.words.check") +tasks.appendaction("processors", "words",       "languages.words.check")                     -- * disabled +  tasks.appendaction("processors", "fonts",       "nodes.process_characters")  tasks.appendaction("processors", "fonts",       "nodes.inject_kerns") @@ -28,21 +29,18 @@ tasks.appendaction("processors", "fonts",       "nodes.protect_glyphs", nil, "no  tasks.appendaction("processors", "fonts",       "kernel.ligaturing")  tasks.appendaction("processors", "fonts",       "kernel.kerning") -tasks.appendaction("processors", "lists",       "lists.handle_spacing")                      -- * -tasks.appendaction("processors", "lists",       "lists.handle_kerning")                      -- * +tasks.appendaction("processors", "lists",       "lists.handle_spacing")                      -- * disabled +tasks.appendaction("processors", "lists",       "lists.handle_kerning")                      -- * disabled  tasks.appendaction("shipouts",   "normalizers", "nodes.cleanup_page")  tasks.appendaction("shipouts",   "normalizers", "nodes.add_references")                      -- *  tasks.appendaction("shipouts",   "normalizers", "nodes.add_destinations")                    -- * -tasks.appendaction("shipouts",   "normalizers", "nodes.rules.process")                       -- * -tasks.appendaction("shipouts",   "normalizers", "nodes.shifts.process")                      -- * - -tasks.disableaction("shipouts",                 "nodes.rules.process")                       -- * only kick in when used -tasks.disableaction("shipouts",                 "nodes.shifts.process")                      -- * only kick in when used +tasks.appendaction("shipouts",   "normalizers", "nodes.rules.process")                       -- * disabled +tasks.appendaction("shipouts",   "normalizers", "nodes.shifts.process")                      -- * disabled  tasks.appendaction("shipouts",   "finishers",   "shipouts.handle_color")  tasks.appendaction("shipouts",   "finishers",   "shipouts.handle_transparency") -tasks.appendaction("shipouts",   "finishers",   "shipouts.handle_colorintent") +tasks.appendaction("shipouts",   "finishers",   "shipouts.handle_colorintent")               -- *  tasks.appendaction("shipouts",   "finishers",   "shipouts.handle_negative")                  -- *  tasks.appendaction("shipouts",   "finishers",   "shipouts.handle_effect")                    -- *  tasks.appendaction("shipouts",   "finishers",   "shipouts.handle_viewerlayer")               -- * @@ -56,3 +54,11 @@ tasks.appendaction("math",       "builders",    "noads.mlist_to_hlist")  -- quite experimental  tasks.appendaction("finalizers", "lists",       "nodes.repackage_graphicvadjust")            -- * + +-- speedup: see * -- only kick in when used + +tasks.disableaction("processors", "languages.words.check") +tasks.disableaction("processors", "lists.handle_spacing") +tasks.disableaction("processors", "lists.handle_kerning") +tasks.disableaction("shipouts",   "nodes.rules.process") +tasks.disableaction("shipouts",   "nodes.shifts.process") diff --git a/tex/context/base/type-otf.mkiv b/tex/context/base/type-otf.mkiv index 983e197de..e7844fb0b 100644 --- a/tex/context/base/type-otf.mkiv +++ b/tex/context/base/type-otf.mkiv @@ -525,6 +525,24 @@      \loadmapfile[mdput.map]  \stoptypescript +% asana math + +\starttypescript [math] [asana] +    \definefontsynonym [AsanaMath] [name:asanamath] +\stoptypescript + +\starttypescript [math] [asana] [name] +    \definefontsynonym [MathRoman] [AsanaMath] [features=math\mathsizesuffix] +\stoptypescript + +\starttypescript[asana] +  \definetypeface [\typescriptone] [rm] [serif] [palatino]       [default] +  \definetypeface [\typescriptone] [ss] [sans]  [modern]         [default] [rscale=1.075] +  \definetypeface [\typescriptone] [tt] [mono]  [modern]         [default] [rscale=1.075] +  \definetypeface [\typescriptone] [mm] [math]  [\typescriptone] [default] +  \quittypescriptscanning +\stoptypescript +  \stoptypescriptcollection  \endinput diff --git a/tex/context/base/typo-krn.lua b/tex/context/base/typo-krn.lua index 5ab0b07ed..87e066531 100644 --- a/tex/context/base/typo-krn.lua +++ b/tex/context/base/typo-krn.lua @@ -217,3 +217,8 @@ lists.handle_kerning = nodes.install_attribute_handler {      namespace = kerns,      processor = kerns.process,  } + +function kerns.enable() +    tasks.enableaction("processors","lists.handle_kerning") +    kerns.enabled = true -- will go +end diff --git a/tex/context/base/typo-spa.lua b/tex/context/base/typo-spa.lua index b6a1fbb5b..56ce36a05 100644 --- a/tex/context/base/typo-spa.lua +++ b/tex/context/base/typo-spa.lua @@ -25,7 +25,7 @@ local fontdata           = fonts.ids  spacings           = spacings         or { }  spacings.mapping   = spacings.mapping or { } -spacings.enabled   = false +spacings.enabled   = false -- will go  spacings.attribute = attributes.private("spacing")  storage.register("spacings/mapping", spacings.mapping, "spacings.mapping") @@ -148,3 +148,18 @@ lists.handle_spacing = nodes.install_attribute_handler {      namespace = spacings,      processor = spacings.process,  } + +function spacings.enable() +    tasks.enableaction("processors","lists.handle_spacing") +    spacings.enabled = true -- will go +end + +--~ local data = { +--~     name      = "spacing", +--~     namespace = spacings, +--~     processor = spacings.process, +--~ } +--~ nodes.process_attribute = process_attribute +--~ function lists.handle_spacing(head) +--~     return process_attribute(head,data) +--~ end diff --git a/tex/context/base/typo-spa.mkiv b/tex/context/base/typo-spa.mkiv index d1b855edd..9ff614be9 100644 --- a/tex/context/base/typo-spa.mkiv +++ b/tex/context/base/typo-spa.mkiv @@ -43,7 +43,8 @@     \fi}  \def\setcharacterspacing -  {\ctxlua{spacings.enabled=true}% +%   {\ctxlua{spacings.enabled=true}% +  {\ctxlua{spacings.enable()}%     \gdef\setcharacterspacing[##1]{\dosetattribute{spacing}{\csname\??ch:##1\endcsname}}%     \setcharacterspacing} diff --git a/tex/generic/context/luatex-fonts-merged.lua b/tex/generic/context/luatex-fonts-merged.lua index 70368ebd9..82fe96610 100644 --- a/tex/generic/context/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex-fonts-merged.lua @@ -1,6 +1,6 @@  -- merged file : c:/data/develop/context/texmf/tex/generic/context/luatex-fonts-merged.lua  -- parent file : c:/data/develop/context/texmf/tex/generic/context/luatex-fonts.lua --- merge date  : 11/13/09 12:51:09 +-- merge date  : 11/18/09 21:55:28  do -- begin closure to overcome local limits and interference @@ -2345,8 +2345,10 @@ local glyph      = nodes.register(new_node("glyph",0))  local textdir    = nodes.register(new_node("whatsit",7))  local rule       = nodes.register(new_node("rule"))  local latelua    = nodes.register(new_node("whatsit",35)) ---~ local user       = nodes.register(new_node("user_defined")) -local user       = nodes.register(new_node(44)) +local user_n     = nodes.register(new_node("whatsit",44)) user_n.type = 100 +local user_l     = nodes.register(new_node("whatsit",44)) user_l.type = 110 +local user_s     = nodes.register(new_node("whatsit",44)) user_s.type = 115 +local user_t     = nodes.register(new_node("whatsit",44)) user_t.type = 116  function nodes.glyph(fnt,chr)      local n = copy_node(glyph) @@ -2396,27 +2398,41 @@ function nodes.latelua(code)      return n  end +local cache = { } +  function nodes.usernumber(num) -    local n = copy_node(user) -    n.type = 100 -    if num then n.value = num end -    return n -end -function nodes.userstring(str) -    local n = copy_node(user) -    n.type = 115 -    if str then n.value = str end -    return n +    local n = cache[num] +    if n then +        return copy_node(n) +    else +        local n = copy_node(user_n) +        if num then n.value = num end +        return n +    end  end +  function nodes.userlist(list) -    local n = copy_node(user) -    n.type = 110 +    local n = copy_node(user_l)      if list then n.value = list end      return n  end + +local cache = { } -- we could use the same cache + +function nodes.userstring(str) +    local n = cache[str] +    if n then +        return copy_node(n) +    else +        local n = copy_node(user_s) +        n.type = 115 +        if str then n.value = str end +        return n +    end +end +  function nodes.usertokens(tokens) -    local n = copy_node(user) -    n.type = 116 +    local n = copy_node(user_t)      if tokens then n.value = tokens end      return n  end @@ -3794,15 +3810,15 @@ local private = fonts.private      end      -- needed for \high cum suis      local tpx = tp.x_height -if hasmath then -    if not tp[13] then tp[13] = .86*tpx end  -- mathsupdisplay -    if not tp[14] then tp[14] = .86*tpx end  -- mathsupnormal -    if not tp[15] then tp[15] = .86*tpx end  -- mathsupcramped -    if not tp[16] then tp[16] = .48*tpx end  -- mathsubnormal -    if not tp[17] then tp[17] = .48*tpx end  -- mathsubcombined -    if not tp[22] then tp[22] =   0     end  -- mathaxisheight -    if t.MathConstants then t.MathConstants.AccentBaseHeight = nil end -- safeguard -end +    if hasmath then +        if not tp[13] then tp[13] = .86*tpx end  -- mathsupdisplay +        if not tp[14] then tp[14] = .86*tpx end  -- mathsupnormal +        if not tp[15] then tp[15] = .86*tpx end  -- mathsupcramped +        if not tp[16] then tp[16] = .48*tpx end  -- mathsubnormal +        if not tp[17] then tp[17] = .48*tpx end  -- mathsubcombined +        if not tp[22] then tp[22] =   0     end  -- mathaxisheight +        if t.MathConstants then t.MathConstants.AccentBaseHeight = nil end -- safeguard +    end      t.tounicode = 1      t.cidinfo = tfmtable.cidinfo      -- we have t.name=metricfile and t.fullname=RealName and t.filename=diskfilename @@ -3810,20 +3826,21 @@ end      -- can have multiple subfonts      if hasmath then          if trace_defining then -            logs.report("define font","math enabled for: %s %s %s",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename") +            logs.report("define font","math enabled for: name '%s', fullname: '%s', filename: '%s'",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename")          end      else          if trace_defining then -            logs.report("define font","math disabled for: %s %s %s",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename") +            logs.report("define font","math disabled for: name '%s', fullname: '%s', filename: '%s'",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename")          end          t.nomath, t.MathConstants = true, nil      end -    -- fullname is used in the subsetting      if not t.psname then -        t.psname = t.fullname -- else bad luck +     -- name used in pdf file as well as for selecting subfont in ttc/dfont +        t.psname = t.fontname or (t.fullname and fonts.names.cleanname(t.fullname))      end      if trace_defining then -        logs.report("define font","used for subsetting: %s ",t.fullname or "nofullname") +        logs.report("define font","used for accesing subfont: '%s'",t.psname or "nopsname") +        logs.report("define font","used for subsetting: '%s'",t.fontname or "nofontname")      end      return t, delta  end @@ -6705,8 +6722,9 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th          tfm.units              = metadata.units_per_em or 1000          -- we need a runtime lookup because of running from cdrom or zip, brrr          tfm.filename           = resolvers.findbinfile(luatex.filename,"") or luatex.filename -        tfm.fullname           = metadata.fontname or metadata.fullname -        tfm.psname             = tfm.fullname +        tfm.fullname           = metadata.fullname +        tfm.fontname           = metadata.fontname +        tfm.psname             = tfm.fontname or tfm.fullname          tfm.encodingbytes      = 2          tfm.cidinfo            = data.cidinfo          tfm.cidinfo.registry   = tfm.cidinfo.registry or "" @@ -6830,7 +6848,8 @@ function tfm.read_from_open_type(specification)          if filename then              tfmtable.encodingbytes = 2              tfmtable.filename = resolvers.findbinfile(filename,"") or filename -            tfmtable.fullname = tfmtable.fullname or otfdata.metadata.fontname or otfdata.metadata.fullname +            tfmtable.fontname = tfmtable.fontname or otfdata.metadata.fontname +            tfmtable.fullname = tfmtable.fullname or otfdata.metadata.fullname or tfmtable.fontname              local order = otfdata and otfdata.metadata.order2              if order == 0 then                  tfmtable.format = 'opentype' @@ -6839,7 +6858,7 @@ function tfm.read_from_open_type(specification)              else                  tfmtable.format = specification.format              end -            tfmtable.name = tfmtable.filename or tfmtable.fullname +            tfmtable.name = tfmtable.filename or tfmtable.fullname or tfmtable.fontname          end          fonts.logger.save(tfmtable,file.extname(specification.filename),specification)      end @@ -7491,7 +7510,7 @@ results in different tables.</p>  -- remark: the 'not implemented yet' variants will be done when we have fonts that use them  -- remark: we need to check what to do with discretionaries -local concat = table.concat +local concat, insert, remove = table.concat, table.insert, table.remove  local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip  local type, next, tonumber, tostring = type, next, tonumber, tostring @@ -7513,6 +7532,7 @@ local trace_details      = false  trackers.register("otf.details",      function  local trace_applied      = false  trackers.register("otf.applied",      function(v) trace_applied      = v end)  local trace_steps        = false  trackers.register("otf.steps",        function(v) trace_steps        = v end)  local trace_skips        = false  trackers.register("otf.skips",        function(v) trace_skips        = v end) +local trace_directions   = false  trackers.register("otf.directions",   function(v) trace_directions   = v end)  trackers.register("otf.verbose_chain", function(v) otf.setcontextchain(v and "verbose") end)  trackers.register("otf.normal_chain",  function(v) otf.setcontextchain(v and "normal")  end) @@ -8117,7 +8137,7 @@ function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) -- to                                          if exit then                                              local dx, dy, bound = set_cursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])                                              if trace_cursive then -                                                logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound) +                                                logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)                                              end                                              done = true                                              break @@ -8769,7 +8789,7 @@ function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache,                                              if exit then                                                  local dx, dy, bound = set_cursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])                                                  if trace_cursive then -                                                    logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound) +                                                    logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode)                                                  end                                                  done = true                                                  break @@ -9206,6 +9226,9 @@ local resolved = { } -- we only resolve a font,script,language pair once  -- todo: pass all these 'locals' in a table +-- maybe some day i'll make an alternative that works on 'sub direction runs' which might be +-- more efficient for arabic but it has quite some consequences +  function fonts.methods.node.otf.features(head,font,attr)      if trace_steps then          checkstep(head) @@ -9249,6 +9272,7 @@ function fonts.methods.node.otf.features(head,font,attr)      local ra  = rl      [attr]     if ra == nil then ra  = { } rl      [attr]     = ra  end -- attr can be false      -- sequences always > 1 so no need for optimization      for s=1,#sequences do +    local pardir, txtdir = 0, { }          local success = false          local sequence = sequences[s]          local r = ra[s] -- cache @@ -9348,7 +9372,7 @@ function fonts.methods.node.otf.features(head,font,attr)                  local ns = #subtables                  local thecache = featuredata[typ] or { }                  start = head -- local ? -                rlmode = 0 +                rlmode = 0 -- to be checked ?                  if ns == 1 then                      local lookupname = subtables[1]                      local lookupcache = thecache[lookupname] @@ -9390,24 +9414,57 @@ function fonts.methods.node.otf.features(head,font,attr)                              --         start = start.next                              --     end                              elseif id == whatsit then +--~                             if subtype == 7 then +--~                                 local dir = start.dir +--~                                 if dir == "+TRT" then +--~                                     rlmode = -1 +--~                                 elseif dir == "+TLT" then +--~                                     rlmode = 1 +--~                                 else +--~                                     rlmode = 0 +--~                                 end +--~                             elseif subtype == 6 then +--~                                 local dir = start.dir +--~                                 if dir == "TRT" then +--~                                     rlmode = -1 +--~                                 elseif dir == "TLT" then +--~                                     rlmode = 1 +--~                                 else +--~                                     rlmode = 0 +--~                                 end +--~                             end                                  local subtype = start.subtype                                  if subtype == 7 then                                      local dir = start.dir -                                    if dir == "+TRT" then +                                    if     dir == "+TRT" or dir == "+TLT" then +                                        insert(txtdir,dir) +                                    elseif dir == "-TRT" or dir == "-TLT" then +                                        remove(txtdir) +                                    end +                                    local d = txtdir[#txtdir] +                                    if d == "+TRT" then                                          rlmode = -1 -                                    elseif dir == "+TLT" then +                                    elseif d == "+TLT" then                                          rlmode = 1                                      else -                                        rlmode = 0 +                                        rlmode = pardir +                                    end +                                    if trace_directions then +                                        logs.report("fonts","directions after textdir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode)                                      end                                  elseif subtype == 6 then                                      local dir = start.dir                                      if dir == "TRT" then -                                        rlmode = -1 +                                        pardir = -1                                      elseif dir == "TLT" then -                                        rlmode = 1 +                                        pardir = 1                                      else -                                        rlmode = 0 +                                        pardir = 0 +                                    end +                                    rlmode = pardir +                                --~ txtdir = { } +                                    if trace_directions then +                                        logs.report("fonts","directions after pardir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode)                                      end                                  end                                  start = start.next @@ -9415,7 +9472,6 @@ function fonts.methods.node.otf.features(head,font,attr)                                  start = start.next                              end                          end -                      end                  else                      while start do @@ -9462,25 +9518,59 @@ function fonts.methods.node.otf.features(head,font,attr)                          --     end                          elseif id == whatsit then                              local subtype = start.subtype -                            if subtype == 7 then -                                local dir = start.dir -                                if dir == "+TRT" then -                                    rlmode = -1 -                                elseif dir == "+TLT" then -                                    rlmode = 1 -                                else -                                    rlmode = 0 +--~                             if subtype == 7 then +--~                                 local dir = start.dir +--~                                 if dir == "+TRT" then +--~                                     rlmode = -1 +--~                                 elseif dir == "+TLT" then +--~                                     rlmode = 1 +--~                                 else +--~                                     rlmode = 0 +--~                                 end +--~                             elseif subtype == 6 then +--~                                 local dir = start.dir +--~                                 if dir == "TRT" then +--~                                     rlmode = -1 +--~                                 elseif dir == "TLT" then +--~                                     rlmode = 1 +--~                                 else +--~                                     rlmode = 0 +--~                                 end +--~                             end +                                local subtype = start.subtype +                                if subtype == 7 then +                                    local dir = start.dir +                                    if     dir == "+TRT" or dir == "+TLT" then +                                        insert(txtdir,dir) +                                    elseif dir == "-TRT" or dir == "-TLT" then +                                        remove(txtdir) +                                    end +                                    local d = txtdir[#txtdir] +                                    if d == "+TRT" then +                                        rlmode = -1 +                                    elseif d == "+TLT" then +                                        rlmode = 1 +                                    else +                                        rlmode = pardir +                                    end +                                    if trace_directions then +                                        logs.report("fonts","directions after textdir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode) +                                    end +                                elseif subtype == 6 then +                                    local dir = start.dir +                                    if dir == "TRT" then +                                        pardir = -1 +                                    elseif dir == "TLT" then +                                        pardir = 1 +                                    else +                                        pardir = 0 +                                    end +                                    rlmode = pardir +                                --~ txtdir = { } +                                if trace_directions then +                                    logs.report("fonts","directions after pardir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode)                                  end -                            elseif subtype == 6 then -                                local dir = start.dir -                                if dir == "TRT" then -                                    rlmode = -1 -                                elseif dir == "TLT" then -                                    rlmode = 1 -                                else -                                    rlmode = 0                                  end -                            end                              start = start.next                          else                              start = start.next @@ -11521,10 +11611,15 @@ function fonts.logger.save()  end  -- names +-- +-- Watch out, the version number is the same as the one used in +-- the mtx-fonts.lua function scripts.fonts.names as we use a +-- simplified font database in the plain solution and by using +-- a different number we're less dependent on context.  fonts.names = fonts.names or { } -fonts.names.version    = 1.014 +fonts.names.version    = 1.001 -- not the same as in context  fonts.names.basename   = "luatex-fonts-names.lua"  fonts.names.new_to_old = { }  fonts.names.old_to_new = { } @@ -11539,16 +11634,6 @@ function fonts.names.resolve(name,sub)                  local foundname = resolvers.find_file(basename,format) or ""                  if foundname ~= "" then                      data = dofile(foundname) -                    if data then -                        local d = {  } -                        for k, v in pairs(data.mapping) do -                            local t = v[1] -                            if t == "ttf" or t == "otf" or t == "ttc" or t == "dfont" then -                                d[k] = v -                            end -                        end -                        data.mapping = d -                    end                      break                  end              end @@ -11559,9 +11644,12 @@ function fonts.names.resolve(name,sub)          local condensed = string.gsub(string.lower(name),"[^%a%d]","")          local found = data.mapping and data.mapping[condensed]          if found then -            local filename, is_sub = found[3], found[4] -            if is_sub then is_sub = found[2] end -            return filename, is_sub +            local fontname, filename, subfont = found[1], found[2], found[3] +            if subfont then +                return filename, fontname +            else +                return filename, false +            end          else              return name, false -- fallback to filename          end | 
