summaryrefslogtreecommitdiff
path: root/tex/context/base/mlib-run.lua
diff options
context:
space:
mode:
authorMarius <mariausol@gmail.com>2010-07-04 15:32:09 +0300
committerMarius <mariausol@gmail.com>2010-07-04 15:32:09 +0300
commit85b7bc695629926641c7cb752fd478adfdf374f3 (patch)
tree80293f5aaa7b95a500a78392c39688d8ee7a32fc /tex/context/base/mlib-run.lua
downloadcontext-85b7bc695629926641c7cb752fd478adfdf374f3.tar.gz
stable 2010-05-24 13:10
Diffstat (limited to 'tex/context/base/mlib-run.lua')
-rw-r--r--tex/context/base/mlib-run.lua379
1 files changed, 379 insertions, 0 deletions
diff --git a/tex/context/base/mlib-run.lua b/tex/context/base/mlib-run.lua
new file mode 100644
index 000000000..f352e1db1
--- /dev/null
+++ b/tex/context/base/mlib-run.lua
@@ -0,0 +1,379 @@
+if not modules then modules = { } end modules ['mlib-run'] = {
+ version = 1.001,
+ comment = "companion to mlib-ctx.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+--~ cmyk -> done, native
+--~ spot -> done, but needs reworking (simpler)
+--~ multitone ->
+--~ shade -> partly done, todo: cm
+--~ figure -> done
+--~ hyperlink -> low priority, easy
+
+-- new * run
+-- or
+-- new * execute^1 * finish
+
+-- a*[b,c] == b + a * (c-b)
+
+--[[ldx--
+<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 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, gsub, match = string.format, string.gsub, string.match
+
+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 file.is_qualified_path(name) then
+ return name
+ else
+ return resolvers.find_file(name,ftype)
+ end
+end
+
+metapost.finder = finder
+
+metapost.parameters = {
+ hash_size = 100000,
+ main_memory = 4000000,
+ max_in_open = 50,
+ param_size = 100000,
+}
+
+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)
+ 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.removesuffix(target),
+ }
+ ) )
+ if mpx then
+ starttiming(metapost.exectime)
+ local result = mpx:execute(format(preamble,version or "unknown",name))
+ stoptiming(metapost.exectime)
+ mpx:finish()
+ end
+ stoptiming(mplib)
+end
+
+function metapost.load(name)
+ 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",
+ }
+ ) )
+ local result
+ if not mpx then
+ result = { status = 99, error = "out of memory"}
+ end
+ stoptiming(mplib)
+ return mpx, result
+end
+
+function metapost.unload(mpx)
+ starttiming(mplib)
+ if mpx then
+ mpx:finish()
+ end
+ stoptiming(mplib)
+end
+
+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.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 = 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 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("show mp_parent_version ;")
+ if not result.log then
+ metapost.reporterror(result)
+ else
+ local version = match(result.log,">> *(.-)[\n\r]") or "unknown"
+ version = gsub(version,"[\'\"]","")
+ 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","making '%s' into '%s'", mpsinput, mpsformat)
+ metapost.make(mpsinput,mpsformat,the_version) -- somehow return ... fails here
+ if lfs.isfile(mpsformat) then
+ commands.writestatus("mplib","loading '%s' from '%s'", mpsinput, mpsformat)
+ return metapost.load(mpsformat)
+ else
+ commands.writestatus("mplib","problems with '%s' from '%s'", mpsinput, mpsformat)
+ end
+end
+
+local mpxformats = { }
+
+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[instance] = mpx
+ end
+ return mpx
+end
+
+function metapost.reset(mpx)
+ if not mpx then
+ -- nothing
+ elseif type(mpx) == "string" then
+ if mpxformats[mpx] then
+ mpxformats[mpx]:finish()
+ mpxformats[mpx] = nil
+ end
+ else
+ for name, instance in next, mpxformats do
+ if instance == mpx then
+ mpx:finish()
+ mpxformats[name] = nil
+ break
+ end
+ end
+ end
+end
+
+local mp_inp, mp_log, mp_tag = { }, { }, 0
+
+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
+ 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
+ if trace_graphics then
+ mp_inp[mpx]:write(d)
+ end
+ starttiming(metapost.exectime)
+ result = mpx:execute(d)
+ 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
+ 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 result.fig then
+ converted = metapost.convert(result, trialrun, flusher, multipass, askedfig)
+ end
+ end
+ else
+ metapost.report("mp error: invalid graphic component %s",i)
+ end
+ end
+ else
+ 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("mp error: no result object returned")
+ elseif result.status > 0 then
+ 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
+ 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()
+ metapost.report('mp warning: no converter set')
+end
+
+function metapost.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=1,#sorted do
+ local v = sorted[k]
+ 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=1,#sorted do
+ local v = sorted[k]
+ 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