~certify-web-dev/twisted/certify-trunk

« back to all changes in this revision

Viewing changes to twisted/lore/man2lore.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-01-17 14:52:35 UTC
  • mfrom: (1.1.5 upstream) (2.1.2 etch)
  • Revision ID: james.westby@ubuntu.com-20070117145235-btmig6qfmqfen0om
Tags: 2.5.0-0ubuntu1
New upstream version, compatible with python2.5.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
 
2
# See LICENSE for details.
 
3
 
 
4
#
 
5
"""man2lore: Converts man page source (i.e. groff) into lore-compatible html.
 
6
 
 
7
This is nasty and hackish (and doesn't support lots of real groff), but is good
 
8
enough for converting fairly simple man pages.
 
9
"""
 
10
from __future__ import nested_scopes
 
11
 
 
12
import re, os
 
13
quoteRE = re.compile('"(.*?)"')
 
14
 
 
15
def escape(text):
 
16
    text = text.replace('<', '&lt;').replace('>', '&gt;')
 
17
    text = quoteRE.sub('<q>\\1</q>', text)
 
18
    return text
 
19
 
 
20
def stripQuotes(s):
 
21
    if s[0] == s[-1] == '"':
 
22
        s = s[1:-1]
 
23
    return s
 
24
 
 
25
class ManConverter:
 
26
    state = 'regular'
 
27
    name = None
 
28
    tp = 0
 
29
    dl = 0
 
30
    para = 0
 
31
 
 
32
    def convert(self, inf, outf):
 
33
        self.write = outf.write
 
34
        longline = ''
 
35
        for line in inf.readlines():
 
36
            if line.rstrip() and line.rstrip()[-1] == '\\':
 
37
                longline += line.rstrip()[:-1] + ' '
 
38
                continue
 
39
            if longline:
 
40
                line = longline + line
 
41
                longline = ''
 
42
            self.lineReceived(line)
 
43
        self.closeTags()
 
44
        self.write('</body>\n</html>\n')
 
45
 
 
46
    def lineReceived(self, line):
 
47
        if line[0] == '.':
 
48
            f = getattr(self, 'macro_' + line[1:3].rstrip().upper(), None)
 
49
            if f:
 
50
                f(line[3:].strip())
 
51
        else:
 
52
            self.text(line)
 
53
 
 
54
    def continueReceived(self, cont):
 
55
        if not cont:
 
56
            return
 
57
        if cont[0].isupper():
 
58
            f = getattr(self, 'macro_' + cont[:2].rstrip().upper(), None)
 
59
            if f:
 
60
                f(cont[2:].strip())
 
61
        else:
 
62
            self.text(cont)
 
63
 
 
64
    def closeTags(self):
 
65
        if self.state != 'regular':
 
66
            self.write('</%s>' % self.state)
 
67
        if self.tp == 3:
 
68
            self.write('</dd>\n\n')
 
69
            self.tp = 0
 
70
        if self.dl:
 
71
            self.write('</dl>\n\n')
 
72
            self.dl = 0
 
73
        if self.para:
 
74
            self.write('</p>\n\n')
 
75
            self.para = 0
 
76
 
 
77
    def paraCheck(self):
 
78
        if not self.tp and not self.para:
 
79
            self.write('<p>')
 
80
            self.para = 1
 
81
 
 
82
    def macro_TH(self, line):
 
83
        self.write('<html><head>\n')
 
84
        parts = [stripQuotes(x) for x in line.split(' ', 2)] + ['', '']
 
85
        title, manSection = parts[:2]
 
86
        self.write('<title>%s.%s</title>' % (title, manSection))
 
87
        self.write('</head>\n<body>\n\n')
 
88
        self.write('<h1>%s.%s</h1>\n\n' % (title, manSection))
 
89
    
 
90
    macro_DT = macro_TH
 
91
    
 
92
    def macro_SH(self, line):
 
93
        self.closeTags()
 
94
        self.write('<h2>')
 
95
        self.para = 1
 
96
        self.text(stripQuotes(line))
 
97
        self.para = 0
 
98
        self.closeTags()
 
99
        self.write('</h2>\n\n')
 
100
 
 
101
    def macro_B(self, line):
 
102
        words = line.split()
 
