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
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(wayland_dtd,
116 sizeof(wayland_dtd),
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 struct description *description;
240 };
241
242 struct parse_context {
243 struct location loc;
244 XML_Parser parser;
245 struct protocol *protocol;
246 struct interface *interface;
247 struct message *message;
248 struct enumeration *enumeration;
249 struct entry *entry;
250 struct description *description;
251 char character_data[8192];
252 unsigned int character_data_length;
253 };
254
255 enum identifier_role {
256 STANDALONE_IDENT,
257 TRAILING_IDENT
258 };
259
260 static void *
fail_on_null(void * p)261 fail_on_null(void *p)
262 {
263 if (p == NULL) {
264 fprintf(stderr, "%s: out of memory\n", PROGRAM_NAME);
265 exit(EXIT_FAILURE);
266 }
267
268 return p;
269 }
270
271 static void *
zalloc(size_t s)272 zalloc(size_t s)
273 {
274 return calloc(s, 1);
275 }
276
277 static void *
xzalloc(size_t s)278 xzalloc(size_t s)
279 {
280 return fail_on_null(zalloc(s));
281 }
282
283 static char *
xstrdup(const char * s)284 xstrdup(const char *s)
285 {
286 return fail_on_null(strdup(s));
287 }
288
289 static char *
uppercase_dup(const char * src)290 uppercase_dup(const char *src)
291 {
292 char *u;
293 int i;
294
295 u = xstrdup(src);
296 for (i = 0; u[i]; i++)
297 u[i] = toupper(u[i]);
298 u[i] = '\0';
299
300 return u;
301 }
302
indent(int n)303 static 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
319 static void
320 desc_dump(char *desc, const char *fmt, ...) WL_PRINTF(2, 3);
321
322 static void
desc_dump(char * desc,const char * fmt,...)323 desc_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(buf, sizeof buf, fmt, 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("%s", buf);
341
342 if (!desc) {
343 printf("(none)\n");
344 return;
345 }
346
347 startcol = col;
348 col += strlen(&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("\n%s*", indent(startcol));
371 if (newlines > 1 || col + i - j > 72) {
372 printf("\n%s*%c", indent(startcol), hang);
373 col = startcol;
374 }
375
376 if (col > startcol && k > 0)
377 col += printf(" ");
378 col += printf("%.*s", i - j, &desc[j]);
379 }
380 putchar('\n');
381 }
382
383 static void __attribute__ ((noreturn))
fail(struct location * loc,const char * msg,...)384 fail(struct location *loc, const char *msg, ...)
385 {
386 va_list ap;
387
388 va_start(ap, msg);
389 fprintf(stderr, "%s:%d: error: ",
390 loc->filename, loc->line_number);
391 vfprintf(stderr, msg, ap);
392 fprintf(stderr, "\n");
393 va_end(ap);
394 exit(EXIT_FAILURE);
395 }
396
397 static void
warn(struct location * loc,const char * msg,...)398 warn(struct location *loc, const char *msg, ...)
399 {
400 va_list ap;
401
402 va_start(ap, msg);
403 fprintf(stderr, "%s:%d: warning: ",
404 loc->filename, loc->line_number);
405 vfprintf(stderr, msg, ap);
406 fprintf(stderr, "\n");
407 va_end(ap);
408 }
409
410 static bool
is_nullable_type(struct arg * arg)411 is_nullable_type(struct arg *arg)
412 {
413 switch (arg->type) {
414 /* Strings and objects are possibly nullable */
415 case STRING:
416 case OBJECT:
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 free_description(entry->description);
546
547 free(entry);
548 }
549
550 static void
free_enumeration(struct enumeration * enumeration)551 free_enumeration(struct enumeration *enumeration)
552 {
553 struct entry *e, *e_next;
554
555 free(enumeration->name);
556 free(enumeration->uppercase_name);
557 free_description(enumeration->description);
558
559 wl_list_for_each_safe(e, e_next, &enumeration->entry_list, link)
560 free_entry(e);
561
562 free(enumeration);
563 }
564
565 static struct interface *
create_interface(struct location loc,const char * name,int version)566 create_interface(struct location loc, const char *name, int version)
567 {
568 struct interface *interface;
569
570 interface = xzalloc(sizeof *interface);
571 interface->loc = loc;
572 interface->name = xstrdup(name);
573 interface->uppercase_name = uppercase_dup(name);
574 interface->version = version;
575 interface->since = 1;
576 wl_list_init(&interface->request_list);
577 wl_list_init(&interface->event_list);
578 wl_list_init(&interface->enumeration_list);
579
580 return interface;
581 }
582
583 static void
free_interface(struct interface * interface)584 free_interface(struct interface *interface)
585 {
586 struct message *m, *next_m;
587 struct enumeration *e, *next_e;
588
589 free(interface->name);
590 free(interface->uppercase_name);
591 free_description(interface->description);
592
593 wl_list_for_each_safe(m, next_m, &interface->request_list, link)
594 free_message(m);
595 wl_list_for_each_safe(m, next_m, &interface->event_list, link)
596 free_message(m);
597 wl_list_for_each_safe(e, next_e, &interface->enumeration_list, link)
598 free_enumeration(e);
599
600 free(interface);
601 }
602
603 /* Convert string to unsigned integer
604 *
605 * Parses a non-negative base-10 number from the given string. If the
606 * specified string is blank, contains non-numerical characters, is out
607 * of range, or results in a negative number, -1 is returned to indicate
608 * an error.
609 *
610 * Upon error, this routine does not modify or set errno.
611 *
612 * Returns -1 on error, or a non-negative integer on success
613 */
614 static int
strtouint(const char * str)615 strtouint(const char *str)
616 {
617 long int ret;
618 char *end;
619 int prev_errno = errno;
620
621 errno = 0;
622 ret = strtol(str, &end, 10);
623 if (errno != 0 || end == str || *end != '\0')
624 return -1;
625
626 /* check range */
627 if (ret < 0 || ret > INT_MAX) {
628 return -1;
629 }
630
631 errno = prev_errno;
632 return (int)ret;
633 }
634
635 /* Check that the provided string will produce valid "C" identifiers.
636 *
637 * If the string will form the prefix of an identifier in the
638 * generated C code, then it must match [_a-zA-Z][_0-9a-zA-Z]*.
639 *
640 * If the string will form the suffix of an identifier, then
641 * it must match [_0-9a-zA-Z]+.
642 *
643 * Unicode characters or escape sequences are not permitted,
644 * since not all C compilers support them.
645 *
646 * If the above conditions are not met, then fail()
647 */
648 static void
validate_identifier(struct location * loc,const char * str,enum identifier_role role)649 validate_identifier(struct location *loc,
650 const char *str,
651 enum identifier_role role)
652 {
653 const char *scan;
654
655 if (!*str) {
656 fail(loc, "element name is empty");
657 }
658
659 for (scan = str; *scan; scan++) {
660 char c = *scan;
661
662 /* we do not use the locale-dependent `isalpha` */
663 bool is_alpha = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
664 bool is_digit = c >= '0' && c <= '9';
665 bool leading_char = (scan == str) && role == STANDALONE_IDENT;
666
667 if (is_alpha || c == '_' || (!leading_char && is_digit))
668 continue;
669
670 if (role == TRAILING_IDENT)
671 fail(loc,
672 "'%s' is not a valid trailing identifier part", str);
673 else
674 fail(loc,
675 "'%s' is not a valid standalone identifier", str);
676 }
677 }
678
679 static int
version_from_since(struct parse_context * ctx,const char * since)680 version_from_since(struct parse_context *ctx, const char *since)
681 {
682 int version;
683
684 if (since != NULL) {
685 version = strtouint(since);
686 if (version == -1) {
687 fail(&ctx->loc, "invalid integer (%s)\n", since);
688 } else if (version > ctx->interface->version) {
689 fail(&ctx->loc, "since (%u) larger than version (%u)\n",
690 version, ctx->interface->version);
691 }
692 } else {
693 version = 1;
694 }
695
696
697 return version;
698 }
699
700 static void
start_element(void * data,const char * element_name,const char ** atts)701 start_element(void *data, const char *element_name, const char **atts)
702 {
703 struct parse_context *ctx = data;
704 struct interface *interface;
705 struct message *message;
706 struct arg *arg;
707 struct enumeration *enumeration;
708 struct entry *entry;
709 struct description *description = NULL;
710 const char *name = NULL;
711 const char *type = NULL;
712 const char *interface_name = NULL;
713 const char *value = NULL;
714 const char *summary = NULL;
715 const char *since = NULL;
716 const char *allow_null = NULL;
717 const char *enumeration_name = NULL;
718 const char *bitfield = NULL;
719 int i, version = 0;
720
721 ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser);
722 for (i = 0; atts[i]; i += 2) {
723 if (strcmp(atts[i], "name") == 0)
724 name = atts[i + 1];
725 if (strcmp(atts[i], "version") == 0) {
726 version = strtouint(atts[i + 1]);
727 if (version == -1)
728 fail(&ctx->loc, "wrong version (%s)", atts[i + 1]);
729 }
730 if (strcmp(atts[i], "type") == 0)
731 type = atts[i + 1];
732 if (strcmp(atts[i], "value") == 0)
733 value = atts[i + 1];
734 if (strcmp(atts[i], "interface") == 0)
735 interface_name = atts[i + 1];
736 if (strcmp(atts[i], "summary") == 0)
737 summary = atts[i + 1];
738 if (strcmp(atts[i], "since") == 0)
739 since = atts[i + 1];
740 if (strcmp(atts[i], "allow-null") == 0)
741 allow_null = atts[i + 1];
742 if (strcmp(atts[i], "enum") == 0)
743 enumeration_name = atts[i + 1];
744 if (strcmp(atts[i], "bitfield") == 0)
745 bitfield = atts[i + 1];
746 }
747
748 ctx->character_data_length = 0;
749 if (strcmp(element_name, "protocol") == 0) {
750 if (name == NULL)
751 fail(&ctx->loc, "no protocol name given");
752
753 validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
754 ctx->protocol->name = xstrdup(name);
755 ctx->protocol->uppercase_name = uppercase_dup(name);
756 } else if (strcmp(element_name, "copyright") == 0) {
757
758 } else if (strcmp(element_name, "interface") == 0) {
759 if (name == NULL)
760 fail(&ctx->loc, "no interface name given");
761
762 if (version == 0)
763 fail(&ctx->loc, "no interface version given");
764
765 validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
766 interface = create_interface(ctx->loc, name, version);
767 ctx->interface = interface;
768 wl_list_insert(ctx->protocol->interface_list.prev,
769 &interface->link);
770 } else if (strcmp(element_name, "request") == 0 ||
771 strcmp(element_name, "event") == 0) {
772 if (name == NULL)
773 fail(&ctx->loc, "no request name given");
774
775 validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
776 message = create_message(ctx->loc, name);
777
778 if (strcmp(element_name, "request") == 0)
779 wl_list_insert(ctx->interface->request_list.prev,
780 &message->link);
781 else
782 wl_list_insert(ctx->interface->event_list.prev,
783 &message->link);
784
785 if (type != NULL && strcmp(type, "destructor") == 0)
786 message->destructor = 1;
787
788 version = version_from_since(ctx, since);
789
790 if (version < ctx->interface->since)
791 warn(&ctx->loc, "since version not increasing\n");
792 ctx->interface->since = version;
793 message->since = version;
794
795 if (strcmp(name, "destroy") == 0 && !message->destructor)
796 fail(&ctx->loc, "destroy request should be destructor type");
797
798 ctx->message = message;
799 } else if (strcmp(element_name, "arg") == 0) {
800 if (name == NULL)
801 fail(&ctx->loc, "no argument name given");
802
803 validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
804 arg = create_arg(name);
805 if (!set_arg_type(arg, type))
806 fail(&ctx->loc, "unknown type (%s)", type);
807
808 switch (arg->type) {
809 case NEW_ID:
810 ctx->message->new_id_count++;
811 /* fallthrough */
812 case OBJECT:
813 if (interface_name) {
814 validate_identifier(&ctx->loc,
815 interface_name,
816 STANDALONE_IDENT);
817 arg->interface_name = xstrdup(interface_name);
818 }
819 break;
820 default:
821 if (interface_name != NULL)
822 fail(&ctx->loc, "interface attribute not allowed for type %s", type);
823 break;
824 }
825
826 if (allow_null) {
827 if (strcmp(allow_null, "true") == 0)
828 arg->nullable = 1;
829 else if (strcmp(allow_null, "false") != 0)
830 fail(&ctx->loc,
831 "invalid value for allow-null attribute (%s)",
832 allow_null);
833
834 if (!is_nullable_type(arg))
835 fail(&ctx->loc,
836 "allow-null is only valid for objects, strings, and arrays");
837 }
838
839 if (enumeration_name == NULL || strcmp(enumeration_name, "") == 0)
840 arg->enumeration_name = NULL;
841 else
842 arg->enumeration_name = xstrdup(enumeration_name);
843
844 if (summary)
845 arg->summary = xstrdup(summary);
846
847 wl_list_insert(ctx->message->arg_list.prev, &arg->link);
848 ctx->message->arg_count++;
849 } else if (strcmp(element_name, "enum") == 0) {
850 if (name == NULL)
851 fail(&ctx->loc, "no enum name given");
852
853 validate_identifier(&ctx->loc, name, TRAILING_IDENT);
854 enumeration = create_enumeration(name);
855
856 if (bitfield == NULL || strcmp(bitfield, "false") == 0)
857 enumeration->bitfield = false;
858 else if (strcmp(bitfield, "true") == 0)
859 enumeration->bitfield = true;
860 else
861 fail(&ctx->loc,
862 "invalid value (%s) for bitfield attribute (only true/false are accepted)",
863 bitfield);
864
865 wl_list_insert(ctx->interface->enumeration_list.prev,
866 &enumeration->link);
867
868 ctx->enumeration = enumeration;
869 } else if (strcmp(element_name, "entry") == 0) {
870 if (name == NULL)
871 fail(&ctx->loc, "no entry name given");
872
873 validate_identifier(&ctx->loc, name, TRAILING_IDENT);
874 entry = create_entry(name, value);
875 version = version_from_since(ctx, since);
876
877 if (version < ctx->enumeration->since)
878 warn(&ctx->loc, "since version not increasing\n");
879 ctx->enumeration->since = version;
880 entry->since = version;
881
882 if (summary)
883 entry->summary = xstrdup(summary);
884 else
885 entry->summary = NULL;
886 wl_list_insert(ctx->enumeration->entry_list.prev,
887 &entry->link);
888 ctx->entry = entry;
889 } else if (strcmp(element_name, "description") == 0) {
890 if (summary == NULL)
891 fail(&ctx->loc, "description without summary");
892
893 description = xzalloc(sizeof *description);
894 description->summary = xstrdup(summary);
895
896 if (ctx->message)
897 ctx->message->description = description;
898 else if (ctx->entry)
899 ctx->entry->description = description;
900 else if (ctx->enumeration)
901 ctx->enumeration->description = description;
902 else if (ctx->interface)
903 ctx->interface->description = description;
904 else
905 ctx->protocol->description = description;
906 ctx->description = description;
907 }
908 }
909
910 static struct enumeration *
find_enumeration(struct protocol * protocol,struct interface * interface,char * enum_attribute)911 find_enumeration(struct protocol *protocol,
912 struct interface *interface,
913 char *enum_attribute)
914 {
915 struct interface *i;
916 struct enumeration *e;
917 char *enum_name;
918 uint32_t idx = 0, j;
919
920 for (j = 0; j + 1 < strlen(enum_attribute); j++) {
921 if (enum_attribute[j] == '.') {
922 idx = j;
923 }
924 }
925
926 if (idx > 0) {
927 enum_name = enum_attribute + idx + 1;
928
929 wl_list_for_each(i, &protocol->interface_list, link)
930 if (strncmp(i->name, enum_attribute, idx) == 0)
931 wl_list_for_each(e, &i->enumeration_list, link)
932 if (strcmp(e->name, enum_name) == 0)
933 return e;
934 } else if (interface) {
935 enum_name = enum_attribute;
936
937 wl_list_for_each(e, &interface->enumeration_list, link)
938 if (strcmp(e->name, enum_name) == 0)
939 return e;
940 }
941
942 return NULL;
943 }
944
945 static void
verify_arguments(struct parse_context * ctx,struct interface * interface,struct wl_list * messages,struct wl_list * enumerations)946 verify_arguments(struct parse_context *ctx,
947 struct interface *interface,
948 struct wl_list *messages,
949 struct wl_list *enumerations)
950 {
951 struct message *m;
952 wl_list_for_each(m, messages, link) {
953 struct arg *a;
954 wl_list_for_each(a, &m->arg_list, link) {
955 struct enumeration *e;
956
957 if (!a->enumeration_name)
958 continue;
959
960
961 e = find_enumeration(ctx->protocol, interface,
962 a->enumeration_name);
963
964 switch (a->type) {
965 case INT:
966 if (e && e->bitfield)
967 fail(&ctx->loc,
968 "bitfield-style enum must only be referenced by uint");
969 break;
970 case UNSIGNED:
971 break;
972 default:
973 fail(&ctx->loc,
974 "enumeration-style argument has wrong type");
975 }
976 }
977 }
978
979 }
980
981 #ifndef HAVE_STRNDUP
982 char *
strndup(const char * s,size_t size)983 strndup(const char *s, size_t size)
984 {
985 char *r = malloc(size + 1);
986 strncpy(r, s, size);
987 r[size] = '\0';
988 return r;
989 }
990 #endif
991
992 static void
end_element(void * data,const XML_Char * name)993 end_element(void *data, const XML_Char *name)
994 {
995 struct parse_context *ctx = data;
996
997 if (strcmp(name, "copyright") == 0) {
998 ctx->protocol->copyright =
999 strndup(ctx->character_data,
1000 ctx->character_data_length);
1001 } else if (strcmp(name, "description") == 0) {
1002 ctx->description->text =
1003 strndup(ctx->character_data,
1004 ctx->character_data_length);
1005 ctx->description = NULL;
1006 } else if (strcmp(name, "request") == 0 ||
1007 strcmp(name, "event") == 0) {
1008 ctx->message = NULL;
1009 } else if (strcmp(name, "enum") == 0) {
1010 if (wl_list_empty(&ctx->enumeration->entry_list)) {
1011 fail(&ctx->loc, "enumeration %s was empty",
1012 ctx->enumeration->name);
1013 }
1014 ctx->enumeration = NULL;
1015 } else if (strcmp(name, "entry") == 0) {
1016 ctx->entry = NULL;
1017 } else if (strcmp(name, "protocol") == 0) {
1018 struct interface *i;
1019
1020 wl_list_for_each(i, &ctx->protocol->interface_list, link) {
1021 verify_arguments(ctx, i, &i->request_list, &i->enumeration_list);
1022 verify_arguments(ctx, i, &i->event_list, &i->enumeration_list);
1023 }
1024 }
1025 }
1026
1027 static void
character_data(void * data,const XML_Char * s,int len)1028 character_data(void *data, const XML_Char *s, int len)
1029 {
1030 struct parse_context *ctx = data;
1031
1032 if (ctx->character_data_length + len > sizeof (ctx->character_data)) {
1033 fprintf(stderr, "too much character data");
1034 exit(EXIT_FAILURE);
1035 }
1036
1037 memcpy(ctx->character_data + ctx->character_data_length, s, len);
1038 ctx->character_data_length += len;
1039 }
1040
1041 static void
format_text_to_comment(const char * text,bool standalone_comment)1042 format_text_to_comment(const char *text, bool standalone_comment)
1043 {
1044 int bol = 1, start = 0, i, length;
1045 bool comment_started = !standalone_comment;
1046
1047 length = strlen(text);
1048 for (i = 0; i <= length; i++) {
1049 if (bol && (text[i] == ' ' || text[i] == '\t')) {
1050 continue;
1051 } else if (bol) {
1052 bol = 0;
1053 start = i;
1054 }
1055 if (text[i] == '\n' ||
1056 (text[i] == '\0' && !(start == i))) {
1057 printf("%s%s%.*s\n",
1058 comment_started ? " *" : "/*",
1059 i > start ? " " : "",
1060 i - start, text + start);
1061 bol = 1;
1062 comment_started = true;
1063 }
1064 }
1065 if (comment_started && standalone_comment)
1066 printf(" */\n\n");
1067 }
1068
1069 static void
emit_opcodes(struct wl_list * message_list,struct interface * interface)1070 emit_opcodes(struct wl_list *message_list, struct interface *interface)
1071 {
1072 struct message *m;
1073 int opcode;
1074
1075 if (wl_list_empty(message_list))
1076 return;
1077
1078 opcode = 0;
1079 wl_list_for_each(m, message_list, link)
1080 printf("#define %s_%s %d\n",
1081 interface->uppercase_name, m->uppercase_name, opcode++);
1082
1083 printf("\n");
1084 }
1085
1086 static void
emit_opcode_versions(struct wl_list * message_list,struct interface * interface)1087 emit_opcode_versions(struct wl_list *message_list, struct interface *interface)
1088 {
1089 struct message *m;
1090
1091 wl_list_for_each(m, message_list, link) {
1092 printf("/**\n * @ingroup iface_%s\n */\n", interface->name);
1093 printf("#define %s_%s_SINCE_VERSION %d\n",
1094 interface->uppercase_name, m->uppercase_name, m->since);
1095 }
1096
1097 printf("\n");
1098 }
1099
1100 static void
emit_type(struct arg * a)1101 emit_type(struct arg *a)
1102 {
1103 switch (a->type) {
1104 default:
1105 case INT:
1106 case FD:
1107 printf("int32_t ");
1108 break;
1109 case NEW_ID:
1110 case UNSIGNED:
1111 printf("uint32_t ");
1112 break;
1113 case FIXED:
1114 printf("wl_fixed_t ");
1115 break;
1116 case STRING:
1117 printf("const char *");
1118 break;
1119 case OBJECT:
1120 printf("struct %s *", a->interface_name);
1121 break;
1122 case ARRAY:
1123 printf("struct wl_array *");
1124 break;
1125 }
1126 }
1127
1128 static void
emit_stubs(struct wl_list * message_list,struct interface * interface)1129 emit_stubs(struct wl_list *message_list, struct interface *interface)
1130 {
1131 struct message *m;
1132 struct arg *a, *ret;
1133 int has_destructor, has_destroy;
1134
1135 printf("/** @ingroup iface_%s */\n", interface->name);
1136 printf("static inline void\n"
1137 "%s_set_user_data(struct %s *%s, void *user_data)\n"
1138 "{\n"
1139 "\twl_proxy_set_user_data((struct wl_proxy *) %s, user_data);\n"
1140 "}\n\n",
1141 interface->name, interface->name, interface->name,
1142 interface->name);
1143
1144 printf("/** @ingroup iface_%s */\n", interface->name);
1145 printf("static inline void *\n"
1146 "%s_get_user_data(struct %s *%s)\n"
1147 "{\n"
1148 "\treturn wl_proxy_get_user_data((struct wl_proxy *) %s);\n"
1149 "}\n\n",
1150 interface->name, interface->name, interface->name,
1151 interface->name);
1152
1153 printf("static inline uint32_t\n"
1154 "%s_get_version(struct %s *%s)\n"
1155 "{\n"
1156 "\treturn wl_proxy_get_version((struct wl_proxy *) %s);\n"
1157 "}\n\n",
1158 interface->name, interface->name, interface->name,
1159 interface->name);
1160
1161 has_destructor = 0;
1162 has_destroy = 0;
1163 wl_list_for_each(m, message_list, link) {
1164 if (m->destructor)
1165 has_destructor = 1;
1166 if (strcmp(m->name, "destroy") == 0)
1167 has_destroy = 1;
1168 }
1169
1170 if (!has_destructor && has_destroy) {
1171 fail(&interface->loc,
1172 "interface '%s' has method named destroy "
1173 "but no destructor",
1174 interface->name);
1175 exit(EXIT_FAILURE);
1176 }
1177
1178 if (!has_destroy && strcmp(interface->name, "wl_display") != 0) {
1179 printf("/** @ingroup iface_%s */\n", interface->name);
1180 printf("static inline void\n"
1181 "%s_destroy(struct %s *%s)\n"
1182 "{\n"
1183 "\twl_proxy_destroy("
1184 "(struct wl_proxy *) %s);\n"
1185 "}\n\n",
1186 interface->name, interface->name, interface->name,
1187 interface->name);
1188 }
1189
1190 if (wl_list_empty(message_list))
1191 return;
1192
1193 wl_list_for_each(m, message_list, link) {
1194 if (m->new_id_count > 1) {
1195 warn(&m->loc,
1196 "request '%s::%s' has more than "
1197 "one new_id arg, not emitting stub\n",
1198 interface->name, m->name);
1199 continue;
1200 }
1201
1202 ret = NULL;
1203 wl_list_for_each(a, &m->arg_list, link) {
1204 if (a->type == NEW_ID)
1205 ret = a;
1206 }
1207
1208 printf("/**\n"
1209 " * @ingroup iface_%s\n", interface->name);
1210 if (m->description && m->description->text)
1211 format_text_to_comment(m->description->text, false);
1212 printf(" */\n");
1213 if (ret && ret->interface_name == NULL)
1214 printf("static inline void *\n");
1215 else if (ret)
1216 printf("static inline struct %s *\n",
1217 ret->interface_name);
1218 else
1219 printf("static inline void\n");
1220
1221 printf("%s_%s(struct %s *%s",
1222 interface->name, m->name,
1223 interface->name, interface->name);
1224
1225 wl_list_for_each(a, &m->arg_list, link) {
1226 if (a->type == NEW_ID && a->interface_name == NULL) {
1227 printf(", const struct wl_interface *interface"
1228 ", uint32_t version");
1229 continue;
1230 } else if (a->type == NEW_ID)
1231 continue;
1232 printf(", ");
1233 emit_type(a);
1234 printf("%s", a->name);
1235 }
1236
1237 printf(")\n"
1238 "{\n");
1239 printf("\t");
1240 if (ret) {
1241 printf("struct wl_proxy *%s;\n\n"
1242 "\t%s = ", ret->name, ret->name);
1243 }
1244 printf("wl_proxy_marshal_flags("
1245 "(struct wl_proxy *) %s,\n"
1246 "\t\t\t %s_%s",
1247 interface->name,
1248 interface->uppercase_name,
1249 m->uppercase_name);
1250
1251 if (ret) {
1252 if (ret->interface_name) {
1253 /* Normal factory case, an arg has type="new_id" and
1254 * an interface is provided */
1255 printf(", &%s_interface", ret->interface_name);
1256 } else {
1257 /* an arg has type ="new_id" but interface is not
1258 * provided, such as in wl_registry.bind */
1259 printf(", interface");
1260 }
1261 } else {
1262 /* No args have type="new_id" */
1263 printf(", NULL");
1264 }
1265
1266 if (ret && ret->interface_name == NULL)
1267 printf(", version");
1268 else
1269 printf(", wl_proxy_get_version((struct wl_proxy *) %s)",
1270 interface->name);
1271 printf(", %s", m->destructor ? "WL_MARSHAL_FLAG_DESTROY" : "0");
1272
1273 wl_list_for_each(a, &m->arg_list, link) {
1274 if (a->type == NEW_ID) {
1275 if (a->interface_name == NULL)
1276 printf(", interface->name, version");
1277 printf(", NULL");
1278 } else {
1279 printf(", %s", a->name);
1280 }
1281 }
1282 printf(");\n");
1283
1284 if (ret && ret->interface_name == NULL)
1285 printf("\n\treturn (void *) %s;\n", ret->name);
1286 else if (ret)
1287 printf("\n\treturn (struct %s *) %s;\n",
1288 ret->interface_name, ret->name);
1289
1290 printf("}\n\n");
1291 }
1292 }
1293
1294 static void
emit_event_wrappers(struct wl_list * message_list,struct interface * interface)1295 emit_event_wrappers(struct wl_list *message_list, struct interface *interface)
1296 {
1297 struct message *m;
1298 struct arg *a;
1299
1300 /* We provide hand written functions for the display object */
1301 if (strcmp(interface->name, "wl_display") == 0)
1302 return;
1303
1304 wl_list_for_each(m, message_list, link) {
1305 printf("/**\n"
1306 " * @ingroup iface_%s\n"
1307 " * Sends an %s event to the client owning the resource.\n",
1308 interface->name,
1309 m->name);
1310 printf(" * @param resource_ The client's resource\n");
1311 wl_list_for_each(a, &m->arg_list, link) {
1312 if (a->summary)
1313 printf(" * @param %s %s\n", a->name, a->summary);
1314 }
1315 printf(" */\n");
1316 printf("static inline void\n"
1317 "%s_send_%s(struct wl_resource *resource_",
1318 interface->name, m->name);
1319
1320 wl_list_for_each(a, &m->arg_list, link) {
1321 printf(", ");
1322 switch (a->type) {
1323 case NEW_ID:
1324 case OBJECT:
1325 printf("struct wl_resource *");
1326 break;
1327 default:
1328 emit_type(a);
1329 }
1330 printf("%s", a->name);
1331 }
1332
1333 printf(")\n"
1334 "{\n"
1335 "\twl_resource_post_event(resource_, %s_%s",
1336 interface->uppercase_name, m->uppercase_name);
1337
1338 wl_list_for_each(a, &m->arg_list, link)
1339 printf(", %s", a->name);
1340
1341 printf(");\n");
1342 printf("}\n\n");
1343 }
1344 }
1345
1346 static void
emit_enumerations(struct interface * interface)1347 emit_enumerations(struct interface *interface)
1348 {
1349 struct enumeration *e;
1350 struct entry *entry;
1351
1352 wl_list_for_each(e, &interface->enumeration_list, link) {
1353 struct description *desc = e->description;
1354
1355 printf("#ifndef %s_%s_ENUM\n",
1356 interface->uppercase_name, e->uppercase_name);
1357 printf("#define %s_%s_ENUM\n",
1358 interface->uppercase_name, e->uppercase_name);
1359
1360 if (desc) {
1361 printf("/**\n");
1362 printf(" * @ingroup iface_%s\n", interface->name);
1363 format_text_to_comment(desc->summary, false);
1364 if (desc->text)
1365 format_text_to_comment(desc->text, false);
1366 printf(" */\n");
1367 }
1368 printf("enum %s_%s {\n", interface->name, e->name);
1369 wl_list_for_each(entry, &e->entry_list, link) {
1370 desc = entry->description;
1371 if (entry->summary || entry->since > 1 || desc) {
1372 printf("\t/**\n");
1373 if (entry->summary)
1374 printf("\t * %s\n", entry->summary);
1375 if (desc) {
1376 printf("\t * %s\n", desc->summary);
1377 printf("\t *\n");
1378 if (desc->text)
1379 desc_dump(desc->text, "\t * ");
1380 }
1381 if (entry->since > 1)
1382 printf("\t * @since %d\n", entry->since);
1383 printf("\t */\n");
1384 }
1385 printf("\t%s_%s_%s = %s,\n",
1386 interface->uppercase_name,
1387 e->uppercase_name,
1388 entry->uppercase_name, entry->value);
1389 }
1390 printf("};\n");
1391
1392 wl_list_for_each(entry, &e->entry_list, link) {
1393 if (entry->since == 1)
1394 continue;
1395
1396 printf("/**\n * @ingroup iface_%s\n */\n", interface->name);
1397 printf("#define %s_%s_%s_SINCE_VERSION %d\n",
1398 interface->uppercase_name,
1399 e->uppercase_name, entry->uppercase_name,
1400 entry->since);
1401
1402 }
1403
1404 printf("#endif /* %s_%s_ENUM */\n\n",
1405 interface->uppercase_name, e->uppercase_name);
1406 }
1407 }
1408
1409 static void
emit_structs(struct wl_list * message_list,struct interface * interface,enum side side)1410 emit_structs(struct wl_list *message_list, struct interface *interface, enum side side)
1411 {
1412 struct message *m;
1413 struct arg *a;
1414 int n;
1415
1416 if (wl_list_empty(message_list))
1417 return;
1418
1419 printf("/**\n");
1420 printf(" * @ingroup iface_%s\n", interface->name);
1421 printf(" * @struct %s_%s\n", interface->name,
1422 (side == SERVER) ? "interface" : "listener");
1423 printf(" */\n");
1424 printf("struct %s_%s {\n", interface->name,
1425 (side == SERVER) ? "interface" : "listener");
1426
1427 wl_list_for_each(m, message_list, link) {
1428 struct description *mdesc = m->description;
1429
1430 printf("\t/**\n");
1431 if (mdesc) {
1432 if (mdesc->summary)
1433 printf("\t * %s\n", mdesc->summary);
1434 printf("\t *\n");
1435 desc_dump(mdesc->text, "\t * ");
1436 }
1437 wl_list_for_each(a, &m->arg_list, link) {
1438 if (side == SERVER && a->type == NEW_ID &&
1439 a->interface_name == NULL)
1440 printf("\t * @param interface name of the objects interface\n"
1441 "\t * @param version version of the objects interface\n");
1442
1443 if (a->summary)
1444 printf("\t * @param %s %s\n", a->name,
1445 a->summary);
1446 }
1447 if (m->since > 1) {
1448 printf("\t * @since %d\n", m->since);
1449 }
1450 printf("\t */\n");
1451 printf("\tvoid (*%s)(", m->name);
1452
1453 n = strlen(m->name) + 17;
1454 if (side == SERVER) {
1455 printf("struct wl_client *client,\n"
1456 "%sstruct wl_resource *resource",
1457 indent(n));
1458 } else {
1459 printf("void *data,\n"),
1460 printf("%sstruct %s *%s",
1461 indent(n), interface->name, interface->name);
1462 }
1463
1464 wl_list_for_each(a, &m->arg_list, link) {
1465 printf(",\n%s", indent(n));
1466
1467 if (side == SERVER && a->type == OBJECT)
1468 printf("struct wl_resource *");
1469 else if (side == SERVER && a->type == NEW_ID && a->interface_name == NULL)
1470 printf("const char *interface, uint32_t version, uint32_t ");
1471 else if (side == CLIENT && a->type == OBJECT && a->interface_name == NULL)
1472 printf("void *");
1473
1474 else if (side == CLIENT && a->type == NEW_ID)
1475 printf("struct %s *", a->interface_name);
1476 else
1477 emit_type(a);
1478
1479 printf("%s", a->name);
1480 }
1481
1482 printf(");\n");
1483 }
1484
1485 printf("};\n\n");
1486
1487 if (side == CLIENT) {
1488 printf("/**\n"
1489 " * @ingroup iface_%s\n"
1490 " */\n", interface->name);
1491 printf("static inline int\n"
1492 "%s_add_listener(struct %s *%s,\n"
1493 "%sconst struct %s_listener *listener, void *data)\n"
1494 "{\n"
1495 "\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n"
1496 "%s(void (**)(void)) listener, data);\n"
1497 "}\n\n",
1498 interface->name, interface->name, interface->name,
1499 indent(14 + strlen(interface->name)),
1500 interface->name,
1501 interface->name,
1502 indent(37));
1503 }
1504 }
1505
1506 static void
emit_types_forward_declarations(struct protocol * protocol,struct wl_list * message_list,struct wl_array * types)1507 emit_types_forward_declarations(struct protocol *protocol,
1508 struct wl_list *message_list,
1509 struct wl_array *types)
1510 {
1511 struct message *m;
1512 struct arg *a;
1513 int length;
1514 char **p;
1515
1516 wl_list_for_each(m, message_list, link) {
1517 length = 0;
1518 m->all_null = 1;
1519 wl_list_for_each(a, &m->arg_list, link) {
1520 length++;
1521 switch (a->type) {
1522 case NEW_ID:
1523 case OBJECT:
1524 if (!a->interface_name)
1525 continue;
1526
1527 m->all_null = 0;
1528 p = fail_on_null(wl_array_add(types, sizeof *p));
1529 *p = a->interface_name;
1530 break;
1531 default:
1532 break;
1533 }
1534 }
1535
1536 if (m->all_null && length > protocol->null_run_length)
1537 protocol->null_run_length = length;
1538 }
1539 }
1540
1541 static int
cmp_names(const void * p1,const void * p2)1542 cmp_names(const void *p1, const void *p2)
1543 {
1544 const char * const *s1 = p1, * const *s2 = p2;
1545
1546 return strcmp(*s1, *s2);
1547 }
1548
1549 static const char *
get_include_name(bool core,enum side side)1550 get_include_name(bool core, enum side side)
1551 {
1552 if (side == SERVER)
1553 return core ? "wayland-server-core.h" : "wayland-server.h";
1554 else
1555 return core ? "wayland-client-core.h" : "wayland-client.h";
1556 }
1557
1558 static void
emit_mainpage_blurb(const struct protocol * protocol,enum side side)1559 emit_mainpage_blurb(const struct protocol *protocol, enum side side)
1560 {
1561 struct interface *i;
1562
1563 printf("/**\n"
1564 " * @page page_%s The %s protocol\n",
1565 protocol->name, protocol->name);
1566
1567 if (protocol->description) {
1568 if (protocol->description->summary) {
1569 printf(" * %s\n"
1570 " *\n", protocol->description->summary);
1571 }
1572
1573 if (protocol->description->text) {
1574 printf(" * @section page_desc_%s Description\n", protocol->name);
1575 format_text_to_comment(protocol->description->text, false);
1576 printf(" *\n");
1577 }
1578 }
1579
1580 printf(" * @section page_ifaces_%s Interfaces\n", protocol->name);
1581 wl_list_for_each(i, &protocol->interface_list, link) {
1582 printf(" * - @subpage page_iface_%s - %s\n",
1583 i->name,
1584 i->description && i->description->summary ? i->description->summary : "");
1585 }
1586
1587 if (protocol->copyright) {
1588 printf(" * @section page_copyright_%s Copyright\n",
1589 protocol->name);
1590 printf(" * <pre>\n");
1591 format_text_to_comment(protocol->copyright, false);
1592 printf(" * </pre>\n");
1593 }
1594
1595 printf(" */\n");
1596 }
1597
1598 static void
emit_header(struct protocol * protocol,enum side side)1599 emit_header(struct protocol *protocol, enum side side)
1600 {
1601 struct interface *i, *i_next;
1602 struct wl_array types;
1603 const char *s = (side == SERVER) ? "SERVER" : "CLIENT";
1604 char **p, *prev;
1605
1606 printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION);
1607
1608 printf("#ifndef %s_%s_PROTOCOL_H\n"
1609 "#define %s_%s_PROTOCOL_H\n"
1610 "\n"
1611 "#include <stdint.h>\n"
1612 "#include <stddef.h>\n"
1613 "#include \"%s\"\n\n"
1614 "#ifdef __cplusplus\n"
1615 "extern \"C\" {\n"
1616 "#endif\n\n",
1617 protocol->uppercase_name, s,
1618 protocol->uppercase_name, s,
1619 get_include_name(protocol->core_headers, side));
1620 if (side == SERVER)
1621 printf("struct wl_client;\n"
1622 "struct wl_resource;\n\n");
1623
1624 emit_mainpage_blurb(protocol, side);
1625
1626 wl_array_init(&types);
1627 wl_list_for_each(i, &protocol->interface_list, link) {
1628 emit_types_forward_declarations(protocol, &i->request_list, &types);
1629 emit_types_forward_declarations(protocol, &i->event_list, &types);
1630 }
1631
1632 wl_list_for_each(i, &protocol->interface_list, link) {
1633 p = fail_on_null(wl_array_add(&types, sizeof *p));
1634 *p = i->name;
1635 }
1636
1637 if (types.size > 0)
1638 qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names);
1639
1640 prev = NULL;
1641 wl_array_for_each(p, &types) {
1642 if (prev && strcmp(*p, prev) == 0)
1643 continue;
1644 printf("struct %s;\n", *p);
1645 prev = *p;
1646 }
1647 wl_array_release(&types);
1648 printf("\n");
1649
1650 wl_list_for_each(i, &protocol->interface_list, link) {
1651 printf("#ifndef %s_INTERFACE\n", i->uppercase_name);
1652 printf("#define %s_INTERFACE\n", i->uppercase_name);
1653 printf("/**\n"
1654 " * @page page_iface_%s %s\n",
1655 i->name, i->name);
1656 if (i->description && i->description->text) {
1657 printf(" * @section page_iface_%s_desc Description\n",
1658 i->name);
1659 format_text_to_comment(i->description->text, false);
1660 }
1661 printf(" * @section page_iface_%s_api API\n"
1662 " * See @ref iface_%s.\n"
1663 " */\n",
1664 i->name, i->name);
1665 printf("/**\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(i->description->text, false);
1670 printf(" */\n");
1671 printf("extern const struct wl_interface "
1672 "%s_interface;\n", i->name);
1673 printf("#endif\n");
1674 }
1675
1676 printf("\n");
1677
1678 wl_list_for_each_safe(i, i_next, &protocol->interface_list, link) {
1679
1680 emit_enumerations(i);
1681
1682 if (side == SERVER) {
1683 emit_structs(&i->request_list, i, side);
1684 emit_opcodes(&i->event_list, i);
1685 emit_opcode_versions(&i->event_list, i);
1686 emit_opcode_versions(&i->request_list, i);
1687 emit_event_wrappers(&i->event_list, i);
1688 } else {
1689 emit_structs(&i->event_list, i, side);
1690 emit_opcodes(&i->request_list, i);
1691 emit_opcode_versions(&i->event_list, i);
1692 emit_opcode_versions(&i->request_list, i);
1693 emit_stubs(&i->request_list, i);
1694 }
1695
1696 free_interface(i);
1697 }
1698
1699 printf("#ifdef __cplusplus\n"
1700 "}\n"
1701 "#endif\n"
1702 "\n"
1703 "#endif\n");
1704 }
1705
1706 static void
emit_null_run(struct protocol * protocol)1707 emit_null_run(struct protocol *protocol)
1708 {
1709 int i;
1710
1711 for (i = 0; i < protocol->null_run_length; i++)
1712 printf("\tNULL,\n");
1713 }
1714
1715 static void
emit_types(struct protocol * protocol,struct wl_list * message_list)1716 emit_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("\t&%s_interface,\n",
1737 a->interface_name);
1738 else
1739 printf("\tNULL,\n");
1740 break;
1741 default:
1742 printf("\tNULL,\n");
1743 break;
1744 }
1745 }
1746 }
1747 }
1748
1749 static void
emit_messages(const char * name,struct wl_list * message_list,struct interface * interface,const char * suffix)1750 emit_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(message_list))
1757 return;
1758
1759 printf("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("\t{ \"%s\", \"", m->name);
1765
1766 if (m->since > 1)
1767 printf("%d", m->since);
1768
1769 wl_list_for_each(a, &m->arg_list, link) {
1770 if (is_nullable_type(a) && a->nullable)
1771 printf("?");
1772
1773 switch (a->type) {
1774 default:
1775 case INT:
1776 printf("i");
1777 break;
1778 case NEW_ID:
1779 if (a->interface_name == NULL)
1780 printf("su");
1781 printf("n");
1782 break;
1783 case UNSIGNED:
1784 printf("u");
1785 break;
1786 case FIXED:
1787 printf("f");
1788 break;
1789 case STRING:
1790 printf("s");
1791 break;
1792 case OBJECT:
1793 printf("o");
1794 break;
1795 case ARRAY:
1796 printf("a");
1797 break;
1798 case FD:
1799 printf("h");
1800 break;
1801 }
1802 }
1803 printf("\", %s_types + %d },\n", name, m->type_index);
1804 }
1805
1806 printf("};\n\n");
1807 }
1808
1809
1810 static void
emit_code(struct protocol * protocol,enum visibility vis)1811 emit_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("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION);
1819
1820 if (protocol->copyright)
1821 format_text_to_comment(protocol->copyright, true);
1822
1823 printf("#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("#ifndef __has_attribute\n"
1832 "# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */\n"
1833 "#endif\n\n");
1834
1835 printf("#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(&types);
1845 wl_list_for_each(i, &protocol->interface_list, link) {
1846 emit_types_forward_declarations(protocol, &i->request_list, &types);
1847 emit_types_forward_declarations(protocol, &i->event_list, &types);
1848 }
1849
1850 if (types.size > 0)
1851 qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names);
1852
1853 prev = NULL;
1854 wl_array_for_each(p, &types) {
1855 if (prev && strcmp(*p, prev) == 0)
1856 continue;
1857 printf("extern const struct wl_interface %s_interface;\n", *p);
1858 prev = *p;
1859 }
1860 wl_array_release(&types);
1861 printf("\n");
1862
1863 printf("static const struct wl_interface *%s_types[] = {\n", protocol->name);
1864 emit_null_run(protocol);
1865 wl_list_for_each(i, &protocol->interface_list, link) {
1866 emit_types(protocol, &i->request_list);
1867 emit_types(protocol, &i->event_list);
1868 }
1869 printf("};\n\n");
1870
1871 wl_list_for_each_safe(i, next, &protocol->interface_list, link) {
1872
1873 emit_messages(protocol->name, &i->request_list, i, "requests");
1874 emit_messages(protocol->name, &i->event_list, i, "events");
1875
1876 printf("%s const struct wl_interface "
1877 "%s_interface = {\n"
1878 "\t\"%s\", %d,\n",
1879 symbol_visibility, i->name, i->name, i->version);
1880
1881 if (!wl_list_empty(&i->request_list))
1882 printf("\t%d, %s_requests,\n",
1883 wl_list_length(&i->request_list), i->name);
1884 else
1885 printf("\t0, NULL,\n");
1886
1887 if (!wl_list_empty(&i->event_list))
1888 printf("\t%d, %s_events,\n",
1889 wl_list_length(&i->event_list), i->name);
1890 else
1891 printf("\t0, NULL,\n");
1892
1893 printf("};\n\n");
1894
1895 /* we won't need it any further */
1896 free_interface(i);
1897 }
1898 }
1899
1900 static void
free_protocol(struct protocol * protocol)1901 free_protocol(struct protocol *protocol)
1902 {
1903 free(protocol->name);
1904 free(protocol->uppercase_name);
1905 free(protocol->copyright);
1906 free_description(protocol->description);
1907 }
1908
main(int argc,char * argv[])1909 int main(int argc, char *argv[])
1910 {
1911 struct parse_context ctx;
1912 struct protocol protocol;
1913 FILE *input = stdin;
1914 char *input_filename = NULL;
1915 int len;
1916 void *buf;
1917 bool help = false;
1918 bool core_headers = false;
1919 bool version = false;
1920 bool strict = false;
1921 bool fail = false;
1922 int opt;
1923 enum {
1924 CLIENT_HEADER,
1925 SERVER_HEADER,
1926 PRIVATE_CODE,
1927 PUBLIC_CODE,
1928 CODE,
1929 } mode;
1930
1931 static const struct option options[] = {
1932 { "help", no_argument, NULL, 'h' },
1933 { "version", no_argument, NULL, 'v' },
1934 { "include-core-only", no_argument, NULL, 'c' },
1935 { "strict", no_argument, NULL, 's' },
1936 { 0, 0, NULL, 0 }
1937 };
1938
1939 while (1) {
1940 opt = getopt_long(argc, argv, "hvcs", options, NULL);
1941
1942 if (opt == -1)
1943 break;
1944
1945 switch (opt) {
1946 case 'h':
1947 help = true;
1948 break;
1949 case 'v':
1950 version = true;
1951 break;
1952 case 'c':
1953 core_headers = true;
1954 break;
1955 case 's':
1956 strict = true;
1957 break;
1958 default:
1959 fail = true;
1960 break;
1961 }
1962 }
1963
1964 argv += optind;
1965 argc -= optind;
1966
1967 if (help)
1968 usage(EXIT_SUCCESS);
1969 else if (version)
1970 scanner_version(EXIT_SUCCESS);
1971 else if ((argc != 1 && argc != 3) || fail)
1972 usage(EXIT_FAILURE);
1973 else if (strcmp(argv[0], "help") == 0)
1974 usage(EXIT_SUCCESS);
1975 else if (strcmp(argv[0], "client-header") == 0)
1976 mode = CLIENT_HEADER;
1977 else if (strcmp(argv[0], "server-header") == 0)
1978 mode = SERVER_HEADER;
1979 else if (strcmp(argv[0], "private-code") == 0)
1980 mode = PRIVATE_CODE;
1981 else if (strcmp(argv[0], "public-code") == 0)
1982 mode = PUBLIC_CODE;
1983 else if (strcmp(argv[0], "code") == 0)
1984 mode = CODE;
1985 else
1986 usage(EXIT_FAILURE);
1987
1988 if (argc == 3) {
1989 input_filename = argv[1];
1990 input = fopen(input_filename, "r");
1991 if (input == NULL) {
1992 fprintf(stderr, "Could not open input file: %s\n",
1993 strerror(errno));
1994 exit(EXIT_FAILURE);
1995 }
1996 if (freopen(argv[2], "w", stdout) == NULL) {
1997 fprintf(stderr, "Could not open output file: %s\n",
1998 strerror(errno));
1999 fclose(input);
2000 exit(EXIT_FAILURE);
2001 }
2002 }
2003
2004 /* initialize protocol structure */
2005 memset(&protocol, 0, sizeof protocol);
2006 wl_list_init(&protocol.interface_list);
2007 protocol.core_headers = core_headers;
2008
2009 /* initialize context */
2010 memset(&ctx, 0, sizeof ctx);
2011 ctx.protocol = &protocol;
2012 if (input == stdin)
2013 ctx.loc.filename = "<stdin>";
2014 else
2015 ctx.loc.filename = input_filename;
2016
2017 if (!is_dtd_valid(input, ctx.loc.filename)) {
2018 fprintf(stderr,
2019 "*******************************************************\n"
2020 "* *\n"
2021 "* WARNING: XML failed validation against built-in DTD *\n"
2022 "* *\n"
2023 "*******************************************************\n");
2024 if (strict) {
2025 fclose(input);
2026 exit(EXIT_FAILURE);
2027 }
2028 }
2029
2030 /* create XML parser */
2031 ctx.parser = XML_ParserCreate(NULL);
2032 XML_SetUserData(ctx.parser, &ctx);
2033 if (ctx.parser == NULL) {
2034 fprintf(stderr, "failed to create parser\n");
2035 fclose(input);
2036 exit(EXIT_FAILURE);
2037 }
2038
2039 XML_SetElementHandler(ctx.parser, start_element, end_element);
2040 XML_SetCharacterDataHandler(ctx.parser, character_data);
2041
2042 do {
2043 buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
2044 len = fread(buf, 1, XML_BUFFER_SIZE, input);
2045 if (len < 0) {
2046 fprintf(stderr, "fread: %s\n", strerror(errno));
2047 fclose(input);
2048 exit(EXIT_FAILURE);
2049 }
2050 if (XML_ParseBuffer(ctx.parser, len, len == 0) == 0) {
2051 fprintf(stderr,
2052 "Error parsing XML at line %ld col %ld: %s\n",
2053 XML_GetCurrentLineNumber(ctx.parser),
2054 XML_GetCurrentColumnNumber(ctx.parser),
2055 XML_ErrorString(XML_GetErrorCode(ctx.parser)));
2056 fclose(input);
2057 exit(EXIT_FAILURE);
2058 }
2059 } while (len > 0);
2060
2061 XML_ParserFree(ctx.parser);
2062
2063 switch (mode) {
2064 case CLIENT_HEADER:
2065 emit_header(&protocol, CLIENT);
2066 break;
2067 case SERVER_HEADER:
2068 emit_header(&protocol, SERVER);
2069 break;
2070 case PRIVATE_CODE:
2071 emit_code(&protocol, PRIVATE);
2072 break;
2073 case CODE:
2074 fprintf(stderr,
2075 "Using \"code\" is deprecated - use "
2076 "private-code or public-code.\n"
2077 "See the help page for details.\n");
2078 /* fallthrough */
2079 case PUBLIC_CODE:
2080 emit_code(&protocol, PUBLIC);
2081 break;
2082 }
2083
2084 free_protocol(&protocol);
2085 fclose(input);
2086
2087 return 0;
2088 }
2089