diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mlib-run.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mlib-run.lua | 312 |
1 files changed, 220 insertions, 92 deletions
diff --git a/Master/texmf-dist/tex/context/base/mlib-run.lua b/Master/texmf-dist/tex/context/base/mlib-run.lua index 30cd01c736d..7351c332fb4 100644 --- a/Master/texmf-dist/tex/context/base/mlib-run.lua +++ b/Master/texmf-dist/tex/context/base/mlib-run.lua @@ -23,35 +23,40 @@ if not modules then modules = { } end modules ['mlib-run'] = { <p>The directional helpers and pen analysis are more or less translated from the <l n='c'/> code. It really helps that Taco know that source so well. Taco and I spent quite some time on speeding up the <l n='lua'/> and <l n='c'/> code. There is not -much to gain, especially if on ekeeps in mind that when integrated in <l n='tex'/> +much to gain, especially if one keeps in mind that when integrated in <l n='tex'/> only a part of the time is spent in <l n='metapost'/>. Of course an integrated approach is way faster than an external <l n='metapost'/> and processing time nears zero.</p> --ldx]]-- +local trace_graphics = false trackers.register("metapost.graphics", function(v) trace_graphics = v end) + local format = string.format +local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming + + metapost = metapost or { } +metapost.showlog = false +metapost.lastlog = "" + +function metapost.resetlastlog() + metapost.lastlog = "" +end + local function finder(name, mode, ftype) if mode=="w" then return name - elseif input.aux.qualified_path(name) then + elseif file.is_qualified_path(name) then return name else - return input.find_file((texmf and texmf.instance) or instance,name,ftype) + return resolvers.find_file(name,ftype) end end metapost.finder = finder ---~ statistics = { ---~ ["hash_size"]=1774, ---~ ["main_memory"]=50237, ---~ ["max_in_open"]=5, ---~ ["param_size"]=4, ---~ } - metapost.parameters = { hash_size = 100000, main_memory = 2000000, @@ -61,103 +66,136 @@ metapost.parameters = { metapost.exectime = metapost.exectime or { } -- hack +local preamble = [[ +boolean mplib; string mp_parent_version; +mplib := true; +mp_parent_version := "%s"; +input %s ; dump ; +]] + function metapost.make(name, target, version) - input.starttiming(mplib) + starttiming(mplib) target = file.replacesuffix(target or name, "mem") local mpx = mplib.new ( table.merged ( metapost.parameters, { ini_version = true, find_file = finder, - job_name = file.stripsuffix(target), + job_name = file.removesuffix(target), } ) ) if mpx then - input.starttiming(metapost.exectime) - local result = mpx:execute(format('\\ ; boolean mplib ; mplib := true ; string mp_parent_version ; mp_parent_version := "%s" ; show mp_parent_version ; input %s ; dump ;', version or "unknown", name)) - input.stoptiming(metapost.exectime) - if mpx then - mpx:finish() - end + starttiming(metapost.exectime) + local result = mpx:execute(format(preamble,version or "unknown",name)) + stoptiming(metapost.exectime) + mpx:finish() end - input.stoptiming(mplib) - return mpx -- mpx = nil will free memory + stoptiming(mplib) end function metapost.load(name) - input.starttiming(mplib) + starttiming(mplib) local mpx = mplib.new ( table.merged ( metapost.parameters, { + ini_version = false, mem_name = file.replacesuffix(name,"mem"), find_file = finder, + -- job_name = "mplib", } ) ) - if mpx then - input.starttiming(metapost.exectime) - mpx:execute("\\") - input.stoptiming(metapost.exectime) + local result + if not mpx then + result = { status = 99, error = "out of memory"} end - input.stoptiming(mplib) - return mpx + stoptiming(mplib) + return mpx, result end function metapost.unload(mpx) - input.starttiming(mplib) + starttiming(mplib) if mpx then mpx:finish() end - input.stoptiming(mplib) + stoptiming(mplib) end -function metapost.checkformat(mpsinput, mpsformat) +function metapost.reporterror(result) + if not result then + metapost.report("mp error: no result object returned") + elseif result.status > 0 then + local t, e, l = result.term, result.error, result.log + if t and t ~= "" then + metapost.report("mp terminal: %s",t) + end + if e then + metapost.report("mp error: %s",(e=="" and "?") or e) + end + if not t and not e and l then + metapost.lastlog = metapost.lastlog .. "\n" .. l + metapost.report("mp log: %s",l) + else + metapost.report("mp error: unknown, no error, terminal or log messages") + end + else + return false + end + return true +end + +function metapost.checkformat(mpsinput, mpsformat, dirname) mpsinput = file.addsuffix(mpsinput or "metafun", "mp") - mpsformat = file.stripsuffix(file.basename(mpsformat or texconfig.formatname or tex.formatname or mpsinput)) - local mpsbase = file.stripsuffix(file.basename(mpsinput)) + mpsformat = file.removesuffix(file.basename(mpsformat or texconfig.formatname or (tex and tex.formatname) or mpsinput)) + local mpsbase = file.removesuffix(file.basename(mpsinput)) if mpsbase ~= mpsformat then mpsformat = mpsformat .. "-" .. mpsbase end mpsformat = file.addsuffix(mpsformat, "mem") - local pth = file.dirname(texconfig.formatname or "") + local pth = dirname or file.dirname(texconfig.formatname or "") if pth ~= "" then mpsformat = file.join(pth,mpsformat) end local the_version = environment.version or "unset version" - if io.exists(mpsformat) then - commands.writestatus("mplib", format("loading format: %s, name: %s", mpsinput, mpsformat)) - local mpx = metapost.load(mpsformat) + if lfs.isfile(mpsformat) then + commands.writestatus("mplib","loading '%s' from '%s'", mpsinput, mpsformat) + local mpx, result = metapost.load(mpsformat) if mpx then - local result = mpx:execute(format("show mp_parent_version ;")) - local version = result.log:match(">> *(.-)[\n\r]") or "unknown" - version = version:gsub("[\'\"]","") - if version ~= the_version then - commands.writestatus("mplib", format("version mismatch: %s <> %s", version or "unknown", the_version)) + local result = mpx:execute("show mp_parent_version ;") + if not result.log then + metapost.reporterror(result) else - return mpx + local version = result.log:match(">> *(.-)[\n\r]") or "unknown" + version = version:gsub("[\'\"]","") + if version ~= the_version then + commands.writestatus("mplib","version mismatch: %s <> %s", version or "unknown", the_version) + else + return mpx + end end + else + commands.writestatus("mplib","error in loading '%s' from '%s'", mpsinput, mpsformat) + metapost.reporterror(result) end end - commands.writestatus("mplib", format("making format: %s, name: %s", mpsinput, mpsformat)) + commands.writestatus("mplib","making '%s' into '%s'", mpsinput, mpsformat) metapost.make(mpsinput,mpsformat,the_version) -- somehow return ... fails here - if io.exists(mpsformat) then - commands.writestatus("mplib", format("loading format: %s, name: %s", mpsinput, mpsformat)) + if lfs.isfile(mpsformat) then + commands.writestatus("mplib","loading '%s' from '%s'", mpsinput, mpsformat) return metapost.load(mpsformat) else - commands.writestatus("mplib", format("problems with format: %s, name: %s", mpsinput, mpsformat)) + commands.writestatus("mplib","problems with '%s' from '%s'", mpsinput, mpsformat) end end ---~ if environment.initex then ---~ metapost.unload(metapost.checkformat("metafun")) ---~ end +local mpxformats = { } -local mpxformats = {} - -function metapost.format(name) - local mpx = mpxformats[name] +function metapost.format(instance,name) + name = name or instance + local mpx = mpxformats[instance] if not mpx then + commands.writestatus("mplib","initializing instance '%s' using format '%s'",instance,name) mpx = metapost.checkformat(name) - mpxformats[name] = mpx + mpxformats[instance] = mpx end return mpx end @@ -171,80 +209,170 @@ function metapost.reset(mpx) mpxformats[mpx] = nil end else - for name=1,#mpxformats do - if mpxformats[name] == mpx then + for name, instance in pairs(mpxformats) do + if instance == mpx then + mpx:finish() mpxformats[name] = nil break end end - mpx:finish() end end -metapost.showlog = false +local mp_inp, mp_log, mp_tag = { }, { }, 0 -function metapost.process(mpx, data, trialrun, flusher, multipass) +function metapost.process(mpx, data, trialrun, flusher, multipass, isextrapass, askedfig) local converted, result = false, {} if type(mpx) == "string" then mpx = metapost.format(mpx) -- goody end if mpx and data then - input.starttiming(metapost) + starttiming(metapost) + if trace_graphics then + if not mp_inp[mpx] then + mp_tag = mp_tag + 1 + mp_inp[mpx] = io.open(format("%s-mplib-run-%03i.mp", tex.jobname,mp_tag),"w") + mp_log[mpx] = io.open(format("%s-mplib-run-%03i.log",tex.jobname,mp_tag),"w") + end + local banner = format("%% begin graphic: n=%s, trialrun=%s, multipass=%s, isextrapass=%s\n\n", metapost.n, tostring(trialrun), tostring(multipass), tostring(isextrapass)) + mp_inp[mpx]:write(banner) + mp_log[mpx]:write(banner) + end if type(data) == "table" then for i=1,#data do local d = data[i] if d then - input.starttiming(metapost.exectime) + if trace_graphics then + mp_inp[mpx]:write(d) + end + starttiming(metapost.exectime) result = mpx:execute(d) - input.stoptiming(metapost.exectime) - if not result then - metapost.report("mp error", "no result object returned") - elseif result.status > 0 then - local t, e, l = result.term, result.error, result.log - if t then - metapost.report("mp terminal",t) + stoptiming(metapost.exectime) + if trace_graphics and result then + local str = result.log or result.error + if str and str ~= "" then + mp_log[mpx]:write(str) end - if e then - metapost.report("mp error",e) + end + if not metapost.reporterror(result) then + if metapost.showlog then + local str = (result.term ~= "" and result.term) or "no terminal output" + if not str:is_empty() then + metapost.lastlog = metapost.lastlog .. "\n" .. str + metapost.report("mp log: %s",str) + end end - if not t and not e and l then - metapost.report("mp log",l) - else - metapost.report("mp error","unknown, no error, terminal or log messages") + if result.fig then + converted = metapost.convert(result, trialrun, flusher, multipass, askedfig) end - elseif metapost.showlog then - metapost.report("mp info",result.term or "no terminal output") - elseif result.fig then - converted = metapost.convert(result, trialrun, flusher, multipass) end else - metapost.report("mp error", "invalid graphic component " .. i) + metapost.report("mp error: invalid graphic component %s",i) end end else - input.starttiming(metapost.exectime) - result = mpx:execute(data) - input.stoptiming(metapost.exectime) + if trace_graphics then + mp_inp:write(data) + end + starttiming(metapost.exectime) + result = mpx[mpx]:execute(data) + stoptiming(metapost.exectime) + if trace_graphics and result then + local str = result.log or result.error + if str and str ~= "" then + mp_log[mpx]:write(str) + end + end -- todo: error message if not result then - metapost.report("error", "no result object returned") + metapost.report("mp error: no result object returned") elseif result.status > 0 then - metapost.report("error",(result.term or "no-term") .. "\n" .. (result.error or "no-error")) - elseif metapost.showlog then - metapost.report("info",result.term or "no-term") - elseif result.fig then - converted = metapost.convert(result, trialrun, flusher, multipass) + metapost.report("mp error: %s",(result.term or "no-term") .. "\n" .. (result.error or "no-error")) + else + if metapost.showlog then + metapost.lastlog = metapost.lastlog .. "\n" .. result.term + metapost.report("mp info: %s",result.term or "no-term") + end + if result.fig then + converted = metapost.convert(result, trialrun, flusher, multipass, askedfig) + end end end - input.stoptiming(metapost) + if trace_graphics then + local banner = "\n% end graphic\n\n" + mp_inp[mpx]:write(banner) + mp_log[mpx]:write(banner) + end + stoptiming(metapost) end return converted, result end -function metapost.convert(result, trialrun, multipass) - metapost.report('Warning','no converter set') +function metapost.convert() + metapost.report('mp warning: no converter set') end function metapost.report(...) - logs.report(...) + logs.report("mplib",...) +end + +-- handy + +function metapost.directrun(formatname,filename,outputformat,astable,mpdata) + local fullname = file.addsuffix(filename,"mp") + local data = mpdata or io.loaddata(fullname) + if outputformat ~= "svg" then + outputformat = "mps" + end + if not data then + logs.simple("unknown file '%s'",filename or "?") + else + local mpx = metapost.checkformat(formatname,formatname,caches.setpath("formats")) + if not mpx then + logs.simple("unknown format '%s'",formatname or "?") + else + logs.simple("processing '%s'",(mpdata and (filename or "data")) or fullname) + local result = mpx:execute(data) + if not result then + logs.simple("error: no result object returned") + elseif result.status > 0 then + logs.simple("error: %s",(result.term or "no-term") .. "\n" .. (result.error or "no-error")) + else + if metapost.showlog then + metapost.lastlog = metapost.lastlog .. "\n" .. result.term + logs.simple("info: %s",result.term or "no-term") + end + local figures = result.fig + if figures then + local sorted = table.sortedkeys(figures) + if astable then + local result = { } + logs.simple("storing %s figures in table",#sorted) + for k, v in ipairs(sorted) do + if outputformat == "mps" then + result[v] = figures[v]:postscript() + else + result[v] = figures[v]:svg() -- (3) for prologues + end + end + return result + else + local basename = file.removesuffix(file.basename(filename)) + for k, v in ipairs(sorted) do + local output + if outputformat == "mps" then + output = figures[v]:postscript() + else + output = figures[v]:svg() -- (3) for prologues + end + local outname = format("%s-%s.%s",basename,v,outputformat) + logs.simple("saving %s bytes in '%s'",#output,outname) + io.savedata(outname,output) + end + return #sorted + end + end + end + end + end end |