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