aboutsummaryrefslogtreecommitdiff
path: root/scripts/maint/checkIncludes.py
blob: b96b7f4b34b8e3b6b33faec877d29f9d81159e89 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#!/usr/bin/python3

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):
    def __init__(self):
        self.patterns = []

    def addPattern(self, pattern):
        self.patterns.append(pattern)

    def includeOk(self, path):
        for pattern in self.patterns:
            if fnmatch.fnmatchcase(path, pattern):
                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))

def load_include_rules(fname):
    result = Rules()
    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

for dirpath, dirnames, fnames in os.walk("src"):
    if ".may_include" in fnames:
        rules = load_include_rules(os.path.join(dirpath, RULES_FNAME))
        for fname in fnames:
            if fname_is_c(fname):
                rules.applyToFile(os.path.join(dirpath,fname))

if trouble:
    err(
"""To change which includes are allowed in a C file, edit the {} files in its
enclosing directory.""".format(RULES_FNAME))