blob: 4160287f221c57c61127b759d44f7ef6863694a2 [file] [log] [blame]
Mateusz Starzyk0d41abb2021-05-12 14:48:40 +02001import re
2import fileinput
3import glob
4import pprint
5import os
6import xml.etree.ElementTree as ET
7
8
9files_to_visit = {}
10
11struct_files = glob.glob("apidoc/xml/structmbedtls*.xml") + glob.glob("apidoc/xml/structpsa*.xml")
12
13for struct_file in struct_files:
14 struct_file_tree = ET.parse(struct_file)
15 all_struct_members_definitions = struct_file_tree.getroot().findall(".//memberdef[@kind='variable']")
16
17 # Create dictionary with following structre
18 # "filepath" : { "variable_name1": (1, 2, 40, 61), # line numbers
19 # "variable_name2": (60, 64),
20 # }
21 for struct_member_def in all_struct_members_definitions:
22 # find file path for this variable
23 member_id = struct_member_def.attrib["id"]
24 location = struct_member_def.find("location")
25 file_path = location.attrib["file"]
26 variable_name = struct_member_def.find("name").text
27 # if path not yet in dictionary, create empty record to initialize
28 if file_path not in files_to_visit:
29 files_to_visit[file_path] = {}
30 # if variable is not yet in this file's dictionary, create empty set to initialize
31 if variable_name not in files_to_visit[file_path]:
32 files_to_visit[file_path][variable_name] = set()
33
34 # add variable definition
35 files_to_visit[file_path][variable_name].add(int(location.attrib["line"]))
36
37 # check where the variable was referenced
38 references = struct_member_def.findall("referencedby")
39 for reference in references:
40 refid = reference.attrib["refid"]
41 # assuming that compound name is related to header's xml file
42 header_file = "apidoc/xml/" + reference.attrib["compoundref"] + ".xml"
43 header_file_tree = ET.parse(header_file)
44 # check if this reference is created by static inline function
45 static_inline_function_definition = header_file_tree.getroot().find(f".//memberdef[@id='{refid}'][@kind='function'][@static='yes'][@inline='yes']")
46 if static_inline_function_definition:
47 static_inline_function_file_path = static_inline_function_definition.find("location").attrib["file"]
48 # if path not yet in dictionary, create empty record to initialize.
49 # This could happen if reference is inside header file which was not yet processed in search for variable definitions
50 if static_inline_function_file_path not in files_to_visit:
51 files_to_visit[static_inline_function_file_path] = {}
52 # if variable is not yet in this file's dictionary, create empty set to initialize
53 if variable_name not in files_to_visit[static_inline_function_file_path]:
54 files_to_visit[static_inline_function_file_path][variable_name] = set()
55 # function block scope
56 function_lines_from = int(reference.attrib["startline"])
57 function_lines_to = int(reference.attrib["endline"])
58 # find codelines referencing struct's variable
59 codelines_xml = header_file_tree.getroot().findall(f".//ref[@refid='{member_id}']/../..")
60 # filter by function's scope
61 codelines = [int(line.attrib["lineno"]) for line in codelines_xml if int(line.attrib["lineno"]) >= function_lines_from and int(line.attrib["lineno"]) <= function_lines_to]
62 # add variable reference
63 files_to_visit[static_inline_function_file_path][variable_name].update(codelines)
64
65pp = pprint.PrettyPrinter(indent=4)
66pp.pprint(files_to_visit)
67
68for file_path, variables in files_to_visit.items():
69 with fileinput.FileInput(file_path, inplace=True) as file:
70 output_line_number = 1
71 re_include_guard = re.compile(r"^#define.*{name}$".format(name=os.path.basename(file_path).replace('.','_').upper()))
72 for line in file:
73 insert_allow_private_include = False
74 if re_include_guard.match(line):
75 insert_allow_private_include = True
76 for variable, var_lines in variables.items():
77 for var_line in var_lines:
78 if output_line_number == var_line:
79 line = re.sub(r"(^.*?\W+)({var})(\W+.*$)".format(var=variable), r"\1MBEDTLS_PRIVATE(\2)\3", line)
80 output_line_number += 1
81 print(line, end='') # fileinput redirects stdout to the target file
82 if insert_allow_private_include:
83 insert_allow_private_include = False
84 print("#include \"mbedtls/private_access.h\"")