|
| 1 | +""" |
| 2 | +Read definitions from /usr/include/systemd/sd-messages.h and systemd/id128-defines.h files, convert to ones in systemd/id128-constants.h |
| 3 | +""" |
| 4 | + |
| 5 | +import os |
| 6 | +import re |
1 | 7 | import sys |
| 8 | +import itertools |
| 9 | +import argparse |
| 10 | +from pathlib import Path |
| 11 | +from collections.abc import Iterable |
| 12 | +from typing import cast |
| 13 | + |
| 14 | + |
| 15 | +REGEX_DEFINE = re.compile(r'^#define\s+(?P<name>SD_MESSAGE_[A-Z0-9_]+)\s+\w+') |
| 16 | + |
| 17 | + |
| 18 | +parser = argparse.ArgumentParser(description="Convert systemd header definitions to id128 constants.") |
| 19 | +parser.add_argument('-i', '--include-dir', type=Path, required=True, help='Path to libsystemd include directory') |
| 20 | +parser.add_argument('-s', '--source-dir', type=Path, required=True, help='Path to C source directory') |
| 21 | +args = parser.parse_args() |
2 | 22 |
|
3 | | -for file in sys.argv[1:]: |
4 | | - lines = iter(open(file).read().splitlines()) |
| 23 | + |
| 24 | +def extract_define_lines(file_path: Path) -> list[str]: |
| 25 | + lines = iter(file_path.open().readlines()) |
| 26 | + out: list[str] = [] |
5 | 27 | for line in lines: |
6 | 28 | if line.startswith('#define SD_MESSAGE') and '_STR ' not in line: |
7 | 29 | if line.endswith('\\'): |
8 | 30 | line = line[:-1] + next(lines) |
9 | | - print(' '.join(line.split())) |
| 31 | + out.append(' '.join(line.split())) |
| 32 | + return out |
| 33 | + |
| 34 | + |
| 35 | +def extract_symbol(line: str) -> str: |
| 36 | + """ |
| 37 | + Extract the symbol name from a line defining a constant. |
| 38 | +
|
| 39 | + For example, given the line: |
| 40 | + #define SD_MESSAGE_USER_STARTUP_FINISHED SD_ID128_MAKE(ee,d0,0a,68,ff,d8,4e,31,88,21,05,fd,97,3a,bd,d1) |
| 41 | + this function will return: |
| 42 | + SD_MESSAGE_USER_STARTUP_FINISHED |
| 43 | + or empty string if the line does not match the expected format. |
| 44 | + """ |
| 45 | + if match := REGEX_DEFINE.match(line): |
| 46 | + return match.group('name') |
| 47 | + return '' |
| 48 | + |
| 49 | + |
| 50 | +def build_line_for_constant(name: str) -> str: |
| 51 | + return f'add_id(m, "{name}", {name}) JOINER' |
| 52 | + |
| 53 | + |
| 54 | +def update_docs(source_dir: Path, symbols: Iterable[str]): |
| 55 | + doc_file = source_dir.joinpath('../docs/id128.rst') |
| 56 | + headers = doc_file.read_text().splitlines()[:9] |
| 57 | + lines = [f' .. autoattribute:: systemd.id128.{s}' for s in symbols] |
| 58 | + new_content = '\n'.join(headers + lines) + '\n' |
| 59 | + doc_file.write_text(new_content) |
| 60 | + rel_doc_path = doc_file.resolve().relative_to(Path('.').resolve(), walk_up=True) |
| 61 | + print(f'Updated {rel_doc_path}.', file=sys.stderr) |
| 62 | + |
| 63 | + |
| 64 | +def main(): |
| 65 | + source_files = [cast(Path, args.include_dir).joinpath('systemd/sd-messages.h'), cast(Path, args.source_dir).joinpath('id128-defines.h')] |
| 66 | + print(f'To extract symbols from {source_files}...', file=sys.stderr) |
| 67 | + source_lines = tuple(itertools.chain.from_iterable(extract_define_lines(file) for file in source_files)) |
| 68 | + print(f'Read {len(source_lines)} lines.', file=sys.stderr) |
| 69 | + symbols = tuple(sorted(frozenset(s for line in source_lines if (s := extract_symbol(line))))) |
| 70 | + print(f'Found {len(symbols)} unique symbols.', file=sys.stderr) |
| 71 | + converted_lines = tuple(build_line_for_constant(s) for s in symbols) |
| 72 | + print(f'Converted to {len(converted_lines)} lines.', file=sys.stderr) |
| 73 | + dest_file = cast(Path, args.source_dir).joinpath('id128-constants.h') |
| 74 | + dest_file.write_text('\n'.join(converted_lines) + '\n') |
| 75 | + print(f'Wrote {len(converted_lines)} constants to {dest_file}.', file=sys.stderr) |
| 76 | + update_docs(cast(Path, args.source_dir), symbols) |
| 77 | + print('🎉 Done.', file=sys.stderr) |
| 78 | + |
| 79 | + |
| 80 | +if __name__ == '__main__': |
| 81 | + main() |
0 commit comments