1if not modules then modules = { } end modules ['data-tex'] = {
2 version = 1.001,
3 comment = "companion to luat-lib.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 tostring, tonumber, type = tostring, tonumber, type
10local char, find = string.char, string.find
11
12local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
13
14local report_tex = logs.reporter("resolvers","tex")
15
16
17local sequencers = utilities.sequencers
18local utffiletype = utf.filetype
19local setmetatableindex = table.setmetatableindex
20local loaddata = io.loaddata
21
22
23local resolvers = resolvers
24local methodhandler = resolvers.methodhandler
25local loadbinfile = resolvers.loadbinfile
26local pushinputname = resolvers.pushinputname
27local popinputname = resolvers.popinputname
28
29
30
31
32local textfileactions = sequencers.new {
33 arguments = "str,filename,coding",
34 returnvalues = "str",
35 results = "str",
36}
37
38local textlineactions = sequencers.new {
39 arguments = "str,filename,linenumber,noflines,coding",
40 returnvalues = "str",
41 results = "str",
42}
43
44local helpers = resolvers.openers.helpers
45local appendgroup = sequencers.appendgroup
46local appendaction = sequencers.appendaction
47
48helpers.textfileactions = textfileactions
49helpers.textlineactions = textlineactions
50
51appendgroup(textfileactions,"before")
52appendgroup(textfileactions,"system")
53appendgroup(textfileactions,"after" )
54
55appendgroup(textlineactions,"before")
56appendgroup(textlineactions,"system")
57appendgroup(textlineactions,"after" )
58
59local ctrl_d = char( 4)
60local ctrl_z = char(26)
61
62
63
64local lpegmatch = lpeg.match
65local newline = lpeg.patterns.newline
66local tsplitat = lpeg.tsplitat
67
68local linesplitters = {
69 tsplitat(newline),
70 tsplitat(lpeg.S(" ")^0 * newline),
71 tsplitat(lpeg.S(" \t")^0 * newline),
72 tsplitat(lpeg.S(" \f\t")^0 * newline),
73
74
75}
76
77local linesplitter = linesplitters[1]
78
79directives.register("system.linesplitmethod",function(v)
80 linesplitter = linesplitters[tonumber(v) or 1] or linesplitters[1]
81end)
82
83local function splitlines(str)
84 return lpegmatch(linesplitter,str)
85end
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102local wideutfcoding = {
103 ["utf-16-be"] = utf.utf16_to_utf8_be_t,
104 ["utf-16-le"] = utf.utf16_to_utf8_le_t,
105 ["utf-32-be"] = utf.utf32_to_utf8_be_t,
106 ["utf-32-le"] = utf.utf32_to_utf8_le_t,
107}
108
109local function textopener(tag,filename,filehandle,coding)
110 local lines
111 local t_filehandle = type(filehandle)
112 if not filehandle then
113 lines = loaddata(filename)
114 elseif t_filehandle == "string" then
115 lines = filehandle
116 elseif t_filehandle == "table" then
117 lines = filehandle
118 else
119 lines = filehandle:read("*a")
120
121 filehandle:close()
122 end
123 if type(lines) == "string" then
124 local coding = coding or utffiletype(lines)
125 if trace_locating then
126 report_tex("%a opener: %a opened using method %a",tag,filename,coding)
127 end
128 local wideutf = wideutfcoding[coding]
129 if wideutf then
130 lines = wideutf(lines)
131 else
132 local runner = textfileactions.runner
133 if runner then
134 lines = runner(lines,filename,coding) or lines
135 end
136 lines = splitlines(lines)
137 end
138 elseif trace_locating then
139 report_tex("%a opener: %a opened",tag,filename)
140 end
141 local noflines = #lines
142 if lines[noflines] == "" then
143 lines[noflines] = nil
144 end
145 pushinputname(filename)
146 local currentline = 0
147 local noflines = noflines
148 local handler = {
149 filename = filename,
150 noflines = noflines,
151
152 gotoline = function(self,n)
153 currentline = n - 1
154 if currentline <= 0 then
155 currentline = 0
156 end
157 end,
158 endoffile = function()
159 return not lines or currentline >= noflines
160 end,
161 close = function()
162 local usedname = popinputname()
163 if trace_locating then
164 report_tex("%a closer: %a closed",tag,filename)
165 end
166 handler = nil
167 lines = nil
168 end,
169 reader = function(self)
170 self = self or handler
171
172 if currentline >= noflines then
173 return nil
174 else
175 currentline = currentline + 1
176
177 local content = lines[currentline]
178
179 if content == "" then
180
181 return content
182
183
184 elseif content then
185 local runner = textlineactions.runner
186 if runner then
187 return runner(content,filename,currentline,noflines,coding) or content
188 else
189 return content
190 end
191 else
192 return nil
193 end
194 end
195 end
196 }
197 setmetatableindex(handler,function(t,k)
198 if k == "currentline" then
199 return currentline
200 else
201
202 end
203 end)
204 return handler
205end
206
207helpers.settextopener(textopener)
208
209function resolvers.findtexfile(filename,filetype)
210 return methodhandler('finders',filename,filetype)
211end
212
213function resolvers.opentexfile(filename)
214 return methodhandler('openers',filename)
215end
216
217function resolvers.openfile(filename)
218 local fullname = methodhandler('finders',filename)
219 return fullname and fullname ~= "" and methodhandler('openers',fullname) or nil
220end
221
222function resolvers.loadtexfile(filename,filetype)
223
224 local ok, data, size = loadbinfile(filename, filetype)
225 return data or ""
226end
227
228resolvers.texdatablob = resolvers.loadtexfile
229
230local function installhandler(namespace,what,where,func)
231 if not func then
232 where, func = "after", where
233 end
234 if where == "before" or where == "after" then
235 appendaction(namespace,where,func)
236 else
237 report_tex("installing input %a handlers in %a is not possible",what,tostring(where))
238 end
239end
240
241function resolvers.installinputlinehandler(...) installhandler(textlineactions,"line",...) end
242function resolvers.installinputfilehandler(...) installhandler(textfileactions,"file",...) end
243
244
245
246
247
248
249
250
251 |