summaryrefslogtreecommitdiff
path: root/lualibs-package.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lualibs-package.lua')
-rw-r--r--lualibs-package.lua338
1 files changed, 338 insertions, 0 deletions
diff --git a/lualibs-package.lua b/lualibs-package.lua
new file mode 100644
index 0000000..7b82fa5
--- /dev/null
+++ b/lualibs-package.lua
@@ -0,0 +1,338 @@
+if not modules then modules = { } end modules ['l-package'] = {
+ version = 1.001,
+ 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"
+}
+
+-- Code moved from data-lua and changed into a plug-in.
+
+-- We overload the regular loader. We do so because we operate mostly in
+-- tds and use our own loader code. Alternatively we could use a more
+-- extensive definition of package.path and package.cpath but even then
+-- we're not done. Also, we now have better tracing.
+--
+-- -- local mylib = require("libtest")
+-- -- local mysql = require("luasql.mysql")
+
+local type = type
+local gsub, format = string.gsub, string.format
+
+local P, S, Cs, lpegmatch = lpeg.P, lpeg.S, lpeg.Cs, lpeg.match
+
+local package = package
+local searchers = package.searchers or package.loaders
+
+-- dummies
+
+local filejoin = file and file.join or function(path,name) return path .. "/" .. name end
+local isreadable = file and file.is_readable or function(name) local f = io.open(name) if f then f:close() return true end end
+local addsuffix = file and file.addsuffix or function(name,suffix) return name .. "." .. suffix end
+
+--
+
+-- local separator, concatinator, placeholder, pathofexecutable, ignorebefore = string.match(package.config,"(.-)\n(.-)\n(.-)\n(.-)\n(.-)\n")
+--
+-- local config = {
+-- separator = separator, -- \ or /
+-- concatinator = concatinator, -- ;
+-- placeholder = placeholder, -- ? becomes name
+-- pathofexecutable = pathofexecutable, -- ! becomes executables dir (on windows)
+-- ignorebefore = ignorebefore, -- - remove all before this when making lua_open
+-- }
+
+--
+
+local function cleanpath(path) -- hm, don't we have a helper for this?
+ return path
+end
+
+local pattern = Cs((((1-S("\\/"))^0 * (S("\\/")^1/"/"))^0 * (P(".")^1/"/"+P(1))^1) * -1)
+
+local function lualibfile(name)
+ return lpegmatch(pattern,name) or name
+end
+
+local helpers = package.helpers or {
+ cleanpath = cleanpath,
+ lualibfile = lualibfile,
+ trace = false,
+ report = function(...) print(format(...)) end,
+ builtin = {
+ ["preload table"] = searchers[1], -- special case, built-in libs
+ ["path specification"] = searchers[2],
+ ["cpath specification"] = searchers[3],
+ ["all in one fallback"] = searchers[4], -- special case, combined libs
+ },
+ methods = {
+ },
+ sequence = {
+ "already loaded",
+ "preload table",
+ "lua extra list",
+ "lib extra list",
+ "path specification",
+ "cpath specification",
+ "all in one fallback",
+ "not loaded",
+ }
+}
+
+package.helpers = helpers
+
+local methods = helpers.methods
+local builtin = helpers.builtin
+
+-- extra tds/ctx paths
+
+local extraluapaths = { }
+local extralibpaths = { }
+local luapaths = nil -- delayed
+local libpaths = nil -- delayed
+
+local function getextraluapaths()
+ return extraluapaths
+end
+
+local function getextralibpaths()
+ return extralibpaths
+end
+
+local function getluapaths()
+ luapaths = luapaths or file.splitpath(package.path, ";")
+ return luapaths
+end
+
+local function getlibpaths()
+ libpaths = libpaths or file.splitpath(package.cpath, ";")
+ return libpaths
+end
+
+package.luapaths = getluapaths
+package.libpaths = getlibpaths
+package.extraluapaths = getextraluapaths
+package.extralibpaths = getextralibpaths
+
+local hashes = {
+ lua = { },
+ lib = { },
+}
+
+local function registerpath(tag,what,target,...)
+ local pathlist = { ... }
+ local cleanpath = helpers.cleanpath
+ local trace = helpers.trace
+ local report = helpers.report
+ local hash = hashes[what]
+ --
+ local function add(path)
+ local path = cleanpath(path)
+ if not hash[path] then
+ target[#target+1] = path
+ hash[path] = true
+ if trace then
+ report("registered %s path %s: %s",tag,#target,path)
+ end
+ else
+ if trace then
+ report("duplicate %s path: %s",tag,path)
+ end
+ end
+ end
+ --
+ for p=1,#pathlist do
+ local path = pathlist[p]
+ if type(path) == "table" then
+ for i=1,#path do
+ add(path[i])
+ end
+ else
+ add(path)
+ end
+ end
+ return paths
+end
+
+helpers.registerpath = registerpath
+
+function package.extraluapath(...)
+ registerpath("extra lua","lua",extraluapaths,...)
+end
+
+function package.extralibpath(...)
+ registerpath("extra lib","lib",extralibpaths,...)
+end
+
+-- lib loader (used elsewhere)
+
+local function loadedaslib(resolved,rawname) -- todo: strip all before first -
+ -- local init = "luaopen_" .. string.match(rawname,".-([^%.]+)$")
+ local init = "luaopen_"..gsub(rawname,"%.","_")
+ if helpers.trace then
+ helpers.report("calling loadlib with '%s' with init '%s'",resolved,init)
+ end
+ return package.loadlib(resolved,init)
+end
+
+helpers.loadedaslib = loadedaslib
+
+-- wrapped and new loaders
+
+local function loadedbypath(name,rawname,paths,islib,what)
+ local trace = helpers.trace
+ local report = helpers.report
+ if trace then
+ report("locating '%s' as '%s' on '%s' paths",rawname,name,what)
+ end
+ for p=1,#paths do
+ local path = paths[p]
+ local resolved = filejoin(path,name)
+ if trace then -- mode detail
+ report("checking '%s' using '%s' path '%s'",name,what,path)
+ end
+ if isreadable(resolved) then
+ if trace then
+ report("'%s' located on '%s'",name,resolved)
+ end
+ local result = nil
+ if islib then
+ result = loadedaslib(resolved,rawname)
+ else
+ result = loadfile(resolved)
+ end
+ if result then
+ result()
+ end
+ return true, result
+ end
+ end
+end
+
+helpers.loadedbypath = loadedbypath
+
+-- alternatively we could set the package.searchers
+
+methods["already loaded"] = function(name)
+ local result = package.loaded[name]
+ if result then
+ return true, result
+ end
+end
+
+methods["preload table"] = function(name)
+ local result = builtin["preload table"](name)
+ if type(result) == "function" then
+ return true, result
+ end
+end
+
+methods["lua extra list"] = function(name)
+ local thename = lualibfile(name)
+ local luaname = addsuffix(thename,"lua")
+ local luapaths = getextraluapaths()
+ local done, result = loadedbypath(luaname,name,luapaths,false,"lua")
+ if done then
+ return true, result
+ end
+end
+
+methods["lib extra list"] = function(name)
+ local thename = lualibfile(name)
+ local libname = addsuffix(thename,os.libsuffix)
+ local libpaths = getextralibpaths()
+ local done, result = loadedbypath(libname,name,libpaths,true,"lib")
+ if done then
+ return true, result
+ end
+end
+
+local shown = false
+
+methods["path specification"] = function(name)
+ if not shown and helpers.trace then
+ local luapaths = getluapaths() -- triggers list building
+ if #luapaths > 0 then
+ helpers.report("using %s built in lua paths",#luapaths)
+ else
+ helpers.report("no built in lua paths defined")
+ end
+ shown = true
+ end
+ local result = builtin["path specification"](name)
+ if type(result) == "function" then
+ return true, result()
+ end
+end
+
+local shown = false
+
+methods["cpath specification"] = function(name)
+ if not shown and helpers.trace then
+ local libpaths = getlibpaths() -- triggers list building
+ if #libpaths > 0 then
+ helpers.report("using %s built in lib paths",#libpaths)
+ else
+ helpers.report("no built in lib paths defined")
+ end
+ shown = true
+ end
+ local result = builtin["cpath specification"](name)
+ if type(result) == "function" then
+ return true, result()
+ end
+end
+
+methods["all in one fallback"] = function(name)
+ local result = builtin["all in one fallback"](name)
+ if type(result) == "function" then
+ return true, result()
+ end
+end
+
+methods["not loaded"] = function(name)
+ if helpers.trace then
+ helpers.report("unable to locate '%s'",name)
+ end
+end
+
+function helpers.loaded(name)
+ local sequence = helpers.sequence
+ for i=1,#sequence do
+ local step = sequence[i]
+ if helpers.trace then
+ helpers.report("locating '%s' using method '%s'",name,step)
+ end
+ local done, result = methods[step](name)
+ if done then
+ if helpers.trace then
+ helpers.report("'%s' located via method '%s' returns '%s'",name,step,type(result))
+ end
+ if result then
+ package.loaded[name] = result
+ end
+ return result
+ end
+ end
+ return nil -- we must return a value
+end
+
+function helpers.unload(name)
+ if helpers.trace then
+ if package.loaded[name] then
+ helpers.report("unloading '%s', %s",name,"done")
+ else
+ helpers.report("unloading '%s', %s",name,"not loaded")
+ end
+ end
+ package.loaded[name] = nil -- does that work? is readable only, maybe we need our own hash
+end
+
+searchers[1] = nil
+searchers[2] = nil
+searchers[3] = nil
+searchers[4] = nil
+
+helpers.savedrequire = helpers.savedrequire or require
+
+require = helpers.loaded