2 * Copyright © 2010 Intel Corporation
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #include "wayland-util.h"
27 static const char copyright[] =
29 " * Copyright © 2010 Kristian Høgsberg\n"
31 " * Permission to use, copy, modify, distribute, and sell this software and its\n"
32 " * documentation for any purpose is hereby granted without fee, provided that\n"
33 " * the above copyright notice appear in all copies and that both that copyright\n"
34 " * notice and this permission notice appear in supporting documentation, and\n"
35 " * that the name of the copyright holders not be used in advertising or\n"
36 " * publicity pertaining to distribution of the software without specific,\n"
37 " * written prior permission. The copyright holders make no representations\n"
38 " * about the suitability of this software for any purpose. It is provided \"as\n"
39 " * is\" without express or implied warranty.\n"
41 " * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,\n"
42 " * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO\n"
43 " * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR\n"
44 " * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,\n"
45 " * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER\n"
46 " * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE\n"
47 " * OF THIS SOFTWARE.\n"
53 fprintf(stderr, "usage: ./scanner [client-header|server-header|code]\n");
57 #define XML_BUFFER_SIZE 4096
62 struct wl_list interface_list;
69 struct wl_list request_list;
70 struct wl_list event_list;
71 struct wl_list enumeration_list;
78 struct wl_list arg_list;
102 char *uppercase_name;
103 struct wl_list entry_list;
109 char *uppercase_name;
114 struct parse_context {
115 const char *filename;
117 struct protocol *protocol;
118 struct interface *interface;
119 struct message *message;
120 struct enumeration *enumeration;
124 uppercase_dup(const char *src)
130 for (i = 0; u[i]; i++)
131 u[i] = toupper(u[i]);
138 fail(struct parse_context *ctx, const char *msg)
140 fprintf(stderr, "%s:%ld: %s\n",
141 ctx->filename, XML_GetCurrentLineNumber(ctx->parser), msg);
146 start_element(void *data, const char *element_name, const char **atts)
148 struct parse_context *ctx = data;
149 struct interface *interface;
150 struct message *message;
152 struct enumeration *enumeration;
154 const char *name, *type, *interface_name, *value;
160 interface_name = NULL;
162 for (i = 0; atts[i]; i += 2) {
163 if (strcmp(atts[i], "name") == 0)
165 if (strcmp(atts[i], "version") == 0)
166 version = atoi(atts[i + 1]);
167 if (strcmp(atts[i], "type") == 0)
169 if (strcmp(atts[i], "value") == 0)
171 if (strcmp(atts[i], "interface") == 0)
172 interface_name = atts[i + 1];
175 if (strcmp(element_name, "protocol") == 0) {
177 fail(ctx, "no protocol name given");
179 ctx->protocol->name = strdup(name);
180 ctx->protocol->uppercase_name = uppercase_dup(name);
181 } else if (strcmp(element_name, "interface") == 0) {
183 fail(ctx, "no interface name given");
186 fail(ctx, "no interface version given");
188 interface = malloc(sizeof *interface);
189 interface->name = strdup(name);
190 interface->uppercase_name = uppercase_dup(name);
191 interface->version = version;
192 wl_list_init(&interface->request_list);
193 wl_list_init(&interface->event_list);
194 wl_list_init(&interface->enumeration_list);
195 wl_list_insert(ctx->protocol->interface_list.prev,
197 ctx->interface = interface;
198 } else if (strcmp(element_name, "request") == 0 ||
199 strcmp(element_name, "event") == 0) {
201 fail(ctx, "no request name given");
203 message = malloc(sizeof *message);
204 message->name = strdup(name);
205 message->uppercase_name = uppercase_dup(name);
206 wl_list_init(&message->arg_list);
208 if (strcmp(element_name, "request") == 0)
209 wl_list_insert(ctx->interface->request_list.prev,
212 wl_list_insert(ctx->interface->event_list.prev,
215 if (type != NULL && strcmp(type, "destructor") == 0)
216 message->destructor = 1;
218 message->destructor = 0;
220 ctx->message = message;
221 } else if (strcmp(element_name, "arg") == 0) {
222 arg = malloc(sizeof *arg);
223 arg->name = strdup(name);
225 if (strcmp(type, "int") == 0)
227 else if (strcmp(type, "uint") == 0)
228 arg->type = UNSIGNED;
229 else if (strcmp(type, "string") == 0)
231 else if (strcmp(type, "array") == 0)
233 else if (strcmp(type, "fd") == 0)
235 else if (strcmp(type, "new_id") == 0) {
236 if (interface_name == NULL)
237 fail(ctx, "no interface name given");
239 arg->interface_name = strdup(interface_name);
240 } else if (strcmp(type, "object") == 0) {
241 if (interface_name == NULL)
242 fail(ctx, "no interface name given");
244 arg->interface_name = strdup(interface_name);
246 fail(ctx, "unknown type");
249 wl_list_insert(ctx->message->arg_list.prev, &arg->link);
250 } else if (strcmp(element_name, "enum") == 0) {
252 fail(ctx, "no enum name given");
254 enumeration = malloc(sizeof *enumeration);
255 enumeration->name = strdup(name);
256 enumeration->uppercase_name = uppercase_dup(name);
257 wl_list_init(&enumeration->entry_list);
259 wl_list_insert(ctx->interface->enumeration_list.prev,
262 ctx->enumeration = enumeration;
263 } else if (strcmp(element_name, "entry") == 0) {
264 entry = malloc(sizeof *entry);
265 entry->name = strdup(name);
266 entry->uppercase_name = uppercase_dup(name);
267 entry->value = strdup(value);
268 wl_list_insert(ctx->enumeration->entry_list.prev,
274 emit_opcodes(struct wl_list *message_list, struct interface *interface)
279 if (wl_list_empty(message_list))
283 wl_list_for_each(m, message_list, link)
284 printf("#define WL_%s_%s\t%d\n",
285 interface->uppercase_name, m->uppercase_name, opcode++);
291 emit_type(struct arg *a)
304 printf("const char *");
307 printf("struct wl_%s *", a->interface_name);
310 printf("struct wl_array *");
316 emit_stubs(struct wl_list *message_list, struct interface *interface)
320 int has_destructor, has_destroy;
322 /* We provide a hand written constructor for the display object */
323 if (strcmp(interface->name, "display") != 0)
324 printf("static inline struct wl_%s *\n"
325 "wl_%s_create(struct wl_display *display, uint32_t id, uint32_t version)\n"
327 "\twl_display_bind(display, id, \"%s\", version);\n\n"
328 "\treturn (struct wl_%s *)\n"
329 "\t\twl_proxy_create_for_id(display, &wl_%s_interface, id);\n"
337 printf("static inline void\n"
338 "wl_%s_set_user_data(struct wl_%s *%s, void *user_data)\n"
340 "\twl_proxy_set_user_data((struct wl_proxy *) %s, user_data);\n"
342 interface->name, interface->name, interface->name,
345 printf("static inline void *\n"
346 "wl_%s_get_user_data(struct wl_%s *%s)\n"
348 "\treturn wl_proxy_get_user_data((struct wl_proxy *) %s);\n"
350 interface->name, interface->name, interface->name,
355 wl_list_for_each(m, message_list, link) {
358 if (strcmp(m->name, "destroy)") == 0)
362 if (!has_destructor && has_destroy) {
364 "interface %s has method named destroy but"
365 "no destructor", interface->name);
369 /* And we have a hand-written display destructor */
370 if (!has_destructor && strcmp(interface->name, "display") != 0)
371 printf("static inline void\n"
372 "wl_%s_destroy(struct wl_%s *%s)\n"
374 "\twl_proxy_destroy("
375 "(struct wl_proxy *) %s);\n"
377 interface->name, interface->name, interface->name,
380 if (wl_list_empty(message_list))
383 wl_list_for_each(m, message_list, link) {
385 wl_list_for_each(a, &m->arg_list, link) {
386 if (a->type == NEW_ID)
391 printf("static inline struct wl_%s *\n",
392 ret->interface_name);
394 printf("static inline void\n");
396 printf("wl_%s_%s(struct wl_%s *%s",
397 interface->name, m->name,
398 interface->name, interface->name);
400 wl_list_for_each(a, &m->arg_list, link) {
401 if (a->type == NEW_ID)
405 printf("%s", a->name);
411 printf("\tstruct wl_proxy *%s;\n\n"
412 "\t%s = wl_proxy_create("
413 "(struct wl_proxy *) %s,\n"
414 "\t\t\t &wl_%s_interface);\n"
416 "\t\treturn NULL;\n\n",
419 interface->name, ret->interface_name,
422 printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
425 interface->uppercase_name,
428 wl_list_for_each(a, &m->arg_list, link) {
430 printf("%s", a->name);
435 printf("\n\twl_proxy_destroy("
436 "(struct wl_proxy *) %s);\n",
440 printf("\n\treturn (struct wl_%s *) %s;\n",
441 ret->interface_name, ret->name);
447 static const char *indent(int n)
449 const char *whitespace[] = {
450 "\t\t\t\t\t\t\t\t\t\t\t\t",
451 "\t\t\t\t\t\t\t\t\t\t\t\t ",
452 "\t\t\t\t\t\t\t\t\t\t\t\t ",
453 "\t\t\t\t\t\t\t\t\t\t\t\t ",
454 "\t\t\t\t\t\t\t\t\t\t\t\t ",
455 "\t\t\t\t\t\t\t\t\t\t\t\t ",
456 "\t\t\t\t\t\t\t\t\t\t\t\t ",
457 "\t\t\t\t\t\t\t\t\t\t\t\t "
460 return whitespace[n % 8] + 12 - n / 8;
464 emit_enumerations(struct interface *interface)
466 struct enumeration *e;
469 wl_list_for_each(e, &interface->enumeration_list, link) {
470 printf("#ifndef WL_%s_%s_ENUM\n",
471 interface->uppercase_name, e->uppercase_name);
472 printf("#define WL_%s_%s_ENUM\n",
473 interface->uppercase_name, e->uppercase_name);
474 printf("enum wl_%s_%s {\n", interface->name, e->name);
475 wl_list_for_each(entry, &e->entry_list, link)
476 printf("\tWL_%s_%s_%s = %s,\n",
477 interface->uppercase_name,
479 entry->uppercase_name, entry->value);
481 printf("#endif /* WL_%s_%s_ENUM */\n\n",
482 interface->uppercase_name, e->uppercase_name);
487 emit_structs(struct wl_list *message_list, struct interface *interface)
493 if (wl_list_empty(message_list))
496 is_interface = message_list == &interface->request_list;
497 printf("struct wl_%s_%s {\n", interface->name,
498 is_interface ? "interface" : "listener");
500 wl_list_for_each(m, message_list, link) {
501 printf("\tvoid (*%s)(", m->name);
503 n = strlen(m->name) + 17;
505 printf("struct wl_client *client,\n"
506 "%sstruct wl_%s *%s",
508 interface->name, interface->name);
510 printf("void *data,\n"),
511 printf("%sstruct wl_%s *%s",
512 indent(n), interface->name, interface->name);
515 wl_list_for_each(a, &m->arg_list, link) {
516 printf(",\n%s", indent(n));
519 printf("%s", a->name);
528 printf("static inline int\n"
529 "wl_%s_add_listener(struct wl_%s *%s,\n"
530 "%sconst struct wl_%s_listener *listener, void *data)\n"
532 "\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n"
533 "%s(void (**)(void)) listener, data);\n"
535 interface->name, interface->name, interface->name,
536 indent(17 + strlen(interface->name)),
545 emit_header(struct protocol *protocol, int server)
548 const char *s = server ? "SERVER" : "CLIENT";
551 "#ifndef %s_%s_PROTOCOL_H\n"
552 "#define %s_%s_PROTOCOL_H\n"
554 "#ifdef __cplusplus\n"
558 "#include <stdint.h>\n"
559 "#include <stddef.h>\n"
560 "#include \"wayland-util.h\"\n\n"
561 "struct wl_client;\n\n",
563 protocol->uppercase_name, s,
564 protocol->uppercase_name, s);
566 wl_list_for_each(i, &protocol->interface_list, link)
567 printf("struct wl_%s;\n", i->name);
570 wl_list_for_each(i, &protocol->interface_list, link) {
571 printf("extern const struct wl_interface "
572 "wl_%s_interface;\n",
577 wl_list_for_each(i, &protocol->interface_list, link) {
579 emit_enumerations(i);
582 emit_structs(&i->request_list, i);
583 emit_opcodes(&i->event_list, i);
585 emit_structs(&i->event_list, i);
586 emit_opcodes(&i->request_list, i);
587 emit_stubs(&i->request_list, i);
591 printf("#ifdef __cplusplus\n"
599 emit_messages(struct wl_list *message_list,
600 struct interface *interface, const char *suffix)
605 if (wl_list_empty(message_list))
608 printf("static const struct wl_message "
610 interface->name, suffix);
612 wl_list_for_each(m, message_list, link) {
613 printf("\t{ \"%s\", \"", m->name);
614 wl_list_for_each(a, &m->arg_list, link) {
647 emit_code(struct protocol *protocol)
652 "#include <stdlib.h>\n"
653 "#include <stdint.h>\n"
654 "#include \"wayland-util.h\"\n\n",
657 wl_list_for_each(i, &protocol->interface_list, link) {
659 emit_messages(&i->request_list, i, "requests");
660 emit_messages(&i->event_list, i, "events");
662 printf("WL_EXPORT const struct wl_interface "
663 "wl_%s_interface = {\n"
665 i->name, i->name, i->version);
667 if (!wl_list_empty(&i->request_list))
668 printf("\tARRAY_LENGTH(%s_requests), %s_requests,\n",
671 printf("\t0, NULL,\n");
673 if (!wl_list_empty(&i->event_list))
674 printf("\tARRAY_LENGTH(%s_events), %s_events,\n",
677 printf("\t0, NULL,\n");
683 int main(int argc, char *argv[])
685 struct parse_context ctx;
686 struct protocol protocol;
693 wl_list_init(&protocol.interface_list);
694 ctx.protocol = &protocol;
696 ctx.filename = "<stdin>";
697 ctx.parser = XML_ParserCreate(NULL);
698 XML_SetUserData(ctx.parser, &ctx);
699 if (ctx.parser == NULL) {
700 fprintf(stderr, "failed to create parser\n");
704 XML_SetElementHandler(ctx.parser, start_element, NULL);
706 buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
707 len = fread(buf, 1, XML_BUFFER_SIZE, stdin);
709 fprintf(stderr, "fread: %s\n", strerror(errno));
712 XML_ParseBuffer(ctx.parser, len, len == 0);
716 XML_ParserFree(ctx.parser);
718 if (strcmp(argv[1], "client-header") == 0) {
719 emit_header(&protocol, 0);
720 } else if (strcmp(argv[1], "server-header") == 0) {
721 emit_header(&protocol, 1);
722 } else if (strcmp(argv[1], "code") == 0) {
723 emit_code(&protocol);