29
29
"""
30
30
31
31
import os
32
+ import re
32
33
import sys
33
34
34
35
import codecs
56
57
TD = '{http://projectmallard.org/1.0/}td'
57
58
OUTPUT = '{http://projectmallard.org/1.0/}output'
58
59
60
+ # Matches "\" and "-", but not "\-".
61
+ replaceables = re .compile (r'(\\(?!-))|((?<!\\)-)' )
62
+
63
+
59
64
class Convert (object ):
60
65
title = None
61
66
subtitle = None
@@ -69,6 +74,9 @@ def __init__(self, inFile, outFile, section):
69
74
self .section = section
70
75
self .sections = []
71
76
77
+ # Map: section id -> section element.
78
+ self .sections_map = {}
79
+
72
80
def _parse (self ):
73
81
self .tree = ElementTree .ElementTree ()
74
82
self .tree .parse (open (self .inFile ))
@@ -87,23 +95,57 @@ def _get_parent(self, ele):
87
95
return self .parent_map [ele ]
88
96
89
97
def _extract (self ):
90
- # Try to extract the title.
98
+ # Extract the title and subtitle .
91
99
for child in self .root .getchildren ():
92
100
if child .tag == TITLE :
93
101
self .title = child .text .strip ()
94
102
elif child .tag == SUBTITLE :
95
103
self .subtitle = child .text .strip ()
96
104
elif child .tag == SECTION :
105
+ if child .get ('id' ):
106
+ self .sections_map [child .get ('id' )] = child
97
107
self .sections .append (child )
98
108
109
+ if not self .subtitle and 'description' in self .sections_map :
110
+ # No "subtitle" element, use description section title as subtitle.
111
+ self .subtitle = self ._section_text (self .sections_map ['description' ])
112
+
113
+ def _section_text (self , section ):
114
+ # Find <section id="description"><p>some text</p></section>.
115
+ for child in section :
116
+ if child .tag != TITLE :
117
+ return self ._textify_elem (child )
118
+
119
+ def _textify_elem (self , elem ):
120
+ return '' .join (elem .itertext ()).strip ()
121
+
99
122
def _writeComment (self , text = '' ):
100
123
lines = text .split ('\n ' )
101
124
for line in lines :
102
125
self .outFile .write ('.\\ " ' )
103
126
self .outFile .write (line )
104
127
self .outFile .write ('\n ' )
105
128
129
+ def _escape_char (self , match ):
130
+ c = match .group (0 )
131
+ if c == "-" :
132
+ return r"\(hy"
133
+ elif c == "\\ " :
134
+ return "\\ e"
135
+
136
+ assert False , "invalid char passed to _escape_char: %r" % c
137
+
138
+ def _escape (self , text ):
139
+ # Avoid "hyphen-used-as-minus-sign" lintian warning about man pages,
140
+ # and escape text like "\0" as "\\0". We'll replace all "-" with "\(hy",
141
+ # which is an explicit hyphen, but leave alone the first line's
142
+ # "name \- description" text.
143
+ return replaceables .sub (self ._escape_char , text )
144
+
106
145
def _write (self , text ):
146
+ self ._write_noescape (self ._escape (text ))
147
+
148
+ def _write_noescape (self , text ):
107
149
self .outFile .write (text )
108
150
109
151
def _writeCommand (self , text ):
@@ -135,11 +177,7 @@ def _generateHeader(self):
135
177
title = self .title .replace ('()' ,'' ).upper ()
136
178
self ._write ('.TH "%s" "%s" "%s" "%s"\n ' % (title , self .section , date , GROUP ))
137
179
self ._write ('.SH NAME\n ' )
138
-
139
- if self .subtitle :
140
- self ._write ('%s \\ - %s\n ' % (self .title , self .subtitle ))
141
- else :
142
- self ._write ('%s\n ' % self .title )
180
+ self ._write_noescape ('%s \\ - %s\n ' % (self .title , self .subtitle ))
143
181
144
182
def _generateSection (self , section ):
145
183
# Try to render the title first
@@ -165,7 +203,7 @@ def _generateCode(self, code):
165
203
is_synopsis = self ._get_parent (code ).tag .endswith ('synopsis' )
166
204
if text and '\n ' not in text and not is_synopsis :
167
205
text = text .replace ('()' , '(%s)' % self .section )
168
- self ._writeCommand ('.BR ' + text )
206
+ self ._writeCommand ('.B ' + text )
169
207
else :
170
208
self ._writeCommand ('.nf' )
171
209
self ._writeLine (code .text )
@@ -203,7 +241,7 @@ def _generateList(self, l):
203
241
self ._generateElement (child )
204
242
205
243
def _generateEM (self , em ):
206
- self ._writeCommand ('.BR %s' % em .text )
244
+ self ._writeCommand ('.B %s' % em .text )
207
245
208
246
def _generateOutput (self , output ):
209
247
self ._generateCode (output )
@@ -274,18 +312,17 @@ def _generateLink(self, link):
274
312
if text and '()' in text :
275
313
text = text .replace ('()' , '(%s)' % self .section )
276
314
if text :
277
- self ._writeCommand ('.BR ' + text )
315
+ self ._writeCommand ('.B ' + text )
278
316
279
317
def _generateSections (self ):
280
318
for section in self .sections :
281
319
self ._generateElement (section )
282
320
283
321
def _generateFooter (self ):
284
- self ._write ('\n .BR ' )
322
+ self ._write ('\n .B ' )
285
323
self ._write ('\n .SH COLOPHON' )
286
324
self ._write ('\n This page is part of %s.' % GROUP )
287
- self ._write ('\n Please report any bugs at\n ' )
288
- self ._write ('\\ %' + BUG_URL .replace ('-' ,'\\ -' ) + '.' )
325
+ self ._write ('\n Please report any bugs at %s.' % BUG_URL .replace ('-' ,'\\ -' ))
289
326
290
327
def _generate (self ):
291
328
self .realname = self .outFile
0 commit comments