blob: dc237817004f48ad973ef06d37f963403a6d9daa [file] [log] [blame]
Vernon Mauery0d0cd162020-01-31 10:04:10 -08001#!/usr/bin/env python3
2
3import re, sys, os.path
4
5def usage():
Vernon Mauery8b7c1562022-09-27 16:10:38 -07006 sys.stderr.write("Usage: $0 allowlist-config-in allowlist-header-out\n")
7 sys.stderr.write(" Reads in allowlist config, sorting the contents\n")
Vernon Mauery0d0cd162020-01-31 10:04:10 -08008 sys.stderr.write(" and outputs a header file\n")
9 sys.exit(-1)
10
11class Error(Exception):
12 pass
13
14class DuplicateEntry(Error):
15 def __init__(self, e):
16 super(Error, self).__init__(
17 "Multiple entries with matching netfn/cmd found ({})".format(e))
18
19class ParseError(Error):
20 def __init__(self, d):
21 super(Error, self).__init__("Parse error at: '{}'".format(d))
22
23class entry:
24 linere = re.compile(
25 r'(0x[0-9a-f]{2}):(0x[0-9a-f]{2})((:(0x[0-9a-f]{4}))?)\s*((//\s*(.*))?)',
26 re.I
27 )
28 def __init__(self, data):
29 # parse data line into values:
30 # type 1, two values: netfn, cmd
31 # type 2, three values: netfn, cmd, channels
32 try:
33 m = self.linere.fullmatch(data).groups()
34 except:
35 raise ParseError(data)
36 self.netfn = int(m[0], 16)
37 self.cmd = int(m[1], 16)
38 if m[4] is not None:
39 self.channels = int(m[4], 16)
40 else:
41 # if no channel was provided, default to previous behavior, which
42 # is allow all interfaces, including the system interface (ch 15)
43 self.channels = 0xffff
44 if m[6] is not None:
45 self.comment = "// " + m[7]
46 else:
47 self.comment = "//"
48 def __str__(self):
49 return " ".join([ '{',
50 "0x{0.netfn:02x},".format(self),
51 "0x{0.cmd:02x},".format(self),
52 "0x{0.channels:04x}".format(self),
53 "},",
54 "{0.comment}".format(self),
55 ])
56 def __lt__(self, other):
57 if self.netfn == other.netfn:
58 return self.cmd < other.cmd
59 return self.netfn < other.netfn
60 def match(self, other):
61 return (self.netfn == other.netfn) and (self.cmd == other.cmd)
62
63def parse(config):
64 entries = []
65 with open(config) as f:
66 for line in f:
67 line = line.strip()
68 if len(line) == 0 or line[0] == '#':
69 continue
70 e = entry(line)
71 if any([e.match(item) for item in entries]):
72 d = DuplicateEntry(e)
73 sys.stderr.write("WARNING: {}\n".format(d))
74 else:
75 entries.append(e)
76 entries.sort()
77 return entries
78
79def output(entries, hppfile):
80 lines = [
81 "#pragma once",
82 "",
83 "// AUTOGENERATED FILE; DO NOT MODIFY",
84 "",
85 "#include <array>",
86 "#include <tuple>",
87 "",
88 "using netfncmd_tuple = std::tuple<unsigned char, unsigned char, unsigned short>;",
89 "",
Vernon Mauery8b7c1562022-09-27 16:10:38 -070090 "constexpr const std::array<netfncmd_tuple, {}> allowlist = ".format(
Vernon Mauery0d0cd162020-01-31 10:04:10 -080091 len(entries)),
92 "{{"
93 ]
94 lines.extend([' {}'.format(e) for e in entries])
95 lines.append("}};\n");
96
97 with open(hppfile, "w") as hpp:
98 hpp.write("\n".join(lines))
99
100
101if __name__ == "__main__":
102 if len(sys.argv) != 3:
103 usage()
104 config = sys.argv[1]
105 header = sys.argv[2]
106 entries = parse(config)
107 output(entries, header)