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
30 #include "wayland-util.h"
35 fprintf(stderr, "usage: ./scanner [client-header|server-header|code]\n");
39 #define XML_BUFFER_SIZE 4096
49 struct wl_list interface_list;
53 struct description *description;
60 struct wl_list request_list;
61 struct wl_list event_list;
62 struct wl_list enumeration_list;
64 struct description *description;
70 struct wl_list arg_list;
76 struct description *description;
100 struct wl_list entry_list;
102 struct description *description;
107 char *uppercase_name;
113 struct parse_context {
114 const char *filename;
116 struct protocol *protocol;
117 struct interface *interface;
118 struct message *message;
119 struct enumeration *enumeration;
120 struct description *description;
121 char character_data[8192];
122 int character_data_length;
126 uppercase_dup(const char *src)
132 for (i = 0; u[i]; i++)
133 u[i] = toupper(u[i]);
140 desc_dump(char *src, int startcol)
142 int i, j = 0, col = startcol, line = 0, len;
144 /* Strip leading space */
145 for (i = 0; isspace(src[i]); i++)
148 for (; src[i]; i++) {
149 /* Collapse multiple spaces into 1 */
150 if (isspace(src[i]) && isspace(src[i + 1]))
156 if (col > 72 && isspace(src[i])) {
159 for (j = 0; j < startcol; j++)
175 fail(struct parse_context *ctx, const char *msg)
177 fprintf(stderr, "%s:%ld: %s\n",
178 ctx->filename, XML_GetCurrentLineNumber(ctx->parser), msg);
183 start_element(void *data, const char *element_name, const char **atts)
185 struct parse_context *ctx = data;
186 struct interface *interface;
187 struct message *message;
189 struct enumeration *enumeration;
191 struct description *description;
192 const char *name, *type, *interface_name, *value, *summary;
198 interface_name = NULL;
202 for (i = 0; atts[i]; i += 2) {
203 if (strcmp(atts[i], "name") == 0)
205 if (strcmp(atts[i], "version") == 0)
206 version = atoi(atts[i + 1]);
207 if (strcmp(atts[i], "type") == 0)
209 if (strcmp(atts[i], "value") == 0)
211 if (strcmp(atts[i], "interface") == 0)
212 interface_name = atts[i + 1];
213 if (strcmp(atts[i], "summary") == 0)
214 summary = atts[i + 1];
217 ctx->character_data_length = 0;
218 if (strcmp(element_name, "protocol") == 0) {
220 fail(ctx, "no protocol name given");
222 ctx->protocol->name = strdup(name);
223 ctx->protocol->uppercase_name = uppercase_dup(name);
224 ctx->protocol->description = NULL;
225 } else if (strcmp(element_name, "copyright") == 0) {
227 } else if (strcmp(element_name, "interface") == 0) {
229 fail(ctx, "no interface name given");
232 fail(ctx, "no interface version given");
234 interface = malloc(sizeof *interface);
235 interface->name = strdup(name);
236 interface->uppercase_name = uppercase_dup(name);
237 interface->version = version;
238 interface->description = NULL;
239 wl_list_init(&interface->request_list);
240 wl_list_init(&interface->event_list);
241 wl_list_init(&interface->enumeration_list);
242 wl_list_insert(ctx->protocol->interface_list.prev,
244 ctx->interface = interface;
245 } else if (strcmp(element_name, "request") == 0 ||
246 strcmp(element_name, "event") == 0) {
248 fail(ctx, "no request name given");
250 message = malloc(sizeof *message);
251 message->name = strdup(name);
252 message->uppercase_name = uppercase_dup(name);
253 wl_list_init(&message->arg_list);
254 message->arg_count = 0;
255 message->description = NULL;
257 if (strcmp(element_name, "request") == 0)
258 wl_list_insert(ctx->interface->request_list.prev,
261 wl_list_insert(ctx->interface->event_list.prev,
264 if (type != NULL && strcmp(type, "destructor") == 0)
265 message->destructor = 1;
267 message->destructor = 0;
269 if (strcmp(name, "destroy") == 0 && !message->destructor)
270 fail(ctx, "destroy request should be destructor type");
272 ctx->message = message;
273 } else if (strcmp(element_name, "arg") == 0) {
274 arg = malloc(sizeof *arg);
275 arg->name = strdup(name);
277 if (strcmp(type, "int") == 0)
279 else if (strcmp(type, "uint") == 0)
280 arg->type = UNSIGNED;
281 else if (strcmp(type, "string") == 0)
283 else if (strcmp(type, "array") == 0)
285 else if (strcmp(type, "fd") == 0)
287 else if (strcmp(type, "new_id") == 0) {
289 } else if (strcmp(type, "object") == 0) {
292 fail(ctx, "unknown type");
298 if (interface_name == NULL)
299 fail(ctx, "no interface name given");
300 arg->interface_name = strdup(interface_name);
303 if (interface_name != NULL)
304 fail(ctx, "interface not allowed");
310 arg->summary = strdup(summary);
312 wl_list_insert(ctx->message->arg_list.prev, &arg->link);
313 ctx->message->arg_count++;
314 } else if (strcmp(element_name, "enum") == 0) {
316 fail(ctx, "no enum name given");
318 enumeration = malloc(sizeof *enumeration);
319 enumeration->name = strdup(name);
320 enumeration->uppercase_name = uppercase_dup(name);
321 enumeration->description = NULL;
322 wl_list_init(&enumeration->entry_list);
324 wl_list_insert(ctx->interface->enumeration_list.prev,
327 ctx->enumeration = enumeration;
328 } else if (strcmp(element_name, "entry") == 0) {
330 fail(ctx, "no entry name given");
332 entry = malloc(sizeof *entry);
333 entry->name = strdup(name);
334 entry->uppercase_name = uppercase_dup(name);
335 entry->value = strdup(value);
337 entry->summary = strdup(summary);
339 entry->summary = NULL;
340 wl_list_insert(ctx->enumeration->entry_list.prev,
342 } else if (strcmp(element_name, "description") == 0) {
344 fail(ctx, "description without summary");
346 description = malloc(sizeof *description);
348 description->summary = strdup(summary);
350 description->summary = NULL;
353 ctx->message->description = description;
354 else if (ctx->enumeration)
355 ctx->enumeration->description = description;
356 else if (ctx->interface)
357 ctx->interface->description = description;
359 ctx->protocol->description = description;
360 ctx->description = description;
365 end_element(void *data, const XML_Char *name)
367 struct parse_context *ctx = data;
369 if (strcmp(name, "copyright") == 0) {
370 ctx->protocol->copyright =
371 strndup(ctx->character_data,
372 ctx->character_data_length);
373 } else if (strcmp(name, "description") == 0) {
374 char *text = strndup(ctx->character_data,
375 ctx->character_data_length);
377 ctx->description->text = strdup(text);
378 ctx->description = NULL;
379 } else if (strcmp(name, "request") == 0 ||
380 strcmp(name, "event") == 0) {
382 } else if (strcmp(name, "enum") == 0) {
383 ctx->enumeration = NULL;
388 character_data(void *data, const XML_Char *s, int len)
390 struct parse_context *ctx = data;
392 if (ctx->character_data_length + len > sizeof (ctx->character_data)) {
393 fprintf(stderr, "too much character data");
397 memcpy(ctx->character_data + ctx->character_data_length, s, len);
398 ctx->character_data_length += len;
402 emit_opcodes(struct wl_list *message_list, struct interface *interface)
407 if (wl_list_empty(message_list))
411 wl_list_for_each(m, message_list, link)
412 printf("#define %s_%s\t%d\n",
413 interface->uppercase_name, m->uppercase_name, opcode++);
419 emit_type(struct arg *a)
432 printf("const char *");
435 printf("struct %s *", a->interface_name);
438 printf("struct wl_array *");
444 emit_stubs(struct wl_list *message_list, struct interface *interface)
448 int has_destructor, has_destroy;
450 /* We provide a hand written functions for the display object */
451 if (strcmp(interface->name, "wl_display") == 0)
454 printf("static inline void\n"
455 "%s_set_user_data(struct %s *%s, void *user_data)\n"
457 "\twl_proxy_set_user_data((struct wl_proxy *) %s, user_data);\n"
459 interface->name, interface->name, interface->name,
462 printf("static inline void *\n"
463 "%s_get_user_data(struct %s *%s)\n"
465 "\treturn wl_proxy_get_user_data((struct wl_proxy *) %s);\n"
467 interface->name, interface->name, interface->name,
472 wl_list_for_each(m, message_list, link) {
475 if (strcmp(m->name, "destroy)") == 0)
479 if (!has_destructor && has_destroy) {
481 "interface %s has method named destroy but"
482 "no destructor", interface->name);
487 printf("static inline void\n"
488 "%s_destroy(struct %s *%s)\n"
490 "\twl_proxy_destroy("
491 "(struct wl_proxy *) %s);\n"
493 interface->name, interface->name, interface->name,
496 if (wl_list_empty(message_list))
499 wl_list_for_each(m, message_list, link) {
501 wl_list_for_each(a, &m->arg_list, link) {
502 if (a->type == NEW_ID)
507 printf("static inline struct %s *\n",
508 ret->interface_name);
510 printf("static inline void\n");
512 printf("%s_%s(struct %s *%s",
513 interface->name, m->name,
514 interface->name, interface->name);
516 wl_list_for_each(a, &m->arg_list, link) {
517 if (a->type == NEW_ID)
521 printf("%s", a->name);
527 printf("\tstruct wl_proxy *%s;\n\n"
528 "\t%s = wl_proxy_create("
529 "(struct wl_proxy *) %s,\n"
530 "\t\t\t &%s_interface);\n"
532 "\t\treturn NULL;\n\n",
535 interface->name, ret->interface_name,
538 printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
541 interface->uppercase_name,
544 wl_list_for_each(a, &m->arg_list, link) {
546 printf("%s", a->name);
551 printf("\n\twl_proxy_destroy("
552 "(struct wl_proxy *) %s);\n",
556 printf("\n\treturn (struct %s *) %s;\n",
557 ret->interface_name, ret->name);
563 static const char *indent(int n)
565 const char *whitespace[] = {
566 "\t\t\t\t\t\t\t\t\t\t\t\t",
567 "\t\t\t\t\t\t\t\t\t\t\t\t ",
568 "\t\t\t\t\t\t\t\t\t\t\t\t ",
569 "\t\t\t\t\t\t\t\t\t\t\t\t ",
570 "\t\t\t\t\t\t\t\t\t\t\t\t ",
571 "\t\t\t\t\t\t\t\t\t\t\t\t ",
572 "\t\t\t\t\t\t\t\t\t\t\t\t ",
573 "\t\t\t\t\t\t\t\t\t\t\t\t "
576 return whitespace[n % 8] + 12 - n / 8;
580 emit_enumerations(struct interface *interface)
582 struct enumeration *e;
585 wl_list_for_each(e, &interface->enumeration_list, link) {
586 struct description *desc = e->description;
588 printf("#ifndef %s_%s_ENUM\n",
589 interface->uppercase_name, e->uppercase_name);
590 printf("#define %s_%s_ENUM\n",
591 interface->uppercase_name, e->uppercase_name);
595 " * %s_%s - %s\n", interface->name,
596 e->name, desc->summary);
597 wl_list_for_each(entry, &e->entry_list, link) {
598 printf(" * @%s_%s_%s: %s\n",
599 interface->uppercase_name,
601 entry->uppercase_name,
607 desc_dump(desc->text, 0);
611 printf("enum %s_%s {\n", interface->name, e->name);
612 wl_list_for_each(entry, &e->entry_list, link)
613 printf("\t%s_%s_%s = %s,\n",
614 interface->uppercase_name,
616 entry->uppercase_name, entry->value);
618 printf("#endif /* %s_%s_ENUM */\n\n",
619 interface->uppercase_name, e->uppercase_name);
624 emit_structs(struct wl_list *message_list, struct interface *interface)
630 if (wl_list_empty(message_list))
633 is_interface = message_list == &interface->request_list;
634 if (interface->description) {
635 struct description *desc = interface->description;
637 " * %s - %s\n", interface->name, desc->summary);
638 wl_list_for_each(m, message_list, link) {
639 struct description *mdesc = m->description;
640 printf(" * @%s: %s\n", m->name, mdesc ? mdesc->summary :
645 desc_dump(desc->text, 0);
648 printf("struct %s_%s {\n", interface->name,
649 is_interface ? "interface" : "listener");
651 wl_list_for_each(m, message_list, link) {
652 struct description *mdesc = m->description;
655 printf("\t * %s - %s\n", m->name, mdesc ? mdesc->summary :
657 wl_list_for_each(a, &m->arg_list, link) {
658 printf("\t * @%s: %s\n", a->name, a->summary ?
659 a->summary : "(none)");
663 desc_dump(mdesc->text, 8);
667 printf("\tvoid (*%s)(", m->name);
669 n = strlen(m->name) + 17;
671 printf("struct wl_client *client,\n"
672 "%sstruct wl_resource *resource",
675 printf("void *data,\n"),
676 printf("%sstruct %s *%s",
677 indent(n), interface->name, interface->name);
680 wl_list_for_each(a, &m->arg_list, link) {
681 printf(",\n%s", indent(n));
683 if (is_interface && a->type == OBJECT)
684 printf("struct wl_resource *");
688 printf("%s", a->name);
697 printf("static inline int\n"
698 "%s_add_listener(struct %s *%s,\n"
699 "%sconst struct %s_listener *listener, void *data)\n"
701 "\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n"
702 "%s(void (**)(void)) listener, data);\n"
704 interface->name, interface->name, interface->name,
705 indent(14 + strlen(interface->name)),
713 format_copyright(const char *copyright)
715 int bol = 1, start = 0, i;
717 for (i = 0; copyright[i]; i++) {
718 if (bol && (copyright[i] == ' ' || copyright[i] == '\t')) {
725 if (copyright[i] == '\n' || copyright[i] == '\0') {
727 i == 0 ? "/*" : " *",
728 i - start, copyright + start);
736 emit_header(struct protocol *protocol, int server)
739 const char *s = server ? "SERVER" : "CLIENT";
741 if (protocol->copyright)
742 format_copyright(protocol->copyright);
744 printf("#ifndef %s_%s_PROTOCOL_H\n"
745 "#define %s_%s_PROTOCOL_H\n"
747 "#ifdef __cplusplus\n"
751 "#include <stdint.h>\n"
752 "#include <stddef.h>\n"
753 "#include \"wayland-util.h\"\n\n"
754 "struct wl_client;\n"
755 "struct wl_resource;\n\n",
756 protocol->uppercase_name, s,
757 protocol->uppercase_name, s);
759 wl_list_for_each(i, &protocol->interface_list, link)
760 printf("struct %s;\n", i->name);
763 wl_list_for_each(i, &protocol->interface_list, link) {
764 printf("extern const struct wl_interface "
770 wl_list_for_each(i, &protocol->interface_list, link) {
772 emit_enumerations(i);
775 emit_structs(&i->request_list, i);
776 emit_opcodes(&i->event_list, i);
778 emit_structs(&i->event_list, i);
779 emit_opcodes(&i->request_list, i);
780 emit_stubs(&i->request_list, i);
784 printf("#ifdef __cplusplus\n"
792 emit_types_forward_declarations(struct protocol *protocol,
793 struct wl_list *message_list)
799 wl_list_for_each(m, message_list, link) {
802 wl_list_for_each(a, &m->arg_list, link) {
808 printf("extern const struct wl_interface %s_interface;\n",
816 if (m->all_null && length > protocol->null_run_length)
817 protocol->null_run_length = length;
822 emit_null_run(struct protocol *protocol)
826 for (i = 0; i < protocol->null_run_length; i++)
831 emit_types(struct protocol *protocol, struct wl_list *message_list)
836 wl_list_for_each(m, message_list, link) {
843 protocol->null_run_length + protocol->type_index;
844 protocol->type_index += m->arg_count;
846 wl_list_for_each(a, &m->arg_list, link) {
850 if (strcmp(a->interface_name,
852 printf("\t&%s_interface,\n",
866 emit_messages(struct wl_list *message_list,
867 struct interface *interface, const char *suffix)
872 if (wl_list_empty(message_list))
875 printf("static const struct wl_message "
877 interface->name, suffix);
879 wl_list_for_each(m, message_list, link) {
880 printf("\t{ \"%s\", \"", m->name);
881 wl_list_for_each(a, &m->arg_list, link) {
907 printf("\", types + %d },\n", m->type_index);
914 emit_code(struct protocol *protocol)
918 if (protocol->copyright)
919 format_copyright(protocol->copyright);
921 printf("#include <stdlib.h>\n"
922 "#include <stdint.h>\n"
923 "#include \"wayland-util.h\"\n\n");
925 wl_list_for_each(i, &protocol->interface_list, link) {
926 emit_types_forward_declarations(protocol, &i->request_list);
927 emit_types_forward_declarations(protocol, &i->event_list);
931 printf("static const struct wl_interface *types[] = {\n");
932 emit_null_run(protocol);
933 wl_list_for_each(i, &protocol->interface_list, link) {
934 emit_types(protocol, &i->request_list);
935 emit_types(protocol, &i->event_list);
939 wl_list_for_each(i, &protocol->interface_list, link) {
941 emit_messages(&i->request_list, i, "requests");
942 emit_messages(&i->event_list, i, "events");
944 printf("WL_EXPORT const struct wl_interface "
947 i->name, i->name, i->version);
949 if (!wl_list_empty(&i->request_list))
950 printf("\tARRAY_LENGTH(%s_requests), %s_requests,\n",
953 printf("\t0, NULL,\n");
955 if (!wl_list_empty(&i->event_list))
956 printf("\tARRAY_LENGTH(%s_events), %s_events,\n",
959 printf("\t0, NULL,\n");
965 int main(int argc, char *argv[])
967 struct parse_context ctx;
968 struct protocol protocol;
975 wl_list_init(&protocol.interface_list);
976 protocol.type_index = 0;
977 protocol.null_run_length = 0;
978 protocol.copyright = NULL;
979 ctx.protocol = &protocol;
981 ctx.filename = "<stdin>";
982 ctx.parser = XML_ParserCreate(NULL);
983 XML_SetUserData(ctx.parser, &ctx);
984 if (ctx.parser == NULL) {
985 fprintf(stderr, "failed to create parser\n");
989 XML_SetElementHandler(ctx.parser, start_element, end_element);
990 XML_SetCharacterDataHandler(ctx.parser, character_data);
993 buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
994 len = fread(buf, 1, XML_BUFFER_SIZE, stdin);
996 fprintf(stderr, "fread: %s\n", strerror(errno));
999 XML_ParseBuffer(ctx.parser, len, len == 0);
1003 XML_ParserFree(ctx.parser);
1005 if (strcmp(argv[1], "client-header") == 0) {
1006 emit_header(&protocol, 0);
1007 } else if (strcmp(argv[1], "server-header") == 0) {
1008 emit_header(&protocol, 1);
1009 } else if (strcmp(argv[1], "code") == 0) {
1010 emit_code(&protocol);