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
44 struct wl_list interface_list;
54 struct wl_list request_list;
55 struct wl_list event_list;
56 struct wl_list enumeration_list;
63 struct wl_list arg_list;
91 struct wl_list entry_list;
102 struct parse_context {
103 const char *filename;
105 struct protocol *protocol;
106 struct interface *interface;
107 struct message *message;
108 struct enumeration *enumeration;
109 char character_data[8192];
110 int character_data_length;
114 uppercase_dup(const char *src)
120 for (i = 0; u[i]; i++)
121 u[i] = toupper(u[i]);
128 fail(struct parse_context *ctx, const char *msg)
130 fprintf(stderr, "%s:%ld: %s\n",
131 ctx->filename, XML_GetCurrentLineNumber(ctx->parser), msg);
136 start_element(void *data, const char *element_name, const char **atts)
138 struct parse_context *ctx = data;
139 struct interface *interface;
140 struct message *message;
142 struct enumeration *enumeration;
144 const char *name, *type, *interface_name, *value;
150 interface_name = NULL;
152 for (i = 0; atts[i]; i += 2) {
153 if (strcmp(atts[i], "name") == 0)
155 if (strcmp(atts[i], "version") == 0)
156 version = atoi(atts[i + 1]);
157 if (strcmp(atts[i], "type") == 0)
159 if (strcmp(atts[i], "value") == 0)
161 if (strcmp(atts[i], "interface") == 0)
162 interface_name = atts[i + 1];
165 ctx->character_data_length = 0;
166 if (strcmp(element_name, "protocol") == 0) {
168 fail(ctx, "no protocol name given");
170 ctx->protocol->name = strdup(name);
171 ctx->protocol->uppercase_name = uppercase_dup(name);
172 } else if (strcmp(element_name, "copyright") == 0) {
174 } else if (strcmp(element_name, "interface") == 0) {
176 fail(ctx, "no interface name given");
179 fail(ctx, "no interface version given");
181 interface = malloc(sizeof *interface);
182 interface->name = strdup(name);
183 interface->uppercase_name = uppercase_dup(name);
184 interface->version = version;
185 wl_list_init(&interface->request_list);
186 wl_list_init(&interface->event_list);
187 wl_list_init(&interface->enumeration_list);
188 wl_list_insert(ctx->protocol->interface_list.prev,
190 ctx->interface = interface;
191 } else if (strcmp(element_name, "request") == 0 ||
192 strcmp(element_name, "event") == 0) {
194 fail(ctx, "no request name given");
196 message = malloc(sizeof *message);
197 message->name = strdup(name);
198 message->uppercase_name = uppercase_dup(name);
199 wl_list_init(&message->arg_list);
200 message->arg_count = 0;
202 if (strcmp(element_name, "request") == 0)
203 wl_list_insert(ctx->interface->request_list.prev,
206 wl_list_insert(ctx->interface->event_list.prev,
209 if (type != NULL && strcmp(type, "destructor") == 0)
210 message->destructor = 1;
212 message->destructor = 0;
214 if (strcmp(name, "destroy") == 0 && !message->destructor)
215 fail(ctx, "destroy request should be destructor type");
217 ctx->message = message;
218 } else if (strcmp(element_name, "arg") == 0) {
219 arg = malloc(sizeof *arg);
220 arg->name = strdup(name);
222 if (strcmp(type, "int") == 0)
224 else if (strcmp(type, "uint") == 0)
225 arg->type = UNSIGNED;
226 else if (strcmp(type, "string") == 0)
228 else if (strcmp(type, "array") == 0)
230 else if (strcmp(type, "fd") == 0)
232 else if (strcmp(type, "new_id") == 0) {
233 if (interface_name == NULL)
234 fail(ctx, "no interface name given");
236 arg->interface_name = strdup(interface_name);
237 } else if (strcmp(type, "object") == 0) {
238 if (interface_name == NULL)
239 fail(ctx, "no interface name given");
241 arg->interface_name = strdup(interface_name);
243 fail(ctx, "unknown type");
246 wl_list_insert(ctx->message->arg_list.prev, &arg->link);
247 ctx->message->arg_count++;
248 } else if (strcmp(element_name, "enum") == 0) {
250 fail(ctx, "no enum name given");
252 enumeration = malloc(sizeof *enumeration);
253 enumeration->name = strdup(name);
254 enumeration->uppercase_name = uppercase_dup(name);
255 wl_list_init(&enumeration->entry_list);
257 wl_list_insert(ctx->interface->enumeration_list.prev,
260 ctx->enumeration = enumeration;
261 } else if (strcmp(element_name, "entry") == 0) {
262 entry = malloc(sizeof *entry);
263 entry->name = strdup(name);
264 entry->uppercase_name = uppercase_dup(name);
265 entry->value = strdup(value);
266 wl_list_insert(ctx->enumeration->entry_list.prev,
272 end_element(void *data, const XML_Char *name)
274 struct parse_context *ctx = data;
276 if (strcmp(name, "copyright") == 0) {
277 ctx->protocol->copyright =
278 strndup(ctx->character_data,
279 ctx->character_data_length);
284 character_data(void *data, const XML_Char *s, int len)
286 struct parse_context *ctx = data;
288 if (ctx->character_data_length + len > sizeof (ctx->character_data)) {
289 fprintf(stderr, "too much character data");
293 memcpy(ctx->character_data + ctx->character_data_length, s, len);
294 ctx->character_data_length += len;
298 emit_opcodes(struct wl_list *message_list, struct interface *interface)
303 if (wl_list_empty(message_list))
307 wl_list_for_each(m, message_list, link)
308 printf("#define %s_%s\t%d\n",
309 interface->uppercase_name, m->uppercase_name, opcode++);
315 emit_type(struct arg *a)
328 printf("const char *");
331 printf("struct %s *", a->interface_name);
334 printf("struct wl_array *");
340 emit_stubs(struct wl_list *message_list, struct interface *interface)
344 int has_destructor, has_destroy;
346 /* We provide a hand written constructor for the display object */
347 if (strcmp(interface->name, "wl_display") != 0)
348 printf("static inline struct %s *\n"
349 "%s_create(struct wl_display *display, uint32_t id, uint32_t version)\n"
351 "\twl_display_bind(display, id, \"%s\", version);\n\n"
352 "\treturn (struct %s *)\n"
353 "\t\twl_proxy_create_for_id(display, &%s_interface, id);\n"
361 printf("static inline void\n"
362 "%s_set_user_data(struct %s *%s, void *user_data)\n"
364 "\twl_proxy_set_user_data((struct wl_proxy *) %s, user_data);\n"
366 interface->name, interface->name, interface->name,
369 printf("static inline void *\n"
370 "%s_get_user_data(struct %s *%s)\n"
372 "\treturn wl_proxy_get_user_data((struct wl_proxy *) %s);\n"
374 interface->name, interface->name, interface->name,
379 wl_list_for_each(m, message_list, link) {
382 if (strcmp(m->name, "destroy)") == 0)
386 if (!has_destructor && has_destroy) {
388 "interface %s has method named destroy but"
389 "no destructor", interface->name);
393 /* And we have a hand-written display destructor */
394 if (!has_destructor && strcmp(interface->name, "wl_display") != 0)
395 printf("static inline void\n"
396 "%s_destroy(struct %s *%s)\n"
398 "\twl_proxy_destroy("
399 "(struct wl_proxy *) %s);\n"
401 interface->name, interface->name, interface->name,
404 if (wl_list_empty(message_list))
407 wl_list_for_each(m, message_list, link) {
409 wl_list_for_each(a, &m->arg_list, link) {
410 if (a->type == NEW_ID)
415 printf("static inline struct %s *\n",
416 ret->interface_name);
418 printf("static inline void\n");
420 printf("%s_%s(struct %s *%s",
421 interface->name, m->name,
422 interface->name, interface->name);
424 wl_list_for_each(a, &m->arg_list, link) {
425 if (a->type == NEW_ID)
429 printf("%s", a->name);
435 printf("\tstruct wl_proxy *%s;\n\n"
436 "\t%s = wl_proxy_create("
437 "(struct wl_proxy *) %s,\n"
438 "\t\t\t &%s_interface);\n"
440 "\t\treturn NULL;\n\n",
443 interface->name, ret->interface_name,
446 printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
449 interface->uppercase_name,
452 wl_list_for_each(a, &m->arg_list, link) {
454 printf("%s", a->name);
459 printf("\n\twl_proxy_destroy("
460 "(struct wl_proxy *) %s);\n",
464 printf("\n\treturn (struct %s *) %s;\n",
465 ret->interface_name, ret->name);
471 static const char *indent(int n)
473 const char *whitespace[] = {
474 "\t\t\t\t\t\t\t\t\t\t\t\t",
475 "\t\t\t\t\t\t\t\t\t\t\t\t ",
476 "\t\t\t\t\t\t\t\t\t\t\t\t ",
477 "\t\t\t\t\t\t\t\t\t\t\t\t ",
478 "\t\t\t\t\t\t\t\t\t\t\t\t ",
479 "\t\t\t\t\t\t\t\t\t\t\t\t ",
480 "\t\t\t\t\t\t\t\t\t\t\t\t ",
481 "\t\t\t\t\t\t\t\t\t\t\t\t "
484 return whitespace[n % 8] + 12 - n / 8;
488 emit_enumerations(struct interface *interface)
490 struct enumeration *e;
493 wl_list_for_each(e, &interface->enumeration_list, link) {
494 printf("#ifndef %s_%s_ENUM\n",
495 interface->uppercase_name, e->uppercase_name);
496 printf("#define %s_%s_ENUM\n",
497 interface->uppercase_name, e->uppercase_name);
498 printf("enum %s_%s {\n", interface->name, e->name);
499 wl_list_for_each(entry, &e->entry_list, link)
500 printf("\t%s_%s_%s = %s,\n",
501 interface->uppercase_name,
503 entry->uppercase_name, entry->value);
505 printf("#endif /* %s_%s_ENUM */\n\n",
506 interface->uppercase_name, e->uppercase_name);
511 emit_structs(struct wl_list *message_list, struct interface *interface)
517 if (wl_list_empty(message_list))
520 is_interface = message_list == &interface->request_list;
521 printf("struct %s_%s {\n", interface->name,
522 is_interface ? "interface" : "listener");
524 wl_list_for_each(m, message_list, link) {
525 printf("\tvoid (*%s)(", m->name);
527 n = strlen(m->name) + 17;
529 printf("struct wl_client *client,\n"
532 interface->name, interface->name);
534 printf("void *data,\n"),
535 printf("%sstruct %s *%s",
536 indent(n), interface->name, interface->name);
539 wl_list_for_each(a, &m->arg_list, link) {
540 printf(",\n%s", indent(n));
543 printf("%s", a->name);
552 printf("static inline int\n"
553 "%s_add_listener(struct %s *%s,\n"
554 "%sconst struct %s_listener *listener, void *data)\n"
556 "\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n"
557 "%s(void (**)(void)) listener, data);\n"
559 interface->name, interface->name, interface->name,
560 indent(17 + strlen(interface->name)),
568 format_copyright(const char *copyright)
570 int bol = 1, start = 0, i;
572 for (i = 0; copyright[i]; i++) {
573 if (bol && (copyright[i] == ' ' || copyright[i] == '\t')) {
580 if (copyright[i] == '\n' || copyright[i] == '\0') {
582 i == 0 ? "/*" : " *",
583 i - start, copyright + start);
591 emit_header(struct protocol *protocol, int server)
594 const char *s = server ? "SERVER" : "CLIENT";
596 if (protocol->copyright)
597 format_copyright(protocol->copyright);
599 printf("#ifndef %s_%s_PROTOCOL_H\n"
600 "#define %s_%s_PROTOCOL_H\n"
602 "#ifdef __cplusplus\n"
606 "#include <stdint.h>\n"
607 "#include <stddef.h>\n"
608 "#include \"wayland-util.h\"\n\n"
609 "struct wl_client;\n\n",
610 protocol->uppercase_name, s,
611 protocol->uppercase_name, s);
613 wl_list_for_each(i, &protocol->interface_list, link)
614 printf("struct %s;\n", i->name);
617 wl_list_for_each(i, &protocol->interface_list, link) {
618 printf("extern const struct wl_interface "
624 wl_list_for_each(i, &protocol->interface_list, link) {
626 emit_enumerations(i);
629 emit_structs(&i->request_list, i);
630 emit_opcodes(&i->event_list, i);
632 emit_structs(&i->event_list, i);
633 emit_opcodes(&i->request_list, i);
634 emit_stubs(&i->request_list, i);
638 printf("#ifdef __cplusplus\n"
646 emit_types_forward_declarations(struct protocol *protocol,
647 struct wl_list *message_list)
653 wl_list_for_each(m, message_list, link) {
656 wl_list_for_each(a, &m->arg_list, link) {
662 printf("extern const struct wl_interface %s_interface;\n",
670 if (m->all_null && length > protocol->null_run_length)
671 protocol->null_run_length = length;
676 emit_null_run(struct protocol *protocol)
680 for (i = 0; i < protocol->null_run_length; i++)
685 emit_types(struct protocol *protocol, struct wl_list *message_list)
690 wl_list_for_each(m, message_list, link) {
697 protocol->null_run_length + protocol->type_index;
698 protocol->type_index += m->arg_count;
700 wl_list_for_each(a, &m->arg_list, link) {
704 if (strcmp(a->interface_name,
706 printf("\t&%s_interface,\n",
720 emit_messages(struct wl_list *message_list,
721 struct interface *interface, const char *suffix)
726 if (wl_list_empty(message_list))
729 printf("static const struct wl_message "
731 interface->name, suffix);
733 wl_list_for_each(m, message_list, link) {
734 printf("\t{ \"%s\", \"", m->name);
735 wl_list_for_each(a, &m->arg_list, link) {
761 printf("\", types + %d },\n", m->type_index);
768 emit_code(struct protocol *protocol)
772 if (protocol->copyright)
773 format_copyright(protocol->copyright);
775 printf("#include <stdlib.h>\n"
776 "#include <stdint.h>\n"
777 "#include \"wayland-util.h\"\n\n");
779 wl_list_for_each(i, &protocol->interface_list, link) {
780 emit_types_forward_declarations(protocol, &i->request_list);
781 emit_types_forward_declarations(protocol, &i->event_list);
785 printf("static const struct wl_interface *types[] = {\n");
786 emit_null_run(protocol);
787 wl_list_for_each(i, &protocol->interface_list, link) {
788 emit_types(protocol, &i->request_list);
789 emit_types(protocol, &i->event_list);
793 wl_list_for_each(i, &protocol->interface_list, link) {
795 emit_messages(&i->request_list, i, "requests");
796 emit_messages(&i->event_list, i, "events");
798 printf("WL_EXPORT const struct wl_interface "
801 i->name, i->name, i->version);
803 if (!wl_list_empty(&i->request_list))
804 printf("\tARRAY_LENGTH(%s_requests), %s_requests,\n",
807 printf("\t0, NULL,\n");
809 if (!wl_list_empty(&i->event_list))
810 printf("\tARRAY_LENGTH(%s_events), %s_events,\n",
813 printf("\t0, NULL,\n");
819 int main(int argc, char *argv[])
821 struct parse_context ctx;
822 struct protocol protocol;
829 wl_list_init(&protocol.interface_list);
830 protocol.type_index = 0;
831 protocol.null_run_length = 0;
832 protocol.copyright = NULL;
833 ctx.protocol = &protocol;
835 ctx.filename = "<stdin>";
836 ctx.parser = XML_ParserCreate(NULL);
837 XML_SetUserData(ctx.parser, &ctx);
838 if (ctx.parser == NULL) {
839 fprintf(stderr, "failed to create parser\n");
843 XML_SetElementHandler(ctx.parser, start_element, end_element);
844 XML_SetCharacterDataHandler(ctx.parser, character_data);
847 buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
848 len = fread(buf, 1, XML_BUFFER_SIZE, stdin);
850 fprintf(stderr, "fread: %s\n", strerror(errno));
853 XML_ParseBuffer(ctx.parser, len, len == 0);
857 XML_ParserFree(ctx.parser);
859 if (strcmp(argv[1], "client-header") == 0) {
860 emit_header(&protocol, 0);
861 } else if (strcmp(argv[1], "server-header") == 0) {
862 emit_header(&protocol, 1);
863 } else if (strcmp(argv[1], "code") == 0) {
864 emit_code(&protocol);