1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0-only 3 4import fnmatch 5import os 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+\S+)?\s+\S+\[\](\s+\S+)?\s*=\s*({.*?);', data): 29 compat_list += re.findall(r'\.compatible\s+=\s+"(\S+)"', m[3]) 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 52def glob_without_symlinks(root, glob): 53 for path, dirs, files in os.walk(root): 54 # Ignore hidden directories 55 for d in dirs: 56 if fnmatch.fnmatch(d, ".*"): 57 dirs.remove(d) 58 for f in files: 59 if fnmatch.fnmatch(f, glob): 60 yield os.path.join(path, f) 61 62def files_to_parse(path_args): 63 for f in path_args: 64 if os.path.isdir(f): 65 for filename in glob_without_symlinks(f, "*.c"): 66 yield filename 67 else: 68 yield f 69 70show_filename = False 71 72if __name__ == "__main__": 73 ap = argparse.ArgumentParser() 74 ap.add_argument("cfile", type=str, nargs='*', help="C source files or directories to parse") 75 ap.add_argument('-H', '--with-filename', help="Print filename with compatibles", action="store_true") 76 args = ap.parse_args() 77 78 show_filename = args.with_filename 79 80 for f in files_to_parse(args.cfile): 81 compat_list = parse_compatibles(f) 82 print_compat(f, compat_list) 83