Bladeren bron

Added tools for generating CHM files

rdb 17 jaren geleden
bovenliggende
commit
8af65bfe45
2 gewijzigde bestanden met toevoegingen van 303 en 0 verwijderingen
  1. 26 0
      doc/makepanda/makechm.bat
  2. 277 0
      doc/makepanda/makechm.py

+ 26 - 0
doc/makepanda/makechm.bat

@@ -0,0 +1,26 @@
+@echo off
+
+REM
+REM Verify that we can find the 'makechm' python script
+REM and the python interpreter.  If we can find both, then
+REM run 'makechm'.
+REM
+
+if not exist makepanda\makechm.py goto :missing1
+if not exist thirdparty\win-python\python.exe goto :missing2
+thirdparty\win-python\python.exe makepanda\makechm.py %*
+goto done
+
+:missing1
+  echo You need to change directory to the root of the panda source tree
+  echo before invoking makechm.
+  goto done
+
+:missing2
+  echo You seem to be missing the 'thirdparty' directory.  You probably checked
+  echo the source code out from sourceforge.  The sourceforge repository is
+  echo missing the 'thirdparty' directory.  You will need to supplement the
+  echo code by downloading the 'thirdparty' directory from panda3d.etc.cmu.edu
+  goto done
+
+:done

+ 277 - 0
doc/makepanda/makechm.py

@@ -0,0 +1,277 @@
+########################################################################
+##
+## 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("</td>")[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("manual/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 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.
+    if not os.path.isdir("manual"):
+        print "No directory named 'manual' found"
+    else:
+        print "Making CHM file for manual..."
+        if VERSION == None:
+            makeManualCHM("panda3d-manual.chm", "manual", "Panda3D Manual")
+        else:
+            makeManualCHM("panda3d-%s-manual.chm" % VERSION, "manual", "Panda3D %s Manual" % VERSION)
+    
+    if not os.path.isdir("reference"):
+        print "No directory named 'reference' found"
+    else:
+        print "Making CHM file for API reference..."
+        if VERSION == None:
+            makeReferenceCHM("panda3d-reference.chm", "reference", "Panda3D Reference")
+        else:
+            makeReferenceCHM("panda3d-%s-reference.chm" % VERSION, "reference", "Panda3D %s Reference" % VERSION)
+    
+    print "Done!"