1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
|
module(...,package.seeall)
local make4ht = require("make4ht-lib")
--template engine
function interp(s, tab)
local tab = tab or {}
return (s:gsub('($%b{})', function(w) return tab[w:sub(3, -2)] or w end))
end
--print( interp("${name} is ${value}", {name = "foo", value = "bar"}) )
function addProperty(s,prop)
if prop ~=nil then
return s .." "..prop
else
return s
end
end
getmetatable("").__mod = interp
getmetatable("").__add = addProperty
--print( "${name} is ${value}" % {name = "foo", value = "bar"} )
-- Outputs "foo is bar"
function string:split(sep)
local sep, fields = sep or ":", {}
local pattern = string.format("([^%s]+)", sep)
self:gsub(pattern, function(c) fields[#fields+1] = c end)
return fields
end
function remove_extension(path)
local found, len, remainder = string.find(path, "^(.*)%.[^%.]*$")
if found then
return remainder
else
return path
end
end
--
function file_exists(file)
local f = io.open(file, "rb")
if f then f:close() end
return f ~= nil
end
-- searching for converted images
function parse_lg(filename)
print("Parse LG")
local outputimages,outputfiles,status={},{},nil
local fonts, used_fonts = {},{}
if not file_exists(filename) then
print("Cannot read log file: "..filename)
else
local usedfiles={}
for line in io.lines(filename) do
--- needs --- pokus.idv[1] ==> pokus0x.png ---
-- line:gsub("needs --- (.+?)[([0-9]+) ==> ([%a%d%p%.%-%_]*)",function(name,page,k) table.insert(outputimages,k)end)
line:gsub("needs %-%-%- (.+)%[([0-9]+)%] ==> ([%a%d%p%.%-%_]*)",
function(file,page,output)
local rec = {
source = file,
page=page,
output = output
}
table.insert(outputimages,rec)
end
)
line:gsub("File: (.*)", function(k)
if not usedfiles[k] then
table.insert(outputfiles,k)
usedfiles[k] = true
end
end)
line:gsub("htfcss: ([^%s]+)(.*)",function(k,r)
local fields = {}
r:gsub("[%s]*([^%:]+):[%s]*([^;]+);",function(c,v)
fields[c] = v
end)
fonts[k] = fields
end)
line:gsub('Font("([^"]+)","([%d]+)","([%d]+)","([%d]+)"',function(n,s1,s2,s3)
table.insert(used_fonts,{n,s1,s2,s3})
end)
end
status=true
end
return {files = outputfiles, images = outputimages},status
end
local cp_func = os.type == "unix" and "cp" or "copy"
function cp(src,dest)
local command = string.format('%s %s %s', cp_func, src, dest)
if cp_func == "copy" then command = command:gsub("/",'\\') end
print("Copy: "..command)
os.execute(command)
end
local used_dir = {}
function prepare_path(path)
--local dirs = path:split("/")
local dirs = {}
if path:match("^/") then dirs = {""}
elseif path:match("^~") then
local home = os.getenv "HOME"
dirs = home:split "/"
path = path:gsub("^~/","")
table.insert(dirs,1,"")
end
if path:match("/$")then path = path .. " " end
for _,d in pairs(path:split "/") do
table.insert(dirs,d)
end
table.remove(dirs,#dirs)
return dirs,table.concat(dirs,"/")
end
-- Find which part of path already exists
-- and which directories have to be created
function find_directories(dirs, pos)
local pos = pos or #dirs
-- we tried whole path and no dir exist
if pos < 1 then return dirs end
local path = ""
-- in the case of unix absolute path, empty string is inserted in dirs
if pos == 1 and dirs[pos] == "" then
path = "/"
else
path = table.concat(dirs,"/", 1,pos) .. "/"
end
if not lfs.chdir(path) then -- recursion until we succesfully changed dir
-- or there are no elements in the dir table
return find_directories(dirs,pos - 1)
elseif pos ~= #dirs then -- if we succesfully changed dir
-- and we have dirs to create
local p = {}
for i = pos+1, #dirs do
table.insert(p, dirs[i])
end
return p
else -- whole path exists
return {}
end
end
function mkdirectories(dirs)
if type(dirs) ~="table" then
return false, "mkdirectories: dirs is not table"
end
for _,d in pairs(dirs) do
local stat,msg = lfs.mkdir(d)
if not stat then return false, "makedirectories error: "..msg end
lfs.chdir(d)
end
return true
end
function copy_filter(src,dest, filter)
local src_f=io.open(src,"rb")
local dst_f=io.open(dest,"w")
local contents = src_f:read("*all")
local filter = filter or function(s) return s end
src_f:close()
dst_f:write(filter(contents))
dst_f:close()
end
function copy(filename,outfilename)
local currdir = lfs.currentdir()
if filename == outfilename then return true end
local parts, path = prepare_path(outfilename)
if not used_dir[path] then
local to_create, msg = find_directories(parts)
if not to_create then
print(msg)
return false
end
used_dir[path] = true
local stat, msg = mkdirectories(to_create)
if not stat then print(msg) end
end
lfs.chdir(currdir)
cp(filename, path)
return true
end
-- Config loading
local function run(untrusted_code, env)
if untrusted_code:byte(1) == 27 then return nil, "binary bytecode prohibited" end
local untrusted_function = nil
if not loadstring then
untrusted_function, message = load(untrusted_code, nil, "t",env)
else
untrusted_function, message = loadstring(untrusted_code)
end
if not untrusted_function then return nil, message end
if not setfenv then setfenv = function(a,b) return true end end
setfenv(untrusted_function, env)
return pcall(untrusted_function)
end
local main_settings = {}
main_settings.fonts = {}
local env = {}
-- We make sandbox for make script, all functions must be explicitely declared
-- Function declarations:
env.pairs = pairs
env.ipairs = ipairs
env.print = print
env.split = split
env.string = string
env.table = table
env.copy = copy
env.mkdirectories = mkdirectories
env.require = require
env.texio = texio
env.type = type
env.lfs = lfs
env.os = os
env.io = io
env.unicode = unicode
env.Font = function(s)
local font_name = s["name"]
if not font_name then return nil, "Cannot find font name" end
env.settings.fonts[font_name] = s
end
env.Make = make4ht.Make
env.Make.params = env.settings
env.Make:add("test","no takže ${tex4ht_sty_par} ${htlatex} ${input} ${config}")
--env.Make:add("htlatex", "${htlatex} ${latex_par} '\\\makeatletter\\def\\HCode{\\futurelet\\HCode\\HChar}\\def\\HChar{\\ifx\"\\HCode\\def\\HCode\"##1\"{\\Link##1}\\expandafter\\HCode\\else\\expandafter\\Link\\fi}\\def\\Link#1.a.b.c.{\\g@addto@macro\\@documentclasshook{\\RequirePackage[#1,html]{tex4ht}\\let\\HCode\\documentstyle\\def\\documentstyle{\\let\\documentstyle\\HCode\\expandafter\\def\\csname tex4ht\\endcsname{#1,html}\\def\\HCode####1{\\documentstyle[tex4ht,}\\@ifnextchar[{\\HCode}{\\documentstyle[tex4ht]}}}\\makeatother\\HCode '${config}${tex4ht_sty_par}'.a.b.c.\\input ' ${input}")
env.Make:add("htlatex",function(par)
local command =
"${htlatex} ${latex_par} '\\makeatletter"..
"\\def\\HCode{\\futurelet\\HCode\\HChar}\\def\\HChar{\\ifx\"\\HCode"..
"\\def\\HCode\"##1\"{\\Link##1}\\expandafter\\HCode\\else"..
"\\expandafter\\Link\\fi}\\def\\Link#1.a.b.c.{\\g@addto@macro"..
"\\@documentclasshook{\\RequirePackage[#1,html]{tex4ht}${packages}}"..
"\\let\\HCode\\documentstyle\\def\\documentstyle{\\let\\documentstyle"..
"\\HCode\\expandafter\\def\\csname tex4ht\\endcsname{#1,html}\\def"..
"\\HCode####1{\\documentstyle[tex4ht,}\\@ifnextchar[{\\HCode}{"..
"\\documentstyle[tex4ht]}}}\\makeatother\\HCode ${tex4ht_sty_par}.a.b.c."..
"\\input ${input}'"
if os.type == "windows" then
command = command:gsub("'",'')
end
command = command % par
print("LaTeX call: "..command)
os.execute(command)
local logfile = par.input .. ".log"
local f = io.open(logfile,"r")
if not f then
print("Make4ht: cannot open log file "..logfile)
return 1
end
local len = f:seek("end")
f:seek("set", len - 256)
local text = f:read("*a")
f:close()
if text:match("No pages of output") then return 1 end
return 0
end
,{correct_exit=0})
env.Make:add("tex4ht","tex4ht ${tex4ht_par} ${input}", nil, 1)
env.Make:add("t4ht","t4ht ${t4ht_par} ${input}.${ext}",{ext="dvi"},1)
function load_config(settings, config_name)
local settings = settings or main_settings
env.settings = settings
env.mode = settings.mode
local config_name = config_name or "config.lua"
local f = io.open(config_name,"r")
if not f then return env, "Cannot open config file" end
local code = f:read("*all")
local fn, msg = run(code,env)
if not fn then print(msg) end
assert(fn)
return env
end
|