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 8import sys 9import os 10import re 11 12SRC_FILE_LIST = [] 13USED_COMPONENT = {} 14KNOWN_COMPONENT = {} 15 16SRC_FILE_DIRS = ["src"] 17TRACE_DEF_FILES = ["include/freetype/internal/fttrace.h"] 18 19 20def 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# 40for 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 53c_pathname_pat = re.compile('^.*\.[ch]$', re.IGNORECASE) 54trace_use_pat = re.compile('^[ \t]*#define[ \t]+FT_COMPONENT[ \t]+') 55 56for 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 79trace_def_pat_opn = re.compile('^.*FT_TRACE_DEF[ \t]*\([ \t]*') 80trace_def_pat_cls = re.compile('[ \t\)].*$') 81 82for 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 103print("# Trace component used in the implementations but not defined in " 104 "fttrace.h.") 105cmpnt = list(USED_COMPONENT.keys()) 106cmpnt.sort() 107for 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 112print("# Trace component is defined but not used in the implementations.") 113cmpnt = list(KNOWN_COMPONENT.keys()) 114cmpnt.sort() 115for 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])) 120