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