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
|
local M = {}
local log = logging.new "indexing"
-- Handle accented characters in files created with \usepackage[utf]{inputenc}
-- this code was originally part of https://github.com/michal-h21/iec2utf/
local enc = {}
local licrs = {}
local codepoint2utf = unicode.utf8.char
local used_encodings = {}
-- load inputenc encoding file
local function load_encfiles(f)
local file= io.open(f,"r")
local encodings = file:read("*all")
file:close()
for codepoint, licr in encodings:gmatch('DeclareUnicodeCharacter(%b{})(%b{})') do
local codepoint = codepoint2utf(tonumber(codepoint:sub(2,-2),16))
local licr= licr:sub(2,-2):gsub('@tabacckludge','')
licrs[licr] = codepoint
end
end
local function sanitize_licr(l)
return l:gsub(" (.)",function(s) if s:match("[%a]") then return " "..s else return s end end):sub(2,-2)
end
local load_enc = function(enc)
-- use default encodings if used doesn't provide one
enc = enc or {"T1","T2A","T2B","T2C","T3","T5", "LGR"}
for _,e in pairs(enc) do
local filename = e:lower() .. "enc.dfu"
-- don't process an enc file multiple times
if not used_encodings[filename] then
local dfufile = kpse.find_file(filename)
if dfufile then
load_encfiles(dfufile)
end
end
used_encodings[filename] = true
end
end
local cache = {}
local get_utf8 = function(input)
local output = input:gsub('\\IeC[%s]*(%b{})',function(iec)
-- remove \protect commands
local iec = iec:gsub("\\protect%s*", "")
local code = cache[iec] or licrs[sanitize_licr(iec)] or '\\IeC '..iec
-- print(iec, code)
cache[iec] = code
return code
end)
return output
end
-- parse the idx file produced by tex4ht
-- it replaces the document page numbers by index entry number
-- each index entry can then link to place in the HTML file where the
-- \index command had been used
local parse_idx = function(content)
-- index entry number
local current_entry = 0
-- map between index entry number and corresponding HTML file and destination
local map = {}
local buffer = {}
for line in content:gmatch("([^\n]+)") do
if line:match("^\\beforeentry") then
-- increment index entry number
current_entry = current_entry + 1
local file, dest = line:match("\\beforeentry{(.-)}{(.-)}")
map[current_entry] = {file = file, dest = dest}
elseif line:match("^\\indexentry") then
-- replace the page number with the current
-- index entry number
local result = line:gsub("{[0-9]+}", "{"..current_entry .."}")
buffer[#buffer+1] = get_utf8(result)
else
buffer[#buffer+1] = line
end
end
-- return table with page to dest map and updated idx file
return {map = map, idx = table.concat(buffer, "\n")}
end
-- replace page numbers in the ind file with hyperlinks
local fix_idx_pages = function(content, idxobj)
local buffer = {}
local entries = idxobj.map
for line in content:gmatch("([^\n]+)") do
local line = line:gsub("(%s*\\%a+.-%,)(.+)$", function(start,rest)
return start .. rest:gsub("(%d+)", function(page)
local entry = entries[tonumber(page)]
if entry then
-- construct link to the index entry
return "\\Link[" .. entry.file .."]{".. entry.dest .."}{}" .. page .."\\EndLink{}"
else
return page
end
end)
end)
buffer[#buffer+1] = line
end
return table.concat(buffer, "\n")
end
-- prepare the .idx file produced by tex4ht
-- for use with Xindy or Makeindex
local prepare_idx = function(filename)
local f = io.open(filename, "r")
if not f then return nil, "Cannot open file :".. tostring(filename) end
local content = f:read("*all")
local idx = parse_idx(content)
local idxname = os.tmpname()
local f = io.open(idxname, "w")
f:write(idx.idx)
f:close()
-- return the object with mapping between dummy page numbers
-- and link destinations in the files, and the temporary .idx file
-- these can be used for the processing with the index processor
return idx, idxname
end
-- add links to a index file
local process_index = function(indname, idx)
local f = io.open(indname, "r")
if not f then return nil, "Cannot open .ind file: " .. tostring(indname) end
local content = f:read("*all")
f:close()
local newcontent = fix_idx_pages(content, idx)
local f = io.open(indname,"w")
f:write(newcontent)
f:close()
return true
end
local prepare_tmp_idx = function(par)
par.idxfile = par.idxfile or par.input .. ".idx"
-- construct the .ind name, based on the .idx name
par.indfile = par.indfile or par.idxfile:gsub("idx$", "ind")
load_enc()
-- save hyperlinks and clean the .idx file
local idxdata, newidxfile = prepare_idx(par.idxfile)
if not idxdata then
-- if the prepare_idx function returns nil, the second reuturned value contains error msg
return nil, newidxfile
end
return newidxfile, idxdata
end
local run_indexing_command = function(command, par)
-- detect command name from the command. It will be the first word
local cmd_name = command:match("^[%a]+") or "indexing"
local xindylog = logging.new(cmd_name)
local newidxfile, idxdata = prepare_tmp_idx(par)
if not newidxfile then
-- the idxdata will contain error message in the case of error
xindylog:warning(idxdata)
return false
end
par.newidxfile = newidxfile
xindylog:debug("Prepared temporary idx file: ", newidxfile)
-- prepare modules
local xindy_call = command % par
xindylog:info(xindy_call)
local status = mkutils.execute(xindy_call)
-- insert correct links to the index
local status, msg = process_index(par.indfile, idxdata)
if not status then xindylog:warning(msg) end
-- remove the temporary idx file
os.remove(newidxfile)
end
M.get_utf8 = get_utf8
M.load_enc = load_enc
M.parse_idx = parse_idx
M.fix_idx_pages = fix_idx_pages
M.prepare_idx = prepare_idx
M.process_index = process_index
M.prepare_tmp_idx = prepare_tmp_idx
M.run_indexing_command = run_indexing_command
return M
|