1if not modules then modules = { } end modules ['mlib-fio'] = {
2 version = 1.001,
3 comment = "companion to mlib-ctx.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 find = string.find
11local concat = table.concat
12local suffix, addsuffix, is_writable = file.suffix, file.addsuffix, file.is_writable
13local urlhashed = url.hashed
14
15local findfile = resolvers.findfile
16local mplibnew = mplib.new
17
18
19local trace_terminal = false trackers.register("metapost.terminal", function(v) trace_terminal = v end)
20
21local report_metapost = logs.reporter("metapost")
22local report_terminal = logs.reporter("metapost","terminal")
23local report_logger = logs.reporter("metapost","log")
24local report_error = logs.reporter("metapost","error")
25
26mplib.realtimelogging = false
27
28local handlelog do
29
30 local l, nl, dl = { }, 0, false
31
32 local to_terminal <const> = 1
33 local to_file <const> = 2
34 local to_both <const> = 3
35 local to_error <const> = 4
36
37 handlelog = function(instance,target,str)
38 if target == to_terminal then
39
40 elseif target == to_file or target == to_both then
41
42 if str == "\n" then
43 mplib.realtimelogging = true
44 if nl > 0 then
45 report_logger(concat(l,"",1,nl))
46 nl, dl = 0, false
47 elseif not dl then
48 report_logger("")
49 dl = true
50 end
51 else
52 nl = nl + 1
53 l[nl] = str
54 end
55 elseif target == to_error then
56 report_error(str)
57 end
58 end
59
60end
61
62local finders = { }
63mplib.finders = finders
64
65local function validftype(ftype)
66 return ftype == "mp" and "mp" or nil
67end
68
69
70
71local findtexfile = resolvers.findtexfile
72local opentexfile = resolvers.opentexfile
73local splitlines = string.splitlines
74
75local suffixlist = { "mpxl", "mpiv", "mp" }
76
77local remapped = {
78
79
80 ["hatching.mp"] = "mp-remapped-hatching.mp",
81 ["boxes.mp"] = "mp-remapped-boxes.mp",
82 ["hatching"] = "mp-remapped-hatching.mp",
83 ["boxes"] = "mp-remapped-boxes.mp",
84}
85
86local function findmpfile(name,ftype)
87 local usedname = remapped[name] or name
88 local validtyp = validftype(ftype)
89 local fullname = findtexfile(usedname,validtyp)
90 if fullname and fullname ~= "" then
91 return fullname
92 elseif suffix(usedname) == "" then
93 for i=1,#suffixlist do
94 fullname = findfile(addsuffix(usedname,suffixlist[i]),validtyp)
95 if fullname and fullname ~= "" then
96 return fullname
97 end
98 end
99 end
100 return nil
101end
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129finders.file = function(specification,name,mode,kind)
130 if mode == "w" then
131 return is_writable(name) and name or nil
132 else
133 return findmpfile(name,kind) or nil
134 end
135end
136
137local function finder(name,mode,kind)
138 local specification = urlhashed(name)
139 local finder = finders[specification.scheme] or finders.file
140 local found = finder(specification,name,mode,validftype(ftype))
141 return found
142end
143
144local function writetoterminal(terminaldata,maxterm,d)
145 local t = type(d)
146 local n = 0
147 if t == "string" then
148 d = splitlines(d)
149 n = #d
150 for i=1,#d do
151 maxterm = maxterm + 1
152 terminaldata[maxterm] = d[i]
153 end
154 elseif t == "table" then
155 for i=1,#d do
156 local l = d[i]
157 if not l then
158
159 elseif find(l,"[\n\r]") then
160 local s = splitlines(l)
161 local m = #s
162 for i=1,m do
163 maxterm = maxterm + 1
164 terminaldata[maxterm] = s[i]
165 end
166 n = n + m
167 else
168 maxterm = maxterm + 1
169 terminaldata[maxterm] = d[i]
170 n = 1
171 end
172 end
173 end
174 if trace_terminal then
175 report_metapost("writing %i lines, in cache %s",n,maxterm)
176 end
177 return maxterm
178end
179
180local function readfromterminal(terminaldata,maxterm,nowterm)
181 if nowterm >= maxterm then
182 terminaldata[nowterm] = false
183 maxterm = 0
184 nowterm = 0
185 if trace_terminal then
186 report_metapost("resetting, maxcache %i",#terminaldata)
187 end
188 return maxterm, nowterm, nil
189 else
190 if nowterm > 0 then
191 terminaldata[nowterm] = false
192 end
193 nowterm = nowterm + 1
194 local s = terminaldata[nowterm]
195 if trace_terminal then
196 report_metapost("reading line %i: %s",nowterm,s)
197 end
198 return maxterm, nowterm, s
199 end
200end
201
202local function fileopener()
203
204
205
206 local terminaldata = { }
207 local maxterm = 0
208 local nowterm = 0
209
210 local terminal = {
211 name = "terminal",
212 close = function()
213
214
215
216 end,
217 reader = function()
218 local line
219 maxterm, nowterm, line = readfromterminal(terminaldata,maxterm,nowterm)
220 return line
221 end,
222 writer = function(d)
223 maxterm = writetoterminal(terminaldata,maxterm,d)
224 end,
225 }
226
227 return function(name,mode,kind)
228 if name == "terminal" then
229
230 return terminal
231 elseif mode == "w" then
232
233 local f = io.open(name,"wb")
234 if f then
235
236 return {
237 name = full,
238 writer = function(s) return f:write(s) end,
239 close = function() f:close() end,
240 }
241 end
242 else
243 local full = findtexfile(name,validftype(ftype))
244 if full then
245
246 return opentexfile(full)
247 end
248 end
249 end
250
251end
252
253local overloadmode = "warning"
254
255directives.register("metapost.overloadmode",function(v)
256 if v == "warning" or v == "error" then
257 overloadmode = v
258 else
259 overloadmode= false
260 end
261end)
262
263local propertycodes = {
264 [-3] = "mutable",
265 [ 1] = "primitive",
266 [ 2] = "permanent",
267 [ 3] = "immutable",
268 [ 4] = "frozen",
269}
270
271mplib.propertycodes = propertycodes
272
273local report = logs.reporter("metafun", "log")
274
275local function overload(property,name)
276 if overloadmode and property >= 0 then
277
278 local code = propertycodes[property] or "unknown"
279 report("overloading %s %a",code, name)
280
281 if overloadmode == "error" then
282 luatex.abort()
283 end
284 return false
285 else
286
287 return true
288 end
289end
290
291local showcontext = mplib.showcontext
292
293local function handleerror(instance, message, helpinfo, interaction)
294 report()
295 report("error: %s", message)
296 report()
297 showcontext(instance)
298 report()
299 report(helpinfo)
300 report()
301 if interaction == 5 then
302
303 end
304end
305
306local function handlewarning(instance, message)
307 report()
308 report("warning: %s", message)
309 report()
310end
311
312function mplib.new(specification)
313 local openfile = fileopener()
314 local handlers = specification.handlers
315 local instance
316 instance = mplibnew {
317 bend_tolerance = specification.bendtolerance,
318 move_tolerance = specification.movetolerance,
319 math_mode = specification.mathmode,
320 run_script = specification.runscript,
321 run_internal = specification.runinternal,
322 make_text = specification.maketext,
323
324 utf8_mode = true,
325 text_mode = true,
326 show_mode = true,
327 find_file = finder,
328 run_overload = overload,
329 open_file = openfile,
330 interaction = "silent",
331 job_name = tex.jobname,
332 halt_on_error = true,
333 run_logger = handlers.log or function(...) handlelog (instance,...) end,
334 run_error = handlers.error or function(...) handleerror (instance,...) end,
335 run_warning = handlers.warning or function(...) handlewarning(instance,...) end,
336 }
337 return instance, openfile("terminal")
338end
339
340mplib.finder = finder
341
342 |