2 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting documentation, and
9 * that the name of the copyright holders not be used in advertising or
10 * publicity pertaining to distribution of the software without specific,
11 * written prior permission. The copyright holders make no representations
12 * about the suitability of this software for any purpose. It is provided "as
13 * is" without express or implied warranty.
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
31 #include "wayland-util.h"
36 fprintf(stderr, "usage: ./scanner [client-header|server-header|code]\n");
40 #define XML_BUFFER_SIZE 4096
50 struct wl_list interface_list;
54 struct description *description;
62 struct wl_list request_list;
63 struct wl_list event_list;
64 struct wl_list enumeration_list;
66 struct description *description;
72 struct wl_list arg_list;
79 struct description *description;
104 char *uppercase_name;
105 struct wl_list entry_list;
107 struct description *description;
112 char *uppercase_name;
118 struct parse_context {
119 const char *filename;
121 struct protocol *protocol;
122 struct interface *interface;
123 struct message *message;
124 struct enumeration *enumeration;
125 struct description *description;
126 char character_data[8192];
127 unsigned int character_data_length;
131 list_length(struct wl_list *list)
136 for (i = 0, l = list->next; l != list; i++, l = l->next)
143 uppercase_dup(const char *src)
149 for (i = 0; u[i]; i++)
150 u[i] = toupper(u[i]);
156 static const char *indent(int n)
158 const char *whitespace[] = {
159 "\t\t\t\t\t\t\t\t\t\t\t\t",
160 "\t\t\t\t\t\t\t\t\t\t\t\t ",
161 "\t\t\t\t\t\t\t\t\t\t\t\t ",
162 "\t\t\t\t\t\t\t\t\t\t\t\t ",
163 "\t\t\t\t\t\t\t\t\t\t\t\t ",
164 "\t\t\t\t\t\t\t\t\t\t\t\t ",
165 "\t\t\t\t\t\t\t\t\t\t\t\t ",
166 "\t\t\t\t\t\t\t\t\t\t\t\t "
169 return whitespace[n % 8] + 12 - n / 8;
173 desc_dump(char *desc, const char *fmt, ...) __attribute__((format(printf,2,3)));
176 desc_dump(char *desc, const char *fmt, ...)
180 int col, i, j, k, startcol;
183 vsnprintf(buf, sizeof buf, fmt, ap);
186 for (i = 0, col = 0; buf[i] != '*'; i++) {
188 col = (col + 8) & ~7;
201 col += strlen(&buf[i]);
202 if (col - startcol > 2)
207 for (i = 0; desc[i]; ) {
209 while (desc[i] && isspace(desc[i]))
215 while (desc[i] && !isspace(desc[i]))
218 if (col + i - j > 72) {
219 printf("\n%s*%c", indent(startcol), hang);
223 if (col > startcol && k > 0)
225 col += printf("%.*s", i - j, &desc[j]);
231 fail(struct parse_context *ctx, const char *msg)
233 fprintf(stderr, "%s:%ld: %s\n",
234 ctx->filename, XML_GetCurrentLineNumber(ctx->parser), msg);
239 is_nullable_type(struct arg *arg)
242 /* Strings, objects, and arrays are possibly nullable */
254 start_element(void *data, const char *element_name, const char **atts)
256 struct parse_context *ctx = data;
257 struct interface *interface;
258 struct message *message;
260 struct enumeration *enumeration;
262 struct description *description;
263 const char *name, *type, *interface_name, *value, *summary, *since;
264 const char *allow_null;
271 interface_name = NULL;
277 for (i = 0; atts[i]; i += 2) {
278 if (strcmp(atts[i], "name") == 0)
280 if (strcmp(atts[i], "version") == 0)
281 version = atoi(atts[i + 1]);
282 if (strcmp(atts[i], "type") == 0)
284 if (strcmp(atts[i], "value") == 0)
286 if (strcmp(atts[i], "interface") == 0)
287 interface_name = atts[i + 1];
288 if (strcmp(atts[i], "summary") == 0)
289 summary = atts[i + 1];
290 if (strcmp(atts[i], "since") == 0)
292 if (strcmp(atts[i], "allow-null") == 0)
293 allow_null = atts[i + 1];
296 ctx->character_data_length = 0;
297 if (strcmp(element_name, "protocol") == 0) {
299 fail(ctx, "no protocol name given");
301 ctx->protocol->name = strdup(name);
302 ctx->protocol->uppercase_name = uppercase_dup(name);
303 ctx->protocol->description = NULL;
304 } else if (strcmp(element_name, "copyright") == 0) {
306 } else if (strcmp(element_name, "interface") == 0) {
308 fail(ctx, "no interface name given");
311 fail(ctx, "no interface version given");
313 interface = malloc(sizeof *interface);
314 interface->name = strdup(name);
315 interface->uppercase_name = uppercase_dup(name);
316 interface->version = version;
317 interface->description = NULL;
318 interface->since = 1;
319 wl_list_init(&interface->request_list);
320 wl_list_init(&interface->event_list);
321 wl_list_init(&interface->enumeration_list);
322 wl_list_insert(ctx->protocol->interface_list.prev,
324 ctx->interface = interface;
325 } else if (strcmp(element_name, "request") == 0 ||
326 strcmp(element_name, "event") == 0) {
328 fail(ctx, "no request name given");
330 message = malloc(sizeof *message);
331 message->name = strdup(name);
332 message->uppercase_name = uppercase_dup(name);
333 wl_list_init(&message->arg_list);
334 message->arg_count = 0;
335 message->description = NULL;
337 if (strcmp(element_name, "request") == 0)
338 wl_list_insert(ctx->interface->request_list.prev,
341 wl_list_insert(ctx->interface->event_list.prev,
344 if (type != NULL && strcmp(type, "destructor") == 0)
345 message->destructor = 1;
347 message->destructor = 0;
350 version = strtol(since, &end, 0);
351 if (errno == EINVAL || end == since || *end != '\0')
352 fail(ctx, "invalid integer\n");
353 if (version <= ctx->interface->since)
354 fail(ctx, "since version not increasing\n");
355 ctx->interface->since = version;
358 message->since = ctx->interface->since;
360 if (strcmp(name, "destroy") == 0 && !message->destructor)
361 fail(ctx, "destroy request should be destructor type");
363 ctx->message = message;
364 } else if (strcmp(element_name, "arg") == 0) {
366 fail(ctx, "no argument name given");
368 arg = malloc(sizeof *arg);
369 arg->name = strdup(name);
371 if (strcmp(type, "int") == 0)
373 else if (strcmp(type, "uint") == 0)
374 arg->type = UNSIGNED;
375 else if (strcmp(type, "fixed") == 0)
377 else if (strcmp(type, "string") == 0)
379 else if (strcmp(type, "array") == 0)
381 else if (strcmp(type, "fd") == 0)
383 else if (strcmp(type, "new_id") == 0) {
385 } else if (strcmp(type, "object") == 0) {
388 fail(ctx, "unknown type");
395 arg->interface_name = strdup(interface_name);
397 arg->interface_name = NULL;
400 if (interface_name != NULL)
401 fail(ctx, "interface not allowed");
405 if (allow_null == NULL || strcmp(allow_null, "false") == 0)
407 else if (strcmp(allow_null, "true") == 0)
410 fail(ctx, "invalid value for allow-null attribute");
412 if (allow_null != NULL && !is_nullable_type(arg))
413 fail(ctx, "allow-null is only valid for objects, strings, and arrays");
417 arg->summary = strdup(summary);
419 wl_list_insert(ctx->message->arg_list.prev, &arg->link);
420 ctx->message->arg_count++;
421 } else if (strcmp(element_name, "enum") == 0) {
423 fail(ctx, "no enum name given");
425 enumeration = malloc(sizeof *enumeration);
426 enumeration->name = strdup(name);
427 enumeration->uppercase_name = uppercase_dup(name);
428 enumeration->description = NULL;
429 wl_list_init(&enumeration->entry_list);
431 wl_list_insert(ctx->interface->enumeration_list.prev,
434 ctx->enumeration = enumeration;
435 } else if (strcmp(element_name, "entry") == 0) {
437 fail(ctx, "no entry name given");
439 entry = malloc(sizeof *entry);
440 entry->name = strdup(name);
441 entry->uppercase_name = uppercase_dup(name);
442 entry->value = strdup(value);
444 entry->summary = strdup(summary);
446 entry->summary = NULL;
447 wl_list_insert(ctx->enumeration->entry_list.prev,
449 } else if (strcmp(element_name, "description") == 0) {
451 fail(ctx, "description without summary");
453 description = malloc(sizeof *description);
454 description->summary = strdup(summary);
457 ctx->message->description = description;
458 else if (ctx->enumeration)
459 ctx->enumeration->description = description;
460 else if (ctx->interface)
461 ctx->interface->description = description;
463 ctx->protocol->description = description;
464 ctx->description = description;
469 end_element(void *data, const XML_Char *name)
471 struct parse_context *ctx = data;
473 if (strcmp(name, "copyright") == 0) {
474 ctx->protocol->copyright =
475 strndup(ctx->character_data,
476 ctx->character_data_length);
477 } else if (strcmp(name, "description") == 0) {
478 ctx->description->text =
479 strndup(ctx->character_data,
480 ctx->character_data_length);
481 ctx->description = NULL;
482 } else if (strcmp(name, "request") == 0 ||
483 strcmp(name, "event") == 0) {
485 } else if (strcmp(name, "enum") == 0) {
486 ctx->enumeration = NULL;
491 character_data(void *data, const XML_Char *s, int len)
493 struct parse_context *ctx = data;
495 if (ctx->character_data_length + len > sizeof (ctx->character_data)) {
496 fprintf(stderr, "too much character data");
500 memcpy(ctx->character_data + ctx->character_data_length, s, len);
501 ctx->character_data_length += len;
505 emit_opcodes(struct wl_list *message_list, struct interface *interface)
510 if (wl_list_empty(message_list))
514 wl_list_for_each(m, message_list, link)
515 printf("#define %s_%s\t%d\n",
516 interface->uppercase_name, m->uppercase_name, opcode++);
522 emit_type(struct arg *a)
535 printf("wl_fixed_t ");
538 printf("const char *");
541 printf("struct %s *", a->interface_name);
544 printf("struct wl_array *");
550 emit_stubs(struct wl_list *message_list, struct interface *interface)
554 int has_destructor, has_destroy;
556 printf("static inline void\n"
557 "%s_set_user_data(struct %s *%s, void *user_data)\n"
559 "\twl_proxy_set_user_data((struct wl_proxy *) %s, user_data);\n"
561 interface->name, interface->name, interface->name,
564 printf("static inline void *\n"
565 "%s_get_user_data(struct %s *%s)\n"
567 "\treturn wl_proxy_get_user_data((struct wl_proxy *) %s);\n"
569 interface->name, interface->name, interface->name,
574 wl_list_for_each(m, message_list, link) {
577 if (strcmp(m->name, "destroy)") == 0)
581 if (!has_destructor && has_destroy) {
583 "interface %s has method named destroy but"
584 "no destructor", interface->name);
588 if (!has_destructor && strcmp(interface->name, "wl_display") != 0)
589 printf("static inline void\n"
590 "%s_destroy(struct %s *%s)\n"
592 "\twl_proxy_destroy("
593 "(struct wl_proxy *) %s);\n"
595 interface->name, interface->name, interface->name,
598 if (wl_list_empty(message_list))
601 wl_list_for_each(m, message_list, link) {
603 wl_list_for_each(a, &m->arg_list, link) {
604 if (a->type == NEW_ID)
608 if (ret && ret->interface_name == NULL)
609 printf("static inline void *\n");
611 printf("static inline struct %s *\n",
612 ret->interface_name);
614 printf("static inline void\n");
616 printf("%s_%s(struct %s *%s",
617 interface->name, m->name,
618 interface->name, interface->name);
620 wl_list_for_each(a, &m->arg_list, link) {
621 if (a->type == NEW_ID && a->interface_name == NULL) {
622 printf(", const struct wl_interface *interface"
623 ", uint32_t version");
625 } else if (a->type == NEW_ID)
629 printf("%s", a->name);
635 printf("\tstruct wl_proxy *%s;\n\n"
636 "\t%s = wl_proxy_create("
637 "(struct wl_proxy *) %s,\n",
638 ret->name, ret->name, interface->name);
639 if (ret->interface_name == NULL)
640 printf("\t\t\t interface);\n");
642 printf("\t\t\t &%s_interface);\n",
643 ret->interface_name);
645 printf("\tif (!%s)\n"
646 "\t\treturn NULL;\n\n",
650 printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
653 interface->uppercase_name,
656 wl_list_for_each(a, &m->arg_list, link) {
657 if (a->type == NEW_ID && a->interface_name == NULL)
658 printf(", interface->name, version");
660 printf("%s", a->name);
665 printf("\n\twl_proxy_destroy("
666 "(struct wl_proxy *) %s);\n",
669 if (ret && ret->interface_name == NULL)
670 printf("\n\treturn (void *) %s;\n", ret->name);
672 printf("\n\treturn (struct %s *) %s;\n",
673 ret->interface_name, ret->name);
680 emit_event_wrappers(struct wl_list *message_list, struct interface *interface)
685 /* We provide hand written functions for the display object */
686 if (strcmp(interface->name, "wl_display") == 0)
689 wl_list_for_each(m, message_list, link) {
690 printf("static inline void\n"
691 "%s_send_%s(struct wl_resource *resource_",
692 interface->name, m->name);
694 wl_list_for_each(a, &m->arg_list, link) {
699 printf("struct wl_resource *");
704 printf("%s", a->name);
709 "\twl_resource_post_event(resource_, %s_%s",
710 interface->uppercase_name, m->uppercase_name);
712 wl_list_for_each(a, &m->arg_list, link)
713 printf(", %s", a->name);
721 emit_enumerations(struct interface *interface)
723 struct enumeration *e;
726 wl_list_for_each(e, &interface->enumeration_list, link) {
727 struct description *desc = e->description;
729 printf("#ifndef %s_%s_ENUM\n",
730 interface->uppercase_name, e->uppercase_name);
731 printf("#define %s_%s_ENUM\n",
732 interface->uppercase_name, e->uppercase_name);
736 desc_dump(desc->summary,
738 interface->name, e->name);
739 wl_list_for_each(entry, &e->entry_list, link) {
740 desc_dump(entry->summary,
742 interface->uppercase_name,
744 entry->uppercase_name);
748 desc_dump(desc->text, " * ");
752 printf("enum %s_%s {\n", interface->name, e->name);
753 wl_list_for_each(entry, &e->entry_list, link)
754 printf("\t%s_%s_%s = %s,\n",
755 interface->uppercase_name,
757 entry->uppercase_name, entry->value);
759 printf("#endif /* %s_%s_ENUM */\n\n",
760 interface->uppercase_name, e->uppercase_name);
765 emit_structs(struct wl_list *message_list, struct interface *interface)
771 if (wl_list_empty(message_list))
774 is_interface = message_list == &interface->request_list;
775 if (interface->description) {
776 struct description *desc = interface->description;
778 desc_dump(desc->summary, " * %s - ", interface->name);
779 wl_list_for_each(m, message_list, link) {
780 struct description *mdesc = m->description;
781 desc_dump(mdesc ? mdesc->summary : "(none)",
786 desc_dump(desc->text, " * ");
789 printf("struct %s_%s {\n", interface->name,
790 is_interface ? "interface" : "listener");
792 wl_list_for_each(m, message_list, link) {
793 struct description *mdesc = m->description;
796 desc_dump(mdesc ? mdesc->summary : "(none)",
797 "\t * %s - ", m->name);
798 wl_list_for_each(a, &m->arg_list, link) {
800 if (is_interface && a->type == NEW_ID &&
801 a->interface_name == NULL)
802 printf("\t * @interface: name of the objects interface\n"
803 "\t * @version: version of the objects interface\n");
806 desc_dump(a->summary ? a->summary : "(none)",
807 "\t * @%s: ", a->name);
811 desc_dump(mdesc->text, "\t * ");
814 printf("\t * @since: %d\n", m->since);
817 printf("\tvoid (*%s)(", m->name);
819 n = strlen(m->name) + 17;
821 printf("struct wl_client *client,\n"
822 "%sstruct wl_resource *resource",
825 printf("void *data,\n"),
826 printf("%sstruct %s *%s",
827 indent(n), interface->name, interface->name);
830 wl_list_for_each(a, &m->arg_list, link) {
831 printf(",\n%s", indent(n));
833 if (is_interface && a->type == OBJECT)
834 printf("struct wl_resource *");
835 else if (is_interface && a->type == NEW_ID && a->interface_name == NULL)
836 printf("const char *interface, uint32_t version, uint32_t ");
837 else if (!is_interface && a->type == OBJECT && a->interface_name == NULL)
838 printf("struct wl_object *");
840 else if (!is_interface && a->type == NEW_ID)
841 printf("struct %s *", a->interface_name);
845 printf("%s", a->name);
854 printf("static inline int\n"
855 "%s_add_listener(struct %s *%s,\n"
856 "%sconst struct %s_listener *listener, void *data)\n"
858 "\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n"
859 "%s(void (**)(void)) listener, data);\n"
861 interface->name, interface->name, interface->name,
862 indent(14 + strlen(interface->name)),
870 format_copyright(const char *copyright)
872 int bol = 1, start = 0, i;
874 for (i = 0; copyright[i]; i++) {
875 if (bol && (copyright[i] == ' ' || copyright[i] == '\t')) {
882 if (copyright[i] == '\n' || copyright[i] == '\0') {
884 i == 0 ? "/*" : " *",
885 i - start, copyright + start);
893 emit_header(struct protocol *protocol, int server)
896 const char *s = server ? "SERVER" : "CLIENT";
898 if (protocol->copyright)
899 format_copyright(protocol->copyright);
901 printf("#ifndef %s_%s_PROTOCOL_H\n"
902 "#define %s_%s_PROTOCOL_H\n"
904 "#ifdef __cplusplus\n"
908 "#include <stdint.h>\n"
909 "#include <stddef.h>\n"
910 "#include \"%s\"\n\n"
911 "struct wl_client;\n"
912 "struct wl_resource;\n\n",
913 protocol->uppercase_name, s,
914 protocol->uppercase_name, s,
915 server ? "wayland-util.h" : "wayland-client.h");
917 wl_list_for_each(i, &protocol->interface_list, link)
918 printf("struct %s;\n", i->name);
921 wl_list_for_each(i, &protocol->interface_list, link) {
922 printf("extern const struct wl_interface "
928 wl_list_for_each(i, &protocol->interface_list, link) {
930 emit_enumerations(i);
933 emit_structs(&i->request_list, i);
934 emit_opcodes(&i->event_list, i);
935 emit_event_wrappers(&i->event_list, i);
937 emit_structs(&i->event_list, i);
938 emit_opcodes(&i->request_list, i);
939 emit_stubs(&i->request_list, i);
943 printf("#ifdef __cplusplus\n"
951 emit_types_forward_declarations(struct protocol *protocol,
952 struct wl_list *message_list)
958 wl_list_for_each(m, message_list, link) {
961 wl_list_for_each(a, &m->arg_list, link) {
966 if (!a->interface_name)
970 printf("extern const struct wl_interface %s_interface;\n",
978 if (m->all_null && length > protocol->null_run_length)
979 protocol->null_run_length = length;
984 emit_null_run(struct protocol *protocol)
988 for (i = 0; i < protocol->null_run_length; i++)
993 emit_types(struct protocol *protocol, struct wl_list *message_list)
998 wl_list_for_each(m, message_list, link) {
1005 protocol->null_run_length + protocol->type_index;
1006 protocol->type_index += m->arg_count;
1008 wl_list_for_each(a, &m->arg_list, link) {
1012 if (a->interface_name)
1013 printf("\t&%s_interface,\n",
1016 printf("\tNULL,\n");
1019 printf("\tNULL,\n");
1027 emit_messages(struct wl_list *message_list,
1028 struct interface *interface, const char *suffix)
1033 if (wl_list_empty(message_list))
1036 printf("static const struct wl_message "
1038 interface->name, suffix);
1040 wl_list_for_each(m, message_list, link) {
1041 printf("\t{ \"%s\", \"", m->name);
1042 wl_list_for_each(a, &m->arg_list, link) {
1043 if (is_nullable_type(a) && a->nullable)
1052 if (a->interface_name == NULL)
1076 printf("\", types + %d },\n", m->type_index);
1083 emit_code(struct protocol *protocol)
1085 struct interface *i;
1087 if (protocol->copyright)
1088 format_copyright(protocol->copyright);
1090 printf("#include <stdlib.h>\n"
1091 "#include <stdint.h>\n"
1092 "#include \"wayland-util.h\"\n\n");
1094 wl_list_for_each(i, &protocol->interface_list, link) {
1095 emit_types_forward_declarations(protocol, &i->request_list);
1096 emit_types_forward_declarations(protocol, &i->event_list);
1100 printf("static const struct wl_interface *types[] = {\n");
1101 emit_null_run(protocol);
1102 wl_list_for_each(i, &protocol->interface_list, link) {
1103 emit_types(protocol, &i->request_list);
1104 emit_types(protocol, &i->event_list);
1108 wl_list_for_each(i, &protocol->interface_list, link) {
1110 emit_messages(&i->request_list, i, "requests");
1111 emit_messages(&i->event_list, i, "events");
1113 printf("WL_EXPORT const struct wl_interface "
1114 "%s_interface = {\n"
1116 i->name, i->name, i->version);
1118 if (!wl_list_empty(&i->request_list))
1119 printf("\t%d, %s_requests,\n",
1120 list_length(&i->request_list), i->name);
1122 printf("\t0, NULL,\n");
1124 if (!wl_list_empty(&i->event_list))
1125 printf("\t%d, %s_events,\n",
1126 list_length(&i->event_list), i->name);
1128 printf("\t0, NULL,\n");
1134 int main(int argc, char *argv[])
1136 struct parse_context ctx;
1137 struct protocol protocol;
1142 usage(EXIT_FAILURE);
1144 wl_list_init(&protocol.interface_list);
1145 protocol.type_index = 0;
1146 protocol.null_run_length = 0;
1147 protocol.copyright = NULL;
1148 memset(&ctx, 0, sizeof ctx);
1149 ctx.protocol = &protocol;
1151 ctx.filename = "<stdin>";
1152 ctx.parser = XML_ParserCreate(NULL);
1153 XML_SetUserData(ctx.parser, &ctx);
1154 if (ctx.parser == NULL) {
1155 fprintf(stderr, "failed to create parser\n");
1159 XML_SetElementHandler(ctx.parser, start_element, end_element);
1160 XML_SetCharacterDataHandler(ctx.parser, character_data);
1163 buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
1164 len = fread(buf, 1, XML_BUFFER_SIZE, stdin);
1166 fprintf(stderr, "fread: %m\n");
1169 XML_ParseBuffer(ctx.parser, len, len == 0);
1173 XML_ParserFree(ctx.parser);
1175 if (strcmp(argv[1], "client-header") == 0) {
1176 emit_header(&protocol, 0);
1177 } else if (strcmp(argv[1], "server-header") == 0) {
1178 emit_header(&protocol, 1);
1179 } else if (strcmp(argv[1], "code") == 0) {
1180 emit_code(&protocol);