| #!/usr/bin/env python3 |
| # |
| # Check trace components in FreeType 2 source. |
| # Author: suzuki toshiya, 2009, 2013, 2020 |
| # |
| # This code is explicitly into the public domain. |
| |
| import sys |
| import os |
| import re |
| |
| SRC_FILE_LIST = [] |
| USED_COMPONENT = {} |
| KNOWN_COMPONENT = {} |
| |
| SRC_FILE_DIRS = ["src"] |
| TRACE_DEF_FILES = ["include/freetype/internal/fttrace.h"] |
| |
| |
| def usage(): |
| print("Usage: %s [option]" % sys.argv[0]) |
| print("Search used-but-defined and defined-but-not-used trace_XXX macros") |
| print("") |
| print(" --help:") |
| print(" Show this help") |
| print("") |
| print(" --src-dirs=dir1:dir2:...") |
| print(" Specify the directories of C source files to be checked") |
| print(" Default is %s" % ":".join(SRC_FILE_DIRS)) |
| print("") |
| print(" --def-files=file1:file2:...") |
| print(" Specify the header files including FT_TRACE_DEF()") |
| print(" Default is %s" % ":".join(TRACE_DEF_FILES)) |
| print("") |
| |
| |
| # -------------------------------------------------------------- |
| # Parse command line options |
| # |
| for i in range(1, len(sys.argv)): |
| if sys.argv[i].startswith("--help"): |
| usage() |
| exit(0) |
| if sys.argv[i].startswith("--src-dirs="): |
| SRC_FILE_DIRS = sys.argv[i].replace("--src-dirs=", "", 1).split(":") |
| elif sys.argv[i].startswith("--def-files="): |
| TRACE_DEF_FILES = sys.argv[i].replace("--def-files=", "", 1).split(":") |
| |
| # -------------------------------------------------------------- |
| # Scan C source and header files using trace macros. |
| # |
| |
| c_pathname_pat = re.compile('^.*\.[ch]$', re.IGNORECASE) |
| trace_use_pat = re.compile('^[ \t]*#define[ \t]+FT_COMPONENT[ \t]+') |
| |
| for d in SRC_FILE_DIRS: |
| for (p, dlst, flst) in os.walk(d): |
| for f in flst: |
| if c_pathname_pat.match(f) is not None: |
| src_pathname = os.path.join(p, f) |
| |
| line_num = 0 |
| for src_line in open(src_pathname, 'r'): |
| line_num = line_num + 1 |
| src_line = src_line.strip() |
| if trace_use_pat.match(src_line) is not None: |
| component_name = trace_use_pat.sub('', src_line) |
| if component_name in USED_COMPONENT: |
| USED_COMPONENT[component_name]\ |
| .append("%s:%d" % (src_pathname, line_num)) |
| else: |
| USED_COMPONENT[component_name] =\ |
| ["%s:%d" % (src_pathname, line_num)] |
| |
| # -------------------------------------------------------------- |
| # Scan header file(s) defining trace macros. |
| # |
| |
| trace_def_pat_opn = re.compile('^.*FT_TRACE_DEF[ \t]*\([ \t]*') |
| trace_def_pat_cls = re.compile('[ \t\)].*$') |
| |
| for f in TRACE_DEF_FILES: |
| line_num = 0 |
| for hdr_line in open(f, 'r'): |
| line_num = line_num + 1 |
| hdr_line = hdr_line.strip() |
| if trace_def_pat_opn.match(hdr_line) is not None: |
| component_name = trace_def_pat_opn.sub('', hdr_line) |
| component_name = trace_def_pat_cls.sub('', component_name) |
| if component_name in KNOWN_COMPONENT: |
| print("trace component %s is defined twice," |
| " see %s and fttrace.h:%d" % |
| (component_name, KNOWN_COMPONENT[component_name], |
| line_num)) |
| else: |
| KNOWN_COMPONENT[component_name] =\ |
| "%s:%d" % (os.path.basename(f), line_num) |
| |
| # -------------------------------------------------------------- |
| # Compare the used and defined trace macros. |
| # |
| |
| print("# Trace component used in the implementations but not defined in " |
| "fttrace.h.") |
| cmpnt = list(USED_COMPONENT.keys()) |
| cmpnt.sort() |
| for c in cmpnt: |
| if c not in KNOWN_COMPONENT: |
| print("Trace component %s (used in %s) is not defined." % |
| (c, ", ".join(USED_COMPONENT[c]))) |
| |
| print("# Trace component is defined but not used in the implementations.") |
| cmpnt = list(KNOWN_COMPONENT.keys()) |
| cmpnt.sort() |
| for c in cmpnt: |
| if c not in USED_COMPONENT: |
| if c != "any": |
| print("Trace component %s (defined in %s) is not used." % |
| (c, KNOWN_COMPONENT[c])) |