import re
import sys
import parser
class Parser(parser.Parser):
def __init__(self, pctxt):
parser.Parser.__init__(self, pctxt)
self.table1Pattern = re.compile(r'^ *(-+\+)+-+')
self.table2Pattern = re.compile(r'^ *\+(-+\+)+')
def parse(self, line):
global document, keywords, keywordsCount, chapters, keyword_conflicts
pctxt = self.pctxt
if pctxt.context['headers']['subtitle'] != 'Configuration Manual':
# Quick exit
return line
elif pctxt.details['chapter'] == "4":
# BUG: the matrix in chapter 4. Proxies is not well displayed, we skip this chapter
return line
if pctxt.has_more_lines(1):
nextline = pctxt.get_line(1)
else:
nextline = ""
if self.table1Pattern.match(nextline):
# activate table rendering only for the Configuration Manual
lineSeparator = nextline
nbColumns = nextline.count("+") + 1
extraColumns = 0
print("Entering table mode (%d columns)" % nbColumns, file=sys.stderr)
table = []
if line.find("|") != -1:
row = []
while pctxt.has_more_lines():
line = pctxt.get_line()
if pctxt.has_more_lines(1):
nextline = pctxt.get_line(1)
else:
nextline = ""
if line == lineSeparator:
# New row
table.append(row)
row = []
if nextline.find("|") == -1:
break # End of table
else:
# Data
columns = line.split("|")
for j in range(0, len(columns)):
try:
if row[j]:
row[j] += "
"
row[j] += columns[j].strip()
except:
row.append(columns[j].strip())
pctxt.next()
else:
row = []
headers = nextline
while pctxt.has_more_lines():
line = pctxt.get_line()
if pctxt.has_more_lines(1):
nextline = pctxt.get_line(1)
else:
nextline = ""
if nextline == "":
if row: table.append(row)
break # End of table
if (line != lineSeparator) and (line[0] != "-"):
start = 0
if row and not line.startswith(" "):
# Row is complete, parse a new one
table.append(row)
row = []
tmprow = []
while start != -1:
end = headers.find("+", start)
if end == -1:
end = len(headers)
realend = end
if realend == len(headers):
realend = len(line)
else:
while realend < len(line) and line[realend] != " ":
realend += 1
end += 1
tmprow.append(line[start:realend])
start = end + 1
if start >= len(headers):
start = -1
for j in range(0, nbColumns):
try:
row[j] += tmprow[j].strip()
except:
row.append(tmprow[j].strip())
deprecated = row[0].endswith("(deprecated)")
if deprecated:
row[0] = row[0][: -len("(deprecated)")].rstrip()
nooption = row[1].startswith("(*)")
if nooption:
row[1] = row[1][len("(*)"):].strip()
if deprecated or nooption:
extraColumns = 1
extra = ""
if deprecated:
extra += '(deprecated)'
if nooption:
extra += '(*)'
row.append(extra)
pctxt.next()
print("Leaving table mode", file=sys.stderr)
pctxt.next() # skip useless next line
pctxt.stop = True
return self.renderTable(table, nbColumns, pctxt.details["toplevel"])
# elif self.table2Pattern.match(line):
# return self.parse_table_format2()
elif line.find("May be used in sections") != -1:
nextline = pctxt.get_line(1)
rows = []
headers = line.split(":")
rows.append(headers[1].split("|"))
rows.append(nextline.split("|"))
table = {
"rows": rows,
"title": headers[0]
}
pctxt.next(2) # skip this previous table
pctxt.stop = True
return self.renderTable(table)
return line
def parse_table_format2(self):
pctxt = self.pctxt
linesep = pctxt.get_line()
rows = []
pctxt.next()
maxcols = 0
while pctxt.get_line().strip().startswith("|"):
row = pctxt.get_line().strip()[1:-1].split("|")
rows.append(row)
maxcols = max(maxcols, len(row))
pctxt.next()
if pctxt.get_line() == linesep:
# TODO : find a way to define a special style for next row
pctxt.next()
pctxt.stop = True
return self.renderTable(rows, maxcols)
# Render tables detected by the conversion parser
def renderTable(self, table, maxColumns = 0, toplevel = None):
pctxt = self.pctxt
template = pctxt.templates.get_template("parser/table.tpl")
res = ""
title = None
if isinstance(table, dict):
title = table["title"]
table = table["rows"]
if not maxColumns:
maxColumns = len(table[0])
rows = []
mode = "th"
headerLine = ""
hasKeywords = False
i = 0
for row in table:
line = ""
if i == 0:
row_template = pctxt.templates.get_template("parser/table/header.tpl")
else:
row_template = pctxt.templates.get_template("parser/table/row.tpl")
if i > 1 and (i - 1) % 20 == 0 and len(table) > 50:
# Repeat headers periodically for long tables
rows.append(headerLine)
j = 0
cols = []
for column in row:
if j >= maxColumns:
break
tplcol = {}
data = column.strip()
keyword = column
if j == 0 and i == 0 and keyword == 'keyword':
hasKeywords = True
if j == 0 and i != 0 and hasKeywords:
if keyword.startswith("[no] "):
keyword = keyword[len("[no] "):]
tplcol['toplevel'] = toplevel
tplcol['keyword'] = keyword
tplcol['extra'] = []
if j == 0 and len(row) > maxColumns:
for k in range(maxColumns, len(row)):
tplcol['extra'].append(row[k])
tplcol['data'] = data
cols.append(tplcol)
j += 1
mode = "td"
line = row_template.render(
pctxt=pctxt,
columns=cols
).strip()
if i == 0:
headerLine = line
rows.append(line)
i += 1
return template.render(
pctxt=pctxt,
title=title,
rows=rows,
)