| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- ########################################################################
- ##
- ## 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("\"", """)
- 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("\"", """))
- 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("\"", """))
- 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("\"", """))
- 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("\"", """))
- 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("\"", """))
- 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!")
|