aidl.cpp revision e24dbeafe64278408b3342fcb77756bc7d091791
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 if (d->item_type == FLATTENABLE_TYPE) { 58 parcelable_type* b = (parcelable_type*)d; 59 printf("flattenable %s %s;\n", b->package, b->name.data); 60 } 61 else { 62 printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type); 63 } 64 d = d->next; 65 } 66} 67 68// ========================================================== 69int 70convert_direction(const char* direction) 71{ 72 if (direction == NULL) { 73 return IN_PARAMETER; 74 } 75 if (0 == strcmp(direction, "in")) { 76 return IN_PARAMETER; 77 } 78 if (0 == strcmp(direction, "out")) { 79 return OUT_PARAMETER; 80 } 81 return INOUT_PARAMETER; 82} 83 84// ========================================================== 85struct import_info { 86 const char* from; 87 const char* filename; 88 buffer_type statement; 89 const char* neededClass; 90 document_item_type* doc; 91 struct import_info* next; 92}; 93 94document_item_type* g_document = NULL; 95import_info* g_imports = NULL; 96 97static void 98main_document_parsed(document_item_type* d) 99{ 100 g_document = d; 101} 102 103static void 104main_import_parsed(buffer_type* statement) 105{ 106 import_info* import = (import_info*)malloc(sizeof(import_info)); 107 memset(import, 0, sizeof(import_info)); 108 import->from = strdup(g_currentFilename); 109 import->statement.lineno = statement->lineno; 110 import->statement.data = strdup(statement->data); 111 import->statement.extra = NULL; 112 import->next = g_imports; 113 import->neededClass = parse_import_statement(statement->data); 114 g_imports = import; 115} 116 117static ParserCallbacks g_mainCallbacks = { 118 &main_document_parsed, 119 &main_import_parsed 120}; 121 122char* 123parse_import_statement(const char* text) 124{ 125 const char* end; 126 int len; 127 128 while (isspace(*text)) { 129 text++; 130 } 131 while (!isspace(*text)) { 132 text++; 133 } 134 while (isspace(*text)) { 135 text++; 136 } 137 end = text; 138 while (!isspace(*end) && *end != ';') { 139 end++; 140 } 141 len = end-text; 142 143 char* rv = (char*)malloc(len+1); 144 memcpy(rv, text, len); 145 rv[len] = '\0'; 146 147 return rv; 148} 149 150// ========================================================== 151static void 152import_import_parsed(buffer_type* statement) 153{ 154} 155 156static ParserCallbacks g_importCallbacks = { 157 &main_document_parsed, 158 &import_import_parsed 159}; 160 161// ========================================================== 162static int 163check_filename(const char* filename, const char* package, buffer_type* name) 164{ 165 const char* p; 166 string expected; 167 string fn; 168 size_t len; 169 char cwd[MAXPATHLEN]; 170 bool valid = false; 171 172#ifdef HAVE_WINDOWS_PATHS 173 if (isalpha(filename[0]) && filename[1] == ':' 174 && filename[2] == OS_PATH_SEPARATOR) { 175#else 176 if (filename[0] == OS_PATH_SEPARATOR) { 177#endif 178 fn = filename; 179 } else { 180 fn = getcwd(cwd, sizeof(cwd)); 181 len = fn.length(); 182 if (fn[len-1] != OS_PATH_SEPARATOR) { 183 fn += OS_PATH_SEPARATOR; 184 } 185 fn += filename; 186 } 187 188 if (package) { 189 expected = package; 190 expected += '.'; 191 } 192 193 len = expected.length(); 194 for (size_t i=0; i<len; i++) { 195 if (expected[i] == '.') { 196 expected[i] = OS_PATH_SEPARATOR; 197 } 198 } 199 200 p = strchr(name->data, '.'); 201 len = p ? p-name->data : strlen(name->data); 202 expected.append(name->data, len); 203 204 expected += ".aidl"; 205 206 len = fn.length(); 207 valid = (len >= expected.length()); 208 209 if (valid) { 210 p = fn.c_str() + (len - expected.length()); 211 212#ifdef HAVE_WINDOWS_PATHS 213 if (OS_PATH_SEPARATOR != '/') { 214 // Input filename under cygwin most likely has / separators 215 // whereas the expected string uses \\ separators. Adjust 216 // them accordingly. 217 for (char *c = const_cast<char *>(p); *c; ++c) { 218 if (*c == '/') *c = OS_PATH_SEPARATOR; 219 } 220 } 221#endif 222 223#ifdef OS_CASE_SENSITIVE 224 valid = (expected == p); 225#else 226 valid = !strcasecmp(expected.c_str(), p); 227#endif 228 } 229 230 if (!valid) { 231 fprintf(stderr, "%s:%d interface %s should be declared in a file" 232 " called %s.\n", 233 filename, name->lineno, name->data, expected.c_str()); 234 return 1; 235 } 236 237 return 0; 238} 239 240static int 241check_filenames(const char* filename, document_item_type* items) 242{ 243 int err = 0; 244 while (items) { 245 if (items->item_type == PARCELABLE_TYPE 246 || items->item_type == FLATTENABLE_TYPE) { 247 parcelable_type* p = (parcelable_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// ========================================================== 266static const char* 267kind_to_string(int kind) 268{ 269 switch (kind) 270 { 271 case Type::INTERFACE: 272 return "an interface"; 273 case Type::PARCELABLE: 274 return "a parcelable"; 275 default: 276 return "ERROR"; 277 } 278} 279 280static char* 281rfind(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 293static int 294gather_types(const char* filename, document_item_type* items) 295{ 296 int err = 0; 297 while (items) { 298 Type* type; 299 if (items->item_type == PARCELABLE_TYPE) { 300 parcelable_type* p = (parcelable_type*)items; 301 type = new ParcelableType(p->package ? p->package : "", 302 p->name.data, false, filename, p->name.lineno); 303 } 304 else if (items->item_type == FLATTENABLE_TYPE) { 305 parcelable_type* p = (parcelable_type*)items; 306 type = new FlattenableType(p->package ? p->package : "", 307 p->name.data, false, filename, p->name.lineno); 308 } 309 else if (items->item_type == INTERFACE_TYPE_BINDER 310 || items->item_type == INTERFACE_TYPE_RPC) { 311 interface_type* c = (interface_type*)items; 312 type = new InterfaceType(c->package ? c->package : "", 313 c->name.data, false, c->oneway, 314 filename, c->name.lineno); 315 } 316 else { 317 fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__); 318 return 1; 319 } 320 321 Type* old = NAMES.Find(type->QualifiedName()); 322 if (old == NULL) { 323 NAMES.Add(type); 324 325 if (items->item_type == INTERFACE_TYPE_BINDER) { 326 // for interfaces, also add the stub and proxy types, we don't 327 // bother checking these for duplicates, because the parser 328 // won't let us do it. 329 interface_type* c = (interface_type*)items; 330 331 string name = c->name.data; 332 name += ".Stub"; 333 Type* stub = new Type(c->package ? c->package : "", 334 name, Type::GENERATED, false, false, false, 335 filename, c->name.lineno); 336 NAMES.Add(stub); 337 338 name = c->name.data; 339 name += ".Stub.Proxy"; 340 Type* proxy = new Type(c->package ? c->package : "", 341 name, Type::GENERATED, false, false, false, 342 filename, c->name.lineno); 343 NAMES.Add(proxy); 344 } 345 else if (items->item_type == INTERFACE_TYPE_RPC) { 346 // for interfaces, also add the service base type, we don't 347 // bother checking these for duplicates, because the parser 348 // won't let us do it. 349 interface_type* c = (interface_type*)items; 350 351 string name = c->name.data; 352 name += ".ServiceBase"; 353 Type* base = new Type(c->package ? c->package : "", 354 name, Type::GENERATED, false, false, false, 355 filename, c->name.lineno); 356 NAMES.Add(base); 357 } 358 } else { 359 if (old->Kind() == Type::BUILT_IN) { 360 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n", 361 filename, type->DeclLine(), 362 type->QualifiedName().c_str()); 363 err = 1; 364 } 365 else if (type->Kind() != old->Kind()) { 366 const char* oldKind = kind_to_string(old->Kind()); 367 const char* newKind = kind_to_string(type->Kind()); 368 369 fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n", 370 filename, type->DeclLine(), 371 type->QualifiedName().c_str(), newKind); 372 fprintf(stderr, "%s:%d previously defined here as %s.\n", 373 old->DeclFile().c_str(), old->DeclLine(), oldKind); 374 err = 1; 375 } 376 } 377 378 items = items->next; 379 } 380 return err; 381} 382 383// ========================================================== 384static bool 385matches_keyword(const char* str) 386{ 387 static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break", 388 "byte", "case", "catch", "char", "class", "const", "continue", 389 "default", "do", "double", "else", "enum", "extends", "final", 390 "finally", "float", "for", "goto", "if", "implements", "import", 391 "instanceof", "int", "interface", "long", "native", "new", "package", 392 "private", "protected", "public", "return", "short", "static", 393 "strictfp", "super", "switch", "synchronized", "this", "throw", 394 "throws", "transient", "try", "void", "volatile", "while", 395 "true", "false", "null", 396 NULL 397 }; 398 const char** k = KEYWORDS; 399 while (*k) { 400 if (0 == strcmp(str, *k)) { 401 return true; 402 } 403 k++; 404 } 405 return false; 406} 407 408static int 409check_method(const char* filename, int kind, method_type* m) 410{ 411 int err = 0; 412 413 // return type 414 Type* returnType = NAMES.Search(m->type.type.data); 415 if (returnType == NULL) { 416 fprintf(stderr, "%s:%d unknown return type %s\n", filename, 417 m->type.type.lineno, m->type.type.data); 418 err = 1; 419 return err; 420 } 421 422 if (returnType == EVENT_FAKE_TYPE) { 423 if (kind != INTERFACE_TYPE_RPC) { 424 fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n", 425 filename, m->type.type.lineno); 426 err = 1; 427 } 428 } else { 429 if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel() 430 : returnType->CanWriteToRpcData())) { 431 fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename, 432 m->type.type.lineno, m->type.type.data); 433 err = 1; 434 } 435 } 436 437 if (m->type.dimension > 0 && !returnType->CanBeArray()) { 438 fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename, 439 m->type.array_token.lineno, m->type.type.data, 440 m->type.array_token.data); 441 err = 1; 442 } 443 444 if (m->type.dimension > 1) { 445 fprintf(stderr, "%s:%d return type %s%s only one" 446 " dimensional arrays are supported\n", filename, 447 m->type.array_token.lineno, m->type.type.data, 448 m->type.array_token.data); 449 err = 1; 450 } 451 452 int index = 1; 453 454 arg_type* arg = m->args; 455 while (arg) { 456 Type* t = NAMES.Search(arg->type.type.data); 457 458 // check the arg type 459 if (t == NULL) { 460 fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n", 461 filename, m->type.type.lineno, arg->name.data, index, 462 arg->type.type.data); 463 err = 1; 464 goto next; 465 } 466 467 if (t == EVENT_FAKE_TYPE) { 468 fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n", 469 filename, m->type.type.lineno, arg->name.data, index, 470 arg->type.type.data); 471 err = 1; 472 goto next; 473 } 474 475 if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) { 476 fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n", 477 filename, m->type.type.lineno, index, 478 arg->type.type.data, arg->name.data); 479 err = 1; 480 } 481 482 if (arg->direction.data == NULL 483 && (arg->type.dimension != 0 || t->CanBeOutParameter())) { 484 fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out" 485 " parameter, so you must declare it as in," 486 " out or inout.\n", 487 filename, m->type.type.lineno, index, 488 arg->type.type.data, arg->name.data); 489 err = 1; 490 } 491 492 if (convert_direction(arg->direction.data) != IN_PARAMETER 493 && !t->CanBeOutParameter() 494 && arg->type.dimension == 0) { 495 fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in" 496 " parameter.\n", 497 filename, m->type.type.lineno, index, 498 arg->direction.data, arg->type.type.data, 499 arg->name.data); 500 err = 1; 501 } 502 503 if (arg->type.dimension > 0 && !t->CanBeArray()) { 504 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an" 505 " array.\n", filename, 506 m->type.array_token.lineno, index, arg->direction.data, 507 arg->type.type.data, arg->type.array_token.data, 508 arg->name.data); 509 err = 1; 510 } 511 512 if (arg->type.dimension > 1) { 513 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one" 514 " dimensional arrays are supported\n", filename, 515 m->type.array_token.lineno, index, arg->direction.data, 516 arg->type.type.data, arg->type.array_token.data, 517 arg->name.data); 518 err = 1; 519 } 520 521 // check that the name doesn't match a keyword 522 if (matches_keyword(arg->name.data)) { 523 fprintf(stderr, "%s:%d parameter %d %s is named the same as a" 524 " Java or aidl keyword\n", 525 filename, m->name.lineno, index, arg->name.data); 526 err = 1; 527 } 528 529next: 530 index++; 531 arg = arg->next; 532 } 533 534 return err; 535} 536 537static int 538check_types(const char* filename, document_item_type* items) 539{ 540 int err = 0; 541 while (items) { 542 // (nothing to check for PARCELABLE_TYPE or FLATTENABLE_TYPE) 543 if (items->item_type == INTERFACE_TYPE_BINDER 544 || items->item_type == INTERFACE_TYPE_RPC) { 545 map<string,method_type*> methodNames; 546 interface_type* c = (interface_type*)items; 547 548 interface_item_type* member = c->interface_items; 549 while (member) { 550 if (member->item_type == METHOD_TYPE) { 551 method_type* m = (method_type*)member; 552 553 err |= check_method(filename, items->item_type, m); 554 555 // prevent duplicate methods 556 if (methodNames.find(m->name.data) == methodNames.end()) { 557 methodNames[m->name.data] = m; 558 } else { 559 fprintf(stderr,"%s:%d attempt to redefine method %s,\n", 560 filename, m->name.lineno, m->name.data); 561 method_type* old = methodNames[m->name.data]; 562 fprintf(stderr, "%s:%d previously defined here.\n", 563 filename, old->name.lineno); 564 err = 1; 565 } 566 } 567 member = member->next; 568 } 569 } 570 571 items = items->next; 572 } 573 return err; 574} 575 576// ========================================================== 577static int 578exactly_one_interface(const char* filename, const document_item_type* items, const Options& options, 579 bool* onlyParcelable) 580{ 581 if (items == NULL) { 582 fprintf(stderr, "%s: file does not contain any interfaces\n", 583 filename); 584 return 1; 585 } 586 587 const document_item_type* next = items->next; 588 if (items->next != NULL) { 589 int lineno = -1; 590 if (next->item_type == INTERFACE_TYPE_BINDER) { 591 lineno = ((interface_type*)next)->interface_token.lineno; 592 } 593 else if (next->item_type == INTERFACE_TYPE_RPC) { 594 lineno = ((interface_type*)next)->interface_token.lineno; 595 } 596 else if (next->item_type == PARCELABLE_TYPE) { 597 lineno = ((parcelable_type*)next)->parcelable_token.lineno; 598 } 599 else if (next->item_type == FLATTENABLE_TYPE) { 600 lineno = ((parcelable_type*)next)->parcelable_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 == PARCELABLE_TYPE || items->item_type == FLATTENABLE_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 ((parcelable_type*)items)->parcelable_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 ((parcelable_type*)items)->parcelable_token.lineno); 616 return 1; 617 } 618 } else { 619 *onlyParcelable = false; 620 } 621 622 return 0; 623} 624 625// ========================================================== 626void 627generate_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// ========================================================== 674static string 675generate_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// ========================================================== 706static string 707generate_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 == PARCELABLE_TYPE || items->item_type == FLATTENABLE_TYPE) { 715 parcelable_type* type = (parcelable_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// ========================================================== 727static void 728check_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// ========================================================== 746static int 747parse_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 parcelable_type* parcl = (parcelable_type*)malloc( 787 sizeof(parcelable_type)); 788 memset(parcl, 0, sizeof(parcelable_type)); 789 parcl->document_item.item_type = PARCELABLE_TYPE; 790 parcl->parcelable_token.lineno = lineno; 791 parcl->parcelable_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 doc = (document_item_type*)parcl; 798 } 799 else if (0 == strcmp("flattenable", type)) { 800 parcelable_type* parcl = (parcelable_type*)malloc( 801 sizeof(parcelable_type)); 802 memset(parcl, 0, sizeof(parcelable_type)); 803 parcl->document_item.item_type = FLATTENABLE_TYPE; 804 parcl->parcelable_token.lineno = lineno; 805 parcl->parcelable_token.data = strdup(type); 806 parcl->package = packagename ? strdup(packagename) : NULL; 807 parcl->name.lineno = lineno; 808 parcl->name.data = strdup(classname); 809 parcl->semicolon_token.lineno = lineno; 810 parcl->semicolon_token.data = strdup(";"); 811 doc = (document_item_type*)parcl; 812 } 813 else if (0 == strcmp("interface", type)) { 814 interface_type* iface = (interface_type*)malloc( 815 sizeof(interface_type)); 816 memset(iface, 0, sizeof(interface_type)); 817 iface->document_item.item_type = INTERFACE_TYPE_BINDER; 818 iface->interface_token.lineno = lineno; 819 iface->interface_token.data = strdup(type); 820 iface->package = packagename ? strdup(packagename) : NULL; 821 iface->name.lineno = lineno; 822 iface->name.data = strdup(classname); 823 iface->open_brace_token.lineno = lineno; 824 iface->open_brace_token.data = strdup("{"); 825 iface->close_brace_token.lineno = lineno; 826 iface->close_brace_token.data = strdup("}"); 827 doc = (document_item_type*)iface; 828 } 829 else { 830 fprintf(stderr, "%s:%d: bad type in line: %s\n", 831 filename.c_str(), lineno, line); 832 return 1; 833 } 834 err = gather_types(filename.c_str(), doc); 835 lineno++; 836 } 837 838 if (!feof(f)) { 839 fprintf(stderr, "%s:%d: error reading file, line to long.\n", 840 filename.c_str(), lineno); 841 return 1; 842 } 843 844 fclose(f); 845 return 0; 846} 847 848// ========================================================== 849static int 850compile_aidl(Options& options) 851{ 852 int err = 0, N; 853 854 set_import_paths(options.importPaths); 855 856 register_base_types(); 857 858 // import the preprocessed file 859 N = options.preprocessedFiles.size(); 860 for (int i=0; i<N; i++) { 861 const string& s = options.preprocessedFiles[i]; 862 err |= parse_preprocessed_file(s); 863 } 864 if (err != 0) { 865 return err; 866 } 867 868 // parse the main file 869 g_callbacks = &g_mainCallbacks; 870 err = parse_aidl(options.inputFileName.c_str()); 871 document_item_type* mainDoc = g_document; 872 g_document = NULL; 873 874 // parse the imports 875 g_callbacks = &g_mainCallbacks; 876 import_info* import = g_imports; 877 while (import) { 878 if (NAMES.Find(import->neededClass) == NULL) { 879 import->filename = find_import_file(import->neededClass); 880 if (!import->filename) { 881 fprintf(stderr, "%s:%d: couldn't find import for class %s\n", 882 import->from, import->statement.lineno, 883 import->neededClass); 884 err |= 1; 885 } else { 886 err |= parse_aidl(import->filename); 887 import->doc = g_document; 888 if (import->doc == NULL) { 889 err |= 1; 890 } 891 } 892 } 893 import = import->next; 894 } 895 // bail out now if parsing wasn't successful 896 if (err != 0 || mainDoc == NULL) { 897 //fprintf(stderr, "aidl: parsing failed, stopping.\n"); 898 return 1; 899 } 900 901 // complain about ones that aren't in the right files 902 err |= check_filenames(options.inputFileName.c_str(), mainDoc); 903 import = g_imports; 904 while (import) { 905 err |= check_filenames(import->filename, import->doc); 906 import = import->next; 907 } 908 909 // gather the types that have been declared 910 err |= gather_types(options.inputFileName.c_str(), mainDoc); 911 import = g_imports; 912 while (import) { 913 err |= gather_types(import->filename, import->doc); 914 import = import->next; 915 } 916 917#if 0 918 printf("---- main doc ----\n"); 919 test_document(mainDoc); 920 921 import = g_imports; 922 while (import) { 923 printf("---- import doc ----\n"); 924 test_document(import->doc); 925 import = import->next; 926 } 927 NAMES.Dump(); 928#endif 929 930 // check the referenced types in mainDoc to make sure we've imported them 931 err |= check_types(options.inputFileName.c_str(), mainDoc); 932 933 // finally, there really only needs to be one thing in mainDoc, and it 934 // needs to be an interface. 935 bool onlyParcelable = false; 936 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable); 937 938 // after this, there shouldn't be any more errors because of the 939 // input. 940 if (err != 0 || mainDoc == NULL) { 941 return 1; 942 } 943 944 // if needed, generate the outputFileName from the outputBaseFolder 945 if (options.outputFileName.length() == 0 && 946 options.outputBaseFolder.length() > 0) { 947 options.outputFileName = generate_outputFileName(options, mainDoc); 948 } 949 950 // if we were asked to, generate a make dependency file 951 // unless it's a parcelable *and* it's supposed to fail on parcelable 952 if ((options.autoDepFile || options.depFileName != "") && 953 !(onlyParcelable && options.failOnParcelable)) { 954 // make sure the folders of the output file all exists 955 check_outputFilePath(options.outputFileName); 956 generate_dep_file(options, mainDoc); 957 } 958 959 // they didn't ask to fail on parcelables, so just exit quietly. 960 if (onlyParcelable && !options.failOnParcelable) { 961 return 0; 962 } 963 964 // make sure the folders of the output file all exists 965 check_outputFilePath(options.outputFileName); 966 967 err = generate_java(options.outputFileName, options.inputFileName.c_str(), 968 (interface_type*)mainDoc); 969 970 return err; 971} 972 973static int 974preprocess_aidl(const Options& options) 975{ 976 vector<string> lines; 977 int err; 978 979 // read files 980 int N = options.filesToPreprocess.size(); 981 for (int i=0; i<N; i++) { 982 g_callbacks = &g_mainCallbacks; 983 err = parse_aidl(options.filesToPreprocess[i].c_str()); 984 if (err != 0) { 985 return err; 986 } 987 document_item_type* doc = g_document; 988 string line; 989 if (doc->item_type == PARCELABLE_TYPE) { 990 line = "parcelable "; 991 parcelable_type* parcelable = (parcelable_type*)doc; 992 if (parcelable->package) { 993 line += parcelable->package; 994 line += '.'; 995 } 996 line += parcelable->name.data; 997 } 998 else if (doc->item_type == FLATTENABLE_TYPE) { 999 line = "parcelable "; 1000 parcelable_type* parcelable = (parcelable_type*)doc; 1001 if (parcelable->package) { 1002 line += parcelable->package; 1003 line += '.'; 1004 } 1005 line += parcelable->name.data; 1006 } else { 1007 line = "interface "; 1008 interface_type* iface = (interface_type*)doc; 1009 if (iface->package) { 1010 line += iface->package; 1011 line += '.'; 1012 } 1013 line += iface->name.data; 1014 } 1015 line += ";\n"; 1016 lines.push_back(line); 1017 } 1018 1019 // write preprocessed file 1020 int fd = open( options.outputFileName.c_str(), 1021 O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 1022#ifdef HAVE_MS_C_RUNTIME 1023 _S_IREAD|_S_IWRITE); 1024#else 1025 S_IRUSR|S_IWUSR|S_IRGRP); 1026#endif 1027 if (fd == -1) { 1028 fprintf(stderr, "aidl: could not open file for write: %s\n", 1029 options.outputFileName.c_str()); 1030 return 1; 1031 } 1032 1033 N = lines.size(); 1034 for (int i=0; i<N; i++) { 1035 const string& s = lines[i]; 1036 int len = s.length(); 1037 if (len != write(fd, s.c_str(), len)) { 1038 fprintf(stderr, "aidl: error writing to file %s\n", 1039 options.outputFileName.c_str()); 1040 close(fd); 1041 unlink(options.outputFileName.c_str()); 1042 return 1; 1043 } 1044 } 1045 1046 close(fd); 1047 return 0; 1048} 1049 1050// ========================================================== 1051int 1052main(int argc, const char **argv) 1053{ 1054 Options options; 1055 int result = parse_options(argc, argv, &options); 1056 if (result) { 1057 return result; 1058 } 1059 1060 switch (options.task) 1061 { 1062 case COMPILE_AIDL: 1063 return compile_aidl(options); 1064 case PREPROCESS_AIDL: 1065 return preprocess_aidl(options); 1066 } 1067 fprintf(stderr, "aidl: internal error\n"); 1068 return 1; 1069} 1070