2018-06-21 20:02:11 +02:00
|
|
|
#!/usr/bin/python3
|
2018-06-21 20:29:00 +02:00
|
|
|
# Copyright 2018 The Tor Project, Inc. See LICENSE file for licensing info.
|
2018-06-21 20:02:11 +02:00
|
|
|
|
|
|
|
import fnmatch
|
|
|
|
import os
|
|
|
|
import re
|
|
|
|
import sys
|
|
|
|
|
|
|
|
trouble = False
|
|
|
|
|
|
|
|
def err(msg):
|
|
|
|
global trouble
|
|
|
|
trouble = True
|
|
|
|
print(msg, file=sys.stderr)
|
|
|
|
|
|
|
|
def fname_is_c(fname):
|
|
|
|
return fname.endswith(".h") or fname.endswith(".c")
|
|
|
|
|
|
|
|
INCLUDE_PATTERN = re.compile(r'\s*#\s*include\s+"([^"]*)"')
|
|
|
|
RULES_FNAME = ".may_include"
|
|
|
|
|
|
|
|
class Rules(object):
|
2018-07-02 00:14:28 +02:00
|
|
|
def __init__(self, dirpath):
|
|
|
|
self.dirpath = dirpath
|
2018-06-21 20:02:11 +02:00
|
|
|
self.patterns = []
|
2018-07-02 00:14:28 +02:00
|
|
|
self.usedPatterns = set()
|
2018-06-21 20:02:11 +02:00
|
|
|
|
|
|
|
def addPattern(self, pattern):
|
|
|
|
self.patterns.append(pattern)
|
|
|
|
|
|
|
|
def includeOk(self, path):
|
|
|
|
for pattern in self.patterns:
|
|
|
|
if fnmatch.fnmatchcase(path, pattern):
|
2018-07-02 00:14:28 +02:00
|
|
|
self.usedPatterns.add(pattern)
|
2018-06-21 20:02:11 +02:00
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def applyToLines(self, lines, context=""):
|
|
|
|
lineno = 0
|
|
|
|
for line in lines:
|
|
|
|
lineno += 1
|
|
|
|
m = INCLUDE_PATTERN.match(line)
|
|
|
|
if m:
|
|
|
|
include = m.group(1)
|
|
|
|
if not self.includeOk(include):
|
|
|
|
err("Forbidden include of {} on line {}{}".format(
|
|
|
|
include, lineno, context))
|
|
|
|
|
|
|
|
def applyToFile(self, fname):
|
|
|
|
with open(fname, 'r') as f:
|
|
|
|
#print(fname)
|
|
|
|
self.applyToLines(iter(f), " of {}".format(fname))
|
|
|
|
|
2018-07-02 00:14:28 +02:00
|
|
|
def noteUnusedRules(self):
|
|
|
|
for p in self.patterns:
|
|
|
|
if p not in self.usedPatterns:
|
|
|
|
print("Pattern {} in {} was never used.".format(p, self.dirpath))
|
|
|
|
|
2018-06-21 20:02:11 +02:00
|
|
|
def load_include_rules(fname):
|
2018-07-02 00:14:28 +02:00
|
|
|
result = Rules(os.path.split(fname)[0])
|
2018-06-21 20:02:11 +02:00
|
|
|
with open(fname, 'r') as f:
|
|
|
|
for line in f:
|
|
|
|
line = line.strip()
|
|
|
|
if line.startswith("#") or not line:
|
|
|
|
continue
|
|
|
|
result.addPattern(line)
|
|
|
|
return result
|
|
|
|
|
2018-07-02 00:14:28 +02:00
|
|
|
list_unused = False
|
|
|
|
|
2018-06-21 20:02:11 +02:00
|
|
|
for dirpath, dirnames, fnames in os.walk("src"):
|
|
|
|
if ".may_include" in fnames:
|
|
|
|
rules = load_include_rules(os.path.join(dirpath, RULES_FNAME))
|
2018-06-26 18:04:24 +02:00
|
|
|
for fname in fnames:
|
|
|
|
if fname_is_c(fname):
|
|
|
|
rules.applyToFile(os.path.join(dirpath,fname))
|
2018-07-02 00:14:28 +02:00
|
|
|
if list_unused:
|
|
|
|
rules.noteUnusedRules()
|
2018-06-21 20:02:11 +02:00
|
|
|
|
|
|
|
if trouble:
|
|
|
|
err(
|
|
|
|
"""To change which includes are allowed in a C file, edit the {} files in its
|
|
|
|
enclosing directory.""".format(RULES_FNAME))
|
2018-06-21 20:29:00 +02:00
|
|
|
sys.exit(1)
|