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