data-ini.lua /size: 10 Kb    last modification: 2020-07-01 14:35
1if not modules then modules = { } end modules ['data-ini'] = {
2    version   = 1.001,
3    comment   = "companion to luat-lib.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 next, type, getmetatable, rawset = next, type, getmetatable, rawset
10local gsub, find, gmatch, char = string.gsub, string.find, string.gmatch, string.char
11local filedirname, filebasename, filejoin = file.dirname, file.basename, file.join
12local ostype, osname, osuname, ossetenv, osgetenv = os.type, os.name, os.uname, os.setenv, os.getenv
13local sortedpairs = table.sortedpairs
14
15local P, S, R, C, Cs, Cc, lpegmatch = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.match
16
17local trace_locating   = false  trackers.register("resolvers.locating",   function(v) trace_locating   = v end)
18local trace_expansions = false  trackers.register("resolvers.expansions", function(v) trace_expansions = v end)
19
20local report_initialization = logs.reporter("resolvers","initialization")
21
22-- The code here used to be part of a data-res but for convenience we now split it over multiple
23-- files. As this file is now the starting point we introduce resolvers here. We also put some
24-- helpers here that later can be reimplemented of extended.
25
26resolvers       = resolvers or { }
27local resolvers = resolvers
28
29-- We don't want the kpse library to kick in. Also, we want to be able to
30-- execute programs. Control over execution is implemented later.
31
32texconfig.kpse_init    = false
33texconfig.shell_escape = 't'
34
35if not (environment and environment.default_texmfcnf) and kpse and kpse.default_texmfcnf then
36    local default_texmfcnf = kpse.default_texmfcnf()
37    -- looks more like context
38    default_texmfcnf = gsub(default_texmfcnf,"$SELFAUTOLOC","selfautoloc:")
39    default_texmfcnf = gsub(default_texmfcnf,"$SELFAUTODIR","selfautodir:")
40    default_texmfcnf = gsub(default_texmfcnf,"$SELFAUTOPARENT","selfautoparent:")
41    default_texmfcnf = gsub(default_texmfcnf,"$HOME","home:")
42    --
43    environment.default_texmfcnf = default_texmfcnf
44end
45
46kpse = { original = kpse }
47
48setmetatable(kpse, {
49    __index = function(kp,name)
50        report_initialization("fatal error: kpse library is accessed (key: %s)",name)
51        os.exit()
52    end
53} )
54
55-- First we check a couple of environment variables. Some might be
56-- set already but we need then later on. We start with the system
57-- font path.
58
59do
60
61    local osfontdir = osgetenv("OSFONTDIR")
62
63    if osfontdir and osfontdir ~= "" then
64        -- ok
65    elseif osname == "windows" then
66        ossetenv("OSFONTDIR","c:/windows/fonts//")
67    elseif osname == "macosx" then
68        ossetenv("OSFONTDIR","$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//")
69    end
70
71end
72
73-- Next comes the user's home path. We need this as later on we have
74-- to replace ~ with its value.
75
76if not environment.homedir then
77
78    local oldhome = osgetenv('HOME')
79    local homedir = osgetenv(ostype == "windows" and 'USERPROFILE' or 'HOME') or ''
80
81    if not homedir or homedir == "" then
82        homedir = char(127) -- we need a value, later we wil trigger on it
83    end
84
85    homedir = file.collapsepath(homedir)
86
87    ossetenv("HOME",       homedir) -- can be used in unix cnf files
88    ossetenv("USERPROFILE",homedir) -- can be used in windows cnf files
89
90    environment.oldhome = oldhome
91    environment.homedir = homedir
92
93end
94
95-- The following code sets the name of the own binary and its
96-- path. This is fallback code as we have os.selfdir now.
97
98do
99
100    local args = environment.originalarguments or arg -- this needs a cleanup
101
102    if not environment.ownmain then
103        environment.ownmain = status and string.match(string.lower(status.banner),"this is ([%a]+)") or "luatex"
104    end
105
106    local ownbin  = environment.ownbin  or args[-2] or arg[-2] or args[-1] or arg[-1] or arg[0] or "luatex"
107    local ownpath = environment.ownpath or os.selfdir
108
109    ownbin  = file.collapsepath(ownbin)
110    ownpath = file.collapsepath(ownpath)
111
112    if not ownpath or ownpath == "" or ownpath == "unset" then
113        ownpath = args[-1] or arg[-1]
114        ownpath = ownpath and filedirname(gsub(ownpath,"\\","/"))
115        if not ownpath or ownpath == "" then
116            ownpath = args[-0] or arg[-0]
117            ownpath = ownpath and filedirname(gsub(ownpath,"\\","/"))
118        end
119        local binary = ownbin
120        if not ownpath or ownpath == "" then
121            ownpath = ownpath and filedirname(binary)
122        end
123        if not ownpath or ownpath == "" then
124            if os.binsuffix ~= "" then
125                binary = file.replacesuffix(binary,os.binsuffix)
126            end
127            local path = osgetenv("PATH")
128            if path then
129                for p in gmatch(path,"[^"..io.pathseparator.."]+") do
130                    local b = filejoin(p,binary)
131                    if lfs.isfile(b) then
132                        -- we assume that after changing to the path the currentdir function
133                        -- resolves to the real location and use this side effect here; this
134                        -- trick is needed because on the mac installations use symlinks in the
135                        -- path instead of real locations
136                        local olddir = lfs.currentdir()
137                        if lfs.chdir(p) then
138                            local pp = lfs.currentdir()
139                            if trace_locating and p ~= pp then
140                                report_initialization("following symlink %a to %a",p,pp)
141                            end
142                            ownpath = pp
143                            lfs.chdir(olddir)
144                        else
145                            if trace_locating then
146                                report_initialization("unable to check path %a",p)
147                            end
148                            ownpath =  p
149                        end
150                        break
151                    end
152                end
153            end
154        end
155        if not ownpath or ownpath == "" then
156            ownpath = "."
157            report_initialization("forcing fallback to ownpath %a",ownpath)
158        elseif trace_locating then
159            report_initialization("using ownpath %a",ownpath)
160        end
161    end
162
163    environment.ownbin  = ownbin
164    environment.ownpath = ownpath
165
166end
167
168resolvers.ownpath = environment.ownpath
169
170function resolvers.getownpath()
171    return environment.ownpath
172end
173
174-- The self variables permit us to use only a few (or even no)
175-- environment variables.
176
177do
178
179    local ownpath = environment.ownpath or dir.current()
180
181    if ownpath then
182        ossetenv('SELFAUTOLOC',    file.collapsepath(ownpath))
183        ossetenv('SELFAUTODIR',    file.collapsepath(ownpath .. "/.."))
184        ossetenv('SELFAUTOPARENT', file.collapsepath(ownpath .. "/../.."))
185    else
186        report_initialization("error: unable to locate ownpath")
187        os.exit()
188    end
189
190end
191
192-- The running os:
193
194-- todo: check is context sits here os.platform is more trustworthy
195-- that the bin check as mtx-update runs from another path
196
197local texos   = environment.texos   or osgetenv("TEXOS")
198local texmfos = environment.texmfos or osgetenv('SELFAUTODIR')
199
200if not texos or texos == "" then
201    texos = file.basename(texmfos)
202end
203
204ossetenv('TEXMFOS',       texmfos)      -- full bin path
205ossetenv('TEXOS',         texos)        -- partial bin parent
206ossetenv('SELFAUTOSYSTEM',os.platform)  -- bonus
207
208environment.texos   = texos
209environment.texmfos = texmfos
210
211-- The current root:
212
213local texroot = environment.texroot or osgetenv("TEXROOT")
214
215if not texroot or texroot == "" then
216    texroot = osgetenv('SELFAUTOPARENT')
217    ossetenv('TEXROOT',texroot)
218end
219
220environment.texroot = file.collapsepath(texroot)
221
222-- a forward definition
223
224-- Because we use resolvers.resolve a lot later on, we will implement the basics here and
225-- add more later.
226
227local prefixes     = utilities.storage.allocate()
228resolvers.prefixes = prefixes
229
230local resolved     = { }
231local abstract     = { }
232local dynamic      = { }
233
234function resolvers.resetresolve(str)
235    resolved, abstract = { }, { }
236end
237
238function resolvers.allprefixes(separator)
239    local all = table.sortedkeys(prefixes)
240    if separator then
241        for i=1,#all do
242            all[i] = all[i] .. ":"
243        end
244    end
245    return all
246end
247
248local function _resolve_(method,target)
249    local action = prefixes[method]
250    if action then
251        return action(target)
252    else
253        return method .. ":" .. target
254    end
255end
256
257function resolvers.unresolve(str)
258    return abstract[str] or str
259end
260
261function resolvers.setdynamic(str)
262    dynamic[str] = true
263end
264
265-- home:xx;selfautoparent:xx;
266
267local pattern   = Cs((C(R("az")^2) * P(":") * C((1-S(" \"\';,"))^1) / _resolve_ + P(1))^0)
268
269local prefix    = C(R("az")^2) * P(":")
270local target    = C((1-S(" \"\';,"))^1)
271local notarget  = (#S(";,") + P(-1)) * Cc("")
272
273local p_resolve = Cs(((prefix * (target + notarget)) / _resolve_ + P(1))^0)
274local p_simple  = prefix * P(-1)
275
276local function resolve(str) -- use schemes, this one is then for the commandline only
277    if type(str) == "table" then
278        local res = { }
279        for i=1,#str do
280            res[i] = resolve(str[i])
281        end
282        return res
283    end
284    -- already resolved
285    local res = resolved[str]
286    if res then
287        return res
288    end
289    -- simple resolving of (dynamic) methods
290    local simple = lpegmatch(p_simple,str)
291    local action = prefixes[simple]
292    if action then
293        local res = action(res)
294        if not dynamic[simple] then
295            resolved[simple] = res
296            abstract[res] = simple
297        end
298        return res
299    end
300    -- more extensive resolving (multiple too)
301    res = lpegmatch(p_resolve,str)
302    resolved[str] = res
303    abstract[res] = str
304    return res
305end
306
307resolvers.resolve = resolve
308
309if type(osuname) == "function" then
310
311    for k, v in next, osuname() do
312        if not prefixes[k] then
313            prefixes[k] = function() return v end
314        end
315    end
316
317end
318
319if ostype == "unix" then
320
321    -- We need to distringuish between a prefix and something else : so we
322    -- have a special repath variant for linux. Also, when a new prefix is
323    -- defined, we need to remake the matcher.
324
325    local pattern
326
327    local function makepattern(t,k,v)
328        if t then
329            rawset(t,k,v)
330        end
331        local colon = P(":")
332        for k, v in sortedpairs(prefixes) do
333            if p then
334                p = P(k) + p
335            else
336                p = P(k)
337            end
338        end
339        pattern = Cs((p * colon + colon/";" + P(1))^0)
340    end
341
342    makepattern()
343
344    table.setmetatablenewindex(prefixes,makepattern)
345
346    function resolvers.repath(str)
347        return lpegmatch(pattern,str)
348    end
349
350else -- already the default:
351
352    function resolvers.repath(str)
353        return str
354    end
355
356end
357