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