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, const document_item_type* items)
    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 = NULL;
    584     if (options.autoDepFile) {
    585         string fileName = options.outputFileName + ".d";
    586         to = fopen(fileName.c_str(), "wb");
    587     } else {
    588         to = fopen(options.depFileName.c_str(), "wb");
    589     }
    590 
    591     if (to == NULL) {
    592         return;
    593     }
    594 
    595     const char* slash = "\\";
    596     import_info* import = g_imports;
    597     if (import == NULL) {
    598         slash = "";
    599     }
    600 
    601     if (items->item_type == INTERFACE_TYPE) {
    602         fprintf(to, "%s: \\\n", options.outputFileName.c_str());
    603     } else {
    604         // parcelable: there's no output file.
    605         fprintf(to, " : \\\n");
    606     }
    607     fprintf(to, "  %s %s\n", options.inputFileName.c_str(), slash);
    608 
    609     while (import) {
    610         if (import->next == NULL) {
    611             slash = "";
    612         }
    613         if (import->filename) {
    614             fprintf(to, "  %s %s\n", import->filename, slash);
    615         }
    616         import = import->next;
    617     }
    618 
    619     fprintf(to, "\n");
    620 
    621     fclose(to);
    622 }
    623 
    624 // ==========================================================
    625 static string
    626 generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
    627 {
    628     string result;
    629 
    630     // create the path to the destination folder based on the
    631     // interface package name
    632     result = options.outputBaseFolder;
    633     result += OS_PATH_SEPARATOR;
    634 
    635     string packageStr = package;
    636     size_t len = packageStr.length();
    637     for (size_t i=0; i<len; i++) {
    638         if (packageStr[i] == '.') {
    639             packageStr[i] = OS_PATH_SEPARATOR;
    640         }
    641     }
    642 
    643     result += packageStr;
    644 
    645     // add the filename by replacing the .aidl extension to .java
    646     const char* p = strchr(name.data, '.');
    647     len = p ? p-name.data : strlen(name.data);
    648 
    649     result += OS_PATH_SEPARATOR;
    650     result.append(name.data, len);
    651     result += ".java";
    652 
    653     return result;
    654 }
    655 
    656 // ==========================================================
    657 static string
    658 generate_outputFileName(const Options& options, const document_item_type* items)
    659 {
    660     // items has already been checked to have only one interface.
    661     if (items->item_type == INTERFACE_TYPE) {
    662         interface_type* type = (interface_type*)items;
    663 
    664         return generate_outputFileName2(options, type->name, type->package);
    665     } else if (items->item_type == PARCELABLE_TYPE) {
    666         parcelable_type* type = (parcelable_type*)items;
    667         return generate_outputFileName2(options, type->name, type->package);
    668     }
    669 
    670     // I don't think we can come here, but safer than returning NULL.
    671     string result;
    672     return result;
    673 }
    674 
    675 
    676 
    677 // ==========================================================
    678 static void
    679 check_outputFilePath(const string& path) {
    680     size_t len = path.length();
    681     for (size_t i=0; i<len ; i++) {
    682         if (path[i] == OS_PATH_SEPARATOR) {
    683             string p = path.substr(0, i);
    684             if (access(path.data(), F_OK) != 0) {
    685 #ifdef HAVE_MS_C_RUNTIME
    686                 _mkdir(p.data());
    687 #else
    688                 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
    689 #endif
    690             }
    691         }
    692     }
    693 }
    694 
    695 
    696 // ==========================================================
    697 static int
    698 parse_preprocessed_file(const string& filename)
    699 {
    700     int err;
    701 
    702     FILE* f = fopen(filename.c_str(), "rb");
    703     if (f == NULL) {
    704         fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
    705                 filename.c_str());
    706         return 1;
    707     }
    708 
    709     int lineno = 1;
    710     char line[1024];
    711     char type[1024];
    712     char fullname[1024];
    713     while (fgets(line, sizeof(line), f)) {
    714         // skip comments and empty lines
    715         if (!line[0] || strncmp(line, "//", 2) == 0) {
    716           continue;
    717         }
    718 
    719         sscanf(line, "%s %[^; \r\n\t];", type, fullname);
    720 
    721         char* packagename;
    722         char* classname = rfind(fullname, '.');
    723         if (classname != NULL) {
    724             *classname = '\0';
    725             classname++;
    726             packagename = fullname;
    727         } else {
    728             classname = fullname;
    729             packagename = NULL;
    730         }
    731 
    732         //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
    733         //        type, packagename, classname);
    734         document_item_type* doc;
    735 
    736         if (0 == strcmp("parcelable", type)) {
    737             parcelable_type* parcl = (parcelable_type*)malloc(
    738                     sizeof(parcelable_type));
    739             memset(parcl, 0, sizeof(parcelable_type));
    740             parcl->document_item.item_type = PARCELABLE_TYPE;
    741             parcl->parcelable_token.lineno = lineno;
    742             parcl->parcelable_token.data = strdup(type);
    743             parcl->package = packagename ? strdup(packagename) : NULL;
    744             parcl->name.lineno = lineno;
    745             parcl->name.data = strdup(classname);
    746             parcl->semicolon_token.lineno = lineno;
    747             parcl->semicolon_token.data = strdup(";");
    748             doc = (document_item_type*)parcl;
    749         }
    750         else if (0 == strcmp("interface", type)) {
    751             interface_type* iface = (interface_type*)malloc(
    752                     sizeof(interface_type));
    753             memset(iface, 0, sizeof(interface_type));
    754             iface->document_item.item_type = INTERFACE_TYPE;
    755             iface->interface_token.lineno = lineno;
    756             iface->interface_token.data = strdup(type);
    757             iface->package = packagename ? strdup(packagename) : NULL;
    758             iface->name.lineno = lineno;
    759             iface->name.data = strdup(classname);
    760             iface->open_brace_token.lineno = lineno;
    761             iface->open_brace_token.data = strdup("{");
    762             iface->close_brace_token.lineno = lineno;
    763             iface->close_brace_token.data = strdup("}");
    764             doc = (document_item_type*)iface;
    765         }
    766         else {
    767             fprintf(stderr, "%s:%d: bad type in line: %s\n",
    768                     filename.c_str(), lineno, line);
    769             return 1;
    770         }
    771         err = gather_types(filename.c_str(), doc);
    772         lineno++;
    773     }
    774 
    775     if (!feof(f)) {
    776         fprintf(stderr, "%s:%d: error reading file, line to long.\n",
    777                 filename.c_str(), lineno);
    778         return 1;
    779     }
    780 
    781     fclose(f);
    782     return 0;
    783 }
    784 
    785 // ==========================================================
    786 static int
    787 compile_aidl(Options& options)
    788 {
    789     int err = 0, N;
    790 
    791     set_import_paths(options.importPaths);
    792 
    793     register_base_types();
    794 
    795     // import the preprocessed file
    796     N = options.preprocessedFiles.size();
    797     for (int i=0; i<N; i++) {
    798         const string& s = options.preprocessedFiles[i];
    799         err |= parse_preprocessed_file(s);
    800     }
    801     if (err != 0) {
    802         return err;
    803     }
    804 
    805     // parse the main file
    806     g_callbacks = &g_mainCallbacks;
    807     err = parse_aidl(options.inputFileName.c_str());
    808     document_item_type* mainDoc = g_document;
    809     g_document = NULL;
    810 
    811     // parse the imports
    812     g_callbacks = &g_mainCallbacks;
    813     import_info* import = g_imports;
    814     while (import) {
    815         if (NAMES.Find(import->neededClass) == NULL) {
    816             import->filename = find_import_file(import->neededClass);
    817             if (!import->filename) {
    818                 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
    819                         import->from, import->statement.lineno,
    820                         import->neededClass);
    821                 err |= 1;
    822             } else {
    823                 err |= parse_aidl(import->filename);
    824                 import->doc = g_document;
    825                 if (import->doc == NULL) {
    826                     err |= 1;
    827                 }
    828             }
    829         }
    830         import = import->next;
    831     }
    832     // bail out now if parsing wasn't successful
    833     if (err != 0 || mainDoc == NULL) {
    834         //fprintf(stderr, "aidl: parsing failed, stopping.\n");
    835         return 1;
    836     }
    837 
    838     // complain about ones that aren't in the right files
    839     err |= check_filenames(options.inputFileName.c_str(), mainDoc);
    840     import = g_imports;
    841     while (import) {
    842         err |= check_filenames(import->filename, import->doc);
    843         import = import->next;
    844     }
    845 
    846     // gather the types that have been declared
    847     err |= gather_types(options.inputFileName.c_str(), mainDoc);
    848     import = g_imports;
    849     while (import) {
    850         err |= gather_types(import->filename, import->doc);
    851         import = import->next;
    852     }
    853 
    854 #if 0
    855     printf("---- main doc ----\n");
    856     test_document(mainDoc);
    857 
    858     import = g_imports;
    859     while (import) {
    860         printf("---- import doc ----\n");
    861         test_document(import->doc);
    862         import = import->next;
    863     }
    864     NAMES.Dump();
    865 #endif
    866 
    867     // check the referenced types in mainDoc to make sure we've imported them
    868     err |= check_types(options.inputFileName.c_str(), mainDoc);
    869 
    870     // finally, there really only needs to be one thing in mainDoc, and it
    871     // needs to be an interface.
    872     bool onlyParcelable = false;
    873     err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
    874 
    875     // after this, there shouldn't be any more errors because of the
    876     // input.
    877     if (err != 0 || mainDoc == NULL) {
    878         return 1;
    879     }
    880 
    881     // if needed, generate the outputFileName from the outputBaseFolder
    882     if (options.outputFileName.length() == 0 &&
    883             options.outputBaseFolder.length() > 0) {
    884         options.outputFileName = generate_outputFileName(options, mainDoc);
    885     }
    886 
    887     // if we were asked to, generate a make dependency file
    888     // unless it's a parcelable *and* it's supposed to fail on parcelable
    889     if ((options.autoDepFile || options.depFileName != "") &&
    890             !(onlyParcelable && options.failOnParcelable)) {
    891         // make sure the folders of the output file all exists
    892         check_outputFilePath(options.outputFileName);
    893         generate_dep_file(options, mainDoc);
    894     }
    895 
    896     // they didn't ask to fail on parcelables, so just exit quietly.
    897     if (onlyParcelable && !options.failOnParcelable) {
    898         return 0;
    899     }
    900 
    901     // make sure the folders of the output file all exists
    902     check_outputFilePath(options.outputFileName);
    903 
    904     err = generate_java(options.outputFileName, options.inputFileName.c_str(),
    905                         (interface_type*)mainDoc);
    906 
    907     return err;
    908 }
    909 
    910 static int
    911 preprocess_aidl(const Options& options)
    912 {
    913     vector<string> lines;
    914     int err;
    915 
    916     // read files
    917     int N = options.filesToPreprocess.size();
    918     for (int i=0; i<N; i++) {
    919         g_callbacks = &g_mainCallbacks;
    920         err = parse_aidl(options.filesToPreprocess[i].c_str());
    921         if (err != 0) {
    922             return err;
    923         }
    924         document_item_type* doc = g_document;
    925         string line;
    926         if (doc->item_type == PARCELABLE_TYPE) {
    927             line = "parcelable ";
    928             parcelable_type* parcelable = (parcelable_type*)doc;
    929             if (parcelable->package) {
    930                 line += parcelable->package;
    931                 line += '.';
    932             }
    933             line += parcelable->name.data;
    934         } else {
    935             line = "interface ";
    936             interface_type* iface = (interface_type*)doc;
    937             if (iface->package) {
    938                 line += iface->package;
    939                 line += '.';
    940             }
    941             line += iface->name.data;
    942         }
    943         line += ";\n";
    944         lines.push_back(line);
    945     }
    946 
    947     // write preprocessed file
    948     int fd = open( options.outputFileName.c_str(),
    949                    O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
    950 #ifdef HAVE_MS_C_RUNTIME
    951                    _S_IREAD|_S_IWRITE);
    952 #else
    953                    S_IRUSR|S_IWUSR|S_IRGRP);
    954 #endif
    955     if (fd == -1) {
    956         fprintf(stderr, "aidl: could not open file for write: %s\n",
    957                 options.outputFileName.c_str());
    958         return 1;
    959     }
    960 
    961     N = lines.size();
    962     for (int i=0; i<N; i++) {
    963         const string& s = lines[i];
    964         int len = s.length();
    965         if (len != write(fd, s.c_str(), len)) {
    966             fprintf(stderr, "aidl: error writing to file %s\n",
    967                 options.outputFileName.c_str());
    968             close(fd);
    969             unlink(options.outputFileName.c_str());
    970             return 1;
    971         }
    972     }
    973 
    974     close(fd);
    975     return 0;
    976 }
    977 
    978 // ==========================================================
    979 int
    980 main(int argc, const char **argv)
    981 {
    982     Options options;
    983     int result = parse_options(argc, argv, &options);
    984     if (result) {
    985         return result;
    986     }
    987 
    988     switch (options.task)
    989     {
    990         case COMPILE_AIDL:
    991             return compile_aidl(options);
    992         case PREPROCESS_AIDL:
    993             return preprocess_aidl(options);
    994     }
    995     fprintf(stderr, "aidl: internal error\n");
    996     return 1;
    997 }
    998 
    999 
   1000