From f78acbeaddf7bb640569ba49eff4be38bad8d2a3 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Thu, 9 Mar 2023 22:22:58 +0100 Subject: [PATCH] scanner: allow element-bits on array args This attribute is optional but required if the element-type attribute is specified. This attribute specifies the size of the array elements in bits to allow for better WAYLAND_DEBUG logging and scanner code generation. Signed-off-by: Isaac Freund --- protocol/wayland.dtd | 1 + src/scanner.c | 124 ++++++++++++++++++++++++++++--------------- 2 files changed, 82 insertions(+), 43 deletions(-) diff --git a/protocol/wayland.dtd b/protocol/wayland.dtd index 6f888168..6a9c55b5 100644 --- a/protocol/wayland.dtd +++ b/protocol/wayland.dtd @@ -29,5 +29,6 @@ + diff --git a/src/scanner.c b/src/scanner.c index 45297e25..a9d8e695 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -224,6 +224,7 @@ struct arg { char *summary; char *enumeration_name; enum element_type element_type; + int element_bits; }; struct enumeration { @@ -725,6 +726,7 @@ start_element(void *data, const char *element_name, const char **atts) const char *bitfield = NULL; const char *element_type = NULL; int i, version = 0; + int element_bits = 0; ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser); for (i = 0; atts[i]; i += 2) { @@ -753,6 +755,21 @@ start_element(void *data, const char *element_name, const char **atts) bitfield = atts[i + 1]; if (strcmp(atts[i], "element-type") == 0) element_type = atts[i + 1]; + if (strcmp(atts[i], "element-bits") == 0) { + element_bits = strtouint(atts[i + 1]); + switch (element_bits) { + case 8: + case 16: + case 32: + /* Note: the wire protocol only guarantees 4 byte alignment + * of array data. Therefore we cannot allow 64 bit elements + * as they require 8 byte alignment on common targets. */ + break; + default: + fail(&ctx->loc, + "invalid element-bits value (%d)", atts[i + 1]); + } + } } ctx->character_data_length = 0; @@ -864,6 +881,7 @@ start_element(void *data, const char *element_name, const char **atts) element_type); } } + arg->element_bits = element_bits; if (summary) arg->summary = xstrdup(summary); @@ -966,6 +984,68 @@ find_enumeration(struct protocol *protocol, return NULL; } +static void +verify_argument_attributes(struct parse_context *ctx, + struct interface *interface, + struct arg *a) +{ + struct enumeration *e; + enum arg_type t; + + if (a->type == ARRAY) { + if ((a->element_type != ELEMENT_TYPE_NONE) != (a->element_bits != 0)) { + fail(&ctx->loc, + "if one of element-type or element-bits is specified " + "the other must be as well"); + } + } else { + if (a->element_type != ELEMENT_TYPE_NONE) { + fail(&ctx->loc, + "only args of type array may specify an element-type"); + } + if (a->element_bits != 0) { + fail(&ctx->loc, + "only args of type array may specify element-bits"); + } + } + + switch (a->element_type) { + case ELEMENT_TYPE_NONE: + t = a->type; + break; + case ELEMENT_TYPE_INT: + t = INT; + break; + case ELEMENT_TYPE_UNSIGNED: + t = UNSIGNED; + break; + default: + abort(); + } + + if (!a->enumeration_name) + return; + + e = find_enumeration(ctx->protocol, interface, + a->enumeration_name); + + switch (t) { + case INT: + if (e && e->bitfield) + fail(&ctx->loc, + "bitfield-style enum must only be referenced by uint"); + break; + case UNSIGNED: + break; + case ARRAY: + fail(&ctx->loc, + "array arg must specify element-type if enum is specified"); + default: + fail(&ctx->loc, + "enumeration-style argument has wrong type"); + } +} + static void verify_arguments(struct parse_context *ctx, struct interface *interface, @@ -976,49 +1056,7 @@ verify_arguments(struct parse_context *ctx, wl_list_for_each(m, messages, link) { struct arg *a; wl_list_for_each(a, &m->arg_list, link) { - struct enumeration *e; - enum arg_type t; - - if (a->element_type != ELEMENT_TYPE_NONE && a->type != ARRAY) { - fail(&ctx->loc, - "only args of type array may specify an element-type"); - } - - switch (a->element_type) { - case ELEMENT_TYPE_NONE: - t = a->type; - break; - case ELEMENT_TYPE_INT: - t = INT; - break; - case ELEMENT_TYPE_UNSIGNED: - t = UNSIGNED; - break; - default: - abort(); - } - - if (!a->enumeration_name) - continue; - - e = find_enumeration(ctx->protocol, interface, - a->enumeration_name); - - switch (t) { - case INT: - if (e && e->bitfield) - fail(&ctx->loc, - "bitfield-style enum must only be referenced by uint"); - break; - case UNSIGNED: - break; - case ARRAY: - fail(&ctx->loc, - "array arg must specify element-type if enum is specified"); - default: - fail(&ctx->loc, - "enumeration-style argument has wrong type"); - } + verify_argument_attributes(ctx, interface, a); } }