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 return ""
181
182
183 elseif content then
184 local runner = textlineactions.runner
185 if runner then
186 return runner(content,filename,currentline,noflines,coding) or content
187 else
188 return content
189 end
190 else
191 return nil
192 end
193 end
194 end
195 }
196 setmetatableindex(handler,function(t,k)
197 if k == "currentline" then
198 return currentline
199 else
200
201 end
202 end)
203 return handler
204end
205
206helpers.settextopener(textopener)
207
208function resolvers.findtexfile(filename,filetype)
209 return methodhandler('finders',filename,filetype)
210end
211
212function resolvers.opentexfile(filename)
213 return methodhandler('openers',filename)
214end
215
216function resolvers.openfile(filename)
217 local fullname = methodhandler('finders',filename)
218 return fullname and fullname ~= "" and methodhandler('openers',fullname) or nil
219end
220
221function resolvers.loadtexfile(filename,filetype)
222
223 local ok, data, size = loadbinfile(filename, filetype)
224 return data or ""
225end
226
227resolvers.texdatablob = resolvers.loadtexfile
228
229local function installhandler(namespace,what,where,func)
230 if not func then
231 where, func = "after", where
232 end
233 if where == "before" or where == "after" then
234 appendaction(namespace,where,func)
235 else
236 report_tex("installing input %a handlers in %a is not possible",what,tostring(where))
237 end
238end
239
240function resolvers.installinputlinehandler(...) installhandler(textlineactions,"line",...) end
241function resolvers.installinputfilehandler(...) installhandler(textfileactions,"file",...) end
242
243
244
245
246
247
248
249
250 |