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