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