mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-04-25 00:02:27 +00:00
234 lines
7.2 KiB
Python
Executable File
234 lines
7.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import os, sys, getopt, re
|
|
|
|
class State:
|
|
SearchTitle = 0
|
|
SearchEndTitle = 1
|
|
SearchStartAPI = 2
|
|
SearchEndAPI = 3
|
|
DoneAPI = 4
|
|
|
|
|
|
def isEndOfComment(line):
|
|
parts = re.match(r'\s*\*\/.*', line)
|
|
if parts:
|
|
return True
|
|
return False
|
|
|
|
|
|
def isStartOfComment(line):
|
|
parts = re.match(r'\s*\/\*\*.*', line)
|
|
if parts:
|
|
return True
|
|
return False
|
|
|
|
|
|
def isComment(line):
|
|
parts = re.match(r'\s*\/\/.*', line)
|
|
if parts:
|
|
return True
|
|
parts = re.match(r'\s*\*.*', line)
|
|
if parts:
|
|
return True
|
|
|
|
return isStartOfComment(line) or isEndOfComment(line)
|
|
|
|
|
|
def isTypedefStart(line):
|
|
return re.match(r'.*typedef\s+struct.*', line)
|
|
|
|
|
|
def filename_stem(filepath):
|
|
return os.path.splitext(os.path.basename(filepath))[0]
|
|
|
|
|
|
def clean_text(text):
|
|
return re.sub(r'\s+', ' ', text).strip()
|
|
|
|
|
|
def validate_function(name, text):
|
|
if text.startswith('#define'):
|
|
print("Error: function name with #define: ", name)
|
|
return False
|
|
if name in ['PBAP_FEATURES_NOT_PRESENT', 'PROFILE_FEATURES_NOT_PRESENT', 'Q7_TO_FLOAT', '_attribute__']:
|
|
print("Error: function name with reserved name: ", name)
|
|
return False
|
|
if '\t' in name:
|
|
print("Error: function name with tabs: ", name)
|
|
return False
|
|
if "PGM_" in text:
|
|
return False
|
|
return True
|
|
|
|
|
|
def parse_header(header_filepath):
|
|
'''
|
|
Parses a header file to extract function definitions and typedefs.
|
|
:param path:
|
|
:return: (title, functions, typedefs)
|
|
|
|
This function reads a header file, identifies function definitions and typedefs.
|
|
It returns the file @title if found and two dictionaries:
|
|
- functions: A dictionary where keys are function names and values are (function signature, line number, is_api).
|
|
- typedefs: A dictionary where keys are typedef names and values are their definitions.
|
|
|
|
'''
|
|
|
|
functions = {}
|
|
typedefs = {}
|
|
title = None
|
|
state = State.SearchStartAPI
|
|
multiline_function_name = None
|
|
multiline_function_text = ''
|
|
typedefFound = False
|
|
typedef_text = ''
|
|
multiline_function_terminator = ''
|
|
is_api = False
|
|
|
|
with open(header_filepath, 'rt') as fin:
|
|
for line_num, line in enumerate(fin, start=1):
|
|
|
|
if multiline_function_name:
|
|
multiline_function_text += "\n" + clean_text(line)
|
|
if multiline_function_terminator in line:
|
|
if validate_function(multiline_function_name, multiline_function_text):
|
|
functions[multiline_function_name] = (multiline_function_text, line_num, is_api)
|
|
multiline_function_name = None
|
|
continue
|
|
|
|
if line.startswith('#define'):
|
|
continue
|
|
|
|
if state == State.SearchStartAPI:
|
|
parts = re.match(r'.*API_START.*', line)
|
|
if parts:
|
|
state = State.SearchEndAPI
|
|
is_api = True
|
|
continue
|
|
|
|
if state == State.SearchEndAPI:
|
|
parts = re.match(r'.*API_END.*', line)
|
|
if parts:
|
|
state = State.DoneAPI
|
|
is_api = False
|
|
continue
|
|
|
|
if isComment(line):
|
|
continue
|
|
|
|
param = re.match(r".*@brief.*", line)
|
|
if param:
|
|
continue
|
|
param = re.match(r".*@param.*", line)
|
|
if param:
|
|
continue
|
|
param = re.match(r".*@return.*", line)
|
|
if param:
|
|
continue
|
|
param = re.match(r".*@result.*", line)
|
|
if param:
|
|
continue
|
|
param = re.match(r".*@note.*", line)
|
|
if param:
|
|
continue
|
|
param = re.match(r".*return.*", line)
|
|
if param:
|
|
continue
|
|
|
|
# search typedef struct begin
|
|
if isTypedefStart(line):
|
|
typedefFound = True
|
|
|
|
# search typedef struct end
|
|
if typedefFound:
|
|
typedef = re.match(r'}\s*(.*);\n', line)
|
|
if typedef:
|
|
typedefFound = False
|
|
typdefef_name = typedef.group(1)
|
|
typedefs[typdefef_name] = typedef_text
|
|
typedef_text = ''
|
|
continue
|
|
|
|
# filter callback
|
|
callback_function_definition = re.match(r'(.*?)\s*\(\s*\*.*\(*.*;\n', line)
|
|
if callback_function_definition:
|
|
continue
|
|
|
|
one_line_function_definition = re.match(r'(.*?)\s*\(.*\(*.*;\n', line)
|
|
if one_line_function_definition:
|
|
parts = one_line_function_definition.group(1).split(" ")
|
|
name = parts[len(parts) - 1].replace('*', '')
|
|
if len(name) == 0:
|
|
print(parts)
|
|
sys.exit(10)
|
|
# ignore typedef for callbacks
|
|
if parts[0] == 'typedef':
|
|
continue
|
|
text = clean_text(line)
|
|
if validate_function(name, text):
|
|
functions[name] = (text, line_num, is_api)
|
|
continue
|
|
|
|
multi_line_function_definition = re.match(r'.(.*?)\s*\(.*\(*.*', line)
|
|
if multi_line_function_definition:
|
|
parts = multi_line_function_definition.group(1).split(" ")
|
|
name = parts[len(parts) - 1].replace('*', '')
|
|
if len(name) == 0:
|
|
print(parts)
|
|
sys.exit(10)
|
|
multiline_function_name = name
|
|
multiline_function_text = clean_text(line)
|
|
if line.startswith('static inline'):
|
|
multiline_function_terminator = '};'
|
|
else:
|
|
multiline_function_terminator = ';'
|
|
|
|
|
|
return (title, functions, typedefs)
|
|
|
|
|
|
def dump_typedefs(typedefs):
|
|
for typedef in sorted(typedefs.keys()):
|
|
print(typedef, "--", typedefs[typedef])
|
|
|
|
|
|
def dump_functions(functions):
|
|
for function in sorted(functions.keys()):
|
|
(text, linenr, is_api) = functions[function]
|
|
print('--', function, "--")
|
|
print(linenr, text, '\n')
|
|
|
|
|
|
files_to_ignore = []
|
|
|
|
def main(btstack_root):
|
|
btstack_srcfolder = btstack_root + "/src/"
|
|
|
|
print('BTstack src: ' + btstack_srcfolder)
|
|
|
|
# create a dictionary of header files {file_path : []}
|
|
header_files = {}
|
|
for root, dirs, files in os.walk(btstack_srcfolder, topdown=True):
|
|
for f in files:
|
|
if not f.endswith(".h"):
|
|
continue
|
|
if not root.endswith("/"):
|
|
root = root + "/"
|
|
if f in files_to_ignore:
|
|
continue
|
|
header_filepath = root + f
|
|
with open(header_filepath, 'rt') as fin:
|
|
header_files[header_filepath] = []
|
|
|
|
for header_filepath in sorted(header_files.keys()):
|
|
# get filename without path
|
|
(title, functions, typedefs) = parse_header(header_filepath)
|
|
print("\n\n==== Parsing file: ", header_filepath)
|
|
print("Title: ", title)
|
|
dump_functions(functions)
|
|
# dump_typedefs(typedefs)
|
|
|
|
if __name__ == "__main__":
|
|
btstack_root = os.path.abspath(os.path.dirname(sys.argv[0]) + '/../..')
|
|
main(btstack_root) |