From b309379ef546b7fa819f493fa3cb1dc559d4c3b8 Mon Sep 17 00:00:00 2001 From: Hans Hagen Date: Wed, 18 Nov 2009 21:51:00 +0100 Subject: beta 2009.11.18 21:51 --- scripts/context/lua/luatools.lua | 395 +++++++++++++++++++++++++------ scripts/context/lua/mtx-context.lua | 23 +- scripts/context/lua/mtx-fonts.lua | 214 ++++++++++++----- scripts/context/lua/mtxrun.lua | 147 +++++++----- scripts/context/stubs/mswin/luatools.lua | 395 +++++++++++++++++++++++++------ scripts/context/stubs/mswin/mtxrun.lua | 147 +++++++----- scripts/context/stubs/unix/luatools | 395 +++++++++++++++++++++++++------ scripts/context/stubs/unix/mtxrun | 147 +++++++----- 8 files changed, 1383 insertions(+), 480 deletions(-) (limited to 'scripts') 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 "", + entry.weight or "", + entry.style or "", + entry.width or "", + 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 ",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 ",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 ",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 -- cgit v1.2.3