chktrcmp.py (4216B)
1 #!/usr/bin/env python3 2 # 3 # Check trace components in FreeType 2 source. 4 # Author: suzuki toshiya, 2009, 2013, 2020 5 # 6 # This code is explicitly into the public domain. 7 8 import sys 9 import os 10 import re 11 12 SRC_FILE_LIST = [] 13 USED_COMPONENT = {} 14 KNOWN_COMPONENT = {} 15 16 SRC_FILE_DIRS = ["src"] 17 TRACE_DEF_FILES = ["include/freetype/internal/fttrace.h"] 18 19 20 def usage(): 21 print("Usage: %s [option]" % sys.argv[0]) 22 print("Search used-but-defined and defined-but-not-used trace_XXX macros") 23 print("") 24 print(" --help:") 25 print(" Show this help") 26 print("") 27 print(" --src-dirs=dir1:dir2:...") 28 print(" Specify the directories of C source files to be checked") 29 print(" Default is %s" % ":".join(SRC_FILE_DIRS)) 30 print("") 31 print(" --def-files=file1:file2:...") 32 print(" Specify the header files including FT_TRACE_DEF()") 33 print(" Default is %s" % ":".join(TRACE_DEF_FILES)) 34 print("") 35 36 37 # -------------------------------------------------------------- 38 # Parse command line options 39 # 40 for i in range(1, len(sys.argv)): 41 if sys.argv[i].startswith("--help"): 42 usage() 43 exit(0) 44 if sys.argv[i].startswith("--src-dirs="): 45 SRC_FILE_DIRS = sys.argv[i].replace("--src-dirs=", "", 1).split(":") 46 elif sys.argv[i].startswith("--def-files="): 47 TRACE_DEF_FILES = sys.argv[i].replace("--def-files=", "", 1).split(":") 48 49 # -------------------------------------------------------------- 50 # Scan C source and header files using trace macros. 51 # 52 53 c_pathname_pat = re.compile('^.*\.[ch]$', re.IGNORECASE) 54 trace_use_pat = re.compile('^[ \t]*#define[ \t]+FT_COMPONENT[ \t]+') 55 56 for d in SRC_FILE_DIRS: 57 for (p, dlst, flst) in os.walk(d): 58 for f in flst: 59 if c_pathname_pat.match(f) is not None: 60 src_pathname = os.path.join(p, f) 61 62 line_num = 0 63 for src_line in open(src_pathname, 'r'): 64 line_num = line_num + 1 65 src_line = src_line.strip() 66 if trace_use_pat.match(src_line) is not None: 67 component_name = trace_use_pat.sub('', src_line) 68 if component_name in USED_COMPONENT: 69 USED_COMPONENT[component_name]\ 70 .append("%s:%d" % (src_pathname, line_num)) 71 else: 72 USED_COMPONENT[component_name] =\ 73 ["%s:%d" % (src_pathname, line_num)] 74 75 # -------------------------------------------------------------- 76 # Scan header file(s) defining trace macros. 77 # 78 79 trace_def_pat_opn = re.compile('^.*FT_TRACE_DEF[ \t]*\([ \t]*') 80 trace_def_pat_cls = re.compile('[ \t\)].*$') 81 82 for f in TRACE_DEF_FILES: 83 line_num = 0 84 for hdr_line in open(f, 'r'): 85 line_num = line_num + 1 86 hdr_line = hdr_line.strip() 87 if trace_def_pat_opn.match(hdr_line) is not None: 88 component_name = trace_def_pat_opn.sub('', hdr_line) 89 component_name = trace_def_pat_cls.sub('', component_name) 90 if component_name in KNOWN_COMPONENT: 91 print("trace component %s is defined twice," 92 " see %s and fttrace.h:%d" % 93 (component_name, KNOWN_COMPONENT[component_name], 94 line_num)) 95 else: 96 KNOWN_COMPONENT[component_name] =\ 97 "%s:%d" % (os.path.basename(f), line_num) 98 99 # -------------------------------------------------------------- 100 # Compare the used and defined trace macros. 101 # 102 103 print("# Trace component used in the implementations but not defined in " 104 "fttrace.h.") 105 cmpnt = list(USED_COMPONENT.keys()) 106 cmpnt.sort() 107 for c in cmpnt: 108 if c not in KNOWN_COMPONENT: 109 print("Trace component %s (used in %s) is not defined." % 110 (c, ", ".join(USED_COMPONENT[c]))) 111 112 print("# Trace component is defined but not used in the implementations.") 113 cmpnt = list(KNOWN_COMPONENT.keys()) 114 cmpnt.sort() 115 for c in cmpnt: 116 if c not in USED_COMPONENT: 117 if c != "any": 118 print("Trace component %s (defined in %s) is not used." % 119 (c, KNOWN_COMPONENT[c]))