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