Generate the wl_*_add_listener() stubs as well
[profile/ivi/wayland.git] / 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 [header|code]\n");
54         exit(ret);
55 }
56
57 #define XML_BUFFER_SIZE 4096
58
59 struct protocol {
60         struct wl_list interface_list;
61 };
62
63 struct interface {
64         char *name;
65         char *uppercase_name;
66         int version;
67         struct wl_list request_list;
68         struct wl_list event_list;
69         struct wl_list link;
70 };
71
72 struct message {
73         char *name;
74         char *uppercase_name;
75         struct wl_list arg_list;
76         struct wl_list link;
77 };
78
79 enum arg_type {
80         NEW_ID,
81         INT,
82         UNSIGNED,
83         STRING,
84         OBJECT,
85         ARRAY
86 };
87
88 struct arg {
89         char *name;
90         enum arg_type type;
91         char *interface_name;
92         struct wl_list link;
93 };
94
95 struct parse_context {
96         struct protocol *protocol;
97         struct interface *interface;
98         struct message *message;
99 };
100
101 static char *
102 uppercase_dup(const char *src)
103 {
104         char *u;
105         int i;
106
107         u = strdup(src);
108         for (i = 0; u[i]; i++)
109                 u[i] = toupper(u[i]);
110         u[i] = '\0';
111
112         return u;
113 }
114
115 static void
116 start_element(void *data, const char *element_name, const char **atts)
117 {
118         struct parse_context *ctx = data;
119         struct interface *interface;
120         struct message *message;
121         struct arg *arg;
122         const char *name, *type, *interface_name;
123         int i, version;
124
125         name = NULL;
126         type = NULL;
127         version = 0;
128         interface_name = NULL;
129         for (i = 0; atts[i]; i += 2) {
130                 if (strcmp(atts[i], "name") == 0)
131                         name = atts[i + 1];
132                 if (strcmp(atts[i], "version") == 0)
133                         version = atoi(atts[i + 1]);
134                 if (strcmp(atts[i], "type") == 0)
135                         type = atts[i + 1];
136                 if (strcmp(atts[i], "interface") == 0)
137                         interface_name = atts[i + 1];
138         }
139
140         if (strcmp(element_name, "interface") == 0) {
141                 if (name == NULL) {
142                         fprintf(stderr, "no interface name given\n");
143                         exit(EXIT_FAILURE);
144                 }
145
146                 if (version == 0) {
147                         fprintf(stderr, "no interface version given\n");
148                         exit(EXIT_FAILURE);
149                 }
150
151                 interface = malloc(sizeof *interface);
152                 interface->name = strdup(name);
153                 interface->uppercase_name = uppercase_dup(name);
154                 interface->version = version;
155                 wl_list_init(&interface->request_list);
156                 wl_list_init(&interface->event_list);
157                 wl_list_insert(ctx->protocol->interface_list.prev,
158                                &interface->link);
159                 ctx->interface = interface;
160         } else if (strcmp(element_name, "request") == 0 ||
161                    strcmp(element_name, "event") == 0) {
162                 if (name == NULL) {
163                         fprintf(stderr, "no request name given\n");
164                         exit(EXIT_FAILURE);
165                 }
166
167                 message = malloc(sizeof *message);
168                 message->name = strdup(name);
169                 message->uppercase_name = uppercase_dup(name);
170                 wl_list_init(&message->arg_list);
171
172                 if (strcmp(element_name, "request") == 0)
173                         wl_list_insert(ctx->interface->request_list.prev,
174                                        &message->link);
175                 else
176                         wl_list_insert(ctx->interface->event_list.prev,
177                                        &message->link);
178
179                 ctx->message = message;
180         } else if (strcmp(element_name, "arg") == 0) {
181                 arg = malloc(sizeof *arg);
182                 arg->name = strdup(name);
183
184                 if (strcmp(type, "int") == 0)
185                         arg->type = INT;
186                 else if (strcmp(type, "uint") == 0)
187                         arg->type = UNSIGNED;
188                 else if (strcmp(type, "string") == 0)
189                         arg->type = STRING;
190                 else if (strcmp(type, "array") == 0)
191                         arg->type = ARRAY;
192                 else if (strcmp(type, "new_id") == 0) {
193                         if (interface_name == NULL) {
194                                 fprintf(stderr, "no interface name given\n");
195                                 exit(EXIT_FAILURE);
196                         }
197                         arg->type = NEW_ID;
198                         arg->interface_name = strdup(interface_name);
199                 } else if (strcmp(type, "object") == 0) {
200                         if (interface_name == NULL) {
201                                 fprintf(stderr, "no interface name given\n");
202                                 exit(EXIT_FAILURE);
203                         }
204                         arg->type = OBJECT;
205                         arg->interface_name = strdup(interface_name);
206                 } else {
207                         fprintf(stderr, "unknown type: %s\n", type);
208                         exit(EXIT_FAILURE);
209                 }
210
211                 wl_list_insert(ctx->message->arg_list.prev,
212                                &arg->link);
213         }
214 }
215
216 static void
217 emit_opcodes(struct wl_list *message_list, struct interface *interface)
218 {
219         struct message *m;
220         int opcode;
221
222         if (wl_list_empty(message_list))
223                 return;
224
225         opcode = 0;
226         wl_list_for_each(m, message_list, link)
227                 printf("#define WL_%s_%s\t%d\n",
228                        interface->uppercase_name, m->uppercase_name, opcode++);
229
230         printf("\n");
231 }
232
233 static void
234 emit_type(struct arg *a)
235 {
236         switch (a->type) {
237         default:
238         case INT:
239                 printf("int32_t ");
240                 break;
241         case NEW_ID:
242         case UNSIGNED:
243                 printf("uint32_t ");
244                 break;
245         case STRING:
246                 printf("const char *");
247                 break;
248         case OBJECT:
249                 printf("struct wl_%s *", a->interface_name);
250                 break;
251         case ARRAY:
252                 printf("struct wl_array *");
253                 break;
254         }
255 }
256
257 static void
258 emit_stubs(struct wl_list *message_list, struct interface *interface)
259 {
260         struct message *m;
261         struct arg *a, *ret;
262
263         if (wl_list_empty(message_list))
264                 return;
265
266         wl_list_for_each(m, message_list, link) {
267                 ret = NULL;
268                 wl_list_for_each(a, &m->arg_list, link) {
269                         if (a->type == NEW_ID)
270                                 ret = a;
271                 }
272
273                 if (ret)
274                         printf("static inline struct wl_%s *\n",
275                                ret->interface_name);
276                 else
277                         printf("static inline void\n");
278
279                 printf("wl_%s_%s(struct wl_%s *%s",
280                        interface->name, m->name,
281                        interface->name, interface->name);
282
283                 wl_list_for_each(a, &m->arg_list, link) {
284                         if (a->type == NEW_ID)
285                                 continue;
286                         printf(", ");
287                         emit_type(a);
288                         printf("%s", a->name);
289                 }
290
291                 printf(")\n"
292                        "{\n");
293                 if (ret)
294                         printf("\tstruct wl_proxy *%s;\n\n"
295                                "\t%s = wl_proxy_create("
296                                "(struct wl_proxy *) %s,\n"
297                                "\t\t\t     &wl_%s_interface);\n"
298                                "\tif (!%s)\n"
299                                "\t\treturn NULL;\n\n",
300                                ret->name,
301                                ret->name,
302                                interface->name, ret->interface_name,
303                                ret->name);
304
305                 printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
306                        "\t\t\t WL_%s_%s",
307                        interface->name,
308                        interface->uppercase_name,
309                        m->uppercase_name);
310
311                 wl_list_for_each(a, &m->arg_list, link) {
312                         printf(", ");
313                                 printf("%s", a->name);
314                 }
315                 printf(");\n");
316
317                 if (ret)
318                         printf("\n\treturn (struct wl_%s *) %s;\n",
319                                ret->interface_name, ret->name);
320
321                 printf("}\n\n");
322         }
323 }
324
325 static const char *indent(int n)
326 {
327         const char *whitespace[] = {
328                 "\t\t\t\t\t\t\t\t\t\t\t\t",
329                 "\t\t\t\t\t\t\t\t\t\t\t\t ",
330                 "\t\t\t\t\t\t\t\t\t\t\t\t  ",
331                 "\t\t\t\t\t\t\t\t\t\t\t\t   ",
332                 "\t\t\t\t\t\t\t\t\t\t\t\t    ",
333                 "\t\t\t\t\t\t\t\t\t\t\t\t     ",
334                 "\t\t\t\t\t\t\t\t\t\t\t\t      ",
335                 "\t\t\t\t\t\t\t\t\t\t\t\t       "
336         };
337
338         return whitespace[n % 8] + 12 - n / 8;
339 }
340
341 static void
342 emit_structs(struct wl_list *message_list, struct interface *interface)
343 {
344         struct message *m;
345         struct arg *a;
346         int is_interface, n;
347
348         if (wl_list_empty(message_list))
349                 return;
350
351         is_interface = message_list == &interface->request_list;
352         printf("struct wl_%s_%s {\n", interface->name,
353                is_interface ? "interface" : "listener");
354
355         wl_list_for_each(m, message_list, link) {
356                 printf("\tvoid (*%s)(", m->name);
357
358                 n = strlen(m->name) + 17;
359                 if (is_interface) {
360                         printf("struct wl_client *client,\n"
361                                "%sstruct wl_%s *%s",
362                                indent(n),
363                                interface->name, interface->name);
364                 } else {
365                         printf("void *data,\n"),
366                         printf("%sstruct wl_%s *%s",
367                                indent(n), interface->name, interface->name);
368                 }
369
370                 wl_list_for_each(a, &m->arg_list, link) {
371                         printf(",\n%s", indent(n));
372
373                         emit_type(a);
374                         printf("%s", a->name);
375                 }
376
377                 printf(");\n");
378         }
379
380         printf("};\n\n");
381
382         if (!is_interface) {
383             printf("static inline int\n"
384                    "wl_%s_add_listener(struct wl_%s *%s,\n"
385                    "%sconst struct wl_%s_listener *listener, void *data)\n"
386                    "{\n"
387                    "\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n"
388                    "%s(void (**)(void)) listener, data);\n"
389                    "}\n\n",
390                    interface->name, interface->name, interface->name,
391                    indent(17 + strlen(interface->name)),
392                    interface->name,
393                    interface->name,
394                    indent(37));
395         }
396 }
397
398 static void
399 emit_header(struct protocol *protocol, int server)
400 {
401         struct interface *i;
402
403         printf("%s\n\n"
404                "#ifndef WAYLAND_PROTOCOL_H\n"
405                "#define WAYLAND_PROTOCOL_H\n"
406                "\n"
407                "#ifdef  __cplusplus\n"
408                "extern \"C\" {\n"
409                "#endif\n"
410                "\n"
411                "#include <stdint.h>\n"
412                "#include \"wayland-util.h\"\n\n"
413                "struct wl_client;\n\n", copyright);
414
415         wl_list_for_each(i, &protocol->interface_list, link)
416                 printf("struct wl_%s;\n", i->name);
417         printf("\n");
418
419         if (!server)
420                 printf("struct wl_proxy;\n\n"
421                        "extern void\n"
422                        "wl_proxy_marshal(struct wl_proxy *p, "
423                        "uint32_t opcode, ...);\n"
424
425                        "extern struct wl_proxy *\n"
426                        "wl_proxy_create(struct wl_proxy *factory,\n"
427                        "\t\tconst struct wl_interface *interface);\n"
428
429                        "extern int\n"
430                        "wl_proxy_add_listener(struct wl_proxy *proxy,\n"
431                        "\t\t      void (**implementation)(void), "
432                        "void *data);\n\n");
433
434         wl_list_for_each(i, &protocol->interface_list, link) {
435                 printf("extern const struct wl_interface "
436                        "wl_%s_interface;\n",
437                        i->name);
438         }
439         printf("\n");
440
441         wl_list_for_each(i, &protocol->interface_list, link) {
442
443                 if (server) {
444                         emit_structs(&i->request_list, i);
445                         emit_opcodes(&i->event_list, i);
446                 } else {
447                         emit_structs(&i->event_list, i);
448                         emit_opcodes(&i->request_list, i);
449                         emit_stubs(&i->request_list, i);
450                 }
451         }
452
453         printf("#ifdef  __cplusplus\n"
454                "}\n"
455                "#endif\n"
456                "\n"
457                "#endif\n");
458 }
459
460 static void
461 emit_messages(struct wl_list *message_list,
462               struct interface *interface, const char *suffix)
463 {
464         struct message *m;
465         struct arg *a;
466
467         if (wl_list_empty(message_list))
468                 return;
469
470         printf("static const struct wl_message "
471                "%s_%s[] = {\n",
472                interface->name, suffix);
473
474         wl_list_for_each(m, message_list, link) {
475                 printf("\t{ \"%s\", \"", m->name);
476                 wl_list_for_each(a, &m->arg_list, link) {
477                         switch (a->type) {
478                         default:
479                         case INT:
480                                 printf("i");
481                                 break;
482                         case NEW_ID:
483                                 printf("n");
484                                 break;
485                         case UNSIGNED:
486                                 printf("u");
487                                 break;
488                         case STRING:
489                                 printf("s");
490                                 break;
491                         case OBJECT:
492                                 printf("o");
493                                 break;
494                         case ARRAY:
495                                 printf("a");
496                                 break;
497                         }
498                 }
499                 printf("\" },\n");
500         }
501
502         printf("};\n\n");
503 }
504
505 static void
506 emit_code(struct protocol *protocol)
507 {
508         struct interface *i;
509
510         printf("%s\n\n"
511                "#include <stdlib.h>\n"
512                "#include <stdint.h>\n"
513                "#include \"wayland-util.h\"\n\n",
514                copyright);
515
516         wl_list_for_each(i, &protocol->interface_list, link) {
517
518                 emit_messages(&i->request_list, i, "requests");
519                 emit_messages(&i->event_list, i, "events");
520
521                 printf("WL_EXPORT const struct wl_interface "
522                        "wl_%s_interface = {\n"
523                        "\t\"%s\", %d,\n",
524                        i->name, i->name, i->version);
525
526                 if (!wl_list_empty(&i->request_list))
527                         printf("\tARRAY_LENGTH(%s_requests), %s_requests,\n",
528                                i->name, i->name);
529                 else
530                         printf("\t0, NULL,\n");
531
532                 if (!wl_list_empty(&i->event_list))
533                         printf("\tARRAY_LENGTH(%s_events), %s_events,\n",
534                                i->name, i->name);
535                 else
536                         printf("\t0, NULL,\n");
537
538                 printf("};\n\n");
539         }
540 }
541
542 int main(int argc, char *argv[])
543 {
544         struct parse_context ctx;
545         struct protocol protocol;
546         XML_Parser parser;
547         int len;
548         void *buf;
549
550         if (argc != 2)
551                 usage(EXIT_FAILURE);
552
553         wl_list_init(&protocol.interface_list);
554         ctx.protocol = &protocol;
555
556         parser = XML_ParserCreate(NULL);
557         XML_SetUserData(parser, &ctx);
558         if (parser == NULL) {
559                 fprintf(stderr, "failed to create parser\n");
560                 exit(EXIT_FAILURE);
561         }
562
563         XML_SetElementHandler(parser, start_element, NULL);
564         do {
565                 buf = XML_GetBuffer(parser, XML_BUFFER_SIZE);
566                 len = fread(buf, 1, XML_BUFFER_SIZE, stdin);
567                 if (len < 0) {
568                         fprintf(stderr, "fread: %s\n", strerror(errno));
569                         exit(EXIT_FAILURE);
570                 }
571                 XML_ParseBuffer(parser, len, len == 0);
572
573         } while (len > 0);
574
575         XML_ParserFree(parser);
576
577         if (strcmp(argv[1], "client-header") == 0) {
578                 emit_header(&protocol, 0);
579         } else if (strcmp(argv[1], "server-header") == 0) {
580                 emit_header(&protocol, 1);
581         } else if (strcmp(argv[1], "code") == 0) {
582                 emit_code(&protocol);
583         }
584
585         return 0;
586 }