summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/data-res.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/data-res.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/data-res.lua1057
1 files changed, 503 insertions, 554 deletions
diff --git a/Master/texmf-dist/tex/context/base/data-res.lua b/Master/texmf-dist/tex/context/base/data-res.lua
index d28a8a69767..73f3cc337e7 100644
--- a/Master/texmf-dist/tex/context/base/data-res.lua
+++ b/Master/texmf-dist/tex/context/base/data-res.lua
@@ -12,7 +12,7 @@ if not modules then modules = { } end modules ['data-res'] = {
-- instance but for practical purposes we now avoid this and use a
-- instance variable. We always have one instance active (sort of global).
--- todo: cache:/// home:///
+-- todo: cache:/// home:/// selfautoparent:/// (sometime end 2012)
local format, gsub, find, lower, upper, match, gmatch = string.format, string.gsub, string.find, string.lower, string.upper, string.match, string.gmatch
local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys
@@ -55,22 +55,65 @@ resolvers.criticalvars = allocate { "SELFAUTOLOC", "SELFAUTODIR", "SELFAUTOPARE
resolvers.luacnfname = 'texmfcnf.lua'
resolvers.luacnfstate = "unknown"
--- resolvers.luacnfspec = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}' -- what a rubish path
-
--- changed by Taco Hoekwater to make <root>/texmfnf.lua take precedence,
--- while still allowing <root>/texmf/texmfnf.lua and
--- <root>/texmf/web2c/texmfnf.lua (in that order)
-resolvers.luacnfspec = '{selfautodir:,selfautoparent:};{selfautodir:,selfautoparent:}{/share,}/texmf{-local,};{selfautodir:,selfautoparent:}{/share,}/texmf{-local,}/web2c'
-
+-- The web2c tex binaries as well as kpse have built in paths for the configuration
+-- files and there can be a depressing truckload of them. This is actually the weak
+-- spot of a distribution. So we don't want:
+--
+-- resolvers.luacnfspec = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}'
+--
+-- but instead use:
+--
+-- resolvers.luacnfspec = 'selfautoparent:{/texmf{-local,}{,/web2c}}'
+--
+-- which does not make texlive happy as there is a texmf-local tree one level up
+-- (sigh), so we need this. (We can assume web2c as mkiv does not run on older
+-- texlives anyway.
+--
+-- texlive:
+--
+-- selfautodir:
+-- selfautoparent:
+-- selfautodir:share/texmf-local/web2c
+-- selfautodir:share/texmf/web2c
+-- selfautodir:texmf-local/web2c
+-- selfautodir:texmf/web2c
+-- selfautoparent:share/texmf-local/web2c
+-- selfautoparent:share/texmf/web2c
+-- selfautoparent:texmf-local/web2c
+-- selfautoparent:texmf/web2c
+--
+-- minimals:
+--
+-- home:texmf/web2c
+-- selfautoparent:texmf-local/web2c
+-- selfautoparent:texmf-context/web2c
+-- selfautoparent:texmf/web2c
+
+if this_is_texlive then
+ -- resolvers.luacnfspec = '{selfautodir:,selfautoparent:}{,{/share,}/texmf{-local,}/web2c}'
+ -- resolvers.luacnfspec = '{selfautodir:{/share,}/texmf-local/web2c,selfautoparent:{/share,}/texmf{-local,}/web2c}'
+ -- resolvers.luacnfspec = 'selfautodir:/texmf-local/web2c;selfautoparent:/texmf{-local,}/web2c'
+ resolvers.luacnfspec = 'selfautodir:;selfautoparent:;{selfautodir:,selfautoparent:}{/share,}/texmf{-local,}/web2c'
+else
+ resolvers.luacnfspec = 'home:texmf/web2c;selfautoparent:texmf{-local,-context,}/web2c'
+end
+
+-- which (as we want users to use the web2c path) be can be simplified to this:
+--
+-- if environment and environment.ownpath and string.find(environment.ownpath,"[\\/]texlive[\\/]") then
+-- resolvers.luacnfspec = 'selfautodir:/texmf-local/web2c,selfautoparent:/texmf-local/web2c,selfautoparent:/texmf/web2c'
+-- else
+-- resolvers.luacnfspec = 'selfautoparent:/texmf-local/web2c,selfautoparent:/texmf/web2c'
+-- end
--~ -- not yet, some reporters expect strings
--~ resolvers.luacnfspec = {
---~ "selfautoparent:/texmf-local",
+--~ "selfautoparent:/texmf-local", -- is actually a user mistake
--~ "selfautoparent:/texmf-local/web2c",
---~ "selfautoparent:/texmf",
+--~ "selfautoparent:/texmf", -- idem
--~ "selfautoparent:/texmf/web2c",
---~ "selfautoparent:",
+--~ "selfautoparent:", -- idem
--~ }
local unset_variable = "unset"
@@ -93,7 +136,7 @@ local instance = resolvers.instance or nil -- the current one (fast access)
function resolvers.setenv(key,value,raw)
if instance then
-- this one will be consulted first when we stay inside
- -- the current environment
+ -- the current environment (prefixes are not resolved here)
instance.environment[key] = value
-- we feed back into the environment, and as this is used
-- by other applications (via os.execute) we need to make
@@ -173,6 +216,7 @@ function resolvers.newinstance() -- todo: all vars will become lowercase and alp
remember = true,
diskcache = true,
renewcache = false,
+ renewtree = false,
loaderror = false,
savelists = true,
pattern = nil, -- lists
@@ -264,7 +308,7 @@ local function makepathexpression(str)
end
end
-local function reportcriticalvariables()
+local function reportcriticalvariables(cnfspec)
if trace_locating then
for i=1,#resolvers.criticalvars do
local k = resolvers.criticalvars[i]
@@ -272,6 +316,14 @@ local function reportcriticalvariables()
report_resolving("variable '%s' set to '%s'",k,v)
end
report_resolving()
+ if cnfspec then
+ if type(cnfspec) == "table" then
+ report_resolving("using configuration specification '%s'",concat(cnfspec,","))
+ else
+ report_resolving("using configuration specification '%s'",cnfspec)
+ end
+ end
+ report_resolving()
end
reportcriticalvariables = function() end
end
@@ -286,7 +338,7 @@ local function identify_configuration_files()
else
resolvers.luacnfstate = "environment"
end
- reportcriticalvariables()
+ reportcriticalvariables(cnfspec)
local cnfpaths = expandedpathfromlist(resolvers.splitpath(cnfspec))
local luacnfname = resolvers.luacnfname
for i=1,#cnfpaths do
@@ -322,6 +374,19 @@ local function load_configuration_files()
if blob then
local setups = instance.setups
local data = blob()
+ local parent = data and data.parent
+ if parent then
+ local filename = filejoin(pathname,parent)
+ local realname = resolvers.resolve(filename) -- no shortcut
+ local blob = loadfile(realname)
+ if blob then
+ local parentdata = blob()
+ if parentdata then
+ report_resolving("loading configuration file '%s'",filename)
+ data = table.merged(parentdata,data)
+ end
+ end
+ end
data = data and data.content
if data then
if trace_locating then
@@ -411,11 +476,6 @@ local function locate_file_databases()
local runtime = stripped == path
path = resolvers.cleanpath(path)
local spec = resolvers.splitmethod(stripped)
- -- TH Original did this the other way around (elseif and if tests
- -- reversed) but then the else branch was never reached, as 'runtime'
- -- would effectively be ignored. In turn, that meant that the wrong
- -- locator method was used, such that tree: and file: were treated
- -- identically (cached and no runtime search).
if runtime and (spec.noscheme or spec.scheme == "file") then
stripped = "tree:///" .. stripped
elseif spec.scheme == "cache" or spec.scheme == "file" then
@@ -423,7 +483,7 @@ local function locate_file_databases()
end
if trace_locating then
if runtime then
- report_resolving("locating list of '%s' (runtime)",path)
+ report_resolving("locating list of '%s' (runtime) (%s)",path,stripped)
else
report_resolving("locating list of '%s' (cached)",path)
end
@@ -467,6 +527,39 @@ local function save_file_databases() -- will become cachers
end
end
+function resolvers.renew(hashname)
+ if hashname and hashname ~= "" then
+ local expanded = resolvers.expansion(hashname) or ""
+ if expanded ~= "" then
+ if trace_locating then
+ report_resolving("identifying tree '%s' from '%s'",expanded,hashname)
+ end
+ hashname = expanded
+ else
+ if trace_locating then
+ report_resolving("identifying tree '%s'",hashname)
+ end
+ end
+ local realpath = resolvers.resolve(hashname)
+ if lfs.isdir(realpath) then
+ if trace_locating then
+ report_resolving("using path '%s'",realpath)
+ end
+ methodhandler('generators',hashname)
+ -- could be shared
+ local content = instance.files[hashname]
+ caches.collapsecontent(content)
+ if trace_locating then
+ report_resolving("saving tree '%s'",hashname)
+ end
+ caches.savecontent(hashname,"files",content)
+ -- till here
+ else
+ report_resolving("invalid path '%s'",realpath)
+ end
+ end
+end
+
local function load_databases()
locate_file_databases()
if instance.diskcache and not instance.renewcache then
@@ -754,6 +847,7 @@ local function collect_files(names)
if dname == "" or find(dname,"^%.") then
dname = false
else
+dname = gsub(dname,"*","%.*")
dname = "/" .. dname .. "$"
end
local hashes = instance.hashes
@@ -813,9 +907,22 @@ local function collect_files(names)
return noffiles > 0 and filelist or nil
end
-function resolvers.registerintrees(name)
- if not find(name,"^%.") then
- instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one
+local fit = { }
+
+function resolvers.registerintrees(filename,format,filetype,usedmethod,foundname)
+ local foundintrees = instance.foundintrees
+ if usedmethod == "direct" and filename == foundname and fit[foundname] then
+ -- just an extra lookup after a test on presence
+ else
+ local t = {
+ filename = filename,
+ format = format ~= "" and format or nil,
+ filetype = filetype ~= "" and filetype or nil,
+ usedmethod = usedmethod,
+ foundname = foundname,
+ }
+ fit[foundname] = t
+ foundintrees[#foundintrees+1] = t
end
end
@@ -835,588 +942,423 @@ end
local preparetreepattern = Cs((P(".")/"%%." + P("-")/"%%-" + P(1))^0 * Cc("$"))
--- this one is split in smaller functions but it needs testing
-
-local function collect_instance_files(filename,askedformat,allresults) -- todo : plugin (scanners, checkers etc)
- local result = { }
- local stamp = nil
- askedformat = askedformat or ""
- filename = collapsepath(filename)
- -- speed up / beware: format problem
- if instance.remember and not allresults then
- stamp = filename .. "--" .. askedformat
- if instance.found[stamp] then
+-- -- -- begin of main file search routing -- -- -- needs checking as previous has been patched
+
+local collect_instance_files
+
+local function find_analyze(filename,askedformat,allresults)
+ local filetype, wantedfiles, ext = '', { }, fileextname(filename)
+ -- too tricky as filename can be bla.1.2.3:
+ --
+ -- if not suffixmap[ext] then
+ -- wantedfiles[#wantedfiles+1] = filename
+ -- end
+ wantedfiles[#wantedfiles+1] = filename
+ if askedformat == "" then
+ if ext == "" or not suffixmap[ext] then
+ local defaultsuffixes = resolvers.defaultsuffixes
+ for i=1,#defaultsuffixes do
+ local forcedname = filename .. '.' .. defaultsuffixes[i]
+ wantedfiles[#wantedfiles+1] = forcedname
+ filetype = resolvers.formatofsuffix(forcedname)
+ if trace_locating then
+ report_resolving("forcing filetype '%s'",filetype)
+ end
+ end
+ else
+ filetype = resolvers.formatofsuffix(filename)
if trace_locating then
- report_resolving("remembered file '%s'",filename)
+ report_resolving("using suffix based filetype '%s'",filetype)
end
- resolvers.registerintrees(filename) -- for tracing used files
- return instance.found[stamp]
end
- end
- if not dangerous[askedformat] then
- if isreadable(filename) then
- if trace_detail then
- report_resolving("file '%s' found directly",filename)
- end
- if stamp then
- instance.found[stamp] = { filename }
+ else
+ if ext == "" or not suffixmap[ext] then
+ local format_suffixes = suffixes[askedformat]
+ if format_suffixes then
+ for i=1,#format_suffixes do
+ wantedfiles[#wantedfiles+1] = filename .. "." .. format_suffixes[i]
+ end
end
- return { filename }
+ end
+ filetype = askedformat
+ if trace_locating then
+ report_resolving("using given filetype '%s'",filetype)
end
end
+ return filetype, wantedfiles
+end
+
+local function find_direct(filename,allresults)
+ if not dangerous[askedformat] and isreadable(filename) then
+ if trace_detail then
+ report_resolving("file '%s' found directly",filename)
+ end
+ return "direct", { filename }
+ end
+end
+
+local function find_wildcard(filename,allresults)
if find(filename,'%*') then
if trace_locating then
report_resolving("checking wildcard '%s'", filename)
end
- result = resolvers.findwildcardfiles(filename) -- we can use th elocal
- elseif file.is_qualified_path(filename) then
- if isreadable(filename) then
- if trace_locating then
- report_resolving("qualified name '%s'", filename)
- end
- result = { filename }
- else
- local forcedname, ok, suffix = "", false, fileextname(filename)
- if suffix == "" then -- why
- local format_suffixes = askedformat == "" and resolvers.defaultsuffixes or suffixes[askedformat]
- if format_suffixes then
- for i=1,#format_suffixes do
- local s = format_suffixes[i]
- forcedname = filename .. "." .. s
- if isreadable(forcedname) then
- if trace_locating then
- report_resolving("no suffix, forcing format filetype '%s'", s)
- end
- result, ok = { forcedname }, true
- break
- end
- end
- end
- end
- if not ok and suffix ~= "" then
- -- try to find in tree (no suffix manipulation), here we search for the
- -- matching last part of the name
- local basename = filebasename(filename)
- local pattern = lpegmatch(preparetreepattern,filename)
- -- messy .. to be sorted out
- local savedformat = askedformat
- local format = savedformat or ""
- if format == "" then
- askedformat = resolvers.formatofsuffix(suffix)
- end
- if not format then
- askedformat = "othertextfiles" -- kind of everything, maybe texinput is better
- end
- --
- if basename ~= filename then
- local resolved = collect_instance_files(basename,askedformat,allresults)
- if #result == 0 then -- shouldn't this be resolved ?
- local lowered = lower(basename)
- if filename ~= lowered then
- resolved = collect_instance_files(lowered,askedformat,allresults)
- end
- end
- resolvers.format = savedformat
- --
- for r=1,#resolved do
- local rr = resolved[r]
- if find(rr,pattern) then
- result[#result+1], ok = rr, true
- end
- end
- end
- -- a real wildcard:
- --
- -- if not ok then
- -- local filelist = collect_files({basename})
- -- for f=1,#filelist do
- -- local ff = filelist[f][3] or ""
- -- if find(ff,pattern) then
- -- result[#result+1], ok = ff, true
- -- end
- -- end
- -- end
- end
- if not ok and trace_locating then
- report_resolving("qualified name '%s'", filename)
- end
+ local method, result = resolvers.findwildcardfiles(filename)
+ if result then
+ return "wildcard", result
end
- else
- -- search spec
- local filetype, done, wantedfiles, ext = '', false, { }, fileextname(filename)
- -- -- tricky as filename can be bla.1.2.3
- -- if not suffixmap[ext] then --- probably needs to be done elsewhere too
- -- wantedfiles[#wantedfiles+1] = filename
- -- end
- wantedfiles[#wantedfiles+1] = filename
- if askedformat == "" then
- if ext == "" or not suffixmap[ext] then
- local defaultsuffixes = resolvers.defaultsuffixes
- for i=1,#defaultsuffixes do
- local forcedname = filename .. '.' .. defaultsuffixes[i]
- wantedfiles[#wantedfiles+1] = forcedname
- filetype = resolvers.formatofsuffix(forcedname)
+ end
+end
+
+local function find_qualified(filename,allresults) -- this one will be split too
+ if not file.is_qualified_path(filename) then
+ return
+ end
+ if trace_locating then
+ report_resolving("checking qualified name '%s'", filename)
+ end
+ if isreadable(filename) then
+ if trace_detail then
+ report_resolving("qualified file '%s' found", filename)
+ end
+ return "qualified", { filename }
+ end
+ if trace_detail then
+ report_resolving("locating qualified file '%s'", filename)
+ end
+ local forcedname, suffix = "", fileextname(filename)
+ if suffix == "" then -- why
+ local format_suffixes = askedformat == "" and resolvers.defaultsuffixes or suffixes[askedformat]
+ if format_suffixes then
+ for i=1,#format_suffixes do
+ local s = format_suffixes[i]
+ forcedname = filename .. "." .. s
+ if isreadable(forcedname) then
if trace_locating then
- report_resolving("forcing filetype '%s'",filetype)
+ report_resolving("no suffix, forcing format filetype '%s'", s)
end
+ return "qualified", { forcedname }
end
- else
- filetype = resolvers.formatofsuffix(filename)
- if trace_locating then
- report_resolving("using suffix based filetype '%s'",filetype)
+ end
+ end
+ end
+ if suffix and suffix ~= "" then
+ -- try to find in tree (no suffix manipulation), here we search for the
+ -- matching last part of the name
+ local basename = filebasename(filename)
+ local pattern = lpegmatch(preparetreepattern,filename)
+ -- messy .. to be sorted out
+ local savedformat = askedformat
+ local format = savedformat or ""
+ if format == "" then
+ askedformat = resolvers.formatofsuffix(suffix)
+ end
+ if not format then
+ askedformat = "othertextfiles" -- kind of everything, maybe all
+ end
+ --
+ if basename ~= filename then
+ local resolved = collect_instance_files(basename,askedformat,allresults)
+ if #resolved == 0 then
+ local lowered = lower(basename)
+ if filename ~= lowered then
+ resolved = collect_instance_files(lowered,askedformat,allresults)
end
end
- else
- if ext == "" or not suffixmap[ext] then
- local format_suffixes = suffixes[askedformat]
- if format_suffixes then
- for i=1,#format_suffixes do
- wantedfiles[#wantedfiles+1] = filename .. "." .. format_suffixes[i]
+ resolvers.format = savedformat
+ --
+ if #resolved > 0 then
+ local result = { }
+ for r=1,#resolved do
+ local rr = resolved[r]
+ if find(rr,pattern) then
+ result[#result+1] = rr
end
end
- end
- filetype = askedformat
- if trace_locating then
- report_resolving("using given filetype '%s'",filetype)
+ if #result > 0 then
+ return "qualified", result
+ end
end
end
- local typespec = resolvers.variableofformat(filetype)
- local pathlist = resolvers.expandedpathlist(typespec)
- if not pathlist or #pathlist == 0 then
- -- no pathlist, access check only / todo == wildcard
- if trace_detail then
- report_resolving("checking filename '%s', filetype '%s', wanted files '%s'",filename, filetype or '?',concat(wantedfiles," | "))
- end
- for k=1,#wantedfiles do
- local fname = wantedfiles[k]
- if fname and isreadable(fname) then
- filename, done = fname, true
- result[#result+1] = filejoin('.',fname)
- break
- end
+ -- a real wildcard:
+ --
+ -- local filelist = collect_files({basename})
+ -- result = { }
+ -- for f=1,#filelist do
+ -- local ff = filelist[f][3] or ""
+ -- if find(ff,pattern) then
+ -- result[#result+1], ok = ff, true
+ -- end
+ -- end
+ -- if #result > 0 then
+ -- return "qualified", result
+ -- end
+ end
+end
+
+local function check_subpath(fname)
+ if isreadable(fname) then
+ if trace_detail then
+ report_resolving("found '%s' by deep scanning",fname)
+ end
+ return fname
+ end
+end
+
+local function find_intree(filename,filetype,wantedfiles,allresults)
+ local typespec = resolvers.variableofformat(filetype)
+ local pathlist = resolvers.expandedpathlist(typespec)
+ local method = "intree"
+ if pathlist and #pathlist > 0 then
+ -- list search
+ local filelist = collect_files(wantedfiles)
+ local dirlist = { }
+ if filelist then
+ for i=1,#filelist do
+ dirlist[i] = filedirname(filelist[i][3]) .. "/" -- was [2] .. gamble
end
- -- this is actually 'other text files' or 'any' or 'whatever'
- local filelist = collect_files(wantedfiles)
- local fl = filelist and filelist[1]
- if fl then
- filename = fl[3] -- not local?
- result[#result+1] = resolvers.resolve(filename)
- done = true
+ end
+ if trace_detail then
+ report_resolving("checking filename '%s'",filename)
+ end
+ local result = { }
+ for k=1,#pathlist do
+ local path = pathlist[k]
+ local pathname = lpegmatch(inhibitstripper,path)
+ local doscan = path == pathname -- no ^!!
+ if not find (pathname,'//$') then
+ doscan = false -- we check directly on the path
end
- else
- -- list search
- local filelist = collect_files(wantedfiles)
- local dirlist = { }
- if filelist then
- for i=1,#filelist do
- dirlist[i] = filedirname(filelist[i][3]) .. "/" -- was [2] .. gamble
+ local done = false
+ -- using file list
+ if filelist then -- database
+ -- compare list entries with permitted pattern -- /xx /xx//
+ local expression = makepathexpression(pathname)
+ if trace_detail then
+ report_resolving("using pattern '%s' for path '%s'",expression,pathname)
end
- end
- if trace_detail then
- report_resolving("checking filename '%s'",filename)
- end
- for k=1,#pathlist do
- local path = pathlist[k]
- local pathname = lpegmatch(inhibitstripper,path)
- local doscan = path == pathname -- no ^!!
- if not find (pathname, '//$') then doscan = false end
- done = false
- -- using file list
- if filelist then
- -- compare list entries with permitted pattern -- /xx /xx//
- local expression = makepathexpression(pathname)
- if trace_detail then
- report_resolving("using pattern '%s' for path '%s'",expression,pathname)
- end
- for k=1,#filelist do
- local fl = filelist[k]
- local f = fl[2]
- local d = dirlist[k]
- if find(d,expression) then
- -- todo, test for readable
- result[#result+1] = resolvers.resolve(fl[3]) -- no shortcut
- done = true
- if allresults then
- if trace_detail then
- report_resolving("match to '%s' in hash for file '%s' and path '%s', continue scanning",expression,f,d)
- end
- else
- if trace_detail then
- report_resolving("match to '%s' in hash for file '%s' and path '%s', quit scanning",expression,f,d)
- end
- break
+ for k=1,#filelist do
+ local fl = filelist[k]
+ local f = fl[2]
+ local d = dirlist[k]
+ if find(d,expression) then
+ -- todo, test for readable
+ result[#result+1] = resolvers.resolve(fl[3]) -- no shortcut
+ done = true
+ if allresults then
+ if trace_detail then
+ report_resolving("match to '%s' in hash for file '%s' and path '%s', continue scanning",expression,f,d)
end
- elseif trace_detail then
- report_resolving("no match to '%s' in hash for file '%s' and path '%s'",expression,f,d)
+ else
+ if trace_detail then
+ report_resolving("match to '%s' in hash for file '%s' and path '%s', quit scanning",expression,f,d)
+ end
+ break
end
+ elseif trace_detail then
+ report_resolving("no match to '%s' in hash for file '%s' and path '%s'",expression,f,d)
end
end
- if not done then
- -- check if on disk / unchecked / does not work at all / also zips
- -- TH perhaps it did not work because of missing resolvers.resolve()
- -- and resolvers.scanfiles() calls ...
- pathname = resolvers.resolve(pathname)
- local scheme = url.hasscheme(pathname)
- if not scheme or scheme == "file" then
- local pname = gsub(pathname,"%.%*$",'')
- if not find(pname,"%*") then
- local ppname = gsub(pname,"/+$","")
- if can_be_dir(ppname) then
- local files = {}
- if doscan then files = resolvers.scanfiles(ppname) end
+ end
+ if done then
+ method = "database"
+ else
+ method = "filesystem" -- bonus, even when !! is specified
+ pathname = gsub(pathname,"/+$","")
+ pathname = resolvers.resolve(pathname)
+ local scheme = url.hasscheme(pathname)
+ if not scheme or scheme == "file" then
+ local pname = gsub(pathname,"%.%*$",'')
+ if not find(pname,"%*") then
+ if can_be_dir(pname) then
+ -- quick root scan first
+ for k=1,#wantedfiles do
+ local w = wantedfiles[k]
+ local fname = check_subpath(filejoin(pname,w))
+ if fname then
+ result[#result+1] = fname
+ done = true
+ if not allresults then
+ break
+ end
+ end
+ end
+ if not done and doscan then
+ -- collect files in path (and cache the result)
+ local files = resolvers.simplescanfiles(pname,false,true)
for k=1,#wantedfiles do
local w = wantedfiles[k]
- local subpath = ''
- if files[w] then
- subpath = type(files[w]) == "table" and files[w][1] or files[w]
- end
- local fname = filejoin(ppname,subpath,w)
- if isreadable(fname) then
- if trace_detail then
- report_resolving("found '%s' by scanning",fname)
+ local subpath = files[w]
+ if not subpath or subpath == "" then
+ -- rootscan already done
+ elseif type(subpath) == "string" then
+ local fname = check_subpath(filejoin(pname,subpath,w))
+ if fname then
+ result[#result+1] = fname
+ done = true
+ if not allresults then
+ break
+ end
+ end
+ else
+ for i=1,#subpath do
+ local sp = subpath[i]
+ if sp == "" then
+ -- roottest already done
+ else
+ local fname = check_subpath(filejoin(pname,sp,w))
+ if fname then
+ result[#result+1] = fname
+ done = true
+ if not allresults then
+ break
+ end
+ end
+ end
+ end
+ if done and not allresults then
+ break
end
- result[#result+1] = fname
- done = true
- if not allresults then break end
end
end
- else
- -- no access needed for non existing path, speedup (esp in large tree with lots of fake)
end
end
+ else
+ -- no access needed for non existing path, speedup (esp in large tree with lots of fake)
end
end
- if not done and doscan then
- -- todo: slow path scanning ... although we now have tree:// supported in $TEXMF
- end
- if done and not allresults then break end
+ end
+ -- todo recursive scanning
+ if done and not allresults then
+ break
end
end
+ if #result > 0 then
+ return method, result
+ end
end
- for k=1,#result do
- local rk = collapsepath(result[k])
- result[k] = rk
- resolvers.registerintrees(rk) -- for tracing used files
+end
+
+local function find_onpath(filename,filetype,wantedfiles,allresults)
+ if trace_detail then
+ report_resolving("checking filename '%s', filetype '%s', wanted files '%s'",filename, filetype or '?',concat(wantedfiles," | "))
end
- if stamp then
- instance.found[stamp] = result
+ local result = { }
+ for k=1,#wantedfiles do
+ local fname = wantedfiles[k]
+ if fname and isreadable(fname) then
+ filename = fname
+ result[#result+1] = filejoin('.',fname)
+ if not allresults then
+ break
+ end
+ end
+ end
+ if #result > 0 then
+ return "onpath", result
+ end
+end
+
+local function find_otherwise(filename,filetype,wantedfiles,allresults) -- other text files | any | whatever
+ local filelist = collect_files(wantedfiles)
+ local fl = filelist and filelist[1]
+ if fl then
+ return "otherwise", { resolvers.resolve(fl[3]) } -- filename
end
- return result
end
--- -- -- begin of main file search routing -- -- --
-
---~ local collect_instance_files
-
---~ local function find_direct(filename)
---~ if not dangerous[askedformat] and isreadable(filename) then
---~ if trace_detail then
---~ report_resolving("file '%s' found directly",filename)
---~ end
---~ return { filename }
---~ end
---~ end
-
---~ local function find_wildcard(filename)
---~ if find(filename,'%*') then
---~ if trace_locating then
---~ report_resolving("checking wildcard '%s'", filename)
---~ end
---~ return resolvers.findwildcardfiles(filename) -- we can use the local
---~ end
---~ end
-
---~ local function find_qualified(filename) -- this one will be split too
---~ if not file.is_qualified_path(filename) then
---~ return
---~ end
---~ if trace_locating then
---~ report_resolving("checking qualified name '%s'", filename)
---~ end
---~ if isreadable(filename) then
---~ if trace_detail then
---~ report_resolving("qualified file '%s' found", filename)
---~ end
---~ return { filename }
---~ else
---~ if trace_detail then
---~ report_resolving("locating qualified file '%s'", filename)
---~ end
---~ local forcedname, suffix = "", fileextname(filename)
---~ if suffix == "" then -- why
---~ local format_suffixes = askedformat == "" and resolvers.defaultsuffixes or suffixes[askedformat]
---~ if format_suffixes then
---~ for i=1,#format_suffixes do
---~ local s = format_suffixes[i]
---~ forcedname = filename .. "." .. s
---~ if isreadable(forcedname) then
---~ if trace_locating then
---~ report_resolving("no suffix, forcing format filetype '%s'", s)
---~ end
---~ return { forcedname }
---~ end
---~ end
---~ end
---~ end
---~ if suffix ~= "" then
---~ -- try to find in tree (no suffix manipulation), here we search for the
---~ -- matching last part of the name
---~ local basename = filebasename(filename)
---~ local pattern = lpegmatch(preparetreepattern,filename)
---~ -- messy .. to be sorted out
---~ local savedformat = askedformat
---~ local format = savedformat or ""
---~ if format == "" then
---~ askedformat = resolvers.formatofsuffix(suffix)
---~ end
---~ if not format then
---~ askedformat = "othertextfiles" -- kind of everything, maybe all
---~ end
---~ --
---~ if basename ~= filename then
---~ local resolved = collect_instance_files(basename,askedformat,allresults)
---~ if #resolved == 0 then
---~ local lowered = lower(basename)
---~ if filename ~= lowered then
---~ resolved = collect_instance_files(lowered,askedformat,allresults)
---~ end
---~ end
---~ resolvers.format = savedformat
---~ --
---~ if #resolved > 0 then
---~ local result = { }
---~ for r=1,#resolved do
---~ local rr = resolved[r]
---~ if find(rr,pattern) then
---~ result[#result+1] = rr
---~ end
---~ end
---~ if #result > 0 then
---~ return result
---~ end
---~ end
---~ end
---~ -- a real wildcard:
---~ --
---~ -- local filelist = collect_files({basename})
---~ -- result = { }
---~ -- for f=1,#filelist do
---~ -- local ff = filelist[f][3] or ""
---~ -- if find(ff,pattern) then
---~ -- result[#result+1], ok = ff, true
---~ -- end
---~ -- end
---~ -- if #result > 0 then
---~ -- return result
---~ -- end
---~ end
---~ end
---~ end
-
---~ local function find_analyze(filename,askedformat)
---~ local filetype, wantedfiles, ext = '', { }, fileextname(filename)
---~ -- too tricky as filename can be bla.1.2.3:
---~ --
---~ -- if not suffixmap[ext] then
---~ -- wantedfiles[#wantedfiles+1] = filename
---~ -- end
---~ wantedfiles[#wantedfiles+1] = filename
---~ if askedformat == "" then
---~ if ext == "" or not suffixmap[ext] then
---~ local defaultsuffixes = resolvers.defaultsuffixes
---~ for i=1,#defaultsuffixes do
---~ local forcedname = filename .. '.' .. defaultsuffixes[i]
---~ wantedfiles[#wantedfiles+1] = forcedname
---~ filetype = resolvers.formatofsuffix(forcedname)
---~ if trace_locating then
---~ report_resolving("forcing filetype '%s'",filetype)
---~ end
---~ end
---~ else
---~ filetype = resolvers.formatofsuffix(filename)
---~ if trace_locating then
---~ report_resolving("using suffix based filetype '%s'",filetype)
---~ end
---~ end
---~ else
---~ if ext == "" or not suffixmap[ext] then
---~ local format_suffixes = suffixes[askedformat]
---~ if format_suffixes then
---~ for i=1,#format_suffixes do
---~ wantedfiles[#wantedfiles+1] = filename .. "." .. format_suffixes[i]
---~ end
---~ end
---~ end
---~ filetype = askedformat
---~ if trace_locating then
---~ report_resolving("using given filetype '%s'",filetype)
---~ end
---~ end
---~ return filetype, wantedfiles
---~ end
-
---~ local function find_intree(filename,filetype,wantedfiles)
---~ local typespec = resolvers.variableofformat(filetype)
---~ local pathlist = resolvers.expandedpathlist(typespec)
---~ if pathlist and #pathlist > 0 then
---~ -- list search
---~ local filelist = collect_files(wantedfiles)
---~ local dirlist = { }
---~ if filelist then
---~ for i=1,#filelist do
---~ dirlist[i] = filedirname(filelist[i][3]) .. "/" -- was [2] .. gamble
---~ end
---~ end
---~ if trace_detail then
---~ report_resolving("checking filename '%s'",filename)
---~ end
---~ local result = { }
---~ for k=1,#pathlist do
---~ local path = pathlist[k]
---~ local pathname = lpegmatch(inhibitstripper,path)
---~ local doscan = path == pathname -- no ^!!
---~ local done = false
---~ -- using file list
---~ if filelist then
---~ -- compare list entries with permitted pattern -- /xx /xx//
---~ local expression = makepathexpression(pathname)
---~ if trace_detail then
---~ report_resolving("using pattern '%s' for path '%s'",expression,pathname)
---~ end
---~ for k=1,#filelist do
---~ local fl = filelist[k]
---~ local f = fl[2]
---~ local d = dirlist[k]
---~ if find(d,expression) then
---~ -- todo, test for readable
---~ result[#result+1] = resolvers.resolve(fl[3]) -- no shortcut
---~ done = true
---~ if allresults then
---~ if trace_detail then
---~ report_resolving("match to '%s' in hash for file '%s' and path '%s', continue scanning",expression,f,d)
---~ end
---~ else
---~ if trace_detail then
---~ report_resolving("match to '%s' in hash for file '%s' and path '%s', quit scanning",expression,f,d)
---~ end
---~ break
---~ end
---~ elseif trace_detail then
---~ report_resolving("no match to '%s' in hash for file '%s' and path '%s'",expression,f,d)
---~ end
---~ end
---~ end
---~ if not done and doscan then
---~ -- check if on disk / unchecked / does not work at all / also zips
---~ local scheme = url.hasscheme(pathname)
---~ if not scheme or scheme == "file" then
---~ local pname = gsub(pathname,"%.%*$",'')
---~ if not find(pname,"%*") then
---~ local ppname = gsub(pname,"/+$","")
---~ if can_be_dir(ppname) then
---~ for k=1,#wantedfiles do
---~ local w = wantedfiles[k]
---~ local fname = filejoin(ppname,w)
---~ if isreadable(fname) then
---~ if trace_detail then
---~ report_resolving("found '%s' by scanning",fname)
---~ end
---~ result[#result+1] = fname
---~ done = true
---~ if not allresults then break end
---~ end
---~ end
---~ else
---~ -- no access needed for non existing path, speedup (esp in large tree with lots of fake)
---~ end
---~ end
---~ end
---~ end
---~ if not done and doscan then
---~ -- todo: slow path scanning ... although we now have tree:// supported in $TEXMF
---~ end
---~ if done and not allresults then
---~ return #result > 0 and result
---~ end
---~ end
---~ end
---~ end
-
---~ local function find_onpath(filename,filetype,wantedfiles)
---~ local done = nil
---~ if trace_detail then
---~ report_resolving("checking filename '%s', filetype '%s', wanted files '%s'",filename, filetype or '?',concat(wantedfiles," | "))
---~ end
---~ for k=1,#wantedfiles do
---~ local fname = wantedfiles[k]
---~ if fname and isreadable(fname) then
---~ filename, done = fname, true
---~ result[#result+1] = filejoin('.',fname)
---~ break
---~ end
---~ end
---~ end
-
---~ local function find_otherwise(filename,filetype,wantedfiles) -- other text files | any | whatever
---~ local filelist = collect_files(wantedfiles)
---~ local fl = filelist and filelist[1]
---~ if fl then
---~ return { resolvers.resolve(fl[3]) } -- filename
---~ end
---~ end
-
---~ collect_instance_files = function(filename,askedformat,allresults) -- uses nested
---~ local result, stamp, filetype, wantedfiles
---~ askedformat = askedformat or ""
---~ filename = collapsepath(filename)
---~ if instance.remember and not allresults then
---~ stamp = format("%s--%s", filename, askedformat)
---~ result = stamp and instance.found[stamp]
---~ if result then
---~ if trace_locating then
---~ report_resolving("remembered file '%s'",filename)
---~ end
---~ return result
---~ end
---~ end
---~ result = find_direct (filename,stamp) or
---~ find_wildcard (filename) or
---~ find_qualified(filename)
---~ if not result then
---~ filetype, wantedfiles = find_analyze(filename,askedformat)
---~ result = find_intree (filename,filetype,wantedfiles) or
---~ find_onpath (filename,filetype,wantedfiles) or
---~ find_otherwise(filename,filetype,wantedfiles)
---~ end
---~ if result then
---~ for k=1,#result do
---~ local rk = collapsepath(result[k])
---~ result[k] = rk
---~ resolvers.registerintrees(rk) -- for tracing used files
---~ end
---~ else
---~ result = { } -- maybe false
---~ end
---~ if stamp then
---~ if trace_locating then
---~ report_resolving("remembering file '%s'",filename)
---~ end
---~ instance.found[stamp] = result
---~ end
---~ return result
---~ end
+-- we could have a loop over the 6 functions but then we'd have to
+-- always analyze
+
+collect_instance_files = function(filename,askedformat,allresults) -- uses nested
+ askedformat = askedformat or ""
+ filename = collapsepath(filename)
+ if allresults then
+ -- no need for caching, only used for tracing
+ local filetype, wantedfiles = find_analyze(filename,askedformat)
+ local results = {
+ { find_direct (filename,true) },
+ { find_wildcard (filename,true) },
+ { find_qualified(filename,true) },
+ { find_intree (filename,filetype,wantedfiles,true) },
+ { find_onpath (filename,filetype,wantedfiles,true) },
+ { find_otherwise(filename,filetype,wantedfiles,true) },
+ }
+ local result, status, done = { }, { }, { }
+ for k, r in next, results do
+ local method, list = r[1], r[2]
+ if method and list then
+ for i=1,#list do
+ local c = collapsepath(list[i])
+ if not done[c] then
+ result[#result+1] = c
+ done[c] = true
+ end
+ status[#status+1] = format("%-10s: %s",method,c)
+ end
+ end
+ end
+ if trace_detail then
+ report_resolving("lookup status: %s",table.serialize(status,filename))
+ end
+ return result, status
+ else
+ local method, result, stamp, filetype, wantedfiles
+ if instance.remember then
+ stamp = format("%s--%s", filename, askedformat)
+ result = stamp and instance.found[stamp]
+ if result then
+ if trace_locating then
+ report_resolving("remembered file '%s'",filename)
+ end
+ return result
+ end
+ end
+ method, result = find_direct(filename)
+ if not result then
+ method, result = find_wildcard(filename)
+ if not result then
+ method, result = find_qualified(filename)
+ if not result then
+ filetype, wantedfiles = find_analyze(filename,askedformat)
+ method, result = find_intree(filename,filetype,wantedfiles)
+ if not result then
+ method, result = find_onpath(filename,filetype,wantedfiles)
+ if not result then
+ method, result = find_otherwise(filename,filetype,wantedfiles)
+ end
+ end
+ end
+ end
+ end
+ if result and #result > 0 then
+ local foundname = collapsepath(result[1])
+ resolvers.registerintrees(filename,askedformat,filetype,method,foundname)
+ result = { foundname }
+ else
+ result = { } -- maybe false
+ end
+ if stamp then
+ if trace_locating then
+ report_resolving("remembering file '%s'",filename)
+ end
+ instance.found[stamp] = result
+ end
+ return result
+ end
+end
-- -- -- end of main file search routing -- -- --
+
local function findfiles(filename,filetype,allresults)
- local result = collect_instance_files(filename,filetype or "",allresults)
- if #result == 0 then
+ local result, status = collect_instance_files(filename,filetype or "",allresults)
+ if not result or #result == 0 then
local lowered = lower(filename)
if filename ~= lowered then
- return collect_instance_files(lowered,filetype or "",allresults)
+ result, status = collect_instance_files(lowered,filetype or "",allresults)
end
end
- return result
+ return result or { }, status
end
function resolvers.findfiles(filename,filetype)
@@ -1583,6 +1525,10 @@ function resolvers.load(option)
return files and next(files) and true
end
+function resolvers.loadtime()
+ return statistics.elapsedtime(instance)
+end
+
local function report(str)
if trace_locating then
report_resolving(str) -- has already verbose
@@ -1596,6 +1542,9 @@ function resolvers.dowithfilesandreport(command, files, ...) -- will move
if trace_locating then
report('') -- ?
end
+ if type(files) == "string" then
+ files = { files }
+ end
for f=1,#files do
local file = files[f]
local result = command(file,...)