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