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]))