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

source code of gtk/subprojects/wayland/src/scanner.c