file-res.lua /size: 6823 b    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['file-res'] = {
2    version   = 1.001,
3    comment   = "companion to supp-fil.mkiv",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    copyright = "PRAGMA ADE / ConTeXt Development Team",
6    license   = "see context related readme files"
7}
8
9local tonumber = tonumber
10local format, find = string.format, string.find
11local isfile = lfs.isfile
12local is_qualified_path = file.is_qualified_path
13local hasscheme, urlescape = url.hasscheme, url.escape
14
15local trace_files   = false  trackers.register("resolvers.readfile",         function(v) trace_files   = v end)
16local trace_details = false  trackers.register("resolvers.readfile.details", function(v) trace_details = v end)
17local report_files  = logs.reporter("files","readfile")
18
19resolvers.maxreadlevel = 2
20
21directives.register("resolvers.maxreadlevel", function(v)
22 -- resolvers.maxreadlevel = (v == false and 0) or (v == true and 2) or tonumber(v) or 2
23    resolvers.maxreadlevel = v == false and 0 or tonumber(v) or 2
24end)
25
26local finders, loaders, openers = resolvers.finders, resolvers.loaders, resolvers.openers
27
28local found = { } -- can best be done in the resolver itself
29
30local function readfilename(specification,backtrack,treetoo)
31    if trace_details then
32        report_files(table.serialize(specification,"specification"))
33    end
34    local name = specification.filename
35    local fnd = name and found[name]
36    if not fnd then
37        local names
38        local suffix = file.suffix(name)
39        if suffix ~= "" then
40            names = { name }
41        else
42            local defaultsuffixes = resolvers.defaultsuffixes
43            names = { }
44            for i=1,#defaultsuffixes do
45                names[i] = name .. "." .. defaultsuffixes[i]
46            end
47            if trace_files then
48                report_files("locating: %s, using default suffixes: %a",name,defaultsuffixes)
49            end
50        end
51        for i=1,#names do
52            local fname = names[i]
53            if isfile(fname) then
54                if trace_files then
55                    report_files("found local: %s",name)
56                end
57                fnd = fname
58                break
59            end
60        end
61        if not fnd and backtrack then
62            local path = environment.arguments.runpath and environment.arguments.path or ""
63            for i=1,#names do
64                local fname = names[i]
65                for i=1,backtrack,1 do
66                    fname = "../" .. fname
67                    local pname = path and (path ~= "") and (path .. "/" .. fname) or fname
68                    if isfile(pname) then
69                        if trace_files then
70                            report_files("found by backtracking: %s",pname)
71                        end
72                        fnd = pname
73                        break
74                    elseif trace_files then
75                        report_files("not found by backtracking: %s",pname)
76                    end
77                end
78                if fnd then
79                    break
80                end
81            end
82        end
83        if not fnd then
84            local paths = resolvers.getextrapaths()
85            if paths then
86                for i=1,#paths do
87                    for i=1,#names do
88                        local fname = paths[i] .. "/" .. names[i]
89                        if isfile(fname) then
90                            if trace_files then
91                                report_files("found on extra path: %s",fname)
92                            end
93                            fnd = fname
94                            break
95                        end
96                    end
97                    if fnd then
98                        break
99                    end
100                end
101            end
102        end
103        if not fnd and treetoo then
104            fnd = resolvers.findtexfile(name) or ""
105            if trace_files then
106                if fnd ~= "" then
107                    report_files("found by tree lookup: %s",fnd)
108                else
109                    report_files("not found by tree lookup: %s",name)
110                end
111            end
112        end
113        found[name] = fnd
114    elseif trace_files then
115        if fnd ~= "" then
116            report_files("already found: %s",fnd)
117        else
118            report_files("already not found: %s",name)
119        end
120    end
121    return fnd or ""
122end
123
124-- resolvers.readfilename = readfilename -- bonus use getreadfilename instead
125
126function resolvers.finders.original(specification) -- handy, see memstreams
127    return specification.path
128end
129
130function finders.job(specification) return readfilename(specification,false,                 false) end -- current path, no backtracking
131function finders.loc(specification) return readfilename(specification,resolvers.maxreadlevel,false) end -- current path, backtracking
132function finders.sys(specification) return readfilename(specification,false,                 true ) end -- current path, obeys tex search
133function finders.fix(specification) return readfilename(specification,resolvers.maxreadlevel,false) end -- specified path, backtracking
134function finders.set(specification) return readfilename(specification,false,                 false) end -- specified path, no backtracking
135function finders.any(specification) return readfilename(specification,resolvers.maxreadlevel,true ) end -- loc job sys
136
137openers.job = openers.file loaders.job = loaders.file -- default anyway
138openers.loc = openers.file loaders.loc = loaders.file
139openers.sys = openers.file loaders.sys = loaders.file
140openers.fix = openers.file loaders.fix = loaders.file
141openers.set = openers.file loaders.set = loaders.file
142openers.any = openers.file loaders.any = loaders.file
143
144local function getreadfilename(scheme,path,name) -- better do a split and then pass table
145    local fullname
146    if hasscheme(name) or is_qualified_path(name) then
147        fullname = name
148    else
149        if not find(name,"%",1,true) then
150            name = urlescape(name) -- if no % in names
151        end
152        fullname = ((path == "") and format("%s:///%s",scheme,name)) or format("%s:///%s/%s",scheme,path,name)
153    end
154    return resolvers.findtexfile(fullname) or "" -- can be more direct
155end
156
157resolvers.getreadfilename = getreadfilename
158
159-- a name belonging to the run but also honoring qualified
160
161local implement = interfaces.implement
162
163implement {
164    name      = "getreadfilename",
165    actions   = { getreadfilename, context },
166    arguments = "3 strings",
167}
168
169implement {
170    name      = "locfilename",
171    actions   = { getreadfilename, context },
172    arguments = { "'loc'","'.'", "string" },
173}
174
175implement {
176    name      = "doifelselocfile",
177    actions   = { getreadfilename, isfile, commands.doifelse },
178    arguments = { "'loc'","'.'", "string" },
179}
180