From 1c7bea4f00308b0c7c4af302e3f9a877876253e0 Mon Sep 17 00:00:00 2001 From: Hans Hagen Date: Tue, 9 Mar 2010 10:39:00 +0100 Subject: beta 2010.03.09 10:39 --- scripts/context/lua/luatools.lua | 223 ++++++++++++++---- scripts/context/lua/mtx-update.lua | 10 +- scripts/context/lua/mtxrun.lua | 197 +++++++++++++--- scripts/context/stubs/mswin/context.exe | Bin 5633 -> 6144 bytes scripts/context/stubs/mswin/luatools.exe | Bin 5633 -> 6144 bytes scripts/context/stubs/mswin/luatools.lua | 223 ++++++++++++++---- scripts/context/stubs/mswin/metatex.exe | Bin 5633 -> 6144 bytes scripts/context/stubs/mswin/mtxrun.dll | Bin 7680 -> 8704 bytes scripts/context/stubs/mswin/mtxrun.exe | Bin 5633 -> 6144 bytes scripts/context/stubs/mswin/mtxrun.lua | 197 +++++++++++++--- scripts/context/stubs/mswin/texexec.exe | Bin 5633 -> 6144 bytes scripts/context/stubs/mswin/texmfstart.exe | Bin 5633 -> 6144 bytes scripts/context/stubs/source/mtxrun_dll.c | 347 ++++++++++++++--------------- scripts/context/stubs/unix/luatools | 223 ++++++++++++++---- scripts/context/stubs/unix/mtxrun | 197 +++++++++++++--- 15 files changed, 1193 insertions(+), 424 deletions(-) (limited to 'scripts') diff --git a/scripts/context/lua/luatools.lua b/scripts/context/lua/luatools.lua index f9b855f74..1a579eb69 100644 --- a/scripts/context/lua/luatools.lua +++ b/scripts/context/lua/luatools.lua @@ -338,6 +338,8 @@ if not modules then modules = { } end modules ['l-lpeg'] = { lpeg = require("lpeg") +lpeg.patterns = lpeg.patterns or { } -- so that we can share + local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc local match = lpeg.match @@ -488,11 +490,9 @@ end --~ --~ 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 - +lpeg.patterns.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont end -- of closure @@ -1868,6 +1868,7 @@ elseif os.type == "windows" then elseif name == "linux" then function os.resolvers.platform(t,k) + -- we sometims have HOSTTYPE set so let's check that first local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or "" if find(architecture,"x86_64") then platform = "linux-64" @@ -1881,17 +1882,28 @@ elseif name == "linux" then return platform end -elseif name == "macosx" then -- a rather inconsistent mess +elseif name == "macosx" then + + --[[ + Identifying the architecture of OSX is quite a mess and this + is the best we can come up with. For some reason $HOSTTYPE is + a kind of pseudo environment variable, not known to the current + environment. And yes, uname cannot be trusted either, so there + is a change that you end up with a 32 bit run on a 64 bit system. + Also, some proper 64 bit intel macs are too cheap (low-end) and + therefore not permitted to run the 64 bit kernel. + ]]-- function os.resolvers.platform(t,k) - local platform, architecture = "", os.resultof("uname -m") or "" + -- local platform, architecture = "", os.getenv("HOSTTYPE") or "" + -- if architecture == "" then + -- architecture = os.resultof("echo $HOSTTYPE") or "" + -- end + local platform, architecture = "", os.resultof("echo $HOSTTYPE") or "" if architecture == "" then - architecture = os.getenv("HOSTTYPE") or "" - end - if architecture == "" then - architecture = os.resultof("echo $HOSTTYPE") or "" - end - if find(architecture,"i386") then + -- print("\nI have no clue what kind of OSX you're running so let's assume an 32 bit intel.\n") + platform = "osx-intel" + elseif find(architecture,"i386") then platform = "osx-intel" elseif find(architecture,"x86_64") then platform = "osx-64" @@ -1931,6 +1943,21 @@ elseif name == "freebsd" then return platform end +elseif name == "kfreebsd" then + + function os.resolvers.platform(t,k) + -- we sometims have HOSTTYPE set so let's check that first + local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or "" + if find(architecture,"x86_64") then + platform = "kfreebsd-64" + else + platform = "kfreebsd-i386" + end + os.setenv("MTX_PLATFORM",platform) + os.platform = platform + return platform + end + else -- platform = "linux" @@ -1967,6 +1994,21 @@ function os.uuid() ) end +local d + +function os.timezone(delta) + d = d or tonumber(tonumber(os.date("%H")-os.date("!%H"))) + if delta then + if d > 0 then + return format("+%02i:00",d) + else + return format("-%02i:00",-d) + end + else + return 1 + end +end + end -- of closure @@ -1985,7 +2027,7 @@ if not modules then modules = { } end modules ['l-file'] = { file = file or { } local concat = table.concat -local find, gmatch, match, gsub, sub = string.find, string.gmatch, string.match, string.gsub, string.sub +local find, gmatch, match, gsub, sub, char = string.find, string.gmatch, string.match, string.gsub, string.sub, string.char local lpegmatch = lpeg.match function file.removesuffix(filename) @@ -2022,14 +2064,33 @@ end file.suffix = file.extname ---~ print(file.join("x/","/y")) ---~ print(file.join("http://","/y")) ---~ print(file.join("http://a","/y")) ---~ print(file.join("http:///a","/y")) ---~ print(file.join("//nas-1","/y")) +--~ function file.join(...) +--~ local pth = concat({...},"/") +--~ pth = gsub(pth,"\\","/") +--~ local a, b = match(pth,"^(.*://)(.*)$") +--~ if a and b then +--~ return a .. gsub(b,"//+","/") +--~ end +--~ a, b = match(pth,"^(//)(.*)$") +--~ if a and b then +--~ return a .. gsub(b,"//+","/") +--~ end +--~ return (gsub(pth,"//+","/")) +--~ end + +local trick_1 = char(1) +local trick_2 = "^" .. trick_1 .. "/+" function file.join(...) - local pth = concat({...},"/") + local lst = { ... } + local a, b = lst[1], lst[2] + if a == "" then + lst[1] = trick_1 + elseif b and find(a,"^/+$") and find(b,"^/") then + lst[1] = "" + lst[2] = gsub(b,"^/+","") + end + local pth = concat(lst,"/") pth = gsub(pth,"\\","/") local a, b = match(pth,"^(.*://)(.*)$") if a and b then @@ -2039,9 +2100,20 @@ function file.join(...) if a and b then return a .. gsub(b,"//+","/") end + pth = gsub(pth,trick_2,"") return (gsub(pth,"//+","/")) end +--~ print(file.join("//","/y")) +--~ print(file.join("/","/y")) +--~ print(file.join("","/y")) +--~ print(file.join("/x/","/y")) +--~ print(file.join("x/","/y")) +--~ print(file.join("http://","/y")) +--~ print(file.join("http://a","/y")) +--~ print(file.join("http:///a","/y")) +--~ print(file.join("//nas-1","/y")) + function file.iswritable(name) local a = lfs.attributes(name) or lfs.attributes(file.dirname(name,".")) return a and sub(a.permissions,2,2) == "w" @@ -2080,16 +2152,22 @@ function file.join_path(tab) return concat(tab,io.pathseparator) -- can have trailing // end +-- we can hash them weakly + function file.collapse_path(str) - str = gsub(str,"/%./","/") - local n, m = 1, 1 - while n > 0 or m > 0 do - str, n = gsub(str,"[^/%.]+/%.%.$","") - str, m = gsub(str,"[^/%.]+/%.%./","") - end - str = gsub(str,"([^/])/$","%1") - str = gsub(str,"^%./","") - str = gsub(str,"/%.$","") + str = gsub(str,"\\","/") + if find(str,"/") then + str = gsub(str,"^%./",(gsub(lfs.currentdir(),"\\","/")) .. "/") -- ./xx in qualified + str = gsub(str,"/%./","/") + local n, m = 1, 1 + while n > 0 or m > 0 do + str, n = gsub(str,"[^/%.]+/%.%.$","") + str, m = gsub(str,"[^/%.]+/%.%./","") + end + str = gsub(str,"([^/])/$","%1") + -- str = gsub(str,"^%./","") -- ./xx in qualified + str = gsub(str,"/%.$","") + end if str == "" then str = "." end return str end @@ -2391,7 +2469,7 @@ function url.hashed(str) end function url.hasscheme(str) - return not url.split(str).nosheme + return url.split(str)[1] ~= "" end function url.addscheme(str,scheme) @@ -2788,7 +2866,7 @@ else --~ print(dir.mkdirs("///a/b/c")) --~ print(dir.mkdirs("a/bbb//ccc/")) - function dir.expand_name(str) + function dir.expand_name(str) -- will be merged with cleanpath and collapsepath if not find(str,"^/") then str = lfs.currentdir() .. "/" .. str end @@ -3503,6 +3581,8 @@ local stripper = lpeg.Cs((number + 1)^0) --~ lpegmatch(stripper,str) --~ print(#str, os.clock()-ts, lpegmatch(stripper,sample)) +lpeg.patterns.strip_zeros = stripper + function aux.strip_zeros(str) return lpegmatch(stripper,str) end @@ -3789,14 +3869,14 @@ end function setters.enable(t,what) local e = t.enable t.enable, t.done = enable, { } - enable(t,string.simpleesc(what)) + enable(t,string.simpleesc(tostring(what))) t.enable, t.done = e, { } end function setters.disable(t,what) local e = t.disable t.disable, t.done = disable, { } - disable(t,string.simpleesc(what)) + disable(t,string.simpleesc(tostring(what))) t.disable, t.done = e, { } end @@ -3847,13 +3927,15 @@ function setters.new(name) return t end -trackers = setters.new("trackers") -directives = setters.new("directives") +trackers = setters.new("trackers") +directives = setters.new("directives") +experiments = setters.new("experiments") -- 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 trace_directives = false local trace_directives = false trackers.register("system.directives", function(v) trace_directives = v end) +local trace_experiments = false local trace_experiments = false trackers.register("system.experiments", function(v) trace_experiments = v end) local e = directives.enable local d = directives.disable @@ -3868,6 +3950,26 @@ function directives.disable(...) d(...) end +local e = experiments.enable +local d = experiments.disable + +function experiments.enable(...) + commands.writestatus("experiments","enabling: %s",concat({...}," ")) + e(...) +end + +function experiments.disable(...) + commands.writestatus("experiments","disabling: %s",concat({...}," ")) + d(...) +end + +-- a useful example + +directives.register("system.nostatistics", function(v) + statistics.enable = not v +end) + + end -- of closure @@ -4181,6 +4283,14 @@ function statistics.hastimer(instance) return instance and instance.starttime end +function statistics.resettiming(instance) + if not instance then + notimer = { timing = 0, loadtime = 0 } + else + instance.timing, instance.loadtime = 0, 0 + end +end + function statistics.starttiming(instance) if not instance then notimer = { } @@ -4240,6 +4350,12 @@ function statistics.elapsedindeed(instance) return t > statistics.threshold end +function statistics.elapsedseconds(instance,rest) -- returns nil if 0 seconds + if statistics.elapsedindeed(instance) then + return format("%s seconds %s", statistics.elapsedtime(instance),rest or "") + end +end + -- general function function statistics.register(tag,fnc) @@ -4318,6 +4434,23 @@ function statistics.timed(action,report) report("total runtime: %s",statistics.elapsedtime(timer)) end +-- where, not really the best spot for this: + +commands = commands or { } + +local timer + +function commands.resettimer() + statistics.resettiming(timer) + statistics.starttiming(timer) +end + +function commands.elapsedtime() + statistics.stoptiming(timer) + tex.sprint(statistics.elapsedtime(timer)) +end + +commands.resettimer() end -- of closure @@ -4755,8 +4888,8 @@ suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' } alternatives['map files'] = 'map' alternatives['enc files'] = 'enc' -alternatives['cid files'] = 'cid' -alternatives['fea files'] = 'fea' +alternatives['cid maps'] = 'cid' -- great, why no cid files +alternatives['font feature files'] = 'fea' -- and fea files here alternatives['opentype fonts'] = 'otf' alternatives['truetype fonts'] = 'ttf' alternatives['truetype collections'] = 'ttc' @@ -4899,8 +5032,10 @@ local function check_configuration() -- not yet ok, no time for debugging now -- bad luck end fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm - fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") - fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + -- this will go away some day + fix("FONTFEATURES", ".;$TEXMF/fonts/{data,fea}//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + fix("FONTCIDMAPS" , ".;$TEXMF/fonts/{data,cid}//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + -- fix("LUATEXLIBS" , ".;$TEXMF/luatex/lua//") end @@ -5290,7 +5425,7 @@ 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] = file.collapse_path(fname) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) @@ -5319,7 +5454,7 @@ 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] = file.collapse_path(fname) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) @@ -5444,7 +5579,7 @@ local weird = lpeg.P(".")^1 + lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,? --~ local l_forbidden = lpeg.S("~`!#$%^&*()={}[]:;\"\'||\\/<>,?\n\r\t") --~ local l_confusing = lpeg.P(" ") ---~ local l_character = lpeg.utf8 +--~ local l_character = lpeg.patterns.utf8 --~ local l_dangerous = lpeg.P(".") --~ local l_normal = (l_character - l_forbidden - l_confusing - l_dangerous) * (l_character - l_forbidden - l_confusing^2)^0 * lpeg.P(-1) @@ -6184,8 +6319,7 @@ 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 = file.collapse_path(filename) -- speed up / beware: format problem if instance.remember then stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -6666,12 +6800,13 @@ end function table.sequenced(t,sep) -- temp here local s = { } for k, v in pairs(t) do -- pairs? - s[#s+1] = k .. "=" .. v + s[#s+1] = k .. "=" .. tostring(v) end return concat(s, sep or " | ") end function resolvers.methodhandler(what, filename, filetype) -- ... + filename = file.collapse_path(filename) local specification = (type(filename) == "string" and resolvers.splitmethod(filename)) or filename -- no or { }, let it bomb local scheme = specification.scheme if resolvers[what][scheme] then diff --git a/scripts/context/lua/mtx-update.lua b/scripts/context/lua/mtx-update.lua index 09d3106b6..4f04b2245 100644 --- a/scripts/context/lua/mtx-update.lua +++ b/scripts/context/lua/mtx-update.lua @@ -383,7 +383,13 @@ function scripts.update.synchronize() end if not force then logs.report("update", "use --force to really update files") + else + -- update filename database for pdftex/xetex + scripts.update.run("mktexlsr") + -- update filename database for luatex + scripts.update.run("luatools --generate") end + logs.report("update","done") end @@ -408,10 +414,6 @@ function scripts.update.make() local formats = states.get('formats') resolvers.load_tree(texroot) - -- update filename database for pdftex/xetex - scripts.update.run("mktexlsr") - -- update filename database for luatex - scripts.update.run("luatools --generate") local askedformats = formats local texformats = table.tohash(scripts.update.texformats) local mpformats = table.tohash(scripts.update.mpformats) diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index 8a2d7a123..ef7eda9b0 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -347,6 +347,8 @@ if not modules then modules = { } end modules ['l-lpeg'] = { lpeg = require("lpeg") +lpeg.patterns = lpeg.patterns or { } -- so that we can share + local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc local match = lpeg.match @@ -497,11 +499,9 @@ end --~ --~ 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 - +lpeg.patterns.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont end -- of closure @@ -1952,6 +1952,21 @@ elseif name == "freebsd" then return platform end +elseif name == "kfreebsd" then + + function os.resolvers.platform(t,k) + -- we sometims have HOSTTYPE set so let's check that first + local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or "" + if find(architecture,"x86_64") then + platform = "kfreebsd-64" + else + platform = "kfreebsd-i386" + end + os.setenv("MTX_PLATFORM",platform) + os.platform = platform + return platform + end + else -- platform = "linux" @@ -2021,7 +2036,7 @@ if not modules then modules = { } end modules ['l-file'] = { file = file or { } local concat = table.concat -local find, gmatch, match, gsub, sub = string.find, string.gmatch, string.match, string.gsub, string.sub +local find, gmatch, match, gsub, sub, char = string.find, string.gmatch, string.match, string.gsub, string.sub, string.char local lpegmatch = lpeg.match function file.removesuffix(filename) @@ -2058,14 +2073,33 @@ end file.suffix = file.extname ---~ print(file.join("x/","/y")) ---~ print(file.join("http://","/y")) ---~ print(file.join("http://a","/y")) ---~ print(file.join("http:///a","/y")) ---~ print(file.join("//nas-1","/y")) +--~ function file.join(...) +--~ local pth = concat({...},"/") +--~ pth = gsub(pth,"\\","/") +--~ local a, b = match(pth,"^(.*://)(.*)$") +--~ if a and b then +--~ return a .. gsub(b,"//+","/") +--~ end +--~ a, b = match(pth,"^(//)(.*)$") +--~ if a and b then +--~ return a .. gsub(b,"//+","/") +--~ end +--~ return (gsub(pth,"//+","/")) +--~ end + +local trick_1 = char(1) +local trick_2 = "^" .. trick_1 .. "/+" function file.join(...) - local pth = concat({...},"/") + local lst = { ... } + local a, b = lst[1], lst[2] + if a == "" then + lst[1] = trick_1 + elseif b and find(a,"^/+$") and find(b,"^/") then + lst[1] = "" + lst[2] = gsub(b,"^/+","") + end + local pth = concat(lst,"/") pth = gsub(pth,"\\","/") local a, b = match(pth,"^(.*://)(.*)$") if a and b then @@ -2075,9 +2109,20 @@ function file.join(...) if a and b then return a .. gsub(b,"//+","/") end + pth = gsub(pth,trick_2,"") return (gsub(pth,"//+","/")) end +--~ print(file.join("//","/y")) +--~ print(file.join("/","/y")) +--~ print(file.join("","/y")) +--~ print(file.join("/x/","/y")) +--~ print(file.join("x/","/y")) +--~ print(file.join("http://","/y")) +--~ print(file.join("http://a","/y")) +--~ print(file.join("http:///a","/y")) +--~ print(file.join("//nas-1","/y")) + function file.iswritable(name) local a = lfs.attributes(name) or lfs.attributes(file.dirname(name,".")) return a and sub(a.permissions,2,2) == "w" @@ -2116,16 +2161,22 @@ function file.join_path(tab) return concat(tab,io.pathseparator) -- can have trailing // end +-- we can hash them weakly + function file.collapse_path(str) - str = gsub(str,"/%./","/") - local n, m = 1, 1 - while n > 0 or m > 0 do - str, n = gsub(str,"[^/%.]+/%.%.$","") - str, m = gsub(str,"[^/%.]+/%.%./","") - end - str = gsub(str,"([^/])/$","%1") - str = gsub(str,"^%./","") - str = gsub(str,"/%.$","") + str = gsub(str,"\\","/") + if find(str,"/") then + str = gsub(str,"^%./",(gsub(lfs.currentdir(),"\\","/")) .. "/") -- ./xx in qualified + str = gsub(str,"/%./","/") + local n, m = 1, 1 + while n > 0 or m > 0 do + str, n = gsub(str,"[^/%.]+/%.%.$","") + str, m = gsub(str,"[^/%.]+/%.%./","") + end + str = gsub(str,"([^/])/$","%1") + -- str = gsub(str,"^%./","") -- ./xx in qualified + str = gsub(str,"/%.$","") + end if str == "" then str = "." end return str end @@ -2824,7 +2875,7 @@ else --~ print(dir.mkdirs("///a/b/c")) --~ print(dir.mkdirs("a/bbb//ccc/")) - function dir.expand_name(str) + function dir.expand_name(str) -- will be merged with cleanpath and collapsepath if not find(str,"^/") then str = lfs.currentdir() .. "/" .. str end @@ -3340,6 +3391,8 @@ local stripper = lpeg.Cs((number + 1)^0) --~ lpegmatch(stripper,str) --~ print(#str, os.clock()-ts, lpegmatch(stripper,sample)) +lpeg.patterns.strip_zeros = stripper + function aux.strip_zeros(str) return lpegmatch(stripper,str) end @@ -3626,14 +3679,14 @@ end function setters.enable(t,what) local e = t.enable t.enable, t.done = enable, { } - enable(t,string.simpleesc(what)) + enable(t,string.simpleesc(tostring(what))) t.enable, t.done = e, { } end function setters.disable(t,what) local e = t.disable t.disable, t.done = disable, { } - disable(t,string.simpleesc(what)) + disable(t,string.simpleesc(tostring(what))) t.disable, t.done = e, { } end @@ -3720,6 +3773,13 @@ function experiments.disable(...) d(...) end +-- a useful example + +directives.register("system.nostatistics", function(v) + statistics.enable = not v +end) + + end -- of closure @@ -3995,9 +4055,9 @@ local function attribute_specification_error(str) return str end -function xml.unknown_dec_entity_format(str) return format("&%s;", str) end +function xml.unknown_dec_entity_format(str) return (str == "" and "&error;") or format("&%s;",str) end function xml.unknown_hex_entity_format(str) return format("&#x%s;",str) end -function xml.unknown_any_entity_format(str) return format("&%s;", str) end +function xml.unknown_any_entity_format(str) return format("&#x%s;",str) end local function handle_hex_entity(str) local h = hcache[str] @@ -4111,7 +4171,11 @@ local function handle_any_entity(str) if trace_entities then logs.report("xml","keeping entity &%s;",str) end - a = "&" .. str .. ";" + if str == "" then + a = "&error;" + else + a = "&" .. str .. ";" + end end end acache[str] = a @@ -4132,6 +4196,9 @@ local function handle_any_entity(str) if a then -- one of the predefined acache[str] = a + elseif str == "" then + a = "&error;" + acache[str] = a else a = "&" .. str .. ";" acache[str] = a @@ -4460,7 +4527,7 @@ function xml.checkbom(root) -- can be made faster local dt, found = root.dt, false for k=1,#dt do local v = dt[k] - if type(v) == "table" and v.special and v.tg == "@pi" and find(v.dt,"xml.*version=") then + if type(v) == "table" and v.special and v.tg == "@pi@" and find(v.dt[1],"xml.*version=") then found = true break end @@ -4842,6 +4909,8 @@ function xml.assign(dt,k,root) end end +-- the following helpers may move + --[[ldx--

The next helper assigns a tree (or string). Usage:

@@ -4860,6 +4929,22 @@ function xml.tocdata(e,wrapper) e.dt = { t } end +function xml.makestandalone(root) + if root.ri then + local dt = root.dt + for k=1,#dt do + local v = dt[k] + if type(v) == "table" and v.special and v.tg == "@pi@" then + local txt = v.dt[1] + if find(txt,"xml.*version=") then + v.dt[1] = txt .. " standalone='yes'" + break + end + end + end + end +end + end -- of closure @@ -5476,8 +5561,13 @@ local register_initial_child = { kind = "axis", axis = "initial-child" local register_all_nodes = { kind = "nodes", nodetest = true, nodes = { true, false, false } } +local skip = { } + local function errorrunner_e(str,cnv) - logs.report("lpath","error in expression: %s => %s",str,cnv) + if not skip[str] then + logs.report("lpath","error in expression: %s => %s",str,cnv) + skip[str] = cnv or str + end return false end local function errorrunner_f(str,arg) @@ -7287,6 +7377,14 @@ function statistics.hastimer(instance) return instance and instance.starttime end +function statistics.resettiming(instance) + if not instance then + notimer = { timing = 0, loadtime = 0 } + else + instance.timing, instance.loadtime = 0, 0 + end +end + function statistics.starttiming(instance) if not instance then notimer = { } @@ -7346,6 +7444,12 @@ function statistics.elapsedindeed(instance) return t > statistics.threshold end +function statistics.elapsedseconds(instance,rest) -- returns nil if 0 seconds + if statistics.elapsedindeed(instance) then + return format("%s seconds %s", statistics.elapsedtime(instance),rest or "") + end +end + -- general function function statistics.register(tag,fnc) @@ -7424,6 +7528,23 @@ function statistics.timed(action,report) report("total runtime: %s",statistics.elapsedtime(timer)) end +-- where, not really the best spot for this: + +commands = commands or { } + +local timer + +function commands.resettimer() + statistics.resettiming(timer) + statistics.starttiming(timer) +end + +function commands.elapsedtime() + statistics.stoptiming(timer) + tex.sprint(statistics.elapsedtime(timer)) +end + +commands.resettimer() end -- of closure @@ -7861,8 +7982,8 @@ suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' } alternatives['map files'] = 'map' alternatives['enc files'] = 'enc' -alternatives['cid files'] = 'cid' -alternatives['fea files'] = 'fea' +alternatives['cid maps'] = 'cid' -- great, why no cid files +alternatives['font feature files'] = 'fea' -- and fea files here alternatives['opentype fonts'] = 'otf' alternatives['truetype fonts'] = 'ttf' alternatives['truetype collections'] = 'ttc' @@ -8005,8 +8126,10 @@ local function check_configuration() -- not yet ok, no time for debugging now -- bad luck end fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm - fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") - fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + -- this will go away some day + fix("FONTFEATURES", ".;$TEXMF/fonts/{data,fea}//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + fix("FONTCIDMAPS" , ".;$TEXMF/fonts/{data,cid}//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + -- fix("LUATEXLIBS" , ".;$TEXMF/luatex/lua//") end @@ -8396,7 +8519,7 @@ 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] = file.collapse_path(fname) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) @@ -8425,7 +8548,7 @@ 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] = file.collapse_path(fname) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) @@ -8550,7 +8673,7 @@ local weird = lpeg.P(".")^1 + lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,? --~ local l_forbidden = lpeg.S("~`!#$%^&*()={}[]:;\"\'||\\/<>,?\n\r\t") --~ local l_confusing = lpeg.P(" ") ---~ local l_character = lpeg.utf8 +--~ local l_character = lpeg.patterns.utf8 --~ local l_dangerous = lpeg.P(".") --~ local l_normal = (l_character - l_forbidden - l_confusing - l_dangerous) * (l_character - l_forbidden - l_confusing^2)^0 * lpeg.P(-1) @@ -9290,8 +9413,7 @@ 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 = file.collapse_path(filename) -- speed up / beware: format problem if instance.remember then stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -9772,12 +9894,13 @@ end function table.sequenced(t,sep) -- temp here local s = { } for k, v in pairs(t) do -- pairs? - s[#s+1] = k .. "=" .. v + s[#s+1] = k .. "=" .. tostring(v) end return concat(s, sep or " | ") end function resolvers.methodhandler(what, filename, filetype) -- ... + filename = file.collapse_path(filename) local specification = (type(filename) == "string" and resolvers.splitmethod(filename)) or filename -- no or { }, let it bomb local scheme = specification.scheme if resolvers[what][scheme] then diff --git a/scripts/context/stubs/mswin/context.exe b/scripts/context/stubs/mswin/context.exe index 9a67fc133..2d45f2749 100755 Binary files a/scripts/context/stubs/mswin/context.exe and b/scripts/context/stubs/mswin/context.exe differ diff --git a/scripts/context/stubs/mswin/luatools.exe b/scripts/context/stubs/mswin/luatools.exe index 9a67fc133..2d45f2749 100755 Binary files a/scripts/context/stubs/mswin/luatools.exe and b/scripts/context/stubs/mswin/luatools.exe differ diff --git a/scripts/context/stubs/mswin/luatools.lua b/scripts/context/stubs/mswin/luatools.lua index f9b855f74..1a579eb69 100644 --- a/scripts/context/stubs/mswin/luatools.lua +++ b/scripts/context/stubs/mswin/luatools.lua @@ -338,6 +338,8 @@ if not modules then modules = { } end modules ['l-lpeg'] = { lpeg = require("lpeg") +lpeg.patterns = lpeg.patterns or { } -- so that we can share + local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc local match = lpeg.match @@ -488,11 +490,9 @@ end --~ --~ 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 - +lpeg.patterns.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont end -- of closure @@ -1868,6 +1868,7 @@ elseif os.type == "windows" then elseif name == "linux" then function os.resolvers.platform(t,k) + -- we sometims have HOSTTYPE set so let's check that first local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or "" if find(architecture,"x86_64") then platform = "linux-64" @@ -1881,17 +1882,28 @@ elseif name == "linux" then return platform end -elseif name == "macosx" then -- a rather inconsistent mess +elseif name == "macosx" then + + --[[ + Identifying the architecture of OSX is quite a mess and this + is the best we can come up with. For some reason $HOSTTYPE is + a kind of pseudo environment variable, not known to the current + environment. And yes, uname cannot be trusted either, so there + is a change that you end up with a 32 bit run on a 64 bit system. + Also, some proper 64 bit intel macs are too cheap (low-end) and + therefore not permitted to run the 64 bit kernel. + ]]-- function os.resolvers.platform(t,k) - local platform, architecture = "", os.resultof("uname -m") or "" + -- local platform, architecture = "", os.getenv("HOSTTYPE") or "" + -- if architecture == "" then + -- architecture = os.resultof("echo $HOSTTYPE") or "" + -- end + local platform, architecture = "", os.resultof("echo $HOSTTYPE") or "" if architecture == "" then - architecture = os.getenv("HOSTTYPE") or "" - end - if architecture == "" then - architecture = os.resultof("echo $HOSTTYPE") or "" - end - if find(architecture,"i386") then + -- print("\nI have no clue what kind of OSX you're running so let's assume an 32 bit intel.\n") + platform = "osx-intel" + elseif find(architecture,"i386") then platform = "osx-intel" elseif find(architecture,"x86_64") then platform = "osx-64" @@ -1931,6 +1943,21 @@ elseif name == "freebsd" then return platform end +elseif name == "kfreebsd" then + + function os.resolvers.platform(t,k) + -- we sometims have HOSTTYPE set so let's check that first + local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or "" + if find(architecture,"x86_64") then + platform = "kfreebsd-64" + else + platform = "kfreebsd-i386" + end + os.setenv("MTX_PLATFORM",platform) + os.platform = platform + return platform + end + else -- platform = "linux" @@ -1967,6 +1994,21 @@ function os.uuid() ) end +local d + +function os.timezone(delta) + d = d or tonumber(tonumber(os.date("%H")-os.date("!%H"))) + if delta then + if d > 0 then + return format("+%02i:00",d) + else + return format("-%02i:00",-d) + end + else + return 1 + end +end + end -- of closure @@ -1985,7 +2027,7 @@ if not modules then modules = { } end modules ['l-file'] = { file = file or { } local concat = table.concat -local find, gmatch, match, gsub, sub = string.find, string.gmatch, string.match, string.gsub, string.sub +local find, gmatch, match, gsub, sub, char = string.find, string.gmatch, string.match, string.gsub, string.sub, string.char local lpegmatch = lpeg.match function file.removesuffix(filename) @@ -2022,14 +2064,33 @@ end file.suffix = file.extname ---~ print(file.join("x/","/y")) ---~ print(file.join("http://","/y")) ---~ print(file.join("http://a","/y")) ---~ print(file.join("http:///a","/y")) ---~ print(file.join("//nas-1","/y")) +--~ function file.join(...) +--~ local pth = concat({...},"/") +--~ pth = gsub(pth,"\\","/") +--~ local a, b = match(pth,"^(.*://)(.*)$") +--~ if a and b then +--~ return a .. gsub(b,"//+","/") +--~ end +--~ a, b = match(pth,"^(//)(.*)$") +--~ if a and b then +--~ return a .. gsub(b,"//+","/") +--~ end +--~ return (gsub(pth,"//+","/")) +--~ end + +local trick_1 = char(1) +local trick_2 = "^" .. trick_1 .. "/+" function file.join(...) - local pth = concat({...},"/") + local lst = { ... } + local a, b = lst[1], lst[2] + if a == "" then + lst[1] = trick_1 + elseif b and find(a,"^/+$") and find(b,"^/") then + lst[1] = "" + lst[2] = gsub(b,"^/+","") + end + local pth = concat(lst,"/") pth = gsub(pth,"\\","/") local a, b = match(pth,"^(.*://)(.*)$") if a and b then @@ -2039,9 +2100,20 @@ function file.join(...) if a and b then return a .. gsub(b,"//+","/") end + pth = gsub(pth,trick_2,"") return (gsub(pth,"//+","/")) end +--~ print(file.join("//","/y")) +--~ print(file.join("/","/y")) +--~ print(file.join("","/y")) +--~ print(file.join("/x/","/y")) +--~ print(file.join("x/","/y")) +--~ print(file.join("http://","/y")) +--~ print(file.join("http://a","/y")) +--~ print(file.join("http:///a","/y")) +--~ print(file.join("//nas-1","/y")) + function file.iswritable(name) local a = lfs.attributes(name) or lfs.attributes(file.dirname(name,".")) return a and sub(a.permissions,2,2) == "w" @@ -2080,16 +2152,22 @@ function file.join_path(tab) return concat(tab,io.pathseparator) -- can have trailing // end +-- we can hash them weakly + function file.collapse_path(str) - str = gsub(str,"/%./","/") - local n, m = 1, 1 - while n > 0 or m > 0 do - str, n = gsub(str,"[^/%.]+/%.%.$","") - str, m = gsub(str,"[^/%.]+/%.%./","") - end - str = gsub(str,"([^/])/$","%1") - str = gsub(str,"^%./","") - str = gsub(str,"/%.$","") + str = gsub(str,"\\","/") + if find(str,"/") then + str = gsub(str,"^%./",(gsub(lfs.currentdir(),"\\","/")) .. "/") -- ./xx in qualified + str = gsub(str,"/%./","/") + local n, m = 1, 1 + while n > 0 or m > 0 do + str, n = gsub(str,"[^/%.]+/%.%.$","") + str, m = gsub(str,"[^/%.]+/%.%./","") + end + str = gsub(str,"([^/])/$","%1") + -- str = gsub(str,"^%./","") -- ./xx in qualified + str = gsub(str,"/%.$","") + end if str == "" then str = "." end return str end @@ -2391,7 +2469,7 @@ function url.hashed(str) end function url.hasscheme(str) - return not url.split(str).nosheme + return url.split(str)[1] ~= "" end function url.addscheme(str,scheme) @@ -2788,7 +2866,7 @@ else --~ print(dir.mkdirs("///a/b/c")) --~ print(dir.mkdirs("a/bbb//ccc/")) - function dir.expand_name(str) + function dir.expand_name(str) -- will be merged with cleanpath and collapsepath if not find(str,"^/") then str = lfs.currentdir() .. "/" .. str end @@ -3503,6 +3581,8 @@ local stripper = lpeg.Cs((number + 1)^0) --~ lpegmatch(stripper,str) --~ print(#str, os.clock()-ts, lpegmatch(stripper,sample)) +lpeg.patterns.strip_zeros = stripper + function aux.strip_zeros(str) return lpegmatch(stripper,str) end @@ -3789,14 +3869,14 @@ end function setters.enable(t,what) local e = t.enable t.enable, t.done = enable, { } - enable(t,string.simpleesc(what)) + enable(t,string.simpleesc(tostring(what))) t.enable, t.done = e, { } end function setters.disable(t,what) local e = t.disable t.disable, t.done = disable, { } - disable(t,string.simpleesc(what)) + disable(t,string.simpleesc(tostring(what))) t.disable, t.done = e, { } end @@ -3847,13 +3927,15 @@ function setters.new(name) return t end -trackers = setters.new("trackers") -directives = setters.new("directives") +trackers = setters.new("trackers") +directives = setters.new("directives") +experiments = setters.new("experiments") -- 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 trace_directives = false local trace_directives = false trackers.register("system.directives", function(v) trace_directives = v end) +local trace_experiments = false local trace_experiments = false trackers.register("system.experiments", function(v) trace_experiments = v end) local e = directives.enable local d = directives.disable @@ -3868,6 +3950,26 @@ function directives.disable(...) d(...) end +local e = experiments.enable +local d = experiments.disable + +function experiments.enable(...) + commands.writestatus("experiments","enabling: %s",concat({...}," ")) + e(...) +end + +function experiments.disable(...) + commands.writestatus("experiments","disabling: %s",concat({...}," ")) + d(...) +end + +-- a useful example + +directives.register("system.nostatistics", function(v) + statistics.enable = not v +end) + + end -- of closure @@ -4181,6 +4283,14 @@ function statistics.hastimer(instance) return instance and instance.starttime end +function statistics.resettiming(instance) + if not instance then + notimer = { timing = 0, loadtime = 0 } + else + instance.timing, instance.loadtime = 0, 0 + end +end + function statistics.starttiming(instance) if not instance then notimer = { } @@ -4240,6 +4350,12 @@ function statistics.elapsedindeed(instance) return t > statistics.threshold end +function statistics.elapsedseconds(instance,rest) -- returns nil if 0 seconds + if statistics.elapsedindeed(instance) then + return format("%s seconds %s", statistics.elapsedtime(instance),rest or "") + end +end + -- general function function statistics.register(tag,fnc) @@ -4318,6 +4434,23 @@ function statistics.timed(action,report) report("total runtime: %s",statistics.elapsedtime(timer)) end +-- where, not really the best spot for this: + +commands = commands or { } + +local timer + +function commands.resettimer() + statistics.resettiming(timer) + statistics.starttiming(timer) +end + +function commands.elapsedtime() + statistics.stoptiming(timer) + tex.sprint(statistics.elapsedtime(timer)) +end + +commands.resettimer() end -- of closure @@ -4755,8 +4888,8 @@ suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' } alternatives['map files'] = 'map' alternatives['enc files'] = 'enc' -alternatives['cid files'] = 'cid' -alternatives['fea files'] = 'fea' +alternatives['cid maps'] = 'cid' -- great, why no cid files +alternatives['font feature files'] = 'fea' -- and fea files here alternatives['opentype fonts'] = 'otf' alternatives['truetype fonts'] = 'ttf' alternatives['truetype collections'] = 'ttc' @@ -4899,8 +5032,10 @@ local function check_configuration() -- not yet ok, no time for debugging now -- bad luck end fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm - fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") - fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + -- this will go away some day + fix("FONTFEATURES", ".;$TEXMF/fonts/{data,fea}//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + fix("FONTCIDMAPS" , ".;$TEXMF/fonts/{data,cid}//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + -- fix("LUATEXLIBS" , ".;$TEXMF/luatex/lua//") end @@ -5290,7 +5425,7 @@ 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] = file.collapse_path(fname) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) @@ -5319,7 +5454,7 @@ 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] = file.collapse_path(fname) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) @@ -5444,7 +5579,7 @@ local weird = lpeg.P(".")^1 + lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,? --~ local l_forbidden = lpeg.S("~`!#$%^&*()={}[]:;\"\'||\\/<>,?\n\r\t") --~ local l_confusing = lpeg.P(" ") ---~ local l_character = lpeg.utf8 +--~ local l_character = lpeg.patterns.utf8 --~ local l_dangerous = lpeg.P(".") --~ local l_normal = (l_character - l_forbidden - l_confusing - l_dangerous) * (l_character - l_forbidden - l_confusing^2)^0 * lpeg.P(-1) @@ -6184,8 +6319,7 @@ 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 = file.collapse_path(filename) -- speed up / beware: format problem if instance.remember then stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -6666,12 +6800,13 @@ end function table.sequenced(t,sep) -- temp here local s = { } for k, v in pairs(t) do -- pairs? - s[#s+1] = k .. "=" .. v + s[#s+1] = k .. "=" .. tostring(v) end return concat(s, sep or " | ") end function resolvers.methodhandler(what, filename, filetype) -- ... + filename = file.collapse_path(filename) local specification = (type(filename) == "string" and resolvers.splitmethod(filename)) or filename -- no or { }, let it bomb local scheme = specification.scheme if resolvers[what][scheme] then diff --git a/scripts/context/stubs/mswin/metatex.exe b/scripts/context/stubs/mswin/metatex.exe index 9a67fc133..2d45f2749 100755 Binary files a/scripts/context/stubs/mswin/metatex.exe and b/scripts/context/stubs/mswin/metatex.exe differ diff --git a/scripts/context/stubs/mswin/mtxrun.dll b/scripts/context/stubs/mswin/mtxrun.dll index 6af687abe..bb7af56ec 100644 Binary files a/scripts/context/stubs/mswin/mtxrun.dll and b/scripts/context/stubs/mswin/mtxrun.dll differ diff --git a/scripts/context/stubs/mswin/mtxrun.exe b/scripts/context/stubs/mswin/mtxrun.exe index 9a67fc133..2d45f2749 100755 Binary files a/scripts/context/stubs/mswin/mtxrun.exe and b/scripts/context/stubs/mswin/mtxrun.exe differ diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua index 8a2d7a123..ef7eda9b0 100644 --- a/scripts/context/stubs/mswin/mtxrun.lua +++ b/scripts/context/stubs/mswin/mtxrun.lua @@ -347,6 +347,8 @@ if not modules then modules = { } end modules ['l-lpeg'] = { lpeg = require("lpeg") +lpeg.patterns = lpeg.patterns or { } -- so that we can share + local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc local match = lpeg.match @@ -497,11 +499,9 @@ end --~ --~ 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 - +lpeg.patterns.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont end -- of closure @@ -1952,6 +1952,21 @@ elseif name == "freebsd" then return platform end +elseif name == "kfreebsd" then + + function os.resolvers.platform(t,k) + -- we sometims have HOSTTYPE set so let's check that first + local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or "" + if find(architecture,"x86_64") then + platform = "kfreebsd-64" + else + platform = "kfreebsd-i386" + end + os.setenv("MTX_PLATFORM",platform) + os.platform = platform + return platform + end + else -- platform = "linux" @@ -2021,7 +2036,7 @@ if not modules then modules = { } end modules ['l-file'] = { file = file or { } local concat = table.concat -local find, gmatch, match, gsub, sub = string.find, string.gmatch, string.match, string.gsub, string.sub +local find, gmatch, match, gsub, sub, char = string.find, string.gmatch, string.match, string.gsub, string.sub, string.char local lpegmatch = lpeg.match function file.removesuffix(filename) @@ -2058,14 +2073,33 @@ end file.suffix = file.extname ---~ print(file.join("x/","/y")) ---~ print(file.join("http://","/y")) ---~ print(file.join("http://a","/y")) ---~ print(file.join("http:///a","/y")) ---~ print(file.join("//nas-1","/y")) +--~ function file.join(...) +--~ local pth = concat({...},"/") +--~ pth = gsub(pth,"\\","/") +--~ local a, b = match(pth,"^(.*://)(.*)$") +--~ if a and b then +--~ return a .. gsub(b,"//+","/") +--~ end +--~ a, b = match(pth,"^(//)(.*)$") +--~ if a and b then +--~ return a .. gsub(b,"//+","/") +--~ end +--~ return (gsub(pth,"//+","/")) +--~ end + +local trick_1 = char(1) +local trick_2 = "^" .. trick_1 .. "/+" function file.join(...) - local pth = concat({...},"/") + local lst = { ... } + local a, b = lst[1], lst[2] + if a == "" then + lst[1] = trick_1 + elseif b and find(a,"^/+$") and find(b,"^/") then + lst[1] = "" + lst[2] = gsub(b,"^/+","") + end + local pth = concat(lst,"/") pth = gsub(pth,"\\","/") local a, b = match(pth,"^(.*://)(.*)$") if a and b then @@ -2075,9 +2109,20 @@ function file.join(...) if a and b then return a .. gsub(b,"//+","/") end + pth = gsub(pth,trick_2,"") return (gsub(pth,"//+","/")) end +--~ print(file.join("//","/y")) +--~ print(file.join("/","/y")) +--~ print(file.join("","/y")) +--~ print(file.join("/x/","/y")) +--~ print(file.join("x/","/y")) +--~ print(file.join("http://","/y")) +--~ print(file.join("http://a","/y")) +--~ print(file.join("http:///a","/y")) +--~ print(file.join("//nas-1","/y")) + function file.iswritable(name) local a = lfs.attributes(name) or lfs.attributes(file.dirname(name,".")) return a and sub(a.permissions,2,2) == "w" @@ -2116,16 +2161,22 @@ function file.join_path(tab) return concat(tab,io.pathseparator) -- can have trailing // end +-- we can hash them weakly + function file.collapse_path(str) - str = gsub(str,"/%./","/") - local n, m = 1, 1 - while n > 0 or m > 0 do - str, n = gsub(str,"[^/%.]+/%.%.$","") - str, m = gsub(str,"[^/%.]+/%.%./","") - end - str = gsub(str,"([^/])/$","%1") - str = gsub(str,"^%./","") - str = gsub(str,"/%.$","") + str = gsub(str,"\\","/") + if find(str,"/") then + str = gsub(str,"^%./",(gsub(lfs.currentdir(),"\\","/")) .. "/") -- ./xx in qualified + str = gsub(str,"/%./","/") + local n, m = 1, 1 + while n > 0 or m > 0 do + str, n = gsub(str,"[^/%.]+/%.%.$","") + str, m = gsub(str,"[^/%.]+/%.%./","") + end + str = gsub(str,"([^/])/$","%1") + -- str = gsub(str,"^%./","") -- ./xx in qualified + str = gsub(str,"/%.$","") + end if str == "" then str = "." end return str end @@ -2824,7 +2875,7 @@ else --~ print(dir.mkdirs("///a/b/c")) --~ print(dir.mkdirs("a/bbb//ccc/")) - function dir.expand_name(str) + function dir.expand_name(str) -- will be merged with cleanpath and collapsepath if not find(str,"^/") then str = lfs.currentdir() .. "/" .. str end @@ -3340,6 +3391,8 @@ local stripper = lpeg.Cs((number + 1)^0) --~ lpegmatch(stripper,str) --~ print(#str, os.clock()-ts, lpegmatch(stripper,sample)) +lpeg.patterns.strip_zeros = stripper + function aux.strip_zeros(str) return lpegmatch(stripper,str) end @@ -3626,14 +3679,14 @@ end function setters.enable(t,what) local e = t.enable t.enable, t.done = enable, { } - enable(t,string.simpleesc(what)) + enable(t,string.simpleesc(tostring(what))) t.enable, t.done = e, { } end function setters.disable(t,what) local e = t.disable t.disable, t.done = disable, { } - disable(t,string.simpleesc(what)) + disable(t,string.simpleesc(tostring(what))) t.disable, t.done = e, { } end @@ -3720,6 +3773,13 @@ function experiments.disable(...) d(...) end +-- a useful example + +directives.register("system.nostatistics", function(v) + statistics.enable = not v +end) + + end -- of closure @@ -3995,9 +4055,9 @@ local function attribute_specification_error(str) return str end -function xml.unknown_dec_entity_format(str) return format("&%s;", str) end +function xml.unknown_dec_entity_format(str) return (str == "" and "&error;") or format("&%s;",str) end function xml.unknown_hex_entity_format(str) return format("&#x%s;",str) end -function xml.unknown_any_entity_format(str) return format("&%s;", str) end +function xml.unknown_any_entity_format(str) return format("&#x%s;",str) end local function handle_hex_entity(str) local h = hcache[str] @@ -4111,7 +4171,11 @@ local function handle_any_entity(str) if trace_entities then logs.report("xml","keeping entity &%s;",str) end - a = "&" .. str .. ";" + if str == "" then + a = "&error;" + else + a = "&" .. str .. ";" + end end end acache[str] = a @@ -4132,6 +4196,9 @@ local function handle_any_entity(str) if a then -- one of the predefined acache[str] = a + elseif str == "" then + a = "&error;" + acache[str] = a else a = "&" .. str .. ";" acache[str] = a @@ -4460,7 +4527,7 @@ function xml.checkbom(root) -- can be made faster local dt, found = root.dt, false for k=1,#dt do local v = dt[k] - if type(v) == "table" and v.special and v.tg == "@pi" and find(v.dt,"xml.*version=") then + if type(v) == "table" and v.special and v.tg == "@pi@" and find(v.dt[1],"xml.*version=") then found = true break end @@ -4842,6 +4909,8 @@ function xml.assign(dt,k,root) end end +-- the following helpers may move + --[[ldx--

The next helper assigns a tree (or string). Usage:

@@ -4860,6 +4929,22 @@ function xml.tocdata(e,wrapper) e.dt = { t } end +function xml.makestandalone(root) + if root.ri then + local dt = root.dt + for k=1,#dt do + local v = dt[k] + if type(v) == "table" and v.special and v.tg == "@pi@" then + local txt = v.dt[1] + if find(txt,"xml.*version=") then + v.dt[1] = txt .. " standalone='yes'" + break + end + end + end + end +end + end -- of closure @@ -5476,8 +5561,13 @@ local register_initial_child = { kind = "axis", axis = "initial-child" local register_all_nodes = { kind = "nodes", nodetest = true, nodes = { true, false, false } } +local skip = { } + local function errorrunner_e(str,cnv) - logs.report("lpath","error in expression: %s => %s",str,cnv) + if not skip[str] then + logs.report("lpath","error in expression: %s => %s",str,cnv) + skip[str] = cnv or str + end return false end local function errorrunner_f(str,arg) @@ -7287,6 +7377,14 @@ function statistics.hastimer(instance) return instance and instance.starttime end +function statistics.resettiming(instance) + if not instance then + notimer = { timing = 0, loadtime = 0 } + else + instance.timing, instance.loadtime = 0, 0 + end +end + function statistics.starttiming(instance) if not instance then notimer = { } @@ -7346,6 +7444,12 @@ function statistics.elapsedindeed(instance) return t > statistics.threshold end +function statistics.elapsedseconds(instance,rest) -- returns nil if 0 seconds + if statistics.elapsedindeed(instance) then + return format("%s seconds %s", statistics.elapsedtime(instance),rest or "") + end +end + -- general function function statistics.register(tag,fnc) @@ -7424,6 +7528,23 @@ function statistics.timed(action,report) report("total runtime: %s",statistics.elapsedtime(timer)) end +-- where, not really the best spot for this: + +commands = commands or { } + +local timer + +function commands.resettimer() + statistics.resettiming(timer) + statistics.starttiming(timer) +end + +function commands.elapsedtime() + statistics.stoptiming(timer) + tex.sprint(statistics.elapsedtime(timer)) +end + +commands.resettimer() end -- of closure @@ -7861,8 +7982,8 @@ suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' } alternatives['map files'] = 'map' alternatives['enc files'] = 'enc' -alternatives['cid files'] = 'cid' -alternatives['fea files'] = 'fea' +alternatives['cid maps'] = 'cid' -- great, why no cid files +alternatives['font feature files'] = 'fea' -- and fea files here alternatives['opentype fonts'] = 'otf' alternatives['truetype fonts'] = 'ttf' alternatives['truetype collections'] = 'ttc' @@ -8005,8 +8126,10 @@ local function check_configuration() -- not yet ok, no time for debugging now -- bad luck end fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm - fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") - fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + -- this will go away some day + fix("FONTFEATURES", ".;$TEXMF/fonts/{data,fea}//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + fix("FONTCIDMAPS" , ".;$TEXMF/fonts/{data,cid}//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + -- fix("LUATEXLIBS" , ".;$TEXMF/luatex/lua//") end @@ -8396,7 +8519,7 @@ 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] = file.collapse_path(fname) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) @@ -8425,7 +8548,7 @@ 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] = file.collapse_path(fname) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) @@ -8550,7 +8673,7 @@ local weird = lpeg.P(".")^1 + lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,? --~ local l_forbidden = lpeg.S("~`!#$%^&*()={}[]:;\"\'||\\/<>,?\n\r\t") --~ local l_confusing = lpeg.P(" ") ---~ local l_character = lpeg.utf8 +--~ local l_character = lpeg.patterns.utf8 --~ local l_dangerous = lpeg.P(".") --~ local l_normal = (l_character - l_forbidden - l_confusing - l_dangerous) * (l_character - l_forbidden - l_confusing^2)^0 * lpeg.P(-1) @@ -9290,8 +9413,7 @@ 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 = file.collapse_path(filename) -- speed up / beware: format problem if instance.remember then stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -9772,12 +9894,13 @@ end function table.sequenced(t,sep) -- temp here local s = { } for k, v in pairs(t) do -- pairs? - s[#s+1] = k .. "=" .. v + s[#s+1] = k .. "=" .. tostring(v) end return concat(s, sep or " | ") end function resolvers.methodhandler(what, filename, filetype) -- ... + filename = file.collapse_path(filename) local specification = (type(filename) == "string" and resolvers.splitmethod(filename)) or filename -- no or { }, let it bomb local scheme = specification.scheme if resolvers[what][scheme] then diff --git a/scripts/context/stubs/mswin/texexec.exe b/scripts/context/stubs/mswin/texexec.exe index 9a67fc133..2d45f2749 100755 Binary files a/scripts/context/stubs/mswin/texexec.exe and b/scripts/context/stubs/mswin/texexec.exe differ diff --git a/scripts/context/stubs/mswin/texmfstart.exe b/scripts/context/stubs/mswin/texmfstart.exe index 9a67fc133..2d45f2749 100755 Binary files a/scripts/context/stubs/mswin/texmfstart.exe and b/scripts/context/stubs/mswin/texmfstart.exe differ diff --git a/scripts/context/stubs/source/mtxrun_dll.c b/scripts/context/stubs/source/mtxrun_dll.c index 6cac18c9b..9836c2ac5 100644 --- a/scripts/context/stubs/source/mtxrun_dll.c +++ b/scripts/context/stubs/source/mtxrun_dll.c @@ -1,214 +1,207 @@ -/* +/************************************************************************ -Copyright: + Copyright: -The originally 'runscript' program was written by in 2009 by -T.M.Trzeciak and is public domain. This derived mtxrun program -is an adapted version by Hans Hagen. + Public Domain + Originally written in 2010 by Tomasz M. Trzeciak and Hans Hagen -Comment: + This program is derived from the 'runscript' program originally + written in 2009 by T.M. Trzeciak. It has been adapted for use in + ConTeXt MkIV. -In ConTeXt MkIV we have two core scripts: luatools.lua and -mtxrun.lua where the second one is used to launch other scripts. -Normally a user will use a call like: + Comment: -mtxrun --script font --reload + In ConTeXt MkIV we have two core scripts: luatools.lua and + mtxrun.lua where the second one is used to launch other scripts. + Normally a user will use a call like: -Here mtxrun is a lua script. In order to avoid the usage of a cmd -file on windows this runner will start texlua directly. In TeXlive -a runner is added for each cmd file but we don't want that overhead -(and extra files). By using an exe we can call these scripts in -batch files without the need for using call. + mtxrun --script font --reload -We also don't want to use other runners, like those that use kpse -to locate the script as this is exactly what mtxrun itself is doing -already. Therefore the runscript program is adapted to a more direct -approach suitable for mtxrun. + Here mtxrun is a lua script. In order to avoid the usage of a cmd + file on windows this runner will start texlua directly. If the + shared library luatex.dll is available, texlua will be started in + the same process avoiding thus any additional overhead. Otherwise + it will be spawned in a new proces. -Compilation: + We also don't want to use other runners, like those that use kpse + to locate the script as this is exactly what mtxrun itself is doing + already. Therefore the runscript program is adapted to a more direct + approach suitable for mtxrun. -with gcc (size optimized): + Compilation: -gcc -Os -s -shared -o mtxrun.dll mtxrun_dll.c -gcc -Os -s -o mtxrun.exe mtxrun_exe.c -L./ -lmtxrun + with gcc (size optimized): -with tcc (ver. 0.9.24), extra small size + gcc -Os -s -shared -o mtxrun.dll mtxrun_dll.c + gcc -Os -s -o mtxrun.exe mtxrun_exe.c -tcc -shared -o runscript.dll runscript_dll.c -tcc -o runscript.exe runscript_exe.c runscript.def + with tcc (extra small size): -*/ + tcc -shared -o mtxrun.dll mtxrun_dll.c + tcc -o mtxrun.exe mtxrun_exe.c mtxrun.def + +************************************************************************/ -#include #include +#include +#include +//#define STATIC #define IS_WHITESPACE(c) ((c == ' ') || (c == '\t')) #define MAX_CMD 32768 -//~ #define DRYRUN +#define DIE(...) { \ + fprintf( stderr, "mtxrun: " ); \ + fprintf( stderr, __VA_ARGS__ ); \ + return 1; \ +} -static char dirname [MAX_PATH]; -static char basename[MAX_PATH]; +char texlua_name[] = "texlua"; // just a bare name, luatex strips the rest anyway +static char cmdline[MAX_CMD]; +static char dirpath[MAX_PATH]; static char progname[MAX_PATH]; -static char cmdline [MAX_CMD]; - -__declspec(dllexport) int dllrunscript( int argc, char *argv[] ) { - - int i; - - static char path[MAX_PATH]; - - // get file name of this executable and split it into parts - - DWORD nchars = GetModuleFileNameA(NULL, path, MAX_PATH); - if ( !nchars || (nchars == MAX_PATH) ) { - fprintf(stderr, "mtxrun: unable to determine a valid own name\n"); - return -1; - } - - // file extension part - - i = strlen(path); - - while ( i && (path[i] != '.') && (path[i] != '\\') ) i--; - - strcpy(basename, path); - - if ( basename[i] == '.' ) basename[i] = '\0'; //remove file extension - - // file name part - - while ( i && (path[i] != '\\') ) i--; - - if ( path[i] != '\\' ) { - fprintf(stderr, "mtxrun: the runner has no directory part in its name: %s\n", path); - return -1; - } - - strcpy(dirname, path); - dirname[i+1] = '\0'; //remove file name, leave trailing backslash - strcpy(progname, &basename[i+1]); - - // find program to execute - - if ( (strlen(basename)+100 >= MAX_PATH) ) { - fprintf(stderr, "mtxrun: the runners path is too long: %s\n", path); - return -1; - } - - // check .lua - - strcpy(path, dirname); - strcat(path, "mtxrun.lua"); - - if ( GetFileAttributesA(path) != INVALID_FILE_ATTRIBUTES ) { - goto PROGRAM_FOUND; - } else { - fprintf(stderr, "mtxrun: the mtxrun.lua file is not in the same path\n"); - return -1; - } - -PROGRAM_FOUND: - - strcpy(cmdline,"texlua.exe "); - - if ( ( strcmp(progname,"mtxrun") == 0 ) || ( strcmp(progname,"luatools") == 0 ) ) { - strcat(cmdline, dirname); - strcat(cmdline,progname); - strcat(cmdline, ".lua"); - } else if ( ( strcmp(progname,"texmfstart") == 0 ) ) { - strcat(cmdline, dirname); - strcat(cmdline,"mtxrun.lua"); - } else { - strcat(cmdline, dirname); - strcat(cmdline, "mtxrun.lua --script "); - strcat(cmdline,progname); - } - - // get the command line for this process - - char *argstr; - argstr = GetCommandLineA(); - if ( argstr == NULL ) { - fprintf(stderr, "mtxrun: fetching the command line string fails\n"); - return -1; +static char scriptpath[MAX_PATH]; +HMODULE dllluatex = NULL; +typedef int ( *mainlikeproc )( int, char ** ); + +#ifdef STATIC +int main( int argc, char *argv[] ) +#else +__declspec(dllexport) int dllrunscript( int argc, char *argv[] ) +#endif +{ + char *s, *argstr, **lua_argv; + int k, quoted, lua_argc; + int passprogname = 0; + + // directory of this module/executable + + HMODULE module_handle = GetModuleHandle( "mtxrun.dll" ); + // if ( module_handle == NULL ) exe path will be used, which is OK too + k = (int) GetModuleFileName( module_handle, dirpath, MAX_PATH ); + if ( !k || ( k == MAX_PATH ) ) + DIE( "unable to determine a valid module name\n" ); + s = strrchr(dirpath, '\\'); + if ( s == NULL ) DIE( "no directory part in module path: %s\n", dirpath ); + *(++s) = '\0'; //remove file name, leave trailing backslash + + // program name + + k = strlen(argv[0]); + while ( k && (argv[0][k] != '/') && (argv[0][k] != '\\') ) k--; + strcpy(progname, &argv[0][k]); + s = progname; + if ( s = strrchr(s, '.') ) *s = '\0'; // remove file extension part + + // script path + + strcpy( scriptpath, dirpath ); + k = strlen(progname); + if ( k < 6 ) k = 6; // in case the program name is shorter than "mtxrun" + if ( strlen(dirpath) + k + 4 >= MAX_PATH ) + DIE( "path too long: %s%s\n", dirpath, progname ); + if ( ( strcmpi(progname,"mtxrun") == 0 ) || ( strcmpi(progname,"luatools") == 0 ) ) { + strcat( scriptpath, progname ); + strcat( scriptpath, ".lua" ); + } else { + strcat( scriptpath, "mtxrun.lua" ); + if ( strcmpi(progname,"texmfstart") != 0 ) passprogname = 1; + } + if ( GetFileAttributes(scriptpath) == INVALID_FILE_ATTRIBUTES ) + DIE( "file not found: %s\n", scriptpath ); + + // link with luatex.dll if available + + if ( dllluatex = LoadLibrary("luatex.dll") ) + { + mainlikeproc dllluatexmain = (mainlikeproc) GetProcAddress( dllluatex, "dllluatexmain" ); + if ( dllluatexmain == NULL ) + DIE( "unable to locate dllluatexmain procedure in luatex.dll" ); + + // set up argument list for texlua script + + lua_argv = (char **)malloc( (argc + 4) * sizeof(char *) ); + if ( lua_argv == NULL ) DIE( "out of memory\n" ); + lua_argv[lua_argc=0] = texlua_name; + lua_argv[++lua_argc] = scriptpath; // script to execute + if (passprogname) { + lua_argv[++lua_argc] = "--script"; + lua_argv[++lua_argc] = progname; } + for ( k = 1; k < argc; k++ ) lua_argv[++lua_argc] = argv[k]; + lua_argv[++lua_argc] = NULL; - // skip over argv[0] (it can contain embedded double quotes if launched from cmd.exe!) + // call texlua interpreter + // dllluatexmain never returns, but we pretend that it does - int argstrlen = strlen(argstr); - int quoted = 0; - for ( i = 0; ( i < argstrlen) && ( !IS_WHITESPACE(argstr[i]) || quoted ); i++ ) + k = dllluatexmain( lua_argc, lua_argv ); + if (lua_argv) free( lua_argv ); + return k; + } - if (argstr[i] == '"') quoted = !quoted; + // we are still here, so no luatex.dll; spawn texlua.exe instead - // while ( IS_WHITESPACE(argstr[i]) ) i++; // arguments leading whitespace + strcpy( cmdline, "\"" ); +// strcat( cmdline, dirpath ); + strcat( cmdline, "texlua.exe\" \"" ); + strcat( cmdline, scriptpath ); + strcat( cmdline, "\"" ); + if (passprogname) { + strcat( cmdline, " --script " ); + strcat( cmdline, progname ); + } - argstr = &argstr[i]; + argstr = GetCommandLine(); // get the command line of this process + if ( argstr == NULL ) DIE( "unable to retrieve the command line string\n" ); - if ( strlen(cmdline) + strlen(argstr) >= MAX_CMD ) { - fprintf(stderr, "mtxrun: the command line string is too long:\n%s%s\n", cmdline, argstr); - return -1; - } + // skip over argv[0] in the argument string + // (it can contain embedded double quotes if launched from cmd.exe!) - // pass through all the arguments + for ( quoted = 0; (*argstr) && ( !IS_WHITESPACE(*argstr) || quoted ); argstr++ ) + if (*argstr == '"') quoted = !quoted; - strcat(cmdline, argstr); + // pass through all the arguments -#ifdef DRYRUN - printf("progname : %s\n", progname); - printf("dirname : %s\n", dirname); - printf("arguments : %s\n", &argstr[-i]); - for (i = 0; i < argc; i++) { - printf("argv[%d] : %s\n", i, argv[i]); - } - printf("commandline : %s\n", cmdline); - return; -#endif + if ( strlen(cmdline) + strlen(argstr) >= MAX_CMD ) + DIE( "command line string too long:\n%s%s\n", cmdline, argstr ); + strcat( cmdline, argstr ); - // create child process + // create child process - STARTUPINFOA si; // ANSI variant - PROCESS_INFORMATION pi; - ZeroMemory( &si, sizeof(si) ); - si.cb = sizeof(si); + STARTUPINFO si; + PROCESS_INFORMATION pi; + ZeroMemory( &si, sizeof(si) ); + si.cb = sizeof(si); si.dwFlags = STARTF_USESTDHANDLES;// | STARTF_USESHOWWINDOW; - //si.dwFlags = STARTF_USESHOWWINDOW; //si.wShowWindow = SW_HIDE ; // can be used to hide console window (requires STARTF_USESHOWWINDOW flag) - - si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); - si.hStdError = GetStdHandle(STD_ERROR_HANDLE); - - ZeroMemory( &pi, sizeof(pi) ); - if( !CreateProcessA( - NULL, // module name (uses command line if NULL) - cmdline, // command line - NULL, // process security attributes - NULL, // thread security attributes - TRUE, // handle inheritance - 0, // creation flags, e.g. CREATE_NEW_CONSOLE, CREATE_NO_WINDOW, DETACHED_PROCESS - NULL, // pointer to environment block (uses parent if NULL) - NULL, // starting directory (uses parent if NULL) - &si, // STARTUPINFO structure - &pi ) // PROCESS_INFORMATION structure - ) { - fprintf(stderr, "mtxrun: unable to create a process for: %s\n", cmdline); - return -1; - } - CloseHandle( pi.hThread ); // thread handle is not needed - DWORD ret = 0; - if ( WaitForSingleObject( pi.hProcess, INFINITE ) == WAIT_OBJECT_0 ) { - if ( !GetExitCodeProcess( pi.hProcess, &ret) ) { - fprintf(stderr, "mtxrun: unable to fetch the exit code for process: %s\n", cmdline); - return -1; - } - } else { - fprintf(stderr, "mtxrun: the script has been terminated unexpectedly: %s\n", cmdline); - return -1; - } - CloseHandle( pi.hProcess ); - - return ret; + si.hStdInput = GetStdHandle( STD_INPUT_HANDLE ); + si.hStdOutput = GetStdHandle( STD_OUTPUT_HANDLE ); + si.hStdError = GetStdHandle( STD_ERROR_HANDLE ); + ZeroMemory( &pi, sizeof(pi) ); + + if( !CreateProcess( + NULL, // module name (uses command line if NULL) + cmdline, // command line + NULL, // process security atrributes + NULL, // thread security atrributes + TRUE, // handle inheritance + 0, // creation flags, e.g. CREATE_NEW_CONSOLE, CREATE_NO_WINDOW, DETACHED_PROCESS + NULL, // pointer to environment block (uses parent if NULL) + NULL, // starting directory (uses parent if NULL) + &si, // STARTUPINFO structure + &pi ) // PROCESS_INFORMATION structure + ) DIE( "command execution failed: %s\n", cmdline ); + + DWORD ret = 0; + CloseHandle( pi.hThread ); // thread handle is not needed + if ( WaitForSingleObject( pi.hProcess, INFINITE ) == WAIT_OBJECT_0 ) { + if ( !GetExitCodeProcess( pi.hProcess, &ret) ) + DIE( "unable to retrieve process exit code: %s\n", cmdline ); + } else DIE( "failed to wait for process termination: %s\n", cmdline ); + CloseHandle( pi.hProcess ); + + // propagate exit code from the child process + + return ret; } diff --git a/scripts/context/stubs/unix/luatools b/scripts/context/stubs/unix/luatools index f9b855f74..1a579eb69 100755 --- a/scripts/context/stubs/unix/luatools +++ b/scripts/context/stubs/unix/luatools @@ -338,6 +338,8 @@ if not modules then modules = { } end modules ['l-lpeg'] = { lpeg = require("lpeg") +lpeg.patterns = lpeg.patterns or { } -- so that we can share + local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc local match = lpeg.match @@ -488,11 +490,9 @@ end --~ --~ 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 - +lpeg.patterns.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont end -- of closure @@ -1868,6 +1868,7 @@ elseif os.type == "windows" then elseif name == "linux" then function os.resolvers.platform(t,k) + -- we sometims have HOSTTYPE set so let's check that first local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or "" if find(architecture,"x86_64") then platform = "linux-64" @@ -1881,17 +1882,28 @@ elseif name == "linux" then return platform end -elseif name == "macosx" then -- a rather inconsistent mess +elseif name == "macosx" then + + --[[ + Identifying the architecture of OSX is quite a mess and this + is the best we can come up with. For some reason $HOSTTYPE is + a kind of pseudo environment variable, not known to the current + environment. And yes, uname cannot be trusted either, so there + is a change that you end up with a 32 bit run on a 64 bit system. + Also, some proper 64 bit intel macs are too cheap (low-end) and + therefore not permitted to run the 64 bit kernel. + ]]-- function os.resolvers.platform(t,k) - local platform, architecture = "", os.resultof("uname -m") or "" + -- local platform, architecture = "", os.getenv("HOSTTYPE") or "" + -- if architecture == "" then + -- architecture = os.resultof("echo $HOSTTYPE") or "" + -- end + local platform, architecture = "", os.resultof("echo $HOSTTYPE") or "" if architecture == "" then - architecture = os.getenv("HOSTTYPE") or "" - end - if architecture == "" then - architecture = os.resultof("echo $HOSTTYPE") or "" - end - if find(architecture,"i386") then + -- print("\nI have no clue what kind of OSX you're running so let's assume an 32 bit intel.\n") + platform = "osx-intel" + elseif find(architecture,"i386") then platform = "osx-intel" elseif find(architecture,"x86_64") then platform = "osx-64" @@ -1931,6 +1943,21 @@ elseif name == "freebsd" then return platform end +elseif name == "kfreebsd" then + + function os.resolvers.platform(t,k) + -- we sometims have HOSTTYPE set so let's check that first + local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or "" + if find(architecture,"x86_64") then + platform = "kfreebsd-64" + else + platform = "kfreebsd-i386" + end + os.setenv("MTX_PLATFORM",platform) + os.platform = platform + return platform + end + else -- platform = "linux" @@ -1967,6 +1994,21 @@ function os.uuid() ) end +local d + +function os.timezone(delta) + d = d or tonumber(tonumber(os.date("%H")-os.date("!%H"))) + if delta then + if d > 0 then + return format("+%02i:00",d) + else + return format("-%02i:00",-d) + end + else + return 1 + end +end + end -- of closure @@ -1985,7 +2027,7 @@ if not modules then modules = { } end modules ['l-file'] = { file = file or { } local concat = table.concat -local find, gmatch, match, gsub, sub = string.find, string.gmatch, string.match, string.gsub, string.sub +local find, gmatch, match, gsub, sub, char = string.find, string.gmatch, string.match, string.gsub, string.sub, string.char local lpegmatch = lpeg.match function file.removesuffix(filename) @@ -2022,14 +2064,33 @@ end file.suffix = file.extname ---~ print(file.join("x/","/y")) ---~ print(file.join("http://","/y")) ---~ print(file.join("http://a","/y")) ---~ print(file.join("http:///a","/y")) ---~ print(file.join("//nas-1","/y")) +--~ function file.join(...) +--~ local pth = concat({...},"/") +--~ pth = gsub(pth,"\\","/") +--~ local a, b = match(pth,"^(.*://)(.*)$") +--~ if a and b then +--~ return a .. gsub(b,"//+","/") +--~ end +--~ a, b = match(pth,"^(//)(.*)$") +--~ if a and b then +--~ return a .. gsub(b,"//+","/") +--~ end +--~ return (gsub(pth,"//+","/")) +--~ end + +local trick_1 = char(1) +local trick_2 = "^" .. trick_1 .. "/+" function file.join(...) - local pth = concat({...},"/") + local lst = { ... } + local a, b = lst[1], lst[2] + if a == "" then + lst[1] = trick_1 + elseif b and find(a,"^/+$") and find(b,"^/") then + lst[1] = "" + lst[2] = gsub(b,"^/+","") + end + local pth = concat(lst,"/") pth = gsub(pth,"\\","/") local a, b = match(pth,"^(.*://)(.*)$") if a and b then @@ -2039,9 +2100,20 @@ function file.join(...) if a and b then return a .. gsub(b,"//+","/") end + pth = gsub(pth,trick_2,"") return (gsub(pth,"//+","/")) end +--~ print(file.join("//","/y")) +--~ print(file.join("/","/y")) +--~ print(file.join("","/y")) +--~ print(file.join("/x/","/y")) +--~ print(file.join("x/","/y")) +--~ print(file.join("http://","/y")) +--~ print(file.join("http://a","/y")) +--~ print(file.join("http:///a","/y")) +--~ print(file.join("//nas-1","/y")) + function file.iswritable(name) local a = lfs.attributes(name) or lfs.attributes(file.dirname(name,".")) return a and sub(a.permissions,2,2) == "w" @@ -2080,16 +2152,22 @@ function file.join_path(tab) return concat(tab,io.pathseparator) -- can have trailing // end +-- we can hash them weakly + function file.collapse_path(str) - str = gsub(str,"/%./","/") - local n, m = 1, 1 - while n > 0 or m > 0 do - str, n = gsub(str,"[^/%.]+/%.%.$","") - str, m = gsub(str,"[^/%.]+/%.%./","") - end - str = gsub(str,"([^/])/$","%1") - str = gsub(str,"^%./","") - str = gsub(str,"/%.$","") + str = gsub(str,"\\","/") + if find(str,"/") then + str = gsub(str,"^%./",(gsub(lfs.currentdir(),"\\","/")) .. "/") -- ./xx in qualified + str = gsub(str,"/%./","/") + local n, m = 1, 1 + while n > 0 or m > 0 do + str, n = gsub(str,"[^/%.]+/%.%.$","") + str, m = gsub(str,"[^/%.]+/%.%./","") + end + str = gsub(str,"([^/])/$","%1") + -- str = gsub(str,"^%./","") -- ./xx in qualified + str = gsub(str,"/%.$","") + end if str == "" then str = "." end return str end @@ -2391,7 +2469,7 @@ function url.hashed(str) end function url.hasscheme(str) - return not url.split(str).nosheme + return url.split(str)[1] ~= "" end function url.addscheme(str,scheme) @@ -2788,7 +2866,7 @@ else --~ print(dir.mkdirs("///a/b/c")) --~ print(dir.mkdirs("a/bbb//ccc/")) - function dir.expand_name(str) + function dir.expand_name(str) -- will be merged with cleanpath and collapsepath if not find(str,"^/") then str = lfs.currentdir() .. "/" .. str end @@ -3503,6 +3581,8 @@ local stripper = lpeg.Cs((number + 1)^0) --~ lpegmatch(stripper,str) --~ print(#str, os.clock()-ts, lpegmatch(stripper,sample)) +lpeg.patterns.strip_zeros = stripper + function aux.strip_zeros(str) return lpegmatch(stripper,str) end @@ -3789,14 +3869,14 @@ end function setters.enable(t,what) local e = t.enable t.enable, t.done = enable, { } - enable(t,string.simpleesc(what)) + enable(t,string.simpleesc(tostring(what))) t.enable, t.done = e, { } end function setters.disable(t,what) local e = t.disable t.disable, t.done = disable, { } - disable(t,string.simpleesc(what)) + disable(t,string.simpleesc(tostring(what))) t.disable, t.done = e, { } end @@ -3847,13 +3927,15 @@ function setters.new(name) return t end -trackers = setters.new("trackers") -directives = setters.new("directives") +trackers = setters.new("trackers") +directives = setters.new("directives") +experiments = setters.new("experiments") -- 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 trace_directives = false local trace_directives = false trackers.register("system.directives", function(v) trace_directives = v end) +local trace_experiments = false local trace_experiments = false trackers.register("system.experiments", function(v) trace_experiments = v end) local e = directives.enable local d = directives.disable @@ -3868,6 +3950,26 @@ function directives.disable(...) d(...) end +local e = experiments.enable +local d = experiments.disable + +function experiments.enable(...) + commands.writestatus("experiments","enabling: %s",concat({...}," ")) + e(...) +end + +function experiments.disable(...) + commands.writestatus("experiments","disabling: %s",concat({...}," ")) + d(...) +end + +-- a useful example + +directives.register("system.nostatistics", function(v) + statistics.enable = not v +end) + + end -- of closure @@ -4181,6 +4283,14 @@ function statistics.hastimer(instance) return instance and instance.starttime end +function statistics.resettiming(instance) + if not instance then + notimer = { timing = 0, loadtime = 0 } + else + instance.timing, instance.loadtime = 0, 0 + end +end + function statistics.starttiming(instance) if not instance then notimer = { } @@ -4240,6 +4350,12 @@ function statistics.elapsedindeed(instance) return t > statistics.threshold end +function statistics.elapsedseconds(instance,rest) -- returns nil if 0 seconds + if statistics.elapsedindeed(instance) then + return format("%s seconds %s", statistics.elapsedtime(instance),rest or "") + end +end + -- general function function statistics.register(tag,fnc) @@ -4318,6 +4434,23 @@ function statistics.timed(action,report) report("total runtime: %s",statistics.elapsedtime(timer)) end +-- where, not really the best spot for this: + +commands = commands or { } + +local timer + +function commands.resettimer() + statistics.resettiming(timer) + statistics.starttiming(timer) +end + +function commands.elapsedtime() + statistics.stoptiming(timer) + tex.sprint(statistics.elapsedtime(timer)) +end + +commands.resettimer() end -- of closure @@ -4755,8 +4888,8 @@ suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' } alternatives['map files'] = 'map' alternatives['enc files'] = 'enc' -alternatives['cid files'] = 'cid' -alternatives['fea files'] = 'fea' +alternatives['cid maps'] = 'cid' -- great, why no cid files +alternatives['font feature files'] = 'fea' -- and fea files here alternatives['opentype fonts'] = 'otf' alternatives['truetype fonts'] = 'ttf' alternatives['truetype collections'] = 'ttc' @@ -4899,8 +5032,10 @@ local function check_configuration() -- not yet ok, no time for debugging now -- bad luck end fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm - fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") - fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + -- this will go away some day + fix("FONTFEATURES", ".;$TEXMF/fonts/{data,fea}//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + fix("FONTCIDMAPS" , ".;$TEXMF/fonts/{data,cid}//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + -- fix("LUATEXLIBS" , ".;$TEXMF/luatex/lua//") end @@ -5290,7 +5425,7 @@ 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] = file.collapse_path(fname) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) @@ -5319,7 +5454,7 @@ 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] = file.collapse_path(fname) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) @@ -5444,7 +5579,7 @@ local weird = lpeg.P(".")^1 + lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,? --~ local l_forbidden = lpeg.S("~`!#$%^&*()={}[]:;\"\'||\\/<>,?\n\r\t") --~ local l_confusing = lpeg.P(" ") ---~ local l_character = lpeg.utf8 +--~ local l_character = lpeg.patterns.utf8 --~ local l_dangerous = lpeg.P(".") --~ local l_normal = (l_character - l_forbidden - l_confusing - l_dangerous) * (l_character - l_forbidden - l_confusing^2)^0 * lpeg.P(-1) @@ -6184,8 +6319,7 @@ 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 = file.collapse_path(filename) -- speed up / beware: format problem if instance.remember then stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -6666,12 +6800,13 @@ end function table.sequenced(t,sep) -- temp here local s = { } for k, v in pairs(t) do -- pairs? - s[#s+1] = k .. "=" .. v + s[#s+1] = k .. "=" .. tostring(v) end return concat(s, sep or " | ") end function resolvers.methodhandler(what, filename, filetype) -- ... + filename = file.collapse_path(filename) local specification = (type(filename) == "string" and resolvers.splitmethod(filename)) or filename -- no or { }, let it bomb local scheme = specification.scheme if resolvers[what][scheme] then diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun index 8a2d7a123..ef7eda9b0 100755 --- a/scripts/context/stubs/unix/mtxrun +++ b/scripts/context/stubs/unix/mtxrun @@ -347,6 +347,8 @@ if not modules then modules = { } end modules ['l-lpeg'] = { lpeg = require("lpeg") +lpeg.patterns = lpeg.patterns or { } -- so that we can share + local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc local match = lpeg.match @@ -497,11 +499,9 @@ end --~ --~ 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 - +lpeg.patterns.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont end -- of closure @@ -1952,6 +1952,21 @@ elseif name == "freebsd" then return platform end +elseif name == "kfreebsd" then + + function os.resolvers.platform(t,k) + -- we sometims have HOSTTYPE set so let's check that first + local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or "" + if find(architecture,"x86_64") then + platform = "kfreebsd-64" + else + platform = "kfreebsd-i386" + end + os.setenv("MTX_PLATFORM",platform) + os.platform = platform + return platform + end + else -- platform = "linux" @@ -2021,7 +2036,7 @@ if not modules then modules = { } end modules ['l-file'] = { file = file or { } local concat = table.concat -local find, gmatch, match, gsub, sub = string.find, string.gmatch, string.match, string.gsub, string.sub +local find, gmatch, match, gsub, sub, char = string.find, string.gmatch, string.match, string.gsub, string.sub, string.char local lpegmatch = lpeg.match function file.removesuffix(filename) @@ -2058,14 +2073,33 @@ end file.suffix = file.extname ---~ print(file.join("x/","/y")) ---~ print(file.join("http://","/y")) ---~ print(file.join("http://a","/y")) ---~ print(file.join("http:///a","/y")) ---~ print(file.join("//nas-1","/y")) +--~ function file.join(...) +--~ local pth = concat({...},"/") +--~ pth = gsub(pth,"\\","/") +--~ local a, b = match(pth,"^(.*://)(.*)$") +--~ if a and b then +--~ return a .. gsub(b,"//+","/") +--~ end +--~ a, b = match(pth,"^(//)(.*)$") +--~ if a and b then +--~ return a .. gsub(b,"//+","/") +--~ end +--~ return (gsub(pth,"//+","/")) +--~ end + +local trick_1 = char(1) +local trick_2 = "^" .. trick_1 .. "/+" function file.join(...) - local pth = concat({...},"/") + local lst = { ... } + local a, b = lst[1], lst[2] + if a == "" then + lst[1] = trick_1 + elseif b and find(a,"^/+$") and find(b,"^/") then + lst[1] = "" + lst[2] = gsub(b,"^/+","") + end + local pth = concat(lst,"/") pth = gsub(pth,"\\","/") local a, b = match(pth,"^(.*://)(.*)$") if a and b then @@ -2075,9 +2109,20 @@ function file.join(...) if a and b then return a .. gsub(b,"//+","/") end + pth = gsub(pth,trick_2,"") return (gsub(pth,"//+","/")) end +--~ print(file.join("//","/y")) +--~ print(file.join("/","/y")) +--~ print(file.join("","/y")) +--~ print(file.join("/x/","/y")) +--~ print(file.join("x/","/y")) +--~ print(file.join("http://","/y")) +--~ print(file.join("http://a","/y")) +--~ print(file.join("http:///a","/y")) +--~ print(file.join("//nas-1","/y")) + function file.iswritable(name) local a = lfs.attributes(name) or lfs.attributes(file.dirname(name,".")) return a and sub(a.permissions,2,2) == "w" @@ -2116,16 +2161,22 @@ function file.join_path(tab) return concat(tab,io.pathseparator) -- can have trailing // end +-- we can hash them weakly + function file.collapse_path(str) - str = gsub(str,"/%./","/") - local n, m = 1, 1 - while n > 0 or m > 0 do - str, n = gsub(str,"[^/%.]+/%.%.$","") - str, m = gsub(str,"[^/%.]+/%.%./","") - end - str = gsub(str,"([^/])/$","%1") - str = gsub(str,"^%./","") - str = gsub(str,"/%.$","") + str = gsub(str,"\\","/") + if find(str,"/") then + str = gsub(str,"^%./",(gsub(lfs.currentdir(),"\\","/")) .. "/") -- ./xx in qualified + str = gsub(str,"/%./","/") + local n, m = 1, 1 + while n > 0 or m > 0 do + str, n = gsub(str,"[^/%.]+/%.%.$","") + str, m = gsub(str,"[^/%.]+/%.%./","") + end + str = gsub(str,"([^/])/$","%1") + -- str = gsub(str,"^%./","") -- ./xx in qualified + str = gsub(str,"/%.$","") + end if str == "" then str = "." end return str end @@ -2824,7 +2875,7 @@ else --~ print(dir.mkdirs("///a/b/c")) --~ print(dir.mkdirs("a/bbb//ccc/")) - function dir.expand_name(str) + function dir.expand_name(str) -- will be merged with cleanpath and collapsepath if not find(str,"^/") then str = lfs.currentdir() .. "/" .. str end @@ -3340,6 +3391,8 @@ local stripper = lpeg.Cs((number + 1)^0) --~ lpegmatch(stripper,str) --~ print(#str, os.clock()-ts, lpegmatch(stripper,sample)) +lpeg.patterns.strip_zeros = stripper + function aux.strip_zeros(str) return lpegmatch(stripper,str) end @@ -3626,14 +3679,14 @@ end function setters.enable(t,what) local e = t.enable t.enable, t.done = enable, { } - enable(t,string.simpleesc(what)) + enable(t,string.simpleesc(tostring(what))) t.enable, t.done = e, { } end function setters.disable(t,what) local e = t.disable t.disable, t.done = disable, { } - disable(t,string.simpleesc(what)) + disable(t,string.simpleesc(tostring(what))) t.disable, t.done = e, { } end @@ -3720,6 +3773,13 @@ function experiments.disable(...) d(...) end +-- a useful example + +directives.register("system.nostatistics", function(v) + statistics.enable = not v +end) + + end -- of closure @@ -3995,9 +4055,9 @@ local function attribute_specification_error(str) return str end -function xml.unknown_dec_entity_format(str) return format("&%s;", str) end +function xml.unknown_dec_entity_format(str) return (str == "" and "&error;") or format("&%s;",str) end function xml.unknown_hex_entity_format(str) return format("&#x%s;",str) end -function xml.unknown_any_entity_format(str) return format("&%s;", str) end +function xml.unknown_any_entity_format(str) return format("&#x%s;",str) end local function handle_hex_entity(str) local h = hcache[str] @@ -4111,7 +4171,11 @@ local function handle_any_entity(str) if trace_entities then logs.report("xml","keeping entity &%s;",str) end - a = "&" .. str .. ";" + if str == "" then + a = "&error;" + else + a = "&" .. str .. ";" + end end end acache[str] = a @@ -4132,6 +4196,9 @@ local function handle_any_entity(str) if a then -- one of the predefined acache[str] = a + elseif str == "" then + a = "&error;" + acache[str] = a else a = "&" .. str .. ";" acache[str] = a @@ -4460,7 +4527,7 @@ function xml.checkbom(root) -- can be made faster local dt, found = root.dt, false for k=1,#dt do local v = dt[k] - if type(v) == "table" and v.special and v.tg == "@pi" and find(v.dt,"xml.*version=") then + if type(v) == "table" and v.special and v.tg == "@pi@" and find(v.dt[1],"xml.*version=") then found = true break end @@ -4842,6 +4909,8 @@ function xml.assign(dt,k,root) end end +-- the following helpers may move + --[[ldx--

The next helper assigns a tree (or string). Usage:

@@ -4860,6 +4929,22 @@ function xml.tocdata(e,wrapper) e.dt = { t } end +function xml.makestandalone(root) + if root.ri then + local dt = root.dt + for k=1,#dt do + local v = dt[k] + if type(v) == "table" and v.special and v.tg == "@pi@" then + local txt = v.dt[1] + if find(txt,"xml.*version=") then + v.dt[1] = txt .. " standalone='yes'" + break + end + end + end + end +end + end -- of closure @@ -5476,8 +5561,13 @@ local register_initial_child = { kind = "axis", axis = "initial-child" local register_all_nodes = { kind = "nodes", nodetest = true, nodes = { true, false, false } } +local skip = { } + local function errorrunner_e(str,cnv) - logs.report("lpath","error in expression: %s => %s",str,cnv) + if not skip[str] then + logs.report("lpath","error in expression: %s => %s",str,cnv) + skip[str] = cnv or str + end return false end local function errorrunner_f(str,arg) @@ -7287,6 +7377,14 @@ function statistics.hastimer(instance) return instance and instance.starttime end +function statistics.resettiming(instance) + if not instance then + notimer = { timing = 0, loadtime = 0 } + else + instance.timing, instance.loadtime = 0, 0 + end +end + function statistics.starttiming(instance) if not instance then notimer = { } @@ -7346,6 +7444,12 @@ function statistics.elapsedindeed(instance) return t > statistics.threshold end +function statistics.elapsedseconds(instance,rest) -- returns nil if 0 seconds + if statistics.elapsedindeed(instance) then + return format("%s seconds %s", statistics.elapsedtime(instance),rest or "") + end +end + -- general function function statistics.register(tag,fnc) @@ -7424,6 +7528,23 @@ function statistics.timed(action,report) report("total runtime: %s",statistics.elapsedtime(timer)) end +-- where, not really the best spot for this: + +commands = commands or { } + +local timer + +function commands.resettimer() + statistics.resettiming(timer) + statistics.starttiming(timer) +end + +function commands.elapsedtime() + statistics.stoptiming(timer) + tex.sprint(statistics.elapsedtime(timer)) +end + +commands.resettimer() end -- of closure @@ -7861,8 +7982,8 @@ suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' } alternatives['map files'] = 'map' alternatives['enc files'] = 'enc' -alternatives['cid files'] = 'cid' -alternatives['fea files'] = 'fea' +alternatives['cid maps'] = 'cid' -- great, why no cid files +alternatives['font feature files'] = 'fea' -- and fea files here alternatives['opentype fonts'] = 'otf' alternatives['truetype fonts'] = 'ttf' alternatives['truetype collections'] = 'ttc' @@ -8005,8 +8126,10 @@ local function check_configuration() -- not yet ok, no time for debugging now -- bad luck end fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm - fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") - fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + -- this will go away some day + fix("FONTFEATURES", ".;$TEXMF/fonts/{data,fea}//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + fix("FONTCIDMAPS" , ".;$TEXMF/fonts/{data,cid}//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + -- fix("LUATEXLIBS" , ".;$TEXMF/luatex/lua//") end @@ -8396,7 +8519,7 @@ 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] = file.collapse_path(fname) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) @@ -8425,7 +8548,7 @@ 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] = file.collapse_path(fname) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) @@ -8550,7 +8673,7 @@ local weird = lpeg.P(".")^1 + lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,? --~ local l_forbidden = lpeg.S("~`!#$%^&*()={}[]:;\"\'||\\/<>,?\n\r\t") --~ local l_confusing = lpeg.P(" ") ---~ local l_character = lpeg.utf8 +--~ local l_character = lpeg.patterns.utf8 --~ local l_dangerous = lpeg.P(".") --~ local l_normal = (l_character - l_forbidden - l_confusing - l_dangerous) * (l_character - l_forbidden - l_confusing^2)^0 * lpeg.P(-1) @@ -9290,8 +9413,7 @@ 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 = file.collapse_path(filename) -- speed up / beware: format problem if instance.remember then stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -9772,12 +9894,13 @@ end function table.sequenced(t,sep) -- temp here local s = { } for k, v in pairs(t) do -- pairs? - s[#s+1] = k .. "=" .. v + s[#s+1] = k .. "=" .. tostring(v) end return concat(s, sep or " | ") end function resolvers.methodhandler(what, filename, filetype) -- ... + filename = file.collapse_path(filename) local specification = (type(filename) == "string" and resolvers.splitmethod(filename)) or filename -- no or { }, let it bomb local scheme = specification.scheme if resolvers[what][scheme] then -- cgit v1.2.3