Select Git revision
modnetwork.c
-
Damien George authored
This follows the pattern of how all other headers are now included, and makes it explicit where the header file comes from. This patch also removes -I options from Makefile's that specify the mp-readline/timeutils/ netutils directories, which are no longer needed.
Damien George authoredThis follows the pattern of how all other headers are now included, and makes it explicit where the header file comes from. This patch also removes -I options from Makefile's that specify the mp-readline/timeutils/ netutils directories, which are no longer needed.
genapi.py 4.77 KiB
import argparse
import contextlib
import os
import re
import subprocess
def main():
parser = argparse.ArgumentParser(
description="Generate the API stubs from a header file."
)
parser.add_argument(
"-H", "--header", required=True, help="The header to base the definitions on."
)
parser.add_argument(
"-c", "--client", required=True, help="The output client-side c source file."
)
parser.add_argument(
"-s", "--server", required=True, help="The output server-side c source file."
)
args = parser.parse_args()
with contextlib.ExitStack() as cx:
# Run the preprocessor on the header file to get the API definitions.
#
# For this, we first need a source to include the header which contains
# an alternative definition of the `API` macro that marks definitions in
# a way we can find later on.
api_src = """\
#define API(id, def) __GENERATE_API $ __GEN_ID_##id $ def $
#include "{header}"
""".format(
header=os.path.relpath(args.header)
)
# Evaluate the preprocessor
source = subprocess.check_output(
["gcc", "-E", "-"], input=api_src.encode()
).decode()
# Parse the header for API definitions
matcher = re.compile(
r"__GENERATE_API \$ __GEN_ID_(?P<id>\w+) \$ void (?P<decl>.+?)\((?P<args>.*?)\) \$",
re.DOTALL | re.MULTILINE,
)
args_matcher = re.compile(r"(?P<type>\w+(?:\*+|\s+))(?P<name>\w+),")
# Open output files
f_client = cx.enter_context(open(args.client, "w"))
f_server = cx.enter_context(open(args.server, "w"))
print('#include "{}"\n'.format(os.path.basename(args.header)), file=f_client)
print(
"""\
#include "{}"
void __api_dispatch_call(uint32_t id, void*buffer)
{{
switch (id) {{""".format(
os.path.basename(args.header)
),
file=f_server,
)
for match in matcher.finditer(source):
api_id = match.group("id")
api_decl = match.group("decl")
api_args = match.group("args")
api_args_names = []
api_args_types = []
api_args_sizes = []
# Destructure args
for match in args_matcher.finditer(api_args + ","):
arg_type = match.group("type").strip()
arg_name = match.group("name")
api_args_names.append(arg_name)
api_args_types.append(arg_type)
api_args_sizes.append("sizeof({})".format(arg_type))
print(
"""\
/* Autogenerated stub for {id} */
void {cdecl}({cargs})
{{
const int size = {total_size};
void*buffer;
buffer = api_call_start({id}, size);
/* TODO: Check if buffer is no NULL */
""".format(
id=api_id,
cdecl=api_decl,
cargs=api_args,
total_size=" + ".join(api_args_sizes),
),
file=f_client,
)
print(
"""\
case {id}:
{cdecl}(""".format(
id=api_id, cdecl=api_decl
),
file=f_server,
)
for i, (arg, ty) in enumerate(zip(api_args_names, api_args_types)):
print(
""" *({type}*)(buffer + {offset}) = {arg};""".format(
type=ty,
offset=" + ".join(api_args_sizes[:i]) if i > 0 else "0",
arg=arg,
),
file=f_client,
)
if i != 0:
print(",", file=f_server)
print(
"""\
*({type}*)(buffer + {offset})""".format(
type=ty, offset=" + ".join(api_args_sizes[:i]) if i > 0 else "0"
),
file=f_server,
end="",
)
print(
"""
);
break;""".format(
cdecl=api_decl, args=", ".join(api_args_names)
),
file=f_server,
)
print(
"""
printf("Sending call {id}\\nBUF: ");
for (int i = 0; i < size; i++) {{
printf("0x%02x ", ((char*)buffer)[i]);
}}
printf("\\n");
api_call_bother_dispatcher(buffer);
}}
""".format(
id=api_id
),
file=f_client,
)
print(
"""\
default:
printf("Error: API function %x is unknown!!\\n", {id});
break;
}}
}}""".format(
id=api_id
),
file=f_server,
)
if __name__ == "__main__":
main()