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