#! lua-5.0.exe
-- Create an HTML table of content (TOC) from an HTML file. Made mostly for the Lua manual...
--
-- Take two parameters: the file to process as input, the resulting file as output.
--
-- The program extracts the hierarchical titles ( tags) and store them with their level.
-- It will then output the list of titles in a hierarchical HTML list.
--
-- Actually, it will also take the latest named link before each title, so the above list
-- can be used to jump to the chosen level.
--
-- Note that the input HTML file must follow this structure for the output to be accurate.
-- I had to make minor, invisible edits to the original Lua manuals,
-- to create anchors or to move them before the title.
--
-- The result must be inserted by hand in the HTML file. If used in a separated page,
-- you must add the destination page name to the links.
--
-- by Philippe Lhoste http://Phi.Lho.free.fr
-- v. 1.2 -- 2004/04/22 -- Conversion to Lua 5.0
-- v. 1.1 -- 2003/05/20 -- Output of TOC
-- v. 1.0 -- 2002/07/26 -- Initial code, extraction of data
filenameIn = (arg and arg[1]) or "-" -- If absent, use standard input
filenameOut = (arg and arg[2]) or "-" -- If absent, use standard output
tocList = {}
--lineNumber = 0
refNumber = 0
prevRef = ""
prevLevel = 0
-- Extract useful information from the given line.
function ProcessLine(line)
if line == nil then
return nil
end
-- lineNumber = lineNumber + 1
-- Remove tags other than those we are looking for.
-- Replace the interesting tags by control chars, remove all other tags,
-- and restore the control chars to the corresponding tags.
line = string.gsub(line, "<[Hh]", "\1")
line = string.gsub(line, "[Hh]", "\2")
line = string.gsub(line, "<[Aa] ", "\3")
line = string.gsub(line, "[Aa]>", "\4")
line = string.gsub(line, "<[^>]->", "")
line = string.gsub(line, "\1", "")
local startRef, endRef, level, ref, title
local tocData = {}
-- Capture latest referenced string (by a tag) of the line
endRef = 0
repeat
startRef, endRef, ref = string.find(line, [[.*]], endRef + 1)
if ref ~= nil then
prevRef = ref
end
until startRef == nil
-- Remove the anchors
line = string.gsub(line, "]+>", "")
line = string.gsub(line, "", "")
-- Search if the line has a title ( tag, up to level 4)
_, _, level, title = string.find(line, [[<[Hh]([1234])>([^<]*)[Hh][1234]>]], 1)
if level ~= nil then
-- No need to loop to search another title in the line,
-- unless the HTML is very sloppy...
refNumber = refNumber + 1
tocData =
{
level = level,
ref = prevRef,
title = title
}
tocList[refNumber] = tocData
end
return true
end
-- Output an element of table of content.
function OutputTOC(el)
local level, nLevel
level = el.level
nLevel = tonumber(level)
while nLevel > prevLevel do
io.write"\n"
nLevel = nLevel - 1
end
while nLevel < prevLevel do
io.write"
\n"
nLevel = nLevel + 1
end
prevLevel = tonumber(level)
io.write([[]] .. el.title .. [[]] .. "\n")
end
-- Process the input file
function ProcessFile()
local fI, fO
if filenameIn ~= '-' then
fI = io.open(filenameIn, "r")
if fI == nil then
return false, "open r " .. filenameIn
end
else
fI = io.stdin
end
if filenameOut ~= '-' then
fO = io.open(filenameOut, "w")
if fO == nil then
return false, "open w " .. filenameOut
end
io.output(fO)
end
-- Loop on the lines and add any tag to the tocList table
-- Note that these titles must be on the same line, no on one line and the title on the next...
for line in fI:lines() do
ProcessLine(line)
end
-- Build the table of content
io.write([[
0 - Contents
]])
for i, elements in ipairs(tocList) do
OutputTOC(elements)
end
while prevLevel > 0 do
io.write"\n"
prevLevel = prevLevel - 1
end
io.write"\n
\n"
if filenameIn ~= '-' then
fI:close()
end
if filenameOut ~= '-' then
io.output()
fO:close()
end
return true, nil
end
result, op = ProcessFile()
if not result then
io.stderr:write("Error on operation : " .. (op or 'nil') .. '\n')
else
io.stderr:write("Done !\n")
end