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