+
+#include "wayland-util.h"
+
+#define PROGRAM_NAME "wayland-scanner"
+
+enum side {
+ CLIENT,
+ SERVER,
+};
+
+enum visibility {
+ PRIVATE,
+ PUBLIC,
+};
+
+static int
+usage(int ret)
+{
+ fprintf(stderr, "usage: %s [OPTION] [client-header|server-header|private-code|public-code]"
+ " [input_file output_file]\n", PROGRAM_NAME);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Converts XML protocol descriptions supplied on "
+ "stdin or input file to client\n"
+ "headers, server headers, or protocol marshalling code.\n\n"
+ "Use \"public-code\" only if the marshalling code will be public - "
+ "aka DSO will export it while other components will be using it.\n"
+ "Using \"private-code\" is strongly recommended.\n\n");
+ fprintf(stderr, "options:\n");
+ fprintf(stderr, " -h, --help display this help and exit.\n"
+ " -v, --version print the wayland library version that\n"
+ " the scanner was built against.\n"
+ " -c, --include-core-only include the core version of the headers,\n"
+ " that is e.g. wayland-client-core.h instead\n"
+ " of wayland-client.h.\n"
+ " -s, --strict exit immediately with an error if DTD\n"
+ " verification fails.\n");
+ exit(ret);
+}
+
+static int
+scanner_version(int ret)
+{
+ fprintf(stderr, "%s %s\n", PROGRAM_NAME, WAYLAND_VERSION);
+ exit(ret);
+}
+
+static bool
+is_dtd_valid(FILE *input, const char *filename)
+{
+ bool rc = true;
+#if HAVE_LIBXML
+ xmlParserCtxtPtr ctx = NULL;
+ xmlDocPtr doc = NULL;
+ xmlDtdPtr dtd = NULL;
+ xmlValidCtxtPtr dtdctx;
+ xmlParserInputBufferPtr buffer;
+ int fd = fileno(input);
+
+ dtdctx = xmlNewValidCtxt();
+ ctx = xmlNewParserCtxt();
+ if (!ctx || !dtdctx)
+ abort();
+
+ buffer = xmlParserInputBufferCreateMem(&DTD_DATA_begin,
+ DTD_DATA_len,
+ XML_CHAR_ENCODING_UTF8);
+ if (!buffer) {
+ fprintf(stderr, "Failed to init buffer for DTD.\n");
+ abort();
+ }
+
+ dtd = xmlIOParseDTD(NULL, buffer, XML_CHAR_ENCODING_UTF8);
+ if (!dtd) {
+ fprintf(stderr, "Failed to parse DTD.\n");
+ abort();
+ }
+
+ doc = xmlCtxtReadFd(ctx, fd, filename, NULL, 0);
+ if (!doc) {
+ fprintf(stderr, "Failed to read XML\n");
+ abort();
+ }
+
+ rc = xmlValidateDtd(dtdctx, doc, dtd);
+ xmlFreeDoc(doc);
+ xmlFreeParserCtxt(ctx);
+ xmlFreeDtd(dtd);
+ xmlFreeValidCtxt(dtdctx);
+ /* xmlIOParseDTD consumes buffer */
+
+ if (lseek(fd, 0, SEEK_SET) != 0) {
+ fprintf(stderr, "Failed to reset fd, output would be garbage.\n");
+ abort();
+ }
+#endif
+ return rc;
+}
+
+#define XML_BUFFER_SIZE 4096
+
+struct location {
+ const char *filename;
+ int line_number;
+};
+
+struct description {
+ char *summary;
+ char *text;
+};
+
+struct protocol {
+ char *name;
+ char *uppercase_name;
+ struct wl_list interface_list;
+ int type_index;
+ int null_run_length;
+ char *copyright;
+ struct description *description;
+ bool core_headers;
+};
+
+struct interface {
+ struct location loc;
+ char *name;
+ char *uppercase_name;
+ int version;
+ int since;
+ struct wl_list request_list;
+ struct wl_list event_list;
+ struct wl_list enumeration_list;
+ struct wl_list link;
+ struct description *description;
+};
+
+struct message {
+ struct location loc;
+ char *name;
+ char *uppercase_name;
+ struct wl_list arg_list;
+ struct wl_list link;
+ int arg_count;
+ int new_id_count;
+ int type_index;
+ int all_null;
+ int destructor;
+ int since;
+ struct description *description;
+};
+
+enum arg_type {
+ NEW_ID,
+ INT,
+ UNSIGNED,
+ FIXED,
+ STRING,
+ OBJECT,
+ ARRAY,
+ FD
+};
+
+struct arg {
+ char *name;
+ enum arg_type type;
+ int nullable;
+ char *interface_name;
+ struct wl_list link;
+ char *summary;
+ char *enumeration_name;
+};
+
+struct enumeration {
+ char *name;
+ char *uppercase_name;
+ struct wl_list entry_list;
+ struct wl_list link;
+ struct description *description;
+ bool bitfield;
+ int since;
+};
+
+struct entry {
+ char *name;
+ char *uppercase_name;
+ char *value;
+ char *summary;
+ int since;
+ struct wl_list link;
+};
+
+struct parse_context {
+ struct location loc;
+ XML_Parser parser;
+ struct protocol *protocol;
+ struct interface *interface;
+ struct message *message;
+ struct enumeration *enumeration;
+ struct description *description;
+ char character_data[8192];
+ unsigned int character_data_length;
+};
+
+enum identifier_role {
+ STANDALONE_IDENT,
+ TRAILING_IDENT
+};
+
+static void *
+fail_on_null(void *p)
+{
+ if (p == NULL) {
+ fprintf(stderr, "%s: out of memory\n", PROGRAM_NAME);
+ exit(EXIT_FAILURE);
+ }
+
+ return p;
+}
+
+static void *
+zalloc(size_t s)
+{
+ return calloc(s, 1);
+}
+
+static void *
+xzalloc(size_t s)
+{
+ return fail_on_null(zalloc(s));
+}
+
+static char *
+xstrdup(const char *s)
+{
+ return fail_on_null(strdup(s));
+}
+
+static char *
+uppercase_dup(const char *src)
+{
+ char *u;
+ int i;
+
+ u = xstrdup(src);
+ for (i = 0; u[i]; i++)
+ u[i] = toupper(u[i]);
+ u[i] = '\0';
+
+ return u;
+}
+
+static const char *indent(int n)
+{
+ const char *whitespace[] = {
+ "\t\t\t\t\t\t\t\t\t\t\t\t",
+ "\t\t\t\t\t\t\t\t\t\t\t\t ",
+ "\t\t\t\t\t\t\t\t\t\t\t\t ",
+ "\t\t\t\t\t\t\t\t\t\t\t\t ",
+ "\t\t\t\t\t\t\t\t\t\t\t\t ",
+ "\t\t\t\t\t\t\t\t\t\t\t\t ",
+ "\t\t\t\t\t\t\t\t\t\t\t\t ",
+ "\t\t\t\t\t\t\t\t\t\t\t\t "
+ };
+
+ return whitespace[n % 8] + 12 - n / 8;
+}
+
+static void
+desc_dump(char *desc, const char *fmt, ...) WL_PRINTF(2, 3);
+
+static void
+desc_dump(char *desc, const char *fmt, ...)
+{
+ va_list ap;
+ char buf[128], hang;
+ int col, i, j, k, startcol, newlines;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof buf, fmt, ap);
+ va_end(ap);
+
+ for (i = 0, col = 0; buf[i] != '*'; i++) {
+ if (buf[i] == '\t')
+ col = (col + 8) & ~7;
+ else
+ col++;
+ }
+
+ printf("%s", buf);
+
+ if (!desc) {
+ printf("(none)\n");
+ return;
+ }
+
+ startcol = col;
+ col += strlen(&buf[i]);
+ if (col - startcol > 2)
+ hang = '\t';
+ else
+ hang = ' ';
+
+ for (i = 0; desc[i]; ) {
+ k = i;
+ newlines = 0;
+ while (desc[i] && isspace(desc[i])) {
+ if (desc[i] == '\n')
+ newlines++;
+ i++;
+ }
+ if (!desc[i])
+ break;
+
+ j = i;
+ while (desc[i] && !isspace(desc[i]))
+ i++;
+
+ if (newlines > 1)
+ printf("\n%s*", indent(startcol));
+ if (newlines > 1 || col + i - j > 72) {
+ printf("\n%s*%c", indent(startcol), hang);
+ col = startcol;
+ }
+
+ if (col > startcol && k > 0)
+ col += printf(" ");
+ col += printf("%.*s", i - j, &desc[j]);
+ }
+ putchar('\n');
+}
+
+static void __attribute__ ((noreturn))
+fail(struct location *loc, const char *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ fprintf(stderr, "%s:%d: error: ",
+ loc->filename, loc->line_number);
+ vfprintf(stderr, msg, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ exit(EXIT_FAILURE);
+}
+
+static void
+warn(struct location *loc, const char *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ fprintf(stderr, "%s:%d: warning: ",
+ loc->filename, loc->line_number);
+ vfprintf(stderr, msg, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+
+static bool
+is_nullable_type(struct arg *arg)
+{
+ switch (arg->type) {
+ /* Strings, objects, and arrays are possibly nullable */
+ case STRING:
+ case OBJECT:
+ case NEW_ID:
+ case ARRAY:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static struct message *
+create_message(struct location loc, const char *name)
+{
+ struct message *message;
+
+ message = xzalloc(sizeof *message);
+ message->loc = loc;
+ message->name = xstrdup(name);
+ message->uppercase_name = uppercase_dup(name);
+ wl_list_init(&message->arg_list);
+
+ return message;
+}
+
+static void
+free_arg(struct arg *arg)
+{
+ free(arg->name);
+ free(arg->interface_name);
+ free(arg->summary);
+ free(arg->enumeration_name);
+ free(arg);
+}
+
+static struct arg *
+create_arg(const char *name)
+{
+ struct arg *arg;
+
+ arg = xzalloc(sizeof *arg);
+ arg->name = xstrdup(name);
+
+ return arg;
+}
+
+static bool
+set_arg_type(struct arg *arg, const char *type)
+{
+ if (strcmp(type, "int") == 0)
+ arg->type = INT;
+ else if (strcmp(type, "uint") == 0)
+ arg->type = UNSIGNED;
+ else if (strcmp(type, "fixed") == 0)
+ arg->type = FIXED;
+ else if (strcmp(type, "string") == 0)
+ arg->type = STRING;
+ else if (strcmp(type, "array") == 0)
+ arg->type = ARRAY;
+ else if (strcmp(type, "fd") == 0)
+ arg->type = FD;
+ else if (strcmp(type, "new_id") == 0)
+ arg->type = NEW_ID;
+ else if (strcmp(type, "object") == 0)
+ arg->type = OBJECT;
+ else
+ return false;
+
+ return true;
+}
+
+static void
+free_description(struct description *desc)
+{
+ if (!desc)
+ return;
+
+ free(desc->summary);
+ free(desc->text);
+
+ free(desc);
+}
+
+static void
+free_message(struct message *message)
+{
+ struct arg *a, *a_next;
+
+ free(message->name);
+ free(message->uppercase_name);
+ free_description(message->description);
+
+ wl_list_for_each_safe(a, a_next, &message->arg_list, link)
+ free_arg(a);
+
+ free(message);
+}
+
+static struct enumeration *
+create_enumeration(const char *name)
+{
+ struct enumeration *enumeration;
+
+ enumeration = xzalloc(sizeof *enumeration);
+ enumeration->name = xstrdup(name);
+ enumeration->uppercase_name = uppercase_dup(name);
+ enumeration->since = 1;
+
+ wl_list_init(&enumeration->entry_list);
+
+ return enumeration;
+}
+
+static struct entry *
+create_entry(const char *name, const char *value)
+{
+ struct entry *entry;
+
+ entry = xzalloc(sizeof *entry);
+ entry->name = xstrdup(name);
+ entry->uppercase_name = uppercase_dup(name);
+ entry->value = xstrdup(value);
+
+ return entry;
+}
+
+static void
+free_entry(struct entry *entry)
+{
+ free(entry->name);
+ free(entry->uppercase_name);
+ free(entry->value);
+ free(entry->summary);
+
+ free(entry);
+}
+
+static void
+free_enumeration(struct enumeration *enumeration)
+{
+ struct entry *e, *e_next;
+
+ free(enumeration->name);
+ free(enumeration->uppercase_name);
+ free_description(enumeration->description);
+
+ wl_list_for_each_safe(e, e_next, &enumeration->entry_list, link)
+ free_entry(e);
+
+ free(enumeration);
+}
+
+static struct interface *
+create_interface(struct location loc, const char *name, int version)
+{
+ struct interface *interface;
+
+ interface = xzalloc(sizeof *interface);
+ interface->loc = loc;
+ interface->name = xstrdup(name);
+ interface->uppercase_name = uppercase_dup(name);
+ interface->version = version;
+ interface->since = 1;
+ wl_list_init(&interface->request_list);
+ wl_list_init(&interface->event_list);
+ wl_list_init(&interface->enumeration_list);
+
+ return interface;
+}
+
+static void
+free_interface(struct interface *interface)
+{
+ struct message *m, *next_m;
+ struct enumeration *e, *next_e;
+
+ free(interface->name);
+ free(interface->uppercase_name);
+ free_description(interface->description);
+
+ wl_list_for_each_safe(m, next_m, &interface->request_list, link)
+ free_message(m);
+ wl_list_for_each_safe(m, next_m, &interface->event_list, link)
+ free_message(m);
+ wl_list_for_each_safe(e, next_e, &interface->enumeration_list, link)
+ free_enumeration(e);
+
+ free(interface);
+}
+
+/* Convert string to unsigned integer
+ *
+ * Parses a non-negative base-10 number from the given string. If the
+ * specified string is blank, contains non-numerical characters, is out
+ * of range, or results in a negative number, -1 is returned to indicate
+ * an error.
+ *
+ * Upon error, this routine does not modify or set errno.
+ *
+ * Returns -1 on error, or a non-negative integer on success
+ */
+static int
+strtouint(const char *str)
+{
+ long int ret;
+ char *end;
+ int prev_errno = errno;
+
+ errno = 0;
+ ret = strtol(str, &end, 10);
+ if (errno != 0 || end == str || *end != '\0')
+ return -1;
+
+ /* check range */
+ if (ret < 0 || ret > INT_MAX) {
+ return -1;
+ }
+
+ errno = prev_errno;
+ return (int)ret;
+}
+
+/* Check that the provided string will produce valid "C" identifiers.
+ *
+ * If the string will form the prefix of an identifier in the
+ * generated C code, then it must match [_a-zA-Z][_0-9a-zA-Z]*.
+ *
+ * If the string will form the suffix of an identifier, then
+ * it must match [_0-9a-zA-Z]+.
+ *
+ * Unicode characters or escape sequences are not permitted,
+ * since not all C compilers support them.
+ *
+ * If the above conditions are not met, then fail()
+ */
+static void
+validate_identifier(struct location *loc,
+ const char *str,
+ enum identifier_role role)
+{
+ const char *scan;
+
+ if (!*str) {
+ fail(loc, "element name is empty");
+ }
+
+ for (scan = str; *scan; scan++) {
+ char c = *scan;
+
+ /* we do not use the locale-dependent `isalpha` */
+ bool is_alpha = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+ bool is_digit = c >= '0' && c <= '9';
+ bool leading_char = (scan == str) && role == STANDALONE_IDENT;
+
+ if (is_alpha || c == '_' || (!leading_char && is_digit))
+ continue;
+
+ if (role == TRAILING_IDENT)
+ fail(loc,
+ "'%s' is not a valid trailing identifier part", str);
+ else
+ fail(loc,
+ "'%s' is not a valid standalone identifier", str);
+ }
+}
+
+static int
+version_from_since(struct parse_context *ctx, const char *since)
+{
+ int version;
+
+ if (since != NULL) {
+ version = strtouint(since);
+ if (version == -1) {
+ fail(&ctx->loc, "invalid integer (%s)\n", since);
+ } else if (version > ctx->interface->version) {
+ fail(&ctx->loc, "since (%u) larger than version (%u)\n",
+ version, ctx->interface->version);
+ }
+ } else {
+ version = 1;
+ }
+
+
+ return version;
+}
+
+static void
+start_element(void *data, const char *element_name, const char **atts)
+{
+ struct parse_context *ctx = data;
+ struct interface *interface;
+ struct message *message;
+ struct arg *arg;
+ struct enumeration *enumeration;
+ struct entry *entry;
+ struct description *description = NULL;
+ const char *name = NULL;
+ const char *type = NULL;
+ const char *interface_name = NULL;
+ const char *value = NULL;
+ const char *summary = NULL;
+ const char *since = NULL;
+ const char *allow_null = NULL;
+ const char *enumeration_name = NULL;
+ const char *bitfield = NULL;
+ int i, version = 0;
+
+ ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser);
+ for (i = 0; atts[i]; i += 2) {
+ if (strcmp(atts[i], "name") == 0)
+ name = atts[i + 1];
+ if (strcmp(atts[i], "version") == 0) {
+ version = strtouint(atts[i + 1]);
+ if (version == -1)
+ fail(&ctx->loc, "wrong version (%s)", atts[i + 1]);
+ }
+ if (strcmp(atts[i], "type") == 0)
+ type = atts[i + 1];
+ if (strcmp(atts[i], "value") == 0)
+ value = atts[i + 1];
+ if (strcmp(atts[i], "interface") == 0)
+ interface_name = atts[i + 1];
+ if (strcmp(atts[i], "summary") == 0)
+ summary = atts[i + 1];
+ if (strcmp(atts[i], "since") == 0)
+ since = atts[i + 1];
+ if (strcmp(atts[i], "allow-null") == 0)
+ allow_null = atts[i + 1];
+ if (strcmp(atts[i], "enum") == 0)
+ enumeration_name = atts[i + 1];
+ if (strcmp(atts[i], "bitfield") == 0)
+ bitfield = atts[i + 1];
+ }
+
+ ctx->character_data_length = 0;
+ if (strcmp(element_name, "protocol") == 0) {
+ if (name == NULL)
+ fail(&ctx->loc, "no protocol name given");
+
+ validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
+ ctx->protocol->name = xstrdup(name);
+ ctx->protocol->uppercase_name = uppercase_dup(name);
+ } else if (strcmp(element_name, "copyright") == 0) {
+
+ } else if (strcmp(element_name, "interface") == 0) {
+ if (name == NULL)
+ fail(&ctx->loc, "no interface name given");
+
+ if (version == 0)
+ fail(&ctx->loc, "no interface version given");
+
+ validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
+ interface = create_interface(ctx->loc, name, version);
+ ctx->interface = interface;
+ wl_list_insert(ctx->protocol->interface_list.prev,
+ &interface->link);
+ } else if (strcmp(element_name, "request") == 0 ||
+ strcmp(element_name, "event") == 0) {
+ if (name == NULL)
+ fail(&ctx->loc, "no request name given");
+
+ validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
+ message = create_message(ctx->loc, name);
+
+ if (strcmp(element_name, "request") == 0)
+ wl_list_insert(ctx->interface->request_list.prev,
+ &message->link);
+ else
+ wl_list_insert(ctx->interface->event_list.prev,
+ &message->link);
+
+ if (type != NULL && strcmp(type, "destructor") == 0)
+ message->destructor = 1;
+
+ version = version_from_since(ctx, since);
+
+ if (version < ctx->interface->since)
+ warn(&ctx->loc, "since version not increasing\n");
+ ctx->interface->since = version;
+ message->since = version;
+
+ if (strcmp(name, "destroy") == 0 && !message->destructor)
+ fail(&ctx->loc, "destroy request should be destructor type");
+
+ ctx->message = message;
+ } else if (strcmp(element_name, "arg") == 0) {
+ if (name == NULL)
+ fail(&ctx->loc, "no argument name given");
+
+ validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
+ arg = create_arg(name);
+ if (!set_arg_type(arg, type))
+ fail(&ctx->loc, "unknown type (%s)", type);
+
+ switch (arg->type) {
+ case NEW_ID:
+ ctx->message->new_id_count++;
+ /* fallthrough */
+ case OBJECT:
+ if (interface_name) {
+ validate_identifier(&ctx->loc,
+ interface_name,
+ STANDALONE_IDENT);
+ arg->interface_name = xstrdup(interface_name);
+ }
+ break;
+ default:
+ if (interface_name != NULL)
+ fail(&ctx->loc, "interface attribute not allowed for type %s", type);
+ break;
+ }
+
+ if (allow_null) {
+ if (strcmp(allow_null, "true") == 0)
+ arg->nullable = 1;
+ else if (strcmp(allow_null, "false") != 0)
+ fail(&ctx->loc,
+ "invalid value for allow-null attribute (%s)",
+ allow_null);
+
+ if (!is_nullable_type(arg))
+ fail(&ctx->loc,
+ "allow-null is only valid for objects, strings, and arrays");
+ }
+
+ if (enumeration_name == NULL || strcmp(enumeration_name, "") == 0)
+ arg->enumeration_name = NULL;
+ else
+ arg->enumeration_name = xstrdup(enumeration_name);
+
+ if (summary)
+ arg->summary = xstrdup(summary);
+
+ wl_list_insert(ctx->message->arg_list.prev, &arg->link);
+ ctx->message->arg_count++;
+ } else if (strcmp(element_name, "enum") == 0) {
+ if (name == NULL)
+ fail(&ctx->loc, "no enum name given");
+
+ validate_identifier(&ctx->loc, name, TRAILING_IDENT);
+ enumeration = create_enumeration(name);
+
+ if (bitfield == NULL || strcmp(bitfield, "false") == 0)
+ enumeration->bitfield = false;
+ else if (strcmp(bitfield, "true") == 0)
+ enumeration->bitfield = true;
+ else
+ fail(&ctx->loc,
+ "invalid value (%s) for bitfield attribute (only true/false are accepted)",
+ bitfield);
+
+ wl_list_insert(ctx->interface->enumeration_list.prev,
+ &enumeration->link);
+
+ ctx->enumeration = enumeration;
+ } else if (strcmp(element_name, "entry") == 0) {
+ if (name == NULL)
+ fail(&ctx->loc, "no entry name given");
+
+ validate_identifier(&ctx->loc, name, TRAILING_IDENT);
+ entry = create_entry(name, value);
+ version = version_from_since(ctx, since);
+
+ if (version < ctx->enumeration->since)
+ warn(&ctx->loc, "since version not increasing\n");
+ ctx->enumeration->since = version;
+ entry->since = version;
+
+ if (summary)
+ entry->summary = xstrdup(summary);
+ else
+ entry->summary = NULL;
+ wl_list_insert(ctx->enumeration->entry_list.prev,
+ &entry->link);
+ } else if (strcmp(element_name, "description") == 0) {
+ if (summary == NULL)
+ fail(&ctx->loc, "description without summary");
+
+ description = xzalloc(sizeof *description);
+ description->summary = xstrdup(summary);
+
+ if (ctx->message)
+ ctx->message->description = description;
+ else if (ctx->enumeration)
+ ctx->enumeration->description = description;
+ else if (ctx->interface)
+ ctx->interface->description = description;
+ else
+ ctx->protocol->description = description;
+ ctx->description = description;
+ }
+}
+
+static struct enumeration *
+find_enumeration(struct protocol *protocol,
+ struct interface *interface,
+ char *enum_attribute)
+{
+ struct interface *i;
+ struct enumeration *e;
+ char *enum_name;
+ uint32_t idx = 0, j;
+
+ for (j = 0; j + 1 < strlen(enum_attribute); j++) {
+ if (enum_attribute[j] == '.') {
+ idx = j;
+ }
+ }
+
+ if (idx > 0) {
+ enum_name = enum_attribute + idx + 1;
+
+ wl_list_for_each(i, &protocol->interface_list, link)
+ if (strncmp(i->name, enum_attribute, idx) == 0)
+ wl_list_for_each(e, &i->enumeration_list, link)
+ if (strcmp(e->name, enum_name) == 0)
+ return e;
+ } else if (interface) {
+ enum_name = enum_attribute;
+
+ wl_list_for_each(e, &interface->enumeration_list, link)
+ if (strcmp(e->name, enum_name) == 0)
+ return e;
+ }
+
+ return NULL;
+}
+
+static void
+verify_arguments(struct parse_context *ctx,
+ struct interface *interface,
+ struct wl_list *messages,
+ struct wl_list *enumerations)
+{
+ struct message *m;
+ wl_list_for_each(m, messages, link) {
+ struct arg *a;
+ wl_list_for_each(a, &m->arg_list, link) {
+ struct enumeration *e;
+
+ if (!a->enumeration_name)
+ continue;
+
+
+ e = find_enumeration(ctx->protocol, interface,
+ a->enumeration_name);
+
+ switch (a->type) {
+ case INT:
+ if (e && e->bitfield)
+ fail(&ctx->loc,
+ "bitfield-style enum must only be referenced by uint");
+ break;
+ case UNSIGNED:
+ break;
+ default:
+ fail(&ctx->loc,
+ "enumeration-style argument has wrong type");
+ }
+ }
+ }
+
+}
+
+static char *
+wayland_strndup(const char *s, size_t size)
+{
+ char *r = malloc(size + 1);
+ strncpy(r, s, size);
+ r[size] = '\0';
+ return r;
+}
+
+static void
+end_element(void *data, const XML_Char *name)
+{
+ struct parse_context *ctx = data;
+
+ if (strcmp(name, "copyright") == 0) {
+ ctx->protocol->copyright =
+ wayland_strndup(ctx->character_data,
+ ctx->character_data_length);
+ } else if (strcmp(name, "description") == 0) {
+ ctx->description->text =
+ wayland_strndup(ctx->character_data,
+ ctx->character_data_length);
+ ctx->description = NULL;
+ } else if (strcmp(name, "request") == 0 ||
+ strcmp(name, "event") == 0) {
+ ctx->message = NULL;
+ } else if (strcmp(name, "enum") == 0) {
+ if (wl_list_empty(&ctx->enumeration->entry_list)) {
+ fail(&ctx->loc, "enumeration %s was empty",
+ ctx->enumeration->name);
+ }
+ ctx->enumeration = NULL;
+ } else if (strcmp(name, "protocol") == 0) {
+ struct interface *i;
+
+ wl_list_for_each(i, &ctx->protocol->interface_list, link) {
+ verify_arguments(ctx, i, &i->request_list, &i->enumeration_list);
+ verify_arguments(ctx, i, &i->event_list, &i->enumeration_list);
+ }
+ }
+}
+
+static void
+character_data(void *data, const XML_Char *s, int len)
+{
+ struct parse_context *ctx = data;
+
+ if (ctx->character_data_length + len > sizeof (ctx->character_data)) {
+ fprintf(stderr, "too much character data");
+ exit(EXIT_FAILURE);
+ }
+
+ memcpy(ctx->character_data + ctx->character_data_length, s, len);
+ ctx->character_data_length += len;
+}
+
+static void
+format_text_to_comment(const char *text, bool standalone_comment)
+{
+ int bol = 1, start = 0, i, length;
+ bool comment_started = !standalone_comment;
+
+ length = strlen(text);
+ for (i = 0; i <= length; i++) {
+ if (bol && (text[i] == ' ' || text[i] == '\t')) {
+ continue;
+ } else if (bol) {
+ bol = 0;
+ start = i;
+ }
+ if (text[i] == '\n' ||
+ (text[i] == '\0' && !(start == i))) {
+ printf("%s%s%.*s\n",
+ comment_started ? " *" : "/*",
+ i > start ? " " : "",
+ i - start, text + start);
+ bol = 1;
+ comment_started = true;
+ }
+ }
+ if (comment_started && standalone_comment)
+ printf(" */\n\n");
+}
+
+static void
+emit_opcodes(struct wl_list *message_list, struct interface *interface)
+{
+ struct message *m;
+ int opcode;
+
+ if (wl_list_empty(message_list))
+ return;
+
+ opcode = 0;
+ wl_list_for_each(m, message_list, link)
+ printf("#define %s_%s %d\n",
+ interface->uppercase_name, m->uppercase_name, opcode++);
+
+ printf("\n");
+}
+
+static void
+emit_opcode_versions(struct wl_list *message_list, struct interface *interface)
+{
+ struct message *m;
+
+ wl_list_for_each(m, message_list, link) {
+ printf("/**\n * @ingroup iface_%s\n */\n", interface->name);
+ printf("#define %s_%s_SINCE_VERSION %d\n",
+ interface->uppercase_name, m->uppercase_name, m->since);
+ }
+
+ printf("\n");
+}
+
+static void
+emit_type(struct arg *a)
+{
+ switch (a->type) {
+ default:
+ case INT:
+ case FD:
+ printf("int32_t ");
+ break;
+ case NEW_ID:
+ case UNSIGNED:
+ printf("uint32_t ");
+ break;
+ case FIXED:
+ printf("wl_fixed_t ");
+ break;
+ case STRING:
+ printf("const char *");
+ break;
+ case OBJECT:
+ printf("struct %s *", a->interface_name);
+ break;
+ case ARRAY:
+ printf("struct wl_array *");
+ break;
+ }
+}
+
+static void
+emit_stubs(struct wl_list *message_list, struct interface *interface)
+{
+ struct message *m;
+ struct arg *a, *ret;
+ int has_destructor, has_destroy;
+
+ printf("/** @ingroup iface_%s */\n", interface->name);
+ printf("static inline void\n"
+ "%s_set_user_data(struct %s *%s, void *user_data)\n"
+ "{\n"
+ "\twl_proxy_set_user_data((struct wl_proxy *) %s, user_data);\n"
+ "}\n\n",
+ interface->name, interface->name, interface->name,
+ interface->name);
+
+ printf("/** @ingroup iface_%s */\n", interface->name);
+ printf("static inline void *\n"
+ "%s_get_user_data(struct %s *%s)\n"
+ "{\n"
+ "\treturn wl_proxy_get_user_data((struct wl_proxy *) %s);\n"
+ "}\n\n",
+ interface->name, interface->name, interface->name,
+ interface->name);
+
+ printf("static inline uint32_t\n"
+ "%s_get_version(struct %s *%s)\n"
+ "{\n"
+ "\treturn wl_proxy_get_version((struct wl_proxy *) %s);\n"
+ "}\n\n",
+ interface->name, interface->name, interface->name,
+ interface->name);
+
+ has_destructor = 0;
+ has_destroy = 0;
+ wl_list_for_each(m, message_list, link) {
+ if (m->destructor)
+ has_destructor = 1;
+ if (strcmp(m->name, "destroy") == 0)
+ has_destroy = 1;
+ }
+
+ if (!has_destructor && has_destroy) {
+ fail(&interface->loc,
+ "interface '%s' has method named destroy "
+ "but no destructor",
+ interface->name);
+ exit(EXIT_FAILURE);
+ }
+
+ if (!has_destroy && strcmp(interface->name, "wl_display") != 0) {
+ printf("/** @ingroup iface_%s */\n", interface->name);
+ printf("static inline void\n"
+ "%s_destroy(struct %s *%s)\n"
+ "{\n"
+ "\twl_proxy_destroy("
+ "(struct wl_proxy *) %s);\n"
+ "}\n\n",
+ interface->name, interface->name, interface->name,
+ interface->name);
+ }
+
+ if (wl_list_empty(message_list))
+ return;
+
+ wl_list_for_each(m, message_list, link) {
+ if (m->new_id_count > 1) {
+ warn(&m->loc,
+ "request '%s::%s' has more than "
+ "one new_id arg, not emitting stub\n",
+ interface->name, m->name);
+ continue;
+ }
+
+ ret = NULL;
+ wl_list_for_each(a, &m->arg_list, link) {
+ if (a->type == NEW_ID)
+ ret = a;
+ }
+
+ printf("/**\n"
+ " * @ingroup iface_%s\n", interface->name);
+ if (m->description && m->description->text)
+ format_text_to_comment(m->description->text, false);
+ printf(" */\n");
+ if (ret && ret->interface_name == NULL)
+ printf("static inline void *\n");
+ else if (ret)
+ printf("static inline struct %s *\n",
+ ret->interface_name);
+ else
+ printf("static inline void\n");
+
+ printf("%s_%s(struct %s *%s",
+ interface->name, m->name,
+ interface->name, interface->name);
+
+ wl_list_for_each(a, &m->arg_list, link) {
+ if (a->type == NEW_ID && a->interface_name == NULL) {
+ printf(", const struct wl_interface *interface"
+ ", uint32_t version");
+ continue;
+ } else if (a->type == NEW_ID)
+ continue;
+ printf(", ");
+ emit_type(a);
+ printf("%s", a->name);
+ }
+
+ printf(")\n"
+ "{\n");
+ if (ret && ret->interface_name == NULL) {
+ /* an arg has type ="new_id" but interface is not
+ * provided, such as in wl_registry.bind */
+ printf("\tstruct wl_proxy *%s;\n\n"
+ "\t%s = wl_proxy_marshal_constructor_versioned("
+ "(struct wl_proxy *) %s,\n"
+ "\t\t\t %s_%s, interface, version",
+ ret->name, ret->name,
+ interface->name,
+ interface->uppercase_name,
+ m->uppercase_name);
+ } else if (ret) {
+ /* Normal factory case, an arg has type="new_id" and
+ * an interface is provided */
+ printf("\tstruct wl_proxy *%s;\n\n"
+ "\t%s = wl_proxy_marshal_constructor("
+ "(struct wl_proxy *) %s,\n"
+ "\t\t\t %s_%s, &%s_interface",
+ ret->name, ret->name,
+ interface->name,
+ interface->uppercase_name,
+ m->uppercase_name,
+ ret->interface_name);
+ } else {
+ /* No args have type="new_id" */
+ printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
+ "\t\t\t %s_%s",
+ interface->name,
+ interface->uppercase_name,
+ m->uppercase_name);
+ }
+
+ wl_list_for_each(a, &m->arg_list, link) {
+ if (a->type == NEW_ID) {
+ if (a->interface_name == NULL)
+ printf(", interface->name, version");
+ printf(", NULL");
+ } else {
+ printf(", %s", a->name);
+ }
+ }
+ printf(");\n");
+
+ if (m->destructor)
+ printf("\n\twl_proxy_destroy("
+ "(struct wl_proxy *) %s);\n",
+ interface->name);
+
+ if (ret && ret->interface_name == NULL)
+ printf("\n\treturn (void *) %s;\n", ret->name);
+ else if (ret)
+ printf("\n\treturn (struct %s *) %s;\n",
+ ret->interface_name, ret->name);
+
+ printf("}\n\n");
+ }
+}
+
+static void
+emit_event_wrappers(struct wl_list *message_list, struct interface *interface)
+{
+ struct message *m;
+ struct arg *a;
+
+ /* We provide hand written functions for the display object */
+ if (strcmp(interface->name, "wl_display") == 0)
+ return;
+
+ wl_list_for_each(m, message_list, link) {
+ printf("/**\n"
+ " * @ingroup iface_%s\n"
+ " * Sends an %s event to the client owning the resource.\n",
+ interface->name,
+ m->name);
+ printf(" * @param resource_ The client's resource\n");
+ wl_list_for_each(a, &m->arg_list, link) {
+ if (a->summary)
+ printf(" * @param %s %s\n", a->name, a->summary);
+ }
+ printf(" */\n");
+ printf("static inline void\n"
+ "%s_send_%s(struct wl_resource *resource_",
+ interface->name, m->name);
+
+ wl_list_for_each(a, &m->arg_list, link) {
+ printf(", ");
+ switch (a->type) {
+ case NEW_ID:
+ case OBJECT:
+ printf("struct wl_resource *");
+ break;
+ default:
+ emit_type(a);
+ }
+ printf("%s", a->name);
+ }
+
+ printf(")\n"
+ "{\n"
+ "\twl_resource_post_event(resource_, %s_%s",
+ interface->uppercase_name, m->uppercase_name);
+
+ wl_list_for_each(a, &m->arg_list, link)
+ printf(", %s", a->name);
+
+ printf(");\n");
+ printf("}\n\n");
+ }
+}
+
+static void
+emit_enumerations(struct interface *interface)
+{
+ struct enumeration *e;
+ struct entry *entry;
+
+ wl_list_for_each(e, &interface->enumeration_list, link) {
+ struct description *desc = e->description;
+
+ printf("#ifndef %s_%s_ENUM\n",
+ interface->uppercase_name, e->uppercase_name);
+ printf("#define %s_%s_ENUM\n",
+ interface->uppercase_name, e->uppercase_name);
+
+ if (desc) {
+ printf("/**\n");
+ printf(" * @ingroup iface_%s\n", interface->name);
+ format_text_to_comment(desc->summary, false);
+ if (desc->text)
+ format_text_to_comment(desc->text, false);
+ printf(" */\n");
+ }
+ printf("enum %s_%s {\n", interface->name, e->name);
+ wl_list_for_each(entry, &e->entry_list, link) {
+ if (entry->summary || entry->since > 1) {
+ printf("\t/**\n");
+ if (entry->summary)
+ printf("\t * %s\n", entry->summary);
+ if (entry->since > 1)
+ printf("\t * @since %d\n", entry->since);
+ printf("\t */\n");
+ }
+ printf("\t%s_%s_%s = %s,\n",
+ interface->uppercase_name,
+ e->uppercase_name,
+ entry->uppercase_name, entry->value);
+ }
+ printf("};\n");
+
+ wl_list_for_each(entry, &e->entry_list, link) {
+ if (entry->since == 1)
+ continue;
+
+ printf("/**\n * @ingroup iface_%s\n */\n", interface->name);
+ printf("#define %s_%s_%s_SINCE_VERSION %d\n",
+ interface->uppercase_name,
+ e->uppercase_name, entry->uppercase_name,
+ entry->since);
+
+ }
+
+ printf("#endif /* %s_%s_ENUM */\n\n",
+ interface->uppercase_name, e->uppercase_name);
+ }
+}
+
+static void
+emit_structs(struct wl_list *message_list, struct interface *interface, enum side side)
+{
+ struct message *m;
+ struct arg *a;
+ int n;
+
+ if (wl_list_empty(message_list))
+ return;
+
+ printf("/**\n");
+ printf(" * @ingroup iface_%s\n", interface->name);
+ printf(" * @struct %s_%s\n", interface->name,
+ (side == SERVER) ? "interface" : "listener");
+ printf(" */\n");
+ printf("struct %s_%s {\n", interface->name,
+ (side == SERVER) ? "interface" : "listener");
+
+ wl_list_for_each(m, message_list, link) {
+ struct description *mdesc = m->description;
+
+ printf("\t/**\n");
+ if (mdesc) {
+ if (mdesc->summary)
+ printf("\t * %s\n", mdesc->summary);
+ printf("\t *\n");
+ desc_dump(mdesc->text, "\t * ");
+ }
+ wl_list_for_each(a, &m->arg_list, link) {
+ if (side == SERVER && a->type == NEW_ID &&
+ a->interface_name == NULL)
+ printf("\t * @param interface name of the objects interface\n"
+ "\t * @param version version of the objects interface\n");
+
+ if (a->summary)
+ printf("\t * @param %s %s\n", a->name,
+ a->summary);
+ }
+ if (m->since > 1) {
+ printf("\t * @since %d\n", m->since);
+ }
+ printf("\t */\n");
+ printf("\tvoid (*%s)(", m->name);
+
+ n = strlen(m->name) + 17;
+ if (side == SERVER) {
+ printf("struct wl_client *client,\n"
+ "%sstruct wl_resource *resource",
+ indent(n));
+ } else {
+ printf("void *data,\n"),
+ printf("%sstruct %s *%s",
+ indent(n), interface->name, interface->name);
+ }
+
+ wl_list_for_each(a, &m->arg_list, link) {
+ printf(",\n%s", indent(n));
+
+ if (side == SERVER && a->type == OBJECT)
+ printf("struct wl_resource *");
+ else if (side == SERVER && a->type == NEW_ID && a->interface_name == NULL)
+ printf("const char *interface, uint32_t version, uint32_t ");
+ else if (side == CLIENT && a->type == OBJECT && a->interface_name == NULL)
+ printf("void *");
+
+ else if (side == CLIENT && a->type == NEW_ID)
+ printf("struct %s *", a->interface_name);
+ else
+ emit_type(a);
+
+ printf("%s", a->name);
+ }
+
+ printf(");\n");
+ }
+
+ printf("};\n\n");
+
+ if (side == CLIENT) {
+ printf("/**\n"
+ " * @ingroup iface_%s\n"
+ " */\n", interface->name);
+ printf("static inline int\n"
+ "%s_add_listener(struct %s *%s,\n"
+ "%sconst struct %s_listener *listener, void *data)\n"
+ "{\n"
+ "\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n"
+ "%s(void (**)(void)) listener, data);\n"
+ "}\n\n",
+ interface->name, interface->name, interface->name,
+ indent(14 + strlen(interface->name)),
+ interface->name,
+ interface->name,
+ indent(37));
+ }
+}
+
+static void
+emit_types_forward_declarations(struct protocol *protocol,
+ struct wl_list *message_list,
+ struct wl_array *types)
+{
+ struct message *m;
+ struct arg *a;
+ int length;
+ char **p;
+
+ wl_list_for_each(m, message_list, link) {
+ length = 0;
+ m->all_null = 1;
+ wl_list_for_each(a, &m->arg_list, link) {
+ length++;
+ switch (a->type) {
+ case NEW_ID:
+ case OBJECT:
+ if (!a->interface_name)
+ continue;
+
+ m->all_null = 0;
+ p = fail_on_null(wl_array_add(types, sizeof *p));
+ *p = a->interface_name;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (m->all_null && length > protocol->null_run_length)
+ protocol->null_run_length = length;
+ }
+}
+
+static int
+cmp_names(const void *p1, const void *p2)
+{
+ const char * const *s1 = p1, * const *s2 = p2;
+
+ return strcmp(*s1, *s2);
+}
+
+static const char *
+get_include_name(bool core, enum side side)
+{
+ if (side == SERVER)
+ return core ? "wayland-server-core.h" : "wayland-server.h";
+ else
+ return core ? "wayland-client-core.h" : "wayland-client.h";
+}
+
+static void
+emit_mainpage_blurb(const struct protocol *protocol, enum side side)
+{
+ struct interface *i;
+
+ printf("/**\n"
+ " * @page page_%s The %s protocol\n",
+ protocol->name, protocol->name);
+
+ if (protocol->description) {
+ if (protocol->description->summary) {
+ printf(" * %s\n"
+ " *\n", protocol->description->summary);
+ }
+
+ if (protocol->description->text) {
+ printf(" * @section page_desc_%s Description\n", protocol->name);
+ format_text_to_comment(protocol->description->text, false);
+ printf(" *\n");
+ }
+ }
+
+ printf(" * @section page_ifaces_%s Interfaces\n", protocol->name);
+ wl_list_for_each(i, &protocol->interface_list, link) {
+ printf(" * - @subpage page_iface_%s - %s\n",
+ i->name,
+ i->description && i->description->summary ? i->description->summary : "");
+ }
+
+ if (protocol->copyright) {
+ printf(" * @section page_copyright_%s Copyright\n",
+ protocol->name);
+ printf(" * \n");
+ format_text_to_comment(protocol->copyright, false);
+ printf(" * \n");
+ }
+
+ printf(" */\n");
+}
+
+static void
+emit_header(struct protocol *protocol, enum side side)
+{
+ struct interface *i, *i_next;
+ struct wl_array types;
+ const char *s = (side == SERVER) ? "SERVER" : "CLIENT";
+ char **p, *prev;
+
+ printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION);
+
+ printf("#ifndef %s_%s_PROTOCOL_H\n"
+ "#define %s_%s_PROTOCOL_H\n"
+ "\n"
+ "#include \n"
+ "#include \n"
+ "#include \"%s\"\n\n"
+ "#ifdef __cplusplus\n"
+ "extern \"C\" {\n"
+ "#endif\n\n",
+ protocol->uppercase_name, s,
+ protocol->uppercase_name, s,
+ get_include_name(protocol->core_headers, side));
+ if (side == SERVER)
+ printf("struct wl_client;\n"
+ "struct wl_resource;\n\n");
+
+ emit_mainpage_blurb(protocol, side);
+
+ wl_array_init(&types);
+ wl_list_for_each(i, &protocol->interface_list, link) {
+ emit_types_forward_declarations(protocol, &i->request_list, &types);
+ emit_types_forward_declarations(protocol, &i->event_list, &types);
+ }
+
+ wl_list_for_each(i, &protocol->interface_list, link) {
+ p = fail_on_null(wl_array_add(&types, sizeof *p));
+ *p = i->name;
+ }
+
+ qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names);
+ prev = NULL;
+ wl_array_for_each(p, &types) {
+ if (prev && strcmp(*p, prev) == 0)
+ continue;
+ printf("struct %s;\n", *p);
+ prev = *p;
+ }
+ wl_array_release(&types);
+ printf("\n");
+
+ wl_list_for_each(i, &protocol->interface_list, link) {
+ printf("#ifndef %s_INTERFACE\n", i->uppercase_name);
+ printf("#define %s_INTERFACE\n", i->uppercase_name);
+ printf("/**\n"
+ " * @page page_iface_%s %s\n",
+ i->name, i->name);
+ if (i->description && i->description->text) {
+ printf(" * @section page_iface_%s_desc Description\n",
+ i->name);
+ format_text_to_comment(i->description->text, false);
+ }
+ printf(" * @section page_iface_%s_api API\n"
+ " * See @ref iface_%s.\n"
+ " */\n",
+ i->name, i->name);
+ printf("/**\n"
+ " * @defgroup iface_%s The %s interface\n",
+ i->name, i->name);
+ if (i->description && i->description->text)
+ format_text_to_comment(i->description->text, false);
+ printf(" */\n");
+ printf("extern const struct wl_interface "
+ "%s_interface;\n", i->name);
+ printf("#endif\n");
+ }
+
+ printf("\n");
+
+ wl_list_for_each_safe(i, i_next, &protocol->interface_list, link) {
+
+ emit_enumerations(i);
+
+ if (side == SERVER) {
+ emit_structs(&i->request_list, i, side);
+ emit_opcodes(&i->event_list, i);
+ emit_opcode_versions(&i->event_list, i);
+ emit_opcode_versions(&i->request_list, i);
+ emit_event_wrappers(&i->event_list, i);
+ } else {
+ emit_structs(&i->event_list, i, side);
+ emit_opcodes(&i->request_list, i);
+ emit_opcode_versions(&i->event_list, i);
+ emit_opcode_versions(&i->request_list, i);
+ emit_stubs(&i->request_list, i);
+ }
+
+ free_interface(i);
+ }
+
+ printf("#ifdef __cplusplus\n"
+ "}\n"
+ "#endif\n"
+ "\n"
+ "#endif\n");
+}
+
+static void
+emit_null_run(struct protocol *protocol)
+{
+ int i;
+
+ for (i = 0; i < protocol->null_run_length; i++)
+ printf("\tNULL,\n");
+}
+
+static void
+emit_types(struct protocol *protocol, struct wl_list *message_list)
+{
+ struct message *m;
+ struct arg *a;
+
+ wl_list_for_each(m, message_list, link) {
+ if (m->all_null) {
+ m->type_index = 0;
+ continue;
+ }
+
+ m->type_index =
+ protocol->null_run_length + protocol->type_index;
+ protocol->type_index += m->arg_count;
+
+ wl_list_for_each(a, &m->arg_list, link) {
+ switch (a->type) {
+ case NEW_ID:
+ case OBJECT:
+ if (a->interface_name)
+ printf("\t&%s_interface,\n",
+ a->interface_name);
+ else
+ printf("\tNULL,\n");
+ break;
+ default:
+ printf("\tNULL,\n");
+ break;
+ }
+ }
+ }
+}
+
+static void
+emit_messages(const char *name, struct wl_list *message_list,
+ struct interface *interface, const char *suffix)
+{
+ struct message *m;
+ struct arg *a;
+
+ if (wl_list_empty(message_list))
+ return;
+
+ printf("static const struct wl_message "
+ "%s_%s[] = {\n",
+ interface->name, suffix);
+
+ wl_list_for_each(m, message_list, link) {
+ printf("\t{ \"%s\", \"", m->name);
+
+ if (m->since > 1)
+ printf("%d", m->since);
+
+ wl_list_for_each(a, &m->arg_list, link) {
+ if (is_nullable_type(a) && a->nullable)
+ printf("?");
+
+ switch (a->type) {
+ default:
+ case INT:
+ printf("i");
+ break;
+ case NEW_ID:
+ if (a->interface_name == NULL)
+ printf("su");
+ printf("n");
+ break;
+ case UNSIGNED:
+ printf("u");
+ break;
+ case FIXED:
+ printf("f");
+ break;
+ case STRING:
+ printf("s");
+ break;
+ case OBJECT:
+ printf("o");
+ break;
+ case ARRAY:
+ printf("a");
+ break;
+ case FD:
+ printf("h");
+ break;
+ }
+ }
+ printf("\", %s_types + %d },\n", name, m->type_index);
+ }
+
+ printf("};\n\n");
+}
+
+
+static void
+emit_code(struct protocol *protocol, enum visibility vis)
+{
+ const char *symbol_visibility;
+ struct interface *i, *next;
+ struct wl_array types;
+ char **p, *prev;
+
+ printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION);
+
+ if (protocol->copyright)
+ format_text_to_comment(protocol->copyright, true);
+
+ printf("#include