\n")
if jobname then
f:write("\t" .. jobname .. "\n")
end
f:write("\t\n")
for _,v in pairs(table.sortedkeys(instance.foundintrees)) do
f:write("\t\t" .. v .. "\n")
end
f:write("\t\n")
f:write("\n")
f:close()
end
end
function input.automount(instance)
-- implemented later
end
function input.load(instance)
input.starttiming(instance)
input.resetconfig(instance)
input.identify_cnf(instance)
input.load_lua(instance)
input.expand_variables(instance)
input.load_cnf(instance)
input.expand_variables(instance)
input.load_hash(instance)
input.automount(instance)
input.stoptiming(instance)
end
function input.for_files(instance, command, files, filetype, mustexist)
if files and #files > 0 then
local function report(str)
if input.verbose then
input.report(str) -- has already verbose
else
print(str)
end
end
if input.verbose then
report('')
end
for _, file in pairs(files) do
local result = command(instance,file,filetype,mustexist)
if type(result) == 'string' then
report(result)
else
for _,v in pairs(result) do
report(v)
end
end
end
end
end
-- strtab
function input.var_value(instance,str) -- output the value of variable $STRING.
return input.variable(instance,str)
end
function input.expand_var(instance,str) -- output variable expansion of STRING.
return input.expansion(instance,str)
end
function input.show_path(instance,str) -- output search path for file type NAME
return file.join_path(input.expanded_path_list(instance,input.format_of_var(str)))
end
-- input.find_file(filename)
-- input.find_file(filename, filetype, mustexist)
-- input.find_file(filename, mustexist)
-- input.find_file(filename, filetype)
function input.aux.register_file(files, name, path)
if files[name] then
if type(files[name]) == 'string' then
files[name] = { files[name], path }
else
files[name] = path
end
else
files[name] = path
end
end
if not input.finders then input.finders = { } end
if not input.openers then input.openers = { } end
if not input.loaders then input.loaders = { } end
input.finders.notfound = { nil }
input.openers.notfound = { nil }
input.loaders.notfound = { false, nil, 0 }
function input.splitmethod(filename)
if not filename then
return { } -- safeguard
elseif type(filename) == "table" then
return filename -- already split
elseif not filename:find("://") then
return { scheme="file", path = filename, original=filename } -- quick hack
else
return url.hashed(filename)
end
end
function input.method_is_file(filename)
return input.splitmethod(filename).scheme == 'file'
end
function table.sequenced(t,sep) -- temp here
local s = { }
for k, v in pairs(t) do
s[#s+1] = k .. "=" .. v
end
return table.concat(s, sep or " | ")
end
function input.methodhandler(what, instance, filename, filetype) -- ...
local specification = (type(filename) == "string" and input.splitmethod(filename)) or filename -- no or { }, let it bomb
local scheme = specification.scheme
if input[what][scheme] then
input.logger('= handler',specification.original .." -> " .. what .. " -> " .. table.sequenced(specification))
return input[what][scheme](instance,filename,filetype) -- todo: specification
else
return input[what].tex(instance,filename,filetype) -- todo: specification
end
end
-- also inside next test?
function input.findtexfile(instance, filename, filetype)
return input.methodhandler('finders',instance, input.normalize_name(filename), filetype)
end
function input.opentexfile(instance,filename)
return input.methodhandler('openers',instance, input.normalize_name(filename))
end
function input.findbinfile(instance, filename, filetype)
return input.methodhandler('finders',instance, input.normalize_name(filename), filetype)
end
function input.openbinfile(instance,filename)
return input.methodhandler('loaders',instance, input.normalize_name(filename))
end
function input.loadbinfile(instance, filename, filetype)
local fname = input.findbinfile(instance, input.normalize_name(filename), filetype)
if fname and fname ~= "" then
return input.openbinfile(instance,fname)
else
return unpack(input.loaders.notfound)
end
end
function input.texdatablob(instance, filename, filetype)
local ok, data, size = input.loadbinfile(instance, filename, filetype)
return data or ""
end
input.loadtexfile = input.texdatablob
function input.openfile(filename) -- brrr texmf.instance here / todo ! ! ! ! !
local fullname = input.findtexfile(texmf.instance, filename)
if fullname and (fullname ~= "") then
return input.opentexfile(texmf.instance, fullname)
else
return nil
end
end
function input.logmode()
return (os.getenv("MTX.LOG.MODE") or os.getenv("MTX_LOG_MODE") or "tex"):lower()
end
-- this is a prelude to engine/progname specific configuration files
-- in which case we can omit files meant for other programs and
-- packages
--- ctx
-- maybe texinputs + font paths
-- maybe positive selection tex/context fonts/tfm|afm|vf|opentype|type1|map|enc
input.validators = { }
input.validators.visibility = { }
function input.validators.visibility.default(path, name)
return true
end
function input.validators.visibility.context(path, name)
path = path[1] or path -- some day a loop
return not (
path:find("latex") or
-- path:find("doc") or
path:find("tex4ht") or
path:find("source") or
-- path:find("config") or
-- path:find("metafont") or
path:find("lists$") or
name:find("%.tpm$") or
name:find("%.bak$")
)
end
-- todo: describe which functions are public (maybe input.private. ... )
-- beware: i need to check where we still need a / on windows:
function input.clean_path(str)
--~ return (((str:gsub("\\","/")):gsub("^!+","")):gsub("//+","//"))
if str then
return ((str:gsub("\\","/")):gsub("^!+",""))
else
return nil
end
end
function input.do_with_path(name,func)
for _, v in pairs(input.expanded_path_list(instance,name)) do
func("^"..input.clean_path(v))
end
end
function input.do_with_var(name,func)
func(input.aux.expanded_var(name))
end
function input.with_files(instance,pattern,handle)
for _, hash in ipairs(instance.hashes) do
local blobpath = hash.tag
local blobtype = hash.type
if blobpath then
local files = instance.files[blobpath]
if files then
for k,v in pairs(files) do
if k:find("^remap:") then
k = files[k]
v = files[k] -- chained
end
if k:find(pattern) then
if type(v) == "string" then
handle(blobtype,blobpath,v,k)
else
for _,vv in pairs(v) do
handle(blobtype,blobpath,vv,k)
end
end
end
end
end
end
end
end
--~ function input.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
--~ newname = file.addsuffix(newname,"lua")
--~ local newscript = input.clean_path(input.find_file(instance, newname))
--~ local oldscript = input.clean_path(oldname)
--~ input.report("old script", oldscript)
--~ input.report("new script", newscript)
--~ if oldscript ~= newscript and (oldscript:find(file.removesuffix(newname).."$") or oldscript:find(newname.."$")) then
--~ local newdata = io.loaddata(newscript)
--~ if newdata then
--~ input.report("old script content replaced by new content")
--~ io.savedata(oldscript,newdata)
--~ end
--~ end
--~ end
function input.update_script(instance,oldname,newname) -- oldname -> own.name, not per se a suffix
local scriptpath = "scripts/context/lua"
newname = file.addsuffix(newname,"lua")
local oldscript = input.clean_path(oldname)
input.report("to be replaced old script", oldscript)
local newscripts = input.find_files(instance, newname) or { }
if #newscripts == 0 then
input.report("unable to locate new script")
else
for _, newscript in ipairs(newscripts) do
newscript = input.clean_path(newscript)
input.report("checking new script", newscript)
if oldscript == newscript then
input.report("old and new script are the same")
elseif not newscript:find(scriptpath) then
input.report("new script should come from",scriptpath)
elseif not (oldscript:find(file.removesuffix(newname).."$") or oldscript:find(newname.."$")) then
input.report("invalid new script name")
else
local newdata = io.loaddata(newscript)
if newdata then
input.report("old script content replaced by new content")
io.savedata(oldscript,newdata)
break
else
input.report("unable to load new script")
end
end
end
end
end
--~ print(table.serialize(input.aux.splitpathexpr("/usr/share/texmf-{texlive,tetex}", {})))
-- command line resolver:
--~ print(input.resolve("abc env:tmp file:cont-en.tex path:cont-en.tex full:cont-en.tex rel:zapf/one/p-chars.tex"))
do
local resolvers = { }
resolvers.environment = function(instance,str)
return input.clean_path(os.getenv(str) or os.getenv(str:upper()) or os.getenv(str:lower()) or "")
end
resolvers.relative = function(instance,str,n)
if io.exists(str) then
-- nothing
elseif io.exists("./" .. str) then
str = "./" .. str
else
local p = "../"
for i=1,n or 2 do
if io.exists(p .. str) then
str = p .. str
break
else
p = p .. "../"
end
end
end
return input.clean_path(str)
end
resolvers.locate = function(instance,str)
local fullname = input.find_given_file(instance,str) or ""
return input.clean_path((fullname ~= "" and fullname) or str)
end
resolvers.filename = function(instance,str)
local fullname = input.find_given_file(instance,str) or ""
return input.clean_path(file.basename((fullname ~= "" and fullname) or str))
end
resolvers.pathname = function(instance,str)
local fullname = input.find_given_file(instance,str) or ""
return input.clean_path(file.dirname((fullname ~= "" and fullname) or str))
end
resolvers.env = resolvers.environment
resolvers.rel = resolvers.relative
resolvers.loc = resolvers.locate
resolvers.kpse = resolvers.locate
resolvers.full = resolvers.locate
resolvers.file = resolvers.filename
resolvers.path = resolvers.pathname
local function resolve(instance,str)
if type(str) == "table" then
for k, v in pairs(str) do
str[k] = resolve(instance,v) or v
end
elseif str and str ~= "" then
str = str:gsub("([a-z]+):([^ ]+)", function(method,target)
if resolvers[method] then
return resolvers[method](instance,target)
else
return method .. ":" .. target
end
end)
end
return str
end
input.resolve = resolve
end
if not modules then modules = { } end modules ['luat-tmp'] = {
version = 1.001,
comment = "companion to luat-lib.tex",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
--[[ldx--
This module deals with caching data. It sets up the paths and
implements loaders and savers for tables. Best is to set the
following variable. When not set, the usual paths will be
checked. Personally I prefer the (users) temporary path.
TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;.
Currently we do no locking when we write files. This is no real
problem because most caching involves fonts and the chance of them
being written at the same time is small. We also need to extend
luatools with a recache feature.
--ldx]]--
caches = caches or { }
dir = dir or { }
texmf = texmf or { }
caches.path = caches.path or nil
caches.base = caches.base or "luatex-cache"
caches.more = caches.more or "context"
caches.direct = false -- true is faster but may need huge amounts of memory
caches.trace = false
caches.tree = false
caches.paths = caches.paths or nil
caches.force = false
input.usecache = not toboolean(os.getenv("TEXMFSHARECACHE") or "false",true) -- true
function caches.temp(instance)
local function checkpath(cachepath)
if not cachepath or cachepath == "" then
return nil
elseif lfs.attributes(cachepath,"mode") == "directory" then -- lfs.isdir(cachepath) then
return cachepath
elseif caches.force or io.ask(string.format("Should I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then
dir.mkdirs(cachepath)
return (lfs.attributes(cachepath,"mode") == "directory") and cachepath
else
return nil
end
end
local cachepath = input.expanded_path_list(instance,"TEXMFCACHE")
cachepath = cachepath and #cachepath > 0 and checkpath(cachepath[1])
if not cachepath then
cachepath = os.getenv("TEXMFCACHE") or os.getenv("HOME") or os.getenv("HOMEPATH") or os.getenv("TMP") or os.getenv("TEMP") or os.getenv("TMPDIR") or nil
cachepath = checkpath(cachepath)
end
if not cachepath then
print("\nfatal error: there is no valid cache path defined\n")
os.exit()
elseif lfs.attributes(cachepath,"mode") ~= "directory" then
print(string.format("\nfatal error: cache path %s is not a directory\n",cachepath))
os.exit()
end
function caches.temp(instance)
return cachepath
end
return cachepath
end
function caches.configpath(instance)
return table.concat(instance.cnffiles,";")
end
function caches.hashed(tree)
return md5.hex((tree:lower()):gsub("[\\\/]+","/"))
end
function caches.treehash(instance)
local tree = caches.configpath(instance)
if not tree or tree == "" then
return false
else
return caches.hashed(tree)
end
end
function caches.setpath(instance,...)
if not caches.path then
if not caches.path then
caches.path = caches.temp(instance)
end
caches.path = input.clean_path(caches.path) -- to be sure
if lfs then
caches.tree = caches.tree or caches.treehash(instance)
if caches.tree then
caches.path = dir.mkdirs(caches.path,caches.base,caches.more,caches.tree)
else
caches.path = dir.mkdirs(caches.path,caches.base,caches.more)
end
end
end
if not caches.path then
caches.path = '.'
end
caches.path = input.clean_path(caches.path)
if lfs and not table.is_empty({...}) then
local pth = dir.mkdirs(caches.path,...)
return pth
end
caches.path = dir.expand_name(caches.path)
return caches.path
end
function caches.definepath(instance,category,subcategory)
return function()
return caches.setpath(instance,category,subcategory)
end
end
function caches.setluanames(path,name)
return path .. "/" .. name .. ".tma", path .. "/" .. name .. ".tmc"
end
function caches.loaddata(path,name)
local tmaname, tmcname = caches.setluanames(path,name)
local loader = loadfile(tmcname) or loadfile(tmaname)
if loader then
return loader()
else
return false
end
end
function caches.is_writable(filepath,filename)
local tmaname, tmcname = caches.setluanames(filepath,filename)
return file.is_writable(tmaname)
end
function caches.savedata(filepath,filename,data,raw) -- raw needed for file cache
local tmaname, tmcname = caches.setluanames(filepath,filename)
local reduce, simplify = true, true
if raw then
reduce, simplify = false, false
end
if caches.direct then
file.savedata(tmaname, table.serialize(data,'return',true,true))
else
table.tofile (tmaname, data,'return',true,true) -- maybe not the last true
end
utils.lua.compile(tmaname, tmcname)
end
-- here we use the cache for format loading (texconfig.[formatname|jobname])
--~ if tex and texconfig and texconfig.formatname and texconfig.formatname == "" then
if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and texmf.instance then
if not texconfig.luaname then texconfig.luaname = "cont-en.lua" end -- or luc
texconfig.formatname = caches.setpath(texmf.instance,"formats") .. "/" .. texconfig.luaname:gsub("%.lu.$",".fmt")
end
--[[ldx--
Once we found ourselves defining similar cache constructs
several times, containers were introduced. Containers are used
to collect tables in memory and reuse them when possible based
on (unique) hashes (to be provided by the calling function).
Caching to disk is disabled by default. Version numbers are
stored in the saved table which makes it possible to change the
table structures without bothering about the disk cache.
Examples of usage can be found in the font related code.
--ldx]]--
containers = { }
containers.trace = false
do -- local report
local function report(container,tag,name)
if caches.trace or containers.trace or container.trace then
logs.report(string.format("%s cache",container.subcategory),string.format("%s: %s",tag,name or 'invalid'))
end
end
local allocated = { }
-- tracing
function containers.define(category, subcategory, version, enabled)
return function()
if category and subcategory then
local c = allocated[category]
if not c then
c = { }
allocated[category] = c
end
local s = c[subcategory]
if not s then
s = {
category = category,
subcategory = subcategory,
storage = { },
enabled = enabled,
version = version or 1.000,
trace = false,
path = caches.setpath(texmf.instance,category,subcategory),
}
c[subcategory] = s
end
return s
else
return nil
end
end
end
function containers.is_usable(container, name)
return container.enabled and caches.is_writable(container.path, name)
end
function containers.is_valid(container, name)
if name and name ~= "" then
local storage = container.storage[name]
return storage and not table.is_empty(storage) and storage.cache_version == container.version
else
return false
end
end
function containers.read(container,name)
if container.enabled and not container.storage[name] then
container.storage[name] = caches.loaddata(container.path,name)
if containers.is_valid(container,name) then
report(container,"loaded",name)
else
container.storage[name] = nil
end
end
if container.storage[name] then
report(container,"reusing",name)
end
return container.storage[name]
end
function containers.write(container, name, data)
if data then
data.cache_version = container.version
if container.enabled then
local unique, shared = data.unique, data.shared
data.unique, data.shared = nil, nil
caches.savedata(container.path, name, data)
report(container,"saved",name)
data.unique, data.shared = unique, shared
end
report(container,"stored",name)
container.storage[name] = data
end
return data
end
function containers.content(container,name)
return container.storage[name]
end
end
-- since we want to use the cache instead of the tree, we will now
-- reimplement the saver.
local save_data = input.aux.save_data
input.cachepath = nil
function input.aux.save_data(instance, dataname, check)
input.cachepath = input.cachepath or caches.definepath(instance,"trees")
save_data(instance, dataname, check, function(cachename,dataname)
if input.usecache then
return file.join(input.cachepath(),caches.hashed(cachename))
else
return file.join(cachename,dataname)
end
end)
end
local load_data = input.aux.load_data
function input.aux.load_data(instance,pathname,dataname,filename)
input.cachepath = input.cachepath or caches.definepath(instance,"trees")
load_data(instance,pathname,dataname,filename,function(dataname,filename)
if input.usecache then
return file.join(input.cachepath(),caches.hashed(pathname))
else
if not filename or (filename == "") then
filename = dataname
end
return file.join(pathname,filename)
end
end)
end
-- we will make a better format, maybe something xml or just text or lua
input.automounted = input.automounted or { }
function input.automount(instance,usecache)
local mountpaths = input.simplified_list(input.expansion(instance,'TEXMFMOUNT'))
if table.is_empty(mountpaths) and usecache then
mountpaths = { caches.setpath(instance,"mount") }
end
if not table.is_empty(mountpaths) then
input.starttiming(instance)
for k, root in pairs(mountpaths) do
local f = io.open(root.."/url.tmi")
if f then
for line in f:lines() do
if line then
if line:find("^[%%#%-]") then -- or %W
-- skip
elseif line:find("^zip://") then
input.report("mounting",line)
table.insert(input.automounted,line)
input.usezipfile(instance,line)
end
end
end
f:close()
end
end
input.stoptiming(instance)
end
end
-- store info in format
input.storage = { }
input.storage.data = { }
input.storage.min = 0 -- 500
input.storage.max = input.storage.min - 1
input.storage.trace = false -- true
input.storage.done = 0
input.storage.evaluators = { }
-- (evaluate,message,names)
function input.storage.register(...)
input.storage.data[#input.storage.data+1] = { ... }
end
function input.storage.evaluate(name)
input.storage.evaluators[#input.storage.evaluators+1] = name
end
function input.storage.finalize() -- we can prepend the string with "evaluate:"
for _, t in ipairs(input.storage.evaluators) do
for i, v in pairs(t) do
if type(v) == "string" then
t[i] = loadstring(v)()
elseif type(v) == "table" then
for _, vv in pairs(v) do
if type(vv) == "string" then
t[i] = loadstring(vv)()
end
end
end
end
end
end
function input.storage.dump()
for name, data in ipairs(input.storage.data) do
local evaluate, message, original, target = data[1], data[2], data[3] ,data[4]
local name, initialize, finalize, code = nil, "", "", ""
for str in target:gmatch("([^%.]+)") do
if name then
name = name .. "." .. str
else
name = str
end
initialize = string.format("%s %s = %s or {} ", initialize, name, name)
end
if evaluate then
finalize = "input.storage.evaluate(" .. name .. ")"
end
input.storage.max = input.storage.max + 1
if input.storage.trace then
logs.report('storage',string.format('saving %s in slot %s',message,input.storage.max))
code =
initialize ..
string.format("logs.report('storage','restoring %s from slot %s') ",message,input.storage.max) ..
table.serialize(original,name) ..
finalize
else
code = initialize .. table.serialize(original,name) .. finalize
end
lua.bytecode[input.storage.max] = loadstring(code)
end
end
if lua.bytecode then -- from 0 upwards
local i = input.storage.min
while lua.bytecode[i] do
lua.bytecode[i]()
lua.bytecode[i] = nil
i = i + 1
end
input.storage.done = i
end
-- filename : luat-zip.lua
-- comment : companion to luat-lib.tex
-- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
-- copyright: PRAGMA ADE / ConTeXt Development Team
-- license : see context related readme files
if not versions then versions = { } end versions['luat-zip'] = 1.001
if zip and input then
zip.supported = true
else
zip = { }
zip.supported = false
end
if not zip.supported then
if not input then input = { } end -- will go away
function zip.openarchive (...) return nil end -- needed ?
function zip.closenarchive (...) end -- needed ?
function input.usezipfile (...) end -- needed ?
else
-- zip:///oeps.zip?name=bla/bla.tex
-- zip:///oeps.zip?tree=tex/texmf-local
local function validzip(str)
if not str:find("^zip://") then
return "zip:///" .. str
else
return str
end
end
zip.archives = { }
zip.registeredfiles = { }
function zip.openarchive(instance,name)
if not name or name == "" then
return nil
else
local arch = zip.archives[name]
if arch then
return arch
else
local full = input.find_file(instance,name) or ""
local arch = (full ~= "" and zip.open(full)) or false
zip.archives[name] = arch
return arch
end
end
end
function zip.closearchive(instance,name)
if not name or name == "" and zip.archives[name] then
zip.close(zip.archives[name])
zip.archives[name] = nil
end
end
-- zip:///texmf.zip?tree=/tex/texmf
-- zip:///texmf.zip?tree=/tex/texmf-local
-- zip:///texmf-mine.zip?tree=/tex/texmf-projects
function input.locators.zip(instance,specification) -- where is this used? startup zips (untested)
specification = input.splitmethod(specification)
local zipfile = specification.path
local zfile = zip.openarchive(instance,name) -- tricky, could be in to be initialized tree
if zfile then
input.logger('! zip locator', specification.original ..' found')
else
input.logger('? zip locator', specification.original ..' not found')
end
end
function input.hashers.zip(instance,tag,name)
input.report("loading zip file",name,"as",tag)
input.usezipfile(instance,tag .."?tree=" .. name)
end
function input.concatinators.zip(tag,path,name)
if not path or path == "" then
return tag .. '?name=' .. name
else
return tag .. '?name=' .. path .. "/" .. name
end
end
function input.is_readable.zip(name)
return true
end
function input.finders.zip(instance,specification,filetype)
specification = input.splitmethod(specification)
if specification.path then
local q = url.query(specification.query)
if q.name then
local zfile = zip.openarchive(instance,specification.path)
if zfile then
input.logger('! zip finder',specification.path)
local dfile = zfile:open(q.name)
if dfile then
dfile = zfile:close()
input.logger('+ zip finder',q.name)
return specification.original
end
else
input.logger('? zip finder',specification.path)
end
end
end
input.logger('- zip finder',filename)
return unpack(input.finders.notfound)
end
function input.openers.zip(instance,specification)
local zipspecification = input.splitmethod(specification)
if zipspecification.path then
local q = url.query(zipspecification.query)
if q.name then
local zfile = zip.openarchive(instance,zipspecification.path)
if zfile then
input.logger('+ zip starter',zipspecification.path)
local dfile = zfile:open(q.name)
if dfile then
input.show_open(specification)
return input.openers.text_opener(specification,dfile,'zip')
end
else
input.logger('- zip starter',zipspecification.path)
end
end
end
input.logger('- zip opener',filename)
return unpack(input.openers.notfound)
end
function input.loaders.zip(instance,specification)
specification = input.splitmethod(specification)
if specification.path then
local q = url.query(specification.query)
if q.name then
local zfile = zip.openarchive(instance,specification.path)
if zfile then
input.logger('+ zip starter',specification.path)
local dfile = zfile:open(q.name)
if dfile then
input.show_load(filename)
input.logger('+ zip loader',filename)
local s = dfile:read("*all")
dfile:close()
return true, s, #s
end
else
input.logger('- zip starter',specification.path)
end
end
end
input.logger('- zip loader',filename)
return unpack(input.openers.notfound)
end
-- zip:///somefile.zip
-- zip:///somefile.zip?tree=texmf-local -> mount
function input.usezipfile(instance,zipname)
zipname = validzip(zipname)
input.logger('! zip use','file '..zipname)
local specification = input.splitmethod(zipname)
local zipfile = specification.path
if zipfile and not zip.registeredfiles[zipname] then
local tree = url.query(specification.query).tree or ""
input.logger('! zip register','file '..zipname)
local z = zip.openarchive(instance,zipfile)
if z then
input.logger("= zipfile","registering "..zipname)
input.starttiming(instance)
input.aux.prepend_hash(instance,'zip',zipname,zipfile)
input.aux.extend_texmf_var(instance,zipname) -- resets hashes too
zip.registeredfiles[zipname] = z
instance.files[zipname] = input.aux.register_zip_file(z,tree or "")
input.stoptiming(instance)
else
input.logger("? zipfile","unknown "..zipname)
end
else
input.logger('! zip register','no file '..zipname)
end
end
function input.aux.register_zip_file(z,tree)
local files, filter = { }, ""
if tree == "" then
filter = "^(.+)/(.-)$"
else
filter = "^"..tree.."/(.+)/(.-)$"
end
input.logger('= zip filter',filter)
local register, n = input.aux.register_file, 0
for i in z:files() do
local path, name = i.filename:match(filter)
if path then
if name and name ~= '' then
register(files, name, path)
n = n + 1
else
-- directory
end
else
register(files, i.filename, '')
n = n + 1
end
end
input.report('= zip entries',n)
return files
end
end
-- filename : luat-zip.lua
-- comment : companion to luat-lib.tex
-- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
-- copyright: PRAGMA ADE / ConTeXt Development Team
-- license : see context related readme files
if not versions then versions = { } end versions['luat-tex'] = 1.001
-- special functions that deal with io
if texconfig and not texlua then
input.level = input.level or 0
if input.logmode() == 'xml' then
function input.show_open(name)
input.level = input.level + 1
texio.write_nl("")
end
function input.show_close(name)
texio.write(" ")
input.level = input.level - 1
end
function input.show_load(name)
texio.write_nl("") -- level?
end
else
function input.show_open () end
function input.show_close() end
function input.show_load () end
end
function input.finders.generic(instance,tag,filename,filetype)
local foundname = input.find_file(instance,filename,filetype)
if foundname and foundname ~= "" then
input.logger('+ ' .. tag .. ' finder',filename,'filetype')
return foundname
else
input.logger('- ' .. tag .. ' finder',filename,'filetype')
return unpack(input.finders.notfound)
end
end
input.filters.dynamic_translator = nil
input.filters.frozen_translator = nil
input.filters.utf_translator = nil
function input.openers.text_opener(filename,file_handle,tag)
local u = unicode.utftype(file_handle)
local t = { }
if u > 0 then
input.logger('+ ' .. tag .. ' opener (' .. unicode.utfname[u] .. ')',filename)
local l
if u > 2 then
l = unicode.utf32_to_utf8(file_handle:read("*a"),u==4)
else
l = unicode.utf16_to_utf8(file_handle:read("*a"),u==2)
end
file_handle:close()
t = {
utftype = u, -- may go away
lines = l,
current = 0, -- line number, not really needed
handle = nil,
noflines = #l,
close = function()
input.logger('= ' .. tag .. ' closer (' .. unicode.utfname[u] .. ')',filename)
input.show_close(filename)
end,
--~ getline = function(n)
--~ local line = t.lines[n]
--~ if not line or line == "" then
--~ return ""
--~ else
--~ local translator = input.filters.utf_translator
--~ return (translator and translator(line)) or line
--~ end
--~ end,
reader = function(self)
self = self or t
local current, lines = self.current, self.lines
if current >= #lines then
return nil
else
current = current + 1
self.current = current
local line = lines[current]
if line == "" then
return ""
else
local translator = input.filters.utf_translator
-- return (translator and translator(line)) or line
if translator then
return translator(line)
else
return line
end
end
end
end
}
else
input.logger('+ ' .. tag .. ' opener',filename)
-- todo: file;name -> freeze / eerste regel scannen -> freeze
local filters = input.filters
t = {
reader = function(self)
local line = file_handle:read()
if line == "" then
return ""
end
local translator = filters.utf_translator
if translator then
return translator(line)
end
translator = filters.dynamic_translator
if translator then
return translator(line)
end
return line
end,
close = function()
input.logger('= ' .. tag .. ' closer',filename)
input.show_close(filename)
file_handle:close()
end,
handle = function()
return file_handle
end,
noflines = function()
t.noflines = io.noflines(file_handle)
return t.noflines
end
}
end
return t
end
function input.openers.generic(instance,tag,filename)
if filename and filename ~= "" then
local f = io.open(filename,"r")
if f then
input.show_open(filename)
return input.openers.text_opener(filename,f,tag)
end
end
input.logger('- ' .. tag .. ' opener',filename)
return unpack(input.openers.notfound)
end
function input.loaders.generic(instance,tag,filename)
if filename and filename ~= "" then
local f = io.open(filename,"rb")
if f then
input.show_load(filename)
input.logger('+ ' .. tag .. ' loader',filename)
local s = f:read("*a")
f:close()
if s then
return true, s, #s
end
end
end
input.logger('- ' .. tag .. ' loader',filename)
return unpack(input.loaders.notfound)
end
function input.finders.tex(instance,filename,filetype)
return input.finders.generic(instance,'tex',filename,filetype)
end
function input.openers.tex(instance,filename)
return input.openers.generic(instance,'tex',filename)
end
function input.loaders.tex(instance,filename)
return input.loaders.generic(instance,'tex',filename)
end
end
-- callback into the file io and related things; disabling kpse
if texconfig and not texlua then do
-- this is not the right place, because we refer to quite some not yet defined tables, but who cares ...
ctx = ctx or { }
local ss = { }
function ctx.writestatus(a,b)
local s = ss[a]
if not ss[a] then
s = a:rpadd(15) .. ": "
ss[a] = s
end
texio.write_nl(s .. b .. "\n")
end
-- this will become: ctx.install_statistics(fnc() return ..,.. end) etc
local statusinfo, n = { }, 0
function ctx.register_statistics(tag,pattern,fnc)
statusinfo[#statusinfo+1] = { tag, pattern, fnc }
if #tag > n then n = #tag end
end
function ctx.show_statistics() -- todo: move calls
if caches then
ctx.register_statistics("used config path", "%s", function() return caches.configpath(texmf.instance) end)
ctx.register_statistics("used cache path", "%s", function() return caches.path end)
end
if status.luabytecodes > 0 and input.storage and input.storage.done then
ctx.register_statistics("modules/dumps/instances", "%s/%s/%s", function() return status.luabytecodes-500, input.storage.done, status.luastates end)
end
if texmf.instance then
ctx.register_statistics("input load time", "%s seconds", function() return input.loadtime(texmf.instance) end)
end
if fonts then
ctx.register_statistics("fonts load time","%s seconds", function() return input.loadtime(fonts) end)
end
if xml then
ctx.register_statistics("xml load time", "%s seconds, backreferences: %i, outer filtering time: %s", function() return input.loadtime(xml), #lxml.self, input.loadtime(lxml) end)
end
if mptopdf then
ctx.register_statistics("mps conversion time", "%s seconds", function() return input.loadtime(mptopdf) end)
end
if nodes then
ctx.register_statistics("node processing time", "%s seconds (including kernel)", function() return input.loadtime(nodes) end)
end
if kernel then
ctx.register_statistics("kernel processing time", "%s seconds", function() return input.loadtime(kernel) end)
end
if attributes then
ctx.register_statistics("attribute processing time", "%s seconds", function() return input.loadtime(attributes) end)
end
if languages then
ctx.register_statistics("language load time", "%s seconds, n=%s", function() return input.loadtime(languages), languages.hyphenation.n() end)
end
if figures then
ctx.register_statistics("graphics processing time", "%s seconds, n=%s (including tex)", function() return input.loadtime(figures), figures.n or "?" end)
end
if metapost then
ctx.register_statistics("metapost processing time", "%s seconds, loading: %s seconds, execution: %s seconds, n: %s", function() return input.loadtime(metapost), input.loadtime(mplib), input.loadtime(metapost.exectime), metapost.n end)
end
if status.luastate_bytes then
ctx.register_statistics("current memory usage", "%s bytes", function() return status.luastate_bytes end)
end
if nodes then
ctx.register_statistics("cleaned up reserved nodes", "%s nodes, %s lists of %s", function() return nodes.cleanup_reserved(tex.count[24]) end) -- \topofboxstack
end
if status.node_mem_usage then
ctx.register_statistics("node memory usage", "%s", function() return status.node_mem_usage end)
end
if languages then
ctx.register_statistics("loaded patterns", "%s", function() return languages.logger.report() end)
end
if fonts then
ctx.register_statistics("loaded fonts", "%s", function() return fonts.logger.report() end)
end
if xml then -- so we are in mkiv, we need a different check
ctx.register_statistics("runtime", "%s seconds, %i processed pages, %i shipped pages, %.3f pages/second", function()
input.stoptiming(texmf)
local runtime = input.loadtime(texmf)
local shipped = tex.count['nofshipouts']
local pages = tex.count['realpageno'] - 1
local persecond = shipped / runtime
return runtime, pages, shipped, persecond
end)
end
for _, t in ipairs(statusinfo) do
local tag, pattern, fnc = t[1], t[2], t[3]
ctx.writestatus("mkiv lua stats", string.format("%s - %s", tag:rpadd(n," "), pattern:format(fnc())))
end
end
end end
if texconfig and not texlua then
texconfig.kpse_init = false
texconfig.trace_file_names = input.logmode() == 'tex'
texconfig.max_print_line = 100000
-- if still present, we overload kpse (put it off-line so to say)
if not texmf then texmf = { } end
input.starttiming(texmf)
if not texmf.instance then
if not texmf.instance then -- prevent a second loading
texmf.instance = input.reset()
texmf.instance.progname = environment.progname or 'context'
texmf.instance.engine = environment.engine or 'luatex'
texmf.instance.validfile = input.validctxfile
input.load(texmf.instance)
end
if callback then
callback.register('find_read_file' , function(id,name) return input.findtexfile(texmf.instance,name) end)
callback.register('open_read_file' , function( name) return input.opentexfile(texmf.instance,name) end)
end
if callback then
callback.register('find_data_file' , function(name) return input.findbinfile(texmf.instance,name,"tex") end)
callback.register('find_enc_file' , function(name) return input.findbinfile(texmf.instance,name,"enc") end)
callback.register('find_font_file' , function(name) return input.findbinfile(texmf.instance,name,"tfm") end)
callback.register('find_format_file' , function(name) return input.findbinfile(texmf.instance,name,"fmt") end)
callback.register('find_image_file' , function(name) return input.findbinfile(texmf.instance,name,"tex") end)
callback.register('find_map_file' , function(name) return input.findbinfile(texmf.instance,name,"map") end)
callback.register('find_ocp_file' , function(name) return input.findbinfile(texmf.instance,name,"ocp") end)
callback.register('find_opentype_file' , function(name) return input.findbinfile(texmf.instance,name,"otf") end)
callback.register('find_output_file' , function(name) return name end)
callback.register('find_pk_file' , function(name) return input.findbinfile(texmf.instance,name,"pk") end)
callback.register('find_sfd_file' , function(name) return input.findbinfile(texmf.instance,name,"sfd") end)
callback.register('find_truetype_file' , function(name) return input.findbinfile(texmf.instance,name,"ttf") end)
callback.register('find_type1_file' , function(name) return input.findbinfile(texmf.instance,name,"pfb") end)
callback.register('find_vf_file' , function(name) return input.findbinfile(texmf.instance,name,"vf") end)
callback.register('read_data_file' , function(file) return input.loadbinfile(texmf.instance,file,"tex") end)
callback.register('read_enc_file' , function(file) return input.loadbinfile(texmf.instance,file,"enc") end)
callback.register('read_font_file' , function(file) return input.loadbinfile(texmf.instance,file,"tfm") end)
-- format
-- image
callback.register('read_map_file' , function(file) return input.loadbinfile(texmf.instance,file,"map") end)
callback.register('read_ocp_file' , function(file) return input.loadbinfile(texmf.instance,file,"ocp") end)
callback.register('read_opentype_file' , function(file) return input.loadbinfile(texmf.instance,file,"otf") end)
-- output
callback.register('read_pk_file' , function(file) return input.loadbinfile(texmf.instance,file,"pk") end)
callback.register('read_sfd_file' , function(file) return input.loadbinfile(texmf.instance,file,"sfd") end)
callback.register('read_truetype_file' , function(file) return input.loadbinfile(texmf.instance,file,"ttf") end)
callback.register('read_type1_file' , function(file) return input.loadbinfile(texmf.instance,file,"pfb") end)
callback.register('read_vf_file' , function(file) return input.loadbinfile(texmf.instance,file,"vf" ) end)
end
if callback and environment.aleph_mode then
callback.register('find_font_file' , function(name) return input.findbinfile(texmf.instance,name,"ofm") end)
callback.register('read_font_file' , function(file) return input.loadbinfile(texmf.instance,file,"ofm") end)
callback.register('find_vf_file' , function(name) return input.findbinfile(texmf.instance,name,"ovf") end)
callback.register('read_vf_file' , function(file) return input.loadbinfile(texmf.instance,file,"ovf") end)
end
if callback then
callback.register('find_write_file' , function(id,name) return name end)
end
if callback and (not config or (#config == 0)) then
callback.register('find_format_file' , function(name) return name end)
end
if callback and false then
for k, v in pairs(callback.list()) do
if not v then texio.write_nl("callback "..k.." is not set") end
end
end
if callback then
input.start_actions = { }
input.stop_actions = { }
function input.register_start_actions(f) table.insert(input.start_actions, f) end
function input.register_stop_actions (f) table.insert(input.stop_actions, f) end
--~ callback.register('start_run', function() for _, a in pairs(input.start_actions) do a() end end)
--~ callback.register('stop_run' , function() for _, a in pairs(input.stop_actions ) do a() end end)
end
if callback then
if input.logmode() == 'xml' then
function input.start_page_number()
texio.write_nl("")
texio.write_nl("")
end
callback.register('start_page_number' , input.start_page_number)
callback.register('stop_page_number' , input.stop_page_number )
function input.report_output_pages(p,b)
texio.write_nl(""..p.."")
texio.write_nl(""..b.."")
texio.write_nl("")
end
function input.report_output_log()
end
callback.register('report_output_pages', input.report_output_pages)
callback.register('report_output_log' , input.report_output_log )
function input.start_run()
texio.write_nl("")
texio.write_nl("")
texio.write_nl("")
end
function input.stop_run()
texio.write_nl("")
end
function input.show_statistics()
for k,v in pairs(status.list()) do
texio.write_nl("log",""..tostring(v).."")
end
end
table.insert(input.start_actions, input.start_run)
table.insert(input.stop_actions , input.show_statistics)
table.insert(input.stop_actions , input.stop_run)
else
table.insert(input.stop_actions , input.show_statistics)
end
callback.register('start_run', function() for _, a in pairs(input.start_actions) do a() end end)
callback.register('stop_run' , function() for _, a in pairs(input.stop_actions ) do a() end ctx.show_statistics() end)
end
end
if kpse then
function kpse.find_file(filename,filetype,mustexist)
return input.find_file(texmf.instance,filename,filetype,mustexist)
end
function kpse.expand_path(variable)
return input.expand_path(texmf.instance,variable)
end
function kpse.expand_var(variable)
return input.expand_var(texmf.instance,variable)
end
function kpse.expand_braces(variable)
return input.expand_braces(texmf.instance,variable)
end
end
end
-- program specific configuration (memory settings and alike)
if texconfig and not texlua then
luatex = luatex or { }
luatex.variablenames = {
'main_memory', 'extra_mem_bot', 'extra_mem_top',
'buf_size','expand_depth',
'font_max', 'font_mem_size',
'hash_extra', 'max_strings', 'pool_free', 'pool_size', 'string_vacancies',
'obj_tab_size', 'pdf_mem_size', 'dest_names_size',
'nest_size', 'param_size', 'save_size', 'stack_size',
'trie_size', 'hyph_size', 'max_in_open',
'ocp_stack_size', 'ocp_list_size', 'ocp_buf_size'
}
function luatex.variables()
local t, x = { }, nil
for _,v in pairs(luatex.variablenames) do
x = input.var_value(texmf.instance,v)
if x and x:find("^%d+$") then
t[v] = tonumber(x)
end
end
return t
end
function luatex.setvariables(tab)
for k,v in pairs(luatex.variables()) do
tab[k] = v
end
end
if not luatex.variables_set then
luatex.setvariables(texconfig)
luatex.variables_set = true
end
texconfig.max_print_line = 100000
texconfig.max_in_open = 127
end
-- some tex basics
if not cs then cs = { } end
function cs.def(k,v)
tex.sprint(tex.texcatcodes, "\\def\\" .. k .. "{" .. v .. "}")
end
function cs.chardef(k,v)
tex.sprint(tex.texcatcodes, "\\chardef\\" .. k .. "=" .. v .. "\\relax")
end
function cs.boolcase(b)
if b then tex.write(1) else tex.write(0) end
end
function cs.testcase(b)
if b then
tex.sprint(tex.texcatcodes, "\\firstoftwoarguments")
else
tex.sprint(tex.texcatcodes, "\\secondoftwoarguments")
end
end
if not modules then modules = { } end modules ['luat-kps'] = {
version = 1.001,
comment = "companion to luatools.lua",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
--[[ldx--
This file is used when we want the input handlers to behave like
kpsewhich. What to do with the following:
{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}
$SELFAUTOLOC : /usr/tex/bin/platform
$SELFAUTODIR : /usr/tex/bin
$SELFAUTOPARENT : /usr/tex
How about just forgetting abou them?
--ldx]]--
input = input or { }
input.suffixes = input.suffixes or { }
input.formats = input.formats or { }
input.suffixes['gf'] = { 'gf' }
input.suffixes['pk'] = { 'pk' }
input.suffixes['base'] = { 'base' }
input.suffixes['bib'] = { 'bib' }
input.suffixes['bst'] = { 'bst' }
input.suffixes['cnf'] = { 'cnf' }
input.suffixes['mem'] = { 'mem' }
input.suffixes['mf'] = { 'mf' }
input.suffixes['mfpool'] = { 'pool' }
input.suffixes['mft'] = { 'mft' }
input.suffixes['mppool'] = { 'pool' }
input.suffixes['graphic/figure'] = { 'eps', 'epsi' }
input.suffixes['texpool'] = { 'pool' }
input.suffixes['PostScript header'] = { 'pro' }
input.suffixes['ist'] = { 'ist' }
input.suffixes['web'] = { 'web', 'ch' }
input.suffixes['cweb'] = { 'w', 'web', 'ch' }
input.suffixes['cmap files'] = { 'cmap' }
input.suffixes['lig files'] = { 'lig' }
input.suffixes['bitmap font'] = { }
input.suffixes['MetaPost support'] = { }
input.suffixes['TeX system documentation'] = { }
input.suffixes['TeX system sources'] = { }
input.suffixes['dvips config'] = { }
input.suffixes['type42 fonts'] = { }
input.suffixes['web2c files'] = { }
input.suffixes['other text files'] = { }
input.suffixes['other binary files'] = { }
input.suffixes['opentype fonts'] = { 'otf' }
input.suffixes['fmt'] = { 'fmt' }
input.suffixes['texmfscripts'] = { 'rb','lua','py','pl' }
input.suffixes['pdftex config'] = { }
input.suffixes['Troff fonts'] = { }
input.suffixes['ls-R'] = { }
--[[ldx--
If you wondered abou tsome of the previous mappings, how about
the next bunch:
--ldx]]--
input.formats['bib'] = ''
input.formats['bst'] = ''
input.formats['mft'] = ''
input.formats['ist'] = ''
input.formats['web'] = ''
input.formats['cweb'] = ''
input.formats['MetaPost support'] = ''
input.formats['TeX system documentation'] = ''
input.formats['TeX system sources'] = ''
input.formats['Troff fonts'] = ''
input.formats['dvips config'] = ''
input.formats['graphic/figure'] = ''
input.formats['ls-R'] = ''
input.formats['other text files'] = ''
input.formats['other binary files'] = ''
input.formats['gf'] = ''
input.formats['pk'] = ''
input.formats['base'] = 'MFBASES'
input.formats['cnf'] = ''
input.formats['mem'] = 'MPMEMS'
input.formats['mf'] = 'MFINPUTS'
input.formats['mfpool'] = 'MFPOOL'
input.formats['mppool'] = 'MPPOOL'
input.formats['texpool'] = 'TEXPOOL'
input.formats['PostScript header'] = 'TEXPSHEADERS'
input.formats['cmap files'] = 'CMAPFONTS'
input.formats['type42 fonts'] = 'T42FONTS'
input.formats['web2c files'] = 'WEB2C'
input.formats['pdftex config'] = 'PDFTEXCONFIG'
input.formats['texmfscripts'] = 'TEXMFSCRIPTS'
input.formats['bitmap font'] = ''
input.formats['lig files'] = 'LIGFONTS'
-- end library merge
-- We initialize some characteristics of this program. We need to
-- do this before we load the libraries, else own.name will not be
-- properly set (handy for selfcleaning the file). It's an ugly
-- looking piece of code.
own = { }
own.libs = { -- todo: check which ones are really needed
'l-string.lua',
'l-lpeg.lua',
'l-table.lua',
'l-io.lua',
'l-number.lua',
'l-set.lua',
'l-os.lua',
'l-md5.lua',
'l-file.lua',
'l-url.lua',
'l-dir.lua',
'l-boolean.lua',
'l-unicode.lua',
'l-utils.lua',
'luat-lib.lua',
'luat-inp.lua',
'luat-tmp.lua',
'luat-zip.lua',
'luat-tex.lua',
'luat-kps.lua',
}
-- We need this hack till luatex is fixed.
if arg and arg[0] == 'luatex' and arg[1] == "--luaonly" then
arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil
end
-- End of hack.
own.name = (environment and environment.ownname) or arg[0] or 'luatools.lua'
own.path = string.match(own.name,"^(.+)[\\/].-$") or "."
own.list = { '.' }
if own.path ~= '.' then
table.insert(own.list,own.path)
end
table.insert(own.list,own.path.."/../../../tex/context/base")
table.insert(own.list,own.path.."/mtx")
table.insert(own.list,own.path.."/../sources")
function locate_libs()
for _, lib in pairs(own.libs) do
for _, pth in pairs(own.list) do
local filename = string.gsub(pth .. "/" .. lib,"\\","/")
local codeblob = loadfile(filename)
if codeblob then
codeblob()
own.list = { pth } -- speed up te search
break
end
end
end
end
if not input then
locate_libs()
end
if not input then
print("")
print("Luatools is unable to start up due to lack of libraries. You may")
print("try to run 'lua luatools.lua --selfmerge' in the path where this")
print("script is located (normally under ..../scripts/context/lua) which")
print("will make luatools library independent.")
os.exit()
end
instance = input.reset()
input.verbose = environment.arguments["verbose"] or false
input.banner = 'LuaTools | '
utils.report = input.report
input.defaultlibs = { -- not all are needed
'l-string.lua', 'l-lpeg.lua', 'l-table.lua', 'l-boolean.lua', 'l-number.lua', 'l-set.lua', 'l-unicode.lua',
'l-md5.lua', 'l-os.lua', 'l-io.lua', 'l-file.lua', 'l-url.lua', 'l-dir.lua', 'l-utils.lua', 'l-tex.lua',
'luat-env.lua', 'luat-lib.lua', 'luat-inp.lua', 'luat-tmp.lua', 'luat-zip.lua', 'luat-tex.lua'
}
-- todo: use environment.argument() instead of environment.arguments[]
instance.engine = environment.arguments["engine"] or 'luatex'
instance.progname = environment.arguments["progname"] or 'context'
instance.luaname = environment.arguments["luafile"] or "" -- environment.ownname or ""
instance.lualibs = environment.arguments["lualibs"] or table.concat(input.defaultlibs,",")
instance.allresults = environment.arguments["all"] or false
instance.pattern = environment.arguments["pattern"] or nil
instance.sortdata = environment.arguments["sort"] or false
instance.kpseonly = not environment.arguments["all"] or false
instance.my_format = environment.arguments["format"] or instance.format
instance.lsrmode = environment.arguments["lsr"] or false
if type(instance.pattern) == 'boolean' then
input.report("invalid pattern specification") -- toto, force verbose for one message
instance.pattern = nil
end
if environment.arguments["trace"] then input.settrace(environment.arguments["trace"]) end
if environment.arguments["minimize"] then
if input.validators.visibility[instance.progname] then
instance.validfile = input.validators.visibility[instance.progname]
end
end
function input.my_prepare_a(instance)
input.resetconfig(instance)
input.identify_cnf(instance)
input.load_lua(instance)
input.expand_variables(instance)
input.load_cnf(instance)
input.expand_variables(instance)
end
function input.my_prepare_b(instance)
input.my_prepare_a(instance)
input.load_hash(instance)
input.automount(instance)
end
-- barename
if not messages then messages = { } end
messages.no_ini_file = [[
There is no lua initialization file found. This file can be forced by the
"--progname" directive, or specified with "--luaname", or it is derived
automatically from the formatname (aka jobname). It may be that you have
to regenerate the file database using "luatools --generate".
]]
messages.help = [[
--generate generate file database
--variables show configuration variables
--expansions show expanded variables
--configurations show configuration order
--expand-braces expand complex variable
--expand-path expand variable (resolve paths)
--expand-var expand variable (resolve references)
--show-path show path expansion of ...
--var-value report value of variable
--find-file report file location
--find-path report path of file
--make or --ini make luatex format
--run or --fmt= run luatex format
--luafile=str lua inifile (default is .lua)
--lualibs=list libraries to assemble (optional when --compile)
--compile assemble and compile lua inifile
--mkii force context mkii mode (only for testing, not usable!)
--verbose give a bit more info
--minimize optimize lists for format
--all show all found files
--sort sort cached data
--engine=str target engine
--progname=str format or backend
--pattern=str filter variables
--lsr use lsr and cnf directly
]]
function input.my_make_format(instance,texname)
if texname and texname ~= "" then
if input.usecache then
local path = file.join(caches.setpath(instance,"formats")) -- maybe platform
if path and lfs then
lfs.chdir(path)
end
end
local barename = texname:gsub("%.%a+$","")
if barename == texname then
texname = texname .. ".tex"
end
local fullname = input.find_files(instance,texname)[1] or ""
if fullname == "" then
input.report("no tex file with name",texname)
else
local luaname, lucname, luapath, lualibs = "", "", "", { }
-- the following is optional, since context.lua can also
-- handle this collect and compile business
if environment.arguments["compile"] then
if luaname == "" then luaname = barename end
input.report("creating initialization file " .. luaname)
luapath = file.dirname(luaname)
if luapath == "" then
luapath = file.dirname(texname)
end
if luapath == "" then
luapath = file.dirname(input.find_files(instance,texname)[1] or "")
end
lualibs = string.split(instance.lualibs,",")
luaname = file.basename(barename .. ".lua")
lucname = file.basename(barename .. ".luc")
-- todo: when this fails, we can just copy the merged libraries from
-- luatools since they are normally the same, at least for context
if lualibs[1] then
local firstlib = file.join(luapath,lualibs[1])
if not lfs.isfile(firstlib) then
local foundname = input.find_files(instance,lualibs[1])[1]
if foundname then
input.report("located library path : " .. luapath)
luapath = file.dirname(foundname)
end
end
end
input.report("using library path : " .. luapath)
input.report("using lua libraries: " .. table.join(lualibs," "))
utils.merger.selfcreate(lualibs,luapath,luaname)
if utils.lua.compile(luaname, lucname) and io.exists(lucname) then
luaname = lucname
input.report("using compiled initialization file " .. lucname)
else
input.report("using uncompiled initialization file " .. luaname)
end
else
for _, v in pairs({instance.luaname, instance.progname, barename}) do
v = string.gsub(v..".lua","%.lua%.lua$",".lua")
if v and (v ~= "") then
luaname = input.find_files(instance,v)[1] or ""
if luaname ~= "" then
break
end
end
end
end
if luaname == "" then
input.reportlines(messages.no_ini_file)
input.report("texname : " .. texname)
input.report("luaname : " .. instance.luaname)
input.report("progname : " .. instance.progname)
input.report("barename : " .. barename)
else
input.report("using lua initialization file " .. luaname)
local flags = { "--ini" }
if environment.arguments["mkii"] then
flags[#flags+1] = "--progname=" .. instance.progname
else
flags[#flags+1] = "--lua=" .. string.quote(luaname)
end
local bs = (environment.platform == "unix" and "\\\\") or "\\" -- todo: make a function
local command = "luatex ".. table.concat(flags," ") .. " " .. string.quote(fullname) .. " " .. bs .. "dump"
input.report("running command: " .. command .. "\n")
os.spawn(command)
end
end
else
input.report("no tex file given")
end
end
function input.my_run_format(instance,name,data,more)
-- hm, rather old code here; we can now use the file.whatever functions
if name and (name ~= "") then
local barename = name:gsub("%.%a+$","")
local fmtname = ""
if input.usecache then
local path = file.join(caches.setpath(instance,"formats")) -- maybe platform
fmtname = file.join(path,barename..".fmt") or ""
end
if fmtname == "" then
fmtname = input.find_files(instance,barename..".fmt")[1] or ""
end
fmtname = input.clean_path(fmtname)
barename = fmtname:gsub("%.%a+$","")
if fmtname == "" then
input.report("no format with name",name)
else
local luaname = barename .. ".luc"
local f = io.open(luaname)
if not f then
luaname = barename .. ".lua"
f = io.open(luaname)
end
if f then
f:close()
local command = "luatex --fmt=" .. string.quote(barename) .. " --lua=" .. string.quote(luaname) .. " " .. string.quote(data) .. " " .. string.quote(more)
input.report("running command: " .. command)
os.spawn(command)
else
input.report("using format name",fmtname)
input.report("no luc/lua with name",barename)
end
end
end
end
-- helpers for verbose lists
input.listers = input.listers or { }
local function tabstr(str)
if type(str) == 'table' then
return table.concat(str," | ")
else
return str
end
end
local function list(instance,list)
local pat = string.upper(instance.pattern or "","")
for _,key in pairs(table.sortedkeys(list)) do
if instance.pattern == "" or string.find(key:upper(),pat) then
if instance.kpseonly then
if instance.kpsevars[key] then
print(format("%s=%s",key,tabstr(list[key])))
end
else
print(format('%s %s=%s',(instance.kpsevars[key] and 'K') or 'E',key,tabstr(list[key])))
end
end
end
end
function input.listers.variables (instance) list(instance,instance.variables ) end
function input.listers.expansions(instance) list(instance,instance.expansions) end
function input.listers.configurations(instance)
for _,key in pairs(table.sortedkeys(instance.kpsevars)) do
if not instance.pattern or (instance.pattern=="") or key:find(instance.pattern) then
print(key.."\n")
for i,c in ipairs(instance.order) do
local str = c[key]
if str then
print(format("\t%s\t\t%s",i,input.aux.tabstr(str)))
end
end
print()
end
end
end
input.report(banner,"\n")
local ok = true
if environment.arguments["find-file"] then
input.my_prepare_b(instance)
instance.format = environment.arguments["format"] or instance.format
if instance.pattern then
instance.allresults = true
input.for_files(instance, input.find_files, { instance.pattern }, instance.my_format)
else
input.for_files(instance, input.find_files, environment.files, instance.my_format)
end
elseif environment.arguments["find-path"] then
input.my_prepare_b(instance)
local path = input.find_file(instance, environment.files[1], instance.my_format)
if input.verbose then
input.report(file.dirname(path))
else
print(file.dirname(path))
end
--~ elseif environment.arguments["first-writable-path"] then
--~ input.my_prepare_b(instance)
--~ input.report(input.first_writable_path(instance,environment.files[1] or "."))
elseif environment.arguments["run"] then
input.my_prepare_a(instance) -- ! no need for loading databases
input.verbose = true
input.my_run_format(instance,environment.files[1] or "",environment.files[2] or "",environment.files[3] or "")
elseif environment.arguments["fmt"] then
input.my_prepare_a(instance) -- ! no need for loading databases
input.verbose = true
input.my_run_format(instance,environment.arguments["fmt"], environment.files[1] or "",environment.files[2] or "")
elseif environment.arguments["expand-braces"] then
input.my_prepare_a(instance)
input.for_files(instance, input.expand_braces, environment.files)
elseif environment.arguments["expand-path"] then
input.my_prepare_a(instance)
input.for_files(instance, input.expand_path, environment.files)
elseif environment.arguments["expand-var"] or environment.arguments["expand-variable"] then
input.my_prepare_a(instance)
input.for_files(instance, input.expand_var, environment.files)
elseif environment.arguments["show-path"] or environment.arguments["path-value"] then
input.my_prepare_a(instance)
input.for_files(instance, input.show_path, environment.files)
elseif environment.arguments["var-value"] or environment.arguments["show-value"] then
input.my_prepare_a(instance)
input.for_files(instance, input.var_value, environment.files)
elseif environment.arguments["format-path"] then
input.my_prepare_b(instance)
input.report(caches.setpath(instance,"format"))
elseif instance.pattern then -- brrr
input.my_prepare_b(instance)
instance.format = environment.arguments["format"] or instance.format
instance.allresults = true
input.for_files(instance, input.find_files, { instance.pattern }, instance.my_format)
elseif environment.arguments["generate"] then
instance.renewcache = true
input.verbose = true
input.my_prepare_b(instance)
elseif environment.arguments["make"] or environment.arguments["ini"] or environment.arguments["compile"] then
input.my_prepare_b(instance)
input.verbose = true
input.my_make_format(instance,environment.files[1] or "")
elseif environment.arguments["selfmerge"] then
utils.merger.selfmerge(own.name,own.libs,own.list)
elseif environment.arguments["selfclean"] then
utils.merger.selfclean(own.name)
elseif environment.arguments["selfupdate"] then
input.my_prepare_b(instance)
input.verbose = true
input.update_script(instance,own.name,"luatools")
elseif environment.arguments["variables"] or environment.arguments["show-variables"] then
input.my_prepare_a(instance)
input.listers.variables(instance)
elseif environment.arguments["expansions"] or environment.arguments["show-expansions"] then
input.my_prepare_a(instance)
input.listers.expansions(instance)
elseif environment.arguments["configurations"] or environment.arguments["show-configurations"] then
input.my_prepare_a(instance)
input.listers.configurations(instance)
elseif environment.arguments["help"] or (environment.files[1]=='help') or (#environment.files==0) then
if not input.verbose then
input.verbose = true
input.report(banner,"\n")
end
input.reportlines(messages.help)
else
input.my_prepare_b(instance)
input.for_files(instance, input.find_files, environment.files, instance.my_format)
end
if input.verbose then
input.report("")
input.report(string.format("runtime: %0.3f seconds",os.runtime()))
end
--~ if ok then
--~ input.report("exit code: 0") os.exit(0)
--~ else
--~ input.report("exit code: 1") os.exit(1)
--~ end
if environment.platform == "unix" then
io.write("\n")
end