#!/usr/bin/env python3 import re import sys def usage(): sys.stderr.write("Usage: $0 allowlist-config-in allowlist-header-out\n") sys.stderr.write(" Reads in allowlist config, sorting the contents\n") sys.stderr.write(" and outputs a header file\n") sys.exit(-1) class Error(Exception): pass class DuplicateEntry(Error): def __init__(self, e): super(Error, self).__init__( "Multiple entries with matching netfn/cmd found ({})".format(e) ) class ParseError(Error): def __init__(self, d): super(Error, self).__init__("Parse error at: '{}'".format(d)) class entry: linere = re.compile( r"(0x[0-9a-f]{2}):(0x[0-9a-f]{2})((:(0x[0-9a-f]{4}))?)\s*((//\s*(.*))?)", # noqa: E501 re.I, ) def __init__(self, data): # parse data line into values: # type 1, two values: netfn, cmd # type 2, three values: netfn, cmd, channels try: m = self.linere.fullmatch(data).groups() except Exception: raise ParseError(data) self.netfn = int(m[0], 16) self.cmd = int(m[1], 16) if m[4] is not None: self.channels = int(m[4], 16) else: # if no channel was provided, default to previous behavior, which # is allow all interfaces, including the system interface (ch 15) self.channels = 0xFFFF if m[6] is not None: self.comment = "// " + m[7] else: self.comment = "//" def __str__(self): return " ".join( [ "{", "0x{0.netfn:02x},".format(self), "0x{0.cmd:02x},".format(self), "0x{0.channels:04x}".format(self), "},", "{0.comment}".format(self), ] ) def __lt__(self, other): if self.netfn == other.netfn: return self.cmd < other.cmd return self.netfn < other.netfn def match(self, other): return (self.netfn == other.netfn) and (self.cmd == other.cmd) def parse(config): entries = [] with open(config) as f: for line in f: line = line.strip() if len(line) == 0 or line[0] == "#": continue e = entry(line) if any([e.match(item) for item in entries]): d = DuplicateEntry(e) sys.stderr.write("WARNING: {}\n".format(d)) else: entries.append(e) entries.sort() return entries def output(entries, hppfile): lines = [ "#pragma once", "", "// AUTOGENERATED FILE; DO NOT MODIFY", "", "#include <array>", "#include <tuple>", "", ( "using netfncmd_tuple = std::tuple<unsigned char, unsigned char," " unsigned short>;" ), "", "constexpr const std::array<netfncmd_tuple, {}> allowlist = ".format( len(entries) ), "{{", ] lines.extend([" {}".format(e) for e in entries]) lines.append("}};\n") with open(hppfile, "w") as hpp: hpp.write("\n".join(lines)) if __name__ == "__main__": if len(sys.argv) != 3: usage() config = sys.argv[1] header = sys.argv[2] entries = parse(config) output(entries, header)