d0aafec6be05f91084748bb51d84f3c417ca909b
[profile/ivi/wayland.git] / src / scanner.c
1 /*
2  * Copyright © 2008-2011 Kristian Høgsberg
3  * Copyright © 2011 Intel Corporation
4  *
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.
14  *
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
21  * OF THIS SOFTWARE.
22  */
23
24 #include <stdio.h>
25 #include <stdarg.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <expat.h>
30
31 #include "wayland-util.h"
32
33 static int
34 usage(int ret)
35 {
36         fprintf(stderr, "usage: ./scanner [client-header|server-header|code]\n");
37         exit(ret);
38 }
39
40 #define XML_BUFFER_SIZE 4096
41
42 struct description {
43         char *summary;
44         char *text;
45 };
46
47 struct protocol {
48         char *name;
49         char *uppercase_name;
50         struct wl_list interface_list;
51         int type_index;
52         int null_run_length;
53         char *copyright;
54         struct description *description;
55 };
56
57 struct interface {
58         char *name;
59         char *uppercase_name;
60         int version;
61         int since;
62         struct wl_list request_list;
63         struct wl_list event_list;
64         struct wl_list enumeration_list;
65         struct wl_list link;
66         struct description *description;
67 };
68
69 struct message {
70         char *name;
71         char *uppercase_name;
72         struct wl_list arg_list;
73         struct wl_list link;
74         int arg_count;
75         int type_index;
76         int all_null;
77         int destructor;
78         int since;
79         struct description *description;
80 };
81
82 enum arg_type {
83         NEW_ID,
84         INT,
85         UNSIGNED,
86         FIXED,
87         STRING,
88         OBJECT,
89         ARRAY,
90         FD
91 };
92
93 struct arg {
94         char *name;
95         enum arg_type type;
96         int nullable;
97         char *interface_name;
98         struct wl_list link;
99         char *summary;
100 };
101
102 struct enumeration {
103         char *name;
104         char *uppercase_name;
105         struct wl_list entry_list;
106         struct wl_list link;
107         struct description *description;
108 };
109
110 struct entry {
111         char *name;
112         char *uppercase_name;
113         char *value;
114         char *summary;
115         struct wl_list link;
116 };
117
118 struct parse_context {
119         const char *filename;
120         XML_Parser parser;
121         struct protocol *protocol;
122         struct interface *interface;
123         struct message *message;
124         struct enumeration *enumeration;
125         struct description *description;
126         char character_data[8192];
127         unsigned int character_data_length;
128 };
129
130 static int
131 list_length(struct wl_list *list)
132 {
133         struct wl_list *l;
134         int i;
135
136         for (i = 0, l = list->next; l != list; i++, l = l->next)
137                 ;
138
139         return i;
140 }
141
142 static char *
143 uppercase_dup(const char *src)
144 {
145         char *u;
146         int i;
147
148         u = strdup(src);
149         for (i = 0; u[i]; i++)
150                 u[i] = toupper(u[i]);
151         u[i] = '\0';
152
153         return u;
154 }
155
156 static const char *indent(int n)
157 {
158         const char *whitespace[] = {
159                 "\t\t\t\t\t\t\t\t\t\t\t\t",
160                 "\t\t\t\t\t\t\t\t\t\t\t\t ",
161                 "\t\t\t\t\t\t\t\t\t\t\t\t  ",
162                 "\t\t\t\t\t\t\t\t\t\t\t\t   ",
163                 "\t\t\t\t\t\t\t\t\t\t\t\t    ",
164                 "\t\t\t\t\t\t\t\t\t\t\t\t     ",
165                 "\t\t\t\t\t\t\t\t\t\t\t\t      ",
166                 "\t\t\t\t\t\t\t\t\t\t\t\t       "
167         };
168
169         return whitespace[n % 8] + 12 - n / 8;
170 }
171
172 static void
173 desc_dump(char *desc, const char *fmt, ...) __attribute__((format(printf,2,3)));
174
175 static void
176 desc_dump(char *desc, const char *fmt, ...)
177 {
178         va_list ap;
179         char buf[128], hang;
180         int col, i, j, k, startcol;
181
182         va_start(ap, fmt);
183         vsnprintf(buf, sizeof buf, fmt, ap);
184         va_end(ap);
185
186         for (i = 0, col = 0; buf[i] != '*'; i++) {
187                 if (buf[i] == '\t')
188                         col = (col + 8) & ~7;
189                 else
190                         col++;
191         }
192
193         printf("%s", buf);
194
195         if (!desc) {
196                 printf("(none)\n");
197                 return;
198         }
199
200         startcol = col;
201         col += strlen(&buf[i]);
202         if (col - startcol > 2)
203                 hang = '\t';
204         else
205                 hang = ' ';
206
207         for (i = 0; desc[i]; ) {
208                 k = i;
209                 while (desc[i] && isspace(desc[i]))
210                         i++;
211                 if (!desc[i])
212                         break;
213
214                 j = i;
215                 while (desc[i] && !isspace(desc[i]))
216                         i++;
217
218                 if (col + i - j > 72) {
219                         printf("\n%s*%c", indent(startcol), hang);
220                         col = startcol;
221                 }
222
223                 if (col > startcol && k > 0)
224                         col += printf(" ");
225                 col += printf("%.*s", i - j, &desc[j]);
226         }
227         putchar('\n');
228 }
229
230 static void
231 fail(struct parse_context *ctx, const char *msg)
232 {
233         fprintf(stderr, "%s:%ld: %s\n",
234                 ctx->filename, XML_GetCurrentLineNumber(ctx->parser), msg);
235         exit(EXIT_FAILURE);
236 }
237
238 static int
239 is_nullable_type(struct arg *arg)
240 {
241         switch (arg->type) {
242         /* Strings, objects, and arrays are possibly nullable */
243         case STRING:
244         case OBJECT:
245         case NEW_ID:
246         case ARRAY:
247                 return 1;
248         default:
249                 return 0;
250         }
251 }
252
253 static void
254 start_element(void *data, const char *element_name, const char **atts)
255 {
256         struct parse_context *ctx = data;
257         struct interface *interface;
258         struct message *message;
259         struct arg *arg;
260         struct enumeration *enumeration;
261         struct entry *entry;
262         struct description *description;
263         const char *name, *type, *interface_name, *value, *summary, *since;
264         const char *allow_null;
265         char *end;
266         int i, version;
267
268         name = NULL;
269         type = NULL;
270         version = 0;
271         interface_name = NULL;
272         value = NULL;
273         summary = NULL;
274         description = NULL;
275         since = NULL;
276         allow_null = NULL;
277         for (i = 0; atts[i]; i += 2) {
278                 if (strcmp(atts[i], "name") == 0)
279                         name = atts[i + 1];
280                 if (strcmp(atts[i], "version") == 0)
281                         version = atoi(atts[i + 1]);
282                 if (strcmp(atts[i], "type") == 0)
283                         type = atts[i + 1];
284                 if (strcmp(atts[i], "value") == 0)
285                         value = atts[i + 1];
286                 if (strcmp(atts[i], "interface") == 0)
287                         interface_name = atts[i + 1];
288                 if (strcmp(atts[i], "summary") == 0)
289                         summary = atts[i + 1];
290                 if (strcmp(atts[i], "since") == 0)
291                         since = atts[i + 1];
292                 if (strcmp(atts[i], "allow-null") == 0)
293                         allow_null = atts[i + 1];
294         }
295
296         ctx->character_data_length = 0;
297         if (strcmp(element_name, "protocol") == 0) {
298                 if (name == NULL)
299                         fail(ctx, "no protocol name given");
300
301                 ctx->protocol->name = strdup(name);
302                 ctx->protocol->uppercase_name = uppercase_dup(name);
303                 ctx->protocol->description = NULL;
304         } else if (strcmp(element_name, "copyright") == 0) {
305                 
306         } else if (strcmp(element_name, "interface") == 0) {
307                 if (name == NULL)
308                         fail(ctx, "no interface name given");
309
310                 if (version == 0)
311                         fail(ctx, "no interface version given");
312
313                 interface = malloc(sizeof *interface);
314                 interface->name = strdup(name);
315                 interface->uppercase_name = uppercase_dup(name);
316                 interface->version = version;
317                 interface->description = NULL;
318                 interface->since = 1;
319                 wl_list_init(&interface->request_list);
320                 wl_list_init(&interface->event_list);
321                 wl_list_init(&interface->enumeration_list);
322                 wl_list_insert(ctx->protocol->interface_list.prev,
323                                &interface->link);
324                 ctx->interface = interface;
325         } else if (strcmp(element_name, "request") == 0 ||
326                    strcmp(element_name, "event") == 0) {
327                 if (name == NULL)
328                         fail(ctx, "no request name given");
329
330                 message = malloc(sizeof *message);
331                 message->name = strdup(name);
332                 message->uppercase_name = uppercase_dup(name);
333                 wl_list_init(&message->arg_list);
334                 message->arg_count = 0;
335                 message->description = NULL;
336
337                 if (strcmp(element_name, "request") == 0)
338                         wl_list_insert(ctx->interface->request_list.prev,
339                                        &message->link);
340                 else
341                         wl_list_insert(ctx->interface->event_list.prev,
342                                        &message->link);
343
344                 if (type != NULL && strcmp(type, "destructor") == 0)
345                         message->destructor = 1;
346                 else
347                         message->destructor = 0;
348
349                 if (since != NULL) {
350                         version = strtol(since, &end, 0);
351                         if (errno == EINVAL || end == since || *end != '\0')
352                                 fail(ctx, "invalid integer\n");
353                         if (version <= ctx->interface->since)
354                                 fail(ctx, "since version not increasing\n");
355                         ctx->interface->since = version;
356                 }
357
358                 message->since = ctx->interface->since;
359
360                 if (strcmp(name, "destroy") == 0 && !message->destructor)
361                         fail(ctx, "destroy request should be destructor type");
362
363                 ctx->message = message;
364         } else if (strcmp(element_name, "arg") == 0) {
365                 if (name == NULL)
366                         fail(ctx, "no argument name given");
367
368                 arg = malloc(sizeof *arg);
369                 arg->name = strdup(name);
370
371                 if (strcmp(type, "int") == 0)
372                         arg->type = INT;
373                 else if (strcmp(type, "uint") == 0)
374                         arg->type = UNSIGNED;
375                 else if (strcmp(type, "fixed") == 0)
376                         arg->type = FIXED;
377                 else if (strcmp(type, "string") == 0)
378                         arg->type = STRING;
379                 else if (strcmp(type, "array") == 0)
380                         arg->type = ARRAY;
381                 else if (strcmp(type, "fd") == 0)
382                         arg->type = FD;
383                 else if (strcmp(type, "new_id") == 0) {
384                         arg->type = NEW_ID;
385                 } else if (strcmp(type, "object") == 0) {
386                         arg->type = OBJECT;
387                 } else {
388                         fail(ctx, "unknown type");
389                 }
390
391                 switch (arg->type) {
392                 case NEW_ID:
393                 case OBJECT:
394                         if (interface_name)
395                                 arg->interface_name = strdup(interface_name);
396                         break;
397                 default:
398                         if (interface_name != NULL)
399                                 fail(ctx, "interface not allowed");
400                         break;
401                 }
402
403                 if (allow_null == NULL || strcmp(allow_null, "false") == 0)
404                         arg->nullable = 0;
405                 else if (strcmp(allow_null, "true") == 0)
406                         arg->nullable = 1;
407                 else
408                         fail(ctx, "invalid value for allow-null attribute");
409
410                 if (allow_null != NULL && !is_nullable_type(arg))
411                         fail(ctx, "allow-null is only valid for objects, strings, and arrays");
412
413                 arg->summary = NULL;
414                 if (summary)
415                         arg->summary = strdup(summary);
416
417                 wl_list_insert(ctx->message->arg_list.prev, &arg->link);
418                 ctx->message->arg_count++;
419         } else if (strcmp(element_name, "enum") == 0) {
420                 if (name == NULL)
421                         fail(ctx, "no enum name given");
422
423                 enumeration = malloc(sizeof *enumeration);
424                 enumeration->name = strdup(name);
425                 enumeration->uppercase_name = uppercase_dup(name);
426                 enumeration->description = NULL;
427                 wl_list_init(&enumeration->entry_list);
428
429                 wl_list_insert(ctx->interface->enumeration_list.prev,
430                                &enumeration->link);
431
432                 ctx->enumeration = enumeration;
433         } else if (strcmp(element_name, "entry") == 0) {
434                 if (name == NULL)
435                         fail(ctx, "no entry name given");
436
437                 entry = malloc(sizeof *entry);
438                 entry->name = strdup(name);
439                 entry->uppercase_name = uppercase_dup(name);
440                 entry->value = strdup(value);
441                 if (summary)
442                         entry->summary = strdup(summary);
443                 else
444                         entry->summary = NULL;
445                 wl_list_insert(ctx->enumeration->entry_list.prev,
446                                &entry->link);
447         } else if (strcmp(element_name, "description") == 0) {
448                 if (summary == NULL)
449                         fail(ctx, "description without summary");
450
451                 description = malloc(sizeof *description);
452                 if (summary)
453                         description->summary = strdup(summary);
454                 else
455                         description->summary = NULL;
456
457                 if (ctx->message)
458                         ctx->message->description = description;
459                 else if (ctx->enumeration)
460                         ctx->enumeration->description = description;
461                 else if (ctx->interface)
462                         ctx->interface->description = description;
463                 else
464                         ctx->protocol->description = description;
465                 ctx->description = description;
466         }
467 }
468
469 static void
470 end_element(void *data, const XML_Char *name)
471 {
472         struct parse_context *ctx = data;
473
474         if (strcmp(name, "copyright") == 0) {
475                 ctx->protocol->copyright =
476                         strndup(ctx->character_data,
477                                 ctx->character_data_length);
478         } else if (strcmp(name, "description") == 0) {
479                 char *text = strndup(ctx->character_data,
480                                      ctx->character_data_length);
481                 if (text)
482                         ctx->description->text = text;
483                 ctx->description = NULL;
484         } else if (strcmp(name, "request") == 0 ||
485                    strcmp(name, "event") == 0) {
486                 ctx->message = NULL;
487         } else if (strcmp(name, "enum") == 0) {
488                 ctx->enumeration = NULL;
489         }
490 }
491
492 static void
493 character_data(void *data, const XML_Char *s, int len)
494 {
495         struct parse_context *ctx = data;
496
497         if (ctx->character_data_length + len > sizeof (ctx->character_data)) {
498                 fprintf(stderr, "too much character data");
499                 exit(EXIT_FAILURE);
500             }
501
502         memcpy(ctx->character_data + ctx->character_data_length, s, len);
503         ctx->character_data_length += len;
504 }
505
506 static void
507 emit_opcodes(struct wl_list *message_list, struct interface *interface)
508 {
509         struct message *m;
510         int opcode;
511
512         if (wl_list_empty(message_list))
513                 return;
514
515         opcode = 0;
516         wl_list_for_each(m, message_list, link)
517                 printf("#define %s_%s\t%d\n",
518                        interface->uppercase_name, m->uppercase_name, opcode++);
519
520         printf("\n");
521 }
522
523 static void
524 emit_type(struct arg *a)
525 {
526         switch (a->type) {
527         default:
528         case INT:
529         case FD:
530                 printf("int32_t ");
531                 break;
532         case NEW_ID:
533         case UNSIGNED:
534                 printf("uint32_t ");
535                 break;
536         case FIXED:
537                 printf("wl_fixed_t ");
538                 break;
539         case STRING:
540                 printf("const char *");
541                 break;
542         case OBJECT:
543                 printf("struct %s *", a->interface_name);
544                 break;
545         case ARRAY:
546                 printf("struct wl_array *");
547                 break;
548         }
549 }
550
551 static void
552 emit_stubs(struct wl_list *message_list, struct interface *interface)
553 {
554         struct message *m;
555         struct arg *a, *ret;
556         int has_destructor, has_destroy;
557
558         printf("static inline void\n"
559                "%s_set_user_data(struct %s *%s, void *user_data)\n"
560                "{\n"
561                "\twl_proxy_set_user_data((struct wl_proxy *) %s, user_data);\n"
562                "}\n\n",
563                interface->name, interface->name, interface->name,
564                interface->name);
565
566         printf("static inline void *\n"
567                "%s_get_user_data(struct %s *%s)\n"
568                "{\n"
569                "\treturn wl_proxy_get_user_data((struct wl_proxy *) %s);\n"
570                "}\n\n",
571                interface->name, interface->name, interface->name,
572                interface->name);
573
574         has_destructor = 0;
575         has_destroy = 0;
576         wl_list_for_each(m, message_list, link) {
577                 if (m->destructor)
578                         has_destructor = 1;
579                 if (strcmp(m->name, "destroy)") == 0)
580                         has_destroy = 1;
581         }
582
583         if (!has_destructor && has_destroy) {
584                 fprintf(stderr,
585                         "interface %s has method named destroy but"
586                         "no destructor", interface->name);
587                 exit(EXIT_FAILURE);
588         }
589
590         if (!has_destructor && strcmp(interface->name, "wl_display") != 0)
591                 printf("static inline void\n"
592                        "%s_destroy(struct %s *%s)\n"
593                        "{\n"
594                        "\twl_proxy_destroy("
595                        "(struct wl_proxy *) %s);\n"
596                        "}\n\n",
597                        interface->name, interface->name, interface->name,
598                        interface->name);
599
600         if (wl_list_empty(message_list))
601                 return;
602
603         wl_list_for_each(m, message_list, link) {
604                 ret = NULL;
605                 wl_list_for_each(a, &m->arg_list, link) {
606                         if (a->type == NEW_ID)
607                                 ret = a;
608                 }
609
610                 if (ret && ret->interface_name == NULL)
611                         printf("static inline void *\n");
612                 else if (ret)
613                         printf("static inline struct %s *\n",
614                                ret->interface_name);
615                 else
616                         printf("static inline void\n");
617
618                 printf("%s_%s(struct %s *%s",
619                        interface->name, m->name,
620                        interface->name, interface->name);
621
622                 wl_list_for_each(a, &m->arg_list, link) {
623                         if (a->type == NEW_ID && a->interface_name == NULL) {
624                                 printf(", const struct wl_interface *interface"
625                                        ", uint32_t version");
626                                 continue;
627                         } else if (a->type == NEW_ID)
628                                 continue;
629                         printf(", ");
630                         emit_type(a);
631                         printf("%s", a->name);
632                 }
633
634                 printf(")\n"
635                        "{\n");
636                 if (ret) {
637                         printf("\tstruct wl_proxy *%s;\n\n"
638                                "\t%s = wl_proxy_create("
639                                "(struct wl_proxy *) %s,\n",
640                                ret->name, ret->name, interface->name);
641                         if (ret->interface_name == NULL)
642                                 printf("\t\t\t     interface);\n");
643                         else
644                                 printf("\t\t\t     &%s_interface);\n",
645                                        ret->interface_name);
646
647                         printf("\tif (!%s)\n"
648                                "\t\treturn NULL;\n\n",
649                                ret->name);
650                 }
651
652                 printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
653                        "\t\t\t %s_%s",
654                        interface->name,
655                        interface->uppercase_name,
656                        m->uppercase_name);
657
658                 wl_list_for_each(a, &m->arg_list, link) {
659                         if (a->type == NEW_ID && a->interface_name == NULL)
660                                 printf(", interface->name, version");
661                         printf(", ");
662                         printf("%s", a->name);
663                 }
664                 printf(");\n");
665
666                 if (m->destructor)
667                         printf("\n\twl_proxy_destroy("
668                                "(struct wl_proxy *) %s);\n",
669                                interface->name);
670
671                 if (ret && ret->interface_name == NULL)
672                         printf("\n\treturn (void *) %s;\n", ret->name);
673                 else if (ret)
674                         printf("\n\treturn (struct %s *) %s;\n",
675                                ret->interface_name, ret->name);
676
677                 printf("}\n\n");
678         }
679 }
680
681 static void
682 emit_event_wrappers(struct wl_list *message_list, struct interface *interface)
683 {
684         struct message *m;
685         struct arg *a;
686
687         /* We provide hand written functions for the display object */
688         if (strcmp(interface->name, "wl_display") == 0)
689                 return;
690
691         wl_list_for_each(m, message_list, link) {
692                 printf("static inline void\n"
693                        "%s_send_%s(struct wl_resource *resource_",
694                        interface->name, m->name);
695
696                 wl_list_for_each(a, &m->arg_list, link) {
697                         printf(", ");
698                         switch (a->type) {
699                         case NEW_ID:
700                         case OBJECT:
701                                 printf("struct wl_resource *");
702                                 break;
703                         default:
704                                 emit_type(a);
705                         }
706                         printf("%s", a->name);
707                 }
708
709                 printf(")\n"
710                        "{\n"
711                        "\twl_resource_post_event(resource_, %s_%s",
712                        interface->uppercase_name, m->uppercase_name);
713
714                 wl_list_for_each(a, &m->arg_list, link)
715                         printf(", %s", a->name);
716
717                 printf(");\n");
718                 printf("}\n\n");
719         }
720 }
721
722 static void
723 emit_enumerations(struct interface *interface)
724 {
725         struct enumeration *e;
726         struct entry *entry;
727
728         wl_list_for_each(e, &interface->enumeration_list, link) {
729                 struct description *desc = e->description;
730
731                 printf("#ifndef %s_%s_ENUM\n",
732                        interface->uppercase_name, e->uppercase_name);
733                 printf("#define %s_%s_ENUM\n",
734                        interface->uppercase_name, e->uppercase_name);
735
736                 if (desc) {
737                         printf("/**\n");
738                         desc_dump(desc->summary,
739                                   " * %s_%s - ",
740                                   interface->name, e->name);
741                         wl_list_for_each(entry, &e->entry_list, link) {
742                                 desc_dump(entry->summary,
743                                           " * @%s_%s_%s: ",
744                                           interface->uppercase_name,
745                                           e->uppercase_name,
746                                           entry->uppercase_name);
747                         }
748                         if (desc->text) {
749                                 printf(" *\n");
750                                 desc_dump(desc->text, " * ");
751                         }
752                         printf(" */\n");
753                 }
754                 printf("enum %s_%s {\n", interface->name, e->name);
755                 wl_list_for_each(entry, &e->entry_list, link)
756                         printf("\t%s_%s_%s = %s,\n",
757                                interface->uppercase_name,
758                                e->uppercase_name,
759                                entry->uppercase_name, entry->value);
760                 printf("};\n");
761                 printf("#endif /* %s_%s_ENUM */\n\n",
762                        interface->uppercase_name, e->uppercase_name);
763         }
764 }
765
766 static void
767 emit_structs(struct wl_list *message_list, struct interface *interface)
768 {
769         struct message *m;
770         struct arg *a;
771         int is_interface, n;
772
773         if (wl_list_empty(message_list))
774                 return;
775
776         is_interface = message_list == &interface->request_list;
777         if (interface->description) {
778                 struct description *desc = interface->description;
779                 printf("/**\n");
780                 desc_dump(desc->summary, " * %s - ", interface->name);
781                 wl_list_for_each(m, message_list, link) {
782                         struct description *mdesc = m->description;
783                         desc_dump(mdesc ? mdesc->summary : "(none)",
784                                   " * @%s: ",
785                                   m->name);
786                 }
787                 printf(" *\n");
788                 desc_dump(desc->text, " * ");
789                 printf(" */\n");
790         }
791         printf("struct %s_%s {\n", interface->name,
792                is_interface ? "interface" : "listener");
793
794         wl_list_for_each(m, message_list, link) {
795                 struct description *mdesc = m->description;
796
797                 printf("\t/**\n");
798                 desc_dump(mdesc ? mdesc->summary : "(none)",
799                           "\t * %s - ", m->name);
800                 wl_list_for_each(a, &m->arg_list, link) {
801
802                         if (is_interface && a->type == NEW_ID &&
803                             a->interface_name == NULL)
804                                 printf("\t * @interface: name of the objects interface\n"
805                                        "\t * @version: version of the objects interface\n");
806
807
808                         desc_dump(a->summary ? a->summary : "(none)",
809                                   "\t * @%s: ", a->name);
810                 }
811                 if (mdesc) {
812                         printf("\t *\n");
813                         desc_dump(mdesc->text, "\t * ");
814                 }
815                 if (m->since > 1) {
816                         printf("\t * @since: %d\n", m->since);
817                 }
818                 printf("\t */\n");
819                 printf("\tvoid (*%s)(", m->name);
820
821                 n = strlen(m->name) + 17;
822                 if (is_interface) {
823                         printf("struct wl_client *client,\n"
824                                "%sstruct wl_resource *resource",
825                                indent(n));
826                 } else {
827                         printf("void *data,\n"),
828                         printf("%sstruct %s *%s",
829                                indent(n), interface->name, interface->name);
830                 }
831
832                 wl_list_for_each(a, &m->arg_list, link) {
833                         printf(",\n%s", indent(n));
834
835                         if (is_interface && a->type == OBJECT)
836                                 printf("struct wl_resource *");
837                         else if (is_interface && a->type == NEW_ID && a->interface_name == NULL)
838                                 printf("const char *interface, uint32_t version, uint32_t ");
839                         else if (!is_interface && a->type == OBJECT && a->interface_name == NULL)
840                                 printf("struct wl_object *");
841
842                         else if (!is_interface && a->type == NEW_ID)
843                                 printf("struct %s *", a->interface_name);
844                         else
845                                 emit_type(a);
846
847                         printf("%s", a->name);
848                 }
849
850                 printf(");\n");
851         }
852
853         printf("};\n\n");
854
855         if (!is_interface) {
856             printf("static inline int\n"
857                    "%s_add_listener(struct %s *%s,\n"
858                    "%sconst struct %s_listener *listener, void *data)\n"
859                    "{\n"
860                    "\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n"
861                    "%s(void (**)(void)) listener, data);\n"
862                    "}\n\n",
863                    interface->name, interface->name, interface->name,
864                    indent(14 + strlen(interface->name)),
865                    interface->name,
866                    interface->name,
867                    indent(37));
868         }
869 }
870
871 static void
872 format_copyright(const char *copyright)
873 {
874         int bol = 1, start = 0, i;
875
876         for (i = 0; copyright[i]; i++) {
877                 if (bol && (copyright[i] == ' ' || copyright[i] == '\t')) {
878                         continue;
879                 } else if (bol) {
880                         bol = 0;
881                         start = i;
882                 }
883
884                 if (copyright[i] == '\n' || copyright[i] == '\0') {
885                         printf("%s %.*s\n",
886                                i == 0 ? "/*" : " *",
887                                i - start, copyright + start);
888                         bol = 1;
889                 }
890         }
891         printf(" */\n\n");
892 }
893
894 static void
895 emit_header(struct protocol *protocol, int server)
896 {
897         struct interface *i;
898         const char *s = server ? "SERVER" : "CLIENT";
899
900         if (protocol->copyright)
901                 format_copyright(protocol->copyright);
902
903         printf("#ifndef %s_%s_PROTOCOL_H\n"
904                "#define %s_%s_PROTOCOL_H\n"
905                "\n"
906                "#ifdef  __cplusplus\n"
907                "extern \"C\" {\n"
908                "#endif\n"
909                "\n"
910                "#include <stdint.h>\n"
911                "#include <stddef.h>\n"
912                "#include \"%s\"\n\n"
913                "struct wl_client;\n"
914                "struct wl_resource;\n\n",
915                protocol->uppercase_name, s,
916                protocol->uppercase_name, s,
917                server ? "wayland-util.h" : "wayland-client.h");
918
919         wl_list_for_each(i, &protocol->interface_list, link)
920                 printf("struct %s;\n", i->name);
921         printf("\n");
922
923         wl_list_for_each(i, &protocol->interface_list, link) {
924                 printf("extern const struct wl_interface "
925                        "%s_interface;\n",
926                        i->name);
927         }
928         printf("\n");
929
930         wl_list_for_each(i, &protocol->interface_list, link) {
931
932                 emit_enumerations(i);
933
934                 if (server) {
935                         emit_structs(&i->request_list, i);
936                         emit_opcodes(&i->event_list, i);
937                         emit_event_wrappers(&i->event_list, i);
938                 } else {
939                         emit_structs(&i->event_list, i);
940                         emit_opcodes(&i->request_list, i);
941                         emit_stubs(&i->request_list, i);
942                 }
943         }
944
945         printf("#ifdef  __cplusplus\n"
946                "}\n"
947                "#endif\n"
948                "\n"
949                "#endif\n");
950 }
951
952 static void
953 emit_types_forward_declarations(struct protocol *protocol,
954                                 struct wl_list *message_list)
955 {
956         struct message *m;
957         struct arg *a;
958         int length;
959
960         wl_list_for_each(m, message_list, link) {
961                 length = 0;
962                 m->all_null = 1;
963                 wl_list_for_each(a, &m->arg_list, link) {
964                         length++;
965                         switch (a->type) {
966                         case NEW_ID:
967                         case OBJECT:
968                                 if (!a->interface_name)
969                                         continue;
970
971                                 m->all_null = 0;
972                                 printf("extern const struct wl_interface %s_interface;\n",
973                                        a->interface_name);
974                                 break;
975                         default:
976                                 break;
977                         }
978                 }
979
980                 if (m->all_null && length > protocol->null_run_length)
981                         protocol->null_run_length = length;
982         }
983 }
984
985 static void
986 emit_null_run(struct protocol *protocol)
987 {
988         int i;
989
990         for (i = 0; i < protocol->null_run_length; i++)
991                 printf("\tNULL,\n");
992 }
993
994 static void
995 emit_types(struct protocol *protocol, struct wl_list *message_list)
996 {
997         struct message *m;
998         struct arg *a;
999
1000         wl_list_for_each(m, message_list, link) {
1001                 if (m->all_null) {
1002                         m->type_index = 0;
1003                         continue;
1004                 }
1005
1006                 m->type_index =
1007                         protocol->null_run_length + protocol->type_index;
1008                 protocol->type_index += m->arg_count;
1009
1010                 wl_list_for_each(a, &m->arg_list, link) {
1011                         switch (a->type) {
1012                         case NEW_ID:
1013                         case OBJECT:
1014                                 if (a->interface_name)
1015                                         printf("\t&%s_interface,\n",
1016                                                a->interface_name);
1017                                 else
1018                                         printf("\tNULL,\n");
1019                                 break;
1020                         default:
1021                                 printf("\tNULL,\n");
1022                                 break;
1023                         }
1024                 }
1025         }
1026 }
1027
1028 static void
1029 emit_messages(struct wl_list *message_list,
1030               struct interface *interface, const char *suffix)
1031 {
1032         struct message *m;
1033         struct arg *a;
1034
1035         if (wl_list_empty(message_list))
1036                 return;
1037
1038         printf("static const struct wl_message "
1039                "%s_%s[] = {\n",
1040                interface->name, suffix);
1041
1042         wl_list_for_each(m, message_list, link) {
1043                 printf("\t{ \"%s\", \"", m->name);
1044                 wl_list_for_each(a, &m->arg_list, link) {
1045                         if (is_nullable_type(a) && a->nullable)
1046                                 printf("?");
1047
1048                         switch (a->type) {
1049                         default:
1050                         case INT:
1051                                 printf("i");
1052                                 break;
1053                         case NEW_ID:
1054                                 if (a->interface_name == NULL)
1055                                         printf("su");
1056                                 printf("n");
1057                                 break;
1058                         case UNSIGNED:
1059                                 printf("u");
1060                                 break;
1061                         case FIXED:
1062                                 printf("f");
1063                                 break;
1064                         case STRING:
1065                                 printf("s");
1066                                 break;
1067                         case OBJECT:
1068                                 printf("o");
1069                                 break;
1070                         case ARRAY:
1071                                 printf("a");
1072                                 break;
1073                         case FD:
1074                                 printf("h");
1075                                 break;
1076                         }
1077                 }
1078                 printf("\", types + %d },\n", m->type_index);
1079         }
1080
1081         printf("};\n\n");
1082 }
1083
1084 static void
1085 emit_code(struct protocol *protocol)
1086 {
1087         struct interface *i;
1088
1089         if (protocol->copyright)
1090                 format_copyright(protocol->copyright);
1091
1092         printf("#include <stdlib.h>\n"
1093                "#include <stdint.h>\n"
1094                "#include \"wayland-util.h\"\n\n");
1095
1096         wl_list_for_each(i, &protocol->interface_list, link) {
1097                 emit_types_forward_declarations(protocol, &i->request_list);
1098                 emit_types_forward_declarations(protocol, &i->event_list);
1099         }
1100         printf("\n");
1101
1102         printf("static const struct wl_interface *types[] = {\n");
1103         emit_null_run(protocol);
1104         wl_list_for_each(i, &protocol->interface_list, link) {
1105                 emit_types(protocol, &i->request_list);
1106                 emit_types(protocol, &i->event_list);
1107         }
1108         printf("};\n\n");
1109
1110         wl_list_for_each(i, &protocol->interface_list, link) {
1111
1112                 emit_messages(&i->request_list, i, "requests");
1113                 emit_messages(&i->event_list, i, "events");
1114
1115                 printf("WL_EXPORT const struct wl_interface "
1116                        "%s_interface = {\n"
1117                        "\t\"%s\", %d,\n",
1118                        i->name, i->name, i->version);
1119
1120                 if (!wl_list_empty(&i->request_list))
1121                         printf("\t%d, %s_requests,\n",
1122                                list_length(&i->request_list), i->name);
1123                 else
1124                         printf("\t0, NULL,\n");
1125
1126                 if (!wl_list_empty(&i->event_list))
1127                         printf("\t%d, %s_events,\n",
1128                                list_length(&i->event_list), i->name);
1129                 else
1130                         printf("\t0, NULL,\n");
1131
1132                 printf("};\n\n");
1133         }
1134 }
1135
1136 int main(int argc, char *argv[])
1137 {
1138         struct parse_context ctx;
1139         struct protocol protocol;
1140         int len;
1141         void *buf;
1142
1143         if (argc != 2)
1144                 usage(EXIT_FAILURE);
1145
1146         wl_list_init(&protocol.interface_list);
1147         protocol.type_index = 0;
1148         protocol.null_run_length = 0;
1149         protocol.copyright = NULL;
1150         ctx.protocol = &protocol;
1151
1152         ctx.filename = "<stdin>";
1153         ctx.parser = XML_ParserCreate(NULL);
1154         XML_SetUserData(ctx.parser, &ctx);
1155         if (ctx.parser == NULL) {
1156                 fprintf(stderr, "failed to create parser\n");
1157                 exit(EXIT_FAILURE);
1158         }
1159
1160         XML_SetElementHandler(ctx.parser, start_element, end_element);
1161         XML_SetCharacterDataHandler(ctx.parser, character_data);
1162
1163         do {
1164                 buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
1165                 len = fread(buf, 1, XML_BUFFER_SIZE, stdin);
1166                 if (len < 0) {
1167                         fprintf(stderr, "fread: %m\n");
1168                         exit(EXIT_FAILURE);
1169                 }
1170                 XML_ParseBuffer(ctx.parser, len, len == 0);
1171
1172         } while (len > 0);
1173
1174         XML_ParserFree(ctx.parser);
1175
1176         if (strcmp(argv[1], "client-header") == 0) {
1177                 emit_header(&protocol, 0);
1178         } else if (strcmp(argv[1], "server-header") == 0) {
1179                 emit_header(&protocol, 1);
1180         } else if (strcmp(argv[1], "code") == 0) {
1181                 emit_code(&protocol);
1182         }
1183
1184         return 0;
1185 }