diff options
| author | Context Git Mirror Bot <phg42.2a@gmail.com> | 2014-07-03 15:15:05 +0200 | 
|---|---|---|
| committer | Context Git Mirror Bot <phg42.2a@gmail.com> | 2014-07-03 15:15:05 +0200 | 
| commit | 6d60c7dc7fbd0b15d205c16ac47dcb8efaefe772 (patch) | |
| tree | 3e28efb0e65ac9519a9754b89f9fb76bffa7db71 /scripts | |
| parent | 8e8dd7540025b45c0fcb5687bcfeb12928b74426 (diff) | |
| download | context-6d60c7dc7fbd0b15d205c16ac47dcb8efaefe772.tar.gz | |
2014-07-03 14:54:00
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/context/lua/mtxrun.lua | 1331 | ||||
| -rw-r--r-- | scripts/context/stubs/mswin/mtxrun.lua | 1331 | ||||
| -rw-r--r-- | scripts/context/stubs/unix/mtxrun | 1331 | ||||
| -rw-r--r-- | scripts/context/stubs/win64/mtxrun.lua | 1331 | 
4 files changed, 3012 insertions, 2312 deletions
diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index 189fc4b7b..70f493525 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -1195,7 +1195,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["l-table"] = package.loaded["l-table"] or true --- original size: 31828, stripped down to: 20814 +-- original size: 33243, stripped down to: 21578  if not modules then modules={} end modules ['l-table']={    version=1.001, @@ -1342,14 +1342,14 @@ local function sortedhash(t,cmp)      end      local n=0      local m=#s -    local function kv(s) +    local function kv()         if n<m then          n=n+1          local k=s[n]          return k,t[k]        end      end -    return kv,s +    return kv     else      return nothing    end @@ -2110,6 +2110,44 @@ function table.values(t,s)      return {}    end  end +function table.filtered(t,pattern,sort,cmp) +  if t and type(pattern)=="string" then +    if sort then +      local s +      if cmp then +        s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) +      else +        s=sortedkeys(t)  +      end +      local n=0 +      local m=#s +      local function kv(s) +        while n<m do +          n=n+1 +          local k=s[n] +          if find(k,pattern) then +            return k,t[k] +          end +        end +      end +      return kv,s +    else +      local n=next(t) +      local function iterator() +        while n do +          local k=n +          n=next(t,k) +          if find(k,pattern) then +            return k,t[k] +          end +        end +      end +      return iterator,t +    end +  else +    return nothing +  end +end  end -- of closure @@ -3775,7 +3813,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["l-dir"] = package.loaded["l-dir"] or true --- original size: 14788, stripped down to: 9096 +-- original size: 16056, stripped down to: 10707  if not modules then modules={} end modules ['l-dir']={    version=1.001, @@ -3785,7 +3823,7 @@ if not modules then modules={} end modules ['l-dir']={    license="see context related readme files"  }  local type,select=type,select -local find,gmatch,match,gsub=string.find,string.gmatch,string.match,string.gsub +local find,gmatch,match,gsub,sub=string.find,string.gmatch,string.match,string.gsub,string.sub  local concat,insert,remove,unpack=table.concat,table.insert,table.remove,table.unpack  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 @@ -3794,54 +3832,123 @@ local dir=dir  local lfs=lfs  local attributes=lfs.attributes  local walkdir=lfs.dir -local isdir=lfs.isdir -local isfile=lfs.isfile +local isdir=lfs.isdir  +local isfile=lfs.isfile   local currentdir=lfs.currentdir  local chdir=lfs.chdir  local mkdir=lfs.mkdir  local onwindows=os.type=="windows" or find(os.getenv("PATH"),";",1,true) -if not isdir then -  function isdir(name) -    local a=attributes(name) -    return a and a.mode=="directory" +if onwindows then +  isdir=function(name) +    name=gsub(name,"([/\\]+)$","/.") +    return attributes(name,"mode")=="directory" +  end +  isfile=function(name) +    return attributes(name,"mode")=="file"    end    lfs.isdir=isdir -end -if not isfile then -  function isfile(name) -    local a=attributes(name) -    return a and a.mode=="file" +  lfs.isfile=isfile +else +  isdir=function(name) +    return attributes(name,"mode")=="directory" +  end +  isfile=function(name) +    return attributes(name,"mode")=="file"    end +  lfs.isdir=isdir    lfs.isfile=isfile  end  function dir.current()    return (gsub(currentdir(),"\\","/"))  end -local lfsisdir=isdir -local function isdir(path) -  path=gsub(path,"[/\\]+$","") -  return lfsisdir(path) +local function glob_pattern_function(path,patt,recurse,action) +  if isdir(path) then +    local usedpath +    if path=="/" then +      usedpath="/." +    elseif not find(path,"/$") then +      usedpath=path.."/." +      path=path.."/" +    else +      usedpath=path +    end +    local dirs +    for name in walkdir(usedpath) do +      if name~="." and name~=".." then +        local full=path..name +        local mode=attributes(full,'mode') +        if mode=='file' then +          if not patt or find(full,patt) then +            action(full) +          end +        elseif recurse and mode=="directory" then +          if not dirs then +            dirs={ full } +          else +            dirs[#dirs+1]=full +          end +        end +      end +    end +    if dirs then +      for i=1,#dirs do +        glob_pattern_function(dirs[i],patt,recurse,action) +      end +    end +  end  end -lfs.isdir=isdir -local function globpattern(path,patt,recurse,action) -  if path=="/" then -    path=path.."." -  elseif not find(path,"/$") then -    path=path..'/' -  end -  if isdir(path) then  -    for name in walkdir(path) do  -      local full=path..name -      local mode=attributes(full,'mode') -      if mode=='file' then -        if find(full,patt) then -          action(full) +local function glob_pattern_table(path,patt,recurse,result) +  if not result then +    result={} +  end +  if isdir(path) then +    local usedpath +    if path=="/" then +      usedpath="/." +    elseif not find(path,"/$") then +      usedpath=path.."/." +      path=path.."/" +    else +      usedpath=path +    end +    local dirs +    for name in walkdir(usedpath) do +      if name~="." and name~=".." then +        local full=path..name +        local mode=attributes(full,'mode') +        if mode=='file' then +          if not patt or find(full,patt) then +            result[#result+1]=full +          end +        elseif recurse and mode=="directory" then +          if not dirs then +            dirs={ full } +          else +            dirs[#dirs+1]=full +          end          end -      elseif recurse and (mode=="directory") and (name~='.') and (name~="..") then -        globpattern(full,patt,recurse,action) +      end +    end +    if dirs then +      for i=1,#dirs do +        glob_pattern_table(dirs[i],patt,recurse,result)        end      end    end +  return result +end +local function globpattern(path,patt,recurse,method) +  local kind=type(method) +  if pattern and sub(patt,1,-3)==path then +    patt=false +  end +  if kind=="function" then +    return glob_pattern_function(path,patt,recurse,method) +  elseif kind=="table" then +    return glob_pattern_table(path,patt,recurse,method) +  else +    return glob_pattern_table(path,patt,recurse,{}) +  end  end  dir.globpattern=globpattern  local function collectpattern(path,patt,recurse,result) @@ -3853,18 +3960,24 @@ local function collectpattern(path,patt,recurse,result)      ok,scanner,first=xpcall(function() return walkdir(path)   end,function() end)     end    if ok and type(scanner)=="function" then -    if not find(path,"/$") then path=path..'/' end +    if not find(path,"/$") then +      path=path..'/' +    end      for name in scanner,first do -      local full=path..name -      local attr=attributes(full) -      local mode=attr.mode -      if mode=='file' then -        if find(full,patt) then +      if name=="." then +      elseif name==".." then +      else +        local full=path..name +        local attr=attributes(full) +        local mode=attr.mode +        if mode=='file' then +          if find(full,patt) then +            result[name]=attr +          end +        elseif recurse and mode=="directory" then +          attr.list=collectpattern(full,patt,recurse)            result[name]=attr          end -      elseif recurse and (mode=="directory") and (name~='.') and (name~="..") then -        attr.list=collectpattern(full,patt,recurse) -        result[name]=attr        end      end    end @@ -3872,15 +3985,15 @@ local function collectpattern(path,patt,recurse,result)  end  dir.collectpattern=collectpattern  local separator -if onwindows then +if onwindows then     local slash=S("/\\")/"/" -  pattern=Ct { +  pattern={      [1]=(Cs(P(".")+slash^1)+Cs(R("az","AZ")*P(":")*slash^0)+Cc("./"))*V(2)*V(3),      [2]=Cs(((1-S("*?/\\"))^0*slash)^0),      [3]=Cs(P(1)^0)    } -else  -  pattern=Ct { +else +  pattern={      [1]=(C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3),      [2]=C(((1-S("*?/"))^0*P("/"))^0),      [3]=C(P(1)^0) @@ -3898,9 +4011,8 @@ local function glob(str,t)      elseif isfile(str) then        t(str)      else -      local split=lpegmatch(pattern,str)  -      if split then -        local root,path,base=split[1],split[2],split[3] +      local root,path,base=lpegmatch(pattern,str)  +      if root and path and base then          local recurse=find(base,"**",1,true)           local start=root..path          local result=lpegmatch(filter,start..base) @@ -3922,16 +4034,12 @@ local function glob(str,t)          return { str }        end      else -      local split=lpegmatch(pattern,str)  -      if split then -        local t=t or {} -        local action=action or function(name) t[#t+1]=name end -        local root,path,base=split[1],split[2],split[3] +      local root,path,base=lpegmatch(pattern,str)  +      if root and path and base then          local recurse=find(base,"**",1,true)           local start=root..path          local result=lpegmatch(filter,start..base) -        globpattern(start,result,recurse,action) -        return t +        return globpattern(start,result,recurse,t)        else          return {}        end @@ -4879,7 +4987,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["util-str"] = package.loaded["util-str"] or true --- original size: 33485, stripped down to: 18420 +-- original size: 34240, stripped down to: 18733  if not modules then modules={} end modules ['util-str']={    version=1.001, @@ -5544,6 +5652,15 @@ else    add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=lpeg.patterns.texescape })    add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=lpeg.patterns.luaescape })  end +local dquote=patterns.dquote  +local equote=patterns.escaped+dquote/'\\"'+1 +local space=patterns.space +local cquote=Cc('"') +local pattern=Cs(dquote*(equote-P(-2))^0*dquote)           ++Cs(cquote*(equote-space)^0*space*equote^0*cquote)  +function string.optionalquoted(str) +  return lpegmatch(pattern,str) or str +end  end -- of closure @@ -8717,7 +8834,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["util-env"] = package.loaded["util-env"] or true --- original size: 8814, stripped down to: 5092 +-- original size: 8022, stripped down to: 5038  if not modules then modules={} end modules ['util-env']={    version=1.001, @@ -8728,7 +8845,7 @@ if not modules then modules={} end modules ['util-env']={  }  local allocate,mark=utilities.storage.allocate,utilities.storage.mark  local format,sub,match,gsub,find=string.format,string.sub,string.match,string.gsub,string.find -local unquoted,quoted=string.unquoted,string.quoted +local unquoted,quoted,optionalquoted=string.unquoted,string.quoted,string.optionalquoted  local concat,insert,remove=table.concat,table.insert,table.remove  environment=environment or {}  local environment=environment @@ -8841,24 +8958,14 @@ function environment.splitarguments(separator)    return before,after  end  function environment.reconstructcommandline(arg,noquote) +  local resolveprefix=resolvers.resolve     arg=arg or environment.originalarguments    if noquote and #arg==1 then -    local a=arg[1] -    a=resolvers.resolve(a) -    a=unquoted(a) -    return a +    return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1])    elseif #arg>0 then      local result={}      for i=1,#arg do -      local a=arg[i] -      a=resolvers.resolve(a) -      a=unquoted(a) -      a=gsub(a,'"','\\"')  -      if find(a," ",1,true) then -        result[#result+1]=quoted(a) -      else -        result[#result+1]=a -      end +      result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix)      end      return concat(result," ")    else @@ -12483,7 +12590,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-ini"] = package.loaded["data-ini"] or true --- original size: 7927, stripped down to: 5528 +-- original size: 10598, stripped down to: 7341  if not modules then modules={} end modules ['data-ini']={    version=1.001, @@ -12492,14 +12599,15 @@ if not modules then modules={} end modules ['data-ini']={    copyright="PRAGMA ADE / ConTeXt Development Team",    license="see context related readme files",  } +local next,type,getmetatable,rawset=next,type,getmetatable,rawset  local gsub,find,gmatch,char=string.gsub,string.find,string.gmatch,string.char -local next,type=next,type  local filedirname,filebasename,filejoin=file.dirname,file.basename,file.join +local ostype,osname,osuname,ossetenv,osgetenv=os.type,os.name,os.uname,os.setenv,os.getenv +local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match  local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end)  local trace_detail=false trackers.register("resolvers.details",function(v) trace_detail=v end)  local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end)  local report_initialization=logs.reporter("resolvers","initialization") -local ostype,osname,ossetenv,osgetenv=os.type,os.name,os.setenv,os.getenv  resolvers=resolvers or {}  local resolvers=resolvers  texconfig.kpse_init=false @@ -12632,10 +12740,88 @@ if type(profiler)=="table" and not jit then      profiler.start("luatex-profile.log")    end)  end -if not resolvers.resolve then -  function resolvers.resolve (s) return s end -  function resolvers.unresolve(s) return s end -  function resolvers.repath  (s) return s end +local prefixes=utilities.storage.allocate() +resolvers.prefixes=prefixes +local resolved={} +local abstract={} +function resolvers.resetresolve(str) +  resolved,abstract={},{} +end +function resolvers.allprefixes(separator) +  local all=table.sortedkeys(prefixes) +  if separator then +    for i=1,#all do +      all[i]=all[i]..":" +    end +  end +  return all +end +local function _resolve_(method,target) +  local action=prefixes[method] +  if action then +    return action(target) +  else +    return method..":"..target +  end +end +function resolvers.unresolve(str) +  return abstract[str] or str +end +local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) +local prefix=C(R("az")^2)*P(":") +local target=C((1-S(" \"\';,"))^1) +local notarget=(#S(";,")+P(-1))*Cc("") +local pattern=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) +local function resolve(str)  +  if type(str)=="table" then +    local res={} +    for i=1,#str do +      res[i]=resolve(str[i]) +    end +    return res +  else +    local res=resolved[str] +    if not res then +      res=lpegmatch(pattern,str) +      resolved[str]=res +      abstract[res]=str +    end +    return res +  end +end +resolvers.resolve=resolve +if type(osuname)=="function" then +  for k,v in next,osuname() do +    if not prefixes[k] then +      prefixes[k]=function() return v end +    end +  end +end +if ostype=="unix" then +  local pattern +  local function makepattern(t,k,v) +    if t then +      rawset(t,k,v) +    end +    local colon=P(":") +    for k,v in table.sortedpairs(prefixes) do +      if p then +        p=P(k)+p +      else +        p=P(k) +      end +    end +    pattern=Cs((p*colon+colon/";"+P(1))^0) +  end +  makepattern() +  table.setmetatablenewindex(prefixes,makepattern) +  function resolvers.repath(str) +    return lpegmatch(pattern,str) +  end +else  +  function resolvers.repath(str) +    return str +  end  end @@ -12645,7 +12831,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-exp"] = package.loaded["data-exp"] or true --- original size: 15317, stripped down to: 9723 +-- original size: 16463, stripped down to: 10113  if not modules then modules={} end modules ['data-exp']={    version=1.001, @@ -12660,11 +12846,14 @@ local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns  local Ct,Cs,Cc,Carg,P,C,S=lpeg.Ct,lpeg.Cs,lpeg.Cc,lpeg.Carg,lpeg.P,lpeg.C,lpeg.S  local type,next=type,next  local ostype=os.type -local collapsepath=file.collapsepath +local collapsepath,joinpath,basename=file.collapsepath,file.join,file.basename  local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end)  local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_globbing=true  trackers.register("resolvers.globbing",function(v) trace_globbing=v end)  local report_expansions=logs.reporter("resolvers","expansions") +local report_globbing=logs.reporter("resolvers","globbing")  local resolvers=resolvers +local resolveprefix=resolvers.resolve  local function f_both(a,b)    local t,n={},0    for sb in gmatch(b,"[^,]+") do        @@ -12754,35 +12943,27 @@ function resolvers.expandedpathfromlist(pathlist)    end    return newlist  end -local cleanup=lpeg.replacer { -  { "!","" }, -  { "\\","/" }, -} -function resolvers.cleanpath(str)  -  local doslashes=(P("\\")/"/"+1)^0 -  local donegation=(P("!")/""   )^0 -  local homedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") -  if homedir=="~" or homedir=="" or not lfs.isdir(homedir) then -    if trace_expansions then -      report_expansions("no home dir set, ignoring dependent paths") -    end -    function resolvers.cleanpath(str) -      if not str or find(str,"~",1,true) then -        return ""  -      else -        return lpegmatch(cleanup,str) +local usedhomedir=nil +local donegation=(P("!")/""   )^0 +local doslashes=(P("\\")/"/"+1)^0 +local function expandedhome() +  if not usedhomedir then +    usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") +    if usedhomedir=="~" or usedhomedir=="" or not lfs.isdir(usedhomedir) then +      if trace_expansions then +        report_expansions("no home dir set, ignoring dependent path using current path")        end -    end -  else -    local dohome=((P("~")+P("$HOME"))/homedir)^0 -    local cleanup=Cs(donegation*dohome*doslashes) -    function resolvers.cleanpath(str) -      return str and lpegmatch(cleanup,str) or "" +      usedhomedir="."      end    end -  return resolvers.cleanpath(str) +  return usedhomedir +end +local dohome=((P("~")+P("$HOME")+P("%HOME%"))/expandedhome)^0 +local cleanup=Cs(donegation*dohome*doslashes) +resolvers.cleanpath=function(str) +  return str and lpegmatch(cleanup,str) or ""  end -local expandhome=P("~")/"$HOME"  +local expandhome=P("~")/"$HOME"  local dodouble=P('"')/""*(expandhome+(1-P('"')))^0*P('"')/""  local dosingle=P("'")/""*(expandhome+(1-P("'")))^0*P("'")/""  local dostring=(expandhome+1       )^0 @@ -12834,7 +13015,7 @@ function resolvers.splitpath(str)  end  function resolvers.joinpath(str)    if type(str)=='table' then -    return file.joinpath(str) +    return joinpath(str)    else      return str    end @@ -12845,35 +13026,54 @@ local timer={}  local scanned={}  local nofscans=0  local scancache={} -local function scan(files,spec,path,n,m,r) -  local full=(path=="" and spec) or (spec..path..'/') +local fullcache={} +local nofsharedscans=0 +local function scan(files,remap,spec,path,n,m,r,onlyone) +  local full=path=="" and spec or (spec..path..'/')    local dirs={}    local nofdirs=0    for name in directory(full) do      if not lpegmatch(weird,name) then -      local mode=attributes(full..name,'mode') -      if mode=='file' then +      local mode=attributes(full..name,"mode") +      if mode=="file" then          n=n+1 -        local f=files[name] -        if f then -          if type(f)=='string' then -            files[name]={ f,path } +        local lower=lower(name) +        local paths=files[lower] +        if paths then +          if onlyone then            else -            f[#f+1]=path +            if type(paths)=="string" then +              files[lower]={ paths,path } +            else +              paths[#paths+1]=path +            end +            if name~=lower then +              local rl=remap[lower] +              if not rl then +                remap[lower]=name +                r=r+1 +              elseif trace_globbing and rl~=name then +                report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) +              end +            end            end          else  -          files[name]=path -          local lower=lower(name) +          files[lower]=path            if name~=lower then -            files["remap:"..lower]=name -            r=r+1 +            local rl=remap[lower] +            if not rl then +              remap[lower]=name +              r=r+1 +            elseif trace_globbing and rl~=name then +              report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) +            end            end          end -      elseif mode=='directory' then +      elseif mode=="directory" then          m=m+1          nofdirs=nofdirs+1          if path~="" then -          dirs[nofdirs]=path..'/'..name +          dirs[nofdirs]=path.."/"..name          else            dirs[nofdirs]=name          end @@ -12883,107 +13083,52 @@ local function scan(files,spec,path,n,m,r)    if nofdirs>0 then      sort(dirs)      for i=1,nofdirs do -      files,n,m,r=scan(files,spec,dirs[i],n,m,r) +      files,remap,n,m,r=scan(files,remap,spec,dirs[i],n,m,r,onlyone)      end    end    scancache[sub(full,1,-2)]=files -  return files,n,m,r +  return files,remap,n,m,r  end -local fullcache={} -function resolvers.scanfiles(path,branch,usecache) -  statistics.starttiming(timer) -  local realpath=resolvers.resolve(path)  +function resolvers.scanfiles(path,branch,usecache,onlyonce) +  local realpath=resolveprefix(path)    if usecache then -    local files=fullcache[realpath] -    if files then +    local content=fullcache[realpath] +    if content then        if trace_locating then -        report_expansions("using caches scan of path %a, branch %a",path,branch or path) +        report_expansions("using cached scan of path %a, branch %a",path,branch or path)        end -      return files +      nofsharedscans=nofsharedscans+1 +      return content      end    end +  statistics.starttiming(timer)    if trace_locating then      report_expansions("scanning path %a, branch %a",path,branch or path)    end -  local files,n,m,r=scan({},realpath..'/',"",0,0,0) -  files.__path__=path  -  files.__files__=n -  files.__directories__=m -  files.__remappings__=r +  local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce) +  local content={ +    metadata={ +      path=path, +      files=n, +      directories=m, +      remappings=r, +    }, +    files=files, +    remap=remap, +  }    if trace_locating then      report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r)    end    if usecache then      scanned[#scanned+1]=realpath -    fullcache[realpath]=files +    fullcache[realpath]=content    end    nofscans=nofscans+1    statistics.stoptiming(timer) -  return files -end -local function simplescan(files,spec,path)  -  local full=(path=="" and spec) or (spec..path..'/') -  local dirs={} -  local nofdirs=0 -  for name in directory(full) do -    if not lpegmatch(weird,name) then -      local mode=attributes(full..name,'mode') -      if mode=='file' then -        if not files[name] then -          files[name]=path -        end -      elseif mode=='directory' then -        nofdirs=nofdirs+1 -        if path~="" then -          dirs[nofdirs]=path..'/'..name -        else -          dirs[nofdirs]=name -        end -      end -    end -  end -  if nofdirs>0 then -    sort(dirs) -    for i=1,nofdirs do -      files=simplescan(files,spec,dirs[i]) -    end -  end -  return files +  return content  end -local simplecache={} -local nofsharedscans=0  function resolvers.simplescanfiles(path,branch,usecache) -  statistics.starttiming(timer) -  local realpath=resolvers.resolve(path)  -  if usecache then -    local files=simplecache[realpath] -    if not files then -      files=scancache[realpath] -      if files then -        nofsharedscans=nofsharedscans+1 -      end -    end -    if files then -      if trace_locating then -        report_expansions("using caches scan of path %a, branch %a",path,branch or path) -      end -      return files -    end -  end -  if trace_locating then -    report_expansions("scanning path %a, branch %a",path,branch or path) -  end -  local files=simplescan({},realpath..'/',"") -  if trace_locating then -    report_expansions("%s files found",table.count(files)) -  end -  if usecache then -    scanned[#scanned+1]=realpath -    simplecache[realpath]=files -  end -  nofscans=nofscans+1 -  statistics.stoptiming(timer) -  return files +  return resolvers.scanfiles(path,branch,usecache,true)   end  function resolvers.scandata()    table.sort(scanned) @@ -12994,6 +13139,49 @@ function resolvers.scandata()      paths=scanned,    }  end +function resolvers.get_from_content(content,path,name)  +  local files=content.files +  if not files then +    return +  end +  local remap=content.remap +  if not remap then +    return +  end +  if name then +    local used=lower(name) +    return path,remap[used] or used +  else +    local name=path +    local used=lower(name) +    local path=files[used] +    if path then +      return path,remap[used] or used +    end +  end +end +local nothing=function() end +function resolvers.filtered_from_content(content,pattern) +  if content and type(pattern)=="string" then +    local pattern=lower(pattern) +    local files=content.files +    local remap=content.remap +    if files and remap then +      local n=next(files) +      local function iterator() +        while n do +          local k=n +          n=next(files,k) +          if find(k,pattern) then +            return files[k],remap and remap[k] or k +          end +        end +      end +      return iterator +    end +  end +  return nothing +end  end -- of closure @@ -13272,7 +13460,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-tmp"] = package.loaded["data-tmp"] or true --- original size: 15532, stripped down to: 11648 +-- original size: 15681, stripped down to: 11761  if not modules then modules={} end modules ['data-tmp']={    version=1.100, @@ -13291,6 +13479,7 @@ local trace_cache=false trackers.register("resolvers.cache",function(v) trace_ca  local report_caches=logs.reporter("resolvers","caches")  local report_resolvers=logs.reporter("resolvers","caching")  local resolvers=resolvers +local cleanpath=resolvers.cleanpath  local directive_cleanup=false directives.register("system.compile.cleanup",function(v) directive_cleanup=v end)  local directive_strip=false directives.register("system.compile.strip",function(v) directive_strip=v end)  local compile=utilities.lua.compile @@ -13312,7 +13501,7 @@ caches.relocate=false  caches.defaults={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" }  local writable,readables,usedreadables=nil,{},{}  local function identify() -  local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") +  local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE")     if texmfcaches then      for k=1,#texmfcaches do        local cachepath=texmfcaches[k] @@ -13566,10 +13755,12 @@ local content_state={}  function caches.contentstate()    return content_state or {}  end -function caches.loadcontent(cachename,dataname) -  local name=caches.hashed(cachename) -  local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") -  local filename=file.join(path,name) +function caches.loadcontent(cachename,dataname,filename) +  if not filename then +    local name=caches.hashed(cachename) +    local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") +    filename=file.join(path,name) +  end    local blob=loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua))    if blob then      local data=blob() @@ -13601,10 +13792,12 @@ function caches.collapsecontent(content)      end    end  end -function caches.savecontent(cachename,dataname,content) -  local name=caches.hashed(cachename) -  local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") -  local filename=file.join(path,name)  +function caches.savecontent(cachename,dataname,content,filename) +  if not filename then +    local name=caches.hashed(cachename) +    local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") +    filename=file.join(path,name)  +  end    local luaname=addsuffix(filename,luasuffixes.lua)    local lucname=addsuffix(filename,luasuffixes.luc)    if trace_locating then @@ -13647,7 +13840,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-met"] = package.loaded["data-met"] or true --- original size: 5460, stripped down to: 4014 +-- original size: 5347, stripped down to: 4015  if not modules then modules={} end modules ['data-met']={    version=1.100, @@ -13675,7 +13868,7 @@ local function splitmethod(filename)    if type(filename)=="table" then      return filename     end -  filename=file.collapsepath(filename,".") +  filename=file.collapsepath(filename,".")     if not find(filename,"://",1,true) then      return { scheme="file",path=filename,original=filename,filename=filename }    end @@ -13766,7 +13959,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-res"] = package.loaded["data-res"] or true --- original size: 62045, stripped down to: 43116 +-- original size: 61031, stripped down to: 42613  if not modules then modules={} end modules ['data-res']={    version=1.001, @@ -13776,7 +13969,7 @@ if not modules then modules={} end modules ['data-res']={    license="see context related readme files",  }  local gsub,find,lower,upper,match,gmatch=string.gsub,string.find,string.lower,string.upper,string.match,string.gmatch -local concat,insert,sortedkeys=table.concat,table.insert,table.sortedkeys +local concat,insert,sortedkeys,sortedhash=table.concat,table.insert,table.sortedkeys,table.sortedhash  local next,type,rawget=next,type,rawget  local os=os  local P,S,R,C,Cc,Cs,Ct,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cc,lpeg.Cs,lpeg.Ct,lpeg.Carg @@ -13785,14 +13978,19 @@ local formatters=string.formatters  local filedirname=file.dirname  local filebasename=file.basename  local suffixonly=file.suffixonly +local addsuffix=file.addsuffix +local removesuffix=file.removesuffix  local filejoin=file.join  local collapsepath=file.collapsepath  local joinpath=file.joinpath +local is_qualified_path=file.is_qualified_path  local allocate=utilities.storage.allocate  local settings_to_array=utilities.parsers.settings_to_array +local getcurrentdir=lfs.currentdir +local isfile=lfs.isfile +local isdir=lfs.isdir  local setmetatableindex=table.setmetatableindex  local luasuffixes=utilities.lua.suffixes -local getcurrentdir=lfs.currentdir  local trace_locating=false trackers .register("resolvers.locating",function(v) trace_locating=v end)  local trace_detail=false trackers .register("resolvers.details",function(v) trace_detail=v end)  local trace_expansions=false trackers .register("resolvers.expansions",function(v) trace_expansions=v end) @@ -13803,10 +14001,14 @@ local expandedpathfromlist=resolvers.expandedpathfromlist  local checkedvariable=resolvers.checkedvariable  local splitconfigurationpath=resolvers.splitconfigurationpath  local methodhandler=resolvers.methodhandler +local filtered=resolvers.filtered_from_content +local lookup=resolvers.get_from_content +local cleanpath=resolvers.cleanpath +local resolveprefix=resolvers.resolve  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' -resolvers.configbanner='' +resolvers.cacheversion="1.100" +resolvers.configbanner=""  resolvers.homedir=environment.homedir  resolvers.criticalvars=allocate { "SELFAUTOLOC","SELFAUTODIR","SELFAUTOPARENT","TEXMFCNF","TEXMF","TEXOS" }  resolvers.luacnfname="texmfcnf.lua" @@ -13833,7 +14035,7 @@ local   instance=resolvers.instance or nil  function resolvers.setenv(key,value,raw)    if instance then      instance.environment[key]=value -    ossetenv(key,raw and value or resolvers.resolve(value)) +    ossetenv(key,raw and value or resolveprefix(value))    end  end  local function getenv(key) @@ -13847,7 +14049,7 @@ local function getenv(key)  end  resolvers.getenv=getenv  resolvers.env=getenv -local function resolve(k) +local function resolvevariable(k)    return instance.expansions[k]  end  local dollarstripper=lpeg.stripper("$") @@ -13856,19 +14058,19 @@ local backslashswapper=lpeg.replacer("\\","/")  local somevariable=P("$")/""  local somekey=C(R("az","AZ","09","__","--")^1)  local somethingelse=P(";")*((1-S("!{}/\\"))^1*P(";")/"")+P(";")*(P(";")/"")+P(1) -local variableexpander=Cs((somevariable*(somekey/resolve)+somethingelse)^1 ) +local variableexpander=Cs((somevariable*(somekey/resolvevariable)+somethingelse)^1 )  local cleaner=P("\\")/"/"+P(";")*S("!{}/\\")^0*P(";")^1/";"  local variablecleaner=Cs((cleaner+P(1))^0) -local somevariable=R("az","AZ","09","__","--")^1/resolve +local somevariable=R("az","AZ","09","__","--")^1/resolvevariable  local variable=(P("$")/"")*(somevariable+(P("{")/"")*somevariable*(P("}")/""))  local variableresolver=Cs((variable+P(1))^0)  local function expandedvariable(var)    return lpegmatch(variableexpander,var) or var  end -function resolvers.newinstance()  -   if trace_locating then +function resolvers.newinstance() +  if trace_locating then      report_resolving("creating instance") -   end +  end    local environment,variables,expansions,order=allocate(),allocate(),allocate(),allocate()    local newinstance={      environment=environment, @@ -13995,13 +14197,13 @@ local function identify_configuration_files()      for i=1,#cnfpaths do        local filepath=cnfpaths[i]        local filename=collapsepath(filejoin(filepath,luacnfname)) -      local realname=resolvers.resolve(filename) +      local realname=resolveprefix(filename)        if trace_locating then -        local fullpath=gsub(resolvers.resolve(collapsepath(filepath)),"//","/") +        local fullpath=gsub(resolveprefix(collapsepath(filepath)),"//","/")          local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true)          report_resolving("looking for %a on %s path %a from specification %a",luacnfname,weirdpath and "weird" or "given",fullpath,filepath)        end -      if lfs.isfile(realname) then +      if isfile(realname) then          specification[#specification+1]=filename           if trace_locating then            report_resolving("found configuration file %a",realname) @@ -14023,7 +14225,7 @@ local function load_configuration_files()        local filename=specification[i]        local pathname=filedirname(filename)        local filename=filejoin(pathname,luacnfname) -      local realname=resolvers.resolve(filename)  +      local realname=resolveprefix(filename)         local blob=loadfile(realname)        if blob then          local setups=instance.setups @@ -14031,7 +14233,7 @@ local function load_configuration_files()          local parent=data and data.parent          if parent then            local filename=filejoin(pathname,parent) -          local realname=resolvers.resolve(filename)  +          local realname=resolveprefix(filename)             local blob=loadfile(realname)            if blob then              local parentdata=blob() @@ -14056,7 +14258,7 @@ local function load_configuration_files()              elseif variables[k]==nil then                if trace_locating and not warning then                  report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable", -                  k,resolvers.resolve(filename)) +                  k,resolveprefix(filename))                  warning=true                end                variables[k]=v @@ -14116,7 +14318,7 @@ local function locate_file_databases()        local stripped=lpegmatch(inhibitstripper,path)         if stripped~="" then          local runtime=stripped==path -        path=resolvers.cleanpath(path) +        path=cleanpath(path)          local spec=resolvers.splitmethod(stripped)          if runtime and (spec.noscheme or spec.scheme=="file") then            stripped="tree:///"..stripped @@ -14179,8 +14381,8 @@ function resolvers.renew(hashname)          report_resolving("identifying tree %a",hashname)        end      end -    local realpath=resolvers.resolve(hashname) -    if lfs.isdir(realpath) then +    local realpath=resolveprefix(hashname) +    if isdir(realpath) then        if trace_locating then          report_resolving("using path %a",realpath)        end @@ -14308,7 +14510,7 @@ function resolvers.registerextrapath(paths,subpaths)            local ps=p.."/"..s            if not done[ps] then              newn=newn+1 -            ep[newn]=resolvers.cleanpath(ps) +            ep[newn]=cleanpath(ps)              done[ps]=true            end          end @@ -14318,7 +14520,7 @@ function resolvers.registerextrapath(paths,subpaths)          local p=paths[i]          if not done[p] then            newn=newn+1 -          ep[newn]=resolvers.cleanpath(p) +          ep[newn]=cleanpath(p)            done[p]=true          end        end @@ -14330,7 +14532,7 @@ function resolvers.registerextrapath(paths,subpaths)          local ps=ep[i].."/"..s          if not done[ps] then            newn=newn+1 -          ep[newn]=resolvers.cleanpath(ps) +          ep[newn]=cleanpath(ps)            done[ps]=true          end        end @@ -14384,7 +14586,7 @@ function resolvers.cleanpathlist(str)    local t=resolvers.expandedpathlist(str)    if t then      for i=1,#t do -      t[i]=collapsepath(resolvers.cleanpath(t[i])) +      t[i]=collapsepath(cleanpath(t[i]))      end    end    return t @@ -14434,7 +14636,7 @@ function resolvers.registerfilehash(name,content,someerror)    end  end  local function isreadable(name) -  local readable=lfs.isfile(name)  +  local readable=isfile(name)     if trace_detail then      if readable then        report_resolving("file %a is readable",name) @@ -14445,69 +14647,56 @@ local function isreadable(name)    return readable  end  local function collect_files(names) -  local filelist,noffiles={},0 +  local filelist={} +  local noffiles=0 +  local function check(hash,root,pathname,path,name) +    if not pathname or find(path,pathname) then +      local variant=hash.type +      local search=filejoin(root,path,name)  +      local result=methodhandler('concatinators',variant,root,path,name) +      if trace_detail then +        report_resolving("match: variant %a, search %a, result %a",variant,search,result) +      end +      noffiles=noffiles+1 +      filelist[noffiles]={ variant,search,result } +    end +  end    for k=1,#names do -    local fname=names[k] +    local filename=names[k]      if trace_detail then -      report_resolving("checking name %a",fname) +      report_resolving("checking name %a",filename)      end -    local bname=filebasename(fname) -    local dname=filedirname(fname) -    if dname=="" or find(dname,"^%.") then -      dname=false +    local basename=filebasename(filename) +    local pathname=filedirname(filename) +    if pathname=="" or find(pathname,"^%.") then +      pathname=false      else -      dname=gsub(dname,"%*",".*") -      dname="/"..dname.."$" +      pathname=gsub(pathname,"%*",".*") +      pathname="/"..pathname.."$"      end      local hashes=instance.hashes      for h=1,#hashes do        local hash=hashes[h] -      local blobpath=hash.name -      local files=blobpath and instance.files[blobpath] -      if files then +      local hashname=hash.name +      local content=hashname and instance.files[hashname] +      if content then          if trace_detail then -          report_resolving("deep checking %a, base %a, pattern %a",blobpath,bname,dname) -        end -        local blobfile=files[bname] -        if not blobfile then -          local rname="remap:"..bname -          blobfile=files[rname] -          if blobfile then -            bname=files[rname] -            blobfile=files[bname] -          end +          report_resolving("deep checking %a, base %a, pattern %a",blobpath,basename,pathname)          end -        if blobfile then -          local blobroot=files.__path__ or blobpath -          if type(blobfile)=='string' then -            if not dname or find(blobfile,dname) then -              local variant=hash.type -              local search=filejoin(blobroot,blobfile,bname) -              local result=methodhandler('concatinators',hash.type,blobroot,blobfile,bname) -              if trace_detail then -                report_resolving("match: variant %a, search %a, result %a",variant,search,result) -              end -              noffiles=noffiles+1 -              filelist[noffiles]={ variant,search,result } -            end +        local path,name=lookup(content,basename) +        if path then +          local metadata=content.metadata +          local realroot=metadata and metadata.path or hashname +          if type(path)=="string" then +            check(hash,realroot,pathname,path,name)            else -            for kk=1,#blobfile do -              local vv=blobfile[kk] -              if not dname or find(vv,dname) then -                local variant=hash.type -                local search=filejoin(blobroot,vv,bname) -                local result=methodhandler('concatinators',hash.type,blobroot,vv,bname) -                if trace_detail then -                  report_resolving("match: variant %a, search %a, result %a",variant,search,result) -                end -                noffiles=noffiles+1 -                filelist[noffiles]={ variant,search,result } -              end +            for i=1,#path do +              check(hash,realroot,pathname,path[i],name)              end            end          end        elseif trace_locating then -        report_resolving("no match in %a (%s)",blobpath,bname) +        report_resolving("no match in %a (%s)",hashname,basename)        end      end    end @@ -14532,7 +14721,7 @@ end  local function can_be_dir(name)     local fakepaths=instance.fakepaths    if not fakepaths[name] then -    if lfs.isdir(name) then +    if isdir(name) then        fakepaths[name]=1       else        fakepaths[name]=2  @@ -14548,10 +14737,11 @@ local function find_analyze(filename,askedformat,allresults)    if askedformat=="" then      if ext=="" or not suffixmap[ext] then        local defaultsuffixes=resolvers.defaultsuffixes +      local formatofsuffix=resolvers.formatofsuffix        for i=1,#defaultsuffixes do          local forcedname=filename..'.'..defaultsuffixes[i]          wantedfiles[#wantedfiles+1]=forcedname -        filetype=resolvers.formatofsuffix(forcedname) +        filetype=formatofsuffix(forcedname)          if trace_locating then            report_resolving("forcing filetype %a",filetype)          end @@ -14591,14 +14781,14 @@ local function find_wildcard(filename,allresults)      if trace_locating then        report_resolving("checking wildcard %a",filename)      end -    local method,result=resolvers.findwildcardfiles(filename) +    local result=resolvers.findwildcardfiles(filename)      if result then        return "wildcard",result      end    end  end  local function find_qualified(filename,allresults,askedformat,alsostripped)  -  if not file.is_qualified_path(filename) then +  if not is_qualified_path(filename) then      return    end    if trace_locating then @@ -14687,7 +14877,6 @@ local function find_intree(filename,filetype,wantedfiles,allresults)      if trace_detail then        report_resolving("checking filename %a",filename)      end -    local resolve=resolvers.resolve      local result={}      for k=1,#pathlist do        local path=pathlist[k] @@ -14706,8 +14895,8 @@ local function find_intree(filename,filetype,wantedfiles,allresults)            local fl=filelist[k]            local f=fl[2]            local d=dirlist[k] -          if find(d,expression) or find(resolve(d),expression) then -            result[#result+1]=resolve(fl[3])  +          if find(d,expression) or find(resolveprefix(d),expression) then +            result[#result+1]=resolveprefix(fl[3])               done=true              if allresults then                if trace_detail then @@ -14729,7 +14918,7 @@ local function find_intree(filename,filetype,wantedfiles,allresults)        else          method="filesystem"           pathname=gsub(pathname,"/+$","") -        pathname=resolve(pathname) +        pathname=resolveprefix(pathname)          local scheme=url.hasscheme(pathname)          if not scheme or scheme=="file" then            local pname=gsub(pathname,"%.%*$",'') @@ -14819,7 +15008,7 @@ local function find_otherwise(filename,filetype,wantedfiles,allresults)    local filelist=collect_files(wantedfiles)    local fl=filelist and filelist[1]    if fl then -    return "otherwise",{ resolvers.resolve(fl[3]) }  +    return "otherwise",{ resolveprefix(fl[3]) }     end  end  collect_instance_files=function(filename,askedformat,allresults)  @@ -14919,39 +15108,30 @@ function resolvers.findpath(filename,filetype)    return filedirname(findfiles(filename,filetype,false)[1] or "")  end  local function findgivenfiles(filename,allresults) -  local bname,result=filebasename(filename),{} +  local base=filebasename(filename) +  local result={}    local hashes=instance.hashes -  local noffound=0 +  local function okay(hash,path,name) +    local found=methodhandler('concatinators',hash.type,hash.name,path,name) +    if found and found~="" then +      result[#result+1]=resolveprefix(found) +      return not allresults +    end +  end    for k=1,#hashes do      local hash=hashes[k] -    local files=instance.files[hash.name] or {} -    local blist=files[bname] -    if not blist then -      local rname="remap:"..bname -      blist=files[rname] -      if blist then -        bname=files[rname] -        blist=files[bname] -      end -    end -    if blist then -      if type(blist)=='string' then -        local found=methodhandler('concatinators',hash.type,hash.name,blist,bname) or "" -        if found~="" then -          noffound=noffound+1 -          result[noffound]=resolvers.resolve(found) -          if not allresults then -            break -          end +    local content=instance.files[hash.name] +    if content then +      local path,name=lookup(content,base) +      if not path then +      elseif type(path)=="string" then +        if okay(hash,path,name) then +          return result          end        else -        for kk=1,#blist do -          local vv=blist[kk] -          local found=methodhandler('concatinators',hash.type,hash.name,vv,bname) or "" -          if found~="" then -            noffound=noffound+1 -            result[noffound]=resolvers.resolve(found) -            if not allresults then break end +        for i=1,#path do +          if okay(hash,path[i],name) then +            return result            end          end        end @@ -14965,64 +15145,80 @@ end  function resolvers.findgivenfile(filename)    return findgivenfiles(filename,false)[1] or ""  end -local function doit(path,blist,bname,tag,variant,result,allresults) -  local done=false -  if blist and variant then -    local resolve=resolvers.resolve  -    if type(blist)=='string' then -      if find(lower(blist),path) then -        local full=methodhandler('concatinators',variant,tag,blist,bname) or "" -        result[#result+1]=resolve(full) -        done=true -      end -    else -      for kk=1,#blist do -        local vv=blist[kk] -        if find(lower(vv),path) then -          local full=methodhandler('concatinators',variant,tag,vv,bname) or "" -          result[#result+1]=resolve(full) -          done=true -          if not allresults then break end -        end -      end -    end -  end -  return done -end  local makewildcard=Cs(    (P("^")^0*P("/")*P(-1)+P(-1))/".*"+(P("^")^0*P("/")/"")^0*(P("*")/".*"+P("-")/"%%-"+P(".")/"%%."+P("?")/"."+P("\\")/"/"+P(1))^0  )  function resolvers.wildcardpattern(pattern)    return lpegmatch(makewildcard,pattern) or pattern  end -local function findwildcardfiles(filename,allresults,result)  -  result=result or {} +local function findwildcardfiles(filename,allresults,result) +  local result=result or {}    local base=filebasename(filename)    local dirn=filedirname(filename)    local path=lower(lpegmatch(makewildcard,dirn) or dirn)    local name=lower(lpegmatch(makewildcard,base) or base) -  local files,done=instance.files,false +  local files=instance.files    if find(name,"*",1,true) then      local hashes=instance.hashes +    local function okay(found,path,base,hashname,hashtype) +      if find(found,path) then +        local full=methodhandler('concatinators',hashtype,hashname,found,base) +        if full and full~="" then +          result[#result+1]=resolveprefix(full) +          return not allresults +        end +      end +    end      for k=1,#hashes do        local hash=hashes[k] -      local hashname,hashtype=hash.name,hash.type -      for kk,hh in next,files[hashname] do -        if not find(kk,"^remap:") then -          if find(lower(kk),name) then -            if doit(path,hh,kk,hashname,hashtype,result,allresults) then done=true end -            if done and not allresults then break end +      local hashname=hash.name +      local hashtype=hash.type +      if hashname and hashtype then +        for found,base in filtered(files[hashname],name) do +          if type(found)=='string' then +            if okay(found,path,base,hashname,hashtype) then +              break +            end +          else +            for i=1,#found do +              if okay(found[i],path,base,hashname,hashtype) then +                break +              end +            end            end          end        end      end    else +    local function okayokay(found,path,base,hashname,hashtype) +      if find(found,path) then +        local full=methodhandler('concatinators',hashtype,hashname,found,base) +        if full and full~="" then +          result[#result+1]=resolveprefix(full) +          return not allresults +        end +      end +    end      local hashes=instance.hashes      for k=1,#hashes do        local hash=hashes[k] -      local hashname,hashtype=hash.name,hash.type -      if doit(path,files[hashname][base],base,hashname,hashtype,result,allresults) then done=true end -      if done and not allresults then break end +      local hashname=hash.name +      local hashtype=hash.type +      if hashname and hashtype then +        local found,base=lookup(content,base) +        if not found then +        elseif type(found)=='string' then +          if okay(found,path,base,hashname,hashtype) then +            break +          end +        else +          for i=1,#found do +            if okay(found[i],path,base,hashname,hashtype) then +              break +            end +          end +        end +      end      end    end    return result @@ -15095,7 +15291,7 @@ end  function resolvers.dowithpath(name,func)    local pathlist=resolvers.expandedpathlist(name)    for i=1,#pathlist do -    func("^"..resolvers.cleanpath(pathlist[i])) +    func("^"..cleanpath(pathlist[i]))    end  end  function resolvers.dowithvariable(name,func) @@ -15103,23 +15299,23 @@ function resolvers.dowithvariable(name,func)  end  function resolvers.locateformat(name)    local engine=environment.ownmain or "luatex" -  local barename=file.removesuffix(name) -  local fullname=file.addsuffix(barename,"fmt") +  local barename=removesuffix(name) +  local fullname=addsuffix(barename,"fmt")    local fmtname=caches.getfirstreadablefile(fullname,"formats",engine) or ""    if fmtname=="" then      fmtname=resolvers.findfile(fullname) -    fmtname=resolvers.cleanpath(fmtname) +    fmtname=cleanpath(fmtname)    end    if fmtname~="" then -    local barename=file.removesuffix(fmtname) -    local luaname=file.addsuffix(barename,luasuffixes.lua) -    local lucname=file.addsuffix(barename,luasuffixes.luc) -    local luiname=file.addsuffix(barename,luasuffixes.lui) -    if lfs.isfile(luiname) then +    local barename=removesuffix(fmtname) +    local luaname=addsuffix(barename,luasuffixes.lua) +    local lucname=addsuffix(barename,luasuffixes.luc) +    local luiname=addsuffix(barename,luasuffixes.lui) +    if isfile(luiname) then        return barename,luiname -    elseif lfs.isfile(lucname) then +    elseif isfile(lucname) then        return barename,lucname -    elseif lfs.isfile(luaname) then +    elseif isfile(luaname) then        return barename,luaname      end    end @@ -15141,29 +15337,24 @@ function resolvers.dowithfilesintree(pattern,handle,before,after)      local hash=hashes[i]      local blobtype=hash.type      local blobpath=hash.name -    if blobpath then +    if blobtype and blobpath then +      local total=0 +      local checked=0 +      local done=0        if before then          before(blobtype,blobpath,pattern)        end -      local files=instance.files[blobpath] -      local total,checked,done=0,0,0 -      if files then -        for k,v in table.sortedhash(files) do  -          total=total+1 -          if find(k,"^remap:") then -          elseif find(k,pattern) then -            if type(v)=="string" then -              checked=checked+1 -              if handle(blobtype,blobpath,v,k) then -                done=done+1 -              end -            else -              checked=checked+#v -              for i=1,#v do -                if handle(blobtype,blobpath,v[i],k) then -                  done=done+1 -                end -              end +      for path,name in filtered(instance.files[blobpath],pattern) do +        if type(path)=="string" then +          checked=checked+1 +          if handle(blobtype,blobpath,path,name) then +            done=done+1 +          end +        else +          checked=checked+#path +          for i=1,#path do +            if handle(blobtype,blobpath,path[i],name) then +              done=done+1              end            end          end @@ -15174,8 +15365,8 @@ function resolvers.dowithfilesintree(pattern,handle,before,after)      end    end  end -resolvers.obsolete=resolvers.obsolete or {} -local obsolete=resolvers.obsolete +local obsolete=resolvers.obsolete or {} +resolvers.obsolete=obsolete  resolvers.find_file=resolvers.findfile  obsolete.find_file=resolvers.findfile  resolvers.find_files=resolvers.findfiles  obsolete.find_files=resolvers.findfiles @@ -15186,7 +15377,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-pre"] = package.loaded["data-pre"] or true --- original size: 6643, stripped down to: 4401 +-- original size: 3106, stripped down to: 2563  if not modules then modules={} end modules ['data-pre']={    version=1.001, @@ -15196,44 +15387,51 @@ if not modules then modules={} end modules ['data-pre']={    license="see context related readme files"  }  local resolvers=resolvers -local prefixes=utilities.storage.allocate() -resolvers.prefixes=prefixes -local cleanpath,findgivenfile,expansion=resolvers.cleanpath,resolvers.findgivenfile,resolvers.expansion +local prefixes=resolvers.prefixes +local cleanpath=resolvers.cleanpath +local findgivenfile=resolvers.findgivenfile +local expansion=resolvers.expansion  local getenv=resolvers.getenv  -local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match -local joinpath,basename,dirname=file.join,file.basename,file.dirname -local getmetatable,rawset,type=getmetatable,rawset,type +local basename=file.basename +local dirname=file.dirname +local joinpath=file.join +local isfile=lfs.isfile  prefixes.environment=function(str)    return cleanpath(expansion(str))  end -prefixes.relative=function(str,n)  -  if io.exists(str) then -  elseif io.exists("./"..str) then -    str="./"..str -  else -    local p="../" -    for i=1,n or 2 do -      if io.exists(p..str) then -        str=p..str -        break -      else -        p=p.."../" +local function relative(str,n) +  if not isfile(str) then +    local pstr="./"..str +    if isfile(pstr) then +      str=pstr +    else +      local p="../" +      for i=1,n or 2 do +        local pstr=p..str +        if isfile(pstr) then +          str=pstr +          break +        else +          p=p.."../" +        end        end      end    end    return cleanpath(str)  end +local function locate(str) +  local fullname=findgivenfile(str) or "" +  return cleanpath(fullname~="" and fullname or str) +end +prefixes.relative=relative +prefixes.locate=locate  prefixes.auto=function(str) -  local fullname=prefixes.relative(str) -  if not lfs.isfile(fullname) then -    fullname=prefixes.locate(str) +  local fullname=relative(str) +  if not isfile(fullname) then +    fullname=locate(str)    end    return fullname  end -prefixes.locate=function(str) -  local fullname=findgivenfile(str) or "" -  return cleanpath((fullname~="" and fullname) or str) -end  prefixes.filename=function(str)    local fullname=findgivenfile(str) or ""    return cleanpath(basename((fullname~="" and fullname) or str))  @@ -15277,87 +15475,6 @@ prefixes.kpse=prefixes.locate  prefixes.full=prefixes.locate  prefixes.file=prefixes.filename  prefixes.path=prefixes.pathname -function resolvers.allprefixes(separator) -  local all=table.sortedkeys(prefixes) -  if separator then -    for i=1,#all do -      all[i]=all[i]..":" -    end -  end -  return all -end -local function _resolve_(method,target) -  local action=prefixes[method] -  if action then -    return action(target) -  else -    return method..":"..target -  end -end -local resolved,abstract={},{} -function resolvers.resetresolve(str) -  resolved,abstract={},{} -end -local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) -local prefix=C(R("az")^2)*P(":") -local target=C((1-S(" \"\';,"))^1) -local notarget=(#S(";,")+P(-1))*Cc("") -local pattern=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) -local function resolve(str)  -  if type(str)=="table" then -    local t={} -    for i=1,#str do -      t[i]=resolve(str[i]) -    end -    return t -  else -    local res=resolved[str] -    if not res then -      res=lpegmatch(pattern,str) -      resolved[str]=res -      abstract[res]=str -    end -    return res -  end -end -local function unresolve(str) -  return abstract[str] or str -end -resolvers.resolve=resolve -resolvers.unresolve=unresolve -if type(os.uname)=="function" then -  for k,v in next,os.uname() do -    if not prefixes[k] then -      prefixes[k]=function() return v end -    end -  end -end -if os.type=="unix" then -  local pattern -  local function makepattern(t,k,v) -    if t then -      rawset(t,k,v) -    end -    local colon=P(":") -    for k,v in table.sortedpairs(prefixes) do -      if p then -        p=P(k)+p -      else -        p=P(k) -      end -    end -    pattern=Cs((p*colon+colon/";"+P(1))^0) -  end -  makepattern() -  getmetatable(prefixes).__newindex=makepattern -  function resolvers.repath(str) -    return lpegmatch(pattern,str) -  end -else  -  function resolvers.repath(str) -    return str -  end -end  end -- of closure @@ -15419,7 +15536,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-fil"] = package.loaded["data-fil"] or true --- original size: 3801, stripped down to: 3231 +-- original size: 3863, stripped down to: 3310  if not modules then modules={} end modules ['data-fil']={    version=1.001, @@ -15431,30 +15548,31 @@ if not modules then modules={} end modules ['data-fil']={  local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end)  local report_files=logs.reporter("resolvers","files")  local resolvers=resolvers +local resolveprefix=resolvers.resolve  local finders,openers,loaders,savers=resolvers.finders,resolvers.openers,resolvers.loaders,resolvers.savers  local locators,hashers,generators,concatinators=resolvers.locators,resolvers.hashers,resolvers.generators,resolvers.concatinators  local checkgarbage=utilities.garbagecollector and utilities.garbagecollector.check  function locators.file(specification) -  local name=specification.filename -  local realname=resolvers.resolve(name)  +  local filename=specification.filename +  local realname=resolveprefix(filename)     if realname and realname~='' and lfs.isdir(realname) then      if trace_locating then -      report_files("file locator %a found as %a",name,realname) +      report_files("file locator %a found as %a",filename,realname)      end -    resolvers.appendhash('file',name,true)  +    resolvers.appendhash('file',filename,true)     elseif trace_locating then -    report_files("file locator %a not found",name) +    report_files("file locator %a not found",filename)    end  end  function hashers.file(specification) -  local name=specification.filename -  local content=caches.loadcontent(name,'files') -  resolvers.registerfilehash(name,content,content==nil) +  local pathname=specification.filename +  local content=caches.loadcontent(pathname,'files') +  resolvers.registerfilehash(pathname,content,content==nil)  end  function generators.file(specification) -  local path=specification.filename -  local content=resolvers.scanfiles(path,false,true) -  resolvers.registerfilehash(path,content,true) +  local pathname=specification.filename +  local content=resolvers.scanfiles(pathname,false,true)  +  resolvers.registerfilehash(pathname,content,true)  end  concatinators.file=file.join  function finders.file(specification,filetype) @@ -15736,7 +15854,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-zip"] = package.loaded["data-zip"] or true --- original size: 8489, stripped down to: 6757 +-- original size: 9043, stripped down to: 7073  if not modules then modules={} end modules ['data-zip']={    version=1.001, @@ -15779,7 +15897,7 @@ function zip.openarchive(name)      local arch=archives[name]      if not arch then        local full=resolvers.findfile(name) or "" -      arch=(full~="" and zip.open(full)) or false +      arch=full~="" and zip.open(full) or false        archives[name]=arch      end      return arch @@ -15938,31 +16056,42 @@ function resolvers.usezipfile(archive)    end  end  function resolvers.registerzipfile(z,tree) -  local files,filter={},"" -  if tree=="" then -    filter="^(.+)/(.-)$" -  else -    filter=format("^%s/(.+)/(.-)$",tree) -  end +  local names={} +  local files={}  +  local remap={}  +  local n=0 +  local filter=tree=="" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) +  local register=resolvers.registerfile    if trace_locating then      report_zip("registering: using filter %a",filter)    end -  local register,n=resolvers.registerfile,0    for i in z:files() do -    local path,name=match(i.filename,filter) -    if path then -      if name and name~='' then -        register(files,name,path) -        n=n+1 -      else +    local filename=i.filename +    local path,name=match(filename,filter) +    if not path then +      n=n+1 +      register(names,filename,"") +      local usedname=lower(filename) +      files[usedname]="" +      if usedname~=filename then +        remap[usedname]=filename        end -    else -      register(files,i.filename,'') +    elseif name and name~="" then        n=n+1 +      register(names,name,path) +      local usedname=lower(name) +      files[usedname]=path +      if usedname~=name then +        remap[usedname]=name +      end +    else      end    end    report_zip("registering: %s files registered",n) -  return files +  return { +    files=files, +    remap=remap, +  }  end @@ -15972,7 +16101,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-tre"] = package.loaded["data-tre"] or true --- original size: 2508, stripped down to: 2074 +-- original size: 4859, stripped down to: 3335  if not modules then modules={} end modules ['data-tre']={    version=1.001, @@ -15981,42 +16110,50 @@ if not modules then modules={} end modules ['data-tre']={    copyright="PRAGMA ADE / ConTeXt Development Team",    license="see context related readme files"  } -local find,gsub,format=string.find,string.gsub,string.format +local find,gsub,lower=string.find,string.gsub,string.lower +local basename,dirname,joinname=file.basename,file.dirname,file  .join +local globdir,isdir=dir.glob,lfs.isdir  local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end)  local report_trees=logs.reporter("resolvers","trees")  local resolvers=resolvers -local done,found,notfound={},{},resolvers.finders.notfound -function resolvers.finders.tree(specification) +local resolveprefix=resolvers.resolve +local notfound=resolvers.finders.notfound +local collectors={} +local found={} +function resolvers.finders.tree(specification)     local spec=specification.filename -  local fnd=found[spec] -  if fnd==nil then +  local okay=found[spec] +  if okay==nil then      if spec~="" then -      local path,name=file.dirname(spec),file.basename(spec) -      if path=="" then path="." end -      local hash=done[path] -      if not hash then -        local pattern=path.."/*"  -        hash=dir.glob(pattern) -        done[path]=hash +      local path=dirname(spec) +      local name=basename(spec) +      if path=="" then +        path="." +      end +      local names=collectors[path] +      if not names then +        local pattern=find(path,"/%*+$") and path or (path.."/*") +        names=globdir(pattern) +        collectors[path]=names        end        local pattern="/"..gsub(name,"([%.%-%+])","%%%1").."$" -      for k=1,#hash do -        local v=hash[k] -        if find(v,pattern) then -          found[spec]=v -          return v +      for i=1,#names do +        local fullname=names[i] +        if find(fullname,pattern) then +          found[spec]=fullname +          return fullname          end        end      end -    fnd=notfound()  -    found[spec]=fnd +    okay=notfound()  +    found[spec]=okay    end -  return fnd +  return okay  end  function resolvers.locators.tree(specification)    local name=specification.filename -  local realname=resolvers.resolve(name)  -  if realname and realname~='' and lfs.isdir(realname) then +  local realname=resolveprefix(name)  +  if realname and realname~='' and isdir(realname) then      if trace_locating then        report_trees("locator %a found",realname)      end @@ -16033,10 +16170,43 @@ function resolvers.hashers.tree(specification)    resolvers.methodhandler("hashers",name)    resolvers.generators.file(specification)  end -resolvers.concatinators.tree=resolvers.concatinators.file -resolvers.generators.tree=resolvers.generators.file -resolvers.openers.tree=resolvers.openers.file -resolvers.loaders.tree=resolvers.loaders.file +local collectors={} +table.setmetatableindex(collectors,function(t,k) +  local rootname=gsub(k,"[/%*]+$","") +  local dataname=joinname(rootname,"dirlist") +  local data=caches.loadcontent(dataname,"files",dataname) +  local content=data and data.content +  local lookup=resolvers.get_from_content +  if not content then +    content=resolvers.scanfiles(rootname) +    caches.savecontent(dataname,"files",content,dataname) +  end +  local files=content.files +  local v=function(filename) +    local path,name=lookup(content,filename) +    if not path then +      return filename +    elseif type(path)=="table" then +      path=path[1] +    end +    return joinname(rootname,path,name) +  end +  t[k]=v +  return v +end) +function resolvers.finders.dirlist(specification)  +  local spec=specification.filename +  if spec~="" then +    local path,name=dirname(spec),basename(spec) +    return path and collectors[path](name) or notfound() +  end +  return notfound() +end +resolvers.locators .dirlist=resolvers.locators .tree +resolvers.hashers  .dirlist=resolvers.hashers  .tree +resolvers.generators.dirlist=resolvers.generators.file +resolvers.openers  .dirlist=resolvers.openers  .file +resolvers.loaders  .dirlist=resolvers.loaders  .file  end -- of closure @@ -16221,7 +16391,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-lua"] = package.loaded["data-lua"] or true --- original size: 4237, stripped down to: 3177 +-- original size: 4313, stripped down to: 3227  if not modules then modules={} end modules ['data-lua']={    version=1.001, @@ -16230,7 +16400,7 @@ if not modules then modules={} end modules ['data-lua']={    copyright="PRAGMA ADE / ConTeXt Development Team",    license="see context related readme files"  } -local resolvers,package=resolvers,package +local package,lpeg=package,lpeg  local gsub=string.gsub  local concat=table.concat  local addsuffix=file.addsuffix @@ -16241,9 +16411,11 @@ local luaformats={ 'TEXINPUTS','LUAINPUTS' }  local libformats={ 'CLUAINPUTS' }  local helpers=package.helpers or {}  local methods=helpers.methods or {} +local resolvers=resolvers +local resolveprefix=resolvers.resolve +helpers.report=logs.reporter("resolvers","libraries")  trackers.register("resolvers.libraries",function(v) helpers.trace=v end)  trackers.register("resolvers.locating",function(v) helpers.trace=v end) -helpers.report=logs.reporter("resolvers","libraries")  helpers.sequence={    "already loaded",    "preload table", @@ -16258,7 +16430,7 @@ helpers.sequence={  }  local pattern=Cs(P("!")^0/""*(P("/")*P(-1)/"/"+P("/")^1/"/"+1)^0)  function helpers.cleanpath(path)  -  return resolvers.resolve(lpegmatch(pattern,path)) +  return resolveprefix(lpegmatch(pattern,path))  end  local loadedaslib=helpers.loadedaslib  local getextraluapaths=package.extraluapaths @@ -16395,7 +16567,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-tmf"] = package.loaded["data-tmf"] or true --- original size: 2600, stripped down to: 1627 +-- original size: 2601, stripped down to: 1627  if not modules then modules={} end modules ['data-tmf']={    version=1.001, @@ -16451,7 +16623,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-lst"] = package.loaded["data-lst"] or true --- original size: 2654, stripped down to: 2301 +-- original size: 2734, stripped down to: 2354  if not modules then modules={} end modules ['data-lst']={    version=1.001, @@ -16460,10 +16632,13 @@ if not modules then modules={} end modules ['data-lst']={    copyright="PRAGMA ADE / ConTeXt Development Team",    license="see context related readme files"  } -local find,concat,upper,format=string.find,table.concat,string.upper,string.format +local rawget,type,next=rawget,type,next +local find,concat,upper=string.find,table.concat,string.upper  local fastcopy,sortedpairs=table.fastcopy,table.sortedpairs -resolvers.listers=resolvers.listers or {}  local resolvers=resolvers +local listers=resolvers.listers or {} +resolvers.listers=listers +local resolveprefix=resolvers.resolve  local report_lists=logs.reporter("resolvers","lists")  local function tabstr(str)    if type(str)=='table' then @@ -16472,7 +16647,7 @@ local function tabstr(str)      return str    end  end -function resolvers.listers.variables(pattern) +function listers.variables(pattern)    local instance=resolvers.instance    local environment=instance.environment    local variables=instance.variables @@ -16493,10 +16668,10 @@ function resolvers.listers.variables(pattern)    for key,value in sortedpairs(configured) do      if key~="" and (pattern=="" or find(upper(key),pattern)) then        report_lists(key) -      report_lists("  env: %s",tabstr(rawget(environment,key))  or "unset") -      report_lists("  var: %s",tabstr(configured[key])      or "unset") -      report_lists("  exp: %s",tabstr(expansions[key])      or "unset") -      report_lists("  res: %s",tabstr(resolvers.resolve(expansions[key])) or "unset") +      report_lists("  env: %s",tabstr(rawget(environment,key))    or "unset") +      report_lists("  var: %s",tabstr(configured[key])        or "unset") +      report_lists("  exp: %s",tabstr(expansions[key])        or "unset") +      report_lists("  res: %s",tabstr(resolveprefix(expansions[key])) or "unset")      end    end    instance.environment=fastcopy(env) @@ -16504,15 +16679,15 @@ function resolvers.listers.variables(pattern)    instance.expansions=fastcopy(exp)  end  local report_resolved=logs.reporter("system","resolved") -function resolvers.listers.configurations() +function listers.configurations()    local configurations=resolvers.instance.specification    for i=1,#configurations do -    report_resolved("file : %s",resolvers.resolve(configurations[i])) +    report_resolved("file : %s",resolveprefix(configurations[i]))    end    report_resolved("")    local list=resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec))    for i=1,#list do -    local li=resolvers.resolve(list[i]) +    local li=resolveprefix(list[i])      if lfs.isdir(li) then        report_resolved("path - %s",li)      else @@ -16951,8 +17126,8 @@ end -- of closure  -- used libraries    : l-lua.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-sto.lua util-prs.lua util-fmt.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-mrg.lua util-tpl.lua util-env.lua luat-env.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua util-lib.lua luat-sta.lua luat-fmt.lua  -- skipped libraries : - --- original bytes    : 699655 --- stripped bytes    : 249540 +-- original bytes    : 704727 +-- stripped bytes    : 250243  -- end library merge diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua index 189fc4b7b..70f493525 100644 --- a/scripts/context/stubs/mswin/mtxrun.lua +++ b/scripts/context/stubs/mswin/mtxrun.lua @@ -1195,7 +1195,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["l-table"] = package.loaded["l-table"] or true --- original size: 31828, stripped down to: 20814 +-- original size: 33243, stripped down to: 21578  if not modules then modules={} end modules ['l-table']={    version=1.001, @@ -1342,14 +1342,14 @@ local function sortedhash(t,cmp)      end      local n=0      local m=#s -    local function kv(s) +    local function kv()         if n<m then          n=n+1          local k=s[n]          return k,t[k]        end      end -    return kv,s +    return kv     else      return nothing    end @@ -2110,6 +2110,44 @@ function table.values(t,s)      return {}    end  end +function table.filtered(t,pattern,sort,cmp) +  if t and type(pattern)=="string" then +    if sort then +      local s +      if cmp then +        s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) +      else +        s=sortedkeys(t)  +      end +      local n=0 +      local m=#s +      local function kv(s) +        while n<m do +          n=n+1 +          local k=s[n] +          if find(k,pattern) then +            return k,t[k] +          end +        end +      end +      return kv,s +    else +      local n=next(t) +      local function iterator() +        while n do +          local k=n +          n=next(t,k) +          if find(k,pattern) then +            return k,t[k] +          end +        end +      end +      return iterator,t +    end +  else +    return nothing +  end +end  end -- of closure @@ -3775,7 +3813,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["l-dir"] = package.loaded["l-dir"] or true --- original size: 14788, stripped down to: 9096 +-- original size: 16056, stripped down to: 10707  if not modules then modules={} end modules ['l-dir']={    version=1.001, @@ -3785,7 +3823,7 @@ if not modules then modules={} end modules ['l-dir']={    license="see context related readme files"  }  local type,select=type,select -local find,gmatch,match,gsub=string.find,string.gmatch,string.match,string.gsub +local find,gmatch,match,gsub,sub=string.find,string.gmatch,string.match,string.gsub,string.sub  local concat,insert,remove,unpack=table.concat,table.insert,table.remove,table.unpack  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 @@ -3794,54 +3832,123 @@ local dir=dir  local lfs=lfs  local attributes=lfs.attributes  local walkdir=lfs.dir -local isdir=lfs.isdir -local isfile=lfs.isfile +local isdir=lfs.isdir  +local isfile=lfs.isfile   local currentdir=lfs.currentdir  local chdir=lfs.chdir  local mkdir=lfs.mkdir  local onwindows=os.type=="windows" or find(os.getenv("PATH"),";",1,true) -if not isdir then -  function isdir(name) -    local a=attributes(name) -    return a and a.mode=="directory" +if onwindows then +  isdir=function(name) +    name=gsub(name,"([/\\]+)$","/.") +    return attributes(name,"mode")=="directory" +  end +  isfile=function(name) +    return attributes(name,"mode")=="file"    end    lfs.isdir=isdir -end -if not isfile then -  function isfile(name) -    local a=attributes(name) -    return a and a.mode=="file" +  lfs.isfile=isfile +else +  isdir=function(name) +    return attributes(name,"mode")=="directory" +  end +  isfile=function(name) +    return attributes(name,"mode")=="file"    end +  lfs.isdir=isdir    lfs.isfile=isfile  end  function dir.current()    return (gsub(currentdir(),"\\","/"))  end -local lfsisdir=isdir -local function isdir(path) -  path=gsub(path,"[/\\]+$","") -  return lfsisdir(path) +local function glob_pattern_function(path,patt,recurse,action) +  if isdir(path) then +    local usedpath +    if path=="/" then +      usedpath="/." +    elseif not find(path,"/$") then +      usedpath=path.."/." +      path=path.."/" +    else +      usedpath=path +    end +    local dirs +    for name in walkdir(usedpath) do +      if name~="." and name~=".." then +        local full=path..name +        local mode=attributes(full,'mode') +        if mode=='file' then +          if not patt or find(full,patt) then +            action(full) +          end +        elseif recurse and mode=="directory" then +          if not dirs then +            dirs={ full } +          else +            dirs[#dirs+1]=full +          end +        end +      end +    end +    if dirs then +      for i=1,#dirs do +        glob_pattern_function(dirs[i],patt,recurse,action) +      end +    end +  end  end -lfs.isdir=isdir -local function globpattern(path,patt,recurse,action) -  if path=="/" then -    path=path.."." -  elseif not find(path,"/$") then -    path=path..'/' -  end -  if isdir(path) then  -    for name in walkdir(path) do  -      local full=path..name -      local mode=attributes(full,'mode') -      if mode=='file' then -        if find(full,patt) then -          action(full) +local function glob_pattern_table(path,patt,recurse,result) +  if not result then +    result={} +  end +  if isdir(path) then +    local usedpath +    if path=="/" then +      usedpath="/." +    elseif not find(path,"/$") then +      usedpath=path.."/." +      path=path.."/" +    else +      usedpath=path +    end +    local dirs +    for name in walkdir(usedpath) do +      if name~="." and name~=".." then +        local full=path..name +        local mode=attributes(full,'mode') +        if mode=='file' then +          if not patt or find(full,patt) then +            result[#result+1]=full +          end +        elseif recurse and mode=="directory" then +          if not dirs then +            dirs={ full } +          else +            dirs[#dirs+1]=full +          end          end -      elseif recurse and (mode=="directory") and (name~='.') and (name~="..") then -        globpattern(full,patt,recurse,action) +      end +    end +    if dirs then +      for i=1,#dirs do +        glob_pattern_table(dirs[i],patt,recurse,result)        end      end    end +  return result +end +local function globpattern(path,patt,recurse,method) +  local kind=type(method) +  if pattern and sub(patt,1,-3)==path then +    patt=false +  end +  if kind=="function" then +    return glob_pattern_function(path,patt,recurse,method) +  elseif kind=="table" then +    return glob_pattern_table(path,patt,recurse,method) +  else +    return glob_pattern_table(path,patt,recurse,{}) +  end  end  dir.globpattern=globpattern  local function collectpattern(path,patt,recurse,result) @@ -3853,18 +3960,24 @@ local function collectpattern(path,patt,recurse,result)      ok,scanner,first=xpcall(function() return walkdir(path)   end,function() end)     end    if ok and type(scanner)=="function" then -    if not find(path,"/$") then path=path..'/' end +    if not find(path,"/$") then +      path=path..'/' +    end      for name in scanner,first do -      local full=path..name -      local attr=attributes(full) -      local mode=attr.mode -      if mode=='file' then -        if find(full,patt) then +      if name=="." then +      elseif name==".." then +      else +        local full=path..name +        local attr=attributes(full) +        local mode=attr.mode +        if mode=='file' then +          if find(full,patt) then +            result[name]=attr +          end +        elseif recurse and mode=="directory" then +          attr.list=collectpattern(full,patt,recurse)            result[name]=attr          end -      elseif recurse and (mode=="directory") and (name~='.') and (name~="..") then -        attr.list=collectpattern(full,patt,recurse) -        result[name]=attr        end      end    end @@ -3872,15 +3985,15 @@ local function collectpattern(path,patt,recurse,result)  end  dir.collectpattern=collectpattern  local separator -if onwindows then +if onwindows then     local slash=S("/\\")/"/" -  pattern=Ct { +  pattern={      [1]=(Cs(P(".")+slash^1)+Cs(R("az","AZ")*P(":")*slash^0)+Cc("./"))*V(2)*V(3),      [2]=Cs(((1-S("*?/\\"))^0*slash)^0),      [3]=Cs(P(1)^0)    } -else  -  pattern=Ct { +else +  pattern={      [1]=(C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3),      [2]=C(((1-S("*?/"))^0*P("/"))^0),      [3]=C(P(1)^0) @@ -3898,9 +4011,8 @@ local function glob(str,t)      elseif isfile(str) then        t(str)      else -      local split=lpegmatch(pattern,str)  -      if split then -        local root,path,base=split[1],split[2],split[3] +      local root,path,base=lpegmatch(pattern,str)  +      if root and path and base then          local recurse=find(base,"**",1,true)           local start=root..path          local result=lpegmatch(filter,start..base) @@ -3922,16 +4034,12 @@ local function glob(str,t)          return { str }        end      else -      local split=lpegmatch(pattern,str)  -      if split then -        local t=t or {} -        local action=action or function(name) t[#t+1]=name end -        local root,path,base=split[1],split[2],split[3] +      local root,path,base=lpegmatch(pattern,str)  +      if root and path and base then          local recurse=find(base,"**",1,true)           local start=root..path          local result=lpegmatch(filter,start..base) -        globpattern(start,result,recurse,action) -        return t +        return globpattern(start,result,recurse,t)        else          return {}        end @@ -4879,7 +4987,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["util-str"] = package.loaded["util-str"] or true --- original size: 33485, stripped down to: 18420 +-- original size: 34240, stripped down to: 18733  if not modules then modules={} end modules ['util-str']={    version=1.001, @@ -5544,6 +5652,15 @@ else    add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=lpeg.patterns.texescape })    add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=lpeg.patterns.luaescape })  end +local dquote=patterns.dquote  +local equote=patterns.escaped+dquote/'\\"'+1 +local space=patterns.space +local cquote=Cc('"') +local pattern=Cs(dquote*(equote-P(-2))^0*dquote)           ++Cs(cquote*(equote-space)^0*space*equote^0*cquote)  +function string.optionalquoted(str) +  return lpegmatch(pattern,str) or str +end  end -- of closure @@ -8717,7 +8834,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["util-env"] = package.loaded["util-env"] or true --- original size: 8814, stripped down to: 5092 +-- original size: 8022, stripped down to: 5038  if not modules then modules={} end modules ['util-env']={    version=1.001, @@ -8728,7 +8845,7 @@ if not modules then modules={} end modules ['util-env']={  }  local allocate,mark=utilities.storage.allocate,utilities.storage.mark  local format,sub,match,gsub,find=string.format,string.sub,string.match,string.gsub,string.find -local unquoted,quoted=string.unquoted,string.quoted +local unquoted,quoted,optionalquoted=string.unquoted,string.quoted,string.optionalquoted  local concat,insert,remove=table.concat,table.insert,table.remove  environment=environment or {}  local environment=environment @@ -8841,24 +8958,14 @@ function environment.splitarguments(separator)    return before,after  end  function environment.reconstructcommandline(arg,noquote) +  local resolveprefix=resolvers.resolve     arg=arg or environment.originalarguments    if noquote and #arg==1 then -    local a=arg[1] -    a=resolvers.resolve(a) -    a=unquoted(a) -    return a +    return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1])    elseif #arg>0 then      local result={}      for i=1,#arg do -      local a=arg[i] -      a=resolvers.resolve(a) -      a=unquoted(a) -      a=gsub(a,'"','\\"')  -      if find(a," ",1,true) then -        result[#result+1]=quoted(a) -      else -        result[#result+1]=a -      end +      result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix)      end      return concat(result," ")    else @@ -12483,7 +12590,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-ini"] = package.loaded["data-ini"] or true --- original size: 7927, stripped down to: 5528 +-- original size: 10598, stripped down to: 7341  if not modules then modules={} end modules ['data-ini']={    version=1.001, @@ -12492,14 +12599,15 @@ if not modules then modules={} end modules ['data-ini']={    copyright="PRAGMA ADE / ConTeXt Development Team",    license="see context related readme files",  } +local next,type,getmetatable,rawset=next,type,getmetatable,rawset  local gsub,find,gmatch,char=string.gsub,string.find,string.gmatch,string.char -local next,type=next,type  local filedirname,filebasename,filejoin=file.dirname,file.basename,file.join +local ostype,osname,osuname,ossetenv,osgetenv=os.type,os.name,os.uname,os.setenv,os.getenv +local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match  local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end)  local trace_detail=false trackers.register("resolvers.details",function(v) trace_detail=v end)  local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end)  local report_initialization=logs.reporter("resolvers","initialization") -local ostype,osname,ossetenv,osgetenv=os.type,os.name,os.setenv,os.getenv  resolvers=resolvers or {}  local resolvers=resolvers  texconfig.kpse_init=false @@ -12632,10 +12740,88 @@ if type(profiler)=="table" and not jit then      profiler.start("luatex-profile.log")    end)  end -if not resolvers.resolve then -  function resolvers.resolve (s) return s end -  function resolvers.unresolve(s) return s end -  function resolvers.repath  (s) return s end +local prefixes=utilities.storage.allocate() +resolvers.prefixes=prefixes +local resolved={} +local abstract={} +function resolvers.resetresolve(str) +  resolved,abstract={},{} +end +function resolvers.allprefixes(separator) +  local all=table.sortedkeys(prefixes) +  if separator then +    for i=1,#all do +      all[i]=all[i]..":" +    end +  end +  return all +end +local function _resolve_(method,target) +  local action=prefixes[method] +  if action then +    return action(target) +  else +    return method..":"..target +  end +end +function resolvers.unresolve(str) +  return abstract[str] or str +end +local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) +local prefix=C(R("az")^2)*P(":") +local target=C((1-S(" \"\';,"))^1) +local notarget=(#S(";,")+P(-1))*Cc("") +local pattern=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) +local function resolve(str)  +  if type(str)=="table" then +    local res={} +    for i=1,#str do +      res[i]=resolve(str[i]) +    end +    return res +  else +    local res=resolved[str] +    if not res then +      res=lpegmatch(pattern,str) +      resolved[str]=res +      abstract[res]=str +    end +    return res +  end +end +resolvers.resolve=resolve +if type(osuname)=="function" then +  for k,v in next,osuname() do +    if not prefixes[k] then +      prefixes[k]=function() return v end +    end +  end +end +if ostype=="unix" then +  local pattern +  local function makepattern(t,k,v) +    if t then +      rawset(t,k,v) +    end +    local colon=P(":") +    for k,v in table.sortedpairs(prefixes) do +      if p then +        p=P(k)+p +      else +        p=P(k) +      end +    end +    pattern=Cs((p*colon+colon/";"+P(1))^0) +  end +  makepattern() +  table.setmetatablenewindex(prefixes,makepattern) +  function resolvers.repath(str) +    return lpegmatch(pattern,str) +  end +else  +  function resolvers.repath(str) +    return str +  end  end @@ -12645,7 +12831,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-exp"] = package.loaded["data-exp"] or true --- original size: 15317, stripped down to: 9723 +-- original size: 16463, stripped down to: 10113  if not modules then modules={} end modules ['data-exp']={    version=1.001, @@ -12660,11 +12846,14 @@ local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns  local Ct,Cs,Cc,Carg,P,C,S=lpeg.Ct,lpeg.Cs,lpeg.Cc,lpeg.Carg,lpeg.P,lpeg.C,lpeg.S  local type,next=type,next  local ostype=os.type -local collapsepath=file.collapsepath +local collapsepath,joinpath,basename=file.collapsepath,file.join,file.basename  local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end)  local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_globbing=true  trackers.register("resolvers.globbing",function(v) trace_globbing=v end)  local report_expansions=logs.reporter("resolvers","expansions") +local report_globbing=logs.reporter("resolvers","globbing")  local resolvers=resolvers +local resolveprefix=resolvers.resolve  local function f_both(a,b)    local t,n={},0    for sb in gmatch(b,"[^,]+") do        @@ -12754,35 +12943,27 @@ function resolvers.expandedpathfromlist(pathlist)    end    return newlist  end -local cleanup=lpeg.replacer { -  { "!","" }, -  { "\\","/" }, -} -function resolvers.cleanpath(str)  -  local doslashes=(P("\\")/"/"+1)^0 -  local donegation=(P("!")/""   )^0 -  local homedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") -  if homedir=="~" or homedir=="" or not lfs.isdir(homedir) then -    if trace_expansions then -      report_expansions("no home dir set, ignoring dependent paths") -    end -    function resolvers.cleanpath(str) -      if not str or find(str,"~",1,true) then -        return ""  -      else -        return lpegmatch(cleanup,str) +local usedhomedir=nil +local donegation=(P("!")/""   )^0 +local doslashes=(P("\\")/"/"+1)^0 +local function expandedhome() +  if not usedhomedir then +    usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") +    if usedhomedir=="~" or usedhomedir=="" or not lfs.isdir(usedhomedir) then +      if trace_expansions then +        report_expansions("no home dir set, ignoring dependent path using current path")        end -    end -  else -    local dohome=((P("~")+P("$HOME"))/homedir)^0 -    local cleanup=Cs(donegation*dohome*doslashes) -    function resolvers.cleanpath(str) -      return str and lpegmatch(cleanup,str) or "" +      usedhomedir="."      end    end -  return resolvers.cleanpath(str) +  return usedhomedir +end +local dohome=((P("~")+P("$HOME")+P("%HOME%"))/expandedhome)^0 +local cleanup=Cs(donegation*dohome*doslashes) +resolvers.cleanpath=function(str) +  return str and lpegmatch(cleanup,str) or ""  end -local expandhome=P("~")/"$HOME"  +local expandhome=P("~")/"$HOME"  local dodouble=P('"')/""*(expandhome+(1-P('"')))^0*P('"')/""  local dosingle=P("'")/""*(expandhome+(1-P("'")))^0*P("'")/""  local dostring=(expandhome+1       )^0 @@ -12834,7 +13015,7 @@ function resolvers.splitpath(str)  end  function resolvers.joinpath(str)    if type(str)=='table' then -    return file.joinpath(str) +    return joinpath(str)    else      return str    end @@ -12845,35 +13026,54 @@ local timer={}  local scanned={}  local nofscans=0  local scancache={} -local function scan(files,spec,path,n,m,r) -  local full=(path=="" and spec) or (spec..path..'/') +local fullcache={} +local nofsharedscans=0 +local function scan(files,remap,spec,path,n,m,r,onlyone) +  local full=path=="" and spec or (spec..path..'/')    local dirs={}    local nofdirs=0    for name in directory(full) do      if not lpegmatch(weird,name) then -      local mode=attributes(full..name,'mode') -      if mode=='file' then +      local mode=attributes(full..name,"mode") +      if mode=="file" then          n=n+1 -        local f=files[name] -        if f then -          if type(f)=='string' then -            files[name]={ f,path } +        local lower=lower(name) +        local paths=files[lower] +        if paths then +          if onlyone then            else -            f[#f+1]=path +            if type(paths)=="string" then +              files[lower]={ paths,path } +            else +              paths[#paths+1]=path +            end +            if name~=lower then +              local rl=remap[lower] +              if not rl then +                remap[lower]=name +                r=r+1 +              elseif trace_globbing and rl~=name then +                report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) +              end +            end            end          else  -          files[name]=path -          local lower=lower(name) +          files[lower]=path            if name~=lower then -            files["remap:"..lower]=name -            r=r+1 +            local rl=remap[lower] +            if not rl then +              remap[lower]=name +              r=r+1 +            elseif trace_globbing and rl~=name then +              report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) +            end            end          end -      elseif mode=='directory' then +      elseif mode=="directory" then          m=m+1          nofdirs=nofdirs+1          if path~="" then -          dirs[nofdirs]=path..'/'..name +          dirs[nofdirs]=path.."/"..name          else            dirs[nofdirs]=name          end @@ -12883,107 +13083,52 @@ local function scan(files,spec,path,n,m,r)    if nofdirs>0 then      sort(dirs)      for i=1,nofdirs do -      files,n,m,r=scan(files,spec,dirs[i],n,m,r) +      files,remap,n,m,r=scan(files,remap,spec,dirs[i],n,m,r,onlyone)      end    end    scancache[sub(full,1,-2)]=files -  return files,n,m,r +  return files,remap,n,m,r  end -local fullcache={} -function resolvers.scanfiles(path,branch,usecache) -  statistics.starttiming(timer) -  local realpath=resolvers.resolve(path)  +function resolvers.scanfiles(path,branch,usecache,onlyonce) +  local realpath=resolveprefix(path)    if usecache then -    local files=fullcache[realpath] -    if files then +    local content=fullcache[realpath] +    if content then        if trace_locating then -        report_expansions("using caches scan of path %a, branch %a",path,branch or path) +        report_expansions("using cached scan of path %a, branch %a",path,branch or path)        end -      return files +      nofsharedscans=nofsharedscans+1 +      return content      end    end +  statistics.starttiming(timer)    if trace_locating then      report_expansions("scanning path %a, branch %a",path,branch or path)    end -  local files,n,m,r=scan({},realpath..'/',"",0,0,0) -  files.__path__=path  -  files.__files__=n -  files.__directories__=m -  files.__remappings__=r +  local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce) +  local content={ +    metadata={ +      path=path, +      files=n, +      directories=m, +      remappings=r, +    }, +    files=files, +    remap=remap, +  }    if trace_locating then      report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r)    end    if usecache then      scanned[#scanned+1]=realpath -    fullcache[realpath]=files +    fullcache[realpath]=content    end    nofscans=nofscans+1    statistics.stoptiming(timer) -  return files -end -local function simplescan(files,spec,path)  -  local full=(path=="" and spec) or (spec..path..'/') -  local dirs={} -  local nofdirs=0 -  for name in directory(full) do -    if not lpegmatch(weird,name) then -      local mode=attributes(full..name,'mode') -      if mode=='file' then -        if not files[name] then -          files[name]=path -        end -      elseif mode=='directory' then -        nofdirs=nofdirs+1 -        if path~="" then -          dirs[nofdirs]=path..'/'..name -        else -          dirs[nofdirs]=name -        end -      end -    end -  end -  if nofdirs>0 then -    sort(dirs) -    for i=1,nofdirs do -      files=simplescan(files,spec,dirs[i]) -    end -  end -  return files +  return content  end -local simplecache={} -local nofsharedscans=0  function resolvers.simplescanfiles(path,branch,usecache) -  statistics.starttiming(timer) -  local realpath=resolvers.resolve(path)  -  if usecache then -    local files=simplecache[realpath] -    if not files then -      files=scancache[realpath] -      if files then -        nofsharedscans=nofsharedscans+1 -      end -    end -    if files then -      if trace_locating then -        report_expansions("using caches scan of path %a, branch %a",path,branch or path) -      end -      return files -    end -  end -  if trace_locating then -    report_expansions("scanning path %a, branch %a",path,branch or path) -  end -  local files=simplescan({},realpath..'/',"") -  if trace_locating then -    report_expansions("%s files found",table.count(files)) -  end -  if usecache then -    scanned[#scanned+1]=realpath -    simplecache[realpath]=files -  end -  nofscans=nofscans+1 -  statistics.stoptiming(timer) -  return files +  return resolvers.scanfiles(path,branch,usecache,true)   end  function resolvers.scandata()    table.sort(scanned) @@ -12994,6 +13139,49 @@ function resolvers.scandata()      paths=scanned,    }  end +function resolvers.get_from_content(content,path,name)  +  local files=content.files +  if not files then +    return +  end +  local remap=content.remap +  if not remap then +    return +  end +  if name then +    local used=lower(name) +    return path,remap[used] or used +  else +    local name=path +    local used=lower(name) +    local path=files[used] +    if path then +      return path,remap[used] or used +    end +  end +end +local nothing=function() end +function resolvers.filtered_from_content(content,pattern) +  if content and type(pattern)=="string" then +    local pattern=lower(pattern) +    local files=content.files +    local remap=content.remap +    if files and remap then +      local n=next(files) +      local function iterator() +        while n do +          local k=n +          n=next(files,k) +          if find(k,pattern) then +            return files[k],remap and remap[k] or k +          end +        end +      end +      return iterator +    end +  end +  return nothing +end  end -- of closure @@ -13272,7 +13460,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-tmp"] = package.loaded["data-tmp"] or true --- original size: 15532, stripped down to: 11648 +-- original size: 15681, stripped down to: 11761  if not modules then modules={} end modules ['data-tmp']={    version=1.100, @@ -13291,6 +13479,7 @@ local trace_cache=false trackers.register("resolvers.cache",function(v) trace_ca  local report_caches=logs.reporter("resolvers","caches")  local report_resolvers=logs.reporter("resolvers","caching")  local resolvers=resolvers +local cleanpath=resolvers.cleanpath  local directive_cleanup=false directives.register("system.compile.cleanup",function(v) directive_cleanup=v end)  local directive_strip=false directives.register("system.compile.strip",function(v) directive_strip=v end)  local compile=utilities.lua.compile @@ -13312,7 +13501,7 @@ caches.relocate=false  caches.defaults={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" }  local writable,readables,usedreadables=nil,{},{}  local function identify() -  local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") +  local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE")     if texmfcaches then      for k=1,#texmfcaches do        local cachepath=texmfcaches[k] @@ -13566,10 +13755,12 @@ local content_state={}  function caches.contentstate()    return content_state or {}  end -function caches.loadcontent(cachename,dataname) -  local name=caches.hashed(cachename) -  local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") -  local filename=file.join(path,name) +function caches.loadcontent(cachename,dataname,filename) +  if not filename then +    local name=caches.hashed(cachename) +    local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") +    filename=file.join(path,name) +  end    local blob=loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua))    if blob then      local data=blob() @@ -13601,10 +13792,12 @@ function caches.collapsecontent(content)      end    end  end -function caches.savecontent(cachename,dataname,content) -  local name=caches.hashed(cachename) -  local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") -  local filename=file.join(path,name)  +function caches.savecontent(cachename,dataname,content,filename) +  if not filename then +    local name=caches.hashed(cachename) +    local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") +    filename=file.join(path,name)  +  end    local luaname=addsuffix(filename,luasuffixes.lua)    local lucname=addsuffix(filename,luasuffixes.luc)    if trace_locating then @@ -13647,7 +13840,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-met"] = package.loaded["data-met"] or true --- original size: 5460, stripped down to: 4014 +-- original size: 5347, stripped down to: 4015  if not modules then modules={} end modules ['data-met']={    version=1.100, @@ -13675,7 +13868,7 @@ local function splitmethod(filename)    if type(filename)=="table" then      return filename     end -  filename=file.collapsepath(filename,".") +  filename=file.collapsepath(filename,".")     if not find(filename,"://",1,true) then      return { scheme="file",path=filename,original=filename,filename=filename }    end @@ -13766,7 +13959,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-res"] = package.loaded["data-res"] or true --- original size: 62045, stripped down to: 43116 +-- original size: 61031, stripped down to: 42613  if not modules then modules={} end modules ['data-res']={    version=1.001, @@ -13776,7 +13969,7 @@ if not modules then modules={} end modules ['data-res']={    license="see context related readme files",  }  local gsub,find,lower,upper,match,gmatch=string.gsub,string.find,string.lower,string.upper,string.match,string.gmatch -local concat,insert,sortedkeys=table.concat,table.insert,table.sortedkeys +local concat,insert,sortedkeys,sortedhash=table.concat,table.insert,table.sortedkeys,table.sortedhash  local next,type,rawget=next,type,rawget  local os=os  local P,S,R,C,Cc,Cs,Ct,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cc,lpeg.Cs,lpeg.Ct,lpeg.Carg @@ -13785,14 +13978,19 @@ local formatters=string.formatters  local filedirname=file.dirname  local filebasename=file.basename  local suffixonly=file.suffixonly +local addsuffix=file.addsuffix +local removesuffix=file.removesuffix  local filejoin=file.join  local collapsepath=file.collapsepath  local joinpath=file.joinpath +local is_qualified_path=file.is_qualified_path  local allocate=utilities.storage.allocate  local settings_to_array=utilities.parsers.settings_to_array +local getcurrentdir=lfs.currentdir +local isfile=lfs.isfile +local isdir=lfs.isdir  local setmetatableindex=table.setmetatableindex  local luasuffixes=utilities.lua.suffixes -local getcurrentdir=lfs.currentdir  local trace_locating=false trackers .register("resolvers.locating",function(v) trace_locating=v end)  local trace_detail=false trackers .register("resolvers.details",function(v) trace_detail=v end)  local trace_expansions=false trackers .register("resolvers.expansions",function(v) trace_expansions=v end) @@ -13803,10 +14001,14 @@ local expandedpathfromlist=resolvers.expandedpathfromlist  local checkedvariable=resolvers.checkedvariable  local splitconfigurationpath=resolvers.splitconfigurationpath  local methodhandler=resolvers.methodhandler +local filtered=resolvers.filtered_from_content +local lookup=resolvers.get_from_content +local cleanpath=resolvers.cleanpath +local resolveprefix=resolvers.resolve  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' -resolvers.configbanner='' +resolvers.cacheversion="1.100" +resolvers.configbanner=""  resolvers.homedir=environment.homedir  resolvers.criticalvars=allocate { "SELFAUTOLOC","SELFAUTODIR","SELFAUTOPARENT","TEXMFCNF","TEXMF","TEXOS" }  resolvers.luacnfname="texmfcnf.lua" @@ -13833,7 +14035,7 @@ local   instance=resolvers.instance or nil  function resolvers.setenv(key,value,raw)    if instance then      instance.environment[key]=value -    ossetenv(key,raw and value or resolvers.resolve(value)) +    ossetenv(key,raw and value or resolveprefix(value))    end  end  local function getenv(key) @@ -13847,7 +14049,7 @@ local function getenv(key)  end  resolvers.getenv=getenv  resolvers.env=getenv -local function resolve(k) +local function resolvevariable(k)    return instance.expansions[k]  end  local dollarstripper=lpeg.stripper("$") @@ -13856,19 +14058,19 @@ local backslashswapper=lpeg.replacer("\\","/")  local somevariable=P("$")/""  local somekey=C(R("az","AZ","09","__","--")^1)  local somethingelse=P(";")*((1-S("!{}/\\"))^1*P(";")/"")+P(";")*(P(";")/"")+P(1) -local variableexpander=Cs((somevariable*(somekey/resolve)+somethingelse)^1 ) +local variableexpander=Cs((somevariable*(somekey/resolvevariable)+somethingelse)^1 )  local cleaner=P("\\")/"/"+P(";")*S("!{}/\\")^0*P(";")^1/";"  local variablecleaner=Cs((cleaner+P(1))^0) -local somevariable=R("az","AZ","09","__","--")^1/resolve +local somevariable=R("az","AZ","09","__","--")^1/resolvevariable  local variable=(P("$")/"")*(somevariable+(P("{")/"")*somevariable*(P("}")/""))  local variableresolver=Cs((variable+P(1))^0)  local function expandedvariable(var)    return lpegmatch(variableexpander,var) or var  end -function resolvers.newinstance()  -   if trace_locating then +function resolvers.newinstance() +  if trace_locating then      report_resolving("creating instance") -   end +  end    local environment,variables,expansions,order=allocate(),allocate(),allocate(),allocate()    local newinstance={      environment=environment, @@ -13995,13 +14197,13 @@ local function identify_configuration_files()      for i=1,#cnfpaths do        local filepath=cnfpaths[i]        local filename=collapsepath(filejoin(filepath,luacnfname)) -      local realname=resolvers.resolve(filename) +      local realname=resolveprefix(filename)        if trace_locating then -        local fullpath=gsub(resolvers.resolve(collapsepath(filepath)),"//","/") +        local fullpath=gsub(resolveprefix(collapsepath(filepath)),"//","/")          local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true)          report_resolving("looking for %a on %s path %a from specification %a",luacnfname,weirdpath and "weird" or "given",fullpath,filepath)        end -      if lfs.isfile(realname) then +      if isfile(realname) then          specification[#specification+1]=filename           if trace_locating then            report_resolving("found configuration file %a",realname) @@ -14023,7 +14225,7 @@ local function load_configuration_files()        local filename=specification[i]        local pathname=filedirname(filename)        local filename=filejoin(pathname,luacnfname) -      local realname=resolvers.resolve(filename)  +      local realname=resolveprefix(filename)         local blob=loadfile(realname)        if blob then          local setups=instance.setups @@ -14031,7 +14233,7 @@ local function load_configuration_files()          local parent=data and data.parent          if parent then            local filename=filejoin(pathname,parent) -          local realname=resolvers.resolve(filename)  +          local realname=resolveprefix(filename)             local blob=loadfile(realname)            if blob then              local parentdata=blob() @@ -14056,7 +14258,7 @@ local function load_configuration_files()              elseif variables[k]==nil then                if trace_locating and not warning then                  report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable", -                  k,resolvers.resolve(filename)) +                  k,resolveprefix(filename))                  warning=true                end                variables[k]=v @@ -14116,7 +14318,7 @@ local function locate_file_databases()        local stripped=lpegmatch(inhibitstripper,path)         if stripped~="" then          local runtime=stripped==path -        path=resolvers.cleanpath(path) +        path=cleanpath(path)          local spec=resolvers.splitmethod(stripped)          if runtime and (spec.noscheme or spec.scheme=="file") then            stripped="tree:///"..stripped @@ -14179,8 +14381,8 @@ function resolvers.renew(hashname)          report_resolving("identifying tree %a",hashname)        end      end -    local realpath=resolvers.resolve(hashname) -    if lfs.isdir(realpath) then +    local realpath=resolveprefix(hashname) +    if isdir(realpath) then        if trace_locating then          report_resolving("using path %a",realpath)        end @@ -14308,7 +14510,7 @@ function resolvers.registerextrapath(paths,subpaths)            local ps=p.."/"..s            if not done[ps] then              newn=newn+1 -            ep[newn]=resolvers.cleanpath(ps) +            ep[newn]=cleanpath(ps)              done[ps]=true            end          end @@ -14318,7 +14520,7 @@ function resolvers.registerextrapath(paths,subpaths)          local p=paths[i]          if not done[p] then            newn=newn+1 -          ep[newn]=resolvers.cleanpath(p) +          ep[newn]=cleanpath(p)            done[p]=true          end        end @@ -14330,7 +14532,7 @@ function resolvers.registerextrapath(paths,subpaths)          local ps=ep[i].."/"..s          if not done[ps] then            newn=newn+1 -          ep[newn]=resolvers.cleanpath(ps) +          ep[newn]=cleanpath(ps)            done[ps]=true          end        end @@ -14384,7 +14586,7 @@ function resolvers.cleanpathlist(str)    local t=resolvers.expandedpathlist(str)    if t then      for i=1,#t do -      t[i]=collapsepath(resolvers.cleanpath(t[i])) +      t[i]=collapsepath(cleanpath(t[i]))      end    end    return t @@ -14434,7 +14636,7 @@ function resolvers.registerfilehash(name,content,someerror)    end  end  local function isreadable(name) -  local readable=lfs.isfile(name)  +  local readable=isfile(name)     if trace_detail then      if readable then        report_resolving("file %a is readable",name) @@ -14445,69 +14647,56 @@ local function isreadable(name)    return readable  end  local function collect_files(names) -  local filelist,noffiles={},0 +  local filelist={} +  local noffiles=0 +  local function check(hash,root,pathname,path,name) +    if not pathname or find(path,pathname) then +      local variant=hash.type +      local search=filejoin(root,path,name)  +      local result=methodhandler('concatinators',variant,root,path,name) +      if trace_detail then +        report_resolving("match: variant %a, search %a, result %a",variant,search,result) +      end +      noffiles=noffiles+1 +      filelist[noffiles]={ variant,search,result } +    end +  end    for k=1,#names do -    local fname=names[k] +    local filename=names[k]      if trace_detail then -      report_resolving("checking name %a",fname) +      report_resolving("checking name %a",filename)      end -    local bname=filebasename(fname) -    local dname=filedirname(fname) -    if dname=="" or find(dname,"^%.") then -      dname=false +    local basename=filebasename(filename) +    local pathname=filedirname(filename) +    if pathname=="" or find(pathname,"^%.") then +      pathname=false      else -      dname=gsub(dname,"%*",".*") -      dname="/"..dname.."$" +      pathname=gsub(pathname,"%*",".*") +      pathname="/"..pathname.."$"      end      local hashes=instance.hashes      for h=1,#hashes do        local hash=hashes[h] -      local blobpath=hash.name -      local files=blobpath and instance.files[blobpath] -      if files then +      local hashname=hash.name +      local content=hashname and instance.files[hashname] +      if content then          if trace_detail then -          report_resolving("deep checking %a, base %a, pattern %a",blobpath,bname,dname) -        end -        local blobfile=files[bname] -        if not blobfile then -          local rname="remap:"..bname -          blobfile=files[rname] -          if blobfile then -            bname=files[rname] -            blobfile=files[bname] -          end +          report_resolving("deep checking %a, base %a, pattern %a",blobpath,basename,pathname)          end -        if blobfile then -          local blobroot=files.__path__ or blobpath -          if type(blobfile)=='string' then -            if not dname or find(blobfile,dname) then -              local variant=hash.type -              local search=filejoin(blobroot,blobfile,bname) -              local result=methodhandler('concatinators',hash.type,blobroot,blobfile,bname) -              if trace_detail then -                report_resolving("match: variant %a, search %a, result %a",variant,search,result) -              end -              noffiles=noffiles+1 -              filelist[noffiles]={ variant,search,result } -            end +        local path,name=lookup(content,basename) +        if path then +          local metadata=content.metadata +          local realroot=metadata and metadata.path or hashname +          if type(path)=="string" then +            check(hash,realroot,pathname,path,name)            else -            for kk=1,#blobfile do -              local vv=blobfile[kk] -              if not dname or find(vv,dname) then -                local variant=hash.type -                local search=filejoin(blobroot,vv,bname) -                local result=methodhandler('concatinators',hash.type,blobroot,vv,bname) -                if trace_detail then -                  report_resolving("match: variant %a, search %a, result %a",variant,search,result) -                end -                noffiles=noffiles+1 -                filelist[noffiles]={ variant,search,result } -              end +            for i=1,#path do +              check(hash,realroot,pathname,path[i],name)              end            end          end        elseif trace_locating then -        report_resolving("no match in %a (%s)",blobpath,bname) +        report_resolving("no match in %a (%s)",hashname,basename)        end      end    end @@ -14532,7 +14721,7 @@ end  local function can_be_dir(name)     local fakepaths=instance.fakepaths    if not fakepaths[name] then -    if lfs.isdir(name) then +    if isdir(name) then        fakepaths[name]=1       else        fakepaths[name]=2  @@ -14548,10 +14737,11 @@ local function find_analyze(filename,askedformat,allresults)    if askedformat=="" then      if ext=="" or not suffixmap[ext] then        local defaultsuffixes=resolvers.defaultsuffixes +      local formatofsuffix=resolvers.formatofsuffix        for i=1,#defaultsuffixes do          local forcedname=filename..'.'..defaultsuffixes[i]          wantedfiles[#wantedfiles+1]=forcedname -        filetype=resolvers.formatofsuffix(forcedname) +        filetype=formatofsuffix(forcedname)          if trace_locating then            report_resolving("forcing filetype %a",filetype)          end @@ -14591,14 +14781,14 @@ local function find_wildcard(filename,allresults)      if trace_locating then        report_resolving("checking wildcard %a",filename)      end -    local method,result=resolvers.findwildcardfiles(filename) +    local result=resolvers.findwildcardfiles(filename)      if result then        return "wildcard",result      end    end  end  local function find_qualified(filename,allresults,askedformat,alsostripped)  -  if not file.is_qualified_path(filename) then +  if not is_qualified_path(filename) then      return    end    if trace_locating then @@ -14687,7 +14877,6 @@ local function find_intree(filename,filetype,wantedfiles,allresults)      if trace_detail then        report_resolving("checking filename %a",filename)      end -    local resolve=resolvers.resolve      local result={}      for k=1,#pathlist do        local path=pathlist[k] @@ -14706,8 +14895,8 @@ local function find_intree(filename,filetype,wantedfiles,allresults)            local fl=filelist[k]            local f=fl[2]            local d=dirlist[k] -          if find(d,expression) or find(resolve(d),expression) then -            result[#result+1]=resolve(fl[3])  +          if find(d,expression) or find(resolveprefix(d),expression) then +            result[#result+1]=resolveprefix(fl[3])               done=true              if allresults then                if trace_detail then @@ -14729,7 +14918,7 @@ local function find_intree(filename,filetype,wantedfiles,allresults)        else          method="filesystem"           pathname=gsub(pathname,"/+$","") -        pathname=resolve(pathname) +        pathname=resolveprefix(pathname)          local scheme=url.hasscheme(pathname)          if not scheme or scheme=="file" then            local pname=gsub(pathname,"%.%*$",'') @@ -14819,7 +15008,7 @@ local function find_otherwise(filename,filetype,wantedfiles,allresults)    local filelist=collect_files(wantedfiles)    local fl=filelist and filelist[1]    if fl then -    return "otherwise",{ resolvers.resolve(fl[3]) }  +    return "otherwise",{ resolveprefix(fl[3]) }     end  end  collect_instance_files=function(filename,askedformat,allresults)  @@ -14919,39 +15108,30 @@ function resolvers.findpath(filename,filetype)    return filedirname(findfiles(filename,filetype,false)[1] or "")  end  local function findgivenfiles(filename,allresults) -  local bname,result=filebasename(filename),{} +  local base=filebasename(filename) +  local result={}    local hashes=instance.hashes -  local noffound=0 +  local function okay(hash,path,name) +    local found=methodhandler('concatinators',hash.type,hash.name,path,name) +    if found and found~="" then +      result[#result+1]=resolveprefix(found) +      return not allresults +    end +  end    for k=1,#hashes do      local hash=hashes[k] -    local files=instance.files[hash.name] or {} -    local blist=files[bname] -    if not blist then -      local rname="remap:"..bname -      blist=files[rname] -      if blist then -        bname=files[rname] -        blist=files[bname] -      end -    end -    if blist then -      if type(blist)=='string' then -        local found=methodhandler('concatinators',hash.type,hash.name,blist,bname) or "" -        if found~="" then -          noffound=noffound+1 -          result[noffound]=resolvers.resolve(found) -          if not allresults then -            break -          end +    local content=instance.files[hash.name] +    if content then +      local path,name=lookup(content,base) +      if not path then +      elseif type(path)=="string" then +        if okay(hash,path,name) then +          return result          end        else -        for kk=1,#blist do -          local vv=blist[kk] -          local found=methodhandler('concatinators',hash.type,hash.name,vv,bname) or "" -          if found~="" then -            noffound=noffound+1 -            result[noffound]=resolvers.resolve(found) -            if not allresults then break end +        for i=1,#path do +          if okay(hash,path[i],name) then +            return result            end          end        end @@ -14965,64 +15145,80 @@ end  function resolvers.findgivenfile(filename)    return findgivenfiles(filename,false)[1] or ""  end -local function doit(path,blist,bname,tag,variant,result,allresults) -  local done=false -  if blist and variant then -    local resolve=resolvers.resolve  -    if type(blist)=='string' then -      if find(lower(blist),path) then -        local full=methodhandler('concatinators',variant,tag,blist,bname) or "" -        result[#result+1]=resolve(full) -        done=true -      end -    else -      for kk=1,#blist do -        local vv=blist[kk] -        if find(lower(vv),path) then -          local full=methodhandler('concatinators',variant,tag,vv,bname) or "" -          result[#result+1]=resolve(full) -          done=true -          if not allresults then break end -        end -      end -    end -  end -  return done -end  local makewildcard=Cs(    (P("^")^0*P("/")*P(-1)+P(-1))/".*"+(P("^")^0*P("/")/"")^0*(P("*")/".*"+P("-")/"%%-"+P(".")/"%%."+P("?")/"."+P("\\")/"/"+P(1))^0  )  function resolvers.wildcardpattern(pattern)    return lpegmatch(makewildcard,pattern) or pattern  end -local function findwildcardfiles(filename,allresults,result)  -  result=result or {} +local function findwildcardfiles(filename,allresults,result) +  local result=result or {}    local base=filebasename(filename)    local dirn=filedirname(filename)    local path=lower(lpegmatch(makewildcard,dirn) or dirn)    local name=lower(lpegmatch(makewildcard,base) or base) -  local files,done=instance.files,false +  local files=instance.files    if find(name,"*",1,true) then      local hashes=instance.hashes +    local function okay(found,path,base,hashname,hashtype) +      if find(found,path) then +        local full=methodhandler('concatinators',hashtype,hashname,found,base) +        if full and full~="" then +          result[#result+1]=resolveprefix(full) +          return not allresults +        end +      end +    end      for k=1,#hashes do        local hash=hashes[k] -      local hashname,hashtype=hash.name,hash.type -      for kk,hh in next,files[hashname] do -        if not find(kk,"^remap:") then -          if find(lower(kk),name) then -            if doit(path,hh,kk,hashname,hashtype,result,allresults) then done=true end -            if done and not allresults then break end +      local hashname=hash.name +      local hashtype=hash.type +      if hashname and hashtype then +        for found,base in filtered(files[hashname],name) do +          if type(found)=='string' then +            if okay(found,path,base,hashname,hashtype) then +              break +            end +          else +            for i=1,#found do +              if okay(found[i],path,base,hashname,hashtype) then +                break +              end +            end            end          end        end      end    else +    local function okayokay(found,path,base,hashname,hashtype) +      if find(found,path) then +        local full=methodhandler('concatinators',hashtype,hashname,found,base) +        if full and full~="" then +          result[#result+1]=resolveprefix(full) +          return not allresults +        end +      end +    end      local hashes=instance.hashes      for k=1,#hashes do        local hash=hashes[k] -      local hashname,hashtype=hash.name,hash.type -      if doit(path,files[hashname][base],base,hashname,hashtype,result,allresults) then done=true end -      if done and not allresults then break end +      local hashname=hash.name +      local hashtype=hash.type +      if hashname and hashtype then +        local found,base=lookup(content,base) +        if not found then +        elseif type(found)=='string' then +          if okay(found,path,base,hashname,hashtype) then +            break +          end +        else +          for i=1,#found do +            if okay(found[i],path,base,hashname,hashtype) then +              break +            end +          end +        end +      end      end    end    return result @@ -15095,7 +15291,7 @@ end  function resolvers.dowithpath(name,func)    local pathlist=resolvers.expandedpathlist(name)    for i=1,#pathlist do -    func("^"..resolvers.cleanpath(pathlist[i])) +    func("^"..cleanpath(pathlist[i]))    end  end  function resolvers.dowithvariable(name,func) @@ -15103,23 +15299,23 @@ function resolvers.dowithvariable(name,func)  end  function resolvers.locateformat(name)    local engine=environment.ownmain or "luatex" -  local barename=file.removesuffix(name) -  local fullname=file.addsuffix(barename,"fmt") +  local barename=removesuffix(name) +  local fullname=addsuffix(barename,"fmt")    local fmtname=caches.getfirstreadablefile(fullname,"formats",engine) or ""    if fmtname=="" then      fmtname=resolvers.findfile(fullname) -    fmtname=resolvers.cleanpath(fmtname) +    fmtname=cleanpath(fmtname)    end    if fmtname~="" then -    local barename=file.removesuffix(fmtname) -    local luaname=file.addsuffix(barename,luasuffixes.lua) -    local lucname=file.addsuffix(barename,luasuffixes.luc) -    local luiname=file.addsuffix(barename,luasuffixes.lui) -    if lfs.isfile(luiname) then +    local barename=removesuffix(fmtname) +    local luaname=addsuffix(barename,luasuffixes.lua) +    local lucname=addsuffix(barename,luasuffixes.luc) +    local luiname=addsuffix(barename,luasuffixes.lui) +    if isfile(luiname) then        return barename,luiname -    elseif lfs.isfile(lucname) then +    elseif isfile(lucname) then        return barename,lucname -    elseif lfs.isfile(luaname) then +    elseif isfile(luaname) then        return barename,luaname      end    end @@ -15141,29 +15337,24 @@ function resolvers.dowithfilesintree(pattern,handle,before,after)      local hash=hashes[i]      local blobtype=hash.type      local blobpath=hash.name -    if blobpath then +    if blobtype and blobpath then +      local total=0 +      local checked=0 +      local done=0        if before then          before(blobtype,blobpath,pattern)        end -      local files=instance.files[blobpath] -      local total,checked,done=0,0,0 -      if files then -        for k,v in table.sortedhash(files) do  -          total=total+1 -          if find(k,"^remap:") then -          elseif find(k,pattern) then -            if type(v)=="string" then -              checked=checked+1 -              if handle(blobtype,blobpath,v,k) then -                done=done+1 -              end -            else -              checked=checked+#v -              for i=1,#v do -                if handle(blobtype,blobpath,v[i],k) then -                  done=done+1 -                end -              end +      for path,name in filtered(instance.files[blobpath],pattern) do +        if type(path)=="string" then +          checked=checked+1 +          if handle(blobtype,blobpath,path,name) then +            done=done+1 +          end +        else +          checked=checked+#path +          for i=1,#path do +            if handle(blobtype,blobpath,path[i],name) then +              done=done+1              end            end          end @@ -15174,8 +15365,8 @@ function resolvers.dowithfilesintree(pattern,handle,before,after)      end    end  end -resolvers.obsolete=resolvers.obsolete or {} -local obsolete=resolvers.obsolete +local obsolete=resolvers.obsolete or {} +resolvers.obsolete=obsolete  resolvers.find_file=resolvers.findfile  obsolete.find_file=resolvers.findfile  resolvers.find_files=resolvers.findfiles  obsolete.find_files=resolvers.findfiles @@ -15186,7 +15377,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-pre"] = package.loaded["data-pre"] or true --- original size: 6643, stripped down to: 4401 +-- original size: 3106, stripped down to: 2563  if not modules then modules={} end modules ['data-pre']={    version=1.001, @@ -15196,44 +15387,51 @@ if not modules then modules={} end modules ['data-pre']={    license="see context related readme files"  }  local resolvers=resolvers -local prefixes=utilities.storage.allocate() -resolvers.prefixes=prefixes -local cleanpath,findgivenfile,expansion=resolvers.cleanpath,resolvers.findgivenfile,resolvers.expansion +local prefixes=resolvers.prefixes +local cleanpath=resolvers.cleanpath +local findgivenfile=resolvers.findgivenfile +local expansion=resolvers.expansion  local getenv=resolvers.getenv  -local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match -local joinpath,basename,dirname=file.join,file.basename,file.dirname -local getmetatable,rawset,type=getmetatable,rawset,type +local basename=file.basename +local dirname=file.dirname +local joinpath=file.join +local isfile=lfs.isfile  prefixes.environment=function(str)    return cleanpath(expansion(str))  end -prefixes.relative=function(str,n)  -  if io.exists(str) then -  elseif io.exists("./"..str) then -    str="./"..str -  else -    local p="../" -    for i=1,n or 2 do -      if io.exists(p..str) then -        str=p..str -        break -      else -        p=p.."../" +local function relative(str,n) +  if not isfile(str) then +    local pstr="./"..str +    if isfile(pstr) then +      str=pstr +    else +      local p="../" +      for i=1,n or 2 do +        local pstr=p..str +        if isfile(pstr) then +          str=pstr +          break +        else +          p=p.."../" +        end        end      end    end    return cleanpath(str)  end +local function locate(str) +  local fullname=findgivenfile(str) or "" +  return cleanpath(fullname~="" and fullname or str) +end +prefixes.relative=relative +prefixes.locate=locate  prefixes.auto=function(str) -  local fullname=prefixes.relative(str) -  if not lfs.isfile(fullname) then -    fullname=prefixes.locate(str) +  local fullname=relative(str) +  if not isfile(fullname) then +    fullname=locate(str)    end    return fullname  end -prefixes.locate=function(str) -  local fullname=findgivenfile(str) or "" -  return cleanpath((fullname~="" and fullname) or str) -end  prefixes.filename=function(str)    local fullname=findgivenfile(str) or ""    return cleanpath(basename((fullname~="" and fullname) or str))  @@ -15277,87 +15475,6 @@ prefixes.kpse=prefixes.locate  prefixes.full=prefixes.locate  prefixes.file=prefixes.filename  prefixes.path=prefixes.pathname -function resolvers.allprefixes(separator) -  local all=table.sortedkeys(prefixes) -  if separator then -    for i=1,#all do -      all[i]=all[i]..":" -    end -  end -  return all -end -local function _resolve_(method,target) -  local action=prefixes[method] -  if action then -    return action(target) -  else -    return method..":"..target -  end -end -local resolved,abstract={},{} -function resolvers.resetresolve(str) -  resolved,abstract={},{} -end -local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) -local prefix=C(R("az")^2)*P(":") -local target=C((1-S(" \"\';,"))^1) -local notarget=(#S(";,")+P(-1))*Cc("") -local pattern=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) -local function resolve(str)  -  if type(str)=="table" then -    local t={} -    for i=1,#str do -      t[i]=resolve(str[i]) -    end -    return t -  else -    local res=resolved[str] -    if not res then -      res=lpegmatch(pattern,str) -      resolved[str]=res -      abstract[res]=str -    end -    return res -  end -end -local function unresolve(str) -  return abstract[str] or str -end -resolvers.resolve=resolve -resolvers.unresolve=unresolve -if type(os.uname)=="function" then -  for k,v in next,os.uname() do -    if not prefixes[k] then -      prefixes[k]=function() return v end -    end -  end -end -if os.type=="unix" then -  local pattern -  local function makepattern(t,k,v) -    if t then -      rawset(t,k,v) -    end -    local colon=P(":") -    for k,v in table.sortedpairs(prefixes) do -      if p then -        p=P(k)+p -      else -        p=P(k) -      end -    end -    pattern=Cs((p*colon+colon/";"+P(1))^0) -  end -  makepattern() -  getmetatable(prefixes).__newindex=makepattern -  function resolvers.repath(str) -    return lpegmatch(pattern,str) -  end -else  -  function resolvers.repath(str) -    return str -  end -end  end -- of closure @@ -15419,7 +15536,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-fil"] = package.loaded["data-fil"] or true --- original size: 3801, stripped down to: 3231 +-- original size: 3863, stripped down to: 3310  if not modules then modules={} end modules ['data-fil']={    version=1.001, @@ -15431,30 +15548,31 @@ if not modules then modules={} end modules ['data-fil']={  local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end)  local report_files=logs.reporter("resolvers","files")  local resolvers=resolvers +local resolveprefix=resolvers.resolve  local finders,openers,loaders,savers=resolvers.finders,resolvers.openers,resolvers.loaders,resolvers.savers  local locators,hashers,generators,concatinators=resolvers.locators,resolvers.hashers,resolvers.generators,resolvers.concatinators  local checkgarbage=utilities.garbagecollector and utilities.garbagecollector.check  function locators.file(specification) -  local name=specification.filename -  local realname=resolvers.resolve(name)  +  local filename=specification.filename +  local realname=resolveprefix(filename)     if realname and realname~='' and lfs.isdir(realname) then      if trace_locating then -      report_files("file locator %a found as %a",name,realname) +      report_files("file locator %a found as %a",filename,realname)      end -    resolvers.appendhash('file',name,true)  +    resolvers.appendhash('file',filename,true)     elseif trace_locating then -    report_files("file locator %a not found",name) +    report_files("file locator %a not found",filename)    end  end  function hashers.file(specification) -  local name=specification.filename -  local content=caches.loadcontent(name,'files') -  resolvers.registerfilehash(name,content,content==nil) +  local pathname=specification.filename +  local content=caches.loadcontent(pathname,'files') +  resolvers.registerfilehash(pathname,content,content==nil)  end  function generators.file(specification) -  local path=specification.filename -  local content=resolvers.scanfiles(path,false,true) -  resolvers.registerfilehash(path,content,true) +  local pathname=specification.filename +  local content=resolvers.scanfiles(pathname,false,true)  +  resolvers.registerfilehash(pathname,content,true)  end  concatinators.file=file.join  function finders.file(specification,filetype) @@ -15736,7 +15854,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-zip"] = package.loaded["data-zip"] or true --- original size: 8489, stripped down to: 6757 +-- original size: 9043, stripped down to: 7073  if not modules then modules={} end modules ['data-zip']={    version=1.001, @@ -15779,7 +15897,7 @@ function zip.openarchive(name)      local arch=archives[name]      if not arch then        local full=resolvers.findfile(name) or "" -      arch=(full~="" and zip.open(full)) or false +      arch=full~="" and zip.open(full) or false        archives[name]=arch      end      return arch @@ -15938,31 +16056,42 @@ function resolvers.usezipfile(archive)    end  end  function resolvers.registerzipfile(z,tree) -  local files,filter={},"" -  if tree=="" then -    filter="^(.+)/(.-)$" -  else -    filter=format("^%s/(.+)/(.-)$",tree) -  end +  local names={} +  local files={}  +  local remap={}  +  local n=0 +  local filter=tree=="" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) +  local register=resolvers.registerfile    if trace_locating then      report_zip("registering: using filter %a",filter)    end -  local register,n=resolvers.registerfile,0    for i in z:files() do -    local path,name=match(i.filename,filter) -    if path then -      if name and name~='' then -        register(files,name,path) -        n=n+1 -      else +    local filename=i.filename +    local path,name=match(filename,filter) +    if not path then +      n=n+1 +      register(names,filename,"") +      local usedname=lower(filename) +      files[usedname]="" +      if usedname~=filename then +        remap[usedname]=filename        end -    else -      register(files,i.filename,'') +    elseif name and name~="" then        n=n+1 +      register(names,name,path) +      local usedname=lower(name) +      files[usedname]=path +      if usedname~=name then +        remap[usedname]=name +      end +    else      end    end    report_zip("registering: %s files registered",n) -  return files +  return { +    files=files, +    remap=remap, +  }  end @@ -15972,7 +16101,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-tre"] = package.loaded["data-tre"] or true --- original size: 2508, stripped down to: 2074 +-- original size: 4859, stripped down to: 3335  if not modules then modules={} end modules ['data-tre']={    version=1.001, @@ -15981,42 +16110,50 @@ if not modules then modules={} end modules ['data-tre']={    copyright="PRAGMA ADE / ConTeXt Development Team",    license="see context related readme files"  } -local find,gsub,format=string.find,string.gsub,string.format +local find,gsub,lower=string.find,string.gsub,string.lower +local basename,dirname,joinname=file.basename,file.dirname,file  .join +local globdir,isdir=dir.glob,lfs.isdir  local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end)  local report_trees=logs.reporter("resolvers","trees")  local resolvers=resolvers -local done,found,notfound={},{},resolvers.finders.notfound -function resolvers.finders.tree(specification) +local resolveprefix=resolvers.resolve +local notfound=resolvers.finders.notfound +local collectors={} +local found={} +function resolvers.finders.tree(specification)     local spec=specification.filename -  local fnd=found[spec] -  if fnd==nil then +  local okay=found[spec] +  if okay==nil then      if spec~="" then -      local path,name=file.dirname(spec),file.basename(spec) -      if path=="" then path="." end -      local hash=done[path] -      if not hash then -        local pattern=path.."/*"  -        hash=dir.glob(pattern) -        done[path]=hash +      local path=dirname(spec) +      local name=basename(spec) +      if path=="" then +        path="." +      end +      local names=collectors[path] +      if not names then +        local pattern=find(path,"/%*+$") and path or (path.."/*") +        names=globdir(pattern) +        collectors[path]=names        end        local pattern="/"..gsub(name,"([%.%-%+])","%%%1").."$" -      for k=1,#hash do -        local v=hash[k] -        if find(v,pattern) then -          found[spec]=v -          return v +      for i=1,#names do +        local fullname=names[i] +        if find(fullname,pattern) then +          found[spec]=fullname +          return fullname          end        end      end -    fnd=notfound()  -    found[spec]=fnd +    okay=notfound()  +    found[spec]=okay    end -  return fnd +  return okay  end  function resolvers.locators.tree(specification)    local name=specification.filename -  local realname=resolvers.resolve(name)  -  if realname and realname~='' and lfs.isdir(realname) then +  local realname=resolveprefix(name)  +  if realname and realname~='' and isdir(realname) then      if trace_locating then        report_trees("locator %a found",realname)      end @@ -16033,10 +16170,43 @@ function resolvers.hashers.tree(specification)    resolvers.methodhandler("hashers",name)    resolvers.generators.file(specification)  end -resolvers.concatinators.tree=resolvers.concatinators.file -resolvers.generators.tree=resolvers.generators.file -resolvers.openers.tree=resolvers.openers.file -resolvers.loaders.tree=resolvers.loaders.file +local collectors={} +table.setmetatableindex(collectors,function(t,k) +  local rootname=gsub(k,"[/%*]+$","") +  local dataname=joinname(rootname,"dirlist") +  local data=caches.loadcontent(dataname,"files",dataname) +  local content=data and data.content +  local lookup=resolvers.get_from_content +  if not content then +    content=resolvers.scanfiles(rootname) +    caches.savecontent(dataname,"files",content,dataname) +  end +  local files=content.files +  local v=function(filename) +    local path,name=lookup(content,filename) +    if not path then +      return filename +    elseif type(path)=="table" then +      path=path[1] +    end +    return joinname(rootname,path,name) +  end +  t[k]=v +  return v +end) +function resolvers.finders.dirlist(specification)  +  local spec=specification.filename +  if spec~="" then +    local path,name=dirname(spec),basename(spec) +    return path and collectors[path](name) or notfound() +  end +  return notfound() +end +resolvers.locators .dirlist=resolvers.locators .tree +resolvers.hashers  .dirlist=resolvers.hashers  .tree +resolvers.generators.dirlist=resolvers.generators.file +resolvers.openers  .dirlist=resolvers.openers  .file +resolvers.loaders  .dirlist=resolvers.loaders  .file  end -- of closure @@ -16221,7 +16391,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-lua"] = package.loaded["data-lua"] or true --- original size: 4237, stripped down to: 3177 +-- original size: 4313, stripped down to: 3227  if not modules then modules={} end modules ['data-lua']={    version=1.001, @@ -16230,7 +16400,7 @@ if not modules then modules={} end modules ['data-lua']={    copyright="PRAGMA ADE / ConTeXt Development Team",    license="see context related readme files"  } -local resolvers,package=resolvers,package +local package,lpeg=package,lpeg  local gsub=string.gsub  local concat=table.concat  local addsuffix=file.addsuffix @@ -16241,9 +16411,11 @@ local luaformats={ 'TEXINPUTS','LUAINPUTS' }  local libformats={ 'CLUAINPUTS' }  local helpers=package.helpers or {}  local methods=helpers.methods or {} +local resolvers=resolvers +local resolveprefix=resolvers.resolve +helpers.report=logs.reporter("resolvers","libraries")  trackers.register("resolvers.libraries",function(v) helpers.trace=v end)  trackers.register("resolvers.locating",function(v) helpers.trace=v end) -helpers.report=logs.reporter("resolvers","libraries")  helpers.sequence={    "already loaded",    "preload table", @@ -16258,7 +16430,7 @@ helpers.sequence={  }  local pattern=Cs(P("!")^0/""*(P("/")*P(-1)/"/"+P("/")^1/"/"+1)^0)  function helpers.cleanpath(path)  -  return resolvers.resolve(lpegmatch(pattern,path)) +  return resolveprefix(lpegmatch(pattern,path))  end  local loadedaslib=helpers.loadedaslib  local getextraluapaths=package.extraluapaths @@ -16395,7 +16567,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-tmf"] = package.loaded["data-tmf"] or true --- original size: 2600, stripped down to: 1627 +-- original size: 2601, stripped down to: 1627  if not modules then modules={} end modules ['data-tmf']={    version=1.001, @@ -16451,7 +16623,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-lst"] = package.loaded["data-lst"] or true --- original size: 2654, stripped down to: 2301 +-- original size: 2734, stripped down to: 2354  if not modules then modules={} end modules ['data-lst']={    version=1.001, @@ -16460,10 +16632,13 @@ if not modules then modules={} end modules ['data-lst']={    copyright="PRAGMA ADE / ConTeXt Development Team",    license="see context related readme files"  } -local find,concat,upper,format=string.find,table.concat,string.upper,string.format +local rawget,type,next=rawget,type,next +local find,concat,upper=string.find,table.concat,string.upper  local fastcopy,sortedpairs=table.fastcopy,table.sortedpairs -resolvers.listers=resolvers.listers or {}  local resolvers=resolvers +local listers=resolvers.listers or {} +resolvers.listers=listers +local resolveprefix=resolvers.resolve  local report_lists=logs.reporter("resolvers","lists")  local function tabstr(str)    if type(str)=='table' then @@ -16472,7 +16647,7 @@ local function tabstr(str)      return str    end  end -function resolvers.listers.variables(pattern) +function listers.variables(pattern)    local instance=resolvers.instance    local environment=instance.environment    local variables=instance.variables @@ -16493,10 +16668,10 @@ function resolvers.listers.variables(pattern)    for key,value in sortedpairs(configured) do      if key~="" and (pattern=="" or find(upper(key),pattern)) then        report_lists(key) -      report_lists("  env: %s",tabstr(rawget(environment,key))  or "unset") -      report_lists("  var: %s",tabstr(configured[key])      or "unset") -      report_lists("  exp: %s",tabstr(expansions[key])      or "unset") -      report_lists("  res: %s",tabstr(resolvers.resolve(expansions[key])) or "unset") +      report_lists("  env: %s",tabstr(rawget(environment,key))    or "unset") +      report_lists("  var: %s",tabstr(configured[key])        or "unset") +      report_lists("  exp: %s",tabstr(expansions[key])        or "unset") +      report_lists("  res: %s",tabstr(resolveprefix(expansions[key])) or "unset")      end    end    instance.environment=fastcopy(env) @@ -16504,15 +16679,15 @@ function resolvers.listers.variables(pattern)    instance.expansions=fastcopy(exp)  end  local report_resolved=logs.reporter("system","resolved") -function resolvers.listers.configurations() +function listers.configurations()    local configurations=resolvers.instance.specification    for i=1,#configurations do -    report_resolved("file : %s",resolvers.resolve(configurations[i])) +    report_resolved("file : %s",resolveprefix(configurations[i]))    end    report_resolved("")    local list=resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec))    for i=1,#list do -    local li=resolvers.resolve(list[i]) +    local li=resolveprefix(list[i])      if lfs.isdir(li) then        report_resolved("path - %s",li)      else @@ -16951,8 +17126,8 @@ end -- of closure  -- used libraries    : l-lua.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-sto.lua util-prs.lua util-fmt.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-mrg.lua util-tpl.lua util-env.lua luat-env.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua util-lib.lua luat-sta.lua luat-fmt.lua  -- skipped libraries : - --- original bytes    : 699655 --- stripped bytes    : 249540 +-- original bytes    : 704727 +-- stripped bytes    : 250243  -- end library merge diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun index 189fc4b7b..70f493525 100644 --- a/scripts/context/stubs/unix/mtxrun +++ b/scripts/context/stubs/unix/mtxrun @@ -1195,7 +1195,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["l-table"] = package.loaded["l-table"] or true --- original size: 31828, stripped down to: 20814 +-- original size: 33243, stripped down to: 21578  if not modules then modules={} end modules ['l-table']={    version=1.001, @@ -1342,14 +1342,14 @@ local function sortedhash(t,cmp)      end      local n=0      local m=#s -    local function kv(s) +    local function kv()         if n<m then          n=n+1          local k=s[n]          return k,t[k]        end      end -    return kv,s +    return kv     else      return nothing    end @@ -2110,6 +2110,44 @@ function table.values(t,s)      return {}    end  end +function table.filtered(t,pattern,sort,cmp) +  if t and type(pattern)=="string" then +    if sort then +      local s +      if cmp then +        s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) +      else +        s=sortedkeys(t)  +      end +      local n=0 +      local m=#s +      local function kv(s) +        while n<m do +          n=n+1 +          local k=s[n] +          if find(k,pattern) then +            return k,t[k] +          end +        end +      end +      return kv,s +    else +      local n=next(t) +      local function iterator() +        while n do +          local k=n +          n=next(t,k) +          if find(k,pattern) then +            return k,t[k] +          end +        end +      end +      return iterator,t +    end +  else +    return nothing +  end +end  end -- of closure @@ -3775,7 +3813,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["l-dir"] = package.loaded["l-dir"] or true --- original size: 14788, stripped down to: 9096 +-- original size: 16056, stripped down to: 10707  if not modules then modules={} end modules ['l-dir']={    version=1.001, @@ -3785,7 +3823,7 @@ if not modules then modules={} end modules ['l-dir']={    license="see context related readme files"  }  local type,select=type,select -local find,gmatch,match,gsub=string.find,string.gmatch,string.match,string.gsub +local find,gmatch,match,gsub,sub=string.find,string.gmatch,string.match,string.gsub,string.sub  local concat,insert,remove,unpack=table.concat,table.insert,table.remove,table.unpack  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 @@ -3794,54 +3832,123 @@ local dir=dir  local lfs=lfs  local attributes=lfs.attributes  local walkdir=lfs.dir -local isdir=lfs.isdir -local isfile=lfs.isfile +local isdir=lfs.isdir  +local isfile=lfs.isfile   local currentdir=lfs.currentdir  local chdir=lfs.chdir  local mkdir=lfs.mkdir  local onwindows=os.type=="windows" or find(os.getenv("PATH"),";",1,true) -if not isdir then -  function isdir(name) -    local a=attributes(name) -    return a and a.mode=="directory" +if onwindows then +  isdir=function(name) +    name=gsub(name,"([/\\]+)$","/.") +    return attributes(name,"mode")=="directory" +  end +  isfile=function(name) +    return attributes(name,"mode")=="file"    end    lfs.isdir=isdir -end -if not isfile then -  function isfile(name) -    local a=attributes(name) -    return a and a.mode=="file" +  lfs.isfile=isfile +else +  isdir=function(name) +    return attributes(name,"mode")=="directory" +  end +  isfile=function(name) +    return attributes(name,"mode")=="file"    end +  lfs.isdir=isdir    lfs.isfile=isfile  end  function dir.current()    return (gsub(currentdir(),"\\","/"))  end -local lfsisdir=isdir -local function isdir(path) -  path=gsub(path,"[/\\]+$","") -  return lfsisdir(path) +local function glob_pattern_function(path,patt,recurse,action) +  if isdir(path) then +    local usedpath +    if path=="/" then +      usedpath="/." +    elseif not find(path,"/$") then +      usedpath=path.."/." +      path=path.."/" +    else +      usedpath=path +    end +    local dirs +    for name in walkdir(usedpath) do +      if name~="." and name~=".." then +        local full=path..name +        local mode=attributes(full,'mode') +        if mode=='file' then +          if not patt or find(full,patt) then +            action(full) +          end +        elseif recurse and mode=="directory" then +          if not dirs then +            dirs={ full } +          else +            dirs[#dirs+1]=full +          end +        end +      end +    end +    if dirs then +      for i=1,#dirs do +        glob_pattern_function(dirs[i],patt,recurse,action) +      end +    end +  end  end -lfs.isdir=isdir -local function globpattern(path,patt,recurse,action) -  if path=="/" then -    path=path.."." -  elseif not find(path,"/$") then -    path=path..'/' -  end -  if isdir(path) then  -    for name in walkdir(path) do  -      local full=path..name -      local mode=attributes(full,'mode') -      if mode=='file' then -        if find(full,patt) then -          action(full) +local function glob_pattern_table(path,patt,recurse,result) +  if not result then +    result={} +  end +  if isdir(path) then +    local usedpath +    if path=="/" then +      usedpath="/." +    elseif not find(path,"/$") then +      usedpath=path.."/." +      path=path.."/" +    else +      usedpath=path +    end +    local dirs +    for name in walkdir(usedpath) do +      if name~="." and name~=".." then +        local full=path..name +        local mode=attributes(full,'mode') +        if mode=='file' then +          if not patt or find(full,patt) then +            result[#result+1]=full +          end +        elseif recurse and mode=="directory" then +          if not dirs then +            dirs={ full } +          else +            dirs[#dirs+1]=full +          end          end -      elseif recurse and (mode=="directory") and (name~='.') and (name~="..") then -        globpattern(full,patt,recurse,action) +      end +    end +    if dirs then +      for i=1,#dirs do +        glob_pattern_table(dirs[i],patt,recurse,result)        end      end    end +  return result +end +local function globpattern(path,patt,recurse,method) +  local kind=type(method) +  if pattern and sub(patt,1,-3)==path then +    patt=false +  end +  if kind=="function" then +    return glob_pattern_function(path,patt,recurse,method) +  elseif kind=="table" then +    return glob_pattern_table(path,patt,recurse,method) +  else +    return glob_pattern_table(path,patt,recurse,{}) +  end  end  dir.globpattern=globpattern  local function collectpattern(path,patt,recurse,result) @@ -3853,18 +3960,24 @@ local function collectpattern(path,patt,recurse,result)      ok,scanner,first=xpcall(function() return walkdir(path)   end,function() end)     end    if ok and type(scanner)=="function" then -    if not find(path,"/$") then path=path..'/' end +    if not find(path,"/$") then +      path=path..'/' +    end      for name in scanner,first do -      local full=path..name -      local attr=attributes(full) -      local mode=attr.mode -      if mode=='file' then -        if find(full,patt) then +      if name=="." then +      elseif name==".." then +      else +        local full=path..name +        local attr=attributes(full) +        local mode=attr.mode +        if mode=='file' then +          if find(full,patt) then +            result[name]=attr +          end +        elseif recurse and mode=="directory" then +          attr.list=collectpattern(full,patt,recurse)            result[name]=attr          end -      elseif recurse and (mode=="directory") and (name~='.') and (name~="..") then -        attr.list=collectpattern(full,patt,recurse) -        result[name]=attr        end      end    end @@ -3872,15 +3985,15 @@ local function collectpattern(path,patt,recurse,result)  end  dir.collectpattern=collectpattern  local separator -if onwindows then +if onwindows then     local slash=S("/\\")/"/" -  pattern=Ct { +  pattern={      [1]=(Cs(P(".")+slash^1)+Cs(R("az","AZ")*P(":")*slash^0)+Cc("./"))*V(2)*V(3),      [2]=Cs(((1-S("*?/\\"))^0*slash)^0),      [3]=Cs(P(1)^0)    } -else  -  pattern=Ct { +else +  pattern={      [1]=(C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3),      [2]=C(((1-S("*?/"))^0*P("/"))^0),      [3]=C(P(1)^0) @@ -3898,9 +4011,8 @@ local function glob(str,t)      elseif isfile(str) then        t(str)      else -      local split=lpegmatch(pattern,str)  -      if split then -        local root,path,base=split[1],split[2],split[3] +      local root,path,base=lpegmatch(pattern,str)  +      if root and path and base then          local recurse=find(base,"**",1,true)           local start=root..path          local result=lpegmatch(filter,start..base) @@ -3922,16 +4034,12 @@ local function glob(str,t)          return { str }        end      else -      local split=lpegmatch(pattern,str)  -      if split then -        local t=t or {} -        local action=action or function(name) t[#t+1]=name end -        local root,path,base=split[1],split[2],split[3] +      local root,path,base=lpegmatch(pattern,str)  +      if root and path and base then          local recurse=find(base,"**",1,true)           local start=root..path          local result=lpegmatch(filter,start..base) -        globpattern(start,result,recurse,action) -        return t +        return globpattern(start,result,recurse,t)        else          return {}        end @@ -4879,7 +4987,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["util-str"] = package.loaded["util-str"] or true --- original size: 33485, stripped down to: 18420 +-- original size: 34240, stripped down to: 18733  if not modules then modules={} end modules ['util-str']={    version=1.001, @@ -5544,6 +5652,15 @@ else    add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=lpeg.patterns.texescape })    add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=lpeg.patterns.luaescape })  end +local dquote=patterns.dquote  +local equote=patterns.escaped+dquote/'\\"'+1 +local space=patterns.space +local cquote=Cc('"') +local pattern=Cs(dquote*(equote-P(-2))^0*dquote)           ++Cs(cquote*(equote-space)^0*space*equote^0*cquote)  +function string.optionalquoted(str) +  return lpegmatch(pattern,str) or str +end  end -- of closure @@ -8717,7 +8834,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["util-env"] = package.loaded["util-env"] or true --- original size: 8814, stripped down to: 5092 +-- original size: 8022, stripped down to: 5038  if not modules then modules={} end modules ['util-env']={    version=1.001, @@ -8728,7 +8845,7 @@ if not modules then modules={} end modules ['util-env']={  }  local allocate,mark=utilities.storage.allocate,utilities.storage.mark  local format,sub,match,gsub,find=string.format,string.sub,string.match,string.gsub,string.find -local unquoted,quoted=string.unquoted,string.quoted +local unquoted,quoted,optionalquoted=string.unquoted,string.quoted,string.optionalquoted  local concat,insert,remove=table.concat,table.insert,table.remove  environment=environment or {}  local environment=environment @@ -8841,24 +8958,14 @@ function environment.splitarguments(separator)    return before,after  end  function environment.reconstructcommandline(arg,noquote) +  local resolveprefix=resolvers.resolve     arg=arg or environment.originalarguments    if noquote and #arg==1 then -    local a=arg[1] -    a=resolvers.resolve(a) -    a=unquoted(a) -    return a +    return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1])    elseif #arg>0 then      local result={}      for i=1,#arg do -      local a=arg[i] -      a=resolvers.resolve(a) -      a=unquoted(a) -      a=gsub(a,'"','\\"')  -      if find(a," ",1,true) then -        result[#result+1]=quoted(a) -      else -        result[#result+1]=a -      end +      result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix)      end      return concat(result," ")    else @@ -12483,7 +12590,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-ini"] = package.loaded["data-ini"] or true --- original size: 7927, stripped down to: 5528 +-- original size: 10598, stripped down to: 7341  if not modules then modules={} end modules ['data-ini']={    version=1.001, @@ -12492,14 +12599,15 @@ if not modules then modules={} end modules ['data-ini']={    copyright="PRAGMA ADE / ConTeXt Development Team",    license="see context related readme files",  } +local next,type,getmetatable,rawset=next,type,getmetatable,rawset  local gsub,find,gmatch,char=string.gsub,string.find,string.gmatch,string.char -local next,type=next,type  local filedirname,filebasename,filejoin=file.dirname,file.basename,file.join +local ostype,osname,osuname,ossetenv,osgetenv=os.type,os.name,os.uname,os.setenv,os.getenv +local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match  local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end)  local trace_detail=false trackers.register("resolvers.details",function(v) trace_detail=v end)  local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end)  local report_initialization=logs.reporter("resolvers","initialization") -local ostype,osname,ossetenv,osgetenv=os.type,os.name,os.setenv,os.getenv  resolvers=resolvers or {}  local resolvers=resolvers  texconfig.kpse_init=false @@ -12632,10 +12740,88 @@ if type(profiler)=="table" and not jit then      profiler.start("luatex-profile.log")    end)  end -if not resolvers.resolve then -  function resolvers.resolve (s) return s end -  function resolvers.unresolve(s) return s end -  function resolvers.repath  (s) return s end +local prefixes=utilities.storage.allocate() +resolvers.prefixes=prefixes +local resolved={} +local abstract={} +function resolvers.resetresolve(str) +  resolved,abstract={},{} +end +function resolvers.allprefixes(separator) +  local all=table.sortedkeys(prefixes) +  if separator then +    for i=1,#all do +      all[i]=all[i]..":" +    end +  end +  return all +end +local function _resolve_(method,target) +  local action=prefixes[method] +  if action then +    return action(target) +  else +    return method..":"..target +  end +end +function resolvers.unresolve(str) +  return abstract[str] or str +end +local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) +local prefix=C(R("az")^2)*P(":") +local target=C((1-S(" \"\';,"))^1) +local notarget=(#S(";,")+P(-1))*Cc("") +local pattern=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) +local function resolve(str)  +  if type(str)=="table" then +    local res={} +    for i=1,#str do +      res[i]=resolve(str[i]) +    end +    return res +  else +    local res=resolved[str] +    if not res then +      res=lpegmatch(pattern,str) +      resolved[str]=res +      abstract[res]=str +    end +    return res +  end +end +resolvers.resolve=resolve +if type(osuname)=="function" then +  for k,v in next,osuname() do +    if not prefixes[k] then +      prefixes[k]=function() return v end +    end +  end +end +if ostype=="unix" then +  local pattern +  local function makepattern(t,k,v) +    if t then +      rawset(t,k,v) +    end +    local colon=P(":") +    for k,v in table.sortedpairs(prefixes) do +      if p then +        p=P(k)+p +      else +        p=P(k) +      end +    end +    pattern=Cs((p*colon+colon/";"+P(1))^0) +  end +  makepattern() +  table.setmetatablenewindex(prefixes,makepattern) +  function resolvers.repath(str) +    return lpegmatch(pattern,str) +  end +else  +  function resolvers.repath(str) +    return str +  end  end @@ -12645,7 +12831,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-exp"] = package.loaded["data-exp"] or true --- original size: 15317, stripped down to: 9723 +-- original size: 16463, stripped down to: 10113  if not modules then modules={} end modules ['data-exp']={    version=1.001, @@ -12660,11 +12846,14 @@ local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns  local Ct,Cs,Cc,Carg,P,C,S=lpeg.Ct,lpeg.Cs,lpeg.Cc,lpeg.Carg,lpeg.P,lpeg.C,lpeg.S  local type,next=type,next  local ostype=os.type -local collapsepath=file.collapsepath +local collapsepath,joinpath,basename=file.collapsepath,file.join,file.basename  local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end)  local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_globbing=true  trackers.register("resolvers.globbing",function(v) trace_globbing=v end)  local report_expansions=logs.reporter("resolvers","expansions") +local report_globbing=logs.reporter("resolvers","globbing")  local resolvers=resolvers +local resolveprefix=resolvers.resolve  local function f_both(a,b)    local t,n={},0    for sb in gmatch(b,"[^,]+") do        @@ -12754,35 +12943,27 @@ function resolvers.expandedpathfromlist(pathlist)    end    return newlist  end -local cleanup=lpeg.replacer { -  { "!","" }, -  { "\\","/" }, -} -function resolvers.cleanpath(str)  -  local doslashes=(P("\\")/"/"+1)^0 -  local donegation=(P("!")/""   )^0 -  local homedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") -  if homedir=="~" or homedir=="" or not lfs.isdir(homedir) then -    if trace_expansions then -      report_expansions("no home dir set, ignoring dependent paths") -    end -    function resolvers.cleanpath(str) -      if not str or find(str,"~",1,true) then -        return ""  -      else -        return lpegmatch(cleanup,str) +local usedhomedir=nil +local donegation=(P("!")/""   )^0 +local doslashes=(P("\\")/"/"+1)^0 +local function expandedhome() +  if not usedhomedir then +    usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") +    if usedhomedir=="~" or usedhomedir=="" or not lfs.isdir(usedhomedir) then +      if trace_expansions then +        report_expansions("no home dir set, ignoring dependent path using current path")        end -    end -  else -    local dohome=((P("~")+P("$HOME"))/homedir)^0 -    local cleanup=Cs(donegation*dohome*doslashes) -    function resolvers.cleanpath(str) -      return str and lpegmatch(cleanup,str) or "" +      usedhomedir="."      end    end -  return resolvers.cleanpath(str) +  return usedhomedir +end +local dohome=((P("~")+P("$HOME")+P("%HOME%"))/expandedhome)^0 +local cleanup=Cs(donegation*dohome*doslashes) +resolvers.cleanpath=function(str) +  return str and lpegmatch(cleanup,str) or ""  end -local expandhome=P("~")/"$HOME"  +local expandhome=P("~")/"$HOME"  local dodouble=P('"')/""*(expandhome+(1-P('"')))^0*P('"')/""  local dosingle=P("'")/""*(expandhome+(1-P("'")))^0*P("'")/""  local dostring=(expandhome+1       )^0 @@ -12834,7 +13015,7 @@ function resolvers.splitpath(str)  end  function resolvers.joinpath(str)    if type(str)=='table' then -    return file.joinpath(str) +    return joinpath(str)    else      return str    end @@ -12845,35 +13026,54 @@ local timer={}  local scanned={}  local nofscans=0  local scancache={} -local function scan(files,spec,path,n,m,r) -  local full=(path=="" and spec) or (spec..path..'/') +local fullcache={} +local nofsharedscans=0 +local function scan(files,remap,spec,path,n,m,r,onlyone) +  local full=path=="" and spec or (spec..path..'/')    local dirs={}    local nofdirs=0    for name in directory(full) do      if not lpegmatch(weird,name) then -      local mode=attributes(full..name,'mode') -      if mode=='file' then +      local mode=attributes(full..name,"mode") +      if mode=="file" then          n=n+1 -        local f=files[name] -        if f then -          if type(f)=='string' then -            files[name]={ f,path } +        local lower=lower(name) +        local paths=files[lower] +        if paths then +          if onlyone then            else -            f[#f+1]=path +            if type(paths)=="string" then +              files[lower]={ paths,path } +            else +              paths[#paths+1]=path +            end +            if name~=lower then +              local rl=remap[lower] +              if not rl then +                remap[lower]=name +                r=r+1 +              elseif trace_globbing and rl~=name then +                report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) +              end +            end            end          else  -          files[name]=path -          local lower=lower(name) +          files[lower]=path            if name~=lower then -            files["remap:"..lower]=name -            r=r+1 +            local rl=remap[lower] +            if not rl then +              remap[lower]=name +              r=r+1 +            elseif trace_globbing and rl~=name then +              report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) +            end            end          end -      elseif mode=='directory' then +      elseif mode=="directory" then          m=m+1          nofdirs=nofdirs+1          if path~="" then -          dirs[nofdirs]=path..'/'..name +          dirs[nofdirs]=path.."/"..name          else            dirs[nofdirs]=name          end @@ -12883,107 +13083,52 @@ local function scan(files,spec,path,n,m,r)    if nofdirs>0 then      sort(dirs)      for i=1,nofdirs do -      files,n,m,r=scan(files,spec,dirs[i],n,m,r) +      files,remap,n,m,r=scan(files,remap,spec,dirs[i],n,m,r,onlyone)      end    end    scancache[sub(full,1,-2)]=files -  return files,n,m,r +  return files,remap,n,m,r  end -local fullcache={} -function resolvers.scanfiles(path,branch,usecache) -  statistics.starttiming(timer) -  local realpath=resolvers.resolve(path)  +function resolvers.scanfiles(path,branch,usecache,onlyonce) +  local realpath=resolveprefix(path)    if usecache then -    local files=fullcache[realpath] -    if files then +    local content=fullcache[realpath] +    if content then        if trace_locating then -        report_expansions("using caches scan of path %a, branch %a",path,branch or path) +        report_expansions("using cached scan of path %a, branch %a",path,branch or path)        end -      return files +      nofsharedscans=nofsharedscans+1 +      return content      end    end +  statistics.starttiming(timer)    if trace_locating then      report_expansions("scanning path %a, branch %a",path,branch or path)    end -  local files,n,m,r=scan({},realpath..'/',"",0,0,0) -  files.__path__=path  -  files.__files__=n -  files.__directories__=m -  files.__remappings__=r +  local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce) +  local content={ +    metadata={ +      path=path, +      files=n, +      directories=m, +      remappings=r, +    }, +    files=files, +    remap=remap, +  }    if trace_locating then      report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r)    end    if usecache then      scanned[#scanned+1]=realpath -    fullcache[realpath]=files +    fullcache[realpath]=content    end    nofscans=nofscans+1    statistics.stoptiming(timer) -  return files -end -local function simplescan(files,spec,path)  -  local full=(path=="" and spec) or (spec..path..'/') -  local dirs={} -  local nofdirs=0 -  for name in directory(full) do -    if not lpegmatch(weird,name) then -      local mode=attributes(full..name,'mode') -      if mode=='file' then -        if not files[name] then -          files[name]=path -        end -      elseif mode=='directory' then -        nofdirs=nofdirs+1 -        if path~="" then -          dirs[nofdirs]=path..'/'..name -        else -          dirs[nofdirs]=name -        end -      end -    end -  end -  if nofdirs>0 then -    sort(dirs) -    for i=1,nofdirs do -      files=simplescan(files,spec,dirs[i]) -    end -  end -  return files +  return content  end -local simplecache={} -local nofsharedscans=0  function resolvers.simplescanfiles(path,branch,usecache) -  statistics.starttiming(timer) -  local realpath=resolvers.resolve(path)  -  if usecache then -    local files=simplecache[realpath] -    if not files then -      files=scancache[realpath] -      if files then -        nofsharedscans=nofsharedscans+1 -      end -    end -    if files then -      if trace_locating then -        report_expansions("using caches scan of path %a, branch %a",path,branch or path) -      end -      return files -    end -  end -  if trace_locating then -    report_expansions("scanning path %a, branch %a",path,branch or path) -  end -  local files=simplescan({},realpath..'/',"") -  if trace_locating then -    report_expansions("%s files found",table.count(files)) -  end -  if usecache then -    scanned[#scanned+1]=realpath -    simplecache[realpath]=files -  end -  nofscans=nofscans+1 -  statistics.stoptiming(timer) -  return files +  return resolvers.scanfiles(path,branch,usecache,true)   end  function resolvers.scandata()    table.sort(scanned) @@ -12994,6 +13139,49 @@ function resolvers.scandata()      paths=scanned,    }  end +function resolvers.get_from_content(content,path,name)  +  local files=content.files +  if not files then +    return +  end +  local remap=content.remap +  if not remap then +    return +  end +  if name then +    local used=lower(name) +    return path,remap[used] or used +  else +    local name=path +    local used=lower(name) +    local path=files[used] +    if path then +      return path,remap[used] or used +    end +  end +end +local nothing=function() end +function resolvers.filtered_from_content(content,pattern) +  if content and type(pattern)=="string" then +    local pattern=lower(pattern) +    local files=content.files +    local remap=content.remap +    if files and remap then +      local n=next(files) +      local function iterator() +        while n do +          local k=n +          n=next(files,k) +          if find(k,pattern) then +            return files[k],remap and remap[k] or k +          end +        end +      end +      return iterator +    end +  end +  return nothing +end  end -- of closure @@ -13272,7 +13460,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-tmp"] = package.loaded["data-tmp"] or true --- original size: 15532, stripped down to: 11648 +-- original size: 15681, stripped down to: 11761  if not modules then modules={} end modules ['data-tmp']={    version=1.100, @@ -13291,6 +13479,7 @@ local trace_cache=false trackers.register("resolvers.cache",function(v) trace_ca  local report_caches=logs.reporter("resolvers","caches")  local report_resolvers=logs.reporter("resolvers","caching")  local resolvers=resolvers +local cleanpath=resolvers.cleanpath  local directive_cleanup=false directives.register("system.compile.cleanup",function(v) directive_cleanup=v end)  local directive_strip=false directives.register("system.compile.strip",function(v) directive_strip=v end)  local compile=utilities.lua.compile @@ -13312,7 +13501,7 @@ caches.relocate=false  caches.defaults={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" }  local writable,readables,usedreadables=nil,{},{}  local function identify() -  local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") +  local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE")     if texmfcaches then      for k=1,#texmfcaches do        local cachepath=texmfcaches[k] @@ -13566,10 +13755,12 @@ local content_state={}  function caches.contentstate()    return content_state or {}  end -function caches.loadcontent(cachename,dataname) -  local name=caches.hashed(cachename) -  local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") -  local filename=file.join(path,name) +function caches.loadcontent(cachename,dataname,filename) +  if not filename then +    local name=caches.hashed(cachename) +    local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") +    filename=file.join(path,name) +  end    local blob=loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua))    if blob then      local data=blob() @@ -13601,10 +13792,12 @@ function caches.collapsecontent(content)      end    end  end -function caches.savecontent(cachename,dataname,content) -  local name=caches.hashed(cachename) -  local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") -  local filename=file.join(path,name)  +function caches.savecontent(cachename,dataname,content,filename) +  if not filename then +    local name=caches.hashed(cachename) +    local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") +    filename=file.join(path,name)  +  end    local luaname=addsuffix(filename,luasuffixes.lua)    local lucname=addsuffix(filename,luasuffixes.luc)    if trace_locating then @@ -13647,7 +13840,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-met"] = package.loaded["data-met"] or true --- original size: 5460, stripped down to: 4014 +-- original size: 5347, stripped down to: 4015  if not modules then modules={} end modules ['data-met']={    version=1.100, @@ -13675,7 +13868,7 @@ local function splitmethod(filename)    if type(filename)=="table" then      return filename     end -  filename=file.collapsepath(filename,".") +  filename=file.collapsepath(filename,".")     if not find(filename,"://",1,true) then      return { scheme="file",path=filename,original=filename,filename=filename }    end @@ -13766,7 +13959,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-res"] = package.loaded["data-res"] or true --- original size: 62045, stripped down to: 43116 +-- original size: 61031, stripped down to: 42613  if not modules then modules={} end modules ['data-res']={    version=1.001, @@ -13776,7 +13969,7 @@ if not modules then modules={} end modules ['data-res']={    license="see context related readme files",  }  local gsub,find,lower,upper,match,gmatch=string.gsub,string.find,string.lower,string.upper,string.match,string.gmatch -local concat,insert,sortedkeys=table.concat,table.insert,table.sortedkeys +local concat,insert,sortedkeys,sortedhash=table.concat,table.insert,table.sortedkeys,table.sortedhash  local next,type,rawget=next,type,rawget  local os=os  local P,S,R,C,Cc,Cs,Ct,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cc,lpeg.Cs,lpeg.Ct,lpeg.Carg @@ -13785,14 +13978,19 @@ local formatters=string.formatters  local filedirname=file.dirname  local filebasename=file.basename  local suffixonly=file.suffixonly +local addsuffix=file.addsuffix +local removesuffix=file.removesuffix  local filejoin=file.join  local collapsepath=file.collapsepath  local joinpath=file.joinpath +local is_qualified_path=file.is_qualified_path  local allocate=utilities.storage.allocate  local settings_to_array=utilities.parsers.settings_to_array +local getcurrentdir=lfs.currentdir +local isfile=lfs.isfile +local isdir=lfs.isdir  local setmetatableindex=table.setmetatableindex  local luasuffixes=utilities.lua.suffixes -local getcurrentdir=lfs.currentdir  local trace_locating=false trackers .register("resolvers.locating",function(v) trace_locating=v end)  local trace_detail=false trackers .register("resolvers.details",function(v) trace_detail=v end)  local trace_expansions=false trackers .register("resolvers.expansions",function(v) trace_expansions=v end) @@ -13803,10 +14001,14 @@ local expandedpathfromlist=resolvers.expandedpathfromlist  local checkedvariable=resolvers.checkedvariable  local splitconfigurationpath=resolvers.splitconfigurationpath  local methodhandler=resolvers.methodhandler +local filtered=resolvers.filtered_from_content +local lookup=resolvers.get_from_content +local cleanpath=resolvers.cleanpath +local resolveprefix=resolvers.resolve  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' -resolvers.configbanner='' +resolvers.cacheversion="1.100" +resolvers.configbanner=""  resolvers.homedir=environment.homedir  resolvers.criticalvars=allocate { "SELFAUTOLOC","SELFAUTODIR","SELFAUTOPARENT","TEXMFCNF","TEXMF","TEXOS" }  resolvers.luacnfname="texmfcnf.lua" @@ -13833,7 +14035,7 @@ local   instance=resolvers.instance or nil  function resolvers.setenv(key,value,raw)    if instance then      instance.environment[key]=value -    ossetenv(key,raw and value or resolvers.resolve(value)) +    ossetenv(key,raw and value or resolveprefix(value))    end  end  local function getenv(key) @@ -13847,7 +14049,7 @@ local function getenv(key)  end  resolvers.getenv=getenv  resolvers.env=getenv -local function resolve(k) +local function resolvevariable(k)    return instance.expansions[k]  end  local dollarstripper=lpeg.stripper("$") @@ -13856,19 +14058,19 @@ local backslashswapper=lpeg.replacer("\\","/")  local somevariable=P("$")/""  local somekey=C(R("az","AZ","09","__","--")^1)  local somethingelse=P(";")*((1-S("!{}/\\"))^1*P(";")/"")+P(";")*(P(";")/"")+P(1) -local variableexpander=Cs((somevariable*(somekey/resolve)+somethingelse)^1 ) +local variableexpander=Cs((somevariable*(somekey/resolvevariable)+somethingelse)^1 )  local cleaner=P("\\")/"/"+P(";")*S("!{}/\\")^0*P(";")^1/";"  local variablecleaner=Cs((cleaner+P(1))^0) -local somevariable=R("az","AZ","09","__","--")^1/resolve +local somevariable=R("az","AZ","09","__","--")^1/resolvevariable  local variable=(P("$")/"")*(somevariable+(P("{")/"")*somevariable*(P("}")/""))  local variableresolver=Cs((variable+P(1))^0)  local function expandedvariable(var)    return lpegmatch(variableexpander,var) or var  end -function resolvers.newinstance()  -   if trace_locating then +function resolvers.newinstance() +  if trace_locating then      report_resolving("creating instance") -   end +  end    local environment,variables,expansions,order=allocate(),allocate(),allocate(),allocate()    local newinstance={      environment=environment, @@ -13995,13 +14197,13 @@ local function identify_configuration_files()      for i=1,#cnfpaths do        local filepath=cnfpaths[i]        local filename=collapsepath(filejoin(filepath,luacnfname)) -      local realname=resolvers.resolve(filename) +      local realname=resolveprefix(filename)        if trace_locating then -        local fullpath=gsub(resolvers.resolve(collapsepath(filepath)),"//","/") +        local fullpath=gsub(resolveprefix(collapsepath(filepath)),"//","/")          local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true)          report_resolving("looking for %a on %s path %a from specification %a",luacnfname,weirdpath and "weird" or "given",fullpath,filepath)        end -      if lfs.isfile(realname) then +      if isfile(realname) then          specification[#specification+1]=filename           if trace_locating then            report_resolving("found configuration file %a",realname) @@ -14023,7 +14225,7 @@ local function load_configuration_files()        local filename=specification[i]        local pathname=filedirname(filename)        local filename=filejoin(pathname,luacnfname) -      local realname=resolvers.resolve(filename)  +      local realname=resolveprefix(filename)         local blob=loadfile(realname)        if blob then          local setups=instance.setups @@ -14031,7 +14233,7 @@ local function load_configuration_files()          local parent=data and data.parent          if parent then            local filename=filejoin(pathname,parent) -          local realname=resolvers.resolve(filename)  +          local realname=resolveprefix(filename)             local blob=loadfile(realname)            if blob then              local parentdata=blob() @@ -14056,7 +14258,7 @@ local function load_configuration_files()              elseif variables[k]==nil then                if trace_locating and not warning then                  report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable", -                  k,resolvers.resolve(filename)) +                  k,resolveprefix(filename))                  warning=true                end                variables[k]=v @@ -14116,7 +14318,7 @@ local function locate_file_databases()        local stripped=lpegmatch(inhibitstripper,path)         if stripped~="" then          local runtime=stripped==path -        path=resolvers.cleanpath(path) +        path=cleanpath(path)          local spec=resolvers.splitmethod(stripped)          if runtime and (spec.noscheme or spec.scheme=="file") then            stripped="tree:///"..stripped @@ -14179,8 +14381,8 @@ function resolvers.renew(hashname)          report_resolving("identifying tree %a",hashname)        end      end -    local realpath=resolvers.resolve(hashname) -    if lfs.isdir(realpath) then +    local realpath=resolveprefix(hashname) +    if isdir(realpath) then        if trace_locating then          report_resolving("using path %a",realpath)        end @@ -14308,7 +14510,7 @@ function resolvers.registerextrapath(paths,subpaths)            local ps=p.."/"..s            if not done[ps] then              newn=newn+1 -            ep[newn]=resolvers.cleanpath(ps) +            ep[newn]=cleanpath(ps)              done[ps]=true            end          end @@ -14318,7 +14520,7 @@ function resolvers.registerextrapath(paths,subpaths)          local p=paths[i]          if not done[p] then            newn=newn+1 -          ep[newn]=resolvers.cleanpath(p) +          ep[newn]=cleanpath(p)            done[p]=true          end        end @@ -14330,7 +14532,7 @@ function resolvers.registerextrapath(paths,subpaths)          local ps=ep[i].."/"..s          if not done[ps] then            newn=newn+1 -          ep[newn]=resolvers.cleanpath(ps) +          ep[newn]=cleanpath(ps)            done[ps]=true          end        end @@ -14384,7 +14586,7 @@ function resolvers.cleanpathlist(str)    local t=resolvers.expandedpathlist(str)    if t then      for i=1,#t do -      t[i]=collapsepath(resolvers.cleanpath(t[i])) +      t[i]=collapsepath(cleanpath(t[i]))      end    end    return t @@ -14434,7 +14636,7 @@ function resolvers.registerfilehash(name,content,someerror)    end  end  local function isreadable(name) -  local readable=lfs.isfile(name)  +  local readable=isfile(name)     if trace_detail then      if readable then        report_resolving("file %a is readable",name) @@ -14445,69 +14647,56 @@ local function isreadable(name)    return readable  end  local function collect_files(names) -  local filelist,noffiles={},0 +  local filelist={} +  local noffiles=0 +  local function check(hash,root,pathname,path,name) +    if not pathname or find(path,pathname) then +      local variant=hash.type +      local search=filejoin(root,path,name)  +      local result=methodhandler('concatinators',variant,root,path,name) +      if trace_detail then +        report_resolving("match: variant %a, search %a, result %a",variant,search,result) +      end +      noffiles=noffiles+1 +      filelist[noffiles]={ variant,search,result } +    end +  end    for k=1,#names do -    local fname=names[k] +    local filename=names[k]      if trace_detail then -      report_resolving("checking name %a",fname) +      report_resolving("checking name %a",filename)      end -    local bname=filebasename(fname) -    local dname=filedirname(fname) -    if dname=="" or find(dname,"^%.") then -      dname=false +    local basename=filebasename(filename) +    local pathname=filedirname(filename) +    if pathname=="" or find(pathname,"^%.") then +      pathname=false      else -      dname=gsub(dname,"%*",".*") -      dname="/"..dname.."$" +      pathname=gsub(pathname,"%*",".*") +      pathname="/"..pathname.."$"      end      local hashes=instance.hashes      for h=1,#hashes do        local hash=hashes[h] -      local blobpath=hash.name -      local files=blobpath and instance.files[blobpath] -      if files then +      local hashname=hash.name +      local content=hashname and instance.files[hashname] +      if content then          if trace_detail then -          report_resolving("deep checking %a, base %a, pattern %a",blobpath,bname,dname) -        end -        local blobfile=files[bname] -        if not blobfile then -          local rname="remap:"..bname -          blobfile=files[rname] -          if blobfile then -            bname=files[rname] -            blobfile=files[bname] -          end +          report_resolving("deep checking %a, base %a, pattern %a",blobpath,basename,pathname)          end -        if blobfile then -          local blobroot=files.__path__ or blobpath -          if type(blobfile)=='string' then -            if not dname or find(blobfile,dname) then -              local variant=hash.type -              local search=filejoin(blobroot,blobfile,bname) -              local result=methodhandler('concatinators',hash.type,blobroot,blobfile,bname) -              if trace_detail then -                report_resolving("match: variant %a, search %a, result %a",variant,search,result) -              end -              noffiles=noffiles+1 -              filelist[noffiles]={ variant,search,result } -            end +        local path,name=lookup(content,basename) +        if path then +          local metadata=content.metadata +          local realroot=metadata and metadata.path or hashname +          if type(path)=="string" then +            check(hash,realroot,pathname,path,name)            else -            for kk=1,#blobfile do -              local vv=blobfile[kk] -              if not dname or find(vv,dname) then -                local variant=hash.type -                local search=filejoin(blobroot,vv,bname) -                local result=methodhandler('concatinators',hash.type,blobroot,vv,bname) -                if trace_detail then -                  report_resolving("match: variant %a, search %a, result %a",variant,search,result) -                end -                noffiles=noffiles+1 -                filelist[noffiles]={ variant,search,result } -              end +            for i=1,#path do +              check(hash,realroot,pathname,path[i],name)              end            end          end        elseif trace_locating then -        report_resolving("no match in %a (%s)",blobpath,bname) +        report_resolving("no match in %a (%s)",hashname,basename)        end      end    end @@ -14532,7 +14721,7 @@ end  local function can_be_dir(name)     local fakepaths=instance.fakepaths    if not fakepaths[name] then -    if lfs.isdir(name) then +    if isdir(name) then        fakepaths[name]=1       else        fakepaths[name]=2  @@ -14548,10 +14737,11 @@ local function find_analyze(filename,askedformat,allresults)    if askedformat=="" then      if ext=="" or not suffixmap[ext] then        local defaultsuffixes=resolvers.defaultsuffixes +      local formatofsuffix=resolvers.formatofsuffix        for i=1,#defaultsuffixes do          local forcedname=filename..'.'..defaultsuffixes[i]          wantedfiles[#wantedfiles+1]=forcedname -        filetype=resolvers.formatofsuffix(forcedname) +        filetype=formatofsuffix(forcedname)          if trace_locating then            report_resolving("forcing filetype %a",filetype)          end @@ -14591,14 +14781,14 @@ local function find_wildcard(filename,allresults)      if trace_locating then        report_resolving("checking wildcard %a",filename)      end -    local method,result=resolvers.findwildcardfiles(filename) +    local result=resolvers.findwildcardfiles(filename)      if result then        return "wildcard",result      end    end  end  local function find_qualified(filename,allresults,askedformat,alsostripped)  -  if not file.is_qualified_path(filename) then +  if not is_qualified_path(filename) then      return    end    if trace_locating then @@ -14687,7 +14877,6 @@ local function find_intree(filename,filetype,wantedfiles,allresults)      if trace_detail then        report_resolving("checking filename %a",filename)      end -    local resolve=resolvers.resolve      local result={}      for k=1,#pathlist do        local path=pathlist[k] @@ -14706,8 +14895,8 @@ local function find_intree(filename,filetype,wantedfiles,allresults)            local fl=filelist[k]            local f=fl[2]            local d=dirlist[k] -          if find(d,expression) or find(resolve(d),expression) then -            result[#result+1]=resolve(fl[3])  +          if find(d,expression) or find(resolveprefix(d),expression) then +            result[#result+1]=resolveprefix(fl[3])               done=true              if allresults then                if trace_detail then @@ -14729,7 +14918,7 @@ local function find_intree(filename,filetype,wantedfiles,allresults)        else          method="filesystem"           pathname=gsub(pathname,"/+$","") -        pathname=resolve(pathname) +        pathname=resolveprefix(pathname)          local scheme=url.hasscheme(pathname)          if not scheme or scheme=="file" then            local pname=gsub(pathname,"%.%*$",'') @@ -14819,7 +15008,7 @@ local function find_otherwise(filename,filetype,wantedfiles,allresults)    local filelist=collect_files(wantedfiles)    local fl=filelist and filelist[1]    if fl then -    return "otherwise",{ resolvers.resolve(fl[3]) }  +    return "otherwise",{ resolveprefix(fl[3]) }     end  end  collect_instance_files=function(filename,askedformat,allresults)  @@ -14919,39 +15108,30 @@ function resolvers.findpath(filename,filetype)    return filedirname(findfiles(filename,filetype,false)[1] or "")  end  local function findgivenfiles(filename,allresults) -  local bname,result=filebasename(filename),{} +  local base=filebasename(filename) +  local result={}    local hashes=instance.hashes -  local noffound=0 +  local function okay(hash,path,name) +    local found=methodhandler('concatinators',hash.type,hash.name,path,name) +    if found and found~="" then +      result[#result+1]=resolveprefix(found) +      return not allresults +    end +  end    for k=1,#hashes do      local hash=hashes[k] -    local files=instance.files[hash.name] or {} -    local blist=files[bname] -    if not blist then -      local rname="remap:"..bname -      blist=files[rname] -      if blist then -        bname=files[rname] -        blist=files[bname] -      end -    end -    if blist then -      if type(blist)=='string' then -        local found=methodhandler('concatinators',hash.type,hash.name,blist,bname) or "" -        if found~="" then -          noffound=noffound+1 -          result[noffound]=resolvers.resolve(found) -          if not allresults then -            break -          end +    local content=instance.files[hash.name] +    if content then +      local path,name=lookup(content,base) +      if not path then +      elseif type(path)=="string" then +        if okay(hash,path,name) then +          return result          end        else -        for kk=1,#blist do -          local vv=blist[kk] -          local found=methodhandler('concatinators',hash.type,hash.name,vv,bname) or "" -          if found~="" then -            noffound=noffound+1 -            result[noffound]=resolvers.resolve(found) -            if not allresults then break end +        for i=1,#path do +          if okay(hash,path[i],name) then +            return result            end          end        end @@ -14965,64 +15145,80 @@ end  function resolvers.findgivenfile(filename)    return findgivenfiles(filename,false)[1] or ""  end -local function doit(path,blist,bname,tag,variant,result,allresults) -  local done=false -  if blist and variant then -    local resolve=resolvers.resolve  -    if type(blist)=='string' then -      if find(lower(blist),path) then -        local full=methodhandler('concatinators',variant,tag,blist,bname) or "" -        result[#result+1]=resolve(full) -        done=true -      end -    else -      for kk=1,#blist do -        local vv=blist[kk] -        if find(lower(vv),path) then -          local full=methodhandler('concatinators',variant,tag,vv,bname) or "" -          result[#result+1]=resolve(full) -          done=true -          if not allresults then break end -        end -      end -    end -  end -  return done -end  local makewildcard=Cs(    (P("^")^0*P("/")*P(-1)+P(-1))/".*"+(P("^")^0*P("/")/"")^0*(P("*")/".*"+P("-")/"%%-"+P(".")/"%%."+P("?")/"."+P("\\")/"/"+P(1))^0  )  function resolvers.wildcardpattern(pattern)    return lpegmatch(makewildcard,pattern) or pattern  end -local function findwildcardfiles(filename,allresults,result)  -  result=result or {} +local function findwildcardfiles(filename,allresults,result) +  local result=result or {}    local base=filebasename(filename)    local dirn=filedirname(filename)    local path=lower(lpegmatch(makewildcard,dirn) or dirn)    local name=lower(lpegmatch(makewildcard,base) or base) -  local files,done=instance.files,false +  local files=instance.files    if find(name,"*",1,true) then      local hashes=instance.hashes +    local function okay(found,path,base,hashname,hashtype) +      if find(found,path) then +        local full=methodhandler('concatinators',hashtype,hashname,found,base) +        if full and full~="" then +          result[#result+1]=resolveprefix(full) +          return not allresults +        end +      end +    end      for k=1,#hashes do        local hash=hashes[k] -      local hashname,hashtype=hash.name,hash.type -      for kk,hh in next,files[hashname] do -        if not find(kk,"^remap:") then -          if find(lower(kk),name) then -            if doit(path,hh,kk,hashname,hashtype,result,allresults) then done=true end -            if done and not allresults then break end +      local hashname=hash.name +      local hashtype=hash.type +      if hashname and hashtype then +        for found,base in filtered(files[hashname],name) do +          if type(found)=='string' then +            if okay(found,path,base,hashname,hashtype) then +              break +            end +          else +            for i=1,#found do +              if okay(found[i],path,base,hashname,hashtype) then +                break +              end +            end            end          end        end      end    else +    local function okayokay(found,path,base,hashname,hashtype) +      if find(found,path) then +        local full=methodhandler('concatinators',hashtype,hashname,found,base) +        if full and full~="" then +          result[#result+1]=resolveprefix(full) +          return not allresults +        end +      end +    end      local hashes=instance.hashes      for k=1,#hashes do        local hash=hashes[k] -      local hashname,hashtype=hash.name,hash.type -      if doit(path,files[hashname][base],base,hashname,hashtype,result,allresults) then done=true end -      if done and not allresults then break end +      local hashname=hash.name +      local hashtype=hash.type +      if hashname and hashtype then +        local found,base=lookup(content,base) +        if not found then +        elseif type(found)=='string' then +          if okay(found,path,base,hashname,hashtype) then +            break +          end +        else +          for i=1,#found do +            if okay(found[i],path,base,hashname,hashtype) then +              break +            end +          end +        end +      end      end    end    return result @@ -15095,7 +15291,7 @@ end  function resolvers.dowithpath(name,func)    local pathlist=resolvers.expandedpathlist(name)    for i=1,#pathlist do -    func("^"..resolvers.cleanpath(pathlist[i])) +    func("^"..cleanpath(pathlist[i]))    end  end  function resolvers.dowithvariable(name,func) @@ -15103,23 +15299,23 @@ function resolvers.dowithvariable(name,func)  end  function resolvers.locateformat(name)    local engine=environment.ownmain or "luatex" -  local barename=file.removesuffix(name) -  local fullname=file.addsuffix(barename,"fmt") +  local barename=removesuffix(name) +  local fullname=addsuffix(barename,"fmt")    local fmtname=caches.getfirstreadablefile(fullname,"formats",engine) or ""    if fmtname=="" then      fmtname=resolvers.findfile(fullname) -    fmtname=resolvers.cleanpath(fmtname) +    fmtname=cleanpath(fmtname)    end    if fmtname~="" then -    local barename=file.removesuffix(fmtname) -    local luaname=file.addsuffix(barename,luasuffixes.lua) -    local lucname=file.addsuffix(barename,luasuffixes.luc) -    local luiname=file.addsuffix(barename,luasuffixes.lui) -    if lfs.isfile(luiname) then +    local barename=removesuffix(fmtname) +    local luaname=addsuffix(barename,luasuffixes.lua) +    local lucname=addsuffix(barename,luasuffixes.luc) +    local luiname=addsuffix(barename,luasuffixes.lui) +    if isfile(luiname) then        return barename,luiname -    elseif lfs.isfile(lucname) then +    elseif isfile(lucname) then        return barename,lucname -    elseif lfs.isfile(luaname) then +    elseif isfile(luaname) then        return barename,luaname      end    end @@ -15141,29 +15337,24 @@ function resolvers.dowithfilesintree(pattern,handle,before,after)      local hash=hashes[i]      local blobtype=hash.type      local blobpath=hash.name -    if blobpath then +    if blobtype and blobpath then +      local total=0 +      local checked=0 +      local done=0        if before then          before(blobtype,blobpath,pattern)        end -      local files=instance.files[blobpath] -      local total,checked,done=0,0,0 -      if files then -        for k,v in table.sortedhash(files) do  -          total=total+1 -          if find(k,"^remap:") then -          elseif find(k,pattern) then -            if type(v)=="string" then -              checked=checked+1 -              if handle(blobtype,blobpath,v,k) then -                done=done+1 -              end -            else -              checked=checked+#v -              for i=1,#v do -                if handle(blobtype,blobpath,v[i],k) then -                  done=done+1 -                end -              end +      for path,name in filtered(instance.files[blobpath],pattern) do +        if type(path)=="string" then +          checked=checked+1 +          if handle(blobtype,blobpath,path,name) then +            done=done+1 +          end +        else +          checked=checked+#path +          for i=1,#path do +            if handle(blobtype,blobpath,path[i],name) then +              done=done+1              end            end          end @@ -15174,8 +15365,8 @@ function resolvers.dowithfilesintree(pattern,handle,before,after)      end    end  end -resolvers.obsolete=resolvers.obsolete or {} -local obsolete=resolvers.obsolete +local obsolete=resolvers.obsolete or {} +resolvers.obsolete=obsolete  resolvers.find_file=resolvers.findfile  obsolete.find_file=resolvers.findfile  resolvers.find_files=resolvers.findfiles  obsolete.find_files=resolvers.findfiles @@ -15186,7 +15377,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-pre"] = package.loaded["data-pre"] or true --- original size: 6643, stripped down to: 4401 +-- original size: 3106, stripped down to: 2563  if not modules then modules={} end modules ['data-pre']={    version=1.001, @@ -15196,44 +15387,51 @@ if not modules then modules={} end modules ['data-pre']={    license="see context related readme files"  }  local resolvers=resolvers -local prefixes=utilities.storage.allocate() -resolvers.prefixes=prefixes -local cleanpath,findgivenfile,expansion=resolvers.cleanpath,resolvers.findgivenfile,resolvers.expansion +local prefixes=resolvers.prefixes +local cleanpath=resolvers.cleanpath +local findgivenfile=resolvers.findgivenfile +local expansion=resolvers.expansion  local getenv=resolvers.getenv  -local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match -local joinpath,basename,dirname=file.join,file.basename,file.dirname -local getmetatable,rawset,type=getmetatable,rawset,type +local basename=file.basename +local dirname=file.dirname +local joinpath=file.join +local isfile=lfs.isfile  prefixes.environment=function(str)    return cleanpath(expansion(str))  end -prefixes.relative=function(str,n)  -  if io.exists(str) then -  elseif io.exists("./"..str) then -    str="./"..str -  else -    local p="../" -    for i=1,n or 2 do -      if io.exists(p..str) then -        str=p..str -        break -      else -        p=p.."../" +local function relative(str,n) +  if not isfile(str) then +    local pstr="./"..str +    if isfile(pstr) then +      str=pstr +    else +      local p="../" +      for i=1,n or 2 do +        local pstr=p..str +        if isfile(pstr) then +          str=pstr +          break +        else +          p=p.."../" +        end        end      end    end    return cleanpath(str)  end +local function locate(str) +  local fullname=findgivenfile(str) or "" +  return cleanpath(fullname~="" and fullname or str) +end +prefixes.relative=relative +prefixes.locate=locate  prefixes.auto=function(str) -  local fullname=prefixes.relative(str) -  if not lfs.isfile(fullname) then -    fullname=prefixes.locate(str) +  local fullname=relative(str) +  if not isfile(fullname) then +    fullname=locate(str)    end    return fullname  end -prefixes.locate=function(str) -  local fullname=findgivenfile(str) or "" -  return cleanpath((fullname~="" and fullname) or str) -end  prefixes.filename=function(str)    local fullname=findgivenfile(str) or ""    return cleanpath(basename((fullname~="" and fullname) or str))  @@ -15277,87 +15475,6 @@ prefixes.kpse=prefixes.locate  prefixes.full=prefixes.locate  prefixes.file=prefixes.filename  prefixes.path=prefixes.pathname -function resolvers.allprefixes(separator) -  local all=table.sortedkeys(prefixes) -  if separator then -    for i=1,#all do -      all[i]=all[i]..":" -    end -  end -  return all -end -local function _resolve_(method,target) -  local action=prefixes[method] -  if action then -    return action(target) -  else -    return method..":"..target -  end -end -local resolved,abstract={},{} -function resolvers.resetresolve(str) -  resolved,abstract={},{} -end -local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) -local prefix=C(R("az")^2)*P(":") -local target=C((1-S(" \"\';,"))^1) -local notarget=(#S(";,")+P(-1))*Cc("") -local pattern=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) -local function resolve(str)  -  if type(str)=="table" then -    local t={} -    for i=1,#str do -      t[i]=resolve(str[i]) -    end -    return t -  else -    local res=resolved[str] -    if not res then -      res=lpegmatch(pattern,str) -      resolved[str]=res -      abstract[res]=str -    end -    return res -  end -end -local function unresolve(str) -  return abstract[str] or str -end -resolvers.resolve=resolve -resolvers.unresolve=unresolve -if type(os.uname)=="function" then -  for k,v in next,os.uname() do -    if not prefixes[k] then -      prefixes[k]=function() return v end -    end -  end -end -if os.type=="unix" then -  local pattern -  local function makepattern(t,k,v) -    if t then -      rawset(t,k,v) -    end -    local colon=P(":") -    for k,v in table.sortedpairs(prefixes) do -      if p then -        p=P(k)+p -      else -        p=P(k) -      end -    end -    pattern=Cs((p*colon+colon/";"+P(1))^0) -  end -  makepattern() -  getmetatable(prefixes).__newindex=makepattern -  function resolvers.repath(str) -    return lpegmatch(pattern,str) -  end -else  -  function resolvers.repath(str) -    return str -  end -end  end -- of closure @@ -15419,7 +15536,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-fil"] = package.loaded["data-fil"] or true --- original size: 3801, stripped down to: 3231 +-- original size: 3863, stripped down to: 3310  if not modules then modules={} end modules ['data-fil']={    version=1.001, @@ -15431,30 +15548,31 @@ if not modules then modules={} end modules ['data-fil']={  local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end)  local report_files=logs.reporter("resolvers","files")  local resolvers=resolvers +local resolveprefix=resolvers.resolve  local finders,openers,loaders,savers=resolvers.finders,resolvers.openers,resolvers.loaders,resolvers.savers  local locators,hashers,generators,concatinators=resolvers.locators,resolvers.hashers,resolvers.generators,resolvers.concatinators  local checkgarbage=utilities.garbagecollector and utilities.garbagecollector.check  function locators.file(specification) -  local name=specification.filename -  local realname=resolvers.resolve(name)  +  local filename=specification.filename +  local realname=resolveprefix(filename)     if realname and realname~='' and lfs.isdir(realname) then      if trace_locating then -      report_files("file locator %a found as %a",name,realname) +      report_files("file locator %a found as %a",filename,realname)      end -    resolvers.appendhash('file',name,true)  +    resolvers.appendhash('file',filename,true)     elseif trace_locating then -    report_files("file locator %a not found",name) +    report_files("file locator %a not found",filename)    end  end  function hashers.file(specification) -  local name=specification.filename -  local content=caches.loadcontent(name,'files') -  resolvers.registerfilehash(name,content,content==nil) +  local pathname=specification.filename +  local content=caches.loadcontent(pathname,'files') +  resolvers.registerfilehash(pathname,content,content==nil)  end  function generators.file(specification) -  local path=specification.filename -  local content=resolvers.scanfiles(path,false,true) -  resolvers.registerfilehash(path,content,true) +  local pathname=specification.filename +  local content=resolvers.scanfiles(pathname,false,true)  +  resolvers.registerfilehash(pathname,content,true)  end  concatinators.file=file.join  function finders.file(specification,filetype) @@ -15736,7 +15854,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-zip"] = package.loaded["data-zip"] or true --- original size: 8489, stripped down to: 6757 +-- original size: 9043, stripped down to: 7073  if not modules then modules={} end modules ['data-zip']={    version=1.001, @@ -15779,7 +15897,7 @@ function zip.openarchive(name)      local arch=archives[name]      if not arch then        local full=resolvers.findfile(name) or "" -      arch=(full~="" and zip.open(full)) or false +      arch=full~="" and zip.open(full) or false        archives[name]=arch      end      return arch @@ -15938,31 +16056,42 @@ function resolvers.usezipfile(archive)    end  end  function resolvers.registerzipfile(z,tree) -  local files,filter={},"" -  if tree=="" then -    filter="^(.+)/(.-)$" -  else -    filter=format("^%s/(.+)/(.-)$",tree) -  end +  local names={} +  local files={}  +  local remap={}  +  local n=0 +  local filter=tree=="" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) +  local register=resolvers.registerfile    if trace_locating then      report_zip("registering: using filter %a",filter)    end -  local register,n=resolvers.registerfile,0    for i in z:files() do -    local path,name=match(i.filename,filter) -    if path then -      if name and name~='' then -        register(files,name,path) -        n=n+1 -      else +    local filename=i.filename +    local path,name=match(filename,filter) +    if not path then +      n=n+1 +      register(names,filename,"") +      local usedname=lower(filename) +      files[usedname]="" +      if usedname~=filename then +        remap[usedname]=filename        end -    else -      register(files,i.filename,'') +    elseif name and name~="" then        n=n+1 +      register(names,name,path) +      local usedname=lower(name) +      files[usedname]=path +      if usedname~=name then +        remap[usedname]=name +      end +    else      end    end    report_zip("registering: %s files registered",n) -  return files +  return { +    files=files, +    remap=remap, +  }  end @@ -15972,7 +16101,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-tre"] = package.loaded["data-tre"] or true --- original size: 2508, stripped down to: 2074 +-- original size: 4859, stripped down to: 3335  if not modules then modules={} end modules ['data-tre']={    version=1.001, @@ -15981,42 +16110,50 @@ if not modules then modules={} end modules ['data-tre']={    copyright="PRAGMA ADE / ConTeXt Development Team",    license="see context related readme files"  } -local find,gsub,format=string.find,string.gsub,string.format +local find,gsub,lower=string.find,string.gsub,string.lower +local basename,dirname,joinname=file.basename,file.dirname,file  .join +local globdir,isdir=dir.glob,lfs.isdir  local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end)  local report_trees=logs.reporter("resolvers","trees")  local resolvers=resolvers -local done,found,notfound={},{},resolvers.finders.notfound -function resolvers.finders.tree(specification) +local resolveprefix=resolvers.resolve +local notfound=resolvers.finders.notfound +local collectors={} +local found={} +function resolvers.finders.tree(specification)     local spec=specification.filename -  local fnd=found[spec] -  if fnd==nil then +  local okay=found[spec] +  if okay==nil then      if spec~="" then -      local path,name=file.dirname(spec),file.basename(spec) -      if path=="" then path="." end -      local hash=done[path] -      if not hash then -        local pattern=path.."/*"  -        hash=dir.glob(pattern) -        done[path]=hash +      local path=dirname(spec) +      local name=basename(spec) +      if path=="" then +        path="." +      end +      local names=collectors[path] +      if not names then +        local pattern=find(path,"/%*+$") and path or (path.."/*") +        names=globdir(pattern) +        collectors[path]=names        end        local pattern="/"..gsub(name,"([%.%-%+])","%%%1").."$" -      for k=1,#hash do -        local v=hash[k] -        if find(v,pattern) then -          found[spec]=v -          return v +      for i=1,#names do +        local fullname=names[i] +        if find(fullname,pattern) then +          found[spec]=fullname +          return fullname          end        end      end -    fnd=notfound()  -    found[spec]=fnd +    okay=notfound()  +    found[spec]=okay    end -  return fnd +  return okay  end  function resolvers.locators.tree(specification)    local name=specification.filename -  local realname=resolvers.resolve(name)  -  if realname and realname~='' and lfs.isdir(realname) then +  local realname=resolveprefix(name)  +  if realname and realname~='' and isdir(realname) then      if trace_locating then        report_trees("locator %a found",realname)      end @@ -16033,10 +16170,43 @@ function resolvers.hashers.tree(specification)    resolvers.methodhandler("hashers",name)    resolvers.generators.file(specification)  end -resolvers.concatinators.tree=resolvers.concatinators.file -resolvers.generators.tree=resolvers.generators.file -resolvers.openers.tree=resolvers.openers.file -resolvers.loaders.tree=resolvers.loaders.file +local collectors={} +table.setmetatableindex(collectors,function(t,k) +  local rootname=gsub(k,"[/%*]+$","") +  local dataname=joinname(rootname,"dirlist") +  local data=caches.loadcontent(dataname,"files",dataname) +  local content=data and data.content +  local lookup=resolvers.get_from_content +  if not content then +    content=resolvers.scanfiles(rootname) +    caches.savecontent(dataname,"files",content,dataname) +  end +  local files=content.files +  local v=function(filename) +    local path,name=lookup(content,filename) +    if not path then +      return filename +    elseif type(path)=="table" then +      path=path[1] +    end +    return joinname(rootname,path,name) +  end +  t[k]=v +  return v +end) +function resolvers.finders.dirlist(specification)  +  local spec=specification.filename +  if spec~="" then +    local path,name=dirname(spec),basename(spec) +    return path and collectors[path](name) or notfound() +  end +  return notfound() +end +resolvers.locators .dirlist=resolvers.locators .tree +resolvers.hashers  .dirlist=resolvers.hashers  .tree +resolvers.generators.dirlist=resolvers.generators.file +resolvers.openers  .dirlist=resolvers.openers  .file +resolvers.loaders  .dirlist=resolvers.loaders  .file  end -- of closure @@ -16221,7 +16391,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-lua"] = package.loaded["data-lua"] or true --- original size: 4237, stripped down to: 3177 +-- original size: 4313, stripped down to: 3227  if not modules then modules={} end modules ['data-lua']={    version=1.001, @@ -16230,7 +16400,7 @@ if not modules then modules={} end modules ['data-lua']={    copyright="PRAGMA ADE / ConTeXt Development Team",    license="see context related readme files"  } -local resolvers,package=resolvers,package +local package,lpeg=package,lpeg  local gsub=string.gsub  local concat=table.concat  local addsuffix=file.addsuffix @@ -16241,9 +16411,11 @@ local luaformats={ 'TEXINPUTS','LUAINPUTS' }  local libformats={ 'CLUAINPUTS' }  local helpers=package.helpers or {}  local methods=helpers.methods or {} +local resolvers=resolvers +local resolveprefix=resolvers.resolve +helpers.report=logs.reporter("resolvers","libraries")  trackers.register("resolvers.libraries",function(v) helpers.trace=v end)  trackers.register("resolvers.locating",function(v) helpers.trace=v end) -helpers.report=logs.reporter("resolvers","libraries")  helpers.sequence={    "already loaded",    "preload table", @@ -16258,7 +16430,7 @@ helpers.sequence={  }  local pattern=Cs(P("!")^0/""*(P("/")*P(-1)/"/"+P("/")^1/"/"+1)^0)  function helpers.cleanpath(path)  -  return resolvers.resolve(lpegmatch(pattern,path)) +  return resolveprefix(lpegmatch(pattern,path))  end  local loadedaslib=helpers.loadedaslib  local getextraluapaths=package.extraluapaths @@ -16395,7 +16567,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-tmf"] = package.loaded["data-tmf"] or true --- original size: 2600, stripped down to: 1627 +-- original size: 2601, stripped down to: 1627  if not modules then modules={} end modules ['data-tmf']={    version=1.001, @@ -16451,7 +16623,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-lst"] = package.loaded["data-lst"] or true --- original size: 2654, stripped down to: 2301 +-- original size: 2734, stripped down to: 2354  if not modules then modules={} end modules ['data-lst']={    version=1.001, @@ -16460,10 +16632,13 @@ if not modules then modules={} end modules ['data-lst']={    copyright="PRAGMA ADE / ConTeXt Development Team",    license="see context related readme files"  } -local find,concat,upper,format=string.find,table.concat,string.upper,string.format +local rawget,type,next=rawget,type,next +local find,concat,upper=string.find,table.concat,string.upper  local fastcopy,sortedpairs=table.fastcopy,table.sortedpairs -resolvers.listers=resolvers.listers or {}  local resolvers=resolvers +local listers=resolvers.listers or {} +resolvers.listers=listers +local resolveprefix=resolvers.resolve  local report_lists=logs.reporter("resolvers","lists")  local function tabstr(str)    if type(str)=='table' then @@ -16472,7 +16647,7 @@ local function tabstr(str)      return str    end  end -function resolvers.listers.variables(pattern) +function listers.variables(pattern)    local instance=resolvers.instance    local environment=instance.environment    local variables=instance.variables @@ -16493,10 +16668,10 @@ function resolvers.listers.variables(pattern)    for key,value in sortedpairs(configured) do      if key~="" and (pattern=="" or find(upper(key),pattern)) then        report_lists(key) -      report_lists("  env: %s",tabstr(rawget(environment,key))  or "unset") -      report_lists("  var: %s",tabstr(configured[key])      or "unset") -      report_lists("  exp: %s",tabstr(expansions[key])      or "unset") -      report_lists("  res: %s",tabstr(resolvers.resolve(expansions[key])) or "unset") +      report_lists("  env: %s",tabstr(rawget(environment,key))    or "unset") +      report_lists("  var: %s",tabstr(configured[key])        or "unset") +      report_lists("  exp: %s",tabstr(expansions[key])        or "unset") +      report_lists("  res: %s",tabstr(resolveprefix(expansions[key])) or "unset")      end    end    instance.environment=fastcopy(env) @@ -16504,15 +16679,15 @@ function resolvers.listers.variables(pattern)    instance.expansions=fastcopy(exp)  end  local report_resolved=logs.reporter("system","resolved") -function resolvers.listers.configurations() +function listers.configurations()    local configurations=resolvers.instance.specification    for i=1,#configurations do -    report_resolved("file : %s",resolvers.resolve(configurations[i])) +    report_resolved("file : %s",resolveprefix(configurations[i]))    end    report_resolved("")    local list=resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec))    for i=1,#list do -    local li=resolvers.resolve(list[i]) +    local li=resolveprefix(list[i])      if lfs.isdir(li) then        report_resolved("path - %s",li)      else @@ -16951,8 +17126,8 @@ end -- of closure  -- used libraries    : l-lua.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-sto.lua util-prs.lua util-fmt.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-mrg.lua util-tpl.lua util-env.lua luat-env.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua util-lib.lua luat-sta.lua luat-fmt.lua  -- skipped libraries : - --- original bytes    : 699655 --- stripped bytes    : 249540 +-- original bytes    : 704727 +-- stripped bytes    : 250243  -- end library merge diff --git a/scripts/context/stubs/win64/mtxrun.lua b/scripts/context/stubs/win64/mtxrun.lua index 189fc4b7b..70f493525 100644 --- a/scripts/context/stubs/win64/mtxrun.lua +++ b/scripts/context/stubs/win64/mtxrun.lua @@ -1195,7 +1195,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["l-table"] = package.loaded["l-table"] or true --- original size: 31828, stripped down to: 20814 +-- original size: 33243, stripped down to: 21578  if not modules then modules={} end modules ['l-table']={    version=1.001, @@ -1342,14 +1342,14 @@ local function sortedhash(t,cmp)      end      local n=0      local m=#s -    local function kv(s) +    local function kv()         if n<m then          n=n+1          local k=s[n]          return k,t[k]        end      end -    return kv,s +    return kv     else      return nothing    end @@ -2110,6 +2110,44 @@ function table.values(t,s)      return {}    end  end +function table.filtered(t,pattern,sort,cmp) +  if t and type(pattern)=="string" then +    if sort then +      local s +      if cmp then +        s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) +      else +        s=sortedkeys(t)  +      end +      local n=0 +      local m=#s +      local function kv(s) +        while n<m do +          n=n+1 +          local k=s[n] +          if find(k,pattern) then +            return k,t[k] +          end +        end +      end +      return kv,s +    else +      local n=next(t) +      local function iterator() +        while n do +          local k=n +          n=next(t,k) +          if find(k,pattern) then +            return k,t[k] +          end +        end +      end +      return iterator,t +    end +  else +    return nothing +  end +end  end -- of closure @@ -3775,7 +3813,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["l-dir"] = package.loaded["l-dir"] or true --- original size: 14788, stripped down to: 9096 +-- original size: 16056, stripped down to: 10707  if not modules then modules={} end modules ['l-dir']={    version=1.001, @@ -3785,7 +3823,7 @@ if not modules then modules={} end modules ['l-dir']={    license="see context related readme files"  }  local type,select=type,select -local find,gmatch,match,gsub=string.find,string.gmatch,string.match,string.gsub +local find,gmatch,match,gsub,sub=string.find,string.gmatch,string.match,string.gsub,string.sub  local concat,insert,remove,unpack=table.concat,table.insert,table.remove,table.unpack  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 @@ -3794,54 +3832,123 @@ local dir=dir  local lfs=lfs  local attributes=lfs.attributes  local walkdir=lfs.dir -local isdir=lfs.isdir -local isfile=lfs.isfile +local isdir=lfs.isdir  +local isfile=lfs.isfile   local currentdir=lfs.currentdir  local chdir=lfs.chdir  local mkdir=lfs.mkdir  local onwindows=os.type=="windows" or find(os.getenv("PATH"),";",1,true) -if not isdir then -  function isdir(name) -    local a=attributes(name) -    return a and a.mode=="directory" +if onwindows then +  isdir=function(name) +    name=gsub(name,"([/\\]+)$","/.") +    return attributes(name,"mode")=="directory" +  end +  isfile=function(name) +    return attributes(name,"mode")=="file"    end    lfs.isdir=isdir -end -if not isfile then -  function isfile(name) -    local a=attributes(name) -    return a and a.mode=="file" +  lfs.isfile=isfile +else +  isdir=function(name) +    return attributes(name,"mode")=="directory" +  end +  isfile=function(name) +    return attributes(name,"mode")=="file"    end +  lfs.isdir=isdir    lfs.isfile=isfile  end  function dir.current()    return (gsub(currentdir(),"\\","/"))  end -local lfsisdir=isdir -local function isdir(path) -  path=gsub(path,"[/\\]+$","") -  return lfsisdir(path) +local function glob_pattern_function(path,patt,recurse,action) +  if isdir(path) then +    local usedpath +    if path=="/" then +      usedpath="/." +    elseif not find(path,"/$") then +      usedpath=path.."/." +      path=path.."/" +    else +      usedpath=path +    end +    local dirs +    for name in walkdir(usedpath) do +      if name~="." and name~=".." then +        local full=path..name +        local mode=attributes(full,'mode') +        if mode=='file' then +          if not patt or find(full,patt) then +            action(full) +          end +        elseif recurse and mode=="directory" then +          if not dirs then +            dirs={ full } +          else +            dirs[#dirs+1]=full +          end +        end +      end +    end +    if dirs then +      for i=1,#dirs do +        glob_pattern_function(dirs[i],patt,recurse,action) +      end +    end +  end  end -lfs.isdir=isdir -local function globpattern(path,patt,recurse,action) -  if path=="/" then -    path=path.."." -  elseif not find(path,"/$") then -    path=path..'/' -  end -  if isdir(path) then  -    for name in walkdir(path) do  -      local full=path..name -      local mode=attributes(full,'mode') -      if mode=='file' then -        if find(full,patt) then -          action(full) +local function glob_pattern_table(path,patt,recurse,result) +  if not result then +    result={} +  end +  if isdir(path) then +    local usedpath +    if path=="/" then +      usedpath="/." +    elseif not find(path,"/$") then +      usedpath=path.."/." +      path=path.."/" +    else +      usedpath=path +    end +    local dirs +    for name in walkdir(usedpath) do +      if name~="." and name~=".." then +        local full=path..name +        local mode=attributes(full,'mode') +        if mode=='file' then +          if not patt or find(full,patt) then +            result[#result+1]=full +          end +        elseif recurse and mode=="directory" then +          if not dirs then +            dirs={ full } +          else +            dirs[#dirs+1]=full +          end          end -      elseif recurse and (mode=="directory") and (name~='.') and (name~="..") then -        globpattern(full,patt,recurse,action) +      end +    end +    if dirs then +      for i=1,#dirs do +        glob_pattern_table(dirs[i],patt,recurse,result)        end      end    end +  return result +end +local function globpattern(path,patt,recurse,method) +  local kind=type(method) +  if pattern and sub(patt,1,-3)==path then +    patt=false +  end +  if kind=="function" then +    return glob_pattern_function(path,patt,recurse,method) +  elseif kind=="table" then +    return glob_pattern_table(path,patt,recurse,method) +  else +    return glob_pattern_table(path,patt,recurse,{}) +  end  end  dir.globpattern=globpattern  local function collectpattern(path,patt,recurse,result) @@ -3853,18 +3960,24 @@ local function collectpattern(path,patt,recurse,result)      ok,scanner,first=xpcall(function() return walkdir(path)   end,function() end)     end    if ok and type(scanner)=="function" then -    if not find(path,"/$") then path=path..'/' end +    if not find(path,"/$") then +      path=path..'/' +    end      for name in scanner,first do -      local full=path..name -      local attr=attributes(full) -      local mode=attr.mode -      if mode=='file' then -        if find(full,patt) then +      if name=="." then +      elseif name==".." then +      else +        local full=path..name +        local attr=attributes(full) +        local mode=attr.mode +        if mode=='file' then +          if find(full,patt) then +            result[name]=attr +          end +        elseif recurse and mode=="directory" then +          attr.list=collectpattern(full,patt,recurse)            result[name]=attr          end -      elseif recurse and (mode=="directory") and (name~='.') and (name~="..") then -        attr.list=collectpattern(full,patt,recurse) -        result[name]=attr        end      end    end @@ -3872,15 +3985,15 @@ local function collectpattern(path,patt,recurse,result)  end  dir.collectpattern=collectpattern  local separator -if onwindows then +if onwindows then     local slash=S("/\\")/"/" -  pattern=Ct { +  pattern={      [1]=(Cs(P(".")+slash^1)+Cs(R("az","AZ")*P(":")*slash^0)+Cc("./"))*V(2)*V(3),      [2]=Cs(((1-S("*?/\\"))^0*slash)^0),      [3]=Cs(P(1)^0)    } -else  -  pattern=Ct { +else +  pattern={      [1]=(C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3),      [2]=C(((1-S("*?/"))^0*P("/"))^0),      [3]=C(P(1)^0) @@ -3898,9 +4011,8 @@ local function glob(str,t)      elseif isfile(str) then        t(str)      else -      local split=lpegmatch(pattern,str)  -      if split then -        local root,path,base=split[1],split[2],split[3] +      local root,path,base=lpegmatch(pattern,str)  +      if root and path and base then          local recurse=find(base,"**",1,true)           local start=root..path          local result=lpegmatch(filter,start..base) @@ -3922,16 +4034,12 @@ local function glob(str,t)          return { str }        end      else -      local split=lpegmatch(pattern,str)  -      if split then -        local t=t or {} -        local action=action or function(name) t[#t+1]=name end -        local root,path,base=split[1],split[2],split[3] +      local root,path,base=lpegmatch(pattern,str)  +      if root and path and base then          local recurse=find(base,"**",1,true)           local start=root..path          local result=lpegmatch(filter,start..base) -        globpattern(start,result,recurse,action) -        return t +        return globpattern(start,result,recurse,t)        else          return {}        end @@ -4879,7 +4987,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["util-str"] = package.loaded["util-str"] or true --- original size: 33485, stripped down to: 18420 +-- original size: 34240, stripped down to: 18733  if not modules then modules={} end modules ['util-str']={    version=1.001, @@ -5544,6 +5652,15 @@ else    add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=lpeg.patterns.texescape })    add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=lpeg.patterns.luaescape })  end +local dquote=patterns.dquote  +local equote=patterns.escaped+dquote/'\\"'+1 +local space=patterns.space +local cquote=Cc('"') +local pattern=Cs(dquote*(equote-P(-2))^0*dquote)           ++Cs(cquote*(equote-space)^0*space*equote^0*cquote)  +function string.optionalquoted(str) +  return lpegmatch(pattern,str) or str +end  end -- of closure @@ -8717,7 +8834,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["util-env"] = package.loaded["util-env"] or true --- original size: 8814, stripped down to: 5092 +-- original size: 8022, stripped down to: 5038  if not modules then modules={} end modules ['util-env']={    version=1.001, @@ -8728,7 +8845,7 @@ if not modules then modules={} end modules ['util-env']={  }  local allocate,mark=utilities.storage.allocate,utilities.storage.mark  local format,sub,match,gsub,find=string.format,string.sub,string.match,string.gsub,string.find -local unquoted,quoted=string.unquoted,string.quoted +local unquoted,quoted,optionalquoted=string.unquoted,string.quoted,string.optionalquoted  local concat,insert,remove=table.concat,table.insert,table.remove  environment=environment or {}  local environment=environment @@ -8841,24 +8958,14 @@ function environment.splitarguments(separator)    return before,after  end  function environment.reconstructcommandline(arg,noquote) +  local resolveprefix=resolvers.resolve     arg=arg or environment.originalarguments    if noquote and #arg==1 then -    local a=arg[1] -    a=resolvers.resolve(a) -    a=unquoted(a) -    return a +    return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1])    elseif #arg>0 then      local result={}      for i=1,#arg do -      local a=arg[i] -      a=resolvers.resolve(a) -      a=unquoted(a) -      a=gsub(a,'"','\\"')  -      if find(a," ",1,true) then -        result[#result+1]=quoted(a) -      else -        result[#result+1]=a -      end +      result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix)      end      return concat(result," ")    else @@ -12483,7 +12590,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-ini"] = package.loaded["data-ini"] or true --- original size: 7927, stripped down to: 5528 +-- original size: 10598, stripped down to: 7341  if not modules then modules={} end modules ['data-ini']={    version=1.001, @@ -12492,14 +12599,15 @@ if not modules then modules={} end modules ['data-ini']={    copyright="PRAGMA ADE / ConTeXt Development Team",    license="see context related readme files",  } +local next,type,getmetatable,rawset=next,type,getmetatable,rawset  local gsub,find,gmatch,char=string.gsub,string.find,string.gmatch,string.char -local next,type=next,type  local filedirname,filebasename,filejoin=file.dirname,file.basename,file.join +local ostype,osname,osuname,ossetenv,osgetenv=os.type,os.name,os.uname,os.setenv,os.getenv +local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match  local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end)  local trace_detail=false trackers.register("resolvers.details",function(v) trace_detail=v end)  local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end)  local report_initialization=logs.reporter("resolvers","initialization") -local ostype,osname,ossetenv,osgetenv=os.type,os.name,os.setenv,os.getenv  resolvers=resolvers or {}  local resolvers=resolvers  texconfig.kpse_init=false @@ -12632,10 +12740,88 @@ if type(profiler)=="table" and not jit then      profiler.start("luatex-profile.log")    end)  end -if not resolvers.resolve then -  function resolvers.resolve (s) return s end -  function resolvers.unresolve(s) return s end -  function resolvers.repath  (s) return s end +local prefixes=utilities.storage.allocate() +resolvers.prefixes=prefixes +local resolved={} +local abstract={} +function resolvers.resetresolve(str) +  resolved,abstract={},{} +end +function resolvers.allprefixes(separator) +  local all=table.sortedkeys(prefixes) +  if separator then +    for i=1,#all do +      all[i]=all[i]..":" +    end +  end +  return all +end +local function _resolve_(method,target) +  local action=prefixes[method] +  if action then +    return action(target) +  else +    return method..":"..target +  end +end +function resolvers.unresolve(str) +  return abstract[str] or str +end +local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) +local prefix=C(R("az")^2)*P(":") +local target=C((1-S(" \"\';,"))^1) +local notarget=(#S(";,")+P(-1))*Cc("") +local pattern=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) +local function resolve(str)  +  if type(str)=="table" then +    local res={} +    for i=1,#str do +      res[i]=resolve(str[i]) +    end +    return res +  else +    local res=resolved[str] +    if not res then +      res=lpegmatch(pattern,str) +      resolved[str]=res +      abstract[res]=str +    end +    return res +  end +end +resolvers.resolve=resolve +if type(osuname)=="function" then +  for k,v in next,osuname() do +    if not prefixes[k] then +      prefixes[k]=function() return v end +    end +  end +end +if ostype=="unix" then +  local pattern +  local function makepattern(t,k,v) +    if t then +      rawset(t,k,v) +    end +    local colon=P(":") +    for k,v in table.sortedpairs(prefixes) do +      if p then +        p=P(k)+p +      else +        p=P(k) +      end +    end +    pattern=Cs((p*colon+colon/";"+P(1))^0) +  end +  makepattern() +  table.setmetatablenewindex(prefixes,makepattern) +  function resolvers.repath(str) +    return lpegmatch(pattern,str) +  end +else  +  function resolvers.repath(str) +    return str +  end  end @@ -12645,7 +12831,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-exp"] = package.loaded["data-exp"] or true --- original size: 15317, stripped down to: 9723 +-- original size: 16463, stripped down to: 10113  if not modules then modules={} end modules ['data-exp']={    version=1.001, @@ -12660,11 +12846,14 @@ local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns  local Ct,Cs,Cc,Carg,P,C,S=lpeg.Ct,lpeg.Cs,lpeg.Cc,lpeg.Carg,lpeg.P,lpeg.C,lpeg.S  local type,next=type,next  local ostype=os.type -local collapsepath=file.collapsepath +local collapsepath,joinpath,basename=file.collapsepath,file.join,file.basename  local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end)  local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_globbing=true  trackers.register("resolvers.globbing",function(v) trace_globbing=v end)  local report_expansions=logs.reporter("resolvers","expansions") +local report_globbing=logs.reporter("resolvers","globbing")  local resolvers=resolvers +local resolveprefix=resolvers.resolve  local function f_both(a,b)    local t,n={},0    for sb in gmatch(b,"[^,]+") do        @@ -12754,35 +12943,27 @@ function resolvers.expandedpathfromlist(pathlist)    end    return newlist  end -local cleanup=lpeg.replacer { -  { "!","" }, -  { "\\","/" }, -} -function resolvers.cleanpath(str)  -  local doslashes=(P("\\")/"/"+1)^0 -  local donegation=(P("!")/""   )^0 -  local homedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") -  if homedir=="~" or homedir=="" or not lfs.isdir(homedir) then -    if trace_expansions then -      report_expansions("no home dir set, ignoring dependent paths") -    end -    function resolvers.cleanpath(str) -      if not str or find(str,"~",1,true) then -        return ""  -      else -        return lpegmatch(cleanup,str) +local usedhomedir=nil +local donegation=(P("!")/""   )^0 +local doslashes=(P("\\")/"/"+1)^0 +local function expandedhome() +  if not usedhomedir then +    usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") +    if usedhomedir=="~" or usedhomedir=="" or not lfs.isdir(usedhomedir) then +      if trace_expansions then +        report_expansions("no home dir set, ignoring dependent path using current path")        end -    end -  else -    local dohome=((P("~")+P("$HOME"))/homedir)^0 -    local cleanup=Cs(donegation*dohome*doslashes) -    function resolvers.cleanpath(str) -      return str and lpegmatch(cleanup,str) or "" +      usedhomedir="."      end    end -  return resolvers.cleanpath(str) +  return usedhomedir +end +local dohome=((P("~")+P("$HOME")+P("%HOME%"))/expandedhome)^0 +local cleanup=Cs(donegation*dohome*doslashes) +resolvers.cleanpath=function(str) +  return str and lpegmatch(cleanup,str) or ""  end -local expandhome=P("~")/"$HOME"  +local expandhome=P("~")/"$HOME"  local dodouble=P('"')/""*(expandhome+(1-P('"')))^0*P('"')/""  local dosingle=P("'")/""*(expandhome+(1-P("'")))^0*P("'")/""  local dostring=(expandhome+1       )^0 @@ -12834,7 +13015,7 @@ function resolvers.splitpath(str)  end  function resolvers.joinpath(str)    if type(str)=='table' then -    return file.joinpath(str) +    return joinpath(str)    else      return str    end @@ -12845,35 +13026,54 @@ local timer={}  local scanned={}  local nofscans=0  local scancache={} -local function scan(files,spec,path,n,m,r) -  local full=(path=="" and spec) or (spec..path..'/') +local fullcache={} +local nofsharedscans=0 +local function scan(files,remap,spec,path,n,m,r,onlyone) +  local full=path=="" and spec or (spec..path..'/')    local dirs={}    local nofdirs=0    for name in directory(full) do      if not lpegmatch(weird,name) then -      local mode=attributes(full..name,'mode') -      if mode=='file' then +      local mode=attributes(full..name,"mode") +      if mode=="file" then          n=n+1 -        local f=files[name] -        if f then -          if type(f)=='string' then -            files[name]={ f,path } +        local lower=lower(name) +        local paths=files[lower] +        if paths then +          if onlyone then            else -            f[#f+1]=path +            if type(paths)=="string" then +              files[lower]={ paths,path } +            else +              paths[#paths+1]=path +            end +            if name~=lower then +              local rl=remap[lower] +              if not rl then +                remap[lower]=name +                r=r+1 +              elseif trace_globbing and rl~=name then +                report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) +              end +            end            end          else  -          files[name]=path -          local lower=lower(name) +          files[lower]=path            if name~=lower then -            files["remap:"..lower]=name -            r=r+1 +            local rl=remap[lower] +            if not rl then +              remap[lower]=name +              r=r+1 +            elseif trace_globbing and rl~=name then +              report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) +            end            end          end -      elseif mode=='directory' then +      elseif mode=="directory" then          m=m+1          nofdirs=nofdirs+1          if path~="" then -          dirs[nofdirs]=path..'/'..name +          dirs[nofdirs]=path.."/"..name          else            dirs[nofdirs]=name          end @@ -12883,107 +13083,52 @@ local function scan(files,spec,path,n,m,r)    if nofdirs>0 then      sort(dirs)      for i=1,nofdirs do -      files,n,m,r=scan(files,spec,dirs[i],n,m,r) +      files,remap,n,m,r=scan(files,remap,spec,dirs[i],n,m,r,onlyone)      end    end    scancache[sub(full,1,-2)]=files -  return files,n,m,r +  return files,remap,n,m,r  end -local fullcache={} -function resolvers.scanfiles(path,branch,usecache) -  statistics.starttiming(timer) -  local realpath=resolvers.resolve(path)  +function resolvers.scanfiles(path,branch,usecache,onlyonce) +  local realpath=resolveprefix(path)    if usecache then -    local files=fullcache[realpath] -    if files then +    local content=fullcache[realpath] +    if content then        if trace_locating then -        report_expansions("using caches scan of path %a, branch %a",path,branch or path) +        report_expansions("using cached scan of path %a, branch %a",path,branch or path)        end -      return files +      nofsharedscans=nofsharedscans+1 +      return content      end    end +  statistics.starttiming(timer)    if trace_locating then      report_expansions("scanning path %a, branch %a",path,branch or path)    end -  local files,n,m,r=scan({},realpath..'/',"",0,0,0) -  files.__path__=path  -  files.__files__=n -  files.__directories__=m -  files.__remappings__=r +  local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce) +  local content={ +    metadata={ +      path=path, +      files=n, +      directories=m, +      remappings=r, +    }, +    files=files, +    remap=remap, +  }    if trace_locating then      report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r)    end    if usecache then      scanned[#scanned+1]=realpath -    fullcache[realpath]=files +    fullcache[realpath]=content    end    nofscans=nofscans+1    statistics.stoptiming(timer) -  return files -end -local function simplescan(files,spec,path)  -  local full=(path=="" and spec) or (spec..path..'/') -  local dirs={} -  local nofdirs=0 -  for name in directory(full) do -    if not lpegmatch(weird,name) then -      local mode=attributes(full..name,'mode') -      if mode=='file' then -        if not files[name] then -          files[name]=path -        end -      elseif mode=='directory' then -        nofdirs=nofdirs+1 -        if path~="" then -          dirs[nofdirs]=path..'/'..name -        else -          dirs[nofdirs]=name -        end -      end -    end -  end -  if nofdirs>0 then -    sort(dirs) -    for i=1,nofdirs do -      files=simplescan(files,spec,dirs[i]) -    end -  end -  return files +  return content  end -local simplecache={} -local nofsharedscans=0  function resolvers.simplescanfiles(path,branch,usecache) -  statistics.starttiming(timer) -  local realpath=resolvers.resolve(path)  -  if usecache then -    local files=simplecache[realpath] -    if not files then -      files=scancache[realpath] -      if files then -        nofsharedscans=nofsharedscans+1 -      end -    end -    if files then -      if trace_locating then -        report_expansions("using caches scan of path %a, branch %a",path,branch or path) -      end -      return files -    end -  end -  if trace_locating then -    report_expansions("scanning path %a, branch %a",path,branch or path) -  end -  local files=simplescan({},realpath..'/',"") -  if trace_locating then -    report_expansions("%s files found",table.count(files)) -  end -  if usecache then -    scanned[#scanned+1]=realpath -    simplecache[realpath]=files -  end -  nofscans=nofscans+1 -  statistics.stoptiming(timer) -  return files +  return resolvers.scanfiles(path,branch,usecache,true)   end  function resolvers.scandata()    table.sort(scanned) @@ -12994,6 +13139,49 @@ function resolvers.scandata()      paths=scanned,    }  end +function resolvers.get_from_content(content,path,name)  +  local files=content.files +  if not files then +    return +  end +  local remap=content.remap +  if not remap then +    return +  end +  if name then +    local used=lower(name) +    return path,remap[used] or used +  else +    local name=path +    local used=lower(name) +    local path=files[used] +    if path then +      return path,remap[used] or used +    end +  end +end +local nothing=function() end +function resolvers.filtered_from_content(content,pattern) +  if content and type(pattern)=="string" then +    local pattern=lower(pattern) +    local files=content.files +    local remap=content.remap +    if files and remap then +      local n=next(files) +      local function iterator() +        while n do +          local k=n +          n=next(files,k) +          if find(k,pattern) then +            return files[k],remap and remap[k] or k +          end +        end +      end +      return iterator +    end +  end +  return nothing +end  end -- of closure @@ -13272,7 +13460,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-tmp"] = package.loaded["data-tmp"] or true --- original size: 15532, stripped down to: 11648 +-- original size: 15681, stripped down to: 11761  if not modules then modules={} end modules ['data-tmp']={    version=1.100, @@ -13291,6 +13479,7 @@ local trace_cache=false trackers.register("resolvers.cache",function(v) trace_ca  local report_caches=logs.reporter("resolvers","caches")  local report_resolvers=logs.reporter("resolvers","caching")  local resolvers=resolvers +local cleanpath=resolvers.cleanpath  local directive_cleanup=false directives.register("system.compile.cleanup",function(v) directive_cleanup=v end)  local directive_strip=false directives.register("system.compile.strip",function(v) directive_strip=v end)  local compile=utilities.lua.compile @@ -13312,7 +13501,7 @@ caches.relocate=false  caches.defaults={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" }  local writable,readables,usedreadables=nil,{},{}  local function identify() -  local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") +  local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE")     if texmfcaches then      for k=1,#texmfcaches do        local cachepath=texmfcaches[k] @@ -13566,10 +13755,12 @@ local content_state={}  function caches.contentstate()    return content_state or {}  end -function caches.loadcontent(cachename,dataname) -  local name=caches.hashed(cachename) -  local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") -  local filename=file.join(path,name) +function caches.loadcontent(cachename,dataname,filename) +  if not filename then +    local name=caches.hashed(cachename) +    local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") +    filename=file.join(path,name) +  end    local blob=loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua))    if blob then      local data=blob() @@ -13601,10 +13792,12 @@ function caches.collapsecontent(content)      end    end  end -function caches.savecontent(cachename,dataname,content) -  local name=caches.hashed(cachename) -  local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") -  local filename=file.join(path,name)  +function caches.savecontent(cachename,dataname,content,filename) +  if not filename then +    local name=caches.hashed(cachename) +    local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") +    filename=file.join(path,name)  +  end    local luaname=addsuffix(filename,luasuffixes.lua)    local lucname=addsuffix(filename,luasuffixes.luc)    if trace_locating then @@ -13647,7 +13840,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-met"] = package.loaded["data-met"] or true --- original size: 5460, stripped down to: 4014 +-- original size: 5347, stripped down to: 4015  if not modules then modules={} end modules ['data-met']={    version=1.100, @@ -13675,7 +13868,7 @@ local function splitmethod(filename)    if type(filename)=="table" then      return filename     end -  filename=file.collapsepath(filename,".") +  filename=file.collapsepath(filename,".")     if not find(filename,"://",1,true) then      return { scheme="file",path=filename,original=filename,filename=filename }    end @@ -13766,7 +13959,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-res"] = package.loaded["data-res"] or true --- original size: 62045, stripped down to: 43116 +-- original size: 61031, stripped down to: 42613  if not modules then modules={} end modules ['data-res']={    version=1.001, @@ -13776,7 +13969,7 @@ if not modules then modules={} end modules ['data-res']={    license="see context related readme files",  }  local gsub,find,lower,upper,match,gmatch=string.gsub,string.find,string.lower,string.upper,string.match,string.gmatch -local concat,insert,sortedkeys=table.concat,table.insert,table.sortedkeys +local concat,insert,sortedkeys,sortedhash=table.concat,table.insert,table.sortedkeys,table.sortedhash  local next,type,rawget=next,type,rawget  local os=os  local P,S,R,C,Cc,Cs,Ct,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cc,lpeg.Cs,lpeg.Ct,lpeg.Carg @@ -13785,14 +13978,19 @@ local formatters=string.formatters  local filedirname=file.dirname  local filebasename=file.basename  local suffixonly=file.suffixonly +local addsuffix=file.addsuffix +local removesuffix=file.removesuffix  local filejoin=file.join  local collapsepath=file.collapsepath  local joinpath=file.joinpath +local is_qualified_path=file.is_qualified_path  local allocate=utilities.storage.allocate  local settings_to_array=utilities.parsers.settings_to_array +local getcurrentdir=lfs.currentdir +local isfile=lfs.isfile +local isdir=lfs.isdir  local setmetatableindex=table.setmetatableindex  local luasuffixes=utilities.lua.suffixes -local getcurrentdir=lfs.currentdir  local trace_locating=false trackers .register("resolvers.locating",function(v) trace_locating=v end)  local trace_detail=false trackers .register("resolvers.details",function(v) trace_detail=v end)  local trace_expansions=false trackers .register("resolvers.expansions",function(v) trace_expansions=v end) @@ -13803,10 +14001,14 @@ local expandedpathfromlist=resolvers.expandedpathfromlist  local checkedvariable=resolvers.checkedvariable  local splitconfigurationpath=resolvers.splitconfigurationpath  local methodhandler=resolvers.methodhandler +local filtered=resolvers.filtered_from_content +local lookup=resolvers.get_from_content +local cleanpath=resolvers.cleanpath +local resolveprefix=resolvers.resolve  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' -resolvers.configbanner='' +resolvers.cacheversion="1.100" +resolvers.configbanner=""  resolvers.homedir=environment.homedir  resolvers.criticalvars=allocate { "SELFAUTOLOC","SELFAUTODIR","SELFAUTOPARENT","TEXMFCNF","TEXMF","TEXOS" }  resolvers.luacnfname="texmfcnf.lua" @@ -13833,7 +14035,7 @@ local   instance=resolvers.instance or nil  function resolvers.setenv(key,value,raw)    if instance then      instance.environment[key]=value -    ossetenv(key,raw and value or resolvers.resolve(value)) +    ossetenv(key,raw and value or resolveprefix(value))    end  end  local function getenv(key) @@ -13847,7 +14049,7 @@ local function getenv(key)  end  resolvers.getenv=getenv  resolvers.env=getenv -local function resolve(k) +local function resolvevariable(k)    return instance.expansions[k]  end  local dollarstripper=lpeg.stripper("$") @@ -13856,19 +14058,19 @@ local backslashswapper=lpeg.replacer("\\","/")  local somevariable=P("$")/""  local somekey=C(R("az","AZ","09","__","--")^1)  local somethingelse=P(";")*((1-S("!{}/\\"))^1*P(";")/"")+P(";")*(P(";")/"")+P(1) -local variableexpander=Cs((somevariable*(somekey/resolve)+somethingelse)^1 ) +local variableexpander=Cs((somevariable*(somekey/resolvevariable)+somethingelse)^1 )  local cleaner=P("\\")/"/"+P(";")*S("!{}/\\")^0*P(";")^1/";"  local variablecleaner=Cs((cleaner+P(1))^0) -local somevariable=R("az","AZ","09","__","--")^1/resolve +local somevariable=R("az","AZ","09","__","--")^1/resolvevariable  local variable=(P("$")/"")*(somevariable+(P("{")/"")*somevariable*(P("}")/""))  local variableresolver=Cs((variable+P(1))^0)  local function expandedvariable(var)    return lpegmatch(variableexpander,var) or var  end -function resolvers.newinstance()  -   if trace_locating then +function resolvers.newinstance() +  if trace_locating then      report_resolving("creating instance") -   end +  end    local environment,variables,expansions,order=allocate(),allocate(),allocate(),allocate()    local newinstance={      environment=environment, @@ -13995,13 +14197,13 @@ local function identify_configuration_files()      for i=1,#cnfpaths do        local filepath=cnfpaths[i]        local filename=collapsepath(filejoin(filepath,luacnfname)) -      local realname=resolvers.resolve(filename) +      local realname=resolveprefix(filename)        if trace_locating then -        local fullpath=gsub(resolvers.resolve(collapsepath(filepath)),"//","/") +        local fullpath=gsub(resolveprefix(collapsepath(filepath)),"//","/")          local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true)          report_resolving("looking for %a on %s path %a from specification %a",luacnfname,weirdpath and "weird" or "given",fullpath,filepath)        end -      if lfs.isfile(realname) then +      if isfile(realname) then          specification[#specification+1]=filename           if trace_locating then            report_resolving("found configuration file %a",realname) @@ -14023,7 +14225,7 @@ local function load_configuration_files()        local filename=specification[i]        local pathname=filedirname(filename)        local filename=filejoin(pathname,luacnfname) -      local realname=resolvers.resolve(filename)  +      local realname=resolveprefix(filename)         local blob=loadfile(realname)        if blob then          local setups=instance.setups @@ -14031,7 +14233,7 @@ local function load_configuration_files()          local parent=data and data.parent          if parent then            local filename=filejoin(pathname,parent) -          local realname=resolvers.resolve(filename)  +          local realname=resolveprefix(filename)             local blob=loadfile(realname)            if blob then              local parentdata=blob() @@ -14056,7 +14258,7 @@ local function load_configuration_files()              elseif variables[k]==nil then                if trace_locating and not warning then                  report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable", -                  k,resolvers.resolve(filename)) +                  k,resolveprefix(filename))                  warning=true                end                variables[k]=v @@ -14116,7 +14318,7 @@ local function locate_file_databases()        local stripped=lpegmatch(inhibitstripper,path)         if stripped~="" then          local runtime=stripped==path -        path=resolvers.cleanpath(path) +        path=cleanpath(path)          local spec=resolvers.splitmethod(stripped)          if runtime and (spec.noscheme or spec.scheme=="file") then            stripped="tree:///"..stripped @@ -14179,8 +14381,8 @@ function resolvers.renew(hashname)          report_resolving("identifying tree %a",hashname)        end      end -    local realpath=resolvers.resolve(hashname) -    if lfs.isdir(realpath) then +    local realpath=resolveprefix(hashname) +    if isdir(realpath) then        if trace_locating then          report_resolving("using path %a",realpath)        end @@ -14308,7 +14510,7 @@ function resolvers.registerextrapath(paths,subpaths)            local ps=p.."/"..s            if not done[ps] then              newn=newn+1 -            ep[newn]=resolvers.cleanpath(ps) +            ep[newn]=cleanpath(ps)              done[ps]=true            end          end @@ -14318,7 +14520,7 @@ function resolvers.registerextrapath(paths,subpaths)          local p=paths[i]          if not done[p] then            newn=newn+1 -          ep[newn]=resolvers.cleanpath(p) +          ep[newn]=cleanpath(p)            done[p]=true          end        end @@ -14330,7 +14532,7 @@ function resolvers.registerextrapath(paths,subpaths)          local ps=ep[i].."/"..s          if not done[ps] then            newn=newn+1 -          ep[newn]=resolvers.cleanpath(ps) +          ep[newn]=cleanpath(ps)            done[ps]=true          end        end @@ -14384,7 +14586,7 @@ function resolvers.cleanpathlist(str)    local t=resolvers.expandedpathlist(str)    if t then      for i=1,#t do -      t[i]=collapsepath(resolvers.cleanpath(t[i])) +      t[i]=collapsepath(cleanpath(t[i]))      end    end    return t @@ -14434,7 +14636,7 @@ function resolvers.registerfilehash(name,content,someerror)    end  end  local function isreadable(name) -  local readable=lfs.isfile(name)  +  local readable=isfile(name)     if trace_detail then      if readable then        report_resolving("file %a is readable",name) @@ -14445,69 +14647,56 @@ local function isreadable(name)    return readable  end  local function collect_files(names) -  local filelist,noffiles={},0 +  local filelist={} +  local noffiles=0 +  local function check(hash,root,pathname,path,name) +    if not pathname or find(path,pathname) then +      local variant=hash.type +      local search=filejoin(root,path,name)  +      local result=methodhandler('concatinators',variant,root,path,name) +      if trace_detail then +        report_resolving("match: variant %a, search %a, result %a",variant,search,result) +      end +      noffiles=noffiles+1 +      filelist[noffiles]={ variant,search,result } +    end +  end    for k=1,#names do -    local fname=names[k] +    local filename=names[k]      if trace_detail then -      report_resolving("checking name %a",fname) +      report_resolving("checking name %a",filename)      end -    local bname=filebasename(fname) -    local dname=filedirname(fname) -    if dname=="" or find(dname,"^%.") then -      dname=false +    local basename=filebasename(filename) +    local pathname=filedirname(filename) +    if pathname=="" or find(pathname,"^%.") then +      pathname=false      else -      dname=gsub(dname,"%*",".*") -      dname="/"..dname.."$" +      pathname=gsub(pathname,"%*",".*") +      pathname="/"..pathname.."$"      end      local hashes=instance.hashes      for h=1,#hashes do        local hash=hashes[h] -      local blobpath=hash.name -      local files=blobpath and instance.files[blobpath] -      if files then +      local hashname=hash.name +      local content=hashname and instance.files[hashname] +      if content then          if trace_detail then -          report_resolving("deep checking %a, base %a, pattern %a",blobpath,bname,dname) -        end -        local blobfile=files[bname] -        if not blobfile then -          local rname="remap:"..bname -          blobfile=files[rname] -          if blobfile then -            bname=files[rname] -            blobfile=files[bname] -          end +          report_resolving("deep checking %a, base %a, pattern %a",blobpath,basename,pathname)          end -        if blobfile then -          local blobroot=files.__path__ or blobpath -          if type(blobfile)=='string' then -            if not dname or find(blobfile,dname) then -              local variant=hash.type -              local search=filejoin(blobroot,blobfile,bname) -              local result=methodhandler('concatinators',hash.type,blobroot,blobfile,bname) -              if trace_detail then -                report_resolving("match: variant %a, search %a, result %a",variant,search,result) -              end -              noffiles=noffiles+1 -              filelist[noffiles]={ variant,search,result } -            end +        local path,name=lookup(content,basename) +        if path then +          local metadata=content.metadata +          local realroot=metadata and metadata.path or hashname +          if type(path)=="string" then +            check(hash,realroot,pathname,path,name)            else -            for kk=1,#blobfile do -              local vv=blobfile[kk] -              if not dname or find(vv,dname) then -                local variant=hash.type -                local search=filejoin(blobroot,vv,bname) -                local result=methodhandler('concatinators',hash.type,blobroot,vv,bname) -                if trace_detail then -                  report_resolving("match: variant %a, search %a, result %a",variant,search,result) -                end -                noffiles=noffiles+1 -                filelist[noffiles]={ variant,search,result } -              end +            for i=1,#path do +              check(hash,realroot,pathname,path[i],name)              end            end          end        elseif trace_locating then -        report_resolving("no match in %a (%s)",blobpath,bname) +        report_resolving("no match in %a (%s)",hashname,basename)        end      end    end @@ -14532,7 +14721,7 @@ end  local function can_be_dir(name)     local fakepaths=instance.fakepaths    if not fakepaths[name] then -    if lfs.isdir(name) then +    if isdir(name) then        fakepaths[name]=1       else        fakepaths[name]=2  @@ -14548,10 +14737,11 @@ local function find_analyze(filename,askedformat,allresults)    if askedformat=="" then      if ext=="" or not suffixmap[ext] then        local defaultsuffixes=resolvers.defaultsuffixes +      local formatofsuffix=resolvers.formatofsuffix        for i=1,#defaultsuffixes do          local forcedname=filename..'.'..defaultsuffixes[i]          wantedfiles[#wantedfiles+1]=forcedname -        filetype=resolvers.formatofsuffix(forcedname) +        filetype=formatofsuffix(forcedname)          if trace_locating then            report_resolving("forcing filetype %a",filetype)          end @@ -14591,14 +14781,14 @@ local function find_wildcard(filename,allresults)      if trace_locating then        report_resolving("checking wildcard %a",filename)      end -    local method,result=resolvers.findwildcardfiles(filename) +    local result=resolvers.findwildcardfiles(filename)      if result then        return "wildcard",result      end    end  end  local function find_qualified(filename,allresults,askedformat,alsostripped)  -  if not file.is_qualified_path(filename) then +  if not is_qualified_path(filename) then      return    end    if trace_locating then @@ -14687,7 +14877,6 @@ local function find_intree(filename,filetype,wantedfiles,allresults)      if trace_detail then        report_resolving("checking filename %a",filename)      end -    local resolve=resolvers.resolve      local result={}      for k=1,#pathlist do        local path=pathlist[k] @@ -14706,8 +14895,8 @@ local function find_intree(filename,filetype,wantedfiles,allresults)            local fl=filelist[k]            local f=fl[2]            local d=dirlist[k] -          if find(d,expression) or find(resolve(d),expression) then -            result[#result+1]=resolve(fl[3])  +          if find(d,expression) or find(resolveprefix(d),expression) then +            result[#result+1]=resolveprefix(fl[3])               done=true              if allresults then                if trace_detail then @@ -14729,7 +14918,7 @@ local function find_intree(filename,filetype,wantedfiles,allresults)        else          method="filesystem"           pathname=gsub(pathname,"/+$","") -        pathname=resolve(pathname) +        pathname=resolveprefix(pathname)          local scheme=url.hasscheme(pathname)          if not scheme or scheme=="file" then            local pname=gsub(pathname,"%.%*$",'') @@ -14819,7 +15008,7 @@ local function find_otherwise(filename,filetype,wantedfiles,allresults)    local filelist=collect_files(wantedfiles)    local fl=filelist and filelist[1]    if fl then -    return "otherwise",{ resolvers.resolve(fl[3]) }  +    return "otherwise",{ resolveprefix(fl[3]) }     end  end  collect_instance_files=function(filename,askedformat,allresults)  @@ -14919,39 +15108,30 @@ function resolvers.findpath(filename,filetype)    return filedirname(findfiles(filename,filetype,false)[1] or "")  end  local function findgivenfiles(filename,allresults) -  local bname,result=filebasename(filename),{} +  local base=filebasename(filename) +  local result={}    local hashes=instance.hashes -  local noffound=0 +  local function okay(hash,path,name) +    local found=methodhandler('concatinators',hash.type,hash.name,path,name) +    if found and found~="" then +      result[#result+1]=resolveprefix(found) +      return not allresults +    end +  end    for k=1,#hashes do      local hash=hashes[k] -    local files=instance.files[hash.name] or {} -    local blist=files[bname] -    if not blist then -      local rname="remap:"..bname -      blist=files[rname] -      if blist then -        bname=files[rname] -        blist=files[bname] -      end -    end -    if blist then -      if type(blist)=='string' then -        local found=methodhandler('concatinators',hash.type,hash.name,blist,bname) or "" -        if found~="" then -          noffound=noffound+1 -          result[noffound]=resolvers.resolve(found) -          if not allresults then -            break -          end +    local content=instance.files[hash.name] +    if content then +      local path,name=lookup(content,base) +      if not path then +      elseif type(path)=="string" then +        if okay(hash,path,name) then +          return result          end        else -        for kk=1,#blist do -          local vv=blist[kk] -          local found=methodhandler('concatinators',hash.type,hash.name,vv,bname) or "" -          if found~="" then -            noffound=noffound+1 -            result[noffound]=resolvers.resolve(found) -            if not allresults then break end +        for i=1,#path do +          if okay(hash,path[i],name) then +            return result            end          end        end @@ -14965,64 +15145,80 @@ end  function resolvers.findgivenfile(filename)    return findgivenfiles(filename,false)[1] or ""  end -local function doit(path,blist,bname,tag,variant,result,allresults) -  local done=false -  if blist and variant then -    local resolve=resolvers.resolve  -    if type(blist)=='string' then -      if find(lower(blist),path) then -        local full=methodhandler('concatinators',variant,tag,blist,bname) or "" -        result[#result+1]=resolve(full) -        done=true -      end -    else -      for kk=1,#blist do -        local vv=blist[kk] -        if find(lower(vv),path) then -          local full=methodhandler('concatinators',variant,tag,vv,bname) or "" -          result[#result+1]=resolve(full) -          done=true -          if not allresults then break end -        end -      end -    end -  end -  return done -end  local makewildcard=Cs(    (P("^")^0*P("/")*P(-1)+P(-1))/".*"+(P("^")^0*P("/")/"")^0*(P("*")/".*"+P("-")/"%%-"+P(".")/"%%."+P("?")/"."+P("\\")/"/"+P(1))^0  )  function resolvers.wildcardpattern(pattern)    return lpegmatch(makewildcard,pattern) or pattern  end -local function findwildcardfiles(filename,allresults,result)  -  result=result or {} +local function findwildcardfiles(filename,allresults,result) +  local result=result or {}    local base=filebasename(filename)    local dirn=filedirname(filename)    local path=lower(lpegmatch(makewildcard,dirn) or dirn)    local name=lower(lpegmatch(makewildcard,base) or base) -  local files,done=instance.files,false +  local files=instance.files    if find(name,"*",1,true) then      local hashes=instance.hashes +    local function okay(found,path,base,hashname,hashtype) +      if find(found,path) then +        local full=methodhandler('concatinators',hashtype,hashname,found,base) +        if full and full~="" then +          result[#result+1]=resolveprefix(full) +          return not allresults +        end +      end +    end      for k=1,#hashes do        local hash=hashes[k] -      local hashname,hashtype=hash.name,hash.type -      for kk,hh in next,files[hashname] do -        if not find(kk,"^remap:") then -          if find(lower(kk),name) then -            if doit(path,hh,kk,hashname,hashtype,result,allresults) then done=true end -            if done and not allresults then break end +      local hashname=hash.name +      local hashtype=hash.type +      if hashname and hashtype then +        for found,base in filtered(files[hashname],name) do +          if type(found)=='string' then +            if okay(found,path,base,hashname,hashtype) then +              break +            end +          else +            for i=1,#found do +              if okay(found[i],path,base,hashname,hashtype) then +                break +              end +            end            end          end        end      end    else +    local function okayokay(found,path,base,hashname,hashtype) +      if find(found,path) then +        local full=methodhandler('concatinators',hashtype,hashname,found,base) +        if full and full~="" then +          result[#result+1]=resolveprefix(full) +          return not allresults +        end +      end +    end      local hashes=instance.hashes      for k=1,#hashes do        local hash=hashes[k] -      local hashname,hashtype=hash.name,hash.type -      if doit(path,files[hashname][base],base,hashname,hashtype,result,allresults) then done=true end -      if done and not allresults then break end +      local hashname=hash.name +      local hashtype=hash.type +      if hashname and hashtype then +        local found,base=lookup(content,base) +        if not found then +        elseif type(found)=='string' then +          if okay(found,path,base,hashname,hashtype) then +            break +          end +        else +          for i=1,#found do +            if okay(found[i],path,base,hashname,hashtype) then +              break +            end +          end +        end +      end      end    end    return result @@ -15095,7 +15291,7 @@ end  function resolvers.dowithpath(name,func)    local pathlist=resolvers.expandedpathlist(name)    for i=1,#pathlist do -    func("^"..resolvers.cleanpath(pathlist[i])) +    func("^"..cleanpath(pathlist[i]))    end  end  function resolvers.dowithvariable(name,func) @@ -15103,23 +15299,23 @@ function resolvers.dowithvariable(name,func)  end  function resolvers.locateformat(name)    local engine=environment.ownmain or "luatex" -  local barename=file.removesuffix(name) -  local fullname=file.addsuffix(barename,"fmt") +  local barename=removesuffix(name) +  local fullname=addsuffix(barename,"fmt")    local fmtname=caches.getfirstreadablefile(fullname,"formats",engine) or ""    if fmtname=="" then      fmtname=resolvers.findfile(fullname) -    fmtname=resolvers.cleanpath(fmtname) +    fmtname=cleanpath(fmtname)    end    if fmtname~="" then -    local barename=file.removesuffix(fmtname) -    local luaname=file.addsuffix(barename,luasuffixes.lua) -    local lucname=file.addsuffix(barename,luasuffixes.luc) -    local luiname=file.addsuffix(barename,luasuffixes.lui) -    if lfs.isfile(luiname) then +    local barename=removesuffix(fmtname) +    local luaname=addsuffix(barename,luasuffixes.lua) +    local lucname=addsuffix(barename,luasuffixes.luc) +    local luiname=addsuffix(barename,luasuffixes.lui) +    if isfile(luiname) then        return barename,luiname -    elseif lfs.isfile(lucname) then +    elseif isfile(lucname) then        return barename,lucname -    elseif lfs.isfile(luaname) then +    elseif isfile(luaname) then        return barename,luaname      end    end @@ -15141,29 +15337,24 @@ function resolvers.dowithfilesintree(pattern,handle,before,after)      local hash=hashes[i]      local blobtype=hash.type      local blobpath=hash.name -    if blobpath then +    if blobtype and blobpath then +      local total=0 +      local checked=0 +      local done=0        if before then          before(blobtype,blobpath,pattern)        end -      local files=instance.files[blobpath] -      local total,checked,done=0,0,0 -      if files then -        for k,v in table.sortedhash(files) do  -          total=total+1 -          if find(k,"^remap:") then -          elseif find(k,pattern) then -            if type(v)=="string" then -              checked=checked+1 -              if handle(blobtype,blobpath,v,k) then -                done=done+1 -              end -            else -              checked=checked+#v -              for i=1,#v do -                if handle(blobtype,blobpath,v[i],k) then -                  done=done+1 -                end -              end +      for path,name in filtered(instance.files[blobpath],pattern) do +        if type(path)=="string" then +          checked=checked+1 +          if handle(blobtype,blobpath,path,name) then +            done=done+1 +          end +        else +          checked=checked+#path +          for i=1,#path do +            if handle(blobtype,blobpath,path[i],name) then +              done=done+1              end            end          end @@ -15174,8 +15365,8 @@ function resolvers.dowithfilesintree(pattern,handle,before,after)      end    end  end -resolvers.obsolete=resolvers.obsolete or {} -local obsolete=resolvers.obsolete +local obsolete=resolvers.obsolete or {} +resolvers.obsolete=obsolete  resolvers.find_file=resolvers.findfile  obsolete.find_file=resolvers.findfile  resolvers.find_files=resolvers.findfiles  obsolete.find_files=resolvers.findfiles @@ -15186,7 +15377,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-pre"] = package.loaded["data-pre"] or true --- original size: 6643, stripped down to: 4401 +-- original size: 3106, stripped down to: 2563  if not modules then modules={} end modules ['data-pre']={    version=1.001, @@ -15196,44 +15387,51 @@ if not modules then modules={} end modules ['data-pre']={    license="see context related readme files"  }  local resolvers=resolvers -local prefixes=utilities.storage.allocate() -resolvers.prefixes=prefixes -local cleanpath,findgivenfile,expansion=resolvers.cleanpath,resolvers.findgivenfile,resolvers.expansion +local prefixes=resolvers.prefixes +local cleanpath=resolvers.cleanpath +local findgivenfile=resolvers.findgivenfile +local expansion=resolvers.expansion  local getenv=resolvers.getenv  -local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match -local joinpath,basename,dirname=file.join,file.basename,file.dirname -local getmetatable,rawset,type=getmetatable,rawset,type +local basename=file.basename +local dirname=file.dirname +local joinpath=file.join +local isfile=lfs.isfile  prefixes.environment=function(str)    return cleanpath(expansion(str))  end -prefixes.relative=function(str,n)  -  if io.exists(str) then -  elseif io.exists("./"..str) then -    str="./"..str -  else -    local p="../" -    for i=1,n or 2 do -      if io.exists(p..str) then -        str=p..str -        break -      else -        p=p.."../" +local function relative(str,n) +  if not isfile(str) then +    local pstr="./"..str +    if isfile(pstr) then +      str=pstr +    else +      local p="../" +      for i=1,n or 2 do +        local pstr=p..str +        if isfile(pstr) then +          str=pstr +          break +        else +          p=p.."../" +        end        end      end    end    return cleanpath(str)  end +local function locate(str) +  local fullname=findgivenfile(str) or "" +  return cleanpath(fullname~="" and fullname or str) +end +prefixes.relative=relative +prefixes.locate=locate  prefixes.auto=function(str) -  local fullname=prefixes.relative(str) -  if not lfs.isfile(fullname) then -    fullname=prefixes.locate(str) +  local fullname=relative(str) +  if not isfile(fullname) then +    fullname=locate(str)    end    return fullname  end -prefixes.locate=function(str) -  local fullname=findgivenfile(str) or "" -  return cleanpath((fullname~="" and fullname) or str) -end  prefixes.filename=function(str)    local fullname=findgivenfile(str) or ""    return cleanpath(basename((fullname~="" and fullname) or str))  @@ -15277,87 +15475,6 @@ prefixes.kpse=prefixes.locate  prefixes.full=prefixes.locate  prefixes.file=prefixes.filename  prefixes.path=prefixes.pathname -function resolvers.allprefixes(separator) -  local all=table.sortedkeys(prefixes) -  if separator then -    for i=1,#all do -      all[i]=all[i]..":" -    end -  end -  return all -end -local function _resolve_(method,target) -  local action=prefixes[method] -  if action then -    return action(target) -  else -    return method..":"..target -  end -end -local resolved,abstract={},{} -function resolvers.resetresolve(str) -  resolved,abstract={},{} -end -local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) -local prefix=C(R("az")^2)*P(":") -local target=C((1-S(" \"\';,"))^1) -local notarget=(#S(";,")+P(-1))*Cc("") -local pattern=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) -local function resolve(str)  -  if type(str)=="table" then -    local t={} -    for i=1,#str do -      t[i]=resolve(str[i]) -    end -    return t -  else -    local res=resolved[str] -    if not res then -      res=lpegmatch(pattern,str) -      resolved[str]=res -      abstract[res]=str -    end -    return res -  end -end -local function unresolve(str) -  return abstract[str] or str -end -resolvers.resolve=resolve -resolvers.unresolve=unresolve -if type(os.uname)=="function" then -  for k,v in next,os.uname() do -    if not prefixes[k] then -      prefixes[k]=function() return v end -    end -  end -end -if os.type=="unix" then -  local pattern -  local function makepattern(t,k,v) -    if t then -      rawset(t,k,v) -    end -    local colon=P(":") -    for k,v in table.sortedpairs(prefixes) do -      if p then -        p=P(k)+p -      else -        p=P(k) -      end -    end -    pattern=Cs((p*colon+colon/";"+P(1))^0) -  end -  makepattern() -  getmetatable(prefixes).__newindex=makepattern -  function resolvers.repath(str) -    return lpegmatch(pattern,str) -  end -else  -  function resolvers.repath(str) -    return str -  end -end  end -- of closure @@ -15419,7 +15536,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-fil"] = package.loaded["data-fil"] or true --- original size: 3801, stripped down to: 3231 +-- original size: 3863, stripped down to: 3310  if not modules then modules={} end modules ['data-fil']={    version=1.001, @@ -15431,30 +15548,31 @@ if not modules then modules={} end modules ['data-fil']={  local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end)  local report_files=logs.reporter("resolvers","files")  local resolvers=resolvers +local resolveprefix=resolvers.resolve  local finders,openers,loaders,savers=resolvers.finders,resolvers.openers,resolvers.loaders,resolvers.savers  local locators,hashers,generators,concatinators=resolvers.locators,resolvers.hashers,resolvers.generators,resolvers.concatinators  local checkgarbage=utilities.garbagecollector and utilities.garbagecollector.check  function locators.file(specification) -  local name=specification.filename -  local realname=resolvers.resolve(name)  +  local filename=specification.filename +  local realname=resolveprefix(filename)     if realname and realname~='' and lfs.isdir(realname) then      if trace_locating then -      report_files("file locator %a found as %a",name,realname) +      report_files("file locator %a found as %a",filename,realname)      end -    resolvers.appendhash('file',name,true)  +    resolvers.appendhash('file',filename,true)     elseif trace_locating then -    report_files("file locator %a not found",name) +    report_files("file locator %a not found",filename)    end  end  function hashers.file(specification) -  local name=specification.filename -  local content=caches.loadcontent(name,'files') -  resolvers.registerfilehash(name,content,content==nil) +  local pathname=specification.filename +  local content=caches.loadcontent(pathname,'files') +  resolvers.registerfilehash(pathname,content,content==nil)  end  function generators.file(specification) -  local path=specification.filename -  local content=resolvers.scanfiles(path,false,true) -  resolvers.registerfilehash(path,content,true) +  local pathname=specification.filename +  local content=resolvers.scanfiles(pathname,false,true)  +  resolvers.registerfilehash(pathname,content,true)  end  concatinators.file=file.join  function finders.file(specification,filetype) @@ -15736,7 +15854,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-zip"] = package.loaded["data-zip"] or true --- original size: 8489, stripped down to: 6757 +-- original size: 9043, stripped down to: 7073  if not modules then modules={} end modules ['data-zip']={    version=1.001, @@ -15779,7 +15897,7 @@ function zip.openarchive(name)      local arch=archives[name]      if not arch then        local full=resolvers.findfile(name) or "" -      arch=(full~="" and zip.open(full)) or false +      arch=full~="" and zip.open(full) or false        archives[name]=arch      end      return arch @@ -15938,31 +16056,42 @@ function resolvers.usezipfile(archive)    end  end  function resolvers.registerzipfile(z,tree) -  local files,filter={},"" -  if tree=="" then -    filter="^(.+)/(.-)$" -  else -    filter=format("^%s/(.+)/(.-)$",tree) -  end +  local names={} +  local files={}  +  local remap={}  +  local n=0 +  local filter=tree=="" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) +  local register=resolvers.registerfile    if trace_locating then      report_zip("registering: using filter %a",filter)    end -  local register,n=resolvers.registerfile,0    for i in z:files() do -    local path,name=match(i.filename,filter) -    if path then -      if name and name~='' then -        register(files,name,path) -        n=n+1 -      else +    local filename=i.filename +    local path,name=match(filename,filter) +    if not path then +      n=n+1 +      register(names,filename,"") +      local usedname=lower(filename) +      files[usedname]="" +      if usedname~=filename then +        remap[usedname]=filename        end -    else -      register(files,i.filename,'') +    elseif name and name~="" then        n=n+1 +      register(names,name,path) +      local usedname=lower(name) +      files[usedname]=path +      if usedname~=name then +        remap[usedname]=name +      end +    else      end    end    report_zip("registering: %s files registered",n) -  return files +  return { +    files=files, +    remap=remap, +  }  end @@ -15972,7 +16101,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-tre"] = package.loaded["data-tre"] or true --- original size: 2508, stripped down to: 2074 +-- original size: 4859, stripped down to: 3335  if not modules then modules={} end modules ['data-tre']={    version=1.001, @@ -15981,42 +16110,50 @@ if not modules then modules={} end modules ['data-tre']={    copyright="PRAGMA ADE / ConTeXt Development Team",    license="see context related readme files"  } -local find,gsub,format=string.find,string.gsub,string.format +local find,gsub,lower=string.find,string.gsub,string.lower +local basename,dirname,joinname=file.basename,file.dirname,file  .join +local globdir,isdir=dir.glob,lfs.isdir  local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end)  local report_trees=logs.reporter("resolvers","trees")  local resolvers=resolvers -local done,found,notfound={},{},resolvers.finders.notfound -function resolvers.finders.tree(specification) +local resolveprefix=resolvers.resolve +local notfound=resolvers.finders.notfound +local collectors={} +local found={} +function resolvers.finders.tree(specification)     local spec=specification.filename -  local fnd=found[spec] -  if fnd==nil then +  local okay=found[spec] +  if okay==nil then      if spec~="" then -      local path,name=file.dirname(spec),file.basename(spec) -      if path=="" then path="." end -      local hash=done[path] -      if not hash then -        local pattern=path.."/*"  -        hash=dir.glob(pattern) -        done[path]=hash +      local path=dirname(spec) +      local name=basename(spec) +      if path=="" then +        path="." +      end +      local names=collectors[path] +      if not names then +        local pattern=find(path,"/%*+$") and path or (path.."/*") +        names=globdir(pattern) +        collectors[path]=names        end        local pattern="/"..gsub(name,"([%.%-%+])","%%%1").."$" -      for k=1,#hash do -        local v=hash[k] -        if find(v,pattern) then -          found[spec]=v -          return v +      for i=1,#names do +        local fullname=names[i] +        if find(fullname,pattern) then +          found[spec]=fullname +          return fullname          end        end      end -    fnd=notfound()  -    found[spec]=fnd +    okay=notfound()  +    found[spec]=okay    end -  return fnd +  return okay  end  function resolvers.locators.tree(specification)    local name=specification.filename -  local realname=resolvers.resolve(name)  -  if realname and realname~='' and lfs.isdir(realname) then +  local realname=resolveprefix(name)  +  if realname and realname~='' and isdir(realname) then      if trace_locating then        report_trees("locator %a found",realname)      end @@ -16033,10 +16170,43 @@ function resolvers.hashers.tree(specification)    resolvers.methodhandler("hashers",name)    resolvers.generators.file(specification)  end -resolvers.concatinators.tree=resolvers.concatinators.file -resolvers.generators.tree=resolvers.generators.file -resolvers.openers.tree=resolvers.openers.file -resolvers.loaders.tree=resolvers.loaders.file +local collectors={} +table.setmetatableindex(collectors,function(t,k) +  local rootname=gsub(k,"[/%*]+$","") +  local dataname=joinname(rootname,"dirlist") +  local data=caches.loadcontent(dataname,"files",dataname) +  local content=data and data.content +  local lookup=resolvers.get_from_content +  if not content then +    content=resolvers.scanfiles(rootname) +    caches.savecontent(dataname,"files",content,dataname) +  end +  local files=content.files +  local v=function(filename) +    local path,name=lookup(content,filename) +    if not path then +      return filename +    elseif type(path)=="table" then +      path=path[1] +    end +    return joinname(rootname,path,name) +  end +  t[k]=v +  return v +end) +function resolvers.finders.dirlist(specification)  +  local spec=specification.filename +  if spec~="" then +    local path,name=dirname(spec),basename(spec) +    return path and collectors[path](name) or notfound() +  end +  return notfound() +end +resolvers.locators .dirlist=resolvers.locators .tree +resolvers.hashers  .dirlist=resolvers.hashers  .tree +resolvers.generators.dirlist=resolvers.generators.file +resolvers.openers  .dirlist=resolvers.openers  .file +resolvers.loaders  .dirlist=resolvers.loaders  .file  end -- of closure @@ -16221,7 +16391,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-lua"] = package.loaded["data-lua"] or true --- original size: 4237, stripped down to: 3177 +-- original size: 4313, stripped down to: 3227  if not modules then modules={} end modules ['data-lua']={    version=1.001, @@ -16230,7 +16400,7 @@ if not modules then modules={} end modules ['data-lua']={    copyright="PRAGMA ADE / ConTeXt Development Team",    license="see context related readme files"  } -local resolvers,package=resolvers,package +local package,lpeg=package,lpeg  local gsub=string.gsub  local concat=table.concat  local addsuffix=file.addsuffix @@ -16241,9 +16411,11 @@ local luaformats={ 'TEXINPUTS','LUAINPUTS' }  local libformats={ 'CLUAINPUTS' }  local helpers=package.helpers or {}  local methods=helpers.methods or {} +local resolvers=resolvers +local resolveprefix=resolvers.resolve +helpers.report=logs.reporter("resolvers","libraries")  trackers.register("resolvers.libraries",function(v) helpers.trace=v end)  trackers.register("resolvers.locating",function(v) helpers.trace=v end) -helpers.report=logs.reporter("resolvers","libraries")  helpers.sequence={    "already loaded",    "preload table", @@ -16258,7 +16430,7 @@ helpers.sequence={  }  local pattern=Cs(P("!")^0/""*(P("/")*P(-1)/"/"+P("/")^1/"/"+1)^0)  function helpers.cleanpath(path)  -  return resolvers.resolve(lpegmatch(pattern,path)) +  return resolveprefix(lpegmatch(pattern,path))  end  local loadedaslib=helpers.loadedaslib  local getextraluapaths=package.extraluapaths @@ -16395,7 +16567,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-tmf"] = package.loaded["data-tmf"] or true --- original size: 2600, stripped down to: 1627 +-- original size: 2601, stripped down to: 1627  if not modules then modules={} end modules ['data-tmf']={    version=1.001, @@ -16451,7 +16623,7 @@ do -- create closure to overcome 200 locals limit  package.loaded["data-lst"] = package.loaded["data-lst"] or true --- original size: 2654, stripped down to: 2301 +-- original size: 2734, stripped down to: 2354  if not modules then modules={} end modules ['data-lst']={    version=1.001, @@ -16460,10 +16632,13 @@ if not modules then modules={} end modules ['data-lst']={    copyright="PRAGMA ADE / ConTeXt Development Team",    license="see context related readme files"  } -local find,concat,upper,format=string.find,table.concat,string.upper,string.format +local rawget,type,next=rawget,type,next +local find,concat,upper=string.find,table.concat,string.upper  local fastcopy,sortedpairs=table.fastcopy,table.sortedpairs -resolvers.listers=resolvers.listers or {}  local resolvers=resolvers +local listers=resolvers.listers or {} +resolvers.listers=listers +local resolveprefix=resolvers.resolve  local report_lists=logs.reporter("resolvers","lists")  local function tabstr(str)    if type(str)=='table' then @@ -16472,7 +16647,7 @@ local function tabstr(str)      return str    end  end -function resolvers.listers.variables(pattern) +function listers.variables(pattern)    local instance=resolvers.instance    local environment=instance.environment    local variables=instance.variables @@ -16493,10 +16668,10 @@ function resolvers.listers.variables(pattern)    for key,value in sortedpairs(configured) do      if key~="" and (pattern=="" or find(upper(key),pattern)) then        report_lists(key) -      report_lists("  env: %s",tabstr(rawget(environment,key))  or "unset") -      report_lists("  var: %s",tabstr(configured[key])      or "unset") -      report_lists("  exp: %s",tabstr(expansions[key])      or "unset") -      report_lists("  res: %s",tabstr(resolvers.resolve(expansions[key])) or "unset") +      report_lists("  env: %s",tabstr(rawget(environment,key))    or "unset") +      report_lists("  var: %s",tabstr(configured[key])        or "unset") +      report_lists("  exp: %s",tabstr(expansions[key])        or "unset") +      report_lists("  res: %s",tabstr(resolveprefix(expansions[key])) or "unset")      end    end    instance.environment=fastcopy(env) @@ -16504,15 +16679,15 @@ function resolvers.listers.variables(pattern)    instance.expansions=fastcopy(exp)  end  local report_resolved=logs.reporter("system","resolved") -function resolvers.listers.configurations() +function listers.configurations()    local configurations=resolvers.instance.specification    for i=1,#configurations do -    report_resolved("file : %s",resolvers.resolve(configurations[i])) +    report_resolved("file : %s",resolveprefix(configurations[i]))    end    report_resolved("")    local list=resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec))    for i=1,#list do -    local li=resolvers.resolve(list[i]) +    local li=resolveprefix(list[i])      if lfs.isdir(li) then        report_resolved("path - %s",li)      else @@ -16951,8 +17126,8 @@ end -- of closure  -- used libraries    : l-lua.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-sto.lua util-prs.lua util-fmt.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-mrg.lua util-tpl.lua util-env.lua luat-env.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua util-lib.lua luat-sta.lua luat-fmt.lua  -- skipped libraries : - --- original bytes    : 699655 --- stripped bytes    : 249540 +-- original bytes    : 704727 +-- stripped bytes    : 250243  -- end library merge  | 
