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