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

5
Last change on this file since fb72a00 was 1599d99, checked in by Chris Johns <chrisj@…>, on 02/27/19 at 22:16:57

waf: Fix python3 issues.

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