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 struct protocol *protocol;
116 struct interface *interface;
117 struct message *message;
118 struct enumeration *enumeration;
122 uppercase_dup(const char *src)
128 for (i = 0; u[i]; i++)
129 u[i] = toupper(u[i]);
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 if (strcmp(element_name, "protocol") == 0) {
167 fprintf(stderr, "no protocol name given\n");
171 ctx->protocol->name = strdup(name);
172 ctx->protocol->uppercase_name = uppercase_dup(name);
173 } else if (strcmp(element_name, "interface") == 0) {
175 fprintf(stderr, "no interface name given\n");
180 fprintf(stderr, "no interface version given\n");
184 interface = malloc(sizeof *interface);
185 interface->name = strdup(name);
186 interface->uppercase_name = uppercase_dup(name);
187 interface->version = version;
188 wl_list_init(&interface->request_list);
189 wl_list_init(&interface->event_list);
190 wl_list_init(&interface->enumeration_list);
191 wl_list_insert(ctx->protocol->interface_list.prev,
193 ctx->interface = interface;
194 } else if (strcmp(element_name, "request") == 0 ||
195 strcmp(element_name, "event") == 0) {
197 fprintf(stderr, "no request name given\n");
201 message = malloc(sizeof *message);
202 message->name = strdup(name);
203 message->uppercase_name = uppercase_dup(name);
204 wl_list_init(&message->arg_list);
206 if (strcmp(element_name, "request") == 0)
207 wl_list_insert(ctx->interface->request_list.prev,
210 wl_list_insert(ctx->interface->event_list.prev,
213 if (type != NULL && strcmp(type, "destructor") == 0)
214 message->destructor = 1;
216 message->destructor = 0;
218 ctx->message = message;
219 } else if (strcmp(element_name, "arg") == 0) {
220 arg = malloc(sizeof *arg);
221 arg->name = strdup(name);
223 if (strcmp(type, "int") == 0)
225 else if (strcmp(type, "uint") == 0)
226 arg->type = UNSIGNED;
227 else if (strcmp(type, "string") == 0)
229 else if (strcmp(type, "array") == 0)
231 else if (strcmp(type, "fd") == 0)
233 else if (strcmp(type, "new_id") == 0) {
234 if (interface_name == NULL) {
235 fprintf(stderr, "no interface name given\n");
239 arg->interface_name = strdup(interface_name);
240 } else if (strcmp(type, "object") == 0) {
241 if (interface_name == NULL) {
242 fprintf(stderr, "no interface name given\n");
246 arg->interface_name = strdup(interface_name);
248 fprintf(stderr, "unknown type: %s\n", type);
252 wl_list_insert(ctx->message->arg_list.prev, &arg->link);
253 } else if (strcmp(element_name, "enum") == 0) {
255 fprintf(stderr, "no enum name given\n");
259 enumeration = malloc(sizeof *enumeration);
260 enumeration->name = strdup(name);
261 enumeration->uppercase_name = uppercase_dup(name);
262 wl_list_init(&enumeration->entry_list);
264 wl_list_insert(ctx->interface->enumeration_list.prev,
267 ctx->enumeration = enumeration;
268 } else if (strcmp(element_name, "entry") == 0) {
269 entry = malloc(sizeof *entry);
270 entry->name = strdup(name);
271 entry->uppercase_name = uppercase_dup(name);
272 entry->value = strdup(value);
273 wl_list_insert(ctx->enumeration->entry_list.prev,
279 emit_opcodes(struct wl_list *message_list, struct interface *interface)
284 if (wl_list_empty(message_list))
288 wl_list_for_each(m, message_list, link)
289 printf("#define WL_%s_%s\t%d\n",
290 interface->uppercase_name, m->uppercase_name, opcode++);
296 emit_type(struct arg *a)
309 printf("const char *");
312 printf("struct wl_%s *", a->interface_name);
315 printf("struct wl_array *");
321 emit_stubs(struct wl_list *message_list, struct interface *interface)
325 int has_destructor, has_destroy;
327 /* We provide a hand written constructor for the display object */
328 if (strcmp(interface->name, "display") != 0)
329 printf("static inline struct wl_%s *\n"
330 "wl_%s_create(struct wl_display *display, uint32_t id)\n"
332 "\treturn (struct wl_%s *)\n"
333 "\t\twl_proxy_create_for_id(display, &wl_%s_interface, id);\n"
340 printf("static inline void\n"
341 "wl_%s_set_user_data(struct wl_%s *%s, void *user_data)\n"
343 "\twl_proxy_set_user_data((struct wl_proxy *) %s, user_data);\n"
345 interface->name, interface->name, interface->name,
348 printf("static inline void *\n"
349 "wl_%s_get_user_data(struct wl_%s *%s)\n"
351 "\treturn wl_proxy_get_user_data((struct wl_proxy *) %s);\n"
353 interface->name, interface->name, interface->name,
358 wl_list_for_each(m, message_list, link) {
361 if (strcmp(m->name, "destroy)") == 0)
365 if (!has_destructor && has_destroy) {
367 "interface %s has method named destroy but"
368 "no destructor", interface->name);
372 /* And we have a hand-written display destructor */
373 if (!has_destructor && strcmp(interface->name, "display") != 0)
374 printf("static inline void\n"
375 "wl_%s_destroy(struct wl_%s *%s)\n"
377 "\twl_proxy_destroy("
378 "(struct wl_proxy *) %s);\n"
380 interface->name, interface->name, interface->name,
383 if (wl_list_empty(message_list))
386 wl_list_for_each(m, message_list, link) {
388 wl_list_for_each(a, &m->arg_list, link) {
389 if (a->type == NEW_ID)
394 printf("static inline struct wl_%s *\n",
395 ret->interface_name);
397 printf("static inline void\n");
399 printf("wl_%s_%s(struct wl_%s *%s",
400 interface->name, m->name,
401 interface->name, interface->name);
403 wl_list_for_each(a, &m->arg_list, link) {
404 if (a->type == NEW_ID)
408 printf("%s", a->name);
414 printf("\tstruct wl_proxy *%s;\n\n"
415 "\t%s = wl_proxy_create("
416 "(struct wl_proxy *) %s,\n"
417 "\t\t\t &wl_%s_interface);\n"
419 "\t\treturn NULL;\n\n",
422 interface->name, ret->interface_name,
425 printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
428 interface->uppercase_name,
431 wl_list_for_each(a, &m->arg_list, link) {
433 printf("%s", a->name);
438 printf("\n\twl_proxy_destroy("
439 "(struct wl_proxy *) %s);\n",
443 printf("\n\treturn (struct wl_%s *) %s;\n",
444 ret->interface_name, ret->name);
450 static const char *indent(int n)
452 const char *whitespace[] = {
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 ",
458 "\t\t\t\t\t\t\t\t\t\t\t\t ",
459 "\t\t\t\t\t\t\t\t\t\t\t\t ",
460 "\t\t\t\t\t\t\t\t\t\t\t\t "
463 return whitespace[n % 8] + 12 - n / 8;
467 emit_enumerations(struct interface *interface)
469 struct enumeration *e;
472 wl_list_for_each(e, &interface->enumeration_list, link) {
473 printf("#ifndef WL_%s_%s_ENUM\n",
474 interface->uppercase_name, e->uppercase_name);
475 printf("#define WL_%s_%s_ENUM\n",
476 interface->uppercase_name, e->uppercase_name);
477 printf("enum wl_%s_%s {\n", interface->name, e->name);
478 wl_list_for_each(entry, &e->entry_list, link)
479 printf("\tWL_%s_%s_%s = %s,\n",
480 interface->uppercase_name,
482 entry->uppercase_name, entry->value);
484 printf("#endif /* WL_%s_%s_ENUM */\n\n",
485 interface->uppercase_name, e->uppercase_name);
490 emit_structs(struct wl_list *message_list, struct interface *interface)
496 if (wl_list_empty(message_list))
499 is_interface = message_list == &interface->request_list;
500 printf("struct wl_%s_%s {\n", interface->name,
501 is_interface ? "interface" : "listener");
503 wl_list_for_each(m, message_list, link) {
504 printf("\tvoid (*%s)(", m->name);
506 n = strlen(m->name) + 17;
508 printf("struct wl_client *client,\n"
509 "%sstruct wl_%s *%s",
511 interface->name, interface->name);
513 printf("void *data,\n"),
514 printf("%sstruct wl_%s *%s",
515 indent(n), interface->name, interface->name);
518 wl_list_for_each(a, &m->arg_list, link) {
519 printf(",\n%s", indent(n));
522 printf("%s", a->name);
531 printf("static inline int\n"
532 "wl_%s_add_listener(struct wl_%s *%s,\n"
533 "%sconst struct wl_%s_listener *listener, void *data)\n"
535 "\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n"
536 "%s(void (**)(void)) listener, data);\n"
538 interface->name, interface->name, interface->name,
539 indent(17 + strlen(interface->name)),
546 static const char client_prototypes[] =
547 "struct wl_proxy;\n\n"
550 "wl_proxy_marshal(struct wl_proxy *p, uint32_t opcode, ...);\n"
552 "extern struct wl_proxy *\n"
553 "wl_proxy_create(struct wl_proxy *factory,\n"
554 "\t\tconst struct wl_interface *interface);\n"
556 "extern struct wl_proxy *\n"
557 "wl_proxy_create_for_id(struct wl_display *display,\n"
558 "\t\t const struct wl_interface *interface, uint32_t id);\n"
561 "wl_proxy_destroy(struct wl_proxy *proxy);\n\n"
564 "wl_proxy_add_listener(struct wl_proxy *proxy,\n"
565 "\t\t void (**implementation)(void), void *data);\n\n"
568 "wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data);\n\n"
571 "wl_proxy_get_user_data(struct wl_proxy *proxy);\n\n";
575 emit_header(struct protocol *protocol, int server)
578 const char *s = server ? "SERVER" : "CLIENT";
581 "#ifndef %s_%s_PROTOCOL_H\n"
582 "#define %s_%s_PROTOCOL_H\n"
584 "#ifdef __cplusplus\n"
588 "#include <stdint.h>\n"
589 "#include <stddef.h>\n"
590 "#include \"wayland-util.h\"\n\n"
591 "struct wl_client;\n\n",
593 protocol->uppercase_name, s,
594 protocol->uppercase_name, s);
596 wl_list_for_each(i, &protocol->interface_list, link)
597 printf("struct wl_%s;\n", i->name);
601 printf(client_prototypes);
603 wl_list_for_each(i, &protocol->interface_list, link) {
604 printf("extern const struct wl_interface "
605 "wl_%s_interface;\n",
610 wl_list_for_each(i, &protocol->interface_list, link) {
612 emit_enumerations(i);
615 emit_structs(&i->request_list, i);
616 emit_opcodes(&i->event_list, i);
618 emit_structs(&i->event_list, i);
619 emit_opcodes(&i->request_list, i);
620 emit_stubs(&i->request_list, i);
624 printf("#ifdef __cplusplus\n"
632 emit_messages(struct wl_list *message_list,
633 struct interface *interface, const char *suffix)
638 if (wl_list_empty(message_list))
641 printf("static const struct wl_message "
643 interface->name, suffix);
645 wl_list_for_each(m, message_list, link) {
646 printf("\t{ \"%s\", \"", m->name);
647 wl_list_for_each(a, &m->arg_list, link) {
680 emit_code(struct protocol *protocol)
685 "#include <stdlib.h>\n"
686 "#include <stdint.h>\n"
687 "#include \"wayland-util.h\"\n\n",
690 wl_list_for_each(i, &protocol->interface_list, link) {
692 emit_messages(&i->request_list, i, "requests");
693 emit_messages(&i->event_list, i, "events");
695 printf("WL_EXPORT const struct wl_interface "
696 "wl_%s_interface = {\n"
698 i->name, i->name, i->version);
700 if (!wl_list_empty(&i->request_list))
701 printf("\tARRAY_LENGTH(%s_requests), %s_requests,\n",
704 printf("\t0, NULL,\n");
706 if (!wl_list_empty(&i->event_list))
707 printf("\tARRAY_LENGTH(%s_events), %s_events,\n",
710 printf("\t0, NULL,\n");
716 int main(int argc, char *argv[])
718 struct parse_context ctx;
719 struct protocol protocol;
727 wl_list_init(&protocol.interface_list);
728 ctx.protocol = &protocol;
730 parser = XML_ParserCreate(NULL);
731 XML_SetUserData(parser, &ctx);
732 if (parser == NULL) {
733 fprintf(stderr, "failed to create parser\n");
737 XML_SetElementHandler(parser, start_element, NULL);
739 buf = XML_GetBuffer(parser, XML_BUFFER_SIZE);
740 len = fread(buf, 1, XML_BUFFER_SIZE, stdin);
742 fprintf(stderr, "fread: %s\n", strerror(errno));
745 XML_ParseBuffer(parser, len, len == 0);
749 XML_ParserFree(parser);
751 if (strcmp(argv[1], "client-header") == 0) {
752 emit_header(&protocol, 0);
753 } else if (strcmp(argv[1], "server-header") == 0) {
754 emit_header(&protocol, 1);
755 } else if (strcmp(argv[1], "code") == 0) {
756 emit_code(&protocol);