1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0-only 3 4import os 5import glob 6import re 7import argparse 8 9 10def parse_of_declare_macros(data): 11 """ Find all compatible strings in OF_DECLARE() style macros """ 12 compat_list = [] 13 # CPU_METHOD_OF_DECLARE does not have a compatible string 14 for m in re.finditer(r'(?<!CPU_METHOD_)(IRQCHIP|OF)_(DECLARE|MATCH)(_DRIVER)?\(.*?\)', data): 15 try: 16 compat = re.search(r'"(.*?)"', m[0])[1] 17 except: 18 # Fails on compatible strings in #define, so just skip 19 continue 20 compat_list += [compat] 21 22 return compat_list 23 24 25def parse_of_device_id(data): 26 """ Find all compatible strings in of_device_id structs """ 27 compat_list = [] 28 for m in re.finditer(r'of_device_id\s+[a-zA-Z0-9_]+\[\]\s*=\s*({.*?);', data): 29 compat_list += re.findall(r'\.compatible\s+=\s+"([a-zA-Z0-9_\-,]+)"', m[1]) 30 31 return compat_list 32 33 34def parse_compatibles(file): 35 with open(file, 'r', encoding='utf-8') as f: 36 data = f.read().replace('\n', '') 37 38 compat_list = parse_of_declare_macros(data) 39 compat_list += parse_of_device_id(data) 40 41 return compat_list 42 43def print_compat(filename, compatibles): 44 if not compatibles: 45 return 46 if show_filename: 47 compat_str = ' '.join(compatibles) 48 print(filename + ": compatible(s): " + compat_str) 49 else: 50 print(*compatibles, sep='\n') 51 52show_filename = False 53 54if __name__ == "__main__": 55 ap = argparse.ArgumentParser() 56 ap.add_argument("cfile", type=str, nargs='*', help="C source files or directories to parse") 57 ap.add_argument('-H', '--with-filename', help="Print filename with compatibles", action="store_true") 58 args = ap.parse_args() 59 60 show_filename = args.with_filename 61 62 for f in args.cfile: 63 if os.path.isdir(f): 64 for filename in glob.iglob(f + "/**/*.c", recursive=True): 65 compat_list = parse_compatibles(filename) 66 print_compat(filename, compat_list) 67 else: 68 compat_list = parse_compatibles(f) 69 print_compat(f, compat_list) 70