1 /*
2 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
4 * Copyright © 2015 Red Hat, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 */
27
28 #include "config.h"
29 #include "wayland-version.h"
30
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <stdarg.h>
34 #include <stdint.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <ctype.h>
38 #include <expat.h>
39 #include <getopt.h>
40 #include <limits.h>
41 #include <unistd.h>
42
43 #if HAVE_LIBXML
44 #include <libxml/parser.h>
45
46 /* Embedded wayland.dtd file, see dtddata.S */
47 extern char DTD_DATA_begin;
48 extern int DTD_DATA_len;
49 #endif
50
51 #include "wayland-util.h"
52
53 #define PROGRAM_NAME "wayland-scanner"
54
55 enum side {
56 CLIENT,
57 SERVER,
58 };
59
60 static int
usage(int ret)61 usage(int ret)
62 {
63 fprintf(stderr, "usage: %s [OPTION] [client-header|server-header|code]"
64 " [input_file output_file]\n", PROGRAM_NAME);
65 fprintf(stderr, "\n");
66 fprintf(stderr, "Converts XML protocol descriptions supplied on "
67 "stdin or input file to client\n"
68 "headers, server headers, or protocol marshalling code.\n\n");
69 fprintf(stderr, "options:\n");
70 fprintf(stderr, " -h, --help display this help and exit.\n"
71 " -v, --version print the wayland library version that\n"
72 " the scanner was built against.\n"
73 " -c, --include-core-only include the core version of the headers,\n"
74 " that is e.g. wayland-client-core.h instead\n"
75 " of wayland-client.h.\n");
76 exit(ret);
77 }
78
79 static int
scanner_version(int ret)80 scanner_version(int ret)
81 {
82 fprintf(stderr, "%s %s\n", PROGRAM_NAME, WAYLAND_VERSION);
83 exit(ret);
84 }
85
86 static bool
is_dtd_valid(FILE * input,const char * filename)87 is_dtd_valid(FILE *input, const char *filename)
88 {
89 bool rc = true;
90 #if HAVE_LIBXML
91 xmlParserCtxtPtr ctx = NULL;
92 xmlDocPtr doc = NULL;
93 xmlDtdPtr dtd = NULL;
94 xmlValidCtxtPtr dtdctx;
95 xmlParserInputBufferPtr buffer;
96 int fd = fileno(input);
97
98 dtdctx = xmlNewValidCtxt();
99 ctx = xmlNewParserCtxt();
100 if (!ctx || !dtdctx)
101 abort();
102
103 buffer = xmlParserInputBufferCreateMem(&DTD_DATA_begin,
104 DTD_DATA_len,
105 XML_CHAR_ENCODING_UTF8);
106 if (!buffer) {
107 fprintf(stderr, "Failed to init buffer for DTD.\n");
108 abort();
109 }
110
111 dtd = xmlIOParseDTD(NULL, buffer, XML_CHAR_ENCODING_UTF8);
112 if (!dtd) {
113 fprintf(stderr, "Failed to parse DTD.\n");
114 abort();
115 }
116
117 doc = xmlCtxtReadFd(ctx, fd, filename, NULL, 0);
118 if (!doc) {
119 fprintf(stderr, "Failed to read XML\n");
120 abort();
121 }
122
123 rc = xmlValidateDtd(dtdctx, doc, dtd);
124 xmlFreeDoc(doc);
125 xmlFreeParserCtxt(ctx);
126 xmlFreeValidCtxt(dtdctx);
127 /* xmlIOParseDTD consumes buffer */
128
129 if (lseek(fd, 0, SEEK_SET) != 0) {
130 fprintf(stderr, "Failed to reset fd, output would be garbage.\n");
131 abort();
132 }
133 #endif
134 return rc;
135 }
136
137 #define XML_BUFFER_SIZE 4096
138
139 struct location {
140 const char *filename;
141 int line_number;
142 };
143
144 struct description {
145 char *summary;
146 char *text;
147 };
148
149 struct protocol {
150 char *name;
151 char *uppercase_name;
152 struct wl_list interface_list;
153 int type_index;
154 int null_run_length;
155 char *copyright;
156 struct description *description;
157 bool core_headers;
158 };
159
160 struct interface {
161 struct location loc;
162 char *name;
163 char *uppercase_name;
164 int version;
165 int since;
166 struct wl_list request_list;
167 struct wl_list event_list;
168 struct wl_list enumeration_list;
169 struct wl_list link;
170 struct description *description;
171 };
172
173 struct message {
174 struct location loc;
175 char *name;
176 char *uppercase_name;
177 struct wl_list arg_list;
178 struct wl_list link;
179 int arg_count;
180 int new_id_count;
181 int type_index;
182 int all_null;
183 int destructor;
184 int since;
185 struct description *description;
186 };
187
188 enum arg_type {
189 NEW_ID,
190 INT,
191 UNSIGNED,
192 FIXED,
193 STRING,
194 OBJECT,
195 ARRAY,
196 FD
197 };
198
199 struct arg {
200 char *name;
201 enum arg_type type;
202 int nullable;
203 char *interface_name;
204 struct wl_list link;
205 char *summary;
206 char *enumeration_name;
207 };
208
209 struct enumeration {
210 char *name;
211 char *uppercase_name;
212 struct wl_list entry_list;
213 struct wl_list link;
214 struct description *description;
215 bool bitfield;
216 };
217
218 struct entry {
219 char *name;
220 char *uppercase_name;
221 char *value;
222 char *summary;
223 struct wl_list link;
224 };
225
226 struct parse_context {
227 struct location loc;
228 XML_Parser parser;
229 struct protocol *protocol;
230 struct interface *interface;
231 struct message *message;
232 struct enumeration *enumeration;
233 struct description *description;
234 char character_data[8192];
235 unsigned int character_data_length;
236 };
237
238 static void *
fail_on_null(void * p)239 fail_on_null(void *p)
240 {
241 if (p == NULL) {
242 fprintf(stderr, "%s: out of memory\n", PROGRAM_NAME);
243 exit(EXIT_FAILURE);
244 }
245
246 return p;
247 }
248
249 static void *
zalloc(size_t s)250 zalloc(size_t s)
251 {
252 return calloc(s, 1);
253 }
254
255 static void *
xzalloc(size_t s)256 xzalloc(size_t s)
257 {
258 return fail_on_null(zalloc(s));
259 }
260
261 static char *
xstrdup(const char * s)262 xstrdup(const char *s)
263 {
264 return fail_on_null(strdup(s));
265 }
266
267 static char *
uppercase_dup(const char * src)268 uppercase_dup(const char *src)
269 {
270 char *u;
271 int i;
272
273 u = xstrdup(src);
274 for (i = 0; u[i]; i++)
275 u[i] = toupper(u[i]);
276 u[i] = '\0';
277
278 return u;
279 }
280
indent(int n)281 static const char *indent(int n)
282 {
283 const char *whitespace[] = {
284 "\t\t\t\t\t\t\t\t\t\t\t\t",
285 "\t\t\t\t\t\t\t\t\t\t\t\t ",
286 "\t\t\t\t\t\t\t\t\t\t\t\t ",
287 "\t\t\t\t\t\t\t\t\t\t\t\t ",
288 "\t\t\t\t\t\t\t\t\t\t\t\t ",
289 "\t\t\t\t\t\t\t\t\t\t\t\t ",
290 "\t\t\t\t\t\t\t\t\t\t\t\t ",
291 "\t\t\t\t\t\t\t\t\t\t\t\t "
292 };
293
294 return whitespace[n % 8] + 12 - n / 8;
295 }
296
297 static void
298 desc_dump(char *desc, const char *fmt, ...) WL_PRINTF(2, 3);
299
300 static void
desc_dump(char * desc,const char * fmt,...)301 desc_dump(char *desc, const char *fmt, ...)
302 {
303 va_list ap;
304 char buf[128], hang;
305 int col, i, j, k, startcol, newlines;
306
307 va_start(ap, fmt);
308 vsnprintf(buf, sizeof buf, fmt, ap);
309 va_end(ap);
310
311 for (i = 0, col = 0; buf[i] != '*'; i++) {
312 if (buf[i] == '\t')
313 col = (col + 8) & ~7;
314 else
315 col++;
316 }
317
318 printf("%s", buf);
319
320 if (!desc) {
321 printf("(none)\n");
322 return;
323 }
324
325 startcol = col;
326 col += strlen(&buf[i]);
327 if (col - startcol > 2)
328 hang = '\t';
329 else
330 hang = ' ';
331
332 for (i = 0; desc[i]; ) {
333 k = i;
334 newlines = 0;
335 while (desc[i] && isspace(desc[i])) {
336 if (desc[i] == '\n')
337 newlines++;
338 i++;
339 }
340 if (!desc[i])
341 break;
342
343 j = i;
344 while (desc[i] && !isspace(desc[i]))
345 i++;
346
347 if (newlines > 1)
348 printf("\n%s*", indent(startcol));
349 if (newlines > 1 || col + i - j > 72) {
350 printf("\n%s*%c", indent(startcol), hang);
351 col = startcol;
352 }
353
354 if (col > startcol && k > 0)
355 col += printf(" ");
356 col += printf("%.*s", i - j, &desc[j]);
357 }
358 putchar('\n');
359 }
360
361 static void
fail(struct location * loc,const char * msg,...)362 fail(struct location *loc, const char *msg, ...)
363 {
364 va_list ap;
365
366 va_start(ap, msg);
367 fprintf(stderr, "%s:%d: error: ",
368 loc->filename, loc->line_number);
369 vfprintf(stderr, msg, ap);
370 fprintf(stderr, "\n");
371 va_end(ap);
372 exit(EXIT_FAILURE);
373 }
374
375 static void
warn(struct location * loc,const char * msg,...)376 warn(struct location *loc, const char *msg, ...)
377 {
378 va_list ap;
379
380 va_start(ap, msg);
381 fprintf(stderr, "%s:%d: warning: ",
382 loc->filename, loc->line_number);
383 vfprintf(stderr, msg, ap);
384 fprintf(stderr, "\n");
385 va_end(ap);
386 }
387
388 static bool
is_nullable_type(struct arg * arg)389 is_nullable_type(struct arg *arg)
390 {
391 switch (arg->type) {
392 /* Strings, objects, and arrays are possibly nullable */
393 case STRING:
394 case OBJECT:
395 case NEW_ID:
396 case ARRAY:
397 return true;
398 default:
399 return false;
400 }
401 }
402
403 static struct message *
create_message(struct location loc,const char * name)404 create_message(struct location loc, const char *name)
405 {
406 struct message *message;
407
408 message = xzalloc(sizeof *message);
409 message->loc = loc;
410 message->name = xstrdup(name);
411 message->uppercase_name = uppercase_dup(name);
412 wl_list_init(&message->arg_list);
413
414 return message;
415 }
416
417 static void
free_arg(struct arg * arg)418 free_arg(struct arg *arg)
419 {
420 free(arg->name);
421 free(arg->interface_name);
422 free(arg->summary);
423 free(arg);
424 }
425
426 static struct arg *
create_arg(const char * name)427 create_arg(const char *name)
428 {
429 struct arg *arg;
430
431 arg = xzalloc(sizeof *arg);
432 arg->name = xstrdup(name);
433
434 return arg;
435 }
436
437 static bool
set_arg_type(struct arg * arg,const char * type)438 set_arg_type(struct arg *arg, const char *type)
439 {
440 if (strcmp(type, "int") == 0)
441 arg->type = INT;
442 else if (strcmp(type, "uint") == 0)
443 arg->type = UNSIGNED;
444 else if (strcmp(type, "fixed") == 0)
445 arg->type = FIXED;
446 else if (strcmp(type, "string") == 0)
447 arg->type = STRING;
448 else if (strcmp(type, "array") == 0)
449 arg->type = ARRAY;
450 else if (strcmp(type, "fd") == 0)
451 arg->type = FD;
452 else if (strcmp(type, "new_id") == 0)
453 arg->type = NEW_ID;
454 else if (strcmp(type, "object") == 0)
455 arg->type = OBJECT;
456 else
457 return false;
458
459 return true;
460 }
461
462 static void
free_description(struct description * desc)463 free_description(struct description *desc)
464 {
465 if (!desc)
466 return;
467
468 free(desc->summary);
469 free(desc->text);
470
471 free(desc);
472 }
473
474 static void
free_message(struct message * message)475 free_message(struct message *message)
476 {
477 struct arg *a, *a_next;
478
479 free(message->name);
480 free(message->uppercase_name);
481 free_description(message->description);
482
483 wl_list_for_each_safe(a, a_next, &message->arg_list, link)
484 free_arg(a);
485
486 free(message);
487 }
488
489 static struct enumeration *
create_enumeration(const char * name)490 create_enumeration(const char *name)
491 {
492 struct enumeration *enumeration;
493
494 enumeration = xzalloc(sizeof *enumeration);
495 enumeration->name = xstrdup(name);
496 enumeration->uppercase_name = uppercase_dup(name);
497
498 wl_list_init(&enumeration->entry_list);
499
500 return enumeration;
501 }
502
503 static struct entry *
create_entry(const char * name,const char * value)504 create_entry(const char *name, const char *value)
505 {
506 struct entry *entry;
507
508 entry = xzalloc(sizeof *entry);
509 entry->name = xstrdup(name);
510 entry->uppercase_name = uppercase_dup(name);
511 entry->value = xstrdup(value);
512
513 return entry;
514 }
515
516 static void
free_entry(struct entry * entry)517 free_entry(struct entry *entry)
518 {
519 free(entry->name);
520 free(entry->uppercase_name);
521 free(entry->value);
522 free(entry->summary);
523
524 free(entry);
525 }
526
527 static void
free_enumeration(struct enumeration * enumeration)528 free_enumeration(struct enumeration *enumeration)
529 {
530 struct entry *e, *e_next;
531
532 free(enumeration->name);
533 free(enumeration->uppercase_name);
534 free_description(enumeration->description);
535
536 wl_list_for_each_safe(e, e_next, &enumeration->entry_list, link)
537 free_entry(e);
538
539 free(enumeration);
540 }
541
542 static struct interface *
create_interface(struct location loc,const char * name,int version)543 create_interface(struct location loc, const char *name, int version)
544 {
545 struct interface *interface;
546
547 interface = xzalloc(sizeof *interface);
548 interface->loc = loc;
549 interface->name = xstrdup(name);
550 interface->uppercase_name = uppercase_dup(name);
551 interface->version = version;
552 interface->since = 1;
553 wl_list_init(&interface->request_list);
554 wl_list_init(&interface->event_list);
555 wl_list_init(&interface->enumeration_list);
556
557 return interface;
558 }
559
560 static void
free_interface(struct interface * interface)561 free_interface(struct interface *interface)
562 {
563 struct message *m, *next_m;
564 struct enumeration *e, *next_e;
565
566 free(interface->name);
567 free(interface->uppercase_name);
568 free_description(interface->description);
569
570 wl_list_for_each_safe(m, next_m, &interface->request_list, link)
571 free_message(m);
572 wl_list_for_each_safe(m, next_m, &interface->event_list, link)
573 free_message(m);
574 wl_list_for_each_safe(e, next_e, &interface->enumeration_list, link)
575 free_enumeration(e);
576
577 free(interface);
578 }
579
580 /* Convert string to unsigned integer
581 *
582 * Parses a non-negative base-10 number from the given string. If the
583 * specified string is blank, contains non-numerical characters, is out
584 * of range, or results in a negative number, -1 is returned to indicate
585 * an error.
586 *
587 * Upon error, this routine does not modify or set errno.
588 *
589 * Returns -1 on error, or a non-negative integer on success
590 */
591 static int
strtouint(const char * str)592 strtouint(const char *str)
593 {
594 long int ret;
595 char *end;
596 int prev_errno = errno;
597
598 errno = 0;
599 ret = strtol(str, &end, 10);
600 if (errno != 0 || end == str || *end != '\0')
601 return -1;
602
603 /* check range */
604 if (ret < 0 || ret > INT_MAX) {
605 return -1;
606 }
607
608 errno = prev_errno;
609 return (int)ret;
610 }
611
612 static void
start_element(void * data,const char * element_name,const char ** atts)613 start_element(void *data, const char *element_name, const char **atts)
614 {
615 struct parse_context *ctx = data;
616 struct interface *interface;
617 struct message *message;
618 struct arg *arg;
619 struct enumeration *enumeration;
620 struct entry *entry;
621 struct description *description = NULL;
622 const char *name = NULL;
623 const char *type = NULL;
624 const char *interface_name = NULL;
625 const char *value = NULL;
626 const char *summary = NULL;
627 const char *since = NULL;
628 const char *allow_null = NULL;
629 const char *enumeration_name = NULL;
630 const char *bitfield = NULL;
631 int i, version = 0;
632
633 ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser);
634 for (i = 0; atts[i]; i += 2) {
635 if (strcmp(atts[i], "name") == 0)
636 name = atts[i + 1];
637 if (strcmp(atts[i], "version") == 0) {
638 version = strtouint(atts[i + 1]);
639 if (version == -1)
640 fail(&ctx->loc, "wrong version (%s)", atts[i + 1]);
641 }
642 if (strcmp(atts[i], "type") == 0)
643 type = atts[i + 1];
644 if (strcmp(atts[i], "value") == 0)
645 value = atts[i + 1];
646 if (strcmp(atts[i], "interface") == 0)
647 interface_name = atts[i + 1];
648 if (strcmp(atts[i], "summary") == 0)
649 summary = atts[i + 1];
650 if (strcmp(atts[i], "since") == 0)
651 since = atts[i + 1];
652 if (strcmp(atts[i], "allow-null") == 0)
653 allow_null = atts[i + 1];
654 if (strcmp(atts[i], "enum") == 0)
655 enumeration_name = atts[i + 1];
656 if (strcmp(atts[i], "bitfield") == 0)
657 bitfield = atts[i + 1];
658 }
659
660 ctx->character_data_length = 0;
661 if (strcmp(element_name, "protocol") == 0) {
662 if (name == NULL)
663 fail(&ctx->loc, "no protocol name given");
664
665 ctx->protocol->name = xstrdup(name);
666 ctx->protocol->uppercase_name = uppercase_dup(name);
667 } else if (strcmp(element_name, "copyright") == 0) {
668
669 } else if (strcmp(element_name, "interface") == 0) {
670 if (name == NULL)
671 fail(&ctx->loc, "no interface name given");
672
673 if (version == 0)
674 fail(&ctx->loc, "no interface version given");
675
676 interface = create_interface(ctx->loc, name, version);
677 ctx->interface = interface;
678 wl_list_insert(ctx->protocol->interface_list.prev,
679 &interface->link);
680 } else if (strcmp(element_name, "request") == 0 ||
681 strcmp(element_name, "event") == 0) {
682 if (name == NULL)
683 fail(&ctx->loc, "no request name given");
684
685 message = create_message(ctx->loc, name);
686
687 if (strcmp(element_name, "request") == 0)
688 wl_list_insert(ctx->interface->request_list.prev,
689 &message->link);
690 else
691 wl_list_insert(ctx->interface->event_list.prev,
692 &message->link);
693
694 if (type != NULL && strcmp(type, "destructor") == 0)
695 message->destructor = 1;
696
697 if (since != NULL) {
698 version = strtouint(since);
699 if (version == -1) {
700 fail(&ctx->loc, "invalid integer (%s)\n", since);
701 } else if (version > ctx->interface->version) {
702 fail(&ctx->loc, "since (%u) larger than version (%u)\n",
703 version, ctx->interface->version);
704 }
705 } else {
706 version = 1;
707 }
708
709 if (version < ctx->interface->since)
710 warn(&ctx->loc, "since version not increasing\n");
711 ctx->interface->since = version;
712 message->since = version;
713
714 if (strcmp(name, "destroy") == 0 && !message->destructor)
715 fail(&ctx->loc, "destroy request should be destructor type");
716
717 ctx->message = message;
718 } else if (strcmp(element_name, "arg") == 0) {
719 if (name == NULL)
720 fail(&ctx->loc, "no argument name given");
721
722 arg = create_arg(name);
723 if (!set_arg_type(arg, type))
724 fail(&ctx->loc, "unknown type (%s)", type);
725
726 switch (arg->type) {
727 case NEW_ID:
728 ctx->message->new_id_count++;
729
730 /* Fall through to OBJECT case. */
731
732 case OBJECT:
733 if (interface_name)
734 arg->interface_name = xstrdup(interface_name);
735 break;
736 default:
737 if (interface_name != NULL)
738 fail(&ctx->loc, "interface attribute not allowed for type %s", type);
739 break;
740 }
741
742 if (allow_null) {
743 if (strcmp(allow_null, "true") == 0)
744 arg->nullable = 1;
745 else if (strcmp(allow_null, "false") != 0)
746 fail(&ctx->loc,
747 "invalid value for allow-null attribute (%s)",
748 allow_null);
749
750 if (!is_nullable_type(arg))
751 fail(&ctx->loc,
752 "allow-null is only valid for objects, strings, and arrays");
753 }
754
755 if (enumeration_name == NULL || strcmp(enumeration_name, "") == 0)
756 arg->enumeration_name = NULL;
757 else
758 arg->enumeration_name = xstrdup(enumeration_name);
759
760 if (summary)
761 arg->summary = xstrdup(summary);
762
763 wl_list_insert(ctx->message->arg_list.prev, &arg->link);
764 ctx->message->arg_count++;
765 } else if (strcmp(element_name, "enum") == 0) {
766 if (name == NULL)
767 fail(&ctx->loc, "no enum name given");
768
769 enumeration = create_enumeration(name);
770
771 if (bitfield == NULL || strcmp(bitfield, "false") == 0)
772 enumeration->bitfield = false;
773 else if (strcmp(bitfield, "true") == 0)
774 enumeration->bitfield = true;
775 else
776 fail(&ctx->loc,
777 "invalid value (%s) for bitfield attribute (only true/false are accepted)",
778 bitfield);
779
780 wl_list_insert(ctx->interface->enumeration_list.prev,
781 &enumeration->link);
782
783 ctx->enumeration = enumeration;
784 } else if (strcmp(element_name, "entry") == 0) {
785 if (name == NULL)
786 fail(&ctx->loc, "no entry name given");
787
788 entry = create_entry(name, value);
789
790 if (summary)
791 entry->summary = xstrdup(summary);
792 else
793 entry->summary = NULL;
794 wl_list_insert(ctx->enumeration->entry_list.prev,
795 &entry->link);
796 } else if (strcmp(element_name, "description") == 0) {
797 if (summary == NULL)
798 fail(&ctx->loc, "description without summary");
799
800 description = xzalloc(sizeof *description);
801 description->summary = xstrdup(summary);
802
803 if (ctx->message)
804 ctx->message->description = description;
805 else if (ctx->enumeration)
806 ctx->enumeration->description = description;
807 else if (ctx->interface)
808 ctx->interface->description = description;
809 else
810 ctx->protocol->description = description;
811 ctx->description = description;
812 }
813 }
814
815 static struct enumeration *
find_enumeration(struct protocol * protocol,struct interface * interface,char * enum_attribute)816 find_enumeration(struct protocol *protocol,
817 struct interface *interface,
818 char *enum_attribute)
819 {
820 struct interface *i;
821 struct enumeration *e;
822 char *enum_name;
823 uint32_t idx = 0, j;
824
825 for (j = 0; j + 1 < strlen(enum_attribute); j++) {
826 if (enum_attribute[j] == '.') {
827 idx = j;
828 }
829 }
830
831 if (idx > 0) {
832 enum_name = enum_attribute + idx + 1;
833
834 wl_list_for_each(i, &protocol->interface_list, link)
835 if (strncmp(i->name, enum_attribute, idx) == 0)
836 wl_list_for_each(e, &i->enumeration_list, link)
837 if (strcmp(e->name, enum_name) == 0)
838 return e;
839 } else if (interface) {
840 enum_name = enum_attribute;
841
842 wl_list_for_each(e, &interface->enumeration_list, link)
843 if (strcmp(e->name, enum_name) == 0)
844 return e;
845 }
846
847 return NULL;
848 }
849
850 static void
verify_arguments(struct parse_context * ctx,struct interface * interface,struct wl_list * messages,struct wl_list * enumerations)851 verify_arguments(struct parse_context *ctx,
852 struct interface *interface,
853 struct wl_list *messages,
854 struct wl_list *enumerations)
855 {
856 struct message *m;
857 wl_list_for_each(m, messages, link) {
858 struct arg *a;
859 wl_list_for_each(a, &m->arg_list, link) {
860 struct enumeration *e;
861
862 if (!a->enumeration_name)
863 continue;
864
865
866 e = find_enumeration(ctx->protocol, interface,
867 a->enumeration_name);
868
869 if (e == NULL)
870 fail(&ctx->loc,
871 "could not find enumeration %s",
872 a->enumeration_name);
873
874 switch (a->type) {
875 case INT:
876 if (e->bitfield)
877 fail(&ctx->loc,
878 "bitfield-style enum must only be referenced by uint");
879 break;
880 case UNSIGNED:
881 break;
882 default:
883 fail(&ctx->loc,
884 "enumeration-style argument has wrong type");
885 }
886 }
887 }
888
889 }
890
891 static void
end_element(void * data,const XML_Char * name)892 end_element(void *data, const XML_Char *name)
893 {
894 struct parse_context *ctx = data;
895
896 if (strcmp(name, "copyright") == 0) {
897 ctx->protocol->copyright =
898 strndup(ctx->character_data,
899 ctx->character_data_length);
900 } else if (strcmp(name, "description") == 0) {
901 ctx->description->text =
902 strndup(ctx->character_data,
903 ctx->character_data_length);
904 ctx->description = NULL;
905 } else if (strcmp(name, "request") == 0 ||
906 strcmp(name, "event") == 0) {
907 ctx->message = NULL;
908 } else if (strcmp(name, "enum") == 0) {
909 if (wl_list_empty(&ctx->enumeration->entry_list)) {
910 fail(&ctx->loc, "enumeration %s was empty",
911 ctx->enumeration->name);
912 }
913 ctx->enumeration = NULL;
914 } else if (strcmp(name, "protocol") == 0) {
915 struct interface *i;
916
917 wl_list_for_each(i, &ctx->protocol->interface_list, link) {
918 verify_arguments(ctx, i, &i->request_list, &i->enumeration_list);
919 verify_arguments(ctx, i, &i->event_list, &i->enumeration_list);
920 }
921 }
922 }
923
924 static void
character_data(void * data,const XML_Char * s,int len)925 character_data(void *data, const XML_Char *s, int len)
926 {
927 struct parse_context *ctx = data;
928
929 if (ctx->character_data_length + len > sizeof (ctx->character_data)) {
930 fprintf(stderr, "too much character data");
931 exit(EXIT_FAILURE);
932 }
933
934 memcpy(ctx->character_data + ctx->character_data_length, s, len);
935 ctx->character_data_length += len;
936 }
937
938 static void
format_text_to_comment(const char * text,bool standalone_comment)939 format_text_to_comment(const char *text, bool standalone_comment)
940 {
941 int bol = 1, start = 0, i, length;
942 bool comment_started = !standalone_comment;
943
944 length = strlen(text);
945 for (i = 0; i <= length; i++) {
946 if (bol && (text[i] == ' ' || text[i] == '\t')) {
947 continue;
948 } else if (bol) {
949 bol = 0;
950 start = i;
951 }
952 if (text[i] == '\n' ||
953 (text[i] == '\0' && !(start == i))) {
954 printf("%s%s%.*s\n",
955 comment_started ? " *" : "/*",
956 i > start ? " " : "",
957 i - start, text + start);
958 bol = 1;
959 comment_started = true;
960 }
961 }
962 if (comment_started && standalone_comment)
963 printf(" */\n\n");
964 }
965
966 static void
emit_opcodes(struct wl_list * message_list,struct interface * interface)967 emit_opcodes(struct wl_list *message_list, struct interface *interface)
968 {
969 struct message *m;
970 int opcode;
971
972 if (wl_list_empty(message_list))
973 return;
974
975 opcode = 0;
976 wl_list_for_each(m, message_list, link)
977 printf("#define %s_%s %d\n",
978 interface->uppercase_name, m->uppercase_name, opcode++);
979
980 printf("\n");
981 }
982
983 static void
emit_opcode_versions(struct wl_list * message_list,struct interface * interface)984 emit_opcode_versions(struct wl_list *message_list, struct interface *interface)
985 {
986 struct message *m;
987
988 wl_list_for_each(m, message_list, link) {
989 printf("/**\n * @ingroup iface_%s\n */\n", interface->name);
990 printf("#define %s_%s_SINCE_VERSION %d\n",
991 interface->uppercase_name, m->uppercase_name, m->since);
992 }
993
994 printf("\n");
995 }
996
997 static void
emit_type(struct arg * a)998 emit_type(struct arg *a)
999 {
1000 switch (a->type) {
1001 default:
1002 case INT:
1003 case FD:
1004 printf("int32_t ");
1005 break;
1006 case NEW_ID:
1007 case UNSIGNED:
1008 printf("uint32_t ");
1009 break;
1010 case FIXED:
1011 printf("wl_fixed_t ");
1012 break;
1013 case STRING:
1014 printf("const char *");
1015 break;
1016 case OBJECT:
1017 printf("struct %s *", a->interface_name);
1018 break;
1019 case ARRAY:
1020 printf("struct wl_array *");
1021 break;
1022 }
1023 }
1024
1025 static void
emit_stubs(struct wl_list * message_list,struct interface * interface)1026 emit_stubs(struct wl_list *message_list, struct interface *interface)
1027 {
1028 struct message *m;
1029 struct arg *a, *ret;
1030 int has_destructor, has_destroy;
1031
1032 printf("/** @ingroup iface_%s */\n", interface->name);
1033 printf("static inline void\n"
1034 "%s_set_user_data(struct %s *%s, void *user_data)\n"
1035 "{\n"
1036 "\twl_proxy_set_user_data((struct wl_proxy *) %s, user_data);\n"
1037 "}\n\n",
1038 interface->name, interface->name, interface->name,
1039 interface->name);
1040
1041 printf("/** @ingroup iface_%s */\n", interface->name);
1042 printf("static inline void *\n"
1043 "%s_get_user_data(struct %s *%s)\n"
1044 "{\n"
1045 "\treturn wl_proxy_get_user_data((struct wl_proxy *) %s);\n"
1046 "}\n\n",
1047 interface->name, interface->name, interface->name,
1048 interface->name);
1049
1050 printf("static inline uint32_t\n"
1051 "%s_get_version(struct %s *%s)\n"
1052 "{\n"
1053 "\treturn wl_proxy_get_version((struct wl_proxy *) %s);\n"
1054 "}\n\n",
1055 interface->name, interface->name, interface->name,
1056 interface->name);
1057
1058 has_destructor = 0;
1059 has_destroy = 0;
1060 wl_list_for_each(m, message_list, link) {
1061 if (m->destructor)
1062 has_destructor = 1;
1063 if (strcmp(m->name, "destroy") == 0)
1064 has_destroy = 1;
1065 }
1066
1067 if (!has_destructor && has_destroy) {
1068 fail(&interface->loc,
1069 "interface '%s' has method named destroy "
1070 "but no destructor",
1071 interface->name);
1072 exit(EXIT_FAILURE);
1073 }
1074
1075 if (!has_destroy && strcmp(interface->name, "wl_display") != 0) {
1076 printf("/** @ingroup iface_%s */\n", interface->name);
1077 printf("static inline void\n"
1078 "%s_destroy(struct %s *%s)\n"
1079 "{\n"
1080 "\twl_proxy_destroy("
1081 "(struct wl_proxy *) %s);\n"
1082 "}\n\n",
1083 interface->name, interface->name, interface->name,
1084 interface->name);
1085 }
1086
1087 if (wl_list_empty(message_list))
1088 return;
1089
1090 wl_list_for_each(m, message_list, link) {
1091 if (m->new_id_count > 1) {
1092 warn(&m->loc,
1093 "request '%s::%s' has more than "
1094 "one new_id arg, not emitting stub\n",
1095 interface->name, m->name);
1096 continue;
1097 }
1098
1099 ret = NULL;
1100 wl_list_for_each(a, &m->arg_list, link) {
1101 if (a->type == NEW_ID)
1102 ret = a;
1103 }
1104
1105 printf("/**\n"
1106 " * @ingroup iface_%s\n", interface->name);
1107 if (m->description && m->description->text)
1108 format_text_to_comment(m->description->text, false);
1109 printf(" */\n");
1110 if (ret && ret->interface_name == NULL)
1111 printf("static inline void *\n");
1112 else if (ret)
1113 printf("static inline struct %s *\n",
1114 ret->interface_name);
1115 else
1116 printf("static inline void\n");
1117
1118 printf("%s_%s(struct %s *%s",
1119 interface->name, m->name,
1120 interface->name, interface->name);
1121
1122 wl_list_for_each(a, &m->arg_list, link) {
1123 if (a->type == NEW_ID && a->interface_name == NULL) {
1124 printf(", const struct wl_interface *interface"
1125 ", uint32_t version");
1126 continue;
1127 } else if (a->type == NEW_ID)
1128 continue;
1129 printf(", ");
1130 emit_type(a);
1131 printf("%s", a->name);
1132 }
1133
1134 printf(")\n"
1135 "{\n");
1136 if (ret && ret->interface_name == NULL) {
1137 /* an arg has type ="new_id" but interface is not
1138 * provided, such as in wl_registry.bind */
1139 printf("\tstruct wl_proxy *%s;\n\n"
1140 "\t%s = wl_proxy_marshal_constructor_versioned("
1141 "(struct wl_proxy *) %s,\n"
1142 "\t\t\t %s_%s, interface, version",
1143 ret->name, ret->name,
1144 interface->name,
1145 interface->uppercase_name,
1146 m->uppercase_name);
1147 } else if (ret) {
1148 /* Normal factory case, an arg has type="new_id" and
1149 * an interface is provided */
1150 printf("\tstruct wl_proxy *%s;\n\n"
1151 "\t%s = wl_proxy_marshal_constructor("
1152 "(struct wl_proxy *) %s,\n"
1153 "\t\t\t %s_%s, &%s_interface",
1154 ret->name, ret->name,
1155 interface->name,
1156 interface->uppercase_name,
1157 m->uppercase_name,
1158 ret->interface_name);
1159 } else {
1160 /* No args have type="new_id" */
1161 printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
1162 "\t\t\t %s_%s",
1163 interface->name,
1164 interface->uppercase_name,
1165 m->uppercase_name);
1166 }
1167
1168 wl_list_for_each(a, &m->arg_list, link) {
1169 if (a->type == NEW_ID) {
1170 if (a->interface_name == NULL)
1171 printf(", interface->name, version");
1172 printf(", NULL");
1173 } else {
1174 printf(", %s", a->name);
1175 }
1176 }
1177 printf(");\n");
1178
1179 if (m->destructor)
1180 printf("\n\twl_proxy_destroy("
1181 "(struct wl_proxy *) %s);\n",
1182 interface->name);
1183
1184 if (ret && ret->interface_name == NULL)
1185 printf("\n\treturn (void *) %s;\n", ret->name);
1186 else if (ret)
1187 printf("\n\treturn (struct %s *) %s;\n",
1188 ret->interface_name, ret->name);
1189
1190 printf("}\n\n");
1191 }
1192 }
1193
1194 static void
emit_event_wrappers(struct wl_list * message_list,struct interface * interface)1195 emit_event_wrappers(struct wl_list *message_list, struct interface *interface)
1196 {
1197 struct message *m;
1198 struct arg *a;
1199
1200 /* We provide hand written functions for the display object */
1201 if (strcmp(interface->name, "wl_display") == 0)
1202 return;
1203
1204 wl_list_for_each(m, message_list, link) {
1205 printf("/**\n"
1206 " * @ingroup iface_%s\n"
1207 " * Sends an %s event to the client owning the resource.\n",
1208 interface->name,
1209 m->name);
1210 printf(" * @param resource_ The client's resource\n");
1211 wl_list_for_each(a, &m->arg_list, link) {
1212 if (a->summary)
1213 printf(" * @param %s %s\n", a->name, a->summary);
1214 }
1215 printf(" */\n");
1216 printf("static inline void\n"
1217 "%s_send_%s(struct wl_resource *resource_",
1218 interface->name, m->name);
1219
1220 wl_list_for_each(a, &m->arg_list, link) {
1221 printf(", ");
1222 switch (a->type) {
1223 case NEW_ID:
1224 case OBJECT:
1225 printf("struct wl_resource *");
1226 break;
1227 default:
1228 emit_type(a);
1229 }
1230 printf("%s", a->name);
1231 }
1232
1233 printf(")\n"
1234 "{\n"
1235 "\twl_resource_post_event(resource_, %s_%s",
1236 interface->uppercase_name, m->uppercase_name);
1237
1238 wl_list_for_each(a, &m->arg_list, link)
1239 printf(", %s", a->name);
1240
1241 printf(");\n");
1242 printf("}\n\n");
1243 }
1244 }
1245
1246 static void
emit_enumerations(struct interface * interface)1247 emit_enumerations(struct interface *interface)
1248 {
1249 struct enumeration *e;
1250 struct entry *entry;
1251
1252 wl_list_for_each(e, &interface->enumeration_list, link) {
1253 struct description *desc = e->description;
1254
1255 printf("#ifndef %s_%s_ENUM\n",
1256 interface->uppercase_name, e->uppercase_name);
1257 printf("#define %s_%s_ENUM\n",
1258 interface->uppercase_name, e->uppercase_name);
1259
1260 if (desc) {
1261 printf("/**\n");
1262 printf(" * @ingroup iface_%s\n", interface->name);
1263 format_text_to_comment(desc->summary, false);
1264 if (desc->text)
1265 format_text_to_comment(desc->text, false);
1266 printf(" */\n");
1267 }
1268 printf("enum %s_%s {\n", interface->name, e->name);
1269 wl_list_for_each(entry, &e->entry_list, link) {
1270 if (entry->summary)
1271 printf("\t/**\n"
1272 "\t * %s\n"
1273 "\t */\n", entry->summary);
1274 printf("\t%s_%s_%s = %s,\n",
1275 interface->uppercase_name,
1276 e->uppercase_name,
1277 entry->uppercase_name, entry->value);
1278 }
1279 printf("};\n");
1280 printf("#endif /* %s_%s_ENUM */\n\n",
1281 interface->uppercase_name, e->uppercase_name);
1282 }
1283 }
1284
1285 static void
emit_structs(struct wl_list * message_list,struct interface * interface,enum side side)1286 emit_structs(struct wl_list *message_list, struct interface *interface, enum side side)
1287 {
1288 struct message *m;
1289 struct arg *a;
1290 int n;
1291
1292 if (wl_list_empty(message_list))
1293 return;
1294
1295 printf("/**\n");
1296 printf(" * @ingroup iface_%s\n", interface->name);
1297 printf(" * @struct %s_%s\n", interface->name,
1298 (side == SERVER) ? "interface" : "listener");
1299 printf(" */\n");
1300 printf("struct %s_%s {\n", interface->name,
1301 (side == SERVER) ? "interface" : "listener");
1302
1303 wl_list_for_each(m, message_list, link) {
1304 struct description *mdesc = m->description;
1305
1306 printf("\t/**\n");
1307 if (mdesc) {
1308 if (mdesc->summary)
1309 printf("\t * %s\n", mdesc->summary);
1310 printf("\t *\n");
1311 desc_dump(mdesc->text, "\t * ");
1312 }
1313 wl_list_for_each(a, &m->arg_list, link) {
1314 if (side == SERVER && a->type == NEW_ID &&
1315 a->interface_name == NULL)
1316 printf("\t * @param interface name of the objects interface\n"
1317 "\t * @param version version of the objects interface\n");
1318
1319 if (a->summary)
1320 printf("\t * @param %s %s\n", a->name,
1321 a->summary);
1322 }
1323 if (m->since > 1) {
1324 printf("\t * @since %d\n", m->since);
1325 }
1326 printf("\t */\n");
1327 printf("\tvoid (*%s)(", m->name);
1328
1329 n = strlen(m->name) + 17;
1330 if (side == SERVER) {
1331 printf("struct wl_client *client,\n"
1332 "%sstruct wl_resource *resource",
1333 indent(n));
1334 } else {
1335 printf("void *data,\n"),
1336 printf("%sstruct %s *%s",
1337 indent(n), interface->name, interface->name);
1338 }
1339
1340 wl_list_for_each(a, &m->arg_list, link) {
1341 printf(",\n%s", indent(n));
1342
1343 if (side == SERVER && a->type == OBJECT)
1344 printf("struct wl_resource *");
1345 else if (side == SERVER && a->type == NEW_ID && a->interface_name == NULL)
1346 printf("const char *interface, uint32_t version, uint32_t ");
1347 else if (side == CLIENT && a->type == OBJECT && a->interface_name == NULL)
1348 printf("void *");
1349
1350 else if (side == CLIENT && a->type == NEW_ID)
1351 printf("struct %s *", a->interface_name);
1352 else
1353 emit_type(a);
1354
1355 printf("%s", a->name);
1356 }
1357
1358 printf(");\n");
1359 }
1360
1361 printf("};\n\n");
1362
1363 if (side == CLIENT) {
1364 printf("/**\n"
1365 " * @ingroup iface_%s\n"
1366 " */\n", interface->name);
1367 printf("static inline int\n"
1368 "%s_add_listener(struct %s *%s,\n"
1369 "%sconst struct %s_listener *listener, void *data)\n"
1370 "{\n"
1371 "\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n"
1372 "%s(void (**)(void)) listener, data);\n"
1373 "}\n\n",
1374 interface->name, interface->name, interface->name,
1375 indent(14 + strlen(interface->name)),
1376 interface->name,
1377 interface->name,
1378 indent(37));
1379 }
1380 }
1381
1382 static void
emit_types_forward_declarations(struct protocol * protocol,struct wl_list * message_list,struct wl_array * types)1383 emit_types_forward_declarations(struct protocol *protocol,
1384 struct wl_list *message_list,
1385 struct wl_array *types)
1386 {
1387 struct message *m;
1388 struct arg *a;
1389 int length;
1390 char **p;
1391
1392 wl_list_for_each(m, message_list, link) {
1393 length = 0;
1394 m->all_null = 1;
1395 wl_list_for_each(a, &m->arg_list, link) {
1396 length++;
1397 switch (a->type) {
1398 case NEW_ID:
1399 case OBJECT:
1400 if (!a->interface_name)
1401 continue;
1402
1403 m->all_null = 0;
1404 p = fail_on_null(wl_array_add(types, sizeof *p));
1405 *p = a->interface_name;
1406 break;
1407 default:
1408 break;
1409 }
1410 }
1411
1412 if (m->all_null && length > protocol->null_run_length)
1413 protocol->null_run_length = length;
1414 }
1415 }
1416
1417 static int
cmp_names(const void * p1,const void * p2)1418 cmp_names(const void *p1, const void *p2)
1419 {
1420 const char * const *s1 = p1, * const *s2 = p2;
1421
1422 return strcmp(*s1, *s2);
1423 }
1424
1425 static const char *
get_include_name(bool core,enum side side)1426 get_include_name(bool core, enum side side)
1427 {
1428 if (side == SERVER)
1429 return core ? "wayland-server-core.h" : "wayland-server.h";
1430 else
1431 return core ? "wayland-client-core.h" : "wayland-client.h";
1432 }
1433
1434 static void
emit_mainpage_blurb(const struct protocol * protocol,enum side side)1435 emit_mainpage_blurb(const struct protocol *protocol, enum side side)
1436 {
1437 struct interface *i;
1438
1439 printf("/**\n"
1440 " * @page page_%s The %s protocol\n",
1441 protocol->name, protocol->name);
1442
1443 if (protocol->description) {
1444 if (protocol->description->summary) {
1445 printf(" * %s\n"
1446 " *\n", protocol->description->summary);
1447 }
1448
1449 if (protocol->description->text) {
1450 printf(" * @section page_desc_%s Description\n", protocol->name);
1451 format_text_to_comment(protocol->description->text, false);
1452 printf(" *\n");
1453 }
1454 }
1455
1456 printf(" * @section page_ifaces_%s Interfaces\n", protocol->name);
1457 wl_list_for_each(i, &protocol->interface_list, link) {
1458 printf(" * - @subpage page_iface_%s - %s\n",
1459 i->name,
1460 i->description && i->description->summary ? i->description->summary : "");
1461 }
1462
1463 if (protocol->copyright) {
1464 printf(" * @section page_copyright_%s Copyright\n",
1465 protocol->name);
1466 printf(" * <pre>\n");
1467 format_text_to_comment(protocol->copyright, false);
1468 printf(" * </pre>\n");
1469 }
1470
1471 printf(" */\n");
1472 }
1473
1474 static void
emit_header(struct protocol * protocol,enum side side)1475 emit_header(struct protocol *protocol, enum side side)
1476 {
1477 struct interface *i, *i_next;
1478 struct wl_array types;
1479 const char *s = (side == SERVER) ? "SERVER" : "CLIENT";
1480 char **p, *prev;
1481
1482 printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION);
1483
1484 printf("#ifndef %s_%s_PROTOCOL_H\n"
1485 "#define %s_%s_PROTOCOL_H\n"
1486 "\n"
1487 "#include <stdint.h>\n"
1488 "#include <stddef.h>\n"
1489 "#include \"%s\"\n\n"
1490 "#ifdef __cplusplus\n"
1491 "extern \"C\" {\n"
1492 "#endif\n\n",
1493 protocol->uppercase_name, s,
1494 protocol->uppercase_name, s,
1495 get_include_name(protocol->core_headers, side));
1496 if (side == SERVER)
1497 printf("struct wl_client;\n"
1498 "struct wl_resource;\n\n");
1499
1500 emit_mainpage_blurb(protocol, side);
1501
1502 wl_array_init(&types);
1503 wl_list_for_each(i, &protocol->interface_list, link) {
1504 emit_types_forward_declarations(protocol, &i->request_list, &types);
1505 emit_types_forward_declarations(protocol, &i->event_list, &types);
1506 }
1507
1508 wl_list_for_each(i, &protocol->interface_list, link) {
1509 p = fail_on_null(wl_array_add(&types, sizeof *p));
1510 *p = i->name;
1511 }
1512
1513 qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names);
1514 prev = NULL;
1515 wl_array_for_each(p, &types) {
1516 if (prev && strcmp(*p, prev) == 0)
1517 continue;
1518 printf("struct %s;\n", *p);
1519 prev = *p;
1520 }
1521 wl_array_release(&types);
1522 printf("\n");
1523
1524 wl_list_for_each(i, &protocol->interface_list, link) {
1525 printf("/**\n"
1526 " * @page page_iface_%s %s\n",
1527 i->name, i->name);
1528 if (i->description && i->description->text) {
1529 printf(" * @section page_iface_%s_desc Description\n",
1530 i->name);
1531 format_text_to_comment(i->description->text, false);
1532 }
1533 printf(" * @section page_iface_%s_api API\n"
1534 " * See @ref iface_%s.\n"
1535 " */\n",
1536 i->name, i->name);
1537 printf("/**\n"
1538 " * @defgroup iface_%s The %s interface\n",
1539 i->name, i->name);
1540 if (i->description && i->description->text)
1541 format_text_to_comment(i->description->text, false);
1542 printf(" */\n");
1543 printf("extern const struct wl_interface "
1544 "%s_interface;\n", i->name);
1545 }
1546
1547 printf("\n");
1548
1549 wl_list_for_each_safe(i, i_next, &protocol->interface_list, link) {
1550
1551 emit_enumerations(i);
1552
1553 if (side == SERVER) {
1554 emit_structs(&i->request_list, i, side);
1555 emit_opcodes(&i->event_list, i);
1556 emit_opcode_versions(&i->event_list, i);
1557 emit_opcode_versions(&i->request_list, i);
1558 emit_event_wrappers(&i->event_list, i);
1559 } else {
1560 emit_structs(&i->event_list, i, side);
1561 emit_opcodes(&i->request_list, i);
1562 emit_opcode_versions(&i->event_list, i);
1563 emit_opcode_versions(&i->request_list, i);
1564 emit_stubs(&i->request_list, i);
1565 }
1566
1567 free_interface(i);
1568 }
1569
1570 printf("#ifdef __cplusplus\n"
1571 "}\n"
1572 "#endif\n"
1573 "\n"
1574 "#endif\n");
1575 }
1576
1577 static void
emit_null_run(struct protocol * protocol)1578 emit_null_run(struct protocol *protocol)
1579 {
1580 int i;
1581
1582 for (i = 0; i < protocol->null_run_length; i++)
1583 printf("\tNULL,\n");
1584 }
1585
1586 static void
emit_types(struct protocol * protocol,struct wl_list * message_list)1587 emit_types(struct protocol *protocol, struct wl_list *message_list)
1588 {
1589 struct message *m;
1590 struct arg *a;
1591
1592 wl_list_for_each(m, message_list, link) {
1593 if (m->all_null) {
1594 m->type_index = 0;
1595 continue;
1596 }
1597
1598 m->type_index =
1599 protocol->null_run_length + protocol->type_index;
1600 protocol->type_index += m->arg_count;
1601
1602 wl_list_for_each(a, &m->arg_list, link) {
1603 switch (a->type) {
1604 case NEW_ID:
1605 case OBJECT:
1606 if (a->interface_name)
1607 printf("\t&%s_interface,\n",
1608 a->interface_name);
1609 else
1610 printf("\tNULL,\n");
1611 break;
1612 default:
1613 printf("\tNULL,\n");
1614 break;
1615 }
1616 }
1617 }
1618 }
1619
1620 static void
emit_messages(struct wl_list * message_list,struct interface * interface,const char * suffix)1621 emit_messages(struct wl_list *message_list,
1622 struct interface *interface, const char *suffix)
1623 {
1624 struct message *m;
1625 struct arg *a;
1626
1627 if (wl_list_empty(message_list))
1628 return;
1629
1630 printf("static const struct wl_message "
1631 "%s_%s[] = {\n",
1632 interface->name, suffix);
1633
1634 wl_list_for_each(m, message_list, link) {
1635 printf("\t{ \"%s\", \"", m->name);
1636
1637 if (m->since > 1)
1638 printf("%d", m->since);
1639
1640 wl_list_for_each(a, &m->arg_list, link) {
1641 if (is_nullable_type(a) && a->nullable)
1642 printf("?");
1643
1644 switch (a->type) {
1645 default:
1646 case INT:
1647 printf("i");
1648 break;
1649 case NEW_ID:
1650 if (a->interface_name == NULL)
1651 printf("su");
1652 printf("n");
1653 break;
1654 case UNSIGNED:
1655 printf("u");
1656 break;
1657 case FIXED:
1658 printf("f");
1659 break;
1660 case STRING:
1661 printf("s");
1662 break;
1663 case OBJECT:
1664 printf("o");
1665 break;
1666 case ARRAY:
1667 printf("a");
1668 break;
1669 case FD:
1670 printf("h");
1671 break;
1672 }
1673 }
1674 printf("\", types + %d },\n", m->type_index);
1675 }
1676
1677 printf("};\n\n");
1678 }
1679
1680 static void
emit_code(struct protocol * protocol)1681 emit_code(struct protocol *protocol)
1682 {
1683 struct interface *i, *next;
1684 struct wl_array types;
1685 char **p, *prev;
1686
1687 printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION);
1688
1689 if (protocol->copyright)
1690 format_text_to_comment(protocol->copyright, true);
1691
1692 printf("#include <stdlib.h>\n"
1693 "#include <stdint.h>\n"
1694 "#include \"wayland-util.h\"\n\n");
1695
1696 wl_array_init(&types);
1697 wl_list_for_each(i, &protocol->interface_list, link) {
1698 emit_types_forward_declarations(protocol, &i->request_list, &types);
1699 emit_types_forward_declarations(protocol, &i->event_list, &types);
1700 }
1701 qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names);
1702 prev = NULL;
1703 wl_array_for_each(p, &types) {
1704 if (prev && strcmp(*p, prev) == 0)
1705 continue;
1706 printf("extern const struct wl_interface %s_interface;\n", *p);
1707 prev = *p;
1708 }
1709 wl_array_release(&types);
1710 printf("\n");
1711
1712 printf("static const struct wl_interface *types[] = {\n");
1713 emit_null_run(protocol);
1714 wl_list_for_each(i, &protocol->interface_list, link) {
1715 emit_types(protocol, &i->request_list);
1716 emit_types(protocol, &i->event_list);
1717 }
1718 printf("};\n\n");
1719
1720 wl_list_for_each_safe(i, next, &protocol->interface_list, link) {
1721
1722 emit_messages(&i->request_list, i, "requests");
1723 emit_messages(&i->event_list, i, "events");
1724
1725 printf("WL_EXPORT const struct wl_interface "
1726 "%s_interface = {\n"
1727 "\t\"%s\", %d,\n",
1728 i->name, i->name, i->version);
1729
1730 if (!wl_list_empty(&i->request_list))
1731 printf("\t%d, %s_requests,\n",
1732 wl_list_length(&i->request_list), i->name);
1733 else
1734 printf("\t0, NULL,\n");
1735
1736 if (!wl_list_empty(&i->event_list))
1737 printf("\t%d, %s_events,\n",
1738 wl_list_length(&i->event_list), i->name);
1739 else
1740 printf("\t0, NULL,\n");
1741
1742 printf("};\n\n");
1743
1744 /* we won't need it any further */
1745 free_interface(i);
1746 }
1747 }
1748
1749 static void
free_protocol(struct protocol * protocol)1750 free_protocol(struct protocol *protocol)
1751 {
1752 free(protocol->name);
1753 free(protocol->uppercase_name);
1754 free(protocol->copyright);
1755 free_description(protocol->description);
1756 }
1757
main(int argc,char * argv[])1758 int main(int argc, char *argv[])
1759 {
1760 struct parse_context ctx;
1761 struct protocol protocol;
1762 FILE *input = stdin;
1763 char *input_filename = NULL;
1764 int len;
1765 void *buf;
1766 bool help = false;
1767 bool core_headers = false;
1768 bool version = false;
1769 bool fail = false;
1770 int opt;
1771 enum {
1772 CLIENT_HEADER,
1773 SERVER_HEADER,
1774 CODE,
1775 } mode;
1776
1777 static const struct option options[] = {
1778 { "help", no_argument, NULL, 'h' },
1779 { "version", no_argument, NULL, 'v' },
1780 { "include-core-only", no_argument, NULL, 'c' },
1781 { 0, 0, NULL, 0 }
1782 };
1783
1784 while (1) {
1785 opt = getopt_long(argc, argv, "hvc", options, NULL);
1786
1787 if (opt == -1)
1788 break;
1789
1790 switch (opt) {
1791 case 'h':
1792 help = true;
1793 break;
1794 case 'v':
1795 version = true;
1796 break;
1797 case 'c':
1798 core_headers = true;
1799 break;
1800 default:
1801 fail = true;
1802 break;
1803 }
1804 }
1805
1806 argv += optind;
1807 argc -= optind;
1808
1809 if (help)
1810 usage(EXIT_SUCCESS);
1811 else if (version)
1812 scanner_version(EXIT_SUCCESS);
1813 else if ((argc != 1 && argc != 3) || fail)
1814 usage(EXIT_FAILURE);
1815 else if (strcmp(argv[0], "help") == 0)
1816 usage(EXIT_SUCCESS);
1817 else if (strcmp(argv[0], "client-header") == 0)
1818 mode = CLIENT_HEADER;
1819 else if (strcmp(argv[0], "server-header") == 0)
1820 mode = SERVER_HEADER;
1821 else if (strcmp(argv[0], "code") == 0)
1822 mode = CODE;
1823 else
1824 usage(EXIT_FAILURE);
1825
1826 if (argc == 3) {
1827 input_filename = argv[1];
1828 input = fopen(input_filename, "r");
1829 if (input == NULL) {
1830 fprintf(stderr, "Could not open input file: %s\n",
1831 strerror(errno));
1832 exit(EXIT_FAILURE);
1833 }
1834 if (freopen(argv[2], "w", stdout) == NULL) {
1835 fprintf(stderr, "Could not open output file: %s\n",
1836 strerror(errno));
1837 fclose(input);
1838 exit(EXIT_FAILURE);
1839 }
1840 }
1841
1842 /* initialize protocol structure */
1843 memset(&protocol, 0, sizeof protocol);
1844 wl_list_init(&protocol.interface_list);
1845 protocol.core_headers = core_headers;
1846
1847 /* initialize context */
1848 memset(&ctx, 0, sizeof ctx);
1849 ctx.protocol = &protocol;
1850 if (input == stdin)
1851 ctx.loc.filename = "<stdin>";
1852 else
1853 ctx.loc.filename = input_filename;
1854
1855 if (!is_dtd_valid(input, ctx.loc.filename)) {
1856 fprintf(stderr,
1857 "*******************************************************\n"
1858 "* *\n"
1859 "* WARNING: XML failed validation against built-in DTD *\n"
1860 "* *\n"
1861 "*******************************************************\n");
1862 }
1863
1864 /* create XML parser */
1865 ctx.parser = XML_ParserCreate(NULL);
1866 XML_SetUserData(ctx.parser, &ctx);
1867 if (ctx.parser == NULL) {
1868 fprintf(stderr, "failed to create parser\n");
1869 fclose(input);
1870 exit(EXIT_FAILURE);
1871 }
1872
1873 XML_SetElementHandler(ctx.parser, start_element, end_element);
1874 XML_SetCharacterDataHandler(ctx.parser, character_data);
1875
1876 do {
1877 buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
1878 len = fread(buf, 1, XML_BUFFER_SIZE, input);
1879 if (len < 0) {
1880 fprintf(stderr, "fread: %m\n");
1881 fclose(input);
1882 exit(EXIT_FAILURE);
1883 }
1884 if (XML_ParseBuffer(ctx.parser, len, len == 0) == 0) {
1885 fprintf(stderr,
1886 "Error parsing XML at line %ld col %ld: %s\n",
1887 XML_GetCurrentLineNumber(ctx.parser),
1888 XML_GetCurrentColumnNumber(ctx.parser),
1889 XML_ErrorString(XML_GetErrorCode(ctx.parser)));
1890 fclose(input);
1891 exit(EXIT_FAILURE);
1892 }
1893 } while (len > 0);
1894
1895 XML_ParserFree(ctx.parser);
1896
1897 switch (mode) {
1898 case CLIENT_HEADER:
1899 emit_header(&protocol, CLIENT);
1900 break;
1901 case SERVER_HEADER:
1902 emit_header(&protocol, SERVER);
1903 break;
1904 case CODE:
1905 emit_code(&protocol);
1906 break;
1907 }
1908
1909 free_protocol(&protocol);
1910 fclose(input);
1911
1912 return 0;
1913 }
1914