diff options
40 files changed, 1342 insertions, 539 deletions
| 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--  <p>The next helper assigns a tree (or string). Usage:</p>  <typing> @@ -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.exeBinary files differ index 9a67fc133..2d45f2749 100755 --- a/scripts/context/stubs/mswin/context.exe +++ b/scripts/context/stubs/mswin/context.exe diff --git a/scripts/context/stubs/mswin/luatools.exe b/scripts/context/stubs/mswin/luatools.exeBinary files differ index 9a67fc133..2d45f2749 100755 --- a/scripts/context/stubs/mswin/luatools.exe +++ b/scripts/context/stubs/mswin/luatools.exe 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.exeBinary files differ index 9a67fc133..2d45f2749 100755 --- a/scripts/context/stubs/mswin/metatex.exe +++ b/scripts/context/stubs/mswin/metatex.exe diff --git a/scripts/context/stubs/mswin/mtxrun.dll b/scripts/context/stubs/mswin/mtxrun.dllBinary files differ index 6af687abe..bb7af56ec 100644 --- a/scripts/context/stubs/mswin/mtxrun.dll +++ b/scripts/context/stubs/mswin/mtxrun.dll diff --git a/scripts/context/stubs/mswin/mtxrun.exe b/scripts/context/stubs/mswin/mtxrun.exeBinary files differ index 9a67fc133..2d45f2749 100755 --- a/scripts/context/stubs/mswin/mtxrun.exe +++ b/scripts/context/stubs/mswin/mtxrun.exe 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--  <p>The next helper assigns a tree (or string). Usage:</p>  <typing> @@ -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.exeBinary files differ index 9a67fc133..2d45f2749 100755 --- a/scripts/context/stubs/mswin/texexec.exe +++ b/scripts/context/stubs/mswin/texexec.exe diff --git a/scripts/context/stubs/mswin/texmfstart.exe b/scripts/context/stubs/mswin/texmfstart.exeBinary files differ index 9a67fc133..2d45f2749 100755 --- a/scripts/context/stubs/mswin/texmfstart.exe +++ b/scripts/context/stubs/mswin/texmfstart.exe 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 <windows.h>  #include <stdio.h> +#include <stdlib.h> +#include <windows.h> +//#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--  <p>The next helper assigns a tree (or string). Usage:</p>  <typing> @@ -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/tex/context/base/char-tex.lua b/tex/context/base/char-tex.lua index f3af91f79..3e726703a 100644 --- a/tex/context/base/char-tex.lua +++ b/tex/context/base/char-tex.lua @@ -58,7 +58,7 @@ local function remap_commands(c)  end  local P, C, R, S, Cs, Cc = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.Cs, lpeg.Cc -local U, lpegmatch = lpeg.utf8, lpeg.match +local U, lpegmatch = lpeg.patterns.utf8, lpeg.match  local accents  = (P('\\') * C(S(accents)) * (P("{") * C(U) * P("}" * Cc(true)) + C(U) * Cc(false))) / remap_accents  local commands = (P('\\') * C(R("az","AZ")^1)) / remap_commands diff --git a/tex/context/base/cont-new.tex b/tex/context/base/cont-new.tex index aada1b888..a80de62a0 100644 --- a/tex/context/base/cont-new.tex +++ b/tex/context/base/cont-new.tex @@ -11,7 +11,7 @@  %C therefore copyrighted by \PRAGMA. See mreadme.pdf for  %C details. -\newcontextversion{2010.03.02 12:34} +\newcontextversion{2010.03.09 10:39}  %D This file is loaded at runtime, thereby providing an  %D excellent place for hacks, patches, extensions and new diff --git a/tex/context/base/context.tex b/tex/context/base/context.tex index 6a89f4cfe..328f3f683 100644 --- a/tex/context/base/context.tex +++ b/tex/context/base/context.tex @@ -20,7 +20,7 @@  %D your styles an modules.  \edef\contextformat {\jobname} -\edef\contextversion{2010.03.02 12:34} +\edef\contextversion{2010.03.09 10:39}  %D For those who want to use this: diff --git a/tex/context/base/data-res.lua b/tex/context/base/data-res.lua index 40cd3eb1a..47c29fda9 100644 --- a/tex/context/base/data-res.lua +++ b/tex/context/base/data-res.lua @@ -645,7 +645,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) @@ -674,7 +674,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) @@ -799,7 +799,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) @@ -1539,8 +1539,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 @@ -2021,7 +2020,7 @@ 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 diff --git a/tex/context/base/font-syn.lua b/tex/context/base/font-syn.lua index 4b892ed8c..1d9bc64f5 100644 --- a/tex/context/base/font-syn.lua +++ b/tex/context/base/font-syn.lua @@ -671,7 +671,7 @@ local function analysefiles()          end      end      if not trace_warnings then -        logs.report("fontnames", "warnings are disables (tracker 'fonts.warnings')") +        logs.report("fontnames", "warnings are disabled (tracker 'fonts.warnings')")      end      traverse("tree", function(suffix) -- TEXTREE only          resolvers.with_files(".*%." .. suffix .. "$", function(method,root,path,name) diff --git a/tex/context/base/grph-inc.lua b/tex/context/base/grph-inc.lua index 7f786248e..574bece89 100644 --- a/tex/context/base/grph-inc.lua +++ b/tex/context/base/grph-inc.lua @@ -377,8 +377,8 @@ local function register(askedname,specification)                  end                  local newname = file.join(newpath,newbase)                  dir.makedirs(newpath) -                oldname = dir.expand_name(oldname) -                newname = dir.expand_name(newname) +                oldname = file.collapse_path(oldname) +                newname = file.collapse_path(newname)                  local oldtime = lfs.attributes(oldname,'modification') or 0                  local newtime = lfs.attributes(newname,'modification') or 0                  if oldtime > newtime then @@ -428,7 +428,7 @@ local function register(askedname,specification)      return specification  end -local resolve_too = true +local resolve_too = true -- urls  local function locate(request) -- name, format, cache      local askedname = resolvers.clean_path(request.name) @@ -544,7 +544,7 @@ local function locate(request) -- name, format, cache              for _, format in ipairs(figures.order) do                  local list = figures.formats[format].list or { format }                  for _, suffix in ipairs(list) do ---~                     local name = file.replacesuffix(askedbase,suffix) +                 -- local name = file.replacesuffix(askedbase,suffix)                      local name = file.replacesuffix(askedname,suffix)                      for _, path in ipairs(figures.paths) do                          local check = path .. "/" .. name @@ -553,7 +553,7 @@ local function locate(request) -- name, format, cache                              if trace_figures then                                  commands.writestatus("figures","warning: skipping path %s",path)                              end -                        elseif figures.exists(check,format,resolve_too) then +                        elseif figures.exists(check,format,true) then                              return register(askedname, {                                  askedname = askedname,                                  fullname = check, diff --git a/tex/context/base/l-dir.lua b/tex/context/base/l-dir.lua index 3760db2c1..369895c43 100644 --- a/tex/context/base/l-dir.lua +++ b/tex/context/base/l-dir.lua @@ -323,7 +323,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 diff --git a/tex/context/base/l-file.lua b/tex/context/base/l-file.lua index 2064fcdd1..0b2c96d8f 100644 --- a/tex/context/base/l-file.lua +++ b/tex/context/base/l-file.lua @@ -139,7 +139,9 @@ end  -- we can hash them weakly  function file.collapse_path(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 @@ -147,7 +149,7 @@ function file.collapse_path(str)              str, m = gsub(str,"[^/%.]+/%.%./","")          end          str = gsub(str,"([^/])/$","%1") -        str = gsub(str,"^%./","") +    --  str = gsub(str,"^%./","") -- ./xx in qualified          str = gsub(str,"/%.$","")      end      if str == "" then str = "." end diff --git a/tex/context/base/l-lpeg.lua b/tex/context/base/l-lpeg.lua index e7b319874..227b193da 100644 --- a/tex/context/base/l-lpeg.lua +++ b/tex/context/base/l-lpeg.lua @@ -160,8 +160,6 @@ 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 diff --git a/tex/context/base/mlib-run.lua b/tex/context/base/mlib-run.lua index 73ce51c89..212b7b7f3 100644 --- a/tex/context/base/mlib-run.lua +++ b/tex/context/base/mlib-run.lua @@ -58,7 +58,7 @@ metapost.finder = finder  metapost.parameters = {      hash_size = 100000, -    main_memory = 2500000, +    main_memory = 4000000,      max_in_open = 50,      param_size = 100000,  } diff --git a/tex/context/base/node-tra.lua b/tex/context/base/node-tra.lua index 3534e9719..39ff32209 100644 --- a/tex/context/base/node-tra.lua +++ b/tex/context/base/node-tra.lua @@ -8,7 +8,7 @@ if not modules then modules = { } end modules ['node-tra'] = {  --[[ldx--  <p>This is rather experimental. We need more control and some of this -might become a runtime module instead.</p> +might become a runtime module instead. This module will be cleaned up!</p>  --ldx]]--  local utf = unicode.utf8 @@ -445,3 +445,20 @@ end  --~ \stopluacode  nodes.show_simple_list = function(h,depth) show_simple_list(h,depth,0) end + +function nodes.list_to_utf(h,joiner) +    local joiner = (joiner ==true and utfchar(0x200C)) or joiner -- zwnj +    local w = { } +    while h do +        if h.id == glyph then -- always true +            w[#w+1] = utfchar(h.char) +            if joiner then +                w[#w+1] = joiner +            end +        else +            w[#w+1] = "[-]" +        end +        h = h.next +    end +    return concat(w) +end diff --git a/tex/context/base/s-fnt-25.tex b/tex/context/base/s-fnt-25.tex index a71aaa330..a8b398716 100644 --- a/tex/context/base/s-fnt-25.tex +++ b/tex/context/base/s-fnt-25.tex @@ -44,7 +44,7 @@     \blank}  \def\mathfontlistentryhexdectit#1#2#3% -  {#1: \ruledhbox{\char#2}\enspace#3\par +  {#1: \char#2\enspace\ruledhbox{\char#2}\enspace#3\par     \advance\leftskip 1em\relax}  \def\mathfontlistentrywdhtdpic#1#2#3#4% @@ -90,7 +90,8 @@ function document.showmathfont(id,slot)              names[k] = (name and file.basename(name)) or v.id          end      end -    print(table.serialize(names)) +    local round = math.round +--  print(table.serialize(names))      for _, s in next, sorted do          local char = characters[s]          if char then @@ -98,7 +99,7 @@ function document.showmathfont(id,slot)              local cnext, cvert_variants, choriz_variants = char.next, char.vert_variants, char.horiz_variants              report("\\startmathfontlistentry")              report("\\mathfontlistentryhexdectit{U+%05X}{%s}{%s}",s,s,string.lower(info.description or "no description, private to font")) -            report("\\mathfontlistentrywdhtdpic{%s}{%s}{%s}{%s}",char.width or 0,char.height or 0,char.depth or 0,char.italic or 0) +            report("\\mathfontlistentrywdhtdpic{%s}{%s}{%s}{%s}",round(char.width or 0),round(char.height or 0),round(char.depth or 0),round(char.italic or 0))              if virtual then                  local commands = char.commands                  if commands then diff --git a/tex/context/base/spec-fdf.mkii b/tex/context/base/spec-fdf.mkii index 5d180b38c..4bf4115c6 100644 --- a/tex/context/base/spec-fdf.mkii +++ b/tex/context/base/spec-fdf.mkii @@ -321,7 +321,17 @@      \addPDFdocumentinfo  \to \everyfirstshipout -\def\PDFversion{1.\the\pdfminorversion} +\ifx\pdfminorversion\undefined +  \ifx\pdfoptionpdfminorversion\undefined +    \newcount\pdfminorversion +  \else +    \let\pdfminorversion\pdfoptionpdfminorversion +  \fi +\fi + +\pdfminorversion=5 + +\def\PDFversion{1.\number\pdfminorversion}  \appendtoksonce    \def\PDFversion{1.\the\pdfminorversion}% diff --git a/tex/context/base/strc-itm.mkiv b/tex/context/base/strc-itm.mkiv index 423508930..6f3f5bb77 100644 --- a/tex/context/base/strc-itm.mkiv +++ b/tex/context/base/strc-itm.mkiv @@ -985,83 +985,6 @@       \fi     \fi\fi} -% \def\dodolapitem -%   {% todo: align+marge binnen de hbox -%    \llap{\hbox to \itemgrouplistwidth{\ifconditional\sublistitem\llap{+\enspace}\fi -%      \symalignleft -%      \box\itemgroupitembox\hfil -%      \hskip\getitemparameter\currentitemlevel\c!distance% T h -%    }}} - -% \def\dolistitem % evt aantal items opslaan per niveau, scheelt zoeken -%   {\ifconditional\textlistitem -%     % begin of item -%    \else -%      \par -%    \fi -%    \advance\noflistelements\plusone -%    \optimizelistitemsbreak -%    \noindent -%    \setbox\itemgroupitembox\hbox -%      {\ifconditional\headlistitem -%         \ifconditional\symbollistitem -%           \dosetitemattributes\currentitemlevel\c!symstyle\c!symcolor{\symsymbol}% -%         \else -%           \dosetitemattributes\currentitemlevel\c!headstyle\c!headcolor{\listitem}% -%         \fi -%       \else -%         \ifconditional\symbollistitem -%           \dosetitemattributes\currentitemlevel\c!symstyle\c!symcolor{\symsymbol}% -%         \else -%           \dosetitemattributes\currentitemlevel\c!style\c!color{\listitem}% -%         \fi -%       \fi}% -%     \ifconditional\fittinglistitems -%       \ifdim\wd\itemgroupitembox>\getitemparameter\currentitemlevel\c!maxwidth sp\relax -%         \xsetitemparameter\currentitemlevel\c!maxwidth{\number\wd\itemgroupitembox}% -%       \fi -%       \ifdim\currentitemmaxwidth>\zeropoint -%         \setbox\itemgroupitembox\simplealignedbox{\getitemparameter\currentitemlevel\c!itemalign}{\currentitemmaxwidth}{\box\itemgroupitembox}% -%       \fi -%    \fi -%    \doifsomething\doitemdestination -%      {\setbox\itemgroupitembox\hbox{\directgotobox{\box\itemgroupitembox}[\doitemdestination]}}% -%    \globallet\doitemdestination\empty -%    \itemgroupaskedwidth\getitemparameter\currentitemlevel\c!width\relax -%    % new, prevents loops when symbol is (not yet found) graphic -%    \ht\itemgroupitembox\strutheight -%    \dp\itemgroupitembox\strutdepth -%    % so that content differs per run (esp mp graphics afterwards) -%    \checkforrepeatedlistitem -%    \ifdim\itemgroupaskedwidth<\zeropoint\relax -%      \llap{\ifconditional\sublistitem\llap{+\enspace}\fi\box\itemgroupitembox\hskip\leftmargindistance}% -%    \else -%      \ifdim\itemgroupaskedwidth=\zeropoint\relax -%        \calculatelistwidth1% -%      \else -%        \calculatelistwidth\currentitemlevel -%      \fi -%      \ifconditional\textlistitem -%        \hbox{\ifconditional\sublistitem+\enspace\fi\box\itemgroupitembox\hskip\interwordspace}\nobreak -%      \else\ifconditional\inlinelistitem -%        \hbox to \itemgrouplistwidth{\ifconditional\sublistitem\llap{+\enspace}\fi\box\itemgroupitembox\hss}% was: \hfill -%      \else\ifconditional\txtlistitem -%        \dodotxtitem -%      \else -%        \dodolapitem -%      \fi\fi\fi -%    \fi -%    \forceunexpanded % needed for m conversion (\os) / i need to look into this -%    \setevalue{\@@currentitemsymbol\currentitemlevel}% -%      {\getvalue{\@@localitemsymbol\currentitemlevel}}% still problems with \uchar ? -%     %{\noexpand\getvalue{\@@localitemsymbol\currentitemlevel}}% no, spoils subrefs -%    \resetunexpanded -%    \setfalse\headlistitem -%    \setfalse\sublistitem -%    \setfalse\symbollistitem -%    \EveryPar{\ignorespaces}% needed ? -%    \ignorespaces} -  \def\dodosubitem    {\ifconditional\sublistitem\llap{+\enspace}\fi} @@ -1074,7 +997,7 @@           \hfil           \hskip\getitemparameter\currentitemlevel\c!distance}}} -\def\dolistitem % evt aantal items opslaan per niveau, scheelt zoeken +\unprotected\def\dolistitem % evt aantal items opslaan per niveau, scheelt zoeken    {\ifconditional\textlistitem      % begin of item     \else @@ -1082,7 +1005,8 @@     \fi     \advance\noflistelements\plusone     \optimizelistitemsbreak -   \noindent +   %\noindent %% WS: don't apply \noindent when the user sets 'first' in the indenting key +   \checkindentation\ifindentfirstparagraph\indent\else\noindent\fi     \setbox\itemgroupitembox\hbox       {\ifconditional\headlistitem          \ifconditional\symbollistitem @@ -1204,7 +1128,7 @@  \chardef\autoitemgroupspacing=2 % 0 = voor/na, 1=tussen als geen voor 2=(prev)tussen=old/normal -\def\complexdoitemgroupitem[#1]% +\unprotected\def\complexdoitemgroupitem[#1]%    {\def\currentitemreference{#1}%     \ifconditional\textlistitem       % begin of item @@ -1239,7 +1163,11 @@       \fi     \else       \ifconditional\textlistitem % was bugged: \inlinelistitem -       \removeunwantedspaces\hskip\emwidth\!!plus\interwordstretch\!!minus\interwordshrink\relax % new per 2006/10/20 +       \ifhmode +         % WS: make the distance between items customizable, think about better default values -> see itemize-1.tex +         \normalexpanded{\doassigntextitemdistance{\getitemparameter\currentitemlevel\c!textdistance}}% HH: moved out and made configurable (sort of) +         \removeunwantedspaces\hskip\textitemdistance\relax +       \fi       \else         \iteminbetweencommand       \fi @@ -1262,6 +1190,28 @@     \hskip\itemsignal        % new, concat     \getitemparameter\currentitemlevel\c!command} % \defaultitemcommand +% \startitemize[text][space=medium] +% \item one \item two \item three +% \stopitemize + +\setvalue{\??op:\??op:\c!textdistance:\v!none}% +  {\let\textitemdistance\zeropoint} + +\def\doassigngiventextitemdistance#1% +  {\assignvalue +     {#1}% +     \textitemdistance +     {.5\interwordspace\!!plus.5\emwidth}% +     {\interwordspace  \!!plus  \emwidth}% +     {\emwidth         \!!plus  \interwordstretch\!!minus\interwordshrink}} + +\unexpanded\def\doassigntextitemdistance#1% +  {\ifcsname\??op:\??op:\c!textdistance:#1\endcsname +     \csname\??op:\??op:\c!textdistance:#1\endcsname +   \else +     \doassigngiventextitemdistance{#1}% +   \fi} +  \def\defaultitemcommand    {\EveryPar{\ignorespaces}% needed ?     \ignorespaces} @@ -1369,6 +1319,7 @@     \c!start=1,     \c!criterium=\v!all, % permits 0 and negative numbers    %\c!option=, +   \c!textdistance=\v!big,     \c!command=\defaultitemcommand,     \c!symbol=\currentitemlevel] diff --git a/tex/context/base/strc-num.mkiv b/tex/context/base/strc-num.mkiv index 42f59c9e7..c5bad7224 100644 --- a/tex/context/base/strc-num.mkiv +++ b/tex/context/base/strc-num.mkiv @@ -203,7 +203,7 @@     \ctxlua{structure.counters.add("\@@thestructurecounter{#1}",1,1)}}  \def\doincrementsubstructurecounter[#1][#2]% -  {\docheckstructurecounterbypage{#1} +  {\docheckstructurecounterbypage{#1}%     \ctxlua{structure.counters.add("\@@thestructurecounter{#1}",#2,1)}}  \def\convertedstructurecounter diff --git a/tex/context/base/trac-tra.lua b/tex/context/base/trac-tra.lua index 4c578fcee..5d15d5ad8 100644 --- a/tex/context/base/trac-tra.lua +++ b/tex/context/base/trac-tra.lua @@ -236,14 +236,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 diff --git a/tex/context/interface/cont-cs.xml b/tex/context/interface/cont-cs.xml index 106f50197..079606e99 100644 --- a/tex/context/interface/cont-cs.xml +++ b/tex/context/interface/cont-cs.xml @@ -6235,6 +6235,13 @@          <cd:parameter name="odsadpristi">            <cd:resolve name="indentnext"/>          </cd:parameter> +        <cd:parameter name="textdistance"> +          <!-- maybe resolve here too --> +          <cd:constant type="zadny"/> +          <cd:constant type="velke"/> +          <cd:constant type="stredni"/> +          <cd:constant type="male"/> +        </cd:parameter>        </cd:assignments>      </cd:arguments>    </cd:command> diff --git a/tex/context/interface/cont-de.xml b/tex/context/interface/cont-de.xml index f2ce1cfe5..bb011ddbc 100644 --- a/tex/context/interface/cont-de.xml +++ b/tex/context/interface/cont-de.xml @@ -6235,6 +6235,13 @@          <cd:parameter name="ziehefolgendeein">            <cd:resolve name="indentnext"/>          </cd:parameter> +        <cd:parameter name="textdistance"> +          <!-- maybe resolve here too --> +          <cd:constant type="kein"/> +          <cd:constant type="gross"/> +          <cd:constant type="mittel"/> +          <cd:constant type="klein"/> +        </cd:parameter>        </cd:assignments>      </cd:arguments>    </cd:command> diff --git a/tex/context/interface/cont-en.xml b/tex/context/interface/cont-en.xml index 9d2319722..4c6ef7c7d 100644 --- a/tex/context/interface/cont-en.xml +++ b/tex/context/interface/cont-en.xml @@ -6235,6 +6235,13 @@          <cd:parameter name="indentnext">            <cd:resolve name="indentnext"/>          </cd:parameter> +        <cd:parameter name="textdistance"> +          <!-- maybe resolve here too --> +          <cd:constant type="none"/> +          <cd:constant type="big"/> +          <cd:constant type="medium"/> +          <cd:constant type="small"/> +        </cd:parameter>        </cd:assignments>      </cd:arguments>    </cd:command> diff --git a/tex/context/interface/cont-fr.xml b/tex/context/interface/cont-fr.xml index 2e38c3667..b07e97936 100644 --- a/tex/context/interface/cont-fr.xml +++ b/tex/context/interface/cont-fr.xml @@ -6235,6 +6235,13 @@          <cd:parameter name="indentesuivant">            <cd:resolve name="indentnext"/>          </cd:parameter> +        <cd:parameter name="distancetexte"> +          <!-- maybe resolve here too --> +          <cd:constant type="rien"/> +          <cd:constant type="grand"/> +          <cd:constant type="moyen"/> +          <cd:constant type="petit"/> +        </cd:parameter>        </cd:assignments>      </cd:arguments>    </cd:command> diff --git a/tex/context/interface/cont-it.xml b/tex/context/interface/cont-it.xml index 94e61e619..fa86d2159 100644 --- a/tex/context/interface/cont-it.xml +++ b/tex/context/interface/cont-it.xml @@ -6235,6 +6235,13 @@          <cd:parameter name="rientrasuccessivo">            <cd:resolve name="indentnext"/>          </cd:parameter> +        <cd:parameter name="distanzatesto"> +          <!-- maybe resolve here too --> +          <cd:constant type="nessuno"/> +          <cd:constant type="grande"/> +          <cd:constant type="medio"/> +          <cd:constant type="piccolo"/> +        </cd:parameter>        </cd:assignments>      </cd:arguments>    </cd:command> diff --git a/tex/context/interface/cont-nl.xml b/tex/context/interface/cont-nl.xml index a337bbb6e..a4bd85c61 100644 --- a/tex/context/interface/cont-nl.xml +++ b/tex/context/interface/cont-nl.xml @@ -6235,6 +6235,13 @@          <cd:parameter name="springvolgendein">            <cd:resolve name="indentnext"/>          </cd:parameter> +        <cd:parameter name="tekstafstand"> +          <!-- maybe resolve here too --> +          <cd:constant type="geen"/> +          <cd:constant type="groot"/> +          <cd:constant type="middel"/> +          <cd:constant type="klein"/> +        </cd:parameter>        </cd:assignments>      </cd:arguments>    </cd:command> diff --git a/tex/context/interface/cont-pe.xml b/tex/context/interface/cont-pe.xml index 9bcda97f7..cf6a91683 100644 --- a/tex/context/interface/cont-pe.xml +++ b/tex/context/interface/cont-pe.xml @@ -6235,6 +6235,13 @@          <cd:parameter name="متنتورفته">            <cd:resolve name="indentnext"/>          </cd:parameter> +        <cd:parameter name="فاصلهمتن"> +          <!-- maybe resolve here too --> +          <cd:constant type="هیچکدام"/> +          <cd:constant type="بزرگ"/> +          <cd:constant type="متوسط"/> +          <cd:constant type="کوچک"/> +        </cd:parameter>        </cd:assignments>      </cd:arguments>    </cd:command> diff --git a/tex/context/interface/cont-ro.xml b/tex/context/interface/cont-ro.xml index 0e83841d3..44d72a866 100644 --- a/tex/context/interface/cont-ro.xml +++ b/tex/context/interface/cont-ro.xml @@ -6235,6 +6235,13 @@          <cd:parameter name="aliniaturmator">            <cd:resolve name="indentnext"/>          </cd:parameter> +        <cd:parameter name="textdistance"> +          <!-- maybe resolve here too --> +          <cd:constant type="niciunul"/> +          <cd:constant type="mare"/> +          <cd:constant type="mediu"/> +          <cd:constant type="mic"/> +        </cd:parameter>        </cd:assignments>      </cd:arguments>    </cd:command> diff --git a/tex/generic/context/luatex-fonts-merged.lua b/tex/generic/context/luatex-fonts-merged.lua index 77600a7bd..3d4bf05e8 100644 --- a/tex/generic/context/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex-fonts-merged.lua @@ -1,6 +1,6 @@  -- merged file : c:/data/develop/context/texmf/tex/generic/context/luatex-fonts-merged.lua  -- parent file : c:/data/develop/context/texmf/tex/generic/context/luatex-fonts.lua --- merge date  : 03/02/10 12:39:47 +-- merge date  : 03/09/10 10:46:16  do -- begin closure to overcome local limits and interference @@ -456,11 +456,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 -- closure @@ -1577,7 +1575,9 @@ end  -- we can hash them weakly  function file.collapse_path(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 @@ -1585,7 +1585,7 @@ function file.collapse_path(str)              str, m = gsub(str,"[^/%.]+/%.%./","")          end          str = gsub(str,"([^/])/$","%1") -        str = gsub(str,"^%./","") +    --  str = gsub(str,"^%./","") -- ./xx in qualified          str = gsub(str,"/%.$","")      end      if str == "" then str = "." end | 
