scall 0.2.5

Friendlier raw system calls for Rust.
Documentation
#!/usr/bin/env python3
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:])