1 # Copyright (c) 2010, 2011, 2012, 2015 Nicira, Inc.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at:
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
17 from ovs.db import error
19 def text_to_nroff(s, font=r'\fR'):
23 # In Roman type, let -- in XML be \- in nroff. That gives us a way to
24 # write minus signs, which is important in some places in manpages.
26 # Bold in nroff usually represents literal text, where there's no
27 # distinction between hyphens and minus sign. The convention in nroff
28 # appears to be to use a minus sign in such cases, so we follow that
31 # Finally, we always output - as a minus sign when it is followed by a
34 if c == '--' and font == r'\fR':
36 if c != '-' or font in (r'\fB', r'\fL'):
37 return c.replace('-', r'\-')
48 # groff(7) says that . can be escaped by \. but in practice groff
49 # still gives an error with \. at the beginning of a line.
52 raise error.Error("bad escape")
54 # Escape - \ " ' . as needed by nroff.
55 s = re.sub('(-[0-9]|--|[-"\'\\\\.])', escape, s)
58 def escape_nroff_literal(s, font=r'\fB'):
59 return font + r'%s\fR' % text_to_nroff(s, font)
61 def inline_xml_to_nroff(node, font, to_upper=False, newline='\n'):
62 if node.nodeType == node.TEXT_NODE:
64 s = text_to_nroff(node.data.upper(), font)
66 s = text_to_nroff(node.data, font)
67 return s.replace('\n', newline)
68 elif node.nodeType == node.ELEMENT_NODE:
69 if node.tagName in ['code', 'em', 'option', 'env', 'b']:
71 for child in node.childNodes:
72 s += inline_xml_to_nroff(child, r'\fB', to_upper, newline)
74 elif node.tagName == 'ref':
76 if node.hasAttribute('column'):
77 s += node.attributes['column'].nodeValue
78 if node.hasAttribute('key'):
79 s += ':' + node.attributes['key'].nodeValue
80 elif node.hasAttribute('table'):
81 s += node.attributes['table'].nodeValue
82 elif node.hasAttribute('group'):
83 s += node.attributes['group'].nodeValue
84 elif node.hasAttribute('db'):
85 s += node.attributes['db'].nodeValue
87 raise error.Error("'ref' lacks required attributes: %s" % node.attributes.keys())
89 elif node.tagName in ['var', 'dfn', 'i']:
91 for child in node.childNodes:
92 s += inline_xml_to_nroff(child, r'\fI', to_upper, newline)
95 raise error.Error("element <%s> unknown or invalid here" % node.tagName)
96 elif node.nodeType == node.COMMENT_NODE:
99 raise error.Error("unknown node %s in inline xml" % node)
101 def pre_to_nroff(nodes, para, font):
102 # This puts 'font' at the beginning of each line so that leading and
103 # trailing whitespace stripping later doesn't removed leading spaces
104 # from preformatted text.
105 s = para + '\n.nf\n' + font
107 s += inline_xml_to_nroff(node, font, False, '\n.br\n' + font)
111 def diagram_header_to_nroff(header_node):
114 for node in header_node.childNodes:
115 if node.nodeType == node.ELEMENT_NODE and node.tagName == 'bits':
116 name = node.attributes['name'].nodeValue
117 width = node.attributes['width'].nodeValue
118 above = node.getAttribute('above')
119 below = node.getAttribute('below')
120 fill = node.getAttribute('fill')
121 header_fields += [{"name": name,
128 elif node.nodeType == node.COMMENT_NODE:
130 elif node.nodeType == node.TEXT_NODE and node.data.isspace():
133 fatal("unknown node %s in diagram <header> element" % node)
136 for f in header_fields:
137 pic_s += " %s: box \"%s\" width %s" % (f['tag'], f['name'], f['width'])
138 if f['fill'] == 'yes':
141 for f in header_fields:
142 pic_s += " \"%s\" at %s.n above\n" % (f['above'], f['tag'])
143 pic_s += " \"%s\" at %s.s below\n" % (f['below'], f['tag'])
144 name = header_node.getAttribute('name')
149 pic_s += "line <->%s \"%s\" above " % (visible, name)
150 pic_s += "from %s.nw + (0,textht) " % header_fields[0]['tag']
151 pic_s += "to %s.ne + (0,textht)\n" % header_fields[-1]['tag']
154 for f in header_fields:
155 text_s += """.IP \\(bu
156 %s bits""" % (f['above'])
158 text_s += ": %s" % f['name']
160 text_s += " (%s)" % f['below']
164 def diagram_to_nroff(nodes, para):
169 if node.nodeType == node.ELEMENT_NODE and node.tagName == 'header':
173 pic_header, text_header = diagram_header_to_nroff(node)
174 pic_s += "[\n" + pic_header + "]\n"
175 text_s += text_header
177 elif node.nodeType == node.ELEMENT_NODE and node.tagName == 'nospace':
179 elif node.nodeType == node.ELEMENT_NODE and node.tagName == 'dots':
181 pic_s += '". . ." ljust\n'
183 elif node.nodeType == node.COMMENT_NODE:
185 elif node.nodeType == node.TEXT_NODE and node.data.isspace():
188 fatal("unknown node %s in diagram <header> element" % node)
190 .\\" check if in troff mode (TTY)
199 .\\" check if in nroff mode:
206 def block_xml_to_nroff(nodes, para='.PP'):
209 if node.nodeType == node.TEXT_NODE:
210 s += text_to_nroff(node.data)
212 elif node.nodeType == node.ELEMENT_NODE:
213 if node.tagName in ['ul', 'ol']:
218 for li_node in node.childNodes:
219 if (li_node.nodeType == node.ELEMENT_NODE
220 and li_node.tagName == 'li'):
222 if node.tagName == 'ul':
225 s += ".IP %d. .25in\n" % i
226 s += block_xml_to_nroff(li_node.childNodes, ".IP")
227 elif li_node.nodeType == node.COMMENT_NODE:
229 elif (li_node.nodeType != node.TEXT_NODE
230 or not li_node.data.isspace()):
231 raise error.Error("<%s> element may only have <li> children" % node.tagName)
233 elif node.tagName == 'dl':
238 for li_node in node.childNodes:
239 if (li_node.nodeType == node.ELEMENT_NODE
240 and li_node.tagName == 'dt'):
246 elif (li_node.nodeType == node.ELEMENT_NODE
247 and li_node.tagName == 'dd'):
251 elif li_node.nodeType == node.COMMENT_NODE:
253 elif (li_node.nodeType != node.TEXT_NODE
254 or not li_node.data.isspace()):
255 raise error.Error("<dl> element may only have <dt> and <dd> children")
256 s += block_xml_to_nroff(li_node.childNodes, ".IP")
258 elif node.tagName == 'p':
260 if not s.endswith("\n"):
263 s += block_xml_to_nroff(node.childNodes, para)
264 elif node.tagName in ('h1', 'h2', 'h3'):
266 if not s.endswith("\n"):
268 nroffTag = {'h1': 'SH', 'h2': 'SS', 'h3': 'ST'}[node.tagName]
269 s += '.%s "' % nroffTag
270 for child_node in node.childNodes:
271 s += inline_xml_to_nroff(child_node, r'\fR',
272 to_upper=(nroffTag == 'SH'))
274 elif node.tagName == 'pre':
275 fixed = node.getAttribute('fixed')
280 s += pre_to_nroff(node.childNodes, para, font)
281 elif node.tagName == 'diagram':
282 s += diagram_to_nroff(node.childNodes, para)
284 s += inline_xml_to_nroff(node, r'\fR')
285 elif node.nodeType == node.COMMENT_NODE:
288 raise error.Error("unknown node %s in block xml" % node)
289 if s != "" and not s.endswith('\n'):