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