103
        words[0] = '\\fB' + words[0] + '\\fR '
 
104
        self.text(' '.join(words))
 
105
 
 
106
    def macro_NM(self, line):
 
107
        if not self.name:
 
108
           self.name = line
 
109
        self.text(self.name + ' ')
 
110
 
 
111
    def macro_NS(self, line):
 
112
        parts = line.split(' Ns ')
 
113
        i = 0
 
114
        for l in parts:
 
115
            i = not i
 
116
            if i:
 
117
                self.text(l)
 
118
            else:
 
119
                self.continueReceived(l)
 
120
 
 
121
    def macro_OO(self, line):
 
122
        self.text('[')
 
123
        self.continueReceived(line)
 
124
 
 
125
    def macro_OC(self, line):
 
126
        self.text(']')
 
127
        self.continueReceived(line)
 
128
 
 
129
    def macro_OP(self, line):
 
130
        self.text('[')
 
131
        self.continueReceived(line)
 
132
        self.text(']')
 
133
 
 
134
    def macro_FL(self, line):
 
135
        parts = line.split()
 
136
        self.text('\\fB-%s\\fR' % parts[0])
 
137
        self.continueReceived(' '.join(parts[1:]))
 
138
 
 
139
    def macro_AR(self, line):
 
140
        parts = line.split()
 
141
        self.text('\\fI %s\\fR' % parts[0])
 
142
        self.continueReceived(' '.join(parts[1:]))
 
143
 
 
144
    def macro_PP(self, line):
 
145
        self.closeTags()
 
146
 
 
147
    def macro_TP(self, line):
 
148
        if self.tp == 3:
 
149
            self.write('</dd>\n\n')
 
150
        self.tp = 1
 
151
 
 
152
    def macro_BL(self, line):
 
153
        #assert self.tp == 0, self.tp
 
154
        self.write('<dl>')
 
155
        self.tp = 1
 
156
 
 
157
    def macro_EL(self, line):
 
158
        if self.tp == 3:
 
159
            self.write('</dd>')
 
160
            self.tp = 1
 
161
        #assert self.tp == 1, self.tp
 
162
        self.write('</dl>\n\n')
 
163
        self.tp = 0
 
164
 
 
165
    def macro_IT(self, line):
 
166
        if self.tp == 3:
 
167
            self.write('</dd>')
 
168
            self.tp = 1
 
169
        #assert self.tp == 1, (self.tp, line)
 
170
        self.write('\n<dt>')
 
171
        self.continueReceived(line)
 
172
        self.write('</dt>')
 
173
        self.tp = 2
 
174
 
 
175
    def text(self, line):
 
176
        if self.tp == 2:
 
177
            self.write('<dd>')
 
178
        self.paraCheck()
 
179
 
 
180
        bits = line.split('\\')
 
181
        self.write(escape(bits[0]))
 
182
        for bit in bits[1:]:
 
183
            if bit[:2] == 'fI':
 
184
                self.write('<em>' + escape(bit[2:]))
 
185
                self.state = 'em'
 
186
            elif bit[:2] == 'fB':
 
187
                self.write('<strong>' + escape(bit[2:]))
 
188
                self.state = 'strong'
 
189
            elif bit[:2] == 'fR':
 
190
                self.write('</%s>' % self.state)
 
191
                self.write(escape(bit[2:]))
 
192
                self.state = 'regular'
 
193
            elif bit[:3] == '(co':
 
194
                self.write('&copy;' + escape(bit[3:]))
 
195
            else:
 
196
                self.write(escape(bit))
 
197
 
 
198
        if self.tp == 2:
 
199
            self.tp = 3
 
200
 
 
201
class ProcessingFunctionFactory:
 
202
 
 
203
    def generate_lore(self, d, filenameGenerator=None):
 
204
        ext = d.get('ext', '.html')
 
205
        return lambda file,_: ManConverter().convert(open(file),
 
206
                                    open(os.path.splitext(file)[0]+ext, 'w'))
 
207
 
 
208
factory = ProcessingFunctionFactory()
 
209
 
 
210
if __name__ == '__main__':
 
211
    import sys
 
212
    mc = ManConverter().convert(open(sys.argv[1]), sys.stdout)