summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/file-lib.lua
blob: 50ac5e1db34d4ce7bad1c2307f0dcbb4ddc72063 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
if not modules then modules = { } end modules ['file-lib'] = {
    version   = 1.001,
    comment   = "companion to file-lib.mkvi",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

-- todo: check all usage of truefilename at the tex end and remove
-- files there (and replace definitions by full names)

local format, gsub = string.format, string.gsub

local trace_libraries = false  trackers.register("resolvers.libraries", function(v) trace_libraries = v end)
----- trace_files     = false  trackers.register("resolvers.readfile",  function(v) trace_files     = v end)

local report_library  = logs.reporter("files","library")
----- report_files    = logs.reporter("files","readfile")

local removesuffix    = file.removesuffix
local collapsepath    = file.collapsepath

local getreadfilename = resolvers.getreadfilename

local libraries       = table.setmetatableindex("table")
local defaultpatterns = { "%s" }

local function defaultaction(name,foundname)
    report_files("asked name %a, found name %a",name,foundname)
end

local function defaultfailure(name)
    report_files("asked name %a, not found",name)
end

function resolvers.uselibrary(specification) -- todo: reporter
    local name = specification.name
    if name and name ~= "" then
        local patterns = specification.patterns or defaultpatterns
        local action   = specification.action   or defaultaction
        local failure  = specification.failure  or defaultfailure
        local onlyonce = specification.onlyonce
        local files    = utilities.parsers.settings_to_array(name)
        local truename = environment.truefilename
        local function found(filename)
            local somename  = truename and truename(filename) or filename
            local foundname = getreadfilename("any",".",somename) -- maybe some day also an option not to backtrack .. and ../.. (or block global)
            return foundname ~= "" and foundname
        end
        local loaded = libraries[patterns]
        for i=1,#files do
            local filename = files[i]
            if not loaded[filename] then
                local foundname = nil
                local barename  = removesuffix(filename)
                -- direct search (we have an explicit suffix)
                if barename ~= filename then
                    foundname = found(filename)
                    if trace_libraries then
                        report_library("checking %a: %s",filename,foundname or "not found")
                    end
                end
                if not foundname then
                    -- pattern based search
                    for i=1,#patterns do
                        local pattern = patterns[i]
                        if pattern and pattern ~= "" then
                            local wanted = format(pattern,barename)
                            foundname = found(wanted)
                            if trace_libraries then
                                report_library("checking %a as %a: %s",filename,wanted,foundname or "not found")
                            end
                            if foundname then
                                break
                            end
                        else
                            -- can be a bogus path (coming from a test)
                        end
                    end
                end
                if type(foundname) == "string" then
                    if not loaded[foundname] then
                        if foundname then
                            foundname = collapsepath(foundname)
                            -- this way we can run a module (nil when making a format):
                            local inputname = environment.inputfilename
                            if not inputname or collapsepath(inputname) ~= foundname then
                                action(name,foundname)
                            end
                            -- afterwards:
                            if onlyonce then
                                loaded[foundname] = true -- todo: base this on return value
                            end
                        elseif failure then
                            failure(name)
                        end
                        if onlyonce then
                            loaded[filename] = true -- todo: base this on return value
                        end
                    end
                end
            end
        end
    end
end

-- We keep these in the commands namespace even if it's not that logical
-- but this way we are compatible.

function commands.loadlibrary(name,foundname,nointerference)
    if not foundname then
        foundname = name
    end
    if foundname and foundname ~= "" then
        if nointerference then
            context.startnointerference()
        end
        context.startreadingfile()
        context.input(foundname)
        context.stopreadingfile()
        if nointerference then
            context.stopnointerference()
        end
    end
end

commands.uselibrary = resolvers.uselibrary