if not modules then modules = { } end modules ['mlib-fio'] = { 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", } local type = type local find = string.find local concat = table.concat local suffix, addsuffix, is_writable = file.suffix, file.addsuffix, file.is_writable local urlhashed = url.hashed local findfile = resolvers.findfile local mplibnew = mplib.new ----- mplibexecute = mplib.execute local trace_terminal = false trackers.register("metapost.terminal", function(v) trace_terminal = v end) local report_metapost = logs.reporter("metapost") local report_terminal = logs.reporter("metapost","terminal") local report_logger = logs.reporter("metapost","log") local report_error = logs.reporter("metapost","error") mplib.realtimelogging = false local handlelog do local l, nl, dl = { }, 0, false handlelog = function(instance,target,str) if target == 1 then -- log elseif target == 2 or target == 3 then -- term if str == "\n" then mplib.realtimelogging = true if nl > 0 then report_logger(concat(l,"",1,nl)) nl, dl = 0, false elseif not dl then report_logger("") dl = true end else nl = nl + 1 l[nl] = str end elseif target == 4 then report_error(str) end end end local finders = { } mplib.finders = finders -- also used in meta-lua.lua local function validftype(ftype) return ftype == "mp" and "mp" or nil end -- We can have a list! local findtexfile = resolvers.findtexfile local opentexfile = resolvers.opentexfile local splitlines = string.splitlines local suffixlist = { "mpxl", "mpiv", "mp" } -- no "mf" local remapped = { -- We don't yet have an interface for adding more here but when needed -- there will be one. ["hatching.mp"] = "mp-remapped-hatching.mp", ["boxes.mp"] = "mp-remapped-boxes.mp", ["hatching"] = "mp-remapped-hatching.mp", ["boxes"] = "mp-remapped-boxes.mp", } local function findmpfile(name,ftype) local usedname = remapped[name] or name local validtyp = validftype(ftype) local fullname = findtexfile(usedname,validtyp) if fullname and fullname ~= "" then return fullname elseif suffix(usedname) == "" then for i=1,#suffixlist do fullname = findfile(addsuffix(usedname,suffixlist[i]),validtyp) if fullname and fullname ~= "" then return fullname end end end return nil end -- variant 1 -- finders.file = function(specification,name,mode,kind) -- if mode == "r" then -- return findmpfile(name,kind) -- elseif is_writable(name) then -- return name -- else -- return nil -- end -- end -- variant 2 -- finders.file = function(specification,name,mode,kind) -- if not mode or mode == "r" then -- return findmpfile(name,kind) -- elseif is_writable(name) then -- return name -- else -- return nil -- end -- end -- variant 3 finders.file = function(specification,name,mode,kind) if mode == "w" then return is_writable(name) and name or nil else return findmpfile(name,kind) or nil end end local function finder(name,mode,kind) -- fake message for mpost.map and metafun.mpvi local specification = urlhashed(name) local finder = finders[specification.scheme] or finders.file local found = finder(specification,name,mode,validftype(ftype)) return found end local function writetoterminal(terminaldata,maxterm,d) local t = type(d) local n = 0 if t == "string" then d = splitlines(d) n = #d for i=1,#d do maxterm = maxterm + 1 terminaldata[maxterm] = d[i] end elseif t == "table" then for i=1,#d do local l = d[i] if not l then -- just ignore elseif find(l,"[\n\r]") then local s = splitlines(l) local m = #s for i=1,m do maxterm = maxterm + 1 terminaldata[maxterm] = s[i] end n = n + m else maxterm = maxterm + 1 terminaldata[maxterm] = d[i] n = 1 end end end if trace_terminal then report_metapost("writing %i lines, in cache %s",n,maxterm) end return maxterm end local function readfromterminal(terminaldata,maxterm,nowterm) if nowterm >= maxterm then terminaldata[nowterm] = false maxterm = 0 nowterm = 0 if trace_terminal then report_metapost("resetting, maxcache %i",#terminaldata) end return maxterm, nowterm, nil else if nowterm > 0 then terminaldata[nowterm] = false end nowterm = nowterm + 1 local s = terminaldata[nowterm] if trace_terminal then report_metapost("reading line %i: %s",nowterm,s) end return maxterm, nowterm, s end end local function fileopener() -- these can go into the table itself local terminaldata = { } local maxterm = 0 local nowterm = 0 local terminal = { name = "terminal", close = function() -- terminal = { } -- maxterm = 0 -- nowterm = 0 end, reader = function() local line maxterm, nowterm, line = readfromterminal(terminaldata,maxterm,nowterm) return line end, writer = function(d) maxterm = writetoterminal(terminaldata,maxterm,d) end, } return function(name,mode,kind) if name == "terminal" then -- report_metapost("opening terminal") return terminal elseif mode == "w" then -- we need an extra check here for permissions local f = io.open(name,"wb") if f then -- report_metapost("opening file %a for writing",full) return { name = full, writer = function(s) return f:write(s) end, -- io.write(f,s) close = function() f:close() end, } end else local full = findtexfile(name,validftype(ftype)) if full then -- report_metapost("opening file %a for reading",full) return opentexfile(full) end end end end local overloadmode = "warning" directives.register("metapost.overloadmode",function(v) if v == "warning" or v == "error" then overloadmode = v else overloadmode= false end end) local propertycodes = { [-3] = "mutable", [ 1] = "primitive", [ 2] = "permanent", [ 3] = "immutable", } mplib.propertycodes = propertycodes local report = logs.reporter("metafun", "log") local function overload(property,name) if overloadmode and property >= 0 then -- turn of warning after format is loaded local code = propertycodes[property] or "unknown" report("overloading %s %a",code, name) -- no overload permitted if overloadmode == "error" then luatex.abort() end return false else -- overload permitted return true end end local showcontext = mplib.showcontext local function handleerror(instance, message, helpinfo, interaction) report() report("error: %s", message) report() showcontext(instance) report() report(helpinfo) report() if interaction == 5 then -- luatex.abort() end end local function handlewarning(instance, message) report() report("warning: %s", message) report() end function mplib.new(specification) local openfile = fileopener() local handlers = specification.handlers local instance instance = mplibnew { -- used bend_tolerance = specification.bendtolerance, move_tolerance = specification.movetolerance, math_mode = specification.mathmode, run_script = specification.runscript, run_internal = specification.runinternal, script_error = specification.scripterror, make_text = specification.maketext, -- always extensions = 1, -- random_seed = specification.seed, utf8_mode = true, text_mode = true, show_mode = true, -- not used -- noninteractive = true; -- ini_version = true, -- always find_file = finder, run_overload = overload, open_file = openfile, interaction = "silent", job_name = tex.jobname, -- mandate in order to get something back halt_on_error = true, run_logger = handlers.log or function(...) handlelog (instance,...) end, run_error = handlers.error or function(...) handleerror (instance,...) end, run_warning = handlers.warning or function(...) handlewarning(instance,...) end, } return instance, openfile("terminal") end mplib.finder = finder -----.execute = executor