diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-09-28 20:50:36 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-09-28 20:54:43 -0600 |
commit | f410026b7bc96dbb42fec3839dc5d2e41b12f4a4 (patch) | |
tree | 22e831eb47101ee4e3635fcaf2729a81a178823c /lib9p | |
parent | f898850c2b4fef03f0d175ec052b3725bd406496 (diff) |
misc
Diffstat (limited to 'lib9p')
-rw-r--r-- | lib9p/include/lib9p/_types.h | 45 | ||||
-rw-r--r-- | lib9p/include/lib9p/srv.h | 14 | ||||
-rw-r--r-- | lib9p/internal.h | 5 | ||||
-rw-r--r-- | lib9p/srv.c | 59 | ||||
-rw-r--r-- | lib9p/types.c | 281 | ||||
-rwxr-xr-x | lib9p/types.gen | 58 |
6 files changed, 394 insertions, 68 deletions
diff --git a/lib9p/include/lib9p/_types.h b/lib9p/include/lib9p/_types.h index 7f320a5..94accc0 100644 --- a/lib9p/include/lib9p/_types.h +++ b/lib9p/include/lib9p/_types.h @@ -8,13 +8,15 @@ /* versions *******************************************************************/ enum lib9p_version { - LIB9P_VER_UNINITIALIZED = 0, - LIB9P_VER_9P2000, /* "9P2000" */ - LIB9P_VER_9P2000_e, /* "9P2000.e" */ - LIB9P_VER_9P2000_u, /* "9P2000.u" */ + LIB9P_VER_unknown = 0, /* "unknown" */ + LIB9P_VER_9P2000, /* "9P2000" */ + LIB9P_VER_9P2000_e, /* "9P2000.e" */ + LIB9P_VER_9P2000_u, /* "9P2000.u" */ LIB9P_VER_NUM, }; +const char *lib9p_version_str(enum lib9p_version); + /* non-message structs ********************************************************/ struct lib9p_d { @@ -90,40 +92,7 @@ enum lib9p_msg_type { /* uint8_t */ LIB9P_TYP_Rswrite = 155, /* 9P2000.e */ }; -#define LIB9P_TYPECODE_FOR_CTYPE(msg) _Generic((msg), \ - struct lib9p_msg_Tversion: LIB9P_TYP_Tversion, \ - struct lib9p_msg_Rversion: LIB9P_TYP_Rversion, \ - struct lib9p_msg_Tauth: LIB9P_TYP_Tauth, \ - struct lib9p_msg_Rauth: LIB9P_TYP_Rauth, \ - struct lib9p_msg_Tattach: LIB9P_TYP_Tattach, \ - struct lib9p_msg_Rattach: LIB9P_TYP_Rattach, \ - struct lib9p_msg_Rerror: LIB9P_TYP_Rerror, \ - struct lib9p_msg_Tflush: LIB9P_TYP_Tflush, \ - struct lib9p_msg_Rflush: LIB9P_TYP_Rflush, \ - struct lib9p_msg_Twalk: LIB9P_TYP_Twalk, \ - struct lib9p_msg_Rwalk: LIB9P_TYP_Rwalk, \ - struct lib9p_msg_Topen: LIB9P_TYP_Topen, \ - struct lib9p_msg_Ropen: LIB9P_TYP_Ropen, \ - struct lib9p_msg_Tcreate: LIB9P_TYP_Tcreate, \ - struct lib9p_msg_Rcreate: LIB9P_TYP_Rcreate, \ - struct lib9p_msg_Tread: LIB9P_TYP_Tread, \ - struct lib9p_msg_Rread: LIB9P_TYP_Rread, \ - struct lib9p_msg_Twrite: LIB9P_TYP_Twrite, \ - struct lib9p_msg_Rwrite: LIB9P_TYP_Rwrite, \ - struct lib9p_msg_Tclunk: LIB9P_TYP_Tclunk, \ - struct lib9p_msg_Rclunk: LIB9P_TYP_Rclunk, \ - struct lib9p_msg_Tremove: LIB9P_TYP_Tremove, \ - struct lib9p_msg_Rremove: LIB9P_TYP_Rremove, \ - struct lib9p_msg_Tstat: LIB9P_TYP_Tstat, \ - struct lib9p_msg_Rstat: LIB9P_TYP_Rstat, \ - struct lib9p_msg_Twstat: LIB9P_TYP_Twstat, \ - struct lib9p_msg_Rwstat: LIB9P_TYP_Rwstat, \ - struct lib9p_msg_Tsession: LIB9P_TYP_Tsession, \ - struct lib9p_msg_Rsession: LIB9P_TYP_Rsession, \ - struct lib9p_msg_Tsread: LIB9P_TYP_Tsread, \ - struct lib9p_msg_Rsread: LIB9P_TYP_Rsread, \ - struct lib9p_msg_Tswrite: LIB9P_TYP_Tswrite, \ - struct lib9p_msg_Rswrite: LIB9P_TYP_Rswrite) +const char *lib9p_msg_type_str(enum lib9p_msg_type); struct lib9p_msg_Tversion { uint32_t max_msg_size; diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h index a8bd9c7..3ca8b4d 100644 --- a/lib9p/include/lib9p/srv.h +++ b/lib9p/include/lib9p/srv.h @@ -4,13 +4,23 @@ #include <libcr/coroutine.h> #include <libcr_ipc/chan.h> -struct lib9p_srvreq; +struct lib9p_srv_req; struct lib9p_srv { int sockfd; - cr_chan_t(struct lib9p_srvreq *) reqch; + + cr_chan_t(struct lib9p_srv_req *) reqch; }; +/** + * Will just close the connection if a T-message has a size[4] <7. + * @errno LINUX_EMSGSIZE T-message has size[4] bigger than max_msg_size + * @errno LINUX_EDOM Tversion specified an impossibly small max_msg_size + * @errno LINUX_EOPNOTSUPP T-message has an R-message type, or an unrecognized T-message type + * @errno LINUX_EBADMSG T-message has wrong size[4] for its content, or has invalid UTF-8 + * @errno LINUX_ERANGE R-message does not fit into max_msg_size + */ + COROUTINE lib9p_srv_read_cr(void *_srv); COROUTINE lib9p_srv_write_cr(void *_srv); diff --git a/lib9p/internal.h b/lib9p/internal.h index a5175af..08bb462 100644 --- a/lib9p/internal.h +++ b/lib9p/internal.h @@ -51,6 +51,7 @@ struct _checksize_ctx { * "extra" beyond sizeof(). */ size_t host_extra; }; +typedef bool (*_checksize_fn_t)(struct _checksize_ctx *ctx); struct _unmarshal_ctx { struct lib9p_ctx *ctx; @@ -60,6 +61,7 @@ struct _unmarshal_ctx { /* `extra` points to the beginning of unallocated space. */ void *extra; }; +typedef void (*_unmarshal_fn_t)(struct _unmarshal_ctx *ctx, void *out); struct _marshal_ctx { struct lib9p_ctx *ctx; @@ -67,9 +69,6 @@ struct _marshal_ctx { uint8_t *net_bytes; uint32_t net_offset; }; - -typedef bool (*_checksize_fn_t)(struct _checksize_ctx *ctx); -typedef void (*_unmarshal_fn_t)(struct _unmarshal_ctx *ctx, void *out); typedef bool (*_marshal_fn_t)(struct _marshal_ctx *ctx, void *host_val); struct _vtable_msg { diff --git a/lib9p/srv.c b/lib9p/srv.c index 039b4c2..74c2014 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -10,18 +10,24 @@ #include <lib9p/srv.h> #include "internal.h" -struct lib9p_srvconn { +/* The hierarchy of concepts is: + * + * server -> connection -> session -> request + * + */ + +struct lib9p_srv_sess { /* immutable */ struct lib9p_srv *srv; - cid_t reader; - int fd; + int connfd; + cid_t reader; /* the lib9p_srv_read_cr() coroutine for this session */ /* mutable */ struct lib9p_ctx ctx; unsigned int refcount; }; -struct lib9p_srvreq { - struct lib9p_srvconn *conn; +struct lib9p_srv_req { + struct lib9p_srv_sess *sess; uint8_t *msg; }; @@ -79,7 +85,7 @@ COROUTINE lib9p_srv_read_cr(void *_srv) { } goal = decode_u32le(buf); if (goal < 7) { - /* We can't respond with an Rerror becuase we wouldn't know what tag to use! */ + /* We can't even respond with an Rerror becuase we wouldn't know what tag to use! */ fprintf(stderr, "error: T-message is impossibly small"); goto close; } @@ -184,5 +190,42 @@ void handle_message(struct lib9p_srvconn *conn, uint8_t *net) { netio_write(req.conn->fd, net, decode_u32le(net)); } -// EMSGSIZE for request too large -// EPROTONOSUPPORT for version errors +void _version(struct lib9p_srv_req *ctx, struct lib9p_msg_Tversion *req, struct lib9p_msg_Rversion *resp) { + enum lib9p_version version = LIB9P_VER_unknown; + + if (req->version.len >= 6 && + req->version.utf8[0] == '9' && + req->version.utf8[1] == 'P' && + '0' <= req->version.utf8[2] && req->version.utf8[2] <= '9' && + '0' <= req->version.utf8[3] && req->version.utf8[3] <= '9' && + '0' <= req->version.utf8[4] && req->version.utf8[4] <= '9' && + '0' <= req->version.utf8[5] && req->version.utf8[5] <= '9' && + (req->version.utf8[6] == '\0' || req->version.utf8[6] == '.')) { + if (strcmp(&req->version.utf8[6], ".u") == 0) + version = LIB9P_VER_9P2000_u; + //else if (strcmp(&req->version.utf8[6], ".e") == 0) + // version = LIB9P_VER_9P2000_e; + else + version = LIB9P_VER_9P2000; + } + + struct lib9p_ctx empty_ctx = { + .version = version, + .max_msg_size = CONFIG_9P_MAX_MSG_SIZE, + }; + struct lib9p_msg_Rerror empty_error = { 0 }; + assert(!lib9p_marshal(&empty_ctx, LIB9P_TYP_Rerror, 0, &empty_error, ctx->net)); + uint32_t min_msg_size = decode_u32le(ctx->net); + assert(CONFIG_9P_MAX_MSG_SIZE >= min_msg_size); + + if (req->max_msg_size < min_msg_size) { + lib9p_errorf(&ctx->ctx, LINUX_EDOM, "requested max_msg_size is less than minimum for %s (%"PRIu32" < %"PRIu32")", + version, req->max_msg_size, min_msg_size); + return; + } + + resp->version = lib9p_version_str(version); + resp->max_msg_size = (CONFIG_9P_MAX_MSG_SIZE < req->max_msg_size) + ? CONFIG_9P_MAX_MSG_SIZE + : req->max_msg_size; +} diff --git a/lib9p/types.c b/lib9p/types.c index 91a503d..8a48b85 100644 --- a/lib9p/types.c +++ b/lib9p/types.c @@ -1,5 +1,6 @@ /* Generated by `./lib9p/types.gen lib9p/9P2000.txt lib9p/9P2000.u.txt lib9p/9P2000.e.txt`. DO NOT EDIT! */ +#include <assert.h> #include <stdbool.h> #include <stddef.h> /* for size_t */ #include <inttypes.h> /* for PRI* macros */ @@ -9,6 +10,284 @@ #include "internal.h" +/* strings ********************************************************************/ + +static const char *version_strs[LIB9P_VER_NUM] = { + [LIB9P_VER_unknown] = "unknown", + [LIB9P_VER_9P2000] = "9P2000", + [LIB9P_VER_9P2000_e] = "9P2000.e", + [LIB9P_VER_9P2000_u] = "9P2000.u", +}; + +const char *lib9p_version_str(enum lib9p_version ver) { + assert(0 <= ver && ver < LIB9P_VER_NUM); + return version_strs[ver]; +} + +static const char *msg_type_strs[0xFF] = { + [0x00] = "0x00", + [0x01] = "0x01", + [0x02] = "0x02", + [0x03] = "0x03", + [0x04] = "0x04", + [0x05] = "0x05", + [0x06] = "0x06", + [0x07] = "0x07", + [0x08] = "0x08", + [0x09] = "0x09", + [0x0A] = "0x0A", + [0x0B] = "0x0B", + [0x0C] = "0x0C", + [0x0D] = "0x0D", + [0x0E] = "0x0E", + [0x0F] = "0x0F", + [0x10] = "0x10", + [0x11] = "0x11", + [0x12] = "0x12", + [0x13] = "0x13", + [0x14] = "0x14", + [0x15] = "0x15", + [0x16] = "0x16", + [0x17] = "0x17", + [0x18] = "0x18", + [0x19] = "0x19", + [0x1A] = "0x1A", + [0x1B] = "0x1B", + [0x1C] = "0x1C", + [0x1D] = "0x1D", + [0x1E] = "0x1E", + [0x1F] = "0x1F", + [0x20] = "0x20", + [0x21] = "0x21", + [0x22] = "0x22", + [0x23] = "0x23", + [0x24] = "0x24", + [0x25] = "0x25", + [0x26] = "0x26", + [0x27] = "0x27", + [0x28] = "0x28", + [0x29] = "0x29", + [0x2A] = "0x2A", + [0x2B] = "0x2B", + [0x2C] = "0x2C", + [0x2D] = "0x2D", + [0x2E] = "0x2E", + [0x2F] = "0x2F", + [0x30] = "0x30", + [0x31] = "0x31", + [0x32] = "0x32", + [0x33] = "0x33", + [0x34] = "0x34", + [0x35] = "0x35", + [0x36] = "0x36", + [0x37] = "0x37", + [0x38] = "0x38", + [0x39] = "0x39", + [0x3A] = "0x3A", + [0x3B] = "0x3B", + [0x3C] = "0x3C", + [0x3D] = "0x3D", + [0x3E] = "0x3E", + [0x3F] = "0x3F", + [0x40] = "0x40", + [0x41] = "0x41", + [0x42] = "0x42", + [0x43] = "0x43", + [0x44] = "0x44", + [0x45] = "0x45", + [0x46] = "0x46", + [0x47] = "0x47", + [0x48] = "0x48", + [0x49] = "0x49", + [0x4A] = "0x4A", + [0x4B] = "0x4B", + [0x4C] = "0x4C", + [0x4D] = "0x4D", + [0x4E] = "0x4E", + [0x4F] = "0x4F", + [0x50] = "0x50", + [0x51] = "0x51", + [0x52] = "0x52", + [0x53] = "0x53", + [0x54] = "0x54", + [0x55] = "0x55", + [0x56] = "0x56", + [0x57] = "0x57", + [0x58] = "0x58", + [0x59] = "0x59", + [0x5A] = "0x5A", + [0x5B] = "0x5B", + [0x5C] = "0x5C", + [0x5D] = "0x5D", + [0x5E] = "0x5E", + [0x5F] = "0x5F", + [0x60] = "0x60", + [0x61] = "0x61", + [0x62] = "0x62", + [0x63] = "0x63", + [0x64] = "Tversion", + [0x65] = "Rversion", + [0x66] = "Tauth", + [0x67] = "Rauth", + [0x68] = "Tattach", + [0x69] = "Rattach", + [0x6A] = "0x6A", + [0x6B] = "Rerror", + [0x6C] = "Tflush", + [0x6D] = "Rflush", + [0x6E] = "Twalk", + [0x6F] = "Rwalk", + [0x70] = "Topen", + [0x71] = "Ropen", + [0x72] = "Tcreate", + [0x73] = "Rcreate", + [0x74] = "Tread", + [0x75] = "Rread", + [0x76] = "Twrite", + [0x77] = "Rwrite", + [0x78] = "Tclunk", + [0x79] = "Rclunk", + [0x7A] = "Tremove", + [0x7B] = "Rremove", + [0x7C] = "Tstat", + [0x7D] = "Rstat", + [0x7E] = "Twstat", + [0x7F] = "Rwstat", + [0x80] = "0x80", + [0x81] = "0x81", + [0x82] = "0x82", + [0x83] = "0x83", + [0x84] = "0x84", + [0x85] = "0x85", + [0x86] = "0x86", + [0x87] = "0x87", + [0x88] = "0x88", + [0x89] = "0x89", + [0x8A] = "0x8A", + [0x8B] = "0x8B", + [0x8C] = "0x8C", + [0x8D] = "0x8D", + [0x8E] = "0x8E", + [0x8F] = "0x8F", + [0x90] = "0x90", + [0x91] = "0x91", + [0x92] = "0x92", + [0x93] = "0x93", + [0x94] = "0x94", + [0x95] = "0x95", + [0x96] = "Tsession", + [0x97] = "Rsession", + [0x98] = "Tsread", + [0x99] = "Rsread", + [0x9A] = "Tswrite", + [0x9B] = "Rswrite", + [0x9C] = "0x9C", + [0x9D] = "0x9D", + [0x9E] = "0x9E", + [0x9F] = "0x9F", + [0xA0] = "0xA0", + [0xA1] = "0xA1", + [0xA2] = "0xA2", + [0xA3] = "0xA3", + [0xA4] = "0xA4", + [0xA5] = "0xA5", + [0xA6] = "0xA6", + [0xA7] = "0xA7", + [0xA8] = "0xA8", + [0xA9] = "0xA9", + [0xAA] = "0xAA", + [0xAB] = "0xAB", + [0xAC] = "0xAC", + [0xAD] = "0xAD", + [0xAE] = "0xAE", + [0xAF] = "0xAF", + [0xB0] = "0xB0", + [0xB1] = "0xB1", + [0xB2] = "0xB2", + [0xB3] = "0xB3", + [0xB4] = "0xB4", + [0xB5] = "0xB5", + [0xB6] = "0xB6", + [0xB7] = "0xB7", + [0xB8] = "0xB8", + [0xB9] = "0xB9", + [0xBA] = "0xBA", + [0xBB] = "0xBB", + [0xBC] = "0xBC", + [0xBD] = "0xBD", + [0xBE] = "0xBE", + [0xBF] = "0xBF", + [0xC0] = "0xC0", + [0xC1] = "0xC1", + [0xC2] = "0xC2", + [0xC3] = "0xC3", + [0xC4] = "0xC4", + [0xC5] = "0xC5", + [0xC6] = "0xC6", + [0xC7] = "0xC7", + [0xC8] = "0xC8", + [0xC9] = "0xC9", + [0xCA] = "0xCA", + [0xCB] = "0xCB", + [0xCC] = "0xCC", + [0xCD] = "0xCD", + [0xCE] = "0xCE", + [0xCF] = "0xCF", + [0xD0] = "0xD0", + [0xD1] = "0xD1", + [0xD2] = "0xD2", + [0xD3] = "0xD3", + [0xD4] = "0xD4", + [0xD5] = "0xD5", + [0xD6] = "0xD6", + [0xD7] = "0xD7", + [0xD8] = "0xD8", + [0xD9] = "0xD9", + [0xDA] = "0xDA", + [0xDB] = "0xDB", + [0xDC] = "0xDC", + [0xDD] = "0xDD", + [0xDE] = "0xDE", + [0xDF] = "0xDF", + [0xE0] = "0xE0", + [0xE1] = "0xE1", + [0xE2] = "0xE2", + [0xE3] = "0xE3", + [0xE4] = "0xE4", + [0xE5] = "0xE5", + [0xE6] = "0xE6", + [0xE7] = "0xE7", + [0xE8] = "0xE8", + [0xE9] = "0xE9", + [0xEA] = "0xEA", + [0xEB] = "0xEB", + [0xEC] = "0xEC", + [0xED] = "0xED", + [0xEE] = "0xEE", + [0xEF] = "0xEF", + [0xF0] = "0xF0", + [0xF1] = "0xF1", + [0xF2] = "0xF2", + [0xF3] = "0xF3", + [0xF4] = "0xF4", + [0xF5] = "0xF5", + [0xF6] = "0xF6", + [0xF7] = "0xF7", + [0xF8] = "0xF8", + [0xF9] = "0xF9", + [0xFA] = "0xFA", + [0xFB] = "0xFB", + [0xFC] = "0xFC", + [0xFD] = "0xFD", + [0xFE] = "0xFE", + [0xFF] = "0xFF", +}; + +const char *lib9p_msg_type_str(enum lib9p_msg_type typ) { + assert(0 <= typ && typ <= 0xFF); + return msg_type_strs[typ]; +} + /* checksize_* (internals of unmarshal_size()) ********************************/ static inline bool _checksize_net(struct _checksize_ctx *ctx, uint32_t n) { @@ -799,7 +1078,7 @@ static bool marshal_Rswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rswrite * } struct _vtable_version _lib9p_vtables[LIB9P_VER_NUM] = { - [LIB9P_VER_UNINITIALIZED] = { .msgs = { + [LIB9P_VER_unknown] = { .msgs = { _MSG(Tversion), _MSG(Rversion), _MSG(Rerror), diff --git a/lib9p/types.gen b/lib9p/types.gen index 15936e7..590e707 100755 --- a/lib9p/types.gen +++ b/lib9p/types.gen @@ -241,14 +241,16 @@ def gen_h(idprefix: str, versions: set[str], structs: list[Struct]) -> str: /* versions *******************************************************************/ enum {idprefix}version {{ - {idprefix.upper()}VER_UNINITIALIZED = 0, """ - verwidth = max(len(v) for v in versions) - for ver in sorted(versions): + fullversions = ["unknown = 0", *sorted(versions)] + verwidth = max(len(v) for v in fullversions) + for ver in fullversions: ret += f"\t{c_verenum(idprefix, ver)}," - ret += (" " * (verwidth - len(ver))) + ' /* "' + ver + '" */\n' - ret += f"\t{idprefix.upper()}VER_NUM,\n" + ret += (" " * (verwidth - len(ver))) + ' /* "' + ver.split()[0] + '" */\n' + ret += f"\t{c_verenum(idprefix, 'NUM')},\n" ret += "};\n" + ret += "\n" + ret += f"const char *{idprefix}version_str(enum {idprefix}version);\n" ret += """ /* non-message structs ********************************************************/ @@ -287,16 +289,8 @@ enum {idprefix}version {{ ret += " " + comment ret += "\n" ret += "};\n" - ret += "\n" - ret += f"#define {idprefix.upper()}TYPECODE_FOR_CTYPE(msg) _Generic((msg)" - for msg in structs: - if msg.msgid is None: - continue - ret += ( - f", \\\n\t\t{c_typename(idprefix, msg)}: {idprefix.upper()}TYP_{msg.name}" - ) - ret += ")\n" + ret += f"const char *{idprefix}msg_type_str(enum {idprefix}msg_type);\n" for msg in structs: if msg.msgid is None: @@ -333,6 +327,7 @@ enum {idprefix}version {{ def gen_c(idprefix: str, versions: set[str], structs: list[Struct]) -> str: ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */ +#include <assert.h> #include <stdbool.h> #include <stddef.h> /* for size_t */ #include <inttypes.h> /* for PRI* macros */ @@ -349,6 +344,37 @@ def gen_c(idprefix: str, versions: set[str], structs: list[Struct]) -> str: def unused(arg: str) -> str: return f"UNUSED({arg})" + # strings ################################################################## + ret += f""" +/* strings ********************************************************************/ + +static const char *version_strs[{c_verenum(idprefix, 'NUM')}] = {{ +""" + for ver in ["unknown", *sorted(versions)]: + ret += f'\t[{c_verenum(idprefix, ver)}] = "{ver}",\n' + ret += "};\n" + ret += f""" +const char *{idprefix}version_str(enum {idprefix}version ver) {{ + assert(0 <= ver && ver < {c_verenum(idprefix, 'NUM')}); + return version_strs[ver]; +}} + +static const char *msg_type_strs[0xFF] = {{ +""" + id2name: dict[int, str] = {} + for msg in structs: + if msg.msgid is not None: + id2name[msg.msgid] = msg.name + for n in range(0, 0x100): + ret += '\t[0x{:02X}] = "{}",\n'.format(n, id2name.get(n, "0x{:02X}".format(n))) + ret += "};\n" + ret += f""" +const char *{idprefix}msg_type_str(enum {idprefix}msg_type typ) {{ + assert(0 <= typ && typ <= 0xFF); + return msg_type_strs[typ]; +}} +""" + # checksize_* ############################################################## ret += """ /* checksize_* (internals of unmarshal_size()) ********************************/ @@ -591,10 +617,10 @@ static inline bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) { .marshal = (_marshal_fn_t)marshal_##typ, \\ }} -struct _vtable_version _{idprefix}vtables[LIB9P_VER_NUM] = {{ +struct _vtable_version _{idprefix}vtables[{c_verenum(idprefix, 'NUM')}] = {{ """ - ret += f"\t[{idprefix.upper()}VER_UNINITIALIZED] = {{ .msgs = {{\n" + ret += f"\t[{c_verenum(idprefix, 'unknown')}] = {{ .msgs = {{\n" for msg in structs: if msg.name in ["Tversion", "Rversion", "Rerror"]: # SPECIAL ret += f"\t\t_MSG({msg.name}),\n" |