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