historical/toontown-just-works.git/build/nirai/panda3d/makepanda/makechm.py
2024-01-16 11:20:27 -06:00

281 lines
12 KiB
Python

########################################################################
##
## Win32 Usage: makepanda\makechm.bat
## Linux Usage: makepanda/makechm.py
##
## To use this script, you will need to have hhc.exe on your system.
## For verbose output, run with -v or --verbose option.
## To keep the temporary .hhc, .hhk, .hhp, .chw files use -k or --keep.
##
## You can also import this file as a python module. You will then have
## access to three functions: makeCHM, makeManualCHM, makeReferenceCHM.
## This is how you call them:
## makeCHM(outputfile, dirname, title)
## where outputfile is the filename where the .chm file will be written,
## and dirname is the directory containing the html files to include.
## Title will be the title of the CHM file.
## The functions makeManualCHM and makeReferenceCHM work exactly the
## same, except that they work with a structure resembling that of the
## Panda3D manual and reference, respectively.
## Note: outputfile should not contain spaces.
##
########################################################################
__all__ = ["makeCHM", "makeManualCHM", "makeReferenceCHM"]
import os, re
from sys import exit
import xml.dom.minidom
from xml.dom.minidom import Node
VERBOSE = False
KEEPTEMP = False
if __name__ == "__main__":
from sys import argv
VERBOSE = ("-v" in argv) or ("-vk" in argv) or ("-kv" in argv) or ("--verbose" in argv)
KEEPTEMP = ("-k" in argv) or ("-kv" in argv) or ("-vk" in argv) or ("--keep" in argv)
OPTIONBLOCK = """
Binary TOC=Yes
Compatibility=1.1 or later
Compiled file=%s
Contents file=%s.hhc
Default Font=Arial,10,0
Default topic=%s
Display compile progress=VERBOSE
Full-text search=Yes
Index file=%s.hhk
Language=0x409 English (United States)
Title=%s""".replace("VERBOSE", VERBOSE and "Yes" or "No")
HTMLBLOCK = """<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<meta name="generator" content="Panda3D - makechm.py">
</head>
<body>
<object type="text/site properties">
<param name="Window Styles" value="0x800025">
<param name="ImageType" value="Folder">
<param name="Font" value="Arial,8,0">
</object>
<ul>\n"""
REFERENCEITEMS = [
("index.html", "Main Page"),
("methods.html", "Methods"),
("functions.html", "Global Functions"),
("classes.html", "Classes"),
]
def urldecode(url):
regex = re.compile("%([0-9a-hA-H][0-9a-hA-H])", re.M)
return regex.sub(lambda x: chr(int(x.group(1), 16)), url)
def ireplace(string, target, replacement):
"""Case-insensitive replace."""
index = string.lower().find(target.lower())
if index >= 0:
result = string[:index] + replacement + string[index + len(target):]
return result
else:
return string
def parseAnchor(node):
"""Parses an XML minidom node representing an anchor and returns a tuple
containing the href and the content of the link."""
assert node.nodeType == Node.ELEMENT_NODE
assert node.localName == "a"
href = ""
title = ""
for localName, a in node.attributes.items():
if localName.lower() == "href":
href = a
for e in node.childNodes:
if e.nodeType == Node.TEXT_NODE:
title += e.data
return href, title
def parseManualTree(node):
"""Parses a tree of the manual Main_Page and returns it through a list containing tuples:
[(title, href, [(title, href, [...]), ...]), ...]"""
if node.nodeType != Node.ELEMENT_NODE: return []
result = []
lastadded = None
for e in node.childNodes:
if e.nodeType == Node.ELEMENT_NODE:
if e.localName == "ol":
assert lastadded != None
for i in xrange(len(result)):
if result[i][:2] == lastadded:
result[i] = lastadded + (parseManualTree(e),)
elif e.localName == "a":
href, title = parseAnchor(e)
lastadded = title, href
result.append((title, href, None))
return result
def parseManualTOC(filename):
"""Reads the manual's Main_Page file and returns a list of all the trees found."""
filename = open(filename)
text = filename.read()
filename.close()
text = text.split("<h2>Table of Contents</h2>")[1].split("</div>")[0]
text = "<root>" + text.replace("<li>", "") + "</root>"
text = re.sub(re.compile("<!--([^>]+)>"), "", text)
result = []
for e in xml.dom.minidom.parseString(text).childNodes[0].childNodes:
if e.nodeType == Node.ELEMENT_NODE:
result.append(parseManualTree(e))
return result
def treeToHTML(tree, dirname, indent = ""):
"""Converts a tree into HTML code suitable for .hhc or .hhk files. The tree should be like:
[(title, href, [(title, href, [...]), ...]), ...]"""
html = ""
for title, href, sub in tree:
html += indent + "<li><object type=\"text/sitemap\">\n"
html += indent + " <param name=\"Name\" value=\"%s\">\n" % title.replace("CXX", "C++").replace("\"", "&quot;")
html += indent + " <param name=\"Local\" value=\"%s\">\n" % urldecode(os.path.join(dirname, href))
html += indent + "</object>\n"
if sub != None:
html += indent + "<ul>\n"
html += treeToHTML(sub, dirname, indent + " ")
html += indent + "</ul>\n"
return html
def makeCHM(outputfile, dirname, title, special = None):
"""Creates a CHM file based on a directory of HTML files. See the top of this file for more info."""
assert special == None or special in ["manual", "reference"]
reference = (special == "reference")
manual = (special == "manual")
base = ireplace(outputfile, ".chm", "")
if os.path.isfile(base + ".chm"): os.remove(base + ".chm")
# Create the hhp file
hhp = open(base + ".hhp", "w")
hhp.write("[OPTIONS]\n")
hhp.write(OPTIONBLOCK % (base + ".chm", base, urldecode(os.path.join(dirname, "index.html")), base, title))
hhp.write("\n[FILES]\n")
# Create the TOC file and Index file
hhk = open(base + ".hhk", "w")
hhc = open(base + ".hhc", "w")
hhk.write(HTMLBLOCK)
hhc.write(HTMLBLOCK)
# The manual should be treated as a special case.
if manual:
hhc.write(" <li><object type=\"text/sitemap\">\n")
hhc.write(" <param name=\"Name\" value=\"Main Page\">\n")
hhc.write(" <param name=\"Local\" value=\"%s\">\n" % urldecode(os.path.join(dirname, "index.html")))
hhc.write(" </object>\n")
for item in parseManualTOC(dirname + "/index.html"):
hhc.write(treeToHTML(item, dirname, " "))
for i in os.listdir(dirname):
hhp.write(os.path.join(dirname, i) + "\n")
if i != "index.html":
hhk.write(" <li><object type=\"text/sitemap\">\n")
hhk.write(" <param name=\"Name\" value=\"%s\">\n" % ireplace(urldecode(i).replace(".1", "").replace("_", " ").replace("CXX", "C++"), ".html", "").replace("\"", "&quot;"))
hhk.write(" <param name=\"Local\" value=\"%s\">\n" % urldecode(os.path.join(dirname, i)))
hhk.write(" </object>\n")
else:
idt = " "
# If we are writing out the reference, write some extra stuff.
if reference:
idt = " "
for i, desc in REFERENCEITEMS:
hhk.write(" <li><object type=\"text/sitemap\">\n")
hhk.write(" <param name=\"Name\" value=\"%s\">\n" % desc.replace("\"", "&quot;"))
hhk.write(" <param name=\"Local\" value=\"%s\">\n" % urldecode(os.path.join(dirname, i)))
hhk.write(" </object>\n")
hhc.write(" <li><object type=\"text/sitemap\">\n")
hhc.write(" <param name=\"Name\" value=\"%s\">\n" % desc.replace("\"", "&quot;"))
hhc.write(" <param name=\"Local\" value=\"%s\">\n" % urldecode(os.path.join(dirname, i)))
hhc.write(" </object>\n")
hhc.write(" <ul>\n")
# Loop through the directories and write out relevant data.
for i in os.listdir(dirname):
hhp.write(os.path.join(dirname, i) + "\n")
if i != "index.html" and ((not reference) or (not i in ["classes.html", "methods.html", "functions.html"])):
hhk.write(" <li><object type=\"text/sitemap\">\n")
hhk.write(" <param name=\"Name\" value=\"%s\">\n" % ireplace(urldecode(i).replace(".1", ""), ".html", "").replace("\"", "&quot;"))
hhk.write(" <param name=\"Local\" value=\"%s\">\n" % urldecode(os.path.join(dirname, i)))
hhk.write(" </object>\n")
hhc.write(idt + "<li><object type=\"text/sitemap\">\n")
hhc.write(idt + " <param name=\"Name\" value=\"%s\">\n" % ireplace(urldecode(i).replace(".1", ""), ".html", "").replace("\"", "&quot;"))
hhc.write(idt + " <param name=\"Local\" value=\"%s\">\n" % urldecode(os.path.join(dirname, i)))
hhc.write(idt + "</object>\n")
# Close the files.
if reference: hhc.write(" </ul>\n")
hhk.write(" </ul>\n </body>\n</html>")
hhc.write(" </ul>\n </body>\n</html>")
hhk.close()
hhc.close()
hhp.close()
# Now, execute the command to compile the files.
if "PROGRAMFILES" in os.environ and os.path.isdir("%s\\HTML Help Workshop" % os.environ["PROGRAMFILES"]):
cmd = "\"%s\\HTML Help Workshop\\hhc.exe\" %s.hhp" % (os.environ["PROGRAMFILES"], base)
elif os.path.isdir("C:\Program Files\HTML Help Workshop"):
cmd = "\"C:\\Program Files\\HTML Help Workshop\\hhc.exe\" %s.hhp" % base
else:
cmd = "hhc \"%s.hhp\"" % base
print cmd
os.system(cmd)
if not KEEPTEMP:
if os.path.isfile("%s.hhp" % base): os.remove("%s.hhp" % base)
if os.path.isfile("%s.hhc" % base): os.remove("%s.hhc" % base)
if os.path.isfile("%s.hhk" % base): os.remove("%s.hhk" % base)
if os.path.isfile("%s.chw" % base): os.remove("%s.chw" % base)
if not os.path.isfile(base + ".chm"):
print "An error has occurred!"
if __name__ == "__main__":
exit(1)
else:
return False
if __name__ != "__main__":
return True
def makeManualCHM(outputfile, dirname, title):
"""Same as makeCHM, but suitable for converting the Panda3D manual."""
return makeCHM(outputfile, dirname, title, special = "manual")
def makeReferenceCHM(outputfile, dirname, title):
"""Same as makeCHM, but converts a structure resembling that of the Panda3D reference."""
return makeCHM(outputfile, dirname, title, special = "reference")
if __name__ == "__main__":
# Extract a version number, if we have one.
VERSION = None
try:
f = file("built/include/pandaVersion.h","r")
pattern = re.compile('^\s*[#]\s*define\s+PANDA_VERSION_STR\s+["]([0-9.]+)["]')
for line in f:
match = pattern.match(line,0)
if (match):
VERSION = match.group(1)
break
f.close()
except:
# If not, we don't care at all.
pass
# Now, make CHM's for both the manual and reference, if we have them.
for lang in ["python", "cxx"]:
if not os.path.isdir("manual-" + lang):
print "No directory named 'manual-%s' found" % lang
else:
print "Making CHM file for manual-%s..." % lang
if VERSION == None:
makeManualCHM("manual-%s.chm" % lang, "manual-" + lang, "Panda3D Manual")
else:
makeManualCHM("manual-%s-%s.chm" % (VERSION, lang), "manual-" + lang, "Panda3D %s Manual" % VERSION)
if not os.path.isdir("reference-" + lang):
print "No directory named 'reference-%s' found" % lang
else:
print "Making CHM file for reference-%s..." % lang
if VERSION == None:
makeReferenceCHM("reference-%s.chm" % lang, "reference-" + lang, "Panda3D Reference")
else:
makeReferenceCHM("reference-%s-%s.chm" % (VERSION, lang), "reference-" + lang, "Panda3D %s Reference" % VERSION)
print "Done!"