• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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