file-lib.lua /size: 5307 b    last modification: 2023-12-21 09:44
1if not modules then modules = { } end modules ['file-lib'] = {
2    version   = 1.001,
3    comment   = "companion to file-lib.mkvi",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    copyright = "PRAGMA ADE / ConTeXt Development Team",
6    license   = "see context related readme files"
7}
8
9-- todo: check all usage of truefilename at the tex end and remove
10-- files there (and replace definitions by full names)
11
12local format, gsub = string.format, string.gsub
13
14local trace_libraries = false  trackers.register("resolvers.libraries", function(v) trace_libraries = v end)
15----- trace_files     = false  trackers.register("resolvers.readfile",  function(v) trace_files     = v end)
16
17local report_library  = logs.reporter("files","library")
18----- report_files    = logs.reporter("files","readfile")
19
20local removesuffix    = file.removesuffix
21local collapsepath    = file.collapsepath
22
23local getreadfilename = resolvers.getreadfilename
24
25local libraries       = table.setmetatableindex("table")
26local defaultpatterns = { "%s" }
27
28local function defaultaction(name,foundname)
29    report_files("asked name %a, found name %a",name,foundname)
30end
31
32local function defaultfailure(name)
33    report_files("asked name %a, not found",name)
34end
35
36local ignoredfiles = { }
37
38function resolvers.ignorelibrary(name)
39    ignoredfiles[name] = true
40end
41
42function resolvers.uselibrary(specification) -- todo: reporter
43    local name = specification.name
44    if name and name ~= "" and not ignoredfiles[name] then
45        local patterns = specification.patterns or defaultpatterns
46        local action   = specification.action   or defaultaction
47        local failure  = specification.failure  or defaultfailure
48        local onlyonce = specification.onlyonce
49        local files    = utilities.parsers.settings_to_array(name)
50        local truename = environment.truefilename
51        local function found(filename)
52            local somename  = truename and truename(filename) or filename
53            local foundname = getreadfilename("any",".",somename) -- maybe some day also an option not to backtrack .. and ../.. (or block global)
54            return foundname ~= "" and foundname
55        end
56        local loaded = libraries[patterns]
57        for i=1,#files do
58            local filename = files[i]
59            if not loaded[filename] then
60                local foundname = nil
61                local barename  = removesuffix(filename)
62                -- direct search (we have an explicit suffix)
63                if barename ~= filename then
64                    foundname = found(filename)
65                    if trace_libraries then
66                        report_library("checking %a: %s",filename,foundname or "not found")
67                    end
68                end
69                if not foundname then
70                    -- pattern based search
71                    for i=1,#patterns do
72                        local pattern = patterns[i]
73                        if pattern and pattern ~= "" then
74                            local wanted = format(pattern,barename)
75                            foundname = found(wanted)
76                            if trace_libraries then
77                                report_library("checking %a as %a: %s",filename,wanted,foundname or "not found")
78                            end
79                            if foundname then
80                                break
81                            end
82                        else
83                            -- can be a bogus path (coming from a test)
84                        end
85                    end
86                end
87                if type(foundname) == "string" then
88                    if not loaded[foundname] then
89                        if foundname then
90                            foundname = collapsepath(foundname)
91                            -- this way we can run a module (nil when making a format):
92                            local inputname = environment.inputfilename
93                            if not inputname or collapsepath(inputname) ~= foundname then
94                                action(name,foundname)
95                            end
96                            -- afterwards:
97                            if onlyonce then
98                                loaded[foundname] = true -- todo: base this on return value
99                            end
100                        elseif failure then
101                            failure(name)
102                        end
103                        if onlyonce then
104                            loaded[filename] = true -- todo: base this on return value
105                        end
106                    end
107                end
108            end
109        end
110    end
111end
112
113-- We keep these in the commands namespace even if it's not that logical
114-- but this way we are compatible.
115
116function commands.loadlibrary(name,foundname,nointerference)
117    if not foundname then
118        foundname = name
119    end
120    if foundname and foundname ~= "" then
121        if nointerference then
122            context.startnointerference()
123        end
124        context.startreadingfile()
125        context.input(foundname)
126        context.stopreadingfile()
127        if nointerference then
128            context.stopnointerference()
129        end
130    end
131end
132
133commands.uselibrary = resolvers.uselibrary
134