1if not modules then modules = { } end modules ['l-package'] = {
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
9
10
11
12
13
14
15
16
17
18
19local type, unpack = type, unpack
20local gsub, format, find = string.gsub, string.format, string.find
21local insert, remove = table.insert, table.remove
22
23local P, S, Cs, lpegmatch = lpeg.P, lpeg.S, lpeg.Cs, lpeg.match
24
25local package = package
26local searchers = package.searchers or package.loaders
27
28
29
30
31
32
33local filejoin = file and file.join or function(path,name) return path .. "/" .. name end
34local isreadable = file and file.is_readable or function(name) local f = io.open(name) if f then f:close() return true end end
35local addsuffix = file and file.addsuffix or function(name,suffix) return name .. "." .. suffix end
36
37
38
39
40
41
42
43
44
45
46
47local function cleanpath(path)
48 return path
49end
50
51local pattern = Cs((((1-S("\\/"))^0 * (S("\\/")^1/"/"))^0 * (P(".")^1/"/"+P(1))^1) * -1)
52
53local function lualibfile(name)
54 return lpegmatch(pattern,name) or name
55end
56
57local offset = luarocks and 1 or 0
58
59local helpers = package.helpers or {
60 cleanpath = cleanpath,
61 lualibfile = lualibfile,
62 trace = false,
63 report = function(...) print(format(...)) end,
64 builtin = {
65 ["preload table"] = searchers[1+offset],
66 ["path specification"] = searchers[2+offset],
67 ["cpath specification"] = searchers[3+offset],
68 ["all in one fallback"] = searchers[4+offset],
69 },
70 methods = {
71 },
72 sequence = {
73 "reset loaded",
74 "already loaded",
75 "preload table",
76 "qualified path",
77 "lua extra list",
78 "lib extra list",
79 "path specification",
80 "cpath specification",
81 "all in one fallback",
82 "not loaded",
83 }
84}
85
86package.helpers = helpers
87
88local methods = helpers.methods
89local builtin = helpers.builtin
90
91
92
93local extraluapaths = { }
94local extralibpaths = { }
95local checkedfiles = { }
96local luapaths = nil
97local libpaths = nil
98local oldluapath = nil
99local oldlibpath = nil
100
101local nofextralua = -1
102local nofextralib = -1
103local nofpathlua = -1
104local nofpathlib = -1
105
106local function listpaths(what,paths)
107 local nofpaths = #paths
108 if nofpaths > 0 then
109 for i=1,nofpaths do
110 helpers.report("using %s path %i: %s",what,i,paths[i])
111 end
112 else
113 helpers.report("no %s paths defined",what)
114 end
115 return nofpaths
116end
117
118local function getextraluapaths()
119 if helpers.trace and #extraluapaths ~= nofextralua then
120 nofextralua = listpaths("extra lua",extraluapaths)
121 end
122 return extraluapaths
123end
124
125local function getextralibpaths()
126 if helpers.trace and #extralibpaths ~= nofextralib then
127 nofextralib = listpaths("extra lib",extralibpaths)
128 end
129 return extralibpaths
130end
131
132local function getluapaths()
133 local luapath = package.path or ""
134 if oldluapath ~= luapath then
135 luapaths = file.splitpath(luapath,";")
136 oldluapath = luapath
137 nofpathlua = -1
138 end
139 if helpers.trace and #luapaths ~= nofpathlua then
140 nofpathlua = listpaths("builtin lua",luapaths)
141 end
142 return luapaths
143end
144
145local function getlibpaths()
146 local libpath = package.cpath or ""
147 if oldlibpath ~= libpath then
148 libpaths = file.splitpath(libpath,";")
149 oldlibpath = libpath
150 nofpathlib = -1
151 end
152 if helpers.trace and #libpaths ~= nofpathlib then
153 nofpathlib = listpaths("builtin lib",libpaths)
154 end
155 return libpaths
156end
157
158package.luapaths = getluapaths
159package.libpaths = getlibpaths
160package.extraluapaths = getextraluapaths
161package.extralibpaths = getextralibpaths
162
163local hashes = {
164 lua = { },
165 lib = { },
166}
167
168local function registerpath(tag,what,target,...)
169 local pathlist = { ... }
170 local cleanpath = helpers.cleanpath
171 local trace = helpers.trace
172 local report = helpers.report
173 local hash = hashes[what]
174
175 local function add(path)
176 local path = cleanpath(path)
177 if not hash[path] then
178 target[#target+1] = path
179 hash[path] = true
180 if trace then
181 report("registered %s path %s: %s",tag,#target,path)
182 end
183 else
184 if trace then
185 report("duplicate %s path: %s",tag,path)
186 end
187 end
188 end
189
190 for p=1,#pathlist do
191 local path = pathlist[p]
192 if type(path) == "table" then
193 for i=1,#path do
194 add(path[i])
195 end
196 else
197 add(path)
198 end
199 end
200end
201
202local function pushpath(tag,what,target,path)
203 local path = helpers.cleanpath(path)
204 insert(target,1,path)
205 if helpers.trace then
206 helpers.report("pushing %s path in front: %s",tag,path)
207 end
208end
209
210local function poppath(tag,what,target)
211 local path = remove(target,1)
212 if helpers.trace then
213 if path then
214 helpers.report("popping %s path from front: %s",tag,path)
215 else
216 helpers.report("no %s path to pop",tag)
217 end
218 end
219end
220
221helpers.registerpath = registerpath
222
223function package.extraluapath(...)
224 registerpath("extra lua","lua",extraluapaths,...)
225end
226function package.pushluapath(path)
227 pushpath("extra lua","lua",extraluapaths,path)
228end
229function package.popluapath()
230 poppath("extra lua","lua",extraluapaths)
231end
232
233function package.extralibpath(...)
234 registerpath("extra lib","lib",extralibpaths,...)
235end
236function package.pushlibpath(path)
237 pushpath("extra lib","lib",extralibpaths,path)
238end
239function package.poplibpath()
240 poppath("extra lib","lua",extralibpaths)
241end
242
243
244
245local function loadedaslib(resolved,rawname)
246 local base = gsub(rawname,"%.","_")
247
248
249 local init = "luaopen_" .. gsub(base,"%.","_")
250 local data = { resolved, init, "" }
251 checkedfiles[#checkedfiles+1] = data
252 if helpers.trace then
253 helpers.report("calling loadlib with '%s' with init '%s'",resolved,init)
254 end
255 local a, b, c = package.loadlib(resolved,init)
256 if not a and type(b) == "string" then
257
258 data[3] = string.fullstrip(b or "unknown error")
259 end
260 return a, b, c
261end
262
263helpers.loadedaslib = loadedaslib
264
265
266
267local function loadedbypath(name,rawname,paths,islib,what)
268 local trace = helpers.trace
269 for p=1,#paths do
270 local path = paths[p]
271 local resolved = filejoin(path,name)
272 if trace then
273 helpers.report("%s path, identifying '%s' on '%s'",what,name,path)
274 end
275 if isreadable(resolved) then
276 if trace then
277 helpers.report("%s path, '%s' found on '%s'",what,name,resolved)
278 end
279 if islib then
280 return loadedaslib(resolved,rawname)
281 else
282 return loadfile(resolved)
283 end
284 end
285 end
286end
287
288helpers.loadedbypath = loadedbypath
289
290local function loadedbyname(name,rawname)
291 if find(name,"^/") or find(name,"^[a-zA-Z]:/") then
292 local trace=helpers.trace
293 if trace then
294 helpers.report("qualified name, identifying '%s'",what,name)
295 end
296 if isreadable(name) then
297 if trace then
298 helpers.report("qualified name, '%s' found",what,name)
299 end
300 return loadfile(name)
301 end
302 end
303end
304
305helpers.loadedbyname = loadedbyname
306
307methods["reset loaded"] = function(name)
308 checkedfiles = { }
309 return false
310end
311
312
313methods["already loaded"] = function(name)
314 return package.loaded[name]
315end
316
317methods["preload table"] = function(name)
318 local f = builtin["preload table"]
319 if f then
320 return f(name)
321 end
322end
323
324methods["qualified path"]=function(name)
325 return loadedbyname(addsuffix(lualibfile(name),"lua"),name)
326end
327
328methods["lua extra list"] = function(name)
329 return loadedbypath(addsuffix(lualibfile(name),"lua"),name,getextraluapaths(),false,"lua")
330end
331
332methods["lib extra list"] = function(name)
333 return loadedbypath(addsuffix(lualibfile(name),os.libsuffix),name,getextralibpaths(),true, "lib")
334end
335
336methods["path specification"] = function(name)
337 local f = builtin["path specification"]
338 if f then
339 getluapaths()
340 return f(name)
341 end
342end
343
344methods["cpath specification"] = function(name)
345 local f = builtin["cpath specification"]
346 if f then
347 getlibpaths()
348 return f(name)
349 end
350end
351
352methods["all in one fallback"] = function(name)
353 local f = builtin["all in one fallback"]
354 if f then
355 return f(name)
356 end
357end
358
359methods["not loaded"] = function(name)
360 if helpers.trace then
361 helpers.report("unable to locate '%s'",name or "?")
362 for i=1,#checkedfiles do
363 helpers.report("checked file '%s', initializer '%s', message '%s'",unpack(checkedfiles[i]))
364 end
365 end
366 return nil
367end
368
369local level = 0
370local used = { }
371
372helpers.traceused = false
373
374function helpers.loaded(name)
375 local sequence = helpers.sequence
376 level = level + 1
377 for i=1,#sequence do
378 local method = sequence[i]
379 local lookup = method and methods[method]
380 if type(lookup) == "function" then
381 if helpers.trace then
382 helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name)
383 end
384 local result, rest = lookup(name)
385 if type(result) == "function" then
386 if helpers.trace then
387 helpers.report("%s, level '%s', method '%s', name '%s'","found",level,method,name)
388 end
389 if helpers.traceused then
390 used[#used+1] = { level = level, name = name }
391 end
392 level = level - 1
393 return result, rest
394 end
395 end
396 end
397
398 level = level - 1
399 return nil
400end
401
402function helpers.showused()
403 local n = #used
404 if n > 0 then
405 helpers.report("%s libraries loaded:",n)
406 helpers.report()
407 for i=1,n do
408 local u = used[i]
409 helpers.report("%i %a",u.level,u.name)
410 end
411 helpers.report()
412 end
413end
414
415function helpers.unload(name)
416 if helpers.trace then
417 if package.loaded[name] then
418 helpers.report("unloading, name '%s', %s",name,"done")
419 else
420 helpers.report("unloading, name '%s', %s",name,"not loaded")
421 end
422 end
423 package.loaded[name] = nil
424end
425
426
427
428
429table.insert(searchers,1,helpers.loaded)
430
431if context then
432 package.path = ""
433end
434 |