#! /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', 'POSIX-2003', 'PSE51', 'PSE52', 'PSE53', 'PSE54', 'C99', 'C11', 'FACE 2.1 Security', 'FACE 2.1 Safety Base', 'FACE 2.1 Safety Extended', 'FACE 2.1 General Purpose', 'FACE 3.0 Security', 'FACE 3.0 Safety Base', 'FACE 3.0 Safety Extended', 'FACE 3.0 General Purpose', 'SCA 2.2.2 AEP', 'SCA 4.1 Ultra Lightweight AEP', 'SCA 4.1 Lightweight AEP', 'SCA 4.1 [Full] AEP' ] standard_names = { 'RTEMS' : 'RTEMS Complete Profile', 'POSIX-2008' : 'POSIX-2008', 'POSIX-2003' : 'POSIX-2003', 'PSE51' : 'POSIX PSE51 - Minimal', 'PSE52' : 'POSIX PSE52 - Real-Time Controller', 'PSE53' : 'POSIX PSE53 - Dedicated', 'PSE54' : 'POSIX PSE54 - Multipurpose', 'C99' : 'C99 Standard Library', 'C11' : 'C11 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', 'FACE 3.0 Security' : 'FACE 3.0 Security', 'FACE 3.0 Safety Base' : 'FACE 3.0 Safety Base', 'FACE 3.0 Safety Extended': 'FACE 3.0 Safety Extended', 'FACE 3.0 General Purpose': 'FACE 3.0 General Purpose', 'SCA 2.2.2 AEP' : 'SCA 2.2.2 AEP', 'SCA 4.1 Ultra Lightweight AEP' : 'SCA 4.1 Ultra Lightweight AEP', 'SCA 4.1 Lightweight AEP' : 'SCA 4.1 Lightweight AEP', 'SCA 4.1 [Full] AEP' : 'SCA 4.1 [Full] AEP' } col_names = { 'api' : 'Methods', 'header' : 'Header File', 'rtems-net' : 'RTEMS w/ Networking', 'rtems-impl' : 'RTEMS Impl Note', 'POSIX-2008' : 'IEEE Std 1003.1-2008', 'POSIX-2003' : 'IEEE Std 1003.1-2003', 'PSE51' : 'PSE51', 'PSE52' : 'PSE52', 'PSE53' : 'PSE53', 'PSE54' : 'PSE54', 'C99' : 'C99', 'C11' : 'C11', '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', 'FACE 3.0 Security' : 'FACE 3.0 Security', 'FACE 3.0 Safety Base' : 'FACE 3.0 Safety Base', 'FACE 3.0 Safety Extended' : 'FACE 3.0 Safety Extended', 'FACE 3.0 General Purpose' : 'FACE 3.0 General Purpose', 'SCA 2.2.2 AEP' : 'SCA 2.2.2 AEP', 'SCA 4.1 Ultra Lightweight AEP' : 'SCA 4.1 Ultra Lightweight AEP', 'SCA 4.1 Lightweight AEP' : 'SCA 4.1 Lightweight AEP', 'SCA 4.1 [Full] AEP' : 'SCA 4.1 [Full] AEP' } # # 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)