aidl.cpp revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
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) { 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%08x d->item_type=%ld\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) { 246 interface_type* c = (interface_type*)items; 247 err |= check_filename(filename, c->package, &c->name); 248 } 249 else { 250 fprintf(stderr, "aidl: internal error unkown document type %d.\n", 251 items->item_type); 252 return 1; 253 } 254 items = items->next; 255 } 256 return err; 257} 258 259// ========================================================== 260static const char* 261kind_to_string(int kind) 262{ 263 switch (kind) 264 { 265 case Type::INTERFACE: 266 return "an interface"; 267 case Type::PARCELABLE: 268 return "a parcelable"; 269 default: 270 return "ERROR"; 271 } 272} 273 274static char* 275rfind(char* str, char c) 276{ 277 char* p = str + strlen(str) - 1; 278 while (p >= str) { 279 if (*p == c) { 280 return p; 281 } 282 p--; 283 } 284 return NULL; 285} 286 287static int 288gather_types(const char* filename, document_item_type* items) 289{ 290 int err = 0; 291 while (items) { 292 Type* type; 293 if (items->item_type == PARCELABLE_TYPE) { 294 parcelable_type* p = (parcelable_type*)items; 295 type = new ParcelableType(p->package ? p->package : "", 296 p->name.data, false, filename, p->name.lineno); 297 } 298 else if (items->item_type == INTERFACE_TYPE) { 299 interface_type* c = (interface_type*)items; 300 type = new InterfaceType(c->package ? c->package : "", 301 c->name.data, false, c->oneway, 302 filename, c->name.lineno); 303 } 304 else { 305 fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__); 306 return 1; 307 } 308 309 Type* old = NAMES.Find(type->QualifiedName()); 310 if (old == NULL) { 311 NAMES.Add(type); 312 313 if (items->item_type == INTERFACE_TYPE) { 314 // for interfaces, also add the stub and proxy types, we don't 315 // bother checking these for duplicates, because the parser 316 // won't let us do it. 317 interface_type* c = (interface_type*)items; 318 319 string name = c->name.data; 320 name += ".Stub"; 321 Type* stub = new Type(c->package ? c->package : "", 322 name, Type::GENERATED, false, false, 323 filename, c->name.lineno); 324 NAMES.Add(stub); 325 326 name = c->name.data; 327 name += ".Stub.Proxy"; 328 Type* proxy = new Type(c->package ? c->package : "", 329 name, Type::GENERATED, false, false, 330 filename, c->name.lineno); 331 NAMES.Add(proxy); 332 } 333 } else { 334 if (old->Kind() == Type::BUILT_IN) { 335 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n", 336 filename, type->DeclLine(), 337 type->QualifiedName().c_str()); 338 err = 1; 339 } 340 else if (type->Kind() != old->Kind()) { 341 const char* oldKind = kind_to_string(old->Kind()); 342 const char* newKind = kind_to_string(type->Kind()); 343 344 fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n", 345 filename, type->DeclLine(), 346 type->QualifiedName().c_str(), newKind); 347 fprintf(stderr, "%s:%d previously defined here as %s.\n", 348 old->DeclFile().c_str(), old->DeclLine(), oldKind); 349 err = 1; 350 } 351 } 352 353 items = items->next; 354 } 355 return err; 356} 357 358// ========================================================== 359static bool 360matches_keyword(const char* str) 361{ 362 static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break", 363 "byte", "case", "catch", "char", "class", "const", "continue", 364 "default", "do", "double", "else", "enum", "extends", "final", 365 "finally", "float", "for", "goto", "if", "implements", "import", 366 "instanceof", "int", "interface", "long", "native", "new", "package", 367 "private", "protected", "public", "return", "short", "static", 368 "strictfp", "super", "switch", "synchronized", "this", "throw", 369 "throws", "transient", "try", "void", "volatile", "while", 370 "true", "false", "null", 371 NULL 372 }; 373 const char** k = KEYWORDS; 374 while (*k) { 375 if (0 == strcmp(str, *k)) { 376 return true; 377 } 378 k++; 379 } 380 return false; 381} 382 383static int 384check_method(const char* filename, method_type* m) 385{ 386 int err = 0; 387 388 // return type 389 Type* returnType = NAMES.Search(m->type.type.data); 390 if (returnType == NULL) { 391 fprintf(stderr, "%s:%d unknown return type %s\n", filename, 392 m->type.type.lineno, m->type.type.data); 393 err = 1; 394 return err; 395 } 396 397 if (!returnType->CanBeMarshalled()) { 398 fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename, 399 m->type.type.lineno, m->type.type.data); 400 err = 1; 401 } 402 403 if (m->type.dimension > 0 && !returnType->CanBeArray()) { 404 fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename, 405 m->type.array_token.lineno, m->type.type.data, 406 m->type.array_token.data); 407 err = 1; 408 } 409 410 if (m->type.dimension > 1) { 411 fprintf(stderr, "%s:%d return type %s%s only one" 412 " dimensional arrays are supported\n", filename, 413 m->type.array_token.lineno, m->type.type.data, 414 m->type.array_token.data); 415 err = 1; 416 } 417 418 int index = 1; 419 420 arg_type* arg = m->args; 421 while (arg) { 422 Type* t = NAMES.Search(arg->type.type.data); 423 424 // check the arg type 425 if (t == NULL) { 426 fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n", 427 filename, m->type.type.lineno, arg->name.data, index, 428 arg->type.type.data); 429 err = 1; 430 goto next; 431 } 432 433 if (!t->CanBeMarshalled()) { 434 fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n", 435 filename, m->type.type.lineno, index, 436 arg->type.type.data, arg->name.data); 437 err = 1; 438 } 439 440 if (arg->direction.data == NULL 441 && (arg->type.dimension != 0 || t->CanBeOutParameter())) { 442 fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out" 443 " parameter, so you must declare it as in," 444 " out or inout.\n", 445 filename, m->type.type.lineno, index, 446 arg->type.type.data, arg->name.data); 447 err = 1; 448 } 449 450 if (convert_direction(arg->direction.data) != IN_PARAMETER 451 && !t->CanBeOutParameter() 452 && arg->type.dimension == 0) { 453 fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in" 454 " parameter.\n", 455 filename, m->type.type.lineno, index, 456 arg->direction.data, arg->type.type.data, 457 arg->name.data); 458 err = 1; 459 } 460 461 if (arg->type.dimension > 0 && !t->CanBeArray()) { 462 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an" 463 " array.\n", filename, 464 m->type.array_token.lineno, index, arg->direction.data, 465 arg->type.type.data, arg->type.array_token.data, 466 arg->name.data); 467 err = 1; 468 } 469 470 if (arg->type.dimension > 1) { 471 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one" 472 " dimensional arrays are supported\n", filename, 473 m->type.array_token.lineno, index, arg->direction.data, 474 arg->type.type.data, arg->type.array_token.data, 475 arg->name.data); 476 err = 1; 477 } 478 479 // check that the name doesn't match a keyword 480 if (matches_keyword(arg->name.data)) { 481 fprintf(stderr, "%s:%d parameter %d %s is named the same as a" 482 " Java keyword\n", 483 filename, m->name.lineno, index, arg->name.data); 484 err = 1; 485 } 486 487next: 488 index++; 489 arg = arg->next; 490 } 491 492 return err; 493} 494 495static int 496check_types(const char* filename, document_item_type* items) 497{ 498 int err = 0; 499 while (items) { 500 // (nothing to check for PARCELABLE_TYPE) 501 if (items->item_type == INTERFACE_TYPE) { 502 map<string,method_type*> methodNames; 503 interface_type* c = (interface_type*)items; 504 505 interface_item_type* member = c->interface_items; 506 while (member) { 507 if (member->item_type == METHOD_TYPE) { 508 method_type* m = (method_type*)member; 509 510 err |= check_method(filename, m); 511 512 // prevent duplicate methods 513 if (methodNames.find(m->name.data) == methodNames.end()) { 514 methodNames[m->name.data] = m; 515 } else { 516 fprintf(stderr,"%s:%d attempt to redefine method %s,\n", 517 filename, m->name.lineno, m->name.data); 518 method_type* old = methodNames[m->name.data]; 519 fprintf(stderr, "%s:%d previously defined here.\n", 520 filename, old->name.lineno); 521 err = 1; 522 } 523 } 524 member = member->next; 525 } 526 } 527 528 items = items->next; 529 } 530 return err; 531} 532 533// ========================================================== 534static int 535exactly_one_interface(const char* filename, const document_item_type* items, const Options& options, 536 bool* onlyParcelable) 537{ 538 if (items == NULL) { 539 fprintf(stderr, "%s: file does not contain any interfaces\n", 540 filename); 541 return 1; 542 } 543 544 const document_item_type* next = items->next; 545 if (items->next != NULL) { 546 int lineno = -1; 547 if (next->item_type == INTERFACE_TYPE) { 548 lineno = ((interface_type*)next)->interface_token.lineno; 549 } 550 else if (next->item_type == PARCELABLE_TYPE) { 551 lineno = ((parcelable_type*)next)->parcelable_token.lineno; 552 } 553 fprintf(stderr, "%s:%d aidl can only handle one interface per file\n", 554 filename, lineno); 555 return 1; 556 } 557 558 if (items->item_type == PARCELABLE_TYPE) { 559 *onlyParcelable = true; 560 if (options.failOnParcelable) { 561 fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not" 562 " parcelables,\n", filename, 563 ((parcelable_type*)items)->parcelable_token.lineno); 564 fprintf(stderr, "%s:%d .aidl files that only declare parcelables " 565 "don't need to go in the Makefile.\n", filename, 566 ((parcelable_type*)items)->parcelable_token.lineno); 567 return 1; 568 } 569 } else { 570 *onlyParcelable = false; 571 } 572 573 return 0; 574} 575 576// ========================================================== 577void 578generate_dep_file(const Options& options) 579{ 580 /* we open the file in binary mode to ensure that the same output is 581 * generated on all platforms !! 582 */ 583 FILE* to = fopen(options.depFileName.c_str(), "wb"); 584 if (to == NULL) { 585 return; 586 } 587 588 const char* slash = "\\"; 589 import_info* import = g_imports; 590 if (import == NULL) { 591 slash = ""; 592 } 593 594 fprintf(to, "%s: \\\n", options.outputFileName.c_str()); 595 fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash); 596 597 while (import) { 598 if (import->next == NULL) { 599 slash = ""; 600 } 601 if (import->filename) { 602 fprintf(to, " %s %s\n", import->filename, slash); 603 } 604 import = import->next; 605 } 606 607 fprintf(to, "\n"); 608 609 fclose(to); 610} 611 612// ========================================================== 613static int 614parse_preprocessed_file(const string& filename) 615{ 616 int err; 617 618 FILE* f = fopen(filename.c_str(), "rb"); 619 if (f == NULL) { 620 fprintf(stderr, "aidl: can't open preprocessd file: %s\n", 621 filename.c_str()); 622 return 1; 623 } 624 625 int lineno = 1; 626 char line[1024]; 627 char type[1024]; 628 char fullname[1024]; 629 while (fgets(line, sizeof(line), f)) { 630 // skip comments and empty lines 631 if (!line[0] || strncmp(line, "//", 2) == 0) { 632 continue; 633 } 634 635 sscanf(line, "%s %[^; \r\n\t];", type, fullname); 636 637 char* packagename; 638 char* classname = rfind(fullname, '.'); 639 if (classname != NULL) { 640 *classname = '\0'; 641 classname++; 642 packagename = fullname; 643 } else { 644 classname = fullname; 645 packagename = NULL; 646 } 647 648 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno, 649 // type, packagename, classname); 650 document_item_type* doc; 651 652 if (0 == strcmp("parcelable", type)) { 653 parcelable_type* parcl = (parcelable_type*)malloc( 654 sizeof(parcelable_type)); 655 memset(parcl, 0, sizeof(parcelable_type)); 656 parcl->document_item.item_type = PARCELABLE_TYPE; 657 parcl->parcelable_token.lineno = lineno; 658 parcl->parcelable_token.data = strdup(type); 659 parcl->package = packagename ? strdup(packagename) : NULL; 660 parcl->name.lineno = lineno; 661 parcl->name.data = strdup(classname); 662 parcl->semicolon_token.lineno = lineno; 663 parcl->semicolon_token.data = strdup(";"); 664 doc = (document_item_type*)parcl; 665 } 666 else if (0 == strcmp("interface", type)) { 667 interface_type* iface = (interface_type*)malloc( 668 sizeof(interface_type)); 669 memset(iface, 0, sizeof(interface_type)); 670 iface->document_item.item_type = INTERFACE_TYPE; 671 iface->interface_token.lineno = lineno; 672 iface->interface_token.data = strdup(type); 673 iface->package = packagename ? strdup(packagename) : NULL; 674 iface->name.lineno = lineno; 675 iface->name.data = strdup(classname); 676 iface->open_brace_token.lineno = lineno; 677 iface->open_brace_token.data = strdup("{"); 678 iface->close_brace_token.lineno = lineno; 679 iface->close_brace_token.data = strdup("}"); 680 doc = (document_item_type*)iface; 681 } 682 else { 683 fprintf(stderr, "%s:%d: bad type in line: %s\n", 684 filename.c_str(), lineno, line); 685 return 1; 686 } 687 err = gather_types(filename.c_str(), doc); 688 lineno++; 689 } 690 691 if (!feof(f)) { 692 fprintf(stderr, "%s:%d: error reading file, line to long.\n", 693 filename.c_str(), lineno); 694 return 1; 695 } 696 697 fclose(f); 698 return 0; 699} 700 701// ========================================================== 702static int 703compile_aidl(const Options& options) 704{ 705 int err = 0, N; 706 707 set_import_paths(options.importPaths); 708 709 register_base_types(); 710 711 // import the preprocessed file 712 N = options.preprocessedFiles.size(); 713 for (int i=0; i<N; i++) { 714 const string& s = options.preprocessedFiles[i]; 715 err |= parse_preprocessed_file(s); 716 } 717 if (err != 0) { 718 return err; 719 } 720 721 // parse the main file 722 g_callbacks = &g_mainCallbacks; 723 err = parse_aidl(options.inputFileName.c_str()); 724 document_item_type* mainDoc = g_document; 725 g_document = NULL; 726 727 // parse the imports 728 g_callbacks = &g_mainCallbacks; 729 import_info* import = g_imports; 730 while (import) { 731 if (NAMES.Find(import->neededClass) == NULL) { 732 import->filename = find_import_file(import->neededClass); 733 if (!import->filename) { 734 fprintf(stderr, "%s:%d: couldn't find import for class %s\n", 735 import->from, import->statement.lineno, 736 import->neededClass); 737 err |= 1; 738 } else { 739 err |= parse_aidl(import->filename); 740 import->doc = g_document; 741 if (import->doc == NULL) { 742 err |= 1; 743 } 744 } 745 } 746 import = import->next; 747 } 748 // bail out now if parsing wasn't successful 749 if (err != 0 || mainDoc == NULL) { 750 //fprintf(stderr, "aidl: parsing failed, stopping.\n"); 751 return 1; 752 } 753 754 // complain about ones that aren't in the right files 755 err |= check_filenames(options.inputFileName.c_str(), mainDoc); 756 import = g_imports; 757 while (import) { 758 err |= check_filenames(import->filename, import->doc); 759 import = import->next; 760 } 761 762 // gather the types that have been declared 763 err |= gather_types(options.inputFileName.c_str(), mainDoc); 764 import = g_imports; 765 while (import) { 766 err |= gather_types(import->filename, import->doc); 767 import = import->next; 768 } 769 770#if 0 771 printf("---- main doc ----\n"); 772 test_document(mainDoc); 773 774 import = g_imports; 775 while (import) { 776 printf("---- import doc ----\n"); 777 test_document(import->doc); 778 import = import->next; 779 } 780 NAMES.Dump(); 781#endif 782 783 // check the referenced types in mainDoc to make sure we've imported them 784 err |= check_types(options.inputFileName.c_str(), mainDoc); 785 786 // finally, there really only needs to be one thing in mainDoc, and it 787 // needs to be an interface. 788 bool onlyParcelable = false; 789 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable); 790 791 // after this, there shouldn't be any more errors because of the 792 // input. 793 if (err != 0 || mainDoc == NULL) { 794 return 1; 795 } 796 797 // they didn't ask to fail on parcelables, so just exit quietly. 798 if (onlyParcelable && !options.failOnParcelable) { 799 return 0; 800 } 801 802 // if we were asked to, generate a make dependency file 803 if (options.depFileName != "") { 804 generate_dep_file(options); 805 } 806 807 err = generate_java(options.outputFileName, options.inputFileName.c_str(), 808 (interface_type*)mainDoc); 809 810 return err; 811} 812 813static int 814preprocess_aidl(const Options& options) 815{ 816 vector<string> lines; 817 int err; 818 819 // read files 820 int N = options.filesToPreprocess.size(); 821 for (int i=0; i<N; i++) { 822 g_callbacks = &g_mainCallbacks; 823 err = parse_aidl(options.filesToPreprocess[i].c_str()); 824 if (err != 0) { 825 return err; 826 } 827 document_item_type* doc = g_document; 828 string line; 829 if (doc->item_type == PARCELABLE_TYPE) { 830 line = "parcelable "; 831 parcelable_type* parcelable = (parcelable_type*)doc; 832 if (parcelable->package) { 833 line += parcelable->package; 834 line += '.'; 835 } 836 line += parcelable->name.data; 837 } else { 838 line = "interface "; 839 interface_type* iface = (interface_type*)doc; 840 if (iface->package) { 841 line += iface->package; 842 line += '.'; 843 } 844 line += iface->name.data; 845 } 846 line += ";\n"; 847 lines.push_back(line); 848 } 849 850 // write preprocessed file 851 int fd = open( options.outputFileName.c_str(), 852 O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 853#ifdef HAVE_MS_C_RUNTIME 854 _S_IREAD|_S_IWRITE); 855#else 856 S_IRUSR|S_IWUSR|S_IRGRP); 857#endif 858 if (fd == -1) { 859 fprintf(stderr, "aidl: could not open file for write: %s\n", 860 options.outputFileName.c_str()); 861 return 1; 862 } 863 864 N = lines.size(); 865 for (int i=0; i<N; i++) { 866 const string& s = lines[i]; 867 int len = s.length(); 868 if (len != write(fd, s.c_str(), len)) { 869 fprintf(stderr, "aidl: error writing to file %s\n", 870 options.outputFileName.c_str()); 871 close(fd); 872 unlink(options.outputFileName.c_str()); 873 return 1; 874 } 875 } 876 877 close(fd); 878 return 0; 879} 880 881// ========================================================== 882int 883main(int argc, const char **argv) 884{ 885 int err = 0; 886 887 Options options; 888 int result = parse_options(argc, argv, &options); 889 if (result) { 890 return result; 891 } 892 893 switch (options.task) 894 { 895 case COMPILE_AIDL: 896 return compile_aidl(options); 897 case PREPROCESS_AIDL: 898 return preprocess_aidl(options); 899 } 900 fprintf(stderr, "aidl: internal error\n"); 901 return 1; 902} 903 904 905