diff options
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/context/lua/mtx-fonts.lua | 4 | ||||
| -rw-r--r-- | scripts/context/lua/mtxrun.lua | 840 | ||||
| -rw-r--r-- | scripts/context/ruby/base/tex.rb | 6 | ||||
| -rw-r--r-- | scripts/context/stubs/mswin/mtxrun.lua | 840 | ||||
| -rw-r--r-- | scripts/context/stubs/unix/mtxrun | 840 | 
5 files changed, 1532 insertions, 998 deletions
| diff --git a/scripts/context/lua/mtx-fonts.lua b/scripts/context/lua/mtx-fonts.lua index 9e370b2d5..b81d50a32 100644 --- a/scripts/context/lua/mtx-fonts.lua +++ b/scripts/context/lua/mtx-fonts.lua @@ -194,7 +194,7 @@ local function list_specifications(t,info)                      fontweight(entry.fontweight),                  }              end -            aux.formatcolumns(s) +            utilities.formatters.formatcolumns(s)              for k=1,#s do                  texio.write_nl(s[k])              end @@ -221,7 +221,7 @@ local function list_matches(t,info)                      subfont(entry.subfont)                  }              end -            aux.formatcolumns(s) +            utilities.formatters.formatcolumns(s)              for k=1,#s do                  texio.write_nl(s[k])              end diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index 68ee3d2c1..ef6ccbfb6 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -52,6 +52,7 @@ if not modules then modules = { } end modules ['l-string'] = {      license   = "see context related readme files"  } +local string = string  local sub, gsub, find, match, gmatch, format, char, byte, rep, lower = string.sub, string.gsub, string.find, string.match, string.gmatch, string.format, string.char, string.byte, string.rep, string.lower  local lpegmatch = lpeg.match @@ -199,11 +200,6 @@ end  string.padd = string.rpadd -function is_number(str) -- tonumber -    return find(str,"^[%-%+]?[%d]-%.?[%d+]$") == 1 -end - -  function string:split_settings() -- no {} handling, see l-aux for lpeg variant      if find(self,"=") then          local t = { } @@ -547,12 +543,10 @@ if not modules then modules = { } end modules ['l-table'] = {      license   = "see context related readme files"  } -table.join = table.concat - +local type, next, tostring, tonumber, ipairs, table, string = type, next, tostring, tonumber, ipairs, table, string  local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove  local format, find, gsub, lower, dump, match = string.format, string.find, string.gsub, string.lower, string.dump, string.match  local getmetatable, setmetatable = getmetatable, setmetatable -local type, next, tostring, tonumber, ipairs = type, next, tostring, tonumber, ipairs  -- Starting with version 5.2 Lua no longer provide ipairs, which makes  -- sense. As we already used the for loop and # in most places the @@ -1452,7 +1446,9 @@ if not modules then modules = { } end modules ['l-io'] = {      license   = "see context related readme files"  } -local byte, find, gsub = string.byte, string.find, string.gsub +local io = io +local byte, find, gsub, format = string.byte, string.find, string.gsub, string.format +local concat = table.concat  if string.find(os.getenv("PATH"),";") then      io.fileseparator, io.pathseparator = "\\", ";" @@ -1463,9 +1459,7 @@ end  function io.loaddata(filename,textmode)      local f = io.open(filename,(textmode and 'r') or 'rb')      if f then -    --  collectgarbage("step") -- sometimes makes a big difference in mem consumption          local data = f:read('*all') -    --  garbagecollector.check(data)          f:close()          return data      else @@ -1477,7 +1471,7 @@ function io.savedata(filename,data,joiner)      local f = io.open(filename,"wb")      if f then          if type(data) == "table" then -            f:write(table.join(data,joiner or "")) +            f:write(concat(data,joiner or ""))          elseif type(data) == "function" then              data(f)          else @@ -1603,12 +1597,12 @@ function io.ask(question,default,options)      while true do          io.write(question)          if options then -            io.write(string.format(" [%s]",table.concat(options,"|"))) +            io.write(format(" [%s]",concat(options,"|")))          end          if default then -            io.write(string.format(" [%s]",default)) +            io.write(format(" [%s]",default))          end -        io.write(string.format(" ")) +        io.write(format(" "))          local answer = io.read()          answer = gsub(answer,"^%s*(.*)%s*$","%1")          if answer == "" and default then @@ -1682,7 +1676,8 @@ local tostring = tostring  local format, floor, insert, match = string.format, math.floor, table.insert, string.match  local lpegmatch = lpeg.match -number = number or { } +number       = number or { } +local number = number  -- a,b,c,d,e,f = number.toset(100101) @@ -1759,6 +1754,8 @@ if not modules then modules = { } end modules ['l-set'] = {      license   = "see context related readme files"  } +-- This will become obsolete when we have the bitset library embedded. +  set = set or { }  local nums   = { } @@ -1840,10 +1837,10 @@ if not modules then modules = { } end modules ['l-os'] = {  -- maybe build io.flush in os.execute +local os = os  local find, format, gsub, upper = string.find, string.format, string.gsub, string.upper  local random, ceil = math.random, math.ceil  local rawget, rawset, type, getmetatable, setmetatable, tonumber = rawget, rawset, type, getmetatable, setmetatable, tonumber -local rawget, rawset, type, getmetatable, setmetatable, tonumber = rawget, rawset, type, getmetatable, setmetatable, tonumber  -- The following code permits traversing the environment table, at least  -- in luatex. Internally all environment names are uppercase. @@ -2193,12 +2190,15 @@ if not modules then modules = { } end modules ['l-file'] = {  -- needs a cleanup  file = file or { } +local file = file  local insert, concat = table.insert, table.concat  local find, gmatch, match, gsub, sub, char = string.find, string.gmatch, string.match, string.gsub, string.sub, string.char  local lpegmatch = lpeg.match  local getcurrentdir = lfs.currentdir +local P, R, S, C, Cs, Cp, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Cp, lpeg.Cc +  local function dirname(name,default)      return match(name,"^(.+)[/\\].-$") or (default or "")  end @@ -2416,11 +2416,11 @@ end  -- also rewrite previous -local letter    = lpeg.R("az","AZ") + lpeg.S("_-+") -local separator = lpeg.P("://") +local letter    = R("az","AZ") + S("_-+") +local separator = P("://") -local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator + letter^1 * lpeg.P("/") -local rootbased = lpeg.P("/") + letter*lpeg.P(":") +local qualified = P(".")^0 * P("/") + letter*P(":") + letter^1*separator + letter^1 * P("/") +local rootbased = P("/") + letter*P(":")  -- ./name ../name  /name c: :// name/name @@ -2432,14 +2432,16 @@ function file.is_rootbased_path(filename)      return lpegmatch(rootbased,filename) ~= nil  end -local slash  = lpeg.S("\\/") -local period = lpeg.P(".") -local drive  = lpeg.C(lpeg.R("az","AZ")) * lpeg.P(":") -local path   = lpeg.C(((1-slash)^0 * slash)^0) -local suffix = period * lpeg.C(lpeg.P(1-period)^0 * lpeg.P(-1)) -local base   = lpeg.C((1-suffix)^0) +-- actually these are schemes + +local slash  = S("\\/") +local period = P(".") +local drive  = C(R("az","AZ")) * P(":") +local path   = C(((1-slash)^0 * slash)^0) +local suffix = period * C(P(1-period)^0 * P(-1)) +local base   = C((1-suffix)^0) -local pattern = (drive + lpeg.Cc("")) * (path + lpeg.Cc("")) * (base + lpeg.Cc("")) * (suffix + lpeg.Cc("")) +local pattern = (drive + Cc("")) * (path + Cc("")) * (base + Cc("")) * (suffix + Cc(""))  function file.splitname(str) -- returns drive, path, base, suffix      return lpegmatch(pattern,str) @@ -2467,6 +2469,7 @@ if not modules then modules = { } end modules ['l-md5'] = {  -- This also provides file checksums and checkers. +local md5, file = md5, file  local gsub, format, byte = string.gsub, string.format, string.byte  local function convert(str,fmt) @@ -2547,7 +2550,8 @@ local lpegmatch, lpegP, lpegC, lpegR, lpegS, lpegCs, lpegCc = lpeg.match, lpeg.P  --     / \ /                        \  --     urn:example:animal:ferret:nose -url = url or { } +url       = url or { } +local url = url  local function tochar(s)      return char(tonumber(s,16)) @@ -2687,20 +2691,30 @@ if not modules then modules = { } end modules ['l-dir'] = {  local type = type  local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub +local concat = table.concat  local lpegmatch = lpeg.match +local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V +  dir = dir or { } +local dir = dir +local lfs = lfs + +local attributes = lfs.attributes +local walkdir    = lfs.dir +local isdir      = lfs.isdir +local isfile     = lfs.isfile +local mkdir      = lfs.mkdir +local chdir      = lfs.chdir +local currentdir = lfs.currentdir  -- handy  function dir.current() -    return (gsub(lfs.currentdir(),"\\","/")) +    return (gsub(currentdir(),"\\","/"))  end --- optimizing for no string.find (*) does not save time - -local attributes = lfs.attributes -local walkdir    = lfs.dir +-- optimizing for no find (*) does not save time  local function glob_pattern(path,patt,recurse,action)      local ok, scanner @@ -2756,8 +2770,6 @@ end  dir.collect_pattern = collect_pattern -local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V -  local pattern = Ct {      [1] = (C(P(".") + P("/")^1) + C(R("az","AZ") * P(":") * P("/")^0) + Cc("./")) * V(2) * V(3),      [2] = C(((1-S("*?/"))^0 * P("/"))^0), @@ -2780,7 +2792,7 @@ local function glob(str,t)              for s=1,#str do                  glob(str[s],t)              end -        elseif lfs.isfile(str) then +        elseif isfile(str) then              t(str)          else              local split = lpegmatch(pattern,str) @@ -2799,7 +2811,7 @@ local function glob(str,t)                  glob(str[s],t)              end              return t -        elseif lfs.isfile(str) then +        elseif isfile(str) then              local t = t or { }              t[#t+1] = str              return t @@ -2863,13 +2875,13 @@ dir.globfiles = globfiles  -- print(dir.ls("*.tex"))  function dir.ls(pattern) -    return table.concat(glob(pattern),"\n") +    return concat(glob(pattern),"\n")  end  local make_indeed = true -- false -if string.find(os.getenv("PATH"),";") then -- os.type == "windows" +if find(os.getenv("PATH"),";") then -- os.type == "windows"      function dir.mkdirs(...)          local str, pth, t = "", "", { ... } @@ -2918,11 +2930,11 @@ if string.find(os.getenv("PATH"),";") then -- os.type == "windows"              else                  pth = pth .. "/" .. s              end -            if make_indeed and not lfs.isdir(pth) then -                lfs.mkdir(pth) +            if make_indeed and not isdir(pth) then +                mkdir(pth)              end          end -        return pth, (lfs.isdir(pth) == true) +        return pth, (isdir(pth) == true)      end @@ -2937,11 +2949,11 @@ if string.find(os.getenv("PATH"),";") then -- os.type == "windows"          if not first then              first, last = match(str,"^([a-zA-Z]:)(.*)$")              if first and not find(last,"^/") then -                local d = lfs.currentdir() -                if lfs.chdir(first) then +                local d = currentdir() +                if chdir(first) then                      first = dir.current()                  end -                lfs.chdir(d) +                chdir(d)              end          end          if not first then @@ -2982,26 +2994,26 @@ else                  else                      pth = pth .. "/" .. s                  end -                if make_indeed and not first and not lfs.isdir(pth) then -                    lfs.mkdir(pth) +                if make_indeed and not first and not isdir(pth) then +                    mkdir(pth)                  end              end          else              pth = "."              for s in gmatch(str,"[^/]+") do                  pth = pth .. "/" .. s -                if make_indeed and not lfs.isdir(pth) then -                    lfs.mkdir(pth) +                if make_indeed and not isdir(pth) then +                    mkdir(pth)                  end              end          end -        return pth, (lfs.isdir(pth) == true) +        return pth, (isdir(pth) == true)      end      function dir.expand_name(str) -- will be merged with cleanpath and collapsepath          if not find(str,"^/") then -            str = lfs.currentdir() .. "/" .. str +            str = currentdir() .. "/" .. str          end          str = gsub(str,"//","/")          str = gsub(str,"/%./","/") @@ -3025,10 +3037,11 @@ if not modules then modules = { } end modules ['l-boolean'] = {      license   = "see context related readme files"  } -boolean = boolean or { } -  local type, tonumber = type, tonumber +boolean = boolean or { } +local boolean = boolean +  function boolean.tonumber(b)      if b then return 1 else return 0 end  end @@ -3109,6 +3122,8 @@ if not unicode then  end +local unicode = unicode +  utf = utf or unicode.utf8  local concat, utfchar, utfgsub = table.concat, utf.char, utf.gsub @@ -3280,7 +3295,7 @@ end  function unicode.utfcodes(str)      local t = { } -    for k,v in string.utfvalues(str) do +    for k,v in utfvalues(str) do          t[#t+1] = format("0x%04X",k)      end      return concat(t,separator or " ") @@ -3339,7 +3354,7 @@ end -- of closure  do -- create closure to overcome 200 locals limit -if not modules then modules = { } end modules ['l-utils'] = { +if not modules then modules = { } end modules ['util-mrg'] = {      version   = 1.001,      comment   = "companion to luat-lib.mkiv",      author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -3353,13 +3368,11 @@ local gsub, format = string.gsub, string.format  local concat = table.concat  local type, next = type, next -if not utils        then utils        = { } end -if not utils.merger then utils.merger = { } end -if not utils.lua    then utils.lua    = { } end - -utils.report = utils.report or print +utilities        = utilities or {} +utilities.merger = utilities.merger or { } +utilities.report = utilities.report or print -local merger = utils.merger +local merger     = utilities.merger  merger.strip_comment = true @@ -3396,9 +3409,9 @@ end  local function self_load(name)      local data = io.loaddata(name) or ""      if data == "" then -        utils.report("merge: unknown file %s",name) +        utilities.report("merge: unknown file %s",name)      else -        utils.report("merge: inserting %s",name) +        utilities.report("merge: inserting %s",name)      end      return data or ""  end @@ -3409,10 +3422,10 @@ local function self_save(name, data)              -- saves some 20K              local n = #data              data = gsub(data,"%-%-~[^\n\r]*[\r\n]","") -            utils.report("merge: %s bytes of comment stripped, %s bytes of code left",n-#data,#data) +            utilities.report("merge: %s bytes of comment stripped, %s bytes of code left",n-#data,#data)          end          io.savedata(name,data) -        utils.report("merge: saving %s",name) +        utilities.report("merge: saving %s",name)      end  end @@ -3429,7 +3442,7 @@ local function self_libs(libs,list)          local lib = libs[i]          for j=1,#list do              local pth = gsub(list[j],"\\","/") -- file.clean_path -            utils.report("merge: checking library path %s",pth) +            utilities.report("merge: checking library path %s",pth)              local name = pth .. "/" .. lib              if lfs.isfile(name) then                  foundpath = pth @@ -3438,30 +3451,30 @@ local function self_libs(libs,list)          if foundpath then break end      end      if foundpath then -        utils.report("merge: using library path %s",foundpath) +        utilities.report("merge: using library path %s",foundpath)          local right, wrong = { }, { }          for i=1,#libs do              local lib = libs[i]              local fullname = foundpath .. "/" .. lib              if lfs.isfile(fullname) then -                utils.report("merge: using library %s",fullname) +                utilities.report("merge: using library %s",fullname)                  right[#right+1] = lib                  result[#result+1] = m_begin_closure                  result[#result+1] = io.loaddata(fullname,true)                  result[#result+1] = m_end_closure              else -                utils.report("merge: skipping library %s",fullname) +                utilities.report("merge: skipping library %s",fullname)                  wrong[#wrong+1] = lib              end          end          if #right > 0 then -            utils.report("merge: used libraries: %s",concat(right," ")) +            utilities.report("merge: used libraries: %s",concat(right," "))          end          if #wrong > 0 then -            utils.report("merge: skipped libraries: %s",concat(wrong," ")) +            utilities.report("merge: skipped libraries: %s",concat(wrong," "))          end      else -        utils.report("merge: no valid library path found") +        utilities.report("merge: no valid library path found")      end      return concat(result, "\n\n")  end @@ -3480,8 +3493,25 @@ function merger.selfclean(name)      self_save(name,self_swap(self_load(name),self_nothing()))  end -function utils.lua.compile(luafile,lucfile,cleanup,strip) -- defaults: cleanup=false strip=true -    utils.report("lua: compiling %s into %s",luafile,lucfile) + +end -- of closure + +do -- create closure to overcome 200 locals limit + +if not modules then modules = { } end modules ['util-lua'] = { +    version   = 1.001, +    comment   = "companion to luat-lib.mkiv", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} + +utilities        = utilities or {} +utilities.lua    = utilities.merger or { } +utilities.report = utilities.report or print + +function utilities.lua.compile(luafile,lucfile,cleanup,strip) -- defaults: cleanup=false strip=true +    utilities.report("lua: compiling %s into %s",luafile,lucfile)      os.remove(lucfile)      local command = "-o " .. string.quote(lucfile) .. " " .. string.quote(luafile)      if strip ~= false then @@ -3489,7 +3519,7 @@ function utils.lua.compile(luafile,lucfile,cleanup,strip) -- defaults: cleanup=f      end      local done = os.spawn("texluac " .. command) == 0 or os.spawn("luac " .. command) == 0      if done and cleanup == true and lfs.isfile(lucfile) and lfs.isfile(luafile) then -        utils.report("lua: removing %s",luafile) +        utilities.report("lua: removing %s",luafile)          os.remove(luafile)      end      return done @@ -3501,7 +3531,7 @@ end -- of closure  do -- create closure to overcome 200 locals limit -if not modules then modules = { } end modules ['l-aux'] = { +if not modules then modules = { } end modules ['util-prs'] = {      version   = 1.001,      comment   = "companion to luat-lib.mkiv",      author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -3509,15 +3539,16 @@ if not modules then modules = { } end modules ['l-aux'] = {      license   = "see context related readme files"  } --- for inline, no store split : for s in string.gmatch(str,",* *([^,]+)") do .. end - -aux = aux or { } +utilities         = utilities or {} +utilities.parsers = utilities.parsers or { } +local parsers     = utilities.parsers +parsers.patterns  = parsers.patterns or { } +local P, R, V, C, Ct, Carg = lpeg.P, lpeg.R, lpeg.V, lpeg.C, lpeg.Ct, lpeg.Carg +local lpegmatch = lpeg.match  local concat, format, gmatch = table.concat, string.format, string.gmatch  local tostring, type = tostring, type -local lpegmatch = lpeg.match - -local P, R, V = lpeg.P, lpeg.R, lpeg.V +local sortedhash = table.sortedhash  local escape, left, right = P("\\"), P('{'), P('}') @@ -3526,23 +3557,23 @@ lpeg.patterns.balanced = P {      [2] = left * V(1) * right  } -local space     = lpeg.P(' ') -local equal     = lpeg.P("=") -local comma     = lpeg.P(",") -local lbrace    = lpeg.P("{") -local rbrace    = lpeg.P("}") +local space     = P(' ') +local equal     = P("=") +local comma     = P(",") +local lbrace    = P("{") +local rbrace    = P("}")  local nobrace   = 1 - (lbrace+rbrace) -local nested    = lpeg.P { lbrace * (nobrace + lpeg.V(1))^0 * rbrace } +local nested    = P { lbrace * (nobrace + V(1))^0 * rbrace }  local spaces    = space^0 -local value     = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0) +local value     = P(lbrace * C((nobrace + nested)^0) * rbrace) + C((nested + (1-comma))^0) -local key       = lpeg.C((1-equal-comma)^1) -local pattern_a = (space+comma)^0 * (key * equal * value + key * lpeg.C("")) +local key       = C((1-equal-comma)^1) +local pattern_a = (space+comma)^0 * (key * equal * value + key * C(""))  local pattern_c = (space+comma)^0 * (key * equal * value) -local key       = lpeg.C((1-space-equal-comma)^1) -local pattern_b = spaces * comma^0 * spaces * (key * ((spaces * equal * spaces * value) + lpeg.C(""))) +local key       = C((1-space-equal-comma)^1) +local pattern_b = spaces * comma^0 * spaces * (key * ((spaces * equal * spaces * value) + C("")))  -- "a=1, b=2, c=3, d={a{b,c}d}, e=12345, f=xx{a{b,c}d}xx, g={}" : outer {} removes, leading spaces ignored @@ -3556,11 +3587,11 @@ local pattern_a_s = (pattern_a/set)^1  local pattern_b_s = (pattern_b/set)^1  local pattern_c_s = (pattern_c/set)^1 -aux.settings_to_hash_pattern_a = pattern_a_s -aux.settings_to_hash_pattern_b = pattern_b_s -aux.settings_to_hash_pattern_c = pattern_c_s +parsers.patterns.settings_to_hash_a = pattern_a_s +parsers.patterns.settings_to_hash_b = pattern_b_s +parsers.patterns.settings_to_hash_c = pattern_c_s -function aux.make_settings_to_hash_pattern(set,how) +function parsers.make_settings_to_hash_pattern(set,how)      if how == "strict" then          return (pattern_c/set)^1      elseif how == "tolerant" then @@ -3570,7 +3601,7 @@ function aux.make_settings_to_hash_pattern(set,how)      end  end -function aux.settings_to_hash(str,existing) +function parsers.settings_to_hash(str,existing)      if str and str ~= "" then          hash = existing or { }          lpegmatch(pattern_a_s,str) @@ -3580,7 +3611,7 @@ function aux.settings_to_hash(str,existing)      end  end -function aux.settings_to_hash_tolerant(str,existing) +function parsers.settings_to_hash_tolerant(str,existing)      if str and str ~= "" then          hash = existing or { }          lpegmatch(pattern_b_s,str) @@ -3590,7 +3621,7 @@ function aux.settings_to_hash_tolerant(str,existing)      end  end -function aux.settings_to_hash_strict(str,existing) +function parsers.settings_to_hash_strict(str,existing)      if str and str ~= "" then          hash = existing or { }          lpegmatch(pattern_c_s,str) @@ -3601,16 +3632,16 @@ function aux.settings_to_hash_strict(str,existing)  end  local separator = comma * space^0 -local value     = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0) -local pattern   = lpeg.Ct(value*(separator*value)^0) +local value     = P(lbrace * C((nobrace + nested)^0) * rbrace) + C((nested + (1-comma))^0) +local pattern   = Ct(value*(separator*value)^0)  -- "aap, {noot}, mies" : outer {} removes, leading spaces ignored -aux.settings_to_array_pattern = pattern +parsers.patterns.settings_to_array = pattern  -- we could use a weak table as cache -function aux.settings_to_array(str) +function parsers.settings_to_array(str)      if not str or str == "" then          return { }      else @@ -3622,14 +3653,14 @@ local function set(t,v)      t[#t+1] = v  end -local value   = lpeg.P(lpeg.Carg(1)*value) / set -local pattern = value*(separator*value)^0 * lpeg.Carg(1) +local value   = P(Carg(1)*value) / set +local pattern = value*(separator*value)^0 * Carg(1) -function aux.add_settings_to_array(t,str) +function parsers.add_settings_to_array(t,str)      return lpegmatch(pattern,str,nil,t)  end -function aux.hash_to_string(h,separator,yes,no,strict,omit) +function parsers.hash_to_string(h,separator,yes,no,strict,omit)      if h then          local t, s = { }, table.sortedkeys(h)          omit = omit and table.tohash(omit) @@ -3658,7 +3689,7 @@ function aux.hash_to_string(h,separator,yes,no,strict,omit)      end  end -function aux.array_to_string(a,separator) +function parsers.array_to_string(a,separator)      if a then          return concat(a,separator or ",")      else @@ -3666,7 +3697,7 @@ function aux.array_to_string(a,separator)      end  end -function aux.settings_to_set(str,t) -- tohash? +function parsers.settings_to_set(str,t) -- tohash? -- todo: lpeg -- duplicate anyway      t = t or { }      for s in gmatch(str,"%s*([^, ]+)") do -- space added          t[s] = true @@ -3674,9 +3705,9 @@ function aux.settings_to_set(str,t) -- tohash?      return t  end -function aux.simple_hash_to_string(h, separator) +function parsers.simple_hash_to_string(h, separator)      local t = { } -    for k, v in table.sortedhash(h) do +    for k, v in sortedhash(h) do          if v then              t[#t+1] = k          end @@ -3684,43 +3715,44 @@ function aux.simple_hash_to_string(h, separator)      return concat(t,separator or ",")  end -local value     = lbrace * lpeg.C((nobrace + nested)^0) * rbrace -local pattern   = lpeg.Ct((space + value)^0) +local value   = lbrace * C((nobrace + nested)^0) * rbrace +local pattern = Ct((space + value)^0) -function aux.arguments_to_table(str) +function parsers.arguments_to_table(str)      return lpegmatch(pattern,str)  end --- temporary here +-- temporary here (unoptimized) -function aux.getparameters(self,class,parentclass,settings) +function parsers.getparameters(self,class,parentclass,settings)      local sc = self[class]      if not sc then          sc = table.clone(self[parent])          self[class] = sc      end -    aux.settings_to_hash(settings,sc) +    parsers.settings_to_hash(settings,sc)  end --- temporary here -local digit         = lpeg.R("09") -local period        = lpeg.P(".") -local zero          = lpeg.P("0") -local trailingzeros = zero^0 * -digit -- suggested by Roberto R -local case_1        = period * trailingzeros / "" -local case_2        = period * (digit - trailingzeros)^1 * (trailingzeros / "") -local number        = digit^1 * (case_1 + case_2) -local stripper      = lpeg.Cs((number + 1)^0) +end -- of closure +do -- create closure to overcome 200 locals limit -lpeg.patterns.strip_zeros = stripper +if not modules then modules = { } end modules ['util-tab'] = { +    version   = 1.001, +    comment   = "companion to luat-lib.mkiv", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} -function aux.strip_zeros(str) -    return lpegmatch(stripper,str) -end +utilities        = utilities or {} +utilities.tables = utilities.tables or { } +local tables     = utilities.tables + +local concat, format, gmatch = table.concat, string.format, string.gmatch -function aux.definetable(target) -- defines undefined tables +function tables.definetable(target) -- defines undefined tables      local composed, t = nil, { }      for name in gmatch(target,"([^%.]+)") do          if composed then @@ -3733,7 +3765,7 @@ function aux.definetable(target) -- defines undefined tables      return concat(t,"\n")  end -function aux.accesstable(target) +function tables.accesstable(target)      local t = _G      for name in gmatch(target,"([^%.]+)") do          t = t[name] @@ -3742,10 +3774,48 @@ function aux.accesstable(target)  end --- as we use this a lot ... +end -- of closure + +do -- create closure to overcome 200 locals limit + +if not modules then modules = { } end modules ['util-fmt'] = { +    version   = 1.001, +    comment   = "companion to luat-lib.mkiv", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} + +utilities            = utilities or { } +utilities.formatters = utilities.formatters or { } +local formatters     = utilities.formatters + +local concat, format = table.concat, string.format +local tostring, type = tostring, type +local strip = string.strip + +local P, R, Cs = lpeg.P, lpeg.R, lpeg.Cs +local lpegmatch = lpeg.match +-- temporary here -function aux.formatcolumns(result,between) +local digit         = R("09") +local period        = P(".") +local zero          = P("0") +local trailingzeros = zero^0 * -digit -- suggested by Roberto R +local case_1        = period * trailingzeros / "" +local case_2        = period * (digit - trailingzeros)^1 * (trailingzeros / "") +local number        = digit^1 * (case_1 + case_2) +local stripper      = Cs((number + 1)^0) + + +lpeg.patterns.strip_zeros = stripper + +function formatters.strip_zeros(str) +    return lpegmatch(stripper,str) +end + +function formatters.formatcolumns(result,between)      if result and #result > 0 then          between = between or "   "          local widths, numbers = { }, { } @@ -3790,10 +3860,10 @@ function aux.formatcolumns(result,between)                  end              end          end -        local template = string.strip(concat(widths)) +        local template = strip(concat(widths))          for i=1,#result do              local str = format(template,unpack(result[i])) -            result[i] = string.strip(str) +            result[i] = strip(str)          end      end      return result @@ -3804,6 +3874,115 @@ end -- of closure  do -- create closure to overcome 200 locals limit +if not modules then modules = { } end modules ['util.deb'] = { +    version   = 1.001, +    comment   = "companion to luat-lib.mkiv", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} + +-- the <anonymous> tag is kind of generic and used for functions that are not +-- bound to a variable, like node.new, node.copy etc (contrary to for instance +-- node.has_attribute which is bound to a has_attribute local variable in mkiv) + +local debug = require "debug" + +local getinfo = debug.getinfo +local type, next = type, next +local format, find = string.format, string.find +local is_boolean = string.is_boolean + +utilities          = utilities or { } +utilities.debugger = utilities.debugger or { } +local debugger     = utilities.debugger + +local counters = { } +local names    = { } + +-- one + +local function hook() +    local f = getinfo(2,"f").func +    local n = getinfo(2,"Sn") +--  if n.what == "C" and n.name then print (n.namewhat .. ': ' .. n.name) end +    if f then +        local cf = counters[f] +        if cf == nil then +            counters[f] = 1 +            names[f] = n +        else +            counters[f] = cf + 1 +        end +    end +end + +local function getname(func) +    local n = names[func] +    if n then +        if n.what == "C" then +            return n.name or '<anonymous>' +        else +            -- source short_src linedefined what name namewhat nups func +            local name = n.name or n.namewhat or n.what +            if not name or name == "" then name = "?" end +            return format("%s : %s : %s", n.short_src or "unknown source", n.linedefined or "--", name) +        end +    else +        return "unknown" +    end +end + +function debugger.showstats(printer,threshold) +    printer   = printer or texio.write or print +    threshold = threshold or 0 +    local total, grandtotal, functions = 0, 0, 0 +    printer("\n") -- ugly but ok + -- table.sort(counters) +    for func, count in next, counters do +        if count > threshold then +            local name = getname(func) +            if not find(name,"for generator") then +                printer(format("%8i  %s", count, name)) +                total = total + count +            end +        end +        grandtotal = grandtotal + count +        functions = functions + 1 +    end +    printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold)) +end + +-- two + + +-- rest + +function debugger.savestats(filename,threshold) +    local f = io.open(filename,'w') +    if f then +        debugger.showstats(function(str) f:write(str) end,threshold) +        f:close() +    end +end + +function debugger.enable() +    debug.sethook(hook,"c") +end + +function debugger.disable() +    debug.sethook() +end + + + + + + +end -- of closure + +do -- create closure to overcome 200 locals limit +  if not modules then modules = { } end modules ['trac-inf'] = {      version   = 1.001,      comment   = "companion to trac-inf.mkiv", @@ -3820,14 +3999,13 @@ if not modules then modules = { } end modules ['trac-inf'] = {  local format = string.format  local clock = os.gettimeofday or os.clock -- should go in environment -local statusinfo, n, registered = { }, 0, { } - -statistics = statistics or { } +statistics       = statistics or { } +local statistics = statistics  statistics.enable    = true  statistics.threshold = 0.05 -local timers = { } +local statusinfo, n, registered, timers = { }, 0, { }, { }  local function hastiming(instance)      return instance and timers[instance] @@ -3995,7 +4173,7 @@ end -- of closure  do -- create closure to overcome 200 locals limit -if not modules then modules = { } end modules ['trac-set'] = { +if not modules then modules = { } end modules ['trac-set'] = { -- might become util-set.lua      version   = 1.001,      comment   = "companion to luat-lib.mkiv",      author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -4007,8 +4185,12 @@ local type, next, tostring = type, next, tostring  local concat = table.concat  local format, find, lower, gsub, simpleesc = string.format, string.find, string.lower, string.gsub, string.simpleesc  local is_boolean = string.is_boolean +local settings_to_hash = utilities.parsers.settings_to_hash -setters = { } +utilities         = utilities or { } +local utilities   = utilities +utilities.setters = utilities.setters or { } +local setters     = utilities.setters  local data = { } -- maybe just local @@ -4064,7 +4246,7 @@ end  local function set(t,what,newvalue)      local data, done = t.data, t.done      if type(what) == "string" then -        what = aux.settings_to_hash(what) -- inefficient but ok +        what = settings_to_hash(what) -- inefficient but ok      end      for w, value in next, what do          if value == "" then @@ -4191,18 +4373,20 @@ end  -- we could have used a bit of oo and the trackers:enable syntax but  -- there is already a lot of code around using the singular tracker --- we could make this into a module +-- we could make this into a module but we also want the rest avaliable + +local enable, disable, register, list, show = setters.enable, setters.disable, setters.register, setters.list, setters.show  function setters.new(name) -    local t +    local t -- we need to access it in t      t = {          data     = { }, -- indexed, but also default and value fields          name     = name, -        enable   = function(...) setters.enable  (t,...) end, -        disable  = function(...) setters.disable (t,...) end, -        register = function(...) setters.register(t,...) end, -        list     = function(...) setters.list    (t,...) end, -        show     = function(...) setters.show    (t,...) end, +        enable   = function(...) enable  (t,...) end, +        disable  = function(...) disable (t,...) end, +        register = function(...) register(t,...) end, +        list     = function(...) list    (t,...) end, +        show     = function(...) show    (t,...) end,      }      data[name] = t      return t @@ -4212,13 +4396,18 @@ trackers    = setters.new("trackers")  directives  = setters.new("directives")  experiments = setters.new("experiments") +local t_enable, t_disable = trackers   .enable, trackers   .disable +local d_enable, d_disable = directives .enable, directives .disable +local e_enable, e_disable = experiments.enable, experiments.disable +  -- experiment  if trackers and environment and environment.engineflags.trackers then -    trackers.enable(environment.engineflags.trackers) +    t_enable(environment.engineflags.trackers)  end +  if directives and environment and environment.engineflags.directives then -    directives.enable(environment.engineflags.directives) +    d_enable(environment.engineflags.directives)  end  -- nice trick: we overload two of the directives related functions with variants that @@ -4232,30 +4421,24 @@ 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 enable  = directives.enable -local disable = directives.disable -  function directives.enable(...)      report("directives","enabling: %s",concat({...}," ")) -    enable(...) +    d_enable(...)  end  function directives.disable(...)      report("directives","disabling: %s",concat({...}," ")) -    disable(...) +    d_disable(...)  end -local enable  = experiments.enable -local disable = experiments.disable -  function experiments.enable(...)      report("experiments","enabling: %s",concat({...}," ")) -    enable(...) +    e_enable(...)  end  function experiments.disable(...)      report("experiments","disabling: %s",concat({...}," ")) -    disable(...) +    e_disable(...)  end  -- a useful example @@ -4264,136 +4447,20 @@ directives.register("system.nostatistics", function(v)      statistics.enable = not v  end) +directives.register("system.nolibraries", function(v) +    libraries = nil -- we discard this tracing for security +end) +  -- experiment  if trackers and environment and environment.engineflags.trackers then -    trackers.enable(environment.engineflags.trackers) +    t_enable(environment.engineflags.trackers)  end  if directives and environment and environment.engineflags.directives then -    directives.enable(environment.engineflags.directives) -end - - -end -- of closure - -do -- create closure to overcome 200 locals limit - -if not modules then modules = { } end modules ['trac-tra'] = { -    version   = 1.001, -    comment   = "companion to trac-tra.mkiv", -    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", -    copyright = "PRAGMA ADE / ConTeXt Development Team", -    license   = "see context related readme files" -} - --- the <anonymous> tag is kind of generic and used for functions that are not --- bound to a variable, like node.new, node.copy etc (contrary to for instance --- node.has_attribute which is bound to a has_attribute local variable in mkiv) - -local debug = require "debug" - -local getinfo = debug.getinfo -local type, next = type, next -local format, find = string.format, string.find -local is_boolean = string.is_boolean - -debugger = debugger or { } - -local counters = { } -local names = { } - --- one - -local function hook() -    local f = getinfo(2,"f").func -    local n = getinfo(2,"Sn") ---  if n.what == "C" and n.name then print (n.namewhat .. ': ' .. n.name) end -    if f then -        local cf = counters[f] -        if cf == nil then -            counters[f] = 1 -            names[f] = n -        else -            counters[f] = cf + 1 -        end -    end -end - -local function getname(func) -    local n = names[func] -    if n then -        if n.what == "C" then -            return n.name or '<anonymous>' -        else -            -- source short_src linedefined what name namewhat nups func -            local name = n.name or n.namewhat or n.what -            if not name or name == "" then name = "?" end -            return format("%s : %s : %s", n.short_src or "unknown source", n.linedefined or "--", name) -        end -    else -        return "unknown" -    end -end - -function debugger.showstats(printer,threshold) -    printer   = printer or texio.write or print -    threshold = threshold or 0 -    local total, grandtotal, functions = 0, 0, 0 -    printer("\n") -- ugly but ok - -- table.sort(counters) -    for func, count in next, counters do -        if count > threshold then -            local name = getname(func) -            if not find(name,"for generator") then -                printer(format("%8i  %s", count, name)) -                total = total + count -            end -        end -        grandtotal = grandtotal + count -        functions = functions + 1 -    end -    printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold)) -end - --- two - - --- rest - -function debugger.savestats(filename,threshold) -    local f = io.open(filename,'w') -    if f then -        debugger.showstats(function(str) f:write(str) end,threshold) -        f:close() -    end -end - -function debugger.enable() -    debug.sethook(hook,"c") -end - -function debugger.disable() -    debug.sethook() -end - -local function trace_calls(n) -    debugger.enable() -    luatex.register_stop_actions(function() -        debugger.disable() -        debugger.savestats(tex.jobname .. "-luacalls.log",tonumber(n)) -    end) -    trace_calls = function() end -end - -if directives then -    directives.register("system.tracecalls", function(n) trace_calls(n) end) -- indirect is needed for nilling +    d_enable(environment.engineflags.directives)  end - - - -  end -- of closure  do -- create closure to overcome 200 locals limit @@ -4422,7 +4489,8 @@ provide an <l n='xml'/> structured file. Actually, any logging that  is hooked into callbacks will be \XML\ by default.</p>  --ldx]]-- -logs = logs or { } +logs       = logs or { } +local logs = logs  --[[ldx--  <p>This looks pretty ugly but we need to speed things up a bit.</p> @@ -4665,8 +4733,8 @@ function noplog.simple(fmt,...) -- todo: fmt,s      end  end -if utils then -    utils.report = function(...) logs.simple(...) end +if utilities then +    utilities.report = function(...) logs.simple(...) end  end  function logs.setprogram(newname,newbanner) @@ -4736,6 +4804,50 @@ function logs.fatal(where,...)  end +function logs.obsolete(old,new) +    local o = loadstring("return " .. new)() +    if type(o) == "function" then +        return function(...) +            logs.report("system","function %s is obsolete, use %s",old,new) +            loadstring(old .. "=" .. new  .. " return ".. old)()(...) +        end +    elseif type(o) == "table" then +        local t, m = { }, { } +        m.__index = function(t,k) +            logs.report("system","table %s is obsolete, use %s",old,new) +            m.__index, m.__newindex = o, o +            return o[k] +        end +        m.__newindex = function(t,k,v) +            logs.report("system","table %s is obsolete, use %s",old,new) +            m.__index, m.__newindex = o, o +            o[k] = v +        end +        if libraries then +            libraries.obsolete[old] = t -- true +        end +        setmetatable(t,m) +        return t +    end +end + +if tex.error then + +    function logs.texerrormessage(...) -- for the moment we put this function here +        tex.error(format(...), { }) +    end + +else + +    function logs.texerrormessage(...) -- for the moment we put this function here +        local v = format(...) +        tex.sprint(tex.ctxcatcodes,"\\errmessage{") +        tex.sprint(tex.vrbcatcodes,v) +        tex.print(tex.ctxcatcodes,"}") +    end + +end +  end -- of closure @@ -4762,7 +4874,8 @@ local trace_namespaces = false  trackers.register("system.namespaces", function(  local report_system = logs.new("system") -namespaces = { } +namespaces       = namespaces or { } +local namespaces = namespaces  local registered = { } @@ -4932,6 +5045,7 @@ local report_resolvers = logs.new("resolvers")  local format, sub, match, gsub, find = string.format, string.sub, string.match, string.gsub, string.find  local unquote, quote = string.unquote, string.quote +local concat = table.concat  -- precautions @@ -4956,6 +5070,8 @@ end  -- environment  environment             = environment or { } +local environment       = environment +  environment.arguments   = { }  environment.files       = { }  environment.sortedflags = nil @@ -5078,7 +5194,7 @@ function environment.reconstruct_commandline(arg,noquote)                  result[#result+1] = a              end          end -        return table.join(result," ") +        return concat(result," ")      else          return ""      end @@ -5248,6 +5364,7 @@ optimize the code.</p>  --ldx]]--  xml = xml or { } +local xml = xml  local concat, remove, insert = table.concat, table.remove, table.insert @@ -6453,6 +6570,8 @@ of <l n='xpath'/> and since we're not compatible we call it <l n='lpath'/>. We  will explain more about its usage in other documents.</p>  --ldx]]-- +local xml = xml +  local lpathcalls  = 0  function xml.lpathcalls () return lpathcalls  end  local lpathcached = 0  function xml.lpathcached() return lpathcached end @@ -7647,6 +7766,8 @@ local type, next, tonumber, tostring, setmetatable, loadstring = type, next, ton  local format, gsub, match = string.format, string.gsub, string.match  local lpegmatch = lpeg.match +local xml = xml +  --[[ldx--  <p>The following helper functions best belong to the <t>lxml-ini</t>  module. Some are here because we need then in the <t>mk</t> @@ -7748,6 +7869,8 @@ local trace_manipulations = false  trackers.register("lxml.manipulations", funct  local report_xml = logs.new("xml") +local xml = xml +  local xmlparseapply, xmlconvert, xmlcopy, xmlname = xml.parse_apply, xml.convert, xml.copy, xml.name  local xmlinheritedconvert = xml.inheritedconvert @@ -8262,6 +8385,8 @@ if not modules then modules = { } end modules ['lxml-xml'] = {      license   = "see context related readme files"  } +local xml = xml +  local finalizers   = xml.finalizers.xml  local xmlfilter    = xml.filter -- we could inline this one for speed  local xmltostring  = xml.tostring @@ -8588,7 +8713,8 @@ local ostype, osname, ossetenv, osgetenv = os.type, os.name, os.setenv, os.geten  -- we now split it over multiple files. As this file is now the  -- starting point we introduce resolvers here. -resolvers = resolvers or { } +resolvers       = resolvers or { } +local resolvers = resolvers  -- We don't want the kpse library to kick in. Also, we want to be able to  -- execute programs. Control over execution is implemented later. @@ -8812,6 +8938,8 @@ local trace_expansions = false  trackers.register("resolvers.expansions", functi  local report_resolvers = logs.new("resolvers") +local resolvers = resolvers +  -- As this bit of code is somewhat special it gets its own module. After  -- all, when working on the main resolver code, I don't want to scroll  -- past this every time. @@ -9119,6 +9247,8 @@ if not modules then modules = { } end modules ['data-env'] = {      license   = "see context related readme files",  } +local resolvers = resolvers +  local formats      = { }  resolvers.formats      = formats  local suffixes     = { }  resolvers.suffixes     = suffixes  local dangerous    = { }  resolvers.dangerous    = dangerous @@ -9309,11 +9439,13 @@ local mkdirs, isdir = dir.mkdirs, lfs.isdir  local trace_locating = false  trackers.register("resolvers.locating", function(v) trace_locating = v end)  local trace_cache    = false  trackers.register("resolvers.cache",    function(v) trace_cache    = v end) -local report_cache = logs.new("cache") - +local report_cache      = logs.new("cache")  local report_resolvers = logs.new("resolvers") -caches = caches or { } +local resolvers = resolvers + +caches           = caches or { } +local caches     = caches  caches.base      = caches.base or "luatex-cache"  caches.more      = caches.more or "context" @@ -9558,7 +9690,7 @@ function caches.savedata(filepath,filename,data,raw)      end      local cleanup = resolvers.boolean_variable("PURGECACHE", false)      local strip = resolvers.boolean_variable("LUACSTRIP", true) -    utils.lua.compile(tmaname, tmcname, cleanup, strip) +    utilities.lua.compile(tmaname, tmcname, cleanup, strip)  end  -- moved from data-res: @@ -9620,7 +9752,7 @@ function caches.savecontent(cachename,dataname,content)          if trace_locating then              report_resolvers("category '%s', cachename '%s' saved in '%s'",dataname,cachename,luaname)          end -        if utils.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip +        if utilities.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip              if trace_locating then                  report_resolvers("'%s' compiled to '%s'",dataname,lucname)              end @@ -9657,6 +9789,8 @@ local trace_locating   = false  trackers.register("resolvers.locating",   functi  local report_resolvers = logs.new("resolvers") +local resolvers = resolvers +  resolvers.locators     = { notfound = { nil } }  -- locate databases  resolvers.hashers      = { notfound = { nil } }  -- load databases  resolvers.generators   = { notfound = { nil } }  -- generate databases @@ -9713,6 +9847,7 @@ if not modules then modules = { } end modules ['data-res'] = {  local format, gsub, find, lower, upper, match, gmatch = string.format, string.gsub, string.find, string.lower, string.upper, string.match, string.gmatch  local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys  local next, type = next, type +local os = os  local lpegP, lpegS, lpegR, lpegC, lpegCc, lpegCs, lpegCt = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct  local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns @@ -9726,10 +9861,14 @@ local trace_expansions = false  trackers.register("resolvers.expansions", functi  local report_resolvers = logs.new("resolvers") +local resolvers = resolvers +  local expanded_path_from_list  = resolvers.expanded_path_from_list  local checked_variable         = resolvers.checked_variable  local split_configuration_path = resolvers.split_configuration_path +local initializesetter = utilities.setters.initialize +  local ostype, osname, osenv, ossetenv, osgetenv = os.type, os.name, os.env, os.setenv, os.getenv  resolvers.cacheversion = '1.0.1' @@ -9949,7 +10088,7 @@ local function load_configuration_files()                                  t[k] = v                              elseif kind == "table" then                                  -- this operates on the table directly -                                setters.initialize(filename,k,v) +                                initializesetter(filename,k,v)                                  -- this doesn't (maybe metatables some day)                                  for kk, vv in next, v do -- vv = variable                                      if vv ~= unset_variable then @@ -11122,6 +11261,8 @@ if not modules then modules = { } end modules ['data-pre'] = {  local upper, lower, gsub = string.upper, string.lower, string.gsub +local resolvers = resolvers +  local prefixes = { }  local getenv = resolvers.getenv @@ -11235,6 +11376,8 @@ if not modules then modules = { } end modules ['data-inp'] = {      license   = "see context related readme files"  } +local resolvers = resolvers +  resolvers.finders = resolvers.finders or { }  resolvers.openers = resolvers.openers or { }  resolvers.loaders = resolvers.loaders or { } @@ -11256,7 +11399,7 @@ if not modules then modules = { } end modules ['data-out'] = {      license   = "see context related readme files"  } -outputs = outputs or { } +-- not used yet @@ -11291,8 +11434,8 @@ table structures without bothering about the disk cache.</p>  <p>Examples of usage can be found in the font related code.</p>  --ldx]]-- -containers = containers or { } - +containers          = containers or { } +local containers    = containers  containers.usecache = true  local report_cache = logs.new("cache") @@ -11418,6 +11561,8 @@ local trace_locating = false  trackers.register("resolvers.locating", function(v  local report_resolvers = logs.new("resolvers") +local resolvers = resolvers +  -- we will make a better format, maybe something xml or just text or lua  resolvers.automounted = resolvers.automounted or { } @@ -11526,15 +11671,20 @@ local report_resolvers = logs.new("resolvers")  -- zip:///texmf.zip?tree=/tex/texmf-local  -- zip:///texmf-mine.zip?tree=/tex/texmf-projects -zip                 = zip or { } -zip.archives        = zip.archives or { } -zip.registeredfiles = zip.registeredfiles or { } +local resolvers = resolvers + +zip                   = zip or { } +local zip             = zip + +zip.archives          = zip.archives or { } +local archives        = zip.archives + +zip.registeredfiles   = zip.registeredfiles or { } +local registeredfiles = zip.registeredfiles  local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders  local locators, hashers, concatinators = resolvers.locators, resolvers.hashers, resolvers.concatinators -local archives = zip.archives -  local function validzip(str) -- todo: use url splitter      if not find(str,"^zip://") then          return "zip:///" .. str @@ -11698,7 +11848,7 @@ function resolvers.usezipfile(zipname)      zipname = validzip(zipname)      local specification = resolvers.splitmethod(zipname)      local zipfile = specification.path -    if zipfile and not zip.registeredfiles[zipname] then +    if zipfile and not registeredfiles[zipname] then          local tree = url.query(specification.query).tree or ""          local z = zip.openarchive(zipfile)          if z then @@ -11709,7 +11859,7 @@ function resolvers.usezipfile(zipname)              statistics.starttiming(instance)              resolvers.prepend_hash('zip',zipname,zipfile)              resolvers.extend_texmf_var(zipname) -- resets hashes too -            zip.registeredfiles[zipname] = z +            registeredfiles[zipname] = z              instance.files[zipname] = resolvers.register_zip_file(z,tree or "")              statistics.stoptiming(instance)          elseif trace_locating then @@ -11769,6 +11919,8 @@ local unpack = unpack or table.unpack  local report_resolvers = logs.new("resolvers") +local resolvers = resolvers +  local done, found, notfound = { }, { }, resolvers.finders.notfound  function resolvers.finders.tree(specification,filetype) @@ -11851,11 +12003,15 @@ if not modules then modules = { } end modules ['data-crl'] = {  -- this one is replaced by data-sch.lua -- -curl = curl or { } -  local gsub = string.gsub + +local resolvers = resolvers +  local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders +curl = curl or { } +local curl = curl +  local cached = { }  function curl.fetch(protocol, name) -- todo: use socket library @@ -11925,6 +12081,8 @@ local report_resolvers = logs.new("resolvers")  local gsub, insert = string.gsub, table.insert  local unpack = unpack or table.unpack +local resolvers, package = resolvers, package +  local  libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -- 'luainputs'  local clibformats = { 'lib' } @@ -12079,6 +12237,8 @@ local type, next = type, next  local trace_locating = false  trackers.register("resolvers.locating", function(v) trace_locating = v end) +local resolvers = resolvers +  local report_resolvers = logs.new("resolvers")  function resolvers.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix @@ -12140,6 +12300,8 @@ if not modules then modules = { } end modules ['data-tmf'] = {      license   = "see context related readme files"  } +local resolvers = resolvers +  --  =  <<  --  ?  ??  --  <  += @@ -12209,6 +12371,8 @@ local find, concat, upper, format = string.find, table.concat, string.upper, str  resolvers.listers = resolvers.listers or { } +local resolvers = resolvers +  local function tabstr(str)      if type(str) == 'table' then          return concat(str," | ") @@ -12258,9 +12422,15 @@ if not modules then modules = { } end modules ['luat-sta'] = {  local gmatch, match = string.gmatch, string.match  local type = type -states          = states          or { } -states.data     = states.data     or { } -states.hash     = states.hash     or { } +states          = states or { } +local states    = states + +states.data     = states.data or { } +local data      = states.data + +states.hash     = states.hash or { } +local hash      = states.hash +  states.tag      = states.tag      or ""  states.filename = states.filename or "" @@ -12270,7 +12440,7 @@ function states.save(filename,tag)      io.savedata(filename,          "-- generator : luat-sta.lua\n" ..          "-- state tag : " .. tag .. "\n\n" .. -        table.serialize(states.data[tag or states.tag] or {},true) +        table.serialize(data[tag or states.tag] or {},true)      )  end @@ -12278,11 +12448,11 @@ function states.load(filename,tag)      states.filename = filename      states.tag = tag or "whatever"      states.filename = file.addsuffix(states.filename,'lus') -    states.data[states.tag], states.hash[states.tag] = (io.exists(filename) and dofile(filename)) or { }, { } +    data[states.tag], hash[states.tag] = (io.exists(filename) and dofile(filename)) or { }, { }  end -function states.set_by_tag(tag,key,value,default,persistent) -    local d, h = states.data[tag], states.hash[tag] +local function set_by_tag(tag,key,value,default,persistent) +    local d, h = data[tag], hash[tag]      if d then          if type(d) == "table" then              local dkey, hkey = key, key @@ -12312,17 +12482,17 @@ function states.set_by_tag(tag,key,value,default,persistent)              d[dkey], h[hkey] = value, value          elseif type(d) == "string" then              -- weird -            states.data[tag], states.hash[tag] = value, value +            data[tag], hash[tag] = value, value          end      end  end -function states.get_by_tag(tag,key,default) -    local h = states.hash[tag] +local function get_by_tag(tag,key,default) +    local h = hash[tag]      if h and h[key] then          return h[key]      else -        local d = states.data[tag] +        local d = data[tag]          if d then              for k in gmatch(key,"[^%.]+") do                  local dk = d[k] @@ -12337,12 +12507,15 @@ function states.get_by_tag(tag,key,default)      end  end +states.set_by_tag = set_by_tag +states.get_by_tag = get_by_tag +  function states.set(key,value,default,persistent) -    states.set_by_tag(states.tag,key,value,default,persistent) +    set_by_tag(states.tag,key,value,default,persistent)  end  function states.get(key,default) -    return states.get_by_tag(states.tag,key,default) +    return get_by_tag(states.tag,key,default)  end @@ -12422,10 +12595,10 @@ function environment.make_format(name)          local lucstubname = file.addsuffix(texbasename,"luc")          -- pack libraries in stub          logs.simple("creating initialization file: %s",luastubname) -        utils.merger.selfcreate(usedlualibs,specificationpath,luastubname) +        utilities.merger.selfcreate(usedlualibs,specificationpath,luastubname)          -- compile stub file (does not save that much as we don't use this stub at startup any more)          local strip = resolvers.boolean_variable("LUACSTRIP", true) -        if utils.lua.compile(luastubname,lucstubname,false,strip) and lfs.isfile(lucstubname) then +        if utilities.lua.compile(luastubname,lucstubname,false,strip) and lfs.isfile(lucstubname) then              logs.simple("using compiled initialization file: %s",lucstubname)              usedluastub = lucstubname          else @@ -12507,12 +12680,16 @@ own.libs = { -- order can be made better      'l-boolean.lua',      'l-unicode.lua',      'l-math.lua', -    'l-utils.lua', -    'l-aux.lua', + +    'util-mrg.lua', +    'util-lua.lua', +    'util-prs.lua', +    'util-tab.lua', +    'util-fmt.lua', +    'util-deb.lua',      'trac-inf.lua',      'trac-set.lua', -    'trac-tra.lua',      'trac-log.lua',      'trac-pro.lua',      'luat-env.lua', -- can come before inf (as in mkiv) @@ -12524,7 +12701,6 @@ own.libs = { -- order can be made better      'lxml-aux.lua',      'lxml-xml.lua', -      'data-ini.lua',      'data-exp.lua',      'data-env.lua', @@ -12589,6 +12765,7 @@ local function locate_libs()              local filename = pth .. "/" .. lib              local found = lfs.isfile(filename)              if found then +                package.path = package.path .. ";" .. pth .. "/?.lua" -- in case l-* does a require                  return pth              end          end @@ -13326,7 +13503,7 @@ if environment.argument("selfmerge") then      runners.loadbase()      local found = locate_libs()      if found then -        utils.merger.selfmerge(own.name,own.libs,{ found }) +        utilities.merger.selfmerge(own.name,own.libs,{ found })      end  elseif environment.argument("selfclean") then @@ -13334,7 +13511,7 @@ elseif environment.argument("selfclean") then      -- remove embedded libraries      runners.loadbase() -    utils.merger.selfclean(own.name) +    utilities.merger.selfclean(own.name)  elseif environment.argument("selfupdate") then @@ -13599,6 +13776,7 @@ elseif false then  else +    runners.loadbase()      runners.execute_ctx_script("mtx-base",filename)  end diff --git a/scripts/context/ruby/base/tex.rb b/scripts/context/ruby/base/tex.rb index e89a88060..5c9fa2c98 100644 --- a/scripts/context/ruby/base/tex.rb +++ b/scripts/context/ruby/base/tex.rb @@ -362,9 +362,9 @@ class TEX              end          rescue          end -        ['mpgraph.mp'].each do |file| -            (File.delete(file) if (FileTest.size?(file) rescue 10) < 10) rescue false -        end +        # ['mpgraph.mp'].each do |file| +            # (File.delete(file) if (FileTest.size?(file) rescue 10) < 10) rescue false +        # end      end      def backends() @@backends.keys.sort end diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua index 68ee3d2c1..ef6ccbfb6 100644 --- a/scripts/context/stubs/mswin/mtxrun.lua +++ b/scripts/context/stubs/mswin/mtxrun.lua @@ -52,6 +52,7 @@ if not modules then modules = { } end modules ['l-string'] = {      license   = "see context related readme files"  } +local string = string  local sub, gsub, find, match, gmatch, format, char, byte, rep, lower = string.sub, string.gsub, string.find, string.match, string.gmatch, string.format, string.char, string.byte, string.rep, string.lower  local lpegmatch = lpeg.match @@ -199,11 +200,6 @@ end  string.padd = string.rpadd -function is_number(str) -- tonumber -    return find(str,"^[%-%+]?[%d]-%.?[%d+]$") == 1 -end - -  function string:split_settings() -- no {} handling, see l-aux for lpeg variant      if find(self,"=") then          local t = { } @@ -547,12 +543,10 @@ if not modules then modules = { } end modules ['l-table'] = {      license   = "see context related readme files"  } -table.join = table.concat - +local type, next, tostring, tonumber, ipairs, table, string = type, next, tostring, tonumber, ipairs, table, string  local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove  local format, find, gsub, lower, dump, match = string.format, string.find, string.gsub, string.lower, string.dump, string.match  local getmetatable, setmetatable = getmetatable, setmetatable -local type, next, tostring, tonumber, ipairs = type, next, tostring, tonumber, ipairs  -- Starting with version 5.2 Lua no longer provide ipairs, which makes  -- sense. As we already used the for loop and # in most places the @@ -1452,7 +1446,9 @@ if not modules then modules = { } end modules ['l-io'] = {      license   = "see context related readme files"  } -local byte, find, gsub = string.byte, string.find, string.gsub +local io = io +local byte, find, gsub, format = string.byte, string.find, string.gsub, string.format +local concat = table.concat  if string.find(os.getenv("PATH"),";") then      io.fileseparator, io.pathseparator = "\\", ";" @@ -1463,9 +1459,7 @@ end  function io.loaddata(filename,textmode)      local f = io.open(filename,(textmode and 'r') or 'rb')      if f then -    --  collectgarbage("step") -- sometimes makes a big difference in mem consumption          local data = f:read('*all') -    --  garbagecollector.check(data)          f:close()          return data      else @@ -1477,7 +1471,7 @@ function io.savedata(filename,data,joiner)      local f = io.open(filename,"wb")      if f then          if type(data) == "table" then -            f:write(table.join(data,joiner or "")) +            f:write(concat(data,joiner or ""))          elseif type(data) == "function" then              data(f)          else @@ -1603,12 +1597,12 @@ function io.ask(question,default,options)      while true do          io.write(question)          if options then -            io.write(string.format(" [%s]",table.concat(options,"|"))) +            io.write(format(" [%s]",concat(options,"|")))          end          if default then -            io.write(string.format(" [%s]",default)) +            io.write(format(" [%s]",default))          end -        io.write(string.format(" ")) +        io.write(format(" "))          local answer = io.read()          answer = gsub(answer,"^%s*(.*)%s*$","%1")          if answer == "" and default then @@ -1682,7 +1676,8 @@ local tostring = tostring  local format, floor, insert, match = string.format, math.floor, table.insert, string.match  local lpegmatch = lpeg.match -number = number or { } +number       = number or { } +local number = number  -- a,b,c,d,e,f = number.toset(100101) @@ -1759,6 +1754,8 @@ if not modules then modules = { } end modules ['l-set'] = {      license   = "see context related readme files"  } +-- This will become obsolete when we have the bitset library embedded. +  set = set or { }  local nums   = { } @@ -1840,10 +1837,10 @@ if not modules then modules = { } end modules ['l-os'] = {  -- maybe build io.flush in os.execute +local os = os  local find, format, gsub, upper = string.find, string.format, string.gsub, string.upper  local random, ceil = math.random, math.ceil  local rawget, rawset, type, getmetatable, setmetatable, tonumber = rawget, rawset, type, getmetatable, setmetatable, tonumber -local rawget, rawset, type, getmetatable, setmetatable, tonumber = rawget, rawset, type, getmetatable, setmetatable, tonumber  -- The following code permits traversing the environment table, at least  -- in luatex. Internally all environment names are uppercase. @@ -2193,12 +2190,15 @@ if not modules then modules = { } end modules ['l-file'] = {  -- needs a cleanup  file = file or { } +local file = file  local insert, concat = table.insert, table.concat  local find, gmatch, match, gsub, sub, char = string.find, string.gmatch, string.match, string.gsub, string.sub, string.char  local lpegmatch = lpeg.match  local getcurrentdir = lfs.currentdir +local P, R, S, C, Cs, Cp, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Cp, lpeg.Cc +  local function dirname(name,default)      return match(name,"^(.+)[/\\].-$") or (default or "")  end @@ -2416,11 +2416,11 @@ end  -- also rewrite previous -local letter    = lpeg.R("az","AZ") + lpeg.S("_-+") -local separator = lpeg.P("://") +local letter    = R("az","AZ") + S("_-+") +local separator = P("://") -local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator + letter^1 * lpeg.P("/") -local rootbased = lpeg.P("/") + letter*lpeg.P(":") +local qualified = P(".")^0 * P("/") + letter*P(":") + letter^1*separator + letter^1 * P("/") +local rootbased = P("/") + letter*P(":")  -- ./name ../name  /name c: :// name/name @@ -2432,14 +2432,16 @@ function file.is_rootbased_path(filename)      return lpegmatch(rootbased,filename) ~= nil  end -local slash  = lpeg.S("\\/") -local period = lpeg.P(".") -local drive  = lpeg.C(lpeg.R("az","AZ")) * lpeg.P(":") -local path   = lpeg.C(((1-slash)^0 * slash)^0) -local suffix = period * lpeg.C(lpeg.P(1-period)^0 * lpeg.P(-1)) -local base   = lpeg.C((1-suffix)^0) +-- actually these are schemes + +local slash  = S("\\/") +local period = P(".") +local drive  = C(R("az","AZ")) * P(":") +local path   = C(((1-slash)^0 * slash)^0) +local suffix = period * C(P(1-period)^0 * P(-1)) +local base   = C((1-suffix)^0) -local pattern = (drive + lpeg.Cc("")) * (path + lpeg.Cc("")) * (base + lpeg.Cc("")) * (suffix + lpeg.Cc("")) +local pattern = (drive + Cc("")) * (path + Cc("")) * (base + Cc("")) * (suffix + Cc(""))  function file.splitname(str) -- returns drive, path, base, suffix      return lpegmatch(pattern,str) @@ -2467,6 +2469,7 @@ if not modules then modules = { } end modules ['l-md5'] = {  -- This also provides file checksums and checkers. +local md5, file = md5, file  local gsub, format, byte = string.gsub, string.format, string.byte  local function convert(str,fmt) @@ -2547,7 +2550,8 @@ local lpegmatch, lpegP, lpegC, lpegR, lpegS, lpegCs, lpegCc = lpeg.match, lpeg.P  --     / \ /                        \  --     urn:example:animal:ferret:nose -url = url or { } +url       = url or { } +local url = url  local function tochar(s)      return char(tonumber(s,16)) @@ -2687,20 +2691,30 @@ if not modules then modules = { } end modules ['l-dir'] = {  local type = type  local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub +local concat = table.concat  local lpegmatch = lpeg.match +local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V +  dir = dir or { } +local dir = dir +local lfs = lfs + +local attributes = lfs.attributes +local walkdir    = lfs.dir +local isdir      = lfs.isdir +local isfile     = lfs.isfile +local mkdir      = lfs.mkdir +local chdir      = lfs.chdir +local currentdir = lfs.currentdir  -- handy  function dir.current() -    return (gsub(lfs.currentdir(),"\\","/")) +    return (gsub(currentdir(),"\\","/"))  end --- optimizing for no string.find (*) does not save time - -local attributes = lfs.attributes -local walkdir    = lfs.dir +-- optimizing for no find (*) does not save time  local function glob_pattern(path,patt,recurse,action)      local ok, scanner @@ -2756,8 +2770,6 @@ end  dir.collect_pattern = collect_pattern -local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V -  local pattern = Ct {      [1] = (C(P(".") + P("/")^1) + C(R("az","AZ") * P(":") * P("/")^0) + Cc("./")) * V(2) * V(3),      [2] = C(((1-S("*?/"))^0 * P("/"))^0), @@ -2780,7 +2792,7 @@ local function glob(str,t)              for s=1,#str do                  glob(str[s],t)              end -        elseif lfs.isfile(str) then +        elseif isfile(str) then              t(str)          else              local split = lpegmatch(pattern,str) @@ -2799,7 +2811,7 @@ local function glob(str,t)                  glob(str[s],t)              end              return t -        elseif lfs.isfile(str) then +        elseif isfile(str) then              local t = t or { }              t[#t+1] = str              return t @@ -2863,13 +2875,13 @@ dir.globfiles = globfiles  -- print(dir.ls("*.tex"))  function dir.ls(pattern) -    return table.concat(glob(pattern),"\n") +    return concat(glob(pattern),"\n")  end  local make_indeed = true -- false -if string.find(os.getenv("PATH"),";") then -- os.type == "windows" +if find(os.getenv("PATH"),";") then -- os.type == "windows"      function dir.mkdirs(...)          local str, pth, t = "", "", { ... } @@ -2918,11 +2930,11 @@ if string.find(os.getenv("PATH"),";") then -- os.type == "windows"              else                  pth = pth .. "/" .. s              end -            if make_indeed and not lfs.isdir(pth) then -                lfs.mkdir(pth) +            if make_indeed and not isdir(pth) then +                mkdir(pth)              end          end -        return pth, (lfs.isdir(pth) == true) +        return pth, (isdir(pth) == true)      end @@ -2937,11 +2949,11 @@ if string.find(os.getenv("PATH"),";") then -- os.type == "windows"          if not first then              first, last = match(str,"^([a-zA-Z]:)(.*)$")              if first and not find(last,"^/") then -                local d = lfs.currentdir() -                if lfs.chdir(first) then +                local d = currentdir() +                if chdir(first) then                      first = dir.current()                  end -                lfs.chdir(d) +                chdir(d)              end          end          if not first then @@ -2982,26 +2994,26 @@ else                  else                      pth = pth .. "/" .. s                  end -                if make_indeed and not first and not lfs.isdir(pth) then -                    lfs.mkdir(pth) +                if make_indeed and not first and not isdir(pth) then +                    mkdir(pth)                  end              end          else              pth = "."              for s in gmatch(str,"[^/]+") do                  pth = pth .. "/" .. s -                if make_indeed and not lfs.isdir(pth) then -                    lfs.mkdir(pth) +                if make_indeed and not isdir(pth) then +                    mkdir(pth)                  end              end          end -        return pth, (lfs.isdir(pth) == true) +        return pth, (isdir(pth) == true)      end      function dir.expand_name(str) -- will be merged with cleanpath and collapsepath          if not find(str,"^/") then -            str = lfs.currentdir() .. "/" .. str +            str = currentdir() .. "/" .. str          end          str = gsub(str,"//","/")          str = gsub(str,"/%./","/") @@ -3025,10 +3037,11 @@ if not modules then modules = { } end modules ['l-boolean'] = {      license   = "see context related readme files"  } -boolean = boolean or { } -  local type, tonumber = type, tonumber +boolean = boolean or { } +local boolean = boolean +  function boolean.tonumber(b)      if b then return 1 else return 0 end  end @@ -3109,6 +3122,8 @@ if not unicode then  end +local unicode = unicode +  utf = utf or unicode.utf8  local concat, utfchar, utfgsub = table.concat, utf.char, utf.gsub @@ -3280,7 +3295,7 @@ end  function unicode.utfcodes(str)      local t = { } -    for k,v in string.utfvalues(str) do +    for k,v in utfvalues(str) do          t[#t+1] = format("0x%04X",k)      end      return concat(t,separator or " ") @@ -3339,7 +3354,7 @@ end -- of closure  do -- create closure to overcome 200 locals limit -if not modules then modules = { } end modules ['l-utils'] = { +if not modules then modules = { } end modules ['util-mrg'] = {      version   = 1.001,      comment   = "companion to luat-lib.mkiv",      author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -3353,13 +3368,11 @@ local gsub, format = string.gsub, string.format  local concat = table.concat  local type, next = type, next -if not utils        then utils        = { } end -if not utils.merger then utils.merger = { } end -if not utils.lua    then utils.lua    = { } end - -utils.report = utils.report or print +utilities        = utilities or {} +utilities.merger = utilities.merger or { } +utilities.report = utilities.report or print -local merger = utils.merger +local merger     = utilities.merger  merger.strip_comment = true @@ -3396,9 +3409,9 @@ end  local function self_load(name)      local data = io.loaddata(name) or ""      if data == "" then -        utils.report("merge: unknown file %s",name) +        utilities.report("merge: unknown file %s",name)      else -        utils.report("merge: inserting %s",name) +        utilities.report("merge: inserting %s",name)      end      return data or ""  end @@ -3409,10 +3422,10 @@ local function self_save(name, data)              -- saves some 20K              local n = #data              data = gsub(data,"%-%-~[^\n\r]*[\r\n]","") -            utils.report("merge: %s bytes of comment stripped, %s bytes of code left",n-#data,#data) +            utilities.report("merge: %s bytes of comment stripped, %s bytes of code left",n-#data,#data)          end          io.savedata(name,data) -        utils.report("merge: saving %s",name) +        utilities.report("merge: saving %s",name)      end  end @@ -3429,7 +3442,7 @@ local function self_libs(libs,list)          local lib = libs[i]          for j=1,#list do              local pth = gsub(list[j],"\\","/") -- file.clean_path -            utils.report("merge: checking library path %s",pth) +            utilities.report("merge: checking library path %s",pth)              local name = pth .. "/" .. lib              if lfs.isfile(name) then                  foundpath = pth @@ -3438,30 +3451,30 @@ local function self_libs(libs,list)          if foundpath then break end      end      if foundpath then -        utils.report("merge: using library path %s",foundpath) +        utilities.report("merge: using library path %s",foundpath)          local right, wrong = { }, { }          for i=1,#libs do              local lib = libs[i]              local fullname = foundpath .. "/" .. lib              if lfs.isfile(fullname) then -                utils.report("merge: using library %s",fullname) +                utilities.report("merge: using library %s",fullname)                  right[#right+1] = lib                  result[#result+1] = m_begin_closure                  result[#result+1] = io.loaddata(fullname,true)                  result[#result+1] = m_end_closure              else -                utils.report("merge: skipping library %s",fullname) +                utilities.report("merge: skipping library %s",fullname)                  wrong[#wrong+1] = lib              end          end          if #right > 0 then -            utils.report("merge: used libraries: %s",concat(right," ")) +            utilities.report("merge: used libraries: %s",concat(right," "))          end          if #wrong > 0 then -            utils.report("merge: skipped libraries: %s",concat(wrong," ")) +            utilities.report("merge: skipped libraries: %s",concat(wrong," "))          end      else -        utils.report("merge: no valid library path found") +        utilities.report("merge: no valid library path found")      end      return concat(result, "\n\n")  end @@ -3480,8 +3493,25 @@ function merger.selfclean(name)      self_save(name,self_swap(self_load(name),self_nothing()))  end -function utils.lua.compile(luafile,lucfile,cleanup,strip) -- defaults: cleanup=false strip=true -    utils.report("lua: compiling %s into %s",luafile,lucfile) + +end -- of closure + +do -- create closure to overcome 200 locals limit + +if not modules then modules = { } end modules ['util-lua'] = { +    version   = 1.001, +    comment   = "companion to luat-lib.mkiv", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} + +utilities        = utilities or {} +utilities.lua    = utilities.merger or { } +utilities.report = utilities.report or print + +function utilities.lua.compile(luafile,lucfile,cleanup,strip) -- defaults: cleanup=false strip=true +    utilities.report("lua: compiling %s into %s",luafile,lucfile)      os.remove(lucfile)      local command = "-o " .. string.quote(lucfile) .. " " .. string.quote(luafile)      if strip ~= false then @@ -3489,7 +3519,7 @@ function utils.lua.compile(luafile,lucfile,cleanup,strip) -- defaults: cleanup=f      end      local done = os.spawn("texluac " .. command) == 0 or os.spawn("luac " .. command) == 0      if done and cleanup == true and lfs.isfile(lucfile) and lfs.isfile(luafile) then -        utils.report("lua: removing %s",luafile) +        utilities.report("lua: removing %s",luafile)          os.remove(luafile)      end      return done @@ -3501,7 +3531,7 @@ end -- of closure  do -- create closure to overcome 200 locals limit -if not modules then modules = { } end modules ['l-aux'] = { +if not modules then modules = { } end modules ['util-prs'] = {      version   = 1.001,      comment   = "companion to luat-lib.mkiv",      author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -3509,15 +3539,16 @@ if not modules then modules = { } end modules ['l-aux'] = {      license   = "see context related readme files"  } --- for inline, no store split : for s in string.gmatch(str,",* *([^,]+)") do .. end - -aux = aux or { } +utilities         = utilities or {} +utilities.parsers = utilities.parsers or { } +local parsers     = utilities.parsers +parsers.patterns  = parsers.patterns or { } +local P, R, V, C, Ct, Carg = lpeg.P, lpeg.R, lpeg.V, lpeg.C, lpeg.Ct, lpeg.Carg +local lpegmatch = lpeg.match  local concat, format, gmatch = table.concat, string.format, string.gmatch  local tostring, type = tostring, type -local lpegmatch = lpeg.match - -local P, R, V = lpeg.P, lpeg.R, lpeg.V +local sortedhash = table.sortedhash  local escape, left, right = P("\\"), P('{'), P('}') @@ -3526,23 +3557,23 @@ lpeg.patterns.balanced = P {      [2] = left * V(1) * right  } -local space     = lpeg.P(' ') -local equal     = lpeg.P("=") -local comma     = lpeg.P(",") -local lbrace    = lpeg.P("{") -local rbrace    = lpeg.P("}") +local space     = P(' ') +local equal     = P("=") +local comma     = P(",") +local lbrace    = P("{") +local rbrace    = P("}")  local nobrace   = 1 - (lbrace+rbrace) -local nested    = lpeg.P { lbrace * (nobrace + lpeg.V(1))^0 * rbrace } +local nested    = P { lbrace * (nobrace + V(1))^0 * rbrace }  local spaces    = space^0 -local value     = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0) +local value     = P(lbrace * C((nobrace + nested)^0) * rbrace) + C((nested + (1-comma))^0) -local key       = lpeg.C((1-equal-comma)^1) -local pattern_a = (space+comma)^0 * (key * equal * value + key * lpeg.C("")) +local key       = C((1-equal-comma)^1) +local pattern_a = (space+comma)^0 * (key * equal * value + key * C(""))  local pattern_c = (space+comma)^0 * (key * equal * value) -local key       = lpeg.C((1-space-equal-comma)^1) -local pattern_b = spaces * comma^0 * spaces * (key * ((spaces * equal * spaces * value) + lpeg.C(""))) +local key       = C((1-space-equal-comma)^1) +local pattern_b = spaces * comma^0 * spaces * (key * ((spaces * equal * spaces * value) + C("")))  -- "a=1, b=2, c=3, d={a{b,c}d}, e=12345, f=xx{a{b,c}d}xx, g={}" : outer {} removes, leading spaces ignored @@ -3556,11 +3587,11 @@ local pattern_a_s = (pattern_a/set)^1  local pattern_b_s = (pattern_b/set)^1  local pattern_c_s = (pattern_c/set)^1 -aux.settings_to_hash_pattern_a = pattern_a_s -aux.settings_to_hash_pattern_b = pattern_b_s -aux.settings_to_hash_pattern_c = pattern_c_s +parsers.patterns.settings_to_hash_a = pattern_a_s +parsers.patterns.settings_to_hash_b = pattern_b_s +parsers.patterns.settings_to_hash_c = pattern_c_s -function aux.make_settings_to_hash_pattern(set,how) +function parsers.make_settings_to_hash_pattern(set,how)      if how == "strict" then          return (pattern_c/set)^1      elseif how == "tolerant" then @@ -3570,7 +3601,7 @@ function aux.make_settings_to_hash_pattern(set,how)      end  end -function aux.settings_to_hash(str,existing) +function parsers.settings_to_hash(str,existing)      if str and str ~= "" then          hash = existing or { }          lpegmatch(pattern_a_s,str) @@ -3580,7 +3611,7 @@ function aux.settings_to_hash(str,existing)      end  end -function aux.settings_to_hash_tolerant(str,existing) +function parsers.settings_to_hash_tolerant(str,existing)      if str and str ~= "" then          hash = existing or { }          lpegmatch(pattern_b_s,str) @@ -3590,7 +3621,7 @@ function aux.settings_to_hash_tolerant(str,existing)      end  end -function aux.settings_to_hash_strict(str,existing) +function parsers.settings_to_hash_strict(str,existing)      if str and str ~= "" then          hash = existing or { }          lpegmatch(pattern_c_s,str) @@ -3601,16 +3632,16 @@ function aux.settings_to_hash_strict(str,existing)  end  local separator = comma * space^0 -local value     = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0) -local pattern   = lpeg.Ct(value*(separator*value)^0) +local value     = P(lbrace * C((nobrace + nested)^0) * rbrace) + C((nested + (1-comma))^0) +local pattern   = Ct(value*(separator*value)^0)  -- "aap, {noot}, mies" : outer {} removes, leading spaces ignored -aux.settings_to_array_pattern = pattern +parsers.patterns.settings_to_array = pattern  -- we could use a weak table as cache -function aux.settings_to_array(str) +function parsers.settings_to_array(str)      if not str or str == "" then          return { }      else @@ -3622,14 +3653,14 @@ local function set(t,v)      t[#t+1] = v  end -local value   = lpeg.P(lpeg.Carg(1)*value) / set -local pattern = value*(separator*value)^0 * lpeg.Carg(1) +local value   = P(Carg(1)*value) / set +local pattern = value*(separator*value)^0 * Carg(1) -function aux.add_settings_to_array(t,str) +function parsers.add_settings_to_array(t,str)      return lpegmatch(pattern,str,nil,t)  end -function aux.hash_to_string(h,separator,yes,no,strict,omit) +function parsers.hash_to_string(h,separator,yes,no,strict,omit)      if h then          local t, s = { }, table.sortedkeys(h)          omit = omit and table.tohash(omit) @@ -3658,7 +3689,7 @@ function aux.hash_to_string(h,separator,yes,no,strict,omit)      end  end -function aux.array_to_string(a,separator) +function parsers.array_to_string(a,separator)      if a then          return concat(a,separator or ",")      else @@ -3666,7 +3697,7 @@ function aux.array_to_string(a,separator)      end  end -function aux.settings_to_set(str,t) -- tohash? +function parsers.settings_to_set(str,t) -- tohash? -- todo: lpeg -- duplicate anyway      t = t or { }      for s in gmatch(str,"%s*([^, ]+)") do -- space added          t[s] = true @@ -3674,9 +3705,9 @@ function aux.settings_to_set(str,t) -- tohash?      return t  end -function aux.simple_hash_to_string(h, separator) +function parsers.simple_hash_to_string(h, separator)      local t = { } -    for k, v in table.sortedhash(h) do +    for k, v in sortedhash(h) do          if v then              t[#t+1] = k          end @@ -3684,43 +3715,44 @@ function aux.simple_hash_to_string(h, separator)      return concat(t,separator or ",")  end -local value     = lbrace * lpeg.C((nobrace + nested)^0) * rbrace -local pattern   = lpeg.Ct((space + value)^0) +local value   = lbrace * C((nobrace + nested)^0) * rbrace +local pattern = Ct((space + value)^0) -function aux.arguments_to_table(str) +function parsers.arguments_to_table(str)      return lpegmatch(pattern,str)  end --- temporary here +-- temporary here (unoptimized) -function aux.getparameters(self,class,parentclass,settings) +function parsers.getparameters(self,class,parentclass,settings)      local sc = self[class]      if not sc then          sc = table.clone(self[parent])          self[class] = sc      end -    aux.settings_to_hash(settings,sc) +    parsers.settings_to_hash(settings,sc)  end --- temporary here -local digit         = lpeg.R("09") -local period        = lpeg.P(".") -local zero          = lpeg.P("0") -local trailingzeros = zero^0 * -digit -- suggested by Roberto R -local case_1        = period * trailingzeros / "" -local case_2        = period * (digit - trailingzeros)^1 * (trailingzeros / "") -local number        = digit^1 * (case_1 + case_2) -local stripper      = lpeg.Cs((number + 1)^0) +end -- of closure +do -- create closure to overcome 200 locals limit -lpeg.patterns.strip_zeros = stripper +if not modules then modules = { } end modules ['util-tab'] = { +    version   = 1.001, +    comment   = "companion to luat-lib.mkiv", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} -function aux.strip_zeros(str) -    return lpegmatch(stripper,str) -end +utilities        = utilities or {} +utilities.tables = utilities.tables or { } +local tables     = utilities.tables + +local concat, format, gmatch = table.concat, string.format, string.gmatch -function aux.definetable(target) -- defines undefined tables +function tables.definetable(target) -- defines undefined tables      local composed, t = nil, { }      for name in gmatch(target,"([^%.]+)") do          if composed then @@ -3733,7 +3765,7 @@ function aux.definetable(target) -- defines undefined tables      return concat(t,"\n")  end -function aux.accesstable(target) +function tables.accesstable(target)      local t = _G      for name in gmatch(target,"([^%.]+)") do          t = t[name] @@ -3742,10 +3774,48 @@ function aux.accesstable(target)  end --- as we use this a lot ... +end -- of closure + +do -- create closure to overcome 200 locals limit + +if not modules then modules = { } end modules ['util-fmt'] = { +    version   = 1.001, +    comment   = "companion to luat-lib.mkiv", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} + +utilities            = utilities or { } +utilities.formatters = utilities.formatters or { } +local formatters     = utilities.formatters + +local concat, format = table.concat, string.format +local tostring, type = tostring, type +local strip = string.strip + +local P, R, Cs = lpeg.P, lpeg.R, lpeg.Cs +local lpegmatch = lpeg.match +-- temporary here -function aux.formatcolumns(result,between) +local digit         = R("09") +local period        = P(".") +local zero          = P("0") +local trailingzeros = zero^0 * -digit -- suggested by Roberto R +local case_1        = period * trailingzeros / "" +local case_2        = period * (digit - trailingzeros)^1 * (trailingzeros / "") +local number        = digit^1 * (case_1 + case_2) +local stripper      = Cs((number + 1)^0) + + +lpeg.patterns.strip_zeros = stripper + +function formatters.strip_zeros(str) +    return lpegmatch(stripper,str) +end + +function formatters.formatcolumns(result,between)      if result and #result > 0 then          between = between or "   "          local widths, numbers = { }, { } @@ -3790,10 +3860,10 @@ function aux.formatcolumns(result,between)                  end              end          end -        local template = string.strip(concat(widths)) +        local template = strip(concat(widths))          for i=1,#result do              local str = format(template,unpack(result[i])) -            result[i] = string.strip(str) +            result[i] = strip(str)          end      end      return result @@ -3804,6 +3874,115 @@ end -- of closure  do -- create closure to overcome 200 locals limit +if not modules then modules = { } end modules ['util.deb'] = { +    version   = 1.001, +    comment   = "companion to luat-lib.mkiv", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} + +-- the <anonymous> tag is kind of generic and used for functions that are not +-- bound to a variable, like node.new, node.copy etc (contrary to for instance +-- node.has_attribute which is bound to a has_attribute local variable in mkiv) + +local debug = require "debug" + +local getinfo = debug.getinfo +local type, next = type, next +local format, find = string.format, string.find +local is_boolean = string.is_boolean + +utilities          = utilities or { } +utilities.debugger = utilities.debugger or { } +local debugger     = utilities.debugger + +local counters = { } +local names    = { } + +-- one + +local function hook() +    local f = getinfo(2,"f").func +    local n = getinfo(2,"Sn") +--  if n.what == "C" and n.name then print (n.namewhat .. ': ' .. n.name) end +    if f then +        local cf = counters[f] +        if cf == nil then +            counters[f] = 1 +            names[f] = n +        else +            counters[f] = cf + 1 +        end +    end +end + +local function getname(func) +    local n = names[func] +    if n then +        if n.what == "C" then +            return n.name or '<anonymous>' +        else +            -- source short_src linedefined what name namewhat nups func +            local name = n.name or n.namewhat or n.what +            if not name or name == "" then name = "?" end +            return format("%s : %s : %s", n.short_src or "unknown source", n.linedefined or "--", name) +        end +    else +        return "unknown" +    end +end + +function debugger.showstats(printer,threshold) +    printer   = printer or texio.write or print +    threshold = threshold or 0 +    local total, grandtotal, functions = 0, 0, 0 +    printer("\n") -- ugly but ok + -- table.sort(counters) +    for func, count in next, counters do +        if count > threshold then +            local name = getname(func) +            if not find(name,"for generator") then +                printer(format("%8i  %s", count, name)) +                total = total + count +            end +        end +        grandtotal = grandtotal + count +        functions = functions + 1 +    end +    printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold)) +end + +-- two + + +-- rest + +function debugger.savestats(filename,threshold) +    local f = io.open(filename,'w') +    if f then +        debugger.showstats(function(str) f:write(str) end,threshold) +        f:close() +    end +end + +function debugger.enable() +    debug.sethook(hook,"c") +end + +function debugger.disable() +    debug.sethook() +end + + + + + + +end -- of closure + +do -- create closure to overcome 200 locals limit +  if not modules then modules = { } end modules ['trac-inf'] = {      version   = 1.001,      comment   = "companion to trac-inf.mkiv", @@ -3820,14 +3999,13 @@ if not modules then modules = { } end modules ['trac-inf'] = {  local format = string.format  local clock = os.gettimeofday or os.clock -- should go in environment -local statusinfo, n, registered = { }, 0, { } - -statistics = statistics or { } +statistics       = statistics or { } +local statistics = statistics  statistics.enable    = true  statistics.threshold = 0.05 -local timers = { } +local statusinfo, n, registered, timers = { }, 0, { }, { }  local function hastiming(instance)      return instance and timers[instance] @@ -3995,7 +4173,7 @@ end -- of closure  do -- create closure to overcome 200 locals limit -if not modules then modules = { } end modules ['trac-set'] = { +if not modules then modules = { } end modules ['trac-set'] = { -- might become util-set.lua      version   = 1.001,      comment   = "companion to luat-lib.mkiv",      author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -4007,8 +4185,12 @@ local type, next, tostring = type, next, tostring  local concat = table.concat  local format, find, lower, gsub, simpleesc = string.format, string.find, string.lower, string.gsub, string.simpleesc  local is_boolean = string.is_boolean +local settings_to_hash = utilities.parsers.settings_to_hash -setters = { } +utilities         = utilities or { } +local utilities   = utilities +utilities.setters = utilities.setters or { } +local setters     = utilities.setters  local data = { } -- maybe just local @@ -4064,7 +4246,7 @@ end  local function set(t,what,newvalue)      local data, done = t.data, t.done      if type(what) == "string" then -        what = aux.settings_to_hash(what) -- inefficient but ok +        what = settings_to_hash(what) -- inefficient but ok      end      for w, value in next, what do          if value == "" then @@ -4191,18 +4373,20 @@ end  -- we could have used a bit of oo and the trackers:enable syntax but  -- there is already a lot of code around using the singular tracker --- we could make this into a module +-- we could make this into a module but we also want the rest avaliable + +local enable, disable, register, list, show = setters.enable, setters.disable, setters.register, setters.list, setters.show  function setters.new(name) -    local t +    local t -- we need to access it in t      t = {          data     = { }, -- indexed, but also default and value fields          name     = name, -        enable   = function(...) setters.enable  (t,...) end, -        disable  = function(...) setters.disable (t,...) end, -        register = function(...) setters.register(t,...) end, -        list     = function(...) setters.list    (t,...) end, -        show     = function(...) setters.show    (t,...) end, +        enable   = function(...) enable  (t,...) end, +        disable  = function(...) disable (t,...) end, +        register = function(...) register(t,...) end, +        list     = function(...) list    (t,...) end, +        show     = function(...) show    (t,...) end,      }      data[name] = t      return t @@ -4212,13 +4396,18 @@ trackers    = setters.new("trackers")  directives  = setters.new("directives")  experiments = setters.new("experiments") +local t_enable, t_disable = trackers   .enable, trackers   .disable +local d_enable, d_disable = directives .enable, directives .disable +local e_enable, e_disable = experiments.enable, experiments.disable +  -- experiment  if trackers and environment and environment.engineflags.trackers then -    trackers.enable(environment.engineflags.trackers) +    t_enable(environment.engineflags.trackers)  end +  if directives and environment and environment.engineflags.directives then -    directives.enable(environment.engineflags.directives) +    d_enable(environment.engineflags.directives)  end  -- nice trick: we overload two of the directives related functions with variants that @@ -4232,30 +4421,24 @@ 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 enable  = directives.enable -local disable = directives.disable -  function directives.enable(...)      report("directives","enabling: %s",concat({...}," ")) -    enable(...) +    d_enable(...)  end  function directives.disable(...)      report("directives","disabling: %s",concat({...}," ")) -    disable(...) +    d_disable(...)  end -local enable  = experiments.enable -local disable = experiments.disable -  function experiments.enable(...)      report("experiments","enabling: %s",concat({...}," ")) -    enable(...) +    e_enable(...)  end  function experiments.disable(...)      report("experiments","disabling: %s",concat({...}," ")) -    disable(...) +    e_disable(...)  end  -- a useful example @@ -4264,136 +4447,20 @@ directives.register("system.nostatistics", function(v)      statistics.enable = not v  end) +directives.register("system.nolibraries", function(v) +    libraries = nil -- we discard this tracing for security +end) +  -- experiment  if trackers and environment and environment.engineflags.trackers then -    trackers.enable(environment.engineflags.trackers) +    t_enable(environment.engineflags.trackers)  end  if directives and environment and environment.engineflags.directives then -    directives.enable(environment.engineflags.directives) -end - - -end -- of closure - -do -- create closure to overcome 200 locals limit - -if not modules then modules = { } end modules ['trac-tra'] = { -    version   = 1.001, -    comment   = "companion to trac-tra.mkiv", -    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", -    copyright = "PRAGMA ADE / ConTeXt Development Team", -    license   = "see context related readme files" -} - --- the <anonymous> tag is kind of generic and used for functions that are not --- bound to a variable, like node.new, node.copy etc (contrary to for instance --- node.has_attribute which is bound to a has_attribute local variable in mkiv) - -local debug = require "debug" - -local getinfo = debug.getinfo -local type, next = type, next -local format, find = string.format, string.find -local is_boolean = string.is_boolean - -debugger = debugger or { } - -local counters = { } -local names = { } - --- one - -local function hook() -    local f = getinfo(2,"f").func -    local n = getinfo(2,"Sn") ---  if n.what == "C" and n.name then print (n.namewhat .. ': ' .. n.name) end -    if f then -        local cf = counters[f] -        if cf == nil then -            counters[f] = 1 -            names[f] = n -        else -            counters[f] = cf + 1 -        end -    end -end - -local function getname(func) -    local n = names[func] -    if n then -        if n.what == "C" then -            return n.name or '<anonymous>' -        else -            -- source short_src linedefined what name namewhat nups func -            local name = n.name or n.namewhat or n.what -            if not name or name == "" then name = "?" end -            return format("%s : %s : %s", n.short_src or "unknown source", n.linedefined or "--", name) -        end -    else -        return "unknown" -    end -end - -function debugger.showstats(printer,threshold) -    printer   = printer or texio.write or print -    threshold = threshold or 0 -    local total, grandtotal, functions = 0, 0, 0 -    printer("\n") -- ugly but ok - -- table.sort(counters) -    for func, count in next, counters do -        if count > threshold then -            local name = getname(func) -            if not find(name,"for generator") then -                printer(format("%8i  %s", count, name)) -                total = total + count -            end -        end -        grandtotal = grandtotal + count -        functions = functions + 1 -    end -    printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold)) -end - --- two - - --- rest - -function debugger.savestats(filename,threshold) -    local f = io.open(filename,'w') -    if f then -        debugger.showstats(function(str) f:write(str) end,threshold) -        f:close() -    end -end - -function debugger.enable() -    debug.sethook(hook,"c") -end - -function debugger.disable() -    debug.sethook() -end - -local function trace_calls(n) -    debugger.enable() -    luatex.register_stop_actions(function() -        debugger.disable() -        debugger.savestats(tex.jobname .. "-luacalls.log",tonumber(n)) -    end) -    trace_calls = function() end -end - -if directives then -    directives.register("system.tracecalls", function(n) trace_calls(n) end) -- indirect is needed for nilling +    d_enable(environment.engineflags.directives)  end - - - -  end -- of closure  do -- create closure to overcome 200 locals limit @@ -4422,7 +4489,8 @@ provide an <l n='xml'/> structured file. Actually, any logging that  is hooked into callbacks will be \XML\ by default.</p>  --ldx]]-- -logs = logs or { } +logs       = logs or { } +local logs = logs  --[[ldx--  <p>This looks pretty ugly but we need to speed things up a bit.</p> @@ -4665,8 +4733,8 @@ function noplog.simple(fmt,...) -- todo: fmt,s      end  end -if utils then -    utils.report = function(...) logs.simple(...) end +if utilities then +    utilities.report = function(...) logs.simple(...) end  end  function logs.setprogram(newname,newbanner) @@ -4736,6 +4804,50 @@ function logs.fatal(where,...)  end +function logs.obsolete(old,new) +    local o = loadstring("return " .. new)() +    if type(o) == "function" then +        return function(...) +            logs.report("system","function %s is obsolete, use %s",old,new) +            loadstring(old .. "=" .. new  .. " return ".. old)()(...) +        end +    elseif type(o) == "table" then +        local t, m = { }, { } +        m.__index = function(t,k) +            logs.report("system","table %s is obsolete, use %s",old,new) +            m.__index, m.__newindex = o, o +            return o[k] +        end +        m.__newindex = function(t,k,v) +            logs.report("system","table %s is obsolete, use %s",old,new) +            m.__index, m.__newindex = o, o +            o[k] = v +        end +        if libraries then +            libraries.obsolete[old] = t -- true +        end +        setmetatable(t,m) +        return t +    end +end + +if tex.error then + +    function logs.texerrormessage(...) -- for the moment we put this function here +        tex.error(format(...), { }) +    end + +else + +    function logs.texerrormessage(...) -- for the moment we put this function here +        local v = format(...) +        tex.sprint(tex.ctxcatcodes,"\\errmessage{") +        tex.sprint(tex.vrbcatcodes,v) +        tex.print(tex.ctxcatcodes,"}") +    end + +end +  end -- of closure @@ -4762,7 +4874,8 @@ local trace_namespaces = false  trackers.register("system.namespaces", function(  local report_system = logs.new("system") -namespaces = { } +namespaces       = namespaces or { } +local namespaces = namespaces  local registered = { } @@ -4932,6 +5045,7 @@ local report_resolvers = logs.new("resolvers")  local format, sub, match, gsub, find = string.format, string.sub, string.match, string.gsub, string.find  local unquote, quote = string.unquote, string.quote +local concat = table.concat  -- precautions @@ -4956,6 +5070,8 @@ end  -- environment  environment             = environment or { } +local environment       = environment +  environment.arguments   = { }  environment.files       = { }  environment.sortedflags = nil @@ -5078,7 +5194,7 @@ function environment.reconstruct_commandline(arg,noquote)                  result[#result+1] = a              end          end -        return table.join(result," ") +        return concat(result," ")      else          return ""      end @@ -5248,6 +5364,7 @@ optimize the code.</p>  --ldx]]--  xml = xml or { } +local xml = xml  local concat, remove, insert = table.concat, table.remove, table.insert @@ -6453,6 +6570,8 @@ of <l n='xpath'/> and since we're not compatible we call it <l n='lpath'/>. We  will explain more about its usage in other documents.</p>  --ldx]]-- +local xml = xml +  local lpathcalls  = 0  function xml.lpathcalls () return lpathcalls  end  local lpathcached = 0  function xml.lpathcached() return lpathcached end @@ -7647,6 +7766,8 @@ local type, next, tonumber, tostring, setmetatable, loadstring = type, next, ton  local format, gsub, match = string.format, string.gsub, string.match  local lpegmatch = lpeg.match +local xml = xml +  --[[ldx--  <p>The following helper functions best belong to the <t>lxml-ini</t>  module. Some are here because we need then in the <t>mk</t> @@ -7748,6 +7869,8 @@ local trace_manipulations = false  trackers.register("lxml.manipulations", funct  local report_xml = logs.new("xml") +local xml = xml +  local xmlparseapply, xmlconvert, xmlcopy, xmlname = xml.parse_apply, xml.convert, xml.copy, xml.name  local xmlinheritedconvert = xml.inheritedconvert @@ -8262,6 +8385,8 @@ if not modules then modules = { } end modules ['lxml-xml'] = {      license   = "see context related readme files"  } +local xml = xml +  local finalizers   = xml.finalizers.xml  local xmlfilter    = xml.filter -- we could inline this one for speed  local xmltostring  = xml.tostring @@ -8588,7 +8713,8 @@ local ostype, osname, ossetenv, osgetenv = os.type, os.name, os.setenv, os.geten  -- we now split it over multiple files. As this file is now the  -- starting point we introduce resolvers here. -resolvers = resolvers or { } +resolvers       = resolvers or { } +local resolvers = resolvers  -- We don't want the kpse library to kick in. Also, we want to be able to  -- execute programs. Control over execution is implemented later. @@ -8812,6 +8938,8 @@ local trace_expansions = false  trackers.register("resolvers.expansions", functi  local report_resolvers = logs.new("resolvers") +local resolvers = resolvers +  -- As this bit of code is somewhat special it gets its own module. After  -- all, when working on the main resolver code, I don't want to scroll  -- past this every time. @@ -9119,6 +9247,8 @@ if not modules then modules = { } end modules ['data-env'] = {      license   = "see context related readme files",  } +local resolvers = resolvers +  local formats      = { }  resolvers.formats      = formats  local suffixes     = { }  resolvers.suffixes     = suffixes  local dangerous    = { }  resolvers.dangerous    = dangerous @@ -9309,11 +9439,13 @@ local mkdirs, isdir = dir.mkdirs, lfs.isdir  local trace_locating = false  trackers.register("resolvers.locating", function(v) trace_locating = v end)  local trace_cache    = false  trackers.register("resolvers.cache",    function(v) trace_cache    = v end) -local report_cache = logs.new("cache") - +local report_cache      = logs.new("cache")  local report_resolvers = logs.new("resolvers") -caches = caches or { } +local resolvers = resolvers + +caches           = caches or { } +local caches     = caches  caches.base      = caches.base or "luatex-cache"  caches.more      = caches.more or "context" @@ -9558,7 +9690,7 @@ function caches.savedata(filepath,filename,data,raw)      end      local cleanup = resolvers.boolean_variable("PURGECACHE", false)      local strip = resolvers.boolean_variable("LUACSTRIP", true) -    utils.lua.compile(tmaname, tmcname, cleanup, strip) +    utilities.lua.compile(tmaname, tmcname, cleanup, strip)  end  -- moved from data-res: @@ -9620,7 +9752,7 @@ function caches.savecontent(cachename,dataname,content)          if trace_locating then              report_resolvers("category '%s', cachename '%s' saved in '%s'",dataname,cachename,luaname)          end -        if utils.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip +        if utilities.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip              if trace_locating then                  report_resolvers("'%s' compiled to '%s'",dataname,lucname)              end @@ -9657,6 +9789,8 @@ local trace_locating   = false  trackers.register("resolvers.locating",   functi  local report_resolvers = logs.new("resolvers") +local resolvers = resolvers +  resolvers.locators     = { notfound = { nil } }  -- locate databases  resolvers.hashers      = { notfound = { nil } }  -- load databases  resolvers.generators   = { notfound = { nil } }  -- generate databases @@ -9713,6 +9847,7 @@ if not modules then modules = { } end modules ['data-res'] = {  local format, gsub, find, lower, upper, match, gmatch = string.format, string.gsub, string.find, string.lower, string.upper, string.match, string.gmatch  local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys  local next, type = next, type +local os = os  local lpegP, lpegS, lpegR, lpegC, lpegCc, lpegCs, lpegCt = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct  local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns @@ -9726,10 +9861,14 @@ local trace_expansions = false  trackers.register("resolvers.expansions", functi  local report_resolvers = logs.new("resolvers") +local resolvers = resolvers +  local expanded_path_from_list  = resolvers.expanded_path_from_list  local checked_variable         = resolvers.checked_variable  local split_configuration_path = resolvers.split_configuration_path +local initializesetter = utilities.setters.initialize +  local ostype, osname, osenv, ossetenv, osgetenv = os.type, os.name, os.env, os.setenv, os.getenv  resolvers.cacheversion = '1.0.1' @@ -9949,7 +10088,7 @@ local function load_configuration_files()                                  t[k] = v                              elseif kind == "table" then                                  -- this operates on the table directly -                                setters.initialize(filename,k,v) +                                initializesetter(filename,k,v)                                  -- this doesn't (maybe metatables some day)                                  for kk, vv in next, v do -- vv = variable                                      if vv ~= unset_variable then @@ -11122,6 +11261,8 @@ if not modules then modules = { } end modules ['data-pre'] = {  local upper, lower, gsub = string.upper, string.lower, string.gsub +local resolvers = resolvers +  local prefixes = { }  local getenv = resolvers.getenv @@ -11235,6 +11376,8 @@ if not modules then modules = { } end modules ['data-inp'] = {      license   = "see context related readme files"  } +local resolvers = resolvers +  resolvers.finders = resolvers.finders or { }  resolvers.openers = resolvers.openers or { }  resolvers.loaders = resolvers.loaders or { } @@ -11256,7 +11399,7 @@ if not modules then modules = { } end modules ['data-out'] = {      license   = "see context related readme files"  } -outputs = outputs or { } +-- not used yet @@ -11291,8 +11434,8 @@ table structures without bothering about the disk cache.</p>  <p>Examples of usage can be found in the font related code.</p>  --ldx]]-- -containers = containers or { } - +containers          = containers or { } +local containers    = containers  containers.usecache = true  local report_cache = logs.new("cache") @@ -11418,6 +11561,8 @@ local trace_locating = false  trackers.register("resolvers.locating", function(v  local report_resolvers = logs.new("resolvers") +local resolvers = resolvers +  -- we will make a better format, maybe something xml or just text or lua  resolvers.automounted = resolvers.automounted or { } @@ -11526,15 +11671,20 @@ local report_resolvers = logs.new("resolvers")  -- zip:///texmf.zip?tree=/tex/texmf-local  -- zip:///texmf-mine.zip?tree=/tex/texmf-projects -zip                 = zip or { } -zip.archives        = zip.archives or { } -zip.registeredfiles = zip.registeredfiles or { } +local resolvers = resolvers + +zip                   = zip or { } +local zip             = zip + +zip.archives          = zip.archives or { } +local archives        = zip.archives + +zip.registeredfiles   = zip.registeredfiles or { } +local registeredfiles = zip.registeredfiles  local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders  local locators, hashers, concatinators = resolvers.locators, resolvers.hashers, resolvers.concatinators -local archives = zip.archives -  local function validzip(str) -- todo: use url splitter      if not find(str,"^zip://") then          return "zip:///" .. str @@ -11698,7 +11848,7 @@ function resolvers.usezipfile(zipname)      zipname = validzip(zipname)      local specification = resolvers.splitmethod(zipname)      local zipfile = specification.path -    if zipfile and not zip.registeredfiles[zipname] then +    if zipfile and not registeredfiles[zipname] then          local tree = url.query(specification.query).tree or ""          local z = zip.openarchive(zipfile)          if z then @@ -11709,7 +11859,7 @@ function resolvers.usezipfile(zipname)              statistics.starttiming(instance)              resolvers.prepend_hash('zip',zipname,zipfile)              resolvers.extend_texmf_var(zipname) -- resets hashes too -            zip.registeredfiles[zipname] = z +            registeredfiles[zipname] = z              instance.files[zipname] = resolvers.register_zip_file(z,tree or "")              statistics.stoptiming(instance)          elseif trace_locating then @@ -11769,6 +11919,8 @@ local unpack = unpack or table.unpack  local report_resolvers = logs.new("resolvers") +local resolvers = resolvers +  local done, found, notfound = { }, { }, resolvers.finders.notfound  function resolvers.finders.tree(specification,filetype) @@ -11851,11 +12003,15 @@ if not modules then modules = { } end modules ['data-crl'] = {  -- this one is replaced by data-sch.lua -- -curl = curl or { } -  local gsub = string.gsub + +local resolvers = resolvers +  local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders +curl = curl or { } +local curl = curl +  local cached = { }  function curl.fetch(protocol, name) -- todo: use socket library @@ -11925,6 +12081,8 @@ local report_resolvers = logs.new("resolvers")  local gsub, insert = string.gsub, table.insert  local unpack = unpack or table.unpack +local resolvers, package = resolvers, package +  local  libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -- 'luainputs'  local clibformats = { 'lib' } @@ -12079,6 +12237,8 @@ local type, next = type, next  local trace_locating = false  trackers.register("resolvers.locating", function(v) trace_locating = v end) +local resolvers = resolvers +  local report_resolvers = logs.new("resolvers")  function resolvers.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix @@ -12140,6 +12300,8 @@ if not modules then modules = { } end modules ['data-tmf'] = {      license   = "see context related readme files"  } +local resolvers = resolvers +  --  =  <<  --  ?  ??  --  <  += @@ -12209,6 +12371,8 @@ local find, concat, upper, format = string.find, table.concat, string.upper, str  resolvers.listers = resolvers.listers or { } +local resolvers = resolvers +  local function tabstr(str)      if type(str) == 'table' then          return concat(str," | ") @@ -12258,9 +12422,15 @@ if not modules then modules = { } end modules ['luat-sta'] = {  local gmatch, match = string.gmatch, string.match  local type = type -states          = states          or { } -states.data     = states.data     or { } -states.hash     = states.hash     or { } +states          = states or { } +local states    = states + +states.data     = states.data or { } +local data      = states.data + +states.hash     = states.hash or { } +local hash      = states.hash +  states.tag      = states.tag      or ""  states.filename = states.filename or "" @@ -12270,7 +12440,7 @@ function states.save(filename,tag)      io.savedata(filename,          "-- generator : luat-sta.lua\n" ..          "-- state tag : " .. tag .. "\n\n" .. -        table.serialize(states.data[tag or states.tag] or {},true) +        table.serialize(data[tag or states.tag] or {},true)      )  end @@ -12278,11 +12448,11 @@ function states.load(filename,tag)      states.filename = filename      states.tag = tag or "whatever"      states.filename = file.addsuffix(states.filename,'lus') -    states.data[states.tag], states.hash[states.tag] = (io.exists(filename) and dofile(filename)) or { }, { } +    data[states.tag], hash[states.tag] = (io.exists(filename) and dofile(filename)) or { }, { }  end -function states.set_by_tag(tag,key,value,default,persistent) -    local d, h = states.data[tag], states.hash[tag] +local function set_by_tag(tag,key,value,default,persistent) +    local d, h = data[tag], hash[tag]      if d then          if type(d) == "table" then              local dkey, hkey = key, key @@ -12312,17 +12482,17 @@ function states.set_by_tag(tag,key,value,default,persistent)              d[dkey], h[hkey] = value, value          elseif type(d) == "string" then              -- weird -            states.data[tag], states.hash[tag] = value, value +            data[tag], hash[tag] = value, value          end      end  end -function states.get_by_tag(tag,key,default) -    local h = states.hash[tag] +local function get_by_tag(tag,key,default) +    local h = hash[tag]      if h and h[key] then          return h[key]      else -        local d = states.data[tag] +        local d = data[tag]          if d then              for k in gmatch(key,"[^%.]+") do                  local dk = d[k] @@ -12337,12 +12507,15 @@ function states.get_by_tag(tag,key,default)      end  end +states.set_by_tag = set_by_tag +states.get_by_tag = get_by_tag +  function states.set(key,value,default,persistent) -    states.set_by_tag(states.tag,key,value,default,persistent) +    set_by_tag(states.tag,key,value,default,persistent)  end  function states.get(key,default) -    return states.get_by_tag(states.tag,key,default) +    return get_by_tag(states.tag,key,default)  end @@ -12422,10 +12595,10 @@ function environment.make_format(name)          local lucstubname = file.addsuffix(texbasename,"luc")          -- pack libraries in stub          logs.simple("creating initialization file: %s",luastubname) -        utils.merger.selfcreate(usedlualibs,specificationpath,luastubname) +        utilities.merger.selfcreate(usedlualibs,specificationpath,luastubname)          -- compile stub file (does not save that much as we don't use this stub at startup any more)          local strip = resolvers.boolean_variable("LUACSTRIP", true) -        if utils.lua.compile(luastubname,lucstubname,false,strip) and lfs.isfile(lucstubname) then +        if utilities.lua.compile(luastubname,lucstubname,false,strip) and lfs.isfile(lucstubname) then              logs.simple("using compiled initialization file: %s",lucstubname)              usedluastub = lucstubname          else @@ -12507,12 +12680,16 @@ own.libs = { -- order can be made better      'l-boolean.lua',      'l-unicode.lua',      'l-math.lua', -    'l-utils.lua', -    'l-aux.lua', + +    'util-mrg.lua', +    'util-lua.lua', +    'util-prs.lua', +    'util-tab.lua', +    'util-fmt.lua', +    'util-deb.lua',      'trac-inf.lua',      'trac-set.lua', -    'trac-tra.lua',      'trac-log.lua',      'trac-pro.lua',      'luat-env.lua', -- can come before inf (as in mkiv) @@ -12524,7 +12701,6 @@ own.libs = { -- order can be made better      'lxml-aux.lua',      'lxml-xml.lua', -      'data-ini.lua',      'data-exp.lua',      'data-env.lua', @@ -12589,6 +12765,7 @@ local function locate_libs()              local filename = pth .. "/" .. lib              local found = lfs.isfile(filename)              if found then +                package.path = package.path .. ";" .. pth .. "/?.lua" -- in case l-* does a require                  return pth              end          end @@ -13326,7 +13503,7 @@ if environment.argument("selfmerge") then      runners.loadbase()      local found = locate_libs()      if found then -        utils.merger.selfmerge(own.name,own.libs,{ found }) +        utilities.merger.selfmerge(own.name,own.libs,{ found })      end  elseif environment.argument("selfclean") then @@ -13334,7 +13511,7 @@ elseif environment.argument("selfclean") then      -- remove embedded libraries      runners.loadbase() -    utils.merger.selfclean(own.name) +    utilities.merger.selfclean(own.name)  elseif environment.argument("selfupdate") then @@ -13599,6 +13776,7 @@ elseif false then  else +    runners.loadbase()      runners.execute_ctx_script("mtx-base",filename)  end diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun index 68ee3d2c1..ef6ccbfb6 100644 --- a/scripts/context/stubs/unix/mtxrun +++ b/scripts/context/stubs/unix/mtxrun @@ -52,6 +52,7 @@ if not modules then modules = { } end modules ['l-string'] = {      license   = "see context related readme files"  } +local string = string  local sub, gsub, find, match, gmatch, format, char, byte, rep, lower = string.sub, string.gsub, string.find, string.match, string.gmatch, string.format, string.char, string.byte, string.rep, string.lower  local lpegmatch = lpeg.match @@ -199,11 +200,6 @@ end  string.padd = string.rpadd -function is_number(str) -- tonumber -    return find(str,"^[%-%+]?[%d]-%.?[%d+]$") == 1 -end - -  function string:split_settings() -- no {} handling, see l-aux for lpeg variant      if find(self,"=") then          local t = { } @@ -547,12 +543,10 @@ if not modules then modules = { } end modules ['l-table'] = {      license   = "see context related readme files"  } -table.join = table.concat - +local type, next, tostring, tonumber, ipairs, table, string = type, next, tostring, tonumber, ipairs, table, string  local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove  local format, find, gsub, lower, dump, match = string.format, string.find, string.gsub, string.lower, string.dump, string.match  local getmetatable, setmetatable = getmetatable, setmetatable -local type, next, tostring, tonumber, ipairs = type, next, tostring, tonumber, ipairs  -- Starting with version 5.2 Lua no longer provide ipairs, which makes  -- sense. As we already used the for loop and # in most places the @@ -1452,7 +1446,9 @@ if not modules then modules = { } end modules ['l-io'] = {      license   = "see context related readme files"  } -local byte, find, gsub = string.byte, string.find, string.gsub +local io = io +local byte, find, gsub, format = string.byte, string.find, string.gsub, string.format +local concat = table.concat  if string.find(os.getenv("PATH"),";") then      io.fileseparator, io.pathseparator = "\\", ";" @@ -1463,9 +1459,7 @@ end  function io.loaddata(filename,textmode)      local f = io.open(filename,(textmode and 'r') or 'rb')      if f then -    --  collectgarbage("step") -- sometimes makes a big difference in mem consumption          local data = f:read('*all') -    --  garbagecollector.check(data)          f:close()          return data      else @@ -1477,7 +1471,7 @@ function io.savedata(filename,data,joiner)      local f = io.open(filename,"wb")      if f then          if type(data) == "table" then -            f:write(table.join(data,joiner or "")) +            f:write(concat(data,joiner or ""))          elseif type(data) == "function" then              data(f)          else @@ -1603,12 +1597,12 @@ function io.ask(question,default,options)      while true do          io.write(question)          if options then -            io.write(string.format(" [%s]",table.concat(options,"|"))) +            io.write(format(" [%s]",concat(options,"|")))          end          if default then -            io.write(string.format(" [%s]",default)) +            io.write(format(" [%s]",default))          end -        io.write(string.format(" ")) +        io.write(format(" "))          local answer = io.read()          answer = gsub(answer,"^%s*(.*)%s*$","%1")          if answer == "" and default then @@ -1682,7 +1676,8 @@ local tostring = tostring  local format, floor, insert, match = string.format, math.floor, table.insert, string.match  local lpegmatch = lpeg.match -number = number or { } +number       = number or { } +local number = number  -- a,b,c,d,e,f = number.toset(100101) @@ -1759,6 +1754,8 @@ if not modules then modules = { } end modules ['l-set'] = {      license   = "see context related readme files"  } +-- This will become obsolete when we have the bitset library embedded. +  set = set or { }  local nums   = { } @@ -1840,10 +1837,10 @@ if not modules then modules = { } end modules ['l-os'] = {  -- maybe build io.flush in os.execute +local os = os  local find, format, gsub, upper = string.find, string.format, string.gsub, string.upper  local random, ceil = math.random, math.ceil  local rawget, rawset, type, getmetatable, setmetatable, tonumber = rawget, rawset, type, getmetatable, setmetatable, tonumber -local rawget, rawset, type, getmetatable, setmetatable, tonumber = rawget, rawset, type, getmetatable, setmetatable, tonumber  -- The following code permits traversing the environment table, at least  -- in luatex. Internally all environment names are uppercase. @@ -2193,12 +2190,15 @@ if not modules then modules = { } end modules ['l-file'] = {  -- needs a cleanup  file = file or { } +local file = file  local insert, concat = table.insert, table.concat  local find, gmatch, match, gsub, sub, char = string.find, string.gmatch, string.match, string.gsub, string.sub, string.char  local lpegmatch = lpeg.match  local getcurrentdir = lfs.currentdir +local P, R, S, C, Cs, Cp, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Cp, lpeg.Cc +  local function dirname(name,default)      return match(name,"^(.+)[/\\].-$") or (default or "")  end @@ -2416,11 +2416,11 @@ end  -- also rewrite previous -local letter    = lpeg.R("az","AZ") + lpeg.S("_-+") -local separator = lpeg.P("://") +local letter    = R("az","AZ") + S("_-+") +local separator = P("://") -local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator + letter^1 * lpeg.P("/") -local rootbased = lpeg.P("/") + letter*lpeg.P(":") +local qualified = P(".")^0 * P("/") + letter*P(":") + letter^1*separator + letter^1 * P("/") +local rootbased = P("/") + letter*P(":")  -- ./name ../name  /name c: :// name/name @@ -2432,14 +2432,16 @@ function file.is_rootbased_path(filename)      return lpegmatch(rootbased,filename) ~= nil  end -local slash  = lpeg.S("\\/") -local period = lpeg.P(".") -local drive  = lpeg.C(lpeg.R("az","AZ")) * lpeg.P(":") -local path   = lpeg.C(((1-slash)^0 * slash)^0) -local suffix = period * lpeg.C(lpeg.P(1-period)^0 * lpeg.P(-1)) -local base   = lpeg.C((1-suffix)^0) +-- actually these are schemes + +local slash  = S("\\/") +local period = P(".") +local drive  = C(R("az","AZ")) * P(":") +local path   = C(((1-slash)^0 * slash)^0) +local suffix = period * C(P(1-period)^0 * P(-1)) +local base   = C((1-suffix)^0) -local pattern = (drive + lpeg.Cc("")) * (path + lpeg.Cc("")) * (base + lpeg.Cc("")) * (suffix + lpeg.Cc("")) +local pattern = (drive + Cc("")) * (path + Cc("")) * (base + Cc("")) * (suffix + Cc(""))  function file.splitname(str) -- returns drive, path, base, suffix      return lpegmatch(pattern,str) @@ -2467,6 +2469,7 @@ if not modules then modules = { } end modules ['l-md5'] = {  -- This also provides file checksums and checkers. +local md5, file = md5, file  local gsub, format, byte = string.gsub, string.format, string.byte  local function convert(str,fmt) @@ -2547,7 +2550,8 @@ local lpegmatch, lpegP, lpegC, lpegR, lpegS, lpegCs, lpegCc = lpeg.match, lpeg.P  --     / \ /                        \  --     urn:example:animal:ferret:nose -url = url or { } +url       = url or { } +local url = url  local function tochar(s)      return char(tonumber(s,16)) @@ -2687,20 +2691,30 @@ if not modules then modules = { } end modules ['l-dir'] = {  local type = type  local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub +local concat = table.concat  local lpegmatch = lpeg.match +local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V +  dir = dir or { } +local dir = dir +local lfs = lfs + +local attributes = lfs.attributes +local walkdir    = lfs.dir +local isdir      = lfs.isdir +local isfile     = lfs.isfile +local mkdir      = lfs.mkdir +local chdir      = lfs.chdir +local currentdir = lfs.currentdir  -- handy  function dir.current() -    return (gsub(lfs.currentdir(),"\\","/")) +    return (gsub(currentdir(),"\\","/"))  end --- optimizing for no string.find (*) does not save time - -local attributes = lfs.attributes -local walkdir    = lfs.dir +-- optimizing for no find (*) does not save time  local function glob_pattern(path,patt,recurse,action)      local ok, scanner @@ -2756,8 +2770,6 @@ end  dir.collect_pattern = collect_pattern -local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V -  local pattern = Ct {      [1] = (C(P(".") + P("/")^1) + C(R("az","AZ") * P(":") * P("/")^0) + Cc("./")) * V(2) * V(3),      [2] = C(((1-S("*?/"))^0 * P("/"))^0), @@ -2780,7 +2792,7 @@ local function glob(str,t)              for s=1,#str do                  glob(str[s],t)              end -        elseif lfs.isfile(str) then +        elseif isfile(str) then              t(str)          else              local split = lpegmatch(pattern,str) @@ -2799,7 +2811,7 @@ local function glob(str,t)                  glob(str[s],t)              end              return t -        elseif lfs.isfile(str) then +        elseif isfile(str) then              local t = t or { }              t[#t+1] = str              return t @@ -2863,13 +2875,13 @@ dir.globfiles = globfiles  -- print(dir.ls("*.tex"))  function dir.ls(pattern) -    return table.concat(glob(pattern),"\n") +    return concat(glob(pattern),"\n")  end  local make_indeed = true -- false -if string.find(os.getenv("PATH"),";") then -- os.type == "windows" +if find(os.getenv("PATH"),";") then -- os.type == "windows"      function dir.mkdirs(...)          local str, pth, t = "", "", { ... } @@ -2918,11 +2930,11 @@ if string.find(os.getenv("PATH"),";") then -- os.type == "windows"              else                  pth = pth .. "/" .. s              end -            if make_indeed and not lfs.isdir(pth) then -                lfs.mkdir(pth) +            if make_indeed and not isdir(pth) then +                mkdir(pth)              end          end -        return pth, (lfs.isdir(pth) == true) +        return pth, (isdir(pth) == true)      end @@ -2937,11 +2949,11 @@ if string.find(os.getenv("PATH"),";") then -- os.type == "windows"          if not first then              first, last = match(str,"^([a-zA-Z]:)(.*)$")              if first and not find(last,"^/") then -                local d = lfs.currentdir() -                if lfs.chdir(first) then +                local d = currentdir() +                if chdir(first) then                      first = dir.current()                  end -                lfs.chdir(d) +                chdir(d)              end          end          if not first then @@ -2982,26 +2994,26 @@ else                  else                      pth = pth .. "/" .. s                  end -                if make_indeed and not first and not lfs.isdir(pth) then -                    lfs.mkdir(pth) +                if make_indeed and not first and not isdir(pth) then +                    mkdir(pth)                  end              end          else              pth = "."              for s in gmatch(str,"[^/]+") do                  pth = pth .. "/" .. s -                if make_indeed and not lfs.isdir(pth) then -                    lfs.mkdir(pth) +                if make_indeed and not isdir(pth) then +                    mkdir(pth)                  end              end          end -        return pth, (lfs.isdir(pth) == true) +        return pth, (isdir(pth) == true)      end      function dir.expand_name(str) -- will be merged with cleanpath and collapsepath          if not find(str,"^/") then -            str = lfs.currentdir() .. "/" .. str +            str = currentdir() .. "/" .. str          end          str = gsub(str,"//","/")          str = gsub(str,"/%./","/") @@ -3025,10 +3037,11 @@ if not modules then modules = { } end modules ['l-boolean'] = {      license   = "see context related readme files"  } -boolean = boolean or { } -  local type, tonumber = type, tonumber +boolean = boolean or { } +local boolean = boolean +  function boolean.tonumber(b)      if b then return 1 else return 0 end  end @@ -3109,6 +3122,8 @@ if not unicode then  end +local unicode = unicode +  utf = utf or unicode.utf8  local concat, utfchar, utfgsub = table.concat, utf.char, utf.gsub @@ -3280,7 +3295,7 @@ end  function unicode.utfcodes(str)      local t = { } -    for k,v in string.utfvalues(str) do +    for k,v in utfvalues(str) do          t[#t+1] = format("0x%04X",k)      end      return concat(t,separator or " ") @@ -3339,7 +3354,7 @@ end -- of closure  do -- create closure to overcome 200 locals limit -if not modules then modules = { } end modules ['l-utils'] = { +if not modules then modules = { } end modules ['util-mrg'] = {      version   = 1.001,      comment   = "companion to luat-lib.mkiv",      author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -3353,13 +3368,11 @@ local gsub, format = string.gsub, string.format  local concat = table.concat  local type, next = type, next -if not utils        then utils        = { } end -if not utils.merger then utils.merger = { } end -if not utils.lua    then utils.lua    = { } end - -utils.report = utils.report or print +utilities        = utilities or {} +utilities.merger = utilities.merger or { } +utilities.report = utilities.report or print -local merger = utils.merger +local merger     = utilities.merger  merger.strip_comment = true @@ -3396,9 +3409,9 @@ end  local function self_load(name)      local data = io.loaddata(name) or ""      if data == "" then -        utils.report("merge: unknown file %s",name) +        utilities.report("merge: unknown file %s",name)      else -        utils.report("merge: inserting %s",name) +        utilities.report("merge: inserting %s",name)      end      return data or ""  end @@ -3409,10 +3422,10 @@ local function self_save(name, data)              -- saves some 20K              local n = #data              data = gsub(data,"%-%-~[^\n\r]*[\r\n]","") -            utils.report("merge: %s bytes of comment stripped, %s bytes of code left",n-#data,#data) +            utilities.report("merge: %s bytes of comment stripped, %s bytes of code left",n-#data,#data)          end          io.savedata(name,data) -        utils.report("merge: saving %s",name) +        utilities.report("merge: saving %s",name)      end  end @@ -3429,7 +3442,7 @@ local function self_libs(libs,list)          local lib = libs[i]          for j=1,#list do              local pth = gsub(list[j],"\\","/") -- file.clean_path -            utils.report("merge: checking library path %s",pth) +            utilities.report("merge: checking library path %s",pth)              local name = pth .. "/" .. lib              if lfs.isfile(name) then                  foundpath = pth @@ -3438,30 +3451,30 @@ local function self_libs(libs,list)          if foundpath then break end      end      if foundpath then -        utils.report("merge: using library path %s",foundpath) +        utilities.report("merge: using library path %s",foundpath)          local right, wrong = { }, { }          for i=1,#libs do              local lib = libs[i]              local fullname = foundpath .. "/" .. lib              if lfs.isfile(fullname) then -                utils.report("merge: using library %s",fullname) +                utilities.report("merge: using library %s",fullname)                  right[#right+1] = lib                  result[#result+1] = m_begin_closure                  result[#result+1] = io.loaddata(fullname,true)                  result[#result+1] = m_end_closure              else -                utils.report("merge: skipping library %s",fullname) +                utilities.report("merge: skipping library %s",fullname)                  wrong[#wrong+1] = lib              end          end          if #right > 0 then -            utils.report("merge: used libraries: %s",concat(right," ")) +            utilities.report("merge: used libraries: %s",concat(right," "))          end          if #wrong > 0 then -            utils.report("merge: skipped libraries: %s",concat(wrong," ")) +            utilities.report("merge: skipped libraries: %s",concat(wrong," "))          end      else -        utils.report("merge: no valid library path found") +        utilities.report("merge: no valid library path found")      end      return concat(result, "\n\n")  end @@ -3480,8 +3493,25 @@ function merger.selfclean(name)      self_save(name,self_swap(self_load(name),self_nothing()))  end -function utils.lua.compile(luafile,lucfile,cleanup,strip) -- defaults: cleanup=false strip=true -    utils.report("lua: compiling %s into %s",luafile,lucfile) + +end -- of closure + +do -- create closure to overcome 200 locals limit + +if not modules then modules = { } end modules ['util-lua'] = { +    version   = 1.001, +    comment   = "companion to luat-lib.mkiv", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} + +utilities        = utilities or {} +utilities.lua    = utilities.merger or { } +utilities.report = utilities.report or print + +function utilities.lua.compile(luafile,lucfile,cleanup,strip) -- defaults: cleanup=false strip=true +    utilities.report("lua: compiling %s into %s",luafile,lucfile)      os.remove(lucfile)      local command = "-o " .. string.quote(lucfile) .. " " .. string.quote(luafile)      if strip ~= false then @@ -3489,7 +3519,7 @@ function utils.lua.compile(luafile,lucfile,cleanup,strip) -- defaults: cleanup=f      end      local done = os.spawn("texluac " .. command) == 0 or os.spawn("luac " .. command) == 0      if done and cleanup == true and lfs.isfile(lucfile) and lfs.isfile(luafile) then -        utils.report("lua: removing %s",luafile) +        utilities.report("lua: removing %s",luafile)          os.remove(luafile)      end      return done @@ -3501,7 +3531,7 @@ end -- of closure  do -- create closure to overcome 200 locals limit -if not modules then modules = { } end modules ['l-aux'] = { +if not modules then modules = { } end modules ['util-prs'] = {      version   = 1.001,      comment   = "companion to luat-lib.mkiv",      author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -3509,15 +3539,16 @@ if not modules then modules = { } end modules ['l-aux'] = {      license   = "see context related readme files"  } --- for inline, no store split : for s in string.gmatch(str,",* *([^,]+)") do .. end - -aux = aux or { } +utilities         = utilities or {} +utilities.parsers = utilities.parsers or { } +local parsers     = utilities.parsers +parsers.patterns  = parsers.patterns or { } +local P, R, V, C, Ct, Carg = lpeg.P, lpeg.R, lpeg.V, lpeg.C, lpeg.Ct, lpeg.Carg +local lpegmatch = lpeg.match  local concat, format, gmatch = table.concat, string.format, string.gmatch  local tostring, type = tostring, type -local lpegmatch = lpeg.match - -local P, R, V = lpeg.P, lpeg.R, lpeg.V +local sortedhash = table.sortedhash  local escape, left, right = P("\\"), P('{'), P('}') @@ -3526,23 +3557,23 @@ lpeg.patterns.balanced = P {      [2] = left * V(1) * right  } -local space     = lpeg.P(' ') -local equal     = lpeg.P("=") -local comma     = lpeg.P(",") -local lbrace    = lpeg.P("{") -local rbrace    = lpeg.P("}") +local space     = P(' ') +local equal     = P("=") +local comma     = P(",") +local lbrace    = P("{") +local rbrace    = P("}")  local nobrace   = 1 - (lbrace+rbrace) -local nested    = lpeg.P { lbrace * (nobrace + lpeg.V(1))^0 * rbrace } +local nested    = P { lbrace * (nobrace + V(1))^0 * rbrace }  local spaces    = space^0 -local value     = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0) +local value     = P(lbrace * C((nobrace + nested)^0) * rbrace) + C((nested + (1-comma))^0) -local key       = lpeg.C((1-equal-comma)^1) -local pattern_a = (space+comma)^0 * (key * equal * value + key * lpeg.C("")) +local key       = C((1-equal-comma)^1) +local pattern_a = (space+comma)^0 * (key * equal * value + key * C(""))  local pattern_c = (space+comma)^0 * (key * equal * value) -local key       = lpeg.C((1-space-equal-comma)^1) -local pattern_b = spaces * comma^0 * spaces * (key * ((spaces * equal * spaces * value) + lpeg.C(""))) +local key       = C((1-space-equal-comma)^1) +local pattern_b = spaces * comma^0 * spaces * (key * ((spaces * equal * spaces * value) + C("")))  -- "a=1, b=2, c=3, d={a{b,c}d}, e=12345, f=xx{a{b,c}d}xx, g={}" : outer {} removes, leading spaces ignored @@ -3556,11 +3587,11 @@ local pattern_a_s = (pattern_a/set)^1  local pattern_b_s = (pattern_b/set)^1  local pattern_c_s = (pattern_c/set)^1 -aux.settings_to_hash_pattern_a = pattern_a_s -aux.settings_to_hash_pattern_b = pattern_b_s -aux.settings_to_hash_pattern_c = pattern_c_s +parsers.patterns.settings_to_hash_a = pattern_a_s +parsers.patterns.settings_to_hash_b = pattern_b_s +parsers.patterns.settings_to_hash_c = pattern_c_s -function aux.make_settings_to_hash_pattern(set,how) +function parsers.make_settings_to_hash_pattern(set,how)      if how == "strict" then          return (pattern_c/set)^1      elseif how == "tolerant" then @@ -3570,7 +3601,7 @@ function aux.make_settings_to_hash_pattern(set,how)      end  end -function aux.settings_to_hash(str,existing) +function parsers.settings_to_hash(str,existing)      if str and str ~= "" then          hash = existing or { }          lpegmatch(pattern_a_s,str) @@ -3580,7 +3611,7 @@ function aux.settings_to_hash(str,existing)      end  end -function aux.settings_to_hash_tolerant(str,existing) +function parsers.settings_to_hash_tolerant(str,existing)      if str and str ~= "" then          hash = existing or { }          lpegmatch(pattern_b_s,str) @@ -3590,7 +3621,7 @@ function aux.settings_to_hash_tolerant(str,existing)      end  end -function aux.settings_to_hash_strict(str,existing) +function parsers.settings_to_hash_strict(str,existing)      if str and str ~= "" then          hash = existing or { }          lpegmatch(pattern_c_s,str) @@ -3601,16 +3632,16 @@ function aux.settings_to_hash_strict(str,existing)  end  local separator = comma * space^0 -local value     = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0) -local pattern   = lpeg.Ct(value*(separator*value)^0) +local value     = P(lbrace * C((nobrace + nested)^0) * rbrace) + C((nested + (1-comma))^0) +local pattern   = Ct(value*(separator*value)^0)  -- "aap, {noot}, mies" : outer {} removes, leading spaces ignored -aux.settings_to_array_pattern = pattern +parsers.patterns.settings_to_array = pattern  -- we could use a weak table as cache -function aux.settings_to_array(str) +function parsers.settings_to_array(str)      if not str or str == "" then          return { }      else @@ -3622,14 +3653,14 @@ local function set(t,v)      t[#t+1] = v  end -local value   = lpeg.P(lpeg.Carg(1)*value) / set -local pattern = value*(separator*value)^0 * lpeg.Carg(1) +local value   = P(Carg(1)*value) / set +local pattern = value*(separator*value)^0 * Carg(1) -function aux.add_settings_to_array(t,str) +function parsers.add_settings_to_array(t,str)      return lpegmatch(pattern,str,nil,t)  end -function aux.hash_to_string(h,separator,yes,no,strict,omit) +function parsers.hash_to_string(h,separator,yes,no,strict,omit)      if h then          local t, s = { }, table.sortedkeys(h)          omit = omit and table.tohash(omit) @@ -3658,7 +3689,7 @@ function aux.hash_to_string(h,separator,yes,no,strict,omit)      end  end -function aux.array_to_string(a,separator) +function parsers.array_to_string(a,separator)      if a then          return concat(a,separator or ",")      else @@ -3666,7 +3697,7 @@ function aux.array_to_string(a,separator)      end  end -function aux.settings_to_set(str,t) -- tohash? +function parsers.settings_to_set(str,t) -- tohash? -- todo: lpeg -- duplicate anyway      t = t or { }      for s in gmatch(str,"%s*([^, ]+)") do -- space added          t[s] = true @@ -3674,9 +3705,9 @@ function aux.settings_to_set(str,t) -- tohash?      return t  end -function aux.simple_hash_to_string(h, separator) +function parsers.simple_hash_to_string(h, separator)      local t = { } -    for k, v in table.sortedhash(h) do +    for k, v in sortedhash(h) do          if v then              t[#t+1] = k          end @@ -3684,43 +3715,44 @@ function aux.simple_hash_to_string(h, separator)      return concat(t,separator or ",")  end -local value     = lbrace * lpeg.C((nobrace + nested)^0) * rbrace -local pattern   = lpeg.Ct((space + value)^0) +local value   = lbrace * C((nobrace + nested)^0) * rbrace +local pattern = Ct((space + value)^0) -function aux.arguments_to_table(str) +function parsers.arguments_to_table(str)      return lpegmatch(pattern,str)  end --- temporary here +-- temporary here (unoptimized) -function aux.getparameters(self,class,parentclass,settings) +function parsers.getparameters(self,class,parentclass,settings)      local sc = self[class]      if not sc then          sc = table.clone(self[parent])          self[class] = sc      end -    aux.settings_to_hash(settings,sc) +    parsers.settings_to_hash(settings,sc)  end --- temporary here -local digit         = lpeg.R("09") -local period        = lpeg.P(".") -local zero          = lpeg.P("0") -local trailingzeros = zero^0 * -digit -- suggested by Roberto R -local case_1        = period * trailingzeros / "" -local case_2        = period * (digit - trailingzeros)^1 * (trailingzeros / "") -local number        = digit^1 * (case_1 + case_2) -local stripper      = lpeg.Cs((number + 1)^0) +end -- of closure +do -- create closure to overcome 200 locals limit -lpeg.patterns.strip_zeros = stripper +if not modules then modules = { } end modules ['util-tab'] = { +    version   = 1.001, +    comment   = "companion to luat-lib.mkiv", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} -function aux.strip_zeros(str) -    return lpegmatch(stripper,str) -end +utilities        = utilities or {} +utilities.tables = utilities.tables or { } +local tables     = utilities.tables + +local concat, format, gmatch = table.concat, string.format, string.gmatch -function aux.definetable(target) -- defines undefined tables +function tables.definetable(target) -- defines undefined tables      local composed, t = nil, { }      for name in gmatch(target,"([^%.]+)") do          if composed then @@ -3733,7 +3765,7 @@ function aux.definetable(target) -- defines undefined tables      return concat(t,"\n")  end -function aux.accesstable(target) +function tables.accesstable(target)      local t = _G      for name in gmatch(target,"([^%.]+)") do          t = t[name] @@ -3742,10 +3774,48 @@ function aux.accesstable(target)  end --- as we use this a lot ... +end -- of closure + +do -- create closure to overcome 200 locals limit + +if not modules then modules = { } end modules ['util-fmt'] = { +    version   = 1.001, +    comment   = "companion to luat-lib.mkiv", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} + +utilities            = utilities or { } +utilities.formatters = utilities.formatters or { } +local formatters     = utilities.formatters + +local concat, format = table.concat, string.format +local tostring, type = tostring, type +local strip = string.strip + +local P, R, Cs = lpeg.P, lpeg.R, lpeg.Cs +local lpegmatch = lpeg.match +-- temporary here -function aux.formatcolumns(result,between) +local digit         = R("09") +local period        = P(".") +local zero          = P("0") +local trailingzeros = zero^0 * -digit -- suggested by Roberto R +local case_1        = period * trailingzeros / "" +local case_2        = period * (digit - trailingzeros)^1 * (trailingzeros / "") +local number        = digit^1 * (case_1 + case_2) +local stripper      = Cs((number + 1)^0) + + +lpeg.patterns.strip_zeros = stripper + +function formatters.strip_zeros(str) +    return lpegmatch(stripper,str) +end + +function formatters.formatcolumns(result,between)      if result and #result > 0 then          between = between or "   "          local widths, numbers = { }, { } @@ -3790,10 +3860,10 @@ function aux.formatcolumns(result,between)                  end              end          end -        local template = string.strip(concat(widths)) +        local template = strip(concat(widths))          for i=1,#result do              local str = format(template,unpack(result[i])) -            result[i] = string.strip(str) +            result[i] = strip(str)          end      end      return result @@ -3804,6 +3874,115 @@ end -- of closure  do -- create closure to overcome 200 locals limit +if not modules then modules = { } end modules ['util.deb'] = { +    version   = 1.001, +    comment   = "companion to luat-lib.mkiv", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} + +-- the <anonymous> tag is kind of generic and used for functions that are not +-- bound to a variable, like node.new, node.copy etc (contrary to for instance +-- node.has_attribute which is bound to a has_attribute local variable in mkiv) + +local debug = require "debug" + +local getinfo = debug.getinfo +local type, next = type, next +local format, find = string.format, string.find +local is_boolean = string.is_boolean + +utilities          = utilities or { } +utilities.debugger = utilities.debugger or { } +local debugger     = utilities.debugger + +local counters = { } +local names    = { } + +-- one + +local function hook() +    local f = getinfo(2,"f").func +    local n = getinfo(2,"Sn") +--  if n.what == "C" and n.name then print (n.namewhat .. ': ' .. n.name) end +    if f then +        local cf = counters[f] +        if cf == nil then +            counters[f] = 1 +            names[f] = n +        else +            counters[f] = cf + 1 +        end +    end +end + +local function getname(func) +    local n = names[func] +    if n then +        if n.what == "C" then +            return n.name or '<anonymous>' +        else +            -- source short_src linedefined what name namewhat nups func +            local name = n.name or n.namewhat or n.what +            if not name or name == "" then name = "?" end +            return format("%s : %s : %s", n.short_src or "unknown source", n.linedefined or "--", name) +        end +    else +        return "unknown" +    end +end + +function debugger.showstats(printer,threshold) +    printer   = printer or texio.write or print +    threshold = threshold or 0 +    local total, grandtotal, functions = 0, 0, 0 +    printer("\n") -- ugly but ok + -- table.sort(counters) +    for func, count in next, counters do +        if count > threshold then +            local name = getname(func) +            if not find(name,"for generator") then +                printer(format("%8i  %s", count, name)) +                total = total + count +            end +        end +        grandtotal = grandtotal + count +        functions = functions + 1 +    end +    printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold)) +end + +-- two + + +-- rest + +function debugger.savestats(filename,threshold) +    local f = io.open(filename,'w') +    if f then +        debugger.showstats(function(str) f:write(str) end,threshold) +        f:close() +    end +end + +function debugger.enable() +    debug.sethook(hook,"c") +end + +function debugger.disable() +    debug.sethook() +end + + + + + + +end -- of closure + +do -- create closure to overcome 200 locals limit +  if not modules then modules = { } end modules ['trac-inf'] = {      version   = 1.001,      comment   = "companion to trac-inf.mkiv", @@ -3820,14 +3999,13 @@ if not modules then modules = { } end modules ['trac-inf'] = {  local format = string.format  local clock = os.gettimeofday or os.clock -- should go in environment -local statusinfo, n, registered = { }, 0, { } - -statistics = statistics or { } +statistics       = statistics or { } +local statistics = statistics  statistics.enable    = true  statistics.threshold = 0.05 -local timers = { } +local statusinfo, n, registered, timers = { }, 0, { }, { }  local function hastiming(instance)      return instance and timers[instance] @@ -3995,7 +4173,7 @@ end -- of closure  do -- create closure to overcome 200 locals limit -if not modules then modules = { } end modules ['trac-set'] = { +if not modules then modules = { } end modules ['trac-set'] = { -- might become util-set.lua      version   = 1.001,      comment   = "companion to luat-lib.mkiv",      author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -4007,8 +4185,12 @@ local type, next, tostring = type, next, tostring  local concat = table.concat  local format, find, lower, gsub, simpleesc = string.format, string.find, string.lower, string.gsub, string.simpleesc  local is_boolean = string.is_boolean +local settings_to_hash = utilities.parsers.settings_to_hash -setters = { } +utilities         = utilities or { } +local utilities   = utilities +utilities.setters = utilities.setters or { } +local setters     = utilities.setters  local data = { } -- maybe just local @@ -4064,7 +4246,7 @@ end  local function set(t,what,newvalue)      local data, done = t.data, t.done      if type(what) == "string" then -        what = aux.settings_to_hash(what) -- inefficient but ok +        what = settings_to_hash(what) -- inefficient but ok      end      for w, value in next, what do          if value == "" then @@ -4191,18 +4373,20 @@ end  -- we could have used a bit of oo and the trackers:enable syntax but  -- there is already a lot of code around using the singular tracker --- we could make this into a module +-- we could make this into a module but we also want the rest avaliable + +local enable, disable, register, list, show = setters.enable, setters.disable, setters.register, setters.list, setters.show  function setters.new(name) -    local t +    local t -- we need to access it in t      t = {          data     = { }, -- indexed, but also default and value fields          name     = name, -        enable   = function(...) setters.enable  (t,...) end, -        disable  = function(...) setters.disable (t,...) end, -        register = function(...) setters.register(t,...) end, -        list     = function(...) setters.list    (t,...) end, -        show     = function(...) setters.show    (t,...) end, +        enable   = function(...) enable  (t,...) end, +        disable  = function(...) disable (t,...) end, +        register = function(...) register(t,...) end, +        list     = function(...) list    (t,...) end, +        show     = function(...) show    (t,...) end,      }      data[name] = t      return t @@ -4212,13 +4396,18 @@ trackers    = setters.new("trackers")  directives  = setters.new("directives")  experiments = setters.new("experiments") +local t_enable, t_disable = trackers   .enable, trackers   .disable +local d_enable, d_disable = directives .enable, directives .disable +local e_enable, e_disable = experiments.enable, experiments.disable +  -- experiment  if trackers and environment and environment.engineflags.trackers then -    trackers.enable(environment.engineflags.trackers) +    t_enable(environment.engineflags.trackers)  end +  if directives and environment and environment.engineflags.directives then -    directives.enable(environment.engineflags.directives) +    d_enable(environment.engineflags.directives)  end  -- nice trick: we overload two of the directives related functions with variants that @@ -4232,30 +4421,24 @@ 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 enable  = directives.enable -local disable = directives.disable -  function directives.enable(...)      report("directives","enabling: %s",concat({...}," ")) -    enable(...) +    d_enable(...)  end  function directives.disable(...)      report("directives","disabling: %s",concat({...}," ")) -    disable(...) +    d_disable(...)  end -local enable  = experiments.enable -local disable = experiments.disable -  function experiments.enable(...)      report("experiments","enabling: %s",concat({...}," ")) -    enable(...) +    e_enable(...)  end  function experiments.disable(...)      report("experiments","disabling: %s",concat({...}," ")) -    disable(...) +    e_disable(...)  end  -- a useful example @@ -4264,136 +4447,20 @@ directives.register("system.nostatistics", function(v)      statistics.enable = not v  end) +directives.register("system.nolibraries", function(v) +    libraries = nil -- we discard this tracing for security +end) +  -- experiment  if trackers and environment and environment.engineflags.trackers then -    trackers.enable(environment.engineflags.trackers) +    t_enable(environment.engineflags.trackers)  end  if directives and environment and environment.engineflags.directives then -    directives.enable(environment.engineflags.directives) -end - - -end -- of closure - -do -- create closure to overcome 200 locals limit - -if not modules then modules = { } end modules ['trac-tra'] = { -    version   = 1.001, -    comment   = "companion to trac-tra.mkiv", -    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", -    copyright = "PRAGMA ADE / ConTeXt Development Team", -    license   = "see context related readme files" -} - --- the <anonymous> tag is kind of generic and used for functions that are not --- bound to a variable, like node.new, node.copy etc (contrary to for instance --- node.has_attribute which is bound to a has_attribute local variable in mkiv) - -local debug = require "debug" - -local getinfo = debug.getinfo -local type, next = type, next -local format, find = string.format, string.find -local is_boolean = string.is_boolean - -debugger = debugger or { } - -local counters = { } -local names = { } - --- one - -local function hook() -    local f = getinfo(2,"f").func -    local n = getinfo(2,"Sn") ---  if n.what == "C" and n.name then print (n.namewhat .. ': ' .. n.name) end -    if f then -        local cf = counters[f] -        if cf == nil then -            counters[f] = 1 -            names[f] = n -        else -            counters[f] = cf + 1 -        end -    end -end - -local function getname(func) -    local n = names[func] -    if n then -        if n.what == "C" then -            return n.name or '<anonymous>' -        else -            -- source short_src linedefined what name namewhat nups func -            local name = n.name or n.namewhat or n.what -            if not name or name == "" then name = "?" end -            return format("%s : %s : %s", n.short_src or "unknown source", n.linedefined or "--", name) -        end -    else -        return "unknown" -    end -end - -function debugger.showstats(printer,threshold) -    printer   = printer or texio.write or print -    threshold = threshold or 0 -    local total, grandtotal, functions = 0, 0, 0 -    printer("\n") -- ugly but ok - -- table.sort(counters) -    for func, count in next, counters do -        if count > threshold then -            local name = getname(func) -            if not find(name,"for generator") then -                printer(format("%8i  %s", count, name)) -                total = total + count -            end -        end -        grandtotal = grandtotal + count -        functions = functions + 1 -    end -    printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold)) -end - --- two - - --- rest - -function debugger.savestats(filename,threshold) -    local f = io.open(filename,'w') -    if f then -        debugger.showstats(function(str) f:write(str) end,threshold) -        f:close() -    end -end - -function debugger.enable() -    debug.sethook(hook,"c") -end - -function debugger.disable() -    debug.sethook() -end - -local function trace_calls(n) -    debugger.enable() -    luatex.register_stop_actions(function() -        debugger.disable() -        debugger.savestats(tex.jobname .. "-luacalls.log",tonumber(n)) -    end) -    trace_calls = function() end -end - -if directives then -    directives.register("system.tracecalls", function(n) trace_calls(n) end) -- indirect is needed for nilling +    d_enable(environment.engineflags.directives)  end - - - -  end -- of closure  do -- create closure to overcome 200 locals limit @@ -4422,7 +4489,8 @@ provide an <l n='xml'/> structured file. Actually, any logging that  is hooked into callbacks will be \XML\ by default.</p>  --ldx]]-- -logs = logs or { } +logs       = logs or { } +local logs = logs  --[[ldx--  <p>This looks pretty ugly but we need to speed things up a bit.</p> @@ -4665,8 +4733,8 @@ function noplog.simple(fmt,...) -- todo: fmt,s      end  end -if utils then -    utils.report = function(...) logs.simple(...) end +if utilities then +    utilities.report = function(...) logs.simple(...) end  end  function logs.setprogram(newname,newbanner) @@ -4736,6 +4804,50 @@ function logs.fatal(where,...)  end +function logs.obsolete(old,new) +    local o = loadstring("return " .. new)() +    if type(o) == "function" then +        return function(...) +            logs.report("system","function %s is obsolete, use %s",old,new) +            loadstring(old .. "=" .. new  .. " return ".. old)()(...) +        end +    elseif type(o) == "table" then +        local t, m = { }, { } +        m.__index = function(t,k) +            logs.report("system","table %s is obsolete, use %s",old,new) +            m.__index, m.__newindex = o, o +            return o[k] +        end +        m.__newindex = function(t,k,v) +            logs.report("system","table %s is obsolete, use %s",old,new) +            m.__index, m.__newindex = o, o +            o[k] = v +        end +        if libraries then +            libraries.obsolete[old] = t -- true +        end +        setmetatable(t,m) +        return t +    end +end + +if tex.error then + +    function logs.texerrormessage(...) -- for the moment we put this function here +        tex.error(format(...), { }) +    end + +else + +    function logs.texerrormessage(...) -- for the moment we put this function here +        local v = format(...) +        tex.sprint(tex.ctxcatcodes,"\\errmessage{") +        tex.sprint(tex.vrbcatcodes,v) +        tex.print(tex.ctxcatcodes,"}") +    end + +end +  end -- of closure @@ -4762,7 +4874,8 @@ local trace_namespaces = false  trackers.register("system.namespaces", function(  local report_system = logs.new("system") -namespaces = { } +namespaces       = namespaces or { } +local namespaces = namespaces  local registered = { } @@ -4932,6 +5045,7 @@ local report_resolvers = logs.new("resolvers")  local format, sub, match, gsub, find = string.format, string.sub, string.match, string.gsub, string.find  local unquote, quote = string.unquote, string.quote +local concat = table.concat  -- precautions @@ -4956,6 +5070,8 @@ end  -- environment  environment             = environment or { } +local environment       = environment +  environment.arguments   = { }  environment.files       = { }  environment.sortedflags = nil @@ -5078,7 +5194,7 @@ function environment.reconstruct_commandline(arg,noquote)                  result[#result+1] = a              end          end -        return table.join(result," ") +        return concat(result," ")      else          return ""      end @@ -5248,6 +5364,7 @@ optimize the code.</p>  --ldx]]--  xml = xml or { } +local xml = xml  local concat, remove, insert = table.concat, table.remove, table.insert @@ -6453,6 +6570,8 @@ of <l n='xpath'/> and since we're not compatible we call it <l n='lpath'/>. We  will explain more about its usage in other documents.</p>  --ldx]]-- +local xml = xml +  local lpathcalls  = 0  function xml.lpathcalls () return lpathcalls  end  local lpathcached = 0  function xml.lpathcached() return lpathcached end @@ -7647,6 +7766,8 @@ local type, next, tonumber, tostring, setmetatable, loadstring = type, next, ton  local format, gsub, match = string.format, string.gsub, string.match  local lpegmatch = lpeg.match +local xml = xml +  --[[ldx--  <p>The following helper functions best belong to the <t>lxml-ini</t>  module. Some are here because we need then in the <t>mk</t> @@ -7748,6 +7869,8 @@ local trace_manipulations = false  trackers.register("lxml.manipulations", funct  local report_xml = logs.new("xml") +local xml = xml +  local xmlparseapply, xmlconvert, xmlcopy, xmlname = xml.parse_apply, xml.convert, xml.copy, xml.name  local xmlinheritedconvert = xml.inheritedconvert @@ -8262,6 +8385,8 @@ if not modules then modules = { } end modules ['lxml-xml'] = {      license   = "see context related readme files"  } +local xml = xml +  local finalizers   = xml.finalizers.xml  local xmlfilter    = xml.filter -- we could inline this one for speed  local xmltostring  = xml.tostring @@ -8588,7 +8713,8 @@ local ostype, osname, ossetenv, osgetenv = os.type, os.name, os.setenv, os.geten  -- we now split it over multiple files. As this file is now the  -- starting point we introduce resolvers here. -resolvers = resolvers or { } +resolvers       = resolvers or { } +local resolvers = resolvers  -- We don't want the kpse library to kick in. Also, we want to be able to  -- execute programs. Control over execution is implemented later. @@ -8812,6 +8938,8 @@ local trace_expansions = false  trackers.register("resolvers.expansions", functi  local report_resolvers = logs.new("resolvers") +local resolvers = resolvers +  -- As this bit of code is somewhat special it gets its own module. After  -- all, when working on the main resolver code, I don't want to scroll  -- past this every time. @@ -9119,6 +9247,8 @@ if not modules then modules = { } end modules ['data-env'] = {      license   = "see context related readme files",  } +local resolvers = resolvers +  local formats      = { }  resolvers.formats      = formats  local suffixes     = { }  resolvers.suffixes     = suffixes  local dangerous    = { }  resolvers.dangerous    = dangerous @@ -9309,11 +9439,13 @@ local mkdirs, isdir = dir.mkdirs, lfs.isdir  local trace_locating = false  trackers.register("resolvers.locating", function(v) trace_locating = v end)  local trace_cache    = false  trackers.register("resolvers.cache",    function(v) trace_cache    = v end) -local report_cache = logs.new("cache") - +local report_cache      = logs.new("cache")  local report_resolvers = logs.new("resolvers") -caches = caches or { } +local resolvers = resolvers + +caches           = caches or { } +local caches     = caches  caches.base      = caches.base or "luatex-cache"  caches.more      = caches.more or "context" @@ -9558,7 +9690,7 @@ function caches.savedata(filepath,filename,data,raw)      end      local cleanup = resolvers.boolean_variable("PURGECACHE", false)      local strip = resolvers.boolean_variable("LUACSTRIP", true) -    utils.lua.compile(tmaname, tmcname, cleanup, strip) +    utilities.lua.compile(tmaname, tmcname, cleanup, strip)  end  -- moved from data-res: @@ -9620,7 +9752,7 @@ function caches.savecontent(cachename,dataname,content)          if trace_locating then              report_resolvers("category '%s', cachename '%s' saved in '%s'",dataname,cachename,luaname)          end -        if utils.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip +        if utilities.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip              if trace_locating then                  report_resolvers("'%s' compiled to '%s'",dataname,lucname)              end @@ -9657,6 +9789,8 @@ local trace_locating   = false  trackers.register("resolvers.locating",   functi  local report_resolvers = logs.new("resolvers") +local resolvers = resolvers +  resolvers.locators     = { notfound = { nil } }  -- locate databases  resolvers.hashers      = { notfound = { nil } }  -- load databases  resolvers.generators   = { notfound = { nil } }  -- generate databases @@ -9713,6 +9847,7 @@ if not modules then modules = { } end modules ['data-res'] = {  local format, gsub, find, lower, upper, match, gmatch = string.format, string.gsub, string.find, string.lower, string.upper, string.match, string.gmatch  local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys  local next, type = next, type +local os = os  local lpegP, lpegS, lpegR, lpegC, lpegCc, lpegCs, lpegCt = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct  local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns @@ -9726,10 +9861,14 @@ local trace_expansions = false  trackers.register("resolvers.expansions", functi  local report_resolvers = logs.new("resolvers") +local resolvers = resolvers +  local expanded_path_from_list  = resolvers.expanded_path_from_list  local checked_variable         = resolvers.checked_variable  local split_configuration_path = resolvers.split_configuration_path +local initializesetter = utilities.setters.initialize +  local ostype, osname, osenv, ossetenv, osgetenv = os.type, os.name, os.env, os.setenv, os.getenv  resolvers.cacheversion = '1.0.1' @@ -9949,7 +10088,7 @@ local function load_configuration_files()                                  t[k] = v                              elseif kind == "table" then                                  -- this operates on the table directly -                                setters.initialize(filename,k,v) +                                initializesetter(filename,k,v)                                  -- this doesn't (maybe metatables some day)                                  for kk, vv in next, v do -- vv = variable                                      if vv ~= unset_variable then @@ -11122,6 +11261,8 @@ if not modules then modules = { } end modules ['data-pre'] = {  local upper, lower, gsub = string.upper, string.lower, string.gsub +local resolvers = resolvers +  local prefixes = { }  local getenv = resolvers.getenv @@ -11235,6 +11376,8 @@ if not modules then modules = { } end modules ['data-inp'] = {      license   = "see context related readme files"  } +local resolvers = resolvers +  resolvers.finders = resolvers.finders or { }  resolvers.openers = resolvers.openers or { }  resolvers.loaders = resolvers.loaders or { } @@ -11256,7 +11399,7 @@ if not modules then modules = { } end modules ['data-out'] = {      license   = "see context related readme files"  } -outputs = outputs or { } +-- not used yet @@ -11291,8 +11434,8 @@ table structures without bothering about the disk cache.</p>  <p>Examples of usage can be found in the font related code.</p>  --ldx]]-- -containers = containers or { } - +containers          = containers or { } +local containers    = containers  containers.usecache = true  local report_cache = logs.new("cache") @@ -11418,6 +11561,8 @@ local trace_locating = false  trackers.register("resolvers.locating", function(v  local report_resolvers = logs.new("resolvers") +local resolvers = resolvers +  -- we will make a better format, maybe something xml or just text or lua  resolvers.automounted = resolvers.automounted or { } @@ -11526,15 +11671,20 @@ local report_resolvers = logs.new("resolvers")  -- zip:///texmf.zip?tree=/tex/texmf-local  -- zip:///texmf-mine.zip?tree=/tex/texmf-projects -zip                 = zip or { } -zip.archives        = zip.archives or { } -zip.registeredfiles = zip.registeredfiles or { } +local resolvers = resolvers + +zip                   = zip or { } +local zip             = zip + +zip.archives          = zip.archives or { } +local archives        = zip.archives + +zip.registeredfiles   = zip.registeredfiles or { } +local registeredfiles = zip.registeredfiles  local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders  local locators, hashers, concatinators = resolvers.locators, resolvers.hashers, resolvers.concatinators -local archives = zip.archives -  local function validzip(str) -- todo: use url splitter      if not find(str,"^zip://") then          return "zip:///" .. str @@ -11698,7 +11848,7 @@ function resolvers.usezipfile(zipname)      zipname = validzip(zipname)      local specification = resolvers.splitmethod(zipname)      local zipfile = specification.path -    if zipfile and not zip.registeredfiles[zipname] then +    if zipfile and not registeredfiles[zipname] then          local tree = url.query(specification.query).tree or ""          local z = zip.openarchive(zipfile)          if z then @@ -11709,7 +11859,7 @@ function resolvers.usezipfile(zipname)              statistics.starttiming(instance)              resolvers.prepend_hash('zip',zipname,zipfile)              resolvers.extend_texmf_var(zipname) -- resets hashes too -            zip.registeredfiles[zipname] = z +            registeredfiles[zipname] = z              instance.files[zipname] = resolvers.register_zip_file(z,tree or "")              statistics.stoptiming(instance)          elseif trace_locating then @@ -11769,6 +11919,8 @@ local unpack = unpack or table.unpack  local report_resolvers = logs.new("resolvers") +local resolvers = resolvers +  local done, found, notfound = { }, { }, resolvers.finders.notfound  function resolvers.finders.tree(specification,filetype) @@ -11851,11 +12003,15 @@ if not modules then modules = { } end modules ['data-crl'] = {  -- this one is replaced by data-sch.lua -- -curl = curl or { } -  local gsub = string.gsub + +local resolvers = resolvers +  local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders +curl = curl or { } +local curl = curl +  local cached = { }  function curl.fetch(protocol, name) -- todo: use socket library @@ -11925,6 +12081,8 @@ local report_resolvers = logs.new("resolvers")  local gsub, insert = string.gsub, table.insert  local unpack = unpack or table.unpack +local resolvers, package = resolvers, package +  local  libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -- 'luainputs'  local clibformats = { 'lib' } @@ -12079,6 +12237,8 @@ local type, next = type, next  local trace_locating = false  trackers.register("resolvers.locating", function(v) trace_locating = v end) +local resolvers = resolvers +  local report_resolvers = logs.new("resolvers")  function resolvers.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix @@ -12140,6 +12300,8 @@ if not modules then modules = { } end modules ['data-tmf'] = {      license   = "see context related readme files"  } +local resolvers = resolvers +  --  =  <<  --  ?  ??  --  <  += @@ -12209,6 +12371,8 @@ local find, concat, upper, format = string.find, table.concat, string.upper, str  resolvers.listers = resolvers.listers or { } +local resolvers = resolvers +  local function tabstr(str)      if type(str) == 'table' then          return concat(str," | ") @@ -12258,9 +12422,15 @@ if not modules then modules = { } end modules ['luat-sta'] = {  local gmatch, match = string.gmatch, string.match  local type = type -states          = states          or { } -states.data     = states.data     or { } -states.hash     = states.hash     or { } +states          = states or { } +local states    = states + +states.data     = states.data or { } +local data      = states.data + +states.hash     = states.hash or { } +local hash      = states.hash +  states.tag      = states.tag      or ""  states.filename = states.filename or "" @@ -12270,7 +12440,7 @@ function states.save(filename,tag)      io.savedata(filename,          "-- generator : luat-sta.lua\n" ..          "-- state tag : " .. tag .. "\n\n" .. -        table.serialize(states.data[tag or states.tag] or {},true) +        table.serialize(data[tag or states.tag] or {},true)      )  end @@ -12278,11 +12448,11 @@ function states.load(filename,tag)      states.filename = filename      states.tag = tag or "whatever"      states.filename = file.addsuffix(states.filename,'lus') -    states.data[states.tag], states.hash[states.tag] = (io.exists(filename) and dofile(filename)) or { }, { } +    data[states.tag], hash[states.tag] = (io.exists(filename) and dofile(filename)) or { }, { }  end -function states.set_by_tag(tag,key,value,default,persistent) -    local d, h = states.data[tag], states.hash[tag] +local function set_by_tag(tag,key,value,default,persistent) +    local d, h = data[tag], hash[tag]      if d then          if type(d) == "table" then              local dkey, hkey = key, key @@ -12312,17 +12482,17 @@ function states.set_by_tag(tag,key,value,default,persistent)              d[dkey], h[hkey] = value, value          elseif type(d) == "string" then              -- weird -            states.data[tag], states.hash[tag] = value, value +            data[tag], hash[tag] = value, value          end      end  end -function states.get_by_tag(tag,key,default) -    local h = states.hash[tag] +local function get_by_tag(tag,key,default) +    local h = hash[tag]      if h and h[key] then          return h[key]      else -        local d = states.data[tag] +        local d = data[tag]          if d then              for k in gmatch(key,"[^%.]+") do                  local dk = d[k] @@ -12337,12 +12507,15 @@ function states.get_by_tag(tag,key,default)      end  end +states.set_by_tag = set_by_tag +states.get_by_tag = get_by_tag +  function states.set(key,value,default,persistent) -    states.set_by_tag(states.tag,key,value,default,persistent) +    set_by_tag(states.tag,key,value,default,persistent)  end  function states.get(key,default) -    return states.get_by_tag(states.tag,key,default) +    return get_by_tag(states.tag,key,default)  end @@ -12422,10 +12595,10 @@ function environment.make_format(name)          local lucstubname = file.addsuffix(texbasename,"luc")          -- pack libraries in stub          logs.simple("creating initialization file: %s",luastubname) -        utils.merger.selfcreate(usedlualibs,specificationpath,luastubname) +        utilities.merger.selfcreate(usedlualibs,specificationpath,luastubname)          -- compile stub file (does not save that much as we don't use this stub at startup any more)          local strip = resolvers.boolean_variable("LUACSTRIP", true) -        if utils.lua.compile(luastubname,lucstubname,false,strip) and lfs.isfile(lucstubname) then +        if utilities.lua.compile(luastubname,lucstubname,false,strip) and lfs.isfile(lucstubname) then              logs.simple("using compiled initialization file: %s",lucstubname)              usedluastub = lucstubname          else @@ -12507,12 +12680,16 @@ own.libs = { -- order can be made better      'l-boolean.lua',      'l-unicode.lua',      'l-math.lua', -    'l-utils.lua', -    'l-aux.lua', + +    'util-mrg.lua', +    'util-lua.lua', +    'util-prs.lua', +    'util-tab.lua', +    'util-fmt.lua', +    'util-deb.lua',      'trac-inf.lua',      'trac-set.lua', -    'trac-tra.lua',      'trac-log.lua',      'trac-pro.lua',      'luat-env.lua', -- can come before inf (as in mkiv) @@ -12524,7 +12701,6 @@ own.libs = { -- order can be made better      'lxml-aux.lua',      'lxml-xml.lua', -      'data-ini.lua',      'data-exp.lua',      'data-env.lua', @@ -12589,6 +12765,7 @@ local function locate_libs()              local filename = pth .. "/" .. lib              local found = lfs.isfile(filename)              if found then +                package.path = package.path .. ";" .. pth .. "/?.lua" -- in case l-* does a require                  return pth              end          end @@ -13326,7 +13503,7 @@ if environment.argument("selfmerge") then      runners.loadbase()      local found = locate_libs()      if found then -        utils.merger.selfmerge(own.name,own.libs,{ found }) +        utilities.merger.selfmerge(own.name,own.libs,{ found })      end  elseif environment.argument("selfclean") then @@ -13334,7 +13511,7 @@ elseif environment.argument("selfclean") then      -- remove embedded libraries      runners.loadbase() -    utils.merger.selfclean(own.name) +    utilities.merger.selfclean(own.name)  elseif environment.argument("selfupdate") then @@ -13599,6 +13776,7 @@ elseif false then  else +    runners.loadbase()      runners.execute_ctx_script("mtx-base",filename)  end | 
