Chris Johns b2527535fd posix-compliance: Reference the generated content via the include file.
- Move the copyright to the top of the generated file.
- Add a glossary and references section.
2017-10-13 07:37:40 -07:00

267 lines
9.0 KiB
Python
Executable File

#! /usr/bin/env python
#
# Convert the CSV compliance data to ReST Format.
#
from __future__ import print_function
import copy
import csv
import os
import sys
standards = [
'RTEMS',
'POSIX-2008',
'PSE51',
'PSE52',
'PSE53',
'PSE54',
'C99',
'FACE 2.1 Security',
'FACE 2.1 Safety Base',
'FACE 2.1 Safety Extended',
'FACE 2.1 General Purpose'
]
standard_names = {
'RTEMS' : 'RTEMS Complete Profile',
'POSIX-2008' : 'POSIX-2008',
'PSE51' : 'POSIX PSE51 - Minimal',
'PSE52' : 'POSIX PSE52 - Real-Time Controller',
'PSE53' : 'POSIX PSE53 - Dedicated',
'PSE54' : 'POSIX PSE54 - Multipurpose',
'C99' : 'C99 Standard Library',
'FACE 2.1 Security' : 'FACE 2.1 Security',
'FACE 2.1 Safety Base' : 'FACE 2.1 Safety Base',
'FACE 2.1 Safety Extended': 'FACE 2.1 Safety Extended',
'FACE 2.1 General Purpose': 'FACE 2.1 General Purpose'
}
col_names = {
'api' : 'Methods',
'header' : 'Header File',
'rtems-net' : 'RTEMS w/ Networking',
'rtems-impl' : 'RTEMS Impl Note',
'POSIX-2008' : 'IEEE Std 1003.1-2008',
'PSE51' : 'PSE51',
'PSE52' : 'PSE52',
'PSE53' : 'PSE53',
'PSE54' : 'PSE54',
'C99' : 'C99',
'FACE 2.1 Security' : 'FACE 2.1 Security',
'FACE 2.1 Safety Base' : 'FACE 2.1 Safety Base',
'FACE 2.1 Safety Extended' : 'FACE 2.1 Safety Extended',
'FACE 2.1 General Purpose' : 'FACE 2.1 General Purpose'
}
#
# The columns here contain the logic to determine the
#
categories = {
'order': ['supported', 'enosys', 'not-supported'],
'name' : {
'supported' : 'Supported',
'enosys' : 'ENOSYS',
'not-supported': 'Not supported'
},
'supported': ['The following methods and variables in ``<@HEADER@>``',
'are supported:',
''],
'not-supported': ['The following methods and variables in ``<@HEADER@>``',
'are not supported:',
''],
'enosys': ['The following methods in ``<@HEADER@>`` are implemented as',
'stubs returning ``-1`` and setting ``errno`` to ``ENOSYS``:',
'']
}
cat_columns = {
'order': ['rtems-net', 'rtems-impl'],
'rtems-net': {
'supported' : {
'CTS-YES' : ['invalid'],
'RT-YES' : ['invalid'],
'HAND-YES': ['invalid']
},
'not-supported': {
'CTS-NO' : ['invalid'],
'RT-NO' : ['invalid'],
'HAND-NO': ['invalid']
}
},
'rtems-impl': {
'enosys': {
'ENOSYS': ['supported']
}
}
}
rst_defaults = {
'header': ['',
'This chapter has a subsection per header file to detail the methods',
'provided by RTEMS that are in that header file.',
'']
}
class error(Exception):
pass
class compliance:
def __init__(self):
self.data = None
def load(self, name):
with open(name, 'rb') as f:
data = csv.reader(f, delimiter = ',', quotechar = '"')
hdr = None
rows = []
for row in data:
if hdr is None:
hdr = row
else:
rows += [row]
for col in col_names:
if col_names[col] not in hdr:
raise error('column not found: %s' % (col_names[col]))
cdata = { 'columns': hdr, 'headers': {}, 'apis': {} }
apic = hdr.index(col_names['api'])
hfc = hdr.index(col_names['header'])
for row in rows:
api = row[apic]
header = row[hfc]
if len(api) == 0 or len(header) == 0:
continue
if header not in cdata['headers']:
cdata['headers'][header] = [api]
else:
cdata['headers'][header] += [api]
if api in cdata['apis']:
raise error('duplicate api: %s' % (api))
cdata['apis'][api] = row
self.data = cdata
def summary(self, standard = 'RTEMS'):
results = { }
for header in self.data['headers']:
hr = self.process_header(header, standard)
if 'invalid' in hr:
error('header contains "invalid": %s' % (header))
for cat in hr:
if cat not in results:
results[cat] = len(hr[cat])
else:
results[cat] += len(hr[cat])
if standard == 'RTEMS':
std_line = 'The follow table summarizes RTEMS supported' \
' methods for all tracked standards:'
else:
std_line = 'The follow table summarizes alignment with ' \
'the %s standard:' % (standard_names[standard])
s = ['Summary',
'=======',
'',
std_line,
'']
cols = [0, 1]
for cat in categories['order']:
if len(categories['name'][cat]) > cols[0]:
cols[0] = len(categories['name'][cat])
if cat in results:
num = '%d' % results[cat]
if len(num) > cols[1]:
cols[1] = len(num)
table_def = ' %s %s' % ('=' * cols[0], '=' * cols[1])
s += [table_def]
for cat in categories['order']:
if cat in results:
s += [' %-*s %d' % (cols[0], categories['name'][cat], results[cat])]
else:
s += [' %-*s %d' % (cols[0], categories['name'][cat], 0)]
s += [table_def, '']
return s
def output(self, standard = 'RTEMS'):
def _category_filter(text, patterns):
for l in range(0, len(text)):
for pat in patterns:
if pat in text[l]:
text[l] = text[l].replace(pat, patterns[pat])
return text
if standard not in standards:
error('invalid standard": %s' % (standard))
s = rst_defaults['header'] + self.summary(standard)
for header in sorted(self.data['headers'].keys()):
hr = self.process_header(header, standard)
if 'invalid' in hr:
error('header contains "invalid": %s' % (header))
print_heading = True
for cat in categories['order']:
if cat in hr:
if print_heading:
s += ['``<%s>``' % (header),
'=' * (len(header) + 2),
'']
print_heading = False
patterns = { '@HEADER@': header }
cat_text = copy.copy(categories[cat])
_category_filter(cat_text, patterns)
s += cat_text
for api in hr[cat]:
s += ['* ``%s``' % (api)]
s += ['']
return s
def process_header(self, header, standard = 'RTEMS'):
results = { }
if standard != 'RTEMS':
std_col = self.data['columns'].index(col_names[standard])
else:
std_col = -1
for api in sorted(self.data['headers'][header]):
api_row = self.data['apis'][api]
if std_col > 0:
if api_row[std_col] != 'INCL':
continue
state = 'invalid'
for test in cat_columns['order']:
col = self.data['columns'].index(col_names[test])
value = api_row[col]
for test_state in cat_columns[test]:
if value in cat_columns[test][test_state]:
if state in cat_columns[test][test_state][value]:
state = test_state
if state not in results:
results[state] = [api]
else:
results[state] += [api]
return results
if __name__ == "__main__":
try:
import pprint
pp = pprint.PrettyPrinter(indent=2)
if len(sys.argv) != 2:
raise error('not enough arguments')
c = compliance()
c.load(sys.argv[1])
for h in sorted(c.data['headers']):
print('-- %s' % (h), '-' * 50)
hr = c.process_header(h)
if 'invalid' in hr:
error('header contains invalid: %s' % (h))
hr = c.process_header(h, 'PSE51')
if 'invalid' in hr:
error('header contains invalid: %s' % (h))
pp.pprint(hr)
print('=' * 80)
print(os.linesep.join(c.output('PSE51')))
print('=' * 80)
print(os.linesep.join(c.output()))
for s in standards:
print('=-' * 40)
print(os.linesep.join(c.summary(s)))
except error as e:
print('error: %s' % (e), file = sys.stderr)