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