1 2 #include "aidl_language.h" 3 #include "options.h" 4 #include "search_path.h" 5 #include "Type.h" 6 #include "generate_java.h" 7 #include <unistd.h> 8 #include <fcntl.h> 9 #include <sys/param.h> 10 #include <sys/stat.h> 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <map> 16 17 #ifdef HAVE_MS_C_RUNTIME 18 #include <io.h> 19 #include <sys/stat.h> 20 #endif 21 22 #ifndef O_BINARY 23 # define O_BINARY 0 24 #endif 25 26 using namespace std; 27 28 static void 29 test_document(document_item_type* d) 30 { 31 while (d) { 32 if (d->item_type == INTERFACE_TYPE_BINDER) { 33 interface_type* c = (interface_type*)d; 34 printf("interface %s %s {\n", c->package, c->name.data); 35 interface_item_type *q = (interface_item_type*)c->interface_items; 36 while (q) { 37 if (q->item_type == METHOD_TYPE) { 38 method_type *m = (method_type*)q; 39 printf(" %s %s(", m->type.type.data, m->name.data); 40 arg_type *p = m->args; 41 while (p) { 42 printf("%s %s",p->type.type.data,p->name.data); 43 if (p->next) printf(", "); 44 p=p->next; 45 } 46 printf(")"); 47 printf(";\n"); 48 } 49 q=q->next; 50 } 51 printf("}\n"); 52 } 53 else if (d->item_type == USER_DATA_TYPE) { 54 user_data_type* b = (user_data_type*)d; 55 if ((b->flattening_methods & PARCELABLE_DATA) != 0) { 56 printf("parcelable %s %s;\n", b->package, b->name.data); 57 } 58 if ((b->flattening_methods & RPC_DATA) != 0) { 59 printf("flattenable %s %s;\n", b->package, b->name.data); 60 } 61 } 62 else { 63 printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type); 64 } 65 d = d->next; 66 } 67 } 68 69 // ========================================================== 70 int 71 convert_direction(const char* direction) 72 { 73 if (direction == NULL) { 74 return IN_PARAMETER; 75 } 76 if (0 == strcmp(direction, "in")) { 77 return IN_PARAMETER; 78 } 79 if (0 == strcmp(direction, "out")) { 80 return OUT_PARAMETER; 81 } 82 return INOUT_PARAMETER; 83 } 84 85 // ========================================================== 86 struct import_info { 87 const char* from; 88 const char* filename; 89 buffer_type statement; 90 const char* neededClass; 91 document_item_type* doc; 92 struct import_info* next; 93 }; 94 95 document_item_type* g_document = NULL; 96 import_info* g_imports = NULL; 97 98 static void 99 main_document_parsed(document_item_type* d) 100 { 101 g_document = d; 102 } 103 104 static void 105 main_import_parsed(buffer_type* statement) 106 { 107 import_info* import = (import_info*)malloc(sizeof(import_info)); 108 memset(import, 0, sizeof(import_info)); 109 import->from = strdup(g_currentFilename); 110 import->statement.lineno = statement->lineno; 111 import->statement.data = strdup(statement->data); 112 import->statement.extra = NULL; 113 import->next = g_imports; 114 import->neededClass = parse_import_statement(statement->data); 115 g_imports = import; 116 } 117 118 static ParserCallbacks g_mainCallbacks = { 119 &main_document_parsed, 120 &main_import_parsed 121 }; 122 123 char* 124 parse_import_statement(const char* text) 125 { 126 const char* end; 127 int len; 128 129 while (isspace(*text)) { 130 text++; 131 } 132 while (!isspace(*text)) { 133 text++; 134 } 135 while (isspace(*text)) { 136 text++; 137 } 138 end = text; 139 while (!isspace(*end) && *end != ';') { 140 end++; 141 } 142 len = end-text; 143 144 char* rv = (char*)malloc(len+1); 145 memcpy(rv, text, len); 146 rv[len] = '\0'; 147 148 return rv; 149 } 150 151 // ========================================================== 152 static void 153 import_import_parsed(buffer_type* statement) 154 { 155 } 156 157 static ParserCallbacks g_importCallbacks = { 158 &main_document_parsed, 159 &import_import_parsed 160 }; 161 162 // ========================================================== 163 static int 164 check_filename(const char* filename, const char* package, buffer_type* name) 165 { 166 const char* p; 167 string expected; 168 string fn; 169 size_t len; 170 char cwd[MAXPATHLEN]; 171 bool valid = false; 172 173 #ifdef HAVE_WINDOWS_PATHS 174 if (isalpha(filename[0]) && filename[1] == ':' 175 && filename[2] == OS_PATH_SEPARATOR) { 176 #else 177 if (filename[0] == OS_PATH_SEPARATOR) { 178 #endif 179 fn = filename; 180 } else { 181 fn = getcwd(cwd, sizeof(cwd)); 182 len = fn.length(); 183 if (fn[len-1] != OS_PATH_SEPARATOR) { 184 fn += OS_PATH_SEPARATOR; 185 } 186 fn += filename; 187 } 188 189 if (package) { 190 expected = package; 191 expected += '.'; 192 } 193 194 len = expected.length(); 195 for (size_t i=0; i<len; i++) { 196 if (expected[i] == '.') { 197 expected[i] = OS_PATH_SEPARATOR; 198 } 199 } 200 201 p = strchr(name->data, '.'); 202 len = p ? p-name->data : strlen(name->data); 203 expected.append(name->data, len); 204 205 expected += ".aidl"; 206 207 len = fn.length(); 208 valid = (len >= expected.length()); 209 210 if (valid) { 211 p = fn.c_str() + (len - expected.length()); 212 213 #ifdef HAVE_WINDOWS_PATHS 214 if (OS_PATH_SEPARATOR != '/') { 215 // Input filename under cygwin most likely has / separators 216 // whereas the expected string uses \\ separators. Adjust 217 // them accordingly. 218 for (char *c = const_cast<char *>(p); *c; ++c) { 219 if (*c == '/') *c = OS_PATH_SEPARATOR; 220 } 221 } 222 #endif 223 224 #ifdef OS_CASE_SENSITIVE 225 valid = (expected == p); 226 #else 227 valid = !strcasecmp(expected.c_str(), p); 228 #endif 229 } 230 231 if (!valid) { 232 fprintf(stderr, "%s:%d interface %s should be declared in a file" 233 " called %s.\n", 234 filename, name->lineno, name->data, expected.c_str()); 235 return 1; 236 } 237 238 return 0; 239 } 240 241 static int 242 check_filenames(const char* filename, document_item_type* items) 243 { 244 int err = 0; 245 while (items) { 246 if (items->item_type == USER_DATA_TYPE) { 247 user_data_type* p = (user_data_type*)items; 248 err |= check_filename(filename, p->package, &p->name); 249 } 250 else if (items->item_type == INTERFACE_TYPE_BINDER 251 || items->item_type == INTERFACE_TYPE_RPC) { 252 interface_type* c = (interface_type*)items; 253 err |= check_filename(filename, c->package, &c->name); 254 } 255 else { 256 fprintf(stderr, "aidl: internal error unkown document type %d.\n", 257 items->item_type); 258 return 1; 259 } 260 items = items->next; 261 } 262 return err; 263 } 264 265 // ========================================================== 266 static const char* 267 kind_to_string(int kind) 268 { 269 switch (kind) 270 { 271 case Type::INTERFACE: 272 return "an interface"; 273 case Type::USERDATA: 274 return "a user data"; 275 default: 276 return "ERROR"; 277 } 278 } 279 280 static char* 281 rfind(char* str, char c) 282 { 283 char* p = str + strlen(str) - 1; 284 while (p >= str) { 285 if (*p == c) { 286 return p; 287 } 288 p--; 289 } 290 return NULL; 291 } 292 293 static int 294 gather_types(const char* filename, document_item_type* items) 295 { 296 int err = 0; 297 while (items) { 298 Type* type; 299 if (items->item_type == USER_DATA_TYPE) { 300 user_data_type* p = (user_data_type*)items; 301 type = new UserDataType(p->package ? p->package : "", p->name.data, 302 false, ((p->flattening_methods & PARCELABLE_DATA) != 0), 303 ((p->flattening_methods & RPC_DATA) != 0), filename, p->name.lineno); 304 } 305 else if (items->item_type == INTERFACE_TYPE_BINDER 306 || items->item_type == INTERFACE_TYPE_RPC) { 307 interface_type* c = (interface_type*)items; 308 type = new InterfaceType(c->package ? c->package : "", 309 c->name.data, false, c->oneway, 310 filename, c->name.lineno); 311 } 312 else { 313 fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__); 314 return 1; 315 } 316 317 Type* old = NAMES.Find(type->QualifiedName()); 318 if (old == NULL) { 319 NAMES.Add(type); 320 321 if (items->item_type == INTERFACE_TYPE_BINDER) { 322 // for interfaces, also add the stub and proxy types, we don't 323 // bother checking these for duplicates, because the parser 324 // won't let us do it. 325 interface_type* c = (interface_type*)items; 326 327 string name = c->name.data; 328 name += ".Stub"; 329 Type* stub = new Type(c->package ? c->package : "", 330 name, Type::GENERATED, false, false, false, 331 filename, c->name.lineno); 332 NAMES.Add(stub); 333 334 name = c->name.data; 335 name += ".Stub.Proxy"; 336 Type* proxy = new Type(c->package ? c->package : "", 337 name, Type::GENERATED, false, false, false, 338 filename, c->name.lineno); 339 NAMES.Add(proxy); 340 } 341 else if (items->item_type == INTERFACE_TYPE_RPC) { 342 // for interfaces, also add the service base type, we don't 343 // bother checking these for duplicates, because the parser 344 // won't let us do it. 345 interface_type* c = (interface_type*)items; 346 347 string name = c->name.data; 348 name += ".ServiceBase"; 349 Type* base = new Type(c->package ? c->package : "", 350 name, Type::GENERATED, false, false, false, 351 filename, c->name.lineno); 352 NAMES.Add(base); 353 } 354 } else { 355 if (old->Kind() == Type::BUILT_IN) { 356 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n", 357 filename, type->DeclLine(), 358 type->QualifiedName().c_str()); 359 err = 1; 360 } 361 else if (type->Kind() != old->Kind()) { 362 const char* oldKind = kind_to_string(old->Kind()); 363 const char* newKind = kind_to_string(type->Kind()); 364 365 fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n", 366 filename, type->DeclLine(), 367 type->QualifiedName().c_str(), newKind); 368 fprintf(stderr, "%s:%d previously defined here as %s.\n", 369 old->DeclFile().c_str(), old->DeclLine(), oldKind); 370 err = 1; 371 } 372 } 373 374 items = items->next; 375 } 376 return err; 377 } 378 379 // ========================================================== 380 static bool 381 matches_keyword(const char* str) 382 { 383 static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break", 384 "byte", "case", "catch", "char", "class", "const", "continue", 385 "default", "do", "double", "else", "enum", "extends", "final", 386 "finally", "float", "for", "goto", "if", "implements", "import", 387 "instanceof", "int", "interface", "long", "native", "new", "package", 388 "private", "protected", "public", "return", "short", "static", 389 "strictfp", "super", "switch", "synchronized", "this", "throw", 390 "throws", "transient", "try", "void", "volatile", "while", 391 "true", "false", "null", 392 NULL 393 }; 394 const char** k = KEYWORDS; 395 while (*k) { 396 if (0 == strcmp(str, *k)) { 397 return true; 398 } 399 k++; 400 } 401 return false; 402 } 403 404 static int 405 check_method(const char* filename, int kind, method_type* m) 406 { 407 int err = 0; 408 409 // return type 410 Type* returnType = NAMES.Search(m->type.type.data); 411 if (returnType == NULL) { 412 fprintf(stderr, "%s:%d unknown return type %s\n", filename, 413 m->type.type.lineno, m->type.type.data); 414 err = 1; 415 return err; 416 } 417 418 if (returnType == EVENT_FAKE_TYPE) { 419 if (kind != INTERFACE_TYPE_RPC) { 420 fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n", 421 filename, m->type.type.lineno); 422 err = 1; 423 } 424 } else { 425 if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel() 426 : returnType->CanWriteToRpcData())) { 427 fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename, 428 m->type.type.lineno, m->type.type.data); 429 err = 1; 430 } 431 } 432 433 if (m->type.dimension > 0 && !returnType->CanBeArray()) { 434 fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename, 435 m->type.array_token.lineno, m->type.type.data, 436 m->type.array_token.data); 437 err = 1; 438 } 439 440 if (m->type.dimension > 1) { 441 fprintf(stderr, "%s:%d return type %s%s only one" 442 " dimensional arrays are supported\n", filename, 443 m->type.array_token.lineno, m->type.type.data, 444 m->type.array_token.data); 445 err = 1; 446 } 447 448 int index = 1; 449 450 arg_type* arg = m->args; 451 while (arg) { 452 Type* t = NAMES.Search(arg->type.type.data); 453 454 // check the arg type 455 if (t == NULL) { 456 fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n", 457 filename, m->type.type.lineno, arg->name.data, index, 458 arg->type.type.data); 459 err = 1; 460 goto next; 461 } 462 463 if (t == EVENT_FAKE_TYPE) { 464 fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n", 465 filename, m->type.type.lineno, arg->name.data, index, 466 arg->type.type.data); 467 err = 1; 468 goto next; 469 } 470 471 if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) { 472 fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n", 473 filename, m->type.type.lineno, index, 474 arg->type.type.data, arg->name.data); 475 err = 1; 476 } 477 478 if (returnType == EVENT_FAKE_TYPE 479 && convert_direction(arg->direction.data) != IN_PARAMETER) { 480 fprintf(stderr, "%s:%d parameter %d: '%s %s' All paremeters on events must be 'in'.\n", 481 filename, m->type.type.lineno, index, 482 arg->type.type.data, arg->name.data); 483 err = 1; 484 goto next; 485 } 486 487 if (arg->direction.data == NULL 488 && (arg->type.dimension != 0 || t->CanBeOutParameter())) { 489 fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out" 490 " parameter, so you must declare it as in," 491 " out or inout.\n", 492 filename, m->type.type.lineno, index, 493 arg->type.type.data, arg->name.data); 494 err = 1; 495 } 496 497 if (convert_direction(arg->direction.data) != IN_PARAMETER 498 && !t->CanBeOutParameter() 499 && arg->type.dimension == 0) { 500 fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in" 501 " parameter.\n", 502 filename, m->type.type.lineno, index, 503 arg->direction.data, arg->type.type.data, 504 arg->name.data); 505 err = 1; 506 } 507 508 if (arg->type.dimension > 0 && !t->CanBeArray()) { 509 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an" 510 " array.\n", filename, 511 m->type.array_token.lineno, index, arg->direction.data, 512 arg->type.type.data, arg->type.array_token.data, 513 arg->name.data); 514 err = 1; 515 } 516 517 if (arg->type.dimension > 1) { 518 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one" 519 " dimensional arrays are supported\n", filename, 520 m->type.array_token.lineno, index, arg->direction.data, 521 arg->type.type.data, arg->type.array_token.data, 522 arg->name.data); 523 err = 1; 524 } 525 526 // check that the name doesn't match a keyword 527 if (matches_keyword(arg->name.data)) { 528 fprintf(stderr, "%s:%d parameter %d %s is named the same as a" 529 " Java or aidl keyword\n", 530 filename, m->name.lineno, index, arg->name.data); 531 err = 1; 532 } 533 534 next: 535 index++; 536 arg = arg->next; 537 } 538 539 return err; 540 } 541 542 static int 543 check_types(const char* filename, document_item_type* items) 544 { 545 int err = 0; 546 while (items) { 547 // (nothing to check for USER_DATA_TYPE) 548 if (items->item_type == INTERFACE_TYPE_BINDER 549 || items->item_type == INTERFACE_TYPE_RPC) { 550 map<string,method_type*> methodNames; 551 interface_type* c = (interface_type*)items; 552 553 interface_item_type* member = c->interface_items; 554 while (member) { 555 if (member->item_type == METHOD_TYPE) { 556 method_type* m = (method_type*)member; 557 558 err |= check_method(filename, items->item_type, m); 559 560 // prevent duplicate methods 561 if (methodNames.find(m->name.data) == methodNames.end()) { 562 methodNames[m->name.data] = m; 563 } else { 564 fprintf(stderr,"%s:%d attempt to redefine method %s,\n", 565 filename, m->name.lineno, m->name.data); 566 method_type* old = methodNames[m->name.data]; 567 fprintf(stderr, "%s:%d previously defined here.\n", 568 filename, old->name.lineno); 569 err = 1; 570 } 571 } 572 member = member->next; 573 } 574 } 575 576 items = items->next; 577 } 578 return err; 579 } 580 581 // ========================================================== 582 static int 583 exactly_one_interface(const char* filename, const document_item_type* items, const Options& options, 584 bool* onlyParcelable) 585 { 586 if (items == NULL) { 587 fprintf(stderr, "%s: file does not contain any interfaces\n", 588 filename); 589 return 1; 590 } 591 592 const document_item_type* next = items->next; 593 // Allow parcelables to skip the "one-only" rule. 594 if (items->next != NULL && next->item_type != USER_DATA_TYPE) { 595 int lineno = -1; 596 if (next->item_type == INTERFACE_TYPE_BINDER) { 597 lineno = ((interface_type*)next)->interface_token.lineno; 598 } 599 else if (next->item_type == INTERFACE_TYPE_RPC) { 600 lineno = ((interface_type*)next)->interface_token.lineno; 601 } 602 fprintf(stderr, "%s:%d aidl can only handle one interface per file\n", 603 filename, lineno); 604 return 1; 605 } 606 607 if (items->item_type == USER_DATA_TYPE) { 608 *onlyParcelable = true; 609 if (options.failOnParcelable) { 610 fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not" 611 " parcelables or flattenables,\n", filename, 612 ((user_data_type*)items)->keyword_token.lineno); 613 fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables" 614 "may not go in the Makefile.\n", filename, 615 ((user_data_type*)items)->keyword_token.lineno); 616 return 1; 617 } 618 } else { 619 *onlyParcelable = false; 620 } 621 622 return 0; 623 } 624 625 // ========================================================== 626 void 627 generate_dep_file(const Options& options, const document_item_type* items) 628 { 629 /* we open the file in binary mode to ensure that the same output is 630 * generated on all platforms !! 631 */ 632 FILE* to = NULL; 633 if (options.autoDepFile) { 634 string fileName = options.outputFileName + ".d"; 635 to = fopen(fileName.c_str(), "wb"); 636 } else { 637 to = fopen(options.depFileName.c_str(), "wb"); 638 } 639 640 if (to == NULL) { 641 return; 642 } 643 644 const char* slash = "\\"; 645 import_info* import = g_imports; 646 if (import == NULL) { 647 slash = ""; 648 } 649 650 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) { 651 fprintf(to, "%s: \\\n", options.outputFileName.c_str()); 652 } else { 653 // parcelable: there's no output file. 654 fprintf(to, " : \\\n"); 655 } 656 fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash); 657 658 while (import) { 659 if (import->next == NULL) { 660 slash = ""; 661 } 662 if (import->filename) { 663 fprintf(to, " %s %s\n", import->filename, slash); 664 } 665 import = import->next; 666 } 667 668 fprintf(to, "\n"); 669 670 fclose(to); 671 } 672 673 // ========================================================== 674 static string 675 generate_outputFileName2(const Options& options, const buffer_type& name, const char* package) 676 { 677 string result; 678 679 // create the path to the destination folder based on the 680 // interface package name 681 result = options.outputBaseFolder; 682 result += OS_PATH_SEPARATOR; 683 684 string packageStr = package; 685 size_t len = packageStr.length(); 686 for (size_t i=0; i<len; i++) { 687 if (packageStr[i] == '.') { 688 packageStr[i] = OS_PATH_SEPARATOR; 689 } 690 } 691 692 result += packageStr; 693 694 // add the filename by replacing the .aidl extension to .java 695 const char* p = strchr(name.data, '.'); 696 len = p ? p-name.data : strlen(name.data); 697 698 result += OS_PATH_SEPARATOR; 699 result.append(name.data, len); 700 result += ".java"; 701 702 return result; 703 } 704 705 // ========================================================== 706 static string 707 generate_outputFileName(const Options& options, const document_item_type* items) 708 { 709 // items has already been checked to have only one interface. 710 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) { 711 interface_type* type = (interface_type*)items; 712 713 return generate_outputFileName2(options, type->name, type->package); 714 } else if (items->item_type == USER_DATA_TYPE) { 715 user_data_type* type = (user_data_type*)items; 716 return generate_outputFileName2(options, type->name, type->package); 717 } 718 719 // I don't think we can come here, but safer than returning NULL. 720 string result; 721 return result; 722 } 723 724 725 726 // ========================================================== 727 static void 728 check_outputFilePath(const string& path) { 729 size_t len = path.length(); 730 for (size_t i=0; i<len ; i++) { 731 if (path[i] == OS_PATH_SEPARATOR) { 732 string p = path.substr(0, i); 733 if (access(path.data(), F_OK) != 0) { 734 #ifdef HAVE_MS_C_RUNTIME 735 _mkdir(p.data()); 736 #else 737 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP); 738 #endif 739 } 740 } 741 } 742 } 743 744 745 // ========================================================== 746 static int 747 parse_preprocessed_file(const string& filename) 748 { 749 int err; 750 751 FILE* f = fopen(filename.c_str(), "rb"); 752 if (f == NULL) { 753 fprintf(stderr, "aidl: can't open preprocessed file: %s\n", 754 filename.c_str()); 755 return 1; 756 } 757 758 int lineno = 1; 759 char line[1024]; 760 char type[1024]; 761 char fullname[1024]; 762 while (fgets(line, sizeof(line), f)) { 763 // skip comments and empty lines 764 if (!line[0] || strncmp(line, "//", 2) == 0) { 765 continue; 766 } 767 768 sscanf(line, "%s %[^; \r\n\t];", type, fullname); 769 770 char* packagename; 771 char* classname = rfind(fullname, '.'); 772 if (classname != NULL) { 773 *classname = '\0'; 774 classname++; 775 packagename = fullname; 776 } else { 777 classname = fullname; 778 packagename = NULL; 779 } 780 781 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno, 782 // type, packagename, classname); 783 document_item_type* doc; 784 785 if (0 == strcmp("parcelable", type)) { 786 user_data_type* parcl = (user_data_type*)malloc( 787 sizeof(user_data_type)); 788 memset(parcl, 0, sizeof(user_data_type)); 789 parcl->document_item.item_type = USER_DATA_TYPE; 790 parcl->keyword_token.lineno = lineno; 791 parcl->keyword_token.data = strdup(type); 792 parcl->package = packagename ? strdup(packagename) : NULL; 793 parcl->name.lineno = lineno; 794 parcl->name.data = strdup(classname); 795 parcl->semicolon_token.lineno = lineno; 796 parcl->semicolon_token.data = strdup(";"); 797 parcl->flattening_methods = PARCELABLE_DATA; 798 doc = (document_item_type*)parcl; 799 } 800 else if (0 == strcmp("flattenable", type)) { 801 user_data_type* parcl = (user_data_type*)malloc( 802 sizeof(user_data_type)); 803 memset(parcl, 0, sizeof(user_data_type)); 804 parcl->document_item.item_type = USER_DATA_TYPE; 805 parcl->keyword_token.lineno = lineno; 806 parcl->keyword_token.data = strdup(type); 807 parcl->package = packagename ? strdup(packagename) : NULL; 808 parcl->name.lineno = lineno; 809 parcl->name.data = strdup(classname); 810 parcl->semicolon_token.lineno = lineno; 811 parcl->semicolon_token.data = strdup(";"); 812 parcl->flattening_methods = RPC_DATA; 813 doc = (document_item_type*)parcl; 814 } 815 else if (0 == strcmp("interface", type)) { 816 interface_type* iface = (interface_type*)malloc( 817 sizeof(interface_type)); 818 memset(iface, 0, sizeof(interface_type)); 819 iface->document_item.item_type = INTERFACE_TYPE_BINDER; 820 iface->interface_token.lineno = lineno; 821 iface->interface_token.data = strdup(type); 822 iface->package = packagename ? strdup(packagename) : NULL; 823 iface->name.lineno = lineno; 824 iface->name.data = strdup(classname); 825 iface->open_brace_token.lineno = lineno; 826 iface->open_brace_token.data = strdup("{"); 827 iface->close_brace_token.lineno = lineno; 828 iface->close_brace_token.data = strdup("}"); 829 doc = (document_item_type*)iface; 830 } 831 else { 832 fprintf(stderr, "%s:%d: bad type in line: %s\n", 833 filename.c_str(), lineno, line); 834 return 1; 835 } 836 err = gather_types(filename.c_str(), doc); 837 lineno++; 838 } 839 840 if (!feof(f)) { 841 fprintf(stderr, "%s:%d: error reading file, line to long.\n", 842 filename.c_str(), lineno); 843 return 1; 844 } 845 846 fclose(f); 847 return 0; 848 } 849 850 // ========================================================== 851 static int 852 compile_aidl(Options& options) 853 { 854 int err = 0, N; 855 856 set_import_paths(options.importPaths); 857 858 register_base_types(); 859 860 // import the preprocessed file 861 N = options.preprocessedFiles.size(); 862 for (int i=0; i<N; i++) { 863 const string& s = options.preprocessedFiles[i]; 864 err |= parse_preprocessed_file(s); 865 } 866 if (err != 0) { 867 return err; 868 } 869 870 // parse the main file 871 g_callbacks = &g_mainCallbacks; 872 err = parse_aidl(options.inputFileName.c_str()); 873 document_item_type* mainDoc = g_document; 874 g_document = NULL; 875 876 // parse the imports 877 g_callbacks = &g_mainCallbacks; 878 import_info* import = g_imports; 879 while (import) { 880 if (NAMES.Find(import->neededClass) == NULL) { 881 import->filename = find_import_file(import->neededClass); 882 if (!import->filename) { 883 fprintf(stderr, "%s:%d: couldn't find import for class %s\n", 884 import->from, import->statement.lineno, 885 import->neededClass); 886 err |= 1; 887 } else { 888 err |= parse_aidl(import->filename); 889 import->doc = g_document; 890 if (import->doc == NULL) { 891 err |= 1; 892 } 893 } 894 } 895 import = import->next; 896 } 897 // bail out now if parsing wasn't successful 898 if (err != 0 || mainDoc == NULL) { 899 //fprintf(stderr, "aidl: parsing failed, stopping.\n"); 900 return 1; 901 } 902 903 // complain about ones that aren't in the right files 904 err |= check_filenames(options.inputFileName.c_str(), mainDoc); 905 import = g_imports; 906 while (import) { 907 err |= check_filenames(import->filename, import->doc); 908 import = import->next; 909 } 910 911 // gather the types that have been declared 912 err |= gather_types(options.inputFileName.c_str(), mainDoc); 913 import = g_imports; 914 while (import) { 915 err |= gather_types(import->filename, import->doc); 916 import = import->next; 917 } 918 919 #if 0 920 printf("---- main doc ----\n"); 921 test_document(mainDoc); 922 923 import = g_imports; 924 while (import) { 925 printf("---- import doc ----\n"); 926 test_document(import->doc); 927 import = import->next; 928 } 929 NAMES.Dump(); 930 #endif 931 932 // check the referenced types in mainDoc to make sure we've imported them 933 err |= check_types(options.inputFileName.c_str(), mainDoc); 934 935 // finally, there really only needs to be one thing in mainDoc, and it 936 // needs to be an interface. 937 bool onlyParcelable = false; 938 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable); 939 940 // after this, there shouldn't be any more errors because of the 941 // input. 942 if (err != 0 || mainDoc == NULL) { 943 return 1; 944 } 945 946 // if needed, generate the outputFileName from the outputBaseFolder 947 if (options.outputFileName.length() == 0 && 948 options.outputBaseFolder.length() > 0) { 949 options.outputFileName = generate_outputFileName(options, mainDoc); 950 } 951 952 // if we were asked to, generate a make dependency file 953 // unless it's a parcelable *and* it's supposed to fail on parcelable 954 if ((options.autoDepFile || options.depFileName != "") && 955 !(onlyParcelable && options.failOnParcelable)) { 956 // make sure the folders of the output file all exists 957 check_outputFilePath(options.outputFileName); 958 generate_dep_file(options, mainDoc); 959 } 960 961 // they didn't ask to fail on parcelables, so just exit quietly. 962 if (onlyParcelable && !options.failOnParcelable) { 963 return 0; 964 } 965 966 // make sure the folders of the output file all exists 967 check_outputFilePath(options.outputFileName); 968 969 err = generate_java(options.outputFileName, options.inputFileName.c_str(), 970 (interface_type*)mainDoc); 971 972 return err; 973 } 974 975 static int 976 preprocess_aidl(const Options& options) 977 { 978 vector<string> lines; 979 int err; 980 981 // read files 982 int N = options.filesToPreprocess.size(); 983 for (int i=0; i<N; i++) { 984 g_callbacks = &g_mainCallbacks; 985 err = parse_aidl(options.filesToPreprocess[i].c_str()); 986 if (err != 0) { 987 return err; 988 } 989 document_item_type* doc = g_document; 990 string line; 991 if (doc->item_type == USER_DATA_TYPE) { 992 user_data_type* parcelable = (user_data_type*)doc; 993 if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) { 994 line = "parcelable "; 995 } 996 if ((parcelable->flattening_methods & RPC_DATA) != 0) { 997 line = "flattenable "; 998 } 999 if (parcelable->package) { 1000 line += parcelable->package; 1001 line += '.'; 1002 } 1003 line += parcelable->name.data; 1004 } else { 1005 line = "interface "; 1006 interface_type* iface = (interface_type*)doc; 1007 if (iface->package) { 1008 line += iface->package; 1009 line += '.'; 1010 } 1011 line += iface->name.data; 1012 } 1013 line += ";\n"; 1014 lines.push_back(line); 1015 } 1016 1017 // write preprocessed file 1018 int fd = open( options.outputFileName.c_str(), 1019 O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 1020 #ifdef HAVE_MS_C_RUNTIME 1021 _S_IREAD|_S_IWRITE); 1022 #else 1023 S_IRUSR|S_IWUSR|S_IRGRP); 1024 #endif 1025 if (fd == -1) { 1026 fprintf(stderr, "aidl: could not open file for write: %s\n", 1027 options.outputFileName.c_str()); 1028 return 1; 1029 } 1030 1031 N = lines.size(); 1032 for (int i=0; i<N; i++) { 1033 const string& s = lines[i]; 1034 int len = s.length(); 1035 if (len != write(fd, s.c_str(), len)) { 1036 fprintf(stderr, "aidl: error writing to file %s\n", 1037 options.outputFileName.c_str()); 1038 close(fd); 1039 unlink(options.outputFileName.c_str()); 1040 return 1; 1041 } 1042 } 1043 1044 close(fd); 1045 return 0; 1046 } 1047 1048 // ========================================================== 1049 int 1050 main(int argc, const char **argv) 1051 { 1052 Options options; 1053 int result = parse_options(argc, argv, &options); 1054 if (result) { 1055 return result; 1056 } 1057 1058 switch (options.task) 1059 { 1060 case COMPILE_AIDL: 1061 return compile_aidl(options); 1062 case PREPROCESS_AIDL: 1063 return preprocess_aidl(options); 1064 } 1065 fprintf(stderr, "aidl: internal error\n"); 1066 return 1; 1067 } 1068