blob: a0530b9c7b4e1a7c962e86da3fadffc4255062a0 [file] [log] [blame]
Simon Hein169de2c2023-07-25 10:35:11 +02001#!/usr/bin/env python3
2
3# Copyright (c) 2023 Baumer (www.baumer.com)
4# SPDX-License-Identifier: Apache-2.0
5
6"""This script converting the Zephyr coding guideline rst file to a output file,
7or print the output to the console. Which than can be used by a tool which
8needs to have that information in a specific format (e.g. for cppcheck).
9Or simply use the rule list to generate a filter to suppress all other rules
10used by default from such a tool.
11"""
12
13import sys
14import re
15import argparse
16from pathlib import Path
17
18class RuleFormatter:
19 """
20 Base class for the different output formats
21 """
22 def table_start_print(self, outputfile):
23 pass
24 def severity_print(self, outputfile, guideline_number, severity):
25 pass
26 def description_print(self, outputfile, guideline_number, description):
27 pass
28 def closing_print(self, outputfile):
29 pass
30
31class CppCheckFormatter(RuleFormatter):
32 """
33 Formatter class to print the rules in a format which can be used by cppcheck
34 """
35 def table_start_print(self, outputfile):
36 # Start search by cppcheck misra addon
37 print('Appendix A Summary of guidelines', file=outputfile)
38
39 def severity_print(self, outputfile, guideline_number, severity):
40 print('Rule ' + guideline_number + ' ' + severity, file=outputfile)
41
42 def description_print(self, outputfile, guideline_number, description):
43 print(description + '(Misra rule ' + guideline_number + ')', file=outputfile)
44
45 def closing_print(self, outputfile):
46 # Make cppcheck happy by starting the appendix
47 print('Appendix B', file=outputfile)
48 print('', file=outputfile)
49
50def convert_guidelines(args):
51 inputfile = args.input
52 outputfile = sys.stdout
53 formatter = None
54
55 # If the output is not empty, open the given file for writing
56 if args.output is not None:
57 outputfile = open(args.output, "w")
58
59 try:
60 file_stream = open(inputfile, 'rt', errors='ignore')
61 except Exception:
62 print('Error opening ' + inputfile +'.')
63 sys.exit()
64
65 # Set formatter according to the used format
66 if args.format == 'cppcheck':
67 formatter = CppCheckFormatter()
68
69 # Search for table named Main rules
70 pattern_table_start = re.compile(r'.*list-table:: Main rules')
71 # Each Rule is a new table column so start with '[tab]* - Rule'
72 # Ignore directives here
73 pattern_new_line = re.compile(r'^ \* - Rule ([0-9]+.[0-9]+).*$')
74 # Each table column start with '[tab]- '
75 pattern_new_col = re.compile(r'^ - (.*)$')
76
77 table_start = False
78 guideline_number = ''
79 guideline_state = 0
80 guideline_list = []
81
82 for line in file_stream:
83
84 line = line.replace('\r', '').replace('\n', '')
85
86 # Done if we find the Additional rules table start
87 if line.find('Additional rules') >= 0:
88 break
89
90 if len(line) == 0:
91 continue
92
93 if not table_start:
94 res = pattern_table_start.match(line)
95 if res:
96 table_start = True
97 formatter.table_start_print(outputfile)
98 continue
99
100 res = pattern_new_line.match(line)
101 if res:
102 guideline_state = "severity"
103 guideline_number = res.group(1)
104 guideline_list.append(guideline_number)
105 continue
106 elif guideline_number == '':
107 continue
108
109 res = pattern_new_col.match(line)
110 if res:
111 if guideline_state == "severity":
112 # Severity
113 formatter.severity_print(outputfile, guideline_number, res.group(1))
114 guideline_state = "description"
115 continue
116 if guideline_state == "description":
117 # Description
118 formatter.description_print(outputfile, guideline_number, res.group(1))
119 guideline_state = "None"
120 # We stop here for now, we do not handle the CERT C col
121 guideline_number = ''
122 continue
123
124 formatter.closing_print(outputfile)
125
126if __name__ == "__main__":
127 supported_formats = ['cppcheck']
128
129 parser = argparse.ArgumentParser(allow_abbrev=False)
130 parser.add_argument(
131 "-i", "--input", metavar="RST_FILE", type=Path, required=True,
132 help="Path to rst input source file, where the guidelines are written down."
133 )
134 parser.add_argument(
135 "-f", "--format", metavar="FORMAT", choices=supported_formats, required=True,
136 help="Format to convert guidlines to. Supported formats are: " + str(supported_formats)
137 )
138 parser.add_argument(
139 "-o", "--output", metavar="OUTPUT_FILE", type=Path, required=False,
140 help="Path to output file, where the converted guidelines are written to. If outputfile is not specified, print to stdout."
141 )
142 args = parser.parse_args()
143
144 convert_guidelines(args)