if not modules then modules = { } end modules ['back-out'] = { version = 1.001, comment = "companion to back-ini.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } local type = type local loadstring = loadstring local context = context -- tokens.scanners..... local get = token.get_index local scanners = tokens.scanners local scaninteger = scanners.integer local scanstring = scanners.string local scankeyword = scanners.keyword local scantokenlist = scanners.tokenlist local serialize = token.serialize local logwriter = logs.writer local openfile = io.open local flushio = io.flush local nuts = nodes.nuts local tonode = nuts.tonode local copynode = nuts.copy local nodepool = nuts.pool local getdata = nuts.getdata local whatsit_code = nodes.nodecodes.whatsit local whatsitcodes = nodes.whatsitcodes local literalvalues = nodes.literalvalues local originliteral_code = literalvalues.origin local pageliteral_code = literalvalues.page local directliteral_code = literalvalues.direct local rawliteral_code = literalvalues.raw local immediate_code = tex.flagcodes.immediate local nodeproperties = nodes.properties.data local channels = { } local register = nodepool.register local newnut = nuts.new local opennode = register(newnut(whatsit_code,whatsitcodes.open)) local writenode = register(newnut(whatsit_code,whatsitcodes.write)) local closenode = register(newnut(whatsit_code,whatsitcodes.close)) local lateluanode = register(newnut(whatsit_code,whatsitcodes.latelua)) local literalnode = register(newnut(whatsit_code,whatsitcodes.literal)) local savenode = register(newnut(whatsit_code,whatsitcodes.save)) local restorenode = register(newnut(whatsit_code,whatsitcodes.restore)) local setmatrixnode = register(newnut(whatsit_code,whatsitcodes.setmatrix)) local open_command, write_command, close_command backends = backends or { } local function immediately(prefix) return prefix and (prefix & immediate_code) ~= 0 end local function openout(prefix) local channel = scaninteger() scankeyword("=") -- hack local filename = scanstring() if not immediately(prefix) then local n = copynode(opennode) nodeproperties[n] = { channel = channel, filename = filename } -- action = "open" return context(tonode(n)) elseif not channels[channel] then local handle = openfile(filename,"wb") or false if handle then channels[channel] = handle else -- error end end end function backends.openout(n) local p = nodeproperties[n] if p then local handle = openfile(p.filename,"wb") or false if handle then channels[p.channel] = handle else -- error end end end local function write(prefix) local channel = scaninteger() if not immediately(prefix) then local t = scantokenlist() local n = copynode(writenode) nodeproperties[n] = { channel = channel, data = t } -- action = "write" return context(tonode(n)) else local content = scanstring() local handle = channels[channel] if handle then handle:write(content,"\n") else logwriter(content,"\n") end end end function backends.writeout(n) local p = nodeproperties[n] if p then local handle = channels[p.channel] local content = serialize(p.data) if handle then handle:write(content,"\n") else logwriter(content,"\n") end end end local function closeout(prefix) local channel = scaninteger() if not immediately(prefix) then local n = copynode(closenode) nodeproperties[n] = { channel = channel } -- action = "close" return context(tonode(n)) else local handle = channels[channel] if handle then handle:close() channels[channel] = false flushio() else -- error end end end function backends.closeout(n) local p = nodeproperties[n] if p then local channel = p.channel local handle = channels[channel] if handle then handle:close() channels[channel] = false flushio() else -- error end end end local noflatelua = 0 local function latelua() local node = copynode(lateluanode) local name = "latelua" if scankeyword("name") then name = scanstring() end local data = scantokenlist() nodeproperties[node] = { name = name, data = data } return context(tonode(node)) end function backends.latelua(current,pos_h,pos_v) -- todo: pass pos_h and pos_v (more efficient in lmtx) local p = nodeproperties[current] if p then data = p.data else data = getdata(current) end noflatelua = noflatelua + 1 local kind = type(data) if kind == "table" then data.action(data.specification or data) elseif kind == "function" then data() else if kind ~= "string" then data = serialize(data) end if #data ~= "" then local code = loadstring(data) if code then code() end end end end function backends.getcallbackstate() return { count = noflatelua } end function nodepool.originliteral(str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = originliteral_code } return t end function nodepool.pageliteral (str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = pageliteral_code } return t end function nodepool.directliteral(str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = directliteral_code } return t end function nodepool.rawliteral (str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = rawliteral_code } return t end local pdfliterals = { [originliteral_code] = originliteral_code, [literalvalues[originliteral_code]] = originliteral_code, [pageliteral_code] = pageliteral_code, [literalvalues[pageliteral_code]] = pageliteral_code, [directliteral_code] = directliteral_code, [literalvalues[directliteral_code]] = directliteral_code, [rawliteral_code] = rawliteral_code, [literalvalues[rawliteral_code]] = rawliteral_code, } function nodepool.literal(mode,str) local t = copynode(literalnode) if str then nodeproperties[t] = { data = str, mode = pdfliterals[mode] or pageliteral_code } else nodeproperties[t] = { data = mode, mode = pageliteral_code } end return t end --- these 3 will move to node-res as they are generic function nodepool.save() return copynode(savenode) end function nodepool.restore() return copynode(restorenode) end function nodepool.setmatrix(rx,sx,sy,ry,tx,ty) local t = copynode(setmatrixnode) nodeproperties[t] = { matrix = { rx, sx, sy, ry, tx, ty } } return t end interfaces.implement { name = "openout", actions = openout, public = true, usage = "value" } interfaces.implement { name = "write", actions = write, public = true, usage = "value" } interfaces.implement { name = "closeout", actions = closeout, public = true, usage = "value" } interfaces.implement { name = "latelua", actions = latelua, public = true, protected = true } interfaces.implement { name = "special", actions = scanstring, public = true, protected = true } open_command = get(token.create("openout")) write_command = get(token.create("write")) close_command = get(token.create("closeout"))