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