import re
import os
import sys
from typing import List
ITEM_RE = re.compile(
r"[ \t]*(?P<nr_range>\d+(-\d+)?)[ \t]+(?P<aue>AUE_[A-Z0-9a-z_]+)[ \t]+(?P<type>[A-Z0-9]+([ \t]*\|[ \t]*[A-Z0-9]+)*)[ \t]*"
r"(\{\s*\w+(\s+|\s*(\*)?\s*)(?P<name>\w+)\s*\([^{}]*?\)(\s*NO_SYSCALL_STUB)?\s*;\s*\}(\s*\{[^}]+\}|([ \t]+(?P<altname>\w+)([ \t+]\w+){0,2})?)?|[^{\n]*)?\s+"
)
NICE_OS_NAMES = {
"freebsd": "FreeBSD",
"macos": "macOS",
}
NICE_ARCH_NAMES = {
"x86_64": "x86-64",
"powerpc": "PowerPC",
"powerpc64": "PowerPC64",
"mips": "MIPS",
"mips64": "MIPS64",
"sparc64": "SPARC64",
}
def main(args: List[str]) -> None:
if len(args) != 2:
print("Usage: {} <syscalls.master file> <OS name>".format(sys.argv[0]))
sys.exit(1)
repo_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
syscalls_fname = args[0]
os_name = args[1]
arches = [
name[len(os_name) + 1 :]
for name in os.listdir(os.path.join(repo_path, "src/platform"))
if name.startswith(os_name + "-")
]
text = ""
with open(syscalls_fname) as file:
for line in file:
line = line.strip()
if line and not line.startswith(
("$", ";", "#include", "#if", "#ifdef", "#else", "#endif", "%%")
):
text += line + "\n"
syscalls = []
scanner = ITEM_RE.scanner(text)
for match in iter(scanner.match, None):
nr_range = match.group("nr_range")
sc_types = [name.strip() for name in match.group("type").split("|")]
name = (match.group("name") or "").upper()
altname = (match.group("altname") or "").upper()
if sc_types == ["RESERVED"]:
continue
if "-" in nr_range:
assert not name
continue
nr = int(nr_range)
if nr == 0 and name in ("NOSYS", "ENOSYS"):
name = "SYSCALL"
if os_name == "freebsd":
if name.startswith("__") and name != "__SYSCALL":
name = name[2:]
if not name:
continue
if name in ("NOSYS", "ENOSYS"):
if altname:
name = altname
else:
continue
if os_name == "freebsd":
name = {
"SYS_EXIT": "EXIT",
}.get(name, name)
if "COMPAT" in sc_types:
continue
for sc_type in sc_types:
if sc_type.startswith("COMPAT"):
name = "FREEBSD{}_{}".format(int(sc_type[6:]), name)
break
elif os_name == "macos":
name = {
"SYSCTL": "__SYSCTL",
}.get(name, name)
if name.startswith("SYS_"):
name = name[4:]
syscalls.append((name, nr))
for arch in arches:
fpath = os.path.join(repo_path, "src/platform", os_name + "-" + arch, "nr.rs")
with open(fpath, "w") as file:
file.write(
"//! System call numbers for {} {}.\n\n".format(
NICE_ARCH_NAMES.get(arch, arch), NICE_OS_NAMES[os_name]
)
)
file.write("/* Automatically generated by bsd_nr_from_src.py */\n\n")
for (name, nr) in syscalls:
file.write("pub const {}: usize = {};\n".format(name, nr))
if __name__ == "__main__":
main(sys.argv[1:])