145 lines
4.8 KiB
Python
Executable File
145 lines
4.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# Copyright (c) 2023 Baumer (www.baumer.com)
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
"""This script converting the Zephyr coding guideline rst file to a output file,
|
|
or print the output to the console. Which than can be used by a tool which
|
|
needs to have that information in a specific format (e.g. for cppcheck).
|
|
Or simply use the rule list to generate a filter to suppress all other rules
|
|
used by default from such a tool.
|
|
"""
|
|
|
|
import sys
|
|
import re
|
|
import argparse
|
|
from pathlib import Path
|
|
|
|
class RuleFormatter:
|
|
"""
|
|
Base class for the different output formats
|
|
"""
|
|
def table_start_print(self, outputfile):
|
|
pass
|
|
def severity_print(self, outputfile, guideline_number, severity):
|
|
pass
|
|
def description_print(self, outputfile, guideline_number, description):
|
|
pass
|
|
def closing_print(self, outputfile):
|
|
pass
|
|
|
|
class CppCheckFormatter(RuleFormatter):
|
|
"""
|
|
Formatter class to print the rules in a format which can be used by cppcheck
|
|
"""
|
|
def table_start_print(self, outputfile):
|
|
# Start search by cppcheck misra addon
|
|
print('Appendix A Summary of guidelines', file=outputfile)
|
|
|
|
def severity_print(self, outputfile, guideline_number, severity):
|
|
print('Rule ' + guideline_number + ' ' + severity, file=outputfile)
|
|
|
|
def description_print(self, outputfile, guideline_number, description):
|
|
print(description + '(Misra rule ' + guideline_number + ')', file=outputfile)
|
|
|
|
def closing_print(self, outputfile):
|
|
# Make cppcheck happy by starting the appendix
|
|
print('Appendix B', file=outputfile)
|
|
print('', file=outputfile)
|
|
|
|
def convert_guidelines(args):
|
|
inputfile = args.input
|
|
outputfile = sys.stdout
|
|
formatter = None
|
|
|
|
# If the output is not empty, open the given file for writing
|
|
if args.output is not None:
|
|
outputfile = open(args.output, "w")
|
|
|
|
try:
|
|
file_stream = open(inputfile, 'rt', errors='ignore')
|
|
except Exception:
|
|
print('Error opening ' + inputfile +'.')
|
|
sys.exit()
|
|
|
|
# Set formatter according to the used format
|
|
if args.format == 'cppcheck':
|
|
formatter = CppCheckFormatter()
|
|
|
|
# Search for table named Main rules
|
|
pattern_table_start = re.compile(r'.*list-table:: Main rules')
|
|
# Each Rule is a new table column so start with '[tab]* - Rule'
|
|
# Ignore directives here
|
|
pattern_new_line = re.compile(r'^ \* - Rule ([0-9]+.[0-9]+).*$')
|
|
# Each table column start with '[tab]- '
|
|
pattern_new_col = re.compile(r'^ - (.*)$')
|
|
|
|
table_start = False
|
|
guideline_number = ''
|
|
guideline_state = 0
|
|
guideline_list = []
|
|
|
|
for line in file_stream:
|
|
|
|
line = line.replace('\r', '').replace('\n', '')
|
|
|
|
# Done if we find the Additional rules table start
|
|
if line.find('Additional rules') >= 0:
|
|
break
|
|
|
|
if len(line) == 0:
|
|
continue
|
|
|
|
if not table_start:
|
|
res = pattern_table_start.match(line)
|
|
if res:
|
|
table_start = True
|
|
formatter.table_start_print(outputfile)
|
|
continue
|
|
|
|
res = pattern_new_line.match(line)
|
|
if res:
|
|
guideline_state = "severity"
|
|
guideline_number = res.group(1)
|
|
guideline_list.append(guideline_number)
|
|
continue
|
|
elif guideline_number == '':
|
|
continue
|
|
|
|
res = pattern_new_col.match(line)
|
|
if res:
|
|
if guideline_state == "severity":
|
|
# Severity
|
|
formatter.severity_print(outputfile, guideline_number, res.group(1))
|
|
guideline_state = "description"
|
|
continue
|
|
if guideline_state == "description":
|
|
# Description
|
|
formatter.description_print(outputfile, guideline_number, res.group(1))
|
|
guideline_state = "None"
|
|
# We stop here for now, we do not handle the CERT C col
|
|
guideline_number = ''
|
|
continue
|
|
|
|
formatter.closing_print(outputfile)
|
|
|
|
if __name__ == "__main__":
|
|
supported_formats = ['cppcheck']
|
|
|
|
parser = argparse.ArgumentParser(allow_abbrev=False)
|
|
parser.add_argument(
|
|
"-i", "--input", metavar="RST_FILE", type=Path, required=True,
|
|
help="Path to rst input source file, where the guidelines are written down."
|
|
)
|
|
parser.add_argument(
|
|
"-f", "--format", metavar="FORMAT", choices=supported_formats, required=True,
|
|
help="Format to convert guidlines to. Supported formats are: " + str(supported_formats)
|
|
)
|
|
parser.add_argument(
|
|
"-o", "--output", metavar="OUTPUT_FILE", type=Path, required=False,
|
|
help="Path to output file, where the converted guidelines are written to. If outputfile is not specified, print to stdout."
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
convert_guidelines(args)
|