2015-02-19 10:59:12 -08:00
|
|
|
# Copyright (c) 2010, 2011, 2012, 2015 Nicira, Inc.
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at:
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
import re
|
|
|
|
|
|
|
|
from ovs.db import error
|
|
|
|
|
2015-07-06 21:05:03 -07:00
|
|
|
def text_to_nroff(s, font=r'\fR'):
|
2015-02-19 10:59:12 -08:00
|
|
|
def escape(match):
|
|
|
|
c = match.group(0)
|
|
|
|
|
|
|
|
# In Roman type, let -- in XML be \- in nroff. That gives us a way to
|
|
|
|
# write minus signs, which is important in some places in manpages.
|
|
|
|
#
|
|
|
|
# Bold in nroff usually represents literal text, where there's no
|
|
|
|
# distinction between hyphens and minus sign. The convention in nroff
|
|
|
|
# appears to be to use a minus sign in such cases, so we follow that
|
|
|
|
# convention.
|
|
|
|
#
|
|
|
|
# Finally, we always output - as a minus sign when it is followed by a
|
|
|
|
# digit.
|
|
|
|
if c.startswith('-'):
|
|
|
|
if c == '--' and font == r'\fR':
|
|
|
|
return r'\-'
|
|
|
|
if c != '-' or font in (r'\fB', r'\fL'):
|
|
|
|
return c.replace('-', r'\-')
|
|
|
|
else:
|
|
|
|
return '-'
|
|
|
|
|
|
|
|
if c == '\\':
|
|
|
|
return r'\e'
|
|
|
|
elif c == '"':
|
|
|
|
return r'\(dq'
|
|
|
|
elif c == "'":
|
|
|
|
return r'\(cq'
|
|
|
|
elif c == ".":
|
|
|
|
# groff(7) says that . can be escaped by \. but in practice groff
|
|
|
|
# still gives an error with \. at the beginning of a line.
|
2015-06-23 11:06:01 -07:00
|
|
|
return r'\[char46]'
|
2015-02-19 10:59:12 -08:00
|
|
|
else:
|
|
|
|
raise error.Error("bad escape")
|
|
|
|
|
|
|
|
# Escape - \ " ' . as needed by nroff.
|
|
|
|
s = re.sub('(-[0-9]|--|[-"\'\\\\.])', escape, s)
|
|
|
|
return s
|
|
|
|
|
2015-07-06 21:05:03 -07:00
|
|
|
def escape_nroff_literal(s, font=r'\fB'):
|
|
|
|
return font + r'%s\fR' % text_to_nroff(s, font)
|
2015-02-19 10:59:12 -08:00
|
|
|
|
2015-07-06 21:05:03 -07:00
|
|
|
def inline_xml_to_nroff(node, font, to_upper=False):
|
2015-02-19 10:59:12 -08:00
|
|
|
if node.nodeType == node.TEXT_NODE:
|
|
|
|
if to_upper:
|
2015-07-06 21:05:03 -07:00
|
|
|
return text_to_nroff(node.data.upper(), font)
|
2015-02-19 10:59:12 -08:00
|
|
|
else:
|
2015-07-06 21:05:03 -07:00
|
|
|
return text_to_nroff(node.data, font)
|
2015-02-19 10:59:12 -08:00
|
|
|
elif node.nodeType == node.ELEMENT_NODE:
|
2015-06-13 18:02:02 -07:00
|
|
|
if node.tagName in ['code', 'em', 'option', 'env']:
|
2015-02-19 10:59:12 -08:00
|
|
|
s = r'\fB'
|
|
|
|
for child in node.childNodes:
|
2015-07-06 21:05:03 -07:00
|
|
|
s += inline_xml_to_nroff(child, r'\fB')
|
2015-02-19 10:59:12 -08:00
|
|
|
return s + font
|
|
|
|
elif node.tagName == 'ref':
|
|
|
|
s = r'\fB'
|
|
|
|
if node.hasAttribute('column'):
|
|
|
|
s += node.attributes['column'].nodeValue
|
|
|
|
if node.hasAttribute('key'):
|
|
|
|
s += ':' + node.attributes['key'].nodeValue
|
|
|
|
elif node.hasAttribute('table'):
|
|
|
|
s += node.attributes['table'].nodeValue
|
|
|
|
elif node.hasAttribute('group'):
|
|
|
|
s += node.attributes['group'].nodeValue
|
|
|
|
elif node.hasAttribute('db'):
|
|
|
|
s += node.attributes['db'].nodeValue
|
|
|
|
else:
|
|
|
|
raise error.Error("'ref' lacks required attributes: %s" % node.attributes.keys())
|
|
|
|
return s + font
|
|
|
|
elif node.tagName == 'var' or node.tagName == 'dfn':
|
|
|
|
s = r'\fI'
|
|
|
|
for child in node.childNodes:
|
2015-07-06 21:05:03 -07:00
|
|
|
s += inline_xml_to_nroff(child, r'\fI')
|
2015-02-19 10:59:12 -08:00
|
|
|
return s + font
|
|
|
|
else:
|
|
|
|
raise error.Error("element <%s> unknown or invalid here" % node.tagName)
|
|
|
|
else:
|
|
|
|
raise error.Error("unknown node %s in inline xml" % node)
|
|
|
|
|
|
|
|
def pre_to_nroff(nodes, para, font):
|
|
|
|
s = para + '\n.nf\n'
|
|
|
|
for node in nodes:
|
|
|
|
if node.nodeType != node.TEXT_NODE:
|
|
|
|
fatal("<pre> element may only have text children")
|
|
|
|
for line in node.data.split('\n'):
|
2015-07-06 21:05:03 -07:00
|
|
|
s += escape_nroff_literal(line, font) + '\n.br\n'
|
2015-02-19 10:59:12 -08:00
|
|
|
s += '.fi\n'
|
|
|
|
return s
|
|
|
|
|
2015-07-06 21:05:03 -07:00
|
|
|
def block_xml_to_nroff(nodes, para='.PP'):
|
2015-02-19 10:59:12 -08:00
|
|
|
s = ''
|
|
|
|
for node in nodes:
|
|
|
|
if node.nodeType == node.TEXT_NODE:
|
2015-07-06 21:05:03 -07:00
|
|
|
s += text_to_nroff(node.data)
|
2015-02-19 10:59:12 -08:00
|
|
|
s = s.lstrip()
|
|
|
|
elif node.nodeType == node.ELEMENT_NODE:
|
|
|
|
if node.tagName in ['ul', 'ol']:
|
|
|
|
if s != "":
|
|
|
|
s += "\n"
|
|
|
|
s += ".RS\n"
|
|
|
|
i = 0
|
2015-07-06 21:05:03 -07:00
|
|
|
for li_node in node.childNodes:
|
|
|
|
if (li_node.nodeType == node.ELEMENT_NODE
|
|
|
|
and li_node.tagName == 'li'):
|
2015-02-19 10:59:12 -08:00
|
|
|
i += 1
|
|
|
|
if node.tagName == 'ul':
|
|
|
|
s += ".IP \\(bu\n"
|
|
|
|
else:
|
|
|
|
s += ".IP %d. .25in\n" % i
|
2015-07-06 21:05:03 -07:00
|
|
|
s += block_xml_to_nroff(li_node.childNodes, ".IP")
|
|
|
|
elif (li_node.nodeType != node.TEXT_NODE
|
|
|
|
or not li_node.data.isspace()):
|
2015-02-19 10:59:12 -08:00
|
|
|
raise error.Error("<%s> element may only have <li> children" % node.tagName)
|
|
|
|
s += ".RE\n"
|
|
|
|
elif node.tagName == 'dl':
|
|
|
|
if s != "":
|
|
|
|
s += "\n"
|
|
|
|
s += ".RS\n"
|
|
|
|
prev = "dd"
|
2015-07-06 21:05:03 -07:00
|
|
|
for li_node in node.childNodes:
|
|
|
|
if (li_node.nodeType == node.ELEMENT_NODE
|
|
|
|
and li_node.tagName == 'dt'):
|
2015-02-19 10:59:12 -08:00
|
|
|
if prev == 'dd':
|
|
|
|
s += '.TP\n'
|
|
|
|
else:
|
|
|
|
s += '.TQ .5in\n'
|
|
|
|
prev = 'dt'
|
2015-07-06 21:05:03 -07:00
|
|
|
elif (li_node.nodeType == node.ELEMENT_NODE
|
|
|
|
and li_node.tagName == 'dd'):
|
2015-02-19 10:59:12 -08:00
|
|
|
if prev == 'dd':
|
|
|
|
s += '.IP\n'
|
|
|
|
prev = 'dd'
|
2015-07-06 21:05:03 -07:00
|
|
|
elif (li_node.nodeType != node.TEXT_NODE
|
|
|
|
or not li_node.data.isspace()):
|
2015-02-19 10:59:12 -08:00
|
|
|
raise error.Error("<dl> element may only have <dt> and <dd> children")
|
2015-07-06 21:05:03 -07:00
|
|
|
s += block_xml_to_nroff(li_node.childNodes, ".IP")
|
2015-02-19 10:59:12 -08:00
|
|
|
s += ".RE\n"
|
|
|
|
elif node.tagName == 'p':
|
|
|
|
if s != "":
|
|
|
|
if not s.endswith("\n"):
|
|
|
|
s += "\n"
|
|
|
|
s += para + "\n"
|
2015-07-06 21:05:03 -07:00
|
|
|
s += block_xml_to_nroff(node.childNodes, para)
|
2015-02-19 10:59:12 -08:00
|
|
|
elif node.tagName in ('h1', 'h2', 'h3'):
|
|
|
|
if s != "":
|
|
|
|
if not s.endswith("\n"):
|
|
|
|
s += "\n"
|
|
|
|
nroffTag = {'h1': 'SH', 'h2': 'SS', 'h3': 'ST'}[node.tagName]
|
|
|
|
s += '.%s "' % nroffTag
|
|
|
|
for child_node in node.childNodes:
|
2015-07-06 21:05:03 -07:00
|
|
|
s += inline_xml_to_nroff(child_node, r'\fR',
|
2015-02-19 10:59:12 -08:00
|
|
|
to_upper=(nroffTag == 'SH'))
|
|
|
|
s += '"\n'
|
|
|
|
elif node.tagName == 'pre':
|
|
|
|
fixed = node.getAttribute('fixed')
|
|
|
|
if fixed == 'yes':
|
|
|
|
font = r'\fL'
|
|
|
|
else:
|
|
|
|
font = r'\fB'
|
|
|
|
s += pre_to_nroff(node.childNodes, para, font)
|
|
|
|
else:
|
2015-07-06 21:05:03 -07:00
|
|
|
s += inline_xml_to_nroff(node, r'\fR')
|
2015-02-19 10:59:12 -08:00
|
|
|
else:
|
|
|
|
raise error.Error("unknown node %s in block xml" % node)
|
|
|
|
if s != "" and not s.endswith('\n'):
|
|
|
|
s += '\n'
|
|
|
|
return s
|