source: orange/install-scripts/doc/htmlparser.py @ 3993:146f3d0a141b

Revision 3993:146f3d0a141b, 12.2 KB checked in by tomazc <tomaz.curk@…>, 6 years ago (diff)

need this before Qt4 become trunk (main branch)

Line 
1from operator import add
2from operator import add
3import re, sys, os, sets
4
5class TOCEntry:
6    def __init__(self, title, url):
7        self.title = title
8        self.url = url
9        self.subentries = []
10
11def copydir(src, target):
12    if os.path.isdir(src):
13        tryMk(target)
14        for f in os.listdir(src):
15            copydir(src+"/"+f, target+"/"+f)
16    else:
17        file(target, "wb").write(file(src, "rb").read())
18
19
20def tryMk(dir):
21    try:
22        os.mkdir(dir)
23    except:
24        pass
25
26
27class IndexStore:
28    def __init__(self, aname, entries = None):
29        self.name = aname
30        if entries:
31            self.entries = entries[:]
32        else:
33            self.entries = []
34        self.subentries = {}
35
36
37htags = [tg % i for tg in ["<h%i>", "<h%i "] for i in range(5)]
38
39def findLastTag(outp, tag, start = None):
40    ri = -1
41    if tag == "h":
42        tags = htags
43    else:
44        tags = "<%s>" % tag, "<%s " % tag
45       
46    for l in range(start or len(outp)-1, -1, -1):
47        ri = max([outp[l].lower().rfind(tg) for tg in tags])
48        if ri > -1:
49            return l, ri
50
51    return -1, -1       
52       
53   
54def addIndex(indexStoreList, name, title=None, filename=None, counter = None):
55    cateS = indexStoreList.get(name.lower(), None)
56    if not cateS:
57        cateS = IndexStore(name)
58        indexStoreList[name.lower()] = cateS
59   
60    if title:
61        cateS.entries.append((title, filename, counter))
62
63    return cateS
64
65
66def addAName(outp, aname, lasttag=None):
67    if not lasttag or lasttag == "here":
68        ri = -1
69    elif lasttag == "head":
70        l, ri = findLastTag(outp, "h")
71    elif lasttag == "phead":
72        l, ri = findLastTag(outp, "p")
73        lh, rih = findLastTag(outp, "h")
74        if rih > -1:
75            lp2, rip2 = findLastTag(outp, "p", l-1)
76            if ri == -1 or lp2 < lh:
77                l, ri = lh, rih
78    else:
79        l, ri = findLastTag(outp, lasttag)
80
81    if ri > -1:
82        outp[l] = outp[l][:ri] + aname + outp[l][ri:]
83    else:
84        outp.append(aname)
85
86       
87def findIndices(filename, title):
88    page = open(filename).read()
89    lowpage = page.lower()
90    outp = []
91    lastout = 0
92    counter = 0
93    lidx = 0
94    H2Entry = None
95    re_idx = re.compile(r'<index(?P<options>\s+[^>]+)?>', re.IGNORECASE + re.DOTALL)
96    re_h2 = re.compile(r'<h2(\s+toc\s*=\s*(?P<toc>("[^"]*"|0)))?>', re.IGNORECASE + re.DOTALL)
97    re_h3 = re.compile(r'<h3(\s+toc\s*=\s*(?P<toc>("[^"]*"|0)))?>', re.IGNORECASE + re.DOTALL)
98
99    re_opt_name = re.compile(r'\s*name\s*=\s*(?P<name>("[^"]*"|0))\s*', re.IGNORECASE + re.DOTALL)
100    re_opt_pos = re.compile(r'\s*pos\s*=\s*(?P<pos>("[^"]*"))\s*', re.IGNORECASE + re.DOTALL)
101
102    while 1:
103        idxm = re_idx.search(lowpage, lidx)
104        indx = idxm and idxm.start() or -1
105
106        if processHeaders:
107            h2m = re_h2.search(lowpage, lidx)
108            h2 = h2m and h2m.start() or -1
109           
110            h3m = re_h3.search(lowpage, lidx)
111            h3 = h3m and h3m.start() or -1
112        else:
113            h2 = h3 = -1
114
115        indices = filter(lambda x:x>=0, (indx, h2, h3))
116        if not indices:
117            break
118       
119        idx = min(indices)
120        if idx == indx:
121            optionsg = idxm.group("options")
122            posg = "phead"
123            name = ""
124            if optionsg:
125                mg = re_opt_name.match(optionsg)
126                if mg:
127                    nameg = mg.group("name")
128                    begopt = idxm.span("options")[0]
129                    b, e = mg.span("name")
130                    name = page[begopt+b+1:begopt+e-1]
131               
132                mg = re_opt_pos.match(optionsg)
133                if mg:
134                    posg = mg.group("posg")
135                    if posg == "here":
136                        posg = None
137                   
138            eidx = lowpage.find("</index>", idx)
139           
140            nextidxm = re_idx.search(lowpage, indx+5)
141            missingendtag = nextidxm and nextidxm.start() < eidx
142
143            if not name:
144                if missingendtag or eidx == -1:
145                    print "Warning: missing end of index in '%s'" % filename
146                    lidx = idxm.end()
147                    continue
148                if eidx - idxm.end() > 100:
149                    print "Warning: suspiciously long index in '%s'" % filename
150                    lidx = indxm.end()
151                    continue
152                name = page[idxm.end():eidx]
153
154            name = name.replace("\n", " ")
155            outp.append(page[lastout:idx])
156            addAName(outp, '<a name="HH%i">' % counter, posg)
157
158            if eidx > -1 and (not nextidxm or eidx < nextidxm.start()):
159                outp.append(page[idxm.end():eidx])
160                lastout = lidx = eidx+8
161            else:
162                lastout = lidx = idxm.end()
163
164            if "+" in name:
165                catename = name.split("+")
166                if len(catename) == 2:
167                    cate, name = catename
168                    cateS = addIndex(index, cate)
169                    addIndex(index, name, title, filename, counter)
170                    addIndex(cateS.subentries, name, title, filename, counter)
171                else:
172                    addIndex(index, name, title, filename, counter)
173            elif "/" in name:
174                cate, name = name.split("/")
175                cateS = addIndex(index, cate)
176                addIndex(cateS.subentries, name, title, filename, counter)
177            else:
178                addIndex(index, name, title, filename, counter)
179            counter += 1
180
181        else:
182            ht = idx==h2 and "h2" or "h3"
183            mo = idx==h2 and h2m or h3m
184
185            skip = 0
186            toc = mo.group("toc")
187            if toc:
188                if toc == "0":
189                    skip = 1
190                else:
191                    b, e = mo.span("toc")
192                    name = page[b+1:e-1]
193            else:
194                eidx = lowpage.find("</%s>" % ht, idx)
195                if eidx == -1:
196                    print "Warning: missing end of %s in '%s'" % (ht, filename)
197                    break
198                if eidx - idx > 100:
199                    print "Warning: suspiciously long %s in '%s'" % (ht, filename)
200                    lidx = idx + 4
201                    continue
202
203                name = page[idx+4:eidx]
204           
205            outp.append(page[lastout:idx])
206            if not skip:
207                outp.append('<a name="HH%i">' % counter)
208            outp.append("<%s>" % ht)
209            lastout = lidx = mo.end()
210
211            if not skip:
212                newEntry = TOCEntry(name, "%s#HH%i" % (filename, counter))
213                if ht == "h2":
214                    TOCStack[-1].subentries.append(newEntry)
215                    H2Entry = newEntry
216                else:
217                    (H2Entry or TOCStack[-1]).subentries.append(newEntry)
218                counter += 1
219
220    outp.append(page[lastout:])
221
222    return reduce(add, outp)   
223
224
225def writeIndexHH_store(hhk, indexStoreList):
226    hhk.write("\n<UL>")
227    for indexStore in indexStoreList.values():
228        if indexStore.entries or indexStore.subentries:
229            hhk.write(hhkentry % indexStore.name)
230            if indexStore.entries:
231                for entry in indexStore.entries:
232                    hhk.write(hhksubentry % entry)
233            else:
234                for substore in indexStore.subentries.values():
235                    for subentry in substore.entries:
236                        hhk.write(hhksubentry % subentry)
237            hhk.write(hhkendentry)
238            if indexStore.subentries:
239                writeIndexHH_store(hhk, indexStore.subentries)
240    hhk.write("\n</UL>")
241   
242def writeIndexHH(outputstub):
243    hhk = file("%s.hhk" % outputstub, "w")
244    hhk.write(hhkhead)
245    writeIndexHH_store(hhk, index)
246    hhk.close()
247
248
249def writeTocHHRec(hhc, node, l=0):
250    spaces = " "*(l*4)
251    hhc.write(hhcentry % {"spc": spaces, "name": node.title, "file": node.url})
252    if node.subentries:
253        hhc.write(spaces + "<UL>\n")
254        for s in node.subentries:
255            writeTocHHRec(hhc, s, l+1)
256        hhc.write(spaces + "</UL>\n\n")
257   
258def writeTocHH(outputstub):
259    hhc = file("%s.hhc" % outputstub, "w")
260    hhc.write(hhchead)
261    for s in TOCRoot.subentries:
262        writeTocHHRec(hhc, s, 0)
263    hhc.write(hhcfoot)
264
265   
266def writeHHP(outputstub, title):
267    hhp = file("%s.hhp" % outputstub, "w")
268    hhp.write(hhphead % {"stub": outputstub, "title": title})
269    hhp.write("[FILES]\n" + "\n".join(files))
270
271
272
273def underspace(s):
274    return s.replace("_", " ")
275
276def main():
277    global processHeaders, outputstub, TOCStack, title, files, index, TOCRoot, TOCStack
278   
279    bookname = ""
280    dir = outputstub = underspace(sys.argv[1])
281   
282    processHeaders = outputstub != "catalog"
283
284    files = sets.Set()
285    files.add(dir+"/style.css")
286
287    index = {}
288    TOCRoot = TOCEntry("", dir + "/default.htm")
289    TOCStack = [TOCRoot]
290
291    re_hrefomod = re.compile(r'href\s*=\s*"\.\.[/\\](?P<module>(ofb)|(reference)|(modules))[/\\](?P<rest>[^"]+)"', re.IGNORECASE + re.DOTALL)
292   
293    for fle in file(dir+"/hhstructure.txt"):
294        fle = fle.rstrip(" \n\r")
295        if not fle:
296            continue
297       
298        level = 0
299        while fle[level] == "\t":
300            level += 1
301
302        arrow = fle.find("--->")
303        title = fle[:arrow].strip()
304        fn = fle[arrow+4:].strip()
305        if not TOCRoot.title:
306            TOCRoot.title = title
307           
308
309        filename = dir+"/"+fn
310
311        newentry = TOCEntry(title, filename)
312
313        if level > len(TOCStack)-1:
314            print "Error in '%s/hhstructure.txt' (invalid identation in line '%s')" % (dir, fle.strip())
315            sys.exit()
316        TOCStack = TOCStack[:level+1]
317        TOCStack[-1].subentries.append(newentry)
318        TOCStack.append(newentry)
319
320        if not filename in files:
321            files.add(filename)
322
323            page = findIndices(filename, title)
324            page = re_hrefomod.sub(r'href="ms-its:\g<module>.chm::/\g<module>/\g<rest>"', page)
325            page = page.replace("../style.css", "ms-its:"+outputstub+".chm::/"+dir+"/style.css")
326            page = page.replace('Up: <a href="../default.htm">Orange Documentation</a>', '')
327
328            file(filename, "w").write(page)   
329
330
331    writeIndexHH(outputstub)
332    writeTocHH(outputstub)
333    writeHHP(outputstub, TOCRoot.title)
334
335    anoun = False
336    cfiles = sets.Set([f.lower() for f in files] + [dir+"/path.htm", dir+"/links.htm"])
337    dir = dir.lower()
338    if processHeaders:
339        for fn in os.listdir(dir):
340            if fn.lower()[-4:] == ".htm" and dir+"/"+fn.lower() not in cfiles:
341                if not anoun:
342                    print "\nFiles that are not referenced in hhstructure.txt:"
343                    anoun = True
344                print "  "+fn
345    else:
346        for dr in os.listdir(dir):
347            adr = (dir+"/"+dr).lower()
348            if os.path.isdir(adr):
349                for fn in os.listdir(adr):
350                    if fn.lower()[-4:] == ".htm" and adr+"/"+fn.lower() not in cfiles:
351                        if not anoun:
352                            print "\nFiles that are not used (possibly due to name mismatches):"
353                            anoun = True
354                        print "  "+fn
355
356
357hhphead = """
358[OPTIONS]
359Binary Index=Yes
360Compiled file=../%(stub)s.chm
361Contents file=%(stub)s.hhc
362Default topic=%(stub)s/default.htm
363Display compile progress=No
364Full text search stop list file=../stop.stp
365Full-text search=Yes
366Index file=%(stub)s.hhk
367Language=0x409
368Title=%(title)s
369"""
370
371hhchead = """
372<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
373<HTML>
374<HEAD>
375<meta name="GENERATOR" content="Microsoft&reg; HTML Help Workshop 4.1">
376<!-- Sitemap 1.0 -->
377</HEAD><BODY>
378<OBJECT type="text/site properties">
379    <param name="Window Styles" value="0x801227">
380    <param name="ImageType" value="Folder">
381</OBJECT>
382<UL>
383"""
384
385hhcentry = """%(spc)s<LI><OBJECT type="text/sitemap">
386%(spc)s    <param name="Name" value="%(name)s">
387%(spc)s    <param name="Local" value="%(file)s">
388%(spc)s</OBJECT>
389"""
390
391hhcfoot = "</UL>"
392
393hhkhead = """
394<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
395<HTML>
396<HEAD>
397<meta name="GENERATOR" content="Microsoft&reg; HTML Help Workshop 4.1">
398<!-- Sitemap 1.0 -->
399</HEAD><BODY>
400"""
401
402hhkentry = """<LI><OBJECT type="text/sitemap">
403    <param name="Name" value="%s">"""
404
405hhksubentry = """
406    <param name="Name" value="%s">
407    <param name="Local" value="%s#HH%i">
408"""
409
410hhkendentry = "\n</OBJECT>\n"
411
412main()
Note: See TracBrowser for help on using the repository browser.