Home | History | Annotate | Download | only in aidl
      1 
      2 #include "aidl_language.h"
      3 #include "options.h"
      4 #include "search_path.h"
      5 #include "Type.h"
      6 #include "generate_java.h"
      7 #include <unistd.h>
      8 #include <fcntl.h>
      9 #include <sys/param.h>
     10 #include <sys/stat.h>
     11 
     12 #include <stdio.h>
     13 #include <stdlib.h>
     14 #include <string.h>
     15 #include <map>
     16 
     17 #ifdef HAVE_MS_C_RUNTIME
     18 #include <io.h>
     19 #include <sys/stat.h>
     20 #endif
     21 
     22 #ifndef O_BINARY
     23 #  define O_BINARY  0
     24 #endif
     25 
     26 using namespace std;
     27 
     28 static void
     29 test_document(document_item_type* d)
     30 {
     31     while (d) {
     32         if (d->item_type == INTERFACE_TYPE) {
     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 // ==========================================================
     65 int
     66 convert_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 // ==========================================================
     81 struct 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 
     90 document_item_type* g_document = NULL;
     91 import_info* g_imports = NULL;
     92 
     93 static void
     94 main_document_parsed(document_item_type* d)
     95 {
     96     g_document = d;
     97 }
     98 
     99 static void
    100 main_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 
    113 static ParserCallbacks g_mainCallbacks = {
    114     &main_document_parsed,
    115     &main_import_parsed
    116 };
    117 
    118 char*
    119 parse_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 // ==========================================================
    147 static void
    148 import_import_parsed(buffer_type* statement)
    149 {
    150 }
    151 
    152 static ParserCallbacks g_importCallbacks = {
    153     &main_document_parsed,
    154     &import_import_parsed
    155 };
    156 
    157 // ==========================================================
    158 static int
    159 check_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 
    236 static int
    237 check_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 // ==========================================================
    260 static const char*
    261 kind_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 
    274 static char*
    275 rfind(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 
    287 static int
    288 gather_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 // ==========================================================
    359 static bool
    360 matches_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 
    383 static int
    384 check_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 
    487 next:
    488         index++;
    489         arg = arg->next;
    490     }
    491 
    492     return err;
    493 }
    494 
    495 static int
    496 check_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 // ==========================================================
    534 static int
    535 exactly_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 // ==========================================================
    577 void
    578 generate_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 // ==========================================================
    613 static string
    614 generate_outputFileName(const Options& options, const document_item_type* items)
    615 {
    616     string result;
    617 
    618     // items has already been checked to have only one interface.
    619     if (items->item_type == INTERFACE_TYPE) {
    620         interface_type* type = (interface_type*)items;
    621 
    622         // create the path to the destination folder based on the
    623         // interface package name
    624         result = options.outputBaseFolder;
    625         result += OS_PATH_SEPARATOR;
    626 
    627         string package = type->package;
    628         size_t len = package.length();
    629         for (size_t i=0; i<len; i++) {
    630             if (package[i] == '.') {
    631                 package[i] = OS_PATH_SEPARATOR;
    632             }
    633         }
    634 
    635         result += package;
    636 
    637         // add the filename by replacing the .aidl extension to .java
    638         const char* p = strchr(type->name.data, '.');
    639         len = p ? p-type->name.data : strlen(type->name.data);
    640 
    641         result += OS_PATH_SEPARATOR;
    642         result.append(type->name.data, len);
    643         result += ".java";
    644     }
    645 
    646     return result;
    647 }
    648 
    649 // ==========================================================
    650 static void
    651 check_outputFileName(const string& path) {
    652     size_t len = path.length();
    653     for (size_t i=0; i<len ; i++) {
    654         if (path[i] == OS_PATH_SEPARATOR) {
    655             string p = path.substr(0, i);
    656             if (access(path.data(), F_OK) != 0) {
    657 #ifdef HAVE_MS_C_RUNTIME
    658                 _mkdir(p.data());
    659 #else
    660                 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
    661 #endif
    662             }
    663         }
    664     }
    665 }
    666 
    667 
    668 // ==========================================================
    669 static int
    670 parse_preprocessed_file(const string& filename)
    671 {
    672     int err;
    673 
    674     FILE* f = fopen(filename.c_str(), "rb");
    675     if (f == NULL) {
    676         fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
    677                 filename.c_str());
    678         return 1;
    679     }
    680 
    681     int lineno = 1;
    682     char line[1024];
    683     char type[1024];
    684     char fullname[1024];
    685     while (fgets(line, sizeof(line), f)) {
    686         // skip comments and empty lines
    687         if (!line[0] || strncmp(line, "//", 2) == 0) {
    688           continue;
    689         }
    690 
    691         sscanf(line, "%s %[^; \r\n\t];", type, fullname);
    692 
    693         char* packagename;
    694         char* classname = rfind(fullname, '.');
    695         if (classname != NULL) {
    696             *classname = '\0';
    697             classname++;
    698             packagename = fullname;
    699         } else {
    700             classname = fullname;
    701             packagename = NULL;
    702         }
    703 
    704         //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
    705         //        type, packagename, classname);
    706         document_item_type* doc;
    707 
    708         if (0 == strcmp("parcelable", type)) {
    709             parcelable_type* parcl = (parcelable_type*)malloc(
    710                     sizeof(parcelable_type));
    711             memset(parcl, 0, sizeof(parcelable_type));
    712             parcl->document_item.item_type = PARCELABLE_TYPE;
    713             parcl->parcelable_token.lineno = lineno;
    714             parcl->parcelable_token.data = strdup(type);
    715             parcl->package = packagename ? strdup(packagename) : NULL;
    716             parcl->name.lineno = lineno;
    717             parcl->name.data = strdup(classname);
    718             parcl->semicolon_token.lineno = lineno;
    719             parcl->semicolon_token.data = strdup(";");
    720             doc = (document_item_type*)parcl;
    721         }
    722         else if (0 == strcmp("interface", type)) {
    723             interface_type* iface = (interface_type*)malloc(
    724                     sizeof(interface_type));
    725             memset(iface, 0, sizeof(interface_type));
    726             iface->document_item.item_type = INTERFACE_TYPE;
    727             iface->interface_token.lineno = lineno;
    728             iface->interface_token.data = strdup(type);
    729             iface->package = packagename ? strdup(packagename) : NULL;
    730             iface->name.lineno = lineno;
    731             iface->name.data = strdup(classname);
    732             iface->open_brace_token.lineno = lineno;
    733             iface->open_brace_token.data = strdup("{");
    734             iface->close_brace_token.lineno = lineno;
    735             iface->close_brace_token.data = strdup("}");
    736             doc = (document_item_type*)iface;
    737         }
    738         else {
    739             fprintf(stderr, "%s:%d: bad type in line: %s\n",
    740                     filename.c_str(), lineno, line);
    741             return 1;
    742         }
    743         err = gather_types(filename.c_str(), doc);
    744         lineno++;
    745     }
    746 
    747     if (!feof(f)) {
    748         fprintf(stderr, "%s:%d: error reading file, line to long.\n",
    749                 filename.c_str(), lineno);
    750         return 1;
    751     }
    752 
    753     fclose(f);
    754     return 0;
    755 }
    756 
    757 // ==========================================================
    758 static int
    759 compile_aidl(const Options& options)
    760 {
    761     int err = 0, N;
    762 
    763     set_import_paths(options.importPaths);
    764 
    765     register_base_types();
    766 
    767     // import the preprocessed file
    768     N = options.preprocessedFiles.size();
    769     for (int i=0; i<N; i++) {
    770         const string& s = options.preprocessedFiles[i];
    771         err |= parse_preprocessed_file(s);
    772     }
    773     if (err != 0) {
    774         return err;
    775     }
    776 
    777     // parse the main file
    778     g_callbacks = &g_mainCallbacks;
    779     err = parse_aidl(options.inputFileName.c_str());
    780     document_item_type* mainDoc = g_document;
    781     g_document = NULL;
    782 
    783     // parse the imports
    784     g_callbacks = &g_mainCallbacks;
    785     import_info* import = g_imports;
    786     while (import) {
    787         if (NAMES.Find(import->neededClass) == NULL) {
    788             import->filename = find_import_file(import->neededClass);
    789             if (!import->filename) {
    790                 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
    791                         import->from, import->statement.lineno,
    792                         import->neededClass);
    793                 err |= 1;
    794             } else {
    795                 err |= parse_aidl(import->filename);
    796                 import->doc = g_document;
    797                 if (import->doc == NULL) {
    798                     err |= 1;
    799                 }
    800             }
    801         }
    802         import = import->next;
    803     }
    804     // bail out now if parsing wasn't successful
    805     if (err != 0 || mainDoc == NULL) {
    806         //fprintf(stderr, "aidl: parsing failed, stopping.\n");
    807         return 1;
    808     }
    809 
    810     // complain about ones that aren't in the right files
    811     err |= check_filenames(options.inputFileName.c_str(), mainDoc);
    812     import = g_imports;
    813     while (import) {
    814         err |= check_filenames(import->filename, import->doc);
    815         import = import->next;
    816     }
    817 
    818     // gather the types that have been declared
    819     err |= gather_types(options.inputFileName.c_str(), mainDoc);
    820     import = g_imports;
    821     while (import) {
    822         err |= gather_types(import->filename, import->doc);
    823         import = import->next;
    824     }
    825 
    826 #if 0
    827     printf("---- main doc ----\n");
    828     test_document(mainDoc);
    829 
    830     import = g_imports;
    831     while (import) {
    832         printf("---- import doc ----\n");
    833         test_document(import->doc);
    834         import = import->next;
    835     }
    836     NAMES.Dump();
    837 #endif
    838 
    839     // check the referenced types in mainDoc to make sure we've imported them
    840     err |= check_types(options.inputFileName.c_str(), mainDoc);
    841 
    842     // finally, there really only needs to be one thing in mainDoc, and it
    843     // needs to be an interface.
    844     bool onlyParcelable = false;
    845     err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
    846 
    847     // after this, there shouldn't be any more errors because of the
    848     // input.
    849     if (err != 0 || mainDoc == NULL) {
    850         return 1;
    851     }
    852 
    853     // they didn't ask to fail on parcelables, so just exit quietly.
    854     if (onlyParcelable && !options.failOnParcelable) {
    855         return 0;
    856     }
    857 
    858     // if we were asked to, generate a make dependency file
    859     if (options.depFileName != "") {
    860         generate_dep_file(options);
    861     }
    862 
    863     // if needed, generate the outputFileName from the outputBaseFolder
    864     string outputFileName = options.outputFileName;
    865     if (outputFileName.length() == 0 &&
    866             options.outputBaseFolder.length() > 0) {
    867         outputFileName = generate_outputFileName(options, mainDoc);
    868     }
    869 
    870     // make sure the folders of the output file all exists
    871     check_outputFileName(outputFileName);
    872 
    873     err = generate_java(outputFileName, options.inputFileName.c_str(),
    874                         (interface_type*)mainDoc);
    875 
    876     return err;
    877 }
    878 
    879 static int
    880 preprocess_aidl(const Options& options)
    881 {
    882     vector<string> lines;
    883     int err;
    884 
    885     // read files
    886     int N = options.filesToPreprocess.size();
    887     for (int i=0; i<N; i++) {
    888         g_callbacks = &g_mainCallbacks;
    889         err = parse_aidl(options.filesToPreprocess[i].c_str());
    890         if (err != 0) {
    891             return err;
    892         }
    893         document_item_type* doc = g_document;
    894         string line;
    895         if (doc->item_type == PARCELABLE_TYPE) {
    896             line = "parcelable ";
    897             parcelable_type* parcelable = (parcelable_type*)doc;
    898             if (parcelable->package) {
    899                 line += parcelable->package;
    900                 line += '.';
    901             }
    902             line += parcelable->name.data;
    903         } else {
    904             line = "interface ";
    905             interface_type* iface = (interface_type*)doc;
    906             if (iface->package) {
    907                 line += iface->package;
    908                 line += '.';
    909             }
    910             line += iface->name.data;
    911         }
    912         line += ";\n";
    913         lines.push_back(line);
    914     }
    915 
    916     // write preprocessed file
    917     int fd = open( options.outputFileName.c_str(),
    918                    O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
    919 #ifdef HAVE_MS_C_RUNTIME
    920                    _S_IREAD|_S_IWRITE);
    921 #else
    922                    S_IRUSR|S_IWUSR|S_IRGRP);
    923 #endif
    924     if (fd == -1) {
    925         fprintf(stderr, "aidl: could not open file for write: %s\n",
    926                 options.outputFileName.c_str());
    927         return 1;
    928     }
    929 
    930     N = lines.size();
    931     for (int i=0; i<N; i++) {
    932         const string& s = lines[i];
    933         int len = s.length();
    934         if (len != write(fd, s.c_str(), len)) {
    935             fprintf(stderr, "aidl: error writing to file %s\n",
    936                 options.outputFileName.c_str());
    937             close(fd);
    938             unlink(options.outputFileName.c_str());
    939             return 1;
    940         }
    941     }
    942 
    943     close(fd);
    944     return 0;
    945 }
    946 
    947 // ==========================================================
    948 int
    949 main(int argc, const char **argv)
    950 {
    951     int err = 0;
    952 
    953     Options options;
    954     int result = parse_options(argc, argv, &options);
    955     if (result) {
    956         return result;
    957     }
    958 
    959     switch (options.task)
    960     {
    961         case COMPILE_AIDL:
    962             return compile_aidl(options);
    963         case PREPROCESS_AIDL:
    964             return preprocess_aidl(options);
    965     }
    966     fprintf(stderr, "aidl: internal error\n");
    967     return 1;
    968 }
    969 
    970 
    971