source: rtems-docs/posix-compliance/posix_rst.py @ b252753

5am
Last change on this file since b252753 was b252753, checked in by Chris Johns <chrisj@…>, on Oct 13, 2017 at 2:37:40 PM

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.
  • Property mode set to 100755
File size: 9.0 KB
Line 
1#! /usr/bin/env python
2#
3# Convert the CSV compliance data to ReST Format.
4#
5
6from __future__ import print_function
7
8import copy
9import csv
10import os
11import sys
12
13standards = [
14    'RTEMS',
15    'POSIX-2008',
16    'PSE51',
17    'PSE52',
18    'PSE53',
19    'PSE54',
20    'C99',
21    'FACE 2.1 Security',
22    'FACE 2.1 Safety Base',
23    'FACE 2.1 Safety Extended',
24    'FACE 2.1 General Purpose'
25]
26
27standard_names = {
28    'RTEMS'                   : 'RTEMS Complete Profile',
29    'POSIX-2008'              : 'POSIX-2008',
30    'PSE51'                   : 'POSIX PSE51 - Minimal',
31    'PSE52'                   : 'POSIX PSE52 - Real-Time Controller',
32    'PSE53'                   : 'POSIX PSE53 - Dedicated',
33    'PSE54'                   : 'POSIX PSE54 - Multipurpose',
34    'C99'                     : 'C99 Standard Library',
35    'FACE 2.1 Security'       : 'FACE 2.1 Security',
36    'FACE 2.1 Safety Base'    : 'FACE 2.1 Safety Base',
37    'FACE 2.1 Safety Extended': 'FACE 2.1 Safety Extended',
38    'FACE 2.1 General Purpose': 'FACE 2.1 General Purpose'
39}
40
41col_names = {
42    'api'                      : 'Methods',
43    'header'                   : 'Header File',
44    'rtems-net'                : 'RTEMS w/ Networking',
45    'rtems-impl'               : 'RTEMS Impl Note',
46    'POSIX-2008'               : 'IEEE Std 1003.1-2008',
47    'PSE51'                    : 'PSE51',
48    'PSE52'                    : 'PSE52',
49    'PSE53'                    : 'PSE53',
50    'PSE54'                    : 'PSE54',
51    'C99'                      : 'C99',
52    'FACE 2.1 Security'        : 'FACE 2.1 Security',
53    'FACE 2.1 Safety Base'     : 'FACE 2.1 Safety Base',
54    'FACE 2.1 Safety Extended' : 'FACE 2.1 Safety Extended',
55    'FACE 2.1 General Purpose' : 'FACE 2.1 General Purpose'
56}
57
58#
59# The columns here contain the logic to determine the
60#
61categories = {
62    'order': ['supported', 'enosys', 'not-supported'],
63    'name' : {
64        'supported'    : 'Supported',
65        'enosys'       : 'ENOSYS',
66        'not-supported': 'Not supported'
67    },
68    'supported': ['The following methods and variables in ``<@HEADER@>``',
69                  'are supported:',
70                  ''],
71    'not-supported': ['The following methods and variables in ``<@HEADER@>``',
72                      'are not supported:',
73                      ''],
74    'enosys': ['The following methods in ``<@HEADER@>`` are implemented as',
75               'stubs returning ``-1`` and setting ``errno`` to ``ENOSYS``:',
76               '']
77}
78
79cat_columns = {
80    'order': ['rtems-net', 'rtems-impl'],
81    'rtems-net': {
82        'supported' : {
83            'CTS-YES' : ['invalid'],
84            'RT-YES'  : ['invalid'],
85            'HAND-YES': ['invalid']
86        },
87        'not-supported': {
88            'CTS-NO' : ['invalid'],
89            'RT-NO'  : ['invalid'],
90            'HAND-NO': ['invalid']
91        }
92    },
93    'rtems-impl': {
94        'enosys': {
95            'ENOSYS': ['supported']
96        }
97    }
98}
99
100rst_defaults = {
101    'header': ['',
102               'This chapter has a subsection per header file to detail the methods',
103               'provided by RTEMS that are in that header file.',
104               '']
105}
106
107class error(Exception):
108    pass
109
110class compliance:
111    def __init__(self):
112        self.data = None
113
114    def load(self, name):
115        with open(name, 'rb') as f:
116            data = csv.reader(f, delimiter = ',', quotechar = '"')
117            hdr = None
118            rows = []
119            for row in data:
120                if hdr is None:
121                    hdr = row
122                else:
123                    rows += [row]
124        for col in col_names:
125            if col_names[col] not in hdr:
126                raise error('column not found: %s' % (col_names[col]))
127        cdata = { 'columns': hdr, 'headers': {}, 'apis': {} }
128        apic = hdr.index(col_names['api'])
129        hfc = hdr.index(col_names['header'])
130        for row in rows:
131            api = row[apic]
132            header = row[hfc]
133            if len(api) == 0 or len(header) == 0:
134                continue
135            if header not in cdata['headers']:
136                cdata['headers'][header] = [api]
137            else:
138                cdata['headers'][header] += [api]
139            if api in cdata['apis']:
140                raise error('duplicate api: %s' % (api))
141            cdata['apis'][api] = row
142        self.data = cdata
143
144    def summary(self, standard = 'RTEMS'):
145        results = { }
146        for header in self.data['headers']:
147            hr = self.process_header(header, standard)
148            if 'invalid' in hr:
149                error('header contains "invalid": %s' % (header))
150            for cat in hr:
151                if cat not in results:
152                    results[cat] = len(hr[cat])
153                else:
154                    results[cat] += len(hr[cat])
155        if standard == 'RTEMS':
156            std_line = 'The follow table summarizes RTEMS supported' \
157                       ' methods for all tracked standards:'
158        else:
159            std_line = 'The follow table summarizes alignment with ' \
160                       'the %s standard:' % (standard_names[standard])
161        s = ['Summary',
162             '=======',
163             '',
164             std_line,
165             '']
166        cols = [0, 1]
167        for cat in categories['order']:
168            if len(categories['name'][cat]) > cols[0]:
169                cols[0] = len(categories['name'][cat])
170            if cat in results:
171                num = '%d' % results[cat]
172                if len(num) > cols[1]:
173                    cols[1] = len(num)
174        table_def = ' %s  %s' % ('=' * cols[0], '=' * cols[1])
175        s += [table_def]
176        for cat in categories['order']:
177            if cat in results:
178                s += [' %-*s  %d' % (cols[0], categories['name'][cat], results[cat])]
179            else:
180                s += [' %-*s  %d' % (cols[0], categories['name'][cat], 0)]
181        s += [table_def, '']
182        return s
183
184    def output(self, standard = 'RTEMS'):
185        def _category_filter(text, patterns):
186            for l in range(0, len(text)):
187                for pat in patterns:
188                    if pat in text[l]:
189                        text[l] = text[l].replace(pat, patterns[pat])
190            return text
191
192        if standard not in standards:
193            error('invalid standard": %s' % (standard))
194        s = rst_defaults['header'] + self.summary(standard)
195        for header in sorted(self.data['headers'].keys()):
196            hr = self.process_header(header, standard)
197            if 'invalid' in hr:
198                error('header contains "invalid": %s' % (header))
199            print_heading = True
200            for cat in categories['order']:
201                if cat in hr:
202                    if print_heading:
203                        s += ['``<%s>``' % (header),
204                              '=' * (len(header) + 2),
205                              '']
206                        print_heading = False
207                    patterns = { '@HEADER@': header }
208                    cat_text = copy.copy(categories[cat])
209                    _category_filter(cat_text, patterns)
210                    s += cat_text
211                    for api in hr[cat]:
212                        s += ['* ``%s``' % (api)]
213                    s += ['']
214        return s
215
216    def process_header(self, header, standard = 'RTEMS'):
217        results = { }
218        if standard != 'RTEMS':
219            std_col = self.data['columns'].index(col_names[standard])
220        else:
221            std_col = -1
222        for api in sorted(self.data['headers'][header]):
223            api_row = self.data['apis'][api]
224            if std_col > 0:
225                if api_row[std_col] != 'INCL':
226                    continue
227            state = 'invalid'
228            for test in cat_columns['order']:
229                col = self.data['columns'].index(col_names[test])
230                value = api_row[col]
231                for test_state in cat_columns[test]:
232                    if value in cat_columns[test][test_state]:
233                        if state in cat_columns[test][test_state][value]:
234                            state = test_state
235            if state not in results:
236                results[state] = [api]
237            else:
238                results[state] += [api]
239        return results
240
241if __name__ == "__main__":
242    try:
243        import pprint
244        pp = pprint.PrettyPrinter(indent=2)
245        if len(sys.argv) != 2:
246            raise error('not enough arguments')
247        c = compliance()
248        c.load(sys.argv[1])
249        for h in sorted(c.data['headers']):
250            print('-- %s' % (h), '-' * 50)
251            hr = c.process_header(h)
252            if 'invalid' in hr:
253                error('header contains invalid: %s' % (h))
254            hr = c.process_header(h, 'PSE51')
255            if 'invalid' in hr:
256                error('header contains invalid: %s' % (h))
257            pp.pprint(hr)
258        print('=' * 80)
259        print(os.linesep.join(c.output('PSE51')))
260        print('=' * 80)
261        print(os.linesep.join(c.output()))
262        for s in standards:
263            print('=-' * 40)
264            print(os.linesep.join(c.summary(s)))
265    except error as e:
266        print('error: %s' % (e), file = sys.stderr)
Note: See TracBrowser for help on using the repository browser.