summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/data-met.lua
blob: bb892957733ce26333d914a07a939d25898477e1 (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
128
129
130
131
132
133
134
135
136
137
138
139
140
if not modules then modules = { } end modules ['data-met'] = {
    version   = 1.100,
    comment   = "companion to luat-lib.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

local find, format = string.find, string.format
local sequenced = table.sequenced
local addurlscheme, urlhashed = url.addscheme, url.hashed

local trace_locating = false
local trace_methods  = false

trackers.register("resolvers.locating", function(v) trace_methods = v end)
trackers.register("resolvers.methods",  function(v) trace_methods = v end)

--~ trace_methods = true

local report_methods = logs.reporter("resolvers","methods")

local allocate = utilities.storage.allocate

local resolvers = resolvers

local registered = { }

local function splitmethod(filename) -- todo: filetype in specification
    if not filename then
        return { scheme = "unknown", original = filename }
    end
    if type(filename) == "table" then
        return filename -- already split
    end
    filename = file.collapsepath(filename,".") -- hm, we should keep ./ in some cases

    if not find(filename,"://",1,true) then
        return { scheme = "file", path = filename, original = filename, filename = filename }
    end
    local specification = url.hashed(filename)
    if not specification.scheme or specification.scheme == "" then
        return { scheme = "file", path = filename, original = filename, filename = filename }
    else
        return specification
    end
end

-- local function splitmethod(filename) -- todo: filetype in specification
--     if not filename then
--         return { scheme = "unknown", original = filename }
--     end
--     if type(filename) == "table" then
--         return filename -- already split
--     end
--     return url.hashed(filename)
-- end

resolvers.splitmethod = splitmethod -- bad name but ok

-- the second argument is always analyzed (saves time later on) and the original
-- gets passed as original but also as argument

local function methodhandler(what,first,...) -- filename can be nil or false
    local method = registered[what]
    if method then
        local how, namespace = method.how, method.namespace
        if how == "uri" or how == "url" then
            local specification = splitmethod(first)
            local scheme = specification.scheme
            local resolver = namespace and namespace[scheme]
            if resolver then
                if trace_methods then
                    report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,scheme,first)
                end
                return resolver(specification,...)
            else
                resolver = namespace.default or namespace.file
                if resolver then
                    if trace_methods then
                        report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"default",first)
                    end
                    return resolver(specification,...)
                elseif trace_methods then
                    report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"unset")
                end
            end
        elseif how == "tag" then
            local resolver = namespace and namespace[first]
            if resolver then
                if trace_methods then
                    report_methods("resolving, method %a, how %a, tag %a",what,how,first)
                end
                return resolver(...)
            else
                resolver = namespace.default or namespace.file
                if resolver then
                    if trace_methods then
                        report_methods("resolving, method %a, how %a, tag %a",what,how,"default")
                    end
                    return resolver(...)
                elseif trace_methods then
                    report_methods("resolving, method %a, how %a, tag %a",what,how,"unset")
                end
            end
        end
    else
        report_methods("resolving, invalid method %a")
    end
end

resolvers.methodhandler = methodhandler

function resolvers.registermethod(name,namespace,how)
    registered[name] = { how = how or "tag", namespace = namespace }
    namespace["byscheme"] = function(scheme,filename,...)
        if scheme == "file" then
            return methodhandler(name,filename,...)
        else
            return methodhandler(name,addurlscheme(filename,scheme),...)
        end
    end
end

local concatinators = allocate { notfound = file.join       }  -- concatinate paths
local locators      = allocate { notfound = function() end  }  -- locate databases
local hashers       = allocate { notfound = function() end  }  -- load databases
local generators    = allocate { notfound = function() end  }  -- generate databases

resolvers.concatinators = concatinators
resolvers.locators      = locators
resolvers.hashers       = hashers
resolvers.generators    = generators

local registermethod = resolvers.registermethod

registermethod("concatinators",concatinators,"tag")
registermethod("locators",     locators,     "uri")
registermethod("hashers",      hashers,      "uri")
registermethod("generators",   generators,   "uri")