summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/mkxl/file-job.lmt
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkxl/file-job.lmt')
-rw-r--r--Master/texmf-dist/tex/context/base/mkxl/file-job.lmt1283
1 files changed, 1283 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkxl/file-job.lmt b/Master/texmf-dist/tex/context/base/mkxl/file-job.lmt
new file mode 100644
index 00000000000..95ad48e824b
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkxl/file-job.lmt
@@ -0,0 +1,1283 @@
+if not modules then modules = { } end modules ['file-job'] = {
+ version = 1.001,
+ comment = "companion to file-job.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- in retrospect dealing it's not that bad to deal with the nesting
+-- and push/poppign at the tex end
+
+local next, rawget, tostring, tonumber = next, rawget, tostring, tonumber
+local gsub, match, find = string.gsub, string.match, string.find
+local insert, remove, concat = table.insert, table.remove, table.concat
+local validstring, formatters = string.valid, string.formatters
+local sortedhash = table.sortedhash
+local setmetatableindex, setmetatablenewindex = table.setmetatableindex, table.setmetatablenewindex
+
+local commands = commands
+local resolvers = resolvers
+local context = context
+
+local ctx_doifelse = commands.doifelse
+
+local implement = interfaces.implement
+
+local trace_jobfiles = false trackers.register("system.jobfiles", function(v) trace_jobfiles = v end)
+
+local report = logs.reporter("system")
+local report_jobfiles = logs.reporter("system", "jobfiles")
+local report_functions = logs.reporter("system", "functions")
+
+local texsetcount = tex.setcount
+local elements = interfaces.elements
+local constants = interfaces.constants
+local variables = interfaces.variables
+local settings_to_array = utilities.parsers.settings_to_array
+local allocate = utilities.storage.allocate
+
+local nameonly = file.nameonly
+local suffixonly = file.suffix
+local basename = file.basename
+local addsuffix = file.addsuffix
+local removesuffix = file.removesuffix
+local dirname = file.dirname
+local is_qualified_path = file.is_qualified_path
+
+local cleanpath = resolvers.cleanpath
+local toppath = resolvers.toppath
+local resolveprefix = resolvers.resolve
+
+local hasscheme = url.hasscheme
+
+local jobresolvers = resolvers.jobs
+
+local registerextrapath = resolvers.registerextrapath
+local resetextrapaths = resolvers.resetextrapaths
+local getextrapaths = resolvers.getextrapath
+local pushextrapath = resolvers.pushextrapath
+local popextrapath = resolvers.popextrapath
+
+----- v_outer = variables.outer
+local v_text = variables.text
+local v_project = variables.project
+local v_environment = variables.environment
+local v_product = variables.product
+local v_component = variables.component
+local v_yes = variables.yes
+
+-- main code .. there is some overlap .. here we have loc://
+
+local function findctxfile(name) -- loc ? any ?
+ if is_qualified_path(name) then -- maybe when no suffix do some test for tex
+ return name
+ elseif not hasscheme(name) then
+ return resolvers.finders.byscheme("loc",name) or ""
+ else
+ return resolvers.findtexfile(name) or ""
+ end
+end
+
+resolvers.findctxfile = findctxfile
+
+implement {
+ name = "processfile",
+ arguments = "string",
+ public = true,
+ protected = true,
+ actions = function(name)
+ name = findctxfile(name)
+ if name ~= "" then
+ context.input(name)
+ end
+ end
+}
+
+implement {
+ name = "doifelseinputfile",
+ arguments = "string",
+ public = true,
+ protected = true,
+ actions = function(name)
+ ctx_doifelse(findctxfile(name) ~= "")
+ end
+}
+
+implement {
+ name = "locatefilepath",
+ arguments = "string",
+ actions = function(name)
+ context(dirname(findctxfile(name)))
+ end
+}
+
+implement {
+ name = "usepath",
+ arguments = "optional",
+ public = true,
+ protected = true,
+ actions = function(paths)
+ report_jobfiles("using path: %s",paths)
+ registerextrapath(paths)
+ end
+}
+
+implement {
+ name = "pushpath",
+ arguments = "optional",
+ public = true,
+ protected = true,
+ actions = function(paths)
+ report_jobfiles("pushing path: %s",paths)
+ pushextrapath(paths)
+ end
+}
+
+implement {
+ name = "poppath",
+ public = true,
+ protected = true,
+ actions = function(paths)
+ popextrapath()
+ report_jobfiles("popping path")
+ end
+}
+
+implement {
+ name = "usesubpath",
+ arguments = "optional",
+ public = true,
+ protected = true,
+ actions = function(subpaths)
+ report_jobfiles("using subpath: %s",subpaths)
+ registerextrapath(nil,subpaths)
+ end
+}
+
+implement {
+ name = "resetpath",
+ public = true,
+ protected = true,
+ actions = function()
+ report_jobfiles("resetting path")
+ resetextrapaths()
+ end
+}
+
+implement {
+ name = "allinputpaths",
+ public = true,
+ actions = function()
+ context(concat(getextrapaths(),","))
+ end
+}
+
+implement {
+ name = "usezipfile",
+ public = true,
+ protected = true,
+ arguments = { "optional", "optional" },
+ actions = function(name,tree)
+ if tree and tree ~= "" then
+ resolvers.usezipfile(formatters["zip:///%s?tree=%s"](name,tree))
+ else
+ resolvers.usezipfile(formatters["zip:///%s"](name))
+ end
+ end
+}
+
+-- moved from tex to lua:
+
+local texpatterns = { "%s.mkvi", "%s.mkiv", "%s.mklx", "%s.mkxl", "%s.tex" }
+local luapatterns = { "%s" .. utilities.lua.suffixes.luc, "%s.lua", "%s.lmt" }
+local cldpatterns = { "%s.cld" }
+local xmlpatterns = { "%s.xml" }
+
+local uselibrary = resolvers.uselibrary
+local input = context.input
+
+-- status
+--
+-- these need to be synced with input stream:
+
+local processstack = { }
+local processedfile = ""
+local processedfiles = { }
+
+implement {
+ name = "processedfile",
+ actions = function()
+ context(processedfile)
+ end
+}
+
+implement {
+ name = "processedfiles",
+ actions = function()
+ context(concat(processedfiles,","))
+ end
+}
+
+implement {
+ name = "dostarttextfile",
+ public = true,
+ protected = true,
+ arguments = "string",
+ actions = function(name)
+ insert(processstack,name)
+ processedfile = name
+ insert(processedfiles,name)
+ end
+}
+
+implement {
+ name = "dostoptextfile",
+ public = true,
+ protected = true,
+ actions = function()
+ processedfile = remove(processstack) or ""
+ end
+}
+
+local function startprocessing(name,notext)
+ if not notext then
+ -- report("begin file %a at line %a",name,status.linenumber or 0)
+ context.dostarttextfile(name)
+ end
+end
+
+local function stopprocessing(notext)
+ if not notext then
+ context.dostoptextfile()
+ -- report("end file %a at line %a",name,status.linenumber or 0)
+ end
+end
+
+--
+
+local typestack = { }
+local currenttype = v_text
+local nofmissing = 0
+local missing = {
+ tex = setmetatableindex("number"),
+ lua = setmetatableindex("number"),
+ cld = setmetatableindex("number"),
+ xml = setmetatableindex("number"),
+}
+
+local function reportfailure(kind,name)
+ nofmissing = nofmissing + 1
+ missing[kind][name] = true
+ report_jobfiles("unknown %s file %a",kind,name)
+end
+
+--
+
+local function action(name,foundname)
+ input(foundname)
+end
+local function failure(name,foundname)
+ reportfailure("tex",name)
+end
+local function usetexfile(name,onlyonce,notext)
+ startprocessing(name,notext)
+ uselibrary {
+ name = name,
+ patterns = texpatterns,
+ action = action,
+ failure = failure,
+ onlyonce = onlyonce,
+ }
+ stopprocessing(notext)
+end
+
+local function action(name,foundname)
+ dofile(foundname)
+end
+local function failure(name,foundname)
+ reportfailure("lua",name)
+end
+local function useluafile(name,onlyonce,notext)
+ uselibrary {
+ name = name,
+ patterns = luapatterns,
+ action = action,
+ failure = failure,
+ onlyonce = onlyonce,
+ }
+end
+
+local function action(name,foundname)
+ dofile(foundname)
+end
+local function failure(name,foundname)
+ reportfailure("cld",name)
+end
+local function usecldfile(name,onlyonce,notext)
+ startprocessing(name,notext)
+ uselibrary {
+ name = name,
+ patterns = cldpatterns,
+ action = action,
+ failure = failure,
+ onlyonce = onlyonce,
+ }
+ stopprocessing(notext)
+end
+
+local function action(name,foundname)
+ context.xmlprocess(foundname,"main","")
+end
+local function failure(name,foundname)
+ reportfailure("xml",name)
+end
+local function usexmlfile(name,onlyonce,notext)
+ startprocessing(name,notext)
+ uselibrary {
+ name = name,
+ patterns = xmlpatterns,
+ action = action,
+ failure = failure,
+ onlyonce = onlyonce,
+ }
+ stopprocessing(notext)
+end
+
+local suffixes = {
+ mkvi = usetexfile,
+ mkiv = usetexfile,
+ mklx = usetexfile,
+ mkxl = usetexfile,
+ tex = usetexfile,
+ luc = useluafile,
+ lua = useluafile,
+ cld = usecldfile,
+ xml = usexmlfile,
+ [""] = usetexfile,
+}
+
+local function useanyfile(name,onlyonce)
+ local s = suffixes[suffixonly(name)]
+ context(function() resolvers.pushpath(name) end)
+ if s then
+ -- s(removesuffix(name),onlyonce)
+ s(name,onlyonce) -- so, first with suffix, then without
+ else
+ usetexfile(name,onlyonce) -- e.g. ctx file
+ -- resolvers.readfilename(name)
+ end
+ context(resolvers.poppath)
+end
+
+implement { name = "loadtexfile", public = true, protected = true, actions = usetexfile, arguments = "optional" }
+implement { name = "loadluafile", public = true, protected = true, actions = useluafile, arguments = "optional" }
+implement { name = "loadcldfile", public = true, protected = true, actions = usecldfile, arguments = "optional" }
+implement { name = "loadxmlfile", public = true, protected = true, actions = usexmlfile, arguments = "optional" }
+
+implement { name = "loadtexfileonce", public = true, protected = true, actions = usetexfile, arguments = { "optional", true } }
+implement { name = "loadluafileonce", public = true, protected = true, actions = useluafile, arguments = { "optional", true } }
+implement { name = "loadcldfileonce", public = true, protected = true, actions = usecldfile, arguments = { "optional", true } }
+implement { name = "loadxmlfileonce", public = true, protected = true, actions = usexmlfile, arguments = { "optional", true } }
+
+implement { name = "useanyfile", actions = useanyfile, arguments = "string" }
+implement { name = "useanyfileonce", actions = useanyfile, arguments = { "string", true } }
+
+function jobresolvers.usefile(name,onlyonce,notext)
+ local s = suffixes[suffixonly(name)]
+ if s then
+ -- s(removesuffix(name),onlyonce,notext)
+ s(name,onlyonce,notext) -- so, first with suffix, then without
+ end
+end
+
+-- document structure
+
+local textlevel = 0 -- inaccessible for user, we need to define counter textlevel at the tex end
+
+local function dummyfunction() end
+
+local function startstoperror()
+ report("invalid \\%s%s ... \\%s%s structure",elements.start,v_text,elements.stop,v_text)
+ startstoperror = dummyfunction
+end
+
+local stopped
+
+local function starttext()
+ if textlevel == 0 then
+ if trace_jobfiles then
+ report_jobfiles("starting text")
+ end
+ context.dostarttext()
+ end
+ textlevel = textlevel + 1
+ texsetcount("global","textlevel",textlevel)
+end
+
+local function stoptext()
+ if not stopped then
+ if textlevel == 0 then
+ startstoperror()
+ elseif textlevel > 0 then
+ textlevel = textlevel - 1
+ end
+ texsetcount("global","textlevel",textlevel)
+ if textlevel <= 0 then
+ if trace_jobfiles then
+ report_jobfiles("stopping text")
+ end
+ context.dostoptext()
+ stopped = true
+ end
+ end
+end
+
+implement {
+ name = "starttext",
+ public = true,
+ protected = true,
+ actions = starttext
+}
+
+implement {
+ name = "stoptext",
+ public = true,
+ protected = true,
+ actions = stoptext
+}
+
+implement {
+ name = "forcequitjob",
+ arguments = "string",
+ public = true,
+ protected = true,
+ actions = function(reason)
+ if reason then
+ report("forcing quit: %s",reason)
+ else
+ report("forcing quit")
+ end
+ context.batchmode()
+ while textlevel >= 0 do
+ context.stoptext()
+ end
+ end
+}
+
+implement {
+ name = "forceendjob",
+ public = true,
+ protected = true,
+ actions = function()
+ report([[don't use \end to finish a document]])
+ context.stoptext()
+ end
+}
+
+implement {
+ name = "autostarttext",
+ public = true,
+ protected = true,
+ actions = function()
+ if textlevel == 0 then
+ report([[auto \starttext ... \stoptext]])
+ end
+ context.starttext()
+ end
+}
+
+implement {
+ name = "autostoptext",
+ public = true,
+ protected = true,
+ actions = stoptext
+}
+
+-- project structure
+
+implement {
+ name = "processfilemany",
+ public = true,
+ protected = true,
+ arguments = { "string", false },
+ actions = useanyfile
+}
+
+implement {
+ name = "processfileonce",
+ public = true,
+ protected = true,
+ arguments = { "string", true },
+ actions = useanyfile
+}
+
+implement {
+ name = "processfilenone",
+ arguments = "string",
+ public = true,
+ protected = true,
+ actions = dummyfunction,
+}
+
+local tree = { type = "text", name = "", branches = { } }
+local treestack = { }
+local top = tree.branches
+local root = tree
+
+local project_stack = { }
+local product_stack = { }
+local component_stack = { }
+local environment_stack = { }
+
+local stacks = {
+ [v_project ] = project_stack,
+ [v_product ] = product_stack,
+ [v_component ] = component_stack,
+ [v_environment] = environment_stack,
+}
+
+--
+
+local function pushtree(what,name)
+ local t = { }
+ top[#top+1] = { type = what, name = name, branches = t }
+ insert(treestack,top)
+ top = t
+end
+
+local function poptree()
+ top = remove(treestack)
+ -- inspect(top)
+end
+
+do
+
+ local function log_tree(report,top,depth)
+ report("%s%s: %s",depth,top.type,top.name)
+ local branches = top.branches
+ if #branches > 0 then
+ depth = depth .. " "
+ for i=1,#branches do
+ log_tree(report,branches[i],depth)
+ end
+ end
+ end
+
+ logs.registerfinalactions(function()
+ root.name = environment.jobname
+ --
+ logs.startfilelogging(report,"used files")
+ log_tree(report,root,"")
+ logs.stopfilelogging()
+ --
+ if nofmissing > 0 and logs.loggingerrors() then
+ logs.starterrorlogging(report,"missing files")
+ for kind, list in sortedhash(missing) do
+ for name in sortedhash(list) do
+ report("%w%s %s",6,kind,name)
+ end
+ end
+ logs.stoperrorlogging()
+ end
+ end)
+
+end
+
+local jobstructure = job.structure or { }
+job.structure = jobstructure
+jobstructure.collected = jobstructure.collected or { }
+jobstructure.tobesaved = root
+jobstructure.components = { }
+
+local function initialize()
+ local function collect(root,result)
+ local branches = root.branches
+ if branches then
+ for i=1,#branches do
+ local branch = branches[i]
+ if branch.type == "component" then
+ result[#result+1] = branch.name
+ end
+ collect(branch,result)
+ end
+ end
+ return result
+ end
+ jobstructure.components = collect(jobstructure.collected,{})
+end
+
+job.register('job.structure.collected',root,initialize)
+
+-- component: small unit, either or not components itself
+-- product : combination of components
+
+local ctx_processfilemany = context.processfilemany
+local ctx_processfileonce = context.processfileonce
+local ctx_processfilenone = context.processfilenone
+
+-- we need a plug in the nested loaded, push pop pseudo current dir
+
+local function processfilecommon(name,action)
+ -- experiment, might go away
+-- if not hasscheme(name) then
+-- local path = dirname(name)
+-- if path ~= "" then
+-- registerextrapath(path)
+-- report_jobfiles("adding search path %a",path)
+-- end
+-- end
+ -- till here
+ action(name)
+end
+
+local function processfilemany(name) processfilecommon(name,ctx_processfilemany) end
+local function processfileonce(name) processfilecommon(name,ctx_processfileonce) end
+local function processfilenone(name) processfilecommon(name,ctx_processfilenone) end
+
+local processors = utilities.storage.allocate {
+ -- [v_outer] = {
+ -- [v_text] = { "many", processfilemany },
+ -- [v_project] = { "once", processfileonce },
+ -- [v_environment] = { "once", processfileonce },
+ -- [v_product] = { "once", processfileonce },
+ -- [v_component] = { "many", processfilemany },
+ -- },
+ [v_text] = {
+ [v_text] = { "many", processfilemany },
+ [v_project] = { "once", processfileonce }, -- dubious
+ [v_environment] = { "once", processfileonce },
+ [v_product] = { "many", processfilemany }, -- dubious
+ [v_component] = { "many", processfilemany },
+ },
+ [v_project] = {
+ [v_text] = { "many", processfilemany },
+ [v_project] = { "none", processfilenone },
+ [v_environment] = { "once", processfileonce },
+ [v_product] = { "none", processfilenone },
+ [v_component] = { "none", processfilenone },
+ },
+ [v_environment] = {
+ [v_text] = { "many", processfilemany },
+ [v_project] = { "none", processfilenone },
+ [v_environment] = { "once", processfileonce },
+ [v_product] = { "none", processfilenone },
+ [v_component] = { "none", processfilenone },
+ },
+ [v_product] = {
+ [v_text] = { "many", processfilemany },
+ [v_project] = { "once", processfileonce },
+ [v_environment] = { "once", processfileonce },
+ [v_product] = { "many", processfilemany },
+ [v_component] = { "many", processfilemany },
+ },
+ [v_component] = {
+ [v_text] = { "many", processfilemany },
+ [v_project] = { "once", processfileonce },
+ [v_environment] = { "once", processfileonce },
+ [v_product] = { "none", processfilenone },
+ [v_component] = { "many", processfilemany },
+ }
+}
+
+local start = {
+ [v_text] = nil,
+ [v_project] = nil,
+ [v_environment] = context.startreadingfile,
+ [v_product] = context.starttext,
+ [v_component] = context.starttext,
+}
+
+local stop = {
+ [v_text] = nil,
+ [v_project] = nil,
+ [v_environment] = context.stopreadingfile,
+ [v_product] = context.stoptext,
+ [v_component] = context.stoptext,
+}
+
+jobresolvers.processors = processors
+
+local function topofstack(what)
+ local stack = stacks[what]
+ return stack and stack[#stack] or environment.jobname
+end
+
+local function productcomponent() -- only when in product
+ local product = product_stack[#product_stack]
+ if product and product ~= "" then
+ local component = component_stack[1]
+ if component and component ~= "" then
+ return component
+ end
+ end
+end
+
+local function justacomponent()
+ local product = product_stack[#product_stack]
+ if not product or product == "" then
+ local component = component_stack[1]
+ if component and component ~= "" then
+ return component
+ end
+ end
+end
+
+jobresolvers.productcomponent = productcomponent
+jobresolvers.justacomponent = justacomponent
+
+function jobresolvers.currentproject () return topofstack(v_project ) end
+function jobresolvers.currentproduct () return topofstack(v_product ) end
+function jobresolvers.currentcomponent () return topofstack(v_component ) end
+function jobresolvers.currentenvironment() return topofstack(v_environment) end
+
+local done = { }
+local tolerant = false -- too messy, mkii user with the wrong structure should adapt
+
+local function process(what,name)
+ local depth = #typestack
+ local process
+ --
+ name = resolveprefix(name)
+ --
+-- if not tolerant then
+ -- okay, would be best but not compatible with mkii
+ process = processors[currenttype][what]
+-- elseif depth == 0 then
+-- -- could be a component, product or (brr) project
+-- if trace_jobfiles then
+-- report_jobfiles("%s : %s > %s (case 1)",depth,currenttype,v_outer)
+-- end
+-- process = processors[v_outer][what]
+-- elseif depth == 1 and typestack[1] == v_text then
+-- -- we're still not doing a component or product
+-- if trace_jobfiles then
+-- report_jobfiles("%s : %s > %s (case 2)",depth,currenttype,v_outer)
+-- end
+-- process = processors[v_outer][what]
+-- else
+-- process = processors[currenttype][what]
+-- end
+ if process then
+ local method = process[1]
+ if method == "none" then
+ if trace_jobfiles then
+ report_jobfiles("%s : %s : %s %s %a in %s %a",depth,method,"ignoring",what,name,currenttype,topofstack(currenttype))
+ end
+ elseif method == "once" and done[name] then
+ if trace_jobfiles then
+ report_jobfiles("%s : %s : %s %s %a in %s %a",depth,method,"skipping",what,name,currenttype,topofstack(currenttype))
+ end
+ else
+ -- keep in mind that we also handle "once" at the file level
+ -- so there is a double catch
+ done[name] = true
+ local before = start[what]
+ local after = stop [what]
+ if trace_jobfiles then
+ report_jobfiles("%s : %s : %s %s %a in %s %a",depth,method,"processing",what,name,currenttype,topofstack(currenttype))
+ end
+ if before then
+ before()
+ end
+ process[2](name)
+ if after then
+ after()
+ end
+ end
+ else
+ if trace_jobfiles then
+ report_jobfiles("%s : %s : %s %s %a in %s %a",depth,"none","ignoring",what,name,currenttype,topofstack(currenttype))
+ end
+ end
+end
+
+local scan_delimited = tokens.scanners.delimited
+
+local function getname()
+ return scan_delimited(91,93) or scan_delimited(0,32) -- [name] or name<space>
+end
+
+implement { name = "project", public = true, protected = true, actions = function() process(v_project, getname()) end }
+implement { name = "environment", public = true, protected = true, actions = function() process(v_environment,getname()) end }
+implement { name = "product", public = true, protected = true, actions = function() process(v_product, getname()) end } -- will be overloaded
+implement { name = "component", public = true, protected = true, actions = function() process(v_component, getname()) end }
+
+implement { name = "useproject", public = true, protected = true, actions = function(name) process(v_project, name) end, arguments = "optional" }
+implement { name = "useenvironment", public = true, protected = true, actions = function(name) process(v_environment,name) end, arguments = "optional" }
+implement { name = "useproduct", public = true, protected = true, actions = function(name) process(v_product, name) end, arguments = "optional" } -- will be overloaded
+implement { name = "usecomponent", public = true, protected = true, actions = function(name) process(v_component, name) end, arguments = "optional" }
+
+-- todo: setsystemmode to currenttype
+-- todo: make start/stop commands at the tex end
+
+local start = {
+ [v_project] = context.startprojectindeed,
+ [v_product] = context.startproductindeed,
+ [v_component] = context.startcomponentindeed,
+ [v_environment] = context.startenvironmentindeed,
+}
+
+local stop = {
+ [v_project] = context.stopprojectindeed,
+ [v_product] = context.stopproductindeed,
+ [v_component] = context.stopcomponentindeed,
+ [v_environment] = context.stopenvironmentindeed,
+}
+
+local function gotonextlevel(what,name) -- todo: something with suffix name
+ insert(stacks[what],name)
+ insert(typestack,currenttype)
+ currenttype = what
+ pushtree(what,name)
+ if start[what] then
+ start[what]()
+ end
+end
+
+local function gotopreviouslevel(what)
+ if stop[what] then
+ stop[what]()
+ end
+ poptree()
+ currenttype = remove(typestack) or v_text
+ remove(stacks[what]) -- not currenttype ... weak recovery
+context.endinput() -- does not work
+-- context.signalendofinput(what)
+end
+
+local function autoname()
+ local name = scan_delimited(91,93) or scan_delimited(0,32) -- [name] or name<space>
+ if name == "*" then
+ name = nameonly(toppath() or name)
+ end
+ return name
+end
+
+implement { name = "startproject", public = true, protected = true, actions = function() gotonextlevel(v_project, autoname()) end }
+implement { name = "startproduct", public = true, protected = true, actions = function() gotonextlevel(v_product, autoname()) end }
+implement { name = "startcomponent", public = true, protected = true, actions = function() gotonextlevel(v_component, autoname()) end }
+implement { name = "startenvironment", public = true, protected = true, actions = function() gotonextlevel(v_environment,autoname()) end }
+
+implement { name = "stopproject", public = true, protected = true, actions = function() gotopreviouslevel(v_project ) end }
+implement { name = "stopproduct", public = true, protected = true, actions = function() gotopreviouslevel(v_product ) end }
+implement { name = "stopcomponent", public = true, protected = true, actions = function() gotopreviouslevel(v_component ) end }
+implement { name = "stopenvironment", public = true, protected = true, actions = function() gotopreviouslevel(v_environment) end }
+
+implement { name = "currentproject", public = true, actions = function() context(topofstack(v_project )) end }
+implement { name = "currentproduct", public = true, actions = function() context(topofstack(v_product )) end }
+implement { name = "currentcomponent", public = true, actions = function() context(topofstack(v_component )) end }
+implement { name = "currentenvironment", public = true, actions = function() context(topofstack(v_environment)) end }
+
+-- -- -- this will move -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+--
+-- <?xml version='1.0' standalone='yes'?>
+-- <exa:variables xmlns:exa='htpp://www.pragma-ade.com/schemas/exa-variables.rng'>
+-- <exa:variable label='mode:pragma'>nee</exa:variable>
+-- <exa:variable label='mode:variant'>standaard</exa:variable>
+-- </exa:variables>
+--
+-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+
+local report_examodes = logs.reporter("system","examodes")
+
+local function convertexamodes(str)
+ local x = xml.convert(str)
+ for e in xml.collected(x,"exa:variable") do
+ local label = e.at and e.at.label
+ if label and label ~= "" then
+ local data = xml.text(e)
+ local mode = match(label,"^mode:(.+)$")
+ if mode then
+ context.enablemode { formatters["%s:%s"](mode,data) }
+ end
+ context.setvariable("exa:variables",label,(gsub(data,"([{}])","\\%1")))
+ end
+ end
+end
+
+function environment.loadexamodes(filename)
+ if not filename or filename == "" then
+ filename = removesuffix(tex.jobname)
+ end
+ filename = resolvers.findfile(addsuffix(filename,'ctm')) or ""
+ if filename ~= "" then
+ report_examodes("loading %a",filename) -- todo: message system
+ convertexamodes(io.loaddata(filename))
+ else
+ report_examodes("no mode file %a",filename) -- todo: message system
+ end
+end
+
+implement {
+ name = "loadexamodes",
+ actions = environment.loadexamodes,
+ public = true,
+ protected = true,
+ arguments = "optional"
+}
+
+-- changed in mtx-context
+-- code moved from luat-ini
+
+-- todo: locals when mtx-context is changed
+
+document = document or {
+ arguments = allocate(),
+ files = allocate(),
+ variables = allocate(), -- for templates
+ options = {
+ commandline = {
+ environments = allocate(),
+ modules = allocate(),
+ modes = allocate(),
+ },
+ ctxfile = {
+ environments = allocate(),
+ modules = allocate(),
+ modes = allocate(),
+ },
+ },
+ functions = table.setmetatablenewindex(function(t,k,v)
+ if rawget(t,k) then
+ report_functions("overloading document function %a",k)
+ end
+ rawset(t,k,v)
+ return v
+ end),
+}
+
+function document.setargument(key,value)
+ document.arguments[key] = value
+end
+
+function document.setdefaultargument(key,default)
+ local v = document.arguments[key]
+ if v == nil or v == "" then
+ document.arguments[key] = default
+ end
+end
+
+function document.setfilename(i,name)
+ if name then
+ document.files[tonumber(i)] = name
+ else
+ document.files[#document.files+1] = tostring(i)
+ end
+end
+
+function document.getargument(key,default)
+ local v = document.arguments[key]
+ if type(v) == "boolean" then
+ v = (v and "yes") or "no"
+ document.arguments[key] = v
+ end
+ return v or default or ""
+end
+
+function document.getfilename(i)
+ return document.files[tonumber(i)] or ""
+end
+
+implement {
+ name = "setdocumentargument",
+ actions = document.setargument,
+ arguments = "2 strings"
+}
+
+implement {
+ name = "setdocumentdefaultargument",
+ actions = document.setdefaultargument,
+ arguments = "2 strings"
+}
+
+implement {
+ name = "setdocumentfilename",
+ actions = document.setfilename,
+ arguments = { "integer", "string" }
+}
+
+implement {
+ name = "getdocumentargument",
+ actions = { document.getargument, context },
+ arguments = "2 strings"
+}
+
+implement {
+ name = "getdocumentfilename",
+ actions = { document.getfilename, context },
+ arguments = "integer"
+}
+
+function document.setcommandline() -- has to happen at the tex end in order to expand
+
+ -- the document[arguments|files] tables are copies
+
+ local arguments = document.arguments
+ local files = document.files
+ local options = document.options
+
+ for k, v in next, environment.arguments do
+ k = gsub(k,"^c:","") -- already done, but better be safe than sorry
+ if arguments[k] == nil then
+ arguments[k] = v
+ end
+ end
+
+ -- in the new mtx=context approach we always pass a stub file so we need to
+ -- to trick the files table which actually only has one entry in a tex job
+
+ if arguments.timing then
+ context.usemodule { "timing" }
+ end
+
+ if arguments.usage then
+ trackers.enable("system.usage")
+ end
+
+ if arguments.batchmode then
+ context.batchmode(false)
+ end
+
+ if arguments.nonstopmode then
+ context.nonstopmode(false)
+ end
+
+ if arguments.nostatistics then
+ directives.enable("system.nostatistics")
+ end
+
+ if arguments.paranoid then
+ context.setvalue("maxreadlevel",1)
+ end
+
+ if validstring(arguments.path) then
+ context.usepath { arguments.path }
+ end
+
+ if arguments.export then
+ context.setupbackend { export = v_yes }
+ end
+
+ local inputfile = validstring(arguments.input)
+
+ if inputfile and dirname(inputfile) == "." and lfs.isfile(inputfile) then
+ -- nicer in checks
+ inputfile = basename(inputfile)
+ end
+
+ local forcedruns = arguments.forcedruns
+ local kindofrun = arguments.kindofrun
+ local currentrun = arguments.currentrun
+ local maxnofruns = arguments.maxnofruns or arguments.runs
+
+ -- context.setupsystem {
+ -- [constants.directory] = validstring(arguments.setuppath),
+ -- [constants.inputfile] = inputfile,
+ -- [constants.file] = validstring(arguments.result),
+ -- [constants.random] = validstring(arguments.randomseed),
+ -- -- old:
+ -- [constants.n] = validstring(kindofrun),
+ -- [constants.m] = validstring(currentrun),
+ -- }
+
+ context.setupsystem {
+ directory = validstring(arguments.setuppath),
+ inputfile = inputfile,
+ file = validstring(arguments.result),
+ random = validstring(arguments.randomseed),
+ -- old:
+ n = validstring(kindofrun),
+ m = validstring(currentrun),
+ }
+
+ forcedruns = tonumber(forcedruns) or 0
+ kindofrun = tonumber(kindofrun) or 0
+ maxnofruns = tonumber(maxnofruns) or 0
+ currentrun = tonumber(currentrun) or 0
+
+ local prerollrun = forcedruns > 0 and currentrun > 0 and currentrun < forcedruns
+
+ environment.forcedruns = forcedruns
+ environment.kindofrun = kindofrun
+ environment.maxnofruns = maxnofruns
+ environment.currentrun = currentrun
+ environment.prerollrun = prerollrun
+
+ context.setconditional("prerollrun",prerollrun)
+
+ if validstring(arguments.arguments) then
+ context.setupenv { arguments.arguments }
+ end
+
+ if arguments.once then
+ directives.enable("system.runonce")
+ end
+
+ if arguments.noarrange then
+ context.setuparranging { variables.disable }
+ end
+
+ --
+
+ local commandline = options.commandline
+
+ commandline.environments = table.append(commandline.environments,settings_to_array(validstring(arguments.environment)))
+ commandline.modules = table.append(commandline.modules, settings_to_array(validstring(arguments.usemodule)))
+ commandline.modes = table.append(commandline.modes, settings_to_array(validstring(arguments.mode)))
+
+ --
+
+ if #files == 0 then
+ local list = settings_to_array(validstring(arguments.files))
+ if list and #list > 0 then
+ files = list
+ end
+ end
+
+ if #files == 0 then
+ files = { validstring(arguments.input) }
+ end
+
+ --
+
+ document.arguments = arguments
+ document.files = files
+
+end
+
+-- commandline wins over ctxfile
+
+local function apply(list,action)
+ if list then
+ for i=1,#list do
+ action { list[i] }
+ end
+ end
+end
+
+function document.setmodes() -- was setup: *runtime:modes
+ apply(document.options.ctxfile .modes,context.enablemode)
+ apply(document.options.commandline.modes,context.enablemode)
+end
+
+function document.setmodules() -- was setup: *runtime:modules
+ apply(document.options.ctxfile .modules,context.usemodule)
+ apply(document.options.commandline.modules,context.usemodule)
+end
+
+function document.setenvironments() -- was setup: *runtime:environments
+ apply(document.options.ctxfile .environments,context.environment)
+ apply(document.options.commandline.environments,context.environment)
+end
+
+function document.setfilenames()
+ local initialize = environment.initializefilenames
+ if initialize then
+ initialize()
+ else
+ -- fatal error
+ end
+end
+
+implement { name = "setdocumentcommandline", actions = document.setcommandline, onlyonce = true }
+implement { name = "setdocumentmodes", actions = document.setmodes, onlyonce = true }
+implement { name = "setdocumentmodules", actions = document.setmodules, onlyonce = true }
+implement { name = "setdocumentenvironments", actions = document.setenvironments, onlyonce = true }
+implement { name = "setdocumentfilenames", actions = document.setfilenames, onlyonce = true }
+
+do
+
+ logs.registerfinalactions(function()
+ local foundintrees = resolvers.foundintrees()
+ if #foundintrees > 0 then
+ logs.startfilelogging(report,"used files")
+ for i=1,#foundintrees do
+ report("%4i: % T",i,foundintrees[i])
+ end
+ logs.stopfilelogging()
+ end
+ end)
+
+ logs.registerfinalactions(function()
+ local files = document.files -- or environment.files
+ local arguments = document.arguments -- or environment.arguments
+ --
+ logs.startfilelogging(report,"commandline options")
+ if arguments and next(arguments) then
+ for argument, value in sortedhash(arguments) do
+ report("%s=%A",argument,value)
+ end
+ else
+ report("no arguments")
+ end
+ logs.stopfilelogging()
+ --
+ logs.startfilelogging(report,"commandline files")
+ if files and #files > 0 then
+ for i=1,#files do
+ report("% 4i: %s",i,files[i])
+ end
+ else
+ report("no files")
+ end
+ logs.stopfilelogging()
+ end)
+
+end
+
+if environment.initex then
+
+ logs.registerfinalactions(function()
+ local startfilelogging = logs.startfilelogging
+ local stopfilelogging = logs.stopfilelogging
+ startfilelogging(report,"stored tables")
+ for k,v in sortedhash(storage.data) do
+ report("%03i %s",k,v[1])
+ end
+ stopfilelogging()
+ startfilelogging(report,"stored modules")
+ for k,v in sortedhash(lua.bytedata) do
+ report("%03i %s %s",k,v.name)
+ end
+ stopfilelogging()
+ startfilelogging(report,"stored attributes")
+ for k,v in sortedhash(attributes.names) do
+ report("%03i %s",k,v)
+ end
+ stopfilelogging()
+ startfilelogging(report,"stored catcodetables")
+ for k,v in sortedhash(catcodes.names) do
+ report("%03i % t",k,v)
+ end
+ stopfilelogging()
+ startfilelogging(report,"stored corenamespaces")
+ for k,v in sortedhash(interfaces.corenamespaces) do
+ report("%03i %s",k,v)
+ end
+ stopfilelogging()
+ end)
+
+end
+
+implement {
+ name = "continueifinputfile",
+ public = true,
+ protected = true,
+ arguments = "string",
+ actions = function(inpname,basetoo)
+ local inpnamefull = addsuffix(inpname,"tex")
+ local inpfilefull = addsuffix(environment.inputfilename,"tex")
+ local continue = inpnamefull == inpfilefull
+ -- if basetoo and not continue then
+ if not continue then
+ continue = inpnamefull == basename(inpfilefull)
+ end
+ if continue then
+ report("continuing input file %a",inpname)
+ else
+ context.endinput()
+ end
+-- ctx_doifelse(continue)
+ end
+}