162306a36Sopenharmony_ci#!/usr/bin/env python3
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0-only
362306a36Sopenharmony_ci
462306a36Sopenharmony_ciimport fnmatch
562306a36Sopenharmony_ciimport os
662306a36Sopenharmony_ciimport re
762306a36Sopenharmony_ciimport argparse
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci
1062306a36Sopenharmony_cidef parse_of_declare_macros(data):
1162306a36Sopenharmony_ci	""" Find all compatible strings in OF_DECLARE() style macros """
1262306a36Sopenharmony_ci	compat_list = []
1362306a36Sopenharmony_ci	# CPU_METHOD_OF_DECLARE does not have a compatible string
1462306a36Sopenharmony_ci	for m in re.finditer(r'(?<!CPU_METHOD_)(IRQCHIP|OF)_(DECLARE|MATCH)(_DRIVER)?\(.*?\)', data):
1562306a36Sopenharmony_ci		try:
1662306a36Sopenharmony_ci			compat = re.search(r'"(.*?)"', m[0])[1]
1762306a36Sopenharmony_ci		except:
1862306a36Sopenharmony_ci			# Fails on compatible strings in #define, so just skip
1962306a36Sopenharmony_ci			continue
2062306a36Sopenharmony_ci		compat_list += [compat]
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	return compat_list
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cidef parse_of_device_id(data):
2662306a36Sopenharmony_ci	""" Find all compatible strings in of_device_id structs """
2762306a36Sopenharmony_ci	compat_list = []
2862306a36Sopenharmony_ci	for m in re.finditer(r'of_device_id(\s+\S+)?\s+\S+\[\](\s+\S+)?\s*=\s*({.*?);', data):
2962306a36Sopenharmony_ci		compat_list += re.findall(r'\.compatible\s+=\s+"(\S+)"', m[3])
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	return compat_list
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cidef parse_compatibles(file):
3562306a36Sopenharmony_ci	with open(file, 'r', encoding='utf-8') as f:
3662306a36Sopenharmony_ci		data = f.read().replace('\n', '')
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	compat_list = parse_of_declare_macros(data)
3962306a36Sopenharmony_ci	compat_list += parse_of_device_id(data)
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	return compat_list
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cidef print_compat(filename, compatibles):
4462306a36Sopenharmony_ci	if not compatibles:
4562306a36Sopenharmony_ci		return
4662306a36Sopenharmony_ci	if show_filename:
4762306a36Sopenharmony_ci		compat_str = ' '.join(compatibles)
4862306a36Sopenharmony_ci		print(filename + ": compatible(s): " + compat_str)
4962306a36Sopenharmony_ci	else:
5062306a36Sopenharmony_ci		print(*compatibles, sep='\n')
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cidef glob_without_symlinks(root, glob):
5362306a36Sopenharmony_ci	for path, dirs, files in os.walk(root):
5462306a36Sopenharmony_ci		# Ignore hidden directories
5562306a36Sopenharmony_ci		for d in dirs:
5662306a36Sopenharmony_ci			if fnmatch.fnmatch(d, ".*"):
5762306a36Sopenharmony_ci				dirs.remove(d)
5862306a36Sopenharmony_ci		for f in files:
5962306a36Sopenharmony_ci			if fnmatch.fnmatch(f, glob):
6062306a36Sopenharmony_ci				yield os.path.join(path, f)
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cidef files_to_parse(path_args):
6362306a36Sopenharmony_ci	for f in path_args:
6462306a36Sopenharmony_ci		if os.path.isdir(f):
6562306a36Sopenharmony_ci			for filename in glob_without_symlinks(f, "*.c"):
6662306a36Sopenharmony_ci				yield filename
6762306a36Sopenharmony_ci		else:
6862306a36Sopenharmony_ci			yield f
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cishow_filename = False
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ciif __name__ == "__main__":
7362306a36Sopenharmony_ci	ap = argparse.ArgumentParser()
7462306a36Sopenharmony_ci	ap.add_argument("cfile", type=str, nargs='*', help="C source files or directories to parse")
7562306a36Sopenharmony_ci	ap.add_argument('-H', '--with-filename', help="Print filename with compatibles", action="store_true")
7662306a36Sopenharmony_ci	args = ap.parse_args()
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	show_filename = args.with_filename
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	for f in files_to_parse(args.cfile):
8162306a36Sopenharmony_ci		compat_list = parse_compatibles(f)
8262306a36Sopenharmony_ci		print_compat(f, compat_list)
83