summaryrefslogtreecommitdiff
path: root/lib9p/core_gen
diff options
context:
space:
mode:
Diffstat (limited to 'lib9p/core_gen')
-rw-r--r--lib9p/core_gen/c.py19
-rw-r--r--lib9p/core_gen/c_fmt_print.py (renamed from lib9p/core_gen/c_format.py)96
-rw-r--r--lib9p/core_gen/c_marshal.py7
-rw-r--r--lib9p/core_gen/c_validate.py20
-rw-r--r--lib9p/core_gen/h.py10
5 files changed, 57 insertions, 95 deletions
diff --git a/lib9p/core_gen/c.py b/lib9p/core_gen/c.py
index 393766b..60ceb70 100644
--- a/lib9p/core_gen/c.py
+++ b/lib9p/core_gen/c.py
@@ -7,7 +7,7 @@ import sys
import idl
-from . import c9util, c_format, c_marshal, c_unmarshal, c_validate, cutil
+from . import c9util, c_fmt_print, c_marshal, c_unmarshal, c_validate, cutil
# This strives to be "general-purpose" in that it just acts on the
# *.9p inputs; but (unfortunately?) there are a few special-cases in
@@ -35,15 +35,6 @@ def gen_c(versions: set[str], typs: list[idl.UserType]) -> str:
#include "core_tables.h"
#include "core_utf8.h"
"""
- # libmisc/obj.h vtables ####################################################
- ret += """
-/* libmisc/obj.h vtables ******************************************************/
-"""
- for typ in typs:
- ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions))
- ret += f"LO_IMPLEMENTATION_C(fmt_formatter, {c9util.typename(typ)}, {c9util.basename(typ)}, static);\n"
- ret += cutil.ifdef_pop(0)
-
# utilities ################################################################
ret += """
/* utilities ******************************************************************/
@@ -111,8 +102,8 @@ def gen_c(versions: set[str], typs: list[idl.UserType]) -> str:
# marshal_* ################################################################
ret += c_marshal.gen_c_marshal(versions, typs)
- # *_format #################################################################
- ret += c_format.gen_c_format(versions, typs)
+ # fmt_print_* ##############################################################
+ ret += c_fmt_print.gen_c_fmt_print(versions, typs)
# tables.h #################################################################
ret += """
@@ -156,8 +147,8 @@ def gen_c(versions: set[str], typs: list[idl.UserType]) -> str:
ret += "\n"
ret += cutil.macro(
f"#define _MSG(typ) [{c9util.Ident('TYP_')}##typ] = {{\n"
- f"\t\t.name = #typ,\n"
- f"\t\t.box_as_fmt_formatter = (_box_as_fmt_formatter_fn_t)lo_box_{c9util.ident('msg_')}##typ##_as_fmt_formatter,\n"
+ f"\t\t.name = #typ,\n"
+ f"\t\t.print = (_print_fn_t)fmt_print_##typ,\n"
f"\t}}\n"
)
ret += msg_table("_msg_tentry", "_table_msg", "_MSG", (0, 0x100, 1))
diff --git a/lib9p/core_gen/c_format.py b/lib9p/core_gen/c_fmt_print.py
index c633fbb..eaacddb 100644
--- a/lib9p/core_gen/c_format.py
+++ b/lib9p/core_gen/c_fmt_print.py
@@ -1,4 +1,4 @@
-# lib9p/core_gen/c_format.py - Generate C pretty-print functions
+# lib9p/core_gen/c_fmt_print.py - Generate C pretty-print functions
#
# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
@@ -6,14 +6,14 @@
import idl
-from . import c9util, cutil
+from . import c9util, cutil, idlutil
# This strives to be "general-purpose" in that it just acts on the
# *.9p inputs; but (unfortunately?) there are a few special-cases in
# this script, marked with "SPECIAL".
# pylint: disable=unused-variable
-__all__ = ["gen_c_format"]
+__all__ = ["gen_c_fmt_print"]
def bf_numname(typ: idl.Bitfield, num: idl.BitNum, base: str) -> str:
@@ -21,46 +21,34 @@ def bf_numname(typ: idl.Bitfield, num: idl.BitNum, base: str) -> str:
return c9util.Ident(c9util.add_prefix(prefix, base))
-def ext_printf(line: str) -> str:
- assert line.startswith("\t")
- assert line.endswith("\n")
- # It sucks that %v trips -Wformat and -Wformat-extra-args
- # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47781
- ret = "#pragma GCC diagnostic push\n"
- ret += '#pragma GCC diagnostic ignored "-Wformat"\n'
- ret += '#pragma GCC diagnostic ignored "-Wformat-extra-args"\n'
- ret += line
- ret += "#pragma GCC diagnostic pop\n"
- return ret
-
-
-def gen_c_format(versions: set[str], typs: list[idl.UserType]) -> str:
+def gen_c_fmt_print(versions: set[str], typs: list[idl.UserType]) -> str:
ret = """
-/* *_format *******************************************************************/
+/* fmt_print_* ****************************************************************/
"""
- for typ in typs:
+ for typ in idlutil.topo_sorted(typs):
ret += "\n"
ret += cutil.ifdef_push(1, c9util.ver_ifdef(typ.in_versions))
- ret += f"static void {c9util.basename(typ)}_format({c9util.typename(typ)} *self, struct fmt_state *state) {{\n"
+ storage = "" if typ.typname == "stat" else "static " # SPECIAL (stat is public)
+ ret += f"[[maybe_unused]] {storage}void fmt_print_{typ.typname}(lo_interface fmt_dest w, [[maybe_unused]] struct lib9p_ctx *ctx, {c9util.typename(typ)} *self) {{\n"
match typ:
case idl.Number():
if typ.vals:
ret += "\tswitch (*self) {\n"
for name in typ.vals:
ret += f"\tcase {c9util.Ident(c9util.add_prefix(f'{typ.typname}_'.upper(), name))}:\n"
- ret += f'\t\tfmt_state_puts(state, "{name}");\n'
+ ret += f'\t\tfmt_print_str(w, "{name}");\n'
ret += "\t\tbreak;\n"
ret += "\tdefault:\n"
- ret += f'\t\tfmt_state_printf(state, "%"PRIu{typ.static_size*8}, *self);\n'
+ ret += "\t\tfmt_print_base10(w, *self);\n"
ret += "\t}\n"
else:
- ret += f'\t\tfmt_state_printf(state, "%"PRIu{typ.static_size*8}, *self);\n'
+ ret += "\t\tfmt_print_base10(w, *self);\n"
case idl.Bitfield():
val = "*self"
if typ.typname == "dm": # SPECIAL (pretty file permissions)
val = f"(*self & ~(({c9util.typename(typ)})0777))"
ret += "\tbool empty = true;\n"
- ret += "\tfmt_state_putchar(state, '(');\n"
+ ret += "\tfmt_print_byte(w, '(');\n"
nums: set[str] = set()
for bit in reversed(typ.bits):
@@ -72,8 +60,8 @@ def gen_c_format(versions: set[str], typs: list[idl.UserType]) -> str:
bitname = bit.bitname
ret += f"\tif ({val} & (UINT{typ.static_size*8}_C(1)<<{bit.num})) {{\n"
ret += "\t\tif (!empty)\n"
- ret += "\t\t\tfmt_state_putchar(state, '|');\n"
- ret += f'\t\tfmt_state_puts(state, "{bitname}");\n'
+ ret += "\t\t\tfmt_print_byte(w, '|');\n"
+ ret += f'\t\tfmt_print_str(w, "{bitname}");\n'
ret += "\t\tempty = false;\n"
ret += "\t}\n"
case idl.BitNum():
@@ -86,34 +74,32 @@ def gen_c_format(versions: set[str], typs: list[idl.UserType]) -> str:
f"{bit.cat.numname}_".upper(), name
)
ret += "\t\tif (!empty)\n"
- ret += "\t\t\tfmt_state_putchar(state, '|');\n"
- ret += f'\t\tfmt_state_puts(state, "{bitname}");\n'
+ ret += "\t\t\tfmt_print_byte(w, '|');\n"
+ ret += f'\t\tfmt_print_str(w, "{bitname}");\n'
ret += "\t\tempty = false;\n"
ret += "\t\tbreak;\n"
ret += "\tdefault:\n"
ret += "\t\tif (!empty)\n"
- ret += "\t\t\tfmt_state_putchar(state, '|');\n"
- ret += f'\t\tfmt_state_printf(state, "%"PRIu{typ.static_size*8}, {val} & {bf_numname(typ, bit.cat, 'MASK')});\n'
+ ret += "\t\t\tfmt_print_byte(w, '|');\n"
+ ret += f"\t\tfmt_print_base10(w, {val} & {bf_numname(typ, bit.cat, 'MASK')});\n"
ret += "\t\tempty = false;\n"
ret += "\t}\n"
nums.add(bit.cat.numname)
if typ.typname == "dm": # SPECIAL (pretty file permissions)
ret += "\tif (!empty)\n"
- ret += "\t\tfmt_state_putchar(state, '|');\n"
- ret += f'\tfmt_state_printf(state, "%#04"PRIo{typ.static_size*8}, *self & 0777);\n'
+ ret += "\t\tfmt_print_byte(w, '|');\n"
+ ret += "\tfmt_print(w, (rjust, 4, '0', (base8, *self & 0777)));\n"
else:
ret += "\tif (empty)\n"
- ret += "\t\tfmt_state_putchar(state, '0');\n"
- ret += "\tfmt_state_putchar(state, ')');\n"
+ ret += "\t\tfmt_print_byte(w, '0');\n"
+ ret += "\tfmt_print_byte(w, ')');\n"
case idl.Struct(typname="s"): # SPECIAL (string)
- ret += ext_printf(
- '\tfmt_state_printf(state, "%.*q", self->len, self->utf8);\n'
- )
+ ret += "\tfmt_print_qmem(w, self->utf8, self->len);\n"
case idl.Struct(): # and idl.Message():
if isinstance(typ, idl.Message):
- ret += f'\tfmt_state_puts(state, "{typ.typname} {{");\n'
+ ret += f'\tfmt_print_str(w, "{typ.typname} {{");\n'
else:
- ret += "\tfmt_state_putchar(state, '{');\n"
+ ret += "\tfmt_print_byte(w, '{');\n"
for member in typ.members:
if member.val:
continue
@@ -127,35 +113,33 @@ def gen_c_format(versions: set[str], typs: list[idl.UserType]) -> str:
cnt_typ = c9util.typename(member.cnt.typ)
if member.typ.static_size == 1: # SPECIAL (data)
ret += f"\tif (is_valid_utf8_without_nul((uint8_t *)self->{member.membname}, (size_t){cnt_str})) {{\n"
- ret += ext_printf(
- f'\t\tfmt_state_printf(state, " {member.membname}=%.*q%s",\n'
- f"\t\t\t(int)({cnt_str} < 50 ? {cnt_str} : 50),\n"
- f"\t\t\t(char *)self->{member.membname},\n"
- f'\t\t\t{cnt_str} < 50 ? "" : "...");\n'
- )
+ ret += f'\t\tfmt_print_str(w, " {member.membname}=");\n'
+ ret += f"\t\tfmt_print_qmem(w, self->{member.membname}, {cnt_str} < 50 ? {cnt_str} : 50);\n"
+ ret += f"\t\tif ({cnt_str} > 50)\n"
+ ret += '\t\t\tfmt_print_str(w, "...");\n'
ret += "\t} else {\n"
- ret += f'\t\tfmt_state_puts(state, " {member.membname}=<bytedata>");\n'
+ ret += f'\t\tfmt_print_str(w, " {member.membname}=<bytedata>");\n'
ret += "\t}\n"
continue
- ret += f'\tfmt_state_puts(state, " {member.membname}=[");\n'
+ ret += f'\tfmt_print_str(w, " {member.membname}=[");\n'
ret += f"\tfor ({cnt_typ} i = 0; i < {cnt_str}; i++) {{\n"
ret += "\t\tif (i)\n"
- ret += "\t\t\tfmt_state_putchar(state, ',');\n"
- ret += "\t\tfmt_state_putchar(state, ' ');\n"
+ ret += "\t\t\tfmt_print_byte(w, ',');\n"
+ ret += "\t\tfmt_print_byte(w, ' ');\n"
if isinstance(member.typ, idl.Primitive):
- ret += f'\t\tfmt_state_printf(state, "%"PRIu{member.typ.static_size*8}, self->{member.membname}[i]);\n'
+ ret += f"\t\tfmt_print_base10(w, self->{member.membname}[i]);\n"
else:
- ret += f"\t\t{c9util.basename(member.typ)}_format(&self->{member.membname}[i], state);\n"
+ ret += f"\t\tfmt_print_{member.typ.typname}(w, ctx, &self->{member.membname}[i]);\n"
ret += "\t}\n"
- ret += '\tfmt_state_puts(state, " ]");\n'
+ ret += '\tfmt_print_str(w, " ]");\n'
else:
- ret += f'\tfmt_state_puts(state, " {member.membname}=");\n'
+ ret += f'\tfmt_print_str(w, " {member.membname}=");\n'
if isinstance(member.typ, idl.Primitive):
- ret += f'\tfmt_state_printf(state, "%"PRIu{member.typ.static_size*8}, self->{member.membname});\n'
+ ret += f"\tfmt_print_base10(w, self->{member.membname});\n"
else:
- ret += f"\t{c9util.basename(member.typ)}_format(&self->{member.membname}, state);\n"
+ ret += f"\tfmt_print_{member.typ.typname}(w, ctx, &self->{member.membname});\n"
ret += cutil.ifdef_pop(1)
- ret += '\tfmt_state_puts(state, " }");\n'
+ ret += '\tfmt_print_str(w, " }");\n'
ret += "}\n"
ret += cutil.ifdef_pop(0)
diff --git a/lib9p/core_gen/c_marshal.py b/lib9p/core_gen/c_marshal.py
index 322e1ef..bddf55f 100644
--- a/lib9p/core_gen/c_marshal.py
+++ b/lib9p/core_gen/c_marshal.py
@@ -381,10 +381,9 @@ def gen_c_marshal(versions: set[str], typs: list[idl.UserType]) -> str:
else:
ret += "\tif (needed_size > ctx->max_msg_size) {\n"
if isinstance(typ, idl.Message): # SPECIAL (disable for stat)
- ret += f'\t\tlib9p_errorf(ctx, {c9util.IDENT("ERRNO_L_ERANGE")}, "%s message too large to marshal into %s limit (%"PRIu{szbits}" > %"PRIu32")",\n'
- ret += f'\t\t\t"{typ.typname}",\n'
- ret += f'\t\t\tctx->version ? "negotiated" : "{'client' if typ.msgid % 2 == 0 else 'server'}",\n'
- ret += "\t\t\tneeded_size, ctx->max_msg_size);\n"
+ ret += f'\t\tlib9p_error(ctx, {c9util.IDENT("ERRNO_L_ERANGE")}, "{typ.typname} message too large to marshal into ",\n'
+ ret += f'\t\t\tctx->version ? "negotiated" : "{'client' if typ.msgid % 2 == 0 else 'server'}", " limit",\n'
+ ret += '\t\t\t" (", needed_size, " > ", ctx->max_msg_size, ")");\n'
ret += "\t\treturn true;\n"
ret += "\t}\n"
diff --git a/lib9p/core_gen/c_validate.py b/lib9p/core_gen/c_validate.py
index 3073ed0..9c55d8d 100644
--- a/lib9p/core_gen/c_validate.py
+++ b/lib9p/core_gen/c_validate.py
@@ -59,7 +59,7 @@ def gen_c_validate(versions: set[str], typs: list[idl.UserType]) -> str:
"\t\t * that. */\n"
f'\t\treturn lib9p_error(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "message is too short for content");\n'
"\tif (net_offset > net_size)\n"
- f'\t\treturn lib9p_errorf(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "message is too short for content (%"PRIu32" > %"PRIu32") @ %d", net_offset, net_size, __LINE__);\n'
+ f'\t\treturn lib9p_error(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "message is too short for content (", net_offset, " > ", net_size, ")");\n'
)
ret += cutil.macro(
"#define VALIDATE_NET_UTF8(n)\n"
@@ -190,11 +190,10 @@ def gen_c_validate(versions: set[str], typs: list[idl.UserType]) -> str:
for tok in child.val.tokens
):
nbits = 32
- act = f"(uint{nbits}_t)GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})"
- exp = f"(uint{nbits}_t)({c9util.idl_expr(child.val, lookup_sym)})"
+ act = f"GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})"
+ exp = f"{c9util.idl_expr(child.val, lookup_sym)}"
ret += f"{'\t'*indent_lvl()}if ({act} != {exp})\n"
- ret += f'{"\t"*(indent_lvl()+1)}return lib9p_errorf(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "{path} value is wrong: actual: %"PRIu{nbits}" != correct:%"PRIu{nbits},\n'
- ret += f"{'\t'*(indent_lvl()+2)}{act}, {exp});\n"
+ ret += f'{"\t"*(indent_lvl()+1)}return lib9p_error(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "{path} value is wrong: actual:", (base10, {act}), " != correct:", (base10, {exp}));\n'
if child.max:
incr_flush()
assert child.typ.static_size
@@ -205,19 +204,18 @@ def gen_c_validate(versions: set[str], typs: list[idl.UserType]) -> str:
for tok in child.max.tokens
):
nbits = 32
- act = f"(uint{nbits}_t)GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})"
- exp = f"(uint{nbits}_t)({c9util.idl_expr(child.max, lookup_sym)})"
+ act = f"GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})"
+ exp = f"{c9util.idl_expr(child.max, lookup_sym)}"
ret += f"{'\t'*indent_lvl()}if ({act} > {exp})\n"
- ret += f'{"\t"*(indent_lvl()+1)}return lib9p_errorf(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "{path} value is too large: %"PRIu{nbits}" > %"PRIu{nbits},\n'
- ret += f"{'\t'*(indent_lvl()+2)}{act}, {exp});\n"
+ ret += f'{"\t"*(indent_lvl()+1)}return lib9p_error(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "{path} value is too large: ", (base10, {act}), " > ", (base10, {exp}));\n'
if isinstance(child.typ, idl.Bitfield):
incr_flush()
nbytes = child.typ.static_size
nbits = nbytes * 8
act = f"GET_U{nbits}LE({lookup_sym(f'&{child.membname}')})"
ret += f"{'\t'*indent_lvl()}if ({act} & ~{child.typ.typname}_masks[ctx->version])\n"
- ret += f'{"\t"*(indent_lvl()+1)}return lib9p_errorf(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "unknown bits in {child.typ.typname} bitfield: %#0{nbytes*2}"PRIx{nbits},\n'
- ret += f"{'\t'*(indent_lvl()+2)}{act} & ~{child.typ.typname}_masks[ctx->version]);\n"
+ ret += f'{"\t"*(indent_lvl()+1)}return lib9p_error(ctx, {c9util.IDENT("ERRNO_L_EBADMSG")}, "unknown bits in {child.typ.typname} bitfield: ",\n'
+ ret += f"{'\t'*(indent_lvl()+2)}(base16_u{nbits}_, {act} & ~{child.typ.typname}_masks[ctx->version]));\n"
def handle(
path: idlutil.Path,
diff --git a/lib9p/core_gen/h.py b/lib9p/core_gen/h.py
index 3c857c1..acf8415 100644
--- a/lib9p/core_gen/h.py
+++ b/lib9p/core_gen/h.py
@@ -163,12 +163,7 @@ def gen_h(versions: set[str], typs: list[idl.UserType]) -> str:
\t#error Do not include <lib9p/_core_generated.h> directly; include <lib9p/core.h> instead
#endif
-#include <stdint.h> /* for uint{{n}}_t types */
-
-#include <libfmt/fmt.h> /* for fmt_formatter */
-#include <libhw/generic/io.h> /* for struct iovec */
"""
-
id2typ: dict[int, idl.Message] = {}
for msg in [msg for msg in typs if isinstance(msg, idl.Message)]:
id2typ[msg.msgid] = msg
@@ -214,7 +209,6 @@ enum {c9util.ident('version')} {{
ret += cutil.ifdef_pop(0)
ret += f"\t{c9util.ver_enum('NUM')},\n"
ret += "};\n"
- ret += f"LO_IMPLEMENTATION_H(fmt_formatter, enum {c9util.ident('version')}, {c9util.ident('version')});\n"
ret += """
/* enum msg_type **************************************************************/
@@ -230,7 +224,6 @@ enum {c9util.ident('version')} {{
ret += f"\t{c9util.Ident(f'TYP_{msg.typname:<{namewidth}}')} = {msg.msgid},\n"
ret += cutil.ifdef_pop(0)
ret += "};\n"
- ret += f"LO_IMPLEMENTATION_H(fmt_formatter, enum {c9util.ident('msg_type')}, {c9util.ident('msg_type')});\n"
ret += """
/* payload types **************************************************************/
@@ -371,7 +364,6 @@ enum {c9util.ident('version')} {{
def gen_number(typ: idl.Number) -> str:
ret = f"typedef {c9util.typename(typ.prim)} {c9util.typename(typ)};\n"
- ret += f"LO_IMPLEMENTATION_H(fmt_formatter, {c9util.typename(typ)}, {c9util.basename(typ)});\n"
def lookup_sym(sym: str) -> str:
assert False
@@ -390,7 +382,6 @@ def gen_number(typ: idl.Number) -> str:
def gen_bitfield(typ: idl.Bitfield) -> str:
ret = f"typedef {c9util.typename(typ.prim)} {c9util.typename(typ)};\n"
- ret += f"LO_IMPLEMENTATION_H(fmt_formatter, {c9util.typename(typ)}, {c9util.basename(typ)});\n"
def lookup_sym(sym: str) -> str:
assert False
@@ -538,5 +529,4 @@ def gen_struct(typ: idl.Struct) -> str: # and idl.Message
ret += f"\t{c9util.typename(member.typ, member):<{typewidth}} {'*' if member.cnt else ' '}{member.membname};\n"
ret += cutil.ifdef_pop(1)
ret += "};\n"
- ret += f"LO_IMPLEMENTATION_H(fmt_formatter, {c9util.typename(typ)}, {c9util.basename(typ)});\n"
return ret