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