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