diff options
Diffstat (limited to 'lib9p/core_gen')
-rw-r--r-- | lib9p/core_gen/c.py | 19 | ||||
-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.py | 7 | ||||
-rw-r--r-- | lib9p/core_gen/c_validate.py | 20 | ||||
-rw-r--r-- | lib9p/core_gen/h.py | 10 |
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 |