-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathmake4ht-htlatex.lua
153 lines (139 loc) · 6.54 KB
/
make4ht-htlatex.lua
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
local log = logging.new "htlatex"
local autolog = logging.new "autohtlatex"
local error_logparser = require("make4ht-errorlogparser")
local Make = Make or {}
-- this function reads the LaTeX log file and tries to detect fatal errors in the compilation
local function testlogfile(par)
local logfile = mkutils.file_in_builddir(par.input .. ".log", par)
local f = io.open(logfile,"r")
if not f then
log:warning("Make4ht: cannot open log file "..logfile)
return 1
end
local content = f:read("*a")
-- test only the end of the log file, no need to run search functions on everything
local text = content:sub(-1256)
f:close()
-- parse log file for all errors in non-interactive modes
if par.interaction~="errorstopmode" then
-- the error log parsing can be slow, so detect errors first
-- detect both default error messages (! msg) and -file-line-number errors (filename:lineno:msg)
if content:match("\n!") or content:match("[^:]+%:%d+%:.+") then
local errors, chunks = error_logparser.parse(content)
if #errors > 0 then
log:error("Compilation errors in the htlatex run")
log:error("Filename", "Line", "Message")
for _, err in ipairs(errors) do
log:error(err.filename or "?", err.line or "?", err.error)
log:status(err.context)
end
end
end
end
-- info about packages with no corresponding .4ht files
local missing_4ht = error_logparser.get_missing_4ht_files(content)
for _, filename in ipairs(missing_4ht) do log:info("Unsupported file: " .. filename) end
-- test for fatal errors
if text:match("No pages of output") or text:match("TeX capacity exceeded, sorry") or text:match("That makes 100 errors") or text:match("Emergency stop") then return 1 end
return 0
end
-- Make this function available in the build files
Make.testlogfile = testlogfile
--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}")
-- template for calling LaTeX with tex4ht loaded
Make.latex_command = "${htlatex} --interaction=${interaction} ${build_dir_arg} ${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.{"..
"\\let\\HCode\\documentstyle\\def\\documentstyle{\\let\\documentstyle"..
"\\HCode\\expandafter\\def\\csname tex4ht\\endcsname{#1,html}\\def"..
"\\HCode####1{\\documentstyle[tex4ht,}\\@ifnextchar[{\\HCode}{"..
"\\documentstyle[tex4ht]}}\\RequirePackage[#1,html]{tex4ht}${packages}}\\makeatother\\HCode ${tex4ht_sty_par}.a.b.c."..
"\\input \"\\detokenize{${tex_file}}\"'"
Make.plain_command = '${htlatex} --interaction=${interaction} ${build_dir_arg} ${latex_par}' ..
"'\\def\\Link#1.a.b.c.{\\expandafter\\def\\csname tex4ht\\endcsname{\\expandafter\\def\\csname tex4ht\\endcsname{#1,html}\\input tex4ht.sty }}" ..
"\\def\\HCode{\\futurelet\\HCode\\HChar}\\def\\HChar{\\ifx\"\\HCode\\def\\HCode\"##1\"{\\Link##1}\\expandafter\\HCode\\else\\expandafter\\Link\\fi}" ..
"\\HCode ${tex4ht_sty_par}.a.b.c.\\input \"\\detokenize{${tex_file}}\"'"
local m = {}
function m.htlatex(par, latex_command)
-- latex_command can be also plain_command for Plain TeX
local command = latex_command or Make.latex_command
local devnull = " > /dev/null 2>&1"
if os.type == "windows" then
command = command:gsub("'",'')
devnull = " > nul 2>&1"
end
par.interaction = par.interaction or "batchmode"
if par.builddir~="" then
par.build_dir_arg = "--output-directory=${builddir}" % par
else
par.build_dir_arg = ""
end
if par.interaction == "batchmode" then
command = command .. devnull
end
command = command % par
log:info("LaTeX call: "..command)
os.execute(command)
return Make.testlogfile(par)
end
function m.httex(par)
local newpar = {}
for k,v in pairs(par) do newpar[k] = v end
-- change executable name from *latex to *tex
newpar.htlatex = newpar.htlatex:gsub("latex", "tex")
-- plain tex command doesn't support etex extensions
-- which are necessary for TeX4ht. just quick hack to fix this
if newpar.htlatex == "tex" then newpar.htlatex = "etex" end
return m.htlatex(newpar, Make.plain_command)
end
local function get_checksum(main_file, extensions)
-- make checksum for temporary files
local checksum = ""
local extensions = extensions or {"aux", "4tc", "xref"}
for _, ext in ipairs(extensions) do
local f = io.open(main_file .. "." .. ext, "r")
if f then
local content = f:read("*all")
f:close()
-- make checksum of the file and previous checksum
-- this way, we will detect change in any file
checksum = md5.sumhexa(checksum .. content)
end
end
return checksum
end
-- this function runs htlatex multiple times until the checksum of temporary files doesn't change
Make:add("autohtlatex", function(par)
-- get checksum of temp files before compilation
local options = get_filter_settings "autohtlatex"
local extensions = par.auto_extensions or options.auto_extensions or {"aux", "4tc", "xref"}
local max_compilations = par.max_compilations or options.max_compilations or 5
local checksum = get_checksum(par.input, extensions)
local status = m.htlatex(par)
-- stop processing on error
if status ~= 0 then
autolog:info("Stopping after first run, with status: " .. status)
return status
end
-- get checksum after compilation
local newchecksum = get_checksum(par.input, extensions)
-- this is needed to prevent possible infinite loops
local compilation_count = 1
while checksum ~= newchecksum do
-- stop processing if we reach maximum number of compilations
if compilation_count > max_compilations then
autolog:info("Stopping after " .. max_compilations .. " compilations")
return status
end
status = m.htlatex(par)
-- stop processing on error
if status ~= 0 then return status end
checksum = newchecksum
-- get checksum after compilation
newchecksum = get_checksum(par.input, extensions)
compilation_count = compilation_count + 1
end
return status
end)
return m