Introduce display.bind to request events from a global
[profile/ivi/wayland.git] / wayland / scanner.c
1 /*
2  * Copyright © 2010 Intel Corporation
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 #include <stdio.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <ctype.h>
23 #include <expat.h>
24
25 #include "wayland-util.h"
26
27 static const char copyright[] =
28         "/*\n"
29         " * Copyright © 2010 Kristian Høgsberg\n"
30         " *\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"
40         " *\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"
48         " */\n";
49
50 static int
51 usage(int ret)
52 {
53         fprintf(stderr, "usage: ./scanner [client-header|server-header|code]\n");
54         exit(ret);
55 }
56
57 #define XML_BUFFER_SIZE 4096
58
59 struct protocol {
60         char *name;
61         char *uppercase_name;
62         struct wl_list interface_list;
63 };
64
65 struct interface {
66         char *name;
67         char *uppercase_name;
68         int version;
69         struct wl_list request_list;
70         struct wl_list event_list;
71         struct wl_list enumeration_list;
72         struct wl_list link;
73 };
74
75 struct message {
76         char *name;
77         char *uppercase_name;
78         struct wl_list arg_list;
79         struct wl_list link;
80         int destructor;
81 };
82
83 enum arg_type {
84         NEW_ID,
85         INT,
86         UNSIGNED,
87         STRING,
88         OBJECT,
89         ARRAY,
90         FD
91 };
92
93 struct arg {
94         char *name;
95         enum arg_type type;
96         char *interface_name;
97         struct wl_list link;
98 };
99
100 struct enumeration {
101         char *name;
102         char *uppercase_name;
103         struct wl_list entry_list;
104         struct wl_list link;
105 };
106
107 struct entry {
108         char *name;
109         char *uppercase_name;
110         char *value;
111         struct wl_list link;
112 };
113
114 struct parse_context {
115         const char *filename;
116         XML_Parser parser;
117         struct protocol *protocol;
118         struct interface *interface;
119         struct message *message;
120         struct enumeration *enumeration;
121 };
122
123 static char *
124 uppercase_dup(const char *src)
125 {
126         char *u;
127         int i;
128
129         u = strdup(src);
130         for (i = 0; u[i]; i++)
131                 u[i] = toupper(u[i]);
132         u[i] = '\0';
133
134         return u;
135 }
136
137 static void
138 fail(struct parse_context *ctx, const char *msg)
139 {
140         fprintf(stderr, "%s:%ld: %s\n",
141                 ctx->filename, XML_GetCurrentLineNumber(ctx->parser), msg);
142         exit(EXIT_FAILURE);
143 }
144
145 static void
146 start_element(void *data, const char *element_name, const char **atts)
147 {
148         struct parse_context *ctx = data;
149         struct interface *interface;
150         struct message *message;
151         struct arg *arg;
152         struct enumeration *enumeration;
153         struct entry *entry;
154         const char *name, *type, *interface_name, *value;
155         int i, version;
156
157         name = NULL;
158         type = NULL;
159         version = 0;
160         interface_name = NULL;
161         value = NULL;
162         for (i = 0; atts[i]; i += 2) {
163                 if (strcmp(atts[i], "name") == 0)
164                         name = atts[i + 1];
165                 if (strcmp(atts[i], "version") == 0)
166                         version = atoi(atts[i + 1]);
167                 if (strcmp(atts[i], "type") == 0)
168                         type = atts[i + 1];
169                 if (strcmp(atts[i], "value") == 0)
170                         value = atts[i + 1];
171                 if (strcmp(atts[i], "interface") == 0)
172                         interface_name = atts[i + 1];
173         }
174
175         if (strcmp(element_name, "protocol") == 0) {
176                 if (name == NULL)
177                         fail(ctx, "no protocol name given");
178
179                 ctx->protocol->name = strdup(name);
180                 ctx->protocol->uppercase_name = uppercase_dup(name);
181         } else if (strcmp(element_name, "interface") == 0) {
182                 if (name == NULL)
183                         fail(ctx, "no interface name given");
184
185                 if (version == 0)
186                         fail(ctx, "no interface version given");
187
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,
196                                &interface->link);
197                 ctx->interface = interface;
198         } else if (strcmp(element_name, "request") == 0 ||
199                    strcmp(element_name, "event") == 0) {
200                 if (name == NULL)
201                         fail(ctx, "no request name given");
202
203                 message = malloc(sizeof *message);
204                 message->name = strdup(name);
205                 message->uppercase_name = uppercase_dup(name);
206                 wl_list_init(&message->arg_list);
207
208                 if (strcmp(element_name, "request") == 0)
209                         wl_list_insert(ctx->interface->request_list.prev,
210                                        &message->link);
211                 else
212                         wl_list_insert(ctx->interface->event_list.prev,
213                                        &message->link);
214
215                 if (type != NULL && strcmp(type, "destructor") == 0)
216                         message->destructor = 1;
217                 else
218                         message->destructor = 0;
219
220                 ctx->message = message;
221         } else if (strcmp(element_name, "arg") == 0) {
222                 arg = malloc(sizeof *arg);
223                 arg->name = strdup(name);
224
225                 if (strcmp(type, "int") == 0)
226                         arg->type = INT;
227                 else if (strcmp(type, "uint") == 0)
228                         arg->type = UNSIGNED;
229                 else if (strcmp(type, "string") == 0)
230                         arg->type = STRING;
231                 else if (strcmp(type, "array") == 0)
232                         arg->type = ARRAY;
233                 else if (strcmp(type, "fd") == 0)
234                         arg->type = FD;
235                 else if (strcmp(type, "new_id") == 0) {
236                         if (interface_name == NULL)
237                                 fail(ctx, "no interface name given");
238                         arg->type = NEW_ID;
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");
243                         arg->type = OBJECT;
244                         arg->interface_name = strdup(interface_name);
245                 } else {
246                         fail(ctx, "unknown type");
247                 }
248
249                 wl_list_insert(ctx->message->arg_list.prev, &arg->link);
250         } else if (strcmp(element_name, "enum") == 0) {
251                 if (name == NULL)
252                         fail(ctx, "no enum name given");
253
254                 enumeration = malloc(sizeof *enumeration);
255                 enumeration->name = strdup(name);
256                 enumeration->uppercase_name = uppercase_dup(name);
257                 wl_list_init(&enumeration->entry_list);
258
259                 wl_list_insert(ctx->interface->enumeration_list.prev,
260                                &enumeration->link);
261
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,
269                                &entry->link);
270         }
271 }
272
273 static void
274 emit_opcodes(struct wl_list *message_list, struct interface *interface)
275 {
276         struct message *m;
277         int opcode;
278
279         if (wl_list_empty(message_list))
280                 return;
281
282         opcode = 0;
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++);
286
287         printf("\n");
288 }
289
290 static void
291 emit_type(struct arg *a)
292 {
293         switch (a->type) {
294         default:
295         case INT:
296         case FD:
297                 printf("int ");
298                 break;
299         case NEW_ID:
300         case UNSIGNED:
301                 printf("uint32_t ");
302                 break;
303         case STRING:
304                 printf("const char *");
305                 break;
306         case OBJECT:
307                 printf("struct wl_%s *", a->interface_name);
308                 break;
309         case ARRAY:
310                 printf("struct wl_array *");
311                 break;
312         }
313 }
314
315 static void
316 emit_stubs(struct wl_list *message_list, struct interface *interface)
317 {
318         struct message *m;
319         struct arg *a, *ret;
320         int has_destructor, has_destroy;
321
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"
326                        "{\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"
330                        "}\n\n",
331                        interface->name,
332                        interface->name,
333                        interface->name,
334                        interface->name,
335                        interface->name);
336
337         printf("static inline void\n"
338                "wl_%s_set_user_data(struct wl_%s *%s, void *user_data)\n"
339                "{\n"
340                "\twl_proxy_set_user_data((struct wl_proxy *) %s, user_data);\n"
341                "}\n\n",
342                interface->name, interface->name, interface->name,
343                interface->name);
344
345         printf("static inline void *\n"
346                "wl_%s_get_user_data(struct wl_%s *%s)\n"
347                "{\n"
348                "\treturn wl_proxy_get_user_data((struct wl_proxy *) %s);\n"
349                "}\n\n",
350                interface->name, interface->name, interface->name,
351                interface->name);
352
353         has_destructor = 0;
354         has_destroy = 0;
355         wl_list_for_each(m, message_list, link) {
356                 if (m->destructor)
357                         has_destructor = 1;
358                 if (strcmp(m->name, "destroy)") == 0)
359                         has_destroy = 1;
360         }
361
362         if (!has_destructor && has_destroy) {
363                 fprintf(stderr,
364                         "interface %s has method named destroy but"
365                         "no destructor", interface->name);
366                 exit(EXIT_FAILURE);
367         }
368
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"
373                        "{\n"
374                        "\twl_proxy_destroy("
375                        "(struct wl_proxy *) %s);\n"
376                        "}\n\n",
377                        interface->name, interface->name, interface->name,
378                        interface->name);
379
380         if (wl_list_empty(message_list))
381                 return;
382
383         wl_list_for_each(m, message_list, link) {
384                 ret = NULL;
385                 wl_list_for_each(a, &m->arg_list, link) {
386                         if (a->type == NEW_ID)
387                                 ret = a;
388                 }
389
390                 if (ret)
391                         printf("static inline struct wl_%s *\n",
392                                ret->interface_name);
393                 else
394                         printf("static inline void\n");
395
396                 printf("wl_%s_%s(struct wl_%s *%s",
397                        interface->name, m->name,
398                        interface->name, interface->name);
399
400                 wl_list_for_each(a, &m->arg_list, link) {
401                         if (a->type == NEW_ID)
402                                 continue;
403                         printf(", ");
404                         emit_type(a);
405                         printf("%s", a->name);
406                 }
407
408                 printf(")\n"
409                        "{\n");
410                 if (ret)
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"
415                                "\tif (!%s)\n"
416                                "\t\treturn NULL;\n\n",
417                                ret->name,
418                                ret->name,
419                                interface->name, ret->interface_name,
420                                ret->name);
421
422                 printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
423                        "\t\t\t WL_%s_%s",
424                        interface->name,
425                        interface->uppercase_name,
426                        m->uppercase_name);
427
428                 wl_list_for_each(a, &m->arg_list, link) {
429                         printf(", ");
430                                 printf("%s", a->name);
431                 }
432                 printf(");\n");
433
434                 if (m->destructor)
435                         printf("\n\twl_proxy_destroy("
436                                "(struct wl_proxy *) %s);\n",
437                                interface->name);
438
439                 if (ret)
440                         printf("\n\treturn (struct wl_%s *) %s;\n",
441                                ret->interface_name, ret->name);
442
443                 printf("}\n\n");
444         }
445 }
446
447 static const char *indent(int n)
448 {
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       "
458         };
459
460         return whitespace[n % 8] + 12 - n / 8;
461 }
462
463 static void
464 emit_enumerations(struct interface *interface)
465 {
466         struct enumeration *e;
467         struct entry *entry;
468
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,
478                                e->uppercase_name,
479                                entry->uppercase_name, entry->value);
480                 printf("};\n");
481                 printf("#endif /* WL_%s_%s_ENUM */\n\n",
482                        interface->uppercase_name, e->uppercase_name);
483         }
484 }
485
486 static void
487 emit_structs(struct wl_list *message_list, struct interface *interface)
488 {
489         struct message *m;
490         struct arg *a;
491         int is_interface, n;
492
493         if (wl_list_empty(message_list))
494                 return;
495
496         is_interface = message_list == &interface->request_list;
497         printf("struct wl_%s_%s {\n", interface->name,
498                is_interface ? "interface" : "listener");
499
500         wl_list_for_each(m, message_list, link) {
501                 printf("\tvoid (*%s)(", m->name);
502
503                 n = strlen(m->name) + 17;
504                 if (is_interface) {
505                         printf("struct wl_client *client,\n"
506                                "%sstruct wl_%s *%s",
507                                indent(n),
508                                interface->name, interface->name);
509                 } else {
510                         printf("void *data,\n"),
511                         printf("%sstruct wl_%s *%s",
512                                indent(n), interface->name, interface->name);
513                 }
514
515                 wl_list_for_each(a, &m->arg_list, link) {
516                         printf(",\n%s", indent(n));
517
518                         emit_type(a);
519                         printf("%s", a->name);
520                 }
521
522                 printf(");\n");
523         }
524
525         printf("};\n\n");
526
527         if (!is_interface) {
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"
531                    "{\n"
532                    "\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n"
533                    "%s(void (**)(void)) listener, data);\n"
534                    "}\n\n",
535                    interface->name, interface->name, interface->name,
536                    indent(17 + strlen(interface->name)),
537                    interface->name,
538                    interface->name,
539                    indent(37));
540         }
541 }
542
543
544 static void
545 emit_header(struct protocol *protocol, int server)
546 {
547         struct interface *i;
548         const char *s = server ? "SERVER" : "CLIENT";
549
550         printf("%s\n\n"
551                "#ifndef %s_%s_PROTOCOL_H\n"
552                "#define %s_%s_PROTOCOL_H\n"
553                "\n"
554                "#ifdef  __cplusplus\n"
555                "extern \"C\" {\n"
556                "#endif\n"
557                "\n"
558                "#include <stdint.h>\n"
559                "#include <stddef.h>\n"
560                "#include \"wayland-util.h\"\n\n"
561                "struct wl_client;\n\n",
562                copyright,
563                protocol->uppercase_name, s,
564                protocol->uppercase_name, s);
565
566         wl_list_for_each(i, &protocol->interface_list, link)
567                 printf("struct wl_%s;\n", i->name);
568         printf("\n");
569
570         wl_list_for_each(i, &protocol->interface_list, link) {
571                 printf("extern const struct wl_interface "
572                        "wl_%s_interface;\n",
573                        i->name);
574         }
575         printf("\n");
576
577         wl_list_for_each(i, &protocol->interface_list, link) {
578
579                 emit_enumerations(i);
580
581                 if (server) {
582                         emit_structs(&i->request_list, i);
583                         emit_opcodes(&i->event_list, i);
584                 } else {
585                         emit_structs(&i->event_list, i);
586                         emit_opcodes(&i->request_list, i);
587                         emit_stubs(&i->request_list, i);
588                 }
589         }
590
591         printf("#ifdef  __cplusplus\n"
592                "}\n"
593                "#endif\n"
594                "\n"
595                "#endif\n");
596 }
597
598 static void
599 emit_messages(struct wl_list *message_list,
600               struct interface *interface, const char *suffix)
601 {
602         struct message *m;
603         struct arg *a;
604
605         if (wl_list_empty(message_list))
606                 return;
607
608         printf("static const struct wl_message "
609                "%s_%s[] = {\n",
610                interface->name, suffix);
611
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) {
615                         switch (a->type) {
616                         default:
617                         case INT:
618                                 printf("i");
619                                 break;
620                         case NEW_ID:
621                                 printf("n");
622                                 break;
623                         case UNSIGNED:
624                                 printf("u");
625                                 break;
626                         case STRING:
627                                 printf("s");
628                                 break;
629                         case OBJECT:
630                                 printf("o");
631                                 break;
632                         case ARRAY:
633                                 printf("a");
634                                 break;
635                         case FD:
636                                 printf("h");
637                                 break;
638                         }
639                 }
640                 printf("\" },\n");
641         }
642
643         printf("};\n\n");
644 }
645
646 static void
647 emit_code(struct protocol *protocol)
648 {
649         struct interface *i;
650
651         printf("%s\n\n"
652                "#include <stdlib.h>\n"
653                "#include <stdint.h>\n"
654                "#include \"wayland-util.h\"\n\n",
655                copyright);
656
657         wl_list_for_each(i, &protocol->interface_list, link) {
658
659                 emit_messages(&i->request_list, i, "requests");
660                 emit_messages(&i->event_list, i, "events");
661
662                 printf("WL_EXPORT const struct wl_interface "
663                        "wl_%s_interface = {\n"
664                        "\t\"%s\", %d,\n",
665                        i->name, i->name, i->version);
666
667                 if (!wl_list_empty(&i->request_list))
668                         printf("\tARRAY_LENGTH(%s_requests), %s_requests,\n",
669                                i->name, i->name);
670                 else
671                         printf("\t0, NULL,\n");
672
673                 if (!wl_list_empty(&i->event_list))
674                         printf("\tARRAY_LENGTH(%s_events), %s_events,\n",
675                                i->name, i->name);
676                 else
677                         printf("\t0, NULL,\n");
678
679                 printf("};\n\n");
680         }
681 }
682
683 int main(int argc, char *argv[])
684 {
685         struct parse_context ctx;
686         struct protocol protocol;
687         int len;
688         void *buf;
689
690         if (argc != 2)
691                 usage(EXIT_FAILURE);
692
693         wl_list_init(&protocol.interface_list);
694         ctx.protocol = &protocol;
695
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");
701                 exit(EXIT_FAILURE);
702         }
703
704         XML_SetElementHandler(ctx.parser, start_element, NULL);
705         do {
706                 buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
707                 len = fread(buf, 1, XML_BUFFER_SIZE, stdin);
708                 if (len < 0) {
709                         fprintf(stderr, "fread: %s\n", strerror(errno));
710                         exit(EXIT_FAILURE);
711                 }
712                 XML_ParseBuffer(ctx.parser, len, len == 0);
713
714         } while (len > 0);
715
716         XML_ParserFree(ctx.parser);
717
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);
724         }
725
726         return 0;
727 }