]*\)>')
-ampprog = regex.compile('&')
-aprog = regex.compile('^A\. +')
-qprog = regex.compile('>Q\. +')
-qrefprog = regex.compile('question +\([0-9]\.[0-9]+\)')
-versionprog = regex.compile('^Version: ')
-emailprog = regex.compile('<\([^>@:]+@[^>@:]+\)>')
+# --------------------------------------------------------- regular expressions
+orditemprog = regex.compile(' ?([1-9][0-9]*\.)+ +')
+itemprog = regex.compile(' ? ?[-*] +')
+headingprog = regex.compile('([1-9][0-9]*\.)+ +')
+prefmtprog = regex.compile(' ')
+blankprog = regex.compile('^[ \t\r\n]$')
+questionprog = regex.compile(' *Q\. +')
+answerprog = regex.compile(' *A\. +')
+sentprog = regex.compile('(([^.:;?!(]|[.:;?!][^ \t\r\n])+[.:;?!]?)')
-def main():
- print 'Reading lines...'
- lines = open(FAQ, 'r').readlines()
- print 'Renumbering in memory...'
- oldlines = lines[:]
- after_blank = 1
- chapter = 0
- question = 0
- chapters = ['']
- questions = ['']
- for i in range(len(lines)):
- line = lines[i]
- if after_blank:
- n = chapterprog.match(line)
- if n >= 0:
- chapter = chapter + 1
- if chapter != 1:
- questions.append('\n')
- question = 0
- lines[i] = '' + line[n:-1] + '
\n'
- chapters.append('- ' + line[n:])
- questions.append('
- ' + line[n:])
- questions.append('
\n')
- for i in range(len(lines)):
- line = lines[i]
- if regex.match(
- '^This FAQ is divided in the following chapters',
- line) >= 0:
- i = i+1
- while 1:
- line = lines[i]
- if indentedorblankprog.match(line) < 0:
- break
- del lines[i]
- lines[i:i] = chapters
- break
- else:
- print '*** Can\'t find header for list of chapters'
- print '*** Chapters found:'
- for line in chapters: print line,
- print 'Inserting list of questions...'
- questions.append('
\n')
- for i in range(len(lines)):
- line = lines[i]
- if regex.match('^Here.s an overview of the questions',
- line) >= 0:
- i = i+1
- while 1:
- line = lines[i]
- if indentedorblankprog.match(line) < 0:
- break
- del lines[i]
- lines[i:i] = questions
- break
- else:
- print '*** Can\'t find header for list of questions'
- print '*** Questions found:'
- for line in questions: print line,
- # final cleanup
- print "Final cleanup..."
- doingpre = 0
- for i in range(len(lines)):
- # set lines indented by >= 8 spaces using PRE
- # blank lines either terminate PRE or separate paragraphs
- n = eightblanksprog.match(lines[i])
- if n < 0: n = mailheaderprog.match(lines[i])
- if n >= 0:
- if versionprog.match(lines[i]) > 0:
- version = string.split(lines[i])[1]
- if doingpre == 0:
- lines[i] = '\n' + lines[i]
- doingpre = 1
- continue
- n = blankprog.match(lines[i])
- if n >= 0:
- # print '*** ', lines[i-1], doingpre
- if doingpre == 1:
- lines[i] = '
\n'
- doingpre = 0
- else:
- lines[i] = '
\n'
- continue
+mailhdrprog = regex.compile('^(Subject|Newsgroups|Followup-To|From|Reply-To'
+ '|Approved|Archive-Name|Version|Last-Modified): +', regex.casefold)
+urlprog = regex.compile('<URL:([^&]+)>')
+addrprog = regex.compile('<([^>@:]+@[^&@:]+)>')
+qrefprog = regex.compile('question +([1-9](\.[0-9]+)*)')
+srefprog = regex.compile('section +([1-9][0-9]*)')
+entityprog = regex.compile('[&<>]')
- # & -> &
- n = ampprog.search(lines[i])
- if n >= 0:
- lines[i] = regsub.gsub(ampprog, '&', lines[i])
- # no continue - there might be other changes to the line...
+# ------------------------------------------------------------ global variables
+body = []
+ollev = ullev = 0
+element = content = secnum = version = ''
- # zap all the 'Q.' and 'A.' leaders - what happened to the
- # last couple?
- n = qprog.search(lines[i])
- if n >= 0:
- lines[i] = regsub.sub(qprog, '>', lines[i])
- # no continue - there might be other changes to the line...
+# ----------------------------------------------------- for making nested lists
+def dnol():
+ global body, ollev
+ ollev = ollev + 1
+ if body[-1] == '': del body[-1]
+ body.append('
')
- n = aprog.search(lines[i])
- if n >= 0:
- lines[i] = regsub.sub(aprog, '', lines[i])
- # no continue - there might be other changes to the line...
+def upol():
+ global body, ollev
+ ollev = ollev - 1
+ body.append(ollev and '
' or '')
- # patch up hard refs to questions
- n = qrefprog.search(lines[i])
- if n >= 0:
- lines[i] = regsub.sub(qrefprog,
- 'question \\1', lines[i])
- # no continue - there might be other changes to the line...
+# --------------------------------- output one element and convert its contents
+def spew(clearol=0, clearul=0):
+ global content, body, ollev, ullev
- # make into actual links
- n = urlprog.search(lines[i])
- if n >= 0:
- lines[i] = regsub.gsub(urlprog, '\\1', lines[i])
- # no continue - there might be other changes to the line...
+ if content:
+ if entityprog.search(content) > -1:
+ content = regsub.gsub('&', '&', content)
+ content = regsub.gsub('<', '<', content)
+ content = regsub.gsub('>', '>', content)
- # make into links
- n = emailprog.search(lines[i])
- if n >= 0:
- lines[i] = regsub.gsub(emailprog,
- '\\1', lines[i])
- # no continue - there might be other changes to the line...
+ n = questionprog.match(content)
+ if n > 0:
+ content = '' + content[n:] + ''
+ if ollev: # question reference in index
+ fragid = regsub.gsub('^ +|\.? +$', '', secnum)
+ content = '%s' % (fragid, content)
- lines[0:0] = ['Python Frequently Asked Questions v',
- version,
- '\n',
- '\n',
- '(This file was generated using\n',
- 'faq2html.py.)\n']
- lines.append('
\n')
+ if element[0] == 'h': # heading in the main text
+ fragid = regsub.gsub('^ +|\.? +$', '', secnum)
+ content = secnum + '%s' % (fragid, content)
- print 'Writing html file...'
- f = open(FAQ + '.html', 'w')
- for line in lines:
- f.write(line)
- f.close()
- print 'Done.'
+ n = answerprog.match(content)
+ if n > 0: # answer paragraph
+ content = regsub.sub(sentprog, '\\1', content[n:])
-main()
+ body.append('<' + element + '>' + content)
+ body.append('' + element + '>')
+ content = ''
+
+ while clearol and ollev: upol()
+ if clearul and ullev: body.append(''); ullev = 0
+
+# ---------------------------------------------------------------- main program
+faq = len(sys.argv)>1 and sys.argv[1] and open(sys.argv[1]) or sys.stdin
+lines = faq.readlines()
+
+for line in lines:
+ if line[2:9] == '=======': #
will appear *before*
+ body.append('
') # the underlined heading
+ continue
+
+ n = orditemprog.match(line)
+ if n > 0: # make ordered list item
+ spew(0, 'clear ul')
+ secnum = line[:n]
+ level = string.count(secnum, '.')
+ while level > ollev: dnol()
+ while level < ollev: upol()
+ element, content = 'li', line[n:]
+ continue
+
+ n = itemprog.match(line)
+ if n > 0: # make unordered list item
+ spew('clear ol', 0)
+ if ullev == 0: body.append(''); ullev = 1
+ element, content = 'li', line[n:]
+ continue
+
+ n = headingprog.match(line)
+ if n > 0: # make heading element
+ spew('clear ol', 'clear ul')
+ secnum = line[:n]
+ sys.stderr.write(line)
+ element, content = 'h%d' % string.count(secnum, '.'), line[n:]
+ continue
+
+ n = 0
+ if not secnum: # haven't hit body yet
+ n = mailhdrprog.match(line)
+ v = version and -1 or regex.match('Version: ', line)
+ if v > 0 and not version: version = line[v:]
+ if n <= 0 and element != 'li': # not pre if after a list item
+ n = prefmtprog.match(line)
+ if n > 0: # make preformatted element
+ if element == 'pre':
+ content = content + line
+ else:
+ spew('clear ol', 'clear ul')
+ element, content = 'pre', line
+ continue
+
+ if blankprog.match(line) > 0: # force a new element
+ spew()
+ element = ''
+ elif element: # continue current element
+ content = content + line
+ else: # no element; make paragraph
+ spew('clear ol', 'clear ul')
+ element, content = 'p', line
+
+spew() # output last element
+
+body = string.joinfields(body, '')
+body = regsub.gsub(urlprog, '\\1', body)
+body = regsub.gsub(addrprog, '\\1', body)
+body = regsub.gsub(qrefprog, 'question \\1', body)
+body = regsub.gsub(srefprog, 'section \\1', body)
+
+print ''
+print 'Python Frequently-Asked Questions v' + version
+print "(This file was generated using Ping's"
+print 'faq2html.py.)'
+print body + ''