Files
Max Wash 26a49162e6 toolchain: replace ifc interface compiler with xpcg
xpcg is used to generate xpc interfaces
2026-03-10 19:12:14 +00:00

1129 lines
25 KiB
C

#include "../../backend.h"
#include "../../interface.h"
#include "../../msg.h"
#include "../../type.h"
#include <blue/core/hash.h>
#include <blue/io/file.h>
#include <blue/io/path.h>
#include <stdarg.h>
#include <stddef.h>
struct emit_ctx {
b_stream *ctx_out;
size_t ctx_max_handle_params;
};
static void emit(struct emit_ctx *ctx, const char *format, ...)
{
va_list arg;
va_start(arg, format);
b_stream_write_vfmt(ctx->ctx_out, NULL, format, arg);
va_end(arg);
}
static void emit_indent(struct emit_ctx *ctx)
{
b_stream_push_indent(ctx->ctx_out, 4);
}
static void emit_indent_zero(struct emit_ctx *ctx)
{
b_stream_push_indent(ctx->ctx_out, -100);
}
static void emit_unindent(struct emit_ctx *ctx)
{
b_stream_pop_indent(ctx->ctx_out);
}
static int emit_include(struct emit_ctx *ctx, const char *path, bool system)
{
if (system) {
emit(ctx, "#include <%s>\n", path);
} else {
emit(ctx, "#include \"%s\"\n", path);
}
return 0;
}
static int emit_header_guard_start(
struct emit_ctx *ctx,
const struct interface_definition *iface)
{
b_string *header_guard = b_string_create();
b_string_append_cstrf(header_guard, "%s_H_", iface->if_name);
b_string_toupper(header_guard);
emit(ctx,
"#ifndef %s\n#define %s\n\n",
b_string_ptr(header_guard),
b_string_ptr(header_guard));
b_string_unref(header_guard);
return 0;
}
static int emit_header_guard_end(
struct emit_ctx *ctx,
const struct interface_definition *iface)
{
emit(ctx, "\n#endif");
return 0;
}
static size_t get_msg_handle_params(const struct msg_definition *msg)
{
size_t count = 0;
b_queue_entry *entry = b_queue_first(&msg->msg_params);
while (entry) {
const struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
if (param->p_type->ty_id == TYPE_HANDLE) {
count++;
}
entry = b_queue_next(entry);
}
return count;
}
static size_t get_max_handle_params(const struct interface_definition *iface)
{
size_t count = 0;
b_queue_entry *entry = b_queue_first(&iface->if_msg);
while (entry) {
const struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
size_t msg_count = get_msg_handle_params(msg);
if (msg_count > count) {
count = msg_count;
}
entry = b_queue_next(entry);
}
return count;
}
static int emit_interface_id_macros(
struct emit_ctx *ctx,
const struct interface_definition *iface)
{
b_string *iface_define_name = b_string_create();
b_string_append_cstr(iface_define_name, iface->if_name);
b_string_toupper(iface_define_name);
uint32_t protocol_id = iface->if_id;
emit(ctx,
"/* %s protocol ID */\n#define INTERFACE_%s 0x%08xU\n\n",
iface->if_name,
b_string_ptr(iface_define_name),
protocol_id);
b_string_unref(iface_define_name);
b_string *msg_name = b_string_create();
b_queue_entry *entry = b_queue_first(&iface->if_msg);
while (entry) {
const struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
b_string_clear(msg_name);
b_string_append_cstrf(
msg_name,
"%s.%s",
iface->if_name,
msg->msg_name);
emit(ctx, "/* %s message ID */\n", b_string_ptr(msg_name));
uint16_t msg_id = msg->msg_id;
b_string_clear(msg_name);
b_string_append_cstrf(
msg_name,
"%s_%s",
iface->if_name,
msg->msg_name);
b_string_toupper(msg_name);
emit(ctx,
"#define MSG_%s 0x%04xU\n",
b_string_ptr(msg_name),
msg_id);
entry = b_queue_next(entry);
}
emit(ctx, "\n");
b_string_unref(msg_name);
return 0;
}
static int emit_msg_struct_member(
struct emit_ctx *ctx,
const struct msg_parameter *param)
{
switch (param->p_type->ty_id) {
case TYPE_INT:
emit(ctx, "uint32_t %s;\n", param->p_name);
break;
case TYPE_HANDLE:
emit(ctx, "kern_handle_t %s;\n", param->p_name);
break;
case TYPE_SIZE:
emit(ctx, "uint64_t %s;\n", param->p_name);
break;
case TYPE_STRING:
case TYPE_BUFFER:
emit(ctx, "uint16_t %s_offset;\n", param->p_name);
emit(ctx, "uint16_t %s_len;\n", param->p_name);
break;
default:
break;
}
return 0;
}
static int emit_msg_struct_params(
struct emit_ctx *ctx,
const struct msg_definition *msg)
{
b_queue_entry *entry = b_queue_first(&msg->msg_params);
while (entry) {
const struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
emit_msg_struct_member(ctx, param);
entry = b_queue_next(entry);
}
entry = b_queue_first(&msg->msg_results);
while (entry) {
const struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_STRING:
emit(ctx, "uint16_t %s_offset;\n", param->p_name);
emit(ctx, "uint16_t %s_max;\n", param->p_name);
break;
case TYPE_BUFFER:
emit(ctx, "uint16_t %s_offset;\n", param->p_name);
emit(ctx, "uint32_t %s_max;\n", param->p_name);
break;
default:
break;
}
entry = b_queue_next(entry);
}
return 0;
}
static int emit_msg_struct_results(
struct emit_ctx *ctx,
const struct msg_definition *msg)
{
b_queue_entry *entry = b_queue_first(&msg->msg_results);
while (entry) {
const struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
emit_msg_struct_member(ctx, param);
entry = b_queue_next(entry);
}
return 0;
}
static int emit_interface_msg_struct(
struct emit_ctx *ctx,
const struct interface_definition *iface,
const struct msg_definition *msg)
{
b_string *tmp = b_string_create();
emit(ctx, "struct %s_%s_msg {\n", iface->if_name, msg->msg_name);
emit_indent(ctx);
emit(ctx, "xpc_msg_header_t msg_header;\n");
emit(ctx, "union {\n");
emit_indent(ctx);
/* msg_request inner struct */
emit(ctx, "struct {\n");
emit_indent(ctx);
emit_msg_struct_params(ctx, msg);
emit_unindent(ctx);
emit(ctx, "} msg_request;\n");
/* msg_response inner struct */
emit(ctx, "struct {\n");
emit_indent(ctx);
emit_msg_struct_results(ctx, msg);
emit_unindent(ctx);
emit(ctx, "} msg_response;\n");
emit_unindent(ctx);
emit(ctx, "};\n");
emit_unindent(ctx);
emit(ctx, "};\n");
b_string_unref(tmp);
return 0;
}
static int emit_interface_msg_structs(
struct emit_ctx *ctx,
const struct interface_definition *iface)
{
b_queue_entry *entry = b_queue_first(&iface->if_msg);
while (entry) {
const struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
emit_interface_msg_struct(ctx, iface, msg);
entry = b_queue_next(entry);
}
emit(ctx, "\n");
return 0;
}
static int emit_interface_msg_function_send_impl(
struct emit_ctx *ctx,
const struct interface_definition *iface,
const struct msg_definition *msg)
{
b_string *iface_ucase = b_string_create_from_cstr(iface->if_name);
b_string_toupper(iface_ucase);
b_string *msg_ucase = b_string_create_from_cstr(msg->msg_name);
b_string_toupper(msg_ucase);
emit(ctx,
"struct %s_%s_msg msg_data = {0};\n",
iface->if_name,
msg->msg_name);
emit(ctx,
"xpc_msg_header_init(&msg_data.msg_header, INTERFACE_%s, "
"MSG_%s_%s);\n",
b_string_ptr(iface_ucase),
b_string_ptr(iface_ucase),
b_string_ptr(msg_ucase));
b_string_unref(iface_ucase);
b_string_unref(msg_ucase);
emit(ctx, "uint32_t in_offset = sizeof msg_data;\n\n");
emit(ctx, "uint32_t out_offset = sizeof msg_data;\n\n");
size_t nr_req_handles = 0;
size_t nr_resp_handles = 0;
b_queue_entry *entry = b_queue_first(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_INT:
case TYPE_SIZE:
emit(ctx,
"msg_data.msg_request.%s = %s;\n\n",
param->p_name,
param->p_name);
break;
case TYPE_HANDLE:
emit(ctx,
"msg_data.msg_request.%s = %zu;\n",
param->p_name,
nr_req_handles);
nr_req_handles++;
break;
case TYPE_STRING:
emit(ctx,
"msg_data.msg_request.%s_offset = in_offset;\n",
param->p_name);
emit(ctx,
"msg_data.msg_request.%s_len = strlen(%s);\n",
param->p_name,
param->p_name);
emit(ctx,
"in_offset += msg_data.msg_request.%s_len;\n",
param->p_name);
break;
case TYPE_BUFFER:
emit(ctx,
"msg_data.msg_request.%s_offset = offset;\n",
param->p_name);
emit(ctx,
"msg_data.msg_request.%s_len = %s_len;\n",
param->p_name,
param->p_name);
emit(ctx,
"in_offset += msg_data.msg_request.%s_len;\n",
param->p_name);
break;
default:
break;
}
entry = b_queue_next(entry);
}
entry = b_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_STRING:
case TYPE_BUFFER:
emit(ctx,
"msg_data.msg_request.%s_offset = out_offset;\n",
param->p_name,
param->p_name);
emit(ctx,
"msg_data.msg_request.%s_max = out_%s_max;\n",
param->p_name,
param->p_name);
emit(ctx, "out_offset += out_%s_max;\n", param->p_name);
break;
case TYPE_HANDLE:
nr_resp_handles++;
break;
default:
break;
}
entry = b_queue_next(entry);
}
emit(ctx, "kern_iovec_t req_iov[] = {\n");
emit_indent(ctx);
emit(ctx, "IOVEC(&msg_data, sizeof msg_data),\n");
size_t nr_req_iov = 1;
entry = b_queue_first(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_STRING:
case TYPE_BUFFER:
emit(ctx,
"IOVEC(%s, msg_data.msg_request.%s_len),\n",
param->p_name,
param->p_name);
nr_req_iov++;
break;
default:
break;
}
entry = b_queue_next(entry);
}
emit_unindent(ctx);
emit(ctx, "};\n\n");
if (nr_req_handles) {
emit(ctx,
"kern_msg_handle_t req_handles[%zu] = {0};\n",
nr_req_handles);
}
emit(ctx, "kern_iovec_t resp_iov[] = {\n");
emit_indent(ctx);
emit(ctx, "IOVEC(&msg_data, sizeof msg_data),\n");
size_t nr_resp_iov = 1;
entry = b_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_STRING:
case TYPE_BUFFER:
emit(ctx,
"IOVEC(out_%s, out_%s_max),\n",
param->p_name,
param->p_name);
nr_resp_iov++;
break;
default:
break;
}
entry = b_queue_next(entry);
}
emit_unindent(ctx);
emit(ctx, "};\n\n");
if (nr_resp_handles) {
emit(ctx,
"kern_msg_handle_t resp_handles[%zu] = {0};\n",
nr_resp_handles);
}
emit(ctx, "kern_msg_t msg = {\n");
emit_indent(ctx);
emit(ctx, ".msg_data = req_iov,\n.msg_data_count = %zu,\n", nr_req_iov);
if (nr_req_handles) {
emit(ctx,
".msg_handles = req_handles,\n.msg_handles_count = %zu,",
nr_req_handles);
}
emit_unindent(ctx);
emit(ctx, "};\n\n");
emit(ctx, "kern_msg_t reply = {\n");
emit_indent(ctx);
emit(ctx,
".msg_data = resp_iov,\n.msg_data_count = %zu,\n",
nr_resp_iov);
if (nr_resp_handles) {
emit(ctx,
".msg_handles = resp_handles,\n.msg_handles_count = "
"%zu,\n",
nr_resp_handles);
}
emit_unindent(ctx);
emit(ctx, "};\n\n");
emit(ctx, "kern_status_t status = msg_send(port, &msg, &reply);\n");
emit(ctx, "if (status != KERN_OK) return status;\n\n");
emit(ctx,
"if (msg_data.msg_header.hdr_status != KERN_OK) return "
"msg_data.msg_header.hdr_status;\n\n");
entry = b_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_HANDLE:
emit(ctx, "*out_%s = ", param->p_name);
emit(ctx,
"msg_data.msg_response.%s < %zu ",
param->p_name,
nr_resp_handles);
emit(ctx,
"? "
"resp_handles[msg_data.msg_response.%s].hnd_"
"value ",
param->p_name);
emit(ctx, ": KERN_HANDLE_INVALID;\n");
break;
case TYPE_BUFFER:
case TYPE_STRING:
break;
default:
emit(ctx,
"*out_%s = msg_data.msg_response.%s;\n",
param->p_name,
param->p_name);
break;
}
entry = b_queue_next(entry);
}
emit(ctx, "return status;\n");
return 0;
}
static int emit_interface_msg_function_send(
struct emit_ctx *ctx,
const struct interface_definition *iface,
const struct msg_definition *msg,
bool prototype_only)
{
if (prototype_only) {
emit(ctx, "extern ");
}
emit(ctx, "kern_status_t %s_%s(\n", iface->if_name, msg->msg_name);
emit_indent(ctx);
emit(ctx, "kern_handle_t port");
b_queue_entry *entry = b_queue_first(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
emit(ctx, ",\n");
switch (param->p_type->ty_id) {
case TYPE_INT:
emit(ctx, "int %s", param->p_name);
break;
case TYPE_HANDLE:
emit(ctx, "kern_handle_t %s", param->p_name);
break;
case TYPE_SIZE:
emit(ctx, "size_t %s", param->p_name);
break;
case TYPE_STRING:
emit(ctx, "const char *%s", param->p_name);
break;
case TYPE_BUFFER:
emit(ctx,
"const void *%s, size_t %s_len",
param->p_name,
param->p_name);
default:
break;
}
entry = b_queue_next(entry);
}
entry = b_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
emit(ctx, ",\n");
switch (param->p_type->ty_id) {
case TYPE_INT:
emit(ctx, "int *out_%s", param->p_name);
break;
case TYPE_SIZE:
emit(ctx, "size_t *out_%s", param->p_name);
break;
case TYPE_HANDLE:
emit(ctx, "kern_handle_t *out_%s", param->p_name);
break;
case TYPE_STRING:
emit(ctx,
"char *out_%s,\nsize_t out_%s_max",
param->p_name,
param->p_name);
break;
case TYPE_BUFFER:
emit(ctx,
"void *out_%s,\nsize_t out_%s_max",
param->p_name,
param->p_name);
break;
default:
break;
}
entry = b_queue_next(entry);
}
emit(ctx, ")");
emit_unindent(ctx);
if (prototype_only) {
emit(ctx, ";\n");
return 0;
}
emit(ctx, "\n{\n");
emit_indent(ctx);
emit_interface_msg_function_send_impl(ctx, iface, msg);
emit_unindent(ctx);
emit(ctx, "}\n\n");
return 0;
}
static int emit_interface_dispatcher_impl_msg(
struct emit_ctx *ctx,
const struct interface_definition *iface,
const struct msg_definition *msg)
{
#define MSG_STRUCT_NAME "__data"
#define MSG_STRUCT_OFFSET_NAME "__data_offset"
emit(ctx,
"if (!vtable->%s) return xpc_msg_reply_error(msg, "
"KERN_UNIMPLEMENTED);\n",
msg->msg_name);
emit(ctx,
"struct %s_%s_msg " MSG_STRUCT_NAME " = {0};\n",
iface->if_name,
msg->msg_name);
emit(ctx,
"status = xpc_msg_read(msg, 0, &" MSG_STRUCT_NAME
", sizeof " MSG_STRUCT_NAME ");\n");
b_queue_entry *entry = b_queue_first(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_INT:
emit(ctx,
"int %s = " MSG_STRUCT_NAME ".msg_request.%s;\n",
param->p_name,
param->p_name);
break;
case TYPE_SIZE:
emit(ctx,
"size_t %s = " MSG_STRUCT_NAME
".msg_request.%s;\n",
param->p_name,
param->p_name);
break;
case TYPE_STRING:
emit(ctx,
"xpc_string_t %s = "
"XPC_STRING_IN(msg, " MSG_STRUCT_NAME
".msg_request.%s_offset, " MSG_STRUCT_NAME
".msg_request.%s_len);\n",
param->p_name,
param->p_name,
param->p_name);
break;
case TYPE_BUFFER:
emit(ctx,
"xpc_string_t %s = "
"XPC_BUFFER_IN(msg, " MSG_STRUCT_NAME
".msg_request.%s_offset, " MSG_STRUCT_NAME
".msg_request.%s_len);\n",
param->p_name,
param->p_name,
param->p_name);
break;
default:
break;
}
entry = b_queue_next(entry);
}
entry = b_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_INT:
emit(ctx, "int %s = 0;\n", param->p_name);
break;
case TYPE_SIZE:
emit(ctx, "size_t %s = 0;\n", param->p_name);
break;
case TYPE_HANDLE:
emit(ctx,
"kern_handle_t %s = KERN_HANDLE_INVALID;\n",
param->p_name);
break;
case TYPE_STRING:
emit(ctx,
"xpc_string_t %s = "
"XPC_STRING_OUT(msg, " MSG_STRUCT_NAME
".msg_request.%s_offset, " MSG_STRUCT_NAME
".msg_request.%s_max);\n",
param->p_name,
param->p_name,
param->p_name);
break;
case TYPE_BUFFER:
emit(ctx,
"xpc_buffer_t %s = "
"XPC_BUFFER_OUT(msg, " MSG_STRUCT_NAME
".msg_request.%s_offset, " MSG_STRUCT_NAME
".msg_request.%s_max);\n",
param->p_name,
param->p_name,
param->p_name);
break;
default:
break;
}
entry = b_queue_next(entry);
}
emit(ctx, "status = vtable->%s(\n", msg->msg_name);
emit_indent(ctx);
emit(ctx, "ctx,\n&msg->msg_sender");
entry = b_queue_first(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_STRING:
case TYPE_BUFFER:
emit(ctx, ",\n&%s", param->p_name);
break;
default:
emit(ctx, ",\n%s", param->p_name);
break;
}
entry = b_queue_next(entry);
}
entry = b_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
emit(ctx, ",\n&%s", param->p_name);
entry = b_queue_next(entry);
}
emit(ctx, ",\narg);\n");
emit_unindent(ctx);
emit(ctx,
"if (status != KERN_OK) return xpc_msg_reply_error(msg, "
"status);\n");
emit(ctx, MSG_STRUCT_NAME ".msg_header.hdr_status = 0;\n");
size_t handle_index = 0;
entry = b_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_INT:
emit(ctx,
MSG_STRUCT_NAME ".msg_response.%s = %s;\n",
param->p_name,
param->p_name);
break;
case TYPE_HANDLE:
emit(ctx,
MSG_STRUCT_NAME ".msg_response.%s = %zu;\n",
param->p_name,
handle_index);
handle_index++;
break;
default:
break;
}
entry = b_queue_next(entry);
}
emit(ctx,
"kern_iovec_t iov = IOVEC(&" MSG_STRUCT_NAME
", sizeof " MSG_STRUCT_NAME ");\n");
emit(ctx, "kern_msg_handle_t out_handles[] = {\n");
emit_indent(ctx);
entry = b_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
switch (param->p_type->ty_id) {
case TYPE_HANDLE:
emit(ctx,
"MSG_HANDLE(KERN_MSG_HANDLE_MOVE, %s),\n",
param->p_name);
break;
default:
break;
}
entry = b_queue_next(entry);
}
emit_unindent(ctx);
emit(ctx, "};\n");
emit(ctx,
"status = xpc_msg_reply(msg, &iov, 1, out_handles, sizeof "
"out_handles / sizeof out_handles[0]);\n");
return 0;
}
static int emit_interface_dispatcher_impl(
struct emit_ctx *ctx,
const struct interface_definition *iface)
{
b_string *iface_ucase = b_string_create_from_cstr(iface->if_name);
b_string_toupper(iface_ucase);
b_string *msg_ucase = b_string_create();
emit(ctx,
"if (msg->msg_header.hdr_interface != INTERFACE_%s) return "
"KERN_INVALID_ARGUMENT;\n\n",
b_string_ptr(iface_ucase));
emit(ctx, "kern_status_t status = KERN_OK;\n");
emit(ctx, "switch (msg->msg_header.hdr_func) {\n");
b_queue_entry *entry = b_queue_first(&iface->if_msg);
while (entry) {
const struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
b_string_clear(msg_ucase);
b_string_append_cstr(msg_ucase, msg->msg_name);
b_string_toupper(msg_ucase);
emit(ctx,
"case MSG_%s_%s: {\n",
b_string_ptr(iface_ucase),
b_string_ptr(msg_ucase));
emit_indent(ctx);
emit_interface_dispatcher_impl_msg(ctx, iface, msg);
emit(ctx, "break;\n");
emit_unindent(ctx);
emit(ctx, "}\n");
entry = b_queue_next(entry);
}
b_string_unref(iface_ucase);
emit(ctx, "default:\n");
emit_indent(ctx);
emit(ctx, "status = KERN_INVALID_ARGUMENT;\nbreak;\n");
emit_unindent(ctx);
emit(ctx, "}\n\nreturn status;\n");
return 0;
}
static int emit_interface_dispatcher(
struct emit_ctx *ctx,
const struct interface_definition *iface,
bool prototype_only)
{
if (prototype_only) {
emit(ctx, "extern ");
}
emit(ctx, "kern_status_t %s_dispatch(\n", iface->if_name);
emit_indent(ctx);
emit(ctx, "xpc_context_t *ctx,\n");
emit(ctx, "const xpc_msg_t *msg,\n");
emit(ctx, "const struct %s_vtable *vtable,\n", iface->if_name);
emit(ctx, "void *arg)");
emit_unindent(ctx);
if (prototype_only) {
emit(ctx, ";\n");
return 0;
}
emit(ctx, "\n{\n");
emit_indent(ctx);
emit_interface_dispatcher_impl(ctx, iface);
emit_unindent(ctx);
emit(ctx, "}\n\n");
return 0;
}
static int emit_interface_functions(
struct emit_ctx *ctx,
const struct interface_definition *iface,
bool prototype_only)
{
b_queue_entry *entry = b_queue_first(&iface->if_msg);
while (entry) {
const struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
emit_interface_msg_function_send(
ctx,
iface,
msg,
prototype_only);
entry = b_queue_next(entry);
}
emit_interface_dispatcher(ctx, iface, prototype_only);
return 0;
}
static int emit_interface_vtable_entry(
struct emit_ctx *ctx,
const struct interface_definition *iface,
const struct msg_definition *msg)
{
emit(ctx, "kern_status_t(*%s)(\n", msg->msg_name);
emit_indent(ctx);
emit(ctx, "xpc_context_t *ctx,\n");
emit(ctx, "const xpc_endpoint_t *sender");
size_t i = 0;
b_queue_entry *entry = b_queue_first(&msg->msg_params);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
emit(ctx, ",\n");
switch (param->p_type->ty_id) {
case TYPE_INT:
emit(ctx, "int %s", param->p_name);
break;
case TYPE_SIZE:
emit(ctx, "size_t %s", param->p_name);
break;
case TYPE_BUFFER:
emit(ctx, "const xpc_buffer_t *%s", param->p_name);
break;
case TYPE_HANDLE:
emit(ctx, "kern_handle_t %s", param->p_name);
break;
case TYPE_STRING:
emit(ctx, "const xpc_string_t *%s", param->p_name);
break;
default:
break;
}
i++;
entry = b_queue_next(entry);
}
entry = b_queue_first(&msg->msg_results);
while (entry) {
struct msg_parameter *param
= b_unbox(struct msg_parameter, entry, p_entry);
emit(ctx, ",\n");
switch (param->p_type->ty_id) {
case TYPE_INT:
emit(ctx, "int *out_%s", param->p_name);
break;
case TYPE_HANDLE:
emit(ctx, "kern_handle_t *out_%s", param->p_name);
break;
case TYPE_STRING:
emit(ctx, "xpc_string_t *out_%s", param->p_name);
break;
case TYPE_SIZE:
emit(ctx, "size_t *out_%s", param->p_name);
break;
case TYPE_BUFFER:
emit(ctx, "xpc_buffer_t *out_%s", param->p_name);
break;
default:
break;
}
i++;
entry = b_queue_next(entry);
}
if (i > 0) {
emit(ctx, ",\n");
}
emit(ctx, "void *");
emit(ctx, ");\n", msg->msg_name);
emit_unindent(ctx);
return 0;
}
static int emit_interface_vtable(
struct emit_ctx *ctx,
const struct interface_definition *iface)
{
emit(ctx, "struct %s_vtable {\n", iface->if_name);
emit_indent(ctx);
b_queue_entry *entry = b_queue_first(&iface->if_msg);
while (entry) {
const struct msg_definition *msg
= b_unbox(struct msg_definition, entry, msg_entry);
emit_interface_vtable_entry(ctx, iface, msg);
entry = b_queue_next(entry);
}
emit_unindent(ctx);
emit(ctx, "};\n\n");
return 0;
}
static int emit_header(
struct emit_ctx *ctx,
const struct interface_definition *iface)
{
emit_header_guard_start(ctx, iface);
emit_include(ctx, "stdint.h", true);
emit_include(ctx, "stddef.h", true);
emit_include(ctx, "string.h", true);
emit_include(ctx, "xpc/endpoint.h", true);
emit_include(ctx, "xpc/msg.h", true);
emit_include(ctx, "xpc/string.h", true);
emit_include(ctx, "xpc/buffer.h", true);
emit_include(ctx, "xpc/context.h", true);
emit_include(ctx, "mango/msg.h", true);
emit_include(ctx, "mango/types.h", true);
emit(ctx, "\n");
emit_interface_id_macros(ctx, iface);
emit_interface_vtable(ctx, iface);
emit_interface_msg_structs(ctx, iface);
emit_interface_functions(ctx, iface, true);
emit(ctx, "\n#if defined(MSG_IMPLEMENTATION)\n");
emit_interface_functions(ctx, iface, false);
emit(ctx, "#endif\n");
emit_header_guard_end(ctx, iface);
return 0;
}
static int emit_interface(const struct interface_definition *iface)
{
char path[4096];
b_file *file = NULL;
snprintf(path, sizeof path, "%s.h", iface->if_name);
b_result result = b_file_open(
NULL,
B_RV_PATH(path),
B_FILE_WRITE_ONLY | B_FILE_CREATE,
&file);
if (b_result_is_error(result)) {
b_throw(result);
fprintf(stderr, "cannot create C header file %s\n", path);
return -1;
}
struct emit_ctx ctx = {
.ctx_out = file,
.ctx_max_handle_params = get_max_handle_params(iface),
};
int err = emit_header(&ctx, iface);
b_file_unref(file);
return err;
}
static struct backend backend = {
.b_name = "c-mpc",
.b_emit = emit_interface,
};
const struct backend *c_mpc_backend(void)
{
return &backend;
}