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