1if not modules then modules = { } end modules ['back-out'] = {
2 version = 1.001,
3 comment = "companion to back-ini.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9local type = type
10local loadstring = loadstring
11
12local context = context
13
14
15
16local get = token.get_index
17local scanners = tokens.scanners
18local scaninteger = scanners.integer
19local scanstring = scanners.string
20local scankeyword = scanners.keyword
21local scantokenlist = scanners.tokenlist
22
23local serialize = token.serialize
24
25local logwriter = logs.writer
26local openfile = io.open
27local flushio = io.flush
28
29local nuts = nodes.nuts
30local tonode = nuts.tonode
31local copynode = nuts.copy
32local nodepool = nuts.pool
33
34local getdata = nuts.getdata
35
36local whatsit_code = nodes.nodecodes.whatsit
37
38local whatsitcodes = nodes.whatsitcodes
39
40local literalvalues = nodes.literalvalues
41local originliteral_code = literalvalues.origin
42local pageliteral_code = literalvalues.page
43local directliteral_code = literalvalues.direct
44local rawliteral_code = literalvalues.raw
45
46local immediate_code = tex.flagcodes.immediate
47
48local nodeproperties = nodes.properties.data
49
50local channels = { }
51
52local register = nodepool.register
53local newnut = nuts.new
54
55local opennode = register(newnut(whatsit_code,whatsitcodes.open))
56local writenode = register(newnut(whatsit_code,whatsitcodes.write))
57local closenode = register(newnut(whatsit_code,whatsitcodes.close))
58local lateluanode = register(newnut(whatsit_code,whatsitcodes.latelua))
59local literalnode = register(newnut(whatsit_code,whatsitcodes.literal))
60local savenode = register(newnut(whatsit_code,whatsitcodes.save))
61local restorenode = register(newnut(whatsit_code,whatsitcodes.restore))
62local setmatrixnode = register(newnut(whatsit_code,whatsitcodes.setmatrix))
63
64local open_command, write_command, close_command
65
66backends = backends or { }
67
68local function immediately(prefix)
69 return prefix and (prefix & immediate_code) ~= 0
70end
71
72local function openout(prefix)
73 local channel = scaninteger()
74 scankeyword("=")
75 local filename = scanstring()
76 if not immediately(prefix) then
77 local n = copynode(opennode)
78 nodeproperties[n] = { channel = channel, filename = filename }
79 return context(tonode(n))
80 elseif not channels[channel] then
81 local handle = openfile(filename,"wb") or false
82 if handle then
83 channels[channel] = handle
84 else
85
86 end
87 end
88end
89
90function backends.openout(n)
91 local p = nodeproperties[n]
92 if p then
93 local handle = openfile(p.filename,"wb") or false
94 if handle then
95 channels[p.channel] = handle
96 else
97
98 end
99 end
100end
101
102local function write(prefix)
103 local channel = scaninteger()
104 if not immediately(prefix) then
105 local t = scantokenlist()
106 local n = copynode(writenode)
107 nodeproperties[n] = { channel = channel, data = t }
108 return context(tonode(n))
109 else
110 local content = scanstring()
111 local handle = channels[channel]
112 if handle then
113 handle:write(content,"\n")
114 else
115 logwriter(content,"\n")
116 end
117 end
118end
119
120function backends.writeout(n)
121 local p = nodeproperties[n]
122 if p then
123 local handle = channels[p.channel]
124 local content = serialize(p.data)
125 if handle then
126 handle:write(content,"\n")
127 else
128 logwriter(content,"\n")
129 end
130 end
131end
132
133local function closeout(prefix)
134 local channel = scaninteger()
135 if not immediately(prefix) then
136 local n = copynode(closenode)
137 nodeproperties[n] = { channel = channel }
138 return context(tonode(n))
139 else
140 local handle = channels[channel]
141 if handle then
142 handle:close()
143 channels[channel] = false
144 flushio()
145 else
146
147 end
148 end
149end
150
151function backends.closeout(n)
152 local p = nodeproperties[n]
153 if p then
154 local channel = p.channel
155 local handle = channels[channel]
156 if handle then
157 handle:close()
158 channels[channel] = false
159 flushio()
160 else
161
162 end
163 end
164end
165
166local noflatelua = 0
167
168local function latelua()
169 local node = copynode(lateluanode)
170 local name = "latelua"
171 if scankeyword("name") then
172 name = scanstring()
173 end
174 local data = scantokenlist()
175 nodeproperties[node] = { name = name, data = data }
176 return context(tonode(node))
177end
178
179function backends.latelua(current,pos_h,pos_v)
180 local p = nodeproperties[current]
181 if p then
182 data = p.data
183 else
184 data = getdata(current)
185 end
186 noflatelua = noflatelua + 1
187 local kind = type(data)
188 if kind == "table" then
189 data.action(data.specification or data)
190 elseif kind == "function" then
191 data()
192 else
193 if kind ~= "string" then
194 data = serialize(data)
195 end
196 if #data ~= "" then
197 local code = loadstring(data)
198 if code then
199 code()
200 end
201 end
202 end
203end
204
205function backends.getcallbackstate()
206 return { count = noflatelua }
207end
208
209function nodepool.originliteral(str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = originliteral_code } return t end
210function nodepool.pageliteral (str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = pageliteral_code } return t end
211function nodepool.directliteral(str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = directliteral_code } return t end
212function nodepool.rawliteral (str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = rawliteral_code } return t end
213
214local pdfliterals = {
215 [originliteral_code] = originliteral_code, [literalvalues[originliteral_code]] = originliteral_code,
216 [pageliteral_code] = pageliteral_code, [literalvalues[pageliteral_code]] = pageliteral_code,
217 [directliteral_code] = directliteral_code, [literalvalues[directliteral_code]] = directliteral_code,
218 [rawliteral_code] = rawliteral_code, [literalvalues[rawliteral_code]] = rawliteral_code,
219}
220
221function nodepool.literal(mode,str)
222 local t = copynode(literalnode)
223 if str then
224 nodeproperties[t] = { data = str, mode = pdfliterals[mode] or pageliteral_code }
225 else
226 nodeproperties[t] = { data = mode, mode = pageliteral_code }
227 end
228 return t
229end
230
231
232
233function nodepool.save()
234 return copynode(savenode)
235end
236
237function nodepool.restore()
238 return copynode(restorenode)
239end
240
241function nodepool.setmatrix(rx,sx,sy,ry,tx,ty)
242 local t = copynode(setmatrixnode)
243 nodeproperties[t] = { matrix = { rx, sx, sy, ry, tx, ty } }
244 return t
245end
246
247interfaces.implement { name = "openout", actions = openout, public = true, usage = "value" }
248interfaces.implement { name = "write", actions = write, public = true, usage = "value" }
249interfaces.implement { name = "closeout", actions = closeout, public = true, usage = "value" }
250interfaces.implement { name = "latelua", actions = latelua, public = true, protected = true }
251interfaces.implement { name = "special", actions = scanstring, public = true, protected = true }
252
253open_command = get(token.create("openout"))
254write_command = get(token.create("write"))
255close_command = get(token.create("closeout"))
256 |