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